-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pruning axioms and functions #427
Pruning axioms and functions #427
Conversation
Why does the axiom in your PR description have incoming edges only for P and Q? How are incoming and outgoing edges of a function determined? |
Its not a well-written description, sorry about that. Rule-wise:
To answer your original question, the axiom's incoming edges are just the triggers---that particular axiom is only useful if somebody mentions |
Please revise the PR description and include your response to my earlier question. Also indicate what is the motivation for this new feature. |
Suppose an axiom does not have any triggers. Would it not have any incoming edges? If yes, then it would always be pruned away. This seems like strange behavior. |
Source/Core/CommandLineOptions.cs
Outdated
@@ -1675,6 +1677,10 @@ public int GetArgumentSeparatorIndex(string argList, int startIndex) | |||
{:ignore} | |||
Ignore the declaration (after checking for duplicate names). | |||
|
|||
{:exclude_dep} | |||
Ignore the declaration for the purpose of pruning, i.e., do not consider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose? The description is mysterious and does not make sense even after reading the PR description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pruning process ignores declarations with this attribute. It removes such declarations from the outgoing set of all others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this to the PR description
Good point. If an axiom is like |
Here's some more information. MotivationA Boogie program typically contains many declarations (functions, axioms, etc.) that are not needed to verify the By pruning away declarations that are not needed for a given piece of an
DependenciesIn general, the incoming edges of a declaration
Unreachable axiomsAs mentioned in the PR description,
would be excluded, unless So, since TypesBoogie type declarations also affect what gets sent to the SMT solver. After |
(Note that this is @zafer-esen's work. I created the PR for permissions reasons.) Dafny uses the Boogie option `prune` by default. (Introduced in [Boogie PR #427](boogie-org/boogie#427), although the semantics explained there is [out of date](boogie-org/boogie#767 (comment)).). The `prune` option, when enabled, runs a reachability analysis in Boogie, and prunes away functions, constants and axioms that are not reachable from root nodes. This greatly reduces resource counts, and leads to less brittleness; which is why pruning is intentionally made as strong as possible. The semantics of pruning, at a high level, is as follows. If an axiom is inside a `uses` clause of some symbol `s`: * without quantifiers or without triggers: do not prune if `s` is reachable. * with both quantifiers and triggers: do not prune if (a) `s` is reachable _or_ (b) all symbols in one of its triggers are reachable. If an axiom is not inside a `uses` clause: * without quantifiers or without triggers: always pruned. * with both quantifiers and triggers: do not prune if (b) all symbols in one of its triggers are reachable. If (a) holds but (b) does not, this leads to a weaker pruning if an axiom with quantifiers and triggers is inside a `uses` clause. (b) matches the semantics of how axioms with triggers are instantiated (AFAIK), so axioms with both quantifiers and triggers should not be inside `uses` clauses (with the exception of purely polymorphic quantifiers, more on this at the end of this comment). Consider the [following lines](https://github.com/dafny-lang/dafny/blob/c31932b4b4f77a38e5da9c9f6a7689d8f57346bf/Source/DafnyCore/DafnyPrelude.bpl#L230-L290) from `DafnyPrelude.bpl`: ``` function $Is<T>(T,Ty): bool uses { // no heap for now axiom(forall v : int :: { $Is(v,TInt) } $Is(v,TInt)); axiom(forall v : real :: { $Is(v,TReal) } $Is(v,TReal)); axiom(forall v : bool :: { $Is(v,TBool) } $Is(v,TBool)); axiom(forall v : char :: { $Is(v,TChar) } $Is(v,TChar)); axiom(forall v : ORDINAL :: { $Is(v,TORDINAL) } $Is(v,TORDINAL)); [...] // more axioms for every type } ``` `$Is` is a function symbol and `TInt`, `TReal` etc. are constant symbols, i.e., the axioms shown are quantified and all have triggers with two function or constant symbols. Since they are inside the `uses` clause of `$Is`, none of these axioms can be pruned if `$Is` is reachable. However, if the second symbol inside the triggers, say `TReal` in the second axiom, is still unreachable, that axiom cannot be triggered despite being preserved (but will negatively affect resource counts). This PR moves all quantified axioms with triggers outside of their `uses` clauses. The one exception is purely polymorphic quantifiers ([example](https://github.com/dafny-lang/dafny/blob/2a2e1c41af9b89c10437abc71cca92eb818e02a8/Source/DafnyCore/DafnyPrelude.bpl#L970-L972)), which should remain inside a `uses` clause, as these quantifiers disappear if monomorphization is used in Boogie. By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license. --------- Co-authored-by: Zafer Esen <zesen@amazon.com> Co-authored-by: Remy Willems <rwillems@amazon.com>
feat: pruning, enabled with flag
/prune
.Before checking an implementation
I
, it prunes away all axioms and functions that are "unreachable" fromI
. For defining reachability, think of every axiom and function as nodes of a directed graph. There is an edge from node A to node B, if A mentions a declaration for which B can say something.More precisely, for every axiom and function I define a set of incoming and outgoing edges. Edges may be labelled with a function or a constant. Incoming (dependency) edges consist of those functions and constants that a node may be useful for.
that the declaration may be useful for. For example, an axiom of the form:
has two incoming edges: the function P and the function Q. Outgoing edges consist of functions and constants that a declaration mentions. For the axiom above, there are 3 outgoing edges: P, Q, and R.
Rule-wise:
In this setup, a declaration A depends on B, if the outgoing edges of A match with some incoming edge of B. Because this is all very syntactic, pruning does not preserve verification outcome. For example, if there is an axiom that says
false
without mentioning any functions or constants, it will be pruned away and verification may fail.I also add an attribute on declarations:
exclude_dep
. The pruning process ignores such declarations while computing dependencies---it removes such declarations from the outgoing set of all others.