Documentation

Mathlib.Data.Nat.Factorial.Basic

Factorial and variants #

This file defines the factorial, along with the ascending and descending variants. For the proof that the factorial of n counts the permutations of an n-element set, see Fintype.card_perm.

Main declarations #

Nat.factorial n is the factorial of n.

Equations
    Instances For

      factorial notation (n)! for Nat.factorial n. In Lean, names can end with exclamation marks (e.g. List.get!), so you cannot write n! in Lean, but must write (n)! or n ! instead. The former is preferred, since Lean can confuse the ! in n ! as the (prefix) Boolean negation operation in some cases. For numerals the parentheses are not required, so e.g. 0! or 1! work fine.

      Equations
        Instances For
          theorem Nat.dvd_factorial {m n : } :
          0 < mm nm n.factorial
          theorem Nat.factorial_lt {m n : } (hn : 0 < n) :
          theorem Nat.factorial_lt_of_lt {m n : } (hn : 0 < n) (h : n < m) :
          @[simp]
          theorem Nat.one_lt_factorial {n : } :
          1 < n.factorial 1 < n
          theorem Nat.factorial_inj {m n : } (hn : 1 < n) :
          theorem Nat.factorial_inj' {m n : } (h : 1 < n 1 < m) :
          theorem Nat.add_factorial_lt_factorial_add {i n : } (hi : 2 i) (hn : 1 n) :
          i + n.factorial < (i + n).factorial

          Ascending and descending factorials #

          def Nat.ascFactorial (n : ) :

          n.ascFactorial k = n (n + 1) ⋯ (n + k - 1). This is closely related to ascPochhammer, but much less general.

          Equations
            Instances For

              (n + 1).ascFactorial k = (n + k) ! / n ! but without ℕ-division. See Nat.ascFactorial_eq_div for the version with ℕ-division.

              theorem Nat.factorial_mul_ascFactorial' (n k : ) (h : 0 < n) :
              (n - 1).factorial * n.ascFactorial k = (n + k - 1).factorial

              n.ascFactorial k = (n + k - 1)! / (n - 1)! for n > 0 but without ℕ-division. See Nat.ascFactorial_eq_div for the version with ℕ-division. Consider using factorial_mul_ascFactorial to avoid complications of ℕ-subtraction.

              theorem Nat.ascFactorial_eq_div (n k : ) :

              Avoid in favor of Nat.factorial_mul_ascFactorial if you can. ℕ-division isn't worth it.

              theorem Nat.ascFactorial_eq_div' (n k : ) (h : 0 < n) :
              n.ascFactorial k = (n + k - 1).factorial / (n - 1).factorial

              Avoid in favor of Nat.factorial_mul_ascFactorial' if you can. ℕ-division isn't worth it.

              theorem Nat.ascFactorial_of_sub {n k : } :
              (n - k) * (n - k + 1).ascFactorial k = (n - k).ascFactorial (k + 1)
              theorem Nat.pow_lt_ascFactorial' (n k : ) :
              (n + 1) ^ (k + 2) < (n + 1).ascFactorial (k + 2)
              theorem Nat.pow_lt_ascFactorial (n : ) {k : } :
              2 k → (n + 1) ^ k < (n + 1).ascFactorial k
              theorem Nat.ascFactorial_lt_pow_add (n : ) {k : } :
              2 k(n + 1).ascFactorial k < (n + k) ^ k
              def Nat.descFactorial (n : ) :

              n.descFactorial k = n! / (n - k)! (as seen in Nat.descFactorial_eq_div), but implemented recursively to allow for "quick" computation when using norm_num. This is closely related to descPochhammer, but much less general.

              Equations
                Instances For
                  @[simp]
                  theorem Nat.descFactorial_succ (n k : ) :
                  n.descFactorial (k + 1) = (n - k) * n.descFactorial k
                  theorem Nat.succ_descFactorial (n k : ) :
                  (n + 1 - k) * (n + 1).descFactorial k = (n + 1) * n.descFactorial k
                  @[simp]
                  theorem Nat.descFactorial_pos {n k : } :
                  theorem Nat.descFactorial_of_lt {n k : } :
                  n < kn.descFactorial k = 0

                  Alias of the reverse direction of Nat.descFactorial_eq_zero_iff_lt.

                  n.descFactorial k = n! / (n - k)! but without ℕ-division. See Nat.descFactorial_eq_div for the version using ℕ-division.

                  theorem Nat.descFactorial_eq_div {n k : } (h : k n) :

                  Avoid in favor of Nat.factorial_mul_descFactorial if you can. ℕ-division isn't worth it.

                  theorem Nat.pow_sub_lt_descFactorial' {n k : } :
                  k + 2 n → (n - (k + 1)) ^ (k + 2) < n.descFactorial (k + 2)
                  theorem Nat.pow_sub_lt_descFactorial {n k : } :
                  2 kk n → (n + 1 - k) ^ k < n.descFactorial k
                  theorem Nat.descFactorial_lt_pow {n : } (hn : n 0) {k : } :
                  2 kn.descFactorial k < n ^ k

                  Factorial via binary splitting. #

                  We prove this is equal to the standard factorial and mark it @[csimp].

                  We could proceed further, with either Legendre or Luschny methods.

                  This is the highest factorial I can #eval using the naive implementation without a stack overflow:

                  /-- info: 114716 -/
                  #guard_msgs in
                  #eval 9718 ! |>.log2
                  

                  Similarly, evaluation of ascFactorial 100 15000 fails with the naive implementation but works with the binary recursion.

                  We could implement a tail-recursive version (or just use Nat.fold), but instead let's jump straight to binary splitting.

                  @[irreducible]

                  ascFactorial implemented using binary splitting.

                  While this still performs the same number of multiplications, the big-integer operands to each are much smaller.

                  Equations
                    Instances For

                      Factorial implemented using binary splitting.

                      While this still performs the same number of multiplications, the big-integer operands to each are much smaller.

                      Equations
                        Instances For
                          @[deprecated Nat.ascFactorialBinary (since := "2025-10-21")]

                          This function was used in the definition of factorialBinarysplitting before it was migrated to ascFactorialBinary.

                          Equations
                            Instances For
                              @[deprecated Nat.factorial_mul_ascFactorial (since := "2025-10-21")]
                              theorem Nat.factorialBinarySplitting.factorial_mul_prodRange (lo hi : ) (h : lo < hi) :
                              lo.factorial * prodRange (lo + 1) (hi + 1) = hi.factorial
                              @[deprecated Nat.factorial_eq_factorialBinarySplitting (since := "2025-10-21")]

                              Alias of Nat.factorial_eq_factorialBinarySplitting.

                              descFactorial implemented using binary splitting.

                              Equations
                                Instances For

                                  We are now limited by time, not stack space, and this is much faster than even the tail-recursive version.

                                  #time -- Less than 1s. (Tail-recursive version takes longer for `(10^5) !`.)
                                  #eval (10^6) ! |>.log2