(* Sqrt *)

 (* Direct transcription of an old proof
     of a fortran program in boyer-moore *)

Ltac elim_div :=
  unfold Z.div, Z.modulo;
  match goal with
  |  H : context[ Z.div_eucl ?X ?Y ] |-  _ =>
     generalize dependent H; generalize (Z_div_mod_full X Y) ; case (Z.div_eucl X Y)
  |  |-  context[ Z.div_eucl ?X ?Y ] =>
     generalize (Z_div_mod_full X Y) ; case (Z.div_eucl X Y)
  end; unfold Remainder.

(* Specifications: *)
Lemma quotient_by_2 a: a - 1 <= (a/2) + (a/2).
Lemma sqrt_main_trick j k: 0 <= j -> 0 <= k -> (j * k) + j <= ((j + k)/2 + 1) ^ 2.
Lemma sqrt_main i j: 0 <= i -> 0 < j -> i < ((j + (i/j))/2 + 1) ^ 2.
Lemma sqrt_test_false i j: 0 <= i -> 0 < j -> i/j < j -> (j + (i/j))/2 < j.
Lemma sqrt_test_true i j: 0 <= i -> 0 < j -> i/j >= j -> j ^ 2 <= i.
Lemma sqrt_step_correct rec i j: 0 < φ i -> 0 < φ j -> φ i < (φ j + 1) ^ 2 -> 2 * φ j < wB -> (forall j1 : int, 0 < φ j1 < φ j -> φ i < (φ j1 + 1) ^ 2 -> φ (rec i j1) ^ 2 <= φ i < (φ (rec i j1) + 1) ^ 2) -> φ (sqrt_step rec i j) ^ 2 <= φ i < (φ (sqrt_step rec i j) + 1) ^ 2.
Lemma iter_sqrt_correct n rec i j: 0 < φ i -> 0 < φ j -> φ i < (φ j + 1) ^ 2 -> 2 * φ j < wB -> (forall j1, 0 < φ j1 -> 2^(Z_of_nat n) + φ j1 <= φ j -> φ i < (φ j1 + 1) ^ 2 -> 2 * φ j1 < wB -> φ (rec i j1) ^ 2 <= φ i < (φ (rec i j1) + 1) ^ 2) -> φ (iter_sqrt n rec i j) ^ 2 <= φ i < (φ (iter_sqrt n rec i j) + 1) ^ 2.
Lemma sqrt_init i: 1 < i -> i < (i/2 + 1) ^ 2.
Lemma sqrt_spec : forall x, φ (sqrt x) ^ 2 <= φ x < (φ (sqrt x) + 1) ^ 2.
Lemma sqrt2_lower_bound ih il j: Φ (WW ih il) < (φ j + 1) ^ 2 -> φ ih <= φ j.
Lemma diveucl_21_spec_aux : forall a1 a2 b, wB/2 <= φ b -> φ a1 < φ b -> let (q,r) := diveucl_21 a1 a2 b in φ a1 *wB+ φ a2 = φ q * φ b + φ r /\ 0 <= φ r < φ b.
Lemma div2_phi ih il j: (2^62 <= φ j -> φ ih < φ j -> φ (fst (diveucl_21 ih il j)) = Φ (WW ih il) / φ j)%Z.
Lemma sqrt2_step_correct rec ih il j: 2 ^ (Z_of_nat (size - 2)) <= φ ih -> 0 < φ j -> Φ (WW ih il) < (φ j + 1) ^ 2 -> (forall j1, 0 < φ j1 < φ j -> Φ (WW ih il) < (φ j1 + 1) ^ 2 -> φ (rec ih il j1) ^ 2 <= Φ (WW ih il) < (φ (rec ih il j1) + 1) ^ 2) -> φ (sqrt2_step rec ih il j) ^ 2 <= Φ (WW ih il) < (φ (sqrt2_step rec ih il j) + 1) ^ 2.
Lemma iter2_sqrt_correct n rec ih il j: 2^(Z_of_nat (size - 2)) <= φ ih -> 0 < φ j -> Φ (WW ih il) < (φ j + 1) ^ 2 -> (forall j1, 0 < φ j1 -> 2^(Z_of_nat n) + φ j1 <= φ j -> Φ (WW ih il) < (φ j1 + 1) ^ 2 -> φ (rec ih il j1) ^ 2 <= Φ (WW ih il) < (φ (rec ih il j1) + 1) ^ 2) -> φ (iter2_sqrt n rec ih il j) ^ 2 <= Φ (WW ih il) < (φ (iter2_sqrt n rec ih il j) + 1) ^ 2.
Lemma of_pos_rec_spec (k: nat) : (k <= size)%nat → ∀ p, φ(of_pos_rec k p) = Zpos p mod 2 ^ Z.of_nat k.
Lemma is_int n : 0 <= n < 2 ^ φ digits → n = φ (of_Z n).
Lemma of_Z_spec n : φ (of_Z n) = n mod wB.
Lemma Z_oddE a : Z.odd a = (a mod 2 =? 1)%Z.
Lemma Z_evenE a : Z.even a = (a mod 2 =? 0)%Z.
Lemma is_zeroE n : is_zero n = Z.eqb (φ n) 0.
Lemma bitE i j : bit i j = Z.testbit φ(i) φ(j).
Lemma lt_pow_lt_log d k n : 0 < d <= n → 0 <= k < 2 ^ d → Z.log2 k < n.
Lemma land_spec' x y : φ (x land y) = Z.land φ(x) φ(y).
Lemma lor_spec' x y : φ (x lor y) = Z.lor φ(x) φ(y).
Lemma lxor_spec' x y : φ (x lxor y) = Z.lxor φ(x) φ(y).
Lemma landC i j : i land j = j land i.
Lemma landA i j k : i land (j land k) = i land j land k.
Lemma land0 i : 0 land i = 0%uint63.
Lemma land0_r i : i land 0 = 0%uint63.
Lemma lorC i j : i lor j = j lor i.
Lemma lorA i j k : i lor (j lor k) = i lor j lor k.
Lemma lor0 i : 0 lor i = i.
Lemma lor0_r i : i lor 0 = i.
Lemma lxorC i j : i lxor j = j lxor i.
Lemma lxorA i j k : i lxor (j lxor k) = i lxor j lxor k.
Lemma lxor0 i : 0 lxor i = i.
Lemma lxor0_r i : i lxor 0 = i.
Lemma opp_to_Z_opp (x : int) : φ x mod wB <> 0 -> (- φ (- x)) mod wB = (φ x) mod wB.