@@ -367,7 +367,10 @@ bool
367
367
RewriteSystem::computeCriticalPair (ArrayRef<Symbol>::const_iterator from,
368
368
const Rule &lhs, const Rule &rhs,
369
369
std::vector<std::pair<MutableTerm,
370
- MutableTerm>> &result) const {
370
+ MutableTerm>> &pairs,
371
+ std::vector<RewritePath> &paths,
372
+ std::vector<std::pair<MutableTerm,
373
+ RewritePath>> &loops) const {
371
374
auto end = lhs.getLHS ().end ();
372
375
if (from + rhs.getLHS ().size () < end) {
373
376
// lhs == TUV -> X, rhs == U -> Y.
@@ -378,17 +381,33 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
378
381
// In this case, T and V are both empty.
379
382
380
383
// Compute the term TYV.
381
- MutableTerm t (lhs.getLHS ().begin (), from);
382
- t.append (rhs.getRHS ());
383
- t.append (from + rhs.getLHS ().size (), lhs.getLHS ().end ());
384
-
385
- if (lhs.getRHS ().size () == t.size () &&
386
- std::equal (lhs.getRHS ().begin (), lhs.getRHS ().end (),
387
- t.begin ())) {
384
+ MutableTerm tyv (lhs.getLHS ().begin (), from);
385
+ tyv.append (rhs.getRHS ());
386
+ tyv.append (from + rhs.getLHS ().size (), lhs.getLHS ().end ());
387
+
388
+ MutableTerm x (lhs.getRHS ());
389
+
390
+ // Compute a path from X to TYV.
391
+ RewritePath path;
392
+
393
+ // (1) First, apply the left hand side rule in the reverse direction.
394
+ path.add (RewriteStep (/* offset=*/ 0 ,
395
+ getRuleID (lhs),
396
+ /* inverse=*/ true ));
397
+ // (2) Now, apply the right hand side in the forward direction.
398
+ path.add (RewriteStep (from - lhs.getLHS ().begin (),
399
+ getRuleID (rhs),
400
+ /* inverse=*/ false ));
401
+
402
+ // If X == TYV, we have a trivial overlap.
403
+ if (x == tyv) {
404
+ loops.emplace_back (x, path);
388
405
return false ;
389
406
}
390
407
391
- result.emplace_back (MutableTerm (lhs.getRHS ()), t);
408
+ // Add the pair (X, TYV).
409
+ pairs.emplace_back (x, tyv);
410
+ paths.push_back (path);
392
411
} else {
393
412
// lhs == TU -> X, rhs == UV -> Y.
394
413
@@ -408,10 +427,27 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
408
427
// Compute the term TY.
409
428
t.append (rhs.getRHS ());
410
429
411
- if (xv == t)
430
+ // Compute a path from XV to TY.
431
+ RewritePath path;
432
+
433
+ // (1) First, apply the left hand side rule in the reverse direction.
434
+ path.add (RewriteStep (/* offset=*/ 0 ,
435
+ getRuleID (lhs),
436
+ /* inverse=*/ true ));
437
+ // (2) Now, apply the right hand side in the forward direction.
438
+ path.add (RewriteStep (from - lhs.getLHS ().begin (),
439
+ getRuleID (rhs),
440
+ /* inverse=*/ false ));
441
+
442
+ // If XV == TY, we have a trivial overlap.
443
+ if (xv == t) {
444
+ loops.emplace_back (xv, path);
412
445
return false ;
446
+ }
413
447
414
- result.emplace_back (xv, t);
448
+ // Add the pair (XV, TY).
449
+ pairs.emplace_back (xv, t);
450
+ paths.push_back (path);
415
451
}
416
452
417
453
return true ;
@@ -435,9 +471,11 @@ RewriteSystem::computeConfluentCompletion(unsigned maxIterations,
435
471
436
472
bool again = false ;
437
473
438
- do {
439
- std::vector<std::pair<MutableTerm, MutableTerm>> resolvedCriticalPairs;
474
+ std::vector<std::pair<MutableTerm, MutableTerm>> resolvedCriticalPairs;
475
+ std::vector<RewritePath> resolvedPaths;
476
+ std::vector<std::pair<MutableTerm, RewritePath>> resolvedLoops;
440
477
478
+ do {
441
479
// For every rule, looking for other rules that overlap with this rule.
442
480
for (unsigned i = 0 , e = Rules.size (); i < e; ++i) {
443
481
const auto &lhs = getRule (i);
@@ -480,9 +518,13 @@ RewriteSystem::computeConfluentCompletion(unsigned maxIterations,
480
518
}
481
519
482
520
// Try to repair the confluence violation by adding a new rule.
483
- if (computeCriticalPair (from, lhs, rhs, resolvedCriticalPairs)) {
521
+ if (computeCriticalPair (from, lhs, rhs,
522
+ resolvedCriticalPairs,
523
+ resolvedPaths,
524
+ resolvedLoops)) {
484
525
if (Debug.contains (DebugFlags::Completion)) {
485
526
const auto &pair = resolvedCriticalPairs.back ();
527
+ const auto &path = resolvedPaths.back ();
486
528
487
529
llvm::dbgs () << " $ Overlapping rules: (#" << i << " ) " ;
488
530
llvm::dbgs () << lhs << " \n " ;
@@ -492,13 +534,26 @@ RewriteSystem::computeConfluentCompletion(unsigned maxIterations,
492
534
<< pair.first << " \n " ;
493
535
llvm::dbgs () << " $$ Second term of critical pair is "
494
536
<< pair.second << " \n\n " ;
537
+
538
+ llvm::dbgs () << " $$ Resolved via path: " ;
539
+ path.dump (llvm::dbgs (), pair.first , *this );
540
+ llvm::dbgs () << " \n\n " ;
495
541
}
496
542
} else {
497
543
if (Debug.contains (DebugFlags::Completion)) {
544
+ const auto &loop = resolvedLoops.back ();
545
+
498
546
llvm::dbgs () << " $ Trivially overlapping rules: (#" << i << " ) " ;
499
547
llvm::dbgs () << lhs << " \n " ;
500
548
llvm::dbgs () << " -vs- (#" << j << " ) " ;
501
549
llvm::dbgs () << rhs << " :\n " ;
550
+
551
+ llvm::dbgs () << " $$ Loop: " ;
552
+ loop.second .dump (llvm::dbgs (), loop.first , *this );
553
+ llvm::dbgs () << " \n\n " ;
554
+
555
+ // Record the trivial loop.
556
+ HomotopyGenerators.push_back (loop);
502
557
}
503
558
}
504
559
});
@@ -509,13 +564,18 @@ RewriteSystem::computeConfluentCompletion(unsigned maxIterations,
509
564
510
565
simplifyRewriteSystem ();
511
566
567
+ assert (resolvedCriticalPairs.size () == resolvedPaths.size ());
568
+
512
569
again = false ;
513
- for (const auto &pair : resolvedCriticalPairs) {
570
+ for (unsigned index : indices (resolvedCriticalPairs)) {
571
+ const auto &pair = resolvedCriticalPairs[index];
572
+ const auto &path = resolvedPaths[index];
573
+
514
574
// Check if we've already done too much work.
515
575
if (Rules.size () > maxIterations)
516
576
return std::make_pair (CompletionResult::MaxIterations, steps);
517
577
518
- if (!addRule (pair.first , pair.second ))
578
+ if (!addRule (pair.first , pair.second , &path ))
519
579
continue ;
520
580
521
581
// Check if the new rule is too long.
@@ -527,6 +587,9 @@ RewriteSystem::computeConfluentCompletion(unsigned maxIterations,
527
587
again = true ;
528
588
}
529
589
590
+ resolvedCriticalPairs.clear ();
591
+ resolvedPaths.clear ();
592
+
530
593
// If the added rules merged any associated types, process the merges now
531
594
// before we continue with the completion procedure. This is important
532
595
// to perform incrementally since merging is required to repair confluence
0 commit comments