Lectures onType Theory
Chapter 88
Chapter 88Optional

Possibility Reasoning and Linearizability Hoare Logic

Prerequisites. Direct starred prerequisites: Chapter 87. No later core chapter depends on this route.

Two queue enqueues overlap. After enq(1) and enq(2), either abstract queue [1,2] or [2,1] respects the observed calls. A later dequeue returns 1. The first queue advances to [2]; the second has no transition returning 1. A proof that chose [2,1] before seeing the dequeue is stuck even though the implementation trace is linearizable. The proof state must retain both compatible abstract executions and prune one only when the return makes it impossible.

The operational state has no scheduler component

The LTS and module operations are those of definition 87.2, definition 87.3. This chapter freezes the exact logic-facing state rather than adding an external scheduler.

Definition 88.1 — Thread and interaction states

For underlay signature E and overlay signature F, a thread state is IdleCont(m,p)UCall(m,u,k), where m:F(A), p:ProgE(A), and the last form records a suspended underlay call u:E(B) with continuation k:BProgE(A). A thread map assigns one such state to every i:Name(T). For VE:SpecT(E), an interaction state is a pair (q,s) of a thread map and a state of VE.

Overlay calls and returns use CL-Overlay-call and CL-Overlay-ret. Underlay calls and returns use CL-Underlay-call and CL-Underlay-ret. A silent step changes Cont(m,Tau(p)) to Cont(m,p). An interleaving step chooses a thread name i and changes only its thread state, together with the underlay state when the chosen rule has an underlay event. The chosen name is part of the transition label; no scheduler object occurs in the state.

Possibilities retain future-compatible linearizations

Definition 88.2 — Possibilities and possibility sets

For a target specification VF:SpecT(F), a possibility is a triple ρ=ρS,ρC,ρR. The component ρS is a state of VF. The components ρC and ρR are partial maps indexed by thread. For each thread, ρC has one of the three forms CallIdle,CallPoss(m),CallDone(m). For each thread, ρR is RetIdle or RetPoss(m,v). A possibility set is represented by its predicate PossSet(VF):=Poss(VF)Prop. Thus the representation admits the empty predicate. Nonemptiness is a proof obligation of commit and return updates, not an invariant of the data type.

The initial possibility has target state sVF and idle call/return maps. An overlay invocation changes the selected thread’s call component from idle to possible without moving the target state. Linearization commits are the only rules that move the target state:

ρSStepVF(i:call(m))σSρC(i)=CallPoss(m)σC(i)=CallDone(m)ρR(i)=σR(i)=RetIdleji. (ρC(j),ρR(j))=(σC(j),σR(j))
ρPossStepiσ
LHL-Commit-call
ρSStepVF(i:ret(m,v))σSρC(i)=σC(i)=CallDone(m)ρR(i)=RetIdleσR(i)=RetPoss(m,v)ji. (ρC(j),ρR(j))=(σC(j),σR(j))
ρPossStepiσ
LHL-Commit-ret

Write PossSteps(ρ,σ) for the reflexive-transitive closure that preserves every unselected thread component at each step.

Definition 88.3 — Lifted possibility update

Let P,Q:PossSet(VF). Define Advance(P,Q) to mean

  1. Q is inhabited;

  2. every σ satisfying Q is reachable by PossSteps from some ρ satisfying P.

The first clause prevents the empty predicate from satisfying an update merely by vacuity. The second is the artifact’s direction of lifted coverage: successors must have represented predecessors. A rule may prune an incompatible predecessor, as the next calculation requires; no converse coverage is built into Advance.

Proposition 88.4 — The ambiguous-queue pruning calculation

After overlapping invocations of enq(1) and enq(2), the possibility set may contain target states [1,2] and [2,1]. If the observed dequeue returns 1, a lifted return commit advances the set to the singleton state [2]. Starting from the forced singleton [2,1] admits no such update.

Proof of Proposition 88.4 — The ambiguous-queue pruning calculation

Proof. From [1,2], the queue rule for dequeue gives [1,2]deq/1[2]. From [2,1], the only dequeue transition returns 2 and reaches [1]. Therefore the successor predicate Q(σ):=(σS=[2]) is inhabited and every one of its elements is reachable from the first predecessor. The incompatible predecessor is pruned. If the predecessor set is the singleton [2,1], no target step labelled deq/1 exists, so the nonemptiness clause of definition 88.3 fails. ◻

Exercise 88.1

★☆☆ Repeat proposition 88.4 when the dequeue returns 2. Give the retained target state and the rejected transition from the other possibility.

Exercise 88.2

★★☆ Let Q be the empty predicate. Show that the universal successor-coverage clause of an update holds vacuously while the nonemptiness clause fails. Explain why omitting nonemptiness would make every impossible concrete return appear provable.

Assertions track concrete and abstract states together

Fix an underlay specification VE, a target specification VF, and an implementation M:Impl(E,F). Let s,t range over interaction states and P,Q over possibility predicates.

Definition 88.5 — Assertions, relations, and stability

A precondition is a predicate P(s,P). A relational assertion is a predicate R(s,P,t,Q). Relational composition is (R;G)(s,P,u,W):=t,Q. R(s,P,t,Q)G(t,Q,u,W). For a precondition P, the mixed composition used below is (P;R)(t,Q):=s,P. P(s,P)R(s,P,t,Q). The relation Q is stable under R when (Q;R)(s,P,t,Q)Q(s,P,t,Q). A precondition is stable when taking one R step from a state that satisfies it yields another state that satisfies it. A postcondition is stable pointwise in its returned value. We abbreviate this relation-stability condition by Stable(R,Q).

For each thread i, the rely Ri describes steps by other threads, and the guarantee Gi describes steps by i. The key side condition is ijGiRj. It turns a guarantee proof for the active thread into the rely step needed by every inactive thread.

Definition 88.6 — Commit, silent, and return obligations

For maps f,g with domain Name(T), put SameExcepti(f,g):=j:Name(T). jig(j)=f(j). The relation UnderStep(u,ω,u) is exactly the local relation given by CL-Underlay-call, CL-Underlay-ret, and the silent clause following those rules; ω is respectively a call, a return, or None. Let s=(q,x) and t=(q,x) range over interaction states, and let X,Y:PossSet(VF).

The judgment Commiti(G,P,e,Q) for e:Event(E) is the following quantified formula: s=(q,x),X,t=(q,x).P(s,X)SameExcepti(q,q)UnderStep(q(i),Some(e),q(i))xStepVE(i:e)xY. Advance(X,Y)Q(s,X,t,Y)G(s,X,t,Y).

The judgment Silenti(G,P,Q) is exact when q,q,x,X. P((q,x),X)SameExcepti(q,q)UnderStep(q(i),None,q(i))Q((q,x),X,(q,x),X)G((q,x),X,(q,x),X). Thus a silent step changes one thread state but keeps both the underlay state and the possibility predicate fixed.

Define Reseti(q,x):=(q[iIdle],x). For m:F(A) and v:A, the consumption relation is Consumei,m,v(ρ,τ):=τC(i)=CallIdleρC(i)=CallDone(m)τR(i)=RetIdleρR(i)=RetPoss(m,v)SameExcepti(ρC,τC)SameExcepti(ρR,τR)τS=ρS, and ConsumeSeti,m,v(Y)(τ):=σ. Y(σ)Consumei,m,v(σ,τ). The judgment ReturnStepi(G,P,m,v,C) is the formula s=(q,x),X. P(s,X)q(i)=Cont(m,Return(v))Y. Advance(X,Y)(σ. Y(σ)σR(i)=RetPoss(m,v)σC(i)=CallDone(m))C(s,X,Reseti(s),ConsumeSeti,m,v(Y))G(s,X,Reseti(s),ConsumeSeti,m,v(Y)). This display includes every premise of the artifact definition: the thread-return observation, successor inhabitation and coverage inside Advance, the two pending-status facts, the reset, and preservation of all unselected possibility components.

Fix m:E(A). The program judgment R,G,i{P} p {Q} is the greatest relation closed by the following three rules. Equivalently, the source declares this judgment coinductively. The visible rule records separate commit obligations for the call and every possible return.

PQ(v)
R,G,i{P} Return(v) {Q}
LHL-Return
Stable(R,S)Silenti(G,P,S)R,G,i{P;S} p {Q}
R,G,i{P}Tau(p){Q}
LHL-Tau
Stable(R,I)Stable(R,Sv) (v:A)Commiti(G,P,call(m),I)v:A. Commiti(G,P;I,ret(m,v),Sv)v:A. R,G,i{P;I;Sv} k(v){Q}
R,G,i{P}Vis(m,k){Q}
LHL-Vis

The rule order follows program observations: return, silent, and visible. At a neutral program no rule applies, because none of the three outer forms is known. For example, if spin=Tau(spin) and there is a relation S with Stable(R,S), Silenti(G,P,S), and P;S=P, then guarded corecursion repeatedly uses LHL-Tau to derive R,G,i{P}spin{Q}. An inductive reading would reject this silent divergence and would therefore be a different logic.

Lemma 88.7 — Rely preservation

Suppose P is stable under Ri and thread ji takes a step satisfying GjRi. Then P holds after that step.

Proof of Lemma 88.7 — Rely preservation

Proof. The concrete step satisfies Gj by the guarantee proof for thread j. The inclusion gives the corresponding Ri step. Stability instantiated with the initial state and possibility predicate gives the final instance of P. ◻

Exercise 88.3

★★☆ Let P assert that a shared lock owner is either none or thread i, and let Ri forbid other threads from changing ownership from i. Prove stability of P. Then delete the rely restriction and give one step that invalidates the assertion.

Module verification and its side conditions

Definition 88.8 — Verified implementation families

A witness VerifyImpl(VE,VF,R,G,P,M,Q,C) consists of families indexed by thread, operation, and return type satisfying:

  1. every Ri is reflexive and transitive;

  2. ij implies GiRj;

  3. overlay invocations and returns by i lie in Rj for ij;

  4. the initial interaction state and singleton initial possibility satisfy every Pi(m);

  5. every Pi(m) is stable under Ri;

  6. after completing one operation, the continuation condition Ci(m,v) implies the precondition of the next operation;

  7. every implementation body M(m) satisfies the program judgment from Pi(m) through invocation and rely closure to Qi(m);

  8. the field all_return proves ReturnStepi(Gi,Pi(m);Qi(m,v),m,v,Ci(m,v)) for every i,m,v.

The family C and the final field are part of the frozen signature. Omitting either one proves a weaker record than the artifact’s VerifyImpl.

Exercise 88.4

★★☆ Let m:F(A), v:A, and let Y:PossSet(VF) be inhabited. Assume every σ satisfying Y has σC(i)=CallDone(m) and σR(i)=RetPoss(m,v). Prove that ConsumeSeti,m,v(Y) is inhabited and that each consumed τ has idle call and return entries at i, preserves the target state, and agrees with its witnessing σ at every ji. State the witness τ as explicit map updates. This is the reset-map sub-obligation of all_return; no unspecified precondition, guarantee, or continuation relation is to be assumed.

The exchanger needs only a singleton possibility predicate. When the second offer is matched, the paired set transition records both possible returns in one target step; subsequent return steps consume them. Thus the exchanger demonstrates a non-atomic specification, not the necessity of multiple possibilities. The ambiguous queue of proposition 88.4 is the witness that forces a non-singleton set.

Theorem 88.9 — Generic lock protection

Let VE be atomic: every invocation transition is immediately followed by its same-thread response. Let Racy(VE) add an undefined-behavior state reached by concurrent invocations. If an implementation ME accesses Racy(VE) only between a successful acquire and its matching release, and a lock implementation is linearizable with respect to the atomic lock specification, then Lin((VLockRacy(VE))ME,VE).

Proof of Theorem 88.9 — Generic lock protection

Proof. Use the invariant that at most one thread is between its acquire and release. If no thread owns the lock, no operation of ME can take a racy-object transition. If thread i owns it, every ji is blocked before its first racy transition. Therefore the undefined-behavior state is unreachable. Each critical section contains one invocation/response pair of the atomic VE and supplies its linearization bracket. The program rules verify the acquire, body, and release sequence under this invariant. Horizontal composition combines lock and racy-object proofs, and vertical composition from theorem 87.8 hides the lock implementation. The remaining visible trace is admitted by VE. ◻

Without mutual exclusion, two threads may enter the racy state, so the unreachable-state step of the proof fails. Without atomic adjacency in VE, one critical section need not determine one abstract transition; the theorem then needs an interval or another non-atomic specification.

The one-shot write-snapshot proof uses an interval-sequential target in which one operation may span several classes. Its proof is separate from theorem 88.9; neither theorem is obtained by renaming the other’s target specification.

Soundness and semantic completeness

Theorem 88.10 — Soundness of LHL

If the following verification record is inhabited, VerifyImpl(VE,VF,R,G,P,M,Q,C), then Lin(VEM,VF).

Proof of Theorem 88.10 — Soundness of LHL

Proof. Induct on a finite execution of VEM, maintaining an inhabited possibility predicate and one invariant for each thread state.

Idle case. For an idle thread i, the precondition Pi(m) holds for every operation that may next be invoked. The initial case uses field four of VerifyImpl; other threads preserve it by lemma 88.7.

Continuation case. For Cont(m,p), the corresponding program judgment relates the remaining program p to its postcondition. A return uses all_return; a silent program step uses LHL-Tau; and a visible operation uses the two commit premises of LHL-Vis. Each commit produces an inhabited successor predicate.

Underlay-call case. For UCall(m,u,k), the call commit has been performed and the return commit is pending. An underlay return supplies the return-commit premise, advances the possibilities, and restores a continuation state. Other-thread steps are handled by the rely inclusion.

At the end of a completed execution every thread is idle. The all_return fields ensure that each retained possibility agrees with the concrete returns. Choose one possibility from the inhabited final predicate. Its target trace is the witness that the concrete trace lies in K(VF), which is Lin by definition 87.6. ◻

Theorem 88.11 — Artifact-faithful semantic completeness

If Lin(VEM,VF), then there exist five families R,G,P,Q,C for which VerifyImpl(VE,VF,R,G,P,M,Q,C). This is semantic, or relative, completeness. It is not an algorithm for inferring the five families.

Proof of Theorem 88.11 — Artifact-faithful semantic completeness

Proof. For an interaction state s and possibility predicate P, define I(s,P) by three clauses:

  1. s is reached by a concrete execution prefix p;

  2. every ρ satisfying P is reached by possibility updates whose overlay projection is the overlay projection of p;

  3. every target execution compatible with that overlay projection has a prefix represented by some ρ satisfying P.

The third clause is the saturation that prevents a future-compatible possibility from being discarded.

Take every rely and guarantee to be the relation I(s,P)I(t,Q) at the appropriate thread step. Take preconditions, postconditions, and continuation conditions to be the instances of I before invocation, after the program return, and after consuming the overlay return. Reflexivity, transitivity, stability, and cross-thread inclusions follow by concatenating execution prefixes.

At a commit, advance to the predicate containing every compatible target successor. Linearizability supplies at least one such successor; clauses two and three prove successor coverage and retain every future-compatible continuation required by the saturation invariant of definition 88.3. At the end of a function, prune to possibilities that record its actual return, then consume that record. This constructs all_return and the family C. The three program forms derive LHL-Return, LHL-Tau, and LHL-Vis, respectively. These fields assemble the required VerifyImpl witness. ◻

The proof constructs assertions from the entire semantic trace relation. Consequently it establishes existence, not usable proof search. Liveness, weak memory, crash behavior, and theorem transfer to Iris, ReLoC, TaDA, or RGSep are outside this system card.

The artifact’s source tree defines the verified exchanger, elimination-array, and stack modules; this chapter does not reproduce their implementation bodies. Combining those source modules uses theorem 88.10 once per module and theorem 87.8 at each vertical or horizontal link. No implementation body is inlined into its client proof.

Suggested first pass.

None of these problems is a prerequisite. Begin with exercise 88.1 and exercise 88.3; for the practical sequence, complete stages 1–3 before the singleton and stability checks.

Exercise 88.5

★★★ Reconstruct the UCall case of theorem 88.10. State the pending call and return components, apply the return commit, and show that every unselected thread component is unchanged. Finish by identifying the continuation-state invariant obtained.

Exercise 88.6

★★☆ Delete clause three of I in the proof of theorem 88.11. Use the queue trace to show that the remaining invariant permits retaining only [2,1], after which the return-1 update has no successor. This is a counterexample to that weakened invariant, not to the theorem.

Exercise 88.7

★★★ Practical project.lhl-possibility-explorer Implement a self-contained Kappa explorer using the queue, possibility, and update definitions supplied in this chapter. Do not consume the checker output of chapter 87. Stage 1 prints {[1,2],[2,1]} after the two enqueues; stage 2 prunes it to {[2]} after deq=1; stage 3 forces singleton [2,1] and prints no-compatible-possibility; stage 4 checks that the exchanger fixture remains singleton; stage 5 checks successor nonemptiness and one stability fixture. Maintain the invariant that every retained possibility has the concrete overlay projection and at least one compatible target continuation. A mutation that retains the incompatible [2,1] state after deq=1 must fail the acceptance test.

Sources. The operational records, possibility representation, program rules, VerifyImpl fields, and soundness/completeness boundaries are frozen to Hatti, Oliveira Vale, Wang, Feng, and Shao’s ECOOP 2026 paper, technical report, and artifact commit 6238a59af9515220d41869abf104e14d1dd26dbd. The artifact defines PossSet as a predicate, includes C and all_return, and proves existence of all five families. Native Rocq replay checks that artifact; it is not evidence that the Kappa explorer proves the logic sound. The paper-level theorem statements are in [HOVW^+26].

Search the book

Type to search the local edition.