Report the state and execution bounds behind a successful check
Distinguish bounded execution search, complete exploration of a finite instance, and an unbounded inductive argument.
On this page
The question for today
What you’ll understand
- Write the bounded counterexample query with k transitions and k+1 states.
- Distinguish parameter domains, depth bounds, and pruning constraints.
- Explain why a successful bounded search does not establish arbitrary-size or unbounded correctness.
A model checker can explore many schedules more systematically than a hand-written test, but its conclusion still has a domain. Two clients, three messages, and twenty transitions describe one analysis boundary. Exhausting a finite reachable graph is a different achievement from searching only a bounded prefix of that graph. Preserve these distinctions in the report so 'no counterexample found' is not silently upgraded into a proof about every client count, failure pattern, and execution length.
A bounded query searches for a finite witness
For safety predicate P, bounded model checking asks whether some allowed execution of up to a chosen number of transitions reaches a state violating P. A typical symbolic encoding combines initialization, a chain of transition relations, and a disjunction of bad states. A satisfying assignment supplies a counterexample within the encoding's scope. An unsatisfiable query rules out those bounded witnesses under the encoded domains and assumptions; it does not rule out a longer failure. Solver timeout or unknown is a separate outcome, not evidence that the property passed.
Apalache's documented bounded mode checks execution lengths under a configured limit; its separate induction workflow asks stronger initiation and preservation questions. TLC ordinarily explores reachable states of a concrete model instance rather than merely enumerating one trace. When that reachable graph is finite and its configured exploration completes without a safety violation, the result covers arbitrarily long paths within that finite instance. It still does not generalize to larger constant domains without an additional argument. State the tool version, specification, configuration, property, and completion status when recording either result.
Finite state does not mean a short search is complete
A finite instance can have deep reachable failures and many paths revisiting the same states. Distinct-state exploration avoids treating every repeated path as a new state, but path depth and state count remain different measures. A counter with eight residue values and one Boolean history flag has at most sixteen valuations. Returning to the same residue does not return to the same full state if the flag changed. Dropping that flag can erase the very property being checked, turning a smaller model into a model of a different contract.
Bounds and constraints require a semantic review. Restricting a parameter to three workers defines a finite instance. Artificially pruning states when a queue exceeds two messages can exclude an overflow failure, especially if that boundary is being investigated. The exact order of constraint and property handling is tool-specific, so inspect it rather than using pruning as a hidden proof premise. A valid cutoff theorem can justify a small instance for a particular parameterized property, but the existence of such a theorem must be established rather than inferred from several successful sizes.
Preserve witnesses and interpret successful scope exactly
Store a failing trace with its specification and configuration, then identify which action first violates the property. Minimize the witness without changing its essential crash, message, or identity assumptions. For successful checks, retain bounds and termination evidence rather than only a green screenshot. A regression suite can compare several small domains and deliberately injected mutants, while an inductive proof or justified reduction addresses a stronger claim. Each method supplies different evidence; their results should not be flattened into a single unqualified 'verified' label.
The modular instrument illustrates a residue that hides history. Reset, set modulus m=8 and additive step a=1, predict residues zero initially, seven after seven transitions, and zero after eight, then take eight Steps. The instrument advances one transition per half-second Step and reports period eight. It has no overflow flag and does not mark the return to zero as an error. The separate counterexample below adds such a flag deliberately. This additive orbit is neither TLC nor a bounded checker and cannot establish that a service's state abstraction preserves its safety property.
Work it through
The first failure lies just past the chosen bound
A model starts with counter c=0 and bad=false. Each transition increments c while c<7, leaving bad unchanged. At c=7, the next transition sets c'=0 and bad'=true; bad stays true thereafter. Safety requires bad=false. Compare bounds of seven and eight transitions.
Through seven transitions, the counter takes values zero through seven while bad remains false. There are eight visited states including the initial state, so the safety query finds no violation at this depth.
The eighth transition wraps the counter from seven to zero and sets bad=true. This ninth visited state violates safety even though its counter residue matches the initial residue.
The full variable domain has 8×2=16 possible valuations. In this deterministic model all sixteen are eventually reachable, but the first bad state already appears at depth eight. A seven-transition success did not establish their safety.
Bound seven misses the bug; bound eight contains its witness. The complete state includes the history flag, not just the displayed residue.
The living notebook
Explore the model
Interactive lab · modular
The same residue can conceal different histories
Reset, set m=8 and a=1, predict period 8 and residues r₇=7, r₈=0, then take eight Steps. Each Step advances n by one. The additive orbit contains no bad flag or model-checking search; it illustrates why a residue-only state omits the worked example's overflow history.
- Residue r0
- 0
- Orbit period · m/gcd(m,a)
- 12
- Distinct residues visited
- 1 of 12
Addition modulo m starts at zero: rₙ = na mod m. Playback advances two additions per second. The orbit has period m/gcd(m,a), including period one for a = 0. This is not a cryptographic security test or a primality algorithm. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forA smaller state representation must preserve the distinctions the property observes.
Pause & reason
Check your understanding
Your turn
Try it yourself
An unconstrained execution tree has exactly three choices at each step and depth four. Count depth-four paths and all tree nodes through depth four. Explain why those counts need not equal the number of distinct states in a model checker.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Use 3⁴ for leaves and add the geometric levels from depth zero through four.
Compare with the solution
There are 3⁴=81 depth-four paths and 1+3+9+27+81=121 tree nodes. Different paths can reach the same state, so distinct-state exploration can merge them. Conversely, a depth-four bound can miss a deeper state even if many shallow paths were checked. Neither path volume nor a raw state-count estimate substitutes for a justified completeness argument.
Keep the idea
Take it with you
- Execution depth, parameter domains, and complete finite-state exploration are different scopes.
- No bounded counterexample does not imply unbounded or arbitrary-size correctness.
- Record configuration, completion status, and the state distinctions relevant to the property.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.