(* ========================================================================= *)
(* Wilson's theorem.                                                         *)
(* ========================================================================= *)

needs "Library/prime.ml";;
needs "Library/pocklington.ml";;

prioritize_num();;

(* ------------------------------------------------------------------------- *)
(* Factorial in terms of products.                                           *)
(* ------------------------------------------------------------------------- *)

let FACT_NPRODUCT = `!n. FACT(n) = nproduct(1..n) (\i. i)`;;

let FACT_NPRODUCT_ALT = `!n. FACT(n) = nproduct(2..n) (\i. i)`;;

(* ------------------------------------------------------------------------- *)
(* General "pairing up" theorem for products.                                *)
(* ------------------------------------------------------------------------- *)

let NPRODUCT_PAIRUP_INDUCT = `!f r n s. FINITE s /\ CARD s = n /\
             (!x:A. x IN s ==> ?!y. y IN s /\ ~(y = x) /\
                                    (f(x) * f(y) == 1) (mod r))
             ==> (nproduct s f == 1) (mod r)`;;

let NPRODUCT_PAIRUP = `!f r s. FINITE s /\
           (!x:A. x IN s ==> ?!y. y IN s /\ ~(y = x) /\
                                  (f(x) * f(y) == 1) (mod r))
           ==> (nproduct s f == 1) (mod r)`;;

(* ------------------------------------------------------------------------- *)
(* Hence Wilson's theorem.                                                   *)
(* ------------------------------------------------------------------------- *)

let WILSON = `!p. prime(p) ==> (FACT(p - 1) == p - 1) (mod p)`;;

(* ------------------------------------------------------------------------- *)
(* And in fact we have a converse.                                           *)
(* ------------------------------------------------------------------------- *)

let WILSON_EQ = `!p. ~(p = 1) ==> (prime p <=> (FACT(p - 1) == p - 1) (mod p))`;;