File indexing completed on 2026-04-09 07:49:24
0001 #pragma once
0002
0003 #include "scanvas.h"
0004
0005
0006 enum {
0007 IN,
0008 RIN,
0009 PRE,
0010 RPRE,
0011 POST,
0012 RPOST
0013 };
0014
0015 struct u
0016 {
0017 static const char* IN_ ;
0018 static const char* RIN_ ;
0019 static const char* PRE_ ;
0020 static const char* RPRE_ ;
0021 static const char* POST_ ;
0022 static const char* RPOST_ ;
0023 static const char* OrderName(int order);
0024 };
0025
0026 const char* u::IN_ = "IN" ;
0027 const char* u::RIN_ = "RIN" ;
0028 const char* u::PRE_ = "PRE" ;
0029 const char* u::RPRE_ = "RPRE" ;
0030 const char* u::POST_ = "POST" ;
0031 const char* u::RPOST_ = "RPOST" ;
0032
0033 const char* u::OrderName(int order)
0034 {
0035 const char* s = nullptr ;
0036 switch(order)
0037 {
0038 case IN: s = IN_ ; break ;
0039 case RIN: s = RIN_ ; break ;
0040 case PRE: s = PRE_ ; break ;
0041 case RPRE: s = RPRE_ ; break ;
0042 case POST: s = POST_ ; break ;
0043 case RPOST: s = RPOST_ ; break ;
0044 }
0045 return s ;
0046 }
0047
0048
0049
0050 enum {
0051 UNDEFINED = 0,
0052 INCLUDE = 1<<0 ,
0053 EXCLUDE = 1<<1 ,
0054 MIXED = INCLUDE | EXCLUDE
0055 };
0056
0057 char pcls( int cls )
0058 {
0059 char pcl = '_' ;
0060 switch( cls )
0061 {
0062 case UNDEFINED: pcl = 'U' ; break ;
0063 case INCLUDE: pcl = 'I' ; break ;
0064 case EXCLUDE: pcl = 'E' ; break ;
0065 case MIXED: pcl = 'X' ; break ;
0066 default: pcl = '?' ; break ;
0067 }
0068 return pcl ;
0069 }
0070
0071 struct nd
0072 {
0073 int value ;
0074 nd* left ;
0075 nd* right ;
0076
0077 nd( int value, nd* left=nullptr, nd* right=nullptr );
0078
0079 const char* desc() const ;
0080 bool is_prim() const ;
0081 bool is_boolean() const ;
0082 bool is_bileaf() const ;
0083 bool is_mixed() const ;
0084 bool is_cut_right() const ;
0085 bool is_cut_left() const ;
0086 bool is_crux() const ;
0087
0088 int cls ;
0089 int depth ;
0090
0091 int in ;
0092 int rin ;
0093 int pre ;
0094 int rpre ;
0095 int post ;
0096 int rpost ;
0097
0098 int index(int order) const ;
0099
0100 char mkr ;
0101
0102 };
0103
0104
0105 int nd::index(int order) const
0106 {
0107 int idx = -1 ;
0108 switch(order)
0109 {
0110 case IN: idx=in ; break ;
0111 case RIN: idx=rin ; break ;
0112 case PRE: idx=pre ; break ;
0113 case RPRE: idx=rpre ; break ;
0114 case POST: idx=post ; break ;
0115 case RPOST: idx=rpost ; break ;
0116 }
0117 return idx ;
0118 }
0119
0120
0121 nd::nd(int value_, nd* left_, nd* right_)
0122 :
0123 value(value_),
0124 left(left_),
0125 right(right_),
0126 cls(UNDEFINED),
0127 depth(UNDEFINED),
0128 in(UNDEFINED),
0129 rin(UNDEFINED),
0130 pre(UNDEFINED),
0131 rpre(UNDEFINED),
0132 post(UNDEFINED),
0133 rpost(UNDEFINED),
0134 mkr('_')
0135 {
0136 }
0137
0138 const char* nd::desc() const
0139 {
0140 char tmp[30] ;
0141 snprintf(tmp, 30, "%d:%c:%c", value, pcls(cls), mkr );
0142 return strdup(tmp);
0143 }
0144
0145 bool nd::is_prim() const { return left == nullptr && right == nullptr ; }
0146 bool nd::is_boolean() const { return left != nullptr && right != nullptr ; }
0147 bool nd::is_bileaf() const { return is_boolean() && left->is_prim() && right->is_prim() ; }
0148 bool nd::is_mixed() const { return cls == MIXED ; }
0149 bool nd::is_cut_right() const { return is_boolean() && left->cls == INCLUDE && right->cls == EXCLUDE ; }
0150 bool nd::is_cut_left() const { return is_boolean() && left->cls == EXCLUDE && right->cls == INCLUDE ; }
0151 bool nd::is_crux() const { return is_cut_right() ^ is_cut_left() ; }
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237 struct tree
0238 {
0239 static const int ORDER1 ;
0240 static const int ORDER2 ;
0241
0242 static int NumNode(int height);
0243 static tree* make_complete(int height);
0244 static tree* make_unbalanced(int numprim);
0245 static nd* build_r(int h, int& count );
0246 static void initvalue_r( nd* n, int order );
0247
0248 bool verbose ;
0249 nd* root ;
0250 int width ;
0251 int height ;
0252 int xscale ;
0253 int yscale ;
0254
0255 scanvas* canvas ;
0256 int value_order ;
0257
0258 std::vector<nd*> inorder ;
0259 std::vector<nd*> rinorder ;
0260 std::vector<nd*> preorder ;
0261 std::vector<nd*> rpreorder ;
0262 std::vector<nd*> postorder ;
0263 std::vector<nd*> rpostorder ;
0264
0265 std::vector<nd*> crux ;
0266 std::map<nd*, nd*> parentmap ;
0267
0268 tree( nd* root );
0269
0270 void instrument();
0271 void initvalue(int order) ;
0272
0273 void inorder_r( nd* n );
0274 void rinorder_r( nd* n );
0275 void preorder_r( nd* n );
0276 void rpreorder_r( nd* n );
0277 void postorder_r( nd* n );
0278 void rpostorder_r( nd* n );
0279
0280 void parent_r( nd* n, int depth );
0281 void depth_r( nd* n, int depth );
0282 void clear_mkr();
0283 void clear_mkr_r( nd* n );
0284
0285 int num_prim() const ;
0286 int num_prim_r( nd* n ) const ;
0287
0288 int num_node(int qcls) const ;
0289 static int num_node_r( nd* n, int qcls);
0290 int num_node() const ;
0291 static int num_node_r( nd* n) ;
0292
0293 const char* desc() const ;
0294
0295 nd* parent( nd* n ) const ;
0296
0297 void dump(const char* msg) const ;
0298 void dump_r( nd* n ) const ;
0299
0300 int maxdepth_r(nd* n, int depth) const ;
0301 int maxdepth() const ;
0302
0303 void draw(const char* msg=nullptr, int meta=-1);
0304 void draw_r( nd* n );
0305
0306 void apply_cut(int cut);
0307
0308 void classify( int cut );
0309 int classify_r( nd* n, int cut );
0310
0311 void prune( bool act, int pass );
0312 void prune_crux( nd* n, bool act, int pass );
0313 };
0314
0315
0316 int tree::NumNode(int height){ return (1 << (height+1)) - 1 ; }
0317
0318
0319 nd* tree::build_r(int h, int& count)
0320 {
0321 nd* l = h > 0 ? build_r( h-1, count) : nullptr ;
0322 nd* r = h > 0 ? build_r( h-1, count ) : nullptr ;
0323 return new nd( count++, l, r) ;
0324 }
0325
0326 tree* tree::make_complete(int height)
0327 {
0328 int count = 0 ;
0329 nd* root = build_r(height, count );
0330 tree* t = new tree(root);
0331 return t ;
0332 }
0333
0334 tree* tree::make_unbalanced(int numprim)
0335 {
0336 nd* root = new nd(0) ;
0337 for(unsigned i=1 ; i < numprim ; i++)
0338 {
0339 nd* right = new nd(i) ;
0340 root = new nd(i, root, right) ;
0341 }
0342 tree* t = new tree(root);
0343 return t ;
0344 }
0345
0346
0347
0348 tree::tree(nd* root_)
0349 :
0350 verbose(getenv("VERBOSE")!=nullptr),
0351 root(root_),
0352 width(num_node_r(root)),
0353 height(maxdepth_r(root,0)),
0354 xscale(5),
0355 yscale(4),
0356 canvas(new scanvas(width,height+1,xscale,yscale)),
0357 value_order(-1)
0358 {
0359 instrument();
0360 initvalue_r(root, PRE);
0361 }
0362
0363 void tree::instrument()
0364 {
0365 if(!root) return ;
0366 clear_mkr();
0367
0368
0369 inorder.clear();
0370 inorder_r(root);
0371
0372 rinorder.clear();
0373 rinorder_r(root);
0374
0375 preorder.clear();
0376 preorder_r(root);
0377
0378 rpreorder.clear();
0379 rpreorder_r(root);
0380
0381 postorder.clear();
0382 postorder_r(root);
0383
0384 rpostorder.clear();
0385 rpostorder_r(root);
0386
0387
0388 parentmap.clear();
0389 parentmap[root] = nullptr ;
0390 parent_r(root, 0 );
0391
0392 depth_r(root, 0);
0393
0394 width = num_node_r(root) ;
0395 height = maxdepth_r(root,0) ;
0396 canvas->resize(width, height+1);
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410 void tree::initvalue(int order_ )
0411 {
0412 value_order = order_ ;
0413 initvalue_r(root, value_order);
0414 }
0415 void tree::initvalue_r( nd* n, int order )
0416 {
0417 if( n == nullptr ) return ;
0418 initvalue_r( n->left, order );
0419 initvalue_r( n->right, order );
0420 n->value = n->index(order);
0421 }
0422
0423 int tree::maxdepth_r(nd* n, int depth) const
0424 {
0425 return n->left && n->right ? std::max( maxdepth_r( n->left, depth+1), maxdepth_r(n->right, depth+1)) : depth ;
0426 }
0427 int tree::maxdepth() const
0428 {
0429 return maxdepth_r( root, 0 );
0430 }
0431
0432 int tree::num_prim_r(nd* n) const
0433 {
0434 if(!n) return 0 ;
0435 return ( n->left && n->right ) ? num_prim_r( n->left) + num_prim_r(n->right) : 1 ;
0436 }
0437 int tree::num_prim() const
0438 {
0439 return num_prim_r(root);
0440 }
0441 int tree::num_node() const
0442 {
0443 return num_node_r(root) ;
0444 }
0445 int tree::num_node_r(nd* n)
0446 {
0447 int num = n ? 1 : 0 ;
0448 if( n && n->left && n->right )
0449 {
0450 num += num_node_r( n->left );
0451 num += num_node_r( n->right );
0452 }
0453 return num ;
0454 }
0455 int tree::num_node_r(nd* n, int qcls)
0456 {
0457 int num = ( n && n->cls == qcls ) ? 1 : 0 ;
0458 if( n && n->left && n->right )
0459 {
0460 num += num_node_r( n->left, qcls );
0461 num += num_node_r( n->right, qcls );
0462 }
0463 return num ;
0464 }
0465 int tree::num_node(int cls) const
0466 {
0467 return num_node_r(root, cls);
0468 }
0469
0470 const char* tree::desc() const
0471 {
0472 char tmp[100];
0473 int num_undefined = num_node(UNDEFINED);
0474 int num_exclude = num_node(EXCLUDE);
0475 int num_include = num_node(INCLUDE);
0476 int num_mixed = num_node(MIXED);
0477 int num_prim_ = num_prim();
0478
0479 snprintf(tmp, 100, "UN:%d EX:%d IN:%d MX:%d prim:%d",num_undefined, num_exclude, num_include, num_mixed, num_prim_ );
0480 return strdup(tmp);
0481 }
0482
0483 nd* tree::parent( nd* n ) const
0484 {
0485 return parentmap.count(n) == 1 ? parentmap.at(n) : nullptr ;
0486 }
0487
0488 void tree::depth_r( nd* n, int d )
0489 {
0490 if( n == nullptr ) return ;
0491 depth_r( n->left , d+1 );
0492 depth_r( n->right, d+1 );
0493 n->depth = d ;
0494 }
0495
0496 void tree::clear_mkr()
0497 {
0498 clear_mkr_r(root);
0499 }
0500
0501 void tree::clear_mkr_r( nd* n )
0502 {
0503 if( n == nullptr ) return ;
0504 clear_mkr_r( n->left );
0505 clear_mkr_r( n->right );
0506 n->mkr = '_' ;
0507 }
0508
0509 void tree::parent_r( nd* n, int depth )
0510 {
0511 if( n->is_boolean() )
0512 {
0513 parent_r( n->left, depth+1 );
0514 parent_r( n->right, depth+1 );
0515
0516 parentmap[n->left] = n ;
0517 parentmap[n->right] = n ;
0518 }
0519 }
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530 void tree::apply_cut(int cut)
0531 {
0532 if(verbose)
0533 printf("tree::apply_cut %d \n", cut );
0534
0535 unsigned pass = 0 ;
0536 unsigned maxpass = 10 ;
0537
0538 while( root != nullptr && root->cls != INCLUDE && pass < maxpass )
0539 {
0540 classify(cut);
0541 prune(false, pass);
0542
0543 if(verbose)
0544 draw("tree::apply_cut before prune", pass );
0545
0546 prune(true, pass );
0547
0548 classify(cut);
0549 instrument();
0550
0551 if(verbose)
0552 draw("tree::apply_cut after prune and re-classify", pass );
0553
0554 pass++ ;
0555 }
0556
0557 printf("tree::apply_cut pass %d \n", pass);
0558 }
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571 void tree::classify( int cut )
0572 {
0573 crux.clear();
0574 classify_r( root, cut );
0575
0576 }
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590 int tree::classify_r( nd* n, int cut )
0591 {
0592 if(!n) return UNDEFINED ;
0593 n->cls = UNDEFINED ;
0594 if( n->left && n->right )
0595 {
0596 n->cls |= classify_r( n->left , cut ) ;
0597 n->cls |= classify_r( n->right, cut ) ;
0598
0599 if( n->is_crux() )
0600 {
0601 n->mkr = '*' ;
0602 crux.push_back(n) ;
0603
0604 if(verbose)
0605 printf("tree::classify_r set crux %s \n", n->desc() );
0606 }
0607 }
0608 else
0609 {
0610 n->cls = n->value >= cut ? EXCLUDE : INCLUDE ;
0611 }
0612 return n->cls ;
0613 }
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648 void tree::prune(bool act, int pass)
0649 {
0650 int num_include = num_node(INCLUDE) ;
0651
0652 if(verbose)
0653 printf("tree::prune num_include %d \n", num_include);
0654
0655 if( num_include == 0)
0656 {
0657 if(verbose)
0658 printf("tree::prune find zero remaining nodes : num_include %d, will set root to nullptr \n", num_include);
0659
0660 if(act)
0661 {
0662 if(verbose)
0663 printf("tree::prune setting root to nullptr \n");
0664
0665 root = nullptr ;
0666 }
0667 }
0668
0669 if(crux.size() == 0 ) return ;
0670 assert(crux.size() == 1) ;
0671
0672 nd* x = crux[0] ;
0673 prune_crux(x, act, pass);
0674 }
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712 void tree::prune_crux( nd* x, bool act, int pass )
0713 {
0714 assert( x && x->is_crux() );
0715 bool cut_left = x->is_cut_left() ;
0716 bool cut_right = x->is_cut_right() ;
0717 assert( cut_left ^ cut_right );
0718
0719 nd* survivor = cut_right ? x->left : x->right ;
0720 assert( survivor );
0721 survivor->mkr = 'S' ;
0722 nd* p = parent(x);
0723
0724 if( p->cls != INCLUDE )
0725 {
0726 printf("tree::prune_crux act:%d pass:%d parent disqualified as not INCLUDE : handle as root(of the new tree) prune \n", act, pass);
0727 p = nullptr ;
0728 }
0729
0730 if( p != nullptr )
0731 {
0732 p->mkr = 'P' ;
0733
0734 if( x == p->left )
0735 {
0736 if(act)
0737 {
0738 if(verbose)
0739 printf("tree::prune_crux act:%d pass:%d setting p->left %s to survivor %s \n", act, pass, p->left->desc(), survivor->desc() );
0740 p->left = survivor ;
0741 }
0742 }
0743 else if( x == p->right )
0744 {
0745 if(act)
0746 {
0747 if(verbose)
0748 printf("tree::prune_crux act:%d pass:%d setting p->right %s to survivor %s \n", act, pass, p->right->desc(), survivor->desc() );
0749 p->right = survivor ;
0750 }
0751 }
0752 }
0753 else
0754 {
0755 if( act )
0756 {
0757 if(verbose)
0758 printf("tree::prune_crux act:%d pass:%d changing root to survivor\n", act, pass);
0759 root = survivor ;
0760 }
0761 }
0762 if(act)
0763 {
0764 instrument();
0765 }
0766 }
0767
0768
0769 void tree::inorder_r( nd* n )
0770 {
0771 if( n == nullptr ) return ;
0772
0773 inorder_r(n->left) ;
0774
0775 n->in = inorder.size() ; inorder.push_back(n);
0776
0777 inorder_r(n->right) ;
0778 }
0779 void tree::rinorder_r( nd* n )
0780 {
0781 if( n == nullptr ) return ;
0782
0783 rinorder_r(n->right) ;
0784
0785 n->rin = rinorder.size() ; rinorder.push_back(n);
0786
0787 rinorder_r(n->left) ;
0788 }
0789
0790
0791 void tree::preorder_r( nd* n )
0792 {
0793 if( n == nullptr ) return ;
0794 n->pre = preorder.size() ; preorder.push_back(n);
0795
0796 preorder_r(n->left) ;
0797 preorder_r(n->right) ;
0798 }
0799 void tree::rpreorder_r( nd* n )
0800 {
0801 if( n == nullptr ) return ;
0802 n->rpre = rpreorder.size() ; rpreorder.push_back(n);
0803
0804 rpreorder_r(n->right) ;
0805 rpreorder_r(n->left) ;
0806 }
0807
0808
0809 void tree::postorder_r( nd* n )
0810 {
0811 if( n == nullptr ) return ;
0812
0813 postorder_r(n->left) ;
0814 postorder_r(n->right) ;
0815
0816 n->post = postorder.size() ; postorder.push_back(n);
0817 }
0818 void tree::rpostorder_r( nd* n )
0819 {
0820 if( n == nullptr ) return ;
0821
0822 rpostorder_r(n->right) ;
0823 rpostorder_r(n->left) ;
0824
0825 n->rpost = rpostorder.size() ; rpostorder.push_back(n);
0826 }
0827
0828 void tree::dump( const char* msg ) const
0829 {
0830 printf("%s\n",msg);
0831 dump_r(root);
0832 }
0833
0834 void tree::dump_r( nd* n ) const
0835 {
0836 if( n == nullptr ) return ;
0837 dump_r( n->left );
0838 dump_r( n->right );
0839 printf(" value %2d depth %2d mkr %c cls %c\n", n->value, n->depth, n->mkr, pcls(n->cls) ) ;
0840 }
0841
0842
0843 const int tree::ORDER1 = RPRE ;
0844 const int tree::ORDER2 = POST ;
0845
0846 void tree::draw(const char* msg, int meta)
0847 {
0848 if(!root) return ;
0849 if(msg) printf("%s [%d] \n", msg, meta );
0850 canvas->clear();
0851
0852 printf("vorder : %s \n", u::OrderName(value_order) );
0853 printf("order1 : %s \n", u::OrderName(ORDER1) );
0854
0855
0856 draw_r(root);
0857 canvas->print();
0858 }
0859
0860 void tree::draw_r( nd* n )
0861 {
0862 if( n == nullptr ) return ;
0863 draw_r( n->left );
0864 draw_r( n->right );
0865
0866 int x = n->in ;
0867 int y = n->depth ;
0868
0869 canvas->draw( x, y, 0,0, n->value );
0870 canvas->draw( x, y, 0,1, n->index(ORDER1));
0871
0872 canvas->drawch( x, y, 0,2, pcls(n->cls) );
0873 canvas->drawch( x, y, 0,3, n->mkr );
0874 }
0875
0876