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)

When C. A. R. Hoare first proposed Hoare logic for program correctness proof in 1960s, the assignment rule is not in the forward direction; it was in the backward direction. Robert W. Floyd proposed forward assignment rule later. Due to this reason, people also use the nomenclature "Floyd-Hoare" logic sometimes. (Another reason is that the original ideas of Hoare logic were seeded by Floyd's work of a similar system for flowcharts.)
Axiom hoare_asgn_bwd : P `(X: var) E,
  {{ P [ XE] }} X ::= E {{ P }}.

Program correctness proof in Coq


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 [Xx] AND
               [[X]] == [[ E [Xx] ]] }}.

Axiom hoare_asgn_bwd : P `(X: var) E,
  {{ P [ XE] }} X ::= E {{ P }}.

Axiom hoare_consequence : (P P' Q Q' : Assertion) c,
  PP'
  {{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 nz 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 [[nX]] ⊢
  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 nX 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 [[ nX ]] )%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 nX 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 [[nX]])%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.
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 nX Do (X ::= X - n);; Y ::= Y + 1 EndWhile {{n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[nX]}}}).
After assert, we first prove the asserted triple.
  apply hoare_while.
  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.

Decorated program as informal Hoare logic proof

The beauty of Hoare Logic is that it is compositional: the structure of proofs exactly follows the structure of programs. This suggests that we can record the essential ideas of a proof by "decorating" a program with appropriate assertions on each of its commands.
In <<software foundation>>, such informal proofs are called decorated programs. In other text books or programming language literature, they are also called annotated programs or commented programs.
Here are two sample decorated programs.
Sample 1
  /* 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 */.
Sample 2
  /* 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 xn * [[Y]] + [[x]] == m AND
         0 ≤ [[x]AND [[n ≤ x]AND [[X]] == [[x - n]] */
    /* EXISTS xn * [[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 yn * [[y]] + [[X]] + n == m AND
         0 ≤ [[X]AND [[Y]] == [[y + 1]] */
    /* EXISTS yn * 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 *)