A Predicate Transformer for Choreographies Computing Preconditions in Choreographic Programming

. Construction and analysis of distributed systems is diﬃcult; choreographic programming is a deadlock-freedom-by-construction approach to simplify it. In this paper, we present a new theory of chore-ographic programming. It supports for the ﬁrst time: construction of distributed systems that require decentralised decision making (i.e., if/ while-statements with multiparty conditions); analysis of distributed systems to provide not only deadlock freedom but also functional correctness (i.e., pre/postcondition reasoning). Both contributions are enabled by a single new technique, namely a predicate transformer for choreographies.


Introduction
Construction and analysis of distributed systems that consist of message passing processes is hard. Typical challenges include providing deadlock freedom (i.e., the processes never get stuck) and functional correctness (i.e., the processes compute the intended outcome). Choreographic programming [8,9,10] is a deadlockfreedom-by-construction approach to make implementation and verification of distributed systems easier. In this paper, to address two limitations of existing theories, we present a new theory of choreographic programming. It supports for the first time: construction of distributed systems that require decentralised decision making; analysis of distributed systems to provide not only deadlock freedom but also functional correctness.

Background: Choreographic Programming by Example
To explain choreographic programming, consider a distributed system in which two processes enact roles Client and Server. First, a username and password are communicated from Client to Server. Next, Server checks Client's credentials and informs Client about the outcome: if authentication succeeded, the execution continues; if it failed, it ends. We construct and analyse this system as follows: all construction/analysis activities happen here (manual) all deployment/execution activities happen there (automatic) G L1 L2 · · · Ln global program projection local programs Fig. 1: Workflow of choreographic programming In this notation, p.e q.y prescribes a value communication to share data from role p to role q: expression e is evaluated at p, sent at p, received at q, and stored in variable y at q. Similarly, p.
q prescribes a label communication to share decisions: label is actively selected at p ("internal choice"), sent at p, received at q, and passively branched on at q ("external choice"). Furthermore, G 1 ; G 2 and if r.e G 1 G 2 prescribe a sequence and a conditional choice (i.e., if e is evaluated to true at r, then G 1 is executed, or else G 2 ). Now, informally, the first theorem of choreographic programming is this: Theorem 1 (Deadlock Freedom). Every global program is deadlock-free.
2. Subsequently, we decompose global program G into local programs L C and L S ("the processes"), using a projection function; every local program prescribes the behaviour of one role, individually, from its own perspective. In this notation, pq !e and pq?y prescribe a send and a receive of a value from p to q. Similarly, pq ! and pq?{ i : L i } i∈I prescribe a send and a receive of a label (i.e., if j is received for some j ∈ I, then L j is executed). Now, informally, the second theorem of choreographic programming is this: Theorem 2 (Operational Equivalence). Every well-formed global program is operationally equivalent to the parallel composition of its projections.
"Well-formedness" is a syntactic condition on global programs; we discuss it in more detail later. Here, we just claim that G above is indeed well-formed.
3. Finally, we compose local programs L C and L S in parallel ("the distributed system"), by deploying them concurrently, and by executing them at their own pace; as they run, L C and L S send and receive messages as prescribed. Now, Thm. 1 and Thm. 2 together entail that L C and L S are deadlock-free, by construction, without extra analysis. Figure 1 summarises the workflow.

Related Work: State of the Art & Open Problems
Early work on choreographic programming was presented by Carbone et al. [8,9] (using binary session types [34]) and by Carbone and Montesi [10] (using multiparty session types [35]); substantial progress has been made since. For instance, Montesi and Yoshida developed a theory of compositional choreographic programming that supports open distributed systems [42]; Carbone et al. studied connections between choreographic programming and linear logic [11,12,7]; Dalla Preda et al. combined choreographic programming with dynamic adaptation [48,46,47]; Cruz-Filipe and Montesi developed a minimal Turing-complete language of global programs [16,19]; Cruz-Filipe et al. presented a technique to extract global programs from families of local programs ("choreography extraction") [14]; and recently, Giallorenzo et al. studied a correspondence between choreographic programming and multitier languages [29]. Other work on choreographic programming includes results on case studies [15], procedural abstractions [18], asynchronous communication [17], polyadic communication [20,31], implementability [28], and formalisation/mechanisation in Coq [21,22]. Furthermore, theoretical developments are supported in practice by several tools, including Chor [10], AIOCJ [48,47], and Choral [29]. However, all publications cited above have two limitations: 1. Regarding the construction of distributed systems, existing work on choreographic programming supports only centralised decision making: every if/ while-statement in a global program has a one-party condition, evaluated at a single role. For instance, in the example above, the decision to continue or end the execution is made by Server alone; Client is duly informed afterwards-with a label communication-as it needs to know how to proceed, but the decision is really Server's. However, in many distributed systems, it is impractical (i.e., unnecessary or unnatural), or even impossible, for a single role to make decisions. For instance, consider a distributed system in which two processes enact roles Player1 and Player2 to simulate a game of chess. The idea is that, at the end of every turn, a move is communicated from "active" Playeri to "passive" Playerj, after which a decision must be made: should Playerj take a next turn, or is the game over? The key point here is that every role has enough knowledge to check if the latest move is, in fact, the final one. So after every turn, every role can privately-without a label communication-decide to continue or end the execution; moreover, unanimity is guaranteed. It is, thus, unnecessary to additionally use a label communication to have one role explicitly inform the other one about how to proceed. Yet, all publications cited above force the usage of a label communication in this situation anyway.
2. Regarding the analysis of distributed systems, existing work on choreographic programming focusses on providing deadlock freedom. In contrast, providing functional correctness has not received due attention. This is surprising: given the sequential programming style in which global programs are expressed, it seems worthwhile to study how classical verification techniques for sequential code can be adapted to choreographic programming.

Analysis:
The new theory ensures that if the precondition is true in the initial state of a global program, then after executing the global program, the postcondition is true in the final state. Similar to deadlock freedom, this form of functional correctness is conferred from the global program to the parallel composition of its projections, by operational equivalence. In both examples, we noted that "unanimity is guaranteed"; this is crucially important to provide deadlock freedom. As a counterexample of what can go wrong in the absence of unanimity, suppose that Bob's condition in Tab. 1 were x2==true (i.e., he ignores Alice's value). In that case, unanimity is not guaranteed, so Alice and Bob can diverge: Alice privately decides to enter one branch, while Bob privately decides to enter the other branch. A deadlock subsequently ensues if, for instance, Alice needs to await a message from Bob in her branch, while Bob needs to await a message from Alice in his branch.
Thus, the key challenge to support decentralised decision making in choreographic programming is this: "How to check if unanimity is guaranteed?" The pivotal insight is that this question can be reduced to a seemingly unrelated one: "Given a global program and a postcondition, how to compute a precondition?" It was first answered for sequential code by Dijkstra in the 1970s [26], in terms of a predicate transformer to compute weakest preconditions. A crucial technical contribution of this paper is a non-trivial adaptation of Dijkstra's seminal work, tailored for choreographic programming, to provide not only functional correctness (i.e., ensure the truth of the postcondition) but also deadlock freedom in the presence of decentralised decision making (i.e., ensure unanimity).

Organisation of This Paper
In Sect. 2, to further motivate this paper's new theory, we present more examples of real(istic) distributed systems that require decentralised decision making.
The new theory is presented in Sects. 3-7: in Sect. 3, we present some preliminaries; in Sect. 4, we present a base calculus of global programs, without if/ while-statements, but with a main theorem that covers both deadlock freedom and functional correctness; in Sect. 5 and Sect. 6, to support decentralised decision making, we extend the base calculus with if/while-statements; in Sect. 7, we present a calculus of local programs and projection. Thus, Sect. 4-6 cover the upper half of Fig. 1, while only Sect. 7 covers the bottom half.
Appendices appear in the full version of this paper [39]. Detailed definitions, auxiliary lemmas, main theorems, and proofs appear in a technical report [40].

Motivating Examples
To further motivate the usefulness and necessity of this paper's new theory, in this section, we present examples of real(istic) distributed systems that require decentralised decision making; see Appx. A [39] for additional examples. Throughout the section, we adopt a programmer's perspective and present only global programs (i.e., all construction and analysis activities that a programmer carries out manually in the workflow, happen in the upper half of Fig. 1).
Regarding the usefulness of the new theory, the following example shows that centralised decision making can be impractical (i.e., unnatural or unnecessary).
Example 1 (Chess simulation). From Sect. 1.2, recall the distributed system in which two processes enact roles Player1 and Player2 to simulate a game of chess.   Figure 2 shows two global programs: one that uses centralised decision making (at Player1 and Player2, in alternating order), and one that uses the new theory's decentralised decision making; both have auxiliary global programs G 12 (Player1 is active, Player2 is passive; details omitted) and G 21 (vice versa).
In Sect. 1.2, we argued for the usefulness of decentralised decision making in this example: the label communications in Fig. 2a are actually unnecessary.
Regarding the necessity of the new theory, the following example shows that centralised decision making can be impossible. In the example, notation G 1 G 2 prescribes an interleaving; it is used to express that the order in which G 1 and G 2 are executed does not matter (i.e., it is not intended to be multi-threading; there is no interaction between G 1 and G 2 ). By convention, sequencing binds stronger than interleaving. For instance, G 1 ; G 2 G 3 should be read as (G 1 ; G 2 ) G 3 .
Example 2 (Probabilistic leader election in anonymous clique networks). Consider a distributed system in which k anonymous processes (i.e., they have no predefined identifiers) need to elect a leader among them. For clique networks (i.e., each process has a channel to each other process), a probabilistic version of Peleg's algorithm [45] can be used in the style of Itai and Rodeh [37,38]. The algorithm proceeds in rounds. In every round, every process picks a random identifier and sends it to every other process. If there is a unique maximal identifier, then the process that picked it becomes the leader. If not, another round follows. Figure 3 shows a global program for k=3; it crucially relies on the new theory's decentralised decision making. We write r.[x 1 , . . . , x n ] := [e 1 , . . . , e n ] to abbreviate r.x 1 := e 1 ; · · · ; r.x n := e n , while we write p.e [q 1 .x 1 , . . . , q n .x n ] to abbreviate p.e q 1 .x 1 ; · · · ; p.e q n .x n . First, the processes initialise five variables (lines 1-3): seed is used to pick random identifiers; id1, id2, and id3 are used to store and compare identifiers; leader indicates whether or not the process was elected. Next, the processes enter the loop (lines 4-7), each of whose iterations represents one round: in every iteration, every process increments its seed, picks a random identifier, and shares it. When the maximal identifier is unique, the processes exit the loop. One process marks itself as leader (lines 8-10).
The point of this example is that the probabilistic version of Peleg's algorithm for cliques-actually, any leader election algorithm-cannot faithfully be implemented using centralised decision making. The reason is that centralised decision  Fig. 3: Global program for probabilistic leader election in anonymous clique networks (k=3), using decentralised decision making making inherently requires the presence of a distinguished process (to evaluate a one-party condition and share the outcome). However, the motivation to run a leader election algorithm in the first place is that such a distinguished process is not yet agreed upon. That is, centralised decision making requires asymmetry of processes, whereas leader election algorithms require symmetry.

Setting the Stage: Data and Conditions
The topic of interest in this paper is "processes that communicate", rather than "data that are communicated". For this reason, we assume that there exists some underlying calculus of data (Sect. 3.1), but we omit most of its details; they are orthogonal to this paper's contributions. On top of it, we adopt a logic to write preconditions, postconditions, and conditions in if/while-statements (Sect. 3.2).

Data
Let R = {A, B, C, . . .} denote a universe of roles, ranged over by p, q, r. Let X = {x, y, z, . . .} denote a universe of variables, ranged over by x, y, z. Let V = {error, true, false, 0, 1, 2, . . .} denote a universe of values, ranged over by v (i.e., V contains at least a distinguished value error, booleans, and numbers, but we also use other data types in examples, including functions). Let E denote a universe of expressions, ranged over by e; it is induced by the following grammar: e 1 ==e 2 e 1 <e 2 e 1 &&e 2 !e e 1 +e 2 · · · compound expressions Let S = R (X V) denote a universe of states (i.e., partial functions from roles to partial functions from variables to values), ranged over by S; the idea is that every state has a separate section for every role of interest, to model disjoint memory spaces. Let eval : S × E → V denote a total evaluation function. For instance, eval {A →{x →5,y →6}} (A.x+A.y) = 11. We assume that bogus expressions are evaluated to error. For instance, eval ∅ (1+true) = error.
Regarding terminology, we say that every role-qualified variable r.x is "local to r". If every role-qualified variable that occurs in e is local to r, then e is "local to r". Regarding notation, if e is local to r, then we often move all "r."-qualifiers that occur in e to the front. For instance, we write A.x+y instead of A.x+A.y.

Conditions
We adopt the following basic logic over expressions in E. Let Ψ denote a universe of formulas, ranged over by φ, χ, ψ; it is induced by the following grammar: φ, χ, ψ ::= e ¬ψ ψ 1 ∧ ψ 2 ∀ψ Informally, given state S, formulas have the following meaning relative to S: -Formula e is an atom: it is true in S iff e evaluates to true using S.
(Negation and conjunction appear also at the level of formulas, and not just at the level of expressions, for technical convenience later on in this paper.) -Formula ∀ψ is a tautology: it is true in S iff ψ is true in every state.
Formally, an interpretation function maps formulas to the sets of states in which they are true, denoted by -; it is induced by the following equations: Regarding terminology, if every expression that occurs in ψ is local to r, then ψ is "local to r"; if so, the truth of ψ can be checked at r. Regarding notation, we often write {ψ r } r∈{r1,...,rn} instead of ψ r1 ∧ · · · ∧ ψ rn if ψ r is local to r for every r ∈ {r 1 , . . . , r n }. Furthermore, we write ψ 1 ∨ ψ 2 and ψ 1 → ψ 2 for disjunction and implication. Finally, we write ψ 1 ≡ ψ 2 instead of ψ 1 = ψ 2 .

Global Programs: Base Calculus
To gently introduce the main components of the new theory, in this section, we present a base calculus of global programs, without if/while statements, but with a main theorem that covers both deadlock freedom and functional correctness.
Initially, we present the syntax and semantics (Sect. 4.1); subsequently, we present a predicate transformer (Sect. 4.2); finally, we present the main theorem, which relies on the predicate transformer (Sect. 4.3). In the next sections, we extend the base calculus to support decentralised decision making.

Syntax and Semantics
Let Γ and G denote universes of global actions and global programs, ranged over by γ and G; they are induced by the following grammar: γ ::= q.y := e p.e q.y G ::= skip γ G 1 ; G 2 G 1 G 2 Informally, these grammar elements have the following meaning: -Global action q.y := e models an assignment of the value of expression e to variable y at role q. As an extra constraint, e is local to q. Regarding notation, we often omit "q."-qualifiers from e. For instance, we write A.z := x+y instead of A.z := A.x+A.y. Also, we write eval S (q.y := e) instead of q.y := eval S (e).
-Global action p.e q.y models a synchronous communication of the value of expression e at role p into variable y at role q. As extra constraints, e is local to p, and p = q. Regarding notation, we often omit " p."-qualifiers from e. Also, we write eval S (p.e q.y) instead of p.eval S (e) q.y.
-Global program skip prescribes an empty execution.
-Global program G 1 ; G 2 prescribes a weak sequence of G 1 and G 2 . The idea is that it resembles a conventional strong sequence (i.e., in-order execution), except that it also allows global actions in G 2 that are independent of those in G 1 to be executed already before G 1 is done (i.e., out-of-order). For instance, in A.x := 5 ; B.y := 6, the assignment at Bob is independent of the assignment at Alice, so they may be executed out-of-order. In contrast, in A.x := 5 ; A.x+1 B.y, the communication from Alice to Bob depends on the assignment at Alice, so they must be executed in-order. In general, when two global actions have disjoint subjects (i.e., participating roles), they are considered independent and may be executed out-of-order. Out-of-order execution of global actions with disjoint subjects is common in choreographic programming: it was first introduced by Carbone and Montesi to deal with latent concurrency among roles in global action sequences [10].
-Global program G 1 G 2 prescribes an interleaving of G 1 and G 2 .
Formally, we define the operational semantics of global programs at two "layers".
(1) The "top layer" consists of an abstract termination relation, denoted by ↓, and an abstract labelled reduction relation, denoted by → in the style of process algebra (e.g., [2]). More precisely, G ↓ means that G can terminate, while G ψ,γ − − → G means that G can reduce to G when ψ is true (i.e., conditionally) by executing γ. For instance, the following abstract execution is possible: First, the global program reduces by executing an assignment; next, it reduces by executing a communication; next, it terminates. For simplicity, skips are not automatically cleaned up by the reduction rules (but they could be).
Relations ↓ and → are induced by the rules in Fig. 4a. Most rules are standard [2]. Notably, in this section, every reduction is unconditional (i.e., labelled with true) due to rule [→-Act]. The only special rule is rule [→-Seq2]: it states that if G 2 can reduce to G 2 by executing γ (right premise), and if γ is independent of G 1 (left premise), then G 1 ; G 2 can reduce accordingly (conclusion). We note that independence is defined in terms of disjointness of subjects, as explained above. For instance, the following abstract out-of-order execution is possible: The "bottom layer" consists of a concrete termination predicate, denoted by ↓ (same symbol as before), and a concrete labelled reduction relation, denoted by → (ditto). The idea is that the bottom layer enriches the top layer by taking into account states, in terms of configurations of the form (G, S). More precisely, G can reduce to G by executing γ c in S to obtain S . We write γ c -with a superscript "c"-to indicate that it is a "concrete" global action in which every expression has been evaluated to a value (using S). For instance, the following concrete execution is possible: Relations ↓ and → are induced by the rules in Fig. 5. Rule [↓] states that if G can terminate, then so can (G, S), regardless of S. More interestingly, rule [→] states that if G can reduce to G when ψ is true by executing γ (left premise), and if ψ is indeed true in S (middle premise), and if γ c is the "concretisation" of γ such that every expression is first evaluated using S (right premise), then (G, S) can reduce accordingly, and the effect of γ c is applied to S (conclusion); the latter means that a variable is bound to a new value in S, formalised using "substitution notation". For instance (cf. second reduction in the concrete execution above), Our formalisation of the operational semantics has two novelties: -Two-layered approach -In existing work on stateful choreographic programming (e.g., [14,19]), abstract and concrete operational semantics are merged into one. An advantage of keeping them separate is that it enables us to prove the main theorems also in a layered fashion; this simplifies our proofs.
(c) Extension with non-blocking if/while-statements -explained in Sect. 6

Fig. 6: Well-formedness of global programs
We end this subsection with a well-formedness relation, denoted by , to check a few basic syntactic properties of global programs; it is induced by the rules in Fig. 6a. For now, there are two aims (to be extended in subsequent sections for if/while-statements): 1. Rules [ -Act1] and [ -Act2] ensure that R contains all roles that occur in G. The idea is that when we project G onto every role in R (Sect. 7), we get a local program for every remaining subject of G (i.e., when G is the remaining global program, R may contain roles that participated in the past, but no longer in the future). Thus, R spans the whole distributed system.

Rule [ -Par
] ensures that the channels (i.e., sender-receiver pairs) that occur in G 1 and G 2 are disjoint; this is a common assumption in choreographic programming (e.g., [8]). The idea is that when a communication happens in G 1 G 2 , it must be unambiguously clear whether it happened in G 1 or in G 2 ; otherwise, the operational equivalence theorem cannot be proved (Sect. 7).

Predicate Transformer
In the next subsection, the main theorem for global programs will be as follows (informally): if the global program is well-formed, and if the precondition is true in the initial state, then deadlock freedom and functional correctness are provided. In this subsection, we present a technique to automatically compute preconditions such that the main theorem can indeed be formulated and proved.
(c) Extension with non-blocking if/while-statements -explained in Sect. 6

Fig. 7: Predicate transformer to compute preconditions
Let φ denote a predicate transformer function; it is defined by the equations in Fig. 7a, where χ[e/q.y] denotes substitution of e for q.y in χ. In words, φ consumes a global program G and a postcondition χ as input, and it produces a precondition φ(G, χ) as output. The idea is that φ is sound : if φ(G, χ) is true in the initial state, then after executing G, χ is true in the final state. Essentially, Fig. 7a is an adaptation of Dijkstra's predicate transformer to compute weakest preconditions for sequential code [26], denoted by wp. More precisely: -For q.y := e, the definitions of φ and wp are the same; for p.e q.y (absent in Dijkstra's work), φ works similarly. Figure 8a shows an example: if A.x is 5 (computed precondition), then after the communication of A.x+1 at Alice into B.y at Bob (global program), the sum of A.x and B.y is 11 (postcondition). We note that the postcondition relates variables at different roles; this is straightforwardly supported by φ, without extra manual effort.
-For G 1 ; G 2 , the definitions of φ and wp are the same as well: first, χ is used as a postcondition of G 2 to compute a precondition φ(G 2 , χ); next, φ(G 2 , χ) is used as a postcondition of G 1 to compute a precondition φ(G 1 , φ(G 2 , χ)). Such a "backwards" computation of a precondition corresponds to the "forwards" execution of the sequence: initially, φ(G 1 , φ(G 2 , χ)) is true; subsequently, φ(G 2 , χ) is true after executing G 1 ; finally, χ is true after executing   G 2 . Figure 8b shows an example: if true is true (i.e., unconditionally), after executing the global program, the sum of A.x and B.y is 11. However, unlike Dijkstra's setting (i.e., strong sequencing), there is a caveat in our setting (i.e., weak): G 1 and G 2 may be executed out-of-order. This makes proving the soundness of φ more challenging than in Dijkstra's work (notably: establishing the correspondence between backwards computation of a precondition and forwards execution of the sequence).
-For G 1 G 2 (absent in Dijkstra's work), the definition of φ is inspired by the notion of disjoint parallelism in Hoare logic [33,1]. There are two cases. If G 1 and G 2 are non-interfering, which means that the variables that occur in G 1 and G 2 are disjoint, denoted as G 1 # G 2 , then the order in which G 1 and G 2 are executed does not affect the truth/falsehood of the postcondition; in that case, a precondition is computed by assuming, arbitrarily, in-order execution of G 1 and G 2 (but any other interleaving would work as well). If G 1 and G 2 are interfering, then φ yields false, so no state satisfies the precondition. This is sound but not complete (i.e., there exist deadlock-free and functionally-correct global programs for which the computed precondition is nevertheless false). For our present purposes, however, φ is "complete enough" (e.g., all examples in Sect. 2 and Appx. A [39] are supported). 4 The following proposition follows almost directly from the definitions. It states that if φ(γ, χ) is true in S, then χ is true in S , after executing γ.

Deadlock Freedom and Functional Correctness
The aim of this subsection is to formulate and prove the main theorem for global programs, which covers both deadlock freedom and functional correctness.
To give a uniform presentation across Sects. 4-6, we formulate the lemmas and theorem for the base calculus in this section in a way that they are reusableverbatim-for the extensions in the next sections. As a result, some formulations are more restrictive than necessary for the base calculus, but this is fine.
The first two lemmas pertain to φ's soundness. The first lemma states that if G is well-formed and can terminate, then the truth of φ(G, χ) implies the truth of χ (i.e., the postcondition has been brought about). The second lemma states that if G is well-formed and can reduce to G when ψ is true by executing γ, then the truth of φ(G, χ) ∧ ψ implies the truth of χ, after executing γ ; G (i.e., the postcondition is being brought about by executing γ).
Proof. By induction on the derivation of G ↓.
Proof. By induction on the derivation of G ψ,γ − − → G . The interesting case is rule [→-Seq2], with G = G 1 ; G 2 . We need to prove the following inclusions: The first inclusion can be proved using the induction hypothesis and G 2 ψ,γ − − → G 2 (right premise of rule [→-Seq2]). The second inclusion can be proved using subj(G 1 ) ∩ subj(γ) = ∅ (left premise) and R (G), to establish that the variables that occur in G 1 and γ are disjoint as well (i.e., G 1 and γ are non-interfering).
The next lemma states that well-formedness is preserved by reduction. The next lemma states that if G is well-formed, and if φ(G, χ) is true in S, then either G can terminate, or G can reduce to G (i.e., G is not stuck). Proof. By induction on the derivation of R (G). Now, our main theorem for global programs states that if G is well-formed, and if φ(G, χ) is true in S, and if (G, S) has a sequence of reductions to (G † , S † ), then either (G † , S † ) can terminate and χ is true in S † , or (G † , S † ) can reduce. Thus, an execution of (G, S) consists of either finitely many reductions, followed by termination, or infinitely many (i.e., deadlock freedom); in the former case, upon termination, the postcondition is true (i.e., functional correctness). Theorem 3. If R (G) and S ∈ φ(G, χ) and (G, S) γ c 1 − → · · · γ c n −→ (G † , S † ), then: Proof. First, we inductively apply Prop. 1 and Lems. 2-3, along the reduction sequence to prove R (G † ) and S † ∈ φ(G † , χ) . Next, we apply Lem. 4 to prove deadlock freedom and Lem. 1 to prove functional correctness, using Fig. 5.

Global Programs: If/While-Statements
In the previous section, to gently introduce the main components of our theory, we presented a base calculus of global programs. In this section, we extend it with if/while-statement to support decentralised decision making.

Syntax and Semantics
Recall that Γ and G denote universes of global actions and global programs, ranged over by γ and G; they are induced by the following extended grammar: Informally, the new grammar elements have the following meaning: -Global action i R , with i ∈ {1, 2}, models a collection of private decisions at all roles in R together (i.e., at the same time). In case of an if-statement, i=1 and i=2 indicate entering the then-branch and else-branch; in case of a while-statement, i=1 and i=2 indicate (re)entering the loop and exiting it.
-Global program if {e r } r∈R G 1 G 2 prescribes a conditional choice of G 1 and G 2 . The idea is that every role r ∈ R privately evaluates its own conjunct e r of multiparty condition {e r } r∈R and, based on the outcome, privately decides to enter G 1 or G 2 . As a result, we have three cases to consider: • Case A: If e r is true for every r ∈ R, then everyone enters G 1 .
• Case B: If e r is false for every r ∈ R, then everyone enters G 2 .
• Case C: If e r1 is true, but e r2 is false, for some r 1 , r 2 ∈ R, then someone enters G 1 , but someone else enters G 2 .
Cases A and B are the "good" situations in which the roles are unanimous. In contrast, case C is the "bad" situation that leads to deadlock. For simplicity, in this section, we assume that roles make private decisions together (i.e., at the same time), using two synchronisation barriers. Intuitively, in operational terms, this means that for every role r: first, it privately evaluates its own conjunct e r ; next, it reaches one of two barriers, depending on the truth/falsehood of e r ; next, it waits until every other role has privately evaluated a conjunct and reached a barrier as well. In cases A and B, all roles eventually reach the same barrier, so it breaks, and all roles enter one branch together; in case C, the roles never reach the same barrier-they are divided-so neither one of them breaks, and the roles get stuck.
(We note that barriers are often undesirable in distributed systems. In the next section, therefore, we also extend the base calculus with barrier-free if/while-statements. However, as the technical details of the barrier-free versions are considerably more complicated than the barrier-based versions, but partly rely on similar principles, we present the barrier-based ones first.) An if-statement cannot terminate: a decision must be made.
Condition ψ inv is the loop invariant; it does not affect the operational semantics of while-statements, but it is used to compute preconditions.
Formally, for if/while-statements, → is induced by the rules in Fig. 4b (page 10).
First, G reduces by executing an assignment at Alice (both executions); next, it reduces by executing private decisions at Alice and Bob together to enter the then-branch (left execution) or else-branch (right); next, in the former case, it reduces by executing an assignment at Bob and terminates, whereas in the latter case, it terminates. Regarding concrete executions, two situations are possible: -If B.y is initially 6, then the left abstract execution can induce a deadlockfree concrete one: after the first concrete reduction, A.x is 5, and B.y is still 6, so A.x==5 ∧ B.y==6 is true (i.e., case A, unanimity), enabling the sequel. -If B.y is initially not 6, then both abstract executions cannot induce a deadlock-free concrete one: after the first concrete reduction, A.x is 5, but B.y is still not 6, so both A.x==5 ∧ B.y==6 and ¬A.x==5 ∧ ¬B.y==6 are false (i.e., case C, non-unanimity), disabling the sequel and causing a deadlock.
This example shows that we need a technique to infer that B.y must initially be 6 to ensure unanimity for deadlock freedom; we present it in the next subsection. We end this subsection with an extension of for if/while-statements; it is induced by the rules in Fig. 6b (page 12). There is a third aim now (cf. page 12):

Rules [ -If] and [ -While
] ensure that every role (in R) has its own conjunct in every multiparty condition. The idea is that every role always needs to know which branch to enter, so it must participate in every decision. 5,6

Predicate Transformer
We proceed with an extension of φ for if/while-statements; it is defined by the equations in Fig. 7b (page 13). As before, the definition of φ for if/whilestatements is an adaptation of the definition of wp (i.e., Dijkstra's original predicate transformer [26]), but it differs on crucial points as well. More precisely: -For if {e r } r∈R G 1 G 2 , the definition of φ has three conjuncts. The first (resp. second) conjunct states that if every e r is true (resp. false), then the precondition of the then-branch (resp. else-branch) is true. This is similar to the definition of wp, and it includes case A (resp. B) on page 16. The third conjunct states that every e r1 must imply every e r2 (i.e., they are either all true or all false); this is new relative to the definition of wp, and it excludes case C on page 16. (i.e., if the precondition computed by φ is true, then case C will never arise). The following proposition makes this precise.
Thus, φ accumulates logical requirements not only to ensure the truth of the postcondition for functional correctness (i.e., the first and second conjunct), but also to ensure unanimity for deadlock freedom (i.e., the third conjunct). Figure 8c (page 14) shows an example, featuring the same global program as G on page 17: if φ 1 [5/A.x] is true (to ensure the truth of χ) and B.y is 6 (to ensure unanimity), then after executing the global program, χ is true. Thus, φ mechanises our reasoning about G on page 17.
-For while {e r } r∈R {ψ inv } G, the definition of φ has an "outer conjunction" and an "inner conjunction". The inner conjunction is similar to φ for if-statements: either every e r and the precondition of the body are true, to (re-)enter the loop, or every ¬e r and the postcondition are true, to exit it. The second outer conjunct states that always (i.e., in every state, i.e., before and after executing the body), if the invariant is true, then the inner conjunction is true; the first outer conjunct states that the invariant is indeed true (i.e., before executing the body). This is similar to the definition of wp.

Deadlock Freedom and Functional Correctness
To extend the main theorem for global programs (Thm. 3, page 16) to cover if/while-statements, we need to extend the auxiliary lemmas (Lem. 1-4, page 15 onwards); the proof of the theorem relies on the lemmas and is the same.
Proof. For Lem. 1 there are no new cases (i.e., no new termination rules in Fig. 4b). For Lems. 2-3, the new cases (i.e., new reduction rules in Fig. 4b) can be proved directly. For Lem. 4, the new cases (i.e., new well-formedness rules in Fig. 6b) can be proved using Prop. 2, to establish that rule [→-If1] or rule [→-If2] is applicable in such a way that S ∈ ψ holds as well.
is not always practical/user-friendly. We therefore aim to offer "native" support for such choices too, using a form of merging [8,9,10]; see also Appx. D [39]. Proof. The same as the proof of Thm. 3, using Lem. 5 instead of Lems. 1-4.

Global Programs: Non-Blocking If/While-Statements
In the previous section, we extended the base calculus of global programs with blocking if/while-statements; they require roles to make private decisions together (i.e., at the same time), using barriers. In this section, we extend the base calculus also with non-blocking if/while-statements; they allow roles to make private decisions alone (i.e., at their own pace). This is often preferable.

Syntax and Semantics
Recall that G denotes a universe of global programs, ranged over by G; it is induced by the following extended grammar: Informally, the new grammar elements have the following meaning: 7 -Global program if {e r } r∈R G 1 | R1 G 2 | R2 prescribes a non-blocking conditional choice of G 1 and G 2 . It relies on similar principles as the blocking version; notably, the same cases A, B, C on page 16 are applicable.
The key difference with the blocking version is that roles make private decisions alone (i.e., at their own pace), without using synchronisation barriers. Intuitively, in operational terms, this means that for every role r: first, it privately evaluates its own conjunct e r ; next, it immediately enters a branch.
To accommodate this, extra syntactic bookkeeping-in the form of the " | R1 " and "| R2 " notation-is needed to keep track of roles' decisions. More precisely, at any time, R i contains every role that has already made a private decision to enter G i . Initially, both R 1 and R 2 are empty. In case A (resp. B), R 1 (resp. R 2 ) eventually becomes "full" and contains all roles, while R 2 (resp. R 1 ) always remains empty. In case C, both R 1 and R 2 eventually become non-empty, but they always remain "non-full" as well.
A non-blocking if-statement can terminate when all roles have made a private decision and every entered branch can terminate.
, except that no extra bookkeeping is needed (i.e., a fixed ∅ in "| ∅ "): nonblocking while-statements will be unfolded into non-blocking if-statements.
(The reason for the seemingly redundant " | ∅ " notation is to give non-blocking while-statements a different grammatical form than blocking ones.) Formally, for non-blocking if/while-statements, ↓ and → are induced by the rules in Fig. 4c (page 10). Rule [↓-NIf] states that if every role has made a private decision (left premise), and if G 1 and G 2 can terminate when at least one role has entered it (middle and right premise), then the non-blocking if-statement can terminate. The effect of the "R i = ∅" conditions is that a non-entered branch does not need to be able to terminate for the whole if-statement to be able to terminate. We note that rule [↓-NIf] also covers the case in which both R 1 and R 2 are non-empty, which should never have happened in the first place; shortly, we will rule it out using well-formedness and the predicate transformer.  , and if the subjects of γ have previously entered G 1 or G 2 (right premise), then the non-blocking if-statement can reduce accordingly. This means that global actions in the branches can be executed already before all private decisions have been made, out-of-order. We note that the set differences in the premises of these rules are needed, because in general (but undesirably), R 1 and R 2 may overlap; shortly, we will rule out this possibility using well-formedness and the predicate transformer. For instance, with the same G as above, also the following abstract execution is possible (due to rule [→-Seq2] as well): Rule [→-NWhile] unfolds the non-blocking while-statement. We end this subsection with an extension of for non-blocking if/whilestatements; it is induced by the rules in Fig. 6c (page 12). There is a fourth aim now (cf. page 12 and page 17): 4. Rule [ -NIf] ensures that case A or B on page 16 applies, but not case C: when roles make private decisions alone, they must still be unanimous.

Predicate Transformer
For non-blocking if/while-statements, φ is defined by the equations in Fig. 7c (page 13). It is based on the extension for the blocking variants in Fig. 7b: , the definition of φ has four cases. If R 1 and R 2 are both empty, then no role has made a private decision to enter a branch yet, so the precondition is the same as for blocking ifstatements (i.e., either choice is still possible). This shows that blocking and non-blocking if-statements are functionally equivalent in the following sense: to ensure that the same postcondition is true in the end, the same precondition must be true in the beginning. If R i and R j are empty and non-empty, then the roles in R j have privately decided to enter G j . Thus, the precondition of G j must be true. Moreover, to ensure that the remaining roles in R \ R j will privately make the same decision to enter G j , their conjuncts must be all true (if j=1) or all false (if j=2) as well. In this way, cases A and B on page 16 are included.
If R 1 and R 2 are both non-empty, then roles have privately decided to enter both G 1 and G 2 , which should never have happened. Thus, the precondition is false. In this way, case C on page 16 is excluded.
-For while {e r } r∈R {ψ inv } G| ∅ , no role has made a private decision to (re)enter the loop or exit it yet, so the precondition is the same as for blocking while-statements. When the first role privately decides, the non-blocking while-statement is unfolded into a non-blocking if-statement.

Main Theorem: Deadlock Freedom and Functional Correctness
To extend the main theorem for global programs (Thm. 3, page 16) to cover nonblocking if/while-statements, we need to extend the auxiliary lemmas (Lem. 1-4, page 15 onwards); the proof of the theorem relies on the lemmas and is the same.  Fig. 4c) can be proved using R (G) and φ(G, χ) = ∅ (first and second premise of Lem. 3), to establish that R 1 or R 2 is empty before the reduction, and remains empty after it (i.e., case C on page 16 never arises). For Lem. 4, the new cases (i.e., new well-formedness rules in Fig. 6b) can be proved using Prop. 2, to establish that rule [→-NIf1] or rule [→-NIf2] is applicable in such a way that S ∈ ψ holds as well.
Theorem 5. Theorem 3 holds for this section's extension.
In the previous sections, to cover the upper half of Fig. 1, we incrementally presented a calculus of global programs with blocking and non-blocking if/whilestatements. In this section, to cover the bottom half, we present a complementary calculus of local programs and a projection function.

Syntax and Semantics
Let Λ and L denote universes of local actions and local programs, ranged over by λ and G; they are induced by the following grammar: λ ::= q.y := e pq !e pq?e i R r τ L ::= skip λ L 1 ; Informally, these grammar elements have the following meaning: -Local action q.y := e models an assignment, as before.
-Local actions pq !e and pq?q model a send and a receive of the value of expression e at role p into variable y at role q. -Local action i R r , with i ∈ {1, 2}, models a private decision at role r, as part of a collection of private decisions at all roles in R together.
-Local action τ models a delay (i.e., passage of time in which a role sits idle).
-The local programs have largely the same meaning as their global counterparts. There are two differences. First, the extra " R." notation in blocking if/while-statements allows a role to know which other roles to wait for before entering a branch. Second, the extra " | n " notation in non-blocking if/ while-statements allows a role to delay n times (motivated below).
Formally, the abstract termination and reduction relations for local programs are induced by the same rules as in Fig. 4 (page 10), mutatis mutandis, except: -In the rules for if/while-statements: every " {e r } r∈R " and " {¬e r } r∈R " is replaced with "e" and "¬e", while every "i R " and "i {r} " is replaced with "i R r " and "i {r} r " such that e is local to r. See Appx. B [39] for details. -There is an extra rule for non-blocking if-statements to execute a delay and decrement n if n>0 (motivated below, when discussing projection).
Let R L denote a universe of families of local programs (i.e., partial functions roles to local programs), ranged over by L. Informally, L prescribes a parallel composition of the k local programs in its image L(r 1 ), . . . , L(r k ). Formally, the abstract termination and reduction relations are induced by the rules in Fig. 9. They state that an assignment and a delay are executed alone, while a send-receive pair and a collection of private decisions are executed together. We note that for n=1, the bottom-left rule to execute i {r1,...,rn} covers the case of non-blocking if/while-statements. Furthermore, the mechanisms by   To decompose global actions and programs into local ones, let denote a projection function; it is induced by the equations in Fig. 10. In words, consumes a global program G and a role r as input, and it produces a local program G r as output. The idea is that is sound and complete: roughly, G can terminate or reduce by executing γ if, and only if, G r can similarly terminate or reduce by executing γ r. The interesting cases of Fig. 10 are as follows: -For γ (any global action), there are basically two possibilities. If r is a subject of γ, then γ r is the contribution of r to γ (i.e., an assignment remains an assignment; a communication is split into a separate send and receive; a collection of private decisions is split into separate ones). If r is not a subject of γ, then γ r is a delay (i.e., r sits idle, without contributing to γ).
-For G = if ψ G 1 | R1 G 2 | R2 , the definition of is most complicated. We explain it from the perspective of soundness. There are three situations to consider.
First, suppose that G reduces by executing a global action γ in which r does participate. To ensure that G r can similarly reduce by executing γ r, it will be sufficient to register in G r whether or not r has already entered a branch in G (and which one). This is achieved by "| R1∩{r} " and "| R2∩{r} ". Second, suppose that G reduces by executing a global action i {r0} in which r does not participate, using rule [→-NIf1] or rule [→-NIf2], so another role r 0 enters G 1 or G 2 . To ensure that G r can similarly reduce by executing τ, it will be sufficient to register in G r the number of roles that have not yet entered a branch in G, excluding r. This is achieved by "| |R\(R1∪R2∪{r})| ". Third, suppose that G reduces by executing a global action γ in which r does not participate using rule [→-NIf3] or rule [→-NIf4]. To ensure that G r can similarly reduce, no additional information needs to be registered.

Operational Equivalence
Informally, our main theorem for local programs and projection is as follows: if the global program is well-formed, and if the computed precondition is true in the initial state, then operational equivalence is provided. In the rest of this section, we first present auxiliary lemmas; next, we present the main theorem. The first lemma pertains to soundness of . It states that if G is well-formed and can terminate or reduce, then G r can similarly terminate or reduce. 1. If R (G) and r ∈ R and G ↓, then (G r) ↓. in those cases, we use premises R (G) and r ∈ R to establish that r must have its own conjunct in the multiparty condition, so it must contribute to γ.
The second lemma pertains to completeness of . It states that if G is wellformed, and if G r can terminate, then G can similarly terminate. Furthermore, it states that if G is well-formed, and if every G r can reduce by executing γ r, for every subject r of γ, then G can similarly reduce. Lemma 8.
Proof. By induction on the derivation of (G r) ↓ (item 1) and the derivations of (G r) ψr,γ r − −−− → L r , for every r ∈ subj(γ) (item 2). The interesting cases are [→-Par1] and [→-Par2]: we use premise R (G) to establish that either the LHS is reduced in every G r, or the RHS (otherwise, there is no unique G ).
Thus, the previous lemmas show that a global program and its family of projections can simulate each other's behaviour, at the abstract "top layer" of the operational semantics. The following theorem shows that this result can be extended to the concrete "bottom layer": it states that if G is well-formed, and if φ(G, χ) is true in S, then (G, S) and ({G r} r∈R , S) are weakly bisimilar (e.g., [30]), denoted with ≈. This means that (G, S) and ({G r} r∈R , S) can coinductively simulate each other's behaviour, modulo delays (i.e., operational equivalence). Theorem 6. If R (G) and S ∈ φ(G, χ) , then (G, S) ≈ ({G r} r∈R , S).
Proof. We prove the theorem using Lems. 7-8 and Fig. 5. See Appx. C [39] for a more detailed overview of the steps, including a weak bisimulation relation.

Conclusion
We presented a new theory of choreographic programming. It supports for the first time: construction of distributed systems that require decentralised decision making; analysis of distributed systems to provide not only deadlock freedom but also functional correctness. Both contributions are enabled by a single new technique, namely a predicate transformer for choreographies.
The following corollary summarises our main theorems (Thms. 3-6): Corollary 1. If global program G (with multiparty conditions in if/while-statements) is well-formed, and if precondition φ(G, χ) is true in initial state S, then the family of projections ({G r} r∈R , S) is deadlock-free and functionally-correct.
For instance, in Sect. 2, we presented a deadlock-free global program for leader election; in Appx. E [39], we demonstrate how to prove its functional correctness; by Cor. 1, these properties are preserved by projection. We implemented the new theory on top of the existing VerCors tool for deductive verification [4]; we present this implementation elsewhere.
In future work, we aim to extend the new theory with: (1) asynchronous communication; (2) a new version of merging [8,9,10] for decentralised decision making (see also footnote 6); (3) more flexible interleaving by relaxing the disjointness requirement for interleaving to support shared variables (e.g., using concurrent separation logic [6,44]).