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. Local Open Scope nat_scope. (** * Division of natural numbers *) (** ** Divisibility *) (** We define divisibility as a relation between natural numbers. *) Class NatDivides (n m : nat) : Type0 := nat_divides : {k : nat & k * n = m}. Notation "( n | m )" := (NatDivides n m) : nat_scope. (** Any number divides [0]. *) Instance nat_divides_zero_r n : (n | 0) := (0; idpath). (** [1] divides any number. *) Instance nat_divides_one_l n : (1 | n) := (n; nat_mul_one_r _). (** Any number divides itself. Divisibility is a reflexive relation. *) Instance nat_divides_refl n : (n | n) := (1; nat_mul_one_l _). Instance reflexive_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. Instance transitive_nat_divides : Transitive NatDivides := @nat_divides_trans. (** A left factor divides a product. *) Instance nat_divides_mul_l' n m : (n | n * m) := (m; nat_mul_comm _ _). (** A right factor divides a product. *) Instance nat_divides_mul_r' n m : (m | n * m) := (n; idpath). (** Divisibility of the product is implied by divisibility of the left factor. *) Instance nat_divides_mul_l {n m} l : (n | m) -> (n | m * l) := fun H => nat_divides_trans _ _. (** Divisibility of the product is implied by divisibility of the right factor. *) Instance nat_divides_mul_r {n m} l : (n | m) -> (n | l * m) := fun H => 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. Instance antisymmetric_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
by apply 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
by apply 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
by contradiction (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

forall x y : (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

let q' := fst (nat_div_mod x y q u) in let u' := 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

let q' := fst (nat_div_mod x y q u) in let u' := 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.+1 * q + (y - u))%nat = (y.+1 * d + (y - r))%nat) * (r <= y))%type
x, y, q, u: nat
H: u <= y
d:= fst (nat_div_mod x.+1 y q u): nat
r:= snd (nat_div_mod x.+1 y q u): nat
IHx: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := snd (nat_div_mod x y q u) in (x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y)

(((x.+1 + y.+1 * q + (y - u))%nat = (y.+1 * d + (y - r))%nat) * (r <= y))%type
x, y, q: nat
H: 0 <= y
d:= fst (nat_div_mod x.+1 y q 0): nat
r:= snd (nat_div_mod x.+1 y q 0): nat
IHx: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := snd (nat_div_mod x y q u) in (x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y)

(((x.+1 + y.+1 * q + (y - 0))%nat = (y.+1 * d + (y - r))%nat) * (r <= y))%type
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: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := snd (nat_div_mod x y q u) in (x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y)
(((x.+1 + y.+1 * q + (y - u.+1))%nat = (y.+1 * d + (y - r))%nat) * (r <= y))%type
x, y, q: nat
H: 0 <= y
d:= fst (nat_div_mod x.+1 y q 0): nat
r:= snd (nat_div_mod x.+1 y q 0): nat
IHx: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := snd (nat_div_mod x y q u) in (x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y)

(((x.+1 + y.+1 * q + (y - 0))%nat = (y.+1 * d + (y - r))%nat) * (r <= y))%type
x, y, q: nat
H: 0 <= y
d:= fst (nat_div_mod x.+1 y q 0): nat
r:= snd (nat_div_mod x.+1 y q 0): nat
IHx: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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.+1 + (y - y) = y.+1 * fst (nat_div_mod x y q.+1 y) + (y - snd (nat_div_mod x y q.+1 y))
H': snd (nat_div_mod x y q.+1 y) <= y

(((x.+1 + y.+1 * q + (y - 0))%nat = (y.+1 * d + (y - r))%nat) * (r <= y))%type
x, y, q: nat
H: 0 <= y
d:= fst (nat_div_mod x.+1 y q 0): nat
r:= snd (nat_div_mod x.+1 y q 0): nat
IHx: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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.+1 + (y - y) = y.+1 * fst (nat_div_mod x y q.+1 y) + (y - snd (nat_div_mod x y q.+1 y))
H': snd (nat_div_mod x y q.+1 y) <= y

x.+1 + y.+1 * q + (y - 0) = y.+1 * d + (y - r)
x, y, q: nat
H: 0 <= y
d:= fst (nat_div_mod x.+1 y q 0): nat
r:= snd (nat_div_mod x.+1 y q 0): nat
IHx: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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.+1 + (y - y) = y.+1 * fst (nat_div_mod x y q.+1 y) + (y - snd (nat_div_mod x y q.+1 y))
H': snd (nat_div_mod x y q.+1 y) <= y

x.+1 + y.+1 * q + y = x + y.+1 * q.+1
x, y, q: nat
H: 0 <= y
d:= fst (nat_div_mod x.+1 y q 0): nat
r:= snd (nat_div_mod x.+1 y q 0): nat
IHx: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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.+1 + (y - y) = y.+1 * fst (nat_div_mod x y q.+1 y) + (y - snd (nat_div_mod x y q.+1 y))
H': snd (nat_div_mod x y q.+1 y) <= y

(x + (q + y * q) + y).+1 = x + (q + y * q.+1).+1
by rewrite nat_add_succ_r, <- 2 nat_add_assoc, nat_mul_succ_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: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := snd (nat_div_mod x y q u) in (x + y.+1 * q + (y - u) = y.+1 * d + (y - r)) * (r <= y)

(((x.+1 + y.+1 * q + (y - u.+1))%nat = (y.+1 * d + (y - r))%nat) * (r <= y))%type
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: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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))%nat = (y.+1 * d + (y - r))%nat) * (r <= y))%type
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: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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: forall y q u : nat, u <= y -> let d := fst (nat_div_mod x y q u) in let r := 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
by rewrite 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]. *) Instance nat_mod_lt_r n m : 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. *) Definition nat_div_unique x y q r (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. *) Definition nat_mod_unique x y q r (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
by induction n. Defined. (** [n] divided by [0] is [0] by convention. *) Definition nat_div_zero_r n : 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
by rewrite 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 (fun x => 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 (fun n : nat => n * k)
k: nat

0 < k -> IsInjective (fun n : 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 (fun x => 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]. *) Definition nat_mod_zero_r n : 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
by induction 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
by rewrite 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. *) Definition nat_gcd_zero_l n : 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
by rewrite nat_sub_cancel. Defined. (** The greatest common divisor of [1] and any number is [1]. *) Definition nat_gcd_one_l n : 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.+1 1 = 1
n: nat

nat_gcd (n - snd match n with | 0 => (1, n) | u'.+1 => (0, u') end) n.+1 = 1
n: nat

nat_gcd (n.+1 - snd (0, n)) n.+2 = 1
n: nat

nat_gcd (n - snd (0, n)).+1 n.+2 = 1
by rewrite nat_sub_cancel. Defined. (** Idempotency. *)
n: nat

nat_gcd n n = n
n: nat

nat_gcd n n = n

nat_gcd 0 0 = 0
n: nat
IHn: nat_gcd n n = n
nat_gcd n.+1 n.+1 = n.+1
n: nat
IHn: nat_gcd n n = n

nat_gcd n.+1 n.+1 = n.+1
n: nat
IHn: nat_gcd n n = n

nat_gcd (n.+1 mod n.+1) n.+1 = n.+1
by rewrite 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: forall m : nat, m < n -> (fun n : nat => forall m0 : 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: forall m : nat, m < 0 -> forall m0 : 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: forall m : nat, m < n.+1 -> forall m0 : 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: forall m : nat, m < n.+1 -> forall m0 : 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: forall m : nat, m < n.+1 -> forall m0 : 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: forall m : nat, m < n.+1 -> forall m0 : 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: forall m : nat, m < n' -> forall m0 : 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: forall m : nat, m < n' -> forall m0 : 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: forall m : nat, m < n' -> forall m0 : 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]. *) Instance nat_divides_l_gcd_l n m : (nat_gcd n m | n) := fst (nat_divides_l_gcd n m). (** The greatest common divisor of [n] and [m] divides [m]. *) Instance divides_l_nat_gcd_r n m : (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: forall m : nat, m < n -> (fun n : nat => forall m0 p : 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: forall m : nat, m < n.+1 -> forall m0 p : 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: forall m : nat, m < n.+1 -> forall m0 p : 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: forall m : nat, m < n.+1 -> forall m0 p : 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: forall m : nat, m < n.+1 -> forall m0 p : 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: forall q : nat, (q | n) -> (q | m) -> (q | p)

(p | n) -> (p | m) -> nat_gcd n m = p
n, m, p: nat
H: forall q : nat, (q | n) -> (q | m) -> (q | p)

(p | n) -> (p | m) -> nat_gcd n m = p
n, m, p: nat
H: forall q : 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. *)
n, m, k: nat

nat_gcd n (nat_gcd m k) = nat_gcd (nat_gcd n m) k
n, m, k: nat

nat_gcd n (nat_gcd m k) = nat_gcd (nat_gcd n m) k
n, m, k: nat

(nat_gcd (nat_gcd n m) k | n)
n, m, k: nat
(nat_gcd (nat_gcd n m) k | nat_gcd m k)
n, m, k: nat

(nat_gcd (nat_gcd n m) k | n)
rapply (nat_divides_trans (nat_divides_l_gcd_l _ _)).
n, m, k: nat

(nat_gcd (nat_gcd n m) k | nat_gcd m k)
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
by apply (nat_gcd_is_zero_l _ m).
n, m: nat
H: nat_gcd n m = 0

m = 0
by apply (nat_gcd_is_zero_r n).
n, m: nat

(n = 0) * (m = 0) -> nat_gcd n m = 0

nat_gcd 0 0 = 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

forall q : 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
by rewrite 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
by rewrite (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. *) Definition NatBezout n m d : Type0 := exists a b, a * n = d + b * m. Existing Class NatBezout.
n, k: nat

NatBezout n k n
n, k: nat

NatBezout n k n
by exists 1, 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

forall q : 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

d = 0
by destruct p. Defined. Hint Immediate nat_bezout_comm : typeclass_instances.
n, m: nat

0 < n -> NatBezout n m (nat_gcd n m)
n, m: nat

0 < n -> NatBezout n m (nat_gcd n m)
n, m, k: nat
p: n + m = k

0 < n -> NatBezout n m (nat_gcd n m)
k: nat
IHk: forall m : nat, m < k -> forall n m0 : 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n

forall n' m' : nat, n + m = n' + m' -> 0 < n' -> n' < m' -> NatBezout n' m' (nat_gcd n' m')
k: nat
IHk: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n

forall n' m' : nat, n + m = n' + m' -> 0 < n' -> n' < m' -> NatBezout n' m' (nat_gcd n' m')
n, m: nat
IHk: forall m0 : nat, m0 < n + m -> forall n m : 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: forall m0 : nat, m0 < n + m -> forall n m : 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: forall m0 : nat, m0 < n + m -> forall n m : 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: forall m0 : nat, m0 < n + m -> forall n m : 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: forall m0 : nat, m0 < n + m -> forall n m : 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: forall m0 : nat, m0 < n + m -> forall n m : 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: forall m0 : nat, m0 < n + m -> forall n m : 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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)
by apply H'.
k: nat
IHk: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n: nat
q: n + n = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n, m: nat
q: n + m = k
H: 0 < n
H': forall n' 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: forall m : nat, m < k -> forall n m0 : nat, n + m0 = m -> 0 < n -> NatBezout n m0 (nat_gcd n m0)
n: nat
q: n + 0 = k
H: 0 < n
H': forall n' 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]. *) Definition nat_lcm (n m : nat) : nat := n * (m / nat_gcd n m). (** The least common multiple of [0] and [n] is [0]. *) Definition nat_lcm_zero_l n : 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
by rewrite 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
by rewrite nat_gcd_one_l, nat_div_one_r, nat_mul_one_l. Defined. (** The least common multiple of [n] and [1] is [n]. *)
n: nat

nat_lcm n 1 = n
n: nat

nat_lcm n 1 = n
n: nat

n * (1 / nat_gcd n 1) = n
by rewrite nat_gcd_one_r, nat_div_one_r, nat_mul_one_r. Defined. (** Idempotency. *)
n: nat

nat_lcm n n = n
n: nat

nat_lcm n n = n
n: nat

n * (n / nat_gcd n n) = n
by rewrite nat_gcd_idem, nat_mul_div_cancel_l. Defined. (** [n] divides the least common multiple of [n] and [m]. *) Instance nat_divides_r_lcm_l n m : (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: forall q : nat, (n | q) -> (m | q) -> (k | q)

(n | k) -> (m | k) -> nat_lcm n m = k
n, m, k: nat
H: forall q : nat, (n | q) -> (m | q) -> (k | q)

(n | k) -> (m | k) -> nat_lcm n m = k
n, m, k: nat
H: forall q : nat, (n | q) -> (m | q) -> (k | q)
H1: (n | k)
H2: (m | k)

nat_lcm n m = k
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

forall q : 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. *) Class IsPrime (n : nat) : Type0 := { gt_one_isprime :: 1 < n; isprime : forall m, (m | n) -> (m = 1) + (m = n); }. Definition issig_IsPrime n : _ <~> IsPrime n := ltac:(issig).
H: Funext
n: nat

IsHProp (IsPrime n)
H: Funext
n: nat

IsHProp (IsPrime n)
H: Funext
n: nat

?Goal <~> IsPrime n
H: Funext
n: nat
IsHProp ?Goal
H: Funext
n: nat

IsHProp {_ : 1 < n & forall m : nat, (m | n) -> (m = 1) + (m = n)}
H: Funext
n: nat

1 < n -> IsHProp (forall m : nat, (m | n) -> (m = 1) + (m = n))
H: Funext
n: nat
H1: 1 < n

IsHProp (forall m : nat, (m | n) -> (m = 1) + (m = n))
H: Funext
n: nat
H1: 1 < n

forall a : nat, IsHProp ((fun a0 : nat => (a0 | n) -> (a0 = 1) + (a0 = n)) a)
H: Funext
n: nat
H1: 1 < n
m: nat

IsHProp ((fun a : nat => (a | n) -> (a = 1) + (a = n)) m)
H: Funext
n: nat
H1: 1 < n
m: nat

forall a : (m | n), IsHProp ((fun _ : (m | n) => ((m = 1) + (m = n))%type) a)
H: Funext
n: nat
H1: 1 < n
m: nat
d: (m | n)

IsHProp ((fun _ : (m | n) => ((m = 1) + (m = n))%type) d)
H: Funext
n: nat
H1: 1 < n
m: nat
d: (m | n)

m = 1 -> m = n -> Empty
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
by left. 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. *)
n: nat

?Goal <~> IsPrime n.+1
n: nat
Decidable ?Goal
n: nat

Decidable {_ : 1 < n.+1 & forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)}
(** The condition in the first component in [IsPrime] is clearly decidable, so we can proceed to the second component. *)
n: nat

?Goal <~> {_ : 1 < n.+1 & forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)}
n: nat
Decidable ?Goal
n: nat

Decidable ((1 < n.+1) * (forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)))
n: nat

Decidable (1 < n.+1)
n: nat
Decidable (forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1))
n: nat

Decidable (forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1))
(** 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. *)
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0

Decidable (forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1))
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat

Decidable (forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1))
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat

for_all P l <-> (forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1))
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat

for_all P l -> forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
(forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)) -> for_all P l
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat

for_all P l -> forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
Pl: for_all P l
x: nat
d: (x | n.+1)

((x = 1) + (x = n.+1))%type
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
x: nat
Pl: P x
d: (x | n.+1)

((x = 1) + (x = n.+1))%type
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
Pl: for_all P l
x: nat
d: (x | n.+1)
InList x l
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
Pl: for_all P l
x: nat
d: (x | n.+1)

InList x l
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
Pl: for_all P l
x: nat
d: (x | n.+1)

(InList x (seq n.+2) * (x | n.+1))%type
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
Pl: for_all P l
x: nat
d: (x | n.+1)

InList x (seq n.+2)
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
Pl: for_all P l
x: nat
d: (x | n.+1)

x < n.+2
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
Pl: for_all P l
x: nat
d: x <= n.+1

x < n.+2
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
Pl: for_all P l
x: nat
d: (x | n.+1)
0 < n.+1
1,2: exact _.
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat

(forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)) -> for_all P l
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
H: forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)

for_all P l
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
H: forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)

forall x : nat, InList x l -> P x
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
H: forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)
x: nat
H': InList x l

P x
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
H: forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)
x: nat
H': (InList x (seq n.+2) * (x | n.+1))%type

P x
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
H: forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)
x: nat
p: InList x (seq n.+2)
H': (x | n.+1)

P x
n: nat
P:= fun m : nat => (m = 1) + (m = n.+1) : Type0: nat -> Type0
l:= list_filter (seq n.+2) (fun x : nat => (x | n.+1)) (fun x : nat => decidable_nat_divides x n.+1): list nat
H: forall m : nat, (m | n.+1) -> (m = 1) + (m = n.+1)
x: nat
p: x < n.+2
H': (x | n.+1)

P x
rapply H. Defined. (** We can show that the first 8 primes are prime as expected. *) Instance isprime_2 : IsPrime 2 := ltac:(decide). Instance isprime_3 : IsPrime 3 := ltac:(decide). Instance isprime_5 : IsPrime 5 := ltac:(decide). Instance isprime_7 : IsPrime 7 := ltac:(decide). Instance isprime_11 : IsPrime 11 := ltac:(decide). Instance isprime_13 : IsPrime 13 := ltac:(decide). Instance isprime_17 : IsPrime 17 := ltac:(decide). Instance isprime_19 : IsPrime 19 := ltac:(decide). (** Similarly, we can see that other natural numbers are not prime. *) Definition not_isprime_0 : not (IsPrime 0) := ltac:(decide). Definition not_isprime_1 : not (IsPrime 1) := ltac:(decide). Definition not_isprime_4 : not (IsPrime 4) := ltac:(decide). (** We can define the type of prime numbers as a subtype of natural numbers. *) Definition Prime : Type0 := {n : nat & IsPrime n}. Coercion nat_of_prime (p : Prime) : nat := p.1. Instance isprime_prime (p : Prime) : IsPrime p := p.2. Instance lt_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

Empty
p: Prime
d: nat
q: nat_gcd p (d * p) = 1

Empty
p: Prime
d: nat
q: nat_gcd p 0 = 1

Empty
p: Prime
d: nat
q: p = 1

Empty
p: Prime
d: nat
q: p = 1

((p < 1) + (p > 1))%type
p: Prime
d: nat
q: p = 1
p = 1
p: Prime
d: nat
q: p = 1

p = 1
exact q.
p: Prime
n: nat

~ (p | n) -> nat_gcd p n = 1
p: Prime
n: nat
nd: ~ (p | n)

nat_gcd p n = 1
p: Prime
n: nat
nd: ~ (p | n)

forall q : nat, (q | p) -> (q | n) -> (q | 1)
p: Prime
n: nat
nd: ~ (p | n)
q: nat
H1: (q | p)
H2: (q | n)

(q | 1)
p: Prime
n: nat
nd: ~ (p | n)
q: nat
H1: ((q = 1) + (q = p))%type
H2: (q | n)

(q | 1)
p: Prime
n: nat
nd: ~ (p | n)
q: nat
H1: q = 1
H2: (q | n)

(q | 1)
p: Prime
n: nat
nd: ~ (p | n)
q: nat
H1: q = p
H2: (q | n)
(q | 1)
p: Prime
n: nat
nd: ~ (p | n)
q: nat
H1: q = 1
H2: (q | n)

(q | 1)
destruct H1; exact _.
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. *) Class IsComposite n : Type0 := iscomposite : exists a, 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

forall k : 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

forall m : 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

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: ~ (1 < d.1)
((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': (d.1 | n)

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 <= n

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': (d.1 | n)
0 < n
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 <= n

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': ((d.1 < n) + (d.1 = n))%type

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 < n

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 = n
((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 < n

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 < n

IsComposite n
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 < n
H': IsComposite n
((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 < n

IsComposite n
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 < n

((1 < d.1 < n) * (d.1 | n))%type
split; only 1: split; exact _.
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 < n
H': IsComposite n

((m = 1) + (m = n))%type
contradiction H.
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 < d.1
d': d.1 = n

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m, d: nat
r: d * m = n
H2: 1 < (d; r).1
d': (d; r).1 = n

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m, d: nat
r: d * m = n
H2: 1 < d
d': d = n

((m = 1) + (m = n))%type
d, m: nat
r: d * m = d
H1: 1 < d
H: ~ IsComposite d
H2: 1 < d

((m = 1) + (m = d))%type
d, m: nat
r: d * m = d
H1: 1 < d
H: ~ IsComposite d
H2: 1 < d

m = 1
d, m: nat
r: d * m = d
H1: 1 < d
H: ~ IsComposite d
H2: 1 < d

m = d / d
d, m: nat
r: d * m = d
H1: 1 < d
H: ~ IsComposite d
H2: 1 < d
0 < d
d, m: nat
r: d * m = d
H1: 1 < d
H: ~ IsComposite d
H2: 1 < d

m = d / d
d, m: nat
r: d * m = d
H1: 1 < d
H: ~ IsComposite d
H2: 1 < d

(d * m) / d = d / d
d, m: nat
r: d * m = d
H1: 1 < d
H: ~ IsComposite d
H2: 1 < d
0 < d
d, m: nat
r: d * m = d
H1: 1 < d
H: ~ IsComposite d
H2: 1 < d

(d * m) / d = d / d
by apply (ap (fun x => x / d)).
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: ~ (1 < d.1)

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
d: (m | n)
H2: 1 >= d.1

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m, d: nat
r: d * m = n
H2: 1 >= (d; r).1

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m, d: nat
r: d * m = n
H2: d <= 1

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
r: 0 * m = n
H2: 0 <= 1

((m = 1) + (m = n))%type
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: 0 * m = n
H2: 0 <= 1

((m = 1) + (m = n))%type
n: nat
H1: 1 < n
H: ~ IsComposite n
m: nat
r: 0 = n
H2: 0 <= 1

((m = 1) + (m = n))%type
H1: 1 < 0
H: ~ IsComposite 0
m: nat
r: 0 = 0
H2: 0 <= 1

((m = 1) + (m = 0))%type
n: nat
H1: 1 < n.+1
H: ~ IsComposite n.+1
m: nat
r: 0 = n.+1
H2: 0 <= 1
((m = 1) + (m = n.+1))%type
n: nat
H1: 1 < n.+1
H: ~ IsComposite n.+1
m: nat
r: 0 = n.+1
H2: 0 <= 1

((m = 1) + (m = n.+1))%type
contradiction (neq_nat_zero_succ _ r).
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
by right.
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. *)
n: nat

(1 < n) * ~ IsPrime n <-> IsComposite n
n: nat

(1 < n) * ~ IsPrime n <-> IsComposite n
n: nat

(1 < n) * ~ IsPrime n <-> ?Goal
n: nat
?Goal <-> IsComposite n
n: nat

(1 < n) * ~ IsPrime n <-> ?Goal
n: nat

1 < n <-> ?Goal0
n: nat
~ IsPrime n <-> ?Goal1
n: nat

~ IsPrime n <-> ?Goal0
n: nat

~ IsPrime n <-> ?Goal1
n: nat
?Goal1 <-> ?Goal0
n: nat

~ IsPrime n <-> ?Goal1
n: nat

IsPrime n <-> ?B
rapply isprime_iff_not_iscomposite.
n: nat

~ ((1 < n) * ~ IsComposite n) <-> ?Goal0
rapply iff_not_prod.
n: nat

(1 < n) * (~ (1 < n) + ~~ IsComposite n) <-> IsComposite n
n: nat

(1 < n) * (~ (1 < n) + ~~ IsComposite n) <-> ?Goal
n: nat
?Goal <-> IsComposite n
n: nat

(1 < n) * ~ (1 < n) + (1 < n) * ~~ IsComposite n <-> IsComposite n
n: nat

(1 < n) * ~ (1 < n) + (1 < n) * ~~ IsComposite n <-> ?Goal
n: nat
?Goal <-> IsComposite n
n: nat

(1 < n) * ~ (1 < n) + (1 < n) * ~~ IsComposite n <-> ?Goal
n: nat

(1 < n) * ~ (1 < n) <-> ?Goal0
n: nat
(1 < n) * ~~ IsComposite n <-> ?Goal1
n: nat

(1 < n) * ~~ IsComposite n <-> ?Goal0
n: nat

1 < n <-> ?Goal0
n: nat
~~ IsComposite n <-> ?Goal1
n: nat

~~ IsComposite n <-> ?Goal0
rapply iff_stable.
n: nat

Empty + (1 < n) * IsComposite n <-> IsComposite n
n: nat

Empty + (1 < n) * IsComposite n <-> ?Goal
n: nat
?Goal <-> IsComposite n
n: nat

(1 < n) * IsComposite n <-> IsComposite n
n: nat

IsComposite n -> (1 < n) * IsComposite n
n: nat
H: IsComposite n

1 < n
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: forall m : nat, m < n -> 1 < m -> {p : Prime & (p | m)}
H: 1 < n

{p : Prime & (p | n)}
n: nat
IHn: forall m : nat, m < n -> 1 < m -> {p : Prime & (p | m)}
H: 1 < n
x: IsPrime n

{p : Prime & (p | n)}
n: nat
IHn: forall m : nat, m < n -> 1 < m -> {p : Prime & (p | m)}
H: 1 < n
x: ~ IsPrime n
{p : Prime & (p | n)}
n: nat
IHn: forall m : nat, m < n -> 1 < m -> {p : Prime & (p | m)}
H: 1 < n
x: ~ IsPrime n

{p : Prime & (p | n)}
n: nat
IHn: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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: forall m : 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.+1 = fold_right (fun (p : Prime) (n : nat) => p * n) 1 (p :: f)
n: nat
IHn: forall m : 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: forall m : 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: forall m : 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. *)