PLearn 0.1
|
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