Library begcd
Require Import Psatz.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq.
Require Import ssrZ ZArith_ext seq_ext uniq_tac integral_type.
Require Import simu.
Import simu.simu_m.
Module EGCD.
Import syntax_m.seplog_m.assert_m.expr_m.
Import syntax_m.seplog_m.assert_m.
Import syntax_m.seplog_m.
Local Open Scope pseudo_cmd_scope.
Local Open Scope pseudo_expr_scope.
Local Open Scope uniq_scope.
Local Open Scope zarith_ext_scope.
Lemma div_e_exact_full_2 : forall e s,
[ e ]e_ s mod 2 = 0 -> 2 * [ e ./e nat_e 2 ]e_s = [ e ]e_s.
Proof. move=> e s He. by rewrite (Z_div_exact_full_2 ([ e ]e_ s) 2). Qed.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq.
Require Import ssrZ ZArith_ext seq_ext uniq_tac integral_type.
Require Import simu.
Import simu.simu_m.
Module EGCD.
Import syntax_m.seplog_m.assert_m.expr_m.
Import syntax_m.seplog_m.assert_m.
Import syntax_m.seplog_m.
Local Open Scope pseudo_cmd_scope.
Local Open Scope pseudo_expr_scope.
Local Open Scope uniq_scope.
Local Open Scope zarith_ext_scope.
Lemma div_e_exact_full_2 : forall e s,
[ e ]e_ s mod 2 = 0 -> 2 * [ e ./e nat_e 2 ]e_s = [ e ]e_s.
Proof. move=> e s He. by rewrite (Z_div_exact_full_2 ([ e ]e_ s) 2). Qed.
prelude of binary gcd algorithms
Definition prelude x y g :=
While var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O {{
x <- var_e x ./e nat_e 2 ;
y <- var_e y ./e nat_e 2 ;
g <- var_e g \* nat_e 2 }}.
Local Open Scope pseudo_hoare_scope.
While var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O {{
x <- var_e x ./e nat_e 2 ;
y <- var_e y ./e nat_e 2 ;
g <- var_e g \* nat_e 2 }}.
Local Open Scope pseudo_hoare_scope.
binary gcd algorithm, from the Handbook of Applied Cryptography
Module BGCD_HAC.
Definition bgcd g x y t :=
g <- nat_e 1 ;
prelude x y g ;
While var_e x \> nat_e 0 {{
While var_e x \% nat_e 2 \= nat_e 0 {{ x <- var_e x ./e nat_e 2 }} ;
While var_e y \% nat_e 2 \= nat_e 0 {{ y <- var_e y ./e nat_e 2 }} ;
t <- \| (var_e x \- var_e y) \| ./e nat_e 2 ;
If var_e x \>= var_e y Then
x <- var_e t
Else
y <- var_e t
}}.
Section bgcd_hac.
Variables x y g t : nat.
Variables vx vy : Z.
Lemma prelude_triple : uniq(x, y, g) -> 0 <= vx -> 0 <= vy ->
{{ fun s _ => 0 <= [ x ]_s /\ 0 <= [ y ]_s /\ 0 <= [ g ]_s /\
[ x ]_ s * [ g ]_ s = vx /\ [ y ]_ s * [ g ]_ s = vy }}
prelude x y g
{{ fun s _ => 0 <= [ x ]_ s /\ 0 <= [ y ]_ s /\ 0 <= [ g ]_ s /\
[ x ]_ s * [ g ]_ s = vx /\ [ y ]_ s * [ g ]_ s = vy /\
~~ [ var_e x \% nat_e 2 \= nat_e 0 \&& var_e y \% nat_e 2 \= nat_e 0 ]b_ s }}.
Proof.
move=> Hset Hvx Hvy.
apply hoare_prop_m.hoare_while_invariant with (fun s _ =>
0 <= [ x ]_ s /\ 0 <= [ y ]_ s /\ 0 <= [ g ]_ s /\
[ x ]_ s * [g ]_ s = vx /\ [ y ]_ s * [ g ]_ s = vy ).
by move=> s h /= [H1 [H2 [H3 [H4 H5]]]].
by move=> s h /= [[H1 [H2 [H3 [H4 H5]]]] H6].
x <- var_e x ./e nat_e 2
apply hoare_assign with (fun s h => 0 <= [ x ]_s /\ 0 <= [ y ]_s /\ 0 <= [ g ]_s /\
2 * [ x ]_s * [ g ]_s = vx /\ [ y ]_s * [ g ]_s = vy /\ [ y ]_s mod 2 = 0).
move=> s h [[H1 [H2 [H3 [H4 H5]]]] H6].
rewrite /wp_assign.
repeat Store_upd => //.
split; first exact: Z_div_pos.
repeat (split; first by []).
split.
- rewrite div_e_exact_full_2 //; by rewrite /hoare_m.eval_b in H6; omegab.
split; first by [].
- by rewrite /hoare_m.eval_b in H6; omegab.
2 * [ x ]_s * [ g ]_s = vx /\ [ y ]_s * [ g ]_s = vy /\ [ y ]_s mod 2 = 0).
move=> s h [[H1 [H2 [H3 [H4 H5]]]] H6].
rewrite /wp_assign.
repeat Store_upd => //.
split; first exact: Z_div_pos.
repeat (split; first by []).
split.
- rewrite div_e_exact_full_2 //; by rewrite /hoare_m.eval_b in H6; omegab.
split; first by [].
- by rewrite /hoare_m.eval_b in H6; omegab.
y <- var_e y ./e nat_e 2;
apply hoare_assign with (fun s h => 0 <= [ x ]_s /\ 0 <= [ y ]_s /\ 0 <= [ g ]_s /\
2 * [ x ]_s * [ g ]_s = vx /\ 2 * [ y ]_s * [ g ]_ s = vy).
move=> s h [H1 [H2 [H3 [H4 [H5 H6]]]]].
rewrite /wp_assign; repeat Store_upd => //.
split; first by [].
split; first exact: Z_div_pos.
repeat (split; first by []).
by rewrite div_e_exact_full_2.
2 * [ x ]_s * [ g ]_s = vx /\ 2 * [ y ]_s * [ g ]_ s = vy).
move=> s h [H1 [H2 [H3 [H4 [H5 H6]]]]].
rewrite /wp_assign; repeat Store_upd => //.
split; first by [].
split; first exact: Z_div_pos.
repeat (split; first by []).
by rewrite div_e_exact_full_2.
g <- nat_e 2 *e var_e g
apply hoare_assign'.
move=> s h [H1 [H2 [H3 [H4 H5]]]].
rewrite /wp_assign; repeat Store_upd => //.
repeat (split; first by []).
split; first exact: mulZ_ge0.
split; rewrite /= -?H4 -?H5 /ZIT.mul; ring.
Qed.
Lemma bgcd_triple : uniq(x, y, g, t) -> 0 <= vx -> 0 <= vy ->
{{ fun s h => [x]_s = vx /\ [y]_s = vy }}
bgcd g x y t
{{ fun s h => 0 <= [ x ]_s /\ 0 <= [ y ]_s /\ 0 <= [ g ]_s /\
Zis_gcd vx vy ([ g ]_s * [y]_s)}}.
Proof.
move=> Hset Hvx Hvy.
rewrite /bgcd.
move=> s h [H1 [H2 [H3 [H4 H5]]]].
rewrite /wp_assign; repeat Store_upd => //.
repeat (split; first by []).
split; first exact: mulZ_ge0.
split; rewrite /= -?H4 -?H5 /ZIT.mul; ring.
Qed.
Lemma bgcd_triple : uniq(x, y, g, t) -> 0 <= vx -> 0 <= vy ->
{{ fun s h => [x]_s = vx /\ [y]_s = vy }}
bgcd g x y t
{{ fun s h => 0 <= [ x ]_s /\ 0 <= [ y ]_s /\ 0 <= [ g ]_s /\
Zis_gcd vx vy ([ g ]_s * [y]_s)}}.
Proof.
move=> Hset Hvx Hvy.
rewrite /bgcd.
g <- nat_e 1 ;
apply hoare_assign with (fun s _ => [x ]_ s = vx /\ [y ]_ s = vy /\ [g ]_ s = 1).
move=> s h; rewrite /wp_assign; move=> [Hx Hy].
by repeat Store_upd => //.
move=> s h; rewrite /wp_assign; move=> [Hx Hy].
by repeat Store_upd => //.
prelude x y g
apply while.hoare_seq with (fun s _ =>
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s).
have Hset' : uniq(x, y, g).
rewrite [Equality.sort _]/= in Hset *; Uniq_uniq O.
eapply while.hoare_conseq; last exact: (prelude_triple Hset' Hvx Hvy).
- move=> s h /= [H1 [H2 [H3 [H4 [H5 H6]]]]].
repeat (split => //).
+ rewrite -H4 -H5.
apply Zis_gcd_gcd; last first.
rewrite (mulZC [x]_s) (mulZC [y]_s); exact/Zis_gcd_mult/Zgcd_is_gcd.
apply mulZ_ge0 => //; exact: Zgcd_is_pos.
+ by move/negP: H6.
- move=> s h /= [-> [-> ->]]; by rewrite 2!mulZ1.
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s).
have Hset' : uniq(x, y, g).
rewrite [Equality.sort _]/= in Hset *; Uniq_uniq O.
eapply while.hoare_conseq; last exact: (prelude_triple Hset' Hvx Hvy).
- move=> s h /= [H1 [H2 [H3 [H4 [H5 H6]]]]].
repeat (split => //).
+ rewrite -H4 -H5.
apply Zis_gcd_gcd; last first.
rewrite (mulZC [x]_s) (mulZC [y]_s); exact/Zis_gcd_mult/Zgcd_is_gcd.
apply mulZ_ge0 => //; exact: Zgcd_is_pos.
+ by move/negP: H6.
- move=> s h /= [-> [-> ->]]; by rewrite 2!mulZ1.
while (nat_e x >> nat_e 0)
apply hoare_prop_m.hoare_while_invariant with (fun s _ => 0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s)).
- move=> s h [Hx_pos [Hy_pos [Hg_pos [H1 H2]]]].
repeat (split => //).
rewrite /= in H2.
move/negP : H2.
rewrite negb_and.
case/orP ;
move/eqP/not_Zmod_2_Zodd ; by auto.
- move=> s h [[Hx_pos [Hy_pos [Hg_pos [Hparity Hgcd]]]] Hx].
repeat (split; first by []).
have {Hx} : [x ]_ s = 0.
move: Hx.
rewrite /hoare_m.eval_b /= -ZIT.gebNgt.
move/ZIT.geP.
rewrite /ZIT.ge => ?; lia.
rewrite /= => Hx.
rewrite Hx /= Z.abs_eq // in Hgcd.
rewrite -Hgcd; exact: Zgcd_is_gcd.
(Zodd [x]_s \/ Zodd [y]_s) /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s)).
- move=> s h [Hx_pos [Hy_pos [Hg_pos [H1 H2]]]].
repeat (split => //).
rewrite /= in H2.
move/negP : H2.
rewrite negb_and.
case/orP ;
move/eqP/not_Zmod_2_Zodd ; by auto.
- move=> s h [[Hx_pos [Hy_pos [Hg_pos [Hparity Hgcd]]]] Hx].
repeat (split; first by []).
have {Hx} : [x ]_ s = 0.
move: Hx.
rewrite /hoare_m.eval_b /= -ZIT.gebNgt.
move/ZIT.geP.
rewrite /ZIT.ge => ?; lia.
rewrite /= => Hx.
rewrite Hx /= Z.abs_eq // in Hgcd.
rewrite -Hgcd; exact: Zgcd_is_gcd.
while (var_e x mode nat_e 2 =e nat_e 0)
apply while.hoare_seq with (fun s _ => 0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
Zodd [x]_s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s).
- apply hoare_prop_m.hoare_while_invariant with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
(Zodd [x ]_ s \/ Zodd [y ]_ s) /\
Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s).
+ by move=> s h /= [[H2 [H3 [H4 [H5 H6]]]] H1].
+ move=> s h /= [[H2 [H3 [H4 [H5 H6]]]]] //.
by move/eqP/not_Zmod_2_Zodd.
+ apply hoare_assign' => s h /= [[H2 [H3 [H4 [H5 H6]]]] H1].
rewrite /wp_assign; repeat Store_upd => //.
split; first exact: Z_div_pos.
do 2 split => //.
case: H5 => H5.
* move/eqP/Zmod_2_Zeven : H1.
by move/Zeven_not_Zodd.
* split; first by auto.
rewrite /= -Zgcd_even_odd //.
by move/eqP/Zmod_2_Zeven : H1.
- apply while.hoare_seq with (fun s _ => 0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
Zodd [x ]_ s /\ Zodd [y]_s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s).
+ apply hoare_prop_m.hoare_while_invariant with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
Zodd [x ]_ s /\ Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s) => //.
* move=> s h /= [[H2 [H3 [H4 [H5 H6]]]] H1].
repeat (split => //).
by move/eqP/not_Zmod_2_Zodd : H1.
* apply hoare_assign' => s h /= [[H2 [H3 [H4 [H5 H6]]]] H1].
rewrite /wp_assign; repeat Store_upd => //.
split; first by [].
split; first exact: Z_div_pos.
repeat (split; first by []).
rewrite /= (Zgcd_sym [x]_s) -Zgcd_even_odd //.
by rewrite (Zgcd_sym [y]_s).
move/eqP : H1; by move/Zmod_2_Zeven.
+ apply hoare_assign with (fun s _ => (0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
Zodd [x ]_ s /\ Zodd [y]_s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s /\
[t]_s = Z.abs ([x]_s - [y]_s) / 2)).
move=> s h /= [Hx_pos [Hy_pos [Hg_pos [Hx [Hy Hgcd]]]]].
by rewrite /wp_assign; repeat Store_upd.
apply while.hoare_ifte.
+ apply hoare_assign'.
move=> s h /= [[Hx_pos [Hy_pos [Hg_pos [Hx [Hy [Hgcd Ht]]]]]] Hcond].
rewrite /wp_assign; repeat Store_upd => //.
split.
* rewrite /= Ht.
apply Z_div_pos => //; exact/normZ_ge0.
* repeat (split; first by []).
split; first by right.
rewrite /= Ht Z.abs_eq; last first.
rewrite /ZIT.geb in Hcond.
move/geZP : Hcond => ?; lia.
rewrite -Zgcd_even_odd //; last first.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
by rewrite (Zgcd_for_euclid _ _ (-1)).
- apply hoare_assign' => s h /= [[Hx_pos [Hy_pos [Hg_pos [Hx [Hy [Hgcd Ht]]]]]] Hcond].
rewrite /wp_assign; repeat Store_upd => //.
split; first by [].
split.
* rewrite /= Ht.
apply Z_div_pos => //; exact/normZ_ge0.
* split; first by [].
split; first by left.
rewrite /= Ht Zabs_non_eq; last by move/negbTE : Hcond => /geZP ?; lia.
rewrite Zopp_plus_distr oppZK addZC (Zgcd_sym [x]_s) -Zgcd_even_odd //; last first.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
by rewrite (Zgcd_for_euclid _ _ (-1)) (Zgcd_sym [y]_s).
Qed.
End bgcd_hac.
End BGCD_HAC.
Zodd [x]_s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s).
- apply hoare_prop_m.hoare_while_invariant with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
(Zodd [x ]_ s \/ Zodd [y ]_ s) /\
Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s).
+ by move=> s h /= [[H2 [H3 [H4 [H5 H6]]]] H1].
+ move=> s h /= [[H2 [H3 [H4 [H5 H6]]]]] //.
by move/eqP/not_Zmod_2_Zodd.
+ apply hoare_assign' => s h /= [[H2 [H3 [H4 [H5 H6]]]] H1].
rewrite /wp_assign; repeat Store_upd => //.
split; first exact: Z_div_pos.
do 2 split => //.
case: H5 => H5.
* move/eqP/Zmod_2_Zeven : H1.
by move/Zeven_not_Zodd.
* split; first by auto.
rewrite /= -Zgcd_even_odd //.
by move/eqP/Zmod_2_Zeven : H1.
- apply while.hoare_seq with (fun s _ => 0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
Zodd [x ]_ s /\ Zodd [y]_s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s).
+ apply hoare_prop_m.hoare_while_invariant with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
Zodd [x ]_ s /\ Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s) => //.
* move=> s h /= [[H2 [H3 [H4 [H5 H6]]]] H1].
repeat (split => //).
by move/eqP/not_Zmod_2_Zodd : H1.
* apply hoare_assign' => s h /= [[H2 [H3 [H4 [H5 H6]]]] H1].
rewrite /wp_assign; repeat Store_upd => //.
split; first by [].
split; first exact: Z_div_pos.
repeat (split; first by []).
rewrite /= (Zgcd_sym [x]_s) -Zgcd_even_odd //.
by rewrite (Zgcd_sym [y]_s).
move/eqP : H1; by move/Zmod_2_Zeven.
+ apply hoare_assign with (fun s _ => (0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
Zodd [x ]_ s /\ Zodd [y]_s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [x ]_ s [y ]_ s /\
[t]_s = Z.abs ([x]_s - [y]_s) / 2)).
move=> s h /= [Hx_pos [Hy_pos [Hg_pos [Hx [Hy Hgcd]]]]].
by rewrite /wp_assign; repeat Store_upd.
apply while.hoare_ifte.
+ apply hoare_assign'.
move=> s h /= [[Hx_pos [Hy_pos [Hg_pos [Hx [Hy [Hgcd Ht]]]]]] Hcond].
rewrite /wp_assign; repeat Store_upd => //.
split.
* rewrite /= Ht.
apply Z_div_pos => //; exact/normZ_ge0.
* repeat (split; first by []).
split; first by right.
rewrite /= Ht Z.abs_eq; last first.
rewrite /ZIT.geb in Hcond.
move/geZP : Hcond => ?; lia.
rewrite -Zgcd_even_odd //; last first.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
by rewrite (Zgcd_for_euclid _ _ (-1)).
- apply hoare_assign' => s h /= [[Hx_pos [Hy_pos [Hg_pos [Hx [Hy [Hgcd Ht]]]]]] Hcond].
rewrite /wp_assign; repeat Store_upd => //.
split; first by [].
split.
* rewrite /= Ht.
apply Z_div_pos => //; exact/normZ_ge0.
* split; first by [].
split; first by left.
rewrite /= Ht Zabs_non_eq; last by move/negbTE : Hcond => /geZP ?; lia.
rewrite Zopp_plus_distr oppZK addZC (Zgcd_sym [x]_s) -Zgcd_even_odd //; last first.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
by rewrite (Zgcd_for_euclid _ _ (-1)) (Zgcd_sym [y]_s).
Qed.
End bgcd_hac.
End BGCD_HAC.
extended binary gcd algorithm, from the Handbook of Applied Cryptography
Module BEGCD_HAC.
Definition inner_loop u x y A B :=
While var_e u \% nat_e 2 \= nat_e O {{
u <- var_e u ./e nat_e 2 ;
If var_e A \% nat_e 2 \= nat_e O \&& var_e B \% nat_e 2 \= nat_e O Then
A <- var_e A ./e nat_e 2 ;
B <- var_e B ./e nat_e 2
Else
A <- (var_e A \+ var_e y) ./e nat_e 2 ;
B <- (var_e B \- var_e x) ./e nat_e 2
}}.
Definition branch u v A B C D :=
u <- var_e u \- var_e v ;
A <- var_e A \- var_e C ;
B <- var_e B \- var_e D.
Definition outer_loop u v x y A B C D :=
While var_e u \> nat_e 0 {{
inner_loop u x y A B ;
inner_loop v x y C D ;
If var_e u \>= var_e v Then
branch u v A B C D
Else
branch v u C D A B
}}.
Definition begcd g x y u v A B C D :=
g <- nat_e 1 ;
prelude x y g ;
u <- var_e x ;
v <- var_e y ;
A <- nat_e 1 ;
B <- nat_e O ;
C <- nat_e O ;
D <- nat_e 1 ;
outer_loop u v x y A B C D.
Lemma inner_loop_triple (x y g u v : nat) vx vy (A B C D : bipl.var.v) :
uniq(x, y, g, u, v, A, B, C, D) ->
{{fun s _ => 0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[ x ]_ s * [ g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[ A ]_ s * [ x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[ C ]_ s * [ x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [u]_s \/ Zodd [v]_s) }}
inner_loop u x y A B
{{fun s _ => 0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[ A ]_ s * [ x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[ C ]_ s * [ x ]_ s + [ D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [ x ]_s \/ Zodd [ y ]_s) /\
Zodd [ u ]_s }}.
Proof.
move=> Hset.
apply hoare_prop_m.hoare_while_invariant with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [u]_s \/ Zodd [v]_s)).
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]].
by intuition.
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]] H1].
repeat (split => //).
move/ZIT.eqP : H1.
by move/not_Zmod_2_Zodd.
u <- var_e u ./e nat_e 2;
apply hoare_assign with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s * 2 /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Zodd [v]_s).
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]] H1].
rewrite /wp_assign; repeat Store_upd.
move/eqP/Zmod_2_Zeven in H1.
repeat (split => //).
exact: Z_div_pos.
rewrite /= /ZIT.div.
case/Zeven_ex : H1 => u' H1.
rewrite [LHS]/= in H1.
by rewrite H1 (mulZC 2) Z_div_mult_full // -(mulZC 2) H9.
rewrite -Zgcd_even_odd //.
case: H13 => //.
by move/Zeven_not_Zodd.
case: H13 => //.
by move/Zeven_not_Zodd.
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s * 2 /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Zodd [v]_s).
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]] H1].
rewrite /wp_assign; repeat Store_upd.
move/eqP/Zmod_2_Zeven in H1.
repeat (split => //).
exact: Z_div_pos.
rewrite /= /ZIT.div.
case/Zeven_ex : H1 => u' H1.
rewrite [LHS]/= in H1.
by rewrite H1 (mulZC 2) Z_div_mult_full // -(mulZC 2) H9.
rewrite -Zgcd_even_odd //.
case: H13 => //.
by move/Zeven_not_Zodd.
case: H13 => //.
by move/Zeven_not_Zodd.
ifte (var_e A mode nat_e 2 =e nat_e 0 &e var_e B mode nat_e 2 =e nat_e 0)
apply while.hoare_ifte.
-
-
A <- var_e A ./e nat_e 2;
apply hoare_assign with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s * 2 + [B ]_ s * [y ]_ s = [u ]_ s * 2 /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Zodd [v ]_ s /\
eval_b (var_e B \% nat_e 2 \= nat_e 0) s).
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]] H1].
rewrite /wp_assign.
repeat Store_upd.
repeat (split=> //).
case/andP : H1.
move/ZIT.eqP; move/Zmod_2_Zeven; case/Zeven_ex=> a H1a.
move/ZIT.eqP; move/Zmod_2_Zeven; case/Zeven_ex=> b H1b.
by rewrite /= /ZIT.div H1a (mulZC 2) Z_div_mult_full //
-H9 -(mulZC 2) mulZA -H1a.
by case/andP : H1.
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s * 2 + [B ]_ s * [y ]_ s = [u ]_ s * 2 /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Zodd [v ]_ s /\
eval_b (var_e B \% nat_e 2 \= nat_e 0) s).
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]] H1].
rewrite /wp_assign.
repeat Store_upd.
repeat (split=> //).
case/andP : H1.
move/ZIT.eqP; move/Zmod_2_Zeven; case/Zeven_ex=> a H1a.
move/ZIT.eqP; move/Zmod_2_Zeven; case/Zeven_ex=> b H1b.
by rewrite /= /ZIT.div H1a (mulZC 2) Z_div_mult_full //
-H9 -(mulZC 2) mulZA -H1a.
by case/andP : H1.
B <- var_e B ./e nat_e 2
apply hoare_assign'.
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 [H13 H14]]]]]]]]]]]].
rewrite /wp_assign.
repeat Store_upd.
repeat (split => //).
move/ZIT.eqP : H14; move/Zmod_2_Zeven; case/Zeven_ex=> a H14.
rewrite H14 in H9.
ring_simplify in H9.
rewrite -!mulZA -mulZDr in H9.
rewrite /= /ZIT.div H14 (mulZC 2) Z_div_mult_full //.
by eapply eqZ_mul2l; eauto.
by right.
-
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 [H13 H14]]]]]]]]]]]].
rewrite /wp_assign.
repeat Store_upd.
repeat (split => //).
move/ZIT.eqP : H14; move/Zmod_2_Zeven; case/Zeven_ex=> a H14.
rewrite H14 in H9.
ring_simplify in H9.
rewrite -!mulZA -mulZDr in H9.
rewrite /= /ZIT.div H14 (mulZC 2) Z_div_mult_full //.
by eapply eqZ_mul2l; eauto.
by right.
-
A <- (var_e A +e var_e y) ./e nat_e 2;
apply hoare_assign with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s * 2 - [y]_s * [x]_s + [B ]_ s * [y ]_ s = [u ]_ s * 2 /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Zodd [v ]_ s /\
(Zodd ([A]_s *2 - [y]_s) \/ Zodd ([B]_s))).
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]] H1].
rewrite /wp_assign; repeat Store_upd.
repeat (split => //).
+ rewrite /= /ZIT.div /ZIT.add.
rewrite negb_and in H1.
case/orP : H1.
* move/ZIT.eqP; move/not_Zmod_2_Zodd => H1.
rewrite -H9.
ring_simplify.
congr (_ + _).
rewrite -Z_div_exact_full_2 //; first ring.
rewrite (mulZC _ 2) in H9.
move/Zmult_2_Zeven : H9 => /Zeven_plus_inv.
case; case => Y1 Y2.
- case: H12 => H12.
+ move: (Zodd_mult_Zodd _ _ H1 H12); by move/Zeven_not_Zodd.
+ exact/Zeven_Zmod_2/Zodd_plus_Zodd.
- apply Zeven_Zmod_2.
case: H12 => H12.
+ case/Zodd_mult_inv : Y2 => Y2 Y3; exact: Zodd_plus_Zodd.
+ exact: Zodd_plus_Zodd.
* move/ZIT.eqP. move/not_Zmod_2_Zodd => H1.
rewrite -H9.
ring_simplify.
f_equal.
rewrite -Z_div_exact_full_2 //; first ring.
rewrite (mulZC _ 2) in H9.
move/Zmult_2_Zeven : H9 => /Zeven_plus_inv.
case; case=> Y1 Y2.
- case: H12 => H12.
+ case/Zeven_mult_inv : Y1 => Y1; last by move/Zeven_not_Zodd : Y1.
case/Zeven_mult_inv : Y2 => Y2; first by move/Zeven_not_Zodd : Y2.
exact/Zeven_Zmod_2/Zeven_plus_Zeven.
+ move: (Zodd_mult_Zodd _ _ H1 H12).
by move/Zodd_not_Zeven.
- case: H12 => H12.
+ case/Zodd_mult_inv : Y1 => Y1 _.
case/Zodd_mult_inv : Y2 => _ Y2'.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
+ case/Zodd_mult_inv : Y1 => Y1 _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
+ rewrite negb_and in H1.
rewrite /= /ZIT.div /ZIT.add.
case/orP : H1.
- move/ZIT.eqP/not_Zmod_2_Zodd => H1.
case: H12 => H12.
* case: (Zeven_odd_dec [B]_s) => X; auto.
rewrite (mulZC _ 2) in H9.
move/Zmult_2_Zeven : H9.
case/Zeven_plus_inv.
- case=> Y1 Y2.
by move: (Zodd_mult_Zodd _ _ H1 H12) => /Zodd_not_Zeven.
- case=> Y1.
by case/Zodd_mult_inv => /Zodd_not_Zeven.
* left.
apply Zeven_plus_Zodd.
- rewrite mulZC; exact: Zeven_2p.
- exact: Zodd_opp.
- move/ZIT.eqP; by move/not_Zmod_2_Zodd; auto.
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s * 2 - [y]_s * [x]_s + [B ]_ s * [y ]_ s = [u ]_ s * 2 /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Zodd [v ]_ s /\
(Zodd ([A]_s *2 - [y]_s) \/ Zodd ([B]_s))).
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]] H1].
rewrite /wp_assign; repeat Store_upd.
repeat (split => //).
+ rewrite /= /ZIT.div /ZIT.add.
rewrite negb_and in H1.
case/orP : H1.
* move/ZIT.eqP; move/not_Zmod_2_Zodd => H1.
rewrite -H9.
ring_simplify.
congr (_ + _).
rewrite -Z_div_exact_full_2 //; first ring.
rewrite (mulZC _ 2) in H9.
move/Zmult_2_Zeven : H9 => /Zeven_plus_inv.
case; case => Y1 Y2.
- case: H12 => H12.
+ move: (Zodd_mult_Zodd _ _ H1 H12); by move/Zeven_not_Zodd.
+ exact/Zeven_Zmod_2/Zodd_plus_Zodd.
- apply Zeven_Zmod_2.
case: H12 => H12.
+ case/Zodd_mult_inv : Y2 => Y2 Y3; exact: Zodd_plus_Zodd.
+ exact: Zodd_plus_Zodd.
* move/ZIT.eqP. move/not_Zmod_2_Zodd => H1.
rewrite -H9.
ring_simplify.
f_equal.
rewrite -Z_div_exact_full_2 //; first ring.
rewrite (mulZC _ 2) in H9.
move/Zmult_2_Zeven : H9 => /Zeven_plus_inv.
case; case=> Y1 Y2.
- case: H12 => H12.
+ case/Zeven_mult_inv : Y1 => Y1; last by move/Zeven_not_Zodd : Y1.
case/Zeven_mult_inv : Y2 => Y2; first by move/Zeven_not_Zodd : Y2.
exact/Zeven_Zmod_2/Zeven_plus_Zeven.
+ move: (Zodd_mult_Zodd _ _ H1 H12).
by move/Zodd_not_Zeven.
- case: H12 => H12.
+ case/Zodd_mult_inv : Y1 => Y1 _.
case/Zodd_mult_inv : Y2 => _ Y2'.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
+ case/Zodd_mult_inv : Y1 => Y1 _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
+ rewrite negb_and in H1.
rewrite /= /ZIT.div /ZIT.add.
case/orP : H1.
- move/ZIT.eqP/not_Zmod_2_Zodd => H1.
case: H12 => H12.
* case: (Zeven_odd_dec [B]_s) => X; auto.
rewrite (mulZC _ 2) in H9.
move/Zmult_2_Zeven : H9.
case/Zeven_plus_inv.
- case=> Y1 Y2.
by move: (Zodd_mult_Zodd _ _ H1 H12) => /Zodd_not_Zeven.
- case=> Y1.
by case/Zodd_mult_inv => /Zodd_not_Zeven.
* left.
apply Zeven_plus_Zodd.
- rewrite mulZC; exact: Zeven_2p.
- exact: Zodd_opp.
- move/ZIT.eqP; by move/not_Zmod_2_Zodd; auto.
B <- (var_e B .-e var_e x) ./e nat_e 2
apply hoare_assign'.
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 [H13 H14]]]]]]]]]]]].
rewrite /wp_assign; repeat Store_upd.
repeat (split => //).
2: by right.
rewrite /= /ZIT.sub /ZIT.div.
have {}H9 : ([B ]_ s - [x ]_ s) * [y ]_ s = [u ]_ s * 2 - [A ]_ s * [x ]_ s * 2.
rewrite -H9; ring.
rewrite -mulZBl -(mulZC 2) in H9.
case: H12 => H12.
+ case: (Zeven_odd_dec [y]_s) => X.
* case: H14 => H14.
- move: (Zeven_plus_Zeven _ _ (Zeven_2p [A]_s) (Zeven_opp _ X)).
by rewrite mulZC => /Zeven_not_Zodd.
- have Y : Zeven ([B]_s - [x]_s).
apply Zodd_plus_Zodd => //.
exact: Zodd_opp.
case/Zeven_ex : Y => b' Y.
rewrite Y -mulZA in H9.
apply eqZ_mul2l in H9 => //.
rewrite Y (mulZC 2) Z_div_mult_full // H9; ring.
* case: (Zeven_odd_dec ([B]_s - [x]_s)) => Y.
- case/Zeven_ex : Y => b' Y.
rewrite Y -mulZA in H9.
apply eqZ_mul2l in H9 => //.
rewrite Y (mulZC 2) Z_div_mult_full // H9; ring.
- have : Zodd ( ([B ]_ s - [x ]_ s) * [y ]_ s ).
apply Zodd_mult_Zodd => //.
rewrite H9.
move: (Zeven_2p (([u ]_ s - [A ]_ s * [x ]_ s))).
by move/Zeven_not_Zodd.
+ case: (Zeven_odd_dec ([B]_s - [x]_s)) => Y.
* case/Zeven_ex : Y => b' Y.
rewrite Y -mulZA in H9.
apply eqZ_mul2l in H9 => //.
rewrite Y (mulZC 2) Z_div_mult_full // H9; ring.
* have : Zodd ( ([B ]_ s - [x ]_ s) * [y ]_ s ) by apply Zodd_mult_Zodd.
rewrite H9.
move: (Zeven_2p (([u ]_ s - [A ]_ s * [x ]_ s))).
by move/Zeven_not_Zodd.
Qed.
Lemma outer_loop_triple (g x y u v A B C D : nat) vx vy :
uniq(g, x, y, u, v, A, B, C, D) -> 0 <= vx -> 0 <= vy ->
{{ (fun s _ => 0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\ (Zodd [x ]_ s \/ Zodd [y ]_ s))}}
outer_loop u v x y A B C D
{{ (fun s h => (0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\ (Zodd [x ]_ s \/ Zodd [y ]_ s)) /\
~~ [ (var_e u \> nat_e 0) ]b_ s) }}.
Proof.
move=> Hset Hvx Hvy.
rewrite /outer_loop.
apply while.hoare_while.
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 [H13 H14]]]]]]]]]]]].
rewrite /wp_assign; repeat Store_upd.
repeat (split => //).
2: by right.
rewrite /= /ZIT.sub /ZIT.div.
have {}H9 : ([B ]_ s - [x ]_ s) * [y ]_ s = [u ]_ s * 2 - [A ]_ s * [x ]_ s * 2.
rewrite -H9; ring.
rewrite -mulZBl -(mulZC 2) in H9.
case: H12 => H12.
+ case: (Zeven_odd_dec [y]_s) => X.
* case: H14 => H14.
- move: (Zeven_plus_Zeven _ _ (Zeven_2p [A]_s) (Zeven_opp _ X)).
by rewrite mulZC => /Zeven_not_Zodd.
- have Y : Zeven ([B]_s - [x]_s).
apply Zodd_plus_Zodd => //.
exact: Zodd_opp.
case/Zeven_ex : Y => b' Y.
rewrite Y -mulZA in H9.
apply eqZ_mul2l in H9 => //.
rewrite Y (mulZC 2) Z_div_mult_full // H9; ring.
* case: (Zeven_odd_dec ([B]_s - [x]_s)) => Y.
- case/Zeven_ex : Y => b' Y.
rewrite Y -mulZA in H9.
apply eqZ_mul2l in H9 => //.
rewrite Y (mulZC 2) Z_div_mult_full // H9; ring.
- have : Zodd ( ([B ]_ s - [x ]_ s) * [y ]_ s ).
apply Zodd_mult_Zodd => //.
rewrite H9.
move: (Zeven_2p (([u ]_ s - [A ]_ s * [x ]_ s))).
by move/Zeven_not_Zodd.
+ case: (Zeven_odd_dec ([B]_s - [x]_s)) => Y.
* case/Zeven_ex : Y => b' Y.
rewrite Y -mulZA in H9.
apply eqZ_mul2l in H9 => //.
rewrite Y (mulZC 2) Z_div_mult_full // H9; ring.
* have : Zodd ( ([B ]_ s - [x ]_ s) * [y ]_ s ) by apply Zodd_mult_Zodd.
rewrite H9.
move: (Zeven_2p (([u ]_ s - [A ]_ s * [x ]_ s))).
by move/Zeven_not_Zodd.
Qed.
Lemma outer_loop_triple (g x y u v A B C D : nat) vx vy :
uniq(g, x, y, u, v, A, B, C, D) -> 0 <= vx -> 0 <= vy ->
{{ (fun s _ => 0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\ (Zodd [x ]_ s \/ Zodd [y ]_ s))}}
outer_loop u v x y A B C D
{{ (fun s h => (0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\
0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\ (Zodd [x ]_ s \/ Zodd [y ]_ s)) /\
~~ [ (var_e u \> nat_e 0) ]b_ s) }}.
Proof.
move=> Hset Hvx Hvy.
rewrite /outer_loop.
apply while.hoare_while.
while (var_e u mode nat_e 2 =e nat_e 0)
apply while.hoare_seq with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\
[y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Zodd [u]_s).
eapply hoare_prop_m.hoare_stren; last first.
have Hset' : uniq(x, y, g, u, v, A, B, C, D).
rewrite [Equality.sort _]/= in Hset *. by Uniq_uniq O.
exact: (inner_loop_triple x y g u v vx vy A B C D Hset').
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 H12]]]]]]]]]] H1]; by intuition.
apply hoare_prop_m.hoare_stren with (fun s _ =>
(0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [v ]_ s [u ]_ s) /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v]_s \/ Zodd [u]_s)).
move=> s h /=.
rewrite (Zgcd_sym [u]_s); by intuition.
have {Hset}Hset' : uniq(x, y, g, v, u, C, D, A, B).
rewrite [Equality.sort _]/= in Hset *; by Uniq_uniq O.
move: (inner_loop_triple x y g v u vx vy C D A B Hset') => Hi.
eapply while.hoare_seq.
eapply hoare_prop_m.hoare_stren; last exact: Hi.
move=> s h /=; by intuition.
apply while.hoare_ifte.
-
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [u ]_ s /\ 0 <= [v ]_ s /\
[x ]_ s * [g ]_ s = vx /\
[y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
Zodd [u]_s).
eapply hoare_prop_m.hoare_stren; last first.
have Hset' : uniq(x, y, g, u, v, A, B, C, D).
rewrite [Equality.sort _]/= in Hset *. by Uniq_uniq O.
exact: (inner_loop_triple x y g u v vx vy A B C D Hset').
move=> s h /= [[H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 H12]]]]]]]]]] H1]; by intuition.
apply hoare_prop_m.hoare_stren with (fun s _ =>
(0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [v ]_ s [u ]_ s) /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v]_s \/ Zodd [u]_s)).
move=> s h /=.
rewrite (Zgcd_sym [u]_s); by intuition.
have {Hset}Hset' : uniq(x, y, g, v, u, C, D, A, B).
rewrite [Equality.sort _]/= in Hset *; by Uniq_uniq O.
move: (inner_loop_triple x y g v u vx vy C D A B Hset') => Hi.
eapply while.hoare_seq.
eapply hoare_prop_m.hoare_stren; last exact: Hi.
move=> s h /=; by intuition.
apply while.hoare_ifte.
-
u <- var_e u .-e var_e v;
apply hoare_assign with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
([A ]_ s - [C]_s)* [x ]_ s + ([B ]_ s - [D]_s)* [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v]_s \/ Zodd [u]_s)).
move=> s h /= [[H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 [H13 H14]]]]]]]]]]] H2].
rewrite /wp_assign; repeat Store_upd => //.
repeat (split => //).
move/geZP in H2.
rewrite /=; omegab.
rewrite /= /ZIT.sub -H10 -H11; ring.
by rewrite /= /ZIT.sub (Zgcd_for_euclid _ _ (-1)) (Zgcd_sym [u]_s).
rewrite /= /ZIT.sub.
case: (Zeven_odd_dec [v]_s) => ?; by auto.
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
([A ]_ s - [C]_s)* [x ]_ s + ([B ]_ s - [D]_s)* [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v]_s \/ Zodd [u]_s)).
move=> s h /= [[H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 [H13 H14]]]]]]]]]]] H2].
rewrite /wp_assign; repeat Store_upd => //.
repeat (split => //).
move/geZP in H2.
rewrite /=; omegab.
rewrite /= /ZIT.sub -H10 -H11; ring.
by rewrite /= /ZIT.sub (Zgcd_for_euclid _ _ (-1)) (Zgcd_sym [u]_s).
rewrite /= /ZIT.sub.
case: (Zeven_odd_dec [v]_s) => ?; by auto.
A <- var_e A .-e var_e C;
apply hoare_assign with (fun s _ =>
(0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
([A ]_ s)* [x ]_ s + ([B ]_ s - [D]_s)* [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v ]_ s \/ Zodd [u ]_ s))).
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 H12]]]]]]]]]].
by rewrite /wp_assign; repeat Store_upd.
(0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
([A ]_ s)* [x ]_ s + ([B ]_ s - [D]_s)* [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + [D ]_ s * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v ]_ s \/ Zodd [u ]_ s))).
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 H12]]]]]]]]]].
by rewrite /wp_assign; repeat Store_upd.
B <- var_e B .-e var_e D
apply hoare_assign'.
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 H9]]]]]]].
rewrite /wp_assign; repeat Store_upd => //.
tauto.
-
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 H9]]]]]]].
rewrite /wp_assign; repeat Store_upd => //.
tauto.
-
v <- var_e v .-e var_e u;
apply hoare_assign with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
([C ]_ s - [A]_s) * [x ]_ s + ([D ]_ s - [B]_s) * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v ]_ s \/ Zodd [u ]_ s)).
move=> s h /= [[H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 [H13 H14]]]]]]]]]]] H2].
rewrite /wp_assign; repeat Store_upd => //.
repeat (split => //).
move/negbTE : H2 => /geZP H2.
rewrite /=; omegab.
rewrite /= /ZIT.sub -H10 -H11; ring.
by rewrite /= /ZIT.sub (Zgcd_sym [u]_s) (Zgcd_for_euclid _ _ (-1)).
case: (Zeven_odd_dec [u]_s) => Htmp; last by right.
left; apply Zodd_plus_Zeven => //.
by destruct ([u]_s).
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
([C ]_ s - [A]_s) * [x ]_ s + ([D ]_ s - [B]_s) * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v ]_ s \/ Zodd [u ]_ s)).
move=> s h /= [[H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 [H13 H14]]]]]]]]]]] H2].
rewrite /wp_assign; repeat Store_upd => //.
repeat (split => //).
move/negbTE : H2 => /geZP H2.
rewrite /=; omegab.
rewrite /= /ZIT.sub -H10 -H11; ring.
by rewrite /= /ZIT.sub (Zgcd_sym [u]_s) (Zgcd_for_euclid _ _ (-1)).
case: (Zeven_odd_dec [u]_s) => Htmp; last by right.
left; apply Zodd_plus_Zeven => //.
by destruct ([u]_s).
C <- var_e C .-e var_e A;
apply hoare_assign with (fun s _ =>
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + ([D ]_ s - [B]_s) * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v ]_ s \/ Zodd [u ]_ s)).
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]].
by rewrite /wp_assign; repeat Store_upd.
0 <= [x ]_ s /\ 0 <= [y ]_ s /\ 0 <= [g ]_ s /\ 0 <= [v ]_ s /\ 0 <= [u ]_ s /\
[x ]_ s * [g ]_ s = vx /\ [y ]_ s * [g ]_ s = vy /\
[A ]_ s * [x ]_ s + [B ]_ s * [y ]_ s = [u ]_ s /\
[C ]_ s * [x ]_ s + ([D ]_ s - [B]_s) * [y ]_ s = [v ]_ s /\
Z.gcd vx vy = [g ]_ s * Z.gcd [u ]_ s [v ]_ s /\
(Zodd [x]_s \/ Zodd [y]_s) /\
(Zodd [v ]_ s \/ Zodd [u ]_ s)).
move=> s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 [H9 [H10 [H11 [H12 H13]]]]]]]]]]].
by rewrite /wp_assign; repeat Store_upd.
D <- var_e D .-e var_e B
apply hoare_assign' => s h /= [H2 [H3 [H4 [H5 [H6 [H7 [H8 H9]]]]]]].
rewrite /wp_assign; repeat Store_upd => //; by intuition.
Qed.
Lemma begcd_triple (g x y u v A B C D : nat) :
uniq(g, x, y, u, v, A, B, C, D) ->
forall vx vy, 0 <= vx -> 0 <= vy ->
{{ fun s h => [x]_s = vx /\ [y]_s = vy }}
begcd g x y u v A B C D
{{ fun s h => [C]_s * vx + [D]_s * vy = [g]_s * [v]_s /\
Zis_gcd vx vy ([g]_s * [v]_s)}}.
Proof.
move=> Hset vx vy Hvx Hvy.
rewrite /begcd.
rewrite /wp_assign; repeat Store_upd => //; by intuition.
Qed.
Lemma begcd_triple (g x y u v A B C D : nat) :
uniq(g, x, y, u, v, A, B, C, D) ->
forall vx vy, 0 <= vx -> 0 <= vy ->
{{ fun s h => [x]_s = vx /\ [y]_s = vy }}
begcd g x y u v A B C D
{{ fun s h => [C]_s * vx + [D]_s * vy = [g]_s * [v]_s /\
Zis_gcd vx vy ([g]_s * [v]_s)}}.
Proof.
move=> Hset vx vy Hvx Hvy.
rewrite /begcd.
g <- nat_e 1 ;
apply hoare_assign with (fun s h => [x]_s = vx /\ [y]_s = vy /\ [g]_s = 1).
move=> s h [Hx Hy].
by rewrite /wp_assign; repeat Store_upd => //.
move=> s h [Hx Hy].
by rewrite /wp_assign; repeat Store_upd => //.
prelude x y g ;
apply while.hoare_seq with (fun s _ =>
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s).
have Hset' : uniq(x, y, g).
rewrite [Equality.sort _]/= in Hset *; by Uniq_uniq O.
eapply while.hoare_conseq; last exact: (BGCD_HAC.prelude_triple _ _ _ _ _ Hset' Hvx Hvy).
- move=> s h /= [H1 [H2 [H3 [x_g [y_g H6]]]]].
repeat (split; first by []).
split; last by move/negP: H6.
rewrite -x_g -y_g.
apply Zis_gcd_gcd; last first.
rewrite (mulZC [x]_s) (mulZC [y]_s); exact/Zis_gcd_mult/Zgcd_is_gcd.
apply mulZ_ge0 => //; exact: Zgcd_is_pos.
- move=> s h /= [-> [-> ->]]; by rewrite 2!mulZ1.
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s).
have Hset' : uniq(x, y, g).
rewrite [Equality.sort _]/= in Hset *; by Uniq_uniq O.
eapply while.hoare_conseq; last exact: (BGCD_HAC.prelude_triple _ _ _ _ _ Hset' Hvx Hvy).
- move=> s h /= [H1 [H2 [H3 [x_g [y_g H6]]]]].
repeat (split; first by []).
split; last by move/negP: H6.
rewrite -x_g -y_g.
apply Zis_gcd_gcd; last first.
rewrite (mulZC [x]_s) (mulZC [y]_s); exact/Zis_gcd_mult/Zgcd_is_gcd.
apply mulZ_ge0 => //; exact: Zgcd_is_pos.
- move=> s h /= [-> [-> ->]]; by rewrite 2!mulZ1.
u <- var_e x ;
apply hoare_assign with (fun s _ =>
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 H5]]]]]]; by rewrite /wp_assign; repeat Store_upd.
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 H5]]]]]]; by rewrite /wp_assign; repeat Store_upd.
v <- var_e y ;
apply hoare_assign with (fun s _ =>
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 Hu]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 Hu]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
A <- nat_e 1 ;
apply hoare_assign with (fun s _ =>
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s /\ [A]_s = 1).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 [Hu Hv]]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s /\ [A]_s = 1).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 [Hu Hv]]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
B <- nat_e O ;
apply hoare_assign with (fun s _ =>
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s /\ [A]_s = 1 /\ [B]_s = 0).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 [Hu [Hv HA]]]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s /\ [A]_s = 1 /\ [B]_s = 0).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 [Hu [Hv HA]]]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
C <- nat_e O ;
apply hoare_assign with (fun s _ =>
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s /\ [A]_s = 1 /\ [B]_s = 0 /\ [C]_s = 0).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 [Hu [Hv [HA HB]]]]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s /\ [A]_s = 1 /\ [B]_s = 0 /\ [C]_s = 0).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 [Hu [Hv [HA HB]]]]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
D <- nat_e 1 ;
apply hoare_assign with (fun s _ =>
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s /\ [A]_s = 1 /\ [B]_s = 0 /\ [C]_s = 0 /\ [D]_s = 1).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 [Hu [Hv [HA [HB HC]]]]]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
0 <= [x]_s /\ 0 <= [y]_s /\ 0 <= [g]_s /\
[x]_ s * [g]_s = vx /\ [y]_s * [g]_s = vy /\
Z.gcd vx vy = [g]_s * Z.gcd ([x]_s) ([y]_s) /\
~ [ var_e x \% nat_e 2 \= nat_e O \&& var_e y \% nat_e 2 \= nat_e O ]b_ s /\
[u]_s = [x]_s /\ [v]_s = [y]_s /\ [A]_s = 1 /\ [B]_s = 0 /\ [C]_s = 0 /\ [D]_s = 1).
move=> s h /= [H1 [H2 [H3 [Hxg [Hyg [H4 [H5 [Hu [Hv [HA [HB HC]]]]]]]]]]]; by rewrite /wp_assign; repeat Store_upd.
outer_loop
eapply while.hoare_conseq; last exact: (outer_loop_triple g x y u v A B C D vx vy Hset Hvx Hvy).
- move=> s h /= [[Hx [Hy [Hg [Hu_pos [Hv_pos [Hxg [Hyg [HAB [HCD [Hgcd Hparity]]]]]]]]]] Heq].
have {}Heq : [u]_s = 0.
move: Heq.
rewrite -ZIT.gebNgt => /ZIT.geP.
rewrite /ZIT.ge => ?; lia.
rewrite Heq /= Z.abs_eq // in Hgcd.
split; [rewrite -Hxg -Hyg -HCD; ring | rewrite -Hgcd; exact: Zgcd_is_gcd].
- move=> s h /= [Hx [Hy [Hg [Hxg [Hyg [Hgcd [Hcond [Hu [Hv [HA [HB [HC HD]]]]]]]]]]]].
rewrite HA HB HC HD 2!mul1Z 2!mul0Z addZ0 add0Z Hu Hv.
move/negP : Hcond.
rewrite negb_and.
case/orP; move/ZIT.eqP; move/not_Zmod_2_Zodd; by intuition.
Qed.
End BEGCD_HAC.
Definition uivi_init u v u1 u2 u3 v1 v2 v3 s :=
[u1]_s = 1 /\ [u2]_s = 0 /\[u3]_s = [u]_s /\
[v1]_s = [v]_s /\ [v2]_s = 1 - [u]_s /\ [v3]_s = [v]_s.
Definition ti_init u v t1 t2 t3 s :=
(Zodd [u]_s -> [t1]_s = 0 /\ [t2]_s = -1 /\ [t3]_s = -[v]_s) /\
(Zeven [u]_s -> [t1]_s = 1 /\ [t2]_s = 0 /\ [t3]_s = [u]_s).
Definition uv_init vu vv u v st := [u]_ st = vu /\ [v]_ st = vv.
Definition C1 vu vv u v g s := uv_init vu vv u v s /\ [g]_s = 1.
Definition C2 vu vv u v g s := 0 < [u]_s /\ 0 < [v]_s /\ 0 < [g]_s /\
[u]_ s * [g]_s = vu /\ [v]_s * [g]_s = vv.
Definition C3 vu vv u v g s :=
Z.gcd vu vv = [g]_s * Z.gcd [u]_s [v]_s /\
~ [ var_e u \% nat_e 2 \= nat_e O \&& var_e v \% nat_e 2 \= nat_e O ]b_ s.
Definition C4 u3 v3 t3 s := exists k, ([t3]_s * 2 ^^ k = - [v3]_s /\ Zodd [u3]_s) \/
([t3]_s * 2 ^^ k = [u3]_s /\ Zodd [v3]_s) \/
([t3]_s * 2 ^^ k = ([u3]_s - [v3]_s) /\ (Zodd [v3]_s \/ Zodd [u3]_s)).
Definition C5 u3 v3 s := 0 < [u3]_s /\ 0 < [v3]_s.
Definition CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s :=
[u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s.
- move=> s h /= [[Hx [Hy [Hg [Hu_pos [Hv_pos [Hxg [Hyg [HAB [HCD [Hgcd Hparity]]]]]]]]]] Heq].
have {}Heq : [u]_s = 0.
move: Heq.
rewrite -ZIT.gebNgt => /ZIT.geP.
rewrite /ZIT.ge => ?; lia.
rewrite Heq /= Z.abs_eq // in Hgcd.
split; [rewrite -Hxg -Hyg -HCD; ring | rewrite -Hgcd; exact: Zgcd_is_gcd].
- move=> s h /= [Hx [Hy [Hg [Hxg [Hyg [Hgcd [Hcond [Hu [Hv [HA [HB [HC HD]]]]]]]]]]]].
rewrite HA HB HC HD 2!mul1Z 2!mul0Z addZ0 add0Z Hu Hv.
move/negP : Hcond.
rewrite negb_and.
case/orP; move/ZIT.eqP; move/not_Zmod_2_Zodd; by intuition.
Qed.
End BEGCD_HAC.
Definition uivi_init u v u1 u2 u3 v1 v2 v3 s :=
[u1]_s = 1 /\ [u2]_s = 0 /\[u3]_s = [u]_s /\
[v1]_s = [v]_s /\ [v2]_s = 1 - [u]_s /\ [v3]_s = [v]_s.
Definition ti_init u v t1 t2 t3 s :=
(Zodd [u]_s -> [t1]_s = 0 /\ [t2]_s = -1 /\ [t3]_s = -[v]_s) /\
(Zeven [u]_s -> [t1]_s = 1 /\ [t2]_s = 0 /\ [t3]_s = [u]_s).
Definition uv_init vu vv u v st := [u]_ st = vu /\ [v]_ st = vv.
Definition C1 vu vv u v g s := uv_init vu vv u v s /\ [g]_s = 1.
Definition C2 vu vv u v g s := 0 < [u]_s /\ 0 < [v]_s /\ 0 < [g]_s /\
[u]_ s * [g]_s = vu /\ [v]_s * [g]_s = vv.
Definition C3 vu vv u v g s :=
Z.gcd vu vv = [g]_s * Z.gcd [u]_s [v]_s /\
~ [ var_e u \% nat_e 2 \= nat_e O \&& var_e v \% nat_e 2 \= nat_e O ]b_ s.
Definition C4 u3 v3 t3 s := exists k, ([t3]_s * 2 ^^ k = - [v3]_s /\ Zodd [u3]_s) \/
([t3]_s * 2 ^^ k = [u3]_s /\ Zodd [v3]_s) \/
([t3]_s * 2 ^^ k = ([u3]_s - [v3]_s) /\ (Zodd [v3]_s \/ Zodd [u3]_s)).
Definition C5 u3 v3 s := 0 < [u3]_s /\ 0 < [v3]_s.
Definition CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s :=
[u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s.
binary extended gcd algorithm from The Art of Computer Programming
Module BEGCD_TAOCP.
Definition init u v u1 u2 u3 v1 v2 v3 t1 t2 t3 :=
(u1 <- nat_e 1 ;
u2 <- nat_e 0 ;
u3 <- var_e u ;
v1 <- var_e v ;
v2 <- nat_e 1 \- var_e u ;
v3 <- var_e v) ;
If var_e u \% nat_e 2 \= nat_e 1 Then
t1 <- nat_e 0 ;
t2 <- cst_e (-1) ;
t3 <- .--e var_e v
Else
(t1 <- nat_e 1 ;
t2 <- nat_e 0 ;
t3 <- var_e u).
Definition halve u v t1 t2 t3 :=
If var_e t1 \% nat_e 2 \= nat_e 0 \&& var_e t2 \% nat_e 2 \= nat_e 0 Then
t1 <- var_e t1 ./e nat_e 2 ;
t2 <- var_e t2 ./e nat_e 2 ;
t3 <- var_e t3 ./e nat_e 2
Else
(t1 <- (var_e t1 \+ var_e v) ./e nat_e 2 ;
t2 <- (var_e t2 \- var_e u) ./e nat_e 2 ;
t3 <- var_e t3 ./e nat_e 2).
Definition reset u v u1 u2 u3 v1 v2 v3 t1 t2 t3 :=
If var_e t3 \>= nat_e 0 Then
u1 <- var_e t1 ;
u2 <- var_e t2 ;
u3 <- var_e t3
Else
v1 <- var_e v \- var_e t1 ;
v2 <- .--e (var_e u \+ var_e t2) ;
v3 <- .--e var_e t3.
Definition subtract u v u1 u2 u3 v1 v2 v3 t1 t2 t3 :=
(t1 <- var_e u1 \- var_e v1 ;
t2 <- var_e u2 \- var_e v2 ;
t3 <- var_e u3 \- var_e v3) ;
If nat_e 0 \>= var_e t1 Then
t1 <- var_e t1 \+ var_e v ;
t2 <- var_e t2 \- var_e u
Else
skip.
Definition begcd g u v u1 u2 u3 v1 v2 v3 t1 t2 t3 :=
g <- nat_e 1 ;
prelude u v g ;
init u v u1 u2 u3 v1 v2 v3 t1 t2 t3 ;
While var_e t3 \!= nat_e 0 {{
While var_e t3 \% nat_e 2 \= nat_e O {{
halve u v t1 t2 t3 }} ;
reset u v u1 u2 u3 v1 v2 v3 t1 t2 t3 ;
subtract u v u1 u2 u3 v1 v2 v3 t1 t2 t3 }}.
End BEGCD_TAOCP.
Functional correctness only
Module BEGCD_TAOCP_FUN_COR.
Import BEGCD_TAOCP.
Section begcd_taocp_fun_cor.
Variables g u v u1 u2 u3 v1 v2 v3 t1 t2 t3 : nat.
Variables vv vu : Z.
Lemma triple_intermediate :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s _ => C2 vu vv u v g s /\
C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\
ti_init u v t1 t2 t3 s }}
While var_e t3 \!= nat_e 0 {{
(While var_e t3 \% nat_e 2 \= nat_e 0 {{ halve u v t1 t2 t3 }};
reset u v u1 u2 u3 v1 v2 v3 t1 t2 t3;
subtract u v u1 u2 u3 v1 v2 v3 t1 t2 t3) }}
{{ fun s _ => vu * [u1 ]_ s + vv * [u2 ]_ s = [g ]_ s * [u3 ]_ s /\
Z.gcd vu vv = [g ]_ s * [u3 ]_ s }}.
Proof.
move=> Hset Hvv Hvu.
while.while (var_e t3 <>e nat_e 0)
apply hoare_prop_m.hoare_while_invariant with (fun s _ =>
C2 vu vv u v g s /\
(Zodd [u]_s \/ Zodd [v]_s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u]_s [v]_s = Z.gcd [u3]_s [v3]_s).
rewrite /while.entails => s h.
case => [[Hu [Hv [Hg [u_g v_g]]] [[Hgcd Hcond] [[Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]]]]] Ht].
rewrite /CVectors Hu1 Hu2 Hu3 Hv1 Hv2 Hv3.
repeat (split; first tauto).
case: (Zeven_odd_dec [u]_s) => u_parity.
- case: Ht => _.
move/(_ u_parity) => [Ht1 [Ht2 Ht3]].
rewrite /C2 /C4 /C5 Ht1 Ht2 Ht3 Hu3 Hv3 mulZ1 mulZ0 addZ0.
split; first by [].
split.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem /=.
case/orP; move/eqP => X.
+ left; exact: not_Zmod_2_Zodd.
+ right; exact: not_Zmod_2_Zodd.
split.
repeat (split; first tauto).
ring.
split; last by [].
exists O; rewrite [_ ^^ _]/= !mulZ1; right; left.
split; first by reflexivity.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem.
case/orP; move/eqP.
+ move/not_Zmod_2_Zodd; by move/Zodd_not_Zeven.
+ by move/not_Zmod_2_Zodd.
- case: Ht.
move/(_ u_parity) => [Ht1 [Ht2 Ht3]] _.
rewrite /C2 /C4 /C5 Ht1 Ht2 Ht3 Hu3 Hv3 mulZ1 mulZ0 add0Z mulZ0 addZ0.
split; first by [].
split.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem /=.
case/orP; move/eqP => X.
* left; exact: not_Zmod_2_Zodd.
* right; exact: not_Zmod_2_Zodd.
split.
split; first by ring.
split; by [ | ring].
split; last by [].
exists O; rewrite [_ ^^ _]/= !mulZ1; tauto.
- rewrite /while.entails => s h.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] H14]]]]] H1].
split; first by rewrite -u_g -v_g -Hui; ring.
rewrite /hoare_m.eval_b /= /ZIT.eqb in H1.
move/negPn/eqP in H1.
case: H10 => k [H10|[H10 | H10]].
+ have abs : [v3 ]_ s = 0.
move: (expZ_gt0 k) => X.
case: H10 => H10 H10'.
rewrite H1 mul0Z in H10; lia.
rewrite abs Zgcd_0 geZ0_norm in H14; last lia.
rewrite -H14 -Zgcd_mult; last lia.
by rewrite mulZC u_g mulZC v_g.
+ have abs : [u ]_ s = 0 by rewrite H1 mul0Z in H10; lia.
rewrite abs in Hu; by apply ltZZ in Hu.
+ have abs : [u3 ]_ s = [v3 ]_ s.
rewrite H1 mul0Z in H10; lia.
rewrite -abs Zgcd_same in H14; last lia.
rewrite -H14 -u_g -v_g -Zgcd_mult; last lia.
by rewrite (mulZC [u ]_ s) (mulZC [v ]_ s).
apply while.hoare_seq with (fun s h =>
C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
Zodd [t3]_s ).
rewrite /halve.
apply hoare_prop_m.hoare_while_invariant with (fun s h =>
C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3]_s <> 0).
move=> s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] H14]]]]] H1].
repeat (split => //).
by move/eqP : H1.
move=> s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H14 H15]]]]]] H1].
repeat (split; first by []).
split.
rewrite /C2 -u_g -v_g -H14 -Zgcd_mult; last lia.
f_equal; by rewrite mulZC.
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem in H1.
by move/eqP/not_Zmod_2_Zodd : H1.
apply while.hoare_ifte.
- apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * 2 * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3 ]_ s <> 0 /\
Zeven [t3]_s /\
Zeven [t2]_s).
move=> s h /=.
case => [[[[Hu [Hv [Hg [u_g v_g]]]] [H7 [[Hti [Hui Hvi]] [H11 [[Hu3 Hv3] [H14 H16]]]]]] H3] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite -mulZA div_e_exact_full_2 //.
rewrite /hoare_m.eval_b /= in H1.
case/andP : H1 => H1 _.
rewrite /ZIT.eqb /ZIT.rem /= in H1.
by move/eqP : H1.
repeat (split; first by []).
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem /= in H1, H3.
move/eqP in H3.
case/andP : H1 => _ /eqP H1.
split; exact: Zmod_2_Zeven.
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * 2 * [t1 ]_ s + [v ]_ s * 2 * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3 ]_ s <> 0 /\ Zeven [t3 ]_ s ).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [H13 [H14 H16]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first tauto).
split; last by [].
rewrite -(mulZA [v]_s) div_e_exact_full_2 //; exact: Zeven_Zmod_2.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]] [H5 [[Hti [Hui Hvi] [H9 [[Hu3 Hv3] [H15 [H16 H17]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite /= -Hti /ZIT.div.
set tmp := _ + [v]_s * 2 * _ .
have -> : tmp = ([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s) * 2 by rewrite /tmp; ring.
by rewrite Z_div_mult_full.
repeat (split; first by []).
split.
case/Zeven_ex : H17 => m H17.
rewrite [eval _ _]/= H17 (mulZC 2) /ZIT.div Z_div_mult_full //.
case: H9 => k [ [H9 H9'] | ].
+ exists (S k); left.
by rewrite ZpowerS mulZA -(mulZC 2) -H17.
+ case ; exists k.+1; right.
* left; by rewrite ZpowerS mulZA -(mulZC 2) -H17.
* right; by rewrite ZpowerS mulZA -(mulZC 2) -H17.
repeat (split; first by []).
case/Zeven_ex : H17 => m H17.
rewrite /= H17 (mulZC 2) /ZIT.div Z_div_mult_full //; lia.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * (2 * [t1 ]_ s - [v]_s) + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3 ]_ s <> 0 /\ Zeven [t3]_s /\
(Zodd (2 * [t1]_s - [v]_s) \/ Zodd [t2]_s)).
move=> s h.
case => [[[[Hu [Hv [Hg [u_g v_g]]]] [H7 [[Hti [Hui Hvi]] [H11 [[Hu3 Hv3] [H14 H16]]]]]] H3] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem in H1 H3.
rewrite negb_and in H1.
have t1_v : [var_e t1 \+ var_e v ]e_ s mod 2 = 0.
rewrite /= /ZIT.add.
case/orP: H1; move/eqP => H1.
- apply Zeven_Zmod_2, Zodd_plus_Zodd.
exact: not_Zmod_2_Zodd.
case: H7 => H7; last by exact H7.
move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv.
+ case=> H31 H32.
have : Zodd ([u ]_ s * [t1 ]_ s).
apply Zodd_mult_Zodd => //; exact: not_Zmod_2_Zodd.
by move/Zodd_not_Zeven.
+ case => _.
by case/Zodd_mult_inv=> ? _.
- case: H7 => H7.
+ move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2]|[]].
* case/Zeven_mult_inv : v_t2 => v_t2.
- case/Zeven_mult_inv : u_t1 => u_t1.
+ by move/Zodd_not_Zeven : H7.
+ exact/Zeven_Zmod_2/Zeven_plus_Zeven.
- move/not_Zmod_2_Zodd : H1.
by move/Zodd_not_Zeven.
* case/Zodd_mult_inv=> _ odd_t1.
case/Zodd_mult_inv=> odd_v _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
+ move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2]| []].
* have : Zodd ([v ]_ s * [t2 ]_ s).
apply Zodd_mult_Zodd => //; exact: not_Zmod_2_Zodd.
by move/Zodd_not_Zeven.
* case/Zodd_mult_inv=> _ odd_t1 _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
split; first by [].
repeat (split; first by []).
split.
split; by [rewrite div_e_exact_full_2 //= /ZIT.add -Hti; ring | ].
repeat (split; first by []).
split; first exact/Zmod_2_Zeven/eqP.
case/orP : H1 => H1.
- left.
rewrite div_e_exact_full_2 //.
move/eqP/not_Zmod_2_Zodd : H1.
suff : [var_e t1 \+ var_e v ]e_ s - [v ]_ s = [t1]_s by move=> ->.
rewrite /= /ZIT.add; ring.
- right.
by move/eqP/not_Zmod_2_Zodd : H1.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * (2 * [t1 ]_ s - [v]_s) + [v ]_ s * (2 * [t2 ]_ s + [u]_s) = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3 ]_ s <> 0 /\ Zeven [t3]_s).
move=> s h H.
rewrite (mulZC 2) /= -(mulZC 2) in H.
case: H => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [H13 [H14 H16]]]]]]]].
rewrite /C2 /wp_assign /C4 /C5.
repeat Store_upd.
have t2_u : [var_e t2 \- var_e u ]e_ s mod 2 = 0.
apply Zeven_Zmod_2.
case: H5 => [odd_u | odd_v].
- case: H16 => H16.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv.
* case.
case/Zeven_mult_inv; by move/Zeven_not_Zodd.
* case.
case/Zodd_mult_inv=> K1 _.
case/Zodd_mult_inv=> _ K4.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
+ apply Zodd_plus_Zodd => //; exact: Zodd_opp.
- case: H16 => H16.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv.
* case.
case/Zeven_mult_inv => [u_even | ].
- case/Zeven_mult_inv => [ | even_t2].
by move/Zeven_not_Zodd.
apply Zeven_plus_Zeven => //; exact: Zeven_opp.
- by move/Zeven_not_Zodd.
* case.
case/Zodd_mult_inv=> odd_u _.
case/Zodd_mult_inv=> _ odd_t2.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv.
* case.
case/Zeven_mult_inv => [u_even | _]; case/Zeven_mult_inv; by move/Zeven_not_Zodd.
* case.
case/Zodd_mult_inv=> odd_u _ _.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
repeat (split; first by []).
split; last by [].
split; by [rewrite div_e_exact_full_2 // /ZIT.add -Hti (mulZC 2) /= /ZIT.sub; ring | ].
apply hoare_assign' => s h H.
rewrite !(mulZC 2) in H.
case: H => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [H13 H15]]]]]]].
rewrite /C2 /wp_assign /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite /= -Hti /ZIT.div.
have : ([u ]_ s * ([t1 ]_ s * 2 - [v ]_ s) + [v ]_ s * ([t2 ]_ s * 2 + [u ]_ s)) =
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s) * 2 by ring.
move=> ->; by rewrite Z_div_mult_full.
repeat (split; first by []).
split.
case/Zeven_ex : H15 => m H15.
rewrite [eval _ _]/= H15 (mulZC 2) /ZIT.div Z_div_mult_full //.
case: H9 => k [[H9 H9']|].
- exists (S k); left.
by rewrite ZpowerS mulZA -(mulZC 2) -H15.
- case=> H9; exists (S k); right.
+ left; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
+ right; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
repeat (split; first by []).
case/Zeven_ex : H15 => m H15 /=.
rewrite H15 mulZC /ZIT.div Z_div_mult_full //; lia.
apply while.hoare_seq with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
(0 <= [t3]_s -> Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\ Zodd [u3]_s /\
[u3]_s = [t3]_s ) /\
([t3]_s < 0 -> Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\ Zodd [v3]_s /\
[v3]_s = - [t3]_s ) /\
C5 u3 v3 s).
rewrite /reset.
apply while.hoare_ifte.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\ Zodd [t3 ]_ s /\
C5 u3 v3 s /\
0 < [t3]_s).
move=> s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 H15]]]]]] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
rewrite /hoare_m.eval_b /= /ZIT.geb in H1.
move/geZP in H1.
repeat (split; first tauto).
move/Z.ge_le : H1.
case/leZ_eqVlt => H1 //.
by rewrite -H1 in H15.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [t3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
Zodd [t3 ]_ s /\ C5 u3 v3 s /\ 0 < [t3 ]_ s).
move=> s h /= H.
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
tauto.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [H11 [[Hu3 Hv3] H15]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
move=> Ht3.
case: H9 => k [ [H9 H9'] | [ [H9 H9'] | [H9 H9']]].
- exfalso.
have abs : -[v3]_s < 0 by lia.
rewrite -H9 in abs.
move/Zlt_not_le : abs.
apply.
apply mulZ_ge0 => //; exact: expZ_ge0.
- rewrite -H9 in H10.
by rewrite Zgcd_Zpower_odd // in H10.
- have Htmp : [u3 ]_ s = [t3 ]_ s * 2 ^^ k + [v3 ]_ s by lia.
rewrite Htmp in H10.
move: (Zgcd_for_euclid ([t3 ]_ s * 2 ^^ k) [v3 ]_ s 1) => X.
rewrite mul1Z in X.
rewrite {}X in H10.
destruct k as [|k].
- by rewrite /= mulZ1 in H10.
- case: H9' => // H9'.
by rewrite Zgcd_Zpower_odd // in H10.
rewrite Zgcd_Zpower_odd // in H10.
have -> : [v3 ]_ s = [u3 ]_ s - [t3 ]_ s * 2 ^^ S k by lia.
apply Zodd_plus_Zeven => //.
exact/Zeven_opp/Zeven_mult_Zeven_r/Zeven_power.
split; last by [].
move=> Ht3.
exfalso.
lia.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1]_s + [v]_s * (- [u]_s - [t2]_s ) = - [t3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\ Zodd [t3 ]_ s /\
[t3]_s < 0).
move=> s h /= H.
case : H => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 H15]]]]]] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first by []).
split.
split; first by rewrite -Hti /= /ZIT.sub; ring.
split; by [ | rewrite -Hti /= /ZIT.sub; ring].
repeat (split; first by []).
rewrite /hoare_m.eval_b /= /ZIT.geb in H1.
move/geZP : H1 => ?; lia.
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1]_s + [v]_s * [v2]_s = - [t3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
Zodd [t3 ]_ s /\ [t3 ]_ s < 0).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [H11 [H12 [H13 H15]]]]]]].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split => //).
rewrite /= /ZIT.add -Hvi; ring.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 [H15 H16]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
split; first by [].
repeat (split; first by []).
rewrite /=.
split; first by move/Zle_not_lt.
split; last lia.
move=> _.
rewrite /=.
case: H10 => k [ [H10 H10'] | [ [H10 H10'] | [H10 H10'] ] ].
- have X : [v3 ]_ s = - ([t3 ]_ s * 2 ^^ k) by lia.
rewrite {}X Zgcd_opp in H13.
symmetry in H13.
rewrite Zgcd_sym Zgcd_Zpower_odd // in H13.
split; first by symmetry; rewrite Zgcd_sym.
split; by [ apply Zodd_opp | ].
- rewrite -H10 in Hu3.
move: (Zmult_lt_0_reg_r _ _ (expZ_gt0 k) Hu3) => abs.
exfalso. lia.
- have Htmp : [v3]_s = [u3 ]_ s - [t3 ]_ s * 2 ^^ k by lia.
rewrite Htmp in H13.
move: (Zgcd_for_euclid (-[t3]_s * 2 ^^ k) ([u3]_s) 1).
rewrite mul1Z addZC mulNZ addZNE Zgcd_sym.
move=> X.
rewrite X (Zgcd_sym _ [u3]_s) Zgcd_opp (Zgcd_sym [u3]_s) in H13.
destruct k.
+ rewrite /= mulZ1 in H13.
split; first by rewrite (Zgcd_sym [u3]_s).
split; by [apply Zodd_opp | ].
+ rewrite Zgcd_Zpower_odd // in H13; last first.
have -> : [u3 ]_ s = [v3 ]_ s + [t3 ]_ s * 2 ^^ S k by lia.
apply Zodd_plus_Zeven; last exact/Zeven_mult_Zeven_r/Zeven_power.
case: H10' => H10'; first by [].
rewrite Htmp.
apply Zodd_plus_Zeven => //.
exact/Zeven_opp/Zeven_mult_Zeven_r/Zeven_power.
split; first by rewrite (Zgcd_sym [u3]_s).
split; by [ apply Zodd_opp |].
rewrite /subtract.
apply while.hoare_seq with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
[t3]_s = [u3]_s - [v3]_s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
(Zodd [v3 ]_ s \/ Zodd [u3 ]_ s) /\
C5 u3 v3 s).
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * ([u2]_s - [v2 ]_ s) = [u3 ]_ s - [v3]_s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
(0 <= [t3]_s -> Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\ Zodd [u3]_s /\
[u3]_s = [t3]_s ) /\
([t3]_s < 0 -> Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\ Zodd [v3]_s /\
[v3]_s = - [t3]_s) /\
C5 u3 v3 s).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [Hu3 Hv3]]]]]].
rewrite /wp_assign /C2 /C5 /CVectors.
repeat Store_upd.
repeat (split; first by []).
split; last by [].
split; by [rewrite /= /ZIT.sub -Hui -Hvi; ring | ].
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2]_s = [u3 ]_ s - [v3]_s/\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
(0 <= [t3]_s -> Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\ Zodd [u3]_s /\
[u3]_s = [t3]_s) /\
([t3]_s < 0 -> Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\ Zodd [v3]_s /\
[v3]_s = - [t3]_s) /\
C5 u3 v3 s).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [Hu3 Hv3]]]]]].
rewrite /wp_assign /C2 /C5.
by repeat Store_upd.
apply hoare_assign'.
move=> s h [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [Hu3 Hv3]]]]]].
rewrite /wp_assign /C2 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
case: (Z_lt_le_dec [t3]_s 0).
- move/H10 => H10'.
move: (Zgcd_for_euclid [u3]_s [v3]_s (-1)).
rewrite mulN1Z addZNE => ->.
case: H10' => H10' [H10'' H10'''].
rewrite H10''' Zgcd_opp; tauto.
- move/H9.
case => H9' [H9'' H9'''].
rewrite /= H9'''.
move: (Zgcd_for_euclid [t3]_s [v3]_s (-1)).
by rewrite mulN1Z addZNE => ->.
split; last by [].
case: (Z_lt_le_dec [t3]_s 0).
- move/H10; tauto.
- move/H9; tauto.
apply while.hoare_ifte.
C2 vu vv u v g s /\
(Zodd [u]_s \/ Zodd [v]_s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u]_s [v]_s = Z.gcd [u3]_s [v3]_s).
rewrite /while.entails => s h.
case => [[Hu [Hv [Hg [u_g v_g]]] [[Hgcd Hcond] [[Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]]]]] Ht].
rewrite /CVectors Hu1 Hu2 Hu3 Hv1 Hv2 Hv3.
repeat (split; first tauto).
case: (Zeven_odd_dec [u]_s) => u_parity.
- case: Ht => _.
move/(_ u_parity) => [Ht1 [Ht2 Ht3]].
rewrite /C2 /C4 /C5 Ht1 Ht2 Ht3 Hu3 Hv3 mulZ1 mulZ0 addZ0.
split; first by [].
split.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem /=.
case/orP; move/eqP => X.
+ left; exact: not_Zmod_2_Zodd.
+ right; exact: not_Zmod_2_Zodd.
split.
repeat (split; first tauto).
ring.
split; last by [].
exists O; rewrite [_ ^^ _]/= !mulZ1; right; left.
split; first by reflexivity.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem.
case/orP; move/eqP.
+ move/not_Zmod_2_Zodd; by move/Zodd_not_Zeven.
+ by move/not_Zmod_2_Zodd.
- case: Ht.
move/(_ u_parity) => [Ht1 [Ht2 Ht3]] _.
rewrite /C2 /C4 /C5 Ht1 Ht2 Ht3 Hu3 Hv3 mulZ1 mulZ0 add0Z mulZ0 addZ0.
split; first by [].
split.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem /=.
case/orP; move/eqP => X.
* left; exact: not_Zmod_2_Zodd.
* right; exact: not_Zmod_2_Zodd.
split.
split; first by ring.
split; by [ | ring].
split; last by [].
exists O; rewrite [_ ^^ _]/= !mulZ1; tauto.
- rewrite /while.entails => s h.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] H14]]]]] H1].
split; first by rewrite -u_g -v_g -Hui; ring.
rewrite /hoare_m.eval_b /= /ZIT.eqb in H1.
move/negPn/eqP in H1.
case: H10 => k [H10|[H10 | H10]].
+ have abs : [v3 ]_ s = 0.
move: (expZ_gt0 k) => X.
case: H10 => H10 H10'.
rewrite H1 mul0Z in H10; lia.
rewrite abs Zgcd_0 geZ0_norm in H14; last lia.
rewrite -H14 -Zgcd_mult; last lia.
by rewrite mulZC u_g mulZC v_g.
+ have abs : [u ]_ s = 0 by rewrite H1 mul0Z in H10; lia.
rewrite abs in Hu; by apply ltZZ in Hu.
+ have abs : [u3 ]_ s = [v3 ]_ s.
rewrite H1 mul0Z in H10; lia.
rewrite -abs Zgcd_same in H14; last lia.
rewrite -H14 -u_g -v_g -Zgcd_mult; last lia.
by rewrite (mulZC [u ]_ s) (mulZC [v ]_ s).
apply while.hoare_seq with (fun s h =>
C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
Zodd [t3]_s ).
rewrite /halve.
apply hoare_prop_m.hoare_while_invariant with (fun s h =>
C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3]_s <> 0).
move=> s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] H14]]]]] H1].
repeat (split => //).
by move/eqP : H1.
move=> s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H14 H15]]]]]] H1].
repeat (split; first by []).
split.
rewrite /C2 -u_g -v_g -H14 -Zgcd_mult; last lia.
f_equal; by rewrite mulZC.
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem in H1.
by move/eqP/not_Zmod_2_Zodd : H1.
apply while.hoare_ifte.
- apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * 2 * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3 ]_ s <> 0 /\
Zeven [t3]_s /\
Zeven [t2]_s).
move=> s h /=.
case => [[[[Hu [Hv [Hg [u_g v_g]]]] [H7 [[Hti [Hui Hvi]] [H11 [[Hu3 Hv3] [H14 H16]]]]]] H3] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite -mulZA div_e_exact_full_2 //.
rewrite /hoare_m.eval_b /= in H1.
case/andP : H1 => H1 _.
rewrite /ZIT.eqb /ZIT.rem /= in H1.
by move/eqP : H1.
repeat (split; first by []).
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem /= in H1, H3.
move/eqP in H3.
case/andP : H1 => _ /eqP H1.
split; exact: Zmod_2_Zeven.
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * 2 * [t1 ]_ s + [v ]_ s * 2 * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3 ]_ s <> 0 /\ Zeven [t3 ]_ s ).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [H13 [H14 H16]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first tauto).
split; last by [].
rewrite -(mulZA [v]_s) div_e_exact_full_2 //; exact: Zeven_Zmod_2.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]] [H5 [[Hti [Hui Hvi] [H9 [[Hu3 Hv3] [H15 [H16 H17]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite /= -Hti /ZIT.div.
set tmp := _ + [v]_s * 2 * _ .
have -> : tmp = ([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s) * 2 by rewrite /tmp; ring.
by rewrite Z_div_mult_full.
repeat (split; first by []).
split.
case/Zeven_ex : H17 => m H17.
rewrite [eval _ _]/= H17 (mulZC 2) /ZIT.div Z_div_mult_full //.
case: H9 => k [ [H9 H9'] | ].
+ exists (S k); left.
by rewrite ZpowerS mulZA -(mulZC 2) -H17.
+ case ; exists k.+1; right.
* left; by rewrite ZpowerS mulZA -(mulZC 2) -H17.
* right; by rewrite ZpowerS mulZA -(mulZC 2) -H17.
repeat (split; first by []).
case/Zeven_ex : H17 => m H17.
rewrite /= H17 (mulZC 2) /ZIT.div Z_div_mult_full //; lia.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * (2 * [t1 ]_ s - [v]_s) + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3 ]_ s <> 0 /\ Zeven [t3]_s /\
(Zodd (2 * [t1]_s - [v]_s) \/ Zodd [t2]_s)).
move=> s h.
case => [[[[Hu [Hv [Hg [u_g v_g]]]] [H7 [[Hti [Hui Hvi]] [H11 [[Hu3 Hv3] [H14 H16]]]]]] H3] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem in H1 H3.
rewrite negb_and in H1.
have t1_v : [var_e t1 \+ var_e v ]e_ s mod 2 = 0.
rewrite /= /ZIT.add.
case/orP: H1; move/eqP => H1.
- apply Zeven_Zmod_2, Zodd_plus_Zodd.
exact: not_Zmod_2_Zodd.
case: H7 => H7; last by exact H7.
move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv.
+ case=> H31 H32.
have : Zodd ([u ]_ s * [t1 ]_ s).
apply Zodd_mult_Zodd => //; exact: not_Zmod_2_Zodd.
by move/Zodd_not_Zeven.
+ case => _.
by case/Zodd_mult_inv=> ? _.
- case: H7 => H7.
+ move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2]|[]].
* case/Zeven_mult_inv : v_t2 => v_t2.
- case/Zeven_mult_inv : u_t1 => u_t1.
+ by move/Zodd_not_Zeven : H7.
+ exact/Zeven_Zmod_2/Zeven_plus_Zeven.
- move/not_Zmod_2_Zodd : H1.
by move/Zodd_not_Zeven.
* case/Zodd_mult_inv=> _ odd_t1.
case/Zodd_mult_inv=> odd_v _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
+ move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2]| []].
* have : Zodd ([v ]_ s * [t2 ]_ s).
apply Zodd_mult_Zodd => //; exact: not_Zmod_2_Zodd.
by move/Zodd_not_Zeven.
* case/Zodd_mult_inv=> _ odd_t1 _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
split; first by [].
repeat (split; first by []).
split.
split; by [rewrite div_e_exact_full_2 //= /ZIT.add -Hti; ring | ].
repeat (split; first by []).
split; first exact/Zmod_2_Zeven/eqP.
case/orP : H1 => H1.
- left.
rewrite div_e_exact_full_2 //.
move/eqP/not_Zmod_2_Zodd : H1.
suff : [var_e t1 \+ var_e v ]e_ s - [v ]_ s = [t1]_s by move=> ->.
rewrite /= /ZIT.add; ring.
- right.
by move/eqP/not_Zmod_2_Zodd : H1.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * (2 * [t1 ]_ s - [v]_s) + [v ]_ s * (2 * [t2 ]_ s + [u]_s) = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
[t3 ]_ s <> 0 /\ Zeven [t3]_s).
move=> s h H.
rewrite (mulZC 2) /= -(mulZC 2) in H.
case: H => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [H13 [H14 H16]]]]]]]].
rewrite /C2 /wp_assign /C4 /C5.
repeat Store_upd.
have t2_u : [var_e t2 \- var_e u ]e_ s mod 2 = 0.
apply Zeven_Zmod_2.
case: H5 => [odd_u | odd_v].
- case: H16 => H16.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv.
* case.
case/Zeven_mult_inv; by move/Zeven_not_Zodd.
* case.
case/Zodd_mult_inv=> K1 _.
case/Zodd_mult_inv=> _ K4.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
+ apply Zodd_plus_Zodd => //; exact: Zodd_opp.
- case: H16 => H16.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv.
* case.
case/Zeven_mult_inv => [u_even | ].
- case/Zeven_mult_inv => [ | even_t2].
by move/Zeven_not_Zodd.
apply Zeven_plus_Zeven => //; exact: Zeven_opp.
- by move/Zeven_not_Zodd.
* case.
case/Zodd_mult_inv=> odd_u _.
case/Zodd_mult_inv=> _ odd_t2.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv.
* case.
case/Zeven_mult_inv => [u_even | _]; case/Zeven_mult_inv; by move/Zeven_not_Zodd.
* case.
case/Zodd_mult_inv=> odd_u _ _.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
repeat (split; first by []).
split; last by [].
split; by [rewrite div_e_exact_full_2 // /ZIT.add -Hti (mulZC 2) /= /ZIT.sub; ring | ].
apply hoare_assign' => s h H.
rewrite !(mulZC 2) in H.
case: H => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [H13 H15]]]]]]].
rewrite /C2 /wp_assign /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite /= -Hti /ZIT.div.
have : ([u ]_ s * ([t1 ]_ s * 2 - [v ]_ s) + [v ]_ s * ([t2 ]_ s * 2 + [u ]_ s)) =
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s) * 2 by ring.
move=> ->; by rewrite Z_div_mult_full.
repeat (split; first by []).
split.
case/Zeven_ex : H15 => m H15.
rewrite [eval _ _]/= H15 (mulZC 2) /ZIT.div Z_div_mult_full //.
case: H9 => k [[H9 H9']|].
- exists (S k); left.
by rewrite ZpowerS mulZA -(mulZC 2) -H15.
- case=> H9; exists (S k); right.
+ left; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
+ right; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
repeat (split; first by []).
case/Zeven_ex : H15 => m H15 /=.
rewrite H15 mulZC /ZIT.div Z_div_mult_full //; lia.
apply while.hoare_seq with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
(0 <= [t3]_s -> Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\ Zodd [u3]_s /\
[u3]_s = [t3]_s ) /\
([t3]_s < 0 -> Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\ Zodd [v3]_s /\
[v3]_s = - [t3]_s ) /\
C5 u3 v3 s).
rewrite /reset.
apply while.hoare_ifte.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\ Zodd [t3 ]_ s /\
C5 u3 v3 s /\
0 < [t3]_s).
move=> s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 H15]]]]]] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
rewrite /hoare_m.eval_b /= /ZIT.geb in H1.
move/geZP in H1.
repeat (split; first tauto).
move/Z.ge_le : H1.
case/leZ_eqVlt => H1 //.
by rewrite -H1 in H15.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [t3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
Zodd [t3 ]_ s /\ C5 u3 v3 s /\ 0 < [t3 ]_ s).
move=> s h /= H.
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
tauto.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [H11 [[Hu3 Hv3] H15]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
move=> Ht3.
case: H9 => k [ [H9 H9'] | [ [H9 H9'] | [H9 H9']]].
- exfalso.
have abs : -[v3]_s < 0 by lia.
rewrite -H9 in abs.
move/Zlt_not_le : abs.
apply.
apply mulZ_ge0 => //; exact: expZ_ge0.
- rewrite -H9 in H10.
by rewrite Zgcd_Zpower_odd // in H10.
- have Htmp : [u3 ]_ s = [t3 ]_ s * 2 ^^ k + [v3 ]_ s by lia.
rewrite Htmp in H10.
move: (Zgcd_for_euclid ([t3 ]_ s * 2 ^^ k) [v3 ]_ s 1) => X.
rewrite mul1Z in X.
rewrite {}X in H10.
destruct k as [|k].
- by rewrite /= mulZ1 in H10.
- case: H9' => // H9'.
by rewrite Zgcd_Zpower_odd // in H10.
rewrite Zgcd_Zpower_odd // in H10.
have -> : [v3 ]_ s = [u3 ]_ s - [t3 ]_ s * 2 ^^ S k by lia.
apply Zodd_plus_Zeven => //.
exact/Zeven_opp/Zeven_mult_Zeven_r/Zeven_power.
split; last by [].
move=> Ht3.
exfalso.
lia.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1]_s + [v]_s * (- [u]_s - [t2]_s ) = - [t3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\ Zodd [t3 ]_ s /\
[t3]_s < 0).
move=> s h /= H.
case : H => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 H15]]]]]] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first by []).
split.
split; first by rewrite -Hti /= /ZIT.sub; ring.
split; by [ | rewrite -Hti /= /ZIT.sub; ring].
repeat (split; first by []).
rewrite /hoare_m.eval_b /= /ZIT.geb in H1.
move/geZP : H1 => ?; lia.
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1]_s + [v]_s * [v2]_s = - [t3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
Zodd [t3 ]_ s /\ [t3 ]_ s < 0).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [H11 [H12 [H13 H15]]]]]]].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split => //).
rewrite /= /ZIT.add -Hvi; ring.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 [H15 H16]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
split; first by [].
repeat (split; first by []).
rewrite /=.
split; first by move/Zle_not_lt.
split; last lia.
move=> _.
rewrite /=.
case: H10 => k [ [H10 H10'] | [ [H10 H10'] | [H10 H10'] ] ].
- have X : [v3 ]_ s = - ([t3 ]_ s * 2 ^^ k) by lia.
rewrite {}X Zgcd_opp in H13.
symmetry in H13.
rewrite Zgcd_sym Zgcd_Zpower_odd // in H13.
split; first by symmetry; rewrite Zgcd_sym.
split; by [ apply Zodd_opp | ].
- rewrite -H10 in Hu3.
move: (Zmult_lt_0_reg_r _ _ (expZ_gt0 k) Hu3) => abs.
exfalso. lia.
- have Htmp : [v3]_s = [u3 ]_ s - [t3 ]_ s * 2 ^^ k by lia.
rewrite Htmp in H13.
move: (Zgcd_for_euclid (-[t3]_s * 2 ^^ k) ([u3]_s) 1).
rewrite mul1Z addZC mulNZ addZNE Zgcd_sym.
move=> X.
rewrite X (Zgcd_sym _ [u3]_s) Zgcd_opp (Zgcd_sym [u3]_s) in H13.
destruct k.
+ rewrite /= mulZ1 in H13.
split; first by rewrite (Zgcd_sym [u3]_s).
split; by [apply Zodd_opp | ].
+ rewrite Zgcd_Zpower_odd // in H13; last first.
have -> : [u3 ]_ s = [v3 ]_ s + [t3 ]_ s * 2 ^^ S k by lia.
apply Zodd_plus_Zeven; last exact/Zeven_mult_Zeven_r/Zeven_power.
case: H10' => H10'; first by [].
rewrite Htmp.
apply Zodd_plus_Zeven => //.
exact/Zeven_opp/Zeven_mult_Zeven_r/Zeven_power.
split; first by rewrite (Zgcd_sym [u3]_s).
split; by [ apply Zodd_opp |].
rewrite /subtract.
apply while.hoare_seq with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
[t3]_s = [u3]_s - [v3]_s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
(Zodd [v3 ]_ s \/ Zodd [u3 ]_ s) /\
C5 u3 v3 s).
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * ([u2]_s - [v2 ]_ s) = [u3 ]_ s - [v3]_s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
(0 <= [t3]_s -> Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\ Zodd [u3]_s /\
[u3]_s = [t3]_s ) /\
([t3]_s < 0 -> Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\ Zodd [v3]_s /\
[v3]_s = - [t3]_s) /\
C5 u3 v3 s).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [Hu3 Hv3]]]]]].
rewrite /wp_assign /C2 /C5 /CVectors.
repeat Store_upd.
repeat (split; first by []).
split; last by [].
split; by [rewrite /= /ZIT.sub -Hui -Hvi; ring | ].
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2]_s = [u3 ]_ s - [v3]_s/\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
(0 <= [t3]_s -> Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\ Zodd [u3]_s /\
[u3]_s = [t3]_s) /\
([t3]_s < 0 -> Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\ Zodd [v3]_s /\
[v3]_s = - [t3]_s) /\
C5 u3 v3 s).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [Hu3 Hv3]]]]]].
rewrite /wp_assign /C2 /C5.
by repeat Store_upd.
apply hoare_assign'.
move=> s h [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [Hu3 Hv3]]]]]].
rewrite /wp_assign /C2 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
case: (Z_lt_le_dec [t3]_s 0).
- move/H10 => H10'.
move: (Zgcd_for_euclid [u3]_s [v3]_s (-1)).
rewrite mulN1Z addZNE => ->.
case: H10' => H10' [H10'' H10'''].
rewrite H10''' Zgcd_opp; tauto.
- move/H9.
case => H9' [H9'' H9'''].
rewrite /= H9'''.
move: (Zgcd_for_euclid [t3]_s [v3]_s (-1)).
by rewrite mulN1Z addZNE => ->.
split; last by [].
case: (Z_lt_le_dec [t3]_s 0).
- move/H10; tauto.
- move/H9; tauto.
apply while.hoare_ifte.
t1 <- svar t1 +e svar v
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * ([t2]_s - [u]_s) = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
[t3 ]_ s = [u3 ]_ s - [v3 ]_ s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
(Zodd [v3 ]_ s \/ Zodd [u3 ]_ s) /\
C5 u3 v3 s).
move=> s h.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [H11 [H12 [Hu3 Hv3]]]]]]] H1].
rewrite /wp_assign /C2 /C5.
repeat Store_upd.
repeat (split; first by []).
split; last by [].
split; by [rewrite /= /ZIT.add -Hti; ring | ].
apply hoare_assign' => s h.
case=> [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [H11 [Hu3 Hv3]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first by []).
split; first by exists O; right; right; rewrite /= mulZ1.
repeat (split; first by []).
rewrite -(Zgcd_for_euclid [u3]_s [v3]_s (-1)) mulN1Z addZNE.
rewrite H9 -u_g -v_g -2!(mulZC [g]_s) Zgcd_mult in H10; last lia.
apply eqZ_mul2l in H10 => //; lia.
apply hoare_skip' => s h.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [H11 [H12 [Hu3 Hv3]]]]]]] H1].
rewrite /wp_assign /C2 /C4.
repeat Store_upd.
repeat (split; first by []).
split; first by exists O; right; right; rewrite /= mulZ1.
repeat (split; first by []).
rewrite -(Zgcd_for_euclid [u3]_s [v3]_s (-1)) mulN1Z addZNE.
rewrite H10 -v_g -u_g -2!(mulZC [g]_s) Zgcd_mult in H11; last lia.
apply eqZ_mul2l in H11 => //; lia.
Qed.
Lemma prelude_triple_strict : uniq(u, v, g) ->
0 < vu -> 0 < vv ->
{{ fun s _ => C2 vu vv u v g s }}
prelude u v g
{{ fun s _ => C2 vu vv u v g s /\
~~ [ var_e u \% nat_e 2 \= nat_e 0 \&& var_e v \% nat_e 2 \= nat_e 0 ]b_ s }}.
Proof.
move=> Hset Hvu Hvv.
apply hoare_prop_m.hoare_while_invariant with (fun s _ => C2 vu vv u v g s).
by move=> s h /= [H1 [H2 [H3 [H4 H5]]]].
by move=> s h /= [[H1 [H2 [H3 [H4 H5]]]] H6].
u <- var_e u ./e nat_e 2
apply hoare_assign with (fun s h => 0 < [ u ]_s /\ 0 < [ v ]_s /\ 0 < [ g ]_s /\
2 * [ u ]_s * [ g ]_s = vu /\ [ v ]_s * [ g ]_s = vv /\ [ v ]_s mod 2 = 0).
move=> s h [[H1 [H2 [H3 [H4 H5]]]] H6].
rewrite /hoare_m.eval_b /= in H6; case/andP : H6. rewrite /ZIT.rem.
move/eqP => even_u. move/eqP => even_v.
rewrite /wp_assign; repeat Store_upd => //.
split.
rewrite /=.
apply Zlt_0_Zdiv => //.
rewrite -> Zmod_divides in even_u; last by auto.
case: even_u => k Hk; lia.
repeat (split; first by []).
split; last by [].
rewrite div_e_exact_full_2 //; by rewrite /hoare_m.eval_b in H6; omegab.
2 * [ u ]_s * [ g ]_s = vu /\ [ v ]_s * [ g ]_s = vv /\ [ v ]_s mod 2 = 0).
move=> s h [[H1 [H2 [H3 [H4 H5]]]] H6].
rewrite /hoare_m.eval_b /= in H6; case/andP : H6. rewrite /ZIT.rem.
move/eqP => even_u. move/eqP => even_v.
rewrite /wp_assign; repeat Store_upd => //.
split.
rewrite /=.
apply Zlt_0_Zdiv => //.
rewrite -> Zmod_divides in even_u; last by auto.
case: even_u => k Hk; lia.
repeat (split; first by []).
split; last by [].
rewrite div_e_exact_full_2 //; by rewrite /hoare_m.eval_b in H6; omegab.
v <- var_e v ./e nat_e 2;
apply hoare_assign with (fun s h => 0 < [ u ]_s /\ 0 < [ v ]_s /\ 0 < [ g ]_s /\
2 * [ u ]_s * [ g ]_s = vu /\ 2 * [ v ]_s * [ g ]_ s = vv).
move=> s h [H1 [H2 [H3 [H4 [H5 H6]]]]].
rewrite /wp_assign; repeat Store_upd => //.
split; first by [].
split.
rewrite /=; apply Zlt_0_Zdiv => //.
rewrite -> Zmod_divides in H6; last by auto.
case: H6 => k Hk; lia.
repeat (split; first by []).
by rewrite div_e_exact_full_2.
2 * [ u ]_s * [ g ]_s = vu /\ 2 * [ v ]_s * [ g ]_ s = vv).
move=> s h [H1 [H2 [H3 [H4 [H5 H6]]]]].
rewrite /wp_assign; repeat Store_upd => //.
split; first by [].
split.
rewrite /=; apply Zlt_0_Zdiv => //.
rewrite -> Zmod_divides in H6; last by auto.
case: H6 => k Hk; lia.
repeat (split; first by []).
by rewrite div_e_exact_full_2.
g <- nat_e 2 *e var_e g
apply hoare_assign' => s h [H1 [H2 [H3 [H4 H5]]]].
rewrite /wp_assign /C2; repeat Store_upd => //.
repeat (split; first by []).
split; first exact: mulZ_gt0.
rewrite /= -H4 -H5 /ZIT.mul; split; ring.
Qed.
Lemma triple_init0 : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) ->
0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s }}
u1 <- nat_e 1;
u2 <- nat_e 0;
u3 <- var_e u;
v1 <- var_e v;
v2 <- nat_e 1 \- var_e u;
v3 <- var_e v
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\ uivi_init u v u1 u2 u3 v1 v2 v3 s}}.
Proof.
move=> Hset Hvu Hvv.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [u1]_s = 1 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 /= in H *.
by repeat Store_upd.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [u2]_s = 0 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 /= in H *.
by repeat Store_upd.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [u3]_s = [u]_s /\ pre s h).
rewrite /wp_assign.
move=> s h H.
rewrite /pre /C2 /C3 /= in H *.
by repeat Store_upd.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [v1]_s = [v]_s /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 /= in H *.
by repeat Store_upd.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [v2]_s = 1 - [u]_s /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 in H *.
repeat Store_upd.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
tauto.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign'.
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 in H *.
rewrite /uivi_init.
repeat Store_upd.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
tauto.
Qed.
Lemma triple_init1 : uniq(g,u,v,u1,u2,u3,v1,v2,v3,t1,t2,t3) ->
0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\ uivi_init u v u1 u2 u3 v1 v2 v3 s}}
while.ifte (var_e u \% nat_e 2 \= nat_e 1)
(t1 <- nat_e 0;
t2 <- cst_e (-1);
t3 <- .--e var_e v)
(
t1 <- nat_e 1;
t2 <- nat_e 0;
t3 <- var_e u)
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\ ti_init u v t1 t2 t3 s}}.
Proof.
move=> Hset Hvu Hvv.
apply while.hoare_ifte.
- set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [t1]_s = 0 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /uivi_init /C2 /C3 in H *.
repeat Store_upd.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
rewrite /hoare_m.eval_b.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
tauto.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [t2]_s = -1 /\ pre s h).
rewrite /wp_assign => s h H /=.
rewrite /pre /uivi_init /C2 /C3 in H *.
repeat Store_upd.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
rewrite /hoare_m.eval_b.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
tauto.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign'.
rewrite /wp_assign => s h H.
repeat Store_upd.
rewrite /pre {pre} in H.
rewrite /uivi_init /C2 /C3 in H *.
rewrite [eval _ _]/=.
repeat Store_upd.
case: H => [Ht2 [Ht1] [[[Hu [Hv [Hg [Hhg Hvg]]]] [[Hgcd Htest'] [Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]]]] Htest]].
repeat (split; first by []).
repeat (split; first by []).
split.
rewrite /=.
by do 2 Store_upd.
repeat (split; first tauto).
rewrite /ti_init.
repeat Store_upd.
rewrite /= /ZIT.eqb /ZIT.rem in Htest.
move/eqP in Htest.
have {}Htest : Zodd [u]_s.
rewrite /= /ZIT.rem in Htest.
apply not_Zmod_2_Zodd; by rewrite Htest.
split; first by [].
by move/Zeven_not_Zodd.
- set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [t1]_s = 1 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /uivi_init /C2 /C3 in H *.
rewrite /hoare_m.eval_b ![fst _]/= in H *.
repeat Store_upd.
by do 2 (rewrite eval_b_upd; last by simpl vars_b; apply/negP/inP; Uniq_not_In).
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [t2]_s = 0 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /uivi_init /C2 /C3 /hoare_m.eval_b in H *.
repeat Store_upd.
by do 2 (rewrite eval_b_upd; last by simpl vars_b; apply/negP/inP; Uniq_not_In).
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign'.
rewrite /wp_assign => s h H.
rewrite /pre /uivi_init /C2 /C3 /= in H *.
split.
repeat Store_upd.
tauto.
repeat Store_upd.
case: H => [Ht2 [Ht1] [[[Hu [Hv [Hg [Hhg Hvg]]]] [[Hgcd Htest'] [Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]]]] Htest]].
repeat (split; first by []).
rewrite /ti_init.
repeat Store_upd.
split => u_parity.
- rewrite /= in Htest', Htest.
move/negP : Htest'.
rewrite negb_and.
case/orP => X.
+ exfalso.
move/negP : X.
apply.
rewrite /hoare_m.eval_b /ZIT.eqb /= /ZIT.rem in Htest *.
move/eqP in Htest.
apply/eqP.
lapply (Z_mod_lt [u]_s 2) => //.
move=> ?; lia.
+ exfalso.
move/negP : Htest; apply.
rewrite /ZIT.eqb /ZIT.rem.
apply/eqP.
by apply Zodd_Zmod_2 in u_parity.
- rewrite /= in Htest, Htest'.
move/negP : Htest'.
rewrite negb_and.
case/orP=> X; last by [].
exfalso.
move/negP : X.
apply.
exact/eqP/Zeven_Zmod_2.
Qed.
Lemma triple_init : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) ->
0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s }}
init u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\ ti_init u v t1 t2 t3 s}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /init.
apply while.hoare_seq with (fun s h => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s).
exact: triple_init0.
exact: triple_init1.
Qed.
Lemma triple_prelude_init : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) ->
0 < vu -> 0 < vv ->
{{ fun s h => [u]_s = vu /\ [v]_s = vv }}
g <- nat_e 1;
prelude u v g;
init u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{ fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\
ti_init u v t1 t2 t3 s }}.
Proof.
move=> Hset Hvu Hvv.
rewrite /wp_assign /C2; repeat Store_upd => //.
repeat (split; first by []).
split; first exact: mulZ_gt0.
rewrite /= -H4 -H5 /ZIT.mul; split; ring.
Qed.
Lemma triple_init0 : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) ->
0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s }}
u1 <- nat_e 1;
u2 <- nat_e 0;
u3 <- var_e u;
v1 <- var_e v;
v2 <- nat_e 1 \- var_e u;
v3 <- var_e v
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\ uivi_init u v u1 u2 u3 v1 v2 v3 s}}.
Proof.
move=> Hset Hvu Hvv.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [u1]_s = 1 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 /= in H *.
by repeat Store_upd.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [u2]_s = 0 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 /= in H *.
by repeat Store_upd.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [u3]_s = [u]_s /\ pre s h).
rewrite /wp_assign.
move=> s h H.
rewrite /pre /C2 /C3 /= in H *.
by repeat Store_upd.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [v1]_s = [v]_s /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 /= in H *.
by repeat Store_upd.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [v2]_s = 1 - [u]_s /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 in H *.
repeat Store_upd.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
tauto.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign'.
rewrite /wp_assign => s h H.
rewrite /pre /C2 /C3 in H *.
rewrite /uivi_init.
repeat Store_upd.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
tauto.
Qed.
Lemma triple_init1 : uniq(g,u,v,u1,u2,u3,v1,v2,v3,t1,t2,t3) ->
0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\ uivi_init u v u1 u2 u3 v1 v2 v3 s}}
while.ifte (var_e u \% nat_e 2 \= nat_e 1)
(t1 <- nat_e 0;
t2 <- cst_e (-1);
t3 <- .--e var_e v)
(
t1 <- nat_e 1;
t2 <- nat_e 0;
t3 <- var_e u)
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\ ti_init u v t1 t2 t3 s}}.
Proof.
move=> Hset Hvu Hvv.
apply while.hoare_ifte.
- set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [t1]_s = 0 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /uivi_init /C2 /C3 in H *.
repeat Store_upd.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
rewrite /hoare_m.eval_b.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
tauto.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [t2]_s = -1 /\ pre s h).
rewrite /wp_assign => s h H /=.
rewrite /pre /uivi_init /C2 /C3 in H *.
repeat Store_upd.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
rewrite /hoare_m.eval_b.
rewrite eval_b_upd; last by rewrite [vars_b _]/=; apply/negP/inP; Uniq_not_In.
tauto.
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign'.
rewrite /wp_assign => s h H.
repeat Store_upd.
rewrite /pre {pre} in H.
rewrite /uivi_init /C2 /C3 in H *.
rewrite [eval _ _]/=.
repeat Store_upd.
case: H => [Ht2 [Ht1] [[[Hu [Hv [Hg [Hhg Hvg]]]] [[Hgcd Htest'] [Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]]]] Htest]].
repeat (split; first by []).
repeat (split; first by []).
split.
rewrite /=.
by do 2 Store_upd.
repeat (split; first tauto).
rewrite /ti_init.
repeat Store_upd.
rewrite /= /ZIT.eqb /ZIT.rem in Htest.
move/eqP in Htest.
have {}Htest : Zodd [u]_s.
rewrite /= /ZIT.rem in Htest.
apply not_Zmod_2_Zodd; by rewrite Htest.
split; first by [].
by move/Zeven_not_Zodd.
- set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [t1]_s = 1 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /uivi_init /C2 /C3 in H *.
rewrite /hoare_m.eval_b ![fst _]/= in H *.
repeat Store_upd.
by do 2 (rewrite eval_b_upd; last by simpl vars_b; apply/negP/inP; Uniq_not_In).
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign with (fun s h => [t2]_s = 0 /\ pre s h).
rewrite /wp_assign => s h H.
rewrite /pre /uivi_init /C2 /C3 /hoare_m.eval_b in H *.
repeat Store_upd.
by do 2 (rewrite eval_b_upd; last by simpl vars_b; apply/negP/inP; Uniq_not_In).
rewrite /pre {pre}.
set pre := fun s (h : heap.t) => _.
apply hoare_assign'.
rewrite /wp_assign => s h H.
rewrite /pre /uivi_init /C2 /C3 /= in H *.
split.
repeat Store_upd.
tauto.
repeat Store_upd.
case: H => [Ht2 [Ht1] [[[Hu [Hv [Hg [Hhg Hvg]]]] [[Hgcd Htest'] [Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]]]] Htest]].
repeat (split; first by []).
rewrite /ti_init.
repeat Store_upd.
split => u_parity.
- rewrite /= in Htest', Htest.
move/negP : Htest'.
rewrite negb_and.
case/orP => X.
+ exfalso.
move/negP : X.
apply.
rewrite /hoare_m.eval_b /ZIT.eqb /= /ZIT.rem in Htest *.
move/eqP in Htest.
apply/eqP.
lapply (Z_mod_lt [u]_s 2) => //.
move=> ?; lia.
+ exfalso.
move/negP : Htest; apply.
rewrite /ZIT.eqb /ZIT.rem.
apply/eqP.
by apply Zodd_Zmod_2 in u_parity.
- rewrite /= in Htest, Htest'.
move/negP : Htest'.
rewrite negb_and.
case/orP=> X; last by [].
exfalso.
move/negP : X.
apply.
exact/eqP/Zeven_Zmod_2.
Qed.
Lemma triple_init : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) ->
0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s }}
init u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\ ti_init u v t1 t2 t3 s}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /init.
apply while.hoare_seq with (fun s h => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s).
exact: triple_init0.
exact: triple_init1.
Qed.
Lemma triple_prelude_init : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) ->
0 < vu -> 0 < vv ->
{{ fun s h => [u]_s = vu /\ [v]_s = vv }}
g <- nat_e 1;
prelude u v g;
init u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{ fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\
ti_init u v t1 t2 t3 s }}.
Proof.
move=> Hset Hvu Hvv.
g <- nat_e 1 ;
apply hoare_assign with (fun s h => C1 vu vv u v g s).
move=> s h [Hu Hv].
by rewrite /wp_assign /C1 /uv_init; repeat Store_upd.
move=> s h [Hu Hv].
by rewrite /wp_assign /C1 /uv_init; repeat Store_upd.
prelude u v g ;
apply while.hoare_seq with (fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s).
have Hset' : uniq(u, v, g) by rewrite [Equality.sort _]/= in Hset *; Uniq_uniq O.
eapply while.hoare_conseq; last exact: (prelude_triple_strict Hset' Hvu Hvv).
- move=> s h /= [[H1 [H2 [H3 [H4 H5]]]] H6].
rewrite /C2 /C3.
repeat (split; first lia).
split; last by move/negP: H6.
rewrite -H4 -H5.
apply Zis_gcd_gcd; last first.
rewrite (mulZC [u]_s) (mulZC [v]_s).
exact/Zis_gcd_mult/Zgcd_is_gcd.
apply mulZ_ge0 => //; [lia | exact: Zgcd_is_pos].
- rewrite /C1 /uv_init /C2 => s h /= [[-> ->] ->]; by rewrite 2!mulZ1.
exact: triple_init.
Qed.
Lemma triple :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s h => [u]_s = vu /\ [v]_s = vv }}
begcd g u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{ fun s h => vu * [u1]_s + vv * [u2]_s = [g]_s * [u3]_s /\
Z.gcd vu vv = ([g]_s * [u3]_s)}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /begcd.
do 2 apply hoare_prop_m.hoare_seq_assoc'.
eapply while.hoare_seq.
apply hoare_prop_m.hoare_seq_assoc.
exact: triple_prelude_init.
exact: triple_intermediate.
Qed.
End begcd_taocp_fun_cor.
End BEGCD_TAOCP_FUN_COR.
Definition uivi_bounds u v u1 v1 u2 v2 u3 v3 st :=
0 <= [u1 ]_ st <= [v ]_ st /\ 0 <= [v1 ]_ st <= [v ]_ st /\
- [u ]_ st <= [u2 ]_ st <= 0 /\ - [u ]_ st <= [v2 ]_ st <= 0 /\
0 < [u3 ]_ st <= [u ]_ st /\ 0 < [v3 ]_ st <= [v ]_ st.
Definition ti_bounds u v t1 t2 t3 st :=
0 <= [t1 ]_ st <= [v ]_ st /\
- [u ]_ st <= [t2 ]_ st <= 0 /\
- [v ]_ st <= [t3 ]_ st <= [u ]_ st.
Lemma init_bounds u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s :
0 < [u]_s -> 0 < [v]_s ->
uivi_init u v u1 u2 u3 v1 v2 v3 s ->
ti_init u v t1 t2 t3 s ->
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s.
Proof.
move=> Hu Hv Huivi_init Hti_init.
rewrite /uivi_init in Hti_init.
rewrite /uivi_init in Huivi_init.
case : Huivi_init => [Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]].
split.
rewrite /uivi_bounds Hu1 Hu2 Hu3 Hv1 Hv2 Hv3.
lia.
rewrite /ti_bounds.
case: (Zeven_odd_dec [u]_s).
case/(proj2 Hti_init) => -> [-> ->]; lia.
case/(proj1 Hti_init)=> -> [-> ->]; lia.
Qed.
Module BEGCD_TAOCP_COR.
Section begcd_taocp_cor.
Variables g u v u1 u2 u3 v1 v2 v3 t1 t2 t3 : nat.
Variables vu vv : Z.
Lemma triple_init :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s h => uv_init vu vv u v s }}
g <- nat_e 1;
prelude u v g;
BEGCD_TAOCP.init u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\
ti_init u v t1 t2 t3 s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s}}.
Proof.
move=> Hset Hvu Hvv.
eapply hoare_prop_m.hoare_weak; last exact: BEGCD_TAOCP_FUN_COR.triple_prelude_init.
rewrite /while.entails => s h.
case => HC2 [HC3 [Huivi_init Hti_init]].
repeat (split; first by []).
rewrite /C2 in HC2.
apply init_bounds => //; tauto.
Qed.
Lemma while_halve_invariant : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) ->
0 < vu -> 0 < vv ->
{{ fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ [t3 ]_ s <> 0) /\
hoare_m.eval_b (var_e t3 \% nat_e 2 \= nat_e 0) (s, h)}}
while.ifte (var_e t1 \% nat_e 2 \= nat_e 0 \&& var_e t2 \% nat_e 2 \= nat_e 0)
(t1 <- var_e t1 ./e nat_e 2;
t2 <- var_e t2 ./e nat_e 2;
t3 <- var_e t3 ./e nat_e 2)
(t1 <- (var_e t1 \+ var_e v) ./e nat_e 2;
t2 <- (var_e t2 \- var_e u) ./e nat_e 2;
t3 <- var_e t3 ./e nat_e 2)
{{ fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ [t3 ]_ s <> 0 }}.
Proof.
move=> Hset Hvu Hvv.
apply while.hoare_ifte.
- apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * 2 * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3 ]_ s <> 0 /\
Zeven [t3]_s /\
Zeven [t2]_s).
move=> s h /=.
case => [[[[Hu [Hv [Hg [u_g v_g]]]] [H7 [[Hti [Hui Hvi]] [H11 [[Hu3 Hv3] [H14 [Hinvar1 [Hinvar2 H16]]]]]]]] H3] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first by []).
split.
rewrite -mulZA div_e_exact_full_2 //.
rewrite /hoare_m.eval_b /= in H1.
case/andP : H1 => H1 _.
rewrite /ZIT.eqb /ZIT.rem /= in H1.
by move/eqP : H1.
repeat (split; first tauto).
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem /= in H1, H3.
move/eqP in H3.
case/andP : H1 => _ /eqP H1.
split.
rewrite /uivi_bounds in Hinvar1 *.
by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; last tauto.
rewrite /= /ZIT.div.
split.
apply Z_div_pos => //; tauto.
apply (@leZ_trans ([t1]_s)); last tauto.
apply Zdiv_le_pos => //; tauto.
split; [assumption | split; exact: Zmod_2_Zeven].
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * 2 * [t1 ]_ s + [v ]_ s * 2 * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3 ]_ s <> 0 /\ Zeven [t3 ]_ s ).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 [H14 H16]]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first tauto).
split; first by rewrite -(mulZA [v]_s) div_e_exact_full_2 //; exact: Zeven_Zmod_2.
repeat (split; first by []).
split.
rewrite /uivi_bounds in Hinvar1 *.
by repeat Store_upd.
split; last by [].
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.div.
split.
apply (@leZ_trans ([t2]_s)); [tauto | apply Zdiv_le_neg => //; tauto].
apply Z_div_neg => //; tauto.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 H15]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite /= -Hti /ZIT.div.
set tmp := _ + [v]_s * 2 * _ .
have -> : tmp = ([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s) * 2 by rewrite /tmp; ring.
by rewrite Z_div_mult_full.
repeat (split; first by []).
split.
case/Zeven_ex : H15 => m H15.
rewrite [eval _ _]/= H15 (mulZC 2) /ZIT.div Z_div_mult_full //.
case: H9 => k [ [H9 H9'] | ].
+ exists (S k); left.
by rewrite ZpowerS mulZA -(mulZC 2) -H15.
+ case => H9; exists (S k); right.
* left; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
* right; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
repeat (split; first by []).
split.
rewrite /uivi_bounds.
by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
repeat (split; first tauto).
rewrite /= /ZIT.div.
split.
case: (Z_lt_le_dec [t3]_s 0) => Ht3.
apply (@leZ_trans [t3]_s); first tauto.
apply Zdiv_le_neg => //; exact: ltZW.
apply (@leZ_trans 0); first lia.
exact: Z_div_pos.
case: (Z_lt_le_dec [t3]_s 0) => Ht3.
apply (@leZ_trans 0); last lia.
apply Z_div_neg => //; exact: ltZW.
apply (@leZ_trans [t3]_s); [exact: Zdiv_le_pos | tauto].
case/Zeven_ex : H15 => m H15.
rewrite /= H15 (mulZC 2) /ZIT.div Z_div_mult_full //; lia.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * (2 * [t1 ]_ s - [v]_s) + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3 ]_ s <> 0 /\ Zeven [t3]_s /\
(Zodd (2 * [t1]_s - [v]_s) \/ Zodd [t2]_s)).
move=> s h.
case => [[[[Hu [Hv [Hg [u_g v_g]]] [H7 [[Hti [Hui Hvi]] [H11 [[Hu3 Hv3] [H14 [Hinvar1 [Hinvar2 H16]]]]]]]]] H3] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem in H1 H3.
rewrite negb_and in H1.
have t1_v : [var_e t1 \+ var_e v ]e_ s mod 2 = 0.
rewrite /= /ZIT.add.
case/orP: H1 => [/eqP odd_t1 | /eqP odd_t2].
- apply Zeven_Zmod_2, Zodd_plus_Zodd.
exact: not_Zmod_2_Zodd.
case: H7 => [odd_u |]; last exact.
move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2] | [] _].
+ move/not_Zmod_2_Zodd : odd_t1.
move/(Zodd_mult_Zodd _ _ odd_u).
by move/Zodd_not_Zeven.
+ by case/Zodd_mult_inv.
- case: H7 => [odd_u | odd_v].
+ move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2] | []].
* case/Zeven_mult_inv : v_t2 => v_t2.
- case/Zeven_mult_inv : u_t1 => u_t1.
+ by move/Zodd_not_Zeven : odd_u.
+ exact/Zeven_Zmod_2/Zeven_plus_Zeven.
- move/not_Zmod_2_Zodd : odd_t2.
by move/Zodd_not_Zeven.
* case/Zodd_mult_inv=> _ odd_t1.
case/Zodd_mult_inv=> odd_v _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
+ move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2] | []].
* have : Zodd ([v ]_ s * [t2 ]_ s).
apply Zodd_mult_Zodd => //; exact: not_Zmod_2_Zodd.
by move/Zodd_not_Zeven.
* case/Zodd_mult_inv=> _ odd_t1 _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
repeat (split; first by []).
split.
split; by [rewrite div_e_exact_full_2 //= /ZIT.add -Hti; ring | ].
repeat (split; first by []).
split.
rewrite /uivi_bounds; by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
rewrite /= /ZIT.div /ZIT.add.
split; last tauto.
split.
+ apply Z_div_pos => //; lia.
+ apply (@leZ_trans (([v]_s + [v]_s) / 2)).
apply Z_div_le => //; lia.
rewrite addZZ Z_div_mult_full //; exact: leZZ.
split; first by [].
split.
apply Zmod_2_Zeven; exact/eqP.
case/orP : H1 => H1.
- left.
rewrite div_e_exact_full_2 //.
move/eqP : H1 => /not_Zmod_2_Zodd.
suff : [var_e t1 \+ var_e v ]e_ s - [v ]_ s = [t1]_s by move=> ->.
rewrite /= /ZIT.add; ring.
- right.
by move/eqP/not_Zmod_2_Zodd : H1.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * (2 * [t1 ]_ s - [v]_s) + [v ]_ s * (2 * [t2 ]_ s + [u]_s) = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3 ]_ s <> 0 /\ Zeven [t3]_s).
move=> s h H.
rewrite (mulZC 2) /= -(mulZC 2) in H.
case: H => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 [H14 H16]]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
have Htmp : [var_e t2 \- var_e u ]e_ s mod 2 = 0.
rewrite /= /ZIT.sub.
apply Zeven_Zmod_2.
case: H5 => H5.
- case: H16 => H16.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv => [[] | [] ].
* case/Zeven_mult_inv; by move/Zeven_not_Zodd.
* case/Zodd_mult_inv=> K1 _.
case/Zodd_mult_inv=> _ K4.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
+ apply Zodd_plus_Zodd => //; exact: Zodd_opp.
- case: H16 => H16.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv => [[] | []].
* case/Zeven_mult_inv => [u_even | ].
- case/Zeven_mult_inv => [ | even_t2].
by move/Zeven_not_Zodd.
apply Zeven_plus_Zeven => //; exact: Zeven_opp.
- by move/Zeven_not_Zodd.
* case/Zodd_mult_inv=> odd_u _.
case/Zodd_mult_inv=> _ odd_t2.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv => [[] | []].
* case/Zeven_mult_inv => [u_even | _]; case/Zeven_mult_inv; by move/Zeven_not_Zodd.
* case/Zodd_mult_inv=> K1 _ _.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
repeat (split; first by []).
split.
split; by [rewrite div_e_exact_full_2 // /ZIT.add -Hti (mulZC 2) /= /ZIT.sub; ring | ].
repeat (split; first by []).
split.
rewrite /uivi_bounds; by repeat Store_upd.
split; last by [].
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.div /ZIT.sub.
split.
- apply (@leZ_trans ((- [u]_s - [u]_s) /2)).
apply Zdiv_le_lower_bound => //; lia.
apply Z_div_le => //; lia.
- apply Z_div_neg => //; lia.
apply hoare_assign' => s h H.
rewrite !(mulZC 2) in H.
case: H => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 H15]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
split; last by [].
rewrite /= -Hti /ZIT.div.
have : ([u ]_ s * ([t1 ]_ s * 2 - [v ]_ s) + [v ]_ s * ([t2 ]_ s * 2 + [u ]_ s)) =
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s) * 2 by ring.
move=> ->; by rewrite Z_div_mult_full.
split.
case/Zeven_ex : H15 => m H15.
rewrite [eval _ _]/= H15 (mulZC 2) /ZIT.div Z_div_mult_full //.
case: H9 => k H9.
case: H9 => H9.
- case: H9 => H9 H9'.
exists (S k); left.
by rewrite ZpowerS mulZA -(mulZC 2) -H15.
- case: H9 => H9; exists (S k); right.
+ left; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
+ right; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
repeat (split; first by []).
split.
rewrite /uivi_bounds; by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
repeat (split; first tauto).
rewrite /= /ZIT.div.
case: (Z_lt_le_dec [t3]_s 0) => Ht3.
split.
apply (@leZ_trans [t3]_s); first tauto.
apply Zdiv_le_neg => //; lia.
apply (@leZ_trans 0); last exact: ltZW.
apply Z_div_neg => //. exact: ltZW.
split.
apply (@leZ_trans 0); [lia | exact: Z_div_pos].
apply (@leZ_trans [t3]_s); [exact: Zdiv_le_pos | tauto].
case/Zeven_ex : H15 => m H15.
rewrite /= H15 mulZC /ZIT.div Z_div_mult_full //; lia.
Qed.
Lemma while_halve_invariant_stren :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
while.entails hoare_m.store hoare_m.heap
(fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s) /\
[ var_e t3 \!= nat_e 0 ]b_ s)
(fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ [t3 ]_ s <> 0).
Proof.
move=> Hset Hvu Hvv => s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [H7 [H8 [H9 [H10 [[Hu3 Hv3] [H12 [H14 [Hinvar1 Hinvar2]]]]]]]]]] H1].
repeat (split => //).
rewrite /hoare_m.eval_b /= /ZIT.eqb in H1.
by move/eqP : H1.
Qed.
Lemma while_halve_invariant_weak :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
while.entails hoare_m.store hoare_m.heap
(fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ [t3 ]_ s <> 0) /\
~~ [ var_e t3 \% nat_e 2 \= nat_e 0 ]b_ s)
(fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ Zodd [t3 ]_ s).
Proof.
move=> Hset Hvu Hvv => s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 [Hinvar1 [Hinvar2 H15]]]]]]]] H1].
repeat (split; first by []).
split.
rewrite -u_g -v_g -H13 -Zgcd_mult; last lia.
f_equal; by rewrite mulZC.
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem in H1.
move/eqP : H1; by move/not_Zmod_2_Zodd.
Qed.
Lemma while_halve :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s) /\
hoare_m.eval_b (var_e t3 \!= nat_e 0) (s, h) }}
while.while (var_e t3 \% nat_e 2 \= nat_e 0) (BEGCD_TAOCP.halve u v t1 t2 t3)
{{ fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ Zodd [t3 ]_ s}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /BEGCD_TAOCP.halve.
apply hoare_prop_m.hoare_while_invariant with (fun s h =>
C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3]_s <> 0).
exact: while_halve_invariant_stren.
exact: while_halve_invariant_weak.
exact: while_halve_invariant.
Qed.
Lemma reset_triple :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ Zodd [t3 ]_ s}}
BEGCD_TAOCP.reset u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
(0 <= [t3 ]_ s ->
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
Zodd [u3 ]_ s /\ [u3 ]_ s = [t3 ]_ s) /\
([t3 ]_ s < 0 ->
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\
Zodd [v3 ]_ s /\ [v3 ]_ s = - [t3 ]_ s) /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ C5 u3 v3 s}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /BEGCD_TAOCP.reset.
apply while.hoare_ifte.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\ Zodd [t3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
C5 u3 v3 s /\
0 < [t3]_s).
move=> s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 [Hinvar1 [Hinvar2 H15]]]]]]]] H1].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
rewrite /hoare_m.eval_b /= /ZIT.geb in H1.
move/geZP in H1.
repeat (split; first by []).
split.
rewrite /uivi_bounds /= in Hinvar1 *.
rewrite /ti_bounds in Hinvar2.
repeat Store_upd.
tauto.
split.
rewrite /ti_bounds; by repeat Store_upd.
move/Z.ge_le : H1; case/leZ_eqVlt => H1 //.
by rewrite -H1 in H15.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [t3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
Zodd [t3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
C5 u3 v3 s /\
0 < [t3 ]_ s).
move=> s h /=.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [H11 [Hinvar1 [Hinvar2 [[H3 Hv3] H17]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite /= /uivi_bounds in Hinvar1 *.
repeat Store_upd.
repeat (split; first tauto).
split; last tauto.
rewrite /ti_bounds in Hinvar2; tauto.
split; last by [].
rewrite /ti_bounds.
by repeat Store_upd.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [H11 [Hinvar1 [Hinvar2 [[Hu3 Hv3] H15]]]]]]]]].
rewrite /wp_assign /C2 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
move=> Ht3.
case: H9 => k [ [H9 H9'] | [ [H9 H9'] | [H9 H9'] ]].
- exfalso.
have : -[v3]_s < 0 by lia.
rewrite -H9.
move/Zlt_not_le.
apply.
apply mulZ_ge0 => //; exact: expZ_ge0.
- by rewrite -H9 Zgcd_Zpower_odd // in H10.
- have Htmp : [u3 ]_ s = [t3 ]_ s * 2 ^^ k + [v3 ]_ s by lia.
rewrite{} Htmp in H10.
move: (Zgcd_for_euclid ([t3 ]_ s * 2 ^^ k) [v3 ]_ s 1) => X.
rewrite mul1Z in X.
rewrite {}X in H10.
destruct k as [|k].
- by rewrite /= mulZ1 in H10.
- case: H9' => // H9'.
by rewrite Zgcd_Zpower_odd // in H10.
rewrite Zgcd_Zpower_odd // in H10.
have -> : [v3 ]_ s = [u3 ]_ s - [t3 ]_ s * 2 ^^ S k by lia.
apply Zodd_plus_Zeven => //.
exact/Zeven_opp/Zeven_mult_Zeven_r/Zeven_power.
split.
move=> Ht3.
exfalso.
lia.
split.
rewrite /uivi_bounds in Hinvar1 *.
repeat Store_upd.
repeat (split; first tauto).
split; last tauto.
rewrite /ti_bounds in Hinvar2.
rewrite /=; lia.
split.
rewrite /ti_bounds.
by repeat Store_upd.
rewrite /C5; by repeat Store_upd.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1]_s + [v]_s * (- [u]_s - [t2]_s ) = - [t3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
Zodd [t3 ]_ s /\
[t3]_s < 0).
move=> s h /= H.
case : H => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hi Hvi]] [H10 [[Hu3 Hv3] [H13 [Hinvar1 [Hinvar2 H15]]]]]]]] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first by []).
split.
repeat (split; first by []).
rewrite -Hti /= /ZIT.sub; ring.
repeat (split; first by []).
split.
rewrite /uivi_bounds in Hinvar1 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.sub.
rewrite /ti_bounds in Hinvar2.
lia.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
tauto.
split; first by [].
rewrite /hoare_m.eval_b /= /ZIT.geb in H1.
move/geZP : H1 => ?; lia.
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1]_s + [v]_s * [v2]_s = - [t3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
Zodd [t3 ]_ s /\ [t3 ]_ s < 0).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 H15]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first by []).
split.
repeat (split; first by []).
rewrite /= /ZIT.add -Hvi; ring.
repeat (split; first by []).
split.
rewrite /uivi_bounds in Hinvar1 *.
repeat Store_upd.
repeat (split; first tauto).
split; last tauto.
rewrite /= /ZIT.add.
rewrite /ti_bounds in Hinvar2; lia.
split; last by [].
rewrite /ti_bounds.
by repeat Store_upd.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 H15]]]]]]]]].
rewrite /wp_assign /C2 /C5 /CVectors.
repeat Store_upd.
repeat (split; first by []).
rewrite /=.
split; first by move/Zle_not_lt.
split.
move=> _.
rewrite /=.
case: H9 => k [ [H9 H9'] | [ [H9 H9'] | [H9 H9'] ] ].
- have X : [v3 ]_ s = - ([t3 ]_ s * 2 ^^ k) by lia.
rewrite {}X Zgcd_opp in H12.
symmetry in H12.
rewrite Zgcd_sym Zgcd_Zpower_odd // in H12.
split; first by symmetry; rewrite Zgcd_sym.
split; by [ apply Zodd_opp | ].
- rewrite -H9 in Hu3.
move: (Zmult_lt_0_reg_r _ _ (expZ_gt0 k) Hu3) => abs.
exfalso. lia.
- have Htmp : [v3]_s = [u3 ]_ s - [t3 ]_ s * 2 ^^ k by lia.
rewrite Htmp in H12.
move: (Zgcd_for_euclid (-[t3]_s * 2 ^^ k) ([u3]_s) 1).
rewrite mul1Z addZC mulNZ addZNE Zgcd_sym.
move=> X.
rewrite X (Zgcd_sym _ [u3]_s) Zgcd_opp (Zgcd_sym [u3]_s) in H12.
destruct k.
+ rewrite /= mulZ1 in H12.
split; first by rewrite (Zgcd_sym [u3]_s).
split; by [ apply Zodd_opp | ].
+ rewrite Zgcd_Zpower_odd // in H12; last first.
have -> : [u3 ]_ s = [v3 ]_ s + [t3 ]_ s * 2 ^^ S k by lia.
apply Zodd_plus_Zeven; last exact/Zeven_mult_Zeven_r/Zeven_power.
case: H9' => H9' //.
rewrite Htmp.
apply Zodd_plus_Zeven => //.
exact/Zeven_opp/Zeven_mult_Zeven_r/Zeven_power.
split; first by rewrite (Zgcd_sym [u3]_s).
split; by [ apply Zodd_opp | ].
split.
rewrite /uivi_bounds in Hinvar1 *.
repeat Store_upd.
repeat (split; first tauto).
rewrite /ti_bounds in Hinvar2.
lia.
split.
rewrite /ti_bounds.
by repeat Store_upd.
lia.
Qed.
Lemma subtract_part1 : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
(0 <= [t3 ]_ s ->
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
Zodd [u3 ]_ s /\ [u3 ]_ s = [t3 ]_ s) /\
([t3 ]_ s < 0 ->
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\
Zodd [v3 ]_ s /\ [v3 ]_ s = - [t3 ]_ s) /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ C5 u3 v3 s}}
t1 <- var_e u1 \- var_e v1;
t2 <- var_e u2 \- var_e v2; t3 <- var_e u3 \- var_e v3
{{fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
[t3 ]_ s = [u3 ]_ s - [v3 ]_ s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
[t1 ]_ s = [u1 ]_ s - [v1 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
((0 < [t1]_s -> ti_bounds u v t1 t2 t3 s) /\
([t1]_s <= 0 ->
0 <= [t1 ]_ s + [v ]_ s <= [v ]_ s /\
- [u ]_ s <= [t2 ]_ s - [u ]_ s <= 0 /\
- [v ]_ s <= [t3 ]_ s <= [u ]_ s)) /\
(Zodd [v3 ]_ s \/ Zodd [u3 ]_ s) /\ C5 u3 v3 s}}.
Proof.
move=> Hset Hvu Hvv.
have Hset' : uniq(u, v, g) by rewrite [Equality.sort _]/= in Hset *; Uniq_uniq O.
eapply while.hoare_conseq; last exact: (prelude_triple_strict Hset' Hvu Hvv).
- move=> s h /= [[H1 [H2 [H3 [H4 H5]]]] H6].
rewrite /C2 /C3.
repeat (split; first lia).
split; last by move/negP: H6.
rewrite -H4 -H5.
apply Zis_gcd_gcd; last first.
rewrite (mulZC [u]_s) (mulZC [v]_s).
exact/Zis_gcd_mult/Zgcd_is_gcd.
apply mulZ_ge0 => //; [lia | exact: Zgcd_is_pos].
- rewrite /C1 /uv_init /C2 => s h /= [[-> ->] ->]; by rewrite 2!mulZ1.
exact: triple_init.
Qed.
Lemma triple :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s h => [u]_s = vu /\ [v]_s = vv }}
begcd g u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{ fun s h => vu * [u1]_s + vv * [u2]_s = [g]_s * [u3]_s /\
Z.gcd vu vv = ([g]_s * [u3]_s)}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /begcd.
do 2 apply hoare_prop_m.hoare_seq_assoc'.
eapply while.hoare_seq.
apply hoare_prop_m.hoare_seq_assoc.
exact: triple_prelude_init.
exact: triple_intermediate.
Qed.
End begcd_taocp_fun_cor.
End BEGCD_TAOCP_FUN_COR.
Definition uivi_bounds u v u1 v1 u2 v2 u3 v3 st :=
0 <= [u1 ]_ st <= [v ]_ st /\ 0 <= [v1 ]_ st <= [v ]_ st /\
- [u ]_ st <= [u2 ]_ st <= 0 /\ - [u ]_ st <= [v2 ]_ st <= 0 /\
0 < [u3 ]_ st <= [u ]_ st /\ 0 < [v3 ]_ st <= [v ]_ st.
Definition ti_bounds u v t1 t2 t3 st :=
0 <= [t1 ]_ st <= [v ]_ st /\
- [u ]_ st <= [t2 ]_ st <= 0 /\
- [v ]_ st <= [t3 ]_ st <= [u ]_ st.
Lemma init_bounds u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s :
0 < [u]_s -> 0 < [v]_s ->
uivi_init u v u1 u2 u3 v1 v2 v3 s ->
ti_init u v t1 t2 t3 s ->
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s.
Proof.
move=> Hu Hv Huivi_init Hti_init.
rewrite /uivi_init in Hti_init.
rewrite /uivi_init in Huivi_init.
case : Huivi_init => [Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]].
split.
rewrite /uivi_bounds Hu1 Hu2 Hu3 Hv1 Hv2 Hv3.
lia.
rewrite /ti_bounds.
case: (Zeven_odd_dec [u]_s).
case/(proj2 Hti_init) => -> [-> ->]; lia.
case/(proj1 Hti_init)=> -> [-> ->]; lia.
Qed.
Module BEGCD_TAOCP_COR.
Section begcd_taocp_cor.
Variables g u v u1 u2 u3 v1 v2 v3 t1 t2 t3 : nat.
Variables vu vv : Z.
Lemma triple_init :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s h => uv_init vu vv u v s }}
g <- nat_e 1;
prelude u v g;
BEGCD_TAOCP.init u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\
ti_init u v t1 t2 t3 s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s}}.
Proof.
move=> Hset Hvu Hvv.
eapply hoare_prop_m.hoare_weak; last exact: BEGCD_TAOCP_FUN_COR.triple_prelude_init.
rewrite /while.entails => s h.
case => HC2 [HC3 [Huivi_init Hti_init]].
repeat (split; first by []).
rewrite /C2 in HC2.
apply init_bounds => //; tauto.
Qed.
Lemma while_halve_invariant : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) ->
0 < vu -> 0 < vv ->
{{ fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ [t3 ]_ s <> 0) /\
hoare_m.eval_b (var_e t3 \% nat_e 2 \= nat_e 0) (s, h)}}
while.ifte (var_e t1 \% nat_e 2 \= nat_e 0 \&& var_e t2 \% nat_e 2 \= nat_e 0)
(t1 <- var_e t1 ./e nat_e 2;
t2 <- var_e t2 ./e nat_e 2;
t3 <- var_e t3 ./e nat_e 2)
(t1 <- (var_e t1 \+ var_e v) ./e nat_e 2;
t2 <- (var_e t2 \- var_e u) ./e nat_e 2;
t3 <- var_e t3 ./e nat_e 2)
{{ fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ [t3 ]_ s <> 0 }}.
Proof.
move=> Hset Hvu Hvv.
apply while.hoare_ifte.
- apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * 2 * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3 ]_ s <> 0 /\
Zeven [t3]_s /\
Zeven [t2]_s).
move=> s h /=.
case => [[[[Hu [Hv [Hg [u_g v_g]]]] [H7 [[Hti [Hui Hvi]] [H11 [[Hu3 Hv3] [H14 [Hinvar1 [Hinvar2 H16]]]]]]]] H3] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first by []).
split.
rewrite -mulZA div_e_exact_full_2 //.
rewrite /hoare_m.eval_b /= in H1.
case/andP : H1 => H1 _.
rewrite /ZIT.eqb /ZIT.rem /= in H1.
by move/eqP : H1.
repeat (split; first tauto).
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem /= in H1, H3.
move/eqP in H3.
case/andP : H1 => _ /eqP H1.
split.
rewrite /uivi_bounds in Hinvar1 *.
by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; last tauto.
rewrite /= /ZIT.div.
split.
apply Z_div_pos => //; tauto.
apply (@leZ_trans ([t1]_s)); last tauto.
apply Zdiv_le_pos => //; tauto.
split; [assumption | split; exact: Zmod_2_Zeven].
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * 2 * [t1 ]_ s + [v ]_ s * 2 * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3 ]_ s <> 0 /\ Zeven [t3 ]_ s ).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 [H14 H16]]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first tauto).
split; first by rewrite -(mulZA [v]_s) div_e_exact_full_2 //; exact: Zeven_Zmod_2.
repeat (split; first by []).
split.
rewrite /uivi_bounds in Hinvar1 *.
by repeat Store_upd.
split; last by [].
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.div.
split.
apply (@leZ_trans ([t2]_s)); [tauto | apply Zdiv_le_neg => //; tauto].
apply Z_div_neg => //; tauto.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 H15]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite /= -Hti /ZIT.div.
set tmp := _ + [v]_s * 2 * _ .
have -> : tmp = ([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s) * 2 by rewrite /tmp; ring.
by rewrite Z_div_mult_full.
repeat (split; first by []).
split.
case/Zeven_ex : H15 => m H15.
rewrite [eval _ _]/= H15 (mulZC 2) /ZIT.div Z_div_mult_full //.
case: H9 => k [ [H9 H9'] | ].
+ exists (S k); left.
by rewrite ZpowerS mulZA -(mulZC 2) -H15.
+ case => H9; exists (S k); right.
* left; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
* right; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
repeat (split; first by []).
split.
rewrite /uivi_bounds.
by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
repeat (split; first tauto).
rewrite /= /ZIT.div.
split.
case: (Z_lt_le_dec [t3]_s 0) => Ht3.
apply (@leZ_trans [t3]_s); first tauto.
apply Zdiv_le_neg => //; exact: ltZW.
apply (@leZ_trans 0); first lia.
exact: Z_div_pos.
case: (Z_lt_le_dec [t3]_s 0) => Ht3.
apply (@leZ_trans 0); last lia.
apply Z_div_neg => //; exact: ltZW.
apply (@leZ_trans [t3]_s); [exact: Zdiv_le_pos | tauto].
case/Zeven_ex : H15 => m H15.
rewrite /= H15 (mulZC 2) /ZIT.div Z_div_mult_full //; lia.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * (2 * [t1 ]_ s - [v]_s) + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3 ]_ s <> 0 /\ Zeven [t3]_s /\
(Zodd (2 * [t1]_s - [v]_s) \/ Zodd [t2]_s)).
move=> s h.
case => [[[[Hu [Hv [Hg [u_g v_g]]] [H7 [[Hti [Hui Hvi]] [H11 [[Hu3 Hv3] [H14 [Hinvar1 [Hinvar2 H16]]]]]]]]] H3] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem in H1 H3.
rewrite negb_and in H1.
have t1_v : [var_e t1 \+ var_e v ]e_ s mod 2 = 0.
rewrite /= /ZIT.add.
case/orP: H1 => [/eqP odd_t1 | /eqP odd_t2].
- apply Zeven_Zmod_2, Zodd_plus_Zodd.
exact: not_Zmod_2_Zodd.
case: H7 => [odd_u |]; last exact.
move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2] | [] _].
+ move/not_Zmod_2_Zodd : odd_t1.
move/(Zodd_mult_Zodd _ _ odd_u).
by move/Zodd_not_Zeven.
+ by case/Zodd_mult_inv.
- case: H7 => [odd_u | odd_v].
+ move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2] | []].
* case/Zeven_mult_inv : v_t2 => v_t2.
- case/Zeven_mult_inv : u_t1 => u_t1.
+ by move/Zodd_not_Zeven : odd_u.
+ exact/Zeven_Zmod_2/Zeven_plus_Zeven.
- move/not_Zmod_2_Zodd : odd_t2.
by move/Zodd_not_Zeven.
* case/Zodd_mult_inv=> _ odd_t1.
case/Zodd_mult_inv=> odd_v _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
+ move/eqP/Zmod_2_Zeven : H3.
rewrite -Hti.
case/Zeven_plus_inv => [[u_t1 v_t2] | []].
* have : Zodd ([v ]_ s * [t2 ]_ s).
apply Zodd_mult_Zodd => //; exact: not_Zmod_2_Zodd.
by move/Zodd_not_Zeven.
* case/Zodd_mult_inv=> _ odd_t1 _.
exact/Zeven_Zmod_2/Zodd_plus_Zodd.
repeat (split; first by []).
split.
split; by [rewrite div_e_exact_full_2 //= /ZIT.add -Hti; ring | ].
repeat (split; first by []).
split.
rewrite /uivi_bounds; by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
rewrite /= /ZIT.div /ZIT.add.
split; last tauto.
split.
+ apply Z_div_pos => //; lia.
+ apply (@leZ_trans (([v]_s + [v]_s) / 2)).
apply Z_div_le => //; lia.
rewrite addZZ Z_div_mult_full //; exact: leZZ.
split; first by [].
split.
apply Zmod_2_Zeven; exact/eqP.
case/orP : H1 => H1.
- left.
rewrite div_e_exact_full_2 //.
move/eqP : H1 => /not_Zmod_2_Zodd.
suff : [var_e t1 \+ var_e v ]e_ s - [v ]_ s = [t1]_s by move=> ->.
rewrite /= /ZIT.add; ring.
- right.
by move/eqP/not_Zmod_2_Zodd : H1.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * (2 * [t1 ]_ s - [v]_s) + [v ]_ s * (2 * [t2 ]_ s + [u]_s) = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3 ]_ s <> 0 /\ Zeven [t3]_s).
move=> s h H.
rewrite (mulZC 2) /= -(mulZC 2) in H.
case: H => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 [H14 H16]]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
have Htmp : [var_e t2 \- var_e u ]e_ s mod 2 = 0.
rewrite /= /ZIT.sub.
apply Zeven_Zmod_2.
case: H5 => H5.
- case: H16 => H16.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv => [[] | [] ].
* case/Zeven_mult_inv; by move/Zeven_not_Zodd.
* case/Zodd_mult_inv=> K1 _.
case/Zodd_mult_inv=> _ K4.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
+ apply Zodd_plus_Zodd => //; exact: Zodd_opp.
- case: H16 => H16.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv => [[] | []].
* case/Zeven_mult_inv => [u_even | ].
- case/Zeven_mult_inv => [ | even_t2].
by move/Zeven_not_Zodd.
apply Zeven_plus_Zeven => //; exact: Zeven_opp.
- by move/Zeven_not_Zodd.
* case/Zodd_mult_inv=> odd_u _.
case/Zodd_mult_inv=> _ odd_t2.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
+ move: H14.
rewrite -Hti.
case/Zeven_plus_inv => [[] | []].
* case/Zeven_mult_inv => [u_even | _]; case/Zeven_mult_inv; by move/Zeven_not_Zodd.
* case/Zodd_mult_inv=> K1 _ _.
apply Zodd_plus_Zodd => //; exact: Zodd_opp.
repeat (split; first by []).
split.
split; by [rewrite div_e_exact_full_2 // /ZIT.add -Hti (mulZC 2) /= /ZIT.sub; ring | ].
repeat (split; first by []).
split.
rewrite /uivi_bounds; by repeat Store_upd.
split; last by [].
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.div /ZIT.sub.
split.
- apply (@leZ_trans ((- [u]_s - [u]_s) /2)).
apply Zdiv_le_lower_bound => //; lia.
apply Z_div_le => //; lia.
- apply Z_div_neg => //; lia.
apply hoare_assign' => s h H.
rewrite !(mulZC 2) in H.
case: H => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 H15]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
split; last by [].
rewrite /= -Hti /ZIT.div.
have : ([u ]_ s * ([t1 ]_ s * 2 - [v ]_ s) + [v ]_ s * ([t2 ]_ s * 2 + [u ]_ s)) =
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s) * 2 by ring.
move=> ->; by rewrite Z_div_mult_full.
split.
case/Zeven_ex : H15 => m H15.
rewrite [eval _ _]/= H15 (mulZC 2) /ZIT.div Z_div_mult_full //.
case: H9 => k H9.
case: H9 => H9.
- case: H9 => H9 H9'.
exists (S k); left.
by rewrite ZpowerS mulZA -(mulZC 2) -H15.
- case: H9 => H9; exists (S k); right.
+ left; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
+ right; by rewrite ZpowerS mulZA -(mulZC 2) -H15.
repeat (split; first by []).
split.
rewrite /uivi_bounds; by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
repeat (split; first tauto).
rewrite /= /ZIT.div.
case: (Z_lt_le_dec [t3]_s 0) => Ht3.
split.
apply (@leZ_trans [t3]_s); first tauto.
apply Zdiv_le_neg => //; lia.
apply (@leZ_trans 0); last exact: ltZW.
apply Z_div_neg => //. exact: ltZW.
split.
apply (@leZ_trans 0); [lia | exact: Z_div_pos].
apply (@leZ_trans [t3]_s); [exact: Zdiv_le_pos | tauto].
case/Zeven_ex : H15 => m H15.
rewrite /= H15 mulZC /ZIT.div Z_div_mult_full //; lia.
Qed.
Lemma while_halve_invariant_stren :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
while.entails hoare_m.store hoare_m.heap
(fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s) /\
[ var_e t3 \!= nat_e 0 ]b_ s)
(fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ [t3 ]_ s <> 0).
Proof.
move=> Hset Hvu Hvv => s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [H7 [H8 [H9 [H10 [[Hu3 Hv3] [H12 [H14 [Hinvar1 Hinvar2]]]]]]]]]] H1].
repeat (split => //).
rewrite /hoare_m.eval_b /= /ZIT.eqb in H1.
by move/eqP : H1.
Qed.
Lemma while_halve_invariant_weak :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
while.entails hoare_m.store hoare_m.heap
(fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ [t3 ]_ s <> 0) /\
~~ [ var_e t3 \% nat_e 2 \= nat_e 0 ]b_ s)
(fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ Zodd [t3 ]_ s).
Proof.
move=> Hset Hvu Hvv => s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 [Hinvar1 [Hinvar2 H15]]]]]]]] H1].
repeat (split; first by []).
split.
rewrite -u_g -v_g -H13 -Zgcd_mult; last lia.
f_equal; by rewrite mulZC.
rewrite /hoare_m.eval_b /= /ZIT.eqb /ZIT.rem in H1.
move/eqP : H1; by move/not_Zmod_2_Zodd.
Qed.
Lemma while_halve :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s) /\
hoare_m.eval_b (var_e t3 \!= nat_e 0) (s, h) }}
while.while (var_e t3 \% nat_e 2 \= nat_e 0) (BEGCD_TAOCP.halve u v t1 t2 t3)
{{ fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ Zodd [t3 ]_ s}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /BEGCD_TAOCP.halve.
apply hoare_prop_m.hoare_while_invariant with (fun s h =>
C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
[t3]_s <> 0).
exact: while_halve_invariant_stren.
exact: while_halve_invariant_weak.
exact: while_halve_invariant.
Qed.
Lemma reset_triple :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ Zodd [t3 ]_ s}}
BEGCD_TAOCP.reset u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
(0 <= [t3 ]_ s ->
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
Zodd [u3 ]_ s /\ [u3 ]_ s = [t3 ]_ s) /\
([t3 ]_ s < 0 ->
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\
Zodd [v3 ]_ s /\ [v3 ]_ s = - [t3 ]_ s) /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ C5 u3 v3 s}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /BEGCD_TAOCP.reset.
apply while.hoare_ifte.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\ Zodd [t3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
C5 u3 v3 s /\
0 < [t3]_s).
move=> s h /=.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H13 [Hinvar1 [Hinvar2 H15]]]]]]]] H1].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
rewrite /hoare_m.eval_b /= /ZIT.geb in H1.
move/geZP in H1.
repeat (split; first by []).
split.
rewrite /uivi_bounds /= in Hinvar1 *.
rewrite /ti_bounds in Hinvar2.
repeat Store_upd.
tauto.
split.
rewrite /ti_bounds; by repeat Store_upd.
move/Z.ge_le : H1; case/leZ_eqVlt => H1 //.
by rewrite -H1 in H15.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [t3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
C4 u3 v3 t3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
Zodd [t3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
C5 u3 v3 s /\
0 < [t3 ]_ s).
move=> s h /=.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [H11 [Hinvar1 [Hinvar2 [[H3 Hv3] H17]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
rewrite /= /uivi_bounds in Hinvar1 *.
repeat Store_upd.
repeat (split; first tauto).
split; last tauto.
rewrite /ti_bounds in Hinvar2; tauto.
split; last by [].
rewrite /ti_bounds.
by repeat Store_upd.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [H11 [Hinvar1 [Hinvar2 [[Hu3 Hv3] H15]]]]]]]]].
rewrite /wp_assign /C2 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
move=> Ht3.
case: H9 => k [ [H9 H9'] | [ [H9 H9'] | [H9 H9'] ]].
- exfalso.
have : -[v3]_s < 0 by lia.
rewrite -H9.
move/Zlt_not_le.
apply.
apply mulZ_ge0 => //; exact: expZ_ge0.
- by rewrite -H9 Zgcd_Zpower_odd // in H10.
- have Htmp : [u3 ]_ s = [t3 ]_ s * 2 ^^ k + [v3 ]_ s by lia.
rewrite{} Htmp in H10.
move: (Zgcd_for_euclid ([t3 ]_ s * 2 ^^ k) [v3 ]_ s 1) => X.
rewrite mul1Z in X.
rewrite {}X in H10.
destruct k as [|k].
- by rewrite /= mulZ1 in H10.
- case: H9' => // H9'.
by rewrite Zgcd_Zpower_odd // in H10.
rewrite Zgcd_Zpower_odd // in H10.
have -> : [v3 ]_ s = [u3 ]_ s - [t3 ]_ s * 2 ^^ S k by lia.
apply Zodd_plus_Zeven => //.
exact/Zeven_opp/Zeven_mult_Zeven_r/Zeven_power.
split.
move=> Ht3.
exfalso.
lia.
split.
rewrite /uivi_bounds in Hinvar1 *.
repeat Store_upd.
repeat (split; first tauto).
split; last tauto.
rewrite /ti_bounds in Hinvar2.
rewrite /=; lia.
split.
rewrite /ti_bounds.
by repeat Store_upd.
rewrite /C5; by repeat Store_upd.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1]_s + [v]_s * (- [u]_s - [t2]_s ) = - [t3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
Zodd [t3 ]_ s /\
[t3]_s < 0).
move=> s h /= H.
case : H => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hi Hvi]] [H10 [[Hu3 Hv3] [H13 [Hinvar1 [Hinvar2 H15]]]]]]]] H1].
rewrite /wp_assign /C2 /C4 /C5.
repeat Store_upd.
repeat (split; first by []).
split.
repeat (split; first by []).
rewrite -Hti /= /ZIT.sub; ring.
repeat (split; first by []).
split.
rewrite /uivi_bounds in Hinvar1 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.sub.
rewrite /ti_bounds in Hinvar2.
lia.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
tauto.
split; first by [].
rewrite /hoare_m.eval_b /= /ZIT.geb in H1.
move/geZP : H1 => ?; lia.
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2 ]_ s = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1]_s + [v]_s * [v2]_s = - [t3 ]_ s) /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
Zodd [t3 ]_ s /\ [t3 ]_ s < 0).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 H15]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first by []).
split.
repeat (split; first by []).
rewrite /= /ZIT.add -Hvi; ring.
repeat (split; first by []).
split.
rewrite /uivi_bounds in Hinvar1 *.
repeat Store_upd.
repeat (split; first tauto).
split; last tauto.
rewrite /= /ZIT.add.
rewrite /ti_bounds in Hinvar2; lia.
split; last by [].
rewrite /ti_bounds.
by repeat Store_upd.
apply hoare_assign' => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [[Hu3 Hv3] [H12 [Hinvar1 [Hinvar2 [H13 H15]]]]]]]]].
rewrite /wp_assign /C2 /C5 /CVectors.
repeat Store_upd.
repeat (split; first by []).
rewrite /=.
split; first by move/Zle_not_lt.
split.
move=> _.
rewrite /=.
case: H9 => k [ [H9 H9'] | [ [H9 H9'] | [H9 H9'] ] ].
- have X : [v3 ]_ s = - ([t3 ]_ s * 2 ^^ k) by lia.
rewrite {}X Zgcd_opp in H12.
symmetry in H12.
rewrite Zgcd_sym Zgcd_Zpower_odd // in H12.
split; first by symmetry; rewrite Zgcd_sym.
split; by [ apply Zodd_opp | ].
- rewrite -H9 in Hu3.
move: (Zmult_lt_0_reg_r _ _ (expZ_gt0 k) Hu3) => abs.
exfalso. lia.
- have Htmp : [v3]_s = [u3 ]_ s - [t3 ]_ s * 2 ^^ k by lia.
rewrite Htmp in H12.
move: (Zgcd_for_euclid (-[t3]_s * 2 ^^ k) ([u3]_s) 1).
rewrite mul1Z addZC mulNZ addZNE Zgcd_sym.
move=> X.
rewrite X (Zgcd_sym _ [u3]_s) Zgcd_opp (Zgcd_sym [u3]_s) in H12.
destruct k.
+ rewrite /= mulZ1 in H12.
split; first by rewrite (Zgcd_sym [u3]_s).
split; by [ apply Zodd_opp | ].
+ rewrite Zgcd_Zpower_odd // in H12; last first.
have -> : [u3 ]_ s = [v3 ]_ s + [t3 ]_ s * 2 ^^ S k by lia.
apply Zodd_plus_Zeven; last exact/Zeven_mult_Zeven_r/Zeven_power.
case: H9' => H9' //.
rewrite Htmp.
apply Zodd_plus_Zeven => //.
exact/Zeven_opp/Zeven_mult_Zeven_r/Zeven_power.
split; first by rewrite (Zgcd_sym [u3]_s).
split; by [ apply Zodd_opp | ].
split.
rewrite /uivi_bounds in Hinvar1 *.
repeat Store_upd.
repeat (split; first tauto).
rewrite /ti_bounds in Hinvar2.
lia.
split.
rewrite /ti_bounds.
by repeat Store_upd.
lia.
Qed.
Lemma subtract_part1 : uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
(0 <= [t3 ]_ s ->
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
Zodd [u3 ]_ s /\ [u3 ]_ s = [t3 ]_ s) /\
([t3 ]_ s < 0 ->
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\
Zodd [v3 ]_ s /\ [v3 ]_ s = - [t3 ]_ s) /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ C5 u3 v3 s}}
t1 <- var_e u1 \- var_e v1;
t2 <- var_e u2 \- var_e v2; t3 <- var_e u3 \- var_e v3
{{fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
[t3 ]_ s = [u3 ]_ s - [v3 ]_ s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
[t1 ]_ s = [u1 ]_ s - [v1 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
((0 < [t1]_s -> ti_bounds u v t1 t2 t3 s) /\
([t1]_s <= 0 ->
0 <= [t1 ]_ s + [v ]_ s <= [v ]_ s /\
- [u ]_ s <= [t2 ]_ s - [u ]_ s <= 0 /\
- [v ]_ s <= [t3 ]_ s <= [u ]_ s)) /\
(Zodd [v3 ]_ s \/ Zodd [u3 ]_ s) /\ C5 u3 v3 s}}.
Proof.
move=> Hset Hvu Hvv.
t1 <- var_e u1 .-e var_e v1;
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * ([u2]_s - [v2 ]_ s) = [u3 ]_ s - [v3]_s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
(0 <= [t3 ]_ s -> Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s/\ Zodd [u3 ]_ s
/\ [u3 ]_ s = [t3 ]_ s) /\
([t3 ]_ s < 0 -> Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\ Zodd [v3 ]_ s /\
[v3 ]_ s = - [t3 ]_ s) /\
[t1]_s = [u1]_s - [v1]_s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
(([v1]_s < [u1]_s -> ti_bounds u v t1 t2 t3 s) /\
([u1]_s <= [v1]_s -> 0 <= [t1 ]_ s + [v]_s <= [v ]_ s /\
- [u ]_ s <= [t2 ]_ s <= 0 /\
- [v ]_ s <= [t3 ]_ s <= [u ]_ s)) /\
C5 u3 v3 s).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [Hinvar1 [Hinvar2 [Hu3 Hv3]]]]]]]].
rewrite /wp_assign /C2.
repeat Store_upd.
repeat (split; first by []).
split.
split; by [rewrite /= /ZIT.sub -Hui -Hvi; ring | ].
repeat (split; first by []).
split.
rewrite /uivi_bounds; by repeat Store_upd.
split.
split=> u1_v1.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; last tauto.
rewrite /= /ZIT.sub.
rewrite /uivi_bounds in Hinvar1.
lia.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; last tauto.
rewrite /= /ZIT.sub.
rewrite /uivi_bounds in Hinvar1.
lia.
rewrite /C5; by repeat Store_upd.
t2 <- svar u2 .-e svar v2;
apply hoare_assign with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * [t2]_s = [u3 ]_ s - [v3]_s/\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
(0 <= [t3 ]_ s ->
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s/\ Zodd [u3 ]_ s /\
[u3 ]_ s = [t3 ]_ s) /\
([t3 ]_ s < 0 ->
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s/\ Zodd [v3 ]_ s /\
[v3 ]_ s = - [t3 ]_ s) /\
[t1]_s = [u1]_s - [v1]_s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
(([v1]_s < [u1]_s -> ti_bounds u v t1 t2 t3 s) /\
([u1]_s <= [v1]_s -> 0 <= [t1 ]_ s + [v]_s <= [v ]_ s /\
- [u ]_ s <= [t2 ]_ s - [u]_s <= 0 /\
- [v ]_ s <= [t3 ]_ s <= [u ]_ s)) /\
C5 u3 v3 s).
move=> s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [tuv1 [Hinvar1 [Hinvar2 [Hu3 Hv3]]]]]]]]].
rewrite /wp_assign /C2.
repeat Store_upd.
repeat (split; first by []).
split.
rewrite /uivi_bounds; by repeat Store_upd.
split.
split=> u1_v1.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.sub.
move: {Hinvar2}(proj1 Hinvar2 u1_v1) => Hinvar2.
rewrite /uivi_bounds in Hinvar1.
split.
lia.
have Htmp : [v3]_s + [v]_s * ([u2]_s - [v2]_s) <= 0.
have -> : [v3]_s + [v]_s * ([u2]_s - [v2]_s) = [u3 ]_ s - [u ]_ s * ([u1 ]_ s - [v1 ]_ s).
rewrite !mulZBr in Hti *.
lia.
have Htmp : 0 < [u1 ]_ s - [v1 ]_ s.
lia.
apply (@leZ_trans ([u ]_ s - [u ]_ s * ([u1 ]_ s - [v1 ]_ s))).
apply leZ_sub => //; lia.
have Htmp2 : [u ]_ s <= [u ]_ s * ([u1 ]_ s - [v1 ]_ s).
apply Zle_scale => //; lia.
lia.
apply Zle_plus_0_inv in Htmp; last lia.
apply Zle_mult_0_inv in Htmp; last lia.
by [].
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.sub.
rewrite /uivi_bounds in Hinvar1.
split; last lia.
move: {Hinvar2}(proj2 Hinvar2 u1_v1) => Hinvar2.
suff : 0 <= [u2 ]_ s - [v2 ]_ s by move=> ?; lia.
have Htmp : - [v]_s * ([u2]_s - [v2]_s) - [v3]_s < 0.
have -> : - [v ]_ s * ([u2 ]_ s - [v2 ]_ s) - [v3 ]_ s =
[u]_s * ([u1]_s - [v1]_s) - [u3]_s.
have Htmp : [u3 ]_ s = [u ]_ s * [t1 ]_ s + [v ]_ s * ([u2 ]_ s - [v2 ]_ s) + [v3 ]_ s.
lia.
rewrite Htmp tuv1; ring.
have Htmp : [u1 ]_ s - [v1 ]_ s <= 0 by lia.
have {}Htmp : [u ]_ s * ([u1 ]_ s - [v1 ]_ s) <= 0.
apply mulZ_ge0_le0 => //; lia.
lia.
have {}Htmp : - [v ]_ s * ([u2 ]_ s - [v2 ]_ s) < [v3 ]_ s by lia.
apply/leZP/negPn/negP; rewrite -ltZNge' => /ltZP abs.
have {}Htmp : - [v ]_ s * ([u2 ]_ s - [v2 ]_ s) < [v]_s by lia.
rewrite mulNZ -mulZN in Htmp.
apply Zlt_Zmult_inv' in Htmp; last 2 first.
lia.
lia.
by apply ltZZ in Htmp.
lia.
rewrite /C5; by repeat Store_upd.
t3 <- var_e u3 .-e var_e v3
apply hoare_assign'.
move=> s h [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [tuv1 [Hinvar1 [Hinvar2 [Hu3 Hv3]]]]]]]]].
rewrite /wp_assign /C2 /CVectors.
repeat Store_upd.
repeat (split; first tauto).
split.
case: (Z_lt_le_dec [t3]_s 0).
- move/H10 => H10'.
move: (Zgcd_for_euclid [u3]_s [v3]_s (-1)).
rewrite mulN1Z addZNE => ->.
case: H10' => H10' [H10'' ->].
rewrite Zgcd_opp; tauto.
- case/H9 => H9' [H9'' /= ->].
move: (Zgcd_for_euclid [t3]_s [v3]_s (-1)).
by rewrite mulN1Z addZNE => ->.
split; first by [].
split.
rewrite /uivi_bounds; by repeat Store_upd.
split.
split=> v1_u1.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
repeat (split; first tauto).
rewrite /= /ZIT.sub.
rewrite /uivi_bounds in Hinvar1.
lia.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
repeat (split; first tauto).
rewrite /= /ZIT.sub.
rewrite /uivi_bounds in Hinvar1; lia.
split; last by rewrite /C5; repeat Store_upd.
case: (Z_lt_le_dec [t3]_s 0) => [/H10 | /H9]; tauto.
Qed.
Lemma subtract_triple :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
(0 <= [t3 ]_ s ->
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
Zodd [u3 ]_ s /\ [u3 ]_ s = [t3 ]_ s) /\
([t3 ]_ s < 0 ->
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\
Zodd [v3 ]_ s /\ [v3 ]_ s = - [t3 ]_ s) /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\ C5 u3 v3 s}}
BEGCD_TAOCP.subtract u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{ fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s}}.
Proof.
move=> Hset Hvu Hvv.
rewrite /BEGCD_TAOCP.subtract.
apply while.hoare_seq with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
[t3]_s = [u3]_s - [v3]_s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
[t1]_s = [u1]_s - [v1]_s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
((0 < [t1]_s -> ti_bounds u v t1 t2 t3 s) /\
([t1]_s <= 0 -> 0 <= [t1 ]_ s + [v]_s <= [v ]_ s /\
- [u ]_ s <= [t2 ]_ s - [u]_s <= 0 /\
- [v ]_ s <= [t3 ]_ s <= [u ]_ s)) /\
(Zodd [v3 ]_ s \/ Zodd [u3 ]_ s) /\
C5 u3 v3 s).
exact: subtract_part1.
apply while.hoare_ifte.
apply hoare_assign with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
([u ]_ s * [t1 ]_ s + [v ]_ s * ([t2]_s - [u]_s) = [t3 ]_ s /\
[u ]_ s * [u1 ]_ s + [v ]_ s * [u2 ]_ s = [u3 ]_ s /\
[u ]_ s * [v1 ]_ s + [v ]_ s * [v2 ]_ s = [v3 ]_ s) /\
[t3 ]_ s = [u3 ]_ s - [v3 ]_ s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\
[u1]_s <= [v1]_s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
(0 <= [t1 ]_ s <= [v ]_ s /\
- [u ]_ s <= [t2 ]_ s - [u]_s <= 0 /\
- [v ]_ s <= [t3 ]_ s <= [u ]_ s) /\
(Zodd [v3 ]_ s \/ Zodd [u3 ]_ s) /\
C5 u3 v3 s).
move=> s h.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [H11 [tuv1 [Hinvar1 [Hinvar2 [H12 [Hu3 Hv3]]]]]]]]]] H1].
rewrite /wp_assign /C2.
repeat Store_upd.
repeat (split; first by []).
split.
split; by [rewrite /= /ZIT.add -Hti; ring | ].
repeat (split; first by []).
split.
rewrite /= /hoare_m.eval_b /ZIT.geb /= in H1.
move/geZP : H1 => ?; lia.
split.
rewrite /uivi_bounds; by repeat Store_upd.
split.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
have u1_v1 : [u1 ]_ s <= [v1 ]_ s.
rewrite /= /hoare_m.eval_b /ZIT.geb /= in H1.
move/geZP : H1 => ?; lia.
move/geZP in H1.
split; last lia.
rewrite /= /ZIT.add.
rewrite /ti_bounds in Hinvar1.
lia.
rewrite /C5; by repeat Store_upd.
apply hoare_assign' => s h.
case=> [[Hu [Hv [Hg [u_g v_g]]]] [H5 [[Hti [Hui Hvi]] [H9 [H10 [uv1 [Hinvar1 [Hinvar2 [H11 [Hu3 Hv3]]]]]]]]]].
rewrite /wp_assign /C2 /C4 /C5 /CVectors.
repeat Store_upd.
repeat (split; first by []).
split; first by exists O; right; right; rewrite /= mulZ1.
repeat (split; first by []).
split.
rewrite -(Zgcd_for_euclid [u3]_s [v3]_s (-1)) mulN1Z addZNE.
rewrite H9 -u_g -v_g -2!(mulZC [g]_s) Zgcd_mult in H10; last lia.
apply eqZ_mul2l in H10 => //; lia.
split.
rewrite /uivi_bounds.
by repeat Store_upd.
rewrite /ti_bounds in Hinvar2 *.
repeat Store_upd.
split; first tauto.
split; last tauto.
rewrite /= /ZIT.sub.
rewrite /uivi_bounds in Hinvar1.
lia.
apply hoare_skip' => s h.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [H11 [tuv1 [Hinvar1 [Hinvar2 [H12 [Hu3 Hv3]]]]]]]]]] H1].
rewrite /wp_assign /C2.
repeat Store_upd.
repeat (split; first by []).
split.
exists O; right; right; by rewrite /= mulZ1.
repeat (split; first by []).
split.
rewrite -(Zgcd_for_euclid [u3]_s [v3]_s (-1)) mulN1Z addZNE.
rewrite H10 -v_g -u_g -2!(mulZC [g]_s) Zgcd_mult in H11; last lia.
apply eqZ_mul2l in H11 => //; lia.
split; first by [].
rewrite /= /hoare_m.eval_b /ZIT.geb /= in H1.
move/geZP in H1.
apply (proj1 Hinvar2); lia.
Qed.
Lemma triple_intermediate_invariant :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
{{ fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s) /\
[ var_e t3 \!= nat_e 0 ]b_ s}}
while.while (var_e t3 \% nat_e 2 \= nat_e 0) (BEGCD_TAOCP.halve u v t1 t2 t3);
BEGCD_TAOCP.reset u v u1 u2 u3 v1 v2 v3 t1 t2 t3;
BEGCD_TAOCP.subtract u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{ fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s }}.
Proof.
move=> Hset Hvu Hvv.
apply while.hoare_seq with (fun s h => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
Zodd [t3]_s).
exact: while_halve.
apply while.hoare_seq with (fun s _ => C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
(0 <= [t3]_s -> Z.gcd vu vv = [g ]_ s * Z.gcd [t3 ]_ s [v3 ]_ s /\ Zodd [u3]_s /\
[u3]_s = [t3]_s) /\
([t3]_s < 0 -> Z.gcd vu vv = [g ]_ s * Z.gcd [u3 ]_ s [t3 ]_ s /\ Zodd [v3]_s /\
[v3]_s = - [t3]_s) /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s /\
C5 u3 v3 s).
exact: reset_triple.
exact: subtract_triple.
Qed.
Lemma triple_intermediate_invariant_stren :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
while.entails hoare_m.store hoare_m.heap
(fun s _ =>
C2 vu vv u v g s /\
C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\
ti_init u v t1 t2 t3 s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s)
(fun s _ =>
C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s).
Proof.
move=> Hset Hvv Hvu.
rewrite /while.entails => s h.
case => [[Hu [Hv [Hg [u_g v_g]]]] [[Hgcd Hcond] [[Hu1 [Hu2 [Hu3 [Hv1 [Hv2 Hv3]]]]] [Ht [Hinvar1 Hinvar2]]]]].
rewrite /CVectors Hu1 Hu2 Hu3 Hv1 Hv2 Hv3.
repeat (split; first tauto).
case: (Zeven_odd_dec [u]_s) => u_parity.
- case: Ht => _.
move/(_ u_parity) => [Ht1 [Ht2 Ht3]].
rewrite /C2 /C4 /C5 Ht1 Ht2 Ht3 Hu3 Hv3 mulZ1 mulZ0 addZ0.
repeat (split; first by []).
split.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem /=.
case/orP => /eqP X.
+ left; exact: not_Zmod_2_Zodd.
+ right; exact: not_Zmod_2_Zodd.
split.
repeat (split; first by []).
ring.
split; last by [].
exists O; rewrite [_ ^^ _]/= !mulZ1; right; left.
split; first by reflexivity.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem.
case/orP => /eqP.
+ move/not_Zmod_2_Zodd; by move/Zodd_not_Zeven.
+ by move/not_Zmod_2_Zodd.
- case: Ht.
move/(_ u_parity) => [Ht1 [Ht2 Ht3]] _.
rewrite Ht1 Ht2 Ht3 /C4 /C5 Hu3 Hv3 mulZ1 mulZ0 add0Z mulZ0 addZ0.
repeat (split; first by []).
split.
move/negP : Hcond => /=.
rewrite negb_and /ZIT.eqb /ZIT.rem /=.
case/orP => /eqP X.
* left; exact: not_Zmod_2_Zodd.
* right; exact: not_Zmod_2_Zodd.
split.
split; first by ring.
split; by [| ring].
split; last by [].
exists O; rewrite [_ ^^ _]/= !mulZ1; tauto.
Qed.
Lemma triple_intermediate_invariant_weak :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
while.entails hoare_m.store hoare_m.heap
(fun s h => (C2 vu vv u v g s /\
(Zodd [u ]_ s \/ Zodd [v ]_ s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u ]_ s [v ]_ s = Z.gcd [u3 ]_ s [v3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s) /\
~~ [ var_e t3 \!= nat_e 0 ]b_ s)
(fun s _ =>
vu * [u1 ]_ s + vv * [u2 ]_ s = [g ]_ s * [u3 ]_ s /\
Z.gcd vu vv = [g ]_ s * [u3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\ ti_bounds u v t1 t2 t3 s).
Proof.
move=> Hset Hvv Hvu.
- rewrite /while.entails => s h.
case => [[[Hu [Hv [Hg [u_g v_g]]]] [H6 [[Hti [Hui Hvi]] [H10 [[Hu3 Hv3] [H12 [H14 [Hinvar1 Hinvar2]]]]]]]] H1].
split; first by rewrite -u_g -v_g -Hui; ring.
rewrite /hoare_m.eval_b /= /ZIT.eqb in H1.
move/negPn : H1 => /eqP H1.
case: H10 => k.
case => [H10|].
+ have abs : [v3 ]_ s = 0.
move: (expZ_gt0 k) => ?.
case: H10 => H10 H10'.
rewrite H1 mul0Z in H10; lia.
rewrite abs Zgcd_0 Z.abs_eq in H12; last lia.
rewrite -H12 -Zgcd_mult; last lia.
by rewrite mulZC u_g mulZC v_g.
+ case => H10.
* have abs : [u ]_ s = 0.
rewrite H1 mul0Z in H10; lia.
rewrite abs in Hu; by apply ltZZ in Hu.
* have abs : [u3 ]_ s = [v3 ]_ s.
rewrite H1 mul0Z in H10; lia.
rewrite -abs Zgcd_same in H12; last lia.
rewrite -H12 -u_g -v_g -Zgcd_mult; last lia.
by rewrite (mulZC [u ]_ s) (mulZC [v ]_ s).
Qed.
Lemma triple_intermediate :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
({{fun s _ => C2 vu vv u v g s /\ C3 vu vv u v g s /\
uivi_init u v u1 u2 u3 v1 v2 v3 s /\
ti_init u v t1 t2 t3 s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s }}
while.while (var_e t3 \!= nat_e 0)
(while.while (var_e t3 \% nat_e 2 \= nat_e 0) (BEGCD_TAOCP.halve u v t1 t2 t3);
BEGCD_TAOCP.reset u v u1 u2 u3 v1 v2 v3 t1 t2 t3;
BEGCD_TAOCP.subtract u v u1 u2 u3 v1 v2 v3 t1 t2 t3)
{{fun s _ =>
vu * [u1 ]_ s + vv * [u2 ]_ s = [g ]_ s * [u3 ]_ s /\
Z.gcd vu vv = [g ]_ s * [u3 ]_ s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s }})%seplog_hoare.
Proof.
move=> Hset Hvv Hvu.
apply hoare_prop_m.hoare_while_invariant with (fun s _ =>
C2 vu vv u v g s /\
(Zodd [u]_s \/ Zodd [v]_s) /\
CVectors u v u1 u2 u3 v1 v2 v3 t1 t2 t3 s /\
C4 u3 v3 t3 s /\
C5 u3 v3 s /\
Z.gcd [u]_s [v]_s = Z.gcd [u3]_s [v3]_s /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 s /\
ti_bounds u v t1 t2 t3 s).
exact: triple_intermediate_invariant_stren.
exact: triple_intermediate_invariant_weak.
exact: triple_intermediate_invariant.
Qed.
Lemma triple :
uniq(g, u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3) -> 0 < vu -> 0 < vv ->
({{ fun st _ => uv_init vu vv u v st }}
BEGCD_TAOCP.begcd g u v u1 u2 u3 v1 v2 v3 t1 t2 t3
{{ fun st _ =>
vu * [u1]_st + vv * [u2]_st = [g]_st * [u3]_st /\
Z.gcd vu vv = ([g]_st * [u3]_st) /\
uivi_bounds u v u1 v1 u2 v2 u3 v3 st /\
ti_bounds u v t1 t2 t3 st
}})%seplog_hoare.
Proof.
move=> Hset Hvu Hvv.
rewrite /BEGCD_TAOCP.begcd.
do 2 apply hoare_prop_m.hoare_seq_assoc'.
eapply while.hoare_seq.
apply hoare_prop_m.hoare_seq_assoc.
exact: triple_init.
exact: triple_intermediate.
Qed.
End begcd_taocp_cor.
End BEGCD_TAOCP_COR.
End EGCD.