Weakest Precondition Calculus
Origin. Edsger Dijkstra (1975, "Guarded Commands, Nondeterminacy and Formal Derivation of Programs"; 1976 monograph). A predicate-transformer semantics giving each program a function on postconditions, turning correctness reasoning into predicate calculus and supporting the systematic derivation of programs from specifications.
Models. Programs as predicate transformers. Rather than assert Hoare triples directly, each command S is interpreted as a function wp(S, ·) mapping a postcondition R to the weakest predicate on the initial state guaranteeing that S terminates in a state satisfying R. Correctness becomes an implication between predicates; program construction becomes calculation.
Formalism.
Weakest precondition: wp(S, R) = the weakest P such that {P} S {R} holds in the total-correctness sense (S terminates and establishes R). Hoare triple recovered: {P} S {R} iff P ⇒ wp(S, R).
Healthiness conditions (Dijkstra): Law of the excluded miracle: wp(S, false) = false. Monotonicity: R ⇒ Q implies wp(S,R) ⇒ wp(S,Q). Conjunctivity: wp(S, R ∧ Q) = wp(S,R) ∧ wp(S,Q). Disjunctivity (for deterministic S): wp(S, R ∨ Q) = wp(S,R) ∨ wp(S,Q).
Rules for the guarded-command language: skip: wp(skip, R) = R assignment: wp(x := e, R) = R[x ↦ e] sequence: wp(S₁; S₂, R) = wp(S₁, wp(S₂, R)) conditional: wp(if □ᵢ Bᵢ → Sᵢ fi, R) = (∃i. Bᵢ) ∧ ∀i. (Bᵢ ⇒ wp(Sᵢ, R)) loop: wp(do B → S od, R) via an invariant I and a variant (bound function) t decreasing on each iteration and bounded below.
Variants: wp = total correctness (demands termination); wlp (weakest liberal precondition) = partial correctness, dropping the termination requirement (wlp(S,false) may be true). Decomposition: wp(S, R) = wlp(S, R) ∧ wp(S, true).
Two different dualities — do not conflate them: Conjugate (angelic vs demonic): wp°(S, R) = ¬ wp(S, ¬R). Adjoint (backward vs forward): sp(S, P) ⇒ R iff P ⇒ wlp(S, R). Strongest postcondition is the adjoint, not the conjugate.
Loop as a limit (Dijkstra): H₀(R) = ¬B ∧ R; H_{k+1}(R) = H₀(R) ∨ (B ∧ wp(S, H_k(R))). wp(do B → S od, R) = ∃k ≥ 0. H_k(R) — valid when nondeterminism is bounded.
Symbols.
| Symbol | Unicode | Name | Meaning |
|---|---|---|---|
| wp(S, R) | — | Weakest precondition | Weakest P with S terminating in R |
| wlp(S, R) | — | Weakest liberal precondition | Same, termination not required |
| sp(S, P) | — | Strongest postcondition | Forward transformer, adjoint to wlp |
| R[x ↦ e] | — | Substitution | e replaces x in R |
| ↦ | U+21A6 | Maps to | Binds the substituted variable |
| □ | U+25A1 | Box / Alternative separator | Separates guarded commands |
| ⇒ | U+21D2 | Implication | Entailment between predicates |
| ∧ | U+2227 | Conjunction | Conjunctivity healthiness condition |
| ∨ | U+2228 | Disjunction | Disjunctivity for deterministic S |
| ∃ | U+2203 | Existential quantifier | Some guard holds; some iteration count suffices |
| ∀ | U+2200 | Universal quantifier | Every enabled guard must establish R |
| → | U+2192 | Guard arrow | Separates guard from body in Bᵢ → Sᵢ |
| ° | U+00B0 | Conjugate | Angelic dual of a transformer |
| I, t | — | Invariant, variant | Loop invariant and bound function |
Metatheory. The transformer semantics is equivalent to Hoare logic and strictly more algebraic: sequencing is function composition, so wp is compositional by construction, and a partial triple is exactly P ⇒ wlp(S, R) while a total triple is P ⇒ wp(S, R). Dijkstra's healthiness conditions are a characterization, not a convenience. Universally conjunctive transformers are exactly those arising from purely demonic (relational) commands; universally disjunctive ones are the angelic commands; transformers that are both are the total deterministic functions; and the merely monotone transformers are the general angelic-demonic games — the classification underlying Back and von Wright's refinement calculus. Continuity is equivalent to bounded nondeterminism, and it is precisely what licenses Dijkstra's ∃k characterization of the loop; Apt and Plotkin (1986) showed that countable nondeterminism destroys continuity and forces variants ranging over countable ordinals rather than ℕ. Flanagan and Saxe (2001) settled the cost of verification-condition generation: naive backward substitution through nested conditionals is exponential in program size, and their passive-form translation brings the obligation down to worst-case quadratic. The resulting obligations are first-order formulas whose validity is undecidable.
Applies to. Formal program derivation and correctness-by-construction. Verification-condition generation (Dafny, Boogie, ESC/Java, Why3). Refinement calculus and specification languages. Teaching rigorous imperative reasoning.
Limitations. The calculus computes wp for every construct except the loop, where the value is a fixpoint the syntax cannot name; supplying it means supplying an invariant, and by Cook's relative-completeness analysis the required invariant need not be expressible in the assertion language at all. The law of the excluded miracle, wp(S, false) = false, blocks specification statements outright — the refinement calculus of Back, Morris, and Morgan works only after that healthiness condition is dropped, so Dijkstra's axioms and program refinement are incompatible as stated. The assignment rule wp(x := e, R) = R[x ↦ e] presupposes that variables do not alias and that e is total and side-effect-free; heap update, integer overflow, and division break it, and repairing the first requires a select-store array theory or the separating conjunction. Continuity fails under unbounded nondeterminism, so the ∃k characterization of the loop is simply false there. Naive verification-condition generation is exponential in program size. The obligations produced are first-order, and their validity is undecidable, so no decision procedure discharges them all.
© 2026 Lingenic LLC