Program Verification Using Cyclic Proof
.
Reuben N. S. Rowe
University College London
Programming Principles, Logic and Verification Research Group (PPLV)
Computer Laboratory Programming Research Group Seminar
Thursday 19th May 2016
Prologue: It's Proof, But Not As We Know It
•.
(Axiom)
..
..
..
. .
•
•
·
·
·
·
·
·
·
•
•
·
·
·
•.
(Axiom)
.
..
.
.
..
•.
.•
(Axiom)
(Inference).
• We are all familiar with proofs as finite trees
1/22
Prologue: It's Proof, But Not As We Know It
•.
(Axiom)
..
..
..
. .
•
•
·
·
·
·
•
•
·
·
·
•.
.•
..
.
.
•.
(Inference).
• We are all familiar with proofs as finite trees
• But what if we allow proofs to be cyclic graphs instead?
1/22
Prologue: It's Proof, But Not As We Know It
•.
(Axiom)
..
..
..
. .
•
•
·
·
·
·
•
•
·
·
·
•.
.•
..
.
.
•.
(Inference).
• We are all familiar with proofs as finite trees
• But what if we allow proofs to be cyclic graphs instead?
• Cyclic proofs must satisfy a global soundness property
1/22
Introduction
• Our research programme has two broad aims:
2/22
Introduction
• Our research programme has two broad aims:
• Develop cyclic proof (meta) theory in a verification setting
2/22
Introduction
• Our research programme has two broad aims:
• Develop cyclic proof (meta) theory in a verification setting
• Implement the techniques for automatic verification
2/22
Introduction
• Our research programme has two broad aims:
• Develop cyclic proof (meta) theory in a verification setting
• Implement the techniques for automatic verification
• Why cyclic proof?
2/22
Introduction
• Our research programme has two broad aims:
• Develop cyclic proof (meta) theory in a verification setting
• Implement the techniques for automatic verification
• Why cyclic proof?
• It subsumes standard induction
2/22
Introduction
• Our research programme has two broad aims:
• Develop cyclic proof (meta) theory in a verification setting
• Implement the techniques for automatic verification
• Why cyclic proof?
• It subsumes standard induction
• It can help discover inductive hypotheses
2/22
Introduction
• Our research programme has two broad aims:
• Develop cyclic proof (meta) theory in a verification setting
• Implement the techniques for automatic verification
• Why cyclic proof?
• It subsumes standard induction
• It can help discover inductive hypotheses
• Termination arguments can often be extracted from cyclic
proofs
2/22
James Brotherston
Alex Simpson
Richard Bornat
Cristiano Calcagno
Dino Distefano
Nikos Gorogiannis
3/22
Example: First Order Logic
• Assume signature with zero, successor, and equality
• Allow inductive predicate definitions, e.g.
Nx
N0
N sx
E0
Ex
Ox
O sx
E sx
4/22
Example: First Order Logic
• Assume signature with zero, successor, and equality
• Allow inductive predicate definitions, e.g.
Nx
N0
N sx
E0
Ex
Ox
O sx
E sx
• These induce unfolding rules for the sequent calculus, e.g.
Γ ⊢ ∆, N t
(NR2 )
Γ ⊢ ∆, N st
Γ, t = 0 ⊢ ∆ Γ, t = sx, N x ⊢ ∆
(Case N)
Γ, N t ⊢ ∆
where x is fresh
4/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x.
.
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
x = 0 ⊢ E x, O x
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
(Case N).
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
⊢ E 0, O 0
x = 0 ⊢ E x, O x
(=L)
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
(Case N).
5/22
A Cyclic Proof of N x ⊢ E x, O x
⊢ E 0, O 0
.
(ER1 )
x = 0 ⊢ E x, O x
(=L)
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
(Case N).
5/22
A Cyclic Proof of N x ⊢ E x, O x
⊢ E 0, O 0
.
(ER1 )
x = 0 ⊢ E x, O x
(=L)
N y ⊢ E sy, O sy
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
(=L)
(Case N).
5/22
A Cyclic Proof of N x ⊢ E x, O x
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(=L)
N y ⊢ E sy, O sy
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
5/22
A Cyclic Proof of N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
• Suppose N x ⊢ E x, O x is not valid:
[[x]]m1
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
• Suppose N x ⊢ E x, O x is not valid:
[[x]]m1 > [[y]]m2
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
• Suppose N x ⊢ E x, O x is not valid:
[[x]]m1 > [[y]]m2 = [[y]]m3
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
• Suppose N x ⊢ E x, O x is not valid:
[[x]]m1 > [[y]]m2 = [[y]]m3 = [[y]]m4
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
• Suppose N x ⊢ E x, O x is not valid:
[[x]]m1 > [[y]]m2 = [[y]]m3 = [[y]]m4 = [[y]]m5
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
• Suppose N x ⊢ E x, O x is not valid:
[[x]]m1 > [[y]]m2 = [[y]]m3 = [[y]]m4 = [[y]]m5 = [[x]]m6
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
• Suppose N x ⊢ E x, O x is not valid:
[[x]]m1 > [[y]]m2 = [[y]]m3 = [[y]]m4 = [[y]]m5 = [[x]]m6 > [[y]]m7 . . .
5/22
A Cyclic Proof of N x ⊢ E x, O x
.
N x ⊢ E x, O x
N y ⊢ E y, O y
⊢ E 0, O 0
N y ⊢ E y, O sy
(ER1 )
x = 0 ⊢ E x, O x
(Subst)
(=L)
N y ⊢ E sy, O sy
(OR1 )
(ER2 )
x = sy, N y ⊢ E x, O x
N x ⊢ E x, O x.
.
(=L)
(Case N).
• Suppose N x ⊢ E x, O x is not valid:
n1 > n2 > n3 > . . .
5/22
Example: Separation Logic
• Separation Logic incorporates formulas for representing
heap memory:
6/22
Example: Separation Logic
• Separation Logic incorporates formulas for representing
heap memory:
• emp denotes the empty heap
6/22
Example: Separation Logic
• Separation Logic incorporates formulas for representing
heap memory:
• emp denotes the empty heap
• x 7→ ⃗v is the single-cell heap containing values ⃗v at
memory location x
6/22
Example: Separation Logic
• Separation Logic incorporates formulas for representing
heap memory:
• emp denotes the empty heap
• x 7→ ⃗v is the single-cell heap containing values ⃗v at
memory location x
• F ∗ G denotes a heap h that can be split into disjoint
sub-heaps h1 and h2 which model F and G respectively
6/22
Example: Separation Logic
• Separation Logic incorporates formulas for representing
heap memory:
• emp denotes the empty heap
• x 7→ ⃗v is the single-cell heap containing values ⃗v at
memory location x
• F ∗ G denotes a heap h that can be split into disjoint
sub-heaps h1 and h2 which model F and G respectively
• Inductive predicates now represent data-structures, e.g.
linked-list segments:
x = y ∧ emp
ls(x, y)
x 7→ z ∗ ls(z, y)
ls(x, y)
6/22
A Cyclic Proof of List Segment Concatenation
.
.
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
.
.
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
.
.
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
ls(x, z) ⊢ ls(x, z)
(≡)
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
.
.
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
(Id)
ls(x, z) ⊢ ls(x, z)
(≡)
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
.
.
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
(Id)
ls(x, z) ⊢ ls(x, z)
(≡)
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
.
.
.
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ x 7→ v ∗ ls(v, z)
.
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
.
(lsR2 )
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
(Id)
ls(x, z) ⊢ ls(x, z)
(≡)
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
.
.
.
x 7→ v ⊢ x 7→ v
ls(v, y) ∗ ls(y, z) ⊢ ls(v, z)
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ x 7→ v ∗ ls(v, z)
.
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
.
(∗)
(lsR2 )
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
(Id)
ls(x, z) ⊢ ls(x, z)
(≡)
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
.
(Id)
.
.
x 7→ v ⊢ x 7→ v
ls(v, y) ∗ ls(y, z) ⊢ ls(v, z)
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ x 7→ v ∗ ls(v, z)
.
.
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
.
(∗)
(lsR2 )
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
(Id)
ls(x, z) ⊢ ls(x, z)
(≡)
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
ls(x,
y)
∗
ls(y,
z) ⊢ ls(x, z)
.
.
.
(Id)
(Subst)
.
.
x 7→ v ⊢ x 7→ v
ls(v, y) ∗ ls(y, z) ⊢ ls(v, z)
.
.
(∗)
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ x 7→ v ∗ ls(v, z)
.
.
(lsR2 )
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
(Id)
ls(x, z) ⊢ ls(x, z)
(≡)
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
ls(x,
y)
∗
ls(y,
z) ⊢ ls(x, z)
.
.
.
(Id)
(Subst)
.
.
x 7→ v ⊢ x 7→ v
ls(v, y) ∗ ls(y, z) ⊢ ls(v, z)
.
.
(∗)
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ x 7→ v ∗ ls(v, z)
.
.
(lsR2 )
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
A Cyclic Proof of List Segment Concatenation
(Id)
ls(x, z) ⊢ ls(x, z)
(≡)
emp ∗ ls(x, z) ⊢ ls(x, z)
(=L)
(x = y ∧ emp) ∗ ls(y, z) ⊢ ls(x, z)
.
.
.
.
.
ls(x,
y)
∗
ls(y,
z) ⊢ ls(x, z)
.
.
.
(Id)
(Subst)
.
.
x 7→ v ⊢ x 7→ v
ls(v, y) ∗ ls(y, z) ⊢ ls(v, z)
.
.
(∗)
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ x 7→ v ∗ ls(v, z)
.
.
(lsR2 )
.
.
.
x 7→ v ∗ ls(v, y) ∗ ls(y, z) ⊢ ls(x, z)
(Case ls).
ls(x, y) ∗ ls(y, z) ⊢ ls(x, z).
7/22
Global Soundness for Cyclic Proof: Elements
• Fix some values that we can trace along paths in the proof
• In our examples: inductive predicate instances
8/22
Global Soundness for Cyclic Proof: Elements
• Fix some values that we can trace along paths in the proof
• In our examples: inductive predicate instances
• Map (model, trace-value) pairs to elements of a w.f. set
8/22
Global Soundness for Cyclic Proof: Elements
• Fix some values that we can trace along paths in the proof
• In our examples: inductive predicate instances
• Map (model, trace-value) pairs to elements of a w.f. set
• Inductive definitions induce a monotone operator φ on
sets of models
8/22
Global Soundness for Cyclic Proof: Elements
• Fix some values that we can trace along paths in the proof
• In our examples: inductive predicate instances
• Map (model, trace-value) pairs to elements of a w.f. set
• Inductive definitions induce a monotone operator φ on
sets of models
• Interpret the inductive definitions using the lfp
φ(⊥) ⊑ φ(φ(⊥)) ⊑ . . . ⊑ φω (⊥) ⊑ . . . ⊑ µX.φ(X)
8/22
Global Soundness for Cyclic Proof: Elements
• Fix some values that we can trace along paths in the proof
• In our examples: inductive predicate instances
• Map (model, trace-value) pairs to elements of a w.f. set
• Inductive definitions induce a monotone operator φ on
sets of models
• Interpret the inductive definitions using the lfp
φ(⊥) ⊑ φ(φ(⊥)) ⊑ . . . ⊑ φω (⊥) ⊑ . . . ⊑ µX.φ(X)
• Map (m, P ⃗t) to the least approximation φα (⊥) of P in
which m appears
8/22
Global Soundness for Cyclic Proof: Elements
• Fix some values that we can trace along paths in the proof
• In our examples: inductive predicate instances
• Map (model, trace-value) pairs to elements of a w.f. set
• Inductive definitions induce a monotone operator φ on
sets of models
• Interpret the inductive definitions using the lfp
φ(⊥) ⊑ φ(φ(⊥)) ⊑ . . . ⊑ φω (⊥) ⊑ . . . ⊑ µX.φ(X)
• Map (m, P ⃗t) to the least approximation φα (⊥) of P in
which m appears
• Identify the progression points of the proof system, e.g.
x = y ∧ emp ⊢ F x 7→ v ∗ ls(v, y) ⊢ F
(Case ls)
ls(x, y) ⊢ F
8/22
Global Soundness for Cyclic Proof: General Principle
• Impose global soundness condition on proof graphs:
• Every infinite path must have an infinitely progressing trace
• This condition is decidable using Büchi automata
9/22
Global Soundness for Cyclic Proof: General Principle
• Impose global soundness condition on proof graphs:
• Every infinite path must have an infinitely progressing trace
• This condition is decidable using Büchi automata
• We obtain an infinite descent proof-by-contradiction:
9/22
Global Soundness for Cyclic Proof: General Principle
• Impose global soundness condition on proof graphs:
• Every infinite path must have an infinitely progressing trace
• This condition is decidable using Büchi automata
• We obtain an infinite descent proof-by-contradiction:
• Assume the conclusion of the proof is invalid
9/22
Global Soundness for Cyclic Proof: General Principle
• Impose global soundness condition on proof graphs:
• Every infinite path must have an infinitely progressing trace
• This condition is decidable using Büchi automata
• We obtain an infinite descent proof-by-contradiction:
• Assume the conclusion of the proof is invalid
• Local soundness implies an infinite sequence of (counter)
models
9/22
Global Soundness for Cyclic Proof: General Principle
• Impose global soundness condition on proof graphs:
• Every infinite path must have an infinitely progressing trace
• This condition is decidable using Büchi automata
• We obtain an infinite descent proof-by-contradiction:
• Assume the conclusion of the proof is invalid
• Local soundness implies an infinite sequence of (counter)
models
• Global soundness then implies an infinite descending
chain in a well-founded set
9/22
Cyclic Proof vs Explicit Induction
• Explicit induction requires induction hypothesis F up-front
Nx
N0
N sx
Γ ⊢ F[0] Γ, F[x] ⊢ F[sx], ∆
Γ, N t ⊢ ∆
Γ, F[t] ⊢ ∆
(Ind N)
10/22
Cyclic Proof vs Explicit Induction
• Explicit induction requires induction hypothesis F up-front
Nx
N0
N sx
Γ ⊢ F[0] Γ, F[x] ⊢ F[sx], ∆
Γ, N t ⊢ ∆
Γ, F[t] ⊢ ∆
(Ind N)
• Cyclic proof enables 'discovery' of induction hypotheses
10/22
Cyclic Proof vs Explicit Induction
• Explicit induction requires induction hypothesis F up-front
Nx
N0
N sx
Γ ⊢ F[0] Γ, F[x] ⊢ F[sx], ∆
Γ, N t ⊢ ∆
Γ, F[t] ⊢ ∆
(Ind N)
• Cyclic proof enables 'discovery' of induction hypotheses
• Complex induction schemes naturally represented by
nested and overlapping cycles
10/22
Cyclic Proof vs Explicit Induction
• Explicit induction requires induction hypothesis F up-front
Nx
N0
N sx
Γ ⊢ F[0] Γ, F[x] ⊢ F[sx], ∆
Γ, N t ⊢ ∆
Γ, F[t] ⊢ ∆
(Ind N)
• Cyclic proof enables 'discovery' of induction hypotheses
• Complex induction schemes naturally represented by
nested and overlapping cycles
• The explicit induction rules are derivable in the cyclic
system (cf. Brotherston & Simpson)
10/22
Cyclic Proofs vs Infinite Proofs
• Cyclic proofs are the (strict) regular subset of the set of
non-well-founded proof trees
11/22
Cyclic Proofs vs Infinite Proofs
• Cyclic proofs are the (strict) regular subset of the set of
non-well-founded proof trees
• Theorem (Brotherston & Simpson): the full infinite system
is cut-free complete
11/22
Cyclic Proofs vs Infinite Proofs
• Cyclic proofs are the (strict) regular subset of the set of
non-well-founded proof trees
• Theorem (Brotherston & Simpson): the full infinite system
is cut-free complete
• Cut is likely not eliminable in the cyclic sub-system
11/22
A Simple Imperative Language
(Terms)
(Boolean Expressions)
(Programs)
t ::= nil | x
B ::= t=t | t!=t
C ::= ɛ
(stop)
|
x:=t;C
(assignment)
|
x:=[y];C | [x]:=y;C
(load/store)
|
free(x);C | x:=new;C
(de/allocate)
|
if B then C;C
(conditional)
|
while B do C;C
(loop)
12/22
A Simple Imperative Language
(Terms)
(Boolean Expressions)
(Programs)
t ::= nil | x
B ::= t=t | t!=t
C ::= ɛ
(stop)
|
x:=t;C
(assignment)
|
x:=[y];C | [x]:=y;C
(load/store)
|
free(x);C | x:=new;C
(de/allocate)
|
if B then C;C
(conditional)
|
while B do C;C
(loop)
• The following program deallocates a linked list
while x!=nil do y:=[x];free(x);x=y;
12/22
Program Verification by Symbolic Execution
• We use Hoare logic for proving triples {P} C {Q} using
Separation Logic as an assertion language
13/22
Program Verification by Symbolic Execution
• We use Hoare logic for proving triples {P} C {Q} using
Separation Logic as an assertion language
• Program commands are executed symbolically by the
proof rules, e.g.
(load):
{x = v[x′ /x] ∧ (P ∗ y 7→ v)[x′ /x]} C {Q}
{P ∗ y 7→ v} x:=[y];C {Q}
(x′ fresh)
13/22
Program Verification by Symbolic Execution
• We use Hoare logic for proving triples {P} C {Q} using
Separation Logic as an assertion language
• Program commands are executed symbolically by the
proof rules, e.g.
(load):
{x = v[x′ /x] ∧ (P ∗ y 7→ v)[x′ /x]} C {Q}
(free):
{P ∗ y 7→ v} x:=[y];C {Q}
(x′ fresh)
{P} C {Q}
{P ∗ x 7→ v} free(x);C {Q}
13/22
Handling Loops in Cyclic Proofs
• The standard Hoare rule for handling while loops:
{B ∧ P} C1 {P} {¬B ∧ P} C2 {Q}
{P} while B do C1 ;C2 {Q}
14/22
Handling Loops in Cyclic Proofs
• The standard Hoare rule for handling while loops:
{t = z ∧ B ∧ P} C1 {t < z ∧ P}
{¬B ∧ P} C2 {Q}
{P} while B do C1 ;C2 {Q}
t is the loop variant
14/22
Handling Loops in Cyclic Proofs
• The standard Hoare rule for handling while loops:
{t = z ∧ B ∧ P} C1 {t < z ∧ P}
{¬B ∧ P} C2 {Q}
{P} while B do C1 ;C2 {Q}
t is the loop variant
• With cyclic proof, it is enough just to unfold loops
{B ∧ P} C1 ;while B do C1 ;C2 {Q}
{¬B ∧ P} C2 {Q}
{P} while B do C1 ;C2 {Q}
14/22
Example: Deallocating the Linked List
while x!=nil do y:=[x];free(x);x=y;
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
while x!=nil do y:=[x];free(x);x=y;
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
while x!=nil do y:=[x];free(x);x=y;
{emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
{
x ̸= nil
while x!=nil do y:=[x];free(x);x=y;
{emp}
}
∧ ls(x, nil)
y:=[x];free(x);x=y;while x!=nil do y:=[x];free(x);x=y; {emp}
{
}
x = nil
.
ɛ {emp}
.
.
∧ ls(x, nil)
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
{
x ̸= nil
{emp}
while x!=nil do y:=[x];free(x);x=y;
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
{
x = nil
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
{
x ̸= nil
{emp}
while x!=nil do y:=[x];free(x);x=y;
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧ emp
{
x ̸= nil
{emp}
while x!=nil do y:=[x];free(x);x=y;
{
x 7→ v
}
∗ ls(v, nil)
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧ emp
{
x ̸= nil
{emp}
while x!=nil do y:=[x];free(x);x=y;
{
x 7→ v
}
∗ ls(v, nil)
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧ emp
{
x ̸= nil
{emp}
while x!=nil do y:=[x];free(x);x=y;
x 7→ y
}
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(load)
}
∗ ls(v, nil)
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
{emp}
while x!=nil do y:=[x];free(x);x=y;
{ls(y, nil)} x=y; . . . {emp}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧ emp
{
x ̸= nil
x 7→ y
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(free)
}
(load)
}
∗ ls(v, nil)
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
{emp}
while x!=nil do y:=[x];free(x);x=y;
.
{ls(x, nil)} while . . . {emp}
(assign)
{ls(y, nil)} x=y; . . . {emp}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧ emp
{
x ̸= nil
x 7→ y
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(free)
}
(load)
}
∗ ls(v, nil)
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
{emp}
while x!=nil do y:=[x];free(x);x=y;
.
{ls(x, nil)} while . . . {emp}
(assign)
{ls(y, nil)} x=y; . . . {emp}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧ emp
{
x ̸= nil
x 7→ y
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(free)
}
(load)
}
∗ ls(v, nil)
(unfold ls)
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
.
y:=[x]; . . . {emp}
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Example: Deallocating the Linked List
{ls(x, nil)}
{emp}
while x!=nil do y:=[x];free(x);x=y;
.
{ls(x, nil)} while . . . {emp}
(assign)
{ls(y, nil)} x=y; . . . {emp}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧ emp
{
x ̸= nil
x 7→ y
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(free)
}
(load)
}
∗ ls(v, nil)
(unfold ls)
}
∧ ls(x, nil)
y:=[x]; . . . {emp}
.
.
.
.
y:=[x]; . . . {emp}
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(while)
.{ls(x, nil)} while . . . {emp}
15/22
Verifying Recursive Procedures
(Procedures)
(Programs)
proc p(⃗x) { C }
C ::= . . . | p(⃗t); C
16/22
Verifying Recursive Procedures
(Procedures)
(Programs)
proc p(⃗x) { C }
C ::= . . . | p(⃗t); C
{P} C {Q}
(proc):
(body(p) = C)
{P} p(⃗x) {Q}
16/22
Verifying Recursive Procedures
(Procedures)
(Programs)
proc p(⃗x) { C }
C ::= . . . | p(⃗t); C
{P} C {Q}
(proc):
(body(p) = C)
{P} p(⃗x) {Q}
(call):
{P} p(⃗t) {P′ } {P′ } C {Q}
{P} p(⃗t); C {Q}
16/22
Verifying Recursive Procedures
(Procedures)
(Programs)
proc p(⃗x) { C }
C ::= . . . | p(⃗t); C
{P} C {Q}
(proc):
(body(p) = C)
(call):
{P} p(⃗t) {P′ } {P′ } C {Q}
{P} p(⃗x) {Q}
(param):
{P} p(⃗t); C {Q}
{P} p(⃗t) {Q}
{P[t/x]} p(⃗t)[t/x] {Q[t/x]}
16/22
Verifying Recursive Procedures
(Procedures)
(Programs)
proc p(⃗x) { C }
C ::= . . . | p(⃗t); C
{P} C {Q}
(proc):
(body(p) = C)
(call):
{P} p(⃗t) {P′ } {P′ } C {Q}
{P} p(⃗x) {Q}
(param):
{P} p(⃗t); C {Q}
{P} p(⃗t) {Q}
{P[t/x]} p(⃗t)[t/x] {Q[t/x]}
• The following procedure recursively deallocates a linked list
proc dealloc(x) { if x!=nil then y:=[x]; free(x); dealloc(y); }
16/22
Example: Deallocating the Linked List (Recursively)
proc dealloc(x) { if x!=nil then y:=[x]; free(x); dealloc(y); }
.
{ls(x, nil)} dealloc(x); {emp}
(param)
{ls(y, nil)} dealloc(y); {emp}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧emp
{
x ̸= nil
x 7→ y
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(load)
}
∗ ls(v, nil)
.
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
(free)
}
y:=[x]; . . . {emp}
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(if )
{ls(x, nil)} if x!=nil then . . . . . . {emp}
(proc)
.{ls(x, nil)} dealloc(x); {emp}
17/22
Example: Deallocating the Linked List (Recursively)
proc dealloc(x) { if x!=nil then y:=[x]; free(x); dealloc(y); }
.
{ls(x, nil)} dealloc(x); {emp}
(param)
{ls(y, nil)} dealloc(y); {emp}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧emp
{
x ̸= nil
x 7→ y
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(load)
}
∗ ls(v, nil)
.
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
(free)
}
y:=[x]; . . . {emp}
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(if )
{ls(x, nil)} if x!=nil then . . . . . . {emp}
(proc)
.{ls(x, nil)} dealloc(x); {emp}
17/22
Example: Deallocating the Linked List (Recursively)
proc dealloc(x) { if x!=nil then y:=[x]; free(x); dealloc(y); }
.
{ls(x, nil)} dealloc(x); {emp}
(param)
{ls(y, nil)} dealloc(y); {emp}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧emp
{
x ̸= nil
x 7→ y
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(load)
}
∗ ls(v, nil)
.
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
(free)
}
y:=[x]; . . . {emp}
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(if )
{ls(x, nil)} if x!=nil then . . . . . . {emp}
(proc)
.{ls(x, nil)} dealloc(x); {emp}
17/22
Example: Deallocating the Linked List (Recursively)
proc dealloc(x) { if x!=nil then y:=[x]; free(x); dealloc(y); }
.
{ls(x, nil)} dealloc(x); {emp}
(param)
{ls(y, nil)} dealloc(y); {emp}
{
(⊥)
x ̸= nil
. ∧ x = nil y:=[x]; . . . {emp}
∧emp
{
x ̸= nil
x 7→ y
free(x); . . . {emp}
∗ ls(y, nil)
{
x 7→ v
(load)
}
∗ ls(v, nil)
.
y:=[x]; . . . {emp}
(unfold ls)
}
∧ ls(x, nil)
(free)
}
y:=[x]; . . . {emp}
{
x = nil
(|=)
}
∧ ls(x, nil)
ɛ {emp}
(if )
{ls(x, nil)} if x!=nil then . . . . . . {emp}
(proc)
.{ls(x, nil)} dealloc(x); {emp}
17/22
A Subtlety with Procedures
proc shuffle(x) {
if x!=nil then
y:=[x]; reverse(y); shuffle(y); [x]:=y;
}
18/22
A Subtlety with Procedures
proc shuffle(x) {
if x!=nil then
y:=[x]; reverse(y); shuffle(y); [x]:=y;
}
·
·
·
{ls(y, nil)} reverse(y); {ls(y, nil)}
(frame)
{x 7→ y ∗ ls(y, nil)} reverse(y); {x 7→ y ∗ ls(y, nil)}
.
·
·
·
{x 7→ y ∗ ls(y, nil)} shuffle(y); . . . {ls(x, nil)} .
.
{x 7→ y ∗ ls(y, nil)} reverse(y); shuffle(y); . . . {ls(x, nil)}
·
·
·
.
18/22
A Subtlety with Procedures
proc shuffle(x) {
if x!=nil then
y:=[x]; reverse(y); shuffle(y); [x]:=y;
}
·
·
·
{ls(y, nil)} reverse(y); {ls(y, nil)}
(frame)
{x 7→ y ∗ ls(y, nil)} reverse(y); {x 7→ y ∗ ls(y, nil)}
.
·
·
·
{x 7→ y ∗ ls(y, nil)} shuffle(y); . . . {ls(x, nil)} .
.
{x 7→ y ∗ ls(y, nil)} reverse(y); shuffle(y); . . . {ls(x, nil)}
·
·
·
.
18/22
A Subtlety with Procedures
proc shuffle(x) {
if x!=nil then
y:=[x]; reverse(y); shuffle(y); [x]:=y;
}
·
·
·
{ls(y, nil)} reverse(y); {ls(y, nil)}
(frame)
{x 7→ y ∗ ls(y, nil)} reverse(y); {x 7→ y ∗ ls(y, nil)}
.
·
·
·
{x 7→ y ∗ ls(y, nil)} shuffle(y); . . . {ls(x, nil)} .
.
{x 7→ y ∗ ls(y, nil)} reverse(y); shuffle(y); . . . {ls(x, nil)}
·
·
·
.
18/22
Solution: Explicit Approximation
• We explicitly label predicate instances, e.g. lsα (x, y)
• indicates which approximation to interpret them in
19/22
Solution: Explicit Approximation
• We explicitly label predicate instances, e.g. lsα (x, y)
• indicates which approximation to interpret them in
• We now use these labels as the trace values, e.g.
·
·
·
{lsβ (y, nil)} reverse(y); {lsβ (y, nil)}
(frame)
{x 7→ y ∗ lsβ (y, nil)} reverse(y); {x 7→ y ∗ lsβ (y, nil)}
.
·
·
·
{x 7→ y ∗ lsβ (y, nil)} shuffle(y); . . . {lsα (x, nil)} .
.
{x 7→ y ∗ lsβ (y, nil)} reverse(y); shuffle(y); . . . {lsα (x, nil)}
·
·
·
.
19/22
Solution: Explicit Approximation
• We explicitly label predicate instances, e.g. lsα (x, y)
• indicates which approximation to interpret them in
• We now use these labels as the trace values, e.g.
·
·
·
{lsβ (y, nil)} reverse(y); {lsβ (y, nil)}
(frame)
{x 7→ y ∗ lsβ (y, nil)} reverse(y); {x 7→ y ∗ lsβ (y, nil)}
.
·
·
·
{x 7→ y ∗ lsβ (y, nil)} shuffle(y); . . . {lsα (x, nil)} .
.
{x 7→ y ∗ lsβ (y, nil)} reverse(y); shuffle(y); . . . {lsα (x, nil)}
·
·
·
.
• We now need constraints on labels when unfolding, e.g.
Γ, β < α, t = 0 ⊢ ∆
Γ, β < α, t = sx, Nβ x ⊢ ∆
Γ, Nα t ⊢ ∆
(Case N)
19/22
The Cyclist Verification Tool
• Our verification tool, C
, is implemented in OCaml
• Generic cyclic proof-search procedure using iterated
depth-first search
• Cycles are formed eagerly and discarded if unsound
• The generic proof search is parametric
• Different proof systems implemented as separate modules
20/22
The Cyclist Verification Tool
• Our verification tool, C
, is implemented in OCaml
• Generic cyclic proof-search procedure using iterated
depth-first search
• Cycles are formed eagerly and discarded if unsound
• The generic proof search is parametric
• Different proof systems implemented as separate modules
github.com/ngorogiannis/cyclist
20/22
Performance Results
Program
Time (ms) LOC Procs Nodes
Back-links
list traverse
tree traverse
list deallocate
tree deallocate
tree reflect
list rev. deallocate
list append
list reverse
list reverse (tail rec.)
list reverse (with append)
list filter
list partition
list ackermann
queue
functional queue
shuffle
Results of Experimental Evaluation on 2.93GHz Intel Core i7-870, 8GB RAM
21/22
Concluding Remarks
• Ongoing work: inferring constraints on predicate labels
automatically
• Some problems remain hard, of course
• Generalisation of inductive hypotheses
• Finding and applying lemmas
• Synthesizing procedure summaries (see previous point!)
22/22
Thank You
Related Work
• Cyclic proofs for FOL with inductive predicates
(Brotherston & Simpson, LICS 2007)
• Cyclic proofs for Separation Logic with inductive predicates
(Brotherston, SAS 2007)
• Cyclic proofs verifying simple heap-manipulating WHILE language
(Brotherston, Bornat & Calcagno, POPL 2008)
• Implementations in Isabelle/HOL, then OCaml
(Brotherston, Distefano, Gorogiannis, CADE 2011/APLAS 2012)
• Abduction of inductive predicates using cyclic proof
(Brotherston & Gorogiannis, SAS 2014)
• Current Work — cyclic proofs for verifying:
• procedural heap-manipulating language (Rowe, Brotherston)
• temporal properties (Tellez Espinosa, Brotherston)
© Copyright 2026 Paperzz