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

In the last lecture, we have learned how to prove a program correct by Hoare logic and how to use apply in Coq to formalize those proofs. We have shown the following swapping program's 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.

Example: Swapping


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.
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.
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 [[AB]] }}
       C ::= B - A
       {{ 0 ≤ [[C]] AND ( [[C]] + [[A]] == [[B]] OR [[C]] + [[B]] == [[A]] ) }}.

Hypothesis triple2:
       {{ True AND NOT [[AB]] }}
       C ::= A - B
       {{ 0 ≤ [[C]] AND ( [[C]] + [[A]] == [[B]] OR [[C]] + [[B]] == [[A]] ) }}.

Fact if_minus_dec_correct:
       {{ True }}
       If AB
       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.

Example: Our Counterexample in the Last Lecture


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.

Example: Reduce to Zero


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.

Example: Division


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 [[nX]] }}
       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 nX Do
         X ::= X - n;;
         Y ::= Y + 1
       EndWhile
       {{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[nX]] }}.
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 nX Do
         X ::= X - n;;
         Y ::= Y + 1
       EndWhile
       {{ n * [[Y]] + [[X]] == m AND 0 ≤ [[X]] AND NOT [[nX]] }}.
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 _ (nX) _ 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
    {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.
We introduce several more axioms in response to this concern.

Assignment rule (forward)

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?
       {n * [[Y]] + [[X]] + n == m AND 0 ≤ [[X]AND [[X]] < n }}
       Y ::= 0
       {{ ??? }}
The best postcondition is:
       {EXISTS yn * 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:
       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

In our assertion language, we have already overloaded the operator + and used it in two different scenarios.
  • + is an operator in our simple programming language, representing the sum
of two integer expressions;
  • + is also a symbol of our assertion language itself, representing the sum
of two values.
For example,
        [[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.
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.

Symbolic substitution in program expressions (object language)

Suppose E is an integer-type expression of the programming 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.
Remark. 1 * Y and Y are two different program expressions although their values are always the same.
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
    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)

We can also define symbolic substitution in assertions. We use
    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]].
        [[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.

Proof rule

The following axiom describes the behavior of assignment commands.
Axiom hoare_asgn_fwd : P `(X: var) E,
  {{ P }}
  X ::= E
  {{ EXISTS x, P [Xx] AND
               [[X]] == [[ E [Xx] ]] }}.

Consequence rule


Axiom hoare_consequence : (P P' Q Q' : Assertion) c,
  PP'
  {{P'}} c {{Q'}} →
  Q'Q
  {{P}} c {{Q}}.

Summary: axiomatic semantics


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

Axiom hoare_consequence : (P P' Q Q' : Assertion) c,
  PP'
  {{P'}} c {{Q'}} →
  Q'Q
  {{P}} c {{Q}}.

End Axiomatic_semantics.

(* Mon Mar 11 15:46:00 UTC 2019 *)