Lecture notes 20190312
Hoare Logic 4
Remark. Some material in this lecture is from << Software Foundation >>
volume 2.
Require Import PL.Imp3.
Assignment rule (backward)
Axiom hoare_asgn_bwd : ∀P `(X: var) E,
{{ P [ X ⟼ E] }} X ::= E {{ P }}.
{{ P [ X ⟼ E] }} X ::= E {{ P }}.
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]] }}.
Having one between the following two assignment rules is enough.
Axiom hoare_asgn_fwd : ∀P `(X: var) E,
{{ P }}
X ::= E
{{ EXISTS x, P [X ⟼ x] AND
[[X]] == [[ E [X ⟼ x] ]] }}.
Axiom hoare_asgn_bwd : ∀P `(X: var) E,
{{ P [ X ⟼ E] }} X ::= E {{ P }}.
Axiom hoare_consequence : ∀(P P' Q Q' : Assertion) c,
P ⊢ P' →
{{P'}} c {{Q'}} →
Q' ⊢ Q →
{{P}} c {{Q}}.
End Axiomatic_semantics.
Module div_mod_dec_again.
Import Axiomatic_semantics.
{{ P }}
X ::= E
{{ EXISTS x, P [X ⟼ x] AND
[[X]] == [[ E [X ⟼ x] ]] }}.
Axiom hoare_asgn_bwd : ∀P `(X: var) E,
{{ P [ X ⟼ E] }} X ::= E {{ P }}.
Axiom hoare_consequence : ∀(P P' Q Q' : Assertion) c,
P ⊢ P' →
{{P'}} c {{Q'}} →
Q' ⊢ Q →
{{P}} c {{Q}}.
End Axiomatic_semantics.
Module div_mod_dec_again.
Import Axiomatic_semantics.
Coq proof time! Now, we are able to prove a nicer Hoare triple with simpler
hypothese.
Local Instance X: var := new_var().
Local Instance Y: var := new_var().
Hypothesis derivation1: ∀m n: Z,
0 ≤ m AND [[X]] == m AND [[Y]] == 0 ⊢
n * [[Y]] + [[X]] == m AND 0 ≤ [[X]].
Hypothesis derivation2: ∀m n: Z,
EXISTS z, n * [[Y]] + z == m AND 0 ≤ z AND n ≤ z AND [[X]] == z - n ⊢
n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]].
Hypothesis derivation3: ∀m n: Z,
EXISTS z, n * z + [[X]] + n == m AND 0 ≤ [[X]] AND [[Y]] == z + 1 ⊢
n * [[Y]] + [[X]] == m AND 0 ≤ [[X]].
Hypothesis derivation4: ∀m n: Z,
n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] ⊢
n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[X]] < n.
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 [[X]] < n }}.
Proof.
intros.
Local Instance Y: var := new_var().
Hypothesis derivation1: ∀m n: Z,
0 ≤ m AND [[X]] == m AND [[Y]] == 0 ⊢
n * [[Y]] + [[X]] == m AND 0 ≤ [[X]].
Hypothesis derivation2: ∀m n: Z,
EXISTS z, n * [[Y]] + z == m AND 0 ≤ z AND n ≤ z AND [[X]] == z - n ⊢
n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]].
Hypothesis derivation3: ∀m n: Z,
EXISTS z, n * z + [[X]] + n == m AND 0 ≤ [[X]] AND [[Y]] == z + 1 ⊢
n * [[Y]] + [[X]] == m AND 0 ≤ [[X]].
Hypothesis derivation4: ∀m n: Z,
n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] ⊢
n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[X]] < n.
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 [[X]] < n }}.
Proof.
intros.
Originally, if we want to use apply to prove this Hoare triple in the
backward direction, we have to feed it an argument, indicating what the middle
condition Q in hoare_seq represents. But if we use eapply instead of
apply, we do not need to provide that argument. Mainly, eapply hoare_seq
says, we will apply this proof rule hoare_seq without knowing what Q is,
and we will know what that Q should be later.
eapply hoare_seq.
As you can see, the unknown argument is marked as ?Q which appear both in
the first proof goal and the second proof goal. Now, we use hoare_asgn_fwd to
solve the first proof goal. It will instantiate ?Q.
apply hoare_asgn_fwd.
The precondition of this current subgoal is the assertion generated by our
previous tactic. The substitution symbol and the existential quantifier make
this assertion really complicated. Our library PL.Imp2 provided the following
two tactics to simplify it. You can freely use it in your assignments.
assert_subst.
assert_simpl.
eapply hoare_seq.
apply hoare_asgn_fwd.
assert_subst.
assert_simpl.
apply hoare_consequence with
(n * [[Y]] + [[X]] == m AND 0 ≤ [[X]])%assert
(n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[ n ≤ X ]] )%assert.
apply (derivation1 m n).
apply hoare_while.
eapply hoare_seq.
apply hoare_asgn_fwd.
assert_subst.
assert_simpl.
eapply hoare_consequence.
apply derivation2.
apply hoare_asgn_fwd.
assert_subst.
assert_simpl.
apply derivation3.
apply derivation4.
Qed.
assert_simpl.
eapply hoare_seq.
apply hoare_asgn_fwd.
assert_subst.
assert_simpl.
apply hoare_consequence with
(n * [[Y]] + [[X]] == m AND 0 ≤ [[X]])%assert
(n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[ n ≤ X ]] )%assert.
apply (derivation1 m n).
apply hoare_while.
eapply hoare_seq.
apply hoare_asgn_fwd.
assert_subst.
assert_simpl.
eapply hoare_consequence.
apply derivation2.
apply hoare_asgn_fwd.
assert_subst.
assert_simpl.
apply derivation3.
apply derivation4.
Qed.
Now we try to prove the same Hoare triple again with forward proof style.
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 [[X]] < n }}.
Proof.
intros.
pose proof hoare_asgn_fwd
(n * [[Y]] + [[X]] == m AND
0 ≤ [[X]] AND [[n ≤ X]])%assert
X (X - n).
{{ 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 [[X]] < n }}.
Proof.
intros.
pose proof hoare_asgn_fwd
(n * [[Y]] + [[X]] == m AND
0 ≤ [[X]] AND [[n ≤ X]])%assert
X (X - n).
These two tactics assert_subst and assert_simpl can also simplify
assertions in assumptions
assert_subst in H.
assert_simpl in H.
pose proof hoare_asgn_fwd
(n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]])%assert
Y (Y + 1).
assert_subst in H0.
assert_simpl in H0.
pose proof hoare_consequence _ _ _ _ _
(derivation2 m n) H0 (derivation3 m n).
pose proof hoare_seq _ _ _ _ _ H H1.
clear H H0 H1.
assert_simpl in H.
pose proof hoare_asgn_fwd
(n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]])%assert
Y (Y + 1).
assert_subst in H0.
assert_simpl in H0.
pose proof hoare_consequence _ _ _ _ _
(derivation2 m n) H0 (derivation3 m n).
pose proof hoare_seq _ _ _ _ _ H H1.
clear H H0 H1.
It is unfortunate that we cannot achieve a Hoare triple for the while loop
here using H2 and hoare_while because the assertion that loop condition is
true
[[n ≤ X]]
has been simplified into n ≤ [[X]] . Thus, we assert the triple that we
want to prove.
assert ({{n * [[Y]] + [[X]] == m AND 0 ≤ [[X]}}} While n ≤ X Do (X ::= X - n);; Y ::= Y + 1 EndWhile {{n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]}}}).
After assert, we first prove the asserted triple.
apply hoare_while.
assert_simpl.
exact H2.
assert_simpl.
exact H2.
We then prove the original proof goal with an extra assumption—-the
asserted triple H.
clear H2.
pose proof hoare_asgn_fwd
(0 ≤ m)%assert
X
m.
assert_subst in H0.
assert_simpl in H0.
pose proof hoare_asgn_fwd
(0 ≤ m AND [[X]] == m)%assert
Y
0.
assert_subst in H1.
assert_simpl in H1.
pose proof hoare_consequence _ _ _ _ _
(derivation1 m n) H (derivation4 m n).
pose proof hoare_seq _ _ _ _ _ H1 H2.
pose proof hoare_seq _ _ _ _ _ H0 H3.
exact H4.
Qed.
End div_mod_dec_again.
pose proof hoare_asgn_fwd
(0 ≤ m)%assert
X
m.
assert_subst in H0.
assert_simpl in H0.
pose proof hoare_asgn_fwd
(0 ≤ m AND [[X]] == m)%assert
Y
0.
assert_subst in H1.
assert_simpl in H1.
pose proof hoare_consequence _ _ _ _ _
(derivation1 m n) H (derivation4 m n).
pose proof hoare_seq _ _ _ _ _ H1 H2.
pose proof hoare_seq _ _ _ _ _ H0 H3.
exact H4.
Qed.
End div_mod_dec_again.
Decorated program as informal Hoare logic proof
/* 0 ≤ m */
X ::= m;;
Y ::= 0;;
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] */
While n ≤ X Do
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[n ≤ X]] */
X ::= X - n;;
Y ::= Y + 1
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] */
EndWhile
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] */
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[X]] < n */.
X ::= m;;
Y ::= 0;;
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] */
While n ≤ X Do
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[n ≤ X]] */
X ::= X - n;;
Y ::= Y + 1
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] */
EndWhile
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] */
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[X]] < n */.
/* 0 ≤ m */
X ::= m;;
/* EXISTS x, 0 ≤ m AND [[X]] == m */
/* 0 ≤ m AND [[X]] == m */
Y ::= 0;;
/* EXISTS y, 0 ≤ m AND [[X]] == m AND [[Y]] == 0 */
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] */
While n ≤ X Do
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[n ≤ X]] */
X ::= X - n;;
/* EXISTS x, n * [[Y]] + [[x]] == m AND
0 ≤ [[x]] AND [[n ≤ x]] AND [[X]] == [[x - n]] */
/* EXISTS x, n * [[Y]] + x == m AND
0 ≤ x AND n ≤ x AND [[X]] == x - n */
/* n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]] */
Y ::= Y + 1
/* EXISTS y, n * [[y]] + [[X]] + n == m AND
0 ≤ [[X]] AND [[Y]] == [[y + 1]] */
/* EXISTS y, n * y + [[X]] + n == m AND
0 ≤ [[X]] AND [[Y]] == y + 1 */
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] */
EndWhile
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] */
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[X]] < n */.
X ::= m;;
/* EXISTS x, 0 ≤ m AND [[X]] == m */
/* 0 ≤ m AND [[X]] == m */
Y ::= 0;;
/* EXISTS y, 0 ≤ m AND [[X]] == m AND [[Y]] == 0 */
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] */
While n ≤ X Do
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[n ≤ X]] */
X ::= X - n;;
/* EXISTS x, n * [[Y]] + [[x]] == m AND
0 ≤ [[x]] AND [[n ≤ x]] AND [[X]] == [[x - n]] */
/* EXISTS x, n * [[Y]] + x == m AND
0 ≤ x AND n ≤ x AND [[X]] == x - n */
/* n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]] */
Y ::= Y + 1
/* EXISTS y, n * [[y]] + [[X]] + n == m AND
0 ≤ [[X]] AND [[Y]] == [[y + 1]] */
/* EXISTS y, n * y + [[X]] + n == m AND
0 ≤ [[X]] AND [[Y]] == y + 1 */
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] */
EndWhile
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[n ≤ X]] */
/* n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND [[X]] < n */.
(* Mon Mar 11 15:46:01 UTC 2019 *)