Lecture notes 20190308
Hoare Logic 3
Remark. Some material in this lecture is from << Software Foundation >>
volume 2.
Require Import PL.Imp2.
Program correctness proof in Coq
Module Axiomatic_semantics_1.
Axiom hoare_seq : ∀(P Q R: Assertion) (c1 c2: com),
{{P}} c1 {{Q}} →
{{Q}} c2 {{R}} →
{{P}} c1;;c2 {{R}}.
Axiom hoare_skip : ∀P,
{{P}} Skip {{P}}.
Axiom hoare_if : ∀P Q b c1 c2,
{{ P AND [[b]] }} c1 {{ Q }} →
{{ P AND NOT [[b]] }} c2 {{ Q }} →
{{ P }} If b Then c1 Else c2 EndIf {{ Q }}.
Axiom hoare_while : ∀P b c,
{{ P AND [[b]] }} c {{P}} →
{{P}} While b Do c EndWhile {{ P AND NOT [[b]] }}.
End Axiomatic_semantics_1.
Axiom hoare_seq : ∀(P Q R: Assertion) (c1 c2: com),
{{P}} c1 {{Q}} →
{{Q}} c2 {{R}} →
{{P}} c1;;c2 {{R}}.
Axiom hoare_skip : ∀P,
{{P}} Skip {{P}}.
Axiom hoare_if : ∀P Q b c1 c2,
{{ P AND [[b]] }} c1 {{ Q }} →
{{ P AND NOT [[b]] }} c2 {{ Q }} →
{{ P }} If b Then c1 Else c2 EndIf {{ Q }}.
Axiom hoare_while : ∀P b c,
{{ P AND [[b]] }} c {{P}} →
{{P}} While b Do c EndWhile {{ P AND NOT [[b]] }}.
End Axiomatic_semantics_1.
Module swapping.
Import Axiomatic_semantics_1.
Local Instance X: var := new_var().
Local Instance Y: var := new_var().
Local Instance TEMP: var := new_var().
Hypothesis triple1: ∀x y: Z,
{{ [[X]] == x AND [[Y]] == y }}
TEMP ::= X
{{ [[Y]] == y AND [[TEMP]] == x }}.
Hypothesis triple2: ∀x y: Z,
{{ [[Y]] == y AND [[TEMP]] == x }}
X ::= Y
{{ [[X]] == y AND [[TEMP]] == x }}.
Hypothesis triple3: ∀x y: Z,
{{ [[X]] == y AND [[TEMP]] == x }}
Y ::= TEMP
{{ [[X]] == y AND [[Y]] == x }}.
Fact swaping_correct:
∀x y: Z,
{{ [[X]] == x AND [[Y]] == y }}
TEMP ::= X;;
X ::= Y;;
Y ::= TEMP
{{ [[X]] == y AND [[Y]] == x }}.
Proof.
intros.
apply hoare_seq with ([[Y]] == y AND [[TEMP]] == x)%assert.
apply triple1.
apply hoare_seq with ([[X]] == y AND [[TEMP]] == x)%assert.
apply triple2.
apply triple3.
Qed.
If you go through this proof above, you may feel that it is in a backward
direction—-we reduced our proof goal step by step and achieve our assuptions
in the end. In fact, you can also write forward proofs in Coq.
Fact swaping_correct_again:
∀x y: Z,
{{ [[X]] == x AND [[Y]] == y }}
TEMP ::= X;;
X ::= Y;;
Y ::= TEMP
{{ [[X]] == y AND [[Y]] == x }}.
Proof.
intros.
pose proof triple1 x y.
pose proof triple2 x y.
pose proof triple3 x y.
pose proof hoare_seq
([[Y]] == y AND [[TEMP]] == x)%assert
([[X]] == y AND [[TEMP]] == x)%assert
([[X]] == y AND [[Y]] == x)%assert
(X ::= Y)
(Y ::= TEMP)
H0
H1.
∀x y: Z,
{{ [[X]] == x AND [[Y]] == y }}
TEMP ::= X;;
X ::= Y;;
Y ::= TEMP
{{ [[X]] == y AND [[Y]] == x }}.
Proof.
intros.
pose proof triple1 x y.
pose proof triple2 x y.
pose proof triple3 x y.
pose proof hoare_seq
([[Y]] == y AND [[TEMP]] == x)%assert
([[X]] == y AND [[TEMP]] == x)%assert
([[X]] == y AND [[Y]] == x)%assert
(X ::= Y)
(Y ::= TEMP)
H0
H1.
When you are able to derive a new conclusion from assumptions, the
"pose proof" tactic can be used to put that conclusion above the line.
clear H0 H1.
At this point, if you feel that some assumptions are redundant above the
line, you can use clear to remove them.
pose proof hoare_seq _ ([[Y]] == y AND [[TEMP]] == x)%assert _ _ _ H H2.
You do not need to type all arguments manually. Use underscore _ if Coq
can infer that.
exact H0.
In the end, what we want to prove is already proved. We use "exact".
Qed.
End swapping.
End swapping.
Before we go through further examples, I wanna remind you that you may
choose your editor preference in menu (Edit => Preferences => Editor). In those
choices, "auto indentation" (自动缩进) and "auto completion" (自动填充) are
very useful.
If you prefer a monospaced font, just choose "monospace". If you prefer to
read those Chinese charecters inside comments, you can choose something like
"YouYuan" or "KaiTi"
Example: Simple Conditionals
Module if_minus_dec.
Import Axiomatic_semantics_1.
Local Instance A: var := new_var().
Local Instance B: var := new_var().
Local Instance C: var := new_var().
Hypothesis triple1:
{{ True AND [[A ≤ B]] }}
C ::= B - A
{{ 0 ≤ [[C]] AND ( [[C]] + [[A]] == [[B]] OR [[C]] + [[B]] == [[A]] ) }}.
Hypothesis triple2:
{{ True AND NOT [[A ≤ B]] }}
C ::= A - B
{{ 0 ≤ [[C]] AND ( [[C]] + [[A]] == [[B]] OR [[C]] + [[B]] == [[A]] ) }}.
Fact if_minus_dec_correct:
{{ True }}
If A ≤ B
Then C ::= B - A
Else C ::= A - B
EndIf
{{ 0 ≤ [[C]] AND ( [[C]] + [[A]] == [[B]] OR [[C]] + [[B]] == [[A]] ) }}.
Proof.
apply hoare_if.
+ apply triple1.
+ apply triple2.
Qed.
End if_minus_dec.
Module counter_example.
Import Axiomatic_semantics_1.
Local Instance X: var := new_var().
Local Instance Y: var := new_var().
Axiom hoare_if_first_try : ∀P Q b c1 c2,
{{P}} c1 {{Q}} →
{{P}} c2 {{Q}} →
{{P}} If b Then c1 Else c2 EndIf {{Q}}.
Fact sample_program_correct_fail:
{{ True }}
If X == 0
Then Y ::= 2
Else Y ::= X + 1
EndIf
{{ [[X]] ≤ [[Y]] }}.
Proof.
apply hoare_if_first_try.
Abort.
Hypothesis triple1:
{{ True AND [[X == 0]] }}
Y ::= 2
{{ [[X]] ≤ [[Y]] }}.
Hypothesis triple2:
{{ True AND NOT [[X == 0]] }}
Y ::= X + 1
{{ [[X]] ≤ [[Y]] }}.
Fact sample_program_correct_:
{{ True }}
If X == 0
Then Y ::= 2
Else Y ::= X + 1
EndIf
{{ [[X]] ≤ [[Y]] }}.
Proof.
apply hoare_if.
+ apply triple1.
+ apply triple2.
Qed.
End counter_example.
Module reduce_to_zero.
Import Axiomatic_semantics_1.
Local Instance X: var := new_var().
Hypothesis triple1:
{{ True AND [[!(X == 0)]] }}
X ::= X - 1
{{ True }}.
Fact reduce_to_zero_correct:
{{ True }}
While !(X == 0) Do
X ::= X - 1
EndWhile
{{ True AND NOT [[ !(X == 0) ]] }}.
Proof.
apply hoare_while.
apply triple1.
Qed.
End reduce_to_zero.
Module div_mod_dec.
Import Axiomatic_semantics_1.
Local Instance X: var := new_var().
Local Instance Y: var := new_var().
Hypothesis triple1: ∀m: Z,
{{ 0 ≤ m }}
X ::= m
{{ [[X]] == m AND 0 ≤ [[X]] }}.
Hypothesis triple2: ∀m n: Z,
{{ [[X]] == m AND 0 ≤ [[X]] }}
Y ::= 0
{{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] }}.
Hypothesis triple3: ∀m n: Z,
{{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[n ≤ X]] }}
X ::= X - n
{{ n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]] }}.
Hypothesis triple4: ∀m n: Z,
{{ n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]] }}
Y ::= Y + 1
{{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] }}.
Fact div_mod_dec_correct: ∀m n: Z,
{{ 0 ≤ m }}
X ::= m;;
Y ::= 0;;
While n ≤ X Do
X ::= X - n;;
Y ::= Y + 1
EndWhile
{{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] }}.
Proof.
intros.
apply hoare_seq with ([[X]] == m AND 0 ≤ [[X]])%assert. apply triple1.
apply hoare_seq with (n * [[Y]] + [[X]] == m AND 0 ≤ [[X]])%assert. apply triple2.
apply hoare_while.
apply hoare_seq with (n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]])%assert.
apply triple3.
apply triple4.
Qed.
Fact div_mod_dec_correct_again: ∀m n: Z,
{{ 0 ≤ m }}
X ::= m;;
Y ::= 0;;
While n ≤ X Do
X ::= X - n;;
Y ::= Y + 1
EndWhile
{{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] }}.
Proof.
intros.
pose proof triple1 m.
pose proof triple2 m n.
pose proof triple3 m n.
pose proof triple4 m n.
pose proof hoare_seq _ _ _ _ _ H1 H2.
clear H1 H2.
pose proof hoare_while _ (n ≤ X) _ H3.
clear H3.
pose proof hoare_seq _ _ _ _ _ H0 H1.
pose proof hoare_seq _ _ _ _ _ H H2.
exact H3.
Qed.
End div_mod_dec.
Till now, we have learnt how to formalize some Hoare logic proofs in Coq.
But you might have noticed two tiny problems. 1. We have proved nothing for
assignment commands. We only assume that some Hoare triples about assignment
commands are true. Coq forces us to distinguish which parts really get proved
and which parts are actually hypotheses. 2. Our postconditions look not nice.
For example, in div_mod_correct we have to write
We introduce several more axioms in response to this concern.
We clear see a common pattern when we try to write postconditions for
assignment commands with form X ::= E. Each of these postconditions has two
parts (1) the original value of X satisfies the precondition; (2) the current
value of X can be calculated by E using the original value of X.
The original value of X plays a very important role here! But, we cannot
always refer to the original value directly. Here is an example:
What is the best postcondition for the following command?
The best postcondition is:
In our assertion language, we have already overloaded the operator + and
used it in two different scenarios.
For example,
In logic study's terminology, a language that talks about other languages is
called metalanguage (元语言). A language that is described by another language
is called object language (对象语言).
So, our simple programming language is the object language when comparing with
our assertion language (the metalanguage). In the sample assertion above, we
can also say that those two "+"s belong to the object language and the
metalanguage respectively. Similarly, we have object language's ≤ and !
(not) and metalanguage's ≤ and NOT.
Suppose E is an integer-type expression of the programming language,
We can also apply symbolic substitution on a boolean expression.
Specifically, for a boolean-type expression B and an integer-type expression
E0, we use
We can also define symbolic substitution in assertions. We use
The following axiom describes the behavior of assignment commands.
{{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] }}
instead of
{{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[X]] < n }}.
Coq forces us to strictly follow axiom statements. But we really hope that we
can at least replace an assertion with an equivalent one.
Assignment rule (forward)
{{ n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]] AND [[X]] < n }}
Y ::= 0
{{ ??? }}
Y ::= 0
{{ ??? }}
{{ EXISTS y, n * y + [[X]] + n == m AND
0 ≤ [[X]] AND [[X]] < n AND [[Y]] == 0 }}
This example gives us a hint—-we do not need to refer to the old value
directly; we can talk about it using the existential quantifier. In general,
given a precondition P, a program variable X and a program expression E,
we can write the following postcondition informally:
0 ≤ [[X]] AND [[X]] < n AND [[Y]] == 0 }}
There exists an old value x of program variable X, such that (1) the precondition P would hold if the value of X would be x (2) the value of X is result of evaluating the expression E if treating all occurrences of X in E as x.
Object language and metalanguage
- + is an operator in our simple programming language, representing the sum
- + is also a symbol of our assertion language itself, representing the sum
[[X + Y ≤ Z]] AND 0 ≤ [[X]] + [[Y]]
has two "+"s involved. The former one is a symbol inside the programming
language's expressions and the latter one is a symbol for describing values of
programming language's expressions.
Symbolic substitution in program expressions (object language)
E [X ⟼ E0]
represents the result of replacing every occurence of program variable X with
program expression E0 in E. This result is still an integer-type
expression.
- (X * Y) [ X ⟼ 1] is 1 * Y , not Y.
- (X + 1) [ X ⟼ 1] is 1 + 1 , not 2.
B [X ⟼ E0]
to represent the result of replacing every occurence of program variable X
with E0 in B, e.g.
(!(X ≤ Y))[X ⟼ 0]
is ! (0 ≤ Y) .
Symbolic substitution in assertions (metalanguage)
P [X ⟼ E0]
to represent the result of replacing every occurence of program variable X
with program expression E0 in assertion P. For example,
([[X + Y ≤ Z]] AND 0 ≤ [[X]] + [[Y]]) [X ⟼ x]
([[X + Y ≤ Z]] AND 0 ≤ [[X]] + [[Y]]) [X ⟼ 0]
are
([[X + Y ≤ Z]] AND 0 ≤ [[X]] + [[Y]]) [X ⟼ 0]
[[x + Y ≤ Z]] AND 0 ≤ [[x]] + [[Y]].
[[0 + Y ≤ Z]] AND 0 ≤ [[0]] + [[Y]].
In other words, the effect of symbolic substitution on an assertion P is
applying object language substitution on those program expressions mentioned in
P.
[[0 + Y ≤ Z]] AND 0 ≤ [[0]] + [[Y]].
Proof rule
Axiom hoare_asgn_fwd : ∀P `(X: var) E,
{{ P }}
X ::= E
{{ EXISTS x, P [X ⟼ x] AND
[[X]] == [[ E [X ⟼ x] ]] }}.
{{ P }}
X ::= E
{{ EXISTS x, P [X ⟼ x] AND
[[X]] == [[ E [X ⟼ x] ]] }}.
Axiom hoare_consequence : ∀(P P' Q Q' : Assertion) c,
P ⊢ P' →
{{P'}} c {{Q'}} →
Q' ⊢ Q →
{{P}} c {{Q}}.
Module Axiomatic_semantics.
Axiom hoare_seq : ∀(P Q R: Assertion) (c1 c2: com),
{{P}} c1 {{Q}} →
{{Q}} c2 {{R}} →
{{P}} c1;;c2 {{R}}.
Axiom hoare_skip : ∀P,
{{P}} Skip {{P}}.
Axiom hoare_if : ∀P Q b c1 c2,
{{ P AND [[b]] }} c1 {{ Q }} →
{{ P AND NOT [[b]] }} c2 {{ Q }} →
{{ P }} If b Then c1 Else c2 EndIf {{ Q }}.
Axiom hoare_while : ∀P b c,
{{ P AND [[b]] }} c {{P}} →
{{P}} While b Do c EndWhile {{ P AND NOT [[b]] }}.
Axiom hoare_asgn_fwd : ∀P `(X: var) E,
{{ P }}
X ::= E
{{ EXISTS x, P [X ⟼ x] AND
[[X]] == [[ E [X ⟼ x] ]] }}.
Axiom hoare_consequence : ∀(P P' Q Q' : Assertion) c,
P ⊢ P' →
{{P'}} c {{Q'}} →
Q' ⊢ Q →
{{P}} c {{Q}}.
End Axiomatic_semantics.
(* Mon Mar 11 15:46:00 UTC 2019 *)