Timings for Factorial.v
Require Import Basics.Overture Basics.Tactics Basics.PathGroupoids
Basics.Decidable Spaces.Nat.Core Spaces.Nat.Division Tactics.EvalIn.
Local Set Universe Minimization ToSet.
Local Open Scope nat_scope.
(** * Factorials *)
(** ** Definition *)
Fixpoint factorial n :=
match n with
| 0 => 1
| S n => S n * factorial n
end.
(** ** Properties *)
(** The factorial of [0] is [1]. *)
Definition nat_factorial_zero : factorial 0 = 1 := idpath.
(** The factorial of [n + 1] is [n + 1] times the factorial of [n]. *)
Definition nat_factorial_succ n : factorial n.+1 = n.+1 * factorial n
:= idpath.
(** A variant of [nat_factorial_succ]. *)
Definition nat_factorial_pred n
: 0 < n -> factorial n = n * factorial (nat_pred n).
(** Every factorial is positive. *)
Instance lt_zero_factorial n : 0 < factorial n.
(** Except for [factorial 0 = factorial 1], the [factorial] function is strictly monotone. We separate out the successor case since it is used twice in the proof of the general result. *)
Definition nat_factorial_strictly_monotone_succ n
: 0 < n -> factorial n < factorial n.+1.
rewrite <- (nat_mul_one_l (factorial n)).
rapply (nat_mul_r_strictly_monotone _).
Instance nat_factorial_strictly_monotone n m
: 0 < n -> n < m -> factorial n < factorial m.
intros H1 H2; induction H2.
rapply nat_factorial_strictly_monotone_succ.
rapply nat_factorial_strictly_monotone_succ.
(** ** Divisibility *)
(** Any number less than or equal to [n] divides [factorial n]. *)
Instance nat_divides_factorial_factor n m
: 0 < n -> n <= m -> (n | factorial m).
(** [factorial] is a monotone function from [nat] to [nat] with respect to [<=] and divides. *)
Instance nat_divides_factorial_lt n m
: n <= m -> (factorial n | factorial m).
intros H; induction H; exact _.
(** A product of factorials divides the factorial of the sum. *)
Instance nat_divides_factorial_mul_factorial_add n m
: (factorial n * factorial m | factorial (n + m)).
remember (n + m) as k eqn:p.
revert k n m p; snapply nat_ind_strong; hnf; intros k IH n m p.
apply equiv_nat_add_zero in p.
rewrite_refl nat_factorial_succ.
assert (helper : forall n' m' (p' : n' + m' = k.+1), (factorial n' * factorial m' | n' * factorial k)).
destruct n'; only 1: exact _.
rewrite nat_factorial_succ.
rewrite <- nat_mul_assoc.
rapply nat_divides_mul_monotone.
lhs napply nat_add_comm; exact p.
(** Here is a variant of [nat_divides_factorial_mul_factorial_add] that is more suitable for binomial coefficients. *)
Instance nat_divides_factorial_mul_factorial_add' n m
: m <= n -> (factorial m * factorial (n - m) | factorial n).
rewrite <- (ap factorial (nat_add_sub_r_cancel H)).
apply nat_divides_factorial_mul_factorial_add.