bool SuppressMatchingLoops() { // NOTE: This only looks for self-loops; that is, loops involving a single // quantifier. // For a given quantifier q, we introduce a triggering relation between trigger // candidates by writing t1 → t2 if instantiating q from t1 introduces a ground // term that matches t2. Then, we notice that this relation is transitive, since // all triggers yield the same set of terms. This means that any matching loop // t1 → ... → t1 can be reduced to a self-loop t1 → t1. Detecting such // self-loops is then only a matter of finding terms in the body of the // quantifier that match a given trigger. // Of course, each trigger that actually appears in the body of the quantifier // yields a trivial self-loop (e.g. P(i) in [∀ i {P(i)} ⋅ P(i)]), so we // ignore this type of loops. In fact, we ignore any term in the body of the // quantifier that matches one of the terms of the trigger (this ensures that // [∀ x {f(x), f(f(x))} ⋅ f(x) = f(f(x))] is not a loop). And we even // ignore terms that almost match a trigger term, modulo a single variable // (this ensures that [∀ x y {a(x, y)} ⋅ a(x, y) == a(y, x)] is not a loop). // In addition, we ignore cases where the only differences between a trigger // and a trigger match are places where a variable is replaced with an // expression whose free variables do not intersect that of the quantifier // in which that expression is found. For examples of this behavious, see // triggers/literals-do-not-cause-loops. // This ignoring logic is implemented by the CouldCauseLoops method. bool foundloop = false; foreach (var q in quantifiers) { var looping = new List <TriggerCandidate>(); var loopingMatches = new List <TriggerMatch>(); var safe = TriggerUtils.Filter( q.Candidates, candidate => candidate.LoopingSubterms(q.quantifier).ToList(), (candidate, loopingSubterms) => !loopingSubterms.Any(), (candidate, loopingSubterms) => { looping.Add(candidate); loopingMatches = loopingSubterms.ToList(); candidate.Annotation = "may loop with " + loopingSubterms.MapConcat(t => "\"" + Printer.ExprToString(t.OriginalExpr) + "\"", ", "); }).ToList(); q.CouldSuppressLoops = safe.Count > 0; q.LoopingMatches = loopingMatches; if (!q.AllowsLoops && q.CouldSuppressLoops) { q.Candidates = safe; q.RejectedCandidates.AddRange(looping); } if (looping.Count > 0) { foundloop = true; } } return(foundloop); }
void SelectTriggers() { foreach (var q in quantifiers) //FIXME Check whether this makes verification faster { q.Candidates = TriggerUtils.Filter(q.Candidates, candidate => q.Candidates.Where(candidate.IsStrongerThan).ToList(), (candidate, weakerCandidates) => !weakerCandidates.Any(), (candidate, weakerCandidates) => { q.RejectedCandidates.Add(candidate); candidate.Annotation = "more specific than " + String.Join(", ", weakerCandidates); }).ToList(); } }
/// <summary> /// Collect triggers from the body of each quantifier, and share them /// between all quantifiers. This method assumes that all quantifiers /// actually come from the same context, and were the result of a split that /// gave them all the same variables. /// </summary> /// <param name="triggersCollector"></param> void CollectAndShareTriggers(TriggersCollector triggersCollector) { List <TriggerTerm> pool = new List <TriggerTerm>(); foreach (var q in quantifiers) { var candidates = triggersCollector.CollectTriggers(q.quantifier).Deduplicate(TriggerTerm.Eq); // filter out the candidates that was "second-class" var filtered = TriggerUtils.Filter(candidates, tr => tr, (tr, _) => !tr.IsTranslatedToFunctionCall(), (tr, _) => { }).ToList(); // if there are only "second-class" candidates, add them back. if (filtered.Count == 0) { filtered = candidates; } pool.AddRange(filtered); } var distinctPool = pool.Deduplicate(TriggerTerm.Eq); foreach (var q in quantifiers) { q.CandidateTerms = distinctPool; // The list of candidate terms is immutable q.Candidates = TriggerUtils.AllNonEmptySubsets(distinctPool, SubsetGenerationPredicate, q.quantifier.BoundVars).Select(set => set.ToTriggerCandidate()).ToList(); } }
internal void TrimInvalidTriggers() { Contract.Requires(CandidateTerms != null); Contract.Requires(Candidates != null); Candidates = TriggerUtils.Filter(Candidates, tr => tr, (tr, _) => tr.MentionsAll(quantifier.BoundVars), (tr, _) => { }).ToList(); }