Inductive Rat :=
    RatIntro : nat -> posnat -> Rat.Inductive Rat :=
    RatIntro : nat -> posnat -> Rat.Definition ratCD(r1 r2 : Rat) : (nat * nat * posnat) :=
  match (r1, r2) with
    | (RatIntro n1 d1, RatIntro n2 d2) =>
      ((n1 * d2), (n2 * d1), (posnatMult d1 d2))
  end.Definition ratMult(r1 r2 : Rat) : Rat :=
  match (r1, r2) with
    | (RatIntro n1 d1, RatIntro n2 d2) =>
      RatIntro (n1 * n2) (posnatMult d1 d2)
  end.Definition rat1 := (RatIntro 1 (pos 1)).Definition rat0 := (RatIntro 0 (pos 1)).Definition ratAdd(r1 r2 : Rat) : Rat :=
  match ratCD r1 r2 with
    | (n1, n2, d) => 
      RatIntro (n1 + n2) d
  end.Definition ratSubtract(r1 r2: Rat) : Rat :=
  match ratCD r1 r2 with
    | (n1, n2, d) =>
      RatIntro (n1 - n2) d
  end.Definition beqRat(r1 r2 : Rat) :=
  match (ratCD r1 r2) with
    | (n1, n2, _) => 
      if (eq_nat_dec n1 n2) then true else false
  end.Definition bleRat(r1 r2 : Rat) :=
  match (ratCD r1 r2) with
    | (n1, n2, _) => 
      if (le_gt_dec n1 n2) then true else false
  end.Definition eqRat(r1 r2 : Rat) :=
  beqRat r1 r2 = true.Definition leRat(r1 r2 : Rat) := 
  bleRat r1 r2 = true.Definition maxRat(r1 r2 : Rat) :=
  if (bleRat r1 r2) then r2 else r1.Definition minRat(r1 r2 : Rat) :=
  if (bleRat r1 r2) then r1 else r2.Definition ratDistance(r1 r2 : Rat) :=
  ratSubtract (maxRat r1 r2) (minRat r1 r2).Ltac rattac_one := 
  match goal with 
    (* rules that solve goals *)
    | [|- posnatMult ?x1 ?x2 = posnatMult ?x2 ?x1] => apply posnatMult_comm
    | [|- posnatToNat (posnatMult ?x1 ?x2) = posnatToNat (posnatMult ?x2 ?x1)] => rewrite posnatMult_comm; trivial
    | [|- ?x1 * ?x2 = ?x2 * ?x1 ] => apply mult_comm
    | [|- (mult (?x1 + ?x2) _)  = (mult (?x2 + ?x1) _ )] => f_equal
    | [|- ?x1 * ?x2 * _ = ?x2 * ?x1 * _ ] => f_equal
    | [ |- posnatToNat ?p > 0 ] => destruct p; unfold posnatToNat; omega
      (* inversion on hypotheses *)
    | [H1 : ?n * ?x = ?n0 * ?x1, H2: ?n1 * ?x1 = ?n * ?x0 |- ?n1 * ?x = ?n0 * ?x0 ] => eapply (@mult_same_l x1)(* ;
      [idtac | rewrite mult_assoc ;
        rewrite (mult_comm x1 n1);
          rewrite H2;
            rewrite <- mult_assoc ;
              rewrite (mult_comm x x0) ;
                repeat rewrite mult_assoc;
                  f_equal] *) 
    | [H : ?x = ?n * (posnatToNat ?p) |- ?x = (posnatToNat ?p) * ?n ] => rewrite H
    | [H : RatIntro _ _ = RatIntro _ _ |- _ ] => inversion H; clear H; subst
    | [H : (eqRat _ _) |- _ ] => unfold eqRat, beqRat in H
    | [H : (leRat _ _) |- _ ] => unfold leRat, bleRat in H
    | [H : ?r = RatIntro _ _ |- context[match ?r with | RatIntro _ _ => _ end] ] => rewrite r
    
    | [|- context[match ?r with | RatIntro _ _ => _ end] ] => case_eq r; intuition
    | [H : (_ , _) = (_ , _) |- _ ] => inversion H; clear H; subst
    | [|- (_, _) = (_, _) ] => f_equal
    | [H: context[ratCD _ _] |- _ ] => unfold ratCD in *
    | [H : context[match rat0 with | RatIntro _ _ => _ end ] |- _ ] => unfold rat0 in H
    | [H1 : context[match ?r with | RatIntro _ _ => _ end], H2 : ?r = RatIntro _ _ |- _ ] => rewrite H2 in H1
    | [H : context[match ?r with | RatIntro _ _ => _ end ] |- _ ] => case_eq r; intuition
    | [|- context[let (_, _) := ?x in _] ] => case_eq x; intuition
    | [H : context[ratAdd _ _] |- _ ] => unfold ratAdd in H    
    | [H : context[ratMult _ _] |- _ ] => unfold ratMult in H   
    | [H: context [eq_nat_dec ?x ?y] |- _] => destruct (eq_nat_dec x y)
    | [H: context [le_gt_dec ?x ?y] |- _] => destruct (le_gt_dec x y)
    | [|- (if (eq_nat_dec ?x ?y) then true else false) = true ] => assert (x = y); destruct (eq_nat_dec x y); trivial
     | [|- (if (le_gt_dec ?x ?y) then true else false) = true ] => assert (x <= y); [idtac | destruct (le_gt_dec x y); trivial]
    | [|- context[posnatMult _ _ ] ] => unfold posnatMult
    | [|- (eqRat _ _) ] => unfold eqRat, beqRat
    | [|- (leRat _ _) ] => unfold leRat, bleRat
    | [|- (posnatEq _ _ ) ] => econstructor
    | [|- context[(posnatToNat _)] ] => unfold posnatToNat in *
    | [H : context[let (_, _) := ?p in _] |- _] => destruct p
    end.Ltac rattac :=
  intuition; unfold ratCD in *; 
    repeat (rattac_one; subst); repeat rewrite mult_1_r; repeat rewrite plus_0_r; trivial; try congruence; try omega.

(* Specifications: *)
Lemma ratCD_comm : forall r1 r2 n1 n2 d n1' n2' d', ratCD r1 r2 = (n1, n2, d) -> ratCD r2 r1 = (n1', n2', d') -> n1 = n2' /\ n1' = n2 /\ (posnatEq d d').