(* Use of this source code is governed by the license described	* * in the LICENSE file at the root of the source tree.		*)
(* A theory of constructed rational numbers *)
Set Implicit Arguments.
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').