@@ -419,52 +419,70 @@ func (po *poset) aliasnewnode(n1, n2 *Value) {
419
419
po .upushalias (n2 .ID , 0 )
420
420
}
421
421
422
- // aliasnode records that n2 (already in the poset) is an alias of n1
423
- func (po * poset ) aliasnode (n1 , n2 * Value ) {
422
+ // aliasnodes records that all the nodes i2s are aliases of a single master node n1.
423
+ // aliasnodes takes care of rearranging the DAG, changing references of parent/children
424
+ // of nodes in i2s, so that they point to n1 instead.
425
+ // Complexity is O(n) (with n being the total number of nodes in the poset, not just
426
+ // the number of nodes being aliased).
427
+ func (po * poset ) aliasnodes (n1 * Value , i2s bitset ) {
424
428
i1 := po .values [n1 .ID ]
425
429
if i1 == 0 {
426
430
panic ("aliasnode for non-existing node" )
427
431
}
428
-
429
- i2 := po .values [n2 .ID ]
430
- if i2 == 0 {
431
- panic ("aliasnode for non-existing node" )
432
+ if i2s .Test (i1 ) {
433
+ panic ("aliasnode i2s contains n1 node" )
432
434
}
433
- // Rename all references to i2 into i1
434
- // (do not touch i1 itself, otherwise we can create useless self-loops)
435
+
436
+ // Go through all the nodes to adjust parent/chidlren of nodes in i2s
435
437
for idx , n := range po .nodes {
436
- if uint32 (idx ) != i1 {
437
- l , r := n .l , n .r
438
- if l .Target () == i2 {
439
- po .setchl (uint32 (idx ), newedge (i1 , l .Strict ()))
440
- po .upush (undoSetChl , uint32 (idx ), l )
438
+ // Do not touch i1 itself, otherwise we can create useless self-loops
439
+ if uint32 (idx ) == i1 {
440
+ continue
441
+ }
442
+ l , r := n .l , n .r
443
+
444
+ // Rename all references to i2s into i1
445
+ if i2s .Test (l .Target ()) {
446
+ po .setchl (uint32 (idx ), newedge (i1 , l .Strict ()))
447
+ po .upush (undoSetChl , uint32 (idx ), l )
448
+ }
449
+ if i2s .Test (r .Target ()) {
450
+ po .setchr (uint32 (idx ), newedge (i1 , r .Strict ()))
451
+ po .upush (undoSetChr , uint32 (idx ), r )
452
+ }
453
+
454
+ // Connect all chidren of i2s to i1 (unless those children
455
+ // are in i2s as well, in which case it would be useless)
456
+ if i2s .Test (uint32 (idx )) {
457
+ if l != 0 && ! i2s .Test (l .Target ()) {
458
+ po .addchild (i1 , l .Target (), l .Strict ())
441
459
}
442
- if r .Target () == i2 {
443
- po .setchr (uint32 (idx ), newedge (i1 , r .Strict ()))
444
- po .upush (undoSetChr , uint32 (idx ), r )
460
+ if r != 0 && ! i2s .Test (r .Target ()) {
461
+ po .addchild (i1 , r .Target (), r .Strict ())
445
462
}
463
+ po .setchl (uint32 (idx ), 0 )
464
+ po .setchr (uint32 (idx ), 0 )
465
+ po .upush (undoSetChl , uint32 (idx ), l )
466
+ po .upush (undoSetChr , uint32 (idx ), r )
446
467
}
447
468
}
448
469
449
470
// Reassign all existing IDs that point to i2 to i1.
450
471
// This includes n2.ID.
451
472
for k , v := range po .values {
452
- if v == i2 {
473
+ if i2s . Test ( v ) {
453
474
po .values [k ] = i1
454
- po .upushalias (k , i2 )
475
+ po .upushalias (k , v )
455
476
}
456
477
}
457
478
458
- if n2 .isGenericIntConst () {
459
- val := n2 .AuxInt
460
- if po .flags & posetFlagUnsigned != 0 {
461
- val = int64 (n2 .AuxUnsigned ())
462
- }
463
- if po .constants [val ] != i2 {
464
- panic ("aliasing constant which is not registered" )
479
+ // If one of the aliased nodes is a constant, then make sure
480
+ // po.constants is updated to point to the master node.
481
+ for val , idx := range po .constants {
482
+ if i2s .Test (idx ) {
483
+ po .constants [val ] = i1
484
+ po .upushconst (i1 , idx )
465
485
}
466
- po .constants [val ] = i1
467
- po .upushconst (i1 , i2 )
468
486
}
469
487
}
470
488
@@ -623,7 +641,9 @@ func (po *poset) collapsepath(n1, n2 *Value) bool {
623
641
// TODO: for now, only handle the simple case of i2 being child of i1
624
642
l , r := po .children (i1 )
625
643
if l .Target () == i2 || r .Target () == i2 {
626
- po .aliasnode (n1 , n2 )
644
+ i2s := newBitset (int (po .lastidx ) + 1 )
645
+ i2s .Set (i2 )
646
+ po .aliasnodes (n1 , i2s )
627
647
po .addchild (i1 , i2 , false )
628
648
return true
629
649
}
@@ -1135,11 +1155,9 @@ func (po *poset) SetEqual(n1, n2 *Value) bool {
1135
1155
1136
1156
// Set n2 as alias of n1. This will also update all the references
1137
1157
// to n2 to become references to n1
1138
- po .aliasnode (n1 , n2 )
1139
-
1140
- // Connect i2 (now dummy) as child of i1. This allows to keep the correct
1141
- // order with its children.
1142
- po .addchild (i1 , i2 , false )
1158
+ i2s := newBitset (int (po .lastidx ) + 1 )
1159
+ i2s .Set (i2 )
1160
+ po .aliasnodes (n1 , i2s )
1143
1161
}
1144
1162
return true
1145
1163
}
0 commit comments