@@ -158,7 +158,7 @@ RewritePath::findRulesAppearingOnceInEmptyContext() const {
158158 for (auto step : Steps) {
159159 switch (step.Kind ) {
160160 case RewriteStep::ApplyRewriteRule: {
161- if (step.StartOffset == 0 && step. EndOffset == 0 )
161+ if (! step.isInContext () )
162162 rulesInEmptyContext.insert (step.RuleID );
163163
164164 ++ruleMultiplicity[step.RuleID ];
@@ -216,8 +216,7 @@ RewritePath RewritePath::splitCycleAtRule(unsigned ruleID) const {
216216 break ;
217217
218218 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?" );
221220
222221 ruleWasInverted = step.Inverse ;
223222 sawRule = true ;
@@ -460,6 +459,7 @@ bool RewritePath::computeCyclicallyReducedLoop(MutableTerm &basepoint,
460459 return count > 0 ;
461460}
462461
462+ // / Apply the interchange rule until fixed point (see maybeSwapRewriteSteps()).
463463bool RewritePath::computeLeftCanonicalForm (const RewriteSystem &system) {
464464 bool changed = false ;
465465
@@ -491,36 +491,103 @@ void RewritePath::dump(llvm::raw_ostream &out,
491491 }
492492}
493493
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+ }
499505
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 ;
504510
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 ;
506517
507- SmallVector<unsigned > redundancyCandidates =
508- loop.Path .findRulesAppearingOnceInEmptyContext ();
509- if (redundancyCandidates.empty ())
510- continue ;
518+ case RewriteStep::AdjustConcreteType:
519+ break ;
520+ }
511521
512- auto ruleID = redundancyCandidates.front ();
513- RewritePath replacementPath = loop.Path .splitCycleAtRule (ruleID);
522+ if (minStartOffset == 0 && minEndOffset == 0 )
523+ break ;
524+ }
514525
515- deletedRules. insert (ruleID );
516- deletedHomotopyGenerators. insert (loopID);
526+ return (minStartOffset > 0 || minEndOffset > 0 );
527+ }
517528
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+ }
520536
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+ }
523587
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 () {
524591 auto deleteRule = [&](unsigned ruleID, RewritePath replacementPath) {
525592 if (Debug.contains (DebugFlags::HomotopyReduction)) {
526593 const auto &rule = getRule (ruleID);
@@ -533,74 +600,63 @@ void RewriteSystem::minimizeRewriteSystem() {
533600 llvm::dbgs () << " \n " ;
534601 }
535602
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 ())
538607 continue ;
539608
540- auto &loop = HomotopyGenerators[loopID];
541609 bool changed = loop.Path .replaceRuleWithPath (ruleID, replacementPath);
610+ if (!changed)
611+ continue ;
542612
543- if (changed) {
544- unsigned size = loop.Path .size ();
613+ unsigned size = loop.Path .size ();
545614
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 );
553616
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 " ;
559621 }
622+ }
560623
624+ if (loop.Path .empty ()) {
561625 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 " ;
566628 }
567- }
568- }
569- };
570-
571- while (auto pair = findRuleToDelete ()) {
572- deleteRule (pair->first , pair->second );
573- }
574629
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 ();
579631 continue ;
632+ }
580633
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+ }
588641
589- const auto &loop = HomotopyGenerators[loopID];
590- if (loop.Path .empty ())
642+ loop.markDeleted ();
591643 continue ;
644+ }
592645
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 " ;
602650 }
603651 }
652+ };
653+
654+ while (true ) {
655+ RewritePath replacementPath;
656+ if (auto optRuleID = findRuleToDelete (replacementPath))
657+ deleteRule (*optRuleID, replacementPath);
658+ else
659+ break ;
604660 }
605661}
606662
@@ -616,7 +672,7 @@ void RewriteSystem::verifyHomotopyGenerators() const {
616672
617673 if (term != loop.Basepoint ) {
618674 llvm::errs () << " Not a loop: " ;
619- loop.Path . dump (llvm::errs (), loop. Basepoint , *this );
675+ loop.dump (llvm::errs (), *this );
620676 llvm::errs () << " \n " ;
621677 abort ();
622678 }
0 commit comments