;;; Contributed by Ruben A. Gamboa ;;; This file includes a proof of the binomial theorem. (in-package "ACL2") (include-book "top") (include-book "factorial") (include-book "sumlist") ;; We begin with the definition of (choose k n), which counts the ;; number of ways k items can be selected out of n distinct items. (defun choose (k n) ; (declare (xargs :guard (and (integerp k) (integerp n) (<= 0 k) (<= k n)))) (if (and (integerp k) (integerp n) (<= 0 k) (<= k n)) (/ (factorial n) (* (factorial k) (factorial (- n k)))) 0)) ;; Unfortunately, ACL2 looks at the previous definition and assumes ;; that choose is a rational number -- not necessarily integer. So ;; our first step is to establish the fact that choose is an integer ;; function. First we need a few simplification rules. ;; The first rule is that n!/(n-1)! is equal to n..... (defthm factorial-n/n-1 (implies (and (integerp n) (<= 1 n)) (equal (* (factorial n) (/ (factorial (+ -1 n)))) n)) :hints (("Goal" :expand ((factorial n))))) ;; A more powerful rule is that n!*x/(n-1)! is equan to n*x. (local (defthm factorial-n/n-1/x (implies (and (integerp n) (<= 1 n)) (equal (* (factorial n) (/ (factorial (+ -1 n))) x) (* n x))))) ;; Now, we can prove the following lemma, which was suggested to us by ;; Matt Kaufmann (thanks, Matt!). We show that the choose function ;; can be defined by a recurrence relation. Basically, the way to ;; choose k things out of n things is to choose 1 thing and take it ;; out. Then, if we decide to choose that item, we need to pick an ;; additional k-1 things out of n-1 things; if not, we still need to ;; pick k things out of n-1 things.... The sum of those is the number ;; we want. (defthm choose-reduction (implies (and (integerp k) (integerp n) (< 0 k) (< k n)) (equal (choose k n) (+ (choose (1- k) (1- n)) (choose k (1- n))))) ; Matt K. change for v2-9: Subgoal number has changed, probably because of the ; change to call-stack to preserve quote-normal form. :hints (("Subgoal 4'" :expand ((factorial n)))) :rule-classes nil) ;; So, we can define a new function choose-mk which follows the ;; recurrence mentioned above.... (defun choose-mk (k n) (if (and (integerp k) (integerp n)) (if (and (< 0 k) (< k n)) (+ (choose-mk (1- k) (1- n)) (choose-mk k (1- n))) (if (and (<= 0 k) (<= k n)) 1 0)) 0)) ;; ...and we can prove that it's the exact same function as choose. (defthm choose-mk-choose (equal (choose-mk k n) (choose k n)) :hints (("Goal" :induct (choose-mk k n)) ("Subgoal *1/1" :use (:instance choose-reduction) :in-theory (disable choose))) :rule-classes nil) ;; Now, the function choose-mk is obviously integer, so that means ;; choose must be obviously integer! (defthm choose-is-non-negative-integer (and (integerp (choose k n)) (<= 0 (choose k n))) :hints (("Goal" :use (:instance choose-mk-choose) :in-theory (disable choose choose-mk))) :rule-classes (:rewrite :type-prescription)) ;; We can now define the binomial expansion of (x+y)^n, starting at ;; the term containing x^k. I.e., to get the entire binomial ;; expansion, use (binomial-expansion x y 0 n). (defun binomial-expansion (x y k n) (declare (xargs :measure (nfix (1+ (- n k))))) (if (and (integerp k) (integerp n) (<= 0 k) (<= k n)) (cons (* (choose k n) (expt x k) (expt y (- n k))) (binomial-expansion x y (1+ k) n)) nil)) ;; We find it useful to explicitly define the expansion of x*(x+y)^n. (defun binomial-expansion-times-x (x y k n) (declare (xargs :measure (nfix (1+ (- n k))))) (if (and (integerp k) (integerp n) (<= 0 k) (<= k n)) (cons (* (choose k n) (expt x (1+ k)) (expt y (- n k))) (binomial-expansion-times-x x y (1+ k) n)) nil)) ;; This lemma shows that our expansion for x*(x+y)^n indeed works. (defthm binomial-expansion-times-x-correct (equal (* x (sumlist (binomial-expansion x y k n))) (sumlist (binomial-expansion-times-x x y k n))) :hints (("Goal" :in-theory (disable choose)))) ;; Similarly, we define an expansion of y*(x+y)^n.... (defun binomial-expansion-times-y (x y k n) (declare (xargs :measure (nfix (1+ (- n k))))) (if (and (integerp k) (integerp n) (<= 0 k) (<= k n)) (cons (* (choose k n) (expt x k) (expt y (1+ (- n k)))) (binomial-expansion-times-y x y (1+ k) n)) nil)) ;; ...and prove it works, too. (defthm binomial-expansion-times-y-correct (equal (* y (sumlist (binomial-expansion x y k n))) (sumlist (binomial-expansion-times-y x y k n))) :hints (("Goal" :in-theory (disable choose)))) ;; The following function expands (x+y)^n in a manner reminiscent of ;; Pascal's triangle. Consider (x+y)^n. It is equal to ;; (x+y)*(x+y)^{n-1} or x*(x+y)^{n-1} + y*(x+y)^{n-1}. If we can show ;; that the binomial theorem is true for (x+y)^{n-1} (for induction, ;; for example), then we can reduce (x+y)^n to x times the binomial ;; expansion of (x+y)^{n-1} plus y times the binomial expansion of ;; (x+y)^{n-1} -- and we already have a function for x/y * the ;; binomial expansion of (x+y) from above! We start with a function ;; which computes x*(x+y)^{n-1} + y*(x+y)^{n-1} by interleaving the ;; terms from each of the two sums. I.e., x*a1, y*a1, x*a2, y*a2, etc ;; where ai are the terms in the binomial expansion of (x+y)^{n-1}. (defun binomial-expansion-triangle (x y k n) (declare (xargs :measure (nfix (1+ (- n k))))) (if (and (integerp k) (integerp n) (<= 0 k) (<= k n)) (cons (* (choose k n) (expt x (1+ k)) (expt y (- n k))) (cons (* (choose k n) (expt x k) (expt y (1+ (- n k)))) (binomial-expansion-triangle x y (1+ k) n))) nil)) ;; This is the key lemma that states that our function defined above ;; really does behave the way we said it did. (defthm binomial-expansion-times-x-plus-times-y (equal (+ (sumlist (binomial-expansion-times-x x y k n)) (sumlist (binomial-expansion-times-y x y k n))) (sumlist (binomial-expansion-triangle x y k n))) :hints (("Goal" :in-theory (disable choose expt)))) ;; The following function computes the same value, but it does it by ;; emulating Pascal's triangle directly. We will next show that this ;; function computes the same value as above, and hence that it is a ;; faithful computation of (a+b)^n. Later, we will only have to ;; reduct the two choose terms below by collecting like x^k*y^{n-k} ;; terms and we'll have the needed result. (defun binomial-expansion-pascal-triangle (x y k n) (declare (xargs :measure (nfix (1+ (- n k))))) (if (and (integerp k) (integerp n) (<= 0 k)) (if (< k n) (cons (* (choose k n) (expt x (1+ k)) (expt y (- n k))) (cons (* (choose (1+ k) n) (expt x (1+ k)) (expt y (- n k))) (binomial-expansion-pascal-triangle x y (1+ k) n))) (if (= k n) (list (* (choose k n) (expt x (1+ k)) (expt y (- n k)))) nil)) nil)) ;; Interesting that ACL2 needs a rewrite rule for this.... (local (defthm silly-inequality (implies (and (integerp k) (integerp n) (< k n)) (<= (+ 1 k) n)))) ;; Now we need to show ACL2 how to reduse some of the terms that ;; appear in the main proof below. First (choose k k) is equal to 1 ;; (except in malformed cases when it's equal to 0). (local (defthm choose-k-k (equal (choose k k) (if (and (integerp k) (<= 0 k)) 1 0)))) ;; I think this is proved elsewhere, but x^0 = 1. (local (defthm expt-x-0 (equal (expt x 0) 1))) ;; Now, the binomial-expansion-triangle function returns an empty list ;; when we want to start at item k+1 and go up to item k.... (local (defthm binomial-expansion-triangle-x-y-k-1+k (equal (binomial-expansion-triangle x y (+ 1 k) k) nil) :hints (("Goal" :expand (binomial-expansion-triangle x y (+ 1 k) K))))) ;; We also show how the last term in the binomial-expansion-triangle ;; is expanded. (local (defthm binomial-expansion-triangle-x-y-k-k-lemma (equal (binomial-expansion-triangle x y k k) (if (and (integerp k) (<= 0 k)) (list (expt x (1+ k)) (* (expt x k) y)) nil)))) ;; And finally, we can show that the Pascal triangle develops the ;; correct binomial coefficients.... (defthm binomial-expansion-pascal-triangle-correct (implies (and (integerp k) (integerp n) (<= 0 k) (<= k n)) (equal (sumlist (binomial-expansion-triangle x y k n)) (+ (* (choose k n) (expt x k) (expt y (1+ (- n k)))) (sumlist (binomial-expansion-pascal-triangle x y k n))))) :hints (("Goal" :in-theory (disable choose expt right-unicity-of-1-for-expt expt-minus distributivity-of-expt-over-* exponents-multiply functional-commutativity-of-expt-/-base exponents-add exponents-add-for-nonneg-exponents)) ("Subgoal *1/5" :in-theory (disable choose expt)))) ;; Now, we show what happens when we try to get the binomial-expansion ;; of an empty interval. (defthm binomial-expansion-zero (implies (< n k) (equal (binomial-expansion x y k n) nil))) ;; From our previous lemma, we can establish quickly that the Pascal ;; triangle computes the same value as the binomial expansion. (defthm pascal-triangle-binomial (implies (and (integerp k) (integerp n) (<= 0 k)) (equal (sumlist (binomial-expansion-pascal-triangle x y k n)) (sumlist (binomial-expansion x y (1+ k) (1+ n))))) :hints (("Goal" :induct (binomial-expansion-pascal-triangle x y k n) :in-theory (disable choose expt right-unicity-of-1-for-expt expt-minus distributivity-of-expt-over-* exponents-multiply functional-commutativity-of-expt-/-base exponents-add exponents-add-for-nonneg-exponents)) ("Subgoal *1/1''" :use ((:instance choose-reduction (k (+ 1 k)) (n (+ 1 n))))))) ;; We are almost ready now to prove the binomial theorem. First, we ;; show ACL2 how to evaluate more terms that appear in the proofs to ;; follow. For example, there's only 1 way to choose the empty set ;; out of a bunch of items -- unless we have a malformed set, in which ;; case it happens to be 0.... (defthm choose-0-n (equal (choose 0 n) (if (and (integerp n) (<= 0 n)) 1 0))) ;; The heart of the proof is the following lemma, which formalizes the ;; (x+y)^n = x*(x+y)^{n-1} + y*(x+y)^{n-1} argument given earlier. (defthm binomial-theorem-induction-lemma (implies (and (integerp n) (< 0 n)) (equal (+ (* x (sumlist (binomial-expansion x y 0 (1- n)))) (* y (sumlist (binomial-expansion x y 0 (1- n))))) (sumlist (binomial-expansion x y 0 n)))) :hints (("Goal" :in-theory (disable expt)))) ;; It's easier to reason about the following function than about the ;; real expt function -- take a look at the definition of expt to see ;; what we mean! (defun n-expt (x n) (declare (xargs :guard (and (acl2-numberp x) (integerp n) (<= n 0)))) (if (and (integerp n) (< 0 n)) (* x (n-expt x (1- n))) 1)) ;; This little theorem is pretty useful below. I'm not sure why it ;; isn't a standard theorem of ACL2, but there's probably a subtle ;; reason involving cyclic rules.... (local (defthm distributivity-2 (equal (* (+ x y) z) (+ (* x z) (* y z))))) ;; Now, we're almost there. We prove the binomial theorem, but using ;; the function n-expt instead of expt -- we told you it was easier to ;; reason about! (defthm binomial-theorem-fake (implies (and (integerp n) (<= 0 n)) (equal (n-expt (+ x y) n) (sumlist (binomial-expansion x y 0 n)))) :hints (("Goal" :induct (n-expt x n)) ("Subgoal *1/1'" :in-theory (disable binomial-expansion)) ("Subgoal *1/1'''" :by (:instance binomial-theorem-induction-lemma)))) ;; For the big step, we now show that our definition of expt really is ;; the same as expt. (defthm n-expt-expt (implies (and (integerp n) (<= 0 n)) (equal (expt x n) (n-expt x n)))) ;; And therefore, we can now prove the binomial theorem! (defthm binomial-theorem (implies (and (integerp n) (<= 0 n)) (equal (expt (+ x y) n) (sumlist (binomial-expansion x y 0 n))))) ;; Here's an added bonus. It's not obvious that the binomial ;; expansions of (x+y)^n and (y+x)^n are the same -- it's a deep ;; consequence of the fact that (choose k n) and (choose (- n k) n) ;; are the same. But, it's obvious if you look at just (x+y)^n ;; vs. (y+x)^n. So, we get the fact that the binomial expansions ;; commute x&y for free! (defthm binomial-sum-commutes (implies (and (integerp n) (<= 0 n)) (equal (sumlist (binomial-expansion x y 0 n)) (sumlist (binomial-expansion y x 0 n)))) :hints (("Goal" :use ((:instance binomial-theorem) (:instance binomial-theorem (x y) (y x))) :in-theory (disable binomial-theorem))) :rule-classes nil)