public QuantifierExpr RewriteMatchingLoops(QuantifierWithTriggers q) { // rewrite quantifier to avoid mathing loops // before: // assert forall i :: 0 <= i < a.Length-1 ==> a[i] <= a[i+1]; // after: // assert forall i,j :: j == i+1 ==> 0 <= i < a.Length-1 ==> a[i] <= a[i+1]; substMap = new Dictionary <Expression, IdentifierExpr>(); usedMap = new Dictionary <Expression, IdentifierExpr>(); foreach (var m in q.LoopingMatches) { var e = m.OriginalExpr; if (TriggersCollector.IsPotentialTriggerCandidate(e) && triggersCollector.IsTriggerKiller(e)) { foreach (var sub in e.SubExpressions) { if (triggersCollector.IsTriggerKiller(sub) && (!TriggersCollector.IsPotentialTriggerCandidate(sub))) { IdentifierExpr ie; if (!substMap.TryGetValue(sub, out ie)) { var newBv = new BoundVar(sub.tok, "_t#" + substMap.Count, sub.Type); ie = new IdentifierExpr(sub.tok, newBv.Name); ie.Var = newBv; ie.Type = newBv.Type; substMap[sub] = ie; } } } } } var expr = (QuantifierExpr)q.quantifier; if (substMap.Count > 0) { var s = new Translator.ExprSubstituter(substMap); expr = s.Substitute(q.quantifier) as QuantifierExpr; } else { // make a copy of the expr if (expr is ForallExpr) { expr = new ForallExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type }; } else { expr = new ExistsExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type }; } } return(expr); }
public QuantifierExpr RewriteMatchingLoops(QuantifierWithTriggers q) { // rewrite quantifier to avoid matching loops // before: // assert forall i :: 0 <= i < a.Length-1 ==> a[i] <= a[i+1]; // after: // assert forall i,j :: j == i+1 ==> 0 <= i < a.Length-1 ==> a[i] <= a[j]; substMap = new List <Tuple <Expression, IdentifierExpr> >(); foreach (var m in q.LoopingMatches) { var e = m.OriginalExpr; if (TriggersCollector.IsPotentialTriggerCandidate(e) && triggersCollector.IsTriggerKiller(e)) { foreach (var sub in e.SubExpressions) { if (triggersCollector.IsTriggerKiller(sub) && (!TriggersCollector.IsPotentialTriggerCandidate(sub))) { var entry = substMap.Find(x => ExprExtensions.ExpressionEq(sub, x.Item1)); if (entry == null) { var newBv = new BoundVar(sub.tok, "_t#" + substMap.Count, sub.Type); var ie = new IdentifierExpr(sub.tok, newBv.Name); ie.Var = newBv; ie.Type = newBv.Type; substMap.Add(new Tuple <Expression, IdentifierExpr>(sub, ie)); } } } } } var expr = (QuantifierExpr)q.quantifier; if (substMap.Count > 0) { var s = new ExprSubstituter(substMap); expr = s.Substitute(q.quantifier) as QuantifierExpr; } else { // make a copy of the expr if (expr is ForallExpr) { expr = new ForallExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type, Bounds = expr.Bounds }; } else { expr = new ExistsExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type, Bounds = expr.Bounds }; } } return(expr); }
private void CommitOne(QuantifierWithTriggers q, bool addHeader) { var errorLevel = ErrorLevel.Info; var msg = new StringBuilder(); var indent = addHeader ? " " : ""; bool suppressWarnings = Attributes.Contains(q.quantifier.Attributes, "nowarn"); if (!TriggerUtils.NeedsAutoTriggers(q.quantifier)) // NOTE: split and autotriggers attributes are passed down to Boogie { var extraMsg = TriggerUtils.WantsAutoTriggers(q.quantifier) ? "" : " Note that {:autotriggers false} can cause instabilities. Consider using {:nowarn}, {:matchingloop} (not great either), or a manual trigger instead."; msg.AppendFormat("Not generating triggers for \"{0}\".{1}", Printer.ExprToString(q.quantifier.Term), extraMsg).AppendLine(); } else { if (addHeader) { msg.AppendFormat("For expression \"{0}\":", Printer.ExprToString(q.quantifier.Term)).AppendLine(); } foreach (var candidate in q.Candidates) { q.quantifier.Attributes = new Attributes("trigger", candidate.Terms.Select(t => t.Expr).ToList(), q.quantifier.Attributes); } AddTriggersToMessage("Selected triggers:", q.Candidates, msg, indent); AddTriggersToMessage("Rejected triggers:", q.RejectedCandidates, msg, indent, true); #if QUANTIFIER_WARNINGS var WARN_TAG = DafnyOptions.O.UnicodeOutput ? "⚠ " : "/!\\ "; var WARN_TAG_OVERRIDE = suppressWarnings ? "(Suppressed warning) " : WARN_TAG; var WARN_LEVEL = suppressWarnings ? ErrorLevel.Info : ErrorLevel.Warning; var WARN = indent + WARN_TAG_OVERRIDE; if (!q.CandidateTerms.Any()) { errorLevel = WARN_LEVEL; msg.Append(WARN).AppendLine("No terms found to trigger on."); } else if (!q.Candidates.Any()) { errorLevel = WARN_LEVEL; msg.Append(WARN).AppendLine("No trigger covering all quantified variables found."); } else if (!q.CouldSuppressLoops && !q.AllowsLoops) { errorLevel = WARN_LEVEL; msg.Append(WARN).AppendLine("Suppressing loops would leave this expression without triggers."); } else if (suppressWarnings) { errorLevel = ErrorLevel.Warning; msg.Append(indent).Append(WARN_TAG).AppendLine("There is no warning here to suppress."); } #endif } if (msg.Length > 0) { var msgStr = msg.ToString().TrimEnd("\r\n ".ToCharArray()); reporter.Message(MessageSource.Rewriter, errorLevel, q.quantifier.tok, msgStr); } }
private bool HasSameTriggers(QuantifierWithTriggers one, QuantifierWithTriggers other) { return(TriggerUtils.SameLists(one.Candidates, other.Candidates, SameTriggerCandidate)); }
// group split quantifier by what triggers they got, and merged them back into one quantifier. private void CombineSplitQuantifier() { if (quantifiers.Count > 1) { List <QuantifierGroup> groups = new List <QuantifierGroup>(); groups.Add(new QuantifierGroup(quantifiers[0], new List <ComprehensionExpr> { quantifiers[0].quantifier })); for (int i = 1; i < quantifiers.Count; i++) { bool found = false; for (int j = 0; j < groups.Count; j++) { if (HasSameTriggers(quantifiers[i], groups[j].quantifier)) { // belong to the same group groups[j].expressions.Add(quantifiers[i].quantifier); found = true; break; } } if (!found) { // start a new group groups.Add(new QuantifierGroup(quantifiers[i], new List <ComprehensionExpr> { quantifiers[i].quantifier })); } } if (groups.Count == quantifiers.Count) { // have the same number of splits, so no splits are combined. return; } // merge expressions in each group back to one quantifier. List <QuantifierWithTriggers> list = new List <QuantifierWithTriggers>(); List <Expression> splits = new List <Expression>(); foreach (var group in groups) { QuantifierWithTriggers q = group.quantifier; if (q.quantifier is ForallExpr) { ForallExpr quantifier = (ForallExpr)q.quantifier; Expression expr = QuantifiersToExpression(quantifier.tok, BinaryExpr.ResolvedOpcode.And, group.expressions); q.quantifier = new ForallExpr(quantifier.tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, expr, TriggerUtils.CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type, Bounds = quantifier.Bounds }; } else if (q.quantifier is ExistsExpr) { ExistsExpr quantifier = (ExistsExpr)q.quantifier; Expression expr = QuantifiersToExpression(quantifier.tok, BinaryExpr.ResolvedOpcode.Or, group.expressions); q.quantifier = new ExistsExpr(quantifier.tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, expr, TriggerUtils.CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type, Bounds = quantifier.Bounds }; } list.Add(q); splits.Add(q.quantifier); } this.quantifiers = list; Contract.Assert(this.expr is QuantifierExpr); // only QuantifierExpr has SplitQuantifier ((QuantifierExpr)this.expr).SplitQuantifier = splits; } }
public QuantifierGroup(QuantifierWithTriggers q, List <ComprehensionExpr> expressions) { this.quantifier = q; this.expressions = expressions; }