# Predicate transformer semantics

(Redirected from Weakest precondition calculus)

Predicate transformer semantics were introduced by Edsger Dijkstra in his seminal paper "Guarded commands, nondeterminacy and formal derivation of programs". They define the semantics of an imperative programming paradigm by assigning to each statement in this language a corresponding predicate transformer: a total function between two predicates on the state space of the statement. In this sense, predicate transformer semantics are a kind of denotational semantics. Actually, in guarded commands, Dijkstra uses only one kind of predicate transformer: the well-known weakest preconditions (see below).

Moreover, predicate transformer semantics are a reformulation of Floyd–Hoare logic. Whereas Hoare logic is presented as a deductive system, predicate transformer semantics (either by weakest-preconditions or by strongest-postconditions see below) are complete strategies to build valid deductions of Hoare logic. In other words, they provide an effective algorithm to reduce the problem of verifying a Hoare triple to the problem of proving a first-order formula. Technically, predicate transformer semantics perform a kind of symbolic execution of statements into predicates: execution runs backward in the case of weakest-preconditions, or runs forward in the case of strongest-postconditions.

## Weakest preconditions

### Definition

For a statement S and a postcondition R, a weakest precondition is a predicate Q such that for any precondition ${\displaystyle P}$, ${\displaystyle \{P\}S\{R\}}$ if and only if ${\displaystyle P\Rightarrow Q}$. In other words, it is the "loosest" or least restrictive requirement needed to guarantee that R holds after S. Uniqueness follows easily from the definition: If both Q and Q' are weakest preconditions, then by the definition ${\displaystyle \{Q'\}S\{R\}}$ so ${\displaystyle Q'\Rightarrow Q}$ and ${\displaystyle \{Q\}S\{R\}}$ so ${\displaystyle Q\Rightarrow Q'}$, and thus ${\displaystyle Q=Q'}$. Denote by ${\displaystyle wp(S,R)}$ the weakest precondition for statement S and postcondition R.

### Skip

 ${\displaystyle wp({\textbf {skip}},R)\ =\ R}$

### Abort

 ${\displaystyle wp({\textbf {abort}},R)\ =\ {\textbf {false}}}$

### Assignment

We give below two equivalent weakest-preconditions for the assignment statement. In these formulas, ${\displaystyle R[x\leftarrow E]}$ is a copy of R where free occurrences of x are replaced by E. Hence, here, expression E is implicitly coerced into a valid term of the underlying logic: it is thus a pure expression, totally defined, terminating and without side effect.

• version 1:
 ${\displaystyle wp(x:=E,R)\ =\ \forall y,y=E\Rightarrow R[x\leftarrow y]}$ where y is a fresh variable (representing the final value of variable x)
• version 2:
 ${\displaystyle wp(x:=E,R)\ =\ R[x\leftarrow E]}$

The first version avoids a potential duplication of E in R, whereas the second version is simpler when there is at most a single occurrence of x in R. The first version also reveals a deep duality between weakest-precondition and strongest-postcondition (see below).

An example of a valid calculation of wp (using version 2) for assignments with integer valued variable x is:

${\displaystyle {\begin{array}{rcl}wp(x:=x-5,x>10)&=&x-5>10\\&\Leftrightarrow &x>15\end{array}}}$

This means that in order for the postcondition x > 10 to be true after the assignment, the precondition x > 15 must be true before the assignment. This is also the "weakest precondition", in that it is the "weakest" restriction on the value of x which makes x > 10 true after the assignment.

### Sequence

 ${\displaystyle wp(S_{1};S_{2},R)\ =\ wp(S_{1},wp(S_{2},R))}$

For example,

${\displaystyle {\begin{array}{rcl}wp(x:=x-5;x:=x*2\ ,\ x>20)&=&wp(x:=x-5,wp(x:=x*2,x>20))\\&=&wp(x:=x-5,x*2>20)\\&=&(x-5)*2>20\\&=&x>15\end{array}}}$

### Conditional

 ${\displaystyle wp({\textbf {if}}\ E\ {\textbf {then}}\ S_{1}\ {\textbf {else}}\ S_{2}\ {\textbf {end}},R)\ =\ (E\Rightarrow wp(S_{1},R))\wedge (\neg E\Rightarrow wp(S_{2},R))}$

As example:

${\displaystyle {\begin{array}{rcl}wp({\textbf {if}}\ x

### While loop

#### Partial Correctness

Ignoring termination for a moment, we can define the rule for the weakest liberal precondition, denoted wlp, using a predicate I, called the loop invariant, typically supplied by the programmer:

 ${\displaystyle wlp({\textbf {while}}\ E\ {\textbf {do}}\ S\ {\textbf {done}},R)\ =\ {\begin{array}{l}I\\\wedge \ \forall y,((E\wedge I)\Rightarrow wlp(S,I))[x\leftarrow y]\\\wedge \ \forall y,((\neg E\wedge I)\Rightarrow R)[x\leftarrow y]\end{array}}}$

This simply states that (1) the invariant must hold at the start of the loop; (2) additionally, for any initial state y, the invariant and guard taken together be strong enough to establish the weakest precondition necessary for the loop body to be able to re-establish the invariant; (3) finally, if and when the loop terminates in a given state y, the fact that the loop guard is false along with the invariant should be able to establish the required postcondition.

#### Total Correctness

To show total correctness, we also have to show that the loop terminates. For this we define a well-founded relation on the state space denoted "<" and called loop variant. Hence, we have:

 ${\displaystyle wp({\textbf {while}}\ E\ {\textbf {do}}\ S\ {\textbf {done}},R)\ =\ {\begin{array}{l}I\\\wedge \ \forall y,((E\wedge I)\Rightarrow wp(S,I\wedge x where y is a fresh tuple of variables

Informally, in the above conjunction of three formulas:

• the first one means that invariant I must initially hold;
• the second one means that the body of the loop (e.g. statement S) must preserve the invariant and decrease the variant: here, variable y represents the initial state of the body execution;
• the last one means that R must be established at the end of the loop: here, variable y represents the final state of the loop.

In predicate transformers semantics, invariant and variant are built by mimicking the Kleene fixed-point theorem. Below, this construction is sketched in set theory. We assume that U is a set denoting the state space. First, we define a family of subsets of U denoted ${\displaystyle (A_{k})_{k\in \mathbb {N} }}$ by induction over natural number k. Informally ${\displaystyle A_{k}}$ represents the set of initial states that makes R satisfied after less than k iterations of the loop:

${\displaystyle {\begin{array}{rcl}A_{0}&=&\emptyset \\A_{k+1}&=&\left\{\ y\in U\ |\ ((E\Rightarrow wp(S,x\in A_{k}))\wedge (\neg E\Rightarrow R))[x\leftarrow y]\ \right\}\\\end{array}}}$

Then, we define:

• invariant I as the predicate ${\displaystyle \exists k,x\in A_{k}}$.
• variant ${\displaystyle y as the proposition ${\displaystyle \exists i,y\in A_{i}\wedge (\forall j,z\in A_{j}\Rightarrow i

With these definitions, ${\displaystyle wp({\textbf {while}}\ E\ {\textbf {do}}\ S\ {\textbf {done}},R)}$ reduces to formula ${\displaystyle \exists k,x\in A_{k}}$.

However, in practice, such an abstract construction cannot be handled efficiently by theorem provers. Hence, loop invariants and variants are provided by human users, or are inferred by some abstract interpretation procedure.

### Non-deterministic guarded commands

Actually, Dijkstra's Guarded Command Language (GCL) is an extension of the simple imperative language given until here with non-deterministic statements. Indeed, GCL aims to be a formal notation to define algorithms. Non-deterministic statements represent choices left to the actual implementation (in an effective programming language): properties proved on non-deterministic statements are ensured for all possible choices of implementation. In other words, weakest-preconditions of non-deterministic statements ensure

• that there exists a terminating execution (e.g. there exists an implementation),
• and, that the final state of all terminating execution satisfies the postcondition.

Notice that the definitions of weakest-precondition given above (in particular for while-loop) preserve this property.

#### Selection

Selection is a generalization of if statement:

 ${\displaystyle wp(\mathbf {if} \ E_{1}\rightarrow S_{1}\ [\!]\ \ldots \ [\!]\ E_{n}\rightarrow S_{n}\ \mathbf {fi} ,R)\ ={\begin{array}{l}(E_{1}\vee \ldots \vee E_{n})\\\wedge \ (E_{1}\Rightarrow wp(S_{1},R))\\\ldots \\\wedge \ (E_{n}\Rightarrow wp(S_{n},R))\\\end{array}}}$

Here, when two guards ${\displaystyle E_{i}}$ and ${\displaystyle E_{j}}$ are simultaneously true, then execution of this statement can run any of the associated statement ${\displaystyle S_{i}}$ or ${\displaystyle S_{j}}$.

#### Repetition

Repetition is a generalization of while statement in a similar way.

### Specification statement (or weakest-precondition of procedure call)

Refinement calculus extends non-deterministic statements with the notion of specification statement. Informally, this statement represents a procedure call in black box, where the body of the procedure is not known. Typically, using a syntax close to B-Method, a specification statement is written

${\displaystyle P\ |}$ @${\displaystyle y.\ Q\rightarrow x:=y}$

where

• x is the global variable modified by the statement,
• P is a predicate representing the precondition,
• y is a fresh logical variable, bound in Q, that represents the new value of x non-deterministically chosen by the statement,
• Q is a predicate representing a postcondition, or more exactly a guard: in Q, variable x represents the initial state and y denotes the final state.

The weakest-precondition of specification statement is given by:

 ${\displaystyle wp(P\ |}$ @${\displaystyle y.\ Q\rightarrow x:=y\ ,\ R)\ =\ P\wedge \forall z,Q[y\leftarrow z]\Rightarrow R[x\leftarrow z]}$ where z is a fresh name

Moreover, a statement S implements such a specification statement if and only if the following predicate is a tautology:

 ${\displaystyle \forall x_{0},(P\Rightarrow wp(S,Q[x\leftarrow x_{0}][y\leftarrow x]))[x\leftarrow x_{0}]}$ where ${\displaystyle x_{0}}$ is a fresh name (denoting the initial state)

Indeed, in such a case, the following property is ensured for all postcondition R (this is a direct consequence of wp monotonicity, see below):

${\displaystyle wp(P\ |}$ @${\displaystyle y.\ Q\rightarrow x:=y\ ,\ R)\Rightarrow wp(S,R)}$

Informally, this last property ensures that any proof about some statement involving a specification remains valid when replacing this specification by any of its implementations.

## Other predicate transformers

### Weakest liberal precondition

An important variant of the weakest precondition is the weakest liberal precondition ${\displaystyle wlp(S,R)}$, which yields the weakest condition under which S either does not terminate or establishes R. It therefore differs from wp in not guaranteeing termination. Hence it corresponds to Hoare logic in partial correctness: for the statement language given above, wlp differs with wp only on while-loop, in not requiring a variant (see above).

### Strongest postcondition

Given S a statement and R a precondition (a predicate on the initial state), then ${\displaystyle sp(S,R)}$ is their strongest-postcondition: it implies any postcondition satisfied by the final state of any execution of S, for any initial state satisfying R. In other words, a Hoare triple ${\displaystyle \{P\}S\{Q\}}$ is provable in Hoare logic if and only if the predicate below hold:

${\displaystyle \forall x,sp(S,P)\Rightarrow Q}$

Usually, strongest-postconditions are used in partial correctness. Hence, we have the following relation between weakest-liberal-preconditions and strongest-postconditions:

${\displaystyle (\forall x,P\Rightarrow wlp(S,Q))\ \Leftrightarrow \ (\forall x,sp(S,P)\Rightarrow Q)}$

For example, on assignment we have:

 ${\displaystyle sp(x:=E,R)\ =\ \exists y,x=E[x\leftarrow y]\wedge R[x\leftarrow y]}$ where y is fresh

Above, the logical variable y represents the initial value of variable x. Hence,

${\displaystyle sp(x:=x-5,x>15)\ =\ \exists y,x=y-5\wedge y>15\ \Leftrightarrow \ x>10}$

On sequence, it appears that sp runs forward (whereas wp runs backward):

 ${\displaystyle sp(S_{1};S_{2}\ ,\ R)\ =\ sp(S_{2},sp(S_{1},R))}$

### Win and sin predicate transformers

Leslie Lamport has suggested win and sin as predicate transformers for concurrent programming.[1]

## Predicate transformers properties

This section presents some characteristic properties of predicate transformers.[2] Below, T denotes a predicate transformer (a function between two predicates on the state space) and P a predicate. For instance, T(P) may denote wp(S,P) or sp(S,P). We keep x as the variable of the state space.

### Monotonic

Predicate transformers of interest (wp, wlp, and sp) are monotonic. A predicate transformer T is monotonic if and only if:

${\displaystyle (\forall x,P\Rightarrow Q)\Rightarrow (\forall x,T(P)\Rightarrow T(Q))}$

This property is related to the consequence rule of Hoare logic.

### Strict

A predicate transformer T is strict iff:

${\displaystyle T(\mathbf {false} )\ \Leftrightarrow \ \mathbf {false} }$

For instance, wp is strict, whereas wlp is generally not. In particular, if statement S may not terminate then ${\displaystyle wlp(S,\mathbf {false} )}$ is satisfiable. We have

${\displaystyle wlp(\mathbf {while} \ \mathbf {true} \ \mathbf {do} \ \mathbf {skip} \ \mathbf {done} ,\mathbf {false} )\ \Leftrightarrow \mathbf {true} }$

Indeed, true is a valid invariant of that loop.

### Terminating

A predicate transformer T is terminating iff:

${\displaystyle T(\mathbf {true} )\ \Leftrightarrow \ \mathbf {true} }$

Actually, this terminology makes sense only for strict predicate transformers: indeed, ${\displaystyle wp(S,\mathbf {true} )}$ is the weakest-precondition ensuring termination of S.

It seems that naming this property non-aborting would be more appropriate: in total correctness, non-termination is abortion, whereas in partial correctness, it is not.

### Conjunctive

A predicate transformer T is conjunctive iff:

${\displaystyle T(P\wedge Q)\ \Leftrightarrow \ (T(P)\wedge T(Q))}$

This is the case for ${\displaystyle wp(S,.)}$, even if statement S is non-deterministic as a selection statement or a specification statement.

### Disjunctive

A predicate transformer T is disjunctive iff:

${\displaystyle T(P\vee Q)\ \Leftrightarrow \ (T(P)\vee T(Q))}$

This is generally not the case of ${\displaystyle wp(S,.)}$ when S is non-deterministic. Indeed, consider a non-deterministic statement S choosing an arbitrary boolean. This statement is given here as the following selection statement:

${\displaystyle S\ =\ \mathbf {if} \ \mathbf {true} \rightarrow x:=0\ [\!]\ \mathbf {true} \rightarrow x:=1\ \mathbf {fi} }$

Then, ${\displaystyle wp(S,R)}$ reduces to the formula ${\displaystyle R[x\leftarrow 0]\wedge R[x\leftarrow 1]}$.

Hence, ${\displaystyle wp(S,\ x=0\vee x=1)}$ reduces to the tautology ${\displaystyle (0=0\vee 0=1)\wedge (1=0\vee 1=1)}$

Whereas, the formula ${\displaystyle wp(S,x=0)\vee wp(S,x=1)}$ reduces to the wrong proposition ${\displaystyle (0=0\wedge 1=0)\vee (1=0\wedge 1=1)}$.

The same counter-example can be reproduced using a specification statement (see above) instead:

${\displaystyle S\ =\ \mathbf {true} \ |}$ @${\displaystyle y.\ y\in \{0,1\}\rightarrow x:=y}$

## Beyond predicate transformers

### Weakest-preconditions and strongest-postconditions of imperative expressions

In predicate transformers semantics, expressions are restricted to terms of the logic (see above). However, this restriction seems too strong for most existing programming languages, where expressions may have side effects (call to a function having a side effect), may not terminate or abort (like division by zero). There are many proposals to extend weakest-preconditions or strongest-postconditions for imperative expression languages and in particular for monads.

Among them, Hoare Type Theory combines Hoare logic for a Haskell-like language, separation logic and type theory.[6] This system is currently implemented as a Coq library called Ynot.[7] In this language, evaluation of expressions corresponds to computations of strongest-postconditions.

### Probabilistic Predicate Transformers

Probabilistic Predicate Transformers are an extension of predicate transformers for probabilistic programs. Indeed, such programs have many applications in cryptography (hiding of information using some randomized noise), distributed systems (symmetry breaking). [8]

## Notes

1. ^ Lamport, Leslie (July 1990). "win and sin: Predicate Transformers for Concurrency". ACM Trans. Program. Lang. Syst. 12 (3): 396–428. CiteSeerX 10.1.1.33.90. doi:10.1145/78969.78970. S2CID 209901.
2. ^ Back, Ralph-Johan; Wright, Joakim (2012) [1978]. Refinement Calculus: A Systematic Introduction. Texts in Computer Science. Springer. ISBN 978-1-4612-1674-2.
3. ^ Dijkstra, Edsger W. (1968). "A Constructive Approach to the Problem of Program Correctness". BIT Numerical Mathematics. 8 (3): 174–186. doi:10.1007/bf01933419. S2CID 62224342.
4. ^ Wirth, N. (April 1971). "Program development by stepwise refinement" (PDF). Comm. ACM. 14 (4): 221–7. doi:10.1145/362575.362577. hdl:20.500.11850/80846. S2CID 13214445.
5. ^ Tutorial on Hoare Logic: a Coq library, giving a simple but formal proof that Hoare logic is sound and complete with respect to an operational semantics.
6. ^ Nanevski, Aleksandar; Morrisett, Greg; Birkedal, Lars (September 2008). "Hoare Type Theory, Polymorphism and Separation" (PDF). Journal of Functional Programming. 18 (5–6): 865–911. doi:10.1017/S0956796808006953.
7. ^ Ynot a Coq library implementing Hoare Type Theory.
8. ^ Morgan, Carroll; McIver, Annabelle; Seidel, Karen (May 1996). "Probabilistic Predicate Transformers" (PDF). ACM Trans. Program. Lang. Syst. 18 (3): 325–353. CiteSeerX 10.1.1.41.9219. doi:10.1145/229542.229547. S2CID 5812195.