PLearn 0.1
DisplayUtils.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002  
00003 // PLearn (A C++ Machine Learning Library)
00004 // Copyright (C) 1998 Pascal Vincent
00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio and University of Montreal
00006 // Copyright (C) 2004 ApSTAT Technologies Inc.
00007 //
00008 
00009 // Redistribution and use in source and binary forms, with or without
00010 // modification, are permitted provided that the following conditions are met:
00011 // 
00012 //  1. Redistributions of source code must retain the above copyright
00013 //     notice, this list of conditions and the following disclaimer.
00014 // 
00015 //  2. Redistributions in binary form must reproduce the above copyright
00016 //     notice, this list of conditions and the following disclaimer in the
00017 //     documentation and/or other materials provided with the distribution.
00018 // 
00019 //  3. The name of the authors may not be used to endorse or promote
00020 //     products derived from this software without specific prior written
00021 //     permission.
00022 // 
00023 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00024 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00025 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00026 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00027 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00028 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00029 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00030 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00031 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 // 
00034 // This file is part of the PLearn library. For more information on the PLearn
00035 // library, go to the PLearn Web site at www.plearn.org
00036 
00037 
00038  
00039 
00040 /* *******************************************************      
00041    * $Id: DisplayUtils.cc 8451 2008-02-03 22:40:49Z plearner $
00042    * AUTHORS: Pascal Vincent & Yoshua Bengio
00043    * This file is part of the PLearn library.
00044    ******************************************************* */
00045 
00046 #include "DisplayUtils.h"
00047 #include <plearn/io/openString.h>
00048 #include <plearn/io/TmpFilenames.h>
00049 #include <plearn/math/pl_math.h>
00050 
00051 #if defined(WIN32) && !defined(__CYGWIN__)
00052 #include <io.h>
00053 #define unlink _unlink
00054 #endif
00055 
00056 namespace PLearn {
00057 using namespace std;
00058 
00059 
00066   void scores_to_winners(Mat scores, Mat& winners)
00067   {
00068     int l = scores.length();
00069     winners.resize(l,3);
00070     for(int i=0; i<l; i++)
00071       {
00072         Vec scorerow = scores(i);
00073         int maxpos = argmax(scorerow);
00074         real maxval = scorerow[maxpos];
00075         scorerow[maxpos] = -FLT_MAX;
00076         real maxval2 = max(scorerow);
00077         scorerow[maxpos] = maxval;
00078         winners(i,0) = maxpos;
00079         winners(i,1) = maxval;
00080         winners(i,2) = maxval-maxval2;
00081       }
00082   }
00083 
00084 
00085   void color_luminance_to_rgb(int colornum, real luminance, real& r, real& g, real& b)
00086   {
00087     if(luminance<0 || luminance>1)
00088       PLERROR("In color_luminance_to_rgb luminance %f outside of range [0,1]",luminance);    
00089   }
00090 
00091   real color_luminance_to_rgbreal(int colornum, real luminance)
00092   {
00093     real r=0, g=0, b=0;
00094     color_luminance_to_rgb(colornum, luminance, r, g, b);
00095     return rgb2real(r,g,b);
00096   }
00097 
00098   void color_luminance_to_rgbreal(Vec colornum, Vec luminance, Vec& rgbreal)
00099   {
00100     int l = colornum.length();
00101     rgbreal.resize(l);
00102     for(int i=0; i<l; i++)
00103       rgbreal[i] = color_luminance_to_rgbreal((int)colornum[i],luminance[i]);
00104   }
00105     
00106   void transform_perclass_values_into_luminance(Vec classnums, const Vec& values, int ndiscretevals)
00107   {
00108     int l = classnums.length();
00109     int nclasses = (int)max(classnums);
00110     Vec minval(nclasses,FLT_MAX);
00111     Vec maxval(nclasses,-FLT_MAX);
00112     for(int i=0; i<l; i++)
00113       {
00114         int c = int(classnums[i]);
00115         real val = values[i];
00116         if(val<minval[c])
00117           minval[c] = val;
00118         if(val>maxval[c])
00119           maxval[c] = val;        
00120       }
00121 
00122     for(int i=0; i<l; i++)
00123       {
00124         int c = int(classnums[i]);
00125         real val = values[i];
00126         // rescale it between 0 and 1
00127         val = (val-minval[c])/(maxval[c]-minval[c]);
00128         if(ndiscretevals>1) // discretize it
00129           val = floor(val*ndiscretevals+0.5)/ndiscretevals;
00130         values[i] = val;
00131       }
00132   }
00133 
00134 
00135   void regulargrid_x_y_rgbreal_to_bitmap(Mat& regulargrid_x_y_rgbreal, 
00136                                          Mat& bm, real& xlow, real& xhigh, real& ylow, real& yhigh)
00137   {
00138     TVec<int> key_columns(2);
00139     key_columns[0] = 0;
00140     key_columns[1] = 1;
00141     sortRows(regulargrid_x_y_rgbreal, key_columns);
00142     int l = regulargrid_x_y_rgbreal.length();
00143     xlow = regulargrid_x_y_rgbreal(0,0);
00144     xhigh = regulargrid_x_y_rgbreal(l-1,0);
00145     ylow = regulargrid_x_y_rgbreal(0,1);
00146     yhigh = regulargrid_x_y_rgbreal(l-1,1);
00147     int ny=1;
00148     while(!fast_exact_is_equal(regulargrid_x_y_rgbreal(ny,1), ylow))
00149       ++ny;
00150 
00151     int nx = l/ny;
00152     if(nx*ny!=l)
00153       PLERROR("Problem in regulargrid_x_y_rgbreal_to_rgbimage : estimated_nx * estimated_ny != l (%d*%d!=%d)",nx,ny,l);
00154 
00155     bm.resize(ny,nx);    
00156     int k = 0;
00157     for(int j=0; j<nx; j++)
00158       for(int i=ny-1; i>=0; i--)
00159         bm(i,j) = regulargrid_x_y_rgbreal(k++,2);
00160   }
00161 
00162 
00163   void regulargrid_x_y_outputs_to_bitmap(Mat regulargrid_x_y_outputs, bool output_margin, int ndiscretevals,
00164                                          Mat& bm, real& xlow, real& xhigh, real& ylow, real& yhigh)
00165 
00166   {
00167     int l = regulargrid_x_y_outputs.length();
00168     int outputsize = regulargrid_x_y_outputs.width()-2;
00169     Mat regulargrid_x_y = regulargrid_x_y_outputs.subMatColumns(0,2);
00170     Mat outputs = regulargrid_x_y_outputs.subMatColumns(2,outputsize);
00171     Mat winners;
00172     scores_to_winners(outputs, winners);
00173     Vec classnums(l);
00174     Vec values(l);
00175     classnums << winners.column(0);
00176     values << winners.column(output_margin ?2 :1);
00177     transform_perclass_values_into_luminance(classnums, values, ndiscretevals);
00178     Vec rgbreal;
00179     color_luminance_to_rgbreal(classnums, values, rgbreal);
00180     Mat regulargrid_x_y_rgbreal(l,3);
00181     regulargrid_x_y_rgbreal.subMatColumns(0,2) << regulargrid_x_y;
00182     regulargrid_x_y_rgbreal.column(2) << rgbreal;    
00183     regulargrid_x_y_rgbreal_to_bitmap(regulargrid_x_y_rgbreal, 
00184                                       bm, xlow, xhigh, ylow, yhigh);  
00185   }
00186 
00187 void displayHistogram(Gnuplot& gp, Mat dataColumn,
00188                       int n_bins, Vec* pbins, 
00189                       bool regular_bins,
00190                       bool normalized, string extra_args)
00191 {
00192   Vec sorted_data = dataColumn.toVecCopy();
00193   sortElements(sorted_data);
00194   int n=sorted_data.length();
00195   real minv = sorted_data[0];
00196   real maxv = sorted_data[n-1];
00197 
00198   // compute "bins" vector, which specifies histogram intervals
00199   // [minv, bins[0]), [bins[0],bins[1]), ... [bin[n_bins-2],maxv]
00200   Vec bins;
00201   if (pbins)
00202     {
00203       bins = *pbins;
00204       n_bins = bins.length()+1;
00205     }
00206   else
00207     {
00208       if (n_bins==0)
00209         n_bins = MIN(5+n/10,1000);
00210       bins.resize(n_bins-1);
00211 
00212       // fill the bins
00213       if (regular_bins)
00214         {
00215           real delta = (maxv-minv)/n_bins;
00216           real v = minv+delta;
00217           real* b=bins.data();
00218           for (int i=0;i<n_bins-1;i++,v+=delta) b[i]=v;
00219         }
00220       else
00221         {
00222           real n_expected_per_bin = n/(real)n_bins;
00223           int current_bin=0;
00224           real* v=sorted_data.data();
00225           real* b=bins.data();
00226           real previous = 1e30;
00227           int n_repeat = 0;
00228           int previous_n_repeat = 0;
00229           int first_of_mass_point = 0;
00230           for (int i=0;i<n;i++)
00231             {
00232               if (fast_exact_is_equal(previous, v[i]))
00233                 {
00234                   if (previous_n_repeat==0) first_of_mass_point = i-1;
00235                   n_repeat++;
00236                 }
00237               else
00238                 n_repeat=0;
00239               if (n_repeat==0  && current_bin < n_bins-1) // put a left_side at i only if v[i]!=v[i-1]
00240                 {
00241                   if (previous_n_repeat==0)
00242                     {
00243                       if (i+1 >= n_expected_per_bin*(1+current_bin))
00244                         b[current_bin++]=v[i];
00245                     }
00246                   else
00247                     {
00248                       if (n_repeat/(real)n > n_expected_per_bin)
00249                         {
00250                           if (current_bin>0 && b[current_bin-1] < v[first_of_mass_point])
00251                             b[current_bin++]=v[first_of_mass_point];
00252                           if (current_bin < n_bins-1)
00253                             b[current_bin++]=v[i];
00254                         }
00255                       else
00256                         if (i+1 >= n_expected_per_bin*(1+current_bin))
00257                           b[current_bin++]=v[i];
00258                     }
00259                 }
00260               previous = v[i];
00261               previous_n_repeat = n_repeat;
00262             }
00263         }
00264     }
00265 
00266   // fill histogram vector with counts in each interval:
00267   // first column is the left border of each bin, 2nd is the count
00268   Mat histogram(n_bins+1,2);
00269   real* left_side = &histogram(0,0);
00270   real* frequency = left_side+1;
00271   real* b = bins.data();
00272   real* v=sorted_data.data();
00273   int current_bin=0;
00274   real left = minv;
00275   for (int i=0;i<n;i++)
00276     {
00277       if (current_bin<n_bins-1 &&
00278           v[i]>=b[current_bin])
00279         {
00280           left_side[2*current_bin]=left;
00281           left = v[i];
00282           current_bin++;
00283         }
00284       frequency[2*current_bin]++;
00285     }
00286   left_side[2*current_bin]=left;
00287   left_side[2*n_bins]=maxv+(maxv-minv)/n;
00288   real norm_factor = normalized? (1.0/n) : 1.0;
00289   for (int i=0;i<n_bins;i++)
00290     {
00291       real deltax = left_side[2*(i+1)]-left_side[2*i];
00292       if (fast_exact_is_equal(deltax, 0)) {
00293           PLWARNING("displayHistogram: 0 deltax!");
00294           deltax=1.0;
00295       }
00296       frequency[i*2] *= norm_factor/deltax;
00297     }
00298 
00299   histogram(n_bins,1)=histogram(n_bins-1,1);
00300 
00301   // display the histogram
00302   string comm = string(" with steps")+extra_args;
00303   gp.plot(histogram,comm.c_str());
00304 }
00305 
00306 
00308   Vec centerSubVec(Vec v, int n=16)
00309   {
00310     int l = v.length();
00311     if(l<=n)
00312       return v;    
00313     return v.subVec((l-n)/2,n);
00314   }
00315 
00316   string summarizedVecString(Vec v, int maxn=16, string format="%2.2g")
00317   {
00318     string result = "";
00319     int n = 0;
00320     char buf[30];
00321     int nsame = 1;
00322     string val;
00323     string prev_val;
00324     int l = v.length();
00325     result = tostring(l)+ " [ ";
00326     int i;
00327     for(i=0; i<l && n<maxn; i++)
00328       {
00329         snprintf(buf,20,format.c_str(),v[i]);
00330         val = buf;
00331         if(i==0)
00332           prev_val = val;
00333         else if(val==prev_val)
00334           { nsame++; }
00335         else 
00336           {
00337             result += prev_val;
00338             if(nsame>1)
00339               result += (string("*")+tostring(nsame));
00340             result += " ";
00341             n++;
00342             nsame = 1;
00343           }
00344         prev_val = val;
00345       }
00346 
00347     if(l>0)
00348       {
00349         result += prev_val;
00350         if(nsame>1)
00351           result += (string("*")+tostring(nsame));
00352       }
00353     if(i<l)
00354       result += " ...]";
00355     else
00356       result += " ]";
00357     return result;
00358   }
00359 
00362 void displayVarGraph(const VarArray& outputs, bool display_values, real boxwidth, const char* the_filename, bool must_wait, VarArray display_only_these)
00363 {
00364   // parameters controlling appearance...
00365   real deltay = 100;
00366   real boxheight = 50;
00367 
00368   char filename[100];
00369   if(the_filename)
00370     strcpy(filename, the_filename);
00371   else
00372   {
00373     TmpFilenames tmpnam;
00374     strcpy(filename, tmpnam.addFilename().c_str());
00375   }
00376   
00377   multimap<real,Var> layers; 
00378   typedef multimap<real,Var>::iterator mmit;
00379 
00380   Mat center(Variable::nvars+1,2);
00381   center.fill(FLT_MAX);
00382   
00383   int n_display_only_these = display_only_these.size();
00384   bool display_all = n_display_only_these==0;
00385 
00386   // find sources of outputs which are not in the outputs array:
00387   outputs.unmarkAncestors();
00388   VarArray sources = outputs.sources();
00389   outputs.unmarkAncestors();
00390   // We dont want any source Var that is in outputs to be in sources so we remove them:
00391   outputs.setMark();
00392   VarArray nonoutputsources;
00393   for(int i=0; i<sources.size(); i++)
00394     if(!sources[i]->isMarked() && (display_all || display_only_these.contains(sources[i])))
00395       nonoutputsources.append(sources[i]);
00396   sources = nonoutputsources;
00397   outputs.clearMark();
00398   
00399   sources.setMark();
00400 
00401   // Place everything but the sources starting from outputs at the bottom
00402 
00403   outputs.unmarkAncestors();
00404 
00405   real y = boxheight;
00406   VarArray varray = outputs;
00407   
00408   while(varray.size()>0)
00409     {
00410       // varray.setMark(); // so that these don't get put in subsequent parents() calls
00411       VarArray parents;
00412       int nvars = varray.size();
00413       for(int i=0; i<nvars; i++)
00414         {
00415           Var v = varray[i];
00416           real old_y = center(v->varnum,1);
00417           if (!fast_exact_is_equal(old_y, FLT_MAX)) // remove pair (old_y,v) from layers
00418           {
00419             pair<mmit,mmit> range = layers.equal_range(old_y);
00420             for (mmit it = range.first; it != range.second; it++)
00421               if (v->varnum == it->second->varnum)
00422               {
00423                 layers.erase(it);
00424                 break;
00425               }
00426           }
00427           layers.insert(pair<real,Var>(y, v));
00428           center(v->varnum,1) = y;
00429           VarArray parents_i = v->parents();
00430           for (int j=0;j<parents_i.size();j++)
00431             if((display_all || display_only_these.contains(parents_i[j])) && !parents.contains(parents_i[j]))
00432               parents &= parents_i[j];
00433         }
00434       varray = parents;
00435       y += deltay;
00436     }
00437   // now place the sources
00438   int nvars = sources.size();
00439   for(int i=0; i<nvars; i++)
00440     {
00441       Var v = sources[i];
00442       real old_y = center(v->varnum,1);
00443       if (!fast_exact_is_equal(old_y, FLT_MAX)) // remove pair (old_y,v) from layers
00444       {
00445         pair<mmit,mmit> range = layers.equal_range(old_y);
00446         for (mmit it = range.first; it != range.second; it++)
00447           if (v->varnum == it->second->varnum)
00448           {
00449             layers.erase(it);
00450             break;
00451           }
00452       }
00453       layers.insert(pair<real,Var>(y,v));
00454     }
00455   real topy = y;
00456 
00457   outputs.unmarkAncestors();
00458   if (display_all)
00459   {
00460     VarArray ancestors = outputs.ancestors();
00461     outputs.unmarkAncestors();   
00462     varray = ancestors;
00463   }
00464   else varray = display_only_these;
00465 
00466   // Find the maximum number of vars in a level...
00467   int maxvarsperlevel = sources.size();
00468 
00469   for (real y_=boxheight;y_<=topy;y_+=deltay)
00470   {
00471     pair<mmit,mmit> range = layers.equal_range(y_);
00472     int nvars_ = (int)distance(range.first,range.second);
00473     if (maxvarsperlevel < nvars_)
00474       maxvarsperlevel = nvars_;
00475   }
00476 
00477   real usewidth = (maxvarsperlevel+1)*(boxwidth+boxheight);
00478 
00479   // Compute the bounding box:
00480   real min_x = 0;
00481   real min_y = 0;
00482   real max_x = usewidth;
00483   real max_y = topy;
00484 
00485   min_x -= boxwidth/2;
00486   max_x += boxwidth/2;
00487   min_y -= boxheight/2;
00488   max_y += boxheight/2;
00489 
00490   for (real y_=boxheight;y_<=topy;y_+=deltay)
00491   {
00492     pair<mmit,mmit> range = layers.equal_range(y_);
00493     int nvars_ = (int)distance(range.first,range.second);
00494     real deltax = usewidth/(nvars_+1);
00495     real x = deltax;
00496     for (mmit it = range.first; it != range.second; it++, x+=deltax)
00497     {
00498       Var v = it->second;
00499       center(v->varnum,0) = x;
00500       center(v->varnum,1) = y_;
00501     }
00502   }
00503 
00504   // Start outputting to the file
00505   {
00506     // make it an eps file with the computed bounding box
00507     GhostScript gs(filename,min_x,min_y,max_x,max_y);
00508 
00509   // Now paint
00510 
00511   // gs.setlinewidth(1.0);
00512 
00513   for (real y_=boxheight;y_<=topy;y_+=deltay)
00514   {
00515     pair<mmit,mmit> range = layers.equal_range(y_);
00516     int nvars_ = (int)distance(range.first,range.second);
00517     real deltax = usewidth/(nvars_+1);
00518     real x = deltax;
00519     for (mmit it = range.first; it != range.second; it++, x+=deltax)
00520     {
00521       Var v = it->second;
00522       real my_x = x;
00523       real my_y = y_;
00524 
00525       // Display v
00526       gs.drawBox(my_x-boxwidth/2, my_y-boxheight/2, boxwidth, boxheight);
00527       char nameline[100];
00528       sprintf(nameline,"%s (%d,%d)",v->getName().c_str(), v->matValue.length(), v->matValue.width());
00529       
00530       string descr;
00531       PStream str_descr = openString(descr, PStream::raw_ascii, "w");
00532       str_descr << v;
00533 
00534       if(display_values)
00535         {
00536           gs.usefont("Times-Bold", 11.0);
00537           gs.centerShow(my_x, my_y+boxheight/4, descr);
00538           gs.usefont("Times-Roman", 10.0);
00539           gs.centerShow(my_x, my_y, nameline);
00540           gs.usefont("Courrier", 6.0);
00541           if (v->rValue.length()>0) // print rvalue if there are some...
00542           {
00543             gs.centerShow(my_x, my_y-boxheight/5, summarizedVecString(v->value));
00544             gs.centerShow(my_x, my_y-boxheight/3, summarizedVecString(v->gradient));
00545             gs.centerShow(my_x, my_y-boxheight/1, summarizedVecString(v->rValue));
00546           }
00547           else
00548           {
00549             gs.centerShow(my_x, my_y-boxheight/5, summarizedVecString(v->value));
00550             gs.centerShow(my_x, my_y-boxheight/2.5, summarizedVecString(v->gradient));
00551           }
00552           /*
00553           cout << descr << " " << nameline << " (" << v->value.length() << ")" << endl;
00554           cout << "value:    " << v->value << endl;
00555           cout << "gradient: " << v->gradient << endl;
00556           */
00557         }
00558       else
00559         {
00560           gs.usefont("Times-Bold", 12.0);
00561           gs.centerShow(my_x, my_y+boxheight/4, descr.c_str());
00562           gs.usefont("Times-Roman", 11.0);
00563           gs.centerShow(my_x, my_y-boxheight/4, nameline);
00564         }
00565 
00566       // Display the arrows from the parents
00567       VarArray parents = v->parents();
00568       int nparents = parents.size();
00569       for(int p=0; p<nparents; p++)
00570         {
00571           Var parent = parents[p];
00572           if (display_all || display_only_these.contains(parent))
00573           {
00574             real parent_x = center(parent->varnum,0);
00575             real parent_y = center(parent->varnum,1);
00576 
00577             gs.drawArrow(parent_x, parent_y-boxheight/2, 
00578                          my_x+0.75*boxwidth*(real(p+1)/real(nparents+1)-0.5), 
00579                          my_y+boxheight/2);
00580           }
00581         }
00582     }
00583   }
00584   outputs.unmarkAncestors();      
00585   }
00586   char command[1000];
00587   if (must_wait)
00588     sprintf(command,"gv %s",filename);
00589   else
00590     sprintf(command,"gv %s &",filename);
00591 
00592   system(command);
00593 
00594   if(the_filename==0 && must_wait)
00595     unlink(filename);
00596 }
00597 
00598 void OldDisplayVarGraph(const VarArray& outputs, bool display_values, real boxwidth, const char* the_filename, bool must_wait, VarArray display_only_these)
00599 {
00600   // parameters controlling appearance...
00601   real deltay = 100;
00602   real boxheight = 50;
00603 
00604   char filename[100];
00605   if(the_filename)
00606     strcpy(filename, the_filename);
00607   else
00608   {
00609     TmpFilenames tmpnam;
00610     strcpy(filename, tmpnam.addFilename().c_str());
00611   }
00612   
00613   Mat center(Variable::nvars+1,2);
00614   center.fill(FLT_MAX);
00615   
00616   int n_display_only_these = display_only_these.size();
00617   bool display_all = n_display_only_these==0;
00618 
00619   // find sources of outputs which are not in the outputs array:
00620   outputs.unmarkAncestors();
00621   VarArray sources = outputs.sources();
00622   outputs.unmarkAncestors();
00623   // We dont want any source Var that is in outputs to be in sources so we remove them:
00624   outputs.setMark();
00625   VarArray nonoutputsources;
00626   for(int i=0; i<sources.size(); i++)
00627     if(!sources[i]->isMarked() && (display_all || display_only_these.contains(sources[i])))
00628       nonoutputsources.append(sources[i]);
00629   sources = nonoutputsources;
00630   outputs.clearMark();
00631   
00632   // Find the maximum number of vars in a level...
00633   int maxvarsperlevel = sources.size();
00634   sources.setMark();
00635   VarArray varray = outputs;
00636   while(varray.size()>0)
00637   {
00638     if(varray.size()>maxvarsperlevel)
00639       maxvarsperlevel = varray.size();
00640     varray.setMark(); // so that these don't get put in subsequent parents() calls
00641     VarArray parents;
00642     for(int i=0; i<varray.size(); i++)
00643       parents &= varray[i]->parents();
00644     varray = VarArray();
00645     for (int i=0;i<parents.size();i++)
00646       if(display_all || display_only_these.contains(parents[i]))
00647         varray &= parents[i];
00648   }
00649   sources.setMark();
00650 
00651   real usewidth = (maxvarsperlevel+1)*(boxwidth+boxheight);
00652 
00653   // Place everything but the sources starting from outputs at the bottom
00654 
00655   outputs.unmarkAncestors();
00656 
00657   real y = boxheight;
00658   varray = outputs;
00659   
00660   while(varray.size()>0)
00661     {
00662       // varray.setMark(); // so that these don't get put in subsequent parents() calls
00663       VarArray parents;
00664       int nvars = varray.size();
00665       for(int i=0; i<nvars; i++)
00666         {
00667           Var v = varray[i];
00668           center(v->varnum,0) = usewidth*(i+1)/(nvars+1);
00669           center(v->varnum,1) = y;                
00670           // bool marked = v->isMarked();
00671           // v->clearMark();
00672           VarArray parents_i = v->parents();
00673           for (int j=0;j<parents_i.size();j++)
00674             if((display_all || display_only_these.contains(parents_i[j])) && !parents.contains(parents_i[j]))
00675               parents &= parents_i[j];
00676         }
00677       varray = parents;
00678       y += deltay;
00679     }
00680   // now place the sources
00681   int nvars = sources.size();
00682   for(int i=0; i<nvars; i++)
00683     {
00684       Var v = sources[i];
00685       center(v->varnum,0) = usewidth*(i+1)/(nvars+1);
00686       center(v->varnum,1) = y;                
00687     }
00688 
00689   outputs.unmarkAncestors();
00690   if (display_all)
00691   {
00692     VarArray ancestors = outputs.ancestors();
00693     outputs.unmarkAncestors();   
00694     varray = ancestors;
00695   }
00696   else varray = display_only_these;
00697 
00698   // Compute the bounding box:
00699   real min_x = FLT_MAX;
00700   real min_y = FLT_MAX;
00701   real max_x = -FLT_MAX;
00702   real max_y = -FLT_MAX;
00703 
00704   for(int i=0; i<varray.size(); i++)
00705     {
00706       Var v = varray[i];
00707       real x = center(v->varnum,0);
00708       real y_ = center(v->varnum,1);
00709       if(x<min_x)
00710         min_x = x;
00711       if(y_<min_y)
00712         min_y = y_;
00713       if(x>max_x)
00714         max_x = x;
00715       if(y_>max_y)
00716         max_y = y_;
00717     }
00718   min_x -= boxwidth/2;
00719   max_x += boxwidth/2;
00720   min_y -= boxheight/2;
00721   max_y += boxheight/2;
00722 
00723   // Start outputting to the file
00724   {
00725     // make it an eps file with the computed bounding box
00726     GhostScript gs(filename,min_x,min_y,max_x,max_y);
00727 
00728   // Now paint
00729 
00730   // gs.setlinewidth(1.0);
00731 
00732   for(int i=0; i<varray.size(); i++)
00733     {
00734       Var v = varray[i];
00735       real my_x = center(v->varnum,0);
00736       real my_y = center(v->varnum,1);
00737 
00738       // Display v
00739       gs.drawBox(my_x-boxwidth/2, my_y-boxheight/2, boxwidth, boxheight);
00740       char nameline[100];
00741       sprintf(nameline,"%s (%d,%d)",v->getName().c_str(), v->matValue.length(), v->matValue.width());
00742 
00743       string descr;
00744       PStream str_descr = openString(descr, PStream::raw_ascii, "w");
00745       str_descr << v;
00746 
00747       if(display_values)
00748         {
00749           gs.usefont("Times-Bold", 11.0);
00750           gs.centerShow(my_x, my_y+boxheight/4, descr.c_str());
00751           gs.usefont("Times-Roman", 10.0);
00752           gs.centerShow(my_x, my_y, nameline);
00753           gs.usefont("Courrier", 6.0);
00754           gs.centerShow(my_x, my_y-boxheight/5, v->value);
00755           gs.centerShow(my_x, my_y-boxheight/2.5, v->gradient);
00756         }
00757       else
00758         {
00759           gs.usefont("Times-Bold", 12.0);
00760           gs.centerShow(my_x, my_y+boxheight/4, descr.c_str());
00761           gs.usefont("Times-Roman", 11.0);
00762           gs.centerShow(my_x, my_y-boxheight/4, nameline);
00763         }
00764 
00765       // Display the arrows from the parents
00766       VarArray parents = v->parents();
00767       int nparents = parents.size();
00768       for(int p=0; p<nparents; p++)
00769         {
00770           Var parent = parents[p];
00771           if (display_all || display_only_these.contains(parent))
00772           {
00773             real parent_x = center(parent->varnum,0);
00774             real parent_y = center(parent->varnum,1);
00775 
00776             gs.drawArrow(parent_x, parent_y-boxheight/2, 
00777                          my_x+0.75*boxwidth*(real(p+1)/real(nparents+1)-0.5), 
00778                          my_y+boxheight/2);
00779           }
00780         }
00781     }
00782   outputs.unmarkAncestors();      
00783   }
00784 
00785   char command[1000];
00786   if (must_wait)
00787     sprintf(command,"gv %s",filename);
00788   else
00789     sprintf(command,"gv %s &",filename);
00790 
00791   system(command);
00792 
00793   if(the_filename==0)
00794     unlink(filename);
00795 }
00796 
00797 void tagVariables(VarArray vars, string tag)
00798 {
00799   for(int i=0; i<vars.length(); i++)
00800     {
00801       string name = vars[i]->getName();
00802       vars[i]->setName(tag+":"+name);
00803     }
00804 }
00805 
00806 void untagVariables(VarArray vars, string tag)
00807 {
00808   int startpos = tag.length()+1;
00809   for(int i=0; i<vars.length(); i++)
00810     {
00811       string name = vars[i]->getName();
00812       vars[i]->setName(name.substr(startpos,name.length()-startpos));
00813     }
00814 }
00815 
00816 void displayFunction(Func f, bool display_values, bool display_differentiation, real boxwidth, const char* the_filename, bool must_wait)
00817 { 
00818   tagVariables(f->inputs,"INPUT");
00819   tagVariables(f->parameters,"PARAM");
00820   tagVariables(f->outputs,"OUTPUT");
00821   if(display_differentiation)
00822     displayVarGraph(f->outputs & f->differentiate()->outputs, display_values, boxwidth, the_filename, must_wait);
00823   else
00824     displayVarGraph(f->outputs, display_values, boxwidth, the_filename, must_wait); 
00825   untagVariables(f->outputs,"OUTPUT");
00826   untagVariables(f->parameters,"PARAM");
00827   untagVariables(f->inputs,"INPUT");
00828 }
00829 
00830 Mat compute2dGridOutputs(PP<PLearner> learner, real min_x, real max_x, real min_y, real max_y, int length, int width, real singleoutput_threshold)
00831 {
00832   Mat m(length,width);
00833   real delta_x = (max_x-min_x)/(width-1);
00834   real delta_y = (max_y-min_y)/(length-1);
00835 
00836   if(learner->inputsize()!=2 || (learner->outputsize()!=1 && learner->outputsize()!=2) )
00837      PLERROR("learner is expected to have an inputsize of 2, and an outputsize of 1 (or possibly 2 for binary classification)");
00838 
00839   Vec input(2);
00840   Vec output(learner->outputsize());
00841   for(int i=0; i<length; i++)
00842   {
00843     input[1] = min_y+(length-i-1)*delta_y;
00844     for(int j=0; j<width; j++)
00845       {
00846         input[0] = min_x+j*delta_x;
00847         learner->computeOutput(input,output);
00848         if(learner->outputsize()==2)
00849           m(i,j) = output[0]-output[1];
00850         else
00851           m(i,j) = output[0]-singleoutput_threshold;
00852       }
00853   }
00854   return m;
00855 }
00856 
00857 void displayPoints(GhostScript& gs, Mat data, real radius, bool color)
00858 {
00859   for(int i=0; i<data.length(); i++)
00860     {
00861       Vec point = data(i);
00862       if(color)
00863         {
00864           if(point[2]<=0.0)
00865             gs.setcolor(1.0,0.0,0.0);
00866           else
00867             gs.setcolor(0.0,0.0,1.0);
00868           gs.drawCross(point[0], point[1], radius);
00869         }
00870       else
00871         gs.drawCross(point[0], point[1], radius, point[2]<=0);
00872     }
00873 } 
00874 
00875 /*
00876   // Old version based on a Classifier
00877 void displayDecisionSurface(GhostScript& gs, Classifier& cl, real xmin, real xmax, int nxsamples, real ymin, real ymax, int nysamples)
00878 {
00879   Vec input(2);
00880   Vec scores(1);
00881   Mat bm(nysamples,nxsamples);
00882 
00883   for(int i=0; i<nysamples; i++)
00884     for(int j=0; j<nxsamples; j++)
00885       {
00886         input[0] = xmin+(xmax-xmin)/(nxsamples-1)*j;
00887         input[1] = ymax-(ymax-ymin)/(nysamples-1)*i;
00888         cl.computeOutput(input,scores);
00889         // cerr << scores[0] << "| ";
00890         real r,g,b;
00891         if(scores[0]<=0.5)
00892           r(i,j) = scores[0]*1.8;
00893         else
00894           b(i,j) = (1.0-scores[0])*1.8;
00895       }
00896   gs.gsave();
00897   gs.translate(xmin,ymin);
00898   gs.scale((xmax-xmin)/nxsamples, (ymax-ymin)/nysamples);
00899   gs.displayRGB(0,0,r,g,b);
00900   gs.grestore();
00901 }
00902 */
00903 
00904 void displayDecisionSurface(GhostScript& gs, real destx, real desty, real destwidth, real destheight, 
00905                             PP<PLearner> learner, Mat trainset, 
00906                             Vec svindexes, Vec outlierindexes, int nextsvindex,
00907                             real min_x, real max_x, real min_y, real max_y,
00908                             real radius, 
00909                             int nx, int ny)
00910   {
00911     gs.gsave();
00912     real scalefactor = (max_x-min_x)/destwidth;
00913     gs.mapping(min_x,min_y,max_x-min_x,max_y-min_y, destx, desty, destwidth, destheight);
00914     gs.setlinewidth(1.0*scalefactor);
00915 
00916     real singleoutput_threshold = 0.;
00917     if(learner->outputsize()==1)
00918     {
00919       Mat targets = trainset.column(learner->inputsize());
00920       singleoutput_threshold = 0.5*(min(targets)+max(targets));
00921     }
00922     Mat decisions = compute2dGridOutputs(learner, min_x, max_x, min_y, max_y, ny, nx, singleoutput_threshold);
00923 
00924     //real posrange = max(decisions);
00925     //real negrange = min(decisions);
00926 
00927     for(int i=0; i<ny; i++)
00928       for(int j=0; j<nx; j++)
00929         {
00930           decisions(i,j) = (decisions(i,j)<0. ? 0.75 : 1.0);
00931           /*
00932           if(decisions(i,j) < 0.0)
00933             decisions(i,j) = 1.0-.5*decisions(i,j)/negrange;
00934           else
00935             decisions(i,j) = .5+.5*decisions(i,j)/posrange;
00936           */
00937         }
00938 
00939     gs.displayGray(decisions,min_x,min_y,max_x-min_x,max_y-min_y);
00940 
00941     // draw x and +
00942     displayPoints(gs, trainset, radius, false);
00943 
00944     // draw black circles around support vectors
00945     for(int k=0; k<svindexes.length(); k++)
00946       {
00947         real x = trainset(int(svindexes[k]),0);
00948         real y = trainset(int(svindexes[k]),1);
00949         // cerr << "{" << x << "," << y << "}";
00950         gs.drawCircle(x,y,radius);
00951       }
00952     // cerr << endl;
00953 
00954     // draw half radius circle around next support vector
00955     if(nextsvindex>=0)
00956     {
00957       real x = trainset(nextsvindex,0);
00958       real y = trainset(nextsvindex,1);
00959       gs.drawCircle(x,y,radius/2);
00960     }
00961 
00962     // draw white circles around outliers
00963     Vec dashpattern(2,4.0*scalefactor);
00964     gs.setdash(dashpattern);
00965     for(int k=0; k<outlierindexes.length(); k++)
00966       {
00967         real x = trainset(int(outlierindexes[k]),0);
00968         real y = trainset(int(outlierindexes[k]),1);
00969         gs.drawCircle(x,y,radius);
00970       }
00971 
00972     gs.grestore();
00973   }
00974 
00975 #ifdef WIN32
00976 #undef unlink
00977 #endif
00978 
00979 } // end of namespace PLearn
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines