source: trunk/MagicSoft/Mars/mranforest/MRanTree.cc@ 7421

Last change on this file since 7421 was 7420, checked in by tbretz, 19 years ago
*** empty log message ***
File size: 20.9 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Hengstebeck 3/2003 <mailto:hengsteb@physik.hu-berlin.de>
19!
20! Copyright: MAGIC Software Development, 2000-2005
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MRanTree
28//
29// ParameterContainer for Tree structure
30//
31/////////////////////////////////////////////////////////////////////////////
32#include "MRanTree.h"
33
34#include <iostream>
35
36#include <TVector.h>
37#include <TMatrix.h>
38#include <TRandom.h>
39
40#include "MLog.h"
41#include "MLogManip.h"
42
43ClassImp(MRanTree);
44
45using namespace std;
46
47
48// --------------------------------------------------------------------------
49// Default constructor.
50//
51MRanTree::MRanTree(const char *name, const char *title):fClassify(kTRUE),fNdSize(0), fNumTry(3)
52{
53
54 fName = name ? name : "MRanTree";
55 fTitle = title ? title : "Storage container for structure of a single tree";
56}
57
58// --------------------------------------------------------------------------
59// Copy constructor
60//
61MRanTree::MRanTree(const MRanTree &tree)
62{
63 fName = tree.fName;
64 fTitle = tree.fTitle;
65
66 fClassify = tree.fClassify;
67 fNdSize = tree.fNdSize;
68 fNumTry = tree.fNumTry;
69
70 fNumNodes = tree.fNumNodes;
71 fNumEndNodes = tree.fNumEndNodes;
72
73 fBestVar = tree.fBestVar;
74 fTreeMap1 = tree.fTreeMap1;
75 fTreeMap2 = tree.fTreeMap2;
76 fBestSplit = tree.fBestSplit;
77 fGiniDec = tree.fGiniDec;
78}
79
80void MRanTree::SetNdSize(Int_t n)
81{
82 // threshold nodesize of terminal nodes, i.e. the training data is splitted
83 // until there is only pure date in the subsets(=terminal nodes) or the
84 // subset size is LE n
85
86 fNdSize=TMath::Max(1,n);//at least 1 event per node
87}
88
89void MRanTree::SetNumTry(Int_t n)
90{
91 // number of trials in random split selection:
92 // choose at least 1 variable to split in
93
94 fNumTry=TMath::Max(1,n);
95}
96
97void MRanTree::GrowTree(TMatrix *mat, const TArrayF &hadtrue, const TArrayI &idclass,
98 TArrayI &datasort, const TArrayI &datarang, TArrayF &tclasspop,
99 float &mean, float &square, TArrayI &jinbag, const TArrayF &winbag,
100 const int nclass)
101{
102 // arrays have to be initialized with generous size, so number of total nodes (nrnodes)
103 // is estimated for worst case
104 const Int_t numdim =mat->GetNcols();
105 const Int_t numdata=winbag.GetSize();
106 const Int_t nrnodes=2*numdata+1;
107
108 // number of events in bootstrap sample
109 Int_t ninbag=0;
110 for (Int_t n=0;n<numdata;n++) if(jinbag[n]==1) ninbag++;
111
112 TArrayI bestsplit(nrnodes); bestsplit.Reset(0);
113 TArrayI bestsplitnext(nrnodes); bestsplitnext.Reset(0);
114
115 fBestVar.Set(nrnodes); fBestVar.Reset(0);
116 fTreeMap1.Set(nrnodes); fTreeMap1.Reset(0);
117 fTreeMap2.Set(nrnodes); fTreeMap2.Reset(0);
118 fBestSplit.Set(nrnodes); fBestSplit.Reset(0);
119 fGiniDec.Set(numdim); fGiniDec.Reset(0);
120
121
122 if(fClassify)
123 FindBestSplit=&MRanTree::FindBestSplitGini;
124 else
125 FindBestSplit=&MRanTree::FindBestSplitSigma;
126
127 // tree growing
128 BuildTree(datasort,datarang,hadtrue,idclass,bestsplit, bestsplitnext,
129 tclasspop,mean,square,winbag,ninbag,nclass);
130
131 // post processing, determine cut (or split) values fBestSplit
132 for(Int_t k=0; k<nrnodes; k++)
133 {
134 if (GetNodeStatus(k)==-1)
135 continue;
136
137 const Int_t &bsp =bestsplit[k];
138 const Int_t &bspn=bestsplitnext[k];
139 const Int_t &msp =fBestVar[k];
140
141 fBestSplit[k] = (*mat)(bsp, msp);
142 fBestSplit[k] += (*mat)(bspn,msp);
143 fBestSplit[k] /= 2.;
144 }
145
146 // resizing arrays to save memory
147 fBestVar.Set(fNumNodes);
148 fTreeMap1.Set(fNumNodes);
149 fTreeMap2.Set(fNumNodes);
150 fBestSplit.Set(fNumNodes);
151}
152
153int MRanTree::FindBestSplitGini(const TArrayI &datasort,const TArrayI &datarang,
154 const TArrayF &hadtrue,const TArrayI &idclass,
155 Int_t ndstart,Int_t ndend, TArrayF &tclasspop,
156 float &mean, float &square, Int_t &msplit,
157 Float_t &decsplit,Int_t &nbest, const TArrayF &winbag,
158 const int nclass)
159{
160 const Int_t nrnodes = fBestSplit.GetSize();
161 const Int_t numdata = (nrnodes-1)/2;
162 const Int_t mdim = fGiniDec.GetSize();
163
164 TArrayF wr(nclass); wr.Reset(0);// right node
165
166 // For the best split, msplit is the index of the variable (e.g Hillas par.,
167 // zenith angle ,...)
168 // split on. decsplit is the decreae in impurity measured by Gini-index.
169 // nsplit is the case number of value of msplit split on,
170 // and nsplitnext is the case number of the next larger value of msplit.
171
172 Int_t nbestvar=0;
173
174 // compute initial values of numerator and denominator of Gini-index,
175 // Gini index= pno/dno
176 Double_t pno=0;
177 Double_t pdo=0;
178
179 for (Int_t j=0; j<nclass; j++)
180 {
181 pno+=tclasspop[j]*tclasspop[j];
182 pdo+=tclasspop[j];
183 }
184
185 const Double_t crit0=pno/pdo;
186
187 // start main loop through variables to find best split,
188 // (Gini-index as criterium crit)
189
190 Double_t critmax=-FLT_MAX;
191
192 // random split selection, number of trials = fNumTry
193 for (Int_t mt=0; mt<fNumTry; mt++)
194 {
195 const Int_t mvar=Int_t(gRandom->Rndm()*mdim);
196 const Int_t mn = mvar*numdata;
197
198 // Gini index = rrn/rrd+rln/rld
199 Double_t rrn=pno;
200 Double_t rrd=pdo;
201 Double_t rln=0;
202 Double_t rld=0;
203
204 TArrayF wl(nclass); wl.Reset(0.);// left node //nclass
205 wr = tclasspop;
206
207 Double_t critvar=-1.0e20;
208 for(Int_t nsp=ndstart;nsp<=ndend-1;nsp++)
209 {
210 const Int_t &nc = datasort[mn+nsp];
211 const Int_t &k = idclass[nc];
212 const Float_t &u = winbag[nc];
213
214 // do classification, Gini index as split rule
215 rln+=u*(2*wl[k]+u);
216 rrn+=u*(-2*wr[k]+u);
217
218 rld+=u;
219 rrd-=u;
220
221 wl[k]+=u;
222 wr[k]-=u;
223
224 if (datarang[mn+nc]>=datarang[mn+datasort[mn+nsp+1]])
225 continue;
226
227 if (TMath::Min(rrd,rld)<=1.0e-5)
228 continue;
229
230 const Double_t crit=(rln/rld)+(rrn/rrd);
231
232
233 if (crit<=critvar) continue;
234
235 nbestvar=nsp;
236 critvar=crit;
237 }
238
239 if (critvar<=critmax) continue;
240
241 msplit=mvar;
242 nbest=nbestvar;
243 critmax=critvar;
244 }
245
246 decsplit=critmax-crit0;
247
248 return critmax<-1.0e10 ? 1 : 0;
249}
250
251int MRanTree::FindBestSplitSigma(const TArrayI &datasort,const TArrayI &datarang,
252 const TArrayF &hadtrue, const TArrayI &idclass,
253 Int_t ndstart,Int_t ndend, TArrayF &tclasspop,
254 float &mean, float &square, Int_t &msplit,
255 Float_t &decsplit,Int_t &nbest, const TArrayF &winbag,
256 const int nclass)
257{
258 const Int_t nrnodes = fBestSplit.GetSize();
259 const Int_t numdata = (nrnodes-1)/2;
260 const Int_t mdim = fGiniDec.GetSize();
261
262 float wr=0;// right node
263
264 // For the best split, msplit is the index of the variable (e.g Hillas par., zenith angle ,...)
265 // split on. decsplit is the decreae in impurity measured by Gini-index.
266 // nsplit is the case number of value of msplit split on,
267 // and nsplitnext is the case number of the next larger value of msplit.
268
269 Int_t nbestvar=0;
270
271 // compute initial values of numerator and denominator of split-index,
272
273 // resolution
274 //Double_t pno=-(tclasspop[0]*square-mean*mean)*tclasspop[0];
275 //Double_t pdo= (tclasspop[0]-1.)*mean*mean;
276
277 // n*resolution
278 //Double_t pno=-(tclasspop[0]*square-mean*mean)*tclasspop[0];
279 //Double_t pdo= mean*mean;
280
281 // variance
282 //Double_t pno=-(square-mean*mean/tclasspop[0]);
283 //Double_t pdo= (tclasspop[0]-1.);
284
285 // n*variance
286 Double_t pno= (square-mean*mean/tclasspop[0]);
287 Double_t pdo= 1.;
288
289 // 1./(n*variance)
290 //Double_t pno= 1.;
291 //Double_t pdo= (square-mean*mean/tclasspop[0]);
292
293 const Double_t crit0=pno/pdo;
294
295 // start main loop through variables to find best split,
296
297 Double_t critmin=1.0e40;
298
299 // random split selection, number of trials = fNumTry
300 for (Int_t mt=0; mt<fNumTry; mt++)
301 {
302 const Int_t mvar=Int_t(gRandom->Rndm()*mdim);
303 const Int_t mn = mvar*numdata;
304
305 Double_t rrn=0, rrd=0, rln=0, rld=0;
306 Double_t esumr=0, esuml=0, e2sumr=0,e2suml=0;
307
308 esumr =mean;
309 e2sumr=square;
310 esuml =0;
311 e2suml=0;
312
313 float wl=0.;// left node
314 wr = tclasspop[0];
315
316 Double_t critvar=critmin;
317 for(Int_t nsp=ndstart;nsp<=ndend-1;nsp++)
318 {
319 const Int_t &nc=datasort[mn+nsp];
320 const Float_t &f=hadtrue[nc];;
321 const Float_t &u=winbag[nc];
322
323 e2sumr-=u*f*f;
324 esumr -=u*f;
325 wr -=u;
326
327 //-------------------------------------------
328 // resolution
329 //rrn=(wr*e2sumr-esumr*esumr)*wr;
330 //rrd=(wr-1.)*esumr*esumr;
331
332 // resolution times n
333 //rrn=(wr*e2sumr-esumr*esumr)*wr;
334 //rrd=esumr*esumr;
335
336 // sigma
337 //rrn=(e2sumr-esumr*esumr/wr);
338 //rrd=(wr-1.);
339
340 // sigma times n
341 rrn=(e2sumr-esumr*esumr/wr);
342 rrd=1.;
343
344 // 1./(n*variance)
345 //rrn=1.;
346 //rrd=(e2sumr-esumr*esumr/wr);
347 //-------------------------------------------
348
349 e2suml+=u*f*f;
350 esuml +=u*f;
351 wl +=u;
352
353 //-------------------------------------------
354 // resolution
355 //rln=(wl*e2suml-esuml*esuml)*wl;
356 //rld=(wl-1.)*esuml*esuml;
357
358 // resolution times n
359 //rln=(wl*e2suml-esuml*esuml)*wl;
360 //rld=esuml*esuml;
361
362 // sigma
363 //rln=(e2suml-esuml*esuml/wl);
364 //rld=(wl-1.);
365
366 // sigma times n
367 rln=(e2suml-esuml*esuml/wl);
368 rld=1.;
369
370 // 1./(n*variance)
371 //rln=1.;
372 //rld=(e2suml-esuml*esuml/wl);
373 //-------------------------------------------
374
375 if (datarang[mn+nc]>=datarang[mn+datasort[mn+nsp+1]])
376 continue;
377
378 if (TMath::Min(rrd,rld)<=1.0e-5)
379 continue;
380
381 const Double_t crit=(rln/rld)+(rrn/rrd);
382
383 if (crit>=critvar) continue;
384
385 nbestvar=nsp;
386 critvar=crit;
387 }
388
389 if (critvar>=critmin) continue;
390
391 msplit=mvar;
392 nbest=nbestvar;
393 critmin=critvar;
394 }
395
396 decsplit=crit0-critmin;
397
398 //return critmin>1.0e20 ? 1 : 0;
399 return decsplit<0 ? 1 : 0;
400}
401
402void MRanTree::MoveData(TArrayI &datasort,Int_t ndstart, Int_t ndend,
403 TArrayI &idmove,TArrayI &ncase,Int_t msplit,
404 Int_t nbest,Int_t &ndendl)
405{
406 // This is the heart of the BuildTree construction. Based on the best split
407 // the data in the part of datasort corresponding to the current node is moved to the
408 // left if it belongs to the left child and right if it belongs to the right child-node.
409 const Int_t numdata = ncase.GetSize();
410 const Int_t mdim = fGiniDec.GetSize();
411
412 TArrayI tdatasort(numdata); tdatasort.Reset(0);
413
414 // compute idmove = indicator of case nos. going left
415 for (Int_t nsp=ndstart;nsp<=ndend;nsp++)
416 {
417 const Int_t &nc=datasort[msplit*numdata+nsp];
418 idmove[nc]= nsp<=nbest?1:0;
419 }
420 ndendl=nbest;
421
422 // shift case. nos. right and left for numerical variables.
423 for(Int_t msh=0;msh<mdim;msh++)
424 {
425 Int_t k=ndstart-1;
426 for (Int_t n=ndstart;n<=ndend;n++)
427 {
428 const Int_t &ih=datasort[msh*numdata+n];
429 if (idmove[ih]==1)
430 tdatasort[++k]=datasort[msh*numdata+n];
431 }
432
433 for (Int_t n=ndstart;n<=ndend;n++)
434 {
435 const Int_t &ih=datasort[msh*numdata+n];
436 if (idmove[ih]==0)
437 tdatasort[++k]=datasort[msh*numdata+n];
438 }
439
440 for(Int_t m=ndstart;m<=ndend;m++)
441 datasort[msh*numdata+m]=tdatasort[m];
442 }
443
444 // compute case nos. for right and left nodes.
445
446 for(Int_t n=ndstart;n<=ndend;n++)
447 ncase[n]=datasort[msplit*numdata+n];
448}
449
450void MRanTree::BuildTree(TArrayI &datasort,const TArrayI &datarang, const TArrayF &hadtrue,
451 const TArrayI &idclass, TArrayI &bestsplit, TArrayI &bestsplitnext,
452 TArrayF &tclasspop, float &tmean, float &tsquare, const TArrayF &winbag,
453 Int_t ninbag, const int nclass)
454{
455 // Buildtree consists of repeated calls to two void functions, FindBestSplit and MoveData.
456 // Findbestsplit does just that--it finds the best split of the current node.
457 // MoveData moves the data in the split node right and left so that the data
458 // corresponding to each child node is contiguous.
459 //
460 // buildtree bookkeeping:
461 // ncur is the total number of nodes to date. nodestatus(k)=1 if the kth node has been split.
462 // nodestatus(k)=2 if the node exists but has not yet been split, and =-1 if the node is
463 // terminal. A node is terminal if its size is below a threshold value, or if it is all
464 // one class, or if all the data-values are equal. If the current node k is split, then its
465 // children are numbered ncur+1 (left), and ncur+2(right), ncur increases to ncur+2 and
466 // the next node to be split is numbered k+1. When no more nodes can be split, buildtree
467 // returns.
468 const Int_t mdim = fGiniDec.GetSize();
469 const Int_t nrnodes = fBestSplit.GetSize();
470 const Int_t numdata = (nrnodes-1)/2;
471
472 TArrayI nodepop(nrnodes); nodepop.Reset(0);
473 TArrayI nodestart(nrnodes); nodestart.Reset(0);
474 TArrayI parent(nrnodes); parent.Reset(0);
475
476 TArrayI ncase(numdata); ncase.Reset(0);
477 TArrayI idmove(numdata); idmove.Reset(0);
478 TArrayI iv(mdim); iv.Reset(0);
479
480 TArrayF classpop(nrnodes*nclass); classpop.Reset(0.);//nclass
481 TArrayI nodestatus(nrnodes); nodestatus.Reset(0);
482
483 for (Int_t j=0;j<nclass;j++)
484 classpop[j*nrnodes+0]=tclasspop[j];
485
486 TArrayF mean(nrnodes); mean.Reset(0.);
487 TArrayF square(nrnodes); square.Reset(0.);
488
489 mean[0]=tmean;
490 square[0]=tsquare;
491
492
493 Int_t ncur=0;
494 nodepop[0]=ninbag;
495 nodestatus[0]=2;
496
497 // start main loop
498 for (Int_t kbuild=0; kbuild<nrnodes; kbuild++)
499 {
500 if (kbuild>ncur) break;
501 if (nodestatus[kbuild]!=2) continue;
502
503 // initialize for next call to FindBestSplit
504
505 const Int_t ndstart=nodestart[kbuild];
506 const Int_t ndend=ndstart+nodepop[kbuild]-1;
507
508 for (Int_t j=0;j<nclass;j++)
509 tclasspop[j]=classpop[j*nrnodes+kbuild];
510
511 tmean=mean[kbuild];
512 tsquare=square[kbuild];
513
514 Int_t msplit, nbest;
515 Float_t decsplit=0;
516
517 if ((*this.*FindBestSplit)(datasort,datarang,hadtrue,idclass,ndstart,
518 ndend, tclasspop,tmean, tsquare,msplit,decsplit,
519 nbest,winbag,nclass))
520 {
521 nodestatus[kbuild]=-1;
522 continue;
523 }
524
525 fBestVar[kbuild]=msplit;
526 fGiniDec[msplit]+=decsplit;
527
528 bestsplit[kbuild]=datasort[msplit*numdata+nbest];
529 bestsplitnext[kbuild]=datasort[msplit*numdata+nbest+1];
530
531 Int_t ndendl;
532 MoveData(datasort,ndstart,ndend,idmove,ncase,
533 msplit,nbest,ndendl);
534
535 // leftnode no.= ncur+1, rightnode no. = ncur+2.
536 nodepop[ncur+1]=ndendl-ndstart+1;
537 nodepop[ncur+2]=ndend-ndendl;
538 nodestart[ncur+1]=ndstart;
539 nodestart[ncur+2]=ndendl+1;
540
541 // find class populations in both nodes
542 for (Int_t n=ndstart;n<=ndendl;n++)
543 {
544 const Int_t &nc=ncase[n];
545 const int j=idclass[nc];
546
547 mean[ncur+1]+=hadtrue[nc]*winbag[nc];
548 square[ncur+1]+=hadtrue[nc]*hadtrue[nc]*winbag[nc];
549
550 classpop[j*nrnodes+ncur+1]+=winbag[nc];
551 }
552
553 for (Int_t n=ndendl+1;n<=ndend;n++)
554 {
555 const Int_t &nc=ncase[n];
556 const int j=idclass[nc];
557
558 mean[ncur+2] +=hadtrue[nc]*winbag[nc];
559 square[ncur+2]+=hadtrue[nc]*hadtrue[nc]*winbag[nc];
560
561 classpop[j*nrnodes+ncur+2]+=winbag[nc];
562 }
563
564 // check on nodestatus
565
566 nodestatus[ncur+1]=2;
567 nodestatus[ncur+2]=2;
568 if (nodepop[ncur+1]<=fNdSize) nodestatus[ncur+1]=-1;
569 if (nodepop[ncur+2]<=fNdSize) nodestatus[ncur+2]=-1;
570
571
572 Double_t popt1=0;
573 Double_t popt2=0;
574 for (Int_t j=0;j<nclass;j++)
575 {
576 popt1+=classpop[j*nrnodes+ncur+1];
577 popt2+=classpop[j*nrnodes+ncur+2];
578 }
579
580 if(fClassify)
581 {
582 // check if only members of one class in node
583 for (Int_t j=0;j<nclass;j++)
584 {
585 if (classpop[j*nrnodes+ncur+1]==popt1) nodestatus[ncur+1]=-1;
586 if (classpop[j*nrnodes+ncur+2]==popt2) nodestatus[ncur+2]=-1;
587 }
588 }
589
590 fTreeMap1[kbuild]=ncur+1;
591 fTreeMap2[kbuild]=ncur+2;
592 parent[ncur+1]=kbuild;
593 parent[ncur+2]=kbuild;
594 nodestatus[kbuild]=1;
595 ncur+=2;
596 if (ncur>=nrnodes) break;
597 }
598
599 // determine number of nodes
600 fNumNodes=nrnodes;
601 for (Int_t k=nrnodes-1;k>=0;k--)
602 {
603 if (nodestatus[k]==0) fNumNodes-=1;
604 if (nodestatus[k]==2) nodestatus[k]=-1;
605 }
606
607 fNumEndNodes=0;
608 for (Int_t kn=0;kn<fNumNodes;kn++)
609 if(nodestatus[kn]==-1)
610 {
611 fNumEndNodes++;
612
613 Double_t pp=0;
614 for (Int_t j=0;j<nclass;j++)
615 {
616 if(classpop[j*nrnodes+kn]>pp)
617 {
618 // class + status of node kn coded into fBestVar[kn]
619 fBestVar[kn]=j-nclass;
620 pp=classpop[j*nrnodes+kn];
621 }
622 }
623
624 float sum=0;
625 for(int i=0;i<nclass;i++) sum+=classpop[i*nrnodes+kn];
626
627 fBestSplit[kn]=mean[kn]/sum;
628 }
629}
630
631Double_t MRanTree::TreeHad(const TVector &event)
632{
633 Int_t kt=0;
634 // to optimize on storage space node status and node class
635 // are coded into fBestVar:
636 // status of node kt = TMath::Sign(1,fBestVar[kt])
637 // class of node kt = fBestVar[kt]+2 (class defined by larger
638 // node population, actually not used)
639 // hadronness assigned to node kt = fBestSplit[kt]
640
641 for (Int_t k=0;k<fNumNodes;k++)
642 {
643 if (fBestVar[kt]<0)
644 break;
645
646 const Int_t m=fBestVar[kt];
647 kt = event(m)<=fBestSplit[kt] ? fTreeMap1[kt] : fTreeMap2[kt];
648 }
649
650 return fBestSplit[kt];
651}
652
653Double_t MRanTree::TreeHad(const TMatrixRow &event)
654{
655 Int_t kt=0;
656 // to optimize on storage space node status and node class
657 // are coded into fBestVar:
658 // status of node kt = TMath::Sign(1,fBestVar[kt])
659 // class of node kt = fBestVar[kt]+2 (class defined by larger
660 // node population, actually not used)
661 // hadronness assigned to node kt = fBestSplit[kt]
662
663 for (Int_t k=0;k<fNumNodes;k++)
664 {
665 if (fBestVar[kt]<0)
666 break;
667
668 const Int_t m=fBestVar[kt];
669 kt = event(m)<=fBestSplit[kt] ? fTreeMap1[kt] : fTreeMap2[kt];
670 }
671
672 return fBestSplit[kt];
673}
674
675Double_t MRanTree::TreeHad(const TMatrix &m, Int_t ievt)
676{
677#if ROOT_VERSION_CODE < ROOT_VERSION(4,00,8)
678 return TreeHad(TMatrixRow(m, ievt));
679#else
680 return TreeHad(TMatrixFRow_const(m, ievt));
681#endif
682}
683
684Bool_t MRanTree::AsciiWrite(ostream &out) const
685{
686 TString str;
687 Int_t k;
688
689 out.width(5);out<<fNumNodes<<endl;
690
691 for (k=0;k<fNumNodes;k++)
692 {
693 str=Form("%f",GetBestSplit(k));
694
695 out.width(5); out << k;
696 out.width(5); out << GetNodeStatus(k);
697 out.width(5); out << GetTreeMap1(k);
698 out.width(5); out << GetTreeMap2(k);
699 out.width(5); out << GetBestVar(k);
700 out.width(15); out << str<<endl;
701 out.width(5); out << GetNodeClass(k);
702 }
703 out<<endl;
704
705 return k==fNumNodes;
706}
Note: See TracBrowser for help on using the repository browser.