* ***************************************************************** * 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 * * ***************************************************************** Tue 10th Nov 2026 Library/llist.ml [new file], holtest.mk Added a library of possibly infinite lists ("lazy lists"), with the type A llist, the constructors LNIL and LCONS, the destructors LHD and LTL, LNTH for the element at a position, if any, and the conversions llist_of_list, list_of_llist and llist_of_seq. The type is the disjoint sum of A list and num->A, but the usual coinductive tools are provided too: corecursion with uniqueness (LCOREC and LUNFOLD), extensionality (LLIST_EQ), coinduction by bisimulation (LLIST_COINDUCT) and the tactics LLIST_CASES_TAC, LLIST_COINDUCT_TAC and LLIST_BISIM_TAC. The operations are finiteness and length (LFINITE, LLENGTH), LMAP, LAPPEND, LTAKE, LDROP, LFILTER, LFLATTEN, LZIP, the set of elements (set_of_llist), the quantifiers LALL and LEXISTS, the relator LALL2, the prefix order LPREFIX, in which every chain has a least upper bound, and LITERATE, plus THE and OPTION_MAP on options. The theorems include 94 statements collected from HOL4's llistTheory, the Isabelle AFP entry Coinductive_List and Lean Mathlib's Seq. This was written by Claude Opus 5.5. Tue 10th Nov 2026 Library/ringtheory.ml, Library/fieldtheory.ml Tweaked a few variable names to avoid unfortunate clashes with s2n-bignum (e.g. "bx" which is stolen as a constant for the x86 register). Tue 10th Nov 2026 ind_defs.ml, sets.ml, hol_lib.ml, holtest.mk, UnitTests/basic_tests.ml, Examples/coinduction.ml [new file], Help/* Added coinductive definitions to the core, as the duals of inductive definitions and sharing most of their code in ind_defs.ml. The new function new_coinductive_definition takes the same input as new_inductive_definition but defines the greatest relations consistent with the rules, i.e. the union of all relations R' such that each R' a follows by some rule from instances of R'. It returns a rules theorem, a coinduction theorem and a cases theorem. For example, the infinite paths in a relation R are defined by new_coinductive_definition `!x:A y. R x y /\ infpath R y ==> infpath R x` with the coinduction theorem |- !R infpath'. (!a. infpath' a ==> (?y. R a y /\ infpath' y)) ==> (!a. infpath' a ==> infpath R a) As with inductive definitions, the rules may be mutual and schematic, and monotonicity is proved automatically using monotonicity_theorems, so the two kinds of definition can be nested. There are also the analogs prove_coinductive_relations_exist, derive_nonschematic_coinductive_relations, the_coinductive_definitions and new_coinductive_set, while derive_strong_coinduction gives a stronger form of coinduction "up to" the defined relations. The new file Examples/coinduction.ml gives classic examples of coinduction: infinite paths and Koenig's lemma, invariants, properties of infinite sequences, the lexicographic order, bisimilarity for transition systems and automata, and coinductive big-step semantics with divergence for a while-language. This was written by Claude Opus 5.5. Mon 9th Nov 2026 drule.ml, fusion.ml, tactics.ml Fixed a few remaining cases where the plain OCaml structural equality function "=" was used in place of "compare"; the latter is preferred since it shortcuts quickly on pointer-eq subterms. These were pointed out by Hanno Becker. Sat 7th Nov 2026 simp.ml, Help/find_witnesses.hlp [new file], Help/satisfy_prover.hlp [new file], passim The simplifier can now use a conditional rewrite |- c ==> l = r whose condition c has variables not determined by matching the left-hand side l, by instantiating them from facts in the context. For example, given an assumption q IN ring_carrier(poly_ring r (:V)), the rewrite |- p IN ring_carrier(poly_ring r s) ==> poly_add r p (poly_0 r) = p now applies to poly_add r q (poly_0 r) even though s does not occur on the left, and with an assumption ring_homomorphism(r,s) f, the call ASM_SIMP_TAC[RING_HOMOMORPHISM_MUL] rewrites f(ring_mul r x y) to ring_mul s (f x) (f y), choosing s for r' although r' also occurs on the right. Previously the latter only worked when the variable names happened to coincide, so one usually wrote something like FIRST_ASSUM(fun th -> ASM_SIMP_TAC[MATCH_MP RING_HOMOMORPHISM_MUL th]). The approach follows Don Syme's SATISFY from hol98 (still in HOL4). A new prover satisfy_prover, included in basic_ss and empty_ss, collects facts from the context and proves an existential ?x1 ... xn. p1 /\ ... /\ pk by matching each conjunct pi against the facts, returning the instance with the witnesses rather than the existential itself. The new function find_witnesses uses this to choose an instantiation, which basic_prover uses for existential conditions (as produced by mk_rewrites for variables occurring only in the condition) and the depth conversions use for conditions with otherwise unconstrained variables. The instantiated condition is then proved in the usual way; if no instantiation is found, the behaviour is as before. Since the right-hand side of a conditional rewrite may now only be fixed when it is applied, such an instance is checked then, much as net_of_thm checks rewrites: it is rejected if the left-hand side occurs in the right-hand side, or if it is permutative and does not decrease in term_order. A few tests of all this are in UnitTests/basic_tests.ml. The extra power broke various existing proofs so these have been tweaked; for example about 95 explicit instantiations of homomorphism and similar theorems in Library/{ringtheory,ring_det,fieldtheory,galois,grouptheory}.ml have been replaced by plain uses of the theorems. Sat 7th Nov 2026 Baker/* [new directory], holtest.mk Added a development of the theory of linear forms in the logarithms of algebraic numbers (Baker theory) and of its applications to transcendence and to Diophantine equations in the new subdirectory Baker, produced by Claude. It proves the effective lower bound of Baker and Feldman for linear forms in logarithms with algebraic coefficients (Baker, Transcendental Number Theory, Thm 3.1) and the qualitative theorem of Baker (1, log a_1, ..., log a_n are linearly independent over the algebraic numbers if the logarithms are linearly independent over Q), with the Gelfond-Schneider theorem, Hermite-Lindemann, the transcendence of e^pi and of other classical constants, irrationality measures and gaps between S-units as corollaries; Sharpening I of Baker (Acta Arith. 21, 1972) for algebraic numbers, uniform in the data, both with integer and with algebraic coefficients (Baker 1973), and Tijdeman's bound for the exponents of the Catalan equation; explicit lower bounds for linear forms in two logarithms by interpolation determinants, with the theorem of Steiner on the 3x+1 problem and the bounds of Laurent (Acta Arith. 133, 2008) for rationals and in number fields; the theorems of Thue, Mordell (y^2 = x^3 + k), Baker on superelliptic and hyperelliptic equations and on integral points on elliptic curves, Lebesgue and Ko Chao, the finiteness of the solutions of the Catalan equation (Tijdeman 1976), the unit equation in a number field; the theorem of Schinzel and Tijdeman on y^m = f(x) for every integer polynomial f with two distinct roots; the finiteness of the S-smooth values of polynomials with two distinct roots (the greatest prime factor of f(x) tends to infinity for nonzero f); the finiteness of perfect powers in Lucas sequences with Q = +-1 (Fibonacci, Pell and Lucas numbers) and of the solutions of x^k + D = y^n for fixed k; the class number one problem (the nine imaginary quadratic fields of Gauss, Baker 1966, Stark 1967); the finiteness of the imaginary quadratic fields of class number two (Baker 1971, Stark 1971), for the class number of Gauss (the number of reduced primitive binary quadratic forms); unique factorization in the ring of integers of Q(sqrt(-d)), which holds exactly for d = m^2 k with k one of the nine (also for every number field of degree 2 with negative discriminant), with the theorems of Ramanujan-Nagell (x^2 + 7 = 2^n), Fermat (26 is the only number between a square and a cube) and the case n = 3 of Fermat's last theorem as applications. Algebraic numbers are those of 100/transcendence.ml, with explicit integer polynomials, degrees and heights in the statements; number fields are the abstract number fields of ANT/ (for the subfields of C generated by finitely many algebraic numbers) and, for the Diophantine applications, vectors of conjugates (nf_data) connected with ANT/ by a bridge. The files build on ANT/ (57 of its files, through their needs lines) and on Library/jacobi.ml, 100/transcendence.ml, Examples/mangoldt.ml, 100/dirichlet.ml, Multivariate/gamma.ml, Examples/gcdrecurrence.ml and 100/sqrt.ml with the library files these load. It uses the shared lemmas FINITE_CARTESIAN_PRODUCT_FINITE of sets.ml, NPRODUCT_SUBSET_LE of Library/products.ml and COMPLEX_PRIME_SUBFIELD of ANT/complex_embeddings.ml, added in the entries below; apart from holtest.mk no existing file is changed. Baker/README describes the organization and the conventions and Baker/OVERVIEW.md states the main results; loadt "Baker/make.ml" loads it all, needs "Baker/x.ml" one file with its prerequisites, and Baker/make_core.ml, make_twolog.ml and make_laurent.ml load parts of it. New definitions: algebraic_integer baker_a baker_alg baker_algterm baker_aux baker_c baker_cexp baker_e1 baker_err baker_gamma baker_index baker_J baker_kpar baker_l7 baker_liou5 baker_liou7 baker_logdata baker_Lpar baker_lu baker_lw baker_nmax baker_omega baker_pbound baker_qreq baker_term baker_ub baker_vb circuit collatz_t cyclo_unit feldman_basis feldman_delta form_classno gaussian_integer imag_quadratic_field imag_quadratic_integers int_polyfun intpoly kchar4 laurent_bound laurent_C laurent_Cp laurent_main laurent_omega laurent_theta nagell_seq nf_alg_int nf_data nf_elem nf_embedding nf_order nf_proj_height nf_unit prin_form prin_rep qchar qdisc qf_reduced qform qform_kernel qform_rep qform_slice qform_term quad_omega sharp_alg sharp_algdata sharp_algterm sharp_aux sharp_bound_property sharp_bound_property_alg sharp_coeff sharp_coeff0 sharp_core_property_alg sharp_deltarep sharp_errb sharp_index sharp_lb8 sharp_liou5 sharp_lv sharp_nfbound sharp_omega sharp_psize sharp_term sharp_ubd sharp_x sharpc_bound_property sharpc_coefdata sharpc_core_property zeta_coprime Some of the main theorems: BAKER_EXP_TRANSCENDENTAL BAKER_FELDMAN BAKER_INHOMOGENEOUS BAKER_LINEAR_INDEPENDENCE BAKER_LOWER_BOUND_INDEPENDENT BAKER_POWER_PRODUCT_TRANSCENDENTAL BAKER_SHARPENING BAKER_SHARPENING_ALGEBRAIC_COEFFS BAKER_SHARPENING_REAL BAKER_UNIFORM_RATIONAL CATALAN_EXPONENT_BOUND CATALAN_FINITE CLASS_NUMBER_ONE CLASS_NUMBER_ONE_BOUND_LAURENT CLASS_NUMBER_ONE_PID CLASS_NUMBER_ONE_UFD CLASS_NUMBER_ONE_UNIQUE_FACTORIZATION CLASS_NUMBER_TWO_EXAMPLES CLASS_NUMBER_TWO_FINITE CUBIC_FORM_REDUCTION ELLIPTIC_INTEGRAL_POINTS EXP_PI_TRANSCENDENTAL FERMAT_26 FIBONACCI_PERFECT_POWERS_FINITE FLT3 GELFOND_SCHNEIDER HYPERELLIPTIC IMAGINARY_QUADRATIC_CLASS_NUMBER_ONE KO_CHAO_EXPONENT_BOUND LAURENT_NF_REAL LAURENT_NF_REAL_PARAM LAURENT_RATIONAL LAURENT_RATIONAL_GENERAL LAURENT_RATIONAL_PARAM LEBESGUE LUCAS_COMPANION_PERFECT_POWERS_FINITE LUCAS_PERFECT_POWERS_FINITE MORDELL NF_UNIT_EQUATION PILLAI_FINITE PI_IRRATIONALITY_MEASURE POLY_LARGEST_PRIME_FACTOR POLY_PRIME_POWER_VALUES_FINITE POLY_SMOOTH_VALUES_FINITE POW_PLUS_POW_FINITE RAMANUJAN_NAGELL SCHINZEL_TIJDEMAN SCHINZEL_TIJDEMAN_FINITE SCHINZEL_TIJDEMAN_FINITE_SIMPLE_ROOTS SHARPC_SHARPENING_REAL SHARP_BAKER_NUMBER_FIELD SQUARE_PLUS_POW_FINITE STEINER_CIRCUITS SUNIT_GAP SUPERELLIPTIC SUPERELLIPTIC_SIMPLE_ROOTS THUE TIJDEMAN_LINEAR_FORMS_RATIONAL TWOLOG_LOG2_LOG3 TWOLOG_RATIONAL WEIERSTRASS_INTEGRAL_POINTS Sat 7th Nov 2026 Library/fieldtheory.ml, ANT/numfield.ml, ANT/complex_embeddings.ml Added the theorem that two fields have isomorphic prime subfields exactly when they have the same characteristic, ISOMORPHIC_PRIME_SUBFIELDS, and its case of characteristic 0, ISOMORPHIC_PRIME_SUBFIELD_RATIONAL_FIELD: the prime subfield of a field is isomorphic to the rational field subfield_generated real_ring {&0}, the prime subfield of the reals, iff the characteristic is 0. Also added the identification of the prime subfields of the reals and of the complex numbers with the rationals of Library/floor.ml: REAL_PRIME_SUBFIELD in ANT/numfield.ml (which now loads Library/floor.ml) and COMPLEX_PRIME_SUBFIELD in ANT/complex_embeddings.ml. Sat 7th Nov 2026 sets.ml, Library/products.ml, database.ml, Library/szemeredi.ml, Sieve/bg_s1.ml, Sieve/selberg.ml, Sieve/gt_majorant.ml Added two general lemmas that the Sieve and Baker developments had each proved: FINITE_CARTESIAN_PRODUCT_FINITE (a cartesian product of finitely many finite sets is finite) in sets.ml, and the general form of NPRODUCT_SUBSET_LE (nproduct s f <= nproduct t f when s SUBSET t, t is finite and f x >= 1 on t) in Library/products.ml. The copies in Sieve/bg_s1.ml and Sieve/selberg.ml (the latter stated only for the identity function) are removed and their uses adapted. FINITE_CARTESIAN_PRODUCT_FINITE is also registered in the core theorem database. Renamed the proof-local variable gamma in DKT_PROP6 to gamma0, so that Library/szemeredi.ml also loads after Multivariate/gamma.ml, which defines the constant gamma. Fri 6th Nov 2026 ANT/* [new directory], holtest.mk Added a library of algebraic number theory in the new subdirectory ANT, produced by Claude. It covers Dedekind domains in general (factorization, valuations, DVRs, localization, valuation rings and the Chevalley extension theorem, fractional ideals and the characterizations of Dedekind domains, Euler and Fermat for ideals), integral closure with lying over and going up, the Hensel lemma, number fields as abstract fields of characteristic 0 finite over their prime subfield, rings of integers, the finiteness of the class group, the splitting of primes with the fundamental identity, discriminants and the index formula, the different and its exponents, the Dedekind-Kummer theorem, Eisenstein polynomials, quadratic fields, the relative ideal norm, different and discriminant of an extension of number fields with their tower formulas, the Hilbert theory of Galois extensions (decomposition and inertia groups and fields, Frobenius elements, the Artin symbol, higher ramification groups and the Hilbert formula for the different), infinitely many totally split primes, units and S-units (the Dirichlet unit theorem and the S-unit theorem with the ranks, the regulator, roots of unity, quadratic units and the Pell equation, rings of S-integers), extensions unramified outside a set of primes and the maximal one, Minkowski theory (the class bound sqrt|d_K|, |d_K| > 1 for k <> Q, the Hermite finiteness theorem), the Stickelberger theorem, cyclotomic fields (the ring of integers, the discriminant, the decomposition law, the Galois group, subfields, cyclotomic units, Gauss sums), complex conjugation and the cyclotomic character, absolute values (the approximation theorem of Artin and Whaples, the Ostrowski theorem for Q and the number fields of degree 1, the places of a number field, the product formula), and the Dedekind zeta function for Re s > 1 with Dirichlet densities, their elementary laws and the Frobenius density theorem. Extensions are given by ring homomorphisms, as in Library/fieldtheory.ml, and the results are stated for extensions of number fields (k,l) h; the classical absolute forms are the case of the prime subfield. A Galois extension is assumed as galois_extension(k,l) h alone, which implies field k, field l and ring_homomorphism(k,l) h (GALOIS_IMP_FIELD_EXTENSION). For a ring extension, unramified is the textbook notion (ramification index 1 and separable residue extensions at the primes above the ideal); weakly_unramified asks only for ramification index 1. The two agree for the nonzero primes of rings of integers of number fields (NUMBER_FIELD_UNRAMIFIED_EQ_WEAKLY_UNRAMIFIED): the results on number fields use unramified, those on general ring extensions weakly_unramified. The maximal extension unramified outside S of a number field inside any field extension l is Galois over it (GALOIS_MAXIMAL_UNRAMIFIED_OUTSIDE). ANT/README describes the organization and the conventions; loadt "ANT/make.ml" loads it all, needs "ANT/x.ml" one file with its prerequisites. New definitions: absolute_value class_group class_number complex_embeddings cyclotomic_character cyclotomic_poly decomposition_group dedekind_domain dedekind_valuation dedekind_zeta DVR fractional_ideal fractional_ideal_group fractional_ideal_inv fractional_ideal_valuation frobenius_element has_dirichlet_density ideal_class ideal_classes ideal_norm ideal_of_valuations ideal_pow ideal_prod ideal_product ideal_quotient ideal_valuation inert inertia_group infinite_places int_cosets int_lattice int_matrix_image integral_element integrally_closed maximal_unramified_outside nonarchimedean_absolute_value number_field number_field_codifferent number_field_different number_field_discriminant number_field_ideal_norm number_field_regulator ramification_index real_embeddings residue_degree ring_of_integers ring_of_s_integers s_unit_group totally_ramified totally_split unramified unramified_outside valuation_ring valuation_subring weakly_unramified Some of the main theorems include: ABSOLUTE_VALUE_WEAK_APPROXIMATION CYCLOTOMIC_FIELD_GALOIS_GROUP CYCLOTOMIC_FIELD_RING_OF_INTEGERS DEDEKIND_EQ_IDEALS_INVERTIBLE DEDEKIND_IDEAL_FACTORIZATION DEDEKIND_INTEGRAL_CLOSURE DEDEKIND_RING_OF_INTEGERS DEDEKIND_ZETA_EULER_PRODUCT GALOIS_MAXIMAL_UNRAMIFIED_OUTSIDE HENSEL_LEMMA IDEAL_EULER IDEAL_NORM_FERMAT NUMBER_FIELD_CLASS_GROUP_FINITE NUMBER_FIELD_DEDEKIND_KUMMER NUMBER_FIELD_DIFFERENT_HILBERT_FORMULA NUMBER_FIELD_DIFFERENT_TOWER NUMBER_FIELD_DISCRIMINANT_ABS_GT_1 NUMBER_FIELD_DISCRIMINANT_MOD_4 NUMBER_FIELD_DISCRIMINANT_TOWER NUMBER_FIELD_EISENSTEIN NUMBER_FIELD_FROBENIUS_DENSITY NUMBER_FIELD_FROBENIUS_ELEMENT NUMBER_FIELD_FUNDAMENTAL_IDENTITY NUMBER_FIELD_FUNDAMENTAL_UNITS NUMBER_FIELD_HERMITE NUMBER_FIELD_IDEAL_MINKOWSKI NUMBER_FIELD_INERTIA_GROUPS_GENERATE NUMBER_FIELD_PRODUCT_FORMULA NUMBER_FIELD_RAMIFIED_DISCRIMINANT NUMBER_FIELD_REGULATOR NUMBER_FIELD_TOTALLY_SPLIT_INFINITE NUMBER_FIELD_UNRAMIFIED_EQ_WEAKLY_UNRAMIFIED OSTROWSKI OSTROWSKI_RATIONAL PELL_EQUATION_INFINITE QUADRATIC_GAUSS_SUM VALUATION_SUBRING_DOMINATES Added ANT/make, Multivariate/complex_ring, Multivariate/complex_field, Multivariate/infinite_galois and Library/normal_basis to holtest.mk. Fri 6th Nov 2026 Library/ringtheory.ml, Library/fieldtheory.ml, Library/ring_det.ml, Library/galois.ml, Library/grouptheory.ml, Library/ring_groups.ml, Library/isum.ml, Library/products.ml, Library/prime.ml, Library/pocklington.ml, Library/multiplicative.ml, Library/primitive.ml, Library/jacobi.ml, Library/modmul_group.ml, Library/floor.ml, Multivariate/transcendentals.ml, Multivariate/realanalysis.ml, Library/normal_basis.ml [new file], Multivariate/profinite_groups.ml [new file], Multivariate/infinite_galois.ml [new file] Added general lemmas used by the algebraic number theory library ANT, each in the library file of its subject: Library/ringtheory.ml: units modulo an ideal (RING_UNIT_QUOTIENT_RING_COSET, RING_UNIT_QUOTIENT_RING_COSET_EQ, RING_UNIT_QUOTIENT_RING_COSET_MUL, RING_UNIT_QUOTIENT_RING_COSET_POW, RING_UNIT_QUOTIENT_RING_MAXIMAL, RING_UNIT_QUOTIENT_RING_RADICAL), polynomials with coefficients in an ideal (RING_IDEAL_POLY_COEFF, POLY_DIVISION_COEFF_IDEAL), values of polynomials (POLY_EVAL_TAYLOR, POLY_EVAL_SUB_IN_IDEAL, POLY_EXTEND_MONIC_UNIVARIATE, RING_MONIC_RELATION_FACTOR, FIELD_POLY_COFACTOR_COEFFS, SUBRING_GENERATED_MONIC_ROOT_SPAN), Lagrange interpolation over a field (POLY_LAGRANGE_INTERPOLATION, RING_SUM_LAGRANGE_COEFF, COEFF_POLY_MUL_X_MINUS), common roots of the images of an ideal of r[X] (POLY_DEG_PSEUDO_DIVISION_STEP, RING_IDEAL_POLY_LEAST_DEGREE_ROOT, IDEAL_GENERATED_ADJOIN_ROOT_UNIT), finite sums over roots of unity and residues (RING_GEOMETRIC_SUM, RING_SUM_ROOT_OF_UNITY_POWERS, RING_SUM_MOD_MULT_REINDEX), integer_mod_ring (RING_EPIMORPHISM_INTEGER_MOD_RING, RING_KERNEL_INTEGER_MOD_RING, POLY_RING_INTEGER_MOD_RING_OF_INT, RING_OF_INT_REM_CHAR_DIVIDES, RING_CHAR_QUOTIENT_RING_DIVIDES), and INTEGER_RING_SUB, NOETHERIAN_RING_FINITELY_GENERATED_ALGEBRA, FIELD_ADD_INV_EQ, FIELD_DIV_EQ_MUL, ROOT_OF_UNITY_IN_SUBRING_GENERATED, IDEAL_GENERATED_PAIR_EQ, IDEAL_GENERATED_INSERT_EQ, QUOTIENT_RING_LINCOMB_LIFT, IN_RING_IDEAL_SUB_SUM_RESTRICT, IN_RING_IDEAL_SUB_SYM, RING_POW_ADD_SQUARE_CONGRUENCE, IMAGE_HOMOMORPHISM_MUL, FIELD_OF_FRACTIONS_IMP_MONOMORPHISM, PID_ANNIHILATOR_ATTAINED, UFD_DIVISOR_PRIME_POW_SUC. Library/fieldtheory.ml: generated subfields (SUBFIELD_GENERATED_SUBSET_EQ, FIELD_EXTENSION_SUBFIELD_GENERATED_SUBSET, SUBFIELD_GENERATED_ROOT_OF_UNITY, SUBFIELD_GENERATED_ROOT_OF_UNITY_EQ, SUBFIELD_GENERATED_SING_ALGEBRAIC, RING_SUM_SUBFIELD_GENERATED), degrees (EXTENSION_DEGREE_SUBFIELD_TOWER, EXTENSION_DEGREE_LE_SPANNING, FINITE_EXTENSION_SIMPLE_EQ), spans and setwise products (RING_SPAN_MINIMAL, RING_SPAN_EQ_SELF, RING_SPAN_SETMUL_SPAN, RING_SPAN_SETMUL_ASSOC, RING_SPAN_SETMUL_SYM, RING_SETMUL_SING_LEFT, RING_SETMUL_IMAGE_MUL, RING_SPAN_IMAGE_MUL, RING_SPAN_SETMUL_IMAGE_MUL, RING_SPAN_SING_IMAGE, RING_SPAN_IMAGE_IDEAL_GENERATED), modules over a Noetherian ring (NOETHERIAN_RING_SPAN_SUBMODULE, NOETHERIAN_RING_FINITE_ALGEBRA), the cyclic vector theorem (POLY_ITER_MODULE, CYCLIC_VECTOR_EXISTS), and the common roots of the images of an ideal of r[X] in an algebraically closed field (RING_IDEAL_POLY_COMMON_ROOT). Library/ring_det.ml: linear systems over any ring with a unit determinant (RING_MATRIX_SOLVE), the Cramer rule through cofactors (RING_DET_CRAMER, RING_DET_CRAMER_SUBRING, RING_COFACTOR_SUBRING), the minors of a matrix whose rows sum to zero (RING_DET_ROW_NEG_SUM, RING_DET_ROWS_SAME_IMAGE, RING_DET_ROWS_OMIT), diagonal dominance (RING_DET_REAL_DIAGONALLY_DOMINANT, the Levy-Desplanques theorem), traces and discriminants of free bases (ALGEBRA_TRACE_FREE_BASIS_MATRIX, BASIS_DISCRIMINANT_MUL, ALGEBRA_TRACE_DUAL_BASIS_EXISTS, FREE_BASIS_SCALE), RING_DET_DIAGONAL_CONGRUENCE, RING_SUM_PRODUCT_INDEX, RING_SUM_NUMSEG_DIV_SLICE, ADD_MULT_LT_MULT. Library/galois.ml: a subfield that is a union of finite Galois subextensions is Galois (GALOIS_EXTENSION_UNION_FINITE_GALOIS_SUBFIELDS), Artin for groups of automorphisms with finite orbits (GALOIS_EXTENSION_FIXED_FIELD_FINITE_ORBITS), GALOIS_CYCLIC_INTERMEDIATE_UNIQUE, GALOIS_EXTENSION_GENERATED_CONJUGATES, GALOIS_GROUP_POW_ROOT, GALOIS_PRIMITIVE_ELEMENT_DERIVATIVE. Library/grouptheory.ml: cyclic subgroups, their torsion subgroups and conjugates (CYCLIC_SUBGROUP_TORSION_SUBGROUP, CYCLIC_SUBGROUP_GENERATED_EQ, CYCLIC_SUBGROUP_CONJUGATE, GROUP_CONJUGATION_SUBGROUP_GENERATED_SING, CARD_RESTRICT_POW_EQ_ID, CARD_CONJUGATES_IN_TORSION, CARD_CONJUGATES_IN_TORSION_NSUM, CARD_CONJUGATES_IN_ORDER, CARD_CONJUGATES_INTO_CYCLIC, CARD_CONJUGATES_INTO_CYCLIC_GENERATORS, CARD_CYCLIC_SUBGROUP_DIVISION), CARD_IMAGE_SUBGROUP_KERNEL, FINITELY_GENERATED_ABELIAN_GROUP_POW, NORMAL_PGROUP_SUBSET_COPRIME_INDEX, SUBGROUP_COMPLEMENT_RIGHT_COSETS. Library/ring_groups.ml: positive real multiplicative functions on groups (GROUP_REAL_MULTIPLICATIVE_ID_INV_POW, GROUP_REAL_MULTIPLICATIVE_ZPOW, GROUP_REAL_MULTIPLICATIVE_SUM), FINITELY_GENERATED_UNIT_GROUP, CARD_UNITS_PROD_RING, ISOMORPHIC_RING_CARD_UNITS, RING_ISOMORPHISM_IMAGE_UNITS, UNIT_GROUP_ZPOW_RING_NEG. Library/isum.ml: ISUM_DELTA_GEN, HAS_SIZE_INT_ABS_LE. Library/products.ml: IPRODUCT_ABS_BOUND, PRODUCT_LT_1, PRODUCT_FACTOR_BOUND. Library/prime.ml: INDEX_NPRODUCT. Library/pocklington.ml: the integer forms of squarefree (INT_SQUAREFREE_DIVPOW, INT_SQUAREFREE_MUL_SQUARE, INT_SQUAREFREE_DECOMPOSITION). Library/multiplicative.ml: MULTIPLICATIVE_LCM_GCD, PHI_LCM_GCD. Library/primitive.ml: INT_QUADRATIC_RESIDUE_MODULO_POWER_2. Library/jacobi.ml: JACOBI_SUM_RESIDUES. Library/modmul_group.ml: MODMUL_GROUP_CONG_EQ. Library/floor.ml: REAL_NUM_FRACTION_BETWEEN, REAL_NUM_FRACTIONS_EQ. Multivariate/transcendentals.ml: REAL_EXP_LE_INV_1_SUB, REAL_INV_1_SUB_LE_EXP, LOG_ZPOW, REAL_ZPOW_RPOW, RPOW_ADD_LE, CX_RPOW, CPOW_NUM_EXP, CPOW_NPRODUCT, LIM_CPRODUCT, CPRODUCT_VSUM_POW. Multivariate/realanalysis.ml: REAL_SERIES_FINITE_SUM, REAL_SUMMABLE_POS_PARTIAL_BOUND, DIRICHLET_SERIES_FINITE_PERTURBATION, REAL_POW_EVENTUALLY_LT, RPOW_TELESCOPE_BOUNDS, REAL_INFSUM_ZETA_BOUNDS (1 / (s - 1) <= zeta(s) <= s / (s - 1)), TRIVIAL_LIMIT_ATREAL_RIGHT. Added topological and profinite groups in the new file Multivariate/profinite_groups.ml (new definitions topological_group and profinite_group), and infinite Galois theory in Multivariate/infinite_galois.ml: with the Krull topology, taken as the pointwise topology on the automorphisms, the Galois group of a Galois extension is profinite (PROFINITE_GROUP_GALOIS_GROUP), and intermediate fields correspond to closed subgroups (INFINITE_GALOIS_CORRESPONDENCE, INFINITE_GALOIS_CORRESPONDENCE_INDEX, INFINITE_GALOIS_CORRESPONDENCE_NORMAL); also ARTIN_FIXED_FIELD_FINITE_ORBITS (the Galois group of l over the fixed field of a group with finite orbits is its closure), and Galois groups as inverse limits of their finite quotients. Added the normal basis theorem for finite Galois extensions over any field (NORMAL_BASIS_THEOREM, with NORMAL_BASIS_RING_BASIS, NORMAL_BASIS_FREE_BASIS, FINITE_FIELD_NORMAL_BASIS and the determinant criterion NORMAL_BASIS_DETERMINANT) in the new file Library/normal_basis.ml. Fri 6th Nov 2026 Multivariate/complex_algebra.ml [new file], Multivariate/complex_ring.ml [new file], Multivariate/complex_field.ml [new file], Multivariate/complexes.ml, 100/transcendence.ml, 100/unsolvability.ml Split Multivariate/complexes.ml: the algebra of the complex numbers (about 2000 lines, all but 12 theorems) is now in the new file Multivariate/complex_algebra.ml, which needs only Multivariate/vectors.ml. complexes.ml loads it and keeps the results on orthogonal transformations, segments, convexity and the interior of the reals, and COMPLEX_POLYFUN_EXTREMAL, so that every file loading complexes.ml sees the same theorems as before. COMPLEX_POLYFUN_ROOTBOUND has a new algebraic proof, so that it and COMPLEX_POLYFUN_FINITE_ROOTS, COMPLEX_POLYFUN_EQ_0 and COMPLEX_POLYFUN_EQ_CONST are in the light file. The new file Multivariate/complex_ring.ml defines complex_ring, the complex numbers as a ring, and proves its basic properties (COMPLEX_RING_CLAUSES, FIELD_COMPLEX_RING, INTEGRAL_DOMAIN_COMPLEX_RING, RING_CHAR_COMPLEX_RING, COMPLEX_RING_OF_NUM, COMPLEX_RING_OF_INT, COMPLEX_RING_SUB, COMPLEX_RING_INV, COMPLEX_RING_DIV, COMPLEX_RING_POW, COMPLEX_RING_SUM, COMPLEX_RING_PRODUCT, POLY_EVAL_COMPLEX_RING, and complex conjugation as a ring automorphism, RING_HOMOMORPHISM_CNJ and RING_AUTOMORPHISM_CNJ); it needs only Library/ringtheory.ml and complex_algebra.ml. The new file Multivariate/complex_field.ml proves that complex_ring is algebraically closed (ALGEBRAICALLY_CLOSED_FIELD_COMPLEX_RING, from the fundamental theorem of algebra of Multivariate/cauchy.ml). 100/transcendence.ml, 100/unsolvability.ml and ANT share these files. In 100/transcendence.ml the lemmas complex_ring_clauses, field_complex, integral_domain_complex, ring_pow_complex, ring_sub_complex, ring_div_complex, ring_char_complex and ring_inv_complex are replaced by COMPLEX_RING_CLAUSES, FIELD_COMPLEX_RING, INTEGRAL_DOMAIN_COMPLEX_RING, COMPLEX_RING_POW, COMPLEX_RING_SUB, COMPLEX_RING_DIV, RING_CHAR_COMPLEX_RING and COMPLEX_RING_INV, with the same statements, vsum_ring_sum_complex and cproduct_ring_product_complex by COMPLEX_RING_SUM and COMPLEX_RING_PRODUCT (the same equations reversed), the abbreviations complex_of_num and complex_of_int by Cx(&n) and Cx(real_of_int n), and ring_of_num_complex and ring_of_int_complex by COMPLEX_RING_OF_NUM and COMPLEX_RING_OF_INT; the 35 statements that mentioned the abbreviations, including the definitions of ZinC and QinC, are the old ones with the abbreviations expanded. In 100/unsolvability.ml COMPLEX_RING_CHAR is replaced by RING_CHAR_COMPLEX_RING, RING_AUTOMORPHISM_CNJ has moved to complex_ring.ml and ALGEBRAICALLY_CLOSED_FIELD_COMPLEX_RING to complex_field.ml. Thu 5th Nov 2026 Sieve/* [new directory], holtest.mk Added a directory of sieve methods and their applications to the primes, leading to Chen's theorem in both of its forms, CHEN and CHEN_TWIN_INFINITE: every large even number is a prime plus a P2 (a prime or a product of two primes), and there are infinitely many primes p with p + 2 a P2: |- ?N0. !N. EVEN N /\ N0 <= N ==> ?p q. prime p /\ almost_prime 2 q /\ p + q = N |- INFINITE {p | prime p /\ almost_prime 2 (p + 2)} with the lower bounds CHEN_GOLDBACH, CHEN_TWIN and CHEN_SHIFT (any positive even shift). The sieve framework is Rosser's beta-sieve with the Jurkat-Richert theorem for the linear sieve (JURKAT_RICHERT), with Selberg's and Brun's sieves and Chen's weighted sieve. The analytic input is proved on top of 100/pnt.ml and 100/dirichlet.ml: primitive characters and L-functions, Siegel's theorem, a zero-free region, a smoothed Perron formula, Vaughan's identity, the large sieve, SIEGEL_WALFISZ and BOMBIERI_VINOGRADOV. The other main theorems are BRUN, PNT_AP, BRUN_TITCHMARSH, ERDOS_PRIME_PLUS_POW2, ROMANOV, TITCHMARSH_DIVISOR, HARDY_RAMANUJAN MAYNARD_TAO, BOUNDED_GAPS (bounded gaps between primes) VINOGRADOV (three primes), GOLDBACH_ALMOST_ALL WARING_HARDY_LITTLEWOOD (G(k) <= 2^k + 1), HILBERT_WARING LINNIK_NONRESIDUE, BARBAN_DAVENPORT_HALBERSTAM, HUA_FIVE_PRIME_SQUARES, SQUARE_PLUS_ONE_P4, SQUARE_PLUS_ONE_P3 VAN_DER_CORPUT (three-term progressions of primes) GREEN_TAO, GREEN_TAO_COUNT, GREEN_TAO_DENSE, GREEN_TAO_DENSE_COUNT the last ones by the Green-Tao majorant, the transference with the dense model theorem and the relative Szemeredi theorem (RELATIVE_SZEMEREDI), and WEIGHTED_SZEMEREDI from Library/szemeredi.ml. Sieve/make.ml loads everything (Sieve/base.ml first: Multivariate/cauchy.ml, Library/multiplicative.ml, 100/pnt.ml, 100/dirichlet.ml, Examples/schnirelmann.ml and Library/szemeredi.ml); Sieve/README.md describes the results, the files and the sources. Each development file sets the parse priorities it was written with (complex, then real, then num) after its needs lines. Most topic-specific constants have prefixes (sieve_, rosser_, selberg_, chen_, maynard_, col_, bv_, waring_, hua_, goldbach_, lf_, zn_, ...). holtest.mk now tests Sieve/make.ml. Thu 5th Nov 2026 Library/szemeredi.ml [new file] Added Szemeredi's theorem and related results of Ramsey theory, all derived from the combinatorics of words. The words of length n over {0,...,k-1} are the functions num->num that are 0 from n on, and hj_cube k n is the set of them; m-variable words (hj_subspace) describe m-dimensional subspaces through the substitution hj_subst, combinatorial lines are the 1-variable words (hj_line, hj_line_point, hj_has_line) and hj_density is the density of a set of words. The main theorems are HALES_JEWETT, HALES_JEWETT_FINITE, MULTIDIM_HALES_JEWETT FOLKMAN, GRAHAM_ROTHSCHILD_LINES DENSITY_HALES_JEWETT, MULTIDIM_DENSITY_HALES_JEWETT WEIGHTED_SZEMEREDI (progressions mod a large prime) SZEMEREDI_COUNT (Varnavides), SZEMEREDI, ROTH, SZEMEREDI_DENSITY VAN_DER_WAERDEN, MULTIDIM_SZEMEREDI, GALLAI_WITT, CORNERS for example |- !k delta. &0 < delta ==> ?N0. !N A. N0 <= N /\ A SUBSET 1..N /\ delta * &N <= &(CARD A) ==> ?a d. 0 < d /\ !j. j < k ==> a + j * d IN A Hales-Jewett is proved by colour focusing, and density Hales-Jewett by the density increment argument of Dodos, Kanellopoulos and Tyros ("A simple proof of the density Hales-Jewett theorem", IMRN 2014) with Graham-Rothschild for lines as the Ramsey input. Szemeredi's theorem in Z_N follows from the lines of [k]^n along progressions mod N, and in 1..N by working modulo a prime in (2N,4N]; the multidimensional version and the corners theorem also come from density Hales-Jewett. The file needs Library/prime.ml, Library/products.ml and 100/bertrand.ml. New definitions: density_hales_jewett fmean hales_jewett_template hj_concat hj_cube hj_density hj_dlift hj_drop hj_first_wildcard hj_has_line hj_identity hj_insensitive hj_insert hj_join hj_lift hj_line hj_line_point hj_replace hj_subspace hj_subst hj_take hj_tiling hj_tiling_union hj_wildcards hj_wlift hjt_almost_mono hjt_focused hjt_lift hjt_line hjt_mono hjt_prod hjt_subst weighted_szemeredi Thu 5th Nov 2026 100/bertrand.ml, 100/primerecip.ml, holtest.mk Replaced the proofs of Bertrand's postulate and of the divergence of the series of reciprocals of the primes by elementary ones that need neither Multivariate nor Library/analysis.ml and Library/transc.ml. In 100/bertrand.ml the proof is Erdos's, in natural numbers, using central binomial coefficients and Legendre's formula INDEX_FACT_ALT, with the cases n < 8192 done by a chain of primes checked by trial division; the file now needs only Library/prime.ml, Library/binomial.ml and Library/products.ml, so unlike the old one it does not load Library/pocklington.ml and the others, and it leaves num rather than real as the number priority. BERTRAND is strengthened (previously it had n <= p) to |- !n. ~(n = 0) ==> ?p. prime p /\ n < p /\ p <= 2 * n Everything else in the old file has been removed, notably the definitions ISQRT, primepow, aprimedivisor, mangoldt, psi, theta and pii and the results about them such as BIG_BERTRAND, LANDAU_TRICK, PII_LBOUND and PII_UBOUND_5, so 100/bertrand.ml no longer clashes with Examples/mangoldt.ml. In 100/primerecip.ml the proof is Erdos's counting argument, and the file now needs only Library/prime.ml and Library/products.ml. PRIMERECIP_DIVERGES and PRIMERECIP_DIVERGES_NUMSEG keep their names but state the divergence directly, as HARMONIC_DIVERGES does in 100/divharmonic.ml, instead of with "convergent" from Library/analysis.ml: |- ~(?s. !e. &0 < e ==> ?N. !n. N <= n ==> abs(sum {p | prime p /\ p <= n} (\p. &1 / &p) - s) < e) They come with PRIMERECIP_BLOCK, the lower bound 1/2 for the sum of 1/p over the primes in (m,4^(m+1)], and PRIMERECIP_UNBOUNDED. The old INDUCTION_FROM_1, SUM_CONV, PRIMERECIP_HARMONIC_LBOUND, PRIMERECIP_LBOUND and UNBOUNDED_DIVERGENT have been removed. No other file in the distribution used any of the removed material. holtest.mk now tests the two files separately, and also tests Library/szemeredi.ml. Tue 27th Oct 2026 100/unsolvability.ml [new file] Proved the unsolvability of the quintic by radicals, number 16 of the 100 theorems. radical_number is the inductively generated set of complex numbers obtained from 0 and 1 by field operations and extraction of roots of positive degree. NOT_RADICAL_QUINTIC_ROOT proves |- ~(?z. radical_number z /\ z pow 5 - Cx(&4) * z + Cx(&2) = Cx(&0)) The polynomial is irreducible by Eisenstein's criterion and has exactly three real roots, so conjugation swaps its two non-real roots. The general Galois-theoretic transposition criterion then excludes every radical root. NOT_RADICAL_ROOT_REAL_FIELD gives the corresponding result for any irreducible polynomial over a real subfield, of prime degree at least 5, with exactly two non-real roots. The file uses the same definition of complex_ring as 100/transcendence.ml, so the two can be loaded together. Tue 27th Oct 2026 Library/finite_fields.ml [new file], Library/rabin_test.ml [deleted] Added primitive roots and cyclic unit groups (FINITE_FIELD_PRIMITIVE_ROOT), subfields and homomorphisms, norm and trace surjectivity and fibre sizes, Hilbert 90 (HILBERT_90_FINITE_FIELD), Frobenius conjugates of irreducible roots, the factorization of X^(q^n) - X (X_POW_SUB_X_FINITE_FIELD), counts and existence of irreducible polynomials of each positive degree (FINITE_FIELD_IRREDUCIBLE_EXISTS), and finite layers of algebraic closures and normal extensions. The Galois group of a normal extension of a finite field is abelian. Rabin's irreducibility test (RABIN_IRREDUCIBILITY_TEST), formerly in Library/rabin_test.ml, is now in finite_fields.ml, with its statements unchanged apart from bound-variable names, and the former file has been deleted. FINITE_FIELD_ELEMENT_POW, FINITE_FIELD_POW_ITERATE and FINITE_FIELD_CARD_CHAR_POWER move here and RING_ENDOMORPHISM_FROBENIUS_ITERATE to ringtheory.ml, with the same statements up to bound-variable names. The other auxiliary lemmas of the former file have been removed, the library now having more general versions; no other file in the distribution used them. The removed names are RING_DIVIDES_POW_ITERATE, POLY_NONUNIT_DEGREE_GE_1, RING_DIVIDES_REDUCE, FIELD_NONZERO_PRODUCT_PERMUTE, QUOTIENT_POLY_RING_FINITE_CARD, IRREDUCIBLE_DIVIDES_XQ_MINUS_X_GEN, IRREDUCIBLE_DIVIDES_XQ_MINUS_X, FIELD_ROOTS_BOUND, IRREDUCIBLE_DIVIDES_DEGREE_BOUND and IRREDUCIBLE_DIVIDES_DEGREE. Tue 27th Oct 2026 Library/galois.ml [new file], Library/cyclotomic.ml [new file], Library/primitive.ml Added Galois groups, Galois extensions and fixed fields, Artin's fixed-field theorem (ARTIN_FIXED_FIELD), the fundamental theorem for finite Galois extensions (FUNDAMENTAL_THEOREM_OF_GALOIS_THEORY), normal subgroups and quotients, conjugation and composita, and natural irrationalities. Added Galois groups of polynomials, including prime-degree transposition, discriminant and cubic criteria; Galois groups of finite fields; Hilbert 90 (HILBERT_90); Kummer and Artin-Schreier extensions; radical extensions and elements; and the equivalence in characteristic zero between solvability by radicals and solvability of the Galois group (SOLVABLE_BY_RADICALS_EQ, GALOIS_SOLVABLE_EQ_RADICAL), with the criterion PRIME_TRANSPOSITION_NO_RADICAL_ROOT for particular polynomials. Material for infinite Galois theory includes restriction maps and the directed family of finite Galois subextensions covering a Galois extension. New definitions: finite_galois_subfields fixed_field galois_extension galois_group radical_element radical_extension The separate cyclotomic.ml embeds the Galois group of k(z), for z of finite positive order n, in the units modulo n, and characterizes when it is the whole group by [k(z):k] = phi(n). It loads modmul_group.ml. Also made primitive.ml explicitly restore its required overload ordering. Tue 27th Oct 2026 Library/fieldtheory.ml, 100/transcendence.ml Extended the field theory library, with extensions given by arbitrary homomorphisms rather than only inclusions, to cover extension degrees, minimal polynomials, perfect fields, splitting extensions with their existence and uniqueness (SPLITTING_EXTENSION_EXISTS, SPLITTING_EXTENSION_UNIQUE), normal and separable extensions, separable closures and purely inseparable extensions, separable and inseparable degrees (EXTENSION_DEGREE_SEPARABLE_INSEPARABLE), extensions and independence of homomorphisms, normal closures and the primitive element theorem (PRIMITIVE_ELEMENT_THEOREM). The degree of an infinite extension is 0, so the tower law EXTENSION_DEGREE_TOWER_LAW needs no finiteness hypothesis. Also added trace and norm of finite extensions, with formulas in terms of minimal polynomials and embeddings (ALGEBRA_TRACE_NORM_EMBEDDINGS) and tower laws, and the existence and uniqueness of finite fields of each prime power order (FINITE_FIELD_EXISTS, ISOMORPHIC_FINITE_FIELDS). fieldtheory.ml now loads Library/ring_det.ml, where the trace and norm are defined. New definitions: extension_degree inseparable_degree minimal_polynomial normal_extension perfect_field poly_splits_over purely_inseparable_extension ring_homomorphism_extensions separable_closure separable_degree separable_element separable_extension splitting_extension Added span and basis lemmas, including free bases of simple algebraic extensions. Over a field, a finite projective basis exists exactly when a finite free basis does. Further root and separability results include that over a field X^n - c is separable for nonzero c when the characteristic does not divide n. FIELD_EXTENSION_INTO_SUBFIELD_GENERATED and RING_SPAN_EMPTY lose redundant hypotheses; FIELD_EXTENSION_FROM_SUBRING_GENERATED now quantifies s; and ALGEBRAICALLY_CLOSED_FIELD_DECOMPOSE has one combined antecedent. The proof of FINITELY_GENERATED_EXTENSION_TRANS_EQ is adapted to the first of these. In 100/transcendence.ml, replaced the local minimal_polynomial constant by minimal_polynomial (QinC_ring,complex_ring) I z from the general library. MINIMAL_POLYNOMIAL_QINC_COMPLEX recovers the old characterization, and the six theorems that mentioned the old constant now use the general one. Added the field-extension, evaluation and algebraicity bridges, adjusted the imports, and adapted the polynomial separability proofs. Tue 27th Oct 2026 Library/ring_det.ml [new file] Added determinants of square arrays over any commutative ring, indexed by any finite set, with the standard determinant, cofactor, adjugate, multilinearity and multiplicativity (RING_DET_MUL) properties, reindexing, triangular and block arrays, Kronecker and Vandermonde formulas, Ryser's formula for the permanent, the Weinstein-Aronszajn identity and characteristic polynomials. Defined finite free and projective bases and the canonical trace and norm of an algebra admitting a finite projective basis, with defaults 0 and 1 when there is none. In a free basis these are the trace and determinant of the multiplication matrix; in a projective basis the norm is det(A + I - E), where A represents multiplication and E the identity. Proved independence of the basis, the basic algebraic, unit, base-change, tower, product and discriminant properties, and Cayley-Hamilton for the multiplication matrix (MUL_MATRIX_CHARPOLY_ROOT). Added polynomial resultants and discriminants and their root formulas. Over a field, excluding a pair of zero polynomials, the resultant vanishes exactly when there is a nonconstant common factor (POLY_RESULTANT_EQ_0). For a polynomial of positive degree, the discriminant vanishes exactly when it is not separable (POLY_DISCRIMINANT_EQ_0). The file does not change the number priority. New definitions: algebra_norm algebra_trace basis_coordinates basis_discriminant free_basis mul_matrix poly_discriminant poly_resultant projective_basis ring_charpoly ring_cofactor ring_det ring_sign Tue 27th Oct 2026 Library/ring_groups.ml [new file] Added a new file with the additive group and the unit group of a ring, their induced homomorphisms and behaviour under subrings and products, including restricted products (as for adeles and ideles), and Dedekind's independence of characters for homomorphisms into the units of an integral domain (GROUP_HOMOMORPHISMS_UNITS_INDEPENDENT). New definitions: ring_additive_group unit_group Tue 27th Oct 2026 Library/grouptheory.ml Added the second and third isomorphism theorems (SECOND_GROUP_ISOMORPHISM_THEOREM, THIRD_GROUP_ISOMORPHISM_THEOREM) and explicit forms of all three, coset and quotient-group lemmas, inverse limits and restricted products, and Iwasawa's simplicity criterion (IWASAWA_SIMPLE): the quotient by the kernel of the action has no normal subgroups other than the trivial one and itself. The inverse-limit construction does not require a directed index relation. Also added normal-subgroup results for groups of orders 6 and 12, and further abelian-group, homomorphism and exact-sequence lemmas. New definitions: group_cosets inverse_limit_group restricted_product_group Tue 27th Oct 2026 Library/ringtheory.ml Added commutative algebra concerning radicals, the Jacobson radical and minimal prime ideals (RADICAL_EQ_INTERS_MINIMAL_PRIMES), localization maps and iterated localizations, fields of fractions with the universal map into fields (FRACTION_FIELD_MAP, FRACTION_FIELD_MAP_ISOMORPHISM), residue fields (FIELD_RESIDUE_FIELD), prime ideals of finite products, and restricted products of rings, together with associated homomorphism, quotient, divisibility and polynomial lemmas. The conversion RING_HOMOMORPHISM_PUSH_CONV moves a homomorphism through ring operations, leaving the carrier conditions on the atoms as hypotheses. New definitions: field_of_fractions fraction_field_map jacobson_radical localization_map minimal_prime_ideal minimal_prime_over residue_field residue_hom restricted_product_ring Tue 27th Oct 2026 Multivariate/metric.ml, Multivariate/topology.ml, Multivariate/canal.ml, Multivariate/determinants.ml, Multivariate/measure.ml Added quotient topologies and their universal property, the topology of pointwise convergence with discrete codomain, irreducible sets and sober spaces, and further results about continuous maps, discrete and product spaces, and locally compact Hausdorff spaces. Added continuity of the norm and complex inverse, and second countability and local compactness of Euclidean space. Moved INDUCT_MATRIX_ROW_OPERATIONS, INDUCT_MATRIX_ELEMENTARY and INDUCT_MATRIX_ELEMENTARY_ALT unchanged from measure.ml to determinants.ml, where they need no measure theory. New definitions: irreducible_in pointwise_topology quotient_topology sober_space Tue 27th Oct 2026 Library/permutations.ml, Library/transc.ml, Multivariate/cvectors.ml, Multivariate/flyspeck.ml, Permutation/permutation.ml, 4CT/kempe.ml Renamed bindings that hid unrelated theorems or tactics in other files: REAL_ABS_SIGN in permutations.ml is now REAL_ABS_SIGN_PERMUTATION; FINITE_INDEX_INRANGE_2 in cvectors.ml is FINITE_INDEX_INRANGE_4; DIVISION_0 and SUM_DIFFS in transc.ml are DIVISION_0_DSIZE and PSUM_DIFFS; NORM_CROSS in flyspeck.ml is NORM_CROSS_SIN; the definition theorem for PERMUTATION in Permutation/permutation.ml is PERMUTATION_DEF; and the three-argument LIST_CASES_TAC in kempe.ml is X_LIST_CASES_TAC. Updated their uses. The mathematical constants and statements are unchanged. Tue 27th Oct 2026 Multivariate/*, Library/jacobi.ml, Library/calc_real.ml, Permutation/morelist.ml Made several analysis and number-theory files explicitly restore the number priorities their proofs require, so that they load the same way after files that leave a different priority. prioritize_complex() now first calls prioritize_real(), giving real priority to overloaded operations without a complex counterpart. Added num annotations to three NUMBER_RULE quotations in jacobi.ml. ASSERT_TAC in Permutation/morelist.ml now uses STRIP_ASSUME_TAC, matching Multivariate/misc.ml. Also made canal.ml explicitly load measure.ml, whose measurability results it uses. Mon 26th Oct 2026 int.ml, iterate.ml, lists.ml, sets.ml, Library/iter.ml, Library/wo.ml Added integer-power monotonicity, list snoc decomposition, commuting-square and fibre-bijection lemmas, bounds on weakly increasing chains of sets, upward-closed number segments, digit-expansion bounds and uniqueness, ITER_INTERTWINE_INVARIANT, and a dual form of Zorn's lemma using intersections of nonempty chains (ZL_SUBSETS_INTERS_NONEMPTY). No existing theorem is changed. Sun 25th Oct 2026 Library/card.ml, Library/fieldtheory.ml Added number-type annotations in CARD_EQ_REAL and FINITELY_GENERATED_EXTENSION_TRANS_EQ to make their proofs independent of the incoming number priority. No statement changes. Sat 24th Oct 2026 Library/ringtheory.ml, Autoformalization/puiseux.ml Added polynomial splitting and separability, further degree, root, derivative and factorization results, Frobenius maps, finite-ring polynomial counts, and multiplicative-order and roots-of-unity results. Generalized RING_MUL_LCANCEL and RING_MUL_RCANCEL from units to regular elements; generalized POLY_DEG_CMUL and POLY_DEG_MUL_X_MINUS_A with conditional conclusions; restated POLY_DEG_VAR_POW and POLY_DERIV_VAR_POW using polynomial operations; quantified the previously free variable of POLY_CONST_SUBRING_GENERATED; and restated the separability theorems with poly_separable. Adapted the use of POLY_DEG_CMUL in puiseux.ml. New definitions: poly_separable poly_splits Sat 24th Oct 2026 Library/matroids.ml, Library/card.ml, Library/permutations.ml, Library/grouptheory.ml, Library/symmetric_group.ml, Examples/digit_serial_methods.ml Added matroid basis and dimension bounds, equal-fibre cardinalities, permutation and restriction lemmas, solvable-group chains with cyclic and prime-order quotients, exponent coordinates for finitely generated abelian groups, and TRANSITIVE_TRANSPOSITION_SYMMETRIC_ISOMORPHISM: a monomorphism into the symmetric group of a set of prime size whose image is transitive and contains a transposition is an isomorphism. Renamed bound variables sigma and tau in symmetric_group.ml and digit_serial_methods.ml so that they can be loaded after multiplicative.ml defines constants of those names. Only bound-variable names change in those existing statements. Mon 19th Oct 2026 4CT/* [new directory], eval_compile/* [new directory], Autoformalization/planar_graph.ml, Multivariate/metric.ml Added a formal proof of the Four Colour Theorem, autoformalized by Claude. It is almost entirely a port of Georges Gonthier's Coq proof, following its theory files closely: hypermaps and their geometry, colourings, the Jordan and Kempe chain arguments, the reducibility of the 633 configurations of Robertson, Sanders, Seymour and Thomas, and unavoidability by discharging. The main exception is the passage to the plane at the end, which goes via the planar graphs of Autoformalization/planar_graph.ml instead of Gonthier's discretization of the plane. The main theorems are FOUR_COLOR for hypermaps (Gonthier's four_color_hypermap), FOUR_COLOR_PLANAR_GRAPH for finite simple planar graphs, and perhaps most satisfyingly of all FOUR_COLOR_MAP for maps in the plane: any set of pairwise disjoint open connected subsets of real^2, finite or not, can be coloured with four colours so that regions sharing a border point lying in the closure of no third region get different colours. Georges Gonthier "Formal Proof - The Four-Color Theorem" Notices of the AMS 55 (2008) https://github.com/rocq-community/fourcolor As in Gonthier's proof, the reducibility checks and the case analysis for unavoidability are carried out by computation, but here entirely inside the logic by proof-producing evaluation, every step a kernel inference. Loading 4CT/make.ml does everything, and takes around 10 hours natively on one core. With OCaml 5, 4CT/make_parallel.ml runs the computations in parallel within one HOL Light process (about 22 minutes on 128 cores), and "make native-hypermap" in 4CT builds just the hypermap theorem, without Multivariate. The reducibility evaluator is generated by eval_compile, Alexey Solovyev's compiler of equational theorems into OCaml code, now included in its own directory eval_compile/ so that it can be used elsewhere too. It is the core of his compute-hol-light, https://github.com/hol-light-family/compute-hol-light changed only in the load paths, a small OCaml version detail and the layout, as recorded in eval_compile/README.md. Also renamed a variable in a proof in each of Multivariate/metric.ml and Autoformalization/planar_graph.ml (`cube` and `edge`), so that they can be loaded after the 4CT files, which define constants of those names. Mon 19th Oct 2026 mcp/ Removed the mcp subdirectory, now moved to a separate repo in the HOL Light family collection here: https://github.com/hol-light-family/hol-light-mcp Mon 19th Oct 2026 holtest_parallel, holtest.mk Added some fixes from June Lee to the holtest machinery, notably fixing an incorrect pathname to Examples/apery which had not been flagged. Sat 17th Oct 2026 Autoformalization/godel_notac.ml [new file], Autoformalization/godel_completeness.ml Added an autoformalized proof of the independence of the axiom of choice from ZF set theory, again produced by Claude, complementing the files of 14th October. The new file godel_notac.ml shows that from an arbitrary model of ZF, again with no assumption that it is well-founded, countable or satisfies choice, one obtains a model of ZF + not AC over the same type (ZF_MODEL_NOT_AC_MODEL); with ZF_MODEL_AC_MODEL from godel_gch.ml this gives the relative consistency of both AC and its negation. It is loaded after godel_forcing.ml, and godel_completeness.ml now loads it in turn and deduces the syntactic form: if ZF is consistent then ZF proves neither AC nor its negation (CON_ZF_IMP_INDEPENDENT_AC, from CON_ZF_IMP_CON_ZFC and CON_ZF_IMP_CON_ZF_NOT_AC). The model is a symmetric submodel of a Cohen extension, again built in Boolean-valued form over L. In a model of ZF + V=L, take the regular-open algebra of the poset of finite partial functions from w1 x omega to 2, where w1 is aleph_1. Permutations of w1 act on conditions, on the algebra (as complete Boolean algebra automorphisms) and on names, compatibly with Boolean values. A name is symmetric if for some countable subset e of w1 it is fixed by every permutation fixing e pointwise, and hereditarily symmetric (HS) if all names hereditarily below it are too. With quantifiers restricted to HS names every axiom of ZF has value top, and the quotient of the HS names by any ultrafilter in the model is a model of ZF by an HS version of Los's theorem (HS_QUOT_MODEL_ZF). Countable rather than the usual finite supports are used because this rests on a maximum principle for HS names, obtained by mixing over an antichain, which is countable as the algebra is ccc, and the mixture is symmetric only if countably many supports can be combined into one. In the quotient, a family of nonempty sets built from the Cohen reals has no choice function: any HS candidate has a countable support e, and a transposition of two indices outside e fixes the candidate and the family but moves the chosen element, so the Boolean value of its being a choice function is bottom (NCR_MAIN, HS_QUOT_NOT_AC). As before, no countable transitive models or generic filters are needed. Fri 16th Oct 2026 Makefile Changed "make switch" and "make switch-5" to pin camlp5 before installing ledit rather than after. Since ledit depends on camlp5, installing it first pulled in the latest camlp5 (8.05.02), so the pin then downgraded camlp5 and made OPAM rebuild ledit. With OPAM 2.6 that rebuild fails with "No rule to make target `all'": when a package with a "remove:" field, as ledit has, must be removed before it is rebuilt, as here, OPAM 2.6 moves the downloaded sources into a directory for the removal and then runs the build in an empty directory. OPAM 2.5 and earlier are not affected, but Homebrew now provides OPAM 2.6, so this showed up in the macOS CI of s2n-bignum. Now ledit is just built once, against the pinned camlp5. The pin and the install are also now joined by "&&", so that a failed pin is reported rather than leaving an unpinned camlp5, and "eval $(opam env)" is now "eval $$(opam env)", since make was expanding "$(opam env)" itself (to nothing). Wed 14th Oct 2026 Autoformalization/godel_gch.ml, Autoformalization/godel_forcing.ml, Autoformalization/godel_completeness.ml [new files] Added autoformalized proofs of the consistency (godel_gch.ml) and independence (godel_forcing.ml) of both the continuum hypothesis CH and the generalized continuum hypothesis GCH, together with the axiom of choice, relative to ZF set theory, again autoformalized by Claude. Starting from an arbitrary model of ZF, with no assumption that it is well-founded, countable or satisfies choice, we obtain models of ZFC + GCH (ZF_MODEL_GCH_MODEL, and ZF_MODEL_CH_MODEL for CH alone) and of ZFC + not CH (ZF_MODEL_NOT_CH_MODEL), which are a fortiori models of ZFC + not GCH (ZF_MODEL_NOT_GCH_MODEL). A third file, godel_completeness.ml, proves a completeness theorem for the object language and deduces the corresponding syntactic statements, e.g. that if ZF is consistent then ZFC proves neither CH nor its negation (CON_ZF_IMP_INDEPENDENT_CH, CON_ZF_IMP_INDEPENDENT_GCH). The object language is first-order set theory with membership as its only nonlogical symbol, interpreted in structures given by a domain D:A->bool and a membership relation E:A->A->bool over an arbitrary HOL type A. In godel_gch.ml, Godel's constructible universe L is built inside the model and shown to be a submodel satisfying ZF + V=L, and hence AC, using the canonical wellordering of L, and GCH, using a condensation argument with the Mostowski collapse of elementary hulls. In godel_forcing.ml, Cohen forcing is carried out in Boolean-valued form over L: in a model of ZF + V=L, the regular-open algebra of the poset of finite partial functions from aleph_2 x omega to 2 is a ccc complete Boolean algebra, all axioms of ZFC and the negation of CH have Boolean value top in the universe of names, and the quotient by an ultrafilter in the model is a two-valued model by Los's theorem, again over the type A. In godel_completeness.ml, a Hilbert-style proof system following Enderton is shown sound and complete by Henkin's method (since the language has no constants, the Henkin witnesses are variables chosen through a Godel numbering), so that a set of formulas is consistent, in the sense that the universal closures of its members do not derive False, exactly when it has a model, which may be taken countable. No countable transitive models or generic filters are needed anywhere. Tue 13th Oct 2026 Autoformalization/puiseux.ml [new file] Added an autoformalized proof of Puiseux's theorem, produced by Claude Opus 5.5: for an algebraically closed field k of characteristic zero, the field of Puiseux series over k is algebraically closed (ALGEBRAICALLY_CLOSED_PUISEUX_RING). It is constructed as the fraction field of the direct limit of the rings k[[t^(1/d)]], and contains k[[t]] and a d-th root of t for every d > 0 (PUISEUX_RING_ROOTS_OF_T); that it is algebraic over k((t)) is not formalized. The proof is the classical Newton-Puiseux argument: after a Tschirnhaus shift and a Newton-polygon rescaling, the reduction mod t of a monic polynomial over k[[t]] has coprime factors, Hensel's lemma lifts them, induction on the degree gives a root in some k[[t^(1/d)]], and a general criterion passes to the fraction field. Characteristic zero is essential: in characteristic p, X^p - X - 1/t has no Puiseux series root. Mon 12th Oct 2026 Autoformalization/carleson.ml, Autoformalization/carleson_hunt.ml [new file] Added the Carleson-Hunt generalization of the autoformalized Carleson theorem, and at the same time streamlined the existing carleson.ml. The new carleson_hunt.ml, produced by Claude Opus 5.5, extends carleson.ml from L^2 to L^p: for every p > 1, the Fourier series of a 2pi-periodic function in L^p[-pi,pi] converges to it almost everywhere (theorem CARLESON_HUNT_THEOREM_ALL_P). This is sharp on the L^p scale: Kolmogorov constructed an integrable function whose Fourier series diverges almost everywhere (1923), and later one whose Fourier series diverges everywhere (1926), though almost everywhere convergence does hold for some classes between L^1 and the L^p spaces, e.g. Antonov's L log L log log log L. The case p >= 2 follows directly from CARLESON_THEOREM, and the main part of the file is the case 1 < p < 2 (CARLESON_HUNT_THEOREM). This uses a density-capped estimate with logarithmic loss for the tile model of the Carleson operator, applied to functions dominated by an indicator, after Lacey-Thiele and Grafakos-Tao-Terwilleger, with the near part of the tree energy controlled by a dyadic Calderon-Zygmund decomposition. The estimate is transferred to the truncated Carleson operator by the averaging argument of Fremlin's sections 286P-286T, giving restricted weak type (q,q) for 1 < q <= 2 uniformly in the truncation, and then weak type (p,p) by a dyadic level decomposition; almost everywhere convergence follows by a Banach-principle argument in which the L^2 theorem is applied to clamped truncations of f. The carleson.ml file was also streamlined, without changing its main results: unused lemmas removed, duplicates of library or earlier lemmas merged, special cases replaced by general forms (some of which now take the plain names, and some with L^1 rather than L^2 hypotheses so that carleson_hunt.ml can use them directly), near-duplicate proofs factored through common helper lemmas and the longest proofs restructured, giving about 20% less proof text; two lemmas clashing with Probability/ names got a CARLESON_ prefix; comments left over from lemmas deleted in the original release were removed and damaged comment layout repaired. Load times are essentially unchanged. Tue 6th Oct 2026 preterm.ml Added a fix from Balaji Rao to generalize the special handling of bound variables sharing the names of existing constants (controlled via ignore_constant_varstruct) so that it works properly even in the presence of type annotations. Fri 2nd Oct 2026 Help/passim Made several fixes to the Help files reported by Chris Walton, uncovered during the creation of HolLean, a new project now available as https://github.com/hol-light-family/HolLean/. Sun 6th Sep 2026 Autoformalization/hilbert_waring.ml [new file], Autoformalization/planar_graph.ml [new file] Added two more fully autonomous formalizations. The hilbert_waring.ml formalization, produced by Claude Opus 4.8, proves Hilbert's solution of Waring's problem: for each positive exponent e there is a bound k(e) such that every natural number is a sum of k(e) e-th powers. The proof follows Linnik's elementary method as presented in Khinchin's "Three Pearls of Number Theory", chapter 3. It develops the difference-polynomial and fiber-counting induction behind Khinchin's fundamental lemma, obtains positive Schnirelmann density for a bounded sumset of e-th powers, and applies the existing Schnirelmann density-to-basis theorem. The planar_graph.ml formalization, produced by GPT-5.6-sol (xhigh), develops a general theory of finite simple planar graphs over an arbitrary vertex type, with edges represented as two-element sets and planarity defined using non-crossing arcs in the plane. It proves Fary's straight-line embedding theorem, equivalent recursive-triangulation and Euler-rotation characterizations of planarity, Euler's formula and the planar edge bound, Kuratowski's theorem in terms of K5 and K3,3 subdivisions, and Wagner's theorem in terms of the corresponding forbidden minors. It also supplies reusable results about graph minors, degrees and degeneracy, relabelling, components, closure operations and amalgamation. The proof of Fary's theorem follows the maximal-triangulation and recursive-disk approach in Jeff Erickson's "Planar Graphs" notes, itself following de Fraysseix, Pach and Pollack. The Kuratowski development uses rotation systems, Thomassen's contractible-edge theorem and separator induction. Tue 1st Sep 2026 Makefile, pa_j/chooser.sh, pa_j/pa_j_8.04.00.ml [renamed] Adopted a simplification and generalization of the pa_j selection for camlp5 contributed by Matthias Kannwischer. In fact the same file pa_j/pa_j_8.04.00.ml works for many OCaml versions including 5.5. Mon 31st Aug 2026 mcp/passim Adopted an update from Sanketh Menda with a more flexible version of the MCP server's "hol_restart", enhancing it from a bare kill/restart into a config-aware restart, so an agent editing an underlying source file can refresh its environment without dropping the session. Mon 31st Aug 2026 Library/records.ml Adopted an update from June Lee to make "define_record_type" idempotent, i.e. to allow "benign redefinition" as with other comparable definitional principles. Sun 16th Aug 2026 Multivariate/realanalysis.ml, Multivariate/lpspaces.ml, 100/fourier.ml, Autoformalization/fifteen_theorem.ml [new file], Autoformalization/carleson.ml [new file], Autoformalization/fourier_transform.ml [new file] Added two more substantial fully autonomous formalizations. The carleson.ml formalization, produced by Claude Opus 4.8, proves Carleson's theorem that the Fourier series of a square-integrable periodic function converges almost everywhere. The development follows Fremlin's presentation of the Lacey-Thiele time-frequency proof in "Measure Theory" volume 2 (sec 286), including the Hardy-Littlewood maximal estimates, tile and tree arguments, and the Carleson maximal inequality. Its supporting Fourier-transform library develops Fourier analysis on the real line, including inversion, Schwartz functions, Plancherel's theorem and the L2 transform, again following Fremlin's, "Measure Theory" volume 2, the earlier sections 283-285. A few small additions and tweaks are made to existing files as part of this formalization (e.g. adding the complex inner product to lpspaces.ml). The fifteen_theorem.ml formalization, produced by GPT-5.6-sol (xhigh), proves the Conway-Schneeberger Fifteen Theorem: a positive-definite integral quadratic form is universal exactly when it represents every positive integer up to 15. The proof follows Bhargava's treatment using truants, escalator lattices, the nine ternary escalators and a finite rank-four analysis, together with classical ternary-form results and checked finite computations. Sat 8th Aug 2026 Autoformalization/three_squares.ml [new file], Autoformalization/sarkovskii.ml [new file] Added a new subdirectory Autoformalization as a home for miscellaneous results formalized entirely autonomously by AI systems. Initially this contains two such formalizations: 1. three_squares.ml is a formalization by Claude Opus 4.8 of the classic Legendre three-squares theorem characterizing those integers representable as a sum of three integer squares, as well as the corollary that every integer is a sum of three triangular numbers. 2. sarkovskii.ml is a formalization by GPT-5.6-sol of Sarkovskii's theorem on periodic points of functions on real intervals. It is initially proved for functions real->real, then that core result is generalized using elementary topological machinery to arbitrary intervals. Mon 3rd Aug 2026 Examples/sos.ml Added a fix to handle degenerate SDPs with an empty constraint in REAL_SOS. This Claude-written change was based on a bug report and suggested fix from Daniel Nezamabadi. The issue is that real_positivnullstellensatz_general eliminates the linear monoid-matching equations in an essentially arbitrary order (via choose), then treats the remaining free variables as the SDP decision variables. Depending on that order, a free variable can turn out not to occur in any semidefinite block, so its constraint matrix mk_matrix is identically zero. CSDP rejects such a problem outright with "Constraint k is empty" and return code 206, rather than solving it. This is order-dependent: HOL Light's choose happens to pick an order that avoids it on the existing examples, but a differently-ordered dictionary implementation (e.g. Candle's) can hit it, e.g. on `a1 >= &0 /\ a2 >= &0 /\ (a1 * a1 + a2 * a2 = b1 * b1 + b2 * b2 + &2) /\ (a1 * b1 + a2 * b2 = &0) ==> a1 * a2 - b1 * b2 >= &0`;; The elimination is otherwise fine: the number of free variables (the affine solution dimension) is invariant across orders, so feasibility and the optimum are unchanged. Only the split of the free variables into "occurs in a block" vs "does not" varies, and an unlucky order leaves one decoupled. The fix is that before calling CSDP, we now drop any free variable whose constraint matrix is zero, solve the reduced SDP, and set the dropped variable to zero in the result. This is lossless: a variable absent from every block also has a zero objective coefficient (the objective is built from diagonal block entries), so it is genuinely unconstrained and irrelevant to the optimum. When no matrix is empty the reduced problem is identical to the original. This update also separately makes the "deepen" iterative deepending search function robust to genuinely malformed problems: CSDP return codes are now classified so that infeasibility (1,2) and numerical trouble (4-9) remain retryable Failures for the iterative deepening / tryfind search (some proofs, e.g. the Chebyshev and Zeng examples, legitimately rely on retrying past a numerical failure), while a structural rejection raises a new Csdp_error that deepen does not catch. Previously such a rejection was either swallowed as "no certificate at this degree", causing "deepen" to loop to ever higher degrees, or surfaced as a confusing missing-output-file error. Sun 2nd Aug 2026 WZ [new directory] Added a formal implementation of the Wilf-Zeilberger algorithm for hypergeometric summation, one which largely avoids akwardnesses over zero denominators and special cases by an interpretion using real gamma function limits. This was fully implemented back in 2014 and described in the paper: John Harrison "Formal Proofs of Hypergeometric Sums" Journal of Automated Reasoning 55 (2015) https://www.cl.cam.ac.uk/~jrh13/papers/wz.html The setup has belatedly been made available having been cleaned up and extended, mainly with a cleaner Maxima certificate-generation interface and a few more examples, by Codex using gpt-5.6-sol (xhigh). Among the automatic examples is the A recurrence that is proved more manually in the recently added Examples/apery.ml proof. Sat 1st Aug 2026 Examples/apery.ml [new file] Added a proof of Apery's theorem, the irrationality of zeta(3). This originates in 2014, when I was inspired by a presentation from Assia Mahboubi of a proof project in Coq, which was eventually completed and published as A. Mahboubi and T. Sibut-Pinote, "A Formal Proof of the Irrationality of zeta(3)" (2021). At that time the A and B recurrences had been proved in Coq following Bruno Salvy's computer algebra proof http://algo.inria.fr/libraries/autocomb/Apery2-html/apery.html but there was no machinery to provide the lcm(1..n) estimate needed for the full result. I decided to derive them from the HOL Light proof of the Prime Number Theorem (which is overkill). At that time I also formalized almost all other parts of the Apery proof including the A recurrence, but ground to a halt on the B recurrence which seemed to require much more work. I eventually revived this in 2026 and had Claude Opus 4.8 complete the B recurrence proof, following Salvy again. Fri 10th Jul 2026 nets.ml Made an optimization from June Lee to the discrimination nets in nets.ml, using balanced trees to speed lookup. The original code is conceptually ancient, little changed from Cambridge LCF days. Mon 15th Jun 2026 iterate.ml Added a simple but useful generalization of CARD_UNIONS whose proof is no more difficult than that special cases, which is now derived from it. CARD_UNIONS_IMAGE = |- !f s. FINITE s /\ (!t. t IN s ==> FINITE(f t)) /\ (!t u. t IN s /\ u IN s /\ ~(t = u) ==> f t INTER f u = {}) ==> CARD(UNIONS(IMAGE f s)) = nsum s (\i. CARD(f i)) Mon 8th Jun 2026 Library/ringtheory.ml, Library/rabin_test.ml, 100/transcendence.ml Extended the ring theory library with the Hilbert Basis Theorem for polynomial and power series rings (the latter via Cohen's prime-ideal criterion and Kaplansky's lemma), prime ideal correspondence under localization, and the preservation by localization of the Noetherian, Bezout, PID and von Neumann regular properties. Also added a ring definition of multiplicative order ("ring_order") with many elementary properties, and many other miscellaneous technical lemmas, as well as streamlining rabin_test.ml. New definition: ring_order and new theorems: BEZOUT_RING BEZOUT_RING_LOCALIZATION COEFF_POWSER_SUM FINITELY_GENERATED_IDEAL_LOCALIZATION FINITELY_GENERATED_IDEAL_SUBSET IDEAL_GENERATED_BY_HOMOMORPHIC_IMAGE IDEAL_GENERATED_EXPLICIT IDEAL_GENERATED_FINITARY IDEAL_GENERATED_FINITARY_ALT IDEAL_GENERATED_FINITE IDEAL_GENERATED_FINITE_IMAGE IDEAL_GENERATED_RING_LOCALIZATION IDEAL_GENERATED_SCALE IDEAL_GENERATED_SETADD_SUBSET IDEAL_LOCALIZATION_CONTRACTION KAPLANSKY_LEMMA LOCALEQUIV_MUL_LCANCEL LOCALEQUIV_MUL_RCANCEL MAXIMAL_NONFG_IMP_PRIME_IDEAL NOETHERIAN_LOCAL_RING_LOCALIZATION NOETHERIAN_POLY_RING NOETHERIAN_POLY_RING_1 NOETHERIAN_POWSER_RING NOETHERIAN_POWSER_RING_1 NOETHERIAN_RING_EQ_FG_PRIME_IDEALS NOETHERIAN_RING_LOCALIZATION PID_RING_LOCALIZATION POLY_ADD_RZERO POLY_DEG_EQ_FROM_LE POLY_DEG_LT_FROM_LE POLY_DEG_MUL_VAR POLY_DEG_MUL_VARPOW POLY_DEG_VARPOW_MUL POLY_DEG_VAR_MUL POLY_MUL_VAR POLY_RING_EPIMORPHISM_COEFF_0 POLY_RING_HOMOMORPHISM_COEFF_0 POLY_VAR_MUL POWSER_EVALUATE_AT_0 POWSER_EVAL_AT_0 POWSER_EXTEND_AT_0 POWSER_MUL_0 POWSER_MUL_MONOMIAL_1 POWSER_MUL_VAR POWSER_RING_EPIMORPHISM_COEFF_0 POWSER_RING_HOMOMORPHISM_COEFF_0 POWSER_VARPOW_MUL_EQ_0 POWSER_VAR_MUL POWSER_VAR_MUL_EQ_0 PRIME_IDEAL_LOCALIZATION PRIME_IDEAL_LOCALIZATION_CONTRACTION PRIME_IDEAL_LOCALIZATION_EXISTS PRINCIPAL_IDEAL_LOCALIZATION PROPER_IDEAL_LOCALIZATION RING_EPIMORPHISM_POWSER_EVALUATE_AT_0 RING_EPIMORPHISM_POWSER_EVAL_AT_0 RING_GEOM_SERIES RING_GEOM_SERIES_GEN RING_HOMOMORPHISM_IN_CARRIER RING_HOMOMORPHISM_POWSER_EVALUATE_AT_0 RING_HOMOMORPHISM_POWSER_EVAL_AT_0 RING_HOMOMORPHISM_POWSER_EXTEND_AT_0 RING_IDEAL RING_IDEAL_LOCALIZATION RING_IDEAL_SCALE RING_LOCALEQUIV_IN_LOCALIZED_IDEAL RING_LOCALEQUIV_REFL RING_LOCALEQUIV_SPLIT RING_LOCALEQUIV_SPLIT_EXPLICIT RING_LOCALIZATION_HOMOMORPHISM_UNIQUE RING_LOCALIZATION_PRIME_IDEAL_CORRESPONDENCE RING_LOCALIZATION_UNIQUE RING_MUL_LCANCEL RING_MUL_RCANCEL RING_NEG_SUB RING_ORDER_1 RING_ORDER_EQ_0 RING_ORDER_EQ_1 RING_ORDER_MUL RING_ORDER_MUL_DIVIDES RING_ORDER_MUL_DIVIDES_GEN RING_ORDER_MUL_DIVIDES_LCM RING_ORDER_POW RING_ORDER_POW_DIVIDES RING_ORDER_POW_GEN RING_ORDER_UNIQUE RING_ORDER_UNIQUE_PRIME RING_POW_COPRIME_EQ_1 RING_POW_EQ_1 RING_POW_GCD_EQ_1 RING_POW_MOD_ORDER RING_POW_MOD_ORDER_GEN RING_POW_RING_ORDER RING_PRODUCT_0 RING_PRODUCT_CASES RING_PRODUCT_NSUM RING_SCALE_SETMUL RING_SUM_DIFFS RING_SUM_DIFFS_ALT RING_UNIT_IDEMPOTENT_EQ_1 VNREGULAR_RING_LOCALIZATION The following are incompatible changes to existing theorems: COEFF_POLY_SUM -> COEFF_POWSER_SUM (COEFF_POLY_SUM is now re-used for the polynomial case) LOCALEQUIV_MUL_CANCEL -> LOCALEQUIV_MUL_RCANCEL (now with a dual LOCALEQUIV_MUL_LCANCEL) POLY_DEG_EQ_COEFF_FROM_LE -> POLY_DEG_EQ_FROM_LE (old name removed) POLY_EVALUATE_AT_0 (additional quantification) Sat 6th Jun 2026 Probability/* Substantially extended the probability theory library. The main themes are: (1) reworking measurability of random variables around the new general Borel sigma-algebra "borel_in" (Multivariate/metric.ml), in place of the previous hand-rolled half-line level-set lemmas; (2) building out the GENERAL conditional expectation "gen_cond_exp" into a usable calculus (linearity, monotone and dominated convergence, "taking out what is known", Cauchy-Schwarz, Jensen) and adding conditional variance; (3) adding the law/distribution (pushforward) of a random variable and the joint distribution function of a pair; (4) the Levy inversion theorem and characteristic-function uniqueness; (5) a new file ergodic.ml with the Birkhoff/maximal-ergodic material; and (6) a much fuller distributions.ml with densities, CDFs and characteristic functions for the standard distributions. As with everying in the Probability subdirectory, this was entirely generated (statements and proofs) by Claude Code, a mix of Opus 4.6 and 4.8. New definitions: cond_variance distribution ergodic exponential_cdf exponential_density exponential_distributed fejer_kernel_real geometric_distributed has_density has_pmf invariant_event joint_distribution_fn measure_preserving normal_cdf normal_density normal_distributed poisson_distributed real_halflines uniform_cdf uniform_density uniform_distributed and theorems: ABEL_SUMMATION_CONVERGENCE ABS_CONT ABS_LIM ABS_MUL_GE_SPLIT ABS_MUL_GE_SPLIT_BOUND ABS_MUL_LT_SQRT ADAPTIVE_SELECTOR_DEP ARCHIMEDEAN_INV_BOUND AS_IMP_IN_DIST AS_IMP_IN_PROB ATN_PI2_BOUND AVG_GT_IMP_MAXSUM_POS AVG_GT_IMP_SUM_POS AVG_LT_IMP_SUM_POS AVG_SHIFT_DIFF BERNOULLI_CHAR_FN_IM BERNOULLI_CHAR_FN_RE BINOMIAL_CHAR_FN_IM BINOMIAL_CHAR_FN_RE BIRKHOFF_ERGODIC BIRKHOFF_ERGODIC_BOUNDED BIRKHOFF_ERGODIC_BOUNDED_L1 BIRKHOFF_ERGODIC_L1 BIRKHOFF_ERGODIC_THEOREM BIRKHOFF_ERGODIC_THEOREM_BOUNDED BIRKHOFF_LIMIT_INVARIANT BIRKHOFF_OSCILLATION_CONTAINMENT BOREL_IN_EUCLIDEANREAL_EQ_SIGMA_GENERATED BOREL_IN_SIGMA_ALGEBRA BOUNDED_LIMSUP_LIMINF_CONVERGE CDF_MONO CDF_RIGHT_CONTINUOUS CHAR_FN_IM_BINOMIAL_RV CHAR_FN_IM_CONTINUOUS CHAR_FN_IM_EXPONENTIAL_DIST CHAR_FN_IM_GEOMETRIC_DIST CHAR_FN_IM_NORMAL_DIST CHAR_FN_IM_POISSON_DIST CHAR_FN_IM_UNIFORM_DIST CHAR_FN_RE_BINOMIAL_RV CHAR_FN_RE_CONTINUOUS CHAR_FN_RE_EXPONENTIAL_DIST CHAR_FN_RE_GEOMETRIC_DIST CHAR_FN_RE_NORMAL_DIST CHAR_FN_RE_POISSON_DIST CHAR_FN_RE_UNIFORM_DIST CHAR_FN_UNIQUENESS COND_EXP_INDICATOR_BOUNDED_AE COND_EXP_L2_CONTRACTION COND_EXP_TAKE_OUT CONTINUOUS_COMPOSE_SEQ CONTINUOUS_MAP_EUCLIDEANREAL CONVERGES_AS_FROM_RATE CONVERGES_IN_PROB_ABS CONVERGES_IN_PROB_ADD CONVERGES_IN_PROB_AE_SUBSEQUENCE CONVERGES_IN_PROB_BOUNDED_MUL CONVERGES_IN_PROB_CMUL CONVERGES_IN_PROB_CONST CONVERGES_IN_PROB_CONTINUOUS_COMPOSE CONVERGES_IN_PROB_DIFF_ZERO CONVERGES_IN_PROB_MAX CONVERGES_IN_PROB_MIN CONVERGES_IN_PROB_MUL CONVERGES_IN_PROB_NEG CONVERGES_IN_PROB_NULL_ADD CONVERGES_IN_PROB_NULL_MUL CONVERGES_IN_PROB_SUB CONVERGES_IN_PROB_SUBSEQUENCE CONVERGES_IN_PROB_SUBSEQUENCE_PRINCIPLE CONVERGES_IN_PROB_UNIQUE CONVEX_AFFINE_MINORANT_SUP CONVEX_CONT_AT COS_DIFF_HAS_REAL_INTEGRAL_HALFLINE COS_DIFF_HAS_REAL_INTEGRAL_HALFLINE_FULL COS_DIFF_HAS_REAL_INTEGRAL_HALFLINE_GEN COS_HAS_REAL_INTEGRAL DECOMPOSITION_UNBOUNDED_IFF DECR_INTEGRAL_TENDS_0 DECR_INTEGRAL_TENDS_0_AE DIRICHLET_INTEGRAL DIRICHLET_INTEGRAL_SCALED DIRICHLET_INTEGRAL_SCALED_NEG DIRICHLET_TAIL_BOUND DISCRIMINANT_NONNEG DISTRIBUTION_CDF DISTRIBUTION_COUNTABLY_ADDITIVE DISTRIBUTION_EMPTY DISTRIBUTION_FN_CONTINUOUS_PROB_ZERO DISTRIBUTION_IN_EVENTS DISTRIBUTION_LE_1 DISTRIBUTION_MONO DISTRIBUTION_POS DISTRIBUTION_UNIV DYADIC_APPROX_BOUND DYADIC_BOUND DYADIC_CONV DYADIC_LEVEL DYADIC_MEASURABLE DYADIC_SIMPLE ERGODIC_AVG_BOUNDED ERGODIC_AVG_DIFF_BOUND ERGODIC_AVG_EXPECTATION ERGODIC_AVG_INTEGRABLE ERGODIC_AVG_INTEGRABLE_POW2 ERGODIC_AVG_VARIANCE_BOUND ERGODIC_LIMINF_NULL ERGODIC_LIMINF_SHIFT ERGODIC_LIMSUP_NULL ERGODIC_LIMSUP_SHIFT ERGODIC_MAXSUM_GE_SUM ERGODIC_MAXSUM_INTEGRABLE ERGODIC_MAXSUM_KEY_INEQ ERGODIC_MAXSUM_MONO ERGODIC_MAXSUM_POS ERGODIC_MAXSUM_POS_EVENT ERGODIC_MAXSUM_RV ERGODIC_OSCILLATION_INVARIANT ERGODIC_OSCILLATION_MEASURABLE ERGODIC_OSCILLATION_NULL ERGODIC_SUM_EXPECTATION ERGODIC_SUM_INTEGRABLE ERGODIC_SUM_SHIFT ERGODIC_TRUNCATION_ABS_BOUND ERGODIC_TRUNCATION_INTEGRABLE ERGODIC_TRUNCATION_L1 ERGODIC_TRUNCATION_POINTWISE ERROR_INTEGRAL_BOUND EXPECTATION_ABS_FROM_SQUARE EXPECTATION_AE_ZERO EXPECTATION_COMP_PRESERVED EXPECTATION_EQ_TAIL_SUM EXPECTATION_EXPONENTIAL_DIST EXPECTATION_GEOMETRIC_DIST EXPECTATION_ITER_COMP_PRESERVED EXPECTATION_MONO_AE EXPECTATION_MUL_INDICATOR_CONULL EXPECTATION_NONNEG_ZERO_AE_ZERO EXPECTATION_NORMAL_DIST EXPECTATION_POISSON_DIST EXPECTATION_SQ_ORTHOGONAL EXPECTATION_UNIFORM_DIST EXPECTATION_ZERO_AE_BOUNDED_MEASURABLE EXPECTATION_ZERO_BOUNDED_MEASURABLE EXPECTATION_ZERO_HALVING EXPONENTIAL_CDF_LE_1 EXPONENTIAL_CDF_NONNEG EXPONENTIAL_CDF_ZERO EXPONENTIAL_CHAR_FN_IM EXPONENTIAL_CHAR_FN_RE EXPONENTIAL_DENSITY_INTEGRABLE_NONNEG EXPONENTIAL_DENSITY_INTEGRAL EXPONENTIAL_DENSITY_NONNEG EXPONENTIAL_DENSITY_POS EXPONENTIAL_DENSITY_ZERO EXPONENTIAL_HAS_REAL_DERIVATIVE EXPONENTIAL_HAS_REAL_DERIVATIVE_WITHIN EXPONENTIAL_INTEGRABLE_INTERVAL EXPONENTIAL_INTEGRAL_INTERVAL EXPONENTIAL_INTEGRAL_SEQ_TENDS_1 EXPONENTIAL_LIMIT_POSINFINITY EXPONENTIAL_LINEAR_DECAY_SEQ EXPONENTIAL_MEAN EXPONENTIAL_MEAN_ANTIDERIV EXPONENTIAL_MEAN_INTEGRAL EXPONENTIAL_MEAN_INTEGRAL_INTERVAL EXPONENTIAL_MEAN_SEQ_TENDS EXPONENTIAL_MEMORYLESS EXPONENTIAL_PRODUCT_DECAY_SEQ EXPONENTIAL_QUADRATIC_DECAY_SEQ EXPONENTIAL_REAL_CONTINUOUS EXPONENTIAL_SECOND_MOMENT EXPONENTIAL_SECOND_MOMENT_ANTIDERIV EXPONENTIAL_SECOND_MOMENT_INTEGRAL EXPONENTIAL_SECOND_MOMENT_INTEGRAL_INTERVAL EXPONENTIAL_SECOND_MOMENT_SEQ_TENDS EXPONENTIAL_VARIANCE_INTEGRAL EXP_AFFINE_DECOMP EXP_COS_ANTIDERIV EXP_COS_INTEGRAL_INTERVAL EXP_DECAY_INTEGRAL EXP_INTEGRAL_REP EXP_SIMPLE_MUL_DECOMP EXP_SIN_ANTIDERIV EXP_SIN_INTEGRAL_INTERVAL FEJER_KERNEL_REAL_COSINE FEJER_KERNEL_REAL_EQ_SINC_SQUARED FEJER_KERNEL_REAL_INTEGRAL FEJER_KERNEL_REAL_POS FEJER_KERNEL_REAL_TAIL_BOUND GAUSSIAN_FT_HALFLINE GEN_COND_EXP_ABS_BOUND GEN_COND_EXP_AFFINE GEN_COND_EXP_CAUCHY_SCHWARZ GEN_COND_EXP_DCT GEN_COND_EXP_DECR_TENDS_0 GEN_COND_EXP_JENSEN GEN_COND_EXP_JENSEN_EXP GEN_COND_EXP_L2_CONTRACTION GEN_COND_EXP_LINEAR3 GEN_COND_EXP_MCT GEN_COND_EXP_SEQ_MONO_AE GEN_COND_EXP_SUB GEN_COND_EXP_TAKE_OUT_AFFINE GEN_COND_EXP_TAKE_OUT_BOUNDED GEN_COND_EXP_TAKE_OUT_INDICATOR GEN_COND_EXP_TAKE_OUT_SIMPLE GEN_COND_EXP_TRIANGLE GEOMETRIC_CHAR_FN_IM GEOMETRIC_CHAR_FN_RE HALFLINES_SUBSET_UNIV HAS_DENSITY_INTEGRABLE HAS_DENSITY_INTEGRAL_ONE HAS_DENSITY_INTERVAL_PROB HAS_DENSITY_NONNEG HAS_DENSITY_RV HAS_PMF_NONNEG HAS_PMF_PROB HAS_PMF_RV HAS_PMF_SUMS_ONE HAS_REAL_INTEGRAL_AFFINITY_UNIV IDENTITY_HAS_REAL_INTEGRAL IID_SLLN_L1_VIA_BIRKHOFF IID_SLLN_VIA_BIRKHOFF INDEP_RV_JOINT_DISTRIBUTION INDICATOR_SUM_BOUNDED INDICATOR_SUM_COMPENSATOR_IDENTITY INDICATOR_SUM_COND_EXP_STEP INDICATOR_SUM_SUBMARTINGALE INF_PERTURB_BOUND INF_SUBSET_LE INNER_INTEGRAL_T INNER_INTEGRAL_U INTEGRABLE_ABS_INDICATOR INTEGRABLE_AFFINE_IND_MUL INTEGRABLE_BOUNDED_POW2 INTEGRABLE_COMP_MP INTEGRABLE_MUL_BOUNDED INTEGRABLE_PRODUCT_INDICATOR INTEGRABLE_TRUNCATION INTEGRAL_EXPECTATION_EXCHANGE INTEGRAL_GAP_TENDS_0 INTEGRAL_INV_ONE_PLUS_SQ INTEGRAL_SPLIT_NUMSEG INVARIANT_EVENTS_SUB_SIGMA_ALGEBRA INVERSION_FUBINI INVERSION_KERNEL_BOUNDED INVERSION_KERNEL_BOUNDED_NZ INVERSION_KERNEL_CONVERGES_AT_A INVERSION_KERNEL_CONVERGES_AT_B INVERSION_KERNEL_CONVERGES_INSIDE INVERSION_KERNEL_CONVERGES_OUTSIDE INVERSION_KERNEL_RV INVERSION_KERNEL_UNIFORM_BOUND INVERSION_SINC_EVEN INVERSION_TRIG_IDENTITY IN_SIGMA_GENERATED_GEN ITER_1 ITER_ADD ITER_IN_INVARIANT JOINT_DISTRIBUTION_LE_MARGINAL_X JOINT_DISTRIBUTION_SYM JOINT_RECTANGLE_IN_EVENTS KOLMOGOROV_SLLN' KRONECKER_RESCALED L2_IMP_IN_DIST LAPLACE_SIN LAW_OF_TOTAL_VARIANCE LEVY_CONDITIONAL_BOREL_CANTELLI LEVY_INVERSION LHS_INTEGRABLE LIFT_INTEGRAL_BRIDGE LIMSUP_EVENTS_IFF_SUM_UNBOUNDED LOTUS_BOUNDED_CONTINUOUS LOTUS_CONTINUOUS LOTUS_COS LOTUS_NONNEG_CONTINUOUS LOTUS_PMF_COS LOTUS_PMF_INTEGRABLE LOTUS_PMF_SIN LOTUS_SIN MARTINGALE_DIFF_ORTHOGONAL MAXIMAL_ERGODIC_INFINITE MAXIMAL_ERGODIC_LEMMA MEAN_ERGODIC_BOUNDED MEAN_ERGODIC_THEOREM MEASURABLE_WRT_INDICATOR MEASURABLE_WRT_INV_GE_ONE MEASURABLE_WRT_MAX_CONST MEASURABLE_WRT_MIN_CONST MEASURABLE_WRT_MUL MEASURABLE_WRT_MUL_INDICATOR MEASURABLE_WRT_POW2 MEASURABLE_WRT_REALLIM MEASURABLE_WRT_SUM MEASURE_AGREE_LAMBDA_SYSTEM MEASURE_PRESERVING_CARRIER MEASURE_PRESERVING_EVENTS MEASURE_PRESERVING_ITER MEASURE_PRESERVING_PROB MEASURE_UNIQUE_ON_PI_SYSTEM MEL_INVARIANT_SET MWRT_AFFINE NN_EXPECTATION_COMP_PRESERVED NN_EXPECTATION_COMP_PRESERVED_BOUNDED NORMAL_CDF_BOUNDS NORMAL_CDF_COMPLEMENT NORMAL_CDF_CONTINUOUS NORMAL_CDF_LIMIT_NEG NORMAL_CDF_LIMIT_POS NORMAL_CDF_MEAN NORMAL_CDF_MONO NORMAL_CDF_STANDARD NORMAL_CHAR_FN_IM NORMAL_CHAR_FN_RE NORMAL_DENSITY_INTEGRABLE NORMAL_DENSITY_INTEGRAL NORMAL_DENSITY_NONNEG NORMAL_DENSITY_POS NORMAL_DENSITY_STANDARD NORMAL_DENSITY_STANDARDIZE NORMAL_DENSITY_SYM NORMAL_MEAN NORMAL_MEAN_HELPER NORMAL_MEAN_INTEGRAL NORMAL_SHIFTED_COS_INTEGRAL NORMAL_SHIFTED_SIN_INTEGRAL NORMAL_VARIANCE NORMAL_VARIANCE_INTEGRAL NOT_CONVERGENT_OSCILLATION OFF_LIMSUP_CONVERGES ONE_MINUS_COS_HAS_REAL_INTEGRAL_HALFLINE ONE_MINUS_COS_HAS_REAL_INTEGRAL_UNIV ONE_MINUS_COS_SCALED_HAS_REAL_INTEGRAL_HALFLINE POISSON_CHAR_FN_IM POISSON_CHAR_FN_RE POISSON_MEAN_SERIES POISSON_PMF_RECURSION POISSON_SECOND_FACTORIAL_MOMENT POISSON_SECOND_MOMENT POISSON_VARIANCE_SERIES POW2_SHRINK_ZERO PROB_ABS_GE_TENDS_TO_ZERO PROB_STRICT_INEQ_LIMIT RADON_NIKODYM_UNIQUE RANDOM_VARIABLE_BOREL_MEASURABLE_COMPOSE RANDOM_VARIABLE_COMP_MP RANDOM_VARIABLE_CONTINUOUS_MAP_COMPOSE RANDOM_VARIABLE_DIV_POS RANDOM_VARIABLE_GT_SUFFICIENT RANDOM_VARIABLE_ITER_COMP_MP RANDOM_VARIABLE_LIMIT RANDOM_VARIABLE_PREIMAGE_BOREL_IN RANDOM_VARIABLE_REAL_LIMSUP_DOMINATED RANDOM_VARIABLE_SUP_SEQ_FN RANDOM_VARIABLE_TRUNCATION RATIONAL_DISCRIMINANT RATIONAL_DISCRIMINANT_DENSITY REALLIM_AT_POSINFINITY_FROM_SUBSEQUENCES REALLIM_AT_POSINFINITY_IMP_SEQUENTIALLY REAL_ABS_DIV_LE REAL_CONTINUOUS_ATREAL_SEQUENTIALLY REAL_CONVEX_SUPPORTING_LINE REAL_DIV_ABS_LE_1 REAL_EQ_EPSILON REAL_EQ_FROM_APPROX REAL_EXP_QUADRATIC_BOUND REAL_HALFLINE_LE_IN_SIGMA REAL_HALFLINE_LT_IN_SIGMA REAL_INTEGRAL_EVEN_SYMMETRIC REAL_INTERVAL_IN_SIGMA REAL_LE_EPSILON REAL_LIMINF_LE_LIMSUP_ABS REAL_LIMINF_LE_PERTURB REAL_LIMINF_LT_EXISTS_BOUNDED REAL_LIMINF_PERTURB_NULL REAL_LIMSUP_GT_EXISTS_BOUNDED REAL_LIMSUP_LE_PERTURB REAL_LIMSUP_LE_SUP' REAL_LIMSUP_NEG REAL_LIMSUP_PERTURB_NULL REAL_OPEN_COUNTABLE_UNION_REAL_INTERVAL REAL_OPEN_IN_SIGMA RESCALED_INDICATOR_CONVERGENCE RESCALED_INDICATOR_CONVERGENCE_MAX RESCALED_MAX_L2_BOUNDED RESCALED_MAX_MARTINGALE RESCALED_TRUNCATED_L2 REVERSE_FATOU_DOMINATED RHS_INTEGRABLE RIEMANN_SUM_CONVERGES RIGHT_CONTINUOUS_MONOTONE_AGREE RV_LEVEL_SET_EVENT RV_LIMIT_GT_EQ RV_PREIMAGE_GE RV_PREIMAGE_GT RV_PREIMAGE_LE RV_PREIMAGE_LT RV_PREIMAGE_LT_EQ_UNIONS RV_PREIMAGE_REAL_INTERVAL RV_PREIMAGE_REAL_OPEN RV_STRICT_INEQ_EVENT SHIFTED_FILTRATION SIGMA_ALGEBRA_INTERS_COUNTABLE SIGMA_ALGEBRA_SIGMA_GENERATED_HALFLINES SIGMA_ALGEBRA_SYM_DIFF SIMPLE_CHAR_FN_IM_CONTINUOUS SIMPLE_CHAR_FN_RE_CONTINUOUS SIMPLE_EXPECTATION_COMP_PRESERVED SIMPLE_EXPECTATION_TRAPEZOIDAL_FOURIER SIMPLE_RV_COMP_MP SIMPLE_RV_SUM_INDICATOR SIN2X_INV_X_SUBSTITUTION SINC_DECOMPOSITION SINC_EXP_DECAY_BOUND SINC_EXP_DECAY_INTEGRABLE SINC_EXP_EQ SINC_INTEGRAL_BOUND SINC_INTEGRAL_BOUND_ALL SINC_INTEGRAL_IDENTITY SINC_INTEGRAL_SPLIT SINC_INTEGRAL_UNIFORM_BOUND SINC_INV_INTEGRABLE SINC_LE_ONE SINC_MUL_INTEGRABLE SINC_SCALED_DIFF_INTEGRABLE SINC_SCALED_INTEGRABLE SINC_SCALED_INTEGRABLE_NZ SINC_SCALED_NEG_INTEGRABLE SINC_SQUARED_CONTINUOUS SINC_SQUARED_HAS_REAL_INTEGRAL_HALFLINE SINC_SQUARED_HAS_REAL_INTEGRAL_UNIV SINC_SQUARED_IDENTITY SINC_SQUARED_INTEGRABLE SINC_SQUARED_INTEGRAL SINC_SQUARED_INTEGRAL_BOUND SINC_SQUARED_LE_ONE SIN_EXP_2D_CONTINUOUS SIN_EXP_FUBINI SIN_HAS_REAL_INTEGRAL SIN_SQUARED_IBP SIN_SQUARED_INV_LE SIN_TAYLOR2_BOUND SMOOTHING_INTEGRAND_INTEGRABLE SMOOTHING_INTEGRAND_MEASURABLE SQUARE_HAS_REAL_INTEGRAL SQ_SUM_BOUND STD_NORMAL_CDF_COMPLEMENT STD_NORMAL_CDF_LIMIT_NEG STD_NORMAL_CDF_LIMIT_POS STD_NORMAL_CDF_SEQ_TENDS_1 STD_NORMAL_CDF_ZERO STD_NORMAL_INTEGRAL_INTERVAL_TENDS_1 SUMMATION_BY_PARTS SUM_INDICATOR_EQ_NAT SUM_SQUARE_CAUCHY_SCHWARZ SUM_TRIG_FACTOR SUPPORTING_SLOPE SUP_PERTURB_BOUND SUP_SEQ_VIA_INF SUP_SUBSET_GE SUP_TAIL_TENDS_0 TAIL_SUM_EQ_NN_EXPECTATION TELESCOPING_STEP TELESCOPING_SUM_BOUND TELESCOPING_SUM_BOUND_SIMPLE TELESCOPING_VARIANCE_BOUND TELESCOPING_VARIANCE_BOUND_SIMPLE THREE_SLOPES TO_POINTWISE TRAPEZOIDAL_ALG_IDENTITY TRAPEZOIDAL_FOURIER_IDENTITY TRIG_COS_DIFF_EXPAND TRUNCATED_DIFF_EXPECTATION_ZERO TRUNCATED_DIFF_SQ_BOUND TRUNCATION_ABS_DIFF TRUNCATION_L2_CONVERGENCE TRUNCATION_PRESERVES_LIMIT T_COS_HAS_REAL_INTEGRAL UI_MARTINGALE_CLOSURE UI_POINTWISE_L1_AE UNIFORM_CDF_BOUNDS UNIFORM_CDF_LEFT UNIFORM_CDF_MONO UNIFORM_CDF_RIGHT UNIFORM_CHAR_FN_IM UNIFORM_CHAR_FN_RE UNIFORM_DENSITY_INTEGRABLE UNIFORM_DENSITY_INTEGRAL UNIFORM_DENSITY_NONNEG UNIFORM_DENSITY_POS UNIFORM_DENSITY_VALUE UNIFORM_DENSITY_ZERO UNIFORM_MEAN UNIFORM_MEAN_INTEGRAL UNIFORM_SECOND_MOMENT UNIFORM_SECOND_MOMENT_INTEGRAL UNIFORM_VARIANCE_INTEGRAL UNIONS_SIGMA_GENERATED_HALFLINES VARIANCE_EXPONENTIAL_DIST VARIANCE_GEOMETRIC_DIST VARIANCE_NORMAL_DIST VARIANCE_POISSON_DIST VARIANCE_UNIFORM_DIST WIENER_MAXIMAL_INEQUALITY X2_CONVEX One existing theorem name THREE_SERIES_CONDITION1 now resolves to a strictly more general statement, by de-duplication. Eight theorems present previously are removed. Four are the bespoke half-line measurability lemmas, now subsumed by the single Borel-preimage characterization RANDOM_VARIABLE_PREIMAGE_BOREL_IN RANDOM_VARIABLE_GE RANDOM_VARIABLE_GT RANDOM_VARIABLE_STRICT_LT RANDOM_VARIABLE_OPEN_HALFLINE (The specific direction still needed in one place is retained/restated as RANDOM_VARIABLE_GT_SUFFICIENT.) The other four were ad-hoc analytic utilities, now removed as redundant with library facts or with local replacements: COS_TAYLOR_CONVERGES SIN_TAYLOR_CONVERGES POW_2_LE_SQRT REAL_CONTINUOUS_OPEN_PREIMAGE_UNIV Numerous existing proofs were also streamlined to go through RANDOM_VARIABLE_PREIMAGE_BOREL_IN and the general Borel machinery rather than re-deriving measurability of level sets by hand, but those leave the theorem statements untouched. Fri 5th Jun 2026 Multivariate/metric.ml, Multivariate/topology.ml Added a general "Borel sets of a topological space" theory, complementing the existing Euclidean-specific "borel" (on real^N) already in topology.ml. In metric.ml, defined "borel_in top" inductively as the smallest family of subsets of the topspace containing the open sets and closed under countable union and under complement (relative to the topspace). Developed the basic sigma-algebra calculus and its behaviour under subtopologies, continuous maps and homeomorphisms: borel_in_RULES borel_in_INDUCT borel_in_CASES OPEN_IMP_BOREL_IN BOREL_IN_COMPLEMENT BOREL_IN_COMPLEMENT_EQ BOREL_IN_UNIONS BOREL_IN_SUBSET_TOPSPACE BOREL_IN_TOPSPACE BOREL_IN_EMPTY BOREL_IN_INTERS BOREL_IN_UNION BOREL_IN_INTER BOREL_IN_DIFF CLOSED_IMP_BOREL_IN FSIGMA_IMP_BOREL_IN GDELTA_IMP_BOREL_IN OPEN_IN_SUBTOPOLOGY_BOREL_IN CLOSED_IN_SUBTOPOLOGY_BOREL_IN BOREL_IN_SUBTOPOLOGY BOREL_FROM_SUBTOPOLOGY BOREL_IN_INTER_SUBTOPOLOGY BOREL_IN_SUBTOPOLOGY_EQ BOREL_IN_CONTINUOUS_MAP_PREIMAGE BOREL_IN_HOMEOMORPHIC_MAP_IMAGE BOREL_IN_HOMEOMORPHIC_MAPS_IMAGE_EQ BOREL_IN_HOMEOMORPHIC_MAP_IMAGE_EQ Also in metric.ml, defined "borel_measurable_map (top1,top2) f" as a function mapping top1 into top2 where the preimage of every "borel_in top2" set is "borel_in top1", with the expected closure properties, the most non-trivial being closure under pointwise sequential limits, assuming a metrizable codomain: borel_measurable_map BOREL_MEASURABLE_MAP_OPEN_IN BOREL_MEASURABLE_MAP_CLOSED_IN BOREL_MEASURABLE_MAP_IMAGE_SUBSET_TOPSPACE CONTINUOUS_IMP_BOREL_MEASURABLE_MAP BOREL_MEASURABLE_MAP_ID BOREL_MEASURABLE_MAP_CONST BOREL_MEASURABLE_MAP_EQ BOREL_MEASURABLE_MAP_COMPOSE BOREL_MEASURABLE_MAP_FROM_SUBTOPOLOGY BOREL_MEASURABLE_MAP_INTO_SUBTOPOLOGY BOREL_MEASURABLE_MAP_LIMIT In topology.ml, connected the general notions back to the existing Euclidean ones. BOREL_IN_EUCLIDEAN shows "borel_in euclidean = borel", so all the existing real^N results about "borel" transfer to the general theory as the Euclidean instance, and vice versa. The identification for the measurable maps is a little more delicate than for the sets, because the existing Euclidean Borel-measurability predicate "f borel_measurable_on s" (topology.ml) is defined quite differently, as a Baire function, i.e. inductively as the closure of the continuous functions under pointwise sequential limits. These are proved equivalent but only under the assumption that the domain is a Borel set, including the special case of the whole of real^N. BOREL_IN_EUCLIDEAN BOREL_MEASURABLE_MAP_EUCLIDEAN BOREL_MEASURABLE_MAP_EUCLIDEAN_SUBTOPOLOGY Wed 3rd Jun 2026 pa_j/chooser.sh Added an update from Matthias Kannwischer to accept camlp5 8.05 with OCaml 5.4 - the actual pa_j_5.4_8.04.00.ml still works so it only needs to improve the selector. Mon 1st Jun 2026 printer.ml, UnitTests/printer_tests.ml Made a fix authored by Balaji Rao and June Lee to the printing of names with their type annotations under print_types_of_subterms := 2 (or := 1 with invented type variables). This now inserts an extra space where needed for symbolic identifers, which otherwise might generate text that does not correctly parse back owing to lexical conventions, absorbing the colon into the name. For example `&3:int` now prints with a space between "&" and its type. Mon 18th May 2026 mcp/make_checkpoint.py Tweaked this script to detect failures when building the checkpoint, which can easily happen if checkpointing material under development. It also now rejects expressions containing ';;' immediately. Mon 18th May 2026 printer.ml Adopted a refactoring from June Lee of the printer, decomposing pp_print_term's special-form chain into separate functions. This also adds unit tests for the printer, now placed in a special UnitTests subdirectory. Sun 17th May 2026 Probability/clt.ml Replaced List.filteri (OCaml >= 4.14) with subtract/el for compatibility with older OCamls. Sat 16th May 2026 Library/grouptheory.ml, Library/symmetric_group.ml, Added the theorems ABELIAN_QUOTIENT_GROUP_DIV and SOLVABLE_GROUP_MONOMORPHIC_PREIMAGE, as well as slightly incompatibly tweaking the statement of ABELIAN_QUOTIENT_COMMUTATOR to make its quantifier structure more harmonious with the library. Fri 15th May 2026 Library/ringtheory.ml, Library/fieldtheory.ml, 100/transcendence.ml, Extended the ring theory library with material on squarefree elements, monic and reciprocal polynomials, formal (univariate) polynomial derivatives plus actual division and remainder functions for polynomials. Much of this material was adopted from the existing formalization in 100/transcendence.ml into the main libraries, though with some notable differences as described below (in particular ring_squarefree). New definitions: monic poly_deriv poly_div poly_recip poly_rem ring_squarefree New theorems in Library/ringtheory.ml: COEFF_0 COEFF_0_POLY_RECIP_EQ_0 COEFF_ABOVE_DEG COEFF_COMPOSE COEFF_POLY_DERIV COEFF_POLY_LMUL COEFF_POLY_MUL_ALT COEFF_POLY_MUL_VAR COEFF_POLY_MUL_VARPOW COEFF_POLY_RECIP COEFF_POLY_RMUL COEFF_POLY_VAR COEFF_POLY_VARPOW COEFF_POLY_VARPOW_MUL COEFF_POLY_VAR_MUL FIELD_MONIC_ASSOCIATE FIELD_MONIC_IRREDUCIBLE_ASSOCIATE FUN_ONE_EQ_ONE FUN_ONE_NUM_EQ INTEGER_RING_POW INTEGRAL_DOMAIN_PRIME_PRODUCT_DIVIDES INTEGRAL_DOMAIN_PRIMES_COPRIME_OR_ASSOCIATES INTEGRAL_DOMAIN_PRIMES_DIVIDES_EQ_ASSOCIATES IRREDUCIBLE_IMP_POLY_DEG_NZ ISOMORPHIC_RING_EQ MONIC_ASSOCIATES_EQ MONIC_CMUL MONIC_DEG_0 MONIC_IMP_NONZERO MONIC_IN_TRIVIAL_RING MONIC_POLY_0 MONIC_POLY_1 MONIC_POLY_CONST MONIC_POLY_MUL MONIC_POLY_POW MONIC_POLY_PRODUCT MONIC_POLY_VAR MONIC_SUBRING_GENERATED MONOMIAL_DIVISORS_1 MONOMIAL_MUL_EQ_VAR MONOMIAL_UNIV_1 MONOMIAL_VAR_DIVIDES_MUL POLY_CONST_DIVIDES_CONST POLY_CONST_EQ_0 POLY_CONST_EQ_1 POLY_CONST_OF_NUM POLY_DEG_CMUL POLY_DEG_DERIV POLY_DEG_DERIV_LE POLY_DEG_DIVIDES_LE POLY_DEG_DIVIDES_LE_MONIC POLY_DEG_DIVIDES_LE_UNIVARIATE POLY_DEG_EQ_COEFF_EQ POLY_DEG_GE_COEFF POLY_DEG_GE_COEFF_EQ POLY_DEG_LE_COEFF_EQ POLY_DEG_MUL_MONIC POLY_DEG_MUL_UNIVARIATE POLY_DEG_RECIP POLY_DEG_RECIP_LE POLY_DEG_REM POLY_DEG_REM_ALT POLY_DERIV_0 POLY_DERIV_1 POLY_DERIV_ADD POLY_DERIV_CMUL POLY_DERIV_CONST POLY_DERIV_HOMOMORPHIC_IMAGE POLY_DERIV_IN_CARRIER POLY_DERIV_MUL POLY_DERIV_NEG POLY_DERIV_NONZERO_CHAR0 POLY_DERIV_POW POLY_DERIV_PRODUCT POLY_DERIV_SUB POLY_DERIV_SUBRING_GENERATED POLY_DERIV_SUM POLY_DERIV_VAR POLY_DERIV_VAR_POW POLY_DIV POLY_DIV_REM POLY_DIV_REM_SIMP POLY_DIVIDES_RECIP POLY_DIVIDES_RECIP_EQ POLY_DIVIDES_RECIP_GALOIS POLY_DIVIDES_RECIP_RECIP POLY_DIVIDES_REM POLY_EVALUATE_RING_SUM POLY_EVAL_RECIP POLY_EVAL_RING_SUM POLY_EXTEND_RING_SUM POLY_IN_POWSER_RING POLY_IRREDUCIBLE_IMP_SEPARABLE POLY_MUL_LEADING_COEFF POLY_MUL_RID POLY_NONCONSTANT_IRREDUCIBLE_IMP_SEPARABLE POLY_RECIP_0 POLY_RECIP_1 POLY_RECIP_CONST POLY_RECIP_EQ_0 POLY_RECIP_IN_CARRIER POLY_RECIP_MUL POLY_RECIP_MUL_GEN POLY_RECIP_NEG POLY_RECIP_RECIP POLY_RECIP_RECIP_EQ POLY_REM POLY_REM_UNIQUE POLY_ROOT_COUNT_IMP_SQUAREFREE POLY_SEPARABLE_EQ_SQUAREFREE POLY_SEPARABLE_IMP_SQUAREFREE POLY_SQUARE_DIVIDES_DERIV POLY_SQUARE_DIVIDES_DERIV_EQ POLY_SQUAREFREE_IMP_SEPARABLE POLY_VARPOW_RECIP_RECIP POWSER_CLAUSES POWSER_DERIV_IN_CARRIER REPEATED_ROOT_POLY_DERIV_ZERO RING_AUTOMORPHISM_I RING_AUTOMORPHISM_ID RING_COPRIME_DISTINCT_MONIC_IRREDUCIBLES RING_COPRIME_DIVISORS RING_COPRIME_HOMOMORPHIC_IMAGE RING_COPRIME_LPOW RING_COPRIME_PRODUCT RING_COPRIME_PRODUCT_DIVIDES RING_COPRIME_PRODUCT_DIVIDES_ALT RING_COPRIME_PRODUCT_EQ RING_COPRIME_RPOW RING_COPRIME_UNIT RING_DIVIDES_ALT RING_DIVIDES_MUL_EQ RING_DIVIDES_PRODUCTS RING_IRREDUCIBLE_IMP_NONTRIVIAL_RING RING_IRREDUCIBLE_IMP_SQUAREFREE RING_IRREDUCIBLE_NEG RING_IRREDUCIBLE_POLY_CONST RING_IRREDUCIBLE_POLY_RECIP RING_IRREDUCIBLE_POLY_RECIP_EQ RING_IRREDUCIBLE_POLY_VAR RING_IRREDUCIBLES_COPRIME_OR_ASSOCIATES RING_OF_NUM_POLY_RING RING_OF_NUM_POWSER_RING RING_POLYNOMIAL_DIV RING_POLYNOMIAL_POLY_DERIV RING_POLYNOMIAL_POWERSERIES_COEFF RING_POLYNOMIAL_RECIP RING_POLYNOMIAL_REM RING_POWERSERIES_POLY_DERIV RING_POWERSERIES_RECIP RING_PRIME_DIVIDES_POW RING_PRIME_IMP_NONTRIVIAL_RING RING_PRIME_IMP_SQUAREFREE RING_PRIME_MUL_DIVIDES RING_PRIME_MUL_DIVIDES_EQ RING_PRIME_NEG RING_PRIME_POLY_RECIP RING_PRIME_POLY_RECIP_EQ RING_PRIME_POLY_VAR RING_PRIME_PRODUCT_DIVIDES RING_SQUAREFREE_0 RING_SQUAREFREE_1 RING_SQUAREFREE_ALT RING_SQUAREFREE_ASSOCIATES RING_SQUAREFREE_COPRIME RING_SQUAREFREE_COPRIME_DIVISORS RING_SQUAREFREE_DECOMPOSITION RING_SQUAREFREE_DIVIDES RING_SQUAREFREE_DIVIDES_SQUARE RING_SQUAREFREE_DIVISOR RING_SQUAREFREE_DIVPOW RING_SQUAREFREE_DIVPOW_EQ RING_SQUAREFREE_GCD RING_SQUAREFREE_IMP_NONZERO RING_SQUAREFREE_IMP_NO_PRIME_SQUARE RING_SQUAREFREE_IN_CARRIER RING_SQUAREFREE_MUL_EQ RING_SQUAREFREE_MUL_IMP RING_SQUAREFREE_POW RING_SQUAREFREE_PRIME_DIVISOR_EQ RING_SQUAREFREE_PRIME_EQ RING_SQUAREFREE_PRODUCT RING_SUM_CONST RING_UNIT_IMP_SQUAREFREE RING_UNIT_POLY_RECIP RING_UNIT_POLY_RECIP_EQ RING_UNIT_POLY_RING_1 RING_UNIT_POLY_VAR TRIVIAL_RING_POLY_0 TRIVIAL_RING_POWSER_0 New theorems in Library/fieldtheory.ml: ALGEBRAICALLY_CLOSED_FIELD_EQ_SPLITS_ALT ALGEBRAICALLY_CLOSED_FIELD_SPLITS COPRIME_POLY_NO_COMMON_ROOT COPRIME_POLY_NO_COMMON_ROOT_I FIELD_EXTENSION_TRANS_I IRREDUCIBLE_ALGEBRAICALLY_CLOSED_FIELD POLY_SQUAREFREE_EXPLICIT_EQ POLY_SQUAREFREE_ROOT_COUNT POLY_SQUAREFREE_ROOT_COUNT_EQ POLY_SQUAREFREE_ROOT_COUNT_EXPLICIT Changed theorems: ALGEBRAICALLY_CLOSED_FIELD_EQ_SPLITS [strengthened, old = _ALT] COEFF_POLY_CONST_MUL [renamed to COEFF_POLY_LMUL] COEFF_POLY_MUL_CONST [renamed to COEFF_POLY_RMUL] POLY_MUL_VAR_COEFF_UNIVARIATE [removed, see COEFF_POLY_VAR_MUL] POLY_VAR_DIVIDES_UNIVARIATE [==> became <=>, lost hyps] RING_PRIME_POLY_CONST [==> became <=>, lost hyps] RING_PRIME_POLY_RING_MONO [lost integral_domain hyp] RING_PRIME_POLY_VAR_UNIVARIATE [==> became <=>] Incompatible changes to existing theorem statements: RING_PRIME_POLY_CONST (ringtheory.ml): strengthened from integral_domain r /\ ring_prime r p ==> ring_prime ... (poly_const ...) to the unconditional equivalence ring_prime (poly_ring r s) (poly_const r p) <=> ring_prime r p RING_PRIME_POLY_VAR_UNIVARIATE (ringtheory.ml): strengthened from integral_domain r ==> ring_prime (poly_ring r (:1)) (poly_var r one) to the equivalence ring_prime (poly_ring r (:1)) (poly_var r one) <=> integral_domain r RING_PRIME_POLY_RING_MONO (ringtheory.ml): lost integral_domain r hypothesis (primality in a sub-polynomial-ring now unconditionally lifts to the larger polynomial ring). POLY_VAR_DIVIDES_UNIVARIATE (ringtheory.ml): strengthened from integral_domain r /\ f IN carrier ==> (x divides f <=> f(0) = 0) to the unconditional equivalence ring_divides ... (poly_var r one) p <=> ring_polynomial r p /\ coeff 0 p = ring_0 r COEFF_POLY_CONST_MUL renamed to COEFF_POLY_LMUL (same statement). COEFF_POLY_MUL_CONST renamed to COEFF_POLY_RMUL (same statement). POLY_MUL_VAR_COEFF_UNIVARIATE removed, subsumed by COEFF_POLY_VAR_MUL. ALGEBRAICALLY_CLOSED_FIELD_EQ_SPLITS (fieldtheory.ml): hypothesis strengthened from ~(poly_deg k p = 0) to ~(p = poly_0 k). The old statement (with the degree condition) is preserved as ALGEBRAICALLY_CLOSED_FIELD_EQ_SPLITS_ALT. ring_squarefree (100/transcendence.ml): definition changed from "a | b^2 ==> a | b" to "no non-unit has its square dividing a". Some downstream theorems in that file have gained hypotheses: ring_squarefree_if_prime now requires integral_domain r; ring_squarefree_if_product_coprime_primes(_indexed) now require UFD r. Mon 27th Apr 2026 Probability/* Substantially extended the probability theory library with new results, generalized definitions, and systematic naming cleanup, also adding standard discrete distributions. This work was entirely done by Claude Opus 4.6. The most significant structural change is the systematic generalization from simple random variables to integrable random variables. The original library developed much of the theory using simple_rv (finite-valued random variables) with simple_expectation. This update adds parallel general definitions using integrable/expectation (Lebesgue integration) and reproves key results at this level of generality. The naming convention is: unprefixed names (e.g. martingale, char_fn_re) now refer to the general versions, while the original simple-RV versions are preserved under SIMPLE_ prefixes (e.g. simple_martingale, simple_char_fn_re). IMPORTANT: Several definitions and theorem names that existed in the previous version now refer to different (strictly more general) objects. The following definitions changed meaning (old simple-RV-based definitions are preserved under the names shown): martingale now uses adapted/integrable/expectation (was: simple_adapted/simple_rv/simple_expectation; old version now called simple_martingale) submartingale same generalization pattern (old version now called simple_submartingale) supermartingale same generalization pattern (old version now called simple_supermartingale) char_fn_re now defined via expectation p (\x. cos(t * X x)) (was: simple_expectation p (\x. cos(t * X x)); old version now called simple_char_fn_re) char_fn_im now defined via expectation p (\x. sin(t * X x)) (was: simple_expectation p (\x. sin(t * X x)); old version now called simple_char_fn_im) converges_L2 now defined via expectation (was: simple_expectation; old version now called simple_converges_L2) The following 20 theorem names that existed in the previous version now prove strictly stronger results (weaker hypotheses, same conclusions). In each case, the hypothesis "simple_rv" was replaced by "random_variable" or "integrable", and "simple_expectation" by "expectation". The old simple-RV versions are preserved with a SIMPLE_ prefix: CDF_LE_EXPECTATION CLT_CHAR_FN_CONVERGENCE CHAR_FN_ADD_INDEP_IM CLT_CHAR_FN_IM_CONVERGENCE CHAR_FN_ADD_INDEP_RE CLT_IM_ERROR_VANISHES CHAR_FN_DETERMINES_NORMAL_CDF_LIMIT EXPECTATION_LE_CDF CHAR_FN_IM_BOUND MCT_NN_EXPECTATION CHAR_FN_MODULUS_LE STEP_C_BOUND CHAR_FN_RE_BOUND TRIG_POLY_WEAK_CONVERGENCE CHAR_FN_RE_POW_CONV_EXP WEAK_CONVERGENCE_FROM_CHAR_FN CHAR_FN_SUM_IID_IM_SQ_BOUND MEASURABLE_WRT_ADD CHAR_FN_SUM_IID_RE_BOUND MEASURABLE_WRT_SUB Major new results include: KOLMOGOROV_SLLN: Kolmogorov's Strong Law of Large Numbers via the maximal inequality for independent summands IID_SLLN: for i.i.d. integrable random variables, the sample mean converges almost surely to the common expectation LINDEBERG_FELLER_CLT: the CLT under the Lindeberg condition for triangular arrays of independent random variables LEVY_CONTINUITY_GENERAL: pointwise convergence of characteristic functions implies convergence in distribution HELLY_SELECTION_THEOREM: every uniformly bounded sequence of distribution functions has a convergent subsequence PROHOROV_FORWARD: tightness implies relative sequential compactness in the topology of convergence in distribution RADON_NIKODYM: for an absolutely continuous signed measure, there exists an integrable density HAHN_DECOMPOSITION / JORDAN_DECOMPOSITION: every signed measure admits a Hahn decomposition and a Jordan decomposition into nonneg measures concentrated on complementary sets GEN_COND_EXP_EXISTS / GEN_COND_EXP_TOWER / GEN_COND_EXP_ITERATED: general conditional expectation via Radon-Nikodym with tower property, iterated conditioning, monotonicity, and linearity GEN_DOOB_DECOMPOSITION: general Doob decomposition of a submartingale into a martingale plus a predictable increasing process BACKWARD_MARTINGALE_CONVERGENCE_L1_BOUNDED: L1-bounded backward martingales converge almost surely UI_SUBMARTINGALE_CONVERGENCE_AS / OPTIONAL_STOPPING_UI: uniformly integrable submartingale convergence and optional stopping AZUMA_HOEFFDING_TWO_SIDED / MCDIARMID_INEQUALITY: concentration inequalities for martingales and bounded-differences functions THREE_SERIES_SUFFICIENCY / THREE_SERIES_NECESSITY / THREE_SERIES_NECESSITY_INDEP: Kolmogorov three-series theorem (both directions; two independent proofs of necessity) PALEY_ZYGMUND: reverse Markov-type inequality for lower bounds on the probability that a nonneg RV exceeds a fraction of its mean UI_BACKWARD_MARTINGALE_CONVERGENCE_AS: UI backward martingales converge almost surely WALD_EQUATION: for a martingale stopped at a bounded stopping time FATOU_LEMMA / REVERSE_FATOU_LEMMA / DOMINATED_CONVERGENCE_AE: convergence theorems for expectations POISSON_LIMIT: the Poisson limit theorem (binomial -> Poisson) Thu 23rd Apr 2026 Library/ringtheory.ml, Library/fieldtheory.ml, 100/transcendence.ml Adopted the "coeff" function from 100/transcendence.ml in the main ring theory file, with an equivalent but more direct definition. Added 28 new theorems about coefficient extraction for basic operations, the Cauchy product, degree interaction, polynomial characterization, and evaluation: COEFF COEFF_IN_CARRIER COEFF_IN_CARRIER_ALT COEFF_NONZERO_LE COEFF_NONZERO_LE_DEG COEFF_POLY_0 COEFF_POLY_1 COEFF_POLY_ADD COEFF_POLY_CONST COEFF_POLY_CONST_MUL COEFF_POLY_MUL COEFF_POLY_MUL_CONST COEFF_POLY_NEG COEFF_POLY_SUB COEFF_POLY_SUM FINITE_COEFF_SUPPORT FUN_EQ_COEFF POLY_DEG_EQ_COEFF POLY_DEG_EQ_COEFF_FROM_LE POLY_DEG_LE_COEFF POLY_EVAL_COEFF POLY_MUL_UNIVARIATE POLY_TOP_EQ_0 RING_POLYNOMIAL_COEFF RING_POLYNOMIAL_COEFF_BOUND RING_POLYNOMIAL_COEFF_ZERO_FROM RING_POLYNOMIAL_SUBRING_COEFF RING_POWERSERIES_COEFF Also added helper lemmas LAMBDA_1_EQ, FINITE_FUN_FROM_1, MONOMIAL_DEG_ONE and moved EXISTS_FUN_FROM_1, FORALL_FUN_FROM_1 earlier in the file. Seven existing theorems are restated to use coeff in their statements: POLY_DIVISION_GEN POLY_EVAL_AT_0 POLY_EVAL_EXPAND POLY_EXPAND POLY_EXTEND_UNIVARIATE POLY_TOP_NONZERO POLY_TOP_TAIL Three proofs in Library/fieldtheory.ml are adjusted for the restated POLY_EXTEND_UNIVARIATE, and in 100/transcendence.ml the local coeff definition is replaced by a bridge lemma "coeff_x_monomial" connecting the ringtheory definition with the local x_monomial construct, and about 20 proofs are simplified to one-line derivations from the new ringtheory theorems. Mon 20th Apr 2026 passim Fixed another case identified by Daniel Nezamabadi where polymorphic comparison was mistakenly being used on the bignum type, this one in Multivariate/vectors.ml; then assisted by Claude found and fixed many other instances of the same issue - iterate.ml: EXPAND_NSUM_CONV, EXPAND_SUM_CONV - printer.ml: DECIMAL printer - calc_rat.ml: RAW_REAL_RAT_MUL_CONV - calc_int.ml: is_realintconst, term_of_rat - int.ml: is_intconst - Library/calc_real.ml: REAL_FLOAT_MUL_CONV helper - Library/bitmatch.ml: bitpat_matches, inst_bitpat_numeral, unword - Library/isum.ml: EXPAND_ISUM_CONV Tue 14th Apr 2026 Library/tactician_light.ml [new file] Added "Tactician Light", a proof format translator for HOL Light, converting between interactive (g/e) and structured (prove) proof styles. It is inspired by Mark Adams' Tactician tool for HOL Light: http://www.proof-technologies.com/tactician/ which provided similar functionality via a "hiproof" representation and refactoring pipeline. This is a from-scratch reimplementation by Claude Code using string-based tactic recording rather than the original promotion/demotion mechanism. Although this simpler version requires some additional user work (e.g. saving a log of the tactic invocations to a file for processing by "i2s"), it is considerably simpler and less sensitive to OCaml internals. Mon 13th Apr 2026 mcp/* Merged an update from Ceren Kocaogullar adding proof recording tools "start_recording" and "stop_recording" to the MCP setup. This helps when the LLM is developing large proofs interactively in cases where the context window is exhausted or the session crashes. By retaining this record, the proof can resume where it left off. Sun 12th Apr 2026 mcp/SKILL.md Merged an update from Nevine Ebeid to the mcp/SKILL.md file that refines or corrects the explanations of several constructs and adds new pitfall warnings. Wed 8th Apr 2026 100/green.ml [new file], 100/isoperimetric.ml, Library/words.ml, Multivariate/measure.ml, Multivariate/transcendentals.ml, Multivariate/realanalysis.ml, Multivariate/cauchy.ml Added a proof of Green's theorem in a fairly general form, autoformalized by Claude Opus 4.6. The proof is based on the Cauchy transform as a left inverse of the Wirtinger d-bar derivative operator. This approach, avoiding any approximation or subdivision arguments while allowing quite general path parametrization, was inspired by Kostya_I's answer here: https://mathoverflow.net/questions/307713 The technique is rooted in the Cauchy transform / dbar framework of Ahlfors, "Lectures on Quasiconformal Mappings" (1966, 2nd ed. 2006), and appears in Bonk's UCLA complex analysis lecture notes, Ch. 20: https://www.math.ucla.edu/~mbonk/complana.pdf The primary versions use complex infrastructure in the statements. More traditional (but verbose) real-analytic variants of the Green theorem and area formulas are derived as easy consequences, e.g. GREEN_THEOREM_CURL = |- f g u. g absolutely_continuous_on interval[vec 0,vec 1] /\ pathfinish g = pathstart g /\ (!z. z IN inside(path_image g) ==> winding_number(g,z) = Cx(&1)) /\ open u /\ inside(path_image g) UNION path_image g SUBSET u /\ f differentiable_on u /\ (!h:real^2. (\z. frechet_derivative f (at z) h) continuous_on u) ==> (\z. lift(frechet_derivative f (at z) (basis 1) $1 - frechet_derivative f (at z) (basis 2) $2)) integrable_on inside(path_image g) /\ (\t. lift(f(g t)$2 * vector_derivative g (at t) $1 + f(g t)$1 * vector_derivative g (at t) $2)) integrable_on interval[vec 0,vec 1] /\ integral (interval[vec 0,vec 1]) (\t. lift(f(g t)$2 * vector_derivative g (at t) $1 + f(g t)$1 * vector_derivative g (at t) $2)) = integral (inside(path_image g)) (\z. lift(frechet_derivative f (at z) (basis 1) $1 - frechet_derivative f (at z) (basis 2) $2)) As a side-effect, added a number of general lemmas to the Multivariate libraries, notably some results on absolutely continuous paths including the winding number integral HAS_PATH_INTEGRAL_WINDING_NUMBER_AC, a complement to HAS_PATH_INTEGRAL_WINDING_NUMBER with non-comparable hypotheses: ABSOLUTELY_CONTINUOUS_IMP_PATH ABSOLUTELY_CONTINUOUS_IMP_RECTIFIABLE_PATH ABSOLUTELY_CONTINUOUS_JOINPATHS ABSOLUTELY_CONTINUOUS_REVERSEPATH ABSOLUTELY_INTEGRABLE_VECTOR_DERIVATIVE_ABSOLUTELY_CONTINUOUS CEXP_LIPSCHITZ_BOUNDED HAS_PATH_INTEGRAL_WINDING_NUMBER_AC LEBESGUE_MEASURABLE_SING LSPACE_ALT LSPACE_SUBSET MEASURABLE_ON_CLOG MEASURABLE_ON_CPOW NEGLIGIBLE_REAL Wed 8th Apr 2026 Library/words.ml Added a word-level carryless multiplication operation word_pmul, in effect performing multiplication in GF2[X], using the bits of a machine word to represent polynomial coefficients in a quite standard way (little-endian: LSB = constant term). It has generic word sizes `word_pmul:M word->N word->P word`, so it can be used as a target for modeling different variants supported by CPUs or just used in other settings. There is an associated evaluation conversion WORD_PMUL_CONV that is included in the usual WORD_RED_CONV / WORD_REDUCE_CONV suite, as well as a bitwise conversion BIT_WORD_PMUL_CONV. New definition: word_pmul new theorems: BITVAL_BIT_WORD_PMUL BIT_WORD_PMUL BIT_WORD_PMUL_ALT WORD_PMUL_0 WORD_PMUL_POW2 WORD_PMUL_STEP WORD_PMUL_SYM WORD_PMUL_XOR WORD_PMUL_ZX and conversions: WORD_PMUL_CONV BIT_WORD_PMUL_CONV Wed 8th Apr 2026 Examples/doomsday.ml Added a new example autoformalized by Claude Opus 4.6, Conway's "Doomsday Algorithm" for finding the weekday for a given (valid Gregorian) date. The overall correctness theorem is: DOOMSDAY_ALGORITHM_CORRECT = |- !y m d. valid_date(y,m,d) ==> doomsday_algorithm y m d = day_of_week y m d Tue 7th Apr 2026 mcp/* Incorporated a number of updates from Sanketh Menda to the MCP server, including queue-based sentinel signaling (in place of polling) and a more efficient apply_tactic, consolidated into a single MCP eval roundtrip. Thu 2nd Apr 2026 mcp/make_checkpoint.py Added a small but useful refinement from Nevin Ebeid to the MCP checkpointing script, with a new block to send Gc.compact ();; to the OCaml REPL right after any extra loads finish and before the DMTCP checkpoint is taken. This performs heap compaction before creating the checkpoint, which can dramatically decrease the checkpoint size. Mon 31st Mar 2026 Library/components.ml, Library/records.ml [new files], unit_tests.ml Added a port by June Lee of code originating in s2n-bignum for creating record types using a natural syntax, together with the supporting library of state components ("lenses"). Mon 31st Mar 2026 calc_num.ml Added a fix from Daniel Nezamabadi to a case where polymorphic comparison <= was mistakenly being used on the bignum type instead of the appropriate special numeric comparison <=/. Mon 31st Mar 2026 mcp/* [new directory] Added a HOL Light MCP server contributed by Sanketh Menda, to support LLM-assisted theorem proving more efficiently. This is a FastMCPstdio server, embedding HOL Light as a subprocess with OCaml-side JSON serialization for structured goal states. It also provides a custom checkpoint creation script mcp/make_checkpoint.py for creating efficiently restartable checkpoints (on Linux). The tools provided are: - apply_tactic: apply tactic, return new state or proved theorem - backtrack: undo N tactic steps - eval: raw OCaml/HOL Light evaluation - goal_state: inspect current goals as JSON - hol_help: serve SKILL.md directly from the MCP server - hol_interrupt: send SIGINT to cancel hung tactics - hol_load: load a HOL Light file via needs - hol_restart: Kill existing HOL process and start a fresh one - hol_status: report alive/dead, pid, checkpoint name, uptime etc. - hol_type: get the type of a term - search_theorems: search by name, return JSON results - set_goal: set proof goal, return JSON goal state See mcp/README.md and other mcp/*.md for more information. Sun 22nd Mar 2026 100/buffon.ml [new file], holtest.mk Added a proof, entirely autoformalized by Claude Opus 4.6, of the solution to the Buffon Needle problem, in both the "short needle" and "long needle" cases. The statements are formulated in terms of the newly added probability theory, with the "position" and "angle" being independent random variables. BUFFON_SHORT = |- !p X Theta l d. &0 < l /\ l <= d /\ &0 < d /\ uniform_rv p X (&0) (d / &2) /\ uniform_rv p Theta (&0) pi /\ indep_rv p X Theta ==> prob p {x | x IN prob_carrier p /\ X x <= (l / &2) * sin(Theta x)} = (&2 * l) / (pi * d) BUFFON_LONG = |- !p X Theta l d. &0 < l /\ &0 < d /\ d <= l /\ uniform_rv p X (&0) (d / &2) /\ uniform_rv p Theta (&0) pi /\ indep_rv p X Theta ==> prob p {x | x IN prob_carrier p /\ X x <= (l / &2) * sin(Theta x)} = (&2 / (pi * d)) * (l - sqrt(l pow 2 - d pow 2) + d * acs(d / l)) Sat 21st Mar 2026 Probability/* [new directory], holtest.mk Added the first version of a new probability theory library. This was autonomously formalized by Claude Opus 4.6, approximately following the presentation in Williams's textbook "Probability with Martingales". It includes the development of Lebesgue-type integration theory within the setting of probability measure spaces as part of the foundational material. Among the classic results proved are the Central Limit Theorem, Laws of Large Numbers (weak and strong), Fair Games Theorem (Doob optional stopping), Borel-Cantelli lemmas, martingale convergence and the Azuma-Hoeffding inequality. Mon 9th Mar 2026 Library/ringtheory.ml Added more elementary results in ring theory: the preservation of the UFD property in localization and in polynomial rings (the latter via Gauss's lemma, some forms of which are broken out, e.g. as POLY_PRIMITIVE_CONST_CANCEL), and the Eisenstein irreducibility criterion: EISENSTEIN_IRREDUCIBILITY EISENSTEIN_IRREDUCIBILITY_FRACTION_RING EISENSTEIN_IRREDUCIBILITY_GEN INTEGRAL_DOMAIN_LOCALIZATION IRREDUCIBLE_PRIMITIVE_POLY_FRACTION_RING LOCALEQUIV_MUL_CANCEL MAKE_PRIMITIVE_IN_IDEAL MONOMIAL_MUL_VAR_ONE POLY_CLEAR_DENOMINATORS POLY_CONST_DIVIDES_COEFFS POLY_CONST_DIVIDES_COEFFS_EQ POLY_CONST_DIVIDES_COEFFS_REV POLY_MAKE_PRIMITIVE POLY_MONOMIALS_ALT POLY_MUL_VAR_COEFF_UNIVARIATE POLY_PRIMITIVE_CONST_CANCEL POLY_RING_HOMOMORPHISM_I POLY_VAR_DIVIDES_UNIVARIATE POLY_VAR_MONOMIAL_1 RING_DIVIDES_LOCALEQUIV RING_PRIME_POLY_CONST RING_PRIME_POLY_RING_MONO RING_PRIME_POLY_VAR_UNIVARIATE UFD_LOCALIZATION UFD_POLY_RING Fri 6th Mar 2026 sets.ml, Library/grouptheory.ml, Library/permutations.ml, Library/symmetric_group.ml [new file] Added a definition of "solvable_group" to the group theory library with some of its basic properties, as well as additional material about permutations. Combining these, the new file Library/symmetric_group.ml gives a basic development of the symmetric group (the group of permutations on set) including its unsolvability for a set of size >= 5. New definitions: solvable_group symmetric_group three_cycle and theorems: ABELIAN_IMP_SOLVABLE_GROUP ABELIAN_QUOTIENT_COMMUTATOR ABELIAN_QUOTIENT_EPIMORPHIC_IMAGE ALL_TRANSPOSITIONS_GENERATE_SYMMETRIC CARD_SYMMETRIC_GROUP CAYLEY_THEOREM CAYLEY_THEOREM_EXPLICIT CHAIN_STEP_THREE_CYCLES_GEN COMMUTATOR_IMP_ABELIAN_QUOTIENT FINITE_SYMMETRIC_GROUP INVERSE_UNIQUE_ALT INVOLUTION_MOVES_2_IS_SWAP INVOLUTION_SIZE_2_IS_SWAP ISOMORPHIC_GROUP_SOLVABILITY NOT_SOLVABLE_SYMMETRIC_GROUP PERMUTES_THREE_CYCLE POINT_TRANSPOSITIONS_GENERATE_ALL PRIME_ORDER_PERM_NO_FIXPOINT PRIME_ORDER_PERM_ORBIT PRIME_ORDER_POW_PERM RESTRICT_COMPOSE RESTRICT_I RESTRICT_INVERSE RESTRICT_PERMUTES_SUBSET RESTRICT_SWAP RESTRICT_SYMMETRIC_GROUP_HOMOMORPHISM SOLVABLE_GROUP_ALT SOLVABLE_GROUP_EPIMORPHIC_IMAGE SOLVABLE_GROUP_NORMAL_EXTENSION SOLVABLE_GROUP_QUOTIENT SOLVABLE_GROUP_SOLVABLE_QUOTIENT SOLVABLE_GROUP_SUBGROUP SUBGROUP_RESTRICT_PERMUTES SWAP_CONJUGATE SWAP_CONJUGATE_IN_SUBGROUP SWAP_IN_SYMMETRIC_GROUP SWAP_LEFT SWAP_OTHER SWAP_RIGHT SWAP_TRIPLE SWAP_TRIPLE_ALT SYMMETRIC_GROUP SYMMETRIC_GROUP_ACTION SYMMETRIC_GROUP_ID SYMMETRIC_GROUP_INV SYMMETRIC_GROUP_MUL SYMMETRIC_GROUP_POW SYMMETRIC_GROUP_POW_IN THREE_CYCLE_AS_COMMUTATOR THREE_CYCLE_COMMUTATOR THREE_CYCLE_COMPOSE_REVERSE THREE_CYCLE_INVERSE THREE_CYCLE_IN_SYMMETRIC THREE_CYCLE_NOT_I TRANSITIVE_TRANSPOSITION_GENERATES_SYMMETRIC TRANSPOSITION_PCYCLE_GENERATES TRIVIAL_IMP_SOLVABLE_GROUP Also added a few simple but natural lemmas to the sets.ml file in support: CARD_LE_2 = |- CARD {a,b} <= 2 CARD_LE_3 = |- CARD {a,b,c} <= 3 CARD_LE_4 = |- CARD {a,b,c,d} <= 4 Thu 5th Mar 2026 Help/mapi.hlp Added a documentation file for the new "mapi" function introduced as part of the METIS restructuring. Wed 4th Mar 2026 Library/words.ml Added a few miscellaneous word lemmas connecting logical left and right shifts with (1) leading/trailing bit counts, and (2) bit reversal. WORD_CLZ_USHR = |- !(x:N word) n. word_clz (word_ushr x n) = MIN (dimindex(:N)) (word_clz x + n) WORD_CTZ_SHL = |- !(x:N word) n. word_ctz (word_shl x n) = MIN (dimindex(:N)) (word_ctz x + n) WORD_SHL_AS_USHR = |- !(x:N word) n. word_shl x n = word_reversefields 1 (word_ushr (word_reversefields 1 x) n) WORD_USHR_AS_SHL = |- !(x:N word) n. word_ushr x n = word_reversefields 1 (word_shl (word_reversefields 1 x) n) Thu 26th Feb 2026 Multivariate/metric.ml, Multivariate/paths.ml Added major new results about path-connectedness in general metric spaces, together with generalizations of existing Euclidean-specific theorems, almost entirely written by Claude Code (Opus 4.6). The Alexandroff-Hausdorff theorem (ALEXANDROFF_HAUSDORFF: every compact metrizable space is a continuous image of the Cantor space) and the Hahn-Mazurkiewicz theorem (HAHN_MAZURKIEWICZ: a metrizable continuum is a Peano continuum iff it is a continuous image of the unit interval) are entirely new results, not generalizations of anything previously in HOL Light. Their proofs go through a chain of substantial lemmas: the Alexandroff-Hausdorff embedding provides dense maps from Cantor space into compact metric spaces, and a gap-filling extension lemma (PEANO_GAP_FILLING_EXTENSION) for locally connected continua then yields the full Hahn-Mazurkiewicz characterization. From Hahn-Mazurkiewicz it follows that compact connected locally connected metric spaces are path-connected (COMPACT_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED). This is then extended to the locally compact case by expressing open subsets as unions of compact connected locally connected sets (LOCALLY_CONNECTED_CONTINUUM_SPACE), then to complete metric spaces (MCOMPLETE_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED, often called Menger's theorem). The existing Euclidean theorem LOCALLY_COMPACT_CONNECTED_IMP_PATH_CONNECTED assumed local compactness; the new general version for complete metric spaces is strictly stronger, since completeness is a weaker hypothesis than local compactness. New Euclidean specializations in paths.ml include optimal G_delta versions: GDELTA_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED gives path-connectedness under the weakest natural hypothesis for R^n, since G_delta is equivalent to completely metrizable in Euclidean space. Supporting infrastructure includes: well-chained set refinements in open covers (CHAIN_FROM_OPEN_COVER), connected chain unions (CONNECTED_IN_CHAIN_UNIONS), compact nested intersections (COMPACT_NESTED_INTERS), fine connected covers of open connected sets (OPEN_CONNECTED_FINE_COVER), the full chain hierarchy construction for dyadic approximation (CHAIN_HIERARCHY), and closure of dyadic rationals in the unit interval (CLOSURE_OF_DYADIC_RATIONALS_IN_UNIT_INTERVAL). New theorems in Multivariate/metric.ml: ALEXANDROFF_HAUSDORFF CHAIN_FROM_OPEN_COVER CHAIN_HIERARCHY CHAIN_IN_OPEN_CONNECTED_SET CHAIN_REFINEMENT_STEP CLOSURE_OF_DYADIC_RATIONALS_IN_UNIT_INTERVAL COMPACT_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED COMPACT_IN_LOCALLY_CONNECTED_EQ_FCCOVERABLE_SPACE_ALT COMPACT_LOCALLY_CONNECTED_NEARBY_PATH COMPACT_METRIZABLE_LOCALLY_CONNECTED_IMP_LOCALLY_PATH_CONNECTED COMPACT_METRIZABLE_PEANO_IMP_PATH_CONNECTED COMPACT_NESTED_INTERS COMPLETELY_METRIZABLE_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED COMPLETELY_METRIZABLE_LOCALLY_PATH_CONNECTED_EQ_LOCALLY_CONNECTED CONNECTED_IN_CHAIN_UNIONS DENSE_FUNCTION_ON_DYADIC FCCOVERABLE_IN_COMPACT_LOCALLY_CONNECTED FINITE_CONNECTED_COMPONENTS_CLOPEN_UNION FINITE_CONNECTED_COMPONENTS_COMPACT_LOCALLY_CONNECTED HAHN_MAZURKIEWICZ HAHN_MAZURKIEWICZ_IMP LOCALLY_COMPACT_CONNECTED_IMP_PATH_CONNECTED_SPACE LOCALLY_COMPACT_LOCALLY_CONNECTED_IMP_LOCALLY_PATH_CONNECTED_SPACE LOCALLY_COMPACT_LOCALLY_PATH_CONNECTED_EQ_LOCALLY_CONNECTED_SPACE LOCALLY_COMPACT_SPACE_IMP_GDELTA_IN LOCALLY_CONNECTED_CONTINUUM_SPACE LOCALLY_CONSTANT_REFINEMENT LOCALLY_FCCOVERABLE_SPACE LOCALLY_FCCOVERABLE_SPACE_CHAIN MCOMPLETE_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED MCOMPLETE_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED_IN MCOMPLETE_DYADIC_APPROXIMATION MCOMPLETE_IMBEDDING_IN_LC_CONTINUUM MCOMPLETE_IMBEDDING_IN_LC_CONTINUUM_IN MCOMPLETE_IN_LOCALLY_COMPACT_IMP_LOCALLY_COMPACT MCOMPLETE_LOCALLY_CONNECTED_IMP_LOCALLY_PATH_CONNECTED MCOMPLETE_LOCALLY_PATH_CONNECTED_EQ_LOCALLY_CONNECTED OPEN_CONNECTED_FINE_COVER PEANO_GAP_FILLING_EXTENSION SECOND_COUNTABLE_CLOSED_MAP_IMAGE SEMI_LOCALLY_CONNECTED_COMPACT_SPACE SEMI_LOCALLY_CONNECTED_CONNECTED SEMI_LOCALLY_CONNECTED_GEN_SPACE SEPARABLE_METRIZABLE_IMP_SECOND_COUNTABLE New theorems in Multivariate/paths.ml: COMPACT_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED_EUCLIDEAN FINITE_CONNECTED_COMPONENTS_COMPACT_LOCALLY_CONNECTED_EUCLIDEAN GDELTA_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED GDELTA_LOCALLY_CONNECTED_IMP_LOCALLY_PATH_CONNECTED GDELTA_LOCALLY_PATH_CONNECTED_EQ_LOCALLY_CONNECTED LOCALLY_COMPACT_CONNECTED_IMP_PATH_CONNECTED_EUCLIDEAN LOCALLY_COMPACT_LOCALLY_CONNECTED_IMP_LOCALLY_PATH_CONNECTED_EUCLIDEAN LOCALLY_COMPACT_LOCALLY_PATH_CONNECTED_EQ_LOCALLY_CONNECTED_EUCLIDEAN LOCALLY_COMPACT_PATH_CONNECTED_EQ_CONNECTED_EUCLIDEAN MCOMPLETE_CONNECTED_LOCALLY_CONNECTED_IMP_PATH_CONNECTED_EUCLIDEAN MCOMPLETE_IMP_LOCALLY_COMPACT_EUCLIDEAN MCOMPLETE_LOCALLY_CONNECTED_IMP_LOCALLY_PATH_CONNECTED_EUCLIDEAN MCOMPLETE_LOCALLY_PATH_CONNECTED_EQ_LOCALLY_CONNECTED_EUCLIDEAN In Multivariate/paths.ml, three existing long Euclidean-specific proofs are replaced by short bridge derivations from the new general metric space versions: SEMI_LOCALLY_CONNECTED (222 lines reduced to 19), SEMI_LOCALLY_CONNECTED_GEN (65 lines reduced to 19), and LOCALLY_COMPACT_CONNECTED_IMP_PATH_CONNECTED (662 lines reduced to 15). All theorem statements are preserved; only the proofs change. The general metric space versions in metric.ml use a _SPACE suffix to distinguish them from existing Euclidean-specific theorems of the same logical content in paths.ml. For example, the general version is LOCALLY_COMPACT_CONNECTED_IMP_PATH_CONNECTED_SPACE while the Euclidean version retains its original name LOCALLY_COMPACT_CONNECTED_IMP_PATH_CONNECTED. Thu 26th Feb 2026 lib.ml, metis.ml Incorporated a cleanup and rationalization of METIS from Daniel Nezamabadi. The main changes are: * Applying the bug fixes from the upstream metis repo * Inlining various definitions, afterwards simplifying where reasonable * Removing duplicate and unused definitions * Replacing {foo=foo} pattern matching with {foo} * Removing the Order module in favor of OCaml's use of integers Wed 25th Feb 2026 Library/ringtheory.ml, Library/fieldtheory.ml Added some material about algebraically closed fields, with a definition algebraically_closed_field and new theorems ALGEBRAICALLY_CLOSED_FIELD_DECOMPOSE ALGEBRAICALLY_CLOSED_FIELD_EQ_IRREDUCIBLES ALGEBRAICALLY_CLOSED_FIELD_EQ_SPLITS ALGEBRAICALLY_CLOSED_FIELD_IMP_FIELD ALGEBRAICALLY_CLOSED_FIELD_IMP_INFINITE ALGEBRAICALLY_CLOSED_FIELD_ISOMORPHIC_IMAGE ALGEBRAICALLY_CLOSED_FIELD_NO_PROPER_ALGEBRAIC_EXTENSION ALGEBRAIC_CLOSURE_EXISTS ALGEBRAIC_CLOSURE_EXISTS_ID ALGEBRAIC_CLOSURE_EXTEND_HOMOMORPHISM ALGEBRAIC_CLOSURE_UNIQUE ALGEBRAIC_CLOSURE_UNIQUE_EXPLICIT FIELD_RING_HOMOMORPHISM_MONOMORPHISM INFINITE_INTEGRAL_DOMAIN_POLY_EVAL_ALL_ZERO ISOMORPHIC_RING_ALGEBRAICALLY_CLOSED_FIELD POLY_COMPOSE_HOMOMORPHISM_ADD POLY_COMPOSE_HOMOMORPHISM_CONST POLY_COMPOSE_HOMOMORPHISM_MUL POLY_COMPOSE_HOMOMORPHISM_NEG POLY_COMPOSE_HOMOMORPHISM_POW POLY_COMPOSE_HOMOMORPHISM_SUB POLY_COMPOSE_HOMOMORPHISM_VAR POLY_DEG_1_ROOT POLY_DEG_MUL_X_MINUS_A POLY_DEG_X_MINUS_A POLY_EVALUATE_RING_PRODUCT POLY_EVAL_RING_PRODUCT POLY_EXTEND_RING_PRODUCT POLY_X_MINUS_A_IN_CARRIER POLY_X_MINUS_A_NONZERO RING_HOMOMORPHISM_EPIMORPHISM_FACTOR RING_POWERSERIES SIMPLE_ALGEBRAIC_EXTEND_HOMOMORPHISM The existence proofs ALGEBRAIC_CLOSURE_EXISTS_ID and ALGEBRAIC_CLOSURE_EXISTS were done by John Harrison following Jelonek's paper "A simple proof of the existence of the algebraic closure of a field". The rest, such as various alternative characterizations and the uniqueness up to isomorphism, were written by Claude Opus 4.6. Sat 21st Feb 2026 100/cubedissection.ml [new file] Added a formalization of the impossibility of cube dissection into finitely many smaller cubes of pairwise distinct sizes ("cubing the cube"), originally proved by R. L. Brooks, C. A. B. Smith, A. H. Stone and W. T. Tutte, "The Dissection of Rectangles into Squares", Duke Mathematical Journal, vol. 7 (1940), pp. 312-340. The proof follows the elegant argument presented in J. E. Littlewood, "A Mathematician's Miscellany" (CUP, 1953), revised edition "Littlewood's Miscellany" (ed. B. Bollobas, CUP, 1986), pp. 28-29 and the HOL Light formalization was almost entirely written by Claude Code (Opus 4.6). Thu 19th Feb 2026 Multivariate/metric.ml Added some basic definitions and theorems about the Cantor space. The basic definition is as the product space (:num->bool), and this is then shown to be homeomorphic to its realization as the usual Cantor "excluded thirds" subset of [0,1]. New definitions: cantor_map cantor_set cantor_space cantor_term tendsto_real_def and theorems: CANTOR_MAP_CLOSED_IMAGE CANTOR_MAP_CLOSED_IN_INTERVAL CANTOR_MAP_CONTINUOUS CANTOR_MAP_EMBEDDING CANTOR_MAP_GE_PARTIAL_SUM CANTOR_MAP_IMAGE_SUBSET_INTERVAL CANTOR_MAP_INJECTIVE CANTOR_MAP_LE_ONE CANTOR_MAP_PARTIAL_SUM_BOUND CANTOR_MAP_POS CANTOR_MAP_RANGE CANTOR_MAP_STRICT_LT CANTOR_MAP_SUMMABLE CANTOR_MAP_SUMS CANTOR_PARTIAL_SUM_DIFF_AT_K CANTOR_PARTIAL_SUM_MONO CANTOR_SET_SUBSET_INTERVAL CANTOR_SPACE_HOMEOMORPHIC_CANTOR_SET CANTOR_TERM_BOUND CANTOR_TERM_CONTINUOUS CANTOR_TERM_POS CLOSED_IN_CANTOR_SET CLOSED_IN_CANTOR_SET_INTERVAL COMPACT_SPACE_CANTOR_SPACE HAUSDORFF_SPACE_CANTOR_SPACE METRIZABLE_SPACE_CANTOR_SPACE NONEMPTY_TOPSPACE_CANTOR_SPACE PERFECT_CANTOR_SPACE PERFECT_CANTOR_SPACE_EQ SUM_TWOTHIRDS TENDSTO_REAL_EPS_DELTA TOPSPACE_CANTOR_SPACE TWOTHIRDS_SUMS ZERO_DIMENSIONAL_CANTOR_SPACE The new definition "tendsto_real_def" is just a more basic definition of the usual notion of the sum of a real series, so that it can be used in the general topology theories without the artificially circuitous derivation via real^N. The former definition "tendsto_real" is now a derived theorem rather than a definition, but is equivalent. Thu 19th Feb 2026 Multivariate/metric.ml, Multivariate/topology.ml, Multivariate/paths.ml Added general metric space versions of well-chainedness, connectedness of chains, and the two uniform variants of local connectedness (ULC = uniformly locally connected and FCCOVERABLE = fine connected coverable, a.k.a. Whyburn's "Property S"), together with key results connecting them to local connectedness and compactness. The Euclidean special cases in paths.ml and topology.ml are then derived from the general versions. New definitions: fccoverable_in fccoverable_space ulc_space and new theorems: COMPACT_IN_LOCALLY_CONNECTED_EQ_FCCOVERABLE_SPACE COMPACT_IN_LOCALLY_CONNECTED_IMP_FCCOVERABLE_SPACE COMPACT_IN_LOCALLY_CONNECTED_IMP_ULC_SPACE COMPACT_IN_LOCALLY_CONNECTED_IMP_ULC_SPACE_ALT CONNECTED_COMPONENT_OF_EQ_WELLCHAINED CONNECTED_COMPONENT_OF_IMP_WELLCHAINED CONNECTED_EQ_WELLCHAINED_IN CONNECTED_IN_CHAIN CONNECTED_IN_CHAIN_GEN CONNECTED_IN_IFF_CONNECTED_COMPONENT_OF CONNECTED_IN_IMP_WELLCHAINED CONNECTED_IN_NEST CONNECTED_IN_NEST_GEN CONNECTED_IN_UNIONS_STRONG EPSILON_ABSORBING_IMP_CLOPEN FCCOVERABLE_IN_IMP_FCCOVERABLE_SPACE_SUBMETRIC FCCOVERABLE_IN_IMP_LOCALLY_CONNECTED_SPACE FCCOVERABLE_SPACE_EQ_FCCOVERABLE_IN_MSPACE FCCOVERABLE_SPACE_IMP_LOCALLY_CONNECTED_SPACE FCCOVERABLE_SPACE_INTERMEDIATE_CLOSURE IN_CLOSURE_OF_IMP_SUBSET_MCBALL MBALL_INTER_DSEPARATED_SINGLETON MDIAMETER_SUBSET_MBALL MDIAMETER_SUBMETRIC MDIST_TRIANGLE_LT NESTED_COMPACT_APPROX TOTALLY_BOUNDED_IMP_DISCRETE_FINITE TOTALLY_BOUNDED_ULC_SPACE_IMP_FCCOVERABLE_SPACE ULC_SPACE_IMP_LOCALLY_CONNECTED_SPACE WELLCHAINED_ELEMENTS WELLCHAINED_INTERS WELLCHAINED_SETS In Multivariate/topology.ml, the theorems CONNECTED_CHAIN, CONNECTED_CHAIN_GEN, CONNECTED_NEST and CONNECTED_NEST_GEN are rederived from their general topological counterparts. All theorem statements are preserved. In Multivariate/paths.ml, the Euclidean-specific theorems about ULC and FCCOVERABLE (FCCOVERABLE_IMP_LOCALLY_CONNECTED through COMPACT_LOCALLY_CONNECTED_EQ_FCCCOVERABLE) are rederived from the general metric space versions via a set of bridge lemmas connecting submetric euclidean_metric to the Euclidean topology. The well-chained theorems (CONNECTED_IMP_WELLCHAINED through CONNECTED_COMPONENT_EQ_WELLCHAINED) are similarly rederived. All theorem statements are preserved. Incompatible changes: In paths.ml, three Euclidean-specific theorems have been renamed with a _EUCLIDEAN suffix to avoid clashing with the new general versions in metric.ml that take the same names: WELLCHAINED_ELEMENTS -> WELLCHAINED_ELEMENTS_EUCLIDEAN WELLCHAINED_SETS -> WELLCHAINED_SETS_EUCLIDEAN WELLCHAINED_INTERS -> WELLCHAINED_INTERS_EUCLIDEAN These were not used outside their original block so the renaming should not affect other files. Several new Euclidean bridge lemmas are introduced in paths.ml (SUBMETRIC_EUCLIDEAN_METRIC, MTOPOLOGY_SUBMETRIC_EUCLIDEAN, MBOUNDED_SUBMETRIC_EUCLIDEAN, MDIAMETER_SUBMETRIC_EUCLIDEAN, and others) to support the derivations. The statements and proofs were almost entirely written by Claude Code (Opus 4.6). Thu 19th Feb 2026 Library/ringtheory.ml, Library/rabin_test.ml [new file] Added a proof of Rabin's test for irreducibility of polynomials over finite fields. The development, both statements and proofs, was entirely written by Claude Code (Opus 4.6, running on AWS Bedrock). A few lemmas have been slightly tweaked manually and placed in the ring theory file, since they seem more broadly applicable: POLY_DEG_1_IMP_IRREDUCIBLE POLY_DEG_EQ_0_UNIT POLY_DEG_UNIT RING_DIVIDES_SUB_POW RING_PRODUCT_CONST RING_PRODUCT_LMUL RING_SUB_TELESCOPE These are the theorems in the main Library/rabin_test.ml file culminating in RABIN_IRREDUCIBILITY_TEST: FIELD_NONZERO_PRODUCT_PERMUTE FIELD_ROOTS_BOUND FINITE_FIELD_ELEMENT_POW FINITE_FIELD_POW_ITERATE ING_DIVIDES_POW_ITERATE IRREDUCIBLE_DIVIDES_DEGREE IRREDUCIBLE_DIVIDES_DEGREE_BOUND IRREDUCIBLE_DIVIDES_XQ_MINUS_X IRREDUCIBLE_DIVIDES_XQ_MINUS_X_GEN IRRED_DIVIDES_POLY_EVAL_MINUS POLY_NONUNIT_DEGREE_GE_1 QUOTIENT_POLY_RING_FINITE_CARD RABIN_IRREDUCIBILITY_NECESSARY RABIN_IRREDUCIBILITY_SUFFICIENT RABIN_IRREDUCIBILITY_TEST RING_DIVIDES_REDUCE RING_ENDOMORPHISM_FROBENIUS_ITERATE Sun 15th Feb 2026 Multivariate/metric.ml, Multivariate/topology.ml, Multivariate/paracompact.ml [new file] Added a definition of paracompactness to the core general topology theory in Multivariate/metric.ml, with a large number of typical results about it including Stone's theorem that a metrizable space is paracompact and the existence of subordinate partitions of unity. Some results that seemed more specialized or obscure (e.g. Nagata-Smirnov metrization and Michael's characterization of paracompactness) are placed in a separate file Multivariate/paracompact.ml that is not part of the main Multivariate load sequence. The vast majority of the proofs, including all those in the Multivariate/paracompact.ml file, were automatically written by Claude Code (two separate instances with a mix of Opus 4.5 and 4.6). Sun 15th Feb 2026 itab.ml, unit_tests.ml Added a new UNIFY_REFL_TAC tactic from June Lee, which unifies metavariables in an equational goal ?- t = X where X is a metavariable by assigning X to t. Thu 29th Jan 2026 Multivariate/metric.ml, Multivariate/topology.ml, Multivariate/paths.ml Added a proof of Urysohn's metrization theorem and also a definition of set diameter for a general metric space, "mdiameter", with basic properties mirroring as appropriate those in the Euclidean special case "diameter". New definition: mdiameter and theorems: EMBEDDING_INTO_METRIZABLE_IMP_METRIZABLE LEBESGUE_COVERING_LEMMA LEBESGUE_COVERING_LEMMA_GEN MBOUNDED_AND_MDIAMETER_LE MBOUNDED_IMP_IN_MSPACE MDIAMETER_BOUNDED MDIAMETER_BOUNDED_BOUND MDIAMETER_CLOSURE MDIAMETER_COMPACT_ATTAINED MDIAMETER_EMPTY MDIAMETER_EQ_0 MDIAMETER_EUCLIDEAN MDIAMETER_LE MDIAMETER_POS_LE MDIAMETER_SING MDIAMETER_SUBSET MDIAMETER_SUBSET_MCBALL MDIAMETER_SUBSET_MCBALL_NONEMPTY MDIAMETER_UNION_LE METRIZABLE_PRODUCT_EUCLIDEANREAL_NUM REGULAR_SECOND_COUNTABLE_HAUSDORFF_IMP_NORMAL_SPACE SEPARATING_FUNCTIONS_INJECTIVE URYSOHN_METRIZATION URYSOHN_METRIZATION_EQ The two theorems LEBESGUE_COVERING_LEMMA / LEBESGUE_COVERING_LEMMA_GEN simply replace and generalize the original Euclidean theorems of that name. The sole current application now uses the more general versions. This update has the distinction of being almost entirely written by AI, mainly Claude Opus 4.5 via AWS Bedrock. It completed the following requests entirely autonomously: * Generalize the existing "diameter" theorems as appropriate * Autoformalize Urysohn Metrization starting from Munkres's book This was inspired by, and in the latter case largely reproduces, work by Josef Urban reported in https://arxiv.org/abs/2601.03298, with the HOL Light setup due to June Lee. Thu 8th Jan 2026 hol_4.14.sh, holtest.mk, holtest_parallel, TacticTrace/passim Adopted a patch from June Lee with many improvements focused on TacticTrace: - Fixes TacticTrace to support OCaml 5.4 - Add an example to TacticTrace. This can be checked with `make test` inside TacticTrace dir, as well as make -f holtest.mk /tmp/hol-light-test/TacticTrace/make-test.ready`. - For easier compilation and inlining of HOL Light proofs, add the following options to hol_4.14.sh: * hol.sh compile * hol.sh link * hol.sh inline-load Updates to hol_4.sh is not necessary because OCaml 4.14 is the minimal version that supports proof compilation. - Also add `hol.sh -use-module` which prints 1 if HOLLIGHT_USE_MODULE was set when built (0 otherwise) - Slighly simplify TacticTrace by removing the usage of TACLOGGER_DIR env variable. Mon 8th Dec 2025 Library/words.ml, Examples/bitblast.ml Fixed a bug in bit-blasting where the conversion from arithmetical to word form was being missed in some cases where arithmetic is nested inside other word operations (possibly after other normalizations that started in word form). The fix is to use DEPTH_CONV in place of ONCE_DEPTH_CONV for the WORDIFY_ATOM_CONV and IWORDIFY_ATOM_CONV conversions. For example, this case formerly failed but now works: BITBLAST_RULE `!x:int64. let y = word_and x (word_sub (word_or x (word 0x0800800800800800)) (word 0x0501501501501501)) in let z = word_ushr (word_and y (word 0x0800800800800800)) 11 in bitval(word_uge (word_subword x (0,12):int16) (word 3329)) + bitval(word_uge (word_subword x (12,12):int16) (word 3329)) + bitval(word_uge (word_subword x (24,12):int16) (word 3329)) + bitval(word_uge (word_subword x (36,12):int16) (word 3329)) + bitval(word_uge (word_subword x (48,12):int16) (word 3329)) = val(word_ushr (word_mul z (word 0x100100100100100)) 56)`;; Added this and a few other new ones to Examples/bitblast.ml Wed 3rd Dec 2025 Library/words.ml Made a small fix in WORD_SIMPLE_SUBWORD_CONV, which was failing to make the simple simplifications based on WORD_SUBWORD_TRIVIAL if the word operation was a composite term matching one of the other cases, e.g. WORD_SIMPLE_SUBWORD_CONV `(word_subword:(16)word->num#num->(16)word) ((word_join:byte->byte->int16) h l) (0,16)`;; Mon 17th Nov 2025 .github/workflows/main.yml, Help/list_mk_exists.hlp, META, Makefile, opam, pa_j/chooser.sh [new file], pa_j/pa_j_5.4_8.04.00.ml [new file], unit_tests.ml, update_database/chooser.sh [new file], update_database/update_database_5.4.ml [new file] Set up appropriate new versions of pa_j and update_database code to work smoothly with OCaml 5.4 (from June Lee). This includes a significant rationalization and cleanup of the version-dependent choosing code. This update also removes a dangling reference in the Help/list_mk_exists.hl file to a nonexistent function EXISTS_EQ, probably a cut-and-paste error wrongly inherited from HOL88 that does/did have such a function. Mon 20th Oct 2025 Library/words.ml Type-generalized the existing theorems WORD_SUBWORD_AS_IWORD and WORD_SUBWORD_IWORD to allow two distinct source and destination word types; the constraint and even the proofs are unchanged. Mon 20th Oct 2025 Library/words.ml Added a couple more theorems about subwords of composite terms: WORD_SUBWORD_ZX = |- !x pos len. MIN (pos + dimindex(:P)) (dimindex(:M)) <= dimindex(:N) ==> word_subword ((word_zx:M word->N word) x) (pos,len):P word = word_subword x (pos,len) WORD_SUBWORD_ZX_TRIVIAL = |- !x pos len. MIN (dimindex(:M)) (dimindex(:N)) <= pos ==> word_subword ((word_zx:M word->N word) x) (pos,len):P word = word 0 and upgraded WORD_SIMPLE_SUBWORD_CONV to make use of those where applicable as well as its existing theorems. This for example makes the following work: WORD_SIMPLE_SUBWORD_CONV `word_subword ((word_zx:int256->int128) x) (16,16):int16`;; WORD_SIMPLE_SUBWORD_CONV `word_subword ((word_zx:int32->int64) x) (48,8):byte`;; Sun 21st Sep 2025 TacticTrace/* [new directory] Added the TacticTrace tools from June Lee, which allow the user to log in JSON format the input/output of tactics and conversions; see the TacticTrace/README.md for more detailed instructions. Sun 21st Sep 2025 metis.ml Adopted a fix from Frederic Blanqui to use the more portable local "float_sqrt" in place of unqualified "sqrt" inside "metis.ml". Fri 19th Sep 2025 Library/words.ml Fixed an over-specialization in the type of "usimd16", which is now in line with "usimd2", "usimd4" and "usimd8". Tue 15th Jul 2025 Makefile, inline_load.ml, pa_j/pa_j_4.xx_8.03.06.ml [new file] Added support for camlp5 8.03.06, from June Lee. This version of camlp5 fixes support for line number directives so one can get better location information for debugging. For example: # Printexc.record_backtrace true;; # #100 "dummy.ml";; failwith ".";; Thu 3rd Jul 2025 Jordan/jordan_curve_theorem.ml, Jordan/metric_spaces.ml, Jordan/misc_defs_and_lemmas.ml, Jordan/tactics_ext2.ml, Help/new_basic_type_definition.hlp, Help/new_type_definition.hlp Adopted a patch from Dan Bernstein to replace the use of pointer-level inequality != with structural inequality <> inside the "Jordan" proofs as was presumably intended, appropriately fixing up the breaks that result (patch taken from https://holtrace.cr.yp.to/jordan310.diff). Improved the type definition documentation by emphasizing explicitly that failure will also occur when the desired names of the abstraction and representation functions to and from the new type are the same. Fri 6th Jun 2025 tactics.ml, unit_tests.ml Added a new 'expand and rotate" function er to the goalstack package, from June Lee. The call `er tac` applies `e tac` followed by `r n` where `n` is the number of subgoals generated by `tac`. This command is useful when you want to interactively try a list of tactics after `THENL`. For example, given a proof `TAC THENL [ TAC_A; TAC_B; .. ]', statements `e TAC;; er TAC_A;;' will execute `TAC`, execute `TAC_A`, then switch to the second subgoal of `e TAC' which will be the input goalstate of `TAC_B`. Tue 3rd Jun 2025 Library/fieldtheory.ml Extended the field theory library, mainly with definitions of algebraic dependence, transcendence bases and related concepts, and a derivation of some of their expected properties. The new definitions are: algebraic_matroid algebraic_span algebraically_dependent algebraically_independent algebraically_spanning transcendence_basis There is no explicit definition of transcendence degree, but it is handled via the cardinality of a transcendence basis, e.g. in the additivity of transcendence degrees in TRANSCENDENCE_BASIS_TOWER_LAW. The properties around algebraic dependence and span are as usual derived from matroids, roughly following Pete Clark's online "Field Theory" notes, section 11.4. One small application to the earlier material on finite extensions is the reverse transitivity/compositionality property for finitely generated extensions, FINITELY_GENERATED_EXTENSION_TRANS_EQ, largely taken from theorem 24.9 in Isaacs: "Algebra: A Graduate Course". Thu 29th May 2025 ind_defs.ml, unit_tests.ml Added an improvement to benign-redefinition checking for inductive definitions, written by June Lee. This previously was too crude in comparing with the earlier definition, not taking account of additional universally quantified variables, so didn't work properly in many cases. For example, the definitions in "GL/completeness.ml" and "Library/fieldtheory.ml" used to fail to load twice but now work smoothly. Sat 24th May 2025 Library/fieldtheory.ml Added a new file giving a basic development of field theory, first some basic constructs about subfields and subfields generated by a set (which could arguably be put back in Library/ringtheory.ml) followed by standard properties of field extensions: finite, fintely generated and algebraic. This includes the general (finite or infinite) tower law for the degree of an extension field. Fri 23rd May 2025 Library/ringtheory.ml, 100/transcendence.ml Imported one more theorem (now called POWSER_MUL_CONST) from Dan Bernstein's development in 100/transcendence.ml back to the Library ring theory file; this generalizes POLY_MUL_CONST and now trivializes its proof. Fri 23rd May 2025 printer.ml Made a trivial recoding to one printer function so that it works smoothly on older OCamls, where the Option-type material is in a different place. Wed 21st May 2025 unit_tests.ml Added some unit tests for EL_CONV, LENGTH_CONV, REVERSE_CONV and LIST_OF_SEQ_CONV, via a generic "test a conversion" function called assert_conv. Tue 20th May 2025 ProofTrace/README, ProofTrace/fusion.ml.diff Adopted an update from Dan Bernstein to bring the fusion.ml patch inside ProofTrace into step with the current version of fusion.ml, as well as to make the guidance on file sizes more explicit. Tue 20th May 2025 hol.ml, printer.ml, tactics.ml, Library/bitmatch.ml Merged an update from June Lee adding a systematic set of color printing functions, and applying them pervasively when printing to the terminal any types, terms, theorems and goals. This colorization is enabled by default, but can be enabled or disabled explicitly with set_color_printer true;; set_color_printer false;; Tue 20th May 2025 lists.ml Added a few elementary list lemmas: LENGTH_EQ_LIST_OF_SEQ = |- forall l n. LENGTH l = n <=> l = list_of_seq (\i. EL i l) LENGTH_FILTER = |- forall P l. LENGTH (FILTER P l) <= LENGTH l LIST_OF_SEQ = |- (forall f. list_of_seq f 0 = []) /\ (forall f n. list_of_seq f (SUC n) = CONS (f 0) (list_of_seq (f o SUC) n)) LIST_OF_SEQ_EQ_SELF = |- forall l. list_of_seq (\i. EL i l) (LENGTH l) = l MAP_LIST_OF_SEQ = |- forall f g n. MAP g (list_of_seq f n) = list_of_seq (g o f) n as well as explicit conversions for the list functions EL, LENGTH, list_of_seq and REVERSE: EL_CONV LENGTH_CONV LIST_OF_SEQ_CONV REVERSE_CONV Tue 13th May 2025 lists.ml Added one straightforward list theorem that seems an odd gap: LENGTH_FILTER |- !P l. LENGTH(FILTER P l) <= LENGTH l Thu 1st May 2025 .gitignore, Makefile, README, hol_4.14.sh, hol_4.sh, make-checkpoint.sh, make.ml [deleted] Added an update from June Lee to support DMTCP-checkpointing more conveniently, including updating the existing but obselete Makefile targets like "hol" and "hol.multivariate". The basic script to create a checkpoint is "make-checkpoint.sh", which can simply create a HOL Light image: make-checkpoint.sh ~/my-checkpoint.sh or a HOL Light image with more code and proofs pre-loaded, e.g. cd ~/s2n-bignum ~/hol-light/make-checkpoint.sh ./my-s2n-bignum-checkpoint.sh "loadt \"arm/proofs/base.ml\"" Mon 21st Apr 2025 Library/word_automata.ml [new file], Examples/bitblast_generic.ml [new file] Added yet another machine word (bitvector) automated proof procedure WORD_AUTO_RULE / WORD_AUTO_TAC, an "arbitrary width" form of bit-blasting for problems involving a single generic word type like `:N word`, not restricted to a specific wordsize. This works internally by treating certain tuples of bits (of inputs, outputs and other subexpressions) as states in an automaton evolving over the sucessive bit positions from the LSB, with standard BDD-based reachability used to test satisfiability. The other new file gives a set of examples, one of which is: WORD_AUTO_RULE `!x y:N word. word_sub x y = word_sub (word_mul (word 2) (word_and x (word_not y))) (word_xor x y)`;; Supporting this are some additions to the BDD code (adding a function for existential quantification over a Boolean variable) and the existing fixed-size bitblasting procedure (handling signed comparisons more comprehensively). Sat 12th Apr 2025 bignum_zarith.ml, unit_tests.ml Fixed the power_num function in the Zarith version to be consistent with the Num library version in handling rational numbers for the base. Fri 4th Apr 2025 Library/matroids.ml, Library/ringtheory.ml, 100/transcendence.ml Made some more additions to matroid and ring background theory, in particular moving a little of the generally useful material from 100/transcendence.ml into the core Library/ringtheory.ml. This includes the definitions of poly_pow - polynomial powers poly_reindex - reindexing polynomial variables over a given ring together with the suite of useful lemmas that were proved there (sometimes with superficial stylistic differences). Sun 16th Mar 2025 equal.ml, hol_loader.ml, lib.ml, printer.ml, tactics.ml Added REMARK_TAC and PRINT_TERM_CONV, a dummy tactic and conversions (equivalent to ALL_TAC and ALL_CONV) but producing informative output, in the first case a string and in the second printing the term to which the conversion is applied. This also fixes a bug in the tracking of loaded files in the presence of use_file_raise_failure and a couple of other minor typos. Wed 12th Mar 2025 hol_loader.ml, Help/loadt.hlp, Help/load_path.hlp Added a facility from June Lee to read additional load_path directories from an environment variable HOLLIGHT_LOAD_PATH, so you can do something like this before starting HOL Light: export HOLLIGHT_LOAD_PATH=/home/me/hol_project:/tmp/otherdir Wed 5th Mar 2025 Library/binomial.ml, Library/primitive.ml Renamed the existing theorem DIVIDES_BINOM_PRIME to DIVIDES_PRIME_BINOM, and moved it from Library/primitive.ml to a more thematic spot in Library/binomial.ml, together with a couple of generalizations: DIVIDES_COPRIME_BINOM = |- forall n k. coprime(n,k) ==> n divides binom(n,k) DIVIDES_GCD_BINOM = |- forall n k. n divides gcd(n,k) * binom(n,k) Thu 20th Feb 2025 lib.ml, unit_tests.ml, Help/index.hlp, find_index.hlp [new file] Added the library function "find_index" corresponding exactly to the function List.find_index in the OCaml library for versions >= 5. Thu 13th Feb 2025 Library/words.ml, Examples/bitblast.ml Enhanced the bit-blasting rule and tactic to handle signed integer comparisons as well as unsigned ones in the top-level atomic formulas, basically by adding analogs of WORDIFY_CONV and related functions for integers instead of natural numbers, like IWORDIFY_CONV. It would be possible to rewrite away natural number atoms into integer ones (e.g. using INT_OF_NUM_LT) and then just avoid the natural number ones entirely, reducing the amount of highly analogous but different code. But it would occasionally have a small impact on the word sizes used. Fri 7th Feb 2025 define.ml, unit_tests.ml Added a fix from June Lee for a subtle problem over benign redefinitions in "define". When the definition is presented in the typical way via term quotation, the underlying term is different when the function is first defined (when a variable takes the place of the constant to be defined) and when a benign redefinition occurs (when it actually parses as that constant). This means that if the constant is polymorphic, it is possible to have more general type instantiations in the latter case, assigning different types to different instances of the constant. By contrast, all variables of the same name in the same scope are assumed to have the same type in the quotation parser. For example: # `(h:A list -> num) [] = 0 /\ h (CONS _ t) = 1 + h t`;; <-- `h` is a variable, so the second `h` in the right clause is also typed as `A list -> num` # define `(h:A list -> num) [] = 0 /\ h (CONS _ t) = 1 + h t`;; <-- makes `h` a constant # `(h:A list -> num) [] = 0 /\ h (CONS _ t) = 1 + h t`;; <-- now `h` is a constant, so the second `h` in the right clause is assigned `:(?143198)list->num` # define `(h:A list -> num) [] = 0 /\ h (CONS _ t) = 1 + h t`;; Warning: inventing type variables Exception: Failure "close_definition_clauses: defining multiple functions". The redefinition above now works correctly as expected. Thu 23rd Jan 2025 compute.ml, unit_tests.ml Added the basic_compset() function from June Lee, which creates a fuller elementary compeset than bool_compset, also including the basic rewrites at the time of the call. Tue 21st Jan 2025 hol_lib.ml, unit_tests.ml Added the check_axioms() function from June Lee, which makes a check that no new axioms were introduced at call time, i.e. no axioms beyond the three standard HOL axioms ETA_AX, INFINITY_AX and SELECT_AX. Wed 15th Jan 2025 sets.ml Added preprocessing of the constants BIJ, INJ and SURJ (bijection, injection and surjection) to SET_TAC and hence to SET_RULE, e.g. SET_RULE `BIJ (\x. b) {a} {b}`;; Sat 21st Dec 2024 100/transcendence.ml [new file] Added a development of transcendence theory from Daniel J. Bernstein, currently a verbatim copy of the original: https://cr.yp.to/2024/transcendence-20241221.ml This, among other results, re-proves the transcendence of e (using a different approach from "100/e_is_transcendental.ml") and proves the transcendence of pi: e_is_transcendental = |- ~algebraic_number (cexp (Cx (&1))) pi_is_transcendental = |- ~algebraic_number (Cx pi) as well as the full Lindemann theorem, which easily implies both of those and more: zero_sum_algebraic_exp_algebraic = |- forall S B. FINITE S /\ S SUBSET algebraic_number /\ (forall s. s IN S ==> algebraic_number (B s)) /\ ring_sum complex_ring S (\s. B s * cexp s) = Cx (&0) ==> (forall s. s IN S ==> B s = Cx (&0)) This more general theorem is also commonly known as Hermite-Lindemann or Lindemann-Weierstrass; see the notes near the top of the file for some historical notes and overview of the proofs. Wed 20th Nov 2024 Makefile, calc_int.ml, calc_num.ml, calc_rat.ml, int.ml, unit_tests.ml, Library/words.ml Merged an update from June Lee adding conversions xxx_COMPUTE_CONV analogous to the existing xxx_REDUCE_CONV but using the call-by-value computational machinery in compute.ml: NUM_COMPUTE_CONV - natural numbers (type `:num`) INT_COMPUTE_CONV - integers (type `:int`) REAL_INT_COMPUTE_CONV - integer-valued reals (type `:real`) REAL_RAT_COMPUTE_CONV - rational-valued reals (type `:real`) WORD_COMPUTE_CONV - machine words (type `:N word` for specific N) Thu 7th Nov 2024 Multivariate/vectors.ml, Library/matroids.ml [new file] Factored the material about linear dependence, span and dimension out of the specific setting of vectors in R^n and set it up as a general theory of "matroids". These don't have all the finiteness assumptions common in matroid theory, but could be considered as "finitary" (matroid span is assumed to have finite character). The setup roughly follows Pete Clark's "Field Theory" notes, 11.4: http://alpha.math.uga.edu/~pete/FieldTheory.pdf Wed 6th Nov 2024 Library/words.ml Added one more theorem relating subwords and duplication, which is also now exploited inside WORD_SIMPLE_SUBWORD_CONV: WORD_SUBWORD_DUPLICATE_DUPLICATE = |- !x pos len. pos MOD dimindex (:M) = 0 /\ dimindex (:P) <= len /\ pos + len <= dimindex (:N) ==> word_subword (word_duplicate x) (pos,len) = word_duplicate x Wed 6th Nov 2024 int.ml Slightly refined the improvements to div/rem elimination made recently, to avoid exponential blowups while preserving the ability to deduce nonnegativity of the quotient in "easy" cases. Fri 1st Nov 2024 Library/words.ml Added both unsigned and signed *saturating* conversions from N and Z to machine words, which rather than wrapping modulo 2^wordsize as the main "word" and "iword" do, saturate at the extremal values of that size: word_saturate = |- word_saturate n = if n > val word_UINT_MAX then word_UINT_MAX else word n iword_saturate = |- iword_saturate x = if x < ival word_INT_MIN then word_INT_MIN else if x > ival word_INT_MAX then word_INT_MAX else iword x Also added a natural "word_duplicate" operation, a kind of iterated word_join inferring relative sizes and hence number of duplicates from the types. word_duplicate = |- (word_duplicate:M word->N word) x = word_of_bits {i | bit (i MOD dimindex (:M)) x There are also a few elementary lemmas about it: BIT_WORD_DUPLICATE = |- !x i. bit i (word_duplicate x) <=> i < dimindex(:N) /\ bit (i MOD dimindex(:M)) x VAL_WORD_DUPLICATE = |- !x k. dimindex(:N) <= k * dimindex(:M) ==> val (word_duplicate x) = ((2 EXP (k * dimindex(:M)) - 1) DIV (2 EXP dimindex(:M) - 1) * val x) MOD 2 EXP dimindex(:N) WORD_DUPLICATE = |- !m k. dimindex(:N) <= k * dimindex(:M) ==> word_duplicate (word m) = word ((2 EXP (k * dimindex(:M)) - 1) DIV (2 EXP dimindex(:M) - 1) * m MOD 2 EXP dimindex(:M)) WORD_DUPLICATE_DOUBLE = |- !x. word_duplicate (word_join x x) = word_duplicate x WORD_DUPLICATE_REFL = |- !x. word_duplicate x = x WORD_SUBWORD_DUPLICATE = |- !x pos len. pos MOD dimindex(:M) + len <= dimindex(:M) /\ pos + len <= dimindex(:N) ==> word_subword (word_duplicate x) (pos,len) = word_subword x (pos MOD dimindex(:M),len) The relevant conversions like BIT_WORD_CONV, SIMPLE_WORD_SUBWORD_CONV and WORD_RED_CONV have all been updated to take these three new operations into account. Tue 22nd Oct 2024 Library/words.ml Added several new lemmas for "simple subwords of composite word expressions": WORD_SUBWORD_INSERT_INNER WORD_SUBWORD_INSERT_OUTER WORD_SUBWORD_JOIN_LOWER WORD_SUBWORD_JOIN_UPPER WORD_SUBWORD_SUBWORD WORD_SUBWORD_TRIVIAL as well as a new conversion WORD_SIMPLE_SUBWORD_CONV that packages them up into a simplifying function, e.g. # WORD_SIMPLE_SUBWORD_CONV `word_subword (x:int16) (0,16):int16`;; val it : thm = |- word_subword x (0,16) = x # WORD_SIMPLE_SUBWORD_CONV `word_subword (word_join (x:int16) (y:int16):int32) (0,16):int16`;; val it : thm = |- word_subword (word_join x y) (0,16) = word_subword y (0,16) # WORD_SIMPLE_SUBWORD_CONV `word_subword (word_subword (x:int64) (32,32):int32) (0,16):int16`;; val it : thm = |- word_subword (word_subword x (32,32)) (0,16) = word_subword x (32,16) Tue 22nd Oct 2024 README, hol.ml, hol_4.sh, hol_4.14.sh, opam [new file], META [new file] Added updates from June Lee with new files containing metadata for opam, as well as appropriately updated instructions in README to reflect that fact that now HOL Light can indeed now be installed via opam. This update also increases the version string to "3.0.0+" to reflect the freezing of a release of that name on the github page and adds a new option "-dir" to the hol.sh script that will print the HOL Light directory. Wed 16th Oct 2024 Library/ringtheory.ml Fixed identical degenerate-case bugs in the decision procedures RING_RULE and INTEGRAL_DOMAIN_RULE (the latter bug being also inherited by FIELD_TAC). Previously these would fail if the input problem was so trivial that the initial normalization converted it to "true", e.g. RING_RULE `x:A = ring_1 r ==> x = ring_1 r`;; INTEGRAL_DOMAIN_RULE `ring_mul r x z = y ==> ring_mul r x z = y`;; Wed 16th Oct 2024 int.ml Fixed a couple of bugs in the handling of div/rem in INT_ARITH that were collectively limiting its ability to reason about formulas using several div/rem operations with distinct arguments. For example, this didn't work before but now does: let hbar = prove (`!x. abs x <= &2 pow 15 ==> let sqdmulh = (&2 * &0x4ebf * x) div &2 pow 16 in let srshr = (sqdmulh + &2 pow 10) div &2 pow 11 in abs(x - &3329 * srshr) <= &1664`, CONV_TAC(TOP_DEPTH_CONV let_CONV) THEN INT_ARITH_TAC);; Sat 12th Oct 2024 update_database/passim [new directory] Merged updates from June Lee completing support for OCaml version 5. As well as fixing deprecated functions and adding a new "switch-5" option in the Makefile, this enables the use of dynamic updating of the theorem search database, which was a significant gap in earlier OCaml 5 support. As part of this, the "update_database*.ml" files have been moved to a new subdirectory "update_database". 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)) Wed 19th Jun 2024 Library/bdd.ml Changed the data structures in the BDD code that are used to store the "unique" and "computed" tables from arrays to finite partial functions. This costs a small but noticeable amount in average-case performance since lookup is now log(n) instead of constant time. But it also avoids inherent arbitrary limits and so sometimes lets the code scale to somewhat larger problems. 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 " &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". 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 .ml Added a recent copyright banner to all the ML files, except the "pa_j.ml" ones. Fri 3rd Jun 05 hol.ml, Examples/ 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 Ported HOL Light from CAML Light to OCaml (3.04), with hacked syntax to make "*" 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 . 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_" and "dest_" to "_mk_" and "_dest_". 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 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 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 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.