3.2 ConGolog
3.2.1 A Transition Semantics
Formally, the semantics of ConGolog is defined using a so-called transition semantics, which de-
fines single steps of computation. There is a relation, denoted by the predicate Trans(σ, s, δ, s0),
that associates with a given program σ and situation s a new situation s0 that results from
executing σ’s first action in s, and a new program δ that represents what remains of σ after
having performed that action. Furthermore, one needs to define which configurationshσ, si
are final, meaning that the computation can be considered completed when a final configura- tion is reached. This is denoted by the predicate Final(σ, s). Note that the use of a transition semantics necessitates the reification of programs as first order terms in the logical language (cf. [dGLL00] and Appendix A). To simplify the discussion, we postpone the introduction of procedures which necessitates the use of second-order logic.
The predicate Final is characterized by the following set of axioms. The term φ[s] denotes the formula obtained by substituting the situation variable s for all occurrences of now in fluents appearing in φ (cf. [dGLL00] and Appendix A).
Final(α, s)≡ False , where α is a primitive action
Final(nil, s)≡ True, where nil is the empty program
Final(φ?, s)≡ False
Final([σ1, σ2], s)≡ Final(σ1, s)∧ Final(σ2, s)
Final(if(φ, σ1, σ2), s)≡ φ[s] ∧ Final(σ1, s)∨ ¬φ[s] ∧ Final(σ2, s)
Final(while(φ, σ), s)≡ ¬φ[s] ∨ Final(σ, s)
Final(σ1 ii σ2, s)≡ Final(σ1, s)∧ Final(σ2, s)
Final(σ1|σ2, s)≡ Final(σ1)∨ Final(σ2)
Final(πx.σ, s)≡ ∃v.Final(σx
v, s)
Final(σ∗, s)≡ True
Final(σ1 || σ2)≡ Final(σ1)∧ Final(σ2)
Final(σ||, s)≡ True
4We remark that non-concurrent GOLOG [LRL+97] considers non-synchronized versions of the if-then-else
3.2. CONGOLOG 45 Let us first consider when a deterministic program is final. A program that consists of a primitive action α or a test φ? is never final. On the other hand, the empty program nil is always final. A conditional if(φ, σ1, σ2) is final if φ holds and σ1 is final, or if φ is false and σ2
is final. A sequence [σ1, σ2] is final if and only if both σ1 and σ2 are final. A while(φ, σ) loop
is final if φ is false or if σ is final. The concurrent, prioritized execution of two programs is
final if and only if both programs are final. As for the nondeterministic instructions, σ1|σ2 is
final if any nondeterministic branch σi is final. πx.σ is final if there exists a binding v for x
such that σvx is final, where σvx is obtained from σ by substituting x with v. σ∗ is final, since
it is allowed to execute 0 times. Similarly for σ||. Finally, σ1 || σ2 is final if and only if both
σi are final.
The following set of axioms characterizes the predicate Trans. Similar to φ[s], α[s] denotes the action obtained by substituting the situation variable s for all occurrences of now in functional fluents appearing in α (cf. [dGLL00] and Appendix A).
Trans(nil, s, δ, s0)≡ False
Trans(α, s, δ, s0)≡ Poss(α[s], s) ∧ δ = nil ∧ s0 = do(α[s], s)
Trans(φ?, s, δ, s0)≡ φ[s] ∧ δ = nil ∧ s0 = s Trans([σ1, σ2], s, δ, s0)≡
∃γ.Trans(σ1, s, γ, s0)∧ δ = [γ, σ2]∨ Final(σ1, s)∧ Trans(σ2, s, δ, s0)
Trans(if(φ, σ1, σ2), s, δ, s0)≡ φ[s]∧ Trans(σ1, s, δ, s0)∨ ¬φ[s] ∧ Trans(σ2, s, δ, s0) Trans(while(φ, σ), s, δ, s0)≡ ∃γ.Trans(σ, s, γ, s0)∧ φ[s] ∧ δ = [γ, while(φ, σ)] Trans(σ1 ii σ2, s, δ, s0)≡ ∃γ.δ = (γ ii σ2)∧ Trans(σ1, s, γ, s0)∨ ∃γ.δ = (σ1 ii γ) ∧ Trans(σ2, s, γ, s0)∧ ∀γ0, s00.¬Trans(σ1, s, γ0, s00)
Trans(σ1|σ2, s, δ, s0)≡ Trans(σ1, s, δ, s0)∨ Trans(σ2, s, δ, s0)
Trans(πx.σ, s, δ, s0)≡ ∃v.Trans(σx v, s, δ, s) Trans(σ∗, s, δ, s0)≡ ∃γ.δ = [γ, σ∗]∧ Trans(σ, s, γ, s0) Trans(σ1 || σ2, s, δ, s0)≡ ∃γ.δ = (γ || σ2)∧ Trans(σ1, s, γ, s0)∨ ∃γ.δ = (σ1 || γ) ∧ Trans(σ2, s, γ, s0) Trans(σ||, s, δ, s0)≡ ∃γ.δ = (γ || σ||)∧ Trans(σ, s, γ, s0)
As before, we first consider the deterministic instructions. Intuitively, a program that consists of a single atomic action α in a situation s results in the execution of α[s] with an empty remaining program if and only if α[s] is executable in s. A test φ? succeeds if φ[s] holds, leaving nothing to be done, or is blocked, meaning that it cannot result in a transition. The
execution of [σ1, σ2] in s may result in any successor situation that could be reached by the
execution of σ1, with remaining program [γ, σ2], where γ is what remains of σ1; or, if σ1
is final in s, it just corresponds to the execution of σ2. The execution of if(φ, σ1, σ2) in s
corresponds to the execution of σ1 if φ is true in s, else it corresponds to the execution of σ2.
A while(φ, σ) loop may only result in a successor configuration if φ is true, in which case the
σ1 whenever possible; however, if σ1 is blocked it executes σ2.
The execution of the nondeterministic instruction (σ1|σ2) in s can result in any successor
configuration that can be reached through the execution of σ1 or σ2 in s. The execution of
πx.σ can result in a successor configuration hδ, s0i if there is a v such that the execution of
any σx
v can result inhδ, s0i. Here, σvxis the program resulting from σ by substituting x with v.
The execution of σ∗ in s can result in a new situation s0 if the execution of σ can do so. The
remaining program then consists of the sequence [γ, σ∗], where γ is what remains of σ after
the transition from s to s0. Similarly, the execution of σ|| in s can result in a new situation s0
if the execution of σ can do so. This time, the remaining program consists of the concurrent
execution of γ and σ||. Finally, (σ1 || σ2) may result in any successor situation which can be
reached by a single step of any σi. The remaining program then consists of the concurrent
execution of what remains of σi, and the other (unmodified) process.
A final situation s0 reachable after a finite number of transitions from a starting situation
s is identified with the situation resulting from a possible execution trace of program σ,
starting in situation s. This is captured by the predicate Do(σ, s, s0), which is defined in
terms of T rans∗, the transitive closure of T rans:
Do(σ, s, s0)≡ ∃δ.T rans∗(σ, s, δ, s0)∧ F inal(δ, s0) Trans∗(σ, s, δ, s0)≡ ∀T [... ⊃ T (σ, s, δ, s0)]
where the ellipsis stands for the universal closure of the conjunction of the following formulas: T (σ, s, σ, s)
Trans(σ, s, σ∗, s∗)∧ T (σ∗, s∗, δ, s0)⊃ T (σ, s, δ, s0)
Given a program δ, proving that δ is executable in the initial situation then amounts to
proving Γ|= ∃s.Do(δ, S0, s), where Γ consists of the above axioms for ConGolog together with
a situation calculus basic action theory. The following proposition (Lemma 4 from [dGLL00]) turns out to be quite useful in doing so. Intuitively, it says that to show that Trans∗(σ, s, δ, s0) holds, it is sufficient to show that there is a sequence of transitions leading fromhσ, si to hδ, s0i.
Proposition 1 : Let AX be the foundational axioms of the situation calculus together
with the definitions of Trans, Final and Trans∗. Then for every model M of AX, M |=
Trans∗(σ, s, δ, s0) if and only if there exist σ1, s1, ..., σn, sn such that σ1 = σ, s1 = s, σn =
δ, sn= s0 and M |= Trans(σi, si, σi+1, si+1) for i = 1, ...n− 1.
3.2.2 An Example
To illustrate the use of ConGolog, let us go back to the coffee delivery example of the previous section. Suppose we want to instruct the robot to subsequently serve coffee to all who have issued a coffee request. This can be specified by the following ConGolog plan:
Πdeliv= while(. ∃r.CoffeeRequest(r),
[gotoRoom(nextRoom), giveCoffee(robotLoc)])
A word on notation: throughout this thesis, we will use terms of the form Πname to denote
plans. Note that we have not yet defined the semantics of procedures; accordingly we consider Πdeliv as an abbreviation. Πdeliv makes use of the defined functional fluent nextRoom to
3.2. CONGOLOG 47
determine the order in which coffee requests are to be fulfilled. nextRoom is defined as
follows:
nextRoom(s) = r≡ r = nil ∧ ∀r0.¬CoffeeRequest(r0, s)∨
CoffeeRequest(r, s)∧ ¬∃r0.[CoffeeRequest(r0, s)∧ roomOrder(r0, r)]. (3.12)
Here, the predicate roomOrder defines an (arbitrary) total ordering on the room names. For means of simplicity, we use the following definition of roomOrder:
roomOrder(r0, r)≡r0 = R1∧ r ∈ {R2, R3, R4}∨
r0 = R2∧ r ∈ {R3, R4}∨
r0 = R3∧ r ∈ {R4}.
(3.13)
Let Γ be the basic action theory describing the coffee delivery domain from the previous
section together with the axioms defining Trans, Final, Trans∗ and Do from this section, the
definitions of nextRoom and roomOrder and the axioms needed for the encoding of programs as first-order terms (cf. [dGLL00] and Appendix A). Then from Γ we can deduce that the
execution of Πdeliv in S0 results in a situation (an execution trace) where all requests have
been satisfied:
Γ|= ∃s.Do(Πdeliv, S0, s)∧ ¬∃r.CoffeeRequest(r, s)∧
s = do([gotoRoom(R2), giveCoffee(R2), gotoRoom(R4), giveCoffee(R4)], S0).
Proof: Although the proof is straightforward, it is quite laborious. By Proposition 1, to
prove that do([gotoRoom(R2), giveCoffee(R2), gotoRoom(R4), giveCoffee(R4)], S0) is an exe-
cution trace of Πdeliv in S0 we have to show that there is a sequence of transitions from S0
to do([gotoRoom(R2), giveCoffee(R2), gotoRoom(R4), giveCoffee(R4)], S0). Furthermore, we
have to show that the last configuration is final. From the initial state description (Ax- iom 3.7), we get:
CoffeeRequest(R2, S0). (3.14)
Hence,∃r.CoffeeRequest(r, S0). From this and the definition of Final:
¬Final(Πdeliv, S0). (3.15)
From the definition of Trans regarding while-loops:5
Trans(while(∃r.CoffeeRequest(r), [gotoRoom(nextRoom), giveCoffee(robotLoc)]), S0, δ, s0)≡ ∃γ.Trans([gotoRoom(nextRoom), giveCoffee(robotLoc)], S0, γ, s0)∧ ∃r.CoffeeRequest(r, S0)∧ δ = [γ, while(∃r.CoffeeRequest(r), [gotoRoom(nextRoom), giveCoffee(robotLoc)])]. (3.16)
From the initial state description (Axiom 3.7), the definition of nextRoom (Axiom 3.12) and the definition of roomOrder (Axiom 3.13):
nextRoom(S0) = R2. (3.17)
5To be more precise, we also need the predicate Holds(φ, s), which is used to evaluate reified conditions
From 3.17, the action precondition for gotoRoom (Axiom 3.8) and the definition of Trans regarding primitive actions:
Trans(gotoRoom(nextRoom), S0, δ, s0)≡ s0 = do(gotoRoom(R2), S0)∧ δ = nil. (3.18)
From 3.18 and the definition of Trans regarding sequences:
Trans([gotoRoom(nextRoom), giveCoffee(robotLoc)]), S0, δ, s0)≡
s0 = do(gotoRoom(R2), S0)∧ δ = [nil, giveCoffee(robotLoc)]. (3.19)
From 3.14, 3.16 and 3.19 we get the following, which shows that there is a transition from S0
to do(gotoRoom(R2), S0).
Trans(while(∃r.CoffeeRequest(r),
[gotoRoom(nextRoom), giveCoffee(robotLoc)]), S0, δ, s0)≡
δ = [[nil, giveCoffee(robotLoc)], while(∃r.CoffeeRequest(r),
[gotoRoom(nextRoom),
giveCoffee(robotLoc)])]∧
s0 = do(gotoRoom(R2), S0).
(3.20)
Let S1= do(gotoRoom(R. 2), S0). From the definition of Final:
¬Final([[nil, giveCoffee(robotLoc)], Πdeliv], S1). (3.21)
From the definition of Trans regarding sequences and 3.21:
Trans([[nil, giveCoffee(robotLoc)], Πdeliv], S1, δ, s0)≡
∃γ.Trans([nil, giveCoffee(robotLoc)], S1, γ, s0)∧
δ = [γ, Πdeliv].
(3.22)
From the definition of Trans regarding sequences and the fact Final(nil, s):
Trans([nil, giveCoffee(robotLoc)], s, δ, s0)≡ Trans(giveCoffee(robotLoc), s, δ, s0). (3.23)
From the successor state axiom for robotLoc (Axiom 3.10):
robotLoc(S1) = R2. (3.24)
From 3.24, the action precondition axiom for giveCoffee (Axiom 3.9) and the definition of Trans regarding primitive actions:
Trans(giveCoffee(robotLoc), S1, δ, s0)≡
s0= do(giveCoffee(R2)], S1)∧ δ = nil.
(3.25) From 3.25 and 3.23 and 3.22 we get the following, which shows that there is a transition from S1 to do(giveCoffee(R2), S1):
Trans([[nil, giveCoffee(robotLoc)], Πdeliv], S1, δ, s0)≡
δ = [nil, Πdeliv]∧ s0 = do(giveCoffee(R2), S1).
(3.26)
Let S2 = do(giveCoffee(R. 2), S1). From the successor state axiom for CoffeeRequest (Ax-
iom 3.11) and the initial state description (Axiom 3.7):
3.2. CONGOLOG 49 From 3.27 and the definition of Final:
¬Final([nil, Πdeliv], S2). (3.28)
From the definition of Trans regarding sequences and the fact Final(nil, s): Trans([nil, Πdeliv], S2, δ, s0)≡
Trans(Πdeliv, S2, δ, s0).
(3.29) From 3.29, 3.27 and the definition of Trans regarding while-loops:
Trans([nil, Πdeliv], S2, δ, s0)≡
Trans([gotoRoom(nextRoom), giveCoffee(robotLoc)], S2, γ, s0)∧
δ = [γ, Πdeliv].
(3.30)
From the definition of nextRoom (Axiom 3.12), the successor state axiom for CoffeeRequest (Axiom 3.11) and the definition of roomOrder (Axiom 3.13):
nextRoom(S2) = R4. (3.31)
From 3.30, 3.31, the action precondition axiom for gotoRoom (Axiom 3.8) and the def-
inition of Trans we get the following, which shows that there is a transition from S2 to
do(gotoRoom(R4), S2):
Trans([nil, Πdeliv], S2, δ, s0)≡
s0 = do(gotoRoom(R4), S2)∧
δ = [[nil, giveCoffee(robotLoc)], Πdeliv].
(3.32)
Let S3= do(gotoRoom(R. 4), S2). From the definition of Final:
¬Final([[nil, giveCoffee(robotLoc)], Πdeliv], S3) (3.33)
From the successor state axiom for robotLoc (Axiom 3.10):
robotLoc(S3) = R4 (3.34)
From the definition of Trans regarding sequences and 3.33:
Trans([[nil, giveCoffee(robotLoc)], Πdeliv], S3, δ, s0)≡
∃γ.Trans([nil, giveCoffee(robotLoc)], S3, γ, s0)∧
δ = [γ, Πdeliv].
(3.35)
From the action precondition axiom for giveCoffee (Axiom 3.9), 3.34 and the definition of Trans:
Trans([nil, giveCoffee(robotLoc)], S3, δ, s0)≡
s0= do(giveCoffee(R4), S3)∧ δ = nil.
(3.36)
From 3.35 and 3.36, we get the following, which shows that there is a transition from S3 to
do(giveCoffee(R4), S3):
Trans([[nil, giveCoffee(robotLoc)], Πdeliv], S3, δ, s0)≡
Let S4 = do(giveCoffee(R. 4), S3). We have now shown that there is a sequence of transi-
tions from S0 to S4 = do([gotoRoom(R2), giveCoffee(R2), gotoRoom(R4), giveCoffee(R4)], S0).
From 3.20, 3.26, 3.32, 3.37 and Proposition 1:
Trans∗(Πdeliv, S0, [nil, Πdeliv], S4). (3.38)
In order to show that S4 is an execution trace of Πdeliv, we still have to show that the
configuration reached is final. From the successor state axiom for CoffeeRequest (Axiom 3.11) and the initial state description (Axiom 3.7):
¬∃r.CoffeeRequest(r, S4). (3.39)
From 3.39 and the definition of Final regarding while-loops:
Final(while(∃r.CoffeeRequest(r),
[gotoRoom(nextRoom), giveCoffee(robotLoc)]), S4).
(3.40) From 3.40, the fact Final(nil, s) and the definition of Final regarding sequences:
Final([nil, Πdeliv], S4). (3.41)
Finally, from the definition of Do, 3.38 and 3.41, we can conclude that S4 is an execution
trace of Πdeliv in S0:
Γ|= Do(Πdeliv, S0, S4). (3.42)
This, together with 3.39, finishes the proof. 2
As the above proof illustrates, proving that the execution of a program results in a par- ticular execution trace is a straightforward but laborious task. In general, it is suggestive to make use of a ConGolog implementation instead of calculating execution traces by hand. In fact, all example executions presented in this thesis were computed using the prototypical implementations described in Chapter 8. Accordingly, in the remainder of this thesis we will only provide some (informal) arguments as to why a program results in a particular execution trace.