HoareHoare Logic, Part I
Our goal in this chapter is to carry out some simple examples of
program verification -- i.e., to use the precise definition of
Imp to prove formally that particular programs satisfy particular
specifications of their behavior.
We'll develop a reasoning system called Floyd-Hoare Logic --
often shortened to just Hoare Logic -- in which each of the
syntactic constructs of Imp is equipped with a generic "proof
rule" that can be used to reason compositionally about the
correctness of programs involving this construct.
Hoare Logic combines two beautiful ideas: a natural way of writing
down specifications of programs, and a structured proof
technique for proving that programs are correct with respect to
such specifications -- where by "structured" we mean that the
structure of proofs directly mirrors the structure of the programs
that they are about.
Assertions
Definition Assertion := state → Prop.
For example,
- fun st ⇒ st X = 3 holds for states st in which value of X
is 3,
- fun st ⇒ True hold for all states, and
- fun st ⇒ False holds for no states.
Paraphrase the following assertions in English (i.e., say
which states satisfy them)
(1) fun st ⇒ st X ≤ st Y
(2) fun st ⇒ st X = 3 ∨ st X ≤ st Y
(3) fun st ⇒ st Z × st Z ≤ st X ∧
¬ (((S (st Z)) × (S (st Z))) ≤ st X)
We'll use Coq's notation features to make assertions look as much like informal math as possible.
fun st ⇒ st X = m we'll usually write just
X = m
Definition assert_implies (P Q : Assertion) : Prop :=
∀ st, P st → Q st.
Notation "P ->> Q" := (assert_implies P Q)
(at level 80) : hoare_spec_scope.
∀ st, P st → Q st.
Notation "P ->> Q" := (assert_implies P Q)
(at level 80) : hoare_spec_scope.
We'll also want the "iff" variant of implication between
assertions:
Notation "P <<->> Q" := (P ->> Q ∧ Q ->> P)
(at level 80) : hoare_spec_scope.
(at level 80) : hoare_spec_scope.
Hoare Triples, Informally
{{P}} c {{Q}} This means:
- If command c begins execution in a state satisfying assertion P,
- and if c eventually terminates in some final state,
- then that final state will satisfy the assertion Q.
For example,
- {{X = 0}} X := X + 1 {{X = 1}} is a valid Hoare triple,
stating that command X := X + 1 will transform a state in
which X = 0 to a state in which X = 1.
- ∀ m, {{X = m}} X := X + 1 {{X = m + 1}} is a proposition stating that the Hoare triple {{X = m}} X := X + 1 {{X = m + 1}} is valid for any choice of m. Note that m in the two assertions and the command in the middle is a reference to the Coq variable m, which is bound outside the Hoare triple.
Paraphrase the following in English.
1) {{True}} c {{X = 5}}
2) ∀ m, {{X = m}} c {{X = m + 5)}}
3) {{X ≤ Y}} c {{Y ≤ X}}
4) {{True}} c {{False}}
5) ∀ m,
{{X = m}}
c
{{Y = real_fact m}}
6) ∀ m,
{{X = m}}
c
{{(Z × Z) ≤ m ∧ ¬(((S Z) × (S Z)) ≤ m)}}
1) {{True}} c {{X = 5}}
2) ∀ m, {{X = m}} c {{X = m + 5)}}
3) {{X ≤ Y}} c {{Y ≤ X}}
4) {{True}} c {{False}}
5) ∀ m,
{{X = m}}
c
{{Y = real_fact m}}
6) ∀ m,
{{X = m}}
c
{{(Z × Z) ≤ m ∧ ¬(((S Z) × (S Z)) ≤ m)}}
Is the following Hoare triple valid -- i.e., is the
claimed relation between P, c, and Q true?
{{True}} X := 5 {{X = 5}}
(1) Yes
(2) No
{{True}} X := 5 {{X = 5}}
What about this one?
{{X = 2}} X := X + 1 {{X = 3}}
(1) Yes
(2) No
{{X = 2}} X := X + 1 {{X = 3}}
What about this one?
{{True}} X := 5; Y := 0 {{X = 5}}
(1) Yes
(2) No
{{True}} X := 5; Y := 0 {{X = 5}}
What about this one?
{{X = 2 ∧ X = 3}} X := 5 {{X = 0}}
(1) Yes
(2) No
{{X = 2 ∧ X = 3}} X := 5 {{X = 0}}
What about this one?
{{True}} skip {{False}}
(1) Yes
(2) No
{{True}} skip {{False}}
What about this one?
{{False}} skip {{True}}
(1) Yes
(2) No
{{False}} skip {{True}}
What about this one?
{{True}} while true do skip end {{False}}
(1) Yes
(2) No
{{True}} while true do skip end {{False}}
This one?
{{X = 0}}
while X = 0 do X := X + 1 end
{{X = 1}}
(1) Yes
(2) No
{{X = 0}}
while X = 0 do X := X + 1 end
{{X = 1}}
This one?
{{X = 1}}
while X ≠ 0 do X := X + 1 end
{{X = 100}}
(1) Yes
(2) No
{{X = 1}}
while X ≠ 0 do X := X + 1 end
{{X = 100}}
Definition valid_hoare_triple
(P : Assertion) (c : com) (Q : Assertion) : Prop :=
∀ st st',
st =[ c ]=> st' →
P st →
Q st'.
Notation "{{ P }} c {{ Q }}" :=
(valid_hoare_triple P c Q)
(at level 90, c custom com at level 99)
: hoare_spec_scope.
Check ({{True}} X := 0 {{True}}).
(P : Assertion) (c : com) (Q : Assertion) : Prop :=
∀ st st',
st =[ c ]=> st' →
P st →
Q st'.
Notation "{{ P }} c {{ Q }}" :=
(valid_hoare_triple P c Q)
(at level 90, c custom com at level 99)
: hoare_spec_scope.
Check ({{True}} X := 0 {{True}}).
Proof Rules
- introduce one "proof rule" for each Imp syntactic form
- plus a couple of "structural rules" that help glue proofs together
- prove these rules correct in terms of the definition of valid_hoare_triple
- prove programs correct using these proof rules, without ever unfolding the definition of valid_hoare_triple
Skip
(hoare_skip) | |
{{ P }} skip {{ P }} |
Theorem hoare_skip : ∀ P,
{{P}} skip {{P}}.
{{P}} skip {{P}}.
Proof.
intros P st st' H HP. inversion H; subst. assumption.
Qed.
intros P st st' H HP. inversion H; subst. assumption.
Qed.
Sequencing
{{ P }} c1 {{ Q }} | |
{{ Q }} c2 {{ R }} | (hoare_seq) |
{{ P }} c1;c2 {{ R }} |
Theorem hoare_seq : ∀ P Q R c1 c2,
{{Q}} c2 {{R}} →
{{P}} c1 {{Q}} →
{{P}} c1; c2 {{R}}.
{{Q}} c2 {{R}} →
{{P}} c1 {{Q}} →
{{P}} c1; c2 {{R}}.
Proof.
unfold valid_hoare_triple.
intros P Q R c1 c2 H1 H2 st st' H12 Pre.
inversion H12; subst.
eauto.
Qed.
unfold valid_hoare_triple.
intros P Q R c1 c2 H1 H2 st st' H12 Pre.
inversion H12; subst.
eauto.
Qed.
Assignment
{{ ??? }} X := Y {{ X = 1 }} One natural possibility is:
{{ Y = 1 }} X := Y {{ X = 1 }}
How about this one?
{{ ??? }} X := X + Y {{ X = 1 }} Replace X with X + Y:
{{ X + Y = 1 }} X := X + Y {{ X = 1 }} This works because "equals 1" holding of X is guaranteed by the property "equals 1" holding of whatever is being assigned to X.
{{ ??? }} X := a {{ Q }} The precondition would then be Q, but with any occurrences of X in it replaced by a.
Let's introduce a notation for this idea of replacing occurrences: Define Q [X ⊢> a] to mean "Q where a is substituted in place of X".
{{ Q [X ⊢> a] }} X := a {{ Q }} One way of reading this rule is: If you want statement X := a to terminate in a state that satisfies assertion Q, then it suffices to start in a state that also satisfies Q, except where a is substituted for every occurrence of X.
{{ (X ≤ 5) [X ⊢> X + 1] }} (that is, X + 1 ≤ 5)
X := X + 1
{{ X ≤ 5 }}
{{ (X = 3) [X ⊢> 3] }} (that is, 3 = 3)
X := 3
{{ X = 3 }}
{{ (0 ≤ X ∧ X ≤ 5) [X ⊢> 3] (that is, 0 ≤ 3 ∧ 3 ≤ 5)
X := 3
{{ 0 ≤ X ∧ X ≤ 5 }}
Definition assertion_sub X a (P:Assertion) : Assertion :=
fun (st : state) ⇒
P (X !-> aeval st a ; st).
Notation "P [ X ⊢> a ]" := (assertion_sub X a P)
(at level 10, X at next level, a custom com) : hoare_spec_scope.
fun (st : state) ⇒
P (X !-> aeval st a ; st).
Notation "P [ X ⊢> a ]" := (assertion_sub X a P)
(at level 10, X at next level, a custom com) : hoare_spec_scope.
That is, P [X ⊢> a] stands for an assertion -- let's call it
P' -- that is just like P except that, wherever P looks up
the variable X in the current state, P' instead uses the value
of the expression a.
Now, using the substitution operation we've just defined, we can
give the precise proof rule for assignment:
We can prove formally that this rule is indeed valid.
(hoare_asgn) | |
{{Q [X ⊢> a]}} X := a {{Q}} |
Theorem hoare_asgn : ∀ Q X a,
{{Q [X ⊢> a]}} X := a {{Q}}.
{{Q [X ⊢> a]}} X := a {{Q}}.
Proof.
unfold valid_hoare_triple.
intros Q X a st st' HE HQ.
inversion HE. subst.
unfold assertion_sub in HQ. assumption. Qed.
unfold valid_hoare_triple.
intros Q X a st st' HE HQ.
inversion HE. subst.
unfold assertion_sub in HQ. assumption. Qed.
Example assertion_sub_example :
{{(X < 5) [X ⊢> X + 1]}}
X := X + 1
{{X < 5}}.
Proof.
apply hoare_asgn. Qed.
{{(X < 5) [X ⊢> X + 1]}}
X := X + 1
{{X < 5}}.
Proof.
apply hoare_asgn. Qed.
Of course, what we'd probably prefer is to prove this simpler triple:
{{X < 4}} X := X + 1 {{X < 5}} We will see how to do so in the next section.
Consequence
For instance,
{{(X = 3) [X ⊢> 3]}} X := 3 {{X = 3}}, follows directly from the assignment rule, but
{{True}} X := 3 {{X = 3}} does not. This triple is valid, but it is not an instance of hoare_asgn because True and (X = 3) [X ⊢> 3] are not syntactically equal assertions.
{{P'}} c {{Q}} | |
P <<->> P' | (hoare_consequence_pre_equiv) |
{{P}} c {{Q}} |
{{P'}} c {{Q}} | |
P ->> P' | (hoare_consequence_pre) |
{{P}} c {{Q}} |
{{P}} c {{Q'}} | |
Q' ->> Q | (hoare_consequence_post) |
{{P}} c {{Q}} |
Theorem hoare_consequence_pre : ∀ (P P' Q : Assertion) c,
{{P'}} c {{Q}} →
P ->> P' →
{{P}} c {{Q}}.
Theorem hoare_consequence_post : ∀ (P Q Q' : Assertion) c,
{{P}} c {{Q'}} →
Q' ->> Q →
{{P}} c {{Q}}.
{{P'}} c {{Q}} →
P ->> P' →
{{P}} c {{Q}}.
Proof.
unfold valid_hoare_triple, "->>".
intros P P' Q c Hhoare Himp st st' Heval Hpre.
apply Hhoare with (st := st).
- assumption.
- apply Himp. assumption.
Qed.
unfold valid_hoare_triple, "->>".
intros P P' Q c Hhoare Himp st st' Heval Hpre.
apply Hhoare with (st := st).
- assumption.
- apply Himp. assumption.
Qed.
Theorem hoare_consequence_post : ∀ (P Q Q' : Assertion) c,
{{P}} c {{Q'}} →
Q' ->> Q →
{{P}} c {{Q}}.
Proof.
unfold valid_hoare_triple, "->>".
intros P Q Q' c Hhoare Himp st st' Heval Hpre.
apply Himp.
apply Hhoare with (st := st).
- assumption.
- assumption.
Qed.
unfold valid_hoare_triple, "->>".
intros P Q Q' c Hhoare Himp st st' Heval Hpre.
apply Himp.
apply Hhoare with (st := st).
- assumption.
- assumption.
Qed.
{{ True }} ->>
{{ (X = 1) [X ⊢> 1] }}
X := 1
{{ X = 1 }} Or, formally...
Example hoare_asgn_example1 :
{{True}} X := 1 {{X = 1}}.
Proof.
(* WORK IN CLASS *) Admitted.
{{True}} X := 1 {{X = 1}}.
Proof.
(* WORK IN CLASS *) Admitted.
We can also use it to prove the example mentioned earlier.
{{ X < 4 }} ->>
{{ (X < 5)[X ⊢> X + 1] }}
X := X + 1
{{ X < 5 }} Or, formally ...
Example assertion_sub_example2 :
{{X < 4}}
X := X + 1
{{X < 5}}.
Proof.
(* WORK IN CLASS *) Admitted.
{{X < 4}}
X := X + 1
{{X < 5}}.
Proof.
(* WORK IN CLASS *) Admitted.
Finally, here is a combined rule of consequence that allows us to vary both the precondition and the postcondition.
{{P'}} c {{Q'}} | |
P ->> P' | |
Q' ->> Q | (hoare_consequence) |
{{P}} c {{Q}} |
Theorem hoare_consequence : ∀ (P P' Q Q' : Assertion) c,
{{P'}} c {{Q'}} →
P ->> P' →
Q' ->> Q →
{{P}} c {{Q}}.
{{P'}} c {{Q'}} →
P ->> P' →
Q' ->> Q →
{{P}} c {{Q}}.
Proof.
intros P P' Q Q' c Htriple Hpre Hpost.
apply hoare_consequence_pre with (P' := P').
- apply hoare_consequence_post with (Q' := Q').
+ assumption.
+ assumption.
- assumption.
Qed.
intros P P' Q Q' c Htriple Hpre Hpost.
apply hoare_consequence_pre with (P' := P').
- apply hoare_consequence_post with (Q' := Q').
+ assumption.
+ assumption.
- assumption.
Qed.
Automation
Hint Unfold assert_implies assertion_sub t_update : core.
Hint Unfold valid_hoare_triple : core.
Hint Unfold assert_of_Prop Aexp_of_nat Aexp_of_aexp : core.
Hint Unfold valid_hoare_triple : core.
Hint Unfold assert_of_Prop Aexp_of_nat Aexp_of_aexp : core.
Also recall that auto will search for a proof involving intros
and apply. By default, the theorems that it will apply include
any of the local hypotheses, as well as theorems in a core
database.
Here's a good candidate for automation:
Theorem hoare_consequence_pre' : ∀ (P P' Q : Assertion) c,
{{P'}} c {{Q}} →
P ->> P' →
{{P}} c {{Q}}.
Proof.
unfold valid_hoare_triple, "->>".
intros P P' Q c Hhoare Himp st st' Heval Hpre.
apply Hhoare with (st := st).
- assumption.
- apply Himp. assumption.
Qed.
{{P'}} c {{Q}} →
P ->> P' →
{{P}} c {{Q}}.
Proof.
unfold valid_hoare_triple, "->>".
intros P P' Q c Hhoare Himp st st' Heval Hpre.
apply Hhoare with (st := st).
- assumption.
- apply Himp. assumption.
Qed.
Theorem hoare_consequence_pre''' : ∀ (P P' Q : Assertion) c,
{{P'}} c {{Q}} →
P ->> P' →
{{P}} c {{Q}}.
Proof.
unfold valid_hoare_triple, "->>".
intros P P' Q c Hhoare Himp st st' Heval Hpre.
eapply Hhoare.
- eassumption.
- apply Himp. assumption.
Qed.
{{P'}} c {{Q}} →
P ->> P' →
{{P}} c {{Q}}.
Proof.
unfold valid_hoare_triple, "->>".
intros P P' Q c Hhoare Himp st st' Heval Hpre.
eapply Hhoare.
- eassumption.
- apply Himp. assumption.
Qed.
The eauto tactic will use eapply as part of its proof search. So, the entire proof can actually be done in just one line.
Theorem hoare_consequence_pre'''' : ∀ (P P' Q : Assertion) c,
{{P'}} c {{Q}} →
P ->> P' →
{{P}} c {{Q}}.
Proof.
eauto.
Qed.
{{P'}} c {{Q}} →
P ->> P' →
{{P}} c {{Q}}.
Proof.
eauto.
Qed.
Theorem hoare_consequence_post' : ∀ (P Q Q' : Assertion) c,
{{P}} c {{Q'}} →
Q' ->> Q →
{{P}} c {{Q}}.
Proof.
eauto.
Qed.
{{P}} c {{Q'}} →
Q' ->> Q →
{{P}} c {{Q}}.
Proof.
eauto.
Qed.
We can also use eapply to streamline a proof (hoare_asgn_example1), that we did earlier as an example of using the consequence rule:
Example hoare_asgn_example1' :
{{True}} X := 1 {{X = 1}}.
Proof.
eapply hoare_consequence_pre. (* no need to state an assertion *)
- apply hoare_asgn.
- unfold "->>", assertion_sub, t_update.
intros st _. simpl. reflexivity.
Qed.
{{True}} X := 1 {{X = 1}}.
Proof.
eapply hoare_consequence_pre. (* no need to state an assertion *)
- apply hoare_asgn.
- unfold "->>", assertion_sub, t_update.
intros st _. simpl. reflexivity.
Qed.
Example hoare_asgn_example1'' :
{{True}} X := 1 {{X = 1}}.
Proof.
eapply hoare_consequence_pre.
- apply hoare_asgn.
- auto.
Qed.
{{True}} X := 1 {{X = 1}}.
Proof.
eapply hoare_consequence_pre.
- apply hoare_asgn.
- auto.
Qed.
Now we have quite a nice proof script: it simply identifies the
Hoare rules that need to be used and leaves the remaining
low-level details up to Coq to figure out.
The other example of using consequence that we did earlier, hoare_asgn_example2, requires a little more work to automate. We can streamline the first line with eapply, but we can't just use auto for the final bullet, since it needs lia.
Example assertion_sub_example2' :
{{X < 4}}
X := X + 1
{{X < 5}}.
Proof.
eapply hoare_consequence_pre.
- apply hoare_asgn.
- auto. (* no progress *)
unfold "->>", assertion_sub, t_update.
intros st H. simpl in ×. lia.
Qed.
{{X < 4}}
X := X + 1
{{X < 5}}.
Proof.
eapply hoare_consequence_pre.
- apply hoare_asgn.
- auto. (* no progress *)
unfold "->>", assertion_sub, t_update.
intros st H. simpl in ×. lia.
Qed.
Ltac assertion_auto :=
try auto; (* as in example 1, above *)
try (unfold "->>", assertion_sub, t_update;
intros; simpl in *; lia). (* as in example 2 *)
try auto; (* as in example 1, above *)
try (unfold "->>", assertion_sub, t_update;
intros; simpl in *; lia). (* as in example 2 *)
Example assertion_sub_example2'' :
{{X < 4}}
X := X + 1
{{X < 5}}.
Proof.
eapply hoare_consequence_pre.
- apply hoare_asgn.
- assertion_auto.
Qed.
{{X < 4}}
X := X + 1
{{X < 5}}.
Proof.
eapply hoare_consequence_pre.
- apply hoare_asgn.
- assertion_auto.
Qed.
Example hoare_asgn_example1''':
{{True}} X := 1 {{X = 1}}.
Proof.
eapply hoare_consequence_pre.
- apply hoare_asgn.
- assertion_auto.
Qed.
{{True}} X := 1 {{X = 1}}.
Proof.
eapply hoare_consequence_pre.
- apply hoare_asgn.
- assertion_auto.
Qed.
Again, we have quite a nice proof script. All the low-level details of proofs about assertions have been taken care of automatically. Of course, assertion_auto isn't able to prove everything we could possibly want to know about assertions -- there's no magic here! But it's good enough so far.
Sequencing + Assignment
Example hoare_asgn_example3 : ∀ (a:aexp) (n:nat),
{{a = n}}
X := a;
skip
{{X = n}}.
Proof.
intros a n. eapply hoare_seq.
- (* right part of seq *)
apply hoare_skip.
- (* left part of seq *)
eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto.
Qed.
{{a = n}}
X := a;
skip
{{X = n}}.
Proof.
intros a n. eapply hoare_seq.
- (* right part of seq *)
apply hoare_skip.
- (* left part of seq *)
eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto.
Qed.
{{ a = n }}
X := a
{{ X = n }}; <--- decoration for Q
skip
{{ X = n }} We'll come back to the idea of decorated programs in much more detail in the next chapter.
Conditionals
{{P}} c1 {{Q}} | |
{{P}} c2 {{Q}} | |
{{P}} if b then c1 else c2 {{Q}} |
{{ True }}
if X = 0
then Y := 2
else Y := X + 1
end
{{ X ≤ Y }} since the rule tells us nothing about the state in which the assignments take place in the "then" and "else" branches.
Better:
{{P /\ b}} c1 {{Q}} | |
{{P /\ ~ b}} c2 {{Q}} | (hoare_if) |
{{P}} if b then c1 else c2 end {{Q}} |
Definition bassertion b : Assertion :=
fun st ⇒ (beval st b = true).
fun st ⇒ (beval st b = true).
Theorem hoare_if : ∀ P Q (b:bexp) c1 c2,
{{ P ∧ b }} c1 {{Q}} →
{{ P ∧ ¬b}} c2 {{Q}} →
{{P}} if b then c1 else c2 end {{Q}}.
{{ P ∧ b }} c1 {{Q}} →
{{ P ∧ ¬b}} c2 {{Q}} →
{{P}} if b then c1 else c2 end {{Q}}.
That is (unwrapping the notations):
Theorem hoare_if : ∀ P Q b c1 c2,
{{fun st ⇒ P st ∧ bassertion b st}} c1 {{Q}} →
{{fun st ⇒ P st ∧ ¬(bassertion b st)}} c2 {{Q}} →
{{P}} if b then c1 else c2 end {{Q}}.
Theorem hoare_if : ∀ P Q b c1 c2,
{{fun st ⇒ P st ∧ bassertion b st}} c1 {{Q}} →
{{fun st ⇒ P st ∧ ¬(bassertion b st)}} c2 {{Q}} →
{{P}} if b then c1 else c2 end {{Q}}.
Proof.
intros P Q b c1 c2 HTrue HFalse st st' HE HP.
inversion HE; subst; eauto.
Qed.
intros P Q b c1 c2 HTrue HFalse st st' HE HP.
inversion HE; subst; eauto.
Qed.
Example if_example :
{{True}}
if (X = 0)
then Y := 2
else Y := X + 1
end
{{X ≤ Y}}.
Proof.
apply hoare_if.
- (* Then *)
eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto. (* no progress *)
unfold "->>", assertion_sub, t_update, bassertion.
simpl. intros st [_ H]. apply eqb_eq in H.
rewrite H. lia.
- (* Else *)
eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto.
Qed.
{{True}}
if (X = 0)
then Y := 2
else Y := X + 1
end
{{X ≤ Y}}.
Proof.
apply hoare_if.
- (* Then *)
eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto. (* no progress *)
unfold "->>", assertion_sub, t_update, bassertion.
simpl. intros st [_ H]. apply eqb_eq in H.
rewrite H. lia.
- (* Else *)
eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto.
Qed.
Ltac assertion_auto' :=
unfold "->>", assertion_sub, t_update, bassertion;
intros; simpl in *;
try rewrite → eqb_eq in *; (* for equalities *)
auto; try lia.
unfold "->>", assertion_sub, t_update, bassertion;
intros; simpl in *;
try rewrite → eqb_eq in *; (* for equalities *)
auto; try lia.
Example if_example'' :
{{True}}
if X = 0
then Y := 2
else Y := X + 1
end
{{X ≤ Y}}.
Proof.
apply hoare_if.
- eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto'.
- eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto'.
Qed.
{{True}}
if X = 0
then Y := 2
else Y := X + 1
end
{{X ≤ Y}}.
Proof.
apply hoare_if.
- eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto'.
- eapply hoare_consequence_pre.
+ apply hoare_asgn.
+ assertion_auto'.
Qed.
Example if_example''' :
{{True}}
if X = 0
then Y := 2
else Y := X + 1
end
{{X ≤ Y}}.
Proof.
apply hoare_if; eapply hoare_consequence_pre;
try apply hoare_asgn; try assertion_auto'.
Qed.
{{True}}
if X = 0
then Y := 2
else Y := X + 1
end
{{X ≤ Y}}.
Proof.
apply hoare_if; eapply hoare_consequence_pre;
try apply hoare_asgn; try assertion_auto'.
Qed.
Ltac assertion_auto'' :=
unfold "->>", assertion_sub, t_update, bassertion;
intros; simpl in *;
try rewrite → eqb_eq in *;
try rewrite → leb_le in *; (* for inequalities *)
auto; try lia.
☐
unfold "->>", assertion_sub, t_update, bassertion;
intros; simpl in *;
try rewrite → eqb_eq in *;
try rewrite → leb_le in *; (* for inequalities *)
auto; try lia.
☐
While Loops
{{P}} c {{P}} holds. Note that the command invariant might temporarily become false in the middle of executing c, but by the end of c it must be restored.
The Hoare while rule combines the idea of a command invariant with information about when guard b does or does not hold.
{{P /\ b}} c {{P}} | (hoare_while) |
{{P} while b do c end {{P /\ ~b}} |
Theorem hoare_while : ∀ P (b:bexp) c,
{{P ∧ b}} c {{P}} →
{{P}} while b do c end {{P ∧ ¬b}}.
{{P ∧ b}} c {{P}} →
{{P}} while b do c end {{P ∧ ¬b}}.
Proof.
intros P b c Hhoare st st' Heval HP.
(* We proceed by induction on Heval, because, in the "keep looping" case,
its hypotheses talk about the whole loop instead of just c. The
remember is used to keep the original command in the hypotheses;
otherwise, it would be lost in the induction. By using inversion
we clear away all the cases except those involving while. *)
remember <{while b do c end}> as original_command eqn:Horig.
induction Heval;
try (inversion Horig; subst; clear Horig);
eauto.
Qed.
intros P b c Hhoare st st' Heval HP.
(* We proceed by induction on Heval, because, in the "keep looping" case,
its hypotheses talk about the whole loop instead of just c. The
remember is used to keep the original command in the hypotheses;
otherwise, it would be lost in the induction. By using inversion
we clear away all the cases except those involving while. *)
remember <{while b do c end}> as original_command eqn:Horig.
induction Heval;
try (inversion Horig; subst; clear Horig);
eauto.
Qed.
{{P ∧ b}} c {{P}} is a valid Hoare triple.
while X = 2 do X := 1 end since the program will never enter the loop.
Is the assertion
Y = 0 a loop invariant of the following?
while X < 100 do X := X + 1 end
(1) Yes
(2) No
Y = 0 a loop invariant of the following?
while X < 100 do X := X + 1 end
Is the assertion
X = 0 a loop invariant of the following?
while X < 100 do X := X + 1 end
(1) Yes
(2) No
X = 0 a loop invariant of the following?
while X < 100 do X := X + 1 end
Is the assertion
X < Y a loop invariant of the following?
while true do X := X + 1; Y := Y + 1 end
(1) Yes
(2) No
X < Y a loop invariant of the following?
while true do X := X + 1; Y := Y + 1 end
Is the assertion
X = Y + Z a loop invariant of the following?
while Y > 10 do Y := Y - 1; Z := Z + 1 end (1) Yes
(2) No
X = Y + Z a loop invariant of the following?
while Y > 10 do Y := Y - 1; Z := Z + 1 end (1) Yes
Is the assertion
X > 0 a loop invariant of the following?
while X = 0 do X := X - 1 end
(1) Yes
(2) No
X > 0 a loop invariant of the following?
while X = 0 do X := X - 1 end
Is the assertion
X < 100 a loop invariant of the following?
while X < 100 do X := X + 1 end
(1) Yes
(2) No
X < 100 a loop invariant of the following?
while X < 100 do X := X + 1 end
Is the assertion
X > 10 a loop invariant of the following?
while X > 10 do X := X + 1 end
(1) Yes
(2) No
X > 10 a loop invariant of the following?
while X > 10 do X := X + 1 end
Summary
(hoare_asgn) | |
{{Q [X ⊢> a]}} X:=a {{Q}} |
(hoare_skip) | |
{{ P }} skip {{ P }} |
{{ P }} c1 {{ Q }} | |
{{ Q }} c2 {{ R }} | (hoare_seq) |
{{ P }} c1;c2 {{ R }} |
{{P /\ b}} c1 {{Q}} | |
{{P /\ ~ b}} c2 {{Q}} | (hoare_if) |
{{P}} if b then c1 else c2 end {{Q}} |
{{P /\ b}} c {{P}} | (hoare_while) |
{{P}} while b do c end {{P /\ ~ b}} |
{{P'}} c {{Q'}} | |
P ->> P' | |
Q' ->> Q | (hoare_consequence) |
{{P}} c {{Q}} |