locus · bigraph tutorial · Chapter III

III Mobile Processes

The π-calculus in binding bigraphs, as it now stands in Lean: names that are sent and received, rules that pass them, and a proof that the reactions of an encoded process are exactly its reductions. Every figure is computed from a Lean term and every result is kernel-checked.

Chapter I, Rooms, Wires and Laws, built bigraphs and said when two are the same. The second, Rules, Reactions and CCS, added reaction rules and encoded CCS, whose communication moves no names. This chapter encodes a calculus in which the name sent is itself a channel, so that a process can learn a link it did not have. The model is Jensen's [Jen06, Ch 7], and the rules are his two.

How this chapter is made. As in the other chapters, no figure is drawn by hand. Each is computed by lake exe bigraphdraw from a Lean term, read off by Bg.describe, and the label under it is the Lean source of the term drawn. Every block of Lean is cut from its source file by name. The examples are in Pi/Examples.lean, and every reaction stated about them is a theorem there.

A theory of its own. The π development is the library Pi/. It imports the generic bigraph modules and the shape layer Bigraph/Shapes/, which holds what an encoding of processes needs whatever its signature: shapes and their isomorphisms, binding, the canonical instance, and rules that pass names; the CCS encodings of Chapter II stand on it too. It imports nothing of the CCS encodings and nothing of Locus; the π-calculus has its own signature.

π notation. Processes in the text are printed from their Lean terms. The free channels 0 and 1 are written x and y, in the text and in the figures. x̄y sends y on x; x(u) receives a name on x and calls it u. A restriction binds z, w, … and an input binds u, v, …, each counted from the outside in. In Lean every bound name is a de Bruijn index.

Numbering is separate for definitions, figures and theorems, and the generator checks every reference and every citation.

  1. §1 The calculus
  2. §2 The encoding
  3. §3 Rules that pass names
  4. §4 Every reduction is a reaction
  5. §5 Every reaction is a reduction
  6. §6 Shared or private
  7. §7 Names that move
  8. §8 What has been proved
  9. §9 References

§1 · The calculus

The calculus has choice between sends and inputs, parallel composition, restriction and replicated input. It is the calculus of Jensen's sixth chapter [Jen06, §6.1], which his seventh models, with channels written as in Chapter II: a channel is a free name or a de Bruijn index.

Definition 1 (Processes). There are three binders. A restriction νP binds index 0 of P; so do an input x(u).P and a replicated input !x(u).P, whose index 0 is the name received.

mutual
inductive Proc where
  | nil : Proc
  | par : Proc → Proc → Proc
  | res : Proc → Proc
  | sum : Sum → Proc
  /-- `!x(z).P`: replicated input; `z` is index `0` of `P`. -/
  | rep : Chan → Proc → Proc
inductive Sum where
  /-- `x̄y.P` -/
  | snd : Chan → Chan → Proc → Sum
  /-- `x(z).P`: `z` is index `0` of `P`. -/
  | rcv : Chan → Proc → Sum
  | plus : Sum → Sum → Sum
end

Definition 2 (Substitution). p.subst k c makes index k of p the channel c and moves the indices above it down by one. Under a binder both the index and c move up.

def Chan.subst (k : Nat) (c : Chan) : Chan → Chan
  | .free n => .free n
  | .bound i => if i < k then .bound i else if i = k then c else .bound (i - 1)

Definition 3 (Reduction). A send x̄y.P meets an input x(u).Q on the same channel, in two sums or with a replicated input. The receiver's body becomes Q with y for u, carried as a field q' = q.subst 0 y. A replicated input stays for the next sender. Reduction is closed under parallel composition, restriction and structural congruence, whose scope extrusion likewise carries the shifted process as a field.

inductive Red : Proc → Proc → Prop where
  | comm {x y p m q n q'} (h₁ : InSnd x y p m) (h₂ : InRcv x q n) (hq : q' = q.subst 0 y) :
      Red (.par (.sum m) (.sum n)) (.par p q')
  | rep {x y p m q q'} (h₁ : InSnd x y p m) (hq : q' = q.subst 0 y) :
      Red (.par (.sum m) (.rep x q)) (.par (.par p q') (.rep x q))
  | parL {p p'} (q) : Red p p' → Red (.par p q) (.par p' q)
  | res {p p'} : Red p p' → Red (.res p) (.res p')
  | struct {p p' q' q} : SC p p' → Red p' q' → SC q' q → Red p q

§2 · The encoding

A process becomes a shape, as in Chapter II: a node for each sum, send and input, an edge for each restriction with its nu node, and names for the free channels. The signature is the π-calculus's own. A sum alt has no port. A send snd has two ports, the channel and the name sent. An input get, and its replicated form rget, has a channel port and a port that binds: it binds the edge of the name to be received, and the body's uses of that name are linked to the same edge. This is how a bigraph declares that a name is bound [JM04, §12]. The binder nu of a restriction has one port, which binds too. Every control is passive.

inductive Ctl where
  /-- A sum. -/
  | alt
  /-- An output `x̄y`: the channel, and the datum. -/
  | snd
  /-- An input `x(z)`: the channel, and the datum, which binds. -/
  | get
  /-- A replicated input `!x(z)`: the channel, and the datum, which binds. -/
  | rget
  /-- The binder of a restriction (Jensen's `res`). -/
  | nu
deriving DecidableEq, Repr

def sig : Sig Ctl where
  ar := fun
    | .alt => 0
    | .nu => 1
    | _ => 2
  atomic := fun _ => false
  active := fun _ _ => false

Definition 4 (An input as a shape). x(u).P is the node on x holding P, under one more restriction. The restriction's edge is the received name: the node's binding port and the uses of index 0 in P reach it. No new way of building shapes is needed. The binding ports are those the signature's Binder instance marks. The rules use only part of what binding means: that a bound edge stays in one region when a body is copied. Jensen's full scope rule, that every point of a bound link lies inside its binder's scope (the input node's contents, the restriction node's parent), is checked separately and holds of every agent.

def inLab (c : Ctl) (x : Chan) : Lab sig := .two c (x.shift 0) (.bound 0)

def inShape (c : Ctl) (x : Chan) (s : Shape sig) : Shape sig := (s.node (inLab c x)).res

instance binder : Binder sig where
  binds := fun
    | .get, i => i.val == 1
    | .rget, i => i.val == 1
    | .nu, _ => true
    | _, _ => false
  nu := .nu
  nu_ar := rfl
  binds_nu := fun _ => rfl

Definition 5 (The shape of a process). Its agent is the shape's bigraph over the names X, the dangling indices named by the environment ρ.

mutual
/-- **The shape of a π process.** -/
def shapeπ : Proc → Shape sig
  | .nil => .empty
  | .par p q => (shapeπ p).par (shapeπ q)
  | .res p => ((shapeπ p).par nuS).res
  | .sum m => (shapeπS m).node altLab
  | .rep x p => inShape .rget x (shapeπ p)
def shapeπS : Sum → Shape sig
  | .snd x y p => (shapeπ p).node (.two Ctl.snd x y)
  | .rcv x p => inShape .get x (shapeπ p)
  | .plus m n => (shapeπS m).par (shapeπS n)
end

def agentπ (X : NameSet Nat) (ρ : Nat → Nat) (p : Proc) (h : NamesIn X.names ρ p) :
    Abstract sig Nat :=
  Abstract.mk (encπ X ρ p h)
Figure 1. Left, x(u).ūy: the input node on x binds the edge of u, and the send inside it uses that edge as its channel. Right, !x(u).ūy: the same body under a replicated input.

Theorem 1 (Congruent processes are one agent, and conversely). Every law of structural congruence is an isomorphism of shapes, including Jensen's exchange of two restrictions, νxνy P ≡ νyνx P, where the two binder nodes simply trade places. The law was added after a check showed it is needed: without it νxνy x̄y and νyνx x̄y are one agent but not congruent (Pi/Converse.lean). So is substitution: the shape of P with c for index k is the shape of P with index k made c (substπ, an isomorphism defined by recursion on the process).

theorem sc_soundπ {X : NameSet Nat} {ρ : Nat → Nat} {p q : Proc} (h : SC p q)
    (hp : NamesIn X.names ρ p) : agentπ X ρ p hp = agentπ X ρ q (Pi.NamesIn.of_sc h hp)

Conversely, for closed processes, one agent means congruent. Equal agents have isomorphic shapes, since no edge of an encoding is idle and no port of a closed process reaches past its binders; and isomorphic shapes are congruent processes, open or closed, so structural congruence is exactly isomorphism of shapes. The proof is an induction on the number of nodes: a binder at the top is brought out to the outermost restriction on both sides and removed, and otherwise a top component is split off on both sides and the parts compared. The exchange law is used there, once; without it the converse fails, as above. Closedness is needed: a port on a bound index and a port on the free name the environment gives that index are linked alike.

theorem sc_iffπ {X : NameSet Nat} {ρ : Nat → Nat} {p q : Proc} (hp : Closed p)
    (hq : Closed q) (hpX : NamesIn X.names ρ p) (hqX : NamesIn X.names ρ q) :
    agentπ X ρ p hpX = agentπ X ρ q hqX ↔ SC p q

§3 · Rules that pass names

A CCS rule only matches; a π rule must also connect. When x̄y meets x(u).Q, every use of u in Q must end up linked to y. Jensen's rules do this with names that belong to a region of the rule [Jen06, Def 7.12]. In the redex, the received name is an edge of the rule, bound by the input's port, and the parameter's body reaches it through an inner name of its own region. In the reactum, the copy of the body has an inner name that the reactum wires to y. The instance renames the one inner name into the other [Jen06, Def 5.2].

A first idea was to let the received name pass out through the redex's outer face, for the context to close. It was dropped before any code. A context could then merge that name with another name of the parameter, and the reactum would leave the body's other name unbound. Names local to a region keep the binder out of the context's reach.

Definition 6 (Rules that pass names). A rule shape has edges of its own, and each of its ports and inner names is linked to an edge or to one of k slots for outer names. A rule pairs a redex and a reactum over the same slots, with an instantiation ϱ of the reactum's sites by the redex's and, for each reactum site j, a renaming η j of inner names.

structure RShape (S : Sig C) (m k l : Nat) where
  V : Type
  finV : Finite V
  ctl : V → C
  up : V → Option V
  depth : V → Nat
  up_depth : ∀ {v u}, up v = some u → depth u < depth v
  bound : Nat
  depth_lt : ∀ v, depth v < bound
  site : Fin m → Option V
  E : Type
  finE : Finite E
  port : (v : V) → Fin (S.ar (ctl v)) → E ⊕ Fin k
  inner : Fin l → E ⊕ Fin k

structure PRuleN (S : Sig C) where
  {m m' k l l' : Nat}
  R : RShape S m k l
  R' : RShape S m' k l'
  ϱ : Fin m' → Fin m
  η : Fin m' → Fin l → Fin l'

def renN {l l' m' : Nat} (zn : Fin l → Nat) (zn' : Fin l' → Nat) (η : Fin m' → Fin l → Fin l')
    (j : Fin m') (n : Nat) : Nat :=
  match slotOf zn n with
  | some s => zn' (η j s)
  | none => n

Definition 7 (Their ground rules). For every choice of names for the slots, inner names apart from the global names, and every binding-discrete parameter, the redex is the rule beside the identity on the parameter's global names, composed with the parameter. The reactum composes the reactum rule with the instance that copies and renames.

def PRuleN.rules (ob : OutBind S) (Ps : PRuleN S → Prop) : Rules S Nat :=
  fun g => ∃ (P : PRuleN S) (nm : Fin P.k → Nat) (zn : Fin P.l → Nat) (hz : ∀ s t, zn s = zn t → s = t)
    (zn' : Fin P.l' → Nat) (hz' : ∀ s t, zn' s = zn' t → s = t) (X : NameSet Nat)
    (hX : ∀ s, zn s ∉ X.names) (hX' : ∀ s, zn' s ∉ X.names)
    (d : Bg S Iface.origin ⟨P.m, NameSet.union (innN zn hz) X⟩) (hb : BDiscrete ob d),
    Ps P ∧ g = P.groundN ob nm zn hz zn' hz' X hX hX' d hb
Figure 2. Communication. In the redex, the edge of the received name is bound by the input's port, and the body's site reaches it through its inner name z. In the reactum, the body's copy has the inner name w, wired to y.
Figure 3. Replicated communication. The body is copied out, its inner name renamed to w and wired to y; the body inside the replicated input keeps z, on the input's edge.

Definition 8 (The two rules). Communication and replicated communication, after Jensen [Jen06, Def 7.12] and [Jen06, Def 7.19]. In the second, the body's site is instantiated twice, once as the copy and once inside the replicated input, and only the copy's inner name is renamed.

def commRule : PRuleN sig where
  R := commRedex
  R' := commReactum
  ϱ := ssInst
  η := fun _ s => s

def repRule : PRuleN sig where
  R := repRedex
  R' := repReactum
  ϱ := repInst
  η := fun j _ => if j.val = 1 then 0 else 1

def piRules : Rules sig Nat := PRuleN.rules ob (fun P => P = commRule ∨ P = repRule)

§4 · Every reduction is a reaction

Theorem 2 (Soundness). Every reduction of every process is a reaction of the encodings under the two rules, for every name set and environment.

theorem red_soundπ {p q : Proc} (h : Red p q) : ∀ (X : NameSet Nat) (ρ : Nat → Nat),
    (hp : NamesIn X.names ρ p) →
      React piRules (agentπ X ρ p hp) (agentπ X ρ q (NamesIn.of_red h hp))

As in Chapter II, the parameter keeps its edges, so a component whose dangling indices are named by the environment is the rule plugged with its parts. Substitution meets the reactum in one lemma: a received body, copied and its local name wired to the datum, is the body with the datum substituted.

theorem plugRef_ren_subst {m k l : Nat} (R : RShape sig m k l) (nm : Fin k → Nat) (zn : Fin l → Nat)
    (hzn : ∀ s t, zn s = zn t → s = t) {X : NameSet Nat} (hX : ∀ s, zn s ∉ X.names)
    (z : Nat) (g : Nat → Nat) (hg : ∀ n ∈ X.names, g n = n) (s₀ : Fin l) (hgz : g z = zn s₀)
    (t : Fin k) (hin : R.inner s₀ = .inr t) (y : Chan) (ρ : Nat → Nat) (hy : nm t = y.name ρ)
    {E F : Type} (f : E → F) (r : Ref E) (hr : ∀ n ∈ r.fv ρ 1, n ∈ X.names) :
    R.plugRef nm zn (((r.cls (consEnv z ρ)).mapE f).ren g) =
      (((r.subst 0 y).cls ρ).mapE f).mapE Sum.inl

§5 · Every reaction is a reduction

The converse is proved for closed processes, as for CCS: a dangling index is named by the environment, so an open process could react on a link it does not own.

Definition 9 (Closed processes). A process is closed when its free names do not depend on the environment, so that no index escapes its binders.

def Closed (p : Proc) : Prop := ∀ (ρ ρ' : Nat → Nat) (n : Nat), n ∈ p.fn ρ 0 → n ∈ p.fn ρ' 0

Theorem 3 (Occurrence determinacy for rules that pass names). Two instances of a rule in context, equivalent by a map that fixes the rule's nodes, have equivalent reactums. The contexts are any, the parameters any binding-discrete ones. Three properties of the redex are assumed, and both π redexes have them: every edge of the rule is reached by a port of the rule, so the map fixes it; every inner name reaches an edge of the rule, different ones different edges, so a parameter port on an inner name goes to one on the same inner name; and every slot is reached by a port of the rule, so the contexts' links of a slot correspond.

structure OccN {m k l : Nat} (R : RShape S m k l) (l' : Nat) where
  nm : Fin k → Nat
  zn : Fin l → Nat
  hz : ∀ s t, zn s = zn t → s = t
  zn' : Fin l' → Nat
  hz' : ∀ s t, zn' s = zn' t → s = t
  X : NameSet Nat
  hX : ∀ s, zn s ∉ X.names
  hX' : ∀ s, zn' s ∉ X.names
  d : Bg S Iface.origin ⟨m, NameSet.union (innN zn hz) X⟩
  hb : BDiscrete ob d
  K : Iface Nat
  D : Bg S (nFace nm X) K

noncomputable def occEquivN :
    SupportEquivI ι κ (o.Gy R' ϱ η).lean (o₀.Gy R' ϱ η).lean

Theorem 4 (The correspondence). For every closed process p, the reactions of the agent of p are exactly the agents of the reducts of p, over all active contexts and all binding-discrete parameters.

theorem react_iffπ (X : NameSet Nat) (ρ : Nat → Nat) {p : Proc} (hcl : Closed p)
    (hp : NamesIn X.names ρ p) (b : Abstract sig Nat) :
    React piRules (agentπ X ρ p hp) b ↔
      ∃ q, ∃ hr : Red p q, b = agentπ X ρ q (NamesIn.of_red hr hp) :=
  ⟨react_completeπ X ρ hcl hp, fun ⟨_, hr, hb⟩ => hb ▸ red_soundπ hr X ρ hp⟩

The rule's nodes are read back as positions of the process. The process is rearranged around them up to structural congruence: the restrictions at the top to the front, the two matched components split out, the send and the input split out of their sums. The π reduction is then read off. Only the two channels are read back from the agent, and they are equal because the rule links both to one slot. The received name is never read back: it is the rule's own edge, and the reactum wires it to the datum, which is the send's. Occurrence determinacy (Theorem 3) then carries the given reaction to the canonical instance of that reduction, whose reactum is the reduct. Jensen states his correspondence with the proof sketched as following the earlier ones [Jen06, Thm 7.21]; this is a kernel-checked version, for closed processes.

§6 · Shared or private

Jensen's own example of why restriction needs a place [Jen06, p. 113] is a pair of processes that differ only in where νz stands: x̄y | (νz !x(u).(z̄u | z(v))) and x̄y | !x(u).νz (z̄u | z(v)). In the first, every copy of the replicated body uses the one z. In the second, every copy gets its own.

Figure 4. Left, x̄y | (νz !x(u).(z̄u | z(v))): the nu node sits in the region, beside the replicated input. Right, x̄y | !x(u).νz (z̄u | z(v)): it sits inside the replicated input's body.

Theorem 5 (Different agents). The two agents differ: the first has a binder in a region, the second has none.

theorem jensen_agents_ne : agentπ X01 ρ01 pShared namesShared ≠ agentπ X01 ρ01 pPrivate namesPrivate
Figure 5. x̄y | (νz !x(u).(z̄u | z(v))) reacts to νz (0 | (z̄y | z(u)) | !x(u).(z̄u | z(v))). The copy is released inside the one νz, after scope extrusion, and shares its edge with the body that stays.
Figure 6. x̄y | !x(u).νz (z̄u | z(v)) reacts to 0 | (νz (z̄y | z(u))) | !x(u).νz (z̄u | z(v)). The copy has its own nu node and its own edge, apart from those inside the replicated input.

Theorem 6 (Each reacts to its reduct). By Theorem 4, these are also the only reactions of the two agents, since both processes are closed.

theorem jensen_react :
    React piRules (agentπ X01 ρ01 pShared namesShared)
        (agentπ X01 ρ01 qShared (NamesIn.of_red red_shared namesShared)) ∧
      React piRules (agentπ X01 ρ01 pPrivate namesPrivate)
        (agentπ X01 ρ01 qPrivate (NamesIn.of_red red_private namesPrivate))

Jensen's printed reduct of the second process puts νz outside the replicated input [Jen06, p. 113]. His rule keeps it inside, and so does 0 | (νz (z̄y | z(u))) | !x(u).νz (z̄u | z(v)) here.

§7 · Names that move

In (νz x̄z.z̄y) | x(u).u(v) the sender owns a private z and sends it along x. The receiver will listen on whatever it receives. After the first reaction, νz (z̄y | z(u)), the receiver's input is on z, and the scope of z holds both. The second reaction, on z itself, leaves νz (0 | 0). Before the first reaction no input is on z: the link was made by passing the name.

Figure 7. Two reactions in sequence. In the middle agent, the edge of z joins the send and the input that the first reaction released.

Theorem 7 (Mobility). The two reductions, and the two reactions of the agents.

theorem red_mob₁ : Red pMob qMob

theorem red_mob₂ : Red qMob rMob

theorem mob_react :
    React piRules (agentπ X01 ρ01 pMob namesMob)
        (agentπ X01 ρ01 qMob (NamesIn.of_red red_mob₁ namesMob)) ∧
      React piRules (agentπ X01 ρ01 qMob (NamesIn.of_red red_mob₁ namesMob))
        (agentπ X01 ρ01 rMob (NamesIn.of_red red_mob₂ (NamesIn.of_red red_mob₁ namesMob)))

§8 · What has been proved

PROVED means sorry-free in Lean, with the axioms checked: every result below rests on propext and Quot.sound only. The gate LocusGate/Pi.lean fixes the correspondence, Jensen's pair, the mobility example, the scope rule and the converse of Theorem 1. It was watched failing on two wrong statements before it was kept, the scope rule with two wrong binding signatures, and the converse with the exchange law taken out.

WhatWhereStatus
The calculus: substitution, structural congruence, reduction; reduction keeps namesPi/CalculusPROVED
Rules that pass names, their ground rules, the instance that copies and renamesShapes/NameRulesPROVED
The encoding; shifting and substitution are isomorphisms; congruent processes are one agent (Theorem 1)Pi/Sig, Pi/EncPROVED
Soundness for every process (Theorem 2)Pi/SoundPROVED
Occurrence determinacy for rules that pass names (Theorem 3); the canonical instanceShapes/NameComplete, Shapes/NameCanonPROVED
The correspondence on every closed process (Theorem 4)Pi/Canon, Pi/IffPROVED
Jensen's pair told apart, each reacting to its reduct (Theorems 5 and 6); mobility (Theorem 7)Pi/Examples, LocusGate/PiPROVED
Every agent obeys Jensen's scope rule [Jen06, Def 4.20]: every point of a bound link lies inside its binder's scopeBigraph/Scope, Pi/Scope, LocusGate/PiPROVED
Without the exchange law, equal agents need not be congruent: the converse of Theorem 1 fails for the congruence first usedPi/ConverseREFUTED
With the exchange law, equal agents of closed processes are congruent (the converse of Theorem 1); structural congruence is isomorphism of shapes, open processes includedShapes/Decomp, Pi/Complete, LocusGate/PiPROVED
Completeness for open processes—OPEN
Labelled transitions and bisimulation for the π encoding—OPEN

§9 · References

  1. [JM04]Ole Høgh Jensen and Robin Milner. Bigraphs and mobile processes (revised). Technical Report UCAM-CL-TR-580, University of Cambridge Computer Laboratory, February 2004. cl.cam.ac.uk/techreports/UCAM-CL-TR-580.pdf.
  2. [Jen06]Ole Høgh Jensen. Mobile Processes in Bigraphs. Dissertation, October 2006, supervised by Robin Milner. cl.cam.ac.uk/archive/rm135/Jensen-monograph.pdf. The PDF does not name the institution.

The quotations are checked against transcriptions of the sources in docs/sources/.