Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
Local Set Universe Minimization ToSet.LocalOpen Scope nat_scope.(** * Division of natural numbers *)(** ** Divisibility *)(** We define divisibility as a relation between natural numbers. *)ClassNatDivides (nm : nat) : Type0 := nat_divides : {k : nat & k * n = m}.Notation"( n | m )" := (NatDivides n m) : nat_scope.(** Any number divides [0]. *)Instancenat_divides_zero_rn : (n | 0)
:= (0; idpath).(** [1] divides any number. *)Instancenat_divides_one_ln : (1 | n)
:= (n; nat_mul_one_r _).(** Any number divides itself. Divisibility is a reflexive relation. *)Instancenat_divides_refln : (n | n)
:= (1; nat_mul_one_l _).Instancereflexive_nat_divides : Reflexive NatDivides := nat_divides_refl.(** Divisibility is transitive. *)
n, m, l: nat
(n | m) -> (m | l) -> (n | l)
n, m, l: nat
(n | m) -> (m | l) -> (n | l)
n, m, l, x: nat p: x * n = m y: nat q: y * m = l
(n | l)
n, m, l, x: nat p: x * n = m y: nat q: y * m = l
y * x * n = l
n, m, l, x: nat p: x * n = m y: nat q: y * m = l
y * (x * n) = l
n, m, l, x: nat p: x * n = m y: nat q: y * m = l
y * m = l
exact q.Defined.Hint Immediate nat_divides_trans : typeclass_instances.Instancetransitive_nat_divides : Transitive NatDivides := @nat_divides_trans.(** A left factor divides a product. *)Instancenat_divides_mul_l'nm : (n | n * m)
:= (m; nat_mul_comm _ _).(** A right factor divides a product. *)Instancenat_divides_mul_r'nm : (m | n * m)
:= (n; idpath).(** Divisibility of the product is implied by divisibility of the left factor. *)Instancenat_divides_mul_l {nm} l : (n | m) -> (n | m * l)
:= funH => nat_divides_trans _ _.(** Divisibility of the product is implied by divisibility of the right factor. *)Instancenat_divides_mul_r {nm} l : (n | m) -> (n | l * m)
:= funH => nat_divides_trans _ _.(** Multiplication is monotone with respect to divisibility. *)
n, m, l, p: nat
(n | m) -> (l | p) -> (n * l | m * p)
n, m, l, p: nat
(n | m) -> (l | p) -> (n * l | m * p)
n, m, l, p, x: nat r: x * n = m y: nat q: y * l = p
(n * l | m * p)
n, m, l, p, x: nat r: x * n = m y: nat q: y * l = p
x * y * (n * l) = m * p
n, l, x, y: nat
x * y * (n * l) = x * n * (y * l)
n, l, x, y: nat
x * y * n * l = x * n * (y * l)
n, l, x, y: nat
x * y * n * l = x * n * y * l
n, l, x, y: nat
x * y * n = x * n * y
n, l, x, y: nat
x * (y * n) = x * n * y
n, l, x, y: nat
x * (y * n) = x * (n * y)
n, l, x, y: nat
y * n = n * y
apply nat_mul_comm.Defined.(** Divisibility of the sum is implied by divisibility of the summands. *)
n, m, l: nat
(n | m) -> (n | l) -> (n | m + l)
n, m, l: nat
(n | m) -> (n | l) -> (n | m + l)
n, m, l, x: nat p: x * n = m y: nat q: y * n = l
(n | m + l)
n, m, l, x: nat p: x * n = m y: nat q: y * n = l
(x + y) * n = m + l
n, x, y: nat
(x + y) * n = x * n + y * n
napply nat_dist_r.Defined.(** If [n] divides a sum and the left summand, then [n] divides the right summand. *)
n, m, l: nat
(n | m) -> (n | m + l) -> (n | l)
n, m, l: nat
(n | m) -> (n | m + l) -> (n | l)
n, m, l, x: nat p: x * n = m y: nat q: y * n = m + l
(n | l)
n, m, l, x: nat p: x * n = m y: nat q: y * n = m + l
(y - x) * n = l
n, m, l, x: nat p: x * n = m y: nat q: y * n = m + l
y * n - x * n = l
n, m, l, x: nat p: x * n = m y: nat q: y * n = m + l
y * n = l + x * n
n, m, l, x: nat p: x * n = m y: nat q: y * n = m + l
m + l = l + x * n
n, m, l, x: nat p: x * n = m y: nat q: y * n = m + l
l + m = l + x * n
exact (ap _ p^).Defined.(** If [n] divides a sum and the right summand, then [n] divides the left summand. *)
n, m, l: nat
(n | l) -> (n | m + l) -> (n | m)
n, m, l: nat
(n | l) -> (n | m + l) -> (n | m)
rewrite nat_add_comm; apply nat_divides_add_r.Defined.(** Divisibility of the difference is implied by divisibility of the minuend and subtrahend. *)
n, m, l: nat
(n | m) -> (n | l) -> (n | m - l)
n, m, l: nat
(n | m) -> (n | l) -> (n | m - l)
n, m, l, x: nat p: x * n = m y: nat q: y * n = l
(n | m - l)
n, m, l, x: nat p: x * n = m y: nat q: y * n = l
(x - y) * n = m - l
n, x, y: nat
(x - y) * n = x * n - y * n
napply nat_dist_sub_r.Defined.(** The divisor is greater than zero when the number being divided is greater than zero. *)
n, m: nat d: (n | m) gt0: 0 < m
0 < n
n, m: nat d: (n | m) gt0: 0 < m
0 < n
n, m, d: nat H: d * n = m gt0: 0 < m
0 < n
n, d: nat gt0: 0 < d * n
0 < n
n, d: nat gt0: 0 < d * n z: 0 = n
0 < n
n, d: nat gt0: 0 < d * n s: 0 < n
0 < n
n, d: nat gt0: 0 < d * n z: 0 = n
0 < n
(* The remaining case is impossible. *)
d: nat gt0: 0 < d * 0
0 < 0
d: nat gt0: 0 < 0
0 < 0
exact gt0.Defined.(** Divisibility implies that the divisor is less than or equal to the dividend. *)
n, m: nat
0 < m -> (n | m) -> n <= m
n, m: nat
0 < m -> (n | m) -> n <= m
n, m: nat H1: 0 < m x: nat p: x * n = m
n <= m
n: nat H1: 0 < 0 * n
n <= 0 * n
n, x: nat H1: 0 < x.+1 * n
n <= x.+1 * n
n, x: nat H1: 0 < x.+1 * n
n <= x.+1 * n
rapply (leq_mul_l _ _ 0).Defined.(** The divisor is strictly less than the dividend when the other factor is greater than one. *)
n, m: nat d: (n | m) gt0: 0 < m gt1: 1 < d.1
n < m
n, m: nat d: (n | m) gt0: 0 < m gt1: 1 < d.1
n < m
n, m: nat d: (n | m) gt0: 0 < m gt1: 1 < d.1
n < d.1 * n
n, m: nat d: (n | m) gt0: 0 < m gt1: 1 < d.1
n <= 1 * n
n, m: nat d: (n | m) gt0: 0 < m gt1: 1 < d.1
1 * n < d.1 * n
n, m: nat d: (n | m) gt0: 0 < m gt1: 1 < d.1
1 * n < d.1 * n
n, m: nat d: (n | m) gt0: 0 < m gt1: 1 < d.1
0 < n
rapply (gt_zero_divides n m).Defined.(** Divisibility is antisymmetric *)
n, m: nat
(n | m) -> (m | n) -> n = m
n, m: nat
(n | m) -> (m | n) -> n = m
n, m: nat H1: (n | m) H2: (m | n)
n = m
n, m: nat H1: (n | m.+1) H2: (m.+1 | n)
n = m.+1
n, m: nat H1: (n.+1 | m.+1) H2: (m.+1 | n.+1)
n.+1 = m.+1
snapply leq_antisym; napply leq_divides; exact _.Defined.Instanceantisymmetric_divides : AntiSymmetric NatDivides
:= nat_divides_antisym.(** If [n] divides [m], then the other factor also divides [m]. *)
n, m: nat H: (n | m)
(H.1 | m)
n, m: nat H: (n | m)
(H.1 | m)
n, m: nat H: (n | m)
n * H.1 = m
n, m: nat H: (n | m)
H.1 * n = m
exact H.2.Defined.(** ** Properties of division *)
b, q1, q2, r1, r2: nat
r1 < b ->
r2 < b -> q1 < q2 -> b * q1 + r1 <> b * q2 + r2
b, q1, q2, r1, r2: nat
r1 < b ->
r2 < b -> q1 < q2 -> b * q1 + r1 <> b * q2 + r2
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: b * q1 + r1 = b * q2 + r2
Empty
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 + b * q1 = r2 + b * q2
Empty
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 = r2 + b * q2 - b * q1
Empty
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 = r2 + (b * q2 - b * q1)
Empty
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 = r2 + b * (q2 - q1)
Empty
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 = b * (q2 - q1) + r2
Empty
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 - r2 = b * (q2 - q1)
Empty
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 - r2 = b * (q2 - q1)
b <= r1 - r2
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 - r2 = b * (q2 - q1)
b > r1 - r2
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 - r2 = b * (q2 - q1)
b <= r1 - r2
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 - r2 = b * (q2 - q1)
b <= b * (q2 - q1)
b, q1, q2, r1, r2: nat H1: r1 < b H2: r2 < b H3: q1 < q2 p: r1 - r2 = b * (q2 - q1)
0 < q2 - q1
byapply equiv_lt_lt_sub.Defined.(** Quotients and remainders are uniquely determined. *)
d, q1, q2, r1, r2: nat
r1 < d ->
r2 < d ->
d * q1 + r1 = d * q2 + r2 -> (q1 = q2) * (r1 = r2)
d, q1, q2, r1, r2: nat
r1 < d ->
r2 < d ->
d * q1 + r1 = d * q2 + r2 -> (q1 = q2) * (r1 = r2)
d, q1, q2, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q2 + r2
((q1 = q2) * (r1 = r2))%type
d, q1, q2, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q2 + r2 q: q1 < q2
((q1 = q2) * (r1 = r2))%type
d, q1, q2, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q2 + r2 q: q1 = q2
((q1 = q2) * (r1 = r2))%type
d, q1, q2, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q2 + r2 q: q1 > q2
((q1 = q2) * (r1 = r2))%type
d, q1, q2, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q2 + r2 q: q1 < q2
((q1 = q2) * (r1 = r2))%type
contradiction (nat_div_mod_unique_helper d q1 q2 r1 r2).
d, q1, q2, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q2 + r2 q: q1 = q2
((q1 = q2) * (r1 = r2))%type
d, q1, q2, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q2 + r2 q: q1 = q2
r1 = r2
d, q1, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q1 + r2
r1 = r2
byapply isinj_nat_add_l in p.
d, q1, q2, r1, r2: nat H1: r1 < d H2: r2 < d p: d * q1 + r1 = d * q2 + r2 q: q1 > q2
((q1 = q2) * (r1 = r2))%type
bycontradiction (nat_div_mod_unique_helper d q2 q1 r2 r1).Defined.(** Divisibility by a positive natural number is a hprop. *)
n, m: nat
0 < n -> IsHProp (n | m)
n, m: nat
0 < n -> IsHProp (n | m)
n, m: nat H: 0 < n
IsHProp (n | m)
n, m: nat H: 0 < n
forallxy : (n | m), x = y
n, m: nat H: 0 < n x: nat p: x * n = m y: nat q: y * n = m
(x; p) = (y; q)
n, m: nat H: 0 < n x: nat p: x * n = m y: nat q: y * n = m
(x; p).1 = (y; q).1
m, x: nat p: x * 1 = m y: nat q: y * 1 = m
x = y
m, n: nat H: 1 <= n x: nat p: x * n.+1 = m y: nat q: y * n.+1 = m
x = y
m, n: nat H: 1 <= n x: nat p: x * n.+1 = m y: nat q: y * n.+1 = m
x = y
m, n: nat H: 1 <= n x: nat p: x * n.+1 = m y: nat q: y * n.+1 = m
n.+1 * x + 0 = n.+1 * y + 0
m, n: nat H: 1 <= n x: nat p: x * n.+1 = m y: nat q: y * n.+1 = m
n.+1 * x = n.+1 * y + 0
m, n: nat H: 1 <= n x: nat p: x * n.+1 = m y: nat q: y * n.+1 = m
n.+1 * x = n.+1 * y
m, n: nat H: 1 <= n x: nat p: x * n.+1 = m y: nat q: y * n.+1 = m
x * n.+1 = y * n.+1
exact (p @ q^).Defined.(** This specifies the behaviour of [nat_div_mod_helper] when [u <= y]. *)
x, y, q, u: nat H: u <= y
letq' := fst (nat_div_mod x y q u) inletu' := snd (nat_div_mod x y q u) in
(((x + y.+1 * q + (y - u))%nat =
(y.+1 * q' + (y - u'))%nat) * (u' <= y))%type
x, y, q, u: nat H: u <= y
letq' := fst (nat_div_mod x y q u) inletu' := snd (nat_div_mod x y q u) in
(((x + y.+1 * q + (y - u))%nat =
(y.+1 * q' + (y - u'))%nat) * (u' <= y))%type
x, y, q, u: nat H: u <= y d:= fst (nat_div_mod x y q u): nat r:= snd (nat_div_mod x y q u): nat
x, y, q, u: nat H: u.+1 <= y d:= fst (nat_div_mod x.+1 y q u.+1): nat r:= snd (nat_div_mod x.+1 y q u.+1): nat IHx: forallyqu : nat,
u <= y ->
letd := fst (nat_div_mod x y q u) inletr := snd (nat_div_mod x y q u) in
(x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y) p: x + y.+1 * q + (y - u) =
y.+1 * fst (nat_div_mod x y q u) +
(y - snd (nat_div_mod x y q u)) H': snd (nat_div_mod x y q u) <= y
x.+1 + y.+1 * q + (y - u.+1) = y.+1 * d + (y - r)
x, y, q, u: nat H: u.+1 <= y d:= fst (nat_div_mod x.+1 y q u.+1): nat r:= snd (nat_div_mod x.+1 y q u.+1): nat IHx: forallyqu : nat,
u <= y ->
letd := fst (nat_div_mod x y q u) inletr := snd (nat_div_mod x y q u) in
(x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y) p: x + y.+1 * q + (y - u) =
y.+1 * fst (nat_div_mod x y q u) +
(y - snd (nat_div_mod x y q u)) H': snd (nat_div_mod x y q u) <= y
x + y.+1 * q + (y - u.+1).+1 = x + y.+1 * q + (y - u)
x, y, q, u: nat H: u.+1 <= y d:= fst (nat_div_mod x.+1 y q u.+1): nat r:= snd (nat_div_mod x.+1 y q u.+1): nat IHx: forallyqu : nat,
u <= y ->
letd := fst (nat_div_mod x y q u) inletr := snd (nat_div_mod x y q u) in
(x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y) p: x + y.+1 * q + (y - u) =
y.+1 * fst (nat_div_mod x y q u) +
(y - snd (nat_div_mod x y q u)) H': snd (nat_div_mod x y q u) <= y
(y - u.+1).+1 = y - u
x, y, q, u: nat H: u.+1 <= y d:= fst (nat_div_mod x.+1 y q u.+1): nat r:= snd (nat_div_mod x.+1 y q u.+1): nat IHx: forallyqu : nat,
u <= y ->
letd := fst (nat_div_mod x y q u) inletr := snd (nat_div_mod x y q u) in
(x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y) p: x + y.+1 * q + (y - u) =
y.+1 * fst (nat_div_mod x y q u) +
(y - snd (nat_div_mod x y q u)) H': snd (nat_div_mod x y q u) <= y
(nat_pred (y - u)).+1 = y - u
x, y, q, u: nat H: u.+1 <= y d:= fst (nat_div_mod x.+1 y q u.+1): nat r:= snd (nat_div_mod x.+1 y q u.+1): nat IHx: forallyqu : nat,
u <= y ->
letd := fst (nat_div_mod x y q u) inletr := snd (nat_div_mod x y q u) in
(x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y) p: x + y.+1 * q + (y - u) =
y.+1 * fst (nat_div_mod x y q u) +
(y - snd (nat_div_mod x y q u)) H': snd (nat_div_mod x y q u) <= y
0 < y - u
rapply lt_moveL_nV.Defined.(** Division and modulo can be put in quotient-remainder form. *)
x, y: nat
x = y * (x / y) + x mod y
x, y: nat
x = y * (x / y) + x mod y
x, y: nat
x = y.+1 * (x / y.+1) + x mod y.+1
x, y: nat p: x + y.+1 * 0 + (y - y) =
y.+1 * fst (nat_div_mod x y 0 y) +
(y - snd (nat_div_mod x y 0 y))
x = y.+1 * (x / y.+1) + x mod y.+1
byrewrite nat_mul_zero_r, nat_sub_cancel, 2 nat_add_zero_r in p.Defined.
x, y: nat
x - y * (x / y) = x mod y
x, y: nat
x - y * (x / y) = x mod y
x, y: nat
x = x mod y + y * (x / y)
x, y: nat
x = y * (x / y) + x mod y
apply nat_div_mod_spec.Defined.
x, y: nat
x - x mod y = y * (x / y)
x, y: nat
x - x mod y = y * (x / y)
x, y: nat
x = y * (x / y) + x mod y
apply nat_div_mod_spec.Defined.
n, m, r: nat
r < m -> n mod m < m
n, m, r: nat
r < m -> n mod m < m
n, r, m: nat H: r.+1 <= m
n mod m.+1 < m.+1
rapply (lt_leq_lt_trans (m:=m)).Defined.Hint Immediate nat_mod_lt_r' : typeclass_instances.(** [n] modulo [m] is less than [m]. *)Instancenat_mod_lt_rnm : 0 < m -> n mod m < m
:= nat_mod_lt_r' n m 0.(** [n] modulo [m] is less than or equal to [m]. *)
n, m: nat
n mod m <= n
n, m: nat
n mod m <= n
n, m: nat
n - m * (n / m) <= n
rapply leq_moveR_nV.Defined.(** Division is unique. *)Definitionnat_div_uniquexyqr (H : r < y) (p : y * q + r = x) : x / y = q
:= fst (nat_div_mod_unique y (x / y) q (x mod y) r _ _ (p @ nat_div_mod_spec x y)^).(** Modulo is unique. *)Definitionnat_mod_uniquexyqr (H : r < y) (p : y * q + r = x) : x mod y = r
:= snd (nat_div_mod_unique y (x / y) q (x mod y) r _ _ (p @ nat_div_mod_spec x y)^).(** [0] divided by any number is [0]. *)
n: nat
0 / n = 0
n: nat
0 / n = 0
byinduction n.Defined.(** [n] divided by [0] is [0] by convention. *)Definitionnat_div_zero_rn : n / 0 = 0 := idpath.(** [n] divided by [1] is [n]. *)
n: nat
n / 1 = n
n: nat
n / 1 = n
n: nat
1 * (n / 1) = n
n: nat
1 * (n / 1) + 0 = n
symmetry; apply nat_div_mod_spec.Defined.(** [n] divided by [n] is [1]. *)
n: nat
0 < n -> n / n = 1
n: nat
0 < n -> n / n = 1
n, m: nat
m.+1 / m.+1 = 1
n, m: nat
m.+1 * 1 + 0 = m.+1
n, m: nat
m.+1 * 1 = m.+1
napply nat_mul_one_r.Defined.(** A number divided by a larger number is 0. *)
n, m: nat
n < m -> n / m = 0
n, m: nat
n < m -> n / m = 0
n, m: nat H: n < m
n / m = 0
n, m: nat H: n < m
m * 0 + n = n
byrewrite nat_mul_zero_r, nat_add_zero_l.Defined.(** [n * m] divided by [n] is [m]. *)
n, m: nat
0 < n -> (n * m) / n = m
n, m: nat
0 < n -> (n * m) / n = m
n, m: nat H: 0 < n
(n * m) / n = m
n, m: nat H: 0 < n
n * m + 0 = n * m
apply nat_add_zero_r.Defined.(** [n * m] divided by [n] is [m]. *)
n, m: nat
0 < m -> (n * m) / m = n
n, m: nat
0 < m -> (n * m) / m = n
n, m: nat
0 < m -> (m * n) / m = n
apply nat_div_mul_cancel_l.Defined.(** More generally, [n * m + k] divided by [n] is [m + k / n]. *)
n, m, k: nat
0 < n -> (n * m + k) / n = m + k / n
n, m, k: nat
0 < n -> (n * m + k) / n = m + k / n
n, m, k: nat H: 0 < n
(n * m + k) / n = m + k / n
n, m, k: nat H: 0 < n
n * (m + k / n) + k mod n = n * m + k
n, m, k: nat H: 0 < n
n * m + n * (k / n) + k mod n = n * m + k
n, m, k: nat H: 0 < n
n * m + (n * (k / n) + k mod n) = n * m + k
n, m, k: nat H: 0 < n
n * (k / n) + k mod n = k
symmetry; apply nat_div_mod_spec.Defined.
n, m, k: nat
0 < m -> (n * m + k) / m = n + k / m
n, m, k: nat
0 < m -> (n * m + k) / m = n + k / m
n, m, k: nat
0 < m -> (m * n + k) / m = n + k / m
apply nat_div_mul_add_cancel_l.Defined.(** If [k] is positive, then multiplication on the left is injective; that is, if [k * m = k * n], then [m = n]. *)
k: nat
0 < k -> IsInjective (nat_mul k)
k: nat
0 < k -> IsInjective (nat_mul k)
k: nat kp: 0 < k m, n: nat p: k * m = k * n
m = n
k: nat kp: 0 < k m, n: nat p: k * m = k * n
(k * m) / k = n
k: nat kp: 0 < k m, n: nat p: k * m = k * n
(k * m) / k = (k * n) / k
exact (ap (funx => x / k) p).Defined.(** If [k] is positive, then multiplication on the right is injective; that is, if [m * k = n * k], then [m = n]. *)
k: nat
0 < k -> IsInjective (funn : nat => n * k)
k: nat
0 < k -> IsInjective (funn : nat => n * k)
k: nat kp: 0 < k m, n: nat p: m * k = n * k
m = n
k: nat kp: 0 < k m, n: nat p: m * k = n * k
(m * k) / k = n
k: nat kp: 0 < k m, n: nat p: m * k = n * k
(m * k) / k = (n * k) / k
exact (ap (funx => x / k) p).Defined.(** When [d] divides one of the summands, division distributes over addition. *)
n, m, d: nat
(d | n) -> (n + m) / d = n / d + m / d
n, m, d: nat
(d | n) -> (n + m) / d = n / d + m / d
n, m: nat
(0 | n) -> (n + m) / 0 = n / 0 + m / 0
n, m, d: nat
(d.+1 | n) -> (n + m) / d.+1 = n / d.+1 + m / d.+1
n, m, d: nat
(d.+1 | n) -> (n + m) / d.+1 = n / d.+1 + m / d.+1
n, m, d, x: nat
(x * d.+1 + m) / d.+1 = (x * d.+1) / d.+1 + m / d.+1
n, m, d, x: nat
(x * d.+1 + m) / d.+1 = x + m / d.+1
n, m, d, x: nat
0 < d.+1
n, m, d, x: nat
(x * d.+1 + m) / d.+1 = x + m / d.+1
rapply nat_div_mul_add_cancel_r.Defined.
n, m, d: nat
(d | m) -> (n + m) / d = n / d + m / d
n, m, d: nat
(d | m) -> (n + m) / d = n / d + m / d
n, m, d: nat H: (d | m)
(n + m) / d = n / d + m / d
n, m, d: nat H: (d | m)
(m + n) / d = n / d + m / d
n, m, d: nat H: (d | m)
(m + n) / d = m / d + n / d
rapply nat_div_dist.Defined.(** In general, [n * (m / n)] is less than or equal to [m]. *)
n, m: nat
n * (m / n) <= m
n, m: nat
n * (m / n) <= m
n, m: nat
n * (m / n) <= n * (m / n) + m mod n
exact _.Defined.(** When [n] divides [m], they are equal. *)
n, m: nat
(n | m) -> m / n * n = m
n, m: nat
(n | m) -> m / n * n = m
m: nat
(0 | m) -> m / 0 * 0 = m
n, m: nat
(n.+1 | m) -> m / n.+1 * n.+1 = m
m: nat
(0 | m) -> m / 0 * 0 = m
m, k: nat
(k * 0) / 0 * 0 = k * 0
m, k: nat
0 = k * 0
symmetry; apply nat_mul_zero_r.
n, m: nat
(n.+1 | m) -> m / n.+1 * n.+1 = m
n, m, k: nat
(k * n.+1) / n.+1 * n.+1 = k * n.+1
n, m, k: nat
(k * n.+1) / n.+1 = k
rapply nat_div_mul_cancel_r.Defined.
n, m: nat
(n | m) -> n * (m / n) = m
n, m: nat
(n | m) -> n * (m / n) = m
n, m: nat
(n | m) -> m / n * n = m
apply nat_mul_div_cancel_r.Defined.(** Division by non-zero [k] is strictly monotone if [k] divides the larger number. *)
n, m, l, k: nat
l < k -> n < m -> (k | m) -> n / k < m / k
n, m, l, k: nat
l < k -> n < m -> (k | m) -> n / k < m / k
n, m, l, k: nat lk: l < k nm: n < m km: (k | m)
n / k < m / k
n, m, l, k: nat lk: l < k nm: n < m km: (k | m)
~ (m / k <= n / k)
n, m, l, k: nat lk: l < k nm: n < m km: (k | m) mknk: m / k <= n / k
Empty
n, m, l, k: nat lk: l < k nm: n < m km: (k | m) mknk: m / k <= n / k
m <= n
n, m, l, k: nat lk: l < k nm: n < m km: (k | m) mknk: m / k <= n / k
k * (m / k) <= n
n, m, l, k: nat lk: l < k nm: n < m km: (k | m) mknk: m / k <= n / k
k * (m / k) <= k * (n / k)
n, m, l, k: nat lk: l < k nm: n < m km: (k | m) mknk: m / k <= n / k
k * (n / k) <= n
n, m, l, k: nat lk: l < k nm: n < m km: (k | m) mknk: m / k <= n / k
k * (m / k) <= k * (n / k)
rapply nat_mul_l_monotone.
n, m, l, k: nat lk: l < k nm: n < m km: (k | m) mknk: m / k <= n / k
k * (n / k) <= n
apply nat_leq_mul_div_l.Defined.(** [0] modulo [n] is [0]. *)
n: nat
0 mod n = 0
n: nat
0 mod n = 0
n: nat IHn: 0 mod n = 0
0 mod n.+1 = 0
apply nat_sub_cancel.Defined.(** [n] modulo [0] is [n]. *)Definitionnat_mod_zero_rn : n mod 0 = n := idpath.
n, k: nat
k < n -> k mod n = k
n, k: nat
k < n -> k mod n = k
n, k: nat H: k < n
k mod n = k
n, k: nat H: k < n
k - n * (k / n) = k
n, k: nat H: k < n
k - n * 0 = k
n, k: nat H: k < n
k < n
n, k: nat H: k < n
k - n * 0 = k
n, k: nat H: k < n
k - 0 = k
apply nat_sub_zero_r.
n, k: nat H: k < n
k < n
exact H.Defined.(** [n] modulo [1] is [0]. *)
n: nat
n mod 1 = 0
n: nat
n mod 1 = 0
byinduction n.Defined.(** If [m] divides [n], then [n mod m = 0]. *)
n, m: nat
(m | n) -> n mod m = 0
n, m: nat
(m | n) -> n mod m = 0
n, m, x: nat p: x * m = n
n mod m = 0
m, x: nat
(x * m) mod m = 0
x: nat
(x * 0) mod 0 = 0
m, x: nat
(x * m.+1) mod m.+1 = 0
x: nat
(x * 0) mod 0 = 0
x: nat
x * 0 = 0
apply nat_mul_zero_r.
m, x: nat
(x * m.+1) mod m.+1 = 0
m, x: nat
x * m.+1 - m.+1 * ((x * m.+1) / m.+1) = 0
m, x: nat
x * m.+1 - m.+1 * x = 0
apply nat_moveR_nV, nat_mul_comm.Defined.(** [n mod m = 0] iff [m] divides [n]. *)
n, m: nat
n mod m = 0 <-> (m | n)
n, m: nat
n mod m = 0 <-> (m | n)
n, m: nat
n mod m = 0 -> (m | n)
n, m: nat
(m | n) -> n mod m = 0
n, m: nat
n mod m = 0 -> (m | n)
n, m: nat p: n mod m = 0
(m | n)
n, m: nat p: n mod m = 0
n / m * m = n
n, m: nat p: n mod m = 0
m * (n / m) = n
n, m: nat p: n mod m = 0
m * (n / m) + 0 = n
n, m: nat p: n mod m = 0
m * (n / m) + n mod m = n
n, m: nat p: n mod m = 0
n = m * (n / m) + n mod m
napply nat_div_mod_spec.Defined.(** Divisibility is therefore decidable. *)
n, m: nat
Decidable (n | m)
n, m: nat
Decidable (n | m)
n, m: nat
?Goal <-> (n | m)
n, m: nat
Decidable ?Goal
n, m: nat
Decidable (m mod n = 0)
exact _.Defined.(** [n] modulo [n] is [0]. *)
n: nat
n mod n = 0
n: nat
n mod n = 0
n: nat
n.+1 mod n.+1 = 0
n: nat
n.+1 * 1 + 0 = n.+1
n: nat
n.+1 * 1 = n.+1
napply nat_mul_one_r.Defined.(** A number can be corrected so that it is divisible by subtracting the modulo. *)
n, m: nat
(n | m - m mod n)
n, m: nat
(n | m - m mod n)
n, m: nat
(n | n * (m / n))
exact _.Defined.(** ** Further Properties of division and modulo *)(** We can cancel common factors on the left in a division. *)
n, m, k: nat
0 < k -> (k * n) / (k * m) = n / m
n, m, k: nat
0 < k -> (k * n) / (k * m) = n / m
n, m, k: nat kp: 0 < k
(k * n) / (k * m) = n / m
n, m, k: nat kp: 0 < k
(k * n) / (k * 0) = n / 0
n, m, k: nat kp: 0 < k mp: 0 < m
(k * n) / (k * m) = n / m
n, m, k: nat kp: 0 < k mp: 0 < m
(k * n) / (k * m) = n / m
n, m, k: nat kp: 0 < k mp: 0 < m
k * (n mod m) < k * m
n, m, k: nat kp: 0 < k mp: 0 < m
k * m * (n / m) + k * (n mod m) = k * n
n, m, k: nat kp: 0 < k mp: 0 < m
k * m * (n / m) + k * (n mod m) = k * n
n, m, k: nat kp: 0 < k mp: 0 < m
k * (m * (n / m)) + k * (n mod m) = k * n
n, m, k: nat kp: 0 < k mp: 0 < m
k * (m * (n / m) + n mod m) = k * n
n, m, k: nat kp: 0 < k mp: 0 < m
m * (n / m) + n mod m = n
symmetry; apply nat_div_mod_spec.Defined.(** We can cancel common factors on the right in a division. *)
n, m, k: nat
0 < k -> (n * k) / (m * k) = n / m
n, m, k: nat
0 < k -> (n * k) / (m * k) = n / m
n, m, k: nat
0 < k -> (k * n) / (k * m) = n / m
napply nat_div_cancel_mul_l.Defined.(** We can swap the order of division and multiplication on the left under certain conditions. *)
n, m, k: nat
(m | n) -> k * (n / m) = (k * n) / m
n, m, k: nat
(m | n) -> k * (n / m) = (k * n) / m
n, m, k: nat H: (m | n)
k * (n / m) = (k * n) / m
n, m, k: nat H: (m | n)
k * (n / 0) = (k * n) / 0
n, m, k: nat H: (m | n) mp: 0 < m
k * (n / m) = (k * n) / m
n, m, k: nat H: (m | n) mp: 0 < m
k * (n / m) = (k * n) / m
n, m, k: nat H: (m | n) mp: 0 < m
m * (k * (n / m)) + 0 = k * n
n, m, k: nat H: (m | n) mp: 0 < m
m * (k * (n / m)) = k * n
n, m, k: nat H: (m | n) mp: 0 < m
m * k * (n / m) = k * n
n, m, k: nat H: (m | n) mp: 0 < m
m * k = ?Goal
n, m, k: nat H: (m | n) mp: 0 < m
?Goal * (n / m) = k * n
n, m, k: nat H: (m | n) mp: 0 < m
k * m * (n / m) = k * n
n, m, k: nat H: (m | n) mp: 0 < m
k * (m * (n / m)) = k * n
n, m, k: nat H: (m | n) mp: 0 < m
m * (n / m) = n
n, m, k: nat H: (m | n) mp: 0 < m
m * (n / m) + 0 = n
n, m, k: nat H: (m | n) mp: 0 < m
m * (n / m) + 0 = m * (n / m) + n mod m
n, m, k: nat H: (m | n) mp: 0 < m
0 = n mod m
n, m, k: nat H: (m | n) mp: 0 < m
n mod m = 0
rapply nat_mod_divides.Defined.(** We can swap the order of division and multiplication on the right under certain conditions. *)
n, m, k: nat
(m | n) -> n / m * k = (n * k) / m
n, m, k: nat
(m | n) -> n / m * k = (n * k) / m
n, m, k: nat
(m | n) -> k * (n / m) = (k * n) / m
snapply nat_div_mul_l.Defined.
n, m: nat
n / m = (n - n mod m) / m
n, m: nat
n / m = (n - n mod m) / m
n, m: nat
n / 0 = (n - n mod 0) / 0
n, m: nat mp: 0 < m
n / m = (n - n mod m) / m
n, m: nat mp: 0 < m
n / m = (n - n mod m) / m
n, m: nat mp: 0 < m
(n - n mod m) / m = n / m
n, m: nat mp: 0 < m
(m * (n / m)) / m = n / m
rapply nat_div_mul_cancel_l.Defined.(** Dividing a quotient is the same as dividing by the product of the divisors. *)
n, m, k: nat
(n / m) / k = n / (m * k)
n, m, k: nat
(n / m) / k = n / (m * k)
n, m, k: nat
(n / m) / 0 = n / (m * 0)
n, m, k: nat kp: 0 < k
(n / m) / k = n / (m * k)
n, m, k: nat kp: 0 < k
(n / m) / k = n / (m * k)
n, m, k: nat kp: 0 < k
(n / 0) / k = n / (0 * k)
n, m, k: nat kp: 0 < k mp: 0 < m
(n / m) / k = n / (m * k)
n, m, k: nat kp: 0 < k mp: 0 < m
(n / m) / k = n / (m * k)
n, m, k: nat kp: 0 < k mp: 0 < m
(n mod (m * k)) / m < k
n, m, k: nat kp: 0 < k mp: 0 < m
k * (n / (m * k)) + (n mod (m * k)) / m = n / m
n, m, k: nat kp: 0 < k mp: 0 < m
(n mod (m * k)) / m < k
n, m, k: nat kp: 0 < k mp: 0 < m
(n mod (m * k)) / m < (m * k) / m
n, m, k: nat kp: 0 < k mp: 0 < m
(m * k) / m <= k
n, m, k: nat kp: 0 < k mp: 0 < m
(n mod (m * k)) / m < (m * k) / m
n, m, k: nat kp: 0 < k mp: 0 < m
n mod (m * k) < m * k
n, m, k: nat kp: 0 < k mp: 0 < m
0 < m * k
exact (nat_mul_strictly_monotone mp kp).
n, m, k: nat kp: 0 < k mp: 0 < m
(m * k) / m <= k
byrewrite nat_div_mul_cancel_l.
n, m, k: nat kp: 0 < k mp: 0 < m
k * (n / (m * k)) + (n mod (m * k)) / m = n / m
n, m, k: nat kp: 0 < k mp: 0 < m
k * (n / (m * k)) + (n mod (m * k)) / m =
(m * (k * (n / (m * k)))) / m + (n mod (m * k)) / m
n, m, k: nat kp: 0 < k mp: 0 < m
(m * (k * (n / (m * k)))) / m + (n mod (m * k)) / m =
n / m
n, m, k: nat kp: 0 < k mp: 0 < m
k * (n / (m * k)) + (n mod (m * k)) / m =
(m * (k * (n / (m * k)))) / m + (n mod (m * k)) / m
n, m, k: nat kp: 0 < k mp: 0 < m
k * (n / (m * k)) = (m * (k * (n / (m * k)))) / m
symmetry; rapply nat_div_mul_cancel_l.
n, m, k: nat kp: 0 < k mp: 0 < m
(m * (k * (n / (m * k)))) / m + (n mod (m * k)) / m =
n / m
n, m, k: nat kp: 0 < k mp: 0 < m
(m * k * (n / (m * k))) / m + (n mod (m * k)) / m =
n / m
n, m, k: nat kp: 0 < k mp: 0 < m
(m | m * k * (n / (m * k)))
n, m, k: nat kp: 0 < k mp: 0 < m
(m * k * (n / (m * k)) + n mod (m * k)) / m = n / m
n, m, k: nat kp: 0 < k mp: 0 < m
(m * k * (n / (m * k)) + n mod (m * k)) / m = n / m
n, m, k: nat kp: 0 < k mp: 0 < m
m * k * (n / (m * k)) + n mod (m * k) = n
symmetry; apply nat_div_mod_spec.Defined.(** Dividing a number by a quotient is the same as dividing the product of the number with the denominator of the quotient by the numerator of the quotient. *)
n, m, k: nat
(k | m) -> n / (m / k) = (n * k) / m
n, m, k: nat
(k | m) -> n / (m / k) = (n * k) / m
n, m, k, d: nat r: d * k = m
n / (m / k) = (n * k) / m
n, m, k, d: nat r: d * k = m
n / (m / 0) = (n * 0) / m
n, m, k, d: nat r: d * k = m kp: 0 < k
n / (m / k) = (n * k) / m
n, m, k, d: nat r: d * k = m kp: 0 < k
n / (m / k) = (n * k) / m
n, k, d: nat kp: 0 < k
n / ((d * k) / k) = (n * k) / (d * k)
n, k, d: nat kp: 0 < k
n / ((d * k) / k) = n / d
n, k, d: nat kp: 0 < k
0 < k
n, k, d: nat kp: 0 < k
n / ((d * k) / k) = n / d
n, k, d: nat kp: 0 < k
(d * k) / k = d
rapply nat_div_mul_cancel_r.Defined.(** A variant of [nat_div_div_r] without the divisibility assumption, by modifying [m] to become divisible. *)
n, m, k: nat
n / (m / k) = (n * k) / (m - m mod k)
n, m, k: nat
n / (m / k) = (n * k) / (m - m mod k)
n, m, k: nat
n / ((m - m mod k) / k) = (n * k) / (m - m mod k)
rapply nat_div_div_r.Defined.(** We can cancel common factors on the left in a modulo. *)
n, m, k: nat
(k * n) mod (k * m) = k * (n mod m)
n, m, k: nat
(k * n) mod (k * m) = k * (n mod m)
n, m, k: nat
(0 * n) mod (0 * m) = 0 * (n mod m)
n, m, k: nat kp: 0 < k
(k * n) mod (k * m) = k * (n mod m)
n, m, k: nat kp: 0 < k
(k * n) mod (k * m) = k * (n mod m)
n, m, k: nat kp: 0 < k
(k * n) mod (k * 0) = k * (n mod 0)
n, m, k: nat kp: 0 < k mp: 0 < m
(k * n) mod (k * m) = k * (n mod m)
n, m, k: nat kp: 0 < k mp: 0 < m
(k * n) mod (k * m) = k * (n mod m)
n, m, k: nat kp: 0 < k mp: 0 < m
k * (n mod m) < k * m
n, m, k: nat kp: 0 < k mp: 0 < m
k * m * (n / m) + k * (n mod m) = k * n
n, m, k: nat kp: 0 < k mp: 0 < m
k * m * (n / m) + k * (n mod m) = k * n
n, m, k: nat kp: 0 < k mp: 0 < m
k * (m * (n / m)) + k * (n mod m) = k * n
n, m, k: nat kp: 0 < k mp: 0 < m
k * (m * (n / m) + n mod m) = k * n
n, m, k: nat kp: 0 < k mp: 0 < m
m * (n / m) + n mod m = n
symmetry; apply nat_div_mod_spec.Defined.(** We can cancel common factors on the right in a modulo. *)
n, m, k: nat
(n * k) mod (m * k) = n mod m * k
n, m, k: nat
(n * k) mod (m * k) = n mod m * k
n, m, k: nat
(k * n) mod (k * m) = k * (n mod m)
napply nat_mod_mul_l.Defined.(** We can move a divisor from the right to become a factor on the left of an equation. *)
n, m, k: nat
0 < k -> n * k = m -> n = m / k
n, m, k: nat
0 < k -> n * k = m -> n = m / k
n, m, k: nat H: 0 < k p: n * k = m
n = m / k
n, k: nat H: 0 < k
n = (n * k) / k
symmetry; rapply nat_div_mul_cancel_r.Defined.
n, m, k: nat
0 < k -> n = m * k -> n / k = m
n, m, k: nat
0 < k -> n = m * k -> n / k = m
n, m, k: nat H: 0 < k p: n = m * k
n / k = m
m, k: nat H: 0 < k p: m * k = m * k
(m * k) / k = m
rapply nat_div_mul_cancel_r.Defined.
n, m, l: nat
0 < m -> (m | n) -> (n | l * m) -> (n / m | l)
n, m, l: nat
0 < m -> (m | n) -> (n | l * m) -> (n / m | l)
n, m, l: nat H1: 0 < m H2: (m | n) y: nat q: y * n = l * m
(n / m | l)
n, m, l: nat H1: 0 < m H2: (m | n) y: nat q: y * n = l * m
y * (n / m) = l
n, m, l: nat H1: 0 < m H2: (m | n) y: nat q: y * n = l * m
(y * n) / m = l
by rapply nat_div_moveR_nV.Defined.
n, m, l: nat
(n * l | m) -> (n | m / l)
n, m, l: nat
(n * l | m) -> (n | m / l)
n, m, l: nat
(n * l.+1 | m) -> (n | m / l.+1)
n, m, l, k: nat p: k * (n * l.+1) = m
(n | m / l.+1)
n, m, l, k: nat p: k * (n * l.+1) = m
k * n = m / l.+1
n, m, l, k: nat p: k * (n * l.+1) = m
k * n * l.+1 = m
by lhs_V napply nat_mul_assoc.Defined.
n, m, l: nat
(l | m) -> (n | m / l) -> (n * l | m)
n, m, l: nat
(l | m) -> (n | m / l) -> (n * l | m)
n, m, l: nat H: (l | m) k: nat p: k * n = m / l
(n * l | m)
n, m, l: nat H: (l | m) k: nat p: k * n = m / l
k * (n * l) = m
n, m, l: nat H: (l | m) k: nat p: k * n = m / l
k * n * l = m
n, m, l: nat H: (l | m) k: nat p: k * n = m / l
m / l * l = m
rapply nat_mul_div_cancel_r.Defined.(** ** Greatest Common Divisor *)(** The greatest common divisor of [0] and a number is the number itself. *)Definitionnat_gcd_zero_ln : nat_gcd 0 n = n := idpath.(** The greatest common divisor of a number and [0] is the number itself. *)
n: nat
nat_gcd n 0 = n
n: nat
nat_gcd n 0 = n
n: nat IHn: nat_gcd n 0 = n
nat_gcd (n - n) n.+1 = n.+1
byrewrite nat_sub_cancel.Defined.(** The greatest common divisor of [1] and any number is [1]. *)Definitionnat_gcd_one_ln : nat_gcd 1 n = 1 := idpath.(** The greatest common divisor of any number and [1] is [1]. *)
n: nat
nat_gcd n 1 = 1
n: nat
nat_gcd n 1 = 1
n: nat
nat_gcd n.+11 = 1
n: nat
nat_gcd
(n -
snd
match n with
| 0 => (1, n)
| u'.+1 => (0, u')
end) n.+1 = 1
byrewrite nat_mod_cancel.Defined.(** We can prove that the greatest common divisor of [n] and [m] divides both [n] and [m]. This proof requires strong induction. *)
n, m: nat
((nat_gcd n m | n) * (nat_gcd n m | m))%type
n, m: nat
((nat_gcd n m | n) * (nat_gcd n m | m))%type
n: nat IHn: forallm : nat,
m < n ->
(funn : nat => forallm0 : nat, (nat_gcd n m0 | n) * (nat_gcd n m0 | m0)) m m: nat
((nat_gcd n m | n) * (nat_gcd n m | m))%type
IHn: forallm : nat,
m < 0 -> forallm0 : nat, (nat_gcd m m0 | m) * (nat_gcd m m0 | m0) m: nat
((nat_gcd 0 m | 0) * (nat_gcd 0 m | m))%type
n: nat IHn: forallm : nat,
m < n.+1 -> forallm0 : nat, (nat_gcd m m0 | m) * (nat_gcd m m0 | m0) m: nat
((nat_gcd n.+1 m | n.+1) * (nat_gcd n.+1 m | m))%type
n: nat IHn: forallm : nat,
m < n.+1 -> forallm0 : nat, (nat_gcd m m0 | m) * (nat_gcd m m0 | m0) m: nat
((nat_gcd n.+1 m | n.+1) * (nat_gcd n.+1 m | m))%type
n: nat IHn: forallm : nat,
m < n.+1 -> forallm0 : nat, (nat_gcd m m0 | m) * (nat_gcd m m0 | m0) m: nat H1: (nat_gcd (m mod n.+1) n.+1 | m mod n.+1) H2: (nat_gcd (m mod n.+1) n.+1 | n.+1)
((nat_gcd n.+1 m | n.+1) * (nat_gcd n.+1 m | m))%type
n: nat IHn: forallm : nat,
m < n.+1 -> forallm0 : nat, (nat_gcd m m0 | m) * (nat_gcd m m0 | m0) m: nat H1: (nat_gcd (m mod n.+1) n.+1 | m mod n.+1) H2: (nat_gcd (m mod n.+1) n.+1 | n.+1)
((nat_gcd (m mod n.+1) n.+1 | n.+1) *
(nat_gcd (m mod n.+1) n.+1 | m))%type
n: nat n':= n.+1: nat IHn: forallm : nat,
m < n' -> forallm0 : nat, (nat_gcd m m0 | m) * (nat_gcd m m0 | m0) m: nat H1: (nat_gcd (m mod n') n' | m mod n') H2: (nat_gcd (m mod n') n' | n')
((nat_gcd (m mod n') n' | n') *
(nat_gcd (m mod n') n' | m))%type
n: nat n':= n.+1: nat IHn: forallm : nat,
m < n' -> forallm0 : nat, (nat_gcd m m0 | m) * (nat_gcd m m0 | m0) m: nat H1: (nat_gcd (m mod n') n' | m mod n') H2: (nat_gcd (m mod n') n' | n')
(nat_gcd (m mod n') n' | m)
n: nat n':= n.+1: nat IHn: forallm : nat,
m < n' -> forallm0 : nat, (nat_gcd m m0 | m) * (nat_gcd m m0 | m0) m: nat H1: (nat_gcd (m mod n') n' | m mod n') H2: (nat_gcd (m mod n') n' | n')
(nat_gcd (m mod n') n' | n' * (m / n') + m mod n')
exact _.Defined.(** The greatest common divisor of [n] and [m] divides [n]. *)Instancenat_divides_l_gcd_lnm : (nat_gcd n m | n)
:= fst (nat_divides_l_gcd n m).(** The greatest common divisor of [n] and [m] divides [m]. *)Instancedivides_l_nat_gcd_rnm : (nat_gcd n m | m)
:= snd (nat_divides_l_gcd n m).(** We can prove that any common divisor of [n] and [m] divides the greatest common divisor of [n] and [m]. It is in that sense the greatest. *)
n, m, p: nat
(p | n) -> (p | m) -> (p | nat_gcd n m)
n, m, p: nat
(p | n) -> (p | m) -> (p | nat_gcd n m)
n: nat IHn: forallm : nat,
m < n ->
(funn : nat => forallm0p : nat, (p | n) -> (p | m0) -> (p | nat_gcd n m0))
m m, p: nat H1: (p | n) H2: (p | m)
(p | nat_gcd n m)
n: nat IHn: forallm : nat,
m < n.+1 -> forallm0p : nat, (p | m) -> (p | m0) -> (p | nat_gcd m m0) m, p: nat H1: (p | n.+1) H2: (p | m)
(p | nat_gcd n.+1 m)
n: nat IHn: forallm : nat,
m < n.+1 -> forallm0p : nat, (p | m) -> (p | m0) -> (p | nat_gcd m m0) m, p: nat H1: (p | n.+1) H2: (p | m)
(p | nat_gcd (m mod n.+1) n.+1)
n: nat IHn: forallm : nat,
m < n.+1 -> forallm0p : nat, (p | m) -> (p | m0) -> (p | nat_gcd m m0) m, p: nat H1: (p | n.+1) H2: (p | m)
(p | m mod n.+1)
n: nat IHn: forallm : nat,
m < n.+1 -> forallm0p : nat, (p | m) -> (p | m0) -> (p | nat_gcd m m0) m, p: nat H1: (p | n.+1) H2: (p | n.+1 * (m / n.+1) + m mod n.+1)
(p | m mod n.+1)
apply nat_divides_add_r in H2; exact _.Defined.
n, m, p: nat
(p | n) * (p | m) <-> (p | nat_gcd n m)
n, m, p: nat
(p | n) * (p | m) <-> (p | nat_gcd n m)
split; [intros [H1 H2] | intros H; split]; exact _.Defined.(** If [p] is divisible by all common divisors of [n] and [m], and [p] is also a common divisor, then it must necessarily be equal to the greatest common divisor. *)
n, m, p: nat H: forallq : nat, (q | n) -> (q | m) -> (q | p)
(p | n) -> (p | m) -> nat_gcd n m = p
n, m, p: nat H: forallq : nat, (q | n) -> (q | m) -> (q | p)
(p | n) -> (p | m) -> nat_gcd n m = p
n, m, p: nat H: forallq : nat, (q | n) -> (q | m) -> (q | p) H1: (p | n) H2: (p | m)
nat_gcd n m = p
rapply nat_divides_antisym.Defined.(** As a corollary of uniqueness, we get that the greatest common divisor operation is commutative. *)
n, m: nat
nat_gcd n m = nat_gcd m n
n, m: nat
nat_gcd n m = nat_gcd m n
rapply nat_gcd_unique.Defined.(** [nat_gcd] is associative. *)
apply nat_divides_r_gcd; rapply nat_divides_trans.Defined.(** If [nat_gcd n m] is [0], then [n] must also be [0]. *)
n, m: nat
nat_gcd n m = 0 -> n = 0
n, m: nat
nat_gcd n m = 0 -> n = 0
n, m: nat H: nat_gcd n m = 0
n = 0
n, m: nat H: nat_gcd n m = 0
(nat_gcd n m | n) -> n = 0
n, m: nat H: nat_gcd n m = 0
(0 | n) -> n = 0
n, m: nat H: nat_gcd n m = 0 x: nat p: x * 0 = n
n = 0
exact (p^ @ nat_mul_zero_r _).Defined.(** If [nat_gcd n m] is [0], then [m] must also be [0]. *)
n, m: nat
nat_gcd n m = 0 -> m = 0
n, m: nat
nat_gcd n m = 0 -> m = 0
n, m: nat
nat_gcd m n = 0 -> m = 0
apply nat_gcd_is_zero_l.Defined.(** [nat_gcd n m] is [0] if and only if both [n] and [m] are [0]. *)
n, m: nat
nat_gcd n m = 0 <-> (n = 0) * (m = 0)
n, m: nat
nat_gcd n m = 0 <-> (n = 0) * (m = 0)
n, m: nat
nat_gcd n m = 0 -> (n = 0) * (m = 0)
n, m: nat
(n = 0) * (m = 0) -> nat_gcd n m = 0
n, m: nat
nat_gcd n m = 0 -> (n = 0) * (m = 0)
n, m: nat H: nat_gcd n m = 0
n = 0
n, m: nat H: nat_gcd n m = 0
m = 0
n, m: nat H: nat_gcd n m = 0
n = 0
byapply (nat_gcd_is_zero_l _ m).
n, m: nat H: nat_gcd n m = 0
m = 0
byapply (nat_gcd_is_zero_r n).
n, m: nat
(n = 0) * (m = 0) -> nat_gcd n m = 0
nat_gcd 00 = 0
reflexivity.Defined.(** [nat_gcd] is positive for positive inputs. *)
n, m: nat
0 < n -> 0 < m -> 0 < nat_gcd n m
n, m: nat
0 < n -> 0 < m -> 0 < nat_gcd n m
n, m: nat H1: 0 < n H2: 0 < m
0 < nat_gcd n m
n, m: nat H1: 0 < n H2: 0 < m
~ (0 >= nat_gcd n m)
n, m: nat H1: 0 < n H2: 0 < m H3: nat_gcd n m <= 0
Empty
n, m: nat H1: 0 < n H2: 0 < m H3: nat_gcd n m = 0
Empty
n, m: nat H1: 0 < n H2: 0 < m H3: ((n = 0) * (m = 0))%type
Empty
m: nat H1: 0 < 0 H2: 0 < m snd: m = 0
Empty
contradiction (not_lt_zero_r _ H1).Defined.
n, m, k: nat
nat_gcd (n + k * m) m = nat_gcd n m
n, m, k: nat
nat_gcd (n + k * m) m = nat_gcd n m
n, m, k: nat
forallq : nat,
(q | n + k * m) -> (q | m) -> (q | nat_gcd n m)
n, m, k, q: nat H1: (q | n + k * m) H2: (q | m)
(q | nat_gcd n m)
n, m, k, q: nat H1: (q | n + k * m) H2: (q | m)
(q | n)
rapply (nat_divides_add_l _ _ (k * m)).Defined.
n, m, k: nat
nat_gcd n (m + k * n) = nat_gcd n m
n, m, k: nat
nat_gcd n (m + k * n) = nat_gcd n m
n, m, k: nat
nat_gcd (m + k * n) n = nat_gcd n m
n, m, k: nat
nat_gcd (m + k * n) n = nat_gcd m n
napply nat_gcd_l_add_r_mul.Defined.
n, m: nat
nat_gcd (n + m) m = nat_gcd n m
n, m: nat
nat_gcd (n + m) m = nat_gcd n m
n, m: nat
nat_gcd (n + m) m = nat_gcd (n + 1 * m) m
byrewrite nat_mul_one_l.Defined.
n, m: nat
nat_gcd n (m + n) = nat_gcd n m
n, m: nat
nat_gcd n (m + n) = nat_gcd n m
n, m: nat
nat_gcd (m + n) n = nat_gcd n m
n, m: nat
nat_gcd (m + n) n = nat_gcd m n
napply nat_gcd_l_add_r.Defined.
n, m: nat
m <= n -> nat_gcd (n - m) m = nat_gcd n m
n, m: nat
m <= n -> nat_gcd (n - m) m = nat_gcd n m
n, m: nat H: m <= n
nat_gcd (n - m) m = nat_gcd n m
n, m: nat H: m <= n
nat_gcd (n - m + m) m = nat_gcd n m
byrewrite (nat_add_sub_l_cancel H).Defined.
n, m: nat
n <= m -> nat_gcd n (m - n) = nat_gcd n m
n, m: nat
n <= m -> nat_gcd n (m - n) = nat_gcd n m
n, m: nat H: n <= m
nat_gcd n (m - n) = nat_gcd n m
n, m: nat H: n <= m
nat_gcd (m - n) n = nat_gcd n m
n, m: nat H: n <= m
nat_gcd (m - n) n = nat_gcd m n
rapply nat_gcd_l_sub.Defined.(** ** Bezout's Identity *)(** Bezout's identity states that for any two numbers [n] and [m], their greatest common divisor can be written as a linear combination of [n] and [m]. This is easy to state for the integers, however since we are working with the natural numbers, we need to be more careful. This is why we write the linear combination as [a * n = d + b * m] rather than the usual [a * n + b * m = d]. *)(** We define a predicate for triples of integers satisfying Bezout's identity. *)DefinitionNatBezoutnmd : Type0
:= existsab, a * n = d + b * m.Existing ClassNatBezout.
n, k: nat
NatBezout n k n
n, k: nat
NatBezout n k n
byexists1, 0.Defined.(** If [a * n = 1 + b * m], then the gcd of [n] and [m] is [1]. *)
n, m: nat
NatBezout n m 1 -> nat_gcd n m = 1
n, m: nat
NatBezout n m 1 -> nat_gcd n m = 1
n, m, a, b: nat p: a * n = 1 + b * m
nat_gcd n m = 1
n, m, a, b: nat p: a * n = 1 + b * m
forallq : nat, (q | n) -> (q | m) -> (q | 1)
n, m, a, b: nat p: a * n = 1 + b * m q: nat H1: (q | n) H2: (q | m)
(q | 1)
n, m, a, b: nat p: a * n = 1 + b * m q: nat H1: (q | n) H2: (q | m)
(q | 1 + b * m)
destruct p; exact _.Defined.
n, m, d: nat
0 < m -> NatBezout n m d -> NatBezout m n d
n, m, d: nat
0 < m -> NatBezout n m d -> NatBezout m n d
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m
NatBezout m n d
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
NatBezout m n d
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m q: 0 = a
NatBezout m n d
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
NatBezout m n d
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
(n * a.+1 * b.+1 - b) * m =
d + (m * a.+1 * b.+1 - a) * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * a.+1 * b.+1 * m - b * m =
d + (m * a.+1 * b.+1 * n - a * n)
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * a.+1 * b.+1 * m =
d + (m * a.+1 * b.+1 * n - a * n) + b * m
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * a.+1 * b.+1 * m =
d + b * m + (m * a.+1 * b.+1 * n - a * n)
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * a.+1 * b.+1 * m =
d + b * m + m * a.+1 * b.+1 * n - a * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
a * n <= m * a.+1 * b.+1 * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
a * n <= m * a.+1 * b.+1 * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
a <= m * a.+1 * b.+1
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
a <= (m * a + m) * b + (m * a + m)
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
a <= m * a + m
exact (leq_trans _ (leq_add_r _ _)).
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * a.+1 * b.+1 * m =
d + b * m + m * a.+1 * b.+1 * n - a * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * a.+1 * b.+1 * m + a * n =
d + b * m + m * a.+1 * b.+1 * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
a * n + n * a.+1 * b.+1 * m =
d + b * m + m * a.+1 * b.+1 * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * a.+1 * b.+1 * m = m * a.+1 * b.+1 * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
m * (n * a.+1 * b.+1) = m * a.+1 * b.+1 * n
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
m * (n * a.+1 * b.+1) = m * a.+1 * (b.+1 * n)
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
m * (n * a.+1 * b.+1) = m * (a.+1 * (b.+1 * n))
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * a.+1 * b.+1 = a.+1 * (b.+1 * n)
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * (a.+1 * b.+1) = a.+1 * (b.+1 * n)
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m l: 0 < a
n * (a.+1 * b.+1) = a.+1 * b.+1 * n
apply nat_mul_comm.
n, m, d: nat H: 0 < m a, b: nat p: a * n = d + b * m q: 0 = a
NatBezout m n d
n, m, d: nat H: 0 < m b: nat p: 0 * n = d + b * m
NatBezout m n d
n, m, d: nat H: 0 < m b: nat p: 0 * n = d + b * m
0 * m = d + 0 * n
n, m, d: nat H: 0 < m b: nat p: 0 = d + b * m
0 = d
n, m, d: nat H: 0 < m b: nat p: d + b * m = 0
d = 0
n, m, d: nat H: 0 < m b: nat p: ((d = 0) * ((b * m)%nat = 0))%type
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n
NatBezout n m (nat_gcd n m)
(** Given a sum [n + m], we can always find another pair [n' + m'] equal to that sum such that [n' < m']. This extra hypothesis lets us prove the statement more directly. *)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n
foralln'm' : nat,
n + m = n' + m' ->
0 < n' -> n' < m' -> NatBezout n' m' (nat_gcd n' m')
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m')
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n
foralln'm' : nat,
n + m = n' + m' ->
0 < n' -> n' < m' -> NatBezout n' m' (nat_gcd n' m')
n, m: nat IHk: forallm0 : nat,
m0 < n + m ->
forallnm : nat, n + m = m0 -> 0 < n -> NatBezout n m (nat_gcd n m) H: 0 < n n', m': nat p: n + m = n' + m' H1: 0 < n' H2: n' < m'
NatBezout n' m' (nat_gcd n' m')
n, m: nat IHk: forallm0 : nat,
m0 < n + m ->
forallnm : nat, n + m = m0 -> 0 < n -> NatBezout n m (nat_gcd n m) H: 0 < n n', m': nat p: n + m = n' + m' H1: 0 < n' H2: n' < m' H0: m' < n + m
NatBezout n' m' (nat_gcd n' m')
n, m: nat IHk: forallm0 : nat,
m0 < n + m ->
forallnm : nat, n + m = m0 -> 0 < n -> NatBezout n m (nat_gcd n m) H: 0 < n n', m': nat p: n + m = n' + m' H1: 0 < n' H2: n' < m' H0: m' < n + m a, b: nat r: a * n' = nat_gcd n' (m' - n') + b * (m' - n')
NatBezout n' m' (nat_gcd n' m')
n, m: nat IHk: forallm0 : nat,
m0 < n + m ->
forallnm : nat, n + m = m0 -> 0 < n -> NatBezout n m (nat_gcd n m) H: 0 < n n', m': nat p: n + m = n' + m' H1: 0 < n' H2: n' < m' H0: m' < n + m a, b: nat r: a * n' = nat_gcd n' (m' - n') + b * (m' - n')
(a + b) * n' = nat_gcd n' m' + b * m'
n, m: nat IHk: forallm0 : nat,
m0 < n + m ->
forallnm : nat, n + m = m0 -> 0 < n -> NatBezout n m (nat_gcd n m) H: 0 < n n', m': nat p: n + m = n' + m' H1: 0 < n' H2: n' < m' H0: m' < n + m a, b: nat r: a * n' = nat_gcd n' (m' - n') + b * (m' - n')
nat_gcd n' (m' - n') + (b * m' - b * n' + b * n') =
nat_gcd n' m' + b * m'
n, m: nat IHk: forallm0 : nat,
m0 < n + m ->
forallnm : nat, n + m = m0 -> 0 < n -> NatBezout n m (nat_gcd n m) H: 0 < n n', m': nat p: n + m = n' + m' H1: 0 < n' H2: n' < m' H0: m' < n + m a, b: nat r: a * n' = nat_gcd n' (m' - n') + b * (m' - n')
nat_gcd n' (m' - n') + b * m' = nat_gcd n' m' + b * m'
n, m: nat IHk: forallm0 : nat,
m0 < n + m ->
forallnm : nat, n + m = m0 -> 0 < n -> NatBezout n m (nat_gcd n m) H: 0 < n n', m': nat p: n + m = n' + m' H1: 0 < n' H2: n' < m' H0: m' < n + m a, b: nat r: a * n' = nat_gcd n' (m' - n') + b * (m' - n')
nat_gcd n' (m' - n') = nat_gcd n' m'
rapply nat_gcd_r_sub.
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m')
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') l: n < m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') p: n = m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') l: n < m
NatBezout n m (nat_gcd n m)
byapply H'.
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') p: n = m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n: nat q: n + n = k H: 0 < n H': foralln'm' : nat,
n + n = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m')
NatBezout n n (nat_gcd n n)
rewrite nat_gcd_idem; exact _.
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m l: 0 < m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m p: 0 = m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m l: 0 < m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m l: 0 < m
NatBezout n m (nat_gcd m n)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m l: 0 < m
NatBezout m n (nat_gcd m n)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m l: 0 < m
n + m = m + n
apply nat_add_comm.
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n, m: nat q: n + m = k H: 0 < n H': foralln'm' : nat,
n + m = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > m p: 0 = m
NatBezout n m (nat_gcd n m)
k: nat IHk: forallm : nat,
m < k ->
forallnm0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0) n: nat q: n + 0 = k H: 0 < n H': foralln'm' : nat,
n + 0 = n' + m' ->
0 < n' ->
n' < m' -> NatBezout n' m' (nat_gcd n' m') r: n > 0
NatBezout n 0 (nat_gcd n 0)
rewrite nat_gcd_zero_r; exact _.Defined.(** For strictly positive numbers, we have Bezout's identity in both directions. *)
n, m: nat
0 < n ->
0 < m ->
NatBezout n m (nat_gcd n m) *
NatBezout m n (nat_gcd n m)
n, m: nat
0 < n ->
0 < m ->
NatBezout n m (nat_gcd n m) *
NatBezout m n (nat_gcd n m)
intros H1 H2; split; [| apply nat_bezout_comm]; exact _.Defined.(** For arbitrary natural numbers, we have Bezout's identity in at least one direction. *)
n, m: nat
(NatBezout n m (nat_gcd n m) +
NatBezout m n (nat_gcd n m))%type
n, m: nat
(NatBezout n m (nat_gcd n m) +
NatBezout m n (nat_gcd n m))%type
destruct n; [ right | left ]; exact _.Defined.(** ** Least common multiple *)(** The least common multiple [nat_lcm n m] is the smallest natural number divisibile by both [n] and [m]. *)Definitionnat_lcm (nm : nat) : nat := n * (m / nat_gcd n m).(** The least common multiple of [0] and [n] is [0]. *)Definitionnat_lcm_zero_ln : nat_lcm 0 n = 0 := idpath.(** The least common multiple of [n] and [0] is [0]. *)
n: nat
nat_lcm n 0 = 0
n: nat
nat_lcm n 0 = 0
n: nat
n * (0 / nat_gcd n 0) = 0
byrewrite nat_div_zero_l, nat_mul_zero_r.Defined.(** The least common multiple of [1] and [n] is [n]. *)
n: nat
nat_lcm 1 n = n
n: nat
nat_lcm 1 n = n
n: nat
1 * (n / nat_gcd 1 n) = n
byrewrite nat_gcd_one_l, nat_div_one_r, nat_mul_one_l.Defined.(** The least common multiple of [n] and [1] is [n]. *)
byrewrite nat_gcd_idem, nat_mul_div_cancel_l.Defined.(** [n] divides the least common multiple of [n] and [m]. *)Instancenat_divides_r_lcm_lnm : (n | nat_lcm n m) := _.(** [m] divides the least common multiple of [n] and [m]. *)
n, m: nat
(m | nat_lcm n m)
n, m: nat
(m | nat_lcm n m)
n, m: nat
(m | n * (m / nat_gcd n m))
n, m: nat
(m | (n * m) / nat_gcd n m)
rewrite <- nat_div_mul_r; exact _.Defined.(** The least common multiple of [n] and [m] divides any multiple of [n] and [m]. *)
n, m, k: nat
(n | k) -> (m | k) -> (nat_lcm n m | k)
n, m, k: nat
(n | k) -> (m | k) -> (nat_lcm n m | k)
n, m, k: nat H1: (n | k) H2: (m | k)
(nat_lcm n m | k)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n
(nat_lcm n m | k)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m
(nat_lcm n m | k)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m
(n * (m / nat_gcd n m) | k)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat p: a * n = nat_gcd n m + b * m
(n * (m / nat_gcd n m) | k)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat p: a * n - b * m = nat_gcd n m
(n * (m / nat_gcd n m) | k)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat p: a * n - b * m = nat_gcd n m
((n * m) / nat_gcd n m | k)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat p: a * n - b * m = nat_gcd n m
(nat_gcd n m | m)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat p: a * n - b * m = nat_gcd n m
((n * m) / nat_gcd n m | k)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat p: a * n - b * m = nat_gcd n m
(n * m | k * nat_gcd n m)
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat
(n * m | k * (a * n - b * m))
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat
(n * m | k * (a * n) - k * (b * m))
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat
(n * m | k * (a * n))
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat
(n * m | k * (b * m))
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat
(m * n | k * (a * n))
n, m, k: nat H1: (n | k) H2: (m | k) lt_n: 0 < n lt_m: 0 < m a, b: nat
(n * m | k * (b * m))
1,2: exact _.Defined.
n, m, k: nat
(n | k) * (m | k) <-> (nat_lcm n m | k)
n, m, k: nat
(n | k) * (m | k) <-> (nat_lcm n m | k)
n, m, k: nat
(n | k) * (m | k) -> (nat_lcm n m | k)
n, m, k: nat
(nat_lcm n m | k) -> (n | k) * (m | k)
n, m, k: nat
(n | k) * (m | k) -> (nat_lcm n m | k)
intros [H1 H2]; exact _.
n, m, k: nat
(nat_lcm n m | k) -> (n | k) * (m | k)
n, m, k: nat H: (nat_lcm n m | k)
(n | k)
n, m, k: nat H: (nat_lcm n m | k)
(m | k)
n, m, k: nat H: (nat_lcm n m | k)
(n | k)
rapply (nat_divides_trans _ H).
n, m, k: nat H: (nat_lcm n m | k)
(m | k)
exact _.Defined.(** If [k] divides all common multiples of [n] and [m], and [k] is also a common multiple, then it must necessarily be equal to the least common multiple. *)
n, m, k: nat H: forallq : nat, (n | q) -> (m | q) -> (k | q)
(n | k) -> (m | k) -> nat_lcm n m = k
n, m, k: nat H: forallq : nat, (n | q) -> (m | q) -> (k | q)
rapply nat_divides_antisym.Defined.(** As a corollary of uniqueness, we get that the least common multiple operation is commutative. *)
n, m: nat
nat_lcm n m = nat_lcm m n
n, m: nat
nat_lcm n m = nat_lcm m n
rapply nat_lcm_unique.Defined.(** [nat_lcm] is associative. *)
n, m, k: nat
nat_lcm n (nat_lcm m k) = nat_lcm (nat_lcm n m) k
n, m, k: nat
nat_lcm n (nat_lcm m k) = nat_lcm (nat_lcm n m) k
n, m, k: nat
forallq : nat,
(n | q) ->
(nat_lcm m k | q) -> (nat_lcm (nat_lcm n m) k | q)
n, m, k, q: nat H1: (n | q) H2: (nat_lcm m k | q)
(nat_lcm (nat_lcm n m) k | q)
n, m, k, q: nat H1: (n | q) H2: (nat_lcm m k | q)
(nat_lcm n m | q)
n, m, k, q: nat H1: (n | q) H2: (nat_lcm m k | q)
(m | q)
rapply (nat_divides_trans _ H2).Defined.(** ** Prime Numbers *)(** A prime number is a number greater than [1] that is only divisible by [1] and itself. *)ClassIsPrime (n : nat) : Type0 := {
gt_one_isprime :: 1 < n;
isprime : forallm, (m | n) -> (m = 1) + (m = n);
}.Definitionissig_IsPrimen : _ <~> IsPrime n := ltac:(issig).
H: Funext n: nat H1: 1 < n m: nat d: (m | n) p: m = 1 q: m = n
Empty
H: Funext n: nat H1: 1 < n m: nat d: (m | n) p: m = 1 q: m = n
((1 < n) + (1 > n))%type
byleft.Defined.(** [0] is not a prime number. *)
~ IsPrime 0
~ IsPrime 0
H: IsPrime 0
Empty
rapply not_lt_zero_r.Defined.(** [1] is not a prime number. *)
~ IsPrime 1
~ IsPrime 1
H: IsPrime 1
Empty
rapply (lt_irrefl 1).Defined.(** Being prime is a decidable property. We give an inefficient procedure for determining primality. More efficient procedures can be given, but for proofs this suffices. *)
n: nat
Decidable (IsPrime n)
n: nat
Decidable (IsPrime n)
(** First we begin by discarding the [n = 0] case as we can easily prove that [0] is not prime. *)
Decidable (IsPrime 0)
n: nat
Decidable (IsPrime n.+1)
n: nat
Decidable (IsPrime n.+1)
(** Next, we rewrite [IsPrime n.+1] as the equivalent sigma type. *)
(** In order to show that this [forall] is decidable, we will exhibit it as a [for_all] statement over a given list. The predicate will be the conclusion we wish to reach here, and the list will consist of all numbers with a condition equivalent to the divisibility condition. *)
rapply H.Defined.(** We can show that the first 8 primes are prime as expected. *)Instanceisprime_2 : IsPrime 2 := ltac:(decide).Instanceisprime_3 : IsPrime 3 := ltac:(decide).Instanceisprime_5 : IsPrime 5 := ltac:(decide).Instanceisprime_7 : IsPrime 7 := ltac:(decide).Instanceisprime_11 : IsPrime 11 := ltac:(decide).Instanceisprime_13 : IsPrime 13 := ltac:(decide).Instanceisprime_17 : IsPrime 17 := ltac:(decide).Instanceisprime_19 : IsPrime 19 := ltac:(decide).(** Similarly, we can see that other natural numbers are not prime. *)Definitionnot_isprime_0 : not (IsPrime 0) := ltac:(decide).Definitionnot_isprime_1 : not (IsPrime 1) := ltac:(decide).Definitionnot_isprime_4 : not (IsPrime 4) := ltac:(decide).(** We can define the type of prime numbers as a subtype of natural numbers. *)DefinitionPrime : Type0 := {n : nat & IsPrime n}.Coercionnat_of_prime (p : Prime) : nat := p.1.Instanceisprime_prime (p : Prime) : IsPrime p := p.2.Instancelt_zero_prime (p : Prime) : 0 < p
:= lt_trans _ gt_one_isprime.(** A prime [p] is coprime to a natural number [n] iff [p] does not divide [n]. *)
p: Prime n: nat
nat_gcd p n = 1 <-> ~ (p | n)
p: Prime n: nat
nat_gcd p n = 1 <-> ~ (p | n)
p: Prime n: nat
nat_gcd p n = 1 -> ~ (p | n)
p: Prime n: nat
~ (p | n) -> nat_gcd p n = 1
p: Prime n: nat
nat_gcd p n = 1 -> ~ (p | n)
p: Prime n: nat q: nat_gcd p n = 1 d: nat r: d * p = n
p: Prime n: nat nd: ~ (p | n) q: nat H1: q = p H2: (q | n)
(q | 1)
destruct H1; contradiction.Defined.(** When a prime number divides a multiple, then the prime must divide one of the factors. *)
p: Prime n, m: nat
(p | n * m) -> (p | n) + (p | m)
p: Prime n, m: nat
(p | n * m) -> (p | n) + (p | m)
p: Prime n, m: nat d: (p | n * m)
((p | n) + (p | m))%type
p: Prime n, m: nat d: (p | n * m) H: (p | n)
((p | n) + (p | m))%type
p: Prime n, m: nat d: (p | n * m) H: ~ (p | n)
((p | n) + (p | m))%type
p: Prime n, m: nat d: (p | n * m) H: ~ (p | n)
((p | n) + (p | m))%type
p: Prime n, m: nat d: (p | n * m) H: ~ (p | n)
(p | m)
p: Prime n, m: nat d: (p | n * m) H: nat_gcd p n = 1
(p | m)
p: Prime n, m: nat d: (p | n * m) H: nat_gcd p n = 1 x, y: nat q: x * p = nat_gcd p n + y * n
(p | m)
p: Prime n, m: nat d: (p | n * m) x, y: nat q: x * p = 1 + y * n
(p | m)
p: Prime n, m, d: nat r: d * p = n * m x, y: nat q: x * p = 1 + y * n
(p | m)
p: Prime n, m, d: nat r: d * p = n * m x, y: nat q: x * p = 1 + y * n
(x * m - y * d) * p = m
p: Prime n, m, d: nat r: d * p = n * m x, y: nat q: x * p = 1 + y * n
x * m * p - y * d * p = m
p: Prime n, m, d: nat r: d * p = n * m x, y: nat q: x * p = 1 + y * n
x * (m * p) - y * (d * p) = m
p: Prime n, m, d: nat r: d * p = n * m x, y: nat q: x * p = 1 + y * n
x * (p * m) - y * (d * p) = m
p: Prime n, m, d, x, y: nat q: x * p = 1 + y * n
x * (p * m) - y * (n * m) = m
p: Prime n, m, d, x, y: nat q: x * p = 1 + y * n
x * p * m - y * n * m = m
p: Prime n, m, d, x, y: nat q: x * p = 1 + y * n
(x * p - y * n) * m = m
p: Prime n, m, d, x, y: nat q: x * p = 1 + y * n
(x * p - y * n) * m = 1 * m
p: Prime n, m, d, x, y: nat q: x * p = 1 + y * n
x * p - y * n = 1
p: Prime n, m, d, x, y: nat q: x * p = 1 + y * n
x * p = 1 + y * n
exact q.Defined.(** ** Composite Numbers *)(** A natural number larger than [1] is composite if it has a divisor other than [1] and itself. *)ClassIsCompositen : Type0
:= iscomposite : existsa, 1 < a < n /\ (a | n).
n: nat
IsComposite n -> 1 < n
n: nat
IsComposite n -> 1 < n
n, a: nat H1: 1 < a H2: a < n H3: (a | n)
1 < n
exact _.Defined.Hint Immediate gt_1_iscomposite : typeclass_instances.(** Being composite is a decidable property. *)
n: nat
Decidable (IsComposite n)
n: nat
Decidable (IsComposite n)
n: nat
Decidable {a : nat & ((1 < a < n) * (a | n))%type}
n: nat
forallk : nat, (1 < k < n) * (k | n) -> k < n
n, k: nat c: ((1 < k < n) * (k | n))%type
k < n
exact (snd (fst c)).Defined.(** For a number larger than [1], being prime is equivalent to not being composite. *)
n: nat
IsPrime n <-> (1 < n) * ~ IsComposite n
n: nat
IsPrime n <-> (1 < n) * ~ IsComposite n
n: nat
IsPrime n -> (1 < n) * ~ IsComposite n
n: nat
(1 < n) * ~ IsComposite n -> IsPrime n
n: nat
IsPrime n -> (1 < n) * ~ IsComposite n
n: nat H: IsPrime n
((1 < n) * ~ IsComposite n)%type
n: nat H: IsPrime n
~ IsComposite n
n: nat H: IsPrime n a: nat H2: 1 < a H3: a < n H4: (a | n)
Empty
n: nat H: IsPrime n a: nat H2: 1 < a H3: a < n H4: ((a = 1) + (a = n))%type
Empty
destruct H4 as [H4|H4]; destruct H4; exact (lt_irrefl _ _).
n: nat
(1 < n) * ~ IsComposite n -> IsPrime n
n: nat H1: 1 < n H: ~ IsComposite n
IsPrime n
n: nat H1: 1 < n H: ~ IsComposite n
forallm : nat, (m | n) -> (m = 1) + (m = n)
n: nat H1: 1 < n H: ~ IsComposite n m: nat d: (m | n)
((m = 1) + (m = n))%type
n: nat H1: 1 < n H: ~ IsComposite n m: nat d: (m | n) H2: 1 < d.1
n: nat H1: 1 < n H: ~ IsComposite n m, d: nat r: d.+1 * m = n H2: d.+1 <= 1
((m = 1) + (m = n))%type
n: nat H1: 1 < n H: ~ IsComposite n m: nat r: 1 * m = n H2: 1 <= 1
((m = 1) + (m = n))%type
n: nat H1: 1 < n H: ~ IsComposite n m, d: nat r: d.+2 * m = n H2: d.+2 <= 1
((m = 1) + (m = n))%type
n: nat H1: 1 < n H: ~ IsComposite n m: nat r: 1 * m = n H2: 1 <= 1
((m = 1) + (m = n))%type
n: nat H1: 1 < n H: ~ IsComposite n m: nat r: m = n H2: 1 <= 1
((m = 1) + (m = n))%type
byright.
n: nat H1: 1 < n H: ~ IsComposite n m, d: nat r: d.+2 * m = n H2: d.+2 <= 1
((m = 1) + (m = n))%type
n: nat H1: 1 < n H: ~ IsComposite n m, d: nat r: d.+2 * m = n H2: d.+1 <= 0
((m = 1) + (m = n))%type
contradiction (not_lt_zero_r d).Defined.(** And since [IsComposite] is decidable, we can show that being not prime is equivalent to being composite. *)
exact _.Defined.(** ** Fundamental theorem of arithmetic *)(** Every natural number greater than [1] has a prime divisor. *)
n: nat
1 < n -> {p : Prime & (p | n)}
n: nat
1 < n -> {p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n
{p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n x: IsPrime n
{p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n x: ~ IsPrime n
{p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n x: ~ IsPrime n
{p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n x: ~ IsPrime n r:= (H, x): ((1 < n) * ~ IsPrime n)%type
{p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n x: ~ IsPrime n r: IsComposite n
{p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n x: ~ IsPrime n d: nat H1: 1 < d H2: d < n H3: (d | n)
{p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n x: ~ IsPrime n d: nat H1: 1 < d H2: d < n H3: (d | n) p: Prime r: (p | d)
{p : Prime & (p | n)}
n: nat IHn: forallm : nat, m < n -> 1 < m -> {p : Prime & (p | m)} H: 1 < n x: ~ IsPrime n d: nat H1: 1 < d H2: d < n H3: (d | n) p: Prime r: (p | d)
(p | n)
exact _.Defined.(** Any natural number can either be written as a product of primes or is zero. *)
n: nat
0 < n ->
{l : list Prime &
n =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat
0 < n ->
{l : list Prime &
n =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} H: 0 < n
{l : list Prime &
n =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
IHn: forallm : nat,
m < 1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
{l : list Prime &
1 =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n
{l : list Prime &
n.+1 =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n
{l : list Prime &
n.+1 =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime d: (p | n.+1)
{l : list Prime &
n.+1 =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime d: (p | n.+1) l: d.1 < n.+1
{l : list Prime &
n.+1 =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1
{l : list Prime &
n.+1 =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1
0 < k
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1 f: list Prime r: k =
fold_right (fun (p : Prime) (n : nat) => p * n) 1
f
{l : list Prime &
n.+1 =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1
0 < k
n: nat p: Prime IHn: forallm : nat,
m < 0 * p ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n l: (0; 1).1 < 0 * p
0 < 0
n: nat p: Prime k: nat IHn: forallm : nat,
m < k.+1 * p ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n l: (k.+1; 1).1 < k.+1 * p
0 < k.+1
n: nat p: Prime k: nat IHn: forallm : nat,
m < k.+1 * p ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n l: (k.+1; 1).1 < k.+1 * p
0 < k.+1
exact _.
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1 f: list Prime r: k =
fold_right (fun (p : Prime) (n : nat) => p * n) 1
f
{l : list Prime &
n.+1 =
fold_right (fun (p : Prime) (n : nat) => p * n) 1 l}
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1 f: list Prime r: k =
fold_right (fun (p : Prime) (n : nat) => p * n) 1
f
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1 f: list Prime
n.+1 = p * k
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1 f: list Prime
p * k = n.+1
n: nat IHn: forallm : nat,
m < n.+1 ->
0 < m ->
{l : list Prime & m = fold_right (fun (p : Prime) (n : nat) => p * n) 1 l} IH: 1 <= n p: Prime k: nat H: k * p = n.+1 l: (k; H).1 < n.+1 f: list Prime
k * p = n.+1
exact H.Defined.(** TODO: show that any two prime factorizations are unique up to permutation of the lists. *)