TotalTotal Correctness
Set Warnings "-notation-overridden,-parsing,-deprecated-hint-without-locality".
From PLF Require Import Maps.
From Coq Require Import Bool.
From Coq Require Import Arith.
From Coq Require Import EqNat.
From Coq Require Import PeanoNat. Import Nat.
From Coq Require Import Lia.
From PLF Require Export Imp.
From PLF Require Import Hoare11.
From PLF Require Import Hoare12.
Set Default Goal Selector "!".
From PLF Require Import Maps.
From Coq Require Import Bool.
From Coq Require Import Arith.
From Coq Require Import EqNat.
From Coq Require Import PeanoNat. Import Nat.
From Coq Require Import Lia.
From PLF Require Export Imp.
From PLF Require Import Hoare11.
From PLF Require Import Hoare12.
Set Default Goal Selector "!".
Total correctness, Informally
[P] c [Q] meaning:
- If command c begins execution in a state satisfying assertion P,
- then c terminates in some final state which satisfies the assertion Q.
|P| c |Q|
Exercise: 1 star, standard, optional (total)
Paraphrase the following Total Correctness statement in English, and tell if there are valid -- i.e., is the claimed relation between P, c, and Q true?1) |True| c |X = 5|
2) |X ≤ Y| c |Y ≤ X|
3) |True| c |False|
4) |False| skip |True|
5) |True| while true do skip end |False|
6) |X = 0|
while X = 0 do X := X + 1 end
|X = 1|
(* FILL IN HERE *)
☐
☐
Definition valid_total
(P : Assertion) (c : com) (Q : Assertion) : Prop :=
∀ st, (P st) → ∃ st', st =[ c ]=> st' ∧ (Q st').
(P : Assertion) (c : com) (Q : Assertion) : Prop :=
∀ st, (P st) → ∃ st', st =[ c ]=> st' ∧ (Q st').
And add a notation for Total Correctness
Hint Unfold valid_total : core.
Declare Scope total_spec_scope.
Notation "| P | c | Q |" := (valid_total P c Q)
(at level 90, c custom com at level 99)
: total_spec_scope.
Open Scope total_spec_scope.
Declare Scope total_spec_scope.
Notation "| P | c | Q |" := (valid_total P c Q)
(at level 90, c custom com at level 99)
: total_spec_scope.
Open Scope total_spec_scope.
We start by proving that Total Correctness is equivalent to having both a
Hoare Triple {P} c {Q} and a proof that the program terminates under the
assumption that the precondition P holds.
Lemma hoare_total P Q c :
|P| c |Q| ↔
({{P}} c {{Q}} ∧
∀ st , P st → (∃ st', st =[ c ]=> st')).
|P| c |Q| ↔
({{P}} c {{Q}} ∧
∀ st , P st → (∃ st', st =[ c ]=> st')).
Proof.
split.
+ intros Ht;split.
× intros st st' Heval1 HPre.
specialize (Ht st HPre) as [st'' (Heval2 & Hq)].
rewrite (ceval_deterministic c _ _ _ Heval1 Heval2).
assumption.
× intros st HPre.
specialize (Ht st HPre) as [st'' (Heval2 & Hq)].
eauto.
+ intros [Hp Hf] st HPre.
specialize (Hf st HPre) as [st' He].
∃ st'. split.
× assumption.
× apply (Hp st);assumption.
Qed.
split.
+ intros Ht;split.
× intros st st' Heval1 HPre.
specialize (Ht st HPre) as [st'' (Heval2 & Hq)].
rewrite (ceval_deterministic c _ _ _ Heval1 Heval2).
assumption.
× intros st HPre.
specialize (Ht st HPre) as [st'' (Heval2 & Hq)].
eauto.
+ intros [Hp Hf] st HPre.
specialize (Hf st HPre) as [st' He].
∃ st'. split.
× assumption.
× apply (Hp st);assumption.
Qed.
Proof Rules
Skip
(total_skip) | |
| P | skip | P | |
Theorem total_skip : ∀ P,
|P| skip |P|.
Proof.
intros P st Pre. ∃ st.
split;[apply E_Skip | assumption].
Qed.
|P| skip |P|.
Proof.
intros P st Pre. ∃ st.
split;[apply E_Skip | assumption].
Qed.
Sequencing
| P | c1 | Q | | |
| Q | c2 | R | | (total_seq) |
| P | c1;c2 | R | |
Theorem total_seq : ∀ P Q R c1 c2,
|Q| c2 |R| →
|P| c1 |Q| →
|P| c1; c2 |R|.
Proof.
intros P Q R c1 c2 H2 H1 st Pre.
specialize (H1 st Pre) as [st'' (He1 & Hq1)].
specialize (H2 st'' Hq1) as [st' (He2 & Hq2)].
∃ st'.
split;[eapply E_Seq;eauto| assumption].
Qed.
|Q| c2 |R| →
|P| c1 |Q| →
|P| c1; c2 |R|.
Proof.
intros P Q R c1 c2 H2 H1 st Pre.
specialize (H1 st Pre) as [st'' (He1 & Hq1)].
specialize (H2 st'' Hq1) as [st' (He2 & Hq2)].
∃ st'.
split;[eapply E_Seq;eauto| assumption].
Qed.
Assignment
(total_asgn) | |
| P[X ⊢> a] | X:= a | P | |
Theorem total_asgn : ∀ Q X (a:aexp),
|Q [X ⊢> a] | X := a |Q|.
Proof.
intros Q X a st HQ.
∃ (X !-> ((a:Aexp) st); st).
split;[apply E_Asgn; reflexivity | assumption].
Qed.
|Q [X ⊢> a] | X := a |Q|.
Proof.
intros Q X a st HQ.
∃ (X !-> ((a:Aexp) st); st).
split;[apply E_Asgn; reflexivity | assumption].
Qed.
Consequence
|P'| c |Q'| | |
P ->> P Q' ->> Q | (total_conseq) |
|P| c |Q| |
Theorem total_consequence_pre : ∀ (P P' Q : Assertion) c,
|P'| c |Q| →
P ->> P' →
|P| c |Q|.
Proof.
unfold valid_total, "->>".
intros P P' Q c Hhoare Himp st Hpre.
apply Hhoare with (st := st).
apply Himp. assumption.
Qed.
Theorem total_consequence_post : ∀ (P Q Q' : Assertion) c,
|P| c |Q'| →
Q' ->> Q →
|P| c |Q|.
Proof.
unfold valid_total, "->>".
intros P Q Q' c Hhoare Himp st Hpre.
specialize (Hhoare st Hpre) as [st' (H1 & H2)].
∃ st'.
split;[assumption | apply Himp;assumption].
Qed.
Theorem total_consequence : ∀ (P P' Q Q' : Assertion) c,
|P'| c |Q'| →
P ->> P' →
Q' ->> Q →
|P| c |Q|.
Proof.
intros P P' Q Q' c Htriple Hpre Hpost.
apply total_consequence_pre with (P' := P').
- apply total_consequence_post with (Q' := Q'); assumption.
- assumption.
Qed.
|P'| c |Q| →
P ->> P' →
|P| c |Q|.
Proof.
unfold valid_total, "->>".
intros P P' Q c Hhoare Himp st Hpre.
apply Hhoare with (st := st).
apply Himp. assumption.
Qed.
Theorem total_consequence_post : ∀ (P Q Q' : Assertion) c,
|P| c |Q'| →
Q' ->> Q →
|P| c |Q|.
Proof.
unfold valid_total, "->>".
intros P Q Q' c Hhoare Himp st Hpre.
specialize (Hhoare st Hpre) as [st' (H1 & H2)].
∃ st'.
split;[assumption | apply Himp;assumption].
Qed.
Theorem total_consequence : ∀ (P P' Q Q' : Assertion) c,
|P'| c |Q'| →
P ->> P' →
Q' ->> Q →
|P| c |Q|.
Proof.
intros P P' Q Q' c Htriple Hpre Hpost.
apply total_consequence_pre with (P' := P').
- apply total_consequence_post with (Q' := Q'); assumption.
- assumption.
Qed.
Conditionals
If command c1 is executed in a state where P ∧ b holds and terminates in a state where Q holds, and, command c2 is execuetd in a state where P ∧ ¬b holds and terminates in a state where Q holds, then executing the conditon in a state where P holds will terminate in a state where R holds:|P /\ b| c1 |Q| | |
|P /\~b| c2 |Q| | (total_If) |
|P| if b then c1 else c2 |Q| |
Theorem total_if : ∀ P Q (b:bexp) c1 c2,
| P ∧ b | c1 |Q| →
| P ∧ ¬ b| c2 |Q| →
|P| if b then c1 else c2 end |Q|.
Proof.
intros P Q b c1 c2 HTrue HFalse st HP.
destruct (beval st b) eqn: Hb.
× assert (HPTrue: P st ∧ bassertion b st);[split;assumption|].
specialize (HTrue st HPTrue) as [st' (He & Hq)].
∃ st'.
split;[apply E_IfTrue;assumption | assumption].
× assert (HPFalse: P st ∧ ¬bassertion b st);
[split;[assumption|apply bexp_eval_false;assumption] |].
specialize (HFalse st HPFalse) as [st' (He & Hq)].
∃ st'.
split;[apply E_IfFalse;assumption | assumption].
Qed.
| P ∧ b | c1 |Q| →
| P ∧ ¬ b| c2 |Q| →
|P| if b then c1 else c2 end |Q|.
Proof.
intros P Q b c1 c2 HTrue HFalse st HP.
destruct (beval st b) eqn: Hb.
× assert (HPTrue: P st ∧ bassertion b st);[split;assumption|].
specialize (HTrue st HPTrue) as [st' (He & Hq)].
∃ st'.
split;[apply E_IfTrue;assumption | assumption].
× assert (HPFalse: P st ∧ ¬bassertion b st);
[split;[assumption|apply bexp_eval_false;assumption] |].
specialize (HFalse st HPFalse) as [st' (He & Hq)].
∃ st'.
split;[apply E_IfFalse;assumption | assumption].
Qed.
While Loops
forall z, |P /\ b /\ z = m | c |P /\ m < z| | (total_while) |
|P| while b do c end |P /\ ~b| |
The measure can be seen as a natural number we assign to a state at every
iteration of the loop. If we make sure that this value strictly decreases
with each iteration, we can be sure that the loop terminates i.e.
the loop can only do a finate number of iteration. This means,
that after a certain number of iteration the loop condition must be false.
We will use this fact in the proof of correctness of the while rule by
defining a unroll function which unroll the loop. By selecting the
right number of unrolling we will be able to
show that the loop condition will get false and thus the loop terminate,
otherwise we have a contradition.
The following definition of the unroll function may look not natural,
but is convenient for proofs by induction.
Fixpoint unroll (n: nat) (b: bexp) (p: com) :=
match n with
| 0 ⇒ CSkip
| S n ⇒ CSeq (unroll n b p) (CIf b p CSkip)
end.
match n with
| 0 ⇒ CSkip
| S n ⇒ CSeq (unroll n b p) (CIf b p CSkip)
end.
We can prove certain properties of the unroll function
that will be important for what follows. One of these properties
is that if the loop body terminates, preserves the loop invariant P, and
a measure decreases, then the command produced by unroll
terminates and preserves the invariant P. In addition, after the command
produced by unroll if the loop condition is true, the measure of the
resulting state is smaller then the measure of the inital state minus
the number of unrolling. This is very important for the proof by
contradiction.
forall z, |P /\ b /\ z = m | c |P /\ m < z| | |
forall z, |P /\ m = z /\ b| unroll n b c |P /\ (b -> m <= z - n)| |
Lemma total_unroll_c P var c b:
(∀ z: nat,
let Pre := (fun st ⇒ P st ∧ var st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ var st' < z) in
|Pre| c |Post|) →
∀ n z,
let Pre := (fun st ⇒ P st ∧ var st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ (bassertion b st' → var st' ≤ z - n)) in
|Pre| (unroll n b c) |Post|.
(∀ z: nat,
let Pre := (fun st ⇒ P st ∧ var st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ var st' < z) in
|Pre| c |Post|) →
∀ n z,
let Pre := (fun st ⇒ P st ∧ var st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ (bassertion b st' → var st' ≤ z - n)) in
|Pre| (unroll n b c) |Post|.
Proof.
intros. unfold Pre, Post. simpl. clear Pre Post.
induction n;intros st HPre.
- ∃ st. simpl.
split.
+ apply E_Skip.
+ destruct HPre.
split;[assumption| intros;subst;Lia.lia].
- specialize (IHn st HPre) as [st' (He & HPre' & Hm')].
destruct (beval st' b) eqn : Hbst'.
+ specialize (Hm' Logic.eq_refl).
assert (HPrex : P st' ∧ var st' = var st' ∧ bassertion b st');
[split;[assumption |]; split;[apply Logic.eq_refl| assumption] | ].
specialize (H (var st') st' HPrex) as [st'' (He'' & Hq'')].
∃ st'' ;simpl.
split.
× eapply E_Seq.
-- apply He.
-- apply E_IfTrue;[assumption|apply He''].
× split;[apply Hq'' | intros; Lia.lia].
+ ∃ st';simpl.
split.
× eapply E_Seq.
-- apply He.
-- apply E_IfFalse ;[assumption| apply E_Skip].
× split.
-- apply HPre'.
-- intros. rewrite H0 in Hbst'. inversion Hbst'.
Qed.
intros. unfold Pre, Post. simpl. clear Pre Post.
induction n;intros st HPre.
- ∃ st. simpl.
split.
+ apply E_Skip.
+ destruct HPre.
split;[assumption| intros;subst;Lia.lia].
- specialize (IHn st HPre) as [st' (He & HPre' & Hm')].
destruct (beval st' b) eqn : Hbst'.
+ specialize (Hm' Logic.eq_refl).
assert (HPrex : P st' ∧ var st' = var st' ∧ bassertion b st');
[split;[assumption |]; split;[apply Logic.eq_refl| assumption] | ].
specialize (H (var st') st' HPrex) as [st'' (He'' & Hq'')].
∃ st'' ;simpl.
split.
× eapply E_Seq.
-- apply He.
-- apply E_IfTrue;[assumption|apply He''].
× split;[apply Hq'' | intros; Lia.lia].
+ ∃ st';simpl.
split.
× eapply E_Seq.
-- apply He.
-- apply E_IfFalse ;[assumption| apply E_Skip].
× split.
-- apply HPre'.
-- intros. rewrite H0 in Hbst'. inversion Hbst'.
Qed.
We can define an auxiliary lemma aux that avoids making an assertion in
the proof, and making the proof shorter.
Lemma aux P (var: measure) z b st :
P st → var st = z → bassertion b st →
P st ∧ var st = z ∧ bassertion b st.
Proof.
split;[assumption |split;assumption].
Qed.
Lemma total_unroll_c' P var c b:
(∀ z: nat,
let Pre := (fun st ⇒ P st ∧ var st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ var st' < z) in
|Pre| c |Post|) →
∀ n z,
let Pre := (fun st ⇒ P st ∧ var st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ (bassertion b st' → var st' ≤ z - n)) in
|Pre| (unroll n b c) |Post|.
P st → var st = z → bassertion b st →
P st ∧ var st = z ∧ bassertion b st.
Proof.
split;[assumption |split;assumption].
Qed.
Lemma total_unroll_c' P var c b:
(∀ z: nat,
let Pre := (fun st ⇒ P st ∧ var st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ var st' < z) in
|Pre| c |Post|) →
∀ n z,
let Pre := (fun st ⇒ P st ∧ var st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ (bassertion b st' → var st' ≤ z - n)) in
|Pre| (unroll n b c) |Post|.
Proof.
intros. unfold Pre, Post. simpl. clear Pre Post.
induction n;intros st HPre.
- ∃ st. simpl.
split.
+ apply E_Skip.
+ destruct HPre.
split;[assumption| intros;subst;Lia.lia].
- specialize (IHn st HPre) as [st' (He & HPre' & Hm')].
destruct (beval st' b) eqn : Hbst'.
+ specialize (Hm' Logic.eq_refl).
specialize (aux _ var (var st') b st' HPre' Logic.eq_refl Hbst') as HPrex.
specialize (H (var st') st' HPrex) as [st'' (He'' & Hq'')].
∃ st'' ;simpl.
split.
× eapply E_Seq.
-- apply He.
-- apply E_IfTrue;[assumption|apply He''].
× split;[apply Hq'' | intros; Lia.lia].
+ ∃ st';simpl.
split.
× eapply E_Seq.
-- apply He.
-- apply E_IfFalse ;[assumption| apply E_Skip].
× split.
-- apply HPre'.
-- intros. rewrite H0 in Hbst'. inversion Hbst'.
Qed.
intros. unfold Pre, Post. simpl. clear Pre Post.
induction n;intros st HPre.
- ∃ st. simpl.
split.
+ apply E_Skip.
+ destruct HPre.
split;[assumption| intros;subst;Lia.lia].
- specialize (IHn st HPre) as [st' (He & HPre' & Hm')].
destruct (beval st' b) eqn : Hbst'.
+ specialize (Hm' Logic.eq_refl).
specialize (aux _ var (var st') b st' HPre' Logic.eq_refl Hbst') as HPrex.
specialize (H (var st') st' HPrex) as [st'' (He'' & Hq'')].
∃ st'' ;simpl.
split.
× eapply E_Seq.
-- apply He.
-- apply E_IfTrue;[assumption|apply He''].
× split;[apply Hq'' | intros; Lia.lia].
+ ∃ st';simpl.
split.
× eapply E_Seq.
-- apply He.
-- apply E_IfFalse ;[assumption| apply E_Skip].
× split.
-- apply HPre'.
-- intros. rewrite H0 in Hbst'. inversion Hbst'.
Qed.
A second property we want to show about the unroll function is stated in
terms of the operational semantics:
Adding the unroll function in front of a while loop with
the same body and condition will not influence the resulting state:
Lemma unroll_while_while n b c: ∀ st st',
st =[ (CSeq (unroll n b c) (CWhile b c)) ]=> st' →
st =[ (CWhile b c ) ]=> st'.
Proof.
induction n;intros.
- simpl in H.
inversion H;subst.
inversion H2;subst.
assumption.
- apply IHn.
inversion H;subst.
inversion H2;subst.
apply (E_Seq _ _ _ _ _ H3).
inversion H7;subst.
+ eapply E_WhileTrue;eauto.
+ inversion H10;subst.
assumption.
Qed.
st =[ (CSeq (unroll n b c) (CWhile b c)) ]=> st' →
st =[ (CWhile b c ) ]=> st'.
Proof.
induction n;intros.
- simpl in H.
inversion H;subst.
inversion H2;subst.
assumption.
- apply IHn.
inversion H;subst.
inversion H2;subst.
apply (E_Seq _ _ _ _ _ H3).
inversion H7;subst.
+ eapply E_WhileTrue;eauto.
+ inversion H10;subst.
assumption.
Qed.
Using the previous two lemmas, we can prove the Total Correctness
rule for while. The proof is done in two steps:
- First, we use lemma hoare_total to split the proof in two parts. The first case is the Hoare rule for while, so we apply the lemma we proved in the previous chapter. It remains to prove that the loop terminates.
- To prove that the loop terminates, we use lemma unroll_while_while to add as many iterations of the loop as the value of measure. Then, we perform a case analysis on the last condition. If the condition is true, we have a contraction, since we have m < 0. If the condition is false, we apply lemma E_WhileFalse from the Imp chapter.
Theorem total_while : ∀ P (b:bexp) c measure,
(∀ z: nat,
let Pre := (fun st ⇒ P st ∧ measure st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ measure st' < z) in
|Pre| c |Post|) →
|P| while b do c end |P ∧ ¬ b|.
(∀ z: nat,
let Pre := (fun st ⇒ P st ∧ measure st = z ∧ bassertion b st) in
let Post := (fun st' ⇒ P st' ∧ measure st' < z) in
|Pre| c |Post|) →
|P| while b do c end |P ∧ ¬ b|.
Proof.
intros P b c measure Hhoare.
apply hoare_total;split.
- assert (HPP: |P ∧ b| c |P|).
{ intros st (HPre & Hb).
specialize (aux _ measure (measure st) _ _ HPre Logic.eq_refl Hb) as HPre'.
specialize (Hhoare (measure st) st HPre') as [st' (He & (HPre'' & _))].
∃ st'. auto.
}
apply hoare_total in HPP as [HPP _ ].
apply hoare_while.
assumption.
- intros st HPre.
destruct (beval st b) eqn: Hb;[| ∃ st; apply E_WhileFalse;assumption].
specialize (aux _ measure (measure st) _ _ HPre Logic.eq_refl Hb) as HPTrue.
specialize (total_unroll_c _ _ _ _ Hhoare (measure st) (measure st) st HPTrue)
as [st' (He & (HPre' & Hm))].
∃ st'.
apply (unroll_while_while (measure st)).
apply (E_Seq _ _ _ _ _ He).
destruct (beval st' b) eqn: Hb'.
+ specialize (Hm Hb').
rewrite sub_diag in Hm.
inversion Hm.
specialize (aux _ _ _ _ _ HPre' H0 Hb') as HP'.
specialize (Hhoare 0 st' HP') as [st'' (_ & ( _ & Hm'' ))].
inversion Hm''.
+ apply E_WhileFalse.
assumption.
Qed.
intros P b c measure Hhoare.
apply hoare_total;split.
- assert (HPP: |P ∧ b| c |P|).
{ intros st (HPre & Hb).
specialize (aux _ measure (measure st) _ _ HPre Logic.eq_refl Hb) as HPre'.
specialize (Hhoare (measure st) st HPre') as [st' (He & (HPre'' & _))].
∃ st'. auto.
}
apply hoare_total in HPP as [HPP _ ].
apply hoare_while.
assumption.
- intros st HPre.
destruct (beval st b) eqn: Hb;[| ∃ st; apply E_WhileFalse;assumption].
specialize (aux _ measure (measure st) _ _ HPre Logic.eq_refl Hb) as HPTrue.
specialize (total_unroll_c _ _ _ _ Hhoare (measure st) (measure st) st HPTrue)
as [st' (He & (HPre' & Hm))].
∃ st'.
apply (unroll_while_while (measure st)).
apply (E_Seq _ _ _ _ _ He).
destruct (beval st' b) eqn: Hb'.
+ specialize (Hm Hb').
rewrite sub_diag in Hm.
inversion Hm.
specialize (aux _ _ _ _ _ HPre' H0 Hb') as HP'.
specialize (Hhoare 0 st' HP') as [st'' (_ & ( _ & Hm'' ))].
inversion Hm''.
+ apply E_WhileFalse.
assumption.
Qed.
Examples
Example while_example :
|X ≤ 3|
while (X ≤ 2) do
X := X + 1
end
|X = 3|.
Proof.
eapply total_consequence_post.
- apply total_while with (measure:=(fun s ⇒ 3 - (s X))).
intros z Pre Post;unfold Pre, Post; clear Pre Post.
eapply total_consequence_pre.
+ apply total_asgn.
+ intros st H; destruct H; destruct H0.
rewrite <- H0. apply leb_le in H1.
split.
× assertion_auto''.
× rewrite t_update_eq.
unfold aeval in ×.
Lia.lia.
- assertion_auto''.
Qed.
|X ≤ 3|
while (X ≤ 2) do
X := X + 1
end
|X = 3|.
Proof.
eapply total_consequence_post.
- apply total_while with (measure:=(fun s ⇒ 3 - (s X))).
intros z Pre Post;unfold Pre, Post; clear Pre Post.
eapply total_consequence_pre.
+ apply total_asgn.
+ intros st H; destruct H; destruct H0.
rewrite <- H0. apply leb_le in H1.
split.
× assertion_auto''.
× rewrite t_update_eq.
unfold aeval in ×.
Lia.lia.
- assertion_auto''.
Qed.
In the following example, we prove that the program computes the greatest
common divisor and terminates.
For the functional correctness part, we take a mathematical definition
of gcd from the standard library as a reference implementation and
proof that location Z contains the greatest common divisor of X and Y.
For the termination part, we can notice that the number of iteration of
the loop can be bounded by X + Y. This is an over-approximation of
the maximum number of iteration of the loop, but has the advantage of
being simple.
Example gcd_example :
|0 < X ∧ 0 < Y|
Z := X;
W := Y;
while (¬ (Z = W)) do
if (Z > W) then
Z := Z - W
else
W := W - Z
end
end
|fun st ⇒ st Z = gcd (st X) (st Y)|.
(* 2025-06-16 19:18 *)
|0 < X ∧ 0 < Y|
Z := X;
W := Y;
while (¬ (Z = W)) do
if (Z > W) then
Z := Z - W
else
W := W - Z
end
end
|fun st ⇒ st Z = gcd (st X) (st Y)|.
Proof.
eapply total_seq.
- eapply total_seq.
+ eapply total_consequence_post.
× apply total_while with
(P:= (fun st ⇒ gcd (st Z) (st W) = gcd (st X) (st Y) ∧
st Z > 0 ∧ st W > 0))
(measure:=(fun st ⇒ (st Z) + (st W))).
intros z Pre Post;unfold Pre, Post; clear Pre Post.
apply total_if.
-- eapply total_consequence_pre.
++ apply total_asgn.
++ intros st H.
destruct H. destruct H. destruct H.
apply negb_true_iff, leb_complete_conv in H0.
split.
** assertion_auto''.
split.
--- rewrite <- H, gcd_comm.
rewrite gcd_sub_diag_r by Lia.lia.
rewrite gcd_comm; reflexivity.
--- assertion_auto''.
** assertion_auto''.
-- eapply total_consequence_pre.
++ apply total_asgn.
++ intros st H.
destruct H. destruct H. destruct H. destruct H1. destruct H2.
apply eq_true_negb_classical, leb_complete in H0.
apply negb_true_iff, eqb_neq in H3.
split.
** assertion_auto''. split.
--- rewrite <- H, gcd_sub_diag_r; assertion_auto''.
--- assertion_auto''.
** simpl.
assertion_auto''.
× intros st H.
destruct H as (H, H1). destruct H. destruct H0.
apply eq_true_negb_classical, eqb_eq in H1.
rewrite <- H.
assertion_auto''.
rewrite H1, gcd_diag; reflexivity.
+ apply total_asgn.
- eapply total_consequence_pre.
+ apply total_asgn.
+ assertion_auto''.
Qed.
eapply total_seq.
- eapply total_seq.
+ eapply total_consequence_post.
× apply total_while with
(P:= (fun st ⇒ gcd (st Z) (st W) = gcd (st X) (st Y) ∧
st Z > 0 ∧ st W > 0))
(measure:=(fun st ⇒ (st Z) + (st W))).
intros z Pre Post;unfold Pre, Post; clear Pre Post.
apply total_if.
-- eapply total_consequence_pre.
++ apply total_asgn.
++ intros st H.
destruct H. destruct H. destruct H.
apply negb_true_iff, leb_complete_conv in H0.
split.
** assertion_auto''.
split.
--- rewrite <- H, gcd_comm.
rewrite gcd_sub_diag_r by Lia.lia.
rewrite gcd_comm; reflexivity.
--- assertion_auto''.
** assertion_auto''.
-- eapply total_consequence_pre.
++ apply total_asgn.
++ intros st H.
destruct H. destruct H. destruct H. destruct H1. destruct H2.
apply eq_true_negb_classical, leb_complete in H0.
apply negb_true_iff, eqb_neq in H3.
split.
** assertion_auto''. split.
--- rewrite <- H, gcd_sub_diag_r; assertion_auto''.
--- assertion_auto''.
** simpl.
assertion_auto''.
× intros st H.
destruct H as (H, H1). destruct H. destruct H0.
apply eq_true_negb_classical, eqb_eq in H1.
rewrite <- H.
assertion_auto''.
rewrite H1, gcd_diag; reflexivity.
+ apply total_asgn.
- eapply total_consequence_pre.
+ apply total_asgn.
+ assertion_auto''.
Qed.
(* 2025-06-16 19:18 *)