(* This program is free software; you can redistribute it and/or      *)
(* modify it under the terms of the GNU Lesser General Public License *)
(* as published by the Free Software Foundation; either version 2.1   *)
(* of the License, or (at your option) any later version.             *)
(*                                                                    *)
(* This program is distributed in the hope that it will be useful,    *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of     *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *)
(* GNU General Public License for more details.                       *)
(*                                                                    *)
(* You should have received a copy of the GNU Lesser General Public   *)
(* License along with this program; if not, write to the Free         *)
(* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *)
(* 02110-1301 USA                                                     *)
Open Scope Z_scope.
(** * Euclid gcd algorithm *)
(** This was previously part of Coq standard library (in Znumtheory). But the new binary algorithm used there is much faster and also easier to prove correct (for the variant that is executable in coq). *)
(** In this first variant, we use an explicit measure in [nat], and we prove later that using [2(d+1)] is enough, where [d] is the number of binary digits of the first argument. *)
Fixpoint Zgcdn (n:nat) : Z -> Z -> Z := fun a b =>
match n with
| O => 1 (* arbitrary, since n should be big enough *)
| S n => match a with
| Z0 => Zabs b
| Zpos _ => Zgcdn n (Zmod b a) a
| Zneg a => Zgcdn n (Zmod b (Zpos a)) (Zpos a)
end
end.
(* For technical reason, we don't use [Ndigit.Psize] but this ad-hoc version: [Psize p = S (Psiz p)]. *)
Fixpoint Psiz (p:positive) : nat :=
match p with
| xH => O
| xI p => S (Psiz p)
| xO p => S (Psiz p)
end.
Definition Zgcd_bound (a:Z) := match a with
| Z0 => S O
| Zpos p => let n := Psiz p in S (S (n+n))
| Zneg p => let n := Psiz p in S (S (n+n))
end.
Definition Zgcd a b := Zgcdn (Zgcd_bound a) a b.
(** A first obvious fact : [Zgcd a b] is positive. *)

(* Specifications: *)
Lemma Zgcdn_is_pos : forall n a b,
0 <= Zgcdn n a b.
Lemma Zgcd_is_pos : forall a b, 0 <= Zgcd a b.
(** We now prove that Zgcd is indeed a gcd. *)
Lemma Zis_gcd_0_abs : forall b,
Zis_gcd 0 b (Zabs b) /\ Zabs b >= 0 /\ 0 = Zabs b * 0 /\ b = Zabs b * Zsgn b.