Ltac refl :=
  abstract (intros ; match goal with
                     | |- context[@inj _ _ ?X] => unfold X, inj
                     end ; reflexivity).#[global]
Instance Inj_Z_Z : InjTyp Z Z :=
  mkinj _ _ (fun x => x) (fun x =>  True ) (fun _ => I).(** Support for nat *)

#[global]
Instance Inj_nat_Z : InjTyp nat Z :=
  mkinj _ _ Z.of_nat (fun x =>  0 <= x ) Nat2Z.is_nonneg.(* zify_nat_rel *)
#[global]
Instance Op_ge : BinRel ge :=
  { TR := Z.ge; TRInj := Nat2Z.inj_ge }.#[global]
Instance Op_lt : BinRel lt :=
  { TR := Z.lt; TRInj := Nat2Z.inj_lt }.#[global]
Instance Op_Nat_lt : BinRel Nat.lt := Op_lt.#[global]
Instance Op_gt : BinRel gt :=
  { TR := Z.gt; TRInj := Nat2Z.inj_gt }.#[global]
Instance Op_le : BinRel le :=
  { TR := Z.le; TRInj := Nat2Z.inj_le }.#[global]
Instance Op_Nat_le : BinRel Nat.le := Op_le.#[global]
Instance Op_eq_nat : BinRel (@eq nat) :=
  { TR := @eq Z ; TRInj x y := iff_sym (Nat2Z.inj_iff x y) }.#[global]
Instance Op_Nat_eq : BinRel (Nat.eq) := Op_eq_nat.(* zify_nat_op *)
#[global]
Instance Op_plus : BinOp Nat.add :=
  { TBOp := Z.add; TBOpInj := Nat2Z.inj_add }.#[global]
Instance Op_sub : BinOp Nat.sub :=
  { TBOp n m := Z.max 0 (n - m) ; TBOpInj := Nat2Z.inj_sub_max }.#[global]
Instance Op_mul : BinOp Nat.mul :=
  { TBOp := Z.mul ; TBOpInj := Nat2Z.inj_mul }.#[global]
Instance Op_min : BinOp Nat.min :=
  { TBOp := Z.min ; TBOpInj := Nat2Z.inj_min }.#[global]
Instance Op_max : BinOp Nat.max :=
  { TBOp := Z.max ; TBOpInj := Nat2Z.inj_max }.#[global]
Instance Op_pred : UnOp Nat.pred :=
  { TUOp n := Z.max 0 (n - 1) ; TUOpInj := Nat2Z.inj_pred_max }.#[global]
Instance Op_S : UnOp S :=
  { TUOp x := Z.add x 1 ; TUOpInj := Nat2Z.inj_succ }.#[global]
Instance Op_O : CstOp O :=
  { TCst := Z0 ; TCstInj := eq_refl (Z.of_nat 0) }.#[global]
Instance Op_Z_abs_nat : UnOp  Z.abs_nat :=
  { TUOp := Z.abs ; TUOpInj := Zabs2Nat.id_abs }.#[global]
Instance Op_nat_div2 : UnOp Nat.div2 :=
  { TUOp x := x / 2 ;
    TUOpInj x := ltac:(now rewrite Nat2Z.inj_div2, Z.div2_div) }.#[global]
Instance Op_nat_double : UnOp Nat.double :=
  {| TUOp := Z.mul 2 ; TUOpInj := Nat2Z.inj_double |}.(** Support for positive *)

#[global]
Instance Inj_pos_Z : InjTyp positive Z :=
  { inj := Zpos ; pred x := 0 < x ; cstr := Pos2Z.pos_is_pos }.#[global]
Instance Op_pos_to_nat : UnOp  Pos.to_nat :=
  {TUOp x := x ; TUOpInj := positive_nat_Z}.#[global]
Instance Inj_N_Z : InjTyp N Z :=
  mkinj _ _ Z.of_N (fun x =>  0 <= x ) N2Z.is_nonneg.#[global]
Instance Op_N_to_nat : UnOp  N.to_nat :=
  { TUOp x := x ; TUOpInj := N_nat_Z }.(* zify_positive_rel *)

#[global]
Instance Op_pos_ge : BinRel Pos.ge :=
  { TR := Z.ge; TRInj x y := iff_refl (Z.pos x >= Z.pos y) }.#[global]
Instance Op_pos_lt : BinRel Pos.lt :=
  { TR := Z.lt; TRInj x y := iff_refl (Z.pos x < Z.pos y) }.#[global]
Instance Op_pos_gt : BinRel Pos.gt :=
  { TR := Z.gt; TRInj x y := iff_refl (Z.pos x > Z.pos y) }.#[global]
Instance Op_pos_le : BinRel Pos.le :=
  { TR := Z.le; TRInj x y := iff_refl (Z.pos x <= Z.pos y) }.

(* Specifications: *)
Lemma eq_pos_inj x y : x = y <-> Z.pos x = Z.pos y.