Open lucab opened 2 months ago
Thanks for submitting the report @lucab! I have been starring at the spec for some time, before I realized that the counter keeps incrementing. Technically, the liveness-to-safety reduction works only on finite-state systems. This explains why you were able to find a counterexample when you bounded myState
in https://github.com/informalsystems/quint/issues/1501.
However, there is another subtle issue at play here. It looks like the liveness reduction does not assume Next
to be stuttering. If I change q_step
as q_step == step \/ UNCHANGED myState
instead of just step
, Apalache finds a loop. It's a bit surprising though that it does not find a self-loop but finds a loop of length 2.
@p-offtermatt could you have a look? I am not really surprised about the behavior on an infinitely-increasing counter, though the example is quite simple. But I am surprised that the minimal counterexample is of length 2, when we add stuttering. Also, do you remember, why we decided not to add stuttering by default?
You are exactly right about the incrementing counter - it is a limitation of the current implementation that to decide liveness properties, we need an execution that has a loop (as in, coming back back to a state we have already visited and thus finding an execution that can loop infinitely).
For the counterexample, if I understand correctly, this is the answer: Apalache first nondeterministically chooses for a state to be the start of the loop, and it then needs to find this same state again. Meaning, counterexamples for temporal properties need to have at least two states (state 0 starts the loop, and then state 1==state 0 ends the loop).
I am not sure why we did not add stuttering by default - probably just to not restrict the expressivity, although it does lead to weird situations like this.
I am not sure why we did not add stuttering by default - probably just to not restrict the expressivity, although it does lead to weird situations like this.
Right. Actually, TLC uses Spec
as the input for checking temporal properties, which normally has stuttering Next
. We did not need that for safety and now it bites us back. Perhaps, we should only allow non-stuttering steps in the expert mode (there is no expert mode though :)).
Thanks for the feedback. You touched quite a bit of topics, so I'll try to split them across different items:
The temporal property above is a plain always
check, i.e. it is a state invariant in disguise. I probably should have written it has a plain invariant without any temporal specifier, but I'm a bit surprised Apalache does not do that lifting for me. In the end, this is a condition that must hold true in each single state separately, regardless of loop-finding.
I'm actually happy that Next
has no stuttering, as my Quint spec does not actually have stuttering. Otherwise, it would break some other properties (e.g. that the counter is always strictly increasing by 1 per step) in a quite opaque way. I can manually encode stuttering in Quint in specific actions, where needed.
I understand much of the trouble here come from the infinite state change, and in this (and most other cases) I can bound the execution. However that brings the additional problem of now having two caps: my arbitrary one, and the checker max-steps. If arbitrary_cap > max_steps
, we are back to the problem of a (seemingly) infinite change.
Ideally I'd need some way in Quint and Apalache to derive one value from the other, e.g. execLimit = (maxSteps / 2) + 1
with maxSteps
coming from somewhere outside of the spec and linked to Quint/Apalache --max-steps
.
- The temporal property above is a plain
always
check, i.e. it is a state invariant in disguise. I probably should have written it has a plain invariant without any temporal specifier, but I'm a bit surprised Apalache does not do that lifting for me. In the end, this is a condition that must hold true in each single state separately, regardless of loop-finding.
This is true. The preprocessor of temporal properties could probably do a better job. It just follows the general algorithm.
- I understand much of the trouble here come from the infinite state change, and in this (and most other cases) I can bound the execution. However that brings the additional problem of now having two caps: my arbitrary one, and the checker max-steps. If
arbitrary_cap > max_steps
, we are back to the problem of a (seemingly) infinite change. Ideally I'd need some way in Quint and Apalache to derive one value from the other, e.g.execLimit = (maxSteps / 2) + 1
withmaxSteps
coming from somewhere outside of the spec and linked to Quint/Apalache--max-steps
.
Yeah. This is actually a very hard problem in bounded model checking. If you are curious about it, there is a paper on reoccurence diameters. In practice, this means though that you have to use something like a napkin computation to figure out the bounds.
@konnov thanks for the paper reference, it looks like an interesting topic, I've put that up in my reading queue!
For clarity, I'm totally fine deriving an approximate bound on my own through some napkin math.
The problem is that the input parameter for this (e.g. the maxSteps
above) can dynamically change outside of the spec, depending on Quint/Apalache CLI argument. And that may turn a finite execution into an infinite one, and vice-versa.
I guess I'm effectively asking for a new(?) feature which somehow propagates Quint/Apalache --max-steps
value to something usable in the spec formulas. That would allow deriving a bound in the spec to make the execution finite, regardless of being invoked with --max-steps 10
or max-steps 99999
.
System information
0.45.4 | build: 99508e4
(latest release)Description
This is a bug report forwarded from Quint: https://github.com/informalsystems/quint/issues/1501
The original Quint specification was:
quint verify
(with Apalache) fails to find a counterexample fortemporalProps
. I followed @bugarela's suggestions and translated the Quint file to TLA+ then directly checked with Apalache, below is the full ouput.Details
TLA+ specification (autogenerated by
quint compile
):Config:
Command:
Output:
I sanity-checked the TLA+ specification (after some minor fixes) with TLC and it correctly finds the counterexample:
Triage checklist (for maintainers)