Add Owicki-Gries annotations#783
Conversation
…/ultimate into wip/dk/empire-owicki
…single assertion condition
…ther classes fields
…/ultimate into wip/dk/empire-owicki
Also fix base name for ghost mirror variables.
# Conflicts: # trunk/source/Library-ModelCheckerUtils/src/de/uni_freiburg/informatik/ultimate/lib/modelcheckerutils/smt/predicates/PredicateUtils.java # trunk/source/TraceAbstraction/src/de/uni_freiburg/informatik/ultimate/plugins/generator/traceabstraction/HoareAnnotationComposer.java # trunk/source/TraceAbstraction/src/de/uni_freiburg/informatik/ultimate/plugins/generator/traceabstraction/TraceAbstractionStarter.java
Previously, each declaration overwrote the previous one.
- initialize to zero (constant expression) - avoid weird symbols in the name
| private final IPetriNet<L, IPredicate> mInitialNet; | ||
| private HashRelation<IPredicate, Transition<L, IPredicate>> mPossibleInterferences; | ||
|
|
||
| private static final boolean USE_ON_DEMAND_RESULT = true; |
There was a problem hiding this comment.
We need to be careful about this change, it affects verification performance.
- Do our algorithms still rely on changing this flag? This was probably only relevant for the unfolding-based approaches (but let's check).
- If we do rely on it, we either need to adapt our implementation, or at least only modify this flag if proof production is enabled.
| return null; | ||
| } | ||
| return scope.getDeclarator().getName().toString(); | ||
| })); |
There was a problem hiding this comment.
This was a hack to get witness production working. I vaguely recall that I either fixed the NPE that occurred here in another way, or at least realised it should be fixed in another way ;-) I think this was related to invariants / ghost updates at global variable initializations (which we probably want to avoid).
Let's check this, and if it's not strictly needed, re-assess whether this change is a good idea or not.
| } | ||
| return result; | ||
| } | ||
|
|
There was a problem hiding this comment.
I think this duplicates some logic from annotateFork; see if they can be combined.
| new DeclarationInformation(StorageClass.QUANTIFIED, null)); | ||
| mAuxiliaryVariables.put(variable, id); | ||
| return id; | ||
| } |
There was a problem hiding this comment.
Should we here also try to preserve meaningful ghost variable names?
| import de.uni_freiburg.informatik.ultimate.util.datastructures.ImmutableSet; | ||
| import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; | ||
|
|
||
| // TODO Give this class a more descriptive name |
There was a problem hiding this comment.
... and document the class
There was a problem hiding this comment.
Maybe we can rename it to Empire if we call the interface IEmpire?
There was a problem hiding this comment.
That seems like a less descriptive name to me :)
There was a problem hiding this comment.
I think it would at least resolve any confusion, whether this class implements the empire as presented in the paper. But maybe something more descriptive would be EmpireTransitionFunctionProvider or EmpireTransitionProvider?
There was a problem hiding this comment.
I am ok with getting rid of the Automaton part (though I do not feel strongly about it).
But in regard to making the name more descriptive, I meant more of an indication of which empire is computed. If I see an interface IEmpire and an implementation Empire, I would always ask why two types are needed for the same concept.
I now renamed the interface IEmpire, and this implementation SaturatedEmpire (as in the paper).
| * one transition in enabled(territory(s)), for which there is no successor in the automaton. In this case, the | ||
| * successor law must be false. | ||
| */ | ||
| public boolean isFinal2(final State<L, P> state) { |
There was a problem hiding this comment.
Re-examine the usages of final states in this class (and the corresponding interfaces). Delete redundant methods.
There was a problem hiding this comment.
After re-examination I did not find any usage of the final method of the EmpireAutomaton class (there are some relevant calls to the isFinal method of the InterpolantAutomaton though).
There was a problem hiding this comment.
| import de.uni_freiburg.informatik.ultimate.automata.statefactory.IStateFactory; | ||
| import de.uni_freiburg.informatik.ultimate.lib.modelcheckerutils.smt.predicates.IPredicate; | ||
|
|
||
| // TODO Possibly rename to IEmpire |
| * automaton. For each region, the assigned law must be weaker than the state's full law, and satisfy additional | ||
| * conditions. | ||
| * | ||
| * TODO Document additional conditions |
There was a problem hiding this comment.
(check in the paper)
| import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.HashRelation; | ||
| import de.uni_freiburg.informatik.ultimate.util.datastructures.relation.Pair; | ||
|
|
||
| public class LegalFocus<S, L, P> implements ILegalFocusFunction<S, P> { |
There was a problem hiding this comment.
document this class
| mSymbolTable = new DefaultIcfgSymbolTable(symbolTable, procedures); | ||
|
|
||
| // TODO let callers pass predicate factory | ||
| mFactory = new BasicPredicateFactory(services, mManagedScript, mSymbolTable); |
There was a problem hiding this comment.
Is this TODO still relevant?
| */ | ||
| @Override | ||
| @Deprecated | ||
| Collection<S> getFinalStates(); |
There was a problem hiding this comment.
This method is marked as deprecated, but it is used in LegalFocus::computeLegalFocus. Is this reason for deprecation ("We should not abuse the final states for empires, they do not represent any meaningful language. Instead introduce a suitably-named new method.") still valid, or should we remove it?
This aligns the implementation terminology with the POPL'26 paper. Furthermore, the class previously called EmpireAutomaton is named SaturatedEmpire to indicate the implemented algorithm.
matthiaszumkeller
left a comment
There was a problem hiding this comment.
Thank you for preparing this merge. I added some additional comments.
There was a problem hiding this comment.
After inspection of this class and as far as I can recall, this class was a nearly 1-to-1 copy from the original (SaturatedEmpire) class at the time, which was only added so that we a able to quickly check test the approach. However if we would also parametrize the empire and State record with the type of region, with some engeneering effort most of this class (maybe even the whole class) should be obsolete (besides the method extendAll ).
| import de.uni_freiburg.informatik.ultimate.util.datastructures.DataStructureUtils; | ||
| import de.uni_freiburg.informatik.ultimate.util.datastructures.ImmutableSet; | ||
|
|
||
| public class DirectedEmpireProduct<L, P> { |
There was a problem hiding this comment.
Maybe this class should also just extend the IEmpire interface? The structure is practically the same and the empire product should again be an empire (I don't think we need to change this right now, but maybe a note for the future).
| return interRegions; | ||
| } | ||
|
|
||
| private INestedWordAutomaton<Transition<L, P>, ProductState<L, P>> constructProductAutomaton() { |
There was a problem hiding this comment.
If this approach gets resumed in the future, I think this could also be done on-the-fly.
| final var comparator = getPreference(); | ||
| return (r1, r2) -> comparator.compare(new Pair<>(r1, law), new Pair<>(r2, law)); | ||
| } | ||
|
|
There was a problem hiding this comment.
Should we add some documentation here? As far as I remember, the heuristics for choosing the right region for the focus also left a lot of space for future work.
|
In another project building of this work (branch
fork-join01.backup.bpl.txt |
Is it really necessary to have an invariant stronger than
Maybe the validator (or your modelling) has a different understanding of the join that allows more behavior?
Still, we should investigate this nondeterministic behavior! |
We do check validity of the OG-proof internally and at least to me, the resulting proof seems valid wrt. the Petri net representation of the program. It is true, that no information about variable
I also think, that the non-deterministic behavior should be investigated. Update: |
Oh, I see. So I guess we do not output the invariant for This also seems to be the reason for non-determinism, it depends whether we put the invariant at |
Nice catch! I think that I found the location where the non-determinism occurs. In the legal focus, method |
I guess we could check for the auxiliary places in the legal focus as a heuristics (even if it is not quite nice). But I am still wondering whether the loss of precision when omitting the invariants for auxiliary places a) only occurs in combination with the legal focus and b) could be always fixed with such a simple heuristics (which I am quite skeptical). |
|
Thanks to both of you for investigating this! This explains why we could get a seemingly invalid annotation after backtranslation but not trigger an error before. Let's maybe continue the discussion how to fix this in another channel to not overload this PR. |
This PR adds Owicki-Gries annotations as proofs for concurrent programs, as well as algorithms to compute such annotations after verification.
🚧 This is work in progress 🚧
Specifically, we add:
basic classes for describing and validating Owicki-Gries annotations.
2 algorithms for the construction of Owicki-Gries annotations:
We previously implemented some other algorithm variants, but as they have been superseeded by the POPL'26 algorithm, they are no longer part of this PR. With one exception:
a partial implementation of a refined algorithm based on directed empires: while not yet complete, this may be a promising base for future improvements to our Owicki-Gries computation.
changes in backtranslation and correctness witness (v2.1) generation that allow us to output correctness witnesses for concurrent programs from Owicki-Gries proofs.