PLearn 0.1
RandomSamplesVMatrix.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // RandomSamplesVMatrix.cc
00004 //
00005 // Copyright (C) 2006 Olivier Delalleau
00006 //
00007 // Redistribution and use in source and binary forms, with or without
00008 // modification, are permitted provided that the following conditions are met:
00009 //
00010 //  1. Redistributions of source code must retain the above copyright
00011 //     notice, this list of conditions and the following disclaimer.
00012 //
00013 //  2. Redistributions in binary form must reproduce the above copyright
00014 //     notice, this list of conditions and the following disclaimer in the
00015 //     documentation and/or other materials provided with the distribution.
00016 //
00017 //  3. The name of the authors may not be used to endorse or promote
00018 //     products derived from this software without specific prior written
00019 //     permission.
00020 //
00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031 //
00032 // This file is part of the PLearn library. For more information on the PLearn
00033 // library, go to the PLearn Web site at www.plearn.org
00034 
00035 // Authors: Olivier Delalleau
00036 
00040 #include "RandomSamplesVMatrix.h"
00041 #include <plearn/vmat/VMatLanguage.h>
00042 
00043 namespace PLearn {
00044 using namespace std;
00045 
00046 PLEARN_IMPLEMENT_OBJECT(
00047     RandomSamplesVMatrix,
00048     "VMat that samples on-the-fly random examples from its source.",
00049     "More precisely, this VMat will:\n"
00050     "- contain all examples from its source that match the 'is_preserved'\n"
00051     "  VPL program (by default, no example is systematically preserved)\n"
00052     "- fill the rest of the data with random source examples that do not\n"
00053     "  match that program\n"
00054     "\n"
00055     "It is important to note that random examples are sampled at each call\n"
00056     "of the 'getNewRow(..)' method, so that the data viewed by this VMatrix\n"
00057     "is not constant (except for the rows that are preserved).\n"
00058     "\n"
00059     "The ordering of the examples is random, and the total length of this\n"
00060     "VMat is determined from the 'length' option, or from the number of non-\n"
00061     "preserved examples if the 'n_non_preserved' option is set.\n"
00062 );
00063 
00065 // RandomSamplesVMatrix //
00067 RandomSamplesVMatrix::RandomSamplesVMatrix():
00068     alternate_targets(false),
00069     is_preserved("0"),
00070     n_non_preserved(-1),
00071     seed(1827),
00072     random_gen(new PRandom())
00073 {
00074 }
00075 
00077 // declareOptions //
00079 void RandomSamplesVMatrix::declareOptions(OptionList& ol)
00080 {
00081     // ### Declare all of this object's options here.
00082     // ### For the "flags" of each option, you should typically specify
00083     // ### one of OptionBase::buildoption, OptionBase::learntoption or
00084     // ### OptionBase::tuningoption. If you don't provide one of these three,
00085     // ### this option will be ignored when loading values from a script.
00086     // ### You can also combine flags, for example with OptionBase::nosave:
00087     // ### (OptionBase::buildoption | OptionBase::nosave)
00088 
00089     declareOption(ol, "is_preserved", &RandomSamplesVMatrix::is_preserved,
00090                                       OptionBase::buildoption,
00091         "VPL program that indicates if a sample is preserved.");
00092 
00093     declareOption(ol, "n_non_preserved",
00094                   &RandomSamplesVMatrix::n_non_preserved,
00095                   OptionBase::buildoption,
00096         "If given a non-negative value, it indicates the total number of\n"
00097         "non-preserved examples that are added to this VMat, and overrides\n"
00098         "the 'length' option. Two special negative values can be used:\n"
00099         " -1: this option is ignored, and the number of non-preserved\n"
00100         "     samples is set so that this VMat has either the desired length\n"
00101         "     (if the 'length' option is provided), or the same length as\n"
00102         "     its source otherwise.\n"
00103         " -2: the number of non-preserved examples is set exactly to match\n"
00104         "     the number of preserved examples.");
00105 
00106     declareOption(ol, "alternate_targets",
00107                   &RandomSamplesVMatrix::alternate_targets,
00108                   OptionBase::buildoption,
00109         "If set to 1, then this VMat will never sample two consecutive rows\n"
00110         "having the same target.");
00111 
00112     declareOption(ol, "seed", &RandomSamplesVMatrix::seed,
00113                               OptionBase::buildoption,
00114         "Seed for random number generation.");
00115 
00116     // Now call the parent class' declareOptions
00117     inherited::declareOptions(ol);
00118 }
00119 
00121 // build //
00123 void RandomSamplesVMatrix::build()
00124 {
00125     inherited::build();
00126     build_();
00127 }
00128 
00130 // build_ //
00132 void RandomSamplesVMatrix::build_()
00133 {
00134     if (!source)
00135         return;
00136 
00137     random_gen->manual_seed(seed);
00138 
00139     // Initialize VPL program.
00140     VMatLanguage program;
00141     TVec<string> fieldnames;
00142     program.setSource(source);
00143     program.compileString(is_preserved, fieldnames);
00144 
00145     // Find out which samples need to be kept.
00146     int n = source->length();
00147     Vec row(source->width());
00148     Vec result(1);
00149     non_preserved.resize(0);
00150     indices.resize(0);
00151     for (int i = 0; i < n; i++) {
00152         program.run(i, result);
00153         if (fast_exact_is_equal(result[0], 1))
00154             // Sample i is to be preserved.
00155             indices.append(i);
00156         else
00157             non_preserved.append(i);
00158     }
00159 
00160     // Find out length of this VMat if the 'n_non_preserved' option is set.
00161     PLASSERT( n_non_preserved >= 0 || n_non_preserved == -1 ||
00162             n_non_preserved == -2 );
00163     if (n_non_preserved >= 0)
00164         length_ = indices.length() + n_non_preserved;
00165     else if (n_non_preserved == -2)
00166         length_ = indices.length() * 2;
00167     else if (length_ < 0)
00168         length_ = source->length();
00169 
00170     // Specific pre-processing for the case where 'alternate_targets' is true.
00171     if (alternate_targets) {
00172         // Currently this feature is not implemented when we preserve examples
00173         // (just because it is a bit more complex).
00174         if (!indices.isEmpty())
00175             PLERROR("In RandomSamplesVMatrix::build_ - The 'alternate_targets'"
00176                     " option is not implemented yet in the case where some "
00177                     "examples are preserved. Please implement it!");
00178         if (source->targetsize() != 1)
00179             PLERROR("In RandomSamplesVMatrix::build_ - The source must have "
00180                     "a targetsize of 1 in order to use the "
00181                     "'alternate_targets' option");
00182         // First we need to find the number of targets.
00183         map<real, TVec<int> > by_target_map; // Map a target to its samples.
00184         Vec input, target;
00185         real weight;
00186         target_to_idx.clear();
00187         for (int i = 0; i < source->length(); i++) {
00188             source->getExample(i, input, target, weight);
00189             by_target_map[target[0]].append(i);
00190             if (target_to_idx.count(target[0]) == 0) {
00191                 int n_cur = target_to_idx.size();
00192                 target_to_idx[target[0]] = n_cur;
00193             }
00194         }
00195         int n_targets = by_target_map.size();
00196         // Convert from map to vector (for convenience).
00197         by_target.resize(n_targets);
00198         map<real, TVec<int> >::const_iterator it = by_target_map.begin();
00199         for (int i = 0; i < n_targets; i++, it++)
00200             by_target[i] = it->second;
00201         // Build a map from a target index to all other target indices that may
00202         // be used afterwards, with corresponding probabilities.
00203         target_list.resize(n_targets);
00204         target_distr.resize(n_targets);
00205         for (int i = 0; i < n_targets; i++) {
00206             TVec<int>& tl = target_list[i];
00207             tl.resize(0);
00208             Vec& td = target_distr[i];
00209             td.resize(0);
00210             int n_others = 0;
00211            
00212             for (int j = 0; j < n_targets; j++)
00213                 if (j != i) {
00214                     tl.append(j); // This is the list of all targets,
00215                                   // excluding 'i'.
00216                     td.append(by_target[j].length());
00217                     n_others += by_target[j].length();
00218                 }
00219             td /= real(n_others); // Normalize probabilities.
00220         }
00221 
00222         // Resize 'last_targets'.
00223         last_targets.resize(source->length());
00224     }
00225 
00226     // Fill in 'indices' with as many -1 as necessary.
00227     if (indices.length() > length_)
00228         PLERROR("In RandomSamplesVMatrix::build_ - The number of preserved"
00229                 "samples (%d) is higher than the length of this VMat (%d)",
00230                 indices.length(), length_);
00231     while (indices.length() != length_)
00232         indices.append(-1);
00233 
00234     // Shuffle the list of indices.
00235     random_gen->shuffleElements(indices);
00236 
00237     setMetaInfoFromSource();
00238 }
00239 
00241 // getNewRow //
00243 void RandomSamplesVMatrix::getNewRow(int i, const Vec& v) const
00244 {
00245     if (indices[i] >= 0)
00246         source->getRow(indices[i], v);
00247     else {
00248         int random_sample;
00249         if (alternate_targets && i > 0) {
00250             // Note that the first sample may be any class since it has no
00251             // previous sample in this VMat.
00252             real previous_target = last_targets[i - 1];
00253             int previous_target_idx = target_to_idx[previous_target];
00254             int random_target = random_gen->multinomial_sample(
00255                     target_distr[previous_target_idx]);
00256             const TVec<int>& candidates =
00257                 by_target[target_list[previous_target_idx][random_target]];
00258             int random_sample_idx = random_gen->uniform_multinomial_sample(
00259                     candidates.length());
00260             random_sample = candidates[random_sample_idx];
00261             PLASSERT( non_preserved.length() == source->length() );
00262         } else {
00263             random_sample =
00264                 random_gen->uniform_multinomial_sample(non_preserved.length());
00265         }
00266         source->getRow(non_preserved[random_sample], v);
00267         if (alternate_targets)
00268             last_targets[i] = v[source->inputsize()];
00269     }
00270 }
00271 
00273 // makeDeepCopyFromShallowCopy //
00275 void RandomSamplesVMatrix::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00276 {
00277     inherited::makeDeepCopyFromShallowCopy(copies);
00278 
00279     deepCopyField(random_gen,       copies);
00280     deepCopyField(non_preserved,    copies);
00281     deepCopyField(indices,          copies);
00282     deepCopyField(last_targets,     copies);
00283     deepCopyField(target_list,      copies);
00284     deepCopyField(target_distr,     copies);
00285     deepCopyField(by_target,        copies);
00286 }
00287 
00288 } // end of namespace PLearn
00289 
00290 
00291 /*
00292   Local Variables:
00293   mode:c++
00294   c-basic-offset:4
00295   c-file-style:"stroustrup"
00296   c-file-offsets:((innamespace . 0)(inline-open . 0))
00297   indent-tabs-mode:nil
00298   fill-column:79
00299   End:
00300 */
00301 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines