(* Addition on Z, (Z, +) is a group *)

(*Recursive Definition addZ : Z -> Z -> Z := 
       OZ        y => y
|   (pos O)      y => (succZ y)
|   (pos (S n1)) y => (succZ (addZ (pos n1) y))
|   (neg O)      y => (predZ y)
|   (neg (S n1)) y => (predZ (addZ (neg n1) y)).*)


(* this definition introduces unnecessary names *)


Fixpoint addpos (x2 : Z) (n : nat) {struct n} : Z :=
  match n with
  | O => succZ x2
  | S n0 => succZ (addpos x2 n0)
  end.Fixpoint addneg (x2 : Z) (n : nat) {struct n} : Z :=
  match n with
  | O => predZ x2
  | S n0 => predZ (addneg x2 n0)
  end.Definition addZ (x1 x2 : Z) :=
  match x1 with
  | OZ => x2
  | pos n => addpos x2 n
  | neg n => addneg x2 n
  end.

(* Specifications: *)
Lemma addZ_eq1 : forall y : Z, addZ OZ y = y.
Lemma addZ_eq2 : forall y : Z, addZ (pos 0) y = succZ y.
Lemma addZ_eq3 : forall (n1 : nat) (y : Z), addZ (pos (S n1)) y = succZ (addZ (pos n1) y).
Lemma addZ_eq4 : forall y : Z, addZ (neg 0) y = predZ y.
Lemma addZ_eq5 : forall (n1 : nat) (y : Z), addZ (neg (S n1)) y = predZ (addZ (neg n1) y).
Lemma succ_addZ_l : forall x y : Z, addZ (succZ x) y = succZ (addZ x y).
Lemma pred_addZ_l : forall x y : Z, addZ (predZ x) y = predZ (addZ x y).
Lemma tech_add_pos_succZ : forall (x : nat) (y : Z), addZ (pos (S x)) y = succZ (addZ (pos x) y).
Lemma tech_add_neg_predZ : forall (x : nat) (y : Z), addZ (neg (S x)) y = predZ (addZ (neg x) y).
Lemma succ_addZ_r : forall x y : Z, addZ x (succZ y) = succZ (addZ x y).
Lemma pred_addZ_r : forall x y : Z, addZ x (predZ y) = predZ (addZ x y).
Lemma add_OZ : forall x : Z, addZ x OZ = x.
Lemma add_IZ_succZ : forall x : Z, addZ x IZ = succZ x.
Lemma add_mIZ_predZ : forall x : Z, addZ x (neg 0) = predZ x.
Theorem addZ_commutativity : commutativity Z addZ.
Lemma tech_add_pos_neg_posZ : forall n1 n2 : nat, n2 < n1 -> addZ (pos n1) (neg n2) = pos (n1 - S n2).
Theorem addZ_associativity : associativity Z addZ.