PLearn 0.1
GenerateDecisionPlot.cc
Go to the documentation of this file.
00001 
00002 // -*- C++ -*-
00003 
00004 // GenerateDecisionPlot.cc
00005 //
00006 // Copyright (C) 2003  Pascal Vincent 
00007 // 
00008 // Redistribution and use in source and binary forms, with or without
00009 // modification, are permitted provided that the following conditions are met:
00010 // 
00011 //  1. Redistributions of source code must retain the above copyright
00012 //     notice, this list of conditions and the following disclaimer.
00013 // 
00014 //  2. Redistributions in binary form must reproduce the above copyright
00015 //     notice, this list of conditions and the following disclaimer in the
00016 //     documentation and/or other materials provided with the distribution.
00017 // 
00018 //  3. The name of the authors may not be used to endorse or promote
00019 //     products derived from this software without specific prior written
00020 //     permission.
00021 // 
00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 // 
00033 // This file is part of the PLearn library. For more information on the PLearn
00034 // library, go to the PLearn Web site at www.plearn.org
00035 
00036 /* *******************************************************      
00037  * $Id: GenerateDecisionPlot.cc 4052 2005-09-07 17:13:17Z plearner $ 
00038  ******************************************************* */
00039 
00041 #include "GenerateDecisionPlot.h"
00042 #include <plearn/math/VecStatsCollector.h>
00043 #include <plearn/vmat/VMat_basic_stats.h>
00044 #include <plearn/io/load_and_save.h>
00045 
00046 namespace PLearn {
00047 using namespace std;
00048 
00049 
00054 void DX_write_2D_fields(ostream& out, const string& basename, TVec<Mat> fields, real x0, real y0, real deltax, real deltay, 
00055                         TVec<string> fieldnames=TVec<string>())
00056 {
00057     int nfields = fields.length();
00058     int nx = fields[0].length();
00059     int ny = fields[0].width();
00060 
00061     string posname = string("\"") + basename + "_gridpos\"";
00062 
00063     out << "object " << posname << " class gridpositions counts " << nx << " " << ny << "\n"
00064         << "origin  " << x0 << " " << y0 << "\n"
00065         << "delta   " << deltax << " 0 \n"
00066         << "delta    0 " << deltay << " \n\n\n";
00067 
00068     string conname = string("\"") + basename + "_gridcon\"";
00069 
00070     out << "object " << conname << " class gridconnections counts " << nx << " " << ny << "\n"
00071         //      << "attribute \"element type\" string \"cubes\" \n"
00072         << "attribute \"ref\" string \"positions\" \n\n\n";
00073 
00074     for(int k=0; k<nfields; k++)
00075     {
00076         Mat& m = fields[k];
00077         string fieldname = tostring(k);
00078         if(fieldnames)
00079             fieldname = fieldnames[k];
00080 
00081         string dataname = string("\"") + basename + "_" + fieldname + "_data\"";
00082 
00083         out << "object " << dataname << " class array type float rank 0 items " << nx*ny << " data follows \n";
00084         for(int i=0; i<nx; i++)
00085         {
00086             for(int j=0; j<ny; j++)
00087                 out << m(i,j) << " ";
00088             out << "\n";
00089         }
00090         out << "attribute \"dep\" string \"positions\" \n\n\n";
00091 
00092         out << "object \"" << fieldname << "\" class field \n"
00093             << "component \"positions\" " << posname << " \n"
00094             << "component \"connections\" " << conname << " \n"
00095             << "component \"data\" " << dataname << " \n\n\n";
00096     }
00097 }
00098 
00099 
00100 void DX_write_2D_fields(ostream& out, const string& basename, Vec X, Vec Y, TVec<Mat> fields)
00101 {
00102     int nfields = fields.length();
00103     int nx = fields[0].length();
00104     int ny = fields[0].width();
00105 
00106     /*
00107       out << "object \"" << basename << "_X\" class array type float rank 0 items " << nx << " data follows \n";
00108       for(int i=0; i<nx; i++)
00109       out << X[i] << "\n";
00110       out << "\n\n";
00111     
00112       out << "object \"" << basename << "_Y\" class array type float rank 0 items " << ny << " data follows \n";
00113       for(int i=0; i<ny; i++)
00114       out << Y[i] << "\n";
00115     */
00116 
00117     string posname = string("\"") + basename + "_gridpos\"";
00118     out << "object " << posname << " class array type float rank 1 shape 2 items " << nx*ny << " data follows\n";
00119     for(int i=0; i<nx; i++)
00120         for(int j=0; j<ny; j++)
00121             out << X[i] << " " << Y[j] << "\n";
00122     out << "\n\n";
00123 
00124     string conname = string("\"") + basename + "_gridcon\"";
00125     out << "object " << conname << " class gridconnections counts " << nx << " " << ny << "\n"
00126         //      << "attribute \"element type\" string \"cubes\" \n"
00127         << "attribute \"ref\" string \"positions\" \n\n\n";
00128 
00129     for(int k=0; k<nfields; k++)
00130     {
00131         Mat& m = fields[k];
00132         string fieldname = "output" + tostring(k);
00133         string dataname = string("\"") + basename + "_" + fieldname + "_data\"";
00134 
00135         out << "object " << dataname << " class array type float rank 0 items " << nx*ny << " data follows \n";
00136         for(int i=0; i<nx; i++)
00137         {
00138             for(int j=0; j<ny; j++)
00139                 out << m(i,j) << " ";
00140             out << "\n";
00141         }
00142         out << "attribute \"dep\" string \"positions\" \n\n\n";
00143 
00144         out << "object \"" << fieldname << "\" class field \n"
00145             << "component \"positions\" " << posname << " \n"
00146             << "component \"connections\" " << conname << " \n"
00147             << "component \"data\" " << dataname << " \n\n\n";
00148     }
00149 }
00150 
00151 
00152 TVec<Mat> computeOutputFields(PP<PLearner> learner, Vec X, Vec Y)
00153 {
00154     int noutputs = learner->outputsize();
00155 
00156     int nx = X.length();
00157     int ny = Y.length();
00158     int nfields = noutputs;
00159     TVec<Mat> fields(nfields);
00160 
00161     for(int k=0; k<nfields; k++)
00162         fields[k].resize(nx,ny);
00163 
00164     Vec input(2);
00165     Vec output(noutputs);
00166 
00167     ProgressBar pb("Computing " + tostring(nx) + " x " + tostring(ny) + " output field",nx*ny);
00168   
00169     for(int i=0; i<nx; i++)
00170         for(int j=0; j<ny; j++)
00171         {
00172             input[0] = X[i];
00173             input[1] = Y[j];
00174             learner->computeOutput(input,output);
00175             // cerr << "in: " << input << " out: " << output << endl;
00176             for(int k=0; k<noutputs; k++)
00177                 fields[k](i,j) = output[k];
00178             pb.update(i*nx+j);
00179         }
00180 
00181     return fields;
00182 }
00183 
00184 
00185 TVec<Mat> computeOutputFields(PP<PLearner> learner, int nx, int ny, real x0, real y0, real deltax, real deltay)
00186 {
00187     int noutputs = learner->outputsize();
00188     int nfields = noutputs;
00189 
00190     TVec<Mat> fields(nfields);
00191     for(int k=0; k<nfields; k++)
00192         fields[k].resize(nx,ny);
00193 
00194     Vec input(2);
00195     Vec output(noutputs);
00196 
00197     ProgressBar pb("Computing " + tostring(nx) + " x " + tostring(ny) + " output field",nx*ny);
00198 
00199     real x = x0;
00200     real y = y0;
00201     for(int i=0; i<nx; i++, x+=deltax)
00202         for(int j=0; j<ny; j++, y+=deltay)
00203         {
00204             input[0] = x;
00205             input[1] = y;
00206             learner->computeOutput(input,output);
00207             // cerr << "in: " << input << " out: " << output << endl;
00208             for(int k=0; k<noutputs; k++)
00209                 fields[k](i,j) = output[k];
00210             pb.update(i*nx+j);
00211         }
00212 
00213     return fields;
00214 }
00215 
00216 // Finds appropriate x0, y0, deltax, deltay from the dataset range, computes the fields and returns them
00217 // extraspace of .10 means we'll look 10% beyond the data range on every side
00218 TVec<Mat> computeOutputFieldsAutoRange(PP<PLearner> learner, VMat dataset, int nx, int ny, 
00219                                        real& x0, real& y0, real& deltax, real& deltay, real extraspace=.10)
00220 {
00221     Vec minv(2);
00222     Vec maxv(2);
00223     computeRange(dataset.subMatColumns(0,2), minv, maxv);
00224     real extrax = (maxv[0]-minv[0])*extraspace;
00225     x0 = minv[0]-extrax;
00226     deltax = (maxv[0]+extrax-x0)/nx;
00227     real extray = (maxv[1]-minv[1])*extraspace;
00228     y0 = minv[1]-extray;
00229     deltay = (maxv[1]+extray-y0)/ny;
00230     return computeOutputFields(learner, nx, ny, x0, y0, deltax, deltay);
00231 }
00232 
00233 
00234 void computeXYPositions(VMat dataset, int nx, int ny, Vec& X, Vec& Y, real extraspace=.10)
00235 {
00236     Vec minv(2);
00237     Vec maxv(2);
00238     computeRange(dataset.subMatColumns(0,2), minv, maxv);
00239     real extrax = (maxv[0]-minv[0])*extraspace;
00240     real x0 = minv[0]-extrax;
00241     real deltax = (maxv[0]+extrax-x0)/nx;
00242     real extray = (maxv[1]-minv[1])*extraspace;
00243     real y0 = minv[1]-extray;
00244     real deltay = (maxv[1]+extray-y0)/ny;
00245 
00246     set<real> xpos;
00247     set<real> ypos;
00248     int l = dataset.length();
00249     Vec datapoint(2);
00250     for(int i=0; i<l; i++)
00251     {
00252         dataset->getRow(i,datapoint);
00253         xpos.insert(datapoint[0]);
00254         ypos.insert(datapoint[1]);
00255     }
00256     real x = x0;
00257     for(int i=0; i<nx; i++, x+=deltax)
00258         xpos.insert(x);
00259     real y = y0;
00260     for(int j=0; j<ny; j++, y+=deltay)
00261         ypos.insert(y);
00262     set<real>::iterator it;
00263     X.resize(xpos.size());
00264     real* xptr = X.data();
00265     it = xpos.begin();
00266     while(it!=xpos.end())
00267         *xptr++ = *it++;
00268     Y.resize(ypos.size());
00269     real* yptr = Y.data();
00270     it = ypos.begin();
00271     while(it!=ypos.end())
00272         *yptr++ = *it++;
00273 }
00274 
00275 
00276 
00279 void DX_create_dataset_outputs_file(const string& filename, PP<PLearner> learner, VMat dataset)
00280 {
00281     ofstream out(filename.c_str());
00282 
00283     int l = dataset.length();
00284     int inputsize = learner->inputsize();
00285     int targetsize = learner->targetsize();
00286     int outputsize = learner->outputsize();
00287 
00288     // First write data points (input -> target, output)
00289     Vec input(inputsize);
00290     Vec target(targetsize);
00291     real weight;
00292     Vec output(outputsize);
00293 
00294     // write 2D positions
00295     out << "object \"dset_pos\" class array type float rank 1 shape " << inputsize << " items " << l << " data follows \n";
00296     for(int i=0; i<l; i++)
00297     {
00298         dataset->getExample(i,input,target,weight);
00299         for(int j=0; j<inputsize; j++)
00300             out << input[j] << " ";
00301         out << "\n";
00302     }
00303     out << "\n\n\n";
00304 
00305     // Now write data for those positions (target and output)
00306     if(targetsize+outputsize>0)
00307     {
00308         ProgressBar pb("Computing outputs for dataset points",l);
00309         out << "object \"dset_value\" class array type float rank 1 shape " << targetsize+outputsize << " items " << l << " data follows \n";
00310         for(int i=0; i<l; i++)
00311         {
00312             dataset->getExample(i,input,target,weight);
00313             for(int j=0; j<targetsize; j++)
00314                 out << target[j] << " ";
00315             learner->computeOutput(input, output);
00316             for(int j=0; j<outputsize; j++)
00317                 out << output[j] << " ";
00318             out << "\n";
00319             pb.update(i);
00320         }
00321         out << "attribute \"dep\" string \"positions\" \n\n\n";
00322     }
00323 
00324     // Field is created with two components: "positions" and "data"
00325     out << "object \"dset\" class field \n"
00326         << "component \"positions\" \"dset_pos\" \n";
00327     if(targetsize+outputsize>0)
00328         out << "component \"data\" \"dset_value\" \n";
00329     out << "\n\n\n";
00330 
00331 
00332   
00333     out << "end" << endl;
00334 }
00335 
00336 
00343 
00344 void DX_create_grid_outputs_file(const string& filename, PP<PLearner> learner, VMat dataset, 
00345                                  int nx, int ny, bool include_datapoint_grid=false, 
00346                                  real xmin=MISSING_VALUE, real xmax=MISSING_VALUE, 
00347                                  real ymin=MISSING_VALUE, real ymax=MISSING_VALUE,
00348                                  real extraspace=.10)
00349 {
00350     ofstream out(filename.c_str());
00351 
00352     double logsum = -FLT_MAX;
00353 
00354     int l = dataset.length();
00355     int inputsize = learner->inputsize();
00356     int targetsize = learner->targetsize();
00357     int outputsize = learner->outputsize();
00358 
00359     Vec input(inputsize);
00360     Vec target(targetsize);
00361     real weight;
00362     Vec output(outputsize);
00363 
00364     // Create the grid field
00365 
00366     set<real> xpos;
00367     set<real> ypos;
00368 
00369     // First the regular grid coordinates
00370     Vec minv(2);
00371     Vec maxv(2);
00372     computeRange(dataset.subMatColumns(0,2), minv, maxv);
00373     real extrax = (maxv[0]-minv[0])*extraspace;
00374     real extray = (maxv[1]-minv[1])*extraspace;
00375     if(is_missing(xmin))
00376         xmin = minv[0]-extrax;
00377     if(is_missing(xmax))
00378         xmax = maxv[0]+extrax;
00379     if(is_missing(ymin))
00380         ymin = minv[1]-extray;
00381     if(is_missing(ymax))
00382         ymax = maxv[1]+extray;
00383     real deltax = (xmax-xmin)/nx;
00384     real deltay = (ymax-ymin)/ny;
00385 
00386     real x = xmin;
00387     for(int i=0; i<nx; i++, x+=deltax)
00388         xpos.insert(x);
00389     real y = ymin;
00390     for(int j=0; j<ny; j++, y+=deltay)
00391         ypos.insert(y);
00392 
00393     // also include irregular grid coordinates based on coordinates of dataset points?
00394     if(include_datapoint_grid) 
00395     {
00396         for(int i=0; i<l; i++)
00397         {
00398             dataset->getExample(i,input,target,weight);
00399             x = input[0];
00400             y = input[1];
00401             if(x>xmin && x<xmax)
00402                 xpos.insert(x);
00403             if(y>ymin && y<ymax)
00404                 ypos.insert(y);
00405         }
00406     }
00407 
00408     nx = xpos.size();
00409     ny = ypos.size();
00410     set<real>::iterator itx;
00411     set<real>::iterator ity;
00412 
00413     out << "object \"outputs_gridpos\" class array type float rank 1 shape 2 items " << nx*ny << " data follows\n";
00414     for(itx=xpos.begin(); itx!=xpos.end(); ++itx)
00415         for(ity=ypos.begin(); ity!=ypos.end(); ++ity)
00416             out << *itx << " " << *ity << "\n";
00417     out << "\n\n";
00418 
00419     out << "object \"outputs_gridcon\" class gridconnections counts " << nx << " " << ny << "\n"
00420         //      << "attribute \"element type\" string \"cubes\" \n"
00421         << "attribute \"ref\" string \"positions\" \n\n\n";
00422 
00423     out << "object \"outputs_values\" class array type float rank 1 shape " << outputsize << " items " << nx*ny << " data follows \n";
00424   
00425     ProgressBar pb("Computing outputs for grid positions: " + tostring(nx)+"x"+tostring(ny), nx*ny);
00426     int n = 0;
00427     for(itx=xpos.begin(); itx!=xpos.end(); ++itx)
00428     {
00429         input[0] = *itx;
00430         for(ity=ypos.begin(); ity!=ypos.end(); ++ity)
00431         {
00432             input[1] = *ity;
00433             learner->computeOutput(input, output);
00434             for(int j=0; j<outputsize; j++)
00435                 out << output[j] << " ";
00436             out << "\n";
00437             if(logsum==-FLT_MAX)
00438                 logsum = output[0];
00439             else 
00440                 logsum = logadd(logsum, output[0]);
00441             pb.update(n++);
00442         }
00443     }
00444     pb.close();
00445     out << "attribute \"dep\" string \"positions\" \n\n\n";
00446 
00447     out << "object \"outputs\" class field \n"
00448         << "component \"positions\" \"outputs_gridpos\" \n"
00449         << "component \"connections\" \"outputs_gridcon\" \n"
00450         << "component \"data\" \"outputs_values\" \n\n\n";
00451   
00452     out << "end" << endl;
00453 
00454     double surfelem = deltax*deltay;
00455     double surfintegral = exp(logsum)*surfelem;
00456     cerr << "Estimated integral over sampled domain: " << surfintegral << endl;
00457 }
00458 
00459 
00460 GenerateDecisionPlot::GenerateDecisionPlot() 
00461     :basename("dxplot"),
00462      nx(10), ny(10),
00463      include_datapoint_grid(false),
00464      xmin(MISSING_VALUE), 
00465      xmax(MISSING_VALUE), 
00466      ymin(MISSING_VALUE), 
00467      ymax(MISSING_VALUE)
00468 {
00469 }
00470 
00471 PLEARN_IMPLEMENT_OBJECT(GenerateDecisionPlot, "ONE LINE DESCR", "NO HELP");
00472 
00473 void GenerateDecisionPlot::declareOptions(OptionList& ol)
00474 {
00475     // ### Declare all of this object's options here
00476     // ### For the "flags" of each option, you should typically specify  
00477     // ### one of OptionBase::buildoption, OptionBase::learntoption or 
00478     // ### OptionBase::tuningoption. Another possible flag to be combined with
00479     // ### is OptionBase::nosave
00480 
00481     declareOption(ol, "basename", &GenerateDecisionPlot::basename, OptionBase::buildoption,
00482                   "Base name of the .dx data file to generate. Running this class will generate\n"
00483                   "files basename_dset.dx containing targets and outputs for the given dataset positions\n"
00484                   "and basename_outputs.dx containing outputs computed at grid positions\n");
00485     declareOption(ol, "learner", &GenerateDecisionPlot::learner, OptionBase::buildoption,
00486                   "The learner to train/test. Its train_set will be used as the dataset on\n"
00487                   "which to base this decision plot (ranges are inferred from it, and decisions\n"
00488                   "on the training points are written in basename_dset.dx");
00489     declareOption(ol, "nx", &GenerateDecisionPlot::nx, OptionBase::buildoption,
00490                   "Number of x sample coordinates (grid)");
00491     declareOption(ol, "ny", &GenerateDecisionPlot::ny, OptionBase::buildoption,
00492                   "Number of y sample coordinates (grid)");
00493     declareOption(ol, "include_datapoint_grid", &GenerateDecisionPlot::include_datapoint_grid, OptionBase::buildoption,
00494                   "");
00495     declareOption(ol, "xmin", &GenerateDecisionPlot::xmin, OptionBase::buildoption,
00496                   "");
00497     declareOption(ol, "xmax", &GenerateDecisionPlot::xmax, OptionBase::buildoption,
00498                   "");
00499     declareOption(ol, "ymin", &GenerateDecisionPlot::ymin, OptionBase::buildoption,
00500                   "");
00501     declareOption(ol, "ymax", &GenerateDecisionPlot::ymax, OptionBase::buildoption,
00502                   "");
00503     declareOption(ol, "save_learner_as", &GenerateDecisionPlot::save_learner_as, OptionBase::buildoption,
00504                   "(Optionally) save trained learner in this file (.psave)");
00505 
00506     // Now call the parent class' declareOptions
00507     inherited::declareOptions(ol);
00508 }
00509 
00510 void GenerateDecisionPlot::build_()
00511 {
00512     // ### This method should do the real building of the object,
00513     // ### according to set 'options', in *any* situation. 
00514     // ### Typical situations include:
00515     // ###  - Initial building of an object from a few user-specified options
00516     // ###  - Building of a "reloaded" object: i.e. from the complete set of all serialised options.
00517     // ###  - Updating or "re-building" of an object after a few "tuning" options have been modified.
00518     // ### You should assume that the parent class' build_() has already been called.
00519 }
00520 
00522 void GenerateDecisionPlot::run()
00523 {
00524     VMat dataset = learner->getTrainingSet();
00525     learner->setTrainStatsCollector(new VecStatsCollector());
00526     learner->train();
00527 
00528     if(save_learner_as!="")
00529     {
00530         cerr << "Saving trained learner in file " << save_learner_as << endl;
00531         PLearn::save(save_learner_as, *learner);
00532     }
00533 
00534     string dset_fname = basename+"_dset.dx";
00535     cerr << "Computing and writing dataset output field to file " << dset_fname << endl;
00536     DX_create_dataset_outputs_file(dset_fname, learner, dataset);
00537 
00538     string outputs_fname = basename+"_outputs.dx";
00539     cerr << "Computing and writing grid output field to file " << outputs_fname << endl; 
00540     DX_create_grid_outputs_file(outputs_fname, learner, dataset, nx, ny, 
00541                                 include_datapoint_grid, 
00542                                 xmin, xmax, ymin, ymax);
00543     cerr << "You can now view those files with OpenDX." << endl;
00544 }
00545 
00546 
00547 // ### Nothing to add here, simply calls build_
00548 void GenerateDecisionPlot::build()
00549 {
00550     inherited::build();
00551     build_();
00552 }
00553 
00554 
00555 void GenerateDecisionPlot::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00556 {
00557     inherited::makeDeepCopyFromShallowCopy(copies);
00558 }
00559 
00560 } // end of namespace PLearn
00561 
00562 
00563 /*
00564   Local Variables:
00565   mode:c++
00566   c-basic-offset:4
00567   c-file-style:"stroustrup"
00568   c-file-offsets:((innamespace . 0)(inline-open . 0))
00569   indent-tabs-mode:nil
00570   fill-column:79
00571   End:
00572 */
00573 // 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