Built with Alectryon, running Coq+SerAPI v8.18.0+0.18.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.
(* -*- mode: coq; mode: visual-line -*- *)
[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
Require Export Basics.Nat.Local Set Universe Minimization ToSet.Local Unset Elimination Schemes.Schemenat_ind := Induction for nat SortType.Schemenat_rect := Induction for nat SortType.Schemenat_rec := Minimality for nat SortType.(** * Theorems about the natural numbers *)(** Many of these definitions and proofs have been ported from the coq stdlib. *)(** Some results are prefixed with [nat_] and some are not. Should we be more consistent? *)(** We want to close the trunc_scope so that notations from there don't conflict here. *)LocalClose Scope trunc_scope.LocalOpen Scope nat_scope.(** ** Basic operations on naturals *)(** It is common to call [S] [succ] so we add it as a parsing only notation. *)Notationsucc := S (only parsing).(** The predecessor of a natural number. *)Definitionpredn : nat :=
match n with
| 0 => n
| S n' => n'
end.(** Addition of natural numbers *)Fixpointaddnm : nat :=
match n with
| 0 => m
| S n' => S (add n' m)
end.Notation"n + m" := (add n m) : nat_scope.Definitiondoublen : nat := n + n.Fixpointmulnm : nat :=
match n with
| 0 => 0
| S n' => m + (mul n' m)
end.Notation"n * m" := (mul n m) : nat_scope.(** Truncated subtraction: [n - m] is [0] if [n <= m] *)Fixpointsubnm : nat :=
match n, m with
| S n' , S m' => sub n' m'
| _ , _ => n
end.Notation"n - m" := (sub n m) : nat_scope.(** ** Minimum, maximum *)Fixpointmaxnm :=
match n, m with
| 0 , _ => m
| S n' , 0 => n'.+1
| S n' , S m' => (max n' m').+1end.Fixpointminnm :=
match n, m with
| 0 , _ => 0
| S n' , 0 => 0
| S n' , S m' => S (min n' m')
end.(** ** Power *)Fixpointpownm :=
match m with
| 0 => 1
| S m' => n * (pow n m')
end.(** ** Euclidean division *)(** This division is linear and tail-recursive. In [divmod], [y] is the predecessor of the actual divisor, and [u] is [y] sub the real remainder. *)Fixpointdivmodxyqu : nat * nat :=
match x with
| 0 => (q , u)
| S x' =>
match u with
| 0 => divmod x' y (S q) y
| S u' => divmod x' y q u'
endend.Definitiondivxy : nat :=
match y with
| 0 => y
| S y' => fst (divmod x y' 0 y')
end.Definitionmoduloxy : nat :=
match y with
| 0 => y
| S y' => y' - snd (divmod x y' 0 y')
end.Infix"/" := div : nat_scope.Infix"mod" := modulo : nat_scope.(** ** Greatest common divisor *)(** We use Euclid algorithm, which is normally not structural, but Coq is now clever enough to accept this (behind modulo there is a subtraction, which now preserves being a subterm) *)Fixpointgcdab :=
match a with
| O => b
| S a' => gcd (b mod a'.+1) a'.+1end.(** ** Square *)Definitionsquaren : nat := n * n.(** ** Square root *)(** The following square root function is linear (and tail-recursive). With Peano representation, we can't do better. For faster algorithm, see Psqrt/Zsqrt/Nsqrt... We search the square root of n = k + p^2 + (q - r) with q = 2p and 0<=r<=q. We start with p=q=r=0, hence looking for the square root of n = k. Then we progressively decrease k and r. When k = S k' and r=0, it means we can use (S p) as new sqrt candidate, since (S k')+p^2+2p = k'+(S p)^2. When k reaches 0, we have found the biggest p^2 square contained in n, hence the square root of n is p.*)Fixpointsqrt_iterkpqr : nat :=
match k with
| O => p
| S k' =>
match r with
| O => sqrt_iter k' p.+1 q.+2 q.+2
| S r' => sqrt_iter k' p q r'
endend.Definitionsqrtn : nat := sqrt_iter n 000.(** ** Log2 *)(** This base-2 logarithm is linear and tail-recursive. In [log2_iter], we maintain the logarithm [p] of the counter [q], while [r] is the distance between [q] and the next power of 2, more precisely [q + S r = 2^(S p)] and [r<2^p]. At each recursive call, [q] goes up while [r] goes down. When [r] is 0, we know that [q] has almost reached a power of 2, and we increase [p] at the next call, while resetting [r] to [q]. Graphically (numbers are [q], stars are [r]) :<< 10 9 8 7 * 6 * 5 ... 4 3 * 2 * 1 * *0 * * *>> We stop when [k], the global downward counter reaches 0. At that moment, [q] is the number we're considering (since [k+q] is invariant), and [p] its logarithm.*)Fixpointlog2_iterkpqr : nat :=
match k with
| O => p
| S k' =>
match r with
| O => log2_iter k' (S p) (S q) q
| S r' => log2_iter k' p (S q) r'
endend.Definitionlog2n : nat := log2_iter (pred n) 010.Local Definitionap_S := @ap _ _ S.Local Definitionap_nat := @ap nat.#[export] Hint Resolve ap_S : core.#[export] Hint Resolve ap_nat : core.
foralln : nat, n = pred n.+1
foralln : nat, n = pred n.+1
auto.Defined.(** Injectivity of successor *)Definitionpath_nat_Snm (H : S n = S m) : n = m := ap pred H.#[export] Hint Immediate path_nat_S : core.
forallnm : nat, n <> m -> n.+1 <> m.+1
forallnm : nat, n <> m -> n.+1 <> m.+1
auto.Defined.#[export] Hint Resolve not_eq_S : core.(** TODO: keep or remove? *)DefinitionIsSucc (n: nat) : Type0 :=
match n with
| O => Empty
| S p => Unit
end.(** Zero is not the successor of a number *)
foralln : nat, 0 <> n.+1
foralln : nat, 0 <> n.+1
discriminate.Defined.#[export] Hint Resolve not_eq_O_S : core.
foralln : nat, n <> n.+1
foralln : nat, n <> n.+1
simple_induction' n; auto.Defined.#[export] Hint Resolve not_eq_n_Sn : core.Local Definitionap011_add := @ap011 _ _ _ add.Local Definitionap011_nat := @ap011 nat nat.#[export] Hint Resolve ap011_add : core.#[export] Hint Resolve ap011_nat : core.
foralln : nat, n = n + 0
foralln : nat, n = n + 0
simple_induction' n; simpl; auto.Defined.#[export] Hint Resolve add_n_O : core.
foralln : nat, 0 + n = n
foralln : nat, 0 + n = n
auto.Defined.
forallnm : nat, (n + m).+1 = n + m.+1
forallnm : nat, (n + m).+1 = n + m.+1
simple_induction' n; simpl; auto.Defined.#[export] Hint Resolve add_n_Sm: core.
byapply IHn, leq_S_n.Defined.(** A general form for injectivity of this constructor *)
n, k: nat p: n <= k r: n = k
p = transport (leq n) r (leq_n n)
n, k: nat p: n <= k r: n = k
p = transport (leq n) r (leq_n n)
n: nat r: n = n
leq_n n = transport (leq n) r (leq_n n)
n, m: nat p: n <= m r: n = m.+1
leq_S n m p = transport (leq n) r (leq_n n)
n: nat r: n = n
leq_n n = transport (leq n) r (leq_n n)
n: nat r: n = n c: 1 = r
leq_n n = transport (leq n) r (leq_n n)
n: nat
leq_n n = transport (leq n) 1 (leq_n n)
reflexivity.
n, m: nat p: n <= m r: n = m.+1
leq_S n m p = transport (leq n) r (leq_n n)
m: nat p: m.+1 <= m r: m.+1 = m.+1
leq_S m.+1 m p = transport (leq m.+1) r (leq_n m.+1)
contradiction (not_leq_Sn_n _ p).Defined.(** Which we specialise to this lemma *)Definitionleq_n_injn (p : n <= n) : p = leq_n n
:= leq_n_inj_gen n n p idpath.
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m, k: nat p: n <= k q: n <= m r: m.+1 = k
p = transport (leq n) r (leq_S n m q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m, k: nat p: n <= k q: n <= m r: m.+1 = k
p = transport (leq n) r (leq_S n m q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, k: nat p: n <= k
forall (m : nat) (q : n <= m) (r : m.+1 = k),
p = transport (leq n) r (leq_S n m q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n: nat
forall (m : nat) (q : n <= m) (r : m.+1 = n),
leq_n n = transport (leq n) r (leq_S n m q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m: nat p: n <= m
forall (m0 : nat) (q : n <= m0)
(r : m0.+1 = m.+1),
leq_S n m p = transport (leq n) r (leq_S n m0 q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n: nat
forall (m : nat) (q : n <= m) (r : m.+1 = n),
leq_n n = transport (leq n) r (leq_S n m q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, k: nat p: n <= k r: k.+1 = n
leq_n n = transport (leq n) r (leq_S n k p)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) k: nat p: k.+1 <= k
leq_n k.+1 = transport (leq k.+1) 1 (leq_S k.+1 k p)
contradiction (not_leq_Sn_n _ p).
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m: nat p: n <= m
forall (m0 : nat) (q : n <= m0) (r : m0.+1 = m.+1),
leq_S n m p = transport (leq n) r (leq_S n m0 q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m: nat p: n <= m m': nat q: n <= m' r: m'.+1 = m.+1
leq_S n m p = transport (leq n) r (leq_S n m' q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m: nat p: n <= m m': nat q: n <= m' r: m'.+1 = m.+1 r':= path_nat_S m' m r: m' = m
leq_S n m p = transport (leq n) r (leq_S n m' q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m': nat p, q: n <= m' r: m'.+1 = m'.+1
leq_S n m' p = transport (leq n) r (leq_S n m' q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m': nat p, q: n <= m' r: m'.+1 = m'.+1 t: 1 = r
leq_S n m' p = transport (leq n) r (leq_S n m' q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m': nat p, q: n <= m'
leq_S n m' p = transport (leq n) 1 (leq_S n m' q)
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m': nat p, q: n <= m'
leq_S n m' p = leq_S n m' q
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m': nat p, q: n <= m'
p = q
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n: nat p: n <= n
p = leq_n n
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m: nat p: n <= m.+1 q: n <= m
p = leq_S n m q
leq_S_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p = transport (leq n) r (leq_S n m q) n, m: nat p: n <= m.+1 q: n <= m
p = leq_S n m q
apply (leq_S_inj_gen n m _ p q idpath).Defined.Definitionleq_S_injnm (p : n <= m.+1) (q : n <= m) : p = leq_S n m q
:= leq_S_inj_gen n m m.+1 p q idpath.
n, m: nat
IsHProp (n <= m)
n, m: nat
IsHProp (n <= m)
n, m: nat
forallxy : n <= m, x = y
n, m: nat q: n <= m
forallp : n <= m, p = q
n: nat
forallp : n <= n, p = leq_n n
n, m: nat q: n <= m IHq: forallp : n <= m, p = q
forallp : n <= m.+1, p = leq_S n m q
n: nat
forallp : n <= n, p = leq_n n
n: nat y: n <= n
y = leq_n n
rapply leq_n_inj.
n, m: nat q: n <= m IHq: forallp : n <= m, p = q
forallp : n <= m.+1, p = leq_S n m q
n, m: nat q: n <= m IHq: forallp : n <= m, p = q y: n <= m.+1
apply leq_S, leq_add.Defined.(** We define the less-than relation [lt] in terms of [leq] *)Definitionltnm : Type0 := leq (S n) m.(** We declare it as an existing class so typeclass search is performed on its goals. *)Existing Classlt.#[export] Hint Unfold lt : core typeclass_instances.Infix"<" := lt : nat_scope.(** We add a typeclass instance for unfolding the definition so lemmas about [leq] can be used. *)Global Instancelt_is_leqnm : leq n.+1 m -> lt n m | 100 := idmap.(** We should also give them their various typeclass instances *)
Transitive lt
Transitive lt
forallxyz : nat,
x.+1 <= y -> y.+1 <= z -> x.+1 <= z
x, y, z: nat p: x.+1 <= y q: y.+1 <= z
x.+1 <= z
rapply leq_trans.Defined.Global Instancedecidable_ltnm : Decidable (lt n m) := _.Definitiongenm := leq m n.Existing Classge.#[export] Hint Unfold ge : core typeclass_instances.Infix">=" := ge : nat_scope.Global Instancege_is_leqnm : leq m n -> ge n m | 100 := idmap.Global Instancereflexive_ge : Reflexive ge := leq_n.Global Instancetransitive_ge : Transitive ge := funxyzpq => leq_trans q p.Global Instancedecidable_genm : Decidable (ge n m) := _.Definitiongtnm := lt m n.Existing Classgt.#[export] Hint Unfold gt : core typeclass_instances.Infix">" := gt : nat_scope.Global Instancegt_is_leqnm : leq m.+1 n -> gt n m | 100 := idmap.Global Instancetransitive_gt : Transitive gt
:= funxyzpq => transitive_lt _ _ _ q p.Global Instancedecidable_gtnm : Decidable (gt n m) := _.Notation"x <= y <= z" := (x <= y /\ y <= z) : nat_scope.Notation"x <= y < z" := (x <= y /\ y < z) : nat_scope.Notation"x < y < z" := (x < y /\ y < z) : nat_scope.Notation"x < y <= z" := (x < y /\ y <= z) : nat_scope.(** Principle of double induction *)
R: nat -> nat -> Type H1: foralln : nat, R 0 n H2: foralln : nat, R n.+10 H3: forallnm : nat, R n m -> R n.+1 m.+1
forallnm : nat, R n m
R: nat -> nat -> Type H1: foralln : nat, R 0 n H2: foralln : nat, R n.+10 H3: forallnm : nat, R n m -> R n.+1 m.+1
forallnm : nat, R n m
R: nat -> nat -> Type H1: foralln : nat, R 0 n H2: foralln : nat, R n.+10 H3: forallnm : nat, R n m -> R n.+1 m.+1 n: nat IH: forallm : nat, R n m
forallm : nat, R n.+1 m
destruct m; auto.Defined.(** Maximum and minimum : definitions and specifications *)
n: nat
max n n = n
n: nat
max n n = n
simple_induction' n; cbn; auto.Defined.#[export] Hint Resolve max_n_n : core.
n: nat
max n.+1 n = n.+1
n: nat
max n.+1 n = n.+1
simple_induction' n; cbn; auto.Defined.#[export] Hint Resolve max_Sn_n : core.
n, m: nat
max n m = max m n
n, m: nat
max n m = max m n
revert m; simple_induction' n; destruct m; cbn; auto.Defined.
n: nat
max 0 n = n
n: nat
max 0 n = n
auto.Defined.#[export] Hint Resolve max_0_n : core.
n: nat
max n 0 = n
n: nat
max n 0 = n
byrewrite max_comm.Defined.#[export] Hint Resolve max_n_0 : core.
forallnm : nat, m <= n -> max n m = n
forallnm : nat, m <= n -> max n m = n
m: nat IHm: foralln : nat, m <= n -> max n m = n
foralln : nat, m.+1 <= n -> max n m.+1 = n
m: nat IHm: foralln : nat, m <= n -> max n m = n p: m.+1 <= 0
max 0 m.+1 = 0
m: nat IHm: foralln : nat, m <= n -> max n m = n n: nat p: m.+1 <= n.+1
max n.+1 m.+1 = n.+1
m: nat IHm: foralln : nat, m <= n -> max n m = n n: nat p: m.+1 <= n.+1
max n.+1 m.+1 = n.+1
cbn; byapply ap_S, IHm, leq_S_n.Defined.
forallnm : nat, n <= m -> max n m = m
forallnm : nat, n <= m -> max n m = m
intros; rewrite max_comm; byapply max_l.Defined.
forallnm : nat, min n m = min m n
forallnm : nat, min n m = min m n
simple_induction' n; destruct m; cbn; auto.Defined.
forallnm : nat, n <= m -> min n m = n
forallnm : nat, n <= m -> min n m = n
n: nat IHn: forallm : nat, n <= m -> min n m = n
forallm : nat, n.+1 <= m -> min n.+1 m = n.+1
n: nat IHn: forallm : nat, n <= m -> min n m = n p: n.+1 <= 0
min n.+10 = n.+1
n: nat IHn: forallm : nat, n <= m -> min n m = n n0: nat p: n.+1 <= n0.+1
min n.+1 n0.+1 = n.+1
n: nat IHn: forallm : nat, n <= m -> min n m = n n0: nat p: n.+1 <= n0.+1
min n.+1 n0.+1 = n.+1
cbn; byapply ap_S, IHn, leq_S_n.Defined.
forallnm : nat, m <= n -> min n m = m
forallnm : nat, m <= n -> min n m = m
intros; rewrite min_comm; byapply min_l.Defined.(** [n]th iteration of the function [f : A -> A]. We have definitional equalities [nat_iter 0 f x = x] and [nat_iter n.+1 f x = f (nat_iter n f x)]. We make this a notation, so it doesn't add a universe variable for the universe containing [A]. *)Notationnat_iter n f x
:= ((fix F (m : nat)
:= match m with
| 0 => x
| m'.+1 => f (F m')
end) n).
n: nat A: Type f: A -> A x: A
nat_iter n.+1 f x = nat_iter n f (f x)
n: nat A: Type f: A -> A x: A
nat_iter n.+1 f x = nat_iter n f (f x)
A: Type f: A -> A x: A n: nat IHn: f (nat_iter n f x) = nat_iter n f (f x)
f (f (nat_iter n f x)) = f (nat_iter n f (f x))
exact (ap f IHn).Defined.
n, m: nat A: Type f: A -> A x: A
nat_iter (n + m) f x = nat_iter n f (nat_iter m f x)
n, m: nat A: Type f: A -> A x: A
nat_iter (n + m) f x = nat_iter n f (nat_iter m f x)
m: nat A: Type f: A -> A x: A n: nat IHn: nat_iter (n + m) f x = nat_iter n f (nat_iter m f x)
f (nat_iter (n + m) f x) =
f (nat_iter n f (nat_iter m f x))
exact (ap f IHn).Defined.(** Preservation of invariants : if [f : A -> A] preserves the invariant [P], then the iterates of [f] also preserve it. *)
n: nat A: Type f: A -> A P: A -> Type
(forallx : A, P x -> P (f x)) ->
forallx : A, P x -> P (nat_iter n f x)
n: nat A: Type f: A -> A P: A -> Type
(forallx : A, P x -> P (f x)) ->
forallx : A, P x -> P (nat_iter n f x)
A: Type f: A -> A P: A -> Type n: nat IHn: (forallx : A, P x -> P (f x)) -> forallx : A, P x -> P (nat_iter n f x)
(forallx : A, P x -> P (f x)) ->
forallx : A, P x -> P (f (nat_iter n f x))
A: Type f: A -> A P: A -> Type n: nat IHn: (forallx : A, P x -> P (f x)) -> forallx : A, P x -> P (nat_iter n f x) Hf: forallx : A, P x -> P (f x) x: A Hx: P x
apply nat_add_n_Sm.Defined.(** ** Exponentiation *)Fixpointnat_exp (nm : nat) : nat
:= match m with
| 0 => 1
| S m => nat_exp n m * n
end.(** ** Factorials *)Fixpointfactorial (n : nat) : nat
:= match n with
| 0 => 1
| S n => S n * factorial n
end.(** ** Natural number ordering *)(** ** Theorems about natural number ordering *)
x, y: nat
x <= y -> y <= x -> x = y
x, y: nat
x <= y -> y <= x -> x = y
x, y: nat p: x <= y q: y <= x
x = y
x: nat q: x <= x
x = x
x, m: nat p: x <= m q: m.+1 <= x
x = m.+1
x, m: nat p: x <= m q: m.+1 <= x
x = m.+1
x, m: nat p: x.+1 <= m q: m.+1 <= x.+1
x.+1 = m.+1
x, m: nat p: x.+1 <= m q: m <= x
x.+1 = m.+1
x, m: nat p: x.+1 <= m q: m <= x r:= leq_trans p q: x.+1 <= x