Require Import Arith.
Require Import Omega.
Open Scope Z_scope.
Variables m n: Z.
Lemma l1: exists m0: Z, m = m0 * Z.gcd m n.
apply Z.gcd_divide_l.
Qed.
Lemma l2: exists n0: Z, n = n0 * Z.gcd m n.
apply Z.gcd_divide_r.
Qed.
Variables m0 n0: Z.
Hypothesis hyp1: (0 <> m)%Z.
Hypothesis hyp2: (0 <> n)%Z.
Hypothesis hyp3: m = m0 * Z.gcd m n.
Hypothesis hyp4: n = n0 * Z.gcd m n.
Hypothesis hyp5: Z.gcd m n + Z.lcm m n = m + n.
Hypothesis hyp6: (0 <= m)%Z.
Hypothesis hyp7: (0 <= n)%Z.
Hypothesis hyp8: Z.lcm m n = m0 * n0 * Z.gcd m n.
Theorem t1: Z.gcd m n + m0 * n0 * Z.gcd m n = m0 * Z.gcd m n + n0 * Z.gcd m n.
replace (m0 * Z.gcd m n) with m.
replace (n0 * Z.gcd m n) with n.
replace (m0 * n0 * Z.gcd m n) with (Z.lcm m n).
apply hyp5.
apply hyp8.
apply hyp4.
apply hyp3.
Qed.
Theorem t2: (1 + m0 * n0)%Z * Z.gcd m n = (m0 + n0)%Z * Z.gcd m n.
replace ((1 + m0 * n0) * Z.gcd m n) with (Z.gcd m n + m0 * n0 * Z.gcd m n).
replace ((m0 + n0) * Z.gcd m n) with (m0 * Z.gcd m n + n0 * Z.gcd m n).
apply t1.
symmetry.
apply Z.mul_add_distr_r.
symmetry.
replace (Z.gcd m n + m0 * n0 * Z.gcd m n) with (1 * Z.gcd m n + m0 * n0 * Z.gcd m n).
apply Z.mul_add_distr_r.
omega.
Qed.
Theorem t3: (0 <= Z.gcd m n)%Z.
apply Z.gcd_nonneg.
Qed.
Theorem t4: (0 <> Z.gcd m n)%Z.
apply not_eq_sym.
rewrite Z.gcd_eq_0.
red.
intros.
destruct H as (H1, H2).
apply hyp1.
symmetry.
auto.
Qed.
Theorem t5: 1 + m0 * n0 = m0 + n0.
assert ((1 + m0 * n0)%Z * Z.gcd m n = (m0 + n0)%Z * Z.gcd m n).
apply t2.
assert (Z.gcd m n <> 0%Z).
apply not_eq_sym.
apply t4.
rewrite <- Z.mul_cancel_r.
eapply H.
apply H0.
Qed.
Theorem t6: m0 * (n0 - 1%Z) = n0 - 1%Z.
assert (1 + m0 * n0 = m0 + n0).
apply t5.
replace (m0 * (n0 - 1)) with (m0 * n0 - m0).
omega.
symmetry.
rewrite Z.mul_sub_distr_l.
replace (m0 * 1) with m0.
auto.
symmetry.
apply Z.mul_1_r.
Qed.
Theorem t7: n0 * (m0 - 1%Z) = m0 - 1%Z.
assert (1 + m0 * n0 = m0 + n0).
apply t5.
replace (n0 * (m0 - 1)) with (n0 * m0 - n0 * 1).
apply Zeq_plus_swap.
rewrite Z.sub_opp_r.
replace (n0 * 1) with n0.
replace (m0 - 1 + n0) with (m0 + n0 - 1).
apply Zplus_minus_eq.
symmetry.
replace (n0 * m0) with (m0 * n0).
apply H.
apply Z.mul_comm.
omega.
symmetry.
apply Z.mul_1_r.
symmetry.
apply Zmult_minus_distr_l.
Qed.
Theorem t8: n0 <> 1 -> m0 = 1.
intros.
assert (m0 * (n0 - 1%Z) = n0 - 1%Z).
apply t6.
assert (n0 - 1 <> 0).
omega.
assert (m0 * (n0 - 1) = 1 * (n0 - 1)).
omega.
apply Z.mul_cancel_r in H2.
apply H2.
apply H1.
Qed.
Theorem t9: m0 <> 1 -> n0 = 1.
intros.
assert (n0 * (m0 - 1%Z) = m0 - 1%Z).
apply t7.
assert (m0 - 1 <> 0).
omega.
assert (n0 * (m0 - 1) = 1 * (m0 - 1)).
omega.
apply Z.mul_cancel_r in H2.
apply H2.
apply H1.
Qed.
Theorem t10: m0 = 1 \/ n0 = 1.
assert (n0 <> 1 -> m0 = 1).
apply t8.
omega.
Qed.
Theorem t11: m = Z.gcd m n \/ n = Z.gcd m n.
assert (m0 = 1 \/ n0 = 1).
apply t10.
assert (m = m0 * Z.gcd m n).
apply hyp3.
assert (n = n0 * Z.gcd m n).
apply hyp4.
case H.
intro.
left.
replace (Z.gcd m n) with (1 * Z.gcd m n).
replace 1 with m0.
apply H0.
apply Z.mul_1_l.
intro.
right.
replace (Z.gcd m n) with (1 * Z.gcd m n).
replace 1 with n0.
apply H1.
apply Z.mul_1_l.
Qed.
Theorem t12: (m | n)%Z \/ (n | m)%Z.
assert (m = Z.gcd m n \/ n = Z.gcd m n).
apply t11.
assert (0 <= m%Z).
apply hyp6.
assert (0 <= n%Z).
apply hyp7.
case H.
intro.
left.
apply Z.divide_gcd_iff.
apply H0.
symmetry.
apply H2.
intro.
right.
apply Z.divide_gcd_iff.
apply H1.
symmetry.
replace (Z.gcd n m) with (Z.gcd m n).
apply H2.
apply Z.gcd_comm.
Qed.