(in-package "ACL2") ;; This book contains a proof of Fermat's Theorem: if p is a prime and m ;; is not divisible by p, then mod(m^(p-1),p) = 1. ;; The proof depends on Euclid's Theorem: (include-book "euclid") ;; We shall construct two lists of integers, each of which is a permutation of the other. (defun perm (a b) (if (consp a) (if (member (car a) b) (perm (cdr a) (remove1 (car a) b)) ()) (not (consp b)))) ;; The first list is positives(p-1) = (1, 2, ..., p-1): (defun positives (n) (if (zp n) () (cons n (positives (1- n))))) ;;The second list is mod-prods(p-1,a,p) = (mod(a,p), mod(2*a,p), ..., mod((p-1)*a,p)): (defun mod-prods (n m p) (if (zp n) () (cons (mod (* m n) p) (mod-prods (1- n) m p)))) ;; The proof is based on the pigeonhole principle. (defthm not-member-remove1 (implies (not (member x l)) (not (member x (remove1 y l))))) (defthm perm-member (implies (and (perm a b) (member x a)) (member x b))) (defun distinct-positives (l n) (if (consp l) (and (not (zp n)) (not (zp (car l))) (<= (car l) n) (not (member (car l) (cdr l))) (distinct-positives (cdr l) n)) t)) (defthm member-positives (iff (member x (positives n)) (and (not (zp n)) (not (zp x)) (<= x n)))) (defthm pigeonhole-principle-lemma-1 (implies (and (natp n) (distinct-positives l (1+ n)) (not (member (1+ n) l))) (distinct-positives l n))) (defthm pigeonhole-principle-lemma-2 (implies (and (not (zp n)) (distinct-positives l n) (member n l)) (distinct-positives (remove1 n l) (+ -1 n)))) (defthm len-remove1 (implies (member x l) (equal (len (remove1 x l)) (1- (len l))))) (defun pigeonhole-induction (l) (declare (xargs :measure (len l))) (if (consp l) (if (member (len l) l) (pigeonhole-induction (remove1 (len l) l)) (pigeonhole-induction (cdr l))) t)) (defthm pigeonhole-principle (implies (distinct-positives l (len l)) (perm (positives (len l)) l)) :rule-classes () :hints (("Goal" :induct (pigeonhole-induction l)))) ;; We must show that mod-prods(p-1,m,p) is a list of length p-1 of distinct ;; integers between 1 and p-1. (defthm len-mod-prods (implies (natp n) (equal (len (mod-prods n m p)) n))) (defthm mod-distinct-lemma (implies (and (integerp p) (not (zp i)) (< i p) (not (zp j)) (< j p)) (< (abs (- i j)) p)) :rule-classes ()) (defthm mod-distinct (implies (and (primep p) (not (zp i)) (< i p) (not (zp j)) (< j p) (not (= j i)) (integerp m) (not (divides p m))) (not (equal (mod (* m i) p) (mod (* m j) p)))) :hints (("Goal" :in-theory (enable divides) :use (mod-distinct-lemma (:instance divides-leq (x p) (y (abs (- i j)))) (:instance mod-equal-int (a (* m i)) (b (* m j)) (n p)) (:instance mod-equal-int (a (* m j)) (b (* m i)) (n p)) (:instance euclid (a (abs (- i j))) (b m)))))) (defthm mod-p-bnds (implies (and (primep p) (not (zp i)) (< i p) (integerp m) (not (divides p m))) (and (< 0 (mod (* m i) p)) (> p (mod (* m i) p)))) :rule-classes () :hints (("Goal" :in-theory (enable divides) :use ((:instance mod-bnd-1 (m (* m i)) (n p)) (:instance mod-0-int (m (* m i)) (n p)) (:instance natp-mod-2 (m (* m i)) (n p)) (:instance euclid (a i) (b m)))))) (defthm mod-prods-distinct-positives-lemma (implies (and (primep p) (integerp p) (>= p 2) (natp n) (< n p) (integerp r) (< r n) (integerp m) (not (divides p m))) (not (member (mod (* m n) p) (mod-prods r m p))))) (defthm mod-prods-distinct-positives (implies (and (primep p) (natp n) (< n p) (integerp m) (not (divides p m))) (distinct-positives (mod-prods n m p) (1- p))) :rule-classes () :hints (("Subgoal *1/5.1" :use ((:instance mod-p-bnds (i n)))))) (defthm perm-mod-prods (implies (and (primep p) (integerp m) (not (divides p m))) (perm (positives (1- p)) (mod-prods (1- p) m p))) :rule-classes () :hints (("Goal" :use ((:instance mod-prods-distinct-positives (n (1- p))) (:instance pigeonhole-principle (l (mod-prods (1- p) m p))))))) ;; The product of the members of a list is invariant under permutation: (defun times-list (l) (if (consp l) (* (ifix (car l)) (times-list (cdr l))) 1)) (defthm times-list-remove1 (implies (and (consp l) (member x l)) (equal (times-list l) (* (ifix x) (times-list (remove1 x l))))) :rule-classes ()) (defthm perm-times-list (implies (perm l1 l2) (equal (times-list l1) (times-list l2))) :rule-classes () :hints (("Subgoal *1/2" :use (:instance times-list-remove1 (x (car l1)) (l l2))))) ;; It follows that the product of the members of mod-prods(p-1,m,p) is (p-1)!. (defthm times-list-positives (equal (times-list (positives n)) (fact n))) (defthm times-list-equal-fact (implies (perm (positives n) l) (equal (times-list l) (fact n))) :hints (("Goal" :use ((:instance perm-times-list (l1 (positives n)) (l2 l)))))) (defthm times-list-mod-prods (implies (and (primep p) (integerp m) (not (divides p m))) (equal (times-list (mod-prods (1- p) m p)) (fact (1- p)))) :hints (("Goal" :use (perm-mod-prods)))) ;; On the other hand, the product mod p may be computed as follows. (defthm mod-mod-prods-lemma-1 (implies (and (integerp x) (integerp y) (integerp z) (not (zp n)) (= (mod x n) (mod y n))) (= (mod (* x (mod z n)) n) (mod (* y z) n))) :rule-classes () :hints (("Goal" :use ((:instance mod-mod-times (a z) (b x)) (:instance mod-mod-times (a x) (b z)) (:instance mod-mod-times (a y) (b z)))))) (defthm mod-mod-prods-lemma-2 (implies (and (not (zp p)) (integerp m) (not (zp n)) (equal (mod (times-list (mod-prods (+ n -1) m p)) p) (mod (* (fact (1- n)) (expt m (+ n -1))) p))) (equal (mod (times-list (mod-prods n m p)) p) (mod (* (fact n) (expt m n)) p))) :hints (("Goal" :use ((:instance mod-mod-prods-lemma-1 (n p) (x (times-list (mod-prods (1- n) m p))) (y (* (fact (1- n)) (expt m (1- n)))) (z (* m n))))))) (defthm mod-mod-prods (implies (and (not (zp p)) (integerp m) (natp n)) (equal (mod (times-list (mod-prods n m p)) p) (mod (* (fact n) (expt m n)) p))) :rule-classes ()) ;; Fermat's theorem now follows easily. (defthm not-divides-p-fact (implies (and (primep p) (natp n) (< n p)) (not (divides p (fact n)))) :rule-classes () :hints (("Subgoal *1/5" :use ((:instance euclid (a (fact (1- n))) (b n)) (:instance divides-leq (x p) (y n)))) ("Subgoal *1/1" :use ((:instance divides-leq (x p) (y 1)))))) (defthm mod-times-prime (implies (and (primep p) (integerp a) (integerp b) (integerp c) (not (divides p a)) (= (mod (* a b) p) (mod (* a c) p))) (= (mod b p) (mod c p))) :rule-classes () :hints (("Goal" :in-theory (enable divides) :use ((:instance euclid (b (- b c))) (:instance mod-equal-int (n p) (a (* a b)) (b (* a c))) (:instance mod-equal-int-reverse (n p) (a b) (b c)))))) (defthm fermat (implies (and (primep p) (integerp m) (not (divides p m))) (equal (mod (expt m (1- p)) p) 1)) :rule-classes () :hints (("Goal" :use (times-list-mod-prods (:instance not-divides-p-fact (n (1- p))) (:instance mod-mod-prods (n (1- p))) (:instance mod-times-prime (a (fact (1- p))) (b 1) (c (expt m (1- p)))) (:instance mod-does-nothing (m 1) (n p))))))