Lecture notes 20210308 Hoare Logic 4
Remark. Some material in this lecture is from << Software Foundation >>
volume 1 and volume 2.
Require Import PL.Imp.
Import Assertion_S.
Import Assertion_S_Tac.
Import Assertion_S_Rules.
Import Concrete_Pretty_Printing.
Import Axiomatic_semantics.
Import Derived_Rules.
Import Assertion_S.
Import Assertion_S_Tac.
Import Assertion_S_Rules.
Import Concrete_Pretty_Printing.
Import Axiomatic_semantics.
Import Derived_Rules.
Review
- assertions (including syntactic substitution and assertion derivation)
- Hoare triples
- axiomatic semantics.
- rewrite
- intros
- apply
- pose proof
- exact
- eapply
- assert.
Assertion entailment
Module reduce_to_zero.
Local Instance X: var := new_var().
Local Instance X: var := new_var().
The question is: do we really need to put derivation into hypothesis?
Can we prove them instead? The answer is yes.
Fact derivation_example:
0 < [[X]] ⊢ 0 ≤ [[X]].
Proof.
0 < [[X]] ⊢ 0 ≤ [[X]].
Proof.
Obviously, this proof goal is equivalent to say: for any integer x, if
0 < x then 0 ≤ x. The following tactic entailer provided by our Imp
library apply this transition for us.
entailer.
Now, we know that we should use "intros" to drag this universally
quantified variable X' above the line.
intros.
Oops, it does more!! But that is reasonable. Proving A -> B (reads "A
implies B" is equivalent with proving B with assumption A. We know that
this proof goal is true. But at this position, what we have already learnt
cannot help us much. The following tactic "lia" is to solve Linear Integer
Arithmetic systems. Let's try it.
lia.
Qed.
Lemma der1:
0 ≤ [[X]] AND NOT [[! (X ≤ 0)]] ⊢ [[X]] = 0.
Proof.
entailer.
intros.
Qed.
Lemma der1:
0 ≤ [[X]] AND NOT [[! (X ≤ 0)]] ⊢ [[X]] = 0.
Proof.
entailer.
intros.
The symbol "/\" (see the assumption H) represents "and" in Coq and the
symbol "~" represents negation or "not". Let's see whether lia can handle
conjunctions in assumptions.
lia.
Bingo!
Qed.
Now we have got both hypotheses proved.
End reduce_to_zero.
Coq also provide an automatic verification tactic for Non-linear Integer
Arithmetics, nia. It supports ring operations on integers (plus, minus and
multiplication). However, it is not a complete solver, i.e. it may fail to prove
a provable fact. Here are two examples in which nia succeeds.
Goal ∀x y: Z, (x + 1) * y < y + x * y + 1.
Proof.
intros.
nia.
Qed.
Proof.
intros.
nia.
Qed.
In principle, nia knows to use commutative-ring equations (commutativity
and associativity of sum and multiplication, and the distributive law) and
to apply linear comparisons.
Goal ∀x y: Z, (x + 1) * (x + 1) ≥ 0.
Proof.
intros.
nia.
Qed.
Proof.
intros.
nia.
Qed.
For non-linear inequalities, nia may succeed.
Goal ∀x y: Z, (x + y) * (x + y) ≥ 0.
Proof.
intros.
Fail nia.
Abort.
Proof.
intros.
Fail nia.
Abort.
Module reduce_to_zero_der.
Local Instance X: var := new_var().
We do not need to derive True from anything else. It is by itself true.
Lemma der1:
True AND [[! (X ≤ 0)]] ⊢ True.
Proof.
entailer.
intros.
True AND [[! (X ≤ 0)]] ⊢ True.
Proof.
entailer.
intros.
In Coq, I is a proof of True. Whenever you want to prove True, use
exact I.
exact I.
Qed.
End reduce_to_zero_der.
Qed.
End reduce_to_zero_der.
Conjunction
Lemma True2: True ∧ True.
Proof.
split.
+ exact I.
+ exact I.
Qed.
Lemma and_intro : ∀A B : Prop, A -> B -> A ∧ B.
Proof.
intros A B HA HB. split.
- apply HA.
- apply HB.
Qed.
Example and_exercise :
∀n m : Z, n + 2*m = 0 -> 2*n + m = 0 -> n = 0 ∧ True.
Proof.
intros.
split.
+ lia.
+ exact I.
Qed.
Proof.
split.
+ exact I.
+ exact I.
Qed.
Lemma and_intro : ∀A B : Prop, A -> B -> A ∧ B.
Proof.
intros A B HA HB. split.
- apply HA.
- apply HB.
Qed.
Example and_exercise :
∀n m : Z, n + 2*m = 0 -> 2*n + m = 0 -> n = 0 ∧ True.
Proof.
intros.
split.
+ lia.
+ exact I.
Qed.
To use a conjunctive hypothesis to help prove something else, we use the
destruct tactic.
Lemma and_example2 :
∀n m : Z, n = 0 ∧ (True -> m = 0) -> n + m = 0.
Proof.
intros.
destruct H.
pose proof H0 I.
lia.
Qed.
Lemma and_example2' :
∀n m : Z, n = 0 ∧ (True -> m = 0) -> n + m = 0.
Proof.
intros.
destruct H as [Hn H].
pose proof H I as Hm.
lia.
Qed.
Theorem and_commut : ∀P Q : Prop,
P ∧ Q -> Q ∧ P.
Proof.
intros.
destruct H as [HP HQ].
split.
- exact HQ.
- exact HP.
Qed.
∀n m : Z, n = 0 ∧ (True -> m = 0) -> n + m = 0.
Proof.
intros.
destruct H.
pose proof H0 I.
lia.
Qed.
Lemma and_example2' :
∀n m : Z, n = 0 ∧ (True -> m = 0) -> n + m = 0.
Proof.
intros.
destruct H as [Hn H].
pose proof H I as Hm.
lia.
Qed.
Theorem and_commut : ∀P Q : Prop,
P ∧ Q -> Q ∧ P.
Proof.
intros.
destruct H as [HP HQ].
split.
- exact HQ.
- exact HP.
Qed.
Theorem and_assoc : ∀P Q R : Prop,
P ∧ (Q ∧ R) -> (P ∧ Q) ∧ R.
Proof.
intros.
destruct H as [HP [HQ HR]].
(* FILL IN HERE *) Admitted.
☐
P ∧ (Q ∧ R) -> (P ∧ Q) ∧ R.
Proof.
intros.
destruct H as [HP [HQ HR]].
(* FILL IN HERE *) Admitted.
Disjunction
Lemma or_example :
∀n m : Z, n = 0 ∨ m = 0 -> n * m = 0.
Proof.
intros.
destruct H.
- rewrite H.
lia.
- rewrite H.
lia.
Qed.
Lemma or_example2 :
∀P Q R: Prop, (P -> R) -> (Q -> R) -> (P ∨ Q -> R).
Proof.
intros.
destruct H1 as [HP | HQ].
- apply H.
exact HP.
- pose proof H0 HQ.
exact H1.
Qed.
∀n m : Z, n = 0 ∨ m = 0 -> n * m = 0.
Proof.
intros.
destruct H.
- rewrite H.
lia.
- rewrite H.
lia.
Qed.
Lemma or_example2 :
∀P Q R: Prop, (P -> R) -> (Q -> R) -> (P ∨ Q -> R).
Proof.
intros.
destruct H1 as [HP | HQ].
- apply H.
exact HP.
- pose proof H0 HQ.
exact H1.
Qed.
Conversely, to show that a disjunction holds, we need to show that
one of its sides does. This is done via two tactics, left and
right. As their names imply, the first one requires
proving the left side of the disjunction, while the second
requires proving its right side. Here is a trivial use...
Lemma or_introl : ∀A B : Prop, A -> A ∨ B.
Proof.
intros.
left.
exact H.
Qed.
Lemma or_intror : ∀A B : Prop, B -> A ∨ B.
Proof.
intros.
right.
exact H.
Qed.
Proof.
intros.
left.
exact H.
Qed.
Lemma or_intror : ∀A B : Prop, B -> A ∨ B.
Proof.
intros.
right.
exact H.
Qed.
Theorem or_commut : ∀P Q : Prop,
P ∨ Q -> Q ∨ P.
Proof.
(* FILL IN HERE *) Admitted.
☐
P ∨ Q -> Q ∨ P.
Proof.
(* FILL IN HERE *) Admitted.
Implication
Theorem modus_ponens: ∀P Q: Prop,
P ∧ (P -> Q) -> Q.
Proof.
intros.
destruct H.
pose proof H0 H.
exact H1.
Qed.
P ∧ (P -> Q) -> Q.
Proof.
intros.
destruct H.
pose proof H0 H.
exact H1.
Qed.
But we can also prove it in alternative ways.
Theorem modus_ponens_alter1: ∀P Q: Prop,
P ∧ (P -> Q) -> Q.
Proof.
intros.
destruct H.
revert H.
exact H0.
Qed.
Theorem modus_ponens_alter2: ∀P Q: Prop,
P ∧ (P -> Q) -> Q.
Proof.
intros.
destruct H.
specialize (H0 H).
exact H0.
Qed.
P ∧ (P -> Q) -> Q.
Proof.
intros.
destruct H.
revert H.
exact H0.
Qed.
Theorem modus_ponens_alter2: ∀P Q: Prop,
P ∧ (P -> Q) -> Q.
Proof.
intros.
destruct H.
specialize (H0 H).
exact H0.
Qed.
Falsehood and Negation
Theorem ex_falso_quodlibet : ∀(P:Prop),
False -> P.
Proof.
(* WORKED IN CLASS *)
intros.
contradiction.
Qed.
False -> P.
Proof.
(* WORKED IN CLASS *)
intros.
contradiction.
Qed.
The Latin ex falso quodlibet means, literally, "from falsehood
follows whatever you like"; this is another common name for the
principle of explosion.
The tactic contradiction also works if both P and ¬P appear
in the proof context.
Theorem contradiction_implies_anything : ∀P Q : Prop,
(P ∧ ¬P) -> Q.
Proof.
(* WORKED IN CLASS *)
intros.
destruct H.
contradiction.
Qed.
(P ∧ ¬P) -> Q.
Proof.
(* WORKED IN CLASS *)
intros.
destruct H.
contradiction.
Qed.
Besides the fact that P and ¬P cannot be both true, one of them must be
true. This principle is called law of excluded middle, and is named
classic in Coq.
Check classic.
(* : forall P : Prop, P \/ ~ P *)
Theorem double_neg_elim : ∀P : Prop,
¬¬P -> P.
Proof.
(* WORKED IN CLASS *)
intros.
pose proof classic P.
destruct H0.
+ exact H0.
+ contradiction.
Qed.
Theorem not_False :
¬False.
Proof.
(* WORKED IN CLASS *)
pose proof classic False.
destruct H.
+ contradiction.
+ exact H.
Qed.
Theorem double_neg_intro : ∀P : Prop,
P -> ¬¬P.
Proof.
(* WORKED IN CLASS *)
intros.
pose proof classic (¬P).
destruct H0.
+ contradiction.
+ exact H0.
Qed.
(* : forall P : Prop, P \/ ~ P *)
Theorem double_neg_elim : ∀P : Prop,
¬¬P -> P.
Proof.
(* WORKED IN CLASS *)
intros.
pose proof classic P.
destruct H0.
+ exact H0.
+ contradiction.
Qed.
Theorem not_False :
¬False.
Proof.
(* WORKED IN CLASS *)
pose proof classic False.
destruct H.
+ contradiction.
+ exact H.
Qed.
Theorem double_neg_intro : ∀P : Prop,
P -> ¬¬P.
Proof.
(* WORKED IN CLASS *)
intros.
pose proof classic (¬P).
destruct H0.
+ contradiction.
+ exact H0.
Qed.
Existential Quantification
Lemma four_is_even : ∃n, 4 = n + n.
Proof.
∃2.
lia.
Qed.
Lemma six_is_not_prime: ∃n, 2 ≤ n < 6 ∧ ∃q, n * q = 6.
Proof.
∃2.
split.
+ lia.
+ ∃3.
lia.
Qed.
Proof.
∃2.
lia.
Qed.
Lemma six_is_not_prime: ∃n, 2 ≤ n < 6 ∧ ∃q, n * q = 6.
Proof.
∃2.
split.
+ lia.
+ ∃3.
lia.
Qed.
Conversely, if we have an existential hypothesis ∃ x, P in Coq, we
can destruct it
Theorem exists_example : ∀n,
(∃m, n = 4 + m) ->
(∃o, n = 2 + o).
Proof.
(* WORKED IN CLASS *)
intros.
destruct H.
∃(2 + x).
lia.
Qed.
Theorem dist_exists_and : ∀(X:Type) (P Q : X -> Prop),
(∃x, P x ∧ Q x) -> (∃x, P x) ∧ (∃x, Q x).
Proof.
(* WORKED IN CLASS *)
intros.
destruct H as [x [HP HQ]].
split.
+ ∃x.
exact HP.
+ ∃x.
exact HQ.
Qed.
(∃m, n = 4 + m) ->
(∃o, n = 2 + o).
Proof.
(* WORKED IN CLASS *)
intros.
destruct H.
∃(2 + x).
lia.
Qed.
Theorem dist_exists_and : ∀(X:Type) (P Q : X -> Prop),
(∃x, P x ∧ Q x) -> (∃x, P x) ∧ (∃x, Q x).
Proof.
(* WORKED IN CLASS *)
intros.
destruct H as [x [HP HQ]].
split.
+ ∃x.
exact HP.
+ ∃x.
exact HQ.
Qed.
Notice that the reverse direction of this theorem is not true. For example,
there obviously exists at least one even number and one odd number but there is
not number which is both even and odd.
Module sample_derivation.
Import Assertion_S.
Import Assertion_S_Tac.
Import Assertion_S_Rules.
Import Concrete_Pretty_Printing.
Local Instance X: var := new_var().
Fact der: ∀(m n: Z),
0 ≤ m AND [[X]] = m ⊢
EXISTS q, n * q + [[X]] = m AND 0 ≤ [[X]].
Proof.
(* WORKED IN CLASS *)
intros.
entailer.
intros.
∃0.
lia.
Qed.
End sample_derivation.
Import Assertion_S.
Import Assertion_S_Tac.
Import Assertion_S_Rules.
Import Concrete_Pretty_Printing.
Local Instance X: var := new_var().
Fact der: ∀(m n: Z),
0 ≤ m AND [[X]] = m ⊢
EXISTS q, n * q + [[X]] = m AND 0 ≤ [[X]].
Proof.
(* WORKED IN CLASS *)
intros.
entailer.
intros.
∃0.
lia.
Qed.
End sample_derivation.
Universal Quantification
Lemma forall_comm: ∀(P: Z -> Z -> Prop),
(∀x y, P x y) ->
(∀y x, P x y).
Proof.
intros.
apply H.
Qed.
Lemma forall_example1: ∀(P Q: Z -> Z -> Prop),
P 0 1 ->
(∀x y, P x y -> Q x y) ->
Q 0 1.
Proof.
intros.
pose proof H0 0 1 H.
exact H1.
Qed.
Lemma forall_example2: ∀(P Q: Z -> Z -> Prop),
P 0 1 ->
(∀x y, P x y -> Q x y) ->
Q 0 1.
Proof.
intros.
specialize (H0 0 1 H).
exact H0.
Qed.
Lemma forall_example3: ∀(P Q: Z -> Z -> Prop),
P 0 1 ->
(∀x y, P x y -> Q x y) ->
Q 0 1.
Proof.
intros.
apply H0.
exact H.
Qed.
Lemma forall_example4: ∀(P Q: Z -> Z -> Prop),
P 0 1 ->
(∀x y, P x y -> Q x y) ->
Q 0 1.
Proof.
intros.
apply H0 in H.
exact H.
Qed.
(∀x y, P x y) ->
(∀y x, P x y).
Proof.
intros.
apply H.
Qed.
Lemma forall_example1: ∀(P Q: Z -> Z -> Prop),
P 0 1 ->
(∀x y, P x y -> Q x y) ->
Q 0 1.
Proof.
intros.
pose proof H0 0 1 H.
exact H1.
Qed.
Lemma forall_example2: ∀(P Q: Z -> Z -> Prop),
P 0 1 ->
(∀x y, P x y -> Q x y) ->
Q 0 1.
Proof.
intros.
specialize (H0 0 1 H).
exact H0.
Qed.
Lemma forall_example3: ∀(P Q: Z -> Z -> Prop),
P 0 1 ->
(∀x y, P x y -> Q x y) ->
Q 0 1.
Proof.
intros.
apply H0.
exact H.
Qed.
Lemma forall_example4: ∀(P Q: Z -> Z -> Prop),
P 0 1 ->
(∀x y, P x y -> Q x y) ->
Q 0 1.
Proof.
intros.
apply H0 in H.
exact H.
Qed.
Exercise: 1 star, standard (dist_not_exists)
Prove that "P holds for all x" implies "there is no x for which P does not hold." (Hint: destruct H as [x E] works on existential assumptions!)
Theorem dist_not_exists : ∀(X:Type) (P : X -> Prop),
(∀x, P x) -> ¬(∃x, ¬P x).
Proof.
(* FILL IN HERE *) Admitted.
☐
(∀x, P x) -> ¬(∃x, ¬P x).
Proof.
(* FILL IN HERE *) Admitted.
Module assertion_FOL.
The Imp library also supports first order logic proof directly, i.e., in
order to verify assertion derivation, you can choose not to reduce it to normal
Coq propositions. The following proof rules are provided for you.
Check AND_left1.
(* : forall P Q R : Assertion,
P ⊢ R -> P AND Q ⊢ R *)
Check AND_left2.
(* : forall P Q R : Assertion,
Q ⊢ R -> P AND Q ⊢ R *)
Check AND_right.
(* : forall P Q R : Assertion,
P ⊢ Q -> P ⊢ R -> P ⊢ Q AND R *)
Check OR_left.
(* : forall P Q R : Assertion,
P ⊢ R -> Q ⊢ R -> P OR Q ⊢ R *)
Check OR_right1.
(* : forall P Q R : Assertion,
P ⊢ Q -> P ⊢ Q OR R *)
Check OR_right2.
(* : forall P Q R : Assertion,
P ⊢ R -> P ⊢ Q OR R *)
Check CONTRA.
(* : forall P Q : Assertion, P AND NOT P ⊢ Q *)
Check LEM.
(* : forall P Q : Assertion, P ⊢ Q OR NOT Q *)
Check True_right.
(* : forall P : Assertion, P ⊢ True *)
Check False_left.
(* : forall P : Assertion, False ⊢ P *)
Check EXISTS_left.
(* : forall P (Q : Assertion),
(forall x : Z, P x ⊢ Q) ->
EXISTS x, P x ⊢ Q *)
Check EXISTS_right.
(* : forall (P : Assertion) Q (x : Z),
P ⊢ Q x -> P ⊢ EXISTS x, Q x *)
Check FORALL_left.
(* : forall P (Q : Assertion) (x : Z),
P x ⊢ Q -> FORALL x0, P x0 ⊢ Q *)
Check FORALL_right.
(* : forall (P : Assertion) Q,
(forall x : Z, P ⊢ Q x) ->
P ⊢ FORALL x, Q x *)
Check derives_refl.
(* : forall P : Assertion, P ⊢ P *)
Check derives_trans.
(* : forall P Q R : Assertion,
P ⊢ Q -> Q ⊢ R -> P ⊢ R *)
Local Instance X: var := new_var().
Fact example: 0 ≤ [[ X ]] AND [[ X ]] < 100 ⊢ [[ X ]] < 100 AND 0 ≤ [[ X ]].
Proof.
apply AND_right.
+ apply AND_left2.
apply derives_refl.
+ apply AND_left1.
apply derives_refl.
Qed.
End assertion_FOL.
(* : forall P Q R : Assertion,
P ⊢ R -> P AND Q ⊢ R *)
Check AND_left2.
(* : forall P Q R : Assertion,
Q ⊢ R -> P AND Q ⊢ R *)
Check AND_right.
(* : forall P Q R : Assertion,
P ⊢ Q -> P ⊢ R -> P ⊢ Q AND R *)
Check OR_left.
(* : forall P Q R : Assertion,
P ⊢ R -> Q ⊢ R -> P OR Q ⊢ R *)
Check OR_right1.
(* : forall P Q R : Assertion,
P ⊢ Q -> P ⊢ Q OR R *)
Check OR_right2.
(* : forall P Q R : Assertion,
P ⊢ R -> P ⊢ Q OR R *)
Check CONTRA.
(* : forall P Q : Assertion, P AND NOT P ⊢ Q *)
Check LEM.
(* : forall P Q : Assertion, P ⊢ Q OR NOT Q *)
Check True_right.
(* : forall P : Assertion, P ⊢ True *)
Check False_left.
(* : forall P : Assertion, False ⊢ P *)
Check EXISTS_left.
(* : forall P (Q : Assertion),
(forall x : Z, P x ⊢ Q) ->
EXISTS x, P x ⊢ Q *)
Check EXISTS_right.
(* : forall (P : Assertion) Q (x : Z),
P ⊢ Q x -> P ⊢ EXISTS x, Q x *)
Check FORALL_left.
(* : forall P (Q : Assertion) (x : Z),
P x ⊢ Q -> FORALL x0, P x0 ⊢ Q *)
Check FORALL_right.
(* : forall (P : Assertion) Q,
(forall x : Z, P ⊢ Q x) ->
P ⊢ FORALL x, Q x *)
Check derives_refl.
(* : forall P : Assertion, P ⊢ P *)
Check derives_trans.
(* : forall P Q R : Assertion,
P ⊢ Q -> Q ⊢ R -> P ⊢ R *)
Local Instance X: var := new_var().
Fact example: 0 ≤ [[ X ]] AND [[ X ]] < 100 ⊢ [[ X ]] < 100 AND 0 ≤ [[ X ]].
Proof.
apply AND_right.
+ apply AND_left2.
apply derives_refl.
+ apply AND_left1.
apply derives_refl.
Qed.
End assertion_FOL.
The following example is about the slow division program. We will show
different proof techniques in this example.
Module slow_div.
Local Instance X: var := new_var().
Local Instance Y: var := new_var().
Lemma derivation1: ∀m n: Z,
0 ≤ m AND [[X]] = m AND [[Y]] = 0 ⊢
n * [[Y]] + [[X]] = m AND 0 ≤ [[X]].
Proof.
intros.
entailer.
intros.
nia.
Qed.
Lemma 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]].
Proof.
intros.
apply EXISTS_left.
intros.
entailer.
intros.
lia.
Qed.
Lemma 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]].
Proof.
intros.
entailer.
intros.
destruct H as [k ?].
nia.
Qed.
Lemma 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.
Proof.
intros.
apply AND_right.
+ apply AND_left1.
apply derives_refl.
+ apply AND_left2.
entailer.
intros.
lia.
Qed.
Fact slow_div_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 }} .
End slow_div.
(* 2021-03-07 20:15 *)
Local Instance X: var := new_var().
Local Instance Y: var := new_var().
Lemma derivation1: ∀m n: Z,
0 ≤ m AND [[X]] = m AND [[Y]] = 0 ⊢
n * [[Y]] + [[X]] = m AND 0 ≤ [[X]].
Proof.
intros.
entailer.
intros.
nia.
Qed.
Lemma 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]].
Proof.
intros.
apply EXISTS_left.
intros.
entailer.
intros.
lia.
Qed.
Lemma 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]].
Proof.
intros.
entailer.
intros.
destruct H as [k ?].
nia.
Qed.
Lemma 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.
Proof.
intros.
apply AND_right.
+ apply AND_left1.
apply derives_refl.
+ apply AND_left2.
entailer.
intros.
lia.
Qed.
Fact slow_div_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.
eapply hoare_seq.
{ apply hoare_asgn_fwd. }
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.
1: { apply (derivation1 m n). }
2: { apply derivation4. }
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.
Qed.
intros.
eapply hoare_seq.
{ apply hoare_asgn_fwd. }
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.
1: { apply (derivation1 m n). }
2: { apply derivation4. }
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.
Qed.
End slow_div.
(* 2021-03-07 20:15 *)