Module Type Int.
Parameter t : Set.
Bind Scope Int_scope with t.
Parameter i2z : t -> Z.
Parameter _0 : t.
Parameter _1 : t.
Parameter _2 : t.
Parameter _3 : t.
Parameter add : t -> t -> t.
Parameter opp : t -> t.
Parameter sub : t -> t -> t.
Parameter mul : t -> t -> t.
Parameter max : t -> t -> t.
Notation "0" := _0 : Int_scope.
Notation "1" := _1 : Int_scope.
Notation "2" := _2 : Int_scope.
Notation "3" := _3 : Int_scope.
Infix "+" := add : Int_scope.
Infix "-" := sub : Int_scope.
Infix "*" := mul : Int_scope.
Notation "- x" := (opp x) : Int_scope.
(** For logical relations, we can rely on their counterparts in Z, since they don't appear after extraction. Moreover, using tactics like omega is easier this way. *)
Notation "x == y" := (i2z x = i2z y)
(at level 70, y at next level, no associativity) : Int_scope.
Notation "x <= y" := (i2z x <= i2z y)%Z : Int_scope.
Notation "x < y" := (i2z x < i2z y)%Z : Int_scope.
Notation "x >= y" := (i2z x >= i2z y)%Z : Int_scope.
Notation "x > y" := (i2z x > i2z y)%Z : Int_scope.
Notation "x <= y <= z" := (x <= y /\ y <= z) : Int_scope.
Notation "x <= y < z" := (x <= y /\ y < z) : Int_scope.
Notation "x < y < z" := (x < y /\ y < z) : Int_scope.
Notation "x < y <= z" := (x < y /\ y <= z) : Int_scope.
(** Informative comparisons. *)
Infix "=?" := eqb.
Infix "<?" := ltb.
Infix "<=?" := leb.
(** For compatibility, some decidability fonctions (informative). *)
(** Specifications *)
(** First, we ask [i2z] to be injective. Said otherwise, our ad-hoc equality [==] and the generic [=] are in fact equivalent. We define [==] nonetheless since the translation to [Z] for using automatic tactic is easier. *)
(** Then, we express the specifications of the above parameters using their Z counterparts. *)

Axiom i2z_0 : i2z _0 = 0%Z.
Axiom i2z_1 : i2z _1 = 1%Z.
Axiom i2z_2 : i2z _2 = 2%Z.
Axiom i2z_3 : i2z _3 = 3%Z.
Axiom i2z_add : forall n p, i2z (n + p) = (i2z n + i2z p)%Z.
Axiom i2z_opp : forall n, i2z (-n) = (-i2z n)%Z.
Axiom i2z_sub : forall n p, i2z (n - p) = (i2z n - i2z p)%Z.
Axiom i2z_mul : forall n p, i2z (n * p) = (i2z n * i2z p)%Z.
Axiom i2z_max : forall n p, i2z (max n p) = Z.max (i2z n) (i2z p).
Axiom i2z_eqb : forall n p, eqb n p = Z.eqb (i2z n) (i2z p).
Axiom i2z_ltb : forall n p, ltb n p = Z.ltb (i2z n) (i2z p).
Axiom i2z_leb : forall n p, leb n p = Z.leb (i2z n) (i2z p).