@@ -158,7 +158,7 @@ RewritePath::findRulesAppearingOnceInEmptyContext() const {
158
158
for (auto step : Steps) {
159
159
switch (step.Kind ) {
160
160
case RewriteStep::ApplyRewriteRule: {
161
- if (step.StartOffset == 0 && step. EndOffset == 0 )
161
+ if (! step.isInContext () )
162
162
rulesInEmptyContext.insert (step.RuleID );
163
163
164
164
++ruleMultiplicity[step.RuleID ];
@@ -216,8 +216,7 @@ RewritePath RewritePath::splitCycleAtRule(unsigned ruleID) const {
216
216
break ;
217
217
218
218
assert (!sawRule && " Rule appears more than once?" );
219
- assert (step.StartOffset == 0 || step.EndOffset == 0 &&
220
- " Rule appears in context?" );
219
+ assert (!step.isInContext () && " Rule appears in context?" );
221
220
222
221
ruleWasInverted = step.Inverse ;
223
222
sawRule = true ;
@@ -460,6 +459,7 @@ bool RewritePath::computeCyclicallyReducedLoop(MutableTerm &basepoint,
460
459
return count > 0 ;
461
460
}
462
461
462
+ // / Apply the interchange rule until fixed point (see maybeSwapRewriteSteps()).
463
463
bool RewritePath::computeLeftCanonicalForm (const RewriteSystem &system) {
464
464
bool changed = false ;
465
465
@@ -491,36 +491,103 @@ void RewritePath::dump(llvm::raw_ostream &out,
491
491
}
492
492
}
493
493
494
- // / Use the 3-cells to delete rewrite rules, updating and simplifying existing
495
- // / 3-cells as each rule is deleted.
496
- void RewriteSystem::minimizeRewriteSystem () {
497
- llvm::SmallDenseSet<unsigned > deletedRules;
498
- llvm::SmallDenseSet<unsigned > deletedHomotopyGenerators;
494
+ // / Compute cyclically-reduced left-canonical normal form of a 3-cell.
495
+ void HomotopyGenerator::normalize (const RewriteSystem &system) {
496
+ // FIXME: This can be more efficient.
497
+ bool changed;
498
+ do {
499
+ changed = false ;
500
+ changed |= Path.computeFreelyReducedPath ();
501
+ changed |= Path.computeCyclicallyReducedLoop (Basepoint, system);
502
+ changed |= Path.computeLeftCanonicalForm (system);
503
+ } while (changed);
504
+ }
499
505
500
- auto findRuleToDelete = [&]() -> Optional<std::pair< unsigned , RewritePath>> {
501
- for ( unsigned loopID : indices (HomotopyGenerators)) {
502
- if (deletedHomotopyGenerators. count (loopID))
503
- continue ;
506
+ // / A 3-cell is "in context" if every rewrite step has a left or right whisker.
507
+ bool HomotopyGenerator::isInContext () const {
508
+ unsigned minStartOffset = ( unsigned ) - 1 ;
509
+ unsigned minEndOffset = ( unsigned ) - 1 ;
504
510
505
- const auto &loop = HomotopyGenerators[loopID];
511
+ for (const auto &step : Path) {
512
+ switch (step.Kind ) {
513
+ case RewriteStep::ApplyRewriteRule:
514
+ minStartOffset = std::min (minStartOffset, step.StartOffset );
515
+ minEndOffset = std::min (minEndOffset, step.EndOffset );
516
+ break ;
506
517
507
- SmallVector<unsigned > redundancyCandidates =
508
- loop.Path .findRulesAppearingOnceInEmptyContext ();
509
- if (redundancyCandidates.empty ())
510
- continue ;
518
+ case RewriteStep::AdjustConcreteType:
519
+ break ;
520
+ }
511
521
512
- auto ruleID = redundancyCandidates.front ();
513
- RewritePath replacementPath = loop.Path .splitCycleAtRule (ruleID);
522
+ if (minStartOffset == 0 && minEndOffset == 0 )
523
+ break ;
524
+ }
514
525
515
- deletedRules. insert (ruleID );
516
- deletedHomotopyGenerators. insert (loopID);
526
+ return (minStartOffset > 0 || minEndOffset > 0 );
527
+ }
517
528
518
- return std::make_pair (ruleID, replacementPath);
519
- }
529
+ void HomotopyGenerator::dump (llvm::raw_ostream &out,
530
+ const RewriteSystem &system) const {
531
+ out << Basepoint << " : " ;
532
+ Path.dump (out, Basepoint, system);
533
+ if (isDeleted ())
534
+ out << " [deleted]" ;
535
+ }
520
536
521
- return None;
522
- };
537
+ Optional<unsigned >
538
+ RewriteSystem::findRuleToDelete (RewritePath &replacementPath) {
539
+ for (auto &loop : HomotopyGenerators) {
540
+ if (loop.isDeleted ())
541
+ continue ;
542
+
543
+ SmallVector<unsigned > redundancyCandidates =
544
+ loop.Path .findRulesAppearingOnceInEmptyContext ();
545
+
546
+ auto found = std::find_if (
547
+ redundancyCandidates.begin (),
548
+ redundancyCandidates.end (),
549
+ [&](unsigned ruleID) -> bool {
550
+ const auto &rule = getRule (ruleID);
551
+
552
+ // We should not find a rule that has already been marked redundant
553
+ // here; it should have already been replaced with a rewrite path
554
+ // in all homotopy generators.
555
+ assert (!rule.isRedundant ());
556
+
557
+ // Associated type introduction rules are 'permanent'. They're
558
+ // not worth eliminating since they are re-added every time; it
559
+ // is better to find other candidates to eliminate in the same
560
+ // 3-cell instead.
561
+ if (rule.isPermanent ())
562
+ return false ;
563
+
564
+ // Protocol conformance rules are eliminated via a different
565
+ // algorithm which computes "generating conformances".
566
+ if (rule.isProtocolConformanceRule ())
567
+ return false ;
568
+
569
+ return true ;
570
+ });
571
+
572
+ if (found == redundancyCandidates.end ())
573
+ continue ;
574
+
575
+ auto ruleID = *found;
576
+ assert (replacementPath.empty ());
577
+ replacementPath = loop.Path .splitCycleAtRule (ruleID);
578
+
579
+ loop.markDeleted ();
580
+ getRule (ruleID).markRedundant ();
581
+
582
+ return ruleID;
583
+ }
584
+
585
+ return None;
586
+ }
523
587
588
+ // / Use the 3-cells to delete rewrite rules, updating and simplifying existing
589
+ // / 3-cells as each rule is deleted.
590
+ void RewriteSystem::minimizeRewriteSystem () {
524
591
auto deleteRule = [&](unsigned ruleID, RewritePath replacementPath) {
525
592
if (Debug.contains (DebugFlags::HomotopyReduction)) {
526
593
const auto &rule = getRule (ruleID);
@@ -533,74 +600,63 @@ void RewriteSystem::minimizeRewriteSystem() {
533
600
llvm::dbgs () << " \n " ;
534
601
}
535
602
536
- for (unsigned loopID : indices (HomotopyGenerators)) {
537
- if (deletedHomotopyGenerators.count (loopID))
603
+ // Replace all occurrences of the rule with the replacement path and
604
+ // normalize all 3-cells.
605
+ for (auto &loop : HomotopyGenerators) {
606
+ if (loop.isDeleted ())
538
607
continue ;
539
608
540
- auto &loop = HomotopyGenerators[loopID];
541
609
bool changed = loop.Path .replaceRuleWithPath (ruleID, replacementPath);
610
+ if (!changed)
611
+ continue ;
542
612
543
- if (changed) {
544
- unsigned size = loop.Path .size ();
613
+ unsigned size = loop.Path .size ();
545
614
546
- bool changed;
547
- do {
548
- changed = false ;
549
- changed |= loop.Path .computeFreelyReducedPath ();
550
- changed |= loop.Path .computeCyclicallyReducedLoop (loop.Basepoint , *this );
551
- changed |= loop.Path .computeLeftCanonicalForm (*this );
552
- } while (changed);
615
+ loop.normalize (*this );
553
616
554
- if (Debug.contains (DebugFlags::HomotopyReduction)) {
555
- if (size != loop.Path .size ()) {
556
- llvm::dbgs () << " ** Note: Reducing the loop eliminated "
557
- << (size - loop.Path .size ()) << " steps\n " ;
558
- }
617
+ if (Debug.contains (DebugFlags::HomotopyReduction)) {
618
+ if (size != loop.Path .size ()) {
619
+ llvm::dbgs () << " ** Note: 3-cell normalization eliminated "
620
+ << (size - loop.Path .size ()) << " steps\n " ;
559
621
}
622
+ }
560
623
624
+ if (loop.Path .empty ()) {
561
625
if (Debug.contains (DebugFlags::HomotopyReduction)) {
562
- llvm::dbgs () << " ** Updated homotopy generator: " ;
563
- llvm::dbgs () << " - " << loop.Basepoint << " : " ;
564
- loop.Path .dump (llvm::dbgs (), loop.Basepoint , *this );
565
- llvm::dbgs () << " \n " ;
626
+ llvm::dbgs () << " ** Deleting trivial 3-cell at basepoint " ;
627
+ llvm::dbgs () << loop.Basepoint << " \n " ;
566
628
}
567
- }
568
- }
569
- };
570
-
571
- while (auto pair = findRuleToDelete ()) {
572
- deleteRule (pair->first , pair->second );
573
- }
574
629
575
- if (Debug.contains (DebugFlags::HomotopyReduction)) {
576
- llvm::dbgs () << " Minimized rewrite system:\n " ;
577
- for (unsigned ruleID : indices (Rules)) {
578
- if (deletedRules.count (ruleID))
630
+ loop.markDeleted ();
579
631
continue ;
632
+ }
580
633
581
- llvm::dbgs () << " (# " << ruleID << " ) " << getRule (ruleID) << " \n " ;
582
- }
583
-
584
- llvm::dbgs () << " Minimized homotopy generators: \n " ;
585
- for ( unsigned loopID : indices (HomotopyGenerators)) {
586
- if (deletedHomotopyGenerators. count (loopID))
587
- continue ;
634
+ // FIXME: Is this correct?
635
+ if (loop. isInContext ()) {
636
+ if (Debug. contains (DebugFlags::HomotopyReduction)) {
637
+ llvm::dbgs () << " ** Deleting 3-cell in context: " ;
638
+ loop. dump ( llvm::dbgs (), * this );
639
+ llvm::dbgs () << " \n " ;
640
+ }
588
641
589
- const auto &loop = HomotopyGenerators[loopID];
590
- if (loop.Path .empty ())
642
+ loop.markDeleted ();
591
643
continue ;
644
+ }
592
645
593
- llvm::dbgs () << " (#" << loopID << " ) " ;
594
- llvm::dbgs () << loop.Basepoint << " : " ;
595
- loop.Path .dump (llvm::dbgs (), loop.Basepoint , *this );
596
- llvm::dbgs () << " \n " ;
597
-
598
- MutableTerm basepoint = loop.Basepoint ;
599
- for (auto step : loop.Path ) {
600
- step.apply (basepoint, *this );
601
- llvm::dbgs () << " - " << basepoint << " \n " ;
646
+ if (Debug.contains (DebugFlags::HomotopyReduction)) {
647
+ llvm::dbgs () << " ** Updated 3-cell: " ;
648
+ loop.dump (llvm::dbgs (), *this );
649
+ llvm::dbgs () << " \n " ;
602
650
}
603
651
}
652
+ };
653
+
654
+ while (true ) {
655
+ RewritePath replacementPath;
656
+ if (auto optRuleID = findRuleToDelete (replacementPath))
657
+ deleteRule (*optRuleID, replacementPath);
658
+ else
659
+ break ;
604
660
}
605
661
}
606
662
@@ -616,7 +672,7 @@ void RewriteSystem::verifyHomotopyGenerators() const {
616
672
617
673
if (term != loop.Basepoint ) {
618
674
llvm::errs () << " Not a loop: " ;
619
- loop.Path . dump (llvm::errs (), loop. Basepoint , *this );
675
+ loop.dump (llvm::errs (), *this );
620
676
llvm::errs () << " \n " ;
621
677
abort ();
622
678
}
0 commit comments