  * *****************************************************************
  * NB: This CHANGES file no longer gives a comprehensive list of   *
  * changes made to the system. In particular, most changes in the  *
  * Multivariate theories are excluded, simply because there are    *
  * so many of them that tracking them would be tedious. For more   *
  * detailed update lists, consult the git logs ("git log" if you   *
  * have the system downloaded) or the list of commits on the Web   *
  * page: https://github.com/jrh13/hol-light/commits/master         *
  * *****************************************************************

Wed  9th Oct 2024               Library/ringtheory.ml

Added a number of miscellaneous and simple ring theory lemmas:

        FIELD_HOMOMORPHISM_DIV
        FIELD_HOMOMORPHISM_INV
        FINITE_MONOMIAL_VARS
        FINITE_MONOMIAL_VARS_1
        IMAGE_POLY_EVAL
        IMAGE_POLY_EXTEND_1
        IN_IDEAL_GENERATED_SELF
        IN_IDEAL_GENERATED_SING
        IN_IDEAL_GENERATED_SING_EQ
        ISOMORPHIC_TRANSPORT_OF_RING
        POLY_DEG_SUBRING_GENERATED
        POLY_EXTEND_FROM_SUBRING_GENERATED
        POLY_EXTEND_INTO_SUBRING_GENERATED
        POLY_SUBRING_GENERATED_1
        POLY_SUBRING_GENERATED_CLAUSES
        RING_0_IN_SUBRING_GENERATED
        RING_1_IN_SUBRING_GENERATED
        RING_ADD_IN_SUBRING_GENERATED
        RING_HOMOMORPHISM_INV
        RING_MONOMORPHISM_INTO_SUBRING
        RING_MUL_IN_SUBRING_GENERATED
        RING_NEG_IN_SUBRING_GENERATED
        RING_POW_IN_SUBRING_GENERATED
        RING_PRODUCT_SUBRING_GENERATED
        RING_PRODUCT_SUBRING_GENERATED_GEN
        RING_SUM_CASES
        SUBRING_GENERATED_INC_GEN

Wed  9th Oct 2024               EC/ccsm2.ml

Added two more easy theorems by analogy with the earlier additions
for NIST curves:

  SM2_GROUP_ORDER =
    |- CARD (group_carrier sm2_group) = n_sm2

  SM2_GROUP_ELEMENT_ORDER =
    |- !P. P IN group_carrier sm2_group
           ==> group_element_order sm2_group P =
               (if P = group_id sm2_group then 1 else n_sm2)

Mon  7th Oct 2024               tactics.ml, pa_j/passim

Merged an update from June Lee that provides an optional change in
the behaviour of THEN, requiring that first tactic should produce only
a single subgoal, rather than applying the second tactic to all the
subgoals regardless of number. This is controlled by an expansion
in the preprocessor switched by the special identifiers

        set_then_multiple_subgoals
        unset_then_multiple_subgoals

The default behavior is "set_then_multiple_subgoals", which as before
allows multiple subgoals.

Tue 24th Sep 2024               bool.ml

Added conveniently packaged interface mappings to set up more friendly
syntax for the quantifiers. New functions "set_verbose_symbols" and
"unset_verbose_symbols" enable and disable, respectively, these more
verbose and descriptive names for some logical symbols:

        F -> false
        T -> true
        ! -> forall
        ? -> exists
        ?! -> existsunique

This is all done via interface maps. Not only is the underlying term
structure unchanged (the "actual" names are the symbolic ones) but
also the original syntax is accepted as an alternative:

  # `exists x. x = 1` = `?x. x = 1`;;
  val it : bool = true

The new syntax is enabled by default, but can, as explained above,
be switched off with "unset_verbose_symbols()".

Thu 19th Sep 2024                .gitignore, Makefile, README,  hol.ml,  hol_4.14.sh,  hol_4.sh,  hol_lib.ml,  hol_lib_use_module.ml [new file],  inline_load.ml [new file]

Merged an update from June Lee that enables compilation of HOL Light
(supported for OCaml >= 4.14). It is controlled by the environment
variable HOLLIGHT_USE_MODULE, such that doing:

  HOLLIGHT_USE_MODULE=1 make

will build "hol.sh" so that it uses the compiled "hol_lib.cmo".

Thu 19th Sep 2024               impconv.ml

Fix IMP_REWRITE_TAC and related tactics in impconv.ml to raise the
preferred "Failure" exception rather than "Unchanged", making them
consistent with the rest of the codebase and in particular compatible
with tactic combinators like ORELSE. This change is from June Lee.

Wed 18th Sep 2024               int.ml, Library/words.ml

Made a small enhancement to div/rem elimination in INT_ARITH, making it
handle the common case where divisor and dividend are nonnegative, thus
being more comparable to ARITH_RULE.

Made some improvements to WORD_ARITH/WORD_ARITH_TAC to further normalize
constants and as a last resort write away all word expressions using numeric
values, to widen the scope, e.g.

  WORD_ARITH
   `!m n. m < 4096 /\ n <= 511
        ==> word_ule (word_add (word_mul (word n) (word 0x00001000)) (word m))
                     (word 0x0000000001FFFFFF:int64)`;;

Tue 17th Sep 2024               trivia.ml

Added the special eta-conversion variant for the 1-element type:

  ETA_ONE = |- !f:1->A. (\x. f one) = f

Tue  3rd Sep 2024               Library/words.ml

Made a couple of small improvements to BITBLAST_RULE: do more systematic
reduction of word constant-expressions in the middle of prenormalization, and
handle val(x) DIV 2^k and val(x) MOD 2^k in the initial bitwise expansion.
(The recognition of powers of 2 in arbitrary numeric expressions is broken out
as a separate conversion EMPOWER_CONV.) For example, this didn't work before
but now does:

  BITBLAST_RULE
    `word_and x (word 256):int64 = word 0 <=> val x MOD 512 < 256`;;

Fri 23rd Aug 2024               hol_lib.ml, hol_loader.ml [new files], passim

Merged a refactoring from June Lee that factors out file loading so that it
can be readily replaced with catenation and module compilation.

Tue  6th Aug 2024               Makefile, bignum_num.ml, bignum_zarith.ml, hol.ml, system.ml, pa_j/passim

Merged an update from June Lee that reorganizes the camlp5 preprocessing in
various ways so that camlp5r can be used with pa_j.cmo as a standaline
preprocessor, e.g. as follows:

  ocamlc -c -pp "camlp5r pa_lexer.cmo pa_extend.cmo q_MLast.cmo -I . pa_j.cmo" test.ml

This required several changes:

  * Printing "* HOL-Light syntax in effect *" is redirected to stderr, not
    stdout, because ocamlc was consuming the log from from stdout too.

  * jrh_lexer is enabled by default.

  * quotexpander is moved to pa_j.ml

  * bignum files had to be separately compiled without using pa_j because
    they were declaring modules which interfere with the preprocessor.

Thu  1st Aug 2024               Library/prime.ml, Arithmetic/definability.ml

Added a simple variant of an existing theorem PRIME_POWER_EXISTS,
characterizing prime powers via their divisors:

  PRIME_POWER_EXISTS_ALT =
    |- !n p.
           prime p
           ==> ((?i. n = p EXP i) <=>
                (!d. d divides n ==> d = 1 \/ p divides d))

Used this to simplify the proof of primepow_DELTA in the arithmetic
definability material, since it is only a minor elaboration of
this lemma.

Sat  6th Jul 2024               Makefile, README, pa_j [new directory], pa_j/pa_j_4.xx_8.03.ml

Merged an update from June Lee adding camlp5 8.03 support and making it the
target version for "make switch", as well as reorganizing this and previous
pa_j files into a subdirectory with a README to explain how they are put
together.

Sat  6th Jul 2024               holtest, holtest.ml, holtest_parallel

Merged an update from June Lee making the various HOL test files use the
"hol.sh" script to invoke HOL Light.

Fri  5th Jul 2024               EC/passim

Added a couple more theorems (easy consequences of existing ones) for
each one of the various Weierstrass curves, all analogs of the
following for P-256:

  P256_GROUP_ELEMENT_ORDER =
    |- !P. P IN group_carrier p256_group
           ==> group_element_order p256_group P =
               if P = group_id p256_group then 1 else n_256

  P256_GROUP_ORDER =
    |- CARD(group_carrier p256_group) = n_256

with the complete list of new theorems being

        P192K1_GROUP_ELEMENT_ORDER
        P192K1_GROUP_ORDER
        P192_GROUP_ELEMENT_ORDER
        P192_GROUP_ORDER
        P224K1_GROUP_ELEMENT_ORDER
        P224K1_GROUP_ORDER
        P224_GROUP_ELEMENT_ORDER
        P256K1_GROUP_ELEMENT_ORDER
        P256K1_GROUP_ORDER
        P256_GROUP_ELEMENT_ORDER
        P256_GROUP_ORDER
        P256_GROUP_ORDER
        P384_GROUP_ELEMENT_ORDER
        P384_GROUP_ORDER
        P521_GROUP_ELEMENT_ORDER
        P521_GROUP_ORDER

Also consistently renamed all the following existing theorems:

        FINITE_GROUP_CARRIER_192   -> FINITE_GROUP_CARRIER_P192
        FINITE_GROUP_CARRIER_192K1 -> FINITE_GROUP_CARRIER_P192K1
        FINITE_GROUP_CARRIER_224   -> FINITE_GROUP_CARRIER_P224
        FINITE_GROUP_CARRIER_224K1 -> FINITE_GROUP_CARRIER_P224K1
        FINITE_GROUP_CARRIER_256   -> FINITE_GROUP_CARRIER_P256
        FINITE_GROUP_CARRIER_256K1 -> FINITE_GROUP_CARRIER_P256K1
        FINITE_GROUP_CARRIER_384   -> FINITE_GROUP_CARRIER_P384
        FINITE_GROUP_CARRIER_521   -> FINITE_GROUP_CARRIER_P521

Wed  3rd Jul 2024               Library/prime.ml

Added a little lemma that is trivial to construct but handy sometimes:

  DIVIDES_EQ_ZERO = |- !p n. n < p ==> (p divides n <=> n = 0)

Wed  3rd Jul 2024               Library/grouptheory.ml

Added a few elementary group lemmas:

  GROUP_ELEMENT_ORDER_PRIME =
    |- !G a.
           prime p /\ group_carrier G HAS_SIZE p /\ a IN group_carrier G
           ==> group_element_order G a =
               (if a = group_id G then 1 else CARD (group_carrier G))

  GROUP_POW_MOD_ELEMENT_ORDER =
    |- !G x n.
           x IN group_carrier G
           ==> group_pow G x (n MOD group_element_order G x) = group_pow G x n

  GROUP_POW_MOD_ORDER =
    |- !G x n.
           FINITE (group_carrier G) /\ x IN group_carrier G
           ==> group_pow G x (n MOD CARD (group_carrier G)) = group_pow G x n

  GROUP_ZPOW_INV =
    |- !G x n.
           x IN group_carrier G
           ==> group_zpow G (group_inv G x) n = group_zpow G x (--n)

  GROUP_ZPOW_REM_ELEMENT_ORDER =
    |- !G x n.
           x IN group_carrier G
           ==> group_zpow G x (n rem &(group_element_order G x)) =
               group_zpow G x n

  GROUP_ZPOW_REM_ORDER =
    |- !G x n.
           FINITE (group_carrier G) /\ x IN group_carrier G
           ==> group_zpow G x (n rem &(CARD (group_carrier G))) =
               group_zpow G x n

Fri 28th Jun 2024               Library/ringtheory.ml

Added more elementary ring lemmas including characterizations of units and
nilpotents in polynomial rings:

  IN_SUBRING_PRODUCT =
    |- !r h f s.
           h subring_of r /\ (!a. a IN s ==> f a IN h)
           ==> ring_product r s f IN h

  IN_SUBRING_SUM =
    |- !r h f s.
           h subring_of r /\ (!a. a IN s ==> f a IN h) ==> ring_sum r s f IN h

  MONOMIAL_VAR_1 =
    |- (!v. ~(monomial_var v = monomial_1)) /\
       (!v. ~(monomial_1 = monomial_var v))

  POLY_EVALUATE_AT_0 =
    |- !r p.
           p IN ring_carrier (poly_ring r v)
           ==> poly_evaluate r p (\x. ring_0 r) = p monomial_1

  POLY_EVAL_AT_0 =
    |- !r p.
           p IN ring_carrier (poly_ring r (:1))
           ==> poly_eval r p (ring_0 r) = p (\v. 0)

  POLY_EXTEND_AT_0 =
    |- !r s v h p.
           ring_homomorphism (r,s) h /\ p IN ring_carrier (poly_ring r v)
           ==> poly_extend (r,s) h (\x. ring_0 s) p = h (p monomial_1)

  POLY_MUL_MONOMIAL_1 =
    |- !r p q.
           ring_polynomial r p /\ ring_polynomial r q
           ==> poly_mul r p q monomial_1 =
               ring_mul r (p monomial_1) (q monomial_1)

  POLY_SUBRING_GENERATED =
    |- !r s.
           subring_generated (poly_ring r s)
           ({poly_const r c | c | c IN ring_carrier r} UNION
            {poly_var r x | x IN s}) =
           poly_ring r s

  RING_HOMOMORPHISM_MONOMIAL_1 =
    |- !r v. ring_homomorphism (poly_ring r v,r) (\p. p monomial_1)

  RING_NILPOTENT_POLY_RING =
    |- !r s p.
           ring_nilpotent (poly_ring r s) p <=>
           p IN ring_carrier (poly_ring r s) /\ (!m. ring_nilpotent r (p m))

  RING_NILPOTENT_SUM =
    |- !r f s.
           FINITE s /\ (!i. i IN s ==> ring_nilpotent r (f i))
           ==> ring_nilpotent r (ring_sum r s f)

  RING_UNIT_POLY_CONST =
    |- !r s c. ring_unit (poly_ring r s) (poly_const r c) <=> ring_unit r c

  RING_UNIT_POLY_DOMAIN =
    |- !r s p.
           integral_domain r
           ==> (ring_unit (poly_ring r s) p <=>
                (?c. ring_unit r c /\ p = poly_const r c))

  RING_UNIT_POLY_RING =
    |- !r s p.
           ring_unit (poly_ring r s) p <=>
           p IN ring_carrier (poly_ring r s) /\
           ring_unit r (p monomial_1) /\
           (!m. ~(m = monomial_1) ==> ring_nilpotent r (p m))

Sun  9th Jun 2024               Library/ringtheory.ml

Added a slew of further elementary definitions and theorems about rings, in
particular definitions of "local_ring" (local ring), "poly_deg" (degree of a
polynomial), "poly_evaluate"/"poly_eval" (evaluation in the multivariate and
univariate settings). In incompatible changes, the original name POLY_CONST_0
is now used for a slightly different theorem. New definitions:

  local_ring =
    |- !r. local_ring r <=> (?!j. maximal_ideal r j)

  poly_deg =
    |- !p r.
           poly_deg r p =
           (minimal d. !m. ~(p m = ring_0 r) ==> monomial_deg m <= d)

  poly_eval =
    |- !r p x. poly_eval r p x = poly_evaluate r p (\v. x)

  poly_evaluate =
    |- !r x p. poly_evaluate r p x = poly_extend (r,r) I x p

  poly_sub =
    |- !r p1 p2. poly_sub r p1 p2 = (\m. ring_sub r (p1 m) (p2 m))

and theorems:

  EUCLIDEAN_POLY_RING =
    |- !f. field f ==> euclidean_ring (poly_ring f (:1))

  EXISTS_FUN_FROM_1 =
    |- !P. (?f. P (f one) f) <=> (?z. P z (\v. z))

  FIELD_IMP_LOCAL_RING =
    |- !r. field r ==> local_ring r

  FORALL_FUN_FROM_1 =
    |- !P. (!f. P (f one) f) <=> (!z. P z (\v. z))

  INTEGER_QUOTIENT_RING_ISOMORPHIC_MOD =
    |- quotient_ring integer_ring (ideal_generated integer_ring {&n})
       isomorphic_ring integer_mod_ring n

  INTEGER_RING_COSET_IDEAL_GENERATED_SING =
    |- !n. ring_coset integer_ring (ideal_generated integer_ring {n}) = mod n

  INTEGER_RING_IDEAL_GENERATED_SING =
    |- !n. ideal_generated integer_ring {n} = {x | n divides x}

  IN_POLY_RING_CARRIER =
    |- !r s.
           p IN ring_carrier (poly_ring r s) <=>
           ring_polynomial r p /\ poly_vars r p SUBSET s

  IN_RING_COSET =
    |- !r j x y.
           (ring_ideal r j \/ j subring_of r) /\
           x IN ring_carrier r /\
           y IN ring_carrier r
           ==> (x IN ring_coset r j y <=> ring_coset r j x = ring_coset r j y)

  IN_RING_POLYNOMIAL_CARRIER_COMPOSE =
    |- !r s f v p.
           ring_homomorphism (r,s) f /\ p IN ring_carrier (poly_ring r v)
           ==> f o p IN ring_carrier (poly_ring s v)

  IN_RING_POWERSERIES_CARRIER_COMPOSE =
    |- !r s v f p.
           ring_homomorphism (r,s) f /\ p IN ring_carrier (powser_ring r v)
           ==> f o p IN ring_carrier (powser_ring s v)

  ISOMORPHIC_RING_LOCALITY =
    |- !r r'. r isomorphic_ring r' ==> (local_ring r <=> local_ring r')

  ISOMORPHIC_SUBCOPY_OF_RING =
    |- !r s.
           ring_carrier r <=_c s
           ==> (?r'. ring_carrier r' SUBSET s /\ r isomorphic_ring r')

  LOCAL_IMP_NONTRIVIAL_RING =
    |- !r. local_ring r ==> ~trivial_ring r

  LOCAL_POWSER_RING =
    |- !r s. local_ring r ==> local_ring (powser_ring r s)

  LOCAL_QUOTIENT_RING =
    |- !r j.
           local_ring r /\ proper_ideal r j ==> local_ring (quotient_ring r j)

  LOCAL_RING_EPIMORPHIC_IMAGE =
    |- !r r' f.
           ring_epimorphism (r,r') f /\ local_ring r /\ ~trivial_ring r'
           ==> local_ring r'

  LOCAL_RING_IDEAL_NONUNITS =
    |- !r.
           local_ring r <=>
           ring_ideal r {x | x IN ring_carrier r /\ ~ring_unit r x}

  LOCAL_RING_LOCALIZATION =
    |- !r j.
           prime_ideal r j
           ==> local_ring (ring_localization r (ring_carrier r DIFF j))

  MAXIMAL_CONTAINING_IDEAL_EXISTS =
    |- !r a.
           a IN ring_carrier r /\ ~ring_unit r a
           ==> (?j. maximal_ideal r j /\ a IN j)

  MAXIMAL_IDEAL_NONUNITS =
    |- !r.
           maximal_ideal r {x | x IN ring_carrier r /\ ~ring_unit r x} <=>
           ring_ideal r {x | x IN ring_carrier r /\ ~ring_unit r x}

  MONOMIAL_DEG =
    |- !m. monomial_deg m = nsum (:V) m

  MONOMIAL_DEG_LE_POLY_DEG =
    |- !r p m.
           ring_polynomial r p /\ ~(p m = ring_0 r)
           ==> monomial_deg m <= poly_deg r p

  MONOMIAL_DEG_UNIVARIATE =
    |- !i. monomial_deg (\v. i) = i

  MONOMIAL_VARS_UNIVARIATE =
    |- !i. monomial_vars (\v. i) = (if i = 0 then {} else {one})

  PID_POLY_RING =
    |- !f. field f ==> PID (poly_ring f (:1))

  POLY_0 =
    |- !r. poly_0 r = (\m. ring_0 r)

  POLY_CLAUSES =
    |- (!r. {p | ring_polynomial r p} = ring_carrier (poly_ring r (:V))) /\
       (!r. poly_0 r = ring_0 (poly_ring r (:V))) /\
       (!r. poly_1 r = ring_1 (poly_ring r (:V))) /\
       (!r. poly_neg r = ring_neg (poly_ring r (:V))) /\
       (!r. poly_add r = ring_add (poly_ring r (:V))) /\
       (!r. poly_sub r = ring_sub (poly_ring r (:V))) /\
       (!r. poly_mul r = ring_mul (poly_ring r (:V)))

  POLY_CONST_1 =
    |- !r. poly_const r (ring_1 r) = poly_1 r

  POLY_DEG_0 =
    |- !r. poly_deg r (poly_0 r) = 0

  POLY_DEG_1 =
    |- !r. poly_deg r (poly_1 r) = 0

  POLY_DEG_ADD =
    |- !r p q.
           ring_polynomial r p /\
           ring_polynomial r q /\
           ~(poly_deg r p = poly_deg r q)
           ==> poly_deg r (poly_add r p q) = MAX (poly_deg r p) (poly_deg r q)

  POLY_DEG_ADD_LE =
    |- !r p q.
           ring_polynomial r p /\ ring_polynomial r q
           ==> poly_deg r (poly_add r p q) <= MAX (poly_deg r p) (poly_deg r q)

  POLY_DEG_CONST =
    |- !r c. poly_deg r (poly_const r c) = 0

  POLY_DEG_EQ =
    |- !r p n.
           ring_polynomial r p
           ==> (poly_deg r p = n <=>
                (!m. ~(p m = ring_0 r) ==> monomial_deg m <= n) /\
                (n = 0 \/ (?m. ~(p m = ring_0 r) /\ monomial_deg m = n)))

  POLY_DEG_EQ_0 =
    |- !r p.
           ring_polynomial r p
           ==> (poly_deg r p = 0 <=>
                (?c. c IN ring_carrier r /\ p = poly_const r c))

  POLY_DEG_EQ_0_ALT =
    |- !r p.
           ring_polynomial r p
           ==> (poly_deg r p = 0 <=> p = poly_const r (p monomial_1))

  POLY_DEG_GE =
    |- !r p m n.
           ring_polynomial r p /\ ~(p m = ring_0 r) /\ n <= monomial_deg m
           ==> n <= poly_deg r p

  POLY_DEG_GE_EQ =
    |- !r p n.
           ring_polynomial r p
           ==> (n <= poly_deg r p <=>
                n = 0 \/ (?m. ~(p m = ring_0 r) /\ n <= monomial_deg m))

  POLY_DEG_HOMOMORPHIC_IMAGE =
    |- !r s f p.
           ring_homomorphism (r,s) f /\ ring_polynomial r p
           ==> poly_deg s (f o p) <= poly_deg r p

  POLY_DEG_LE =
    |- !r p n.
           ring_polynomial r p /\
           (!m. ~(p m = ring_0 r) ==> monomial_deg m <= n)
           ==> poly_deg r p <= n

  POLY_DEG_LE_EQ =
    |- !r p n.
           ring_polynomial r p
           ==> (poly_deg r p <= n <=>
                (!m. ~(p m = ring_0 r) ==> monomial_deg m <= n))

  POLY_DEG_MONOMIAL_EXISTS =
    |- !r p.
           ring_polynomial r p /\ ~(p = poly_0 r)
           ==> (?m. ~(p m = ring_0 r) /\ monomial_deg m = poly_deg r p)

  POLY_DEG_MONOMORPHIC_IMAGE =
    |- !r s f p.
           ring_monomorphism (r,s) f /\ ring_polynomial r p
           ==> poly_deg s (f o p) = poly_deg r p

  POLY_DEG_MUL =
    |- !r p q.
           integral_domain r /\
           ring_polynomial r p /\
           ring_polynomial r q /\
           (p = poly_0 r <=> q = poly_0 r)
           ==> poly_deg r (poly_mul r p q) = poly_deg r p + poly_deg r q

  POLY_DEG_MUL_LE =
    |- !r p q.
           ring_polynomial r p /\ ring_polynomial r q
           ==> poly_deg r (poly_mul r p q) <= poly_deg r p + poly_deg r q

  POLY_DEG_NEG =
    |- !r p. ring_polynomial r p ==> poly_deg r (poly_neg r p) = poly_deg r p

  POLY_DEG_RING_ADD_LE =
    |- !r s p q n.
           p IN ring_carrier (poly_ring r s) /\
           q IN ring_carrier (poly_ring r s) /\
           poly_deg r p <= n /\
           poly_deg r q <= n
           ==> poly_deg r (ring_add (poly_ring r s) p q) <= n

  POLY_DEG_RING_SUB_LE =
    |- !r s p q n.
           p IN ring_carrier (poly_ring r s) /\
           q IN ring_carrier (poly_ring r s) /\
           poly_deg r p <= n /\
           poly_deg r q <= n
           ==> poly_deg r (ring_sub (poly_ring r s) p q) <= n

  POLY_DEG_RING_SUM_LE =
    |- !r s f k n.
           FINITE k /\
           (!i.
                i IN k
                ==> f i IN ring_carrier (poly_ring r s) /\
                    poly_deg r (f i) <= n)
           ==> poly_deg r (ring_sum (poly_ring r s) k f) <= n

  POLY_DEG_SUB =
    |- !r p q.
           ring_polynomial r p /\
           ring_polynomial r q /\
           ~(poly_deg r p = poly_deg r q)
           ==> poly_deg r (poly_sub r p q) = MAX (poly_deg r p) (poly_deg r q)

  POLY_DEG_SUB_LE =
    |- !r p q.
           ring_polynomial r p /\ ring_polynomial r q
           ==> poly_deg r (poly_sub r p q) <= MAX (poly_deg r p) (poly_deg r q)

  POLY_DEG_UNIQUE =
    |- !r p n.
           ring_polynomial r p /\
           (!m. ~(p m = ring_0 r) ==> monomial_deg m <= n) /\
           (n = 0 \/ (?m. ~(p m = ring_0 r) /\ monomial_deg m = n))
           ==> poly_deg r p = n

  POLY_DEG_VAR =
    |- !r. poly_deg r (poly_var r v) = (if ring_1 r = ring_0 r then 0 else 1)

  POLY_DEG_VAR_POW =
    |- !r s i k.
           poly_deg r (ring_pow (poly_ring r s) (poly_var r i) k) =
           (if ring_1 r = ring_0 r then 0 else k)

  POLY_DIVIDES_X_MINUS_A =
    |- !r a p.
           a IN ring_carrier r /\ p IN ring_carrier (poly_ring r (:1))
           ==> ring_divides (poly_ring r (:1))
               (poly_sub r (poly_var r one) (poly_const r a))
               (poly_sub r p (poly_const r (poly_eval r p a)))

  POLY_DIVIDES_X_MINUS_ROOT =
    |- !r a p.
           a IN ring_carrier r /\
           p IN ring_carrier (poly_ring r (:1)) /\
           poly_eval r p a = ring_0 r
           ==> ring_divides (poly_ring r (:1))
               (poly_sub r (poly_var r one) (poly_const r a))
               p

  POLY_DIVIDES_X_MINUS_ROOT_EQ =
    |- !r a p.
           a IN ring_carrier r /\ p IN ring_carrier (poly_ring r (:1))
           ==> (ring_divides (poly_ring r (:1))
                (poly_sub r (poly_var r one) (poly_const r a))
                p <=>
                poly_eval r p a = ring_0 r)

  POLY_DIVISION =
    |- !f p d.
           field f /\
           p IN ring_carrier (poly_ring f (:1)) /\
           d IN ring_carrier (poly_ring f (:1)) /\
           ~(d = ring_0 (poly_ring f (:1)))
           ==> (?q t.
                    q IN ring_carrier (poly_ring f (:1)) /\
                    t IN ring_carrier (poly_ring f (:1)) /\
                    (poly_deg f t < poly_deg f d \/
                     t = ring_0 (poly_ring f (:1))) /\
                    ring_add (poly_ring f (:1))
                    (ring_mul (poly_ring f (:1)) q d)
                    t =
                    p)

  POLY_DIVISION_GEN =
    |- !r p d.
           p IN ring_carrier (poly_ring r (:1)) /\
           d IN ring_carrier (poly_ring r (:1)) /\
           ring_unit r (d (\v. poly_deg r d))
           ==> (?q t.
                    q IN ring_carrier (poly_ring r (:1)) /\
                    t IN ring_carrier (poly_ring r (:1)) /\
                    (poly_deg r t < poly_deg r d \/
                     t = ring_0 (poly_ring r (:1))) /\
                    ring_add (poly_ring r (:1))
                    (ring_mul (poly_ring r (:1)) q d)
                    t =
                    p)

  POLY_EQ_0_MONOMORPHIC_IMAGE =
    |- !r s f p.
           ring_monomorphism (r,s) f /\ ring_polynomial r p
           ==> (f o p = poly_0 s <=> p = poly_0 r)

  POLY_EVAL =
    |- !r p x. poly_eval r p x IN ring_carrier r

  POLY_EVALUATE =
    |- !r p x. poly_evaluate r p x IN ring_carrier r

  POLY_EVALUATE_0 =
    |- !r x. poly_evaluate r (poly_0 r) x = ring_0 r

  POLY_EVALUATE_1 =
    |- !r x. poly_evaluate r (poly_1 r) x = ring_1 r

  POLY_EVALUATE_ADD =
    |- !r p q x.
           ring_polynomial r p /\ ring_polynomial r q
           ==> poly_evaluate r (poly_add r p q) x =
               ring_add r (poly_evaluate r p x) (poly_evaluate r q x)

  POLY_EVALUATE_CONST =
    |- !r a x. a IN ring_carrier r ==> poly_evaluate r (poly_const r a) x = a

  POLY_EVALUATE_EQ =
    |- !r s p x y.
           (!i. i IN s ==> x i IN ring_carrier r) /\
           (!i. i IN s ==> x i = y i) /\
           p IN ring_carrier (poly_ring r s)
           ==> poly_evaluate r p x = poly_evaluate r p y

  POLY_EVALUATE_HOMOMORPHIC_IMAGE =
    |- !r s x f v p.
           ring_homomorphism (r,s) f /\
           IMAGE x v SUBSET ring_carrier r /\
           p IN ring_carrier (poly_ring r v)
           ==> f (poly_evaluate r p x) = poly_evaluate s (f o p) (f o x)

  POLY_EVALUATE_MUL =
    |- !r p q x.
           ring_polynomial r p /\
           ring_polynomial r q /\
           (!i.
                i IN poly_vars r p UNION poly_vars r q
                ==> x i IN ring_carrier r)
           ==> poly_evaluate r (poly_mul r p q) x =
               ring_mul r (poly_evaluate r p x) (poly_evaluate r q x)

  POLY_EVALUATE_SUB =
    |- !r p q x.
           ring_polynomial r p /\ ring_polynomial r q
           ==> poly_evaluate r (poly_sub r p q) x =
               ring_sub r (poly_evaluate r p x) (poly_evaluate r q x)

  POLY_EVALUATE_VAR =
    |- !r i x. x i IN ring_carrier r ==> poly_evaluate r (poly_var r i) x = x i

  POLY_EVAL_0 =
    |- !r x. poly_eval r (poly_0 r) x = ring_0 r

  POLY_EVAL_1 =
    |- !r x. poly_eval r (poly_1 r) x = ring_1 r

  POLY_EVAL_ADD =
    |- !r p q x.
           ring_polynomial r p /\ ring_polynomial r q
           ==> poly_eval r (poly_add r p q) x =
               ring_add r (poly_eval r p x) (poly_eval r q x)

  POLY_EVAL_CONST =
    |- !r a x. a IN ring_carrier r ==> poly_eval r (poly_const r a) x = a

  POLY_EVAL_EXPAND =
    |- !r x p.
           x IN ring_carrier r /\ p IN ring_carrier (poly_ring r (:1))
           ==> poly_eval r p x =
               ring_sum r (0..poly_deg r p)
               (\i. ring_mul r (p (\v. i)) (ring_pow r x i))

  POLY_EVAL_HOMOMORPHIC_IMAGE =
    |- !r s x f p.
           ring_homomorphism (r,s) f /\
           x IN ring_carrier r /\
           p IN ring_carrier (poly_ring r (:1))
           ==> f (poly_eval r p x) = poly_eval s (f o p) (f x)

  POLY_EVAL_MUL =
    |- !r p q x.
           ring_polynomial r p /\ ring_polynomial r q /\ x IN ring_carrier r
           ==> poly_eval r (poly_mul r p q) x =
               ring_mul r (poly_eval r p x) (poly_eval r q x)

  POLY_EVAL_SUB =
    |- !r p q x.
           ring_polynomial r p /\ ring_polynomial r q
           ==> poly_eval r (poly_sub r p q) x =
               ring_sub r (poly_eval r p x) (poly_eval r q x)

  POLY_EVAL_VAR =
    |- !r x. x IN ring_carrier r ==> poly_eval r (poly_var r one) x = x

  POLY_EXPAND =
    |- !r p.
           p IN ring_carrier (poly_ring r (:1))
           ==> p =
               ring_sum (poly_ring r (:1)) (0..poly_deg r p)
               (\i.
                    ring_mul (poly_ring r (:1)) (poly_const r (p (\v. i)))
                    (ring_pow (poly_ring r (:1)) (poly_var r one) i))

  POLY_EXTEND_EQ =
    |- !r r' s h k x y p.
           ring_homomorphism (r,r') h /\
           (!i. i IN s ==> x i IN ring_carrier r') /\
           (!a. a IN ring_carrier r ==> h a = k a) /\
           (!i. i IN s ==> x i = y i) /\
           p IN ring_carrier (poly_ring r s)
           ==> poly_extend (r,r') h x p = poly_extend (r,r') k y p

  POLY_EXTEND_EVALUATE =
    |- !r s f x p.
           ring_homomorphism (r,s) f
           ==> poly_extend (r,s) f x p = poly_evaluate s (f o p) x

  POLY_EXTEND_HOMOMORPHIC_IMAGE =
    |- !r s t h v x f p.
           ring_homomorphism (r,s) h /\
           ring_homomorphism (s,t) f /\
           IMAGE x v SUBSET ring_carrier s /\
           p IN ring_carrier (poly_ring r v)
           ==> f (poly_extend (r,s) h x p) =
               poly_extend (r,t) (f o h) (f o x) p

  POLY_EXTEND_SUB =
    |- !r r' h x p1 p2.
           ring_homomorphism (r,r') h /\
           ring_polynomial r p1 /\
           ring_polynomial r p2
           ==> poly_extend (r,r') h x (poly_sub r p1 p2) =
               ring_sub r' (poly_extend (r,r') h x p1)
               (poly_extend (r,r') h x p2)

  POLY_EXTEND_UNIVARIATE =
    |- !r r' h x p.
           ring_homomorphism (r,r') h /\
           x one IN ring_carrier r' /\
           p IN ring_carrier (poly_ring r (:1))
           ==> poly_extend (r,r') h x p =
               ring_sum r' (0..poly_deg r p)
               (\i. ring_mul r' (h (p (\v. i))) (ring_pow r' (x one) i))

  POLY_MONOMIALS =
    |- !r s m.
           p IN ring_carrier (poly_ring r s) /\ ~(p m = ring_0 r)
           ==> monomial s m

  POLY_MONOMIALS_FINITE =
    |- !r s.
           p IN ring_carrier (poly_ring r s) ==> FINITE {m | ~(p m = ring_0 r)}

  POLY_MONOMIAL_IN_CARRIER =
    |- !r s p m. p IN ring_carrier (poly_ring r s) ==> p m IN ring_carrier r

  POLY_MUL_0 =
    |- (!r p. ring_polynomial r p ==> poly_mul r p (poly_0 r) = poly_0 r) /\
       (!r q. ring_polynomial r q ==> poly_mul r (poly_0 r) q = poly_0 r)

  POLY_RING_CLAUSES =
    |- (!r s.
            ring_carrier (poly_ring r s) =
            {p | ring_polynomial r p /\ poly_vars r p SUBSET s}) /\
       (!r s. ring_0 (poly_ring r s) = poly_0 r) /\
       (!r s. ring_1 (poly_ring r s) = poly_1 r) /\
       (!r s. ring_neg (poly_ring r s) = poly_neg r) /\
       (!r s. ring_add (poly_ring r s) = poly_add r) /\
       (!r s. ring_sub (poly_ring r s) = poly_sub r) /\
       (!r s. ring_mul (poly_ring r s) = poly_mul r)

  POLY_ROOT_BOUND =
    |- !r p.
           integral_domain r /\
           p IN ring_carrier (poly_ring r (:1)) /\
           ~(p = ring_0 (poly_ring r (:1)))
           ==> FINITE {x | x IN ring_carrier r /\ poly_eval r p x = ring_0 r} /\
               CARD {x | x IN ring_carrier r /\ poly_eval r p x = ring_0 r} <=
               poly_deg r p

  POLY_SUB =
    |- !r p q. poly_sub r p q = poly_add r p (poly_neg r q)

  POLY_TOP_MONOMIAL_LE =
    |- !(<<=) r p.
           toset (<<=) /\
           fld (<<=) = (:V) /\
           ring_polynomial r p /\
           ~(p = poly_0 r)
           ==> (?m.
                    ~(p m = ring_0 r) /\
                    monomial_deg m = poly_deg r p /\
                    (!m'.
                         ~(p m' = ring_0 r) /\ monomial_deg m' = poly_deg r p
                         ==> monomial_le (<<=) m' m))

  POLY_TOP_MONOMIAL_LT =
    |- !(<<=) r p.
           toset (<<=) /\
           fld (<<=) = (:V) /\
           ring_polynomial r p /\
           ~(p = poly_0 r)
           ==> (?m.
                    ~(p m = ring_0 r) /\
                    monomial_deg m = poly_deg r p /\
                    (!m'.
                         ~(p m' = ring_0 r) /\
                         monomial_deg m' = poly_deg r p /\
                         ~(m' = m)
                         ==> monomial_lt (<<=) m' m))

  POLY_TOP_NONZERO =
    |- !r p.
           p IN ring_carrier (poly_ring r (:1)) /\
           ~(p = ring_0 (poly_ring r (:1)))
           ==> ~(p (\v. poly_deg r p) = ring_0 r)

  POLY_TOP_TAIL =
    |- !r p.
           p IN ring_carrier (poly_ring r (:1)) /\
           ~(p = ring_0 (poly_ring r (:1)))
           ==> (?q.
                    q IN ring_carrier (poly_ring r (:1)) /\
                    (poly_deg r q < poly_deg r p \/
                     q = ring_0 (poly_ring r (:1))) /\
                    ring_add (poly_ring r (:1))
                    (ring_mul (poly_ring r (:1))
                     (poly_const r (p (\v. poly_deg r p)))
                    (ring_pow (poly_ring r (:1)) (poly_var r one)
                    (poly_deg r p)))
                    q =
                    p)

  POLY_VAR_UNIV =
    |- !r i. poly_var r i IN ring_carrier (poly_ring r (:V))

  POWSER_MONOMIALS =
    |- !r s m.
           p IN ring_carrier (powser_ring r s) /\ ~(p m = ring_0 r)
           ==> monomial s m

  POWSER_MONOMIAL_IN_CARRIER =
    |- !r s p m. p IN ring_carrier (powser_ring r s) ==> p m IN ring_carrier r

  POWSER_VAR_UNIV =
    |- !r i. poly_var r i IN ring_carrier (powser_ring r (:V))

  PRIME_IDEAL_CONTAINS_NILPOTENTS =
    |- !r j. prime_ideal r j ==> {x | ring_nilpotent r x} SUBSET j

  PRIME_IDEAL_NONUNITS =
    |- !r.
           prime_ideal r {x | x IN ring_carrier r /\ ~ring_unit r x} <=>
           ring_ideal r {x | x IN ring_carrier r /\ ~ring_unit r x}

  PROPER_IDEAL_NONUNITS =
    |- !r.
           proper_ideal r {x | x IN ring_carrier r /\ ~ring_unit r x} <=>
           ring_ideal r {x | x IN ring_carrier r /\ ~ring_unit r x}

  PROPER_IDEAL_SUBSET_NONUNITS =
    |- !r j.
           proper_ideal r j
           ==> j SUBSET {x | x IN ring_carrier r /\ ~ring_unit r x}

  RING_COSET_IDEAL_GENERATED_SING =
    |- !r a x.
           a IN ring_carrier r /\ x IN ring_carrier r
           ==> ring_coset r (ideal_generated r {a}) x =
               {y | y IN ring_carrier r /\ ring_divides r a (ring_sub r x y)}

  RING_COSET_IDEAL_GENERATED_SING_EQ =
    |- !r a x y.
           a IN ring_carrier r /\ x IN ring_carrier r /\ y IN ring_carrier r
           ==> (ring_coset r (ideal_generated r {a}) x =
                ring_coset r (ideal_generated r {a}) y <=>
                ring_divides r a (ring_sub r x y))

  RING_COSET_RELATIONAL =
    |- !r j x y.
           (ring_ideal r j \/ j subring_of r) /\
           x IN ring_carrier r /\
           y IN ring_carrier r
           ==> (ring_coset r j x y <=> ring_coset r j x = ring_coset r j y)

  RING_EPIMORPHISM_I =
    |- !r. ring_epimorphism (r,r) I

  RING_EPIMORPHISM_POLY_EVAL =
    |- !r s x.
           x IN ring_carrier r
           ==> ring_epimorphism (poly_ring r s,r) (\p. poly_eval r p x)

  RING_EPIMORPHISM_POLY_EVALUATE =
    |- !r s x.
           IMAGE x s SUBSET ring_carrier r
           ==> ring_epimorphism (poly_ring r s,r) (\p. poly_evaluate r p x)

  RING_EPIMORPHISM_POLY_RINGS =
    |- !r s f v.
           ring_epimorphism (r,s) f
           ==> ring_epimorphism (poly_ring r v,poly_ring s v) (\p. f o p)

  RING_EPIMORPHISM_POWSER_RINGS =
    |- !r s f v.
           ring_epimorphism (r,s) f
           ==> ring_epimorphism (powser_ring r v,powser_ring s v) (\p. f o p)

  RING_HOMOMORPHISM_I =
    |- !r. ring_homomorphism (r,r) I

  RING_HOMOMORPHISM_INTEGER_MOD_RINGS =
    |- !p m n.
           ring_homomorphism (integer_mod_ring m,integer_mod_ring n)
           (\x. x rem &n) <=>
           n divides m

  RING_HOMOMORPHISM_INTEGER_MOD_RINGS_POW =
    |- !p i j.
           i <= j
           ==> ring_homomorphism
               (integer_mod_ring (p EXP j),integer_mod_ring (p EXP i))
               (\x. x rem &p pow i)

  RING_HOMOMORPHISM_POLY_EVAL =
    |- !r s x.
           x IN ring_carrier r
           ==> ring_homomorphism (poly_ring r s,r) (\p. poly_eval r p x)

  RING_HOMOMORPHISM_POLY_EVALUATE =
    |- !r s x.
           IMAGE x s SUBSET ring_carrier r
           ==> ring_homomorphism (poly_ring r s,r) (\p. poly_evaluate r p x)

  RING_HOMOMORPHISM_POLY_RINGS =
    |- !r s f v.
           ring_homomorphism (r,s) f
           ==> ring_homomorphism (poly_ring r v,poly_ring s v) (\p. f o p)

  RING_HOMOMORPHISM_POWSER_RINGS =
    |- !r s f v.
           ring_homomorphism (r,s) f
           ==> ring_homomorphism (powser_ring r v,powser_ring s v) (\p. f o p)

  RING_IDEAL_NONUNITS =
    |- !r.
           ring_ideal r {x | x IN ring_carrier r /\ ~ring_unit r x} <=>
           ~trivial_ring r /\
           (!x y.
                x IN ring_carrier r /\
                ~ring_unit r x /\
                y IN ring_carrier r /\
                ~ring_unit r y
                ==> ~ring_unit r (ring_add r x y))

  RING_ISOMORPHISMS_I =
    |- !r. ring_isomorphisms (r,r) (I,I)

  RING_ISOMORPHISM_I =
    |- !r. ring_isomorphism (r,r) I

  RING_ISOMORPHISM_POLY_RINGS =
    |- !r s f v.
           ring_isomorphism (r,s) f
           ==> ring_isomorphism (poly_ring r v,poly_ring s v) (\p. f o p)

  RING_ISOMORPHISM_POWSER_RINGS =
    |- !r s f v.
           ring_isomorphism (r,s) f
           ==> ring_isomorphism (powser_ring r v,powser_ring s v) (\p. f o p)

  RING_MONOMORPHISM_I =
    |- !r. ring_monomorphism (r,r) I

  RING_MONOMORPHISM_POLY_RINGS =
    |- !r s f v.
           ring_monomorphism (r,s) f
           ==> ring_monomorphism (poly_ring r v,poly_ring s v) (\p. f o p)

  RING_MONOMORPHISM_POWSER_RINGS =
    |- !r s f v.
           ring_monomorphism (r,s) f
           ==> ring_monomorphism (powser_ring r v,powser_ring s v) (\p. f o p)

  RING_MULTSYS =
    |- (!r s x. ring_multsys r s /\ x IN s ==> x IN ring_carrier r) /\
       (!r s. ring_multsys r s ==> ring_1 r IN s) /\
       (!r s x y. ring_multsys r s /\ x IN s /\ y IN s ==> ring_mul r x y IN s)

  RING_NILPOTENT_UNIT =
    |- !r x.
           ring_unit r x /\ ring_nilpotent r x <=>
           trivial_ring r /\ x = ring_0 r

  RING_POLYNOMIAL =
    |- !r p. ring_polynomial r p <=> p IN ring_carrier (poly_ring r (:V))

  RING_POLYNOMIAL_CARRIER =
    |- !r p.
           ring_polynomial r p <=>
           p IN ring_carrier (poly_ring r (poly_vars r p))

  RING_POLYNOMIAL_CARRIER_GEN =
    |- !r s p.
           poly_vars r p SUBSET s
           ==> (ring_polynomial r p <=> p IN ring_carrier (poly_ring r s))

  RING_POLYNOMIAL_COMPOSE =
    |- !r s f p.
           ring_homomorphism (r,s) f /\ ring_polynomial r p
           ==> ring_polynomial s (f o p)

  RING_POLYNOMIAL_MONOMIAL =
    |- !r p m. ring_polynomial r p /\ ~(p m = ring_0 r) ==> monomial (:V) m

  RING_POLYNOMIAL_SUB =
    |- !r p1 p2.
           ring_polynomial r p1 /\ ring_polynomial r p2
           ==> ring_polynomial r (poly_sub r p1 p2)

  RING_POWERSERIES_COMPOSE =
    |- !r s f p.
           ring_homomorphism (r,s) f /\ ring_powerseries r p
           ==> ring_powerseries s (f o p)

  RING_POWERSERIES_MONOMIAL =
    |- !r p m. ring_powerseries r p /\ ~(p m = ring_0 r) ==> monomial (:V) m

  RING_POWERSERIES_SUB =
    |- !r p1 p2.
           ring_powerseries r p1 /\ ring_powerseries r p2
           ==> ring_powerseries r (poly_sub r p1 p2)

  RING_SATURATED_MULTSYS_NONPRIME =
    |- !r j.
           prime_ideal r j
           ==> ring_multsys r (ring_carrier r DIFF j) /\
               (!x y.
                    x IN ring_carrier r /\
                    y IN ring_carrier r /\
                    ring_mul r x y IN ring_carrier r DIFF j
                    ==> x IN ring_carrier r DIFF j /\
                        y IN ring_carrier r DIFF j)

  RING_SUM_CLAUSES_RIGHT =
    |- !r f m n.
           0 < n /\ m <= n
           ==> ring_sum r (m..n) f =
               (if f n IN ring_carrier r
                then ring_add r (ring_sum r (m..n - 1) f) (f n)
                else ring_sum r (m..n - 1) f)

  RING_UNIT_LOCALEQUIV_EQ =
    |- !r s a b.
           ring_multsys r s /\
           (!x y.
                x IN ring_carrier r /\
                y IN ring_carrier r /\
                ring_mul r x y IN s
                ==> x IN s /\ y IN s) /\
           a IN ring_carrier r /\
           b IN s
           ==> (ring_unit (ring_localization r s) (ring_localequiv r s (a,b)) <=>
                a IN s)

  RING_UNIT_LOCALIZATION =
    |- !r s c.
           ring_multsys r s /\
           (!x y.
                x IN ring_carrier r /\
                y IN ring_carrier r /\
                ring_mul r x y IN s
                ==> x IN s /\ y IN s)
           ==> (ring_unit (ring_localization r s) c <=>
                (?a b. a IN s /\ b IN s /\ c = ring_localequiv r s (a,b)))

  UNIONS_PRIME_IDEALS =
    |- !r.
           UNIONS {j | prime_ideal r j} =
           {x | x IN ring_carrier r /\ ~ring_unit r x}

  UNIONS_PROPER_IDEALS =
    |- !r.
           UNIONS {j | proper_ideal r j} =
           {x | x IN ring_carrier r /\ ~ring_unit r x}

  UNIQUE_PRIME_IDEAL =
    |- !r.
           (?!j. prime_ideal r j) <=>
           ~trivial_ring r /\
           (!x. x IN ring_carrier r ==> ring_unit r x \/ ring_nilpotent r x)

  UNIQUE_PRIME_IDEAL_IMP_LOCAL_RING =
    |- !r. (?!j. prime_ideal r j) ==> local_ring r

Thu  6th Jun 2024               Library/words.ml

Added a more general variant of the existing theorem TWOS_COMPLEMENT:

  TWOS_COMPLEMENT_GEN =
    |- !p k n x.
           (&n == x) (mod (&2 pow (p + k))) /\
           n < 2 EXP (p + k) /\ --(&2 pow p) <= x /\ x < &2 pow p
           ==> n DIV 2 EXP p = (2 EXP k - 1) * bitval (x < &0) /\
               &n - &2 pow (p + k) * &(bitval (x < &0)) = x

Thu 16th May 2024               metis.ml

Added a small refinement from Joe Hurd that eliminates the
catching of completely arbitrary exception patterns ("with _ -> ...")
in the METIS code. In principle, such patterns could hide or be
confused by asynchronous interrupts.

Fri 10th May 2024               Makefile, README, hol_4.sh, hol_4.14.sh

Added a new "make switch" Makefile option from June Lee, which automatically
sets up an appropriate "local" OCaml implementation in an "_opam" subdirectory,
removing versioning dependencies on the system-wide OCaml. This also updates
the hol.sh shell scripts to invoke a line editor by default.

Fri 10th May 2024               bignum_zarith.ml, Formal_ineqs/passim

Added a number of updates to Formal_ineqs from Alexey Solovyev, including
modifications for OCaml zarith and other improvements.

Wed  8th May 2024               sets.ml, Library/grouptheory.ml, Library/ringtheory.ml

Added a couple of generalizations of the existing FINITE_SUBSET_UNIONS_CHAIN
(first to an equivalence, and then to directed families not just chains):

  FINITE_SUBSET_UNIONS_CHAIN_EQ =
   |- !f s. ~(f = {}) /\
            (!t u. t IN f /\ u IN f ==> t SUBSET u \/ u SUBSET t) /\
            FINITE s
            ==> (s SUBSET UNIONS f <=> ?t. t IN f /\ s SUBSET t)

  FINITE_SUBSET_UNIONS_DIRECTED_EQ =
   |- !f s. ~(f = {}) /\
            (!t u. t IN f /\ u IN f
                   ==> ?v. v IN f /\ t SUBSET v /\ u SUBSET v) /\
            FINITE s
            ==> (s SUBSET UNIONS f <=> ?t. t IN f /\ s SUBSET t)

Also added theorems asserting the existence of direct limits of groups and
rings, in the special case of actual inclusion maps (these are conceptually
similar algebraic facts):

  GROUP_DIRECT_LIMIT =
    |- !c. ~(c = {}) /\
           (!g g'. g IN c /\ g' IN c
                   ==> ?G. G IN c /\
                           group_monomorphism(g,G) I /\
                           group_monomorphism(g',G) I)
           ==> ?G. group_carrier G = UNIONS {group_carrier g | g IN c} /\
                   !g. g IN c ==> group_monomorphism(g,G) I

  RING_DIRECT_LIMIT =
    |- !c. ~(c = {}) /\
           (!r r'. r IN c /\ r' IN c
                   ==> ?R. R IN c /\
                           ring_monomorphism(r,R) I /\
                           ring_monomorphism(r',R) I)
           ==> ?R. ring_carrier R = UNIONS {ring_carrier r | r IN c} /\
                   !r. r IN c ==> ring_monomorphism(r,R) I

Mon  6th May 2024               Library/wo.ml

Generalized the existing theorem HP (Hausdorff maximal principle) from
posets to qosets (quasi-ordered sets = preorders), and also proved a
variant of Zorn's lemma for qosets, expressing the set-theoretic aspects
following current style using IN:

  ZL_STRONG =
    |- !l. qoset l /\
           (!c. chain l c
                ==> ?y. y IN fld l /\ !x. x IN c ==> l x y)
           ==> ?y. y IN fld l /\ !x. l y x ==> l x y

Added three trivial supporting lemmas, re-naming the old QOSET_REFL
to QOSET_REFL_EQ to maintain terminological consistency with POSET_REFL:

  QOSET_FLDEQ =
    |- !l. qoset l ==> (!x. fld l x <=> l x x)

  QOSET_REFL =
    |- !l. qoset l ==> (!x. fld l x ==> l x x)

  QOSET_TRANS =
    |- !l. qoset l ==> (!x y z. l x y /\ l y z ==> l x z)

Mon  6th May 2024               sets.ml

Added an explicit characterization of the universe of the 1-element set:

  UNIV_1 = |- (:1) = {one}

Fri 26th Apr 2024               sets.ml

Added a few set lemmas including a slightly curious characterization of
unique existence:

  EXISTS_UNIQUE_UNIONS_INTERS =
   |- !P. (?!s. P s) <=> UNIONS {s | P s} = INTERS {s | P s}

  SING_ALT =
   |- !s. (?x. s = {x}) <=> ?!x. x IN s

  UNIONS_EQ_INTERS =
   |- !f. UNIONS f = INTERS f <=> ?s. f = {s}

Tue 23rd Apr 2024               sets.ml

Added one triviality about restriction:

  RESTRICTION_UNIV =
    |- !f. RESTRICTION (:A) f = f

Mon 15th Apr 2024               Library/words.ml

Added a few little lemmas giving characterizations of various orderings
in terms of the top bit (cf. Hacker's Delight 2-11). They are mostly
proved completely automatically by WORD_ARITH, but are sufficiently
intricate that it seemed worth recording them.

  WORD_COMPARISON_EQ =
    |- !x y.
           x = y <=>
           bit (dimindex (:N) - 1)
           (word_not (word_or (word_xor x y) (word_neg (word_xor x y))))

  WORD_COMPARISON_ILE =
    |- !x y.
           ival x <= ival y <=>
           bit (dimindex (:N) - 1)
           (word_and (word_or x (word_not y))
           (word_or (word_xor x y) (word_not (word_sub y x))))

  WORD_COMPARISON_ILT =
    |- !x y.
           ival x < ival y <=>
           bit (dimindex (:N) - 1)
           (word_or (word_and x (word_not y))
           (word_and (word_not (word_xor x y)) (word_sub x y)))

  WORD_COMPARISON_NE =
    |- !x y.
           ~(x = y) <=>
           bit (dimindex (:N) - 1)
           (word_or (word_xor x y) (word_neg (word_xor x y)))

  WORD_COMPARISON_ULE =
    |- !x y.
           val x <= val y <=>
           bit (dimindex (:N) - 1)
           (word_and (word_or (word_not x) y)
           (word_or (word_xor x y) (word_not (word_sub y x))))

  WORD_COMPARISON_ULT =
    |- !x y.
           val x < val y <=>
           bit (dimindex (:N) - 1)
           (word_or (word_and (word_not x) y)
           (word_and (word_or (word_not x) y) (word_sub x y)))

Mon 15th Apr 2024               printer.ml

Made a very tiny tweak to the printer to allow/encourage linbreak after
the varstruct of an abstraction, even if it consists of just a single
variable.

Fri 12th Apr 2024               Cadical/* [new directory]

Added a proof-checking interface to the Cadical SAT solver
(https://github.com/arminbiere/cadical). This is highly analogous
to the existing interfaces to Minisat and zchaff in "Minisat/*"
and uses some very similar code for CNF transformation. Among
other facilities, this makes available a Cadical-powered tautology
checker, with the LRAT proof produced by Cadical (it is tidied up
with lrat-trim in the standard flow) checked in the HOL Light
kernel. For example:

  # CADICAL_PROVE `(p ==> q) <=> (p <=> p /\ q)`;;
  val it : thm = |- p ==> q <=> p <=> p /\ q

Thu 11th Apr 2024               Examples/complexpolygon.ml

Added a proof that a polygon with all its vertices on the unit circle
is closed under complex multiplication iff the vertices are the n'th
complex roots of unity for some n. This is based on the discussion in

  https://math.stackexchange.com/questions/4892153

in particular the observation from Dario extending Carl Schildkraut's
proof of the original problem to an equivalence.

Thu 11th Apr 2024               Library/grouptheory.ml

Added a few new miscellaneous theorems:

  BILINEAR_IN_AFFINE_HULL =
    |- !f s t x y.
           bilinear f /\ x IN affine hull s /\ y IN affine hull t
           ==> f x y IN affine hull {f a b | a IN s /\ b IN t}

  BILINEAR_IN_CONVEX_HULL =
    |- !f s t x y.
           bilinear f /\ x IN convex hull s /\ y IN convex hull t
           ==> f x y IN convex hull {f a b | a IN s /\ b IN t}

  FINITE_SUBGROUP_OF_SETWISE =
    |- !G s.
           FINITE s
           ==> (s subgroup_of G <=>
                s SUBSET group_carrier G /\
                ~(s = {}) /\
                group_setmul G s s SUBSET s)

  SIMPLEX_FURTHEST_LT_EXISTS =
    |- !a s x.
           x IN convex hull s /\ ~(x IN s)
           ==> ?y. y IN s /\ norm(x - a) < norm(y - a)

as well as generalizing both SIMPLEX_FURTHEST_LT and SIMPLEX_FURTHEST_LE_EXISTS
to remove the finiteness assumption (hence perhaps making the "SIMPLEX" in the
name a bit misleading).

Tue  2nd Apr 2024               printer.ml, bool.ml, Arithmetic/passim, Model/passim

Fixed a bug in the printer where the interface map was not reversed for
binders. Also made a few minor name changes in the embedded logics to
avoid using "true" and "false", to make room for using those as alternative
names for T and F.

Mon  1st Apr 2024               sets.ml

Made a few useful improvements to SET_TAC and SET_RULE. First of all, they now
deal with conditionals at least to some extent (the previous failure to do so
was a basic bug). They also use streamlined versions of certain "write away set
concepts" rules such as UNIONS_GSPEC, which can be helpful preprocessing to
make the eventual MESON problem easier, or even provable at all. Here are a
couple of trivial examples that now work but didn't previously:

  SET_RULE `IMAGE (f:A->B) s = UNIONS {{f x} | x IN s}`;;

  SET_RULE `{a,b} DELETE (a:A) = if a = b then {} else {b}`;;

Fri 22nd Mar 2024               bool.ml

Made a few tiny optimizations to basic rules like CONJUNCT1 by switching
the implementation from PROVE_HYP to the underlying primitive rules
DEDUCT_ANTISYM_RULE and EQ_MP. This has the advantage of skipping a check
that in context we know is redundant (whether the PROVE_HYP is
non-trivial in the sense that the assumption is not there to start with).

Tue 19th Mar 2024               lib.ml

Made "strings_of_file" and "string_of_file" more robust so they can handle
bigger input files without problems. Previously, the core loop of
"strings_of_file" was not tail recursive because the body was enclosed in
a "try...with" block; this is now changed. The "string_of_file" function now
just uses more basic library functions directly instead of calling
"strings_of_file" and concatenating the results.

Mon 18th Mar 2024               Library/words.ml, Examples/bitblast.ml [new file]

Added a basic bit-blasting tactic and rule to the word library, using
BDDs as the backend by default (BITBLAST_TAC and BITBLAST_RULE) but
providing a more general BITBLAST_THEN that does the reduction followed
by another tactic (e.g. SAT). The new file "Examples/bitblast.ml" gives
a number of examples, mainly typical "Hacker's Delight" fare.

Sat 16th Mar 2024               Examples/bondy.ml [new file]

Added a new example, a proof of Bondy's theorem, following the first
of the two proofs given in Bollobas's "Combinatorics" for Theorem 1 (p4).

Fri 15th Mar 2024               Library/bdd.ml [new file], Examples/bdd_examples.ml [new file]

Added a new file giving a basic implementation (as a HOL derived rule) of
ordered binary decision diagrams with complement edges, a canonical form for
Boolean formulas. The style of implementation follows Brace, Rudell and
Bryant's paper "Efficient implementation of a BDD package" (DAC 1990). This
implementation is distantly descended from the hol90 implementation in "Binary
Decision Diagrams as a HOL Derived Rule", but greatly simplified since HOL
Light handles pointer-eq subterms more efficiently and so we can avoid
introducing any additional variables.

The two top-level functions are BDD_TAUT just taking a formula and BDD_DEFTAUT
taking both a list of variables determining the BDD variable order (allowed to
be empty in which case the default is used) and a formula that is also allowed
to contain "definitions". The examples in Examples/bdd_examples.ml give an idea
how to use these options.

Fri 15th Mar 2024               passim

Made a number of explicit type variable choices in theorems (and occasionally
fixed up or added quantifiers), just so things look tidier.

Thu 14th Mar 2024               Makefile, README, .github/workflows/main.yml, .gitignore [new file], hol_4.14.sh [new file], hol_4.sh [new file]

Added an update from June Lee that automatically creates (as part of
the default "make" target) a shell script "hol.sh" to run HOL Light
directly.

Wed 13th Mar 2024               Library/ringtheory.ml

Added a few more ring theory lemmas, mainly basic machinery including the
usual "Chinese remainder theorem" facts about Z_{m*n}, and also the simple
but rather obscure fact that Z_n is a von Neumann regular ring iff n is
squarefree:

  ISOMORPHIC_PROD_INTEGER_MOD_RING =
    |- !m n.
           integer_mod_ring (m * n) isomorphic_ring
           prod_ring (integer_mod_ring m) (integer_mod_ring n) <=>
           coprime(m,n)

  RING_CARRIER_INTEGER_MOD_RING =
    |- !n. ring_carrier (integer_mod_ring n) = IMAGE (\x. x rem &n) (:int)

  RING_HOMOMORPHISM_PROD_INTEGER_MOD_RING =
    |- !m n.
           ring_homomorphism
           (integer_mod_ring (m * n),
            prod_ring (integer_mod_ring m) (integer_mod_ring n))
           (\a. a rem &m,a rem &n)

  RING_ISOMORPHISM_PROD_INTEGER_MOD_RING =
    |- !m n.
           ring_isomorphism
           (integer_mod_ring (m * n),
            prod_ring (integer_mod_ring m) (integer_mod_ring n))
           (\a. a rem &m,a rem &n) <=>
           coprime(m,n)

  RING_OF_INT_PROD_RING =
    |- !r s n. ring_of_int (prod_ring r s) n = ring_of_int r n,ring_of_int s n

  RING_OF_NUM_PROD_RING =
    |- !r s n. ring_of_num (prod_ring r s) n = ring_of_num r n,ring_of_num s n

  VNREGULAR_INTEGER_MOD_RING =
    |- !n. vnregular_ring (integer_mod_ring n) <=> squarefree n

Wed 13th Mar 2024               Library/prime.ml, Library/pocklington.ml

Added a few more number theory lemmas, mainly involving "squarefree":

  FORALL_PRIME_INDEX =
    |- (!p. prime p ==> (!P. (!x. P (index p x)) <=> (!k. P k))) /\
       (!p. prime p ==> (!P. (!x. ~(x = 0) ==> P (index p x)) <=> (!k. P k)))

  SQUAREFREE =
    |- !n. squarefree n <=>
           ~(n = 0) /\ (!m k. n divides m EXP k ==> n divides m)

  SQUAREFREE_ALT =
    |- !n. squarefree n <=> ~(n = 0) /\ (!m. n divides m EXP 2 ==> n divides m)

  SQUAREFREE_DIVEXP =
    |- !n q x. squarefree q /\ q divides x EXP n ==> q divides x

  SQUAREFREE_DIVEXP_EQ =
    |- !n q x. squarefree q /\ ~(n = 0) ==> (q divides x EXP n <=> q divides x)

  SQUAREFREE_DIVIDES =
    |- !q n.
           squarefree q
           ==> (q divides n <=> (!p. prime p /\ p divides q ==> p divides n))

  SQUAREFREE_GCD =
    |- !m n. squarefree m \/ squarefree n ==> squarefree (gcd (m,n))

  SQUAREFREE_GCD_SQUARE =
    |- !n. squarefree n <=> (!x. gcd (x EXP 2,n) divides x)

Tue 12th Mar 2024               sets.ml, passim

Added one basic lemma that was previously regenerated many times via
SET_RULE

  IMAGE_EQ =
    |- !f g s. (!x. x IN s ==> f x = g x) ==> IMAGE f s = IMAGE g s

as well as a couple of elaborations of "image of a set is <= the set"
using two different imaging functions:

  CARD_IMAGE_LE2 =
    |- !f g s.
           FINITE s /\ (!x y. x IN s /\ y IN s /\ g x = g y ==> f x = f y)
           ==> CARD(IMAGE f s) <= CARD(IMAGE g s)

  CARD_IMAGE_LT2 =
    |- !f g s.
           FINITE s /\
           (!x y. x IN s /\ y IN s /\ g x = g y ==> f x = f y) /\
           ~(!x y. x IN s /\ y IN s /\ f x = f y ==> g x = g y)
           ==> CARD(IMAGE f s) < CARD(IMAGE g s)

Mon 11th Mar 2024               basics.ml, Minisat/minisat_prove.ml

Added a function "atoms" to return the set (as a list with no repetitions
but arbitrary order) of atomic formulas in a term, considering it as a
propositional formula and any non-propositional subterms as atomic:

  # atoms `x < 1 \/ x > 1 ==> ~(x = 1)`;;
  val it : term list = [`x < 1`; `x > 1`; `x = 1`]

Fri  1st Mar 2024               Library/words.ml

Added a few more miscellaneous word lemmas:

  BIT_REVERSEFIELDS_1 =
    |- !x i.
           bit i (word_reversefields 1 x) <=>
           i < dimindex (:N) /\ bit (dimindex (:N) - 1 - i) x

  WORD_CLZ_REVERSEFIELDS =
    |- !x. word_clz (word_reversefields 1 x) = word_ctz x

  WORD_CTZ_EMULATION_POPCOUNT =
    |- !x. word_ctz x =
           word_popcount (word_and (word_not x) (word_sub x (word 1)))

  WORD_CTZ_REVERSEFIELDS =
    |- !x. word_ctz (word_reversefields 1 x) = word_clz x

  WORD_EVENPARITY_POPCOUNT =
    |- !x. word (bitval (word_evenparity x)) =
           word_zx (word_not (word (word_popcount x)))

  WORD_MUL_EXPAND =
    |- !x y.
           word_mul x y =
           word
           (nsum {i | i < dimindex (:N)}
           (\i. bitval (bit i x) * val (word_shl y i)))

  WORD_MUL_EXPAND_ALT =
    |- !x y.
           word_mul x y =
           word
           (nsum {i | i < dimindex (:N)}
           (\i. val
                (word_and (word_neg (word (bitval (bit i x)))) (word_shl y i))))

  WORD_ODDPARITY_POPCOUNT =
    |- !x. word (bitval (word_oddparity x)) = word_zx (word (word_popcount x))

  WORD_POPCOUNT_MUL =
    |- !x y. word_popcount (word_mul x y) <= word_popcount x * word_popcount y

and two new type constructor/destructor utility functions,
"dest_word_ty" and "mk_word_ty", e.g.

  #  dest_word_ty `:int64`;;
  val it : num = 64

Fri  1st Mar 2024               printer.ml

Added a new printing option from June Lee, controlled by a flag
"print_types_of_subterms".

        0 - Behaviour as before, no printing of types
        1 - prints types of subterms containing invented type variables
        2 - prints the types of all constants and variables

Thu 29th Feb 2024               Library/words.ml

Augmented BIT_WORD_CONV to handle the two special cases of condition
and mask words based on "bitval b":

  BIT_WORD_CONV `bit 0 (word(bitval b):byte)`;;

  BIT_WORD_CONV `bit 42 (word_neg(word(bitval b)):int64)`;;

Tue 27th Feb 2024               Minisat/minisat_prove.ml, Minisat/README, Minisat/zc2mso/README

Made the overall GEN_SAT_PROVE, SAT_PROVE and ZSAT_PROVE initially convert
any non-variable atomic formulas into variables before calling the core
procedure. This makes things work on more general tautologies where the
atomic formulas are arbitrary.

Also made a few modernizations to the two README files to better reflect
the current experience with MiniSat and zchaff.


Wed 21st Feb 2024               EC/jacobian.ml

Added some alternative definitions of Jacobian-coordinate elliptic curve
operations with fewer special case distinctions, "jacobian_add_unexceptional"
and "jacobian_double_unexceptional". The key theorems still work for these,
with the exception of using the addition formula for doubling, which still
needs to be handled separately:

  WEIERSTRASS_OF_JACOBIAN_ADD_UNEXCEPTIONAL =
    |- !f a b p q.
          field f /\ ~(ring_char f = 2) /\ ~(ring_char f = 3) /\
          a IN ring_carrier f /\ b IN ring_carrier f /\
          jacobian_point f p /\ jacobian_point f q /\
          ~(jacobian_eq f p q)
          ==> weierstrass_of_jacobian f (jacobian_add_unexceptional (f,a,b) p q) =
              weierstrass_add (f,a,b)
               (weierstrass_of_jacobian f p)
               (weierstrass_of_jacobian f q)

  WEIERSTRASS_OF_JACOBIAN_DOUBLE_UNEXCEPTIONAL =
    |- !f a b p.
        field f /\ ~(ring_char f = 2) /\ ~(ring_char f = 3) /\
        a IN ring_carrier f /\ b IN ring_carrier f /\
        jacobian_point f p
        ==> weierstrass_of_jacobian f (jacobian_double_unexceptional (f,a,b) p) =
            weierstrass_add (f,a,b)
             (weierstrass_of_jacobian f p)
             (weierstrass_of_jacobian f p)

Wed 21st Feb 2024               calc_rat.ml, class.ml, define.ml, fusion.ml, int.ml, tactics.ml, Library/words.ml, Help/passim

Added an update from June Lee with two new tactics

  NAME_ASSUMS_TAC - names unlabelled assumptions ("H0", "H1" etc.)

  PRINT_GOAL_TAC - prints the current subgoal, useful for debugging

as well as several improvements in the error messages from automated
rules and tactics.

Wed 21st Feb 2024               Proofrecording/README

Fixed a broken link, thanks to Yiyuan Cao, in the Proofrecording
documentation, with an updated link to Chantal Keller's code for
replaying HOL Light proofs in Coq.

Tue 20th Feb 2024               Library/words.ml

Added a few additional word lemmas:

  DIGITSUM_UNIQUE =
    |- !B b c s n.
           FINITE s /\ (!i. i IN s ==> b i < B) /\ (!i. i IN s ==> c i < B)
           ==> (nsum s (\i. B EXP i * b i) = nsum s (\i. B EXP i * c i) <=>
                (!i. i IN s ==> b i = c i))

  VAL_EXPAND_SUBWORDS =
    |- !k m x.
           dimindex (:M) = k /\ dimindex (:N) = k * m
           ==> nsum {i | i < m}
               (\i. 2 EXP (k * i) * val (word_subword x (k * i,k))) =
               val x

  VAL_SUBWORDS_EQ =
    |- !k m f x.
           dimindex (:M) = k /\ dimindex (:N) = k * m
           ==> ((!i. i < m ==> val (word_subword x (k * i,k)) = f i) <=>
                (!i. i < m ==> f i < 2 EXP k) /\
                val x = nsum {i | i < m} (\i. 2 EXP (k * i) * f i))

  WORD_SUBWORD_ADD =
    |- !x y.
           dimindex (:M) = len /\
           pos + len <= dimindex (:N) /\
           val x MOD 2 EXP pos + val y MOD 2 EXP pos < 2 EXP pos
           ==> word_subword (word_add x y) (pos,len) =
               word_add (word_subword x (pos,len)) (word_subword y (pos,len))

  WORD_SUBWORDS_EQ =
    |- !k m f x.
           dimindex (:M) = k /\ dimindex (:N) = k * m
           ==> ((!i. i < m ==> val (word_subword x (k * i,k)) = f i) <=>
                (!i. i < m ==> f i < 2 EXP k) /\
                word (nsum {i | i < m} (\i. 2 EXP (k * i) * f i)) = x)

Tue 13th Feb 2024               arith.ml

Added a few more conditions for distributing DIV or MOD over addition:

  DIV_ADD_EQ =
    |- !n x y. x MOD n + y MOD n < n ==> (x + y) DIV n = x DIV n + y DIV n

  DIV_ADD_EQ_EQ =
    |- !n x y.
           (x + y) DIV n = x DIV n + y DIV n <=> n = 0 \/ x MOD n + y MOD n < n

  MOD_ADD_EQ =
    |- !n x y. x MOD n + y MOD n < n ==> (x + y) MOD n = x MOD n + y MOD n

  MOD_ADD_EQ_EQ =
    |- !n x y.
           (x + y) MOD n = x MOD n + y MOD n <=> n = 0 \/ x MOD n + y MOD n < n

Tue  6th Feb 2024               Library/words.ml

Added a couple of little word lemmas:

  INT_VAL_WORD_SUB =
    |- !x y.
           &(val (word_sub x y)) =
           (&(val x) - &(val y)) rem &2 pow dimindex(:N)

  IVAL_EQ_VAL =
    |- !x. val x < 2 EXP (dimindex(:N) - 1) ==> ival x = &(val x)

Mon  5th Feb 2024               Divstep/idivstep.ml

Added a few simple divstep lemmas, noting that once g = 0 the update
matrix remains diagonal thereafter:

  DIVSTEP_MAT_DIAGONAL =
    |- d f n. divstep_mat n (d,f,&0) $1$2 = &0 /\
              divstep_mat n (d,f,&0) $2$1 = &0

  DIVSTEP_MAT_DIAGONAL_1 =
    |- !d f g n. g = &0 ==> divstep_mat n (d,f,g) $1$2 = &0

  DIVSTEP_MAT_DIAGONAL_2 =
    |- !d f g n. g = &0 ==> divstep_mat n (d,f,g) $2$1 = &0

  IDIVSTEP_STAYS_ZERO =
    |- !d f g d' f' g'.
        g = &0 /\ idivstep(d,f,g) = d',f',g' ==> g' = &0

Fri 12th Jan 2024               preterm.ml, Help/type_invention_error.hlp

Added an update from June Lee to provide more explicit information
to accompany the type variable invention error triggered when the
"type_invention_warning" flag is set, e.g.

  # type_invention_error := true;;
  val it : unit = ()
  # `f x`;;
  Exception:
  Failure "typechecking error (cannot infer type of variables): f, x".

Fri 12th Jan 2024               README, Makefile

Added an update from June Lee which now correctly documents not only
the use of the DMTCP checkpointer with HOL Light, but also two other
checkpointing tools, CRIU and selfie.

Fri  3rd Nov 2023               cart.ml, Library/words.ml

Added various lemmas, mostly about machine words and with a focus
on bounds for "word_popcount" (population count, Hamming weight)
including its subadditivity (WORD_POPCOUNT_ADD). New theorems:

  BITS_OF_WORD_SUBSET =
    |- !x y. bits_of_word x SUBSET bits_of_word y <=>
             (!i. bit i x ==> bit i y)

  BITS_OF_WORD_SUBSET_ALT =
    |- !x y.
           bits_of_word x SUBSET bits_of_word y <=>
           (!i. i < dimindex(:M) /\ bit i x ==> bit i y)

  BITS_OF_WORD_SUBSET_NUMSEG =
    |- !x. bits_of_word x SUBSET {i | i < dimindex(:N)}

  BIT_WORD_JOIN_GEN =
    |- !e h l i.
           l < 2 EXP e
           ==> (ODD((2 EXP e * h + l) DIV 2 EXP i) <=>
                (if i < e
                 then ODD(l DIV 2 EXP i)
                 else ODD(h DIV 2 EXP (i - e))))

  NUMSEG_LT_DIMINDEX =
    |- {i | i < dimindex(:N)} = 0..dimindex(:N) - 1

  VAL_LE_SUBSET =
    |- !x y. bits_of_word x SUBSET bits_of_word y ==> val x <= val y

  WORD_OF_BITS_EMPTY =
    |- word_of_bits {} = word 0

  WORD_POPCOUNT_ADD =
    |- !x y. word_popcount(word_add x y) <= word_popcount x + word_popcount y

  WORD_POPCOUNT_ADD_DISJOINT =
    |- !x y.
           word_and x y = word 0
           ==> word_popcount(word_add x y) = word_popcount x + word_popcount y

  WORD_POPCOUNT_ADD_OR =
    |- !x y. word_popcount(word_add x y) <= word_popcount(word_or x y)

  WORD_POPCOUNT_AND =
    |- !x y.
           word_popcount(word_and x y) <=
           MIN (word_popcount x) (word_popcount y)

  WORD_POPCOUNT_BITVAL =
    |- !b. word_popcount(word(bitval b)) <= 1

  WORD_POPCOUNT_BOUND_SIZE =
    |- !x n. val x < 2 EXP n ==> word_popcount x <= n

  WORD_POPCOUNT_LE_BITS =
    |- !x y.
           (!i. i < dimindex(:M) /\ bit i x ==> bit i y)
           ==> word_popcount x <= word_popcount y

  WORD_POPCOUNT_NSUM =
    |- !x. word_popcount x =
           nsum {i | i < dimindex(:N)} (\i. bitval(bit i x))

  WORD_POPCOUNT_OR =
    |- !x y. word_popcount(word_or x y) <= word_popcount x + word_popcount y

  WORD_POPCOUNT_OR_AND =
    |- !x y.
           word_popcount(word_or x y) + word_popcount(word_and x y) =
           word_popcount x + word_popcount y

  WORD_POPCOUNT_OR_DISJOINT =
    |- !x y.
           word_and x y = word 0
           ==> word_popcount(word_or x y) = word_popcount x + word_popcount y

  WORD_POPCOUNT_SHL =
    |- !x n. word_popcount(word_shl x n) <= word_popcount x

  WORD_POPCOUNT_USHR =
    |- !x n. word_popcount(word_ushr x n) <= word_popcount x

  WORD_POPCOUNT_WORD_OF_BITS =
    |- !s. s SUBSET {i | i < dimindex(:N)}
           ==> word_popcount(word_of_bits s) = CARD s

  WORD_POPCOUNT_WORD_OF_BITS_GEN =
    |- !s. word_popcount(word_of_bits s) =
           CARD ({i | i < dimindex(:N)} INTER s)

  WORD_POPCOUNT_XOR =
    |- !x y. word_popcount(word_xor x y) <= word_popcount x + word_popcount y

  WORD_POPCOUNT_XOR_AND =
    |- !x y.
           word_popcount(word_xor x y) + word_popcount(word_and x y) =
           word_popcount(word_or x y)

  WORD_POPCOUNT_XOR_AND2 =
    |- !x y.
           word_popcount(word_xor x y) + 2 * word_popcount(word_and x y) =
           word_popcount x + word_popcount y

Thu  2nd Nov 2023               Library/words.ml

Added a construct "word_insert x (pos,len) y" which inserts a length len
subword of word y at position pos into x (with a result possibly another
wordsize), together with one basic lemma and support in BIT_WORD_CONV
and WORD_RED_CONV/WORD_REDUCE_CONV:

  word_insert =
   |- !x' len x pos.
         word_insert x (pos,len) x' =
         word
         (2 EXP (pos + len) * val x DIV 2 EXP (pos + len) +
          2 EXP pos * val x' MOD 2 EXP len +
          val x MOD 2 EXP pos)

  BIT_WORD_INSERT =
   |- !x x' pos len i.
         bit i (word_insert x (pos,len) x') <=>
         i < dimindex (:P) /\
         (if pos <= i /\ i < pos + len then bit (i - pos) x' else bit i x)

Fri 20th Oct 2023               tactics.ml, Help/print_all_thm.hlp, Help/print_goal_hyp_max_boxes.hlp [new file]

Added a variable controlling prettyprinter box limits on the hypotheses
of goals, from June Lee (PR https://github.com/jrh13/hol-light/pull/84).
This is

        print_goal_hyp_max_boxes

and can be set either to None (the default) or Some limit.

Fri 20th Oct 2023               hol.ml, Help/use_file_raise_failure.hlp [new file]

Made the recent error behavior on loads switchable by a flag, since
both behaviors can be useful. This is an update from June Lee
(see PR https://github.com/jrh13/hol-light/pull/83). The flag is

        use_file_raise_failure

Fri 20th Oct 2023               load_camlp5_topfind.ml, update_database_4.14.ml

Incorporated an update from June Lee to avoid loading compiler-libs.common
when using OCaml 4.14. This does have the side-effect of requiring an
explicit OCaml toplevel in more cases, but this is already recommended
in the latest README:

  ocamlmktop -o ocaml-hol

Fri 20th Oct 2023               Makefile, pa_j_4.xx_8.02.ml [new file]

Added support for another camlp5 version, 8.02, with a new file from
Stephane Glondu (see PR https://github.com/jrh13/hol-light/pull/81)

Thu 14th Sep 2023               hol.ml

Finally adopted an old improvement from Quentin Carbonneaux to the loading of
files containing errors via "loads" or "loadt", forcing an immediate stop on
the first error.

Thu 14th Sep 2023               README, hol.ml, load_camlp4.ml [new file], load_camlp5.ml [new file], load_camlp5_topfind.ml [new file]

Added an improved approach from June Lee to the camlp5 and num dependencies,
using Topfind to find them when the OCaml version is >= 4.14.

Tue 18th Jul 2023               Library/pocklington.ml, Library/integer.ml, 100/reciprocity.ml, 100/wilson.ml

Removed a couple of effective duplicates with this renaming

        CONG_MOD_MULT -> CONG_DIVIDES_MODULUS

        INT_CONG_MOD_MULT -> INT_CONG_INT_DIVIDES_MODULUS

Tue 18th Jul 2023               int.ml

Enhanced INT_ARITH, INT_ARITH_TAC and ASM_INT_ARITH_TAC with better reduction
of constant-expressions and elimination of div and rem analogous to that
already present for DIV and MOD in the corresponding natural number routines
ARITH_RULE etc. For example, the new version can handle basic lemmas like this:

  let lemma = prove
   (`abs(n) <= &2 pow 320
     ==> let p = &2 pow 255 - &19 in
         let q = n div &2 pow 255 in
         let q' = if q < &0 then q - &1 else q in
         &0 <= n - q' * p /\ n - q' * p < &2 * p`,
  REWRITE_TAC[LET_DEF; LET_END_DEF] THEN INT_ARITH_TAC);;

Mon 17th Jul 2023               lib.ml

Added two trivial but handy functions to convert an integer into a
hex string (string_of_num_hex), or a string to any base <= 16
(string_of_num_nary), e.g.

  # string_of_num_nary 2 (Int 255);;
  val it : string = "11111111"
  # string_of_num_nary 16 (Int 255);;
  val it : string = "ff"
  # string_of_num_nary 10 (Int 255);;
  val it : string = "255"
  #  string_of_num_hex (Int 126);;
  val it : string = "0x7e"

Mon 17th Jul 2023               Help/passim, help.ml, doc-to-help.sed

Renamed all the ".doc" documentation files (used by "help" as well as
in autogeneration of HTML and LaTeX reference documentation) to have
the ".hlp" extension instead. This avoids complaints from tools that
make assumptions about file type based on the extension.

Thu 13th Jun 2023               Library/words.ml

Added a few more miscellaneous word theorems. TWOS_COMPLEMENT is only
really word-specific in its use of the bitval constant, but anyway is
intended for word-oriented applications.

  BITVAL_MSB =
    |- !x. bitval(bit (dimindex(:N) - 1) x) =
           val x DIV 2 EXP (dimindex(:N) - 1)

  INT_VAL_IWORD =
    |- !x. &0 <= x /\ x < &2 pow dimindex(:N) ==> &(val(iword x)) = x

  INT_VAL_IWORD_EQ =
    |- !x. &(val(iword x)) = x <=> &0 <= x /\ x < &2 pow dimindex(:N)

  INT_VAL_WORD_NEG =
    |- !x. &(val(word_neg x)) =
           &2 pow dimindex(:N) * &(bitval(~(x = word 0))) - &(val x)

  REAL_VAL_WORD_NEG =
    |- !x. &(val(word_neg x)) =
           &2 pow dimindex(:N) * &(bitval(~(x = word 0))) - &(val x)

  TWOS_COMPLEMENT =
    |- !p n x.
           (&n == x) (mod (&2 pow p)) /\
           ~(p = 0) /\
           n < 2 EXP p /\
           --(&2 pow (p - 1)) <= x /\
           x < &2 pow (p - 1)
           ==> (2 EXP (p - 1) <= n <=> x < &0) /\
               n DIV 2 EXP (p - 1) = bitval(x < &0) /\
               &n - &2 pow p * &(bitval(x < &0)) = x

Wed 12th Jul 2023               int.ml

Added a couple of lemmas about bounding integer remainders in terms of
a bound on the left hand argument, a trivial but occasionally useful
case:

  INT_REM_LE =
    |- !m n p. (n = &0 \/ &0 <= m) /\ m <= p ==> m rem n <= p

  INT_REM_LE_EQ =
    |- !m n. m rem n <= m <=> n = &0 \/ &0 <= m

Tue 20th Jun 2023               Library/prime.ml, Library/pocklington.ml

Added a couple of simple lemmas that both, in slightly different ways,
help to work around the inconvenience of congruences on N with limited
support for subtraction, one by switching into Z and one by eliminating
an ostensible case split:

  PRIME_INT_DIVPROD_EQ =
    |- !p a b.
          prime p ==> (&p divides a * b <=> &p divides a \/ &p divides b)

  CONG_CASE =
    |- !n a x. a < n ==> ((x == a) (mod n) <=> ?q. x = q * n + a)

Wed 24th May 2023               Divstep/idivstep.ml [new file], divstep_bounds.ml

Added an integer-scaled version of "divstep", which scales the delta by a
factor of 2 and assumes that it is an odd number. This defines various
sub-functions for specific fields of the n-fold iteration of divstep.

Sat 20th May 2023               Library/words.ml

Added a few more lemmas about expressing "word_subword" as right+left
shifts, including the corresponding sign-extended version, and uniqueness for
"word_sxfrom":

  IVAL_WORD_SXFROM_UNIQUE =
    |- !w k x.
           k < dimindex(:N)
           ==> (ival(word_sxfrom k w) = x <=>
                --(&2 pow k) <= x /\
                x < &2 pow k /\
                (ival w == x) (mod (&2 pow (k + 1))))

  WORD_SUBWORD_AS_USHR_SHL =
    |- !x pos len.
           pos + len <= dimindex(:N)
           ==> word_subword x (pos,len) =
               word_ushr (word_shl x (dimindex(:N) - (pos + len)))
               (dimindex (:N) - len)

  WORD_SXFROM_SUBWORD_AS_ISHR_SHL =
    |- !x pos len.
           pos + len <= dimindex(:N) /\ 0 < len
           ==> word_sxfrom (len - 1) (word_subword x (pos,len)) =
               word_ishr (word_shl x (dimindex(:N) - (pos + len)))
               (dimindex(:N) - len)

Tue 16th May 2023               int.ml, Library/words.ml

Added two more elementary integer remainder lemmas (analogous to similar
ones for natural number MOD that are already there)

  INT_REM_REM_LE =
    |- !m n p. ~(n = &0) /\ abs n <= abs p ==> m rem n rem p = m rem n

  INT_REM_REM_POW_MIN =
    |- !x p m n. x rem p pow m rem p pow n = x rem p pow MIN m n

and a few miscellaneous useful word lemmas:

  DIVIDES_VAL_WORD =
    |- !n x.
         n <= dimindex(:N)
         ==> (2 EXP n divides val(word x) <=> 2 EXP n divides x)

  DIVIDES_VAL_WORD_EQ =
    |- !n x.
         2 EXP n divides val(word x) <=>
         (if n < dimindex(:N) then 2 EXP n divides x else word x = word 0)

  INT_DIVIDES_IVAL_IWORD =
    |- !n x.
         n <= dimindex(:N)
         ==> (&2 pow n divides ival(iword x) <=> &2 pow n divides x)

  INT_REM_IVAL_IWORD =
    |- !x k.
           k <= dimindex(:N) ==> ival(iword x) rem &2 pow k = x rem &2 pow k

  IVAL_WORD_ISHR_SHL_UNIQUE =
    |- !n x y.
           ival(word_ishr (word_shl x n) n) = y <=>
           ival(word_shl x n) = &2 pow n * y

  MOD_VAL_WORD =
    |- !n k. k <= dimindex(:N) ==> val(word n) MOD 2 EXP k = n MOD 2 EXP k

  VAL_IVAL_REM =
    |- !x. &(val x) = ival x rem &2 pow dimindex(:N)

  WORD_ISHR_UNIQUE =
    |- !x y n.
           ival x = &2 pow n * y
           ==> word_ishr x n = iword y

  WORD_SHL_AS_IWORD =
    |- !x n. word_shl x n = iword(ival x * &2 pow n)

  WORD_SHL_IWORD =
    |- !x n. word_shl (iword x) n = iword(&2 pow n * x)

  WORD_SHL_WORD =
    |- !x n. word_shl (word x) n = word(2 EXP n * x)

  WORD_SUBWORD_AS_IWORD =
    |- !w pos len.
           pos + len <= dimindex(:N)
           ==> word_subword w (pos,len) =
               iword((ival w div &2 pow pos) rem &2 pow len)

  WORD_SUBWORD_IWORD =
    |- !x pos len.
           pos + len <= dimindex(:N)
           ==> word_subword (iword x) (pos,len) =
               iword((x div &2 pow pos) rem &2 pow len)

  WORD_SUBWORD_WORD =
    |- !n pos len.
           pos + len <= dimindex(:N)
           ==> word_subword (word n) (pos,len) =
               word((n DIV 2 EXP pos) MOD 2 EXP len)

Tue 16th May 2023               nums.ml

Added an update from Juneyoung Lee to extend the free variable feedback
in the error messages (see change of Wed 25th Jan 2023 below) to the case
of "new_specification", and hence by inheritance in "define".

Fri 12th May 2023               Library/words.ml

Added a construct "word_sxfrom" to sign-extend a word (within a fixed size)
from an arbitrary bit position, together with a conversion WORD_SXFROM_CONV and
the usual support in BIT_WORD_CONV, WORD_RED_CONV and WORD_REDUCE_CONV. As well
as the basics about this, added a few more miscelleneous lemmas about signed
words and their values.

  word_sxfrom =
    |- word_sxfrom n x =
       word_ishr (word_shl x (dimindex(:N) - 1 - n)) (dimindex(:N) - 1 - n)

  BIT_LSB_IWORD =
    |- !x. bit 0 (iword x) <=> x rem &2 = &1

  BIT_WORD_SXFROM =
    |- !n i x. bit i (word_sxfrom n x) <=> i < dimindex(:N) /\ bit (MIN n i) x

  EXISTS_IWORD =
    |- !P. (?x. P x) <=> (?n. P (iword n))

  FORALL_IVAL =
    |- !P. (!x. P (ival x)) <=>
           (!n. --(&2 pow (dimindex(:N) - 1)) <= n /\
                n < &2 pow (dimindex(:N) - 1)
                ==> P n)

  FORALL_IVAL_GEN =
    |- !P. (!x. P (ival x) x) <=>
           (!n. --(&2 pow (dimindex(:N) - 1)) <= n /\
                n < &2 pow (dimindex(:N) - 1)
                ==> P n (iword n))

  FORALL_IWORD =
    |- !P. (!x. P x) <=> (!n. P (iword n))

  IVAL_REM_2 =
    |- !x. ival x rem &2 = &(bitval(bit 0 x))

Fri 12th May 2023               int.ml, calc_int.ml

Fixed a surprisingly gross bug in INT_ADD_CONV and REAL_INT_ADD_CONV
which were not failing as they should on some inappropriate terms
like `x 1 + x 2`.

Wed 10th May 2023               int.ml

Added a couple of trivial but handy properties about integer
remainders modulo 2:

  INT_REM_2_EXPAND =
   |- !x. x rem &2 = (if &2 divides x then &0 else &1)

  INT_REM_2_NEG =
   |- !x. --x rem &2 = x rem &2

Tue  9th May 2023               Library/grouptheory.ml

Added a few more elementary group theory lemmas:

  GROUP_INV_SUBGROUP =
    |- !x. x IN group_carrier (subgroup_generated G s)
           ==> group_inv G x IN group_carrier (subgroup_generated G s)

  GROUP_MUL_SUBGROUP =
    |- !x y.
           x IN group_carrier (subgroup_generated G s) /\
           y IN group_carrier (subgroup_generated G s)
           ==> group_mul G x y IN group_carrier (subgroup_generated G s)

  SUBGROUP_GENERATED_BY_EPIMORPHIC_IMAGE =
    |- !G H s f.
           group_epimorphism (G,H) f /\
           s SUBSET group_carrier G /\
           subgroup_generated G s = G
           ==> subgroup_generated H (IMAGE f s) = H

  SUBGROUP_GENERATED_BY_HOMOMORPHIC_IMAGE_EQ =
    |- !G H s t f.
           group_homomorphism (G,H) f /\
           s SUBSET group_carrier G /\
           t SUBSET group_carrier G /\
           subgroup_generated G s = subgroup_generated G t
           ==> subgroup_generated H (IMAGE f s) =
               subgroup_generated H (IMAGE f t)

Wed 26th Apr 2023               Library/bitmatch.ml

Added a function "bm_check_disjointness" written by Juneyoung Lee to check
whether word bitmatch patterns are pairwise disjoint, and hence whether the
semantics of the bitmatch is independent of their ordering. This can be quite
painful to analyze by hand in complicated cases but can now be done easily:

  # bm_check_disjointness
      `bitmatch (x:(2)word) with | [T; x] -> T | [y; T] -> T`;;
  Exception: Invalid_argument "Pattern number 1 and pattern number 0 overlap".

Mon 24th Apr 2023               Divstep/* [new directory]

Added a formalization, with an iteration bound proof from Dan Bernstein,
of the Bernstein-Yang "divstep" algorithm as described in the paper:

  Daniel J. Bernstein and Bo-Yin Yang
  "Fast constant-time gcd computation and modular inversion"
  https://gcd.cr.yp.to/safegcd-20190413.pdf

Wed 19th Apr 2023               Library/words.ml

Added a few more basic word lemmas about sign extension and related things:

  BIT_WORD_SX =
    |- !x i.
         bit i (word_sx x) <=>
         i < dimindex(:N) /\ bit (MIN i (dimindex(:M) - 1)) x

  WORD_SHL_TRIVIAL =
    |- !x n. dimindex(:N) <= n ==> word_shl x n = word 0

  WORD_SX_ZX =
    |- !x. dimindex(:N) <= dimindex(:M) ==> word_sx x = word_zx x

  WORD_SX_ZX_GEN =
    |- !x. word_sx x =
           word_or
           (word_shl (word_neg (word (bitval (bit (dimindex(:M) - 1) x))))
                     (dimindex(:M)))
           (word_zx x)

Fixed BIT_WORD_CONV to handle both zero and sign extension (word_zx and
word_sx) and made one further small improvement to WORD_BLAST, which among
other things means it can get this formula from "Hacker's Delight" 2-5:

  WORD_BLAST
   `word_sub (word_xor ((word_zx:byte->int16) x) (word 0x80))
             (word 0x80) =
    word_sx x`;;

Thu 13th Apr 2023               Library/words.ml

Made a few additional enhancements and cleanups to WORD_BLAST, in particular
making it try to use hypotheses of the form "val x < 2 EXP n" as well as
explicit equations. This includes fixing a bug in the VAL_EXPAND_CONV
expansion of "val x MOD 2 EXP n". For example, WORD_BLAST can now handle

  WORD_BLAST
   `val (x:int16) <= 255
    ==> word_add (word_and x (word 0x000F)) (word_and x (word 0x00F0)) = x`;;

Mon  3rd Apr 2023               Library/words.ml

Improved the ability of WORD_RULE to handle some arithmetic-bitwise
combinations (mainly arithmetic over bitwise rather than the reverse, so
still not a full solution the general case):

  WORD_RULE
    `word_add x y = word_add (word_xor x y) (word_shl (word_and x y) 1)`;;

Also added a fourth distinct words decision procedure, this one expanding
word expressions for specific sizes in terms of bits then using arithmetic
(not SAT as with full bit-blasting), e.g.

  WORD_BLAST
    `!x:int32. val(word_shl x 2) + 2 EXP 32 * val(word_ushr x 30) =
              4 * val x`;;

  WORD_BLAST
    `word_add (word_and x (word 0x0F)) (word_and x (word 0xF0)):byte = x`;;

These use a refactoring via new conversions:

 - BINT_POLY_CONV: like INT_POLY_CONV but exploiting the fact that
   higher powers of bit values b collapse as b^k = b (k >= 1)

 - WORD_VAL_CONG_CONV: converts word equation into integer congruence
   in terms of numeric values

 - VAL_EXPAND_CONV: expand "val x" (as well as, for a numeral k,
   "val x DIV 2 EXP k" and "val x MOD 2 EXP k") bitwise for words
   of a specific size.

Also added a few new lemmas:

  BITVAL_EXP =
    |- !b k. bitval b EXP k = (if k = 0 then 1 else bitval b)

  INT_BITVAL_AND =
    |- !b c. &(bitval(b /\ c)) = &(bitval b) * &(bitval c)

  INT_BITVAL_IFF =
    |- !b c.
           &(bitval(b <=> c)) =
           &1 - ((&(bitval b) + &(bitval c)) - &2 * &(bitval b) * &(bitval c))

  INT_BITVAL_IMP =
     |- !b c.
           &(bitval(b ==> c)) =
           (&1 - &(bitval b) + &(bitval c)) - (&1 - &(bitval b)) * &(bitval c)

  INT_BITVAL_OR =
     |- !b c.
           &(bitval(b \/ c)) =
           (&(bitval b) + &(bitval c)) - &(bitval b) * &(bitval c)

  INT_BITVAL_POW =
     |- !b k. &(bitval b) pow k = (if k = 0 then &1 else &(bitval b))

  VAL =
    |- !x. val x = nsum (0..dimindex(:N) - 1) (\i. 2 EXP i * bitval(bit i x))


Mon  3rd Apr 2023               int.ml

Added a collected clausal rewrite of all the "real_of_int" mapping
properties

  REAL_OF_INT_CLAUSES =
    |- (!x y. real_of_int x = real_of_int y <=> x = y) /\
       (!x y. real_of_int x >= real_of_int y <=> x >= y) /\
       (!x y. real_of_int x > real_of_int y <=> x > y) /\
       (!x y. real_of_int x <= real_of_int y <=> x <= y) /\
       (!x y. real_of_int x < real_of_int y <=> x < y) /\
       (!x y. max (real_of_int x) (real_of_int y) = real_of_int(max x y)) /\
       (!x y. min (real_of_int x) (real_of_int y) = real_of_int(min x y)) /\
       (!n. &n = real_of_int(&n)) /\
       (!x. --real_of_int x = real_of_int(--x)) /\
       (!x. abs(real_of_int x) = real_of_int(abs x)) /\
       (!x y. max (real_of_int x) (real_of_int y) = real_of_int(max x y)) /\
       (!x y. min (real_of_int x) (real_of_int y) = real_of_int(min x y)) /\
       (!x. real_sgn (real_of_int x) = real_of_int(int_sgn x)) /\
       (!x y. real_of_int x + real_of_int y = real_of_int(x + y)) /\
       (!x y. real_of_int x - real_of_int y = real_of_int(x - y)) /\
       (!x y. real_of_int x * real_of_int y = real_of_int(x * y)) /\
       (!x n. real_of_int x pow n = real_of_int(x pow n))

Thu 30th Mar 2023               Library/words.ml

Tweaked BIT_WORD_CONV to rewrite bits beyond the end of a word to "F" when
there are otherwise no applicable recursions, for example, on a variable:

  # BIT_WORD_CONV `bit 40 (x:int32)`;;
  val it : thm = |- bit 40 x <=> F

Thu 30th Mar 2023               pa_j_4.xx_8.00.ml

Restored to the latest version of the pa_j file the special "it" identifier
automatically assigned to otherwise nameless toplevel expressions:

  # 42;;
  val it : int = 42

Fri 10th Mar 2023               EC/ccsm2.ml [new file]

Added one more specific elliptic curve to the collection, the
SM2 curve. For more info see "https://www.cryptopp.com/wiki/SM2".
The parameters are taken from Table 11 (SM2_P256) here:

https://trustedcomputinggroup.org/wp-content/uploads/TCGAlgorithmRegistry_Rev01.15.pdf

Mon 27th Feb 2023               Library/words.ml

Added a general "reverse b-bit fields" operation generalizing the
existing "word_bytereverse", based on material from Juneyoung Lee.
The operation also works on inputs where the word size is not an
exact multiple of the field width, mapping bits in the upper overspill
from b * N DIV b upwards to themselves, for definiteness.

  word_reversefields =
    |- !b w.
           word_reversefields b w =
           word_of_bits
           {i | i < dimindex(:N) /\
                bit
                (if i < b * dimindex(:N) DIV b
                 then b * (dimindex(:N) DIV b - 1 - i DIV b) + i MOD b
                 else i)
                w}

This is supported by an extension of BIT_WORD_CONV and WORD_RED_CONV
as well as a custom conversion WORD_REVERSEFIELDS_CONV. Added a few
more basic lemmas about this and other word concepts:

  BIT_WORD_REVERSEFIELDS =
    |- !x b i.
           bit i (word_reversefields b x) <=>
           i < dimindex(:N) /\
           bit
           (if i < b * dimindex(:N) DIV b
            then b * (dimindex(:N) DIV b - 1 - i DIV b) + i MOD b
            else i)
           x

  VAL_WORD_AND_POW2_BITVAL =
    |- (!x k b.
            val (word_and x (word (2 EXP k * bitval b))) =
            2 EXP k * bitval (bit k x /\ b)) /\
       (!x k b.
            val (word_and (word (2 EXP k * bitval b)) x) =
            2 EXP k * bitval (b /\ bit k x))

  WORD_AND_POW2_BITVAL =
    |- (!x k b.
            word_and x (word (2 EXP k * bitval b)) =
            word (2 EXP k * bitval (bit k x /\ b))) /\
       (!x k b.
            word_and (word (2 EXP k * bitval b)) x =
            word (2 EXP k * bitval (b /\ bit k x)))

  WORD_BYTEREVERSE_REVERSEFIELDS =
    |- word_bytereverse = word_reversefields 8

  WORD_REVERSEFIELDS_REVERSEFIELDS =
    |- !x b. word_reversefields b (word_reversefields b x) = x

  WORD_SHL_LSB =
    |- !x. word_shl x (dimindex(:N) - 1) =
           word (2 EXP (dimindex(:N) - 1) * bitval (bit 0 x))

  WORD_SHL_LSB_ALT =
    |- !x. word_shl x (dimindex(:N) - 1) =
           (if bit 0 x then word (2 EXP (dimindex(:N) - 1)) else word 0)

Mon 27th Feb 2023               calc_num.ml

Updated NUM_DIV_CONV and NUM_MOD_CONV to handle the degenerate cases
of the form `m DIV 0` and `m MOD 0` (where m is a numeral), which
are fixed by definition to convenient values, 0 and m respectively.

Fri 27th Jan 2023               Makefile, update_database_4.14.ml [new file], pa_j_4.xx_8.00.ml [renamed pa_j_8.xx.ml]

Added an update from Juneyoung Lee based on work by Chet Murthy
to make the "update_database" functionality work in OCaml 4.14.

Wed 25th Jan 2023               fusion.ml

Added an update from Juneyoung Lee that provides better feedback
when definitions are disallowed because of free variables by
listing those free variables in the failure string.

Wed 25th Jan 2023               Makefile, pa_j_8.xx.ml [new file]

Added an update from Quentin Carbonneaux with support for newer
OCaml (4.14) and camlp5 (8.00) versions.

Thu 19th Jan 2023               Library/words.ml

Made a change from Juneyoung Lee generalizing the types of the "usimdN"
constructors so that the source and destination types can differ:
usimd2, usimd4 and usimd8.

Tue 13th Dec 2022               100/isoperimetric.ml [new file], Multivariate/passim

Added a proof of the isoperimetric theorem to the "100 greatest
theorems" subdirectory. The proof roughly follows the sketch in
Osserman's "The Isoperimetric Inequality" (Bulletin of the AMS,
1978), straightforwardly generalized to avoid any smoothness
assumption, and with the proof of Wirtinger's inequality taken from
Hardy, Littlewood and Polya's "Inequalities". The Green's theorem
line integral for area is done in a very limited ad hoc way just
for this single application.

As part of this added quite a few general supporting Multivariate
theorems, notably a Hoelder-based bound (Hardy-Littlewood-Polya
theorem 222) and a fairly general form of integration by
substitution following Serrin and Varberg's paper "A general
chain rule...". Their Theorem 1 on critical values is called
CONVERSE_SARD_1 following their observation that it is very
much like a converse to BABY_SARD. Our proof is via a more
general CONVERSE_SARD simply using the existing theorem
NEGLIGIBLE_DIFFERENTIABLE_PREIMAGE.

Thu 17th Nov 2022               EC/exprojective.ml

Added more to the Edwards extended projective coordinates material,
notably defining a pure projective relational analog "projective"
and various formulations of the doubling formula using both this
and extended projective. New definitions:

  edwards_exprojdouble =
    |- edwards_exprojdouble (f,a,d) (X1,Y1,Z1,T1) =
       edwards_prexprojdouble (f,a,d) (X1,Y1,Z1)

  edwards_pcurve =
    |- edwards_pcurve (f,a,d) (X,Y,Z) <=>
       X IN ring_carrier f /\
       Y IN ring_carrier f /\
       Z IN ring_carrier f /\
       ~(Z = ring_0 f) /\
       ring_mul f (ring_pow f Z 2)
       (ring_add f (ring_mul f a (ring_pow f X 2)) (ring_pow f Y 2)) =
       ring_add f (ring_pow f Z 4)
       (ring_mul f d (ring_mul f (ring_pow f X 2) (ring_pow f Y 2)))

  edwards_prexprojdouble =
    |- edwards_prexprojdouble (f,a,d) (X1,Y1,Z1) =
       ring_mul f (ring_of_num f 2)
       (ring_mul f X1
       (ring_mul f Y1
       (ring_sub f
        (ring_sub f (ring_mul f (ring_of_num f 2) (ring_pow f Z1 2))
        (ring_pow f Y1 2))
       (ring_mul f a (ring_pow f X1 2))))),
       ring_mul f
       (ring_add f (ring_pow f Y1 2) (ring_mul f a (ring_pow f X1 2)))
       (ring_sub f (ring_pow f Y1 2) (ring_mul f a (ring_pow f X1 2))),
       ring_mul f
       (ring_add f (ring_pow f Y1 2) (ring_mul f a (ring_pow f X1 2)))
       (ring_sub f
        (ring_sub f (ring_mul f (ring_of_num f 2) (ring_pow f Z1 2))
        (ring_pow f Y1 2))
       (ring_mul f a (ring_pow f X1 2))),
       ring_mul f (ring_of_num f 2)
       (ring_mul f X1
       (ring_mul f Y1
       (ring_sub f (ring_pow f Y1 2) (ring_mul f a (ring_pow f X1 2)))))

  edwards_prexprojdoublen =
    |- edwards_prexprojdoublen (f,a,d) (X1,Y1,Z1) =
       (let X3,Y3,Z3,T3 = edwards_prexprojdouble (f,a,d) (X1,Y1,Z1) in
        ring_neg f X3,ring_neg f Y3,ring_neg f Z3,ring_neg f T3)

  edwards_projdouble =
    |- edwards_projdouble (f,a,d) (X1,Y1,Z1) =
       (let X2,Y2,Z2,T2 = edwards_prexprojdouble (f,a,d) (X1,Y1,Z1) in
        X2,Y2,Z2)

  projective =
    |- projective f (x,y) (X,Y,Z) <=>
       x IN ring_carrier f /\
       y IN ring_carrier f /\
       X IN ring_carrier f /\
       Y IN ring_carrier f /\
       Z IN ring_carrier f /\
       ~(Z = ring_0 f) /\
       ring_div f X Z = x /\
       ring_div f Y Z = y

and theorems:

  EDWARDS_EXPROJDOUBLE =
    |- !f a d x1 y1 X1 Y1 Z1 T1.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_nonsingular (f,a,d) /\
           edwards_curve (f,a,d) (x1,y1) /\
           exprojective f (x1,y1) (X1,Y1,Z1,T1)
           ==> exprojective f (edwards_add (f,a,d) (x1,y1) (x1,y1))
               (edwards_exprojdouble (f,a,d) (X1,Y1,Z1,T1))

  EDWARDS_EXPROJDOUBLE_EXPROJADD =
    |- !f a d X1 Y1 Z1 T1.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_excurve (f,a,d) (X1,Y1,Z1,T1)
           ==> edwards_exprojdouble (f,a,d) (X1,Y1,Z1,T1) =
               edwards_exprojadd (f,a,d) (X1,Y1,Z1,T1) (X1,Y1,Z1,T1)

  EDWARDS_PCURVE =
    |- !f a d p Q.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           projective f p Q
           ==> (edwards_curve (f,a,d) p <=> edwards_pcurve (f,a,d) Q)

  EDWARDS_PREXPROJDOUBLE =
    |- !f a d x1 y1 X1 Y1 Z1.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_nonsingular (f,a,d) /\
           edwards_curve (f,a,d) (x1,y1) /\
           projective f (x1,y1) (X1,Y1,Z1)
           ==> exprojective f (edwards_add (f,a,d) (x1,y1) (x1,y1))
               (edwards_prexprojdouble (f,a,d) (X1,Y1,Z1))

  EDWARDS_PREXPROJDOUBLEN =
    |- !f a d x1 y1 X1 Y1 Z1.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_nonsingular (f,a,d) /\
           edwards_curve (f,a,d) (x1,y1) /\
           projective f (x1,y1) (X1,Y1,Z1)
           ==> exprojective f (edwards_add (f,a,d) (x1,y1) (x1,y1))
               (edwards_prexprojdoublen (f,a,d) (X1,Y1,Z1))

  EDWARDS_PREXPROJDOUBLEN_EXPROJADDN =
    |- !f a d X1 Y1 Z1 T1.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_excurve (f,a,d) (X1,Y1,Z1,T1)
           ==> edwards_prexprojdoublen (f,a,d) (X1,Y1,Z1) =
               edwards_exprojaddn (f,a,d) (X1,Y1,Z1,T1) (X1,Y1,Z1,T1)

  EDWARDS_PREXPROJDOUBLE_EXPROJADD =
    |- !f a d X1 Y1 Z1 T1.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_excurve (f,a,d) (X1,Y1,Z1,T1)
           ==> edwards_prexprojdouble (f,a,d) (X1,Y1,Z1) =
               edwards_exprojadd (f,a,d) (X1,Y1,Z1,T1) (X1,Y1,Z1,T1)

  EDWARDS_PROJDOUBLE =
    |- !f a d x1 y1 X1 Y1 Z1.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_nonsingular (f,a,d) /\
           edwards_curve (f,a,d) (x1,y1) /\
           projective f (x1,y1) (X1,Y1,Z1)
           ==> projective f (edwards_add (f,a,d) (x1,y1) (x1,y1))
               (edwards_projdouble (f,a,d) (X1,Y1,Z1))

  EXPROJECTIVE_PROJECTIVE =
    |- !f x y X Y Z W.
           field f
           ==> (exprojective f (x,y) (X,Y,Z,W) <=>
                projective f (x,y) (X,Y,Z) /\ ring_div f (ring_mul f X Y) Z = W)

  EXPROJECTIVE_PROJECTIVE_ALT =
    |- !f x y X Y Z W.
           field f
           ==> (exprojective f (x,y) (X,Y,Z,W) <=>
                projective f (x,y) (X,Y,Z) /\
                W IN ring_carrier f /\
                ring_mul f X Y = ring_mul f W Z)

  PROJECTIVE_ALT =
    |- !f x y X Y Z.
           field f
           ==> (projective f (x,y) (X,Y,Z) <=>
                x IN ring_carrier f /\
                y IN ring_carrier f /\
                X IN ring_carrier f /\
                Y IN ring_carrier f /\
                Z IN ring_carrier f /\
                ~(Z = ring_0 f) /\
                ring_mul f x Z = X /\
                ring_mul f y Z = Y)

  PROJECTIVE_EXPROJECTIVE =
    |- !f x y X Y Z.
           field f
           ==> (projective f (x,y) (X,Y,Z) <=>
                exprojective f (x,y) (X,Y,Z,ring_div f (ring_mul f X Y) Z))

while removing the former EDWARDS_EXPROJADD_DOUBLE (which is effectively
just EDWARDS_EXPROJDOUBLE_EXPROJADD reversed and with the new definition
expanded).

Wed  9th Nov 2022               Library/words.ml

Added some natural notations for n-fold SIMD-style repetition of unary and
binary operations on machine words, following the index type to decompose:

  simd2 =
    |- !f x y.
           simd2 f x y =
           word_join
           (f (word_subword x (dimindex(:N),dimindex(:N)))
           (word_subword y (dimindex(:N),dimindex(:N))))
           (f (word_subword x (0,dimindex(:N)))
           (word_subword y (0,dimindex(:N))))

  simd4 =
    |- !f. simd4 f = simd2 (simd2 f)

  simd8 =
    |- !f. simd8 f = simd2 (simd4 f)

  simd16 =
    |- !f. simd16 f = simd2 (simd8 f)

  usimd2 =
    |- !f x.
           usimd2 f x =
           word_join (f (word_subword x (dimindex(:N),dimindex(:N))))
           (f (word_subword x (0,dimindex(:N))))
  usimd4 =
    |- !f. usimd4 f = usimd2 (usimd2 f)

  usimd8 =
    |- !f. usimd8 f = usimd2 (usimd4 f)

  usimd16 =
    |- !f. usimd16 f = usimd2 (usimd8 f)

  SIMD2 =
    |- !f xhi xlo yhi ylo.
           simd2 f (word_join xhi xlo) (word_join yhi ylo) =
           word_join (f xhi yhi) (f xlo ylo)

  USIMD2 =
    |- !f xhi xlo. usimd2 f (word_join xhi xlo) = word_join (f xhi) (f xlo)

Mon  7th Nov 2022               EC/x25519.ml, EC/edwards.ml, EC/edwards448.ml

Added the nonzeroness of the X25519 function on the standard basepoint X = 9:

 RFCX25519_BASE_NONZERO =
   |- !n. ~(rfcx25519(n,9) = 0)

as well as systematically renaming these theorems to be more intuitive,
albeit even more verbose:

  EDWARDS_GROUP_ORDER_EQ_2        -> EDWARDS_GROUP_ELEMENT_ORDER_EQ_2
  EDWARDS_GROUP_ORDER_EQ_4        -> EDWARDS_GROUP_ELEMENT_ORDER_EQ_4
  EDWARDS_GROUP_ORDER_EQ_4_EQUIV  -> EDWARDS_GROUP_ELEMENT_ORDER_EQ_4_EQUIV
  EDWARDS_GROUP_ORDER_EQ_8        -> EDWARDS_GROUP_ELEMENT_ORDER_EQ_8
  EDWARDS_GROUP_ORDER_EQ_8_EQUIV  -> EDWARDS_GROUP_ELEMENT_ORDER_EQ_8_EQUIV

Mon 17th Oct 2022               EC/exprojective.ml [new file], passim

Added a new file with some basic material on extended projective coordinates
for Edwards curves, with several variants of the basic extended projective
addition with different scale factors and their core relationships with the
affine representation:

  edwards_excurve =
    |- edwards_excurve (f,a,d) (X,Y,Z,W) <=>
       X IN ring_carrier f /\
       Y IN ring_carrier f /\
       Z IN ring_carrier f /\
       W IN ring_carrier f /\
       ~(Z = ring_0 f) /\
       ring_add f (ring_mul f a (ring_pow f X 2)) (ring_pow f Y 2) =
       ring_add f (ring_pow f Z 2) (ring_mul f d (ring_pow f W 2))

  edwards_exprojadd =
    |- edwards_exprojadd (f,a,d) (X1,Y1,Z1,T1) (X2,Y2,Z2,T2) =
       ring_mul f (ring_add f (ring_mul f X1 Y2) (ring_mul f Y1 X2))
       (ring_sub f (ring_mul f Z1 Z2) (ring_mul f d (ring_mul f T1 T2))),
       ring_mul f
       (ring_sub f (ring_mul f Y1 Y2) (ring_mul f a (ring_mul f X1 X2)))
       (ring_add f (ring_mul f Z1 Z2) (ring_mul f d (ring_mul f T1 T2))),
       ring_mul f
       (ring_sub f (ring_mul f Z1 Z2) (ring_mul f d (ring_mul f T1 T2)))
       (ring_add f (ring_mul f Z1 Z2) (ring_mul f d (ring_mul f T1 T2))),
       ring_mul f
       (ring_sub f (ring_mul f Y1 Y2) (ring_mul f a (ring_mul f X1 X2)))
       (ring_add f (ring_mul f X1 Y2) (ring_mul f Y1 X2))

  edwards_exprojadd4 =
    |- edwards_exprojadd4 (f,a,d) (X1,Y1,Z1,T1) (X2,Y2,Z2,T2) =
       (let X3,Y3,Z3,T3 =
          edwards_exprojadd (f,a,d) (X1,Y1,Z1,T1) (X2,Y2,Z2,T2) in
        ring_mul f (ring_of_num f 4) X3,
        ring_mul f (ring_of_num f 4) Y3,
        ring_mul f (ring_of_num f 4) Z3,
        ring_mul f (ring_of_num f 4) T3)

  edwards_exprojaddn =
    |- edwards_exprojaddn (f,a,d) (X1,Y1,Z1,T1) (X2,Y2,Z2,T2) =
       (let X3,Y3,Z3,T3 =
          edwards_exprojadd (f,a,d) (X1,Y1,Z1,T1) (X2,Y2,Z2,T2) in
        ring_neg f X3,ring_neg f Y3,ring_neg f Z3,ring_neg f T3)

  exprojective =
    |- exprojective f (x,y) (X,Y,Z,W) <=>
       x IN ring_carrier f /\
       y IN ring_carrier f /\
       X IN ring_carrier f /\
       Y IN ring_carrier f /\
       W IN ring_carrier f /\
       Z IN ring_carrier f /\
       ~(Z = ring_0 f) /\
       ring_div f X Z = x /\
       ring_div f Y Z = y /\
       ring_div f W Z = ring_mul f x y

  EDWARDS_EXCURVE =
    |- !f a d p Q.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           exprojective f p Q
           ==> (edwards_curve (f,a,d) p <=> edwards_excurve (f,a,d) Q)

  EDWARDS_EXPROJADD =
    |- !f a d x1 y1 X1 Y1 Z1 T1 x2 y2 X2 Y2 Z2 T2.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_nonsingular (f,a,d) /\
           edwards_curve (f,a,d) (x1,y1) /\
           edwards_curve (f,a,d) (x2,y2) /\
           exprojective f (x1,y1) (X1,Y1,Z1,T1) /\
           exprojective f (x2,y2) (X2,Y2,Z2,T2)
           ==> exprojective f (edwards_add (f,a,d) (x1,y1) (x2,y2))
               (edwards_exprojadd (f,a,d) (X1,Y1,Z1,T1) (X2,Y2,Z2,T2))

  EDWARDS_EXPROJADD4 =
    |- !f a d x1 y1 X1 Y1 Z1 T1 x2 y2 X2 Y2 Z2 T2.
           field f /\
           ~(ring_char f = 2) /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_nonsingular (f,a,d) /\
           edwards_curve (f,a,d) (x1,y1) /\
           edwards_curve (f,a,d) (x2,y2) /\
           exprojective f (x1,y1) (X1,Y1,Z1,T1) /\
           exprojective f (x2,y2) (X2,Y2,Z2,T2)
           ==> exprojective f (edwards_add (f,a,d) (x1,y1) (x2,y2))
               (edwards_exprojadd4 (f,a,d) (X1,Y1,Z1,T1) (X2,Y2,Z2,T2))

  EDWARDS_EXPROJADDN =
    |- !f a d x1 y1 X1 Y1 Z1 T1 x2 y2 X2 Y2 Z2 T2.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_nonsingular (f,a,d) /\
           edwards_curve (f,a,d) (x1,y1) /\
           edwards_curve (f,a,d) (x2,y2) /\
           exprojective f (x1,y1) (X1,Y1,Z1,T1) /\
           exprojective f (x2,y2) (X2,Y2,Z2,T2)
           ==> exprojective f (edwards_add (f,a,d) (x1,y1) (x2,y2))
               (edwards_exprojaddn (f,a,d) (X1,Y1,Z1,T1) (X2,Y2,Z2,T2))

  EDWARDS_EXPROJADD_DOUBLE =
    |- !f a d X1 Y1 Z1 T1.
           field f /\
           a IN ring_carrier f /\
           d IN ring_carrier f /\
           edwards_excurve (f,a,d) (X1,Y1,Z1,T1)
           ==> edwards_exprojadd (f,a,d) (X1,Y1,Z1,T1) (X1,Y1,Z1,T1) =
               ring_mul f (ring_of_num f 2)
               (ring_mul f X1
               (ring_mul f Y1
               (ring_sub f
                (ring_sub f (ring_mul f (ring_of_num f 2) (ring_pow f Z1 2))
                (ring_pow f Y1 2))
               (ring_mul f a (ring_pow f X1 2))))),
               ring_mul f
               (ring_add f (ring_pow f Y1 2) (ring_mul f a (ring_pow f X1 2)))
               (ring_sub f (ring_pow f Y1 2) (ring_mul f a (ring_pow f X1 2))),
               ring_mul f
               (ring_add f (ring_pow f Y1 2) (ring_mul f a (ring_pow f X1 2)))
               (ring_sub f
                (ring_sub f (ring_mul f (ring_of_num f 2) (ring_pow f Z1 2))
                (ring_pow f Y1 2))
               (ring_mul f a (ring_pow f X1 2))),
               ring_mul f (ring_of_num f 2)
               (ring_mul f X1
               (ring_mul f Y1
               (ring_sub f (ring_pow f Y1 2) (ring_mul f a (ring_pow f X1 2)))))

  EXPROJECTIVE_ALT =
    |- !f x y X Y Z W.
           field f
           ==> (exprojective f (x,y) (X,Y,Z,W) <=>
                x IN ring_carrier f /\
                y IN ring_carrier f /\
                X IN ring_carrier f /\
                Y IN ring_carrier f /\
                W IN ring_carrier f /\
                Z IN ring_carrier f /\
                ~(Z = ring_0 f) /\
                ring_mul f x Z = X /\
                ring_mul f y Z = Y /\
                ring_mul f W Z = ring_mul f X Y)

Also fixed some fumbled theorem names "EDWARD_..." to "EDWARDS_..." in the
existing material.

Mon 19th Sep 2022               Library/words.ml

Added a definition of the byte reversal operation to the word library,
including the following definition and basic lemmas as well as adding
its reduction to the usual conversions like WORD_RED_CONV. The type
is constrained so that the indexing type has to be effectively a
multiple of 8 (i.e. of the form :(((N)tybit0)tybit0)tybit0).

  word_bytereverse =
   |- word_bytereverse x =
      word_of_bits { i | i < 8 * dimindex(:N) /\
                         bit (8 * (dimindex(:N) - 1 - i DIV 8) + i MOD 8) x}

  BIT_WORD_BYTEREVERSE =
   |- !x i. bit i (word_bytereverse x) <=>
            i < 8 * dimindex(:N) /\
            bit (8 * (dimindex(:N) - 1 - i DIV 8) + i MOD 8) x

  WORD_BYTEREVERSE_BYTEREVERSE =
   |- !x. word_bytereverse(word_bytereverse x) = x

Thu 15th Sep 2022               EC/x25519.ml [new file]

Added a definition of x25519, the curve25519 x-coordinate mapping that
allows the y coordinate to live in an extension field, following
Bernstein's original paper and RFC-7748. This development includes the
auxiliary concept of a quadratic extension field, which is only used
to construct the special case (Z/(2^255-19))[sqrt(2)]). There are
two variants "purex25519" and "rfcx25519", with the latter adding the
specific prenormalization from the RFC (considering the inputs as
numbers).

  curve25519x =
    |- curve25519x f = f,ring_of_num f A_25519,ring_of_num f 1

  curve25519x_curve25519 =
    |- curve25519x (integer_mod_ring p_25519) = curve25519

  curve25519x_group =
    |- curve25519x_group f = montgomery_group (curve25519x f)

  purex25519 =
    |- !n q.
           purex25519 (n,q) =
           (@s. s < p_25519 /\
                (!Q. Q IN group_carrier (curve25519x_group sqintmod_field) /\
                     montgomery_xmap sqintmod_field Q =
                     ring_of_num sqintmod_field q
                     ==> montgomery_xmap sqintmod_field
                         (group_pow (curve25519x_group sqintmod_field) Q n) =
                         ring_of_num sqintmod_field s))

  purex25519_def =
    |- purex25519 (n,q) =
       (if q MOD p_25519 = 0
        then 0
        else let X,Z = FST (x25519_ladder n (&q,&1)) in
             let x = num_of_int (X rem &p_25519)
             and z = num_of_int (Z rem &p_25519) in
             if z = 0 then 0 else (x * inverse_mod p_25519 z) MOD p_25519)

  quadratic_extension =
    |- !a r.
           quadratic_extension r a =
           ring
           (ring_carrier r CROSS ring_carrier r,
            (ring_0 r,ring_0 r),
            (ring_1 r,ring_0 r),
            (\(x,y). ring_neg r x,ring_neg r y),
            (\(x1,y1) (x2,y2). ring_add r x1 x2,ring_add r y1 y2),
            (\(x1,y1) (x2,y2).
                 ring_add r (ring_mul r x1 x2)
                 (ring_mul r (ring_of_num r a) (ring_mul r y1 y2)),
                 ring_add r (ring_mul r x1 y2) (ring_mul r x2 y1)))

  rfcx25519 =
    |- rfcx25519 (n,q) =
       purex25519 (2 EXP 254 + n MOD 2 EXP 254 - n MOD 8,q MOD 2 EXP 255)

  sqintmod_field =
    |- sqintmod_field = quadratic_extension (integer_mod_ring p_25519) 2

  x25519_ladder =
    |- x25519_ladder n P =
       (if n = 0
        then (&1,&0),P
        else x25519_ladderstep (n MOD 2 = 1) P (x25519_ladder (n DIV 2) P))

  x25519_ladderstep =
    |- x25519_ladderstep b P (P0,P1) =
       (if b
        then montgomery_xzdiffadd curve25519 P P1 P0,
             montgomery_xzdouble curve25519 P1
        else montgomery_xzdouble curve25519 P0,
             montgomery_xzdiffadd curve25519 P P1 P0)

  CURVE25519X_CURVE25519_GROUP =
    |- curve25519x_group (integer_mod_ring p_25519) = curve25519_group

  CURVE25519X_GROUP =
    |- !f. field f /\ ring_char f = p_25519
           ==> group_carrier (curve25519x_group f) =
               montgomery_curve (curve25519x f) /\
               group_id (curve25519x_group f) = NONE /\
               group_inv (curve25519x_group f) = montgomery_neg (curve25519x f) /\
               group_mul (curve25519x_group f) = montgomery_add (curve25519x f)

  CURVE25519X_GROUP_GEN =
    |- !f. field f /\ ~(ring_char f divides 14802493890)
           ==> group_carrier (curve25519x_group f) =
               montgomery_curve (curve25519x f) /\
               group_id (curve25519x_group f) = NONE /\
               group_inv (curve25519x_group f) = montgomery_neg (curve25519x f) /\
               group_mul (curve25519x_group f) = montgomery_add (curve25519x f)

  FIELD_QUADRATIC_EXTENSION =
    |- !r a.
           field r /\
           (!d. d IN ring_carrier r ==> ~(ring_pow r d 2 = ring_of_num r a))
           ==> field (quadratic_extension r a)

  FIELD_SQINTMOD_FIELD =
    |- field sqintmod_field

  GROUP_POW_CURVE25519X_TORSION =
    |- !f n.
           field f /\ ring_char f = p_25519
           ==> group_pow (curve25519x_group f) (SOME (ring_0 f,ring_0 f)) n =
               (if EVEN n then NONE else SOME (ring_0 f,ring_0 f))

  MONTGOMERY_NONSINGULAR_CURVE25519X =
    |- !f. field f /\ ring_char f = p_25519
           ==> montgomery_nonsingular (curve25519x f)

  MONTGOMERY_NONSINGULAR_CURVE25519X_GEN =
    |- !f. field f /\ ~(ring_char f divides 14802493890)
           ==> montgomery_nonsingular (curve25519x f)

  PUREX25519 =
    |- !f n q Q.
           field f /\
           ring_char f = p_25519 /\
           Q IN group_carrier (curve25519x_group f) /\
           montgomery_xmap f Q = ring_of_num f q
           ==> montgomery_xmap f (group_pow (curve25519x_group f) Q n) =
               ring_of_num f (purex25519 (n,q))

  PUREX25519_BOUND =
    |- !n q. purex25519 (n,q) < p_25519

  PUREX25519_LADDER =
    |- !f x y n.
           field f /\
           ring_char f = p_25519 /\
           SOME (ring_of_num f x,y) IN group_carrier (curve25519x_group f) /\
           ~(ring_of_num f x = ring_0 f)
           ==> (let (X,Z),X',Z' = x25519_ladder n (&x,&1) in
                montgomery_xz f
                (group_pow (curve25519x_group f) (SOME (ring_of_num f x,y)) n)
                (ring_of_int f X,ring_of_int f Z) /\
                montgomery_xz f
                (group_pow (curve25519x_group f) (SOME (ring_of_num f x,y))
                (n + 1))
                (ring_of_int f X',ring_of_int f Z'))

  PUREX25519_MOD =
    |- !n q. purex25519 (n,q MOD p_25519) = purex25519 (n,q)

  PUREX25519_UNIQUE =
    |- !n q s.
           purex25519 (n,q) = s <=>
           s < p_25519 /\
           (!Q. Q IN group_carrier (curve25519x_group sqintmod_field) /\
                montgomery_xmap sqintmod_field Q = ring_of_num sqintmod_field q
                ==> montgomery_xmap sqintmod_field
                    (group_pow (curve25519x_group sqintmod_field) Q n) =
                    ring_of_num sqintmod_field s)

  PUREX25519_UNIQUE_IMP =
    |- !n q s.
           s < p_25519 /\
           (!f Q.
                field f /\
                ring_char f = p_25519 /\
                Q IN group_carrier (curve25519x_group f) /\
                montgomery_xmap f Q = ring_of_num f q
                ==> montgomery_xmap f (group_pow (curve25519x_group f) Q n) =
                    ring_of_num f s)
           ==> purex25519 (n,q) = s

  QUADRATIC_EXTENSION =
    |- (!r a.
            ring_carrier (quadratic_extension r a) =
            ring_carrier r CROSS ring_carrier r) /\
       (!r a. ring_0 (quadratic_extension r a) = ring_0 r,ring_0 r) /\
       (!r a. ring_1 (quadratic_extension r a) = ring_1 r,ring_0 r) /\
       (!r a.
            ring_neg (quadratic_extension r a) =
            (\(x,y). ring_neg r x,ring_neg r y)) /\
       (!r a.
            ring_add (quadratic_extension r a) =
            (\(x1,y1) (x2,y2). ring_add r x1 x2,ring_add r y1 y2)) /\
       (!r a.
            ring_mul (quadratic_extension r a) =
            (\(x1,y1) (x2,y2).
                 ring_add r (ring_mul r x1 x2)
                 (ring_mul r (ring_of_num r a) (ring_mul r y1 y2)),
                 ring_add r (ring_mul r x1 y2) (ring_mul r x2 y1)))

  RFCX25519_PUREX25519 =
    |- !n q.
           n IN {2 EXP 254 + 8 * i | i < 2 EXP 251} /\ q < 2 EXP 255
           ==> rfcx25519 (n,q) = purex25519 (n,q)

  RING_CHAR_QUADRATIC_EXTENSION =
    |- !r a. ring_char (quadratic_extension r a) = ring_char r

  RING_CHAR_SQINTMOD_FIELD =
    |- ring_char sqintmod_field = p_25519

  RING_HOMOMORPHISM_INTO_QUADRATIC_EXTENSION =
    |- !r a. ring_homomorphism (r,quadratic_extension r a) (\x. x,ring_0 r)

  RING_MONOMORPHISM_INTO_QUADRATIC_EXTENSION =
    |- !r a. ring_monomorphism (r,quadratic_extension r a) (\x. x,ring_0 r)

  RING_OF_INT_QUADRATIC_EXTENSION =
    |- !r a n.
           ring_of_int (quadratic_extension r a) n = ring_of_int r n,ring_0 r

  RING_OF_NUM_QUADRATIC_EXTENSION =
    |- !r a n.
           ring_of_num (quadratic_extension r a) n = ring_of_num r n,ring_0 r

  SPECIALLY_NONSINGULAR_CURVE25519X =
    |- !f X y.
           field f /\
           ring_char f = p_25519 /\
           montgomery_curve (curve25519x f) (SOME (ring_of_num f X,y))
           ==> (y = ring_0 f <=> ring_of_num f X = ring_0 f)

  SQUARE_ROOTS_SQINTMOD_FIELD =
    |- !n. ?x. x IN ring_carrier sqintmod_field /\
               ring_pow sqintmod_field x 2 = ring_of_num sqintmod_field n

Thu 15th Sep 2022               EC/montgomery.ml, EC/xzprojective.ml

Added a definition of the X coordinate mapping for Montgomery curves
(with zero default for the point at infinity) as used in the definition
of curve25519-related functions, and a few lemmas, mainly about that.

  montgomery_xmap
    |- montgomery_xmap f NONE = ring_0 f /\ montgomery_xmap f (SOME (x,y)) = x

  GROUP_POW_MONTGOMERY_TORSION =
    |- !f a b P n.
           field f /\
           ~(ring_char f = 2) /\
           a IN ring_carrier f /\
           b IN ring_carrier f /\
           montgomery_nonsingular (f,a,b)
           ==> group_pow (montgomery_group (f,a,b)) (SOME (ring_0 f,ring_0 f))
               n =
               (if EVEN n then NONE else SOME (ring_0 f,ring_0 f))

  MONTGOMERY_XMAP_EQ_0
    |- !f a b P.
           field f /\
           ~(ring_char f = 2) /\
           a IN ring_carrier f /\
           b IN ring_carrier f /\
           montgomery_nonsingular (f,a,b) /\
           P IN group_carrier (montgomery_group (f,a,b))
           ==> (montgomery_xmap f P = ring_0 f <=>
                P = NONE \/ P = SOME (ring_0 f,ring_0 f))

  MONTGOMERY_XMAP_EQ_0_POW
    |- !f a b P n.
           field f /\
           ~(ring_char f = 2) /\
           a IN ring_carrier f /\
           b IN ring_carrier f /\
           montgomery_nonsingular (f,a,b) /\
           P IN group_carrier (montgomery_group (f,a,b)) /\
           montgomery_xmap f P = ring_0 f
           ==> montgomery_xmap f (group_pow (montgomery_group (f,a,b)) P n) =
               ring_0 f

  MONTGOMERY_XZ_XMAP
    |- !f P X.
           field f /\ X IN ring_carrier f /\ ~(X = ring_0 f)
           ==> (montgomery_xz f P (X,ring_1 f) <=> montgomery_xmap f P = X)

Tue 13th Sep 2022               Library/ringtheory.ml

Added a miscellany of straightforward ring theory lemmas:

  FIELD_NONTRIVIAL =
   |- !f. field f ==> ~(ring_1 f = ring_0 f)

  INTEGRAL_DOMAIN_NONTRIVIAL =
   |- !r. integral_domain r ==> ~(ring_1 r = ring_0 r)

  RING_CHAR_HOMOMORPHIC_IMAGE =
    |- !r r' f. ring_homomorphism (r,r') f ==> ring_char r' divides ring_char r

  RING_HOMOMORPHISM_FROM_INTEGER_MOD_RING =
    |- !r p.
           (?f. ring_homomorphism (integer_mod_ring p,r) f) <=>
           ring_char r divides p

  RING_HOMOMORPHISM_INTEGER_MOD_RING_OF_INT =
    |- !r p.
           ring_homomorphism (integer_mod_ring p,r) (ring_of_int r) <=>
           ring_char r divides p

  RING_MONOMORPHISM_FROM_INTEGER_MOD_RING =
    |- !r p.
           (?f. ring_monomorphism (integer_mod_ring p,r) f) <=> ring_char r = p

  RING_MONOMORPHISM_INTEGER_MOD_RING_OF_INT =
    |- !r p.
           ring_monomorphism (integer_mod_ring p,r) (ring_of_int r) <=>
           ring_char r = p

  RING_OF_INT_CLAUSES =
    |- (!r. ring_0 r = ring_of_int r (&0)) /\
       (!r. ring_1 r = ring_of_int r (&1)) /\
       (!r n. ring_neg r (ring_of_int r n) = ring_of_int r (--n)) /\
       (!r m n.
            ring_add r (ring_of_int r m) (ring_of_int r n) =
            ring_of_int r (m + n)) /\
       (!r m n.
            ring_sub r (ring_of_int r m) (ring_of_int r n) =
            ring_of_int r (m - n)) /\
       (!r m n.
            ring_mul r (ring_of_int r m) (ring_of_int r n) =
            ring_of_int r (m * n)) /\
       (!r m n. ring_pow r (ring_of_int r m) n = ring_of_int r (m pow n))

  RING_OF_INT_REM =
    |- !f n. ring_of_int f (n rem &(ring_char f)) = ring_of_int f n

  RING_OF_NUM_CHAR =
   |- !r. ring_of_num r (ring_char r) = ring_0 r

  RING_OF_NUM_CLAUSES =
    |- (!r. ring_0 r = ring_of_num r 0) /\
       (!r. ring_1 r = ring_of_num r 1) /\
       (!r m n.
            ring_add r (ring_of_num r m) (ring_of_num r n) =
            ring_of_num r (m + n)) /\
       (!r m n.
            ring_mul r (ring_of_num r m) (ring_of_num r n) =
            ring_of_num r (m * n)) /\
       (!r m n. ring_pow r (ring_of_num r m) n = ring_of_num r (m EXP n))

  RING_OF_NUM_MOD =
   |- !f n. ring_of_num f (n MOD ring_char f) = ring_of_num f n

as well as renaming the old RING_OF_INT_CLAUSES -> RING_OF_INT_CASES,
with the above theorem taking the name RING_OF_INT_CLAUSES.

Mon 12th Sep 2022               ind_types.ml

Added a natural dual to FORALL_OPTION_THM:

  EXISTS_OPTION_THM =
    |- !P. (?x. P x) <=> P NONE \/ ?a. P(SOME a)

Wed  7th Sep 2022               Library/ringtheory.ml

Fixed a trivial bug in RING_TAC that could make it fail on trivial
goals having no domain variables, e.g.

  prove(`ring_0 r = ring_add r (ring_0 r) (ring_0 r)`,RING_TAC);;

Fri 26th Aug 2022               realarith.ml

Added an improvement from Chun Tian to REAL_LINEAR_PROVER, making
it automatically recognize strict positivity of "successor" terms
cast to reals, of the form `&(SUC n)`.

  REAL_LT_NZ =
    |- !n. ~(&n = &0) <=> (&0 < &n)

  REAL_POS_LT =
    |- !n. &0 < &(SUC n)

Tue 23rd Aug 2022               EC/passim

Added a few short names for the package of parameters defining some
common elliptic curves:

  curve25519 =
    |- curve25519 = integer_mod_ring p_25519,&A_25519,&1

  nistp256 =
    |- nistp256 =
       integer_mod_ring p_256,ring_neg (integer_mod_ring p_256) (&3),&b_256

  nistp384 =
    |- nistp384 =
       integer_mod_ring p_384,ring_neg (integer_mod_ring p_384) (&3),&b_384

  nistp521 =
    |- nistp521 =
       integer_mod_ring p_521,ring_neg (integer_mod_ring p_521) (&3),&b_521

  secp256k1 =
    |- secp256k1 =
       integer_mod_ring p_256k1,&0,&7

and a few additional Montgomery curve lemmas:

  MONTGOMERY_NONSINGULAR_CURVE25519 =
    |- montgomery_nonsingular curve25519

  MONTGOMERY_STRONGLY_NONSINGULAR_CURVE25519 =
    |- montgomery_strongly_nonsingular curve25519

  MONTGOMERY_XZ_IN_CARRIER =
    |- !P X Z.
         montgomery_xz f P (X,Z)
         ==> X IN ring_carrier f /\ Z IN ring_carrier f

  MONTGOMERY_XZDOUBLE_GROUP =
    |- !f a b p n q.
         field f /\
         ~(ring_char f = 2) /\
         a IN ring_carrier f /\
         b IN ring_carrier f /\
         montgomery_nonsingular (f,a,b) /\
         p IN group_carrier (montgomery_group (f,a,b)) /\
         montgomery_xz f (group_pow (montgomery_group (f,a,b)) p n) q
         ==> montgomery_xz f (group_pow (montgomery_group (f,a,b)) p (2 * n))
             (montgomery_xzdouble (f,a,b) q)

  MONTGOMERY_XZDIFFADD_GROUP =
    |- !f a b p n q qm qn.
         field f /\
         ~(ring_char f = 2) /\
         ~(ring_char f = 3) /\
         a IN ring_carrier f /\
         b IN ring_carrier f /\
         montgomery_nonsingular (f,a,b) /\
         ~(FST q = ring_0 f) /\
         ~(SND q = ring_0 f) /\
         p IN group_carrier (montgomery_group (f,a,b)) /\
         montgomery_xz f p q /\
         montgomery_xz f (group_pow (montgomery_group (f,a,b)) p (n + 1)) qm /\
         montgomery_xz f (group_pow (montgomery_group (f,a,b)) p n) qn
         ==> montgomery_xz f
             (group_pow (montgomery_group (f,a,b)) p (2 * n + 1))
             (montgomery_xzdiffadd (f,a,b) q qm qn)

Mon  1st Aug 2022               Library/words.ml

Added a straightforward variant of existing word lemmas:

  REAL_VAL_WORD_XOR =
    |- !x y.
           &(val(word_xor x y)) =
           (&(val x) + &(val y)) - &2 * &(val(word_and x y))

Wed 27th Jul 2022               tactics.ml, define.ml, meson.ml, Examples/holby.ml, Examples/mizar.ml, 100/e_is_transcendental.ml

Made "prove" explicitly check that the result does not include any
additional assumptions. This seems usually what is expected (if not
TAC_PROOF can be used directly). There were just a few places
where the original behavior was used essentially, and those have
been updated.

Mon 25th Jul 2022               EC/computegroup.ml

Slightly improved the efficiency of ECGROUP_MUL_CONV using a more
refined reduction strategy.

Mon 25th Jul 2022               pair.ml

Added SUBLET_CONV, to apply a conversion to the RHSs of the toplevel
let-term but neither expand it as with let_CONV nor apply the
conversion to the body, e.g.

  # SUBLET_CONV NUM_ADD_CONV
     `let x = 5 + 2 and y = 8 + 17 and z = 3 + 7 in x + y + z`;;
  val it : thm =
    |- (let x = 5 + 2 and y = 8 + 17 and z = 3 + 7 in x + y + z) =
       (let x = 7 and y = 25 and z = 10 in x + y + z)

Tue 10th May 2022               EC/edwards448.ml [new file], Library/grouptheory.ml

Added a formalization of the "Goldilocks" curve edwards448, based on Mike
Hamburg's paper "Ed448-Goldilocks" (https://eprint.iacr.org/2015/625.pdf).
So far, we just have the Edwards form of it as in that paper. This is all
highly analogous to curve25519.ml, except that the group order computation
is a bit more involved: to avoid using a more refined Hasse-type bound
we need to do a bit of explicit analysis of the low-order points because
the group order is less than half of the very naive bound.

Also made a couple of trivial variable name tweaks to grouptheory.ml to
avoid name clashes with "decode" and "encode" when loaded with some other
theories.

Fri 22nd Apr 2022               GL/*

Added an update from Marco Maggesi and Cosimo Perini Brogi to their GL
provability logic theory. This now includes a decision procedure (GL_RULE
and GL_TAC) for the GL logic that will prove a valid formula or generate
a countermodel for an invalid one (stored in "!the_gl_countermodel").
This example, in the provability interpretation, corresponds to a
formalized Goedel's Second Incompleteness Theorem: if a system is
consistent it does not prove its own consistency. The file GL/decid.ml
has a number of applications of this kind:

  #  GL_RULE `|-- (Not (Box False) --> Not (Box (Not (Box False))))`;;
  val it : thm = |- |-- (Not Box False --> Not Box Not Box False)

Wed  6th Apr 2022               EC/* [new directory], Examples/nist_curves.ml [deleted]

Replaced the increasingly unwieldy and poorly-named "nist_curves.ml"
file with a new directory "EC" (for Elliptic Curves) that develops
elliptic curve theory in a more systematic way, with separate files
for all the specific curves, as well as adding new material,
particularly around Edwards curves. The general short Weierstrass,
Montgomery and Edwards forms are defined and their properties derived
separately to minimize interdependencies, and here the only field
characteristic assumptions made are common or natural ones: char = 2
and char = 3 are excluded for short Weierstrass, just char = 2 is
excluded for Montgomery, and in principle there are no restrictions at
all on the Edwards theory (though "edwards_nonsingular" cannot be
satisfied in a *finite* field of characteristic 2 since then every
element is a square).

Wed  6th Apr 2022               lists.ml

Added a little clausal rewrite for BUTLAST:

  BUTLAST_CLAUSES =
   |- BUTLAST []  = [] /\
      (!a. BUTLAST [a] = []) /\
      (!a h t. BUTLAST(CONS a (CONS h t)) = CONS a (BUTLAST(CONS h t)))

Mon  4th Apr 2022               Library/ringtheory.ml

Fixed a prenormalization bug where RING_RULE and RING_TAC were not
handling the general case of "ring_of_num r n".

Fri  1st Apr 2022               Library/ringtheory.ml

Added a few more trivial theorems about terms involving inversion being
zero in a field and a handy collection of the various individual closure
properties (RING_ADD, RING_POW etc.) into a single clausal theorem:

  FIELD_DIV_EQ_0 =
    |- !f x y.
           field f /\ x IN ring_carrier f /\ y IN ring_carrier f
           ==> (ring_div f x y = ring_0 f <=> x = ring_0 f \/ y = ring_0 f)

  FIELD_INV_EQ_0 =
    |- !f x.
           field f /\ x IN ring_carrier f
           ==> (ring_inv f x = ring_0 f <=> x = ring_0 f)

  RING_1_DIV =
    |- !r x. x IN ring_carrier r ==> ring_div r (ring_1 r) x = ring_inv r x

  RING_CLAUSES =
    |- (!r. ring_0 r IN ring_carrier r) /\
       (!r. ring_1 r IN ring_carrier r) /\
       (!r n. ring_of_num r n IN ring_carrier r) /\
       (!r x. x IN ring_carrier r ==> ring_neg r x IN ring_carrier r) /\
       (!r x. x IN ring_carrier r ==> ring_inv r x IN ring_carrier r) /\
       (!r x y.
            x IN ring_carrier r /\ y IN ring_carrier r
            ==> ring_add r x y IN ring_carrier r) /\
       (!r x y.
            x IN ring_carrier r /\ y IN ring_carrier r
            ==> ring_sub r x y IN ring_carrier r) /\
       (!r x y.
            x IN ring_carrier r /\ y IN ring_carrier r
            ==> ring_mul r x y IN ring_carrier r) /\
       (!r x y.
            x IN ring_carrier r /\ y IN ring_carrier r
            ==> ring_div r x y IN ring_carrier r) /\
       (!r x n. x IN ring_carrier r ==> ring_pow r x n IN ring_carrier r)

Tue 29th Mar 2022               Library/grouptheory.ml

Added a couple more lemmas about orders of powers in groups:

 GROUP_ELEMENT_ORDER_EQ_MUL_GEN =
  |- !G x k n.
         x IN group_carrier G /\ ~(k = 0)
         ==> (group_element_order G x = k * n <=>
              k divides group_element_order G x /\
              group_element_order G (group_pow G x k) = n)

 GROUP_ELEMENT_ORDER_EQ_MUL =
  |- !G x k n.
         x IN group_carrier G /\ ~(k = 0) /\ k divides n
         ==> (group_element_order G x = k * n <=>
              group_element_order G (group_pow G x k) = n)

Wed 23rd Mar 2022               Library/ringtheory.ml

Added one more trivial rewrite that's handy to hide explicit case splits
over the trivial case of integers modulo:

  IN_INTEGER_MOD_RING_CARRIER =
    |- !n a.
         a IN ring_carrier(integer_mod_ring n) <=>
         &n = &0 \/ &0 <= a /\ a < &n

Wed 16th Mar 2022               Library/ringtheory.ml

Added some basic support for generic field automation to the ring theory,
adapted and extended from material already there in "nist_curves.ml".
This includes an elimination-based tactic FIELD_TAC as well as a more
directed "pull division terms up" tactic RING_PULL_DIV_TAC and its
contextual conversion RING_PULL_DIV_CONV, these based on the following
new clausal theorem:

  |- !f. field f
         ==> (!x y n.
                  x IN ring_carrier f /\ y IN ring_carrier f
                  ==> ring_pow f (ring_div f x y) n =
                      ring_div f (ring_pow f x n) (ring_pow f y n)) /\
             (!x1 y1 x2 y2.
                  x1 IN ring_carrier f /\
                  x2 IN ring_carrier f /\
                  y1 IN ring_carrier f /\
                  y2 IN ring_carrier f
                  ==> ring_div f (ring_div f x1 y1) (ring_div f x2 y2) =
                      ring_div f (ring_mul f x1 y2) (ring_mul f x2 y1)) /\
             (!x1 x2 y.
                  x1 IN ring_carrier f /\
                  x2 IN ring_carrier f /\
                  y IN ring_carrier f /\
                  ~(y = ring_0 f)
                  ==> ring_add f (ring_div f x1 y) (ring_div f x2 y) =
                      ring_div f (ring_add f x1 x2) y /\
                      ring_sub f (ring_div f x1 y) (ring_div f x2 y) =
                      ring_div f (ring_sub f x1 x2) y /\
                      (ring_div f x1 y = ring_div f x2 y <=> x1 = x2) /\
                      ring_add f (ring_div f x1 y) x2 =
                      ring_div f (ring_add f x1 (ring_mul f x2 y)) y /\
                      ring_add f x1 (ring_div f x2 y) =
                      ring_div f (ring_add f (ring_mul f x1 y) x2) y /\
                      ring_sub f (ring_div f x1 y) x2 =
                      ring_div f (ring_sub f x1 (ring_mul f x2 y)) y /\
                      ring_sub f x1 (ring_div f x2 y) =
                      ring_div f (ring_sub f (ring_mul f x1 y) x2) y /\
                      ring_mul f (ring_div f x1 y) x2 =
                      ring_div f (ring_mul f x1 x2) y /\
                      ring_mul f x1 (ring_div f x2 y) =
                      ring_div f (ring_mul f x1 x2) y /\
                      (ring_div f x1 y = x2 <=> x1 = ring_mul f x2 y) /\
                      (x1 = ring_div f x2 y <=> ring_mul f x1 y = x2)) /\
             (!x y.
                  x IN ring_carrier f /\
                  y IN ring_carrier f /\
                  ~(x = ring_0 f) /\
                  ~(y = ring_0 f)
                  ==> ~(ring_mul f x y = ring_0 f)) /\
             (!x n.
                  x IN ring_carrier f /\ ~(x = ring_0 f)
                  ==> ~(ring_pow f x n = ring_0 f))

Wed 16th Mar 2022               Library/pocklington.ml

Removed some functions around primality proving from "nist_curves.ml" and
put them in the main "pocklington.ml" file, as well as filling out the
functions a bit. The new functions are:

  general_certify_prime - Like certify_prime with any factorizing function

  guided_certify_prime - Taking a set of hereditary sub-factors as a hint

  extract_primes_from_certificate - Getting such sub-factor hints from number

  GUIDED_PROVE_PRIME, PRIME_RULE - Proving primality with sub-factor hints

Mon 14th Mar 2022               Library/integer.ml

Did a bit of renaming to resolve a name clash with the core "int_coprime"
theorem from int.ml, renaming int_coprime -> INT_COPRIME and the former
INT_COPRIME -> INT_COPRIME_ALT in this file, so now:

  int_coprime =
    |- !a b. coprime(a,b) <=> (?x y. a * x + b * y = &1)

  INT_COPRIME =
    |- !a b.
         coprime(a,b) <=> (!d. d divides a /\ d divides b ==> d divides &1)

  INT_COPRIME_ALT =
    |- !a b.
         coprime(a,b) <=> (!d. d divides a /\ d divides b <=> d divides &1)

Fri 11th Mar 2022               Library/ringtheory.ml

Added a few more handy facts about "integer_mod_ring", as well
as defining the ring/field of real numbers explicitly as a ring
structure and proving the usual facts about that too:

  real_ring =
    |- real_ring = ring ((:real),&0,&1,(--),(+),(*))

  FIELD_REAL_RING =
    |- field real_ring

  INTEGER_MOD_RING_CARRIER_REM =
    |- !n x. x rem &n IN ring_carrier (integer_mod_ring n)

  INTEGER_MOD_RING_CLAUSES =
    |- ring_carrier (integer_mod_ring 0) = (:int) /\
       (!n. 0 < n
            ==> ring_carrier (integer_mod_ring n) = {m | &0 <= m /\ m < &n}) /\
       (!n. ring_0 (integer_mod_ring n) = &0) /\
       (!n. ring_1 (integer_mod_ring n) = &1 rem &n) /\
       (!n. ring_neg (integer_mod_ring n) = (\a. --a rem &n)) /\
       (!n. ring_add (integer_mod_ring n) = (\a b. (a + b) rem &n)) /\
       (!n. ring_sub (integer_mod_ring n) = (\a b. (a - b) rem &n)) /\
       (!n. ring_mul (integer_mod_ring n) = (\a b. (a * b) rem &n)) /\
       (!n. ring_pow (integer_mod_ring n) = (\a k. a pow k rem &n)) /\
       (!n. ring_of_num (integer_mod_ring n) = (\k. &k rem &n)) /\
       (!n. ring_of_int (integer_mod_ring n) = (\x. x rem &n))

  INTEGER_MOD_RING_SUB =
    |- !n. ring_sub (integer_mod_ring n) = (\a b. (a - b) rem &n)

  INTEGRAL_DOMAIN_REAL_RING =
    |- integral_domain real_ring

  REAL_FIELD_CLAUSES =
    |- ring_carrier real_ring = (:real) /\
       ring_0 real_ring = &0 /\
       ring_1 real_ring = &1 /\
       ring_neg real_ring = (--) /\
       ring_add real_ring = (+) /\
       ring_mul real_ring = (*) /\
       ring_of_num real_ring = & /\
       ring_sub real_ring = (-) /\
       ring_inv real_ring = inv /\
       ring_div real_ring = (/) /\
       ring_pow real_ring = (pow)

  REAL_RING_CHAR =
    |- ring_char real_ring = 0

  REAL_RING_CLAUSES =
    |- ring_carrier real_ring = (:real) /\
       ring_0 real_ring = &0 /\
       ring_1 real_ring = &1 /\
       ring_neg real_ring = (--) /\
       ring_add real_ring = (+) /\
       ring_mul real_ring = (*)

  REAL_RING_DIV =
    |- ring_div real_ring = (/)

  REAL_RING_INV =
    |- ring_inv real_ring = inv

  REAL_RING_OF_INT =
    |- ring_of_int real_ring = real_of_int

  REAL_RING_OF_NUM =
    |- ring_of_num real_ring = &

  REAL_RING_POW =
    |- ring_pow real_ring = (pow)

  REAL_RING_SUB =
    |- ring_sub real_ring = (-)

Fri  4th Mar 2022               Examples/nist_curves.ml

Added a formalization of curve25519, and Montgomery curves in general,
to the increasingly inaccurately-named "nist_curves.ml" file. Mainly
for ease of re-use of the existing short Weierstrass material, the
properties of Montgomery operations are first derived from their
Weierstrass versions via the standard mapping, even defining the
"wei25519" curve as the short Weierstrass variant (nomenclature taken
from Struik's "Alternative Elliptic Curve Representations"). After
that, all the usual things are proved about curve25519, including the
y-free doubling and differential addition operations (following
Bernstein and Lange, "Montgomery cuves and the Montgomery ladder") and
a y-recovery formula (from Okeya and Sakurai). Also filled out the
earlier curve material with some additional facts, most interestingly
a standard easily computable endomorphism of secp256k1.

Thu 24th Feb 2022               Library/grouptheory.ml

Added this somewhat technical lemma which is handy for explicitly
creating a group as an isomorphic image and not then doing a
separate proof of group-ness and the isomorphism with the original:

  CREATE_ISOMORPHIC_COPY_OF_GROUP =
    |- !f g G s z i m.
         z IN s /\
         (!x. x IN group_carrier G ==> f x IN s /\ g (f x) = x) /\
         (!y. y IN s ==> g y IN group_carrier G /\ f (g y) = y) /\
         g z = group_id G /\
         (!x. x IN s ==> i x = f (group_inv G (g x))) /\
         (!x y. x IN s /\ y IN s ==> m x y = f (group_mul G (g x) (g y)))
         ==> group_isomorphisms (G,group (s,z,i,m)) (f,g) /\
             group_carrier (group (s,z,i,m)) = s /\
             group_id (group (s,z,i,m)) = z /\
             group_inv (group (s,z,i,m)) = i /\
             group_mul (group (s,z,i,m)) = m

Wed 23rd Feb 2022               Library/ringtheory.ml

Added an explicit conversion INTEGER_MOD_RING_RED_CONV for computing
terms in "integer_mod_ring n" (for nonzero n, the case of n = 0 being
just the integers anyway). This also adds the theorem:

  RING_INV_INTEGER_MOD_RING =
    |- !n a.
           ring_inv (integer_mod_ring n) (&a) =
           (if (n = 0 \/ ~(n = 1) /\ a < n) /\ coprime(a,n)
            then &(inverse_mod n a) else &0)

This introduces a dependency on the Library/pocklington.ml file for
some additional material about "inverse_mod".

Wed 23rd Feb 2022               calc_num.ml, int.ml, Library/pocklington.ml

Moved EXP_MOD_CONV from "Library/pocklington.ml" into the core (in the
process slightly improving the implementation) and added an analogous
integer form INT_POW_REM_CONV.

Wed 23rd Feb 2022               Library/pocklington.ml

Added INVERSE_MOD_CONV, an explicit calculation conversion for modular
inverse terms of the form `inverse_mod m n` for numerals m and n.

Tue  7th Dec 2021               Library/words.ml

Added one more little missing lemma:

  BIT_WORD_BITVAL =
    |- !b i. bit i (word(bitval b):N word) <=> i = 0 /\ b

Thu 25th Nov 2021               Examples/nist_curves.ml

Added the other SECG curves defined over prime order fields: secp192k1,
secp224k1 and secp256k1 (the Bitcoin curve). This extends the existing
NIST curve material with the same verification of basic data like
number of points on the curve, and adds some possible computational
formulas in projective and Jacobian coordinates for Weierstrass curves
like these with a = 0.

Wed 10th Nov 2021               Library/words.ml

Added a new construct "bits_of_num" analogous to "bits_of_word" but
for actual numbers not words. The suite of theorems about it helps
with some kinds of "effectively bitwise" reasoning on natural numbers
such as pushing division and modulus w.r.t. powers of 2 through sums
based on the intuition that the bit patterns are not overlapping
(DIV_MOD_DISJOINT_BITS, DISJOINT_BITS_CLAUSES)

  bits_of_num =
    |- !n. bits_of_num n = {i | numbit i n}

  BITSUM_BOUND =
    |- !s k.
           FINITE s
           ==> (nsum s (\i. 2 EXP i) < 2 EXP k <=> s SUBSET {i | i < k})

  BITSUM_DIVIDES =
    |- !s k.
           FINITE s
           ==> (2 EXP k divides nsum s (\i. 2 EXP i) <=>
                DISJOINT {i | i < k} s)

  BITS_OF_NUM_0 =
    |- bits_of_num 0 = {}

  BITS_OF_NUM_1 =
    |- bits_of_num 1 = {0}

  BITS_OF_NUM_ADD =
    |- !m n.
           DISJOINT (bits_of_num m) (bits_of_num n)
           ==> bits_of_num(m + n) = bits_of_num m UNION bits_of_num n

  BITS_OF_NUM_DISJOINT_NUMSEG_EQ =
    |- !n k. DISJOINT {i | i < k} (bits_of_num n) <=> 2 EXP k divides n

  BITS_OF_NUM_DIV =
    |- !n k. bits_of_num(n DIV 2 EXP k) = {i | k + i IN bits_of_num n}

  BITS_OF_NUM_EQ =
    |- !m n. bits_of_num m = bits_of_num n <=> m = n

  BITS_OF_NUM_GALOIS =
    |- !n s. bits_of_num n = s <=> FINITE s /\ nsum s (\i. 2 EXP i) = n

  BITS_OF_NUM_MOD =
    |- !n k. bits_of_num(n MOD 2 EXP k) = {i | i IN bits_of_num n /\ i < k}

  BITS_OF_NUM_MUL =
    |- (!n k. bits_of_num(2 EXP k * n) = IMAGE (\i. k + i) (bits_of_num n)) /\
       (!n k. bits_of_num(n * 2 EXP k) = IMAGE (\i. k + i) (bits_of_num n))

  BITS_OF_NUM_MUL_ALT =
    |- (!n k.
            bits_of_num(2 EXP k * n) =
            {i | k <= i /\ i - k IN bits_of_num n}) /\
       (!n k.
            bits_of_num(n * 2 EXP k) =
            {i | k <= i /\ i - k IN bits_of_num n})

  BITS_OF_NUM_NSUM =
    |- !s. FINITE s ==> bits_of_num(nsum s (\i. 2 EXP i)) = s

  BITS_OF_NUM_POW2 =
    |- !k. bits_of_num(2 EXP k) = {k}

  BITS_OF_NUM_SUBSET_NUMSEG_EQ =
    |- !n k. bits_of_num n SUBSET {i | i < k} <=> n < 2 EXP k

  BITS_OF_NUM_SUBSET_NUMSEG_LT =
    |- !n. bits_of_num n SUBSET {i | i < n}

  BITS_OF_NUM_VAL =
    |- !x. bits_of_num(val x) = bits_of_word x

  BITS_OF_WORD_WORD =
    |- !n. bits_of_word (word n) = {i | i < dimindex(:N)} INTER bits_of_num n

  DISJOINT_BITS_CLAUSES =
    |- (!k h l.
            l < 2 EXP k
            ==> DISJOINT (bits_of_num(2 EXP k * h)) (bits_of_num l)) /\
       (!k h l.
            l < 2 EXP k
            ==> DISJOINT (bits_of_num(h * 2 EXP k)) (bits_of_num l)) /\
       (!k h l.
            l < 2 EXP k
            ==> DISJOINT (bits_of_num l) (bits_of_num(2 EXP k * h))) /\
       (!k h l.
            l < 2 EXP k
            ==> DISJOINT (bits_of_num l) (bits_of_num(h * 2 EXP k))) /\
       (!m n k.
            DISJOINT (bits_of_num m) (bits_of_num n)
            ==> DISJOINT (bits_of_num(2 EXP k * m))
                         (bits_of_num(2 EXP k * n))) /\
       (!m n k.
            DISJOINT (bits_of_num m) (bits_of_num n)
            ==> DISJOINT (bits_of_num(m * 2 EXP k))
                         (bits_of_num(n * 2 EXP k))) /\
       (!m n k.
            DISJOINT (bits_of_num m) (bits_of_num n)
            ==> DISJOINT (bits_of_num(m DIV 2 EXP k))
                         (bits_of_num(n DIV 2 EXP k))) /\
       (!m n k.
            DISJOINT (bits_of_num m) (bits_of_num n)
            ==> DISJOINT (bits_of_num(m MOD 2 EXP k))
                         (bits_of_num(n MOD 2 EXP k)))

  DISJOINT_BITS_HILO =
    |- !k h l.
           l < 2 EXP k ==> DISJOINT (bits_of_num(2 EXP k * h)) (bits_of_num l)

  DIV_MOD_DISJOINT_BITS =
    |- (!m n.
            DISJOINT (bits_of_num m) (bits_of_num n)
            ==> (m + n) DIV 2 EXP k = m DIV 2 EXP k + n DIV 2 EXP k) /\
       (!m n.
            DISJOINT (bits_of_num m) (bits_of_num n)
            ==> (m + n) MOD 2 EXP k = m MOD 2 EXP k + n MOD 2 EXP k)

  FINITE_BITS_OF_NUM =
    |- !n. FINITE (bits_of_num n)

  IN_BITS_OF_NUM =
    |- !n i. i IN bits_of_num n <=> ODD (n DIV 2 EXP i)

  NSUM_BITS_DIV =
    |- !s k.
           FINITE s
           ==> nsum s (\i. 2 EXP i) DIV 2 EXP k =
               nsum {i | i IN s /\ k <= i} (\i. 2 EXP (i - k))

  NSUM_BITS_EQ =
    |- !s t.
           FINITE s /\ FINITE t
           ==> (nsum s (\i. 2 EXP i) = nsum t (\i. 2 EXP i) <=> s = t)

  NSUM_BITS_MOD =
    |- !s k.
           FINITE s
           ==> nsum s (\i. 2 EXP i) MOD 2 EXP k =
               nsum {i | i IN s /\ i < k} (\i. 2 EXP i)

  NSUM_BITS_OF_NUM =
    |- !n. nsum (bits_of_num n) (\i. 2 EXP i) = n

Tue  9th Nov 2021               int.ml, real.ml, Library/words.ml

Added a few miscelleneous lemmas:

  IVAL_WORD_CONG =
   |- !n. (ival (word n) == &n) (mod (&2 pow dimindex(:N)))

  MULT_DIV =
    |- (!m n p. p divides m ==> (m * n) DIV p = m DIV p * n) /\
       (!m n p. p divides n ==> (m * n) DIV p = m * n DIV p)

  REAL_OF_NUM_DIV =
   |- !m n. &(m DIV n) = &m / &n - &(m MOD n) / &n

  VAL_WORD_AND_NOT_MASK_WORD =
    |- !x k.
           val (word_and x (word_not (word(2 EXP k - 1)))) =
           2 EXP k * val x DIV 2 EXP k

  WORD_AND_MASK_WORDS =
    |- !i j.
           word_and (word(2 EXP j - 1)) (word(2 EXP k - 1)) =
           word(2 EXP MIN j k - 1)

  WORD_AND_NOT_MASK_WORD =
    |- (!x k.
            word_and x (word_not (word(2 EXP k - 1))) =
            word(2 EXP k * val x DIV 2 EXP k)) /\
       (!x k.
            word_and (word_not (word(2 EXP k - 1))) x =
            word(2 EXP k * val x DIV 2 EXP k))

  WORD_OR_MASK_WORDS =
    |- !i j.
           word_or (word(2 EXP j - 1)) (word(2 EXP k - 1)) =
           word(2 EXP MAX j k - 1)

  WORD_USHR_MASK_WORD =
    |- !k i.
           k <= dimindex(:N)
           ==> word_ushr (word(2 EXP k - 1)) i = word(2 EXP (k - i) - 1)

Fri  5th Nov 2021       Library/words.ml

Added more word lemmas, mainly connected with selecting trailing bits and
emulating ctz in terms of clz, very much in line with material in
the "Manipulating Rightmost Bits" section of "Hacker's Delight":

  BIT_WORD_XOR_ADD_1 =
    |- !x i.
           bit i (word_xor x (word_add x (word 1))) <=>
           i < dimindex(:N) /\ (!j. j < i ==> bit j x)

  BIT_WORD_XOR_NEG =
    |- !x i.
           bit i (word_xor x (word_neg x)) <=>
           i < dimindex(:N) /\ (?j. j < i /\ bit j x)

  BIT_WORD_XOR_SUB_1 =
    |- !x i.
           bit i (word_xor x (word_sub x (word 1))) <=>
           i < dimindex(:N) /\ (!j. j < i ==> ~bit j x)

  WORD_AND_NEG_CTZ =
    |- !x. word_and x (word_neg x) = word_of_bits {word_ctz x}

  WORD_AND_NOT_SUB_1_CTZ =
    |- !x. word_and (word_not x) (word_sub x (word 1)) =
           word(2 EXP word_ctz x - 1)

  WORD_CLZ_BIT =
    |- !k. word_clz (word_of_bits {k}) =
           (if k < dimindex(:N) then dimindex(:N) - 1 - k else dimindex(:N))

  WORD_CLZ_MASK_WORD =
    |- !k. word_clz (word(2 EXP k - 1)) = dimindex(:N) - k

  WORD_CTZ_BIT =
    |- !k. word_ctz (word_of_bits {k}) = MIN k (dimindex(:N))

  WORD_CTZ_EMULATION_AND_NEG =
    |- !x. word_ctz x =
           (if x = word 0
            then dimindex(:N)
            else dimindex(:N) - 1 - word_clz (word_and x (word_neg x)))

  WORD_CTZ_EMULATION_AND_NEG_REV =
    |- !x. word_clz (word_and x (word_neg x)) =
           (if x = word 0
            then dimindex(:N)
            else dimindex(:N) - 1 - word_ctz x)

  WORD_CTZ_EMULATION_XOR_SUB_1 =
    |- !x. word_ctz x =
           (if x = word 0
            then dimindex(:N)
            else dimindex(:N) -
                 1 -
                 word_clz (word_xor x (word_sub x (word 1))))

  WORD_CTZ_EMULATION_XOR_SUB_1_REV =
    |- !x. word_clz (word_xor x (word_sub x (word 1))) =
           dimindex(:N) - 1 - word_ctz x

  WORD_CTZ_MASK_WORD =
    |- !k. word_ctz (word(2 EXP k - 1)) = (if k = 0 then dimindex(:N) else 0)

  WORD_XOR_SUB_1_CTZ =
    |- !x. word_xor x (word_sub x (word 1)) = word(2 EXP (word_ctz x + 1) - 1)

Tue  2nd Nov 2021       Library/words.ml

Added missing conversions WORD_JROL_CONV and WORD_JROR_CONV (for
word-word rotate operations) and included them in WORD_RED_CONV
and hence WORD_REDUCE_CONV.

Mon  1st Nov 2021       parser.ml

Fixed a trivial typo in the error message "closing square bracket
of list expected".

Tue 12th Oct 2021       Library/words.ml

Added a couple more word lemmas about pushing logical complements through
other constructs; the side-conditions make them a bit ugly but they can be
useful:

  WORD_JOIN_NOT =
   |- !v w.
         dimindex(:P) <= dimindex(:M) + dimindex(:N)
         ==> word_join (word_not v) (word_not w) = word_not (word_join v w)

  WORD_SUBWORD_NOT =
    |- !x pos len.
         dimindex(:N) <= len /\ pos + len <= dimindex(:M)
         ==> word_subword (word_not x) (pos,len) =
             word_not (word_subword x (pos,len))

Sat  9th Oct 2021       Library/words.ml

Added a few more elementary word lemmas like a simple upper bound on
a concrete masking of a word:

  VAL_WORD_AND_LE =
    |- (!x y. val (word_and x y) <= val x) /\
       (!x y. val (word_and x y) <= val y)

  VAL_WORD_AND_LE_MIN =
    |- !x y. val (word_and x y) <= MIN (val x) (val y)

  VAL_WORD_AND_WORD_LE =
    |- (!x n. val (word_and x (word n)) <= n) /\
       (!x n. val (word_and (word n) x) <= n)

  VAL_WORD_OR_LE_MAX =
    |- !x y. MAX (val x) (val y) <= val (word_or x y)

Fri  8th Oct 2021       int.ml

Added a systematic set of missing analogs of real theorems for ints:

  INT_ABS_BOUNDS : thm =
   |- !x k. abs x <= k <=> --k <= x /\ x <= k

  INT_EQ_LCANCEL_IMP : thm =
    |- !x y z. ~(z = &0) /\ z * x = z * y ==> x = y

  INT_EQ_RCANCEL_IMP : thm =
    |- !x y z. ~(z = &0) /\ x * z = y * z ==> x = y

  INT_LE_LCANCEL_IMP : thm =
   |- !x y z. &0 < x /\ x * y <= x * z ==> y <= z

  INT_LE_POW_2 : thm =
   |- !x. &0 <= x pow 2

  INT_LE_RCANCEL_IMP : thm =
   |- !x y z. &0 < z /\ x * z <= y * z ==> x <= y

  INT_LE_RMUL_EQ : thm =
   |- !x y z. &0 < z ==> (x * z <= y * z <=> x <= y)

  INT_LT_LADD_IMP : thm =
   |- !x y z. y < z ==> x + y < x + z

  INT_LT_LCANCEL_IMP : thm =
   |- !x y z. &0 < x /\ x * y < x * z ==> y < z

  INT_LT_LMUL : thm =
   |- !x y z. &0 < x /\ y < z ==> x * y < x * z

  INT_LT_LNEG : thm =
   |- !x y. --x < y <=> &0 < x + y

  INT_LT_POW_2 : thm =
   |- !x. &0 < x pow 2 <=> ~(x = &0)

  INT_LT_RCANCEL_IMP : thm =
   |- !x y z. &0 < z /\ x * z < y * z ==> x < y

  INT_LT_RMUL : thm =
   |- !x y z. x < y /\ &0 < z ==> x * z < y * z

  INT_LT_RNEG : thm =
   |- !x y. x < --y <=> x + y < &0

  INT_LT_SQUARE : thm =
   |- !x. &0 < x * x <=> ~(x = &0)

  INT_OF_NUM_SUB_CASES : thm =
    |- !m n. &m - &n = (if n <= m then &(m - n) else -- &(n - m))

  INT_POS_EQ_SQUARE : thm =
    |- !x. &0 <= x <=> (?y. y pow 2 = real_of_int x)

  INT_POW_EQ_1 : thm =
    |- !x n. x pow n = &1 <=> abs x = &1 /\ (x < &0 ==> EVEN n) \/ n = 0

  INT_POW_EQ_1_IMP : thm =
   |- !x n. ~(n = 0) /\ x pow n = &1 ==> abs x = &1

  INT_POW_EQ_EQ : thm =
    |- !n x y.
           x pow n = y pow n <=>
           (if EVEN n then n = 0 \/ abs x = abs y else x = y)

  INT_POW_EQ_ODD : thm =
   |- !n x y. ODD n /\ x pow n = y pow n ==> x = y

  INT_POW_EQ_ODD_EQ : thm =
    |- !n x y. ODD n ==> (x pow n = y pow n <=> x = y)

  INT_POW_LBOUND : thm =
   |- !x n. &0 <= x ==> &1 + &n * x <= (&1 + x) pow n

  INT_POW_LE2_ODD_EQ : thm =
    |- !n x y. ODD n ==> (x pow n <= y pow n <=> x <= y)

  INT_POW_LT2_ODD : thm =
   |- !n x y. x < y /\ ODD n ==> x pow n < y pow n

  INT_POW_LT2_ODD_EQ : thm =
    |- !n x y. ODD n ==> (x pow n < y pow n <=> x < y)

Fri  8th Oct 2021       real.ml, int.ml

Added integer and real forms of this simple lemma:

  INT_EVENPOW_ABS =
   |- !x n. EVEN n ==> abs x pow n = x pow n

  REAL_EVENPOW_ABS =
    |- !x n. EVEN n ==> abs x pow n = x pow n

Wed  6th Oct 2021       int.ml

Added a natural integer analog of MOD_UNIQUE:

  INT_REM_UNIQUE =
    |- !m n p.
         m rem n = p <=>
         (n = &0 /\ m = p \/ &0 <= p /\ p < abs n) /\ (m == p) (mod n)

Tue  5th Oct 2021       Library/words.ml

Added a few trivial theorems about unsigned word max/min:

  WORD_UMAX =
    |- !x y. word_umax x y = (if val x <= val y then y else x)

  WORD_UMAX_ASSOC =
    |- !x y z. word_umax x (word_umax y z) = word_umax (word_umax x y) z

  WORD_UMAX_SYM =
    |- !x y. word_umax x y = word_umax y x

  WORD_UMIN =
    |- !x y. word_umin x y = (if val x <= val y then x else y)

  WORD_UMIN_ASSOC =
    |- !x y z. word_umin x (word_umin y z) = word_umin (word_umin x y) z

  WORD_UMIN_SYM =
    |- !x y. word_umin x y = word_umin y x

Fri 20th Aug 2021       Library/words.ml

Added three more word lemmas connecting shifts and subwords:

  WORD_SHL_SUBWORD =
    |- !x d l.
           dimindex(:N) <= l + d
           ==> word_shl (word_subword x (0,l)) d = word_shl x d

  WORD_SUBWORD_AS_USHR =
    |- !x k l. dimindex(:N) <= k + l ==> word_subword x (k,l) = word_ushr x k

  WORD_USHR_AS_SUBWORD =
    |- !x k. word_ushr x k = word_subword x (k,dimindex(:N) - k)

Fri 30th Jul 2021       Library/words.ml

Made the trivial generalization to WORD_ARITH / WORD_ARITH_TAC of also
breaking apart conjunctions at the start. Added these lemmas
characterizing exactness of additions or additions-with-carry in terms
of a later word comparison on the result, all of which are just
proved automatically by WORD_ARITH_TAC.

  WORD_ADC_LE_EXACT =
    |- (!x y.
            val(word_add (word_add x y) (word 1)) <= val x <=>
            val(word_add (word_add x y) (word 1)) + 2 EXP dimindex(:N) =
            val x + val y + 1) /\
       (!x y.
            val(word_add (word_add x y) (word 1)) <= val y <=>
            val(word_add (word_add x y) (word 1)) + 2 EXP dimindex(:N) =
            val x + val y + 1)

  WORD_ADC_LE_INEXACT =
    |- (!x y.
            val(word_add (word_add x y) (word 1)) <= val x <=>
            ~(val(word_add (word_add x y) (word 1)) = val x + val y + 1)) /\
       (!x y.
            val(word_add (word_add x y) (word 1)) <= val y <=>
            ~(val(word_add (word_add x y) (word 1)) = val x + val y + 1))

  WORD_ADD_LT_EXACT =
    |- (!x y.
            val(word_add x y) < val x <=>
            val(word_add x y) + 2 EXP dimindex(:N) = val x + val y) /\
       (!x y.
            val(word_add x y) < val y <=>
            val(word_add x y) + 2 EXP dimindex(:N) = val x + val y)

  WORD_ADD_LT_INEXACT =
    |- (!x y.
            val(word_add x y) < val x <=>
            ~(val(word_add x y) = val x + val y)) /\
       (!x y.
            val(word_add x y) < val y <=>
            ~(val(word_add x y) = val x + val y))

  WORD_LE_ADD_EXACT =
    |- (!x y.
            val x <= val(word_add x y) <=> val(word_add x y) = val x + val y) /\
       (!x y.
            val y <= val(word_add x y) <=> val(word_add x y) = val x + val y)

  WORD_LT_ADC_EXACT =
    |- (!x y.
            val x < val(word_add (word_add x y) (word 1)) <=>
            val(word_add (word_add x y) (word 1)) = val x + val y + 1) /\
       (!x y.
            val y < val(word_add (word_add x y) (word 1)) <=>
            val(word_add (word_add x y) (word 1)) = val x + val y + 1)

Wed 28th Jul 2021       Library/words.ml

Added two more simple word lemmas (the de Morgan laws in this setting)

  WORD_NOT_AND =
    |- !x y. word_not (word_and x y) = word_or (word_not x) (word_not y)

  WORD_NOT_OR =
    |- !x y. word_not (word_or x y) = word_and (word_not x) (word_not y)

Tue 20th Jul 2021       Library/words.ml

Added another couple of elementary lemmas about AND with a word
consisting of a single bit expressed as a power of 2.

  VAL_WORD_AND_POW2 =
   |- (!x k. val(word_and x (word(2 EXP k))) = 2 EXP k * bitval(bit k x)) /\
      (!x k. val(word_and (word(2 EXP k)) x) = 2 EXP k * bitval(bit k x))

  WORD_AND_POW2 =
   |- (!x k. word_and x (word(2 EXP k)) = word(2 EXP k * bitval(bit k x))) /\
      (!x k. word_and (word(2 EXP k)) x = word(2 EXP k * bitval(bit k x)))

Fri 16th Jul 2021       Library/words.ml

Added one more little word lemma that zero-extension of a 1-bit
Boolean value is trivial:

  WORD_ZX_BITVAL = |- !b. word_zx(word(bitval b)) = word(bitval b)

Wed  7th Jul 2021       Library/words.ml

Added a few miscellaneous word theorems with an emphasis on commuting
word_zx, mainly as a shortening, through other word operations:

  BIT_GUARD =
    |- !x i. bit i x <=> i < dimindex(:N) /\ bit i x

  VAL_WORD_SUBWORD_DIMINDEX =
    |- !pos w.
           val (word_subword w (pos,dimindex(:N))) =
           (val w DIV 2 EXP pos) MOD 2 EXP dimindex(:N)

  VAL_WORD_SUBWORD_SIMPLE =
    |- !w. val (word_subword w (0,dimindex(:N))) =
           val w MOD 2 EXP dimindex(:N)

  WORD_SUBWORD_AND =
    |- !x y pos len.
           word_subword (word_and x y) (pos,len) =
           word_and (word_subword x (pos,len)) (word_subword y (pos,len))

  WORD_SUBWORD_OR =
    |- !x y pos len.
           word_subword (word_or x y) (pos,len) =
           word_or (word_subword x (pos,len)) (word_subword y (pos,len))

  WORD_SUBWORD_XOR =
    |- !x y pos len.
           word_subword (word_xor x y) (pos,len) =
           word_xor (word_subword x (pos,len)) (word_subword y (pos,len))

  WORD_ZX_ADD =
    |- !x y.
           dimindex(:N) <= dimindex(:M)
           ==> word_zx (word_add x y) = word_add (word_zx x) (word_zx y)

  WORD_ZX_AND =
    |- !x y. word_zx (word_and x y) = word_and (word_zx x) (word_zx y)

  WORD_ZX_MUL =
    |- !x y.
           dimindex(:N) <= dimindex(:M)
           ==> word_zx (word_mul x y) = word_mul (word_zx x) (word_zx y)

  WORD_ZX_NEG =
    |- !x. dimindex(:N) <= dimindex(:M)
           ==> word_zx (word_neg x) = word_neg (word_zx x)

  WORD_ZX_NOT =
    |- !x. dimindex(:N) <= dimindex(:M)
           ==> word_zx (word_not x) = word_not (word_zx x)

  WORD_ZX_OR =
    |- !x y. word_zx (word_or x y) = word_or (word_zx x) (word_zx y)

  WORD_ZX_SHL =
    |- !x n.
           dimindex(:N) <= dimindex(:M)
           ==> word_zx (word_shl x n) = word_shl (word_zx x) n

  WORD_ZX_SUB =
    |- !x y.
           dimindex(:N) <= dimindex(:M)
           ==> word_zx (word_sub x y) = word_sub (word_zx x) (word_zx y)

  WORD_ZX_SUBWORD =
    |- !x. word_zx x = word_subword x (0,dimindex(:M))

  WORD_ZX_WORD_SIMPLE =
    |- !n. dimindex(:N) <= dimindex(:M) ==> word_zx (word n) = word n

  WORD_ZX_XOR =
    |- !x y. word_zx (word_xor x y) = word_xor (word_zx x) (word_zx y)

Tue 23rd Mar 2021       Library/bitsize.ml

Added one more basic theorem about "bitsize"

  BITSIZE_UNIQUE_EQ =
    |- !n k. bitsize n = k <=> n < 2 EXP k /\ (~(k = 0) ==> 2 EXP k <= 2 * n)

and a standard conversion, BITSIZE_CONV for concrete instances of it, e.g.

  # BITSIZE_CONV `bitsize 12345`;;
  val it : thm = |- bitsize 12345 = 14

Wed 24th Feb 2021       Library/words.ml

Added a definition of alignment of machine words (in the sense of
alignment restrictions on addresses in CPUs) and a few simple theorems:

  aligned =
    |- !n a. aligned n a <=> n divides 2 EXP dimindex(:N) /\ n divides val a

  ALIGNED =
    |- !n x. aligned n x <=> n divides 2 EXP dimindex(:N) /\ &n divides ival x

  ALIGNED_IWORD =
    |- !n k.
         aligned n (iword k) <=>
         n divides 2 EXP diminde (:N) /\ &n divides k

  ALIGNED_WORD =
    |- !n k.
           aligned n (word k) <=> n divides 2 EXP dimindex(:N) /\ n divides k

  ALIGNED_WORD_0 =
    |- !n. aligned n (word 0) <=> n divides 2 EXP dimindex(:N)

  ALIGNED_WORD_ADD =
    |- !n a b. aligned n a /\ aligned n b ==> aligned n (word_add a b)

  ALIGNED_WORD_ADD_EQ =
    |- (!n x y. aligned n x ==> (aligned n (word_add x y) <=> aligned n y)) /\
       (!n x y. aligned n y ==> (aligned n (word_add x y) <=> aligned n x))

  ALIGNED_WORD_MUL =
    |- !n a b. aligned n a \/ aligned n b ==> aligned n (word_mul a b)

  ALIGNED_WORD_NEG =
    |- !n x. aligned n (word_neg x) <=> aligned n x

  ALIGNED_WORD_SUB =
    |- !n a b. aligned n a /\ aligned n b ==> aligned n (word_sub a b)

  ALIGNED_WORD_SUB_EQ =
    |- (!n x y. aligned n x ==> (aligned n (word_sub x y) <=> aligned n y)) /\
       (!n x y. aligned n y ==> (aligned n (word_sub x y) <=> aligned n x))

  VAL_IWORD_CONG =
    |- !x. (&(val (iword x)) == x) (mod (&2 pow dimindex(:N)))

Sat 23rd Jan 2021       GL [new directory]

Added an extended example from Marco Maggesi and Cosimo Perini Brogi
setting up the provability logic GL and proving its modal completeness
(see COMPLETENESS_THEOREM_GEN).

Wed 30th Dec 2020       Library/words.ml

Added three more trivial word lemmas:

  WORD_AND_ASSOC =
    |- !x y z. word_and x (word_and y z) = word_and (word_and x y) z

  WORD_OR_ASSOC =
    |- !x y z. word_or x (word_or y z) = word_or (word_or x y) z

  WORD_XOR_ASSOC =
    |- !x y z. word_xor x (word_xor y z) = word_xor (word_xor x y) z

Wed 16th Dec 2020       Library/pocklington.ml

Added one more simple lemma about modular inverses:

  INVERSE_MOD_1 =
    |- !n. inverse_mod n 1 = 1

Tue  8th Dec 2020       preterm.ml

Made an improvement to pretype_of_type pointed out by Ben Kordesh and
Bill Richter, using pattern-matching instead of the destructor style.
This is not only much cleaner but probably more efficient.

Mon  7th Dec 2020       Library/words.ml

Added a few more word lemmas:

  BIT_MASK_WORD =
    |- !k i. bit i (word (2 EXP k - 1)) <=> i < dimindex(:N) /\ i < k

  VAL_WORD_LE =
   |- !n k. n <= k ==> val (word n) <= k

  VAL_WORD_LT =
   |- !n k. n < k ==> val (word n) < k

  WORD_ADD_OR_EQ =
   |- !x y. word_add x y = word_or x y <=> word_and x y = word 0

  WORD_OR_XOR_EQ =
   |- !x y. word_or x y = word_xor x y <=> word_and x y = word 0

  WORD_SUB_MASK_WORD =
    |- !k x.
           val x < 2 EXP k
           ==> word_sub (word (2 EXP k - 1)) x =
               word_xor (word (2 EXP k - 1)) x

  WORD_SUB_XOR =
    |- !x y. word_and (word_not x) y = word 0 ==> word_sub x y = word_xor x y

  WORD_XOR_MASK_WORD =
    |- !k x.
           val x < 2 EXP k
           ==> word_xor (word (2 EXP k - 1)) x =
               word_sub (word (2 EXP k - 1)) x

  WORD_XOR_SUB =
    |- !x y. word_and (word_not x) y = word 0 ==> word_xor x y = word_sub x y

Thu  3rd Dec 2020       Library/words.ml

Added a few more fairly straightforward but handy word lemmas:

  BLOCK_BITS_ZERO =
    |- !x m n.
           (!i. m <= i /\ i < n ==> ~bit i x) <=> val x MOD 2 EXP n < 2 EXP m

  BLOCK_BITS_ZERO_ALT =
    |- !x m n.
           (!i. m <= i /\ i < n ==> ~bit i x) <=>
           (val x MOD 2 EXP n) DIV 2 EXP m = 0

  EVEN_VAL_WORD =
   |- !n. EVEN(val(word n)) <=> EVEN n

  LOWER_BITS_ZERO =
   |- !x n. (!i. i < n ==> ~bit i x) <=> val x MOD 2 EXP n = 0

  ODD_VAL_WORD =
   |- !n. ODD(val(word n)) <=> ODD n

  UPPER_BITS_ZERO =
   |- !x n. (!i. n <= i ==> ~bit i x) <=> val x < 2 EXP n

  UPPER_BITS_ZERO_ALT =
   |- !x n. (!i. n <= i ==> ~bit i x) <=> val x DIV 2 EXP n = 0

  VAL_WORD_SUB_EQ_0 =
   |- !x y. val(word_sub x y) = 0 <=> val x = val y

  WORD_SUBWORD_JOIN_AS_SHL =
    |- !x k.
           k <= dimindex(:N)
           ==> word_subword (word_join x (word 0)) (k,dimindex(:N)) =
               word_shl x (dimindex(:N) - k)

  WORD_SUBWORD_JOIN_AS_USHR =
    |- !x k.
           word_subword (word_join (word 0) x) (k,dimindex(:N)) =
           word_ushr x k

Fri 27th Nov 2020       Library/bitsize.ml

Added a few more properties of "bitsize":

  BITSIZE_DIV =
    |- !n k. bitsize(n DIV 2 EXP k) = bitsize n - k

  BITSIZE_MAX =
    |- !m n. bitsize(MAX m n) = MAX (bitsize m) (bitsize n)

  BITSIZE_MIN =
    |- !m n. bitsize(MIN m n) = MIN (bitsize m) (bitsize n)

Wed 25th Nov 2020       Library/integer.ml

Added a few more integer divisibility lemmas:

  INT_GCD_POW =
    |- !a b n. gcd(a pow n,b pow n) = gcd(a,b) pow n

  INT_LCM_LMUL =
    |- !a b c. lcm(c * a,c * b) = abs c * lcm(a,b)

  INT_LCM_POW =
   |- !a b n. lcm(a pow n,b pow n) = lcm(a,b) pow n

  INT_LCM_RMUL =
   |- !a b c. lcm(a * c,b * c) = lcm(a,b) * abs c

as well as removing the nonzeroness hypothesis from INT_GCD_COPRIME_EXISTS
(in line with the natural number version GCD_COPRIME_EXISTS), which is now:

  INT_GCD_COPRIME_EXISTS =
    |- !a b. ?a' b'. a = a' * gcd(a,b) /\ b = b' * gcd(a,b) /\ coprime(a',b')

Tue 24th Nov 2020       Library/words.ml

Added various new word lemmas:

  BIT_WORD_ZX =
    |- !x i. bit i (word_zx x) <=> i < dimindex(:N) /\ bit i x

  VAL_LE_BITS =
    |- !x y. (!i. i < dimindex(:N) /\ bit i x ==> bit i y) ==> val x <= val y

  VAL_WORD_OR_LE =
    |- (!x y. val x <= val(word_or x y)) /\ (!x y. val y <= val(word_or x y))

  VAL_WORD_SUBWORD_JOIN =
    |- !h l n m.
           m <= dimindex(:N)
           ==> val(word_subword (word_join h l) (n,m)) =
               ((2 EXP dimindex(:N) * val h + val l) DIV 2 EXP n) MOD 2 EXP m

  VAL_WORD_SUBWORD_JOIN_FULL =
    |- !h l k.
           k <= dimindex(:N)
           ==> val(word_subword (word_join h l) (k,dimindex(:N))) =
               2 EXP (dimindex(:N) - k) * val h MOD 2 EXP k +
               val l DIV 2 EXP k

  WORD_ADD_SHL_USHR =
    |- !h l m n.
           m + n = dimindex(:N)
           ==> word_add (word_shl h m) (word_ushr l n) =
               word_zx (word_ushr (word_join h l) n)

  WORD_ADD_USHR_SHL =
    |- !h l m n.
           m + n = dimindex(:N)
           ==> word_add (word_ushr l m) (word_shl h n) =
               word_zx (word_ushr (word_join h l) m)

  WORD_CLZ_IMP =
    |- !x y.
           (!i. i < dimindex(:N) /\ bit i x ==> bit i y)
           ==> word_clz y <= word_clz x

  WORD_CLZ_MONO =
    |- !x y. val x <= val y ==> word_clz y <= word_clz x

  WORD_CLZ_OR =
    |- !x y. word_clz (word_or x y) = MIN (word_clz x) (word_clz y)

  WORD_CTZ_IMP =
    |- !x y.
           (!i. i < dimindex(:N) /\ bit i x ==> bit i y)
           ==> word_ctz y <= word_ctz x

  WORD_CTZ_OR =
    |- !x y. word_ctz (word_or x y) = MIN (word_ctz x) (word_ctz y)

  WORD_ISHR_0 =
    |- !n. word_ishr (word 0) n = word 0

  WORD_JSHL_NEG =
    |- !w k.
           dimindex(:N) divides 2 EXP dimindex(:N)
           ==> word_jshl w (word_neg k) =
               (if val k MOD dimindex(:N) = 0
                then w
                else word_shl w (dimindex(:N) - val k MOD dimindex(:N)))

  WORD_JUSHR_NEG =
    |- !w k.
           dimindex(:N) divides 2 EXP dimindex(:N)
           ==> word_jushr w (word_neg k) =
               (if val k MOD dimindex(:N) = 0
                then w
                else word_ushr w (dimindex(:N) - val k MOD dimindex(:N)))

  WORD_OR_SHL_USHR =
    |- !h l m n.
           m + n = dimindex(:N)
           ==> word_or (word_shl h m) (word_ushr l n) =
               word_zx (word_ushr (word_join h l) n)

  WORD_OR_USHR_SHL =
    |- !h l m n.
           m + n = dimindex(:N)
           ==> word_or (word_ushr l m) (word_shl h n) =
               word_zx (word_ushr (word_join h l) m)

  WORD_SHL_0 =
    |- !n. word_shl (word 0) n = word 0

  WORD_SUBWORD_DIMINDEX =
    |- !x k. word_subword x (k,dimindex(:M)) = word_zx (word_ushr x k)

  WORD_USHR_0 =
    |- !n. word_ushr (word 0) n = word 0

Mon 23rd Nov 2020       Library/integer.ml

Added a few more routine lemmas about integer GCDs and LCMs under sign flip:

  INT_GCD_ABS =
    |- (!a b. gcd(abs a,b) = gcd(a,b)) /\ (!a b. gcd(a,abs b) = gcd(a,b))

  INT_GCD_LABS =
   |- !a b. gcd(abs a,b) = gcd(a,b)

  INT_GCD_LNEG =
   |- !a b. gcd(--a,b) = gcd(a,b)

  INT_GCD_NEG =
    |- (!a b. gcd(--a,b) = gcd(a,b)) /\ (!a b. gcd(a,--b) = gcd(a,b))

  INT_GCD_RABS =
   |- !a b. gcd(a,abs b) = gcd(a,b)

  INT_GCD_RNEG =
   |- !a b. gcd(a,--b) = gcd(a,b)

  INT_LCM_ABS =
    |- (!a b. lcm(abs a,b) = lcm(a,b)) /\ (!a b. lcm(a,abs b) = lcm(a,b))

  INT_LCM_LABS =
   |- !a b. lcm(abs a,b) = lcm(a,b)

  INT_LCM_LNEG =
   |- !a b. lcm(--a,b) = lcm(a,b)

  INT_LCM_NEG =
    |- (!a b. lcm(--a,b) = lcm(a,b)) /\ (!a b. lcm(a,--b) = lcm(a,b))

  INT_LCM_RABS =
   |- !a b. lcm(a,abs b) = lcm(a,b)

  INT_LCM_RNEG =
   |- !a b. lcm(a,--b) = lcm(a,b)

Fri 20th Nov 2020       int.ml, Library/prime.ml, Library/pocklington.ml, Library/integer.ml, Library/floor.ml

Added various simple divisibility-related lemmas of one sort or another:

  CONG_LMUL =
     |- !a x y n. (x == y) (mod n) ==> (a * x == a * y) (mod n)

  CONG_MULT_LCANCEL_ALL =
    |- !a x y n. (a * x == a * y) (mod (a * n)) <=> a = 0 \/ (x == y) (mod n)

  CONG_RMUL =
     |- !x y a n. (x == y) (mod n) ==> (x * a == y * a) (mod n)

  GCD_COPRIME_DIVIDES_LMUL =
    |- !a b c. coprime(a,b) /\ a divides c ==> gcd(a * b,c) = a * gcd(b,c)

  GCD_COPRIME_DIVIDES_RMUL =
    |- !a b c. coprime(b,c) /\ b divides a ==> gcd(a,b * c) = b * gcd(a,c)

  INT_CONG_LMUL =
     |- !a x y n. (x == y) (mod n) ==> (a * x == a * y) (mod n)

  INT_CONG_MULT_LCANCEL_ALL =
    |- !a x y n. (a * x == a * y) (mod (a * n)) <=> a = &0 \/ (x == y) (mod n)

  INT_CONG_RMUL =
     |- !x y a n. (x == y) (mod n) ==> (x * a == y * a) (mod n)

  INT_GCD_COPRIME_DIVIDES_LMUL =
    |- !a b c.
           coprime(a,b) /\ a divides c ==> gcd(a * b,c) = abs a * gcd(b,c)

  INT_GCD_COPRIME_DIVIDES_RMUL =
    |- !a b c.
           coprime(b,c) /\ b divides a ==> gcd(a,b * c) = abs b * gcd(a,c)

  INT_GCD_COPRIME_LMUL =
    |- !a b c. coprime(a,b) ==> gcd(a * b,c) = gcd(a,c) * gcd(b,c)

  INT_GCD_COPRIME_RMUL =
    |- !a b c. coprime(b,c) ==> gcd(a,b * c) = gcd(a,b) * gcd(a,c)

  INT_GCD_LMUL =
     |- !a b c. gcd(c * a,c * b) = abs c * gcd(a,b)

  INT_GCD_RMUL =
     |- !a b c. gcd(a * c,b * c) = gcd(a,b) * abs c

  INT_MUL_2 =
     |- !x. &2 * x = x + x

  REAL_INT_CONGRUENCE =
    |- !a b n.
           (a == b) (mod n) <=>
           (if n = &0
            then real_of_int a = real_of_int b
            else integer ((real_of_int a - real_of_int b) / real_of_int n))

Sat 14th Nov 2020       Library/integer.ml

Added a few more basic integer lemmas, mainly related to LCMs.

  INT_ABS_GCD =
     |- !a b. abs(gcd(a,b)) = gcd(a,b)

  INT_ABS_LCM =
     |- !a b. abs(lcm(a,b)) = lcm(a,b)

  INT_DIVIDES_ANTISYM_MULTIPLES =
    |- !a b. a divides b /\ b divides a <=> (!d. a divides d <=> b divides d)

  INT_DIVIDES_LCM =
     |- !m n r. r divides m \/ r divides n ==> r divides lcm(m,n)

  INT_LCM_0 =
     |- (!n. lcm(&0,n) = &0) /\ (!n. lcm(n,&0) = &0)

  INT_LCM_1 =
     |- (!n. lcm(&1,n) = abs n) /\ (!n. lcm(n,&1) = abs n)

  INT_LCM_ASSOC =
     |- !m n p. lcm(m,lcm(n,p)) = lcm(lcm(m,n),p)

  INT_LCM_EQ =
    |- !x y u v.
           (!m. x divides m /\ y divides m <=> u divides m /\ v divides m)
           ==> lcm(x,y) = lcm(u,v)

  INT_LCM_EQ_0 =
     |- !m n. lcm(m,n) = &0 <=> m = &0 \/ n = &0

  INT_LCM_REFL =
     |- !n. lcm(n,n) = abs n

  INT_LCM_SYM =
     |- !m n. lcm(m,n) = lcm(n,m)

  INT_LCM_UNIQUE =
    |- !a b m.
           lcm(a,b) = m <=>
           &0 <= m /\
           a divides m /\
           b divides m /\
           (!n. a divides n /\ b divides n ==> m divides n)

  INT_LCM_UNIQUE_ABS =
    |- !a b m.
           lcm(a,b) = abs m <=>
           a divides m /\
           b divides m /\
           (!n. a divides n /\ b divides n ==> m divides n)

Also renamed the existing COPRIME there to the more idiomatic INT_COPRIME,
avoiding a name clash with the corresponding theorem for N in Library/prime.ml
that was inconvenient if one wanted to use both together.

Thu 12th Nov 2020       Library/words.ml

Added a systematic set of basic word lemmas, mainly around evenness and
oddity of values from word operations

  BIT_LSB_WORD =
     |- !n. bit 0 (word n) <=> ODD n

  EVEN_VAL_WORD_ADD =
    |- !x y. EVEN(val(word_add x y)) <=> EVEN(val x) <=> EVEN(val y)

  EVEN_VAL_WORD_MUL =
    |- !x y. EVEN(val(word_mul x y)) <=> EVEN(val x) \/ EVEN(val y)

  EVEN_VAL_WORD_NEG =
     |- !x. EVEN(val(word_neg x)) <=> EVEN(val x)

  EVEN_VAL_WORD_SUB =
    |- !x y. EVEN(val(word_sub x y)) <=> EVEN(val x) <=> EVEN(val y)

  INT_CONG_WORD_ADD =
    |- !x y.
         (&(val(word_add x y)) == &(val x) + &(val y))
         (mod (&2 pow dimindex(:N)))

  INT_CONG_WORD_MUL =
    |- !x y.
         (&(val(word_mul x y)) == &(val x) * &(val y))
         (mod (&2 pow dimindex(:N)))

  INT_CONG_WORD_NEG =
    |- !x. (&(val(word_neg x)) == -- &(val x)) (mod (&2 pow dimindex(:N)))

  INT_CONG_WORD_SUB =
    |- !x y.
         (&(val(word_sub x y)) == &(val x) - &(val y))
         (mod (&2 pow dimindex(:N)))

  ODD_VAL_WORD_ADD =
    |- !x y. ODD(val(word_add x y)) <=> ~(ODD(val x) <=> ODD(val y))

  ODD_VAL_WORD_MUL =
    |- !x y. ODD(val(word_mul x y)) <=> ODD(val x) /\ ODD(val y)

  ODD_VAL_WORD_NEG =
     |- !x. ODD(val(word_neg x)) <=> ODD(val x)

  ODD_VAL_WORD_SUB =
    |- !x y. ODD(val(word_sub x y)) <=> ~(ODD(val x) <=> ODD(val y))

Thu 12th Nov 2020       arith.ml

Added a couple of arithmetic lemmas that are handy to have bound to names,
albeit the proofs are trivial (the latter is just proved by ARITH_TAC):

  DOUBLE_HALF =
    |- (!n. EVEN n ==> 2 * n DIV 2 = n) /\ (!n. EVEN n ==> n DIV 2 * 2 = n)

  HALF_DOUBLE =
    |- (!n. (2 * n) DIV 2 = n) /\ (!n. (n * 2) DIV 2 = n)

Sat 24th Oct 2020       Library/words.ml

Added a few word lemmas, renaming the former WORD_USHR_MSB -> WORD_USHR_MSB_ALT
to make room for the new one here:

  IVAL_WORD_MASK =
    |- !b. ival(word_neg (word(bitval b))) = -- &(bitval b)

  MASK_WORD_SUB =
    |- !k. word_sub (word(2 EXP k)) (word 1) = word(2 EXP k - 1)

  WORD_ISHR_MSB =
    |- !x. word_ishr x (dimindex(:N) - 1) =
           word_neg (word(bitval(bit (dimindex(:N) - 1) x)))

  WORD_USHR_MSB =
    |- !x. word_ushr x (dimindex(:N) - 1) =
           word(bitval(bit (dimindex(:N) - 1) x))

  WORD_AND_MASK_WORD =
    |- (!x k. word_and x (word(2 EXP k - 1)) = word(val x MOD 2 EXP k)) /\
       (!x k. word_and (word(2 EXP k - 1)) x = word(val x MOD 2 EXP k))

Sat 24th Oct 2020       passim

Systematically fixed redundant quantifiers in many existing theorems:

    calc_rat.ml                     REAL_GROW_SHRINK
    calc_rat.ml                     REAL_SHRINK_GROW
    class.ml                        SKOLEM_THM_GEN
    sets.ml                         LIST_OF_SET_SING
    sets.ml                         REAL_LE_INF_EQ
    Library/grouptheory.ml          GROUP_NEG_ID
    Library/grouptheory.ml          SUBGROUP_OF_UNIONS
    Library/grouptheory.ml          GROUP_HOMOMORPHISM_COMPONENTWISE_UNIV
    Library/grouptheory.ml          ISOMORPHIC_GROUP_ORDER
    Library/grouptheory.ml          PAIRWISE_DISJOINT_GROUP_ORBITS
    Library/grouptheory.ml          NORMAL_SUBGROUP_OF_UNIONS
    Library/grouptheory.ml          GROUP_CENTRALIZER_SUBSET_EQ
    Library/pocklington.ml          CONG_MINUS1
    Library/pocklington.ml          CONG_ADD_LCANCEL_EQ_0
    Library/pocklington.ml          CONG_ADD_RCANCEL_EQ_0
    Library/pocklington.ml          CHINESE_REMAINDER_COUNT
    Library/pocklington.ml          CHINESE_REMAINDER_COPRIME_COUNT
    Library/pocklington.ml          PHI_FINITE_LEMMA
    Library/pocklington.ml          NPRODUCT_CMUL
    Library/ringtheory.ml           RING_SUB_REFL
    Library/ringtheory.ml           SUBRING_OF_UNIONS
    Library/ringtheory.ml           RING_SETADD_SYM
    Library/ringtheory.ml           RING_SETMUL_SYM
    Library/ringtheory.ml           ISOMORPHIC_RING_CARD
    Library/ringtheory.ml           RING_HOMOMORPHISM_COMPONENTWISE_UNIV
    Library/ringtheory.ml           RING_COSET_EQ
    Library/wo.ml                   UNION_FLD
    Library/words.ml                WORD_OF_BITS_SING_AS_WORD
    Library/words.ml                IVAL_EQ_0
    Library/words.ml                BIT_WORD_AND
    Library/words.ml                BIT_WORD_OR
    Library/words.ml                BIT_WORD_XOR
    Library/words.ml                BIT_WORD_SHL
    Library/words.ml                WORD_ZX_ZX
    Multivariate/canal.ml           LIM_COMPLEX_INV
    Multivariate/canal.ml           HAS_COMPLEX_DERIVATIVE_CDIV_AT
    Multivariate/canal.ml           COMPLEX_DIFFERENTIABLE_COMPOSE_AT
    Multivariate/canal.ml           SERIES_DIRICHLET_COMPLEX_GEN
    Multivariate/cauchy.ml          WINDING_NUMBER_UNIQUE
    Multivariate/cauchy.ml          higher_complex_derivative_alt
    Multivariate/clifford.ml        LINEAR_EQ_MBASIS
    Multivariate/clifford.ml        BILINEAR_EQ_MBASIS
    Multivariate/clifford.ml        OUTERMORPHISM_MBASIS
    Multivariate/complexes.ml       COMPLEX_EQ_INV2
    Multivariate/convex.ml          AFFINE_STANDARD_HYPERPLANE
    Multivariate/convex.ml          FRONTIER_OF_CONNECTED_COMPONENT_SUBSET
    Multivariate/convex.ml          SEPARATING_HYPERPLANE_SET_0
    Multivariate/convex.ml          CONVEX_HULL_SPHERE
    Multivariate/convex.ml          LIPSCHITZ_CONVEX_SPHERICAL_PROJECTION_EXPLICIT
    Multivariate/derivatives.ml     DIFFERENTIABLE_IMP_OPEN_MAP_ALT
    Multivariate/determinants.ml    REFLECT_ALONG_ZERO
    Multivariate/homology.ml        SIMPLICIAL_SIMPLEX_EMPTY
    Multivariate/integration.ml     INTEGRAL_ADD
    Multivariate/integration.ml     INTEGRAL_SUB
    Multivariate/integration.ml     INTEGRAL_SPIKE
    Multivariate/integration.ml     INTEGRAL_PASTECART_SYM
    Multivariate/integration.ml     INTEGRABLE_PASTECART_SYM
    Multivariate/integration.ml     ABSOLUTELY_INTEGRABLE_PASTECART_SYM
    Multivariate/integration.ml     DOMINATED_CONVERGENCE_INTEGRABLE
    Multivariate/integration.ml     DOMINATED_CONVERGENCE_ABSOLUTELY_INTEGRABLE
    Multivariate/measure.ml         NEGLIGIBLE_SPHERE
    Multivariate/measure.ml         ABSOLUTELY_INTEGRABLE_IMPROPER
    Multivariate/measure.ml         BAIRE_IMP_MEASURABLE_ON
    Multivariate/measure.ml         BAIRE_IMP_MEASURABLE_ON_UNIV
    Multivariate/measure.ml         ABSOLUTELY_INTEGRABLE_CHANGE_OF_VARIABLES_1
    Multivariate/metric.ml          OPEN_IN_TRANS_FULL
    Multivariate/metric.ml          CLOSED_IN_TRANS_FULL
    Multivariate/metric.ml          TOPOLOGY_BASES_EQ
    Multivariate/metric.ml          SECTION_AND_RETRACTION_EQ_HOMEOMORPHIC_MAP
    Multivariate/metric.ml          NET
    Multivariate/metric.ml          SEQUENTIALLY
    Multivariate/metric.ml          NETLIMITS_SEQUENTIALLY
    Multivariate/metric.ml          CONTINUOUS_MAP_UPPER_LOWER_SEMICONTINUOUS_LTE
    Multivariate/paths.ml           HOMOTOPIC_WITH_SUBSET_RIGHT
    Multivariate/paths.ml           HOMOTOPIC_WITH_ORTHOGONAL_TRANSFORMATIONS_ALT
    Multivariate/paths.ml           HOMOTOPIC_PATHS_REPARAMETRIZE
    Multivariate/realanalysis.ml    REAL_DIFFERENTIABLE_AT
    Multivariate/realanalysis.ml    REAL_DIFFERENTIABLE_WITHIN
    Multivariate/realanalysis.ml    REAL_DERIVATIVE_IVT_DECREASING
    Multivariate/topology.ml        EVENTUALLY_WITHIN_OPEN
    Multivariate/topology.ml        DENSE_LIMIT_POINTS
    Multivariate/topology.ml        CONNECTED_COMPONENT_IN_COMPONENTS
    Multivariate/topology.ml        CONTINUOUS_MATRIX_VECTOR_MUL
    Multivariate/topology.ml        CONTINUOUS_ON_MATRIX_VECTOR_MUL
    Multivariate/topology.ml        RIGHT_LIMIT_ALT
    Multivariate/topology.ml        LEFT_LIMIT_ALT
    Multivariate/topology.ml        BOREL_MEASURABLE_MAX
    Multivariate/topology.ml        BOREL_MEASURABLE_MIN
    Multivariate/transcendentals.ml DIST_CEXP_II_1
    Multivariate/transcendentals.ml REAL_ROOT_POW_GEN
    Multivariate/transcendentals.ml ABSOLUTELY_INTEGRABLE_CHANGE_OF_VARIABLES_POLAR
    Multivariate/vectors.ml         LINEAR_IMP_LIPSCHITZ

Fri 18th Aug 2020       Library/bitsize.ml [new file]

Added a simple new library file giving a definition and basic properties of
the "bitsize" function, which determines how many bits are needed to represent
a natural number.

  bitsize =
    |- !n. bitsize n = (minimal i. n < 2 EXP i)

  BITSIZE =
    |- !n. n < 2 EXP bitsize n

  BITSIZE_0 =
    |- bitsize 0 = 0

  BITSIZE_1 =
    |- bitsize 1 = 1

  BITSIZE_2 =
    |- bitsize 2 = 2

  BITSIZE_EQ_0 =
    |- !n. bitsize n = 0 <=> n = 0

  BITSIZE_LE =
    |- !n k. bitsize n <= k <=> n < 2 EXP k

  BITSIZE_MONO =
    |- !m n. m <= n ==> bitsize m <= bitsize n

  BITSIZE_MULT =
    |- (!k n. bitsize(2 EXP k * n) = (if n = 0 then 0 else k + bitsize n)) /\
       (!k n. bitsize(n * 2 EXP k) = (if n = 0 then 0 else bitsize n + k))

  BITSIZE_MULT_ADD =
    |- (!k m n.
            ~(m = 0) /\ n < 2 EXP k
            ==> bitsize(2 EXP k * m + n) = k + bitsize m) /\
       (!k m n.
            ~(m = 0) /\ n < 2 EXP k
            ==> bitsize(m * 2 EXP k + n) = k + bitsize m) /\
       (!k m n.
            ~(m = 0) /\ n < 2 EXP k
            ==> bitsize(n + 2 EXP k * m) = k + bitsize m) /\
       (!k m n.
            ~(m = 0) /\ n < 2 EXP k
            ==> bitsize(n + m * 2 EXP k) = k + bitsize m)

  BITSIZE_MULT_LE =
    |- !m n. bitsize(m * n) <= bitsize m + bitsize n

  BITSIZE_POW2 =
    |- !k. bitsize(2 EXP k) = k + 1

  BITSIZE_REV =
    |- !n. ~(n = 0) ==> 2 EXP (bitsize n - 1) <= n

  BITSIZE_REV_ALT =
    |- !n. ~(n = 0) ==> 2 EXP bitsize n <= 2 * n

  BITSIZE_REV_EQ =
    |- !n. 2 EXP (bitsize n - 1) <= n <=> ~(n = 0)

  BITSIZE_REV_EQ_ALT =
    |- !n. 2 EXP bitsize n <= 2 * n <=> ~(n = 0)

  BITSIZE_UNIQUE =
    |- !n k. bitsize n = k <=> n < 2 EXP k /\ (!j. j < k ==> 2 EXP j <= n)

  BITSIZE_UNIQUE_ALT =
    |- !n k. bitsize n = k <=> (!j. n < 2 EXP j <=> k <= j)

  LE_BITSIZE =
    |- !n k. k <= bitsize n <=> ~(k = 0) ==> 2 EXP (k - 1) <= n

  LE_BITSIZE_ALT =
    |- !n k. k <= bitsize n <=> ~(k = 0) ==> 2 EXP k <= 2 * n

Thu 17th Aug 2020       arith.ml, real.ml. int.ml, Library/prime.ml

Added a few miscellaneous lemmas of an arithmetic character:

  INDEX_ADD =
    |- !p n m.
           ~(n = 0) /\ (~(m = 0) ==> index p n < index p m)
           ==> index p (m + n) = index p n

  INDEX_MULT_ADD =
    |- (!p m n k.
        ~(n = 0) /\ index p n < k ==> index p (p EXP k * m + n) = index p n) /\
       (!p m n k.
        ~(n = 0) /\ index p n < k ==> index p (m * p EXP k + n) = index p n) /\
       (!p m n k.
        ~(n = 0) /\ index p n < k ==> index p (n + m * p EXP k) = index p n) /\
       (!p m n k.
        ~(n = 0) /\ index p n < k ==> index p (n + p EXP k * m) = index p n)

  INDEX_MULT_BASE =
    |- (!p n. index p (p * n) = if p <= 1 \/ n = 0 then 0 else index p n + 1) /\
       (!p n. index p (n * p) = if p <= 1 \/ n = 0 then 0 else index p n + 1)

  INDEX_MULT_EXP =
    |- (!p n k.
            index p (p EXP k * n) =
            (if p <= 1 \/ n = 0 then 0 else k + index p n)) /\
       (!p n k.
            index p (n * p EXP k) =
            (if n = 0 \/ p <= 1 then 0 else index p n + k))

  INT_OF_NUM_MOD =
    |- !m n. &(m MOD n) = &m - &(m DIV n) * &n

  INDEX_LT =
    |- !n p k. (~(n = 0) \/ ~(k = 0)) /\ n < p EXP k ==> index p n < k

  MINIMAL_MONO =
    |- !P Q. (?n. P n) /\ (!n. P n ==> Q n) ==> (minimal) Q <= (minimal) P

  REAL_CONGRUENCE =
    |- !a b n.
           (a == b) (mod n) <=>
           (if n = 0 then &a = &b else integer ((&a - &b) / &n))

  REAL_OF_NUM_MOD =
    |- !m n. &(m MOD n) = &m - &(m DIV n) * &n

Wed 16th Aug 2020       Library/words.ml

Added some additional word lemmas, including many standard bit twiddling hacks
inclduing emulation of "count trailing zeros" via "count leading zeros", as for
example in "Hacker's Delight" section 2-1 etc.:

  BIT_WORD_AND_ADD_1 =
    |- !x i.
           bit i (word_and x (word_add x (word 1))) <=>
           bit i x /\ (?j. j < i /\ ~bit j x)

  BIT_WORD_AND_NEG =
    |- !x i.
           bit i (word_and x (word_neg x)) <=>
           bit i x /\ (!j. j < i ==> ~bit j x)

  BIT_WORD_AND_NOT_ADD_1 =
    |- !x i.
           bit i (word_and (word_not x) (word_add x (word 1))) <=>
           i < dimindex(:N) /\ ~bit i x /\ (!j. j < i ==> bit j x)

  BIT_WORD_AND_NOT_SUB_1 =
    |- !x i.
           bit i (word_and (word_not x) (word_sub x (word 1))) <=>
           i < dimindex(:N) /\ (!j. j <= i ==> ~bit j x)

  BIT_WORD_AND_SUB_1 =
    |- !x i.
           bit i (word_and x (word_sub x (word 1))) <=>
           bit i x /\ (?j. j < i /\ bit j x)

  BIT_WORD_OR_ADD_1 =
    |- !x i.
           bit i (word_or x (word_add x (word 1))) <=>
           i < dimindex(:N) /\ (bit i x \/ (!j. j < i ==> bit j x))

  BIT_WORD_OR_NEG =
    |- !x i.
           bit i (word_or x (word_neg x)) <=>
           i < dimindex(:N) /\ (?j. j <= i /\ bit j x)

  BIT_WORD_OR_SUB_1 =
    |- !x i.
           bit i (word_or x (word_sub x (word 1))) <=>
           i < dimindex(:N) /\ (bit i x \/ (!j. j < i ==> ~bit j x))

  WORD_CLZ =
    |- !x. word_clz x = dimindex(:N) - (minimal m. val x < 2 EXP m)

  WORD_CTZ_EMULATION =
    |- !x. word_ctz x =
           dimindex(:N) -
           word_clz (word_and (word_not x) (word_sub x (word 1)))

  WORD_CTZ_EMULATION_REV =
    |- !x. word_clz (word_and (word_not x) (word_sub x (word 1))) =
           dimindex(:N) - word_ctz x

  WORD_EQ_0 =
    |- !m. m < 2 EXP dimindex(:N) ==> (word m = word 0 <=> m = 0)

  WORD_EQ_IMP =
    |- !m n.
           m < 2 EXP dimindex(:N) /\ n < 2 EXP dimindex(:N)
           ==> (word m = word n <=> m = n)

Fri 21st Aug 2020       Library/grouptheory.ml

Added a more refined and explicit version of the existing theorem
FINITELY_GENERATED_ABELIAN_SUBGROUP (which is now derived directly
from it), via essentially the same proof with cardinality bound
systematically added:

  FINITELY_GENERATED_ABELIAN_SUBGROUP_EXPLICIT =
    |- !G s h.
          FINITE s /\
          s SUBSET group_carrier G /\
          abelian_group G /\
          h subgroup_of subgroup_generated G s
          ==> ?t. FINITE t /\
                  t SUBSET group_carrier G /\
                  CARD t <= CARD s /\
                  subgroup_generated G t = subgroup_generated G h

Fri 21st Aug 2020       sets.ml

Added a few more handy theorems for rewriting things about "small"
subsets of an image:

  EXISTS_SMALL_SUBSET_IMAGE =
    |- !P f s n.
           (?t. FINITE t /\ CARD t < n /\ t SUBSET IMAGE f s /\ P t) <=>
           (?t. FINITE t /\ CARD t < n /\ t SUBSET s /\ P (IMAGE f t))

  EXISTS_SMALL_SUBSET_IMAGE_INJ =
    |- !P f s n.
           (?t. FINITE t /\ CARD t < n /\ t SUBSET IMAGE f s /\ P t) <=>
           (?t. FINITE t /\
                CARD t < n /\
                t SUBSET s /\
                (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y)) /\
                P (IMAGE f t))

  FORALL_SMALL_SUBSET_IMAGE =
    |- !P f s n.
           (!t. FINITE t /\ CARD t < n /\ t SUBSET IMAGE f s ==> P t) <=>
           (!t. FINITE t /\ CARD t < n /\ t SUBSET s ==> P (IMAGE f t))

  FORALL_SMALL_SUBSET_IMAGE_INJ =
    |- !P f s n.
           (!t. FINITE t /\ CARD t < n /\ t SUBSET IMAGE f s ==> P t) <=>
           (!t. FINITE t /\
                CARD t < n /\
                t SUBSET s /\
                (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y))
                ==> P (IMAGE f t))

Thu 20th Aug 2020       Library/ringtheory.ml

Added more technical ring theory lemmas to keep things as closely in
step with the group theory analogs as relevant/possible:

  IDEAL_GENERATED_INDUCT_STRONG =
    |- !r P s.
           (!x. x IN ring_carrier r /\ x IN s ==> P x) /\
           P (ring_0 r) /\
           (!x. x IN ring_carrier r /\ P x ==> P (ring_neg r x)) /\
           (!x y.
                x IN ring_carrier r /\ y IN ring_carrier r /\ P x /\ P y
                ==> P (ring_add r x y)) /\
           (!x y.
                x IN ring_carrier r /\ y IN ring_carrier r /\ P y
                ==> P (ring_mul r x y))
           ==> (!x. x IN ideal_generated r s ==> P x)

  INTEGER_MOD_RING_TRIVIAL =
    |- integer_mod_ring 0 = integer_ring

  ISOMORPHIC_PRODUCT_RING_BIJECTIONS =
    |- !s r t r' f g.
           (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
           (!y. y IN t ==> g y IN s /\ f (g y) = y) /\
           (!i. i IN s ==> r i isomorphic_ring r' (f i))
           ==> product_ring s r isomorphic_ring product_ring t r'

  ISOMORPHIC_PRODUCT_RING_INSERT =
    |- !f i k.
           ~(i IN k)
           ==> product_ring (i INSERT k) f isomorphic_ring
               prod_ring (f i) (product_ring k f)

  ISOMORPHIC_PRODUCT_RING_SING =
    |- !r k. product_ring {k} r isomorphic_ring r k

  ISOMORPHIC_PRODUCT_RING_SUPPORT =
    |- !k r.
           product_ring {i | i IN k /\ ~trivial_ring (r i)} r isomorphic_ring
           product_ring k r

  ISOMORPHIC_PRODUCT_RING_SYMDIFF =
    |- !k l r.
           (!i. i IN k DIFF l UNION l DIFF k ==> trivial_ring (r i))
           ==> product_ring k r isomorphic_ring product_ring l r

  RING_HOMOMORPHISM_BETWEEN_SUBRINGS_ALT =
    |- !r s g h f.
           ring_homomorphism (r,s) f /\
           IMAGE f (ring_carrier r INTER g) SUBSET h
           ==> ring_homomorphism (subring_generated r g,subring_generated s h)
               f

  RING_ISOMORPHISMS_BETWEEN_SUBRINGS_ALT =
    |- !r s g h f f'.
           ring_isomorphisms (r,s) (f,f') /\
           IMAGE f (ring_carrier r INTER g) SUBSET h /\
           IMAGE f' (ring_carrier s INTER h) SUBSET g
           ==> ring_isomorphisms (subring_generated r g,subring_generated s h)
               (f,f')

  RING_ISOMORPHISMS_PRODUCT_RING_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> ring_isomorphisms
               (product_ring (k UNION l) f,
                prod_ring (product_ring k f) (product_ring l f))
               ((\f. RESTRICTION k f,RESTRICTION l f),
                (\(f,g) x. if x IN k then f x else g x))

  RING_ISOMORPHISM_EPIMORPHISM =
    |- !r r' f.
           ring_isomorphism (r,r') f <=>
           ring_epimorphism (r,r') f /\
           (!x y.
                x IN ring_carrier r /\ y IN ring_carrier r /\ f x = f y
                ==> x = y)

  RING_ISOMORPHISM_PRODUCT_PROJECTION =
    |- !r k. ring_isomorphism (product_ring {k} r,r k) (\x. x k)

  RING_ISOMORPHISM_PRODUCT_RING_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> ring_isomorphism
               (product_ring (k UNION l) f,
                prod_ring (product_ring k f) (product_ring l f))
               (\f. RESTRICTION k f,RESTRICTION l f)

  RING_PRODUCT_INJECTION =
    |- !k r a i.
           RESTRICTION k (\j. if j = i then a else ring_0 (r j)) IN
           ring_carrier(product_ring k r) <=>
           i IN k ==> a IN ring_carrier(r i)

  SUBRINGS_GENERATED_EQ =
    |- !r s t.
           s SUBSET ring_carrier(subring_generated r t) /\
           t SUBSET ring_carrier(subring_generated r s)
           ==> subring_generated r s = subring_generated r t

  SUBRING_GENERATED_BY_SUBRING_GENERATED_IDEMPOT =
    |- !r s t.
           s SUBSET t
           ==> subring_generated (subring_generated r t)
               (ring_carrier(subring_generated r s)) =
               subring_generated r s

  SUBRING_GENERATED_IDEMPOT_GEN =
    |- !r s t.
           s SUBSET ring_carrier(subring_generated r t)
           ==> subring_generated (subring_generated r t) s =
               subring_generated r s

  SUBRING_GENERATED_INDUCT_STRONG =
    |- !r P s.
           (!x. x IN ring_carrier r /\ x IN s ==> P x) /\
           P (ring_0 r) /\
           P (ring_1 r) /\
           (!x. x IN ring_carrier r /\ P x ==> P (ring_neg r x)) /\
           (!x y.
                x IN ring_carrier r /\ y IN ring_carrier r /\ P x /\ P y
                ==> P (ring_add r x y)) /\
           (!x y.
                x IN ring_carrier r /\ y IN ring_carrier r /\ P x /\ P y
                ==> P (ring_mul r x y))
           ==> (!x. x IN ring_carrier(subring_generated r s) ==> P x)

  SUBRING_GENERATED_MINIMAL_EQ =
    |- !r h s.
           h subring_of r
           ==> (ring_carrier(subring_generated r s) SUBSET h <=>
                ring_carrier r INTER s SUBSET h)

  SUBRING_GENERATED_UNION =
    |- !r s t.
           subring_generated r
           (ring_carrier(subring_generated r s) UNION
            ring_carrier(subring_generated r t)) =
           subring_generated r (s UNION t)

  SUBRING_GENERATED_UNION_LEFT =
    |- !r s t.
           subring_generated r (ring_carrier(subring_generated r s) UNION t) =
           subring_generated r (s UNION t)

  SUBRING_GENERATED_UNION_RIGHT =
    |- !r s t.
           subring_generated r (s UNION ring_carrier(subring_generated r t)) =
           subring_generated r (s UNION t)

  SUBSET_CARRIER_SUBRING_GENERATED =
    |- !r s t.
           s SUBSET ring_carrier r /\ s SUBSET t
           ==> s SUBSET ring_carrier(subring_generated r t)

Thu 20th Aug 2020       Library/grouptheory.ml

Added the structure theorem for finitely generated Abelian groups, in
several different variants, with isomorphisms both to products and sums
(which of course are the same since they are finite, but for the sake
of completeness) of cyclic groups generated by elements of the group
and canonical cyclic groups based on the integers. Also included a few
other miscellaneous lemmas including the existence of maximal (normal)
subgroups in finitely generated groups and FINITE_SUBGROUPS_EQ, which
is an equivalential form of "finite group has finitely many subgroups".

  FINITELY_GENERATED_ABELIAN_GROUP_AS_PRODUCT_OF_CYCLIC_GROUPS =
    |- !G. finitely_generated_group G /\ abelian_group G <=>
           (?n H.
                (!i. 1 <= i /\ i <= n ==> cyclic_group (H i)) /\
                G isomorphic_group product_group (1..n) H)

  FINITELY_GENERATED_ABELIAN_GROUP_AS_PRODUCT_OF_INTEGER_GROUPS =
    |- !G. finitely_generated_group G /\
           abelian_group G /\
           (!x. x IN group_carrier G ==> group_element_order G x <= 1) <=>
           (?n. G isomorphic_group product_group (1..n) (\i. integer_group))

  FINITELY_GENERATED_ABELIAN_GROUP_AS_PRODUCT_OF_INTEGER_MOD_GROUPS =
    |- !G. finitely_generated_group G /\ abelian_group G <=>
           (?n d.
                G isomorphic_group
                product_group (1..n) (\i. integer_mod_group (d i)))

  FINITELY_GENERATED_ABELIAN_GROUP_AS_SUM_OF_CYCLIC_GROUPS =
    |- !G. finitely_generated_group G /\ abelian_group G <=>
           (?n H.
                (!i. 1 <= i /\ i <= n ==> cyclic_group (H i)) /\
                G isomorphic_group sum_group (1..n) H)

  FINITELY_GENERATED_ABELIAN_GROUP_AS_SUM_OF_INTEGER_GROUPS =
    |- !G. finitely_generated_group G /\
           abelian_group G /\
           (!x. x IN group_carrier G ==> group_element_order G x <= 1) <=>
           (?n. G isomorphic_group sum_group (1..n) (\i. integer_group))

  FINITELY_GENERATED_ABELIAN_GROUP_AS_SUM_OF_INTEGER_MOD_GROUPS =
    |- !G. finitely_generated_group G /\ abelian_group G <=>
           (?n d.
                G isomorphic_group
                sum_group (1..n) (\i. integer_mod_group (d i)))

  FINITELY_GENERATED_ABELIAN_GROUP_STRUCTURE_EXPLICIT =
    |- !G. finitely_generated_group G /\ abelian_group G <=>
           (?t. FINITE t /\
                t SUBSET group_carrier G /\
                G isomorphic_group sum_group t (\x. subgroup_generated G {x}))

  FINITELY_GENERATED_ABELIAN_GROUP_STRUCTURE_EXPLICIT_ALT =
    |- !G. finitely_generated_group G /\ abelian_group G <=>
           (?t. FINITE t /\
                t SUBSET group_carrier G /\
                G isomorphic_group
                product_group t (\x. subgroup_generated G {x}))

  FINITELY_GENERATED_ABELIAN_SUBGROUP_STRUCTURE_EXPLICIT =
    |- !G s.
           abelian_group G /\ FINITE s
           ==> (?t. FINITE t /\
                    CARD t <= CARD s /\
                    t SUBSET group_carrier G /\
                    subgroup_generated G t = subgroup_generated G s /\
                    subgroup_generated G s isomorphic_group
                    sum_group t (\x. subgroup_generated G {x}))

  FINITELY_GENERATED_ABELIAN_SUBGROUP_STRUCTURE_EXPLICIT_ALT =
    |- !G s.
           abelian_group G /\ FINITE s
           ==> (?t. FINITE t /\
                    CARD t <= CARD s /\
                    t SUBSET group_carrier G /\
                    subgroup_generated G t = subgroup_generated G s /\
                    subgroup_generated G s isomorphic_group
                    product_group t (\x. subgroup_generated G {x}))

  FINITELY_GENERATED_ABELIAN_SUBGROUP_STRUCTURE_ISOMORPHISM =
    |- !G s.
           abelian_group G /\ FINITE s
           ==> (?t. FINITE t /\
                    CARD t <= CARD s /\
                    t SUBSET group_carrier G /\
                    subgroup_generated G t = subgroup_generated G s /\
                    group_isomorphism
                    (sum_group t (\x. subgroup_generated G {x}),
                     subgroup_generated G s)
                    (group_sum G t))

  FINITELY_GENERATED_ABELIAN_SUBGROUP_STRUCTURE_ISOMORPHISM_ALT =
    |- !G s.
           abelian_group G /\ FINITE s
           ==> (?t. FINITE t /\
                    CARD t <= CARD s /\
                    t SUBSET group_carrier G /\
                    subgroup_generated G t = subgroup_generated G s /\
                    group_isomorphism
                    (product_group t (\x. subgroup_generated G {x}),
                     subgroup_generated G s)
                    (group_sum G t))

  FINITE_SUBGROUPS_EQ =
    |- !G. FINITE {h | h subgroup_of G} <=> FINITE (group_carrier G)

  GROUP_ELEMENT_ORDER_INTEGER_GROUP =
    |- !n. group_element_order integer_group n = (if n = &0 then 1 else 0)

  GROUP_POW_EQ_ID_DIVISOR =
    |- !G x m n.
           x IN group_carrier G /\ group_pow G x m = group_id G /\ m divides n
           ==> group_pow G x n = group_id G

  GROUP_ZPOW_ABS_EQ_ID =
    |- !G x n.
           x IN group_carrier G
           ==> (group_zpow G x (abs n) = group_id G <=>
                group_zpow G x n = group_id G)

  GROUP_ZPOW_EQ_ID_DIVISOR =
    |- !G x m n.
           x IN group_carrier G /\ group_zpow G x m = group_id G /\ m divides n
           ==> group_zpow G x n = group_id G

  INTEGER_MOD_GROUP_TRIVIAL =
    |- integer_mod_group 0 = integer_group

  MAXIMAL_NORMAL_SUBGROUP_EXISTS =
    |- !G. finitely_generated_group G /\ ~trivial_group G
           ==> (?h. h normal_subgroup_of G /\
                    ~(h = group_carrier G) /\
                    (!h'. h' normal_subgroup_of G /\ h PSUBSET h'
                          ==> h' = group_carrier G))

  MAXIMAL_SUBGROUP_EXISTS =
    |- !G. finitely_generated_group G /\ ~trivial_group G
           ==> (?h. h subgroup_of G /\
                    ~(h = group_carrier G) /\
                    (!h'. h' subgroup_of G /\ h PSUBSET h'
                          ==> h' = group_carrier G))

  NORMAL_SUBGROUP_OF_UNIONS =
    |- !G k u.
           ~(u = {}) /\
           (!h. h IN u ==> h normal_subgroup_of G) /\
           (!g h. g IN u /\ h IN u ==> g SUBSET h \/ h SUBSET g)
           ==> UNIONS u normal_subgroup_of G

  SUBGROUP_GENERATED_IDEMPOT_GEN =
    |- !G s t.
           s SUBSET group_carrier(subgroup_generated G t)
           ==> subgroup_generated (subgroup_generated G t) s =
               subgroup_generated G s

Also added a missing outer universal quantifier to the existing lemma
SUBGROUP_GENERATED_IDEMPOT.

Sat 15th Aug 2020       Library/grouptheory.ml

Added various group theory material including some boring but useful things
about iterated operations, leading up to one form of structure theorem
for Abelian groups, expressing torsion (of an) Abelian group, not necessarily
finitely generated, as a sum of p-groups over all primes p, for example in
TORSION_ABELIAN_GROUP_AS_SUM_OF_PGROUPS. New theorems:

  ABELIAN_GROUP_SUM_INV =
    |- !G k f.
           abelian_group G /\
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G)
           ==> group_sum G k (\i. group_inv G (f i)) =
               group_inv G (group_sum G k f)

  ABELIAN_GROUP_SUM_MUL =
    |- !G k f g.
           abelian_group G /\
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           FINITE {i | i IN k /\ ~(g i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G /\ g i IN group_carrier G)
           ==> group_sum G k (\i. group_mul G (f i) (g i)) =
               group_mul G (group_sum G k f) (group_sum G k g)

  ABELIAN_GROUP_SUM_POW =
    |- !G k f n.
           abelian_group G /\
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G)
           ==> group_sum G k (\i. group_pow G (f i) n) =
               group_pow G (group_sum G k f) n

  ABELIAN_GROUP_SUM_ZPOW =
    |- !G k f n.
           abelian_group G /\
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G)
           ==> group_sum G k (\i. group_zpow G (f i) n) =
               group_zpow G (group_sum G k f) n

  ABELIAN_GROUP_TORSION_ISOMORPHISM =
    |- !G. abelian_group G
           ==> group_isomorphism
               (sum_group {p | prime p}
                (\p. subgroup_generated G
                     {x | x IN group_carrier G /\
                          (?k. group_element_order G x = p EXP k)}),
                subgroup_generated G
                {x | x IN group_carrier G /\ ~(group_element_order G x = 0)})
               (group_sum G {p | prime p})

  ABELIAN_GROUP_TORSION_STRUCTURE =
    |- !G. abelian_group G
           ==> subgroup_generated G
               {x | x IN group_carrier G /\ ~(group_element_order G x = 0)} isomorphic_group
               sum_group {p | prime p}
               (\p. subgroup_generated G
                    {x | x IN group_carrier G /\
                         (?k. group_element_order G x = p EXP k)})

  CARRIER_SUBGROUP_GENERATED_ALT =
    |- !G s.
           abelian_group G /\ s SUBSET group_carrier G
           ==> group_carrier(subgroup_generated G s) =
               {group_sum G s (\x. group_zpow G x (n x)) | n | FINITE
                                                               {x | x IN s /\
                                                                    ~(n x = &0)}}

  CARRIER_SUBGROUP_GENERATED_EXPLICIT =
    |- !G s.
           abelian_group G /\ s SUBSET group_carrier G
           ==> group_carrier(subgroup_generated G s) =
               {group_sum G t (\x. group_zpow G x (n x)) | t,n | FINITE t /\
                                                                 t SUBSET s}

  CARRIER_SUBGROUP_GENERATED_FINITE =
    |- !G s.
           abelian_group G /\ FINITE s /\ s SUBSET group_carrier G
           ==> group_carrier(subgroup_generated G s) =
               {group_sum G s (\x. group_zpow G x (n x)) | n IN (:A->int)}

  CARRIER_SUBGROUP_GENERATED_UNIONS =
    |- !G u.
           abelian_group G
           ==> group_carrier(subgroup_generated G (UNIONS u)) =
               IMAGE (group_sum G u)
               (group_carrier(sum_group u (\i. subgroup_generated G i)))

  CARRIER_SUBGROUP_GENERATED_UNIONS_ALT =
    |- !G u.
           abelian_group G
           ==> group_carrier(subgroup_generated G (UNIONS u)) =
               {group_sum G u f | f | (!s. s IN u
                                           ==> f s IN
                                               group_carrier
                                               (subgroup_generated G s)) /\
                                      FINITE
                                      {s | s IN u /\ ~(f s = group_id G)}}

  CARRIER_SUBGROUP_GENERATED_UNIONS_EXPLICIT =
    |- !G u.
           abelian_group G
           ==> group_carrier(subgroup_generated G (UNIONS u)) =
               {group_sum G t f | t,f | FINITE t /\
                                        t SUBSET u /\
                                        (!s. s IN t
                                             ==> f s IN
                                                 group_carrier
                                                 (subgroup_generated G s))}

  CARRIER_SUBGROUP_GENERATED_UNIONS_FINITE =
    |- !G u.
           abelian_group G /\ FINITE u
           ==> group_carrier(subgroup_generated G (UNIONS u)) =
               {group_sum G u f | f | !s. s IN u
                                          ==> f s IN
                                              group_carrier
                                              (subgroup_generated G s)}

  FINITE_ABELIAN_GROUP_STRUCTURE =
    |- !G. abelian_group G /\ FINITE (group_carrier G)
           ==> G isomorphic_group
               sum_group {p | prime p /\ p divides CARD (group_carrier G)}
               (\p. subgroup_generated G
                    {x | x IN group_carrier G /\
                         (?k. group_element_order G x = p EXP k)})

  FINITE_ABELIAN_GROUP_STRUCTURE_ALT =
    |- !G. abelian_group G /\ FINITE (group_carrier G)
           ==> G isomorphic_group
               product_group {p | prime p /\ p divides CARD (group_carrier G)}
               (\p. subgroup_generated G
                    {x | x IN group_carrier G /\
                         (?k. group_element_order G x = p EXP k)})

  GROUP_ELEMENT_ORDER_COPRIME_DECOMP =
    |- !G z m n.
           coprime(m,n) /\
           z IN group_carrier G /\
           group_element_order G z = m * n
           ==> (?x y.
                    x IN group_carrier G /\
                    y IN group_carrier G /\
                    group_mul G x y = z /\
                    group_mul G y x = z /\
                    group_element_order G x = m /\
                    group_element_order G y = n)

  GROUP_ELEMENT_ORDER_COPRIME_DECOMP_DIVIDES =
    |- !G z m n.
           coprime(m,n) /\
           z IN group_carrier G /\
           group_element_order G z divides m * n
           ==> (?x y.
                    x IN group_carrier G /\
                    y IN group_carrier G /\
                    group_mul G x y = z /\
                    group_mul G y x = z /\
                    group_element_order G x divides m /\
                    group_element_order G y divides n)

  GROUP_ELEMENT_ORDER_COPRIME_DECOMP_EXPLICIT =
    |- !G x m n.
           coprime(m,n) /\
           x IN group_carrier G /\
           group_element_order G x = m * n
           ==> (?r s.
                    group_element_order G (group_zpow G x r) = m /\
                    group_element_order G (group_zpow G x s) = n /\
                    group_mul G (group_zpow G x r) (group_zpow G x s) = x)

  GROUP_ELEMENT_ORDER_COPRIME_DECOMP_UNIQUE =
    |- !G z m n.
           coprime(m,n) /\
           z IN group_carrier G /\
           group_element_order G z = m * n
           ==> (?!(x,y). x IN group_carrier G /\
                         y IN group_carrier G /\
                         group_mul G x y = z /\
                         group_mul G y x = z /\
                         group_element_order G x = m /\
                         group_element_order G y = n)

  GROUP_ELEMENT_ORDER_PRIMEPOW_DECOMP =
    |- !G z p.
           prime p /\ z IN group_carrier G /\ ~(group_element_order G z = 0)
           ==> (?x y.
                    x IN group_carrier G /\
                    y IN group_carrier G /\
                    group_mul G x y = z /\
                    group_mul G y x = z /\
                    (?k. group_element_order G x = p EXP k) /\
                    coprime(p,group_element_order G y))

  GROUP_ELEMENT_ORDER_SUM_GROUP_EQ_0 =
    |- !G k x.
           x IN group_carrier(sum_group k G)
           ==> (group_element_order (sum_group k G) x = 0 <=>
                (?i. i IN k /\ group_element_order (G i) (x i) = 0))

  GROUP_POW_COPRIME_EQ_ID =
    |- !G x m n.
           x IN group_carrier G /\ coprime(m,n)
           ==> (group_pow G x m = group_id G /\ group_pow G x n = group_id G <=>
                x = group_id G)

  GROUP_POW_EQ_ID_DECOMP =
    |- !G z m n.
           coprime(m,n) /\
           z IN group_carrier G /\
           group_pow G z (m * n) = group_id G
           ==> (?x y.
                    x IN group_carrier G /\
                    y IN group_carrier G /\
                    group_mul G x y = z /\
                    group_mul G y x = z /\
                    group_pow G x m = group_id G /\
                    group_pow G y n = group_id G)

  GROUP_POW_GCD_EQ_ID =
    |- !G x m n.
           x IN group_carrier G
           ==> (group_pow G x (gcd(m,n)) = group_id G <=>
                group_pow G x m = group_id G /\ group_pow G x n = group_id G)

  GROUP_PRODUCT_EQ_ID =
    |- !G (<<=) s f.
           (!i. i IN s ==> f i = group_id G)
           ==> group_product G (<<=) s f = group_id G

  GROUP_PRODUCT_ID =
    |- !G (<<=) s. group_product G (<<=) s (\x. group_id G) = group_id G

  GROUP_PRODUCT_RESTRICT_SET =
    |- !G (<<=) P s f.
           group_product G (<<=) {x | x IN s /\ P x} f =
           group_product G (<<=) s (\x. if P x then f x else group_id G)

  GROUP_PRODUCT_SUPERSET =
    |- !G (<<=) s t f.
           t SUBSET s /\ (!x. x IN s /\ ~(x IN t) ==> f x = group_id G)
           ==> group_product G (<<=) s f = group_product G (<<=) t f

  GROUP_SUM_EQ_ID =
    |- !G s f.
           (!i. i IN s ==> f i = group_id G) ==> group_sum G s f = group_id G

  GROUP_SUM_ID =
    |- !G s. group_sum G s (\x. group_id G) = group_id G

  GROUP_SUM_IMAGE =
    |- !G f g s.
           abelian_group G /\ (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
           ==> group_sum G (IMAGE f s) g = group_sum G s (g o f)

  GROUP_SUM_INV =
    |- !G k f.
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G) /\
           pairwise (\i j. group_mul G (f i) (f j) = group_mul G (f j) (f i)) k
           ==> group_sum G k (\i. group_inv G (f i)) =
               group_inv G (group_sum G k f)

  GROUP_SUM_POW =
    |- !G k f n.
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G) /\
           pairwise (\i j. group_mul G (f i) (f j) = group_mul G (f j) (f i)) k
           ==> group_sum G k (\i. group_pow G (f i) n) =
               group_pow G (group_sum G k f) n

  GROUP_SUM_RESTRICT_SET =
    |- !G P s f.
           group_sum G {x | x IN s /\ P x} f =
           group_sum G s (\x. if P x then f x else group_id G)

  GROUP_SUM_SUPERSET =
    |- !G s t f.
           t SUBSET s /\ (!x. x IN s /\ ~(x IN t) ==> f x = group_id G)
           ==> group_sum G s f = group_sum G t f

  GROUP_SUM_ZPOW =
    |- !G k f n.
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G) /\
           pairwise (\i j. group_mul G (f i) (f j) = group_mul G (f j) (f i)) k
           ==> group_sum G k (\i. group_zpow G (f i) n) =
               group_zpow G (group_sum G k f) n

  PGROUP_PRIME_TORSION =
    |- !G p.
           abelian_group G /\ prime p
           ==> pgroup {p}
               (subgroup_generated G
               {x | x IN group_carrier G /\
                    (?k. group_element_order G x = p EXP k)})

  PGROUP_SUBSET_PRIME_TORSION =
    |- !G p s.
           prime p /\
           s SUBSET group_carrier G /\
           pgroup {p} (subgroup_generated G s)
           ==> s SUBSET
               {x | x IN group_carrier G /\
                    (?k. group_element_order G x = p EXP k)}

  SUBGROUP_GENERATED_UNIONS_PRIME_TORSION =
    |- !G P.
           subgroup_generated G
           (UNIONS
           {{x | x IN group_carrier G /\
                 (?k. group_element_order G x = p EXP k)} | prime p /\ P p}) =
           subgroup_generated G
           {x | x IN group_carrier G /\
                ~(group_element_order G x = 0) /\
                (!p. prime p /\ p divides group_element_order G x ==> P p)}

  SUBGROUP_GENERATED_UNIONS_PRIME_TORSION_FINITE =
    |- !G P.
           FINITE {p | prime p /\ P p}
           ==> subgroup_generated G
               (UNIONS
               {{x | x IN group_carrier G /\
                     (?k. group_element_order G x = p EXP k)} | prime p /\ P p}) =
               subgroup_generated G
               {x | x IN group_carrier G /\
                    (!p. prime p /\ p divides group_element_order G x ==> P p)}

  SUBGROUP_GENERATED_UNIONS_PRIME_TORSION_FULL =
    |- !G. subgroup_generated G
           (UNIONS
           {{x | x IN group_carrier G /\
                 (?k. group_element_order G x = p EXP k)} | prime p}) =
           subgroup_generated G
           {x | x IN group_carrier G /\ ~(group_element_order G x = 0)}

  TORSION_ABELIAN_GROUP_AS_SUM_OF_PGROUPS =
    |- !G. abelian_group G
           ==> ((!x. x IN group_carrier G ==> ~(group_element_order G x = 0)) <=>
                (?H. (!p. prime p ==> pgroup {p} (H p)) /\
                     G isomorphic_group sum_group {p | prime p} H))

  TORSION_ABELIAN_GROUP_ISOMORPHISM =
    |- !G. abelian_group G /\
           (!x. x IN group_carrier G ==> ~(group_element_order G x = 0))
           ==> group_isomorphism
               (sum_group {p | prime p}
                (\p. subgroup_generated G
                     {x | x IN group_carrier G /\
                          (?k. group_element_order G x = p EXP k)}),
                G)
               (group_sum G {p | prime p})

  TORSION_ABELIAN_GROUP_STRUCTURE =
    |- !G. abelian_group G /\
           (!x. x IN group_carrier G ==> ~(group_element_order G x = 0))
           ==> G isomorphic_group
               sum_group {p | prime p}
               (\p. subgroup_generated G
                    {x | x IN group_carrier G /\
                         (?k. group_element_order G x = p EXP k)})

Sun  9th Aug 2020       Library/prime.ml

Added a simple suite of theorems about where iterated GCDs and LCMs collapse
to 0 or 1 (plus one for binary LCM and 1, which was previously missing):

  ITERATE_GCD_EQ_0 =
    |- !k f.
           FINITE k
           ==> (iterate (\m n. gcd(m,n)) k f = 0 <=> (!j. j IN k ==> f j = 0))

  ITERATE_GCD_EQ_0_GEN =
    |- !k f.
           iterate (\m n. gcd(m,n)) k f = 0 <=>
           FINITE {j | j IN k /\ ~(f j = 0)} ==> (!j. j IN k ==> f j = 0)

  ITERATE_LCM_EQ_0 =
    |- !k f.
           FINITE k
           ==> (iterate (\m n. lcm(m,n)) k f = 0 <=> (?j. j IN k /\ f j = 0))

  ITERATE_LCM_EQ_0_GEN =
    |- !k f.
           iterate (\m n. lcm(m,n)) k f = 0 <=>
           FINITE {j | j IN k /\ ~(f j = 1)} /\ (?j. j IN k /\ f j = 0)

  ITERATE_LCM_EQ_1 =
    |- !k f.
           FINITE k
           ==> (iterate (\m n. lcm(m,n)) k f = 1 <=> (!j. j IN k ==> f j = 1))

  ITERATE_LCM_EQ_1_GEN =
    |- !k f.
           iterate (\m n. lcm(m,n)) k f = 1 <=>
           FINITE {j | j IN k /\ ~(f j = 1)} ==> (!j. j IN k ==> f j = 1)

  LCM_EQ_1 =
    |- !m n. lcm(m,n) = 1 <=> m = 1 /\ n = 1

Sat  8th Aug 2020       Library/grouptheory.ml

Added more group theory material, including various systematic technical
lemmas for sum and product groups (permuting and restricting the indexing
sets etc.) and a definition of finitely generated groups with some basic
lemmas about the concept:

  finitely_generated_group =
    |- !G. finitely_generated_group G <=>
           (?s. FINITE s /\ subgroup_generated G s = G)

  ABELIAN_SUM_GROUP =
    |- !k G.
           abelian_group (sum_group k G) <=>
           (!i. i IN k ==> abelian_group (G i))

  CARD_EQ_BIJECTIONS_SPECIAL =
    |- !s t a b.
           FINITE s /\ FINITE t /\ CARD s = CARD t /\ a IN s /\ b IN t
           ==> (?f g.
                    f a = b /\
                    g b = a /\
                    (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
                    (!y. y IN t ==> g y IN s /\ f (g y) = y))

  CARD_LE_SUBGROUP_GENERATED =
    |- !G s k.
           INFINITE k /\ s <=_c k
           ==> group_carrier(subgroup_generated G s) <=_c k

  COUNTABLE_SUBGROUP_GENERATED =
    |- !G s.
           COUNTABLE (group_carrier G) \/ COUNTABLE s
           ==> COUNTABLE (group_carrier(subgroup_generated G s))

  CYCLIC_IMP_FINITELY_GENERATED_GROUP =
    |- !G. cyclic_group G ==> finitely_generated_group G

  FINITELY_GENERATED_ABELIAN_SUBGROUP =
    |- !G h.
           finitely_generated_group G /\ abelian_group G /\ h subgroup_of G
           ==> finitely_generated_group (subgroup_generated G h)

  FINITELY_GENERATED_FINITE_INDEX_SUBGROUP =
    |- !G h.
           finitely_generated_group G /\
           h subgroup_of G /\
           FINITE {right_coset G h x | x | x IN group_carrier G}
           ==> finitely_generated_group (subgroup_generated G h)

  FINITELY_GENERATED_FIXED_INDEX_SUBGROUPS =
    |- !G n.
           finitely_generated_group G
           ==> FINITE
               {h | h subgroup_of G /\
                    {right_coset G h x | x | x IN group_carrier G} HAS_SIZE n}

  FINITELY_GENERATED_GROUP =
    |- !G. finitely_generated_group G <=>
           (?s. FINITE s /\
                s SUBSET group_carrier G /\
                subgroup_generated G s = G)

  FINITELY_GENERATED_GROUP_EPIMORPHIC_IMAGE =
    |- !G H f.
           group_epimorphism (G,H) f /\ finitely_generated_group G
           ==> finitely_generated_group H

  FINITELY_GENERATED_GROUP_QUOTIENT_GROUP =
    |- !G n.
           finitely_generated_group G /\ n normal_subgroup_of G
           ==> finitely_generated_group (quotient_group G n)

  FINITELY_GENERATED_IMP_COUNTABLE_GROUP =
    |- !G. finitely_generated_group G ==> COUNTABLE (group_carrier G)

  FINITELY_GENERATED_PRODUCT_GROUP =
    |- !k G.
           finitely_generated_group (product_group k G) <=>
           FINITE {i | i IN k /\ ~trivial_group (G i)} /\
           (!i. i IN k ==> finitely_generated_group (G i))

  FINITELY_GENERATED_PROD_GROUP =
    |- !G H.
           finitely_generated_group (prod_group G H) <=>
           finitely_generated_group G /\ finitely_generated_group H

  FINITELY_GENERATED_SUM_GROUP =
    |- !k G.
           finitely_generated_group (sum_group k G) <=>
           FINITE {i | i IN k /\ ~trivial_group (G i)} /\
           (!i. i IN k ==> finitely_generated_group (G i))

  FINITE_GROUP_ACTIONS =
    |- !G s f.
           finitely_generated_group G /\
           FINITE s /\
           (!a a'.
                (!g x. g IN group_carrier G /\ x IN s ==> a g x = a' g x)
                ==> f a = f a')
           ==> FINITE {f a | group_action G s a}

  FINITE_IMAGE_GEN =
    |- !f g s t.
           IMAGE f s SUBSET t /\
           FINITE t /\
           (!x y. x IN s /\ y IN s /\ f x = f y ==> g x = g y)
           ==> FINITE (IMAGE g s)

  FINITE_IMP_FINITELY_GENERATED_GROUP =
    |- !G. FINITE (group_carrier G) ==> finitely_generated_group G

  GROUP_ACTIONS_EQ_ON_GENERATORS =
    |- !G t s a a'.
           group_action G s a /\
           group_action G s a' /\
           (!g x. g IN group_carrier G /\ g IN t /\ x IN s ==> a g x = a' g x)
           ==> (!g x.
                    g IN group_carrier(subgroup_generated G t) /\ x IN s
                    ==> a g x = a' g x)

  GROUP_HOMOMORPHISMS_EQ_ON_GENERATORS =
    |- !G H s f g.
           group_homomorphism (G,H) f /\
           group_homomorphism (G,H) g /\
           (!x. x IN group_carrier G /\ x IN s ==> f x = g x)
           ==> (!x. x IN group_carrier(subgroup_generated G s) ==> f x = g x)

  GROUP_HOMOMORPHISM_BETWEEN_SUBGROUPS_ALT =
    |- !G H g h f.
           group_homomorphism (G,H) f /\
           IMAGE f (group_carrier G INTER g) SUBSET h
           ==> group_homomorphism
               (subgroup_generated G g,subgroup_generated H h)
               f

  GROUP_ISOMORPHISMS_BETWEEN_SUBGROUPS_ALT =
    |- !G H g h f f'.
           group_isomorphisms (G,H) (f,f') /\
           IMAGE f (group_carrier G INTER g) SUBSET h /\
           IMAGE f' (group_carrier H INTER h) SUBSET g
           ==> group_isomorphisms
               (subgroup_generated G g,subgroup_generated H h)
               (f,f')

  GROUP_ISOMORPHISMS_PRODUCT_GROUP_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> group_isomorphisms
               (product_group (k UNION l) f,
                prod_group (product_group k f) (product_group l f))
               ((\f. RESTRICTION k f,RESTRICTION l f),
                (\(f,g) x. if x IN k then f x else g x))

  GROUP_ISOMORPHISMS_SUM_GROUP_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> group_isomorphisms
               (sum_group (k UNION l) f,
                prod_group (sum_group k f) (sum_group l f))
               ((\f. RESTRICTION k f,RESTRICTION l f),
                (\(f,g) x. if x IN k then f x else g x))

  GROUP_ISOMORPHISM_EPIMORPHISM =
    |- !G G' f.
           group_isomorphism (G,G') f <=>
           group_epimorphism (G,G') f /\
           (!x y.
                x IN group_carrier G /\ y IN group_carrier G /\ f x = f y
                ==> x = y)

  GROUP_ISOMORPHISM_EPIMORPHISM_ALT =
    |- !G G' f.
           group_isomorphism (G,G') f <=>
           group_epimorphism (G,G') f /\
           (!x. x IN group_carrier G /\ f x = group_id G' ==> x = group_id G)

  GROUP_ISOMORPHISM_PRODUCT_GROUP_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> group_isomorphism
               (product_group (k UNION l) f,
                prod_group (product_group k f) (product_group l f))
               (\f. RESTRICTION k f,RESTRICTION l f)

  GROUP_ISOMORPHISM_PRODUCT_PROJECTION =
    |- !G k. group_isomorphism (product_group {k} G,G k) (\x. x k)

  GROUP_ISOMORPHISM_SUM_GROUP_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> group_isomorphism
               (sum_group (k UNION l) f,
                prod_group (sum_group k f) (sum_group l f))
               (\f. RESTRICTION k f,RESTRICTION l f)

  GROUP_ISOMORPHISM_SUM_PROJECTION =
    |- !G k. group_isomorphism (sum_group {k} G,G k) (\x. x k)

  GROUP_PRODUCT_INJECTION =
    |- !k G a i.
           RESTRICTION k (\j. if j = i then a else group_id (G j)) IN
           group_carrier(product_group k G) <=>
           i IN k ==> a IN group_carrier(G i)

  GROUP_SUM_INJECTION =
    |- !k G a i.
           RESTRICTION k (\j. if j = i then a else group_id (G j)) IN
           group_carrier(sum_group k G) <=>
           i IN k ==> a IN group_carrier(G i)

  HAS_SIZE_LEFT_RIGHT_COSETS =
    |- !G h.
           h subgroup_of G
           ==> ({left_coset G x h | x | x IN group_carrier G} HAS_SIZE n <=>
                {right_coset G h x | x | x IN group_carrier G} HAS_SIZE n)

  ISOMORPHIC_COPY_OF_GROUP =
    |- !G s.
           (?G'. group_carrier G' = s /\ G isomorphic_group G') <=>
           group_carrier G =_c s

  ISOMORPHIC_GROUP_FINITE_GENERATION =
    |- !G H.
           G isomorphic_group H
           ==> (finitely_generated_group G <=> finitely_generated_group H)

  ISOMORPHIC_GROUP_TORSION =
    |- !P G H.
           G isomorphic_group H
           ==> ((!x. x IN group_carrier G ==> P (group_element_order G x)) <=>
                (!y. y IN group_carrier H ==> P (group_element_order H y)))

  ISOMORPHIC_PRODUCT_GROUP_BIJECTIONS =
    |- !s G t H f g.
           (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
           (!y. y IN t ==> g y IN s /\ f (g y) = y) /\
           (!i. i IN s ==> G i isomorphic_group H (f i))
           ==> product_group s G isomorphic_group product_group t H

  ISOMORPHIC_PRODUCT_GROUP_INSERT =
    |- !f i k.
           ~(i IN k)
           ==> product_group (i INSERT k) f isomorphic_group
               prod_group (f i) (product_group k f)

  ISOMORPHIC_PRODUCT_GROUP_SING =
    |- !G k. product_group {k} G isomorphic_group G k

  ISOMORPHIC_PRODUCT_GROUP_SUPPORT =
    |- !k G.
           product_group {i | i IN k /\ ~trivial_group (G i)} G isomorphic_group
           product_group k G

  ISOMORPHIC_PRODUCT_GROUP_SYMDIFF =
    |- !k l G.
           (!i. i IN k DIFF l UNION l DIFF k ==> trivial_group (G i))
           ==> product_group k G isomorphic_group product_group l G

  ISOMORPHIC_SUM_GROUP_BIJECTIONS =
    |- !s G t H f g.
           (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
           (!y. y IN t ==> g y IN s /\ f (g y) = y) /\
           (!i. i IN s ==> G i isomorphic_group H (f i))
           ==> sum_group s G isomorphic_group sum_group t H

  ISOMORPHIC_SUM_GROUP_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> sum_group (k UNION l) f isomorphic_group
               prod_group (sum_group k f) (sum_group l f)

  ISOMORPHIC_SUM_GROUP_INSERT =
    |- !f i k.
           ~(i IN k)
           ==> sum_group (i INSERT k) f isomorphic_group
               prod_group (f i) (sum_group k f)

  ISOMORPHIC_SUM_GROUP_SING =
    |- !G k. sum_group {k} G isomorphic_group G k

  ISOMORPHIC_SUM_GROUP_SUPPORT =
    |- !k G.
           sum_group {i | i IN k /\ ~trivial_group (G i)} G isomorphic_group
           sum_group k G

  ISOMORPHIC_SUM_GROUP_SYMDIFF =
    |- !k l G.
           (!i. i IN k DIFF l UNION l DIFF k ==> trivial_group (G i))
           ==> sum_group k G isomorphic_group sum_group l G

  SCHREIER_TRANSVERSAL_LEMMA =
    |- !G h s t.
           h subgroup_of G /\
           s SUBSET group_carrier G /\
           subgroup_generated G s = G /\
           (!x. x IN s ==> group_inv G x IN s) /\
           t SUBSET group_carrier G /\
           UNIONS {right_coset G h x | x IN t} = group_carrier G /\
           t INTER h SUBSET {group_id G}
           ==> group_carrier
               (subgroup_generated G
               (h INTER group_setmul G t (group_setmul G s (group_setinv G t)))) =
               h

  SUBGROUPS_GENERATED_EQ =
    |- !G s t.
           s SUBSET group_carrier(subgroup_generated G t) /\
           t SUBSET group_carrier(subgroup_generated G s)
           ==> subgroup_generated G s = subgroup_generated G t

  SUBGROUP_GENERATED_BY_SUBGROUP_GENERATED_IDEMPOT =
    |- !G s t.
           s SUBSET t
           ==> subgroup_generated (subgroup_generated G t)
               (group_carrier(subgroup_generated G s)) =
               subgroup_generated G s

  SUBGROUP_GENERATED_INDUCT_ALT =
    |- !G P s.
           P (group_id G) /\
           (!x. x IN group_carrier G /\ x IN s ==> P x /\ P (group_inv G x)) /\
           (!x y.
                x IN group_carrier G /\ y IN group_carrier G /\ P x /\ P y
                ==> P (group_mul G x y))
           ==> (!x. x IN group_carrier(subgroup_generated G s) ==> P x)

  SUBGROUP_GENERATED_INDUCT_LEFT =
    |- !G P s.
           P (group_id G) /\
           (!x y.
                x IN group_carrier G /\ x IN s /\ y IN group_carrier G /\ P y
                ==> P (group_mul G x y) /\ P (group_mul G (group_inv G x) y))
           ==> (!x. x IN group_carrier(subgroup_generated G s) ==> P x)

  SUBGROUP_GENERATED_INDUCT_STRONG =
    |- !G P s.
           (!x. x IN group_carrier G /\ x IN s ==> P x) /\
           P (group_id G) /\
           (!x. x IN group_carrier G /\ P x ==> P (group_inv G x)) /\
           (!x y.
                x IN group_carrier G /\ y IN group_carrier G /\ P x /\ P y
                ==> P (group_mul G x y))
           ==> (!x. x IN group_carrier(subgroup_generated G s) ==> P x)

  SUBGROUP_GENERATED_UNION =
    |- !G s t.
           subgroup_generated G
           (group_carrier(subgroup_generated G s) UNION
            group_carrier(subgroup_generated G t)) =
           subgroup_generated G (s UNION t)

  SUBGROUP_GENERATED_UNION_LEFT =
    |- !G s t.
           subgroup_generated G
           (group_carrier(subgroup_generated G s) UNION t) =
           subgroup_generated G (s UNION t)

  SUBGROUP_GENERATED_UNION_RIGHT =
    |- !G s t.
           subgroup_generated G
           (s UNION group_carrier(subgroup_generated G t)) =
           subgroup_generated G (s UNION t)

  SUBSET_CARRIER_SUBGROUP_GENERATED =
    |- !G s t.
           s SUBSET group_carrier G /\ s SUBSET t
           ==> s SUBSET group_carrier(subgroup_generated G t)

  TRIVIAL_IMP_FINITELY_GENERATED_GROUP =
    |- !G. trivial_group G ==> finitely_generated_group G

Thu  6th Aug 2020       sets.ml, iterate.ml, Multivariate/misc.ml

Added a couple more finite set lemmas

  FINITE_IMAGE_GEN =
    |- !f g s t.
           IMAGE f s SUBSET t /\
           FINITE t /\
           (!x y. x IN s /\ y IN s /\ f x = f y ==> g x = g y)
           ==> FINITE (IMAGE g s)

  CARD_EQ_BIJECTIONS_SPECIAL =
    |- !s t a b.
           FINITE s /\ FINITE t /\ CARD s = CARD t /\ a IN s /\ b IN t
           ==> (?f g.
                    f a = b /\
                    g b = a /\
                    (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
                    (!y. y IN t ==> g y IN s /\ f (g y) = y))

Also cleaned up proofs of FINITE_INDEX_NUMSEG and FINITE_INDEX_NUMSEG_SPECIAL
elsewhere, since they are after all trivial instances of
CARD_EQ_BIJECTIONS and CARD_EQ_BIJECTIONS_SPECIAL.

Fri 24th Jul 2020       Library/ringtheory.ml

Added a few new basic ring theorems, keeping things more in step with the
analogous things in Library/grouptheory.ml

  RING_MONOMORPHISM_INTO_SUPERRING =
    |- !r r' t f.
           ring_monomorphism (r,subring_generated r' t) f
           ==> ring_monomorphism (r,r') f

  SUBRING_GENERATED_SUPERSET =
   |- !r s.
           subring_generated r s = r <=>
           ring_carrier r SUBSET ring_carrier(subring_generated r s)

  SUBRING_MONOMORPHISM_EPIMORPHISM =
    |- !r r' s f.
           ring_monomorphism (r,r') f /\
           ring_epimorphism (r,subring_generated r' s) f <=>
           ring_isomorphism (r,subring_generated r' s) f

  RING_AUTOMORPHISM_IMP_ENDOMORPHISM =
   |- !r f. ring_automorphism r f ==> ring_endomorphism r f

and fixed an entirely analogous fumble where this theorem formerly
didn't say what the name suggests, but now does:

  RING_ISOMORPHISM_EQ_EPIMORPHISM_FINITE =
    |- !G H f.
         FINITE (ring_carrier G) /\
         FINITE (ring_carrier H) /\
         CARD (ring_carrier G) = CARD (ring_carrier H)
         ==> (ring_isomorphism (G,H) f <=> ring_epimorphism (G,H) f)

Fri 24th Jul 2020       Library/grouptheory.ml

Added more group theory material, in particular a constant for the
concept of "p-group" in a somewhat general sense:

 |- !G s. pgroup s G <=>
          !p x. prime p /\
                x IN group_carrier G /\
                p divides group_element_order G x
                ==> p IN s

This allows an arbitrary set of numbers, not just a singleton
(as in Rose's "A Course in Group Theory", definition 3.41), and
uses element orders to make it workable in infinite groups, while
still satisfying natural combinator theorems like PGROUP_SUM_GROUP
and PGROUP_EPIMORPHIC_IMAGE. Various theorems listed below like
FINITE_PGROUP_SING give the collapse to a more common definition
for finite groups. New theorems:

  CARRIER_SUBGROUP_GENERATED_UNION =
    |- !G g h.
           g subgroup_of G /\
           h subgroup_of G /\
           group_setmul G g h = group_setmul G h g
           ==> group_carrier(subgroup_generated G (g UNION h)) =
               group_setmul G g h

  CARRIER_SUBGROUP_GENERATED_UNION_LEFT =
    |- !G g h.
           g normal_subgroup_of G /\ h subgroup_of G
           ==> group_carrier(subgroup_generated G (g UNION h)) =
               group_setmul G g h

  CARRIER_SUBGROUP_GENERATED_UNION_RIGHT =
    |- !G g h.
           g subgroup_of G /\ h normal_subgroup_of G
           ==> group_carrier(subgroup_generated G (g UNION h)) =
               group_setmul G g h

  FINITE_AND_PGROUP_SING =
    |- !G p.
           prime p
           ==> (FINITE (group_carrier G) /\ pgroup {p} G <=>
                (?k. group_carrier G HAS_SIZE p EXP k))

  FINITE_PGROUP =
    |- !s G.
           FINITE (group_carrier G)
           ==> (pgroup s G <=>
                (!p. prime p /\ p divides CARD (group_carrier G) ==> p IN s))

  FINITE_PGROUP_SING =
    |- !G p.
           FINITE (group_carrier G) /\ prime p
           ==> (pgroup {p} G <=> (?k. CARD (group_carrier G) = p EXP k))

  GROUP_ELEMENT_ORDER_HOMOMORPHIC_IMAGE =
    |- !G H f x.
           group_homomorphism (G,H) f /\ x IN group_carrier G
           ==> group_element_order H (f x) divides group_element_order G x

  GROUP_ELEMENT_ORDER_SUM_GROUP =
    |- !G k x.
           x IN group_carrier(sum_group k G)
           ==> group_element_order (sum_group k G) x =
               iterate (\m n. lcm(m,n)) k
               (\i. group_element_order (G i) (x i))

  GROUP_EPIMORPHISM_SUBSET =
    |- !G G' f.
           group_epimorphism (G,G') f <=>
           group_homomorphism (G,G') f /\
           group_carrier G' SUBSET IMAGE f (group_carrier G)

  GROUP_EPIMORPHISM_SUM_PROJECTION =
    |- !G k i. i IN k ==> group_epimorphism (sum_group k G,G i) (\x. x i)

  GROUP_POW_PRODUCT_GROUP =
    |- !G k x n.
           group_pow (product_group k G) x n =
           RESTRICTION k (\i. group_pow (G i) (x i) n)

  GROUP_POW_SUM_GROUP =
    |- !G k x n.
           group_pow (sum_group k G) x n =
           RESTRICTION k (\i. group_pow (G i) (x i) n)

  GROUP_ZPOW_PRODUCT_GROUP =
    |- !G k x n.
           group_zpow (product_group k G) x n =
           RESTRICTION k (\i. group_zpow (G i) (x i) n)

  GROUP_ZPOW_SUM_GROUP =
    |- !G k x n.
           group_zpow (sum_group k G) x n =
           RESTRICTION k (\i. group_zpow (G i) (x i) n)

  ISOMORPHIC_PROD_GROUP_SUBGROUP_GENERATED =
    |- !G g h.
           g normal_subgroup_of G /\
           h normal_subgroup_of G /\
           g INTER h = {group_id G}
           ==> prod_group (subgroup_generated G g) (subgroup_generated G h)
               isomorphic_group
               subgroup_generated G (group_setmul G g h)

  PGROUP_EMPTY =
    |- !G. pgroup {} G <=> trivial_group G

  PGROUP_EPIMORPHIC_IMAGE =
    |- !G H f s. group_epimorphism (G,H) f /\ pgroup s G ==> pgroup s H

  PGROUP_MONO =
    |- !G s t. pgroup s G /\ s SUBSET t ==> pgroup t G

  PGROUP_MONOMORPHIC_PREIMAGE =
    |- !G H f s. group_monomorphism (G,H) f /\ pgroup s H ==> pgroup s G

  PGROUP_PROD_GROUP =
    |- !G H s. pgroup s (prod_group G H) <=> pgroup s G /\ pgroup s H

  PGROUP_QUOTIENT_GROUP =
    |- !G n s.
           n normal_subgroup_of G /\ pgroup s G
           ==> pgroup s (quotient_group G n)

  PGROUP_SING =
    |- !G p.
           prime p
           ==> (pgroup {p} G <=>
                (!x. x IN group_carrier G
                     ==> (?k. group_element_order G x = p EXP k)))

  PGROUP_SUBGROUP_GENERATED =
    |- !G s h. pgroup s G ==> pgroup s (subgroup_generated G h)

  PGROUP_SUM_GROUP =
    |- !k G s. pgroup s (sum_group k G) <=> (!i. i IN k ==> pgroup s (G i))

  QUOTIENT_GROUP_POW_EQ_ID =
    |- !G n x k.
           n normal_subgroup_of G /\ x IN group_carrier G
           ==> (group_pow (quotient_group G n) (right_coset G n x) k =
                group_id (quotient_group G n) <=>
                group_pow G x k IN n)

  SUBGROUP_OF_COPRIME_ORDER =
    |- !G n.
           abelian_group G
           ==> {x | x IN group_carrier G /\ coprime(n,group_element_order G x)}
               subgroup_of G

  SUBGROUP_OF_LOWER_ORDER =
    |- !G n.
           abelian_group G
           ==> {x | x IN group_carrier G /\ group_element_order G x divides n}
               subgroup_of G

  SUBGROUP_OF_LOWER_ORDER_ALT =
    |- !G n.
           abelian_group G
           ==> {x | x IN group_carrier G /\ group_pow G x n = group_id G}
               subgroup_of G

  SUBGROUP_OF_NONDIVISIBLE_ORDER =
    |- !G p.
           abelian_group G /\ prime p
           ==> {x | x IN group_carrier G /\
                    ~(p divides group_element_order G x)}
               subgroup_of G

  SUBGROUP_OF_PRIMES_TORSION =
    |- !G Q.
           abelian_group G
           ==> {x | x IN group_carrier G /\
                    (!p. prime p /\ p divides group_element_order G x ==> Q p)}
               subgroup_of G

  SUBGROUP_OF_PRIME_TORSION =
    |- !G p.
           abelian_group G /\ prime p
           ==> {x | x IN group_carrier G /\
                    (?k. group_element_order G x = p EXP k)}
               subgroup_of G

  SUBGROUP_OF_TORSION =
    |- !G. abelian_group G
           ==> {x | x IN group_carrier G /\ ~(group_element_order G x = 0)}
               subgroup_of G

  SUBGROUP_OF_TORSION_GEN =
    |- !P G.
           abelian_group G /\
           P 1 /\
           (!m n p. p divides m * n /\ P m /\ P n ==> P p)
           ==> {x | x IN group_carrier G /\ P (group_element_order G x)}
               subgroup_of G

  SUBGROUP_OF_TORSION_GENERAL =
    |- !P G.
           abelian_group G /\
           P 1 /\
           (!m n p. p divides lcm(m,n) /\ P m /\ P n ==> P p)
           ==> {x | x IN group_carrier G /\ P (group_element_order G x)}
               subgroup_of G

  TORSION_FREE_GROUP =
    |- !G. (!x. x IN group_carrier G ==> group_element_order G x <= 1) <=>
           (!x. x IN group_carrier G /\ ~(x = group_id G)
                ==> group_element_order G x = 0)

  TORSION_FREE_GROUP_ALT =
    |- !G. (!x. x IN group_carrier G ==> group_element_order G x <= 1) <=>
           (!x n.
                x IN group_carrier G /\ group_pow G x n = group_id G
                ==> x = group_id G \/ n = 0)

  TORSION_FREE_QUOTIENT_GROUP =
    |- !G H.
           abelian_group G /\
           quotient_group G
           {x | x IN group_carrier G /\ ~(group_element_order G x = 0)} = H
           ==> (!x. x IN group_carrier H ==> group_element_order H x <= 1)

Deleted the old theorems PGROUP and PGROUP_GEN (which are now just trivial
expanded combinations of stuff above), and changed the following to use the
new "pgroup" constant explicitly:

  PGROUP_ACTION_FIXPOINTS =
    |- !G s a p.
          group_action G s a /\
          FINITE s /\
          prime p /\
          FINITE (group_carrier G) /\
          pgroup {p} G
          ==> (CARD {x | x IN s /\ (!g. g IN group_carrier G ==> a g x = x)} ==
               CARD s) (mod p)

  PGROUP_ACTION_FIXPOINT =
    |- !G s a p.
           group_action G s a /\
           prime p /\
           FINITE (group_carrier G) /\
           pgroup {p} G /\
           FINITE s /\
           ~(p divides CARD s)
           ==> (?x. x IN s /\ (!g. g IN group_carrier G ==> a g x = x))

  PGROUP_MAXIMAL_NORMAL_SUBGROUP_OF =
    |- !G p h.
           prime p /\
           FINITE (group_carrier G) /\
           pgroup {p} G /\
           h subgroup_of G /\
           (!h'. h' subgroup_of G /\ h PSUBSET h' ==> h' = group_carrier G)
           ==> h normal_subgroup_of G

  PGROUP_NONTRIVIAL_CENTRE_GEN =
    |- !G n p.
           prime p /\
           FINITE (group_carrier G) /\
           pgroup {p} G /\
           n normal_subgroup_of G /\
           ~(n = {group_id G})
           ==> {group_id G} PSUBSET
               group_centralizer G (group_carrier G) INTER n

  PGROUP_SUBGROUP_PSUBSET_NORMALIZER =
    |- !G p h.
           prime p /\
           FINITE (group_carrier G) /\
           pgroup {p} G /\
           h subgroup_of G /\
           ~(h = group_carrier G)
           ==> h PSUBSET group_normalizer G h

Thu 23rd Jul 2020       Library/prime.ml

Added a basic suite of theorems about iterated GCD and LCM over finite sets,
or more generally those where the operator has finite support (with neutral
elements 0 and 1 respectively). This all fits naturally into the general
"iterate" framework with the minor syntactic cruft arising from currying the
two operators. New theorems:

  DIVIDES_ITERATE_GCD =
    |- !f k d.
           FINITE k
           ==> (d divides iterate (\m n. gcd(m,n)) k f <=>
                (!i. i IN k ==> d divides f i))

  DIVIDES_ITERATE_GCD_GEN =
    |- !f k d.
           d divides iterate (\m n. gcd(m,n)) k f <=>
           FINITE {j | j IN k /\ ~(f j = 0)} ==> (!i. i IN k ==> d divides f i)

  DIVIDES_ITERATE_LCM =
    |- !f k i. FINITE k /\ i IN k ==> f i divides iterate (\m n. lcm(m,n)) k f

  DIVIDES_ITERATE_LCM_GEN =
    |- !f k i.
           i IN k
           ==> (f i divides iterate (\m n. lcm(m,n)) k f <=>
                FINITE {j | j IN k /\ ~(f j = 1)} \/ f i = 1)

  ITERATE_GCD_DIVIDES =
    |- !f k i. FINITE k /\ i IN k ==> iterate (\m n. gcd(m,n)) k f divides f i

  ITERATE_GCD_DIVIDES_EQ =
    |- !f k i.
           i IN k
           ==> (iterate (\m n. gcd(m,n)) k f divides f i <=>
                FINITE {j | j IN k /\ ~(f j = 0)} \/ f i = 0)

  ITERATE_LCM_DIVIDES =
    |- !f k n.
           FINITE k
           ==> (iterate (\m n. lcm(m,n)) k f divides n <=>
                (!i. i IN k ==> f i divides n))

  ITERATE_LCM_DIVIDES_GEN =
    |- !f k n.
           iterate (\m n. lcm(m,n)) k f divides n <=>
           FINITE {j | j IN k /\ ~(f j = 1)} ==> (!i. i IN k ==> f i divides n)

  MONOIDAL_GCD =
    |- monoidal (\m n. gcd(m,n))

  MONOIDAL_LCM =
    |- monoidal (\m n. lcm(m,n))

  NEUTRAL_GCD =
    |- neutral (\m n. gcd(m,n)) = 0

  NEUTRAL_LCM =
    |- neutral (\m n. lcm(m,n)) = 1

  PRIMEPOW_DIVIDES_ITERATE_LCM =
    |- !f k p m.
           FINITE k /\ prime p
           ==> (p EXP m divides iterate (\m n. lcm(m,n)) k f <=>
                m = 0 \/ (?i. i IN k /\ p EXP m divides f i))

  PRIMEPOW_DIVIDES_ITERATE_LCM_GEN =
    |- !f k p m.
           prime p
           ==> (p EXP m divides iterate (\m n. lcm(m,n)) k f <=>
                m = 0 \/
                FINITE {j | j IN k /\ ~(f j = 1)} /\
                (?i. i IN k /\ p EXP m divides f i))

  PRIME_DIVIDES_ITERATE_LCM =
    |- !f k p.
           FINITE k /\ prime p
           ==> (p divides iterate (\m n. lcm(m,n)) k f <=>
                (?i. i IN k /\ p divides f i))

  PRIME_DIVIDES_ITERATE_LCM_GEN =
    |- !f k p.
           prime p
           ==> (p divides iterate (\m n. lcm(m,n)) k f <=>
                FINITE {j | j IN k /\ ~(f j = 1)} /\
                (?i. i IN k /\ p divides f i))

  PRIME_DIVIDES_LCM =
    |- !m n p. prime p ==> (p divides lcm(m,n) <=> p divides m \/ p divides n)

Fri 26th Jun 2020       Library/groups.ml

Made a few miscellaneous additions to the group theory material

  ABELIAN_GROUP_PRODUCT_ITERATE =
    |- !G (<<=) x k.
           woset (<<=) /\
           fld (<<=) = (:K) /\
           abelian_group G /\
           (!i. i IN k ==> x i IN group_carrier G)
           ==> group_product G (<<=) k x = iterate (group_add G) k x

  ABELIAN_GROUP_SUM_ITERATE =
    |- !G x k.
           abelian_group G /\ (!i. i IN k ==> x i IN group_carrier G)
           ==> group_sum G k x = iterate (group_add G) k x

  GROUP_HOMOMORPHISM_PRODUCT =
    |- !f k G H.
           group_homomorphism (product_group k G,product_group k H)
           (\x. RESTRICTION k (\i. f i (x i))) <=>
           (!i. i IN k ==> group_homomorphism (G i,H i) (f i))

  GROUP_HOMOMORPHISM_PRODUCT_INJECTION =
    |- !k G i.
           group_homomorphism (G i,product_group k G)
           (\a. RESTRICTION k (\j. if j = i then a else group_id (G j)))

  GROUP_HOMOMORPHISM_SUM =
    |- !f k G H.
           group_homomorphism (sum_group k G,sum_group k H)
           (\x. RESTRICTION k (\i. f i (x i))) <=>
           (!i. i IN k ==> group_homomorphism (G i,H i) (f i))

  GROUP_HOMOMORPHISM_SUM_INJECTION =
    |- !k G i.
           group_homomorphism (G i,sum_group k G)
           (\a. RESTRICTION k (\j. if j = i then a else group_id (G j)))

  GROUP_HOMOMORPHISM_SUM_PROJECTION =
    |- !G k i. i IN k ==> group_homomorphism (sum_group k G,G i) (\x. x i)

  SUM_GROUP_ALT =
    |- !k G.
           sum_group k G =
           subgroup_generated (product_group k G)
           {x | FINITE {i | i IN k /\ ~(x i = group_id (G i))}}

Also made a couple of changes to emphasize the newer "group_sum G" in place
of "iterate (group_add G)", renaming ABELIAN_GROUP_SUM to ABELIAN_GROUP_ITERATE
while also removing its finiteness assumption:

  ABELIAN_GROUP_ITERATE =
    |- !G x k.
           abelian_group G /\ (!i. i IN k ==> x i IN group_carrier G)
           ==> iterate (group_add G) k x IN group_carrier G

and changing ABELIAN_GROUP_HOMOMORPHISM_GROUP_SUM to use "group_sum"
explicitly:

  ABELIAN_GROUP_HOMOMORPHISM_GROUP_SUM =
    |- !f k A B.
           abelian_group B /\ (!i. i IN k ==> group_homomorphism (A i,B) (f i))
           ==> group_homomorphism (sum_group k A,B)
               (\x. group_sum B k (\i. f i (x i)))

Wed 24th Jun 2020       Library/words.ml

Added a few more trivial word lemmas:

  INT_VAL_WORD_MASK =
    |- !b. &(val(word_neg (word(bitval b)))) =
           (&2 pow dimindex(:N) - &1) * &(bitval b)

  REAL_VAL_WORD_MASK =
    |- !b. &(val(word_neg (word(bitval b)))) =
           (&2 pow dimindex(:N) - &1) * &(bitval b)

  REAL_VAL_WORD_NEG_CASES =
    |- !x. &(val(word_neg x)) =
           (if &(val x) = &0 then &0 else &2 pow dimindex(:N) - &(val x))

  VAL_WORD_MASK =
    |- !b. val(word_neg (word(bitval b))) =
           (2 EXP dimindex(:N) - 1) * bitval b

Mon 22nd Jun 2020       Library/floor.ml

Added a simple tactic (naive backchaining plus optional initial polynomial
normalization) that tries to prove a real expression is an integer

        # g `integer(&22 / &7 * (x - x * &1) + &n pow 7)`;;
        ...
        # e REAL_INTEGER_TAC;;
        val it : goalstack = No subgoals

Sat 20th Jun 2020       Library/grouptheory.ml

Added a number of technical group lemmas, mostly around the correspondence
between internal and external direct sums over an arbitrary indexing set:

        GROUP_EPIMORPHISM_ABELIAN_GROUP_SUM
        GROUP_EPIMORPHISM_GROUP_SUM
        GROUP_EPIMORPHISM_GROUP_SUM_EQ
        GROUP_EPIMORPHISM_GROUP_SUM_GEN
        GROUP_EPIMORPHISM_INTO_SUBGROUP_EQ
        GROUP_EPIMORPHISM_INTO_SUBGROUP_EQ_GEN
        GROUP_HOMOMORPHISM_GROUP_SUM
        GROUP_HOMOMORPHISM_GROUP_SUM_EQ
        GROUP_HOMOMORPHISM_GROUP_SUM_GEN
        GROUP_ISOMORPHISM_ABELIAN_GROUP_SUM
        GROUP_ISOMORPHISM_GROUP_SUM
        GROUP_ISOMORPHISM_GROUP_SUM_EQ
        GROUP_ISOMORPHISM_GROUP_SUM_GEN
        GROUP_MONOMORPHISM_ABELIAN_GROUP_SUM
        GROUP_MONOMORPHISM_GROUP_SUM
        GROUP_MONOMORPHISM_GROUP_SUM_EQ
        GROUP_MONOMORPHISM_GROUP_SUM_GEN
        GROUP_MONOMORPHISM_INTO_SUPERGROUP
        IN_SUBGROUP_PRODUCT
        IN_SUBGROUP_SUM
        ISOMORPHIC_ABELIAN_SUM_GROUP
        ISOMORPHIC_NORMAL_SUM_GROUP
        ISOMORPHIC_SUM_GROUP
        ISOMORPHIC_SUM_GROUP_GEN
        SUBGROUP_EPIMORPHISM_ABELIAN_GROUP_SUM
        SUBGROUP_EPIMORPHISM_GROUP_SUM
        SUBGROUP_EPIMORPHISM_GROUP_SUM_EQ
        SUBGROUP_EPIMORPHISM_GROUP_SUM_GEN
        SUBGROUP_GENERATED_SUPERSET
        SUBGROUP_ISOMORPHISM_ABELIAN_GROUP_SUM
        SUBGROUP_ISOMORPHISM_GROUP_SUM
        SUBGROUP_ISOMORPHISM_GROUP_SUM_EQ
        SUBGROUP_ISOMORPHISM_GROUP_SUM_GEN
        SUBGROUP_MONOMORPHISM_EPIMORPHISM

For example this is a fairly standard form, in among numerous other variants:

  ISOMORPHIC_NORMAL_SUM_GROUP =
    |- !k G h.
         (!i. i IN k ==> h i normal_subgroup_of G) /\
         subgroup_generated G (UNIONS {h i | i IN k}) = G /\
         (!i. i IN k
              ==> h i INTER
                  group_carrier
                  (subgroup_generated G (UNIONS {h j | j IN k DELETE i})) =
                  {group_id G})
         ==> sum_group k (\i. subgroup_generated G (h i)) isomorphic_group G

Fri 19th Jun 2020       Library/words.ml

Added three more trivial word lemmas, which can be derived automatically
but seem natural enough to deserve names:

  WORD_NEG_SUB =
    |- !x y. word_neg (word_sub x y) = word_sub y x

  WORD_NOT_NOT =
    |- !x. word_not (word_not x) = x

  WORD_XOR_NOT =
    |- (!x y. word_xor (word_not x) y = word_not (word_xor x y)) /\
       (!x y. word_xor x (word_not y) = word_not (word_xor x y))

Fri 19th Jun 2020       Library/grouptheory.ml

Renamed SUBGROUP_GENERATED_SETOP -> SUBGROUP_GENERATED_SETMUL, which is a
more natural name (this was a survival from more general "op" terminology
which tried to be neutral between additive and multiplicative forms of
group properties).

Mon 15th Jun 2020       sets.ml

Added an "eta-converted" definition of RESTRICTION:

  RESTRICTION_THM =
    |- !s f. RESTRICTION s f = (\x. if x IN s then f x else ARB)

Mon 15th Jun 2020       Library/ringtheory.ml

Added "ring_sum" and "ring_product" to the basic congruence rules for the
simplifier, and also switched around all the theorems RING_SUM_RESTRICT,
RING_SUM_SUPPORT, RING_PRODUCT_RESTRICT and RING_PRODUCT_SUPPORT, to be
more consistent with similar clauses for "group_sum" and "group_product"
and other iterated operations. So now:

  RING_SUM_RESTRICT =
    |- !s f.
           ring_sum r {a | a IN s /\ f a IN ring_carrier r} f = ring_sum r s f

  RING_SUM_SUPPORT =
    |- !s f. ring_sum r {a | a IN s /\ ~(f a = ring_0 r)} f = ring_sum r s f

  RING_PRODUCT_RESTRICT =
    |- !s f.
           ring_product r {a | a IN s /\ f a IN ring_carrier r} f =
           ring_product r s f

  RING_PRODUCT_SUPPORT =
    |- !s f.
           ring_product r {a | a IN s /\ ~(f a = ring_1 r)} f =
           ring_product r s f

Sat 13th Jun 2020       pair.ml, iterate.ml, Library/grouptheory.ml

Added a more generic iterator "iterato" ("o" for "ordered"), analogous to
"iterate" and collapsing to it in the usual universal commuting case, and
then its instantiations to two slightly different iterated operations on
groups, "group_product" (a product in order, an order given explicitly as
an argument) and "group_sum" (using an arbitrary wellorder, intended for
cases where it doesn't matter such as Abelian groups or more specific
settings in general groups). New definitions:

  iterato =
    |- !dom neut op (<<=) k f.
           iterato dom neut op (<<=) k f =
           (if FINITE {i | i IN k /\ f i IN dom DIFF {neut}} /\
               ~({i | i IN k /\ f i IN dom DIFF {neut}} = {})
            then let i =
                     (if ?i. i IN k /\
                             f i IN dom DIFF {neut} /\
                             (!j. j <<= i /\ j IN k /\ f j IN dom DIFF {neut}
                                  ==> j = i)
                      then @i. i IN k /\
                               f i IN dom DIFF {neut} /\
                               (!j. j <<= i /\ j IN k /\ f j IN dom DIFF {neut}
                                    ==> j = i)
                      else @i. i IN k /\ f i IN dom DIFF {neut}) in
                 op (f i)
                 (iterato dom neut op (<<=)
                  {j | j IN k DELETE i /\ f j IN dom DIFF {neut}}
                 f)
            else neut)

  group_product =
    |- !G. group_product G =
           iterato (group_carrier G) (group_id G) (group_mul G)

  group_sum =
    |- !G. group_sum G = group_product G (@l. woset l /\ fld l = (:K))

and theorems:

  ABELIAN_GROUP_PRODUCT_CLAUSES =
    |- !G (<<=) i k f.
           woset (<<=) /\
           fld (<<=) = (:K) /\
           abelian_group G /\
           FINITE {j | j IN k /\ f j IN group_carrier G DIFF {group_id G}}
           ==> group_product G (<<=) (i INSERT k) f =
               (if f i IN group_carrier G ==> i IN k
                then group_product G (<<=) k f
                else group_mul G (f i) (group_product G (<<=) k f))

  ABELIAN_GROUP_SUM_CLAUSES =
    |- !G i k f.
           abelian_group G /\
           FINITE {j | j IN k /\ f j IN group_carrier G DIFF {group_id G}}
           ==> group_sum G (i INSERT k) f =
               (if f i IN group_carrier G ==> i IN k
                then group_sum G k f
                else group_mul G (f i) (group_sum G k f))

  EMPTY_NUMSEG =
    |- !m n. n < m ==> m..n = {}

  EXISTS_SWAP_FUN_THM =
    |- !P. (?f. P f) <=> (?f. P (\a b. f b a))

  GROUP_COMMUTES_MUL =
    |- !G x y z.
           x IN group_carrier G /\
           y IN group_carrier G /\
           z IN group_carrier G /\
           group_mul G x z = group_mul G z x /\
           group_mul G y z = group_mul G z y
           ==> group_mul G (group_mul G x y) z =
               group_mul G z (group_mul G x y)

  GROUP_COMMUTES_PRODUCT =
    |- !G (<<=) k f z.
           (!i. i IN k /\ f i IN group_carrier G /\ ~(f i = group_id G)
                ==> group_mul G (f i) z = group_mul G z (f i)) /\
           z IN group_carrier G
           ==> group_mul G (group_product G (<<=) k f) z =
               group_mul G z (group_product G (<<=) k f)

  GROUP_COMMUTES_SUM =
    |- !G k f z.
           (!i. i IN k /\ f i IN group_carrier G /\ ~(f i = group_id G)
                ==> group_mul G (f i) z = group_mul G z (f i)) /\
           z IN group_carrier G
           ==> group_mul G (group_sum G k f) z =
               group_mul G z (group_sum G k f)

  GROUP_PRODUCT =
    |- !G (<<=) k f. group_product G (<<=) k f IN group_carrier G

  GROUP_PRODUCT_CLAUSES =
    |- !G (<<=) f.
         group_product G (<<=) {} f = group_id G /\
         (!i k.
              FINITE {j | j IN k /\ f j IN group_carrier G DIFF {group_id G}} /\
              (!j. j IN k ==> i <<= j /\ ~(j <<= i))
              ==> group_product G (<<=) (i INSERT k) f =
                  (if f i IN group_carrier G ==> i IN k
                   then group_product G (<<=) k f
                   else group_mul G (f i) (group_product G (<<=) k f)))

  GROUP_PRODUCT_CLAUSES_COMMUTING =
    |- !G (<<=) i k f.
           woset (<<=) /\
           fld (<<=) = (:K) /\
           FINITE {j | j IN k /\ f j IN group_carrier G DIFF {group_id G}} /\
           (!j. j IN k /\
                j <<= i /\
                ~(j = i) /\
                f i IN group_carrier G /\
                f j IN group_carrier G
                ==> group_mul G (f i) (f j) = group_mul G (f j) (f i))
           ==> group_product G (<<=) (i INSERT k) f =
               (if f i IN group_carrier G ==> i IN k
                then group_product G (<<=) k f
                else group_mul G (f i) (group_product G (<<=) k f))

  GROUP_PRODUCT_CLAUSES_EXISTS =
    |- !G (<<=) f.
         group_product G (<<=) {} f = group_id G /\
         (!k. FINITE {i | i IN k /\ f i IN group_carrier G DIFF {group_id G}} /\
              ~({i | i IN k /\ f i IN group_carrier G DIFF {group_id G}} =
                {})
              ==> (?i. i IN k /\
                       f i IN group_carrier G DIFF {group_id G} /\
                       group_product G (<<=) k f =
                       group_mul G (f i)
                       (group_product G (<<=) (k DELETE i) f)))

  GROUP_PRODUCT_CLAUSES_LEFT =
    |- !G f m n.
           group_product G (<=) (m..n) f =
           (if m <= n
            then if f m IN group_carrier G
                 then group_mul G (f m) (group_product G (<=) (m + 1..n) f)
                 else group_product G (<=) (m + 1..n) f
            else group_id G)

  GROUP_PRODUCT_CLAUSES_NUMSEG =
    |- (!G m f.
            group_product G (<=) (m..0) f =
            (if m = 0 /\ f 0 IN group_carrier G then f 0 else group_id G)) /\
       (!G m n f.
            group_product G (<=) (m..SUC n) f =
            (if m <= SUC n /\ f (SUC n) IN group_carrier G
             then group_mul G (group_product G (<=) (m..n) f) (f (SUC n))
             else group_product G (<=) (m..n) f))

  GROUP_PRODUCT_CLAUSES_RIGHT =
    |- !G f m n.
           group_product G (<=) (m..n) f =
           (if m <= n
            then if f n IN group_carrier G
                 then if n = 0
                      then f 0
                      else group_mul G (group_product G (<=) (m..n - 1) f)
                           (f n)
                 else group_product G (<=) (m..n - 1) f
            else group_id G)

  GROUP_PRODUCT_CLOSED =
    |- !P G (<<=) k f.
           P (group_id G) /\
           (!x y.
                x IN group_carrier G /\ y IN group_carrier G /\ P x /\ P y
                ==> P (group_mul G x y)) /\
           (!i. i IN k /\ f i IN group_carrier G /\ ~(f i = group_id G)
                ==> P (f i))
           ==> P (group_product G (<<=) k f)

  GROUP_PRODUCT_EQ =
    |- !G (<<=) k f g.
           (!i. i IN k ==> f i = g i)
           ==> group_product G (<<=) k f = group_product G (<<=) k g

  GROUP_PRODUCT_EXPAND_CASES =
    |- !G (<<=) k f.
           group_product G (<<=) k f =
           (if FINITE {i | i IN k /\ f i IN group_carrier G DIFF {group_id G}}
            then group_product G (<<=)
                 {i | i IN k /\ f i IN group_carrier G DIFF {group_id G}}
                 f
            else group_id G)

  GROUP_PRODUCT_MUL =
    |- !G (<<=) k f g.
           woset (<<=) /\
           fld (<<=) = (:K) /\
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           FINITE {i | i IN k /\ ~(g i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G /\ g i IN group_carrier G) /\
           pairwise (\i j. group_mul G (f i) (g j) = group_mul G (g j) (f i)) k
           ==> group_product G (<<=) k (\i. group_mul G (f i) (g i)) =
               group_mul G (group_product G (<<=) k f)
               (group_product G (<<=) k g)

  GROUP_PRODUCT_RESTRICT =
    |- !G (<<=) k f.
           group_product G (<<=) {i | i IN k /\ f i IN group_carrier G} f =
           group_product G (<<=) k f

  GROUP_PRODUCT_SING =
    |- !G (<<=) i f.
           group_product G (<<=) {i} f =
           (if f i IN group_carrier G then f i else group_id G)

  GROUP_PRODUCT_SUPPORT =
    |- !G (<<=) k f.
           group_product G (<<=) {i | i IN k /\ ~(f i = group_id G)} f =
           group_product G (<<=) k f

  GROUP_PRODUCT_UNION =
    |- !G (<<=) f s t.
           woset (<<=) /\
           fld (<<=) = (:K) /\
           (FINITE {i | i IN s /\ f i IN group_carrier G DIFF {group_id G}} <=>
            FINITE {i | i IN t /\ f i IN group_carrier G DIFF {group_id G}}) /\
           (!x y. x IN s /\ y IN t ==> x <<= y /\ ~(x = y))
           ==> group_product G (<<=) (s UNION t) f =
               group_mul G (group_product G (<<=) s f)
               (group_product G (<<=) t f)

  GROUP_SUM =
    |- !G k f. group_sum G k f IN group_carrier G

  GROUP_SUM_CLAUSES_COMMUTING =
    |- !G i k f.
           FINITE {j | j IN k /\ f j IN group_carrier G DIFF {group_id G}} /\
           (!j. j IN k /\
                ~(j = i) /\
                f i IN group_carrier G /\
                f j IN group_carrier G
                ==> group_mul G (f i) (f j) = group_mul G (f j) (f i))
           ==> group_sum G (i INSERT k) f =
               (if f i IN group_carrier G ==> i IN k
                then group_sum G k f
                else group_mul G (f i) (group_sum G k f))

  GROUP_SUM_CLAUSES_EXISTS =
    |- !G f.
         group_sum G {} f = group_id G /\
         (!k. FINITE {i | i IN k /\ f i IN group_carrier G DIFF {group_id G}} /\
              ~({i | i IN k /\ f i IN group_carrier G DIFF {group_id G}} =
                {})
              ==> (?i. i IN k /\
                       f i IN group_carrier G DIFF {group_id G} /\
                       group_sum G k f =
                       group_mul G (f i) (group_sum G (k DELETE i) f)))

  GROUP_SUM_CLOSED =
    |- !P G k f.
           P (group_id G) /\
           (!x y.
                x IN group_carrier G /\ y IN group_carrier G /\ P x /\ P y
                ==> P (group_mul G x y)) /\
           (!i. i IN k /\ f i IN group_carrier G /\ ~(f i = group_id G)
                ==> P (f i))
           ==> P (group_sum G k f)

  GROUP_SUM_EQ =
    |- !G k f g.
           (!i. i IN k ==> f i = g i) ==> group_sum G k f = group_sum G k g

  GROUP_SUM_EXPAND_CASES =
    |- !G k f.
           group_sum G k f =
           (if FINITE {i | i IN k /\ f i IN group_carrier G DIFF {group_id G}}
            then group_sum G
                 {i | i IN k /\ f i IN group_carrier G DIFF {group_id G}}
                 f
            else group_id G)

  GROUP_SUM_MUL =
    |- !G k f g.
           FINITE {i | i IN k /\ ~(f i = group_id G)} /\
           FINITE {i | i IN k /\ ~(g i = group_id G)} /\
           (!i. i IN k ==> f i IN group_carrier G /\ g i IN group_carrier G) /\
           pairwise (\i j. group_mul G (f i) (g j) = group_mul G (g j) (f i)) k
           ==> group_sum G k (\i. group_mul G (f i) (g i)) =
               group_mul G (group_sum G k f) (group_sum G k g)

  GROUP_SUM_RESTRICT =
    |- !G k f.
           group_sum G {i | i IN k /\ f i IN group_carrier G} f =
           group_sum G k f

  GROUP_SUM_SING =
    |- !G i f.
           group_sum G {i} f =
           (if f i IN group_carrier G then f i else group_id G)

  GROUP_SUM_SUPPORT =
    |- !G k f.
           group_sum G {i | i IN k /\ ~(f i = group_id G)} f = group_sum G k f

  ITERATO_CLAUSES =
    |- !dom neut op (<<=) f.
           iterato dom neut op (<<=) {} f = neut /\
           (!i k.
                FINITE {i | i IN k /\ f i IN dom DIFF {neut}} /\
                (!j. j IN k ==> i <<= j /\ ~(j <<= i))
                ==> iterato dom neut op (<<=) (i INSERT k) f =
                    (if f i IN dom ==> f i = neut \/ i IN k
                     then iterato dom neut op (<<=) k f
                     else op (f i) (iterato dom neut op (<<=) k f)))

  ITERATO_CLAUSES_EXISTS =
    |- !dom neut op (<<=) f.
           iterato dom neut op (<<=) {} f = neut /\
           (!k. FINITE {i | i IN k /\ f i IN dom DIFF {neut}} /\
                ~({i | i IN k /\ f i IN dom DIFF {neut}} = {})
                ==> (?i. i IN k /\
                         f i IN dom DIFF {neut} /\
                         iterato dom neut op (<<=) k f =
                         op (f i) (iterato dom neut op (<<=) (k DELETE i) f)))

  ITERATO_CLAUSES_GEN =
    |- !dom neut op (<<=) f.
           iterato dom neut op (<<=) {} f = neut /\
           (!i k.
                FINITE {j | j IN k /\ f j IN dom DIFF {neut}} /\
                (!j. j IN k ==> i = j \/ i <<= j \/ j <<= i) /\
                (!j. j <<= i /\ j IN k /\ f j IN dom DIFF {neut} ==> j = i)
                ==> iterato dom neut op (<<=) (i INSERT k) f =
                    (if f i IN dom ==> f i = neut \/ i IN k
                     then iterato dom neut op (<<=) k f
                     else op (f i) (iterato dom neut op (<<=) k f)))

  ITERATO_CLAUSES_NUMSEG_LEFT =
    |- !dom neut op f m n.
           iterato dom neut op (<=) (m..n) f =
           (if m <= n
            then if f m IN dom ==> f m = neut
                 then iterato dom neut op (<=) (m + 1..n) f
                 else op (f m) (iterato dom neut op (<=) (m + 1..n) f)
            else neut)

  ITERATO_CLOSED =
    |- !dom neut op (<<=) k f P.
           P neut /\
           (!x y. P x /\ P y ==> P (op x y)) /\
           (!i. i IN k /\ f i IN dom /\ ~(f i = neut) ==> P (f i))
           ==> P (iterato dom neut op (<<=) k f)

  ITERATO_EQ =
    |- !dom neut op (<<=) k f g.
           (!i. i IN k ==> f i = g i)
           ==> iterato dom neut op (<<=) k f = iterato dom neut op (<<=) k g

  ITERATO_EXPAND_CASES =
    |- !dom neut op (<<=) k f.
           iterato dom neut op (<<=) k f =
           (if FINITE {i | i IN k /\ f i IN dom DIFF {neut}}
            then iterato dom neut op (<<=)
                 {i | i IN k /\ f i IN dom DIFF {neut}}
                 f
            else neut)

  ITERATO_INDUCT =
    |- !dom neut op (<<=) k f P.
           P neut /\
           (!i x.
                i IN k /\ f i IN dom /\ ~(f i = neut) /\ P x ==> P (op (f i) x))
           ==> P (iterato dom neut op (<<=) k f)

  ITERATO_ITERATE =
    |- !op (<<=).
           monoidal op ==> iterato (:A) (neutral op) op (<<=) = iterate op

  ITERATO_SUPPORT =
    |- !dom neut op (<<=) k f.
           iterato dom neut op (<<=) {i | i IN k /\ f i IN dom DIFF {neut}} f =
           iterato dom neut op (<<=) k f

Fri 12th Jun 2020       Library/words.ml

Added a few miscellaneous useful lemmas about machine words:

  BITVAL_POS =
    |- !b. 0 < bitval b <=> b

  EQ_BITVAL =
    |- !b c. bitval b = bitval c <=> b <=> c

  INT_EQ_BITVAL =
    |- !b c. &(bitval b) = &(bitval c) <=> b <=> c

  INT_LE_BITVAL =
    |- !b c. &(bitval b) <= &(bitval c) <=> b ==> c

  INT_VAL_WORD_NOT =
     |- !x. &(val(word_not x)) = &2 pow dimindex(:N) - &1 - &(val x)

  LE_BITVAL =
    |- !b c. bitval b <= bitval c <=> b ==> c

  REAL_BITVAL_NOT =
    |- !b. &(bitval(~b)) = &1 - &(bitval b)

  REAL_EQ_BITVAL =
    |- !b c. &(bitval b) = &(bitval c) <=> b <=> c

  REAL_LE_BITVAL =
    |- !b c. &(bitval b) <= &(bitval c) <=> b ==> c

  REAL_VAL_WORD_NOT =
     |- !x. &(val(word_not x)) = &2 pow dimindex(:N) - &1 - &(val x)

  VAL_EQ_MAX_MASK =
     |- !x. val x = 2 EXP dimindex(:N) - 1 <=> x = word_neg (word 1)

  VAL_MOD_2 =
    |- !x. val x MOD 2 = bitval(bit 0 x)

  WORD_AND_1_BITVAL =
     |- (!x. word_and (word 1) x = word(bitval(bit 0 x))) /\
        (!x. word_and x (word 1) = word(bitval(bit 0 x)))

  WORD_NEG_AND_MASK =
    |- (!b x.
            word_neg (word_and (word_neg (word(bitval b))) x) =
            word_and (word_neg (word(bitval b))) (word_neg x)) /\
       (!b x.
            word_neg (word_and x (word_neg (word(bitval b)))) =
            word_and (word_neg x) (word_neg (word(bitval b))))

Thu 11th Jun 2020       int.ml, Library/integer.ml, Library/pocklington.ml

Sharpened the existing theorems INT_CONG_DIV2 and INT_CONG_DIV, which formerly
assumed nonnegativity of m and are now:

  INT_CONG_DIV2 =
    |- !a b m n. (a == b) (mod (m * n)) ==> (a div m == b div m) (mod n)

  INT_CONG_DIV =
    |- !m n a b.
           ~(m = &0) /\ (a == m * b) (mod (m * n)) ==> (a div m == b) (mod n)

Fixed a trivial fumble in the outer quantifiers of CONG_DIV2, now:

  CONG_DIV2 =
    |- !a b m n. (a == b) (mod (m * n)) ==> (a DIV m == b DIV m) (mod n)

and added two new variants in the setting of N and Z:

  CONG_DIV_COPRIME =
    |- !m n a b.
         coprime(m,n) /\ m divides a /\ (a == m * b) (mod n)
         ==> (a DIV m == b) (mod n)

  INT_CONG_DIV_COPRIME =
    |- !m n a b.
         coprime(m,n) /\ m divides a /\ (a == m * b) (mod n)
         ==> (a div m == b) (mod n)

Fri  5th Jun 2020       real.ml, int.ml

Added a couple of trivial theorems collecting the basic properties of the
N->R and N->Z type casts together into a single conjunction (leaving out those
for successor and subtraction that seem a bit more delicate).

  REAL_OF_NUM_CLAUSES =
    |- (!m n. &m = &n <=> m = n) /\
       (!m n. &m >= &n <=> m >= n) /\
       (!m n. &m > &n <=> m > n) /\
       (!m n. &m <= &n <=> m <= n) /\
       (!m n. &m < &n <=> m < n) /\
       (!m n. max (&m) (&n) = &(MAX m n)) /\
       (!m n. min (&m) (&n) = &(MIN m n)) /\
       (!m n. &m + &n = &(m + n)) /\
       (!m n. &m * &n = &(m * n)) /\
       (!x n. &x pow n = &(x EXP n))

and the identical-looking INT_OF_NUM_CLAUSES (with the type ":int" instead of
":real").

Sat 23rd May 2020       Examples/pseudoprime.ml [new file]

Added a file about three additional concepts of "pseudoprime", in addition to
the Miller-Rabin or strong pseudoprime material in "Examples/miller_rabin.ml".
Together these two files now define four different concepts of pseudoprime. The
phrase "Euler pseudoprime" can be used for either of the middle ones; this
terminology is chosen in an attempt to be less ambiguous.

        fermat_pseudoprime
        weak_euler_pseudoprime
        euler_jacobi_pseudoprime
        miller_rabin_pseudoprime

This file proves all the standard implications and equivalences between the
concepts, density bounds for composites with or without exceptions etc., as
well as some auxiliary results about Carmichael numbers (defined as
"carmichael_number").

Fri 22nd May 2020       int.ml, Library/products.ml, Library/integer.ml, Library/jacobi.ml

Added a few miscellaneous arithmetical lemmas

  DIVIDES_DIVIDES_DIV_IMP =
    |- !n d e. d * e divides n ==> e divides n DIV d

  EXP_NSUM =
    |- !m n s. FINITE s ==> m EXP nsum s n = nproduct s (\i. m EXP n i)

  INT_CONG_MUL_1 =
    |- !n x y. (x == &1) (mod n) /\ (y == &1) (mod n) ==> (x * y == &1) (mod n)

  INT_CONG_POW_1 =
    |- !a k n. (a == &1) (mod n) ==> (a pow k == &1) (mod n)

  INT_POW_NSUM =
    |- !x n s. FINITE s ==> x pow nsum s n = iproduct s (\i. x pow n i)

  JACOBI_NPRODUCT_LEFT =
    |- !a n k.
           FINITE k
           ==> jacobi (nproduct k a,n) = iproduct k (\i. jacobi (a i,n))

  JACOBI_NPRODUCT_RIGHT =
    |- !a n k.
           FINITE k
           ==> jacobi (a,nproduct k n) = iproduct k (\i. jacobi (a,n i))

  REAL_POW_NSUM =
    |- !x n s. FINITE s ==> x pow nsum s n = product s (\i. x pow n i)

Thu 21st May 2020       Examples/miller_rabin.ml

As a prelude to introducing a first-class definition of "Fermat pseudoprime",
renamed two existing theorems:

  MILLER_RABIN_IMP_FERMAT_PSEUDOPRIME ->
    MILLER_RABIN_IMP_FERMAT_PSEUDOPRIME_EXPLICIT

  MILLER_RABIN_EQ_FERMAT_PSEUDOPRIME ->
    MILLER_RABIN_EQ_FERMAT_PSEUDOPRIME_EXPLICIT

and added the following, which is an easy consequence of the bound theorems but
worth calling out explicitly:

  ABSOLUTE_MILLER_RABIN_PSEUDOPRIME =
    |- !n. (!a. coprime(a,n) ==> miller_rabin_pseudoprime a n) <=>
         n = 1 \/ prime n

Wed 20th May 2020       Library/pocklington.ml

Added a couple more natural lemmas about congruences modulo squarefree numbers:

  CONG_MOD_SQUAREFREE =
    |- !n a b.
           squarefree n /\ (!p. prime p /\ p divides n ==> (a == b) (mod p))
           ==> (a == b) (mod n)

  CONG_MOD_SQUAREFREE_EQ =
    |- !n a b.
           squarefree n
           ==> ((a == b) (mod n) <=>
                (!p. prime p /\ p divides n ==> (a == b) (mod p)))

Fri 15th May 2020       Library/pocklington.ml, Library/primitive.ml

Added theorems about injectivity and surjectivity of powers modulo an integer,
which can actually be considered as special cases (for the multiplicative group
of integers) of the group powering theorems added yesterday. Indeed
PRIME_DIVISOR_ORDER_EXISTS is in effect the special case of Cauchy's theorem in
group theory for the case of multiplicative groups of integers, but we maintain
the policy of keeping the two settings independent until brought together in
"Library/modmul_group.ml".

  INJECTIVE_EXP_MODULO =
    |- !n a b k.
           coprime(k,phi n) /\
           coprime(n,a) /\
           coprime(n,b) /\
           (a EXP k == b EXP k) (mod n)
           ==> (a == b) (mod n)

  INJECTIVE_EXP_MODULO_EQ =
    |- !n k.
           ~(n = 0)
           ==> ((!a b.
                     coprime(n,a) /\
                     coprime(n,b) /\
                     (a EXP k == b EXP k) (mod n)
                     ==> (a == b) (mod n)) <=>
                coprime(k,phi n))

  POWER_RESIDUE_MODULO_COPRIME =
    |- !n a k.
           coprime(n,a) /\ coprime(k,phi n) ==> (?x. (x EXP k == a) (mod n))

  POWER_RESIDUE_MODULO_EQ =
    |- !n k.
           ~(n = 0)
           ==> ((!a. coprime(n,a) ==> (?x. (x EXP k == a) (mod n))) <=>
                coprime(k,phi n))

  POWER_RESIDUE_MODULO_EQ_ALT =
    |- !n k.
           ~(n = 0)
           ==> ((!a. coprime(n,a)
                     ==> (?x. coprime(n,x) /\ (x EXP k == a) (mod n))) <=>
                coprime(k,phi n))

  POWER_RESIDUE_MODULO_PRIME =
    |- !p a k.
           prime p /\ ~(p divides a) /\ coprime(k,p - 1)
           ==> (?x. (x EXP k == a) (mod p))

  PRIME_DIVISOR_ORDER_EXISTS =
    |- !n p. ~(n = 0) /\ prime p /\ p divides phi n ==> (?x. order n x = p)

Thu 14th May 2020       Library/grouptheory.ml

Added a number of theorems around injectivity and surjectivity of the n'th
power function in finite groups (including the easier special case of
n = -1, inversion). For example FINITE_GROUP_POW_INJECTIVE_EQ which says that
the "n'th power" function is injective in a finite group iff n is coprime to
|G|.

  ABELIAN_GROUP_EPIMORPHISM_INVERSION =
    |- !G. group_epimorphism (G,G) (group_inv G) <=> abelian_group G

  ABELIAN_GROUP_EPIMORPHISM_POWERING =
    |- !G n.
           abelian_group G /\
           FINITE(group_carrier G) /\
           coprime(n,CARD(group_carrier G))
           ==> group_epimorphism (G,G) (\x. group_pow G x n)

  ABELIAN_GROUP_EPIMORPHISM_POWERING_EQ =
    |- !G n.
           abelian_group G /\ FINITE(group_carrier G)
           ==> (group_epimorphism (G,G) (\x. group_pow G x n) <=>
                coprime(n,CARD(group_carrier G)))

  ABELIAN_GROUP_HOMOMORPHISM_INVERSION =
    |- !G. group_homomorphism (G,G) (group_inv G) <=> abelian_group G

  ABELIAN_GROUP_ISOMORPHISMS_INVERSION =
    |- !G. group_isomorphisms (G,G) (group_inv G,group_inv G) <=>
           abelian_group G

  ABELIAN_GROUP_ISOMORPHISM_INVERSION =
    |- !G. group_isomorphism (G,G) (group_inv G) <=> abelian_group G

  ABELIAN_GROUP_ISOMORPHISM_POWERING =
    |- !G n.
           abelian_group G /\
           FINITE(group_carrier G) /\
           coprime(n,CARD(group_carrier G))
           ==> group_isomorphism (G,G) (\x. group_pow G x n)

  ABELIAN_GROUP_ISOMORPHISM_POWERING_EQ =
    |- !G n.
           abelian_group G /\ FINITE(group_carrier G)
           ==> (group_isomorphism (G,G) (\x. group_pow G x n) <=>
                coprime(n,CARD(group_carrier G)))

  ABELIAN_GROUP_MONOMORPHISM_INVERSION =
    |- !G. group_monomorphism (G,G) (group_inv G) <=> abelian_group G

  ABELIAN_GROUP_MONOMORPHISM_POWERING =
    |- !G n.
           abelian_group G /\
           FINITE(group_carrier G) /\
           coprime(n,CARD(group_carrier G))
           ==> group_monomorphism (G,G) (\x. group_pow G x n)

  ABELIAN_GROUP_MONOMORPHISM_POWERING_EQ =
    |- !G n.
           abelian_group G /\ FINITE(group_carrier G)
           ==> (group_monomorphism (G,G) (\x. group_pow G x n) <=>
                coprime(n,CARD(group_carrier G)))

  FINITE_GROUP_POW_INJECTIVE_EQ =
    |- !G n.
           FINITE(group_carrier G)
           ==> ((!x y.
                     x IN group_carrier G /\
                     y IN group_carrier G /\
                     group_pow G x n = group_pow G y n
                     ==> x = y) <=>
                coprime(n,CARD(group_carrier G)))

  FINITE_GROUP_POW_SURJECTIVE_EQ =
    |- !G n.
           FINITE(group_carrier G)
           ==> ((!x. x IN group_carrier G
                     ==> (?y. y IN group_carrier G /\ group_pow G y n = x)) <=>
                coprime(n,CARD(group_carrier G)))

  FINITE_GROUP_ROOT_EXISTS =
    |- !G n x.
           FINITE(group_carrier G) /\
           coprime(n,CARD(group_carrier G)) /\
           x IN group_carrier G
           ==> (?y. y IN group_carrier G /\ group_pow G y n = x)

  FINITE_GROUP_ZPOW_INJECTIVE_EQ =
    |- !G n.
           FINITE(group_carrier G)
           ==> ((!x y.
                     x IN group_carrier G /\
                     y IN group_carrier G /\
                     group_zpow G x n = group_zpow G y n
                     ==> x = y) <=>
                coprime(n,&(CARD(group_carrier G))))

  FINITE_GROUP_ZPOW_SURJECTIVE_EQ =
    |- !G n.
           FINITE(group_carrier G)
           ==> ((!x. x IN group_carrier G
                     ==> (?y. y IN group_carrier G /\ group_zpow G y n = x)) <=>
                coprime(n,&(CARD(group_carrier G))))

  FINITE_GROUP_ZROOT_EXISTS =
    |- !G n x.
           FINITE(group_carrier G) /\
           coprime(n,&(CARD(group_carrier G))) /\
           x IN group_carrier G
           ==> (?y. y IN group_carrier G /\ group_zpow G y n = x)

  GROUP_INV_EQ =
    |- !G x y.
           x IN group_carrier G /\ y IN group_carrier G
           ==> (group_inv G x = group_inv G y <=> x = y)

  GROUP_POW_CANCEL =
    |- !G n x y.
           FINITE(group_carrier G) /\
           coprime(n,CARD(group_carrier G)) /\
           x IN group_carrier G /\
           y IN group_carrier G /\
           group_pow G x n = group_pow G y n
           ==> x = y

  GROUP_ZPOW_CANCEL =
    |- !G n x y.
           FINITE(group_carrier G) /\
           coprime(n,&(CARD(group_carrier G))) /\
           x IN group_carrier G /\
           y IN group_carrier G /\
           group_zpow G x n = group_zpow G y n
           ==> x = y

Thu 14th May 2020       Library/grouptheory.ml

Fixed a trivial error where GROUP_ISOMORPHISM_EQ_EPIMORPHISM_FINITE was
in fact a duplicate of GROUP_ISOMORPHISM_EQ_MONOMORPHISM_FINITE, not proving
what it was supposed to prove. Now:

  GROUP_ISOMORPHISM_EQ_EPIMORPHISM_FINITE
    |- !G H f.
         FINITE (group_carrier G) /\
         FINITE (group_carrier H) /\
         CARD(group_carrier G) = CARD(group_carrier H)
         ==> (group_isomorphism (G,H) f <=> group_epimorphism (G,H) f)

Wed 13th May 2020       arith.ml, Library/prime.ml

Added a few simple but nice rewrites to map between bounded quantifiers
are "modularized" ones:

  EXISTS_LT_MOD_THM =
    |- !P n. (?a. a < n /\ P a) <=> ~(n = 0) /\ (?a. P (a MOD n))

  EXISTS_MOD_THM =
    |- !P n. ~(n = 0) ==> ((?a. P (a MOD n)) <=> (?a. a < n /\ P a))

  FORALL_LT_MOD_THM =
    |- !P n. (!a. a < n ==> P a) <=> n = 0 \/ (!a. P (a MOD n))

  FORALL_MOD_THM =
    |- !P n. ~(n = 0) ==> ((!a. P (a MOD n)) <=> (!a. a < n ==> P a))

and some "if and only if" variants of cancellability in congruences
asserting that it is actually equivalent to coprimality:

  CONG_MULT_LCANCEL_IFF =
    |- !a n.
           ~(n = 0)
           ==> ((!x y. (a * x == a * y) (mod n) ==> (x == y) (mod n)) <=>
                coprime(a,n))

  CONG_MULT_RCANCEL_IFF =
    |- !a n.
           ~(n = 0)
           ==> ((!x y. (x * a == y * a) (mod n) ==> (x == y) (mod n)) <=>
                coprime(a,n))

  COPRIME_DIVPROD_IFF =
    |- !d a.
           ~(d = 0)
           ==> ((!b. d divides a * b ==> d divides b) <=> coprime(d,a))

Tue 12th May 2020       Library/pocklington.ml, Library/multiplicative.ml

Added three more natural lemmas about "squarefree" (the last one indeed
being another characterization of it):

  SQUAREFREE_DECOMPOSITION =
    |- !n. ?m r. squarefree m /\ m * r EXP 2 = n

  SQUAREFREE_EXPAND =
    |- !n. squarefree n ==> nproduct {p | prime p /\ p divides n} (\p. p) = n

  SQUAREFREE_EXPAND_EQ =
    |- !n. squarefree n <=>
           ~(n = 0) /\ nproduct {p | prime p /\ p divides n} (\p. p) = n

and also changed the definition of the Moebius function "mobius" in
"Library/multiplicative.ml" to use the concept "squarefree" explicitly,
streamlining some proofs in the process. Kept the former "expanded"
definition as a new theorem:

  MOBIUS_ALT =
    |- !n. mobius n =
           if ?p. prime p /\ p EXP 2 divides n then &0
           else -- &1 pow CARD {p | prime p /\ p divides n}

Mon 11th May 2020       Library/prime.ml

Added two versions of prime factorization with "bare hands" proofs, not even
assuming trivial lemmas about "nproduct". It seemed silly that previously one
had to get this very basic fact by expanding MULTIPLICATIVE_ID and so pulling
in additional dependencies.

  PRIME_FACTORIZATION =
    |- !n. ~(n = 0)
           ==> nproduct {p | prime p /\ p divides n} (\p. p EXP index p n) = n

  PRIME_FACTORIZATION_ALT =
    |- !n. ~(n = 0) ==> nproduct {p | prime p} (\p. p EXP index p n) = n

Sat  9th May 2020       Library/bitmatch.ml [new file]

Added a new library from Mario Carneiro supporting "bit matches" of the kind
often found in machine instruction decoding where words are decomposed into
bitfields for casewise matching. This not only supports parsing and printing
of such expressions with intuitive syntax

 `bitmatch w:int32 with
    [sf; op; S; 0b100010:6; sh; imm12:12; Rn:5; Rd:5] -> Rn
  | [sf; op; S; 0b01011000:8; Rm:5; 0:6; Rn:5; Rd:5] -> Rn`;;

but also provides efficient proof tools for manipulating such expressions, e.g.
bm_seq_numeral

 # bm_seq_numeral
   `bitmatch w:byte with
      [hi3:3; 0b00:2; lo3:3] -> foo hi3 lo3
    | [hi3:3; 0b1:1; lo4:4]  -> bar hi3 lo4
    | [0b1010101:7; b]       -> baz b`
    (Int 17);;

 val it : term * thm =
  (`word 17`,
   |- (bitmatch word 17 with
        [hi3:3; 0:2; lo3:3] -> foo hi3 lo3
      | [hi3:3; 1:1; lo4:4] -> bar hi3 lo4
      | [85:7; b] -> baz b) =
      bar (word 0) (word 1))

and BITMATCH_SEQ_CONV:

 # BITMATCH_SEQ_CONV
    `bitmatch (word 289406645 :int32) with
       [sf; op; S; 0b100010:6; sh; imm12:12; Rn:5; Rd:5] -> Rn
     | [sf; op; S; 0b01011000:8; Rm:5; 0:6; Rn:5; Rd:5] -> Rn`;;

  val it : thm =
  |- (bitmatch word 289406645 with
       [sf; op; S; 34:6; sh; imm12:12; Rn:5; Rd:5] -> Rn
     | [sf; op; S; 88:8; Rm:5; 0:6; Rn:5; Rd:5] -> Rn) =
     word 21

Sat  9th May 2020       Library/words.ml

Added two new tranches of material for word-like computation with natural
numbers, all from Mario Carneiro. They are installed in the machine words
theory since that is the intended application domain, but they are in fact
largely separate from the actual type. The new material  includes two new
constants "numbit" (analogous to "bit" but over :num not :N word) and
"num_shift_add" (for decomposing numerals along powers of 2):

  numbit =
    |- !n i. numbit i n <=> ODD(n DIV 2 EXP i)

  num_shift_add =
    |- !a b n. num_shift_add a b n = a MOD 2 EXP n + b * 2 EXP n

together with additional lemmas:

  num_shift_add_0 =
    |- num_shift_add a b 0 = b

  num_shift_add_SUC =
    |- num_shift_add (BIT0 a) b (SUC n) = BIT0 (num_shift_add a b n) /\
       num_shift_add (BIT1 a) b (SUC n) = BIT1 (num_shift_add a b n)

  num_shift_add_lt =
    |- !a b n i. b < 2 EXP i ==> num_shift_add a b n < 2 EXP (i + n)

  num_shift_add_mod =
    |- num_shift_add a (b MOD 2 EXP i) n =
       num_shift_add a b n MOD 2 EXP (i + n)

and supporting proof tools

  BIT_PRED
  NUMBIT_CONV
  NUM_SHIFT_ADD_CORE
  NUM_SHIFT_ADD_CONV

Sat  9th May 2020       arith.ml, calc_num.ml

Added a few more simple handy lemmas (from Mario Carneiro)

  BIT0_0 =
    |- BIT0 0 = 0

  BIT1_0 =
    |- BIT1 0 = 1

  EXP_2_NE_0 =
    |- !n. ~(2 EXP n = 0)

  MOD_DIV_EQ_0 =
    |- !m n. ~(n = 0) ==> (m MOD n) DIV n = 0

Sat 18th Apr 2020       Library/grouptheory.ml

Added a number of new group theory results, some plugging routine
gaps, others additional simple Sylow corollaries or other p-group facts
like the Frattini argument (PGROUP_FRATTINI):

  CARD_EQ_LEFT_RIGHT_COSETS =
    |- !G h.
           h subgroup_of G
           ==> {left_coset G x h | x | x IN group_carrier G} =_c
               {right_coset G h x | x | x IN group_carrier G}

  COUNT_FINITE_CYCLIC_GROUP_SUBGROUPS_ALL =
    |- !G. FINITE (group_carrier G) /\ cyclic_group G
           ==> CARD {h | h subgroup_of G} =
               CARD {d | d divides CARD (group_carrier G)}

  GROUP_CENTRALIZER_SUBGROUP_GENERATED =
    |- !G h s.
           s SUBSET h /\ h subgroup_of G
           ==> group_centralizer (subgroup_generated G h) s =
               h INTER group_centralizer G s

  GROUP_NORMALIZER_SUBGROUP_GENERATED =
    |- !G h s.
           s SUBSET h /\ h subgroup_of G
           ==> group_normalizer (subgroup_generated G h) s =
               h INTER group_normalizer G s

  GROUP_SETINV_AS_IMAGE =
    |- !G. group_setinv G = IMAGE (group_inv G)

  GROUP_SETINV_LEFT_COSET_GEN =
    |- !G h a.
           h subgroup_of G /\ a IN group_carrier G
           ==> group_setinv G (left_coset G a h) =
               right_coset G h (group_inv G a)

  GROUP_SETINV_RIGHT_COSET_GEN =
    |- !G h a.
           h subgroup_of G /\ a IN group_carrier G
           ==> group_setinv G (right_coset G h a) =
               left_coset G (group_inv G a) h

  LAGRANGE_THEOREM_LEFT_DIV =
    |- !G h.
           FINITE (group_carrier G) /\ h subgroup_of G
           ==> CARD {left_coset G x h | x | x IN group_carrier G} =
               CARD (group_carrier G) DIV CARD h

  LAGRANGE_THEOREM_RIGHT_DIV =
    |- !G h.
           FINITE (group_carrier G) /\ h subgroup_of G
           ==> CARD {right_coset G h x | x | x IN group_carrier G} =
               CARD (group_carrier G) DIV CARD h

  PGROUP_DIVIDES_NORMALIZER_QUOTIENT =
    |- !G p k h.
           FINITE (group_carrier G) /\
           prime p /\
           h subgroup_of G /\
           CARD h = p EXP k /\
           p divides CARD (group_carrier G) DIV CARD h
           ==> p divides CARD (group_normalizer G h) DIV CARD h

  PGROUP_FRATTINI =
    |- !G p k h j.
           prime p /\
           FINITE j /\
           j normal_subgroup_of G /\
           h SUBSET j /\
           h subgroup_of G /\
           index p (CARD j) = k /\
           CARD h = p EXP k
           ==> group_setmul G (group_normalizer G h) j = group_carrier G

  PGROUP_GEN =
    |- !G Q.
           FINITE (group_carrier G)
           ==> ((!x p.
                     x IN group_carrier G /\
                     prime p /\
                     p divides group_element_order G x
                     ==> Q p) <=>
                (!p. prime p /\ p divides CARD (group_carrier G) ==> Q p))

  PGROUP_MAXIMAL_NORMAL_SUBGROUP_OF =
    |- !G p k h.
           FINITE (group_carrier G) /\
           prime p /\
           CARD (group_carrier G) = p EXP k /\
           h subgroup_of G /\
           (!h'. h' subgroup_of G /\ h PSUBSET h' ==> h' = group_carrier G)
           ==> h normal_subgroup_of G

  PGROUP_NONTRIVIAL_CENTRE =
    |- !G p k.
           prime p /\ ~(k = 0) /\ group_carrier G HAS_SIZE p EXP k
           ==> {group_id G} PSUBSET group_centralizer G (group_carrier G)

  PGROUP_NONTRIVIAL_CENTRE_GEN =
    |- !G n p k.
           prime p /\
           group_carrier G HAS_SIZE p EXP k /\
           n normal_subgroup_of G /\
           ~(n = {group_id G})
           ==> {group_id G} PSUBSET
               group_centralizer G (group_carrier G) INTER n

  PGROUP_NORMALIZER_NORMALIZER =
    |- !G p k h.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD (group_carrier G)) = k /\
           h subgroup_of G /\
           CARD h = p EXP k
           ==> group_normalizer G (group_normalizer G h) = group_normalizer G h

  PGROUP_SELF_NORMALIZER =
    |- !G p k s h.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD (group_carrier G)) = k /\
           s subgroup_of G /\
           CARD s = p EXP k /\
           h subgroup_of G /\
           group_normalizer G s SUBSET h
           ==> group_normalizer G h = h

  PGROUP_SUBGROUP_PSUBSET_NORMALIZER =
    |- !G p k h.
           FINITE (group_carrier G) /\
           prime p /\
           CARD (group_carrier G) = p EXP k /\
           h subgroup_of G /\
           ~(h = group_carrier G)
           ==> h PSUBSET group_normalizer G h

  SYLOW_THEOREM_NORMAL_UNIQUE =
    |- !G p k h h'.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD (group_carrier G)) = k /\
           h normal_subgroup_of G /\
           CARD h = p EXP k
           ==> (h' subgroup_of G /\ CARD h' = p EXP k <=> h' = h)

  SYLOW_THEOREM_NORMAL_UNIQUE_EQ =
    |- !G p k h.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD (group_carrier G)) = k /\
           h subgroup_of G /\
           CARD h = p EXP k
           ==> ((!h'. h' subgroup_of G /\ CARD h' = p EXP k <=> h' = h) <=>
                h normal_subgroup_of G)

  SYLOW_THEOREM_PGROUP_SUPERSET =
    |- !G p k h.
           FINITE (group_carrier G) /\
           prime p /\
           h subgroup_of G /\
           CARD h = p EXP k
           ==> (?h'. h' subgroup_of G /\
                     h SUBSET h' /\
                     CARD h' = p EXP index p (CARD (group_carrier G)))

  SYLOW_THEOREM_UNIQUE =
    |- !G p k.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD (group_carrier G)) = k
           ==> ((?!h. h subgroup_of G /\ CARD h = p EXP k) <=>
                (?h. h normal_subgroup_of G /\ CARD h = p EXP k))

Thu 16th Apr 2020       Library/card.ml

Added a few natural lemmas about cardinal comparison and preimages:

  CARD_EQ_PREIMAGE =
   |- !f s t.
         (!x y.
              x IN s /\ y IN s /\ f x IN t /\ f y IN t /\ f x = f y
              ==> x = y) /\
         t SUBSET IMAGE f s
         ==> {x | x IN s /\ f x IN t} =_c t

  CARD_GE_PREIMAGE =
    |- !f s t. t SUBSET IMAGE f s ==> t <=_c {x | x IN s /\ f x IN t}

  CARD_LE_PREIMAGE
   |- !f s t.
         (!x y.
              x IN s /\ y IN s /\ f x IN t /\ f y IN t /\ f x = f y
              ==> x = y)
         ==> {x | x IN s /\ f x IN t} <=_c t

Tue 14th Apr 2020       Library/pocklington.ml

Added a definition of "square-free" natural numbers with several different
characterizations and a few useful lemmas:

  squarefree =
    |- !n. squarefree n <=> (!m. m EXP 2 divides n ==> m = 1)

  PRIME_IMP_SQUAREFREE =
    |- !p. prime p ==> squarefree p

  SQUAREFREE_0 =
    |- ~squarefree 0

  SQUAREFREE_1 =
    |- squarefree 1

  SQUAREFREE_COPRIME =
    |- !n. squarefree n <=> (!a b. a * b = n ==> coprime(a,b))

  SQUAREFREE_COPRIME_DIVISORS =
    |- !n. squarefree n <=> (!a b. a * b divides n ==> coprime(a,b))

  SQUAREFREE_DIVISOR =
    |- !m n. squarefree n /\ m divides n ==> squarefree m

  SQUAREFREE_EXP =
    |- !n k. squarefree(n EXP k) <=> n = 1 \/ k = 0 \/ squarefree n /\ k = 1

  SQUAREFREE_IMP_NZ =
    |- !n. squarefree n ==> ~(n = 0)

  SQUAREFREE_INDEX =
    |- !n. squarefree n <=> ~(n = 0) /\ (!m. index m n <= 1)

  SQUAREFREE_MUL =
    |- !m n.
          squarefree(m * n) <=>
          coprime(m,n) /\ squarefree m /\ squarefree n

  SQUAREFREE_NPRODUCT =
    |- !s. FINITE s
          ==> (squarefree(nproduct s (\n. n)) <=>
               pairwise (\a b. coprime(a,b)) s /\
               (!n. n IN s ==> squarefree n))

  SQUAREFREE_PRIME =
    |- !n. squarefree n <=> (!p. prime p ==> ~(p EXP 2 divides n))

  SQUAREFREE_PRIME_DIVISOR =
    |- !n. squarefree n <=>
           (!p. prime p /\ p divides n ==> ~(p EXP 2 divides n))

  SQUAREFREE_PRIME_INDEX =
    |- !n. squarefree n <=> ~(n = 0) /\ (!p. prime p ==> index p n <= 1)

Mon 13th Apr 2020       Library/words.ml

Added a few more simple machine word lemmas:

  VAL_EQ_MAX =
   |- !x. val x = 2 EXP dimindex(:N) - 1 <=> word_not x = word 0

  VAL_EQ_MAX_ALT =
    |- !x. val x = 2 EXP dimindex(:N) - 1 <=> x = word_not (word 0)

  VAL_WORD_AND_EQ_MAX =
   |- !x y.
           val(word_and x y) = 2 EXP dimindex(:N) - 1 <=>
           val x = 2 EXP dimindex(:N) - 1 /\ val y = 2 EXP dimindex(:N) - 1

  VAL_WORD_OR_EQ_0 =
    |- !x y. val(word_or x y) = 0 <=> val x = 0 /\ val y = 0

Sat 11th Apr 2020       Library/grouptheory.ml, Library/modmul_group.ml

Added proofs of the Sylow theorems in a reasonably general form; the
core SYLOW_THEOREM_COUNT_MOD is a Frobenius generalization following
from approximately the usual Wielandt-style proof, modelled on the
presentation here

  https://people.bath.ac.uk/dmjc20/GpThy/wiel.pdf

while the conjugacy part also has a generalized (though easy to prove) form
SYLOW_THEOREM_CONJUGATE_GEN taken from Rose's "A Course on Group Theory"
(theorem 5.4, p89).

Added more miscellaneous group theory machinery, some of it in support
of the Sylow proofs, and as part of the latest additions, gave up the
losing battle to avoid including the number-theory lemma library from
"Library/prime.ml", and so at least was able to move some lemmas on
the order of group elements back out of "Library/modmul_group.ml" to
where they more naturally belong. New theorems:

  CARD_CONJUGATE_SUBSETS =
    |- !G s.
           FINITE (group_carrier G) /\ s SUBSET group_carrier G
           ==> CARD {t | group_conjugate G s t} =
               CARD(group_carrier G) DIV CARD(group_normalizer G s)

  CARD_CONJUGATE_SUBSETS_MUL =
    |- !G s.
           FINITE (group_carrier G) /\ s SUBSET group_carrier G
           ==> CARD {t | group_conjugate G s t} * CARD(group_normalizer G s) =
               CARD(group_carrier G)

  CARD_CONJUGATE_SUBSETS_MUL_GEN =
    |- !G s.
           s SUBSET group_carrier G
           ==> {t | group_conjugate G s t} *_c group_normalizer G s =_c
               group_carrier G

  CAUCHY_GROUP_THEOREM =
    |- !G p.
           FINITE (group_carrier G) /\
           prime p /\
           p divides CARD(group_carrier G)
           ==> (?x. x IN group_carrier G /\ group_element_order G x = p)

  COPRIME_GROUP_ORDER =
    |- !G n.
           FINITE (group_carrier G)
           ==> ((!x. x IN group_carrier G
                     ==> coprime(group_element_order G x,n)) <=>
                coprime(CARD(group_carrier G),n))

  COUNT_FINITE_CYCLIC_GROUP_SUBGROUPS =
    |- !G d.
         FINITE (group_carrier G) /\ cyclic_group G
         ==> CARD {h | h subgroup_of G /\ CARD h = d} =
             (if d divides CARD(group_carrier G) then 1 else 0)

  FINITE_GROUP_CENTRALIZER =
    |- !G s. FINITE (group_carrier G) ==> FINITE (group_centralizer G s)

  FINITE_GROUP_NORMALIZER =
    |- !G s. FINITE (group_carrier G) ==> FINITE (group_normalizer G s)

  FINITE_RESTRICTED_SUBGROUPS =
    |- !P G. FINITE (group_carrier G) ==> FINITE {h | h subgroup_of G /\ P h}

  FINITE_SUBGROUPS =
    |- !G. FINITE (group_carrier G) ==> FINITE {h | h subgroup_of G}

  GROUP_CENTRALIZER_NONEMPTY =
    |- !G s. ~(group_centralizer G s = {})

  GROUP_ID_IN_LEFT_COSET =
    |- !G h x.
         h subgroup_of G /\ x IN group_carrier G
         ==> (group_id G IN left_coset G x h <=> x IN h)

  GROUP_ID_IN_LEFT_COSET_GEN =
   |- !G h x.
         h SUBSET group_carrier G /\ x IN group_carrier G
         ==> (group_id G IN left_coset G x h <=> group_inv G x IN h)

  GROUP_ID_IN_RIGHT_COSET =
    |- !G h x.
         h subgroup_of G /\ x IN group_carrier G
         ==> (group_id G IN right_coset G h x <=> x IN h)

  GROUP_ID_IN_RIGHT_COSET_GEN =
    |- !G h x.
         h SUBSET group_carrier G /\ x IN group_carrier G
         ==> (group_id G IN right_coset G h x <=> group_inv G x IN h)

  GROUP_NORMALIZER_NONEMPTY =
    |- !G s. ~(group_normalizer G s = {})

  GROUP_ORBIT_COMMON_DIVISOR =
    |- !G s a n.
           group_action G s a /\
           FINITE s /\
           (!x. x IN s ==> n divides CARD(group_orbit G s a x))
           ==> n divides CARD s

  GROUP_ORBIT_COMMON_INDEX =
    |- !G s a p k.
           group_action G s a /\
           FINITE s /\
           (s = {} ==> k = 0) /\
           (!x. x IN s ==> k <= index p (CARD(group_orbit G s a x)))
           ==> k <= index p (CARD s)

  GROUP_POW_EQ =
    |- !G x m n.
           x IN group_carrier G
           ==> (group_pow G x m = group_pow G x n <=>
                (m == n) (mod group_element_order G x))

  GROUP_SETINV_MONO =
    |- !G s s'. s SUBSET s' ==> group_setinv G s SUBSET group_setinv G s'

  GROUP_SETMUL_INC =
    |- (!G s t.
            s subgroup_of G /\ t subgroup_of G
            ==> t SUBSET group_setmul G s t) /\
       (!G s t.
            s subgroup_of G /\ t subgroup_of G
            ==> s SUBSET group_setmul G s t)

  GROUP_SETMUL_INC_GEN =
    |- (!G s t.
            group_id G IN s /\ t SUBSET group_carrier G
            ==> t SUBSET group_setmul G s t) /\
       (!G s t.
            s SUBSET group_carrier G /\ group_id G IN t
            ==> s SUBSET group_setmul G s t)

  GROUP_SETMUL_MONO =
    |- !G s t s' t'.
           s SUBSET s' /\ t SUBSET t'
           ==> group_setmul G s t SUBSET group_setmul G s' t'

  GROUP_ZPOW_EQ =
    |- !G x m n.
           x IN group_carrier G
           ==> (group_zpow G x m = group_zpow G x n <=>
                (m == n) (mod &(group_element_order G x)))

  GROUP_ZPOW_EQ_ALT =
    |- !G x m n.
           x IN group_carrier G
           ==> (group_zpow G x m = group_zpow G x n <=>
                &(group_element_order G x) divides n - m)

  IN_GROUP_CENTRALIZER_ID =
    |- !G s. group_id G IN group_centralizer G s

  IN_GROUP_NORMALIZER_ID =
    |- !G s. group_id G IN group_normalizer G s

  IN_IMAGE_GROUP_CONJUGATION =
    |- !G s x y.
           x IN group_carrier G /\
           y IN group_carrier G /\
           s SUBSET group_carrier G
           ==> (x IN IMAGE (group_conjugation G y) s <=>
                group_conjugation G (group_inv G y) x IN s)

  NORMAL_SUBGROUP_CONJUGATE_EQ =
    |- !G n n'.
         n normal_subgroup_of G \/ n' normal_subgroup_of G
         ==> (group_conjugate G n n' <=> n = n')

  NORMAL_SUBGROUP_CONJUGATE_INV =
    |- !G n.
           n normal_subgroup_of G <=>
           n subgroup_of G /\
           (!x. x IN group_carrier G
                ==> group_setmul G {group_inv G x} (group_setmul G n {x})
                    SUBSET n)

  NORMAL_SUBGROUP_OF_IMP_SUBSET =
    |- !G n. n normal_subgroup_of G ==> n SUBSET group_carrier G

  PGROUP =
    |- !G p.
           FINITE (group_carrier G) /\ prime p
           ==> ((!x. x IN group_carrier G
                     ==> (?k. group_element_order G x = p EXP k)) <=>
                (?k. CARD(group_carrier G) = p EXP k))

  PGROUP_ACTION_FIXPOINT =
    |- !G s a p k.
           group_action G s a /\
           prime p /\
           group_carrier G HAS_SIZE p EXP k /\
           FINITE s /\
           ~(p divides CARD s)
           ==> (?x. x IN s /\ (!g. g IN group_carrier G ==> a g x = x))

  PGROUP_ACTION_FIXPOINTS =
    |- !G s a p k.
           group_action G s a /\
           FINITE s /\
           prime p /\
           group_carrier G HAS_SIZE p EXP k
           ==> (CARD {x | x IN s /\
                          (!g. g IN group_carrier G ==> a g x = x)} ==
                CARD s)
               (mod p)

  PRIME_DIVIDES_GROUP_ORDER =
    |- !G p.
           FINITE (group_carrier G) /\ prime p
           ==> ((?x. x IN group_carrier G /\
                     p divides group_element_order G x) <=>
                p divides CARD(group_carrier G))

  SUBGROUP_OF_FINITE_CYCLIC_GROUP =
    |- !G h a.
         FINITE (group_carrier G) /\
         a IN group_carrier G /\
         subgroup_generated G {a} = G
         ==> (h subgroup_of G <=>
              ?d. d divides CARD(group_carrier G) /\
                  h = group_carrier(subgroup_generated G {group_pow G a d}))

  SUBGROUP_OF_LEFT_COSET =
   |- !G h x.
         h subgroup_of G /\ x IN group_carrier G
         ==> (left_coset G x h subgroup_of G <=> left_coset G x h = h)

  SUBGROUP_OF_RIGHT_COSET =
   |- !G h x.
         h subgroup_of G /\ x IN group_carrier G
         ==> (right_coset G h x subgroup_of G <=> right_coset G h x = h)

  SYLOW_THEOREM =
    |- !G p k.
           FINITE (group_carrier G) /\
           prime p /\
           p EXP k divides CARD(group_carrier G)
           ==> (?h. h subgroup_of G /\ CARD h = p EXP k)

  SYLOW_THEOREM_CONJUGATE =
    |- !G p k h h'.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD(group_carrier G)) = k /\
           h subgroup_of G /\
           CARD h = p EXP k /\
           h' subgroup_of G /\
           CARD h' = p EXP k
           ==> group_conjugate G h h'

  SYLOW_THEOREM_CONJUGATE_ALT =
    |- !G p k h h'.
           FINITE (group_carrier G) /\
           prime p /\
           ~(p EXP (k + 1) divides CARD(group_carrier G)) /\
           h subgroup_of G /\
           CARD h = p EXP k /\
           h' subgroup_of G /\
           CARD h' = p EXP k
           ==> group_conjugate G h h'

  SYLOW_THEOREM_CONJUGATE_EQ =
    |- !G p k h h'.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD(group_carrier G)) = k /\
           h subgroup_of G /\
           CARD h = p EXP k
           ==> (h' subgroup_of G /\ CARD h' = p EXP k <=>
                group_conjugate G h h')

  SYLOW_THEOREM_CONJUGATE_GEN =
    |- !G p k h j.
           prime p /\
           h subgroup_of G /\
           FINITE {left_coset G x h | x | x IN group_carrier G} /\
           ~(p divides CARD {left_coset G x h | x | x IN group_carrier G}) /\
           j subgroup_of G /\
           FINITE j /\
           CARD j = p EXP k
           ==> (?a. a IN group_carrier G /\
                    j SUBSET IMAGE (group_conjugation G a) h)

  SYLOW_THEOREM_CONJUGATE_SUBSET =
    |- !G p k l h j.
           FINITE (group_carrier G) /\
           prime p /\
           ~(p EXP (k + 1) divides CARD(group_carrier G)) /\
           h subgroup_of G /\
           CARD h = p EXP k /\
           j subgroup_of G /\
           CARD j = p EXP l
           ==> (?a. a IN group_carrier G /\
                    j SUBSET IMAGE (group_conjugation G a) h)

  SYLOW_THEOREM_COUNT_DIVISOR =
    |- !G p k.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD(group_carrier G)) = k
           ==> CARD {h | h subgroup_of G /\ CARD h = p EXP k} divides
               CARD(group_carrier G) DIV p EXP k

  SYLOW_THEOREM_COUNT_MOD =
    |- !G p k.
         FINITE (group_carrier G) /\
         prime p /\
         p EXP k divides CARD(group_carrier G)
         ==> (CARD {h | h subgroup_of G /\ CARD h = p EXP k} == 1) (mod p)

  SYLOW_THEOREM_COUNT_NORMALIZER =
    |- !G h p k.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD(group_carrier G)) = k /\
           h subgroup_of G /\
           CARD h = p EXP k
           ==> CARD {h | h subgroup_of G /\ CARD h = p EXP k} =
               CARD(group_carrier G) DIV CARD(group_normalizer G h)

  SYLOW_THEOREM_COUNT_NORMALIZER_MUL =
    |- !G h p k.
           FINITE (group_carrier G) /\
           prime p /\
           index p (CARD(group_carrier G)) = k /\
           h subgroup_of G /\
           CARD h = p EXP k
           ==> CARD {h | h subgroup_of G /\ CARD h = p EXP k} *
               CARD(group_normalizer G h) =
               CARD(group_carrier G)

Renamed the existing NORMAL_SUBGROUP_CONJUGATE (which rather suggests the use
of the "group_conjugate" concept) to NORMAL_SUBGROUP_CONJUGATE_INV, and
renamed GROUP_ZPOW_EQ to GROUP_ZPOW_EQ_ALT, using the original names for:

  GROUP_ZPOW_EQ =
    |- !G x m n.
         x IN group_carrier G
         ==> (group_zpow G x m = group_zpow G x n <=>
              (m == n) (mod &(group_element_order G x)))

  NORMAL_SUBGROUP_CONJUGATE =
    |- !G n.
         n normal_subgroup_of G <=>
         n subgroup_of G /\ (!n'. group_conjugate G n n' ==> n' = n)

and incompatibly improved the existing theorem GROUP_ACTION_FROM_SUBGROUP
by removing the "subgroup" hypothesis, so it's now just:

  GROUP_ACTION_FROM_SUBGROUP =
    |- !G s h a.
          group_action G s a ==> group_action (subgroup_generated G h) s a

Wed  8th Apr 2020       sets.ml, Library/binomial.ml, 100/combinations.ml

Moved the "number of combinations" formula into "Library/binomial.ml" under
these two names:

  HAS_SIZE_RESTRICTED_POWERSET =
    |- !n m s.
         s HAS_SIZE n
         ==> {t | t SUBSET s /\ t HAS_SIZE m} HAS_SIZE binom(n,m)

  CARD_RESTRICTED_POWERSET =
    |- !s k.
         FINITE s
         ==> CARD {t | t SUBSET s /\ t HAS_SIZE k} = binom(CARD s,k)

and also added the following missing general lemma to the core "sets.ml":

  FINITE_RESTRICTED_SUBSETS =
    |- !P s. FINITE s ==> FINITE {t | t SUBSET s /\ P t}

Removed most of the proof in "100/combinations.ml" since it is all either
duplicating stuff in "Library/binomial.ml" or an immediate consequence. Also
removed any "prioritize..." calls from "Library/binomial.ml" to make things
less brittle w.r.t. overloading.

Wed  8th Apr 2020       Library/prime.ml, Library/pocklington.ml

Did some more cleanup and reorganizing around "Library/prime.ml", reordering
and tweaking some proofs, moving these theorems from "Library/pocklington.ml":

        PRIME
        PRIME_PRIME_FACTOR
        PRIME_POWER_EXISTS

Removed the not-very-useful lemma PARITY_EXP (easily subsumed by combining
existing theorems like EVEN_EXP and ARITH_EQ) and added the following; the
first two are handy to avoid too much mess when dealing with cutoff subtraction
over N in the setting of congruences:

  DIVIDES_SUB_EQ =
   |- !d a b. d divides a - b <=> a < b \/ (a == b) (mod d)

  DIVIDES_SUB_1 =
    |- !d n. d divides n - 1 <=> n = 0 \/ (n == 1) (mod d)

  INDEX_FACT_PRIME_MULT =
    |- !p n. prime p ==> index p (FACT (p * n)) = n + index p (FACT n)

  PRIME_ALT =
    |- !p. prime p <=>
           ~(p = 0) /\ ~(p = 1) /\ (!n. 1 < n /\ n < p ==> ~(n divides p))

Sat  4th Apr 2020       itab.ml

Merged a pull request from Ben Lynn, removing a redundant line from the
intuitionistic prover (handling negation, which is already effectively
done by DISCH_TAC).

Sat  4th Apr 2020       Library/grouptheory.ml

Added a further series of definitions and lemmas setting up more basic group
theory machinery: defined the notion of conjugate sets ("group_conjugate"),
normalizer ("group_normalizer") and centralizer ("group_centralizer") with the
obvious elementary lemmas. Also renamed a couple of existing theorems which
seemed poorly named:

  GROUP_ISOMORPHISMS_CONJUNCTION -> GROUP_ISOMORPHISMS_CONJUGATION

  GROUP_ACTION_GROUP_CONJUGATION -> GROUP_ACTION_CONJUGATION

and removed the "abelian" hypothesis from the existing theorem
CARD_GROUP_SETMUL_DIVIDES, as well as providing more general infinitary
versions like CARD_GROUP_SETMUL_GEN. New definitions

  group_centralizer =
    |- !s G.
           group_centralizer G s =
           {x | x IN group_carrier G /\
                !y. y IN group_carrier G /\ y IN s
                    ==> group_mul G x y = group_mul G y x}

  group_conjugate =
    |- !G s t.
           group_conjugate G s t <=>
           s SUBSET group_carrier G /\
           t SUBSET group_carrier G /\
           ?a. a IN group_carrier G /\ IMAGE (group_conjugation G a) s = t

  group_normalizer =
    |- !G s.
           group_normalizer G s =
           {x | x IN group_carrier G /\
                group_setmul G {x} (group_carrier G INTER s) =
                group_setmul G (group_carrier G INTER s) {x}}

and theorems:

  ABELIAN_GROUP_SUBGROUP_GENERATED_GEN =
    |- !G s.
           (!x y.
                x IN group_carrier G /\
                x IN s /\
                y IN group_carrier G /\
                y IN s
                ==> group_mul G x y = group_mul G y x)
           ==> abelian_group (subgroup_generated G s)

  CARD_EQ_GROUP_ORBIT_STABILIZERS =
    |- !G s a x y.
           group_action G s a /\ group_orbit G s a x y
           ==> group_stabilizer G a x =_c group_stabilizer G a y

  CARD_GROUP_SETMUL =
    |- !G g h.
           FINITE g /\ FINITE h /\ g subgroup_of G /\ h subgroup_of G
           ==> CARD(group_setmul G g h) =
               (CARD g * CARD h) DIV CARD(g INTER h)

  CARD_GROUP_SETMUL_GEN =
    |- !G g h.
           g subgroup_of G /\ h subgroup_of G
           ==> group_setmul G g h *_c (g INTER h) =_c g *_c h

  CARD_GROUP_SETMUL_MUL =
    |- !G g h.
           FINITE g /\ FINITE h /\ g subgroup_of G /\ h subgroup_of G
           ==> CARD(group_setmul G g h) * CARD(g INTER h) = CARD g * CARD h

  EXISTS_IN_GROUP_CARRIER_INV =
    |- !P G.
           (?x. x IN group_carrier G /\ P (group_inv G x)) <=>
           (?x. x IN group_carrier G /\ P x)

  FINITE_GROUP_SETMUL =
    |- !G s t. FINITE s /\ FINITE t ==> FINITE (group_setmul G s t)

  GROUP_ACTION_CONJUGATION_NORMAL_SUBGROUP =
    |- !G n. n normal_subgroup_of G ==> group_action G n (group_conjugation G)

  GROUP_ACTION_IMAGE_CONJUGATION =
    |- !G u.
           (!t. t IN u ==> t SUBSET group_carrier G) /\
           (!g t.
                g IN group_carrier G /\ t IN u
                ==> IMAGE (group_conjugation G g) t IN u)
           ==> group_action G u (IMAGE o group_conjugation G)

  GROUP_ACTION_IMAGE_CONJUGATION_CARRIER =
    |- !G. group_action G {s | s SUBSET group_carrier G}
           (IMAGE o group_conjugation G)

  GROUP_ACTION_IMAGE_CONJUGATION_SUBGROUPS =
    |- !G. group_action G {n | n subgroup_of G} (IMAGE o group_conjugation G)

  GROUP_ACTION_KERNEL_POINTWISE =
    |- !G s a.
           {g | g IN group_carrier G /\ (!x. x IN s ==> a g x = x)} =
           (if s = {}
            then group_carrier G
            else INTERS {group_stabilizer G a x | x IN s})

  GROUP_AUTOMORPHISM_IMP_ENDOMORPHISM =
    |- !G f. group_automorphism G f ==> group_endomorphism G f

  GROUP_CENTRALIZER =
    |- !G s.
           s SUBSET group_carrier G
           ==> group_centralizer G s =
               {x | x IN group_carrier G /\
                    (!y. y IN s ==> group_mul G x y = group_mul G y x)}

  GROUP_CENTRALIZER_ALT =
    |- !G s.
           group_centralizer G s =
           {x | x IN group_carrier G /\
                (!y. y IN group_carrier G /\ y IN s
                     ==> group_conjugation G x y = y)}

  GROUP_CENTRALIZER_CENTRALIZER_SUBSET =
    |- !G s.
           s SUBSET group_centralizer G (group_centralizer G s) <=>
           s SUBSET group_carrier G

  GROUP_CENTRALIZER_GALOIS =
    |- !G s t.
           s SUBSET group_carrier G /\ t SUBSET group_centralizer G s
           ==> s SUBSET group_centralizer G t

  GROUP_CENTRALIZER_GALOIS_EQ =
    |- !G s t.
           s SUBSET group_carrier G /\ t SUBSET group_carrier G
           ==> (s SUBSET group_centralizer G t <=>
                t SUBSET group_centralizer G s)

  GROUP_CENTRALIZER_MONO =
    |- !G s t.
           s SUBSET t ==> group_centralizer G t SUBSET group_centralizer G s

  GROUP_CENTRALIZER_POINTWISE =
    |- !G s.
           group_centralizer G s =
           (if s = {}
            then group_carrier G
            else INTERS {group_centralizer G {x} | x IN s})

  GROUP_CENTRALIZER_RESTRICT =
    |- !G s.
           group_centralizer G s =
           group_centralizer G (group_carrier G INTER s)

  GROUP_CENTRALIZER_SUBSET =
    |- !G s.
           s SUBSET group_centralizer G s <=>
           s SUBSET group_carrier G /\
           (!a b. a IN s /\ b IN s ==> group_mul G a b = group_mul G b a)

  GROUP_CENTRALIZER_SUBSET_CARRIER =
    |- !G s. group_centralizer G s SUBSET group_carrier G

  GROUP_CENTRALIZER_SUBSET_EQ =
    |- !g h.
           h subgroup_of G
           ==> (h SUBSET group_centralizer G h <=>
                abelian_group (subgroup_generated G h))

  GROUP_CENTRALIZER_SUBSET_NORMALIZER =
    |- !G s. group_centralizer G s SUBSET group_normalizer G s

  GROUP_CENTRE_EQ_CARRIER =
    |- !G. group_centralizer G (group_carrier G) = group_carrier G <=>
           abelian_group G

  GROUP_CONJUGATE_IMP_CARD_EQ =
    |- !G s t. group_conjugate G s t ==> s =_c t

  GROUP_CONJUGATE_IMP_ISOMORPHIC =
    |- !G s t.
           group_conjugate G s t
           ==> subgroup_generated G s isomorphic_group subgroup_generated G t

  GROUP_CONJUGATE_NORMAL_SUBGROUP_OF =
    |- !G s t.
           group_conjugate G s t
           ==> (s normal_subgroup_of G <=> t normal_subgroup_of G)

  GROUP_CONJUGATE_REFL =
    |- !G s. group_conjugate G s s <=> s SUBSET group_carrier G

  GROUP_CONJUGATE_SUBGROUPS_GENERATED =
    |- !G s t.
           group_conjugate G s t
           ==> group_conjugate G (group_carrier(subgroup_generated G s))
               (group_carrier(subgroup_generated G t))

  GROUP_CONJUGATE_SUBGROUP_OF =
    |- !G s t. group_conjugate G s t ==> (s subgroup_of G <=> t subgroup_of G)

  GROUP_CONJUGATE_SYM =
    |- !G s t. group_conjugate G s t <=> group_conjugate G t s

  GROUP_CONJUGATE_TRANS =
    |- !G s t u.
           group_conjugate G s t /\ group_conjugate G t u
           ==> group_conjugate G s u

  GROUP_CONJUGATION_EQ =
    |- !G a x y.
           a IN group_carrier G /\ x IN group_carrier G /\ y IN group_carrier G
           ==> (group_conjugation G a x = group_conjugation G a y <=> x = y)

  GROUP_CONJUGATION_SUBGROUP_GENERATED =
    |- !G s. group_conjugation (subgroup_generated G s) = group_conjugation G

  GROUP_HOMOMORPHISM_CONJUGATION =
    |- !G a.
           a IN group_carrier G
           ==> group_homomorphism (G,G) (group_conjugation G a)

  GROUP_ISOMORPHISM_CONJUGATION =
    |- !G a.
           a IN group_carrier G
           ==> group_isomorphism (G,G) (group_conjugation G a)

  GROUP_NORMALIZER =
    |- !G s.
           s SUBSET group_carrier G
           ==> group_normalizer G s =
               {x | x IN group_carrier G /\
                    group_setmul G {x} s = group_setmul G s {x}}

  GROUP_NORMALIZER_CONJUGATION =
    |- !G s.
           s SUBSET group_carrier G
           ==> group_normalizer G s =
               {x | x IN group_carrier G /\ IMAGE (group_conjugation G x) s = s}

  GROUP_NORMALIZER_CONJUGATION_EQ =
    |- !G s.
           group_normalizer G s =
           {x | x IN group_carrier G /\
                IMAGE (group_conjugation G x) (group_carrier G INTER s) =
                group_carrier G INTER s}

  GROUP_NORMALIZER_FINITE =
    |- !G s.
           s SUBSET group_carrier G /\ FINITE s
           ==> group_normalizer G s =
               {x | x IN group_carrier G /\
                    IMAGE (group_conjugation G x) s SUBSET s}

  GROUP_NORMALIZER_MAXIMAL =
    |- !G h n.
           n subgroup_of G
           ==> (h normal_subgroup_of subgroup_generated G n <=>
                h subgroup_of G /\ h SUBSET n /\ n SUBSET group_normalizer G h)

  GROUP_NORMALIZER_MAXIMAL_GEN =
    |- !G h n.
           h normal_subgroup_of subgroup_generated G n <=>
           h subgroup_of subgroup_generated G n /\
           group_carrier G INTER n SUBSET group_normalizer G h

  GROUP_NORMALIZER_RESTRICT =
    |- !G s.
           group_normalizer G s = group_normalizer G (group_carrier G INTER s)

  GROUP_NORMALIZER_SING =
    |- !G a. group_normalizer G {a} = group_centralizer G {a}

  GROUP_NORMALIZER_SUBSET =
    |- !G h. h subgroup_of G ==> h SUBSET group_normalizer G h

  GROUP_NORMALIZER_SUBSET_CARRIER =
    |- !G s. group_normalizer G s SUBSET group_carrier G

  GROUP_ORBIT_CONJUGATE_STABILIZERS =
    |- !G s a x y.
           group_action G s a /\ group_orbit G s a x y
           ==> group_conjugate G (group_stabilizer G a x)
               (group_stabilizer G a y)

  GROUP_ORBIT_CONJUGATION =
    |- !G x.
           group_orbit G (group_carrier G) (group_conjugation G) x =
           (if x IN group_carrier G
            then {y | y IN group_carrier G /\ group_conjugate G {x} {y}}
            else {})

  GROUP_ORBIT_CONJUGATION_GEN =
    |- !G s x.
           s SUBSET group_carrier G
           ==> group_orbit G s (group_conjugation G) x =
               (if x IN s
                then {y | y IN s /\ group_conjugate G {x} {y}}
                else {})

  GROUP_ORBIT_EQ_SING =
    |- !G s a x y.
           group_action G s a
           ==> (group_orbit G s a y = {x} <=>
                x IN s /\ y = x /\ (!g. g IN group_carrier G ==> a g x = x))

  GROUP_ORBIT_EQ_SING_SELF =
    |- !G s a x.
           group_action G s a
           ==> (group_orbit G s a x = {x} <=>
                x IN s /\ (!g. g IN group_carrier G ==> a g x = x))

  GROUP_ORBIT_HAS_SIZE_1 =
    |- !G s a x.
           group_action G s a
           ==> (group_orbit G s a x HAS_SIZE 1 <=>
                x IN s /\ (!g. g IN group_carrier G ==> a g x = x))

  GROUP_ORBIT_IMAGE_CONJUGATION =
    |- !G. group_orbit G {s | s SUBSET group_carrier G}
           (IMAGE o group_conjugation G) =
           group_conjugate G

  GROUP_ORBIT_IMAGE_CONJUGATION_GEN =
    |- !G u s.
           (!t. t IN u ==> t SUBSET group_carrier G) /\ s IN u
           ==> group_orbit G u (IMAGE o group_conjugation G) s =
               (\t. t IN u /\ group_conjugate G s t)

  GROUP_ORBIT_ON_SUBSET =
    |- !G s t a.
           t SUBSET s /\ x IN t
           ==> group_orbit G t a x = t INTER group_orbit G s a x

  GROUP_SETMUL_EMPTY =
    |- (!G s. group_setmul G s {} = {}) /\ (!G t. group_setmul G {} t = {})

  GROUP_SETMUL_SYM_ELEMENTWISE =
    |- !G s t u.
           (!a. a IN s ==> group_setmul G {a} t = group_setmul G u {a})
           ==> group_setmul G s t = group_setmul G u s

  GROUP_STABILIZER_CONJUGATION =
    |- !G a.
           a IN group_carrier G
           ==> group_stabilizer G (group_conjugation G) a =
               group_centralizer G {a}

  GROUP_STABILIZER_IMAGE_CONJUGATION =
    |- !G s.
           s SUBSET group_carrier G
           ==> group_stabilizer G (IMAGE o group_conjugation G) s =
               group_normalizer G s

  GROUP_STABILIZER_OF_ACTION =
    |- !G s a g x.
           group_action G s a /\ g IN group_carrier G /\ x IN s
           ==> group_stabilizer G a (a g x) =
               IMAGE (group_conjugation G g) (group_stabilizer G a x)

  GROUP_STABILIZER_ON_SUBGROUP =
    |- !G h a x.
           h subgroup_of G
           ==> group_stabilizer (subgroup_generated G h) a x =
               h INTER group_stabilizer G a x

  GROUP_STABILIZER_SUBGROUP_GENERATED =
    |- !G h a x.
           group_stabilizer (subgroup_generated G h) a x =
           group_carrier(subgroup_generated G h) INTER group_stabilizer G a x

  IMAGE_GROUP_CONJUGATION_BY_ID =
    |- !G s.
           s SUBSET group_carrier G
           ==> IMAGE (group_conjugation G (group_id G)) s = s

  IMAGE_GROUP_CONJUGATION_BY_INV =
    |- !G a s t.
           a IN group_carrier G /\
           s SUBSET group_carrier G /\
           t SUBSET group_carrier G
           ==> (IMAGE (group_conjugation G (group_inv G a)) s = t <=>
                IMAGE (group_conjugation G a) t = s)

  IMAGE_GROUP_CONJUGATION_BY_MUL =
    |- !G s a b.
           a IN group_carrier G /\
           b IN group_carrier G /\
           s SUBSET group_carrier G
           ==> IMAGE (group_conjugation G (group_mul G a b)) s =
               IMAGE (group_conjugation G a) (IMAGE (group_conjugation G b) s)

  IMAGE_GROUP_CONJUGATION_EQ =
    |- !G a s t.
           a IN group_carrier G /\
           s SUBSET group_carrier G /\
           t SUBSET group_carrier G
           ==> (IMAGE (group_conjugation G a) s = t <=>
                group_setmul G {a} s = group_setmul G t {a})

  IMAGE_GROUP_CONJUGATION_EQ_PREIMAGE =
    |- !G a s t.
           a IN group_carrier G /\
           s SUBSET group_carrier G /\
           t SUBSET group_carrier G
           ==> (IMAGE (group_conjugation G a) s = t <=>
                {x | x IN group_carrier G /\ group_conjugation G a x IN t} = s)

  IMAGE_GROUP_CONJUGATION_EQ_SWAP =
    |- !G a s t.
           a IN group_carrier G /\
           s SUBSET group_carrier G /\
           t SUBSET group_carrier G /\
           IMAGE (group_conjugation G (group_inv G a)) s = t
           ==> IMAGE (group_conjugation G a) t = s

  IMAGE_GROUP_CONJUGATION_SUBGROUP =
    |- !G h a.
           h subgroup_of G /\ a IN h ==> IMAGE (group_conjugation G a) h = h

  IMAGE_GROUP_CONJUGATION_SUBSET =
    |- !G a s.
           a IN group_carrier G /\ s SUBSET group_carrier G
           ==> IMAGE (group_conjugation G a) s SUBSET group_carrier G

  IN_GROUP_ORBIT =
    |- !G s a x y.
           y IN group_orbit G s a x <=>
           x IN s /\ y IN s /\ (?g. g IN group_carrier G /\ a g x = y)

  IN_SUBGROUP_CONJUGATION =
    |- !G h a x.
           h subgroup_of G /\ a IN h /\ x IN h ==> group_conjugation G a x IN h

  NORMAL_SUBGROUP_ACTION_KERNEL =
    |- !G s a.
           group_action G s a
           ==> {g | g IN group_carrier G /\ (!x. x IN s ==> a g x = x)}
               normal_subgroup_of G

  NORMAL_SUBGROUP_CENTRALIZER =
    |- !G n.
           n normal_subgroup_of G
           ==> group_centralizer G n normal_subgroup_of G

  NORMAL_SUBGROUP_CENTRALIZER_NORMALIZER =
    |- !G h.
           group_centralizer G h normal_subgroup_of
           subgroup_generated G (group_normalizer G h)

  NORMAL_SUBGROUP_NORMALIZER_CONTAINS_CARRIER =
    |- !G n.
           n normal_subgroup_of G <=>
           n subgroup_of G /\ group_carrier G SUBSET group_normalizer G n

  NORMAL_SUBGROUP_NORMALIZER_EQ_CARRIER =
    |- !G n.
           n normal_subgroup_of G <=>
           n subgroup_of G /\ group_normalizer G n = group_carrier G

  NORMAL_SUBGROUP_OF_INTER =
    |- !G g h.
           g normal_subgroup_of G /\ h normal_subgroup_of G
           ==> g INTER h normal_subgroup_of G

  NORMAL_SUBGROUP_OF_INTERS =
    |- !G gs.
           (!g. g IN gs ==> g normal_subgroup_of G) /\ ~(gs = {})
           ==> INTERS gs normal_subgroup_of G

  NORMAL_SUBGROUP_OF_NORMALIZER =
    |- !G h.
           h normal_subgroup_of subgroup_generated G (group_normalizer G h) <=>
           h subgroup_of G

  NSUM_CARD_GROUP_ORBITS =
    |- !G s a.
           group_action G s a /\ FINITE s
           ==> nsum {group_orbit G s a x | x | x IN s} CARD = CARD s

  SUBGROUP_GENERATED_MINIMAL_EQ =
    |- !G h s.
           h subgroup_of G
           ==> (group_carrier(subgroup_generated G s) SUBSET h <=>
                group_carrier G INTER s SUBSET h)

  SUBGROUP_GROUP_CENTRALIZER =
    |- !G s. group_centralizer G s subgroup_of G

  SUBGROUP_GROUP_NORMALIZER =
    |- !G s. group_normalizer G s subgroup_of G

Sat 28th Mar 2020       Library/grouptheory.ml

Added a systematic series of basic definitions and lemmas about conjugation and
about group actions, together with orbits and stabilizers. As a small and
slightly gratuitous application, re-derived the Lagrange theorem as an instance
of orbit-stabilizer. New definitions and theorems:

  group_action =
    |- !s G a.
           group_action G s a <=>
           (!g x. g IN group_carrier G /\ x IN s ==> a g x IN s) /\
           (!x. x IN s ==> a (group_id G) x = x) /\
           (!g h x.
                g IN group_carrier G /\ h IN group_carrier G /\ x IN s
                ==> a (group_mul G g h) x = a g (a h x))

  group_conjugation =
    |- !x G a.
           group_conjugation G a x =
           group_mul G a (group_mul G x (group_inv G a))

  group_orbit =
    |- !s G a x y.
           group_orbit G s a x y <=>
           x IN s /\ y IN s /\ (?g. g IN group_carrier G /\ a g x = y)

  group_stabilizer =
    |- !G a x. group_stabilizer G a x = {g | g IN group_carrier G /\ a g x = x}

  ABELIAN_GROUP_CONJUGATION =
    |- !G a x.
           abelian_group G /\ a IN group_carrier G /\ x IN group_carrier G
           ==> group_conjugation G a x = x

  CARD_GROUP_ORBIT_DIVIDES =
    |- !G s a x.
           FINITE (group_carrier G) /\ group_action G s a /\ x IN s
           ==> CARD(group_orbit G s a x) divides CARD(group_carrier G)

  CARD_GROUP_STABILIZER_DIVIDES =
    |- !G s a x.
           FINITE (group_carrier G) /\ group_action G s a /\ x IN s
           ==> CARD(group_stabilizer G a x) divides CARD(group_carrier G)

  CLOSED_GROUP_ORBIT =
    |- !G s a x g.
           group_action G s a /\ g IN group_carrier G
           ==> IMAGE (a g) (group_orbit G s a x) SUBSET group_orbit G s a x

  DISJOINT_GROUP_ORBITS =
    |- !G s a x y.
           group_action G s a /\ x IN s /\ y IN s
           ==> (DISJOINT (group_orbit G s a x) (group_orbit G s a y) <=>
                ~(group_orbit G s a x = group_orbit G s a y))

  FINITE_GROUP_ORBIT =
    |- !G s a x.
           FINITE (group_carrier G) \/ FINITE s
           ==> FINITE (group_orbit G s a x)

  FINITE_GROUP_STABILIZER =
    |- !G a x. FINITE (group_carrier G) ==> FINITE (group_stabilizer G a x)

  GROUP_ACTION_ALT =
    |- !G s a.
           group_action G s a <=>
           (!g x. g IN group_carrier G /\ x IN s ==> a g x IN s) /\
           (!x. x IN s ==> a (group_id G) x = x) /\
           (!g h x.
                g IN group_carrier G /\ h IN group_carrier G /\ x IN s
                ==> a g (a h x) = a (group_mul G g h) x)

  GROUP_ACTION_BIJECTIVE =
    |- !G s a g.
           group_action G s a /\ g IN group_carrier G
           ==> (!y. y IN s ==> (?!x. x IN s /\ a g x = y))

  GROUP_ACTION_CLOSED =
    |- !G s a g.
           group_action G s a /\ g IN group_carrier G
           ==> IMAGE (a g) s SUBSET s

  GROUP_ACTION_EQ =
    |- !G s a g h x.
           group_action G s a /\
           g IN group_carrier G /\
           h IN group_carrier G /\
           x IN s
           ==> (a g x = a h x <=>
                group_mul G (group_inv G g) h IN group_stabilizer G a x)

  GROUP_ACTION_FIBRES =
    |- !G s a h x.
           group_action G s a /\ h IN group_carrier G /\ x IN s
           ==> {g | g IN group_carrier G /\ a g x = a h x} =
               IMAGE (group_mul G h) (group_stabilizer G a x)

  GROUP_ACTION_FROM_SUBGROUP =
    |- !G s h a.
           group_action G s a /\ h subgroup_of G
           ==> group_action (subgroup_generated G h) s a

  GROUP_ACTION_GROUP_CONJUGATION =
    |- !G. group_action G (group_carrier G) (group_conjugation G)

  GROUP_ACTION_GROUP_TRANSLATION =
    |- !G. group_action G (group_carrier G) (group_mul G)

  GROUP_ACTION_IMAGE =
    |- !G u s a.
           group_action G s a /\
           (!t. t IN u ==> t SUBSET s) /\
           (!g t. g IN group_carrier G /\ t IN u ==> IMAGE (a g) t IN u)
           ==> group_action G u (IMAGE o a)

  GROUP_ACTION_IMAGE_SIZED =
    |- !G s k a.
           group_action G s a
           ==> group_action G {t | t SUBSET s /\ t HAS_SIZE k} (IMAGE o a)

  GROUP_ACTION_INJECTIVE =
    |- !G s a.
           group_action G s a /\ g IN group_carrier G /\ x IN s /\ y IN s
           ==> (a g x = a g y <=> x = y)

  GROUP_ACTION_INVARIANT =
    |- !G s a g.
           group_action G s a /\ g IN group_carrier G ==> IMAGE (a g) s = s

  GROUP_ACTION_INVARIANT_SUBSET =
    |- !G s a t.
           group_action G s a /\ t SUBSET s
           ==> ((!g. g IN group_carrier G ==> IMAGE (a g) t SUBSET t) <=>
                (!g. g IN group_carrier G ==> IMAGE (a g) t = t))

  GROUP_ACTION_LEFT_COSET_MULTIPLICATION =
    |- !G h.
           h SUBSET group_carrier G
           ==> group_action G {left_coset G x h | x | x IN group_carrier G}
               (IMAGE o group_mul G)

  GROUP_ACTION_LINV =
    |- !G s a g x.
           group_action G s a /\ g IN group_carrier G /\ x IN s
           ==> a (group_inv G g) (a g x) = x

  GROUP_ACTION_MUL =
    |- !G s a g h x.
           group_action G s a /\
           g IN group_carrier G /\
           h IN group_carrier G /\
           x IN s
           ==> a g (a h x) = a (group_mul G g h) x

  GROUP_ACTION_ON_SUBSET =
    |- !G s t a.
           group_action G s a /\
           t SUBSET s /\
           (!g x. g IN group_carrier G /\ x IN t ==> a g x IN t)
           ==> group_action G t a

  GROUP_ACTION_RINV =
    |- !G s a g x.
           group_action G s a /\ g IN group_carrier G /\ x IN s
           ==> a g (a (group_inv G g) x) = x

  GROUP_ACTION_SUBGROUP_TRANSLATION =
    |- !G h.
           group_action (subgroup_generated G h) (group_carrier G)
           (group_mul G)

  GROUP_ACTION_SUBSET_TRANSLATION =
    |- !G u.
           (!s. s IN u ==> s SUBSET group_carrier G) /\
           (!a s.
                a IN group_carrier G /\ s IN u ==> IMAGE (group_mul G a) s IN u)
           ==> group_action G u (IMAGE o group_mul G)

  GROUP_ACTION_SURJECTIVE =
    |- !G s a g y.
           group_action G s a /\ g IN group_carrier G /\ y IN s
           ==> (?x. a g x = y)

  GROUP_AUTOMORPHISM_CONJUGATION =
    |- !G a.
           a IN group_carrier G
           ==> group_automorphism G (group_conjugation G a)

  GROUP_CONJUGATION =
    |- !G x y.
           x IN group_carrier G /\ y IN group_carrier G
           ==> group_conjugation G x y IN group_carrier G

  GROUP_CONJUGATION_BY_ID =
    |- !G x. x IN group_carrier G ==> group_conjugation G (group_id G) x = x

  GROUP_CONJUGATION_CONJUGATION =
    |- !G a b x.
           a IN group_carrier G /\ b IN group_carrier G /\ x IN group_carrier G
           ==> group_conjugation G a (group_conjugation G b x) =
               group_conjugation G (group_mul G a b) x

  GROUP_CONJUGATION_EQ_ID =
    |- !G a x.
           a IN group_carrier G /\ x IN group_carrier G
           ==> (group_conjugation G a x = group_id G <=> x = group_id G)

  GROUP_CONJUGATION_EQ_SELF =
    |- !G x y.
           x IN group_carrier G /\ y IN group_carrier G
           ==> (group_conjugation G x y = y <=>
                group_mul G x y = group_mul G y x)

  GROUP_CONJUGATION_LINV =
    |- !G a x.
           a IN group_carrier G /\ x IN group_carrier G
           ==> group_conjugation G (group_inv G a) (group_conjugation G a x) =
               x

  GROUP_CONJUGATION_RIGHT_COSET =
    |- !G h x.
           x IN group_carrier G /\ h SUBSET group_carrier G
           ==> IMAGE (group_conjugation G x) (right_coset G h x) =
               left_coset G x h

  GROUP_CONJUGATION_RINV =
    |- !G a x.
           a IN group_carrier G /\ x IN group_carrier G
           ==> group_conjugation G a (group_conjugation G (group_inv G a) x) =
               x

  GROUP_ELEMENT_ORDER_CONJUGATION =
    |- !G x y.
           x IN group_carrier G /\ y IN group_carrier G
           ==> group_element_order G (group_conjugation G x y) =
               group_element_order G y

  GROUP_ISOMORPHISMS_CONJUNCTION =
    |- !G a.
           a IN group_carrier G
           ==> group_isomorphisms (G,G)
               (group_conjugation G a,group_conjugation G (group_inv G a))

  GROUP_ORBIT =
    |- !G s a x.
           group_action G s a
           ==> group_orbit G s a x =
               (if x IN s then {a g x | g IN group_carrier G} else {})

  GROUP_ORBITS_EQ =
    |- !G s a x y.
           group_action G s a /\ x IN s /\ y IN s
           ==> (group_orbit G s a x = group_orbit G s a y <=>
                ~DISJOINT (group_orbit G s a x) (group_orbit G s a y))

  GROUP_ORBIT_EMPTY =
    |- !G s a x. ~(x IN s) ==> group_orbit G s a x = {}

  GROUP_ORBIT_EQ =
    |- !G s a x y.
           group_action G s a /\ x IN s /\ y IN s
           ==> (group_orbit G s a x = group_orbit G s a y <=>
                group_orbit G s a x y)

  GROUP_ORBIT_EQ_EMPTY =
    |- !G s a x.
           group_action G s a ==> (group_orbit G s a x = {} <=> ~(x IN s))

  GROUP_ORBIT_GROUP_TRANSLATION =
    |- !G a.
           a IN group_carrier G
           ==> group_orbit G (group_carrier G) (group_mul G) a =
               group_carrier G

  GROUP_ORBIT_IN_SET =
    |- !G s a x y. group_orbit G s a x y ==> x IN s /\ y IN s

  GROUP_ORBIT_LEFT_COSET_MULTIPLICATION =
    |- !G h a.
           a IN group_carrier G /\ h subgroup_of G
           ==> group_orbit G {left_coset G x h | x | x IN group_carrier G}
                             (IMAGE o group_mul G) (left_coset G a h) =
               {left_coset G x h | x | x IN group_carrier G}

  GROUP_ORBIT_LEFT_COSET_MULTIPLICATION_ID =
    |- !G h.
           h subgroup_of G
           ==> group_orbit G {left_coset G x h | x | x IN group_carrier G}
                             (IMAGE o group_mul G) h =
               {left_coset G x h | x | x IN group_carrier G}

  GROUP_ORBIT_REFL =
    |- !G s a x. group_action G s a /\ x IN s ==> group_orbit G s a x x

  GROUP_ORBIT_REFL_EQ =
    |- !G s a x. group_action G s a ==> (group_orbit G s a x x <=> x IN s)

  GROUP_ORBIT_SUBGROUP_TRANSLATION =
    |- !G h a.
           h subgroup_of G /\ a IN group_carrier G
           ==> group_orbit (subgroup_generated G h) (group_carrier G)
                           (group_mul G) a =
               right_coset G h a

  GROUP_ORBIT_SUBSET = |- !G s a x. group_orbit G s a x SUBSET s

  GROUP_ORBIT_SYM =
    |- !G s a x y.
           group_action G s a /\ group_orbit G s a x y
           ==> group_orbit G s a y x

  GROUP_ORBIT_SYM_EQ =
    |- !G s a x y.
           group_action G s a
           ==> (group_orbit G s a x y <=> group_orbit G s a y x)

  GROUP_ORBIT_TRANS =
    |- !G s a x y z.
           group_action G s a /\ group_orbit G s a x y /\ group_orbit G s a y z
           ==> group_orbit G s a x z

  GROUP_STABILIZER_GROUP_TRANSLATION =
    |- !G a.
           a IN group_carrier G
           ==> group_stabilizer G (group_mul G) a = {group_id G}

  GROUP_STABILIZER_LEFT_COSET_MULTIPLICATION =
    |- !G h a.
           a IN group_carrier G /\ h subgroup_of G
           ==> group_stabilizer G (IMAGE o group_mul G) (left_coset G a h) =
               IMAGE (group_conjugation G a) h

  GROUP_STABILIZER_LEFT_COSET_MULTIPLICATION_ID =
    |- !G h. h subgroup_of G ==> group_stabilizer G (IMAGE o group_mul G) h = h

  GROUP_STABILIZER_NONEMPTY =
    |- !G a s x.
           group_action G s a /\ x IN s ==> ~(group_stabilizer G a x = {})

  GROUP_STABILIZER_SUBGROUP_TRANSLATION =
    |- !G h a.
           h subgroup_of G /\ a IN group_carrier G
           ==> group_stabilizer (subgroup_generated G h) (group_mul G) a =
               {group_id G}

  GROUP_STABILIZER_SUBSET_CARRIER =
    |- !G a x. group_stabilizer G a x SUBSET group_carrier G

  IMAGE_GROUP_CONJUGATION =
    |- !G a s.
           IMAGE (group_conjugation G a) s =
           group_setmul G {a} (group_setmul G s {group_inv G a})

  IMAGE_GROUP_CONJUGATION_TORSION_GEN =
    |- !G P a.
           a IN group_carrier G
           ==> IMAGE (group_conjugation G a)
               {x | x IN group_carrier G /\ P (group_element_order G x)} =
               {x | x IN group_carrier G /\ P (group_element_order G x)}

  INVARIANT_GROUP_ORBIT =
    |- !G s a x g.
           group_action G s a /\ g IN group_carrier G
           ==> IMAGE (a g) (group_orbit G s a x) = group_orbit G s a x

  IN_GROUP_ORBIT_SELF =
    |- !G s a x. group_action G s a /\ x IN s ==> x IN group_orbit G s a x

  LAGRANGE_THEOREM_LEFT_GEN =
    |- !G h.
           h subgroup_of G
           ==> {left_coset G x h | x | x IN group_carrier G} *_c h =_c
               group_carrier G

  LAGRANGE_THEOREM_RIGHT_GEN =
    |- !G h.
           h subgroup_of G
           ==> {right_coset G h x | x | x IN group_carrier G} *_c h =_c
               group_carrier G

  LEFT_COSET_AS_IMAGE =
    |- !x h. left_coset G x h = IMAGE (group_mul G x) h

  LEFT_COSET_LEFT_COSET =
    |- !x y h.
           x IN group_carrier G /\
           y IN group_carrier G /\
           h SUBSET group_carrier G
           ==> left_coset G x (left_coset G y h) =
               left_coset G (group_mul G x y) h

  NORMAL_SUBGROUP_CONJUGATION =
    |- !G h.
           h normal_subgroup_of G <=>
           h subgroup_of G /\
           (!a. a IN group_carrier G
                ==> IMAGE (group_conjugation G a) h SUBSET h)

  NORMAL_SUBGROUP_CONJUGATION_EQ =
    |- !G h.
           h normal_subgroup_of G <=>
           h subgroup_of G /\
           (!a. a IN group_carrier G ==> IMAGE (group_conjugation G a) h = h)

  NORMAL_SUBGROUP_CONJUGATION_SUPERSET =
    |- !G h.
           h normal_subgroup_of G <=>
           h subgroup_of G /\
           (!a. a IN group_carrier G
                ==> h SUBSET IMAGE (group_conjugation G a) h)

  NORMAL_SUBGROUP_OF_TORSION =
    |- !G. {x | x IN group_carrier G /\ ~(group_element_order G x = 0)}
           normal_subgroup_of G <=>
           {x | x IN group_carrier G /\ ~(group_element_order G x = 0)}
           subgroup_of G

  NORMAL_SUBGROUP_OF_TORSION_GEN =
    |- !P G.
           {x | x IN group_carrier G /\ P (group_element_order G x)}
             normal_subgroup_of G <=>
           {x | x IN group_carrier G /\ P (group_element_order G x)}
           subgroup_of G

  ORBIT_STABILIZER =
    |- !G s a x.
           FINITE (group_carrier G) /\ group_action G s a /\ x IN s
           ==> CARD(group_orbit G s a x) =
               CARD {left_coset G g (group_stabilizer G a x) | g |
                     g IN group_carrier G}

  ORBIT_STABILIZER_GEN =
    |- !G s a x.
           group_action G s a /\ x IN s
           ==> group_orbit G s a x =_c
               {left_coset G g (group_stabilizer G a x) | g |
                g IN group_carrier G}

  ORBIT_STABILIZER_MUL =
    |- !G s a x.
           FINITE (group_carrier G) /\ group_action G s a /\ x IN s
           ==> CARD(group_orbit G s a x) * CARD(group_stabilizer G a x) =
               CARD(group_carrier G)

  ORBIT_STABILIZER_MUL_GEN =
    |- !G s a x.
           group_action G s a /\ x IN s
           ==> group_orbit G s a x *_c group_stabilizer G a x =_c
               group_carrier G

  PAIRWISE_DISJOINT_GROUP_ORBITS =
    |- !G h.
           group_action G s a
           ==> pairwise DISJOINT {group_orbit G s a x | x | x IN s}

  RIGHT_COSET_GROUP_CONJUGATION =
    |- !G h x.
           x IN group_carrier G /\ h SUBSET group_carrier G
           ==> right_coset G (IMAGE (group_conjugation G x) h) x =
               left_coset G x h

  RIGHT_COSET_RIGHT_COSET =
    |- !x y h.
           h SUBSET group_carrier G /\
           x IN group_carrier G /\
           y IN group_carrier G
           ==> right_coset G (right_coset G h x) y =
               right_coset G h (group_mul G x y)

  SUBGROUP_OF_GROUP_STABILIZER =
    |- !G s a x.
           group_action G s a /\ x IN s
           ==> group_stabilizer G a x subgroup_of G

  SUBSET_GROUP_ORBIT_CLOSED =
    |- !G s a x t.
           group_action G s a /\
           t SUBSET s /\
           (!g. g IN group_carrier G ==> IMAGE (a g) t SUBSET t)
           ==> (group_orbit G s a x SUBSET t <=>
                x IN s ==> ~DISJOINT (group_orbit G s a x) t)

  SUBSET_GROUP_ORBIT_INVARIANT =
    |- !G s a x t.
           group_action G s a /\
           t SUBSET s /\
           (!g. g IN group_carrier G ==> IMAGE (a g) t = t)
           ==> (group_orbit G s a x SUBSET t <=>
                x IN s ==> ~DISJOINT (group_orbit G s a x) t)

  UNIONS_GROUP_ORBITS =
    |- !G s a.
           group_action G s a ==> UNIONS {group_orbit G s a x | x | x IN s} = s

  UNIONS_GROUP_ORBITS_CLOSED =
    |- !G s a t.
           group_action G s a /\
           t SUBSET s /\
           (!g. g IN group_carrier G ==> IMAGE (a g) t SUBSET t)
           ==> UNIONS {group_orbit G s a x | x IN t} = t

  UNIONS_GROUP_ORBITS_INVARIANT =
    |- !G s a t.
           group_action G s a /\
           t SUBSET s /\
           (!g. g IN group_carrier G ==> IMAGE (a g) t = t)
           ==> UNIONS {group_orbit G s a x | x IN t} = t

Fri 27th Mar 2020       Library/prime.ml

Further cleaned up the Library/prime.ml file, deriving the various forms
of the Bezout property for N more efficiently from the (automatic) one
for Z, and eliminating three otherwise unused lemmas:

        BEZOUT_GCD_POW
        BEZOUT_LEMMA
        IND_EUCLID

Also strengthened the existing theorem GCD_COPRIME_EXISTS by removing the
precondition, so it is now simply:

  GCD_COPRIME_EXISTS =
   |- !a b.
         ?a' b'. a = a' * gcd(a,b) /\ b = b' * gcd(a,b) /\ coprime(a',b')

Thu 26th Mar 2020       Library/grouptheory.ml, Library/ringtheory.ml

Added a collection of highly analogous theorems for groups and rings,
mainly about cardinality properties w.r.t. morphisms and the elaborations
with the cardinalities of carriers dividing each other:

  CARD_DIVIDES_GROUP_EPIMORPHIC_IMAGE =
    |- !G H f.
           group_epimorphism (G,H) f /\ FINITE(group_carrier G)
           ==> CARD(group_carrier H) divides CARD(group_carrier G)

  CARD_DIVIDES_GROUP_MONOMORPHIC_IMAGE =
    |- !G H f.
           group_monomorphism (G,H) f /\ FINITE(group_carrier H)
           ==> CARD(group_carrier G) divides CARD(group_carrier H)

  CARD_DIVIDES_RING_EPIMORPHIC_IMAGE =
    |- !r r' f.
           ring_epimorphism (r,r') f /\ FINITE(ring_carrier r)
           ==> CARD(ring_carrier r') divides CARD(ring_carrier r)

  CARD_DIVIDES_RING_MONOMORPHIC_IMAGE =
    |- !r r' f.
           ring_monomorphism (r,r') f /\ FINITE(ring_carrier r')
           ==> CARD(ring_carrier r) divides CARD(ring_carrier r')

  CARD_EQ_GROUP_IMAGE_KERNEL =
    |- !G H f.
           group_homomorphism (G,H) f
           ==> group_image (G,H) f *_c group_kernel (G,H) f =_c group_carrier G

  CARD_EQ_GROUP_ISOMORPHIC_IMAGE =
    |- !G H f.
           group_isomorphism (G,H) f ==> group_carrier G =_c group_carrier H

  CARD_EQ_GROUP_MONOMORPHIC_IMAGE =
    |- !G H f.
           group_monomorphism (G,H) f
           ==> IMAGE f (group_carrier G) =_c group_carrier G

  CARD_EQ_RING_IMAGE_KERNEL =
    |- !r r' f.
           ring_homomorphism (r,r') f
           ==> ring_image (r,r') f *_c ring_kernel (r,r') f =_c ring_carrier r

  CARD_EQ_RING_ISOMORPHIC_IMAGE =
    |- !r r' f.
           ring_isomorphism (r,r') f ==> ring_carrier r =_c ring_carrier r'

  CARD_EQ_RING_MONOMORPHIC_IMAGE =
    |- !r r' f.
           ring_monomorphism (r,r') f
           ==> IMAGE f (ring_carrier r) =_c ring_carrier r

  CARD_GROUP_SETMUL_DIVIDES =
    |- !G g h.
           abelian_group G /\
           FINITE g /\
           FINITE h /\
           g subgroup_of G /\
           h subgroup_of G
           ==> CARD(group_setmul G g h) divides CARD g * CARD h

  CARD_LEFT_COSETS_DIVIDES =
    |- !G h.
           FINITE(group_carrier G) /\ h subgroup_of G
           ==> CARD {left_coset G x h | x | x IN group_carrier G} divides
               CARD(group_carrier G)

  CARD_LE_GROUP_EPIMORPHIC_IMAGE =
    |- !G H f.
           group_epimorphism (G,H) f ==> group_carrier H <=_c group_carrier G

  CARD_LE_GROUP_MONOMORPHIC_IMAGE =
    |- !G H f.
           group_monomorphism (G,H) f ==> group_carrier G <=_c group_carrier H

  CARD_LE_QUOTIENT_GROUP =
    |- !G n.
           n normal_subgroup_of G
           ==> group_carrier(quotient_group G n) <=_c group_carrier G

  CARD_LE_QUOTIENT_RING =
    |- !r j.
           ring_ideal r j
           ==> ring_carrier(quotient_ring r j) <=_c ring_carrier r

  CARD_LE_RING_EPIMORPHIC_IMAGE =
    |- !r r' f.
           ring_epimorphism (r,r') f ==> ring_carrier r' <=_c ring_carrier r

  CARD_LE_RING_MONOMORPHIC_IMAGE =
    |- !r r' f.
           ring_monomorphism (r,r') f ==> ring_carrier r <=_c ring_carrier r'

  CARD_QUOTIENT_GROUP_DIVIDES =
    |- !G n.
           FINITE(group_carrier G) /\ n normal_subgroup_of G
           ==> CARD(group_carrier(quotient_group G n)) divides
               CARD(group_carrier G)

  CARD_QUOTIENT_RING_DIVIDES =
    |- !r j.
           FINITE(ring_carrier r) /\ ring_ideal r j
           ==> CARD(ring_carrier(quotient_ring r j)) divides
               CARD(ring_carrier r)

  CARD_RIGHT_COSETS_DIVIDES =
    |- !G h.
           FINITE(group_carrier G) /\ h subgroup_of G
           ==> CARD {right_coset G h x | x | x IN group_carrier G} divides
               CARD(group_carrier G)

  CARD_RING_COSETS_DIVIDES =
    |- !r j.
           FINITE(ring_carrier r) /\ (ring_ideal r j \/ j subring_of r)
           ==> CARD {ring_coset r j x | x | x IN ring_carrier r} divides
               CARD(ring_carrier r)

  FINITE_GROUP_EPIMORPHIC_IMAGE =
    |- !G H f.
           group_epimorphism (G,H) f /\ FINITE(group_carrier G)
           ==> FINITE(group_carrier H)

  FINITE_GROUP_MONOMORPHIC_PREIMAGE =
    |- !G H f.
           group_monomorphism (G,H) f /\ FINITE(group_carrier H)
           ==> FINITE(group_carrier G)

  FINITE_RING_EPIMORPHIC_IMAGE =
    |- !r r' f.
           ring_epimorphism (r,r') f /\ FINITE(ring_carrier r)
           ==> FINITE(ring_carrier r')

  FINITE_RING_MONOMORPHIC_PREIMAGE =
    |- !r r' f.
           ring_monomorphism (r,r') f /\ FINITE(ring_carrier r')
           ==> FINITE(ring_carrier r)

Also modified the following to replace the "ring_ideal r j" assumption
with a disjunction "ring_ideal r j \/ j subring_of r", since these are
really just about the additive group structure and work in either case.


        CARD_EQ_RING_COSETS
        CARD_EQ_RING_COSET_IDEAL
        DISJOINT_RING_COSETS
        IMAGE_RING_COSET_SWITCH
        IN_RING_COSET_SELF
        LAGRANGE_THEOREM_RING_EXPLICIT
        PAIRWISE_DISJOINT_RING_COSETS
        RING_COSETS_EQ
        RING_COSET_EQ
        RING_COSET_EQ_IDEAL
        RING_SETNEG_COSET
        UNIONS_RING_COSETS

Made the same change to LAGRANGE_THEOREM_RING_IDEAL *and* changed the
name to just LAGRANGE_THEOREM_RING, otherwise it now seems misleading.

Wed 25th Mar 2020       iterate.ml, Library/products.ml, Library/isum.ml, Library/prime.ml, Library/pocklington.ml, Library/multiplicative.ml, 100/wilson.ml, Model/modelset.ml

Moved the basic definitions and derivations of the clausal recursions for
the "second-tier" iterated operations isum, nproduct, iproduct and product,
into the basic "iterate.ml" file, so that at least they can be used as
concepts without loading in the more extensive lemma libraries about them. So
these existing definitions and theorems are now available without loading any
libraries:

        iproduct
        isum
        nproduct
        product
        IPRODUCT_CLAUSES
        ISUM_CLAUSES
        MONOIDAL_INT_ADD
        MONOIDAL_INT_MUL
        NEUTRAL_INT_ADD
        NEUTRAL_INT_MUL
        NPRODUCT_CLAUSES
        PRODUCT_CLAUSES

Added to "Library/prime.ml" one additional lemma COPRIME_NPRODUCT_EQ, as
well as moving back the weaker COPRIME_NPRODUCT from "Library/pocklington.ml"
to "Library/prime.ml" and restating it using the actual "nproduct" constant:

  COPRIME_NPRODUCT_EQ =
    |- (!f a s.
          FINITE s
          ==> (coprime(a,nproduct s f) <=> (!i. i IN s ==> coprime(a,f i)))) /\
     (!f b s.
          FINITE s
          ==> (coprime(nproduct s f,b) <=> (!i. i IN s ==> coprime(f i,b))))

In addition in other files changed the following theorems to use the "nproduct"
construct explicitly instead of "iterate ( * )":

        NPRODUCT_MOD
        NPRODUCT_CMUL
        COUNT_ROOTS_MODULO_ODD_GEN
        COUNT_ROOTS_MODULO_ODD_ALT_GEN
        COUNT_ROOTS_MODULO_ODD_ALT
        COUNT_ROOTS_MODULO_ODD

Changed a couple of places where the newly introduced constants clased with
something (in the case of "100/wilson.ml" just switched to using "nproduct").

Mon 23rd Mar 2020       int.ml, Library/prime.ml

Added yet one more "if and only if" theorem relating primality to other
divisibility properties into the basic "int.ml" file, rendering
PRIME_COPRIME_EQ in "Library/prime.ml" a trivial consequence. This is one
of the nicer theorems of this kind since it doesn't have any special cases
for 0 and 1.

  PRIME_COPRIME_EQ_NONDIVISIBLE =
    |- !p. prime p <=> (!n. coprime(p,n) <=> ~(p divides n))

Sat 21st Mar 2020       Library/grouptheory.ml

Added a number of miscellaneous and natural group theory lemmas, in particular
some around the correspondence principle for (normal) subgroups under an
epimorphism.

  ABELIAN_SIMPLE_GROUP =
    |- !G. abelian_group G
           ==> ((!h. h normal_subgroup_of G
                     ==> h = {group_id G} \/ h = group_carrier G) <=>
                FINITE(group_carrier G) /\
                (CARD(group_carrier G) = 1 \/ prime (CARD(group_carrier G))))

  CYCLIC_GROUP_PRIME_ORDER_EQ =
    |- !G. (!a. a IN group_carrier G /\ ~(a = group_id G)
                ==> subgroup_generated G {a} = G) <=>
           FINITE(group_carrier G) /\
           (CARD(group_carrier G) = 1 \/ prime (CARD(group_carrier G)))

  FIRST_GROUP_EPIMORPHISM_THEOREM =
    |- !G G' f.
           group_epimorphism (G,G') f
           ==> quotient_group G (group_kernel (G,G') f) isomorphic_group G'

  FIRST_GROUP_ISOMORPHISM_THEOREM_GEN =
    |- !G H f j k.
           group_epimorphism (G,H) f /\
           k normal_subgroup_of H /\
           {x | x IN group_carrier G /\ f x IN k} = j
           ==> quotient_group G j isomorphic_group quotient_group H k

  FIRST_GROUP_ISOMORPHISM_THEOREM_GEN_ALT =
    |- !G H f j k.
           group_epimorphism (G,H) f /\
           j normal_subgroup_of G /\
           group_kernel (G,H) f SUBSET j /\
           IMAGE f j = k
           ==> quotient_group G j isomorphic_group quotient_group H k

  FORALL_IN_GROUP_CARRIER_INV =
    |- !P G.
           (!x. x IN group_carrier G ==> P (group_inv G x)) <=>
           (!x. x IN group_carrier G ==> P x)

  GROUP_EPIMORPHISM_NORMAL_SUBGROUP_CORRESPONDENCE =
    |- !G H f k.
           group_epimorphism (G,H) f
           ==> (k normal_subgroup_of H <=>
                (?j. j normal_subgroup_of G /\
                     group_kernel (G,H) f SUBSET j /\
                     {x | x IN group_carrier G /\ f x IN k} = j /\
                     IMAGE f j = k))

  GROUP_EPIMORPHISM_NORMAL_SUBGROUP_CORRESPONDENCE_ALT =
    |- !G H f j.
           group_epimorphism (G,H) f
           ==> (j normal_subgroup_of G /\ group_kernel (G,H) f SUBSET j <=>
                (?k. k normal_subgroup_of H /\
                     {x | x IN group_carrier G /\ f x IN k} = j /\
                     IMAGE f j = k))

  GROUP_EPIMORPHISM_SUBGROUP_CORRESPONDENCE =
    |- !G H f k.
           group_epimorphism (G,H) f
           ==> (k subgroup_of H <=>
                (?j. j subgroup_of G /\
                     group_kernel (G,H) f SUBSET j /\
                     {x | x IN group_carrier G /\ f x IN k} = j /\
                     IMAGE f j = k))

  GROUP_EPIMORPHISM_SUBGROUP_CORRESPONDENCE_ALT =
    |- !G H f j.
           group_epimorphism (G,H) f
           ==> (j subgroup_of G /\ group_kernel (G,H) f SUBSET j <=>
                (?k. k subgroup_of H /\
                     {x | x IN group_carrier G /\ f x IN k} = j /\
                     IMAGE f j = k))

  GROUP_HOMOMORPHISM_IMAGE_PREIMAGE =
    |- !G H f t.
           group_homomorphism (G,H) f
           ==> IMAGE f {x | x IN group_carrier G /\ f x IN t} =
               t INTER group_image (G,H) f

  GROUP_HOMOMORPHISM_IMAGE_PREIMAGE_EQ =
    |- !G H f t.
           group_homomorphism (G,H) f /\ t SUBSET group_image (G,H) f
           ==> IMAGE f {x | x IN group_carrier G /\ f x IN t} = t

  GROUP_HOMOMORPHISM_PREIMAGE_IMAGE =
    |- !G H f s.
           group_homomorphism (G,H) f /\
           group_kernel (G,H) f SUBSET s /\
           s subgroup_of G
           ==> {x | x IN group_carrier G /\ f x IN IMAGE f s} = s

  GROUP_HOMOMORPHISM_PREIMAGE_IMAGE_LEFT =
    |- !G H f s.
           group_homomorphism (G,H) f /\ s SUBSET group_carrier G
           ==> {x | x IN group_carrier G /\ f x IN IMAGE f s} =
               group_setmul G (group_kernel (G,H) f) s

  GROUP_HOMOMORPHISM_PREIMAGE_IMAGE_RIGHT =
    |- !G H f s.
           group_homomorphism (G,H) f /\ s SUBSET group_carrier G
           ==> {x | x IN group_carrier G /\ f x IN IMAGE f s} =
               group_setmul G s (group_kernel (G,H) f)

  GROUP_KERNEL_NONEMPTY =
    |- !G H f. group_homomorphism (G,H) f ==> ~(group_kernel (G,H) f = {})

  GROUP_KERNEL_SUBSET_CARRIER =
    |- !G H f. group_kernel (G,H) f SUBSET group_carrier G

  GROUP_SETMUL_NORMAL_SUBGROUP =
    |- !G h k.
           h normal_subgroup_of G /\ k normal_subgroup_of G
           ==> group_setmul G h k normal_subgroup_of G

  GROUP_SETMUL_NORMAL_SUBGROUP_LEFT =
    |- !G n h.
           n normal_subgroup_of G /\ h subgroup_of G
           ==> group_setmul G n h subgroup_of G

  GROUP_SETMUL_NORMAL_SUBGROUP_RIGHT =
    |- !G h n.
           h subgroup_of G /\ n normal_subgroup_of G
           ==> group_setmul G h n subgroup_of G

  IN_LEFT_COSET =
    |- !G h x a.
           h SUBSET group_carrier G /\
           a IN group_carrier G /\
           x IN group_carrier G
           ==> (x IN left_coset G a h <=> group_mul G (group_inv G a) x IN h)

  IN_LEFT_COSET_INV =
    |- !G h x y.
           h SUBSET group_carrier G /\
           x IN group_carrier G /\
           y IN group_carrier G
           ==> (x IN left_coset G (group_inv G y) h <=> group_mul G y x IN h)

  IN_RIGHT_COSET =
    |- !G h x a.
           h SUBSET group_carrier G /\
           a IN group_carrier G /\
           x IN group_carrier G
           ==> (x IN right_coset G h a <=> group_mul G x (group_inv G a) IN h)

  IN_RIGHT_COSET_INV =
    |- !G h x y.
           h SUBSET group_carrier G /\
           x IN group_carrier G /\
           y IN group_carrier G
           ==> (x IN right_coset G h (group_inv G y) <=> group_mul G x y IN h)

  MAXIMAL_NORMAL_SUBGROUP =
    |- !G n.
           n normal_subgroup_of G
           ==> ((!h. h normal_subgroup_of G /\ n PSUBSET h
                     ==> h = group_carrier G) <=>
                (!k. k normal_subgroup_of quotient_group G n
                     ==> k = {group_id (quotient_group G n)} \/
                         k = group_carrier(quotient_group G n)))

  MAXIMAL_PROPER_SUBGROUP_PRIME_INDEX =
    |- !G n.
           n normal_subgroup_of G /\ ~(n = group_carrier G)
           ==> ((!h. h subgroup_of G /\ n PSUBSET h ==> h = group_carrier G) <=>
                FINITE {right_coset G n x | x | x IN group_carrier G} /\
                prime (CARD {right_coset G n x | x | x IN group_carrier G}))

  MAXIMAL_SUBGROUP =
    |- !G n.
           n normal_subgroup_of G
           ==> ((!h. h subgroup_of G /\ n PSUBSET h ==> h = group_carrier G) <=>
                (!k. k subgroup_of quotient_group G n
                     ==> k = {group_id (quotient_group G n)} \/
                         k = group_carrier(quotient_group G n)))

  MAXIMAL_SUBGROUP_PRIME_INDEX =
    |- !G n.
           n normal_subgroup_of G
           ==> ((!h. h subgroup_of G /\ n PSUBSET h ==> h = group_carrier G) <=>
                FINITE {right_coset G n x | x | x IN group_carrier G} /\
                (CARD {right_coset G n x | x | x IN group_carrier G} = 1 \/
                 prime (CARD {right_coset G n x | x | x IN group_carrier G})))

  NORMAL_SUBGROUP_LEFT_EQ_RIGHT_COSETS =
    |- !G n.
           n normal_subgroup_of G <=>
           n subgroup_of G /\
           {left_coset G x n | x | x IN group_carrier G} =
           {right_coset G n x | x | x IN group_carrier G}

  NORMAL_SUBGROUP_LEFT_SUBSET_RIGHT_COSETS =
    |- !G n.
           n normal_subgroup_of G <=>
           n subgroup_of G /\
           {left_coset G x n | x | x IN group_carrier G} SUBSET
           {right_coset G n x | x | x IN group_carrier G}

  NORMAL_SUBGROUP_MUL_SYM =
    |- !G h.
           h normal_subgroup_of G <=>
           h subgroup_of G /\
           (!x y.
                x IN group_carrier G /\ y IN group_carrier G
                ==> (group_mul G x y IN h <=> group_mul G y x IN h))

  NORMAL_SUBGROUP_OF_EPIMORPHIC_IMAGE =
    |- !G H f n.
           group_epimorphism (G,H) f /\ n normal_subgroup_of G
           ==> IMAGE f n normal_subgroup_of H

  NORMAL_SUBGROUP_OF_EPIMORPHIC_PREIMAGE_EQ =
    |- !G H f j k.
           group_epimorphism (G,H) f /\
           k subgroup_of H /\
           {x | x IN group_carrier G /\ f x IN k} = j
           ==> (j normal_subgroup_of G <=> k normal_subgroup_of H)

  NORMAL_SUBGROUP_OF_HOMOMORPHIC_PREIMAGE =
    |- !G H f j.
           group_homomorphism (G,H) f /\ j normal_subgroup_of H
           ==> {x | x IN group_carrier G /\ f x IN j} normal_subgroup_of G

  NORMAL_SUBGROUP_OF_ISOMORPHIC_IMAGE_EQ =
    |- !G H f j.
           group_isomorphism (G,H) f /\ j SUBSET group_carrier G
           ==> (IMAGE f j normal_subgroup_of H <=> j normal_subgroup_of G)

  NORMAL_SUBGROUP_RIGHT_SUBSET_LEFT_COSETS =
    |- !G n.
           n normal_subgroup_of G <=>
           n subgroup_of G /\
           {right_coset G n x | x | x IN group_carrier G} SUBSET
           {left_coset G x n | x | x IN group_carrier G}

  NO_PROPER_SUBGROUP_EPIMORPHIC_IMAGE_EQ =
    |- !G H f.
           group_epimorphism (G,H) f
           ==> ((!k. k subgroup_of H
                     ==> k = {group_id H} \/ k = group_carrier H) <=>
                (!h. h subgroup_of G /\ group_kernel (G,H) f PSUBSET h
                     ==> h = group_carrier G))

  PRIME_INDEX_MAXIMAL_PROPER_SUBGROUP =
    |- !G n.
           n normal_subgroup_of G
           ==> (FINITE {right_coset G n x | x | x IN group_carrier G} /\
                prime (CARD {right_coset G n x | x | x IN group_carrier G}) <=>
                ~(n = group_carrier G) /\
                (!h. h subgroup_of G /\ n PSUBSET h ==> h = group_carrier G))

  QUOTIENT_NORMAL_SUBGROUP_CORRESPONDENCE =
    |- !G j k.
           j normal_subgroup_of G
           ==> (k normal_subgroup_of quotient_group G j <=>
                (?i. i normal_subgroup_of G /\
                     j SUBSET i /\
                     {x | x IN group_carrier G /\ right_coset G j x IN k} = i /\
                     IMAGE (right_coset G j) i = k))

  QUOTIENT_SUBGROUP_CORRESPONDENCE =
    |- !G j k.
           j normal_subgroup_of G
           ==> (k subgroup_of quotient_group G j <=>
                (?i. i subgroup_of G /\
                     j SUBSET i /\
                     {x | x IN group_carrier G /\ right_coset G j x IN k} = i /\
                     IMAGE (right_coset G j) i = k))

  SIMPLE_GROUP_EPIMORPHIC_IMAGE_EQ =
    |- !G H f.
           group_epimorphism (G,H) f
           ==> ((!k. k normal_subgroup_of H
                     ==> k = {group_id H} \/ k = group_carrier H) <=>
                (!h. h normal_subgroup_of G /\ group_kernel (G,H) f PSUBSET h
                     ==> h = group_carrier G))

  SUBGROUP_OF_ISOMORPHIC_IMAGE_EQ =
    |- !G H f j.
           group_isomorphism (G,H) f /\ j SUBSET group_carrier G
           ==> (IMAGE f j subgroup_of H <=> j subgroup_of G)

  TRIVIAL_QUOTIENT_GROUP_EQ =
    |- !G n.
           n normal_subgroup_of G
           ==> (trivial_group (quotient_group G n) <=> n = group_carrier G)

Sat 21st Mar 2020       int.ml

Added one more basic primality property to the core results in int.ml:

  ONE_OR_PRIME_DIVIDES_OR_COPRIME =
    |- !p. p = 1 \/ prime p <=> (!n. p divides n \/ coprime(p,n))

Mon 15th Mar 2020       Examples/nist_curves.ml

Slightly reorganized the existing proofs with a mildly different approach to
field reasoning, and added new material about (standard) projective and
Jacobian coordinates for Weierstrass curves. In each case we define parallel
versions of the group operations as well as equivalence relations
"projective_eq" and "jacobian_eq" and show that they have all the expected
properties relative to the affine coordinates.

Fri 13th Mar 2020       Library/card.ml, Library/grouptheory.ml, Library/ringtheory.ml

Added a miscellany of technical lemmas, mainly about group theory but in a
few places ring theory and cardinality. In fact, the three theorems with
"DISJOINT_UNION" in the name are effectively the same result in three
different categories.

  ABELIAN_GROUP_ELEMENT_ORDER_MUL_DIVIDES_GEN =
    |- !G x y n.
           abelian_group G /\
           x IN group_carrier G /\
           y IN group_carrier G /\
           group_element_order G x divides n /\
           group_element_order G y divides n
           ==> group_element_order G (group_mul G x y) divides n

  ABELIAN_GROUP_ELEMENT_ORDER_MUL_DIVIDES_LCM =
    |- !G x y.
           abelian_group G /\ x IN group_carrier G /\ y IN group_carrier G
           ==> group_element_order G (group_mul G x y) divides
               lcm(group_element_order G x,group_element_order G y)

  ABELIAN_GROUP_HOMOMORPHISM_POWERING =
    |- !G n. abelian_group G ==> group_homomorphism (G,G) (\x. group_pow G x n)

  ABELIAN_GROUP_HOMOMORPHISM_ZPOWERING =
    |- !G n.
           abelian_group G ==> group_homomorphism (G,G) (\x. group_zpow G x n)

  CARD_EQ_CARTESIAN_PRODUCT =
    |- !s t k.
           (!i. i IN k ==> s i =_c t i)
           ==> cartesian_product k s =_c cartesian_product k t

  CARD_EQ_CARTESIAN_PRODUCT_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> cartesian_product (k UNION l) f =_c
               cartesian_product k f CROSS cartesian_product l f

  CYCLIC_PRIME_ORDER_GROUP =
    |- !G a.
           FINITE(group_carrier G) /\
           (CARD(group_carrier G) = 1 \/ prime (CARD(group_carrier G))) /\
           a IN group_carrier G /\
           ~(a = group_id G)
           ==> subgroup_generated G {a} = G

  CYCLIC_PROD_GROUP =
    |- !G H.
           cyclic_group (prod_group G H) <=>
           cyclic_group G /\
           cyclic_group H /\
           (trivial_group G \/
            trivial_group H \/
            FINITE(group_carrier G) /\
            FINITE(group_carrier H) /\
            coprime(CARD(group_carrier G),CARD(group_carrier H)))

  CYCLIC_PROD_INTEGER_MOD_GROUP =
    |- !m n.
           cyclic_group
           (prod_group (integer_mod_group m) (integer_mod_group n)) <=>
           coprime(m,n)

  GENERATOR_INTEGER_MOD_GROUP =
    |- !n a.
           subgroup_generated (integer_mod_group n) {a} = integer_mod_group n <=>
           (n <= 1 \/ &0 <= a /\ a < &n) /\ coprime(&n,a)

  GROUP_CARRIER_INTEGER_MOD_GROUP =
    |- !n. group_carrier(integer_mod_group n) = IMAGE (\x. x rem &n) (:int)

  GROUP_ELEMENT_ORDER_INTEGER_MOD_GROUP =
    |- !n m.
           group_element_order (integer_mod_group n) (&m) =
           (if m = 0 /\ n = 0 then 1 else n DIV gcd(n,m))

  GROUP_ELEMENT_ORDER_INTEGER_MOD_GROUP_1 =
    |- !n. group_element_order (integer_mod_group n) (&1) = n

  GROUP_ELEMENT_ORDER_INTEGER_MOD_GROUP_1R =
    |- !n. group_element_order (integer_mod_group n) (&1 rem &n) = n

  GROUP_ELEMENT_ORDER_MUL_DIVIDES_GEN =
    |- !G x y n.
           x IN group_carrier G /\
           y IN group_carrier G /\
           group_mul G x y = group_mul G y x /\
           group_element_order G x divides n /\
           group_element_order G y divides n
           ==> group_element_order G (group_mul G x y) divides n

  GROUP_ELEMENT_ORDER_MUL_DIVIDES_LCM =
    |- !G x y.
           x IN group_carrier G /\
           y IN group_carrier G /\
           group_mul G x y = group_mul G y x
           ==> group_element_order G (group_mul G x y) divides
               lcm(group_element_order G x,group_element_order G y)

  GROUP_ELEMENT_ORDER_PROD_GROUP =
    |- !G H x y.
           x IN group_carrier G /\ y IN group_carrier H
           ==> group_element_order (prod_group G H) (x,y) =
               lcm(group_element_order G x,group_element_order H y)

  GROUP_ELEMENT_ORDER_PROD_GROUP_ALT =
    |- !G H z.
           z IN group_carrier(prod_group G H)
           ==> group_element_order (prod_group G H) z =
               lcm
               (group_element_order G (FST z),group_element_order H (SND z))

  GROUP_ELEMENT_ORDER_SUBGROUP_GENERATED =
    |- !G h x.
           group_element_order (subgroup_generated G h) x =
           group_element_order G x

  GROUP_HOMOMORPHISM_INCLUSION =
    |- !G s. group_homomorphism (subgroup_generated G s,G) (\x. x)

  GROUP_HOMOMORPHISM_OF_ID =
    |- !f G G'. group_homomorphism (G,G') f ==> f (group_id G) = group_id G'

  GROUP_HOMOMORPHISM_PROD_INTEGER_MOD_GROUP =
    |- !m n.
           group_homomorphism
           (integer_mod_group (m * n),
            prod_group (integer_mod_group m) (integer_mod_group n))
           (\a. a rem &m,a rem &n)

  GROUP_ISOMORPHISMS =
    |- !G H f g.
           group_isomorphisms (G,H) (f,g) <=>
           group_homomorphism (G,H) f /\
           (!x. x IN group_carrier G ==> g (f x) = x) /\
           (!y. y IN group_carrier H ==> g y IN group_carrier G /\ f (g y) = y)

  GROUP_ISOMORPHISM_PROD_INTEGER_MOD_GROUP =
    |- !m n.
           group_isomorphism
           (integer_mod_group (m * n),
            prod_group (integer_mod_group m) (integer_mod_group n))
           (\a. a rem &m,a rem &n) <=>
           coprime(m,n)

  GROUP_ISOMORPHISM_SUBSET =
    |- !G G' f.
           group_isomorphism (G,G') f <=>
           group_homomorphism (G,G') f /\
           (!z. z IN group_carrier G'
                ==> ?x. x IN group_carrier G /\ f x = z) /\
           (!x y.
                x IN group_carrier G /\ y IN group_carrier G /\ f x = f y
                ==> x = y)

  GROUP_MONOMORPHISM_BETWEEN_SUBGROUPS =
    |- !G H s t f.
           group_monomorphism (G,H) f /\ IMAGE f s SUBSET t
           ==> group_monomorphism
               (subgroup_generated G s,subgroup_generated H t)
               f

  GROUP_MONOMORPHISM_FROM_SUBGROUP_GENERATED =
    |- !f G H s.
           group_monomorphism (G,H) f
           ==> group_monomorphism (subgroup_generated G s,H) f

  GROUP_MONOMORPHISM_INCLUSION =
    |- !G s. group_monomorphism (subgroup_generated G s,G) (\x. x)

  GROUP_POW_PROD_GROUP =
    |- !G H x y n.
           x IN group_carrier G /\ y IN group_carrier H
           ==> group_pow (prod_group G H) (x,y) n =
               group_pow G x n,group_pow H y n

  GROUP_ZPOW_PROD_GROUP =
    |- !G H x y n.
           x IN group_carrier G /\ y IN group_carrier H
           ==> group_zpow (prod_group G H) (x,y) n =
               group_zpow G x n,group_zpow H y n

  INTEGER_MOD_GROUP_1R =
    |- !n x. x rem &n IN group_carrier(integer_mod_group n)

  INTEGER_MOD_SUBGROUP_GENERATED_BY_1R =
    |- !n. subgroup_generated (integer_mod_group n) {&1 rem &n} =
           integer_mod_group n

  ISOMORPHIC_PRODUCT_GROUP_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> product_group (k UNION l) f isomorphic_group
               prod_group (product_group k f) (product_group l f)

  ISOMORPHIC_PRODUCT_RING_DISJOINT_UNION =
    |- !f k l.
           DISJOINT k l
           ==> product_ring (k UNION l) f isomorphic_ring
               prod_ring (product_ring k f) (product_ring l f)

  ISOMORPHIC_PROD_INTEGER_MOD_GROUP =
    |- !m n.
           prod_group (integer_mod_group m) (integer_mod_group n) isomorphic_group
           integer_mod_group (m * n) <=>
           coprime(m,n)

  PAIRWISE_DISJOINT_LEFT_COSETS =
    |- !G h.
           h subgroup_of G
           ==> pairwise DISJOINT {left_coset G a h | a | a IN group_carrier G}

  PAIRWISE_DISJOINT_RIGHT_COSETS =
    |- !G h.
           h subgroup_of G
           ==> pairwise DISJOINT {right_coset G h a | a | a IN group_carrier G}

  PAIRWISE_DISJOINT_RING_COSETS =
    |- !r j.
           ring_ideal r j
           ==> pairwise DISJOINT {ring_coset r j x | x | x IN ring_carrier r}

  SHORT_EXACT_SEQUENCE_NORMAL_SUBGROUP =
    |- !G n.
           n normal_subgroup_of G
           ==> short_exact_sequence
               (subgroup_generated G n,G,quotient_group G n)
               ((\x. x),right_coset G n)

  SHORT_EXACT_SEQUENCE_PROD_GROUP =
    |- !G H. short_exact_sequence (G,prod_group G H,H) ((\x. x,group_id H),SND)

  SHORT_EXACT_SEQUENCE_PROD_GROUP_ALT =
    |- !G H. short_exact_sequence (H,prod_group G H,G) ((\x. group_id G,x),FST)

  TRIVIAL_GROUP_GENERATED_BY_ANYTHING =
    |- !G s. trivial_group G ==> subgroup_generated G s = G

Fri 13th Mar 2020       Library/prime.ml

Added four miscellaneous lemmas around divisibility:

  COPRIME_PRIME_PRIME =
    |- !p q. prime p /\ prime q ==> (coprime(p,q) <=> ~(p = q))

  INDEX_NSUM_LE =
    |- !f p n k.
           FINITE k /\ ~(k = {}) /\ (!a. a IN k ==> n <= index p (f a))
           ==> n <= index p (nsum k f)

  INDEX_POW =
    |- !p n k. index (p EXP k) n = index p n DIV k

  LCM_DIVIDES_MUL =
    |- !m n. lcm(m,n) divides m * n

Fri 13th Mar 2020       Library/ringtheory.ml

Added a few new elementary theorems about ring inverses

  RING_DIV_1 =
    |- !r x. x IN ring_carrier r ==> ring_div r x (ring_1 r) = x

  RING_INV_POW =
    |- !r x n.
           x IN ring_carrier r
           ==> ring_inv r (ring_pow r x n) = ring_pow r (ring_inv r x) n

  RING_INV_ZERO =
    |- !r x. ~ring_unit r x ==> ring_inv r x = ring_0 r

  RING_MUL_LINV_EQ =
    |- !r x.
           x IN ring_carrier r
           ==> (ring_mul r (ring_inv r x) x = ring_1 r <=> ring_unit r x)

  RING_MUL_RINV_EQ =
    |- !r x.
           x IN ring_carrier r
           ==> (ring_mul r x (ring_inv r x) = ring_1 r <=> ring_unit r x)

  RING_POW_INV =
    |- !r x n.
           x IN ring_carrier r
           ==> ring_pow r (ring_inv r x) n = ring_inv r (ring_pow r x n)

as well as generalizing the existing theorem RING_INV_MUL to just assume
carrier membership, not that the elements are units:

  RING_INV_MUL =
    |- !r a b.
           a IN ring_carrier r /\ b IN ring_carrier r
           ==> ring_inv r (ring_mul r a b) =
               ring_mul r (ring_inv r a) (ring_inv r b)

Thu 12th Mar 2020       int.ml, Library/prime.ml, Library/integer.ml

Moved these theorems back into int.ml, also adding the first one to the
initial simplifications inside INTEGER_RULE:

        INT_DIVIDES_ABS
        INT_DIVIDES_LABS
        INT_DIVIDES_RABS

and defined an integer lcm operation with some rudimentary theorems

  int_lcm =
    |- !m n. lcm(m,n) = (if m * n = &0 then &0 else abs(m * n) div gcd(m,n))

  INT_DIVIDES_LCM_GCD =
    |- !m n d. d divides lcm(m,n) <=> d * gcd(m,n) divides m * n

  INT_DIVIDES_RABS =
    |- !d n. d divides abs n <=> d divides n

  INT_LCM =
    |- !m n.
           m divides lcm(m,n) /\
           n divides lcm(m,n) /\
           (!d. m divides d /\ n divides d ==> lcm(m,n) divides d)

  INT_LCM_DIVIDES =
    |- !m n d. lcm(m,n) divides d <=> m divides d /\ n divides d

  INT_LCM_POS =
    |- !m n. &0 <= lcm(m,n)

  INT_MUL_GCD_LCM =
    |- !m n. gcd(m,n) * lcm(m,n) = abs(m * n)

  INT_MUL_LCM_GCD =
    |- !m n. lcm(m,n) * gcd(m,n) = abs(m * n)

Also made a definition of num_lcm here, changing the later "definition" in
Library/prime.ml into a derived theorem and making some of the first lemmas
there more or less just NUMBER_TAC invocations. This restructuring makes lcms
available without loading any libraries and also keeps the treatments of gcd
and lcm more closely analogous.

Thu 12th Mar 2020       int.ml

Added the following new theorems

  DIVIDES_DIVIDES_DIV_EQ =
    |- ![1;5An d e. d divides n /\ e divides n DIV d <=> d * e divides n

  INT_DIVIDES_DIVIDES_DIV =
    |- !n d e. d divides n ==> (e divides n div d <=> d * e divides n)

  INT_DIVIDES_DIVIDES_DIV_EQ =
    |- !n d e. d divides n /\ e divides n div d <=> d * e divides n

  INT_DIVIDES_DIV_DIVIDES =
    |- !n d e.
           d divides n /\ (n = &0 ==> e = &0)
           ==> (n div d divides e <=> n divides d * e)

  INT_DIVIDES_DIV_SELF =
    |- !n d. d divides n ==> n div d divides n

  INT_DIV_BY_DIV =
    |- !m n. ~(n = &0) /\ m divides n ==> n div (n div m) = m

as well as moving the following back from Library/prime.ml into int.ml,
where they can be easily derived from their integer counterparts.

        DIVIDES_DIVIDES_DIV
        DIVIDES_DIV_DIVIDES
        DIVIDES_DIV_MULT
        DIVIDES_DIV_SELF
        DIVIDES_MOD
        DIV_BY_DIV

Thu 12th Mar 2020       Library/prime.ml, Library/pocklington.ml, Examples/pell.ml, 100/bertrand.ml, 100/constructible.ml

Made another series of removals of ad-hoc lemmas that are largely subsumed
by those elsewhere (e.g. EXP_MONO_LE_SUC by EXP_MONO_LE + NOT_SUC).

        DIFF_SQUARE
        EVEN_SQUARE
        EXP_0
        EXP_4
        EXP_MONO_EQ_SUC
        EXP_MONO_LE_SUC
        EXP_MONO_LT_SUC
        ODD_SQUARE

Wed 11th Mar 2020       arith.ml, Library/prime.ml

Removed a lot of little-used lemmas that are mainly HOL88 relics from
Library/prime.ml, while moving a single one EXP_EXP back into the core
arith.ml file. The following have disappeared (from here, though several
are there in other places too). If these are needed then there are other
theorems very close to them and/or they can trivially be generated by
calling ARITH_RULE:

        ADD_IMP_SUB
        ADD_SUM_DIFF
        CANCEL_TIMES2
        DIFF_LEMMA
        LESS_0_CASES
        LESS_ADD_1
        LESS_ADD_NONZERO
        LESS_ADD_SUC
        LESS_EQ_0
        LESS_LESS_CASES
        LESS_MONO_ADD
        LESS_THM
        MULT_FIX
        MULT_LCANCEL
        MULT_MONO_EQ
        NOT_EVEN_EQ_ODD
        NOT_EXP_0
        NOT_LESS_0
        ZERO_LESS_EXP

Sat  7th Mar 2020       iterate.ml, Library/products.ml, Library/isum.ml

Added slight variants of the "CLOSED" and "RELATED" theorems for iterators,
where the set is assumed nonempty (and now finite in the case of "CLOSED"
whereas that isn't needed for the other version), but you don't need to assume
anything about the neutral element. Systematically added the generic theorem
and the common instances for sums and products, as well as backfilling the
others in the case of "isum" which were previously missing.

  ITERATE_CLOSED_NONEMPTY =
    |- !op. monoidal op
            ==> (!P. (!x y. P x /\ P y ==> P (op x y))
                     ==> (!f s.
                              FINITE s /\ ~(s = {}) /\ (!x. x IN s ==> P (f x))
                              ==> P (iterate op s f)))

  ITERATE_RELATED_NONEMPTY =
    |- !op. monoidal op
            ==> (!R. (!x1 y1 x2 y2.
                          R x1 x2 /\ R y1 y2 ==> R (op x1 y1) (op x2 y2))
                     ==> (!f g s.
                              FINITE s /\
                              ~(s = {}) /\
                              (!x. x IN s ==> R (f x) (g x))
                              ==> R (iterate op s f) (iterate op s g)))

  NSUM_CLOSED_NONEMPTY =
    |- !P f s.
           FINITE s /\
           ~(s = {}) /\
           (!x y. P x /\ P y ==> P (x + y)) /\
           (!a. a IN s ==> P (f a))
           ==> P (nsum s f)

  NSUM_RELATED_NONEMPTY =
    |- !R f g s.
           (!m n m' n'. R m n /\ R m' n' ==> R (m + m') (n + n')) /\
           FINITE s /\
           ~(s = {}) /\
           (!x. x IN s ==> R (f x) (g x))
           ==> R (nsum s f) (nsum s g)

  SUM_CLOSED_NONEMPTY =
    |- !P f s.
           FINITE s /\
           ~(s = {}) /\
           (!x y. P x /\ P y ==> P (x + y)) /\
           (!a. a IN s ==> P (f a))
           ==> P (sum s f)

  SUM_RELATED_NONEMPTY =
    |- !R f g s.
           (!m n m' n'. R m n /\ R m' n' ==> R (m + m') (n + n')) /\
           FINITE s /\
           ~(s = {}) /\
           (!x. x IN s ==> R (f x) (g x))
           ==> R (sum s f) (sum s g)

  NPRODUCT_CLOSED_NONEMPTY =
    |- !P f s.
           FINITE s /\
           ~(s = {}) /\
           (!x y. P x /\ P y ==> P (x * y)) /\
           (!a. a IN s ==> P (f a))
           ==> P (nproduct s f)

  NPRODUCT_RELATED_NONEMPTY =
    |- !R f g s.
           (!m n m' n'. R m n /\ R m' n' ==> R (m * m') (n * n')) /\
           FINITE s /\
           ~(s = {}) /\
           (!i. i IN s ==> R (f i) (g i))
           ==> R (nproduct s f) (nproduct s g)

  IPRODUCT_CLOSED_NONEMPTY =
    |- !P f s.
           FINITE s /\
           ~(s = {}) /\
           (!x y. P x /\ P y ==> P (x * y)) /\
           (!a. a IN s ==> P (f a))
           ==> P (iproduct s f)

  IPRODUCT_RELATED_NONEMPTY =
    |- !R f g s.
           (!m n m' n'. R m n /\ R m' n' ==> R (m * m') (n * n')) /\
           FINITE s /\
           ~(s = {}) /\
           (!i. i IN s ==> R (f i) (g i))
           ==> R (iproduct s f) (iproduct s g)

  PRODUCT_CLOSED_NONEMPTY =
    |- !P f s.
           FINITE s /\
           ~(s = {}) /\
           (!x y. P x /\ P y ==> P (x * y)) /\
           (!a. a IN s ==> P (f a))
           ==> P (product s f)

  PRODUCT_RELATED_NONEMPTY =
    |- !R f g s.
           (!m n m' n'. R m n /\ R m' n' ==> R (m * m') (n * n')) /\
           FINITE s /\
           ~(s = {}) /\
           (!i. i IN s ==> R (f i) (g i))
           ==> R (product s f) (product s g)

  ISUM_CLOSED =
    |- !P f s.
           P (&0) /\
           (!x y. P x /\ P y ==> P (x + y)) /\
           (!a. a IN s ==> P (f a))
           ==> P (isum s f)

  ISUM_RELATED =
    |- !R f g s.
           R (&0) (&0) /\
           (!m n m' n'. R m n /\ R m' n' ==> R (m + m') (n + n')) /\
           FINITE s /\
           (!x. x IN s ==> R (f x) (g x))
           ==> R (isum s f) (isum s g)

  ISUM_CLOSED_NONEMPTY =
    |- !P f s.
           FINITE s /\
           ~(s = {}) /\
           (!x y. P x /\ P y ==> P (x + y)) /\
           (!a. a IN s ==> P (f a))
           ==> P (isum s f)

  ISUM_RELATED_NONEMPTY =
    |- !R f g s.
           (!m n m' n'. R m n /\ R m' n' ==> R (m + m') (n + n')) /\
           FINITE s /\
           ~(s = {}) /\
           (!x. x IN s ==> R (f x) (g x))
           ==> R (isum s f) (isum s g)

Fri  6th Mar 2020       Library/card.ml

Added a few more natural cardinality lemmas, including cardinality of
function images where all fibres have the same cardinal:

  CARD_EQ_DISJOINT_UNIONS =
    |- !s t.
           pairwise DISJOINT s /\ (!u. u IN s ==> u =_c t)
           ==> UNIONS s =_c s *_c t

  CARD_EQ_IMAGE_MUL_FIBRES =
    |- !f s t.
           (!x. x IN s ==> {z | z IN s /\ f z = f x} =_c t)
           ==> IMAGE f s *_c t =_c s

  CARD_EQ_IMAGES =
    |- !f g s.
           (!x y. x IN s /\ y IN s ==> (f x = f y <=> g x = g y))
           ==> IMAGE f s =_c IMAGE g s

  CARD_LE_DISJOINT_UNIONS =
    |- !s t.
         pairwise DISJOINT s /\ (!u. u IN s ==> t <=_c u)
         ==> s *_c t <=_c UNIONS s

  CARD_LE_IMAGES =
    |- !f g s.
           (!x y. x IN s /\ y IN s /\ g x = g y ==> f x = f y)
           ==> IMAGE f s <=_c IMAGE g s

Sat 29th Feb 2020       Examples/nist_curves.ml

Added a new Examples file giving basic properties of the NIST-recommended
(though see https://eprint.iacr.org/2015/1018.pdf) elliptic curves over
prime-order fields, P-384 and friends. This file sets up the parameters
for P-192, P-224, P-256, P-384 and P-521, defines those curve groups in affine
Weierstrass form, and shows they do indeed form groups and have the orders
claimed in the NIST documents; it is also proved here that those orders are
prime and hence that the groups are cyclic, plus a few other expected
properties of the NIST parameters.

Sat 29th Feb 2020       Library/ringtheory.ml

Made a small tweak to the totalization process inside INTEGRAL_DOMAIN_RULE,
keeping the names of the monomorphically mapped variables instead of choosing
genvars for them. This makes it easier to maintain control over the variable
ordering in the Groebner basis process simply by alphabetic choices at the top
level.

Sat 29th Feb 2020       Library/ringtheory.ml

Added a few more basic ring lemmas:

  RING_CHAR_DIVIDES_MUL =
    |- !r m n.
         integral_domain r \/ field r
         ==> (ring_char r divides m * n <=>
              ring_char r divides m \/ ring_char r divides n)

  RING_CHAR_DIVIDES_PRIME =
    |- !r p.
         (integral_domain r \/ field r) /\ prime p
         ==> (ring_char r divides p <=> ring_char r = p)

  RING_INV_0 =
     |- !r. ring_inv r (ring_0 r) = ring_0 r

Sat 29th Feb 2020       int.ml

Added a couple more basic lemmas about primes to the core int.ml file,
so they can be deployed without loading all the number theory material in the
Library files. Moreover they are not already present in exactly this sharpened
form anyway.

  ZERO_ONE_OR_PRIME_DIVPROD =
    |- !p a b.
           p = 0 \/ p = 1 \/ prime p
           ==> (p divides a * b <=> p divides a \/ p divides b)

  ZERO_ONE_OR_PRIME =
    |- !p. p = 0 \/ p = 1 \/ prime p <=>
           (!a b. p divides a * b ==> p divides a \/ p divides b)

Fri 28th Feb 2020       grobner.ml

Made a bugfix / optimization to the proof replay in the grobner.ml procedure.
In cases where there are no negated equations (i.e. you are originally just
trying to refute a set of equations, not show that some other equation follows
from them), it tries to replay the proof directly rather than go via the
circuitous (and sometimes very inefficient) route of computing the cofactors
explicitly, doing the weak->strong Nullstellensatz transform etc. But this does
not in general work if there are non-integer constants in the trace, e.g.

  # INT_RING `&3 * x + &1:int  = &0 /\ &7 * x = &43 ==> F`;;
  1 basis elements and 0 critical pairs
  Exception: Failure "integer argument required".

Changed this so that unless the Rabinowitsch theorem provided is non-trivial,
it will do a more careful "scaled" version of proof replay. The above now
works, and refutation in non-field integral domains (or ostensible ones,
i.e. fields where the field properties aren't supplied to the generic
procedure) can often become more efficient as a result since they don't need to
go through the lengthier path. Also added a more informative message about
how the proof generation is done, so you get exactly one of

 "Translating certificate to HOL inferences"    (cofactor certificate)
 "Generating HOL version of proof"              (direct proof replay)
 "Generating HOL version of scaled proof"       (integer-scaled proof replay)

Thu 27th Feb 2020       arith.ml, int.ml, Library/words.ml

Moved out of the words theory into the core two conversions that seemed
generally useful enough not to hide there, the transformations they do
otherwise being a bit tedious to orchestrate: MOD_DOWN_CONV and
INT_REM_DOWN_CONV.

Thu 27th Feb 2020       sets.ml

Added a few theorems that help to chain through standard constructions for
assertions of the form "s is finite and |s| <= n", which otherwise sometimes
have to be unpacked and some work duplicated:

  FINITE_CARD_LE_IMAGE;;
    |- !f s n.
           FINITE s /\ CARD s <= n
           ==> FINITE(IMAGE f s) /\ CARD(IMAGE f s) <= n

  FINITE_CARD_LE_SUBSET;;
    |- !s t n.
           s SUBSET t /\ FINITE t /\ CARD t <= n ==> FINITE s /\ CARD s <= n

  FINITE_CARD_LE_UNION;;
    |- !s t m n.
           (FINITE s /\ CARD s <= m) /\ FINITE t /\ CARD t <= n
           ==> FINITE(s UNION t) /\ CARD(s UNION t) <= m + n

  FINITE_CARD_LE_UNIONS;;
    |- !s t m n.
           (!x. x IN s ==> FINITE(t x) /\ CARD(t x) <= n) /\
           FINITE s /\
           CARD s <= m
           ==> FINITE(UNIONS {t x | x IN s}) /\
               CARD(UNIONS {t x | x IN s}) <= m * n

Wed 26th Feb 2020       ind_types.ml

Bound the distinctness and injectivity theorems for the option type to names:

  option_DISTINCT = |- !a. ~(SOME a = NONE)

  option_INJ  = |- !a b. SOME a = SOME b <=> a = b

Wed 26th Feb 2020       Library/ringtheory.ml

Added a couple more forgotten trivialities about the ring of intgers mod n:

  CARD_INTEGER_MOD_RING =
    |- !n. ~(n = 0) ==> CARD(ring_carrier(integer_mod_ring n)) = n

  INTEGER_MOD_RING_POW =
    |- !n a k. ring_pow (integer_mod_ring n) a k = a pow k rem &n

Tue 25th Feb 2020       Library/ringtheory.ml

Added two new carrier membership tools RING_CARRIER_RULE and RING_CARRIER_TAC
(both of which basically just do the obvious backchaining with a few tweaks),
as well as improving the implementation of RING_TAC (so it doesn't call the
core rule twoce) and fixing a big in RING_INTEGRAL_DOMAIN_UNIVERSAL where it
was not writing away "ring_of_num" terms in the input in the initial
simplification step.

Mon 24th Feb 2020       ind_types.ml

Added a trivial but occasionally handy rewrite for the option type:

  FORALL_OPTION_THM =
    |- P. (!x. P x) <=> P NONE /\ (!a. P (SOME a))

Mon 24th Feb 2020       Library/ringtheory.ml

Added a definition of the ring of integers mod n. As with the analogous group
thing "integer_mod_group", this defaults to the full ring of integers for
n = 0, which makes quite a few of the theorems work more smoothly without case
distinctions. New theorems:

  FIELD_INTEGER_MOD_RING =
    |- !n. field (integer_mod_ring n) <=> prime n

  FINITE_INTEGER_MOD_RING =
    |- !n. FINITE(ring_carrier(integer_mod_ring n)) <=> ~(n = 0)

  FINITE_INTEGRAL_DOMAIN_EQ_FIELD =
    |- !r. FINITE(ring_carrier r) ==> (integral_domain r <=> field r)

  INTEGER_MOD_RING =
    |- ring_carrier(integer_mod_ring 0) = (:int) /\
       (!n. 0 < n
            ==> ring_carrier(integer_mod_ring n) = {m | &0 <= m /\ m < &n}) /\
       (!n. ring_0 (integer_mod_ring n) = &0) /\
       (!n. ring_1 (integer_mod_ring n) = &1 rem &n) /\
       (!n. ring_neg (integer_mod_ring n) = (\a. --a rem &n)) /\
       (!n. ring_add (integer_mod_ring n) = (\a b. (a + b) rem &n)) /\
       (!n. ring_mul (integer_mod_ring n) = (\a b. (a * b) rem &n))

  INTEGER_MOD_RING_ASSOCIATES =
    |- !n x y.
           ring_associates (integer_mod_ring n) x y <=>
           x IN ring_carrier(integer_mod_ring n) /\
           y IN ring_carrier(integer_mod_ring n) /\
           gcd(x,&n) = gcd(y,&n)

  INTEGER_MOD_RING_CHAR =
    |- !n. ring_char (integer_mod_ring n) = n

  INTEGER_MOD_RING_DIVIDES =
    |- !n a b.
           ring_divides (integer_mod_ring n) a b <=>
           a IN ring_carrier(integer_mod_ring n) /\
           b IN ring_carrier(integer_mod_ring n) /\
           gcd(a,&n) divides b

  INTEGER_MOD_RING_OF_INT =
    |- !n x. ring_of_int (integer_mod_ring n) x = x rem &n

  INTEGER_MOD_RING_OF_NUM =
    |- !n k. ring_of_num (integer_mod_ring n) k = &k rem &n

  INTEGER_MOD_RING_UNIT =
    |- !n x.
           ring_unit (integer_mod_ring n) x <=>
           x IN ring_carrier(integer_mod_ring n) /\ coprime(x,&n)

  INTEGRAL_DOMAIN_INTEGER_MOD_RING =
    |- !n. integral_domain (integer_mod_ring n) <=> n = 0 \/ prime n

  TRIVIAL_INTEGER_MOD_RING =
    |- !n. trivial_ring (integer_mod_ring n) <=> n = 1

Mon 24th Feb 2020       Library/pocklington.ml, Library/grouptheory.ml

Added a few more basic lemmas including analogous uniqueness for prime
order in the general group case and the particular case of modular
arithmetic:

  GROUP_ELEMENT_ORDER_EQ_2_ALT =
    |- !G x.
           x IN group_carrier G
           ==> (group_element_order G x = 2 <=>
                ~(x = group_id G) /\ group_inv G x = x)

  GROUP_ELEMENT_ORDER_UNIQUE_PRIME =
    |- !G x p.
           x IN group_carrier G /\ prime p
           ==> (group_element_order G x = p <=>
                ~(x = group_id G) /\ group_pow G x p = group_id G)

  ORDER_EQ_1 =
    |- !n a. order n a = 1 <=> (a == 1) (mod n)

  ORDER_UNIQUE_PRIME =
    |- !n a p.
           prime p
           ==> (order n a = p <=> ~(a == 1) (mod n) /\ (a EXP p == 1) (mod n))

Mon 24th Feb 2020       sets.ml, 100/two_squares.ml, 100/four_squares.ml

Factored out the core lemmas about parity of the set of fixed points of
an involution from the two Zagier-style "Great 100 theorems", since they
are a bit more generally applicable:

  INVOLUTION_EVEN_NOFIXPOINTS =
    |- !f s.
         FINITE s /\ (!x. x IN s ==> f x IN s /\ ~(f x = x) /\ f (f x) = x)
         ==> EVEN(CARD s)

  INVOLUTION_EVEN_FIXPOINTS =
    |- !f s.
         FINITE s /\ (!x. x IN s ==> f x IN s /\ f (f x) = x)
         ==> (EVEN(CARD {x | x IN s /\ f x = x}) <=> EVEN(CARD s))

Mon 24th Feb 2020       int.ml, Library/prime.ml

Moved a couple more very basic divisibility theorems back into the core,
to make it easier to use them in a rudimentary way without loading lots
of additional material:

  GCD =
    |- !a b.
         (gcd(a,b) divides a /\ gcd(a,b) divides b) /\
         (!e. e divides a /\ e divides b ==> e divides gcd(a,b))

  coprime =
    |- coprime(a,b) <=> !d. d divides a /\ d divides b ==> d = 1

Mon 24th Feb 2020       int.ml

Added a few more basic lemmas about intger remainders:

  INT_LT_REM_EQ =
    |- !m n. m rem n < n <=> &0 < n \/ n = &0 /\ m < &0

  INT_REM_POS =
    |- !a b. ~(b = &0) ==> &0 <= a rem b

  INT_REM_POS_EQ =
    |- !m n. &0 <= m rem n <=> n = &0 ==> &0 <= m

Fri 21st Feb 2020       Library/primitive.ml

Renamed a few existing theorems where the original name seemed ill-chosen
(since they are about counting the number of preimages giving a residue,
not the number of residues themselves)

  COUNT_POWER_RESIDUES_MODULO_ODD
          -> COUNT_ROOTS_MODULO_ODD_GEN

  COUNT_POWER_RESIDUES_MODULO_ODD_ALT
          -> COUNT_ROOTS_MODULO_ODD_ALT_GEN

  COUNT_POWER_RESIDUES_MODULO_PRIMITIVE
          -> COUNT_ROOTS_MODULO_PRIMITIVE_GEN

  COUNT_POWER_RESIDUES_MODULO_PRIMITIVE_ALT
          -> COUNT_ROOTS_MODULO_PRIMITIVE_GEN_ALT

And then added a few new theorems, one of them taking over the old name

  COUNT_POWER_RESIDUES_MODULO_PRIMITIVE =
    |- !n k.
           ~(n = 0) /\ (?g. order n g = phi n)
           ==> {a | a < n /\ coprime(n,a) /\ (?x. (x EXP k == a) (mod n))}
               HAS_SIZE phi n DIV gcd(k,phi n)

  COUNT_QUADRATIC_RESIDUES_MODULO_PRIMITIVE =
    |- !n. 3 <= n /\ (?g. order n g = phi n)
           ==> {a | a < n /\ coprime(n,a) /\ (?x. (x EXP 2 == a) (mod n))}
               HAS_SIZE phi n DIV 2

  POWER_RESIDUE_EXISTS =
    |- !n k.
           ~(n = 0)
           ==> (?a. a < n /\ coprime(n,a) /\ (?x. (x EXP k == a) (mod n)))

  QUADRATIC_NONRESIDUE_EXISTS =
    |- !n. (?a. a < n /\ coprime(n,a) /\ ~(?x. (x EXP 2 == a) (mod n))) <=>
           3 <= n

Fri 21st Feb 2020       sets.ml

Added a couple more trivial things about proper subset related to cardinality:

  CARD_PSUBSET_IMP =
    |- !a b. a SUBSET b /\ ~(CARD a = CARD b) ==> a PSUBSET b

  CARD_PSUBSET_EQ =
    |- !a b. FINITE b /\ a SUBSET b ==> (a PSUBSET b <=> CARD a < CARD b)

Fri 14th Feb 2020       Library/pocklington.ml

Added two more simple consequences of existing theorems:

  PHI_LIMIT_COMPOSITE =
    |- !n. ~prime n /\ ~(n = 0) /\ ~(n = 1) ==> phi n < n - 1

  PRIMITIVE_ROOT_IMP_COPRIME =
    |- !n g. order n g = phi n ==> n = 0 \/ coprime(n,g)

Mon 10th Feb 2020       Examples/zolotarev.ml [new file]

Added a new Examples file with Zolotarev's characterization of the Jacobi
symbol (for odd modulus) as the sign of the permutation induced by
multplication modulo.

Sun  9th Feb 2020       Library/permutations.ml

Added various new facts about permutations, including some results on
transferring them "isomorphically" and forming Cartesian products of them,
as well as concrete results about cyclic permutations, in the form of
modular successor/addition:

  EVENPERM_CYCLIC =
    |- !n. evenperm (\i. if i < n then (i + 1) MOD n else i) <=>
           n = 0 \/ ODD n

  EVENPERM_CYCLIC_N =
    |- !n k.
           evenperm (\i. if i < n then (i + k) MOD n else i) <=>
           n = 0 \/ ODD n \/ EVEN k

  EVENPERM_ID =
    |- evenperm (\x. x)

  EVENPERM_TRANSFER =
    |- !f s p q.
           FINITE s /\
           (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
           p permutes s /\
           (!x. x IN s ==> q (f x) = f (p x)) /\
           (!y. ~(y IN IMAGE f s) ==> q y = y)
           ==> (evenperm q <=> evenperm p)

  PERMUTATION_CYCLIC =
    |- !n. permutation (\i. if i < n then (i + 1) MOD n else i)

  PERMUTATION_CYCLIC_N =
    |- !n k. permutation (\i. if i < n then (i + k) MOD n else i)

  PERMUTATION_RESTRICT =
    |- !Q p.
           permutation p /\ (!x. Q (p x) <=> Q x)
           ==> permutation (\i. if Q i then p i else i)

  PERMUTES_ALT =
    |- !p s.
           p permutes s <=>
           (!x. x IN s ==> p x IN s) /\
           (!x. ~(x IN s) ==> p x = x) /\
           (!y. y IN s ==> (?!x. x IN s /\ p x = y))

  PERMUTES_CARTESIAN_PRODUCT =
    |- !p q s t.
           p permutes s /\ q permutes t
           ==> (\(i,j). if i IN s /\ j IN t then p i,q j else i,j) permutes
               s CROSS t

  PERMUTES_CYCLIC =
    |- !n. (\i. if i < n then (i + 1) MOD n else i) permutes {i | i < n}

  PERMUTES_CYCLIC_N =
    |- !n k. (\i. if i < n then (i + k) MOD n else i) permutes {i | i < n}

  PERMUTES_INDUCT_STRONG =
    |- !P s.
           FINITE s /\
           P I /\
           (!a b p.
                a IN s /\ b IN s /\ ~(a = b) /\ P p /\ p permutes s
                ==> P (swap (a,b) o p))
           ==> (!p. p permutes s ==> P p)

  PERMUTES_INVERSE_FUNCTION =
    |- !s p.
           p permutes s <=>
           (?q. (!x. ~(x IN s) ==> p x = x) /\
                (!x. x IN s ==> p x IN s) /\
                (!x. x IN s ==> p (q x) = x /\ q (p x) = x))

  PERMUTES_RESTRICT =
    |- !Q p s.
           p permutes s /\ (!x. x IN s ==> (Q (p x) <=> Q x))
           ==> (\i. if Q i then p i else i) permutes s

  PERMUTES_RESTRICT_SET =
    |- !Q p s.
           p permutes s /\ (!x. x IN s ==> (Q (p x) <=> Q x))
           ==> (\i. if Q i then p i else i) permutes {x | x IN s /\ Q x}

  PERMUTES_TRANSFER =
    |- !f p q s.
           p permutes s /\
           (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
           (!x. x IN s ==> q (f x) = f (p x)) /\
           (!y. ~(y IN IMAGE f s) ==> q y = y)
           ==> q permutes IMAGE f s

  PERMUTES_TRANSFER_BIJECTIONS =
    |- !f f' p s t.
           (!x. f' (f x) = x) /\
           (!y. f (f' y) = y) /\
           (!x. x IN s ==> f x IN t) /\
           (!y. y IN t ==> f' y IN s)
           ==> (f' o p o f permutes s <=> p permutes t)

  SIGN_CARTESIAN_PRODUCT =
    |- !p q s t.
           FINITE s /\ FINITE t /\ p permutes s /\ q permutes t
           ==> sign (\(i,j). if i IN s /\ j IN t then p i,q j else i,j) =
               sign p pow CARD t * sign q pow CARD s

  SIGN_CYCLIC =
    |- !n k.
           sign (\i. if i < n then (i + k) MOD n else i) =
           -- &1 pow (k * (n - 1))

  SIGN_CYCLIC_N =
    |- !n k.
           sign (\i. if i < n then (i + k) MOD n else i) =
           -- &1 pow (k * (n - 1))

  SIGN_ID =
    |- sign (\x. x) = &1

  SIGN_TRANSFER =
    |- !f s p q.
           FINITE s /\
           (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
           p permutes s /\
           (!x. x IN s ==> q (f x) = f (p x)) /\
           (!y. ~(y IN IMAGE f s) ==> q y = y)
           ==> sign q = sign p

Fri  7th Feb 2010       arith.ml, int.ml, Library/prime.ml, Library/pocklington.ml, Library/primitive.ml

Added a wide miscellany of number-theoretic results, including basic
divisibility lemmas, more about primitive roots, quadratic residues and the
Euler totient function, plus additional properties of "inverse_mod" including
the reciprocity property, a.k.a. Arazi's inversion formula.

  CHINESE_REMAINDER_USUAL =
    |- !a b u v. coprime(a,b) ==> (?x. (x == u) (mod a) /\ (x == v) (mod b))

  DIVIDES_DIV_DIVIDES =
    |- !n d e.
           d divides n /\ (n = 0 ==> e = 0)
           ==> (n DIV d divides e <=> n divides d * e)

  DIVIDES_DIV_SELF =
    |- !n d. d divides n ==> n DIV d divides n

  DIV_BY_DIV =
    |- !m n. ~(n = 0) /\ m divides n ==> n DIV (n DIV m) = m

  EVEN_MOD_EVEN =
    |- !m n. EVEN n ==> (EVEN(m MOD n) <=> EVEN m)

  GCD_2_CASES =
    |- (!n. gcd(2,n) = (if EVEN n then 2 else 1)) /\
       (!n. gcd(n,2) = (if EVEN n then 2 else 1))

  GCD_PRIME_CASES =
    |- (!p n. prime p ==> gcd(p,n) = (if p divides n then p else 1)) /\
       (!p n. prime p ==> gcd(n,p) = (if p divides n then p else 1))

  INDUCT_COPRIME_ALT =
    |- !P. P 0 /\
           (!a b. 1 < a /\ 1 < b /\ coprime(a,b) /\ P a /\ P b ==> P (a * b)) /\
           (!p k. prime p ==> P (p EXP k))
           ==> (!n. P n)

  INT_2_DIVIDES_ADD =
    |- !m n. &2 divides m + n <=> &2 divides m <=> &2 divides n

  INT_2_DIVIDES_MUL =
    |- !m n. &2 divides m * n <=> &2 divides m \/ &2 divides n

  INT_2_DIVIDES_POW =
    |- !n k. &2 divides n pow k <=> &2 divides n /\ ~(k = 0)

  INT_2_DIVIDES_SUB =
    |- !m n. &2 divides m - n <=> &2 divides m <=> &2 divides n

  INVERSE_MOD_BOUND_LE =
    |- !n a. inverse_mod n a <= n <=> ~(n = 0)

  INVERSE_MOD_INVERSION =
    |- !m n.
           coprime(m,n)
           ==> m * inverse_mod n m + n * inverse_mod m n = m * n + 1

  INVERSE_MOD_NONZERO =
    |- !n a. coprime(n,a) ==> ~(inverse_mod n a = 0)

  INVERSE_MOD_NONZERO_ALT =
    |- !n a. ~(n divides a) ==> ~(inverse_mod n a = 0)

  MOD_EVEN_2 =
    |- !m n. EVEN n ==> m MOD n MOD 2 = m MOD 2

  ODD_MOD_EVEN =
    |- !m n. EVEN n ==> (ODD(m MOD n) <=> ODD m)

  ORDER_LE_PHI =
    |- !n. ~(n = 0) ==> order n a <= phi n

  PHI_EQ_PRIME =
    |- !p. phi p = p - 1 <=> p = 0 \/ prime p

  POWER_RESIDUE_MODULO_PRIMITIVE_POWER =
    |- !n g m k.
           coprime(n,g) /\ order n g = phi n
           ==> ((?x. (x EXP k == g EXP m) (mod n)) <=> gcd(k,phi n) divides m)

  PRIMITIVE_ROOT_IMAGE =
    |- !n g.
           order n g = phi n
           ==> IMAGE (\i. g EXP i MOD n) {i | i < phi n} =
               {a | coprime(a,n) /\ a < n}

  PRIMITIVE_ROOT_IMAGE_PRIME =
    |- !p g.
           order p g = p - 1
           ==> IMAGE (\i. g EXP i MOD p) {i | i < p - 1} = {a | 0 < a /\ a < p}

  PRIMITIVE_ROOT_IMP_PRIME =
    |- !p g. order p g = p - 1 ==> p = 0 \/ prime p

  PRIMITIVE_ROOT_SURJECTIVE =
    |- !n g a.
           ~(n = 0) /\ order n g = phi n /\ coprime(a,n)
           ==> (?m. m < phi n /\ (a == g EXP m) (mod n))

  PRIMITIVE_ROOT_SURJECTIVE_ALT =
    |- !n g a.
           order n g = phi n /\ coprime(a,n) ==> (?m. (a == g EXP m) (mod n))

  PRIMITIVE_ROOT_SURJECTIVE_PRIME =
    |- !p g a.
           ~(p = 0) /\ order p g = p - 1 /\ coprime(a,p)
           ==> (?m. m < p - 1 /\ (a == g EXP m) (mod p))

  PRIMITIVE_ROOT_SURJECTIVE_PRIME_ALT =
    |- !p g a.
           order p g = p - 1 /\ coprime(a,p) ==> (?m. (a == g EXP m) (mod p))

  QUADRATIC_RESIDUE_MODULO_POWER_2 =
    |- !a k.
           ODD a /\ 3 <= k
           ==> ((?x. (x EXP 2 == a) (mod (2 EXP k))) <=> (a == 1) (mod 8))

  QUADRATIC_RESIDUE_MODULO_POWER_2_STABLE =
    |- !a k.
           ODD a /\ 3 <= k
           ==> ((?x. (x EXP 2 == a) (mod (2 EXP k))) <=>
                (?x. (x EXP 2 == a) (mod 8)))

  QUADRATIC_RESIDUE_MODULO_PRIMITIVE_POWER =
    |- !n g m.
           coprime(n,g) /\ order n g = phi n
           ==> ((?x. (x EXP 2 == g EXP m) (mod n)) <=> 3 <= n ==> EVEN m)

Tue  4th Feb 2020       arith.ml

Added a few rudimentary lemmas about the "minimal" constant, which
was otherwise little more than a binder definition.

  LE_MINIMAL =
   |- !P n. (?r. P r) ==> (n <= (minimal) P <=> (!i. P i ==> n <= i))

  MINIMAL_LBOUND =
   |- !P n. (?r. P r) /\ (!m. m < n ==> ~P m) ==> n <= (minimal) P

  MINIMAL_LE =
   |- !P n. (?r. P r) ==> ((minimal) P <= n <=> (?i. i <= n /\ P i))

  MINIMAL_UBOUND =
   |- !P n. P n ==> (minimal) P <= n

  MINIMAL_UNIQUE =
   |- !P n. P n /\ (!m. m < n ==> ~P m) ==> (minimal) P = n

Fri 31st Jan 2020       Library/jacobi.ml [new file]

Added a new library file giving the definition of and basic results about the
Jacobi symbol. The basic NxN->Z version is "jacobi" and there is an integer
(ZxZ->Z) version "int_jacobi". This development doesn't explicitly break out
the concept of Legendgre symbol, since the Jacobi symbol cleanly subsumes it,
but "100/reciprocity.ml" has an explicit definition if wanted, and the proof
here of reciprocity for the Jacobi symbol repurposes some of that material,
mainly the Gauss's Lemma variants.

Thu 30th Jan 2020       int.ml, Library/integer.ml, Library/prime.ml, Library/primitive.ml

Added a miscellany of theorems all connected with integers, divisibility etc.,
a few filling rather surprising gaps.

  COMPLETE_FACTOR_INDUCT =
    |- !P. P 0 /\
           P 1 /\
           (!p. prime p ==> P p) /\
           (!m n. P m /\ P n ==> P (m * n))
           ==> (!n. P n)

  EXISTS_INT_CASES =
    |- !P. (?x. P x) <=> (?n. P (&n)) \/ (?n. P (-- &n))

  INT_CONG_NUM_EXISTS =
    |- !x y. (y = &0 ==> &0 <= x) ==> (?n. (&n == x) (mod y))

  INT_CONG_SOLVE_EQ =
    |- !n a b. (?x. (a * x == b) (mod n)) <=> gcd(a,n) divides b

  INT_DIVIDES_POW_LE_IMP =
    |- !p m n. m <= n ==> p pow m divides p pow n

  INT_OF_NUM_POWER_RESIDUE =
    |- !n k a. (?x. (x EXP k == a) (mod n)) <=> (?x. (x pow k == &a) (mod &n))

  POWER_RESIDUE_MODULO_PRIMITIVE_ORDER =
    |- !n a k.
           coprime(n,a) /\ (?x. order n x = phi n)
           ==> ((?x. (x EXP k == a) (mod n)) <=>
                gcd(k,phi n) divides phi n DIV order n a)

  POWER_RESIDUE_MODULO_PRIMITIVE_ORDER_ALT =
    |- !n a k.
           coprime(n,a) /\ (?x. order n x = phi n)
           ==> ((?x. (x EXP k == a) (mod n)) <=>
                order n a divides phi n DIV gcd(k,phi n))

  QUADRATIC_RESIDUE_MODULO_ODD_POWER =
    |- !n a k.
           ODD n /\ coprime(n,a)
           ==> ((?x. (x EXP 2 == a) (mod (n EXP k))) <=>
                k = 0 \/ (?x. (x EXP 2 == a) (mod n)))

  QUADRATIC_RESIDUE_MODULO_PRIMITIVE_ORDER =
    |- !n a.
           coprime(n,a) /\ 3 <= n /\ (?x. order n x = phi n)
           ==> ((?x. (x EXP 2 == a) (mod n)) <=> EVEN(phi n DIV order n a))

Wed 29th Jan 2020       int.ml

Added a simple but usefully sharp fact about commuting addition and
truncating division over N:

  |- !d a b. d divides a \/ d divides b ==> (a + b) DIV d = a DIV d + b DIV d

Tue 28th Jan 2020       Library/products.ml, 100/reciprocity.ml

Added four groups of analogous product theorems for real, integer and natural
number products:

  IPRODUCT_INJECTION =
    |- !f p s.
           FINITE s /\
           (!x. x IN s ==> p x IN s) /\
           (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y)
           ==> iproduct s (f o p) = iproduct s f

  IPRODUCT_RELATED =
    |- !R f g s.
           R (&1) (&1) /\
           (!m n m' n'. R m n /\ R m' n' ==> R (m * m') (n * n')) /\
           FINITE s /\
           (!i. i IN s ==> R (f i) (g i))
           ==> R (iproduct s f) (iproduct s g)

  IPRODUCT_RESTRICT =
    |- !f s.
           FINITE s
           ==> iproduct s (\i. if i IN s then f i else &1) = iproduct s f

  IPRODUCT_RESTRICT_SET =
    |- !P s f.
           iproduct {i | i IN s /\ P i} f =
           iproduct s (\i. if P i then f i else &1)

  NPRODUCT_INJECTION =
    |- !f p s.
           FINITE s /\
           (!x. x IN s ==> p x IN s) /\
           (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y)
           ==> nproduct s (f o p) = nproduct s f

  NPRODUCT_RELATED =
    |- !R f g s.
           R 1 1 /\
           (!m n m' n'. R m n /\ R m' n' ==> R (m * m') (n * n')) /\
           FINITE s /\
           (!i. i IN s ==> R (f i) (g i))
           ==> R (nproduct s f) (nproduct s g)

  NPRODUCT_RESTRICT =
    |- !f s.
           FINITE s
           ==> nproduct s (\i. if i IN s then f i else 1) = nproduct s f

  NPRODUCT_RESTRICT_SET =
    |- !P s f.
           nproduct {i | i IN s /\ P i} f =
           nproduct s (\i. if P i then f i else 1)

  PRODUCT_INJECTION =
    |- !f p s.
           FINITE s /\
           (!x. x IN s ==> p x IN s) /\
           (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y)
           ==> product s (f o p) = product s f

  PRODUCT_RELATED =
    |- !R f g s.
           R (&1) (&1) /\
           (!m n m' n'. R m n /\ R m' n' ==> R (m * m') (n * n')) /\
           FINITE s /\
           (!i. i IN s ==> R (f i) (g i))
           ==> R (product s f) (product s g)

  PRODUCT_RESTRICT =
    |- !f s.
           FINITE s
           ==> product s (\i. if i IN s then f i else &1) = product s f

  PRODUCT_RESTRICT_SET =
    |- !P s f.
           product {i | i IN s /\ P i} f =
           product s (\i. if P i then f i else &1)

Removed a few effective duplications from 100/reciprocity.ml including
NPRODUCT_INJECTION above.

Fri 24th Jan 2020       Library/prime.ml

Removed the unnecessary 1 <= n hypothesis from

  DIVIDES_DIVIDES_DIV =
   |- !n d e. d divides n ==> (e divides n DIV d <=> d * e divides n)

and likewise a ~(n = 0) hypothesis from

  POWER_RESIDUE_MODULO_PRIMITIVE =
    |- !n a k.
         coprime(n,a) /\ (?x. order n x = phi n)
         ==> ((?x. (x EXP k == a) (mod n)) <=>
              (a EXP (phi n DIV gcd(k,phi n)) == 1) (mod n))

Thu 23rd Jan 2020       int.ml, Library/integer.ml

Added miscelleneous trivia around integer divisibility:

  INT_CONG_MOD_ABS =
    |- !a b n. (a == b) (mod abs n) <=> (a == b) (mod n)

  INT_COPRIME_LREM =
    |- !a b. coprime(a rem n,n) <=> coprime(a,n)

  INT_COPRIME_RREM =
   |- !m n. coprime(m,n rem m) <=> coprime(m,n)

  INT_REM_RABS =
   |- !x y. x rem abs y = x rem y

  NUM_OF_INT_ADD =
    |- !x y.
           &0 <= x /\ &0 <= y
           ==> num_of_int (x + y) = num_of_int x + num_of_int y

  NUM_OF_INT_MUL =
    |- !x y.
           &0 <= x /\ &0 <= y
           ==> num_of_int (x * y) = num_of_int x * num_of_int y

  NUM_OF_INT_POW =
   |- !x n. &0 <= x ==> num_of_int (x pow n) = num_of_int x EXP n

Wed 22nd Jan 2020       int.ml

Added a few trivial integer remainder theorems, analogs of things already
there for the natural numbers

  INT_CONG_LREM =
    |- !x y n. (x rem n == y) (mod n) <=> (x == y) (mod n)

  INT_CONG_RREM =
    |- !x y n. (x == y rem n) (mod n) <=> (x == y) (mod n)

  INT_REM_REM_MUL =
    |- (!m n p. m rem (n * p) rem n = m rem n) /\
       (!m n p. m rem (n * p) rem p = m rem p)

Tue 21st Jan 2020       Library/pocklington.ml

Added a couple of trivial but handy formulations of congruences mod 2:

  CONG_MOD_2 =
    |- !a b. (a == b) (mod 2) <=> (EVEN a <=> EVEN b)

  CONG_MOD_2_ALT =
    |- !a b. (a == b) (mod 2) <=> (ODD a <=> ODD b)

Mon 20th Jan 2020       int.ml, Library/products.ml

Added a definition of "iproduct" (product over integers) to the Library file
"Library/products.ml", with theorems exactly analogous to those of real
products minus the ones about inversion and division. The only other difference
is that there is no "prioritize_int()" to avoid disturbing any existing
applications.

In support, added two trivial theorems where the analogs of existing real
theorems were forgotten:

  INT_LE_MUL2 =
    |- !w x y z. &0 <= w /\ w <= x /\ &0 <= y /\ y <= z ==> w * y <= x * z

  INT_LT_MUL2 =
    |- !w x y z. &0 <= w /\ w < x /\ &0 <= y /\ y < z ==> w * y < x * z

Sun  5th Jan 2020       Examples/miller_rabin.ml [new file]

Added a new file giving some results about Miller-Rabin strong probable primes
or pseudoprimes (in our naming we  use "pseudoprime" inclusively to include
primes). This consists of the basic definitions, a few elementary properties
and relations with primality, and then the main "1/4 of (coprime) numbers"
upper bounds on the density of pseudoprime bases for a composite number.

Sat 28th Dec 2019       arith.ml, Library/prime.ml, Library/pocklington.ml

Added a few more basic number-theoretic lemmas:

  DIV_EQ_SELF =
    |- !m n. m DIV n = m <=> m = 0 \/ n = 1

  LCM_EQ_MULT =
    |- !m n. lcm(m,n) = m * n <=> m = 0 \/ n = 0 \/ coprime(m,n)

  LCM_LE_MULT =
    |- !m n. lcm(m,n) <= m * n

  LE_LCM =
    |- (!m n. m <= lcm(m,n) <=> n = 0 ==> m = 0) /\
       (!m n. n <= lcm(m,n) <=> m = 0 ==> n = 0)

  MAX_LE_LCM =
    |- !m n. (m = 0 <=> n = 0) ==> MAX m n <= lcm(m,n)

  MAX_LE_LCM_EQ =
    |- !m n. MAX m n <= lcm(m,n) <=> m = 0 <=> n = 0

  ORDER_DIVIDES_MAXIMAL =
    |- !p. ~(p = 1)
           ==> ?n. coprime(p,n) /\
                   !m. coprime(p,m) ==> order p m divides order p n


Fri 27th Dec 2019       Library/prime.ml

Added the simple fact that one can choose a number with a given prime
factorization, expressed via index:

  PRIME_FACTORIZATION_INDEX =
    |- !k. FINITE {p | prime p /\ ~(k p = 0)}
           ==> ?n. ~(n = 0) /\ !p. prime p ==> index p n = k p

Thu 26th Dec 2019       Library/pocklington.ml

Added a few more basic theorems, mainly analogs for the special case
of natural number "order" of existing theorems for "group_element_order":

  CONG_MULT_1 =
    |- !n x y. (x == 1) (mod n) /\ (y == 1) (mod n) ==> (x * y == 1) (mod n)

  ORDER_LCM_EXISTS =
    |- !p a b. ?c. order p c = lcm(order p a,order p b)

  ORDER_MUL_DIVIDES =
    |- !p a b. order p (a * b) divides order p a * order p b

  ORDER_MUL_EQ =
    |- !p a b.
           coprime(order p a,order p b)
           ==> order p (a * b) = order p a * order p b

Tue 24th Dec 2019       int.ml, Library/prime.ml

Added a few more simple number-theoretic lemmas:

  GCD_MUL_COPRIME =
    |- (!a b c. coprime(a,b) ==> gcd(a,b * c) = gcd(a,c)) /\
       (!a b c. coprime(a,c) ==> gcd(a,b * c) = gcd(a,b)) /\
       (!a b c. coprime(b,c) ==> gcd(a,b * c) = gcd(a,b) * gcd(a,c)) /\
       (!a b c. coprime(a,c) ==> gcd(a * b,c) = gcd(b,c)) /\
       (!a b c. coprime(b,c) ==> gcd(a * b,c) = gcd(a,c)) /\
       (!a b c. coprime(a,b) ==> gcd(a * b,c) = gcd(a,c) * gcd(b,c))

  INDEX_UNIQUE_ALT =
    |- !n p k.
           index p n = k <=>
           (if p = 1 \/ n = 0
            then k = 0
            else p EXP k divides n /\ ~(p EXP (k + 1) divides n))

  INDEX_UNIQUE_EQ =
    |- !n p k.
           index p n = k <=>
           (if p = 1 \/ n = 0 then k = 0 else !j. p EXP j divides n <=> j <= k)

  PROPERLY_DIVIDES_LE_IMP =
    |- !m n. m divides n /\ ~(n = 0) /\ ~(m = n) ==> 2 * m <= n

Mon 23rd Dec 2019       Library/prime.ml, Library/pocklington.ml, Library/multiplicative.ml, Library/primitive.ml, Library/modmul_group.ml

Added some new theorems and reshuffled existing material, in particular
moving the "inverse_mod" stuff from "Library/modmul_group.ml" to the pure
number theory file "Library/pocklington.ml". Furthermore added a
dependency on "Library/products.ml" to "Library/multiplicative.ml", since
it seems unnatural not to have MULTIPLICATIVE_EXPAND and PHI_EXPAND use it.

  ABELIAN_GROUP_ELEMENT_ORDER_DIVIDES_MAXIMAL_ALT =
    |- !G. abelian_group G /\ FINITE(group_carrier G)
           ==> ?x. x IN group_carrier G /\
                   !y. y IN group_carrier G
                       ==> group_pow G y (group_element_order G x) =
                           group_id G

  ABELIAN_GROUP_ELEMENT_ORDER_LCM_EXISTS =
    |- !G x y.
         abelian_group G /\ x IN group_carrier G /\ y IN group_carrier G
         ==> ?z. z IN group_carrier G /\
                 group_element_order G z =
                 lcm(group_element_order G x,group_element_order G y)

  ABELIAN_GROUP_ORDER_DIVIDES_MAXIMAL =
    |- !G. abelian_group G /\ FINITE(group_carrier G)
           ==> ?x. x IN group_carrier G /\
                   !y. y IN group_carrier G
                       ==> group_element_order G y divides
                           group_element_order G x

  CONG_SQUARE_1_PRIME_POWER =
    |- !p k x.
           prime p /\ ~(p = 2)
           ==> ((x EXP 2 == 1) (mod (p EXP k)) <=>
                (x == 1) (mod (p EXP k)) \/ (x == p EXP k - 1) (mod (p EXP k)))

  COUNT_PRIMITIVE_ROOTS =
    |- !n. {x | x < n /\ order n x = phi n} HAS_SIZE
           (if n = 0 \/
               n = 2 \/
               n = 4 \/
               ?p k. prime p /\ 3 <= p /\ (n = p EXP k \/ n = 2 * p EXP k)
            then phi(phi n)
            else 0)

  COUNT_PRIMITIVE_ROOTS_ALT =
    |- !n. {a | a < n /\ coprime(n,a) /\ order n a = phi n} HAS_SIZE
           (if n = 0 \/
               n = 2 \/
               n = 4 \/
               ?p k. prime p /\ 3 <= p /\ (n = p EXP k \/ n = 2 * p EXP k)
            then phi (phi n)
            else 0)

  GCD_ONE =
    |- !a b. coprime(a,b) ==> gcd(a,b) = 1

  GROUP_ELEMENT_ORDER_LCM_EXISTS =
    |- !G x y.
           x IN group_carrier G /\
           y IN group_carrier G /\
           group_mul G x y = group_mul G y x
           ==> ?z. z IN group_carrier G /\
                   group_element_order G z =
                   lcm(group_element_order G x,group_element_order G y)

  MULTIPLICATIVE_EXPAND =
    |- !f n.
           multiplicative f /\ ~(n = 0)
           ==> f n =
               nproduct {p | prime p /\ p divides n} (\p. f(p EXP index p n))

  ORDER_MOD =
    |- !p n. order p (n MOD p) = order p n

  PHI_EXPAND =
    |- !n. phi n =
           (if n = 0
            then 0
            else nproduct {p | prime p /\ p divides n}
                 (\p. p EXP (index p n - 1) * (p - 1)))

  PRIME_DIVPROD_POW_EQ =
    |- !n p a b.
           prime p /\ coprime(a,b)
           ==> (p EXP n divides a * b <=>
                p EXP n divides a \/ p EXP n divides b)

  PRIME_DIVPROD_POW_GEN =
    |- !n p a b.
           prime p /\ ~(p divides gcd(a,b)) /\ p EXP n divides a * b
           ==> p EXP n divides a \/ p EXP n divides b

  PRIME_DIVPROD_POW_GEN_EQ =
    |- !n p a b.
           prime p /\ ~(p divides gcd(a,b))
           ==> (p EXP n divides a * b <=>
                p EXP n divides a \/ p EXP n divides b)

Mon 23rd Dec 2019       Library/products.ml

Removed redundant 0 <= ... clauses (which over N are trivially true)
from NPRODUCT_LE and NPRODUCT_LE_NUMSEG.

Sat 21st Dec 2019       Library/pocklington.ml, Library/primitive.ml

Added some additional theorems, mainly generalizing the root counts
modulo odd integers, expressed via prime factorization, to general
power residues:

  COUNT_POWER_RESIDUES_MODULO_ODD =
    |- !n a k.
           ODD n /\ coprime(n,a) /\ ~(k = 0)
           ==> {x | x < n /\ (x EXP k == a) (mod n)} HAS_SIZE
               (if !p. prime p /\ p divides n
                       ==> (a EXP
                            ((p EXP (index p n - 1) * (p - 1)) DIV
                             gcd(k,p EXP (index p n - 1) * (p - 1))) ==
                            1)
                           (mod (p EXP index p n))
                then iterate (*) {p | prime p /\ p divides n}
                     (\p. gcd(k,p EXP (index p n - 1) * (p - 1)))
                else 0)


  COUNT_POWER_RESIDUES_MODULO_ODD_ALT =
    |- !n a k.
           ODD n /\ ~(k = 0)
           ==> {x | x < n /\ coprime(n,x) /\ (x EXP k == a) (mod n)} HAS_SIZE
               (if !p. prime p /\ p divides n
                       ==> (a EXP
                            ((p EXP (index p n - 1) * (p - 1)) DIV
                             gcd(k,p EXP (index p n - 1) * (p - 1))) ==
                            1)
                           (mod (p EXP index p n))
                then iterate (*) {p | prime p /\ p divides n}
                     (\p. gcd(k,p EXP (index p n - 1) * (p - 1)))
                else 0)

  COUNT_ROOTS_MODULO_ODD_ALT =
    |- !n k.
           ODD n /\ ~(k = 0)
           ==> {x | x < n /\ coprime(n,x) /\ (x EXP k == 1) (mod n)} HAS_SIZE
               iterate (*) {p | prime p /\ p divides n}
               (\p. gcd(k,p EXP (index p n - 1) * (p - 1)))

  ORDER_EXP =
    |- !p a k.
           ~(k = 0) /\ k divides order p a
           ==> order p (a EXP k) = order p a DIV k

  ORDER_EXP_GEN =
    |- !p a k.
           order p (a EXP k) =
           (if k = 0 then 1 else order p a DIV gcd(order p a,k))

  POWER_RESIDUE_MODULO_ODD =
    |- !n a k.
           ODD n /\ ~(k = 0) /\ coprime(n,a)
           ==> ((?x. (x EXP k == a) (mod n)) <=>
                (!p. prime p /\ p divides n
                     ==> (a EXP
                          ((p EXP (index p n - 1) * (p - 1)) DIV
                           gcd(k,p EXP (index p n - 1) * (p - 1))) ==
                          1)
                         (mod (p EXP index p n))))

Fri 20th Dec 2019       Library/prime.ml, Library/pocklington.ml, Library/primitive.ml, Library/modmul_group.ml

Added another slew of number-theoretic lemmas, various trivia together with
nice characterizations of (and counts of) power residues modulo any n for
which there is a primitive root. This is most clearly stated in the classic
GENERALIZED_EULER_CRITERION and POWER_RESIDUE_MODULO_PRIMITIVE (basically the
same except that the condition for a primitive root is expanded out in the
former).

  COUNT_CONG_SOLVE =
    |- !n a b.
           {x | x < n /\ (a * x == b) (mod n)} HAS_SIZE
           (if ~(n = 0) /\ gcd(n,a) divides b then gcd(n,a) else 0)

  COUNT_CONG_SOLVE_GEN =
    |- !m n a b.
           {x | x < m * n /\ (a * x == b) (mod n)} HAS_SIZE
           (if ~(n = 0) /\ gcd(n,a) divides b then m * gcd(n,a) else 0)

  COUNT_CONG_SOLVE_SIMPLE =
    |- !m n b.
           {x | x < m * n /\ (x == b) (mod n)} HAS_SIZE
           (if n = 0 then 0 else m)

  COUNT_POWER_RESIDUES_MODULO_PRIMITIVE =
    |- !n a k.
           ~(n = 0) /\ ~(k = 0) /\ coprime(n,a) /\ (?x. order n x = phi n)
           ==> {x | x < n /\ (x EXP k == a) (mod n)} HAS_SIZE
               (if (a EXP (phi n DIV gcd(k,phi n)) == 1) (mod n)
                then gcd(k,phi n)
                else 0)

  COUNT_POWER_RESIDUES_MODULO_PRIMITIVE_ALT =
    |- !n a k.
           ~(n = 0) /\ ~(k = 0) /\ (?x. order n x = phi n)
           ==> {x | x < n /\ coprime(n,x) /\ (x EXP k == a) (mod n)} HAS_SIZE
               (if (a EXP (phi n DIV gcd(k,phi n)) == 1) (mod n)
                then gcd(k,phi n)
                else 0)

  DIVIDES_LE_IMP =
    |- !m n. m divides n /\ (n = 0 ==> m = 0) ==> m <= n

  GCD_LE =
    |- (!m n. gcd(m,n) <= m <=> m = 0 ==> n = 0) /\
       (!m n. gcd(m,n) <= n <=> n = 0 ==> m = 0)

  GCD_LE_MAX =
    |- !m n. gcd(m,n) <= MAX m n

  GCD_LE_MIN =
    |- !m n. (m = 0 <=> n = 0) ==> gcd(m,n) <= MIN m n

  GCD_LE_MIN_EQ =
    |- !m n. gcd(m,n) <= MIN m n <=> m = 0 <=> n = 0

  GENERALIZED_EULER_CRITERION =
    |- !n a k.
           (n = 0 \/
            n = 1 \/
            n = 2 \/
            n = 4 \/
            (?p k. prime p /\ 3 <= p /\ (n = p EXP k \/ n = 2 * p EXP k))) /\
           ~(k = 0) /\
           coprime(n,a)
           ==> ((?x. (x EXP k == a) (mod n)) <=>
                (a EXP (phi n DIV gcd(k,phi n)) == 1) (mod n))

  ORDER_INVERSE_MOD =
    |- !n a. coprime(n,a) ==> order n (inverse_mod n a) = order n a

  ORDER_MUL_LCM =
    |- !m n a. coprime(m,n) ==> order (m * n) a = lcm(order m a,order n a)

  ORDER_UNIQUE_ALT =
    |- !n a d. order n a = d <=> (!k. (a EXP k == 1) (mod n) <=> d divides k)

  POWER_RESIDUE_MODULO_PRIMITIVE =
    |- !n a k.
           ~(n = 0) /\ ~(k = 0) /\ coprime(n,a) /\ (?x. order n x = phi n)
           ==> ((?x. (x EXP k == a) (mod n)) <=>
                (a EXP (phi n DIV gcd(k,phi n)) == 1) (mod n))

Thu 19th Dec 2019       Library/prime.ml, Library/pratt.ml, Library/pocklington.ml, Library/multiplicative.ml, Library/primitive.ml, Library/modmul_group.ml

Added various miscellanous number-theoretic lemmas in multiple places, many
trivial but a few more interesting; for example COUNT_ROOTS_MODULO_ODD
characterizes the number of solutions of (x^k == 1) modulo any odd number.

  CHINESE_REMAINDER_COPRIME_COUNT =
    |- !P Q R a b k m n.
           coprime(a,b) /\
           (!x. x < a * b ==> (R x <=> P (x MOD a) /\ Q (x MOD b))) /\
           {x | x < a /\ coprime(a,x) /\ P x} HAS_SIZE m /\
           {x | x < b /\ coprime(b,x) /\ Q x} HAS_SIZE n
           ==> {x | x < a * b /\ coprime(a * b,x) /\ R x} HAS_SIZE m * n

  CHINESE_REMAINDER_COUNT =
    |- !P Q R a b k m n.
           coprime(a,b) /\
           (!x. x < a * b ==> (R x <=> P (x MOD a) /\ Q (x MOD b))) /\
           {x | x < a /\ P x} HAS_SIZE m /\
           {x | x < b /\ Q x} HAS_SIZE n
           ==> {x | x < a * b /\ R x} HAS_SIZE m * n

  CONG_EXP_1 =
    |- !x n k. (x == 1) (mod n) ==> (x EXP k == 1) (mod n)

  CONG_MINUS1 =
    |- !a b n. (a == n - 1) (mod n) <=> n = 0 /\ a = 0 \/ n divides a + 1

  CONG_MINUS1_SQUARED =
    |- !p. ((p - 1) EXP 2 == 1) (mod p) <=> ~(p = 0)

  COUNT_ROOTS_MODULO_COPRIME =
    |- !a b k m n.
           coprime(a,b) /\
           {x | x < a /\ (x EXP k == 1) (mod a)} HAS_SIZE m /\
           {x | x < b /\ (x EXP k == 1) (mod b)} HAS_SIZE n
           ==> {x | x < a * b /\ (x EXP k == 1) (mod (a * b))} HAS_SIZE m * n

  COUNT_ROOTS_MODULO_ODD =
    |- !n k.
           ODD n /\ ~(k = 0)
           ==> {x | x < n /\ (x EXP k == 1) (mod n)} HAS_SIZE
               iterate (*) {p | prime p /\ p divides n}
               (\p. gcd(k,p EXP (index p n - 1) * (p - 1)))

  COUNT_ROOTS_MODULO_PRIMITIVE =
    |- !n k.
           ~(n = 0) /\ ~(k = 0) /\ (?x. order n x = phi n)
           ==> {x | x < n /\ (x EXP k == 1) (mod n)} HAS_SIZE gcd(k,phi n)

  COUNT_ROOTS_MODULO_PRIMITIVE_ALT =
    |- !n k.
           ~(n = 0) /\ (?x. order n x = phi n)
           ==> {x | x < n /\ coprime(n,x) /\ (x EXP k == 1) (mod n)} HAS_SIZE
               gcd(k,phi n)

  DIVIDES_LMUL_GCD =
    |- (!d a b. d divides gcd(d,a) * b <=> d divides a * b) /\
       (!d a b. d divides gcd(a,d) * b <=> d divides a * b)

  DIVIDES_RMUL_GCD =
    |- (!d a b. d divides a * gcd(d,b) <=> d divides a * b) /\
       (!d a b. d divides a * gcd(b,d) <=> d divides a * b)

  GCD_COPRIME_LMUL =
    |- !a b c. coprime(a,b) ==> gcd(a * b,c) = gcd(a,c) * gcd(b,c)

  GCD_COPRIME_RMUL =
    |- !a b c. coprime(a,b) ==> gcd(c,a * b) = gcd(c,a) * gcd(c,b)

  INDEX_PRIME =
    |- !p a. prime p ==> index a p = (if p = a then 1 else 0)

  INDEX_ZERO =
    |- !p n. ~(p divides n) ==> index p n = 0

  INVERSE_MOD_CONG =
    |- !n x y. (x == y) (mod n) ==> inverse_mod n x = inverse_mod n y

  INVERSE_MOD_INVERSE_MOD =
    |- !n x.
           coprime(n,x) /\ 1 <= x /\ x <= n
           ==> inverse_mod n (inverse_mod n x) = x

  INVERSE_MOD_INVERSE_MOD_CONG =
    |- !n x. coprime(n,x) ==> (inverse_mod n (inverse_mod n x) == x) (mod n)

  ODD_PRIME =
    |- !p. prime p ==> (ODD p <=> 3 <= p)

  PHI_PRIMEPOW_ALT =
    |- !p k.
           prime p
           ==> phi (p EXP k) = (if k = 0 then 1 else p EXP (k - 1) * (p - 1))

Thu 19th Dec 2019       int.ml, passim

Put these two theorems into the basic int.ml file, and removed the existing
theorem COPRIME_MOD which is now consistently called COPRIME_LMOD:

  COPRIME_LMOD = |- !a n. coprime(a MOD n,n) <=> coprime(a,n)

  COPRIME_RMOD = |- !a n. coprime(n,a MOD n) <=> coprime(n,a)

Also incompatibly improved the existing theorem COPRIME_1 by adding both
symmetric versions and so save twiddling things round in some cases.

  COPRIME_1 = |- (!a. coprime(a,1)) /\ (!a. coprime(1,a))

Thu 19th Dec 2019       sets.ml

Added the following; it's a trivial enough combination of existing theorems
SURJECTIVE_IFF_INJECTIVE_GEN and HAS_SIZE_IMAGE_INJ, but it's nice to factor
out the injectivity so it can be handled just once:

  HAS_SIZE_IMAGE_INJ_RESTRICT =
    |- !f s t P n.
         FINITE s /\
         FINITE t /\
         CARD s = CARD t /\
         IMAGE f s SUBSET t /\
         (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
         {x | x IN s /\ P (f x)} HAS_SIZE n
         ==> {x | x IN t /\ P x} HAS_SIZE n

Tue 17th Dec 2019       Library/prime.ml, Library/pocklington.ml

Added a few miscellaneous divisibility-type properties:

  CONG_1_DIVIDES_EQ =
    |- !n x. (x == 1) (mod n) <=> (x = 0 ==> n = 1) /\ n divides x - 1

  COPRIME_INDEX =
    |- !m n.
           coprime(m,n) <=>
           (m = 0 ==> n = 1) /\
           (n = 0 ==> m = 1) /\
           (!p. prime p ==> index p m = 0 \/ index p n = 0)

  COPRIME_PAIR_DECOMP =
    |- !n1 n2 m.
           coprime(n1,n2) /\ ~(m = 0)
           ==> (?m1 m2.
                    coprime(m1,n1) /\
                    coprime(m2,n2) /\
                    coprime(m1,m2) /\
                    m1 * m2 = m)
  DIVIDES_INDEX =
    |- !m n.
           m divides n <=>
           n = 0 \/ ~(m = 0) /\ (!p. prime p ==> index p m <= index p n)

  DIVIDES_LCM_LEFT =
    |- !m n. n divides m <=> lcm(m,n) = m

  DIVIDES_LCM_RIGHT =
    |- !m n. m divides n <=> lcm(m,n) = n

  EQ_INDEX =
    |- !m n.
           m = n <=>
           (m = 0 <=> n = 0) /\ (!p. prime p ==> index p m = index p n)

  INDEX_DECOMPOSITION_LE =
    |- !p e1 m1 e2 m2.
           p EXP e1 * m1 = p EXP e2 * m2 /\ ~(p = 0) /\ ~(p divides m2)
           ==> e1 <= e2

  INDEX_DECOMPOSITION_UNIQUE =
    |- !p e1 m1 e2 m2.
           p EXP e1 * m1 = p EXP e2 * m2 /\
           ~(p = 0) /\
           ~(p divides m1) /\
           ~(p divides m2)
           ==> e1 = e2

  INDEX_GCD =
    |- !m n p.
           prime p
           ==> index p (gcd(m,n)) =
               (if m = 0
                then index p n
                else if n = 0 then index p m else MIN (index p m) (index p n))

  INDEX_LCM =
    |- !m n p.
           prime p
           ==> index p (lcm(m,n)) =
               (if m = 0 \/ n = 0 then 0 else MAX (index p m) (index p n))

  INDEX_UNIQUE =
    |- !p m n e.
           p EXP e * m = n /\ (p = 0 ==> e = 0) /\ ~(p divides m)
           ==> index p n = e

  LCM_COPRIME_DECOMP =
    |- !m n.
           ?m' n'.
               m' divides m /\
               n' divides n /\
               coprime(m',n') /\
               m' * n' = lcm(m,n)

  MULT_GCD_LCM =
    |- !m n. gcd(m,n) * lcm(m,n) = m * n

  MULT_LCM_GCD =
    |- !m n. lcm(m,n) * gcd(m,n) = m * n

  PRIME_FACTOR_PARTITION =
    |- !Q n.
           ~(n = 0)
           ==> (?n1 n2.
                    n1 * n2 = n /\
                    (!p. prime p /\ p divides n1 ==> Q p) /\
                    (!p. prime p /\ p divides n2 ==> ~Q p))

Sun 15th Dec 2019       Library/modmul_group.ml

Added a new library file "Library/modmul_group.ml" with a basic setup of
the multiplicative group of integers modulo n. This is more or less just
a straightforward combination of existing number-theoretic material with
explicitly group-theoretic language. For example, CYCLIC_MODMUL_GROUP
characterizes when this group is cyclic, and the core content here is
essentially the same as PRIMITIVE_ROOT_EXISTS in "Library/primitive.ml".

Sun 27th Oct 2019       sets.ml, Library/card.ml

Added a few miscellaneous cardinality-related lemmas:

  CARD_EQ_EXP_INFINITE_FINITE =
    |- !s t. INFINITE s /\ FINITE t /\ ~(t = {}) ==> s ^_c t =_c s

  CARD_EQ_FUNSPACE =
    |- !s t k.
           {f | IMAGE f s SUBSET t /\ {x | ~(f x = k x)} SUBSET s} =_c t ^_c s

  CARD_EQ_INFINITE =
    |- !s t. INFINITE t /\ s =_c t ==> INFINITE s

  CARD_EQ_RESTRICTED_FUNSPACE_INFINITE =
    |- !s t k.
           INFINITE s /\ ~(?a. t SUBSET {a}) /\ IMAGE k s SUBSET t
           ==> {f | IMAGE f s SUBSET t /\
                    {x | ~(f x = k x)} SUBSET s /\
                    FINITE {x | ~(f x = k x)}} =_c
               s *_c t

  CARD_LE_RESTRICTED_FUNSPACE_INFINITE =
    |- !s t k.
           INFINITE s /\ ~(t = {})
           ==> {f | IMAGE f s SUBSET t /\
                    {x | ~(f x = k x)} SUBSET s /\
                    FINITE {x | ~(f x = k x)}} <=_c
               s *_c t

  CARD_MUL2_ABSORB_LE_ALT =
    |- !s t u.
           (INFINITE s \/ INFINITE t) /\ s <=_c u /\ t <=_c u
           ==> s *_c t <=_c u

  CARD_MUL_LID =
    |- !a t. {a} *_c t =_c t

  CARD_MUL_RID =
    |- !s b. s *_c {b} =_c s

  FINITE_CROSS_UNIV =
    |- FINITE(:A#B) <=> FINITE(:A) /\ FINITE(:B)

  INFINITE_CROSS_EQ =
    |- !s t.
           INFINITE(s CROSS t) <=>
           ~(s = {}) /\ INFINITE t \/ INFINITE s /\ ~(t = {})

  INFINITE_CROSS_UNIV =
    |- INFINITE(:A#B) <=> INFINITE(:A) \/ INFINITE(:B)

Thu 10th Oct 2019       sets.ml

Added a trivial but not quite 1-line equivalence for finiteness of the
set of n-element subsets:

  FINITE_RESTRICTED_POWERSET =
    |- !s n. FINITE {t | t SUBSET s /\ t HAS_SIZE n} <=> FINITE s \/ n = 0

Mon  7th Oct 2019       wf.ml

Added missing outer quantifiers to WF_SUBSET.

Sat  5th Oct 2019       Library/wo.ml

Made an additional revamp of the wellordering material, trying to rationalize
things and start a switch from predicate to set notation. Also changed the name
of "fl" (field of a binary relation) to "fld", and added "qoset" (quasi-order /
preorder) and "wqoset" (well quasi-order) to the menagerie of ordered sets. As
a result changed the names of many ...FL... theorems to ...FLD..., and really
changed the definitions of the following to be more systematic stylistically
and use set notation:

        chain
        poset
        toset
        woset
        WOSET

Also WOSET_POSET is now a different theorem, the old one being renamed
WOSET_IMP_POSET, more in keeping with other theorem names of the same form.

Sat  5th Oct 2019       Library/rstc.ml, Examples/reduct.ml

Moved the fact that transitive closure preserves wellfoundedness (WF_TC)
from "Examples/reduct.ml" to "Library/rstc.ml". This seems a more natural
home, since it is independent of the more reduction-relation-oriented stuff
in the former.

Fri  4th Oct 2019       Examples/safetyliveness.ml

Added a very simple but classic example, a formalization of "safety" and
"liveness" for properties of traces, and a proof following Gries's "Decomposing
Properties into Safety and Liveness using Predicate Logic" that any property of
traces can be decomposed into the conjunction of a safety and a liveness
property.

Fri  4th Oct 2019       wf.ml

Added a couple more trivial facts about wellfounded relations:

  WF_RESTRICT = |- !(<<) P. WF (<<) ==> WF (\x y. P x /\ P y /\ x << y)

  WF_DHAIN_TRANSITIVE =
    |- !(<<). (!x y z. x << y /\ y << z ==> x << z)
              ==> (WF (<<) <=> ~(?s. !i j. i < j ==> s j << s i))

Tue  1st Oct 2019       wf.ml, define.ml, Examples/dickson.ml

Factored out the key "minimal bad sequence" argument a la Nash-Williams from
the existing example of Dickson's lemma and added it (for a more general
wellfounded ordering) to the core wf.ml file:

  MINIMAL_BAD_SEQUENCE =
   |- !(<<) bad.
         WF (<<) /\
         (!x. ~bad x ==> ?n. !y. (!k. k < n ==> y k = x k) ==> ~bad y) /\
         (?x. bad x)
         ==> ?y. bad y /\
                 !z n. bad z /\ (!k. k < n ==> z k = y k) ==> ~(z n << y n)

The hypothesis are that the "ordering" is wellfounded, that the notion of
"bad" is a "safety property", and that there exists some bad sequence. Also
made the tiny tweak of adding a missing outer quantifier to the existing
theorem WF_MEASURE_GEN.

Mon 30th Sep 2019       sets.ml, Library/card.ml

Added the following, factoring out its proof from Library/card.ml where
it was already there inside the proof of INFINITE_CARD_LE.

  INFINITE_ENUMERATE_SUBSET
    |- !s. INFINITE s <=>
           ?f:num->A. (!x. f x IN s) /\ (!x y. f x = f y ==> x = y)

Sun 29th Sep 2019       Library/wo.ml, Library/card.ml, Logic/fol_prop.ml, Multivariate/topology.ml

Made a small but systematic switch of the whole theory of orderings in this
file (poset, toset, woset, ordinal, ...) from uncurried relations `:A#A->bool`
to curried ones `:A->A->bool`. This has the slight negative feature that you
can't directly use set unions, but in all other respects is more coherent: it
is consistent with the core definition of WF, with all the stuff in
Library/rstc.ml and Examples/reduct.ml, and with all the concrete cases like
"<" on number systems.

Fri 20th Sep 2019       sets.ml

Added an additional conjunct to IN_ELIM_TRIPLE_THM and also added an
analogous IN_ELIM_QUAD_THM, so:

  IN_ELIM_TRIPLE_THM =
    |- (!P a b c. a,b,c IN {x,y,z | P x y z} <=> P a b c) /\
       (!P a b c. (a,b),c IN {(x,y),z | P x y z} <=> P a b c)

  IN_ELIM_QUAD_THM =
    |- (!P a b c d. a,b,c,d IN {w,x,y,z | P w x y z} <=> P a b c d) /\
       (!P a b c d. (a,b),c,d IN {(w,x),y,z | P w x y z} <=> P a b c d) /\
       (!P a b c d. ((a,b),c),d IN {((w,x),y),z | P w x y z} <=> P a b c d)

Tue  3rd Sep 2019       sets.ml

Added a trivial variant of IN_ELIM_PAIR_THM that is not an instance of it:

  IN_ELIM_TRIPLE_THM =
    |- !P a b c. a,b,c IN {x,y,z | P x y z} <=> P a b c

Fri 30th Aug 2019       int.ml, Library/integer.ml

Renamed the theorem INT_DIVISION_DECOMP in int.ml to INT_DIVISION_SIMP,
which better maintains the pattern of DIVISION_SIMP and avoids a clash
with a different theorem in Library/integer.ml. Also added one more
simple theorem to the latter file, something that INTEGER_RULE won't do
by default, depending as it does on the canonical choice of nonnegative
integer gcds:

  INT_GCD_EQ =
    |- !x y u v.
         (!d. d divides x /\ d divides y <=> d divides u /\ d divides v)
         ==> gcd(x,y) = gcd(u,v)

Fri 30th Aug 2019       int.ml

Added some trivialities about integer div and rem, the last three being
especially handy when reasoning about even/odd integers.

  let INT_MUL_DIV_EQ = prove
   |- (!m n. n * m div n = m <=> n divides m) /\
      (!m n. m div n * n = m <=> n divides m)

  INT_REM_2_CASES =
    |- !n. n rem &2 = &0 \/ n rem &2 = &1

  INT_REM_2_DIVIDES =
    |- (!n. n rem &2 = &0 <=> &2 divides n) /\
       (!n. n rem &2 = &1 <=> ~(&2 divides n))

  NOT_INT_REM_2 =
    |- (!n. ~(n rem &2 = &0) <=> n rem &2 = &1) /\
       (!n. ~(n rem &2 = &1) <=> n rem &2 = &0)

Wed  7th Aug 2019       grobner.ml

Made a few small tweaks so that the derived rule inside RING becomes
more delicate, and in particular more robust with respect to parameters
and extra hypotheses on theorems.

Sun  4th Aug 2019       Library/words.ml [new file]

Added a new file with a basic theory of machine words via the type
`:N word` of N-bit words. Here `:N` is a type of size N, so we are using
essentially the same indexing scheme as in the Multivariate theories for
vectors of size N. Note that this builds in a priori the assumption the
wordsize is nonzero.

Mappings `val:N word->num` and `word:num->N word` for unsigned values, and
similar 2s-complement `ival:N word->int` and `iword:int->word`, cast
(reducing modulo word in one direction) between words and numbers. The
`bit` function gives a specific bit as a Boolean.

The usual operations are provided like `word_add`, `word_xor`; currently
for explicitness we don't overload the usual operators. Some have signed
and unsigned variants (e.g. `word_ushr` is unsigned/logical shift right,
while `word_ishr` is signed/arithmetical shift right).

Tue 23rd Jul 2019       sets.ml

Added one more simple theorem about Cartesian products, a kind of Skolemization
theorem:

  EXISTS_CARTESIAN_PRODUCT_ELEMENT =
    |- !P k s.
         (?z. z IN cartesian_product k s /\ (!i. i IN k ==> P i (z i))) <=>
         (!i. i IN k ==> (?x. x IN s i /\ P i x))

Wed 10th Jul 2019       sets.ml

Added two more handy theorems about extensional/restricted functions:

 RESTRICTION_UNIQUE =
  |- !s f g.
         RESTRICTION s f = g <=>
         EXTENSIONAL s g /\ (!x. x IN s ==> f x = g x)

 RESTRICTION_UNIQUE_ALT =
  |- !s f g.
         f = RESTRICTION s g <=>
         EXTENSIONAL s f /\ (!x. x IN s ==> f x = g x)

Mon 24th Jun 2019       sets.ml

Added one more trivial set rewrite:

  DISJOINT_SING =
    |- (!s a. DISJOINT s {a} <=> ~(a IN s)) /\
       (!s a. DISJOINT {a} s <=> ~(a IN s))

Sat 22nd Jun 2019       Library/ringtheory.ml [new file]

Added a new library file with a basic development of ring theory (where
ring = commutative ring with 1), using a type `:(A)ring`. The setup is
directly analogous to "Library/grouptheory.ml" and follows roughly the
same naming conventions for theorems and general style. So far this is
mainly a lot of definitions of basic ring concepts and a slew of trivial
theorems about them. New definitions:

        field
        ideal_generated
        integral_domain
        isomorphic_ring
        prod_ring
        product_ring
        quotient_ring
        ring_0
        ring_1
        ring_add
        ring_associates
        ring_automorphism
        ring_carrier
        ring_char
        ring_coprime
        ring_coset
        ring_div
        ring_divides
        ring_endomorphism
        ring_epimorphism
        ring_homomorphism
        ring_ideal
        ring_image
        ring_inv
        ring_isomorphism
        ring_isomorphisms
        ring_kernel
        ring_monomorphism
        ring_mul
        ring_neg
        ring_of_int
        ring_of_num
        ring_pow
        ring_regular
        ring_setadd
        ring_setmul
        ring_setneg
        ring_sub
        ring_unit
        ring_zerodivisor
        subring_generated
        subring_of
        trivial_ring

Mon 10th Jun 2019       sets.ml

Added a few trivial but occasionally useful set restriction theorems:

  DIFF_RESTRICT =
    |- !P s t.
           {x | x IN s DIFF t /\ P x} =
           {x | x IN s /\ P x} DIFF {x | x IN t /\ P x}

  INSERT_RESTRICT =
    |- !P s a.
           {x | x IN a INSERT s /\ P x} =
           (if P a then a INSERT {x | x IN s /\ P x} else {x | x IN s /\ P x})

  INTER_RESTRICT =
    |- !P s t.
           {x | x IN s INTER t /\ P x} =
           {x | x IN s /\ P x} INTER {x | x IN t /\ P x}

  UNION_RESTRICT =
    |- !P s t.
           {x | x IN s UNION t /\ P x} =
           {x | x IN s /\ P x} UNION {x | x IN t /\ P x}

Sat 18th May 2019       Multivariate/realanalysis.ml

Merged in a fix from Alexey Solovyev for a curious change in behaviour starting
with OCaml >= 4.06 (?). This seems to be connected with having a "let rec"
definition containing a nested "let rec" for a local function with the same
name. As Alexey pointed out this consistently crashes on recent OCaml versions:

  let rec f =
    let s t = t in
    let rec f t = s t
    and g a = a in
    f;;

  Gc.minor();;

  f 0;;

While it's probably fundamentally an OCaml bug, there was no good reason for
the code to be the way it was anyway.

Sat 18th May 2019       tactics.ml

Merged a fix from Petros Papapanagiotou for a bug in metavariable
instantiation in THEN/THENL. This bug had been around a long time!

Sat 20th Apr 2019       lists.ml

Added a two-list asymmetric analog of ALL / PAIRWISE called ALLPAIRS, with
the obvious definition and a few basic theorems:

  ALLPAIRS =
    |- (ALLPAIRS f [] l <=> T) /\
       (ALLPAIRS f (CONS h t) l <=> ALL (f h) l /\ ALLPAIRS f t l))

  ALLPAIRS_EQ =
    |- !l m P Q.
           ALL P l /\ ALL Q m /\ (!p q. P p /\ Q q ==> (R p q <=> R' p q))
           ==> (ALLPAIRS R l m <=> ALLPAIRS R' l m)

  ALLPAIRS_MAP =
    |- !P l m.
           ALLPAIRS P (MAP f l) (MAP g m) <=>
           ALLPAIRS (\x y. P (f x) (g y)) l m

  ALLPAIRS_MEM =
    |- !P l m. (!x y. MEM x l /\ MEM y m ==> P x y) <=> ALLPAIRS P l m

  ALLPAIRS_SYM =
    |- !P l m. ALLPAIRS P l m <=> ALLPAIRS (\x y. P y x) m l

Mon  1st Apr 2019       arith.ml, Formal_ineqs/arith/arith_num.hl

Added one simple new theorem EQ_DIVMOD and generalized the existing theorems
DIV_MULT_ADD and MOD_MULT_ADD to have four conjuncts with all orderings of
addition and multiplication in the main term. This is often more convenient and
better matches the integer variants INT_DIV_MUL_ADD and INT_REM_MUL_ADD. So
now:

  DIV_MULT_ADD =
    |- (!a b n. ~(n = 0) ==> (a * n + b) DIV n = a + b DIV n) /\
       (!a b n. ~(n = 0) ==> (n * a + b) DIV n = a + b DIV n) /\
       (!a b n. ~(n = 0) ==> (b + a * n) DIV n = b DIV n + a) /\
       (!a b n. ~(n = 0) ==> (b + n * a) DIV n = b DIV n + a)

  EQ_DIVMOD =
    |- !p m n. m DIV p = n DIV p /\ m MOD p = n MOD p <=> m = n

  MOD_MULT_ADD =
    |- (!m n p. (m * n + p) MOD n = p MOD n) /\
       (!m n p. (n * m + p) MOD n = p MOD n) /\
       (!m n p. (p + m * n) MOD n = p MOD n) /\
       (!m n p. (p + n * m) MOD n = p MOD n)

the main term

Sun 31st Mar 2019       ProofTrace/* [new files]

Merged in Stanislas Polu's new ProofTrace proof recording setup.
This gives a much more lightweight proof recording toolchain than
the existing Proofrecording, and it is entirely written in OCaml.

Wed 26th Mar 2019       Makefile, pa_j_4.xx_7.06.ml [new file]

Merged in a pull request from ivarsfg, which fixes the compatibility problems
introduced with recent camlp5 versions. I've confirmed that everything now
works with Ocaml 4.07.1 and camlp5 7.07.

Fri  1st Mar 2019       Library/floor.ml

Added a simple theorem relating integer-valued reals and the integer type:

  IMAGE_REAL_OF_INT_UNIV =
    |- IMAGE real_of_int (:int) = integer

Wed 27th Feb 2019       int.ml

Added a definition of "real_zpow" (just "zpow" for short in the interface map),
real numbers to integer powers, with some basic lemmas. While trivial, this is
sometimes much more natural than forcing the use of natural number indices.

  real_zpow =
    |- !z i.
           z zpow i =
           (if &0 <= i
            then z pow num_of_int i
            else inv (z pow num_of_int (--i)))

  REAL_ABS_ZPOW =
    |- !x n. abs(x zpow n) = abs x zpow n

  REAL_INV_ZPOW =
    |- !x n. inv (x zpow n) = inv x zpow n

  REAL_POW_ZPOW =
    |- !x n. x pow n = x zpow &n

  REAL_SGN_ZPOW =
    |- !x n. real_sgn (x zpow n) = real_sgn x zpow n

  REAL_ZPOW_0 =
    |- !x. x zpow &0 = &1

  REAL_ZPOW_1 =
    |- !x. x zpow &1 = x

  REAL_ZPOW_2 =
    |- !x. x zpow &2 = x * x

  REAL_ZPOW_ADD =
    |- !x m n. ~(x = &0) ==> x zpow (m + n) = x zpow m * x zpow n

  REAL_ZPOW_DIV =
    |- !x y n. (x / y) zpow n = x zpow n / y zpow n

  REAL_ZPOW_EQ_0 =
    |- !x n. x zpow n = &0 <=> x = &0 /\ ~(n = &0)

  REAL_ZPOW_INV =
    |- !x n. inv x zpow n = inv (x zpow n)

  REAL_ZPOW_LE =
    |- !x n. &0 <= x ==> &0 <= x zpow n

  REAL_ZPOW_LT =
    |- !x n. &0 < x ==> &0 < x zpow n

  REAL_ZPOW_MINUS1 =
    |- !x. x zpow -- &1 = inv x

  REAL_ZPOW_MUL =
    |- !x y n. (x * y) zpow n = x zpow n * y zpow n

  REAL_ZPOW_NEG =
    |- !x n. x zpow --n = inv (x zpow n)

  REAL_ZPOW_NUM =
    |- !x n. x zpow &n = x pow n

  REAL_ZPOW_ONE =
    |- !n. &1 zpow n = &1

  REAL_ZPOW_POW =
    |- (!x n. x zpow &n = x pow n) /\ (!x n. x zpow -- &n = inv (x pow n))

  REAL_ZPOW_SUB =
    |- !x m n. ~(x = &0) ==> x zpow (m - n) = x zpow m / x zpow n

  REAL_ZPOW_ZERO =
    |- !n. &0 zpow n = (if n = &0 then &1 else &0)

  REAL_ZPOW_ZPOW =
    |- !x m n. x zpow m zpow n = x zpow (m * n)

Mon 11th Feb 2019       Multivariate/msum.ml, 100/cayley_hamilton.ml

Eliminated most of the ad hoc collection of material about matrix sums in the
old Cayley-Hamilton proof and instead just included the more general
development "Multivariate/msum.ml". But also merged a few things from the
Cayley-Hamilton proof into there: MSUM_MATRIX_LMUL, MSUM_MATRIX_RMUL and
switched to a sharper form of MSUM_IMAGE without a finiteness assumption, as
well as renaming the old MSUM_SUPPORT to MSUM_SUPPORT_EXPLICIT, making room for
a new version of MSUM_SUPPORT actually using the "support" constant.

Sat  9th Feb 2019       compute.ml [new file]

Added a new file from Alexey Solovyev containing tools for doing ML-style
call-by-value reduction of terms by inference inside the logic. This is a port
of the HOL4 "computeLib" library originally developed by Bruno Barras
(see "Programming and Computing in HOL", TPHOLs 2000).

Wed  6th Feb 2019       lib.ml, parser.ml, printer.ml, system.ml, tactics.ml, Help/print_num.doc [new file], Help/pp_print_num.doc [new file]

Made several fixes from pull requests prepared by Alexey Solovyev. Made the
parser error messages a bit more explicit (based on local code in Flyspeck by
Tom Hales). Fixed some cases where printing functions were not properly
parametrized by the formatter, with new functions "pp_print_num" and
"pp_print_fpf" that are used to print nums and finite partial functions, plus
proper use of the pre-existing parametrized form for types, terms, theorems,
goals and goalstacks in the #install_printer directives.

Wed  6th Feb 2019       sets.ml

Added a couple of trivial but handy clausal theorems about initial number
segments:

  NUMSEG_CLAUSES_LT =
    |- {i | i < 0} = {} /\ (!k. {i | i < SUC k} = k INSERT {i | i < k})

  NUMSEG_CLAUSES_LE =
    |- {i | i <= 0} = {0} /\ (!k. {i | i <= SUC k} = SUC k INSERT {i | i <= k})

and some corresponding clauses for sums and other iterated operations:

  ITERATE_CLAUSES_NUMSEG_LE =
    |- !op. monoidal op
            ==> iterate op {i | i <= 0} f = f 0 /\
                (!k. iterate op {i | i <= SUC k} f =
                     op (iterate op {i | i <= k} f) (f (SUC k)))

  ITERATE_CLAUSES_NUMSEG_LT =
    |- !op. monoidal op
            ==> iterate op {i | i < 0} f = neutral op /\
                (!k. iterate op {i | i < SUC k} f =
                     op (iterate op {i | i < k} f) (f k))

  NSUM_CLAUSES_NUMSEG_LE =
    |- nsum {i | i <= 0} f = f 0 /\
       (!k. nsum {i | i <= SUC k} f = nsum {i | i <= k} f + f (SUC k))

  NSUM_CLAUSES_NUMSEG_LT =
    |- nsum {i | i < 0} f = 0 /\
       (!k. nsum {i | i < SUC k} f = nsum {i | i < k} f + f k)

  SUM_CLAUSES_NUMSEG_LE =
    |- sum {i | i <= 0} f = f 0 /\
       (!k. sum {i | i <= SUC k} f = sum {i | i <= k} f + f (SUC k))

  SUM_CLAUSES_NUMSEG_LT =
    |- sum {i | i < 0} f = &0 /\
       (!k. sum {i | i < SUC k} f = sum {i | i < k} f + f k)

Sat  2nd Feb 2019       Multivariate/vectors.ml, Multivariate/msum.ml [new file]

Added a lot of new material, mainly about matrices, from Andrea Gabrielli
and Marco Maggesi.

In the core "Multivariate/vectors.ml" file are several new theorems and
also a linear decision procedure for matrix equations (MATRIX_ARITH and
MATRIX_ARITH_TAC), which is now used to derive many of the basic matrix
lemmas automatically. Also incompatibly changed VSUM_COMPONENT to their
improved version, with no range conditions on the indices.

The new file "Multivariate/msum.ml" defines sums of matrices over indexing
sets ("msum"), with a large suite of natural properties. It also contains a
definition of "matrix_norm" (= the usual Euclidean norm of the "flattened"
form).

Sat  2nd Feb 2019       cart.ml

Added three new theorems about the Cartesian variant of products,
from Andrea Gabrielli and Marco Maggesi:

  FSTCART_COMPONENT =
    |- !x i. 1 <= i /\ i <= dimindex(:M) ==> fstcart x$i = x$i

  SNDCART_COMPONENT =
    |- !x i. 1 <= i /\ i <= dimindex(:N) ==> sndcart x$i = x$(i + dimindex(:M))

  PASTECART_COMPONENT =
    |- (!u v i. 1 <= i /\ i <= dimindex(:M) ==> pastecart u v$i = u$i) /\
       (!u v i.
            dimindex(:M) + 1 <= i /\ i <= dimindex(:M) + dimindex(:N)
            ==> pastecart u v$i = v$(i - dimindex(:M)))

Tue 29th Jan 2019       int.ml

Added a simple but sometimes useful theorem that one can pick an integer
congruence solution in a canonical range:

  INT_CONG_SOLVE_BOUNDS =
    |- !a n. ~(n = &0) ==> (?x. &0 <= x /\ x < abs n /\ (x == a) (mod n))

Thu 17th Jan 2019       arith.ml

Added a slight generalization of MOD_ADD_CASES:

  MOD_CASES = |- !n p. n < 2 * p ==> n MOD p = (if n < p then n else n - p)

Tue 15th Jan 2019       arith.ml

Added one more trivial arithmetical theorem

  MOD_EQ_SELF = |- !m n. m MOD n = m <=> n = 0 \/ m < n

MOD_EQ_SELF

Sat  5th Jan 2019       arith.ml, basics.ml, cart.ml, parser.ml, printer.ml, Formal_ineqs/taylor/m_taylor.hl, Help/BITS_ELIM_CONV.doc [new file], Help/DIMINDEX_CONV.doc [new file], Help/DIMINDEX_TAC.doc [new file], Help/HAS_SIZE_DIMINDEX_RULE.doc [new file], Help/dest_finty.doc [new file], Help/mk_finty.doc [new file]

Added a complete replacement, from Andrea Gabrielli and Marco Maggesi, of the
previous arrangements for the definition of finite types of specified size. In
place of the former case-by-case approach via "define_finite_type", there is
now a pair of type constructors "tybit0" and "tybit1" allowing finite types to
be represented schematically in binary, keeping the old scheme only for the
base type `:1` defined in "trivia.ml". The parser and printer are modified so
that this representation is parsed and printed as before (e.g. what is written
`:6` is actually `:(1 tybit1) tybit0`).

A conversion "DIMINDEX_CONV", rule "HAS_SIZE_DIMINDEX_RULE"  and corresponding
tactic "DIMINDEX_TAC" are also provided to compute the `dimindex` function for
such types, while syntax constructors and destructors "mk_finty" and
"dest_finty" convert between such types and nums.

The old "define_finite_type" has been deleted, since it could just be
confusing. The same final theorem (without the side-effects) from the call
"define_finite_type k" can be obtained using the new setup by
"HAS_SIZE_DIMINDEX_RULE(mk_finty(Num.num_of_int k))".

In addition, a useful conversion "BITS_ELIM_CONV" is provided for eliminating
some stray instances of numeral-constructing constants.

Thu  3rd Jan 2019       equal.ml, Help/BINOP2_CONV.doc  [new file]

Added a simple new conversional BINOP2_CONV, which is similar to BINOP_CONV
but with different conversions for the left and right.

Thu  3rd Jan 2019       arith.ml

Added a couple of trivial results that are easy via DIVISION / LE_1 but
seemed worth having as simple equivalences:

  MOD_LT_EQ = |- !m n. m MOD n < n <=> ~(n = 0)

  MOD_LT_EQ_LT = |- !m n. m MOD n < n <=> 0 < n

Fri 21st Dec 2018       Library/grouptheory.ml

Added a number of theorems about group theory, mainly natural interrelations
among various concepts:

  CARTESIAN_PRODUCT_NORMAL_SUBGROUP_OF_PRODUCT_GROUP =
    |- !G h k.
           cartesian_product k h normal_subgroup_of product_group k G <=>
           (!i. i IN k ==> h i normal_subgroup_of G i)

  CROSS_NORMAL_SUBGROUP_OF_PROD_GROUP =
    |- !G1 G2 h1 h2.
           h1 CROSS h2 normal_subgroup_of prod_group G1 G2 <=>
           h1 normal_subgroup_of G1 /\ h2 normal_subgroup_of G2

  GROUP_ELEMENT_ORDER_EQ_2 =
    |- !G x.
           x IN group_carrier G
           ==> (group_element_order G x = 2 <=>
                ~(x = group_id G) /\ group_pow G x 2 = group_id G)

  GROUP_ELEMENT_ORDER_MUL_SYM =
    |- !G x y.
           x IN group_carrier G /\ y IN group_carrier G
           ==> group_element_order G (group_mul G x y) =
               group_element_order G (group_mul G y x)

  GROUP_ELEMENT_ORDER_UNIQUE_ALT =
    |- !G x n.
           x IN group_carrier G /\ ~(n = 0)
           ==> (group_element_order G x = n <=>
                group_pow G x n = group_id G /\
                (!m. 0 < m /\ m < n ==> ~(group_pow G x m = group_id G)))

  GROUP_ISOMORPHISM_PRODUCT_QUOTIENT_GROUP =
    |- !G n k.
           (!i. i IN k ==> n i normal_subgroup_of G i)
           ==> group_isomorphism
               (product_group k (\i. quotient_group (G i) (n i)),
                quotient_group (product_group k G) (cartesian_product k n))
               (cartesian_product k)

  GROUP_ISOMORPHISM_PROD_QUOTIENT_GROUP =
    |- !G1 G2 n1 n2.
           n1 normal_subgroup_of G1 /\ n2 normal_subgroup_of G2
           ==> group_isomorphism
               (prod_group (quotient_group G1 n1) (quotient_group G2 n2),
                quotient_group (prod_group G1 G2) (n1 CROSS n2))
               (\(s,t). s CROSS t)

  GROUP_POW_MUL_EQ_ID_SYM =
    |- !G n x y.
           x IN group_carrier G /\ y IN group_carrier G
           ==> (group_pow G (group_mul G x y) n = group_id G <=>
                group_pow G (group_mul G y x) n = group_id G)

  GROUP_SETINV_SUBGROUP_GENERATED =
    |- !G h. group_setinv (subgroup_generated G h) = group_setinv G

  GROUP_SETMUL_PRODUCT_GROUP =
    |- !G k s t.
           group_setmul (product_group k G) (cartesian_product k s)
           (cartesian_product k t) =
           cartesian_product k (\i. group_setmul (G i) (s i) (t i))

  GROUP_SETMUL_PROD_GROUP =
    |- !G1 G2 s1 s2 t1 t2.
           group_setmul (prod_group G1 G2) (s1 CROSS s2) (t1 CROSS t2) =
           group_setmul G1 s1 t1 CROSS group_setmul G2 s2 t2

  GROUP_SETMUL_SUBGROUP_GENERATED =
    |- !G h. group_setmul (subgroup_generated G h) = group_setmul G

  ISOMORPHIC_QUOTIENT_PRODUCT_GROUP =
    |- !G n k.
           (!i. i IN k ==> n i normal_subgroup_of G i)
           ==> quotient_group (product_group k G) (cartesian_product k n)
               isomorphic_group
               product_group k (\i. quotient_group (G i) (n i))

  ISOMORPHIC_QUOTIENT_PROD_GROUP =
    |- !G1 G2 n1 n2.
           n1 normal_subgroup_of G1 /\ n2 normal_subgroup_of G2
           ==> quotient_group (prod_group G1 G2) (n1 CROSS n2) isomorphic_group
               prod_group (quotient_group G1 n1) (quotient_group G2 n2)

  LEFT_COSET_PRODUCT_GROUP =
    |- !G h x k.
           left_coset (product_group k G) x (cartesian_product k h) =
           cartesian_product k (\i. left_coset (G i) (x i) (h i))

  LEFT_COSET_PROD_GROUP =
    |- !G1 G2 h1 h2 x1 x2.
           left_coset (prod_group G1 G2) (x1,x2) (h1 CROSS h2) =
           left_coset G1 x1 h1 CROSS left_coset G2 x2 h2

  LEFT_COSET_SUBGROUP_GENERATED =
    |- !G h k x. left_coset (subgroup_generated G h) x k = left_coset G x k

  NORMAL_SUBGROUP_OF_SUBGROUP_GENERATED =
    |- !G s h.
           h normal_subgroup_of G /\ h SUBSET s
           ==> h normal_subgroup_of subgroup_generated G s

  NORMAL_SUBGROUP_OF_SUBGROUP_GENERATED_GEN =
    |- !G s h.
           h normal_subgroup_of G /\
           h SUBSET group_carrier(subgroup_generated G s)
           ==> h normal_subgroup_of subgroup_generated G s

  OPPOSITE_PRODUCT_GROUP =
    |- !G k.
           opposite_group (product_group k G) =
           product_group k (\i. opposite_group (G i))

  OPPOSITE_PROD_GROUP =
    |- !G1 G2.
           opposite_group (prod_group G1 G2) =
           prod_group (opposite_group G1) (opposite_group G2)

  QUOTIENT_GROUP_SUBGROUP_GENERATED =
    |- !G h n.
           n normal_subgroup_of G /\ h subgroup_of G /\ n SUBSET h
           ==> quotient_group (subgroup_generated G h) n =
               subgroup_generated (quotient_group G n)
               {right_coset G n x | x IN h}

  RIGHT_COSET_PRODUCT_GROUP =
    |- !G h x k.
           right_coset (product_group k G) (cartesian_product k h) x =
           cartesian_product k (\i. right_coset (G i) (h i) (x i))

  RIGHT_COSET_PROD_GROUP =
    |- !G1 G2 h1 h2 x1 x2.
           right_coset (prod_group G1 G2) (h1 CROSS h2) (x1,x2) =
           right_coset G1 h1 x1 CROSS right_coset G2 h2 x2

  RIGHT_COSET_SUBGROUP_GENERATED =
    |- !G h k x. right_coset (subgroup_generated G h) k x = right_coset G k x

  SUBGROUP_GENERATED_REFL =
    |- !G s. group_carrier G SUBSET s ==> subgroup_generated G s = G

  SUBGROUP_OF_EPIMORPHIC_PREIMAGE =
    |- !G H f h.
           group_epimorphism (G,H) f /\ h subgroup_of H
           ==> {x | x IN group_carrier G /\ f x IN h} subgroup_of G /\
               IMAGE f {x | x IN group_carrier G /\ f x IN h} = h

  SUBGROUP_OF_HOMOMORPHIC_PREIMAGE =
    |- !G H f h.
           group_homomorphism (G,H) f /\ h subgroup_of H
           ==> {x | x IN group_carrier G /\ f x IN h} subgroup_of G

  SUBGROUP_OF_QUOTIENT_GROUP =
    |- !G n h.
           n normal_subgroup_of G
           ==> (h subgroup_of quotient_group G n <=>
                (?k. k subgroup_of G /\ {right_coset G n x | x IN k} = h))

  SUBGROUP_OF_QUOTIENT_GROUP_ALT =
    |- !G n h.
           n normal_subgroup_of G
           ==> (h subgroup_of quotient_group G n <=>
                (?k. k subgroup_of G /\
                     n SUBSET k /\
                     {right_coset G n x | x IN k} = h))

  SUBGROUP_OF_QUOTIENT_GROUP_GENERATED_BY =
    |- !G n h.
           n normal_subgroup_of G /\ h subgroup_of quotient_group G n
           ==> (?k. k subgroup_of G /\
                    n SUBSET k /\
                    quotient_group (subgroup_generated G k) n =
                    subgroup_generated (quotient_group G n) h)

  SUM_GROUP_EQ_PRODUCT_GROUP =
    |- !k G. FINITE k ==> sum_group k G = product_group k G

Wed 19th Dec 2018       iterate.ml, Library/isum.ml

Added a conversion EXPAND_NSUM_CONV to expand natural-number sums over
explicit numeric ranges like `nsum (1..10) ...`.  This is exactly analogous to
the EXPAND_SUM_CONV for real sums that was there already, and the code is the
same modulo the obvious changes. Likewise added EXPAND_ISUM_CONV to the
"Library/isum.ml" file.

Fri 14th Dec 2018       thecops.ml, Help/LEANCOP.doc, Help/LEANCOP_TAC.doc, Help/NANOCOP.doc, Help/NANOCOP_TAC.doc, Help/copverb.doc [new files]

Added a new file "thecops.ml" with two connection-based proof-producing
first-order provers from Michael Faerber: leanCoP and nanoCoP. This
provides in particular two new first-order derived inference rules

        LEANCOP
        NANOCOP

and two corresponding tactics

        LEANCOP_TAC
        NANOCOP_TAC

These are analogous to MESON/MESON_TAC and METIS/METIS_TAC, so there are now
four different proof-producing first-order provers to choose from, any of which
may work particularly well on problems of a particular structure.

Mon 10th Dec 2018       arith.ml

Added another trivial but handy theorem

        MOD_2_CASES = |- !n. n MOD 2 = if EVEN n then 0 else 1

Fri  7th Dec 2018       arith.ml

Added a simple but sometimes useful theorem

  MOD_ADD_CASES =
    |- !m n p.
           m < p /\ n < p
           ==> (m + n) MOD p = if m + n < p then m + n else (m + n) - p

Wed  5th Dec 2018       printer.ml

Changed, in a rather ad hoc but potentially valuable way, how some larger
nested conditionals are printed. Now when the nesting depth gets above 4, the
printer switches from following the logical nesting recursively to a flatter
style. For example, what was printed as:

   `if x = 1
     then 6
     else if x = 2
          then 5
          else if x = 3
               then 4
               else if x = 4
                    then 3
                    else if x = 5 then 2 else if x = 6 then 1 else 0`

now becomes

  `if x = 1 then 6
   else if x = 2 then 5
   else if x = 3 then 4
   else if x = 4 then 3
   else if x = 5 then 2
   else if x = 6 then 1
   else 0`

while slightly smaller nesting maintains the old behaviour, which does seem
clearer in such cases.

Fri 30th Nov 2018       calc_rat.ml, int.ml

Added two missing explicit value conversions for the real and integer signum
functions applied to concrete rational or integer numbers, REAL_RAT_SGN_CONV
and INT_SGN_CONV, also rolling them into the corresponding "..._RED_CONV" and
"..._REDUCE_CONV" functions.

Thu 29th Nov 2018       int.ml, Library/pocklington.ml, Library/integer.ml

Added a number of new theorems, mainly about integer division and remainder
and all pretty straightforward but nice to have:

  CONG_DIV2 =
    |- !a n m n. (a == b) (mod (m * n)) ==> (a DIV m == b DIV m) (mod n)

  CONG_GCD_LEFT =
    |- !x y n. (x == y) (mod n) ==> gcd(x,n) = gcd(y,n)

  CONG_GCD_RIGHT =
    |- !x y n. (x == y) (mod n) ==> gcd(n,x) = gcd(n,y)

  INT_CONG_DIV =
    |- !m n a b.
          &0 < m /\ (a == m * b) (mod (m * n)) ==> (a div m == b) (mod n)

  INT_CONG_DIV2 =
    |- !a n m n.
           &0 <= m /\ (a == b) (mod (m * n))
           ==> (a div m == b div m) (mod n)

  INT_CONG_GCD_LEFT =
    |- !x y n. (x == y) (mod n) ==> gcd(x,n) = gcd(y,n)

  INT_CONG_GCD_RIGHT =
    |- !x y n. (x == y) (mod n) ==> gcd(n,x) = gcd(n,y)

  INT_DIV_1 =
    |- !n. n div &1 = n

  INT_DIV_DIV =
    |- !m n p. &0 <= n ==> m div n div p = m div (n * p)

  INT_DIV_EQ_0 =
    |- !m n. m div n = &0 <=> n = &0 \/ &0 <= m /\ m < abs n

  INT_DIV_LE =
    |- !m n. abs(m div n) <= abs m

  INT_DIV_LE_EQ =
    |- !a b c. &0 < a ==> (b div a <= c <=> b < a * (c + &1))

  INT_DIV_LNEG =
   |- !m n.
         --m div n =
         (if m rem n = &0 then --(m div n) else --(m div n) - int_sgn n)

  INT_DIV_LT_EQ =
    |- !a b c. &0 < a ==> (b div a < c <=> b < a * c)

  INT_DIV_MUL =
   |- (!m n. ~(n = &0) ==> (m * n) div n = m) /\
      (!m n. ~(m = &0) ==> (m * n) div m = n)

  INT_DIV_MUL_ADD =
   |- (!m n p. ~(n = &0) ==> (m * n + p) div n = m + p div n) /\
      (!m n p. ~(n = &0) ==> (n * m + p) div n = m + p div n) /\
      (!m n p. ~(n = &0) ==> (p + m * n) div n = p div n + m) /\
      (!m n p. ~(n = &0) ==> (p + n * m) div n = p div n + m)

  INT_DIV_NEG2 =
    |- !m n. --m div --n = if m rem n = &0 then m div n else m div n + int_sgn n

  INT_DIV_REFL =
    |- !n. n div n = (if n = &0 then &0 else &1)

  INT_DIV_REM =
    |- !m n p. &0 <= n ==> (m div n) rem p = (m rem (n * p)) div n

  INT_LE_DIV =
    |- !m n. &0 <= m /\ &0 <= n ==> &0 <= m div n

  INT_LE_DIV_EQ =
    |- !a b c. &0 < a ==> (c <= b div a <=> a * c <= b)

  INT_LE_LMUL_EQ =
    |- !x y z. &0 < z ==> (z * x <= z * y <=> x <= y)

  INT_LT_DIV =
    |- !m n. &0 < n /\ n <= m ==> &0 < m div n

  INT_LT_DIV_EQ =
    |- !a b c. &0 < a ==> (c < b div a <=> a * (c + &1) <= b)

  INT_NEG_REM =
    |- !n p. --(n rem p) rem p = --n rem p

  INT_POW_REM =
    |- !m n p. (m rem p) pow n rem p = m pow n rem p

  INT_REM_1 =
    |- !n. n rem &1 = &0

  INT_REM_EQ_SELF =
    |- !m n. m rem n = m <=> n = &0 \/ &0 <= m /\ m < abs n

  INT_REM_LNEG =
   |- !m n. --m rem n = (if m rem n = &0 then &0 else abs n - m rem n)

  INT_REM_MUL =
    |- (!m n. (m * n) rem n = &0) /\
       (!m n. (m * n) rem m = &0)

  INT_REM_MUL_ADD =
    |- (!m n p. (m * n + p) rem n = p rem n) /\
       (!m n p. (n * m + p) rem n = p rem n) /\
       (!m n p. (p + m * n) rem n = p rem n) /\
       (!m n p. (p + n * m) rem n = p rem n)

  INT_REM_MUL_REM =
   |- !m n p. &0 <= n ==> m rem (n * p) = n * (m div n) rem p + m rem n

  INT_REM_NEG2 =
   |- !m n. --m rem --n = if m rem n = &0 then &0 else abs n - m rem n

  INT_REM_REFL =
    |- !n. n rem n = &0

  INT_SUB_REM =
    |- |- !m n p. (m rem p - n rem p) rem p = (m - n) rem p

  MOD_MULT_MOD =
    |- !m n p. m MOD (n * p) = n * (m DIV n) MOD p + m MOD n

Also moved two existing theorems from "Library/integer.ml" back into the
main "int.ml" file: INT_CONG_IMP_EQ and INT_DIVIDES_LE.

Wed 28th Nov 2018       int.ml, Library/prime.ml

Made a few small but useful improvements to INTEGER_RULE/INTEGER_TAC
(slightly better gcd elimination) and NUMBER_RULE/NUMBER_TAC (also
better splitting up of conjuncts and some limited exploitation of
antisymmetry of divisibility relation over N). Here are a couple of
examples that failed before but are now proved automatically:

  NUMBER_RULE
   `!a b c:num. gcd(c * a,c * b) = c * gcd(a,b)`;;

  NUMBER_RULE
   `(!a m n k. coprime(a,k) ==> gcd(a * m + k,a * n) = gcd(a * m + k,n)) /\
    (!a m n k. coprime(a,k) ==> gcd(a * m,a * n + k) = gcd(m,a * n + k))`;;

Made a few tweaks to "Library/prime.ml" where things can now be done more
automatically, and also eliminated pointless duplicates (reflecting the
origins of that file in ancient HOL88 stuff)

  LESS_EQ_MULT -> LE_MULT2
  LESS_MULT -> LT_MULT2

Tue 27th Nov 2018       int.ml, Library/pratt.ml, Library/pocklington.ml

Added two new theorems connecting division and modulus over N and Z in the
obvious way:

  INT_OF_NUM_DIV = |- !m n. &m div &n = &(m DIV n)

  INT_OF_NUM_REM = |- !m n. &m rem &n = &(m MOD n)

Also moved three elementary theorems about congruences, which are quite handy
(but, in contrast to many other basic congruence properties, not automatically
creatable by NUMBER_RULE etc.) from the Library to the core "int.ml" file:

  CONG = |- !x y n. (x == y) (mod n) <=> x MOD n = y MOD n

  CONG_LMOD = |- !x y n. (x MOD n == y) (mod n) <=> (x == y) (mod n)

  CONG_RMOD = |- !x y n. (x == y MOD n) (mod n) <=> (x == y) (mod n)

Mon 26th Nov 2018       arith.ml

Added one very simple theorem about modulus

  MOD_MOD_LE =
    |- !m n p. ~(n = 0) /\ n <= p ==> m MOD n MOD p = m MOD n

as well as sharpening the existing MOD_MOD_EXP_MIN by removing a nonzeroness
assumption, so it is now:

 MOD_MOD_EXP_MIN =
  |- !x p m n. x MOD p EXP m MOD p EXP n = x MOD p EXP MIN m n

Sat 10th Nov 2018       lists.ml, int.ml, iterate.ml, Library/binary.ml

Added a few elementary theorems (the first one BINARY_INDUCT just
moved from Library/binary.ml into the core files).

  BINARY_INDUCT
    |- !P. P 0 /\ (!n. P n ==> P (2 * n) /\ P (2 * n + 1)) ==> (!n. P n)

  CONG_NSUM =
    |- !n f g s.
           FINITE s /\ (!x. x IN s ==> (f x == g x) (mod n))
           ==> (nsum s f == nsum s g) (mod n)

  HD_REVERSE =
    |- !l. ~(l = []) ==> HD (REVERSE l) = LAST l

  LAST_REVERSE =
    |- !l. ~(l = []) ==> LAST (REVERSE l) = HD l

  LENGTH_REVERSE =
    |- !l. LENGTH (REVERSE l) = LENGTH l

  NSUM_RELATED =
    |- !R f g s.
           R 0 0 /\
           (!m n m' n'. R m n /\ R m' n' ==> R (m + m') (n + n')) /\
           FINITE s /\
           (!x. x IN s ==> R (f x) (g x))
           ==> R (nsum s f) (nsum s g)

  NUM_CASES_BINARY =
    |- !P. (!n. P n) <=> (!n. P (2 * n)) /\ (!n. P (2 * n + 1))

  REVERSE_EQ_EMPTY =
    |- !l. REVERSE l = [] <=> l = []

  SUM_RELATED =
    |- !R f g s.
           R (&0) (&0) /\
           (!m n m' n'. R m n /\ R m' n' ==> R (m + m') (n + n')) /\
           FINITE s /\
           (!x. x IN s ==> R (f x) (g x))
           ==> R (sum s f) (sum s g)

  num_WF_DOWN =
    |- !P m.
           (!n. m <= n ==> P n) /\ (!n. n < m /\ (!p. n < p ==> P p) ==> P n)
           ==> (!n. P n)

Fri  9th Nov 2018       firstorder.ml [new file], metis.ml

Added a complete revision of the METIS prover code from Michael Faerber.
This fixes some known failures of the previous version and also separates
off and generalizes utilities for first-order term manipulation that can
be used in other first-order provers.

Fri  9th Nov 2018       lib.ml

Added a definition of the reversed function application operator "|>".
This is already there as standard with recent versions of OCaml, but
this helps backwards compatibility with much older ones.

Sat  3rd Nov 2018       sets.ml

Added a basic "disjoint union" set construction with the obvious lemmas:

  disjoint_union =
    |- !k s. disjoint_union k s = {i,x | i IN k /\ x IN s i}

  DISJOINT_DISJOINT_UNION =
    |- !k s t.
           DISJOINT (disjoint_union k s) (disjoint_union k t) <=>
           (!i. i IN k ==> DISJOINT (s i) (t i))

  DISJOINT_UNION_EQ =
    |- !k s t.
           disjoint_union k s = disjoint_union k t <=>
           (!i. i IN k ==> s i = t i)

  DISJOINT_UNION_EQ_EMPTY =
    |- !k s. disjoint_union k s = {} <=> (!i. i IN k ==> s i = {})

  INTER_DISJOINT_UNION =
    |- !k s t.
           disjoint_union k s INTER disjoint_union k t =
           disjoint_union k (\i. s i INTER t i)

  SUBSET_DISJOINT_UNION =
    |- !k s t.
           disjoint_union k s SUBSET disjoint_union k t <=>
           (!i. i IN k ==> s i SUBSET t i)

  SUBSET_DISJOINT_UNION_EXISTS =
    |- !k s u.
           u SUBSET disjoint_union k s <=>
           (?t. u = disjoint_union k t /\ (!i. i IN k ==> t i SUBSET s i))

  UNION_DISJOINT_UNION =
    |- !k s t.
           disjoint_union k s UNION disjoint_union k t =
           disjoint_union k (\i. s i UNION t i)

Sat  3rd Nov 2018       trivia.ml

Added for completeness the trivial quantification theorems for the
one-element type ":1":

  FORALL_ONE_THM = |- (!x. P x) <=> P one

  EXISTS_ONE_THM = |- (?x. P x) <=> P one

Sat 20th Oct 2018       Geometric_Algebra [new directory]

Added a new contribution from Liming Li, Zhiping Shi, Yong Guan, Guohui Wang
and Sha Ma, from Capital Normal University, Beijing. This is a theory of
geometric algebra with a multivector structure (P,Q,R)multivector for
formulating any geometric algebra G(P,Q,R) with positive definite, negative
definite and zero quadratic forms.

Fri 19th Oct 2018       Library/rstc.ml, Help/*

Made a small change from Marco Maggesi to the proof of TC_CLOSED to remove
warnings, as well as fixing a few documentation issues he pointed out.

Fri 19th Oct 2018       Library/card.ml

Added one trivial cardinal theorem where the FINITE analog is already there:

COUNTABLE_DIFF =
  |- !s t. COUNTABLE s ==> COUNTABLE (s DIFF t)

Sun 23rd Sep 2018       sets.ml

Added one trivial theorem, occasionally useful to avoid disturbing the
"cartesian_product" construct:

  IN_CARTESIAN_PRODUCT =
    |-!k s x.
        x IN cartesian_product k s <=>
        EXTENSIONAL k x /\ (!i. i IN k ==> x i IN s i)

Sun 23rd Sep 2018       sets.ml

Added a definition of the product of a family of maps in the setting of
"cartesian_product", with two basic theorems:

  product_map =
    |- !k f. product_map k f = (\x. RESTRICTION k (\i. f i (x i)))

  IMAGE_PRODUCT_MAP =
    |- !f k s.
           IMAGE (product_map k f) (cartesian_product k s) =
           cartesian_product k (\i. IMAGE (f i) (s i))

  PRODUCT_MAP_RESTRICTION =
    |- !f k x.
           product_map k f (RESTRICTION k x) = RESTRICTION k (\i. f i (x i))

Sat 11th Aug 2018       pair.ml

Added two more theorems that are morally consequences of the corresponding
"PAIR" versions already there, but not literally so in the encoding and
therefore useful to have sometimes:

  LAMBDA_TRIPLE =
    |- !f. (\(x,y,z). f x y z) = (\t. f (FST t) (FST (SND t)) (SND (SND t)))

  LAMBDA_TRIPLE_THM =
    |- !f. (\t. f t) = (\(x,y,z). f (x,y,z))

Fri 27th Jul 2018       Library/card.ml

Added some handy "cancellation" properties of cardinal addition
(in finite case mainly but slightly sharper)

  CARD_EQ_ADD_LCANCEL =
    |- !s t u.
           (FINITE s \/ s <=_c t /\ s <=_c u) /\ s +_c t =_c s +_c u
           ==> t =_c u

  CARD_EQ_ADD_LCANCEL_EQ =
    |- !s t u.
           FINITE s \/ s <=_c t /\ s <=_c u
           ==> (s +_c t =_c s +_c u <=> t =_c u)

  CARD_EQ_ADD_RCANCEL =
    |- !s t u.
           (FINITE u \/ u <=_c s /\ u <=_c t) /\ s +_c u =_c t +_c u
           ==> s =_c t

  CARD_EQ_ADD_RCANCEL_EQ =
    |- !s t u.
           FINITE u \/ u <=_c s /\ u <=_c t
           ==> (s +_c u =_c t +_c u <=> s =_c t)

  CARD_LE_ADD_LCANCEL =
    |- !s t u. (FINITE s \/ s <=_c u) /\ s +_c t <=_c s +_c u ==> t <=_c u

  CARD_LE_ADD_LCANCEL_EQ =
    |- !s t u. FINITE s \/ s <=_c u ==> (s +_c t <=_c s +_c u <=> t <=_c u)

  CARD_LE_ADD_RCANCEL =
    |- !s t u. (FINITE u \/ u <=_c t) /\ s +_c u <=_c t +_c u ==> s <=_c t

  CARD_LE_ADD_RCANCEL_EQ =
    |- !s t u. FINITE u \/ u <=_c t ==> (s +_c u <=_c t +_c u <=> s <=_c t)

Tue 17th Jul 2018       sets.ml

Added a handy rewrite for "pairwise" with a symmetric relation:

  PAIRWISE_INSERT_SYMMETRIC =
    |- !r x s.
         (!y. y IN s ==> (r x y <=> r y x))
         ==> (pairwise r (x INSERT s) <=>
              (!y. y IN s /\ ~(y = x) ==> r x y) /\ pairwise r s)

Mon 16th Jul 2018       Library/card.ml

Added a theorem expressing a simple equivalent idiom for the intuitive "a set
s has cardinality >= n" (finite or infinite), which is otherwise a bit of a
mouthful when expressed as a case analysis (the rhs of this theorem):

  NUMSEG_CARD_LE =
   |- !s. 1..n <=_c s <=> FINITE s ==> n <= CARD s

Sun 15th Jul 2018       arith.ml, iter.ml, Library/prime.ml, Library/pratt.ml, Library/pocklington.ml

Added a few new DIV/MOD/congruence-related theorems as well as a "downward"
induction variant:

  CONG_DIV =
    |- !m n a b.
         ~(m = 0) /\ (a == m * b) (mod (m * n)) ==> (a DIV m == b) (mod n)

  CONG_SOLVE_EQ =
    |- !n a b. (?x. (a * x == b) (mod n)) <=> gcd(a,n) divides b

  CONG_SOLVE_LT_EQ =
    |- !n a b.
         (?x. x < n /\ (a * x == b) (mod n)) <=>
         ~(n = 0) /\ gcd(a,n) divides b

  DIV_ZERO =
    |- !n. n DIV 0 = 0

  MOD_LE_TWICE =
    |- !m n. 0 < m /\ m <= n ==> 2 * n MOD m <= n

  MOD_ZERO =
    |- !n. n MOD 0 = n

  num_INDUCTION_DOWN =
    |- !P m.
         (!n. m <= n ==> P n) /\ (!n. n < m /\ P (n + 1) ==> P n)
         ==> (!n. P n)

Having called out that special case DIV_ZERO and MOD_ZERO, took the chance
to streamline a lot of existing theorems, removing nonzeroness hypotheses
completely from the following:

        CONG
        CONG_LMOD
        CONG_MOD
        CONG_RMOD
        COPRIME_MOD
        DIVIDES_MOD
        DIVISION_SIMP
        DIV_0
        DIV_DIV
        DIV_LE
        DIV_MOD
        MOD_0
        MOD_ADD_MOD
        MOD_EQ_0
        MOD_EXP_MOD
        MOD_LE
        MOD_MOD
        MOD_MOD_REFL
        MOD_MULT
        MOD_MULT2
        MOD_MULT_CONG
        MOD_MULT_LMOD
        MOD_MULT_MOD2
        MOD_MULT_RMOD
        MOD_NSUM_MOD
        MOD_NSUM_MOD_NUMSEG
        MOD_REFL
        MULT_DIV_LE

sharpening the hypothesis of these

        DIV_MULT2
        DIV_MONO

and indicdentally adding missing quantifiers to

        DIV_EQ_EXCLUSION

On the other hand simply removed DIVIDES_DIV which is now even more
clearly subsumed by DIVIDES_MOD.

Tue  3rd Jul 2018       Library/pocklington.ml

Added one more uniqueness theorem for modulus based on congruences:

  MOD_UNIQUE =
    |- !m n p. m MOD n = p <=> (n = 0 /\ m = p \/ p < n) /\ (m == p) (mod n)

Mon  2nd Jul 2018       list.ml

Added one more basic list lemma:

  EL_MAP2 =
    |- !f l m k.
           k < LENGTH l /\ k < LENGTH m
           ==> EL k (MAP2 f l m) = f (EL k l) (EL k m)

Wed 27th Jun 2018       Library/group.ml

Added one more basic homological algebra lemma (found in Dieck's "Algebraic
Topology", 11.1.3), which is a bit of a mouthful but intuitively nice when
you look at the picture:

  EXACT_SEQUENCE_HEXAGON_LEMMA =
    |- !f g h h' i j k k' a b c d l m A B C D W X Y.
           abelian_group X /\
           group_homomorphism (A,Y) a /\
           group_homomorphism (B,Y) b /\
           group_homomorphism (W,C) c /\
           group_homomorphism (W,D) d /\
           group_isomorphisms (A,C) (h,h') /\
           group_isomorphisms (B,D) (k,k') /\
           group_exactness (A,X,D) (i,g) /\
           group_exactness (B,X,C) (j,f) /\
           group_exactness (W,X,Y) (l,m) /\
           (!x. x IN group_carrier W ==> f (l x) = c x) /\
           (!x. x IN group_carrier W ==> g (l x) = d x) /\
           (!x. x IN group_carrier A ==> f (i x) = h x) /\
           (!x. x IN group_carrier A ==> m (i x) = a x) /\
           (!x. x IN group_carrier B ==> g (j x) = k x) /\
           (!x. x IN group_carrier B ==> m (j x) = b x)
           ==> (!x. x IN group_carrier W
                    ==> group_inv Y (a (h' (c x))) = b (k' (d x)))

Mon 19th Jun 2018       Library/card.ml

Incompatibly improved the existing theorem CARD_HAS_SIZE_CONG to
have an "iff" in the conclusion:

  CARD_HAS_SIZE_CONG =
    |- !s t n. s =_c t ==> (s HAS_SIZE n <=> t HAS_SIZE n)

Sun 10th Jun 2018       Library/grouptheory.ml

Added a few more or less trivial theorems about group isomorphisms up
to swapping of pairs:

  GROUP_ISOMORPHISMS_PROD_GROUP_SWAP =
    |- !G H.
           group_isomorphisms (prod_group G H,prod_group H G)
           ((\(x,y). y,x),(\(y,x). x,y))

  ISOMORPHIC_GROUP_PROD_GROUP_SYM =
    |- !G H. prod_group G H isomorphic_group prod_group H G

  ISOMORPHIC_GROUP_PROD_GROUP_SWAP_LEFT =
    |- !G H K.
           prod_group G H isomorphic_group K <=>
           prod_group H G isomorphic_group K

  ISOMORPHIC_GROUP_PROD_GROUP_SWAP_RIGHT =
    |- !G H K.
           G isomorphic_group prod_group H K <=>
           G isomorphic_group prod_group K H

Sun 13th May 2018       Examples/digit_serial_methods.ml [new file]

Added a new file with the HOL Light formalizations mentioned in the paper by
Warren Ferguson, Jesse Bingham, Levent Erkok, John Harrison and Joe
Leslie-Hurd: "Digit Serial Methods with Applications to Division and Square
Root", IEEE Transactions on Computers, vol. 67, issue 3, pp. 449-456, 2017.

Fri 11th May 2018       drule.ml

Added two new functions "type_unify" for unifying types and "term_type_unify"
for unifying terms by instantiating both term and type variables, both
contributed by Michael Faerber. Also fixed a bug he pointed out in the existing
"term_unify" which does term unification only when the types are already
compatible. Since this is essentially subsumed anyway by the new
"term_type_unify" it might be appropriate to simply delete "term_unify", but as
the interface is minutely different and it's used in a few places I kept it for
now.

Sat 24th Mar 2018       lists.ml

Added a trivial but sometimes convenient list theorem:

  MEM_REPLICATE =
   |- !n x y:A. MEM x (REPLICATE n y) <=> x = y /\ ~(n = 0)

Sat 10th Mar 2018       int.ml

Added a somewhat surprising missing lemma:

  INT_MUL_EQ_1 =
    |- !x y:int. x * y = &1 <=> x = &1 /\ y = &1 \/ x = --(&1) /\ y = --(&1)

Sat 10th Feb 2018       iterate.ml, Library/grouptheory.ml,

Fixed a couple of name collisions, renaming the GROUP_SUM in the group theory
library to GROUP_SUM_CLAUSES to avoid clashing with the theorem about
rearranging real sums into groups, and renamed FINITE_INTSEG in iterate.ml to
FINITE_INT_SEG to avoid the other theorem of the same name in Library/floor.ml.

Sat 27th Jan 2018       int.ml, sets.ml

Added a few trivial theorems, two about integer division, one about sets:

  INT_LT_REM = |- !x n. &0 < n ==> x rem n < n

  INT_REM_DIV = |- !m n. m rem n = m - m div n * n

  INTERS_ANTIMONO_GEN =
    |- !s t. (!y. y IN t ==> ?x. x IN s /\ x SUBSET y)
             ==> INTERS s SUBSET INTERS t

Mon 22nd Jan 2018         Library/grouptheory.ml

Added a few more theorems to the group theory library, and in the process
created a dependency of this file on Library/card.ml, since all of these
theorems use material from there.

  CARD_EQ_FREE_ABELIAN_GROUP_INFINITE =
    |- !s. INFINITE s ==> group_carrier(free_abelian_group s) =_c s

  CARD_EQ_HOMOMORPHISMS_FROM_FREE_ABELIAN_GROUP =
    |- !s G.
           abelian_group G
           ==> {f | EXTENSIONAL (group_carrier(free_abelian_group s)) f /\
                    group_homomorphism (free_abelian_group s,G) f} =_c
               group_carrier G ^_c s

  FINITE_PRODUCT_GROUP =
    |- !k G.
           FINITE(group_carrier(product_group k G)) <=>
           FINITE {i | i IN k /\ ~trivial_group (G i)} /\
           (!i. i IN k ==> FINITE(group_carrier(G i)))

  ISOMORPHIC_FREE_ABELIAN_GROUPS =
    |- !s t.
           free_abelian_group s isomorphic_group free_abelian_group t <=>
           s =_c t

Sun 31st Dec 2017         Examples/padics.ml [new file]

Added a construction of the p-adic numbers. This is mostly meant as an example
of using metric space completion, but some effort is made to create a usable
theory, with the p-adics for each p occupying the whole type ":padic" and with
the embeddings of naturals overlaid in the same way for all p.

Tue  5th Dec 2017         int.ml

Beefed up the previously minimal set of theorems about integer division and
remainder with the following:

  INT_ADD_REM =
    |- !m n p. (m rem p + n rem p) rem p = (m + n) rem p

  INT_DIVISION_DECOMP =
    |- !m n. m div n * n + m rem n = m

  INT_DIV_0 =
    |- !m. m div &0 = &0

  INT_DIV_LT =
    |- !m n. (~(n = &0) ==> &0 <= m) /\ m < n ==> m div n = &0

  INT_DIV_RNEG =
    |- !m n. m div --n = --(m div n)

  INT_DIV_UNIQ =
    |- !m n q r. m = q * n + r /\ &0 <= r /\ r < abs n ==> m div n = q

  INT_DIV_ZERO =
    |- !n. &0 div n = &0

  INT_MUL_REM =
    |- !m n p. (m rem p * n rem p) rem p = (m * n) rem p

  INT_REM_0 =
    |- !m. m rem &0 = m

  INT_REM_EQ =
    |- !m n p. m rem p = n rem p <=> (m == n) (mod p)

  INT_REM_EQ_0 =
    |- !m n. m rem n = &0 <=> n divides m

  INT_REM_LT =
    |- !m n. (~(n = &0) ==> &0 <= m) /\ m < n ==> m rem n = m

  INT_REM_MOD_SELF =
    |- !m n. (m rem n == m) (mod n)

  INT_REM_REM =
    |- !m n. m rem n rem n = m rem n

  INT_REM_RNEG =
    |- !m n. m rem --n = m rem n

  INT_REM_UNIQ =
    |- !m n q r. m = q * n + r /\ &0 <= r /\ r < abs n ==> m rem n = r

  INT_REM_ZERO =
    |- !n. &0 rem n = &0

Sat  2nd Dec 2017       real.ml, sets.ml

Added a couple of somewhat random but useful theorems:

  CARTESIAN_PRODUCT_AS_RESTRICTIONS =
    |- !k s.
         cartesian_product k s =
         {RESTRICTION k f |f| !i. i IN k ==> f i IN s i}

  REAL_POS_EQ_SQUARE =
    |- !x. &0 <= x <=> ?y. y pow 2 = x

Sat  2nd Dec 2017       Library/card.ml

Added a few elementary cardinality theorems, some of them surprising gaps:

  CARD_EQ_INT_NUM = |- (:int) =_c (:num)

  CARD_EXP_FINITE_EQ =
   |- !s t. FINITE(s ^_c t) <=>
          (?a. s SUBSET {a}) \/ t = {} \/ FINITE s /\ FINITE t

  CARD_LE_RESTRICTED_FUNSPACE =
   |- !s t k.
           {f | IMAGE f s SUBSET t /\
               {x | ~(f x = k x)} SUBSET s /\
               FINITE {x | ~(f x = k x)}}
          <=_c {u | u SUBSET (s CROSS t) /\ FINITE u}

  INT_COUNTABLE = |- COUNTABLE (:int)

  int_INFINITE = |- INFINITE(:int)

Sat  2nd Dec 2017       README

Updated the build instructions, in particular taking into account the fact
(pointed out by John O'Leary) that OCaml >= 4.06 no longer includes the
"num" library by default.

Sat 18th Nov 2017       Makefile, update_database_3.ml, update_database_4.ml [new file]

Incorporated an improved "update_database.ml" file from Michael Färber which
handles theorems inside modules; this had otherwise started failing in more
recent versions of OCaml. Rather than add yet more version-dependent logic into
the files themselves, renamed the old "update_database.ml" file as
"update_database_3.ml", called the new one "update_database_4.ml" and modified
the Makefile to copy the appropriate one to "update_database.ml".

Mon 29th Oct 2017       iter.ml

Fixed a weird fumble in ITERATE_CLAUSES_GEN where there was a
redundant instance of the "monoidal" hypothesis.

Wed 11th Oct 2017       sets.ml

Added three more simple lemmas about the "cartesian_product" construct:

  CARTESIAN_PRODUCT_EMPTY =
    |- !s. cartesian_product {} s = {(\i. ARB)}

  CARTESIAN_PRODUCT_EQ_MEMBERS_EQ =
    |- !k s x y.
          x IN cartesian_product k s /\
          y IN cartesian_product k s
          ==> (x = y <=> !i. i IN k ==> x i = y i)

  RESTRICTION_IN_CARTESIAN_PRODUCT =
    |- !k s (f:K->A).
          RESTRICTION k f IN cartesian_product k s <=>
          !i. i IN k ==> (f i) IN (s i)

Mon  2nd Oct 2017       parser.ml

Fixed an amazingly stupid and longstanding bug arising from mis-use of an
accumulator variable in preterm parsing. As a consequence "pfrees" could be
wrong in situations where the same variable appears both free and bound, which
can have consequences for determining the relevant variables in a set
abstraction, typified by the mis-parsing of this:

 `{{x | x IN (\i. T) /\ x i = 1} | i IN 1..n}`;;

versus the correctly parsed:

  `{{x | x IN (\j. T) /\ x i = 1} | i IN 1..n}`;;

Sat 30th Sep 2017       Multivariate/homology.ml [new file]

Added a new file with an initial development of singular homology.

Sun 24th Sep 2017       Ntrie/ntrie.ml

Added a complete revision from Marco Maggesi of the "Ntrie" library for
manipulation of concrete numeral sets using a trie-like representation. Among
other improvements, the conversions have been made cleaner (always failing
predictably on non-minimal ntries) and much more efficient (typically 5x-15x as
fast), and a syntax extension for ntries has been added.

Wed 20th Sep 2017       int.ml, Library/prime.ml

Moved a few existing things (theorems DIVIDES_ANTISYM, DIVIDES_LE_STRONG,
DIVIDES_ONE and the definition of "prime") from "Library/prime.ml" into the
core, to avoid loading all that file for a few more simple facts, and also
added two new (and trivial) theorems:

  ONE_OR_PRIME =
    |- !p. p = 1 \/ prime p <=> (!n. n divides p ==> n = 1 \/ n = p)

  FORALL_INT_CASES =
    |- !P:int->bool. (!x. P x) <=> (!n. P(&n)) /\ (!n. P(-- &n))

Sat 16th Sep 2017       Library/frag.ml [new file], Library/grouptheory.ml

Added another file "Library/frag.ml" with a type constructor for defining the
free Abelian group on a given type. Incorporated this into the general group
theory. In that "Library/grouptheory.ml" file, systematically adopted a
multiplicative terminology (changing various names from "op/OP" to "mul/MUL")
as well as adding new material: powers (natural number and integer), trivial
homomorphisms, Abelian groups, cyclic groups and the group of integers.

Sun 10th Sep 2017       Library/grouptheory.ml [new file]

Added a new file with a basic development of group theory, using a type of
":(A)group" for a group on a (subset of a) type ":A". So far this is all pretty
elementary but it's good to have some standard version of groups.

Fri  1st Sep 2017       sets.ml

Added a simple theorem about the image of a Cartesian product:

  IMAGE_PAIRED_CROSS =
    |- !f g s t.
           IMAGE (\(x,y). f x,g y) (s CROSS t) = IMAGE f s CROSS IMAGE g t

Thu 24th Aug 2017       passim

Eliminated a number of duplicated theorems (often exact duplicates,
otherwise differing at most in their outer universal quantifiers or
bound variable names):

        BOREL_INDUCT_OPEN_UNIONS_INTERS -> BOREL_INDUCT_UNIONS_INTERS
        CLOSED_SIMPLEX -> SIMPLEX_IMP_CLOSED
        COMPACT_IN_SUBTOPOLOGY_EQ -> COMPACT_IN_SUBTOPOLOGY
        COMPACT_SIMPLEX -> SIMPLEX_IMP_COMPACT
        COMPLEX_DIFFERENTIABLE_COMPOSE -> COMPLEX_DIFFERENTIABLE_COMPOSE_AT
        CONVEX_SIMPLEX -> SIMPLEX_IMP_CONVEX
        DIAGONAL_MATRIX_MUL_EXPLICIT -> MATRIX_MUL_DIAGONAL
        DOT_NORM_NEG -> DOT_NORM_SUB
        FINITE_EMPTY_INTERIOR -> EMPTY_INTERIOR_FINITE
        HAS_VECTOR_DERIVATIVE_UNIQUE_AT -> VECTOR_DERIVATIVE_AT
        HAUSDIST_TRANS -> HAUSDIST_TRIANGLE
        INT_LE_NEG -> INT_LE_NEG2
        INT_LT_NEG -> INT_LT_NEG2
        INT_NEGNEG -> INT_NEG_NEG
        INT_OF_REAL_OF_INT -> int_abstr
        LAMBDA_UNPAIR_THM -> LAMBDA_PAIR
        LIM_NULL_COMPLEX_BOUND -> LIM_NULL_COMPARISON_COMPLEX
        MATRIX_LEFT_INVERTIBLE_NULLSPACE -> MATRIX_LEFT_INVERTIBLE_KER
        MBOUNDED_IFF_FINITE_DIAMETER -> MBOUNDED_ALT
        PSUBSET_MEMBER -> PSUBSET_ALT
        REALLIM_TRANSFORM_BOUND -> REALLIM_NULL_COMPARISON
        REAL_LE_NEG -> REAL_LE_NEG2
        REAL_LT_NEG -> REAL_LT_NEG2
        REAL_NEGNEG -> REAL_NEG_NEG
        REAL_POS_NZ -> REAL_LT_IMP_NZ
        RELATIVE_FRONTIER_CONVEX_HULL_CASES -> RELATIVE_FRONTIER_OF_CONVEX_HULL
        SETDIST_LIPSCHITZ -> SETDIST_SING_TRIANGLE
        num_RECURSION_STD -> num_RECURSION

Also changed the following to be the genuinely distinct theorems that were
presumably intended:

  ABS_DROP (was same as NORM_1)
  ANGLE_EQ_PI_RIGHT (was same as ANGLE_EQ_PI_LEFT)
  CLOSURE_RATIONALS_IN_OPEN_SET (was same as CLOSURE_DYADIC_RATIONALS_IN_OPEN_SET)
  CONNECTED_CONVEX_1_GEN (was same as CONVEX_CONNECTED_1_GEN)

Fri 18th Aug 2017       real.ml

Added quite a few new and fairly basic real number theorems (some of the convex
bounds ones were moved out of Multivariate/misc.ml).

  REAL_ABS_LE_SQRT =
   |- !x y. abs(sqrt x - sqrt y) <= sqrt (&2 * abs(x - y))

  REAL_ABS_LE_SQRT_POS =
    |- !x y. &0 <= x /\ &0 <= y ==> abs(sqrt x - sqrt y) <= sqrt (abs(x - y))

  REAL_ABS_SQRT =
    |- !x. abs(sqrt x) = sqrt (abs x)

  REAL_CONVEX_BOUND2_LE =
    |- !x y a u v.
           x <= a /\ y <= b /\ &0 <= u /\ &0 <= v /\ u + v = &1
           ==> u * x + v * y <= u * a + v * b

  REAL_CONVEX_BOUND2_LT =
    |- !x y a u v.
           x < a /\ y < b /\ &0 <= u /\ &0 <= v /\ u + v = &1
           ==> u * x + v * y < u * a + v * b

  REAL_CONVEX_BOUNDS_LE =
    |- !x y a b u v.
           a <= x /\
           x <= b /\
           a <= y /\
           y <= b /\
           &0 <= u /\
           &0 <= v /\
           u + v = &1
           ==> a <= u * x + v * y /\ u * x + v * y <= b

  REAL_CONVEX_BOUNDS_LT =
    |- !x y a b u v.
           a < x /\ x < b /\ a < y /\ y < b /\ &0 <= u /\ &0 <= v /\ u + v = &1
           ==> a < u * x + v * y /\ u * x + v * y < b

  REAL_CONVEX_BOUND_GE =
    |- !x y a u v.
           a <= x /\ a <= y /\ &0 <= u /\ &0 <= v /\ u + v = &1
           ==> a <= u * x + v * y

  REAL_CONVEX_BOUND_GT =
    |- !x y a u v.
           a < x /\ a < y /\ &0 <= u /\ &0 <= v /\ u + v = &1
           ==> a < u * x + v * y

  REAL_CONVEX_BOUND_LE =
    |- !x y a u v.
           x <= a /\ y <= a /\ &0 <= u /\ &0 <= v /\ u + v = &1
           ==> u * x + v * y <= a

  REAL_CONVEX_BOUND_LT =
    |- !x y a u v.
           x < a /\ y < a /\ &0 <= u /\ &0 <= v /\ u + v = &1
           ==> u * x + v * y < a

  REAL_DIV_EQ_1 =
    |- !x y. x / y = &1 <=> x = y /\ ~(x = &0) /\ ~(y = &0)

  SQRT_EQ_1 =
    |- !x. sqrt x = &1 <=> x = &1

Fri  4th Aug 2017       IsabelleLight/new_tactics.ml

Made a tiny tweak of adding parens where very old versions of OCaml
expect them.

Thu  3rd Aug 2017       Makefile, pa_j_4.xx_7.xx.ml [new file]

Made some changes suggested by Hendrik Tews to support the latest OCaml (4.05)
and camlp5 (7.01).

Sat 29th Jul 2017       passim

Merged in three github pull requests from asr (Makefile), Hendrik Tews
(parallel tests) and Petros Papapanagiotou (Isabelle Light and
Boyer-Moore improvements).

Thu 22nd Jun 2017       sets.ml, Multivariate/misc.ml

Added three new theorems about Cartesian product as well as moving the
definition of and lemmas about RESTRICTION into the main sets.ml file,
so overall we have these new theorems in the core:

  CARTESIAN_PRODUCT_SINGS =
    |- !k x. EXTENSIONAL k x ==> cartesian_product k (\i. {x i}) = {x}

  CARTESIAN_PRODUCT_SINGS_GEN =
    |- !k x. cartesian_product k (\i. {x i}) = {RESTRICTION k x}

  FORALL_CARTESIAN_PRODUCT_ELEMENTS_EQ =
    |- !P k s.
         ~(cartesian_product k s = {})
         ==> ((!i x. i IN k /\ x IN s i ==> P i x) <=>
              (!z i. z IN cartesian_product k s /\ i IN k ==> P i (z i)))

  IMAGE_RESTRICTION =
    |- !f s t. s SUBSET t ==> IMAGE (RESTRICTION t f) s = IMAGE f s

  RESTRICTION =
    |- !s f x. RESTRICTION s f x = (if x IN s then f x else ARB)

  RESTRICTION_COMPOSE =
    |- !f g s t.
         IMAGE f s SUBSET t
         ==> RESTRICTION s (RESTRICTION t g o RESTRICTION s f) =
             RESTRICTION s (g o f)

  RESTRICTION_COMPOSE_LEFT =
    |- !f g s t.
         IMAGE f s SUBSET t
         ==> RESTRICTION s (RESTRICTION t g o f) = RESTRICTION s (g o f)

  RESTRICTION_COMPOSE_RIGHT =
    |- !f g s. RESTRICTION s (g o RESTRICTION s f) = RESTRICTION s (g o f)

  RESTRICTION_DEFINED =
    |- !s f x. x IN s ==> RESTRICTION s f x = f x

  RESTRICTION_EQ =
    |- !s f x y. x IN s /\ f x = y ==> RESTRICTION s f x = y

  RESTRICTION_EXTENSION =
    |- !s f g. RESTRICTION s f = RESTRICTION s g <=> (!x. x IN s ==> f x = g x)

  RESTRICTION_FIXPOINT =
    |- !s f. RESTRICTION s f = f <=> f IN EXTENSIONAL s

  RESTRICTION_IDEMP =
    |- !s f. RESTRICTION s (RESTRICTION s f) = RESTRICTION s f

  RESTRICTION_IN_EXTENSIONAL =
    |- !s f. RESTRICTION s f IN EXTENSIONAL s

  RESTRICTION_RESTRICTION =
    |- !s t f. s SUBSET t ==> RESTRICTION s (RESTRICTION t f) = RESTRICTION s f

  RESTRICTION_UNDEFINED =
    |- !s f x. ~(x IN s) ==> RESTRICTION s f x = ARB

Tue 13th Jun 2017       drule.ml, grobner.ml

Fixed a couple of cases where "||" was used instead of "or" in error
strings, as a result of overenthusiastic search-and-replace.

Wed  7th Jun 2017       arith.ml, sets.ml, Library/card.ml

Added a few miscellaneous theorems including some basics about
cardinality of Cartesian products:

  CARD_DIFF_CONG =
    |- !s s' t t'.
         s' SUBSET s /\
         t' SUBSET t /\
         s =_c t /\
         s' =_c t' /\
         (INFINITE s ==> s' <_c s)
         ==> s DIFF s' =_c t DIFF t'

  CARD_EQ_REAL_SUBSET =
    |- !s a b. a < b /\ (!x. a < x /\ x < b ==> x IN s) ==> s =_c (:real)

  CARD_LE_1 =
    |- !s. FINITE s /\ CARD s <= 1 <=> (?a. s SUBSET {a})

  CARD_LE_CARTESIAN_PRODUCT =
    |- !s t k.
         (!i. i IN k ==> s i <=_c t i)
         ==> cartesian_product k s <=_c cartesian_product k t

  CARD_LE_CARTESIAN_PRODUCT_SUBINDEX =
    |- !s k l.
         k SUBSET l /\ ~(cartesian_product l s = {})
         ==> cartesian_product k s <=_c cartesian_product l s

  CARD_LE_EQ_SUBSET_UNIV =
    |- !s. (?t. t =_c s) <=> s <=_c (:B)

  CARD_LE_SING =
    |- !c s. s <=_c {c} <=> (?a. s SUBSET {a})

  CARTESIAN_PRODUCT_CONST =
    |- !s t. cartesian_product t (\i. s) = s ^_c t

  CARTESIAN_PRODUCT_EQ_MEMBERS =
    |- !k s x y.
         x IN cartesian_product k s /\
         y IN cartesian_product k s /\
         (!i. i IN k ==> x i = y i)
         ==> x = y

  COUNTABLE_CARTESIAN_PRODUCT =
    |- !s k.
         COUNTABLE (cartesian_product k s) <=>
         cartesian_product k s = {} \/
         FINITE {i | i IN k /\ ~(?a. s i SUBSET {a})} /\
         (!i. i IN k ==> COUNTABLE (s i))

  COUNTABLE_RESTRICTED_FUNSPACE =
    |- !s t k.
         COUNTABLE s /\ COUNTABLE t
         ==> COUNTABLE
             {f | IMAGE f s SUBSET t /\
                  {x | ~(f x = k x)} SUBSET s /\
                  FINITE {x | ~(f x = k x)}}

  EQ_C_BIJECTIONS_DISJOINT =
    |- !s s' t t'.
         DISJOINT s s' /\ DISJOINT t t'
         ==> (s =_c t /\ s' =_c t' <=>
              (?f g.
                   (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
                   (!y. y IN t ==> g y IN s /\ f (g y) = y) /\
                   (!x. x IN s' ==> f x IN t' /\ g (f x) = x) /\
                   (!y. y IN t' ==> g y IN s' /\ f (g y) = y)))

  EQ_C_BIJECTIONS_EXTEND =
    |- !f g s s' t t'.
         s SUBSET s' /\
         t SUBSET t' /\
         s' DIFF s =_c t' DIFF t /\
         (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
         (!y. y IN t ==> g y IN s /\ f (g y) = y)
         ==> (?f' g'.
                  (!x. x IN s' ==> f' x IN t' /\ g' (f' x) = x) /\
                  (!y. y IN t' ==> g' y IN s' /\ f' (g' y) = y) /\
                  (!x. x IN s ==> f' x = f x) /\
                  (!y. y IN t ==> g' y = g y))

  EQ_C_BIJECTIONS_SUBSETS =
    |- !s s' t t'.
         s' SUBSET s /\ t' SUBSET t
         ==> (s' =_c t' /\ s DIFF s' =_c t DIFF t' <=>
              (?f g.
                   (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
                   (!y. y IN t ==> g y IN s /\ f (g y) = y) /\
                   IMAGE f s' = t' /\
                   IMAGE g t' = s'))

  EQ_C_BIJECTIONS_SUBSETS_LT =
    |- !s s' t t'.
         s' SUBSET s /\ t' SUBSET t /\ (INFINITE s ==> s' <_c s)
         ==> (s =_c t /\ s' =_c t' <=>
              (?f g.
                   (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
                   (!y. y IN t ==> g y IN s /\ f (g y) = y) /\
                   IMAGE f s' = t' /\
                   IMAGE g t' = s'))

  EQ_C_INVOLUTION =
    |- !f s t.
         (!x. x IN s ==> f x IN t) /\
         (!x. x IN t ==> f x IN s) /\
         (!x. x IN s \/ x IN t ==> f (f x) = x)
         ==> s =_c t

  FINITE_CARTESIAN_PRODUCT =
    |- !s k.
         FINITE(cartesian_product k s) <=>
         cartesian_product k s = {} \/
         FINITE {i | i IN k /\ ~(?a. s i SUBSET {a})} /\
         (!i. i IN k ==> FINITE(s i))

  FINITE_POWERSET_EQ =
    |- !s. FINITE {t | t SUBSET s} <=> FINITE s

  FINITE_RESTRICTED_FUNSPACE =
    |- !s t k.
         FINITE s /\ FINITE t
         ==> FINITE {f | IMAGE f s SUBSET t /\ {x | ~(f x = k x)} SUBSET s}

  LT_IMP_NE =
    |- !m n. m < n ==> ~(m = n)

Tue  6th Jun 2017       calc_rat.ml

Added some basic properties of the "shrinking" mapping x |-> x / (1 + |x|)
and its inverse. These have natural generalizations to R^n (see
CONVEXITY_PRESERVING_SHRINK_0 in "Multivariate/convex.ml") but these simple
forms are nice to have too:

  REAL_GROW_SHRINK =
    |- !x y. x / (&1 + abs x) / (&1 - abs(x / (&1 + abs x))) = x

  REAL_SHRINK_EQ =
    |- !x y. x / (&1 + abs x) = y / (&1 + abs y) <=> x = y

  REAL_SHRINK_GALOIS =
    |- !x y. x / (&1 + abs x) = y <=> abs y < &1 /\ y / (&1 - abs y) = x

  REAL_SHRINK_GROW =
    |- !x y. abs x < &1
             ==> x / (&1 - abs x) / (&1 + abs(x / (&1 - abs x))) = x

  REAL_SHRINK_GROW_EQ =
    |- !x y. x / (&1 - abs x) / (&1 + abs(x / (&1 - abs x))) = x <=>
             abs x < &1

  REAL_SHRINK_LE =
    |- !x y. x / (&1 + abs x) <= y / (&1 + abs y) <=> x <= y

  REAL_SHRINK_LT =
    |- !x y. x / (&1 + abs x) < y / (&1 + abs y) <=> x < y

  REAL_SHRINK_RANGE =
    |- !x. abs(x / (&1 + abs x)) < &1

Sat  3rd Jun 2017       Library/floor.ml

Added some more specific versions of rational approximation where we
want to choose "p-adic" rationals:

  PADIC_RATIONAL_APPROXIMATION_STRADDLE =
    |- !p x e.
         &0 < e /\ &1 < p
         ==> (?n q r.
                  integer q /\
                  integer r /\
                  q / p pow n < x /\
                  x < r / p pow n /\
                  abs(q / p pow n - r / p pow n) < e)

  PADIC_RATIONAL_APPROXIMATION_STRADDLE_POS =
    |- !p x e.
         &0 < e /\ &1 < p /\ &0 < x
         ==> (?n q r.
                  &q / p pow n < x /\
                  x < &r / p pow n /\
                  abs(&q / p pow n - &r / p pow n) < e)

  PADIC_RATIONAL_APPROXIMATION_STRADDLE_POS_LE =
    |- !p x e.
         &0 < e /\ &1 < p /\ &0 <= x
         ==> (?n q r.
                  &q / p pow n <= x /\
                  x < &r / p pow n /\
                  abs(&q / p pow n - &r / p pow n) < e)

Sat  3rd Jun 2017       real.ml, sets.ml, passim

Moved a few theorems into the core that were formerly tucked away in
"Multivariate/misc.ml", including variants of the Archimedean property:

  REAL_ARCH_INV =
    |- !e. &0 < e <=> (?n. ~(n = 0) /\ &0 < inv (&n) /\ inv (&n) < e)

  REAL_ARCH_POW =
    |- !x y. &1 < x ==> (?n. y < x pow n)

  REAL_ARCH_POW2 =
    |- !x. ?n. x < &2 pow n

  REAL_ARCH_POW_INV =
    |- !x y. &0 < y /\ x < &1 ==> (?n. x pow n < y)

  REAL_MAX_SUP =
    |- !x y. max x y = sup {x, y}

  REAL_MIN_INF =
     |- !x y. min x y = inf {x, y}

  REAL_POW_LBOUND =
    |- !x n. &0 <= x ==> &1 + &n * x <= (&1 + x) pow n

Sun 21st May 2017       arith.ml

Added ternary versions of the basic "WLOG" lemma for naturals, reals and
integers, as well as adding missing binary versions for integers:

  INT_WLOG_LE =
    |- (!x y. P x y <=> P y x) /\ (!x y. x <= y ==> P x y) ==> (!x y. P x y)

  INT_WLOG_LT =
    |- (!x. P x x) /\ (!x y. P x y <=> P y x) /\ (!x y. x < y ==> P x y)
       ==> (!x y. P x y)

  INT_WLOG_LE_3 =
    |- !P. (!x y z. P x y z ==> P y x z /\ P x z y) /\
           (!x y z. x <= y /\ y <= z ==> P x y z)
           ==> (!x y z. P x y z)

  REAL_WLOG_LE_3 =
    |- !P. (!x y z. P x y z ==> P y x z /\ P x z y) /\
           (!x y z. x <= y /\ y <= z ==> P x y z)
           ==> (!x y z. P x y z)

  WLOG_LE_3 =
    |- !P. (!x y z. P x y z ==> P y x z /\ P x z y) /\
           (!x y z. x <= y /\ y <= z ==> P x y z)
           ==> (!x y z. P x y z)

Sat 13th May 2017       printer.ml

Added a patch to the prettyprinter from Marco Maggesi that ensures better
printing of set enumerations and lists by inserting split hints in a correct
way. A typical example where this helps is the following term, which now prints
as shown, but was formerly broken up irregularly and hence was much less
readable.

  `{[a 1 2 3 4 5 6 7 8; b 1 2 3 4 5 6 7 8 9; c 1 2 3 4 5; d 1 2 3 4 5 6 7],
    [e 1 2 3 4 5 6; f 1 2 3 4 5 6 7 8; g 1 2 3 4 5],
    [h 1 2 3 4 5 6 7 8 9 10 11; i 1 2 3 4 5 6 7 8 9 10; j 1 2 3 4 5 6 7 8 9;
     k 1 2 3 4 5],
    [l 1 2 3 4 5 6 7 8 9; m 1 2 3 4 5 6 7 8; n 1 2 3 4 5 6 7 8 9;
     p 2 3 4 5 6 7 8 9]}`

Thu 11th May 2017       sets.ml

Added one more handy little theorem about arbitrary unions:

  ARBITRARY_UNION_OF_ALT =
    |- !B s.
         (ARBITRARY UNION_OF B) s <=>
         (!x. x IN s ==> (?u. u IN B /\ x IN u /\ u SUBSET s))

Sat  6th May 2017       sets.ml, Library/card.ml

Added four theorems that are rather easy special cases of existing
ones (FORALL_COUNTABLE_SUBSET_IMAGE_INJ etc.), but awkward enough
to derive by 1-liners that they are worth having for themselves:

  FINITE_IMAGE_EQ =
    |- !f s.
         FINITE(IMAGE f s) <=>
         (?t. FINITE t /\ t SUBSET s /\ IMAGE f s = IMAGE f t)

  FINITE_IMAGE_EQ_INJ =
    |- !f s.
         FINITE(IMAGE f s) <=>
         (?t. FINITE t /\
              t SUBSET s /\
              IMAGE f s = IMAGE f t /\
              (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y)))

  COUNTABLE_IMAGE_EQ =
    |- !f s.
         COUNTABLE (IMAGE f s) <=>
         (?t. COUNTABLE t /\ t SUBSET s /\ IMAGE f s = IMAGE f t)

  COUNTABLE_IMAGE_EQ_INJ =
    |- !f s.
         COUNTABLE (IMAGE f s) <=>
         (?t. COUNTABLE t /\
              t SUBSET s /\
              IMAGE f s = IMAGE f t /\
              (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y)))

Sat 30th Apr 2017       pair.ml, sets.ml, Library/card.ml

Added various simple lemmas, the only one that isn't completely trivial
being FORALL_CARTESIAN_PRODUCT_ELEMENTS:

  CARD_LE_COUNTABLE_INFINITE =
    |- !s t. COUNTABLE s /\ INFINITE t ==> s <=_c t

  CARD_LT_COUNTABLE_UNCOUNTABLE =
    |- !s t. COUNTABLE s /\ ~COUNTABLE t ==> s <_c t

  CARD_LT_NUM_REAL =
    |- (:num) <_c (:real)

  EXISTS_UNPAIR_FUN_THM =
    |- !P. (?f g. P f g) <=> (?h. P (FST o h) (SND o h))

  FORALL_CARTESIAN_PRODUCT_ELEMENTS =
    |- !P k s.
         (!z i. z IN cartesian_product k s /\ i IN k ==> P i (z i)) <=>
         cartesian_product k s = {} \/ (!i x. i IN k /\ x IN s i ==> P i x)

  FORALL_UNPAIR_FUN_THM =
    |- !P. (!f g. P f g) <=> (!h. P (FST o h) (SND o h))

  INTERS_ANTIMONO =
    |- !f g. g SUBSET f ==> INTERS f SUBSET INTERS g

  IN_GSPEC =
    |- !s. {x | x IN s} = s

  UNIONS_SINGS =
    |- !s. UNIONS {{x} | x IN s} = s

  UNIONS_SINGS_GEN =
    |- !P. UNIONS {{x} | P x} = {x | P x}

Wed 11th Apr 2017       pair.ml, sets.ml, cart.ml

Added a few more trivial but nice-to-have rewrites:

  EXISTS_PAIR_FUN_THM =
    |- !P. (?f. P f) <=> (?g h. P (\a. g a,h a))

  FORALL_PAIR_FUN_THM =
    |- !P. (!f. P f) <=> (!g h. P (\a. g a,h a))

  CROSS_SING =
    |- !x y. {x} CROSS {y} = {(x,y)}

  PCROSS_SING =
     |- !x y. {x} PCROSS {y} = {pastecart x y}

Sat  8th Apr 2017       cart.ml

Type-generalized PASTECART_INJ which had a pointless restriction to ":real".

Sat  8th Apr 2017       sets.ml

Added a number of new theorems from Andrea Gabrielli and Marco Maggesi, giving
some additional properties of sup and inf and using useful relational versions
"has_sup" and "has_inf" to express some properties more nicely:

  has_inf =
    |- !s b. s has_inf b <=> (!c. (!x. x IN s ==> c <= x) <=> c <= b)

  has_sup =
    |- !s b. s has_sup b <=> (!c. (!x. x IN s ==> x <= c) <=> b <= c)

  HAS_INF =
    |- !s l.
           s has_inf l <=>
           ~(s = {}) /\
           (!x. x IN s ==> l <= x) /\
           (!c. l < c ==> (?x. x IN s /\ x < c))

  HAS_INF_APPROACH =
    |- !s l c. s has_inf l /\ l < c ==> (?x. x IN s /\ x < c)

  HAS_INF_INF =
    |- !s l.
           s has_inf l <=>
           ~(s = {}) /\ (?b. !x. x IN s ==> b <= x) /\ inf s = l

  HAS_INF_LBOUND =
    |- !s b x. s has_inf b /\ x IN s ==> b <= x

  HAS_INF_LE =
    |- !s t l m.
           s has_inf l /\
           t has_inf m /\
           (!y. y IN t ==> (?x. x IN s /\ x <= y))
           ==> l <= m

  HAS_SUP =
    |- !s l.
           s has_sup l <=>
           ~(s = {}) /\
           (!x. x IN s ==> x <= l) /\
           (!c. c < l ==> (?x. x IN s /\ c < x))

  HAS_SUP_APPROACH =
    |- !s l c. s has_sup l /\ c < l ==> (?x. x IN s /\ c < x)

  HAS_SUP_LE =
    |- !s t l m.
           s has_sup l /\
           t has_sup m /\
           (!y. y IN t ==> (?x. x IN s /\ y <= x))
           ==> m <= l

  HAS_SUP_SUP =
    |- !s l.
           s has_sup l <=>
           ~(s = {}) /\ (?b. !x. x IN s ==> x <= b) /\ sup s = l

  HAS_SUP_UBOUND =
    |- !s b x. s has_sup b /\ x IN s ==> x <= b

  INF_APPROACH =
    |- !s c.
           ~(s = {}) /\ (?b. !x. x IN s ==> b <= x) /\ inf s < c
           ==> (?x. x IN s /\ x < c)

  INF_EXISTS =
    |- !s. (?l. s has_inf l) <=> ~(s = {}) /\ (?b. !x. x IN s ==> b <= x)

  SUP_APPROACH =
    |- !s c.
           ~(s = {}) /\ (?b. !x. x IN s ==> x <= b) /\ c < sup s
           ==> (?x. x IN s /\ c < x)

  SUP_EXISTS =
    |- !s. (?l. s has_sup l) <=> ~(s = {}) /\ (?b. !x. x IN s ==> x <= b)

Wed 29th Mar 2017       arith.ml

Added some natural theorems that were missing:

  DIV_EXP =
    |- m n p. ~(m = 0)
              ==> (m EXP n) DIV (m EXP p) =
                  if p <= n then m EXP (n - p)
                  else if m = 1 then 1 else 0)

  MOD_EXP =
    |- !m n p. ~(m = 0)
               ==> (m EXP n) MOD (m EXP p) =
                   if p <= n \/ m = 1 then 0 else m EXP n)

Tue 28th Mar 2017       Library/card.ml

Added a small but more compact reformulation of cardinal exponentiation:

  EXP_C =
   |- !s t. s ^_c t = {f | IMAGE f t SUBSET s /\ EXTENSIONAL t f}

Mon 27th Mar 2018       Library/floor.ml, Library/prime.ml

Added a few handy lemmas:

  RATIONAL_ABS_EQ = prove
    |- !x. rational(abs x) <=> rational x

  DIVIDES_EXP_LE_IMP = prove
    |- !p m n. m <= n ==> (p EXP m) divides (p EXP n)

  EXP_INDEX_DIVIDES = prove
    |- !p n. p EXP (index p n) divides n

  INDEX_ADD_MIN = prove
    |- !p m n. MIN (index p m) (index p n) <= index p (m + n)

  INDEX_SUB_MIN = prove
    |- !p m n. n < m ==> MIN (index p m) (index p n) <= index p (m - n)

Sat 25th Mar 2017       Minisat/minisat_parse.ml

Replaced the use of int32 literals "0x...l" with "Int32.of_int 0x...".
The former seems to have recently started to be problematic with the
camlp5 preprocessing; really the underlying problem should be investigated and
fixed but as this is the only instance, I just made this change for now.

Fri 24th Mar 2017       holtest, holtest.ml

Added "Multivariate/lpspaces.ml" to the test suite (formerly missing its
own individual entry, though it's called in 100/fourier.ml anyway).

Wed 22nd Mar 2017       Library/card.ml

Added another variant of relational cardinal equality, as well as simplifying
the proof of the Schroeder-Bernstein theorem using a formulation in the
relational style (following a paper by Chad Brown, perhaps actually following
Knaster?)

  EQ_C_ALT =
   |- s =_c t <=>
      ?R:A#B->bool. (!x. x IN s ==> ?!y. y IN t /\ R(x,y)) /\
                    (!y. y IN t ==> ?!x. x IN s /\ R(x,y))

Thu 16th Mar 2017       Makefile

Added yet another disjunct to the camlp5 version cases after a report from
Vu Khac Ky of a failure with camlp5 6.17 (currently the latest version).

Wed 15th Mar 2017       real.ml, Library/transc.ml, 100/sqrt.ml, Jordan/metric_spaces.ml, Jordan/jordan_curve_theorem.ml

Added a definition and basic properties of square roots to the core system,
mainly lifted from the existing Multivariate code. The proof that the
definition works is laborious without any analytical machinery but it seemed
artificial to make such a basic and well-known function dependent on such
machinery. Note that the definition is totalized to be sign-preserving,
which makes various theorems work nicely without side-conditions while not
affecting its value for nonnegative arguments where it is usually considered
to be defined. New definitions and theorems:

  sqrt = |- !x. sqrt x = (@y. real_sgn y = real_sgn x /\ y pow 2 = abs x)

  POW_2_SQRT =
     |- !x. &0 <= x ==> sqrt (x pow 2) = x

  POW_2_SQRT_ABS =
     |- !x. sqrt (x pow 2) = abs x

  REAL_DIV_SQRT =
     |- !x. &0 <= x ==> x / sqrt x = sqrt x

  REAL_LE_LSQRT =
     |- !x y. &0 <= y /\ x <= y pow 2 ==> sqrt x <= y

  REAL_LE_RSQRT =
     |- !x y. x pow 2 <= y ==> x <= sqrt y

  REAL_LSQRT_LE =
     |- !x y. &0 <= x /\ sqrt x <= y ==> x <= y pow 2

  REAL_LT_LSQRT =
     |- !x y. &0 <= y /\ x < y pow 2 ==> sqrt x < y

  REAL_LT_RSQRT =
     |- !x y. x pow 2 < y ==> x < sqrt y

  REAL_RSQRT_LE =
     |- !x y. &0 <= x /\ &0 <= y /\ x <= sqrt y ==> x pow 2 <= y

  REAL_SGN_SQRT =
     |- !x. real_sgn (sqrt x) = real_sgn x

  REAL_SQRT_POW_2 =
     |- !x. sqrt x pow 2 = abs x

  SQRT_0 =
     |- sqrt (&0) = &0

  SQRT_1 =
     |- sqrt (&1) = &1

  SQRT_DIV =
     |- !x y. sqrt (x / y) = sqrt x / sqrt y

  SQRT_EQ_0 =
     |- !x. sqrt x = &0 <=> x = &0

  SQRT_EVEN_POW2 =
     |- !n. EVEN n ==> sqrt (&2 pow n) = &2 pow (n DIV 2)

  SQRT_INJ =
     |- !x y. sqrt x = sqrt y <=> x = y

  SQRT_INV =
     |- !x. sqrt (inv x) = inv (sqrt x)

  SQRT_LE_0 =
     |- !x. &0 <= sqrt x <=> &0 <= x

  SQRT_LT_0 =
     |- !x. &0 < sqrt x <=> &0 < x

  SQRT_MONO_LE =
     |- !x y. x <= y ==> sqrt x <= sqrt y

  SQRT_MONO_LE_EQ =
     |- !x y. sqrt x <= sqrt y <=> x <= y

  SQRT_MONO_LT =
     |- !x y. x < y ==> sqrt x < sqrt y

  SQRT_MONO_LT_EQ =
     |- !x y. sqrt x < sqrt y <=> x < y

  SQRT_MUL =
     |- !x y. sqrt (x * y) = sqrt x * sqrt y

  SQRT_NEG =
     |- !x. sqrt (--x) = --sqrt x

  SQRT_POS_LE =
     |- !x. &0 <= x ==> &0 <= sqrt x

  SQRT_POS_LT =
     |- !x. &0 < x ==> &0 < sqrt x

  SQRT_POW2 =
     |- !x. sqrt x pow 2 = x <=> &0 <= x

  SQRT_POW_2 =
     |- !x. &0 <= x ==> sqrt x pow 2 = x

  SQRT_UNIQUE =
     |- !x y. &0 <= y /\ y pow 2 = x ==> sqrt x = y

  SQRT_UNIQUE_GEN =
      |- !x y. real_sgn y = real_sgn x /\ y pow 2 = abs x ==> sqrt x = y

  SQRT_WORKS =
     |- !x. &0 <= x ==> &0 <= sqrt x /\ sqrt x pow 2 = x

  SQRT_WORKS_GEN =
     |- !x. real_sgn (sqrt x) = real_sgn x /\ sqrt x pow 2 = abs x

Also removed either duplicates or weaker theorems (with more hypotheses)
sharing the same names from "Library/transc.ml", removed a dependency in
"100/sqrt.ml", and fixed some consequentially broken proofs in Jordan.

Sun  5th Mar 2017       sets.ml

Added a kind of infinite pigeonhole principle:

  FINITE_IMAGE_INFINITE =
    |- !f:A->B s.
          INFINITE s /\ FINITE(IMAGE f s)
          ==> ?a. a IN s /\ INFINITE {x | x IN s /\ f x = f a}

Thu  2nd Mar 2017       sets.ml, cart.ml

Added one more triviality about products of sets, both in the real product and
the "cart" variant:

  DISJOINT_CROSS =
   |- !s t s' t'.
        DISJOINT (s CROSS t) (s' CROSS t') <=>
        DISJOINT s s' \/ DISJOINT t t'

  DISJOINT_PCROSS =
   |- !s t s' t'.
        DISJOINT (s PCROSS t) (s' PCROSS t') <=>
        DISJOINT s s' \/ DISJOINT t t'

Sat 25th Feb 2017       sets.ml

Added one more trivial but handy theorems about Cartesian products:

  CARTESIAN_PRODUCT_UNIV = |- cartesian_product (:K) (\i. (:A)) = (:K->A)

Wed 15th Feb 2017       sets.ml

Added a definition of "extensional" functions, all the material lifted from
Multivariate/misc.ml (except for the renaming of UNDEFINED -> ARB, which helps
to emphasize that these are not truly partial functions). Used that to define a
natural space of general Cartesian products of sets (or, viewed differently, a
dependent function space), with a few lemmas. New definitions:

  ARB =
    |- ARB = (@x. F)

  EXTENSIONAL =
    |- !s. EXTENSIONAL s = {f | !x. ~(x IN s) ==> f x = ARB}

  cartesian_product =
    |- !k s.
         cartesian_product k s =
         {f | EXTENSIONAL k f /\ (!i. i IN k ==> f i IN s i)}

and theorems:

  CARTESIAN_PRODUCT =
    |- !k s.
           cartesian_product k s =
           {f | !i. f i IN (if i IN k then s i else {ARB})}

  CARTESIAN_PRODUCT_EQ =
    |- !k s t.
           cartesian_product k s = cartesian_product k t <=>
           cartesian_product k s = {} /\ cartesian_product k t = {} \/
           (!i. i IN k ==> s i = t i)

  CARTESIAN_PRODUCT_EQ_EMPTY =
    |- !k s. cartesian_product k s = {} <=> (?i. i IN k /\ s i = {})

  EXTENSIONAL_EMPTY =
    |- EXTENSIONAL {} = {(\x. ARB)}

  EXTENSIONAL_EQ =
    |- !s f g.
           f IN EXTENSIONAL s /\
           g IN EXTENSIONAL s /\
           (!x. x IN s ==> f x = g x)
           ==> f = g

  EXTENSIONAL_UNIV =
    |- !f. EXTENSIONAL (:A) f

  IMAGE_PROJECTION_CARTESIAN_PRODUCT =
    |- !k s i.
           IMAGE (\x. x i) (cartesian_product k s) =
           (if cartesian_product k s = {}
            then {}
            else if i IN k then s i else {ARB})

  INTER_CARTESIAN_PRODUCT =
    |- !k s t.
           cartesian_product k s INTER cartesian_product k t =
           cartesian_product k (\i. s i INTER t i)

  IN_EXTENSIONAL =
    |- !s f. f IN EXTENSIONAL s <=> (!x. ~(x IN s) ==> f x = ARB)

  IN_EXTENSIONAL_UNDEFINED =
    |- !s f x. f IN EXTENSIONAL s /\ ~(x IN s) ==> f x = ARB

  SUBSET_CARTESIAN_PRODUCT =
    |- !k s t.
           cartesian_product k s SUBSET cartesian_product k t <=>
           cartesian_product k s = {} \/ (!i. i IN k ==> s i SUBSET t i)

Sat  4th Feb 2017       sets.ml, Library/card.ml

Added quite a number of theorems about the UNION_OF and INTERSECTION_OF
constructs in three common cases, one of which uses a new constant
"ARBITRARY".

  ARBITRARY =
    |- !s. ARBITRARY s <=> T

  ARBITRARY_INTERSECTION_OF_COMPLEMENT =
    |- !P s.
           (ARBITRARY INTERSECTION_OF P) s <=>
           (ARBITRARY UNION_OF (\s. P ((:A) DIFF s))) ((:A) DIFF s)

  ARBITRARY_INTERSECTION_OF_EMPTY =
    |- !P. (ARBITRARY INTERSECTION_OF P) (:A)

  ARBITRARY_INTERSECTION_OF_IDEMPOT =
    |- !P. ARBITRARY INTERSECTION_OF ARBITRARY INTERSECTION_OF P =
           ARBITRARY INTERSECTION_OF P

  ARBITRARY_INTERSECTION_OF_INC =
    |- !P s. P s ==> (ARBITRARY INTERSECTION_OF P) s

  ARBITRARY_INTERSECTION_OF_INTER =
    |- !P s t.
           (ARBITRARY INTERSECTION_OF P) s /\ (ARBITRARY INTERSECTION_OF P) t
           ==> (ARBITRARY INTERSECTION_OF P) (s INTER t)

  ARBITRARY_INTERSECTION_OF_INTERS =
    |- !P u.
           (!s. s IN u ==> (ARBITRARY INTERSECTION_OF P) s)
           ==> (ARBITRARY INTERSECTION_OF P) (INTERS u)

  ARBITRARY_INTERSECTION_OF_UNION =
    |- !P. (!s t. P s /\ P t ==> P (s UNION t))
           ==> (!s t.
                    (ARBITRARY INTERSECTION_OF P) s /\
                    (ARBITRARY INTERSECTION_OF P) t
                    ==> (ARBITRARY INTERSECTION_OF P) (s UNION t))

  ARBITRARY_INTERSECTION_OF_UNION_EQ =
    |- !P. (!s t.
                (ARBITRARY INTERSECTION_OF P) s /\
                (ARBITRARY INTERSECTION_OF P) t
                ==> (ARBITRARY INTERSECTION_OF P) (s UNION t)) <=>
           (!s t. P s /\ P t ==> (ARBITRARY INTERSECTION_OF P) (s UNION t))

  ARBITRARY_UNION_OF_COMPLEMENT =
    |- !P s.
           (ARBITRARY UNION_OF P) s <=>
           (ARBITRARY INTERSECTION_OF (\s. P ((:A) DIFF s))) ((:A) DIFF s)

  ARBITRARY_UNION_OF_EMPTY =
    |- !P. (ARBITRARY UNION_OF P) {}

  ARBITRARY_UNION_OF_IDEMPOT =
    |- !P. ARBITRARY UNION_OF ARBITRARY UNION_OF P = ARBITRARY UNION_OF P

  ARBITRARY_UNION_OF_INC =
    |- !P s. P s ==> (ARBITRARY UNION_OF P) s

  ARBITRARY_UNION_OF_INTER =
    |- !P. (!s t. P s /\ P t ==> P (s INTER t))
           ==> (!s t.
                    (ARBITRARY UNION_OF P) s /\ (ARBITRARY UNION_OF P) t
                    ==> (ARBITRARY UNION_OF P) (s INTER t))

  ARBITRARY_UNION_OF_INTER_EQ =
    |- !P. (!s t.
                (ARBITRARY UNION_OF P) s /\ (ARBITRARY UNION_OF P) t
                ==> (ARBITRARY UNION_OF P) (s INTER t)) <=>
           (!s t. P s /\ P t ==> (ARBITRARY UNION_OF P) (s INTER t))

  ARBITRARY_UNION_OF_UNION =
    |- !P s t.
           (ARBITRARY UNION_OF P) s /\ (ARBITRARY UNION_OF P) t
           ==> (ARBITRARY UNION_OF P) (s UNION t)

  ARBITRARY_UNION_OF_UNIONS =
    |- !P u.
           (!s. s IN u ==> (ARBITRARY UNION_OF P) s)
           ==> (ARBITRARY UNION_OF P) (UNIONS u)

  FINITE_INTERSECTION_OF_COMPLEMENT =
    |- !P s.
           (FINITE INTERSECTION_OF P) s <=>
           (FINITE UNION_OF (\s. P ((:A) DIFF s))) ((:A) DIFF s)

  FINITE_INTERSECTION_OF_EMPTY =
    |- !P. (FINITE INTERSECTION_OF P) (:A)

  FINITE_INTERSECTION_OF_IDEMPOT =
    |- !P. FINITE INTERSECTION_OF FINITE INTERSECTION_OF P =
           FINITE INTERSECTION_OF P

  FINITE_INTERSECTION_OF_INC =
    |- !P s. P s ==> (FINITE INTERSECTION_OF P) s

  FINITE_INTERSECTION_OF_INTER =
    |- !P s t.
           (FINITE INTERSECTION_OF P) s /\ (FINITE INTERSECTION_OF P) t
           ==> (FINITE INTERSECTION_OF P) (s INTER t)

  FINITE_INTERSECTION_OF_INTERS =
    |- !P u.
           FINITE u /\ (!s. s IN u ==> (FINITE INTERSECTION_OF P) s)
           ==> (FINITE INTERSECTION_OF P) (INTERS u)

  FINITE_INTERSECTION_OF_UNION =
    |- !P. (!s t. P s /\ P t ==> P (s UNION t))
           ==> (!s t.
                    (FINITE INTERSECTION_OF P) s /\ (FINITE INTERSECTION_OF P) t
                    ==> (FINITE INTERSECTION_OF P) (s UNION t))

  FINITE_INTERSECTION_OF_UNION_EQ =
    |- !P. (!s t.
                (FINITE INTERSECTION_OF P) s /\ (FINITE INTERSECTION_OF P) t
                ==> (FINITE INTERSECTION_OF P) (s UNION t)) <=>
           (!s t. P s /\ P t ==> (FINITE INTERSECTION_OF P) (s UNION t))

  FINITE_UNION_OF_COMPLEMENT =
    |- !P s.
           (FINITE UNION_OF P) s <=>
           (FINITE INTERSECTION_OF (\s. P ((:A) DIFF s))) ((:A) DIFF s)

  FINITE_UNION_OF_EMPTY =
    |- !P. (FINITE UNION_OF P) {}

  FINITE_UNION_OF_IDEMPOT =
    |- !P. FINITE UNION_OF FINITE UNION_OF P = FINITE UNION_OF P

  FINITE_UNION_OF_INC =
    |- !P s. P s ==> (FINITE UNION_OF P) s

  FINITE_UNION_OF_INTER =
    |- !P. (!s t. P s /\ P t ==> P (s INTER t))
           ==> (!s t.
                    (FINITE UNION_OF P) s /\ (FINITE UNION_OF P) t
                    ==> (FINITE UNION_OF P) (s INTER t))

  FINITE_UNION_OF_INTER_EQ =
    |- !P. (!s t.
                (FINITE UNION_OF P) s /\ (FINITE UNION_OF P) t
                ==> (FINITE UNION_OF P) (s INTER t)) <=>
           (!s t. P s /\ P t ==> (FINITE UNION_OF P) (s INTER t))

  FINITE_UNION_OF_UNION =
    |- !P s t.
           (FINITE UNION_OF P) s /\ (FINITE UNION_OF P) t
           ==> (FINITE UNION_OF P) (s UNION t)

  FINITE_UNION_OF_UNIONS =
    |- !P u.
           FINITE u /\ (!s. s IN u ==> (FINITE UNION_OF P) s)
           ==> (FINITE UNION_OF P) (UNIONS u)

  FORALL_INTERSECTION_OF =
    |- (!s. (P INTERSECTION_OF Q) s ==> R s) <=>
       (!t. P t /\ (!c. c IN t ==> Q c) ==> R (INTERS t))

  FORALL_UNION_OF =
    |- (!s. (P UNION_OF Q) s ==> R s) <=>
       (!t. P t /\ (!c. c IN t ==> Q c) ==> R (UNIONS t))

  INTERSECTION_OF_EMPTY =
    |- !P Q. P {} ==> (P INTERSECTION_OF Q) (:A)

  UNION_OF_EMPTY =
    |- !P Q. P {} ==> (P UNION_OF Q) {}



  COUNTABLE_DISJOINT_UNION_OF_IDEMPOT =
    |- !P. (COUNTABLE INTER pairwise DISJOINT) UNION_OF
           (COUNTABLE INTER pairwise DISJOINT) UNION_OF P =
           (COUNTABLE INTER pairwise DISJOINT) UNION_OF P

  COUNTABLE_INTERSECTION_OF_EMPTY =
    |- !P. (COUNTABLE INTERSECTION_OF P) (:A)

  COUNTABLE_INTERSECTION_OF_UNIONS =
    |- !P u.
           (COUNTABLE INTERSECTION_OF P) {} /\
           (!s t. P s /\ P t ==> P (s UNION t)) /\
           FINITE u /\
           (!s. s IN u ==> (COUNTABLE INTERSECTION_OF P) s)
           ==> (COUNTABLE INTERSECTION_OF P) (UNIONS u)

  COUNTABLE_INTERSECTION_OF_UNIONS_NONEMPTY =
    |- !P u.
           (!s t. P s /\ P t ==> P (s UNION t)) /\
           FINITE u /\
           ~(u = {}) /\
           (!s. s IN u ==> (COUNTABLE INTERSECTION_OF P) s)
           ==> (COUNTABLE INTERSECTION_OF P) (UNIONS u)

  COUNTABLE_INTERSECTION_OF_UNION_EQ =
    |- !P. (!s t.
                (COUNTABLE INTERSECTION_OF P) s /\
                (COUNTABLE INTERSECTION_OF P) t
                ==> (COUNTABLE INTERSECTION_OF P) (s UNION t)) <=>
           (!s t. P s /\ P t ==> (COUNTABLE INTERSECTION_OF P) (s UNION t))

  COUNTABLE_UNION_OF_EMPTY =
    |- !P. (COUNTABLE UNION_OF P) {}

  COUNTABLE_UNION_OF_INTERS =
    |- !P u.
           (COUNTABLE UNION_OF P) (:A) /\
           (!s t. P s /\ P t ==> P (s INTER t)) /\
           FINITE u /\
           (!s. s IN u ==> (COUNTABLE UNION_OF P) s)
           ==> (COUNTABLE UNION_OF P) (INTERS u)

  COUNTABLE_UNION_OF_INTERS_NONEMPTY =
    |- !P u.
           (!s t. P s /\ P t ==> P (s INTER t)) /\
           FINITE u /\
           ~(u = {}) /\
           (!s. s IN u ==> (COUNTABLE UNION_OF P) s)
           ==> (COUNTABLE UNION_OF P) (INTERS u)

  COUNTABLE_UNION_OF_INTER_EQ =
    |- !P. (!s t.
                (COUNTABLE UNION_OF P) s /\ (COUNTABLE UNION_OF P) t
                ==> (COUNTABLE UNION_OF P) (s INTER t)) <=>
           (!s t. P s /\ P t ==> (COUNTABLE UNION_OF P) (s INTER t))

Sat 14th Jan 2017       passim

Switched quite a few more instances of the deprecated "&" to "&&" (these got
missed on the 9th Sep 2016 update because they are at the end of a line).

Fri 13th Jan 2017       lists.ml

Made a small recoding of a phrase that OCaml has started treating as
erroneous in version 4.03 (pointed out by Hendrik Tews).

Fri  6th Jan 2017       iterate.ml, 100/cayley_hamilton.ml

Added two more generic "iterate" theorems that were already there in
specific instances, and re-derived the special cases from them:

  ITERATE_RESTRICT_SET =
    |- !op. monoidal op
            ==> !P s f. iterate op {x | x IN s /\ P x} f =
                        iterate op s (\x. if P x then f x else neutral op)


  ITERATE_IMAGE_GEN =
    |- !op. monoidal op
            ==> !f g. FINITE s
                      ==> iterate op s g =
                          iterate op (IMAGE f s)
                             (\y. iterate op {x | x IN s /\ f x = y} g)

Sun  4th Dec 2016       iterate.ml

Added a generic "iterate" version of a theorem already present in various
instantiations (SUM_SWAP etc.)

  ITERATE_SWAP =
    |- !op. monoidal op
            ==> (!f s t.
                     FINITE s /\ FINITE t
                     ==> iterate op s (\i. iterate op t (f i)) =
                         iterate op t (\j. iterate op s (\i. f i j)))

Thu 17th Nov 2016       arith.ml, real.ml, int.ml, iterate.ml

Added a miscellany of trivial but handy theorems:

  INTER_NUMSEG =
    |- !m n p q. (m..n) INTER (p..q) = MAX m p..MIN n q

  INT_SGNS_EQ =
    |- !x y.
           int_sgn x = int_sgn y <=>
           (x = &0 <=> y = &0) /\ (x > &0 <=> y > &0) /\ (x < &0 <=> y < &0)

  INT_SGNS_EQ_ALT =
    |- !x y.
           int_sgn x = int_sgn y <=>
           (x = &0 ==> y = &0) /\ (x > &0 ==> y > &0) /\ (x < &0 ==> y < &0)

  LDIV_LT_EQ =
    |- !a b n. ~(a = 0) ==> (n < b DIV a <=> a * (n + 1) <= b)

  RDIV_LT_EQ =
    |- !a b n. ~(a = 0) ==> (b DIV a < n <=> b < a * n)

  REAL_SGNS_EQ =
    |- !x y.
           real_sgn x = real_sgn y <=>
           (x = &0 <=> y = &0) /\ (x > &0 <=> y > &0) /\ (x < &0 <=> y < &0)

  REAL_SGNS_EQ_ALT =
    |- !x y.
           real_sgn x = real_sgn y <=>
           (x = &0 ==> y = &0) /\ (x > &0 ==> y > &0) /\ (x < &0 ==> y < &0)

Mon 24th Oct 2016       wf.ml

Added the following theorem about defining recursive functions based on an
existential condition, after finally getting tired of effectively proving
special cases using the same reasoning:

  WF_REC_EXISTS =
    |- WF (<<)
       ==> (!P. (!f g x y.
                     (!z. z << x ==> f z = g z) ==> (P f x y <=> P g x y)) /\
                (!f x. (!z. z << x ==> P f z (f z)) ==> (?y. P f x y))
                ==> (?f. !x. P f x (f x)))

Sun 23rd Oct 2016       sets.ml, Library/isum.ml, Library/products.ml

Added the following occasionally handy manipulative theorem for iterated
operations, the generic one and various instances:

  ITERATE_UNIV =
    |- !op. monoidal op
            ==> (!f s.
                     support op f (:A) SUBSET s
                     ==> iterate op s f = iterate op (:A) f)

  NSUM_UNIV =
    |- !f s. support (+) f (:A) SUBSET s ==> nsum s f = nsum (:A) f

  SUM_UNIV =
    |- !f s. support (+) f (:A) SUBSET s ==> sum s f = sum (:A) f

  ISUM_UNIV =
    |- !f s. support (+) f (:A) SUBSET s ==> isum s f = isum (:A) f

  NPRODUCT_UNIV =
    |- !f s. support (*) f (:A) SUBSET s ==> nproduct s f = nproduct (:A) f

  PRODUCT_UNIV =
    |- !f s. support (*) f (:A) SUBSET s ==> product s f = product (:A) f

Thu  6th Oct 2016       preterm.ml, bool.ml, impconv.ml, nums.ml

Removed a few bindings that generate "unused variable" warnings from OCaml.

Thu  6th Oct 2016       calc_rat.ml, Multivariate/complexes.ml

Improved REAL_FIELD so that it does a somewhat better job of handling
denominators of the form "c pow n" where c is a rational number and
n is non-constant (actually the new version marginally improves the
case where c is variable too, e.g. REAL_FIELD `&n pow n / &n pow n = &1`).
The main differences are that prenormalization does not distribute
"inv" through "pow" in the case of a non-constant power, and then the
nonzeroness-proving logic uses obvious facts like ~(x = 0) ==> ~(x^n = 0).
For instance things like this now just work:

  REAL_FIELD `&2 pow m * x / &2 pow (n + m) * &2 pow n = x`;;

Also made a completely analogous change to COMPLEX_FIELD so for example

   COMPLEX_FIELD `Cx(&2) pow n / Cx(&2) pow n = Cx(&1)`;;

Tue  4th Oct 2016       int.ml

Added the trivial but convenient theorem:

  INTEGER_REAL_OF_INT = |- !x. integer(real_of_int x)

Tue  4th Oct 2016       Minisat/minisat_prove.ml

Fixed a long-standing and trivial bug in the preprocessing into clause form,
where definitionalization was missing a "mk_neg" in the code processing
implications, meaning they were partly confused with disjunctions. This must
have been able to lurk for such a long time because most of the tests are
already in clausal form.

Tue 27th Sep 2016       Library/floor.ml

Added a few more theorems about the "floor" function:

  REAL_FLOOR_FLOOR_DIV =
    |- !x n. floor (floor x / &n) = floor (x / &n)

  REAL_FLOOR_LT =
    |- !x n. integer n ==> (floor x < n <=> x < n)

  REAL_FLOOR_TRIANGLE =
    |- !x y.
           floor x + floor y <= floor (x + y) /\
           floor (x + y) <= (floor x + floor y) + &1

  REAL_LT_FLOOR =
    |- !x n. integer n ==> (n < floor x <=> n <= x - &1)

and renamed the existing REAL_FLOOR_LT to REAL_FLOOR_LT_REFL:

  |- !x. floor x < x <=> ~integer x

Fri  9th Sep 2016       passim

Changed all (?) instances of "&" to "&&" and "or" to "||" to avoid any
OCaml "deprecated" warnings which will presumably soon enough become
actual errors.

Fri  9th Sep 2016       parser.ml, theorems.ml, help.ml, Examples/mizar.ml, Examples/sos.ml, miz3/miz3.ml, Help/*.doc

Renamed the parser "or" combinator from "||" to "|||", which is a bit of
a mouthful but still quite intuitive. This seemed worth doing in principle
given that "||" is overwriting an OCaml builtin, and I was more motivated
because the word "or" is now deprecated in favour of "||" for the logical
"or" operation.

Fri  2nd Sep 2016       Library/card.ml

Added a couple more lemmas about bounding cardinalities of "sequences"
(expressed via cardinal exponentiation for maximum generality):

  CARD_EXP_LE_REAL =
    |- !s t. s <=_c (:real) /\ COUNTABLE t ==> s ^_c t <=_c (:real)

  CARD_EXP_EQ_REAL =
    |- !s. COUNTABLE s /\ ~(s = {}) ==> (:real) ^_c s =_c (:real)

Thu 25th Aug 2016       Library/sets.ml

Added a number of simple results about the COUNTABLE case of the new
constructs "UNION_OF" and "INTERSECTION_OF". This is the immediately
most useful case in topology, but one could of course reasonably
add "FINITE" or more general variants too.

  COUNTABLE_INTERSECTION_OF_COMPLEMENT =
    |- !P s. (COUNTABLE INTERSECTION_OF P) s <=>
             (COUNTABLE UNION_OF (\s. P((:A) DIFF s))) ((:A) DIFF s)

  COUNTABLE_INTERSECTION_OF_IDEMPOT =
    |- !P:(A->bool)->bool.
          COUNTABLE INTERSECTION_OF COUNTABLE INTERSECTION_OF P =
          COUNTABLE INTERSECTION_OF P

  COUNTABLE_INTERSECTION_OF_INC =
    |- !P s:A->bool. P s ==> (COUNTABLE INTERSECTION_OF P) s

  COUNTABLE_INTERSECTION_OF_INTER =
    |- !P s t. (COUNTABLE INTERSECTION_OF P) s /\
               (COUNTABLE INTERSECTION_OF P) t
               ==> (COUNTABLE INTERSECTION_OF P) (s INTER t)

  COUNTABLE_INTERSECTION_OF_INTERS =
    |- !P u:(A->bool)->bool.
          COUNTABLE u /\ (!s. s IN u ==> (COUNTABLE INTERSECTION_OF P) s)
          ==> (COUNTABLE INTERSECTION_OF P) (INTERS u)

  COUNTABLE_INTERSECTION_OF_UNION =
    |- !P:(A->bool)->bool.
          (!s t. P s /\ P t ==> P(s UNION t))
          ==> (!s t. (COUNTABLE INTERSECTION_OF P) s /\
                     (COUNTABLE INTERSECTION_OF P) t
                     ==> (COUNTABLE INTERSECTION_OF P) (s UNION t))

  COUNTABLE_UNION_OF_ASCENDING =
    |- !P s:A->bool.
          P {} /\ (!t u. P t /\ P u ==> P(t UNION u))
          ==> ((COUNTABLE UNION_OF P) s <=>
               ?t. (!n. P(t n)) /\
                   (!n. t n SUBSET t(SUC n)) /\
                   UNIONS {t n | n IN (:num)} = s)

  COUNTABLE_UNION_OF_COMPLEMENT =
    |- !P s. (COUNTABLE UNION_OF P) s <=>
             (COUNTABLE INTERSECTION_OF (\s. P((:A) DIFF s))) ((:A) DIFF s)

  COUNTABLE_UNION_OF_EXPLICIT =
    |- !P s:A->bool.
          P {}
          ==> ((COUNTABLE UNION_OF P) s <=>
               ?t. (!n. P(t n)) /\ UNIONS {t n | n IN (:num)} = s)

  COUNTABLE_UNION_OF_IDEMPOT =
    |- !P:(A->bool)->bool.
          COUNTABLE UNION_OF COUNTABLE UNION_OF P = COUNTABLE UNION_OF P

  COUNTABLE_UNION_OF_INC =
    |- !P s:A->bool. P s ==> (COUNTABLE UNION_OF P) s

  COUNTABLE_UNION_OF_INTER =
    |- !P:(A->bool)->bool.
          (!s t. P s /\ P t ==> P(s INTER t))
          ==> (!s t. (COUNTABLE UNION_OF P) s /\ (COUNTABLE UNION_OF P) t
                     ==> (COUNTABLE UNION_OF P) (s INTER t))

  COUNTABLE_UNION_OF_UNION =
    |- !P s t. (COUNTABLE UNION_OF P) s /\ (COUNTABLE UNION_OF P) t
             ==> (COUNTABLE UNION_OF P) (s UNION t)

  COUNTABLE_UNION_OF_UNIONS =
    |- !P u:(A->bool)->bool.
          COUNTABLE u /\ (!s. s IN u ==> (COUNTABLE UNION_OF P) s)
          ==> (COUNTABLE UNION_OF P) (UNIONS u)

Fri 19th Aug 2016       sets.ml

Added a few basic theorems, one trivial but very useful fact that
complementation is an involution, and a few basic general properties
of the "UNION_OF" and "INTERSECTION_OF" constructs:

  COMPL_COMPL =
    |- !s. (:A) DIFF ((:A) DIFF s) = s

  INTERSECTION_OF_INC =
    |- !P Q s:A->bool. P {s} /\ Q s ==> (P INTERSECTION_OF Q) s

  INTERSECTION_OF_MONO =
    |- !P Q Q' s:A->bool.
         (P INTERSECTION_OF Q) s /\ (!x. Q x ==> Q' x)
         ==> (P INTERSECTION_OF Q') s

  UNION_OF_INC =
    |- !P Q s:A->bool. P {s} /\ Q s ==> (P UNION_OF Q) s

  UNION_OF_MONO =
    |- !P Q Q' s:A->bool.
        (P UNION_OF Q) s /\ (!x. Q x ==> Q' x) ==> (P UNION_OF Q') s


Fri 12th Aug 2016       sets.ml

Added two natural infix constants "UNION_OF" and "INTERSECTION_OF" for the
useful and otherwise longwinded idiom that a set is a suitable (e.g. finite or
countable or pairwise disjoint) union/intersection of "somethings". Typical
examples are topological: `fsigma = COUNTABLE UNION_OF closed` etc.

        UNION_OF =
          |- !P Q. P UNION_OF Q =
                   (\s. ?u. P u /\ (!c. c IN u ==> Q c) /\ UNIONS u = s)

        INTERSECTION_OF =
          |- !P Q. P INTERSECTION_OF Q =
                   (\s. ?u. P u /\ (!c. c IN u ==> Q c) /\ INTERS u = s)

Sat  9th Jul 2016       Makefile

Added yet another disjunct to the OCaml and camlp5 version case split
for 4.03 and 6.15 respectively (Flemming Andersen pointed out that
this combination failed).

Sun  3rd Jul 2016       cart.ml

Added a finite-forcing Cartesian product for type indices (a natural thing to
have by analogy with finite_sum and finite_diff, and also requested on
hol-info by Abid Rauf):

  finite_prod_tybij =
    |- (!a. mk_finite_prod(dest_finite_prod a) = a) /\
       (!r. r IN 1..dimindex(:A) * dimindex(:B) <=>
            dest_finite_prod(mk_finite_prod r) = r)

  FINITE_PROD_IMAGE =
    |- (:(A,B)finite_prod) =
       IMAGE mk_finite_prod (1..dimindex(:A) * dimindex(:B))

  DIMINDEX_HAS_SIZE_FINITE_PROD =
    |- (:(M,N)finite_prod) HAS_SIZE dimindex(:M) * dimindex(:N)

  DIMINDEX_FINITE_PROD =
    |- dimindex(:(M,N)finite_prod) = dimindex(:M) * dimindex(:N)

Sun  3rd Jul 2016       sets.ml, cart.ml

Added analogous theorems about distributing intersections over
Cartesian products, in two forms:

  CROSS_INTERS =
   |- (!s f. s CROSS (INTERS f) =
             if f = {} then s CROSS UNIV else INTERS {s CROSS t | t IN f}) /\
      (!f t. (INTERS f) CROSS t =
             if f = {} then UNIV CROSS t else INTERS {s CROSS t | s IN f})

  CROSS_INTERS_INTERS =
    |- !f g. (INTERS f) CROSS (INTERS g) =
             if f = {} then INTERS {UNIV CROSS t | t IN g}
             else if g = {} then INTERS {s CROSS UNIV | s IN f}
             else INTERS {s CROSS t | s IN f /\ t IN g}

  PCROSS_INTERS =
    |- (!s f. s PCROSS (INTERS f) =
              if f = {} then s PCROSS UNIV
              else INTERS {s PCROSS t | t IN f}) /\
       (!f t. (INTERS f) PCROSS t =
              if f = {} then UNIV PCROSS t else INTERS {s PCROSS t | s IN f})

  PCROSS_INTERS_INTERS =
    |- !f g. (INTERS f) PCROSS (INTERS g) =
             if f = {} then INTERS {UNIV PCROSS t | t IN g}
             else if g = {} then INTERS {s PCROSS UNIV | s IN f}
             else INTERS {s PCROSS t | s IN f /\ t IN g}

Fri 24th Jun 2016       lists.ml

Added a definition of "list_of_seq" mapping a sequence s and length n
to the list [s_0,...,s_{n-1}], and various basic list theorems:


  APPEND_LCANCEL =
    |- !l1 l2 l3. APPEND l1 l2 = APPEND l1 l3 <=> l2 = l3

  APPEND_RCANCEL =
    |- !l1 l2 l3. APPEND l1 l3 = APPEND l2 l3 <=> l1 = l2

  BUTLAST_APPEND =
    |- !l m.
         BUTLAST (APPEND l m) =
         (if m = [] then BUTLAST l else APPEND l (BUTLAST m))

  EL_LIST_OF_SEQ =
    |- !s m n. m < n ==> EL m (list_of_seq s n) = s m

  LENGTH_LIST_OF_SEQ =
    |- !s n. LENGTH (list_of_seq s n) = n

  LIST_EQ =
    |- !l1 l2.
         l1 = l2 <=>
         LENGTH l1 = LENGTH l2 /\ (!n. n < LENGTH l2 ==> EL n l1 = EL n l2)

  LIST_OF_SEQ_EQ_NIL =
    |- !s n. list_of_seq s n = [] <=> n = 0

  list_of_seq =
    |- list_of_seq s 0 = [] /\
       list_of_seq s (SUC n) = APPEND (list_of_seq s n) [s n]

Fri 24th Jun 2016       sets.ml

Added a few more handy set lemmas

  INTER_INTERS =
   |- (!f s. s INTER INTERS f =
             if f = {} then s else INTERS {s INTER t | t IN f}) /\
      (!f s. INTERS f INTER s =
             if f = {} then s else INTERS {t INTER s | t IN f})

  FINITE_UNIV_PAIR =
   |- FINITE(:A#A) <=> FINITE(:A)

  INFINITE_UNIV_PAIR =
   |- INFINITE(:A#A) <=> INFINITE(:A)

Tue 14th Jun 2016       sets.ml

Added a few handy set theory lemmas, mainly on a theme of finite subsets
of the union of a chain:

  CARD_LE_UNIONS_CHAIN =
    |- !f n.
         (!t u. t IN f /\ u IN f ==> t SUBSET u \/ u SUBSET t) /\
         (!t. t IN f ==> FINITE t /\ CARD t <= n)
         ==> FINITE(UNIONS f) /\ CARD(UNIONS f) <= n

  CHOOSE_SUBSET_EQ =
    |- !n s. FINITE s ==> n <= CARD s <=> (?t. t SUBSET s /\ t HAS_SIZE n)

  FINITE_SUBSET_UNIONS =
    |- !f s.
           FINITE s /\ s SUBSET UNIONS f
           ==> (?f'. FINITE f' /\ f' SUBSET f /\ s SUBSET UNIONS f')

  FINITE_SUBSET_UNIONS_CHAIN =
    |- !f s.
           FINITE s /\
           s SUBSET UNIONS f /\
           ~(f = {}) /\
           (!t u. t IN f /\ u IN f ==> t SUBSET u \/ u SUBSET t)
           ==> (?t. t IN f /\ s SUBSET t)

  INTERS_IN_CHAIN =
    |- !f. FINITE f /\
           ~(f = {}) /\
           (!s t. s IN f /\ t IN f ==> s SUBSET t \/ t SUBSET s)
           ==> INTERS f IN f

  UNIONS_IN_CHAIN =
    |- !f. FINITE f /\
           ~(f = {}) /\
           (!s t. s IN f /\ t IN f ==> s SUBSET t \/ t SUBSET s)
           ==> UNIONS f IN f

Sat  4th Jun 2016       Examples/division_algebras.ml [new file]

Added a new example with two nonexistence proofs for division algebras in
higher dimensions; these are fairly straightforward corollaries of some
Multivariate results like the global inverse function theorem.

Sat  4th Jun 2016       sets.ml

Added an equivalential form of an existing theorem:

 INFINITE_ENUMERATE_EQ =
  |- !s. INFINITE s <=>
         (?r. (!m n. m < n ==> r m < r n) /\ IMAGE r (:num) = s)

Wed 25th May 2016       sets.ml

Added the simple fact that the "proper subset" relation on a finite
set is wellfounded:

  WF_PSUBSET = |- !s. FINITE s ==> WF (\t1 t2. t1 PSUBSET t2 /\ t2 SUBSET s)

Sat  7th May 2016       Library/floor.ml

Added RATIONAL_BETWEEN_EQ =
          |- !a b. (?q. rational q /\ a < q /\ q < b) <=> a < b

Fri 29th Apr 2016       Library/card.ml

Added two theorems asserting that a countable chain has an "equivalent"
omega-indexed chain:

 COUNTABLE_ASCENDING_CHAIN =
   |- !f:(A->bool)->bool.
        COUNTABLE f /\ ~(f = {}) /\
        (!s t. s IN f /\ t IN f ==> s SUBSET t \/ t SUBSET s)
        ==> ?u. (!n. u(n) IN f) /\ (!n. u(n) SUBSET u(SUC n)) /\
                UNIONS {u n | n IN (:num)} = UNIONS f

 COUNTABLE_DESCENDING_CHAIN =
   |- !f:(A->bool)->bool.
        COUNTABLE f /\ ~(f = {}) /\
        (!s t. s IN f /\ t IN f ==> s SUBSET t \/ t SUBSET s)
        ==> ?u. (!n. u(n) IN f) /\ (!n. u(SUC n) SUBSET u(n)) /\
                INTERS {u n | n IN (:num)} = INTERS f

Sat 23rd Apr 2016       Library/products.ml

Added two obvious theorems about the sizes of cartesian products:

  HAS_SIZE_CART =
    |- !P m.
           (!i. 1 <= i /\ i <= dimindex(:N) ==> {x | P i x} HAS_SIZE m i)
           ==> {v | !i. 1 <= i /\ i <= dimindex(:N) ==> P i (v$i)} HAS_SIZE
               nproduct (1..dimindex(:N)) m

  CARD_CART =
    |- !P. (!i. 1 <= i /\ i <= dimindex(:N) ==> FINITE {x | P i x})
           ==> CARD {v | !i. 1 <= i /\ i <= dimindex(:N) ==> P i (v$i)} =
               nproduct (1..dimindex(:N)) (\i. CARD {x | P i x})

Wed 13th Apr 2016       Library/wo.ml, Library/card.ml

Added a few basic theorems including the fact that a toset contains a
cofinal woset.


   COUNTABLE_FL =
        |- !l. COUNTABLE(fl l) <=> COUNTABLE l

   FINITE_FL =
        |- !l. FINITE(fl l) <=> FINITE l

   FL =
        |- !l. fl l = {x | ?y. l(x,y) \/ l(y,x)}

   FL_SUBSET =
        |- !l r. l SUBSET r ==> fl l SUBSET fl r

   TOSET_COFINAL_WOSET =
    |- !l. toset l
           ==> ?w. w SUBSET l /\
                   woset w /\
                   !x. x IN fl l ==> ?y. y IN fl w /\ l(x,y)

Wed 13th Apr 2016       sets.ml

Added one more trivial set theorem:

        INTERS_EQ_UNIV = |- !f. INTERS f = (:A) <=> !s. s IN f ==> s = (:A)

Fri  8th Apr 2016       iterate.ml, Library/products.ml

Added some theorems about "reflecting" (= reindexing in reverse order)
various iterated constructs:

  ITERATE_REFLECT =
    |- !op:A->A->A.
          monoidal op
          ==> !x m n. iterate op (m..n) x =
                      if n < m then neutral op
                      else iterate op (0..n-m) (\i. x(n - i))

  NSUM_REFLECT =
    |- !x m n. nsum(m..n) x = if n < m then 0 else nsum(0..n-m) (\i. x(n - i))

  SUM_REFLECT =
    |- !x m n. sum(m..n) x = if n < m then &0 else sum(0..n-m) (\i. x(n - i))

  NPRODUCT_REFLECT =
    |- !x m n. nproduct(m..n) x =
               if n < m then 1 else nproduct(0..n-m) (\i. x(n - i))

  PRODUCT_REFLECT =
    |- !x m n. product(m..n) x =
               if n < m then &1 else product(0..n-m) (\i. x(n - i))

Sun 20th Mar 2016       class.ml, sets.ml, Library/card.ml

Added a few handy trivialities:

  COND_SWAP = |- !p x y. (if ~p then x else y) = (if p then y else x)

  num_INFINITE_EQ = |- !s:num->bool. INFINITE s <=> !N. ?n. N <= n /\ n IN s

  CARD_POWERSET_CONG =
    |- !s t. s =_c t ==> {u | u SUBSET s} =_c {v | v SUBSET t}

Fri 26th Feb 2016       real.ml, int.ml

Added another simple lemma about the sign function for reals and integers:

  REAL_SGN_ABS_ALT = |- !x. real_sgn x * x = abs x

  INT_SGN_ABS_ALT = |- !x. int_sgn x * x = abs x

Wed 17th Feb 2016       metis.ml

Hid or removed some local theorems inside the Metis module so that they don't
show up in "search" results:

        Metis_reconstruct.EXCLUDED_MIDDLE
        Metis_reconstruct.IMPL_NOT_L
        Metis_reconstruct.IMPL_NOT_R
        Metis_reconstruct.RESOLVE_1
        Metis_reconstruct.RESOLVE_2L
        Metis_reconstruct.RESOLVE_2R
        Metis_reconstruct.RESOLVE_3

Wed 17th Feb 2016       Permutation/morelist.ml, Permutation/permutation.ml

Added a few more lemmas based on the concepts in the Permutation library:

  LIST_UNIQ_EQ_PAIRWISE_DISTINCT =
   |- LIST_UNIQ = PAIRWISE (\x y. ~(x = y))

  ORDERED_PAIRWISE =
   |- ORDERED = PAIRWISE

  PERMUTED_APPEND_CONG =
    |- !l1 l1' l2 l2'.
           l1 PERMUTED l1' /\ l2 PERMUTED l2'
           ==> APPEND l1 l2 PERMUTED APPEND l1' l2'

  PERMUTED_APPEND_LCANCEL =
    |- !l1 l2 l3. APPEND l1 l2 PERMUTED APPEND l1 l3 <=> l2 PERMUTED l3

  PERMUTED_APPEND_RCANCEL =
    |- !l1 l2 l3. APPEND l1 l3 PERMUTED APPEND l2 l3 <=> l1 PERMUTED l2

  PERMUTED_LENGTH_MEM =
    |- !l l'.
           LIST_UNIQ l /\ LENGTH l = LENGTH l' /\ (!x. MEM x l <=> MEM x l')
           ==> l PERMUTED l'

Wed 17th Feb 2016       lists.ml, sets.ml

Added a few elementary list theorems and moved the definition of (list)
PAIRWISE from sets.ml to lists.ml, which seems a more thematic home. New
theorems:

  LENGTH_ZIP =
    |- !l1 l2. LENGTH l1 = LENGTH l2 ==> LENGTH (ZIP l1 l2) = LENGTH l2

  PAIRWISE_APPEND =
    |- !R l m.
           PAIRWISE R (APPEND l m) <=>
           PAIRWISE R l /\ PAIRWISE R m /\ (!x y. MEM x l /\ MEM y m ==> R x y)

  PAIRWISE_IMPLIES =
    |- !R R' l.
           PAIRWISE R l /\ (!x y. MEM x l /\ MEM y l /\ R x y ==> R' x y)
           ==> PAIRWISE R' l

  PAIRWISE_MAP =
    |- !R f l. PAIRWISE R (MAP f l) <=> PAIRWISE (\x y. R (f x) (f y)) l

  PAIRWISE_TRANSITIVE =
    |- !R x y l.
           (!x y z. R x y /\ R y z ==> R x z)
           ==> (PAIRWISE R (CONS x (CONS y l)) <=>
                R x y /\ PAIRWISE R (CONS y l))

Fri 12th Feb 2016       Minisat/README, Minisat/zc2mso/zc2mso.C, Formal_ineqs/examples_flyspeck.hl, Formal_ineqs/docs/FormalVerifier.tex

Fixed a few broken URLs (including changing Flyspeck from Google Code to the
new Github repo: https://github.com/flyspeck/flyspeck), and added a line to
Minisat/zc2mso/zc2mso.C to make it compile out of the box with a recent g++.

Thu 11th Feb 2016       fusion.ml, nums.ml, calc_num.ml

Slightly tweaked "MK_COMB" to compare the types of the right-hand sides of the
equations rather than the left (on the expectation that in typical uses the
RHS will be simpler and therefore quicker to type).

Also made a couple of tiny efficiency tweaks to ensure the :num and :num->num
types in "NUMERAL", "BIT0" and "BIT1" are actually pointer ==.

Tue  9th Feb 2016       metis.ml [new file], meson.ml, passim

Installed Michael Färber and Cezary Kaliszyk's OCaml and HOL Light version
of Joe Leslie-Hurd's Metis prover. This provides alternatives to the various
MESON functions with the same naming convention: ASM_METIS_TAC, METIS_TAC and
METIS. Slightly reorganized meson.ml as part of this installation into a module
so that some of the "hidden" functions can be re-used, and changed a few MESON
calls to METIS where it is obviously faster (no doubt there are many more, and
many opportunities to prove things automatically that are currently manual).

Fri 29th Jan 2016       cart.ml

Added a "subtraction" on type indices, with a type constructor "finite_diff"
analogous to "finite_sum", with the following type definition theorem and other
lemmas:

 finite_diff_tybij =
  |- (!a. mk_finite_diff (dest_finite_diff a) = a) /\
     (!r. r IN
          1..
          (if dimindex(:B) < dimindex(:A)
           then dimindex(:A) - dimindex(:B)
           else 1) <=>
          dest_finite_diff (mk_finite_diff r) = r)

 FINITE_DIFF_IMAGE =
  |- (:(A,B)finite_diff) =
     IMAGE mk_finite_diff
     (1..
      (if dimindex(:B) < dimindex(:A)
       then dimindex(:A) - dimindex(:B)
       else 1))

 DIMINDEX_HAS_SIZE_FINITE_DIFF =
  |- (:(M,N)finite_diff) HAS_SIZE
     (if dimindex(:N) < dimindex(:M)
      then dimindex(:M) - dimindex(:N)
      else 1)

 DIMINDEX_FINITE_DIFF =
  |- dimindex(:(M,N)finite_diff) =
     (if dimindex(:N) < dimindex(:M)
      then dimindex(:M) - dimindex(:N)
      else 1)

 FINITE_DIFF_IMAGE =
  |- (:(A,B)finite_diff) =
     IMAGE mk_finite_diff
     (1..
      (if dimindex(:B) < dimindex(:A)
       then dimindex(:A) - dimindex(:B)
       else 1))

 DIMINDEX_HAS_SIZE_FINITE_DIFF =
  |- (:(M,N)finite_diff) HAS_SIZE
     (if dimindex(:N) < dimindex(:M)
      then dimindex(:M) - dimindex(:N)
      else 1)

This can occasionally be useful to make "size-lowering" arguments.

Fri 29th Jan 2016       sets.ml

Incompatibly improved (by making the hypotheses sharper) the following
two theorems (formerly, the antecendent did not have the set membership
assertions in their own antecedent):

 IMAGE_DIFF_INJ =
  |- !f s t.
         (!x y. x IN s /\ y IN t /\ f x = f y ==> x = y)
         ==> IMAGE f (s DIFF t) = IMAGE f s DIFF IMAGE f t

 IMAGE_DELETE_INJ =
  |- !f s a.
         (!x. x IN s /\ f x = f a ==> x = a)
         ==> IMAGE f (s DELETE a) = IMAGE f s DELETE f a

Also added the following two variants:

 IMAGE_DIFF_INJ_ALT =
  |- !f s t.
         (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\ t SUBSET s
         ==> IMAGE f (s DIFF t) = IMAGE f s DIFF IMAGE f t

 IMAGE_DELETE_INJ_ALT =
  |- !f s a.
         (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\ a IN s
         ==> IMAGE f (s DELETE a) = IMAGE f s DELETE f a

Thu 28th Jan 2016       Makefile

Updated the Makefile with yet more cases, to work with OCaml 4.02 and with
camlp5 6.15. HOL Light has been tested with OCaml 4.02.3 and camlp5 6.15 (under
Cygwin64), so the combination of the two seems to work.

Thu 17th Dec 2015       Help/*.doc

Fixed several documentation errors pointed out by Marco Maggesi.

Thu 17th Dec 2015       Library/card.ml

Added a few more fairly basic cardinality lemmas:

  COUNTABLE_CARD_ADD =
    |- !s t. COUNTABLE s /\ COUNTABLE t ==> COUNTABLE (s +_c t)

  COUNTABLE_CARD_ADD_EQ =
    |- !s t. COUNTABLE (s +_c t) <=> COUNTABLE s /\ COUNTABLE t

  CARD_LE_EXISTS = |-  !s t. s <=_c t <=> (?u. t =_c s +_c u)

  CARD_LT_IMP_SUC_LE = |- !s t a. s <_c t ==> s +_c {a} <=_c t

Thu 17th Dec 2015       real.ml, int.ml

Added two theorems characterizing sign equality as an inequality for R and Z:

  REAL_SGN_EQ_INEQ =
    |- !x y. real_sgn x = real_sgn y <=>
             x = y \/ abs(x - y) < max (abs x) (abs y)


  INT_SGN_EQ_INEQ =
    |- !x y. int_sgn x = int_sgn y <=>
             x = y \/ abs(x - y) < max (abs x) (abs y)

Thu 17th Dec 2015       sets.ml

Added a new and stronger form of INTERS_SUBSET

 INTERS_SUBSET_STRONG =
   |- !u s. (?t. t IN u /\ t SUBSET s) ==> INTERS u SUBSET s

and fixed a quantifier fumble in IMAGE_INTERS_SUBSET (now quantifies over all
the free variables and not the spurious "s"). Both these improvements were
pointed out by Joe Hurd.

Thu  3rd Dec 2015       Multivariate/cvectors.ml [new file], holtest, holtest.mk

Added a new contribution from Sanaz Khan Afshar and Vincent Aravantinos (with
contributions also from Harsh Singhal), a full theory of *complex* vectors
analogous to the real theory already in that directory.

Fri 20th Nov 2015       Library/products.ml

Added POLYNOMIAL_FUNCTION_PRODUCT =
  |- !s p.
         FINITE s /\ (!i. i IN s ==> polynomial_function (\x. p x i))
         ==> polynomial_function (\x. product s (p x))

Fri 20th Nov 2015       Library/floor.ml

Added the following natural analog of INTEGER_SUM:

  RATIONAL_SUM = |- !s x. (!i. i IN s ==> rational(x i)) ==> rational(sum s x)

Fri 20th Nov 2015       sets.ml

Added a few miscellaneous set theorems, especially about images of
saturated intersections.

  IMAGE_INTERS_SATURATED =
    |- !f g s.
           ~(g = {}) /\
           (!t. t IN g DELETE s ==> {x | f x IN IMAGE f t} SUBSET t)
           ==> IMAGE f (INTERS g) = INTERS (IMAGE (IMAGE f) g)

  IMAGE_INTERS_SATURATED_GEN =
    |- !f g s u.
           ~(g = {}) /\
           (!t. t IN g ==> t SUBSET u) /\
           (!t. t IN g DELETE s ==> {x | x IN u /\ f x IN IMAGE f t} SUBSET t)
           ==> IMAGE f (INTERS g) = INTERS (IMAGE (IMAGE f) g)

  IMAGE_INTERS_SUBSET =
    |- !f s. IMAGE f (INTERS g) SUBSET INTERS (IMAGE (IMAGE f) g)

  IMAGE_INTER_SATURATED =
    |- !f s t.
           {x | f x IN IMAGE f s} SUBSET s \/ {x | f x IN IMAGE f t} SUBSET t
           ==> IMAGE f (s INTER t) = IMAGE f s INTER IMAGE f t

  IMAGE_INTER_SATURATED_GEN =
    |- !f s t u.
           {x | x IN u /\ f x IN IMAGE f s} SUBSET s /\ t SUBSET u \/
           {x | x IN u /\ f x IN IMAGE f t} SUBSET t /\ s SUBSET u
           ==> IMAGE f (s INTER t) = IMAGE f s INTER IMAGE f t

  IMAGE_INTER_SUBSET =
    |- !f s t. IMAGE f (s INTER t) SUBSET IMAGE f s INTER IMAGE f t

  PSUBSET_UNIONS_PAIRWISE_DISJOINT =
    |- !u v.
           pairwise DISJOINT v /\ u PSUBSET v DELETE {}
           ==> UNIONS u PSUBSET UNIONS v

  UNIONS_DELETE_EMPTY =
    |- !s. UNIONS (s DELETE {}) = UNIONS s

  UNIONS_INSERT_EMPTY =
    |- !s. UNIONS ({} INSERT s) = UNIONS s

Sun 15th Nov 2015       Library/wo.ml, Library/card.ml

Added a few basic ordinal and cardinal lemmas, such as that every set is the
same size as an ordinal (on the same type) and that strict cardinal
comparability is, on a given type, wellfounded.

  CARD_EQ_ORDINAL_EXISTS = |- !s. ?l. ordinal l /\ fl l =_c s

  INSEG_FL_SUBSET = |- !l m. l inseg m ==> fl l SUBSET fl m

  ORDINAL_FL_SUBSET_EQ =
    |- !l m. ordinal l /\ ordinal m ==> (fl l SUBSET fl m <=> l inseg m)

  ORDINAL_IMP_WOSET = |- !l. ordinal l ==> woset l

  SUBWOSET_ISO_INSEG =
    |- !l s.
           woset l /\ fl l = (:A)
           ==> ?f. (!x y. x IN s /\ y IN s ==> (l (f x,f y) <=> l (x,y))) /\
                   (!x y. y IN IMAGE f s /\ l (x,y) ==> x IN IMAGE f s)

  WF_CARD_LT =  |- WF (<_c)

Fri  6th Nov 2015       Makefile, pa_j_3.1x_6.11.ml, README

Made two changes suggested by Randy Pollack so that HOL Light makes use
of the non-mutable strings in OCaml 4.02 in the build process for the
camlp5 syntax extension. First, modified the Makefile to explicitly build
with the "-safe-string" option for OCaml >= 4.02, and recoded the
"implode" function in pa_j_3.1x_6.11.ml to avoid the use of imperative
features. Also added a recommendation to the README file to use the
"-safe-string" option in the main HOL Light session itself.

Wed 22nd Jul 2015       Library/wo.ml

Added the basic fact that a finite toset is a woset:

 WOSET_FINITE_TOSET = |- !l. toset l /\ FINITE(fl l) ==> woset l

Mon 20th Jul 2015       sets.ml

Added a series of theorems about injectivity and surjectivity of the "preimage"
construct. These are a natural dual to existing "IMAGE" versions, and
essentially show that the preimage map is injective/surjective when the
function itself is surjective/injective.

  INJECTIVE_ON_PREIMAGE =
    |- !f:A->B s u.
          (!t t'. t SUBSET u /\ t' SUBSET u /\
                  {x | x IN s /\ f x IN t} = {x | x IN s /\ f x IN t'}
                  ==> t = t') <=>
          u SUBSET IMAGE f s

  SURJECTIVE_ON_PREIMAGE =
    |- !f s u.
        (!k. k SUBSET s ==> ?t. t SUBSET u /\ {x | x IN s /\ f x IN t} = k) <=>
        IMAGE f s SUBSET u /\ (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)

  INJECTIVE_PREIMAGE =
    |- !f. (!t t'. {x | f x IN t} = {x | f x IN t'} ==> t = t') <=>
           IMAGE f UNIV = UNIV

  SURJECTIVE_PREIMAGE =
    |- !f. (!k. ?t. {x | f x IN t} = k) <=> (!x y. f x = f y ==> x = y)

Sun 19th Jul 2015       Library/card.ml

Renamed CARD_ADD_ABSORB to CARD_ADD_ABSORB_LEFT and added a few more basic
theorems:

  CARD_ADD_ABSORB_RIGHT  = |- !s t. INFINITE s /\ t <=_c s ==> s +_c t =_c s

  CARD_DIFF_ABSORB = |- !s t. INFINITE s /\ t <_c s ==> s DIFF t =_c s

  CARD_UNION_ABSORB_LEFT = |- !s t. INFINITE t /\ s <=_c t ==> s UNION t =_c t

  CARD_UNION_ABSORB_RIGHT = |- !s t. INFINITE s /\ t <=_c s ==> s UNION t =_c s

Fri 17th Jul 2015       Library/floor.ml

Added one more theorem about the rationals:

  INFINITE_RATIONAL_IN_RANGE =
    |- !a b. a < b ==> INFINITE {q | rational q /\ a < q /\ q < b}

Mon 13th Jul 2015       Library/prime.ml

Added one more natural theorem about primality on N, as well as slightly
reorganizing a couple of existing proofs:

 PRIME_IRREDUCIBLE =
  |- !p. prime p <=>
         p > 1 /\ (!a b. p divides a * b ==> p divides a \/ p divides b)

Fri 10th Jul 2015       Library/floor.ml

Added a couple more rational approximation theorems:

  RATIONAL_APPROXIMATION_ABOVE =
    |- !x e. &0 < e ==> (?q. rational q /\ x < q /\ q < x + e)

  RATIONAL_APPROXIMATION_BELOW =
    |- !x e. &0 < e ==> (?q. rational q /\ x - e < q /\ q < x)

Fri 10th Jul 2015       Library/wo.ml, Library/card.ml

Added a few new theorems about ordered sets, ordinals and cardinals, including
slightly reshuffling things between these two files. Tukey's lemma is the only
real "named" theorem. Several of these slightly fill out the rather sparse
theory of ordinals (for example showing they are themselves wellordered by
"initial segment of"), which however remains pretty sparse.

  INSEG_ANTISYM = |- !l m. l inseg m /\ m inseg l ==> l = m

  INSEG_ORDINAL = |- !l m. m inseg l /\ ordinal l ==> ordinal m

  INSEG_REFL = |- !l. l inseg l

  INSEG_TRANS = |- !l m n. l inseg m /\ m inseg n ==> l inseg n

  LE_C_IMAGE_SUBSET = |- !s t. s <=_c t <=> (?f. s SUBSET IMAGE f t)

  ORDINAL_FL_SUBSET =
    |- !l m. ordinal l /\ ordinal m /\ fl l SUBSET fl m ==> l inseg m

  ORDINAL_FL_UNIQUE =
   |- !l m. ordinal l /\ ordinal m /\ fl l = fl m ==> l = m

  TUKEY =
    |- !s. ~(s = {}) /\
           (!t. (!c. FINITE c /\ c SUBSET t ==> c IN s) <=> t IN s)
           ==> (?u. u IN s /\ (!v. v IN s /\ u SUBSET v ==> u = v))

  WF_INSEG_WOSET =
    |- WF (\x y. woset x /\ woset y /\ x inseg y /\ ~(x = y))

  WOSET_INSEG_ORDINAL =
    |- woset (\(x,y). ordinal x /\ ordinal y /\ x inseg y)

  WOSET_WF =
    |- !l. woset l <=>
           WF (\x y. l(x,y) /\ ~(x = y)) /\
           (!x y. fl l x /\ fl l y ==> l(x,y) \/ l(y,x))

Fri 10th Jul 2015       wf.ml

Added the simple fact that a wellfounded relation is antisymmetric

 WF_ANTISYM = |- !(<<) x y. WF (<<) ==> ~(x << y /\ y << x)

Tue 30th Jun 2015       sets.ml

Added a variety of set theorems, mostly basic properties of CROSS that are
near-clones of existing theorems for PCROSS, many with the same proof.

  CROSS_DIFF =
    |- (!s t u. s CROSS (t DIFF u) = s CROSS t DIFF s CROSS u) /\
       (!s t u. (s DIFF t) CROSS u = s CROSS u DIFF t CROSS u)

  CROSS_EQ =
    |- !s s' t t'.
           s CROSS t = s' CROSS t' <=>
           (s = {} \/ t = {}) /\ (s' = {} \/ t' = {}) \/ s = s' /\ t = t'

  CROSS_INTER =
    |- (!s t u. s CROSS (t INTER u) = s CROSS t INTER s CROSS u) /\
       (!s t u. (s INTER t) CROSS u = s CROSS u INTER t CROSS u)

  CROSS_MONO =
    |- !s t s' t'. s SUBSET s' /\ t SUBSET t' ==> s CROSS t SUBSET s' CROSS t'

  CROSS_UNION =
    |- (!s t u. s CROSS (t UNION u) = s CROSS t UNION s CROSS u) /\
       (!s t u. (s UNION t) CROSS u = s CROSS u UNION t CROSS u)

  CROSS_UNIONS =
    |- (!s f. s CROSS UNIONS f = UNIONS {s CROSS t | t IN f}) /\
       (!f t. UNIONS f CROSS t = UNIONS {s CROSS t | s IN f})

  CROSS_UNIONS_UNIONS =
    |- !f g. UNIONS f CROSS UNIONS g = UNIONS {s CROSS t | s IN f /\ t IN g}

  EXISTS_IN_CROSS =
    |- !P s t.
         (?z. z IN s CROSS t /\ P z) <=> (?x y. x IN s /\ y IN t /\ P (x,y))

  FORALL_IN_CROSS =
    |- !P s t.
         (!z. z IN s CROSS t ==> P z) <=>
         (!x y. x IN s /\ y IN t ==> P (x,y))

  IMAGE_FST_CROSS =
    |- !s t. IMAGE FST (s CROSS t) = (if t = {} then {} else s)

  IMAGE_SND_CROSS =
    |- !s t. IMAGE SND (s CROSS t) = (if s = {} then {} else t)

  INTER_CROSS =
    |- !s s' t t'.
         s CROSS t INTER s' CROSS t' = (s INTER s') CROSS (t INTER t')

  SUBSET_CROSS =
    |- !s t s' t'.
         s CROSS t SUBSET s' CROSS t' <=>
         s = {} \/ t = {} \/ s SUBSET s' /\ t SUBSET t'

  UNIONS_UNIV =
    |- UNIONS (:A->bool) = (:A)

Fri 12th Jun 2015       sets.ml

Added two useful rewrites for sup and inf on finite sets from Marco
Maggesi. Note that they don't a priori require the set to be finite,
so they are easy to apply.

  INF_INSERT_INSERT =
    |- !a b s. inf (b INSERT a INSERT s) = inf (min a b INSERT s)

  SUP_INSERT_INSERT =
    |- !a b s. sup (b INSERT a INSERT s) = sup (max a b INSERT s)

Fri 29th May 2015       Library/card.ml

Added two more theorems about representing countable sets as images:

  COUNTABLE_AS_IMAGE_NUM_SUBSET =
    |- !s. COUNTABLE s <=> (?f k. s = IMAGE f k)

  COUNTABLE_AS_INJECTIVE_IMAGE_SUBSET =
    |- !s. COUNTABLE s <=>
           (?f k.
                s = IMAGE f k /\
                (!m n. m IN k /\ n IN k /\ f m = f n ==> m = n))

Fri 15th May 2015       pair.ml, arith.ml, sets.ml

Added a few useful theorems from Marco Maggesi:

  CHOICE_PAIRED_THM =
    |- !P Q. (?x y. P x y) /\ (!x y. P x y ==> Q (x,y)) ==> Q (@(x,y). P x y)

  CHOICE_UNPAIR_THM =
    |- !P. (@(x,y). P x y) = (@p. P (FST p) (SND p))

  INTERS_SUBSET =
    |- !u s. ~(u = {}) /\ (!t. t IN u ==> t SUBSET s) ==> INTERS u SUBSET s

  LAMBDA_UNPAIR_THM =
    |- !f. (\(x,y). f x y) = (\p. f (FST p) (SND p))

  LE_INDUCT =
    |- !P. (!m. P m m) /\ (!m n. m <= n /\ P m n ==> P m (SUC n))
           ==> (!m n. m <= n ==> P m n)

Fri 24th Apr 2015       sets.ml

Slightly sharpened PAIRWISE_IMP to

  |- !P Q s.
         pairwise P s /\
         (!x y. x IN s /\ y IN s /\ P x y /\ ~(x = y) ==> Q x y)
         ==> pairwise Q s

and added one more trivial but useful theorem about "pairwise":

  PAIRWISE_CHAIN_UNIONS =
    |- !R c.
         (!s. s IN c ==> pairwise R s) /\
         (!s t. s IN c /\ t IN c ==> s SUBSET t \/ t SUBSET s)
         ==> pairwise R (UNIONS c)

Fri 17th Apr 2015       calc_rat.ml, int.ml

Added a few equivalential forms of transitivity; the first few in
particular can be useful for epsilon-delta arguments in analysis.

  REAL_LE_TRANS_LE = |- !x y:real. x <= y <=> (!z. y <= z ==> x <= z)
  REAL_LE_TRANS_LTE = |- !x y:real. x <= y <=> (!z. y < z ==> x <= z)
  REAL_LE_TRANS_LT = |- !x y:real. x <= y <=> (!z. y < z ==> x < z)
  INT_LE_TRANS_LE = |- !x y:int x <= y <=> (!z. y <= z ==> x <= z)
  INT_LE_TRANS_LT = |- !x y:int. x <= y <=> (!z. y < z ==> x < z)

Mon 30th Mar 2015       sets.ml

Added a simple lemma about "pairwise":

  PAIRWISE_UNION =
   |- !R s t. pairwise R (s UNION t) <=>
              pairwise R s /\ pairwise R t /\
              (!x y. x IN s DIFF t /\ y IN t DIFF s ==> R x y /\ R y x)

Fri 20th Mar 2015       sets.ml, Library/card.ml

Added a few convenient rewrites extending existing ones with an injectivity
assumption:

  EXISTS_COUNTABLE_SUBSET_IMAGE_INJ =
    |- !P f s.
           (?t. COUNTABLE t /\ t SUBSET IMAGE f s /\ P t) <=>
           (?t. COUNTABLE t /\
                t SUBSET s /\
                (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y)) /\
                P (IMAGE f t))

  EXISTS_FINITE_SUBSET_IMAGE_INJ =
    |- !P f s.
           (?t. FINITE t /\ t SUBSET IMAGE f s /\ P t) <=>
           (?t. FINITE t /\
                t SUBSET s /\
                (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y)) /\
                P (IMAGE f t))

  EXISTS_SUBSET_IMAGE_INJ =
    |- !P f s.
           (?t. t SUBSET IMAGE f s /\ P t) <=>
           (?t. t SUBSET s /\
                (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y)) /\
                P (IMAGE f t))

  FORALL_COUNTABLE_SUBSET_IMAGE_INJ =
    |- !P f s.
           (!t. COUNTABLE t /\ t SUBSET IMAGE f s ==> P t) <=>
           (!t. COUNTABLE t /\
                t SUBSET s /\
                (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y))
                ==> P (IMAGE f t))

  FORALL_FINITE_SUBSET_IMAGE_INJ =
    |- !P f s.
           (!t. FINITE t /\ t SUBSET IMAGE f s ==> P t) <=>
           (!t. FINITE t /\
                t SUBSET s /\
                (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y))
                ==> P (IMAGE f t))

  FORALL_SUBSET_IMAGE_INJ =
    |- !P f s.
           (!t. t SUBSET IMAGE f s ==> P t) <=>
           (!t. t SUBSET s /\
                (!x y. x IN t /\ y IN t ==> (f x = f y <=> x = y))
                ==> P (IMAGE f t))

  SUBSET_IMAGE_INJ =
    |- !f s t.
           s SUBSET IMAGE f t <=>
           (?u. u SUBSET t /\
                (!x y. x IN u /\ y IN u ==> (f x = f y <=> x = y)) /\
                s = IMAGE f u)

Wed 11th Mar 2015       sets.ml

Added a couple of trivial but convenient sup/inf theorems:

  ELEMENT_LE_SUP =
    |- !s a. (?b. !x. x IN s ==> x <= b) /\ a IN s ==> a <= sup s

  INF_LE_ELEMENT =
    |- !s a. (?b. !x. x IN s ==> b <= x) /\ a IN s ==> inf s <= a

Fri  6th Mar 2015       sets.ml

Added PAIRWISE_AND =
    |- !R R' s.
           pairwise R s /\ pairwise R' s <=> pairwise (\x y. R x y /\ R' x y) s

Fri  6th Feb 2015       iterate.ml

Added two rather trivial but occasionally useful results:

  NSUM_MUL_BOUND =
    |- !a b s. FINITE s ==> nsum s (\i. a i * b i) <= nsum s a * nsum s b

  SUM_MUL_BOUND =
    |- !a b s.
        FINITE s /\ (!i. i IN s ==> &0 <= a i /\ &0 <= b i)
        ==> sum s (\i. a i * b i) <= sum s a * sum s b

Fri 30th Jan 2015       sets.ml

Added the following, which is convenient to avoid manual reshuffling
around FORALL_IN_IMAGE:

 FORALL_IN_IMAGE_2 =
  |- !f P s.
         (!x y. x IN IMAGE f s /\ y IN IMAGE f s ==> P x y) <=>
         (!x y. x IN s /\ y IN s ==> P (f x) (f y))

Fri 23rd Jan 2015       Library/card.ml

Added

   CARD_MUL_FINITE_EQ =
     |- !s t. FINITE(s *_c t) <=> s = {} \/ t = {} \/ FINITE s /\ FINITE t

Fri 23rd Jan 2015       sets.ml

Added three more simple theorems:

  CROSS_EMPTY = |- (!s. s CROSS {} = {}) /\ (!t. {} CROSS t = {})

  FINITE_CROSS_EQ =
    |- !s t. FINITE(s CROSS t) <=> s = {} \/ t = {} \/ FINITE s /\ FINITE t

  PAIRWISE_IMP =
   |- !P Q s.
        pairwise P s /\ (!x y. P x y /\ ~(x = y) ==> Q x y)
        ==> pairwise Q s

Mon 12th Jan 2015       sets.ml

Added another related theorem to the previous addition:

 INTER_UNIONS_PAIRWISE_DISJOINT =
  |- !s t.
         pairwise DISJOINT (s UNION t)
         ==> UNIONS s INTER UNIONS t = UNIONS (s INTER t)

Fri  9th Jan 2015       sets.ml

Added this fairly obvious theorem:

  DIFF_UNIONS_PAIRWISE_DISJOINT =
    |- !s t. pairwise DISJOINT s /\ t SUBSET s
             ==> UNIONS s DIFF UNIONS t = UNIONS(s DIFF t)

Sat 27th Dec 2014       Quaternions/*

Added a substantial new theory of quaternions from Marco Maggesi. This includes
basic operations, automatic normalization, quaternionic analysis and the
relation of quaternions to orthogonal transformations.

Sat 13th Dec 2014       theorems.ml

Added CLAIM_TAC from Marco Maggesi. This combines SUBGOAL_THEN and DESTRUCT_TAC
in a natural way so one can make a labelled claim with a subproof.

Sat  6th Dec 2014       IEEE/* [new directory]

Added an extensive formal theory of IEEE floating-point arithmetic, written by
Charlie Jacobsen. This includes theories of fixed-point numbers, generalized
floating-point numbers (with any even radix >= 2 and any precision >= 2) and
then the properties of the usual IEEE floating-point numbers.

Sun 30th Nov 2014       lists.ml, Help/dest_char.doc [new file], Help/mk_char.doc [new file], Help/dest_string.doc [new file], Help/mk_string.doc [new file], Help/CHAR_EQ_CONV.doc [new file], Help/STRING_EQ_CONV.doc [new file]

Added a systematic set of syntax constructors, destructors and comparison
conversions for characters and for strings (== char lists), written by Marco
Maggesi:

        dest_char
        mk_char
        dest_string
        mk_string
        CHAR_EQ_CONV
        STRING_EQ_CONV

Sun 30th Nov 2014       parser.ml

Fixed a bug in the parsing of HOL strings where the special handling of a
quotation with just a single identifier (designed to allow one to omit the
parantheses round infixes in this special case) was accidentally catching
strings as well.

Sun 23rd Nov 2014       sets.ml

Added this, a natural dual to the existing INTERS_OVER_UNIONS

UNIONS_OVER_INTERS =
  |- !f s. UNIONS {INTERS (f x) | x IN s} =
           INTERS {UNIONS {g x | x IN s} | g | !x. x IN s ==> g x IN f x}

Fri  7th Nov 2014       Examples/misiurewicz.ml [new file]

Added a new example, a formalization (suggested on the FOM list by Lasse
Rempe-Gillen) of Misiurewicz's original proof that the complex exponential map
is topologically transitive. See "On iterates of e^z", Ergodic Theory and
Dynamical Systems, vol 1, pp. 103-106, 1981.

Fri  7th Nov 2014       Library/iter.ml

Added ITER_ADD_POINTLESS = |- !m n. ITER (m + n) f = ITER m f o ITER n f

Fri  7th Nov 2014       sets.ml

Added FINITE_SUBSET_NUMSEG = |- !s. FINITE s <=> (?n. s SUBSET 0..n)

Fri 31st Oct 2014       sets.ml

Added the following, both stronger and more convenient than the existing
INFINITE_IMAGE_INJ (which is kept for compatibility):

  INFINITE_IMAGE
    |- !f s.
         INFINITE s /\ (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
         ==> INFINITE(IMAGE f s)

Fri 31st Oct 2014       theorems.ml, ind_defs.ml

Added a general form of "without loss of generality" lemmas like REAL_WLOG_LE,
as well as reshuffling other theorems from ind_defs.ml to theorems.ml.

  WLOG_RELATION =
    |- !R P.
         (!x y. P x y ==> P y x) /\
         (!x y. R x y \/ R y x) /\
         (!x y. R x y ==> P x y)
         ==> (!x y. P x y)

Sun 12th Oct 2014       theorems.ml, Help/DESTRUCT_TAC/doc, Help/FIX_TAX.doc, Help/HYP_TAC.doc [new file]

Added a new tactic HYP_TAC from Marco Maggesi. This fits into the existing
suite of tatics (FIX_TAC, DESTRUCT_TAC etc.) for manipulations via brief
strings, now applying to a named hypothesis. Also added a few improvements
to the existing suite and their documentation.

Sun 12th Oct 2014       Library/integer.ml

Removed the theorem INT_CONG_0, which as pointed out by Marco Maggesi is
the same as INT_CONG_0_DIVIDES except for the order of quantification.
The longer name was kept because it fits the natural number case which
is called CONG_DIVIDES_0, and it is actually used elsewhere.

Thu  9th Oct 2014       iterate.ml

Added variants of "grouping" theorems for sums, not requiring an explicit
function:

  NSUM_GROUP_RELATION =
    |- !R g s t.
           FINITE s /\ (!x. x IN s ==> (?!y. y IN t /\ R x y))
           ==> nsum t (\y. nsum {x | x IN s /\ R x y} g) = nsum s g

  SUM_GROUP_RELATION =
    |- !R g s t.
           FINITE s /\ (!x. x IN s ==> (?!y. y IN t /\ R x y))
           ==> sum t (\y. sum {x | x IN s /\ R x y} g) = sum s g

Sat  4th Oct 2014       Functionspaces/README, Functionspaces/make.ml, Functionspaces/utils.ml, Functionspaces/cfunspace.ml [new files], Jordan/float.ml

Added a new library by Mohamed Yousri Mahmoud and Vincent Aravantinos of vector
spaces of complex functions, building on top of the Multivariate theories.

Sat  4th Oct 2014       system.ml

Added another form to the quotation expander so that any quotation ending
in a colon, i.e. of the form `....:`, will just be parsed as an (escaped)
string. This is convenient for use with the new Library/q.ml file so that
potential issues with capturing backslashes in plain strings can be
avoided. It seems quite an intuitive syntax since one is then expecting
the system to infer the type from context.

Tweaked cases in Jordan/float.ml where there was already a colon at
the end of a quotation, just adding spaces around the body.

Fri 26th Sep 2014       sets.ml

Added the following, a natural complement to IMAGE_UNIONS and IMAGE_INTER:

  IMAGE_INTERS =
    |- !f s. ~(s = {}) /\
             (!x y. x IN UNIONS s /\ y IN UNIONS s /\ f x = f y ==> x = y)
             ==> IMAGE f (INTERS s) = INTERS(IMAGE (IMAGE f) s)

Fri 19th Sep 2014       Library/q.ml [new file]

Added a file from Vincent Aravantinos with Pa.xxx variants of many standard
HOL Light functions, taking strings instead of terms and inferring types
appropriately. This is similar to the Q module in HOL4.

Thu 18th Sep 2014       sets.ml

Added a couple more set theory rewrites:

        FORALL_SUBSET_INSERT =
         |- !a t. (!s. s SUBSET a INSERT t ==> P s) <=>
                  (!s. s SUBSET t ==> P s /\ P (a INSERT s))

        EXISTS_SUBSET_INSERT =
         |- !a t. (?s. s SUBSET a INSERT t /\ P s) <=>
                  (?s. s SUBSET t /\ (P s \/ P (a INSERT s)))

Tue 16th Sep 2014       Library/permutations.ml

Added a couple more theorems about permutations:

 PERMUTES_ID = |- !s. (\x. x) permutes s

 REAL_SGN_SIGN = |- !p. real_sgn (sign p) = sign p

Tue  9th Sep 2014       Library/card.ml

Added a few more general lemma about cardinal operations

        CARD_EMPTY_LE =
              |- !s. {} <=_c s

        CARD_EQ_REFL_IMP =
              |- !s t. s = t ==> s =_c t

        CARD_LE_FINITE_INFINITE =
              |- !s t. FINITE s /\ INFINITE t ==> s <=_c t

        CARD_MUL_C =
          |- !s t. FINITE s /\ FINITE t ==> CARD(s *_c t) = CARD s * CARD t

        CARD_SING_LE =
              |- !a s. {a} <=_c s <=> ~(s = {})

        LE_C_IMAGE =
              |- !s t. s <=_c t <=> s = {} \/ (?f. IMAGE f t = s)

together with a definition of cardinal exponentiation and its
basic properties:

        exp_c =
          |- !s t.
                 s ^_c t =
                 {f | (!x. x IN t ==> f x IN s) /\
                      (!x. ~(x IN t) ==> f x = (@y. F))}

       CARD_EQ_COUNTABLE_SUBSETS_SUBREAL =
         |- !s. INFINITE s /\ s <=_c (:real)
                ==> {t | t SUBSET s /\ COUNTABLE t} =_c (:real)

        CARD_EQ_FULLSIZE_POWERSET =
          |- !s. INFINITE s ==> {t | t SUBSET s /\ t =_c s} =_c {t | t SUBSET s}

        CARD_EQ_LIMITED_POWERSET =
          |- !s t.
                 INFINITE s
                 ==> (if t <=_c s
                      then {k | k SUBSET s /\ k <=_c t} =_c s ^_c t
                      else {k | k SUBSET s /\ k <=_c t} =_c (:bool) ^_c s)

        CARD_EQ_RESTRICTED_POWERSET =
          |- !s t.
                 INFINITE s
                 ==> {k | k SUBSET s /\ k =_c t} =_c
                     (if t <=_c s then s ^_c t else {})

        CARD_EXP_0 =
              |- !s c. s ^_c {} =_c {c};

        CARD_EXP_ABSORB =
              |- !s t.
                    INFINITE t /\ (:bool) <=_c s /\ s <=_c (:bool) ^_c t
                    ==> s ^_c t =_c (:bool) ^_c t

        CARD_EXP_ADD =
              |- !s t u. s ^_c (t +_c u) =_c s ^_c t *_c s ^_c u

        CARD_EXP_C =
          |- !s t. FINITE s /\ FINITE t ==> CARD(s ^_c t) = CARD s EXP CARD t

        CARD_EXP_CANTOR =
              |- !s. s <_c (:bool) ^_c s

        CARD_EXP_CONG =
              |- !s s' t t'. s =_c s' /\ t =_c t' ==> s ^_c t =_c s' ^_c t'

        CARD_EXP_FINITE =
              |- !s t. FINITE s /\ FINITE t ==> FINITE(s ^_c t)

        CARD_EXP_GRAPH =
          |- !s t.
                 s ^_c t =_c
                 {R | (!x y. R x y ==> x IN t /\ y IN s) /\
                      (!x. x IN t ==> (?!y. R x y))}

        CARD_EXP_GRAPH_PAIRED =
          |- !s t.
                 s ^_c t =_c
                 {R | (!x y. R (x,y) ==> x IN t /\ y IN s) /\
                      (!x. x IN t ==> (?!y. R (x,y)))}

        CARD_EXP_MUL =
              |- !s t u. s ^_c (t *_c u) =_c s ^_c t ^_c u

        CARD_EXP_POWERSET =
              |- !s. (:bool) ^_c s =_c {t | t SUBSET s}

        CARD_EXP_SING =
              |- !s b. s ^_c {b} =_c s

        CARD_EXP_UNIV =
              |- (:A) ^_c (:B) = (:B->A)

        CARD_EXP_ZERO =
              |- !s c. {} ^_c s =_c (if s = {} then {c} else {})

        CARD_LE_EXP =
              |- !s s' t t'.
                 ~(s = {}) /\ s <=_c s' /\ t <=_c t' ==> s ^_c t <=_c s' ^_c t'

        CARD_LE_EXP_LEFT =
              |- !s s' t. s <=_c s' ==> s ^_c t <=_c s' ^_c t

        CARD_LE_EXP_RIGHT =
              |- !s t t'. ~(s = {}) /\ t <=_c t' ==> s ^_c t <=_c s ^_c t'

        CARD_MUL_EXP =
              |- !s t u. (s *_c t) ^_c u =_c s ^_c u *_c t ^_c u

Tue  9th Sep 2014       Library/products.ml

Added two straightforward "finite support" generalizations of existing theorems
about products:

NPRODUCT_MUL_GEN =
 |- !f g s.
       FINITE {x | x IN s /\ ~(f x = 1)} /\ FINITE {x | x IN s /\ ~(g x = 1)}
       ==> nproduct s (\x. f x * g x) = nproduct s f * nproduct s g

PRODUCT_MUL_GEN =
 |- !f g s.
       FINITE {x | x IN s /\ ~(f x = &1)} /\ FINITE {x | x IN s /\ ~(g x = &1)}
       ==> product s (\x. f x * g x) = product s f * product s g

Tue 19th Aug 2014       Library/floor.ml

Added

        NONNEGATIVE_INTEGER =
         |- !x. integer x /\ &0 <= x <=> ?n. x = &n

        NONPOSITIVE_INTEGER =
         |- !x. integer x /\ x <= &0 <=> ?n. x = -- &n

        NONPOSITIVE_INTEGER_ALT =
         |- !x. integer x /\ x <= &0 <=> ?n. x + &n = &0

        REAL_FLOOR_NEG =
         |- !x. floor(--x) = if integer x then --x else --(floor x + &1)

        FRAC_NEG =
         |- !x. frac(--x) = if integer x then &0 else &1 - frac x

Tue 19th Aug 2014       iterate.ml

Added REAL_OF_NUM_SUM_GEN =
   |- !f s. FINITE {i | i IN s /\ ~(f i = 0)}
            ==> &(nsum s f) = sum s (\x. &(f x))`,

Tue 19th Aug 2014       real.ml

Added REAL_OF_NUM_SUB_CASES =
        |- `!m n. &m - &n = if n <= m then &(m - n) else -- &(n - m)

Sun 13th Jul 2014       Formal_ineqs/* [new files]

Added Alexey Solovyev's formal inequality prover (used extensively
in the Flyspeck project) to the HOL Light distribution.

Thu 10th Jul 2014       Library/products.ml

Added a couple more trivial theorems about products:

  NPRODUCT_DELTA =
    |- !s a.
         nproduct s (\x. if x = a then b else 1) = (if a IN s then b else 1)

  PRODUCT_DELTA =
    |- !s a.
         product s (\x. if x = a then b else &1) = (if a IN s then b else &1)

Tue  1st Jul 2014       Library/floor.ml

Added clauses for "max" and "min" to INTEGER_CLOSED, so it is now:

  INTEGER_CLOSED =
  |- (!n. integer (&n)) /\
     (!x y. integer x /\ integer y ==> integer (x + y)) /\
     (!x y. integer x /\ integer y ==> integer (x - y)) /\
     (!x y. integer x /\ integer y ==> integer (x * y)) /\
     (!x r. integer x ==> integer (x pow r)) /\
     (!x. integer x ==> integer (--x)) /\
     (!x. integer x ==> integer (abs x)) /\
     (!x y. integer x /\ integer y ==> integer (max x y)) /\
     (!x y. integer x /\ integer y ==> integer (min x y))

Tue  1st Jul 2014       sets.ml

Added CROSS_UNIV = |- (:A) CROSS (:B) = (:A#B)

Tue 27th May 2014       Library/permutations.ml

Added three more lemmas about permutations:

  CARD_EVEN_PERMUTATIONS =
    |- !s. FINITE s /\ 2 <= CARD s
           ==> 2 * CARD {p | p permutes s /\ evenperm p} = FACT (CARD s)

  PERMUTES_INVOLUTION =
    |- !p s. (!x. p (p x) = x) /\ (!x. ~(x IN s) ==> p x = x) ==> p permutes s

  SIGN_INVOLUTION =
    |- !p s.
         FINITE s /\ (!x. p (p x) = x) /\ (!x. ~(x IN s) ==> p x = x)
         ==> sign p = -- &1 pow (CARD {x | ~(p x = x)} DIV 2)

Tue 27th May 2014       Library/floor.ml

Added the following theorem, a natural counterpart for FLOOR_DIV_DIV

  FRAC_DIV_MOD =
   |- !m n. ~(n = 0) ==> frac(&m / &n) = &(m MOD n) / &n

Mon 12th May 2014       Examples/gcdrecurrence.ml [new file]

Added a new file with the cute result that the gcd operation "commutes" with
certain integer sequences, with applications to the Mersenne numbers, the
Fibonacci series, and solutions to the Pell equation.

Sat 10th May 2014       int.ml, real.ml, Library/prime.ml, Library/integer.ml

Added a few miscellaneous trivial theorems:

  DIVIDES_GCD_LEFT =
    |- !m n. m divides n <=> gcd(m,n) = m

  DIVIDES_GCD_RIGHT =
    |- !m n. n divides m <=> gcd(m,n) = n

  INT_DIVIDES_ANTISYM_DIVISORS =
    |- !a b. a divides b /\ b divides a <=> (!d. d divides a <=> d divides b)

  INT_DIVIDES_GCD_LEFT =
    |- !m n. m divides n <=> gcd(m,n) = abs m

  INT_DIVIDES_GCD_RIGHT =
    |- !m n. n divides m <=> gcd(m,n) = abs n

  INT_EQ_SGN_ABS =
    |- !x y. x = y <=> int_sgn x = int_sgn y /\ abs x = abs y

  REAL_EQ_SGN_ABS =
    |- !x y. x = y <=> real_sgn x = real_sgn y /\ abs x = abs y

Sat 10th May 2014       Examples/dickson.ml

Added a proof of Dickson's Lemma, plus the Nash-Williams minimal bad sequence
property in a bit more generality (for a "safety property" of sequences in the
Lamport/Alpern/Schneider sense).

Fri  9th May 2014       Library/card.ml

Added COUNTABLE_SUBSET_NUM = |- !s:num->bool. COUNTABLE s

Sun 27th Apr 2014       Library/permutations.ml

Added

  PERMUTES_BIJECTIONS =
   |- !p q. (!x. x IN s ==> p x IN s) /\ (!x. ~(x IN s) ==> p x = x) /\
            (!x. x IN s ==> q x IN s) /\ (!x. ~(x IN s) ==> q x = x) /\
            (!x. p(q x) = x) /\ (!x. q(p x) = x)
            ==> p permutes s

Sat 19th Apr 2014       sets.ml

Added another clause to FORALL_IN_GSPEC and EXISTS_IN_GSPEC for the case of 4
bound variables, so they have now become:

  FORALL_IN_GSPEC =
   |- (!P f. (!z. z IN {f x | P x} ==> Q z) <=> (!x. P x ==> Q(f x))) /\
      (!P f. (!z. z IN {f x y | P x y} ==> Q z) <=>
             (!x y. P x y ==> Q(f x y))) /\
      (!P f. (!z. z IN {f w x y | P w x y} ==> Q z) <=>
             (!w x y. P w x y ==> Q(f w x y))) /\
      (!P f. (!z. z IN {f v w x y | P v w x y} ==> Q z) <=>
             (!v w x y. P v w x y ==> Q(f v w x y)))

  EXISTS_IN_GSPEC =
   |- (!P f. (?z. z IN {f x | P x} /\ Q z) <=> (?x. P x /\ Q(f x))) /\
      (!P f. (?z. z IN {f x y | P x y} /\ Q z) <=>
             (?x y. P x y /\ Q(f x y))) /\
      (!P f. (?z. z IN {f w x y | P w x y} /\ Q z) <=>
             (?w x y. P w x y /\ Q(f w x y))) /\
      (!P f. (?z. z IN {f v w x y | P v w x y} /\ Q z) <=>
             (?v w x y. P v w x y /\ Q(f v w x y)))

Sat 19th Apr 2014       pair.ml

Added "unpair" theorems:

  FORALL_UNPAIR_THM =
    |- (!x y. P x y) <=> (!z. P (FST z) (SND z))

  EXISTS_UNPAIR_THM =
    |- (?x y. P x y) <=> (?z. P (FST z) (SND z))

Tue 15th Apr 2014       bool.ml

Did a little more rationalization of the Boolean rule, recoding MP so that it
produces precisely the union of the two assumption lists, as the documentation
claims.

Mon 14th Apr 2014       Examples/lucas_lehmer.ml, 100/sqrt.ml [new file]

Added a new file containing a formalization of the Lucas-Lehmer test for
primality of Mersenne numbers, and a derived rule for applying it in particular
cases. This is quite a bit faster than the usual PRIME_CONV (in this special
case 2^p-1), and also scales better because it doesn't rely on factorization at
all. This uses as a lemma the fact that sqrt(3) is not rational, so also added
a file with a trivial proof that sqrt(p) is irrational for prime p.

Mon 14th Apr 2014       int.ml, Library/prime.ml, Library/iter.ml, Library/pocklington.ml, Library/primitive.ml

Moved this very basic result out of the Library/prime.ml file into the main
core

  DIVIDES_LE = |- !m n. m divides n ==> m <= n \/ n = 0

Added some theorems to Library/iter.ml about the "order" or "characteristic" in
a general setting

  val ORDER_EXISTENCE_GEN =
    |- !P f.
           P (f 0) /\
           (!m n. P (f m) /\ ~(m = 0) ==> (P (f (m + n)) <=> P (f n)))
           ==> ?d. !n. P (f n) <=> d divides n

  val ORDER_EXISTENCE_ITER =
    |- !R f z.
           R z z /\
           (!x y. R x y ==> R y x) /\
           (!x y z. R x y /\ R y z ==> R x z) /\
           (!x y. R x y ==> R (f x) (f y))
           ==> ?d. !n. R (ITER n f z) z <=> d divides n

  val ORDER_EXISTENCE_CARD =
    |- !R f z k.
           FINITE {R (ITER n f z) | n IN (:num)} /\
           CARD {R (ITER n f z) | n IN (:num)} <= k /\
           R z z /\
           (!x y. R x y ==> R y x) /\
           (!x y z. R x y /\ R y z ==> R x z) /\
           (!x y. R (f x) (f y) <=> R x y)
           ==> ?d. 0 < d /\ d <= k /\ (!n. R (ITER n f z) z <=> d divides n)

  val ORDER_EXISTENCE_FINITE =
    |- !R f z.
           FINITE {R (ITER n f z) | n IN (:num)} /\
           R z z /\
           (!x y. R x y ==> R y x) /\
           (!x y z. R x y /\ R y z ==> R x z) /\
           (!x y. R (f x) (f y) <=> R x y)
           ==> ?d. 0 < d /\ (!n. R (ITER n f z) z <=> d divides n)

Changed the definition of "order" in Library/pocklington.ml to use that as the
basis, as well as adding three basic new theorems:

        EXP_ITER = |- !x n. x EXP n = ITER n (\y. x * y) 1

        PHI_EQ_0 = |- !n. phi n = 0 <=> n = 0

        ORDER_1 = |- !n. order n 1 = 1

Fri 11th Apr 2014       bool.ml

Bill Richter pointed out that IMP_ANTISYM_RULE could sometimes give fewer
assumptions than its documentation (with a simple union of the two lists)
suggested. Fixed this, as well as a similar problem with CONJ, and a few
related documentation issues also uncovered by Bill.

Wed  9th Apr 2014       equal.ml

Made a few minor optimizations to some functions here, using more
pattern-matching in place of destructors and adding partial evaluation to
AP_TERM.

Fri  4th Apr 2014       arith.ml

Added MOD_REFL = |- !n. ~(n = 0) ==> n MOD n = 0

Thu  3rd Apr 2014       nums.ml, calc_num.ml

Completely rewrote the conversions NUM_SUC_CONV, NUM_ADD_CONV and NUM_MULT_CONV
to improve efficiency, as well as the auxiliary syntax function mk_numeral. The
new versions do addition in larger blocks for a decent constant factor
improvement and the multiplication routine uses squaring as the core with quite
tight coding and the use of 2-part and 3-part interpolation. Also rewrote the
main relational conversions NUM_LT_CONV, NUM_LE_CONV and NUM_EQ_CONV to call
addition directly, which is (now) much more efficient than what was used
before, though it could still be optimized a bit more.

Tue  1st Apr 2014       fusion.ml

Made another rather minor optimization, this time making the check for
type compatibility in the "vsubst" outer wrapper marginally more efficient.

Thu 27th Mar 2014       fusion.ml

Made a small change to the "type_of" function to use an explicit match in the
Comb case instead of applying "hd" and "tl". Although perhaps marginally
uglier, it is somewhat more efficient and gets two more library functions (hd
and tl) out of the core.

Sun 23rd Mar 2014       Examples/harmonicsum.ml [new file]

Added a new file with a rather trivial but nice result that a non-trivial
contiguous segment of the harmonic series never sums to an integer.

Tue 18th Mar 2014       iterate.ml

Added a definition of a "polynomial function" (R->R) with various basic closure
properties. This is a sufficiently useful concept that it seems worth having in
the core, not just in the analytical theories.

 polynomial_function =
  |- !p. polynomial_function p <=>
         (?m c. !x. p x = sum (0..m) (\i. c i * x pow i))

 POLYNOMIAL_FUNCTION_ADD =
  |- !p q.
         polynomial_function p /\ polynomial_function q
         ==> polynomial_function (\x. p x + q x)

 POLYNOMIAL_FUNCTION_CONST =
  |- !c. polynomial_function (\x. c)

 POLYNOMIAL_FUNCTION_FINITE_ROOTS =
  |- !p a.
         polynomial_function p ==> (FINITE {x | p x = a} <=> ~(!x. p x = a))

 POLYNOMIAL_FUNCTION_I =
  |- polynomial_function I

  POLYNOMIAL_FUNCTION_ID =
   |- polynomial_function (\x. x)

  POLYNOMIAL_FUNCTION_INDUCT =
   |- !P. P (\x. x) /\
          (!c. P (\x. c)) /\
          (!p q. P p /\ P q ==> P (\x. p x + q x)) /\
          (!p q. P p /\ P q ==> P (\x. p x * q x))
          ==> (!p. polynomial_function p ==> P p)

  POLYNOMIAL_FUNCTION_LMUL =
   |- !p c. polynomial_function p ==> polynomial_function (\x. c * p x)

  POLYNOMIAL_FUNCTION_MUL =
   |- !p q.
         polynomial_function p /\ polynomial_function q
         ==> polynomial_function (\x. p x * q x)

  POLYNOMIAL_FUNCTION_NEG =
   |- !p. polynomial_function (\x. --p x) <=> polynomial_function p

  POLYNOMIAL_FUNCTION_POW =
    |- !p n. polynomial_function p ==> polynomial_function (\x. p x pow n)

  POLYNOMIAL_FUNCTION_RMUL =
    |- !p c. polynomial_function p ==> polynomial_function (\x. p x * c)

  POLYNOMIAL_FUNCTION_SUB =
    |- !p q.
         polynomial_function p /\ polynomial_function q
         ==> polynomial_function (\x. p x - q x)

  POLYNOMIAL_FUNCTION_SUM =
    |- !s p.
         FINITE s /\ (!i. i IN s ==> polynomial_function (\x. p x i))
         ==> polynomial_function (\x. sum s (p x))

  POLYNOMIAL_FUNCTION_o =
    |- !p q.
         polynomial_function p /\ polynomial_function q
         ==> polynomial_function (p o q)

Tue 18th Mar 2014       iterate.ml

Added a conversion EXPAND_SUM_CONV to expand "sum (m..n) f" where m and
n are particular numerals.

Tue 18th Mar 2014       Library/binomial.ml

Added one more lemma about binomial coefficients, a characteristic property of
Appell sequences:

 APPELL_SEQUENCE =
  |- !c n x y.
         sum (0..n)
         (\k. &(binom(n,k)) *
              sum (0..k) (\l. &(binom(k,l)) * c l * x pow (k - l)) *
              y pow (n - k)) =
         sum (0..n) (\k. &(binom(n,k)) * c k * (x + y) pow (n - k))

Sun 16th Mar 2014       Multivariate/gamma.ml [new file]

Added a new file giving a definition of the complex and real gamma functions
and proofs of some basic properties.

Mon 10th Mar 2014       Library/binomial.ml

Added a couple more lemmas:

 BINOM_SYM = |- !n k. binom(n,n - k) = (if k <= n then binom(n,k) else 1)

 BINOM_MUL_SHIFT =
  |- !m n k.
         k <= m
         ==> binom(n,m) * binom(m,k) = binom(n,k) * binom(n - k,m - k)

as well as putting a simple symmetry optimization into NUM_BINOM_CONV for
the case of NUM_BINOM_CONV `binom(n,k)` where k is small.

Sat  8th Mar 2014       printer.ml

Added two improvements from Joe Hurd to the treatment of printing.
First, user printers are generalized over the formatter so that they will
respect the overall output formatter settings. Moreover, the "print_to_string"
function now takes the margin into account.

Fri 28th Feb 2014       Library/prime.ml

Added a few more number-theory results, mainly concerning the "index":

  INDEX_REFL =
    |- !n. index n n = (if n <= 1 then 0 else 1)

  INDEX_EQ_0 =
    |- !p n. index p n = 0 <=> n = 0 \/ p = 1 \/ ~(p divides n)

  INDEX_TRIVIAL_BOUND =
    |- !n p. index p n <= n

  INDEX_DECOMPOSITION =
    |- !n p. ?m. p EXP index p n * m = n /\ (n = 0 \/ p = 1 \/ ~(p divides m))

  INDEX_DECOMPOSITION_PRIME =
    |- !n p.
         prime p
         ==> (?m. p EXP index p n * m = n /\ (n = 0 \/ coprime(p,m)))

  DIVIDES_NSUM =
    |- !n f s.
         FINITE s /\ (!i. i IN s ==> n divides f i) ==> n divides nsum s f

Fri 28th Feb 2014       real.ml

Added REAL_LT_POW_2 = |- |- !x. &0 < x pow 2 <=> ~(x = &0)

Fri 28th Feb 2014       Library/products.ml

Added a few more basic theorems about products:

  NPRODUCT_FACT = |- !n. nproduct (1..n) (\m. m) = FACT n

  NPRODUCT_PAIR =
    |- !f m n.
           nproduct (2 * m..2 * n + 1) f =
           nproduct (m..n) (\i. f (2 * i) * f (2 * i + 1))

  NPRODUCT_DELETE =
    |- !f s a.
         FINITE s /\ a IN s ==> f a * nproduct (s DELETE a) f = nproduct s f

  PRODUCT_PAIR =
    |- !f m n.
           product (2 * m..2 * n + 1) f =
           product (m..n) (\i. f (2 * i) * f (2 * i + 1))

  PRODUCT_DELETE =
    |- !f s a.
         FINITE s /\ a IN s ==> f a * product (s DELETE a) f = product s f

Sat 22nd Feb 2014       impconv.ml, Help/CASE_REWRITE_TAC.doc, Help/HINT_EXISTS_TAC.doc, Help/IMP_REWRITE_TAC.doc, Help/SEQ_IMP_REWRITE_TAC.doc, Help/TARGET_REWRITE_TAC.doc [new files], hol.ml

Added a new file from Vincent Aravantinos containing several powerful new
tactics: IMP_REWRITE_TAC, TARGET_REWRITE_TAC, CASE_REWRITE_TAC,
SEQ_IMP_REWRITE_TAC and HINT_EXISTS_TAC.

Sat 22nd Feb 2014       arith.ml, Library/binary.ml, Library/prime.ml

Added the rather trivial "finite Cantor's theorem", which is otherwise
defined in several different places and is useful enough:

  LT_POW2_REFL = |- !n. n < 2 EXP n

Deleted it from other places now that it's in the core.

Sun 16th Feb 2014       real.ml

Added the following additional properties of the signum function:

  INT_SGN_POW =
   |- !x n. int_sgn(x pow n) = int_sgn(x) pow n

  INT_SGN_POW_2 =
   |- !x. int_sgn(x pow 2) = int_sgn(abs x)

  INT_SGN_REAL_SGN =
   |- int_sgn(int_sgn x) = int_sgn x

  REAL_INV_SGN =
   |- !x. inv (real_sgn x) = real_sgn x

  REAL_SGN_POW =
   |- !x n. real_sgn(x pow n) = real_sgn(x) pow n

  REAL_SGN_POW_2 =
   |- !x. real_sgn(x pow 2) = real_sgn(abs x)

  REAL_SGN_REAL_SGN =
   |- real_sgn(real_sgn x) = real_sgn x

Sun 16th Feb 2014       Library/prime.ml

Added a conversion LCM_CONV to compute LCMs of particular numerals, plus a few
more theorems including a definition of "index":

  PRIMEPOW_DIVIDES_PROD =
   |- !p k m n.
        prime p /\ (p EXP k) divides (m * n)
        ==> ?i j. (p EXP i) divides m /\ (p EXP j) divides n /\ k = i + j

  FINITE_EXP_LE =
   |- !P p n. 2 <= p ==> FINITE {j | P j /\ p EXP j <= n}

  FINITE_INDICES =
   |- !P p n. 2 <= p /\ ~(n = 0) ==> FINITE {j | P j /\ p EXP j divides n}

  index_def =
   |- index p n = if p <= 1 \/ n = 0 then 0
                  else CARD {j | 1 <= j /\ p EXP j divides n}

  INDEX_0 =
   |- !p. index p 0 = 0

  PRIMEPOW_DIVIDES_INDEX =
   |- !n p k. p EXP k divides n <=> n = 0 \/ p = 1 \/ k <= index p n

  LE_INDEX =
   |- !n p k. k <= index p n <=>
              (n = 0 \/ p = 1 ==> k = 0) /\ p EXP k divides n

  INDEX_1 = |- !p. index p 1 = 0

  INDEX_MUL =
   |- !m n. prime p /\ ~(m = 0) /\ ~(n = 0)
            ==> index p (m * n) = index p m + index p n

  INDEX_EXP =
   |- !p n k. prime p ==> index p (n EXP k) = k * index p n

  INDEX_FACT =
   |- !p n. prime p ==> index p (FACT n) = nsum(1..n) (\m. index p m)

  INDEX_FACT_ALT =
   |- !p n. prime p
            ==> index p (FACT n) =
                nsum {j | 1 <= j /\ p EXP j <= n} (\j. n DIV (p EXP j))

  INDEX_FACT_UNBOUNDED =
   |- !p n. prime p
            ==> index p (FACT n) = nsum {j | 1 <= j} (\j. n DIV (p EXP j))

  PRIMEPOW_DIVIDES_FACT =
   |- !p n k. prime p
              ==> (p EXP k divides FACT n <=>
                  k <= nsum {j | 1 <= j /\ p EXP j <= n} (\j. n DIV (p EXP j)))

Sun 16th Feb 2014       iterate.ml

Added a slightly more delicate "finite support" vesion of sum comparison:

 NSUM_LE_GEN =
  |- !f g s. (!x. x IN s ==> f x <= g x) /\ FINITE {x | x IN s /\ ~(g x = 0)}
             ==> nsum s f <= nsum s g

Wed 12th Feb 2014       Library/floor.ml

Added INTEGER_DIV = |- !m n. integer(&m / &n) <=> n = 0 \/ n divides m

Wed 12th Feb 2014       int.ml, Library/prime.ml

Moved the theorem "divides" out of Library/prime.ml into the core, since it
seems silly not to have such a basic fact available.

Wed 12th Feb 2014       Library/binomial.ml

Added

  BINOM_0 = |- !n. binom(0,n) = if n = 0 then 1 else 0

  BINOM_GE_TOP = |- !m n. 1 <= m /\ m < n ==> n <= binom(n,m)

Wed 12th Feb 2014       Library/products.ml

Added

  NPRODUCT_SUPPORT =
   |- !f s. nproduct (support ( * ) f s) f = nproduct s f

  NPRODUCT_SUPERSET =
   |- !f u v.
        u SUBSET v /\ (!x. x IN v /\ ~(x IN u) ==> f(x) = 1)
        ==> nproduct v f = nproduct u f`

  PRODUCT_SUPPORT =
   |- !f s. product (support ( * ) f s) f = product s f

  PRODUCT_SUPERSET =
   |- !f:A->real u v.
        u SUBSET v /\ (!x. x IN v /\ ~(x IN u) ==> f(x) = &1)
        ==> product v f = product u f

Wed 12th Feb 2014       iterate.ml

Added a couple of convenient theorems about when sums are stricly
positive:

  NSUM_POS_LT_ALL =
   |- !s f.
        FINITE s /\ ~(s = {}) /\ (!i. i IN s ==> 0 < f i) ==> 0 < nsum s f

  SUM_POS_LT_ALL =
   |- !s f.
        FINITE s /\ ~(s = {}) /\ (!i. i IN s ==> &0 < f i) ==> &0 < sum s f

Thu  6th Feb 2014       int.ml

Added INT_LE_DISCRETE = |- !x y:int. x <= y <=> x < y + &1

Thu  6th Feb 2014       Library/prime.ml

Added a definition of lcm to this file, and a suite of theorems mainly about
that. Also added "symmetric" clauses to GCD_0 and GCD_1.

  DIVIDES_LCM =
    |- !m n r. r divides m \/ r divides n ==> r divides lcm(m,n)

  DIVIDES_LCM_GCD =
    |- !m n d. d divides lcm(m,n) <=> d * gcd(m,n) divides m * n

  DIVISORS_EQ =
    |- !m n. m = n <=> (!d. d divides m <=> d divides n)

  GCD_LCM_DISTRIB =
    |- !a b c. gcd(a,lcm(b,c)) = lcm(gcd(a,b),gcd(a,c))

  lcm =
    |- !m n. lcm(m,n) = (if m * n = 0 then 0 else (m * n) DIV gcd(m,n))

  LCM =
    |- !m n.
         m divides lcm(m,n) /\
         n divides lcm(m,n) /\
         (!d. m divides d /\ n divides d ==> lcm(m,n) divides d)

  LCM_0 =
    |- (!n. lcm(0,n) = 0) /\ (!n. lcm(n,0) = 0)

  LCM_1 =
    |- (!n. lcm(1,n) = n) /\ (!n. lcm(n,1) = n)

  LCM_ASSOC =
    |- !m n p. lcm(m,lcm(n,p)) = lcm(lcm(m,n),p)

  LCM_DIVIDES =
    |- !m n d. lcm(m,n) divides d <=> m divides d /\ n divides d

  LCM_EQ =
    |- !x y u v.
            (!d. x divides d /\ y divides d <=> u divides d /\ v divides d)
            ==> lcm(x,y) = lcm(u,v)

  LCM_EXP =
    |- !n a b. lcm(a EXP n,b EXP n) = lcm(a,b) EXP n

  LCM_GCD_DISTRIB =
    |- !a b c. lcm(a,gcd(b,c)) = gcd(lcm(a,b),lcm(a,c))

  LCM_LMUL =
    |- !a b c. lcm(c * a,c * b) = c * lcm(a,b)

  LCM_MULTIPLE =
    |- !a b. lcm(b,a * b) = a * b

  LCM_REFL =
    |- !n. lcm(n,n) = n

  LCM_RMUL =
    |- !a b c. lcm(a * c,b * c) = c * lcm(a,b)

  LCM_SYM =
    |- !m n. lcm(m,n) = lcm(n,m)

  LCM_UNIQUE =
    |- !d m n.
          m divides d /\
          n divides d /\
          (!e. m divides e /\ n divides e ==> d divides e) <=>
          d = lcm(m,n)

  LCM_ZERO =
    |- !m n. lcm(m,n) = 0 <=> m = 0 \/ n = 0

  MULTIPLES_EQ =
    |- !m n. m = n <=> (!d. m divides d <=> n divides d)

  PRIMEPOW_DIVIDES_LCM =
    |- !m n p k. prime p
                 ==> (p EXP k divides lcm(m,n) <=>
                      p EXP k divides m \/ p EXP k divides n)

  PRIMEPOW_DIVISORS_DIVIDES =
    |- !m n. m divides n <=>
             (!p k.
                  prime p /\ p EXP k divides m
                  ==> p EXP k divides n)

  PRIMEPOW_DIVISORS_EQ =
    |- !m n. m = n <=>
             (!p k.
                  prime p
                  ==> (p EXP k divides m <=> p EXP k divides n))

Wed  5th Feb 2014       Library/products.ml

Added natural number products to "Library/products.ml", with all the analogous
theorems that are meaningful for their real counterparts:

  nproduct =
    |- nproduct = iterate (*)

  NPRODUCT_ADD_SPLIT =
    |- !f m n p.
               m <= n + 1
               ==> nproduct (m..n + p) f =
                   nproduct (m..n) f * nproduct (n + 1..n + p) f

  NPRODUCT_CLAUSES =
    |- (!f. nproduct {} f = 1) /\
       (!x f s.
              FINITE s
              ==> nproduct (x INSERT s) f =
                  (if x IN s
                   then nproduct s f
                   else f x * nproduct s f))

  NPRODUCT_CLAUSES_LEFT =
    |- !f m n. m <= n
                ==> nproduct (m..n) f =
                    f m * nproduct (m + 1..n) f

  NPRODUCT_CLAUSES_NUMSEG =
    |- (!m. nproduct (m..0) f = (if m = 0 then f 0 else 1)) /\
       (!m n.
            nproduct (m..SUC n) f =
            (if m <= SUC n
             then nproduct (m..n) f * f (SUC n)
             else nproduct (m..n) f))

  NPRODUCT_CLAUSES_RIGHT =
    |- !f m n.
           0 < n /\ m <= n
           ==> nproduct (m..n) f =
               nproduct (m..n - 1) f * f n

  NPRODUCT_CLOSED =
    |- !P f s.
            P 1 /\
            (!x y. P x /\ P y ==> P (x * y)) /\
            (!a. a IN s ==> P (f a))
            ==> P (nproduct s f)

  NPRODUCT_CONST =
    |- !c s. FINITE s ==> nproduct s (\x. c) = c EXP CARD s

  NPRODUCT_CONST_NUMSEG =
    |- !c m n. nproduct (m..n) (\x. c) = c EXP ((n + 1) - m)

  NPRODUCT_CONST_NUMSEG_1 =
    |- !c n. nproduct (1..n) (\x. c) = c EXP n

  NPRODUCT_EQ =
    |- !f g s. (!x. x IN s ==> f x = g x) ==> nproduct s f = nproduct s g

  NPRODUCT_EQ_0 =
    |- !f s.
          FINITE s
          ==> (nproduct s f = 0 <=> (?x. x IN s /\ f x = 0))

  NPRODUCT_EQ_0_NUMSEG =
    |- !f m n.
                 nproduct (m..n) f = 0 <=>
                 (?x. m <= x /\ x <= n /\ f x = 0)
  NPRODUCT_EQ_1 =
    |- !f s. (!x. x IN s ==> f x = 1) ==> nproduct s f = 1

  NPRODUCT_EQ_1_NUMSEG =
    |- !f m n. (!i. m <= i /\ i <= n ==> f i = 1)
               ==> nproduct (m..n) f = 1

  NPRODUCT_EQ_NUMSEG =
    |- !f g m n.
          (!i. m <= i /\ i <= n ==> f i = g i)
          ==> nproduct (m..n) f = nproduct (m..n) g

  NPRODUCT_IMAGE =
    |- !f g s.
           (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
           ==> nproduct (IMAGE f s) g = nproduct s (g o f)

  NPRODUCT_LE =
    |- !f s.
        FINITE s /\ (!x. x IN s ==> 0 <= f x /\ f x <= g x)
        ==> nproduct s f <= nproduct s g

  NPRODUCT_LE_NUMSEG =
    |- !f m n.
               (!i. m <= i /\ i <= n ==> 0 <= f i /\ f i <= g i)
               ==> nproduct (m..n) f <= nproduct (m..n) g

  NPRODUCT_MUL =
    |- !f g s.
         FINITE s
         ==> nproduct s (\x. f x * g x) =
             nproduct s f * nproduct s g

  NPRODUCT_MUL_NUMSEG =
    |- !f g m n.
                nproduct (m..n) (\x. f x * g x) =
                nproduct (m..n) f * nproduct (m..n) g

  NPRODUCT_OFFSET =
    |- !f m p.
            nproduct (m + p..n + p) f =
            nproduct (m..n) (\i. f (i + p))

  NPRODUCT_ONE =
    |- !s. nproduct s (\n. 1) = 1

  NPRODUCT_POS_LT =
    |- !f s.
            FINITE s /\ (!x. x IN s ==> 0 < f x)
            ==> 0 < nproduct s f

  NPRODUCT_POS_LT_NUMSEG =
    |- !f m n.
                   (!x. m <= x /\ x <= n ==> 0 < f x)
                   ==> 0 < nproduct (m..n) f

  NPRODUCT_SING =
    |- !f x. nproduct {x} f = f x

  NPRODUCT_SING_NUMSEG =
    |- !f n. nproduct (n..n) f = f n

  NPRODUCT_UNION =
    |- !f s t.
           FINITE s /\ FINITE t /\ DISJOINT s t
           ==> nproduct (s UNION t) f = nproduct s f * nproduct t f

  REAL_OF_NUM_NPRODUCT =
    |- !f s. FINITE s
             ==> &(nproduct s f) = product s (\x. &(f x))

Thu 23rd Jan 2014       iterate.ml, Library/isum.ml

Made the incompatible "improvement" of removing the finiteness hypothesis from
SUM_POS_LE, as well as adding two theorems about how sums of natural numbers
and integers collapse in the degenerate case of infinite support:

  NSUM_DEGENERATE =
    |- !f s. ~FINITE {x | x IN s /\ ~(f x = 0)} ==> nsum s f = 0

  SUM_DEGENERATE =
    |- !f s. ~FINITE {x | x IN s /\ ~(f x = &0)} ==> sum s f = &0

Although I didn't explicitly change the file Library/isum.ml, the theorem
ISUM_POS_LE automatically inherits the removal of the finiteness hypothesis.

Thu 16th Jan 2014       sets.ml

Added a few more basic properties of sup and inf:

  REAL_LE_SUP =
    |- !s a b y. y IN s /\ a <= y /\ (!x. x IN s ==> x <= b) ==> a <= sup s

  REAL_INF_LE =
    |- !s a b y. y IN s /\ y <= b /\ (!x. x IN s ==> a <= x) ==> inf s <= b

  REAL_SUP_LE_EQ =
    |- !s y.
           ~(s = {}) /\ (?b. !x. x IN s ==> x <= b)
           ==> (sup s <= y <=> (!x. x IN s ==> x <= y))

  REAL_LE_INF_EQ =
    |- !s t.
           ~(s = {}) /\ (?b. !x. x IN s ==> b <= x)
           ==> (y <= inf s <=> (!x. x IN s ==> y <= x))

  SUP_UNIQUE =
    |- !s b. (!c. (!x. x IN s ==> x <= c) <=> b <= c) ==> sup s = b

  INF_UNIQUE =
    |- !s b. (!c. (!x. x IN s ==> c <= x) <=> c <= b) ==> inf s = b

  SUP_UNION =
    |- !s t.
           ~(s = {}) /\
           ~(t = {}) /\
           (?b. !x. x IN s ==> x <= b) /\
           (?c. !x. x IN t ==> x <= c)
           ==> sup (s UNION t) = max (sup s) (sup t)

  INF_UNION =
    |- !s t.
           ~(s = {}) /\
           ~(t = {}) /\
           (?b. !x. x IN s ==> b <= x) /\
           (?c. !x. x IN t ==> c <= x)
           ==> inf (s UNION t) = min (inf s) (inf t)

Thu  9th Jan 2014       class.ml, sets.ml

Added a few theorems, two trivial but useful decomposition theorems for
quantifiers over set unions, and two forms of the Axiom of Dependent Choice.
These are a bit gratuitously overparameterized by "n", but this gives wider
applicability and still works in the standard unparameterized case.

FORALL_IN_UNION =
  |- !P s t.
         (!x. x IN s UNION t ==> P x) <=>
         (!x. x IN s ==> P x) /\ (!x. x IN t ==> P x)

EXISTS_IN_UNION =
  |- !P s t.
         (?x. x IN s UNION t /\ P x) <=>
         (?x. x IN s /\ P x) \/ (?x. x IN t /\ P x)

DEPENDENT_CHOICE_FIXED =
  |- !P R a.
         P 0 a /\ (!n x. P n x ==> (?y. P (SUC n) y /\ R n x y))
         ==> ?f. f 0 = a /\ (!n. P n (f n)) /\ (!n. R n (f n) (f (SUC n)))

DEPENDENT_CHOICE =
  |- !P R.
         (?a. P 0 a) /\ (!n x. P n x ==> (?y. P (SUC n) y /\ R n x y))
         ==> ?f. (!n. P n (f n)) /\ (!n. R n (f n) (f (SUC n)))

Mon  6th Jan 2014       holtest, holtest.mk [new file], holtest_parallel [new file]

Added a new parallel version of holtest from Hendrik Tews, which is able to
distribute tests over available processors/threads and is in general quite a
bit faster. Also unified this and the old serial "holtest" over what to use as
the HOL image: just use "hol-light" if it exists; make a "hol" executable if
ckpt is available, otherwise just use ocaml directly.

Fri  3rd Jan 2014       sets.ml, Permutation/morelist.ml

Added a couple of simple lemmas about "list_of_set", for the simple case where
there is no question about ordering:

        LIST_OF_SET_EMPTY = |- list_of_set {} = []

        LIST_OF_SET_SING = |- !x. list_of_set {a} = [a]

and a couple more related theorems in the Permutations library:

        LIST_UNIQ_APPEND =
          |- !l m.
                 LIST_UNIQ (APPEND l m) <=>
                 LIST_UNIQ l /\ LIST_UNIQ m /\ (!x. ~(MEM x l /\ MEM x m))

        LIST_UNIQ_LIST_OF_SET =
           |- !s. FINITE s ==> LIST_UNIQ (list_of_set s)

Sun 27th Oct 2013       class.ml

Added a slightly more refined variant of SKOLEM_THM:

  SKOLEM_THM_GEN =
  |- !P s. (!x. P x ==> ?y. R x y) <=> (?f. !x. P x ==> R x (f x))

Sun 27th Oct 2013       cart.ml

Added

  PCROSS_DIFF =
  |- (!s t u. s PCROSS (t DIFF u) = s PCROSS t DIFF s PCROSS u) /\
     (!s t u. (s DIFF t) PCROSS u = s PCROSS u DIFF t PCROSS u)

Wed 23rd Oct 2013       Makefile,  pa_j_3.1x_6.11.ml [new file]

Added yet another pa_j file, created by Freek Wiedijk, that appears to work
correctly for all camlp5 versions 6.07 - 6.11 (current one), and modified the
Makefile to select appropriately.

Mon 23rd Sep 2013       nums.ml

Made a modification from Tom Hales to "new_specification", simply using the
names of the constants instead of some hidden counter to make the definitions
unique.

Fri  6th Sep 2013       cart.ml

Added

  INTER_PCROSS =
    |- !s s' t t'.
          (s PCROSS t) INTER (s' PCROSS t') = (s INTER s') PCROSS (t INTER t')

Mon 26th Aug 2013       sets.ml

Added

  INFINITE_ENUMERATE =
    |- !s:num->bool.
         INFINITE s
         ==> ?r:num->num. (!m n. m < n ==> r(m) < r(n)) /\
                          IMAGE r (:num) = s

Thu 15th Aug 2013       Library/card.ml

Added

  CARD_LE_RELATIONAL_FULL =
   |- !R:A->B->bool s t.
        (!y. y IN t ==> ?x. x IN s /\ R x y) /\
        (!x y y'. x IN s /\ y IN t /\ y' IN t /\ R x y /\ R x y' ==> y = y')
        ==> t <=_c s

Wed 17th Jul 2013       Library/floor.ml

  Added INTEGER_ROUND = |- !x. ?n. integer n /\ abs(x - n) <= &1 / &2

Fri 12th Jul 2013       Library/floor.ml

Added a few theorems asserting that there are integers between well-spaced
pairs of reals:

  INTEGER_EXISTS_BETWEEN =
    |- !x y. x + &1 <= y ==> ?n. integer n /\ x <= n /\ n < y

  INTEGER_EXISTS_BETWEEN_ABS =
    |- !x y. &1 <= abs(x - y)
         ==> ?n. integer n /\ (x <= n /\ n < y \/ y <= n /\ n < x)

  INTEGER_EXISTS_BETWEEN_ABS_LT =
    |- !x y. &1 < abs(x - y)
         ==> ?n. integer n /\ (x < n /\ n < y \/ y < n /\ n < x)

  INTEGER_EXISTS_BETWEEN_ALT =
    |- !x y. x + &1 <= y ==> ?n. integer n /\ x < n /\ n <= y

  INTEGER_EXISTS_BETWEEN_LT =
    |- !x y. x + &1 < y ==> ?n. integer n /\ x < n /\ n < y

Thu 11th Jul 2013       sets.ml

Added a couple of slightly technical set lemmas:

  FINITE_TRANSITIVITY_CHAIN =
   |- !R s.
          FINITE s /\
          (!x. ~(R x x)) /\
          (!x y z. R x y /\ R y z ==> R x z) /\
          (!x. x IN s ==> ?y. y IN s /\ R x y)
          ==> s = {}

  UNIONS_MAXIMAL_SETS =
   |- !f. FINITE f
         ==> UNIONS {t | t IN f /\ !u. u IN f ==> ~(t PSUBSET u)} =
             UNIONS f

Mon  8th Jul 2013       int.ml

Added a trivial but useful theorem:

  INT_OF_NUM_EXISTS = |- !x. (?n. x = &n) <=> &0 <= x

Wed  3rd Jul 2013       real.ml, int.ml

Added two simple clausal theorems for "signs of signs"

  REAL_SGN_INEQS =
   |- (!x. &0 <= real_sgn x <=> &0 <= x) /\
      (!x. &0 < real_sgn x <=> &0 < x) /\
      (!x. &0 >= real_sgn x <=> &0 >= x) /\
      (!x. &0 > real_sgn x <=> &0 > x) /\
      (!x. &0 = real_sgn x <=> &0 = x) /\
      (!x. real_sgn x <= &0 <=> x <= &0) /\
      (!x. real_sgn x < &0 <=> x < &0) /\
      (!x. real_sgn x >= &0 <=> x >= &0) /\
      (!x. real_sgn x > &0 <=> x > &0) /\
      (!x. real_sgn x = &0 <=> x = &0)

  INT_SGN_INEQS =
   |- (!x. &0 <= int_sgn x <=> &0 <= x) /\
      (!x. &0 < int_sgn x <=> &0 < x) /\
      (!x. &0 >= int_sgn x <=> &0 >= x) /\
      (!x. &0 > int_sgn x <=> &0 > x) /\
      (!x. &0 = int_sgn x <=> &0 = x) /\
      (!x. int_sgn x <= &0 <=> x <= &0) /\
      (!x. int_sgn x < &0 <=> x < &0) /\
      (!x. int_sgn x >= &0 <=> x >= &0) /\
      (!x. int_sgn x > &0 <=> x > &0) /\
      (!x. int_sgn x = &0 <=> x = &0)

Wed  3rd Jul 2013       int.ml

Fixed a bug in INT_OF_REAL_THM where theorems with more than 2 conjuncts
were not being transformed correctly.

Sat 29th Jun 2013       miz3/miz3.ml, miz3/bin/miz3

Made a couple of improvements to the portability of miz3 to Mac OS X, based on
suggestions from Josh Jordan. Replaced the explicit signal number 12 by
Sys.sigusr2, and replace realpath (which doesn't exist by default in OS X) by a
line of Perl from Freek Wiedijk.

Fri 28th Jun 2013       tactics.ml, Library/card.ml

Moved TRANS_TAC from the cardinality theories to the main core.

Fri 21st Jun 2013       Library/products.ml

Added the obvious theorems about products of negations:

  PRODUCT_NEG =
  |- !f s.
         FINITE s ==> product s (\i. --f i) = -- &1 pow CARD s * product s f

  PRODUCT_NEG_NUMSEG =
  |- !f m n.
         product (m..n) (\i. --f i) =
         -- &1 pow ((n + 1) - m) * product (m..n) f

  PRODUCT_NEG_NUMSEG_1 =
  |- !f n. product (1..n) (\i. --f i) = -- &1 pow n * product (1..n) f

Tue  4th Jun 2013       cart.ml

Added a 4-element type and corresponding theorems

        HAS_SIZE_4 = |- (:4) HAS_SIZE 4
        DIMINDEX_4 = |- dimindex(:4) = 4

Fri 31st May 2013       cart.ml

Added:

  PCROSS_INTER =
   |- (!s t u. s PCROSS (t INTER u) = (s PCROSS t) INTER (s PCROSS u)) /\
      (!s t u. (s INTER t) PCROSS u = (s PCROSS u) INTER (t PCROSS u))

  PCROSS_UNION =
   |- (!s t u. s PCROSS (t UNION u) = (s PCROSS t) UNION (s PCROSS u)) /\
      (!s t u. (s UNION t) PCROSS u = (s PCROSS u) UNION (t PCROSS u))

  PCROSS_UNIONS_UNIONS =
   |- !f g. (UNIONS f) PCROSS (UNIONS g) =
            UNIONS {s PCROSS t | s IN f /\ t IN g}

  PCROSS_UNIONS =
   |- (!s f. s PCROSS (UNIONS f) = UNIONS {s PCROSS t | t IN f}) /\
      (!f t. (UNIONS f) PCROSS t = UNIONS {s PCROSS t | s IN f})

Thu 30th May 2013       Library/card.ml

Added some analogs of theorems already there for FINITE

  COUNTABLE_SUBSET_IMAGE =
    |- !f s t.
         COUNTABLE t /\ t SUBSET IMAGE f s <=>
         (?s'. COUNTABLE s' /\ s' SUBSET s /\ t = IMAGE f s')

  EXISTS_COUNTABLE_SUBSET_IMAGE =
    |- !P f s.
         (?t. COUNTABLE t /\ t SUBSET IMAGE f s /\ P t) <=>
         (?t. COUNTABLE t /\ t SUBSET s /\ P (IMAGE f t))

  FORALL_COUNTABLE_SUBSET_IMAGE =
    |- !P f s.
         (!t. COUNTABLE t /\ t SUBSET IMAGE f s ==> P t) <=>
         (!t. COUNTABLE t /\ t SUBSET s ==> P (IMAGE f t))

Thu 30th May 2013       sets.ml

Added the following

  FORALL_SUBSET_UNION =
   |- !t u:A->bool.
        (!s. s SUBSET t UNION u ==> P s) <=>
        (!t' u'. t' SUBSET t /\ u' SUBSET u ==> P(t' UNION u'))

  EXISTS_SUBSET_UNION =
   |- !t u:A->bool.
        (?s. s SUBSET t UNION u /\ P s) <=>
        (?t' u'. t' SUBSET t /\ u' SUBSET u /\ P(t' UNION u'))

Sun 26th May 2013       hol.ml

Added an extra line from Hendrik Tews to make things work more smoothly
with OCaml 4.xx:

#directory "+compiler-libs";;

Fri 24th May 2013       Library/iter.ml

Addded

  ITER_1 = |- !f x. ITER 1 f x = f x

Mon 20th May 2013       Library/card.ml

Added

  COUNTABLE_IMP_CARD_LT_REAL =
    |- !s. COUNTABLE s ==> s <_c (:real)

Thu  2nd May 2013       sets.ml

Added CARD_SING = |- !a. CARD {a} = 1

Wed  1st May 2013       cart.ml

Added:

  PCROSS_EQ =
   |- !s s' t t'.
        s PCROSS t = s' PCROSS t' <=>
        (s = {} \/ t = {}) /\ (s' = {} \/ t' = {}) \/ s = s' /\ t = t'

Tue 30th Apr 2013       cart.ml

Added:

  IMAGE_FSTCART_PCROSS =
    |- !s t. IMAGE fstcart (s PCROSS t) = if t = {} then {} else s

  IMAGE_SNDCART_PCROSS =
    |- !s t. IMAGE sndcart (s PCROSS t) = if s = {} then {} else t

Fri  5th Apr 2013       Examples/inverse_bug_puzzle_tac.ml

Updated this file to a new version from Bill Richter using some slightly
different constructs.

Fri  5th Apr 2013       Examples/prover9.ml

Fixed a bug in the prover9 interface pointed out by Keiichi Tsujimoto, where
the initial preprocessing could cause the initial goal to collapse to `T` or
`F`, which is then not handled properly by the main prover9 step. The fix is
to treat this specially in the preprocessing phase.

Sun 31st Mar 2013       Examples/inverse_bug_puzzle_miz3.ml

Made an update to Bill Richter's miz3 version of the inverse bug puzzle.

Sat 23rd Mar 2013       Examples/inverse_bug_puzzle_tac.ml, Examples/inverse_bug_puzzle_miz3.ml

Added a tactic version Examples/inverse_bug_puzzle_tac.ml of Bill Richter's
inverse bug puzzle solution, and renamed the earlier one as
Examples/inverse_bug_puzzle_miz3.ml.

Sat 23rd Mar 2013       Makefile

Incorporated a change from Jack Pappas to ensure that the Makefile handles
non-standard locations for camlp4, using "`camlp[45] -where`" instead of
"+camlp[45]".

Fri 22nd Mar 2013       cart.ml, Library/card.ml

Added

EXISTS_IN_PCROSS =
  |- (?z. z IN s PCROSS t /\ P z) <=>
     (?x y. x IN s /\ y IN t /\ P (pastecart x y))

PCROSS_MONO =
  |- !s t s' t'.
         s SUBSET s' /\ t SUBSET t' ==> s PCROSS t SUBSET s' PCROSS t'

SUBSET_PCROSS =
  |- !s t s' t'.
         s PCROSS t SUBSET s' PCROSS t' <=>
         s = {} \/ t = {} \/ s SUBSET s' /\ t SUBSET t'

UNIV_PCROSS_UNIV =
  |- (:A^M) PCROSS (:A^N) = (:A^(M,N)finite_sum)

FINITE_PCROSS_EQ =
  |- !s t. FINITE(s PCROSS t) <=> s = {} \/ t = {} \/ FINITE s /\ FINITE t

COUNTABLE_CARD_MUL =
 |- !s t. COUNTABLE s /\ COUNTABLE t ==> COUNTABLE (s *_c t);

COUNTABLE_CARD_MUL_EQ =
  |- !s t.
         COUNTABLE (s *_c t) <=>
         s = {} \/ t = {} \/ COUNTABLE s /\ COUNTABLE t

CARD_EQ_PCROSS =
  |- !s t. s PCROSS t =_c s *_c t

COUNTABLE_PCROSS_EQ =
  |- !s t.
         COUNTABLE (s PCROSS t) <=>
         s = {} \/ t = {} \/ COUNTABLE s /\ COUNTABLE t

COUNTABLE_PCROSS =
  |- !s t. COUNTABLE s /\ COUNTABLE t ==> COUNTABLE (s PCROSS t)

Thu 21st Mar 2013       cart.ml

Added more theorems about PCROSS:

PCROSS_EQ_EMPTY =
  |- !s t. s PCROSS t = {} <=> s = {} \/ t = {}

HAS_SIZE_PCROSS =
  |- !s t m n. s HAS_SIZE m /\ t HAS_SIZE n ==> s PCROSS t HAS_SIZE m * n

FINITE_PCROSS =
  |- !s t. FINITE s /\ FINITE t ==> FINITE(s PCROSS t)

PCROSS_EMPTY =
  |- (!s. s PCROSS {} = {}) /\ (!t. {} PCROSS t = {})

Wed 20th Mar 2013       cart.ml

Added a definition of a variant notion of product using pasting of vectors,
called PCROSS, plus two elementary theorems:

PCROSS =
 |- s PCROSS t = {pastecart (x:A^M) (y:A^N) | x IN s /\ y IN t}

FORALL_IN_PCROSS =
 |- (!z. z IN s PCROSS t ==> P z) <=>
    (!x y. x IN s /\ y IN t ==> P(pastecart x y))

PASTECART_IN_PCROSS =
 |- !s t x y. (pastecart x y) IN (s PCROSS t) <=> x IN s /\ y IN t

Mon 18th Mar 2013       preterm.ml

Added a slight update from Vincent Aravantinos to the typechecking error
messages, to handle additional cases.

Fri 15th Mar 2013       iterate.ml

Added a couple of strict positivity theorems for sums:

NSUM_POS_LT =
  |- !f s.
        FINITE s /\ (?x. x IN s /\ 0 < f x)
        ==> 0 < nsum s f

SUM_POS_LT =
  |- !f s.
        FINITE s /\
        (!x. x IN s ==> &0 <= f x) /\
        (?x. x IN s /\ &0 < f x)
        ==> &0 < sum s f

Fri 15th Feb 2013       Examples/inverse_bug_puzzle.ml [new file]

Added a new file due to Bill Richter giving a solution to the inverse
bug puzzle in the tutorial, using miz3 and the vector theories.

Fri 15th Feb 2013       tactics.ml

Improved the error reporting in EXISTS_TAC, X_CHOOSE_TAC and X_GEN_TAC, which
now in particular specify the expected and received types of the terms when
they don't agree.

Wed 13th Feb 2013       real.ml

Added the following obvious theorem (which does depend on the choice of
1/0):

REAL_DIV_EQ_0 = |- !x y. x / y = &0 <=> x = &0 \/ y = &0

Fri 18th Jan 2013       lists.ml, Library/prime.ml, Library/pocklington.ml, Permutation/permuted.ml

Added a miscellany of theorems:

APPEND_SING =
  |- !h t. APPEND [h] t = CONS h t

MEM_APPEND_DECOMPOSE_LEFT =
  |- !x l. MEM x l <=> (?l1 l2. ~MEM x l1 /\ l = APPEND l1 (CONS x l2))

MEM_APPEND_DECOMPOSE =
  |- !x l. MEM x l <=> (?l1 l2. l = APPEND l1 (CONS x l2))

PERMUTED_APPEND_SWAP =
  |- !l1 l2. (APPEND l1 l2) PERMUTED (APPEND l2 l1)

DIVIDES_EXP_MINUS1 =
  |- !k n. n - 1 divides n EXP k - 1

DIVIDES_EXP_PLUS1 =
  |- !n k. ODD k ==> n + 1 divides n EXP k + 1

PRIME_DIVEXP_EQ =
  |- !n p x. prime p ==> (p divides x EXP n <=> p divides x /\ ~(n = 0))

PRIME_POWER_EXISTS =
  |- !q. prime q
         ==> ((?i. n = q EXP i) <=> (!p. prime p /\ p divides n ==> p = q))

Thu 17th Jan 2013       Library/products.ml

Added

  PRODUCT_CLAUSES_LEFT =
    |- !f m n. m <= n ==> product (m..n) f = f m * product (m + 1..n) f

  PRODUCT_CLAUSES_RIGHT =
    |- !f m n.
           0 < n /\ m <= n ==> product (m..n) f = product (m..n - 1) f * f n

Wed 16th Jan 2013       sets.ml

Added

UNIONS_MONO =
  |- (!x. x IN s ==> (?y. y IN t /\ x SUBSET y)) ==> UNIONS s SUBSET UNIONS t

UNIONS_MONO_IMAGE =
  |- (!x. x IN s ==> f x SUBSET g x)
     ==> UNIONS (IMAGE f s) SUBSET UNIONS (IMAGE g s)

Sun  6th Jan 2013       miz3/Samples/icms.ml

Removed the load of Multivariate/misc.ml from this example, putting the proof
of the Archimedian lemma directly in this file. There is now an incompatibility
with the Multivariate use of "from" as a constant with the use as a miz3
reserved word. This should probably be dealt with more systematically, perhaps
by renaming the constant to FROM.

Fri  4th Jan 2013       tactics.ml, theorems.ml, help.ml, Help/DESTRUCT_TAC.doc [new file], Help/FIX_TAC.doc [new file], Help/HYP.doc [new file], Help/INTRO_TAC.doc [new file]

Added four new tactic constructs from Marco Maggesi. HYP is analogous to ASM
but restricting to named (labelled) assumptions. DESTRUCT_TAC, FIX_TAC and
INTRO_TAC give more concise and elegant ways of fixing variables, performing
introduction on a goal or elimination on a theorem, labelling assumptions in
the process.

Fri  4th Jan 2013       Multivariate/tarski.ml, 100/independence.ml

Added two files showing Tarski's 11 axioms for geometry hold in the Euclidean
plane but all except axiom 10 hold in the Klein model of the hyperbolic plane.
This effectively proves the independence of the parallel postulate.

Fri  4th Jan 2013       Library/floor.ml

Added RATIONAL_BETWEEN = |- !a b. a < b ==> ?q. rational q /\ a < q /\ q < b

Fri  4th Jan 2013       cart.ml

Added PASTECART_INJ =
  |- !x y w z.  pastecart x y = pastecart w z <=> x = w /\ y = z

Wed  2nd Jan 2013       system.ml, miz3/miz3.ml

Extended the regular quotation parser to pass quotations of the form
`;....` to miz3's "parse_qproof". This makes it more convenient to load
files with miz3 proofs in without first setting up the new parser before
the file is loaded.

Thu 20th Dec 2012       sets.ml

Added SUBSET_INTERS =
  |- !s f. s SUBSET INTERS f <=> (!t. t IN f ==> s SUBSET t)

Wed 19th Dec 2012       sets.ml

Renamed the existing DIFF_UNIONS to UNIONS_DIFF and added the following:

DIFF_UNIONS =
  |- !u s. u DIFF UNIONS s = u INTER INTERS {u DIFF t | t IN s}

DIFF_UNIONS_NONEMPTY =
  |- !u s. ~(s = {}) ==> u DIFF UNIONS s = INTERS {u DIFF t | t IN s}

This seems more consistent with the naming of DIFF_INTERS.

Mon 17th Dec 2012       Library/wo.ml

Added the definition of total order and a proof of the order extension theorem:

toset =
 |- toset l <=>
    poset l /\ !x y. x IN fl(l) /\ y IN fl(l) ==> l(x,y) \/ l(y,x)

OEP = |- !p. poset p ==> ?t. toset t /\ fl(t) = fl(p) /\ p SUBSET t

Fri 14th Dec 2012       preterm.ml

Updated the typechecker with a new version from Vincent Aravantinos that gives
more useful error messages when typechecking fails.

Wed  5th Dec 2012       sets.ml

Added a couple of reformulations of injectivity. This is useful since the
left-hand characterization can make the simplifier get very slow.

INJECTIVE_ON_ALT =
  |- !P f.
         (!x y. P x /\ P y /\ f x = f y ==> x = y) <=>
         (!x y. P x /\ P y ==> (f x = f y <=> x = y))

INJECTIVE_ALT =
  |- !f. (!x y. f x = f y ==> x = y) <=> (!x y. f x = f y <=> x = y)

Fri 16th Nov 2012       tactics.ml, Help/STRUCT_CASES_THEN.doc [new file]

At the suggestion of Petros Papapanagiotou, made a theorem-tactic form
STRUCT_CASES_THEN of STRUCT_CASES_TAC, to allow for more flexibility in how the
resulting theorems get used.

Fri 16th Nov 2012       IsabelleLight/*, RichterHilbertAxiomGeometry/*

Brought these up to date with recent changes by their respective authors.

Fri 16th Nov 2012       hol.ml, preterm.ml, parser.ml, printer.ml

Reshuffled a few preliminaries between these files so that "printer.ml"
could be loaded before the other two. This is a prelude to putting in code from
Vincent Aravantinos for better error messages from typechecking, where it's
useful to have functions from "printer.ml" for the error reporting.

Fri 16th Nov 2012       sets.ml, cart.ml

Added a few simple theorems about cardinalities of finite universe sets,
and also a natural counterpart UNIV_GSPEC to EMPTY_GSPEC. New theorems:

CARD_BOOL =
  |- CARD(:bool) = 2

CARD_CART_UNIV =
  |- FINITE(:A) ==> CARD(:A^N) = CARD(:A) EXP dimindex(:N)

CARD_FUNSPACE_UNIV =
  |- FINITE(:A) /\ FINITE(:B) ==> CARD(:A->B) = CARD(:B) EXP CARD(:A)

FINITE_BOOL =
  |- FINITE(:bool)

FINITE_CART_UNIV =
  |- FINITE(:A) ==> FINITE(:A^N)

FINITE_FUNSPACE_UNIV =
  |- FINITE(:A) /\ FINITE(:B) ==> FINITE(:A->B)

HAS_SIZE_BOOL =
  |- (:bool) HAS_SIZE 2

HAS_SIZE_CART_UNIV =
  |- !m. (:A) HAS_SIZE m ==> (:A^N) HAS_SIZE m EXP dimindex(:N)

HAS_SIZE_FUNSPACE_UNIV =
  |- !m n. (:A) HAS_SIZE m /\ (:B) HAS_SIZE n ==> (:A->B) HAS_SIZE n EXP m

UNIV_GSPEC =
  |- {x | T} = UNIV

Tue 13th Nov 2012       sets.ml, Library/card.ml

Added three new theorems about COUNTABLE in exact analogy with FINITE, and also
cleaned up the FINITE proof of one of them based on the pattern.

COUNTABLE_IMAGE_INJ =
  |- !f A.
         (!x y. f x = f y ==> x = y) /\ COUNTABLE A
         ==> COUNTABLE {x | f x IN A}

COUNTABLE_IMAGE_INJ_EQ =
  |- !f s.
         (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
         ==> (COUNTABLE (IMAGE f s) <=> COUNTABLE s)

COUNTABLE_IMAGE_INJ_GENERAL =
  |- !f A s.
         (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\ COUNTABLE A
         ==> COUNTABLE {x | x IN s /\ f x IN A}

Fri 28th Sep 2012       pair.ml, int.ml, sets.ml, database.ml, Library/card.ml

Added a few miscellaneous little theorems:

  CHOOSE_SUBSET_BETWEEN =
    |- !n s u.
           s SUBSET u /\ FINITE s /\ CARD s <= n /\ (FINITE u ==> n <= CARD u)
           ==> (?t. s SUBSET t /\ t SUBSET u /\ t HAS_SIZE n)

  EXISTS_CURRY =
    |- !P. (?f. P f) <=> (?f. P (\(a,b). f a b))

  FORALL_CURRY =
    |- !P. (!f. P f) <=> (!f. P (\(a,b). f a b))

  FORALL_FINITE_SUBSET_IMAGE =
    |- !P f s.
           (!t. FINITE t /\ t SUBSET IMAGE f s ==> P t) <=>
           (!t. FINITE t /\ t SUBSET s ==> P (IMAGE f t))

  INFINITE_SUPERSET =
    |- !s t. INFINITE s /\ s SUBSET t ==> INFINITE t

  INF_SING =
    |- !a. inf {a} = a

  PAIRED_ETA_THM =
    |- (!f. (\(x,y). f (x,y)) = f) /\
       (!f. (\(x,y,z). f (x,y,z)) = f) /\
       (!f. (\(w,x,y,z). f (w,x,y,z)) = f)

  SUP_SING =
    |- !a. sup {a} = a

as well as slightly reshuffling some existing theorems and adding new
cardinality theorems.

Thu  6th Sep 2012       update_database.ml

Fixed the update_database code for OCaml 4.00. This entails making a couple
more things conditional on the version number (using the exec "code" method
already used in Roland Zumkeller's original code). First, the "Tvar"
constructor now takes an argument (and because of the way OCaml's internal
representation works with different sequences for nullary and non-nullary, this
changes some of the constructor numbers). Second, the tbl type has changed to
the use of EnvTbl that effectively wraps up the core type 'a into 'a * bool
ref.

Fri 31st Aug 2012       Makefile, README

Fixed up the Makefile both for recent camlp5s (not exhaustively tested, but I
think it is right) and also for OCaml 4.00, as well as making the instructions
in the README file a bit more up-to-date.

Fri  1st Jun 2012       100/descartes.ml [new file]

Added a proof of Descartes's rule of signs, based on Rob Arthan's paper
"Descartes's Rule of Signs by an Easy Induction".

Wed 30th May 2012       100/cayley_hamilton.ml [new file]

Added a proof of the Cayley-Hamilton theorem for real matrices.

Wed 30th May 2012       100/feuerbach.ml [new file]

Added a proof of Feuerbach's theorem.

Tue 29th May 2012       Examples/sylvester_gallai.ml [new file]

Added a proof of the Sylvester-Gallai theorem.

Mon 28th May 2012       100/morley.ml [new file]

Added a proof of Morley's theorem, following Alain Connes's paper "A new proof
of Morley's theorem".

Sun 27th May 2012       Examples/brunn_minkowski.ml [new file]

Added a proof of the Brunn-Minkowski theorem.

Sat 26th May 2012       100/platonic.ml [new file]

Added a proof that the Platonic solids are limited to the classic five, and
that those all do exist and are regular. Because of the rather crude way in
which the computations of facial structure are done, this proof takes quite a
long time to load.

Sat 26th May 2012       QBF/* [new files]

Added Ondrej Kuncar's code for constructing proofs of quantified boolean
formulas in HOL Light using proof traces from Squolem.

Fri 25th May 2012       100/polyhedron.ml [new file]

Added a proof of Euler's polyhedron formula for convex polytopes, and indeed
the general Euler-Poincare relation. This follows Jim Lawrence's "A short proof
of Euler's relation for convex polytopes" (Canadian Math Bulletin, 1997). This
proof was mostly quite easy and natural to formalize, except for some slightly
tedious switching between open and closed cells at one point.

Wed 16th May 2012       Makefile

Added a test to the Makefile to catch camlp5 6.05 and use the pa_j.ml designed
for 6.02.2, which according to a test by Bill Richter works fine. I could
probably also add the intermediate versions 6.03 and 6.04, but I didn't do so
for now.

Wed 16th May 2012       miz3/miz3.ml, miz3/test.ml, holtest

Made a small tweak to miz3.ml from Freek, and removed the test run in the final
line. Also replaced the former test.ml file with the former Samples/ALL (which
is no longer there now), and made "holtest" run it twice in case cacheing
changes things.

Mon  7th May 2012       sets.ml

Added the trivial but sometimes useful lemma

 INFINITE_SUPERSET =
   |- !s t. INFINITE s /\ s SUBSET t ==> INFINITE t

Fri  4th May 2012       miz3/* [new files], passim

Added Freek Wiedijk's miz3 mode, and since there I first made a tweak of
open_in -> Pervasives.open_in (to avoid possible namespace conflicts with
Multivariate/topology.ml) made a similar change in a few other places too.

Fri 27th Apr 2012       sets.ml, Help/new_inductive_set.doc [new file]

Added a function from Marco Maggesi for defining sets inductively by analogy
with new_inductive_definition for relations.

Fri 27th Apr 2012       preterm.ml, Help/the_implicit_types.doc [new file], Help/passim

Added another extra feature to term parsing from Marco Maggesi, a list of
implicit type schemes for variables in quotations, "the_implicit_types".

Thu 26th Apr 2012       preterm.ml, Help/type_invention_error.doc [new file], type_invention_warning.doc

Added code from Marco Maggesi to incorporate an additional option
"type_invention_error" that forces type variables to be an error, not merely be
warned about. Added a corresponding documentation file and some
cross-referencing w.r.t the existing file "type_invention_warning.doc".

Thu 26th Apr 2012       holtest

Incorporated some changes from Hendrik Tews to make "holtest" a bit more
robust and keep it consistent with the HOL Light debian package.

Tue 24th Apr 2012       Help/new_axiom.doc

Made a couple of small fixes to the "new_axiom" documentation, removing a stray
paren and adding a cross-reference to "axioms".

Fri 30th Mar 2012       Permutation/permuted.ml

Added a couple of lemmas about list permutations preserving "PAIRWISE" for a
symmetric relation, plus strong induction PERMUTED_INDUCT_STRONG:

  PERMUTED_IMP_PAIRWISE =
   |- !P l l'. (!x y. P x y ==> P y x) /\ l PERMUTED l' /\ PAIRWISE P l
               ==> PAIRWISE P l'

  PERMUTED_PAIRWISE =
   |- !P l l'. (!x y. P x y ==> P y x) /\ l PERMUTED l'
               ==> (PAIRWISE P l <=> PAIRWISE P l')

Thu 29th Mar 2012       Library/card.ml

Added a few new theorems about cardinal arithmetic:

  CARD_LE_RELATIONAL =
    |- !R. (!x y y'. x IN s /\ R x y /\ R x y' ==> y = y')
           ==> {y | ?x. x IN s /\ R x y} <=_c s

  CARD_LT_FINITE_INFINITE =
    |- !s t. FINITE s /\ INFINITE t ==> s <_c t

  CARD_ADD2_ABSORB_LT =
    |- !s t u. INFINITE u /\ s <_c u /\ t <_c u ==> s +_c t <_c u

  CARD_ADD_FINITE_EQ =
    |- !s t. FINITE(s +_c t) <=> FINITE s /\ FINITE t

  CARD_ADD_C =
    |- !s t. FINITE s /\ FINITE t ==> CARD(s +_c t) = CARD s + CARD t

  CARD_LT_ADD =
    |- !s s' t t'. s <_c s' /\ t <_c t' ==> s +_c t <_c s' +_c t'

Fri  9th Mar 2012       Library/card.ml

Added a few more trivial lemmas about cardinality:

  CARD_LT_LE = |- !s t. s <_c t <=> s <=_c t /\ ~(s =_c t)

  CARD_LE_LT = |- !s t. s <=_c t <=> s <_c t \/ s =_c t

  COUNTABLE_ALT = |- !s. COUNTABLE s <=> s <=_c (:num)

  COUNTABLE_CASES = |- !s. COUNTABLE s <=> FINITE s \/ s =_c (:num)

Sun 26th Feb 2012       sets.ml

Added

    CARD_IMAGE_EQ_INJ =
     |- !f:A->B s.
        FINITE s
        ==> (CARD(IMAGE f s) = CARD s <=>
             !x y. x IN s /\ y IN s /\ f x = f y ==> x = y)

    PAIRWISE_IMAGE =
     |- !r f. pairwise r (IMAGE f s) <=>
              pairwise (\x y. ~(f x = f y) ==> r (f x) (f y)) s

Thu 23rd Feb 2012       sets.ml

Added

    PAIRWISE_INSERT =
     |- !r x s.
          pairwise r (x INSERT s) <=>
          (!y. y IN s /\ ~(y = x) ==> r x y /\ r y x) /\
          pairwise r s

Tue 21st Feb 2012       sets.ml, Library/card.ml

Added two direct equality results for sups and infs:

SUP_EQ =
 |- !s t. (!b. (!x. x IN s ==> x <= b) <=> (!x. x IN t ==> x <= b))
          ==> sup s = sup t

INF_EQ =
 |- !s t. (!a. (!x. x IN s ==> a <= x) <=> (!x. x IN t ==> a <= x))
           ==> inf s = inf t

and a few basic lemmas about cardinality:

  CARD_LE_COUNTABLE =
    |- !s t. COUNTABLE t /\ s <=_c t ==> COUNTABLE s

  CARD_COUNTABLE_CONG =
    |- !s t. s =_c t ==> (COUNTABLE s <=> COUNTABLE t)

  CARD_EQ_FINITE =
    |- !s t. FINITE t /\ s =_c t ==> FINITE s

  CARD_EQ_COUNTABLE =
   |- !s t. COUNTABLE t /\ s =_c t ==> COUNTABLE s

  CARD_EQ_IMAGE =
   |- !f s.
          (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
          ==> IMAGE f s =_c s

  CARD_EQ_REAL_IMP_UNCOUNTABLE =
   |- !s. s =_c (:real) ==> ~COUNTABLE s

Sat 11th Feb 2012       Library/floor.ml

Added the obvious facts that the integer and rational valued reals are
both infinite:

 INFINITE_INTEGER  = |- INFINITE integer

 INFINITE_RATIONAL = |- INFINITE rational

Thu  2nd Feb 2012       iterate.ml

Added two theorems about pushing MODs through sums of natural numbers:

MOD_NSUM_MOD =
  |- !f n s.
         FINITE s /\ ~(n = 0)
         ==> nsum s f MOD n = nsum s (\i. f i MOD n) MOD n

MOD_NSUM_MOD_NUMSEG =
  |- !f a b n.
         ~(n = 0) ==> nsum (a..b) f MOD n = nsum (a..b) (\i. f i MOD n) MOD n

Wed  1st Feb 2012       arith.ml

Added a theorem that's a trivial consequence of DIVISION, but sometimes a
bit more convenient

  DIVISION_SIMP =
   |- (!m n. ~(n = 0) ==> m DIV n * n + m MOD n = m) /\
      (!m n. ~(n = 0) ==> n * m DIV n + m MOD n = m)

Wed  1st Feb 2012       Mizarlight/Makefile

Fixed up the Makefile to choose camlp5 versus camlp4 in a correct way
as in the main system Makefile (previously this failed for OCaml >= 3.12).

Tue 31st Jan 2012       sets.ml

Added one more set lemma, analogous to INTER_UNIONS:

  DIFF_UNIONS =
   |- !s t. (UNIONS s) DIFF t = UNIONS {x DIFF t | x IN s}

Thu 26th Jan 2012       cart.ml

Added a somewhat technical lemma, a generalization of FINITE_INDEX_INRANGE
that is useful for obscure situations to get rid of range conditions in
doubly indexed cartesian products:

  FINITE_INDEX_INRANGE_2 =
   |- !i. ?k. 1 <= k /\ k <= dimindex(:N) /\
             (!x:A^N. x$i = x$k) /\ (!y:B^N. y$i = y$k)

Thu 19th Jan 2012       Library/card.ml

Generalized COUNTABLE_PRODUCT_DEPENDENT to have the same form as
FINITE_PRODUCT_DEPENDENT instead of being tied specifically to pairs.

Sat 14th Jan 2012       sets.ml

Added "localized" forms of the theorems about factoring functions through
each other:

  FUNCTION_FACTORS_LEFT_GEN =
    |- !P f g. (!x y. P x /\ P y /\ g x = g y ==> f x = f y) <=>
               (?h. !x. P x ==> f(x) = h(g x))

  FUNCTION_FACTORS_RIGHT_GEN =
    |- !P f g. (!x. P x ==> ?y. g(y) = f(x)) <=>
               (?h. !x. P x ==> f(x) = g(h x))

Mon  9th Jan 2012       list.ml

Added two new list theorems

 MAP_REVERSE = |- !f l. REVERSE(MAP f l) = MAP f (REVERSE l)

 ALL_FILTER = |- !P Q l. ALL P (FILTER Q l) <=> ALL (\x. Q x ==> P x) l

Thu 23rd Dec 2011       Library/card.ml

Added CARD_LE_UNIV = |- !s:A->bool. s <=_c (:A)

Wed 22nd Dec 2011       sets.ml, iterate.ml, define.ml, Library/permutations.ml, Library/products.ml, Library/iter.ml, Multivariate/ passim

Did a bit of cleaning up of theorems to remove redundant quantifiers (put there
by accident for variables that aren't free in the body). This includes the
following and numerous theorems in the Multivariate theories:

========= sets.ml ============
        SIMPLE_IMAGE_GEN
        HAS_SIZE_0
========= iterate.ml ============
        NSUM_BOUND_GEN
        NSUM_BOUND_LT_GEN
        NSUM_EQ_0_NUMSEG
        SUM_BOUND_GEN
        SUM_BOUND_LT_GEN
        SUM_EQ_0_NUMSEG
========= define.ml ============
        ADMISSIBLE_MATCH
========= Library/permutations.ml ============
        PERMUTES_COMPOSE
========= Library/products.ml ============
        PRODUCT_EQ_1_NUMSEG
========= Library/iter.ml ============
        ITER_ALT_POINTLESS

Sun 18th Dec 2011       cart.ml

Added a convenient set elimination theorem for pasted vectors:

  IN_ELIM_PASTECART_THM =
    |- !P a b. pastecart a b IN {pastecart x y | P x y} <=> P a b

Thu  1st Dec 2011       Library/card.ml

Added a few more theorems on cardinality of list and cartesian product types
and also the cardinality and uncountability of the reals. This last fact is
done in a primitive way to avoid depending on the analytical theories. The
theorem UNCOUNTABLE_REAL has been taken out of the Multivariate theories now
in consequence.

  CARD_EQ_LIST = |- INFINITE(:A) ==> (:(A)list) =_c (:A)

  CARD_EQ_CART = |- INFINITE(:A) ==> (:A^N) =_c (:A)

  CARD_EQ_REAL = |- (:real) =_c (:num->bool)

  UNCOUNTABLE_REAL = |- ~COUNTABLE (:real)

Thu  1st Dec 2011       sets.ml

Moved all the definitions and basic theorems about sup and inf to the end of
this file from Multivariate/misc.ml:

   inf =
    |- !s. inf s =
           (@a. (!x. x IN s ==> a <= x) /\
                (!b. (!x. x IN s ==> b <= x) ==> b <= a))

   sup =
    |- !s. sup s =
           (@a. (!x. x IN s ==> x <= a) /\
                (!b. (!x. x IN s ==> x <= b) ==> a <= b)))]

   INF =
    |- !s. ~(s = {}) /\ (?b. !x. x IN s ==> b <= x)
           ==> (!x. x IN s ==> inf s <= x) /\
               (!b. (!x. x IN s ==> b <= x) ==> b <= inf s)

   INF_FINITE =
    |- !s. FINITE s /\ ~(s = {})
           ==> inf s IN s /\ (!x. x IN s ==> inf s <= x)

   INF_FINITE_LEMMA =
    |- !s. FINITE s /\ ~(s = {}) ==> (?b. b IN s /\ (!x. x IN s ==> b <= x))

   INF_INSERT_FINITE =
    |- !x s.
           FINITE s
           ==> inf (x INSERT s) = (if s = {} then x else min x (inf s))

   INF_UNIQUE_FINITE =
    |- !s. FINITE s /\ ~(s = {})
           ==> (inf s = a <=> a IN s /\ (!y. y IN s ==> a <= y))

   REAL_ABS_INF_LE =
    |- !s a. ~(s = {}) /\ (!x. x IN s ==> abs x <= a) ==> abs(inf s) <= a

   REAL_ABS_SUP_LE =
    |- !s a. ~(s = {}) /\ (!x. x IN s ==> abs x <= a) ==> abs(sup s) <= a

   REAL_INF_ASCLOSE =
    |- !s l e.
           ~(s = {}) /\ (!x. x IN s ==> abs(x - l) <= e)
           ==> abs(inf s - l) <= e

   REAL_INF_BOUNDS =
    |- !s a b.
           ~(s = {}) /\ (!x. x IN s ==> a <= x /\ x <= b)
           ==> a <= inf s /\ inf s <= b

   REAL_INF_LE_FINITE =
    |- !s a.
           FINITE s /\ ~(s = {}) ==> (inf s <= a <=> (?x. x IN s /\ x <= a))

   REAL_INF_LT_FINITE =
    |- !s a. FINITE s /\ ~(s = {}) ==> (inf s < a <=> (?x. x IN s /\ x < a))

   REAL_INF_UNIQUE =
    |- !s b.
           (!x. x IN s ==> b <= x) /\
           (!b'. b < b' ==> (?x. x IN s /\ x < b'))
           ==> inf s = b

   REAL_LE_INF =
    |- !b. ~(s = {}) /\ (!x. x IN s ==> b <= x) ==> b <= inf s

   REAL_LE_INF_FINITE =
    |- !s a.
           FINITE s /\ ~(s = {}) ==> (a <= inf s <=> (!x. x IN s ==> a <= x))

   REAL_LE_INF_SUBSET =
    |- !s t.
           ~(t = {}) /\ t SUBSET s /\ (?b. !x. x IN s ==> b <= x)
           ==> inf s <= inf t

   REAL_LE_SUP_FINITE =
    |- !s a.
           FINITE s /\ ~(s = {}) ==> (a <= sup s <=> (?x. x IN s /\ a <= x))

   REAL_LT_INF_FINITE =
    |- !s a. FINITE s /\ ~(s = {}) ==> (a < inf s <=> (!x. x IN s ==> a < x))

   REAL_LT_SUP_FINITE =
    |- !s a. FINITE s /\ ~(s = {}) ==> (a < sup s <=> (?x. x IN s /\ a < x))

   REAL_SUP_ASCLOSE =
    |- !s l e.
           ~(s = {}) /\ (!x. x IN s ==> abs(x - l) <= e)
           ==> abs(sup s - l) <= e

   REAL_SUP_BOUNDS =
    |- !s a b.
           ~(s = {}) /\ (!x. x IN s ==> a <= x /\ x <= b)
           ==> a <= sup s /\ sup s <= b

   REAL_SUP_EQ_INF =
    |- !s. ~(s = {}) /\ (?B. !x. x IN s ==> abs x <= B)
           ==> (sup s = inf s <=> (?a. s = {a}))

   REAL_SUP_LE =
    |- !b. ~(s = {}) /\ (!x. x IN s ==> x <= b) ==> sup s <= b

   REAL_SUP_LE_FINITE =
    |- !s a.
           FINITE s /\ ~(s = {}) ==> (sup s <= a <=> (!x. x IN s ==> x <= a))

   REAL_SUP_LE_SUBSET =
    |- !s t.
           ~(s = {}) /\ s SUBSET t /\ (?b. !x. x IN t ==> x <= b)
           ==> sup s <= sup t

   REAL_SUP_LT_FINITE =
    |- !s a. FINITE s /\ ~(s = {}) ==> (sup s < a <=> (!x. x IN s ==> x < a))

   REAL_SUP_UNIQUE =
    |- !s b.
           (!x. x IN s ==> x <= b) /\
           (!b'. b' < b ==> (?x. x IN s /\ b' < x))
           ==> sup s = b

   SUP =
    |- !s. ~(s = {}) /\ (?b. !x. x IN s ==> x <= b)
           ==> (!x. x IN s ==> x <= sup s) /\
               (!b. (!x. x IN s ==> x <= b) ==> sup s <= b)

   SUP_FINITE =
    |- !s. FINITE s /\ ~(s = {})
           ==> sup s IN s /\ (!x. x IN s ==> x <= sup s)

   SUP_FINITE_LEMMA =
    |- !s. FINITE s /\ ~(s = {}) ==> (?b. b IN s /\ (!x. x IN s ==> x <= b))

   SUP_INSERT_FINITE =
    |- !x s.
           FINITE s
           ==> sup (x INSERT s) = (if s = {} then x else max x (sup s))

   SUP_UNIQUE_FINITE =
    |- !s. FINITE s /\ ~(s = {})
           ==> (sup s = a <=> a IN s /\ (!y. y IN s ==> y <= a))

Thu  1st Dec 2011       real.ml

Moved three basic Archimedian properties back to here from
Multivariate/misc.ml:

  REAL_ARCH_SIMPLE = |- !x. ?n. x <= &n

  REAL_ARCH_LT = |- !x. ?n. x < &n

  REAL_ARCH = |- !x. &0 < x ==> (!y. ?n. y < &n * x)

Thu  1st Dec 2011       list.ml

Added EL_MAP = |- !f n l. n < LENGTH l ==> EL n (MAP f l) = f (EL n l)

Mon 21st Nov 2011       iterate.ml

Added a few lemmas about the behaviour of real polynomial functions, since
these are quite often useful:

 REAL_SUB_POLYFUN =
  |- !a x y n.
         1 <= n
         ==> sum(0..n) (\i. a i * x pow i) - sum(0..n) (\i. a i * y pow i) =
             (x - y) *
             sum(0..n - 1)
             (\j. sum(j + 1..n) (\i. a i * y pow (i - j - 1)) * x pow j)

 REAL_SUB_POLYFUN_ALT =
  |- !a x y n.
         1 <= n
         ==> sum(0..n) (\i. a i * x pow i) - sum(0..n) (\i. a i * y pow i) =
             (x - y) *
             sum(0..n - 1)
             (\j. sum(0..n - j - 1) (\k. a (j + k + 1) * y pow k) * x pow j)

 REAL_POLYFUN_ROOTBOUND =
  |- !n c.
         ~(!i. i IN 0..n ==> c i = &0)
         ==> FINITE {x | sum(0..n) (\i. c i * x pow i) = &0} /\
             CARD {x | sum(0..n) (\i. c i * x pow i) = &0} <= n

 REAL_POLYFUN_FINITE_ROOTS =
  |- !n c.

         FINITE {x | sum(0..n) (\i. c i * x pow i) = &0} <=>
         (?i. i IN 0..n /\ ~(c i = &0))

 REAL_POLYFUN_EQ_0 =
  |- !n c.
         (!x. sum(0..n) (\i. c i * x pow i) = &0) <=>
         (!i. i IN 0..n ==> c i = &0)

 REAL_POLYFUN_EQ_CONST =
  |- !n c k.
         (!x. sum(0..n) (\i. c i * x pow i) = k) <=>
         c 0 = k /\ (!i. i IN 1..n ==> c i = &0)

Thu  3rd Nov 2011       arith.ml

Added another somewhat intricate DIV/MOD theorem:

 MOD_MOD_EXP_MIN =
   |- !x p m n. ~(p = 0) ==> x MOD p EXP m MOD p EXP n = x MOD p EXP MIN m n

Tue  1st Nov 2011       arith.ml

Added the following, a natural counterpart to MOD_MULT_ADD:

  DIV_MULT_ADD = |- !a b n. ~(n = 0) ==> (a * n + b) DIV n = a + b DIV n

Thu 20th Oct 2011       hol.ml, class.ml, nums.ml, arith.ml, recursion.ml, pair.ml

Based on an idea discussed with Mark Adams, changed "new_specification" to
exploit dummy quantifiers and numeral tags to avoid provable equalities between
different constants introduced with new_specification based on the same (or a
provably equivalent) existence theorem. Since this requires the existence of
numerals, quite a bit of build order reshuffling was necessary, and two former
uses of new_specification (IND_SUC/IND_0 and BIT0_DEF) are now done "manually".

Fri  7th Oct 2011       Makefile

Made a fix to the Makefile from Ramana Kumar on the hol-light page (see issue
2). This uses the file  pa_j_3.1x_6.02.2.ml for version 6.03 of OCaml as well.
I just tried it with Ocaml 3.12.1 and camlp5 6.02.3, and it seems to work fine.

Mon 29th Aug 2011       calc_rat.ml

Changed REAL_RAT_DIV_CONV not to fail if it is given a canonical rational;
instead used CHANGED_CONV in the depth conversion in REAL_RAT_REDUCE_CONV. This
is consistent with the use of REAL_RAT_NEG_CONV, makes REAL_RAT_DIV_CONV a more
convenient building block, and agrees with the current documentation.

Wed 24th Aug 2011       real.ml, int.ml

Added theorems about the real and integer sign function:

  REAL_SGN_CASES =
    |- !x. real_sgn x = &0 \/ real_sgn x = &1 \/ real_sgn x = -- &1

  REAL_SGN_EQ =
    |- (!x. real_sgn x = &0 <=> x = &0) /\
       (!x. real_sgn x = &1 <=> x > &0) /\
       (!x. real_sgn x = -- &1 <=> x < &0)

with INT_SGN_CASES and INT_SGN_EQ being the same for integers.

Wed 24th Aug 2011       sets.ml

Added two natural theorems about intersections of unions

  INTERS_UNION =
   |- !s t. INTERS (s UNION t) = INTERS s INTER INTERS t

  INTERS_OVER_UNIONS =
   |- !f s.
        INTERS {UNIONS (f x) | x IN s} =
        UNIONS {INTERS {g x | x IN s} | g | !x. x IN s ==> g x IN f x}

Thu 18th Aug 2011       100/inclusion_exclusion.ml

Added versions of inclusion-exclusion for additive real functions
(INCLUSION_EXCLUSION_REAL_RESTRICTED_INDEXED,
INCLUSION_EXCLUSION_REAL_RESTRICTED, INCLUSION_EXCLUSION_REAL_INDEXED and
INCLUSION_EXCLUSION_REAL), deriving the cardinality version from those. Renamed
the old INCLUSION_EXCLUSION_REAL as INCLUSION_EXCLUSION_REAL_FUNCTION and
commented it out together with its dependency on Library/products.ml

Sun 31st Jul 2011       IsabelleLight/* [new files]

Installed "Isabelle Light" from Petros Papapanagiotou and Jacques Fleuriot,
which consists of implementations of Isabelle-style tactics and other
user-friendly shortcuts.

Sun 10th Jul 2011       100/fourier.ml [new file]

Added a file with some material on L_p spaces and Fourier series.

Tue 28th Jun 2011       pair.ml, parser.ml

Fixed a LET_TAC bug pointed out by Vu Khac Ky: failures were occurring if the
same variable was used on the left and right of a pattern (except if they are a
trivial let, i.e. corresponding lefts and rights exactly equal), e.g.

  g `v IN V DIFF (let k,ul = (P:num#(real^3)list->num#(real^3)list) (k,ul) in
     (Q:num#(real^3)list->real^3->bool) (k,ul)) ==> F`;;
  e LET_TAC;;

Now the abbreviating variables are renamed as necessary to avoid clashes with
free variables of the goal or each other (some of this would previously happen
later in the ABBREV_TAC step anyway in some cases, but not this one).

Looking at such corner cases made me add a parsing warning if there are
multiple uses of the same variable in different arms of a simultaneous let
binding, e.g. `let x = 1 and x = 2 in x = 42`, in which case the first one is
hidden.

Thu  9th Jun 2011       realarith.ml

Made a change in the variable-choosing heuristic in Fourier-Motzkin, motivated
by the disastrous slowness of this trivial example:

  time REAL_ARITH
  `c < e / &3 /\ i1 < e / &12 /\ i3 < e / &12 /\ i2 < e / &12 /\ i4 < e / &12
     ==> (i1 + i2) + (c + i3 + i4) <= &2 * e / &3`;;

The previous heuristic chose a variable that minimized the number of
inequalities after elimination, which is p * n + z where p, n and z are the
number of current inequalities where that variable occurs positively,
negatively and not at all respectively. The downside is that it doesn't take
any account of the complexity of the resulting inequalities, so in a
prototypical example like the above

 x1 < e /\ .... /\ xn < e ==> x1 + ... + xn < n * e

all variables give equal blowup of n, and so e may get chosen from among the
available alternatives. That's something of a disaster since from that point on
you get doubly exponential blowup per stage. The new heuristic is simply p * n,
counting the number of new inequalities created by the elimination step. It
makes this sort of example, which is probably pretty common, dramatically
better. It also seems to lead to a small but notable average speedup.

Mon 23rd May 2011       Library/floor.ml, Library/sets.ml

Added

  COUNTABLE_RESTRICT = |- !s P. COUNTABLE s ==> COUNTABLE {x | x IN s /\ P x}

  RATIONAL_APPROXIMATION_STRADDLE =
    |- !x e. &0 < e
             ==> ?a b. rational a /\ rational b /\
                       a < x /\ x < b /\ abs(b - a) < e

Sun 22nd May 2011       sets.ml

Added the following duality for unions and intersections:

  DIFF_INTERS = |- !u s. u DIFF INTERS s = UNIONS {u DIFF t | t IN s}

  INTERS_UNIONS = |- !s. INTERS s = UNIV DIFF (UNIONS {UNIV DIFF t | t IN s})

  UNIONS_INTERS = |- !s. UNIONS s = UNIV DIFF (INTERS {UNIV DIFF t | t IN s})

Thu 12th May 2011       Library/floor.ml

  FRAC_UNIQUE = |- !x a. integer(x - a) /\ &0 <= a /\ a < &1 <=> frac x = a

  REAL_FRAC_EQ = |- !x. frac x = x <=> &0 <= x /\ x < &1

Tue  5th Apr 2011       Library/floor.ml

  REAL_FLOOR_LE =
    |- !x n. integer n ==> (floor x <= n <=> x - &1 < n)

  HAS_SIZE_INTSEG_INT =
    |- !a b.
           integer a /\ integer b
           ==> {x | integer x /\ a <= x /\ x <= b} HAS_SIZE
               (if b < a then 0 else num_of_int(int_of_real(b - a + &1)))

  CARD_INTSEG_INT =
    |- !a b.
           integer a /\ integer b
           ==> CARD {x | integer x /\ a <= x /\ x <= b} =
               (if b < a then 0 else num_of_int(int_of_real(b - a + &1)))

  REAL_CARD_INTSEG_INT =
    |- !a b.
           integer a /\ integer b
           ==> &(CARD {x | integer x /\ a <= x /\ x <= b}) =
               (if b < a then &0 else b - a + &1)

Tue  5th Apr 2011       sets.ml

Added

  POWERSET_CLAUSES =
   |- {s | s SUBSET {}} = {{}} /\
      (!a t.
           {s | s SUBSET a INSERT t} =
           {s | s SUBSET t} UNION IMAGE (\s. a INSERT s) {s | s SUBSET t})

Fri  1st Apr 2011       Makefile, pa_j_3.1x_6.02.2.ml [new file]

Once again there is an incompatibility with the latest version of camlp5, this
time 6.02.2, as was reported by Kevin S. Van Horn. Made yet another appropriate
version of pa_j.ml, and put another case split in the Makefile.

Fri  1st Apr 2011       Minisat/minisat_parse.ml

Rewrote readTrace_aux in a slightly different style, avoiding wrapping
an exception handler round the recursive calls, since this had the effect of
making it not be tail-recursive.

Thu 31st Mar 2011       sets.ml

Added the following

  IMAGE_INJECTIVE_IMAGE_OF_SUBSET =
   |- !f s.
         ?t. t SUBSET s /\
             IMAGE f s = IMAGE f t /\
             (!x y. x IN t /\ y IN t /\ f x = f y ==> x = y)

Tue 22nd Mar 2011       sets.ml

Added the following, a natural dual of EXISTS_SUBSET_IMAGE:

  FORALL_SUBSET_IMAGE =
   |- !P f s.
          (!t. t SUBSET IMAGE f s ==> P t) <=>
          (!t. t SUBSET s ==> P (IMAGE f t))

Tue 15th Mar 2011       fusion.ml

Made a small but significant change to the kernel, based on an observation by
Ondrej Kuncar, optimizing the pointer-EQ shortcut in "orda" so that it does not
require an empty environment but merely one full of identical pairs. This can
substantially speed up many derived rules by allowing efficient use of
proformas even inside bound variables.

Sat  5th Mar 2011       bool.ml

Noticed that GEN is not constant-time, which is bad. On closer inspection the
problem was that the abstraction that's used to instantiate the proforma is
created separately from the abstracted input theorem, so the pointer-EQ
subterms are hidden under an abstraction. As well as fixing that, made it more
efficient in two other ways: used EQ_MP instead of PROVE_HYP, and added partial
evaluation based on the first argument.

Fri 25th Feb 2011       Library/poly.ml

Fixed an error where override_interface was used for "divides", hiding
all the other desired overloadings. Also added many new polynomial
theorems from Jesse Bingham's e-transcendence proof:

  HD_POLY_ADD
  HD_POLY_CMUL
  HD_POLY_EXP
  HD_POLY_EXP_X_SUC
  HD_POLY_MUL
  HD_POLY_MUL_X
  ITERATE_RADD_POLYADD
  MONOIDAL_POLY_ADD
  NOT_POLY_CMUL_NIL
  NOT_POLY_EXP_NIL
  NOT_POLY_EXP_X_NIL
  NOT_POLY_MUL_NIL
  POLYDIFF_ADD
  POLY_ADD_ASSOC
  POLY_ADD_IDENT
  POLY_ADD_LENGTH
  POLY_ADD_NEUTRAL
  POLY_ADD_SYM
  POLY_CMUL_LENGTH
  POLY_CMUL_LID
  POLY_CMUL_POLY_DIFF
  POLY_DIFF_AUX_ADD_LEMMA
  POLY_DIFF_AUX_POLY_CMUL
  POLY_EXP_X_LENGTH
  POLY_EXP_X_REC
  POLY_MUL_LENGTH
  POLY_MUL_LENGTH2
  POLY_MUL_LID
  POLY_MUL_RID
  POLY_SUM_EQUIV
  TL_POLY_CMUL
  TL_POLY_EXP_X_SUC
  TL_POLY_MUL_X

Fri 25th Feb 2011       fusion.ml, ind_defs.ml, simp.ml, define.ml, Library/analysis.ml, Library/transc.ml

Removed a few unused variables in these files, after noticing OCaml warnings
about them. It makes things minutely smaller and faster, I suppose.

Tue 22nd Feb 2011       lists.ml

Added two additional list lemmas taken from Jesse Bingham's e-transcendence
proof, which seem to be quite generally useful.

  ALL_EL = |- !P l. (!i. i < LENGTH l ==> P (EL i l)) <=> ALL P l

  CONS_HD_TL = |- !l. ~(l = []) ==> l = CONS (HD l) (TL l)

Thu 17th Feb 2011       Examples/sos.ml

Renamed a few of the ML operations on vectors since the existing names
can lead to annoying name clashes with the names of theorems in the
Multivariate/vectors.ml theories.

 vector_0       -> vec_0
 dim            -> vec_dim
 vector_const   -> vec_const
 vector_1       -> vec_1
 vector_cmul    -> vec_cmul
 vector_neg     -> vec_neg
 vector_add     -> vec_add
 vector_sub     -> vec_sub
 vector_dot     -> vec_dot
 vector_of_list -> vec_of_list

Of course, it is arguable that all this should be hidden anyway, but
since this file is still somewhat experimental I don't want to tidy up
and modularize the namespace just yet.

Mon 14th Feb 2011       int.ml, Library/floor.ml

Removed the constant "is_int" and replaced it with "integer", moving the
definition of that back from the "Library/floor.ml" file to the "int.ml"
file. Kept the theorem "is_int" for compatibility, with just the different
constant, and removed the now redundant/meaningless INTEGER_IS_INT.

Tue  8th Feb 2011       Makefile, pa_j_3.1x_6.02.1.ml [new file]

Added (directly from Ondrej Kuncar) an updated version of pa_j for the latest
sub-version of camlp5, and modified the Makefile to use it as needed (though
this selection logic is starting to get ugly).

Tue 21st Dec 2010       real.ml, database.ml

Added a lemma from Valentina Bruno used in the Multivariate complex analysis
theories, plus other variants.

  REAL_LT_LINV  = |- !x y. &0 < y /\ inv y < x ==> inv x < y
  REAL_LT_RINV  = |- !x y. &0 < x /\ x < inv y ==> y < inv x
  REAL_LE_LINV  = |- !x y. &0 < y /\ inv y <= x ==> inv x <= y
  REAL_LE_RINV  = |- !x y. &0 < x /\ x <= inv y ==> y <= inv x

Wed 15th Dec 2010       system.ml

At the suggestion of Ondrej Kuncar, switched from

  fun set_jrh_lexer -> set_jrh_lexer;;

to just

  set_jrh_lexer;;

This magic variable gets mapped to a constant anyway, so there is no need for
this elaborate expression, which moreover generates a warning about
a non-exhaustive match.

Mon 13th Dec 2010       sets.ml

Added SET_PAIR_THM = |- !P. {p | P p} = {a,b | P (a,b)}

Thu  2nd Dec 2010       Makefile, Proofrecording/hol_light/Makefile, pa_j_3.1x_5.xx.ml [new file], pa_j_3.1x_6.xx.ml [new file], pa_j_3.10.ml [deleted], pa_j_3.11.ml [deleted]

Ondrej Kuncar pointed out that the system doesn't build with the new camlp5
6.0. So now for OCaml >= 3.10 I need to start distinguishing only based on
the camlp5 version. Modified the Makefile accordingly, making the two current
versions for < 6.0 and >= 6.0 of camlp5 called pa_j_3.1x_5.xx.ml (what used
to be pa_j_3.10.ml and pa_j_3.11.ml) and pa_j_3.1x_6.xx.ml (a new one derived
by modifying the source to camlp5 6.02.0).

Thu 18th Nov 2010       real.ml

Finally added the theorem REAL_LE_POW_2 = |- !x. &0 <= x pow 2.
Even though REAL_LE_SQUARE is close, it's nice not to have to make
trivial rewrites back and forth just to use it.

Thu 28th Oct 2010       Library/rstc.ml

Noticed that the theorems RTC_INDUCT_L and RTC_INDUCT_R both had the hypothesis
(!x y. R x y ==> P x y), which is redundant since it follows from the other
two. So I just removed it; as far as I can see there are no proof changes
needed.

Thu 28th Oct 2010       arith.ml, passim

Joe Hurd pointed out that EQ_SUC proved in arith.ml was just a duplicate of the
theorem SUC_INJ from nums.ml, so I removed its proof and replaced EQ_SUC by
SUC_INJ everywhere it was used.

Fri  8th Oct 2010       README

Updated the README file with a few modernizations, in particular a more careful
discussion of checkpointing options in the light of the fact that it seems hard
to get ckpt working on recent Linuxes.

Fri  8th Oct 2010       theorems.ml

Joe Hurd pointed out that EQ_REFL_T is a duplicate of REFL_CLAUSE, so I removed
EQ_REFL_T.

Fri  8th Oct 2010       Makefile, hol.ml

There was a problem pointed out by Anthony V. Pulido with OCaml 3.12 because
a couple of tests had equality tests for 3.10 or 3.11. Replaced this with a
simple test of the first digit after the decimal point of the OCaml version in
the Makefile and a string inequality comparison in "hol.ml".

Wed  9th Jun 2010       nums.ml, arith.ml

Made some changes suggested by Joe Hurd to allow cleaner separation into
theories by avoiding the use of addition when defining the numeral constants
BIT0 and BIT1. Now those are defined directly using primitive recursion
(BIT0_DEF and BIT1_DEF) and the former definitions BIT0 and BIT1 are derived
from those later.

Wed 24th Mar 2010       nums.ml, 100/four_squares.ml, 100/ramsey.ml, Complex/complexnumbers.ml, Examples/mccarthy.ml, Examples/multiwf.ml, Mizarlight/duality_holby.ml, Model/modelset.ml, Multivariate/clifford.ml, Multivariate/topology.ml, Rqe/asym.ml, Rqe/examples.ml, Rqe/rol.ml

Made changes essentially corresponding to the steps of hol-online's
"hol-preparse-patch", fixing some bugs, removing redundant material
and regularizing some syntax:

      * Replaced a = by <=> in "100/four_squares.ml" (I'd left this
        out of my test suite, which is why it hadn't been spotted
        before).

      * Added a couple of missing real numeral coercions "&" in
        "Rqe/examples.ml".

      * Removed duplicate definition for degree in "Rqe/asym.ml"
        (it's already defined in "Library/poly.ml").

      * Removed terms with antiquotation, an unused relic from HOL88
        in "100/ramsey.ml".

      * Avoided programmatically created terms in
        "Examples/mccarthy.ml", "Mizarlight/duality_holby.ml" and
        "Rqe/rol.ml".

      * Added IND_SUC_SPEC to regularize new_specification syntax in
        "nums.ml"

      * Stylistic change to type definition in
        "Complex/complexnumbers.ml", "Examples/multiwf.ml",
        "Mizarlight/duality_holby.ml", "Model/modelset.ml",
        "Multivariate/clifford.ml", "Multivariate/topology.ml".

Tue 23rd Mar 2010       lists.ml

Added several miscellaneous lemmas about lists:

  LENGTH_TL =
   |- !l. ~(l = []) ==> LENGTH (TL l) = LENGTH l - 1

  EL_APPEND =
   |- !k l m.
         EL k (APPEND l m) =
         (if k < LENGTH l then EL k l else EL (k - LENGTH l) m)

  EL_TL =
   |- !n. EL n (TL l) = EL (n + 1) l

  EL_CONS =
   |- !n h t. EL n (CONS h t) = (if n = 0 then h else EL (n - 1) t)

  LAST_EL =
   |- !l. ~(l = []) ==> LAST l = EL (LENGTH l - 1) l

  HD_APPEND =
   |- !l m. HD (APPEND l m) = (if l = [] then HD m else HD l)

Tue 23rd Mar 2010       sets.ml

Added SET_OF_LIST_EQ_EMPTY = |- !l. set_of_list l = {} <=> l = []

Mon 22nd Mar 2010       lists.ml

Added one more simple list lemma:

  LAST_APPEND =
    |- !p q. LAST(APPEND p q) = (if q = [] then LAST p else LAST q)

Sat 20th Mar 2010       lists.ml, Rqe/work_thms.ml

Moved the definition of BUTLAST from Rqe into the core, and added one trivial
theorem about it:

  BUTLAST =
    |- BUTLAST [] = [] /\
       BUTLAST (CONS h t) = (if t = [] then [] else CONS h (BUTLAST t))

  APPEND_BUTLAST_LAST =
    |- !l. ~(l = []) ==> APPEND (BUTLAST l) [LAST l] = l

Fri 12th Mar 2010       sets.ml

Added

  CHOOSE_SUBSET_STRONG =
    |- !n s. (FINITE s ==> n <= CARD s) ==> (?t. t SUBSET s /\ t HAS_SIZE n)

Thu 11th Mar 2010       ints.ml

Made a further small stylistic change following hol-online to make the integer
type bijection at the top level instead of hiding it. This introduces a new
theorem int_tybij.

Tue  9th Mar 2010       lists.ml

Added a couple of trivial lemmas about MAP:

  MAP_ID = |- !l. MAP (\x. x) l = l

  MAP_I = |- MAP I = I

Mon  8th Mar 2010       bool.ml, ind_types.ml, cart.ml, int.ml, realax.ml

Made minor stylistic changes following hol-online. These essentially make it
easier to recognize parsing directives and definitions.

Mon  8th Mar 2010       Proofrecording/diffs/basics.ml [new file]

Chantal Keller pointed out that the "needs" directive is wrong in the
proof-recording version where separate type, term and theorem files are used in
place of fusion. Fixed this by putting the version of basics.ml without the
"needs" line in the diffs directory.

Sun  7th Mar 2010       passim

Moved more hol-online changes upstream, adding explicit "needs" directives to
the core files in the toplevel directory. Also modified the
"make_database_assignment" function in "update_database.ml" so that it adds
such a directive at the top of any file it creates.

Sat  6th Mar 2010       Examples/vitali.ml [new file]

Added a simple example, the existence of a non-measurable set. Since it doesn't
seem likely to be useful for anything, I didn't put it in the Multivariate
measure theory itself.

Tue  2nd Mar 2010       class.ml

Jeremy Bem had pointed out that TAUT has an implicit dependency on the current
default rewrites because of the embedded REWRITE_TAC[]. This can make it do
more than it should if the rewrites are expanded, or stop working if they are
contracted. Fixed this by partially evaluating the REWRITE_TAC[] in the
definition, though this means defining it twice in class.ml, once as a sort of
bootstrapping version without the COND rewrites, and one after.

Mon  1st Mar 2010       update_database.ml

Added alphabetic sorting of the results to the "search" function. Note that the
reference variable "theorems" itself is not sorted, but sorting is imposed
afterwards on the filtered results (likewise in "make_database_assignment").

Thu 25th Feb 2010       real.ml, int.ml

Added the definitions of the real and integer signum function. I was
tempted to add the interface "sgn" for both of them, but perhaps one
doesn't want to be deprived of that as a variable name. New theorems
(and of course INT_OF_REAL_THM is updated):

  real_sgn
  REAL_ABS_SGN
  REAL_SGN
  REAL_SGN_0
  REAL_SGN_ABS
  REAL_SGN_DIV
  REAL_SGN_INV
  REAL_SGN_MUL
  REAL_SGN_NEG

  int_sgn
  int_sgn_th
  INT_ABS_SGN
  INT_SGN
  INT_SGN_0
  INT_SGN_ABS
  INT_SGN_MUL
  INT_SGN_NEG

Thu 25th Feb 2010       Examples/sos.ml

Replaced a couple of explicit uses of the Empty constructor for finite partial
functions by "undefined" and "is_undefined". This was causing a clash with the
Empty constructor for the tbl type in the new update_database.ml, and avoiding
the constructors is good practice anyway (maybe I should make it an abstract
type).

Wed 24th Feb 2010       basics.ml

Tweaked "subst" to filter out trivial substitutions from the instantiation list
first. This is a small thing but was actually ultimately responsible for some
extreme slowness of UNWIND_CONV on very large terms owing to the underlying
REWR_CONV SWAP_EXISTS_THM. For example defining the following

  let test n =
    let t = `m < n + 1` in
    let tm = funpow n (fun x -> mk_conj(x,t)) t in
    let et = list_mk_exists([`m:num`;`n:num`],tm) in
    time (REWR_CONV SWAP_EXISTS_THM) et; 1;;

then "test 100000" used to take 9.5 seconds, and now takes 0.5. There are still
some wasteful things going, so it might be worth explicitly optimizing
UNWIND_CONV, but this is much better than before and might have beneficial
effects elsewhere too.

Fri 19th Feb 2010       update_database.ml, Examples/update_database.ml [new file]

Moved the old update_database.ml script back into Examples and installed
instead the somewhat nicer one from Roland Zumkeller, which doesn't rely on the
OCaml sources.

Fri 19th Feb 2010       sets.ml

Added some theorems showing that surjectivity is exactly equivalent to
inserting the function in universal and existential quantifiers and gives rise
to a related property for set comprehensions:

  SURJECTIVE_FORALL_THM =
    |- !f. (!y. ?x. f x = y) <=> (!P. (!x. P (f x)) <=> (!y. P y))

  SURJECTIVE_EXISTS_THM =
    |- !f. (!y. ?x. f x = y) <=> (!P. (?x. P (f x)) <=> (?y. P y))

  SURJECTIVE_IMAGE_THM =
    |- !f. (!y. ?x. f x = y) <=> (!P. IMAGE f {x | P (f x)} = {x | P x})

Fri 19th Feb 2010       lists.ml

Added one trivial lemma and a couple of theorems showing that injectivity and
surjectivity are preserved by the MAP construct:

  MAP_EQ_NIL = |- !f l. MAP f l = [] <=> l = []

  INJECTIVE_MAP =
    |- !f. (!l m. MAP f l = MAP f m ==> l = m) <=> (!x y. f x = f y ==> x = y)

  SURJECTIVE_MAP =
    |- !f. (!m. ?l. MAP f l = m) <=> (!y. ?x. f x = y)

Tue 16th Feb 2010       Proofrecording/README Proofrecording/diffs/equal.ml, Proofrecording/diffs/hol.ml, Proofrecording/diffs/proofobjects_dummy.ml, Proofrecording/diffs/proofobjects_init.ml,  Proofrecording/diffs/proofobjects_trt.ml, Proofrecording/hol_light/Makefile, Proofrecording/diffs/depgraph.ml [new file],  Proofrecording/diffs/proofobjects_coq.ml [new file]

Installed several updates from Chantal Keller to the proof-recording
infrastructure, slightly tweaked and merged with my latest updates. This fixes
a few incompatibilities and also extends the proof-recording infrastructure to
produce Coq proofs (set HOLPROOFOBJECTS=COQ). The new code uses the ocamlgraph
library, so there is a new entry "top" in the Makefile to make it.

********************** FIRST GOOGLE CODE VERSION **********************

Fri 12th Feb 2010       passim

Moved many of the files from Examples into a new Library directory, and changed
the names of various others, to support easier native-code compilation. Most of
these changes are again modelled on Jeremy Bem's hol1process.sh file, though a
few of the new names are different. The basic idea is to make the names of
files distinct from each other and give rise to valid module names that are
distinct from built-in OCaml modules, while moreover avoiding directory
dependencies (e.g. between files in Examples and Multivariate). Here's a
complete list of the changes:

  ind-defs.ml -> ind_defs.ml
  ind-types.ml -> ind_types.ml
  iter.ml -> iterate.ml
  list.ml -> lists.ml
  num.ml -> nums.ml
  sys.ml -> system.ml
  100/2squares.ml -> 100/two_squares.ml
  100/4squares.ml -> 100/four_squares.ml
  100/agm.ml -> 100/arithmetic_geometric_mean.ml
  Complex/complex.ml -> Complex/complexnumbers.ml
  Complex/grobner.ml -> Complex/complex_grobner.ml
  Complex/real.ml -> Complex/complex_real.ml
  Complex/transc.ml -> Complex/complex_transc.ml
  Examples/agm.ml -> Library/agm.ml
  Examples/analysis.ml -> Library/analysis.ml
  Examples/binary.ml -> Library/binary.ml
  Examples/binomial.ml -> Library/binomial.ml
  Examples/calc_real.ml -> Library/calc_real.ml
  Examples/card.ml -> Library/card.ml
  Examples/floor.ml -> Library/floor.ml
  Examples/integer.ml -> Library/integer.ml
  Examples/isum.ml -> Library/isum.ml
  Examples/iter.ml -> Library/iter.ml
  Examples/lagrange.ml -> Examples/lagrange_lemma.ml
  Examples/multiplicative.ml -> Library/multiplicative.ml
  Examples/permutations.ml -> Library/permutations.ml
  Examples/pocklington.ml -> Library/pocklington.ml
  Examples/poly.ml -> Library/poly.ml
  Examples/pratt.ml -> Library/pratt.ml
  Examples/prime.ml -> Library/prime.ml
  Examples/primitive.ml -> Library/primitive.ml
  Examples/products.ml -> Library/products.ml
  Examples/rstc.ml -> Library/rstc.ml
  Examples/transc.ml -> Library/transc.ml
  Examples/update_database.ml -> update_database.ml
  Examples/wo.ml -> Library/wo.ml
  Jordan/num_calc_simp.ml -> Rqe/num_calc_simp.ml
  Minisat/SatSolvers.ml -> Minisat/sat_solvers.ml
  Minisat/dimacsTools.ml -> Minisat/dimacs_tools.ml
  Minisat/minisatParse.ml -> Minisat/minisat_parse.ml
  Minisat/minisatProve.ml -> Minisat/minisat_prove.ml
  Minisat/minisatResolve.ml -> Minisat/minisat_resolve.ml
  Minisat/satCommonTools.ml -> Minisat/sat_common_tools.ml
  Minisat/satScript.ml -> Minisat/sat_script.ml
  Minisat/satTools.ml -> Minisat/sat_tools.ml
  Model/set.ml -> Model/modelset.ml
  Multivariate/analysis.ml -> Multivariate/derivatives.ml
  Multivariate/complex.ml -> Multivariate/complexes.ml
  Multivariate/real.ml -> Multivariate/realanalysis.ml
  Multivariate/transc.ml -> Multivariate/transcendentals.ml
  Rqe/lib.ml -> Rqe/rqe_lib.ml
  Rqe/list.ml -> Rqe/rqe_list.ml
  Rqe/main.ml -> Rqe/rqe_main.ml
  Rqe/num.ml -> Rqe/rqe_num.ml
  Rqe/real.ml -> Rqe/rqe_real.ml
  Rqe/tactics-ext.ml -> Rqe/rqe_tactics_ext.ml

Fri 12th Feb 2010       Examples/sos.ml, Minisat/minisatParse.ml, Rqe/main.ml, Rqe/matinsert.ml, Unity/mk_unless.ml

Made some small changes based on the hol1process.sh file in Jeremy Bem's
hol-online, mainly connected with eliminating unused state or dead code. Also
removed the following files that are not runnable as they stand and were
probably not intended to be in the final version:

  Complex/maple.ml
  Complex/geom.ml
  Boyer_Moore/induct_then.ml
  Boyer_Moore/testset/eval.ml

Mon 25th Jan 2010       sets.ml

Added the following, which is really just plugging two existing results
together, but in a way that's not completely trivial for the built-in
automation:

  HAS_SIZE_IMAGE_INJ_EQ =
    |- !f s n.
           (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
           ==> (IMAGE f s HAS_SIZE n <=> s HAS_SIZE n)

Tue 12th Jan 2010       sets.ml

Added some trivial but useful theorems about infiniteness of various real
intervals.

  FINITE_REAL_INTERVAL =
    |- (!a. ~FINITE {x | a < x}) /\
       (!a. ~FINITE {x | a <= x}) /\
       (!b. ~FINITE {x | x < b}) /\
       (!b. ~FINITE {x | x <= b}) /\
       (!a b. FINITE {x | a < x /\ x < b} <=> b <= a) /\
       (!a b. FINITE {x | a <= x /\ x < b} <=> b <= a) /\
       (!a b. FINITE {x | a < x /\ x <= b} <=> b <= a) /\
       (!a b. FINITE {x | a <= x /\ x <= b} <=> b <= a)

as well as the trivial consequence

  real_INFINITE = |- INFINITE(:real)

Fri  8th Jan 2010       pair.ml

When rerunning some files I noticed a subtle issue in the benignity checking of
definitions: when recreating the desired definition from the old one, it is
only quantified over the explicitly quantified variables in the input term.
Changed this to finally generalize afterwards over all the (remaining) free
variables, which makes it completely identical with the theorem returned by the
original invocation of the same definition.

Fri  8th Jan 2010       sets.ml, passim

Modified SET_TAC so that it throws away the assumption list. Until recently I
had been under the impression that this was the actual behaviour, and was using
ASM SET_TAC explicitly when I wanted the assumptions included. Needless to say,
there were a few places where I'd relied on the old behaviour, so I changed
SET_TAC to ASM SET_TAC in those places.

Fri  8th Jan 2010       parser.ml

Added an additional clause to the toplevel function "parse_preterm" so that it
accepts an identifier (i.e. anything except a reserved word) as the entire
string to be parsed. This was mainly intended as a convenience for the search
function, so that one can do, say

        search [`UNION`];;

instead of the slightly longer-to-type

        search [`(UNION)`];;

Mon 28th Dec 2009       sets.ml

Added a few theorems about injectivity and surjectivity of the image under a
map:

  INJECTIVE_ON_IMAGE =
    |- !f u.
         (!s t. s SUBSET u /\ t SUBSET u /\ IMAGE f s = IMAGE f t ==> s = t) <=>
         (!x y. x IN u /\ y IN u /\ f x = f y ==> x = y)

  INJECTIVE_IMAGE =
    |- !f. (!s t. IMAGE f s = IMAGE f t ==> s = t) <=>
           (!x y. f x = f y ==> x = y)

  SURJECTIVE_ON_IMAGE =
    |- !f u v.
           (!t. t SUBSET v ==> (?s. s SUBSET u /\ IMAGE f s = t)) <=>
           (!y. y IN v ==> (?x. x IN u /\ f x = y))

  SURJECTIVE_IMAGE =
    |- !f. (!t. ?s. IMAGE f s = t) <=> (!y. ?x. f x = y)

Sun 27th Dec 2009       sets.ml

Added FINITE_HAS_SIZE = |- !s. FINITE s <=> s HAS_SIZE CARD s

and generalized the theorem FINITE_PRODUCT_DEPENDENT from pairs to the
application of any function:

  FINITE_PRODUCT_DEPENDENT =
    |- !f s t.
         FINITE s /\ (!x. x IN s ==> FINITE(t x))
         ==> FINITE {f x y | x IN s /\ y IN t x}

Fri 20th Nov 2009       sets.ml

Noticed that FINITE_UNIONS could be stronger (funny that I only just noticed
this). Changed the name of the former FINITE_UNIONS to FINITE_FINITE_UNIONS and
made FINITE_UNIONS the stronger theorem. I hope that most proofs will not break
after this change because it's usually used with SIMP_TAC.

  FINITE_FINITE_UNIONS =
   |- !s. FINITE s ==> (FINITE(UNIONS s) <=> (!t. t IN s ==> FINITE t))

  FINITE_UNIONS =
   |- !s. FINITE(UNIONS s) <=> FINITE s /\ (!t. t IN s ==> FINITE t)

Fri 20th Nov 2009       Examples/floor.ml

Added RATIONAL_ALT for use in some places where I'd used that as an adhoc
definition (100/constructible.ml and 100/liouville.ml).

  RATIONAL_ALT =
    |- !x. rational x <=> (?p q. ~(q = 0) /\ abs x = &p / &q)

Tue 17th Nov 2009       Examples/floor.ml

Added a definition of "rational" and closure theorems, corresponding as
appropriate to those for "integer".

Mon 16th Nov 2009       real.ml

Added a suite of theorems to complement REAL_POW_LE2_ODD (which is still there
but with a simpler proof, the complicated one now reserved for
REAL_POW_LT2_ODD).

  REAL_POW_LT2_ODD =
    |- !n x y. x < y /\ ODD n ==> x pow n < y pow n

  REAL_POW_LT2_ODD_EQ =
    |- !n x y. ODD n ==> (x pow n < y pow n <=> x < y)

  REAL_POW_LE2_ODD_EQ =
    |- !n x y. ODD n ==> (x pow n <= y pow n <=> x <= y)

  REAL_POW_EQ_ODD_EQ =
    |- !n x y. ODD n ==> (x pow n = y pow n <=> x = y)

  REAL_POW_EQ_ODD =
    |- !n x y. ODD n /\ x pow n = y pow n ==> x = y

  REAL_POW_EQ_EQ =
  |- !n x y.
         x pow n = y pow n <=>
         (if EVEN n then n = 0 \/ abs x = abs y else x = y)

Wed 11th Nov 2009       sets.ml

Added PAIRWISE_MONO = |- !r s t. pairwise r s /\ t SUBSET s ==> pairwise r t

Tue  3rd Nov 2009       Proofrecording/diffs/thm.ml

Added a new version of thm.ml from Chantal Keller, which makes things basically
compatible with the new core, though it's still implemented via separate
type.ml, term.ml and thm.ml files instead of a single fusion.ml; at some point
I should go through and make it all perfectly compatible.

Wed 21st Oct 2009       Examples/primitive.ml [new file]

Added a file giving the usual existence results for primitive roots.

Mon 19th Oct 2009       theorems.ml

Added universally quantified versions of unwinding theorems, since I often seem
to use these and have to laboriously use SIMP_TAC[] then LEFT_FORALL_IMP_THM
and EXISTS_REFL.

  FORALL_UNWIND_THM1 = |- !P a. (!x. a = x ==> P x) <=> P a

  FORALL_UNWIND_THM2 = |- !P a. (!x. x = a ==> P x) <=> P a

Wed 14th Oct 2009       Examples/integer.ml

Added a couple of theorems to help transfer solutions of congruences back to
the natural numbers:

  INT_LINEAR_CONG_POS =
    |- !n a x. ~(n = &0) ==> (?y. &0 <= y /\ (a * x == a * y) (mod n))

  INT_CONG_SOLVE_POS =
    |- !a b n.
           coprime(a,n) /\ ~(n = &0 /\ abs a = &1)
           ==> (?x. &0 <= x /\ (a * x == b) (mod n))

Tue 13th Oct 2009       int.ml

Added outer quantifiers to these two theorems:

  INT_FORALL_POS = |- !P. (!n. P(&n)) <=> (!i. &0 <= i ==> P i)

  INT_EXISTS_POS = |- !P. (?n. P(&n)) <=> (?i. &0 <= i /\ P i)

and added the following two analogous ones:

  INT_FORALL_ABS = |- !P. (!n. P(&n)) <=> (!x. P (abs x))

  INT_EXISTS_ABS = |- !P. (?n. P(&n)) <=> (?x. P (abs x))

Tue 13th Oct 2009       Examples/pratt.ml, Examples/pocklington.ml

Renamed PHI_PRIME to PHI_PRIME_EQ

  PHI_PRIME_EQ =
   |- !n. phi n = n - 1 /\ ~(n = 0) /\ ~(n = 1) <=> prime n

and made PHI_PRIME the following:

  PHI_PRIME =
   |- !p. prime p ==> phi p = p - 1

Tue 13th Oct 2009       sets.ml

Added the following, which is a bit more convenient than manually chaining two
lemmas:

  CARD_SUBSET_IMAGE =
    |- !f s t. FINITE t /\ s SUBSET IMAGE f t ==> CARD s <= CARD t

Tue 13th Oct 2009       Examples/update_database.ml

Propagated an earlier fix from the "search" implementation in "help.ml", to
ignore pure variables in patterns.

Mon 12th Oct 2009       iter.ml

Added the following about finiteness of integer segments; although
trivial-looking it's actually quite a bit of work to derive from scratch:

FINITE_INTSEG =
  |- (!l r. FINITE {x:int | l <= x /\ x <= r}) /\
     (!l r. FINITE {x:int | l <= x /\ x < r}) /\
     (!l r. FINITE {x:int | l < x /\ x <= r}) /\
     (!l r. FINITE {x:int | l < x /\ x < r})

Thu 27th Aug 2009       sets.ml

Added two more lemmas about subsets of images:

EXISTS_SUBSET_IMAGE =
  |- !P f s.
         (?t. t SUBSET IMAGE f s /\ P t) <=>
         (?t. t SUBSET s /\ P (IMAGE f t))

EXISTS_FINITE_SUBSET_IMAGE =
  |- !P f s.
         (?t. FINITE t /\ t SUBSET IMAGE f s /\ P t) <=>
         (?t. FINITE t /\ t SUBSET s /\ P (IMAGE f t))

Sun 23rd Aug 2009       sets.ml

Added CROSS_EQ_EMPTY = |- !s t. s CROSS t = {} <=> s = {} \/ t = {}

Sat 22nd Aug 2009       iter.ml

Added two general number-segment theorems for the general "iterate":

  ITERATE_CLAUSES_NUMSEG =
    |- !op. monoidal op
            ==> (!m. iterate op (m..0) f =
                     (if m = 0 then f 0 else neutral op)) /\
                (!m n.
                     iterate op (m..SUC n) f =
                     (if m <= SUC n
                      then op (iterate op (m..n) f) (f (SUC n))
                      else iterate op (m..n) f))

  ITERATE_PAIR =
    |- !op. monoidal op
            ==> (!f m n.
                     iterate op (2 * m..2 * n + 1) f =
                     iterate op (m..n) (\i. op (f (2 * i)) (f (2 * i + 1))))

and two instances of the latter:

  NSUM_PAIR =
    |- !f m n.
         nsum (2 * m..2 * n + 1) f =
         nsum (m..n) (\i. f (2 * i) + f (2 * i + 1))

  SUM_PAIR =
    |- !f m n.
         sum (2 * m..2 * n + 1) f =
         sum (m..n) (\i. f (2 * i) + f (2 * i + 1))

Fri 21st Aug 2009       sets.ml

Added the following for dealing with unions and intersections of images
(explicit or implicit), which can otherwise be a bit tedious:

 UNIONS_IMAGE =
  |- !f s. UNIONS (IMAGE f s) = {y | ?x. x IN s /\ y IN f x}

 INTERS_IMAGE =
  |- !f s. INTERS (IMAGE f s) = {y | !x. x IN s ==> y IN f x}

 UNIONS_GSPEC =
  |- (!P f. UNIONS {f x | P x} = {a | ?x. P x /\ a IN f x}) /\
     (!P f. UNIONS {f x y | P x y} = {a | ?x y. P x y /\ a IN f x y}) /\
     (!P f. UNIONS {f x y z | P x y z} = {a | ?x y z. P x y z /\ a IN f x y z})

 INTERS_GSPEC =
  |- (!P f. INTERS {f x | P x} = {a | !x. P x ==> a IN f x}) /\
     (!P f. INTERS {f x y | P x y} = {a | !x y. P x y ==> a IN f x y}) /\
     (!P f. INTERS {f x y z | P x y z} = {a | !x y z. P x y z ==> a IN f x y z})

Tue 18th Aug 2009       sets.ml

Removed the theorem FINITE_SUBSETS, which is just a duplicate of
FINITE_POWERSET.

Mon 17th Aug 2009       sets.ml

Added the following, which is somewhat trivial but quite laborious to derive:

  SET_PROVE_CASES =
    |- !P. P {} /\ (!a s. ~(a IN s) ==> P (a INSERT s)) ==> (!s. P s)

Mon 10th Aug 2009       basics.ml

Norbert Voelker pointed out that list_mk_icomb can give unexpected "capture" of
type variables because of the iterative implementation instantiating part at a
time using mk_icomb. For example

  list_mk_icomb "," [`b:B`;`c:C`];;

formerly gave `(b:C,c:C)`. I changed to a different implementation that
computes the type instantiation once and for all.

Sat  8th Aug 2009       iter.ml

Got rid of ITERATE_CLOSED_GEN and made simple ITERATE_CLOSED still stronger
without any finiteness hypothesis:

  ITERATE_CLOSED =
    |- !op. monoidal op
            ==> (!P. P(neutral op) /\ (!x y. P x /\ P y ==> P(op x y))
                     ==> (!f s.
                              (!x. x IN s /\ ~(f x = neutral op) ==> P(f x))
                              ==> P(iterate op s f)))

Also added two special cases:

  NSUM_CLOSED =
    |- !P f s.
           P 0 /\ (!x y. P x /\ P y ==> P(x + y)) /\ (!a. a IN s ==> P(f a))
           ==> P(nsum s f)

  SUM_CLOSED =
    |- !P f s.
           P(&0) /\
           (!x y. P x /\ P y ==> P(x + y)) /\
           (!a. a IN s ==> P(f a))
           ==> P(sum s f)

Sun 26th Jul 2009       class.ml

Shortened the proof of EXCLUDED_MIDDLE using a method shown to me by Mark
Adams, which uses a smaller and simpler select-term in the main step.

Thu 23rd Jul 2009       hol.ml

Roland Zumkeller pointed out to me that "fusion.ml" is loaded by #use, whereas
it should be loads to be consistent with the others and make it work even when
not in the current directory.

Tue 21st Jul 2009       iter.ml

Removed the unnecessary finiteness hypotheses from

NSUM_RESTRICT_SET =
  |- !P s f. nsum {x | x IN s /\ P x} f = nsum s (\x. if P x then f x else 0)

SUM_RESTRICT_SET =
  |- !P s f. sum {x | x IN s /\ P x} f = sum s (\x. if P x then f x else &0)

Tue 21st Jul 2009       iter.ml

Added another useful lemma for computing slightly tweaked sums:

SUM_CASES_1 =
  |- !s a.
         FINITE s /\ a IN s
         ==> sum s (\x. if x = a then y else f x) = sum s f + y - f a

Mon 20th Jul 2009       iter.ml

Added the following; even though it's rarely needed the derivation is
surprisingly painful:

  ITERATE_OP_GEN =
    |- !op. monoidal op
            ==> (!f g s.
                     FINITE(support op f s) /\ FINITE(support op g s)
                     ==> iterate op s (\x. op (f x) (g x)) =
                         op (iterate op s f) (iterate op s g))

and then the two usual instances:

  NSUM_ADD_GEN =
    |- !f g s.
           FINITE {x | x IN s /\ ~(f x = 0)} /\
           FINITE {x | x IN s /\ ~(g x = 0)}
           ==> nsum s (\x. f x + g x) = nsum s f + nsum s g

  SUM_ADD_GEN =
    |- !f g s.
         FINITE {x | x IN s /\ ~(f x = &0)} /\
         FINITE {x | x IN s /\ ~(g x = &0)}
         ==> sum s (\x. f x + g x) = sum s f + sum s g

Wed  8th Jul 2009       ind-defs.ml

Added derive_strong_induction, which is pretty much the same thing as the
function of that name in Tom Melham's original inductive definitions package.
In fact, this was about the only significant respect in which my package was
not a generalization of it. This was inspired by Sean McLaughlin's observation
that the Coq inductive definitions package gives you this automatically, and it
can be quite useful.

Tue  7th Jul 2009       class.ml

Freek and Cezary pointed out that I have duplicates of the two basic_rewrites
|- ~T <=> F and |- ~F <=> T, because I add NOT_CLAUSES_WEAK and then later
NOT_CLAUSES. Changed the latter to CONJUNCT1 NOT_CLAUSES.

Mon  6th Jul 2009       pair.ml

Added the following, for constructs that are otherwise painful:

 FORALL_PAIRED_THM = |- !P. (!(x,y). P x y) <=> (!x y. P x y)

 EXISTS_PAIRED_THM = |- !P. (?(x,y). P x y) <=> (?x y. P x y)

 FORALL_TRIPLED_THM = |- !P. (!(x,y,z). P x y z) <=> (!x y z. P x y z)

 EXISTS_TRIPLED_THM = |- !P. (?(x,y,z). P x y z) <=> (?x y z. P x y z)

Also added outer quantifiers to FORALL_PAIR_THM, EXISTS_PAIR_THM and
LAMBDA_PAIR_THM, also changing the variable from P to t in the last.

Tue 30th Jun 2009       tactics.ml

Dan Synek pointed out some issues over using REPEAT_GTCL on IMP_RES_THEN. I
decided that things like this would work properly if IMP_RES_THEN checked its
list of derived tactics to make sure it's nonempty, so that it will actually
fail in such cases instead of running an empty tactic. So I made this change in
ANTE_RES_THEN and IMP_RES_THEN.

Tue 30th Jun 2009       hol.ml

Sean McLaughlin pointed out that relocation of hol_dir also spoils the list of
loaded files in "loaded_files", which uses absolute paths. I changed this so
that the filenames just have the "basename", and it seems to work well.

Sat 27th Jun 2009       make.ml

Changed "checkpoint" to use the "-l" option to CryoPID, since it does seem to
give at least some measure of portability in the resulting binaries, though
problems over exceptions and general unpredictability remain.

Sat 27th Jun 2009       hol.ml, help.ml

Sean McLaughlin pointed out that the "help" function doesn't adjust dynamically
to the change of !hol_dir, so I changed it to redo more stuff dynamically per
argument. It also seemed worth making help_path an assignable reference
variable so people can add more help entries (maybe indeed I should do this for
some non-core extensions). I was now also dissatisfied that load_path needs
changing separately. So I set up a scheme where a new function
"hol_expand_directory" is applied dynamically to help_path and load_path,
inside "help" and "file_on_path" (hence derivatives like "loadt"). It maps an
initial $ into !hol_dir.

Tue 16th Jun 2009       100/lagrange.ml [new file]

Freek was asking me about Lagrange's theorem, and I realized I don't have it in
the standard system anywhere (this and a few others oddments were in
Work/group.ml). So I put it here.

Tue 16th Jun 2009       help.ml

Sean McLaughlin pointed out that the use of "cat" in the help system won't work
on Windows unless you are inside Cygwin. It wasn't really needed anyway to
do "cat file | sed -f script": I replaced it by "sed -f script file".

Mon  1st Jun 2009       Examples/multiwf.ml

Renamed two theorems here that now overwrite other theorems in the main
system: FINITE_EMPTY->EMPTY_IS_FINITE and
FINITE_SING->SING_IS_FINITE.

Tue 26th May 2009       Ntrie/ntrie.ml, Ntrie/ntrie_tests.ml [new files]

Added a nice new library by Clelia Lomuto and Marco Maggesi that performs
efficient set operations on sets of natural numbers using a trie representation
internally.

Mon 25th May 2009       Complex/cpoly.ml, Complex/fundamental.ml

Added more "needs" directives to these files so that you can load more things
individually without special measures. This was inspired by a bug report from
Loic Pottier who tried to load Complex/grobner.ml directly.

Mon 25th May 2009       pair.ml

Added an outer universal quantifier over P to the theorem pair_INDUCT; Norbert
Voelker had pointed out that it didn't fit the pattern of all the other
induction theorems that have this quantifier.

Sat 16th May 2009       help.ml

Modified "search" function so it ignores pure variables, with a warning, and
also returns the empty list if the input list is nonempty but entirely full of
variables.

Sat 16th May 2009       real.ml, int.ml

Added the following two to complete the suite with LE and LT variants:

REAL_EQ_SQUARE_ABS = |- !x y. abs x = abs y <=> x pow 2 = y pow 2
INT_EQ_SQUARE_ABS = |- !x y. abs x = abs y <=> x pow 2 = y pow 2

Thu 14th May 2009       sets.ml

Added the following, which is potentially quite useful for otherwise tedious
reasoning patterns:

SURJECTIVE_IMAGE_EQ =
  |- !s t.
         (!y. y IN t ==> (?x. f x = y)) /\ (!x. f x IN t <=> x IN s)
         ==> IMAGE f s = t

Sat  9th May 2009       Examples/update_database.ml

Made a small tweak so that "make_database_assignment" applies "uniq" to its
list. Some duplicates do otherwise happen, and now they are mostly deliberate
overwritings like num_Axiom.

Tue  5th May 2009       cart.ml

Added a couple of theorems that are trivial, but can be used to eliminate
conditions on indices in some interesting situations, e.g. in vector arithmetic
operations.

  CART_EQ_FULL = |- !x y. x = y <=> (!i. x$i = y$i)

  FINITE_INDEX_INRANGE =
   |- !i. ?k. 1 <= k /\ k <= dimindex(:N) /\ (!x:A^N. x$i = x$k)

Sat  2nd May 2009       sets.ml

Added a trivial theorem that I sometimes want:

  FINITE_EMPTY = |- FINITE {}

Of course, it already exists, but CONJUNCT1 FINITE_RULES is slightly
more to type, while just FINITE_RULES can make the simplifier work much
harder trying to backchain.

Mon 20th Apr 2009       sets.ml

Added a couple of potentially useful theorems; there are similar things in
Examples/card.ml, but not the "universal" form and it seems natural for it to
be in the core.

BIJECTIVE_ON_LEFT_RIGHT_INVERSE =
  |- !f s t.
         (!x. x IN s ==> f x IN t)
         ==> ((!x y. x IN s /\ y IN s /\ f x = f y ==> x = y) /\
              (!y. y IN t ==> (?x. x IN s /\ f x = y)) <=>
              (?g. (!y. y IN t ==> g y IN s) /\
                   (!y. y IN t ==> f (g y) = y) /\
                   (!x. x IN s ==> g (f x) = x)))

BIJECTIVE_LEFT_RIGHT_INVERSE =
  |- !f. (!x y. f x = f y ==> x = y) /\ (!y. ?x. f x = y) <=>
         (?g. (!y. f (g y) = y) /\ (!x. g (f x) = x))

Fri 17th Apr 2009       sets.ml

Added two degenerate cases for "pairwise", which are trivial to prove but where
you wouldn't really want to divert a proof to do so:

  PAIRWISE_EMPTY = |- !r. pairwise r {} <=> T

  PAIRWISE_SING = |- !r x. pairwise r {x} <=> T

Tue 14th Apr 2009       equal.ml

Changed the implementation of CACHE_CONV slightly so that it pushes the
function ALPHA_HACK inside the term net. The motivation was that Freek
discovered a problem when adding definitions to constants in theorems: in the
existing implementation this was comparing theorems when inserting things into
the list at a particular net node, when used in the real arithmetic decision
procedure. Actually, since it's almost always used with functions now, maybe I
should just simplify the code by forgetting about eliminating duplicates in
this list.

Sat 11th Apr 2009       pa_j_3.11.ml (new file)

Just to avoid generating a harmless error message, copied "pa_j_3.10.ml" to
"pa_j_3.11.ml". Fortunately no changes are needed for the latest camlp5 (I just
tried camlp5 5.11 and it's fine) so maybe thanks to camlp5 I'll be able to stop
continually having to release new syntax extension files for each major OCaml
release.

Tue 31st Mar 2009       Examples/moebius.ml

Added a new file Examples/moebius.ml by Gianni Ciolli, Graziano Gentili and
Marco Maggesi defining Moebius functions and proving they are the
biholomorphisms of the unit disc. This uses Cartan's theorem, which they also
contributed and I installed in the Multivariate theories.

Tue 17th Mar 2009       basics.ml

Added "mk_let", which Roland Zumkeller had pointed out was missing, even though
there was a dead link to documentation for it (of course, I now added the
documentation too). Also made dest_let a bit fussier: it used not to check that
the head operator was in fact "LET".

Tue 24th Feb 2009       basics.ml, ind-defs.ml

Fixed a bug in subst pointed out by Mark Adams, where for example:

  subst [v,`1`] (mk_exists(v,`1 + 1 = 2`));;

where v happens to be the next genvar to be generated. Just used "variants" to
avoid the existing variables in the term when creating intermediate variables.
(To do this, I moved "variables" from ind-defs.ml, which is hardly a natural
place for it anyway, and moved back the definition of "variants" within
"basics.ml".) There must be a few other places where such genvar coincidences
would kill things too.

Sun 22nd Feb 2009       sets.ml

Finally added these, which I seem to generate quite a bit at the moment:

  IMAGE_ID = |- !s. IMAGE (\x. x) s = s

  IMAGE_I = |- !s. IMAGE I s = s

Fri 20th Feb 2009       sets.ml

Added natural duals to corresponding FORALL_xxx theorems:

  EXISTS_IN_INSERT =
    |- !P a s. (?x. x IN a INSERT s /\ P x) <=> P a \/ (?x. x IN s /\ P x)

  EXISTS_IN_GSPEC =
    |- (!P f. (?z. z IN {f x | P x} /\ Q z) <=> (?x. P x /\ Q (f x))) /\
       (!P f. (?z. z IN {f x y | P x y} /\ Q z) <=>
              (?x y. P x y /\ Q (f x y))) /\
       (!P f.
            (?z. z IN {f w x y | P w x y} /\ Q z) <=>
            (?w x y. P w x y /\ Q (f w x y)))

Fri 13th Feb 2009       sets.ml

Added

  IMAGE_INTER_INJ =
    |- !f s t.
         (!x y. f x = f y ==> x = y)
         ==> IMAGE f (s INTER t) = IMAGE f s INTER IMAGE f t

and also added outer universal quantifiers to similar theorems IMAGE_DIFF_INJ
and IMAGE_DELETE_INJ.

Thu 15th Jan 2009       Examples/borsuk.ml

Added a proof of the Borsuk-Ulam theorem, so far just for the ordinary 2-sphere
in real^3.

Wed 14th Jan 2009       sets.ml

Added FUN_IN_IMAGE = |- !f s x. x IN s ==> f x IN IMAGE f s

Wed 14th Jan 2009       sets.ml

Added  PSUBSET_ALT =
  |- !s t:A->bool. s PSUBSET t <=> s SUBSET t /\ (?a. a IN t /\ ~(a IN s))

Thu 25th Dec 2008       sets.ml

Added SET_OF_LIST_MAP =
  |- !f l. set_of_list (MAP f l) = IMAGE f (set_of_list l)

Wed 24th Dec 2008       list.ml

Added the following useful theorem, which is actually one of very few about EL:

  MEM_EXISTS_EL =
   |- !l x. MEM x l <=> (?i. i < LENGTH l /\ x = EL i l)

Sun 21st Dec 2008       sets.ml

Added the following, not in wf.ml because it needs set notions like "FINITE":

  WF_FINITE =
    |- !(<<). (!x. ~(x << x)) /\
              (!x y z. x << y /\ y << z ==> x << z) /\
              (!x. FINITE {y | y << x})
              ==> WF (<<)

Sun 21st Dec 2008       arith.ml, sets.ml

Moved the following theorems from "sets.ml" back to "arith.ml":
TRANSITIVE_STEPWISE_LT_EQ, TRANSITIVE_STEPWISE_LT, TRANSITIVE_STEPWISE_LE_EQ,
TRANSITIVE_STEPWISE_LE. This was mainly so I could exploit them sooner, but in
any case they seem to belong there more naturally.

Sat 20th Dec 2008       Examples/card.ml

Added a few more general lemmas and particularly a few non-trivial results
about countable sets.

Sat 20th Dec 2008       sets.ml, Examples/card.ml

It seemed ugly having these hardly-used relations like CARD_GE that are then
superseded by >=_c etc. in Examples/card.ml. So I replaced the definitions in
sets.ml with those <=_c forms, adding >= and >, also moving LE_C and proving
GE_C which is essentially a replacement for the old CARD_GE. Deleted the
little-used theorems CARD_GE_REFL, CARD_GE_TRANS and FINITE_HAS_SIZE_LEMMA
(these would belong in Examples/card.ml) but put copies in Jordan for now.

Fri 19th Dec 2008       sets.ml

Added the following, which is actually often nicer than using SIMPLE_IMAGE,
and applicable to cases with 1, 2 or 3 parameters:

  FORALL_IN_GSPEC =
  |- (!P f. (!z. z IN {f x | P x} ==> Q z) <=> (!x. P x ==> Q (f x))) /\
     (!P f.
          (!z. z IN {f x y | P x y} ==> Q z) <=> (!x y. P x y ==> Q (f x y))) /\
     (!P f.
          (!z. z IN {f w x y | P w x y} ==> Q z) <=>
          (!w x y. P w x y ==> Q (f w x y)))

Tue 16th Dec 2008       Makefile

Made a few small tweaks to the Makefile, in particular forcing loading
Examples/update_database.ml right at the end of the loads for each
image. I had earlier encountered problems with duplicates because of the
explicit assignment of theorems in "multivariate_database.ml" etc.

Sun 14th Dec 2008       sets.ml

Added the following, which saves some trivial "unwinding"

  FORALL_IN_INSERT =
    |- !P a s. (!x. x IN a INSERT s ==> P x) <=> P a /\ (!x. x IN s ==> P x)

Tue  9th Dec 2008       cart.ml

Added "vector", which was formerly defined in the multivariate theories and for
the special type real. Here generalized it to type A, and eliminated special
choice of zero for higher elements (which is irrelevant anyway and doesn't
really generalize). The immediate impetus was that I wanted to use it to define
matrices.

Fri  5th Dec 2008       iter.ml

Added the following theorems about differences of powers. Could add the sums of
powers too, but they would hardly be nicer than just instantiating one of these
with a negated argument.

REAL_SUB_POW =
  |- !x y n.
         1 <= n
         ==> x pow n - y pow n =
             (x - y) * sum (0..n - 1) (\i. x pow i * y pow (n - 1 - i))

REAL_SUB_POW_R1 =
  |- !x n. 1 <= n ==> x pow n - &1 = (x - &1) * sum (0..n - 1) (\i. x pow i)

REAL_SUB_POW_L1 =
  |- !x n. 1 <= n ==> &1 - x pow n = (&1 - x) * sum (0..n - 1) (\i. x pow i)

Fri  5th Dec 2008       arith.ml

Added EXP_ZERO = |- !n. 0 EXP n = (if n = 0 then 1 else 0)

Thu  4th Dec 2008       int.ml

Added another forgotten analog of a real theorem:

  INT_POW_ZERO = |- !n. &0 pow n = (if n = 0 then &1 else &0)

Thu  4th Dec 2008       Examples/mangoldt.ml Examples/agm.ml Examples/multiplicative.ml [new files]

Added three new files to Examples with stuff that is generally useful. The
mangoldt.ml one is essentially common to 100/pnt.ml and 100/dirichlet.ml, so it
makes sense to have it common. The agm.ml one was already basically there in
100/agm.ml, but I factored out the explicit use of roots so this version is
more portable. The multiplicative.ml defines the notion for both N and R and
has the Mobius function for R.

Wed  4th Dec 2008       100/dirichlet.ml [new file]

Added the proof of Dirichlet's theorem to the Great 100 Theorems directory.

Wed  3rd Dec 2008       iter.ml

Changed the quantification in NSUM_OFFSET and SUM_OFFSET. Previously one
variable was left free, and it was inconvenient to have the "offset" variable
at the end of the list because that is often necessary to instantiate in order
to get higher order matching working.

Wed  3rd Dec 2008       sets.ml

Added a lemma that I seem to regenerate quite often. I'm not very keen on the
name but it's consistent with EMPTY_GSPEC, which admittedly I don't use much.

  SING_GSPEC =
    |- (!a. {x | x = a} = {a}) /\ (!a. {x | a = x} = {a})

Also added the following, which I seem to want quite often:

  FINITE_SING = |- !a. FINITE {a}

Sat 29th Nov 2008       real.ml

Added a few useful theorems that are obvious holes in the current pattern:

 REAL_INV_POW = |- !x n. inv (x pow n) = inv x pow n

 REAL_INV_LT_1 = |- !x. &1 < x ==> inv x < &1

 REAL_INV_1_LT = |- !x. &0 < x /\ x < &1 ==> &1 < inv x

Thu 27th Nov 2008       passim

Changed a lot of instances of GSYM IMP_IMP to IMP_CONJ, and likewise changed
explicit TAUT calls to IMP_CONJ, IMP_CONJ_ALT. Even caught one or two instances
of IMP_IMP and EQ_IMP replacing explicit tautologies.

Wed 26th Nov 2008       theorems.ml

Added the following, which I keep regenerating ad hoc:

  IMP_CONJ_ALT = |- p /\ q ==> r <=> q ==> p ==> r

Wed 26th Nov 2008       iter.ml

Added two theorems relating explicit number segments to the m..n notation:

  NUMSEG_LE = |- !n. {x | x <= n} = 0..n

  NUMSEG_LT = |- !n. {x | x < n} = (if n = 0 then {} else 0..n - 1)

Mon 24th Nov 2008       drule.ml

Changed two instances of "=" between terms (when checking whether the result
needs non-trivial alpha-conversion) to Pervasives.compare, one each in
PART_MATCH and GEN_PART_MATCH. This came up when checking some big tables where
this step was taking half a second.

Then wondered about matching itself. Although in this case it's not the
bottleneck, I made some corresponding changes inside term_match (more of them).

Sun 23rd Nov 2008       real.ml, Examples/isum.ml

Added a version of telescoping the other way round, otherwise it's tedious to
apply it.

SUM_DIFFS_ALT =
  |- !m n.
         sum(m..n) (\k. f (k + 1) - f k) =
         (if m <= n then f (n + 1) - f m else &0)

ISUM_DIFFS_ALT =
  |- !m n.
         isum(m..n) (\k. f (k + 1) - f k) =
         (if m <= n then f (n + 1) - f m else &0)

Sun 23rd Nov 2008       int.ml

Added the following, which had somehow got left out:

  INT_SUB_RDISTRIB = |- !x y z. (x - y) * z = x * z - y * z

Sun 23rd Nov 2008       Examples/isum.ml [new file]

Added a new file of theorems about integer sums. I decided to do it by
generalizing INT_OF_REAL_THM, which works quite nicely, and would be quicker if
I ever rolled it into the core. The generalized INT_OF_REAL_THM could
conceivably be useful in itself.

Sun 23rd Nov 2008       int.ml

Surprisingly, found that my last change had broken INTEGER_TAC, which was
sometimes calling int_ideal_cofactors in cases where not all the terms are
integers. Put in filtering, but really I should think more about how this
happens, since it may be indicative of some more systematic improvements I
could make.

Sat 22nd Nov 2008       calc_rat.ml, int.ml

Modified "int_ideal_cofactors" and "real_ideal_cofactors" to give a clearer
error messages if the types of the terms are unexpected. This was stimulated by
a report from Loic Pottier who tried the example from the reference manual.
Anyway I also added a "prioritize_real()" to the help entry for
"int_ideal_cofactors".

Fri 21st Nov 2008       calc_rat.ml

Made a change corresponding to what I did for num's MAX and MIN: added
conversions REAL_RAT_MAX_CONV and REAL_RAT_MIN_CONV and rolled them into
REAL_RAT_RED_CONV and hence REAL_RAT_REDUCE_CONV.

Did likewise over integers, adding conversions INT_MAX_CONV and INT_MIN_CONV
and rolled them into INT_RED_CONV and hence INT_REDUCE_CONV. Also added two
supporting pseudo-definitions:

  INT_MAX = |- !x y. max x y = (if x <= y then y else x)

  INT_MIN = |- !x y. min x y = (if x <= y then x else y)

Fri 21st Nov 2008       Examples/schnirelmann.ml [new file]

Added my little file of properties of Schnirelmann density to Examples, since
it is relatively self-contained and potentially useful.

Wed 19th Nov 2008       iter.ml

Added the following; the "sum" analog was already there but now I needed the
natural number version:

NSUM_IMAGE_NONZERO =
  |- !d i s.
         FINITE s /\
         (!x y. x IN s /\ y IN s /\ ~(x = y) /\ i x = i y ==> d (i x) = 0)
         ==> nsum (IMAGE i s) d = nsum s (d o i)

Tue 18th Nov 2008       iter.ml

Added a result about enumerating elements of a finite set in order; it's
strange I'd never wanted this before!

TOPOLOGICAL_SORT =
  |- !(<<). (!x y. x << y /\ y << x ==> x = y) /\
            (!x y z. x << y /\ y << z ==> x << z)
            ==> (!n s.
                     s HAS_SIZE n
                     ==> (?f. s = IMAGE f (1..n) /\
                              (!j k.
                                   j IN 1..n /\ k IN 1..n /\ j < k
                                   ==> ~(f k << f j))))

Mon 17th Nov 2008       calc_num.ml

Added NUM_MAX_CONV and NUM_MIN_CONV and rolled them into NUM_RED_CONV and
NUM_REDUCE_CONV.

Mon 17th Nov 2008       real.ml

Added two more theorems that I was surprised weren't (quite) already there.

REAL_POW_EQ_1_IMP =
  |- !x n. ~(n = 0) /\ x pow n = &1 ==> abs x = &1

REAL_POW_EQ_1 =
  |- !x n. x pow n = &1 <=> abs x = &1 /\ (x < &0 ==> EVEN n) \/ n = 0

Fri 14th Nov 2008       Makefile

Changed the Makefile to load the dynamic database update into the basic
hol image, not only the extra builds on top. Put a final "search" in
those, however, so that the very first search is not slow.

Fri 14th Nov 2008       sets.ml

Added three more theorems about unions that I was rather surprised I'd never
done before:

CARD_UNION_GEN =
  |- !s t.
         FINITE s /\ FINITE t
         ==> CARD(s UNION t) = (CARD s + CARD t) - CARD(s INTER t)

CARD_UNION_OVERLAP_EQ =
  |- !s t.
         FINITE s /\ FINITE t
         ==> (CARD(s UNION t) = CARD s + CARD t <=> s INTER t = {})

CARD_UNION_OVERLAP =
  |- !s t.
         FINITE s /\ FINITE t /\ CARD(s UNION t) < CARD s + CARD t
         ==> ~(s INTER t = {})

Wed 12th Nov 2008       int.ml

Added a dual to the existing theorem for the universal quantifier:

  INT_EXISTS_POS = |- (?n. P (&n)) <=> (?i. &0 <= i /\ P i)

Wed 12th Nov 2008       int.ml

Changed the definition of (a == b) to assume both sides have the same type.
This is a useful type constraint and I can't imagine the accidental generality
ever actually being useful.

Tue 11th Nov 2008       arith.ml, real.ml, int.ml, passim

Finally added natural number MAX and MIN:

  MAX = |- !m n. MAX m n = (if m <= n then n else m)

  MIN = |- !m n. MIN m n = (if m <= n then m else n)

and some basic supporting theorems, just enough to roll it into ARITH_RULE etc.

  REAL_OF_NUM_MAX = |- !m n. max (&m) (&n) = &(MAX m n)
  REAL_OF_NUM_MIN = |- !m n. min (&m) (&n) = &(MIN m n)

  INT_OF_NUM_MAX = |- !m n. max (&m) (&n) = &(MAX m n)
  INT_OF_NUM_MIN = |- !m n. min (&m) (&n) = &(MIN m n)

Removed corresponding or slightly different definitions from the places where
it was already used, and occasionally simplified proofs just to use the
enhanced ARITH_TAC.

Sun  2nd Nov 2008       Mizarlight/make.ml

There was still an issue with getting Pa_j when not in the HOL directory, so
added the line:

  Topdirs.dir_directory (!hol_dir);;

Sun  2nd Nov 2008       Mizarlight/make.ml

Changed "#load" to my own explicit path version so it works wherever HOL Light
is installed.

Sat  1st Nov 2008       Minisat/make.ml, Boyer_Moore/make.ml

Changed "#use" into "loads" so that it will find the path wherever HOL Light is
installed.

Sat  1st Nov 2008       Examples/pratt.ml, Examples/pocklington.ml

Added "2>/dev/null" to the GP invocations so we avoid the "reading .gprc"
messages.

Sat 25th Oct 2008       Makefile, Multivariate/make.ml, Multivariate/make_complex.ml, Multivariate/multivariate_database.ml [new file], Multivariate/complex_database.ml [new file]

Added pre-built databases for the multivariate and complex-multivariate
theories, as a convenience for people who aren't able to use the dynamic
updating.

Sat 25th Oct 2008       Examples/sos.ml

Put preprocessing of DECIMAL (i.e. the #x.y notation) into REAL_SOS in exactly
the same way as REAL_ARITH. This was motivated by the example of using
REAL_SQRTSOSFIELD on `&2 * #1.255 < sqrt(&8)` that I mentioned on the Flyspeck
list.

Sat 25th Oct 2008       set.ml

Added these two lemmas, which came up naturally in a query from Truong Nguyen
on the Flyspeck list.

  CARD_SET_OF_LIST_LE = |- !l. CARD(set_of_list l) <= LENGTH l

  HAS_SIZE_SET_OF_LIST =
    |- !l. (set_of_list l) HAS_SIZE (LENGTH l) <=> PAIRWISE (\x y. ~(x = y)) l

Fri 24th Oct 2008       drule.ml, simp.ml, tactics.ml

Since the change to PART_MATCH on 22nd Sep was breaking too much stuff, I
restored the old version but added a new one GEN_PART_MATCH with the new
behaviour, and used that so far just in congruence rule handling in the
simplifier.

Tue 21st Oct 2008       Examples/pratt.ml, Examples/pocklington.ml

When trying out HOL Light on a new platform (my own little Debian thing inside
Virtualbox) I hit a problem with the PARI/GP interface because I was looking
for the first "[" to find the output, yet in this case that occurred in the
startup banner. Made the chopping of the output slightly less unintelligent by
starting at the rightmost "]" then the rightmost "[".

Wed 24th Sep 2008       Examples/analysis.ml

Made the overload skeleton and overloading instances of "sum" more general;
before the overload skeleton was restricted to sums out of a set of numbers.
This was pointed out by Tom Hales.

Tue 23rd Sep 2008       tactics.ml

Fixed a bug in FREEZE_THEN: the implementation using SUBGOAL_THEN was presuming
two subgoals afterwards, yet it's possible that the ttac will solve the
original goal completely and just leave the trivial one. This actually came up
when I used FREEZE_THEN(fun t -> SIMP_TAC[t]) in order to fix some cases where
things coincidentally worked thanks to the old PART_MATCH behaviour.

Tue 23rd Sep 2008       tactics.ml

I had compensated for the modified PART_MATCH and its consequent effect on
MATCH_MP_TAC by tweaking a few proofs. But it was getting a bit tedious, and it
didn't actually seem that the new behaviour was beneficial in this context
since the invented variables are effectively frozen and so almost certainly not
what's wanted. It seemed surprisingly difficult to put a basic wrapper round
the existing PART_MATCH (I wanted some FREEZE-type thing, but you need to watch
out for type instantiation and theorems with hypotheses). So I basically just
copied the old PART_MATCH into this code.

Mon 22nd Sep 2008       drule.ml

Changed PART_MATCH so that it renames even free variables in the theorem if
necessary when they would otherwise be uninstantiated (because they don't occur
in the bit actually being matched) and clash with some post-instantiation
variables. This is exemplified by the following:

  let th =
    TAUT `(g = g') ==>
          (g' ==> (t = t')) ==>
          (~g' ==> (e = e')) ==>
          ((if g then t else e) = (if g' then t' else e'))`;;

  let tm =
   `if CONS h' t' = []
    then a
    else CONS h' t'`;;

PART_MATCH (lhs o funpow 3 rand) th tm;;

which used to give

  |- (CONS h' t' = [] <=> g')
     ==> (g' ==> a = t')
     ==> (~g' ==> CONS h' t' = e')
     ==> (if CONS h' t' = [] then a else CONS h' t') =
         (if g' then t' else e')

but now gives

  |- (CONS h' t' = [] <=> g')
     ==> (g' ==> a = t'')
     ==> (~g' ==> CONS h' t' = e')
     ==> (if CONS h' t' = [] then a else CONS h' t') =
         (if g' then t'' else e')

This was originally found by Jesse Bingham, who encountered a case where
SIMP_CONV returned the "wrong" left-hand side thanks to this congruence rule
instantiation.

Tue 19th Aug 2008       lib.ml

Removed a stray ";" in the definition of "mem'", pointed out by Mark Adams. For
some reason OCaml didn't complain.

Mon 11th Aug 2008       Boyer_Moore/* [new directory]

Added a new directory containing code for Boyer-Moore automation. This was
written by Petros Papapanagiotou, working with Jacques Fleuriot and starting
from Richard Boulton's HOL88 code. Petros's thesis describing the setup is
available at "http://www.inf.ed.ac.uk/publications/thesis/online/IM070466.pdf".

Mon 11th Aug 2008       Examples/iter.ml [new file]

Added a new file with theorems about the function iterator, from
Marco et al. Occasionally I had used something similar but called
it FUNPOW.

Mon 11th Aug 2008       sets.ml

Added SING_SUBSET = |- !s x. {x} SUBSET s <=> x IN s
which was used in Marco et al's Cartan proof.

Fri  8th Aug 2008       arith.ml, int.ml

Changed the natural number and integer modulus operations so that n MOD 0 = n
and n rem 0 = n. This was with the idea of removing the ~(n = 0) hypothesis
from (a == b) (mod n) <=> (a MOD n = b MOD n) and others, though I didn't
actually do that now.

Thu  7th Aug 2008       int.ml

Added INT_DIV_CONV and INT_REM_CONV for explicit calculations, and rolled these
into INT_RED_CONV and INT_REDUCE_CONV. I should do something for INT_ARITH at
some stage too.

Thu  7th Aug 2008       int.ml

Added definitions of "div" and "rem", using what Raymond Boute calls the
"Euclidean" definition. Also added some supporting theorems, so we have:

  INT_WOP =
    |- (?x. &0 <= x /\ P x) <=>
       (?x. &0 <= x /\ P x /\ (!y. &0 <= y /\ P y ==> x <= y))

  INT_DIVMOD_EXIST_0 =
    |- !m n.
           ?q r.
               if n = &0
               then q = &0 /\ r = &0
               else &0 <= r /\ r < abs n /\ m = q * n + r

  INT_DIVISION_0 =
    |- !m n.
           if n = &0
           then m div n = &0 /\ m rem n = &0
           else &0 <= m rem n /\ m rem n < abs n /\ m = m div n * n + m rem n

  INT_DIVISION =
    |- !m n.
           ~(n = &0)
           ==> m = m div n * n + m rem n /\ &0 <= m rem n /\ m rem n < abs n

  INT_DIVMOD_UNIQ =
    |- !m n q r.
           m = q * n + r /\ &0 <= r /\ r < abs n ==> m div n = q /\ m rem n = r

Thu  7th Aug 2008       int.ml

Added more forgotten analogues of real theorems, including the most recent set
just below but also with one other strange omission:

  INT_LE_RMUL =
    |- !x y z. x <= y /\ &0 <= z ==> x * z <= y * z

  INT_POW_LE2_REV =
    |- !n x y. ~(n = 0) /\ &0 <= y /\ x pow n <= y pow n ==> x <= y

  INT_POW_LT2_REV =
    |- !n x y. &0 <= y /\ x pow n < y pow n ==> x < y

  INT_POW_EQ =
    |- !n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y /\ x pow n = y pow n ==> x = y

  INT_POW_EQ_ABS =
    |- !n x y. ~(n = 0) /\ x pow n = y pow n ==> abs x = abs y

Tue 22nd Apr 2008       real.ml

Added a few theorems that seem like glaring omissions, even though they're not
really hard to derive when needed:

  REAL_POW_LE2_REV =
    |- !n x y. ~(n = 0) /\ &0 <= y /\ x pow n <= y pow n ==> x <= y

  REAL_POW_LT2_REV =
    |- !n x y. &0 <= y /\ x pow n < y pow n ==> x < y

  REAL_POW_EQ =
    |- !n x y. ~(n = 0) /\ &0 <= x /\ &0 <= y /\ x pow n = y pow n ==> x = y

  REAL_POW_EQ_ABS =
    |- !n x y. ~(n = 0) /\ x pow n = y pow n ==> abs x = abs y

Mon 21st Apr 2008       lib.ml

Made a few small optimizations to the FPF code, basically inlining "ldb" and
"is_undefined" to reduce function call overhead.

Fri 29th Feb 2008       arith.ml

Yet more simplifications suggested by Mark Bouler, though not using the same
techniques, just more efficiently exploiting DIVMOD_UNIQ. Now the pairs
DIV_0/MOD_0, DIV_1/MOD_1 and DIV_MULT/MOD_MULT are proved together using that
and split into pairs.

Tue 26th Feb 2008       arith.ml

Simplified several proofs, this time of DIV_MOD, DIV_MONO, DIV_MOD_LT and
DIV_LE_EXCLUSION_EXCLUSION using Mark Bouler's method. The only price was that
the proof of the core lemma LE_RDIV_EQ became slightly longer so as not to rely
on DIV_MONO. Also took the chance to slightly reorder things to separate the
second suite of theorems about EXP from those about DIV and MOD.

Sat 23rd Feb 2008       arith.ml

Greatly simplified the proof of DIV_DIV using a trick that Mark Bouler showed
me yesterday, using indirect equality (easy by MESON) and then the "Galois
connection" lemma LE_RDIV_EQ. I should maybe see if this is more widely
applicable.

Tue 19th Feb 2008       arith.ml

I always seem to be inventing ad-hoc lemmas to shuffle between different
formulations of a natural number being strictly positive, so I added the
following. Of course it will somewhat expand the search space in the simplifier
but cuts through all the mess by having implications between all 6 pairs of
formulations:

  LE_1 =
    |- (!n. ~(n = 0) ==> 0 < n) /\
       (!n. ~(n = 0) ==> 1 <= n) /\
       (!n. 0 < n ==> ~(n = 0)) /\
       (!n. 0 < n ==> 1 <= n) /\
       (!n. 1 <= n ==> 0 < n) /\
       (!n. 1 <= n ==> ~(n = 0))

Sun 17th Feb 2008       iter.ml

Slighly weakened hypothesis inequalities, formerly "m <= p" and "p <= n", in

  NUMSEG_COMBINE_R =
    |- !m p n. m <= p + 1 /\ p <= n ==> ((m..p) UNION ((p+1)..n) = m..n)

  NUMSEG_COMBINE_L =
    |- !m p n. m <= p /\ p <= n + 1 ==> ((m..(p-1)) UNION (p..n) = m..n)

and added two combinations with sums:

  SUM_COMBINE_L =
    |- !f m n p.
         0 < n /\ m <= n /\ n <= p + 1
         ==> sum (m..n - 1) f + sum (n..p) f = sum (m..p) f
  SUM_COMBINE_R =
    |- !f m n p.
         m <= n + 1 /\ n <= p
         ==> sum (m..n) f + sum (n + 1..p) f = sum (m..p) f

and an unrelated but useful theorem:

  SUM_ABS_LE =
    |- !f g s.
         FINITE s /\ (!x. x IN s ==> abs(f x) <= g x)
         ==> abs(sum s f) <= sum s g

Wed 13th Feb 2008       iter.ml

Added two forms of partial summation:

  SUM_PARTIAL_SUC =
    |- !f g m n.
           sum (m..n) (\k. f k * (g(k + 1) - g k)) =
           (if m <= n
            then f(n + 1) * g(n + 1) -
                 f m * g m -
                 sum (m..n) (\k. g(k + 1) * (f(k + 1) - f k))
            else &0)

  SUM_PARTIAL_PRE =
    |- !f g m n.
           sum (m..n) (\k. f k * (g k - g(k - 1))) =
           (if m <= n
            then f(n + 1) * g n -
                 f m * g(m - 1) -
                 sum (m..n) (\k. g k * (f(k + 1) - f k))
            else &0)

Tue 12th Feb 2008       itab.ml

So it turns out that my tweak on 31st Jan last year was not right after all.
Sean McLaughlin pointed out that the following now didn't work:

  ITAUT `(((~ ~ (p \/ ~p)) ==> (p \/ ~p)) ==> (p \/ ~p))`;;

So I just went back to the old code in this respect, putting back FIRST_ASSUM
instead of FIRST_X_ASSUM.

Tue  5th Feb 2008       real.ml

Added: REAL_EQ_INV2 = |- !x y. inv x = inv y <=> x = y
       REAL_INV_EQ_1 = |- !x. inv x = &1 <=> x = &1

Tue  5th Feb 2008       arith.ml

Added a bunch of theorems that are an obvious gap in the arithmetic suite;
several variants of these are in Examples/prime.ml, but often decorated with
"SUC". So I added "SUC" suffixes to those versions.

  EXP_EQ_1 = |- !x n. x EXP n = 1 <=> x = 1 \/ n = 0
  EXP_MONO_LE_IMP = |- !x y n. x <= y ==> x EXP n <= y EXP n
  EXP_MONO_LT_IMP = |- !x y n. x < y /\ ~(n = 0) ==> x EXP n < y EXP n
  EXP_MONO_LE = |- !x y n. x EXP n <= y EXP n <=> x <= y \/ n = 0
  EXP_MONO_LT = |- !x y n. x EXP n < y EXP n <=> x < y /\ ~(n = 0)
  EXP_MONO_EQ = |- !x y n. x EXP n = y EXP n <=> x = y \/ n = 0

Mon  4th Feb 2008       calc_rat.ml, int.ml

Added something I should probably have done a long time ago:

  ASM_ARITH_TAC
  ASM_INT_ARITH_TAC
  ASM_REAL_ARITH_TAC

These basically pop every assumption that isn't universally quantified and use
them as additional hypotheses. I was getting sick of using repeated idioms
like "REPEAT(POP_ASSUM MP_TAC) THEN ARITH_TAC".

Mon  4th Feb 2008       arith.ml

Added MULT_DIV_LE = |- !m n p. ~(p = 0) ==> m * (n DIV p) <= (m * n) DIV p

Sun  3rd Feb 2008       arith.ml

Added

  EQ_EXP =
    |- !x m n.
         x EXP m = x EXP n <=>
         (if x = 0 then m = 0 <=> n = 0 else x = 1 \/ m = n)

Tue 29th Jan 2008       sets.ml

Added:

  FINITE_FINITE_PREIMAGE_GENERAL =
    |- !f s t.
           FINITE t /\ (!y. y IN t ==> FINITE {x | x IN s /\ f x = y})
           ==> FINITE {x | x IN s /\ f x IN t}

  FINITE_FINITE_PREIMAGE =
    |- !f t.
           FINITE t /\ (!y. y IN t ==> FINITE {x | f x = y})
           ==> FINITE {x | f x IN t}

Thu 24th Jan 2008       Unity/make.ml, Unity/mk_unity_prog.ml

Made a fix indicated by Flemming to the "mk_unity_prog.ml" file so that now it
loads unproblematically, and hence uncommented its load in the "make.ml" root.

Fri 18th Jan 2008       Unity [new directory]

Added the first version of Flemming Andersen's Unity theory, which he has
ported to HOL Light.

Wed 16th Jan 2008       real.ml

Added

REAL_POW_ZERO =
  |- !n. &0 pow n = (if n = 0 then &1 else &0)

REAL_POW_MONO_INV =
  |- !m n x. &0 <= x /\ x <= &1 /\ n <= m ==> x pow m <= x pow n

Tue 15th Jan 2008       arith.ml

Finally added FACT_NZ = |- !n. ~(FACT n = 0). Of course it's trivial to
generate, but I seem to be doing it quite often.

Wed  7th Jan 2008       hol.ml

Changed (back?) from Filename.temp_dir to "/tmp", since I just discovered on
getting a new laptop that the OCaml in Cygwin, still 3.08, doesn't have that.
It seems a pity to force people to upgrade their OCaml just for this slightly
more elegant solution. Maybe in a year or two I'll change it back.

Wed  2nd Jan 2008       define.ml

Put in a rewritten version of this stuff, with a few new proforma theorems and
a somewhat different (simpler?) method for hacking the proformas to include
many variables. Most notably, this adds support for the new "match" and
"function" constructs, but has some other enhancements too such as "MAP". Also
the "instantiate_casewise_recursion" folds in the tupling of multiple
arguments, which was otherwise only done in functions further out.

Sat 29th Dec 2007       Permutation/*.ml

Installed new version of the Permutation material from Marco Maggesi.

Thu 27th Dec 2007       sets.ml

Added

  SIMPLE_IMAGE_GEN = |- !f p. {f x | P x} = IMAGE f {x | P x}

Sun 23rd Dec 2007       iter.ml

Added SUM_IMAGE_LE =

  |- !f g s.
         FINITE s /\ (!x. x IN s ==> &0 <= g(f x))
         ==> sum (IMAGE f s) g <= sum s (g o f)

and IN_NUMSEG_0 = |- !m n. m IN 0..n <=> m <= n

Sun 23rd Dec 2007       sets.ml

Added

  EXISTS_IN_UNIONS =
    |- !P s. (?x. x IN UNIONS s /\ P x) <=> (?t x. t IN s /\ x IN t /\ P x)

Tue 18th Dec 2007       realarith.ml

Tweaked the "eliminate_construct" subfunction in GEN_REAL_ARITH to check that
the term it's finding is actually free in the whole term. Previously, it could
go into an infinite loop in cases like this by repeatedly attempting to replace
non-free subterms:

  REAL_ARITH `&0 <= abs(sum s (\x. abs x))`;;

Tue 18th Dec 2007       real.ml

Added

  REAL_POW_1_LT = |- !n x. ~(n = 0) /\ &0 <= x /\ x < &1 ==> x pow n < &1
  REAL_POW_LT_1 = |- !n x. ~(n = 0) /\ &1 < x ==> &1 < x pow n

which I was a bit surprised not to have already, and also the integer
counterparts INT_POW_1_LT and INT_POW_LT_1.

Tue 18th Dec 2007       Examples/floor.ml

To be more consistent with other names, redefined:

  REAL_EQ_INTEGERS =
    |- !x y. integer x /\ integer y ==> (x = y <=> abs(x - y) < &1)

and renamed the old theorem that had that name:


  REAL_EQ_INTEGERS_IMP =
    |- !x y. integer x /\ integer y /\ abs(x - y) < &1 ==> x = y

Sun 16th Dec 2007       cart.ml

Added this finiteness theorem (which is actually quite tedious to prove!)

  FINITE_CART =
    |- !P. (!i. 1 <= i /\ i <= dimindex(:N) ==> FINITE {x | P i x})
           ==> FINITE {v | !i. 1 <= i /\ i <= dimindex(:N) ==> P i (v$i)}

Mon 10th Dec 2007       iter.ml

Added two slighly generalized forms of [N]SUM_IMAGE_GEN:

NSUM_GROUP =
  |- !f g s t.
         FINITE s /\ IMAGE f s SUBSET t
         ==> nsum t (\y. nsum {x | x IN s /\ f x = y} g) = nsum s g

SUM_GROUP =
  |- !f g s t.
         FINITE s /\ IMAGE f s SUBSET t
         ==> sum t (\y. sum {x | x IN s /\ f x = y} g) = sum s g

Sat  8th Dec 2007       sets.ml

Added  UNIONS_UNION = |- !s t. UNIONS (s UNION t) = UNIONS s UNION UNIONS t

Tue  4th Dec 2007       iter.ml

Added the following (maybe should also do an ITERATE version sometime).

NSUM_UNIONS_NONZERO =
  |- !f s.
         FINITE s /\
         (!t. t IN s ==> FINITE t) /\
         (!t1 t2 x.
              t1 IN s /\ t2 IN s /\ ~(t1 = t2) /\ x IN t1 /\ x IN t2
              ==> f x = 0)
         ==> nsum (UNIONS s) f = nsum s (\t. nsum t f)

SUM_UNIONS_NONZERO =
  |- !f s.
         FINITE s /\
         (!t. t IN s ==> FINITE t) /\
         (!t1 t2 x.
              t1 IN s /\ t2 IN s /\ ~(t1 = t2) /\ x IN t1 /\ x IN t2
              ==> f x = &0)
         ==> sum (UNIONS s) f = sum s (\t. sum t f)

Tue  4th Dec 2007       sets.ml

Added

SUBSET_CARD_EQ =
  |- !s t. FINITE t /\ s SUBSET t ==> (CARD s = CARD t <=> s = t)

Mon  3rd Dec 2007       wf.ml, define.ml, passim

Changed "measure" to "MEASURE" (both the constant name and the ML binding of
its definition). This frees up lowercase "measure" for Lebesgue measure, which
I've finally started seriously working with.

Sun  2nd Dec 2007       set.ml

Added

  UNIONS_SUBSET =
    |- !f t. UNIONS f SUBSET t <=> (!s. s IN f ==> s SUBSET t)

  SUBSET_UNIONS =
  |- !f g. f SUBSET g ==> UNIONS f SUBSET UNIONS g


Fri 23rd Nov 2007       iter.ml

Added

  CARD_UNIONS =
    |- !s. FINITE s /\
           (!t. t IN s ==> FINITE t) /\
           (!t u. t IN s /\ u IN s /\ ~(t = u) ==> t INTER u = {})
           ==> CARD(UNIONS s) = nsum s CARD

Thu 22nd Nov 2007       sets.ml

To celebrate Thanksgiving I proved that integrals of arbitrary functions over a
set of measure zero are 0. I ended up using a lemma about sums, and I thought
I'd add it to the core. In one sense it's a bit ad hoc, but corresponds to a
very straightforward intuition: all elements of one sum are dominated by some
of another, and the rest of the second sum are nonnegative.

  SUM_LE_INCLUDED =
    |- !f g s t i.
           FINITE s /\
           FINITE t /\
           (!y. y IN t ==> &0 <= g y) /\
           (!x. x IN s ==> (?y. y IN t /\ i y = x /\ f x <= g y))
           ==> sum s f <= sum t g

Tue 20th Nov 2007       int.ml

Added integer versions of some recent additions I'd forgotten, including the
latest:

  INT_BOUNDS_LE = |- !x k. --k <= x /\ x <= k <=> abs x <= k

  INT_BOUNDS_LT = |- !x k. --k < x /\ x < k <=> abs x < k

  INT_MUL_POS_LT =
    |- !x y. &0 < x * y <=> &0 < x /\ &0 < y \/ x < &0 /\ y < &0

  INT_MUL_POS_LE =
    |- !x y.
           &0 <= x * y <=>
           x = &0 \/ y = &0 \/ &0 < x /\ &0 < y \/ x < &0 /\ y < &0

  INT_LE_MUL_EQ =
    |- (!x y. &0 < x ==> (&0 <= x * y <=> &0 <= y)) /\
       (!x y. &0 < y ==> (&0 <= x * y <=> &0 <= x))

  INT_LT_MUL_EQ =
    |- (!x y. &0 < x ==> (&0 < x * y <=> &0 < y)) /\
       (!x y. &0 < y ==> (&0 < x * y <=> &0 < x))

To get the last two I had to add a little tweak to INT_OF_REAL_THM to handle
conjunctive equations; previously it only worked if all the universal
quantifiers were at the outside.

Tue 20th Nov 2007       real.ml

Added two theorems that I keep regenerating:

  REAL_BOUNDS_LE = |- !x k. --k <= x /\ x <= k <=> abs x <= k
  REAL_BOUNDS_LT = |- !x k. --k < x /\ x < k <=> abs x < k

The symmetric form of the first one was already there as REAL_ABS_BOUNDS, but
I've never actually used it (however, since it's used by Freek and Tom, I
didn't delete it).

Mon 19th Nov 2007       real.ml

Added

  REAL_MUL_POS_LT =
    |- !x y. &0 < x * y <=> &0 < x /\ &0 < y \/ x < &0 /\ y < &0

  REAL_MUL_POS_LE =
    |- !x y.
           &0 <= x * y <=>
           x = &0 \/ y = &0 \/ &0 < x /\ &0 < y \/ x < &0 /\ y < &0

Wed 14th Nov 2007       ind-types.ml

Added a trivial tweak in "prove_cases_thm" so that it works on num_INDUCTION,
where one of the "constructors" 0 is not really a constant. Just check for
reflexivity in "prove_triv" subfunction.

Wed 14th Nov 2007       calc_rat.ml

Added a little extra feature to REAL_FIELD so that it uses any strict
inequality hypotheses s < t to add a hypothesis ~(s = t). Previously, this only
happened if there was a correlation in a branch with an explicit equation (s =
t), e.g. introduced in the elimination of inverses. Now, for example, we solve
this which failed before:

  REAL_FIELD `&0 < x ==> x * y = x * z ==> y = z`;;

Tue 13th Nov 2007       sets.ml

Added SUBSET_ANTISYM_EQ = |- !s t. s SUBSET t /\ t SUBSET s <=> s = t

Tue 13th Nov 2007

Modified "pa_j_3.10.ml" for the latest version of camlp5 (5.02). Needed a bit
of grubbing round; in particular I had to add "translate_operator" into the new
"val_ident" clause.

Mon 12th Nov 2007

Added FORALL_UNWIND_CONV; I wanted some such operation inside the new "define"
wellfoundedness-guessing, and it seemed useful and general enough to do
properly.

Wed  7th Nov 2007               sets.ml

Added SUBSET_INTER = |- !s t u. s SUBSET t INTER u <=> s SUBSET t /\ s SUBSET u

Tue  6th Nov 2007               printer.ml

Modified the printer so that when trying to print a "function" or "match"
construct it *first* makes sure the construct is in the canonical form before
printing anything. Otherwise the kind of more general cases that crop up in
admissibility lemmas show up as an exception when printing.

Tue 30th Oct 2007               Makefile

Changed "[ ... ]" to "test", and "==" to "=" in the Makefile, which for some
reason barfed on my new Ubuntu box but not on other platforms. Anyway it seems
more correct/portable.

Wed 17th Oct 2007               pair.ml, ind-types.ml

Changed the definitions of _MATCH and _FUNCTION from

 |- _MATCH = \e r. (@) (r e)
 |- _FUNCTION = \r x. (@) (r x)

to

 |- _MATCH =  \e r. if (?!) (r e) then (@) (r e) else @z. F
 |- _FUNCTION = \r x. if (?!) (r x) then (@) (r x) else @z. F

I'd discovered painfully that the former does not interact well with the
special treatment of tail recursion in the "define.ml" setup, because in
general there is some nondeterminacy there. The new definition clears up this
problem, and is also perhaps a little more satisfying on general grounds
anyway, because it avoids any "accidental" assignments in cases where the match
isn't really well-defined, and so provides a bit more automatic debugging. The
only changes necessary were to the newish MATCH_CONV. They were fairly
non-invasive and should only have a small efficiency cost (the expensive
unwinding etc. is only done once even though the predicate appears twice in the
underlying expression).

Tue 16th Oct 2007               sets.ml

Added the infinitude of the new string type:

  string_INFINITE = |- INFINITE(:(char)list)

Fri 12th Oct 2007               printer.ml, parser.ml

Finished the job, more or less, by adding printer support for strings too, and
also improving the treatment of escapes so they correspond to OCaml (or at
least to the OCaml manual). That should more or less give a parse/print
equivalence.

Fri 12th Oct 2007               list.ml, parser.ml

Added a new type "char" defined like the old HOL88 type "ascii" with a
constructor ASCII taking 8 Booleans, together with the abbreviation of "string"
for "char list" (not a separate type, which aids orthogonality). Added support
for strings in the parser. I should probably do a more systematic set of escape
sequences; as it is I only have \n, \\ and \".

Mon  8th Oct 2007               Examples/sos.ml

I'd noticed that my REAL_SOSFIELD was in step with an earlier mistaken
optimization of REAL_FIELD, which generated fewer cases but was not in general
complete. It probably doesn't matter, but now it's fixed.

Mon  8th Oct 2007               Examples/sos.ml

I wanted to take a careful look at the iterative deepening I was doing in SOS
w.r.t. strict inequalities to make absolutely sure that it was indeed
theoretically complete. It does seem all right in principle, though I can think
of other state space explorations that might be more efficient to try. But
anyway I did spot one little error in the case where there are no strict
inequalities in the hypotheses. Changed maximal degree of the polynomial to
consider from 0 to 1, since otherwise one is simply duplicating work. From

    let k = if e = 0 then 1 else d / e in

to

    let k = if e = 0 then 0 else d / e in

Tue 11th Sep 2007               basics.ml

Removed duplicate definitions of "dest_forall" and "strip_forall" inside the
"dest_gabs" function. These were, I guess, a relic of the time when these
functions too were defined in "bool.ml", as "mk_forall" still is. This was
pointed out by Viorel Preoteasa.

Tue 11th Sep 2007               ind-types.ml

Added UNWIND_CONV (which was useful as a subroutine in the following, and seems
useful enough to expose) and MATCH_CONV to reduce matches applied to specific
cases. Also added the "simple" case of MATCH_CONV, where an unambiguous
reduction is achieved automatically, to the default conversions.

Sat  8th Sep 2007               ind-defs.ml, sets.ml, recursion.ml

Added a list "the_inductive_definitions" and associated benignity checking.
This was a reaction to the observation by Norbert Voelker that reloading
"sets.ml" gives an error because of the inductive definition of FINITE. (For
extra credit, I could search for redefinition in exactly the same form with
variables in the input, in case it's generated other than by the quotation
parser.) However, I had also to add a type constraint to make sure the types in
the empty and insert claises really are the same and hence it is an instance.
I also discovered I still need benignity checking in "recursion.ml" to handle
FINREC. So I added that too, though didn't expose the theorem list in this
case. And once again I needed to add a type constrain (many from "list.ml"
won't work because the types are insufficiently constrained). All a bit crude
and inadequate, but it does solve the top-level problem: "sets.ml" *can* now be
reloaded.

Fri  7th Sep 2007               Examples/prover9.ml [new file]

Added to the standard release the simple prover9 interface I hacked up at
Marktoberdorf and slightly refined more recently. It could still use more work
(e.g. a disjunctive splitter, and more systematic treatment of "pure equality
islands") but it's nice to have.

Fri  7th Sep 2007               Examples/update_database.ml

Switched the load order of "env.cmo" and "clflags.cmo", so the latter now comes
first. This seems to be necessary for 3.10.0?

Fri  7th Sep 2007               Examples/pratt.ml, Examples/pocklington.ml

Renamed the image name just "gp" not "parigp", which seems to be what it (now)
is OOTB.

Fri  7th Sep 2007               make.ml

Added (and documented) a "checkpoint" function to create a checkpoint with
CryoPID. This is a temporary compromise since I have trouble getting it to work
cleanly in a batch build.

Wed  5th Sep 2007               hol.ml, passim

Changed "temp_path" to read the OCaml Filename.temp_dir_name at the outset,
though the user can set it. Also modified a few bits and pieces to use this
interface consistently (e.g. SOS and Minisat) where previously there was a
hardwired "/tmp" pathname.

Tue  4th Sep 2007               preterm.ml

Added some error traps to produce a "Typechecking error" report rather than the
less helpful "not found".

Mon  3rd Sep 2007               tactics.ml

Put in a fix for an assumption of equality instead of alpha-convertibility of
hypotheses into VALID, which indirectly affects "e". Previously, for example,
if a goal had an assumption `!x. x = 1`, then using ASSUME(`!z. z = 1`) would
give a validty failure. Possibly a more systematic approach would be to replace
each "union" with "term_union", but I wanted to be minimally invasive.

Mon  3rd Sep 2007               printer.ml

Fixed something pointed out by Carl Witty a while ago: a construct `DECIMAL mmm
nnn` where nnn is a numeral but not a power of 10 prints misleadingly, e.g.
`DECIMAL 99 77` as `#.19`.

Mon  3rd Sep 2007               preterm.ml, parser.ml

Added a warning if something starting with a digit is not a valid numeral, e.g.
`0xgh` or `0b12`. It seems unintuitive to parse this as a variable without any
warning. To support this change I moved the character discrimination functions
back from "parser.ml" to "preterm.ml".

Mon  3rd Sep 2007               bool.ml

Recoded IMP_TRANS and EQ_IMP_RULE with more elaborate versions that correspond
exactly (I hope) to their specification, taking the union of the assumption
list even if some of the implication components are in the assumptions; with
the old implementations one could sometimes get fewer assumptions. The case of
IMP_TRANS was pointed out on info-hol by Tony Johnson (complaining about HOL4,
but it also applies to HOL Light), and I noticed a similar problem with
EQ_IMP_RULE when I dived in to fix that.

Mon  3rd Sep 2007               printer.ml

Modified the printer so it prints parentheses exactly round generalized
varstructs and not regular ones. This fixes one flat bug where an iterated
mixture of generalized and non-generalized abstractions would print without the
parentheses necessary to re-parse the same thing, e.g. `\x y,z. bod` instead of
`\x (y,z). bod`. It also seems nice to have a visual cue that generalized and
non-generalized abstractions differ even in the unit variable case. I would
have liked to establish the same thing on input, but that's not completely
trivial given that for a long time things exist as preterms and only get mapped
to any sort of abstraction later on.

Fri 31st Aug 2007               tactics.ml

Fixed a bug in the printing of goalstacks where the boxes inside hypotheses
were getting offset by 2, e.g.

 1 [`i IN 1 .. dimindex (:?162964) /\
       j IN 1 .. dimindex (:?162964) /\
       ~(i = j)`]

It turns out I'd misunderstood what "print_as" does: it doesn't print a string
in a fixed field but just sets the counts as if it did. So I added my own
custom function to print the assumption number padded up to 3 digits if it
would otherwise be shorter.

Fri 31st Aug 2007               make.ml

Thanks to an email from Vic Zandy, I finally solved the problem of incorrect
PIDs on recent Linuxes. The issue seems to be that the glibc implementation of
getpid is cacheing the PID in userspace, so all you have to do is use some
other method of getting the PID. Vic suggested reading /proc/self/stat, but for
my application it's even easier to look at $PPID. Also, experimenting on
Knoppix I found that adding a 1-second sleep before the kill call deals with
the intermittent race issue. I don't really understand this but I put it in
anyway.

Thu 30th Aug 2007               basics.ml, equal.ml

Changed "mk_primed_var" so that it ignores hidden constants. This entailed
moving it forward a bit till after the "hide" stuff, and therefore I moved it
from "basics.ml" to "equal.ml".

Thu 30th Aug 2007               lib.ml, grobner.ml, help.ml, meson.ml, tactics.ml

A suggestion from Jesse Alama was a quiet loading mode. When experimenting
with this I noticed quite a few places where I used raw "print_string" (and
occasionally "print_newline" and maybe others) instead of their Format
versions, so fixed that for consistency.

Tue 28th Aug 2007       parser.ml

Fixed a bug in pfrees where "can int_of_string" actually built in a size
limitation so large numerals would be treated as variables! Now uses
"num_of_string" instead.

Tue 28th Aug 2007       parser.ml, pair.ml, printer.ml

Added OCaml-like pattern-matching constructs to the parser, together with
definitions in "pair.ml" for the supporting constants _SEQPATTERN,
_UNGUARDED_PATTERN, _GUARDED_PATTERN, _MATCH and _FUNCTION. The main
incompatible change is making the following reserved words:

  match   with   function   ->   when

Tue 28th Aug 2007       parser.ml

Modified the "nocommapreterm" so it won't fail if "," doesn't have infix parse
status (just a trivial little bug I noticed).

Tue 28th Aug 2007       realarith.ml

Changed some quotations in GEN_LINEAR_PROVER to force them to evaluate here.
Although they get partially evaluated anyway when this is applied to the first
argument (like LINEAR_PROVER), that still introduces a nasty dependency on the
overload prioritization, and I hit this while checking Lars's more general
code, discovering that with prioritize_int() set even "GEN_REAL_ARITH
REAL_LINEAR_PROVER tm" fails.

Mon 27th Aug 2007       meson.ml

Removed the default "time" inside the core function so it doesn't automatically
report CPU times; I felt the output was already quite verbose enough.

Fri 24th Aug 2007       int.ml

Fixed bug of using int_sub instead of INT_SUB in the definition of
INT_RED_CONV, which was causing evaluation of integer constant expressions to
fail. This and the last item while getting my car serviced.

Fri 24th Aug 2007       Examples/integer.ml [new file]

Put in a convenient place the basic development of divisibility properties over
Z. Much of it is automatic with INTEGER_TAC but some slightly tedious hacking
is needed for signs of GCDs and suchlike.

Fri 24th Aug 2007       fusion.ml

Added back an internal list of definitions (called "the_definitions", but not
exported and distinct from the same thing defined later) and a function
"definitions" to get at them. Mark Adams pointed out that otherwise you can't
distinguish axioms that should be sound from those that aren't because they
clash with definitions.

Thu 23rd Aug 2007       sets.ml

Added two theorems that I can hardly believe I'd never wanted before:

  CARD_DIFF =
    |- !s t. FINITE s /\ t SUBSET s ==> CARD(s DIFF t) = CARD s - CARD t

  HAS_SIZE_DIFF =
    |- !s t m n.
           s HAS_SIZE m /\ t HAS_SIZE n /\ t SUBSET s
           ==> s DIFF t HAS_SIZE m - n

Sun 29th Jul 2007       Makefile, hol.ml

Modified things so that camlp5 more or less automatically gets used if
the OCaml version is >= 3.10. Also reduced the proliferation of pa_j
files by employing "cut" on the version number to look at the major
number only.

Wed 25th Jul 2007       real.ml, int.ml

Added REAL_LT_SQUARE_ABS = |- !x y. abs x < abs y <=> x pow 2 < y pow 2
  and INT_LT_SQUARE_ABS = |- !x y. abs x < abs y <=> x pow 2 < y pow 2

Mon 23rd Jul 2007       iter.ml, passim

Added a theorem from Lars Schewe, though this time with a different proof using
SUM_POS_EQ_0.

 SUM_ZERO_EXISTS =
  |- !u s.
         FINITE s /\ sum s u = &0
         ==> (!i. i IN s ==> u i = &0) \/
             (?j k. j IN s /\ u j < &0 /\ k IN s /\ u k > &0)

Added Lars to copyright for this file and took the chance to update all the
others from "2006" to "2007".

Mon 23rd Jul 2007       hol.ml and a few others

Changed HOLDIR to HOLLIGHT_DIR at Hasan's request, to make it easier to
work in a multi-HOL environment.

Mon 23rd Jul 2007       Minisat/zc2mso [new directory]

Added Hasan's new "zc2mso" translator, the C++ source and README. Also
slightly modified the main README to point out its existence.

Fri 13th Jul 2007       real.ml

Added

  REAL_LE_MUL_EQ =
   |- (!x y. &0 < x ==> (&0 <= x * y <=> &0 <= y)) /\
      (!x y. &0 < y ==> (&0 <= x * y <=> &0 <= x))

  REAL_LT_MUL_EQ =
   |- (!x y. &0 < x ==> (&0 < x * y <=> &0 < y)) /\
      (!x y. &0 < y ==> (&0 < x * y <=> &0 < x))

Wed 11th Jul 2007       sets.ml

Fixed FINITE_RESTRICT to |- !s P. FINITE s ==> FINITE {x | x IN s /\ P x}
instead of vacuous quantifeer |- !s p. FINITE s ==> FINITE {x | x IN s /\ P x}
as pointed out by Lars Schewe.

Wed 11th Jul 2007       iter.ml

Added some new theorems about sums, based on Lars Schewe's files, and using
some of the same proofs modulo trivial changes. First of all, renamed the old

 ITERATE_CASES -> ITERATE_EXPAND_CASES

in order to make the more natural namespace available. Then added

  ITERATE_INCL_EXCL =
    |- !op. monoidal op
            ==> (!s t f.
                     FINITE s /\ FINITE t
                     ==> op (iterate op s f) (iterate op t f) =
                         op (iterate op (s UNION t) f)
                         (iterate op (s INTER t) f))

  ITERATE_CASES =
    |- !op. monoidal op
            ==> (!s P f g.
                     FINITE s
                     ==> iterate op s (\x. if P x then f x else g x) =
                         op (iterate op {x | x IN s /\ P x} f)
                         (iterate op {x | x IN s /\ ~P x} g))

as well as versions for natural number sums

  NSUM_INCL_EXCL =
    |- !s t f.
           FINITE s /\ FINITE t
           ==> nsum s f + nsum t f = nsum (s UNION t) f + nsum (s INTER t) f
  NSUM_CASES =
    |- !s P f g.
           FINITE s
           ==> nsum s (\x. if P x then f x else g x) =
               nsum {x | x IN s /\ P x} f + nsum {x | x IN s /\ ~P x} g

and real sums:

  SUM_INCL_EXCL =
    |- !s t f.
           FINITE s /\ FINITE t
           ==> sum s f + sum t f = sum (s UNION t) f + sum (s INTER t) f
  SUM_CASES =
    |- !s P f g.
           FINITE s
           ==> sum s (\x. if P x then f x else g x) =
               sum {x | x IN s /\ P x} f + sum {x | x IN s /\ ~P x} g

Wed 11th Jul 2007       calc_rat.ml, Complex/complex.ml

Undid the change to the two FIELD rules made on 23rd Feb 06, though keeping the
two later tweaks (inverse-inverse and checking freeness). The problem is that
sometimes the "inefficient" case split is necessary to pick up correlations
between nonzeroness assumptions. I thought this was more important than
efficiency. For example, the following previously failed:

  REAL_FIELD `~(c = &0) /\ ~(c' = &0) /\
              ~(c * c' - s * s' = &0)
              ==> (s * c' + c * s') / (c * c' - s * s') =
              (s / c + s' / c') / (&1 - s / c * s' / c')`;;

even though both the following worked:

  REAL_FIELD `~(c = &0) /\ ~(c' = &0) /\
              ~(c * c' - s * s' = &0) /\
              ~(&1 - s / c * s' / c' = &0)
              ==> (s * c' + c * s') / (c * c' - s * s') =
              (s / c + s' / c') / (&1 - s / c * s' / c')`;;

  REAL_FIELD `~(c = &0) /\ ~(c' = &0) /\
              ~(c * c' - s * s' = &0)
              ==> ~(&1 - s / c * s' / c' = &0)`;;

Now they all work, albeit a bit more slowly.

Wed 23rd May 2007       Multivariate/vectors.ml

Installed NORM_ARITH in the main file and already used it in several places in
place of explicit proofs.

Tue 22nd May 2007       Examples/sos.ml

Added a little wrapper REAL_NONLINEAR_SUBST_PROVER round
REAL_NONLINEAR_PROVER, which tries to first substitute variables in equations.
This must almost invariably be a good idea. The particular motivation was the
application of Solovay's procedure to the triangle law, which gives rise to the
real problem:

  |- &0 <= c /\
     &0 <= z /\
     z pow 2 = h pow 2 * d + c /\
     &0 <= y /\
     y pow 2 = d /\
     &0 <= x /\
     x pow 2 = d + &2 * h * d + h pow 2 * d + c /\
     y + z < x
     ==> F

With the substitution this takes about 18 seconds; without it about 180. So
here it's worthwhile, and I guess this is true more generally.

Tue  1st May 2007       simp.ml

Well, backed off that change for a while, since it broke things in
Jordan/metric_spaces.ml and I ended up not really using it myself.

Tue 24th Apr 2007       simp.ml

Modified ONCE_DEPTH_SQCONV and ONCE_SIMPLIFY_CONV so that the prover list in
the subcalls is modified to try assumption if all else fails. Then modified
ONCE_SIMP_TAC (and so implicitly ONCE_ASM_SIMP_TAC) so that they handle the
possible new assumption and split it off as a subgoal. The net effect, I hope,
is that ONCE_SIMP_TAC will now actually be useful for cases where you really
want to split off the lemma.

Tue 13th Mar 2007       iter.ml

Added SUM_DELETE_CASES =
  |- !f s a.
         FINITE s
         ==> sum (s DELETE a) f = (if a IN s then sum s f - f a else sum s f)

Tue 13th Feb 2007

Added a theorem that only recently occurred to me; it can occasionally be
useful not to have to discharge a nonnegativity assumption when the exponent is
odd.

 REAL_POW_LE2_ODD = |- !n x y. x <= y /\ ODD n ==> x pow n <= y pow n

Added the counterpart for the integers and also some other theorems I seem to
have forgotten to transfer:

  INT_LE_SQUARE_ABS = |- !x y. abs x <= abs y <=> x pow 2 <= y pow 2
  INT_SOS_EQ_0 = |- !x y. x pow 2 + y pow 2 = &0 <=> x = &0 /\ y = &0
  INT_POW_LE2_ODD = |- !n x y. x <= y /\ ODD n ==> x pow n <= y pow n

Sat  3rd Feb 2007        tactics.ml

Realized I'd put the tweaked error message only in a place where failure will
occur if there is a current goal but it has no subgoals. Reworded that one
slightly and added it where I should have, in "refine".

Thu  1st Feb 2007       iter.ml

Added SUM_DIFFS =
  |- !m n.
         sum (m..n) (\k. f k - f (k + 1)) =
         (if m <= n then f m - f (n + 1) else &0)

Wed 31st Jan 2007       itab.ml

Made a small tweak to the G3 implementation, which I noticed when reminding
myself about stuff in order to answer a question on hol-info. In the
left-implication rule, I was using FIRST_ASSUM, but it should/could be
FIRST_X_ASSUM, I guess.

Wed 31st Jan 2007       Makefile

Added "hol.complex" to the Makefile, since I'm using it heavily at the moment,
and it's becoming non-trivial.

Wed 31st Jan 2007       parser.ml, tactics.ml

Changed some annoying error messages, the "unexpected junk" to "unparsed input"
and also a more informative error than "hd" when trying to apply a tactic with
no goals.

Mon 22nd Jan 2007       simp.ml

Fixed a plain bug in ABBREV_TAC which failed when abbreviations had more
than one argument due to a trivial blunder.

Sun 21st Jan 2007       sets.ml

Added a suite of theorems to capture a pattern of reasoning I seem to go
through very often:

  TRANSITIVE_STEPWISE_LE =
    |- !R. (!x. R x x) /\
           (!x y z. R x y /\ R y z ==> R x z) /\
           (!n. R n (SUC n))
           ==> (!m n. m <= n ==> R m n)

  TRANSITIVE_STEPWISE_LT =
    |- !R. (!x y z. R x y /\ R y z ==> R x z) /\ (!n. R n (SUC n))
           ==> (!m n. m < n ==> R m n)

  TRANSITIVE_STEPWISE_LE_EQ =
    |- !R. (!x. R x x) /\ (!x y z. R x y /\ R y z ==> R x z)
           ==> ((!m n. m <= n ==> R m n) <=> (!n. R n (SUC n)))

  TRANSITIVE_STEPWISE_LT_EQ =
    |- !R. (!x y z. R x y /\ R y z ==> R x z)
           ==> ((!m n. m < n ==> R m n) <=> (!n. R n (SUC n)))

Sat 20th Jan 2007       sets.ml

Added IMAGE_UNIONS = |- !f s. IMAGE f (UNIONS s) = UNIONS (IMAGE (IMAGE f) s)

Tue 16th Jan 2007       iter.ml

Added four new theorems relevant to iterated operations:

  MONOIDAL_AC =
    |- !op. monoidal op
            ==> (!a. op (neutral op) a = a) /\
                (!a. op a (neutral op) = a) /\
                (!a b. op a b = op b a) /\
                (!a b c. op (op a b) c = op a (op b c)) /\
                (!a b c. op a (op b c) = op b (op a c))

  ITERATE_OP =
    |- !op. monoidal op
            ==> (!f g s.
                     FINITE s
                     ==> iterate op s (\x. op (f x) (g x)) =
                         op (iterate op s f) (iterate op s g))
  ITERATE_SUPERSET =
    |- !op. monoidal op
            ==> (!f u v.
                     u SUBSET v /\
                     (!x. x IN v /\ ~(x IN u) ==> f x = neutral op)
                     ==> iterate op v f = iterate op u f)

  ITERATE_IMAGE_NONZERO =
    |- !op. monoidal op
            ==> (!g f s.
                     FINITE s /\
                     (!x y.
                          x IN s /\ y IN s /\ ~(x = y) /\ f x = f y
                          ==> g (f x) = neutral op)
                     ==> iterate op (IMAGE f s) g = iterate op s (g o f))

The penultimate one made me realize that the finiteness condition on
NSUM_SUPERSET and SUM_SUPERSET was superfluous, so I removed it.

Mon 15th Jan 07         pair.ml, wf.ml, Examples/hol88.ml, passim

Retired PAIRED_BETA_CONV, moving it from "pair.ml" just into the HOL88
compatibility files. In a handful of modern proofs scrubbed it when it's now
subsumed by rewrites; in older files mechanically changed to "GEN_BETA_CONV".
In the process, I've quietly generalized let_CONV to work over other varstructs
subject to analogous restrictions to the pair instance.

Mon 15th Jan 07         class.ml, trivia.ml, pair.ml, num.ml, ind-types.ml

Changed "inductive_type_store" to be built up one at a time as the new types
are added, really just so that GEN_BETA_CONV on pairs already works inside
the pairs file plus a bit of intellectual consistency.

Mon 15th Jan 07         pair.ml

Added LAMBDA_PAIR_THM = |- (\p. P p) = (\(x,y). P (x,y))

Mon 15th Jan 07         iter.ml

Added the following suite, which are just tedious enough not to want to derive
by hand when needed:

  ITERATE_UNION_NONZERO =
    |- !op. monoidal op
            ==> (!f s t.
                     FINITE s /\
                     FINITE t /\
                     (!x. x IN s INTER t ==> f x = neutral op)
                     ==> iterate op (s UNION t) f =
                         op (iterate op s f) (iterate op t f))

  NSUM_UNION_NONZERO =
    |- !f s t.
           FINITE s /\ FINITE t /\ (!x. x IN s INTER t ==> f x = 0)
           ==> nsum (s UNION t) f = nsum s f + nsum t f

  SUM_UNION_NONZERO =
    |- !f s t.
           FINITE s /\ FINITE t /\ (!x. x IN s INTER t ==> f x = &0)
           ==> sum (s UNION t) f = sum s f + sum t f

Sat 13th Jan 07         iter.ml

Added the following; I already have the vector version, and I didn't yet decide
to add the natural number version. Should really do a generic one.

SUM_IMAGE_NONZERO =
  |- !d i s.
         FINITE s /\
         (!x y. x IN s /\ y IN s /\ ~(x = y) /\ i x = i y ==> d (i x) = &0)
         ==> sum (IMAGE i s) d = sum s (d o i)

Thu 11th Jan 07         sets.ml

Added another theorem:

  INTER_UNIONS =
    |- (!s t. UNIONS s INTER t = UNIONS {x INTER t | x IN s}) /\
       (!s t. t INTER UNIONS s = UNIONS {t INTER x | x IN s})

Wed 13th Dec 06         Examples/hol88.ml, Examples/analysis.ml

Fixed bugs in the local MK_ABS and MK_EXISTS (which is not the usual version).
In both cases they had SUB_CONV instead of BINOP_CONV; this was formerly masked
because until I recoded it, SUB_CONV would quietly return a reflexive theorem
if the core conversion failed.

Thu  7th Dec 06         term.ml

Again inspired by work on Holst, recoded "vsubst" to avoid using set
operations, via a generalization of "variant" (and consequently "variants" too)
to avoid all free variables of the terms in the avoid list. This is doubly
nicer since it avoids set operations and corresponds better to what I've
actually verified in Model; those could be brought closer in step. Also,
orthogonally really, made Boultonization work properly in the abstraction case.

Wed  6th Dec 06         Examples/sos.ml

Recoded REAL_NONLINEAR_PROVER to do a better job with trivial hypotheses. This
was stimulated by a failure Laurent hit experimenting with the Coq port:

  REAL_SOS
   `&0 <= (r - r1) * (r1 - r) ==>
    &0 <= (r0 - r2) * (r2 - r0) ==>
    r1 * (r0 - r2) + r * (r2 - r2) + r1 * (r2 - r0) = &0 ==> r1 - r = &0`;;

The fact that one hypothesis is trivial caused all the parameters of the ideal
cofactor to "disappear" and give lookup failures afterwards.

Tue 28th Nov 06         bool.ml

Recoded GEN in a more elegant and efficient way. The old version was an MP
relic, and it didn't do alpha-conversion very cleverly. Also tweaked EXISTS to
use PROVE_HYP rather than MP. Nearly did the same to CHOOSE, but I was getting
too tired to figure out for sure whether we can guarantee that PROVE_HYP will
be non-trivial (all this is on the train back to Nice). Did do the same to
DISJ1 and DISJ2; also fixed the exception from the latter, which was a
cut-and-paste error of "DISJ1", and a similar one in "NOT_INTRO" which was a
cut-and-paste "NOT_ELIM".

Tue 28th Nov 06         equal.ml

Recoded SUB_CONV, BINOP_CONV and DEPTH_BINOP_CONV to be a little more delicate,
not that it really matters.

Mon 20th Nov 06         define.ml

Added clauses to scrub distinctness theorems of the form "2 * n + 1 = 2 * m +
1". This was a bit ad hoc to make "recounting the rationals" work as given, but
it's reasonable as a general idea.

Sun 19th Nov 06         thm.ml

Recoded several primitive rules to use pattern-matching rather than the
destructor functions. The efficiency gain seems real though unspectacular
(around 4%) and in any case the result is slightly shorter and arguably
clearer.

Sun 19th Nov 06         thm.ml

Changed "rator" and "rand" to use pattern-matching. Also noticed this as a
result of Holst.

Fri 17th Nov 06         term.ml

Slightly recoded variant to use pattern-matching and the Var constructor
directly (might as well since we're here!) Came across these while starting
Holst on the train from Nice to Lyon.

Mon 23rd Oct 06         iter.ml

Fixed some faulty trivial quantifiers in NUMSEG_COMBINE_L and NUMSEG_COMBINE_R,
pointed out by Lars Schewe.

Mon  9th Oct 06         lib.ml, nets.ml

Decommissioned the orderings like "=?" and "<?", using explicit
Pervasives.compare calls in their place. In some cases, this allows a bit of
computation re-use anyway, and even without it, there must be some minor
performance benefits to not adding an extra layer of function calls.

Mon  9th Oct 06         lib.ml

Fixed a bug/feature in FPF application where the branches would be followed as
far as the leaf without checking in the process whether the prefix agrees with
the hash. This may make successful applications a constant factor slower (about
15% in some tests), but should often make unsuccessful ones much faster.

Also removed the symmetry requirement from "combine" by just adding two cases
for the two branches that were hacked into one.

Mon  9th Oct 06         iter.ml

Added NUMSEG_CONV to evaluate m..n for specific numerals m and n.

Mon  9th Oct 06         drule.ml

Slightly recoded the core function in "term_match" to use pattern-matching. It
does seem slightly faster, though I was hoping for a more substantial speedup
in "search".

Thu  5th Oct 06         term.ml

Bravely, made a change in alpha-conversion, motivated by the experiments with
Hasan's Minisat interface using full-size terms instead of the abbreviating
variables. The first "conceptual" change is that I just do a pure single
traversal, testing pointer eq as I go, rather than having a completely separate
equality test, which is crude. (And of course I need to check emptiness of
environment as well as pointer EQ --- could generalize to identity but it is
worth it? Also could avoid reflexive entries, for that matter, but that would
need a theorem to justify it.) The other change is the minor implementation
detail of making the underlying "alphavars" and "raconv" unpaired; that turns
out to make quite a significant difference too!

Thu  5th Oct 06         passim

Fixed a lot of "unused variables" (sometimes just "as" in patterns, but
sometimes real computation). In one case in ABBREV_TAC, actually realized I
should have been using the variable to avoid repeated recomputation.

Wed  4th Oct 06         ind-types.ml

Fixed a bug pointed out by Sean where failed calls to "define_type" could still
define types and constants before the point of failure, spoiling a repeat
invocation with corrections. The fix was simply to check for various things
upfront before diving into the definition.

Tue  3rd Oct 06         doc-to-help.sed

Added a few lines to make a natural textual translation of "itemize" constructs
and of "{\em word}".

Tue  3rd Oct 06         help.ml

Added the "search" function and the query constructors "omit", "exactly" and
"name". I did consider "left" and "right" but I'm not yet convinced it's worth
the effort.

Tue  3rd Oct 06         help.ml, database.ml [new file], Examples/update_database.ml

Added an assignable variable "theorems" (in help.ml), an appropriate list for
the core system (database.ml), and a library file to create updated versions of
the database file, and optionally load them in directly.

Tue  3rd Oct 06         lib.ml, Examples/pratt.ml, Examples/pocklington.ml, Examples/sos.ml

Added "strings_of_file", "string_of_file" and "file_of_string", which seem
generally useful. Replaced some ad-hoc uses elsewhere with these functions.

Mon 18th Sep 06         ind-types.ml

Replaced the original with a new variant due to Hasan: he noticed that in (the
use of) SCRUB_EQUATION I use the ordering of assumptions, and so lose the
possibility of using other data structures (trees, even sorted lists) for
assumptions. His solution looks quite non-invasive so I just adopted it.

Mon 18th Sep 06         Minisat [new directory]

Made a few minor tweaks to Hasan's Minisat interface and rolled it into the
release.

Sat 16th Sep 06         calc_rat.ml, Examples/sos.ml

Added REAL_SOSFIELD, which does the same kind of preprocessing as REAL_FIELD
(slightly more since it actually substitutes new variables for the inverse
terms to better suit the underlying rule) and then tries REAL_SOS in the mix.
It does work on some elementary examples, like these (the last one would have
essentially solved the second subgoal for the ICMS demo session).

  REAL_SOSFIELD `&0 < x /\ &0 < y ==> &0 < x / y`;;
  REAL_SOSFIELD `&0 <= x /\ &0 < y ==> &0 <= x / y`;;
  REAL_SOSFIELD `&1 < y /\ ~(z = &0) /\ abs z <= x ==> ~(x <= x / y)`;;

I also noticed that there's an unused expression in the existing REAL_FIELD (I
must have condensed it into the next expression and not deleted the
abbreviation) which I deleted.

Thu 13th Jul 06         bool.ml, calc_int.ml, calc_rat.ml, sys.ml, hol.ml, Examples/poly.ml

Fixed the permissions on these files, which were unreadable for "other" users.
This was pointed out by Nobuki Takayama as part of the ICMS preparation.

********************** RELEASE OF VERSION 2.20 **********************

Wed 17th May 06         tactics.ml

After doing enough regression testing (particularly no changes at all to the
Jordan proof), I plucked up the courage and inserted the new CONJUNCTS_THEN2
implementation which ASSUMEs the two conjuncts. I hope this will be a less
invasive way of counteracting the counterintuitive effects of spurious free
variables "hiding" in the goal.

Wed 17th May 06         class.ml

Added a quite distinct benignity mechanism and a list "the_specifications" (the
old one was lost in the last change and perhaps wasn't entirely satisfactory
since the original plan was not to expose the underlying definition).

Wed 17th May 06         drule.ml, pair.ml

Moved all the benignity, including the definition of the initial (now somewhat
larger) list "the_definitions", into "pair.ml" so it directly returns the
theorems from that, which is what's mainly used later.

Tue 16th May 06         drule.ml

Changed "the_definitions" to be as entered by the user, since Steve Brackin
preferred this and I don't have any reason for this other than checking
benignity.

Tue 16th May 06         realax.ml

Changed one proof not to rely on the fact that CONJUNCTS_THEN doesn't use
ASSUMEd conjuncts. This is in the hope that I may actually manage to switch
over to that, avoiding most of the confusion currently caused.

Fri 12th May 06         parser.ml

Changed the internal definition of "pfrees" used in set abstractions to check
also whether some name has an interface mapping and if so count it as a
constant. Otherwise there could be issues with overloaded constants being
treated as variables in set abstractions, e.g.

 `onorm (f:real^M->real^N) = sup { norm(f x) | norm(x) = &1 }`;;

Fri 12th May 06         preterm.ml

Added a flag "type_invention_warning" to control the "inventing type variables"
warning. This was inspired by Cezary, who wanted to disable these warnings and
had rewritten some of the code himself to remove it; this would now have
required even more duplicate-and-tweak now that "stvs_translated" is hidden.

Thu 11th May 06         realax.ml

Removed "real_lift_function", replacing the only uses by mapping the definition
over lists.

Thu 11th May 06         define.ml

Renamed "pure_prove_general_recursive_function_exists" as simply
"pure_prove_recursive_function_exists". The name was too long for the reference
manual banner. Of course that's not such a good reason...

Thu 11th May 06         tactics.ml

Hid "print_hyp" and "print_hyps" inside "print_goal" and "print_goalstate"
inside "print_goalstack".

Thu 11th May 06         realax.ml

Also removed "real_lift_theorem", replacing the only use by its definition.

Thu 11th May 06         drule.ml

Hid "match_bvs" inside "PART_MATCH"; it was not used anywhere else. And hid
"tryalpha" inside "deep_alpha". And deleted "unify_terms". I'm a bit mystified
why that's there as well as "term_unify"; the latter is at least used!

Wed 10th May 06         simp.ml, Examples/mizar.ml

Removed LIMITED_REWRITE_CONV, which was an egregious hack, and put in in
Examples/mizar.ml, which contains the only use of it.

Wed 10th May 06         thm.ml, meson.ml

Removed "le_thm" and replaced the one application with its definition.

Wed 10th May 06         realax.ml

Hid "hreal_lift_fn" and "hreal_lift_thm".

Wed 10th May 06         simp.ml

Hid GEN_SUB_CONV, IMP_REWRITES_CONV and RUN_SUB_CONV.

Wed 10th May 06         parser.ml

Added a "string" type constraint into "install_parser", which otherwise has an
undetermined type for the tags.

Wed 10th May 06         ind-types.ml

Removed RECTYPE_EQ_CONV, which was never used in the latest "define".

Wed 10th May 06         bool.ml, passim

Added "mk_iff" and "dest_iff" and renamed "is_beq" to "is_iff". Pity to make an
incompatible change but it seems far more intuitive.

Wed 10th May 06         ind-types.ml

Again hid a lot of internal stuff:

sucivate, SCRUB_EQUATION, justify_inductive_type_model,
prove_model_inhabitation, define_inductive_type,
define_inductive_type_constructor, instantiate_induction_theorem,
pullback_induction_clause, finish_induction_conclusion,
derive_induction_theorem, create_recursive_functions,
create_recursion_iso_constructor, derive_recursion_theorem,
generalize_recursion_theorem, define_type_mutual, TRIV_ANTE_RULE,
ISO_EXPAND_CONV, lift_type_bijections, DE_EXISTENTIALIZE_RULE, grab_type,
clause_corresponds, prove_inductive_types_isomorphic, SCRUB_ASSUMPTION,
define_type_basecase, SIMPLE_BETA_RULE, ISO_USAGE_RULE, SIMPLE_ISO_EXPAND_RULE,
REWRITE_FUN_EQ_RULE, define_type_nested.

What used to be called "define_type_nested" is now called "define_type_raw"
(which was formerly a limited and not specially useful version used in
bootstrapping).

Wed 10th May 06         preterm.ml, parser.ml

Hid the following "internal" things: new_type_var, reset_type_num [actually
deleted that completely], pretype_subst, pretype_instance, get_generic_type,
istrivial, unify, typify, resolve_interface, solve, solve_preterm and
stvs_translated.

Removed pmk_eq, pmk_conj and split_ppair.

Hid pmk_let, pmk_set_enum, pfrees, pmk_setabs, pmk_setcompr, pmk_vbinder,
pmk_binder, pmk_cv, pmk_numeral, pgenvar, split_ppair, pmk_conj, pmk_exists.

Added a few of these needed back to Examples/mizar.ml.

Wed 10th May 06         lib.ml, preterm.ml

Moved "num_of_string" from "preterm.ml" to "lib.ml". It seemed an unnatural
fit, even though its primary purpose is indeed for parsing etc.

Tue  9th May 06         parser.ml

Hid "mk_precedence" and "parse_typed_apreterm", which seemed a bit too ad hoc.

Tue  9th May 06         meson.ml

Removed two less useful flags: "precheck" and "cache"; in neither case is it
really plausible that they'll be changed.

Renamed others with too-short names: depth, prefine, dcutin, skew and brand to
meson_depth, meson_prefine, meson_dcutin, meson_skew and meson_brand.

Hid a whole bunch of internal things in MESON:

offinc, inferences, qpartition, reset_vars, fol_of_var, hol_of_var,
reset_consts, fol_of_const, hol_of_const, fol_of_term, fol_of_atom,
fol_of_literal, fol_of_form, hol_of_term, hol_of_atom, hol_of_literal,
fol_free_in, fol_frees, fol_subst, fol_substl, fol_inst, fol_subst_bump,
fol_inst_bump, istriv, fol_unify, fol_eq, cacheconts, checkan, insertan,
fol_subst_partial, separate_insts, meson_single_expand, meson_expand_cont,
meson_expand, expand_goal, solve_goal, fol_of_hol_clauses, optimize_rules,
clear_contrapos_cache, make_hol_contrapos, meson_to_hol,
create_equality_axioms, perform_brand_modification, POLY_ASSUME_TAC,
SIMPLE_MESON_REFUTE, PURE_MESON_TAC, QUANT_BOOL_CONV, SPLIT_TAC.

Mon  8th May 06         define.ml

Removed "closed_prove_general_recursive_function_exists", which seemed a bit
overspecialized and confusing.

Hid various functions inside prove_general_recursive_function_exists, namely:
prove_depth_measure_exists, INDUCTIVE_MEASURE_THEN, CONSTANT_MEASURE_THEN,
GUESS_MEASURE_THEN, GUESS_WF_THEN, and GUESS_ORDERING_TAC.

Hid "EXPAND_PAIRED_ALL_CONV", "SIMPLIFY_CASE_DISTINCTNESS_CLAUSES" and
"FORALL_PAIR_CONV" inside "instantiate_casewise_recursion".

Hid "tuple_function_existence", "is_applicative", "LAMBDA_PAIR_CONV" and
"break_down_admissibility" inside
"pure_prove_general_recursive_function_exists".

Hid "close_definition_clauses" inside "define".

Mon  8th May 06         define.ml, pair.ml

Moved GABS_CONV back to "pair.ml", since it seems relatively natural and
generally useful; I'm planning to hide most other internal functions in the
"define" stuff. Also made it work on standard abstractions too, otherwise it's
a bit unnatural as a general building-block.

Fri  5th May 06         Proofrecording/diffs/*.ml

Carefully went through making sure I'd changed the "copies" inside the
Proofrecording library to keep them perfectly in step (modulo only the
necessary changes) with the current core. Actually, every single file had at
least cosmetic changes required.

Thu  4th May 06         equal.ml

Inspired by Steve Brackin's question on info-hol, generalized PAT_CONV so you
can have multiple position-identifying variables.

Thu  4th May 06         class.ml

Changed "subst" to "vsubst" inside SELECT_CONV, which is trivial but will save
a tiny bit of time.

Thu  4th May 06         canon.ml, class.ml

Moved REFUTE_THEN into the "class.ml" file, where it seems a more natural fit,
and SPLIT_THEN into "meson.ml", since it's only used there and I may eventually
rethink all this splitting stuff anyway.

Hid SELECT_ELIM_CONV and SELECT_ELIM_ICONV inside SELECT_ELIM_TAC. Actually,
I'm a bit confused about why I don't just do REDEPTH_CONV SELECT_CONV instead
of this custom SELECT_ELIM_CONV, but I left it as is just in case I'm
forgetting something important.

Renamed CONDS_ELIM_CONV' as CONDS_CELIM_CONV, which is a bit more consistent
with NNFC_CONV.

Hid get_heads, get_thm_heads, GEN_FOL_CONV and FOL_CONV inside ASM_FOL_TAC.

Wed  3rd May 06         canon.ml, meson.ml

Added quick getout clauses for the reflexive case in CONJ_ACI_RULE and
DISJ_ACI_RULE.

Removed PROP_CNF_CONV and PROP_DNF_CONV. Renamed STRONG_CNF_CONV and
STRONG_DNF_CONV to just CNF_CONV and DNF_CONV, and made them descend inside the
two core quantifiers so that they subsume the old PROP_CNF_CONV and
PROP_DNF_CONV.

Also added ASSOC_CONV. Changed MESON to use WEAK_CNF_CONV and then ASSOC_CONV,
since that seems more compatible and slightly faster than CNF_CONV.

Tue  2nd May 06         canon.ml

Modified PRENEX_CONV so it also pulls out existential quantifiers. I tend to
use it after Skolemizing so there's no need, but for some sort of general entry
point it seems sensible to enhance things. I don't think the lookup time will
make a significant difference to anything.

Tue  2nd May 06         canon.ml

Removed MINISCOPE_CONV. In principle it's quite useful, but it's a bit
overspecialized (only does universal quantifiers...) and was never used
anywhere.

Tue  2nd May 06         canon.ml

Added an initial primitive miniscoping to SKOLEM_CONV, to push quantifiers in
naively first before doing the Skolemizing, for which the universal quantifiers
get pulled out again. I'm not 100% sure this is good / worthwhile, but let's
try.

Tue  2nd May 06         canon.ml

Removed "CNNF_CONV" (NNF with an atom base conversion), which was never used;
in the rare cases when this generality is needed, one can use GEN_NNF_CONV.

Mon  1st May 06         int.ml, Examples/prime.ml, Examples/pocklington.ml

Put in definitions of divisibility, coprimality and gcd over both Z and N. The
net new definitions/theorems are, I believe:

  int_divides = |- !b a. a divides b <=> (?x. b = a * x)
  int_mod = |- !n x y. mod n x y <=> n divides x - y
  int_congruent = |- !x y n. (x == y) (mod n) <=> (?d. x - y = n * d)
  int_coprime = |- !a b. coprime(a,b) <=> (?x y. a * x + b * y = &1)

  num_divides = |- !a b. a divides b <=> &a divides &b
  num_mod = |- !n x y. mod n x y <=> mod &n (&x) (&y)
  num_congruent = |- !x y n. (x == y) (mod n) <=> (&x == &y) (mod &n)
  num_coprime = |- !a b. coprime(a,b) <=> coprime(&a,&b)
  num_gcd = |- !a b. gcd(a,b) = num_of_int (gcd(&a,&b))

  NUM_GCD = |- !a b. &(gcd(a,b)) = gcd(&a,&b)
  INT_GCD_EXISTS =
   |- !a b. ?d. d divides a /\ d divides b /\ (?x y. d = a * x + b * y)
  INT_GCD_EXISTS_POS =
    |- !a b.
           ?d. &0 <= d /\
               d divides a /\
               d divides b /\
               (?x y. d = a * x + b * y)
  int_gcd =
    |- !a b.
           &0 <= gcd(a,b) /\
           gcd(a,b) divides a /\
           gcd(a,b) divides b /\
           (?x y. gcd(a,b) = a * x + b * y)

Also defined a mapping "num_of_int" from integers back to natural numbers and
proved a few lemmas about it:

  num_of_int = |- !x. num_of_int x = (@n. &n = x)
  NUM_OF_INT_OF_NUM = |- !n. num_of_int (&n) = n
  INT_OF_NUM_OF_INT = |- !x. &0 <= x ==> &(num_of_int x) = x
  NUM_OF_INT = |- !x. &0 <= x <=> &(num_of_int x) = x

Plus a few auxiliary lemmas that I might just want to hide, but perhaps they'll
be useful.

  FORALL_UNCURRY = |- !P. (!f. P f) <=> (!f. P (\a b. f (a,b)))
  EXISTS_UNCURRY = |- !P. (?f. P f) <=> (?f. P (\a b. f (a,b)))

  WF_INT_MEASURE =
    |- !P m.
           (!x. &0 <= m x) /\ (!x. (!y. m y < m x ==> P y) ==> P x)
           ==> (!x. P x)

  WF_INT_MEASURE_2 =
    |- !P m.
           (!x y. &0 <= m x y) /\
           (!x y. (!x' y'. m x' y' < m x y ==> P x' y') ==> P x y)
           ==> (!x y. P x y)

Also added INTEGER_TAC, INTEGER_RULE, NUMBER_TAC and NUMBER_RULE, which are a
first "production" version of the ideal-based hacks I've been using lately.
They will probably get some future refinements (especially the number ones,
which could probably have their

Finally, switched the definition of integers from "new_basic_type_definition"
to just "new_type_definition" for benignity.

I modified the existing files where such divisibility concepts (over N) were
defined, so they use the new definitions and often use NUMBER_TAC instead of
manual proofs, but are otherwise identical in structure. I can no doubt
substantially improve this, but it's not critical to get to it soon.

Mon  1st May 06         class.ml

Fixed up "new_specification" to inherit acceptance of benign redefinition from
the underlying "new_definition". This meant first not adding an outer check,
and second replacing the variable in the input term by a constant if need be.

Mon  1st May 06         arith.ml, realax.ml, int.ml

Removed all the congruence-related stuff from its various points, as a prelude
to a nicer arrangement afterwards.

Mon  1st May 06         canon.ml

Removed GEN_NNFC_CONV as a separate function, instead adding the same flag
argument used internally to GEN_NNF_CONV. So

 GEN_NNF_CONV |-> GEN_NNF_CONV false
 GEN_NNFC_CONV |-> GEN_NNF_CONV true

Also removed the toplevel binding of GEN_NNF_DCONV, which is a bit over-refined
and I never actually used.

Fri 28th Apr 06         list.ml

Added

  ITLIST_APPEND =
    |- !f a l1 l2. ITLIST f (APPEND l1 l2) a = ITLIST f l1 (ITLIST f l2 a)

The existing ITLIST_EXTRA is just a special case of this, so possibly I
should remove it. Still, it's used once.

Thu 27th Apr 06         help.ml [new file], doc-to-help.sed [new file]

Introduced simple "help" system on the lines of HOL88. So far it's a little
more inflexible, e.g. doesn't have a separate help path, but I might think
about later generalizations.

Couldn't resist adding a cool hack to compute the "edit distance" (aka
Levenshtein distance) between two strings and try to guess what you meant.

Thu 27th Apr 06         canon.ml

Corrected DISJ_CANON_CONV, which simply didn't work, since several things were
not modified from cut-and-pasting CONJ_CANON_CONV.

Thu 27th Apr 06         canon.ml

Changed DEPTH_CONV to TOP_DEPTH_CONV in PRESIMP_CONV, since several of the
transformations are inherently top-down.

Thu 27th Apr 06         preterm.ml, int.ml, realax.ml, real.ml

Added a new function "prioritize_overload" that essentially prioritizes the
first instance of each thing where the desired type appears as an instantiation
of one of the type variables in the generic type. Made prioritize_num,
prioritize_int, prioritize_real all just instances of this. The main point is
that then it "automatically" expands to cover newly defined overloaded
constants without continual redefinition of the prioritizer functions.

Also renamed "mod_nat" as "nat_mod"; "mod_int" as "int_mod", and "mod_real" as
"real_mod"; these are more consistent with the usual naming conventions.

Also redefined "real_mod", which was stupidly trivial; moved its definition
into "int.ml" so I could use the "is_int" property.

Fri 21st Apr 06         lib.ml

A relatively trivial change: modified the implementation of "allpairs" to be
less hacky-combinatorial and probably slightly more efficient. Not that it
really matters, of course...

Fri 21st Apr 06         int.ml

Dumped in all the operations on integers, analogous to the ones over reals:

  INT_LE_CONV
  INT_LT_CONV
  INT_GE_CONV
  INT_GT_CONV
  INT_EQ_CONV
  INT_NEG_CONV
  INT_MUL_CONV
  INT_ADD_CONV
  INT_SUB_CONV
  INT_POW_CONV
  INT_ABS_CONV
  INT_RED_CONV
  INT_REDUCE_CONV

as well as instantiations of the normalizer and ring/ideal procedures:

 INT_POLY_CONV
 INT_RING
 int_ideal_cofactors

Thu 20th Apr 06         sets.ml

Added a stronger form of set induction, which can be useful:

  FINITE_INDUCT_DELETE =
    |- !P. P {} /\
           (!s. FINITE s /\ ~(s = {})
                ==> (?x. x IN s /\ (P (s DELETE x) ==> P s)))
           ==> (!s. FINITE s ==> P s)

Thu 20th Apr 06         int.ml, Examples/floor.ml

Changed "dest_int" to "real_of_int" and "mk_int" to "int_of_real". These are
much more natural and people may really want to use them. I now removed
interface mappings with similar effect from "Examples/floor.ml". The only
remaining thing I should probably do is unify "integer" and "is_int", but
that's a lower priority. It might also be nice to rename things like "int_le"
so that the correspondence with real is perfect. Call that "int_le_def" and
move the current INT_LE to int_le etc.

Thu 20th Apr 06         int.ml

Added "dest_intconst", "is_intconst" and "mk_intconst" as the start of a
campaign to bring type "int" up to a more equal footing with "real".

Wed 19th Apr 06         calc_int.ml

Decomissioned "is_numconst", "dest_numconst" and "mk_numconst"; except for an
odd use in the Maxima interface (now changed), these were little used. Also
systematically renamed "[is|mk|dest]_intconst" as "[is|mk|dest|]_realintconst",
since this is a bit more intuitive and makes room for those names for the type
of integers.

Mon 17th Apr 06         iter.ml

Added a third congruence variant for iterated operations, this time for
"iterator {x | P x}" assuming "P x" rather than "x IN {x | P x}" which is what
the default will give.

Mon 17th Apr 06         iter.ml

Changed "[N]SUM_CMUL" to "[N]SUM_LMUL" and added right-handed variants
"[N]SUM_RMUL":

  |- !f c s. nsum s (\x. f x * c) = nsum s f * c
  |- !f c s. sum s (\x. f x * c) = sum s f * c

It was starting to get silly how often I was generating these by manually
rewriting.

Fri 14th Apr 06         grobner.ml, calc_rat.ml, Complex/complex.ml

Made two significant changes to Grobner bases. The first is rather trifling;
changed the existential variable in the Rabinowitsch theorems from "d" to "z".
Since this puts it at or near the end of the resulting variable order, it
matters! At least on one important example, it makes things significantly
better, though I don't know how stable that is; I'm about to run tests.

The other is more interesting: in the case where there are only positive
equations (e.g. the Rabinowitsch trick has been pre-applied) and we have a true
ring, I directly execute the "history" proof trace rather than create the
intermediate cofactors list, which can sometimes really blow up.

Fri 14th Apr 06         cart.ml

Changed the ML binding of the definition of "finite_index" to "finite_index"
rather than "index_def".

Fri 14th Apr 06         calc_int.ml, calc_rat.ml

Cleaned up a few places replacing "COMB2_CONV (RAND_CONV c) c" with just
"BINOP_CONV c", which is simpler and probably slightly more efficient.

Fri 14th Apr 06         drule.ml, calc_rat.ml

Remove the ad-hoccery of "REAL_INT_POS_CONV" and "REAL_INT_POS_PROVE",
replacing them by a potentially more generally useful function MP_CONV, which
eliminates the antecedent of an implicational theorem |- p ==> q by applying a
conversion, which may either return "p <=> T" or just "p".

Fri 14th Apr 06         calc_rat.ml

Deleted REAL_INT_RAT_UNOP_CONV, which in fact wasn't used at all.
Replaced REAL_INT_RAT_BINOP_CONV by its trivial definition; actually made it
more trivial by using BINOP_CONV. Also replaced REAL_RAT_INT_CONV by its
definition and deleted it.

Fri 14th Apr 06         sets.ml

Added yet another few theorems about set bijections. I get the feeling that
this disparate collection of lemmas is rather spinning out of control and needs
to be rationalized. Anyway:

  BIJECTIONS_HAS_SIZE =
    |- !s t f g.
           (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
           (!y. y IN t ==> g y IN s /\ f (g y) = y) /\
           s HAS_SIZE n
           ==> t HAS_SIZE n

  BIJECTIONS_HAS_SIZE_EQ =
    |- !s t f g.
           (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
           (!y. y IN t ==> g y IN s /\ f (g y) = y)
           ==> (!n. s HAS_SIZE n <=> t HAS_SIZE n)

  BIJECTIONS_CARD_EQ =
    |- !s t f g.
           (FINITE s \/ FINITE t) /\
           (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
           (!y. y IN t ==> g y IN s /\ f (g y) = y)
           ==> CARD s = CARD t

Thu 13th Apr 06         grobner.ml, calc_rat.ml

Put a simple Rabinowitsch parameter into RING, and made the real version use
it. Indeed, it seems that this can make quite a difference. One example I tried
went from a minute (generating a degree-3 strong certificate in the biggest
subcase) to 3 seconds. There may be some still more dramatic cases.

Thu 13th Apr 06         calc_rat.ml, Complex/complex.ml

Tweaked the implementations of REAL_FIELD and COMPLEX_FIELD so they do
splitting up first, and separately introduce the inversion hypotheses for each
conjunct. In some cases, this may save quite a few cases. For example, on the
cubic, we went down from 68 cases to 32. This is still not a complete answer to
its inefficiency, though: to cure that we need to tackle the underlying
procedure. Perhaps I'll try aplying the Rabinowitsch trick first to avoid the
overhead generating strong Nullstellensatz certificates?

Thu 13th Apr 06         arith.ml, grobner.ml

Finally got round to tracing why the ARITH_TAC calls in Zagier's 2-squares
proof are so excruciatingly slow. Realized that the forms of theorems like
SUB_ELIM_THM are stupid, because they have two separate instances of P on the
right, "P d" and "P 0". It's much better to keep them as "P d" but have a
"d = 0" assumption. Otherwise, you may be creating twice as many other
instances, and getting doubly exponential performance! Accordingly, changed the
elimination theorems and incorporated them into NUM_SIMPLIFY_CONV. Also made it
behave better with respect to formula sense when introducing quantifiers, by
also defining "existential" variants:

PRE_ELIM_THM = |- P (PRE n) <=> (!m. n = SUC m \/ m = 0 /\ n = 0 ==> P m)
PRE_ELIM_THM' = |- P (PRE n) <=> (?m. (n = SUC m \/ m = 0 /\ n = 0) /\ P m)

SUB_ELIM_THM = |- P (a - b) <=> (!d. a = b + d \/ a < b /\ d = 0 ==> P d)
SUB_ELIM_THM' = |- P (a - b) <=> (?d. (a = b + d \/ a < b /\ d = 0) /\ P d)

DIVMOD_ELIM_THM =
  |- P (m DIV n) (m MOD n) <=>
     (!q r. n = 0 /\ q = 0 /\ r = 0 \/ m = q * n + r /\ r < n ==> P q r)
DIVMOD_ELIM_THM' =
  |- P (m DIV n) (m MOD n) <=>
     (?q r. (n = 0 /\ q = 0 /\ r = 0 \/ m = q * n + r /\ r < n) /\ P q r)

Thu 13th Apr 06         parser.ml

Took the plunge and rewrote the precedence parser so it collects all operators
with the same parse status in bunches. This was stimulated by the fact that
after the recent modifications, something in Tom's Jordan proof failed because
when using a binary operator "+." with the same precedence as "+", the input
"a +. b + c" was parsed as "(a +. b) + c".

Wed 12th Apr 06         parser.ml, preterm.ml

Added support for type abbreviations:

  new_type_abbrev
  remove_type_abbrev
  type_abbrevs

These are applied each time the type parser is looking at an atomic string.

Wed 12th Apr 06         hol.ml

Tweaked "load_on_path" so it only adds to the list of loaded files after the
load. In some ways this seems more reasonable, since "already loaded" is a bit
misleading if the load failed. Of course, one advantage of doing things the old
way would be the impossibility of infinite loops...

Wed 12th Apr 06         Examples/pocklington.ml

Added a completely stupid factoring algorithm as a catchall; this is invoked
either for small numbers (< 2^25 currently; the naive algorithm starts to take
of the order of a second for primes of this size) or when the call to PARI/GP
fails, e.g. because it's not installed.

Tue 11th Apr 06         bool.ml

Took away the initial infix of "=", which gets overwritten anyway. Very trivial
but...

Tue 11th Apr 06         iter.ml

Added some theorems that are a bit specialized but capture quite a common
situation, where you iterate something composed with an injective function
from a finite set into itself:

  ITERATE_INJECTION =
    |- !op. monoidal op
            ==> !f p s.
                    FINITE s /\
                    (!x. x IN s ==> p x IN s) /\
                    (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y)
                    ==> iterate op s (f o p) = iterate op s f

  NSUM_INJECTION =
    |- !f p s.
           FINITE s /\
           (!x. x IN s ==> p x IN s) /\
           (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y)
           ==> nsum s (f o p) = nsum s f

  SUM_INJECTION =
    |- !f p s.
           FINITE s /\
           (!x. x IN s ==> p x IN s) /\
           (!x y. x IN s /\ y IN s /\ p x = p y ==> x = y)
           ==> sum s (f o p) = sum s f

Tue 11th Apr 06         preterm.ml

Enhanced "num_of_string" to handle binary numbers with notation "0b<digits>".
Also put in an error check for empty digit lists in the based case; previously,
for example, "0x" was quietly accepted as zero!

Mon 10th Apr 06         grobner.ml

Fixed a strikingly trivial error in the ideal part of RING_AND_IDEAL_CONV,
where I'd missed a prime from "pol'", and so was failing by seeing that the
original polynomial is nonzero.

Mon 10th Apr 06         cart.ml, ind-types.ml

Removed the "inductive type" definitions of the types ":2" and ":3". Added a
function "define_finite_type", and made ":2" and ":3" instances of that.
Derived all these theorems, some for the type ":1" which is defined the same
old way:

  HAS_SIZE_1 = |- (:1) HAS_SIZE 1
  HAS_SIZE_2 = |- (:2) HAS_SIZE 2
  HAS_SIZE_3 = |- (:3) HAS_SIZE 3

  DIMINDEX_1 = |- dimindex(:1) = 1
  DIMINDEX_2 = |- dimindex(:2) = 2
  DIMINDEX_3 = |- dimindex(:3) = 3

Mon 10th Apr 06         cart.ml

Added

  DIMINDEX_UNIQUE = |- (:A) HAS_SIZE n ==> dimindex(:A) = n

Mon 10th Apr 06         theorems.ml, passim.

Finally added EQ_IMP = |- (a <=> b) ==> a ==> b
which I seem to use a great deal as a prelude to congruence reasoning. Changed
numerous explicit TAUT instances into that.

Mon 10th Apr 06         arith.ml

Added two occasionally useful and very natural rewrites:

  EVEN_SUB = |- !m n. EVEN(m - n) <=> m <= n \/ (EVEN m <=> EVEN n)
  ODD_SUB = |- !m n. ODD(m - n) <=> n < m /\ ~(ODD m <=> ODD n)

Mon 10th Apr 06         iter.ml

Added some theorems about iterations over sets with deleted elements. Note that
the REAL one is a bit different, presumably more convenient in a ring.

  ITERATE_DELETE =
    |- !op. monoidal op
            ==> !f s a.
                    FINITE s /\ a IN s
                    ==> op (f a) (iterate op (s DELETE a) f) = iterate op s f

  NSUM_DELETE =
    |- !f s a. FINITE s /\ a IN s ==> f a + nsum (s DELETE a) f = nsum s f

  SUM_DELETE =
    |- !f s a. FINITE s /\ a IN s ==> sum (s DELETE a) f = sum s f - f a

ITERATE_DELETE

NSUM_DELETE

Mon 10th Apr 06         arith.ml, grobner.ml

Hid NUM_MULTIPLY_CONV inside NUM_SIMPLIFY_CONV; that's actually the only place
where it's used.

Mon 10th Apr 06         grobner.ml

Completely hid almost all the internal functions inside RING_AND_IDEAL_CONV.
(After carefully confirming that they weren't used anywhere, or anywhere
interesting anyway.) So now all of the following are hidden away:

  morder_lt
  morder_le
  morder_gt
  grob_neg
  grob_add
  grob_sub
  grob_mmul
  grob_cmul
  grob_mul
  grob_inv
  grob_div
  grob_pow
  mdiv
  mlcm
  reduce1
  reduceb
  reduce
  orthogonal
  spoly
  monic
  forder
  poly_lt
  align
  poly_eq
  memx
  criterion2
  constant_poly
  grobner_basis
  grobner_interreduce
  grobner
  grobner_refute
  resolve_proof
  grobner_weak
  grobner_ideal
  grobner_strong

Sat  8th Apr 06         grobner.ml

Fixed a little error in "grobvars", which was descending to the "x" in all
terms of the form "x pow n", without checking if "n" is a numeral. This was
inconsistent with the actual normalizer functions, which treat "x pow n" for
non-numeral n as atomic variables. For example this now works, whereas before:

  # REAL_RING `!x:real. &2 pow n = x ==> x = &2 pow n`;;
  Exception: Failure "grobify_term: unknown or invalid term".

Fri  7th Apr 06         printer.ml

Added ".." and "$" to the unspaced_binops. Don't know why I didn't think of it
before.

Fri  7th Apr 06         arith.ml, sets.ml, Examples/analysis.ml

Fixed more cases of "=" that should be "<=>"; the error was only apparent
because of the slight reshuffling of the precedences. In fact I discovered all
but one by deliberately upping the precedence of "=" to 13 temporarily.

Fri  7th Apr 06         parser.ml

Modified the sorting of the infixes list to make it a canonical ordering,
lexicographically by precedence, then fixity (left is higher) then alphabetical
name of the operator. This was motivated by the fact that adding "CROSS" the
other day had actually changed the order of "<" and "=" and affected parsing,
albeit only on formulas that were "wrong".

Fri  7th Apr 06         normalizer.ml

Removed SEMIRING_NORMALIZE_CONV; after all it's only a small wrap round
SEMIRING_NORMALIZERS_CONV, and was only used once in the core.

Thu  6th Apr 06         Examples/combin.ml [new file]

Added a new example, the old combinatory logic one done by Tom Melham and
Juanito Camilleri in HOL88. My source and inspiration was the HOL4 tutorial and
distribution; the proof is quite close to the one there apart from cosmetic
features.

Thu  6th Apr 06         printer.ml

Restored behaviour of "name_of" that I'd changed inadvertently in my recoding:
it should return "" rather than fail on combinations or abstractions.

Thu  6th Apr 06         sets.ml

Added a proper "Cartesian product" operation CROSS and the theorems:

  CROSS = |- !s t. s CROSS t = {x,y | x IN s /\ y IN t}

  IN_CROSS = |- !x y s t. x,y IN s CROSS t <=> x IN s /\ y IN t

  HAS_SIZE_CROSS =
    |- !s t m n. s HAS_SIZE m /\ t HAS_SIZE n ==> s CROSS t HAS_SIZE m * n

  FINITE_CROSS =
   |- !s t. FINITE s /\ FINITE t ==> FINITE(s CROSS t)

  CARD_CROSS =
    |- !s t. FINITE s /\ FINITE t ==> CARD(s CROSS t) = CARD s * CARD t

All these are just trivial rewrites of "..._PRODUCT" theorems. I would rather
like to decomission those, but it might be a bit disruptive. One idea would be
to rename the "DEPENDENT" versions, since in many "crude" applications they
would work equally well. But then all the explicit enumerations eliminated with
IN_ELIM_PAIR_THM would need to be tracked. Scarcely worth it.

Thu  6th Apr 06         recursion.ml, pair.ml

Hid "prove_raw_recursive_functions_exist" and
"prove_canon_recursive_functions_exist" inside the main function; they are
never used and there's no obvious reason why one would want to.

Also hid "projection_cache" and "create_projections", moving them inside
GEN_BETA_CONV. Again, this seems sensible since they're hardly of general
utility. I hesitated briefly because there's now no way to flush the cache, but
since in the typical case it will contain only the theorem for pairs, and
anyway is sorta linear in the number of constructors declared, I decided this
was a non-issue.

Wed  5th Apr 06         realarith.ml, calc_rat.ml

Rearranged GEN_REAL_ARITH to be further specialized twice from its
bootstrapping version so that it only takes the prover as an argument and
otherwise has everything fixed. That makes things a bit simpler conceptually,
and moreover I could now hide ABSMAXMIN_ELIM_CONV1 and ABSMAXMIN_ELIM_CONV2
inside and intermediate version.

Tue  4th Apr 06         printer.ml

Deleted "backquote_char" (never used, a relic from the separate filter for CAML
Light), "IS_BINDER", "IS_PREFIX", "IS_INFIX", "FIXITY" (all have trivial
synonyms and are only used in the printer).

Hid "DEST_BINARY", "ARIGHT" and "dest_binder_vorc" inside "pp_print_term",
which is the only place they are used.

Renamed "NAME_OF" to "name_of" since the case conventions make the former look
like an inference rule; also slightly optimized the implementation.

Hid "reverse_interface". The parametrization by the reference flag makes it
less generally useful, and as a matter of fact it isn't used anywhere.

Also hid the initial "string_of_type" and added a new variant in the same style
as the other "to string" stuff. Eventually I would like this to be derived, if
at all, from the printer rather than vice versa, so it works more nicely on
huge types.

Sun  2nd Apr 06         int.ml

Removed ARITH_CONV and INT_ARITH_CONV; these were almost never used and seem
merely likely to create more confusion given that ARITH_RULE and INT_ARITH both
exist and do almost the same thing.

Sat  1st Apr 06         sets.ml, define.ml

Got rid of various explicit "CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV)" type
things now that generalized beta conversion is in the basic rewrites.

Fri 31st Mar 06         pair.ml, realax.ml, wf.ml

Removed the horribly ad-hoc GEN_PAIR_TAC. Replaced the instances in other files
with other proofs, actually often simpler, typically using FORALL_PAIR_THM.
Also forced "LET_TAC" to have abbreviated type "tactic".

Tue 28th Mar 06         realax.ml

Hid "DIST_ELIM_TAC" inside some proofs. The net effect is also a bit shorter,
since I noticed three proofs were identical.

Tue 28th Mar 06         sets.ml

Renamed yesterday's theorem (CARD_EQ_BIJ -> CARD_EQ_BIJECTION), and added a new
version with two bijections:

  CARD_EQ_BIJECTION =
    |- !s t.
           FINITE s /\ FINITE t /\ CARD s = CARD t
           ==> ?f. (!x. x IN s ==> f x IN t) /\
                   (!y. y IN t ==> (?x. x IN s /\ f x = y)) /\
                   (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)

  CARD_EQ_BIJECTIONS =
    |- !s t.
           FINITE s /\ FINITE t /\ CARD s = CARD t
           ==> ?f g. (!x. x IN s ==> f x IN t /\ g (f x) = x) /\
                     (!y. y IN t ==> g y IN s /\ f (g y) = y)

Tue 28th Mar 06         wf.ml

Got rid of WF_INDUCT_THEN, which was never used. Kept WF_INDUCT_TAC.

Tue 28th Mar 06         arith.ml

Got rid of PRE_ELIM_TAC and SUB_ELIM_TAC too. They're both subsumed really by
NUM_MULTIPLY_CONV, and I only had one instance of each (one in Tom's Jordan
proof, one in my ancient Ramsey proof where it was doing manually something
doable by ARITH_TAC anyway).

Tue 28th Mar 06         calc_num.ml

Removed one instance of NUM_CANCEL_CONV. I had wanted to get rid of it, but
then some of the proofs in "realax.ml" would become somewhat tedious, so I
thought better of it.

Tue 28th Mar 06         Rqe/make.ml

Deleted the files "core.ml" and "analysis.ml" from the build. They aren't
necessary and break when any theorems vanish, even obscure ones. Sean himself
suggested getting rid of this.

Mon 27th Mar 06         Examples/binary.ml [new file]

Added a basic development of the "binary expansion" bijection between finite
sets and functions. It's actually surprisingly tedious...

Mon 27th Mar 06         arith.ml

Recoded mk_small_numeral and dest_small_numeral in terms of their mk_numeral
and dest_numeral counterparts. This is not only simpler but in the latter case
has better error checking instead of silently overflowing. Also deleted
"is_small_numeral", which is rather obscure and had never been used at all.

Also hid PRE_ELIM_CONV and SUB_ELIM_CONV inside the corresponding tactics.

Mon 27th Mar 06         sets.ml

Removed SETIFY_CONV and SETENUM_UNION_CONV. I'm not really very satisfied with
this half-baked solution. I think I should really do it all modulo an equality
conversion or something.

Mon 27th Mar 06         sets.ml

Added another of those "how did I manage without it for so long?" theorems:

CARD_EQ_BIJ =
  |- !s t.
         FINITE s /\ FINITE t /\ CARD s = CARD t
         ==> (?f. (!y. y IN t ==> (?x. x IN s /\ f x = y)) /\
                  (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y))

Mon 27th Mar 06         calc_num.ml

Decided to hide NUM_DIVMOD_CONV. It's potentially useful, but I'd never used it
and in any really critical situation one would probably want even more
delicacy.

Sun 26th Mar 06         calc_num.ml

Removed toplevel binding of NUM_SUC_CONV', which is never used.

Changed one right-hand clause of ARITH_LE to "n <= _0" rather than "n = 0"
since it keeps the rewrites more thematic. Slightly reorganized the definitions
of the inequality conversions to be more efficient exploiting this, and recoded
NUM_REL_CONV. Made the final net use the explicit conversions rather than
NUM_REL_CONV; I can't remember how that happened. And in the process, hid
NUM_REL_CONV'. And hid both NUM_ADD_CONV' and NUM_MULT_CONV'.

Finally renamed "mangle" to a more meaningful name DENUMERAL. I could just hide
it, since it's not used outside this file, but that's a bit tedious.

Fri 24th Mar 06         class.ml, Examples/hol88.ml

Tweaked ETA_CONV so it doesn't muss the variable name. Previously
ETA_CONV `\n. SUC n` returned `(\x. SUC x) = SUC`.

Also removed EXT, or moved it to Examples/hol88.ml; I've never used it.

And removed "list_mk_select" and "strip_select", which were never used, and
"simple_new_specification".

Fri 24th Mar 06         sets.ml, cart.ml [new file]

Slightly reorganized the definitions of finite_index and finite_sum to use
simple correspondence with ranges, parametrized by the base type, rather than
the somewhat laborious constructions within the core types. As a consequence, I
needed to move this stuff after the definition of ranges "..", so I put it in a
new file "cart.ml". This is arguably a structural improvement anyway since it
really is rather out of character with the rest of "sets.ml".

Fri 24th Mar 06         ind-defs.ml

Removed HALF_BETA_EXPAND; it hardly seemed worthwhile given that the definition
in terms of RIGHT_BETAS is simple and it's not used much.

Fri 24th Mar 06         ind-defs.ml, ind-types.ml, num.ml

Deleted "prove_nonschematic_inductive_relations_exist", and changed the only
two applications of it into simple "prove_inductive_relations_exist". Also
removed RULE_INDUCT_TAC and RULE_INDUCT_THEN. I don't really want these ad-hoc
things when MATCH_MP_TAC works fine. There are some instances of
RULE_INDUCT_TAC in Examples/rstc.ml but that's already using a slightly
different local definition.

Also hid "generalize_schematic_variables", "derive_existence",
"make_definitions", "prove_inductive_properties" and "unschematize_clauses".

Fri 24th Mar 06         ind-defs.ml, class.ml, list.ml

Restructured the monotonicity-proving code somewhat, hiding BACKCHAIN_TAC,
MONO_ABS_TAC, APPLY_MONOTAC and MONO_STEP_TAC, and replacing "mono_tactics"
with "monotonicity_theorems", which is *just* a list of theorems. This seems to
be a much more straightforward interface.

Thu 23rd Mar 06         ind-defs.ml

Hid: FORALL_IMPS_CONV, AND_IMPS_CONV, SIMPLE_DISJ_PAIR, canonicalize_clause,
canonicalize_clauses, derive_canon_inductive_relations; all of these are just
used once inside the core function.

Wed 22nd Mar 06         ind-defs.ml

Hid "getconcl". I'll do some more tomorrow...

Wed 22nd Mar 06         tactics.ml

Removed the binding of REFINEMENT_PROOF, which seems entirely useless.

Wed 22nd Mar 06         tactics.ml

Removed the type constructor "Goalstack" everywhere and just made "goalstack" a
direct abbreciation of "goalstate list". It seemed just to get in the way and
make things less intuitive.

Tue 21st Mar 06         tactics.ml

Deleted DISJ_CASES_THENL, which is quite rarely used and has a trivial
definition; it's also a bit inconsistent to have this but not the corresponding
thing for conjunction.

Tue 21st Mar 06         tactics.ml

Fixed a small but real error in CONV_TAC, which was checking for equations "x =
T" without taking into account that the goal might itself be of the form
"something = T" and the tactic may be returning the goal itself.

Sat 18th Mar 06         drule.ml

Deleted "find_matching_subterm", which was never used at all. It was probably
used in a previous version of HIGHER_REWRITE_CONV. Actually, I'm quite tempted
to get rid of that too: in particular its treatment of freeness in conditionals
is too conservative (only the condition arm needs to be free).

Fri 17th Mar 06         drule.ml

Changed BETAS_CONV so that it just infers the number of reductions to make from
the form of the term, rather than taking it as a separate parameter. There's
really not much to be done besides following the form of the term, and that's
really all the old function did.

Thu 16th Mar 06         bool.ml

Made a trivial syntactic tweak to the concrete syntax in the definition of
unique existence, to remove excessive bracketing.

Wed 15th Mar 06         equal.ml

Removed SINGLE_DEPTH_CONV, which is very specialized, only really used to do an
old-style SKOLEM_CONV. The latter is used in a few places so I copied the
definition there, but eventually I really ought to scrub those too.

Wed 15th Mar 06         equal.ml

Hid all the "failure propagating" depth conversions (even removed COMB2_QCONV,
which was only used in the instance COMB_QCONV) inside the core functions. This
means COMB2_QCONV, COMB_QCONV, DEPTH_QCONV, ONCE_DEPTH_QCONV, REDEPTH_QCONV,
SUB_QCONV, TOP_DEPTH_QCONV and TOP_SWEEP_QCONV are no longer bound.

Tue 14th Mar 06         nets.ml

Hid "label_to_store", "label_for_lookup", "follow" and "net_update" inside the
main two functions "enter" and "lookup".

Mon 13th Mar 06         basics.ml, equal.ml

Changed the notion of "path" in find_path, follow_path and PATH_CONV to be a
string rather than a list of strings. After all, the whole point is to be
terse.

Sat 11th Mar 06         basics.ml

Removed "dest_cvar". It's not unreasonable a priori but isn't even used once,
and I didn't want to document it. I'm plodding through reference manual entries
in Atlanta airport.

Fri 10th Mar 06         make.ml, hol.ml

Moved "hol_version" into the "hol.ml" file, since there seems to be no reason
to confine it to the built version. And also hid "nice_date" inside
"startup_banner".

Fri 10th Mar 06         sys.ml

Removed the assignable variable "set_jrh_lexer", which probably gives a false
impression that it's a Boolean flag. Just used the name in an identity function
in order to force things.

Fri 10th Mar 06         lib.ml, meson.ml

Removed "uniq'" and "setify'" from the library file and inserted them
internally in the only application, in MESON (something I eventually want to
get rid of anyway). Also removed "assoc'" and "pair_equals" completely, since
they are apparently never used.

Thu  9th Mar 06         lib.ml, Examples/holby.ml

Deleted less useful FPF functions "tryapply" and "tryapply" (had a few
instances of the latter in Holby to expand by changing to "tryapplyd ... []".
Also hid a lot of things that should really be considered internal functions to
the implementation: map_list, foldl_list, foldr_list, apply_listd,
undefine_list, define_list, combine_list, ldb, newbranch.

Thu  9th Mar 06         basics.ml

Realized I'd been stupid yesterday: the messiness in "subst" with genvars is
used to rename variables, and it is necessary; thanks to that a proof failed.
So restored the basic structure, but kept the superior handling of unchanged
subterms.

Thu  9th Mar 06         lib.ml

Modified "lcm_num" to return 0 rather than fail if both inputs are zero.

Wed  8th Mar 06         lib.ml

Fixed "gcd" to always return nonnegative gcds. Now it's basically consistent
with gcd_num in the absence of overflow. Removed "lcm" which was particularly
vulnerable to overflow and never got used.

Wed  8th Mar 06         lib.ml

Removed "munion" and "msubtract" (the later is used in the Tang exponential
proof so I put a copy there).

Removed all the flag functions: flags, get_flag_value, new_flag, set_flag. I
had intended to use these as in HOL88, but it seems somewhat pointless; better
to just use assignable variables, which can then have different types (one idea
would be to put them all together in a record for tidiness).

Removed "abs" (integer absolute value) which is already in OCaml and "sgn",
which seems pretty minimally useful since its definition is so short; indeed it
was never used.

Wed  8th Mar 06         lib.ml, nets.ml

Took the functions "set_insert" and "set_merge" from the library and hid them
inside the unique net function they are used in. They are never used anywhere
else.

Wed  8th Mar 06         lib.ml, passim

And removed "upto" which is just a synonm for "--". Needed to change a lot of
instances.

And removed "gather", which is just a synonym (and a less efficient one) for
"filter". Just one or two instances in use.

And removed "do_list2" which was never, ever, used.

Wed  8th Mar 06         lib.ml, basics.ml

Recoded "subst" to use pointer-eq rather than Unchanged exceptions, and
generally wrote a simpler implementation; I can't figure out why I formerly
replaced with genvars and then replaced those; it just looks weird. And this
was the only place where "qcomb" was used, so removed that too. Removed "qtry"
too, which wasn't used at all!

Also removed all the "lazy sum" stuff that's now not used: the type "lazysum"
and the functions "lazify", "eager" and "eval".

Wed  8th Mar 06         lib.ml, ind-defs.ml

Removed the function "assoc2", mainly to avoid documenting it, and replaced its
unique application in ind-defs:

    let vargs = shareout xargs flargs in
    let cargs = map (C assoc2 (rels,vargs) o fst) uncs in

with

    let cargs = map (fun (r,a) -> assoc2 r (rels,vargs)) uncs

Also moved "shareout" back into "lib.ml"; it seems it sorta belongs there.

Thu  2nd Mar 06         printer.ml

Re-fixed the problem of "--&n" printing; I'd accidentally knocked this out when
improving the behaviour of "----" to take into account any interface.

Thu  2nd Mar 06         calc_rat.ml

Added REAL_INV_INV into the initial normalizations done in REAL_FIELD; this
catches an issue where in the absence of this normalization one of the proofs
in 100/stirling.ml was failing; it had worked before because of a lucky
correlation in the older algorithm.

Wed  1st Mar 06         calc_rat.ml, Complex/complex.ml

Fixed an error in REAL_FIELD and COMPLEX_FIELD: they picked out a list of any
inverse terms. Now they pick only those that occur free in the formula. With
the earlier implementation this led only to pointless case splits, but now it
can lead to failure, e.g. if the term involves "sum (\k. ... / &(FACT k))" it
would attempt to establish ~(&(FACT k) = &0) in context, which is unlikely to
work.

Wed  1st Mar 06         itab.ml, bool.ml, tactics.ml, class.ml, Examples/hol88.ml

Removed CONTRAPOS (but put it in Examples/hol88.ml). This was very seldom used
and it can be done perfectly well by GEN_REWRITE_RULE I [GSYM CONTRAPOS_THM]
at worst. Likewise moved NEG_DISCH. And also SELECT_ELIM and SELECT_INTRO:
neither of these was *ever* used (by me).

Thu 23rd Feb 06         calc_rat.ml, Complex/complex.ml

Recoded REAL_FIELD and COMPLEX_FIELD to make a much less unintelligent
case-split. Instead of all 2^n combinations of cases for each x = 0 or x *
inv(x) = 1 for the n terms that are inverted, use the superior n+1 cases. This
should be a lot faster on formulas with many inverses.

Thu 23rd Feb 06         preterm.ml

Renamed "istriv" as "istrivial", since the former is already used for a MESON
function (not that there's much need for anyone to use either).

Tue 21st Feb 06         real.ml, num.ml, Examples/analysis.ml, Examples/transc.ml
                        Examples/card.ml, Examples/reduct.ml, Examples/wo.ml,
                        ind-types.ml

Spotted various "duplicate definition" type errors while accumulating a list of
identifiers for the reference manual.

Removed duplicate proofs of REAL_LE_REFL, REAL_LE_TOTAL and REAL_LE_ANTISYM,
which are already proved in "realax.ml".

Also removed the pointless rewrite with _0 = 0 of SUC_INJ, which doesn't
involve the constant zero.

Removed double proofs of SUB_LEFT_LESS_EQ and TC_CR, and the whole series
WOSET_REFL, WOSET_TRANS, WOSET_ANTISYM, WOSET_TOTAL and WOSET_WELL, plus
finally INTEGRAL_LE (though there was a slight difference in the first
instance) and renamed CARD_MUL_ASSOC correctly (it had been called
CARD_ADD_ASSOC in a cut-and-paste error).

Removed definitions of p_tm and d_tm from "transc.ml", kl_tm from "wo.ml", and
localized (stupidly) t_tm in "ind-types.ml".

Tue 14th Feb 06         class.ml

Changed the "new_specification" code to use "new_definition" rather than
"new_basic_definition", otherwise the new constants don't get added to the
definitions list.

Mon 13th Feb 06         printer.ml

Fixed a problem with the printer pointed out by Cezary Kaliszyk: the special
avoidance of printing double-negations *not* as "----" was only working for
some instances, and not vectors (indeed, not complex numbers either). So I
changed the code a bit so that now it comprehensively looks if the reverse
interface mapping is "--", which seems more satisfactory.

Fri 13th Jan 06         preterm.ml

Modified "pmk_let" so that it will allow "<=>" as well as "=" as the binding
construct; remember that typechecking and overloading resolution hasn't been
performed at this point. This was to fix an unanticipated issue with the change
of precedence: neither "let x = y \/ z in ..." nor "let x <=> y \/ z in ..."
was accepted. Now the latter is; in either case "let x = (y \/ z) in ..." was
of course. Still, I wonder if I ought to do a more special-case parse of the
let bindings rather than relying on treating it as a preterm directly. Of
course it prints as "<=>" anyway. Let's stick with this for now.

Mon  9th Jan 06         define.ml

Fixed one case where there was a reliance on the default rewriting net at
runtime, in ELIM_LISTOPS_CONV within instantiate_casewise_recursion. With
paired beta inside, this was breaking. Also changed REWRITE_CONV to
PURE_REWRITE_CONV on line 451. Although I don't think that was currently
causing problems, it could in principle. There are still a few defaulted
REWRITE_TACs in the later order-guessing stuff, but then that should be
rewritten more fundamentally anyway so I'm not planning to tinker unless I need
to.

Fri  6th Jan 06         pair.ml

So, added GEN_BETA_CONV to the basic rewrites at the end of "pair.ml". Seems
not to kill anything in the core; I'll run some tests to see if anything
breaks. Eventually I can go through and make some consequential
simplifications.

Fri  6th Jan 06         simp.ml

I really wanted to add paired (or generalized) beta-conversion to the basic
"rewrites", but the mechanism for adding a conversion is not really there. So I
restructured, adding

  set_basic_convs
  extend_basic_convs
  basic_convs

and tweaked all the setting functions so that updating either the basic
theorems or conversions will "rehash" the whole term net starting from those
two lists. Should be compatible...

Wed  4th Jan 06         printer.ml

Prompted by Steve Brackin, who wanted to convert terms to strings, I
generalized several printing functions into "pp_" variants that take a
formatter as an additional argument:

  pp_print_type
  pp_print_qtype
  pp_print_term
  pp_print_qterm
  pp_print_thm

Also added more explicit string conversion functions:

  print_to_string
  string_of_term
  string_of_thm

Mon 12th Dec 05         iter.ml

Removed more redundant finiteness assumptions from some theorems. These
may seem a bit too "hacky" to expose, but it's very convenient to be able to
apply these with no finiteness worries.

  NSUM_SUPPORT = |- !f s. nsum (support (+) f s) f = nsum s f
  SUM_SUPPORT = |- !f s. sum (support (+) f s) f = sum s f

  NSUM_CMUL = |- !f c s. nsum s (\x. c * f x) = c * nsum s f
  SUM_CMUL = |- !f c s. sum s (\x. c * f x) = c * sum s f
  SUM_NEG = |- !f s. sum s (\x. --f x) = --sum s f

Deleted NSUM_CMUL_NUMSEG, SUM_CMUL_NUMSEG and SUM_NEG_NUMSEG since they're now
nothing but instances of the general case.

Fri  9th Dec 05         iter.ml

Realized that several "nsum" theorems had stupid "0 <= ..." properties that I
just took over from the real numbers, but of course these are redundant for N.
Just removed NSUM_POS_LE and NSUM_POS_LE_NUMSEG, NSUM_POS_EQ_0 and
NSUM_POS_EQ_0_NUMSEG. On the other hand added the more useful bi-implications:

  NSUM_EQ_0_IFF =
   |- !s. FINITE s ==> (nsum s f = 0 <=> !x. x IN s ==> f x = 0)

  NSUM_EQ_0_IFF_NUMSEG =
    |- !f m n. nsum (m .. n) f = 0 <=> (!i. m <= i /\ i <= n ==> f i = 0)

Thu  8th Dec 05         iter.ml

Made quite a few theorems stronger by removing unnecessary finiteness
assumptions. The first was just stupidity; the others have become possible
thanks to the canonical choice in the "infinite support" case:

  ITERATE_SUPPORT =
   |- !op f s. iterate op (support op f s) f = iterate op s f

  ITERATE_IMAGE =
    |- !op. monoidal op
            ==> (!f g s.
                     (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
                     ==> iterate op (IMAGE f s) g = iterate op s (g o f))

  ITERATE_BIJECTION =
    |- !op. monoidal op
            ==> (!f p s.
                     (!x. x IN s ==> p x IN s) /\
                     (!y. y IN s ==> (?!x. x IN s /\ p x = y))
                     ==> iterate op s f = iterate op s (f o p))

  ITERATE_EQ =
    |- !op. monoidal op
            ==> (!f g s.
                     (!x. x IN s ==> f x = g x)
                     ==> iterate op s f = iterate op s g)

  ITERATE_EQ_GENERAL =
    |- !op. monoidal op
            ==> (!s t f g h.
                     (!y. y IN t ==> (?!x. x IN s /\ h x = y)) /\
                     (!x. x IN s ==> h x IN t /\ g (h x) = f x)
                     ==> iterate op s f = iterate op t g)

 ITERATE_EQ_GENERAL_INVERSES =
  |- !op. monoidal op
          ==> (!s t f g h k.
                   (!y. y IN t ==> k y IN s /\ h (k y) = y) /\
                   (!x. x IN s ==> h x IN t /\ k (h x) = x /\ g (h x) = f x)
                   ==> iterate op s f = iterate op t g)

and likewise for all the instantiations. Also added the following clause to
SUPPORT_CLAUSES:

   |- ... /\
      (!f g s. support op g (IMAGE f s) = IMAGE f (support op (g o f) s))

Thu  8th Dec 05         sets.ml

Added

  FINITE_IMAGE_INJ_EQ
    |- !f s.
           (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y)
           ==> (FINITE(IMAGE f s) <=> FINITE s)

Wed  7th Dec 05         iter.ml

Changed the definition of "iter" so it always returns the neutral element in
the case of non-finite support. The principal motivation is to allow us to have
a simple congruence rule, which at the moment we have for the special case of
"m..n" but not for general sets. Another pleasing consequence is that quite a
few theorems (ITERATE_EQ, ITERATE_IMAGE, ...) can lose their finiteness
hypothesis. However, I haven't at present added the new congruence rules or
modified the theorems; that will require quite a bit of effort to fix proofs
broken by becoming "too easy".

Tue  6th Dec 05         canon.ml, meson.ml

Attempted to improve CONDS_ELIM_CONV, a slightly dangerous undertaking. Now it
more aggressively splits at the outer level, even if the term contains
quantifiers, provided the condition being tested is free. Moreover, it will
achieve some level of sharing when multiple conditional expressions have the
same test.

I also changed CONDS_ELIM_CONV to CONDS_ELIM_CONV' in MESON, since it seems to
be a case where conjunctive splitting is called for.

Tue  6th Dec 05         iter.ml

Added variants of general equality between sums using mutually inverse
functions. This clutter is getting a bit much, but these often seem more
useful.

  ITERATE_EQ_GENERAL_INVERSES =
    |- !op. monoidal op
            ==> (!s t f g h k.
                     FINITE s /\
                     (!y. y IN t ==> k y IN s /\ h (k y) = y) /\
                     (!x. x IN s ==> h x IN t /\ k (h x) = x /\ g (h x) = f x)
                     ==> iterate op s f = iterate op t g)

  NSUM_EQ_GENERAL_INVERSES =
    |- !s t f g h k.
           FINITE s /\
           (!y. y IN t ==> k y IN s /\ h (k y) = y) /\
           (!x. x IN s ==> h x IN t /\ k (h x) = x /\ g (h x) = f x)
           ==> nsum s f = nsum t g

  SUM_EQ_GENERAL_INVERSES =
    |- !s t f g h k.
           FINITE s /\
           (!y. y IN t ==> k y IN s /\ h (k y) = y) /\
           (!x. x IN s ==> h x IN t /\ k (h x) = x /\ g (h x) = f x)
           ==> sum s f = sum t g

Mon  5th Dec 05         Examples/pocklington.ml

It was pointed out to me by Freek that there's still no proof of the
multiplicativity of the totient function, so I added this and various other
useful lemmas:

  PHI_FINITE_LEMMA =
    |- !P n. FINITE {m | coprime(m,n) /\ m < n}

  CONG_IMP_EQ =
    |- !x y n. x < n /\ y < n /\ (x == y) (mod n) ==> x = y

  CONG_DIVIDES_MODULUS =
    |- !x y m n. (x == y) (mod m) /\ n divides m ==> (x == y) (mod n)

  MOD_MULT_CONG =
    |- !a b x y.
           ~(a = 0) /\ ~(b = 0)
           ==> ((x MOD (a * b) == y) (mod a) <=> (x == y) (mod a))

including more forms of the Chinese remainder theorem combining existence and
uniqueness:

  CHINESE_REMAINDER_UNIQUE =
    |- !a b m n.
           coprime(a,b) /\ ~(a = 0) /\ ~(b = 0)
           ==> (?!x. x < a * b /\ (x == m) (mod a) /\ (x == n) (mod b))

  CHINESE_REMAINDER_COPRIME_UNIQUE =
    |- !a b m n.
           coprime(a,b) /\
           ~(a = 0) /\
           ~(b = 0) /\
           coprime(m,a) /\
           coprime(n,b)
           ==> (?!x. coprime(x,a * b) /\
                     x < a * b /\
                     (x == m) (mod a) /\
                     (x == n) (mod b))

and finally the multiplicativity property itself:

  PHI_MULTIPLICATIVE =
    |- !a b. coprime(a,b) ==> phi (a * b) = phi a * phi b

Mon  5th Dec 05         sets.ml

Added CARD_IMAGE_INJ_EQ, which can be handy to avoid explicitly expanding
the image.

  |- !f s t.
         FINITE s /\
         (!x. x IN s ==> f x IN t) /\
         (!y. y IN t ==> (?!x. x IN s /\ f x = y))
         ==> CARD t = CARD s

Sat  3rd Dec 05         sets.ml

Added a type annotation to INTERS_0 so it doesn't look so ugly with the new
union-printing.

Sat  3rd Dec 05         meson.ml

Tried to do the dual thing for MESON, adding a new UNWIND_CLAUSAL_EQUATION
to eliminate equality from assumptions that modulo clausification are like `!x.
x = a ==> P(x)` and replace them with `P(a)`. Took the chance to eliminate
definition of the function GSPEC, which is only really used locally and clashes
with the definitional theorem for the set constant. Just doing
UNWIND_CLAUSAL_EQUATION where possible *can* actually make things worse,
because the "stupid" form was useful in contrapositive mode I assume. So
instead of replacing the "stupid" form I add both. This is a compromise: it may
still increase the search space but at least shouldn't increase the depth and
so *really* be a disaster. Well, that's the theory...

Sat  3rd Dec 05         tactics.ml

Generalized SUBST_VAR_TAC to do constants too, which is even easier.

Fri  2nd Dec 05         tactics.ml, meson.ml

Added SUBST_VAR_TAC, which will perform substitution if one side of the
equation is a variable not occurring in the other (or do nothing for a
reflexive equation). Added it just at the end of the MESON canonicalization;
I hope this will render some simple equality propagation more efficient.

********************** RELEASE OF VERSION 2.10 **********************

Wed 30th Nov 05         Examples/permutations.ml, Examples/product.ml [new files]

Added these two files, one with a quite decent theory of permutations, one with
a fairly spartan theory of products, which could be beefed up with a little
boring work.

Wed 30th Nov 05         iter.ml

Added theorems about bijections of the indexing set:

  ITERATE_BIJECTION =
    |- !op. monoidal op
            ==> (!f p s.
                     FINITE s /\
                     (!x. x IN s ==> p x IN s) /\
                     (!y. y IN s ==> (?!x. x IN s /\ p x = y))
                     ==> iterate op s f = iterate op s (f o p))

  SUM_BIJECTION =
    |- !f p s.
           FINITE s /\
           (!x. x IN s ==> p x IN s) /\
           (!y. y IN s ==> (?!x. x IN s /\ p x = y))
           ==> sum s f = sum s (f o p)

  NSUM_BIJECTION =
    |- !f p s.
           FINITE s /\
           (!x. x IN s ==> p x IN s) /\
           (!y. y IN s ==> (?!x. x IN s /\ p x = y))
           ==> nsum s f = nsum s (f o p)

about composing iterated operations over a Cartesian product set:

  ITERATE_ITERATE_PRODUCT =
    |- !op. monoidal op
            ==> (!s t x.
                     FINITE s /\ (!i. i IN s ==> FINITE(t i))
                     ==> iterate op s (\i. iterate op (t i) (x i)) =
                         iterate op {i,j | i IN s /\ j IN t i} (\(i,j). x i j))

  NSUM_NSUM_PRODUCT =
    |- !s t x.
           FINITE s /\ (!i. i IN s ==> FINITE(t i))
           ==> nsum s (\i. nsum (t i) (x i)) =
               nsum {i,j | i IN s /\ j IN t i} (\(i,j). x i j)

  SUM_SUM_PRODUCT =
    |- !s t x.
           FINITE s /\ (!i. i IN s ==> FINITE(t i))
           ==> sum s (\i. sum (t i) (x i)) =
               sum {i,j | i IN s /\ j IN t i} (\(i,j). x i j)

And this, which had somehow been forgotten in the general case:

  ITERATE_EQ =
   |- !op. monoidal op
           ==> (!f g s.
                    FINITE s /\ (!x. x IN s ==> f x = g x)
                    ==> iterate op s f = iterate op s g)

and these more general-looking theorems in all instantiations:

  ITERATE_EQ_GENERAL =
    |- !op. monoidal op
            ==> (!s t f g h.
                     FINITE s /\
                     (!y. y IN t ==> (?!x. x IN s /\ h x = y)) /\
                     (!x. x IN s ==> h x IN t /\ g (h x) = f x)
                     ==> iterate op s f = iterate op t g)

  NSUM_EQ_GENERAL =
    |- !s t f g h.
           FINITE s /\
           (!y. y IN t ==> (?!x. x IN s /\ h x = y)) /\
           (!x. x IN s ==> h x IN t /\ g (h x) = f x)
           ==> nsum s f = nsum t g

  SUM_EQ_GENERAL =
    |- !s t f g h.
           FINITE s /\
           (!y. y IN t ==> (?!x. x IN s /\ h x = y)) /\
           (!x. x IN s ==> h x IN t /\ g (h x) = f x)
           ==> sum s f = sum t g


Wed 30th Nov 05         sets.ml

Added IN_ELIM_PAIR_THM = |- !P a b. (a,b) IN {(x,y) | P x y} <=> P a b

Tue 22nd Nov 05         Examples/transc.ml

Added some missing derivative theorems to "diff_net": sqrt, asn and acs. The
DIFF_SQRT theorem wasn't even there at all:

  DIFF_SQRT = |- !x. &0 < x ==> (sqrt diffl inv (&2 * sqrt x)) x

Fri 18th Nov 05         Examples/floor.ml

Put interface maps "real_of_int" and "int_of_real" for the "dest_int" and
"mk_int" functions, and proved "integer" and "is_int" are the same. Really, I
would have preferred to just fix the names back in "int.ml" but was put off by
the thought of breaking Tom's proofs: he uses "dest_int" at least quite
extensively and may rely on its hash value.

Thu 17th Nov 05         make.ml

Added a version number (now set to "2.10" for next planned public release) and
set it to appear in the startup banner.

Thu 17th Nov 05         meson.ml

Scaled back the default chattiness of MESON (unless "meson_chatty" is set),
with a one-line output that's almost as informative as the old screed.

Thu 17th Nov 05         parser.ml. printer.ml

Introduced "string_of_type" and "print_type" (now without surrounding quotes
and colon) and renamed old "print_type" (with quotes and colon) as
"print_qtype". This is more consistent with the naming scheme for terms.

Introduced parsing and printing of "(:ty)" as "UNIV:ty->bool". This is very
helpful when using my functional approach to Cartesian products. It can be
disabled by setting the new variable "typify_universal_set" to false.

Wed 16th Nov 05         define.ml

Added some limited support for intelligent admissibility analysis of "sum" and
"nsum". Slightly lazily, I don't do the careful tupling, and just do
beta-conversion afterwards, so it's only really reliable for one-argument
functions that appear themselves in the summation. But this is a useful special
case. It would be easy but tedious to generalize it. The new theorems
themselves are, I believe, sufficiently generic,

  ADMISSIBLE_SUM =
    |- !(<<) p s h a b.
           (!k. admissible (<<) (\f x. a(x) <= k /\ k <= b(x) /\ p f x) s
                (\f x. h f x k))
           ==> admissible (<<) p s (\f x. sum (a(x) .. b(x)) (h f x))

  ADMISSIBLE_NSUM =
    |- !(<<) p s h a b.
           (!k. admissible (<<) (\f x. a(x) <= k /\ k <= b(x) /\ p f x) s
                (\f x. h f x k))
           ==> admissible (<<) p s (\f x. nsum (a(x) .. b(x)) (h f x))

Tue  8th Nov 05         pa_j_3.09.ml [new file]

Flemming Andersen pointed out that the latest pa_j.ml doesn't work in 3.09;
there have been yet more changes! So I created a new pa_j.ml for 3.09,
correctly I hope.

Tue  8th Nov 05         preterm.ml, parser.ml, printer.ml

Added pmk_setcompr, which generalizes pmk_setabs to be given an explicit
set of bound variables (code from Sean McLaughlin). Now "pmk_setabs" just
figures out the default and calls that. In the parser, added parsing for set
comprehensions with explicit bound variable indication as in "{t | vs | p}".
The printer will also print in this form if either (i) flag
print_unambiguous_comprehensions is set, or (ii) the choices don't match the
defaults (which are unchanged).

Fri  4th Nov 05         printer.ml

Added two new reference variables "unspaced_binops" (binary operators to be
printed without spaces round them) and "prebroken_binops" (binary operators
where line breaks are to be inserted before the operator for preference). This
generalizes the special treatments originally given to "," and "==>"
respectively, which I wanted to extend to "::" and "-->" for a Murphi spec.

Also added "reverse_interface" and used it, and changed DEST_BINARY further, so
that it treats as the same all constants (only constants) that have the same
interface map. Once again this is good for "::" which I had overloaded to two
different things.

Wed  2nd Nov 05         equal.ml

Added PAT_CONV, identifying positions for conversion application using a simple
pattern term. I've contemplated this for a while and I know John Matthews also
suggested it.

Mon 31st Oct 05         hol.ml

Just when I was ready for a Halloween release! I found that I was not
consistently keeping a fully qualified path in the lost "loaded_files". This
can mean "needs" forcing a repetition of something that was loaded using ".".
So I added an explicit transformation of "." into "Sys.getcwd()" in
"file_on_path".

Fri 28th Oct 05         parser.ml

Realized I'd been too hasty accommodating Steve B's requests. The new lexical
conventions hit me almost as soon as I started loading the complex numbers and
hit `&1,&2`. So I implemented a somewhat more intricate approach, where ","
and ";" are set aside into their own class of "separators", and the only
permissible combination is repetition within that class. This gives ",,", which
Steve wanted, and ";;", which I sometimes use in programming language
semantics.

Fri 28th Oct 05         calc_rat.ml

Finally fixed REAL_RAT_DIV_CONV so it doesn't incorrectly ignore "&n / &1".
Also fixed what is a bug, though I've never seen it come up: I was using "="
instead of "=/" for the gcd equality test.

Thu 27th Oct 05         lib.ml

After finally tracking a performance bug to large traversals inside set
operations like "union", I defined inequalities and equalities like "=?", "<=?"
etc. and tried to use them consistently inside the set operations and other
related stuff like "setify", finite partial functions etc. I found this by
porting by old Stalmarck code because Hasan Amjad was interested, and
discovered that compared with 1995 the pure (O)Caml proof search is about 50X
as fast, yet sometimes proof reconstruction was only 3X.

Thu 27th Oct 05         bool.ml

Reorganized derivations to avoid gratuituous MP in CONTR and DISJ_CASES. There
are plenty of others worth doing, no doubt.

Wed 26th Oct 05         parser.ml

Moved the comma from punctuation/bracket status to regular symbol. There seems
no really compelling reason for its position, given that "." and ";" are now
classed as regular symbols. The only slight danger is using identifiers with
leading or trailing underscores next to commas, as for example with ML
pattern-matching "a,_,b". This was stimulated by Steve Brackin's desire to use
",," as the record selector.

Mon 24th Oct 05         calc_rat.ml

Added inv(x pow n) = inv(x) pow n to the initial normalization in REAL_FIELD,
which is consistent with the existing use of inv(x * y) = inv(x) * inv(y). This
fixes the fact that things like this failed (and none too fast!)

 REAL_FIELD
   `&0 < x
    ==> &1 / x pow 2 - &1 / (x + &1) pow 2 =
        (&2 * x + &1) / (x * (x + &1)) pow 2`;;

Mon 24th Oct 05         Makefile

Added a catchall so that if there's no pa_j_XXX.ml for the version of OCaml
being used, we use the 3.08 one. This was stimulated by Steve Brackin's
observation that the build didn't just work on 3.08.4.

Thu 20th Oct 05         Examples/analysis.ml

Added a theorem that's pretty trivial, but tiresome to prove each time it
comes up: SEQ_HARMONIC = |- !a. (\n. a / &n) --> &0.

Thu 20th Oct 05         Examples/hol88.ml [new file]

Added a "HOL88 compatibility" file. This is by no means perfect, but fixes the
most important gaps and incompatibilities I've come across when porting stuff.

Wed 19th Oct 05         grobner.ml

Fixed a bug in "grobner_strong" by adding a special case for pol = []. As it
stood, this was correctly returning the trivial certificate, but incorrectly
returning the degree d = 0 instead of d = 1. This caused some later things to
fail in trivial cases, e.g.

  REAL_RING `x:real = y ==> z:real = z`;;

Mon 17th Oct 05         real.ml

Added REAL_SOS_EQ_0 = |- !x y. x pow 2 + y pow 2 = &0 <=> x = &0 /\ y = &0

Fri  7th Oct 05         parser.ml

Added "isalpha" (letter or prime or underscore) to the character discrimination
functions, and slightly rejigged the implementation.

Tue 20th Sep 05         lib.ml

Tweaked "setify" and "setify'" to remove the pointless historical relic of a
trap for the Unchanged exception. And it was wrong anyway: should have returned
the intermediate sorted list if the exception came from "uniq". This was
pointed out by Sean McLaughlin.

Wed  7th Sep 05         printer.ml

At Sean's suggestion, modified the store of printers to have names. So now
"install_user_printer" takes a name-printer pair not just a printer, and
delete_user_printer takes just a name (it wasn't really usable with just a
function since they can't be compared for equality).

Thu  1st Sep 05         ind-types.ml

Added induction and recursion theorems for treating "bool" as just another
inductive type:

  bool_INDUCT = |- !P. P F /\ P T ==> (!x. P x)
  bool_RECURSION = |- !a b. ?f. f F = a /\ f T = b

and added them to the inductive type store, with knock-on effects on the
"rectype net". This was needed to make a definition Damir Jamsek wanted to work
accepted by "define":

  define `(cnt3(T,T) = 0) /\ (cnt3(F,T) = 1) /\ (cnt3(T,F) = 2)`;;

Sat 20th Aug 05         tactics.ml

Added a warning to the "g" goal-setting function about free variables in the
goal.

Tue 16th Aug 05         parser.ml

At Sean's suggestion, removed the second (parser function) argument from
"delete_parser", since it wasn't used anyway.

Thu 11th Aug 05         sets.ml

Added some theorems about general intersections:

  INTERS_0 = |- INTERS {} = UNIV
  INTERS_1 = |- INTERS {s} = s
  INTERS_2 = |- INTERS {s,t} = s INTER t
  INTERS_INSERT = |- INTERS (s INSERT u) = s INTER (INTERS u)

Tue  2nd Aug 05         Examples/analysis.ml, Examples/transc.ml

Added another tranche of basic but sometimes non-trivial theorems about
integration, including integration over a combined interval, integration over a
subinterval and integrability of continuous functions.

Tue 26th Jul 05         tactics.ml, simp.ml

Enhanced ABBREV_TAC so you can introduce functions with arguments directly
rather than explicitly using the lambda-abstraction. Haven't correspondingly
changed EXPAND_TAC as yet, and I'm not sure I will. Also moved ABBREV_TAC and
EXPAND_TAC into "simp.ml" so the former can use rewriting.

Mon 25th Jul 05         Examples/analysis.ml, Examples/transc.ml

Added quite a few theorems to these files. Some, amazingly, had been put into
the CAML Light version (gtt) but left out here. More substantially, added quite
a few new lemmas about integration, which otherwise had hardly any theorems
except for the FTC.

********************** RELEASE OF VERSION 2.00 **********************

Fri 22nd Jul 05         hol.ml, Examples/sos.ml

At the suggestion of Tom Hales, added "tmp_path", a settable variable for a
temporary path, and used that instead of explicit "/tmp" string in SOS.

Fri 22nd Jul 05         sets.ml

Added HAS_SIZE_PRODUCT_DEPENDENT =
  |- !s m t n.
         s HAS_SIZE m /\ (!x. x IN s ==> t(x) HAS_SIZE n)
         ==> {(x:A,y:B) | x IN s /\ y IN t(x)} HAS_SIZE (m * n)
and made CARD_PRODUCT proof just use this as a lemma.

Fri 22nd Jul 05         Examples/pocklington.ml

Added more basic lemmas about congruences, including solving linear
congruences:

CONG_MOD_MULT =
  |- !x y m n. (x == y) (mod n) /\ m divides n ==> (x == y) (mod m)

CONG_SOLVE = |- !a b n. coprime(a,n) ==> ?x. (a * x == b) (mod n)

CONG_SOLVE_UNIQUE =
 |- !a b n. coprime(a,n) /\ ~(n = 0) ==> ?!x. x < n /\ (a * x == b) (mod n)

CONG_UNIQUE_INVERSE_PRIME =
 |- !p x. prime p /\ 0 < x /\ x < p
          ==> ?!y. 0 < y /\ y < p /\ (x * y == 1) (mod p)

Fri 22nd Jul 05         Examples/card.ml

Added CANTOR_THM = |- (UNIV:A->bool) <_c (UNIV:(A->bool)->bool)
to the cardinality theory.

Tue 12th Jul 05         hol.ml

Changed the first element of load_path to "."; formerly it used Sys.getcwd()
but of course that's at build time, making it rather useless.

Tue 12th Jul 05         calc_rat.ml

Fixed up REAL_FIELD to (i) avoid using the non-trivial inverse adjunction for
inverses of rational constants, and (ii) do a conjunctive not disjunctive
split in its initial canonicalization.

Tue 12th Jul 05         grobner.ml, passim

Added another parameter to "RING_AND_IDEAL_CONV" (hence also "RING" and
"ideal_cofactors") for the inversion ("inv") operation of the ring. Made the
corresponding routine changes to the code to exploit "inv" correctly. It seemed
inconsistent that, say, REAL_RING copes fine with &1 / &3 but not inv(&3)!

Tue 12th Jul 05         canon.ml

Added NNFC_CONV and GEN_NNFC_CONV, which force a conjunctive NNF split. This is
sometimes useful if you're trying to prove something rather than refute its
negation.

Mon 11th Jul 05         grobner.ml

Made "grobner_ideal" fail if the polynomial is not in the ideal instead of just
returning an unsatisfactory list of cofactors. Obviously this is better on
general grounds, and in particular it ensures that failure comes early on big
applications of the IDEAL part of RING_AND_IDEAL_CONV.

Also added initial interreduction of the input polynomials before forming a
Grobner basis. (It would be more elegant just to put them in the spoly rather
than basis list, but that gets complicated by all the criteria that are applied
only when processed.)

Also added depth BETA_CONV and PRESIMP_CONV to the initializations that go on,
otherwise it fails to deal properly with things like REAL_RING `x = &1 ==> T`;
also put a special-case check in the REFUTE code for `F`.

Finally, fixed a problem where if the Strong Nullstellensatz certificate
happened to have degree zero (i.e. the equations along imply 1=0) yet there are
also assumed inequations to refute, the wrong thing was generated. This line:

          let th2 = funpow (deg-1) (IDOM_RULE o CONJ th1) th1 in

was changed to this:

     let th2 = funpow deg (IDOM_RULE o CONJ th1) NOT_EQ_01

Sun 10th Jul 05         sets.ml

Added yet more rather elementary set-theoretic results that aren't completely
trivial conseqences of stuff I already have:

  CHOOSE_SUBSET =
   |- !s:A->bool. FINITE s
                  ==> !n. n <= CARD s ==> ?t. t SUBSET s /\ t HAS_SIZE n

  CARD_UNION_LE =
   |- !s t:A->bool.
          FINITE s /\ FINITE t ==> CARD(s UNION t) <= CARD(s) + CARD(t)

  CARD_UNIONS_LE =
   |- !s t:A->B->bool m n.
          s HAS_SIZE m /\ (!x. x IN s ==> FINITE(t x) /\ CARD(t x) <= n)
          ==> CARD(UNIONS {t(x) | x IN s}) <= m * n

Sat  9th Jul 05         grobner.ml

Fixed an error where in the "no negated equations" case of Grobner, the
filtered set of "things that are indeed equations" was not being used
consistently, but rather at one point the original term was fed to
"grobify_equations".

Fri  8th Jul 05         sets.ml

Added a few new set-theoretic lemmas:

  EMPTY_UNIONS = |- !s. UNIONS s = {} <=> (!t. t IN s ==> t = {})

  HAS_SIZE_UNION =
    |- !s t m n.
           s HAS_SIZE m /\ t HAS_SIZE n /\ DISJOINT s t
           ==> s UNION t HAS_SIZE m + n

  HAS_SIZE_UNIONS =
    |- !s t m n.
           s HAS_SIZE m /\
           (!x. x IN s ==> t x HAS_SIZE n) /\
           (!x y. x IN s /\ y IN s /\ ~(x = y) ==> DISJOINT (t x) (t y))
           ==> UNIONS {t x | x IN s} HAS_SIZE m * n

Thu  7th Jul 05         Examples/prime.ml

Added

  DIVIDES_PRIMEPOW =
  |- !p. prime p ==> (!d. d divides p EXP k <=> (?i. i <= k /\ d = p EXP i))

  COPRIME_DIVISORS =
  |- !a b d e. d divides a /\ e divides b /\ coprime(a,b) ==> coprime(d,e)

Thu  7th Jul 05         Makefile

Added some files to the HOLSRC list in the Makefile; it was missing a few
recent ones such as "iter.ml".

Thu  7th Jul 05         iter.ml

Added some more theorems about sums w.r.t. subsets, which I was a bit surprised
I'd never proved before:

  NSUM_SUBSET =
    |- !u v f.
           FINITE u /\ FINITE v /\ (!x. x IN u DIFF v ==> f x = 0)
           ==> nsum u f <= nsum v f

  NSUM_SUBSET_SIMPLE =
    |- !u v f. FINITE v /\ u SUBSET v ==> nsum u f <= nsum v f

  SUM_SUBSET =
    |- !u v f.
           FINITE u /\
           FINITE v /\
           (!x. x IN u DIFF v ==> f x <= &0) /\
           (!x. x IN v DIFF u ==> &0 <= f x)
           ==> sum u f <= sum v f

  SUM_SUBSET_SIMPLE =
    |- !u v f.
           FINITE v /\ u SUBSET v /\ (!x. x IN v DIFF u ==> &0 <= f x)
           ==> sum u f <= sum v f

Sun  3rd Jul 05         Examples/analysis.ml

Used overloading rather than overriding for the new and "pair-style" sums so it
isn't so thoroughly awkward to mix the two. And added two theorems that relate
old-style and new-style sums (which are a bit messy):

 PSUM_SUM =
  |- !f m n. sum (m,n) f = sum {i | m <= i /\ i < m + n} f

 PSUM_SUM_NUMSEG =
  |- !f m n. ~(m = 0 /\ n = 0) ==> sum (m,n) f = sum (m .. (m + n) - 1) f

Sun  3rd Jul 05         calc_rat.ml

Added a small but significant tweak to REAL_FIELD: rewrite with REAL_INV_MUL in
the initial canonicalization. This often means that it only has to prove
nonzeroness for individual factors, which is in general much easier. For
example, it can now do this, which it couldn't before:

REAL_FIELD `&1 / (&n + &1) - &1 / (&n + &2) = &1 / ((&n + &1) * (&n + &2))`;;

Sun  3rd Jul 05         iter.ml

Added:

  REAL_OF_NUM_SUM =
    |- !f s. FINITE s ==> &(nsum s f) = sum s (\x. &(f x))

  REAL_OF_NUM_SUM_NUMSEG =
  |- !f m n. &(nsum (m .. n) f) = sum (m .. n) (\i. &(f i))

Fri  1st Jul 05         Examples/analysis.ml, Examples/transc.ml

Changed the definitions of "sup" and "sqrt" to match the ones in the
multivariate theory (called xxx_def here) and changed the current definitional
theorems "sup" and "sqrt" to derived consequences. This removes some of the
more gratuitous clashes between the univariate and multivariate theories.

Thu 30th Jun 05         iter.ml, real.ml

Changed "CARD_EQ_SUM" to "CARD_EQ_NSUM" for the "nsum" version; before it
erroneously duplicated the "sum" version. Also removed duplicates from
"real.ml" of REAL_LE_ADD, REAL_LET_ADD and REAL_LT_ADD, already defined in
"realarith.ml". All this name duplication was found by Steven Obua's editing
script!

Thu 30th Jun 05         lib.ml, passim

Made changes so that Steven Obua's proof recording stuff does not require much
to be changed. Mainly: add new parametrized set operations in "lib.ml", define
"equals_thm" and "equals_goal" and use them consistently to avoid ever
comparing theorems for equality with the built-in relation. With a few minor
changes, all the things I did were just following Steven's suggestions.

Wed 29th Jun 05         inter.ml

Changed some bound variables names that range over number segments from x/y (as
in the general set case) to i/j, which seems a bit more intuitive.

Tue 28th Jun 05         define.ml

Fixed some degenerate cases in "define" and associated functions so that it can
handle a trivial equational definition "v = t" and hence be used quite
generally.

Tue 28th Jun 05         tactics.ml

Finally removed the use of "mk_thm" from tactic validity checking. Instead used
a technique going back to Cambridge LCF: added a function "mk_fthm" which adds
a trivially false assumption (actually a distinct constant _FALSITY_ to avoid
unfortunate interactions with real parts of the goal). On a superficial test it
seems to work fine.

Mon 27th Jun 05         class.ml, ind-types.ml

Added sort of benignity checking to type definitions made with
"new_type_definition" and inductive types defined with "define_type". They are
separate mechanisms, and the second is rather crude, actually using the input
*string*. But it should suffice to make sure that almost all proof files will
now load multiple times without redefinition complaints.

Mon 27th Jun 05         drule.ml, define.ml

Added "benign definition" acceptance to "define" and beefed up that in
"new_definition" with the same new feature: it's OK it type variables etc.
change provided both the old and new definitions can be instantiated (by
PART_MATCH) to each other. (This ensures that we can change type variables but
not make the definition more type-constrained, e.g. making two formerly
distinct type variables the same.)

Mon 27th Jun 05         tactics.ml

Changed "REMOVE_THEN" so it removes only the first assumption with that label
(and always the one that's handed to the thm-tactic). Previously it removed
every assumption with that label. However it seemed it might sometimes be
useful to have gentler behaviour; for example in porting Gappa proofs to Coq I
wanted to flag certain assumptions defined by "Notation" to be automatically
expanded so it was natural to use a fixed label for all of them and do
REPEAT(REMOVE_THEN ...).

Thu 23rd Jun 05         calc_rat.ml

Inspired by porting Guillaume Marquiond's support files for Gappa, I decided it
was about time I had some sort of analog to Coq's "field", so I added
"REAL_FIELD". This basically uses RING after adding hypotheses "~(x = &0) ==>
x * inv(x) = &1` for any inverted terms "x" appearing in the formula. But it
splits up the DNF/CNF and separately tries both REAL_RING and REAL_ARITH on
each part, meaning that one can sometimes deduce the nonzero-ness from some
inequalities. For example it will prove this:

  REAL_FIELD
   `!c. &0 < c /\
        &0 < d /\ d < b
        ==> (a - c) / c + (c - b) / b + ((a - c) / c) * ((c - b) / b) =
            (a - b) / b`;;

Tue 21st Jun 05         define.ml

Separated out the initial instantiation of casewise recursion (still called
"instantiate_casewise_recursion") and the later first-pass processing of the
"superadmissible" hypotheses, the latter now a new function
"break_down_admissibility". Also reintroduced into the latter the more
aggressive descent through lambdas, removing the sidecondition check on
"is_applicative" for going through a lambda.

Wed 15th Jun 05         sets.ml

Tweaked SET_RULE so before the final MESON it also writes away "IN". This makes
it better in cases where there's a mixture of set-style and predicate-style set
constructs. I just threw "IN" into the same bunch of rewrites; by the top-down
and minimal-generality rules this should always be fine.

Fri  3rd Jun 05         Examples/binomial.ml, Examples/prime.ml

Cleaned up the proofs a bit; even the definition of the binomial coefficients
is easier using "define". Also added the real-number version.

Also simplified the proof of EUCLID_BOUND and added an explicit "infinite set"
version of the same thing: "PRIMES_INFINITE = |- INFINITE {p | prime p}".

Fri 3rd Jun 05          <passim>.ml

Added a recent copyright banner to all the ML files, except the "pa_j.ml" ones.

Fri 3rd Jun 05          hol.ml, Examples/<passim>

Made loads keep track of files already loaded together with MD5 checksums in a
variable "loaded_files". Added a "needs" function which will act like "loadt"
unless the file, with unchanged checksum, has already been loaded. (It would be
more rigorous to check the timestamps too, but that seems to require
OS-specific stuff, as far as I can see.) Made a few uses of it to show mutual
interdependencies of some of the examples.

Fri  3rd Jun 05         .ocamlinit, hol.ml, sys.ml

Reorganize the system a bit by removing the ".ocamlinit" file and shuffling
much of the stuff from this and the root file into "sys.ml". Reorganized the
root file so that simply modifying the "hol_dir" on the first line will make
everything relocatable.

Sun 29th May 05         Makefile

Made a trivial-looking change to the Makefile: in the preprocessing directive
to build the syntax extension file, changed -pp '...' to -pp "...". The double
quotes also work OK in a pure Windows environment at the command prompt,
whereas single quotes do not. This problem was pointed out to me by Yuri
Matiyasevich.

Fri 27th May 05         ind-types.ml

Added "cases", which is just a slightly more convenient interface to
"prove_cases_thm"; it also handles "num" specially, which otherwise fails
because 0 isn't actually a constant.

Fri 27th May 05         simp.ml

Removed the mostly commented out stuff that's concerned with making simplifier
extensions. (I kept it in "Work/simp.ml" in case I want it sometime.)

Thu 18th May 05         define.ml

Forced the breakdown under admissibility combinators to fail if the function
being defined is used in an apparently `higher-order' way, i.e. inside a lambda
or not applied to anything at one point in the body. This prevents the
breakdown in difficult cases (e.g. the power series example) from going so far
that the wellfoundedndess theorem is unprovable.

Tue 17th May 05         meson.ml

Upped the default MESON limit from 30 to 50. It's occasionally useful for goals
where the proof is long but the search space is narrow, and seems harmless.
When a smaller bound is required it can always be asserted.

Tue 17th May 05         define.ml, wf.ml

Moved the lemma MEASURE_LE back into wf.ml, since it seems more general.

Mon 16th Mat 05         ind-types.ml, list.ml, sets.ml

Added two new stores of injectivity and distinctness theorems and a function to
simply look them up: "distinctness" and "injectivity". This avoids repeated
calls and the verbose names of "prove_constructors_distinct" and
"prove_constructors_injective". Took calls to those out of other files.

Fri 13th May 05         iter.ml

Added  "left" version of the recursion equations for sums, as well as a more
matchable "right" version:

  SUM_CLAUSES_LEFT =
    |- !f m n. m <= n ==> sum (m .. n) f = f m + sum (m + 1 .. n) f
  SUM_CLAUSES_RIGHT =
    |- !f m n. 0 < n /\ m <= n ==> sum (m .. n) f = sum (m .. n - 1) f + f n

  NSUM_CLAUSES_LEFT =
    |- !f m n. m <= n ==> nsum (m .. n) f = f m + nsum (m + 1 .. n) f
  NSUM_CLAUSES_RIGHT =
    |- !f m n. 0 < n /\ m <= n ==> nsum (m .. n) f = nsum (m .. n - 1) f + f n

Fri 13th May 05         arith.ml, passim

Also added another theorem I always end up regenerating:

  LT_NZ = |- !n. 0 < n <=> ~(n = 0)

and changed various scripts to make use of it.

Fri 13th May 05         theorems.ml, passim

Added the two "distribution" theorems that otherwise I always end up recreating
manually. In HOL88 they were called "LEFT_AND_OVER_OR" and "RIGHT_AND_OVER_OR";
I hope these names are more consistent with my naming conventions and a bit
less of a mouthful.

  LEFT_OR_DISTRIB = |- !p q r. p /\ (q \/ r) <=> p /\ q \/ p /\ r
  RIGHT_OR_DISTRIB = |- !p q r. (p \/ q) /\ r <=> p /\ r \/ q /\ r

Fixed up scripts to take out some explicit calls to TAUT replacing them with
this, and likewise with IMP_IMP and IMP_CONJ.

Mon  9th May 05         define.ml [new file]

Added a suite of tools for making general recursive definitions. Some of the
later stuff is a bit hacky, but it's a good placeholder and so long as I make
things upwards compatible, we're OK.

Fri  6th May 05         printer.ml

Fixed an error in the printing of "let"s. Previously no brackets were printed
in `(let x = 2 in x + x) = 4`. Fixed by analogy with the printing of other
binders.

Thu  5th May 05         int.ml

Finally rewrote ARITH_RULE more carefully so that it takes out atomic terms,
and generalizes them with a positivity hypothesis in the integer transition,
after doing basic normalization to expand products etc. This fixes a lot of
problems I've noted over the years with ARITH_RULE not assuming linearity for
composite terms that are otherwise treated atomically, even including the
alpha-equivalence problem:

ARITH_RULE `2 * a * b <= a * b ==> a * b = 0`;;
ARITH_RULE `~(k1 * k2 = 0) ==> 1 <= k1 * k2`;;
ARITH_RULE `n * n * n <= n * n * n + 1 + n + n * n`;;
ARITH_RULE `~(b = 0) ==> 1 <= a * n + b`;;
ARITH_RULE `~(p = 0)
  ==> ~(binade (p,N) b = 0)
  ==> (binade (p,N) b + p - 1 = binade (p,N) b - 1 + p)`;;
ARITH_RULE `2 EXP (p - 1) < k ==> 1 <= k`;;
ARITH_RULE `2 * a * b <= a * b ==> a * b = 0`;;
ARITH_RULE `2 * a * b EXP 2 <= b * a * b ==> (SUC c - SUC(a * b * b) <= c)`;;
ARITH_RULE `7 <= CARD {x | x = 0} ==> 6 < CARD {x | x = 0}`;;

Thu  5th May 05         canon.ml

Added a conversional to apply a conversion to the "atoms" in a first-order
formula: PROP_ATOM_CONV.

Thu  5th May 05         wf.ml

Added the more sophisticated mix of tail and wellfounded recursion:

  WF_REC_TAIL_GENERAL =
   |- !P G H.
          WF (<<) /\
          (!f g x.
               (!z. z << x ==> f z = g z)
               ==> (P f x <=> P g x) /\ G f x = G g x /\ H f x = H g x) /\
          (!f g x. (!z. z << x ==> f z = g z) ==> H f x = H g x) /\
          (!f x y. P f x /\ y << G f x ==> y << x)
          ==> (?f. !x. f x = (if P f x then f (G f x) else H f x))

Tue  3rd May 05         wf.ml

Added wellfoundedness triviality: WF_FALSE = |- WF(\x y. F).

Mon  2nd May 05         grobner.ml

Added conditional elimination to the pre-canonicalization in RING. So now this
works:

REAL_RING
 `p = (&3 * a1 - a2 pow 2) / &3 /\
  q = (&9 * a1 * a2 - &27 * a0 - &2 * a2 pow 3) / &27 /\
  x = z + a2 / &3 /\
  x * w = w pow 2 - p / &3
  ==> (z pow 3 + a2 * z pow 2 + a1 * z + a0 = &0 <=>
       if p = &0 then x pow 3 = q
       else (w pow 3) pow 2 - q * (w pow 3) - p pow 3 / &27 = &0)`;;

Sun 24th Apr 05         sets.ml

Added another "how did I manage without it for so long" result about sets and
functions:

  CARD_LE_INJ =
  |- !s t.
         FINITE s /\ FINITE t /\ CARD s <= CARD t
         ==> (?f. IMAGE f s SUBSET t /\
                  (!x y. x IN s /\ y IN s /\ f x = f y ==> x = y))

Sat 23rd Apr 05         arith.ml, Examples/pocklington.ml

Moved the definition of the "minimal" binder back into the core arithmetic
file, since it seems potentially to be quite useful.

Fri 22nd Apr 05         iter.ml

Added

 HAS_SIZE_NUMSEG    = |- !m n. m .. n HAS_SIZE (n + 1) - m
 CARD_NUMSEG_1      = |- !n. CARD(1 .. n) = n
 HAS_SIZE_NUMSEG_1  = |- !n. 1 .. n HAS_SIZE n

Fri 22nd Apr 05         sets.ml

Added  CARD_PSUBSET =
  |- !a b. a PSUBSET b /\ FINITE b ==> CARD a < CARD b

Tue 19th Apr 05         sets.ml

Added IN_IMAGE into SET_TAC, which had somehow got forgotten before.

Thu 14th Apr 05         sets.ml

Added

  FORALL_IN_CLAUSES =
   |- (!P. (!x. x IN {} ==> P x) <=> T) /\
      (!P a s. (!x. x IN a INSERT s ==> P x) <=> P a /\ (!x. x IN s ==> P x))

  EXISTS_IN_CLAUSES =
   |- (!P. (?x. x IN {} /\ P x) <=> F) /\
      (!P a s. (?x. x IN a INSERT s /\ P x) <=> P a \/ (?x. x IN s /\ P x))

Tue 12th Apr 05         iter.ml [new file]

Added a new file right at the end of the core build containing segments of
natural numbers together with iterated operations in general and the cases of
sums of natural numbers ("nsum") and reals ("sum") in particular.

Tue 12th Apr 05         realax.ml, real.ml, calc_rat.ml, Examples/analysis.ml

Removed the definition of "sum" (realax.ml), as well as all the theorems about
it (in real.ml) and the conversions REAL_SUM_CONV, REAL_HORNER_SUM_CONV (from
calc_rat.ml). Moved it all into "Examples/analysis.ml", ready to make a nicer
version the core default.

Thu  7th Apr 05         meson.ml, sets.ml

Added MESON, a rule form of MESON_TAC[]. Useful for generating trivial lemmas
on the fly. Used it once in "sets.ml"; also made a similar tweak replacing
SET_TAC[] proof with SET_RULE.

Thu  7th Apr 05         bool.ml

Uncommented the line giving "=" precedence 12; I'd like the keep this as the
default now.

Mon  4th Apr 05         printer.ml

Fixed a bug where prefix operators weren't getting parenthesized in the "1000
precedence context" case; this was pointed out by Tom Hales. For example `f
(~x) y` and `f x (--(&1))` were printing without brackets.

Also fixed the longstanding bug of printing double negations without an
intervening space.

Sun  3rd Apr 05         Makefile

Modified the Makefile so that "hol.multivariate" gets built from "hol" not
right from scratch. Also added "hol.sosa" with SOS and analysis and "hol.card"
with cardinal arithmetic.

Sun  3rd Apr 05         printer.ml

Fixed the printer so it doesn't put brackets in right-iterated pairs like
`1,2,3`, which formerly printed as `1,(2,3)`. The problem was that when
stripping an iterated pair, a comparison with the original "," was done, yet
that has a different type. Fixed it by putting a special case for "," in
DEST_BINARY.

Sat  2nd Apr 05         sets.ml

Added three theorems (formerly in Multivariate/misc.ml):

SUBSET_RESTRICT = |- !s P. {x | x IN s /\ P x} SUBSET s
FINITE_RESTRICT = |- !s p. FINITE s ==> FINITE {x | x IN s /\ P x}
CARD_UNION_EQ =
  |- !s t u.
         FINITE u /\ (s INTER t = {}) /\ (s UNION t = u)
         ==> (CARD s + CARD t = CARD u)

Fri  1st Apr 05         calc_rat.ml

Made both REAL_RING and REAL_ARITH (hence REAL_ARITH_TAC) first write away the
decimal notation "#n". Otherwise they failed on trivialities containing decimal
numbers, e.g. `~(#1 = #2)`.

Mon 28th Mar 05         grobner.ml, int.ml

Moved back NUM_SIMPLIFY_CONV and applied it as a prenormalizer to NUM_RING;
also made it rewrite SUC to something recongnizable inside. In addition, made
the generic RING tactic simply ignore non-equational atoms, rather than choking
on them.

Fri 25th Mar 05         ind-types.ml

Fixed "prove_constructors_distinct" so that it will work with
num_RECURSION_STD. (The fact that `0` is not actually a constant was previously
causing trouble.) Added "num" to !inductive_type_store and slightly reordered
it. More dramatically, added a new store "basic_rectype_net" and a function
"extend_rectype_net" to expand it, making the type definition stuff
automatically add cases and distinctness theorems to it; also provided a
conversion RECTYPE_EQ_CONV to apply it reasonably efficiently at depth. Since
there can be quadratically many distinctness clauses, it would be better to
have a clever conversion (e.g. via an auxiliary discriminator map into N) but I
tried a 100-constructor type and the time to add this stuff was comparable to
the time for the core definition.

Thu 24th Mar 05         arith.ml

Modified NUM_MULTIPLY_CONV so that it doesn't descend into subterms that are
unquantified. This is analogous to what's done in CONDS_ELIM_CONV, and perhaps
in fact I ought to be doing something more sophisticated like that. Anyway,
this fixes a regressive bug that ARITH_RULE was failing on `2 EXP (p - 1) < k
==> 2 EXP (p - 1) <= k - 1` because it was creating a separate quantified
formula in both arms of the implication.

Sun 20th Mar 05         term.ml, thm.ml, basics.ml, pair.ml, drule.ml

Recoded "mk_comb", "is_eq" and "dest_eq" in a somewhat more "pattern-matchy"
style. Also PE'd the "mk_const" in "mk_binder". Similarly PE'd MK_FORALL,
MK_EXISTS and mk_pair. The efficiency difference doesn't seem to be great, but
it is a bit faster.

Sun 20th Mar 05         lib.ml

Made explicit definitions of "assoc" and "rev_assoc" rather than calling
"find". (But kept the exception as "find" for compatibility.) Not so
spectacular, but it takes a couple of percent off the load time.

Sun 20th Mar 05         thm.ml

Inspired by Sean's observation that "find" was taking 70% of the profile, I
tried replacing "mk_eq" with a version that does an "inst" rather than a
"mk_const" each time. This made the core a *lot* faster (1:25 to build versus
2:11).

Mon 14th Mar 05         make.ml

Added a call to "Gc.compact()" before the checkpointing in "self_destruct".
This often makes the image a lot smaller.

Thu 10th Mar 05         tactics.ml

Removed old USE_ASSUM which I'd forgotten I ever wrote and duplicates the
function of USE_THEN.

Tue  8th Mar 05         parser.ml

Made a little tweak to the lexical analysis so that you can use the
"glue either symbolic or alphanumeric tokens together with underscores"
more general in two respects: these identifiers can start with an underscore,
and there can be multiple underscores in the glueing section. The immediate
motivation was that I wanted to use "_|_" for a perpendicularity relation, but
it seems generally sensible.

Tue  8th Mar 05         grobner.ml

Changed to using WEAK_DNF_CONV, which is a *lot* faster in many cases than
the egregious PROP_DNF_CONV; added a custom disjunctive refuter so that we
don't need to reassociate the disjuncts. I should probably go one step
further as in realarith.ml and use conjuncts directly too, and hence never
create the normal forms at all.

Fri  4th Mar 05         grobner.ml

Fixed a (fairly gross) error in the RING procedure, which was not working
properly in relatively trivial cases where there were no "positive" or no
"negative" elements in the certificate, notably in degenerate cases like
`(x = &0) ==> (&1 = &1)`;;

Wed  2nd Mar 05         sets.ml

Added use of "IN_ELIM_THM" to SET_TAC. Funny this wasn't done before, but I
guess I was mainly using it for combinations of the usual set operators.

Also added SET_RULE, not before time.

Tue  1st Mar 05         Makefile

Simplified the camlp4 library search yet again using "-I +camlp4", which was
pointed out to me by Trevor Morris.

Thu 17th Feb 05         term.ml

Slightly recoded "paconv" in what I think is a clearer style with corresponding
matching of the pair of terms. Moreover it should I hope be a little more
efficient, with no subcalls to "type_of" and wasteful "alphavars" checking of
cases where only one term is a variable.

Also did a similar simplification of "type_of"; it now doesn't have the extra
"chase length" argument (which didn't pass through abstractions anyway). I hope
this simpler version will also be more efficient.

Mon 14th Feb 05         sets.ml

Added SIMPLE_IMAGE = |- !f s. {f x | x IN s} = IMAGE f s

Wed  9th Feb 05         lib.ml, pa_j_3.08.ml, pa_j_3.07+2.ml, tactics.ml, equal.ml

Added a few more syntax tweaks so that new infixes work when parenthesized as
in "(o)" or "(THEN)". For "o" and "upto" I removed the underscored names, which
are not needed. But I can't seem to do the same for the others because the
uppercaseness still spoils stuff; nevertheless the underscored names don't need
to appear in sources. Also exposed the hashtable (Pa_j.ht) so that additional
extensions can do the same thing without needing to copy all the pa_j stuff.
I'm planning to use this to deal with Freek's Mizar Light.

Wed  9th Feb 05         preterm.ml

Made "make_overloadable" accept repetition of the same overload skeleton, and
only fail if it differs (could even look for equivalence, i.e. mutual
matchability, but I don't think it's worth the additional complexity).

Wed  9th Feb 05         parser.ml

Changed element-parser in set abstractions from "typed_apreterm" to a new class
"nocommapreterm", which is essentially all infix terms that don't, except
inside nested brackets etc., use the "," operator. This allows almost all terms
to be put as elements in set abstractions, with only pairs requiring the
bracketing. I think this is about the best we can do without a more radical
change like using ";" or another reserved word as the separator. One might
argue it would be more consistent to only allow infixes with higher precedence
than ","; that would also be easy to implement if desired.

Tue  8th Feb 05         grobner.ml, calc_rat.ml

Backed off the introduction of IDEAL_CONV and just put in "ideal_cofactors",
which returns the cofactors needed for an ideal certificate, but doesn't
actually prove the equality. (This is really what I wanted for use in the
Positivstellensatz prover.) However, defined appropriate REAL_IDEAL_CONV since
that one might actually be useful.

Mon  7th Feb 05         grobner.ml, calc_rat.ml

Made a new "RING_AND_IDEAL_CONV" which returns a pair of the old RING procedure
plus a more tightly restricted "IDEAL_CONV" that will prove one term is in the
ideal generated by the others. In "calc_rat.ml", put instantiations of both of
them to the reals: REAL_RING and REAL_IDEAL_CONV.

Sun  6th Feb 05         printer.ml

Added a flag "print_all_thm", which suppresses the printing of theorem
hypotheses if set to false. Sean McLaughlin was wanting this, and I sometimes
find it useful myself. It was in fact the default in old HOL88 not to print
hypotheses.

Sat  5th Feb 05         Makefile, make.ml

At the suggestion of Freek Wiedijk, changed the checkpointing signal
from TSTP to USR1. This means you can still do the usual ctrl-z suspend
of a checkpointed process without causing another checkpoint dump.

Thu  3rd Feb 05         arith.ml

Added natural number counterparts of the real "without loss of generality"
lemmas:

  WLOG_LE =
    |- (!m n. P m n <=> P n m) /\ (!m n. m <= n ==> P m n) ==> (!m n. P m n)

  WLOG_LT =
    |- (!m. P m m) /\ (!m n. P m n <=> P n m) /\ (!m n. m < n ==> P m n)
       ==> (!m y. P m y)

Thu  3rd Feb 05         canon.ml

Refined CONDS_ELIM_CONV/CONDS_ELIM_CONV' so that they appropriately share
conditionals with a common condition, even if the things decided by those
conditions are different. For example,

  (if x = 1 then a = 1 else b = 2) /\ (if x = 1 then T else F)

will now generate just one case split over x = 1, not two nested ones.
Although this may seem like a relatively minor efficiency issue, the
change to a more "global" CONDS_ELIM_CONV yesterday was actually breaking
some proofs, because the redundant case splits were then causing MESON to
hit its split limit.

Thu  3rd Feb 05         int.ml

Slightly tweaked NUM_SIMPLIFY_CONV to apply NUM_REDUCE_CONV before the
elimination of division etc. This makes ARITH_RULE a bit better at
handling cases involving unevaluated constant expressions.

Wed  2nd Feb 05         canon.ml, realarith.ml, int.ml

Modified CONDS_ELIM_CONV so that it takes the topmost formula not involving
quantifiers and does the main transformation there; on balance this seems to
give the best chance of sharing several with identical tests, and will also
make the parity of the newly introduced formulas more controllable; the latter
was a problem before in REAL_ARITH. Added parallel CONDS_ELIM_CONV' for
contexts where you want a disjunction; attempted to make both keep the right
parity as they descend terms (but don't expand any <=>s so you can't really do
it right there). Used that in NUM_SIMPLIFY_CONV, which makes
conditional-elimination in the discrete decision procedures better.

Even though I can now rely better on parity, I added the tweak in REAL_ARITH of
doing a preliminary NNF conversion and applying CONDS_ELIM_CONV over the
disjuncts, to avoid gratuitous "sharing" among separate subgoals.

Fixed a silly bug in INT_ARITH, which simply wasn't applying the initialization
conversion and so wouldn't always handle conditionals etc. properly; took the
chance to make it more like the reals one.

Seems to work pretty well, and this fixes a few regressions such as this
(previously this generated a complicated DNF with a = b and ~(a = b) in one
disjunct, which wasn't picked up by the core routine).

  REAL_ARITH `~(x - (if a = b then &1 else &0) <= &0) ==> ~(x = &0)`;;
  ARITH_RULE `~(multiplicity M x - (if x = a then 1 else 0) = 0)
              ==> ~(multiplicity M x = 0)`

Wed  2nd Feb 05         tactics.ml

Only 10 years too late, introduced a few tactics for making more convenient use
of labelled assumptions: USE_THEN, REMOVE_THEN and SUBGOAL_TAC. I was actually
doing a proof today where quoting the terms was becoming too painful. Also
added REPLICATE_TAC, which I occasionally want and end up hacking round.

Tue  1st Feb 05         grobner.ml

Added "grobner_ideal" to certify that a polynomial is in the ideal generated by
another; via a tweak to "resolve_proof" so Start(-1) is treated as zero, I
could essentially use the same framework. Next I'll integrate it into an
actual HOL conversion.

Tue  1st Feb 05         realarith.ml

Made the initial normalization, once it's reached a formula (negating the thing
to be proved for refutation) ?x1..xn. !y1..ym.... no longer just die if m =/=
0. This spoiled the "ignoring" of hopefully irrelevant subterms, as in:

  REAL_ARITH `(!x. x + 1 = SUC x) ==> (y:real = y)`;;

Now it just specializes them, so it not only does that but even will use
universal formulas provided that a completely arbitrary instantiation works:

 REAL_ARITH `(!x:real. x < x) ==> (w = z:real)`;;

This ought to propagate to integer and natural versions too and so fix one or
two regressions.

Mon 31st Jan 05         grobner.ml

Fixed a little potential performance bug: the initial critical pairs were not
sorted by "forder", so that entire optimization was only partly useful.

Fri 28th Jan 05         Makefile

Tidied up the Makefile a bit with more verbose explanations, and made use
of "camlp4 -where" instead of the former hack to find the camlp4 library
directory. Also added a dependency on "pa_j_3.08.2" (these flaws were
pointed out by Tom Hales).

Mon 24th Jan 05         bool.ml

Backed off the change to precedence of "=" a while longer since I want to make
a preliminary quasi-release with Tom's Flyspeck proof.

Fri 21st Jan 05         tactics.ml

Made the change to ABBREV_TAC slightly less sharp by not looking in the
"assumptions of the assumptions" for existing variables.

Thu 20th Jan 05         int.ml

Made a few little tweaks and improvements to INT_ARITH: treated abs (and now
max and min) using the same bubble treatment rather than eliminating them, and
avoided explicitly locating and replacing the alien subterms, leaving that to
REAL_ARITH; this makes the basic approach applicable even in situations with a
more complicated quantifier structure (in case we ever care).

Thu 20th Jan 05         bool.ml, passim

Finished updating all the Examples for the new precedences; hence made it the
default. Now I just need to fix up some of my own proofs, which I can do little
by little.

Thu 20th Jan 05         realarith.ml, real.ml

Moved REAL_POS back into "realarith.ml" for use in REAL_ARITH. Then modified
REAL_ARITH (not the general wrapper REAL_ARITH, since one really needs a
different notion of 'variable' in the nonlinear case) so that it identifies
"alien" subterms of the form "&t" for t not a numeral, and adds positivity
hypotheses. This means that REAL_ARITH `&k + x:real <= x`, and more interesting
examples, work. But the real advantage is that alien subterms in ARITH_RULE
should inherit the effects.

Thu 20th Jan 05         int.ml

Added a conversion NUM_TO_INT_CONV to convert an assertion over N to a
corresponding one over Z. Previously this was embedded in INT_ARITH itself
and would only handle universal formulas. But now I want to use it as a
subcomponent in Cooper's algorithm too. Modified ARITH_RULE to use this
rather than the previous stuff. This now no longer does anything about
alien subterms, i.e. "&t" for t a non-numeral. I plan to put this into
REAL_ARITH (and so implicitly INT_ARITH) instead, since it may occasionally be
useful there anyway. On a quick test of explicitly grepped cases, the only
failure in the new version that worked before was the following, and since the3
solution (rewrite with sub-distributivity) seems ad hoc I changed the proof to
remove it.

 `n * b <= 1 * b + c ==> (n - 1) * b <= c`

The new version also fixes a number of the bugs I had against the old
ARITH_RULE, e.g. `p - 1 <= 2 * p` and `g (f m) < f m + g (f m) + 1`. It still
doesn't fix some cases where the bubbling through `known' operators will fail
to leave a simple "alien" term for REAL_ARITH, e.g. `~(k1 * k2 = 0) ==> 1 <= k1
* k2`. But they're a bit marginal and maybe I should defer them to a more
interesting nonlinear case anyway.

Wed 19th Jan 05         int.ml

Added NUM_SIMPLIFY_CONV, a somewhat more capable conversion for initial
canonicalization of natural number formulas with arbitrary quantifier
structure, which reduces pretty much everything to addition and multiplication.
It does take care to keep the result universal if the original was, and returns
something in NNF. Eventually this will be used in ARITH_RULE (and in Cooper's
procedure in the examples).

Wed 19th Jan 05         arith.ml

Slightly modified NUM_MULTIPLY_CONV to make it a bit better as a component
elsewhere: it now puts the newly introduced subterm in NNF, so if the original
was in NNF so will be the result. Added a flag which if set will stop it from
descending through negations (hence better for a term already in NNF to keep
the signs of the subsidiary quantifiers straight). I also removed the initial
LAMBDA_ELIM_CONV and COND_ELIM_CONVs which I'd rather be able to choreograph
separately.

Sun 16th Jan 05         passim

Finished fixing up the core so that it works with new scheme for "<=>", and for
now returned the precedence of "=" to 2.

Sat 15th Jan 05         bool.ml and passim

Started the project of making the core safe with "<=>" and a higher precision
for "=". Started by adding the following to "bool.ml":

  parse_as_infix("<=>",(2,"right"));;
  override_interface ("<=>",`(=):bool->bool->bool`);;
  parse_as_infix("=",(12,"right"));;

Then went through changing "=" into "<=>" in most places; at least all places
where it would otherwise break, though I probably missed quite a few "harmless"
ones. The medium-term goal is to make the entire core, libraries and proofs I
care about work equally well with or without the last one of the above three
lines. Then I'll probably be brave enough to use the last line in the
production system, and start relying on the new precedence. At least I'm going
to use the first two.

Fri 14th Jan 05         calc_rat.ml

Fixed REAL_RAT_INV_CONV so that "inv(&1 / &n)" or "inv(-- &1 / &n)" return
integer constants not non-canonical things like "&n / &1".

Fri 14th Jan 05         type.ml, term.ml

Added "types()" and "constants()" to return the type and term constants. As
Freek had pointed out, now the underlying lists are hidden, one wants some way
of looking at them.

Fri 14th Jan 05         basics.ml

Deleted the near-duplicate definition of "vfree_in", which is already defined
in "term.ml". They are perfectly identical assuming the first argument is
indeed a variable; there is a small difference in that the term.ml version will
accept a constant and tell you if it's free, whereas the deleted one will give
false if the first argument is not a variable. I don't think this is ever
relied on. I could change it, but (a) it could actually be useful, and (b) it
might be marginally faster, and (c) it keeps the core one line shorter.

Fri 14th Jan 05         tactics.ml

Modified ABBREV_TAC so that it will fail if the chosen abbreviating variable is
already used somewhere in the goal. Previously it would just silently pick a
variant.

Fri 14th Jan 05         printer.ml

Made the printer print a space between two "--" negation symbols; previously it
wasn't doing so and the result "----" didn't re-parse. Also slightly
generalized the circumstances under which it adds a space in "-- &n": now it
does it even if n is not a numeral.

Fri 14th Jan 05         int.ml

Added new definitions int_max and int_min together with int_max_th and
int_min_th, and updated the theorem-lifter to deal with them. Hence added
integer clones of all the real theorems I added in the last batch:

  INT_MIN_MAX = |- !x y. min x y = --(max (--x) (--y))
  INT_MAX_MIN = |- !x y. max x y = --(min (--x) (--y))
  INT_MAX_MAX = |- !x y. x <= max x y /\ y <= max x y
  INT_MIN_MIN = |- !x y. min x y <= x /\ min x y <= y
  INT_MAX_SYM = |- !x y. max x y = max y x
  INT_MIN_SYM = |- !x y. min x y = min y x
  INT_LE_MAX = |- !x y z. z <= max x y = z <= x \/ z <= y
  INT_LE_MIN = |- !x y z. z <= min x y = z <= x /\ z <= y
  INT_LT_MAX = |- !x y z. z < max x y = z < x \/ z < y
  INT_LT_MIN = |- !x y z. z < min x y = z < x /\ z < y
  INT_MAX_LE = |- !x y z. max x y <= z = x <= z /\ y <= z
  INT_MIN_LE = |- !x y z. min x y <= z = x <= z \/ y <= z
  INT_MAX_LT = |- !x y z. max x y < z = x < z /\ y < z
  INT_MIN_LT = |- !x y z. min x y < z = x < z \/ y < z
  INT_MAX_ASSOC = |- !x y z. max x (max y z) = max (max x y) z
  INT_MIN_ASSOC = |- !x y z. min x (min y z) = min (min x y) z
  INT_MAX_ACI = |- (max x y = max y x) /\
                   (max (max x y) z = max x (max y z)) /\
                   (max x (max y z) = max y (max x z)) /\
                   (max x x = x) /\
                   (max x (max x y) = max x y)
  INT_MIN_ACI = |- (min x y = min y x) /\
                   (min (min x y) z = min x (min y z)) /\
                   (min x (min y z) = min y (min x z)) /\
                   (min x x = x) /\
                   (min x (min x y) = min x y)

Fri 14th Jan 05         list.ml

Replaced EX_MEM with the equation the other way round. It's never used anywhere
anyway and it seems better to have it consistent with ALL_MEM. It's now:

 EX_MEM = |- !P l. (?x. P x /\ MEM x l) = EX P l

Thu 13th Jan 05         Examples/pratt.ml, Examples/pocklington.ml

Renamed an overwritten theorem CONG_SUB_CASES. Actually it's only in
pocklington that it gets overwritten, but it seems wise to be consistent.

Thu 13th Jan 05         simp.ml, class.ml, pair.ml, wf.ml, ind-types.ml, realax.ml, sets.ml

Finally cured the minor but persistent irritant that one can't easily use
ETA_AX as a rewrite because it will in general loop on any lambda owing to the
higher-order match. The fix was to modify "net_of_thm" to treat an
(unconditional) rewrite alpha-equivalent to ETA_AX as a special case with a
first order match. Changed various proof scripts to avoid ETA_CONV and just use
ETA_AX as a rewrite, which is the usage pattern I now want to establish.

Thu 13th Jan 05         real.ml

Added a large suite of basic lemmas about max and min, all of which are proved
automatically by the new REAL_ARITH_TAC.

  REAL_MIN_MAX = |- !x y. min x y = --(max (--x) (--y))
  REAL_MAX_MIN = |- !x y. max x y = --(min (--x) (--y))
  REAL_MAX_MAX = |- !x y. x <= max x y /\ y <= max x y
  REAL_MIN_MIN = |- !x y. min x y <= x /\ min x y <= y
  REAL_MAX_SYM = |- !x y. max x y = max y x
  REAL_MIN_SYM = |- !x y. min x y = min y x
  REAL_LE_MAX = |- !x y z. z <= max x y = z <= x \/ z <= y
  REAL_LE_MIN = |- !x y z. z <= min x y = z <= x /\ z <= y
  REAL_LT_MAX = |- !x y z. z < max x y = z < x \/ z < y
  REAL_LT_MIN = |- !x y z. z < min x y = z < x /\ z < y
  REAL_MAX_LE = |- !x y z. max x y <= z = x <= z /\ y <= z
  REAL_MIN_LE = |- !x y z. min x y <= z = x <= z \/ y <= z
  REAL_MAX_LT = |- !x y z. max x y < z = x < z /\ y < z
  REAL_MIN_LT = |- !x y z. min x y < z = x < z \/ y < z
  REAL_MAX_ASSOC = |- !x y z. max x (max y z) = max (max x y) z
  REAL_MIN_ASSOC = |- !x y z. min x (min y z) = min (min x y) z
  REAL_MAX_ACI = |- (max x y = max y x) /\
                    (max (max x y) z = max x (max y z)) /\
                    (max x (max y z) = max y (max x z)) /\
                    (max x x = x) /\
                    (max x (max x y) = max x y)
  REAL_MIN_ACI = |- (min x y = min y x) /\
                    (min (min x y) z = min x (min y z)) /\
                    (min x (min y z) = min y (min x z)) /\
                    (min x x = x) /\
                    (min x (min x y) = min x y)

Mon 10th Jan 05         realarith.ml

Fixed a little bug: the translator for "Square" in Positivstellensatz proofs
was not forcing normalization. Of course this only matters for the extra stuff
I'm doing on nonlinear arithmetic outside the core.

Mon 10th Jan 05         hol.ml

Added an explicit printer for the type "num". I thought this was already there,
but apparently not; I guess I just mostly look at small numbers.

Mon 10th Jan 05         lib.ml, arith.ml, basics.ml, calc_int.ml, grobner.ml, normalizer.ml, preterm.ml, realarith.ml

Added a few bits and pieces: num_0, num_1, num_2, num_10, pow2, pow10,
increasing, decreasing.

Swept through the other files changing "Int x" to "num_x" for x in 0, 1, 2 and
10. This is hardly a big issue, but we might as well get a little extra partial
evaluation.

Sat  8th Jan 05         realarith.ml

Fixed yet another tiny failure in REAL_ARITH: it was failing if the initial
canonicalization already returned `F`.

Fri  7th Jan 05         calc_int.ml

Made the destructor and tester functions for rationals an integers more careful
about excluding non-canonical cases like '--(&0)`, `&5 / &1` and `&2 / &4`.
This is more important now these are used in REAL_ARITH as the justification
for doing no internal simplification.

Fri  7th Jan 05         basics.ml

Modified some of the destructors to use direct pattern-matching rather than
nested primitive destructors. Rather disappointingly, I see no speedup; in fact
if anything it's slower.

Thu  6th Jan 05         canon.ml

Added two more carefully implemented variants of CNF and DNF, though kept the
old olds since they work inside a quantifier prefix and that's depended on
sometimes. WEAK_CNF_CONV and WEAK_DNF_CONV force the appropriate conj-of-disj
or vice versa, but no association, and STRONG_CNF_CONV and STRONG_DNF_CONV go
further and AC-canonicalize. Perhaps I should modify the full conversions to be
comparably efficient; at the moment they're just crude rewrites and may be very
slow.

Thu  6th Jan 05         calc_int.ml, realarith.ml, real.ml, calc_rat.ml

Radically updated the reals decision procedure REAL_ARITH (and so
REAL_ARITH_TAC). The new version copes with arbitrary numbers, rationals and
powers, and uses better data structures for normalization so it can be
dramatically faster on big algebraic simplification tasks (though the more
general approach can make it a little slower on smaller problems).

In addition, sepearated out the integer calculations into a (new) separate file
"calc_int.ml", and the decision procedure into another new file
"realarith.ml". The procedure is highly parametrized, and in fact it's first
bootstrapped over the integers and only extended to cope with rationals later
in "calc_rat.ml". It's also ready to incorporate the kind of more general
Positivstellensatz certificates that nonlinear procedures may want to use.

Thu  6th Jan 05         grobner.ml, list.ml

Renamed the more general basis-computing function "grobner_basis"; it seemed a
bit inelegant to use "grobner" twice for different things. Removed duplicate
(except for one quantifier; anyway it was unused) FORALL_ALL.

Thu  6th Jan 05         printer.ml, basics.ml, bool.ml

Removed some duplicate definitions of syntax operations; moved all those
possible (basically, testers and destructors but not constructors) from
"bool.ml" back to "basics.ml", even when the underlying constants haven't been
defined.

Thu  6th Jan 05         normalizer.ml

Fixed a little bug in the normalizer, which would choke on "x pow y" for "y" a
non-numeral, rather than the desirable behaviour of returning a reflexive
theorem in such a case.

Wed  5th Jan 05         realax.ml, int.ml

Made the natural-number injection symbol "&" overloaded rather than separately
overriden for the integers and reals.

Wed  5th Jan 05         calc_rat.ml

Fixed "dest_ratconst" and "is_ratconst" (and hence "rat_of_term" which uses the
former) so that they refuse to accept rationals with negative or zero
denominators.

Tue  4th Jan 05         canon.ml, meson.ml

Installed a new version of NNF_CONV. This provides a new more general
GEN_NNF_CONV which allows a user-installed conversion for the atomic formulas.
Moreover, it performs a fancier recursion (computing the NNF of a formula and
its negation in parallel) to avoid some recomputation when doing multiple
splits of "iff". Finally, it's just more carefully (and painfully) coded than
the previous version, which was simply done by rewrites.

Threw away the CNF-angling "NNFC_CONV" and made this standard function enter a
similar mode below universal quantifiers; hence used the new function in
MESON_TAC. This should be better than the old version of NNFC_CONV anyway,
which stupidly did the same thing even before passing through quantifiers, less
good for initial case splits. Indeed, the new version only gives 1024 basic
MESON problems when building the core, whereas the old gives 1939.

The speedup is actually quite significant: according to some quick tests, the
time to build the core on my laptop is reduced by about 7% to just under 2
minutes.

Tue  4th Jan 05         theorems.ml

Added EXISTS_UNIQUE = |- !P. (?!x. P x) = (?x. P x /\ (!y. P y ==> (y = x)))

Tue 28th Dec 04         lib.ml

Incorporated my entire "fpf.ml" file for finite partial functions, which
notably adds the "combine" function to what I had before.

Tue 28th Dec 04         realax.ml

Added definitions of "real_max" and "real_min", as well as incorporating their
overloaded forms "max" and "min".

Mon 27th Dec 04         meson.ml

Deleted unused PREMESON_CANON_TAC.

Fri 17th Dec 04         meson.ml

Started reworking the basics of MESON_TAC's first order core. Introduced
somewhat different and simpler unification algorithm that keeps
instantiation in a "graph" (not fully solved) form; also changed the
equality test function. Made the unification function more rationally
keep the two terms asymmetrical so that you know which the variable
offset applies to. Well, this is now a bit neater, but outside the
individual unification steps I still in general solve the graph;
eventually I'd like to fix this too, and move to a more efficient data
structure for instantiations, but that was enough for one day.

Mon 13th Dec 04         sets.ml

Added some theorems about the cardinality of function spaces with finite
"support"/"domain":

  HAS_SIZE_FUNSPACE =
    |- !d n t m s.
           s HAS_SIZE m /\ t HAS_SIZE n
           ==> {f | (!x. x IN s ==> f x IN t) /\ (!x. ~(x IN s) ==> (f x = d))}
               HAS_SIZE (n EXP m)

  CARD_FUNSPACE =
    |- !s t.
           FINITE s /\ FINITE t
           ==> (CARD
                {f | (!x. x IN s ==> f x IN t) /\
                     (!x. ~(x IN s) ==> (f x = d))} = CARD t EXP CARD s)

  FINITE_FUNSPACE =
    |- !s t.
           FINITE s /\ FINITE t
           ==> FINITE
               {f | (!x. x IN s ==> f x IN t) /\
                    (!x. ~(x IN s) ==> (f x = d))}

Changed the proofs of HAS_SIZE_POWERSET and FINITE_POWERSET to use that as a
lemma, and added

  CARD_POWERSET = |- !s. FINITE s ==> (CARD {t | t SUBSET s} = 2 EXP CARD s)

Mon 13th Dec 04         sets.ml, preterm.ml, printer.ml

Fixed a long-standing irritation, that IN_ELIM_THM would disturb the
internal structure of set abstractions that it didn't eliminate; and at
the same time some other apparently harmless theorems like CONJ_ACI
could do the same. Fixed this by defining a new constant SETSPEC and
using this instead of the conjunction and equation it's equivalent to.

  SETSPEC = |- SETSPEC v P t = P /\ (v = t)

Correspondingly changed IN_ELIM_THM to be more delicate; note that we
use a high-order rewrite to ensure that we only eliminate SETSPEC as
part of a successful overall elimination:

  IN_ELIM_THM =
  |- (!P x. x IN GSPEC (\v. P (SETSPEC v)) = P (\p t. p /\ (x = t))) /\
     (!p x. x IN {y | p y} = p x) /\
     (!P x. GSPEC (\v. P (SETSPEC v)) x = P (\p t. p /\ (x = t))) /\
     (!p x. {y | p y} x = p x) /\
     (!p x. x IN (\y. p y) = p x)

More ambitiously, I reverted to an old policy of making the implicit
bound variables in a set abstraction the ones free on both sides of
the "|" in a set enumeration. However, to avoid the problems that caused
me to abandon this policy originally, I special-case the two cases:
(1) when there is exactly one free variable on the left of "|", we
always consider it bound, and (2) if there are no free variables on the
right of the "|" we just consider all those on the left bound. I hope
this will be much more useful.

Fri 10th Dec 04         sets.ml

Added a generalized form of yesterday's theorem; the original is a trivial
consequence of this one.

  SURJECTIVE_IFF_INJECTIVE_GEN =
    |- !s t f.
           FINITE s /\ FINITE t /\ (CARD s = CARD t) /\ IMAGE f s SUBSET t
           ==> ((!y. y IN t ==> (?x. x IN s /\ (f x = y))) =
                (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)))

Also added a couple of simple consequences:

  IMAGE_IMP_INJECTIVE_GEN =
    |- !s t f.
           FINITE s /\ (CARD s = CARD t) /\ (IMAGE f s = t)
           ==> (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y))

  IMAGE_IMP_INJECTIVE =
    |- !s f.
           FINITE s /\ (IMAGE f s = s)
           ==> (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y))

Also added one more triviality:

 HAS_SIZE_CARD = |- !s n. s HAS_SIZE n ==> (CARD s = n)

Thu  9th Dec 04         sets.ml

Added the classic theorem that a function from a finite set into itself is
injective iff surjective. Quite surprising I've managed without it all these
years...

SURJECTIVE_IFF_INJECTIVE =
  |- !s f.
         FINITE s /\ IMAGE f s SUBSET s
         ==> ((!y. y IN s ==> (?x. x IN s /\ (f x = y))) =
              (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)))

Mon  6th Dec 04         README, Examples/pratt.ml, Examples/pocklington.ml

Some minor tidying up: described the new Make process better and made the two
primality-proving routines use the standard "Filename.temp_file" function
rather than an ad-hoc alternative of my own.

Fri  3rd Dec 04         sets.ml

Added HAS_SIZE_CLAUSES =
  |- (s HAS_SIZE 0 = (s = {})) /\
     (s HAS_SIZE SUC n =
      (?a t. t HAS_SIZE n /\ ~(a IN t) /\ (s = a INSERT t)))
which is more useful in many cases than the "more general" HAS_SIZE_SUC; in
particular one can just blindly apply num_CONV and that rewrite rule to produce
expressions for a set known to have a particular number of elements. Added
a conversion HAS_SIZE_CONV to do this expansion in a fairly efficient and
controlled way.

Also added PAIRWISE and "pairwise", which I hope will be useful.

Thu  2nd Dec 04         Makefile

Tidied up the Makefile a bit and made it issue a more explanatory failure
if the native OS isn't Linux and the user tries to build a checkpointed image.

Wed  1st Dec 04         Makefile, make.ml [new file]

Set up a build process for images using "ckpt". It's slightly hacky with
the process sending out a signal to suspend itself, but it seems to work.

Wed  1st Dec 04         lib.ml

Changed the representation of finite partial functions to the canonical
Patricia tree form instead of the AVL variant that was there before.

Wed  1st Dec 04         canon.ml, ind-defs.ml, ind-types.ml, Examples/transc.ml

Added hand-coded rules CONJ_ACI_RULE and DISJ_ACI_RULE for reordering
conjunctions and disjunctions. Got rid of some more ad-hoc implementations in
other files.

Tue 30th Nov 04         sets.ml

Added CARD_EQ_0 = |- !s. FINITE s ==> ((CARD s = 0) = (s = {}))
  and IMAGE_CONST = |- !s c. IMAGE (\x. c) s = if s = {} then {} else {c}

Mon 29th Nov 04         sets.ml

Modified FORALL_PASTECART to |- (!p. P p) = (!x y. P (pastecart x y))
and added EXISTS_PASTECART = |- (?p. P p) = (?x y. P (pastecart x y))

Sat 27th Nov 04         printer.ml

Fixed the internal precedence setting when printing lists, so
that no redundant bracketing is done. Before `[1,2]` would print
as `[(1,2)]`. Of course some people might regard that as a
feature...

Sat 27th Nov 04         sets.ml

Added a natural dual to FORALL_IN_IMAGE, namely

  EXISTS_IN_IMAGE =
   |- !f s. (?y. y IN IMAGE f s /\ P y) = (?x. x IN s /\ P (f x))

as well as this useful lemma:

  SUBSET_IMAGE =
   |- !f s t. s SUBSET IMAGE f t = (?u. u SUBSET t /\ (s = IMAGE f u))

Replaced the old FINITE_SUBSET_IMAGE, which is now called
FINITE_SUBSET_IMAGE_IMP, with the stronger result:

  FINITE_SUBSET_IMAGE =
    |- !f s t.
           FINITE t /\ t SUBSET IMAGE f s =
           (?s'. FINITE s' /\ s' SUBSET s /\ (t = IMAGE f s'))

Wed 24th Nov 04         list.ml

Added LENGTH_MAP2 =
   |- !f l m. (LENGTH l = LENGTH m) ==> (LENGTH (MAP2 f l m) = LENGTH m)

Tue 23rd Nov 04         list.ml

Added LENGTH_EQ_CONS =
  |- !l n. (LENGTH l = SUC n) = (?h t. (l = CONS h t) /\ (LENGTH t = n))

Fri 19th Nov 04         sets.ml

Added two more useful theorems of function calculus, generalizing the
"injectivity" and "surjectivity" theorems, which are the special case of
identity:

  FUNCTION_FACTORS_LEFT =
    |- !f g. (!x y. (g x = g y) ==> (f x = f y)) = (?h. f = h o g)

  FUNCTION_FACTORS_RIGHT =
    |- !f g. (!x. ?y. g y = f x) = (?h. f = g o h)

I suppose I ought, by analogy with the injectivity and surjectivity ones, to
prove them with set restrictions too.

Mon 15th Nov 04         real.ml

Added REAL_SUB_INV =
  |- !x y. ~(x = &0) /\ ~(y = &0) ==> (inv(x) - inv(y) = (y - x) / (x * y))

Mon 15th Nov 04         sets.ml

Added the suite of useful lemmas relating (local) injectivity and surjectivity
to left and right inverses:

  SURJECTIVE_ON_RIGHT_INVERSE =
   |- !f t.
         (!y. y IN t ==> (?x. x IN s /\ (f x = y))) =
         (?g. !y. y IN t ==> g y IN s /\ (f (g y) = y))

  INJECTIVE_ON_LEFT_INVERSE =
    |- !f s.
           (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)) =
           (?g. !x. x IN s ==> (g (f x) = x))

  SURJECTIVE_RIGHT_INVERSE =
    |- (!y. ?x. f x = y) = (?g. !y. f (g y) = y)

  INJECTIVE_LEFT_INVERSE =
    |- (!x y. (f x = f y) ==> (x = y)) = (?g. !x. g (f x) = x)

Sun 14th Nov 04         sets.ml

Added FORALL_PASTECART = |- (!p. P (fstcart p) (sndcart p)) = (!x y. P x y)

Mon  8th Nov 04         sets.ml

Added FORALL_IN_UNIONS =
  |- !P s. (!x. x IN UNIONS s ==> P x) = (!t x. t IN s /\ x IN t ==> P x)

Fri  5th Nov 04         sets.ml

Added PASTECART_EQ =
 |- !x y. (x = y) = (fstcart x = fstcart y) /\ (sndcart x = sndcart y)

Fri  5th Nov 04         sets.ml

Added DIMINDEX_GE_1 = |- !s:A->bool. 1 <= dimindex(s), which is trivial
but often useful.

Thu  4th Nov 04         sets.ml

Added stuff for pasting together two Cartesian products; the type constructor
"finite_sum", pairing and projection functions "pastecart", "fstcart" and
"sndcart", together with the following theorems: DIMINDEX_HAS_SIZE_FINITE_SUM,
DIMINDEX_FINITE_SUM, FSTCART_PASTECART, SNDCART_PASTECART and
PASTECART_FST_SND.

Thu  4th Nov 04         real.ml, int.ml, Examples/analysis.ml

Fixed a trivial and long-standing bug. The theorem REAL_LET_ANTISYM is what
should have been called REAL_LTE_ANTISYM. Moreover, the latter didn't exist
but was misspelled as REAL_LTE_ANTSYM, and was the wrong way round too! This
has been changed to do the obviously right thing. The corresponding change
was made for the integers too.

Thu  4th Nov 04         parser.ml

Added the "atleast" parser combinator, just because I've found it handy in
other contexts.

Tue  2nd Nov 04         sets.ml

Added UNION_SUBSET = |- !s t u. (s UNION t) SUBSET u = s SUBSET u /\ t SUBSET u

Thu 28th Oct 04         type.ml, term.ml

After asking on the OCaml list, I found out (thanks to Andrej Bauer, William
Lovas and Brian Rogoff) that there's a way of making type constructors visible
in pattern matching yet still disallowing their use as constructors, by
using the explicit type definition together with the "private" keyword in the
signature. So I changed the abstract type definitions of types and terms in
that way. That's good, because it won't require people like Tom Hales who've
written code by pattern-matching to change it now I have a proper LCF core. And
maybe I can start defining things that way myself now; it should be much
cleaner and probably more efficient.

Tue 19th Oct 04         Makefile

Modified the Makefile to eliminate the hardwired path to camlp4 (this was
pointed out by Sean); now it looks for the ocaml binary and guesses the
camlp4's library directory based on that.

Tue 12th Oct 04         type.ml, term.ml, thm.ml

Changed the three instances of "open" for the core modules to "include". This
was pointed out by Freek --- the effect is the same but one no longer gets the
irritating qualifiers "Term.term" etc.

Mon 11th Oct 04         arith.ml

Added NUM_MULTIPLY_CONV, which should fairly reliably remove all the "nasties"
from statements about N: predecessor, cutoff subtraction, division and modulus,
plus abstractions and conditionals. This could possibly be a precursor to a
clever decision procedure; at least it makes it easy to adapt my Cooper
implementation for the linear case.

Mon 11th Oct 04         arith.ml

Modified the definitions of DIV and MOD to force them both to be zero when the
divisor is zero. This does make DIV consistent with the reals in that case, and
more importantly it made possible the next part of the change: changed
DIVMOD_ELIM_THM into a simple equality. Previous fixes were on the plane; made
the last in O'Hare airport.

Mon 11th Oct 04         meson.ml

Moved the generalization over free variables in MESON to a later phase when
everything has been loaded into the conclusion. This works better in situations
where you have a given Boolean variable free in both assumptions and
conclusion, by eventually forcing a case split.

Mon 11th Oct 04         printer.ml

Modified the printing of types so it uses precedence and associativity of type
constructors in order to reduce the bracketing; formerly it just blindly
bracketed all nested infixes.

Mon 11th Oct 04         printer.ml

Fixed a misfeature in the treatment of binary operators. They are broken up
iteratively as an easy was of getting a list to then treat according to
specified associativity. But previously the splitup was done based only on the
head operator name, ignoring the type, so that the apparent iteration of a
single operator could actually be multiple type instances. This was
particularly striking after doing the <=>/= redefinition below, when `1 = 2
<=> 2 = 3` would print as `1 = 2 <=> 2 <=> 3`;;

Sat  9th Oct 04         grobner.ml [new file]

Added a new "generic" Grobner basis procedure and its instantiation to N. This
essentially uses Nullstellensatz certificates, so it's only really complete for
C, but still gets a lot of "natural" stuff on other rings and semirings. It
uses Strong Nullstellensatz certificates to avoid using any field properties to
do the Rabinowitsch trick. (If one does have a field it's probably more
efficient to use Weak Nullstellensatz certificates directly and in fact do
proof generation without explicitly contructing the certificate --- the hooks
are all there to do this if desired.) Roughly, it's complete for the universal
theory of commutative cancellation semirings with no nilpotents and
characteristic zero, I think.

Sat  9th Oct 04         lib.ml, calc_rat.ml

Added "lcm_num", "merge" and "mergesort", and moved "gcd_num", "numdom",
"numerator" and "denominator" back from "calc_rat.ml". Also modified
"allpairs" to use appending rather than unioning; I think in most
applications that's actually what's wanted.

Sat  9th Oct 04         parser.ml

Removed the hacky special treatment of equality among the binary operators. I
think this was only necessary because of the lack of a left bracketing symbol
in the old conditionals notation, which I've just scrubbed. Now the infixes are
treated in a completely regular way based only on the list of precedences and
associativities. Among other things, this makes possible a simple change to a
"better" way of dealing with "=" and "<=>" that Freek at least wanted and I
might end up making the default:

  parse_as_infix("<=>",(2,"right"));;
  override_interface ("<=>",`(=):bool->bool->bool`);;
  parse_as_infix("=",(15,"right"));;

Sat  9th Oct 04         parser.ml, Examples/analysis.ml, Examples/transc.ml, Examples/poly.ml

Eliminated the old notation ".. => .. | .." for conditionals; now only the
preferred notation "if .. then .. else .." is accepted. Removed it from the
parser and eliminated the only remaining uses elsewhere in the system. Also
unreserved the "=>" symbol, though not "|" which is also special in set
abstractions.

Sat  9th Oct 04         term.ml

Changed "aconv" to use "Pervasives.compare tm1 tm2 = 0" rather than simply
"tm1 = tm2". This is Xavier Leroy's recommended solution in response to an
observation by Christophe Raffalli on the OCaml list that the builtin equality
no longer guarantees an early-out in the case of pointer eq. A quick test on my
laptop indicates that the build time for the core goes down from 2m7.845s to
1m58.681, nearly an 8% improvement. With non-trivial proofs containing big
terms, the difference might be much more.

Wed  6th Oct 04         drule.ml

Modified "PART_MATCH" so that it fails if any type variables in the hypothesis
get instantiated; previously it only checked for terms in the assumptions
becoming instantiated, and this can lead to some oddities in rewriting, e.g.

  let th1 = ASSUME `f = \s f x:A. if x IN s then f(x) else &0`;;
  let th2 = BETA_RULE (AP_THM th1  `s:A->bool`);;
  let th3 = SYM(BETA_RULE(AP_THM  th2 `f:A->real`));;
  GEN_REWRITE_CONV I [th3] `\a:B. if a IN s then f a else &0`;;

Tue  5th Oct 04         meson.ml

Made one more small tweak to the new MESON canonicalization, to generalize the
goal first. Though this normally disappears, it's beneficial if the variables
are Boolean since it allows for subsequent elimination. This finally fixes a
problem Mike Gordon pointed out back on 15th March 2001, that MESON_TAC fails
on `?b. b = ~a`.

Mon  4th Oct 04         arith.ml, real.ml, int.ml, Examples/pratt.ml Examples/pocklington.ml Examples/cong.ml

Introduced congruence notation "(x == y)" and three overloaded variants of
"mod" for the three basic number systems. All non-trivial stuff is delegated to
Examples files, but at least this gives a uniform approach; formerly the two
prime-number-proving files used a congruence that, while superficially similar,
was defined in a completely different way.

Mon  4th Oct 04         meson.ml

With some trepidation, put a new initial normalizer into MESON_TAC. This should
split conditionals and treat select-terms and abstractions with a degree of
intelligence; this has long been a weak spot of MESON_TAC. I was pleasantly
surprised how little stuff broke, and the ability to handle more things is
already quite useful.

Mon  4th Oct 04         bool.ml

Added syntax operations for "unique exists": is_uexists, dest_uexists and
mk_uexists.

Mon  4th Oct 04         class.ml

Added FORALL_BOOL_THM and EXISTS_BOOL_THM to deal with quantification over
Booleans.

Mon  4th Oct 04         canon.ml

Eliminated the old "EQ_ABS_CONV" and "DELAMB_CONV", which are respectively not
so very useful and only used by MESON. Slightly modified SPLIT_TAC, which will
now be used by MESON instead of a bespoke variant. Added several new functions:
SELECT_ELIM_CONV, SELECT_ELIM_ICONV, SELECT_ELIM_TAC, LAMBDA_ELIM_CONV and
CONDS_ELIM_CONV.

Sat  2nd Oct 04         trivia.ml, ind-types.ml

Renamed the type "one" to "1". Didn't change any theorem names, but also added
the obvious one_INDUCT and one_RECURSION and included them in the inductive
type store (they were forgotten before).

Also defined types "2" (with 2 elements) and "3" (with 3 elements), since I
think all of them will be natural when using low-dimensional vectors ("real^3"
etc.)

Fri  1st Oct 04         sets.ml

Changed FINITE_INTER to |- !s t. FINITE s \/ FINITE t ==> FINITE(s INTER t)
where before it had a conjunction in the assumption, gratuitously weak.

Fri  1st Oct 04         bool.ml

Changed the bound variable names in the connective definitions to be more
intuitive, e.g. "p" (not "P" or "t1") for Booleans, as suggested by Heath
Putnam.

Thu 30th Sep 04         term.ml, thm.ml

Completed the basic "LCF-ization" by making terms and theorems into proper
abstract types.

Thu 30th Sep 04         drule.ml

Removed use of "paconv" in PART_MATCH; I wanted to hide "paconv" and the new
version is more efficient anyway.

Wed 29th Sep 04         type.ml

Made "hol_type" an abstract type, the first step in the more rigorous
"LCF-ification". This was fairly painless; the only hidden value is a
"the_type_constants" reference, which seems not to be used anywhere anyway.

Wed 22nd Sep 04         hol.ml

Modified the default setting of "hol_dir" so that if the "HOLDIR" environment
variable isn't set, it will default to the current directory. The problem with
the existing default was pointed out by Joe Hurd: it only really fits with my
personal setup, whereas the current directory fits the intended build process.

Wed 23rd Jun 04         sets.ml

Added IMAGE_EQ_EMPTY = |- !f s. (IMAGE f s = {}) = (s = {})
  and FORALL_IN_IMAGE =
       |- (!y. y IN IMAGE f s ==> P y) = (!x. x IN s ==> P(f x))

Mon  7th Jun 04         simp.ml

Fixed an error in the treatment of "higher-order" congruence rules. Still,
these need to be chosen with care otherwise beta-redexes arise in matching
and send us into a loop.

Wed  2nd Jun 04         parser.ml, printer.ml, sets.ml

Added a new type of finite Cartesian products with a supported infix syntax
`:A^B`, an indexing function so elements of `x` can be accessed by `x$1` ...
`x$n`, and even a syntax for lambdas. If the type A is infinite, then it forces
a 1-element type, otherwise uses an isomorphic image of A. The immediate
motivation for this was multivariate calculus, but given that parser and
printer support is needed anyway it seemed worth adding to the core. Various
theorems have been included at the end of "sets.ml".

Wed  2nd Jun 04         thm.ml

Modified the basic type definition function so it sorts the type variables into
alphabetical order. It's a pity to put sorting into the core, but we could if
desired use some ultra-simple version. Without this there's no way of enforcing
the right order of type variables, in particular for Cartesian products being
defined.

Wed  2nd Jun 04         sets.ml

Added

  HAS_SIZE_IMAGE_INJ =
   |- !f s n.
        (!x y. x IN s /\ y IN s /\ (f(x) = f(y)) ==> (x = y)) /\ s HAS_SIZE n
        ==> (IMAGE f s) HAS_SIZE n

Wed 12th May 04         sets.ml

Strengthened num_FINITE from an implication to an equality:
|- !s:num->bool. FINITE s = ?a. !x. x IN s ==> x <= a.

Thu 6th May 04          preterm.ml

Completely rewrote the typechecker. The initial motivation was to fix the
fact that overload resolution was not working when the possible types could
contain type variables, e.g. "N->real" for addition in multivariate calculus.
But I took the chance to completely rewrite the typechecker in a more
functional style so that I understand it, expunging the last non-trivial piece
of hol90 code remaining in HOL Light. I suspect the new version is less
efficient, but this is not really an issue for typical use.

Sat 24th Apr 04         hol.ml

Modified the "use_file" function used by "loads" and "loadt" so that it just
returns quietly in the event of failure instead of raising an exception. The
former behaviour resulted in OCaml rolling back the symbol table to the point
before the load. The new behaviour is compatible with "#use" itself. However,
I'd really like to make everything stop on the first error...

Fri 23rd Apr 04         pa_j.ml, Makefile, .ocamlinit

Replaced the old pa_j.ml, which doesn't work under 3.07, with a modified
version kindly provided by Carl Witty. Also added a Makefile encapsulating the
simple build process he pointed out to me.

Fri 16th Apr 04         normalizer.ml

Added parametrization over a variable ordering instead of assuming the default
ordering. The impetus was the desire to re-use this inside the Cooper
quantifier elimination procedure, in which case we want to use the order of
quantifiers to decide the order of variables for easiest elimination.

Also added SEMIRING_NORMALIZERS_CONV which exposes a whole suite of arithmetic
operation conversions as well as the overall normalizer.

Thu  8th Apr 04         lib.ml

Renamed "funset" (map a finite partial function to a set representation of its
graph) to just "graph".

Wed 31st Mar 04         preterm.ml

Fixed a bug in overloading, which was not following its promise to utilize
polymorphic matching rather than simple equality among the possible alternative
types. It was always assigning the generic type instead of the one resulting
from matching, which of course results in an overall typechecking failure.

Wed 31st Mar 04         arith.ml

Added SUC_SUB1 = |- !n. SUC n - 1 = n, which I often use but is not in the
main core arith file.

Tue 30th Mar 04         theorems.ml

Added the following two theorems, which I keep on regenerating for proofs:

 IMP_CONJ = |- p /\ q ==> r = p ==> q ==> r

 IMP_IMP = |- p ==> q ==> r = p /\ q ==> r

Thu 26th Feb 04         real.ml

Added "without loss of generality assume x <= y" (or "x < y") lemmas:

  REAL_WLOG_LE =
    |- (!x y. P x y = P y x) /\ (!x y. x <= y ==> P x y) ==> (!x y. P x y)
  REAL_WLOG_LT =
   |- (!x. P x x) /\ (!x y. P x y = P y x) /\ (!x y. x < y ==> P x y)
      ==> (!x y. P x y)

Tue  3rd Feb 04         arith.ml

Added a couple of theorems that embody some "exclusion zone" reasoning about
integer quotients, and are quite tedious to derive for the cases in hand.

  DIV_LE_EXCLUSION =
    |- !a b c d. ~(b = 0) /\ b * c < (a + 1) * d ==> c DIV d <= a DIV b

  DIV_EQ_EXCLUSION =
    |- b * c < (a + 1) * d /\ a * d < (c + 1) * b ==> (a DIV b = c DIV d)

Tue 25th Nov 03         wf.ml

Added a more general form of the wellfounded recursion theorem with an
"inductive invariant", based on the paper by Krstic and Matthews in TPHOLs'03.
As they point out, this is much more useful for nested recursions like:

  `?g. !x. g(x) = if x = 0 then 0 else g(g(x - 1))`

The proof can be condensed a bit by relying on MESON more but it gets rather
slow in that case:

  let WF_REC_INVARIANT = prove
   (`WF(<<)
     ==> !H S. (!f g x. (!z. z << x ==> (f z = g z) /\ S z (f z))
                        ==> (H f x = H g x) /\ S x (H f x))
               ==> ?f:A->B. !x. (f x = H f x)`,
    let lemma = prove_inductive_relations_exist
      `!f:A->B x. (!z. z << x ==> R z (f z)) ==> R x (H f x)` in
    REWRITE_TAC[WF_IND] THEN REPEAT STRIP_TAC THEN
    X_CHOOSE_THEN `R:A->B->bool` STRIP_ASSUME_TAC lemma THEN
    SUBGOAL_THEN `!x:A. ?!y:B. R x y` (fun th -> ASM_MESON_TAC[th]) THEN
    FIRST_X_ASSUM MATCH_MP_TAC THEN
    SUBGOAL_THEN `!x:A y:B. R x y ==> S x y` MP_TAC THEN ASM_MESON_TAC[]);;

Mon  1st Sep 03         term.ml

Fix for a second soundness bug, this time found by Bob Solovay; it was later
independently discovered by Kevin Watkins. There was an asymmetry in the way
alpha-conversion made its tests, which didn't check the proper correspondences
between binding instances.

  let A = `\z:num. \z:num.z`
  and B = `\x:num. \y:num. x` in
  CONV_RULE NUM_REDUCE_CONV
   (BETA_RULE (AP_THM (AP_THM (ALPHA B A) `1`) `2`));;

The new version, instead of using "assoc", traverses the environment more
carefully checking proper correspondence.

Wed 27th Aug 03         lib.ml

Added "ran" (range of a finite partial function).

Mon 18th Aug 03         normalizer.ml

Added a new file, with a generic (semi)ring normalizer and its instantiation to
the natural numbers. Later, this will be used more, e.g. in REAL_ARITH instead
of the current mediocre version.

Fri 15th Aug 03         sets.ml

Added operations on set enumerations: dest_setenum, is_setenum, mk_setenum,
mk_fset and some conversions SETIFY_CONV and SET_UNION_CONV. I suppose I should
add a whole set eventually.

Tue 22nd Jul 03         term.ml

Did a bit of tidying up of the revised "inst" function, reinstating
Boultonization of the Abs case and removing a redundant "qtry". Actually, we
could now remove "qtry" from "lib.ml", and indeed get rid of "qcomb[2]" with
only one change to the core.

Fri 19th Jul 03         term.ml

Made a preliminary fix to "inst" in order to fix a serious error leading to a
soundness bug found by Tom Hales (the first soundness bug since 1996). The
"unchanged" short-circuiting was bypassing the test for consistency with the
environment, which can still fail even when the current variable is unchanged.
I still need to think more carefully about this code, though. Here is my
simplification of Tom's way of reaching a false theorem:

  let th0 = prove
   (`(?p:bool#B. P p) ==> ?x y. P(x,y)`,
    REWRITE_TAC[EXISTS_PAIR_THM]);;

  let th1 = CONV_RULE (RAND_CONV (BINDER_CONV (GEN_ALPHA_CONV `x:B`))) th0;;

  let th2 = INST_TYPE [`:bool`,`:B`] th1;;

Mon  5th May 03         lib.ml and passim

Made the trivial change of changing "sort" from uncurried to curried
(the expected order is now 'a -> 'a -> bool not 'a # 'a -> bool). This
meant a lot of trivial changes elsewhere, but it's worth getting it
right once and for all.

I also added all the "finite partial" functions stuff, which I've found
very useful in my book code. This is useful for implementing some lookup
structures a bit more efficiently.

This also requires some changes elsewhere, changing "apply" to "apply_prover"
in "simp.ml".

Fri  4th Apr 03         arith.ml

Added EVEN_ODD_DECOMPOSITION =
 |- !n. (?k m. ODD m /\ (n = 2 EXP k * m)) = ~(n = 0)

Fri  7th Mar 03         list.ml

Added APPEND_EQ_NIL = |- !l m. (APPEND l m = []) = (l = []) /\ (m = [])

Thu  6th Mar 03         wf.ml

Added a tactical and tactic WF_INDUCT_THEN and WF_INDUCT_TAC to perform
wellfounded induction over a natural number measure. I do this quite often
and I'm getting fed up with manually introducing a tweaked goal with a new
variable etc.

Wed  5th Mar 03         sets.ml

Added CARD_IMAGE_LE = |- !f s. FINITE s ==> CARD(IMAGE f s) <= CARD s

Tue  4th Mar 03         sets.ml

Added a "dependent" generalization of a previous theorem:

FINITE_PRODUCT_DEPENDENT =
 |- !s t.
        FINITE s /\ (!x. x IN s ==> FINITE(t x))
        ==> FINITE {x,y | x IN s /\ y IN t x}

Thu 27th Feb 03         parser.ml

Made carriage return ("\r", 0x0d) another space. This is helpful on Windows,
which normally uses CR/LF pairs for newline.

Mon 24th Feb 03         sets.ml

Added two theorems about cardinality of Cartesian products:

 CARD_PRODUCT =
   |- !s t.
        FINITE s /\ FINITE t
        ==> (CARD {x,y | x IN s /\ y IN t} = CARD s * CARD t)
 HAS_SIZE_PRODUCT =
   |- !s m t n.
        s HAS_SIZE m /\ t HAS_SIZE n
        ==> {x,y | x IN s /\ y IN t} HAS_SIZE m * n

as well as "<=" versions of existing theorems for "<":

  HAS_SIZE_NUMSEG_LE = |- !n. {m | m <= n} HAS_SIZE n + 1

  CARD_NUMSEG_LE = |- !n. CARD {m | m <= n} = n + 1

  FINITE_NUMSEG_LE = |- !n. FINITE {m | m <= n}

Fri 31st Jan 03         int.ml

Removed spurious "integer" theorems that keep in the type destructors:
INT_INV_0, INT_MUL_LINV, INT_POW_INV.

Also tweaked INT_OF_REAL_THM so it handles conditionals (by adding a theorem to
push "dest_int" through a conditional), and thus INT_POW_NEG is now what it was
always supposed to be instead of having the spurious "dest_int"s.

Fri 31st Jan 03         int.ml

Added more pseudo-definitions (they are definitions on the reals)
INT_GT, INT_LT and INT_SUB.

Tue 28th Jan 03         int.ml

Added INT_LT_TOTAL, which had got left out (probably because it was one
of the real-closed field "axioms" over the reals).

Tue 26th Nov 02         passim

Made various changes to make HOL Light work in OCaml 3.06. The Camlp4
preprocessing can now be switched on and off with the magic identifiers
"set_jrh_parsing" and "unset_jrh_parsing". Also set things up to look in
$HOME/holl before defaulting to "johnh".

Fri  1st Nov 02         real.ml

Added another couple of handy theorems about finite sums:

  SUM_MORETERMS_EQ =
   |- !m n p.
          n <= p /\ (!r. m + n <= r /\ r < m + p ==> (f r = &0))
          ==> (sum (m,p) f = sum (m,n) f)

  SUM_DIFFERENCES_EQ =
   |- !m n p.
          n <= p /\ (!r. m + n <= r /\ r < m + p ==> (f r = g r))
          ==> (sum (m,p) f - sum (m,n) f = sum (m,p) g - sum (m,n) g)

Fri  1st Nov 02         arith.ml

Another basic theorem about DIV and MOD added. Will it never end?

DIV_MONO2 = |- !m n p. ~(p = 0) /\ p <= m ==> n DIV m <= n DIV p

Thu 31st Oct 02         real.ml

Added

 SUM_EQ_0 = |- (!r. m <= r /\ r < m + n ==> (f r = &0)) ==> (sum (m,n) f = &0)

There were already several theorems of that kind, but none of them quite in
the natural convenient form I keep wanting.

Thu 17th Oct 02         real.ml

Added SUM_SWAP =
 |- !f m1 n1 m2 n2.
        sum (m1,n1) (\a. sum (m2,n2) (\b. f a b)) =
        sum (m2,n2) (\b. sum (m1,n1) (\a. f a b))

Wed 16th Oct 02         real.ml

Added SUM_SPLIT = |- !f n p. sum(m,n) f + sum(m + n,p) f = sum(m,n + p) f,
a useful generalization of SUM_TWO, which required a zero start.

Tue 15th Oct 02         arith.ml

Added DIV_MONO_LT = |- !m n p. ~(p = 0) /\ m + p <= n ==> m DIV p < n DIV p

Mon 14th Oct 02         class.ml

Finally added the following theorem, which I should use consistently instead of
CONTRAPOS_CONV. I keep generating it by hand...

  let CONTRAPOS_THM = TAUT `!t1 t2. (~t1 ==> ~t2) = (t2 ==> t1)`;;

Tue 13th Aug 02         wf.ml

Couldn't resist putting in the simpler proof of WF_REC, where by using
FIRST_X_ASSUM, the MESON proof search is quite feasible. I'd used this as an
example at my PaPS invited talk and discussed it with Freek, so had started
looking at the proof again.

Tue 14th May 02         lib.ml

Tidied up "lib.ml" in order to make things more consistent between CAML Light
and OCaml versions. Also tweaked "partition" to do eq-optimization of either
"yes" or "no" results.

Mon  5th May 02         lib.ml

Changed "forall", "exists" and "forall2" to treat list lazily; the previous
implementations in terms of itlist did not have this property! This triviality
improves runtimes by 3.5%

Wed 4th  Apr 02         lib.ml, type.ml, recursion.ml, preterm.ml, real.ml,
                        term.ml

Set up "assocd" and "rev_assocd" to return given defaults rather than failure;
made use of these to replace a few of "try [rev_]assoc ... with Failure _
->" idioms. Perhaps this should be done by more general functions that take
a continuation, to allow us to scrub most of the others?

Wed  4th Apr 02         lib.ml, type.ml, term.ml, meson.ml

Changed "qmap" to propagate pointer equality not use the "Unchanged" exception.
Modified type substitution and the meson FOL shadow syntax operations to work
this way. Still need to do the same to terms.

Tue  5th Mar 02         term.ml, basics.ml, thm.ml

Moved a definition of "vfree_in" from basics.ml into term.ml and added a few
function "freesin". Modified the inference rules to use these instead of
"frees". This was motivated by the fact that GEN "x" (!x. Big[x] |- small[x])
took forever, since a full "frees" of the big assumption is performed.
Admittedly this expands the size of the core, but the new functions are even
simpler than "frees". It would perhaps be nice to eliminate "frees" completely
from the core; it's now only used in variant-finding, and this could presumably
be modified to use the new functions.

Mon  4th Mar 02         pa_j.ml

Added a new extension to bind the last toplevel expression to "it". The code
was provided by Daniel de Rauglaudre in response to my question on the CAML
list, following on from someone else wanting the same thing.

Wed 13th Feb 02         drule.ml

Further modified "new_definition" so that it uses recalled benign definitions
correctly rather than taking the underlying definition as the overall theorem.

Tue 12th Feb 02         drule.ml

Modified "new_definition" so that it does in fact enter definitions in the
store used to accept benign redefinitions --- previously this store was checked
but not updated!

Fri  8th Feb 02         sets.ml

Changed the mis-named FINITE_RECUSION_DELETE to FINITE_RECURSION_DELETE.

Fri  8th Feb 02         <passim>

Ported HOL Light from CAML Light to OCaml (3.04), with hacked syntax to make
"<uppercase><lowercase>*" the special identifiers reserved for type
constructors and modules, and with perverted-comma `...` quotations as well as
<<...>>. The syntax modifier is kept in "pa_j.ml". Some minor syntactic
changes were needed in most filed; only the following are unchanged:

  itab.ml, list.ml, nets.ml, num.ml, sets.ml, theorems.ml, wf.ml

The names of useful functions and theorems are maintained, with the following
exceptions (and lazy -> lazify but I never use that):

 Sum --> sum (the real number sum contravened even modified case conventions)

 assert -> check (assert is a reserved word with incompatible behaviour)

Wed  6th Feb 02         arith.ml

Added DIV_ADD_MOD =
 |- !a b n.
        ~(n = 0)
        ==> (((a + b) MOD n = a MOD n + b MOD n) =
             ((a + b) DIV n = a DIV n + b DIV n))

and DIV_REFL = |- !n. ~(n = 0) ==> (n DIV n = 1)

and MOD_LE = |- !m n. ~(n = 0) ==> m MOD n <= m

Tue  5th Feb 02         sets.ml

Added ITSET_EQ =
 |- !s f g b.
        FINITE s /\
        (!x. x IN s ==> (f x = g x)) /\
        (!x y s. ~(x = y) ==> (f x (f y s) = f y (f x s))) /\
        (!x y s. ~(x = y) ==> (g x (g y s) = g y (g x s)))
        ==> (ITSET f s b = ITSET g s b)

Wed 30th Jan 02         int.ml

Added INT_ABS_MUL_1 =
 |- !x y. (abs(x * y) = &1) = (abs x = &1) /\ (abs y = &1)

Fri 25th Jan 02         int.ml

Added INT_ABS_NUM and INT_ABS_MUL

Wed 23rd Jan 02         sets.ml

Added FINITE_DIFF = |- !s t. FINITE s ==> FINITE(s DIFF t)

Tue 22nd Jan 02         int.ml

Added INT_LE_SQUARE, another forgotten theorem.

Wed  9th Jan 02         lib.ml, gtt.ml/hol.ml, caml, hol

Stimulated by a message from Robert Solovay, re-organized and simplified the
way the system is set up and loaded.

Removed all use of the "Unix" library, so that one doesn't need a special
CAML Light toplevel but can just use "camllight camlnum". (The use of
"sys__command" still assumes a Unix-like environment, but this could also be
changed quite easily.) The changes were:

* Removing the "Interrupt" exception and the signal setup for it, just using
  CAML Light's native "Break", making sure "catch_break true" is set.

* Using sys__time instead of unix__times in the "time" function

* Avoiding using the PID to create unique temporary filenames, instead
  repeatedly adding "_" to the last component of the filename until it
  does not coincide with an existing file. (The file manipulation stuff in
  "sys" is a bit limited, so the code is messy.)

Modified the setup to allow more flexibility over the placement of the filter
file and avoid forcing the user to work in the HOL Light directory itself. The
HOL directory and filter location are now specified by macros HOLDIR and
HOLFILTER in the "hol" and "caml" scripts, and the load sequence attempts to
read these if possible. These use new functions "includes" and "loads" so that
HOL can be run from any location, and the original function "loadt" now uses a
settable load path "load_path" which by default is the current directory and
the HOL system directory.

Wed 21st Nov 01         int.ml

Added a whole new raft of theorems that were forgotten, to do with integer
powers.

 INT_ABS_POW, INT_LE_POW2, INT_LT_POW2, INT_POW_1, INT_POW_1_LE,
 INT_POW2_ABS, INT_POW_2, INT_POW_ADD, INT_POW_EQ_0, INT_POW_INV,
 INT_POW_LE_1, INT_POW_LE2, INT_POW_LE, INT_POW_LT2, INT_POW_LT,
 INT_POW_MONO, INT_POW_MONO_LT, INT_POW_MUL, INT_POW_NEG, INT_POW_NZ,
 INT_POW_ONE, INT_POW_POW

Thu 15th Nov 01         int.ml

Added INT_OF_NUM_SUB = |- !m n. m <= n ==> (&n - &m = &(n - m)) which had
somehow got left out, despite the analogous result for reals.

Thu 15th Nov 01         arith.ml

Added LE_EXP, a natural counterpart to LT_EXP. I'd avoided adding it until now
(doubtless because it's so hideous with all the special cases).

 |- !x m n.
        x EXP m <= x EXP n =
        if x = 0 then (m = 0) ==> (n = 0) else (x = 1) \/ m <= n

Wed 24th Oct 01         bool.ml

Stimulated by a message from Mike Gordon on the hol-developers list, I
discovered that the time taken for GEN on a theorem with an empty assumption
list was not constant. This turned out to be because the MP with the proforma
theorem was comparing (... = (\x. T)) and (... = (\v. T)), and this tips
"aconv" into the full traversal instead of quick equality. Added an explicit
alpha conversion to GEN so that this will now succeed instantly. Actually,
several of these derived rules should avoid MP and use hypotheses, but that's
another issue.

Thu  5th Jul 01         preterm.ml

Fixed a bug that Freek Wiedijk hit when trying to parse a set abstraction
{t[x] | P[x]} with multiple instances of the same variable in the term t[x].
It turned out that "pfrees" was not returning a set, and could repeat the
same variable because "ptm::acc" was used instead of "insert ptm acc", and
this led to the problem since the variable then got existentially quantified
twice, the outer one picking up a polymorphic type.

Thu 28th Jun 01         basics.ml

Fixed a bug in "type_match" pointed out by Michael Norrish; embarrassingly I
thought I'd fixed this before (see 14 Feb 01). This was not recording identity
mappings "A|->A" in the environment so far, meaning that it could allow
impossible matches like `:A#A` to `:A#num`. Fixed it simply by removing the
first line "if vty = cty then sofar else".

Thu 21st Jun 01         sets.ml

Added:

  CARD_IMAGE_INJ =
   |- !f s.
          (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)) /\ FINITE s
          ==> (CARD(IMAGE f s) = CARD s)

  HAS_SIZE_POWERSET =
   |- !s n. s HAS_SIZE n ==> {t | t SUBSET s} HAS_SIZE 2 EXP n

  FINITE_POWERSET =
   |- !s. FINITE s ==> FINITE {t | t SUBSET s}

  IMAGE_DELETE_INJ =
   |- (!x. (f x = f a) ==> (x = a))
      ==> (IMAGE f (s DELETE a) = IMAGE f s DELETE f a)

Tue 22nd May 01         wf.ml

In fact, it's even better; the reverse Skolemization is unnecessary! I took it
out, and MESON can still do everything itself. In fact, with a few minutes, it
can even absorb the shorter proof:

  REWRITE_TAC[WF_IND] THEN REPEAT STRIP_TAC THEN
  X_CHOOSE_THEN `R:A->B->bool` (ASSUME_TAC o last o CONJUNCTS) lemma THEN
  SUBGOAL_THEN `!x:A. ?!y:B. R x y` (fun th -> ASM_MESON_TAC[th]) THEN
  FIRST_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]

Mon 21st May 01         wf.ml

Simplified the proof of WF_REC using "reverse Skolemization" to hide the
messy details of converting a relation into a function. This is now appealingly
short, if tricky.

Wed  9th May 01         int.ml

Some more escapees: INT_ENTIRE, INT_EQ_MUL_LCANCEL, INT_EQ_MUL_RCANCEL,
INT_LT_LMUL_EQ, INT_LT_RMUL_EQ.

Wed  9th May 01         printer.ml

Corrected a few irritating misfeatures with printing of numerals like "&1".
First, avoided space after "&" for integers as well as reals. Second, made
a space appear after "--" in "-- &1" etc. Really, we should have a more
principled treatment of spacing based mainly on whether we end up with two
adjacent printer tokens in the same lexical category (alphanumeric or
symbolic). One day the printer will be rewritten.

Sun  7th May 01         lib.ml

Modified the "time" function so that it also reports elapsed times when a
function generates an exception, i.e. fails or is interrupted. In addition,
moved back the testing of "report_timing" to avoid doing anything special at
all when it's false.

Sat  6th May 01         int.ml

Added INT_LT_MUL, another escapee.

Fri  5th May 01         int.ml

As part of writing a "proforma theorem" version of Michael Norrish's hol98
Cooper algorithm, I improved the integer theory a bit (this is the first time
I've ever used it non-trivially).

Added INT_LT_REFL, INT_LE_LMUL and INT_SUB_LDISTRIB, which had somehow got
forgotten.

Exposed INT_FORALL_POS at the top level (previously it was hidden inside
ARITH_RULE, but is sometimes useful).

Added the Archimedian theorem

  INT_ARCH = |- !x d. ~(d = & 0) ==> (?c. x < c * d)

Fri 13th Apr 01         list.ml

Added ALL2_ALL = |- !P l. ALL2 P l l = ALL (\x. P x x) l

Mon  9th Apr 01         list.ml

Added

  ALL2_MAP2 =
   |- !l m. ALL2 P (MAP f l) (MAP g m) = ALL2 (\x y. P (f x) (g y)) l m

  AND_ALL2 =
 |- !P Q l m. ALL2 P l m /\ ALL2 Q l m = ALL2 (\x y. P x y /\ Q x y) l m

Sat 7th Apr 01          lib.ml

Modified "forall2" to return falsity rather than fail when the two lists have
different lengths. I had been under the impression it already worked this way.

Fri 30th Mar 01         quot.ml

Shortened the proof of the main proforma theorem by using MESON. I don't
remember why I had such an intricate manual proof before. Actually, with
better tweaks for extensionality and select terms, MESON should be capable
of doing the whole thing automatically.

Thu 29th Mar 01         thm.ml, bool.ml, drule.ml, class.ml

Took the lists storing term and type variables out of the core "thm.ml". The
discussion with Roger Jones on the Isabelle list reminded me of something
Konrad Slind pointed out early on in the development of GTT: you don't need to
store the actual definitions to ensure consistency. Renamed the basic
definitional principle "new_basic_definition" by analogy with
"new_basic_type_definition" and used this in bool.ml before the full
definitional principle is defined, and also in class.ml to define
"new_specification".

However, re-introduced the list of definitions higher up in bool.ml, to enable
acceptance of benign redefinitions. This was a nice feature that I used to
have, but it got lost somewhere. This should be extended in two ways: allow
appropriately named variables on the left (in case the definition was generated
by code rather than entered via the quotation parser), and modify for
higher-level derived rules like new_inductive_definition. And likewise for
types.

Sat 24th Mar 01         printer.ml

Fixed a bug in the printing of "{}", which would print that whenever the head
operator is the empty set, even if applied to an argument. This came up porting
Peter Homeier's Church-Rosser proof.

Wed 21st Mar 01         sets.ml

Added a theorem about indexing of finite sets. Surprising I'd always managed
without this so far:

  HAS_SIZE_INDEX =
   |- !s n.
          s HAS_SIZE n
          ==> (?f. (!m. m < n ==> f m IN s) /\
                   (!x. x IN s ==> (?!m. m < n /\ (f m = x))))

Tue  6th Mar 01         tactics.ml

Removed VALID from TAC_PROOF, at the suggestion of Freek Wiedijk. This is a
rather inefficient way to do things since it leads to a double evaluation of
the justification function. Besides, we might want to remove VALID from the
system, since on non-empty lists of subgoals it calls mk_thm (though here it's
only used on the empty list of subgoals).

Instead, added a test and alpha-conversion coercion to "prove" itself, to
ensure that the theorem returned is exactly the same as the original goal, even
up to variable naming.

Tue 27th Feb 01         sets.ml

Added SUBSET_DIFF = |- !s t. (s DIFF t) SUBSET s

Mon 26th Feb 01         sets.ml

Added

  IMAGE_DIFF_INJ =
   |- (!x y. (f x = f y) ==> (x = y))
      ==> (IMAGE f (s DIFF t) = (IMAGE f s) DIFF (IMAGE f t))

Sun 25th Feb 01         sets.ml

Added

  IMAGE_SUBSET = |- !f s t. s SUBSET t ==> IMAGE f s SUBSET IMAGE f t

Sun 25th Feb 01         list.ml

Added MEM_EL = |- !l n. n < LENGTH l ==> MEM (EL n l) l

Sun 25th Feb 01         sets.ml

Added SET_OF_LIST_APPEND =
 |- !l1 l2. set_of_list (APPEND l1 l2) = set_of_list l1 UNION set_of_list l2

Sat 24th Feb 01         meson.ml

Fixed a bug in MESON where an error trap was capturing all failures

  with Cut -> failwith "meson_expand" | _ ->

including Interrupt, hence in some circumstances making it impossible to
interrupt the search. Changed "_" to "Failure _". This has popped up
occasionally over the years, but last time I looked I didn't notice it,
probably because I was searching for "with _".

Thu 22nd Feb 01         sets.ml

Added FINITE_SUBSETS = |- !s. FINITE s ==> FINITE {t | t SUBSET s}

Wed 21st Feb 01         sets.ml

Added IN_SET_OF_LIST = |- !x l. x IN set_of_list l = MEM x l

Wed 14th Feb 01         basics.ml

Fixed a bug in "type_match". Strangely, it was failing to detect inconsistent
matching assignments and allowing say [`:num`,`:A`; `:bool`,`:A`]. This must
have been around for ages without causing (many) problems.

Sun 11th Feb 01         sets.ml

Added

  IMAGE_UNION =
    |- !f s t. IMAGE f (s UNION t) = IMAGE f s UNION IMAGE f t

  IMAGE_o =
    |- !f g s. IMAGE (f o g) s = IMAGE f (IMAGE g s)

Sat 10th Feb 01         wf.ml

Added a theorem asserting that tail-recursive recursion schemes are always
satisfiable.

  WF_REC_TAIL = |- !P g h. ?f. !x. f x = (if P x then f (g x) else h x)

This was pointed out to me by J Moore at the 2000 ACL2 workshop. It would
have saved me a bit of tedious hacking around defining things like unification
algorithms.

Sat 10th Feb 01         num.ml

Added

  num_CASES = |- !m. (m = 0) \/ (?n. m = SUC n)

This is often quite useful, and was in HOL88.

Thu  8th Feb 01         sets.ml

Added:

 FINITE_PRODUCT =
  |- !s t. FINITE s /\ FINITE t ==> FINITE {x,y | x IN s /\ y IN t}

 CARD_DELETE =
  |- !x s.
        FINITE s
        ==> (CARD(s DELETE x) = (if x IN s then CARD s - 1 else CARD s))

Tue  6th Feb 01         sets.ml

Added FINITE_SUBSET_IMAGE =

 |- !f s t.
        FINITE t /\ t SUBSET IMAGE f s
        ==> (?s'. FINITE s' /\ s' SUBSET s /\ t SUBSET IMAGE f s')

The proof is a bit slow (15 seconds); maybe I should unpick more of the
automation. I've already separated out the two subgoals, which improves
things slightly. Anyway, Moore's Law will save me eventually.

Thu 25th Jan 01         tactics.ml

Updated "STRIP_ASSUME_TAC" to discard the theorem if it's alpha-convertible to
an existing assumption. This seems sensible, and the update brings HOL Light in
line with HOL88. The implementation is the same, based on DISCARD_TAC, but this
is only introduced locally since it doesn't seem particularly useful. This
incompatibility arose in porting the proofs concerning graph planarity by
Yamamoto et al. to HOL Light from hol90.

Tue 23rd Jan 01         sets.ml

Uncommented proof (it used to blow up the space usage a long time ago) of

  IN_DELETE_EQ =
   |- !s x x'. (x IN s = x' IN s) = x IN s DELETE x' = x' IN s DELETE x

and added the theorems:

  INTER_ACI =
   |- (p INTER q = q INTER p) /\
      ((p INTER q) INTER r = p INTER q INTER r) /\
      (p INTER q INTER r = q INTER p INTER r) /\
      (p INTER p = p) /\
      (p INTER p INTER q = p INTER q)

  UNION_ACI =
   |- (p UNION q = q UNION p) /\
      ((p UNION q) UNION r = p UNION q UNION r) /\
      (p UNION q UNION r = q UNION p UNION r) /\
      (p UNION p = p) /\
      (p UNION p UNION q = p UNION q)

while renaming the following, inexplicably called INTER_ACI and never used:

  INSERT_AC =
   |- (x INSERT y INSERT s = y INSERT x INSERT s) /\
      (x INSERT x INSERT s = x INSERT s)

Thu 18th Jan 01         lib.ml, calc_num.ml, ind-types.ml, real.ml, tactics.ml

Modified "upto" to be an infix and take two arguments. This seems a much nicer
and more flexible arrangement, and I've been meaning to do it for ages. Of
course, quite a few consequential changes were needed, mostly from "upto n" to
"0 upto n".

Fri 12th Jan 01         tactics.ml

Made the assumption list numbering when a goal is printed work from top to
bottom, i.e. give the oldest assumption number zero, even though it is actually
the last element of the list. NB: this only affects printing, and has no effect
on goal representation. This policy seems more logical and should certainly be
better when using numbers to refer to assumptions (as Freek Wiedijk is thinking
of doing), since an assumption number won't change unless a prior assumption is
deleted. Even better might be to allocate default labels, which would then
never change.

Thu 11th Nov 00         printer.ml

Made set enumerations like `{1,2}` print properly instead of as `1 INSERT 2
INSERT EMPTY`. This includes the case of EMPTY printing as {}. Noticed this
defect while doing 4CT statement with Freek Wiedijk, so made this fix on the
boat from Holland. Apparently this once worked a long time ago with a different
printer-constant called ESPEC, which is no longer used.

Wed  4th Oct 00         wf.ml

Added WF_REFL = |- !x. WF (<<) ==> ~(x << x)

Wed  4th Oct 00         list.ml

Added:

  MAP_FST_ZIP =
   |- !l1 l2. (LENGTH l1 = LENGTH l2) ==> (MAP FST (ZIP l1 l2) = l1)

  MAP_SND_ZIP =
   |- !l1 l2. (LENGTH l1 = LENGTH l2) ==> (MAP SND (ZIP l1 l2) = l2)

  MEM_ASSOC =
   |- !l x. MEM (x,ASSOC x l) l = MEM x (MAP FST l)

  ALL_APPEND = |- !P l1 l2. ALL P (APPEND l1 l2) = ALL P l1 /\ ALL P l2

Note that MAP_FST_ZIP is actually true without the precondition, but this is an
accident of the way ZIP is defined by recursion on the first argument.

Wed  4th Oct 00         basics.ml

Fixed a bug in "mk_gabs" which must have been there forever and I only
noticed when neither PAIRED_BETA_CONV nor GEN_BETA_CONV worked for
`(\(p1,p2). f(p1,p2)) (p1,p2)`. The problem was that "f" was also used for
the internal variable, with a faulty variant procedure due to a type or thinko.
The line:

 let f = variant (frees tm1 @ frees tm2) (mk_var("f",fty))

was originally

 let f = variant (frees tm1 @ frees tm1) (mk_var("f",fty))

Tue  3rd Oct 00         wf.ml

Added WF_LEX_DEPENDENT =
 |- !R S.
        WF R /\ (!a. WF (S a))
        ==> WF (\(r1,s1). \(r2,s2). R r1 r2 \/ (r1 = r2) /\ S r1 s1 s2)

and now deduced WF_LEX as a special case. The extra generality makes almost no
difference to the proof, so it seemed we might as well prove a stronger form.

Mon  2nd Oct 00         list.ml

Added EX_MEM = |- !P l. EX P l = (?x. P x /\ MEM x l)

Fri 29th Sep 00         wf.ml

Finished the proof of WF_LEX which was commented out (actually took it from an
old multiset ordering proof). Also uncommented WF_POINTWISE. However, erased
WF_TC since TC isn't defined at this point in the build, and there is a short
proof in Examples/reduct.ml

Fri 29th Sep 00         list.ml

Defined ASSOC (as in the ML "assoc"), and ITLIST2, and ZIP. I'm suffering from
CAML envy.

Fri 29th Sep 00         trivia.ml

Removed various unused stuff from this file, including the definitions and
consequential theorems for ASSOC, COMM, FCOMM, RIGHT_ID, LEFT_ID and MONOID.
They don't seem particularly general (I've never used them), and I happened to
want the name ASSOC for association lists.

Fri 29th Sep 00         list.ml

Defined FILTER. Added theorems:

  FILTER_APPEND =
    |- !P l1 l2. FILTER P (APPEND l1 l2) = APPEND (FILTER P l1) (FILTER P l2)
  FILTER_MAP = |- !P f l. FILTER P (MAP f l) = MAP f (FILTER (P o f) l)
  MEM_FILTER = |- !P l x. MEM x (FILTER P l) = P x /\ MEM x l

Thu 28th Sep 00         sets.ml

Added FINITE_SET_OF_LIST = |- !l. FINITE(set_of_list l)
      EX_MAP = |- !P f l. EX P (MAP f l) = EX (P o f) l
      EXISTS_EX = |- !P l. (?x. EX (P x) l) = EX (\s. ?x. P x s) l
      FORALL_ALL = |- !P l. (!x. ALL (P x) l) = ALL (\s. !x. P x s) l
      MEM_APPEND = |-!x l1 l2. MEM x (APPEND l1 l2) = MEM x l1 \/ MEM x l2
      MEM_MAP = |- !f y l. MEM y (MAP f l) = ?x. MEM x l /\ (y = f x)

Mon 25th Sep 00         filter.c

Added #include <ctype.h>. Michael Beeson pointed out that this was missing. I'd
just got used to the laxity of gcc's default, but it also complains given
-Wall.

Mon 25th Sep 00         ind-types.ml

Fixed a bug that had been lurking undiscovered in recursive types for a long
time. It was found by Kim Sunesen in hol98 by trying the following:

define_type
  "repDatatype =
      repBool bool
    | repTuple (repDatatype list)
    | repMap (bool list) # (repDatatype list)
    | repSet (bool list)
    | repEnum (bool list)";;

and Michael Norrish identified the fix. Instead of applying the 1-step
denesting transformation just to any of the nested types, apply it to one that
is not a proper subtype of another. Otherwise, "lift_type_bijections" may later
need to cope with lifting isomorphisms through other free recursive types,
which it isn't able to do. The fix just uses:

    let nty = hd (sort (fun (t1,t2) -> occurs_in t2 t1) rectys) in

instead of

    let nty = hd rectys in

Wed 20th Sep 00         tactics.ml

Modified UNDISCH_THEN so it tests for alpha-convertibility rather than
equality. UNDISCH_TAC already did this, but it was forgotten here.

Wed 20th Sep 00         sets.ml

Added FINITE_IMAGE_INJ_GENERAL =
        |- !f A s.
               (!x y. x IN s /\ y IN s /\ (f x = f y) ==> (x = y)) /\ FINITE A
               ==> FINITE {x | x IN s /\ f x IN A}

      HAS_SIZE_NUMSEG_LT = |- !n. {m | m < n} HAS_SIZE n

      CARD_NUMSEG_LT = |- !n. CARD {m | m < n} = n

      FINITE_NUMSEG_LT = |- !n. FINITE {m | m < n}

      INFINITE_NONEMPTY= |- !s. INFINITE s ==> ~(s = EMPTY)

      INFINITE_DIFF_FINITE = |- !s t. INFINITE s /\ FINITE t
                                      ==> INFINITE(s DIFF t)

Thu  7th Sep 00         list.ml

Added LENGTH_REPLICATE = !n x. LENGTH (REPLICATE n x) = n

Sat  2nd Sep 00         parser.ml

Relaxed the lexical rules to allow identifiers to be built up from a mixture
of alphanumerics and symbolics provided adjacent strings of opposite types are
connected by "_". This is a bit of a hack but allows natural idioms like "++_2"
as identifiers. It's also pretty sure to be upwards compatible.

Fri 25th Aug 00         sets.ml

Added INFINITE_IMAGE_INJ =
 |- !f. (!x y. (f x = f y) ==> (x = y))
        ==> !s. INFINITE s ==> INFINITE(IMAGE f s)

Mon 21st Aug 00         printer.ml

Made general binders print properly. Previously this only worked for binders
with simple abstractions as bodies, but not pairs etc. This should now work.

Tue 18th Apr 00         tactics.ml

Added "ANTS_TAC", a slightly more refined version of an idiom I use a great
deal. I had the habit of using the cruder

  W(C SUBGOAL_THEN (fun th -> REWRITE_TAC[th]) o funpow 2 lhand o snd)

but this is better and has a short name. Simply splits off antecedent of
antecedent as a separate subgoal. The tactic has a laborious tautology
definition; with a bit of reordering, we could use ITAUT or even TAUT.

Fri 24th Mar 00         list.ml

Added ALL_MEM = |- !P l. (!x. MEM x l ==> P x) = ALL P l

Tue 18th Jan 00         arith.ml

Added MOD_ADD_MOD =
 |- !a b n. ~(n = 0) ==> ((a MOD n + b MOD n) MOD n = (a + b) MOD n)

Tue 21st Dec 99         printer.ml

Changed the "dest_binder" used by printer stuff to "dest_binder_vorc" which
will break binders even when the binder thing is a variable. Otherwise the
printer actually crashes when used on a binder that isn't a constant, as I
discovered by trying to demonstrate how to define binders to Jim Grundy.

Thu 16th Dec 99         arith.ml

Added MOD_MULT2:

  |- !m n p. ~(m * p = 0) ==> ((m * n) MOD (m * p) = m * n MOD p)

this was wanted by Jim Grundy, and in any case is a logical addition since the
corresponding theorem for DIV (DIV_MULT2) was already there.

Tue 14th Dec 99         calc_rat.ml

Modified REAL_RAT_POW_CONV so that it works when the argument is a decimal.
Previously for example this would fail: REAL_RAT_POW_CONV `#0.7854 pow 2`

Thu  9th Dec 99         class.ml

Modified COND_CASES_TAC so that if the expression being split over is a
negation, the assumption in the second branch eliminates the double negation.
This was a suggestion from Jim Grundy.

Fri  3rd Dec 99         preterm.ml

Fixed a bug in overloading found by Jim Grundy. It was the case that if
there was enough type information to resolve an overload unambiguously,
then this already-gathered type information was used as the type for the
object, instead of taking the type of the overload instance from the interface
list.

However, this is no good when we have enough type information to resolve the
overload but still have indeterminate parts, e.g. a binary function where we
have the type of the first argument (and hence resolve the overload) but not
the second. Not only doesn't the subsequent typecheck ever resolve the
indeterminate parts, they actually look to it like incompatibilities, so it
fails. This has been modified to simply take the type from the interface list,
as is done anyway in the case of defaulting. Also, typechecking is now repeated
whenever "overresolve" changed the preterm, not just when it set the
"overloads_defaulted" flag.

Fri  3rd Dec 99         printer.ml

Put in a flag "reverse_interface_mapping" that controls whether overloaded
identifiers print as the overloaded name (flag = true, default) or their true
name (flag = false). This was a suggestion from Jim Grundy.

Fri  3rd Dec 99         preterm.ml

Backed off the change made a year ago that made "\const. tm" always interpret
"const" as a variable. Now this behaviour is under the control of a settable
flag called "ignore_constant_varstructs". However, the default is true, which
means no (intentional) change in behaviour. Setting it to false would restore
the state of affairs in version 1.0

Fri  3rd Dec 99         pair.ml

Added the GEN_BETA_CONV function that does generalized beta conversion over
nested linear patterns of constructors, e.g. GEN_BETA_CONV
`(\[SUC m; SUC n]. m + n) [SUC 1; SUC 2]`. This subsumes PAIRED_BETA_CONV, but
it is slower.

Fri  3rd Dec 99         recursion.ml

Added "create_projections" which demonstrates the existence of projection
functions for a type constructor. These are then stored away in a cache. The
main intention is to do genrealized betas over arbitrarily nested type
constructors automatically.

Fri  3rd Dec 99         drule.ml

Added BETAS_CONV where BETAS_CONV n `(\x1...xn. E[xs]) a1 ... an` reduces all
the beta redexes.

Thu  2nd Dec 99         printer.ml

Stuck an additional "print_break" before the "and"s in a printing of "let ...
and ... and ... and", otherwise the line would never break properly. This bug
was pointed out by Jim Grundy.

Thu  2nd Dec 99         ind-type.ml

Added ":num" to the inductive type store. I needed to swap the order of
arguments; I should really make this standard anyway.

Wed  1st Dec 99         arith.ml

Added MOD_MULT_ADD = |- !m n p. (m * n + p) MOD n = p MOD n

Mon 29th Nov 99         ind-types.ml

Changed the recursive type definition type bijections used internally from
"mk_<type>" and "dest_<type>" to "_mk_<type>" and "_dest_<type>". Jim Grundy
was caught out by the original, since he wanted a constructor with the same
name.

Sun 22nd Aug 99         real.ml

Added REAL_POW2_ABS = |- !x. abs(x) pow 2 = x pow 2
      REAL_LE_SQUARE_ABS = |- !x y. abs(x) <= abs(y) = x pow 2 <= y pow 2

Sun 22nd Aug 99         ind-defs.ml

Renamed MONO_ALL to MONO_FORALL; it's more logical and the second is already
used for list quantification.

Mon  3rd May 99         realax.ml, calc_rat.ml, calc_real.ml

Set up "--" as a prefix, so one can write "--R(j)" rather than "--(R(j))" etc.
This meant changing a few `--`s to `(--)`s otherwise the parser complains.

Fri 23rd Apr 99         meson.ml

Wow, found and removed a second "with Cut -> raise Cut". What fascinating
optimizations there are to be found!

Fri  9th Apr 99         meson.ml

While nosing around meson.ml looking for Wishnu's bug (see last item) I
spotted and removed a pointless "with Cut -> raise Cut". Might speed things up
by a few microseconds.

Fri  9th Apr 99         canon.ml

Fixed a bug in NNFC_CONV. The "clever" optimization that avoided rewriting a
term twice at one level is wrong in the case "~ ~ (p ==> q)". This caused a
MESON_TAC failure spotted by Wishnu Prasetya:

    `~(p /\ q ==> ~r) = (p /\ q /\ r)`;;

The new version simply uses TOP_SWEEP_CONV. I don't believe the impact will
be that significant. These things aren't that well optimized anyway; if speed
is critical I should rewrite it to do the maching manually.

Fri  2nd Apr 99         tactics.ml

Fixed a bug in THENL where "g THENL [non-empty-list]" would fail if
g left no subgoals. Now it behaves like THEN.

Thu 25th Mar 99         calc_num.ml

Installed a more efficient version of NUM_ADD_CONV and NUM_SUC_CONV. These are
hand-coded instantiations rather than being based on rewriting. The motivation
is that addition is now fairly important in proofs, though the long-term goal
is to improve multiplication, which is the real bottleneck. Anyway, this
improved the speed of my current proofs (division algorithms) by about 12%.

Wed 24th Mar 99         real.ml

Added: REAL_EQ_RDIV_EQ = |- !x y z. &0 < z ==> ((x = y / z) = x * z = y)
       REAL_EQ_LDIV_EQ = |- !x y z. &0 < z ==> ((x / z = y) = x = y * z)

Thu 18th Feb 99         sets.ml

Renamed the old FINITE_IMAGE to FINITE_IMAGE_EXPAND and added:

  FINITE_IMAGE = |- !f s. FINITE s ==> FINITE(IMAGE f s)

The previous version had the definition of IMAGE expanded...

Thu 18th Feb 99         sets.ml

Added IMAGE_CLAUSES =
 |- (IMAGE f EMPTY = EMPTY) /\ (IMAGE f (x INSERT s) = f x INSERT IMAGE f s)

Thu 18th Feb 99         arith.ml

Added: MOD_MULT_RMOD =
         |- !m n p. ~(n = 0) ==> ((m * p MOD n) MOD n = (m * p) MOD n)
       MOD_MULT_LMOD =
         |- !m n p. ~(n = 0) ==> ((m MOD n * p) MOD n = (m * p) MOD n)
       MOD_MULT_MOD2 =
         |- !m n p. ~(n = 0) ==> ((m MOD n * p MOD n) MOD n = (m * p) MOD n)
       MOD_EXP_MOD =
         |- !m n p. ~(n = 0) ==> ((m MOD n) EXP p MOD n = m EXP p MOD n)

Wed 27th Jan 99         real.ml

Added: REAL_LT_POW2 = |- !n. &0 < &2 pow n
       REAL_LE_POW2 = |- !n. &1 <= &2 pow n

Wed 27th Jan 99         pair.ml

Added EXISTS_PAIR_THM = |- (?p. P p) = (?p1 p2. P (p1,p2))

Fri 22nd Jan 99         real.ml

Moved the quantifier from ... ==> !n. to !n. ... ==> in SUM_POS_GEN, so that
we can later use MATCH_MP_TAC more conveniently.

Wed 20th Jan 99         drule.ml

Modified HIGHER_REWRITE_CONV so that it takes a flag allowing one to pick the
lowest subterm (as originally) or the highest. Now the latter is used for
COND_CASES_TAC, which seems much more sensible. However, note that lowest still
makes sense for many things, e.g. the elimination of subtractions. And the new
COND_CASES_TAC has the "defect" that if (if ...) will put the inner
conditional on the assumptions so REPEAT COND_CASES_TAC is no good.

Wed 20th Jan 99         pair.ml

Modified let_CONV so that it deals with paired lets correctly provided the
thing being abbreviated is also paired. Modified LET_TAC so that it works on
any paired let at all, introducing appropriate abbreviatory assumptions.

Wed 20th Jan 99         basics.ml, equal.ml

Added three new functions "find_path", "follow_path" and "PATH_CONV" to create
and use paths, i.e. director strings. These are useful for modifying terms at
a precise position without any accidents.

Thu  7th Jan 99         arith.ml

Made "mk_numeral" and "mk_small_numeral" fail when given negative arguments.

Thu 10th Dec 98         preterm.ml

Modified the behaviour of "typify" on the varstruct of a preterm so that if the
varstruct is a single variable, it is always treated as a variable even if
there is a constant with that name. This makes (simply) bound variables
override constants, conforming to the intuition that constants are like
outer-level bound variables. However, this does not apply to complex
varstructs; this seems hard in general since we need to recognize certain
constants like the comma in "\(x,y). ...". Probably need to think more about
this in concert with set abstraction syntax.

Tue  8th Dec 98         arith.ml

Added LE_SQUARE_REFL = |- !n. n <= n * n

Fri  4th Dec 98         real.ml

Added REAL_DIV_REFL = |- !x. ~(x = &0) ==> (x / x = &1)
      REAL_DIV_LMUL = |- !x y. ~(y = &0) ==> (y * (x / y) = x)
      REAL_DIV_RMUL = |- !x y. ~(y = &0) ==> ((x / y) * y = x)

Thu  3rd Dec 98         arith.ml

Added the new theorems:

LE_LDIV = |- !a b n. ~(a = 0) /\ b <= a * n ==> b DIV a <= n
LE_RDIV_EQ = |- !a b n. ~(a = 0) ==> (n <= b DIV a = a * n <= b)
LE_LDIV_EQ = |- !a b n. ~(a = 0) ==> (b DIV a <= n = b < a * (n + 1))

Wed  2nd Dec 98         class.ml

Modified the condition syntax of COND_CONG to the new "if g then t else e"
instead of the old "g => t | e".

Thu 12th Nov 98         arith.ml

Added MOD_EQ_0 = |- !m n. ~(n = 0) ==> ((m MOD n = 0) = (?q. m = q * n))
      EVEN_MOD = |- !n. EVEN(n) = (n MOD 2 = 0)
       ODD_MOD = |- !n. ODD(n) = (n MOD 2 = 1)

Wed 11th Nov 98         arith.ml

Added DIV_MONO = |- !m n p. ~(p = 0) /\ m <= n ==> m DIV p <= n DIV p
      DIV_EQ_0 = |- !m n. ~(n = 0) ==> ((m DIV n = 0) = m < n)

Fri 23rd Oct 98         gtt.ml, hol.ml

Set up an allocated scratch_directory that is used instead of /tmp when the
environment variable TMPDIR isn't set. This was because, at least on my laptop,
/tmp was getting cleared so often that it sometimes happened in the middle of
loading a multiple-day proof.

Tue 20th Oct 98         list.ml

Changed the names of FORALL and FORALL2 to ALL and ALL2. The new names are
shorter, more consistent with EX, and make it easier to name theorems relating
ordinary quantifiers to these. For example the theorem previously known as
FORALL_FORALL gives no clue in its name about which way it switches the
quantifiers. The names of theorems have been changed as follows:

    FORALL -> ALL
    FORALL2 -> ALL2
    FORALL_IMP -> ALL_IMP
    NOT_FORALL -> NOT_ALL
    FORALL_MAP -> ALL_MAP
    FORALL_T -> ALL_T
    FORALL_MP -> ALL_MP
    FORALL_FORALL -> FORALL_ALL
    AND_FORALL -> AND_ALL
    MONO_FORALL -> MONO_ALL
    FORALL2_DEF -> ALL2_DEF
    MAP_EQ_FORALL2 -> MAP_EQ_ALL2
    FORALL2_MAP -> ALL2_MAP
    FORALL2_AND_RIGHT -> ALL2_AND_RIGHT
    MONO_FORALL2 -> MONO_ALL2

Tue 20th Oct 98         printer.ml

Made sure that a space is printed between a prefix operator and its arguments,
and between a binder and its bound variables, when (and only when) the
operator's name is alphanumeric.

Mon 19th Oct 98         class.ml, ind-defs.ml, itab.ml real.ml tactics.ml

Removed "PROVE" since there's now no compactor, and replaced it by "prove".

Mon 19th Oct 98         calc_num.ml

Added EXPAND_CASES_CONV, which I seem to use quite often to expand "!n. n < N
==> P n" into "P 0 /\ P 1 /\ ... /\ P (N-1)".

Mon 19th Oct 98         calc_rat.ml

Added more functions for dealing with rational number terms:
numdom, numerator, denominator, term_of_rat, rat_of_term.

Fri 16th Oct 98         basics.ml, bool.ml, tactics.ml

Eliminated the compactor and loading and saving of theorems. This was a
hack and in fact turned out to inhibit performance on really big examples.
Admittedly, this is probably just because I used the built-in CAML hash tables
which clearly aren't designed for hashing objects of this size and structure.

Fri 16th Oct 98         tactics.ml

Optimized the implementations of THEN and THENL which were recreating
nontrivial bits of the justification function; these are now going to be
function closures. This saves piles of memory on really big case splits.
Also made similar optimizations to a few other "terminal" tactics such as
ACCEPT_TAC.

Thu 15th Oct 98         real.ml, int.ml

Renamed REAL_NEG_EQ_0 and INT_NEG_EQ_0 from REAL_NEG_EQ0 and INT_NEG_EQ0
for consistency with other REAL_opr_EQ_0. Really a more serious bash at making
these names consistent would be worthwhile before they become entrenched.

Thu 15th Oct 98         simp.ml

Modified "net_of_thm" so it also translates |- p ==> (s = t[s]) into
|- p ==> ((s = t[s]) = T). Previously this was only happening for
non-conditional rewrites. Also eliminated the "discarding looping rewrite"
warning which would need changing to "modifying looping rewrite" and is
probably more irritating than useful.

Fri  9th Oct 98         parser.ml

Removed the special "bracket" status for semicolon; there seem to be few
natural situations where a semicolon is followed by a symbolic ID. Anyway, I
wanted to use ";;" for a sequencing operator. Maybe I should do the same for
comma?

Wed  7th Oct 98         tactics.ml

Made goals print the other way up, i.e. with the conclusion at the bottom
with the head (most recently added) assumptions above them. This is a trivial
change, but seems much more sensible to avoid goals with zillions of
assumptions scrolling off the screen.

Tue  6th Oct 98         tactics.ml

Reimplemented THEN and THENL in a more direct way, not relying on hacking
up a goalstate and manipulating it using "by" and "bys". This is partly
because I suspect the space behaviour of the old one is very bad when there
are splits into many subgoals. Anyway the aesthetics are better. The
left-right order for metavariable instantiation has been maintained.

Tue  6th Oct 98         drule.ml

Optimized INSTANTIATE_ALL for the case where the instantiation is null.

Tue  6th Oct 98         tactics.ml

Made similar optimization to the one below for THENL, this time for THEN, and
hence EVERY. I had misthought that THEN called THENL, but of course it doesn't.

Tue  6th Oct 98         real.ml

Changed "prove" to "PROVE" so that REAL_ARITH doesn't cache what probably are,
after all, only temporary theorems.

Mon  5th Oct 98         real.ml

Added call to "clear_atom_cache" in SIMPLE_REAL_ARITH_TAC; previously the
cache would just extend forever across multiple calls, surely not a very good
idea...

Mon  5th Oct 98         tactics.ml

Optimized the implementation of "THENL" for the case where the composite
construct finishes off the goal. Now, rather than keeping the perhaps
complicated justification function hanging around, we apply it at once, then
return a trivial wrapper round the resulting theorem.

Tue 15th Sep 98         real.ml

Added  REAL_DIV_POW2_ALT =
  |- !x m n.
        ~(x = &0)
        ==> (x pow m / x pow n =
             (if n < m then x pow (m - n) else inv (x pow (n - m))))

Mon 14th Sep 98         arith.ml

Added MOD_EXISTS =
 |- !m n. (?q. m = n * q) = (if n = 0 then m = 0 else m MOD n = 0)

Mon 14th Sep 98         pair.ml

Made LET_TAC scrub trivial lets first. This is a bit ad-hoc, but helps it
goals with parallel chains of lets but different bodies.

Fri  4th Sep 98         arith.ml

Added LT_MULT2 = |- !m n p q. m < n /\ p < q ==> m * p < n * q
which had somehow got forgotten.

Thu  3rd Sep 98         basics.ml, pair.ml

Modified dest_let so that it allows arbitrary varstructs on the left of
the equals sign. This was just a matter of changing "strip_abs" to
"strip_gabs". Also modified let_CONV so that it works on paired varstructs
provided the right hand side is a pair, as in "let (x,y,z) = (1,2,3) in ...".
The parser already worked in the general case, and the change to "dest_let"
makes the printer work. However let_CONV needs more work, changing ABS
to an equivalent for varstructs. Pretty easy...

Wed  2nd Sep 98         arith.ml

Added EXP_1 = |- !n. n EXP 1 = n, and renamed the theorem previously
called EXP_1 to EXP_ONE = |- !n. 1 EXP n = 1

Wed  2nd Sep 98         pair.ml

Added LET_TAC to eliminate let_terms while replacing them with equivalently
named abbreviatory assumptions.

Sun 16th Aug 98         real.ml

Added REAL_DIV_POW2 =
 |- !x m n.
        ~(x = &0)
        ==> (x pow m / x pow n =
             (if n <= m then x pow (m - n) else inv (x pow (n - m))))

Fri 14th Aug 98         calc_rat.ml

Improved REAL_RAT_MUL_CONV which did cancellation in an utterly inept
way, requiring big multiplications in many cases.

Fri 14th Aug 98         real.ml

Term-netted REAL_INT_RED_CONV and so REAL_INT_REDUCE_CONV.

Fri 14th Aug 98         real.ml

Added REAL_LT_DIV = |- !x y. &0 < x /\ &0 < y ==> &0 < x / y
      REAL_LE_DIV = |- !x y. &0 <= x /\ &0 <= y ==> &0 <= x / y

Tue  4th Aug 98         calc_rat.ml

The conversion CALC_DIV_CONV was failing if the input was of the form
"m / n" for integers m and n even if m and n were cancellable. Now it
cancels if possible.

Wed 29th Jul 98         arith.ml

Added MOD_MOD_REFL = |- !m n. ~(n = 0) ==> (m MOD n MOD n = m MOD n)

Mon 27th Jul 98         tactics.ml

Added RECALL_ACCEPT_TAC, intended for use by extremely time-consuming
rules that take some argument(s) other than the goal term. One can use
it to delay evaluation till after lookup in the theorem compactor.

Fri 24th Jul 98         calc_rat.ml

Term-netted REAL_RAT_RED_CONV and so REAL_RAT_REDUCE_CONV.

Thu 23rd Jul 98         pair.ml

Added FORALL_PAIR_THM = |- (!p. P p) = (!p1 p2. P (p1,p2))
I should probably get rid of GEN_PAIR_TAC one day.

Wed 22nd Jul 98         real.ml

Added REAL_LE_RDIV_EQ = |- !x y z. &0 < z ==> (x <= y / z = x * z <= y)
      REAL_LE_LDIV_EQ = |- !x y z. &0 < z ==> (x / z <= y = x <= y * z)
      REAL_LT_RDIV_EQ = |- !x y z. &0 < z ==> (x < y / z = x * z < y)
      REAL_LT_LDIV_EQ = |- !x y z. &0 < z ==> (x / z < y = x < y * z)
      REAL_LT_DIV2_EQ = |- !x y z. &0 < z ==> (x / z < y / z = x < y)
      REAL_LE_DIV2_EQ = |- !x y z. &0 < z ==> (x / z <= y / z = x <= y)
      REAL_EQ_LCANCEL_IMP = |- !x y z. ~(z = &0) /\ (z * x = z * y) ==> (x = y)
      REAL_EQ_RCANCEL_IMP = |- !x y z. ~(z = &0) /\ (x * z = y * z) ==> (x = y)

Wed 15th Jul 98         real.ml

Added SUM_CONST = |- !c n. Sum (0,n) (\m. c) = &n * c

Mon 13th Jul 98         real.ml

Added REAL_INV_1_LE = |- x. &0 < x /\ x <= &1 ==> &1 <= inv x

Fri 10th Jul 98         calc_num.ml

Added NUM_FACT_CONV into the set of conversions applied by NUM_RED_CONV
and hence NUM_REDUCE_CONV.

Fri 10th Jul 98         real.ml

Added REAL_POW_POW = |- !x m n. x pow m pow n = x pow (m * n)

Thu  9th Jul 98         arith.ml

Added MOD_MOD = |- !m n p. ~(n * p = 0) ==> (m MOD (n * p) MOD n = m MOD n)
and DIV_MULT2 = |- !m n p. ~(m * p = 0) ==> ((m * n) DIV (m * p) = n DIV p)
and     MOD_1 = |- !n. n MOD 1 = 0

Mon  5th Jul 98         real.ml

Added REAL_POW_MONO_LT = |- !m n x. &1 < x /\ m < n ==> x pow m < x pow n

Mon  5th Jul 98         tactics.ml

Made the variant-choosing in CHOOSE_TAC more conservative, to avoid
problems where the variable coincides with something in the hypotheses
of an assumption theorem, yet not in any of the conclusions.

Mon  5th Jul 98         real.ml

Added another couple:

  REAL_LT_RMUL_EQ = |- &0 < z ==> (x * z < y * z = x < y)

  REAL_LT_LMUL_EQ = |- &0 < z ==> (z * x < z * y = x < y)

Thu  2nd Jul 98         real.ml

Added two theorems that are specially useful in conjunction with the
simplifier:

  REAL_LE_RMUL_EQ = |- &0 < z ==> (x * z <= y * z = x <= y)

  REAL_LE_LMUL_EQ = |- &0 < z ==> (z * x <= z * y = x <= y)

Thu 25th Jun 98         realax.ml

Avoided the auxiliary definition of "sum". This was inelegant, and particularly
inconvenient since "sum" is quite a useful constant name for the user.

Wed 24th Jun 98         tactics.ml

Added EXPAND_TAC, the natural complement to ABBREV_TAC.

Tue 23rd Jun 98         parser.ml

Added comments to the quotation parser. These are one-line comments
started by a settable symbol, initially // as in BCPL/C++.

Tue 26th May 98         calc_rat.ml, parser.ml, printer.ml

Made `#xxxx.yyyy` acceptable instead of explicit fraction, using a new constant
DECIMAL. Modified parser and printer appropriately and tweaked rational
arithmetic stuff so it accepts these (but always returns a conventional
rational).

Wed 20th May 98         preterm.ml

Made hexadecimal numerals acceptable to the parser. They are entered in C
notation, i.e. 0x... with either upper or lower case or mixed case for the
hex digits (but the initial x must be lowercase). Note that this has no
logical meaning, so the numerals are still printed as decimals. However it
would be possible to have a more general numeral syntax, e.g. several
alternatives to "NUMERAL". This would mean changing some calculation code.

********************** RELEASE OF VERSION 1.00 **********************

Thu 30th Apr 98         preterm.ml, parser.ml, printer.ml, passim

Abolished interface maps, integrating them with overloading. Renamed the
functions involved, except make_overloadable. Now we have override_interface,
overload_interface, reduce_interface and remove_interface.

Wed 29th Apr 98         tactics.ml

Deleted test_just. I think the stuff is all OK, so I shouldn't need it; and it
cheats!

Wed 29th Apr 98         arith.ml

Fixed a bug in PRE_ELIM_TAC, used in preprocessing phase of the decision
procedure for naturals. It was substituting x = SUC m where we had PRE(x),
but of course x might not be a variable and then the x = SUC m was lost. The
analogous SUB_ELIM_CONV already did this right.

Wed 29th Apr 98         simp.ml, theorems.ml, class.ml

Tweaked simplification slightly, adding new rewrites for "(x = x) ==> p" and
"if x = x then y else z" so that we never perform a contextual rewrite in such
a trivial case.

Wed 29th Apr 98         meson.ml

Limited the case-splitting before MESON proper is applied; this was getting to
rather extreme levels for propositional tautologies. The limit is controlled by
an assignable variable meson_split_limit; this is initially 4, meaning no more
than 2^4 = 16 separate cases.

Wed 29th Apr 98         real.ml

Optimized the linear decision procedure in several ways. (1) the most
important: the case-splitting induced by "abs" is now somewhat more intelligent
that blindly doing COND_CASES as before. Something like abs(x) <= y is expanded
to x <= y /\ --x <= y, which is much better: no case-splitting. In the case
split from x <= abs(y) we have a case split but leave out &0 <= x and &0 <= -x
indications; they are not needed and if "x" involves abs, can lead to further
expansion. It's still not perfect; for example &2 * abs(x) <= y is still
treated in the old way. But it's much better. (2) We avoid ASSUMEing and
PROVE_HYPing the starting theorems. (3) simplified the proof traces slightly,
which for no good reason kept the shadow forms of the intermediate
inequalities.

Mon 27th Apr 98         thm.ml, drule.ml, class.ml, bool.ml

Abandoned the "clever" definitional principle and made the equational form
primitive.

Mon 27th Apr 98         type.ml, term.ml, drule.ml, tactics.ml

Renamed type_subst to raw_type_subst and made type_subst a version that
doesn't create an unchanged exception; better for external use.

Tue 21st Apr 98         int.ml

Added some theorems whose real counterparts were in realax.ml not real.ml and
hence got left out, e.g. INT_ADD_SYM and INT_ADD_ASSOC (!)

Tue 21st Apr 98         pair.ml

Added let_CONV.

Tue 31st Mar 98         type.ml, term.ml

Made a few efficiency tweaks and tidyings.

Tue 31st Mar 98         type.ml

Removed "tyvarsl" which was never used.

Wed 25th Mar 98         list.ml

Added definition of constant EL.

Tue 24th Mar 98         printer.ml

Forced the printer to print brackets round paired abstractions.

Mon 23rd Mar 98         printer.ml

Stopped printing of CONS as (CONS). I've no idea why I did this.

Mon  2nd Mar 98         simp.ml, class.ml

Set up useful simplifier as the default SIMP_TAC, ASM_SIMP_TAC etc., for the
situations where one needs implicational rewriting but doesn't want to fuss
with constructing simpsets. Fitted mechanism for basic congruences and
augmented it with conditional in class.ml

Wed 18th Feb 98         printer.ml

Made a modification to compile under 0.74: print_break is now curried.

Wed 11th Feb 98         ind-types.ml

Changed "BOT" to "BOTTOM", less likely to be wanted elsewhere when dealing with
Boolean algebras.

Tue 10th Feb 98         printer.ml

Modified the printer to use bracketing instead of dollaring.

Tue 10th Feb 98         quot.ml, real.ml

Modified "define_quotient_type" so the user can specify the names of the
abstraction and representation functions.

Mon  9th Feb 98         parser.ml, printer.ml, passim

Eliminated the use of dollaring to force non-special status. Now just use
brackets: (+), (==>), (!) etc. This seems much more intuitive and also makes
the lexical stuff simpler.

Sun  8th Feb 98         printer.ml

Added user-installable printers, via a trivial "try them first" interface.

Wed  4th Feb 98         list.ml

Added EX_IMP.

Wed 28th Jan 98         list.ml

Added NOT_FORALL, FORALL_FORALL and AND_FORALL.

Mon 19th Jan 98         list.ml

Added FORALL_MP.

Wed 14th Jan 98         list.ml

Added ITLIST_EXTRA.

Fri  2nd Jan 98         simp.ml

Inserted a warning when discarding a looping rewrite.

Wed 24th Dec 97         drule.ml

Made INSTANTIATE fail if anything gets instantiated in assumptions. The main
reason is that on occasion ASM_REWRITE_TAC[] could instantiate the assumptions
of goal-assumptions and lead to an invalid tactic, whereas it should fail.

Mon 22nd Dec 97         sets.ml

Added LENGTH_LIST_OF_SET and rejigged the definition to make sure "list_of_set"
is repetition-free.

Mon 22nd Dec 97         list.ml

Added MAP2.

Sat 20th Dec 97         sets.ml

Added num_FINITE, num_FINITE_AVOID and num_INFINITE.

Fri 19th Dec 97         list.ml

Added FORALL2_AND_RIGHT.

Thu 18th Dec 97         sets.ml

Added FINITE_IMAGE_INJ.

Thu 18th Dec 97         list.ml

Added MAP_EQ_DEGEN.

Thu 18th Dec 97         ind-types.ml

Made "prove_constructors_injective" and "prove_constructors_distinct" return a
single conjunctive theorem rather than a list of theorems. This strange
decision has been an irritation for ages, so I decided to change it now before
it requires any more tweaking of work.

Thu 18th Dec 97         list.ml

Added FORALL2, with theorems MAP_EQ_FORALL2 and FORALL2_MAP; added in
monotonicity theorems for FORALL and FORALL2 for ind-defs package. Also tweaked
a couple of proofs.

Wed 17th Dec 97         list.ml

Added FORALL_T.

Sat 13th Dec 97         sets.ml

Added UNIONS_INSERT, FINITE_UNIONS and FINITE_IMAGE.

Thu 11th Dec 97         sets.ml

Added IN_UNIONS, IN_INTERS, UNIONS_0, UNIONS_1, UNIONS_2.

Tue  2nd Dec 97         equal.ml

Added CACHE_CONV, which seems potentially quite useful. I should probably use
it in the reals decision procedure in future; it uses a term net rather than a
linear list, as now. However this version also uses a modicum of intelligence.

Tue  2nd Dec 97         tactics.ml

Changed THENL so it succeeds if the first tactic creates no subgoals, even if
the list of tactics is of nonzero length. This was suggested by Michael
Norrish (for hol90).

Sat 29th Nov 97         preterm.ml

Updated the earlier change so it also checks for numerals, not actually there
as single constants. At this stage they are not written out in binary.

Fri 28th Nov 97         preterm.ml

Fixed up set abstractions so they don't generalize over constants in the left;
the problem was that at the preterm stage these are still "variables", so
needed to put a check in "pfrees" whether something is a constant name. This is
safe: any inner bound variables aren't free anyway(!)

Fri 28th Nov 97         printer.ml

Fixed the printing of iterated polymorphic binary operators without brackets by
changing dest_binop to DEST_BINARY where needed, so any instances of operators
with the same name are accepted. This function DEST_BINARY is new: it works for
variable infixes as well as constants.

Wed 26th Nov 97         arith.ml

Added: DIV_0 = |- !n. ~(n = 0) ==> (0 DIV n = 0)
       MOD_0 = |- !n. ~(n = 0) ==> (0 MOD n = 0)
       EXP_1 = |- !n. 1 EXP n = 1
       DIV_LT = |- !m n. m < n ==> (m DIV n = 0)
       LT_EXP =
         |- !x m n.
                x EXP m < x EXP n = 2 <= x /\ m < n \/
                                    (x = 0) /\ ~(m = 0) /\ (n = 0)

Thu 20th Nov 97         basics.ml, tactics.ml

Finally, I've done something about a fast save/resume. I started by creating
a (term-netted) stock of theorems, optionally with names. The old COMPACT
function now not only compacts theorems, but also stores them in this
structure. This "theory file" is loadable and savable. Also, "prove" tries to
find a theorem in the net before running the tactic to prove it; the
disadvantage is that it still *creates* the tactic --- in cases where this is
expensive we're going to need something like a "fun g -> tac g" wrapper.

Sat 15th Nov 97         preterm.ml, sets.ml

Fixed a bug pointed out by Mark Woodcock: in general set abstractions {t | P},
the only variables getting existentially quantified were those in both t *and*
P, the idea being that if a variable doesn't appear in P, then it means
something outside and the user doesn't want to bind it. However this is quite
wrong, as pointed out by Mark's example { x | T }. So now I quantify any
variables appearing in t. This meant I had to change the definition of IMAGE f
s = {f x | x IN s} to an explicit existential. Really, it would only be
possible to do this better using parsing in a context of meaningful (in
particular bound) variables, and that creates all sorts of new problems.
Probably better to accept occasional inconvenience.

Tue 11th Nov 97         real.ml, int.ml

Removed a few duplicated theorems.

Tue 11th Nov 97         term.ml, drule.ml

Chaged "paconv" to delete the env argument at toplevel.

Tue 11th Nov 97         term.ml, thm.ml, bool.ml, equal.ml, basics.ml

Moved syntax constructors from term.ml out to more appropriate places, since
this is after all part of the core.

Mon 10th Nov 97         bool.ml

Put back an old optimization into PROVE_HYP, which is now completely different,
so that it does no inference in the trivial case.

Mon 10th Nov 97         thm.ml, equal.ml

Changed the beta conversion primitive so that it only does the trivial case.
This is now called BETA. The general case, BETA_CONV, is done by adding INST
where needed.

Mon 10th Nov 97         thm.ml, equal.ml, bool.ml

Returned to old name INST despite the fact that it instantiates in assumptions,
as does INST_TYPE. Profiling indicated this was safe, i.e. failure never
occurred at all, let alone in a situation where failure causes some other
action.

Sun  9th Nov 97         term.ml, thm.ml, equal.ml bool.ml

Changed the primitive basis to cut out implication as a primitive. Introduced
the new inference rule DEDUCT_ANTISYM_RULE, made instantiation apply to
assumptions, and moved MP, DISCH, IMP_ANTISYM_RULE and SYM from primitive to
derived. The derivation of SYM is something independent from the effort of
eliminating implication; I could have done it before. It doesn't appear that
often in profiles, whereas TRANS does.

Sun 12th Oct 97         sets.ml

Strengthened FINITE_UNION to an equation, and renamed the implicational version
FINITE_UNION_IMP.

Wed 17th Sep 97         meson.ml

Changed "Var" to "Fvar" to avoid a clash with the standard term constructors;
this was also pointed out by Mark Woodcock.

Wed 17th Sep 97         class.ml

Deleted duplicate proof of BOOL_CASES_AX (pointed out by Mark Woodcock).

Mon 8th Sep 97          wf.ml

Added an "exists unique" version of the wellfounded recursion theorem.

Mon 8th Sep 97          sets.ml

Remarkably, I had UNIONS and INTERS defined wrong way round, and only now
discovered it while trying to use them! Fixed it.

Fri  5th Sep 97         wf.ml

Simplified the proof that recursive existence implies wellfoundedness following
a suggestion of Torkel Franzen.

Wed  3rd Sep 97         gtt.ml, wf.ml, arith.ml

Added a proof that the existence part of wellfounded recursion implies
wellfoundedness. Needed to swap arith.ml and wf.ml in the load sequence and
transfer a few theorems in order to make this cleaner. Also moved
"recursion.ml" back in the load sequence so as to make
"prove_recursive_functions_exist" available during wellfoundedness proof.

Sat 21st Jun 97         list.ml

Added FORALL_MAP = |- !P f l. FORALL P (MAP f l) = FORALL (P o f) l

Fri 20th Jun 97         ind-types.ml

Fixed a bug in "derive_recursion_theorem", which was failing in the case where
a type had only a single constructor; the theorem was being treated as if it
were a conjunction even though it wasn't.

Sat  7th Jun 97         tactics.ml

Modified VALID so it takes into account ASSUME-ability of conclusions of
hypotheses (if you see what I mean). Since it should now be OK, inserted it
into "TAC_PROOF" and "e".

Sat  7th Jun 97         bool.ml

Optimized PROVE_HYP so it doesn't do any work in the trivial case. This seems
wise now it will get called even more often in tactic proof reconstructions.

Sat  7th Jun 97         tactics.ml

Modified RULE_ASSUM_TAC so that it works via a series of ASSUME_TACs; this
allows the traditional HOL practice of ASSUMEing assumptions after
modification. I believe now that all ways of getting a theorem onto the
assumption list support this style.

Fri  6th Jun 97         tactics.ml

Changed b() so it doesn't back up to an empty goalstack.

Tue  3rd Jun 97         tactics.ml

Added checks to X_GEN_TAC and X_CHOOSE_TAC to ensure that the variables chosen
aren't already free.

Fri 30th May 97         tactics.ml

Added "flush_goalstack".

Tue 27th May 97         real.ml

Added REAL_POW_LT2 =
  |- !n x y. ~(n = 0) /\ &0 <= x /\ x < y ==> x pow n < y pow n

Fri 23rd May 97         real.ml

Added REAL_POW_SUB = |- !x m n. ~(x = &0) /\ m <= n
                                ==> (x pow (n - m) = x pow n / x pow m)
  and REAL_POW_NZ = |- !x n. ~(x = &0) ==> ~(x pow n = &0)

Wed 21st May 97         type.ml, term.ml, preterm.ml, thm.ml

Made sure that the binary type constructors are not treated as if they take
pairs; after a message from the CAML list I'm not sure this is safe.

Tue 20th May 97         real.ml

Added REAL_OF_NUM_SUB = |- !m n. m <= n ==> (&n - &m = &(n - m))

Tue 20th May 97         meson.ml

Deleted the unused internal function "bump_hol_thm" (pointed out by
Michael Norrish again).

Mon 19th May 97         arith.ml

Added EVEN_EXP = |- !m n. EVEN(m EXP n) = EVEN m /\ ~(n = 0)
  and ODD_EXP = |- !m n. ODD(m EXP n) = ODD m \/ (n = 0)

Sun 18th May 97         real.ml,calc_rat.ml

Added SUM_HORNER =
  |- !f n x.
        Sum (0,SUC n) (\i. f i * x pow i) =
        f 0 + x * Sum (0,n) (\i. f (SUC i) * x pow i)

and a corresponding conversion REAL_HORNER_SUM_CONV.

Wed 14th May 97         meson.ml

Deleted duplicate definition of POLY_ASSUME_TAC; thanks to Michael Norrish
for pointing this out.

Tue 13th May 97         real.ml

Added REAL_POW_ONE  = |- !n. &1 pow n = &1
  and REAL_POW_MONO = |- !m n x. &1 <= x /\ m <= n ==> x pow m <= x pow n

Mon 12th May 97         gtt.ml

Moved "quot.ml" to earlier in the build sequence, in an attempt to move
closer to the (unrealizable) ideal of deductive system first, theories second.

Mon 12th May 97         calc_num.ml

Fixed a bug in the rewrites for EXP, which was leaving "1" instead of "BIT1 _0"
in the right hand side; this was then unsimplifiable by the other rewrites
in certain situations.

Sat 10th May 97         preterm.ml, passim

Modified "overload" so it checks that the thing being overloaded (a) conforms
to the type skeleton, and (b) isn't polymorphic. Also changed "overesolve" so
that it will accept overloading of variables, purely so that the overloaded
form (and parse status) can be used during an actual definition.

Sat 10th May 97         mizar.ml

Made the "given" construct use the types of variables in the thesis; even
improved "consider" slightly by linking the evars and the body before
typechecking. Did a few other bits of tidying up.

Fri  9th May 97         parser.ml

Deleted the stuff that parses types after binary operators. By construction it
could never get called; types are attached to the unary subterms.

Fri  9th May 97         preterm.ml, passim

Added a fairly major new feature: operator overloading. The main new functions
are "make_overloadable", "overload", "unoverload", "prioritize_overload" and
"retypecheck", though these include various auxiliary functions. It seems to
work quite well.

Thu  8th May 97         tactics.ml

Added "top_realgoal", which is useful for investigating goalstacks.

Thu  8th May 97         gtt.ml

Changed "loadt" to be less dependent on the Unix library. Now it only depends
on Unix for the PID, and this could be avoided.

Thu  8th May 97         mizar.ml

Simplified Mizar to avoid using metavariables; hence diffuse statements are now
banned. This makes lots of things much simpler.

Mon  5th May 97         pair.ml, basics.ml

Changed the bodies of generalized abstractions to use a new constant "GEQ"
rather than equality. The problem is that with standard equality, "\(tup). T"
gets its equality predicate obliterated by the default rewrite "(x = T) = x".
Changed syntax functions and PAIRED_BETA_CONV correspondingly.

Sun  4th May 97         arith.ml

Added the definition of "measure" (natural number measures) and proved
wellfoundedness.

Wed 30th Apr 97         passim

Changed a lot of "b => x | y"s into "if b then x else y"s.

Sun 27th Apr 97         parser.ml, printer.ml

Made the syntax "if b then l else r" acceptable as well as "b => l | r". Made
the printer print conditionals as "if-then-else". In the long run, I might try
and scrub the conditional expression; I think "if-then-else" is normally
clearer.

Mon 21st Apr 97         ind-defs.ml, basics.ml

Moved the function "make_args" back from ind-defs into a more general place,
since it's used in other places. Also tweaked it to avoid using numbers when
only a single argument is required.

Mon 21st Apr 97         ind-types.ml

Added "prove_cases_thm" to prove the exhaustive case analysis theorems. Also
changed the variable name stylization in the induction theorems to use "x"
rather than "a" since the latter is already in use for the arguments.

Mon 21st Apr 97         term.ml, basics.ml, bool.ml, tactics.ml

Backed off the change to "variant" and instead installed an alternative
"mk_primed_var" and used that in a few tactics instead of "variant".

Fri 18th Apr 97         trivia.ml

Deleted the constants S and K and redefined I directly. They were not
useful and frequently clashed with variable names, even more troublesome
given the change to variant.

Fri 18th Apr 97         term.ml

Changed "variant" so that it also avoids constant names. This seems useful
in many situations, e.g. in problems with CHOOSE_TAC in the presence of
constants with the same name as the existential variable (this was pointed
out by B. Karthikeyan).

Fri 18th Apr 97         class.ml

Fixed a subtle bug in the tautology checker found by Claire and Tom at Glasgow.
The collection of useful case splits was being accumulated at the start.
However in certain composite expressions other than boolean variables, new
subterms can be created by the case splits chosen by the unsubtle "deepest
first" algorithm, e.g. from a term "P(x:bool)" two new terms "P T" and "P F".
Fixed this by moving the "ok" accumulation into the REPEAT loop.

Sun 23rd Mar 97         calc_num.ml

Term-netted the general numeral arithmetic conversion to make its
discrimination a bit faster. Added Karatsuba multiplication, which is a lot
faster for really big numbers. It's pretty crude and could be optimized a
great deal.

Sat  8th Mar 97         basics.ml

Slightly modified the term compactor: since "mk_mconst" recreates its types
anyway, there's no point in rehashing the type. Fortunately there aren't
usually all that many different polymorphic instances of constants! Also made
the hash tables visible, for convenient tweaking.

Sat  8th Mar 97         sets.ml

Added stuff about recursive definitions over finite sets. The proofs are a
slight variant of those from Ching-Tsun Chou for his HOL88 "aci" contribution.
It's actually quite tricky; we copy his trick of defining a relational form
including the cardinal, as in Tom Melham's original definition of CARD.

Fri  7th Mar 97         sets.ml

Added some trivia about finiteness being preserved by subset, union and
intersection. Also added definitions of cardinal relations, but not much more.

Wed  5th Mar 97         meson.ml

Put an EQ-test optimization in unification and equality-under-instantiation
tests.

Wed  5th Mar 97         real.ml, calc_rat.ml

Added a "proper" definition of summation, and a load of theorems from the old
reals library. Threw away "Sum0".

Wed  5th Mar 97         parser.ml

Added another syntax class of "typed_appl_preterm", to allow types on
subcomponents of binary operators, e.g. `x:A,y`. This has the side-effect that
`x,y:A` means `x,(y:A)` not `(x,y):A`. We could change this by slightly
generalizing "precedence" to take two different parsers, but the new behaviour
seems at least as intuitive.

Mon  3rd Mar 97         mizar.ml

Corrected Mizar mode so that "endcase" does not perform an "end". This
is achieved by doing a SUBGOAL_THEN followed by a "conclusion" in the
global goal. There are still other things to fix here; in particular there
are problems with the treatment of metavariables in several ways; best
to avoid "now" for the present!

Sun  2nd Mar 97         mizar.ml

Changed treatment of case splits so "per cases" creates two subgoals,
the first trivial, and "suppose" now *always* tries to finish the current
subgoal before splitting. This seems neater than repeating each time a
test for whether there were any conclusions; this was hard when using
metavariables. Also fixed a bug in transitivity chaining.

Sat  1st Mar 97         meson.ml

Made the polymorphic duplication more generous: it was missing trivial
instantiations if it could find any others.

Sat  1st Mar 97         parser.ml

Changed the parsing of set enumerations to parse a list of comma separated
"typed_apreterms", rather than parsing a preterm then splitting pairs. The snag
with that was that it was impossible to enumerate a set of pairs, since even
bracketing was ignored.

Sat  1st  Mar 97        list.ml

Added ITLIST and EX(ISTS).

Sat  1st Mar 97         int.ml

Corrected ARITH_TAC so that it deals correctly with non-variable terms;
previously, it only worked if the ultimate constituents of the terms were
atoms.

Fri 28th Feb 97         mizar.ml, arith.ml, real.ml, int.ml

Changed the treatment of transitivity chains to be more powerful and useful.
Now they store some transitivity theorems, and these are used to connect
together binary relations where the left of the second is "...".

Fri 28th Feb 97         mizar.ml

Generalized labelled formulas so one can label the conjuncts, separating them
by "and". Also cleaned up the parser and treatment of let-bound variables,
which were working out wrong when dollared.

Thu 27th Feb 97         mizar.ml

Fixed up Mizar mode with a parser based on the new combinators.

Tue 25th Feb 97         ind-types.ml

Added tools to prove injectivity and distinctness of inductive type
constructors.

Tue 25th Feb 97         list.ml

Added FORALL

Mon 24th Feb 97         recursion.ml

Fixed a bug in proving recursive functions exist, so it still works even if the
user only wants to justify some, not all, of the recursive functions. This is
useful as a subroutine for the expansion of nested types, even if the user is
unlikely to want trivially mutual definitions.

Mon 24th Feb 97         lib.ml

Added "set_eq", a set comparison of lists.

Sun 23rd Feb 97         pair.ml

Manually redid an automatic proof --- it was already highly inefficient using
meson, and now with duplication of polymorphic theorems it's even worse.

Sun 23rd Feb 97         tab.ml, meson.ml

Deleted tableaux prover, which seems merely a diversion now meson can cope
with polymorphism. Also in the interest of simplifying interfaces, threw away
equality-free versions of meson and deleted the "EQ" from names.

Sun 23rd Feb 97         meson.ml

Fixed up meson so that polymorphic lemmas to x_MESON_TAC are automatically
duplicated for relevant-looking instances in the existing assumptions. This
seems crude and is probably incomplete, but it seems to make meson cope with
most or all cases of polymorphic instantiation that occur in practice.

Sun 23rd Feb 97         meson.ml

Slightly improved the standard equality handling by adding just (x = y) /\
(x = z) ==> (y = z) instead of separate symmetry and transitivity laws.

Sun 23rd Feb 97         bool.ml

Fixed "is_beq", which was always returning false by comparing wrong type with
`:bool`.

Sun 23rd Feb 97         recursion.ml

Corrected the argument reshuffling so that it works even if the recursive
instances of the function are applied to fewer arguments than in the
varstructs on the left.

Sat 22nd Feb 97         meson.ml

Installed Brand's transformation (SIAM J. Computing, vol. 4, pp. 412-430,
1975). Pending detailed comparative tests, left the old equality stuff in as an
alternative. Early indications are that most cases get quicker (proofs a bit
longer but found more quickly) but a few hard ones get quite a bit longer.

Sat 22nd Feb 97         ind-types.ml

At last, cleaned up the mutually recursive types so the postulated recursive
functions have different codomain types. Reshuffled definition of sum type
as we need this first.

Wed 19th Feb 97         recursion.ml

Reimplemented "new_recursive_definition" to work properly, even in the mutual
case.

Tue 18th Feb 97         parser.ml, passim

Rewrote the parser in terms of nicer infix combinators. Also made the
installation of user parsers more flexible (try-fail interface rather than
keying on brackets). Also, treated "=" explicitly with lower precedence than
conditionals.

Mon  4th Nov 96         lib.ml

Added multiset union and subtraction (could no doubt be done much more
efficiently).

Sun  3rd Nov 96         printer.ml

Put in a rather ad hoc printer for program stuff. One day all this will be
completely reweitten and replaced by something nice.

Sun  3rd Nov 96         wf.ml

Added a theorem saying that applying a measure function into a WF ordering
gives a WF ordering.

Sun  3rd Nov 96         tactics.ml

Changed META_EXISTS_TAC to X_META_EXISTS_TAC, and provided a META_EXISTS_TAC
that invents a variant of the original name.

Sat  2nd Nov 96         sets.ml

Beefed up "IN_ELIM_THM" with a predicate version of the GSPEC clause.

Sat  2nd Nov 96         preterm.ml

Corrected "undollar" so it also works inside varstructs.

Fri  1st Nov 96         printer.ml

Threw in printing of generalized abstractions. Really, all this stuff
could be done much more neatly.

Thu 31st Oct 96         ind-defs.ml

Added a few extra entry points and a flag to "generalize_schematic_variables"
so that the user can avoid gratuitously generalizing monotonicity hypotheses
that weren't proved. This came up in defining the WP semantics of while loops;
one wants to modify the monotonicity assumption to the monotonicity of the
body.

Wed 30th Oct 96         mizar.ml

Put in a couple of pre-provers to get the common cases quickly. First try
to match a conjunct of the assumptions, then try rewriting. This works out
a lot quicker on average.

Wed 30th Oct 96         tab.ml

Added two new equality handling features to tableaux. Though incomplete, they
should be pretty useful. First it uses initial equational theorems as rewrite
rules. Second, it uses any clauses "v = t" or "t = v" to rewrite with "v = t"
everywhere and dispose of the assumption. Finally, added a type variable
renaming feature to better allow unification with type instantiation.

Wed 30th Oct 96         simp.ml

Added "LIMITED_REWRITE_CONV", which is useful in a few situations.

Fri 25th Oct 96         bool.ml

Made a few small tweaks, mainly replacing "type_of v" by "snd(dest_var v)"
where "v" is a type.

Thu 24th Oct 96         preterm.ml

Corrected the function "typify": the environment was being used to attach types
to binding instances of variables.

Tue 22nd Oct 96         meson.ml, pair.ml

Fixed yet another bug in the equality adder: it was creating congruence rules
assuming that constants are fully applied. However after first order reduction
this is not so for the I (application) combinator. Now fixed. At last, meson
proves the goal in "pair.ml" that it should --- although it takes a while of
course.

Tue 22nd Oct 96         canon.ml, meson.ml

Rewrote the FOL reduction so that it can be applied in an integrated manner
to all the assumptions of a goal, rather than merely a term at a time. This
fixed a few cases where meson would fail. Also made the precanonicalizer for
meson simpler by using genvars for specializations.

Tue 22nd Oct 96         drule.ml

Fixed a bug in matching where even pure variables were treated as a higher
order match, requiring all type instantiations to have been resolved.

Mon 21st Oct 96         mizar.ml

Finished a completely rewritten version of Mizar mode, with metavariables for
diffuse statements, nested proofs, alternative prover via "by ... with ..." and
various other enhancements and bugfixes. Got out the following nice proof of
Tarski's fixpoint theorem:

  let f be A->A;
  assume L:antecedent;
  antisymmetry: (!x y. x <= y /\ y <= x ==> (x = y)) by L;
  transitivity: (!x y z. x <= y /\ y <= z ==> x <= z) by L;
  monotonicity: (!x y. x <= y ==> f x <= f y) by L;
  least_upper_bound:
            (!X. ?s:A. (!x. x IN X ==> s <= x) /\
                       (!s'. (!x. x IN X ==> s' <= x) ==> s' <= s)) by L;
  set Y_def: Y = {b | f b <= b};
  Y_thm: !b. b IN Y = f b <= b by rewriting with Y_def,IN_ELIM_THM,BETA_THM;
  consider a such that
      lub: (!x. x IN Y ==> a <= x) /\
           (!a'. (!x. x IN Y ==> a' <= x) ==> a' <= a) by least_upper_bound;
  take a;
  !b. b IN Y ==> f a <= b
    proof
      let b be A;
      assume b_in_Y: b IN Y;
      then L0: f b <= b by Y_thm;
      a <= b by b_in_Y, lub;
      so f a <= f b by monotonicity;
      hence f a <= b by L0, transitivity;
    end;
  so Part1: f(a) <= a by lub;
  so f(f(a)) <= f(a) by monotonicity;
  so f(a) IN Y by Y_thm;
  so a <= f(a) by lub;
  hence thesis by Part1, antisymmetry;
  end

Sun 20th Oct 96         basics.ml and others

Added "compact" and "COMPACT" to enforce maximal sharing on terms and types
(well, not quite, because of the way mk_const works, but not bad). Made
separate "prove" and "PROVE" which respectively do and don't apply the
compactor. So far the results are positive but the improvement is surprisingly
modest; maybe CAML does this sort of thing itself anyway.

Sat 19th Oct 96         canon.ml

Fixed the lambda-remover to be less zealous, otherwise there will be problems
with special binder terms. Now it will just remove lambdas in beta redexes and
on either side of equations. This probably covers most cases in practice.

Tue 15th Oct 96         nets.ml

Fixed a bug in the term nets code. This would very seldom strike; the problem
was that "label_to_store" was not remembering the environment of bound
variables. This means if one of them happened to be the same as a local
constant, it would disable a match with an alpha-equivalent but unequal term.
This showed up in matching ASSUME `sup (\x. ?n. x = f n) - e < f n` with
`sup (\x. ?m. x = f m) - e < f n`. The fix is crude but adequate: replace the
variable by a genvar in such cases so it couldn't possibly be the same as a
local constant.

Tue 15th Oct 96         arith.ml

Put in the (easy) proof of DIV_MUL_LE, which has been mk_thm'd for a long time,
for some reason.

Tue 15th Oct 96         meson.ml

Fixed the use of "FOL_CONV" at the right point in the MESON canonicalizer, i.e.
after NNF conversion and CHOOSE-ing of existential variables. The practical
effect of this is that we can prove Andrews's "unique fixed point" theorem in
its most natural form.

Mon 14th Oct 96         basics.ml, drule.ml, and passim

Completely rewrote matching and higher order instantiation. Instead of the
crude old 2-phase approach where the beta conversions were applied in a rather
indiscriminate way, the new version has the instantiation list contain a list
of pattern variables to beta-reduce. A few proofs broke under this because
accidental beta conversions was relied on. The simplest solution was simply to
install BETA_THM as a basic rewrite (long-term, will use BETA_CONV in the net
directly, but this is OK pro tem). Don has done this anyway, i.e. replaced
ABS_SIMP with BETA_THM. Rather surprisingly this change broke no proofs at all,
so it's definitely a good idea. Lots of BETA_THM's deleted from rewrites all
over the system.

Sun 13th Oct 96         basics.ml, bool.ml

Made "type_match" keep its accumulator in the visible version. This at least
makes ISPECL tidier, and seems a good idea in principle.

Sun 13th Oct 96         equal.ml

Tweaked SUBS_CONV so that if no substitutions occur, any new hypotheses in the
equational theorems get included in the result. That this was happening was an
unfortunate consequence of the implementation style. It affected later tactic
proofs by propagating bogus assumptions in SUBST_ALL_TAC.

Sun 13th Oct 96         meson.ml

Fixed a serious and longstanding bug in the MESON equality axiom producer. It
was only producing equivalence axioms for equalities of a type that actually
occur in the target. However in general this is not enough, e.g.
"P x y /\ ~P x z ==> (y = z)" requires equality axioms for the type of "x" too!

Sun 13th Oct 96         tactics.ml

Put a check for boolean goal into mk_goalstate, from where it propagates out to
other relevant functions like "prove".

Sun 13th Oct 96         basics.ml

Did a lot of cleaning up of the basic term matching function, including
avoiding inefficient recalculation of the type instantiations from the term
instantiations over a set of higher order pattern subterms. Also a bit of dead
code removal and other minor efficiency tweaks like using "snd o dest_var"
instead of "type_of" for known variables. Also an enhancement: the outer types
of patterns are matched first, which in principle could lead to more matches.
Another enhancement: the local constants, besides stopping instantiations of
variables, are used to fix those too for the matching of patterns. This will be
specially useful for Mizar, but seems a good idea anyway.

Sat 12th Oct 96         basics.ml, bool.ml, drule.ml

Tidied and optimized the simple stuff in "basics.ml". Moved the binder syntax
back here from "bool.ml" (hence reduced the duplication in the deneralized
abstraction syntax operations, which use universal quantifiers). Also moved the
dreaded "mk_thm" to the start of "drule.ml". Deleted the function "beta"
completely; it was only used once in "ind-types.ml".

Sat 12th Oct 96         equal.ml

Made a few minor tweaks, including delting BODY_CONV which was no longer used
(the old canonicalizer used it). Mostly replacing "rhs" with "rand" and
reorganizing type annotations more tidily.

Sat 12th Oct 96         term.ml

Made various minor but probably worthwhile optimizations, including the
avoidance of rebuiling some paired varstructs, and slightly tidier control flow
in "inst"; also the type_of tests for known variables have been optimized.

Fri 11th Oct 96         tactics.ml, passim

Corrected CONV_TAC so it accepts |- p rather than |- p = T even if p is an
equation. Hence removed some EQT_INTROs.

Fri 11th Oct 96         tactics.ml

Fixed an analogous bug in DISJ_CASES_TAC; I notices how slow really big case
splits were becoming. The resulting theorem was getting all prefixes of a big
disjunction. Now I recall this was a fix due to TFM for a problem in the HOL88
subgoal mechanism. I guess it won't affect mine as the assumption is explicit;
should think it over though. Anyway it all seems to work.

Fri 11th Oct 96         canon.ml, tab.ml, meson.ml, real.ml

Replaced the old complicated (but slightly more efficient) canonicalization
stuff with simpler versions using rewriting. In particular, took out all the
"REFUTER" stuff which is cute but too complicated. This necessitated a lot of
consequential changes in files that use that stuff.

Fri 11th Oct 96         tactics.ml

Fixed a bizarre bug in X_CHOOSE_TAC, which was keeping the existential
assumption in the new theorem. Also a less bizarre but completely stupid one in
CHOOSE_THEN: the variant was being chosen avoiding the hypotheses of the
existing assumption theorems, rather than the conclusion!

Fri 11th Oct 96         iprover.ml, tactics.ml

Moved FIRST_X_ASSUM into the main tactic file.

Wed  9th Oct 96         drule.ml

Beefed up the sanity check in PART_MATCH to force equality rather than alpha
conversion.

Wed  9th Oct 96         term.ml

Separated off "pure alpha conversion" (without a preceding equality test)
as "paconv".

Wed  9th Oct 96         list.ml

Locally changed the bound variable names of list_INDUCT inside LIST_INDUCT_TAC
so that the induction subgoals have these names, as before.

Tue  8th Oct 96         cprover.ml

Implemented the main prover module. However it's very slow compared with
the search-separated TAB_TAC.

Tue  8th Oct 96         iprover.ml

Fixed a bug in the unifier.

Tue  8th Oct 96         tab.ml

Fixed a bug resulting from the backing off of the equality stuff; a previous
version of NNF_CONV had been used that took its args in a different order.

Tue  8th Oct 96         list.ml

Proved the remaining theorems in the modest list theory that had previously
been asserted.

Tue  8th Oct 96         ind-types.ml

Moved the definition of lists to here, and also proved standard induction and
recursion theorems for the pair type.

Tue  8th Oct 96         ac.ml + passim

Now we have ordered rewriting, the small performance improvement from
AC_CONV et al. hardly seems worthwhile. So I removed ac.ml from the
build sequence, inserting a trivial "AC" using ordered rewriting in
theorems.ml, and using ordered rewriting directly in many of the proofs.
Some other things, like syntax for binary operators, have been
scattered in other files. The ASSOC and DISTRIB conversions have gone
in canon.ml pro tem, pending a complete rewrite of that file.

Mon  7th Oct 96         cprover.ml

Set up basic canonicalization conversions for the classical prover and
the mechanism to set it up as a prover, using a goalstate as a context.

Sun  6th Oct 96         simp.ml

Corrected some of the simplifier traversal strategies, and generally
rewrote and optimized stuff.

Sat  5th Oct 96         simp.ml

Made a few minor tweaks, including optimizing and correcting the default term
ordering.

Sat  5th Oct 96         theorems.ml

Now all the equality-free theorems here are provable by ITAUT rather than
special tactic scripts, so I've done that. In the long run, we could deal
with equality too.

Sat  5th Oct 96         tactics.ml

Fixed a bug in META_EXISTS_TAC, and a corresponding one in EXISTS_TAC; these
were not instantiating the pattern argument to exists (left part of paired
argument). This was causing problems with proving things involving existential
quantifiers in ITAUT_xx.

Fri  4th Oct 96         tactics.ml

Fixed a bug in "by", which was passing the non-updated instantiation to
the body of the new justification function.

Fri  4th Oct 96         iprover.ml

Replaced the ad hoc tautology prover by one using tactics, exploiting the
metavariable feature. This also does some first order logic (without equality),
modulo bugs.

Fri  4th Oct 96         tactics.ml

Added (as an experiment) two metavariable tactics: META_EXISTS_TAC and
META_SPEC_TAC.

Fri  4th Oct 96         tactics.ml

Optimized UNDISCH_THEN, so now it uses the theorem directly rather than
doing inference.

Fri  4th Oct 96         tactics.ml

Added "FIND_ASSUM" to use an assumption with given conclusion. (A more
efficient alternative than using ASSUME, now to be deprecated.)

Fri  4th Oct 96         bool.ml, canon.ml

Corrected "is_beq" and moved it back to "bool.ml".

Fri  4th Oct 96         simp.ml, tactics.ml

Reversed the build order of these two files so that tactics come first. This
seems better as we can then use tactics to get a simple logical theorem prover.
Accordingly, moved the rewriting tactics out of "tactics.ml" and into
"simp.ml".

Tue  1st Oct 96         ind-types.ml

Fixed a silly little bug in the "extract_arg" function; it only worked when
the string of FSTs and SNDs generated by a recursive call was exactly one
of FST and SND without nesting. This caused examples from Steve Brackin and
Konrad Slind to fail. Now they all seem OK. It even handles Konrad's big 68000
instruction set example (418 seconds on swordfish).

Tue  1st Oct 96         parser.ml

Added semicolon and comma to the stock of "brackets" (single-character
identifiers).

Tue  1st Oct 96         parser.ml

Added an option (lexquotes) to allow recognition of items in '....' as variable
names, even if they don't obey the usual syntactic conventions. This was to
simplify supporting Prover logs, but is arguably useful. Anyway it's switched
off. Also corrected the string quotes inside quotation parser to double quotes.

Mon 30th Sep 96         lib.ml

Inserted a slightly seedy hack into "set_insert" and "set_merge" to make the
builtin orderings return false rather than fail when given functional values.
Since the built-in ordering is lexicographic on pairs, this lets us prioritize
the data lists in term nets without any special ordering. Perhaps I should do
this properly...

Mon 30th Sep 96         nets.ml

Rewrote nets completely. First, included a facility for local constants (i.e.
variables not instantiable in context), and included a function to merge sets.
This is more or less ripped off from Don's hol-lite code, though I don't store
the local constants in the net as he does. Also made the data lists canonically
sorted, so that we can encode priorities in convnets without any special
measures.

Mon 30th Sep 96         lib.ml

Added a function "set_merge" to perform (set) union of canon-sorted sets.

Mon 30th Sep 96         theorems.ml

Stepped the _AC suites for conjunction and disjunction up to _ACI ones;
this still gives a normalizer with ordered rewriting (I hope).

Mon 30th Sep 96         simp.ml

Modified the default term ordering to be a dynamic lex order. I think this is
AC-compatible and efficient, but I'm not 100% sure. We'll see...

Sat 28th Sep 96         wf.ml, arith.ml

Fixed two broken proofs. The "arith.ml" one was the old favourite of
nonconfluent rewrites. The "wf.ml" one is a bit odd; the name of a bound
variable, later freed by STRIP_TAC, changed. This is presumably because I
deleted the alpha conversion wrapper round REWR_CONV, since it seemed
pointless. But I guess some consequences made it to the toplevel, maybe via the
ind def package. Anyway, gratifyingly few breaks.

Sat 28th Sep 96         simp.ml, drule.ml, iprover.ml

Created "simp.ml" containing the core of a simplifier. This is crudely
speaking all the "atomic" stuff, which is a generalization of basic HOL
rewriting to include ordered rewriting and conditional rewriting (though
without doing anything with the conditions yet except leaving them as
assumptions.) The nice thing about isolating this part first is that we
can integrate it with the basic HOL rewriting. This has been done, so
the rewriting stuff has been taken out of "drule.ml". I've also separated
off the intuitionistic tautology prover; this is a bit half-baked and
deserves to be the core of a more serious prover anyway.

Sat 28th Sep 96         theorems.ml, arith.ml, reals.ml, int.ml

Added xxx_AC theorems for conjunction and disjunction, and for addition and
multiplication of naturals, reals and integers. This is in preparation for
ordered rewriting, when lots of things will become better.

Fri 27th Sep 96         ind-defs.ml, lib.ml

Moved "nsplit" back into lib.ml since it seems fairly general.

Fri 27th Sep 96         basics.ml

Made "free_in" work up to alpgha-equivalence.

Wed 25th Sep 96         tactics.ml

Abandoned pro tem the keeping of a series of goalstacks as completed ones were
stuck there, causing problems.

Wed 11th Sep 96         equal.ml

Cleaned up the file a bit, e.g. removed pointless error traps for RAND_CONV and
RATOR_CONV.

Fri  6th Sep 96         term-nc.ml

Added an optimization to "type_of" for the case "(\x. s[x]) t". Also renamed
the file simply to "term.ml" since there's no foreseeable prospect of having dB
terms back.

Fri  6th Sep 96         type.ml

Fixed a bug in "tyvarsl", which simply returned the list unchanged due to a
permutation of the arguments to itlist. Fortunately this wasn't used anywhere.
Now "tyvars" and "tyvarsl" are mutually recursive.

Thu 15th Aug 96         tactics.ml

Renamed "merge_insts" to "compose_insts" (which better suggests its sequential
nature). Also corrected (?) the implementation, which was completely wrong.

Thu 15th Aug 96         tactics.ml (was newtactics.ml)

Fixed a moronic error in the goalstack printer which usually caused no subgoals
to be printed during an interactive goalstack proof. (Basically, it used the
number of current goals minus the previous number to indicate how many to
print. It should be one greater than that, while being at least 1, and with no
previous goal being another special case of 1.)

Thu 15th Aug 96         tab.ml

Replaced the new but more complicated version of tableaux (with a half-baked
and incomplete equality handling system) by the old equality-free but simple
version. I'll attack this again in a different way sometime. Must also try
Brand/E-SETHEO transformation to MESON.

Thu 15th Aug 96         <passim>

Made bool_ty (":bool"), aty (":A") and bty (":B") global; removed
all their local bindings.

Thu 15th Aug 96         term-nc.ml,ind-defs.ml

Moves "lhand" back with the other term syntax stuff.

Thu 15th Aug 96         <passim>

Following a suggestion of Donald Syme, deleted the file "dsyntax.ml" and
inserted these syntax functions in the natural (usually) places in the
development. The main defect is that some duplications are needed in the
printer, which uses some derived destructors. Eventually this will be fixed
when the printer prints preterms not terms (another suggestion from Don; I
think Isabelle does it this way too).

Thu 15th Aug 96         preterm.ml

Trivial change: made "unify" curried, to use "do_list2" instead of "zip" in
its implementation.

Wed 14th Aug 96         parser.ml

Fixed parser not to keep swallowing undefined type constructors. This
introduces more context-sensitivity into parsing. However this was my
original intention, since one part of the pretype parser already made
this check.

Mon 12th Aug 96         ind-defs.ml

Made "make_args" take a letter argument, for greater flexibility.

Thu 27th Jun 96         newtactics.ml

Added an experimental new scheme for tactics. This retains labels, but also
(1) makes the assumptions theorems, and (2) includes metavariables. There is
now a move to the notion of a "refinement" on a set of subgoals (since with
metavariables, the order in which goals are solved matters). This has been used
to provide goalstack-like facilities in a less ad hoc fashion. The new aspects
may be buggy, but it's surprisingly upward-compatible.

Mon 17th Jun 96         tacticals.ml,tactics.ml

I discovered SUBST_ALL_TAC was throwing away assumptions. Fixed this and
related problems by adding "POP_LASSUM_TAC" and making RULE_ASSUM_TAC use it to
preserve labellings. There might be a few others of these lurking.

Sun 16th Jun 96         subgoal.ml

Made the subgoal state a list (i.e. stack) of goalstacks. This allows one to go
into a new goal state then return to the old one (but you need to "b()"
explicitly; it doesn't happen just when the subgoal is proved). This is to
support Mizar processing but it's handy anyway. I think hol90 does it.

Sat 15th Jun 96         subgoal.ml

Added a flag "valcheck" to make validity checking optional.

Sat  8th Jun 96         basics.ml, printer.ml, subgoal.ml, tacticals.ml,
                        tactics.ml, meson.ml

Introduced labelled assumptions in tactics. The main reason was to achieve
a new level of integration between tactics and MESON proofs. However labels
seem useful for other reasons. The main additions are "LABEL_TAC" to perform a
labelled "ASSUME_TAC", and "USE_ASSUM" to grab the assumption with a given
label. The goal prettyprinter puts any labels in parentheses at the right of
the term, which seems quite close to mathematics books, and doesn't disturb the
formatting.

While tinkering with tactics, I also grabbed the chance to add "UNDISCH_THEN"
which I've always wanted, and added a generic function "ASM_TAC" to augment the
theorem list given to a tactic with the assumptions of the goal. In fact, if we
called it just "ASM" then "ASM REWRITE_TAC[]" and "ASM_REWRITE_TAC[]" would be
the same and we could avoid all those extra functions. Perhaps the HOL world
isn't quite ready for that, though.

Since I can't use my pet "W(ACCEPT_TAC o mk_thm)" any more, I decided to add
"CHEAT_TAC"!

Anyway, no proofs broke, and there are some big ones now. Of course, there was
no reason why they should.

Fri  7th Jun 96         ind-defs.ml

Corrected a non-PE'd quotation (just `T` fortunately) which somehow got left
in.

Sat 25th May 96         calc_rat.ml

Added "REAL_SUM0_CONV" to evaluate summations. I don't really know why I put it
in this file.

Fri 24th May 96         calc_rat.ml

Included "REAL_RAT_DIV_CONV" in the overall conversion; it had been
inadvertently left out. Also optimized REAL_RAT_DIV_CONV to fail quickly
when given a canonical rational.

Wed 22nd May 96         tactics.ml

Added "ABBREV_TAC", which I found quite useful in the reals library in HOL88.
I've now come across a use for it, and in general, I think it's a worthy
inclusion.

Wed 22nd May 96         calc_num.ml

Added a "NUMERAL" on the right-hand side of the first ARITH_SUB theorem!

Tue 21st May 96         tab.ml

Put proper initialization of "cstore" in "fol_of_const" and friends, so that
a call to "reset_cstore" isn't necessary at the start. This bug was pointed out
by Donald Syme.

Mon 20th May 96         dsyntax.ml

Added "is_beq" test for Boolean equations (iffs).

Sun 19th May 96         equal.ml

Fixed up "BINOP_CONV" to do what it should do, i.e. ignore the operator. (The
old one checked it against an additional argument).

Added "DEPTH_PRED_CONV" to apply a conversion to atoms in pred. calc.

Fri 26th Apr 96         calc_num.ml

Added "num_CONV"; not before time! Now it's derived, of course.

Sat 20th Apr 96         printer.ml

Added printing of a space after the ";" and "," separators for lists and
sets.

Sat 20th Apr 96         dsyntax.ml, equal.ml

Added "is_cons" (forgotten earlier) and a conversion "LIST_CONV" to apply a
conversion to each element of a list.

Sun 31st Mar 96         printer.ml

Put special syntax for list printing in; also fixed a bug in printing of term
sequences (it always used "," regardless of the separator argument, and due to
a syntax ambiguity in CAML, it wasn't dealing with empty lists correctly).

Sun 31st Mar 96         dsyntax.ml

Put in syntax functions for lists: mk_cons, dest_cons, mk_list, mk_flist,
dest_list and is_list.

Sun 31st Mar 96         real.ml

Took the rewrite-based natural number arithmetic conversions out; now the new,
more efficient ones are used. This file now does seem to go through a bit
faster (2:25 rather that 2:50 real time for the REAL_ARITH_TAC applications).

Sun 31st Mar 96         calc_num.ml

Finished a complete suite of numeric calculation routines. They're OK, but
really multiplication should be O(n^log_2(3)) optimized. Anyway, the
performance is not too disastrous, e.g. `2 EXP 1000` takes under 7 seconds;
`(2 EXP (4 + 5) * 2) DIV (3 EXP (8 MOD 4))` takes 0.35 seconds (on woodcock).
Note the "n * 1 = n" traps in multiplication; given these, then
denormalization will never occur, per construction (or so I hope).

Sun 31st Mar 96         arith.ml

Added theorems about the uniqueness of DIV and MOD, and derived some earlier
theorems from them.

Sat 30th Mar 96         arith.ml calc_num.ml

Separated off the arithmetic rewrites into a separate file "calc_num.ml". Began
augmenting these crude rewrites with some more efficient conversions.

Sat 30th Mar 96         dsyntax.ml arith.ml parser.ml printer.ml

Wrote versions of numeral conversions using Valerie's bignums. Just in case,
added "small" versions for type "int"; maybe these should be scrubbed in fact.
Moved the numeral constructors forward into "arith.ml" to get the benefit of a
bit of PE. (The destructors are needed in the printer at present.) Fixed up the
parser and printer to use bignums; changing pmk_numeral.

Sat 30th Mar 96         -

Moved over to version 0.71 of CAML without obvious problems. Took the chance to
set up a preload of both unix and bignum stuff in "my_little_caml".

Sat 30th Mar 96         real.ml

Fixed a thinko in "REAL_ATOM_NORM_CONV". I'd defined an optimized conversion
internally to avoid pointless "&0 = a" -> "&0 = a - &0" canonicalization, but
then never used it. This ought to make the real arithmetic stuff marginally
faster on average.

Fri 29th Mar 96         arith.ml, parser.ml, perterm.ml, dsyntax.ml, num.ml

Put an extra tag "NUMERAL" round all bitwise numerals. This is to fix an
old bug where one numeral is actually a subterm of another, leading to bizarre
effect such as rewrites with |- 1 = SUC 0 to "2". The change was pretty trivial
to make, fixing all the numeral manipulating syntax functions, parser etc. and
throwing in NUMERAL as an additional rewrite to derive some theorems. All the
arithmetic rewrites now have the extra "numeral" tag. NB! We consistently use
the numeral tag for zero too (which therefore ceases to be a constant). This
may require a modest hack when we get round to defining
"new_recursive_definition" properly. As it is, we now have "_0" for the
constant (which is needed as a foundation for the numerals).

Thu 28th Mar 96         thm.ml

Hey -- our first unsoundness bug since teething troubles over prelogic! This
was pointed out by Tom: in the definition rules there's a requirement not to
have type variables free in the term being defined which aren't free in the
new constant. For example:

  let th0 = new_definition `X = !x:A. !y. x = y`;;
  let th1 = INST_TYPE [`:one`,`:A`] th0
  and th1' = INST_TYPE [`:bool`,`:A`] th0;;
  let th2 = TRANS (SYM th1) th1';;
  let th3 = ONCE_REWRITE_RULE[one] th2;;
  let th4 = REWRITE_RULE[] th3;;
  let th5 = SPECL [`T`;`F`] th4;;
  let th6 = REWRITE_RULE[] th5;;

Fixed this by a check in "new_basic_definition" that all type variables in
the predicate are in the type of the constant to be defined. I think this is
the right thing: it means that type instantiation of the predicate is
reflected in a change to the constant. But should think this over carefully
one day...

Thu 28th Mar 96         lib.ml

Put a "subset" function in. About time; see above for the reason. It would be
more efficient to sort first, but I don't really mind...

Thu 21st Mar 96         meson.ml

Fixed a very strange bug in the production of congruence rules for EQ_MESON. It
was completely wayward, producing something not in clausal form. Obviously I'd
just assumed this worked without even the most rudimentary testing.

Wed 20th Mar 96         meson.ml

Fixed a gross blunder in "fol_of_hol_clauses". It was taking as the set
of local constants the hypothesis frees of the head theorem, but now takes
the hypothesis frees of the theorem it's actually doing. What was I thinking?

Sat 17th Feb 96         drule.ml

Removed "part_match_error". I've no idea how that got there. Anyway the
compiler couldn't infer the types ("I" in a ref) so it spoiled my profile run.

Wed 14th Feb 96         gtt.ml

Moved "trivia" back before "canon", since we might as well use I_THM for first
order reduction.

Wed 14th Feb 96         canon.ml, meson.ml, tab.ml

Wrote a conversion FOL_CONV to produce a better FOL reduction (Donald Syme was
already finding examples where the naive apporach failed). Basically it finds
the minimal application level for each "constant", then fills out any greater
levels with explicit invocations of the "apply" operator (we use I for this --
probably should use a separate constant just in case the original formula
involves "I"...) This is now used by tableaux and MESON.

Wed 14th Feb 96         canon.ml

Put in an extra conversion for REFUTE and CNF_REFUTE which is applied after the
reduction to NNF, but before any splitting etc. The idea is to allow a superior
massage into first order form.

Wed 14th Feb 96         printer.ml

Put a break after each assumption in "print_thm".

Tue 13th Feb 96         real.ml

Proved all the trivial lemmas leading up to the arithmetic decision procedure,
which had previously been mk_thm'ed (they all turned out to be true!) Really,
should go over these again when the equality handling in TAB_TAC improves; it
should do almost all of them automatically.

Tue 13th Feb 96         canon.ml, tab.ml, meson.ml, real.ml, int.ml

Added conversions EQ_ABS_CONV and UNLAMB_CONV. The latter tries to eliminate
lambda-terms from formulas as input to first order automation tools. Now since
the elimination of a lambda requires the resulting term to be further processed
(to get it into NNF and remove any further lambdas), the NNF_CONV function has
been modified to do a retraversal after calling "baseconv". Now to stop this,
the conversion given must be NO_CONV, not REFL. This has been appropriately
fixed up. The extra baseconv argument has been retained in CNF_REFUTE too. Now
tableaux and MESON use UNLAMB_CONV in their NNF steps.

Mon 12th Feb 96         thm.ml

Put an extra test in BETA_CONV to avoid calling "vsubst" in the special
situation where the abstraction variable and argument are the same, i.e.
"(\x. t[x]) x". This was intended to make let-elimination more efficient in
certain situations, but should have other efficiency payoffs since these
trivial beta-redexes often arise in higher order matching, and in SPEC_ALL.

Sun 11th Feb 96         parser.ml, printer.ml, dsyntax.ml, pair.ml

Changed the representation of lets so that "let x = s and y = t in u[x,y]"
becomes "LET (\x y. LET_END (u[x,y])) s t"; the new constant "LET_END" is used
to flag the end of the let-terms in case "u" is itself an abstraction. Put
in a "dest_let" and "is_let"; the former is now used in the printer.

Sun 11th Feb 96         printer.ml

Increased box limit (after which elision starts) from default of 35 to 100.

Sun 11th Feb 96         parser.ml, printer.ml

Added parsing support (actually just a correct "pmk_let" constructor; the
parser was already OK) and printing support for let-expressions.

Fri  9th Feb 96         equal.ml

Fixed a fumble in TOP_SWEEP_QCONV, which had TOP_DEPTH_QCONV in place of a
recursive call. Thanks to Don Syme for pointing this out.

Thu  8th Feb 96         realax.ml

Filled in the remaining gaps in the real construction: construction of
multiplicative inverse and completeness transfer from ":hreal".

Fri  2nd Feb 96         arith.ml

Added a proper derivation of the existence of DIV and MOD, and defined them by
constant specification. The proof was basically the same as (Tom's?) HOL88 one.

Tue 12th Dec 95         meson.ml, arith.ml, realax.ml

Added versions of MESON_TAC which take theorems and allow throwing in of the
assumptions, by analogy with REWRITE_TAC and ASM_REWRITE_TAC. These are much
more convenient to use, and instances in other files have been updated.

Tue 12th Dec 95         canon.ml

Added "CONV_OF_PROVER", useful for more palatable forms of MESON_TAC, TAB_TAC
and no doubt others in the future.

Fri  8th Dec 95         fol.ml

Fixed a bug in the addition of equality axioms; it was leaving implications
in the supposed clausal form of the congruence rules.

Wed  6th Dec 95         canon.ml

Used a different version of EXISTS_UNIQUE_THM to eliminate unique-existence;
this should make the resulting proofs easier.

Wed  6th Dec 95         fol.ml

Fixed a bug in the HOL translation of MESON proofs. The local instantiations
saved in the proof tree were merely being unioned in, but it can happen that
the toplevel instantiations change them (because some variable free in the,
err, residue, gets instantiated "right" in the proof.

Wed  6th Dec 95         canon.ml

Added a preprocessing phase to NNF_CONV which eliminates any logical
constants T and F used in combination; it also makes a few other handy
simplifications and expands unique-existence instances. The REFUTE
function checks whether it's already got "F", just in case that would
stump the later function!

Tue  5th Dec 95         basics.ml, drule.ml, ac.ml, ind-types.ml

Introduced an extra argument "local constants" for term_match. This is
instantiated to the variables free in both hyp and concl of the theorem
when it's used in PART_MATCH. The main idea is to inhibit impossible
higher order matches, and so improve efficiency. However it may lead to
usefully more rapid failures in other no-match situations too.

Sun  3rd Dec 95         class.ml

Took out duplicate SELECT_AX. How did that get there?

Tue 28th Nov 95         printer.ml

Fixed up the printing of negation properly: it was giving it precedence
over infixes --- actually HOL88 does this for high-binding infixes, meaning
basically not the logical operations. Perhaps I should introduce precedence for
prefixes and follow suit. Also generalized printer to arbitrary prefixes
(though in fact we don't have any besides negation yet!)

Sun 26th Nov 95         fol.ml

Added a new version of MESON_TAC which throws in the equality axioms to the
proof search. The initial results are not encouraging... For example Pelletier
number 49 takes 6 minutes! But some of the others aren't too bad...

Sun 26th Nov 95         sets.ml

More set theory stuff ported, using automated proofs; however we still specify
by trial and error which equality theorems etc. to throw in. There's also a
slight problem over when we want the extra theorems to get rewritten with the
definitions (use MP_TAC first when we do, rather than giving it in the theorem
list argument).

Sun 26th Nov 95         <passim>

It was just getting too tedious being unable to interrupt things, now we have
all these first order automation tools, so... Made a signal call so that
SIGINTs raise a new exception "Interrupt". Then trawled through systematically
taking out all "with _ ->" traps. Most can be replaced by "with Failure _ ->",
since practically every function used is one of ours (except arithmetic, and I
think that just wraps without failing). A few need to be treated more carefully
(Unchanged exceptions and Cut too in the Prolog engine). So, after a small
number of fixes, everything seems to work again, and now interrupts will
always(?) propagate. Really, it would be preferable to have a separate signal
mechanism, but...

Fri 24th Nov 95         fol.ml

Modified the tableau procedure to use a similar "offset" technique to MESON in
order to create temporary variables. This is much better than inventing stacks
of genvars of its own, each with a HOL analog...

Thu 23rd Nov 95         fol.ml

Added a depth bound (as opposed to inference bound) option to MESON_TAC. Of
course it's important that this switches off the divide-and-conquer
optimization; this is forced even if the user forgets. We also disable the size
consideration in the continuation cacher, to avoid uneccessary conservatism.

Wed 22nd Nov 95         fol.ml

Added MESON_TAC. It seems to work reasonably well.

Tue 21st Nov 95         canon.ml

Added conversions for DNF and CNF. Also added the wrapper CNF_THEN_REFUTE,
which is a bit more efficient than just applying the conversion at toplevel.

Tue 21st Nov 95         ac.ml

Added DISTRIB_CONV and BODY_CONV.

Tue 21st Nov 95         equal.ml, ac.ml, drule.ml

Introduced COMB2_QCONV and COMB_QCONV; renamed COMB_CONV2 to COMB2_CONV
everywhere.

Mon 20th Nov 95         equal.ml, real.ml

Introduced BINOP_CONV as an analog to SUB_CONV which is what I thought it was;
the old one is renamed to DEPTH_BINOP_CONV and the two instances in real.ml
changed.

Mon 20th Nov 95         gtt.ml

Fixed the filter to use suffix of pathname only when creating its temporary
filename, otherwise it tries to deal with a nonexsistent directory.

Mon 20th Nov 95         parser.ml

Modified set enumeration parsing to use "INSERT" and "EMPTY", rather than write
down an abstraction term explicitly.

Mon 20th Nov 95         int.ml

Modified the integer decision procedure to do discretization properly, i.e. to
force NNF and hence fix the signs of all the inequalities first. The overhead
shouldn't be too large since the NNF run introduced by the reals decision
procedure will be trivial in most cases (the refuter will give a toplevel
double negation, and the remainder is already in NNF).

Mon 20th Nov 95         basics.ml

Modified "find_terms" to use "insert" rather than "::", and hence produce a
set.

Mon 20th Nov 95         real.ml

Added a quick prepass to REAL_ARITH_CONV to eliminate trivial quantifiers; this
can get a few more things into prenex universal form, though it's probably
quite useless in practice. Renamed "REAL_ARITH_CONV" to "REAL_ARITH" and put in
a separate EQT_INTRO version called "REAL_ARITH_CONV" (just for consistency; it
wasn't a conversion).

Sun 19th Nov 95         real.ml

Altered REAL_ARITH_CONV to force prenex form, and hence avoid failing where a
trivial transformation would bring the theorem into universal form, e.g.
"!x. x < y \/ !z. z <= y ==> z <= x".

Sun 19th Nov 95         canon.ml

Added a conversion for prenexing (assuming there are no equivalences or
conditionals).

Sun 19th Nov 95         int.ml

Put in a decision procedure for the naturals; a wrapper for the one for
integers.

Sun 19th Nov 95         filter.c

Tweaked the filter again; it still wasn't giving the right line numbers!

Sun 19th Nov 95         real.ml

Made sure all quotations get evaluated at load time. This is not just an
efficiency tweak -- if a different interface map is in action at runtime, we
get a change in behaviour! This was exhibited in the integer decision
procedure.

Sun 19th Nov 95         int.ml

Added a simple decision procedure for linear arithmetic over the integers. This
just hacks the term down to the corresponding real fact (we assume it's
universal in these procedures anyway) then calls REAL_ARITH_CONV.

Sun 19th Nov 95         gtt.ml

Made the filter pick a temporary filename which depends on the PID and the
original filename -- this should avoid the problem of contention between
parallel GTT sessions on the same machine, and give more helpful error
messages.

Sun 19th Nov 95         thm.ml

Made benign type redefinitions acceptable, by the crude device of inserting a
cache of previous calls and results.

Sat 18th Nov 95         ind-defs.ml

INDUCT_THEN and INDUCT_TAC added. These are similar, but not the same, as the
ones in the HOL88/hol90 library. In particular, there is no distinction made
between "hypotheses" and "side-conditions", and so no call for two separate
theorem continuations.

Sat 18th Nov 95         sets.ml

Wrote simple tactic to reduce the very elementary reasoning to FOL, then call
TAB_TAC; hence automatically proved a reasonable number of the theorems in the
HOL88 pred_sets library.

Sat 18th Nov 95         thm.ml, bool.ml, drule.ml

Made benign term definitions acceptable (up to alpha conversion; this is
necessary since pairs and set abstractions may introduce different bound
variable names on different occasions); also introduced storage of definitions
(which was not done before, despite the presence of the variable
"the_definitions"!)

Fri 17th Nov 95         ind-defs.ml, num.ml, ind-types.ml

Changed "new_inductive_definition" to split up the three conjuncts into
separate theorems. Modified the two existing uses in the core.

Fri 17th Nov 95         sets.ml [new file]

Basic definitions for set theory added.

Fri 17th Nov 95         parser.ml, preterm.ml, printer.ml

Included parsing and printing support for enumerated and generalized set
specifications; also added to "preterm.ml" a few preterm syntax functions that
were needed and may be useful elsewhere.


Fri 17th Nov 95         arith.ml, bool.ml, int.ml, pair.ml,
                        realax.ml, trivia.ml, wf.ml

Rationalized the infix precedences as follows (arithmetic operators include
their analogs in other number systems and in set theory). They're
right-associative, unless marked "L". These seem the most sensible; e.g. x - y
+ z and x - y - z work as expected. I'm not quite sure where pairing (,) should
go really...

         2       =
         4       ==>
         6       \/
         8       /\
        10      general_equivalence_relation
        11      IN
        12      < <= >= > general_order_relation SUBSET PSUBSET
        14      ,
        16      + UNION
        18 L    - DIFF
        20      * INTER
        21      INSERT DELETE
        22 L    / DIV MOD
        24 L    pow EXP
        26      o

Fri 17th Nov 95         lib.ml

Put in a version of "map" with a more intuitive evaluation order (left to
right).

Fri 17th Nov 95         fol.ml

Put continuation cacheing into tableau prover (so repeated attempts will
immediately fail). On big examples this seems quite useful; e.g. Andrews's
challenge now takes 89.77 seconds instead of 130.23. Pelletier 43 now takes
2.21 seconds instead of 13.50. The other Pelletier examples are all pretty much
the same.

Fri 17th Nov 95         filter.c

Changed the filter to echo all newlines (and to flush stdout after each
newline, rather than after each ";;"). This makes the error messages from CAML
better in two respects: (1) the line numbers are right; (2) you don't get lots
of previous phrases spat out at you.

Fri 17th Nov 95         real.ml

Fixed a bug in the cacher's translator, which did not distribute negations over
the final term in a sum.

Thu 16th Nov 95         lib.ml

Added a timing function.

Thu 16th Nov 95         lib.ml

Added "report" function and verbose/terse flag; modified "warn" to use it.

Thu 16th Nov 95         fol.ml

Integrated a simple tableau prover based on Lean-TAP into HOL. The preliminary
results are quite good; e.g. it solves most of the equality-free Pelletier
problems fairly quickly. Andrews's challenge takes about 2 minutes.

Wed 15th Nov 95         real.ml

Cleaned up the decision procedure REAL_ARITH_CONV and modified it to use the
refuter in "canon.ml" rather than its own bespoke code. Also added intelligent
cacheing of atom normaliztion theorems (i.e. it remembers negations of previous
atoms --- this seemed easier than canonicalizing prior to the NNF conversion,
and probably as efficient, on average, since it might on occasion catch
complicated duplicates).

Wed 15th Nov 95         quot.ml

The "lift_theorem" function in the quotient stuff has been rewritten: given the
new higher order rewriting, it's trivial. The left and right sides of the
derived theorems returned by "lift_function" have been swapped; this seems more
sensible.

Wed 15th Nov 95         drule.ml, arith.ml, realax.ml

Changed PART_MATCH to attempt a crude (but adequate) preservation of bound
variable names. Really, all the higher order matching, BETA_VAR and this should
be more neatly integrated in PART_MATCH, which is the practically universal
entry point. There are further things one would like, e.g. the recognition that
"f" and "f'" should be changed in parallel -- but where do we stop?

A few consequentially broken proofs fixed; broken mainly because INDUCT_TAC now
(correctly!) preserves the bound variable name in the goal rather than
replacing it by "n".

Mon 13th Nov 95         basics.ml

Substantially enhanced higher order matching so that (1) Manifestly first order
bits are handled first, which may increase the stock of determinate variables
available later; this is sometimes useful; e.g. RULE_INDUCT_TAC has a more
natural coding; and (2) More general patterns are allowed, of the form P
(t1[x1,..,xn]) ... (tm[x1,..,xn]), where the x1,..,xn are all determinate. This
is useful for doing some transfer stuff (!n. P(&n) = ...) etc. and occasionally
in other places too.

Mon 13th Nov 95         term-nc.ml

Put trivial PE into "inst"; it returns the identity function if the
instantiation list is empty.

Thu  9th Nov 95         filter.c

Fixed filter to ignore interrupts, and also to insert "let it = " before
any toplevel phrases which are not declarations.

Thu  9th Nov 95         nets.ml, arith.ml, realax.ml

Reversed the appending in "follow" to favour specificity in matches; that is
"SUC n" will (if matchable) be put ahead of "m" in the list of possible
matches. This seems a more sensible defalt. A few consequentially broken
proofs fixed.

Wed  1st Nov 95         theorems.ml

Cleaned up a few proofs, now that higher order matching bugs are cleared.

Tue 31st Oct 95         printer.ml

Terms and types are now printed with backquotes, not double quotes.

Tue 31st Oct 95         parser.ml

"lextoken" now uses consing followed by final reverse; probably a bit better
than iterative snoc-ing.

Tue 31st Oct 95         drule.ml, ind-defs.ml

Moved the derived congruence rules back into drule.ml.

Tue 31st Oct 95         parser.ml

Put in faster character disrimination based on lookup table. (Be nicer to have
bitwise operations for this as some aren't mutually exclusive).

Mon 30th Oct 95         lib.ml

Slightly less lamentable implementation of "explode" substituted. (The old one
kept taking the `tail' of the string, which involved creating new copies!)

Mon 30th Oct 95         lib.ml,preterm.ml,subgoal.ml

The "warn" function added, and the two warnings to date modified to use it.

Mon 30th Oct 95         preterm.ml

"type_of_pretype" and "term_of_preterm" tweaked so they will invent names for
STVs, but issue a warning.

Sun 29th Oct 95         subgoal.ml

Inserted a warning into "expand" if the tactic does not change the goal state.
