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]
Export Basics.Nat.Local Set Universe Minimization ToSet.Local Unset Elimination Schemes.(** * Natural numbers *)(** 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 *)(** *** Iteration *)(** [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).(** *** Successor and predecessor *)(** [nat_succ n] is the successor of a natural number [n]. We defined a notation [x.+1] for it in Overture.v. *)Notationnat_succ := S (only parsing).(** [nat_pred n] is the predecessor of a natural number [n]. When [n] is [0] we return [0]. *)Definitionnat_predn : nat :=
match n with
| 0 => n
| S n' => n'
end.(** *** Arithmetic operations *)(** Addition of natural numbers *)Definitionnat_addnm : nat
:= nat_iter n nat_succ m.Notation"n + m" := (nat_add n m) : nat_scope.(** Multiplication of natural numbers *)Definitionnat_mulnm : nat
:= nat_iter n (nat_add m) 0.Notation"n * m" := (nat_mul n m) : nat_scope.(** Truncated subtraction: [n - m] is [0] if [n <= m] *)Fixpointnat_subnm : nat :=
match n, m with
| S n' , S m' => nat_sub n' m'
| _ , _ => n
end.Notation"n - m" := (nat_sub n m) : nat_scope.(** Powers or exponentiation of natural numbers. *)Definitionnat_pownm := nat_iter m (nat_mul n) 1.(** *** Maximum and minimum *)(** The maximum [nat_max n m] of two natural numbers [n] and [m]. *)Fixpointnat_maxnm :=
match n, m with
| 0 , _ => m
| S n' , 0 => n'.+1
| S n' , S m' => (nat_max n' m').+1end.(** The minimum [nat_min n m] of two natural numbers [n] and [m]. *)Fixpointnat_minnm :=
match n, m with
| 0 , _ => 0
| S n' , 0 => 0
| S n' , S m' => S (nat_min n' m')
end.(** *** Euclidean division *)(** This division takes time linear in `x` and is tail-recursive. In [nat_div_mod x y q u], [x + y.+1 * q + (y - u)] is the quantity being divided and [y] is the predecessor of the divisor. It will be called with [q] zero and [u] equal to [y], so that [x] is the quantity being divided. The return value is a pair [(q', u')] with [x + y.+1 * q + (y - u) = y.+1 * q' + (y - u')], at least when [u <= y], as shown in [nat_div_mod_spec_helper] in Nat/Divison.v. *)Fixpointnat_div_modxyqu : nat * nat :=
match x with
| 0 => (q , u)
| S x' =>
match u with
| 0 => nat_div_mod x' y (S q) y
| S u' => nat_div_mod x' y q u'
endend.Definitionnat_divxy : nat :=
match y with
| 0 => y
| S y' => fst (nat_div_mod x y' 0 y')
end.Infix"/" := nat_div : nat_scope.(** [nat_mod x y] is the remainder when [x] is divided by [y]. When [y] is zero, it is defined to be [x]. See [nat_div_mod_spec] and related results below. *)Definitionnat_modxy : nat :=
match y with
| 0 => x
| S y' => y' - snd (nat_div_mod x y' 0 y')
end.Infix"mod" := nat_mod : nat_scope.(** For results about division and modulo, see Nat/Division.v. *)(** *** 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) *)Fixpointnat_gcdab :=
match a with
| O => b
| S a' => nat_gcd (b mod a'.+1) a'.+1end.(** ** Comparison predicates *)(** *** Less than or equal To [<=] *)Inductiveleq (n : nat) : nat -> Type0 :=
| leq_refl : leq n n
| leq_succ_r m : leq n m -> leq n (S m).Arguments leq_succ_r {n m} _.Schemeleq_ind := Induction for leq SortType.Schemeleq_rect := Induction for leq SortType.Schemeleq_rec := Induction for leq SortType.Notation"n <= m" := (leq n m) : nat_scope.Existing Classleq.Existing Instances leq_refl leq_succ_r.(** *** Less than [<] *)(** 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 : typeclass_instances.Infix"<" := lt : nat_scope.(** *** Greater than or equal To [>=] *)Definitiongeqnm := leq m n.Existing Classgeq.#[export] Hint Unfold geq : typeclass_instances.Infix">=" := geq : nat_scope.(*** Greater Than [>] *)Definitiongtnm := lt m n.Existing Classgt.#[export] Hint Unfold gt : typeclass_instances.Infix">" := gt : nat_scope.(** *** Combined comparison predicates *)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.(** ** Properties of [nat_iter]. *)
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
P (f (nat_iter n f x))
apply Hf, IHn; trivial.Defined.(** ** Properties of successors *)(** The predecessor of a successor is the original number. *)Definitionnat_pred_succ@{} n : nat_pred (nat_succ n) = n
:= idpath.(** The successor of a predecessor is the original as long as there is a strict lower bound. *)
n, i: nat
i < n -> (nat_pred n).+1 = n
n, i: nat
i < n -> (nat_pred n).+1 = n
byintros [].Defined.(** The most common lower bound is to take [0]. *)Definitionnat_succ_pred@{} n : 0 < n -> nat_succ (nat_pred n) = n
:= nat_succ_pred' n 0.(** Injectivity of successor. *)Definitionpath_nat_succ@{} n m (H : S n = S m) : n = m := ap nat_pred H.Instanceisinj_succ : IsInjective nat_succ := path_nat_succ.(** Inequality of successors is implied with inequality of the arguments. *)
n, m: nat
n <> m -> n.+1 <> m.+1
n, m: nat
n <> m -> n.+1 <> m.+1
n, m: nat np: n <> m q: n.+1 = m.+1
Empty
n, m: nat np: n <> m q: n.+1 = m.+1
n = m
exact (path_nat_succ _ _ q).Defined.(** Zero is not the successor of a number. *)
n: nat
0 <> n.+1
n: nat
0 <> n.+1
discriminate.Defined.(** A natural number cannot be equal to its own successor. *)
n: nat
n <> n.+1
n: nat
n <> n.+1
0 <> 1
n: nat IH: n <> n.+1
n.+1 <> n.+2
0 <> 1
apply neq_nat_zero_succ.
n: nat IH: n <> n.+1
n.+1 <> n.+2
byapply neq_nat_succ.Defined.(** ** Truncatedness of natural numbers *)(** [nat] has decidable paths. *)
DecidablePaths nat
DecidablePaths nat
n, m: nat
Decidable (n = m)
Decidable (0 = 0)
m: nat
Decidable (0 = m.+1)
n: nat IHn: forallm : nat, Decidable (n = m)
Decidable (n.+1 = 0)
n, m: nat IHn: forallm : nat, Decidable (n = m)
Decidable (n.+1 = m.+1)
Decidable (0 = 0)
exact (inl idpath).
m: nat
Decidable (0 = m.+1)
exact (inr (neq_nat_zero_succ m)).
n: nat IHn: forallm : nat, Decidable (n = m)
Decidable (n.+1 = 0)
exact (inr (funp => neq_nat_zero_succ n p^)).
n, m: nat IHn: forallm : nat, Decidable (n = m)
Decidable (n.+1 = m.+1)
n, m: nat IHn: forallm : nat, Decidable (n = m) p: n = m
Decidable (n.+1 = m.+1)
n, m: nat IHn: forallm : nat, Decidable (n = m) q: n <> m
Decidable (n.+1 = m.+1)
n, m: nat IHn: forallm : nat, Decidable (n = m) p: n = m
Decidable (n.+1 = m.+1)
exact (inl (ap S p)).
n, m: nat IHn: forallm : nat, Decidable (n = m) q: n <> m
Decidable (n.+1 = m.+1)
exact (inr (funp => q (path_nat_succ _ _ p))).Defined.(** [nat] is therefore a hset. *)Instanceishset_nat : IsHSet nat := _.(** ** Properties of addition *)(** [0] is the left identity of addition. *)Definitionnat_add_zero_l@{} n : 0 + n = n
:= idpath.(** [0] is the right identity of addition. *)
n: nat
n + 0 = n
n: nat
n + 0 = n
0 + 0 = 0
n: nat IHn: n + 0 = n
n.+1 + 0 = n.+1
0 + 0 = 0
reflexivity.
n: nat IHn: n + 0 = n
n.+1 + 0 = n.+1
n: nat IHn: n + 0 = n
nat_iter n S 0 = n
exact IHn.Defined.(** Adding a successor on the left is the same as adding and then taking the successor. *)Definitionnat_add_succ_l@{} n m : n.+1 + m = (n + m).+1
:= idpath.(** Adding a successor on the right is the same as adding and then taking the successor. *)
n, m: nat
n + m.+1 = (n + m).+1
n, m: nat
n + m.+1 = (n + m).+1
m: nat
m.+1 = m.+1
m, n: nat IH: n + m.+1 = (n + m).+1
(n + m.+1).+1 = (n + m).+2
m, n: nat IH: n + m.+1 = (n + m).+1
(n + m.+1).+1 = (n + m).+2
exact (ap S IH).Defined.(** Addition of natural numbers is commutative. *)
n, m: nat
n + m = m + n
n, m: nat
n + m = m + n
m: nat
0 + m = m + 0
n, m: nat IHn: n + m = m + n
n.+1 + m = m + n.+1
m: nat
0 + m = m + 0
exact (nat_add_zero_r m)^.
n, m: nat IHn: n + m = m + n
n.+1 + m = m + n.+1
n, m: nat IHn: n + m = m + n
n.+1 + m = (m + n).+1
n, m: nat IHn: n + m = m + n
nat_iter n S m = m + n
exact IHn.Defined.(** Addition of natural numbers is associative. *)
n, m, k: nat
n + (m + k) = n + m + k
n, m, k: nat
n + (m + k) = n + m + k
m, k: nat
0 + (m + k) = 0 + m + k
n, m, k: nat IHn: n + (m + k) = n + m + k
n.+1 + (m + k) = n.+1 + m + k
m, k: nat
0 + (m + k) = 0 + m + k
reflexivity.
n, m, k: nat IHn: n + (m + k) = n + m + k
n.+1 + (m + k) = n.+1 + m + k
n, m, k: nat IHn: n + (m + k) = n + m + k
nat_iter n S (m + k) = nat_iter (nat_iter n S m) S k
exact IHn.Defined.(** Addition on the left is injective. *)
k: nat
IsInjective (nat_add k)
k: nat
IsInjective (nat_add k)
simple_induction k k Ik; exact _.Defined.(** Addition on the right is injective. *)
k: nat
IsInjective (funx : nat => x + k)
k: nat
IsInjective (funx : nat => x + k)
k, x, y: nat H: x + k = y + k
x = y
k, x, y: nat H: x + k = y + k
k + x = k + y
k, x, y: nat H: x + k = y + k
x + k = k + y
k, x, y: nat H: x + k = y + k
y + k = k + y
napply nat_add_comm.Defined.(** A sum being zero is equivalent to both summands being zero. *)
n, m: nat
(n = 0) * (m = 0) <~> n + m = 0
n, m: nat
(n = 0) * (m = 0) <~> n + m = 0
n, m: nat
(n = 0) * (m = 0) -> n + m = 0
n, m: nat
n + m = 0 -> (n = 0) * (m = 0)
n, m: nat
(n = 0) * (m = 0) -> n + m = 0
intros [-> ->]; reflexivity.
n, m: nat
n + m = 0 -> (n = 0) * (m = 0)
m: nat
0 + m = 0 -> (0 = 0) * (m = 0)
n, m: nat
n.+1 + m = 0 -> (n.+1 = 0) * (m = 0)
m: nat
0 + m = 0 -> (0 = 0) * (m = 0)
bysplit.
n, m: nat
n.+1 + m = 0 -> (n.+1 = 0) * (m = 0)
n, m: nat H: 0 = n.+1 + m
((n.+1 = 0) * (m = 0))%type
byapply neq_nat_zero_succ in H.Defined.(** ** Properties of multiplication *)(** Multiplication by [0] on the left is [0]. *)Definitionnat_mul_zero_l@{} n : 0 * n = 0
:= idpath.(** Multiplication by [0] on the right is [0]. *)
n: nat
n * 0 = 0
n: nat
n * 0 = 0
byinduction n.Defined.Definitionnat_mul_succ_l@{} n m : n.+1 * m = m + n * m
:= idpath.
n, m: nat
n * m.+1 = n * m + n
n, m: nat
n * m.+1 = n * m + n
m: nat
0 * m.+1 = 0 * m + 0
n, m: nat IHn: n * m.+1 = n * m + n
n.+1 * m.+1 = n.+1 * m + n.+1
m: nat
0 * m.+1 = 0 * m + 0
reflexivity.
n, m: nat IHn: n * m.+1 = n * m + n
n.+1 * m.+1 = n.+1 * m + n.+1
n, m: nat IHn: n * m.+1 = n * m + n
n.+1 * m.+1 = (n.+1 * m + n).+1
n, m: nat IHn: n * m.+1 = n * m + n
nat_iter m S (nat_iter n (nat_add m.+1) 0) =
n.+1 * m + n
n, m: nat IHn: n * m.+1 = n * m + n
nat_iter m S (nat_iter n (nat_add m.+1) 0) =
m + (nat_iter n (nat_add m) 0 + n)
n, m: nat IHn: n * m.+1 = n * m + n
nat_iter n (nat_add m.+1) 0 =
nat_iter n (nat_add m) 0 + n
exact IHn.Defined.(** Multiplication of natural numbers is commutative. *)
n, m: nat
n * m = m * n
n, m: nat
n * m = m * n
n: nat
n * 0 = 0
n, m: nat IHm: n * m = m * n
n * m.+1 = n + m * n
n: nat
n * 0 = 0
napply nat_mul_zero_r.
n, m: nat IHm: n * m = m * n
n * m.+1 = n + m * n
n, m: nat IHm: n * m = m * n
n * m + n = n + m * n
n, m: nat IHm: n * m = m * n
n + n * m = n + m * n
n, m: nat IHm: n * m = m * n
n * m = m * n
exact IHm.Defined.(** Multiplication of natural numbers distributes over addition on the left. *)
n, m, k: nat
n * (m + k) = n * m + n * k
n, m, k: nat
n * (m + k) = n * m + n * k
m, k: nat
0 = 0
n, m, k: nat IHn: n * (m + k) = n * m + n * k
m + k + n * (m + k) = m + n * m + (k + n * k)
m, k: nat
0 = 0
reflexivity.
n, m, k: nat IHn: n * (m + k) = n * m + n * k
m + k + n * (m + k) = m + n * m + (k + n * k)
n, m, k: nat IHn: n * (m + k) = n * m + n * k
m + (k + n * (m + k)) = m + n * m + (k + n * k)
n, m, k: nat IHn: n * (m + k) = n * m + n * k
m + (k + n * (m + k)) = m + (n * m + (k + n * k))
n, m, k: nat IHn: n * (m + k) = n * m + n * k
k + n * (m + k) = n * m + (k + n * k)
n, m, k: nat IHn: n * (m + k) = n * m + n * k
n * (m + k) + k = n * m + (k + n * k)
n, m, k: nat IHn: n * (m + k) = n * m + n * k
n * m + n * k + k = n * m + (k + n * k)
n, m, k: nat IHn: n * (m + k) = n * m + n * k
n * m + (n * k + k) = n * m + (k + n * k)
n, m, k: nat IHn: n * (m + k) = n * m + n * k
n * k + k = k + n * k
napply nat_add_comm.Defined.(** Multiplication of natural numbers distributes over addition on the right. *)
n, m, k: nat
(n + m) * k = n * k + m * k
n, m, k: nat
(n + m) * k = n * k + m * k
n, m, k: nat
k * (n + m) = n * k + m * k
n, m, k: nat
k * n + k * m = n * k + m * k
napply ap011; napply nat_mul_comm.Defined.(** Multiplication of natural numbers is associative. *)
n, m, k: nat
n * (m * k) = n * m * k
n, m, k: nat
n * (m * k) = n * m * k
m, k: nat
0 = 0
n, m, k: nat IHn: n * (m * k) = n * m * k
m * k + n * (m * k) = (m + n * m) * k
m, k: nat
0 = 0
reflexivity.
n, m, k: nat IHn: n * (m * k) = n * m * k
m * k + n * (m * k) = (m + n * m) * k
n, m, k: nat IHn: n * (m * k) = n * m * k
m * k + n * (m * k) = m * k + n * m * k
n, m, k: nat IHn: n * (m * k) = n * m * k
n * (m * k) = n * m * k
exact IHn.Defined.(** Multiplication by [1] on the left is the identity. *)Definitionnat_mul_one_l@{} n : 1 * n = n
:= nat_add_zero_r _.(** Multiplication by [1] on the right is the identity. *)Definitionnat_mul_one_r@{} n : n * 1 = n
:= nat_mul_comm _ _ @ nat_mul_one_l _.(** ** Basic properties of comparison predicates *)(** *** Basic properties of [<=] *)(** [<=] is reflexive by definition. *)Instancereflexive_leq : Reflexive leq := leq_refl.(** Being less than or equal to is a transitive relation. *)
x, y, z: nat
x <= y -> y <= z -> x <= z
x, y, z: nat
x <= y -> y <= z -> x <= z
intros H1 H2; induction H2; exact _.Defined.Hint Immediate leq_trans : typeclass_instances.(** [<=] is transitive. *)Instancetransitive_leq : Transitive leq := @leq_trans.(** [0] is less than or equal to any natural number. *)
destruct m; exact _.Defined.(** A predecessor is less than or equal to a predecessor if the original number is less than or equal. *)
n, m: nat
n <= m -> nat_pred n <= nat_pred m
n, m: nat
n <= m -> nat_pred n <= nat_pred m
intros H; induction H; exact _.Defined.(** A successor is less than or equal to a successor if the original numbers are less than or equal. *)
n, m: nat
n <= m -> n.+1 <= m.+1
n, m: nat
n <= m -> n.+1 <= m.+1
induction1; exact _.Defined.Existing Instanceleq_succ | 100.(** The converse to [leq_succ] also holds. *)Definitionleq_pred' {nm} : n.+1 <= m.+1 -> n <= m := leq_pred.Hint Immediate leq_pred' : typeclass_instances.(** [<] is an irreflexive relation. *)
contradiction (lt_irrefl _ (leq_trans p q)).Defined.Instanceantisymmetric_leq : AntiSymmetric leq := @leq_antisym.Instanceantisymemtric_geq : AntiSymmetric geq
:= fun__pq => leq_antisym q p.(** Every natural number is zero or greater than zero. *)
n: nat
((0 = n) + (0 < n))%type
n: nat
((0 = n) + (0 < n))%type
((0 = 0) + (0 < 0))%type
n: nat IHn: ((0 = n) + (0 < n))%type
((0 = n.+1) + (0 < n.+1))%type
n: nat IHn: ((0 = n) + (0 < n))%type
((0 = n.+1) + (0 < n.+1))%type
right; exact _.Defined.(** Being less than or equal to [0] implies being [0]. *)
n: nat
n <= 0 -> n = 0
n: nat
n <= 0 -> n = 0
intros H; rapply leq_antisym.Defined.(** Nothing can be less than [0]. *)
intro l; apply leq_pred'; exact _.Defined.(** A general form for injectivity of this constructor *)
n, k: nat p: n <= k r: n = k
p = transport (leq n) r (leq_refl n)
n, k: nat p: n <= k r: n = k
p = transport (leq n) r (leq_refl n)
n: nat r: n = n
leq_refl n = transport (leq n) r (leq_refl n)
n, m: nat p: n <= m r: n = m.+1
leq_succ_r p = transport (leq n) r (leq_refl n)
n: nat r: n = n
leq_refl n = transport (leq n) r (leq_refl n)
n: nat r: n = n c: 1 = r
leq_refl n = transport (leq n) r (leq_refl n)
n: nat
leq_refl n = transport (leq n) 1 (leq_refl n)
reflexivity.
n, m: nat p: n <= m r: n = m.+1
leq_succ_r p = transport (leq n) r (leq_refl n)
m: nat p: m.+1 <= m r: m.+1 = m.+1
leq_succ_r p = transport (leq m.+1) r (leq_refl m.+1)
contradiction (lt_irrefl _ p).Defined.(** Which we specialise to this lemma *)Definitionleq_refl_injn (p : n <= n) : p = leq_refl n
:= leq_refl_inj_gen n n p idpath.
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m, k: nat p: n <= k q: n <= m r: m.+1 = k
p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m, k: nat p: n <= k q: n <= m r: m.+1 = k
p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, k: nat p: n <= k
forall (m : nat) (q : n <= m)
(r : m.+1 = k), p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n: nat
forall (m : nat) (q : n <= m)
(r : m.+1 = n),
leq_refl n = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m: nat p: n <= m
forall (m0 : nat)
(q : n <= m0) (r : m0.+1 = m.+1),
leq_succ_r p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n: nat
forall (m : nat) (q : n <= m)
(r : m.+1 = n),
leq_refl n = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, k: nat p: n <= k r: k.+1 = n
leq_refl n = transport (leq n) r (leq_succ_r p)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) k: nat p: k.+1 <= k
leq_refl k.+1 = transport (leq k.+1) 1 (leq_succ_r p)
contradiction (lt_irrefl _ p).
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m: nat p: n <= m
forall (m0 : nat)
(q : n <= m0) (r : m0.+1 = m.+1),
leq_succ_r p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m: nat p: n <= m m': nat q: n <= m' r: m'.+1 = m.+1
leq_succ_r p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m: nat p: n <= m m': nat q: n <= m' r: m'.+1 = m.+1 r':= path_nat_succ m' m r: m' = m
leq_succ_r p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m': nat p, q: n <= m' r: m'.+1 = m'.+1
leq_succ_r p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m': nat p, q: n <= m' r: m'.+1 = m'.+1 t: 1 = r
leq_succ_r p = transport (leq n) r (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m': nat p, q: n <= m'
leq_succ_r p = transport (leq n) 1 (leq_succ_r q)
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m': nat p, q: n <= m'
leq_succ_r p = leq_succ_r q
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m': nat p, q: n <= m'
p = q
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n: nat p: n <= n
p = leq_refl n
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m: nat p: n <= m.+1 q: n <= m
p = leq_succ_r q
leq_succ_r_inj_gen: forall (nmk : nat)
(p : n <= k) (q : n <= m)
(r : m.+1 = k),
p =
transport (leq n) r
(leq_succ_r q) n, m: nat p: n <= m.+1 q: n <= m
p = leq_succ_r q
exact (leq_succ_r_inj_gen n m _ p q idpath).Defined.Definitionleq_succ_r_injnm (p : n <= m.+1) (q : n <= m) : p = leq_succ_r q
:= leq_succ_r_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_refl n
n, m: nat q: n <= m IHq: forallp : n <= m, p = q
forallp : n <= m.+1, p = leq_succ_r q
n: nat
forallp : n <= n, p = leq_refl n
n: nat y: n <= n
y = leq_refl n
rapply leq_refl_inj.
n, m: nat q: n <= m IHq: forallp : n <= m, p = q
forallp : n <= m.+1, p = leq_succ_r q
n, m: nat q: n <= m IHq: forallp : n <= m, p = q y: n <= m.+1
apply equiv_leq_succ.Defined.(** The default induction principle for [leq] applies to a type family depending on the second variable. Here is a version involving a type family depending on the first variable. *)
n: nat Q: forallm : nat, m <= n.+1 -> Type H_Sn: Q n.+1 (leq_refl n.+1) H_m: forall (m : nat) (l : m <= n),
Q m (leq_succ_r l)
forall (m : nat) (l : m <= n.+1), Q m l
n: nat Q: forallm : nat, m <= n.+1 -> Type H_Sn: Q n.+1 (leq_refl n.+1) H_m: forall (m : nat) (l : m <= n),
Q m (leq_succ_r l)
forall (m : nat) (l : m <= n.+1), Q m l
n: nat Q: forallm : nat, m <= n.+1 -> Type H_Sn: Q n.+1 (leq_refl n.+1) H_m: forall (m : nat) (l : m <= n),
Q m (leq_succ_r l) m: nat leq_m_Sn: m <= n.+1
Q m leq_m_Sn
n: nat Q: forallm : nat, m <= n.+1 -> Type H_Sn: Q n.+1 (leq_refl n.+1) H_m: forall (m : nat) (l : m <= n),
Q m (leq_succ_r l) leq_m_Sn: n.+1 <= n.+1
Q n.+1 leq_m_Sn
n: nat Q: forallm : nat, m <= n.+1 -> Type H_Sn: Q n.+1 (leq_refl n.+1) H_m: forall (m : nat) (l : m <= n),
Q m (leq_succ_r l) m: nat leq_m_Sn: m <= n.+1 H: m <= n
Q m leq_m_Sn
n: nat Q: forallm : nat, m <= n.+1 -> Type H_Sn: Q n.+1 (leq_refl n.+1) H_m: forall (m : nat) (l : m <= n),
Q m (leq_succ_r l) leq_m_Sn: n.+1 <= n.+1
Q n.+1 leq_m_Sn
exact (path_ishprop _ _ # H_Sn).
n: nat Q: forallm : nat, m <= n.+1 -> Type H_Sn: Q n.+1 (leq_refl n.+1) H_m: forall (m : nat) (l : m <= n),
Q m (leq_succ_r l) m: nat leq_m_Sn: m <= n.+1 H: m <= n
Q m leq_m_Sn
exact (path_ishprop _ _ # H_m _ _).Defined.(** *** Basic properties of [<] *)(** [<=] and [<] imply [<] *)Definitionlt_leq_lt_trans {nmk} : n <= m -> m < k -> n < k
:= funleqlt => leq_trans (leq_succ leq) lt.(** [<=] and [<] imply [<] *)Definitionlt_lt_leq_trans {nmk} : n < m -> m <= k -> n < k
:= funltleq => leq_trans lt leq.Definitionleq_lt {nm} : n < m -> n <= m
:= leq_succ_l.Hint Immediate leq_lt : typeclass_instances.Definitionlt_trans {nmk} : n < m -> m < k -> n < k
:= funH1H2 => leq_lt (lt_leq_lt_trans H1 H2).Hint Immediate lt_trans : typeclass_instances.Instancetransitive_lt : Transitive lt := @lt_trans.Instanceishprop_ltnm : IsHProp (n < m) := _.Instancedecidable_ltnm : Decidable (lt n m) := _.(** *** Basic properties of [>=] *)Instancereflexive_geq : Reflexive geq := leq_refl.Instancetransitive_geq : Transitive geq := funxyzpq => leq_trans q p.Instanceishprop_geqnm : IsHProp (geq n m) := _.Instancedecidable_geqnm : Decidable (geq n m) := _.(** *** Basic properties of [>] *)Instancetransitive_gt : Transitive gt
:= funxyzpq => transitive_lt _ _ _ q p.Instanceishprop_gtnm : IsHProp (gt n m) := _.Instancedecidable_gtnm : Decidable (gt n m) := _.(** ** Properties of subtraction *)(** Subtracting a number from [0] is [0]. *)Definitionnat_sub_zero_l@{} n : 0 - n = 0 := idpath.(** Subtracting [0] from a number is the number itself. *)
n: nat
n - 0 = n
n: nat
n - 0 = n
destruct n; reflexivity.Defined.(** Subtracting a number from itself is [0]. *)
n: nat
n - n = 0
n: nat
n - n = 0
0 - 0 = 0
n: nat IHn: n - n = 0
n.+1 - n.+1 = 0
0 - 0 = 0
reflexivity.
n: nat IHn: n - n = 0
n.+1 - n.+1 = 0
exact IHn.Defined.(** Subtracting an addition is the same as subtracting the two numbers separately. *)
n, m, k: nat
n - (m + k) = n - m - k
n, m, k: nat
n - (m + k) = n - m - k
m, k: nat
0 - (m + k) = 0 - m - k
n, m, k: nat IHn: forallmk : nat, n - (m + k) = n - m - k
n.+1 - (m + k) = n.+1 - m - k
m, k: nat
0 - (m + k) = 0 - m - k
reflexivity.
n, m, k: nat IHn: forallmk : nat, n - (m + k) = n - m - k
n.+1 - (m + k) = n.+1 - m - k
n, k: nat IHn: forallmk : nat, n - (m + k) = n - m - k
n.+1 - (0 + k) = n.+1 - 0 - k
n, m, k: nat IHn: forallmk : nat, n - (m + k) = n - m - k
n.+1 - (m.+1 + k) = n.+1 - m.+1 - k
n, k: nat IHn: forallmk : nat, n - (m + k) = n - m - k
n.+1 - (0 + k) = n.+1 - 0 - k
reflexivity.
n, m, k: nat IHn: forallmk : nat, n - (m + k) = n - m - k
n.+1 - (m.+1 + k) = n.+1 - m.+1 - k
napply IHn.Defined.(** The order in which two numbers are subtracted does not matter. *)
n, m, k: nat
n - m - k = n - k - m
n, m, k: nat
n - m - k = n - k - m
n, m, k: nat
n - (m + k) = n - k - m
n, m, k: nat
n - (k + m) = n - k - m
napply nat_sub_r_add.Defined.(** Subtracting a larger number from a smaller number is [0]. *)
n, m: nat
n <= m <~> n - m = 0
n, m: nat
n <= m <~> n - m = 0
n, m: nat
n <= m -> n - m = 0
n, m: nat
n - m = 0 -> n <= m
n, m: nat
n <= m -> n - m = 0
n: nat
n - n = 0
n, m: nat l: n <= m IHl: n - m = 0
n - m.+1 = 0
n: nat
n - n = 0
exact (nat_sub_cancel n).
n, m: nat l: n <= m IHl: n - m = 0
n - m.+1 = 0
n, m: nat l: n <= m IHl: n - m = 0
n - (1 + m) = 0
n, m: nat l: n <= m IHl: n - m = 0
n - 1 - m = 0
n, m: nat l: n <= m IHl: n - m = 0
n - m - 1 = 0
bydestruct IHl^.
n, m: nat
n - m = 0 -> n <= m
m: nat
0 - m = 0 -> 0 <= m
n, m: nat IHn: forallm : nat, n - m = 0 -> n <= m
n.+1 - m = 0 -> n.+1 <= m
n, m: nat IHn: forallm : nat, n - m = 0 -> n <= m
n.+1 - m = 0 -> n.+1 <= m
n: nat IHn: forallm : nat, n - m = 0 -> n <= m
n.+1 - 0 = 0 -> n.+1 <= 0
n, m: nat IHn: forallm : nat, n - m = 0 -> n <= m
n.+1 - m.+1 = 0 -> n.+1 <= m.+1
n: nat IHn: forallm : nat, n - m = 0 -> n <= m
n.+1 - 0 = 0 -> n.+1 <= 0
intros p; bydestruct p.
n, m: nat IHn: forallm : nat, n - m = 0 -> n <= m
n.+1 - m.+1 = 0 -> n.+1 <= m.+1
n, m: nat IHn: forallm : nat, n - m = 0 -> n <= m p: n.+1 - m.+1 = 0
n.+1 <= m.+1
n, m: nat IHn: forallm : nat, n - m = 0 -> n <= m p: n.+1 - m.+1 = 0
n - m = 0
exact p.Defined.(** We can cancel a left summand when subtracting it from a sum. *)
m, n: nat
n + m - n = m
m, n: nat
n + m - n = m
m: nat
0 + m - 0 = m
m, n: nat IHn: n + m - n = m
n.+1 + m - n.+1 = m
m: nat
0 + m - 0 = m
napply nat_sub_zero_r.
m, n: nat IHn: n + m - n = m
n.+1 + m - n.+1 = m
exact IHn.Defined.(** We can cancel a right summand when subtracting it from a sum. *)
m, n: nat
m + n - n = m
m, n: nat
m + n - n = m
m, n: nat
m + n - n = n + m - n
m, n: nat
m + n = n + m
napply nat_add_comm.Defined.(** We can cancel a right subtrahend when adding it on the right to a subtraction if the subtrahend is less than the number being subtracted from. *)
n, m: nat
n <= m -> m - n + n = m
n, m: nat
n <= m -> m - n + n = m
n, m: nat H: n <= m
m - n + n = m
m: nat H: 0 <= m
m - 0 + 0 = m
n, m: nat H: n.+1 <= m IHn: forallm : nat, n <= m -> m - n + n = m
m - n.+1 + n.+1 = m
m: nat H: 0 <= m
m - 0 + 0 = m
m: nat H: 0 <= m
m - 0 = m
napply nat_sub_zero_r.
n, m: nat H: n.+1 <= m IHn: forallm : nat, n <= m -> m - n + n = m
m - n.+1 + n.+1 = m
n: nat H: n.+1 <= 0 IHn: forallm : nat, n <= m -> m - n + n = m
0 - n.+1 + n.+1 = 0
n, m: nat H: n.+1 <= m.+1 IHn: forallm : nat, n <= m -> m - n + n = m
m.+1 - n.+1 + n.+1 = m.+1
n, m: nat H: n.+1 <= m.+1 IHn: forallm : nat, n <= m -> m - n + n = m
m.+1 - n.+1 + n.+1 = m.+1
n, m: nat H: n.+1 <= m.+1 IHn: forallm : nat, n <= m -> m - n + n = m
(m.+1 - n.+1 + n).+1 = m.+1
n, m: nat H: n.+1 <= m.+1 IHn: forallm : nat, n <= m -> m - n + n = m
m.+1 - n.+1 + n = m
n, m: nat H: n.+1 <= m.+1 IHn: forallm : nat, n <= m -> m - n + n = m
n <= m
exact (leq_pred' H).Defined.(** We can cancel a right subtrahend when adding it on the left to a subtraction if the subtrahend is less than the number being subtracted from. *)
n, m: nat
n <= m -> n + (m - n) = m
n, m: nat
n <= m -> n + (m - n) = m
n, m: nat H: n <= m
n + (m - n) = m
n, m: nat H: n <= m
n + (m - n) = m - n + n
apply nat_add_comm.Defined.(** We can move a subtracted number to the left-hand side of an equation. *)
n, m, k: nat
n + k = m -> n = m - k
n, m, k: nat
n + k = m -> n = m - k
n, m, k: nat p: n + k = m
n = m - k
n, k: nat
n = n + k - k
n, k: nat
n + k - k = n
apply nat_add_sub_cancel_r.Defined.(** We can move a subtracted number to the right-hand side of an equation. *)Definitionnat_moveR_nV {nm} k : n = m + k -> n - k = m
:= funp => (nat_moveL_nV _ p^)^.(** Subtracting a successor is the predecessor of subtracting the original number. *)
n, m: nat
n - m.+1 = nat_pred (n - m)
n, m: nat
n - m.+1 = nat_pred (n - m)
m: nat
0 - m.+1 = nat_pred (0 - m)
n, m: nat IHn: forallm : nat, n - m.+1 = nat_pred (n - m)
n.+1 - m.+1 = nat_pred (n.+1 - m)
n, m: nat IHn: forallm : nat, n - m.+1 = nat_pred (n - m)
n.+1 - m.+1 = nat_pred (n.+1 - m)
n: nat IHn: forallm : nat, n - m.+1 = nat_pred (n - m)
n.+1 - 1 = nat_pred (n.+1 - 0)
n, m: nat IHn: forallm : nat, n - m.+1 = nat_pred (n - m)
n.+1 - m.+2 = nat_pred (n.+1 - m.+1)
n, m: nat IHn: forallm : nat, n - m.+1 = nat_pred (n - m)
n.+1 - m.+2 = nat_pred (n.+1 - m.+1)
apply IHn.Defined.(** ** Properties of maximum and minimum *)(** *** Properties of maximum *)(** [nat_max] is idempotent. *)
n: nat
nat_max n n = n
n: nat
nat_max n n = n
0 = 0
n: nat IH: nat_max n n = n
(nat_max n n).+1 = n.+1
n: nat IH: nat_max n n = n
(nat_max n n).+1 = n.+1
exact (ap S IH).Defined.(** The defining properties of [nat_max]: [m] and [n] are less than or equal to [nat_max n m] and [nat_max n m] is less than or equal to any number greater than or equal to [m] and [n]. *)
n, m: nat
n <= nat_max n m
n, m: nat
n <= nat_max n m
m: nat
0 <= nat_max 0 m
n, m: nat IHn: forallm : nat, n <= nat_max n m
n.+1 <= nat_max n.+1 m
n, m: nat IHn: forallm : nat, n <= nat_max n m
n.+1 <= nat_max n.+1 m
n: nat IHn: forallm : nat, n <= nat_max n m
n.+1 <= n.+1
n, m: nat IHn: forallm : nat, n <= nat_max n m
n.+1 <= (nat_max n m).+1
n, m: nat IHn: forallm : nat, n <= nat_max n m
n.+1 <= (nat_max n m).+1
exact (leq_succ (IHn m)).Defined.
n, m: nat
m <= nat_max n m
n, m: nat
m <= nat_max n m
m: nat
m <= nat_max 0 m
n, m: nat IHn: forallm : nat, m <= nat_max n m
m <= nat_max n.+1 m
n, m: nat IHn: forallm : nat, m <= nat_max n m
m <= nat_max n.+1 m
n: nat IHn: forallm : nat, m <= nat_max n m
0 <= n.+1
n, m: nat IHn: forallm : nat, m <= nat_max n m
m.+1 <= (nat_max n m).+1
n, m: nat IHn: forallm : nat, m <= nat_max n m
m.+1 <= (nat_max n m).+1
exact (leq_succ (IHn m)).Defined.
n, m, k: nat Hn: n <= k Hm: m <= k
nat_max n m <= k
n, m, k: nat Hn: n <= k Hm: m <= k
nat_max n m <= k
Hn, Hm: 0 <= 0
0 <= 0
n: nat Hn: n.+1 <= 0 Hm: 0 <= 0
n.+1 <= 0
m: nat Hn: 0 <= 0 Hm: m.+1 <= 0
m.+1 <= 0
n, m: nat Hn: n.+1 <= 0 Hm: m.+1 <= 0
(nat_max n m).+1 <= 0
k: nat Hn, Hm: 0 <= k.+1 IHk: forallnm : nat, n <= k -> m <= k -> nat_max n m <= k
0 <= k.+1
n, k: nat Hn: n.+1 <= k.+1 Hm: 0 <= k.+1 IHk: forallnm : nat, n <= k -> m <= k -> nat_max n m <= k
n.+1 <= k.+1
m, k: nat Hn: 0 <= k.+1 Hm: m.+1 <= k.+1 IHk: forallnm : nat, n <= k -> m <= k -> nat_max n m <= k
m.+1 <= k.+1
n, m, k: nat Hn: n.+1 <= k.+1 Hm: m.+1 <= k.+1 IHk: forallnm : nat, n <= k -> m <= k -> nat_max n m <= k
(nat_max n m).+1 <= k.+1
n, m: nat Hn: n.+1 <= 0 Hm: m.+1 <= 0
(nat_max n m).+1 <= 0
n, m, k: nat Hn: n.+1 <= k.+1 Hm: m.+1 <= k.+1 IHk: forallnm : nat, n <= k -> m <= k -> nat_max n m <= k
(nat_max n m).+1 <= k.+1
n, m: nat Hn: n.+1 <= 0 Hm: m.+1 <= 0
(nat_max n m).+1 <= 0
contradiction (not_lt_zero_r _ _).
n, m, k: nat Hn: n.+1 <= k.+1 Hm: m.+1 <= k.+1 IHk: forallnm : nat, n <= k -> m <= k -> nat_max n m <= k
(nat_max n m).+1 <= k.+1
exact (leq_succ (IHk n m _ _)).Defined.(** [nat_max] is commutative. *)
n, m: nat
nat_max n m = nat_max m n
n, m: nat
nat_max n m = nat_max m n
0 = 0
m: nat
m.+1 = m.+1
n: nat IHn: forallm : nat, nat_max n m = nat_max m n
n.+1 = n.+1
n, m: nat IHn: forallm : nat, nat_max n m = nat_max m n
(nat_max n m).+1 = (nat_max m n).+1
n, m: nat IHn: forallm : nat, nat_max n m = nat_max m n
(nat_max n m).+1 = (nat_max m n).+1
exact (ap S (IHn _)).Defined.(** The maximum of [n.+1] and [n] is [n.+1]. *)
n: nat
nat_max n.+1 n = n.+1
n: nat
nat_max n.+1 n = n.+1
1 = 1
n: nat IH: nat_max n.+1 n = n.+1
match n with
| 0 => n.+1
| m'.+1 => (nat_max n m').+1end.+1 = n.+2
n: nat IH: nat_max n.+1 n = n.+1
match n with
| 0 => n.+1
| m'.+1 => (nat_max n m').+1end.+1 = n.+2
exact (ap S IH).Defined.(** The maximum of [n] and [n.+1] is [n.+1]. *)Definitionnat_max_succ_r@{} n : nat_max n n.+1 = n.+1
:= nat_max_comm _ _ @ nat_max_succ_l _.(** [0] is the left identity of [nat_max]. *)Definitionnat_max_zero_l@{} n : nat_max 0 n = n := idpath.(** [0] is the right identity of [nat_max]. *)Definitionnat_max_zero_r@{} n : nat_max n 0 = n
:= nat_max_comm _ _ @ nat_max_zero_l _.(** [nat_max n m] is [n] if [m <= n]. *)
n, m: nat
m <= n -> nat_max n m = n
n, m: nat
m <= n -> nat_max n m = n
n, m: nat H: m <= n
nat_max n m = n
n: nat H: 0 <= n
nat_max n 0 = n
n, m: nat H: m.+1 <= n IHm: foralln : nat, m <= n -> nat_max n m = n
nat_max n m.+1 = n
n, m: nat H: m.+1 <= n IHm: foralln : nat, m <= n -> nat_max n m = n
nat_max n m.+1 = n
m: nat H: m.+1 <= 0 IHm: foralln : nat, m <= n -> nat_max n m = n
nat_max 0 m.+1 = 0
n, m: nat H: m.+1 <= n.+1 IHm: foralln : nat, m <= n -> nat_max n m = n
nat_max n.+1 m.+1 = n.+1
n, m: nat H: m.+1 <= n.+1 IHm: foralln : nat, m <= n -> nat_max n m = n
nat_max n.+1 m.+1 = n.+1
cbn; byapply (ap S), IHm, leq_pred'.Defined.(** [nat_max n m] is [m] if [n <= m]. *)Definitionnat_max_r {nm} : n <= m -> nat_max n m = m
:= fun_ => nat_max_comm _ _ @ nat_max_l _.(** [nat_max n m] is associative. *)
n, m, k: nat
nat_max n (nat_max m k) = nat_max (nat_max n m) k
n, m, k: nat
nat_max n (nat_max m k) = nat_max (nat_max n m) k
m, k: nat
nat_max 0 (nat_max m k) = nat_max (nat_max 0 m) k
n, m, k: nat IHn: forallmk : nat, nat_max n (nat_max m k) = nat_max (nat_max n m) k
nat_max n.+1 (nat_max m k) =
nat_max (nat_max n.+1 m) k
n, m, k: nat IHn: forallmk : nat, nat_max n (nat_max m k) = nat_max (nat_max n m) k
nat_max n.+1 (nat_max m k) =
nat_max (nat_max n.+1 m) k
n: nat IHn: forallmk : nat, nat_max n (nat_max m k) = nat_max (nat_max n m) k
byapply (ap S), IHn.Defined.(** Properties of Minima *)(** [nat_min] is idempotent. *)
n: nat
nat_min n n = n
n: nat
nat_min n n = n
0 = 0
n: nat IH: nat_min n n = n
(nat_min n n).+1 = n.+1
n: nat IH: nat_min n n = n
(nat_min n n).+1 = n.+1
exact (ap S IH).Defined.(** The defining properties of [nat_min]: [nat_min n m] is less than or equal to [m] and [n] and any number less than or equal to [m] and [n] is less than or equal to [nat_min n m]. *)
n, m: nat
nat_min n m <= n
n, m: nat
nat_min n m <= n
m: nat
nat_min 0 m <= 0
n, m: nat IHn: forallm : nat, nat_min n m <= n
nat_min n.+1 m <= n.+1
n, m: nat IHn: forallm : nat, nat_min n m <= n
nat_min n.+1 m <= n.+1
n: nat IHn: forallm : nat, nat_min n m <= n
0 <= n.+1
n, m: nat IHn: forallm : nat, nat_min n m <= n
(nat_min n m).+1 <= n.+1
n, m: nat IHn: forallm : nat, nat_min n m <= n
(nat_min n m).+1 <= n.+1
exact (leq_succ (IHn m)).Defined.
n, m: nat
nat_min n m <= m
n, m: nat
nat_min n m <= m
m: nat
nat_min 0 m <= m
n, m: nat IHn: forallm : nat, nat_min n m <= m
nat_min n.+1 m <= m
n, m: nat IHn: forallm : nat, nat_min n m <= m
nat_min n.+1 m <= m
n: nat IHn: forallm : nat, nat_min n m <= m
0 <= 0
n, m: nat IHn: forallm : nat, nat_min n m <= m
(nat_min n m).+1 <= m.+1
n, m: nat IHn: forallm : nat, nat_min n m <= m
(nat_min n m).+1 <= m.+1
exact (leq_succ (IHn m)).Defined.
n, m, k: nat Hn: k <= n Hm: k <= m
k <= nat_min n m
n, m, k: nat Hn: k <= n Hm: k <= m
k <= nat_min n m
Hn, Hm: 0 <= 0
0 <= 0
n: nat Hn: 0 <= n.+1 Hm: 0 <= 0
0 <= 0
m: nat Hn: 0 <= 0 Hm: 0 <= m.+1
0 <= 0
n, m: nat Hn: 0 <= n.+1 Hm: 0 <= m.+1
0 <= (nat_min n m).+1
k: nat Hn, Hm: k.+1 <= 0 IHk: forallnm : nat, k <= n -> k <= m -> k <= nat_min n m
k.+1 <= 0
n, k: nat Hn: k.+1 <= n.+1 Hm: k.+1 <= 0 IHk: forallnm : nat, k <= n -> k <= m -> k <= nat_min n m
k.+1 <= 0
m, k: nat Hn: k.+1 <= 0 Hm: k.+1 <= m.+1 IHk: forallnm : nat, k <= n -> k <= m -> k <= nat_min n m
k.+1 <= 0
n, m, k: nat Hn: k.+1 <= n.+1 Hm: k.+1 <= m.+1 IHk: forallnm : nat, k <= n -> k <= m -> k <= nat_min n m
k.+1 <= (nat_min n m).+1
n, m, k: nat Hn: k.+1 <= n.+1 Hm: k.+1 <= m.+1 IHk: forallnm : nat, k <= n -> k <= m -> k <= nat_min n m
k.+1 <= (nat_min n m).+1
exact (leq_succ (IHk n m _ _)).Defined.(** [nat_min] is commutative. *)
n, m: nat
nat_min n m = nat_min m n
n, m: nat
nat_min n m = nat_min m n
0 = 0
m: nat
0 = 0
n: nat IHn: forallm : nat, nat_min n m = nat_min m n
0 = 0
n, m: nat IHn: forallm : nat, nat_min n m = nat_min m n
(nat_min n m).+1 = (nat_min m n).+1
n, m: nat IHn: forallm : nat, nat_min n m = nat_min m n
(nat_min n m).+1 = (nat_min m n).+1
exact (ap S (IHn _)).Defined.(** [nat_min] of [0] and [n] is [0]. *)Definitionnat_min_zero_ln : nat_min 0 n = 0 := idpath.(** [nat_min] of [n] and [0] is [0]. *)Definitionnat_min_zero_rn : nat_min n 0 = 0:=
nat_min_comm _ _ @ nat_min_zero_l _.(** [nat_min n m] is [n] if [n <= m]. *)
n, m: nat
n <= m -> nat_min n m = n
n, m: nat
n <= m -> nat_min n m = n
forallnm : nat, n <= m -> nat_min n m = n
n: nat IHn: forallm : nat, n <= m -> nat_min n m = n
forallm : nat, n.+1 <= m -> nat_min n.+1 m = n.+1
n: nat IHn: forallm : nat, n <= m -> nat_min n m = n p: n.+1 <= 0
nat_min n.+10 = n.+1
n: nat IHn: forallm : nat, n <= m -> nat_min n m = n n0: nat p: n.+1 <= n0.+1
nat_min n.+1 n0.+1 = n.+1
n: nat IHn: forallm : nat, n <= m -> nat_min n m = n n0: nat p: n.+1 <= n0.+1
nat_min n.+1 n0.+1 = n.+1
cbn; byapply (ap S), IHn, leq_pred'.Defined.(** [nat_min n m] is [m] if [m <= n]. *)Definitionnat_min_r {nm} : m <= n -> nat_min n m = m
:= fun_ => nat_min_comm _ _ @ nat_min_l _.(** [nat_min n m] is associative. *)
n, m, k: nat
nat_min n (nat_min m k) = nat_min (nat_min n m) k
n, m, k: nat
nat_min n (nat_min m k) = nat_min (nat_min n m) k
m, k: nat
nat_min 0 (nat_min m k) = nat_min (nat_min 0 m) k
n, m, k: nat IHn: forallmk : nat, nat_min n (nat_min m k) = nat_min (nat_min n m) k
nat_min n.+1 (nat_min m k) =
nat_min (nat_min n.+1 m) k
n, m, k: nat IHn: forallmk : nat, nat_min n (nat_min m k) = nat_min (nat_min n m) k
nat_min n.+1 (nat_min m k) =
nat_min (nat_min n.+1 m) k
n: nat IHn: forallmk : nat, nat_min n (nat_min m k) = nat_min (nat_min n m) k
byapply (ap S), IHn.Defined.(** ** More theory of comparison predicates *)(** *** Addition lemmas *)(** The second summand is less than or equal to the sum. *)
n, m: nat
n <= m + n
n, m: nat
n <= m + n
n: nat
n <= 0 + n
n, m: nat IH: n <= m + n
n <= m.+1 + n
n: nat
n <= 0 + n
exact (leq_refl n).
n, m: nat IH: n <= m + n
n <= m.+1 + n
exact (leq_succ_r IH).Defined.(** The first summand is less than or equal to the sum. *)
n, m: nat
n <= n + m
n, m: nat
n <= n + m
m: nat
0 <= 0 + m
m, n: nat IHn: n <= n + m
n.+1 <= n.+1 + m
m: nat
0 <= 0 + m
exact (leq_zero_l m).
m, n: nat IHn: n <= n + m
n.+1 <= n.+1 + m
exact (leq_succ IHn).Defined.(** *** Multiplication lemmas *)(** The second multiplicand is less than or equal to the product. *)
n, m, l: nat
l < m -> n <= m * n
n, m, l: nat
l < m -> n <= m * n
intros H; induction H; exact _.Defined.(** The first multiplicand is less than or equal to the product. *)
n, m, l: nat
l < m -> n <= n * m
n, m, l: nat
l < m -> n <= n * m
rewrite nat_mul_comm; exact _.Defined.(** ** Eliminating positive assumptions *)(** Sometimes we want to prove a predicate which assumes that [0 < x]. In that case, it suffices to prove it for [x.+1] instead. *)
P: nat -> Type H: forallx : nat, P x.+1
forallx : nat, 0 < x -> P x
P: nat -> Type H: forallx : nat, P x.+1
forallx : nat, 0 < x -> P x
P: nat -> Type H: forallx : nat, P x.+1 x: nat l: 0 < x
P x
P: nat -> Type H: forallx : nat, P x.+1 l: 0 < 0
P 0
P: nat -> Type H: forallx : nat, P x.+1 x: nat l: 0 < x.+1
P x.+1
P: nat -> Type H: forallx : nat, P x.+1 x: nat l: 0 < x.+1
P x.+1
apply H.Defined.(** Alternative Characterizations of [<=] *)(** [n <= m] is equivalent to [(n < m) + (n = m)]. This justifies the name "less than or equal to". Note that it is not immediately obvious that the latter type is a hprop. *)
n, m: nat
n <= m <~> (n < m) + (n = m)
n, m: nat
n <= m <~> (n < m) + (n = m)
n, m: nat
IsHProp ((n < m) + (n = m))
n, m: nat
n <= m -> (n < m) + (n = m)
n, m: nat
(n < m) + (n = m) -> n <= m
n, m: nat
IsHProp ((n < m) + (n = m))
n, m: nat
IsHProp (n < m)
n, m: nat
IsHProp (n = m)
n, m: nat
n < m -> n = m -> Empty
n, m: nat
n < m -> n = m -> Empty
n: nat H1: n < n
Empty
contradiction (lt_irrefl _ _).
n, m: nat
n <= m -> (n < m) + (n = m)
n: nat
((n < n) + (n = n))%type
n, m: nat l: n <= m IHl: ((n < m) + (n = m))%type
((n < m.+1) + (n = m.+1))%type
n: nat
((n < n) + (n = n))%type
byright.
n, m: nat l: n <= m IHl: ((n < m) + (n = m))%type
((n < m.+1) + (n = m.+1))%type
left; exact (leq_succ l).
n, m: nat
(n < m) + (n = m) -> n <= m
n, m: nat l: n < m
n <= m
n, m: nat p: n = m
n <= m
n, m: nat l: n < m
n <= m
exact (leq_succ_l l).
n, m: nat p: n = m
n <= m
n: nat
n <= n
exact (leq_refl _).Defined.(** Here is an alternative characterization of [<=] in terms of an existence predicate and addition. *)
n, m: nat
n <= m <~> {k : nat & k + n = m}
n, m: nat
n <= m <~> {k : nat & k + n = m}
n, m: nat
IsHProp {k : nat & k + n = m}
n, m: nat
n <= m -> {k : nat & k + n = m}
n, m: nat
{k : nat & k + n = m} -> n <= m
n, m: nat
IsHProp {k : nat & k + n = m}
n, m: nat
forallxy : {k : nat & k + n = m}, x = y
n, m, x: nat p: x + n = m y: nat q: y + n = m
(x; p) = (y; q)
n, m, x: nat p: x + n = m y: nat q: y + n = m r:= nat_moveL_nV n p @ (nat_moveL_nV n q)^: x = y
(x; p) = (y; q)
n, m, x: nat p, q: x + n = m
(x; p) = (x; q)
n, m, x: nat p, q: x + n = m
p = q
apply path_ishprop.
n, m: nat
n <= m -> {k : nat & k + n = m}
n, m: nat p: n <= m
{k : nat & k + n = m}
n, m: nat p: n <= m
m - n + n = m
apply nat_add_sub_l_cancel, p.
n, m: nat
{k : nat & k + n = m} -> n <= m
n, m, k: nat p: k + n = m
n <= m
n, k: nat
n <= k + n
apply leq_add_l.Defined.(** *** Dichotomy of [<=] *)
m, n: nat
((m <= n) + (m > n))%type
m, n: nat
((m <= n) + (m > n))%type
n: nat
((0 <= n) + (0 > n))%type
m, n: nat IHm: foralln : nat, (m <= n) + (m > n)
((m.+1 <= n) + (m.+1 > n))%type
m, n: nat IHm: foralln : nat, (m <= n) + (m > n)
((m.+1 <= n) + (m.+1 > n))%type
m: nat IHm: foralln : nat, (m <= n) + (m > n)
((m.+1 <= 0) + (m.+1 > 0))%type
m, n: nat IHm: foralln : nat, (m <= n) + (m > n)
((m.+1 <= n.+1) + (m.+1 > n.+1))%type
m, n: nat IHm: foralln : nat, (m <= n) + (m > n)
((m.+1 <= n.+1) + (m.+1 > n.+1))%type
m, n: nat IHm: foralln : nat, (m <= n) + (m > n) l: m <= n
((m.+1 <= n.+1) + (m.+1 > n.+1))%type
m, n: nat IHm: foralln : nat, (m <= n) + (m > n) g: m > n
((m.+1 <= n.+1) + (m.+1 > n.+1))%type
m, n: nat IHm: foralln : nat, (m <= n) + (m > n) g: m > n
((m.+1 <= n.+1) + (m.+1 > n.+1))%type
1: right; exact _.Defined.(** A variant. *)
n, m: nat l: m <= n.+1
((m = n.+1) + (m <= n))%type
n, m: nat l: m <= n.+1
((m = n.+1) + (m <= n))%type
n, m: nat l: m <= n.+1 X: m = n.+1
((n.+1 = n.+1) + (n.+1 <= n))%type
n, m: nat l: m <= n.+1 m0: nat H: m <= n X0: m0 = n
((m = n.+1) + (m <= n))%type
n, m: nat l: m <= n.+1 X: m = n.+1
((n.+1 = n.+1) + (n.+1 <= n))%type
left; reflexivity.
n, m: nat l: m <= n.+1 m0: nat H: m <= n X0: m0 = n
((m = n.+1) + (m <= n))%type
right; assumption.Defined.(** *** Trichotomy *)(** Any two natural numbers are either equal, less than, or greater than each other. *)
m, n: nat
((m < n) + (m = n) + (m > n))%type
m, n: nat
((m < n) + (m = n) + (m > n))%type
m, n: nat
(m <= n) + (m > n) -> (m < n) + (m = n) + (m > n)
m, n: nat
m <= n -> (m < n) + (m = n)
exact equiv_leq_lt_or_eq.Defined.(** *** Negation lemmas *)(** There are various lemmas we can state about negating the comparison operators on [nat]. To aid readability, we opt to keep the order of the variables in each statement consistent. *)
intros ? ?; contradiction (lt_irrefl m); exact _.Defined.Definitionleq_iff_not_gt {nm} : ~(n > m) <-> n <= m
:= geq_iff_not_lt.Definitionlt_iff_not_geq {nm} : ~(n >= m) <-> n < m
:= gt_iff_not_leq.(** *** Dichotomy of [<>] *)(** The inequality of natural numbers is equivalent to [n < m] or [n > m]. This could be an equivalence; however, one of the sections requires [Funext] since we are comparing two inequality proofs. It is therefore more useful to keep it as a biimplication. Note that this is a negated version of antisymmetry of [<=]. *)
n, m: nat
n <> m <-> (n < m) + (n > m)
n, m: nat
n <> m <-> (n < m) + (n > m)
n, m: nat
n <> m -> (n < m) + (n > m)
n, m: nat
(n < m) + (n > m) -> n <> m
n, m: nat
n <> m -> (n < m) + (n > m)
n, m: nat diseq: n <> m
((n < m) + (n > m))%type
n, m: nat diseq: n <> m a: ~ (n < m)
((n < m) + (n > m))%type
n, m: nat diseq: n <> m a: n >= m
((n < m) + (n > m))%type
n, m: nat diseq: n <> m a: ((m < n) + (m = n))%type
((n < m) + (n > m))%type
n, m: nat diseq: n <> m lt: m < n
((n < m) + (n > m))%type
n, m: nat diseq: n <> m eq: m = n
((n < m) + (n > m))%type
n, m: nat diseq: n <> m eq: m = n
((n < m) + (n > m))%type
n, m: nat diseq: n <> m eq: n = m
((n < m) + (n > m))%type
contradiction.
n, m: nat
(n < m) + (n > m) -> n <> m
intros [H' | H'] nq; destruct nq; exact (lt_irrefl _ H').Defined.(** ** Arithmetic relations between [trunc_index] and [nat]. *)
exact (ap (funx => x.+2%trunc) IHn).Defined.(** *** Subtraction *)
n, m: nat
n <= n - m + m
n, m: nat
n <= n - m + m
n, m: nat l: m <= n
n <= n - m + m
n, m: nat g: m > n
n <= n - m + m
n, m: nat l: m <= n
n <= n - m + m
byrewrite nat_add_sub_l_cancel.
n, m: nat g: m > n
n <= n - m + m
n, m: nat g: n <= m
n <= n - m + m
bydestruct (equiv_nat_sub_leq _)^.Defined.
n, m: nat
n <= m + (n - m)
n, m: nat
n <= m + (n - m)
rewrite nat_add_comm; exact _.Defined.(** A number being less than another is equivalent to their difference being greater than zero. *)
n, m: nat
m < n <~> 0 < n - m
n, m: nat
m < n <~> 0 < n - m
m: nat
m < 0 <~> 0 < 0 - m
n, m: nat IHn: forallm : nat, m < n <~> 0 < n - m
m < n.+1 <~> 0 < n.+1 - m
n, m: nat IHn: forallm : nat, m < n <~> 0 < n - m
m < n.+1 <~> 0 < n.+1 - m
n, m: nat IHn: forallm : nat, m < n <~> 0 < n - m
m.+1 < n.+1 <~> 0 < n.+1 - m.+1
n, m: nat IHn: forallm : nat, m < n <~> 0 < n - m
m.+1 < n.+1 <~> m < n
srapply equiv_iff_hprop.Defined.(** *** Monotonicity of addition *)(** TODO: use [OrderPreserving] from canonical_names *)(** Addition on the left is monotone. *)
n, m, k: nat
n <= m -> k + n <= k + m
n, m, k: nat
n <= m -> k + n <= k + m
intros H; induction k; exact _.Defined.Hint Immediate nat_add_l_monotone : typeclass_instances.(** Addition on the right is monotone. *)
n, m, k: nat
n <= m -> n + k <= m + k
n, m, k: nat
n <= m -> n + k <= m + k
intros H; rewrite2 (nat_add_comm _ k); exact _.Defined.Hint Immediate nat_add_r_monotone : typeclass_instances.(** Addition is monotone in both arguments. (This makes [+] a bifunctor when treating [nat] as a category (as a preorder)). *)
n, n', m, m': nat
n <= m -> n' <= m' -> n + n' <= m + m'
n, n', m, m': nat
n <= m -> n' <= m' -> n + n' <= m + m'
intros H1 H2; induction H1; exact _.Defined.Hint Immediate nat_add_monotone : typeclass_instances.(** *** Strict monotonicity of addition *)(** [nat_succ] is strictly monotone. *)Instancelt_succ {nm} : n < m -> n.+1 < m.+1 := _.Instancelt_succ_r {nm} : n < m -> n < m.+1 | 100 := _.(** Addition on the left is strictly monotone. *)
n, m, k: nat
n < m -> k + n < k + m
n, m, k: nat
n < m -> k + n < k + m
intros H; induction k; exact _.Defined.Hint Immediate nat_add_l_strictly_monotone : typeclass_instances.(** Addition on the right is strictly monotone. *)
n, m, k: nat
n < m -> n + k < m + k
n, m, k: nat
n < m -> n + k < m + k
intros H; rewrite2 (nat_add_comm _ k); exact _.Defined.Hint Immediate nat_add_r_strictly_monotone : typeclass_instances.(** Addition is strictly monotone in both arguments. *)
n, n', m, m': nat
n < m -> n' < m' -> n + n' < m + m'
n, n', m, m': nat
n < m -> n' < m' -> n + n' < m + m'
intros H1 H2; induction H1; exact _.Defined.Hint Immediate nat_add_strictly_monotone : typeclass_instances.(** *** Monotonicity of multiplication *)(** Multiplication on the left is monotone. *)
n, m, k: nat
n <= m -> k * n <= k * m
n, m, k: nat
n <= m -> k * n <= k * m
intros H; induction k; exact _.Defined.Hint Immediate nat_mul_l_monotone : typeclass_instances.(** Multiplication on the right is monotone. *)
n, m, k: nat
n <= m -> n * k <= m * k
n, m, k: nat
n <= m -> n * k <= m * k
intros H; rewrite2 (nat_mul_comm _ k); exact _.Defined.Hint Immediate nat_mul_r_monotone : typeclass_instances.(** Multiplication is monotone in both arguments. *)
n, n', m, m': nat
n <= m -> n' <= m' -> n * n' <= m * m'
n, n', m, m': nat
n <= m -> n' <= m' -> n * n' <= m * m'
intros H1 H2; induction H1; exact _.Defined.Hint Immediate nat_mul_monotone : typeclass_instances.(** *** Strict monotonicity of multiplication *)(** Multiplication on the left by a positive number is strictly monotone. *)
n, m, l, k: nat
l < k -> n < m -> k * n < k * m
n, m, l, k: nat
l < k -> n < m -> k * n < k * m
n, m, l: nat
l < 0 -> n < m -> 0 * n < 0 * m
n, m, l, k: nat
l < k.+1 -> n < m -> k.+1 * n < k.+1 * m
n, m, l, k: nat
l < k.+1 -> n < m -> k.+1 * n < k.+1 * m
intros _ H; induction k as [|k IHk] in |- *; exact _.Defined.Hint Immediate nat_mul_l_strictly_monotone : typeclass_instances.(** Multiplication on the right by a positive number is strictly monotone. *)
n, m, l, k: nat
l < k -> n < m -> n * k < m * k
n, m, l, k: nat
l < k -> n < m -> n * k < m * k
intros ? H; rewrite2 (nat_mul_comm _ k); exact _.Defined.Hint Immediate nat_mul_r_strictly_monotone : typeclass_instances.(** Multiplication is strictly monotone in both arguments. *)
n, n', m, m': nat
n < m -> n' < m' -> n * n' < m * m'
n, n', m, m': nat
n < m -> n' < m' -> n * n' < m * m'
n, n', m, m': nat H1: n < m H2: n' < m'
n * n' < m * m'
n, n', m, m': nat H1: n < m H2: n' < m'
n * n' <= n * m'
n, n', m, m': nat H1: n < m H2: n' < m'
n * m' < m * m'
n, n', m, m': nat H1: n < m H2: n' < m'
n * m' < m * m'
rapply nat_mul_r_strictly_monotone.Defined.Hint Immediate nat_mul_strictly_monotone : typeclass_instances.(** *** Order-reflection *)(** Addition on the left is order-reflecting. *)
n, m, k: nat
k + n <= k + m -> n <= m
n, m, k: nat
k + n <= k + m -> n <= m
intros H; induction k; exact _.Defined.(** Addition on the right is order-reflecting. *)
n, m, k: nat
n + k <= m + k -> n <= m
n, m, k: nat
n + k <= m + k -> n <= m
rewrite2 (nat_add_comm _ k); napply leq_reflects_add_l.Defined.(** Addition on the left is strictly order-reflecting. *)
n, m, k: nat
k + n < k + m -> n < m
n, m, k: nat
k + n < k + m -> n < m
intros H; induction k; exact _.Defined.(** Addition on the right is strictly order-reflecting. *)
n, m, k: nat
n + k < m + k -> n < m
n, m, k: nat
n + k < m + k -> n < m
rewrite2 (nat_add_comm _ k); napply lt_reflects_add_l.Defined.(** ** Further properties of subtraction *)
n, m: nat
n - m <= n
n, m: nat
n - m <= n
n, m: nat
n - m - n = 0
n, m: nat
n - n - m = 0
n, m: nat
0 - m = 0
apply nat_sub_zero_l.Defined.(** Subtracting from a successor is the successor of subtracting from the original number, as long as the amount being subtracted is less than or equal to the original number. *)
n, m: nat
m <= n -> n.+1 - m = (n - m).+1
n, m: nat
m <= n -> n.+1 - m = (n - m).+1
n, m: nat H: m <= n
n.+1 - m = (n - m).+1
n: nat H: 0 <= n
n.+1 - 0 = (n - 0).+1
n, m: nat H: m.+1 <= n IHm: foralln : nat, m <= n -> n.+1 - m = (n - m).+1
n.+1 - m.+1 = (n - m.+1).+1
n: nat H: 0 <= n
n.+1 - 0 = (n - 0).+1
byrewrite2 nat_sub_zero_r.
n, m: nat H: m.+1 <= n IHm: foralln : nat, m <= n -> n.+1 - m = (n - m).+1
n.+1 - m.+1 = (n - m.+1).+1
n, m: nat H: m.+1 <= n IHm: foralln : nat, m <= n -> n.+1 - m = (n - m).+1
n - m = (n - m.+1).+1
n, m: nat H: m.+1 <= n IHm: foralln : nat, m <= n -> n.+1 - m = (n - m).+1
n - m = (nat_pred (n - m)).+1
n, m: nat H: m.+1 <= n IHm: foralln : nat, m <= n -> n.+1 - m = (n - m).+1
(nat_pred (n - m)).+1 = n - m
n, m: nat H: m.+1 <= n IHm: foralln : nat, m <= n -> n.+1 - m = (n - m).+1
0 < n - m
byapply equiv_lt_lt_sub.Defined.(** Under certain conditions, subtracting a predecessor is the successor of the subtraction. *)
n, m: nat
0 < m -> m < n -> n - nat_pred m = (n - m).+1
n, m: nat
0 < m -> m < n -> n - nat_pred m = (n - m).+1
n: nat
forallx : nat,
(funx0 : nat =>
x0 < n -> n - nat_pred x0 = (n - x0).+1) x.+1
n, m: nat H1: m.+1 < n
n - nat_pred m.+1 = (n - m.+1).+1
n, m: nat H1: m.+1 < n
n - nat_pred m.+1 = (nat_pred (n - m)).+1
n, m: nat H1: m.+1 < n
n - nat_pred m.+1 = n - m
n, m: nat H1: m.+1 < n
0 < n - m
n, m: nat H1: m.+1 < n
0 < n - m
n, m: nat H1: m.+1 < n
m < n
exact (lt_trans _ H1).Defined.(** Subtracting from a sum is the sum of subtracting from the second summand. *)
m, n, k: nat
k <= m -> n + m - k = n + (m - k)
m, n, k: nat
k <= m -> n + m - k = n + (m - k)
m, k: nat H: k <= m
0 + m - k = 0 + (m - k)
m, n, k: nat H: k <= m IHn: n + m - k = n + (m - k)
n.+1 + m - k = n.+1 + (m - k)
m, k: nat H: k <= m
0 + m - k = 0 + (m - k)
reflexivity.
m, n, k: nat H: k <= m IHn: n + m - k = n + (m - k)
n.+1 + m - k = n.+1 + (m - k)
m, n, k: nat H: k <= m IHn: n + m - k = n + (m - k)
(n + m).+1 - k = (n + (m - k)).+1
m, n, k: nat H: k <= m IHn: n + m - k = n + (m - k)
k <= n + m
m, n, k: nat H: k <= m IHn: n + m - k = n + (m - k)
(n + m - k).+1 = (n + (m - k)).+1
m, n, k: nat H: k <= m IHn: n + m - k = n + (m - k)
k <= n + m
exact _.Defined.(** Subtracting from a sum is the sum of subtracting from the first summand. *)
n, m, k: nat
k <= n -> n + m - k = n - k + m
n, m, k: nat
k <= n -> n + m - k = n - k + m
n, m, k: nat l: k <= n
n + m - k = n - k + m
n, m, k: nat l: k <= n
m + n - k = n - k + m
n, m, k: nat l: k <= n
m + (n - k) = n - k + m
apply nat_add_comm.Defined.(** Subtracting a subtraction is the subtrahend. *)
n, m: nat
n <= m -> m - (m - n) = n
n, m: nat
n <= m -> m - (m - n) = n
n: nat
n - (n - n) = n
n, m: nat H: n <= m IHleq: m - (m - n) = n
m.+1 - (m.+1 - n) = n
n: nat
n - (n - n) = n
byrewrite nat_sub_cancel, nat_sub_zero_r.
n, m: nat H: n <= m IHleq: m - (m - n) = n
m.+1 - (m.+1 - n) = n
n, m: nat H: n <= m IHleq: m - (m - n) = n
m.+1 - (m - n).+1 = n
exact IHleq.Defined.(** Multiplication on the left distributes over subtraction. *)
n, m, k: nat
n * (m - k) = n * m - n * k
n, m, k: nat
n * (m - k) = n * m - n * k
m, k: nat
0 * (m - k) = 0 * m - 0 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k
n.+1 * (m - k) = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k
n.+1 * (m - k) = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k l: k <= m
n.+1 * (m - k) = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: k > m
n.+1 * (m - k) = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k l: k <= m
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: k > m
n.+1 * (m - k) = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: m <= k
n.+1 * (m - k) = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: m - k = 0
n.+1 * (m - k) = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: m - k = 0
n.+1 * 0 = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: m - k = 0
0 = n.+1 * m - n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: m - k = 0
n.+1 * m - n.+1 * k = 0
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: m - k = 0
n.+1 * m <= n.+1 * k
n, m, k: nat IHn: forallmk : nat, n * (m - k) = n * m - n * k r: m - k = 0
m <= k
byapply equiv_nat_sub_leq.Defined.(** Multiplication on the right distributes over subtraction. *)
n, m, k: nat
(n - m) * k = n * k - m * k
n, m, k: nat
(n - m) * k = n * k - m * k
n, m, k: nat
k * (n - m) = k * n - k * m
apply nat_dist_sub_l.Defined.(** *** Monotonicity of subtraction *)(** Subtraction is monotone in the left argument. *)
n, m, k: nat
n <= m -> n - k <= m - k
n, m, k: nat
n <= m -> n - k <= m - k
n, m, k: nat H: n <= m
n - k <= m - k
n, m, k: nat H: n <= m l: k <= n
n - k <= m - k
n, m, k: nat H: n <= m r: k > n
n - k <= m - k
n, m, k: nat H: n <= m l: k <= n
n - k <= m - k
n, m, k: nat H: n <= m l: k <= n
k + (n - k) <= k + (m - k)
n, m, k: nat H: n <= m l: k <= n
n <= m
n, m, k: nat H: n <= m l: k <= n
k <= m
n, m, k: nat H: n <= m l: k <= n
k <= n
n, m, k: nat H: n <= m l: k <= n
n <= m
exact H.
n, m, k: nat H: n <= m l: k <= n
k <= m
rapply leq_trans.
n, m, k: nat H: n <= m l: k <= n
k <= n
exact l.
n, m, k: nat H: n <= m r: k > n
n - k <= m - k
n, m, k: nat H: n <= m r: n <= k
n - k <= m - k
n, m, k: nat H: n <= m r: n - k = 0
n - k <= m - k
n, m, k: nat H: n <= m r: 0 = 0
0 <= m - k
exact _.Defined.Hint Immediate nat_sub_monotone_l : typeclass_instances.(** Subtraction is contravariantly monotone in the right argument. *)
n, m, k: nat
n <= m -> k - m <= k - n
n, m, k: nat
n <= m -> k - m <= k - n
n, m, k: nat H: n <= m
k - m <= k - n
n, m: nat H: n <= m
0 - m <= 0 - n
n, m, k: nat H: n <= m IHk: k - m <= k - n
k.+1 - m <= k.+1 - n
n, m: nat H: n <= m
0 - m <= 0 - n
byrewrite nat_sub_zero_l.
n, m, k: nat H: n <= m IHk: k - m <= k - n
k.+1 - m <= k.+1 - n
n, m, k: nat H: n <= m IHk: k - m <= k - n l: m <= k
k.+1 - m <= k.+1 - n
n, m, k: nat H: n <= m IHk: k - m <= k - n r: m > k
k.+1 - m <= k.+1 - n
n, m, k: nat H: n <= m IHk: k - m <= k - n l: m <= k
k.+1 - m <= k.+1 - n
rewrite2 nat_sub_succ_l; exact _.
n, m, k: nat H: n <= m IHk: k - m <= k - n r: m > k
k.+1 - m <= k.+1 - n
n, m, k: nat H: n <= m IHk: k - m <= k - n r: k.+1 - m = 0
k.+1 - m <= k.+1 - n
n, m, k: nat H: n <= m IHk: k - m <= k - n r: 0 = 0
0 <= k.+1 - n
exact _.Defined.Hint Immediate nat_sub_monotone_r : typeclass_instances.(** *** Order-reflection lemmas *)(** Subtraction reflects [<=] in the left argument. *)
n, m, k: nat
k <= m -> n - k <= m - k -> n <= m
n, m, k: nat
k <= m -> n - k <= m - k -> n <= m
n, m, k: nat ineq1: k <= m ineq2: n - k <= m - k
n <= m
n, m, k: nat ineq1: k <= m ineq2: n - k + k <= m - k + k
n <= m
n, m, k: nat ineq1: k <= m ineq2: n - k + k <= m - k + k
n - k + k <= m
n, m, k: nat ineq1: k <= m ineq2: n - k + k <= m - k + k
m - k + k <= m
byrewrite nat_add_sub_l_cancel.Defined.(** Subtraction reflects [<=] in the right argument contravariantly. *)
n, m, k: nat
m <= k -> n <= k -> k - n <= k - m -> m <= n
n, m, k: nat
m <= k -> n <= k -> k - n <= k - m -> m <= n
n, m, k: nat H1: m <= k H2: n <= k H3: k - n <= k - m
m <= n
n, m, k: nat H1: m <= k H2: n <= k H3: k - (k - m) <= k - (k - n)
m <= n
rewrite2 nat_sub_sub_cancel_r in H3; exact _.Defined.(** *** Movement lemmas *)(** Given an inequality [n < m] we can move around a summand or subtrahend [k] from either side. *)
n, m, k: nat
n - k <= m -> n <= k + m
n, m, k: nat
n - k <= m -> n <= k + m
n, m, k: nat H: n - k <= m
n <= k + m
n, m, k: nat H: n - k <= m
n <= m + k
n, m, k: nat H: n - k + k <= m + k
n <= m + k
rapply leq_trans.Defined.
n, m, k: nat
n - k <= m -> n <= m + k
n, m, k: nat
n - k <= m -> n <= m + k
n, m, k: nat
n - k <= m -> n <= k + m
apply leq_moveL_Mn.Defined.
n, m, k: nat
k <= m -> n <= m - k -> k + n <= m
n, m, k: nat
k <= m -> n <= m - k -> k + n <= m
n, m, k: nat H1: k <= m H2: n <= m - k
k + n <= m
n, m, k: nat H1: k <= m H2: n <= m - k
k + n - k <= m - k
byrewrite nat_add_sub_cancel_l.Defined.
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: nat
k <= m -> n <= m - k -> k + n <= m
apply leq_moveR_Mn.Defined.
n, m, k: nat
n + k <= m -> n <= m - k
n, m, k: nat
n + k <= m -> n <= m - k
n, m, k: nat H: n + k <= m
n <= m - k
n, m, k: nat H: n + k <= m
n + k <= m - k + k
rapply leq_trans.Defined.
n, m, k: nat
n <= m + k -> n - k <= m
n, m, k: nat
n <= m + k -> n - k <= m
n, m, k: nat H: n <= m + k
n - k <= m
n, m, k: nat H: n - k <= m + k - k
n - k <= m
byrewrite nat_add_sub_cancel_r in H.Defined.
n, m, k: nat
n - k < m -> n < k + m
n, m, k: nat
n - k < m -> n < k + m
n, m, k: nat H: n - k < m
n < k + m
n, m, k: nat H: k + (n - k) < k + m
n < k + m
rapply lt_leq_lt_trans.Defined.
n, m, k: nat
n - k < m -> n < m + k
n, m, k: nat
n - k < m -> n < m + k
n, m, k: nat
n - k < m -> n < k + m
apply lt_moveL_Mn.Defined.
n, m, k: nat
k < m -> n < m - k -> k + n < m
n, m, k: nat
k < m -> n < m - k -> k + n < m
n, m, k: nat H1: k < m H2: n < m - k
k + n < m
n, m, k: nat H1: k < m H2: n < m - k
n + k < m
rapply (leq_moveR_nM (n:=n.+1) k).Defined.
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: nat
k < m -> n < m - k -> k + n < m
apply lt_moveR_Mn.Defined.
n, m, k: nat
n + k < m -> n < m - k
n, m, k: nat
n + k < m -> n < m - k
n, m, k: nat H: n + k < m
n < m - k
rapply leq_moveL_nV.Defined.
n, m, k: nat
k <= n -> n < k + m -> n - k < m
n, m, k: nat
k <= n -> n < k + m -> n - k < m
n, m, k: nat H1: k <= n H2: n < k + m
(n - k).+1 <= m
n, m, k: nat H1: k <= n H2: n < k + m
n.+1 - k <= m
n, m, k: nat H1: k <= n H2: n < k + m
n.+1 - k <= k + m - k
byapply nat_sub_monotone_l.Defined.(** ** Properties of powers *)(** [0] to any power is [0] unless that power is [0] in which case it is [1]. *)
n: nat
nat_pow 0 n = (if dec (n = 0) then1else0)
n: nat
nat_pow 0 n = (if dec (n = 0) then1else0)
destruct n; reflexivity.Defined.(** Any number to the power of [0] is [1]. *)Definitionnat_pow_zero_r@{} n : nat_pow n 0 = 1
:= idpath.(** [1] to any power is [1]. *)
n: nat
nat_pow 1 n = 1
n: nat
nat_pow 1 n = 1
1 = 1
n: nat IHn: nat_pow 1 n = 1
nat_pow 1 n + 0 = 1
n: nat IHn: nat_pow 1 n = 1
nat_pow 1 n + 0 = 1
n: nat IHn: nat_pow 1 n = 1
nat_pow 1 n = 1
exact IHn.Defined.(** Any number to the power of [1] is itself. *)Definitionnat_pow_one_r@{} n : nat_pow n 1 = n
:= nat_mul_one_r _.(** Exponentiation of natural numbers is distributive over addition on the left. *)
n, m, k: nat
nat_pow n (m + k) = nat_pow n m * nat_pow n k
n, m, k: nat
nat_pow n (m + k) = nat_pow n m * nat_pow n k
n, k: nat
nat_pow n k = nat_pow n k + 0
n, m, k: nat IHm: nat_pow n (m + k) = nat_pow n m * nat_pow n k
n * nat_pow n (m + k) = n * nat_pow n m * nat_pow n k
n, k: nat
nat_pow n k = nat_pow n k + 0
n, k: nat
nat_pow n k + 0 = nat_pow n k
apply nat_add_zero_r.
n, m, k: nat IHm: nat_pow n (m + k) = nat_pow n m * nat_pow n k
n * nat_pow n (m + k) = n * nat_pow n m * nat_pow n k
n, m, k: nat IHm: nat_pow n (m + k) = nat_pow n m * nat_pow n k
n * nat_pow n (m + k) =
n * (nat_pow n m * nat_pow n k)
exact (ap _ IHm).Defined.(** Exponentiation of natural numbers is distributive over multiplication on the right. *)
n, m, k: nat
nat_pow (n * m) k = nat_pow n k * nat_pow m k
n, m, k: nat
nat_pow (n * m) k = nat_pow n k * nat_pow m k
n, m: nat
1 = 1
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
n * m * nat_pow (n * m) k =
n * nat_pow n k * (m * nat_pow m k)
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
n * m * nat_pow (n * m) k =
n * nat_pow n k * (m * nat_pow m k)
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
n * (m * nat_pow (n * m) k) =
n * nat_pow n k * (m * nat_pow m k)
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
n * (m * nat_pow (n * m) k) =
n * (nat_pow n k * (m * nat_pow m k))
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
m * nat_pow (n * m) k =
nat_pow n k * (m * nat_pow m k)
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
m * nat_pow (n * m) k = m * nat_pow m k * nat_pow n k
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
m * nat_pow (n * m) k =
m * (nat_pow m k * nat_pow n k)
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
nat_pow (n * m) k = nat_pow m k * nat_pow n k
n, m, k: nat IHk: nat_pow (n * m) k = nat_pow n k * nat_pow m k
nat_pow (n * m) k = nat_pow n k * nat_pow m k
exact IHk.Defined.(** Exponentiation of natural numbers is distributive over multiplication on the left. *)
n, m, k: nat
nat_pow n (m * k) = nat_pow (nat_pow n m) k
n, m, k: nat
nat_pow n (m * k) = nat_pow (nat_pow n m) k
n, k: nat
1 = nat_pow 1 k
n, m, k: nat IHm: nat_pow n (m * k) = nat_pow (nat_pow n m) k
nat_pow n (k + m * k) = nat_pow (n * nat_pow n m) k
n, k: nat
1 = nat_pow 1 k
exact (nat_pow_one_l _)^.
n, m, k: nat IHm: nat_pow n (m * k) = nat_pow (nat_pow n m) k
nat_pow n (k + m * k) = nat_pow (n * nat_pow n m) k
n, m, k: nat IHm: nat_pow n (m * k) = nat_pow (nat_pow n m) k
nat_pow n k * nat_pow n (m * k) =
nat_pow (n * nat_pow n m) k
n, m, k: nat IHm: nat_pow n (m * k) = nat_pow (nat_pow n m) k
nat_pow n k * nat_pow n (m * k) =
nat_pow n k * nat_pow (nat_pow n m) k
n, m, k: nat IHm: nat_pow n (m * k) = nat_pow (nat_pow n m) k
nat_pow n (m * k) = nat_pow (nat_pow n m) k
exact IHm.Defined.(** *** Monotonicity of powers *)
n, m, k: nat
n <= m -> nat_pow k.+1 n <= nat_pow k.+1 m
n, m, k: nat
n <= m -> nat_pow k.+1 n <= nat_pow k.+1 m
intros H; induction H; exact _.Defined.
n, m, k: nat
n <= m -> nat_pow n k <= nat_pow m k
n, m, k: nat
n <= m -> nat_pow n k <= nat_pow m k
intros H; induction k; exact _.Defined.(** ** Strong induction *)(** Sometimes using [nat_ind] is not sufficient to prove a statement as it may be difficult to prove [P n -> P n.+1]. We can strengthen the induction hypothesis by assuming that [P m] holds for all [m] less than [n]. This is known as strong induction. *)
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n
foralln : nat, P n
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n
foralln : nat, P n
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat
P n
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat
forallm : nat, m < n -> P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n m: nat H: m < 0
P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat IHn: forallm : nat, m < n -> P m m: nat H: m < n.+1
P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat IHn: forallm : nat, m < n -> P m m: nat H: m < n.+1
P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat IHn: forallm : nat, m < n -> P m m: nat H: m <= n
P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat IHn: forallm : nat, m < n -> P m m: nat H: ((m < n) + (m = n))%type
P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat IHn: forallm : nat, m < n -> P m m: nat H: m < n
P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat IHn: forallm : nat, m < n -> P m m: nat p: m = n
P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat IHn: forallm : nat, m < n -> P m m: nat H: m < n
P m
byapply IHn.
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n n: nat IHn: forallm : nat, m < n -> P m m: nat p: m = n
P m
P: nat -> Type IH_strong: foralln : nat,
(forallm : nat, m < n -> P m) -> P n m: nat IHn: forallm0 : nat, m0 < m -> P m0
P m
byapply IH_strong.Defined.(** ** An induction principle for two variables with a constraint. *)
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1
forallnm : nat, m <= n -> P n m
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1
forallnm : nat, m <= n -> P n m
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 m: nat H: m <= 0
P 0 m
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat H: m <= n.+1
P n.+1 m
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 m: nat H: m <= 0
P 0 m
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1
P 00
apply Hn0.
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat H: m <= n.+1
P n.+1 m
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m H: 0 <= n.+1
P n.+10
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat H: m.+1 <= n.+1
P n.+1 m.+1
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m H: 0 <= n.+1
P n.+10
apply Hn0.
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat H: m.+1 <= n.+1
P n.+1 m.+1
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat H: ((m.+1 < n.+1) + (m.+1 = n.+1))%type
P n.+1 m.+1
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat H: m.+1 < n.+1
P n.+1 m.+1
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat
P m.+1 m.+1
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat H: m.+1 < n.+1
P n.+1 m.+1
P: nat -> nat -> Type Hn0: foralln : nat, P n 0 Hnn: foralln : nat, P n.+1 n.+1 IH: forallnm : nat,
m < n ->
(forallm' : nat, m' <= n -> P n m') ->
P n.+1 m.+1 n: nat IHn: forallm : nat, m <= n -> P n m m: nat H: m.+1 < n.+1