Domain theory
When reasoning about loops and procedures, we typically need to reason about fixed points; a fixed point of a function f
is some x
such that f(x) = x
.
This kind of reasoning requires a few definitions and results from domain theory, particularly complete lattices, monotone functions, the Knaster-Tarski fixed point theorem, continuous functions, and Kleene's fixed point theorem.
We briefly summarize the main definitions and results that we will need in the course. For an in-depth introduction, we refer to the literature at the end of this page.
We will see more examples in class. You can use this form for questions and unclarities about the reading material. I will try to address your questions in class.
Partial orders
In the following let D
be a non-empty set and ⊑: D x D
a binary relation over the elements of D
.
We call the pair `(D, ⊑) a partial order (or a poset: partially ordered set) if for all
- ⊑ is reflexive: for all
a ∈ D
,a ⊑ a
; - ⊑ is transitive: for all
a,b,c ∈ D
, ifa ⊑ b
andb ⊑ c
, thena ⊑ c
; and - ⊑ is antisymmetric: for all
a,b,c ∈ D
, ifa ⊑ b
andb ⊑ a
, thena = b
.
For example, and - the sets of integers and natural numbers with the usual ordering - are partial orders. Another example with perhaps a less obvious order are predicates:
Example. Recall that we initially did not fix a specific syntax for predicates. Instead, we considered the set
Pred ::= { P | P: States -> Bool }
consisting of arbitrary mappings from states to
Bool = {true, false}
. We can order predicates by pointwise logical implication, i.e. for⊑ ::= ==>
. More formally, for for two predicatesP, Q in Pred
, we define
P ==> Q iff for all states s, the predicate P(s) ==> Q(s) maps to true
.
Lemma.
(Pred, ==>)
is a partial order.
We leave the proof, i.e. showing that ==>
is indeed reflexive, transitive, and antisymmetric as an exercise.
Complete lattices
Let (D, ⊑)
be a partial order and let S ⊆ D
be any subset of D
.
- We call an element
d ∈ D
an upper bound ofS
if it is larger than every element ofS
, that is, iffs ⊑ d
holds for alld ∈ D
. - If there is no other upper bound of
S
that is smaller thand
, thend
is the least upper bound ofS
; formally: for alld ∈ D
, ifd'
is an upper bound ofS
, thend ⊑ d'
. - We also call the least upper bound (with respect to the considered ordering relation ⊑) the supremum of
S
and denote it bysup S
. - Analogously,
d ∈ D
is a lower bound ofS
if it is smaller than every element ofS
, that is, iffd ⊑ s
holds for alld ∈ D
. - If there is no other lower bound of
S
that is larger thand
, thend
is the greatest bound ofS
; formally: for alld ∈ D
, ifd'
is a lower bound ofS
, thend' ⊑ d
. - We also call the greatest lower bound (with respect to the considered ordering relation ⊑) the infimum of
S
and denote it byinf S
.
For example, consider the partial order (Pred, ==>)
and the subset
S ::= {x == 1, x == 2, x == 3}
Then x >= 1
is an upper bound of S
since it is implies by each element.
However, it is not the least upper bound; that is x == 1 || x == 2 || x == 3
.
Not every subset of a partial order has a least upper bound or a greatest lower bound. For example, consider the partial order and the subset . There is no natural number that is larger or equal to every natural number.
Complete lattice. A partial order
(D, ⊑)
where every subsetS ⊆ D
has a least upper bound inD
is called a complete lattice.
In fact, if (D, ⊑)
is a complete lattice, then every subset S ⊆ D
automatically also has a greatest lower bound in D
.
Furthermore, it follows that D
has a unique smallest element, called bot
(bottom), which is given by
bot = sup {} = inf D
D
also has a unique largest element, called top
, which is given by
top = inf {} = sup D
Notice that neither nor can be complete lattices, since they have no largest element.
By contrast, is a complete lattice: for every subset S
,
the supremum of S
is the maximal element of S
if such an element exists; otherwise, the supremum sup S
is .
Lemma. (Pred, ==>) is a complete lattice.
To show that the partial order (Pred, ==>)
is a complete lattice, we need to find a suitable least upper bound in Pred
for every subset S ⊆ Pred
of predicates. The main idea is that the supremum sup S
maps a state s
to true
if there exists a predicate P ∈ S
such that P(s)
is true; if no such predicate exists, sup S
maps s
to false. Formally, for all states s
,
(sup S)(s) ::= exists P:Pred :: P ∈ Pred && P(s) == true
Clearly this definition yields an upper bound: whenever a predicate in S
is true, so is sup S
.
We leave the proof that sup S
is indeed the least upper bound as an exercise.
Question: What is the smallest (resp. the largest) element of the complete lattice
(Pred, ==>)
?
Monotone functions
Let (D, ⊑)
be a complete lattice and let f: D -> D
be a function mapping elements in D
to elements in D
.
The function f
is monotone if it preserves the ordering ⊑. Formally, f
is monotone iff
f is monotone
iff
for all a,b ∈ D, a ⊑ b implies f(a) ⊑ f(b)
For example, the function given by f(x) ::= x+1
is monotone for the complete lattice .
By contrast, the function given by f(x) ::= -x
is not.
Lemma. For every PL0 statement
S
, the mapping from postconditionsQ
to the weakest precondition ofS
andQ
, that is the fucntionWP(S, .): Pred -> Pred
, is monotone.
The proof is by structural induction on the structure of PL0 programs and left as an exercise.
Fixed points of monotone functions
Let (D, ⊑)
be a complete lattice.
Moreover, let f: D -> D
be a monotone function.
- We call
d ∈ D
a fixed point off
iff(d) = d
. - Every element
d in D
such thatf(d) <= d
holds is called a pre-fixed point off
. - Conversely, every element
d in D
such thatd <= f(d)
holds is called a post-fixed point off
.
Every fixed point of f
is thus both a pre-fixed and a post-fixed point of f
.
In general, a function can have no, exactly one, or arbitrarily many fixed points:
- The function
f(x) ::= -x
has no fixed point when considering the complete lattice , since the result always oscillates between two possible results. - For the function
f(x) ::= x
, every element in its domain is a fixed point. - For the function
f(x) ::= x + 1
and the complete lattice , there is only one fixed point: we havef(∞) = ∞
.
The Tarski-Knaster fixed point theorem ensures that every monotone function f: D -> D
over a complete (D, ⊑)
has at least one fixed point.
Even better, the theorem gives characterizations of the least fixed point and the greatest fixed point of f
: the least fixed point is the smallest pre-fixed point and the greatest fixed point is the largest post-fixed point.
Knaster-Tarski Fixed Point Theorem. Let
(D, ⊑)
be a complete lattice and letf: D -> D
be a monotone function.Then the least fixed point of
f
,fix(f)
for short, is given by
fix(f) = inf { d ∈ D | f(d) ⊑ d }
.Furthermore, the greatest fixed point of
f
,FIX(f)
for short, is given by
FIX(f) = sup { d ∈ D | d ⊑ f(d) }
.
For example, for the identify function f(x) ::= x
, the least fixed point is
fix(f) = inf { d ∈ D | f(d) ⊑ d } = inf { d ∈ D } = bot
A proof is found, for example, in Proposition 2.1.7 of Samson Abramsky and Achim Jung: Domain Theory, available online.
Fixed points of continuous functions
The Tarski-Knaster theorem gives us a theoretical characterization of least and greatest fixed points.
However, it does not explain how we could try to compute them, for example by applying f
repeatedly until we reach a fixed point.
For such a computational characterization, we need a stronger notion than monotonicity, which admits swapping function application and taking the supremum:
A function f: D -> D
is continuous iff for every subset S ⊆ D
, we have
sup { f(d) | d in S } = f( sup S )
In particular, every continuous function is also monotonous. Hence, it has a least and greatest fixed point (which may be identical).
Lemma. For every PL0 program
S
, the functionWP(S, .): Pred -> Pred
is continuous.
For continuous functions, Kleene's fixed point theorem allows us to characterize the least and greatest fixed point through iterative application:
Kleene fixed point theorem. Let
(D, <=)
be a complete lattice. Moreover, letf: D -> D
be a continuous function. Then:
fix(f) ::= sup { f^n(bot) | n in Nat }
and
FIX(f) ::= inf { f^n(top) | n in Nat }
,where
f^n
denotes the n-fold application off
, that is,
f^0(d) ::= d
andf^{n+1}(d) ::= f^{n}(f(d))
.
Notice that Kleene's fixed point theorem does not mean that we will reach the least or greatest fixed point after finitely many function applications. It is possible, that we might actually have to apply f
infinitely often and only reach the fixed point in the limit.
This is different from fixed point theorems you might have encountered in program analysis or other courses, where additional constraints (e.g. finite height) guarantee that one reaches the fix point after finitely many steps.
For example, consider the function f
given by f(x) ::= x+1
over the complete lattice .
We can iteratively apply f
to the least element bot
to approximate the least fixed point:
f^0(bot) = bot = 0
f^1(bot) = f(0) = 0 + 1 = 1
f^2(bot) = f(f(0)) = f(1) = 1 + 1 = 2
f^3(bot) = f(f(f(0)) = f(2) = 3
...
f^n(bot) = f(f^{n-1}(bot)) = f(n-1) = n
We can continue apply f
forever. After each application, we get slightly closer to the function's unique fixed point, ∞, but we never reach it.
Further reading
Chapter 8 of Glynn Winskel: The formal semantics of programming languages - an introduction. Foundation of computing series, MIT Press 1993, available online.
Chapter 5 of Hanne Riis Nielson, Flemming Nielson: Semantics with Applications: An Appetizer. Undergraduate Topics in Computer Science, Springer 2007, available online.
A thorough introduction to domain theory is found in
Samson Abramsky and Achim Jung: Domain Theory, available online.
Chapter 2 roughly covers the results presented above.