Miscellaneous HOL Examples
December 12, 2016
Contents
1 Some Isar command definitions 15 1.1 Diagnostic command: no state change...... 16 1.2 Old-style global theory declaration...... 16 1.3 Local theory specification...... 16
2 Infinite Sets and Related Concepts 17 2.1 Infinitely Many and Almost All...... 18 2.2 Enumeration of an Infinite Set...... 21
3 Ad Hoc Overloading 24 3.1 Plain Ad Hoc Overloading...... 24 3.2 Adhoc Overloading inside Locales...... 25
4 Permutation Types 27
5 Example of Declaring an Oracle 29 5.1 Oracle declaration...... 29 5.2 Oracle as low-level rule...... 29 5.3 Oracle as proof method...... 30
6 Abstract Natural Numbers primitive recursion 34
7 Proof by guessing 37
8 Examples of function definitions 38 8.1 Very basic...... 38 8.2 Currying...... 38 8.3 Nested recursion...... 38 8.3.1 Here comes McCarthy’s 91-function...... 39 8.4 More general patterns...... 39 8.4.1 Overlapping patterns...... 39 8.4.2 Guards...... 40
1 8.5 Mutual Recursion...... 41 8.6 Definitions in local contexts...... 41 8.7 fun-cases ...... 42 8.7.1 Predecessor...... 42 8.7.2 List to option...... 42 8.7.3 Boolean Functions...... 43 8.7.4 Many parameters...... 43 8.8 Partial Function Definitions...... 43 8.9 Regression tests...... 43 8.9.1 Context recursion...... 44 8.9.2 A combination of context and nested recursion.... 44 8.9.3 Context, but no recursive call...... 44 8.9.4 Tupled nested recursion...... 44 8.9.5 Let...... 44 8.9.6 Abbreviations...... 45 8.9.7 Simple Higher-Order Recursion...... 45 8.9.8 Pattern matching on records...... 45 8.9.9 The diagonal function...... 45 8.9.10 Many equations (quadratic blowup)...... 46 8.9.11 Automatic pattern splitting...... 46 8.9.12 Polymorphic partial-function...... 46
9 Examples of automatically derived induction rules 47 9.1 Some simple induction principles on nat...... 47
10 Test of Locale Interpretation 48
11 Interpretation of Defined Concepts 48 11.1 Lattices...... 48 11.1.1 Definitions...... 48 11.1.2 Total order <= on int ...... 57 11.1.3 Total order <= on nat ...... 58 11.1.4 Lattice dvd on nat ...... 59 11.2 Group example with defined operations inv and unit ..... 61 11.2.1 Locale declarations and lemmas...... 61 11.2.2 Interpretation of Functions...... 65
12 Using extensible records in HOL – points and coloured points 66 12.1 Points...... 67 12.1.1 Introducing concrete records and record schemes... 67 12.1.2 Record selection and record update...... 67 12.1.3 Some lemmas about records...... 67 12.2 Coloured points: record extension...... 69 12.2.1 Non-coercive structural subtyping...... 70
2 12.3 Other features...... 70 12.4 A more complex record expression...... 72 12.5 Some code generation...... 72
13 A general “while” combinator 72 13.1 Partial version...... 72 13.2 Total version...... 76
14 An application of the While combinator 82 14.1 Example...... 82
15 Monoids and Groups as predicates over record schemes 83
16 Binary arithmetic examples 83 16.1 Regression Testing for Cancellation Simprocs...... 83 16.2 Arithmetic Method Tests...... 85 16.3 The Integers...... 86 16.4 The Natural Numbers...... 89 16.5 Real Arithmetic...... 91 16.5.1 Addition...... 91 16.5.2 Negation...... 91 16.5.3 Multiplication...... 91 16.5.4 Inequalities...... 91 16.5.5 Powers...... 92 16.5.6 Tests...... 92 16.6 Complex Arithmetic...... 98
17 Examples for hexadecimal and binary numerals 99
18 Antiquotations 99
19 Multiple nested quotations and anti-quotations 100
20 Partial equivalence relations 101 20.1 Partial equivalence...... 101 20.2 Equivalence on function spaces...... 102 20.3 Total equivalence...... 103 20.4 Quotient types...... 103 20.5 Equality on quotients...... 104 20.6 Picking representing elements...... 105
21 Summing natural numbers 106
3 22 Three Divides Theorem 108 22.1 Abstract...... 108 22.2 Formal proof...... 108 22.2.1 Miscellaneous summation lemmas...... 108 22.2.2 Generalised Three Divides...... 109 22.2.3 Three Divides Natural...... 110
23 The Cubic and Quartic Root Formulas 112
24 The Cubic Formula 112
25 The Quartic Formula 115
26 The Pythagorean Theorem 115
27 Higher-Order Logic: Intuitionistic predicate calculus prob- lems 116
28 CTL formulae 122 28.1 Basic fixed point properties...... 123 28.2 The tree induction principle...... 125 28.3 An application of tree induction...... 127
29 Arithmetic 127 29.1 Splitting of Operators: max, min, abs, op −, nat, op mod, op div ...... 128 29.2 Meta-Logic...... 130 29.3 Various Other Examples...... 130
30 2-3 Trees 132
31 (Finite) multisets 141 31.1 The type of multisets...... 141 31.2 Representing multisets...... 142 31.3 Basic operations...... 144 31.3.1 Conversion to set and membership...... 144 31.3.2 Union...... 146 31.3.3 Difference...... 147 31.3.4 Equality of multisets...... 149 31.3.5 Pointwise ordering induced by count...... 151 31.3.6 Intersection and bounded union...... 155 31.3.7 Additional intersection facts...... 156 31.3.8 Additional bounded union facts...... 159 31.3.9 Subset is an order...... 160 31.4 Replicate and repeat operations...... 160
4 31.4.1 Simprocs...... 161 31.4.2 Conditionally complete lattice...... 162 31.4.3 Filter (with comprehension syntax)...... 167 31.4.4 Size...... 169 31.5 Induction and case splits...... 171 31.5.1 Strong induction and subset induction for multisets. 172 31.6 The fold combinator...... 173 31.7 Image...... 175 31.8 Further conversions...... 177 31.9 More properties of the replicate and repeat operations.... 183 31.10Big operators...... 184 31.11Alternative representations...... 191 31.11.1 Lists...... 191 31.12The multiset order...... 195 31.12.1 Well-foundedness...... 195 31.12.2 Closure-free presentation...... 198 31.13The multiset extension is cancellative for multiset union... 199 31.14Quasi-executable version of the multiset extension...... 200 31.14.1 Partial-order properties...... 201 31.14.2 Monotonicity of multiset union...... 203 31.14.3 Termination proofs with multiset orders...... 203 31.15Legacy theorem bindings...... 206 31.16Naive implementation using lists...... 208 31.17BNF setup...... 212 31.18Size setup...... 219
32 Bubblesort 219
33 Merge Sort 221
34 A lemma for Lagrange’s theorem 222
35 Groebner Basis Examples 223 35.1 Basic examples...... 223 35.2 Lemmas for Lagrange’s theorem...... 224 35.3 Colinearity is invariant by rotation...... 225
36 Substitution and Unification 225 36.1 Terms...... 226 36.2 Substitutions...... 226 36.3 Unifiers and Most General Unifiers...... 228 36.4 The unification algorithm...... 229 36.5 Properties used in termination proof...... 229 36.6 Termination proof...... 233
5 36.7 Unification returns a Most General Unifier...... 233 36.8 Unification returns Idempotent Substitution...... 234
37 Primitive Recursive Functions 236 37.1 Ackermann’s Function...... 236 37.2 Primitive Recursive Functions...... 238
38 The Full Theorem of Tarski 241 38.1 Partial Order...... 244 38.2 sublattice...... 248 38.3 lub...... 248 38.4 glb...... 250 38.5 fixed points...... 251 38.6 lemmas for Tarski, lub...... 251 38.7 Tarski fixpoint theorem 1, first part...... 252 38.8 interval...... 253 38.9 Top and Bottom...... 256 38.10fixed points form a partial order...... 257
39 Classical Predicate Calculus Problems 260 39.1 Traditional Classical Reasoner...... 260 39.1.1 Pelletier’s examples...... 260 39.1.2 Classical Logic: examples with quantifiers...... 262 39.1.3 Problems requiring quantifier duplication...... 262 39.1.4 Hard examples with quantifiers...... 263 39.1.5 Problems (mainly) involving equality or functions.. 266 39.2 Model Elimination Prover...... 268 39.2.1 Pelletier’s examples...... 269 39.2.2 Classical Logic: examples with quantifiers...... 270 39.2.3 Hard examples with quantifiers...... 271
40 Set Theory examples: Cantor’s Theorem, Schr¨oder-Bernstein Theorem, etc. 277 40.1 Examples for the blast paper...... 277 40.2 Cantor’s Theorem: There is no surjection from a set to its powerset...... 278 40.3 The Schr¨oder-BernsteinTheorem...... 278 40.4 A simple party theorem...... 279
41 Examples and regression tests for automated termination proofs 281 41.1 Manually giving termination relations using relation and mea- sure ...... 281 41.2 lexicographic-order: Trivial examples...... 282
6 41.3 Examples on natural numbers...... 282 41.4 Simple examples with other datatypes than nat, e.g. trees and lists...... 283 41.5 Examples with mutual recursion...... 284 41.6 Refined analysis: The size-change method...... 284
42 Coherent Logic Problems 286 42.1 Equivalence of two versions of Pappus’ Axiom...... 286 42.2 Preservation of the Diamond Property under reflexive closure 287
43 Some examples for Presburger Arithmetic 288
44 Generic reflection and reification 290
45 Examples for generic reflection and reification 291
46 Factorial (semi)rings 301 46.1 Irreducible and prime elements...... 301 46.2 Generalized primes: normalized prime elements...... 308 46.3 In a semiring with GCD, each irreducible element is a prime elements...... 313 46.4 Factorial semirings: algebraic structures with unique prime factorizations...... 314 46.5 GCD and LCM computation with unique factorizations... 331
47 Abstract euclidean algorithm 339 47.1 Typical instances...... 354
48 Primes 354 48.0.1 Make prime naively executable...... 358 48.1 Infinitely many primes...... 359 48.2 Powers of Primes...... 360 48.3 Chinese Remainder Theorem Variants...... 361 48.4 Multiplicity and primality for natural numbers and integers. 363
49 Square roots of primes are irrational 367 49.1 Variations...... 368
50 Square roots of primes are irrational (script version) 369 50.1 Preliminaries...... 369 50.2 Main theorem...... 370
51 Type of finite sets defined as a subtype of sets 370 51.1 Definition of the type...... 370 51.2 Basic operations and type class instantiations...... 370
7 51.3 Other operations...... 373 51.4 Transferred lemmas from Set.thy...... 375 51.5 Additional lemmas...... 380 51.5.1 fsingleton ...... 380 51.5.2 femepty ...... 380 51.5.3 fset ...... 380 51.5.4 ffilter ...... 380 51.5.5 fset-of-list ...... 381 51.5.6 finsert ...... 381 51.5.7 fimage ...... 381 51.5.8 bounded quantification...... 381 51.5.9 fcard ...... 382 51.5.10 ffold ...... 383 51.6 Choice in fsets...... 385 51.7 Induction and Cases rules for fsets...... 385 51.8 Setup for Lifting/Transfer...... 386 51.8.1 Relator and predicator properties...... 386 51.8.2 Transfer rules for the Transfer package...... 387 51.9 BNF setup...... 389 51.10Size setup...... 391 51.11Advanced relator customization...... 391 51.12Quickcheck setup...... 392 51.131. A missing transfer rule...... 394 51.142. Unwanted instantiation of a transfer relation variable... 395
52 Using the transfer method between nat and int 396 52.1 Correspondence relation...... 396 52.2 Transfer domain rules...... 396 52.3 Transfer rules...... 396 52.4 Transfer examples...... 398
53 Various examples for transfer procedure 400
54 Simple example for table-based implementation of the re- flexive transitive closure 401
55 Divergence of the Harmonic Series 402 55.1 Abstract...... 402 55.2 Formal Proof...... 402
56 Examples for the ’refute’ command 407 56.1 Examples and Test Cases...... 408 56.1.1 Propositional logic...... 408 56.1.2 Predicate logic...... 409
8 56.1.3 Equality...... 409 56.1.4 First-Order Logic...... 409 56.1.5 Higher-Order Logic...... 411 56.1.6 Meta-logic...... 413 56.1.7 Schematic variables...... 413 56.1.8 Abstractions...... 414 56.1.9 Sets...... 414 56.1.10 undefined...... 415 56.1.11 The...... 415 56.1.12 Eps...... 416 56.1.13 Subtypes (typedef), typedecl...... 416 56.1.14 Inductive datatypes...... 416 56.1.15 Examples involving special functions...... 422 56.1.16 Type classes and overloading...... 423
57 Implementation of Association Lists 425 57.1 update and updates ...... 425 57.2 delete ...... 428 57.3 update-with-aux and delete-aux ...... 429 57.4 restrict ...... 431 57.5 clearjunk ...... 433 57.6 map-ran ...... 435 57.7 merge ...... 435 57.8 compose ...... 437 57.9 map-entry ...... 440 57.10map-default ...... 440
58 An abstract view on maps for code generation. 441 58.1 Parametricity transfer rules...... 441 58.2 Type definition and primitive operations...... 443 58.3 Functorial structure...... 444 58.4 Derived operations...... 445 58.5 Properties...... 446 58.6 Code generator setup...... 455
59 Implementation of mappings with Association Lists 455
60 A simple cookbook example how to eliminate choice in pro- grams. 458
61 Theory of Integration on real intervals 460 61.1 Gauges...... 460 61.2 Gauge-fine divisions...... 460 61.3 Riemann sum...... 464
9 61.4 Gauge integrability (definite)...... 465
62 Positive real numbers 473 62.1 Properties of Ordering...... 476 62.2 Properties of Addition...... 477 62.3 Properties of Multiplication...... 479 62.4 Distribution of Multiplication across Addition...... 483 62.5 Existence of Inverse, a Positive Real...... 484 62.6 Gleason’s Lemma 9-3.4, page 122...... 486 62.7 Gleason’s Lemma 9-3.6...... 488 62.8 Existence of Inverse: Part 2...... 488 62.9 Subtraction for Positive Reals...... 491 62.10proving that S ≤ R + D — trickier...... 493 62.11Completeness of type preal ...... 495
63 Defining the Reals from the Positive Reals 496 63.1 Equivalence relation over positive reals...... 497 63.2 Addition and Subtraction...... 498 63.3 Multiplication...... 499 63.4 Inverse and Division...... 501 63.5 The Real Numbers form a Field...... 501 63.6 The ≤ Ordering...... 501 63.7 The Reals Form an Ordered Field...... 504 63.8 Theorems About the Ordering...... 505 63.9 Completeness of Positive Reals...... 506 63.10The Archimedean Property of the Reals...... 510
64 Quicksort with function package 511
65 A Formulation of the Birthday Paradox 512
66 Cardinality 512
67 Birthday paradox 514
68 Examples for the list comprehension to set comprehension simproc 514 68.1 Some own examples for set (case ..) simpproc...... 515 68.2 Existing examples from the List theory...... 515
69 Finite sequences 516
10 70 Testing of arithmetic simprocs 517 70.1 ML bindings...... 517 70.2 Cancellation simprocs from Nat.thy ...... 517 70.3 Abelian group cancellation simprocs...... 518 70.4 int-combine-numerals ...... 518 70.5 inteq-cancel-numerals ...... 519 70.6 intless-cancel-numerals ...... 520 70.7 ring-eq-cancel-numeral-factor ...... 520 70.8 int-div-cancel-numeral-factors ...... 521 70.9 ring-less-cancel-numeral-factor ...... 521 70.10ring-le-cancel-numeral-factor ...... 522 70.11divide-cancel-numeral-factor ...... 522 70.12ring-eq-cancel-factor ...... 523 70.13int-div-cancel-factor ...... 523 70.14divide-cancel-factor ...... 524 70.15linordered-ring-less-cancel-factor ...... 524 70.16linordered-ring-le-cancel-factor ...... 525 70.17field-combine-numerals ...... 525 70.18nat-combine-numerals ...... 526 70.19nateq-cancel-numerals ...... 526 70.20natless-cancel-numerals ...... 527 70.21natle-cancel-numerals ...... 528 70.22natdiff-cancel-numerals ...... 528 70.23Factor-cancellation simprocs for type nat ...... 530 70.24Numeral-cancellation simprocs for type nat ...... 531 70.25Integer numeral div/mod simprocs...... 531 70.26A dedicated type for relations...... 532 70.26.1 Definition of the dedicated type for relations..... 532 70.26.2 Constant definitions on relations...... 533 70.26.3 Code generation...... 533
71 A generic phantom type 534
72 Cardinality of types 534 72.1 Preliminary lemmas...... 535 72.2 Cardinalities of types...... 535 72.3 Classes with at least 1 and 2...... 538 72.4 A type class for deciding finiteness of types...... 538 72.5 A type class for computing the cardinality of types...... 538 72.6 Instantiations for card-UNIV ...... 539 72.7 Code setup for sets...... 543
11 73 Almost everywhere constant functions 546 73.1 The map-default operation...... 546 73.2 The finfun type...... 547 73.3 Kernel functions for type 0a ⇒f 0b ...... 551 73.4 Code generator setup...... 552 73.5 Setup for quickcheck...... 552 73.6 finfun-update as instance of comp-fun-commute ...... 552 73.7 Default value for FinFuns...... 553 73.8 Recursion combinator and well-formedness conditions.... 555 73.9 Weak induction rule and case analysis for FinFuns...... 563 73.10Function application...... 564 73.11Function composition...... 565 73.12Universal quantification...... 567 73.13A diagonal operator for FinFuns...... 568 73.14Currying for FinFuns...... 571 73.15Executable equality for FinFuns...... 573 73.16An operator that explicitly removes all redundant updates in the generated representations...... 573 73.17The domain of a FinFun as a FinFun...... 574 73.18The domain of a FinFun as a sorted list...... 575 73.18.1 Bundles for concrete syntax...... 579
74 Predicates modelled as FinFuns 580
75 Examples for the set comprehension to pointfree simproc 586
76 Testing simproc in code generation 588
77 Futures and parallel lists for code generated towards Is- abelle/ML 589 77.1 Futures...... 589 77.2 Parallel lists...... 589
78 Debugging facilities for code generated towards Isabelle/ML590
79 A simple example demonstrating parallelism for code gen- erated towards Isabelle/ML 591 79.1 Compute-intensive examples...... 591 79.1.1 Fragments of the harmonic series...... 591 79.1.2 The sieve of Erathostenes...... 591 79.1.3 Naive factorisation...... 592 79.2 Concurrent computation via futures...... 593
80 Immutable Arrays with Code Generation 593 80.1 Code Generation...... 594
12 81 Implementation of integer numbers by target-language in- tegers 596
82 Implementation of natural numbers by target-language in- tegers 599 82.1 Implementation for nat ...... 599
83 Implementation of natural and integer numbers by target- language integers 602
84 Tests for the Simps¡-¿Case conversion tools 603
85 Isabelle/ML basics 606
86 ML expressions 606
87 Antiquotations 606
88 Recursive ML evaluation 607
89 IDE support 607
90 Example: factorial and ackermann function in Isabelle/ML607
91 Parallel Isabelle/ML 608
92 Function specifications in Isabelle/HOL 608
93 The rewrite Proof Method by Example 609
94 Regression tests 615
95 Examples for proof methods ”sat” and ”satx” 615
96 A decision procedure for universal multivariate real arith- metic with addition, multiplication and ordering using semidef- inite programming 626
97 Bertrand’s Ballot Theorem 633 97.1 Preliminaries...... 633 97.2 Formalization of Problem Statement...... 633 97.2.1 Basic Definitions...... 633 97.2.2 Equivalence with Set Cardinality...... 634 97.3 Facts About valid-countings ...... 636 97.3.1 Non-Recursive Cases...... 636 97.4 Relation Between valid-countings and all-countings ...... 639 97.4.1 Executable Definition...... 640
13 97.4.2 Executable Definition...... 640
98 The Erdoes-Szekeres Theorem 640 98.1 Addition to Lattices-Big Theory...... 640 98.2 Additions to Finite-Set Theory...... 640 98.3 Definition of Monotonicity over a Carrier Set...... 641 98.4 The Erdoes-Szekeres Theorem following Seidenberg’s (1959) argument...... 642
99 Sum of Powers 644 99.1 Additions to Binomial Theory...... 644 99.2 Preliminaries...... 645 99.3 Bernoulli Numbers and Bernoulli Polynomials...... 645 99.4 Basic Observations on Bernoulli Polynomials...... 645 99.5 Sum of Powers with Bernoulli Polynomials...... 646 99.6 Instances for Square And Cubic Numbers...... 647
100A SAT-based Sudoku Solver 648
101The sieve of Eratosthenes 655 101.1Preliminary: strict divisibility...... 655 101.2Main corpus...... 655 101.3Application: smallest prime beyond a certain number.... 661
102Examples for code generation timing measures 663
103Permutations as abstract type 664 103.1Abstract type of permutations...... 664 103.2Identity, composition and inversion...... 666 103.3Orbit and order of elements...... 668 103.4Swaps...... 679 103.5Permutations specified by cycles...... 680 103.6Syntax...... 680
104Listswith elements distinct as canonical example for datatype invariants 680 104.1The type of distinct lists...... 680 104.2Executable version obeying invariant...... 682 104.3Induction principle and case distinction...... 683 104.4Functorial structure...... 684 104.5Quickcheck generators...... 684 104.6BNF instance...... 684
105Fragments on permuations 687
14 106Argo 693 106.1Propositional logic...... 693 106.2Equality, congruence and predicates...... 696 106.3Linear real arithmetic...... 699 106.3.1 Negation and subtraction...... 699 106.3.2 Multiplication...... 699 106.3.3 Division...... 700 106.3.4 Addition...... 700 106.3.5 Minimum and maximum...... 701 106.3.6 Absolute value...... 701 106.3.7 Equality...... 702 106.3.8 Less-equal...... 702 106.3.9 Less...... 703 106.3.10Otherexamples...... 703 106.4Larger examples...... 705
107Numeral Syntax for Types 720 107.1Numeral Types...... 720 107.2Locales for for modular arithmetic subtypes...... 721 107.3Ring class instances...... 723 107.4Order instances...... 726 107.5Code setup and type classes for code generation...... 726 107.6Syntax...... 729 107.7Examples...... 731
108Assigning lengths to types by type classes 731
109Proof of concept for algebraically founded bit word types 732 109.1Truncating bit representations of numeric types...... 732 109.2Bit strings as quotient type...... 735 109.2.1 Basic properties...... 735 109.2.2 Conversions...... 736 109.2.3 Properties...... 738 109.2.4 Division...... 738 109.2.5 Orderings...... 738
110Meson test cases 739 110.1Interactive examples...... 739
1 Some Isar command definitions theory Commands imports Main keywords print-test :: diag and
15 global-test :: thy-decl and local-test :: thy-decl begin
1.1 Diagnostic command: no state change
ML h Outer-Syntax.command @{command-keyword print-test} print term test (Parse.term >> (fn s => Toplevel.keep (fn st => let val ctxt = Toplevel.context-of st; val t = Syntax.read-term ctxt s; in Pretty.writeln (Syntax.pretty-term ctxt t) end))); i print-test x print-test λx. x = a
1.2 Old-style global theory declaration
ML h Outer-Syntax.command @{command-keyword global-test} test constant declaration (Parse.binding >> (fn b => Toplevel.theory (fn thy => let val thy 0 = Sign.add-consts [(b, @{typ 0a}, NoSyn)] thy; in thy 0 end))); i global-test a global-test b print-test a
1.3 Local theory specification
ML h Outer-Syntax.local-theory @{command-keyword local-test} test local definition (Parse.binding −− (@{keyword =} |−− Parse.term) >> (fn (b, s) => fn lthy => let val t = Syntax.read-term lthy s; val (def , lthy 0) = Local-Theory.define ((b, NoSyn), ((Thm.def-binding b, []), t)) lthy; in lthy 0 end)); i local-test true = True print-test true thm true-def local-test identity = λx. x
16 print-test identity x thm identity-def context fixes x y :: nat begin local-test test = x + y print-test test thm test-def end print-test test 0 1 thm test-def end
2 Infinite Sets and Related Concepts theory Infinite-Set imports Main begin
The set of natural numbers is infinite. lemma infinite-nat-iff-unbounded-le: infinite (S::nat set) ←→ (∀ m. ∃ n≥m. n ∈ S) using frequently-cofinite[of λx. x ∈ S] by (simp add: cofinite-eq-sequentially frequently-def eventually-sequentially) lemma infinite-nat-iff-unbounded: infinite (S::nat set) ←→ (∀ m. ∃ n>m. n ∈ S) using frequently-cofinite[of λx. x ∈ S] by (simp add: cofinite-eq-sequentially frequently-def eventually-at-top-dense) lemma finite-nat-iff-bounded: finite (S::nat set) ←→ (∃ k. S ⊆ {.. For a set of natural numbers to be infinite, it is enough to know that for any number larger than some k, there is some larger number that is an element of the set. lemma unbounded-k-infinite: ∀ m>k. ∃ n>m. n ∈ S =⇒ infinite (S::nat set) apply (clarsimp simp add: finite-nat-set-iff-bounded) apply (drule-tac x=Suc (max m k) in spec) 17 using less-Suc-eq by fastforce lemma nat-not-finite: finite (UNIV ::nat set) =⇒ R by simp lemma range-inj-infinite: inj (f ::nat ⇒ 0a) =⇒ infinite (range f ) proof assume finite (range f ) and inj f then have finite (UNIV ::nat set) by (rule finite-imageD) then show False by simp qed The set of integers is also infinite. lemma infinite-int-iff-infinite-nat-abs: infinite (S::int set) ←→ infinite ((nat o abs) ‘S) by (auto simp: transfer-nat-int-set-relations o-def image-comp dest: finite-image-absD) proposition infinite-int-iff-unbounded-le: infinite (S::int set) ←→ (∀ m. ∃ n. |n| ≥ m ∧ n ∈ S) apply (simp add: infinite-int-iff-infinite-nat-abs infinite-nat-iff-unbounded-le o-def image-def ) apply (metis abs-ge-zero nat-le-eq-zle le-nat-iff ) done proposition infinite-int-iff-unbounded: infinite (S::int set) ←→ (∀ m. ∃ n. |n| > m ∧ n ∈ S) apply (simp add: infinite-int-iff-infinite-nat-abs infinite-nat-iff-unbounded o-def image-def ) apply (metis (full-types) nat-le-iff nat-mono not-le) done proposition finite-int-iff-bounded: finite (S::int set) ←→ (∃ k. abs ‘ S ⊆ {.. 2.1 Infinitely Many and Almost All We often need to reason about the existence of infinitely many (resp., all but finitely many) objects satisfying some predicate, so we introduce corre- sponding binders and their proof rules. lemma not-INFM [simp]: ¬ (INFM x. P x) ←→ (MOST x. ¬ P x) by (fact not-frequently) lemma not-MOST [simp]: ¬ (MOST x. P x) ←→ (INFM x. ¬ P x) by (fact not-eventually) 18 lemma INFM-const [simp]: (INFM x:: 0a. P) ←→ P ∧ infinite (UNIV :: 0a set) by (simp add: frequently-const-iff ) lemma MOST-const [simp]: (MOST x:: 0a. P) ←→ P ∨ finite (UNIV :: 0a set) by (simp add: eventually-const-iff ) lemma INFM-imp-distrib:(INFM x. P x −→ Q x) ←→ ((MOST x. P x) −→ (INFM x. Q x)) by (simp only: imp-conv-disj frequently-disj-iff not-eventually) lemma MOST-imp-iff : MOST x. P x =⇒ (MOST x. P x −→ Q x) ←→ (MOST x. Q x) by (auto intro: eventually-rev-mp eventually-mono) lemma INFM-conjI : INFM x. P x =⇒ MOST x. Q x =⇒ INFM x. P x ∧ Q x by (rule frequently-rev-mp[of P]) (auto elim: eventually-mono) Properties of quantifiers with injective functions. lemma INFM-inj : INFM x. P (f x) =⇒ inj f =⇒ INFM x. P x using finite-vimageI [of {x. P x} f ] by (auto simp: frequently-cofinite) lemma MOST-inj : MOST x. P x =⇒ inj f =⇒ MOST x. P (f x) using finite-vimageI [of {x. ¬ P x} f ] by (auto simp: eventually-cofinite) Properties of quantifiers with singletons. lemma not-INFM-eq [simp]: ¬ (INFM x. x = a) ¬ (INFM x. a = x) unfolding frequently-cofinite by simp-all lemma MOST-neq [simp]: MOST x. x 6= a MOST x. a 6= x unfolding eventually-cofinite by simp-all lemma INFM-neq [simp]: (INFM x:: 0a. x 6= a) ←→ infinite (UNIV :: 0a set) (INFM x:: 0a. a 6= x) ←→ infinite (UNIV :: 0a set) unfolding frequently-cofinite by simp-all lemma MOST-eq [simp]: (MOST x:: 0a. x = a) ←→ finite (UNIV :: 0a set) (MOST x:: 0a. a = x) ←→ finite (UNIV :: 0a set) unfolding eventually-cofinite by simp-all lemma MOST-eq-imp: MOST x. x = a −→ P x MOST x. a = x −→ P x 19 unfolding eventually-cofinite by simp-all Properties of quantifiers over the naturals. lemma MOST-nat:(∀ ∞n. P (n::nat)) ←→ (∃ m. ∀ n>m. P n) by (auto simp add: eventually-cofinite finite-nat-iff-bounded-le subset-eq not-le[symmetric]) lemma MOST-nat-le:(∀ ∞n. P (n::nat)) ←→ (∃ m. ∀ n≥m. P n) by (auto simp add: eventually-cofinite finite-nat-iff-bounded subset-eq not-le[symmetric]) lemma INFM-nat:(∃ ∞n. P (n::nat)) ←→ (∀ m. ∃ n>m. P n) by (simp add: frequently-cofinite infinite-nat-iff-unbounded) lemma INFM-nat-le:(∃ ∞n. P (n::nat)) ←→ (∀ m. ∃ n≥m. P n) by (simp add: frequently-cofinite infinite-nat-iff-unbounded-le) lemma MOST-INFM : infinite (UNIV :: 0a set) =⇒ MOST x:: 0a. P x =⇒ INFM x:: 0a. P x by (simp add: eventually-frequently) lemma MOST-Suc-iff :(MOST n. P (Suc n)) ←→ (MOST n. P n) by (simp add: cofinite-eq-sequentially eventually-sequentially-Suc) lemma shows MOST-SucI : MOST n. P n =⇒ MOST n. P (Suc n) and MOST-SucD: MOST n. P (Suc n) =⇒ MOST n. P n by (simp-all add: MOST-Suc-iff ) lemma MOST-ge-nat: MOST n::nat. m ≤ n by (simp add: cofinite-eq-sequentially eventually-ge-at-top) lemma Inf-many-def : Inf-many P ←→ infinite {x. P x} by (fact frequently-cofinite) lemma Alm-all-def : Alm-all P ←→ ¬ (INFM x. ¬ P x) by simp lemma INFM-iff-infinite:(INFM x. P x) ←→ infinite {x. P x} by (fact frequently-cofinite) lemma MOST-iff-cofinite:(MOST x. P x) ←→ finite {x. ¬ P x} by (fact eventually-cofinite) lemma INFM-EX :(∃ ∞x. P x) =⇒ (∃ x. P x) by (fact frequently-ex) lemma ALL-MOST : ∀ x. P x =⇒ ∀ ∞x. P x by (fact always-eventually) V lemma INFM-mono: ∃ ∞x. P x =⇒ ( x. P x =⇒ Q x) =⇒ ∃ ∞x. Q x by (fact frequently-elim1 ) V lemma MOST-mono: ∀ ∞x. P x =⇒ ( x. P x =⇒ Q x) =⇒ ∀ ∞x. Q x by (fact eventually-mono) lemma INFM-disj-distrib:(∃ ∞x. P x ∨ Q x) ←→ (∃ ∞x. P x) ∨ (∃ ∞x. Q x) by (fact frequently-disj-iff ) lemma MOST-rev-mp: ∀ ∞x. P x =⇒ ∀ ∞x. P x −→ Q x =⇒ ∀ ∞x. Q x by (fact eventually-rev-mp) lemma MOST-conj-distrib:(∀ ∞x. P x ∧ Q x) ←→ (∀ ∞x. P x) ∧ (∀ ∞x. Q x) by (fact eventually-conj-iff ) lemma MOST-conjI : MOST x. P x =⇒ MOST x. Q x =⇒ MOST x. P x ∧ Q x by (fact eventually-conj ) 20 lemma INFM-finite-Bex-distrib: finite A =⇒ (INFM y. ∃ x∈A. P x y) ←→ (∃ x∈A. INFM y. P x y) by (fact frequently-bex-finite-distrib) lemma MOST-finite-Ball-distrib: finite A =⇒ (MOST y. ∀ x∈A. P x y) ←→ (∀ x∈A. MOST y. P x y) by (fact eventually-ball-finite-distrib) lemma INFM-E: INFM x. P x =⇒ (Vx. P x =⇒ thesis) =⇒ thesis by (fact frequentlyE) lemma MOST-I :(Vx. P x) =⇒ MOST x. P x by (rule eventuallyI ) lemmas MOST-iff-finiteNeg = MOST-iff-cofinite 2.2 Enumeration of an Infinite Set The set’s element type must be wellordered (e.g. the natural numbers). Could be generalized to enumerate 0 S n = (SOME t. t ∈ s ∧ finite {s ∈ S. s < t} ∧ card {s ∈ S. s < t} = n). primrec (in wellorder) enumerate :: 0a set ⇒ nat ⇒ 0a where enumerate-0 : enumerate S 0 = (LEAST n. n ∈ S) | enumerate-Suc: enumerate S (Suc n) = enumerate (S − {LEAST n. n ∈ S}) n lemma enumerate-Suc 0: enumerate S (Suc n) = enumerate (S − {enumerate S 0 }) n by simp lemma enumerate-in-set: infinite S =⇒ enumerate S n ∈ S apply (induct n arbitrary: S) apply (fastforce intro: LeastI dest!: infinite-imp-nonempty) apply simp apply (metis DiffE infinite-remove) done declare enumerate-0 [simp del] enumerate-Suc [simp del] lemma enumerate-step: infinite S =⇒ enumerate S n < enumerate S (Suc n) apply (induct n arbitrary: S) apply (rule order-le-neq-trans) apply (simp add: enumerate-0 Least-le enumerate-in-set) apply (simp only: enumerate-Suc 0) apply (subgoal-tac enumerate (S − {enumerate S 0 }) 0 ∈ S − {enumerate S 0 }) apply (blast intro: sym) apply (simp add: enumerate-in-set del: Diff-iff ) apply (simp add: enumerate-Suc 0) done lemma enumerate-mono: m < n =⇒ infinite S =⇒ enumerate S m < enumerate S n apply (erule less-Suc-induct) apply (auto intro: enumerate-step) 21 done lemma le-enumerate: assumes S: infinite S shows n ≤ enumerate S n using S proof (induct n) case 0 then show ?case by simp next case (Suc n) then have n ≤ enumerate S n by simp also note enumerate-mono[of n Suc n, OF - hinfinite S i] finally show ?case by simp qed lemma enumerate-Suc 00: fixes S :: 0a::wellorder set assumes infinite S shows enumerate S (Suc n) = (LEAST s. s ∈ S ∧ enumerate S n < s) using assms proof (induct n arbitrary: S) case 0 then have ∀ s ∈ S. enumerate S 0 ≤ s by (auto simp: enumerate.simps intro: Least-le) then show ?case unfolding enumerate-Suc 0 enumerate-0 [of S − {enumerate S 0 }] by (intro arg-cong[where f = Least] ext) auto next case (Suc n S) show ?case using enumerate-mono[OF zero-less-Suc hinfinite S i, of n] hinfinite S i apply (subst (1 2 ) enumerate-Suc 0) apply (subst Suc) using hinfinite S i apply simp apply (intro arg-cong[where f = Least] ext) apply (auto simp: enumerate-Suc 0[symmetric]) done qed lemma enumerate-Ex: assumes S: infinite (S::nat set) shows s ∈ S =⇒ ∃ n. enumerate S n = s proof (induct s rule: less-induct) case (less s) show ?case proof cases 22 let ?y = Max {s 0∈S. s 0 < s} assume ∃ y∈S. y < s then have y: Vx. ?y < x ←→ (∀ s 0∈S. s 0 < s −→ s 0 < x) by (subst Max-less-iff ) auto then have y-in: ?y ∈ {s 0∈S. s 0 < s} by (intro Max-in) auto with less.hyps[of ?y] obtain n where enumerate S n = ?y by auto with S have enumerate S (Suc n) = s by (auto simp: y less enumerate-Suc 00 intro!: Least-equality) then show ?case by auto next assume ∗: ¬ (∃ y∈S. y < s) then have ∀ t∈S. s ≤ t by auto with hs ∈ S i show ?thesis by (auto intro!: exI [of - 0 ] Least-equality simp: enumerate-0 ) qed qed lemma bij-enumerate: fixes S :: nat set assumes S: infinite S shows bij-betw (enumerate S) UNIV S proof − have Vn m. n 6= m =⇒ enumerate S n 6= enumerate S m using enumerate-mono[OF - hinfinite S i] by (auto simp: neq-iff ) then have inj (enumerate S) by (auto simp: inj-on-def ) moreover have ∀ s ∈ S. ∃ i. enumerate S i = s using enumerate-Ex[OF S] by auto moreover note hinfinite S i ultimately show ?thesis unfolding bij-betw-def by (auto intro: enumerate-in-set) qed A pair of weird and wonderful lemmas from HOL Light lemma finite-transitivity-chain: assumes finite A and R: Vx. ∼ R x x Vx y z. [[R x y; R y z]] =⇒ R x z and A: Vx. x ∈ A =⇒ ∃ y. y ∈ A ∧ R x y shows A = {} using hfinite Ai A proof (induction A) case (insert a A) with R show ?case by (metis empty-iff insert-iff ) qed simp corollary Union-maximal-sets: 23 assumes finite F shows S {T ∈ F. ∀ U ∈F. ¬ T ⊂ U } = S F (is ?lhs = ?rhs) proof show ?rhs ⊆ ?lhs proof (rule Union-subsetI ) fix S assume S ∈ F have {T ∈ F. S ⊆ T } = {} if ∼ (∃ y. y ∈ {T ∈ F. ∀ U ∈F. ¬ T ⊂ U } ∧ S ⊆ y) apply (rule finite-transitivity-chain [of - λTU . S ⊆ T ∧ T ⊂ U ]) using assms that apply auto by (blast intro: dual-order.trans psubset-imp-subset) then show ∃ y. y ∈ {T ∈ F. ∀ U ∈F. ¬ T ⊂ U } ∧ S ⊆ y using hS ∈ F i by blast qed qed force end 3 Ad Hoc Overloading theory Adhoc-Overloading-Examples imports Main ∼∼/src/HOL/Library/Infinite-Set ∼∼/src/Tools/Adhoc-Overloading begin Adhoc overloading allows to overload a constant depending on its type. Typ- ically this involves to introduce an uninterpreted constant (used for input and output) and then add some variants (used internally). 3.1 Plain Ad Hoc Overloading Consider the type of first-order terms. datatype ( 0a, 0b) term = Var 0b | Fun 0a ( 0a, 0b) term list The set of variables of a term might be computed as follows. fun term-vars :: ( 0a, 0b) term ⇒ 0b set where term-vars (Var x) = {x} | term-vars (Fun f ts) = S set (map term-vars ts) However, also for rules (i.e., pairs of terms) and term rewrite systems (i.e., sets of rules), the set of variables makes sense. Thus we introduce an un- specified constant vars. 24 consts vars :: 0a ⇒ 0b set Which is then overloaded with variants for terms, rules, and TRSs. adhoc-overloading vars term-vars value vars (Fun 00f 00 [Var 0 , Var 1 ]) fun rule-vars :: ( 0a, 0b) term × ( 0a, 0b) term ⇒ 0b set where rule-vars (l, r) = vars l ∪ vars r adhoc-overloading vars rule-vars value vars (Var 1 , Var 0 ) definition trs-vars :: (( 0a, 0b) term × ( 0a, 0b) term) set ⇒ 0b set where trs-vars R = S (rule-vars ‘ R) adhoc-overloading vars trs-vars value vars {(Var 1 , Var 0 )} Sometimes it is necessary to add explicit type constraints before a variant can be determined. value vars (R :: (( 0a, 0b) term × ( 0a, 0b) term) set) It is also possible to remove variants. no-adhoc-overloading vars term-vars rule-vars As stated earlier, the overloaded constant is only used for input and output. Internally, always a variant is used, as can be observed by the configuration option show-variants. adhoc-overloading vars term-vars declare [[show-variants]] term vars (Var 1 ) 3.2 Adhoc Overloading inside Locales As example we use permutations that are parametrized over an atom type 0a. definition perms :: ( 0a ⇒ 0a) set where 25 perms = {f . bij f ∧ finite {x. f x 6= x}} typedef 0a perm = perms :: ( 0a ⇒ 0a) set by standard (auto simp: perms-def ) First we need some auxiliary lemmas. lemma permsI [Pure.intro]: assumes bij f and MOST x. f x = x shows f ∈ perms using assms by (auto simp: perms-def )(metis MOST-iff-finiteNeg) lemma perms-imp-bij : f ∈ perms =⇒ bij f by (simp add: perms-def ) lemma perms-imp-MOST-eq: f ∈ perms =⇒ MOST x. f x = x by (simp add: perms-def )(metis MOST-iff-finiteNeg) lemma id-perms [simp]: id ∈ perms (λx. x) ∈ perms by (auto simp: perms-def bij-def ) lemma perms-comp [simp]: assumes f : f ∈ perms and g: g ∈ perms shows (f ◦ g) ∈ perms apply (intro permsI bij-comp) apply (rule perms-imp-bij [OF g]) apply (rule perms-imp-bij [OF f ]) apply (rule MOST-rev-mp [OF perms-imp-MOST-eq [OF g]]) apply (rule MOST-rev-mp [OF perms-imp-MOST-eq [OF f ]]) by simp lemma perms-inv: assumes f : f ∈ perms shows inv f ∈ perms apply (rule permsI ) apply (rule bij-imp-bij-inv) apply (rule perms-imp-bij [OF f ]) apply (rule MOST-mono [OF perms-imp-MOST-eq [OF f ]]) apply (erule subst, rule inv-f-f ) apply (rule bij-is-inj [OF perms-imp-bij [OF f ]]) done lemma bij-Rep-perm: bij (Rep-perm p) using Rep-perm [of p] unfolding perms-def by simp instantiation perm :: (type) group-add 26 begin definition 0 = Abs-perm id definition − p = Abs-perm (inv (Rep-perm p)) definition p + q = Abs-perm (Rep-perm p ◦ Rep-perm q) definition (p1 :: 0a perm) − p2 = p1 + − p2 lemma Rep-perm-0 : Rep-perm 0 = id unfolding zero-perm-def by (simp add: Abs-perm-inverse) lemma Rep-perm-add: Rep-perm (p1 + p2 ) = Rep-perm p1 ◦ Rep-perm p2 unfolding plus-perm-def by (simp add: Abs-perm-inverse Rep-perm) lemma Rep-perm-uminus: Rep-perm (− p) = inv (Rep-perm p) unfolding uminus-perm-def by (simp add: Abs-perm-inverse perms-inv Rep-perm) instance apply standard unfolding Rep-perm-inject [symmetric] unfolding minus-perm-def unfolding Rep-perm-add unfolding Rep-perm-uminus unfolding Rep-perm-0 apply (simp-all add: o-assoc inv-o-cancel [OF bij-is-inj [OF bij-Rep-perm]]) done end lemmas Rep-perm-simps = Rep-perm-0 Rep-perm-add Rep-perm-uminus 4 Permutation Types We want to be able to apply permutations to arbitrary types. To this end we introduce a constant PERMUTE together with convenient infix syntax. consts PERMUTE :: 0a perm ⇒ 0b ⇒ 0b (infixr · 75 ) Then we add a locale for types 0b that support appliciation of permutations. locale permute = fixes permute :: 0a perm ⇒ 0b ⇒ 0b assumes permute-zero [simp]: permute 0 x = x and permute-plus [simp]: permute (p + q) x = permute p (permute q x) begin 27 adhoc-overloading PERMUTE permute end Permuting atoms. definition permute-atom :: 0a perm ⇒ 0a ⇒ 0a where permute-atom p a = (Rep-perm p) a adhoc-overloading PERMUTE permute-atom interpretation atom-permute: permute permute-atom by standard (simp-all add: permute-atom-def Rep-perm-simps) Permuting permutations. definition permute-perm :: 0a perm ⇒ 0a perm ⇒ 0a perm where permute-perm p q = p + q − p adhoc-overloading PERMUTE permute-perm interpretation perm-permute: permute permute-perm apply standard unfolding permute-perm-def apply simp apply (simp only: diff-conv-add-uminus minus-add add.assoc) done Permuting functions. locale fun-permute = dom: permute perm1 + ran: permute perm2 for perm1 :: 0a perm ⇒ 0b ⇒ 0b and perm2 :: 0a perm ⇒ 0c ⇒ 0c begin adhoc-overloading PERMUTE perm1 perm2 definition permute-fun :: 0a perm ⇒ ( 0b ⇒ 0c) ⇒ ( 0b ⇒ 0c) where permute-fun p f = (λx. p · (f (−p · x))) adhoc-overloading PERMUTE permute-fun end sublocale fun-permute ⊆ permute permute-fun by (unfold-locales, auto simp: permute-fun-def ) 28 (metis dom.permute-plus minus-add) lemma (Abs-perm id :: nat perm) · Suc 0 = Suc 0 unfolding permute-atom-def by (metis Rep-perm-0 id-apply zero-perm-def ) interpretation atom-fun-permute: fun-permute permute-atom permute-atom by (unfold-locales) adhoc-overloading PERMUTE atom-fun-permute.permute-fun lemma (Abs-perm id :: 0a perm) · id = id unfolding atom-fun-permute.permute-fun-def unfolding permute-atom-def by (metis Rep-perm-0 id-def inj-imp-inv-eq inj-on-id uminus-perm-def zero-perm-def ) end 5 Example of Declaring an Oracle theory Iff-Oracle imports Main begin 5.1 Oracle declaration This oracle makes tautologies of the form P = (P = (P = P)). The length is specified by an integer, which is checked to be even and positive. oracle iff-oracle = h let fun mk-iff 1 = Var ((P, 0 ), @{typ bool}) | mk-iff n = HOLogic.mk-eq (Var ((P, 0 ), @{typ bool}), mk-iff (n − 1 )); in fn (thy, n) => if n > 0 andalso n mod 2 = 0 then Thm.global-cterm-of thy (HOLogic.mk-Trueprop (mk-iff n)) else raise Fail (iff-oracle: ˆ string-of-int n) end i 5.2 Oracle as low-level rule ML hiff-oracle (@{theory}, 2 )i ML hiff-oracle (@{theory}, 10 )i ML h Thm.peek-status (iff-oracle (@{theory}, 10 )); 29 @{assert} (#oracle it); i These oracle calls had better fail. ML h (iff-oracle (@{theory}, 5 ); error Bad oracle) handle Fail - => writeln Oracle failed, as expected i ML h (iff-oracle (@{theory}, 1 ); error Bad oracle) handle Fail - => writeln Oracle failed, as expected i 5.3 Oracle as proof method method-setup iff = hScan.lift Parse.nat >> (fn n => fn ctxt => SIMPLE-METHOD (HEADGOAL (resolve-tac ctxt [iff-oracle (Proof-Context.theory-of ctxt, n)]) handle Fail - => no-tac))i lemma A ←→ A by (iff 2 ) lemma A ←→ A ←→ A ←→ A ←→ A ←→ A ←→ A ←→ A ←→ A ←→ A by (iff 10 ) lemma A ←→ A ←→ A ←→ A ←→ A apply (iff 5 )? oops lemma A apply (iff 1 )? oops end theory Coercion-Examples imports Main begin declare[[coercion-enabled]] consts func :: (nat ⇒ int) ⇒ nat 30 consts arg :: int ⇒ nat consts func 0 :: int ⇒ int consts arg 0 :: nat abbreviation nat-of-bool :: bool ⇒ nat where nat-of-bool ≡ of-bool declare [[coercion nat-of-bool]] declare [[coercion int]] declare [[coercion-map map]] definition map-fun :: ( 0a ⇒ 0b) ⇒ ( 0c ⇒ 0d) ⇒ ( 0b ⇒ 0c) ⇒ ( 0a ⇒ 0d) where map-fun f g h = g o h o f declare [[coercion-map λ f g h . g o h o f ]] primrec map-prod :: ( 0a ⇒ 0c) ⇒ ( 0b ⇒ 0d) ⇒ ( 0a ∗ 0b) ⇒ ( 0c ∗ 0d) where map-prod f g (x,y) = (f x, g y) declare [[coercion-map map-prod]] term (1 ::nat) = True term True = (1 ::nat) term (1 ::nat) = (True = (1 ::nat)) term op = (True = (1 ::nat)) term [1 ::nat,True] term [True,1 ::nat] term [1 ::nat] = [True] term [True] = [1 ::nat] 31 term [[True]] = [[1 ::nat]] term [[[[[[[[[[True]]]]]]]]]] = [[[[[[[[[[1 ::nat]]]]]]]]]] term [[True],[42 ::nat]] = rev [[True]] term rev [10000 ::nat] = [False, 420000 ::nat, True] term λ x . x = (3 ::nat) term (λ x . x = (3 ::nat)) True term map (λ x . x = (3 ::nat)) term map (λ x . x = (3 ::nat)) [True,1 ::nat] consts bnn :: (bool ⇒ nat) ⇒ nat consts nb :: nat ⇒ bool consts ab :: 0a ⇒ bool term bnn nb term bnn ab term λ x . x = (3 ::int) term map (λ x . x = (3 ::int)) [True] term map (λ x . x = (3 ::int)) [True,1 ::nat] term map (λ x . x = (3 ::int)) [True,1 ::nat,1 ::int] term [1 ::nat,True,1 ::int,False] term map (map (λ x . x = (3 ::int))) [[True],[1 ::nat],[True,1 ::int]] consts cbool :: 0a ⇒ bool consts cnat :: 0a ⇒ nat consts cint :: 0a ⇒ int term [id, cbool, cnat, cint] consts funfun :: ( 0a ⇒ 0b) ⇒ 0a ⇒ 0b consts flip :: ( 0a ⇒ 0b ⇒ 0c) ⇒ 0b ⇒ 0a ⇒ 0c term flip funfun term map funfun [id,cnat,cint,cbool] 32 term map (flip funfun True) term map (flip funfun True)[id,cnat,cint,cbool] consts ii :: int ⇒ int consts aaa :: 0a ⇒ 0a ⇒ 0a consts nlist :: nat list consts ilil :: int list ⇒ int list term ii (aaa (1 ::nat) True) term map ii nlist term ilil nlist definition xs :: bool list where xs = [True] term (xs::nat list) term (1 ::nat) = True term True = (1 ::nat) term int (1 ::nat) term ((True::nat)::int) term 1 ::nat term nat 1 definition C :: nat where C = 123 consts g :: int ⇒ int consts h :: nat ⇒ nat term (g (1 ::nat)) + (h 2 ) term g 1 term 1 +(1 ::nat) term ((1 ::int) + (1 ::nat),(1 ::int)) 33 definition ys :: bool list list list list list where ys=[[[[[True]]]]] term ys=[[[[[1 ::nat]]]]] typedecl ( 0a, 0b, 0c) F consts Fmap :: ( 0a ⇒ 0d) ⇒ ( 0a, 0b, 0c) F ⇒ ( 0d, 0b, 0c) F consts z :: (bool, nat, bool) F declare [[coercion-map Fmap :: ( 0a ⇒ 0d) ⇒ ( 0a, 0b, 0c) F ⇒ ( 0d, 0b, 0c) F ]] term z :: (nat, nat, bool) F consts case-nil :: 0a ⇒ 0b case-cons :: ( 0a ⇒ 0b) ⇒ ( 0a ⇒ 0b) ⇒ 0a ⇒ 0b case-abs :: ( 0c ⇒ 0b) ⇒ 0b case-elem :: 0a ⇒ 0b ⇒ 0a ⇒ 0b declare [[coercion-args case-cons − −]] declare [[coercion-args case-abs −]] declare [[coercion-args case-elem − +]] term case-cons (case-abs (λn. case-abs (λis. case-elem (((n::nat),(is::int list))) (n#is)))) case-nil consts n :: nat m :: nat term − (n + m) declare [[coercion-args uminus −]] declare [[coercion-args plus + +]] term − (n + m) end 6 Abstract Natural Numbers primitive recursion theory Abstract-NAT imports Main begin Axiomatic Natural Numbers (Peano) – a monomorphic theory. locale NAT = fixes zero :: 0n and succ :: 0n ⇒ 0n assumes succ-inject [simp]: succ m = succ n ←→ m = n and succ-neq-zero [simp]: succ m 6= zero and induct [case-names zero succ, induct type: 0n]: P zero =⇒ (Vn. P n =⇒ P (succ n)) =⇒ P n begin lemma zero-neq-succ [simp]: zero 6= succ m 34 by (rule succ-neq-zero [symmetric]) Primitive recursion as a (functional) relation – polymorphic! inductive Rec :: 0a ⇒ ( 0n ⇒ 0a ⇒ 0a) ⇒ 0n ⇒ 0a ⇒ bool for e :: 0a and r :: 0n ⇒ 0a ⇒ 0a where Rec-zero: Rec e r zero e | Rec-succ: Rec e r m n =⇒ Rec e r (succ m)(r m n) lemma Rec-functional: fixes x :: 0n shows ∃ !y:: 0a. Rec e r x y proof − let ?R = Rec e r show ?thesis proof (induct x) case zero show ∃ !y. ?R zero y proof show ?R zero e .. show y = e if ?R zero y for y using that by cases simp-all qed next case (succ m) from h∃ !y. ?R m y i obtain y where y: ?R m y and yy 0: Vy 0. ?R m y 0 =⇒ y = y 0 by blast show ∃ !z. ?R (succ m) z proof from y show ?R (succ m)(r m y) .. next fix z assume ?R (succ m) z then obtain u where z = r m u and ?R m u by cases simp-all with yy 0 show z = r m y by (simp only:) qed qed qed The recursion operator – polymorphic! definition rec :: 0a ⇒ ( 0n ⇒ 0a ⇒ 0a) ⇒ 0n ⇒ 0a where rec e r x = (THE y. Rec e r x y) lemma rec-eval: assumes Rec: Rec e r x y 35 shows rec e r x = y unfolding rec-def using Rec-functional and Rec by (rule the1-equality) lemma rec-zero [simp]: rec e r zero = e proof (rule rec-eval) show Rec e r zero e .. qed lemma rec-succ [simp]: rec e r (succ m) = r m (rec e r m) proof (rule rec-eval) let ?R = Rec e r have ?R m (rec e r m) unfolding rec-def using Rec-functional by (rule theI 0) then show ?R (succ m)(r m (rec e r m)) .. qed Example: addition (monomorphic) definition add :: 0n ⇒ 0n ⇒ 0n where add m n = rec n (λ- k. succ k) m lemma add-zero [simp]: add zero n = n and add-succ [simp]: add (succ m) n = succ (add m n) unfolding add-def by simp-all lemma add-assoc: add (add k m) n = add k (add m n) by (induct k) simp-all lemma add-zero-right: add m zero = m by (induct m) simp-all lemma add-succ-right: add m (succ n) = succ (add m n) by (induct m) simp-all lemma add (succ (succ (succ zero))) (succ (succ zero)) = succ (succ (succ (succ (succ zero)))) by simp Example: replication (polymorphic) definition repl :: 0n ⇒ 0a ⇒ 0a list where repl n x = rec [] (λ- xs. x # xs) n lemma repl-zero [simp]: repl zero x = [] and repl-succ [simp]: repl (succ n) x = x # repl n x unfolding repl-def by simp-all lemma repl (succ (succ (succ zero))) True = [True, True, True] by simp 36 end Just see that our abstract specification makes sense . . . interpretation NAT 0 Suc proof (rule NAT .intro) fix m n show Suc m = Suc n ←→ m = n by simp show Suc m 6= 0 by simp show P n if zero: P 0 and succ: Vn. P n =⇒ P (Suc n) for P proof (induct n) case 0 show ?case by (rule zero) next case Suc then show ?case by (rule succ) qed qed end 7 Proof by guessing theory Guess imports Main begin notepad begin have 1 : ∃ x. x = x by simp from 1 guess .. from 1 guess x .. from 1 guess x :: 0a .. from 1 guess x :: nat .. have 2 : ∃ x y. x = x ∧ y = y by simp from 2 guess apply − apply (erule exE conjE)+ done from 2 guess x apply − apply (erule exE conjE)+ done from 2 guess x y apply − apply (erule exE conjE)+ done from 2 guess x :: 0a and y :: 0b apply − apply (erule exE conjE)+ done from 2 guess x y :: nat apply − apply (erule exE conjE)+ done end end 37 8 Examples of function definitions theory Functions imports Main ∼∼/src/HOL/Library/Monad-Syntax begin 8.1 Very basic fun fib :: nat ⇒ nat where fib 0 = 1 | fib (Suc 0 ) = 1 | fib (Suc (Suc n)) = fib n + fib (Suc n) Partial simp and induction rules: thm fib.psimps thm fib.pinduct There is also a cases rule to distinguish cases along the definition: thm fib.cases Total simp and induction rules: thm fib.simps thm fib.induct Elimination rules: thm fib.elims 8.2 Currying fun add where add 0 y = y | add (Suc x) y = Suc (add x y) thm add.simps thm add.induct — Note the curried induction predicate 8.3 Nested recursion function nz where nz 0 = 0 | nz (Suc x) = nz (nz x) by pat-completeness auto lemma nz-is-zero: — A lemma we need to prove termination assumes trm: nz-dom x shows nz x = 0 38 using trm by induct (auto simp: nz.psimps) termination nz by (relation less-than)(auto simp:nz-is-zero) thm nz.simps thm nz.induct 8.3.1 Here comes McCarthy’s 91-function function f91 :: nat ⇒ nat where f91 n = (if 100 < n then n − 10 else f91 (f91 (n + 11 ))) by pat-completeness auto Prove a lemma before attempting a termination proof: lemma f91-estimate: assumes trm: f91-dom n shows n < f91 n + 11 using trm by induct (auto simp: f91 .psimps) termination proof let ?R = measure (λx. 101 − x) show wf ?R .. fix n :: nat assume ¬ 100 < n — Inner call then show (n + 11 , n) ∈ ?R by simp assume inner-trm: f91-dom (n + 11 ) — Outer call with f91-estimate have n + 11 < f91 (n + 11 ) + 11 . with h¬ 100 < n i show (f91 (n + 11 ), n) ∈ ?R by simp qed Now trivial (even though it does not belong here): lemma f91 n = (if 100 < n then n − 10 else 91 ) by (induct n rule: f91 .induct) auto 8.4 More general patterns 8.4.1 Overlapping patterns Currently, patterns must always be compatible with each other, since no automatic splitting takes place. But the following definition of GCD is OK, although patterns overlap: fun gcd2 :: nat ⇒ nat ⇒ nat 39 where gcd2 x 0 = x | gcd2 0 y = y | gcd2 (Suc x)(Suc y) = (if x < y then gcd2 (Suc x)(y − x) else gcd2 (x − y)(Suc y)) thm gcd2 .simps thm gcd2 .induct 8.4.2 Guards We can reformulate the above example using guarded patterns: function gcd3 :: nat ⇒ nat ⇒ nat where gcd3 x 0 = x | gcd3 0 y = y | gcd3 (Suc x)(Suc y) = gcd3 (Suc x)(y − x) if x < y | gcd3 (Suc x)(Suc y) = gcd3 (x − y)(Suc y) if ¬ x < y apply (case-tac x, case-tac a, auto) apply (case-tac ba, auto) done termination by lexicographic-order thm gcd3 .simps thm gcd3 .induct General patterns allow even strange definitions: function ev :: nat ⇒ bool where ev (2 ∗ n) = True | ev (2 ∗ n + 1 ) = False proof − — completeness is more difficult here . . . fix P :: bool fix x :: nat assume c1 : Vn. x = 2 ∗ n =⇒ P and c2 : Vn. x = 2 ∗ n + 1 =⇒ P have divmod: x = 2 ∗ (x div 2 ) + (x mod 2 ) by auto show P proof (cases x mod 2 = 0 ) case True with divmod have x = 2 ∗ (x div 2 ) by simp with c1 show P . next case False then have x mod 2 = 1 by simp with divmod have x = 2 ∗ (x div 2 ) + 1 by simp with c2 show P . qed qed presburger+ — solve compatibility with presburger 40 termination by lexicographic-order thm ev.simps thm ev.induct thm ev.cases 8.5 Mutual Recursion fun evn od :: nat ⇒ bool where evn 0 = True | od 0 = False | evn (Suc n) = od n | od (Suc n) = evn n thm evn.simps thm od.simps thm evn-od.induct thm evn-od.termination thm evn.elims thm od.elims 8.6 Definitions in local contexts locale my-monoid = fixes opr :: 0a ⇒ 0a ⇒ 0a and un :: 0a assumes assoc: opr (opr x y) z = opr x (opr y z) and lunit: opr un x = x and runit: opr x un = x begin fun foldR :: 0a list ⇒ 0a where foldR [] = un | foldR (x # xs) = opr x (foldR xs) fun foldL :: 0a list ⇒ 0a where foldL [] = un | foldL [x] = x | foldL (x # y # ys) = foldL (opr x y # ys) thm foldL.simps lemma foldR-foldL: foldR xs = foldL xs by (induct xs rule: foldL.induct)(auto simp:lunit runit assoc) 41 thm foldR-foldL end thm my-monoid.foldL.simps thm my-monoid.foldR-foldL 8.7 fun-cases 8.7.1 Predecessor fun pred :: nat ⇒ nat where pred 0 = 0 | pred (Suc n) = n thm pred.elims lemma assumes pred x = y obtains x = 0 y = 0 | n where x = Suc n y = n by (fact pred.elims[OF assms]) If the predecessor of a number is 0, that number must be 0 or 1. fun-cases pred0E[elim]: pred n = 0 lemma pred n = 0 =⇒ n = 0 ∨ n = Suc 0 by (erule pred0E) metis+ Other expressions on the right-hand side also work, but whether the gener- ated rule is useful depends on how well the simplifier can simplify it. This example works well: fun-cases pred42E[elim]: pred n = 42 lemma pred n = 42 =⇒ n = 43 by (erule pred42E) 8.7.2 List to option fun list-to-option :: 0a list ⇒ 0a option where list-to-option [x] = Some x | list-to-option - = None fun-cases list-to-option-NoneE: list-to-option xs = None and list-to-option-SomeE: list-to-option xs = Some x lemma list-to-option xs = Some y =⇒ xs = [y] by (erule list-to-option-SomeE) 42 8.7.3 Boolean Functions fun xor :: bool ⇒ bool ⇒ bool where xor False False = False | xor True True = False | xor - - = True thm xor.elims fun-cases does not only recognise function equations, but also works with functions that return a boolean, e.g.: fun-cases xor-TrueE: xor a b and xor-FalseE: ¬xor a b print-theorems 8.7.4 Many parameters fun sum4 :: nat ⇒ nat ⇒ nat ⇒ nat ⇒ nat where sum4 a b c d = a + b + c + d fun-cases sum40E: sum4 a b c d = 0 lemma sum4 a b c d = 0 =⇒ a = 0 by (erule sum40E) 8.8 Partial Function Definitions Partial functions in the option monad: partial-function (option) collatz :: nat ⇒ nat list option where collatz n = (if n ≤ 1 then Some [n] else if even n then do { ns ← collatz (n div 2 ); Some (n # ns) } else do { ns ← collatz (3 ∗ n + 1 ); Some (n # ns)}) declare collatz.simps[code] value collatz 23 Tail-recursive functions: partial-function (tailrec) fixpoint :: ( 0a ⇒ 0a) ⇒ 0a ⇒ 0a where fixpoint f x = (if f x = x then x else fixpoint f (f x)) 8.9 Regression tests The following examples mainly serve as tests for the function package. 43 fun listlen :: 0a list ⇒ nat where listlen [] = 0 | listlen (x#xs) = Suc (listlen xs) 8.9.1 Context recursion fun f :: nat ⇒ nat where zero: f 0 = 0 | succ: f (Suc n) = (if f n = 0 then 0 else f n) 8.9.2 A combination of context and nested recursion function h :: nat ⇒ nat where h 0 = 0 | h (Suc n) = (if h n = 0 then h (h n) else h n) by pat-completeness auto 8.9.3 Context, but no recursive call fun i :: nat ⇒ nat where i 0 = 0 | i (Suc n) = (if n = 0 then 0 else i n) 8.9.4 Tupled nested recursion fun fa :: nat ⇒ nat ⇒ nat where fa 0 y = 0 | fa (Suc n) y = (if fa n y = 0 then 0 else fa n y) 8.9.5 Let fun j :: nat ⇒ nat where j 0 = 0 | j (Suc n) = (let u = n in Suc (j u)) There were some problems with fresh names . . . function k :: nat ⇒ nat where k x = (let a = x; b = x in k x) by pat-completeness auto function f2 :: (nat × nat) ⇒ (nat × nat) where 44 f2 p = (let (x,y) = p in f2 (y,x)) by pat-completeness auto 8.9.6 Abbreviations fun f3 :: 0a set ⇒ bool where f3 x = finite x 8.9.7 Simple Higher-Order Recursion datatype 0a tree = Leaf 0a | Branch 0a tree list fun treemap :: ( 0a ⇒ 0a) ⇒ 0a tree ⇒ 0a tree where treemap fn (Leaf n) = (Leaf (fn n)) | treemap fn (Branch l) = (Branch (map (treemap fn) l)) fun tinc :: nat tree ⇒ nat tree where tinc (Leaf n) = Leaf (Suc n) | tinc (Branch l) = Branch (map tinc l) fun testcase :: 0a tree ⇒ 0a list where testcase (Leaf a) = [a] | testcase (Branch x) = (let xs = concat (map testcase x); ys = concat (map testcase x) in xs @ ys) 8.9.8 Pattern matching on records record point = Xcoord :: int Ycoord :: int function swp :: point ⇒ point where swp (| Xcoord = x, Ycoord = y |) = (| Xcoord = y, Ycoord = x |) proof − fix P x assume Vxa y. x = (|Xcoord = xa, Ycoord = y|) =⇒ P then show P by (cases x) qed auto termination by rule auto 8.9.9 The diagonal function fun diag :: bool ⇒ bool ⇒ bool ⇒ nat 45 where diag x True False = 1 | diag False y True = 2 | diag True False z = 3 | diag True True True = 4 | diag False False False = 5 8.9.10 Many equations (quadratic blowup) datatype DT = A | B | C | D | E | F | G | H | I | J | K | L | M | N | P | Q | R | S | T | U | V fun big :: DT ⇒ nat where big A = 0 | big B = 0 | big C = 0 | big D = 0 | big E = 0 | big F = 0 | big G = 0 | big H = 0 | big I = 0 | big J = 0 | big K = 0 | big L = 0 | big M = 0 | big N = 0 | big P = 0 | big Q = 0 | big R = 0 | big S = 0 | big T = 0 | big U = 0 | big V = 0 8.9.11 Automatic pattern splitting fun f4 :: nat ⇒ nat ⇒ bool where f4 0 0 = True | f4 - - = False 8.9.12 Polymorphic partial-function partial-function (option) f5 :: 0a list ⇒ 0a option where f5 x = f5 x 46 end 9 Examples of automatically derived induction rules theory Induction-Schema imports Main begin 9.1 Some simple induction principles on nat lemma nat-standard-induct: [[P 0 ; Vn. P n =⇒ P (Suc n)]] =⇒ P x by induction-schema (pat-completeness, lexicographic-order) lemma nat-induct2 : [[ P 0 ; P (Suc 0 ); Vk. P k ==> P (Suc k) ==> P (Suc (Suc k)) ]] =⇒ P n by induction-schema (pat-completeness, lexicographic-order) lemma minus-one-induct: [[Vn::nat. (n 6= 0 =⇒ P (n − 1 )) =⇒ P n]] =⇒ P x by induction-schema (pat-completeness, lexicographic-order) theorem diff-induct: (!!x. P x 0 ) ==> (!!y. P 0 (Suc y)) ==> (!!x y. P x y ==> P (Suc x)(Suc y)) ==> P m n by induction-schema (pat-completeness, lexicographic-order) lemma list-induct2 0: [[ P [] []; Vx xs. P (x#xs) []; Vy ys. P [] (y#ys); Vx xs y ys. P xs ys =⇒ P (x#xs)(y#ys) ]] =⇒ P xs ys by induction-schema (pat-completeness, lexicographic-order) theorem even-odd-induct: assumes R 0 assumes Q 0 assumes Vn. Q n =⇒ R (Suc n) assumes Vn. R n =⇒ Q (Suc n) shows R n Q n using assms by induction-schema (pat-completeness+, lexicographic-order) end 47 10 Test of Locale Interpretation theory LocaleTest2 imports Main GCD begin 11 Interpretation of Defined Concepts Naming convention for global objects: prefixes D and d 11.1 Lattices Much of the lattice proofs are from HOL/Lattice. 11.1.1 Definitions locale dpo = fixes le :: [ 0a, 0a] => bool (infixl v 50 ) assumes refl [intro, simp]: x v x and antisym [intro]: [| x v y; y v x |] ==> x = y and trans [trans]: [| x v y; y v z |] ==> x v z begin theorem circular: [| x v y; y v z; z v x |] ==> x = y & y = z by (blast intro: trans) definition less :: [ 0a, 0a] => bool (infixl 50 ) ∼ where (x y) = (x v y & x < = y) < theorem abs-test: op = (%x y. x y) by 48 and ex-sup: EX sup. dpo.is-sup le x y sup begin definition meet :: [ 0a, 0a] => 0a (infixl u 70 ) where x u y = (THE inf . is-inf x y inf ) definition join :: [ 0a, 0a] => 0a (infixl t 65 ) where x t y = (THE sup. is-sup x y sup) lemma is-infI [intro?]: i v x =⇒ i v y =⇒ (Vz. z v x =⇒ z v y =⇒ z v i) =⇒ is-inf x y i by (unfold is-inf-def ) blast lemma is-inf-lower [elim?]: is-inf x y i =⇒ (i v x =⇒ i v y =⇒ C ) =⇒ C by (unfold is-inf-def ) blast lemma is-inf-greatest [elim?]: is-inf x y i =⇒ z v x =⇒ z v y =⇒ z v i by (unfold is-inf-def ) blast theorem is-inf-uniq: is-inf x y i =⇒ is-inf x y i 0 =⇒ i = i 0 proof − assume inf : is-inf x y i assume inf 0: is-inf x y i 0 show ?thesis proof (rule antisym) from inf 0 show i v i 0 proof (rule is-inf-greatest) from inf show i v x .. from inf show i v y .. qed from inf show i 0 v i proof (rule is-inf-greatest) from inf 0 show i 0 v x .. from inf 0 show i 0 v y .. qed qed qed theorem is-inf-related [elim?]: x v y =⇒ is-inf x y x proof − assume x v y show ?thesis proof show x v x .. 49 show x v y by fact fix z assume z v x and z v y show z v x by fact qed qed lemma meet-equality [elim?]: is-inf x y i =⇒ x u y = i proof (unfold meet-def ) assume is-inf x y i then show (THE i. is-inf x y i) = i by (rule the-equality)(rule is-inf-uniq [OF - his-inf x y i i]) qed lemma meetI [intro?]: i v x =⇒ i v y =⇒ (Vz. z v x =⇒ z v y =⇒ z v i) =⇒ x u y = i by (rule meet-equality, rule is-infI ) blast+ lemma is-inf-meet [intro?]: is-inf x y (x u y) proof (unfold meet-def ) from ex-inf obtain i where is-inf x y i .. then show is-inf x y (THE i. is-inf x y i) by (rule theI )(rule is-inf-uniq [OF - his-inf x y i i]) qed lemma meet-left [intro?]: x u y v x by (rule is-inf-lower)(rule is-inf-meet) lemma meet-right [intro?]: x u y v y by (rule is-inf-lower)(rule is-inf-meet) lemma meet-le [intro?]: [| z v x; z v y |] ==> z v x u y by (rule is-inf-greatest)(rule is-inf-meet) lemma is-supI [intro?]: x v s =⇒ y v s =⇒ (Vz. x v z =⇒ y v z =⇒ s v z) =⇒ is-sup x y s by (unfold is-sup-def ) blast lemma is-sup-least [elim?]: is-sup x y s =⇒ x v z =⇒ y v z =⇒ s v z by (unfold is-sup-def ) blast lemma is-sup-upper [elim?]: is-sup x y s =⇒ (x v s =⇒ y v s =⇒ C ) =⇒ C by (unfold is-sup-def ) blast theorem is-sup-uniq: is-sup x y s =⇒ is-sup x y s 0 =⇒ s = s 0 proof − 50 assume sup: is-sup x y s assume sup 0: is-sup x y s 0 show ?thesis proof (rule antisym) from sup show s v s 0 proof (rule is-sup-least) from sup 0 show x v s 0 .. from sup 0 show y v s 0 .. qed from sup 0 show s 0 v s proof (rule is-sup-least) from sup show x v s .. from sup show y v s .. qed qed qed theorem is-sup-related [elim?]: x v y =⇒ is-sup x y y proof − assume x v y show ?thesis proof show x v y by fact show y v y .. fix z assume x v z and y v z show y v z by fact qed qed lemma join-equality [elim?]: is-sup x y s =⇒ x t y = s proof (unfold join-def ) assume is-sup x y s then show (THE s. is-sup x y s) = s by (rule the-equality)(rule is-sup-uniq [OF - his-sup x y s i]) qed lemma joinI [intro?]: x v s =⇒ y v s =⇒ (Vz. x v z =⇒ y v z =⇒ s v z) =⇒ x t y = s by (rule join-equality, rule is-supI ) blast+ lemma is-sup-join [intro?]: is-sup x y (x t y) proof (unfold join-def ) from ex-sup obtain s where is-sup x y s .. then show is-sup x y (THE s. is-sup x y s) by (rule theI )(rule is-sup-uniq [OF - his-sup x y s i]) qed lemma join-left [intro?]: x v x t y 51 by (rule is-sup-upper)(rule is-sup-join) lemma join-right [intro?]: y v x t y by (rule is-sup-upper)(rule is-sup-join) lemma join-le [intro?]: [| x v z; y v z |] ==> x t y v z by (rule is-sup-least)(rule is-sup-join) theorem meet-assoc:(x u y) u z = x u (y u z) proof (rule meetI ) show x u (y u z) v x u y proof show x u (y u z) v x .. show x u (y u z) v y proof − have x u (y u z) v y u z .. also have ... v y .. finally show ?thesis . qed qed show x u (y u z) v z proof − have x u (y u z) v y u z .. also have ... v z .. finally show ?thesis . qed fix w assume w v x u y and w v z show w v x u (y u z) proof show w v x proof − have w v x u y by fact also have ... v x .. finally show ?thesis . qed show w v y u z proof show w v y proof − have w v x u y by fact also have ... v y .. finally show ?thesis . qed show w v z by fact qed qed qed 52 theorem meet-commute: x u y = y u x proof (rule meetI ) show y u x v x .. show y u x v y .. fix z assume z v y and z v x then show z v y u x .. qed theorem meet-join-absorb: x u (x t y) = x proof (rule meetI ) show x v x .. show x v x t y .. fix z assume z v x and z v x t y show z v x by fact qed theorem join-assoc:(x t y) t z = x t (y t z) proof (rule joinI ) show x t y v x t (y t z) proof show x v x t (y t z) .. show y v x t (y t z) proof − have y v y t z .. also have ... v x t (y t z) .. finally show ?thesis . qed qed show z v x t (y t z) proof − have z v y t z .. also have ... v x t (y t z) .. finally show ?thesis . qed fix w assume x t y v w and z v w show x t (y t z) v w proof show x v w proof − have x v x t y .. also have ... v w by fact finally show ?thesis . qed show y t z v w proof show y v w proof − have y v x t y .. 53 also have ... v w by fact finally show ?thesis . qed show z v w by fact qed qed qed theorem join-commute: x t y = y t x proof (rule joinI ) show x v y t x .. show y v y t x .. fix z assume y v z and x v z then show y t x v z .. qed theorem join-meet-absorb: x t (x u y) = x proof (rule joinI ) show x v x .. show x u y v x .. fix z assume x v z and x u y v z show x v z by fact qed theorem meet-idem: x u x = x proof − have x u (x t (x u x)) = x by (rule meet-join-absorb) also have x t (x u x) = x by (rule join-meet-absorb) finally show ?thesis . qed theorem meet-related [elim?]: x v y =⇒ x u y = x proof (rule meetI ) assume x v y show x v x .. show x v y by fact fix z assume z v x and z v y show z v x by fact qed theorem meet-related2 [elim?]: y v x =⇒ x u y = y by (drule meet-related)(simp add: meet-commute) theorem join-related [elim?]: x v y =⇒ x t y = y proof (rule joinI ) assume x v y show y v y .. show x v y by fact fix z assume x v z and y v z 54 show y v z by fact qed theorem join-related2 [elim?]: y v x =⇒ x t y = x by (drule join-related)(simp add: join-commute) Additional theorems theorem meet-connection:(x v y) = (x u y = x) proof assume x v y then have is-inf x y x .. then show x u y = x .. next have x u y v y .. also assume x u y = x finally show x v y . qed theorem meet-connection2 :(x v y) = (y u x = x) using meet-commute meet-connection by simp theorem join-connection:(x v y) = (x t y = y) proof assume x v y then have is-sup x y y .. then show x t y = y .. next have x v x t y .. also assume x t y = y finally show x v y . qed theorem join-connection2 :(x v y) = (x t y = y) using join-commute join-connection by simp Naming according to Jacobson I, p. 459. lemmas L1 = join-commute meet-commute lemmas L2 = join-assoc meet-assoc lemmas L4 = join-meet-absorb meet-join-absorb end locale ddlat = dlat + assumes meet-distr: dlat.meet le x (dlat.join le y z) = dlat.join le (dlat.meet le x y)(dlat.meet le x z) begin 55 lemma join-distr: x t (y u z) = (x t y) u (x t z) Jacobson I, p. 462 proof − have x t (y u z) = (x t (x u z)) t (y u z) by (simp add: L4 ) also have ... = x t ((x u z) t (y u z)) by (simp add: L2 ) also have ... = x t ((x t y) u z) by (simp add: L1 meet-distr) also have ... = ((x t y) u x) t ((x t y) u z) by (simp add: L1 L4 ) also have ... = (x t y) u (x t z) by (simp add: meet-distr) finally show ?thesis . qed end locale dlo = dpo + assumes total: x v y | y v x begin lemma less-total: x y | x = y | y x using total < < by (unfold less-def ) blast end sublocale dlo < dlat proof fix x y from total have is-inf x y (if x v y then x else y) by (auto simp: is-inf-def ) then show EX inf . is-inf x y inf by blast next fix x y from total have is-sup x y (if x v y then y else x) by (auto simp: is-sup-def ) then show EX sup. is-sup x y sup by blast qed sublocale dlo < ddlat proof fix x y z show x u (y t z) = x u y t x u z (is ?l = ?r) Jacobson I, p. 462 proof − { assume c: y v x z v x from c have ?l = y t z by (metis c join-connection2 join-related2 meet-connection meet-related2 total) 56 also from c have ... = ?r by (metis meet-related2 ) finally have ?l = ?r . } moreover { assume c: x v y | x v z from c have ?l = x by (metis join-connection2 join-related2 meet-connection total trans) also from c have ... = ?r by (metis join-commute join-related2 meet-connection meet-related2 total) finally have ?l = ?r . } moreover note total ultimately show ?thesis by blast qed qed 11.1.2 Total order <= on int interpretation int: dpo op <= :: [int, int] => bool rewrites (dpo.less (op <=) (x::int) y) = (x < y) We give interpretation for less, but not is-inf and is-sub. proof − show dpo (op <= :: [int, int] => bool) proof qed auto then interpret int: dpo op <= :: [int, int] => bool . Gives interpreted version of less-def (without condition). show (dpo.less (op <=) (x::int) y) = (x < y) by (unfold int.less-def ) auto qed thm int.circular lemma [[ (x::int) ≤ y; y ≤ z; z ≤ x]] =⇒ x = y ∧ y = z apply (rule int.circular) apply assumption apply assumption apply assumption done thm int.abs-test lemma (op < :: [int, int] => bool) = op < apply (rule int.abs-test) done interpretation int: dlat op <= :: [int, int] => bool rewrites meet-eq: dlat.meet (op <=) (x::int) y = min x y and join-eq: dlat.join (op <=) (x::int) y = max x y proof − show dlat (op <= :: [int, int] => bool) apply unfold-locales apply (unfold int.is-inf-def int.is-sup-def ) apply arith+ done then interpret int: dlat op <= :: [int, int] => bool . 57 Interpretation to ease use of definitions, which are conditional in general but un- conditional after interpretation. show dlat.meet (op <=) (x::int) y = min x y apply (unfold int.meet-def ) apply (rule the-equality) apply (unfold int.is-inf-def ) by auto show dlat.join (op <=) (x::int) y = max x y apply (unfold int.join-def ) apply (rule the-equality) apply (unfold int.is-sup-def ) by auto qed interpretation int: dlo op <= :: [int, int] => bool proof qed arith Interpreted theorems from the locales, involving defined terms. thm int.less-def from dpo thm int.meet-left from dlat thm int.meet-distr from ddlat thm int.less-total from dlo 11.1.3 Total order <= on nat interpretation nat: dpo op <= :: [nat, nat] => bool rewrites dpo.less (op <=) (x::nat) y = (x < y) We give interpretation for less, but not is-inf and is-sub. proof − show dpo (op <= :: [nat, nat] => bool) proof qed auto then interpret nat: dpo op <= :: [nat, nat] => bool . Gives interpreted version of less-def (without condition). show dpo.less (op <=) (x::nat) y = (x < y) apply (unfold nat.less-def ) apply auto done 58 qed interpretation nat: dlat op <= :: [nat, nat] => bool rewrites dlat.meet (op <=) (x::nat) y = min x y and dlat.join (op <=) (x::nat) y = max x y proof − show dlat (op <= :: [nat, nat] => bool) apply unfold-locales apply (unfold nat.is-inf-def nat.is-sup-def ) apply arith+ done then interpret nat: dlat op <= :: [nat, nat] => bool . Interpretation to ease use of definitions, which are conditional in general but un- conditional after interpretation. show dlat.meet (op <=) (x::nat) y = min x y apply (unfold nat.meet-def ) apply (rule the-equality) apply (unfold nat.is-inf-def ) by auto show dlat.join (op <=) (x::nat) y = max x y apply (unfold nat.join-def ) apply (rule the-equality) apply (unfold nat.is-sup-def ) by auto qed interpretation nat: dlo op <= :: [nat, nat] => bool proof qed arith Interpreted theorems from the locales, involving defined terms. thm nat.less-def from dpo thm nat.meet-left from dlat thm nat.meet-distr from ddlat thm nat.less-total from ldo 11.1.4 Lattice dvd on nat interpretation nat-dvd: dpo op dvd :: [nat, nat] => bool rewrites dpo.less (op dvd)(x::nat) y = (x dvd y & x ∼= y) 59 We give interpretation for less, but not is-inf and is-sub. proof − show dpo (op dvd :: [nat, nat] => bool) proof qed (auto simp: dvd-def ) then interpret nat-dvd: dpo op dvd :: [nat, nat] => bool . Gives interpreted version of less-def (without condition). show dpo.less (op dvd)(x::nat) y = (x dvd y & x ∼= y) apply (unfold nat-dvd.less-def ) apply auto done qed interpretation nat-dvd: dlat op dvd :: [nat, nat] => bool rewrites dlat.meet (op dvd)(x::nat) y = gcd x y and dlat.join (op dvd)(x::nat) y = lcm x y proof − show dlat (op dvd :: [nat, nat] => bool) apply unfold-locales apply (unfold nat-dvd.is-inf-def nat-dvd.is-sup-def ) apply (rule-tac x = gcd x y in exI ) apply auto [1 ] apply (rule-tac x = lcm x y in exI ) apply (auto intro: dvd-lcm1 dvd-lcm2 lcm-least) done then interpret nat-dvd: dlat op dvd :: [nat, nat] => bool . Interpretation to ease use of definitions, which are conditional in general but un- conditional after interpretation. show dlat.meet (op dvd)(x::nat) y = gcd x y apply (unfold nat-dvd.meet-def ) apply (rule the-equality) apply (unfold nat-dvd.is-inf-def ) by auto show dlat.join (op dvd)(x::nat) y = lcm x y apply (unfold nat-dvd.join-def ) apply (rule the-equality) apply (unfold nat-dvd.is-sup-def ) by (auto intro: dvd-lcm1 dvd-lcm2 lcm-least) qed Interpreted theorems from the locales, involving defined terms. thm nat-dvd.less-def from dpo lemma ((x::nat) dvd y & x ∼= y) = (x dvd y & x ∼= y) apply (rule nat-dvd.less-def ) done thm nat-dvd.meet-left 60 from dlat lemma gcd x y dvd (x::nat) apply (rule nat-dvd.meet-left) done 11.2 Group example with defined operations inv and unit 11.2.1 Locale declarations and lemmas locale Dsemi = fixes prod (infixl ∗∗ 65 ) assumes assoc:(x ∗∗ y) ∗∗ z = x ∗∗ (y ∗∗ z) locale Dmonoid = Dsemi + fixes one assumes l-one [simp]: one ∗∗ x = x and r-one [simp]: x ∗∗ one = x begin definition inv where inv x = (THE y. x ∗∗ y = one & y ∗∗ x = one) definition unit where unit x = (EX y. x ∗∗ y = one & y ∗∗ x = one) lemma inv-unique: assumes eq: y ∗∗ x = one x ∗∗ y 0 = one shows y = y 0 proof − from eq have y = y ∗∗ (x ∗∗ y 0) by (simp add: r-one) also have ... = (y ∗∗ x) ∗∗ y 0 by (simp add: assoc) also from eq have ... = y 0 by (simp add: l-one) finally show ?thesis . qed lemma unit-one [intro, simp]: unit one by (unfold unit-def ) auto lemma unit-l-inv-ex: unit x ==> ∃ y. y ∗∗ x = one by (unfold unit-def ) auto lemma unit-r-inv-ex: unit x ==> ∃ y. x ∗∗ y = one by (unfold unit-def ) auto lemma unit-l-inv: unit x ==> inv x ∗∗ x = one apply (simp add: unit-def inv-def ) apply (erule exE) 61 apply (rule theI2 , fast) apply (rule inv-unique) apply fast+ done lemma unit-r-inv: unit x ==> x ∗∗ inv x = one apply (simp add: unit-def inv-def ) apply (erule exE) apply (rule theI2 , fast) apply (rule inv-unique) apply fast+ done lemma unit-inv-unit [intro, simp]: unit x ==> unit (inv x) proof − assume x: unit x show unit (inv x) by (auto simp add: unit-def intro: unit-l-inv unit-r-inv x) qed lemma unit-l-cancel [simp]: unit x ==> (x ∗∗ y = x ∗∗ z) = (y = z) proof assume eq: x ∗∗ y = x ∗∗ z and G: unit x then have (inv x ∗∗ x) ∗∗ y = (inv x ∗∗ x) ∗∗ z by (simp add: assoc) with G show y = z by (simp add: unit-l-inv) next assume eq: y = z and G: unit x then show x ∗∗ y = x ∗∗ z by simp qed lemma unit-inv-inv [simp]: unit x ==> inv (inv x) = x proof − assume x: unit x then have inv x ∗∗ inv (inv x) = inv x ∗∗ x by (simp add: unit-l-inv unit-r-inv) with x show ?thesis by simp qed lemma inv-inj-on-unit: inj-on inv {x. unit x} proof (rule inj-onI , simp) fix x y 62 assume G: unit x unit y and eq: inv x = inv y then have inv (inv x) = inv (inv y) by simp with G show x = y by simp qed lemma unit-inv-comm: assumes inv: x ∗∗ y = one and G: unit x unit y shows y ∗∗ x = one proof − from G have x ∗∗ y ∗∗ x = x ∗∗ one by (auto simp add: inv) with G show ?thesis by (simp del: r-one add: assoc) qed end locale Dgrp = Dmonoid + assumes unit [intro, simp]: Dmonoid.unit (op ∗∗) one x begin lemma l-inv-ex [simp]: ∃ y. y ∗∗ x = one using unit-l-inv-ex by simp lemma r-inv-ex [simp]: ∃ y. x ∗∗ y = one using unit-r-inv-ex by simp lemma l-inv [simp]: inv x ∗∗ x = one using unit-l-inv by simp lemma l-cancel [simp]: (x ∗∗ y = x ∗∗ z) = (y = z) using unit-l-inv by simp lemma r-inv [simp]: x ∗∗ inv x = one proof − have inv x ∗∗ (x ∗∗ inv x) = inv x ∗∗ one by (simp add: assoc [symmetric] l-inv) then show ?thesis by (simp del: r-one) qed lemma r-cancel [simp]: (y ∗∗ x = z ∗∗ x) = (y = z) proof 63 assume eq: y ∗∗ x = z ∗∗ x then have y ∗∗ (x ∗∗ inv x) = z ∗∗ (x ∗∗ inv x) by (simp add: assoc [symmetric] del: r-inv) then show y = z by simp qed simp lemma inv-one [simp]: inv one = one proof − have inv one = one ∗∗ (inv one) by (simp del: r-inv) moreover have ... = one by simp finally show ?thesis . qed lemma inv-inv [simp]: inv (inv x) = x using unit-inv-inv by simp lemma inv-inj : inj-on inv UNIV using inv-inj-on-unit by simp lemma inv-mult-group: inv (x ∗∗ y) = inv y ∗∗ inv x proof − have inv (x ∗∗ y) ∗∗ (x ∗∗ y) = (inv y ∗∗ inv x) ∗∗ (x ∗∗ y) by (simp add: assoc l-inv)(simp add: assoc [symmetric]) then show ?thesis by (simp del: l-inv) qed lemma inv-comm: x ∗∗ y = one ==> y ∗∗ x = one by (rule unit-inv-comm) auto lemma inv-equality: y ∗∗ x = one ==> inv x = y apply (simp add: inv-def ) apply (rule the-equality) apply (simp add: inv-comm [of y x]) apply (rule r-cancel [THEN iffD1 ], auto) done end locale Dhom = prod: Dgrp prod one + sum: Dgrp sum zero for prod (infixl ∗∗ 65 ) and one and sum (infixl +++ 60 ) and zero + fixes hom assumes hom-mult [simp]: hom (x ∗∗ y) = hom x +++ hom y 64 begin lemma hom-one [simp]: hom one = zero proof − have hom one +++ zero = hom one +++ hom one by (simp add: hom-mult [symmetric] del: hom-mult) then show ?thesis by (simp del: sum.r-one) qed end 11.2.2 Interpretation of Functions interpretation Dfun: Dmonoid op o id :: 0a => 0a rewrites Dmonoid.unit (op o) id f = bij (f :: 0a => 0a) proof − show Dmonoid op o (id :: 0a => 0a) proof qed (simp-all add: o-assoc) note Dmonoid = this show Dmonoid.unit (op o)(id :: 0a => 0a) f = bij f apply (unfold Dmonoid.unit-def [OF Dmonoid]) apply rule apply clarify proof − fix f g assume id1 : f o g = id and id2 : g o f = id show bij f proof (rule bijI ) show inj f proof (rule inj-onI ) fix x y assume f x = f y then have (g o f ) x = (g o f ) y by simp with id2 show x = y by simp qed next show surj f proof (rule surjI ) fix x from id1 have (f o g) x = x by simp then show f (g x) = x by simp qed qed next fix f assume bij : bij f then 65 have inv: f o Hilbert-Choice.inv f = id & Hilbert-Choice.inv f o f = id by (simp add: bij-def surj-iff inj-iff ) show EX g. f o g = id & g o f = id by rule (rule inv) qed qed thm Dmonoid.unit-def Dfun.unit-def thm Dmonoid.inv-inj-on-unit Dfun.inv-inj-on-unit lemma unit-id: (f :: unit => unit) = id by rule simp interpretation Dfun: Dgrp op o id :: unit => unit rewrites Dmonoid.inv (op o) id f = inv (f :: unit => unit) proof − have Dmonoid op o (id :: 0a => 0a) .. note Dmonoid = this show Dgrp (op o)(id :: unit => unit) apply unfold-locales apply (unfold Dmonoid.unit-def [OF Dmonoid]) apply (insert unit-id) apply simp done show Dmonoid.inv (op o) id f = inv (f :: unit => unit) apply (unfold Dmonoid.inv-def [OF Dmonoid]) apply (insert unit-id) apply simp apply (rule the-equality) apply rule apply rule apply simp done qed thm Dfun.unit-l-inv Dfun.l-inv thm Dfun.inv-equality thm Dfun.inv-equality end 12 Using extensible records in HOL – points and coloured points theory Records 66 imports Main begin 12.1 Points record point = xpos :: nat ypos :: nat Apart many other things, above record declaration produces the following theorems: thm point.simps thm point.iffs thm point.defs The set of theorems point.simps is added automatically to the standard simpset, point.iffs is added to the Classical Reasoner and Simplifier context. Record declarations define new types and type abbreviations: point = (|xpos :: nat, ypos :: nat|) = () point-ext-type 0a point-scheme = (|xpos :: nat, ypos :: nat, ... :: 0a|) = 0a point-ext-type consts foo2 :: (| xpos :: nat, ypos :: nat |) consts foo4 :: 0a => (| xpos :: nat, ypos :: nat, ... :: 0a |) 12.1.1 Introducing concrete records and record schemes definition foo1 :: point where foo1 = (| xpos = 1 , ypos = 0 |) definition foo3 :: 0a => 0a point-scheme where foo3 ext = (| xpos = 1 , ypos = 0 , ... = ext |) 12.1.2 Record selection and record update definition getX :: 0a point-scheme => nat where getX r = xpos r definition setX :: 0a point-scheme => nat => 0a point-scheme where setX r n = r (| xpos := n |) 12.1.3 Some lemmas about records Basic simplifications. lemma point.make n p = (| xpos = n, ypos = p |) by (simp only: point.make-def ) lemma xpos (| xpos = m, ypos = n, ... = p |) = m 67 by simp lemma (| xpos = m, ypos = n, ... = p |)(| xpos:= 0 |) = (| xpos = 0 , ypos = n, ... = p |) by simp Equality of records. lemma n = n 0 ==> p = p 0 ==> (| xpos = n, ypos = p |) = (| xpos = n 0, ypos = p 0 |) — introduction of concrete record equality by simp lemma (| xpos = n, ypos = p |) = (| xpos = n 0, ypos = p 0 |) ==> n = n 0 — elimination of concrete record equality by simp lemma r (| xpos := n |)(| ypos := m |) = r (| ypos := m |)(| xpos := n |) — introduction of abstract record equality by simp lemma r (| xpos := n |) = r (| xpos := n 0 |) ==> n = n 0 — elimination of abstract record equality (manual proof) proof − assume r (| xpos := n |) = r (| xpos := n 0 |)(is ?lhs = ?rhs) then have xpos ?lhs = xpos ?rhs by simp then show ?thesis by simp qed Surjective pairing lemma r = (| xpos = xpos r, ypos = ypos r |) by simp lemma r = (| xpos = xpos r, ypos = ypos r, ... = point.more r |) by simp Representation of records by cases or (degenerate) induction. lemma r(| xpos := n |)(| ypos := m |) = r (| ypos := m |)(| xpos := n |) proof (cases r) fix xpos ypos more assume r = (| xpos = xpos, ypos = ypos, ... = more |) then show ?thesis by simp qed lemma r (| xpos := n |)(| ypos := m |) = r (| ypos := m |)(| xpos := n |) proof (induct r) fix xpos ypos more show (| xpos = xpos, ypos = ypos, ... = more |)(| xpos := n, ypos := m |) = 68 (| xpos = xpos, ypos = ypos, ... = more |)(| ypos := m, xpos := n |) by simp qed lemma r (| xpos := n |)(| xpos := m |) = r (| xpos := m |) proof (cases r) fix xpos ypos more assume r = (|xpos = xpos, ypos = ypos,... = more|) then show ?thesis by simp qed lemma r (| xpos := n |)(| xpos := m |) = r (| xpos := m |) proof (cases r) case fields then show ?thesis by simp qed lemma r (| xpos := n |)(| xpos := m |) = r (| xpos := m |) by (cases r) simp Concrete records are type instances of record schemes. definition foo5 :: nat where foo5 = getX (| xpos = 1 , ypos = 0 |) Manipulating the “...” (more) part. definition incX :: 0a point-scheme => 0a point-scheme where incX r = (| xpos = xpos r + 1 , ypos = ypos r, ... = point.more r |) lemma incX r = setX r (Suc (getX r)) by (simp add: getX-def setX-def incX-def ) An alternative definition. definition incX 0 :: 0a point-scheme => 0a point-scheme where incX 0 r = r (| xpos := xpos r + 1 |) 12.2 Coloured points: record extension datatype colour = Red | Green | Blue record cpoint = point + colour :: colour The record declaration defines a new type constructor and abbreviations: cpoint = (| xpos :: nat, ypos :: nat, colour :: colour |) = () cpoint-ext-type point-ext-type 0a cpoint-scheme = (| xpos :: nat, ypos :: nat, colour :: colour, ... :: 0a |) = 0a cpoint-ext-type point-ext-type 69 consts foo6 :: cpoint consts foo7 :: (| xpos :: nat, ypos :: nat, colour :: colour |) consts foo8 :: 0a cpoint-scheme consts foo9 :: (| xpos :: nat, ypos :: nat, colour :: colour, ... :: 0a |) Functions on point schemes work for cpoints as well. definition foo10 :: nat where foo10 = getX (| xpos = 2 , ypos = 0 , colour = Blue |) 12.2.1 Non-coercive structural subtyping Term foo11 has type cpoint, not type point — Great! definition foo11 :: cpoint where foo11 = setX (| xpos = 2 , ypos = 0 , colour = Blue |) 0 12.3 Other features Field names contribute to record identity. record point 0 = xpos 0 :: nat ypos 0 :: nat May not apply getX to (| xpos 0 = 2 , ypos 0 = 0 |) – type error. Polymorphic records. record 0a point 00 = point + content :: 0a type-synonym cpoint 00 = colour point 00 Updating a record field with an identical value is simplified. lemma r (| xpos := xpos r |) = r by simp Only the most recent update to a component survives simplification. lemma r (| xpos := x, ypos := y, xpos := x 0 |) = r (| ypos := y, xpos := x 0 |) by simp In some cases its convenient to automatically split (quantified) records. For this purpose there is the simproc Record.split_simproc and the tac- tic Record.split_simp_tac. The simplification procedure only splits the records, whereas the tactic also simplifies the resulting goal with the stan- dard record simplification rules. A (generalized) predicate on the record is passed as parameter that decides whether or how ‘deep’ to split the record. It can peek on the subterm starting at the quantified occurrence of the record (including the quantifier). The value 0 indicates no split, a value greater 0 70 splits up to the given bound of record extension and finally the value ~1 completely splits the record. Record.split_simp_tac additionally takes a list of equations for simplification and can also split fixed record variables. lemma (∀ r. P (xpos r)) −→ (∀ x. P x) apply (tactic hsimp-tac (put-simpset HOL-basic-ss @{context} ∼ addsimprocs [Record.split-simproc (K 1 )]) 1 i) apply simp done lemma (∀ r. P (xpos r)) −→ (∀ x. P x) ∼ apply (tactic hRecord.split-simp-tac @{context} [] (K 1 ) 1 i) apply simp done lemma (∃ r. P (xpos r)) −→ (∃ x. P x) apply (tactic hsimp-tac (put-simpset HOL-basic-ss @{context} ∼ addsimprocs [Record.split-simproc (K 1 )]) 1 i) apply simp done lemma (∃ r. P (xpos r)) −→ (∃ x. P x) ∼ apply (tactic hRecord.split-simp-tac @{context} [] (K 1 ) 1 i) apply simp done lemma Vr. P (xpos r) =⇒ (∃ x. P x) apply (tactic hsimp-tac (put-simpset HOL-basic-ss @{context} ∼ addsimprocs [Record.split-simproc (K 1 )]) 1 i) apply auto done lemma Vr. P (xpos r) =⇒ (∃ x. P x) ∼ apply (tactic hRecord.split-simp-tac @{context} [] (K 1 ) 1 i) apply auto done lemma P (xpos r) =⇒ (∃ x. P x) ∼ apply (tactic hRecord.split-simp-tac @{context} [] (K 1 ) 1 i) apply auto done lemma True proof − { fix P r assume pre: P (xpos r) then have ∃ x. P x apply − ∼ apply (tactic hRecord.split-simp-tac @{context} [] (K 1 ) 1 i) 71 apply auto done } show ?thesis .. qed The effect of simproc Record.ex_sel_eq_simproc is illustrated by the fol- lowing lemma. lemma ∃ r. xpos r = x apply (tactic hsimp-tac (put-simpset HOL-basic-ss @{context} addsimprocs [Record.ex-sel-eq-simproc]) 1 i) done 12.4 A more complex record expression record ( 0a, 0b, 0c) bar = bar1 :: 0a bar2 :: 0b bar3 :: 0c bar21 :: 0b × 0a bar32 :: 0c × 0b bar31 :: 0c × 0a print-record ( 0a, 0b, 0c) bar 12.5 Some code generation export-code foo1 foo3 foo5 foo10 checking SML Code generation can also be switched off, for instance for very large records declare [[record-codegen = false]] record not-so-large-record = bar520 :: nat bar521 :: nat ∗ nat declare [[record-codegen = true]] end 13 A general “while” combinator theory While-Combinator imports Main begin 13.1 Partial version definition while-option :: ( 0a ⇒ bool) ⇒ ( 0a ⇒ 0a) ⇒ 0a ⇒ 0a option where while-option b c s = (if (∃ k. ∼ b ((c ˆˆ k) s)) 72 then Some ((c ˆˆ (LEAST k. ∼ b ((c ˆˆ k) s))) s) else None) theorem while-option-unfold[code]: while-option b c s = (if b s then while-option b c (c s) else Some s) proof cases assume b s show ?thesis proof (cases ∃ k. ∼ b ((c ˆˆ k) s)) case True then obtain k where 1 : ∼ b ((c ˆˆ k) s) .. with hb s i obtain l where k = Suc l by (cases k) auto with 1 have ∼ b ((c ˆˆ l)(c s)) by (auto simp: funpow-swap1 ) then have 2 : ∃ l. ∼ b ((c ˆˆ l)(c s)) .. from 1 have (LEAST k. ∼ b ((c ˆˆ k) s)) = Suc (LEAST l. ∼ b ((c ˆˆ Suc l) s)) by (rule Least-Suc)(simp add: hb s i) also have ... = Suc (LEAST l. ∼ b ((c ˆˆ l)(c s))) by (simp add: funpow-swap1 ) finally show ?thesis using True 2 hb s i by (simp add: funpow-swap1 while-option-def ) next case False then have ∼ (∃ l. ∼ b ((c ˆˆ Suc l) s)) by blast then have ∼ (∃ l. ∼ b ((c ˆˆ l)(c s))) by (simp add: funpow-swap1 ) with False hb s i show ?thesis by (simp add: while-option-def ) qed next assume [simp]: ∼ b s have least:(LEAST k. ∼ b ((c ˆˆ k) s)) = 0 by (rule Least-equality) auto moreover have ∃ k. ∼ b ((c ˆˆ k) s) by (rule exI [of - 0 ::nat]) auto ultimately show ?thesis unfolding while-option-def by auto qed lemma while-option-stop2 : while-option b c s = Some t =⇒ EX k. t = (cˆˆk) s ∧ ¬ b t apply(simp add: while-option-def split: if-splits) by (metis (lifting) LeastI-ex) lemma while-option-stop: while-option b c s = Some t =⇒ ∼ b t by(metis while-option-stop2 ) theorem while-option-rule: assumes step: !!s. P s ==> b s ==> P (c s) and result: while-option b c s = Some t 73 and init: P s shows P t proof − define k where k = (LEAST k. ∼ b ((c ˆˆ k) s)) from assms have t: t = (c ˆˆ k) s by (simp add: while-option-def k-def split: if-splits) have 1 : ALL i { fix i assume i <= k then have P ((c ˆˆ i) s) by (induct i)(auto simp: init step 1 ) } thus P t by (auto simp: t) qed lemma funpow-commute: [[∀ k 0 < k. f (c ((cˆˆk 0) s)) = c 0 (f ((cˆˆk 0) s))]] =⇒ f ((cˆˆk) s) = (c 0ˆˆk)(f s) by (induct k arbitrary: s) auto lemma while-option-commute-invariant: assumes Invariant: Vs. P s =⇒ b s =⇒ P (c s) assumes TestCommute: Vs. P s =⇒ b s = b 0 (f s) assumes BodyCommute: Vs. P s =⇒ b s =⇒ f (c s) = c 0 (f s) assumes Initial: P s shows map-option f (while-option b c s) = while-option b 0 c 0 (f s) unfolding while-option-def proof (rule trans[OF if-distrib if-cong], safe, unfold option.inject) fix k assume ¬ b ((c ˆˆ k) s) with Initial show ∃ k. ¬ b 0 ((c 0 ˆˆ k)(f s)) proof (induction k arbitrary: s) case 0 thus ?case by (auto simp: TestCommute intro: exI [of - 0 ]) next case (Suc k) thus ?case proof (cases b s) assume b s with Suc.IH [of c s] Suc.prems show ?thesis by (metis BodyCommute Invariant comp-apply funpow.simps(2 ) funpow-swap1 ) next assume ¬ b s with Suc show ?thesis by (auto simp: TestCommute intro: exI [of - 0 ]) qed qed next fix k assume ¬ b 0 ((c 0 ˆˆ k)(f s)) with Initial show ∃ k. ¬ b ((c ˆˆ k) s) proof (induction k arbitrary: s) case 0 thus ?case by (auto simp: TestCommute intro: exI [of - 0 ]) next 74 case (Suc k) thus ?case proof (cases b s) assume b s with Suc.IH [of c s] Suc.prems show ?thesis by (metis BodyCommute Invariant comp-apply funpow.simps(2 ) funpow-swap1 ) next assume ¬ b s with Suc show ?thesis by (auto simp: TestCommute intro: exI [of - 0 ]) qed qed next fix k assume k: ¬ b 0 ((c 0 ˆˆ k)(f s)) have ∗:(LEAST k. ¬ b 0 ((c 0 ˆˆ k)(f s))) = (LEAST k. ¬ b ((c ˆˆ k) s)) (is ?k 0 = ?k) proof (cases ?k 0) case 0 have ¬ b 0 ((c 0 ˆˆ 0 )(f s)) unfolding 0 [symmetric] by (rule LeastI [of - k]) (rule k) hence ¬ b s by (auto simp: TestCommute Initial) hence ?k = 0 by (intro Least-equality) auto with 0 show ?thesis by auto next case (Suc k 0) have ¬ b 0 ((c 0 ˆˆ Suc k 0)(f s)) unfolding Suc[symmetric] by (rule LeastI )(rule k) moreover { fix k assume k ≤ k 0 hence k < ?k 0 unfolding Suc by simp hence b 0 ((c 0 ˆˆ k)(f s)) by (rule iffD1 [OF not-not, OF not-less-Least]) } note b 0 = this { fix k assume k ≤ k 0 hence f ((c ˆˆ k) s) = (c 0 ˆˆ k)(f s) and b ((c ˆˆ k) s) = b 0 ((c 0 ˆˆ k)(f s)) and P ((c ˆˆ k) s) by (induct k)(auto simp: b 0 assms) 0 with hk ≤ k i have b ((c ˆˆ k) s) and f ((c ˆˆ k) s) = (c 0 ˆˆ k)(f s) and P ((c ˆˆ k) s) by (auto simp: b 0) } note b = this(1 ) and body = this(2 ) and inv = this(3 ) hence k 0: f ((c ˆˆ k 0) s) = (c 0 ˆˆ k 0)(f s) by auto ultimately show ?thesis unfolding Suc using b proof (intro Least-equality[symmetric], goal-cases) case 1 hence Test: ¬ b 0 (f ((c ˆˆ Suc k 0) s)) 75 by (auto simp: BodyCommute inv b) have P ((c ˆˆ Suc k 0) s) by (auto simp: Invariant inv b) with Test show ?case by (auto simp: TestCommute) next case 2 thus ?case by (metis not-less-eq-eq) qed qed have f ((c ˆˆ ?k) s) = (c 0 ˆˆ ?k 0)(f s) unfolding ∗ proof (rule funpow-commute, clarify) fix k assume k < ?k hence TestTrue: b ((c ˆˆ k) s) by (auto dest: not-less-Least) from hk < ?k i have P ((c ˆˆ k) s) proof (induct k) case 0 thus ?case by (auto simp: assms) next case (Suc h) hence P ((c ˆˆ h) s) by auto with Suc show ?case by (auto, metis (lifting, no-types) Invariant Suc-lessD not-less-Least) qed with TestTrue show f (c ((c ˆˆ k) s)) = c 0 (f ((c ˆˆ k) s)) by (metis BodyCommute) qed thus ∃ z. (c ˆˆ ?k) s = z ∧ f z = (c 0 ˆˆ ?k 0)(f s) by blast qed lemma while-option-commute: assumes Vs. b s = b 0 (f s) Vs. [[b s]] =⇒ f (c s) = c 0 (f s) shows map-option f (while-option b c s) = while-option b 0 c 0 (f s) by(rule while-option-commute-invariant[where P = λ-. True]) (auto simp add: assms) 13.2 Total version definition while :: ( 0a ⇒ bool) ⇒ ( 0a ⇒ 0a) ⇒ 0a ⇒ 0a where while b c s = the (while-option b c s) lemma while-unfold [code]: while b c s = (if b s then while b c (c s) else s) unfolding while-def by (subst while-option-unfold) simp lemma def-while-unfold: assumes fdef : f == while test do shows f x = (if test x then f (do x) else x) unfolding fdef by (fact while-unfold) The proof rule for while, where P is the invariant. theorem while-rule-lemma: 76 assumes invariant: !!s. P s ==> b s ==> P (c s) and terminate: !!s. P s ==> ¬ b s ==> Q s and wf : wf {(t, s). P s ∧ b s ∧ t = c s} shows P s =⇒ Q (while b c s) using wf apply (induct s) apply simp apply (subst while-unfold) apply (simp add: invariant terminate) done theorem while-rule: [| P s; !!s. [| P s; b s |] ==> P (c s); !!s. [| P s; ¬ b s |] ==> Q s; wf r; !!s. [| P s; b s |] ==> (c s, s) ∈ r |] ==> Q (while b c s) apply (rule while-rule-lemma) prefer 4 apply assumption apply blast apply blast apply (erule wf-subset) apply blast done Proving termination: theorem wf-while-option-Some: assumes wf {(t, s). (P s ∧ b s) ∧ t = c s} and !!s. P s =⇒ b s =⇒ P(c s) and P s shows EX t. while-option b c s = Some t using assms(1 ,3 ) proof (induction s) case less thus ?case using assms(2 ) by (subst while-option-unfold) simp qed lemma wf-rel-while-option-Some: assumes wf : wf R assumes smaller: Vs. P s ∧ b s =⇒ (c s, s) ∈ R assumes inv: Vs. P s ∧ b s =⇒ P(c s) assumes init: P s shows ∃ t. while-option b c s = Some t proof − from smaller have {(t,s). P s ∧ b s ∧ t = c s} ⊆ R by auto with wf have wf {(t,s). P s ∧ b s ∧ t = c s} by (auto simp: wf-subset) with inv init show ?thesis by (auto simp: wf-while-option-Some) qed 77 theorem measure-while-option-Some: fixes f :: 0s ⇒ nat shows (!!s. P s =⇒ b s =⇒ P(c s) ∧ f (c s) < f s) =⇒ P s =⇒ EX t. while-option b c s = Some t by(blast intro: wf-while-option-Some[OF wf-if-measure, of P b f ]) Kleene iteration starting from the empty set and assuming some finite bounding set: lemma while-option-finite-subset-Some: fixes C :: 0a set assumes mono f and !!X . X ⊆ C =⇒ f X ⊆ C and finite C shows ∃ P. while-option (λA. f A 6= A) f {} = Some P proof(rule measure-while-option-Some[where f = %A:: 0a set. card C − card A and P= %A. A ⊆ C ∧ A ⊆ f A and s= {}]) fix A assume A: A ⊆ C ∧ A ⊆ f A f A 6= A show (f A ⊆ C ∧ f A ⊆ f (f A)) ∧ card C − card (f A) < card C − card A (is ?L ∧ ?R) proof show ?L by(metis A(1 ) assms(2 ) monoD[OF hmono f i]) show ?R by (metis A assms(2 ,3 ) card-seteq diff-less-mono2 equalityI linorder-le-less-linear rev-finite-subset) qed qed simp lemma lfp-the-while-option: assumes mono f and !!X . X ⊆ C =⇒ f X ⊆ C and finite C shows lfp f = the(while-option (λA. f A 6= A) f {}) proof− obtain P where while-option (λA. f A 6= A) f {} = Some P using while-option-finite-subset-Some[OF assms] by blast with while-option-stop2 [OF this] lfp-Kleene-iter[OF assms(1 )] show ?thesis by auto qed lemma lfp-while: assumes mono f and !!X . X ⊆ C =⇒ f X ⊆ C and finite C shows lfp f = while (λA. f A 6= A) f {} unfolding while-def using assms by (rule lfp-the-while-option) blast lemma wf-finite-less: assumes finite (C :: 0a::order set) shows wf {(x, y). {x, y} ⊆ C ∧ x < y} by (rule wf-measure[where f =λb. card {a. a ∈ C ∧ a < b}, THEN wf-subset]) (fastforce simp: less-eq assms intro: psubset-card-mono) lemma wf-finite-greater: assumes finite (C :: 0a::order set) shows wf {(x, y). {x, y} ⊆ C ∧ y < x} by (rule wf-measure[where f =λb. card {a. a ∈ C ∧ b < a}, THEN wf-subset]) (fastforce simp: less-eq assms intro: psubset-card-mono) 78 lemma while-option-finite-increasing-Some: fixes f :: 0a::order ⇒ 0a assumes mono f and finite (UNIV :: 0a set) and s ≤ f s shows ∃ P. while-option (λA. f A 6= A) f s = Some P by (rule wf-rel-while-option-Some[where R={(x, y). y < x} and P=λA. A ≤ f A and s=s]) (auto simp: assms monoD intro: wf-finite-greater[where C =UNIV :: 0a set, sim- plified]) lemma lfp-the-while-option-lattice: fixes f :: 0a::complete-lattice ⇒ 0a assumes mono f and finite (UNIV :: 0a set) shows lfp f = the (while-option (λA. f A 6= A) f bot) proof − obtain P where while-option (λA. f A 6= A) f bot = Some P using while-option-finite-increasing-Some[OF assms, where s=bot] by simp blast with while-option-stop2 [OF this] lfp-Kleene-iter[OF assms(1 )] show ?thesis by auto qed lemma lfp-while-lattice: fixes f :: 0a::complete-lattice ⇒ 0a assumes mono f and finite (UNIV :: 0a set) shows lfp f = while (λA. f A 6= A) f bot unfolding while-def using assms by (rule lfp-the-while-option-lattice) lemma while-option-finite-decreasing-Some: fixes f :: 0a::order ⇒ 0a assumes mono f and finite (UNIV :: 0a set) and f s ≤ s shows ∃ P. while-option (λA. f A 6= A) f s = Some P by (rule wf-rel-while-option-Some[where R={(x, y). x < y} and P=λA. f A ≤ A and s=s]) (auto simp add: assms monoD intro: wf-finite-less[where C =UNIV :: 0a set, simplified]) lemma gfp-the-while-option-lattice: fixes f :: 0a::complete-lattice ⇒ 0a assumes mono f and finite (UNIV :: 0a set) shows gfp f = the(while-option (λA. f A 6= A) f top) proof − obtain P where while-option (λA. f A 6= A) f top = Some P using while-option-finite-decreasing-Some[OF assms, where s=top] by simp blast with while-option-stop2 [OF this] gfp-Kleene-iter[OF assms(1 )] show ?thesis by auto qed lemma gfp-while-lattice: 79 fixes f :: 0a::complete-lattice ⇒ 0a assumes mono f and finite (UNIV :: 0a set) shows gfp f = while (λA. f A 6= A) f top unfolding while-def using assms by (rule gfp-the-while-option-lattice) Computing the reflexive, transitive closure by iterating a successor function. Stops when an element is found that dos not satisfy the test. More refined (and hence more efficient) versions can be found in ITP 2011 paper by Nipkow (the theories are in the AFP entry Flyspeck by Nipkow) and the AFP article Executable Transitive Closures by Ren´eThiemann. context fixes p :: 0a ⇒ bool and f :: 0a ⇒ 0a list and x :: 0a begin qualified fun rtrancl-while-test :: 0a list × 0a set ⇒ bool where rtrancl-while-test (ws,-) = (ws 6= [] ∧ p(hd ws)) qualified fun rtrancl-while-step :: 0a list × 0a set ⇒ 0a list × 0a set where rtrancl-while-step (ws, Z ) = (let x = hd ws; new = remdups (filter (λy. y ∈/ Z )(f x)) in (new @ tl ws, set new ∪ Z )) definition rtrancl-while :: ( 0a list ∗ 0a set) option where rtrancl-while = while-option rtrancl-while-test rtrancl-while-step ([x],{x}) qualified fun rtrancl-while-invariant :: 0a list × 0a set ⇒ bool where rtrancl-while-invariant (ws, Z ) = (x ∈ Z ∧ set ws ⊆ Z ∧ distinct ws ∧ {(x,y). y ∈ set(f x)} ‘‘ (Z − set ws) ⊆ Z ∧ Z ⊆ {(x,y). y ∈ set(f x)}ˆ∗ ‘‘ {x} ∧ (∀ z∈Z − set ws. p z)) qualified lemma rtrancl-while-invariant: assumes inv: rtrancl-while-invariant st and test: rtrancl-while-test st shows rtrancl-while-invariant (rtrancl-while-step st) proof (cases st) fix ws Z assume st: st = (ws, Z ) with test obtain h t where ws = h # t p h by (cases ws) auto with inv st show ?thesis by (auto intro: rtrancl.rtrancl-into-rtrancl) qed lemma rtrancl-while-Some: assumes rtrancl-while = Some(ws,Z ) shows if ws = [] then Z = {(x,y). y ∈ set(f x)}ˆ∗ ‘‘ {x} ∧ (∀ z∈Z . p z) else ¬p(hd ws) ∧ hd ws ∈ {(x,y). y ∈ set(f x)}ˆ∗ ‘‘ {x} proof − have rtrancl-while-invariant ([x],{x}) by simp with rtrancl-while-invariant have I : rtrancl-while-invariant (ws,Z ) 80 by (rule while-option-rule[OF - assms[unfolded rtrancl-while-def ]]) { assume ws = [] hence ?thesis using I by (auto simp del:Image-Collect-case-prod dest: Image-closed-trancl) } moreover { assume ws 6= [] hence ?thesis using I while-option-stop[OF assms[unfolded rtrancl-while-def ]] by (simp add: subset-iff ) } ultimately show ?thesis by simp qed lemma rtrancl-while-finite-Some: assumes finite ({(x, y). y ∈ set (f x)}∗ ‘‘ {x})(is finite ?Cl) shows ∃ y. rtrancl-while = Some y proof − let ?R = (λ(-, Z ). card (?Cl − Z )) <∗mlex∗> (λ(ws, -). length ws) <∗mlex∗> {} have wf ?R by (blast intro: wf-mlex) then show ?thesis unfolding rtrancl-while-def proof (rule wf-rel-while-option-Some[of ?R rtrancl-while-invariant]) fix st assume ∗: rtrancl-while-invariant st ∧ rtrancl-while-test st hence I : rtrancl-while-invariant (rtrancl-while-step st) by (blast intro: rtrancl-while-invariant) show (rtrancl-while-step st, st) ∈ ?R proof (cases st) fix ws Z let ?ws = fst (rtrancl-while-step st) and ?Z = snd (rtrancl-while-step st) assume st: st = (ws, Z ) with ∗ obtain h t where ws: ws = h # t p h by (cases ws) auto { assume remdups (filter (λy. y ∈/ Z )(f h)) 6= [] then obtain z where z ∈ set (remdups (filter (λy. y ∈/ Z )(f h))) by fastforce with st ws I have Z ⊂ ?Z Z ⊆ ?Cl ?Z ⊆ ?Cl by auto with assms have card (?Cl − ?Z ) < card (?Cl − Z ) by (blast intro: psubset-card-mono) with st ws have ?thesis unfolding mlex-prod-def by simp } moreover { assume remdups (filter (λy. y ∈/ Z )(f h)) = [] with st ws have ?Z = Z ?ws = t by (auto simp: filter-empty-conv) with st ws have ?thesis unfolding mlex-prod-def by simp } ultimately show ?thesis by blast qed qed (simp-all add: rtrancl-while-invariant) qed end 81 end 14 An application of the While combinator theory While-Combinator-Example imports ∼∼/src/HOL/Library/While-Combinator begin Computation of the lfp on finite sets via iteration. theorem lfp-conv-while: [| mono f ; finite U ; f U = U |] ==> lfp f = fst (while (λ(A, fA). A 6= fA)(λ(A, fA). (fA, f fA)) ({}, f {})) apply (rule-tac P = λ(A, B). (A ⊆ U ∧ B = f A ∧ A ⊆ B ∧ B ⊆ lfp f ) and r = ((Pow U × UNIV ) × (Pow U × UNIV )) ∩ inv-image finite-psubset (op − U o fst) in while-rule) apply (subst lfp-unfold) apply assumption apply (simp add: monoD) apply (subst lfp-unfold) apply assumption apply clarsimp apply (blast dest: monoD) apply (fastforce intro!: lfp-lowerbound) apply (blast intro: wf-finite-psubset Int-lower2 [THEN [2 ] wf-subset]) apply (clarsimp simp add: finite-psubset-def order-less-le) apply (blast dest: monoD) done 14.1 Example Cannot use set-eq-subset because it leads to looping because the antisym- metry simproc turns the subset relationship back into equality. theorem P (lfp (λN ::int set. {0 } ∪ {(n + 2 ) mod 6 | n. n ∈ N })) = P {0 , 4 , 2 } proof − have seteq: !!AB. (A = B) = ((!a : A. a:B) & (!b:B. b:A)) by blast have aux: !!f A B. {f n | n. A n ∨ B n} = {f n | n. A n} ∪ {f n | n. B n} apply blast done show ?thesis apply (subst lfp-conv-while [where ?U = {0 , 1 , 2 , 3 , 4 , 5 }]) apply (rule monoI ) apply blast apply simp apply (simp add: aux set-eq-subset) 82 The fixpoint computation is performed purely by rewriting: apply (simp add: while-unfold aux seteq del: subset-empty) done qed end 15 Monoids and Groups as predicates over record schemes theory MonoidGroup imports Main begin record 0a monoid-sig = times :: 0a => 0a => 0a one :: 0a record 0a group-sig = 0a monoid-sig + inv :: 0a => 0a definition monoid :: (| times :: 0a => 0a => 0a, one :: 0a, ... :: 0b |) => bool where monoid M = (∀ x y z. times M (times M x y) z = times M x (times M y z) ∧ times M (one M ) x = x ∧ times M x (one M ) = x) definition group :: (| times :: 0a => 0a => 0a, one :: 0a, inv :: 0a => 0a, ... :: 0b |) => bool where group G = (monoid G ∧ (∀ x. times G (inv G x) x = one G)) definition reverse :: (| times :: 0a => 0a => 0a, one :: 0a, ... :: 0b |) => (| times :: 0a => 0a => 0a, one :: 0a, ... :: 0b |) where reverse M = M (| times := λx y. times M y x |) end 16 Binary arithmetic examples theory BinEx imports Complex-Main begin 16.1 Regression Testing for Cancellation Simprocs lemma l + 2 + 2 + 2 + (l + 2 ) + (oo + 2 ) = (uu::int) apply simp oops 83 lemma 2 ∗u = (u::int) apply simp oops lemma (i + j + 12 + (k::int)) − 15 = y apply simp oops lemma (i + j + 12 + (k::int)) − 5 = y apply simp oops lemma y − b < (b::int) apply simp oops lemma y − (3 ∗b + c) < (b::int) − 2 ∗c apply simp oops lemma (2 ∗x − (u∗v) + y) − v∗3 ∗u = (w::int) apply simp oops lemma (2 ∗x∗u∗v + (u∗v)∗4 + y) − v∗u∗4 = (w::int) apply simp oops lemma (2 ∗x∗u∗v + (u∗v)∗4 + y) − v∗u = (w::int) apply simp oops lemma u∗v − (x∗u∗v + (u∗v)∗4 + y) = (w::int) apply simp oops lemma (i + j + 12 + (k::int)) = u + 15 + y apply simp oops lemma (i + j ∗2 + 12 + (k::int)) = j + 5 + y apply simp oops lemma 2 ∗y + 3 ∗z + 6 ∗w + 2 ∗y + 3 ∗z + 2 ∗u = 2 ∗y 0 + 3 ∗z 0 + 6 ∗w 0 + 2 ∗y 0 + 3 ∗z 0 + u + (vv::int) apply simp oops lemma a + −(b+c) + b = (d::int) apply simp oops lemma a + −(b+c) − b = (d::int) apply simp oops lemma (i + j + −2 + (k::int)) − (u + 5 + y) = zz apply simp oops lemma (i + j + −3 + (k::int)) < u + 5 + y 84 apply simp oops lemma (i + j + 3 + (k::int)) < u + −6 + y apply simp oops lemma (i + j + −12 + (k::int)) − 15 = y apply simp oops lemma (i + j + 12 + (k::int)) − −15 = y apply simp oops lemma (i + j + −12 + (k::int)) − −15 = y apply simp oops lemma − (2 ∗i) + 3 + (2 ∗i + 4 ) = (0 ::int) apply simp oops lemma (pi ∗ (real u ∗ 2 ) = pi ∗ (real (xa v) ∗ − 2 )) apply simp oops 16.2 Arithmetic Method Tests lemma !!a::int. [| a <= b; c <= d; x+y 85 lemma !!a::int. [| a+b+c+d <= i+j +k+l; a<=b; b<=c; c<=d; i<=j ; j <=k; k<=l |] ==> a+a+a+a <= l+l+l+l by arith lemma !!a::int. [| a+b+c+d <= i+j +k+l; a<=b; b<=c; c<=d; i<=j ; j <=k; k<=l |] ==> a+a+a+a+a <= l+l+l+l+i by arith lemma !!a::int. [| a+b+c+d <= i+j +k+l; a<=b; b<=c; c<=d; i<=j ; j <=k; k<=l |] ==> a+a+a+a+a+a <= l+l+l+l+i+l by arith lemma !!a::int. [| a+b+c+d <= i+j +k+l; a<=b; b<=c; c<=d; i<=j ; j <=k; k<=l |] ==> 6 ∗a <= 5 ∗l+i by arith 16.3 The Integers Addition lemma (13 ::int) + 19 = 32 by simp lemma (1234 ::int) + 5678 = 6912 by simp lemma (1359 ::int) + −2468 = −1109 by simp lemma (93746 ::int) + −46375 = 47371 by simp Negation lemma − (65745 ::int) = −65745 by simp lemma − (−54321 ::int) = 54321 by simp Multiplication lemma (13 ::int) ∗ 19 = 247 by simp 86 lemma (−84 ::int) ∗ 51 = −4284 by simp lemma (255 ::int) ∗ 255 = 65025 by simp lemma (1359 ::int) ∗ −2468 = −3354012 by simp lemma (89 ::int) ∗ 10 6= 889 by simp lemma (13 ::int) < 18 − 4 by simp lemma (−345 ::int) < −242 + −100 by simp lemma (13557456 ::int) < 18678654 by simp lemma (999999 ::int) ≤ (1000001 + 1 ) − 2 by simp lemma (1234567 ::int) ≤ 1234567 by simp No integer overflow! lemma 1234567 ∗ (1234567 ::int) < 1234567 ∗1234567 ∗1234567 by simp Quotient and Remainder lemma (10 ::int) div 3 = 3 by simp lemma (10 ::int) mod 3 = 1 by simp A negative divisor lemma (10 ::int) div −3 = −4 by simp lemma (10 ::int) mod −3 = −2 by simp A negative dividend1 1The definition agrees with mathematical convention and with ML, but not with the hardware of most computers 87 lemma (−10 ::int) div 3 = −4 by simp lemma (−10 ::int) mod 3 = 2 by simp A negative dividend and divisor lemma (−10 ::int) div −3 = 3 by simp lemma (−10 ::int) mod −3 = −1 by simp A few bigger examples lemma (8452 ::int) mod 3 = 1 by simp lemma (59485 ::int) div 434 = 137 by simp lemma (1000006 ::int) mod 10 = 6 by simp Division by shifting lemma 10000000 div 2 = (5000000 ::int) by simp lemma 10000001 mod 2 = (1 ::int) by simp lemma 10000055 div 32 = (312501 ::int) by simp lemma 10000055 mod 32 = (23 ::int) by simp lemma 100094 div 144 = (695 ::int) by simp lemma 100094 mod 144 = (14 ::int) by simp Powers lemma 2 ˆ 10 = (1024 ::int) by simp lemma (− 3 ) ˆ 7 = (−2187 ::int) 88 by simp lemma 13 ˆ 7 = (62748517 ::int) by simp lemma 3 ˆ 15 = (14348907 ::int) by simp lemma (− 5 ) ˆ 11 = (−48828125 ::int) by simp 16.4 The Natural Numbers Successor lemma Suc 99999 = 100000 by simp Addition lemma (13 ::nat) + 19 = 32 by simp lemma (1234 ::nat) + 5678 = 6912 by simp lemma (973646 ::nat) + 6475 = 980121 by simp Subtraction lemma (32 ::nat) − 14 = 18 by simp lemma (14 ::nat) − 15 = 0 by simp lemma (14 ::nat) − 1576644 = 0 by simp lemma (48273776 ::nat) − 3873737 = 44400039 by simp Multiplication lemma (12 ::nat) ∗ 11 = 132 by simp lemma (647 ::nat) ∗ 3643 = 2357021 by simp 89 Quotient and Remainder lemma (10 ::nat) div 3 = 3 by simp lemma (10 ::nat) mod 3 = 1 by simp lemma (10000 ::nat) div 9 = 1111 by simp lemma (10000 ::nat) mod 9 = 1 by simp lemma (10000 ::nat) div 16 = 625 by simp lemma (10000 ::nat) mod 16 = 0 by simp Powers lemma 2 ˆ 12 = (4096 ::nat) by simp lemma 3 ˆ 10 = (59049 ::nat) by simp lemma 12 ˆ 7 = (35831808 ::nat) by simp lemma 3 ˆ 14 = (4782969 ::nat) by simp lemma 5 ˆ 11 = (48828125 ::nat) by simp Testing the cancellation of complementary terms lemma y + (x + −x) = (0 ::int) + y by simp lemma y + (−x + (− y + x)) = (0 ::int) by simp lemma −x + (y + (− y + x)) = (0 ::int) by simp lemma x + (x + (− x + (− x + (− y + − z)))) = (0 ::int) − y − z by simp 90 lemma x + x − x − x − y − z = (0 ::int) − y − z by simp lemma x + y + z − (x + z) = y − (0 ::int) by simp lemma x + (y + (y + (y + (−x + −x)))) = (0 ::int) + y − x + y + y by simp lemma x + (y + (y + (y + (−y + −x)))) = y + (0 ::int) + y by simp lemma x + y − x + z − x − y − z + x < (1 ::int) by simp 16.5 Real Arithmetic 16.5.1 Addition lemma (1359 ::real) + −2468 = −1109 by simp lemma (93746 ::real) + −46375 = 47371 by simp 16.5.2 Negation lemma − (65745 ::real) = −65745 by simp lemma − (−54321 ::real) = 54321 by simp 16.5.3 Multiplication lemma (−84 ::real) ∗ 51 = −4284 by simp lemma (255 ::real) ∗ 255 = 65025 by simp lemma (1359 ::real) ∗ −2468 = −3354012 by simp 16.5.4 Inequalities lemma (89 ::real) ∗ 10 6= 889 by simp lemma (13 ::real) < 18 − 4 91 by simp lemma (−345 ::real) < −242 + −100 by simp lemma (13557456 ::real) < 18678654 by simp lemma (999999 ::real) ≤ (1000001 + 1 ) − 2 by simp lemma (1234567 ::real) ≤ 1234567 by simp 16.5.5 Powers lemma 2 ˆ 15 = (32768 ::real) by simp lemma (− 3 ) ˆ 7 = (−2187 ::real) by simp lemma 13 ˆ 7 = (62748517 ::real) by simp lemma 3 ˆ 15 = (14348907 ::real) by simp lemma (− 5 ) ˆ 11 = (−48828125 ::real) by simp 16.5.6 Tests lemma (x + y = x) = (y = (0 ::real)) by arith lemma (x + y = y) = (x = (0 ::real)) by arith lemma (x + y = (0 ::real)) = (x = −y) by arith lemma (x + y = (0 ::real)) = (y = −x) by arith lemma ((x + y) < (x + z)) = (y < (z::real)) by arith lemma ((x + z) < (y + z)) = (x < (y::real)) by arith 92 lemma (¬ x < y) = (y ≤ (x::real)) by arith lemma ¬ (x < y ∧ y < (x::real)) by arith lemma (x::real) < y ==> ¬ y < x by arith lemma ((x::real) 6= y) = (x < y ∨ y < x) by arith lemma (¬ x ≤ y) = (y < (x::real)) by arith lemma x ≤ y ∨ y ≤ (x::real) by arith lemma x ≤ y ∨ y < (x::real) by arith lemma x < y ∨ y ≤ (x::real) by arith lemma x ≤ (x::real) by arith lemma ((x::real) ≤ y) = (x < y ∨ x = y) by arith lemma ((x::real) ≤ y ∧ y ≤ x) = (x = y) by arith lemma ¬(x < y ∧ y ≤ (x::real)) by arith lemma ¬(x ≤ y ∧ y < (x::real)) by arith lemma (−x < (0 ::real)) = (0 < x) by arith lemma ((0 ::real) < −x) = (x < 0 ) by arith lemma (−x ≤ (0 ::real)) = (0 ≤ x) by arith 93 lemma ((0 ::real) ≤ −x) = (x ≤ 0 ) by arith lemma (x::real) = y ∨ x < y ∨ y < x by arith lemma (x::real) = 0 ∨ 0 < x ∨ 0 < −x by arith lemma (0 ::real) ≤ x ∨ 0 ≤ −x by arith lemma ((x::real) + y ≤ x + z) = (y ≤ z) by arith lemma ((x::real) + z ≤ y + z) = (x ≤ y) by arith lemma (w::real) < x ∧ y < z ==> w + y < x + z by arith lemma (w::real) ≤ x ∧ y ≤ z ==> w + y ≤ x + z by arith lemma (0 ::real) ≤ x ∧ 0 ≤ y ==> 0 ≤ x + y by arith lemma (0 ::real) < x ∧ 0 < y ==> 0 < x + y by arith lemma (−x < y) = (0 < x + (y::real)) by arith lemma (x < −y) = (x + y < (0 ::real)) by arith lemma (y < x + −z) = (y + z < (x::real)) by arith lemma (x + −y < z) = (x < z + (y::real)) by arith lemma x ≤ y ==> x < y + (1 ::real) by arith lemma (x − y) + y = (x::real) by arith lemma y + (x − y) = (x::real) 94 by arith lemma x − x = (0 ::real) by arith lemma (x − y = 0 ) = (x = (y::real)) by arith lemma ((0 ::real) ≤ x + x) = (0 ≤ x) by arith lemma (−x ≤ x) = ((0 ::real) ≤ x) by arith lemma (x ≤ −x) = (x ≤ (0 ::real)) by arith lemma (−x = (0 ::real)) = (x = 0 ) by arith lemma −(x − y) = y − (x::real) by arith lemma ((0 ::real) < x − y) = (y < x) by arith lemma ((0 ::real) ≤ x − y) = (y ≤ x) by arith lemma (x + y) − x = (y::real) by arith lemma (−x = y) = (x = (−y::real)) by arith lemma x < (y::real) ==> ¬(x = y) by arith lemma (x ≤ x + y) = ((0 ::real) ≤ y) by arith lemma (y ≤ x + y) = ((0 ::real) ≤ x) by arith lemma (x < x + y) = ((0 ::real) < y) by arith lemma (y < x + y) = ((0 ::real) < x) by arith 95 lemma (x − y) − x = (−y::real) by arith lemma (x + y < z) = (x < z − (y::real)) by arith lemma (x − y < z) = (x < z + (y::real)) by arith lemma (x < y − z) = (x + z < (y::real)) by arith lemma (x ≤ y − z) = (x + z ≤ (y::real)) by arith lemma (x − y ≤ z) = (x ≤ z + (y::real)) by arith lemma (−x < −y) = (y < (x::real)) by arith lemma (−x ≤ −y) = (y ≤ (x::real)) by arith lemma (a + b) − (c + d) = (a − c) + (b − (d::real)) by arith lemma (0 ::real) − x = −x by arith lemma x − (0 ::real) = x by arith lemma w ≤ x ∧ y < z ==> w + y < x + (z::real) by arith lemma w < x ∧ y ≤ z ==> w + y < x + (z::real) by arith lemma (0 ::real) ≤ x ∧ 0 < y ==> 0 < x + (y::real) by arith lemma (0 ::real) < x ∧ 0 ≤ y ==> 0 < x + y by arith lemma −x − y = −(x + (y::real)) by arith 96 lemma x − (−y) = x + (y::real) by arith lemma −x − −y = y − (x::real) by arith lemma (a − b) + (b − c) = a − (c::real) by arith lemma (x = y − z) = (x + z = (y::real)) by arith lemma (x − y = z) = (x = z + (y::real)) by arith lemma x − (x − y) = (y::real) by arith lemma x − (x + y) = −(y::real) by arith lemma x = y ==> x ≤ (y::real) by arith lemma (0 ::real) < x ==> ¬(x = 0 ) by arith lemma (x + y) ∗ (x − y) = (x ∗ x) − (y ∗ y) oops lemma (−x = −y) = (x = (y::real)) by arith lemma (−x < −y) = (y < (x::real)) by arith lemma !!a::real. a ≤ b ==> c ≤ d ==> x + y < z ==> a + c ≤ b + d by linarith lemma !!a::real. a < b ==> c < d ==> a − d ≤ b + (−c) by linarith lemma !!a::real. a ≤ b ==> b + b ≤ c ==> a + a ≤ c by linarith lemma !!a::real. a + b ≤ i + j ==> a ≤ b ==> i ≤ j ==> a + a ≤ j + j by linarith lemma !!a::real. a + b < i + j ==> a < b ==> i < j ==> a + a < j + j 97 by linarith lemma !!a::real. a + b + c ≤ i + j + k ∧ a ≤ b ∧ b ≤ c ∧ i ≤ j ∧ j ≤ k −−> a + a + a ≤ k + k + k by arith lemma !!a::real. a + b + c + d ≤ i + j + k + l ==> a ≤ b ==> b ≤ c ==> c ≤ d ==> i ≤ j ==> j ≤ k ==> k ≤ l ==> a ≤ l by linarith lemma !!a::real. a + b + c + d ≤ i + j + k + l ==> a ≤ b ==> b ≤ c ==> c ≤ d ==> i ≤ j ==> j ≤ k ==> k ≤ l ==> a + a + a + a ≤ l + l + l + l by linarith lemma !!a::real. a + b + c + d ≤ i + j + k + l ==> a ≤ b ==> b ≤ c ==> c ≤ d ==> i ≤ j ==> j ≤ k ==> k ≤ l ==> a + a + a + a + a ≤ l + l + l + l + i by linarith lemma !!a::real. a + b + c + d ≤ i + j + k + l ==> a ≤ b ==> b ≤ c ==> c ≤ d ==> i ≤ j ==> j ≤ k ==> k ≤ l ==> a + a + a + a + a + a ≤ l + l + l + l + i + l by linarith 16.6 Complex Arithmetic lemma (1359 + 93746 ∗i) − (2468 + 46375 ∗i) = −1109 + 47371 ∗i by simp lemma − (65745 + −47371 ∗i) = −65745 + 47371 ∗i by simp Multiplication requires distributive laws. Perhaps versions instantiated to literal constants should be added to the simpset. lemma (1 + i) ∗ (1 − i) = 2 by (simp add: ring-distribs) lemma (1 + 2 ∗i) ∗ (1 + 3 ∗i) = −5 + 5 ∗i by (simp add: ring-distribs) lemma (−84 + 255 ∗i) + (51 ∗ 255 ∗i) = −84 + 13260 ∗ i by (simp add: ring-distribs) No inequalities or linear arithmetic: the complex numbers are unordered! No powers (not supported yet) end 98 17 Examples for hexadecimal and binary numerals theory Hex-Bin-Examples imports Main begin Hex and bin numerals can be used like normal decimal numerals in input lemma 0xFF = 255 by (rule refl) lemma 0xF = 0b1111 by (rule refl) Just like decimal numeral they are polymorphic, for arithmetic they need to be constrained lemma 0x0A + 0x10 = (0x1A :: nat) by simp The number of leading zeros is irrelevant lemma 0b00010000 = 0x10 by (rule refl) Unary minus works as for decimal numerals lemma − 0x0A = − 10 by (rule refl) Hex and bin numerals are printed as decimal: 2 :: 0a term 0b10 term 0x0A The numerals 0 and 1 are syntactically different from the constants 0 and 1. For the usual numeric types, their values are the same, though. lemma 0x01 = 1 oops lemma 0x00 = 0 oops lemma 0x01 = (1 ::nat) by simp lemma 0b0000 = (0 ::int) by simp end 18 Antiquotations theory Antiquote imports Main begin A simple example on quote / antiquote in higher-order abstract syntax. definition var :: 0a ⇒ ( 0a ⇒ nat) ⇒ nat (VAR - [1000 ] 999 ) where var x env = env x definition Expr :: (( 0a ⇒ nat) ⇒ nat) ⇒ ( 0a ⇒ nat) ⇒ nat where Expr exp env = exp env 99 syntax -Expr :: 0a ⇒ 0a (EXPR - [1000 ] 999 ) parse-translation h[Syntax-Trans.quote-antiquote-tr @{syntax-const -Expr} @{const-syntax var} @{const-syntax Expr}]i print-translation 0 h[Syntax-Trans.quote-antiquote-tr @{syntax-const -Expr} @{const-syntax var} @{const-syntax Expr}]i term EXPR (a + b + c) term EXPR (a + b + c + VAR x + VAR y + 1 ) term EXPR (VAR (f w) + VAR x) term Expr (λenv. env x) — improper term Expr (λenv. f env) term Expr (λenv. f env + env x) — improper term Expr (λenv. f env y z) term Expr (λenv. f env + g y env) term Expr (λenv. f env + g env y + h a env z) end 19 Multiple nested quotations and anti-quotations theory Multiquote imports Main begin Multiple nested quotations and anti-quotations – basically a generalized version of de-Bruijn representation. syntax 0 0 0 -quote :: b ⇒ ( a ⇒ b)(- [0 ] 1000 ) -antiquote :: ( 0a ⇒ 0b) ⇒ 0b (´- [1000 ] 1000 ) parse-translation h let fun antiquote-tr i (Const (@{syntax-const -antiquote}, -) $ (t as Const (@{syntax-const -antiquote}, -) $ -)) = skip-antiquote-tr i t | antiquote-tr i (Const (@{syntax-const -antiquote}, -) $ t) = antiquote-tr i t $ Bound i | antiquote-tr i (t $ u) = antiquote-tr i t $ antiquote-tr i u | antiquote-tr i (Abs (x, T , t)) = Abs (x, T , antiquote-tr (i + 1 ) t) | antiquote-tr - a = a and skip-antiquote-tr i ((c as Const (@{syntax-const -antiquote}, -)) $ t) = c $ skip-antiquote-tr i t | skip-antiquote-tr i t = antiquote-tr i t; 100 fun quote-tr [t] = Abs (s, dummyT , antiquote-tr 0 (Term.incr-boundvars 1 t)) | quote-tr ts = raise TERM (quote-tr, ts); in [(@{syntax-const -quote}, K quote-tr)] end i basic examples term a + b + c term a + b + c + ´x + ´y + 1 term ´(f w) + ´x term f ´x ´y z advanced examples term ´´x + ´y term ´´x + ´y ◦ ´f term ´(f ◦ ´g) term ´´(f ◦ ´g) end 20 Partial equivalence relations theory PER imports Main begin Higher-order quotients are defined over partial equivalence relations (PERs) instead of total ones. We provide axiomatic type classes equiv < partial-equiv and a type constructor 0a quot with basic operations. This development is based on: Oscar Slotosch: Higher Order Quotients and their Implementation in Isabelle HOL. Elsa L. Gunter and Amy Felty, editors, Theorem Proving in Higher Order Logics: TPHOLs ’97, Springer LNCS 1275, 1997. 20.1 Partial equivalence Type class partial-equiv models partial equivalence relations (PERs) using the polymorphic ∼ :: 0a ⇒ 0a ⇒ bool relation, which is required to be symmetric and transitive, but not necessarily reflexive. class partial-equiv = fixes eqv :: 0a ⇒ 0a ⇒ bool (infixl ∼ 50 ) assumes partial-equiv-sym [elim?]: x ∼ y =⇒ y ∼ x assumes partial-equiv-trans [trans]: x ∼ y =⇒ y ∼ z =⇒ x ∼ z The domain of a partial equivalence relation is the set of reflexive elements. Due to symmetry and transitivity this characterizes exactly those elements that are connected with any other one. 101 definition domain :: 0a::partial-equiv set where domain = {x. x ∼ x} lemma domainI [intro]: x ∼ x =⇒ x ∈ domain unfolding domain-def by blast lemma domainD [dest]: x ∈ domain =⇒ x ∼ x unfolding domain-def by blast theorem domainI 0 [elim?]: x ∼ y =⇒ x ∈ domain proof assume xy: x ∼ y also from xy have y ∼ x .. finally show x ∼ x . qed 20.2 Equivalence on function spaces The ∼ relation is lifted to function spaces. It is important to note that this is not the direct product, but a structural one corresponding to the congruence property. instantiation fun :: (partial-equiv, partial-equiv) partial-equiv begin definition f ∼ g ←→ (∀ x ∈ domain. ∀ y ∈ domain. x ∼ y −→ f x ∼ g y) lemma partial-equiv-funI [intro?]: (Vx y. x ∈ domain =⇒ y ∈ domain =⇒ x ∼ y =⇒ f x ∼ g y) =⇒ f ∼ g unfolding eqv-fun-def by blast lemma partial-equiv-funD [dest?]: f ∼ g =⇒ x ∈ domain =⇒ y ∈ domain =⇒ x ∼ y =⇒ f x ∼ g y unfolding eqv-fun-def by blast The class of partial equivalence relations is closed under function spaces (in both argument positions). instance proof fix f g h :: 0a::partial-equiv ⇒ 0b::partial-equiv assume fg: f ∼ g show g ∼ f proof fix x y :: 0a assume x: x ∈ domain and y: y ∈ domain assume x ∼ y then have y ∼ x .. with fg y x have f y ∼ g x .. then show g x ∼ f y .. qed 102 assume gh: g ∼ h show f ∼ h proof fix x y :: 0a assume x: x ∈ domain and y: y ∈ domain and x ∼ y with fg have f x ∼ g y .. also from y have y ∼ y .. with gh y y have g y ∼ h y .. finally show f x ∼ h y . qed qed end 20.3 Total equivalence The class of total equivalence relations on top of PERs. It coincides with the standard notion of equivalence, i.e. ∼ :: 0a ⇒ 0a ⇒ bool is required to be reflexive, transitive and symmetric. class equiv = assumes eqv-refl [intro]: x ∼ x On total equivalences all elements are reflexive, and congruence holds un- conditionally. theorem equiv-domain [intro]: (x:: 0a::equiv) ∈ domain proof show x ∼ x .. qed theorem equiv-cong [dest?]: f ∼ g =⇒ x ∼ y =⇒ f x ∼ g (y:: 0a::equiv) proof − assume f ∼ g moreover have x ∈ domain .. moreover have y ∈ domain .. moreover assume x ∼ y ultimately show ?thesis .. qed 20.4 Quotient types The quotient type 0a quot consists of all equivalence classes over elements of the base type 0a. definition quot = {{x. a ∼ x}| a:: 0a::partial-equiv. True} typedef (overloaded) 0a quot = quot :: 0a::partial-equiv set set unfolding quot-def by blast 103 lemma quotI [intro]: {x. a ∼ x} ∈ quot unfolding quot-def by blast lemma quotE [elim]: R ∈ quot =⇒ (Va. R = {x. a ∼ x} =⇒ C ) =⇒ C unfolding quot-def by blast Abstracted equivalence classes are the canonical representation of elements of a quotient type. definition eqv-class :: ( 0a::partial-equiv) ⇒ 0a quot (b-c) where bac = Abs-quot {x. a ∼ x} theorem quot-rep: ∃ a. A = bac proof (cases A) fix R assume R: A = Abs-quot R assume R ∈ quot then have ∃ a. R = {x. a ∼ x} by blast with R have ∃ a. A = Abs-quot {x. a ∼ x} by blast then show ?thesis by (unfold eqv-class-def ) qed lemma quot-cases [cases type: quot]: obtains (rep) a where A = bac using quot-rep by blast 20.5 Equality on quotients Equality of canonical quotient elements corresponds to the original relation as follows. theorem eqv-class-eqI [intro]: a ∼ b =⇒ bac = bbc proof − assume ab: a ∼ b have {x. a ∼ x} = {x. b ∼ x} proof (rule Collect-cong) fix x show a ∼ x ←→ b ∼ x proof from ab have b ∼ a .. also assume a ∼ x finally show b ∼ x . next note ab also assume b ∼ x finally show a ∼ x . qed qed then show ?thesis by (simp only: eqv-class-def ) qed theorem eqv-class-eqD 0 [dest?]: bac = bbc =⇒ a ∈ domain =⇒ a ∼ b proof (unfold eqv-class-def ) 104 assume Abs-quot {x. a ∼ x} = Abs-quot {x. b ∼ x} then have {x. a ∼ x} = {x. b ∼ x} by (simp only: Abs-quot-inject quotI ) moreover assume a ∈ domain then have a ∼ a .. ultimately have a ∈ {x. b ∼ x} by blast then have b ∼ a by blast then show a ∼ b .. qed theorem eqv-class-eqD [dest?]: bac = bbc =⇒ a ∼ (b:: 0a::equiv) proof (rule eqv-class-eqD 0) show a ∈ domain .. qed lemma eqv-class-eq 0 [simp]: a ∈ domain =⇒ bac = bbc ←→ a ∼ b using eqv-class-eqI eqv-class-eqD 0 by (blast del: eqv-refl) lemma eqv-class-eq [simp]: bac = bbc ←→ a ∼ (b:: 0a::equiv) using eqv-class-eqI eqv-class-eqD by blast 20.6 Picking representing elements definition pick :: 0a::partial-equiv quot ⇒ 0a where pick A = (SOME a. A = bac) theorem pick-eqv 0 [intro?, simp]: a ∈ domain =⇒ pick bac ∼ a proof (unfold pick-def ) assume a: a ∈ domain show (SOME x. bac = bxc) ∼ a proof (rule someI2 ) show bac = bac .. fix x assume bac = bxc from this and a have a ∼ x .. then show x ∼ a .. qed qed theorem pick-eqv [intro, simp]: pick bac ∼ (a:: 0a::equiv) proof (rule pick-eqv 0) show a ∈ domain .. qed theorem pick-inverse: bpick Ac = (A:: 0a::equiv quot) proof (cases A) fix a assume a: A = bac then have pick A ∼ a by simp then have bpick Ac = bac by simp with a show ?thesis by simp qed 105 end 21 Summing natural numbers theory NatSum imports Main begin Summing natural numbers, squares, cubes, etc. Thanks to Sloane’s On-Line Encyclopedia of Integer Sequences, http:// www.research.att.com/∼njas/sequences. lemmas [simp] = ring-distribs diff-mult-distrib diff-mult-distrib2 — for type nat The sum of the first n odd numbers equals n squared. lemma sum-of-odds:(P i=0 .. The sum of the first n odd squares. lemma sum-of-odd-squares: 3 ∗ (P i=0 .. The sum of the first n odd cubes lemma sum-of-odd-cubes: (P i=0 .. The sum of the first n positive integers equals n (n + 1 ) / 2. lemma sum-of-naturals: 2 ∗ (P i=0 ..n. i) = n ∗ Suc n by (induct n) auto lemma sum-of-squares: 6 ∗ (P i=0 ..n. i ∗ i) = n ∗ Suc n ∗ Suc (2 ∗ n) by (induct n) auto lemma sum-of-cubes: 4 ∗ (P i=0 ..n. i ∗ i ∗ i) = n ∗ n ∗ Suc n ∗ Suc n by (induct n) auto A cute identity: lemma sum-squared:(P i=0 ..n. i)ˆ2 = (P i=0 ..n::nat. iˆ3 ) proof(induct n) 106 case 0 show ?case by simp next case (Suc n) have (P i = 0 ..Suc n. i)ˆ2 = (P i = 0 ..n. iˆ3 ) + (2 ∗(P i = 0 ..n. i)∗(n+1 ) + (n+1 )ˆ2 ) (is - = ?A + ?B) using Suc by(simp add:eval-nat-numeral) also have ?B = (n+1 )ˆ3 using sum-of-naturals by(simp add:eval-nat-numeral) also have ?A + (n+1 )ˆ3 = (P i=0 ..Suc n. iˆ3 ) by simp finally show ?case . qed Sum of fourth powers: three versions. lemma sum-of-fourth-powers: 30 ∗ (P i=0 ..n. i ∗ i ∗ i ∗ i) = n ∗ Suc n ∗ Suc (2 ∗ n) ∗ (3 ∗ n ∗ n + 3 ∗ n − 1 ) apply (induct n) apply simp-all apply (case-tac n) — eliminates the subtraction apply (simp-all (no-asm-simp)) done Two alternative proofs, with a change of variables and much more subtrac- tion, performed using the integers. lemma int-sum-of-fourth-powers: 30 ∗ int (P i=0 .. Sums of geometric series: 2, 3 and the general case. lemma sum-of-2-powers:(P i=0 .. 107 22 Three Divides Theorem theory ThreeDivides imports Main ∼∼/src/HOL/Library/LaTeXsugar begin 22.1 Abstract The following document presents a proof of the Three Divides N theorem formalised in the Isabelle/Isar theorem proving system. Theorem: 3 divides n if and only if 3 divides the sum of all digits in n. P j Informal Proof: Take n = nj ∗ 10 where nj is the j’th least significant digit of the decimal denotation of the number n and the sum ranges over all digits. Then X X j (n − nj) = nj ∗ (10 − 1) We know ∀j 3|(10j − 1) and hence 3|LHS, therefore X ∀n 3|n ⇐⇒ 3| nj 2 22.2 Formal proof 22.2.1 Miscellaneous summation lemmas If a divides A x for all x then a divides any sum over terms of the form (A x)∗(P x) for arbitrary P . lemma div-sum: fixes a::nat and n::nat shows ∀ x. a dvd A x =⇒ a dvd (P x 108 22.2.2 Generalised Three Divides This section solves a generalised form of the three divides problem. Here we show that for any sequence of numbers the theorem holds. In the next section we specialise this theorem to apply directly to the decimal expansion of the natural numbers. Here we show that the first statement in the informal proof is true for all natural numbers. Note we are using D i to denote the i’th element in a sequence of numbers. lemma digit-diff-split: fixes n::nat and nd::nat and x::nat shows n = (P x∈{.. 109 qed We now present the final theorem of this section. For any sequence of numbers (defined by a function D), we show that 3 divides the expansive sum P (D x) ∗ 10x over x if and only if 3 divides the sum of the individual numbers P D x. lemma three-div-general: fixes D :: nat ⇒ nat shows (3 dvd (P x This lets us form the term (P x 22.2.3 Three Divides Natural This section shows that for all natural numbers we can generate a sequence of digits less than ten that represent the decimal expansion of the number. We then use the lemma three-div-general to prove our final theorem. Definitions of length and digit sum. This section introduces some functions to calculate the required properties of natural numbers. We then proceed to prove some properties of these functions. The function nlen returns the number of digits in a natural number n. fun nlen :: nat ⇒ nat where nlen 0 = 0 | nlen x = 1 + nlen (x div 10 ) The function sumdig returns the sum of all digits in some number n. definition 110 sumdig :: nat ⇒ nat where sumdig n = (P x < nlen n. n div 10ˆx mod 10 ) Some properties of these functions follow. lemma nlen-zero: 0 = nlen x =⇒ x = 0 by (induct x rule: nlen.induct) auto lemma nlen-suc: Suc m = nlen n =⇒ m = nlen (n div 10 ) by (induct n rule: nlen.induct) simp-all The following lemma is the principle lemma required to prove our theorem. It states that an expansion of some natural number n into a sequence of its individual digits is always possible. lemma exp-exists: m = (P x 111 Final theorem. We now combine the general theorem three-div-general and existence result of exp-exists to prove our final theorem. theorem three-divides-nat: shows (3 dvd n) = (3 dvd sumdig n) proof (unfold sumdig-def ) have n = (P x 23 The Cubic and Quartic Root Formulas theory Cubic-Quartic imports Complex-Main begin 24 The Cubic Formula definition ccbrt z = (SOME (w::complex). wˆ3 = z) lemma ccbrt:(ccbrt z) ˆ 3 = z proof − from rcis-Ex obtain r a where ra: z = rcis r a by blast let ?r 0 = if r < 0 then − root 3 (−r) else root 3 r let ?a 0 = a/3 have rcis ?r 0 ?a 0 ˆ 3 = rcis r a by (cases r < 0 )(simp-all add: DeMoivre2 ) then have ∗: ∃ w. wˆ3 = z unfolding ra by blast from someI-ex [OF ∗] show ?thesis unfolding ccbrt-def by blast qed The reduction to a simpler form: lemma cubic-reduction: fixes a :: complex assumes a 6= 0 ∧ x = y − b / (3 ∗ a) ∧ p = (3 ∗ a ∗ c − bˆ2 ) / (9 ∗ aˆ2 ) ∧ 112 q = (9 ∗ a ∗ b ∗ c − 2 ∗ bˆ3 − 27 ∗ aˆ2 ∗ d) / (54 ∗ aˆ3 ) shows a ∗ xˆ3 + b ∗ xˆ2 + c ∗ x + d = 0 ←→ yˆ3 + 3 ∗ p ∗ y − 2 ∗ q = 0 proof − from assms have 3 ∗ a 6= 0 9 ∗ aˆ2 6= 0 54 ∗ aˆ3 6= 0 by auto then have ∗: x = y − b / (3 ∗ a) ←→ (3 ∗a) ∗ x = (3 ∗a) ∗ y − b p = (3 ∗ a ∗ c − bˆ2 ) / (9 ∗ aˆ2 ) ←→ (9 ∗ aˆ2 ) ∗ p = (3 ∗ a ∗ c − bˆ2 ) q = (9 ∗ a ∗ b ∗ c − 2 ∗ bˆ3 − 27 ∗ aˆ2 ∗ d) / (54 ∗ aˆ3 ) ←→ (54 ∗ aˆ3 ) ∗ q = (9 ∗ a ∗ b ∗ c − 2 ∗ bˆ3 − 27 ∗ aˆ2 ∗ d) by (simp-all add: field-simps) from assms [unfolded ∗] show ?thesis by algebra qed The solutions of the special form: lemma cubic-basic: fixes s :: complex assumes sˆ2 = qˆ2 + pˆ3 ∧ s1ˆ3 = (if p = 0 then 2 ∗ q else q + s) ∧ s2 = −s1 ∗ (1 + i ∗ t) / 2 ∧ s3 = −s1 ∗ (1 − i ∗ t) / 2 ∧ iˆ2 + 1 = 0 ∧ tˆ2 = 3 shows if p = 0 then yˆ3 + 3 ∗ p ∗ y − 2 ∗ q = 0 ←→ y = s1 ∨ y = s2 ∨ y = s3 else s1 6= 0 ∧ (yˆ3 + 3 ∗ p ∗ y − 2 ∗ q = 0 ←→ (y = s1 − p / s1 ∨ y = s2 − p / s2 ∨ y = s3 − p / s3 )) proof (cases p = 0 ) case True with assms show ?thesis by (simp add: field-simps) algebra next case False with assms have ∗: s1 6= 0 by (simp add: field-simps) algebra with assms False have s2 6= 0 s3 6= 0 by (simp-all add: field-simps) algebra+ with ∗ have ∗∗: y = s1 − p / s1 ←→ s1 ∗ y = s1ˆ2 − p y = s2 − p / s2 ←→ s2 ∗ y = s2ˆ2 − p y = s3 − p / s3 ←→ s3 ∗ y = s3ˆ2 − p by (simp-all add: field-simps power2-eq-square) from assms False show ?thesis unfolding ∗∗ by (simp add: field-simps) algebra qed Explicit formula for the roots: 113 lemma cubic: assumes a0 : a 6= 0 shows let p = (3 ∗ a ∗ c − bˆ2 ) / (9 ∗ aˆ2 ); q = (9 ∗ a ∗ b ∗ c − 2 ∗ bˆ3 − 27 ∗ aˆ2 ∗ d) / (54 ∗ aˆ3 ); s = csqrt(qˆ2 + pˆ3 ); s1 = (if p = 0 then ccbrt(2 ∗ q) else ccbrt(q + s)); s2 = −s1 ∗ (1 + i ∗ csqrt 3 ) / 2 ; s3 = −s1 ∗ (1 − i ∗ csqrt 3 ) / 2 in if p = 0 then a ∗ xˆ3 + b ∗ xˆ2 + c ∗ x + d = 0 ←→ x = s1 − b / (3 ∗ a) ∨ x = s2 − b / (3 ∗ a) ∨ x = s3 − b / (3 ∗ a) else s1 6= 0 ∧ (a ∗ xˆ3 + b ∗ xˆ2 + c ∗ x + d = 0 ←→ x = s1 − p / s1 − b / (3 ∗ a) ∨ x = s2 − p / s2 − b / (3 ∗ a) ∨ x = s3 − p / s3 − b / (3 ∗ a)) proof − let ?p = (3 ∗ a ∗ c − bˆ2 ) / (9 ∗ aˆ2 ) let ?q = (9 ∗ a ∗ b ∗ c − 2 ∗ bˆ3 − 27 ∗ aˆ2 ∗ d) / (54 ∗ aˆ3 ) let ?s = csqrt (?qˆ2 + ?pˆ3 ) let ?s1 = if ?p = 0 then ccbrt(2 ∗ ?q) else ccbrt(?q + ?s) let ?s2 = − ?s1 ∗ (1 + i ∗ csqrt 3 ) / 2 let ?s3 = − ?s1 ∗ (1 − i ∗ csqrt 3 ) / 2 let ?y = x + b / (3 ∗ a) from a0 have zero: 9 ∗ aˆ2 6= 0 aˆ3 ∗ 54 6= 0 (a ∗ 3 ) 6= 0 by auto have eq: a ∗ xˆ3 + b ∗ xˆ2 + c ∗ x + d = 0 ←→ ?yˆ3 + 3 ∗ ?p ∗ ?y − 2 ∗ ?q = 0 by (rule cubic-reduction)(auto simp add: field-simps zero a0 ) have csqrt 3ˆ2 = 3 by (rule power2-csqrt) then have th0 : ?sˆ2 = ?qˆ2 + ?p ˆ 3 ∧ ?s1ˆ 3 = (if ?p = 0 then 2 ∗ ?q else ?q + ?s) ∧ ?s2 = − ?s1 ∗ (1 + i ∗ csqrt 3 ) / 2 ∧ ?s3 = − ?s1 ∗ (1 − i ∗ csqrt 3 ) / 2 ∧ iˆ2 + 1 = 0 ∧ csqrt 3ˆ2 = 3 using zero by (simp add: field-simps ccbrt) from cubic-basic[OF th0 , of ?y] show ?thesis apply (simp only: Let-def eq) using zero apply (simp add: field-simps ccbrt) using zero apply (cases a ∗ (c ∗ 3 ) = bˆ2 ) apply (simp-all add: field-simps) 114 done qed 25 The Quartic Formula lemma quartic: (y::real)ˆ3 − b ∗ yˆ2 + (a ∗ c − 4 ∗ d) ∗ y − aˆ2 ∗ d + 4 ∗ b ∗ d − cˆ2 = 0 ∧ Rˆ2 = aˆ2 / 4 − b + y ∧ sˆ2 = yˆ2 − 4 ∗ d ∧ (Dˆ2 = (if R = 0 then 3 ∗ aˆ2 / 4 − 2 ∗ b + 2 ∗ s else 3 ∗ aˆ2 / 4 − Rˆ2 − 2 ∗ b + (4 ∗ a ∗ b − 8 ∗ c − aˆ3 ) / (4 ∗ R))) ∧ (Eˆ2 = (if R = 0 then 3 ∗ aˆ2 / 4 − 2 ∗ b − 2 ∗ s else 3 ∗ aˆ2 / 4 − Rˆ2 − 2 ∗ b − (4 ∗ a ∗ b − 8 ∗ c − aˆ3 ) / (4 ∗ R))) =⇒ xˆ4 + a ∗ xˆ3 + b ∗ xˆ2 + c ∗ x + d = 0 ←→ x = −a / 4 + R / 2 + D / 2 ∨ x = −a / 4 + R / 2 − D / 2 ∨ x = −a / 4 − R / 2 + E / 2 ∨ x = −a / 4 − R / 2 − E / 2 apply (cases R = 0 ) apply (simp-all add: field-simps divide-minus-left[symmetric] del: divide-minus-left) apply algebra apply algebra done end 26 The Pythagorean Theorem theory Pythagoras imports Complex-Main begin Expressed in real numbers: lemma pythagoras-verbose: ((A1 ::real) − B1 ) ∗ (C1 − B1 ) + (A2 − B2 ) ∗ (C2 − B2 ) = 0 =⇒ (C1 − A1 ) ∗ (C1 − A1 ) + (C2 − A2 ) ∗ (C2 − A2 ) = ((B1 − A1 ) ∗ (B1 − A1 ) + (B2 − A2 ) ∗ (B2 − A2 )) + (C1 − B1 ) ∗ (C1 − B1 ) + (C2 − B2 ) ∗ (C2 − B2 ) by algebra Expressed in vectors: type-synonym point = real × real lemma pythagoras: defines ort:orthogonal ≡ (λ(A::point) B. fst A ∗ fst B + snd A ∗ snd B = 0 ) 115 and vc:vector ≡ (λ(A::point) B. (fst A − fst B, snd A − snd B)) and vcn:vecsqnorm ≡ (λA::point. fst A ˆ 2 + snd A ˆ2 ) assumes o: orthogonal (vector A B)(vector C B) shows vecsqnorm(vector C A) = vecsqnorm(vector B A) + vecsqnorm(vector C B) using o unfolding ort vc vcn by (algebra add: fst-conv snd-conv) end 27 Higher-Order Logic: Intuitionistic predicate cal- culus problems theory Intuitionistic imports Main begin lemma (∼∼(P&Q)) = ((∼∼P)&(∼∼Q)) by iprover lemma ∼∼ ((∼P −−> Q) −−> (∼P −−> ∼Q) −−> P) by iprover lemma (∼∼(P−−>Q)) = (∼∼P −−> ∼∼Q) by iprover lemma (∼∼∼P) = (∼P) by iprover lemma ∼∼((P −−> Q | R) −−> (P−−>Q) | (P−−>R)) by iprover lemma (P=Q) = (Q=P) by iprover lemma ((P −−> (Q | (Q−−>R))) −−> R) −−> R by iprover lemma (((G−−>A) −−> J ) −−> D −−> E) −−> (((H −−>B)−−>I )−−>C −−>J ) −−> (A−−>H ) −−> F −−> G −−> (((C −−>B)−−>I )−−>D)−−>(A−−>C ) −−> (((F −−>A)−−>B) −−> I ) −−> E by iprover 116 lemma P −−> ∼∼P by iprover lemma ∼∼(∼∼P −−> P) by iprover lemma ∼∼P & ∼∼(P −−> Q) −−> ∼∼Q by iprover lemma ((P=Q) −−> P&Q&R)& ((Q=R) −−> P&Q&R)& ((R=P) −−> P&Q&R) −−> P&Q&R by iprover lemma ((P=Q) −−> P&Q&R&S&T )& ((Q=R) −−> P&Q&R&S&T )& ((R=S) −−> P&Q&R&S&T )& ((S=T ) −−> P&Q&R&S&T )& ((T =P) −−> P&Q&R&S&T ) −−> P&Q&R&S&T by iprover lemma (ALL x. EX y. ALL z. p(x)& q(y)& r(z)) = (ALL z. EX y. ALL x. p(x)& q(y)& r(z)) by (iprover del: allE elim 2 : allE 0) lemma ∼ (EX x. ALL y. p y x = (∼ p x x)) by iprover lemma ∼∼((P−−>Q) = (∼Q −−> ∼P)) by iprover lemma ∼∼(∼∼P = P) by iprover 117 lemma ∼(P−−>Q) −−> (Q−−>P) by iprover lemma ∼∼((∼P−−>Q) = (∼Q −−> P)) by iprover lemma ∼∼((P|Q−−>P|R) −−> P|(Q−−>R)) by iprover lemma ∼∼(P | ∼P) by iprover lemma ∼∼(P | ∼∼∼P) by iprover lemma ∼∼(((P−−>Q) −−> P) −−> P) by iprover lemma ((P|Q)&(∼P|Q)&(P| ∼Q)) −−> ∼ (∼P | ∼Q) by iprover lemma (Q−−>R) −−> (R−−>P&Q) −−> (P−−>(Q|R)) −−> (P=Q) by iprover lemma P=P by iprover lemma ∼∼(((P = Q) = R) = (P = (Q = R))) by iprover lemma ((P = Q) = R) −−> ∼∼(P = (Q = R)) by iprover lemma (P | (Q & R)) = ((P | Q)&(P | R)) by iprover lemma ∼∼((P = Q) = ((Q | ∼P)&(∼Q|P))) 118 by iprover lemma ∼∼((P −−> Q) = (∼P | Q)) by iprover lemma ∼∼((P−−>Q) | (Q−−>P)) by iprover lemma ∼∼(((P &(Q−−>R))−−>S) = ((∼P | Q | S)&(∼P | ∼R | S))) oops lemma (P&Q) = (P = (Q = (P|Q))) by iprover lemma (EX x. P(x)−−>Q) −−> (ALL x. P(x)) −−> Q by iprover lemma ((ALL x. P(x))−−>Q) −−> ∼ (ALL x. P(x)& ∼Q) by iprover lemma ((ALL x. ∼P(x))−−>Q) −−> ∼ (ALL x. ∼ (P(x)|Q)) by iprover lemma (ALL x. P(x)) | Q −−> (ALL x. P(x) | Q) by iprover lemma (EX x. P −−> Q(x)) −−> (P −−> (EX x. Q(x))) by iprover lemma ∼∼(EX x. ALL y z. (P(y)−−>Q(z)) −−> (P(x)−−>Q(x))) by iprover lemma (ALL x y. EX z. ALL w. (P(x)&Q(y)−−>R(z)&S(w))) 119 −−> (EX x y. P(x)& Q(y)) −−> (EX z. R(z)) by iprover lemma (EX x. P−−>Q(x)) & (EX x. Q(x)−−>P) −−> ∼∼(EX x. P=Q(x)) by iprover lemma (ALL x. P = Q(x)) −−> (P = (ALL x. Q(x))) by iprover lemma ∼∼ ((ALL x. P | Q(x)) = (P | (ALL x. Q(x)))) by iprover lemma (EX x. P(x)) & (ALL x. L(x) −−> ∼ (M (x)& R(x))) & (ALL x. P(x) −−> (M (x)& L(x))) & ((ALL x. P(x)−−>Q(x)) | (EX x. P(x)&R(x))) −−> (EX x. Q(x)&P(x)) by iprover lemma (EX x. P(x)& ∼Q(x)) & (ALL x. P(x) −−> R(x)) & (ALL x. M (x)& L(x) −−> P(x)) & ((EX x. R(x)& ∼ Q(x)) −−> (ALL x. L(x) −−> ∼ R(x))) −−> (ALL x. M (x) −−> ∼L(x)) by iprover lemma (ALL x. P(x) −−> (ALL x. Q(x))) & (∼∼(ALL x. Q(x)|R(x)) −−> (EX x. Q(x)&S(x))) & (∼∼(EX x. S(x)) −−> (ALL x. L(x) −−> M (x))) −−> (ALL x. P(x)& L(x) −−> M (x)) by iprover lemma (((EX x. P(x)) & (EX y. Q(y))) −−> (((ALL x. (P(x) −−> R(x))) & (ALL y. (Q(y) −−> S(y)))) = (ALL x y. ((P(x)& Q(y)) −−> (R(x)& S(y)))))) by iprover lemma (ALL x. (P(x) | Q(x)) −−> ∼ R(x)) & (ALL x. (Q(x) −−> ∼ S(x)) −−> P(x)& R(x)) −−> (ALL x. ∼∼S(x)) by iprover 120 lemma ∼(EX x. P(x)&(Q(x) | R(x))) & (EX x. L(x)& P(x)) & (ALL x. ∼ R(x) −−> M (x)) −−> (EX x. L(x)& M (x)) by iprover lemma (ALL x. P(x)&(Q(x)|R(x))−−>S(x)) & (ALL x. S(x)& R(x) −−> L(x)) & (ALL x. M (x) −−> R(x)) −−> (ALL x. P(x)& M (x) −−> L(x)) by iprover lemma (ALL x. ∼∼(P(a)&(P(x)−−>P(b))−−>P(c))) = (ALL x. ∼∼((∼P(a) | P(x) | P(c)) & (∼P(a) | ∼P(b) | P(c)))) oops lemma (ALL x. EX y. J x y)& (ALL x. EX y. G x y)& (ALL x y. J x y | G x y −−> (ALL z. J y z | G y z −−> H x z)) −−> (ALL x. EX y. H x y) by iprover lemma ∼ (EX x. ALL y. F y x = (∼F y y)) by iprover lemma (EX y. ALL x. F x y = F x x) −−> ∼(ALL x. EX y. ALL z. F z y = (∼ F z x)) by iprover lemma (ALL x. f (x) −−> (EX y. g(y)& h x y &(EX y. g(y)& ∼ h x y))) & (EX x. j (x)&(ALL y. g(y) −−> h x y)) −−> (EX x. j (x)& ∼f (x)) by iprover lemma (a=b | c=d)&(a=c | b=d) −−> a=d | b=c by iprover 121 lemma ((EX z w. (ALL x y. (P x y = ((x = z)&(y = w))))) −−> (EX z. (ALL x. (EX w. ((ALL y. (P x y = (y = w))) = (x = z)))))) by iprover lemma ((EX z w. (ALL x y. (P x y = ((x = z)&(y = w))))) −−> (EX w. (ALL y. (EX z. ((ALL x. (P x y = (x = z))) = (y = w)))))) by iprover lemma (ALL x. (EX y. P(y)& x=f (y)) −−> P(x)) = (ALL x. P(x) −−> P(f (x))) by iprover lemma P (f a b)(f b c)& P (f b c)(f a c)& (ALL x y z. P x y & P y z −−> P x z) −−> P (f a b)(f a c) by iprover lemma ALL x. P x (f x) = (EX y. (ALL z. P z y −−> P z (f x)) & P x y) by iprover end 28 CTL formulae theory CTL imports Main begin We formalize basic concepts of Computational Tree Logic (CTL) [2,1] within the simply-typed set theory of HOL. By using the common technique of “shallow embedding”, a CTL formula is identified with the corresponding set of states where it holds. Consequently, CTL operations such as negation, conjunction, disjunction simply become complement, intersection, union of sets. We only require a separate oper- ation for implication, as point-wise inclusion is usually not encountered in plain set-theory. lemmas [intro!] = Int-greatest Un-upper2 Un-upper1 Int-lower1 Int-lower2 type-synonym 0a ctl = 0a set definition imp :: 0a ctl ⇒ 0a ctl ⇒ 0a ctl (infixr → 75 ) where p → q = − p ∪ q lemma [intro!]: p ∩ p → q ⊆ q unfolding imp-def by auto 122 lemma [intro!]: p ⊆ (q → p) unfolding imp-def by rule The CTL path operators are more interesting; they are based on an arbitrary, but fixed model M, which is simply a transition relation over states 0a. axiomatization M :: ( 0a × 0a) set The operators EX, EF, EG are taken as primitives, while AX, AF, AG are defined as derived ones. The formula EX p holds in a state s, iff there is a successor state s 0 (with respect to the model M), such that p holds in s 0. The formula EF p holds in a state s, iff there is a path in M, starting from s, such that there exists a state s 0 on the path, such that p holds in s 0. The formula EG p holds in a state s, iff there is a path, starting from s, such that for all states s 0 on the path, p holds in s 0. It is easy to see that EF p and EG p may be expressed using least and greatest fixed points [2]. definition EX (EX - [80 ] 90 ) where [simp]: EX p = {s. ∃ s 0. (s, s 0) ∈ M ∧ s 0 ∈ p} definition EF (EF - [80 ] 90 ) where [simp]: EF p = lfp (λs. p ∪ EX s) definition EG (EG - [80 ] 90 ) where [simp]: EG p = gfp (λs. p ∩ EX s) AX, AF and AG are now defined dually in terms of EX, EF and EG. definition AX (AX - [80 ] 90 ) where [simp]: AX p = − EX − p definition AF (AF - [80 ] 90 ) where [simp]: AF p = − EG − p definition AG (AG - [80 ] 90 ) where [simp]: AG p = − EF − p 28.1 Basic fixed point properties First of all, we use the de-Morgan property of fixed points. lemma lfp-gfp: lfp f = − gfp (λs:: 0a set. − (f (− s))) proof show lfp f ⊆ − gfp (λs. − f (− s)) proof show x ∈ − gfp (λs. − f (− s)) if l: x ∈ lfp f for x proof assume x ∈ gfp (λs. − f (− s)) then obtain u where x ∈ u and u ⊆ − f (− u) by (auto simp add: gfp-def ) then have f (− u) ⊆ − u by auto then have lfp f ⊆ − u by (rule lfp-lowerbound) from l and this have x ∈/ u by auto with hx ∈ u i show False by contradiction 123 qed qed show − gfp (λs. − f (− s)) ⊆ lfp f proof (rule lfp-greatest) fix u assume f u ⊆ u then have − u ⊆ − f u by auto then have − u ⊆ − f (− (− u)) by simp then have − u ⊆ gfp (λs. − f (− s)) by (rule gfp-upperbound) then show − gfp (λs. − f (− s)) ⊆ u by auto qed qed lemma lfp-gfp 0: − lfp f = gfp (λs:: 0a set. − (f (− s))) by (simp add: lfp-gfp) lemma gfp-lfp 0: − gfp f = lfp (λs:: 0a set. − (f (− s))) by (simp add: lfp-gfp) In order to give dual fixed point representations of AF p and AG p: lemma AF-lfp: AF p = lfp (λs. p ∪ AX s) by (simp add: lfp-gfp) lemma AG-gfp: AG p = gfp (λs. p ∩ AX s) by (simp add: lfp-gfp) lemma EF-fp: EF p = p ∪ EX EF p proof − have mono (λs. p ∪ EX s) by rule auto then show ?thesis by (simp only: EF-def )(rule lfp-unfold) qed lemma AF-fp: AF p = p ∪ AX AF p proof − have mono (λs. p ∪ AX s) by rule auto then show ?thesis by (simp only: AF-lfp)(rule lfp-unfold) qed lemma EG-fp: EG p = p ∩ EX EG p proof − have mono (λs. p ∩ EX s) by rule auto then show ?thesis by (simp only: EG-def )(rule gfp-unfold) qed From the greatest fixed point definition of AG p, we derive as a consequence of the Knaster-Tarski theorem on the one hand that AG p is a fixed point of the monotonic function λs. p ∩ AX s. lemma AG-fp: AG p = p ∩ AX AG p proof − 124 have mono (λs. p ∩ AX s) by rule auto then show ?thesis by (simp only: AG-gfp)(rule gfp-unfold) qed This fact may be split up into two inequalities (merely using transitivity of ⊆, which is an instance of the overloaded ≤ in Isabelle/HOL). lemma AG-fp-1 : AG p ⊆ p proof − note AG-fp also have p ∩ AX AG p ⊆ p by auto finally show ?thesis . qed lemma AG-fp-2 : AG p ⊆ AX AG p proof − note AG-fp also have p ∩ AX AG p ⊆ AX AG p by auto finally show ?thesis . qed On the other hand, we have from the Knaster-Tarski fixed point theorem that any other post-fixed point of λs. p ∩ AX s is smaller than AG p.A post-fixed point is a set of states q such that q ⊆ p ∩ AX q. This leads to the following co-induction principle for AG p. lemma AG-I : q ⊆ p ∩ AX q =⇒ q ⊆ AG p by (simp only: AG-gfp)(rule gfp-upperbound) 28.2 The tree induction principle With the most basic facts available, we are now able to establish a few more interesting results, leading to the tree induction principle for AG (see below). We will use some elementary monotonicity and distributivity rules. lemma AX-int: AX (p ∩ q) = AX p ∩ AX q by auto lemma AX-mono: p ⊆ q =⇒ AX p ⊆ AX q by auto lemma AG-mono: p ⊆ q =⇒ AG p ⊆ AG q by (simp only: AG-gfp, rule gfp-mono) auto The formula AG p implies AX p (we use substitution of ⊆ with mono- tonicity). lemma AG-AX : AG p ⊆ AX p proof − have AG p ⊆ AX AG p by (rule AG-fp-2 ) also have AG p ⊆ p by (rule AG-fp-1 ) moreover note AX-mono finally show ?thesis . qed Furthermore we show idempotency of the AG operator. The proof is a good example of how accumulated facts may get used to feed a single rule step. 125 lemma AG-AG: AG AG p = AG p proof show AG AG p ⊆ AG p by (rule AG-fp-1 ) next show AG p ⊆ AG AG p proof (rule AG-I ) have AG p ⊆ AG p .. moreover have AG p ⊆ AX AG p by (rule AG-fp-2 ) ultimately show AG p ⊆ AG p ∩ AX AG p .. qed qed We now give an alternative characterization of the AG operator, which describes the AG operator in an “operational” way by tree induction: In a state holds AG p iff in that state holds p, and in all reachable states s follows from the fact that p holds in s, that p also holds in all successor states of s. We use the co-induction principle AG-I to establish this in a purely algebraic manner. theorem AG-induct: p ∩ AG (p → AX p) = AG p proof show p ∩ AG (p → AX p) ⊆ AG p (is ?lhs ⊆ -) proof (rule AG-I ) show ?lhs ⊆ p ∩ AX ?lhs proof show ?lhs ⊆ p .. show ?lhs ⊆ AX ?lhs proof − { have AG (p → AX p) ⊆ p → AX p by (rule AG-fp-1 ) also have p ∩ p → AX p ⊆ AX p .. finally have ?lhs ⊆ AX p by auto } moreover { have p ∩ AG (p → AX p) ⊆ AG (p → AX p) .. also have ... ⊆ AX ... by (rule AG-fp-2 ) finally have ?lhs ⊆ AX AG (p → AX p) . } ultimately have ?lhs ⊆ AX p ∩ AX AG (p → AX p) .. also have ... = AX ?lhs by (simp only: AX-int) finally show ?thesis . qed qed qed next show AG p ⊆ p ∩ AG (p → AX p) proof show AG p ⊆ p by (rule AG-fp-1 ) 126 show AG p ⊆ AG (p → AX p) proof − have AG p = AG AG p by (simp only: AG-AG) also have AG p ⊆ AX p by (rule AG-AX ) moreover note AG-mono also have AX p ⊆ (p → AX p) .. moreover note AG-mono finally show ?thesis . qed qed qed 28.3 An application of tree induction Further interesting properties of CTL expressions may be demonstrated with the help of tree induction; here we show that AX and AG commute. theorem AG-AX-commute: AG AX p = AX AG p proof − have AG AX p = AX p ∩ AX AG AX p by (rule AG-fp) also have ... = AX (p ∩ AG AX p) by (simp only: AX-int) also have p ∩ AG AX p = AG p (is ?lhs = -) proof have AX p ⊆ p → AX p .. also have p ∩ AG (p → AX p) = AG p by (rule AG-induct) also note Int-mono AG-mono ultimately show ?lhs ⊆ AG p by fast next have AG p ⊆ p by (rule AG-fp-1 ) moreover { have AG p = AG AG p by (simp only: AG-AG) also have AG p ⊆ AX p by (rule AG-AX ) also note AG-mono ultimately have AG p ⊆ AG AX p . } ultimately show AG p ⊆ ?lhs .. qed finally show ?thesis . qed end 29 Arithmetic theory Arith-Examples imports Main begin The arith method is used frequently throughout the Isabelle distribution. This file merely contains some additional tests and special corner cases. 127 Some rather technical remarks: Lin_Arith.simple_tac is a very basic version of the tactic. It performs no meta-to-object-logic conversion, and only some splitting of operators. Lin_Arith.tac performs meta-to-object-logic conversion, full splitting of operators, and NNF normalization of the goal. The arith method combines them both, and tries other methods (e.g. presburger) as well. This is the one that you should use in your proofs! An arith-based simproc is available as well (see Lin_Arith.simproc), which— for performance reasons—however does even less splitting than Lin_Arith.simple_tac at the moment (namely inequalities only). (On the other hand, it does take apart conjunctions, which Lin_Arith.simple_tac currently does not do.) 29.1 Splitting of Operators: max, min, abs, op −, nat, op mod, op div lemma (i::nat) <= max i j by linarith lemma (i::int) <= max i j by linarith lemma min i j <= (i::nat) by linarith lemma min i j <= (i::int) by linarith lemma min (i::nat) j <= max i j by linarith lemma min (i::int) j <= max i j by linarith lemma min (i::nat) j + max i j = i + j by linarith lemma min (i::int) j + max i j = i + j by linarith lemma (i::nat) < j ==> min i j < max i j by linarith lemma (i::int) < j ==> min i j < max i j by linarith lemma (0 ::int) <= |i| by linarith 128 lemma (i::int) <= |i| by linarith lemma ||i::int|| = |i| by linarith Also testing subgoals with bound variables. lemma !!x. (x::nat) <= y ==> x − y = 0 by linarith lemma !!x. (x::nat) − y = 0 ==> x <= y by linarith lemma !!x. ((x::nat) <= y) = (x − y = 0 ) by linarith lemma [| (x::nat) < y; d < 1 |] ==> x − y = d by linarith lemma [| (x::nat) < y; d < 1 |] ==> x − y − x = d − x by linarith lemma (x::int) < y ==> x − y < 0 by linarith lemma nat (i + j ) <= nat i + nat j by linarith lemma i < j ==> nat (i − j ) = 0 by linarith lemma (i::nat) mod 0 = i using split-mod [of - - 0 , arith-split] by linarith lemma (i::nat) mod 1 = 0 using split-mod [of - - 1 , arith-split] by linarith lemma (i::nat) mod 42 <= 41 by linarith lemma (i::int) mod 0 = i using split-zmod [of - - 0 , arith-split] by linarith 129 lemma (i::int) mod 1 = 0 using split-zmod [of - - 1 , arith-split] by linarith lemma (i::int) mod 42 <= 41 by linarith lemma −(i::int) ∗ 1 = 0 ==> i = 0 by linarith lemma [| (0 ::int) < |i|; |i| ∗ 1 < |i| ∗ j |] ==> 1 < |i| ∗ j by linarith 29.2 Meta-Logic lemma x < Suc y == x <= y by linarith lemma ((x::nat) == z ==> x ∼= y) ==> x ∼= y | z ∼= y by linarith 29.3 Various Other Examples lemma (x < Suc y) = (x <= y) by linarith lemma [| (x::nat) < y; y < z |] ==> x < z by linarith lemma (x::nat) < y & y < z ==> x < z by linarith This example involves no arithmetic at all, but is solved by preprocessing (i.e. NNF normalization) alone. lemma (P::bool) = Q ==> Q = P by linarith lemma [| P = (x = 0 ); (∼P) = (y = 0 ) |] ==> min (x::nat) y = 0 by linarith lemma [| P = (x = 0 ); (∼P) = (y = 0 ) |] ==> max (x::nat) y = x + y by linarith lemma [| (x::nat) ∼= y; a + 2 = b; a < y; y < b; a < x; x < b |] ==> False by linarith lemma [| (x::nat) > y; y > z; z > x |] ==> False 130 by linarith lemma (x::nat) − 5 > y ==> y < x by linarith lemma (x::nat) ∼= 0 ==> 0 < x by linarith lemma [| (x::nat) ∼= y; x <= y |] ==> x < y by linarith lemma [| (x::nat) < y; P (x − y) |] ==> P 0 by linarith lemma (x − y) − (x::nat) = (x − x) − y by linarith lemma [| (a::nat) < b; c < d |] ==> (a − b) = (c − d) by linarith lemma ((a::nat) − (b − (c − (d − e)))) = (a − (b − (c − (d − e)))) by linarith lemma (n < m & m < n 0) | (n < m & m = n 0) | (n < n 0 & n 0 < m) | (n = n 0 & n 0 < m) | (n = m & m < n 0) | (n 0 < m & m < n) | (n 0 < m & m = n) | (n 0 < n & n < m) | (n 0 = n & n < m) | (n 0 = m & m < n) | (m < n & n < n 0) | (m < n & n 0 = n) | (m < n 0 & n 0 < n) | (m = n & n < n 0) | (m = n 0 & n 0 < n) | (n 0 = m & m = (n::nat)) oops lemma 2 ∗ (x::nat) ∼= 1 oops Constants. lemma (0 ::nat) < 1 by linarith lemma (0 ::int) < 1 by linarith 131 lemma (47 ::nat) + 11 < 8 ∗ 15 by linarith lemma (47 ::int) + 11 < 8 ∗ 15 by linarith Splitting of inequalities of different type. lemma [| (a::nat) ∼= b;(i::int) ∼= j ; a < 2 ; b < 2 |] ==> a + b <= nat (max |i| |j |) by linarith Again, but different order. lemma [| (i::int) ∼= j ;(a::nat) ∼= b; a < 2 ; b < 2 |] ==> a + b <= nat (max |i| |j |) by linarith end 30 2-3 Trees theory Tree23 imports Main begin This is a very direct translation of some of the functions in table.ML in the Isabelle source code. That source is due to Makarius Wenzel and Stefan Berghofer. So far this file contains only data types and functions, but no proofs. Feel free to have a go at the latter! Note that because of complicated patterns and mutual recursion, these func- tion definitions take a few minutes and can also be seen as stress tests for the function definition facility. type-synonym key = int — for simplicity, should be a type class datatype ord = LESS | EQUAL | GREATER definition ord i j = (if i 132 fun add :: key ⇒ 0a ⇒ 0a tree23 ⇒ 0a growth where add key y Empty = Sprout Empty (key,y) Empty | add key y (Branch2 left (k,x) right) = (case ord key k of LESS => (case add key y left of Stay left 0 => Stay (Branch2 left 0 (k,x) right) | Sprout left1 q left2 => Stay (Branch3 left1 q left2 (k,x) right)) | EQUAL => Stay (Branch2 left (k,y) right) | GREATER => (case add key y right of Stay right 0 => Stay (Branch2 left (k,x) right 0) | Sprout right1 q right2 => Stay (Branch3 left (k,x) right1 q right2 ))) | add key y (Branch3 left (k1 ,x1 ) mid (k2 ,x2 ) right) = (case ord key k1 of LESS => (case add key y left of Stay left 0 => Stay (Branch3 left 0 (k1 ,x1 ) mid (k2 ,x2 ) right) | Sprout left1 q left2 => Sprout (Branch2 left1 q left2 )(k1 ,x1 )(Branch2 mid (k2 ,x2 ) right)) | EQUAL => Stay (Branch3 left (k1 ,y) mid (k2 ,x2 ) right) | GREATER => (case ord key k2 of LESS => (case add key y mid of Stay mid 0 => Stay (Branch3 left (k1 ,x1 ) mid 0 (k2 ,x2 ) right) | Sprout mid1 q mid2 => Sprout (Branch2 left (k1 ,x1 ) mid1 ) q (Branch2 mid2 (k2 ,x2 ) right)) | EQUAL => Stay (Branch3 left (k1 ,x1 ) mid (k2 ,y) right) | GREATER => (case add key y right of Stay right 0 => Stay (Branch3 left (k1 ,x1 ) mid (k2 ,x2 ) right 0) | Sprout right1 q right2 => Sprout (Branch2 left (k1 ,x1 ) mid)(k2 ,x2 )(Branch2 right1 q right2 )))) definition add0 :: key ⇒ 0a ⇒ 0a tree23 ⇒ 0a tree23 where add0 k y t = (case add k y t of Stay t 0 => t 0 | Sprout l p r => Branch2 l p r) value add0 5 e (add0 4 d (add0 3 c (add0 2 b (add0 1 a Empty)))) fun compare where compare None (k2 , -) = LESS | compare (Some k1 )(k2 , -) = ord k1 k2 133 fun if-eq where if-eq EQUAL x y = x | if-eq - x y = y fun del :: key option ⇒ 0a tree23 ⇒ ((key ∗ 0a) ∗ bool ∗ 0a tree23 )option where del (Some k) Empty = None | del None (Branch2 Empty p Empty) = Some(p, (True, Empty)) | del None (Branch3 Empty p Empty q Empty) = Some(p, (False, Branch2 Empty q Empty)) | del k (Branch2 Empty p Empty) = (case compare k p of EQUAL => Some(p, (True, Empty)) | - => None) | del k (Branch3 Empty p Empty q Empty) = (case compare k p of EQUAL => Some(p, (False, Branch2 Empty q Empty)) | - => (case compare k q of EQUAL => Some(q, (False, Branch2 Empty p Empty)) | - => None)) | del k (Branch2 l p r) = (case compare k p of LESS => (case del k l of None ⇒ None | Some(p 0, (False, l 0)) => Some(p 0, (False, Branch2 l 0 p r)) | Some(p 0, (True, l 0)) => Some(p 0, case r of Branch2 rl rp rr => (True, Branch3 l 0 p rl rp rr) | Branch3 rl rp rm rq rr => (False, Branch2 (Branch2 l 0 p rl) rp (Branch2 rm rq rr)))) | or => (case del (if-eq or None k) r of None ⇒ None | Some(p 0, (False, r 0)) => Some(p 0, (False, Branch2 l (if-eq or p 0 p) r 0)) | Some(p 0, (True, r 0)) => Some(p 0, case l of Branch2 ll lp lr => (True, Branch3 ll lp lr (if-eq or p 0 p) r 0) | Branch3 ll lp lm lq lr => (False, Branch2 (Branch2 ll lp lm) lq (Branch2 lr (if-eq or p 0 p) r 0))))) | del k (Branch3 l p m q r) = (case compare k q of LESS => (case compare k p of LESS => (case del k l of None ⇒ None | Some(p 0, (False, l 0)) => Some(p 0, (False, Branch3 l 0 p m q r)) | Some(p 0, (True, l 0)) => Some(p 0, (False, case (m, r) of (Branch2 ml mp mr, Branch2 - - -) => Branch2 (Branch3 l 0 p ml mp mr) q r | (Branch3 ml mp mm mq mr, -) => Branch3 (Branch2 l 0 p ml) mp (Branch2 mm mq mr) q r | (Branch2 ml mp mr, Branch3 rl rp rm rq rr) => Branch3 (Branch2 l 0 p ml) mp (Branch2 mr q rl) rp (Branch2 rm rq rr)))) | or => (case del (if-eq or None k) m of None ⇒ None | Some(p 0, (False, m 0)) => Some(p 0, (False, Branch3 l (if-eq or p 0 p) m 0 q r)) | Some(p 0, (True, m 0)) => Some(p 0, (False, case (l, r) of (Branch2 ll lp lr, Branch2 - - -) => Branch2 (Branch3 ll lp lr (if-eq or p 0 p) m 0) q r 134 | (Branch3 ll lp lm lq lr, -) => Branch3 (Branch2 ll lp lm) lq (Branch2 lr (if-eq or p 0 p) m 0) q r | (-, Branch3 rl rp rm rq rr) => Branch3 l (if-eq or p 0 p)(Branch2 m 0 q rl) rp (Branch2 rm rq rr))))) | or => (case del (if-eq or None k) r of None ⇒ None | Some(q 0, (False, r 0)) => Some(q 0, (False, Branch3 l p m (if-eq or q 0 q) r 0)) | Some(q 0, (True, r 0)) => Some(q 0, (False, case (l, m) of (Branch2 - - -, Branch2 ml mp mr) => Branch2 l p (Branch3 ml mp mr (if-eq or q 0 q) r 0) | (-, Branch3 ml mp mm mq mr) => Branch3 l p (Branch2 ml mp mm) mq (Branch2 mr (if-eq or q 0 q) r 0) | (Branch3 ll lp lm lq lr, Branch2 ml mp mr) => Branch3 (Branch2 ll lp lm) lq (Branch2 lr p ml) mp (Branch2 mr (if-eq or q 0 q) r 0))))) definition del0 :: key ⇒ 0a tree23 ⇒ 0a tree23 where del0 k t = (case del (Some k) t of None ⇒ t | Some(-,(-,t 0)) ⇒ t 0) Ordered trees definition opt-less :: key option ⇒ key option ⇒ bool where opt-less x y = (case x of None ⇒ True | Some a ⇒ (case y of None ⇒ True | Some b ⇒ a < b)) lemma opt-less-simps [simp]: opt-less None y = True opt-less x None = True opt-less (Some a)(Some b) = (a < b) unfolding opt-less-def by (auto simp add: ord-def split: option.split) primrec ord 0 :: key option ⇒ 0a tree23 ⇒ key option ⇒ bool where ord 0 x Empty y = opt-less x y | ord 0 x (Branch2 l p r) y = (ord 0 x l (Some (fst p)) & ord 0 (Some (fst p)) r y) | ord 0 x (Branch3 l p m q r) y = (ord 0 x l (Some (fst p)) & ord 0 (Some (fst p)) m (Some (fst q)) & ord 0 (Some (fst q)) r y) definition ord0 :: 0a tree23 ⇒ bool where ord0 t = ord 0 None t None Balanced trees inductive full :: nat ⇒ 0a tree23 ⇒ bool where full 0 Empty | [[full n l; full n r]] =⇒ full (Suc n)(Branch2 l p r) | [[full n l; full n m; full n r]] =⇒ full (Suc n)(Branch3 l p m q r) inductive-cases full-elims: full n Empty full n (Branch2 l p r) full n (Branch3 l p m q r) 135 inductive-cases full-0-elim: full 0 t inductive-cases full-Suc-elim: full (Suc n) t lemma full-0-iff [simp]: full 0 t ←→ t = Empty by (auto elim: full-0-elim intro: full.intros) lemma full-Empty-iff [simp]: full n Empty ←→ n = 0 by (auto elim: full-elims intro: full.intros) lemma full-Suc-Branch2-iff [simp]: full (Suc n)(Branch2 l p r) ←→ full n l ∧ full n r by (auto elim: full-elims intro: full.intros) lemma full-Suc-Branch3-iff [simp]: full (Suc n)(Branch3 l p m q r) ←→ full n l ∧ full n m ∧ full n r by (auto elim: full-elims intro: full.intros) fun height :: 0a tree23 ⇒ nat where height Empty = 0 | height (Branch2 l - r) = Suc(max (height l)(height r)) | height (Branch3 l - m - r) = Suc(max (height l)(max (height m)(height r))) Is a tree balanced? fun bal :: 0a tree23 ⇒ bool where bal Empty = True | bal (Branch2 l - r) = (bal l & bal r & height l = height r) | bal (Branch3 l - m - r) = (bal l & bal m & bal r & height l = height m & height m = height r) lemma full-imp-height: full n t =⇒ height t = n by (induct set: full, simp-all) lemma full-imp-bal: full n t =⇒ bal t by (induct set: full, auto dest: full-imp-height) lemma bal-imp-full: bal t =⇒ full (height t) t by (induct t, simp-all) lemma bal-iff-full: bal t ←→ (∃ n. full n t) by (auto elim!: bal-imp-full full-imp-bal) The add0 function either preserves the height of the tree, or increases it by one. The constructor returned by the add function determines which: A return value of the form Stay t indicates that the height will be the same. A value of the form Sprout l p r indicates an increase in height. primrec gfull :: nat ⇒ 0a growth ⇒ bool where gfull n (Stay t) ←→ full n t | gfull n (Sprout l p r) ←→ full n l ∧ full n r 136 lemma gfull-add: full n t =⇒ gfull n (add k y t) by (induct set: full, auto split: ord.split growth.split) The add0 operation preserves balance. lemma bal-add0 : bal t =⇒ bal (add0 k y t) unfolding bal-iff-full add0-def apply (erule exE) apply (drule gfull-add [of - - k y]) apply (cases add k y t) apply (auto intro: full.intros) done The add0 operation preserves order. lemma ord-cases: fixes a b :: int obtains ord a b = LESS and a < b | ord a b = EQUAL and a = b | ord a b = GREATER and a > b unfolding ord-def by (rule linorder-cases [of a b]) auto definition gtree :: 0a growth ⇒ 0a tree23 where gtree g = (case g of Stay t ⇒ t | Sprout l p r ⇒ Branch2 l p r) lemma gtree-simps [simp]: gtree (Stay t) = t gtree (Sprout l p r) = Branch2 l p r unfolding gtree-def by simp-all lemma add0 : add0 k y t = gtree (add k y t) unfolding add0-def by (simp split: growth.split) lemma ord 0-add0 : [[ord 0 k1 t k2 ; opt-less k1 (Some k); opt-less (Some k) k2 ]] =⇒ ord 0 k1 (add0 k y t) k2 unfolding add0 apply (induct t arbitrary: k1 k2 ) apply simp apply clarsimp apply (rule-tac a=k and b=a in ord-cases) apply simp apply (case-tac add k y t1 , simp, simp) apply simp apply simp apply (case-tac add k y t2 , simp, simp) apply clarsimp apply (rule-tac a=k and b=a in ord-cases) apply simp apply (case-tac add k y t1 , simp, simp) apply simp 137 apply simp apply (rule-tac a=k and b=aa in ord-cases) apply simp apply (case-tac add k y t2 , simp, simp) apply simp apply simp apply (case-tac add k y t3 , simp, simp) done lemma ord0-add0 : ord0 t =⇒ ord0 (add0 k y t) by (simp add: ord0-def ord 0-add0 ) The del function preserves balance. lemma del-extra-simps: l 6= Empty ∨ r 6= Empty =⇒ del k (Branch2 l p r) = (case compare k p of LESS => (case del k l of None ⇒ None | Some(p 0, (False, l 0)) => Some(p 0, (False, Branch2 l 0 p r)) | Some(p 0, (True, l 0)) => Some(p 0, case r of Branch2 rl rp rr => (True, Branch3 l 0 p rl rp rr) | Branch3 rl rp rm rq rr => (False, Branch2 (Branch2 l 0 p rl) rp (Branch2 rm rq rr)))) | or => (case del (if-eq or None k) r of None ⇒ None | Some(p 0, (False, r 0)) => Some(p 0, (False, Branch2 l (if-eq or p 0 p) r 0)) | Some(p 0, (True, r 0)) => Some(p 0, case l of Branch2 ll lp lr => (True, Branch3 ll lp lr (if-eq or p 0 p) r 0) | Branch3 ll lp lm lq lr => (False, Branch2 (Branch2 ll lp lm) lq (Branch2 lr (if-eq or p 0 p) r 0))))) l 6= Empty ∨ m 6= Empty ∨ r 6= Empty =⇒ del k (Branch3 l p m q r) = (case compare k q of LESS => (case compare k p of LESS => (case del k l of None ⇒ None | Some(p 0, (False, l 0)) => Some(p 0, (False, Branch3 l 0 p m q r)) | Some(p 0, (True, l 0)) => Some(p 0, (False, case (m, r) of (Branch2 ml mp mr, Branch2 - - -) => Branch2 (Branch3 l 0 p ml mp mr) q r | (Branch3 ml mp mm mq mr, -) => Branch3 (Branch2 l 0 p ml) mp (Branch2 mm mq mr) q r | (Branch2 ml mp mr, Branch3 rl rp rm rq rr) => Branch3 (Branch2 l 0 p ml) mp (Branch2 mr q rl) rp (Branch2 rm rq rr)))) | or => (case del (if-eq or None k) m of None ⇒ None | Some(p 0, (False, m 0)) => Some(p 0, (False, Branch3 l (if-eq or p 0 p) m 0 q r)) | Some(p 0, (True, m 0)) => Some(p 0, (False, case (l, r) of (Branch2 ll lp lr, Branch2 - - -) => Branch2 (Branch3 ll lp lr (if-eq or p 0 p) m 0) q r | (Branch3 ll lp lm lq lr, -) => Branch3 (Branch2 ll lp lm) lq (Branch2 lr (if-eq or p 0 p) m 0) q r 138 | (-, Branch3 rl rp rm rq rr) => Branch3 l (if-eq or p 0 p)(Branch2 m 0 q rl) rp (Branch2 rm rq rr))))) | or => (case del (if-eq or None k) r of None ⇒ None | Some(q 0, (False, r 0)) => Some(q 0, (False, Branch3 l p m (if-eq or q 0 q) r 0)) | Some(q 0, (True, r 0)) => Some(q 0, (False, case (l, m) of (Branch2 - - -, Branch2 ml mp mr) => Branch2 l p (Branch3 ml mp mr (if-eq or q 0 q) r 0) | (-, Branch3 ml mp mm mq mr) => Branch3 l p (Branch2 ml mp mm) mq (Branch2 mr (if-eq or q 0 q) r 0) | (Branch3 ll lp lm lq lr, Branch2 ml mp mr) => Branch3 (Branch2 ll lp lm) lq (Branch2 lr p ml) mp (Branch2 mr (if-eq or q 0 q) r 0))))) apply − apply (cases l, cases r, simp-all only: del.simps, simp) apply (cases l, cases m, cases r, simp-all only: del.simps, simp) done fun dfull where dfull n None ←→ True | dfull n (Some (p, (True, t 0))) ←→ full n t 0 | dfull n (Some (p, (False, t 0))) ←→ full (Suc n) t 0 lemmas dfull-case-intros = ord.exhaust [of y dfull a (case-ord b c d y)] option.exhaust [of y dfull a (case-option b c y)] prod.exhaust [of y dfull a (case-prod b y)] bool.exhaust [of y dfull a (case-bool b c y)] tree23 .exhaust [of y dfull a (Some (b, case-tree23 c d e y))] tree23 .exhaust [of y full a (case-tree23 b c d y)] for a b c d e y lemma dfull-del: full (Suc n) t =⇒ dfull n (del k t) proof − { fix n :: nat and p :: key × 0a and l r :: 0a tree23 and k assume Vn. [[compare k p = LESS; full (Suc n) l]] =⇒ dfull n (del k l) and Vn. [[compare k p = EQUAL; full (Suc n) r]] =⇒ dfull n (del (if-eq EQUAL None k) r) and Vn. [[compare k p = GREATER; full (Suc n) r]] =⇒ dfull n (del (if-eq GREATER None k) r) and full (Suc n)(Branch2 l p r) hence dfull n (del k (Branch2 l p r)) apply clarsimp apply (cases n) apply (cases k) apply simp apply (simp split: ord.split) apply simp apply (subst del-extra-simps, force) 139 apply (simp | rule dfull-case-intros)+ done } note A = this { fix n :: nat and p q :: key × 0a and l m r :: 0a tree23 and k assume Vn. [[compare k q = LESS; compare k p = LESS; full (Suc n) l]] =⇒ dfull n (del k l) and Vn. [[compare k q = LESS; compare k p = EQUAL; full (Suc n) m]] =⇒ dfull n (del (if-eq EQUAL None k) m) and Vn. [[compare k q = LESS; compare k p = GREATER; full (Suc n) m]] =⇒ dfull n (del (if-eq GREATER None k) m) and Vn. [[compare k q = EQUAL; full (Suc n) r]] =⇒ dfull n (del (if-eq EQUAL None k) r) and Vn. [[compare k q = GREATER; full (Suc n) r]] =⇒ dfull n (del (if-eq GREATER None k) r) and full (Suc n)(Branch3 l p m q r) hence dfull n (del k (Branch3 l p m q r)) apply clarsimp apply (cases n) apply (cases k) apply simp apply (simp split: ord.split) apply simp apply (subst del-extra-simps, force) apply (simp | rule dfull-case-intros)+ done } note B = this show full (Suc n) t =⇒ dfull n (del k t) proof (induct k t arbitrary: n rule: del.induct, goal-cases) case (1 k n) thus dfull n (del (Some k) Empty) by simp next case (2 p n) thus dfull n (del None (Branch2 Empty p Empty)) by simp next case (3 p q n) thus dfull n (del None (Branch3 Empty p Empty q Empty)) by simp next case (4 v p n) thus dfull n (del (Some v)(Branch2 Empty p Empty)) by (simp split: ord.split) next case (5 v p q n) thus dfull n (del (Some v)(Branch3 Empty p Empty q Empty)) by (simp split: ord.split) next case (26 n) thus ?case by simp qed (fact A | fact B)+ qed 140 lemma bal-del0 : bal t =⇒ bal (del0 k t) unfolding bal-iff-full del0-def apply (erule exE) apply (case-tac n, simp, simp) apply (frule dfull-del [where k=Some k]) apply (cases del (Some k) t, force) apply (rename-tac a, case-tac a, rename-tac b t 0, case-tac b, auto) done This is a little test harness and should be commented out once the above functions have been proved correct. datatype 0a act = Add int 0a | Del int fun exec where exec [] t = t | exec (Add k x # as) t = exec as (add0 k x t) | exec (Del k # as) t = exec as (del0 k t) Some quick checks: lemma bal-exec: bal t =⇒ bal (exec as t) by (induct as t arbitrary: t rule: exec.induct, simp-all add: bal-add0 bal-del0 ) lemma bal(exec as Empty) by (simp add: bal-exec) lemma ord0 (exec as Empty) quickcheck oops end 31 (Finite) multisets theory Multiset imports Main begin 31.1 The type of multisets definition multiset = {f :: 0a ⇒ nat. finite {x. f x > 0 }} typedef 0a multiset = multiset :: ( 0a ⇒ nat) set morphisms count Abs-multiset unfolding multiset-def proof show (λx. 0 ::nat) ∈ {f . finite {x. f x > 0 }} by simp 141 qed setup-lifting type-definition-multiset lemma multiset-eq-iff : M = N ←→ (∀ a. count M a = count N a) by (simp only: count-inject [symmetric] fun-eq-iff ) lemma multiset-eqI :(Vx. count A x = count B x) =⇒ A = B using multiset-eq-iff by auto Preservation of the representing set multiset. lemma const0-in-multiset:(λa. 0 ) ∈ multiset by (simp add: multiset-def ) lemma only1-in-multiset:(λb. if b = a then n else 0 ) ∈ multiset by (simp add: multiset-def ) lemma union-preserves-multiset: M ∈ multiset =⇒ N ∈ multiset =⇒ (λa. M a + N a) ∈ multiset by (simp add: multiset-def ) lemma diff-preserves-multiset: assumes M ∈ multiset shows (λa. M a − N a) ∈ multiset proof − have {x. N x < M x} ⊆ {x. 0 < M x} by auto with assms show ?thesis by (auto simp add: multiset-def intro: finite-subset) qed lemma filter-preserves-multiset: assumes M ∈ multiset shows (λx. if P x then M x else 0 ) ∈ multiset proof − have {x. (P x −→ 0 < M x) ∧ P x} ⊆ {x. 0 < M x} by auto with assms show ?thesis by (auto simp add: multiset-def intro: finite-subset) qed lemmas in-multiset = const0-in-multiset only1-in-multiset union-preserves-multiset diff-preserves-multiset filter-preserves-multiset 31.2 Representing multisets Multiset enumeration instantiation multiset :: (type) cancel-comm-monoid-add begin 142 lift-definition zero-multiset :: 0a multiset is λa. 0 by (rule const0-in-multiset) abbreviation Mempty :: 0a multiset ({#}) where Mempty ≡ 0 lift-definition plus-multiset :: 0a multiset ⇒ 0a multiset ⇒ 0a multiset is λMN . (λa. M a + N a) by (rule union-preserves-multiset) lift-definition minus-multiset :: 0a multiset ⇒ 0a multiset ⇒ 0a multiset is λ M N . λa. M a − N a by (rule diff-preserves-multiset) instance by (standard; transfer; simp add: fun-eq-iff ) end context begin qualified definition is-empty :: 0a multiset ⇒ bool where [code-abbrev]: is-empty A ←→ A = {#} end lemma add-mset-in-multiset: assumes M : hM ∈ multiset i shows h(λb. if b = a then Suc (M b) else M b) ∈ multiset i using assms by (simp add: multiset-def insert-Collect[symmetric]) lift-definition add-mset :: 0a ⇒ 0a multiset ⇒ 0a multiset is λa M b. if b = a then Suc (M b) else M b by (rule add-mset-in-multiset) syntax -multiset :: args ⇒ 0a multiset ({#(-)#}) translations {#x, xs#} == CONST add-mset x {#xs#} {#x#} == CONST add-mset x {#} lemma count-empty [simp]: count {#} a = 0 by (simp add: zero-multiset.rep-eq) lemma count-add-mset [simp]: count (add-mset b A) a = (if b = a then Suc (count A a) else count A a) by (simp add: add-mset.rep-eq) 143 lemma count-single: count {#b#} a = (if b = a then 1 else 0 ) by simp lemma add-mset-not-empty [simp]: hadd-mset a A 6= {#}i and empty-not-add-mset [simp]: {#}= 6 add-mset a A by (auto simp: multiset-eq-iff ) lemma add-mset-add-mset-same-iff [simp]: add-mset a A = add-mset a B ←→ A = B by (auto simp: multiset-eq-iff ) lemma add-mset-commute: add-mset x (add-mset y M ) = add-mset y (add-mset x M ) by (auto simp: multiset-eq-iff ) 31.3 Basic operations 31.3.1 Conversion to set and membership definition set-mset :: 0a multiset ⇒ 0a set where set-mset M = {x. count M x > 0 } abbreviation Melem :: 0a ⇒ 0a multiset ⇒ bool where Melem a M ≡ a ∈ set-mset M notation Melem (op ∈#) and Melem ((-/ ∈# -)[51 , 51 ] 50 ) notation (ASCII ) Melem (op :#) and Melem ((-/ :# -)[51 , 51 ] 50 ) abbreviation not-Melem :: 0a ⇒ 0a multiset ⇒ bool where not-Melem a M ≡ a ∈/ set-mset M notation not-Melem (op ∈/#) and not-Melem ((-//∈# -)[51 , 51 ] 50 ) notation (ASCII ) not-Melem (op ∼:#) and not-Melem ((-/ ∼:# -)[51 , 51 ] 50 ) context begin qualified abbreviation Ball :: 0a multiset ⇒ ( 0a ⇒ bool) ⇒ bool 144 where Ball M ≡ Set.Ball (set-mset M ) qualified abbreviation Bex :: 0a multiset ⇒ ( 0a ⇒ bool) ⇒ bool where Bex M ≡ Set.Bex (set-mset M ) end syntax -MBall :: pttrn ⇒ 0a set ⇒ bool ⇒ bool ((3 ∀ -∈#-./ -)[0 , 0 , 10 ] 10 ) -MBex :: pttrn ⇒ 0a set ⇒ bool ⇒ bool ((3 ∃ -∈#-./ -)[0 , 0 , 10 ] 10 ) syntax (ASCII ) -MBall :: pttrn ⇒ 0a set ⇒ bool ⇒ bool ((3 ∀ -:#-./ -)[0 , 0 , 10 ] 10 ) -MBex :: pttrn ⇒ 0a set ⇒ bool ⇒ bool ((3 ∃ -:#-./ -)[0 , 0 , 10 ] 10 ) translations ∀ x∈#A. P CONST Multiset.Ball A (λx. P) ∃ x∈#A. P CONST Multiset.Bex A (λx. P) lemma count-eq-zero-iff : count M x = 0 ←→ x ∈/# M by (auto simp add: set-mset-def ) lemma not-in-iff : x ∈/# M ←→ count M x = 0 by (auto simp add: count-eq-zero-iff ) lemma count-greater-zero-iff [simp]: count M x > 0 ←→ x ∈# M by (auto simp add: set-mset-def ) lemma count-inI : assumes count M x = 0 =⇒ False shows x ∈# M proof (rule ccontr) assume x ∈/# M with assms show False by (simp add: not-in-iff ) qed lemma in-countE: assumes x ∈# M obtains n where count M x = Suc n proof − from assms have count M x > 0 by simp then obtain n where count M x = Suc n using gr0-conv-Suc by blast with that show thesis . qed 145 lemma count-greater-eq-Suc-zero-iff [simp]: count M x ≥ Suc 0 ←→ x ∈# M by (simp add: Suc-le-eq) lemma count-greater-eq-one-iff [simp]: count M x ≥ 1 ←→ x ∈# M by simp lemma set-mset-empty [simp]: set-mset {#} = {} by (simp add: set-mset-def ) lemma set-mset-single: set-mset {#b#} = {b} by (simp add: set-mset-def ) lemma set-mset-eq-empty-iff [simp]: set-mset M = {} ←→ M = {#} by (auto simp add: multiset-eq-iff count-eq-zero-iff ) lemma finite-set-mset [iff ]: finite (set-mset M ) using count [of M ] by (simp add: multiset-def ) lemma set-mset-add-mset-insert [simp]: hset-mset (add-mset a A) = insert a (set-mset A)i by (auto simp del: count-greater-eq-Suc-zero-iff simp: count-greater-eq-Suc-zero-iff [symmetric] split: if-splits) lemma multiset-nonemptyE [elim]: assumes A 6= {#} obtains x where x ∈# A proof − have ∃ x. x ∈# A by (rule ccontr)(insert assms, auto) with that show ?thesis by blast qed 31.3.2 Union lemma count-union [simp]: count (M + N ) a = count M a + count N a by (simp add: plus-multiset.rep-eq) lemma set-mset-union [simp]: set-mset (M + N ) = set-mset M ∪ set-mset N by (simp only: set-eq-iff count-greater-zero-iff [symmetric] count-union) simp lemma union-mset-add-mset-left [simp]: add-mset a A + B = add-mset a (A + B) 146 by (auto simp: multiset-eq-iff ) lemma union-mset-add-mset-right [simp]: A + add-mset a B = add-mset a (A + B) by (auto simp: multiset-eq-iff ) lemma add-mset-add-single: hadd-mset a A = A + {#a#}i by (subst union-mset-add-mset-right, subst add.comm-neutral) standard 31.3.3 Difference instance multiset :: (type) comm-monoid-diff by standard (transfer; simp add: fun-eq-iff ) lemma count-diff [simp]: count (M − N ) a = count M a − count N a by (simp add: minus-multiset.rep-eq) lemma add-mset-diff-bothsides: hadd-mset a M − add-mset a A = M − Ai by (auto simp: multiset-eq-iff ) lemma in-diff-count: a ∈# M − N ←→ count N a < count M a by (simp add: set-mset-def ) lemma count-in-diffI : assumes Vn. count N x = n + count M x =⇒ False shows x ∈# M − N proof (rule ccontr) assume x ∈/# M − N then have count N x = (count N x − count M x) + count M x by (simp add: in-diff-count not-less) with assms show False by auto qed lemma in-diff-countE: assumes x ∈# M − N obtains n where count M x = Suc n + count N x proof − from assms have count M x − count N x > 0 by (simp add: in-diff-count) then have count M x > count N x by simp then obtain n where count M x = Suc n + count N x using less-iff-Suc-add by auto with that show thesis . qed lemma in-diffD: assumes a ∈# M − N 147 shows a ∈# M proof − have 0 ≤ count N a by simp also from assms have count N a < count M a by (simp add: in-diff-count) finally show ?thesis by simp qed lemma set-mset-diff : set-mset (M − N ) = {a. count N a < count M a} by (simp add: set-mset-def ) lemma diff-empty [simp]: M − {#} = M ∧ {#} − M = {#} by rule (fact Groups.diff-zero, fact Groups.zero-diff ) lemma diff-cancel: A − A = {#} by (fact Groups.diff-cancel) lemma diff-union-cancelR: M + N − N = (M :: 0a multiset) by (fact add-diff-cancel-right 0) lemma diff-union-cancelL: N + M − N = (M :: 0a multiset) by (fact add-diff-cancel-left 0) lemma diff-right-commute: fixes MNQ :: 0a multiset shows M − N − Q = M − Q − N by (fact diff-right-commute) lemma diff-add: fixes MNQ :: 0a multiset shows M − (N + Q) = M − N − Q by (rule sym)(fact diff-diff-add) lemma insert-DiffM [simp]: x ∈# M =⇒ add-mset x (M − {#x#}) = M by (clarsimp simp: multiset-eq-iff ) lemma insert-DiffM2 : x ∈# M =⇒ (M − {#x#}) + {#x#} = M by simp lemma diff-union-swap: a 6= b =⇒ add-mset b (M − {#a#}) = add-mset b M − {#a#} by (auto simp add: multiset-eq-iff ) lemma diff-add-mset-swap [simp]: b ∈/# A =⇒ add-mset b M − A = add-mset b (M − A) by (auto simp add: multiset-eq-iff simp: not-in-iff ) lemma diff-union-swap2 [simp]: y ∈# M =⇒ add-mset x M − {#y#} = add-mset 148 x (M − {#y#}) by (metis add-mset-diff-bothsides diff-union-swap diff-zero insert-DiffM ) lemma diff-diff-add-mset [simp]: (M :: 0a multiset) − N − P = M − (N + P) by (rule diff-diff-add) lemma diff-union-single-conv: a ∈# J =⇒ I + J − {#a#} = I + (J − {#a#}) by (simp add: multiset-eq-iff Suc-le-eq) lemma mset-add [elim?]: assumes a ∈# A obtains B where A = add-mset a B proof − from assms have A = add-mset a (A − {#a#}) by simp with that show thesis . qed lemma union-iff : a ∈# A + B ←→ a ∈# A ∨ a ∈# B by auto 31.3.4 Equality of multisets lemma single-eq-single [simp]: {#a#} = {#b#} ←→ a = b by (auto simp add: multiset-eq-iff ) lemma union-eq-empty [iff ]: M + N = {#} ←→ M = {#} ∧ N = {#} by (auto simp add: multiset-eq-iff ) lemma empty-eq-union [iff ]: {#} = M + N ←→ M = {#} ∧ N = {#} by (auto simp add: multiset-eq-iff ) lemma multi-self-add-other-not-self [simp]: M = add-mset x M ←→ False by (auto simp add: multiset-eq-iff ) lemma add-mset-remove-trivial [simp]: hadd-mset x M − {#x#} = M i by (auto simp: multiset-eq-iff ) lemma diff-single-trivial: ¬ x ∈# M =⇒ M − {#x#} = M by (auto simp add: multiset-eq-iff not-in-iff ) lemma diff-single-eq-union: x ∈# M =⇒ M − {#x#} = N ←→ M = add-mset x N by auto lemma union-single-eq-diff : add-mset x M = N =⇒ M = N − {#x#} unfolding add-mset-add-single[of - M ] by (fact add-implies-diff ) 149 lemma union-single-eq-member: add-mset x M = N =⇒ x ∈# N by auto lemma add-mset-remove-trivial-If : add-mset a (N − {#a#}) = (if a ∈# N then N else add-mset a N ) by (simp add: diff-single-trivial) lemma add-mset-remove-trivial-eq: hN = add-mset a (N − {#a#}) ←→ a ∈# N i by (auto simp: add-mset-remove-trivial-If ) lemma union-is-single: M + N = {#a#} ←→ M = {#a#} ∧ N = {#} ∨ M = {#} ∧ N = {#a#} (is ?lhs = ?rhs) proof show ?lhs if ?rhs using that by auto show ?rhs if ?lhs by (metis Multiset.diff-cancel add.commute add-diff-cancel-left 0 diff-add-zero diff-single-trivial insert-DiffM that) qed lemma single-is-union: {#a#} = M + N ←→ {#a#} = M ∧ N = {#} ∨ M = {#} ∧ {#a#} = N by (auto simp add: eq-commute [of {#a#} M + N ] union-is-single) lemma add-eq-conv-diff : add-mset a M = add-mset b N ←→ M = N ∧ a = b ∨ M = add-mset b (N − {#a#}) ∧ N = add-mset a (M − {#b#}) (is ?lhs ←→ ?rhs) proof show ?lhs if ?rhs using that by (auto simp add: add-mset-commute[of a b]) show ?rhs if ?lhs proof (cases a = b) case True with h?lhs i show ?thesis by simp next case False from h?lhs i have a ∈# add-mset b N by (rule union-single-eq-member) with False have a ∈# N by auto moreover from h?lhs i have M = add-mset b N − {#a#} by (rule union-single-eq-diff ) moreover note False ultimately show ?thesis by (auto simp add: diff-right-commute [of - {#a#}]) qed qed lemma add-mset-eq-single [iff ]: add-mset b M = {#a#} ←→ b = a ∧ M = {#} 150 by (auto simp: add-eq-conv-diff ) lemma single-eq-add-mset [iff ]: {#a#} = add-mset b M ←→ b = a ∧ M = {#} by (auto simp: add-eq-conv-diff ) lemma insert-noteq-member: assumes BC : add-mset b B = add-mset c C and bnotc: b 6= c shows c ∈# B proof − have c ∈# add-mset c C by simp have nc: ¬ c ∈# {#b#} using bnotc by simp then have c ∈# add-mset b B using BC by simp then show c ∈# B using nc by simp qed lemma add-eq-conv-ex: (add-mset a M = add-mset b N ) = (M = N ∧ a = b ∨ (∃ K . M = add-mset b K ∧ N = add-mset a K )) by (auto simp add: add-eq-conv-diff ) lemma multi-member-split: x ∈# M =⇒ ∃ A. M = add-mset x A by (rule exI [where x = M − {#x#}]) simp lemma multiset-add-sub-el-shuffle: assumes c ∈# B and b 6= c shows add-mset b (B − {#c#}) = add-mset b B − {#c#} proof − from hc ∈# B i obtain A where B: B = add-mset c A by (blast dest: multi-member-split) have add-mset b A = add-mset c (add-mset b A) − {#c#} by simp then have add-mset b A = add-mset b (add-mset c A) − {#c#} by (simp add: hb 6= ci) then show ?thesis using B by simp qed lemma add-mset-eq-singleton-iff [iff ]: add-mset x M = {#y#} ←→ M = {#} ∧ x = y by auto 31.3.5 Pointwise ordering induced by count definition subseteq-mset :: 0a multiset ⇒ 0a multiset ⇒ bool (infix ⊆# 50 ) where A ⊆# B = (∀ a. count A a ≤ count B a) definition subset-mset :: 0a multiset ⇒ 0a multiset ⇒ bool (infix ⊂# 50 ) where A ⊂# B = (A ⊆# B ∧ A 6= B) 151 abbreviation (input) supseteq-mset :: 0a multiset ⇒ 0a multiset ⇒ bool (infix ⊇# 50 ) where supseteq-mset A B ≡ B ⊆# A abbreviation (input) supset-mset :: 0a multiset ⇒ 0a multiset ⇒ bool (infix ⊃# 50 ) where supset-mset A B ≡ B ⊂# A notation (input) subseteq-mset (infix ≤# 50 ) and supseteq-mset (infix ≥# 50 ) notation (ASCII ) subseteq-mset (infix <=# 50 ) and subset-mset (infix <# 50 ) and supseteq-mset (infix >=# 50 ) and supset-mset (infix ># 50 ) interpretation subset-mset: ordered-ab-semigroup-add-imp-le op + op − op ⊆# op ⊂# by standard (auto simp add: subset-mset-def subseteq-mset-def multiset-eq-iff in- tro: order-trans antisym) interpretation subset-mset: ordered-ab-semigroup-monoid-add-imp-le op + 0 op − op ≤# op <# by standard lemma mset-subset-eqI : (Va. count A a ≤ count B a) =⇒ A ⊆# B by (simp add: subseteq-mset-def ) lemma mset-subset-eq-count: A ⊆# B =⇒ count A a ≤ count B a by (simp add: subseteq-mset-def ) lemma mset-subset-eq-exists-conv:(A:: 0a multiset) ⊆# B ←→ (∃ C . B = A + C ) unfolding subseteq-mset-def apply (rule iffI ) apply (rule exI [where x = B − A]) apply (auto intro: multiset-eq-iff [THEN iffD2 ]) done interpretation subset-mset: ordered-cancel-comm-monoid-diff op + 0 op ≤# op <# op − by standard (simp, fact mset-subset-eq-exists-conv) declare subset-mset.add-diff-assoc[simp] subset-mset.add-diff-assoc2 [simp] lemma mset-subset-eq-mono-add-right-cancel:(A:: 0a multiset) + C ⊆# B + C 152 ←→ A ⊆# B by (fact subset-mset.add-le-cancel-right) lemma mset-subset-eq-mono-add-left-cancel: C + (A:: 0a multiset) ⊆# C + B ←→ A ⊆# B by (fact subset-mset.add-le-cancel-left) lemma mset-subset-eq-mono-add:(A:: 0a multiset) ⊆# B =⇒ C ⊆# D =⇒ A + C ⊆# B + D by (fact subset-mset.add-mono) lemma mset-subset-eq-add-left:(A:: 0a multiset) ⊆# A + B by simp lemma mset-subset-eq-add-right: B ⊆#(A:: 0a multiset) + B by simp lemma single-subset-iff [simp]: {#a#} ⊆# M ←→ a ∈# M by (auto simp add: subseteq-mset-def Suc-le-eq) lemma mset-subset-eq-single: a ∈# B =⇒ {#a#} ⊆# B by simp lemma mset-subset-eq-add-mset-cancel: hadd-mset a A ⊆# add-mset a B ←→ A ⊆# B i unfolding add-mset-add-single[of - A] add-mset-add-single[of - B] by (rule mset-subset-eq-mono-add-right-cancel) lemma multiset-diff-union-assoc: fixes ABCD :: 0a multiset shows C ⊆# B =⇒ A + B − C = A + (B − C ) by (fact subset-mset.diff-add-assoc) lemma mset-subset-eq-multiset-union-diff-commute: fixes ABCD :: 0a multiset shows B ⊆# A =⇒ A − B + C = A + C − B by (fact subset-mset.add-diff-assoc2 ) lemma diff-subset-eq-self [simp]: (M :: 0a multiset) − N ⊆# M by (simp add: subseteq-mset-def ) lemma mset-subset-eqD: assumes A ⊆# B and x ∈# A shows x ∈# B proof − from hx ∈# Ai have count A x > 0 by simp also from hA ⊆# B i have count A x ≤ count B x 153 by (simp add: subseteq-mset-def ) finally show ?thesis by simp qed lemma mset-subsetD: A ⊂# B =⇒ x ∈# A =⇒ x ∈# B by (auto intro: mset-subset-eqD [of A]) lemma set-mset-mono: A ⊆# B =⇒ set-mset A ⊆ set-mset B by (metis mset-subset-eqD subsetI ) lemma mset-subset-eq-insertD: add-mset x A ⊆# B =⇒ x ∈# B ∧ A ⊂# B apply (rule conjI ) apply (simp add: mset-subset-eqD) apply (clarsimp simp: subset-mset-def subseteq-mset-def ) apply safe apply (erule-tac x = a in allE) apply (auto split: if-split-asm) done lemma mset-subset-insertD: add-mset x A ⊂# B =⇒ x ∈# B ∧ A ⊂# B by (rule mset-subset-eq-insertD) simp lemma mset-subset-of-empty[simp]: A ⊂# {#} ←→ False by (simp only: subset-mset.not-less-zero) lemma empty-subset-add-mset[simp]: {#} <# add-mset x M by(auto intro: subset-mset.gr-zeroI ) lemma empty-le: {#} ⊆# A by (fact subset-mset.zero-le) lemma insert-subset-eq-iff : add-mset a A ⊆# B ←→ a ∈# B ∧ A ⊆# B − {#a#} using le-diff-conv2 [of Suc 0 count B a count A a] apply (auto simp add: subseteq-mset-def not-in-iff Suc-le-eq) apply (rule ccontr) apply (auto simp add: not-in-iff ) done lemma insert-union-subset-iff : add-mset a A ⊂# B ←→ a ∈# B ∧ A ⊂# B − {#a#} by (auto simp add: insert-subset-eq-iff subset-mset-def ) lemma subset-eq-diff-conv: A − C ⊆# B ←→ A ⊆# B + C 154 by (simp add: subseteq-mset-def le-diff-conv) lemma multi-psub-of-add-self [simp]: A ⊂# add-mset x A by (auto simp: subset-mset-def subseteq-mset-def ) lemma multi-psub-self : A ⊂# A = False by simp lemma mset-subset-add-mset [simp]: add-mset x N ⊂# add-mset x M ←→ N ⊂# M unfolding add-mset-add-single[of - N ] add-mset-add-single[of - M ] by (fact subset-mset.add-less-cancel-right) lemma mset-subset-diff-self : c ∈# B =⇒ B − {#c#} ⊂# B by (auto simp: subset-mset-def elim: mset-add) lemma Diff-eq-empty-iff-mset: A − B = {#} ←→ A ⊆# B by (auto simp: multiset-eq-iff subseteq-mset-def ) lemma add-mset-subseteq-single-iff [iff ]: add-mset a M ⊆# {#b#} ←→ M = {#} ∧ a = b proof assume A: add-mset a M ⊆# {#b#} then have ha = bi by (auto dest: mset-subset-eq-insertD) then show M ={#} ∧ a=b using A by (simp add: mset-subset-eq-add-mset-cancel) qed simp 31.3.6 Intersection and bounded union definition inf-subset-mset :: 0a multiset ⇒ 0a multiset ⇒ 0a multiset (infixl ∩# 70 ) where multiset-inter-def : inf-subset-mset A B = A − (A − B) interpretation subset-mset: semilattice-inf inf-subset-mset op ⊆# op ⊂# proof − have [simp]: m ≤ n =⇒ m ≤ q =⇒ m ≤ n − (n − q) for m n q :: nat by arith show class.semilattice-inf op ∩# op ⊆# op ⊂# by standard (auto simp add: multiset-inter-def subseteq-mset-def ) qed — FIXME: avoid junk stemming from type class interpretation definition sup-subset-mset :: 0a multiset ⇒ 0a multiset ⇒ 0a multiset(infixl ∪# 70 ) where sup-subset-mset A B = A + (B − A) — FIXME irregular fact name interpretation subset-mset: semilattice-sup sup-subset-mset op ⊆# op ⊂# 155 proof − have [simp]: m ≤ n =⇒ q ≤ n =⇒ m + (q − m) ≤ n for m n q :: nat by arith show class.semilattice-sup op ∪# op ⊆# op ⊂# by standard (auto simp add: sup-subset-mset-def subseteq-mset-def ) qed — FIXME: avoid junk stemming from type class interpretation interpretation subset-mset: bounded-lattice-bot op ∩# op ⊆# op ⊂# op ∪# {#} by standard auto 31.3.7 Additional intersection facts lemma multiset-inter-count [simp]: fixes AB :: 0a multiset shows count (A ∩# B) x = min (count A x)(count B x) by (simp add: multiset-inter-def ) lemma set-mset-inter [simp]: set-mset (A ∩# B) = set-mset A ∩ set-mset B by (simp only: set-eq-iff count-greater-zero-iff [symmetric] multiset-inter-count) simp lemma diff-intersect-left-idem [simp]: M − M ∩# N = M − N by (simp add: multiset-eq-iff min-def ) lemma diff-intersect-right-idem [simp]: M − N ∩# M = M − N by (simp add: multiset-eq-iff min-def ) lemma multiset-inter-single[simp]: a 6= b =⇒ {#a#} ∩# {#b#} = {#} by (rule multiset-eqI ) auto lemma multiset-union-diff-commute: assumes B ∩# C = {#} shows A + B − C = A − C + B proof (rule multiset-eqI ) fix x from assms have min (count B x)(count C x) = 0 by (auto simp add: multiset-eq-iff ) then have count B x = 0 ∨ count C x = 0 unfolding min-def by (auto split: if-splits) then show count (A + B − C ) x = count (A − C + B) x by auto qed lemma disjunct-not-in: 156 A ∩# B = {#} ←→ (∀ a. a ∈/# A ∨ a ∈/# B)(is ?P ←→ ?Q) proof assume ?P show ?Q proof fix a from h?P i have min (count A a)(count B a) = 0 by (simp add: multiset-eq-iff ) then have count A a = 0 ∨ count B a = 0 by (cases count A a ≤ count B a)(simp-all add: min-def ) then show a ∈/# A ∨ a ∈/# B by (simp add: not-in-iff ) qed next assume ?Q show ?P proof (rule multiset-eqI ) fix a from h?Q i have count A a = 0 ∨ count B a = 0 by (auto simp add: not-in-iff ) then show count (A ∩# B) a = count {#} a by auto qed qed lemma inter-mset-empty-distrib-right: A ∩#(B + C ) = {#} ←→ A ∩# B = {#} ∧ A ∩# C = {#} by (meson disjunct-not-in union-iff ) lemma inter-mset-empty-distrib-left:(A + B) ∩# C = {#} ←→ A ∩# C = {#} ∧ B ∩# C = {#} by (meson disjunct-not-in union-iff ) lemma add-mset-inter-add-mset[simp]: add-mset a A ∩# add-mset a B = add-mset a (A ∩# B) by (metis add-mset-add-single add-mset-diff-bothsides diff-subset-eq-self multiset-inter-def subset-mset.diff-add-assoc2 ) lemma add-mset-disjoint [simp]: add-mset a A ∩# B = {#} ←→ a ∈/# B ∧ A ∩# B = {#} {#} = add-mset a A ∩# B ←→ a ∈/# B ∧ {#} = A ∩# B by (auto simp: disjunct-not-in) lemma disjoint-add-mset [simp]: B ∩# add-mset a A = {#} ←→ a ∈/# B ∧ B ∩# A = {#} {#} = A ∩# add-mset b B ←→ b ∈/# A ∧ {#} = A ∩# B by (auto simp: disjunct-not-in) lemma inter-add-left1 : ¬ x ∈# N =⇒ (add-mset x M ) ∩# N = M ∩# N 157 by (simp add: multiset-eq-iff not-in-iff ) lemma inter-add-left2 : x ∈# N =⇒ (add-mset x M ) ∩# N = add-mset x (M ∩# (N − {#x#})) by (auto simp add: multiset-eq-iff elim: mset-add) lemma inter-add-right1 : ¬ x ∈# N =⇒ N ∩#(add-mset x M ) = N ∩# M by (simp add: multiset-eq-iff not-in-iff ) lemma inter-add-right2 : x ∈# N =⇒ N ∩#(add-mset x M ) = add-mset x ((N − {#x#}) ∩# M ) by (auto simp add: multiset-eq-iff elim: mset-add) lemma disjunct-set-mset-diff : assumes M ∩# N = {#} shows set-mset (M − N ) = set-mset M proof (rule set-eqI ) fix a from assms have a ∈/# M ∨ a ∈/# N by (simp add: disjunct-not-in) then show a ∈# M − N ←→ a ∈# M by (auto dest: in-diffD)(simp add: in-diff-count not-in-iff ) qed lemma at-most-one-mset-mset-diff : assumes a ∈/# M − {#a#} shows set-mset (M − {#a#}) = set-mset M − {a} using assms by (auto simp add: not-in-iff in-diff-count set-eq-iff ) lemma more-than-one-mset-mset-diff : assumes a ∈# M − {#a#} shows set-mset (M − {#a#}) = set-mset M proof (rule set-eqI ) fix b have Suc 0 < count M b =⇒ count M b > 0 by arith then show b ∈# M − {#a#} ←→ b ∈# M using assms by (auto simp add: in-diff-count) qed lemma inter-iff : a ∈# A ∩# B ←→ a ∈# A ∧ a ∈# B by simp lemma inter-union-distrib-left: A ∩# B + C = (A + C ) ∩#(B + C ) by (simp add: multiset-eq-iff min-add-distrib-left) lemma inter-union-distrib-right: C + A ∩# B = (C + A) ∩#(C + B) 158 using inter-union-distrib-left [of A B C ] by (simp add: ac-simps) lemma inter-subset-eq-union: A ∩# B ⊆# A + B by (auto simp add: subseteq-mset-def ) 31.3.8 Additional bounded union facts lemma sup-subset-mset-count [simp]: — FIXME irregular fact name count (A ∪# B) x = max (count A x)(count B x) by (simp add: sup-subset-mset-def ) lemma set-mset-sup [simp]: set-mset (A ∪# B) = set-mset A ∪ set-mset B by (simp only: set-eq-iff count-greater-zero-iff [symmetric] sup-subset-mset-count) (auto simp add: not-in-iff elim: mset-add) lemma sup-union-left1 [simp]: ¬ x ∈# N =⇒ (add-mset x M ) ∪# N = add-mset x (M ∪# N ) by (simp add: multiset-eq-iff not-in-iff ) lemma sup-union-left2 : x ∈# N =⇒ (add-mset x M ) ∪# N = add-mset x (M ∪#(N − {#x#})) by (simp add: multiset-eq-iff ) lemma sup-union-right1 [simp]: ¬ x ∈# N =⇒ N ∪#(add-mset x M ) = add-mset x (N ∪# M ) by (simp add: multiset-eq-iff not-in-iff ) lemma sup-union-right2 : x ∈# N =⇒ N ∪#(add-mset x M ) = add-mset x ((N − {#x#}) ∪# M ) by (simp add: multiset-eq-iff ) lemma sup-union-distrib-left: A ∪# B + C = (A + C ) ∪#(B + C ) by (simp add: multiset-eq-iff max-add-distrib-left) lemma union-sup-distrib-right: C + A ∪# B = (C + A) ∪#(C + B) using sup-union-distrib-left [of A B C ] by (simp add: ac-simps) lemma union-diff-inter-eq-sup: A + B − A ∩# B = A ∪# B by (auto simp add: multiset-eq-iff ) lemma union-diff-sup-eq-inter: A + B − A ∪# B = A ∩# B by (auto simp add: multiset-eq-iff ) 159 lemma add-mset-union: hadd-mset a A ∪# add-mset a B = add-mset a (A ∪# B)i by (auto simp: multiset-eq-iff max-def ) 31.3.9 Subset is an order interpretation subset-mset: order op ⊆# op ⊂# by unfold-locales 31.4 Replicate and repeat operations definition replicate-mset :: nat ⇒ 0a ⇒ 0a multiset where replicate-mset n x = (add-mset x ˆˆ n) {#} lemma replicate-mset-0 [simp]: replicate-mset 0 x = {#} unfolding replicate-mset-def by simp lemma replicate-mset-Suc [simp]: replicate-mset (Suc n) x = add-mset x (replicate-mset n x) unfolding replicate-mset-def by (induct n)(auto intro: add.commute) lemma count-replicate-mset[simp]: count (replicate-mset n x) y = (if y = x then n else 0 ) unfolding replicate-mset-def by (induct n) auto fun repeat-mset :: nat ⇒ 0a multiset ⇒ 0a multiset where repeat-mset 0 - = {#} | repeat-mset (Suc n) A = A + repeat-mset n A lemma count-repeat-mset [simp]: count (repeat-mset i A) a = i ∗ count A a by (induction i) auto lemma repeat-mset-right [simp]: repeat-mset a (repeat-mset b A) = repeat-mset (a ∗ b) A by (auto simp: multiset-eq-iff left-diff-distrib 0) 0 lemma left-diff-repeat-mset-distrib : hrepeat-mset (i − j ) u = repeat-mset i u − repeat-mset j u i by (auto simp: multiset-eq-iff left-diff-distrib 0) lemma left-add-mult-distrib-mset: repeat-mset i u + (repeat-mset j u + k) = repeat-mset (i+j ) u + k by (auto simp: multiset-eq-iff add-mult-distrib) lemma repeat-mset-distrib: repeat-mset (m + n) A = repeat-mset m A + repeat-mset n A by (auto simp: multiset-eq-iff Nat.add-mult-distrib) lemma repeat-mset-distrib2 [simp]: repeat-mset n (A + B) = repeat-mset n A + repeat-mset n B by (auto simp: multiset-eq-iff add-mult-distrib2 ) 160 lemma repeat-mset-replicate-mset[simp]: repeat-mset n {#a#} = replicate-mset n a by (auto simp: multiset-eq-iff ) lemma repeat-mset-distrib-add-mset[simp]: repeat-mset n (add-mset a A) = replicate-mset n a + repeat-mset n A by (auto simp: multiset-eq-iff ) lemma repeat-mset-empty[simp]: repeat-mset n {#} = {#} by (induction n) simp-all 31.4.1 Simprocs lemma mset-diff-add-eq1 : j ≤ (i::nat) =⇒ ((repeat-mset i u + m) − (repeat-mset j u + n)) = ((repeat-mset (i−j ) u + m) − n) by (auto simp: multiset-eq-iff nat-diff-add-eq1 ) lemma mset-diff-add-eq2 : i ≤ (j ::nat) =⇒ ((repeat-mset i u + m) − (repeat-mset j u + n)) = (m − (repeat-mset (j −i) u + n)) by (auto simp: multiset-eq-iff nat-diff-add-eq2 ) lemma mset-eq-add-iff1 : j ≤ (i::nat) =⇒ (repeat-mset i u + m = repeat-mset j u + n) = (repeat-mset (i−j ) u + m = n) by (auto simp: multiset-eq-iff nat-eq-add-iff1 ) lemma mset-eq-add-iff2 : i ≤ (j ::nat) =⇒ (repeat-mset i u + m = repeat-mset j u + n) = (m = repeat-mset (j −i) u + n) by (auto simp: multiset-eq-iff nat-eq-add-iff2 ) lemma mset-subseteq-add-iff1 : j ≤ (i::nat) =⇒ (repeat-mset i u + m ⊆# repeat-mset j u + n) = (repeat-mset (i−j ) u + m ⊆# n) by (auto simp add: subseteq-mset-def nat-le-add-iff1 ) lemma mset-subseteq-add-iff2 : i ≤ (j ::nat) =⇒ (repeat-mset i u + m ⊆# repeat-mset j u + n) = (m ⊆# repeat-mset (j −i) u + n) by (auto simp add: subseteq-mset-def nat-le-add-iff2 ) lemma mset-subset-add-iff1 : j ≤ (i::nat) =⇒ (repeat-mset i u + m ⊂# repeat-mset j u + n) = (repeat-mset (i−j ) u + m ⊂# n) unfolding subset-mset-def by (simp add: mset-eq-add-iff1 mset-subseteq-add-iff1 ) 161 lemma mset-subset-add-iff2 : i ≤ (j ::nat) =⇒ (repeat-mset i u + m ⊂# repeat-mset j u + n) = (m ⊂# repeat-mset (j −i) u + n) unfolding subset-mset-def by (simp add: mset-eq-add-iff2 mset-subseteq-add-iff2 ) ML-file multiset-simprocs-util.ML ML-file multiset-simprocs.ML simproc-setup mseteq-cancel-numerals ((l:: 0a multiset) + m = n | (l:: 0a multiset) = m + n | add-mset a m = n | m = add-mset a n | replicate-mset p a = n | m = replicate-mset p a | repeat-mset p m = n | m = repeat-mset p m) = hfn phi => Multiset-Simprocs.eq-cancel-msets i simproc-setup msetless-cancel-numerals ((l:: 0a multiset) + m ⊂# n | (l:: 0a multiset) ⊂# m + n | add-mset a m ⊂# n | m ⊂# add-mset a n | replicate-mset p r ⊂# n | m ⊂# replicate-mset p r | repeat-mset p m ⊂# n | m ⊂# repeat-mset p m) = hfn phi => Multiset-Simprocs.subset-cancel-msets i simproc-setup msetle-cancel-numerals ((l:: 0a multiset) + m ⊆# n | (l:: 0a multiset) ⊆# m + n | add-mset a m ⊆# n | m ⊆# add-mset a n | replicate-mset p r ⊆# n | m ⊆# replicate-mset p r | repeat-mset p m ⊆# n | m ⊆# repeat-mset p m) = hfn phi => Multiset-Simprocs.subseteq-cancel-msets i simproc-setup msetdiff-cancel-numerals (((l:: 0a multiset) + m) − n | (l:: 0a multiset) − (m + n) | add-mset a m − n | m − add-mset a n | replicate-mset p r − n | m − replicate-mset p r | repeat-mset p m − n | m − repeat-mset p m) = hfn phi => Multiset-Simprocs.diff-cancel-msets i 31.4.2 Conditionally complete lattice instantiation multiset :: (type) Inf begin lift-definition Inf-multiset :: 0a multiset set ⇒ 0a multiset is λA i. if A = {} then 0 else Inf ((λf . f i) ‘A) proof − fix A :: ( 0a ⇒ nat) set assume ∗: Vx. x ∈ A =⇒ x ∈ multiset have finite {i. (if A = {} then 0 else Inf ((λf . f i) ‘A)) > 0 } unfolding multiset-def proof (cases A = {}) case False 162 then obtain f where f ∈ A by blast hence {i. Inf ((λf . f i) ‘A) > 0 } ⊆ {i. f i > 0 } by (auto intro: less-le-trans[OF - cInf-lower]) moreover from hf ∈ Ai ∗ have finite ... by (simp add: multiset-def ) ultimately have finite {i. Inf ((λf . f i) ‘A) > 0 } by (rule finite-subset) with False show ?thesis by simp qed simp-all thus (λi. if A = {} then 0 else INF f :A. f i) ∈ multiset by (simp add: multiset-def ) qed instance .. end lemma Inf-multiset-empty: Inf {} = {#} by transfer simp-all lemma count-Inf-multiset-nonempty: A 6= {} =⇒ count (Inf A) x = Inf ((λX . count X x) ‘A) by transfer simp-all instantiation multiset :: (type) Sup begin definition Sup-multiset :: 0a multiset set ⇒ 0a multiset where Sup-multiset A = (if A 6= {} ∧ subset-mset.bdd-above A then Abs-multiset (λi. Sup ((λX . count X i) ‘A)) else {#}) lemma Sup-multiset-empty: Sup {} = {#} by (simp add: Sup-multiset-def ) lemma Sup-multiset-unbounded: ¬subset-mset.bdd-above A =⇒ Sup A = {#} by (simp add: Sup-multiset-def ) instance .. end lemma bdd-above-multiset-imp-bdd-above-count: assumes subset-mset.bdd-above (A :: 0a multiset set) shows bdd-above ((λX . count X x) ‘A) proof − from assms obtain Y where Y : ∀ X ∈A. X ⊆# Y by (auto simp: subset-mset.bdd-above-def ) hence count X x ≤ count Y x if X ∈ A for X using that by (auto intro: mset-subset-eq-count) thus ?thesis by (intro bdd-aboveI [of - count Y x]) auto 163 qed lemma bdd-above-multiset-imp-finite-support: assumes A 6= {} subset-mset.bdd-above (A :: 0a multiset set) shows finite (S X ∈A. {x. count X x > 0 }) proof − from assms obtain Y where Y : ∀ X ∈A. X ⊆# Y by (auto simp: subset-mset.bdd-above-def ) hence count X x ≤ count Y x if X ∈ A for X x using that by (auto intro: mset-subset-eq-count) hence (S X ∈A. {x. count X x > 0 }) ⊆ {x. count Y x > 0 } by safe (erule less-le-trans) moreover have finite ... by simp ultimately show ?thesis by (rule finite-subset) qed lemma Sup-multiset-in-multiset: assumes A 6= {} subset-mset.bdd-above A shows (λi. SUP X :A. count X i) ∈ multiset unfolding multiset-def proof have {i. Sup ((λX . count X i) ‘A) > 0 } ⊆ (S X ∈A. {i. 0 < count X i}) proof safe fix i assume pos:(SUP X :A. count X i) > 0 show i ∈ (S X ∈A. {i. 0 < count X i}) proof (rule ccontr) assume i ∈/ (S X ∈A. {i. 0 < count X i}) hence ∀ X ∈A. count X i ≤ 0 by (auto simp: count-eq-zero-iff ) with assms have (SUP X :A. count X i) ≤ 0 by (intro cSup-least bdd-above-multiset-imp-bdd-above-count) auto with pos show False by simp qed qed moreover from assms have finite ... by (rule bdd-above-multiset-imp-finite-support) ultimately show finite {i. Sup ((λX . count X i) ‘A) > 0 } by (rule finite-subset) qed lemma count-Sup-multiset-nonempty: assumes A 6= {} subset-mset.bdd-above A shows count (Sup A) x = (SUP X :A. count X x) using assms by (simp add: Sup-multiset-def Abs-multiset-inverse Sup-multiset-in-multiset) interpretation subset-mset: conditionally-complete-lattice Inf Sup op ∩# op ⊆# op ⊂# op ∪# proof fix X :: 0a multiset and A assume X ∈ A show Inf A ⊆# X 164 proof (rule mset-subset-eqI ) fix x from hX ∈ Ai have A 6= {} by auto hence count (Inf A) x = (INF X :A. count X x) by (simp add: count-Inf-multiset-nonempty) also from hX ∈ Ai have ... ≤ count X x by (intro cInf-lower) simp-all finally show count (Inf A) x ≤ count X x . qed next fix X :: 0a multiset and A assume nonempty: A 6= {} and le: VY . Y ∈ A =⇒ X ⊆# Y show X ⊆# Inf A proof (rule mset-subset-eqI ) fix x from nonempty have count X x ≤ (INF X :A. count X x) by (intro cInf-greatest)(auto intro: mset-subset-eq-count le) also from nonempty have ... = count (Inf A) x by (simp add: count-Inf-multiset-nonempty) finally show count X x ≤ count (Inf A) x . qed next fix X :: 0a multiset and A assume X : X ∈ A and bdd: subset-mset.bdd-above A show X ⊆# Sup A proof (rule mset-subset-eqI ) fix x from X have A 6= {} by auto have count X x ≤ (SUP X :A. count X x) by (intro cSUP-upper X bdd-above-multiset-imp-bdd-above-count bdd) also from count-Sup-multiset-nonempty[OF hA 6= {}i bdd] have (SUP X :A. count X x) = count (Sup A) x by simp finally show count X x ≤ count (Sup A) x . qed next fix X :: 0a multiset and A assume nonempty: A 6= {} and ge: VY . Y ∈ A =⇒ Y ⊆# X from ge have bdd: subset-mset.bdd-above A by (rule subset-mset.bdd-aboveI [of -X ]) show Sup A ⊆# X proof (rule mset-subset-eqI ) fix x from count-Sup-multiset-nonempty[OF hA 6= {}i bdd] have count (Sup A) x = (SUP X :A. count X x) . also from nonempty have ... ≤ count X x by (intro cSup-least)(auto intro: mset-subset-eq-count ge) finally show count (Sup A) x ≤ count X x . qed qed 165 lemma set-mset-Inf : assumes A 6= {} shows set-mset (Inf A) = (T X ∈A. set-mset X ) proof safe fix x X assume x ∈# Inf A X ∈ A hence nonempty: A 6= {} by (auto simp: Inf-multiset-empty) from hx ∈# Inf Ai have {#x#} ⊆# Inf A by auto also from hX ∈ Ai have ... ⊆# X by (rule subset-mset.cInf-lower) simp-all finally show x ∈# X by simp next fix x assume x: x ∈ (T X ∈A. set-mset X ) hence {#x#} ⊆# X if X ∈ A for X using that by auto from assms and this have {#x#} ⊆# Inf A by (rule subset-mset.cInf-greatest) thus x ∈# Inf A by simp qed lemma in-Inf-multiset-iff : assumes A 6= {} shows x ∈# Inf A ←→ (∀ X ∈A. x ∈# X ) proof − from assms have set-mset (Inf A) = (T X ∈A. set-mset X ) by (rule set-mset-Inf ) also have x ∈ ... ←→ (∀ X ∈A. x ∈# X ) by simp finally show ?thesis . qed lemma in-Inf-multisetD: x ∈# Inf A =⇒ X ∈ A =⇒ x ∈# X by (subst (asm) in-Inf-multiset-iff ) auto lemma set-mset-Sup: assumes subset-mset.bdd-above A shows set-mset (Sup A) = (S X ∈A. set-mset X ) proof safe fix x assume x ∈# Sup A hence nonempty: A 6= {} by (auto simp: Sup-multiset-empty) show x ∈ (S X ∈A. set-mset X ) proof (rule ccontr) assume x: x ∈/ (S X ∈A. set-mset X ) have count X x ≤ count (Sup A) x if X ∈ A for X x using that by (intro mset-subset-eq-count subset-mset.cSup-upper assms) with x have X ⊆# Sup A − {#x#} if X ∈ A for X using that by (auto simp: subseteq-mset-def algebra-simps not-in-iff ) hence Sup A ⊆# Sup A − {#x#} by (intro subset-mset.cSup-least nonempty) with hx ∈# Sup Ai show False by (auto simp: subseteq-mset-def count-greater-zero-iff [symmetric] simp del: count-greater-zero-iff dest!: spec[of - x]) qed next fix x X assume x ∈ set-mset X X ∈ A hence {#x#} ⊆# X by auto 166 also have X ⊆# Sup A by (intro subset-mset.cSup-upper hX ∈ Ai assms) finally show x ∈ set-mset (Sup A) by simp qed lemma in-Sup-multiset-iff : assumes subset-mset.bdd-above A shows x ∈# Sup A ←→ (∃ X ∈A. x ∈# X ) proof − from assms have set-mset (Sup A) = (S X ∈A. set-mset X ) by (rule set-mset-Sup) also have x ∈ ... ←→ (∃ X ∈A. x ∈# X ) by simp finally show ?thesis . qed lemma in-Sup-multisetD: assumes x ∈# Sup A shows ∃ X ∈A. x ∈# X proof − have subset-mset.bdd-above A by (rule ccontr)(insert assms, simp-all add: Sup-multiset-unbounded) with assms show ?thesis by (simp add: in-Sup-multiset-iff ) qed interpretation subset-mset: distrib-lattice op ∩# op ⊆# op ⊂# op ∪# proof fix ABC :: 0a multiset show A ∪#(B ∩# C ) = A ∪# B ∩#(A ∪# C ) by (intro multiset-eqI ) simp-all qed 31.4.3 Filter (with comprehension syntax) Multiset comprehension lift-definition filter-mset :: ( 0a ⇒ bool) ⇒ 0a multiset ⇒ 0a multiset is λPM . λx. if P x then M x else 0 by (rule filter-preserves-multiset) syntax (ASCII ) -MCollect :: pttrn ⇒ 0a multiset ⇒ bool ⇒ 0a multiset ((1 {#- :# -./ -#})) syntax -MCollect :: pttrn ⇒ 0a multiset ⇒ bool ⇒ 0a multiset ((1 {#- ∈# -./ -#})) translations {#x ∈# M . P#} == CONST filter-mset (λx. P) M lemma count-filter-mset [simp]: count (filter-mset P M ) a = (if P a then count M a else 0 ) by (simp add: filter-mset.rep-eq) lemma set-mset-filter [simp]: set-mset (filter-mset P M ) = {a ∈ set-mset M . P a} 167 by (simp only: set-eq-iff count-greater-zero-iff [symmetric] count-filter-mset) simp lemma filter-empty-mset [simp]: filter-mset P {#} = {#} by (rule multiset-eqI ) simp lemma filter-single-mset: filter-mset P {#x#} = (if P x then {#x#} else {#}) by (rule multiset-eqI ) simp lemma filter-union-mset [simp]: filter-mset P (M + N ) = filter-mset P M + filter-mset P N by (rule multiset-eqI ) simp lemma filter-diff-mset [simp]: filter-mset P (M − N ) = filter-mset P M − filter-mset PN by (rule multiset-eqI ) simp lemma filter-inter-mset [simp]: filter-mset P (M ∩# N ) = filter-mset P M ∩# filter-mset P N by (rule multiset-eqI ) simp lemma filter-sup-mset[simp]: filter-mset P (A ∪# B) = filter-mset P A ∪# filter-mset PB by (rule multiset-eqI ) simp lemma filter-mset-add-mset [simp]: filter-mset P (add-mset x A) = (if P x then add-mset x (filter-mset P A) else filter-mset P A) by (auto simp: multiset-eq-iff ) lemma multiset-filter-subset[simp]: filter-mset f M ⊆# M by (simp add: mset-subset-eqI ) lemma multiset-filter-mono: assumes A ⊆# B shows filter-mset f A ⊆# filter-mset f B proof − from assms[unfolded mset-subset-eq-exists-conv] obtain C where B: B = A + C by auto show ?thesis unfolding B by auto qed lemma filter-mset-eq-conv: filter-mset P M = N ←→ N ⊆# M ∧ (∀ b∈#N . P b) ∧ (∀ a∈#M − N . ¬ P a) (is ?P ←→ ?Q) proof assume ?P then show ?Q by auto (simp add: multiset-eq-iff in-diff-count) next assume ?Q then obtain Q where M : M = N + Q 168 by (auto simp add: mset-subset-eq-exists-conv) then have MN : M − N = Q by simp show ?P proof (rule multiset-eqI ) fix a from h?Q i MN have ∗: ¬ P a =⇒ a ∈/# N P a =⇒ a ∈/# Q by auto show count (filter-mset P M ) a = count N a proof (cases a ∈# M ) case True with ∗ show ?thesis by (simp add: not-in-iff M ) next case False then have count M a = 0 by (simp add: not-in-iff ) with M show ?thesis by simp qed qed qed lemma filter-filter-mset: filter-mset P (filter-mset Q M ) = {#x ∈# M . Q x ∧ P x#} by (auto simp: multiset-eq-iff ) lemma filter-mset-True[simp]: {#y ∈# M . True#} = M and filter-mset-False[simp]: {#y ∈# M . False#} = {#} by (auto simp: multiset-eq-iff ) 31.4.4 Size definition wcount where wcount f M = (λx. count M x ∗ Suc (f x)) lemma wcount-union: wcount f (M + N ) a = wcount f M a + wcount f N a by (auto simp: wcount-def add-mult-distrib) lemma wcount-add-mset: wcount f (add-mset x M ) a = (if x = a then Suc (f a) else 0 ) + wcount f M a unfolding add-mset-add-single[of - M ] wcount-union by (auto simp: wcount-def ) definition size-multiset :: ( 0a ⇒ nat) ⇒ 0a multiset ⇒ nat where size-multiset f M = sum (wcount f M )(set-mset M ) lemmas size-multiset-eq = size-multiset-def [unfolded wcount-def ] instantiation multiset :: (type) size begin definition size-multiset where 169 size-multiset-overloaded-def : size-multiset = Multiset.size-multiset (λ-. 0 ) instance .. end lemmas size-multiset-overloaded-eq = size-multiset-overloaded-def [THEN fun-cong, unfolded size-multiset-eq, simplified] lemma size-multiset-empty [simp]: size-multiset f {#} = 0 by (simp add: size-multiset-def ) lemma size-empty [simp]: size {#} = 0 by (simp add: size-multiset-overloaded-def ) lemma size-multiset-single : size-multiset f {#b#} = Suc (f b) by (simp add: size-multiset-eq) lemma size-single: size {#b#} = 1 by (simp add: size-multiset-overloaded-def size-multiset-single) lemma sum-wcount-Int: finite A =⇒ sum (wcount f N )(A ∩ set-mset N ) = sum (wcount f N ) A by (induct rule: finite-induct) (simp-all add: Int-insert-left wcount-def count-eq-zero-iff ) lemma size-multiset-union [simp]: size-multiset f (M + N :: 0a multiset) = size-multiset f M + size-multiset f N apply (simp add: size-multiset-def sum-Un-nat sum.distrib sum-wcount-Int wcount-union) apply (subst Int-commute) apply (simp add: sum-wcount-Int) done lemma size-multiset-add-mset [simp]: size-multiset f (add-mset a M ) = Suc (f a) + size-multiset f M unfolding add-mset-add-single[of - M ] size-multiset-union by (auto simp: size-multiset-single) lemma size-add-mset [simp]: size (add-mset a A) = Suc (size A) by (simp add: size-multiset-overloaded-def wcount-add-mset) lemma size-union [simp]: size (M + N :: 0a multiset) = size M + size N by (auto simp add: size-multiset-overloaded-def ) lemma size-multiset-eq-0-iff-empty [iff ]: size-multiset f M = 0 ←→ M = {#} by (auto simp add: size-multiset-eq count-eq-zero-iff ) lemma size-eq-0-iff-empty [iff ]: (size M = 0 ) = (M = {#}) by (auto simp add: size-multiset-overloaded-def ) 170 lemma nonempty-has-size:(S 6= {#}) = (0 < size S) by (metis gr0I gr-implies-not0 size-empty size-eq-0-iff-empty) lemma size-eq-Suc-imp-elem: size M = Suc n =⇒ ∃ a. a ∈# M apply (unfold size-multiset-overloaded-eq) apply (drule sum-SucD) apply auto done lemma size-eq-Suc-imp-eq-union: assumes size M = Suc n shows ∃ a N . M = add-mset a N proof − from assms obtain a where a ∈# M by (erule size-eq-Suc-imp-elem [THEN exE]) then have M = add-mset a (M − {#a#}) by simp then show ?thesis by blast qed lemma size-mset-mono: fixes AB :: 0a multiset assumes A ⊆# B shows size A ≤ size B proof − from assms[unfolded mset-subset-eq-exists-conv] obtain C where B: B = A + C by auto show ?thesis unfolding B by (induct C ) auto qed lemma size-filter-mset-lesseq[simp]: size (filter-mset f M ) ≤ size M by (rule size-mset-mono[OF multiset-filter-subset]) lemma size-Diff-submset: M ⊆# M 0 =⇒ size (M 0 − M ) = size M 0 − size(M :: 0a multiset) by (metis add-diff-cancel-left 0 size-union mset-subset-eq-exists-conv) 31.5 Induction and case splits theorem multiset-induct [case-names empty add, induct type: multiset]: assumes empty: P {#} assumes add: Vx M . PM =⇒ P (add-mset x M ) shows PM proof (induct n ≡ size M arbitrary: M ) case 0 thus PM by (simp add: empty) next case (Suc k) obtain N x where M = add-mset x N using hSuc k = size M i [symmetric] using size-eq-Suc-imp-eq-union by fast 171 with Suc add show PM by simp qed lemma multi-nonempty-split: M 6= {#} =⇒ ∃ A a. M = add-mset a A by (induct M ) auto lemma multiset-cases [cases type]: obtains (empty) M = {#} | (add) x N where M = add-mset x N by (induct M ) simp-all lemma multi-drop-mem-not-eq: c ∈# B =⇒ B − {#c#}= 6 B by (cases B = {#})(auto dest: multi-member-split) lemma multiset-partition: M = {# x∈#M . P x #} + {# x∈#M . ¬ P x #} apply (subst multiset-eq-iff ) apply auto done lemma mset-subset-size:(A:: 0a multiset) ⊂# B =⇒ size A < size B proof (induct A arbitrary: B) case (empty M ) then have M 6= {#} by (simp add: subset-mset.zero-less-iff-neq-zero) then obtain M 0 x where M = add-mset x M 0 by (blast dest: multi-nonempty-split) then show ?case by simp next case (add x S T ) have IH : VB. S ⊂# B =⇒ size S < size B by fact have SxsubT : add-mset x S ⊂# T by fact then have x ∈# T and S ⊂# T by (auto dest: mset-subset-insertD) then obtain T 0 where T : T = add-mset x T 0 by (blast dest: multi-member-split) then have S ⊂# T 0 using SxsubT by simp then have size S < size T 0 using IH by simp then show ?case using T by simp qed lemma size-1-singleton-mset: size M = 1 =⇒ ∃ a. M = {#a#} by (cases M ) auto 31.5.1 Strong induction and subset induction for multisets Well-foundedness of strict subset relation lemma wf-subset-mset-rel: wf {(M , N :: 0a multiset). M ⊂# N } apply (rule wf-measure [THEN wf-subset, where f1 =size]) apply (clarsimp simp: measure-def inv-image-def mset-subset-size) 172 done lemma full-multiset-induct [case-names less]: assumes ih: VB. ∀ (A:: 0a multiset). A ⊂# B −→ PA =⇒ PB shows PB apply (rule wf-subset-mset-rel [THEN wf-induct]) apply (rule ih, auto) done lemma multi-subset-induct [consumes 2 , case-names empty add]: assumes F ⊆# A and empty: P {#} and insert: Va F . a ∈# A =⇒ PF =⇒ P (add-mset a F ) shows PF proof − from hF ⊆# Ai show ?thesis proof (induct F ) show P {#} by fact next fix x F assume P: F ⊆# A =⇒ PF and i: add-mset x F ⊆# A show P (add-mset x F ) proof (rule insert) from i show x ∈# A by (auto dest: mset-subset-eq-insertD) from i have F ⊆# A by (auto dest: mset-subset-eq-insertD) with P show PF . qed qed qed 31.6 The fold combinator definition fold-mset :: ( 0a ⇒ 0b ⇒ 0b) ⇒ 0b ⇒ 0a multiset ⇒ 0b where fold-mset f s M = Finite-Set.fold (λx. f x ˆˆ count M x) s (set-mset M ) lemma fold-mset-empty [simp]: fold-mset f s {#} = s by (simp add: fold-mset-def ) context comp-fun-commute begin lemma fold-mset-add-mset [simp]: fold-mset f s (add-mset x M ) = f x (fold-mset f s M ) proof − interpret mset: comp-fun-commute λy. f y ˆˆ count M y by (fact comp-fun-commute-funpow) interpret mset-union: comp-fun-commute λy. f y ˆˆ count (add-mset x M ) y 173 by (fact comp-fun-commute-funpow) show ?thesis proof (cases x ∈ set-mset M ) case False then have ∗: count (add-mset x M ) x = 1 by (simp add: not-in-iff ) from False have Finite-Set.fold (λy. f y ˆˆ count (add-mset x M ) y) s (set-mset M ) = Finite-Set.fold (λy. f y ˆˆ count M y) s (set-mset M ) by (auto intro!: Finite-Set.fold-cong comp-fun-commute-funpow) with False ∗ show ?thesis by (simp add: fold-mset-def del: count-add-mset) next case True define N where N = set-mset M − {x} from N-def True have ∗: set-mset M = insert x N x ∈/ N finite N by auto then have Finite-Set.fold (λy. f y ˆˆ count (add-mset x M ) y) s N = Finite-Set.fold (λy. f y ˆˆ count M y) s N by (auto intro!: Finite-Set.fold-cong comp-fun-commute-funpow) with ∗ show ?thesis by (simp add: fold-mset-def del: count-add-mset) simp qed qed corollary fold-mset-single: fold-mset f s {#x#} = f x s by simp lemma fold-mset-fun-left-comm: f x (fold-mset f s M ) = fold-mset f (f x s) M by (induct M )(simp-all add: fun-left-comm) lemma fold-mset-union [simp]: fold-mset f s (M + N ) = fold-mset f (fold-mset f s M ) N by (induct M )(simp-all add: fold-mset-fun-left-comm) lemma fold-mset-fusion: assumes comp-fun-commute g and ∗: Vx y. h (g x y) = f x (h y) shows h (fold-mset g w A) = fold-mset f (h w) A proof − interpret comp-fun-commute g by (fact assms) from ∗ show ?thesis by (induct A) auto qed end lemma union-fold-mset-add-mset: A + B = fold-mset add-mset A B proof − interpret comp-fun-commute add-mset by standard auto show ?thesis 174 by (induction B) auto qed A note on code generation: When defining some function containing a sub- term fold-mset F, code generation is not automatic. When interpreting locale left-commutative with F, the would be code thms for fold-mset be- come thms like fold-mset F z {#} = z where F is not a pattern but contains defined symbols, i.e. is not a code thm. Hence a separate constant with its own code thms needs to be introduced for F. See the image operator below. 31.7 Image definition image-mset :: ( 0a ⇒ 0b) ⇒ 0a multiset ⇒ 0b multiset where image-mset f = fold-mset (add-mset ◦ f ) {#} lemma comp-fun-commute-mset-image: comp-fun-commute (add-mset ◦ f ) proof qed (simp add: fun-eq-iff ) lemma image-mset-empty [simp]: image-mset f {#} = {#} by (simp add: image-mset-def ) lemma image-mset-single: image-mset f {#x#} = {#f x#} proof − interpret comp-fun-commute add-mset ◦ f by (fact comp-fun-commute-mset-image) show ?thesis by (simp add: image-mset-def ) qed lemma image-mset-union [simp]: image-mset f (M + N ) = image-mset f M + image-mset f N proof − interpret comp-fun-commute add-mset ◦ f by (fact comp-fun-commute-mset-image) show ?thesis by (induct N )(simp-all add: image-mset-def ) qed corollary image-mset-add-mset [simp]: image-mset f (add-mset a M ) = add-mset (f a)(image-mset f M ) unfolding image-mset-union add-mset-add-single[of a M ] by (simp add: image-mset-single) lemma set-image-mset [simp]: set-mset (image-mset f M ) = image f (set-mset M ) by (induct M ) simp-all lemma size-image-mset [simp]: size (image-mset f M ) = size M by (induct M ) simp-all lemma image-mset-is-empty-iff [simp]: image-mset f M = {#} ←→ M = {#} 175 by (cases M ) auto lemma image-mset-If : image-mset (λx. if P x then f x else g x) A = image-mset f (filter-mset P A) + image-mset g (filter-mset (λx. ¬P x) A) by (induction A) auto lemma image-mset-Diff : assumes B ⊆# A shows image-mset f (A − B) = image-mset f A − image-mset f B proof − have image-mset f (A − B + B) = image-mset f (A − B) + image-mset f B by simp also from assms have A − B + B = A by (simp add: subset-mset.diff-add) finally show ?thesis by simp qed lemma count-image-mset: count (image-mset f A) x = (P y∈f −‘ {x} ∩ set-mset A. count A y) proof (induction A) case empty then show ?case by simp next case (add x A) moreover have ∗:(if x = y then Suc n else n) = n + (if x = y then 1 else 0 ) for n y by simp ultimately show ?case by (auto simp: sum.distrib sum.delta 0 intro!: sum.mono-neutral-left) qed lemma image-mset-subseteq-mono: A ⊆# B =⇒ image-mset f A ⊆# image-mset f B by (metis image-mset-union subset-mset.le-iff-add) syntax (ASCII ) -comprehension-mset :: 0a ⇒ 0b ⇒ 0b multiset ⇒ 0a multiset (({#-/. - :# -#})) syntax -comprehension-mset :: 0a ⇒ 0b ⇒ 0b multiset ⇒ 0a multiset (({#-/. - ∈# -#})) translations {#e. x ∈# M #} CONST image-mset (λx. e) M syntax (ASCII ) -comprehension-mset 0 :: 0a ⇒ 0b ⇒ 0b multiset ⇒ bool ⇒ 0a multiset (({#-/ | - :# -./ -#})) syntax -comprehension-mset 0 :: 0a ⇒ 0b ⇒ 0b multiset ⇒ bool ⇒ 0a multiset (({#-/ | - ∈# -./ -#})) 176 translations {#e | x∈#M . P#} * {#e. x ∈# {# x∈#M . P#}#} This allows to write not just filters like {#x ∈# M . x < c#} but also images like {#x + x. x ∈# M #} and {#x+x|x∈#M . x 31.8 Further conversions primrec mset :: 0a list ⇒ 0a multiset where mset [] = {#} | mset (a # x) = add-mset a (mset x) lemma in-multiset-in-set: x ∈# mset xs ←→ x ∈ set xs 177 by (induct xs) simp-all lemma count-mset: count (mset xs) x = length (filter (λy. x = y) xs) by (induct xs) simp-all lemma mset-zero-iff [simp]: (mset x = {#}) = (x = []) by (induct x) auto lemma mset-zero-iff-right[simp]: ({#} = mset x) = (x = []) by (induct x) auto lemma mset-single-iff [iff ]: mset xs = {#x#} ←→ xs = [x] by (cases xs) auto lemma mset-single-iff-right[iff ]: {#x#} = mset xs ←→ xs = [x] by (cases xs) auto lemma set-mset-mset[simp]: set-mset (mset xs) = set xs by (induct xs) auto lemma set-mset-comp-mset [simp]: set-mset ◦ mset = set by (simp add: fun-eq-iff ) lemma size-mset [simp]: size (mset xs) = length xs by (induct xs) simp-all lemma mset-append [simp]: mset (xs @ ys) = mset xs + mset ys by (induct xs arbitrary: ys) auto lemma mset-filter: mset (filter P xs) = {#x ∈# mset xs. P x #} by (induct xs) simp-all lemma mset-rev [simp]: mset (rev xs) = mset xs by (induct xs) simp-all lemma surj-mset: surj mset apply (unfold surj-def ) apply (rule allI ) apply (rule-tac M = y in multiset-induct) apply auto apply (rule-tac x = x # xa in exI ) apply auto done lemma distinct-count-atmost-1 : distinct x = (∀ a. count (mset x) a = (if a ∈ set x then 1 else 0 )) proof (induct x) 178 case Nil then show ?case by simp next case (Cons x xs) show ?case (is ?lhs ←→ ?rhs) proof assume ?lhs then show ?rhs using Cons by simp next assume ?rhs then have x ∈/ set xs by (simp split: if-splits) moreover from h?rhs i have (∀ a. count (mset xs) a = (if a ∈ set xs then 1 else 0 )) by (auto split: if-splits simp add: count-eq-zero-iff ) ultimately show ?lhs using Cons by simp qed qed lemma mset-eq-setD: assumes mset xs = mset ys shows set xs = set ys proof − from assms have set-mset (mset xs) = set-mset (mset ys) by simp then show ?thesis by simp qed lemma set-eq-iff-mset-eq-distinct: distinct x =⇒ distinct y =⇒ (set x = set y) = (mset x = mset y) by (auto simp: multiset-eq-iff distinct-count-atmost-1 ) lemma set-eq-iff-mset-remdups-eq: (set x = set y) = (mset (remdups x) = mset (remdups y)) apply (rule iffI ) apply (simp add: set-eq-iff-mset-eq-distinct[THEN iffD1 ]) apply (drule distinct-remdups [THEN distinct-remdups [THEN set-eq-iff-mset-eq-distinct [THEN iffD2 ]]]) apply simp done lemma mset-compl-union [simp]: mset [x←xs. P x] + mset [x←xs. ¬P x] = mset xs by (induct xs) auto lemma nth-mem-mset: i < length ls =⇒ (ls ! i) ∈# mset ls proof (induct ls arbitrary: i) case Nil then show ?case by simp next case Cons then show ?case by (cases i) auto 179 qed lemma mset-remove1 [simp]: mset (remove1 a xs) = mset xs − {#a#} by (induct xs)(auto simp add: multiset-eq-iff ) lemma mset-eq-length: assumes mset xs = mset ys shows length xs = length ys using assms by (metis size-mset) lemma mset-eq-length-filter: assumes mset xs = mset ys shows length (filter (λx. z = x) xs) = length (filter (λy. z = y) ys) using assms by (metis count-mset) lemma fold-multiset-equiv: assumes f : Vx y. x ∈ set xs =⇒ y ∈ set xs =⇒ f x ◦ f y = f y ◦ f x and equiv: mset xs = mset ys shows List.fold f xs = List.fold f ys using f equiv [symmetric] proof (induct xs arbitrary: ys) case Nil then show ?case by simp next case (Cons x xs) then have ∗: set ys = set (x # xs) by (blast dest: mset-eq-setD) have Vx y. x ∈ set ys =⇒ y ∈ set ys =⇒ f x ◦ f y = f y ◦ f x by (rule Cons.prems(1 )) (simp-all add: ∗) moreover from ∗ have x ∈ set ys by simp ultimately have List.fold f ys = List.fold f (remove1 x ys) ◦ f x by (fact fold-remove1-split) moreover from Cons.prems have List.fold f xs = List.fold f (remove1 x ys) by (auto intro: Cons.hyps) ultimately show ?case by simp qed lemma mset-insort [simp]: mset (insort x xs) = add-mset x (mset xs) by (induct xs) simp-all lemma mset-map[simp]: mset (map f xs) = image-mset f (mset xs) by (induct xs) simp-all global-interpretation mset-set: folding add-mset {#} defines mset-set = folding.F add-mset {#} by standard (simp add: fun-eq-iff ) lemma count-mset-set [simp]: 180 finite A =⇒ x ∈ A =⇒ count (mset-set A) x = 1 (is PROP ?P) ¬ finite A =⇒ count (mset-set A) x = 0 (is PROP ?Q) x ∈/ A =⇒ count (mset-set A) x = 0 (is PROP ?R) proof − have ∗: count (mset-set A) x = 0 if x ∈/ A for A proof (cases finite A) case False then show ?thesis by simp next case True from True hx ∈/ Ai show ?thesis by (induct A) auto qed then show PROP ?P PROP ?Q PROP ?R by (auto elim!: Set.set-insert) qed — TODO: maybe define mset-set also in terms of Abs-multiset lemma elem-mset-set[simp, intro]: finite A =⇒ x ∈# mset-set A ←→ x ∈ A by (induct A rule: finite-induct) simp-all lemma mset-set-Union: finite A =⇒ finite B =⇒ A ∩ B = {} =⇒ mset-set (A ∪ B) = mset-set A + mset-set B by (induction A rule: finite-induct) auto lemma filter-mset-mset-set [simp]: finite A =⇒ filter-mset P (mset-set A) = mset-set {x∈A. P x} proof (induction A rule: finite-induct) case (insert x A) from insert.hyps have filter-mset P (mset-set (insert x A)) = filter-mset P (mset-set A) + mset-set (if P x then {x} else {}) by simp also have filter-mset P (mset-set A) = mset-set {x∈A. P x} by (rule insert.IH ) also from insert.hyps have ... + mset-set (if P x then {x} else {}) = mset-set ({x ∈ A. P x} ∪ (if P x then {x} else {})) (is - = mset-set ?A) by (intro mset-set-Union [symmetric]) simp-all also from insert.hyps have ?A = {y∈insert x A. P y} by auto finally show ?case . qed simp-all lemma mset-set-Diff : assumes finite A B ⊆ A shows mset-set (A − B) = mset-set A − mset-set B proof − from assms have mset-set ((A − B) ∪ B) = mset-set (A − B) + mset-set B by (intro mset-set-Union)(auto dest: finite-subset) also from assms have A − B ∪ B = A by blast finally show ?thesis by simp qed 181 lemma mset-set-set: distinct xs =⇒ mset-set (set xs) = mset xs by (induction xs) simp-all context linorder begin definition sorted-list-of-multiset :: 0a multiset ⇒ 0a list where sorted-list-of-multiset M = fold-mset insort [] M lemma sorted-list-of-multiset-empty [simp]: sorted-list-of-multiset {#} = [] by (simp add: sorted-list-of-multiset-def ) lemma sorted-list-of-multiset-singleton [simp]: sorted-list-of-multiset {#x#} = [x] proof − interpret comp-fun-commute insort by (fact comp-fun-commute-insort) show ?thesis by (simp add: sorted-list-of-multiset-def ) qed lemma sorted-list-of-multiset-insert [simp]: sorted-list-of-multiset (add-mset x M ) = List.insort x (sorted-list-of-multiset M ) proof − interpret comp-fun-commute insort by (fact comp-fun-commute-insort) show ?thesis by (simp add: sorted-list-of-multiset-def ) qed end lemma mset-sorted-list-of-multiset [simp]: mset (sorted-list-of-multiset M ) = M by (induct M ) simp-all lemma sorted-list-of-multiset-mset [simp]: sorted-list-of-multiset (mset xs) = sort xs by (induct xs) simp-all lemma finite-set-mset-mset-set[simp]: finite A =⇒ set-mset (mset-set A) = A by (induct A rule: finite-induct) simp-all lemma mset-set-empty-iff : mset-set A = {#} ←→ A = {} ∨ infinite A using finite-set-mset-mset-set by fastforce lemma infinite-set-mset-mset-set: ¬ finite A =⇒ set-mset (mset-set A) = {} by simp 182 lemma set-sorted-list-of-multiset [simp]: set (sorted-list-of-multiset M ) = set-mset M by (induct M )(simp-all add: set-insort) lemma sorted-list-of-mset-set [simp]: sorted-list-of-multiset (mset-set A) = sorted-list-of-set A by (cases finite A)(induct A rule: finite-induct, simp-all) lemma mset-upt [simp]: mset [m.. 31.9 More properties of the replicate and repeat operations lemma in-replicate-mset[simp]: x ∈# replicate-mset n y ←→ n > 0 ∧ x = y unfolding replicate-mset-def by (induct n) auto lemma set-mset-replicate-mset-subset[simp]: set-mset (replicate-mset n x) = (if n = 0 then {} else {x}) 183 by (auto split: if-splits) lemma size-replicate-mset[simp]: size (replicate-mset n M ) = n by (induct n, simp-all) lemma count-le-replicate-mset-subset-eq: n ≤ count M x ←→ replicate-mset n x ⊆# M by (auto simp add: mset-subset-eqI )(metis count-replicate-mset subseteq-mset-def ) lemma filter-eq-replicate-mset: {#y ∈# D. y = x#} = replicate-mset (count D x) x by (induct D) simp-all lemma replicate-count-mset-eq-filter-eq: replicate (count (mset xs) k) k = filter (HOL.eq k) xs by (induct xs) auto lemma replicate-mset-eq-empty-iff [simp]: replicate-mset n a = {#} ←→ n = 0 by (induct n) simp-all lemma replicate-mset-eq-iff : replicate-mset m a = replicate-mset n b ←→ m = 0 ∧ n = 0 ∨ m = n ∧ a = b by (auto simp add: multiset-eq-iff ) lemma repeat-mset-cancel1 : repeat-mset a A = repeat-mset a B ←→ A = B ∨ a = 0 by (auto simp: multiset-eq-iff ) lemma repeat-mset-cancel2 : repeat-mset a A = repeat-mset b A ←→ a = b ∨ A = {#} by (auto simp: multiset-eq-iff ) lemma repeat-mset-eq-empty-iff : repeat-mset n A = {#} ←→ n = 0 ∨ A = {#} by (cases n) auto lemma image-replicate-mset [simp]: image-mset f (replicate-mset n a) = replicate-mset n (f a) by (induct n) simp-all 31.10 Big operators locale comm-monoid-mset = comm-monoid begin interpretation comp-fun-commute f by standard (simp add: fun-eq-iff left-commute) 184 interpretation comp?: comp-fun-commute f ◦ g by (fact comp-comp-fun-commute) context begin definition F :: 0a multiset ⇒ 0a where eq-fold: FM = fold-mset f 1 M lemma empty [simp]: F {#} = 1 by (simp add: eq-fold) lemma singleton [simp]: F {#x#} = x proof − interpret comp-fun-commute by standard (simp add: fun-eq-iff left-commute) show ?thesis by (simp add: eq-fold) qed lemma union [simp]: F (M + N ) = FM ∗ FN proof − interpret comp-fun-commute f by standard (simp add: fun-eq-iff left-commute) show ?thesis by (induct N )(simp-all add: left-commute eq-fold) qed lemma add-mset [simp]: F (add-mset x N ) = x ∗ FN unfolding add-mset-add-single[of x N ] union by (simp add: ac-simps) lemma insert [simp]: shows F (image-mset g (add-mset x A)) = g x ∗ F (image-mset g A) by (simp add: eq-fold) lemma remove: assumes x ∈# A shows FA = x ∗ F (A − {#x#}) using multi-member-split[OF assms] by auto lemma neutral: ∀ x∈#A. x = 1 =⇒ FA = 1 by (induct A) simp-all lemma neutral-const [simp]: F (image-mset (λ-. 1) A) = 1 by (simp add: neutral) private lemma F-image-mset-product: F {#g x j ∗ F {#g i j . i ∈# A#}. j ∈# B#} = 185 F (image-mset (g x) B) ∗ F {#F {#g i j . i ∈# A#}. j ∈# B#} by (induction B)(simp-all add: left-commute semigroup.assoc semigroup-axioms) lemma commute: F (image-mset (λi. F (image-mset (g i) B)) A) = F (image-mset (λj . F (image-mset (λi. g i j ) A)) B) apply (induction A, simp) apply (induction B, auto simp add: F-image-mset-product ac-simps) done lemma distrib: F (image-mset (λx. g x ∗ h x) A) = F (image-mset g A) ∗ F (image-mset h A) by (induction A)(auto simp: ac-simps) lemma union-disjoint: A ∩# B = {#} =⇒ F (image-mset g (A ∪# B)) = F (image-mset g A) ∗ F (image-mset g B) by (induction A)(auto simp: ac-simps) end end lemma comp-fun-commute-plus-mset[simp]: comp-fun-commute (op + :: 0a multi- set ⇒ - ⇒ -) by standard (simp add: add-ac comp-def ) declare comp-fun-commute.fold-mset-add-mset[OF comp-fun-commute-plus-mset, simp] lemma in-mset-fold-plus-iff [iff ]: x ∈# fold-mset (op +) M NN ←→ x ∈# M ∨ (∃ N . N ∈# NN ∧ x ∈# N ) by (induct NN ) auto context comm-monoid-add begin sublocale sum-mset: comm-monoid-mset plus 0 defines sum-mset = sum-mset.F .. lemma (in semiring-1 ) sum-mset-replicate-mset [simp]: sum-mset (replicate-mset n a) = of-nat n ∗ a by (induct n)(simp-all add: algebra-simps) lemma sum-unfold-sum-mset: sum f A = sum-mset (image-mset f (mset-set A)) by (cases finite A)(induct A rule: finite-induct, simp-all) lemma sum-mset-delta: sum-mset (image-mset (λx. if x = y then c else 0 ) A) = c ∗ count A y 186 by (induction A) simp-all lemma sum-mset-delta 0: sum-mset (image-mset (λx. if y = x then c else 0 ) A) = c ∗ count A y by (induction A) simp-all end lemma of-nat-sum-mset [simp]: of-nat (sum-mset M ) = sum-mset (image-mset of-nat M ) by (induction M ) auto lemma sum-mset-0-iff [simp]: sum-mset M = (0 :: 0a::canonically-ordered-monoid-add) ←→ (∀ x ∈ set-mset M . x = 0 ) by(induction M ) auto lemma sum-mset-diff : fixes MN :: ( 0a :: ordered-cancel-comm-monoid-diff ) multiset shows N ⊆# M =⇒ sum-mset (M − N ) = sum-mset M − sum-mset N by (metis add-diff-cancel-right 0 sum-mset.union subset-mset.diff-add) lemma size-eq-sum-mset: size M = sum-mset (image-mset (λ-. 1 ) M ) proof (induct M ) case empty then show ?case by simp next case (add x M ) then show ?case by (cases x ∈ set-mset M ) (simp-all add: size-multiset-overloaded-eq not-in-iff sum.If-cases Diff-eq[symmetric] sum.remove) qed lemma size-mset-set [simp]: size (mset-set A) = card A by (simp only: size-eq-sum-mset card-eq-sum sum-unfold-sum-mset) lemma sum-mset-sum-list: sum-mset (mset xs) = sum-list xs by (induction xs) auto syntax (ASCII ) -sum-mset-image :: pttrn ⇒ 0b set ⇒ 0a ⇒ 0a::comm-monoid-add ((3SUM -:#-. -)[0 , 51 , 10 ] 10 ) syntax -sum-mset-image :: pttrn ⇒ 0b set ⇒ 0a ⇒ 0a::comm-monoid-add ((3 P -∈#-. -)[0 , 51 , 10 ] 10 ) translations P i ∈# A. b CONST sum-mset (CONST image-mset (λi. b) A) lemma sum-mset-distrib-left: fixes f :: 0a ⇒ 0b::semiring-0 187 shows c ∗ (P x ∈# M . f x) = (P x ∈# M . c ∗ f (x)) by (induction M )(simp-all add: distrib-left) lemma sum-mset-distrib-right: fixes f :: 0a ⇒ 0b::semiring-0 shows (P b ∈# B. f b) ∗ a = (P b ∈# B. f b ∗ a) by (induction B)(auto simp: distrib-right) lemma sum-mset-constant [simp]: fixes y :: 0b::semiring-1 shows h(P x∈#A. y) = of-nat (size A) ∗ y i by (induction A)(auto simp: algebra-simps) lemma (in ordered-comm-monoid-add) sum-mset-mono: assumes Vi. i ∈# K =⇒ f i ≤ g i shows sum-mset (image-mset f K ) ≤ sum-mset (image-mset g K ) using assms by (induction K )(simp-all add: local.add-mono) lemma sum-mset-product: fixes f :: 0a::{comm-monoid-add,times} ⇒ 0b::semiring-0 shows (P i ∈# A. f i) ∗ (P i ∈# B. g i) = (P i∈#A. P j ∈#B. f i ∗ g j ) by (subst sum-mset.commute)(simp add: sum-mset-distrib-left sum-mset-distrib-right) abbreviation Union-mset :: 0a multiset multiset ⇒ 0a multiset (S #- [900 ] 900 ) where S # MM ≡ sum-mset MM — FIXME ambiguous notation – could likewise refer to F # lemma set-mset-Union-mset[simp]: set-mset (S # MM ) = (S M ∈ set-mset MM . set-mset M ) by (induct MM ) auto lemma in-Union-mset-iff [iff ]: x ∈# S # MM ←→ (∃ M . M ∈# MM ∧ x ∈# M ) by (induct MM ) auto lemma count-sum: count (sum f A) x = sum (λa. count (f a) x) A by (induct A rule: infinite-finite-induct) simp-all lemma sum-eq-empty-iff : assumes finite A shows sum f A = {#} ←→ (∀ a∈A. f a = {#}) using assms by induct simp-all lemma Union-mset-empty-conv[simp]: S # M = {#} ←→ (∀ i∈#M . i = {#}) by (induction M ) auto context comm-monoid-mult begin 188 sublocale prod-mset: comm-monoid-mset times 1 defines prod-mset = prod-mset.F .. lemma prod-mset-empty: prod-mset {#} = 1 by (fact prod-mset.empty) lemma prod-mset-singleton: prod-mset {#x#} = x by (fact prod-mset.singleton) lemma prod-mset-Un: prod-mset (A + B) = prod-mset A ∗ prod-mset B by (fact prod-mset.union) lemma prod-mset-replicate-mset [simp]: prod-mset (replicate-mset n a) = a ˆ n by (induct n) simp-all lemma prod-unfold-prod-mset: prod f A = prod-mset (image-mset f (mset-set A)) by (cases finite A)(induct A rule: finite-induct, simp-all) lemma prod-mset-multiplicity: prod-mset M = prod (λx. x ˆ count M x)(set-mset M ) by (simp add: fold-mset-def prod.eq-fold prod-mset.eq-fold funpow-times-power comp-def ) lemma prod-mset-delta: prod-mset (image-mset (λx. if x = y then c else 1 ) A) = c ˆ count A y by (induction A) simp-all lemma prod-mset-delta 0: prod-mset (image-mset (λx. if y = x then c else 1 ) A) = c ˆ count A y by (induction A) simp-all end syntax (ASCII ) -prod-mset-image :: pttrn ⇒ 0b set ⇒ 0a ⇒ 0a::comm-monoid-mult ((3PROD -:#-. -)[0 , 51 , 10 ] 10 ) syntax -prod-mset-image :: pttrn ⇒ 0b set ⇒ 0a ⇒ 0a::comm-monoid-mult ((3 Q -∈#-. -)[0 , 51 , 10 ] 10 ) translations Q i ∈# A. b CONST prod-mset (CONST image-mset (λi. b) A) lemma (in comm-monoid-mult) prod-mset-subset-imp-dvd: 189 assumes A ⊆# B shows prod-mset A dvd prod-mset B proof − from assms have B = (B − A) + A by (simp add: subset-mset.diff-add) also have prod-mset ... = prod-mset (B − A) ∗ prod-mset A by simp also have prod-mset A dvd ... by simp finally show ?thesis . qed lemma (in comm-monoid-mult) dvd-prod-mset: assumes x ∈# A shows x dvd prod-mset A using assms prod-mset-subset-imp-dvd [of {#x#} A] by simp lemma (in semidom) prod-mset-zero-iff [iff ]: prod-mset A = 0 ←→ 0 ∈# A by (induct A) auto lemma (in semidom-divide) prod-mset-diff : assumes B ⊆# A and 0 ∈/# B shows prod-mset (A − B) = prod-mset A div prod-mset B proof − from assms obtain C where A = B + C by (metis subset-mset.add-diff-inverse) with assms show ?thesis by simp qed lemma (in semidom-divide) prod-mset-minus: assumes a ∈# A and a 6= 0 shows prod-mset (A − {#a#}) = prod-mset A div a using assms prod-mset-diff [of {#a#} A] by auto lemma (in algebraic-semidom) is-unit-prod-mset-iff : is-unit (prod-mset A) ←→ (∀ x ∈# A. is-unit x) by (induct A)(auto simp: is-unit-mult-iff ) lemma (in normalization-semidom) normalize-prod-mset: normalize (prod-mset A) = prod-mset (image-mset normalize A) by (induct A)(simp-all add: normalize-mult) lemma (in normalization-semidom) normalized-prod-msetI : assumes Va. a ∈# A =⇒ normalize a = a shows normalize (prod-mset A) = prod-mset A proof − from assms have image-mset normalize A = A by (induct A) simp-all then show ?thesis by (simp add: normalize-prod-mset) qed 190 lemma prod-mset-prod-list: prod-mset (mset xs) = prod-list xs by (induct xs) auto 31.11 Alternative representations 31.11.1 Lists context linorder begin lemma mset-insort [simp]: mset (insort-key k x xs) = add-mset x (mset xs) by (induct xs) simp-all lemma mset-sort [simp]: mset (sort-key k xs) = mset xs by (induct xs) simp-all This lemma shows which properties suffice to show that a function f with f xs = ys behaves like sort. lemma properties-for-sort-key: assumes mset ys = mset xs and Vk. k ∈ set ys =⇒ filter (λx. f k = f x) ys = filter (λx. f k = f x) xs and sorted (map f ys) shows sort-key f xs = ys using assms proof (induct xs arbitrary: ys) case Nil then show ?case by simp next case (Cons x xs) from Cons.prems(2 ) have ∀ k ∈ set ys. filter (λx. f k = f x)(remove1 x ys) = filter (λx. f k = f x) xs by (simp add: filter-remove1 ) with Cons.prems have sort-key f xs = remove1 x ys by (auto intro!: Cons.hyps simp add: sorted-map-remove1 ) moreover from Cons.prems have x ∈# mset ys by auto then have x ∈ set ys by simp ultimately show ?case using Cons.prems by (simp add: insort-key-remove1 ) qed lemma properties-for-sort: assumes multiset: mset ys = mset xs and sorted ys shows sort xs = ys proof (rule properties-for-sort-key) from multiset show mset ys = mset xs . from hsorted ys i show sorted (map (λx. x) ys) by simp 191 from multiset have length (filter (λy. k = y) ys) = length (filter (λx. k = x) xs) for k by (rule mset-eq-length-filter) then have replicate (length (filter (λy. k = y) ys)) k = replicate (length (filter (λx. k = x) xs)) k for k by simp then show k ∈ set ys =⇒ filter (λy. k = y) ys = filter (λx. k = x) xs for k by (simp add: replicate-length-filter) qed lemma sort-key-inj-key-eq: assumes mset-equal: mset xs = mset ys and inj-on f (set xs) and sorted (map f ys) shows sort-key f xs = ys proof (rule properties-for-sort-key) from mset-equal show mset ys = mset xs by simp from hsorted (map f ys)i show sorted (map f ys) . show [x←ys . f k = f x] = [x←xs . f k = f x] if k ∈ set ys for k proof − from mset-equal have set-equal: set xs = set ys by (rule mset-eq-setD) with that have insert k (set ys) = set ys by auto with hinj-on f (set xs)i have inj : inj-on f (insert k (set ys)) by (simp add: set-equal) from inj have [x←ys . f k = f x] = filter (HOL.eq k) ys by (auto intro!: inj-on-filter-key-eq) also have ... = replicate (count (mset ys) k) k by (simp add: replicate-count-mset-eq-filter-eq) also have ... = replicate (count (mset xs) k) k using mset-equal by simp also have ... = filter (HOL.eq k) xs by (simp add: replicate-count-mset-eq-filter-eq) also have ... = [x←xs . f k = f x] using inj by (auto intro!: inj-on-filter-key-eq [symmetric] simp add: set-equal) finally show ?thesis . qed qed lemma sort-key-eq-sort-key: assumes mset xs = mset ys and inj-on f (set xs) shows sort-key f xs = sort-key f ys by (rule sort-key-inj-key-eq)(simp-all add: assms) lemma sort-key-by-quicksort: sort-key f xs = sort-key f [x←xs. f x < f (xs !(length xs div 2 ))] 192 @[x←xs. f x = f (xs !(length xs div 2 ))] @ sort-key f [x←xs. f x > f (xs !(length xs div 2 ))] (is sort-key f ?lhs = ?rhs) proof (rule properties-for-sort-key) show mset ?rhs = mset ?lhs by (rule multiset-eqI )(auto simp add: mset-filter) show sorted (map f ?rhs) by (auto simp add: sorted-append intro: sorted-map-same) next fix l assume l ∈ set ?rhs let ?pivot = f (xs !(length xs div 2 )) have ∗: Vx. f l = f x ←→ f x = f l by auto have [x ← sort-key f xs . f x = f l] = [x ← xs. f x = f l] unfolding filter-sort by (rule properties-for-sort-key)(auto intro: sorted-map-same) with ∗ have ∗∗:[x ← sort-key f xs . f l = f x] = [x ← xs. f l = f x] by simp have Vx P. P (f x) ?pivot ∧ f l = f x ←→ P (f l) ?pivot ∧ f l = f x by auto then have VP. [x ← sort-key f xs . P (f x) ?pivot ∧ f l = f x] = [x ← sort-key f xs. P (f l) ?pivot ∧ f l = f x] by simp note ∗∗∗ = this [of op <] this [of op >] this [of op =] show [x ← ?rhs. f l = f x] = [x ← ?lhs. f l = f x] proof (cases f l ?pivot rule: linorder-cases) case less then have f l 6= ?pivot and ¬ f l > ?pivot by auto with less show ?thesis by (simp add: filter-sort [symmetric] ∗∗ ∗∗∗) next case equal then show ?thesis by (simp add: ∗ less-le) next case greater then have f l 6= ?pivot and ¬ f l < ?pivot by auto with greater show ?thesis by (simp add: filter-sort [symmetric] ∗∗ ∗∗∗) qed qed lemma sort-by-quicksort: sort xs = sort [x←xs. x < xs !(length xs div 2 )] @[x←xs. x = xs !(length xs div 2 )] @ sort [x←xs. x > xs !(length xs div 2 )] (is sort ?lhs = ?rhs) using sort-key-by-quicksort [of λx. x, symmetric] by simp A stable parametrized quicksort definition part :: ( 0b ⇒ 0a) ⇒ 0a ⇒ 0b list ⇒ 0b list × 0b list × 0b list where part f pivot xs = ([x ← xs. f x < pivot], [x ← xs. f x = pivot], [x ← xs. pivot < f x]) lemma part-code [code]: part f pivot [] = ([], [], []) 193 part f pivot (x # xs) = (let (lts, eqs, gts) = part f pivot xs; x 0 = f x in if x 0 < pivot then (x # lts, eqs, gts) else if x 0 > pivot then (lts, eqs, x # gts) else (lts, x # eqs, gts)) by (auto simp add: part-def Let-def split-def ) lemma sort-key-by-quicksort-code [code]: sort-key f xs = (case xs of [] ⇒ [] | [x] ⇒ xs | [x, y] ⇒ (if f x ≤ f y then xs else [y, x]) | - ⇒ let (lts, eqs, gts) = part f (f (xs !(length xs div 2 ))) xs in sort-key f lts @ eqs @ sort-key f gts) proof (cases xs) case Nil then show ?thesis by simp next case (Cons - ys) note hyps = Cons show ?thesis proof (cases ys) case Nil with hyps show ?thesis by simp next case (Cons - zs) note hyps = hyps Cons show ?thesis proof (cases zs) case Nil with hyps show ?thesis by auto next case Cons from sort-key-by-quicksort [of f xs] have sort-key f xs = (let (lts, eqs, gts) = part f (f (xs !(length xs div 2 ))) xs in sort-key f lts @ eqs @ sort-key f gts) by (simp only: split-def Let-def part-def fst-conv snd-conv) with hyps Cons show ?thesis by (simp only: list.cases) qed qed qed end hide-const (open) part lemma mset-remdups-subset-eq: mset (remdups xs) ⊆# mset xs by (induct xs)(auto intro: subset-mset.order-trans) lemma mset-update: i < length ls =⇒ mset (ls[i := v]) = add-mset v (mset ls − {#ls ! i#}) proof (induct ls arbitrary: i) case Nil then show ?case by simp next case (Cons x xs) 194 show ?case proof (cases i) case 0 then show ?thesis by simp next case (Suc i 0) with Cons show ?thesis 0 by (cases hx = xs ! i i) auto qed qed lemma mset-swap: i < length ls =⇒ j < length ls =⇒ mset (ls[j := ls ! i, i := ls ! j ]) = mset ls by (cases i = j )(simp-all add: mset-update nth-mem-mset) 31.12 The multiset order 31.12.1 Well-foundedness definition mult1 :: ( 0a × 0a) set ⇒ ( 0a multiset × 0a multiset) set where mult1 r = {(N , M ). ∃ a M0 K . M = add-mset a M0 ∧ N = M0 + K ∧ (∀ b. b ∈# K −→ (b, a) ∈ r)} definition mult :: ( 0a × 0a) set ⇒ ( 0a multiset × 0a multiset) set where mult r = (mult1 r)+ lemma mult1I : assumes M = add-mset a M0 and N = M0 + K and Vb. b ∈# K =⇒ (b, a) ∈ r shows (N , M ) ∈ mult1 r using assms unfolding mult1-def by blast lemma mult1E: assumes (N , M ) ∈ mult1 r obtains a M0 K where M = add-mset a M0 N = M0 + K Vb. b ∈# K =⇒ (b, a) ∈ r using assms unfolding mult1-def by blast lemma mono-mult1 : assumes r ⊆ r 0 shows mult1 r ⊆ mult1 r 0 unfolding mult1-def using assms by blast lemma mono-mult: assumes r ⊆ r 0 shows mult r ⊆ mult r 0 unfolding mult-def using mono-mult1 [OF assms] trancl-mono by blast lemma not-less-empty [iff ]: (M , {#}) ∈/ mult1 r by (simp add: mult1-def ) lemma less-add: 195 assumes mult1 :(N , add-mset a M0 ) ∈ mult1 r shows (∃ M . (M , M0 ) ∈ mult1 r ∧ N = add-mset a M ) ∨ (∃ K . (∀ b. b ∈# K −→ (b, a) ∈ r) ∧ N = M0 + K ) proof − let ?r = λK a. ∀ b. b ∈# K −→ (b, a) ∈ r let ?R = λNM . ∃ a M0 K . M = add-mset a M0 ∧ N = M0 + K ∧ ?r K a obtain a 0 M0 0 K where M0 : add-mset a M0 = add-mset a 0 M0 0 and N : N = M0 0 + K and r: ?r K a 0 using mult1 unfolding mult1-def by auto show ?thesis (is ?case1 ∨ ?case2 ) proof − from M0 consider M0 = M0 0 a = a 0 | K 0 where M0 = add-mset a 0 K 0 M0 0 = add-mset a K 0 by atomize-elim (simp only: add-eq-conv-ex) then show ?thesis proof cases case 1 with N r have ?r K a ∧ N = M0 + K by simp then have ?case2 .. then show ?thesis .. next case 2 from N 2 (2 ) have n: N = add-mset a (K 0 + K ) by simp with r 2 (1 ) have ?R (K 0 + K ) M0 by blast with n have ?case1 by (simp add: mult1-def ) then show ?thesis .. qed qed qed lemma all-accessible: assumes wf r shows ∀ M . M ∈ Wellfounded.acc (mult1 r) proof let ?R = mult1 r let ?W = Wellfounded.acc ?R { fix M M0 a assume M0 : M0 ∈ ?W and wf-hyp: Vb. (b, a) ∈ r =⇒ (∀ M ∈ ?W . add-mset b M ∈ ?W ) and acc-hyp: ∀ M . (M , M0 ) ∈ ?R −→ add-mset a M ∈ ?W have add-mset a M0 ∈ ?W proof (rule accI [of add-mset a M0 ]) fix N assume (N , add-mset a M0 ) ∈ ?R then consider M where (M , M0 ) ∈ ?R N = add-mset a M | K where ∀ b. b ∈# K −→ (b, a) ∈ r N = M0 + K 196 by atomize-elim (rule less-add) then show N ∈ ?W proof cases case 1 from acc-hyp have (M , M0 ) ∈ ?R −→ add-mset a M ∈ ?W .. from this and h(M , M0 ) ∈ ?Ri have add-mset a M ∈ ?W .. then show N ∈ ?W by (simp only: hN = add-mset a M i) next case 2 from this(1 ) have M0 + K ∈ ?W proof (induct K ) case empty from M0 show M0 + {#} ∈ ?W by simp next case (add x K ) from add.prems have (x, a) ∈ r by simp with wf-hyp have ∀ M ∈ ?W . add-mset x M ∈ ?W by blast moreover from add have M0 + K ∈ ?W by simp ultimately have add-mset x (M0 + K ) ∈ ?W .. then show M0 + (add-mset x K ) ∈ ?W by simp qed then show N ∈ ?W by (simp only: 2 (2 )) qed qed } note tedious-reasoning = this show M ∈ ?W for M proof (induct M ) show {#} ∈ ?W proof (rule accI ) fix b assume (b, {#}) ∈ ?R with not-less-empty show b ∈ ?W by contradiction qed fix M a assume M ∈ ?W from hwf r i have ∀ M ∈ ?W . add-mset a M ∈ ?W proof induct fix a assume r: Vb. (b, a) ∈ r =⇒ (∀ M ∈ ?W . add-mset b M ∈ ?W ) show ∀ M ∈ ?W . add-mset a M ∈ ?W proof fix M assume M ∈ ?W then show add-mset a M ∈ ?W by (rule acc-induct)(rule tedious-reasoning [OF - r]) qed qed from this and hM ∈ ?W i show add-mset a M ∈ ?W .. qed qed 197 theorem wf-mult1 : wf r =⇒ wf (mult1 r) by (rule acc-wfI )(rule all-accessible) theorem wf-mult: wf r =⇒ wf (mult r) unfolding mult-def by (rule wf-trancl)(rule wf-mult1 ) 31.12.2 Closure-free presentation One direction. lemma mult-implies-one-step: assumes trans: trans r and MN :(M , N ) ∈ mult r shows ∃ IJK . N = I + J ∧ M = I + K ∧ J 6= {#} ∧ (∀ k ∈ set-mset K . ∃ j ∈ set-mset J . (k, j ) ∈ r) using MN unfolding mult-def mult1-def proof (induction rule: converse-trancl-induct) case (base y) then show ?case by force next case (step y z) note yz = this(1 ) and zN = this(2 ) and N-decomp = this(3 ) obtain IJK where N : N = I + J z = I + KJ 6= {#} ∀ k∈#K . ∃ j ∈#J . (k, j ) ∈ r using N-decomp by blast obtain a M0 K 0 where z: z = add-mset a M0 and y: y = M0 + K 0 and K : ∀ b. b ∈# K 0 −→ (b, a) ∈ r using yz by blast show ?case proof (cases a ∈# K ) case True moreover have ∃ j ∈#J . (k, j ) ∈ r if k ∈# K 0 for k using K N trans True by (meson that transE) ultimately show ?thesis by (rule-tac x = I in exI , rule-tac x = J in exI , rule-tac x = (K − {#a#}) + K 0 in exI ) (use z y N in hauto simp del: subset-mset.add-diff-assoc2 dest: in-diffD i) next case False then have a ∈# I by (metis N (2 ) union-iff union-single-eq-member z) moreover have M0 = I + K − {#a#} using N (2 ) z by force ultimately show ?thesis by (rule-tac x = I − {#a#} in exI , rule-tac x = add-mset a J in exI , rule-tac x = K + K 0 in exI ) (use z y N False K in hauto simp: add.associ) qed qed 198 lemma one-step-implies-mult: assumes J 6= {#} and ∀ k ∈ set-mset K . ∃ j ∈ set-mset J . (k, j ) ∈ r shows (I + K , I + J ) ∈ mult r using assms proof (induction size J arbitrary: IJK ) case 0 then show ?case by auto next case (Suc n) note IH = this(1 ) and size-J = this(2 )[THEN sym] obtain J 0 a where J : J = add-mset a J 0 using size-J by (blast dest: size-eq-Suc-imp-eq-union) show ?case proof (cases J 0 = {#}) case True then show ?thesis using J Suc by (fastforce simp add: mult-def mult1-def ) next case [simp]: False have K : K = {#x ∈# K . (x, a) ∈ r#} + {#x ∈# K . (x, a) ∈/ r#} by (rule multiset-partition) have (I + K , (I + {# x ∈# K . (x, a) ∈ r #}) + J 0) ∈ mult r using IH [of J 0 {# x ∈# K . (x, a) ∈/ r#} I + {# x ∈# K . (x, a) ∈ r#}] J Suc.prems K size-J by (auto simp: ac-simps) moreover have (I + {#x ∈# K . (x, a) ∈ r#} + J 0, I + J ) ∈ mult r by (fastforce simp: J mult1-def mult-def ) ultimately show ?thesis unfolding mult-def by simp qed qed 31.13 The multiset extension is cancellative for multiset union lemma mult-cancel: assumes trans s and irrefl s shows (X + Z , Y + Z ) ∈ mult s ←→ (X , Y ) ∈ mult s (is ?L ←→ ?R) proof assume ?L thus ?R proof (induct Z ) case (add z Z ) obtain X 0 Y 0 Z 0 where ∗: add-mset z X + Z = Z 0 + X 0 add-mset z Y + Z = Z 0 + Y 0 Y 0 6= {#} ∀ x ∈ set-mset X 0. ∃ y ∈ set-mset Y 0. (x, y) ∈ s using mult-implies-one-step[OF htrans s i add(2 )] by auto consider Z2 where Z 0 = add-mset z Z2 | X2 Y2 where X 0 = add-mset z X2 Y 0 = add-mset z Y2 using ∗(1 ,2 ) by (metis add-mset-remove-trivial-If insert-iff set-mset-add-mset-insert 199 union-iff ) thus ?case proof (cases) case 1 thus ?thesis using ∗ one-step-implies-mult[of Y 0 X 0 s Z2 ] by (auto simp: add.commute[of - {#-#}] add.assoc intro: add(1 )) next case 2 then obtain y where y ∈ set-mset Y2 (z, y) ∈ s using ∗(4 ) hirrefl s i by (auto simp: irrefl-def ) moreover from this transD[OF htrans s i - this(2 )] have x 0 ∈ set-mset X2 =⇒ ∃ y ∈ set-mset Y2 . (x 0, y) ∈ s for x 0 using 2 ∗(4 )[rule-format, of x 0] by auto ultimately show ?thesis using ∗ one-step-implies-mult[of Y2 X2 s Z 0] 2 by (force simp: add.commute[of {#-#}] add.assoc[symmetric] intro: add(1 )) qed qed auto next assume ?R then obtain IJK where Y = I + JX = I + KJ 6= {#} ∀ k ∈ set-mset K . ∃ j ∈ set-mset J . (k, j ) ∈ s using mult-implies-one-step[OF htrans s i] by blast thus ?L using one-step-implies-mult[of J K s I + Z ] by (auto simp: ac-simps) qed lemma mult-cancel-max: assumes trans s and irrefl s shows (X , Y ) ∈ mult s ←→ (X − X ∩# Y , Y − X ∩# Y ) ∈ mult s (is ?L ←→ ?R) proof − have X − X ∩# Y + X ∩# Y = XY − X ∩# Y + X ∩# Y = Y by (auto simp: count-inject[symmetric]) thus ?thesis using mult-cancel[OF assms, of X − X ∩# YX ∩# YY − X ∩# Y ] by auto qed 31.14 Quasi-executable version of the multiset extension Predicate variants of mult and the reflexive closure of mult, which are exe- cutable whenever the given predicate P is. Together with the standard code equations for op ∩# and op − this should yield quadratic (with respect to calls to P) implementations of multp and multeqp. definition multp :: ( 0a ⇒ 0a ⇒ bool) ⇒ 0a multiset ⇒ 0a multiset ⇒ bool where multp P N M = (let Z = M ∩# N ; X = M − Z in X 6= {#} ∧ (let Y = N − Z in (∀ y ∈ set-mset Y . ∃ x ∈ set-mset X . P y x))) definition multeqp :: ( 0a ⇒ 0a ⇒ bool) ⇒ 0a multiset ⇒ 0a multiset ⇒ bool where multeqp P N M = 200 (let Z = M ∩# N ; X = M − Z ; Y = N − Z in (∀ y ∈ set-mset Y . ∃ x ∈ set-mset X . P y x)) lemma multp-iff : assumes irrefl R and trans R and [simp]: Vx y. P x y ←→ (x, y) ∈ R shows multp P N M ←→ (N , M ) ∈ mult R (is ?L ←→ ?R) proof − have ∗: M ∩# N + (N − M ∩# N ) = NM ∩# N + (M − M ∩# N ) = M (M − M ∩# N ) ∩#(N − M ∩# N ) = {#} by (auto simp: count-inject[symmetric]) show ?thesis proof assume ?L thus ?R using one-step-implies-mult[of M − M ∩# NN − M ∩# NRM ∩# N ] ∗ by (auto simp: multp-def Let-def ) next { fix IJK :: 0a multiset assume (I + J ) ∩#(I + K ) = {#} then have I = {#} by (metis inter-union-distrib-right union-eq-empty) } note [dest!] = this assume ?R thus ?L using mult-implies-one-step[OF assms(2 ), of N − M ∩# NM − M ∩# N ] mult-cancel-max[OF assms(2 ,1 ), of N M ] ∗ by (auto simp: multp-def ) qed qed lemma multeqp-iff : assumes irrefl R and trans R and Vx y. P x y ←→ (x, y) ∈ R shows multeqp P N M ←→ (N , M ) ∈ (mult R)= proof − { assume N 6= MM − M ∩# N = {#} then obtain y where count N y 6= count M y by (auto simp: count-inject[symmetric]) then have ∃ y. count M y < count N y using hM − M ∩# N = {#}i by (auto simp: count-inject[symmetric] dest!: le-neq-implies-less fun-cong[of - - y]) } then have multeqp P N M ←→ multp P N M ∨ N = M by (auto simp: multeqp-def multp-def Let-def in-diff-count) thus ?thesis using multp-iff [OF assms] by simp qed 31.14.1 Partial-order properties lemma (in preorder) mult1-lessE: assumes (N , M ) ∈ mult1 {(a, b). a < b} obtains a M0 K where M = add-mset a M0 N = M0 + K a ∈/# K Vb. b ∈# K =⇒ b < a proof − from assms obtain a M0 K where M = add-mset a M0 N = M0 + K and ∗: b ∈# K =⇒ b < a for b by (blast elim: mult1E) moreover from ∗ [of a] have a ∈/# K by auto 201 ultimately show thesis by (auto intro: that) qed instantiation multiset :: (preorder) order begin definition less-multiset :: 0a multiset ⇒ 0a multiset ⇒ bool where M 0 < M ←→ (M 0, M ) ∈ mult {(x 0, x). x 0 < x} definition less-eq-multiset :: 0a multiset ⇒ 0a multiset ⇒ bool where less-eq-multiset M 0 M ←→ M 0 < M ∨ M 0 = M instance proof − have irrefl: ¬ M < M for M :: 0a multiset proof assume M < M then have MM :(M , M ) ∈ mult {(x, y). x < y} by (simp add: less-multiset-def ) have trans {(x 0:: 0a, x). x 0 < x} by (metis (mono-tags, lifting) case-prodD case-prodI less-trans mem-Collect-eq transI ) moreover note MM ultimately have ∃ IJK . M = I + J ∧ M = I + K ∧ J 6= {#} ∧ (∀ k∈set-mset K . ∃ j ∈set-mset J . (k, j ) ∈ {(x, y). x < y}) by (rule mult-implies-one-step) then obtain IJK where M = I + J and M = I + K and J 6= {#} and (∀ k∈set-mset K . ∃ j ∈set-mset J . (k, j ) ∈ {(x, y). x < y}) by blast then have ∗: K 6= {#} and ∗∗: ∀ k∈set-mset K . ∃ j ∈set-mset K . k < j by auto have finite (set-mset K ) by simp moreover note ∗∗ ultimately have set-mset K = {} by (induct rule: finite-induct)(auto intro: order-less-trans) with ∗ show False by simp qed have trans: K < M =⇒ M < N =⇒ K < N for KMN :: 0a multiset unfolding less-multiset-def mult-def by (blast intro: trancl-trans) show OFCLASS( 0a multiset, order-class) by standard (auto simp add: less-eq-multiset-def irrefl dest: trans) qed end — FIXME avoid junk stemming from type class interpretation lemma mset-le-irrefl [elim!]: fixes M :: 0a::preorder multiset shows M < M =⇒ R by simp 202 31.14.2 Monotonicity of multiset union lemma mult1-union:(B, D) ∈ mult1 r =⇒ (C + B, C + D) ∈ mult1 r by (force simp: mult1-def ) lemma union-le-mono2 : B < D =⇒ C + B < C + (D:: 0a::preorder multiset) apply (unfold less-multiset-def mult-def ) apply (erule trancl-induct) apply (blast intro: mult1-union) apply (blast intro: mult1-union trancl-trans) done lemma union-le-mono1 : B < D =⇒ B + C < D + (C :: 0a::preorder multiset) apply (subst add.commute [of B C ]) apply (subst add.commute [of D C ]) apply (erule union-le-mono2 ) done lemma union-less-mono: fixes ABCD :: 0a::preorder multiset shows A < C =⇒ B < D =⇒ A + B < C + D by (blast intro!: union-le-mono1 union-le-mono2 less-trans) instantiation multiset :: (preorder) ordered-ab-semigroup-add begin instance by standard (auto simp add: less-eq-multiset-def intro: union-le-mono2 ) end 31.14.3 Termination proofs with multiset orders lemma multi-member-skip: x ∈# XS =⇒ x ∈# {# y #} + XS and multi-member-this: x ∈# {# x #} + XS and multi-member-last: x ∈# {# x #} by auto definition ms-strict = mult pair-less definition ms-weak = ms-strict ∪ Id lemma ms-reduction-pair: reduction-pair (ms-strict, ms-weak) unfolding reduction-pair-def ms-strict-def ms-weak-def pair-less-def by (auto intro: wf-mult1 wf-trancl simp: mult-def ) lemma smsI : (set-mset A, set-mset B) ∈ max-strict =⇒ (Z + A, Z + B) ∈ ms-strict unfolding ms-strict-def by (rule one-step-implies-mult)(auto simp add: max-strict-def pair-less-def elim!:max-ext.cases) lemma wmsI : (set-mset A, set-mset B) ∈ max-strict ∨ A = {#} ∧ B = {#} 203 =⇒ (Z + A, Z + B) ∈ ms-weak unfolding ms-weak-def ms-strict-def by (auto simp add: pair-less-def max-strict-def elim!:max-ext.cases intro: one-step-implies-mult) inductive pw-leq where pw-leq-empty: pw-leq {#}{#} | pw-leq-step: [[(x,y) ∈ pair-leq; pw-leq X Y ]] =⇒ pw-leq ({#x#} + X )({#y#} + Y ) lemma pw-leq-lstep: (x, y) ∈ pair-leq =⇒ pw-leq {#x#}{#y#} by (drule pw-leq-step)(rule pw-leq-empty, simp) lemma pw-leq-split: assumes pw-leq X Y shows ∃ ABZ . X = A + Z ∧ Y = B + Z ∧ ((set-mset A, set-mset B) ∈ max-strict ∨ (B = {#} ∧ A = {#})) using assms proof induct case pw-leq-empty thus ?case by auto next case (pw-leq-step x y X Y ) then obtain ABZ where [simp]: X = A + ZY = B + Z and 1 [simp]: (set-mset A, set-mset B) ∈ max-strict ∨ (B = {#} ∧ A = {#}) by auto from pw-leq-step consider x = y | (x, y) ∈ pair-less unfolding pair-leq-def by auto thus ?case proof cases case [simp]: 1 have {#x#} + X = A + ({#y#}+Z ) ∧ {#y#} + Y = B + ({#y#}+Z ) ∧ ((set-mset A, set-mset B) ∈ max-strict ∨ (B = {#} ∧ A = {#})) by auto thus ?thesis by blast next case 2 let ?A 0 = {#x#} + A and ?B 0 = {#y#} + B have {#x#} + X = ?A 0 + Z {#y#} + Y = ?B 0 + Z by auto moreover have (set-mset ?A 0, set-mset ?B 0) ∈ max-strict using 1 2 unfolding max-strict-def by (auto elim!: max-ext.cases) ultimately show ?thesis by blast qed qed 204 lemma assumes pwleq: pw-leq Z Z 0 shows ms-strictI :(set-mset A, set-mset B) ∈ max-strict =⇒ (Z + A, Z 0 + B) ∈ ms-strict and ms-weakI1 :(set-mset A, set-mset B) ∈ max-strict =⇒ (Z + A, Z 0 + B) ∈ ms-weak and ms-weakI2 :(Z + {#}, Z 0 + {#}) ∈ ms-weak proof − from pw-leq-split[OF pwleq] obtain A 0 B 0 Z 00 where [simp]: Z = A 0 + Z 00 Z 0 = B 0 + Z 00 and mx-or-empty:(set-mset A 0, set-mset B 0) ∈ max-strict ∨ (A 0 = {#} ∧ B 0 = {#}) by blast { assume max:(set-mset A, set-mset B) ∈ max-strict from mx-or-empty have (Z 00 + (A + A 0), Z 00 + (B + B 0)) ∈ ms-strict proof assume max 0:(set-mset A 0, set-mset B 0) ∈ max-strict with max have (set-mset (A + A 0), set-mset (B + B 0)) ∈ max-strict by (auto simp: max-strict-def intro: max-ext-additive) thus ?thesis by (rule smsI ) next assume [simp]: A 0 = {#} ∧ B 0 = {#} show ?thesis by (rule smsI )(auto intro: max) qed thus (Z + A, Z 0 + B) ∈ ms-strict by (simp add: ac-simps) thus (Z + A, Z 0 + B) ∈ ms-weak by (simp add: ms-weak-def ) } from mx-or-empty have (Z 00 + A 0, Z 00 + B 0) ∈ ms-weak by (rule wmsI ) thus (Z + {#}, Z 0 + {#}) ∈ ms-weak by (simp add: ac-simps) qed lemma empty-neutral: {#} + x = x x + {#} = x and nonempty-plus: {# x #} + rs 6= {#} and nonempty-single: {# x #}= 6 {#} by auto setup h let fun msetT T = Type (@{type-name multiset}, [T ]); fun mk-mset T [] = Const (@{const-abbrev Mempty}, msetT T ) | mk-mset T [x] = Const (@{const-name add-mset}, T −−> msetT T −−> msetT T ) $ x $ Const (@{const-abbrev Mempty}, msetT T ) 205 | mk-mset T (x :: xs) = Const (@{const-name plus}, msetT T −−> msetT T −−> msetT T ) $ mk-mset T [x] $ mk-mset T xs fun mset-member-tac ctxt m i = if m <= 0 then resolve-tac ctxt @{thms multi-member-this} i ORELSE resolve-tac ctxt @{thms multi-member-last} i else resolve-tac ctxt @{thms multi-member-skip} i THEN mset-member-tac ctxt (m − 1 ) i fun mset-nonempty-tac ctxt = resolve-tac ctxt @{thms nonempty-plus} ORELSE 0 resolve-tac ctxt @{thms nonempty-single} fun regroup-munion-conv ctxt = Function-Lib.regroup-conv ctxt @{const-abbrev Mempty} @{const-name plus} (map (fn t => t RS eq-reflection) (@{thms ac-simps} @@{thms empty-neutral})) fun unfold-pwleq-tac ctxt i = (resolve-tac ctxt @{thms pw-leq-step} i THEN (fn st => unfold-pwleq-tac ctxt (i + 1 ) st)) ORELSE (resolve-tac ctxt @{thms pw-leq-lstep} i) ORELSE (resolve-tac ctxt @{thms pw-leq-empty} i) val set-mset-simps = [@{thm set-mset-empty}, @{thm set-mset-single}, @{thm set-mset-union}, @{thm Un-insert-left}, @{thm Un-empty-left}] in ScnpReconstruct.multiset-setup (ScnpReconstruct.Multiset { msetT =msetT , mk-mset=mk-mset, mset-regroup-conv=regroup-munion-conv, mset-member-tac=mset-member-tac, mset-nonempty-tac=mset-nonempty-tac, mset-pwleq-tac=unfold-pwleq-tac, set-of-simps=set-mset-simps, smsI 0= @{thm ms-strictI }, wmsI2 00= @{thm ms-weakI2 }, wmsI1 = @{thm ms-weakI1 }, reduction-pair = @{thm ms-reduction-pair} }) end i 31.15 Legacy theorem bindings lemmas multi-count-eq = multiset-eq-iff [symmetric] lemma union-commute: M + N = N + (M :: 0a multiset) by (fact add.commute) 206 lemma union-assoc:(M + N ) + K = M + (N + (K :: 0a multiset)) by (fact add.assoc) lemma union-lcomm: M + (N + K ) = N + (M + (K :: 0a multiset)) by (fact add.left-commute) lemmas union-ac = union-assoc union-commute union-lcomm add-mset-commute lemma union-right-cancel: M + K = N + K ←→ M = (N :: 0a multiset) by (fact add-right-cancel) lemma union-left-cancel: K + M = K + N ←→ M = (N :: 0a multiset) by (fact add-left-cancel) lemma multi-union-self-other-eq:(A:: 0a multiset) + X = A + Y =⇒ X = Y by (fact add-left-imp-eq) lemma mset-subset-trans:(M :: 0a multiset) ⊂# K =⇒ K ⊂# N =⇒ M ⊂# N by (fact subset-mset.less-trans) lemma multiset-inter-commute: A ∩# B = B ∩# A by (fact subset-mset.inf .commute) lemma multiset-inter-assoc: A ∩#(B ∩# C ) = A ∩# B ∩# C by (fact subset-mset.inf .assoc [symmetric]) lemma multiset-inter-left-commute: A ∩#(B ∩# C ) = B ∩#(A ∩# C ) by (fact subset-mset.inf .left-commute) lemmas multiset-inter-ac = multiset-inter-commute multiset-inter-assoc multiset-inter-left-commute lemma mset-le-not-refl: ¬ M < (M :: 0a::preorder multiset) by (fact less-irrefl) lemma mset-le-trans: K < M =⇒ M < N =⇒ K < (N :: 0a::preorder multiset) by (fact less-trans) lemma mset-le-not-sym: M < N =⇒ ¬ N < (M :: 0a::preorder multiset) by (fact less-not-sym) lemma mset-le-asym: M < N =⇒ (¬ P =⇒ N < (M :: 0a::preorder multiset)) =⇒ P by (fact less-asym) declaration h let 207 fun multiset-postproc - maybe-name all-values (T as Type (-, [elem-T ])) (Const - $ t 0) = let val (maybe-opt, ps) = Nitpick-Model.dest-plain-fun t 0 ||> op ∼∼ ||> map (apsnd (snd o HOLogic.dest-number)) fun elems-for t = (case AList.lookup (op =) ps t of SOME n => replicate n t | NONE => [Const (maybe-name, elem-T −−> elem-T ) $ t]) in (case maps elems-for (all-values elem-T )@ (if maybe-opt then [Const (Nitpick-Model.unrep-mixfix (), elem-T )] else []) of [] => Const (@{const-name zero-class.zero}, T ) | ts => foldl1 (fn (s, t) => Const (@{const-name add-mset}, elem-T −−> T −−> T ) $ s $ t) ts) end | multiset-postproc - - - - t = t in Nitpick-Model.register-term-postprocessor @{typ 0a multiset} multiset-postproc end i 31.16 Naive implementation using lists code-datatype mset lemma [code]: {#} = mset [] by simp lemma [code]: add-mset x (mset xs) = mset (x # xs) by simp lemma [code]: Multiset.is-empty (mset xs) ←→ List.null xs by (simp add: Multiset.is-empty-def List.null-def ) lemma union-code [code]: mset xs + mset ys = mset (xs @ ys) by simp lemma [code]: image-mset f (mset xs) = mset (map f xs) by simp lemma [code]: filter-mset f (mset xs) = mset (filter f xs) by (simp add: mset-filter) lemma [code]: mset xs − mset ys = mset (fold remove1 ys xs) 208 by (rule sym, induct ys arbitrary: xs)(simp-all add: diff-add diff-right-commute diff-diff-add) lemma [code]: mset xs ∩# mset ys = mset (snd (fold (λx (ys, zs). if x ∈ set ys then (remove1 x ys, x # zs) else (ys, zs)) xs (ys, []))) proof − have Vzs. mset (snd (fold (λx (ys, zs). if x ∈ set ys then (remove1 x ys, x # zs) else (ys, zs)) xs (ys, zs))) = (mset xs ∩# mset ys) + mset zs by (induct xs arbitrary: ys) (auto simp add: inter-add-right1 inter-add-right2 ac-simps) then show ?thesis by simp qed lemma [code]: mset xs ∪# mset ys = mset (case-prod append (fold (λx (ys, zs). (remove1 x ys, x # zs)) xs (ys, []))) proof − have Vzs. mset (case-prod append (fold (λx (ys, zs). (remove1 x ys, x # zs)) xs (ys, zs))) = (mset xs ∪# mset ys) + mset zs by (induct xs arbitrary: ys)(simp-all add: multiset-eq-iff ) then show ?thesis by simp qed declare in-multiset-in-set [code-unfold] lemma [code]: count (mset xs) x = fold (λy. if x = y then Suc else id) xs 0 proof − have Vn. fold (λy. if x = y then Suc else id) xs n = count (mset xs) x + n by (induct xs) simp-all then show ?thesis by simp qed declare set-mset-mset [code] declare sorted-list-of-multiset-mset [code] lemma [code]: — not very efficient, but representation-ignorant! mset-set A = mset (sorted-list-of-set A) apply (cases finite A) apply simp-all apply (induct A rule: finite-induct) apply simp-all done declare size-mset [code] 209 fun subset-eq-mset-impl :: 0a list ⇒ 0a list ⇒ bool option where subset-eq-mset-impl [] ys = Some (ys 6= []) | subset-eq-mset-impl (Cons x xs) ys = (case List.extract (op = x) ys of None ⇒ None | Some (ys1 ,-,ys2 ) ⇒ subset-eq-mset-impl xs (ys1 @ ys2 )) lemma subset-eq-mset-impl:(subset-eq-mset-impl xs ys = None ←→ ¬ mset xs ⊆# mset ys) ∧ (subset-eq-mset-impl xs ys = Some True ←→ mset xs ⊂# mset ys) ∧ (subset-eq-mset-impl xs ys = Some False −→ mset xs = mset ys) proof (induct xs arbitrary: ys) case (Nil ys) show ?case by (auto simp: subset-mset.zero-less-iff-neq-zero) next case (Cons x xs ys) show ?case proof (cases List.extract (op = x) ys) case None hence x: x ∈/ set ys by (simp add: extract-None-iff ) { assume mset (x # xs) ⊆# mset ys from set-mset-mono[OF this] x have False by simp } note nle = this moreover { assume mset (x # xs) ⊂# mset ys hence mset (x # xs) ⊆# mset ys by auto from nle[OF this] have False . } ultimately show ?thesis using None by auto next case (Some res) obtain ys1 y ys2 where res: res = (ys1 ,y,ys2 ) by (cases res, auto) note Some = Some[unfolded res] from extract-SomeE[OF Some] have ys = ys1 @ x # ys2 by simp hence id: mset ys = add-mset x (mset (ys1 @ ys2 )) by auto show ?thesis unfolding subset-eq-mset-impl.simps unfolding Some option.simps split unfolding id using Cons[of ys1 @ ys2 ] unfolding subset-mset-def subseteq-mset-def by auto qed qed lemma [code]: mset xs ⊆# mset ys ←→ subset-eq-mset-impl xs ys 6= None using subset-eq-mset-impl[of xs ys] by (cases subset-eq-mset-impl xs ys, auto) 210 lemma [code]: mset xs ⊂# mset ys ←→ subset-eq-mset-impl xs ys = Some True using subset-eq-mset-impl[of xs ys] by (cases subset-eq-mset-impl xs ys, auto) instantiation multiset :: (equal) equal begin definition [code del]: HOL.equal A (B :: 0a multiset) ←→ A = B lemma [code]: HOL.equal (mset xs)(mset ys) ←→ subset-eq-mset-impl xs ys = Some False unfolding equal-multiset-def using subset-eq-mset-impl[of xs ys] by (cases subset-eq-mset-impl xs ys, auto) instance by standard (simp add: equal-multiset-def ) end lemma [code]: sum-mset (mset xs) = sum-list xs by (induct xs) simp-all lemma [code]: prod-mset (mset xs) = fold times xs 1 proof − have Vx. fold times xs x = prod-mset (mset xs) ∗ x by (induct xs)(simp-all add: ac-simps) then show ?thesis by simp qed Exercise for the casual reader: add implementations for op ≤ and op < (multiset order). Quickcheck generators definition (in term-syntax) msetify :: 0a::typerep list × (unit ⇒ Code-Evaluation.term) ⇒ 0a multiset × (unit ⇒ Code-Evaluation.term) where [code-unfold]: msetify xs = Code-Evaluation.valtermify mset {·} xs notation fcomp (infixl ◦> 60 ) notation scomp (infixl ◦→ 60 ) instantiation multiset :: (random) random begin definition Quickcheck-Random.random i = Quickcheck-Random.random i ◦→ (λxs. Pair (msetify xs)) instance .. 211 end no-notation fcomp (infixl ◦> 60 ) no-notation scomp (infixl ◦→ 60 ) instantiation multiset :: (full-exhaustive) full-exhaustive begin definition full-exhaustive-multiset :: ( 0a multiset × (unit ⇒ term) ⇒ (bool × term list) option) ⇒ natural ⇒ (bool × term list) option where full-exhaustive-multiset f i = Quickcheck-Exhaustive.full-exhaustive (λxs. f (msetify xs)) i instance .. end hide-const (open) msetify 31.17 BNF setup definition rel-mset where rel-mset R X Y ←→ (∃ xs ys. mset xs = X ∧ mset ys = Y ∧ list-all2 R xs ys) lemma mset-zip-take-Cons-drop-twice: assumes length xs = length ys j ≤ length xs shows mset (zip (take j xs @ x # drop j xs)(take j ys @ y # drop j ys)) = add-mset (x,y)(mset (zip xs ys)) using assms proof (induct xs ys arbitrary: x y j rule: list-induct2 ) case Nil thus ?case by simp next case (Cons x xs y ys) thus ?case proof (cases j = 0 ) case True thus ?thesis by simp next case False then obtain k where k: j = Suc k by (cases j ) simp hence k ≤ length xs using Cons.prems by auto hence mset (zip (take k xs @ x # drop k xs)(take k ys @ y # drop k ys)) = add-mset (x,y)(mset (zip xs ys)) 212 by (rule Cons.hyps(2 )) thus ?thesis unfolding k by auto qed qed lemma ex-mset-zip-left: assumes length xs = length ys mset xs 0 = mset xs shows ∃ ys 0. length ys 0 = length xs 0 ∧ mset (zip xs 0 ys 0) = mset (zip xs ys) using assms proof (induct xs ys arbitrary: xs 0 rule: list-induct2 ) case Nil thus ?case by auto next case (Cons x xs y ys xs 0) obtain j where j-len: j < length xs 0 and nth-j : xs 0 ! j = x by (metis Cons.prems in-set-conv-nth list.set-intros(1 ) mset-eq-setD) define xsa where xsa = take j xs 0 @ drop (Suc j ) xs 0 have mset xs 0 = {#x#} + mset xsa unfolding xsa-def using j-len nth-j by (metis Cons-nth-drop-Suc union-mset-add-mset-right add-mset-remove-trivial add-diff-cancel-left 0 append-take-drop-id mset.simps(2 ) mset-append) hence ms-x: mset xsa = mset xs by (simp add: Cons.prems) then obtain ysa where len-a: length ysa = length xsa and ms-a: mset (zip xsa ysa) = mset (zip xs ys) using Cons.hyps(2 ) by blast define ys 0 where ys 0 = take j ysa @ y # drop j ysa have xs 0: xs 0 = take j xsa @ x # drop j xsa using ms-x j-len nth-j Cons.prems xsa-def by (metis append-eq-append-conv append-take-drop-id diff-Suc-Suc Cons-nth-drop-Suc length-Cons length-drop size-mset) have j-len 0: j ≤ length xsa using j-len xs 0 xsa-def by (metis add-Suc-right append-take-drop-id length-Cons length-append less-eq-Suc-le not-less) have length ys 0 = length xs 0 unfolding ys 0-def using Cons.prems len-a ms-x by (metis add-Suc-right append-take-drop-id length-Cons length-append mset-eq-length) moreover have mset (zip xs 0 ys 0) = mset (zip (x # xs)(y # ys)) unfolding xs 0 ys 0-def by (rule trans[OF mset-zip-take-Cons-drop-twice]) (auto simp: len-a ms-a j-len 0) ultimately show ?case 213 by blast qed lemma list-all2-reorder-left-invariance: assumes rel: list-all2 R xs ys and ms-x: mset xs 0 = mset xs shows ∃ ys 0. list-all2 R xs 0 ys 0 ∧ mset ys 0 = mset ys proof − have len: length xs = length ys using rel list-all2-conv-all-nth by auto obtain ys 0 where len 0: length xs 0 = length ys 0 and ms-xy: mset (zip xs 0 ys 0) = mset (zip xs ys) using len ms-x by (metis ex-mset-zip-left) have list-all2 R xs 0 ys 0 using assms(1 ) len 0 ms-xy unfolding list-all2-iff by (blast dest: mset-eq-setD) moreover have mset ys 0 = mset ys using len len 0 ms-xy map-snd-zip mset-map by metis ultimately show ?thesis by blast qed lemma ex-mset: ∃ xs. mset xs = X by (induct X )(simp, metis mset.simps(2 )) inductive pred-mset :: ( 0a ⇒ bool) ⇒ 0a multiset ⇒ bool where pred-mset P {#} | [[P a; pred-mset P M ]] =⇒ pred-mset P (add-mset a M ) bnf 0a multiset map: image-mset sets: set-mset bd: natLeq wits: {#} rel: rel-mset pred: pred-mset proof − show image-mset id = id by (rule image-mset.id) show image-mset (g ◦ f ) = image-mset g ◦ image-mset f for f g unfolding comp-def by (rule ext)(simp add: comp-def image-mset.compositionality) show (Vz. z ∈ set-mset X =⇒ f z = g z) =⇒ image-mset f X = image-mset g X for f g X by (induct X ) simp-all show set-mset ◦ image-mset f = op ‘ f ◦ set-mset for f by auto show card-order natLeq by (rule natLeq-card-order) show BNF-Cardinal-Arithmetic.cinfinite natLeq by (rule natLeq-cinfinite) 214 show ordLeq3 (card-of (set-mset X )) natLeq for X by transfer (auto intro!: ordLess-imp-ordLeq simp: finite-iff-ordLess-natLeq[symmetric] multiset-def ) show rel-mset R OO rel-mset S ≤ rel-mset (R OO S) for RS unfolding rel-mset-def [abs-def ] OO-def apply clarify subgoal for X Z Y xs ys 0 ys zs apply (drule list-all2-reorder-left-invariance [where xs = ys 0 and ys = zs and xs 0 = ys]) apply (auto intro: list-all2-trans) done done show rel-mset R = (λx y. ∃ z. set-mset z ⊆ {(x, y). R x y} ∧ image-mset fst z = x ∧ image-mset snd z = y) for R unfolding rel-mset-def [abs-def ] apply (rule ext)+ apply safe apply (rule-tac x = mset (zip xs ys) in exI ; auto simp: in-set-zip list-all2-iff mset-map[symmetric]) apply (rename-tac XY ) apply (cut-tac X = XY in ex-mset) apply (erule exE) apply (rename-tac xys) apply (rule-tac x = map fst xys in exI ) apply (auto simp: mset-map) apply (rule-tac x = map snd xys in exI ) apply (auto simp: mset-map list-all2I subset-eq zip-map-fst-snd) done show z ∈ set-mset {#} =⇒ False for z by auto show pred-mset P = (λx. Ball (set-mset x) P) for P proof (intro ext iffI ) fix x assume pred-mset P x then show Ball (set-mset x) P by (induct pred: pred-mset; simp) next fix x assume Ball (set-mset x) P then show pred-mset P x by (induct x; auto intro: pred-mset.intros) qed qed inductive rel-mset 0 where Zero[intro]: rel-mset 0 R {#}{#} | Plus[intro]: [[R a b; rel-mset 0 RMN ]] =⇒ rel-mset 0 R (add-mset a M )(add-mset b N ) 215 lemma rel-mset-Zero: rel-mset R {#}{#} unfolding rel-mset-def Grp-def by auto declare multiset.count[simp] declare Abs-multiset-inverse[simp] declare multiset.count-inverse[simp] declare union-preserves-multiset[simp] lemma rel-mset-Plus: assumes ab: R a b and MN : rel-mset R M N shows rel-mset R (add-mset a M )(add-mset b N ) proof − have ∃ ya. add-mset a (image-mset fst y) = image-mset fst ya ∧ add-mset b (image-mset snd y) = image-mset snd ya ∧ set-mset ya ⊆ {(x, y). R x y} if R a b and set-mset y ⊆ {(x, y). R x y} for y using that by (intro exI [of - add-mset (a,b) y]) auto thus ?thesis using assms unfolding multiset.rel-compp-Grp Grp-def by blast qed lemma rel-mset 0-imp-rel-mset: rel-mset 0 RMN =⇒ rel-mset R M N by (induct rule: rel-mset 0.induct)(auto simp: rel-mset-Zero rel-mset-Plus) lemma rel-mset-size: rel-mset R M N =⇒ size M = size N unfolding multiset.rel-compp-Grp Grp-def by auto lemma multiset-induct2 [case-names empty addL addR]: assumes empty: P {#}{#} and addL: Va M N . PMN =⇒ P (add-mset a M ) N and addR: Va M N . PMN =⇒ PM (add-mset a N ) shows PMN apply(induct N rule: multiset-induct) apply(induct M rule: multiset-induct, rule empty, erule addL) apply(induct M rule: multiset-induct, erule addR, erule addR) done lemma multiset-induct2-size[consumes 1 , case-names empty add]: assumes c: size M = size N and empty: P {#}{#} and add: Va b M N a b. PMN =⇒ P (add-mset a M )(add-mset b N ) shows PMN using c proof (induct M arbitrary: N rule: measure-induct-rule[of size]) case (less M ) show ?case 216 proof(cases M = {#}) case True hence N = {#} using less.prems by auto thus ?thesis using True empty by auto next case False then obtain M1 a where M : M = add-mset a M1 by (metis multi-nonempty-split) have N 6= {#} using False less.prems by auto then obtain N1 b where N : N = add-mset b N1 by (metis multi-nonempty-split) have size M1 = size N1 using less.prems unfolding MN by auto thus ?thesis using M N less.hyps add by auto qed qed lemma msed-map-invL: assumes image-mset f (add-mset a M ) = N shows ∃ N1 . N = add-mset (f a) N1 ∧ image-mset f M = N1 proof − have f a ∈# N using assms multiset.set-map[of f add-mset a M ] by auto then obtain N1 where N : N = add-mset (f a) N1 using multi-member-split by metis have image-mset f M = N1 using assms unfolding N by simp thus ?thesis using N by blast qed lemma msed-map-invR: assumes image-mset f M = add-mset b N shows ∃ M1 a. M = add-mset a M1 ∧ f a = b ∧ image-mset f M1 = N proof − obtain a where a: a ∈# M and fa: f a = b using multiset.set-map[of f M ] unfolding assms by (metis image-iff union-single-eq-member) then obtain M1 where M : M = add-mset a M1 using multi-member-split by metis have image-mset f M1 = N using assms unfolding M fa[symmetric] by simp thus ?thesis using M fa by blast qed lemma msed-rel-invL: assumes rel-mset R (add-mset a M ) N shows ∃ N1 b. N = add-mset b N1 ∧ R a b ∧ rel-mset R M N1 proof − obtain K where KM : image-mset fst K = add-mset a M and KN : image-mset snd K = N and sK : set-mset K ⊆ {(a, b). R a b} using assms unfolding multiset.rel-compp-Grp Grp-def by auto obtain K1 ab where K : K = add-mset ab K1 and a: fst ab = a and K1M : image-mset fst K1 = M using msed-map-invR[OF KM ] by auto obtain N1 where N : N = add-mset (snd ab) N1 and K1N1 : image-mset snd 217 K1 = N1 using msed-map-invL[OF KN [unfolded K ]] by auto have Rab: R a (snd ab) using sK a unfolding K by auto have rel-mset R M N1 using sK K1M K1N1 unfolding K multiset.rel-compp-Grp Grp-def by auto thus ?thesis using N Rab by auto qed lemma msed-rel-invR: assumes rel-mset R M (add-mset b N ) shows ∃ M1 a. M = add-mset a M1 ∧ R a b ∧ rel-mset R M1 N proof − obtain K where KN : image-mset snd K = add-mset b N and KM : image-mset fst K = M and sK : set-mset K ⊆ {(a, b). R a b} using assms unfolding multiset.rel-compp-Grp Grp-def by auto obtain K1 ab where K : K = add-mset ab K1 and b: snd ab = b and K1N : image-mset snd K1 = N using msed-map-invR[OF KN ] by auto obtain M1 where M : M = add-mset (fst ab) M1 and K1M1 : image-mset fst K1 = M1 using msed-map-invL[OF KM [unfolded K ]] by auto have Rab: R (fst ab) b using sK b unfolding K by auto have rel-mset R M1 N using sK K1N K1M1 unfolding K multiset.rel-compp-Grp Grp-def by auto thus ?thesis using M Rab by auto qed lemma rel-mset-imp-rel-mset 0: assumes rel-mset R M N shows rel-mset 0 RMN using assms proof(induct M arbitrary: N rule: measure-induct-rule[of size]) case (less M ) have c: size M = size N using rel-mset-size[OF less.prems] . show ?case proof(cases M = {#}) case True hence N = {#} using c by simp thus ?thesis using True rel-mset 0.Zero by auto next case False then obtain M1 a where M : M = add-mset a M1 by (metis multi-nonempty-split) obtain N1 b where N : N = add-mset b N1 and R: R a b and ms: rel-mset R M1 N1 using msed-rel-invL[OF less.prems[unfolded M ]] by auto have rel-mset 0 R M1 N1 using less.hyps[of M1 N1 ] ms unfolding M by simp thus ?thesis using rel-mset 0.Plus[of R a b, OF R] unfolding MN by simp qed qed lemma rel-mset-rel-mset 0: rel-mset R M N = rel-mset 0 RMN 218 using rel-mset-imp-rel-mset 0 rel-mset 0-imp-rel-mset by auto The main end product for rel-mset: inductive characterization: lemmas rel-mset-induct[case-names empty add, induct pred: rel-mset] = rel-mset 0.induct[unfolded rel-mset-rel-mset 0[symmetric]] 31.18 Size setup lemma multiset-size-o-map: size-multiset g ◦ image-mset f = size-multiset (g ◦ f ) apply (rule ext) subgoal for x by (induct x) auto done setup h BNF-LFP-Size.register-size-global @{type-name multiset} @{const-name size-multiset} @{thm size-multiset-overloaded-def } @{thms size-multiset-empty size-multiset-single size-multiset-union size-empty size-single size-union} @{thms multiset-size-o-map} i hide-const (open) wcount end 32 Bubblesort theory Bubblesort imports ∼∼/src/HOL/Library/Multiset begin This is a version of bubblesort. context linorder begin fun bubble-min where bubble-min [] = [] | bubble-min [x] = [x] | bubble-min (x#xs) = (case bubble-min xs of y#ys ⇒ if x>y then y#x#ys else x#y#ys) lemma size-bubble-min: size(bubble-min xs) = size xs by(induction xs rule: bubble-min.induct)(auto split: list.split) lemma bubble-min-eq-Nil-iff [simp]: bubble-min xs = [] ←→ xs = [] by (metis length-0-conv size-bubble-min) 219 lemma bubble-minD-size: bubble-min (xs) = ys =⇒ size xs = size ys by(auto simp: size-bubble-min) function (sequential) bubblesort where bubblesort [] = [] | bubblesort [x] = [x] | bubblesort xs = (case bubble-min xs of y#ys ⇒ y # bubblesort ys) by pat-completeness auto termination proof show wf (measure size) by simp next fix x1 x2 y :: 0a fix xs ys :: 0a list show bubble-min(x1 #x2 #xs) = y#ys =⇒ (ys, x1 #x2 #xs) ∈ measure size by(auto simp: size-bubble-min dest!: bubble-minD-size split: list.splits if-splits) qed lemma mset-bubble-min: mset (bubble-min xs) = mset xs apply(induction xs rule: bubble-min.induct) apply simp apply simp apply (auto simp: add-eq-conv-ex split: list.split) done lemma bubble-minD-mset: bubble-min (xs) = ys =⇒ mset xs = mset ys by(auto simp: mset-bubble-min) lemma mset-bubblesort: mset (bubblesort xs) = mset xs apply(induction xs rule: bubblesort.induct) apply simp apply simp by(auto split: list.splits if-splits dest: bubble-minD-mset) lemma set-bubblesort: set (bubblesort xs) = set xs by(rule mset-bubblesort[THEN mset-eq-setD]) lemma bubble-min-min: bubble-min xs = y#ys =⇒ z ∈ set ys =⇒ y ≤ z apply(induction xs arbitrary: y ys z rule: bubble-min.induct) apply simp apply simp apply (fastforce split: list.splits if-splits dest!: sym[of a#b for a b]) done lemma sorted-bubblesort: sorted(bubblesort xs) apply(induction xs rule: bubblesort.induct) 220 apply simp apply simp apply (fastforce simp: set-bubblesort split: list.split if-splits intro!: sorted.Cons dest: bubble-min-min) done end end 33 Merge Sort theory MergeSort imports ∼∼/src/HOL/Library/Multiset begin context linorder begin fun merge :: 0a list ⇒ 0a list ⇒ 0a list where merge (x#xs)(y#ys) = (if x ≤ y then x # merge xs (y#ys) else y # merge (x#xs) ys) | merge xs [] = xs | merge [] ys = ys lemma mset-merge [simp]: mset (merge xs ys) = mset xs + mset ys by (induct xs ys rule: merge.induct)(simp-all add: ac-simps) lemma set-merge [simp]: set (merge xs ys) = set xs ∪ set ys by (induct xs ys rule: merge.induct) auto lemma sorted-merge [simp]: sorted (merge xs ys) ←→ sorted xs ∧ sorted ys by (induct xs ys rule: merge.induct)(auto simp add: ball-Un not-le less-le sorted-Cons) fun msort :: 0a list ⇒ 0a list where msort [] = [] | msort [x] = [x] | msort xs = merge (msort (take (size xs div 2 ) xs)) (msort (drop (size xs div 2 ) xs)) lemma sorted-msort: sorted (msort xs) by (induct xs rule: msort.induct) simp-all 221 lemma mset-msort: mset (msort xs) = mset xs by (induct xs rule: msort.induct) (simp-all, metis append-take-drop-id drop-Suc-Cons mset.simps(2 ) mset-append take-Suc-Cons) theorem msort-sort: sort = msort by (rule ext, rule properties-for-sort)(fact mset-msort sorted-msort)+ end end 34 A lemma for Lagrange’s theorem theory Lagrange imports Main begin This theory only contains a single theorem, which is a lemma in Lagrange’s proof that every natural number is the sum of 4 squares. Its sole purpose is to demonstrate ordered rewriting for commutative rings. The enterprising reader might consider proving all of Lagrange’s theorem. definition sq :: 0a::times => 0a where sq x == x∗x The following lemma essentially shows that every natural number is the sum of four squares, provided all prime numbers are. However, this is an abstract theorem about commutative rings. It has, a priori, nothing to do with nat. lemma Lagrange-lemma: fixes x1 :: 0a::comm-ring shows (sq x1 + sq x2 + sq x3 + sq x4 ) ∗ (sq y1 + sq y2 + sq y3 + sq y4 ) = sq (x1 ∗y1 − x2 ∗y2 − x3 ∗y3 − x4 ∗y4 ) + sq (x1 ∗y2 + x2 ∗y1 + x3 ∗y4 − x4 ∗y3 ) + sq (x1 ∗y3 − x2 ∗y4 + x3 ∗y1 + x4 ∗y2 ) + sq (x1 ∗y4 + x2 ∗y3 − x3 ∗y2 + x4 ∗y1 ) by (simp only: sq-def algebra-simps) A challenge by John Harrison. Takes about 12s on a 1.6GHz machine. lemma fixes p1 :: 0a::comm-ring shows (sq p1 + sq q1 + sq r1 + sq s1 + sq t1 + sq u1 + sq v1 + sq w1 ) ∗ (sq p2 + sq q2 + sq r2 + sq s2 + sq t2 + sq u2 + sq v2 + sq w2 ) = sq (p1 ∗p2 − q1 ∗q2 − r1 ∗r2 − s1 ∗s2 − t1 ∗t2 − u1 ∗u2 − v1 ∗v2 − w1 ∗w2 ) + sq (p1 ∗q2 + q1 ∗p2 + r1 ∗s2 − s1 ∗r2 + t1 ∗u2 − u1 ∗t2 − v1 ∗w2 + w1 ∗v2 ) + sq (p1 ∗r2 − q1 ∗s2 + r1 ∗p2 + s1 ∗q2 + t1 ∗v2 + u1 ∗w2 − v1 ∗t2 − w1 ∗u2 ) + sq (p1 ∗s2 + q1 ∗r2 − r1 ∗q2 + s1 ∗p2 + t1 ∗w2 − u1 ∗v2 + v1 ∗u2 − w1 ∗t2 ) + 222 sq (p1 ∗t2 − q1 ∗u2 − r1 ∗v2 − s1 ∗w2 + t1 ∗p2 + u1 ∗q2 + v1 ∗r2 + w1 ∗s2 ) + sq (p1 ∗u2 + q1 ∗t2 − r1 ∗w2 + s1 ∗v2 − t1 ∗q2 + u1 ∗p2 − v1 ∗s2 + w1 ∗r2 ) + sq (p1 ∗v2 + q1 ∗w2 + r1 ∗t2 − s1 ∗u2 − t1 ∗r2 + u1 ∗s2 + v1 ∗p2 − w1 ∗q2 ) + sq (p1 ∗w2 − q1 ∗v2 + r1 ∗u2 + s1 ∗t2 − t1 ∗s2 − u1 ∗r2 + v1 ∗q2 + w1 ∗p2 ) by (simp only: sq-def algebra-simps) end 35 Groebner Basis Examples theory Groebner-Examples imports ∼∼/src/HOL/Groebner-Basis begin 35.1 Basic examples lemma fixes x :: int shows x ˆ 3 = x ˆ 3 apply (tactic hALLGOALS (CONVERSION (Conv.arg-conv (Conv.arg1-conv (Semiring-Normalizer.semiring-normalize-conv @{context}))))i) by (rule refl) lemma fixes x :: int shows (x − (−2 ))ˆ5 = x ˆ 5 + (10 ∗ x ˆ 4 + (40 ∗ x ˆ 3 + (80 ∗ x 2 + (80 ∗ x + 32 )))) apply (tactic hALLGOALS (CONVERSION (Conv.arg-conv (Conv.arg1-conv (Semiring-Normalizer.semiring-normalize-conv @{context}))))i) by (rule refl) schematic-goal fixes x :: int shows (x − (−2 ))ˆ5 ∗ (y − 78 ) ˆ 8 = ?X apply (tactic hALLGOALS (CONVERSION (Conv.arg-conv (Conv.arg1-conv (Semiring-Normalizer.semiring-normalize-conv @{context}))))i) by (rule refl) lemma ((−3 ) ˆ (Suc (Suc (Suc 0 )))) == (X :: 0a::{comm-ring-1 }) apply (simp only: power-Suc power-0 ) apply (simp only: semiring-norm) oops 223 lemma ((x::int) + y)ˆ3 − 1 = (x − z)ˆ2 − 10 =⇒ x = z + 3 =⇒ x = − y by algebra lemma (4 ::nat) + 4 = 3 + 5 by algebra lemma (4 ::int) + 0 = 4 apply algebra? by simp lemma assumes a ∗ x 2 + b ∗ x + c = (0 ::int) and d ∗ x 2 + e ∗ x + f = 0 shows d 2 ∗ c2 − 2 ∗ d ∗ c ∗ a ∗ f + a2 ∗ f 2 − e ∗ d ∗ b ∗ c − e ∗ b ∗ a ∗ f + a ∗ e2 ∗ c + f ∗ d ∗ b2 = 0 using assms by algebra lemma (x::int)ˆ3 − xˆ2 − 5 ∗x − 3 = 0 ←→ (x = 3 ∨ x = −1 ) by algebra theorem x∗ (x 2 − x − 5 ) − 3 = (0 ::int) ←→ (x = 3 ∨ x = −1 ) by algebra lemma fixes x:: 0a::idom shows x 2∗y = x 2 & x∗y2 = y2 ←→ x = 1 & y = 1 | x = 0 & y = 0 by algebra 35.2 Lemmas for Lagrange’s theorem definition sq :: 0a::times => 0a where sq x == x∗x lemma fixes x1 :: 0a::{idom} shows (sq x1 + sq x2 + sq x3 + sq x4 ) ∗ (sq y1 + sq y2 + sq y3 + sq y4 ) = sq (x1 ∗y1 − x2 ∗y2 − x3 ∗y3 − x4 ∗y4 ) + sq (x1 ∗y2 + x2 ∗y1 + x3 ∗y4 − x4 ∗y3 ) + sq (x1 ∗y3 − x2 ∗y4 + x3 ∗y1 + x4 ∗y2 ) + sq (x1 ∗y4 + x2 ∗y3 − x3 ∗y2 + x4 ∗y1 ) by (algebra add: sq-def ) lemma fixes p1 :: 0a::{idom} shows (sq p1 + sq q1 + sq r1 + sq s1 + sq t1 + sq u1 + sq v1 + sq w1 ) ∗ (sq p2 + sq q2 + sq r2 + sq s2 + sq t2 + sq u2 + sq v2 + sq w2 ) = sq (p1 ∗p2 − q1 ∗q2 − r1 ∗r2 − s1 ∗s2 − t1 ∗t2 − u1 ∗u2 − v1 ∗v2 − w1 ∗w2 ) 224 + sq (p1 ∗q2 + q1 ∗p2 + r1 ∗s2 − s1 ∗r2 + t1 ∗u2 − u1 ∗t2 − v1 ∗w2 + w1 ∗v2 ) + sq (p1 ∗r2 − q1 ∗s2 + r1 ∗p2 + s1 ∗q2 + t1 ∗v2 + u1 ∗w2 − v1 ∗t2 − w1 ∗u2 ) + sq (p1 ∗s2 + q1 ∗r2 − r1 ∗q2 + s1 ∗p2 + t1 ∗w2 − u1 ∗v2 + v1 ∗u2 − w1 ∗t2 ) + sq (p1 ∗t2 − q1 ∗u2 − r1 ∗v2 − s1 ∗w2 + t1 ∗p2 + u1 ∗q2 + v1 ∗r2 + w1 ∗s2 ) + sq (p1 ∗u2 + q1 ∗t2 − r1 ∗w2 + s1 ∗v2 − t1 ∗q2 + u1 ∗p2 − v1 ∗s2 + w1 ∗r2 ) + sq (p1 ∗v2 + q1 ∗w2 + r1 ∗t2 − s1 ∗u2 − t1 ∗r2 + u1 ∗s2 + v1 ∗p2 − w1 ∗q2 ) + sq (p1 ∗w2 − q1 ∗v2 + r1 ∗u2 + s1 ∗t2 − t1 ∗s2 − u1 ∗r2 + v1 ∗q2 + w1 ∗p2 ) by (algebra add: sq-def ) 35.3 Colinearity is invariant by rotation type-synonym point = int × int definition collinear ::point ⇒ point ⇒ point ⇒ bool where collinear ≡ λ(Ax,Ay)(Bx,By)(Cx,Cy). ((Ax − Bx) ∗ (By − Cy) = (Ay − By) ∗ (Bx − Cx)) lemma collinear-inv-rotation: assumes collinear (Ax, Ay)(Bx, By)(Cx, Cy) and c2 + s2 = 1 shows collinear (Ax ∗ c − Ay ∗ s, Ay ∗ c + Ax ∗ s) (Bx ∗ c − By ∗ s, By ∗ c + Bx ∗ s)(Cx ∗ c − Cy ∗ s, Cy ∗ c + Cx ∗ s) using assms by (algebra add: collinear-def split-def fst-conv snd-conv) lemma EX (d::int). a∗y − a∗x = n∗d =⇒ EX u v. a∗u + n∗v = 1 =⇒ EX e. y − x = n∗e by algebra end 36 Substitution and Unification theory Unification imports Main begin Implements Manna & Waldinger’s formalization, with Paulson’s simplifica- tions, and some new simplifications by Slind and Krauss. Z Manna & R Waldinger, Deductive Synthesis of the Unification Algorithm. SCP 1 (1981), 5-48 L C Paulson, Verifying the Unification Algorithm in LCF. SCP 5 (1985), 225 143-170 K Slind, Reasoning about Terminating Functional Programs, Ph.D. thesis, TUM, 1999, Sect. 5.8 A Krauss, Partial and Nested Recursive Function Definitions in Higher- Order Logic, JAR 44(4):303-336, 2010. Sect. 6.3 36.1 Terms Binary trees with leaves that are constants or variables. datatype 0a trm = Var 0a | Const 0a | Comb 0a trm 0a trm (infix · 60 ) primrec vars-of :: 0a trm ⇒ 0a set where vars-of (Var v) = {v} | vars-of (Const c) = {} | vars-of (M · N ) = vars-of M ∪ vars-of N fun occs :: 0a trm ⇒ 0a trm ⇒ bool (infixl ≺ 54 ) where u ≺ Var v ←→ False | u ≺ Const c ←→ False | u ≺ M · N ←→ u = M ∨ u = N ∨ u ≺ M ∨ u ≺ N lemma finite-vars-of [intro]: finite (vars-of t) by (induct t) simp-all lemma vars-iff-occseq: x ∈ vars-of t ←→ Var x ≺ t ∨ Var x = t by (induct t) auto lemma occs-vars-subset: M ≺ N =⇒ vars-of M ⊆ vars-of N by (induct N ) auto 36.2 Substitutions type-synonym 0a subst = ( 0a × 0a trm) list fun assoc :: 0a ⇒ 0b ⇒ ( 0a × 0b) list ⇒ 0b where assoc x d [] = d | assoc x d ((p,q)#t) = (if x = p then q else assoc x d t) primrec subst :: 0a trm ⇒ 0a subst ⇒ 0a trm (infixl 55 ) where (Var v) s = assoc v (Var v) s 226 | (Const c) s = (Const c) | (M · N ) s = (M s) · (N s) . definition subst-eq (infixr = 52 ) where . s1 = s2 ←→ (∀ t. t s1 = t s2 ) 0 0 0 fun comp :: a subst ⇒ a subst ⇒ a subst (infixl ♦ 56 ) where [] ♦ bl = bl | ((a,b)# al) ♦ bl = (a, b bl)#(al ♦ bl) lemma subst-Nil[simp]: t [] = t by (induct t) auto lemma subst-mono: t ≺ u =⇒ t s ≺ u s by (induct u) auto lemma agreement:(t r = t s) ←→ (∀ v ∈ vars-of t. Var v r = Var v s) by (induct t) auto lemma repl-invariance: v ∈/ vars-of t =⇒ t (v,u)# s = t s by (simp add: agreement) lemma remove-var: v ∈/ vars-of s =⇒ v ∈/ vars-of (t [(v, s)]) by (induct t) simp-all . lemma subst-refl[iff ]: s = s by (auto simp:subst-eq-def ) . . lemma subst-sym[sym]: [[s1 = s2 ]] =⇒ s2 = s1 by (auto simp:subst-eq-def ) . . . lemma subst-trans[trans]: [[s1 = s2 ; s2 = s3 ]] =⇒ s1 = s3 by (auto simp:subst-eq-def ) lemma subst-no-occs: ¬ Var v ≺ t =⇒ Var v 6= t =⇒ t [(v,s)] = t by (induct t) auto lemma comp-Nil[simp]: σ ♦ [] = σ by (induct σ) auto lemma subst-comp[simp]: t (r ♦ s) = t r s proof (induct t) case (Var v) thus ?case by (induct r) auto qed auto 227 . lemma subst-eq-intro[intro]: (Vt. t σ = t ϑ) =⇒ σ = ϑ by (auto simp:subst-eq-def ) . lemma subst-eq-dest[dest]: s1 = s2 =⇒ t s1 = t s2 by (auto simp:subst-eq-def ) . lemma comp-assoc:(a ♦ b) ♦ c = a ♦ (b ♦ c) by auto . 0 . 0 . 0 0 lemma subst-cong: [[σ = σ ; ϑ = ϑ ]] =⇒ (σ ♦ ϑ) = (σ ♦ ϑ ) by (auto simp: subst-eq-def ) . lemma var-self : [(v, Var v)] = [] proof fix t show t [(v, Var v)] = t [] by (induct t) simp-all qed . lemma var-same[simp]: [(v, t)] = [] ←→ t = Var v by (metis assoc.simps(2 ) subst.simps(1 ) subst-eq-def var-self ) 36.3 Unifiers and Most General Unifiers definition Unifier :: 0a subst ⇒ 0a trm ⇒ 0a trm ⇒ bool where Unifier σ t u ←→ (t σ = u σ) definition MGU :: 0a subst ⇒ 0a trm ⇒ 0a trm ⇒ bool where MGU σ t u ←→ . Unifier σ t u ∧ (∀ ϑ. Unifier ϑ t u −→ (∃ γ. ϑ = σ ♦ γ)) lemma MGUI [intro]: V . [[t σ = u σ; ϑ. t ϑ = u ϑ =⇒ ∃ γ. ϑ = σ ♦ γ]] =⇒MGU σt u by (simp only:Unifier-def MGU-def , auto) lemma MGU-sym[sym]: MGU σ s t =⇒ MGU σ t s by (auto simp:MGU-def Unifier-def ) lemma MGU-is-Unifier: MGU σ t u =⇒ Unifier σ t u unfolding MGU-def by (rule conjunct1 ) lemma MGU-Var: assumes ¬ Var v ≺ t shows MGU [(v,t)] (Var v) t proof (intro MGUI exI ) show Var v [(v,t)] = t [(v,t)] using assms by (metis assoc .simps(2 ) repl-invariance subst.simps(1 ) subst-Nil vars-iff-occseq) 228 next fix ϑ assume th: Var v ϑ = t ϑ . show ϑ = [(v,t)] ♦ ϑ proof fix s show s ϑ = s [(v,t)] ♦ ϑ using th by (induct s) auto qed qed lemma MGU-Const: MGU [] (Const c)(Const d) ←→ c = d by (auto simp: MGU-def Unifier-def ) 36.4 The unification algorithm function unify :: 0a trm ⇒ 0a trm ⇒ 0a subst option where unify (Const c)(M · N ) = None | unify (M · N )(Const c) = None | unify (Const c)(Var v) = Some [(v, Const c)] | unify (M · N )(Var v) = (if Var v ≺ M · N then None else Some [(v, M · N )]) | unify (Var v) M = (if Var v ≺ M then None else Some [(v, M )]) | unify (Const c)(Const d) = (if c=d then Some [] else None) | unify (M · N )(M 0 · N 0) = (case unify M M 0 of None ⇒ None | Some ϑ ⇒ (case unify (N ϑ)(N 0 ϑ) of None ⇒ None | Some σ ⇒ Some (ϑ ♦ σ))) by pat-completeness auto 36.5 Properties used in termination proof Elimination of variables by a substitution: definition elim σ v ≡ ∀ t. v ∈/ vars-of (t σ) lemma elim-intro[intro]: (Vt. v ∈/ vars-of (t σ)) =⇒ elim σ v by (auto simp:elim-def ) lemma elim-dest[dest]: elim σ v =⇒ v ∈/ vars-of (t σ) by (auto simp:elim-def ) . lemma elim-eq: σ = ϑ =⇒ elim σ x = elim ϑ x by (auto simp:elim-def subst-eq-def ) lemma occs-elim: ¬ Var v ≺ t 229 . =⇒ elim [(v,t)] v ∨ [(v,t)] = [] by (metis elim-intro remove-var var-same vars-iff-occseq) The result of a unification never introduces new variables: declare unify.psimps[simp] lemma unify-vars: assumes unify-dom (M , N ) assumes unify M N = Some σ shows vars-of (t σ) ⊆ vars-of M ∪ vars-of N ∪ vars-of t (is ?P M N σ t) using assms proof (induct M N arbitrary:σ t) case (3 c v) hence σ = [(v, Const c)] by simp thus ?case by (induct t) auto next case (4 M N v) hence ¬ Var v ≺ M · N by auto with 4 have σ = [(v, M ·N )] by simp thus ?case by (induct t) auto next case (5 v M ) hence ¬ Var v ≺ M by auto with 5 have σ = [(v, M )] by simp thus ?case by (induct t) auto next case (7 M N M 0 N 0 σ) then obtain ϑ1 ϑ2 where unify M M 0 = Some ϑ1 and unify (N ϑ1 )(N 0 ϑ1 ) = Some ϑ2 and σ: σ = ϑ1♦ ϑ2 and ih1 : Vt. ?P M M 0 ϑ1 t and ih2 : Vt. ?P (N ϑ1 )(N 0 ϑ1 ) ϑ2 t by (auto split:option.split-asm) show ?case proof fix v assume a: v ∈ vars-of (t σ) show v ∈ vars-of (M · N ) ∪ vars-of (M 0 · N 0) ∪ vars-of t proof (cases v ∈/ vars-of M ∧ v ∈/ vars-of M 0 ∧ v ∈/ vars-of N ∧ v ∈/ vars-of N 0) case True with ih1 have l:Vt. v ∈ vars-of (t ϑ1 ) =⇒ v ∈ vars-of t by auto from a and ih2 [where t=t ϑ1 ] 0 have v ∈ vars-of (N ϑ1 ) ∪ vars-of (N ϑ1 ) 230 ∨ v ∈ vars-of (t ϑ1 ) unfolding σ by auto hence v ∈ vars-of t proof assume v ∈ vars-of (N ϑ1 ) ∪ vars-of (N 0 ϑ1 ) with True show ?thesis by (auto dest:l) next assume v ∈ vars-of (t ϑ1 ) thus ?thesis by (rule l) qed thus ?thesis by auto qed auto qed qed (auto split: if-split-asm) The result of a unification is either the identity substitution or it eliminates a variable from one of the terms: lemma unify-eliminates: assumes unify-dom (M , N ) assumes unify M N = Some σ . shows (∃ v∈vars-of M ∪ vars-of N . elim σ v) ∨ σ = [] (is ?P M N σ) using assms proof (induct M N arbitrary:σ) case 1 thus ?case by simp next case 2 thus ?case by simp next case (3 c v) have no-occs: ¬ Var v ≺ Const c by simp with 3 have σ = [(v, Const c)] by simp with occs-elim[OF no-occs] show ?case by auto next case (4 M N v) hence no-occs: ¬ Var v ≺ M · N by auto with 4 have σ = [(v, M ·N )] by simp with occs-elim[OF no-occs] show ?case by auto next case (5 v M ) hence no-occs: ¬ Var v ≺ M by auto with 5 have σ = [(v, M )] by simp with occs-elim[OF no-occs] show ?case by auto next case (6 c d) thus ?case by (cases c = d) auto 231 next case (7 M N M 0 N 0 σ) then obtain ϑ1 ϑ2 where unify M M 0 = Some ϑ1 and unify (N ϑ1 )(N 0 ϑ1 ) = Some ϑ2 and σ: σ = ϑ1♦ ϑ2 and ih1 : ?P M M 0 ϑ1 and ih2 : ?P (N ϑ1 )(N 0 ϑ1 ) ϑ2 by (auto split:option .split-asm ) 0 0 from hunify-dom (M · N , M · N )i have unify-dom (M , M 0) by (rule accp-downward)(rule unify-rel.intros) hence no-new-vars: Vt. vars-of (t ϑ1 ) ⊆ vars-of M ∪ vars-of M 0 ∪ vars-of t 0 by (rule unify-vars )(rule hunify M M = Some ϑ1 i) from ih2 show ?case proof assume ∃ v∈vars-of (N ϑ1 ) ∪ vars-of (N 0 ϑ1 ). elim ϑ2 v then obtain v where v∈vars-of (N ϑ1 ) ∪ vars-of (N 0 ϑ1 ) and el: elim ϑ2 v by auto with no-new-vars show ?thesis unfolding σ by (auto simp:elim-def ) next . assume empty[simp]: ϑ2 = [] . have σ = (ϑ1 ♦ []) unfolding σ by (rule subst-cong) auto . also have ... = ϑ1 by auto . finally have σ = ϑ1 . from ih1 show ?thesis proof assume ∃ v∈vars-of M ∪ vars-of M 0. elim ϑ1 v . with elim-eq[OF hσ = ϑ1 i] show ?thesis by auto next . note hσ = ϑ1 i . also assume ϑ1 = [] finally show ?thesis .. qed qed qed declare unify.psimps[simp del] 232 36.6 Termination proof termination unify proof let ?R = measures [λ(M ,N ). card (vars-of M ∪ vars-of N ), λ(M , N ). size M ] show wf ?R by simp fix MNM 0 N 0 :: 0a trm show ((M , M 0), (M · N , M 0 · N 0)) ∈ ?R — Inner call by (rule measures-lesseq)(auto intro: card-mono) fix ϑ — Outer call assume inner: unify-dom (M , M 0) unify M M 0 = Some ϑ from unify-eliminates[OF inner] show ((N ϑ, N 0 ϑ), (M · N , M 0 · N 0)) ∈?R proof — Either a variable is eliminated . . . assume (∃ v∈vars-of M ∪ vars-of M 0. elim ϑ v) then obtain v where elim ϑ v and v∈vars-of M ∪ vars-of M 0 by auto with unify-vars[OF inner] have vars-of (N ϑ) ∪ vars-of (N 0 ϑ) 0 0 ⊂ vars-of (M ·N) ∪ vars-of (M ·N) by auto thus ?thesis by (auto intro!: measures-less intro: psubset-card-mono) next — Or the substitution is empty . assume ϑ = [] hence N ϑ = N 0 0 and N ϑ = N by auto thus ?thesis by (auto intro!: measures-less intro: psubset-card-mono) qed qed 36.7 Unification returns a Most General Unifier lemma unify-computes-MGU : unify M N = Some σ =⇒ MGU σ MN proof (induct M N arbitrary: σ rule: unify.induct) case (7 M N M 0 N 0 σ) — The interesting case then obtain ϑ1 ϑ2 where unify M M 0 = Some ϑ1 233 and unify (N ϑ1 )(N 0 ϑ1 ) = Some ϑ2 and σ: σ = ϑ1♦ ϑ2 and MGU-inner: MGU ϑ1 M M 0 and MGU-outer: MGU ϑ2 (N ϑ1 )(N 0 ϑ1 ) by (auto split:option.split-asm) show ?case proof from MGU-inner and MGU-outer have M ϑ1 = M 0 ϑ1 0 and N ϑ1 ϑ2 = N ϑ1 ϑ2 unfolding MGU-def Unifier-def by auto thus M · N σ = M 0 · N 0 σ unfolding σ by simp next fix σ 0 assume M · N σ 0 = M 0 · N 0 σ 0 0 0 0 hence M σ = M σ 0 0 0 and Ns: N σ = N σ by auto with MGU-inner obtain δ 0 . where eqv: σ = ϑ1 ♦ δ unfolding MGU-def Unifier-def by auto from Ns have N ϑ1 δ = N 0 ϑ1 δ by (simp add:subst-eq-dest [OF eqv]) with MGU-outer obtain % . where eqv2 : δ = ϑ2 ♦ % unfolding MGU-def Unifier-def by auto 0 . have σ = σ ♦ % unfolding σ by (rule subst-eq-intro, auto simp:subst-eq-dest[OF eqv] subst-eq-dest[OF eqv2 ]) 0 . thus ∃ γ. σ = σ ♦ γ .. qed qed (auto simp: MGU-Const intro: MGU-Var MGU-Var[symmetric] split: if-split-asm) 36.8 Unification returns Idempotent Substitution definition Idem :: 0a subst ⇒ bool . where Idem s ←→ (s ♦ s) = s lemma Idem-Nil [iff ]: Idem [] by (simp add: Idem-def ) lemma Var-Idem: assumes ∼ (Var v ≺ t) shows Idem [(v,t)] 234 unfolding Idem-def proof from assms have [simp]: t [(v, t)] = t by (metis assoc.simps(2 ) subst .simps(1 ) subst-no-occs) fix s show s [(v, t)] ♦ [(v, t)] = s [(v, t)] by (induct s) auto qed lemma Unifier-Idem-subst: Idem(r) =⇒ Unifier s (t r)(u r) =⇒ Unifier (r ♦ s)(t r)(u r) by (simp add: Idem-def Unifier-def subst-eq-def ) lemma Idem-comp: Idem r =⇒ Unifier s (t r)(u r) =⇒ . (!!q. Unifier q (t r)( u r) =⇒ s ♦ q = q) =⇒ Idem (r ♦ s) apply (frule Unifier-Idem-subst, blast) apply (force simp add: Idem-def subst-eq-def ) done theorem unify-gives-Idem: unify M N = Some σ =⇒ Idem σ proof (induct M N arbitrary: σ rule: unify.induct) case (7 M M 0 NN 0 σ) then obtain ϑ1 ϑ2 where unify M N = Some ϑ1 and ϑ2 : unify (M 0 ϑ1 )(N 0 ϑ1 ) = Some ϑ2 and σ: σ = ϑ1 ♦ ϑ2 and Idem ϑ1 and Idem ϑ2 by (auto split: option.split-asm) from ϑ2 have Unifier ϑ2 (M 0 ϑ1 )(N 0 ϑ1 ) by (rule unify-computes-MGU[THEN MGU-is-Unifier ]) with hIdem ϑ1 i show Idem σ unfolding σ proof (rule Idem-comp) fix σ assume Unifier σ (M 0 ϑ1 )(N 0 ϑ1 ) . with ϑ2 obtain γ where σ: σ = ϑ2 ♦ γ using unify-computes-MGU MGU-def by blast . have ϑ2 σ = ϑ2 (ϑ2 γ) by (rule subst-cong)(auto simp: σ) ♦ . ♦ ♦ also have ... = (ϑ2 ϑ2 ) γ by (rule comp-assoc[symmetric]) . ♦ ♦ also have ... = ϑ2 ♦ γ by (rule subst-cong)(auto simp: hIdem ϑ2 i[unfolded Idem-def ]) 235 . also have ... = σ by (rule σ[symmetric]) . finally show ϑ2 ♦ σ = σ . qed qed (auto intro!: Var-Idem split: option.splits if-splits) end 37 Primitive Recursive Functions theory Primrec imports Main begin Proof adopted from Nora Szasz, A Machine Checked Proof that Ackermann’s Function is not Primitive Recursive, In: Huet & Plotkin, eds., Logical Environments (CUP, 1993), 317-338. See also E. Mendelson, Introduction to Mathematical Logic. (Van Nostrand, 1964), page 250, exercise 11. 37.1 Ackermann’s Function fun ack :: nat => nat => nat where ack 0 n = Suc n | ack (Suc m) 0 = ack m 1 | ack (Suc m)(Suc n) = ack m (ack (Suc m) n) PROPERTY A 4 lemma less-ack2 [iff ]: j < ack i j by (induct i j rule: ack.induct) simp-all PROPERTY A 5-, the single-step lemma lemma ack-less-ack-Suc2 [iff ]: ack i j < ack i (Suc j ) by (induct i j rule: ack.induct) simp-all PROPERTY A 5, monotonicity for < lemma ack-less-mono2 : j < k ==> ack i j < ack i k using lift-Suc-mono-less[where f = ack i] by (metis ack-less-ack-Suc2 ) PROPERTY A 5’, monotonicity for ≤ lemma ack-le-mono2 : j ≤ k ==> ack i j ≤ ack i k apply (simp add: order-le-less) apply (blast intro: ack-less-mono2 ) done PROPERTY A 6 lemma ack2-le-ack1 [iff ]: ack i (Suc j ) ≤ ack (Suc i) j 236 proof (induct j ) case 0 show ?case by simp next case (Suc j ) show ?case by (auto intro!: ack-le-mono2 ) (metis Suc Suc-leI Suc-lessI less-ack2 linorder-not-less) qed PROPERTY A 7-, the single-step lemma lemma ack-less-ack-Suc1 [iff ]: ack i j < ack (Suc i) j by (blast intro: ack-less-mono2 less-le-trans) PROPERTY A 4’? Extra lemma needed for CONSTANT case, constant functions lemma less-ack1 [iff ]: i < ack i j apply (induct i) apply simp-all apply (blast intro: Suc-leI le-less-trans) done PROPERTY A 8 lemma ack-1 [simp]: ack (Suc 0 ) j = j + 2 by (induct j ) simp-all PROPERTY A 9. The unary 1 and 2 in ack is essential for the rewriting. lemma ack-2 [simp]: ack (Suc (Suc 0 )) j = 2 ∗ j + 3 by (induct j ) simp-all PROPERTY A 7, monotonicity for < [not clear why ack-1 is now needed first!] lemma ack-less-mono1-aux: ack i k < ack (Suc (i +i 0)) k proof (induct i k rule: ack.induct) case (1 n) show ?case by (simp, metis ack-less-ack-Suc1 less-ack2 less-trans-Suc) next case (2 m) thus ?case by simp next case (3 m n) thus ?case by (simp, blast intro: less-trans ack-less-mono2 ) qed lemma ack-less-mono1 : i < j ==> ack i k < ack j k apply (drule less-imp-Suc-add) apply (blast intro!: ack-less-mono1-aux) done PROPERTY A 7’, monotonicity for ≤ lemma ack-le-mono1 : i ≤ j ==> ack i k ≤ ack j k 237 apply (simp add: order-le-less) apply (blast intro: ack-less-mono1 ) done PROPERTY A 10 lemma ack-nest-bound: ack i1 (ack i2 j ) < ack (2 + (i1 + i2 )) j apply simp apply (rule ack2-le-ack1 [THEN [2 ] less-le-trans]) apply simp apply (rule le-add1 [THEN ack-le-mono1 , THEN le-less-trans]) apply (rule ack-less-mono1 [THEN ack-less-mono2 ]) apply (simp add: le-imp-less-Suc le-add2 ) done PROPERTY A 11 lemma ack-add-bound: ack i1 j + ack i2 j < ack (4 + (i1 + i2 )) j apply (rule less-trans [of - ack (Suc (Suc 0 )) (ack (i1 + i2 ) j )]) prefer 2 apply (rule ack-nest-bound [THEN less-le-trans]) apply (simp add: Suc3-eq-add-3 ) apply simp apply (cut-tac i = i1 and m1 = i2 and k = j in le-add1 [THEN ack-le-mono1 ]) apply (cut-tac i = i2 and m1 = i1 and k = j in le-add2 [THEN ack-le-mono1 ]) apply auto done PROPERTY A 12. Article uses existential quantifier but the ALF proof used k + 4. Quantified version must be nested ∃ k 0. ∀ i j . ... lemma ack-add-bound2 : i < ack k j ==> i + j < ack (4 + k) j apply (rule less-trans [of - ack k j + ack 0 j ]) apply (blast intro: add-less-mono) apply (rule ack-add-bound [THEN less-le-trans]) apply simp done 37.2 Primitive Recursive Functions primrec hd0 :: nat list => nat where hd0 [] = 0 | hd0 (m # ms) = m Inductive definition of the set of primitive recursive functions of type nat list ⇒ nat. definition SC :: nat list => nat where SC l = Suc (hd0 l) definition CONSTANT :: nat => nat list => nat where CONSTANT k l = k 238 definition PROJ :: nat => nat list => nat where PROJ i l = hd0 (drop i l) definition COMP :: (nat list => nat) => (nat list => nat) list => nat list => nat where COMP g fs l = g (map (λf . f l) fs) definition PREC :: (nat list => nat) => (nat list => nat) => nat list => nat where PREC f g l = (case l of [] => 0 | x # l 0 => rec-nat (f l 0)(λy r. g (r # y # l 0)) x) — Note that g is applied first to PREC f g y and then to y! inductive PRIMREC :: (nat list => nat) => bool where SC : PRIMREC SC | CONSTANT : PRIMREC (CONSTANT k) | PROJ : PRIMREC (PROJ i) | COMP: PRIMREC g ==> ∀ f ∈ set fs. PRIMREC f ==> PRIMREC (COMP g fs) | PREC : PRIMREC f ==> PRIMREC g ==> PRIMREC (PREC f g) Useful special cases of evaluation lemma SC [simp]: SC (x # l) = Suc x by (simp add: SC-def ) lemma CONSTANT [simp]: CONSTANT k l = k by (simp add: CONSTANT-def ) lemma PROJ-0 [simp]: PROJ 0 (x # l) = x by (simp add: PROJ-def ) lemma COMP-1 [simp]: COMP g [f ] l = g [f l] by (simp add: COMP-def ) lemma PREC-0 [simp]: PREC f g (0 # l) = f l by (simp add: PREC-def ) lemma PREC-Suc [simp]: PREC f g (Suc x # l) = g (PREC f g (x # l)# x # l) by (simp add: PREC-def ) MAIN RESULT lemma SC-case: SC l < ack 1 (sum-list l) apply (unfold SC-def ) apply (induct l) apply (simp-all add: le-add1 le-imp-less-Suc) 239 done lemma CONSTANT-case: CONSTANT k l < ack k (sum-list l) by simp lemma PROJ-case: PROJ i l < ack 0 (sum-list l) apply (simp add: PROJ-def ) apply (induct l arbitrary:i) apply (auto simp add: drop-Cons split: nat.split) apply (blast intro: less-le-trans le-add2 ) done COMP case lemma COMP-map-aux: ∀ f ∈ set fs. PRIMREC f ∧ (∃ kf . ∀ l. f l < ack kf (sum-list l)) ==> ∃ k. ∀ l. sum-list (map (λf . f l) fs) < ack k (sum-list l) apply (induct fs) apply (rule-tac x = 0 in exI ) apply simp apply simp apply (blast intro: add-less-mono ack-add-bound less-trans) done lemma COMP-case: ∀ l. g l < ack kg (sum-list l) ==> ∀ f ∈ set fs. PRIMREC f ∧ (∃ kf . ∀ l. f l < ack kf (sum-list l)) ==> ∃ k. ∀ l. COMP g fs l < ack k (sum-list l) apply (unfold COMP-def ) apply (drule COMP-map-aux) apply (meson ack-less-mono2 ack-nest-bound less-trans) done PREC case lemma PREC-case-aux: ∀ l. f l + sum-list l < ack kf (sum-list l) ==> ∀ l. g l + sum-list l < ack kg (sum-list l) ==> PREC f g l + sum-list l < ack (Suc (kf + kg)) (sum-list l) apply (unfold PREC-def ) apply (case-tac l) apply simp-all apply (blast intro: less-trans) apply (erule ssubst) — get rid of the needless assumption apply (induct-tac a) apply simp-all base case apply (blast intro: le-add1 [THEN le-imp-less-Suc, THEN ack-less-mono1 ] less-trans) induction step 240 apply (rule Suc-leI [THEN le-less-trans]) apply (rule le-refl [THEN add-le-mono, THEN le-less-trans]) prefer 2 apply (erule spec) apply (simp add: le-add2 ) final part of the simplification apply simp apply (rule le-add2 [THEN ack-le-mono1 , THEN le-less-trans]) apply (erule ack-less-mono2 ) done lemma PREC-case: ∀ l. f l < ack kf (sum-list l) ==> ∀ l. g l < ack kg (sum-list l) ==> ∃ k. ∀ l. PREC f g l < ack k (sum-list l) by (metis le-less-trans [OF le-add1 PREC-case-aux] ack-add-bound2 ) lemma ack-bounds-PRIMREC : PRIMREC f ==> ∃ k. ∀ l. f l < ack k (sum-list l) apply (erule PRIMREC .induct) apply (blast intro: SC-case CONSTANT-case PROJ-case COMP-case PREC-case)+ done theorem ack-not-PRIMREC : ¬ PRIMREC (λl. case l of [] => 0 | x # l 0 => ack x x) apply (rule notI ) apply (erule ack-bounds-PRIMREC [THEN exE]) apply (rule less-irrefl [THEN notE]) apply (drule-tac x = [x] in spec) apply simp done end 38 The Full Theorem of Tarski theory Tarski imports Main ∼∼/src/HOL/Library/FuncSet begin Minimal version of lattice theory plus the full theorem of Tarski: The fixed- points of a complete lattice themselves form a complete lattice. Illustrates first-class theories, using the Sigma representation of structures. Tidied and converted to Isar by lcp. record 0a potype = pset :: 0a set order :: ( 0a ∗ 0a) set 241 definition monotone :: [ 0a => 0a, 0a set, ( 0a ∗ 0a)set] => bool where monotone f A r = (∀ x∈A. ∀ y∈A. (x, y): r −−> ((f x), (f y)) : r) definition least :: [ 0a => bool, 0a potype] => 0a where least P po = (SOME x. x: pset po & P x & (∀ y ∈ pset po. P y −−> (x,y): order po)) definition greatest :: [ 0a => bool, 0a potype] => 0a where greatest P po = (SOME x. x: pset po & P x & (∀ y ∈ pset po. P y −−> (y,x): order po)) definition lub :: [ 0a set, 0a potype] => 0a where lub S po = least (%x. ∀ y∈S. (y,x): order po) po definition glb :: [ 0a set, 0a potype] => 0a where glb S po = greatest (%x. ∀ y∈S. (x,y): order po) po definition isLub :: [ 0a set, 0a potype, 0a] => bool where isLub S po = (%L. (L: pset po &(∀ y∈S. (y,L): order po)& (∀ z∈pset po. (∀ y∈S. (y,z): order po) −−> (L,z): order po))) definition isGlb :: [ 0a set, 0a potype, 0a] => bool where isGlb S po = (%G. (G: pset po &(∀ y∈S. (G,y): order po)& (∀ z ∈ pset po. (∀ y∈S. (z,y): order po) −−> (z,G): order po))) definition fix :: [( 0a => 0a), 0a set] => 0a set where fix f A = {x. x: A & f x = x} definition interval :: [( 0a∗ 0a) set, 0a, 0a ] => 0a set where interval r a b = {x. (a,x): r &(x,b): r} definition Bot :: 0a potype => 0a where Bot po = least (%x. True) po definition Top :: 0a potype => 0a where Top po = greatest (%x. True) po 242 definition PartialOrder :: ( 0a potype) set where PartialOrder = {P. refl-on (pset P)(order P)& antisym (order P)& trans (order P)} definition CompleteLattice :: ( 0a potype) set where CompleteLattice = {cl. cl: PartialOrder & (∀ S. S ⊆ pset cl −−> (∃ L. isLub S cl L)) & (∀ S. S ⊆ pset cl −−> (∃ G. isGlb S cl G))} definition CLF-set :: ( 0a potype ∗ ( 0a => 0a)) set where CLF-set = (SIGMA cl: CompleteLattice. {f . f : pset cl → pset cl & monotone f (pset cl)(order cl)}) definition induced :: [ 0a set, ( 0a ∗ 0a) set] => ( 0a ∗ 0a)set where induced A r = {(a,b). a : A & b: A &(a,b): r} definition sublattice :: ( 0a potype ∗ 0a set)set where sublattice = (SIGMA cl: CompleteLattice. {S. S ⊆ pset cl & (| pset = S, order = induced S (order cl) |): CompleteLattice}) abbreviation sublat :: [ 0a set, 0a potype] => bool (- <<= - [51 ,50 ]50 ) where S <<= cl == S : sublattice ‘‘ {cl} definition dual :: 0a potype => 0a potype where dual po = (| pset = pset po, order = converse (order po) |) locale S = fixes cl :: 0a potype and A :: 0a set and r :: ( 0a ∗ 0a) set defines A-def : A == pset cl and r-def : r == order cl locale PO = S + assumes cl-po: cl : PartialOrder locale CL = S + assumes cl-co: cl : CompleteLattice 243 sublocale CL < po?: PO apply (simp-all add: A-def r-def ) apply unfold-locales using cl-co unfolding CompleteLattice-def by auto locale CLF = S + fixes f :: 0a => 0a and P :: 0a set assumes f-cl:(cl,f ): CLF-set defines P-def : P == fix f A sublocale CLF < cl?: CL apply (simp-all add: A-def r-def ) apply unfold-locales using f-cl unfolding CLF-set-def by auto locale Tarski = CLF + fixes Y :: 0a set and intY1 :: 0a set and v :: 0a assumes Y-ss: Y ⊆ P defines intY1-def : intY1 == interval r (lub Y cl)(Top cl) and v-def : v == glb {x. ((%x: intY1 . f x) x, x): induced intY1 r & x: intY1 } (| pset=intY1 , order=induced intY1 r|) 38.1 Partial Order lemma (in PO) dual: PO (dual cl) apply unfold-locales using cl-po unfolding PartialOrder-def dual-def by auto lemma (in PO) PO-imp-refl-on [simp]: refl-on A r apply (insert cl-po) apply (simp add: PartialOrder-def A-def r-def ) done lemma (in PO) PO-imp-sym [simp]: antisym r apply (insert cl-po) apply (simp add: PartialOrder-def r-def ) done lemma (in PO) PO-imp-trans [simp]: trans r 244 apply (insert cl-po) apply (simp add: PartialOrder-def r-def ) done lemma (in PO) reflE: x ∈ A ==> (x, x) ∈ r apply (insert cl-po) apply (simp add: PartialOrder-def refl-on-def A-def r-def ) done lemma (in PO) antisymE:[| (a, b) ∈ r;(b, a) ∈ r |] ==> a = b apply (insert cl-po) apply (simp add: PartialOrder-def antisym-def r-def ) done lemma (in PO) transE:[| (a, b) ∈ r;(b, c) ∈ r|] ==> (a,c) ∈ r apply (insert cl-po) apply (simp add: PartialOrder-def r-def ) apply (unfold trans-def , fast) done lemma (in PO) monotoneE: [| monotone f A r; x ∈ A; y ∈ A;(x, y) ∈ r |] ==> (f x, f y) ∈ r by (simp add: monotone-def ) lemma (in PO) po-subset-po: S ⊆ A ==> (| pset = S, order = induced S r |) ∈ PartialOrder apply (simp (no-asm) add: PartialOrder-def ) apply auto — refl apply (simp add: refl-on-def induced-def ) apply (blast intro: reflE) — antisym apply (simp add: antisym-def induced-def ) apply (blast intro: antisymE) — trans apply (simp add: trans-def induced-def ) apply (blast intro: transE) done lemma (in PO) indE:[| (x, y) ∈ induced S r; S ⊆ A |] ==> (x, y) ∈ r by (simp add: add: induced-def ) lemma (in PO) indI :[| (x, y) ∈ r; x ∈ S; y ∈ S |] ==> (x, y) ∈ induced S r by (simp add: add: induced-def ) lemma (in CL) CL-imp-ex-isLub: S ⊆ A ==> ∃ L. isLub S cl L apply (insert cl-co) apply (simp add: CompleteLattice-def A-def ) done 245 declare (in CL) cl-co [simp] lemma isLub-lub:(∃ L. isLub S cl L) = isLub S cl (lub S cl) by (simp add: lub-def least-def isLub-def some-eq-ex [symmetric]) lemma isGlb-glb:(∃ G. isGlb S cl G) = isGlb S cl (glb S cl) by (simp add: glb-def greatest-def isGlb-def some-eq-ex [symmetric]) lemma isGlb-dual-isLub: isGlb S cl = isLub S (dual cl) by (simp add: isLub-def isGlb-def dual-def converse-unfold) lemma isLub-dual-isGlb: isLub S cl = isGlb S (dual cl) by (simp add: isLub-def isGlb-def dual-def converse-unfold) lemma (in PO) dualPO: dual cl ∈ PartialOrder apply (insert cl-po) apply (simp add: PartialOrder-def dual-def refl-on-converse trans-converse antisym-converse) done lemma Rdual: ∀ S. (S ⊆ A −−>( ∃ L. isLub S (| pset = A, order = r|) L)) ==> ∀ S. (S ⊆ A −−> (∃ G. isGlb S (| pset = A, order = r|) G)) apply safe apply (rule-tac x = lub {y. y ∈ A &(∀ k ∈ S. (y, k) ∈ r)} (|pset = A, order = r|) in exI ) apply (drule-tac x = {y. y ∈ A &(∀ k ∈ S. (y,k) ∈ r) } in spec) apply (drule mp, fast) apply (simp add: isLub-lub isGlb-def ) apply (simp add: isLub-def , blast) done lemma lub-dual-glb: lub S cl = glb S (dual cl) by (simp add: lub-def glb-def least-def greatest-def dual-def converse-unfold) lemma glb-dual-lub: glb S cl = lub S (dual cl) by (simp add: lub-def glb-def least-def greatest-def dual-def converse-unfold) lemma CL-subset-PO: CompleteLattice ⊆ PartialOrder by (simp add: PartialOrder-def CompleteLattice-def , fast) lemmas CL-imp-PO = CL-subset-PO [THEN subsetD] lemma (in CL) CO-refl-on: refl-on A r by (rule PO-imp-refl-on) 246 lemma (in CL) CO-antisym: antisym r by (rule PO-imp-sym) lemma (in CL) CO-trans: trans r by (rule PO-imp-trans) lemma CompleteLatticeI : [| po ∈ PartialOrder;(∀ S. S ⊆ pset po −−> (∃ L. isLub S po L)); (∀ S. S ⊆ pset po −−> (∃ G. isGlb S po G))|] ==> po ∈ CompleteLattice apply (unfold CompleteLattice-def , blast) done lemma (in CL) CL-dualCL: dual cl ∈ CompleteLattice apply (insert cl-co) apply (simp add: CompleteLattice-def dual-def ) apply (fold dual-def ) apply (simp add: isLub-dual-isGlb [symmetric] isGlb-dual-isLub [symmetric] dualPO) done lemma (in PO) dualA-iff : pset (dual cl) = pset cl by (simp add: dual-def ) lemma (in PO) dualr-iff : ((x, y) ∈ (order(dual cl))) = ((y, x) ∈ order cl) by (simp add: dual-def ) lemma (in PO) monotone-dual: monotone f (pset cl)(order cl) ==> monotone f (pset (dual cl)) (order(dual cl)) by (simp add: monotone-def dualA-iff dualr-iff ) lemma (in PO) interval-dual: [| x ∈ A; y ∈ A|] ==> interval r x y = interval (order(dual cl)) y x apply (simp add: interval-def dualr-iff ) apply (fold r-def , fast) done lemma (in PO) trans: (x, y) ∈ r =⇒ (y, z) ∈ r =⇒ (x, z) ∈ r using cl-po apply (auto simp add: PartialOrder-def r-def ) unfolding trans-def by blast lemma (in PO) interval-not-empty: interval r a b 6= {} ==> (a, b) ∈ r apply (simp add: interval-def ) using trans by blast lemma (in PO) interval-imp-mem: x ∈ interval r a b ==> (a, x) ∈ r 247 by (simp add: interval-def ) lemma (in PO) left-in-interval: [| a ∈ A; b ∈ A; interval r a b 6= {} |] ==> a ∈ interval r a b apply (simp (no-asm-simp) add: interval-def ) apply (simp add: PO-imp-trans interval-not-empty) apply (simp add: reflE) done lemma (in PO) right-in-interval: [| a ∈ A; b ∈ A; interval r a b 6= {} |] ==> b ∈ interval r a b apply (simp (no-asm-simp) add: interval-def ) apply (simp add: PO-imp-trans interval-not-empty) apply (simp add: reflE) done 38.2 sublattice lemma (in PO) sublattice-imp-CL: S <<= cl ==> (| pset = S, order = induced S r |) ∈ CompleteLattice by (simp add: sublattice-def CompleteLattice-def r-def ) lemma (in CL) sublatticeI : [| S ⊆ A;(| pset = S, order = induced S r |) ∈ CompleteLattice |] ==> S <<= cl by (simp add: sublattice-def A-def r-def ) lemma (in CL) dual: CL (dual cl) apply unfold-locales using cl-co unfolding CompleteLattice-def apply (simp add: dualPO isGlb-dual-isLub [symmetric] isLub-dual-isGlb [symmetric] dualA-iff ) done 38.3 lub lemma (in CL) lub-unique:[| S ⊆ A; isLub S cl x; isLub S cl L|] ==> x = L apply (rule antisymE) apply (auto simp add: isLub-def r-def ) done lemma (in CL) lub-upper:[|S ⊆ A; x ∈ S|] ==> (x, lub S cl) ∈ r apply (rule CL-imp-ex-isLub [THEN exE], assumption) apply (unfold lub-def least-def ) apply (rule some-equality [THEN ssubst]) apply (simp add: isLub-def ) apply (simp add: lub-unique A-def isLub-def ) apply (simp add: isLub-def r-def ) done 248 lemma (in CL) lub-least: [| S ⊆ A; L ∈ A; ∀ x ∈ S. (x,L) ∈ r |] ==> (lub S cl, L) ∈ r apply (rule CL-imp-ex-isLub [THEN exE], assumption) apply (unfold lub-def least-def ) apply (rule-tac s=x in some-equality [THEN ssubst]) apply (simp add: isLub-def ) apply (simp add: lub-unique A-def isLub-def ) apply (simp add: isLub-def r-def A-def ) done lemma (in CL) lub-in-lattice: S ⊆ A ==> lub S cl ∈ A apply (rule CL-imp-ex-isLub [THEN exE], assumption) apply (unfold lub-def least-def ) apply (subst some-equality) apply (simp add: isLub-def ) prefer 2 apply (simp add: isLub-def A-def ) apply (simp add: lub-unique A-def isLub-def ) done lemma (in CL) lubI : [| S ⊆ A; L ∈ A; ∀ x ∈ S. (x,L) ∈ r; ∀ z ∈ A. (∀ y ∈ S. (y,z) ∈ r) −−> (L,z) ∈ r |] ==> L = lub S cl apply (rule lub-unique, assumption) apply (simp add: isLub-def A-def r-def ) apply (unfold isLub-def ) apply (rule conjI ) apply (fold A-def r-def ) apply (rule lub-in-lattice, assumption) apply (simp add: lub-upper lub-least) done lemma (in CL) lubIa:[| S ⊆ A; isLub S cl L |] ==> L = lub S cl by (simp add: lubI isLub-def A-def r-def ) lemma (in CL) isLub-in-lattice: isLub S cl L ==> L ∈ A by (simp add: isLub-def A-def ) lemma (in CL) isLub-upper:[|isLub S cl L; y ∈ S|] ==> (y, L) ∈ r by (simp add: isLub-def r-def ) lemma (in CL) isLub-least: [| isLub S cl L; z ∈ A; ∀ y ∈ S. (y, z) ∈ r|] ==> (L, z) ∈ r by (simp add: isLub-def A-def r-def ) lemma (in CL) isLubI : [| L ∈ A; ∀ y ∈ S. (y, L) ∈ r; (∀ z ∈ A. (∀ y ∈ S. (y, z):r) −−> (L, z) ∈ r)|] ==> isLub S cl L by (simp add: isLub-def A-def r-def ) 249 38.4 glb lemma (in CL) glb-in-lattice: S ⊆ A ==> glb S cl ∈ A apply (subst glb-dual-lub) apply (simp add: A-def ) apply (rule dualA-iff [THEN subst]) apply (rule CL.lub-in-lattice) apply (rule dual) apply (simp add: dualA-iff ) done lemma (in CL) glb-lower:[|S ⊆ A; x ∈ S|] ==> (glb S cl, x) ∈ r apply (subst glb-dual-lub) apply (simp add: r-def ) apply (rule dualr-iff [THEN subst]) apply (rule CL.lub-upper) apply (rule dual) apply (simp add: dualA-iff A-def , assumption) done Reduce the sublattice property by using substructural properties; abandoned see Tarski-4 .ML. lemma (in CLF )[simp]: f : pset cl → pset cl & monotone f (pset cl)(order cl) apply (insert f-cl) apply (simp add: CLF-set-def ) done declare (in CLF ) f-cl [simp] lemma (in CLF ) f-in-funcset: f ∈ A → A by (simp add: A-def ) lemma (in CLF ) monotone-f : monotone f A r by (simp add: A-def r-def ) lemma (in CLF ) CLF-dual:(dual cl, f ) ∈ CLF-set apply (simp add: CLF-set-def CL-dualCL monotone-dual) apply (simp add: dualA-iff ) done lemma (in CLF ) dual: CLF (dual cl) f apply (rule CLF .intro) apply (rule CLF-dual) done 250 38.5 fixed points lemma fix-subset: fix f A ⊆ A by (simp add: fix-def , fast) lemma fix-imp-eq: x ∈ fix f A ==> f x = x by (simp add: fix-def ) lemma fixf-subset: [| A ⊆ B; x ∈ fix (%y: A. f y) A |] ==> x ∈ fix f B by (simp add: fix-def , auto) 38.6 lemmas for Tarski, lub lemma (in CLF ) lubH-le-flubH : H = {x. (x, f x) ∈ r & x ∈ A} ==> (lub H cl, f (lub H cl)) ∈ r apply (rule lub-least, fast) apply (rule f-in-funcset [THEN funcset-mem]) apply (rule lub-in-lattice, fast) — ∀ x:H . (x, f (lub H r)) ∈ r apply (rule ballI ) apply (rule transE) — instantiates (x, ???z) ∈ order cl to (x, f x), — because of the def of H apply fast — so it remains to show (f x, f (lub H cl)) ∈ r apply (rule-tac f = f in monotoneE) apply (rule monotone-f , fast) apply (rule lub-in-lattice, fast) apply (rule lub-upper, fast) apply assumption done lemma (in CLF ) flubH-le-lubH : [| H = {x. (x, f x) ∈ r & x ∈ A} |] ==> (f (lub H cl), lub H cl) ∈ r apply (rule lub-upper, fast) apply (rule-tac t = H in ssubst, assumption) apply (rule CollectI ) apply (rule conjI ) apply (rule-tac [2 ] f-in-funcset [THEN funcset-mem]) apply (rule-tac [2 ] lub-in-lattice) prefer 2 apply fast apply (rule-tac f = f in monotoneE) apply (rule monotone-f ) apply (blast intro: lub-in-lattice) apply (blast intro: lub-in-lattice f-in-funcset [THEN funcset-mem]) apply (simp add: lubH-le-flubH ) done lemma (in CLF ) lubH-is-fixp: 251 H = {x. (x, f x) ∈ r & x ∈ A} ==> lub H cl ∈ fix f A apply (simp add: fix-def ) apply (rule conjI ) apply (rule lub-in-lattice, fast) apply (rule antisymE) apply (simp add: flubH-le-lubH ) apply (simp add: lubH-le-flubH ) done lemma (in CLF ) fix-in-H : [| H = {x. (x, f x) ∈ r & x ∈ A}; x ∈ P |] ==> x ∈ H by (simp add: P-def fix-imp-eq [of - f A] reflE CO-refl-on fix-subset [of f A, THEN subsetD]) lemma (in CLF ) fixf-le-lubH : H = {x. (x, f x) ∈ r & x ∈ A} ==> ∀ x ∈ fix f A. (x, lub H cl) ∈ r apply (rule ballI ) apply (rule lub-upper, fast) apply (rule fix-in-H ) apply (simp-all add: P-def ) done lemma (in CLF ) lubH-least-fixf : H = {x. (x, f x) ∈ r & x ∈ A} ==> ∀ L. (∀ y ∈ fix f A. (y,L) ∈ r) −−> (lub H cl, L) ∈ r apply (rule allI ) apply (rule impI ) apply (erule bspec) apply (rule lubH-is-fixp, assumption) done 38.7 Tarski fixpoint theorem 1, first part lemma (in CLF ) T-thm-1-lub: lub P cl = lub {x. (x, f x) ∈ r & x ∈ A} cl apply (rule sym) apply (simp add: P-def ) apply (rule lubI ) apply (rule fix-subset) apply (rule lub-in-lattice, fast) apply (simp add: fixf-le-lubH ) apply (simp add: lubH-least-fixf ) done lemma (in CLF ) glbH-is-fixp: H = {x. (f x, x) ∈ r & x ∈ A} ==> glb H cl ∈ P — Tarski for glb apply (simp add: glb-dual-lub P-def A-def r-def ) apply (rule dualA-iff [THEN subst]) apply (rule CLF .lubH-is-fixp) apply (rule dual) 252 apply (simp add: dualr-iff dualA-iff ) done lemma (in CLF ) T-thm-1-glb: glb P cl = glb {x. (f x, x) ∈ r & x ∈ A} cl apply (simp add: glb-dual-lub P-def A-def r-def ) apply (rule dualA-iff [THEN subst]) apply (simp add: CLF .T-thm-1-lub [of - f , OF dual] dualPO CL-dualCL CLF-dual dualr-iff ) done 38.8 interval lemma (in CLF ) rel-imp-elem:(x, y) ∈ r ==> x ∈ A apply (insert CO-refl-on) apply (simp add: refl-on-def , blast) done lemma (in CLF ) interval-subset:[| a ∈ A; b ∈ A |] ==> interval r a b ⊆ A apply (simp add: interval-def ) apply (blast intro: rel-imp-elem) done lemma (in CLF ) intervalI : [| (a, x) ∈ r;(x, b) ∈ r |] ==> x ∈ interval r a b by (simp add: interval-def ) lemma (in CLF ) interval-lemma1 : [| S ⊆ interval r a b; x ∈ S |] ==> (a, x) ∈ r by (unfold interval-def , fast) lemma (in CLF ) interval-lemma2 : [| S ⊆ interval r a b; x ∈ S |] ==> (x, b) ∈ r by (unfold interval-def , fast) lemma (in CLF ) a-less-lub: [| S ⊆ A; S 6= {}; ∀ x ∈ S. (a,x) ∈ r; ∀ y ∈ S. (y, L) ∈ r |] ==> (a,L) ∈ r by (blast intro: transE) lemma (in CLF ) glb-less-b: [| S ⊆ A; S 6= {}; ∀ x ∈ S. (x,b) ∈ r; ∀ y ∈ S. (G, y) ∈ r |] ==> (G,b) ∈ r by (blast intro: transE) lemma (in CLF ) S-intv-cl: [| a ∈ A; b ∈ A; S ⊆ interval r a b |]==> S ⊆ A by (simp add: subset-trans [OF - interval-subset]) lemma (in CLF ) L-in-interval: 253 [| a ∈ A; b ∈ A; S ⊆ interval r a b; S 6= {}; isLub S cl L; interval r a b 6= {} |] ==> L ∈ interval r a b apply (rule intervalI ) apply (rule a-less-lub) prefer 2 apply assumption apply (simp add: S-intv-cl) apply (rule ballI ) apply (simp add: interval-lemma1 ) apply (simp add: isLub-upper) —(L, b) ∈ r apply (simp add: isLub-least interval-lemma2 ) done lemma (in CLF ) G-in-interval: [| a ∈ A; b ∈ A; interval r a b 6= {}; S ⊆ interval r a b; isGlb S cl G; S 6= {} |] ==> G ∈ interval r a b apply (simp add: interval-dual) apply (simp add: CLF .L-in-interval [of - f , OF dual] dualA-iff A-def isGlb-dual-isLub) done lemma (in CLF ) intervalPO: [| a ∈ A; b ∈ A; interval r a b 6= {} |] ==> (| pset = interval r a b, order = induced (interval r a b) r |) ∈ PartialOrder apply (rule po-subset-po) apply (simp add: interval-subset) done lemma (in CLF ) intv-CL-lub: [| a ∈ A; b ∈ A; interval r a b 6= {} |] ==> ∀ S. S ⊆ interval r a b −−> (∃ L. isLub S (| pset = interval r a b, order = induced (interval r a b) r |) L) apply (intro strip) apply (frule S-intv-cl [THEN CL-imp-ex-isLub]) prefer 2 apply assumption apply assumption apply (erule exE) — define the lub for the interval as apply (rule-tac x = if S = {} then a else L in exI ) apply (simp (no-asm-simp) add: isLub-def split del: if-split) apply (intro impI conjI ) —(if S = {} then a else L) ∈ interval r a b apply (simp add: CL-imp-PO L-in-interval) apply (simp add: left-in-interval) — lub prop 1 apply (case-tac S = {}) — S = {}, y ∈ S = False => everything 254 apply fast — S 6= {} apply simp — ∀ y:S. (y, L) ∈ induced (interval r a b) r apply (rule ballI ) apply (simp add: induced-def L-in-interval) apply (rule conjI ) apply (rule subsetD) apply (simp add: S-intv-cl, assumption) apply (simp add: isLub-upper) — ∀ z:interval r a b. (∀ y:S. (y, z) ∈ induced (interval r a b) r −→ (if S = {} then a else L, z) ∈ induced (interval r a b) r apply (rule ballI ) apply (rule impI ) apply (case-tac S = {}) — S = {} apply simp apply (simp add: induced-def interval-def ) apply (rule conjI ) apply (rule reflE, assumption) apply (rule interval-not-empty) apply (simp add: interval-def ) — S 6= {} apply simp apply (simp add: induced-def L-in-interval) apply (rule isLub-least, assumption) apply (rule subsetD) prefer 2 apply assumption apply (simp add: S-intv-cl, fast) done lemmas (in CLF ) intv-CL-glb = intv-CL-lub [THEN Rdual] lemma (in CLF ) interval-is-sublattice: [| a ∈ A; b ∈ A; interval r a b 6= {} |] ==> interval r a b <<= cl apply (rule sublatticeI ) apply (simp add: interval-subset) apply (rule CompleteLatticeI ) apply (simp add: intervalPO) apply (simp add: intv-CL-lub) apply (simp add: intv-CL-glb) done lemmas (in CLF ) interv-is-compl-latt = interval-is-sublattice [THEN sublattice-imp-CL] 255 38.9 Top and Bottom lemma (in CLF ) Top-dual-Bot: Top cl = Bot (dual cl) by (simp add: Top-def Bot-def least-def greatest-def dualA-iff dualr-iff ) lemma (in CLF ) Bot-dual-Top: Bot cl = Top (dual cl) by (simp add: Top-def Bot-def least-def greatest-def dualA-iff dualr-iff ) lemma (in CLF ) Bot-in-lattice: Bot cl ∈ A apply (simp add: Bot-def least-def ) apply (rule-tac a=glb A cl in someI2 ) apply (simp-all add: glb-in-lattice glb-lower r-def [symmetric] A-def [symmetric]) done lemma (in CLF ) Top-in-lattice: Top cl ∈ A apply (simp add: Top-dual-Bot A-def ) apply (rule dualA-iff [THEN subst]) apply (rule CLF .Bot-in-lattice [OF dual]) done lemma (in CLF ) Top-prop: x ∈ A ==> (x, Top cl) ∈ r apply (simp add: Top-def greatest-def ) apply (rule-tac a=lub A cl in someI2 ) apply (rule someI2 ) apply (simp-all add: lub-in-lattice lub-upper r-def [symmetric] A-def [symmetric]) done lemma (in CLF ) Bot-prop: x ∈ A ==> (Bot cl, x) ∈ r apply (simp add: Bot-dual-Top r-def ) apply (rule dualr-iff [THEN subst]) apply (rule CLF .Top-prop [OF dual]) apply (simp add: dualA-iff A-def ) done lemma (in CLF ) Top-intv-not-empty: x ∈ A ==> interval r x (Top cl) 6= {} apply (rule notI ) apply (drule-tac a = Top cl in equals0D) apply (simp add: interval-def ) apply (simp add: refl-on-def Top-in-lattice Top-prop) done lemma (in CLF ) Bot-intv-not-empty: x ∈ A ==> interval r (Bot cl) x 6= {} apply (simp add: Bot-dual-Top) apply (subst interval-dual) prefer 2 apply assumption apply (simp add: A-def ) apply (rule dualA-iff [THEN subst]) apply (rule CLF .Top-in-lattice [OF dual]) 256 apply (rule CLF .Top-intv-not-empty [OF dual]) apply (simp add: dualA-iff A-def ) done 38.10 fixed points form a partial order lemma (in CLF ) fixf-po:(| pset = P, order = induced P r|) ∈ PartialOrder by (simp add: P-def fix-subset po-subset-po) lemma (in Tarski) Y-subset-A: Y ⊆ A apply (rule subset-trans [OF - fix-subset]) apply (rule Y-ss [simplified P-def ]) done lemma (in Tarski) lubY-in-A: lub Y cl ∈ A by (rule Y-subset-A [THEN lub-in-lattice]) lemma (in Tarski) lubY-le-flubY :(lub Y cl, f (lub Y cl)) ∈ r apply (rule lub-least) apply (rule Y-subset-A) apply (rule f-in-funcset [THEN funcset-mem]) apply (rule lubY-in-A) — Y ⊆ P ==> f x = x apply (rule ballI ) apply (rule-tac t = x in fix-imp-eq [THEN subst]) apply (erule Y-ss [simplified P-def , THEN subsetD]) — reduce (f x, f (lub Y cl)) ∈ r to (x, lub Y cl) ∈ r by monotonicity apply (rule-tac f = f in monotoneE) apply (rule monotone-f ) apply (simp add: Y-subset-A [THEN subsetD]) apply (rule lubY-in-A) apply (simp add: lub-upper Y-subset-A) done lemma (in Tarski) intY1-subset: intY1 ⊆ A apply (unfold intY1-def ) apply (rule interval-subset) apply (rule lubY-in-A) apply (rule Top-in-lattice) done lemmas (in Tarski) intY1-elem = intY1-subset [THEN subsetD] lemma (in Tarski) intY1-f-closed: x ∈ intY1 =⇒ f x ∈ intY1 apply (simp add: intY1-def interval-def ) apply (rule conjI ) apply (rule transE) apply (rule lubY-le-flubY ) —(f (lub Y cl), f x) ∈ r 257 apply (rule-tac f =f in monotoneE) apply (rule monotone-f ) apply (rule lubY-in-A) apply (simp add: intY1-def interval-def intY1-elem) apply (simp add: intY1-def interval-def ) —(f x, Top cl) ∈ r apply (rule Top-prop) apply (rule f-in-funcset [THEN funcset-mem]) apply (simp add: intY1-def interval-def intY1-elem) done lemma (in Tarski) intY1-mono: monotone (%x: intY1 . f x) intY1 (induced intY1 r) apply (auto simp add: monotone-def induced-def intY1-f-closed) apply (blast intro: intY1-elem monotone-f [THEN monotoneE]) done lemma (in Tarski) intY1-is-cl: (| pset = intY1 , order = induced intY1 r |) ∈ CompleteLattice apply (unfold intY1-def ) apply (rule interv-is-compl-latt) apply (rule lubY-in-A) apply (rule Top-in-lattice) apply (rule Top-intv-not-empty) apply (rule lubY-in-A) done lemma (in Tarski) v-in-P: v ∈ P apply (unfold P-def ) apply (rule-tac A = intY1 in fixf-subset) apply (rule intY1-subset) unfolding v-def apply (rule CLF .glbH-is-fixp [OF CLF .intro, unfolded CLF-set-def , of (|pset = intY1 , order = induced intY1 r|), simplified]) apply auto apply (rule intY1-is-cl) apply (erule intY1-f-closed) apply (rule intY1-mono) done lemma (in Tarski) z-in-interval: [| z ∈ P; ∀ y∈Y . (y, z) ∈ induced P r |] ==> z ∈ intY1 apply (unfold intY1-def P-def ) apply (rule intervalI ) prefer 2 apply (erule fix-subset [THEN subsetD, THEN Top-prop]) apply (rule lub-least) apply (rule Y-subset-A) apply (fast elim!: fix-subset [THEN subsetD]) 258 apply (simp add: induced-def ) done lemma (in Tarski) f 0z-in-int-rel:[| z ∈ P; ∀ y∈Y . (y, z) ∈ induced P r |] ==> ((%x: intY1 . f x) z, z) ∈ induced intY1 r apply (simp add: induced-def intY1-f-closed z-in-interval P-def ) apply (simp add: fix-imp-eq [of - f A] fix-subset [of f A, THEN subsetD] reflE) done lemma (in Tarski) tarski-full-lemma: ∃ L. isLub Y (| pset = P, order = induced P r |) L apply (rule-tac x = v in exI ) apply (simp add: isLub-def ) — v ∈ P apply (simp add: v-in-P) apply (rule conjI ) — v is lub — 1 . ∀ y:Y . (y, v) ∈ induced P r apply (rule ballI ) apply (simp add: induced-def subsetD v-in-P) apply (rule conjI ) apply (erule Y-ss [THEN subsetD]) apply (rule-tac b = lub Y cl in transE) apply (rule lub-upper) apply (rule Y-subset-A, assumption) apply (rule-tac b = Top cl in interval-imp-mem) apply (simp add: v-def ) apply (fold intY1-def ) apply (rule CL.glb-in-lattice [OF CL.intro [OF intY1-is-cl], simplified]) apply auto apply (rule indI ) prefer 3 apply assumption prefer 2 apply (simp add: v-in-P) apply (unfold v-def ) apply (rule indE) apply (rule-tac [2 ] intY1-subset) apply (rule CL.glb-lower [OF CL.intro [OF intY1-is-cl], simplified]) apply (simp add: CL-imp-PO intY1-is-cl) apply force apply (simp add: induced-def intY1-f-closed z-in-interval) apply (simp add: P-def fix-imp-eq [of - f A] reflE fix-subset [of f A, THEN subsetD]) done lemma CompleteLatticeI-simp: [| (| pset = A, order = r |) ∈ PartialOrder; ∀ S. S ⊆ A −−> (∃ L. isLub S (| pset = A, order = r |) L) |] ==> (| pset = A, order = r |) ∈ CompleteLattice 259 by (simp add: CompleteLatticeI Rdual) theorem (in CLF ) Tarski-full: (| pset = P, order = induced P r|) ∈ CompleteLattice apply (rule CompleteLatticeI-simp) apply (rule fixf-po, clarify) apply (simp add: P-def A-def r-def ) apply (rule Tarski.tarski-full-lemma [OF Tarski.intro [OF - Tarski-axioms.intro]]) proof − show CLF cl f .. qed end 39 Classical Predicate Calculus Problems theory Classical imports Main begin 39.1 Traditional Classical Reasoner The machine ”griffon” mentioned below is a 2.5GHz Power Mac G5. Taken from FOL/Classical.thy. When porting examples from first-order logic, beware of the precedence of = versus ↔. lemma (P −−> Q | R) −−> (P−−>Q) | (P−−>R) by blast If and only if lemma (P=Q) = (Q = (P::bool)) by blast lemma ∼ (P = (∼P)) by blast Sample problems from F. J. Pelletier, Seventy-Five Problems for Testing Automatic Theorem Provers, J. Automated Reasoning 2 (1986), 191-216. Errata, JAR 4 (1988), 236-236. The hardest problems – judging by experience with several theorem provers, including matrix ones – are 34 and 43. 39.1.1 Pelletier’s examples 1 lemma (P−−>Q) = (∼Q −−> ∼P) by blast 2 lemma (∼ ∼ P) = P 260 by blast 3 lemma ∼(P−−>Q) −−> (Q−−>P) by blast 4 lemma (∼P−−>Q) = (∼Q −−> P) by blast 5 lemma ((P|Q)−−>(P|R)) −−> (P|(Q−−>R)) by blast 6 lemma P | ∼ P by blast 7 lemma P | ∼ ∼ ∼ P by blast 8. Peirce’s law lemma ((P−−>Q) −−> P) −−> P by blast 9 lemma ((P|Q)&(∼P|Q)&(P| ∼Q)) −−> ∼ (∼P | ∼Q) by blast 10 lemma (Q−−>R)&(R−−>P&Q)&(P−−>Q|R) −−> (P=Q) by blast 11. Proved in each direction (incorrectly, says Pelletier!!) lemma P=(P::bool) by blast 12. ”Dijkstra’s law” lemma ((P = Q) = R) = (P = (Q = R)) by blast 13. Distributive law lemma (P | (Q & R)) = ((P | Q)&(P | R)) by blast 14 261 lemma (P = Q) = ((Q | ∼P)&(∼Q|P)) by blast 15 lemma (P −−> Q) = (∼P | Q) by blast 16 lemma (P−−>Q) | (Q−−>P) by blast 17 lemma ((P &(Q−−>R))−−>S) = ((∼P | Q | S)&(∼P | ∼R | S)) by blast 39.1.2 Classical Logic: examples with quantifiers lemma (∀ x. P(x)& Q(x)) = ((∀ x. P(x)) & (∀ x. Q(x))) by blast lemma (∃ x. P−−>Q(x)) = (P −−> (∃ x. Q(x))) by blast lemma (∃ x. P(x)−−>Q) = ((∀ x. P(x)) −−> Q) by blast lemma ((∀ x. P(x)) | Q) = (∀ x. P(x) | Q) by blast From Wishnu Prasetya lemma (∀ s. q(s) −−> r(s)) & ∼r(s)&(∀ s. ∼r(s)& ∼q(s) −−> p(t) | q(t)) −−> p(t) | r(t) by blast 39.1.3 Problems requiring quantifier duplication Theorem B of Peter Andrews, Theorem Proving via General Matings, JACM 28 (1981). lemma (∃ x. ∀ y. P(x) = P(y)) −−> ((∃ x. P(x)) = (∀ y. P(y))) by blast Needs multiple instantiation of the quantifier. lemma (∀ x. P(x)−−>P(f (x))) & P(d)−−>P(f (f (f (d)))) by blast Needs double instantiation of the quantifier lemma ∃ x. P(x) −−> P(a)& P(b) 262 by blast lemma ∃ z. P(z) −−> (∀ x. P(x)) by blast lemma ∃ x. (∃ y. P(y)) −−> P(x) by blast 39.1.4 Hard examples with quantifiers Problem 18 lemma ∃ y. ∀ x. P(y)−−>P(x) by blast Problem 19 lemma ∃ x. ∀ y z. (P(y)−−>Q(z)) −−> (P(x)−−>Q(x)) by blast Problem 20 lemma (∀ x y. ∃ z. ∀ w. (P(x)&Q(y)−−>R(z)&S(w))) −−> (∃ x y. P(x)& Q(y)) −−> (∃ z. R(z)) by blast Problem 21 lemma (∃ x. P−−>Q(x)) & (∃ x. Q(x)−−>P) −−> (∃ x. P=Q(x)) by blast Problem 22 lemma (∀ x. P = Q(x)) −−> (P = (∀ x. Q(x))) by blast Problem 23 lemma (∀ x. P | Q(x)) = (P | (∀ x. Q(x))) by blast Problem 24 lemma ∼(∃ x. S(x)&Q(x)) & (∀ x. P(x) −−> Q(x)|R(x)) & (∼(∃ x. P(x)) −−> (∃ x. Q(x))) & (∀ x. Q(x)|R(x) −−> S(x)) −−> (∃ x. P(x)&R(x)) by blast Problem 25 lemma (∃ x. P(x)) & (∀ x. L(x) −−> ∼ (M (x)& R(x))) & (∀ x. P(x) −−> (M (x)& L(x))) & ((∀ x. P(x)−−>Q(x)) | (∃ x. P(x)&R(x))) −−> (∃ x. Q(x)&P(x)) 263 by blast Problem 26 lemma ((∃ x. p(x)) = (∃ x. q(x))) & (∀ x. ∀ y. p(x)& q(y) −−> (r(x) = s(y))) −−> ((∀ x. p(x)−−>r(x)) = (∀ x. q(x)−−>s(x))) by blast Problem 27 lemma (∃ x. P(x)& ∼Q(x)) & (∀ x. P(x) −−> R(x)) & (∀ x. M (x)& L(x) −−> P(x)) & ((∃ x. R(x)& ∼ Q(x)) −−> (∀ x. L(x) −−> ∼ R(x))) −−> (∀ x. M (x) −−> ∼L(x)) by blast Problem 28. AMENDED lemma (∀ x. P(x) −−> (∀ x. Q(x))) & ((∀ x. Q(x)|R(x)) −−> (∃ x. Q(x)&S(x))) & ((∃ x. S(x)) −−> (∀ x. L(x) −−> M (x))) −−> (∀ x. P(x)& L(x) −−> M (x)) by blast Problem 29. Essentially the same as Principia Mathematica *11.71 lemma (∃ x. F (x)) & (∃ y. G(y)) −−> ( ((∀ x. F (x)−−>H (x)) & (∀ y. G(y)−−>J (y))) = (∀ x y. F (x)& G(y) −−> H (x)& J (y))) by blast Problem 30 lemma (∀ x. P(x) | Q(x) −−> ∼ R(x)) & (∀ x. (Q(x) −−> ∼ S(x)) −−> P(x)& R(x)) −−> (∀ x. S(x)) by blast Problem 31 lemma ∼(∃ x. P(x)&(Q(x) | R(x))) & (∃ x. L(x)& P(x)) & (∀ x. ∼ R(x) −−> M (x)) −−> (∃ x. L(x)& M (x)) by blast Problem 32 lemma (∀ x. P(x)&(Q(x)|R(x))−−>S(x)) & (∀ x. S(x)& R(x) −−> L(x)) & (∀ x. M (x) −−> R(x)) −−> (∀ x. P(x)& M (x) −−> L(x)) by blast 264 Problem 33 lemma (∀ x. P(a)&(P(x)−−>P(b))−−>P(c)) = (∀ x. (∼P(a) | P(x) | P(c)) & (∼P(a) | ∼P(b) | P(c))) by blast Problem 34 AMENDED (TWICE!!) Andrews’s challenge lemma ((∃ x. ∀ y. p(x) = p(y)) = ((∃ x. q(x)) = (∀ y. p(y)))) = ((∃ x. ∀ y. q(x) = q(y)) = ((∃ x. p(x)) = (∀ y. q(y)))) by blast Problem 35 lemma ∃ x y. P x y −−> (∀ u v. P u v) by blast Problem 36 lemma (∀ x. ∃ y. J x y)& (∀ x. ∃ y. G x y)& (∀ x y. J x y | G x y −−> (∀ z. J y z | G y z −−> H x z)) −−> (∀ x. ∃ y. H x y) by blast Problem 37 lemma (∀ z. ∃ w. ∀ x. ∃ y. (P x z −−>P y w)& P y z &(P y w −−> (∃ u. Q u w))) & (∀ x z. ∼(P x z) −−> (∃ y. Q y z)) & ((∃ x y. Q x y) −−> (∀ x. R x x)) −−> (∀ x. ∃ y. R x y) by blast Problem 38 lemma (∀ x. p(a)&(p(x) −−> (∃ y. p(y)& r x y)) −−> (∃ z. ∃ w. p(z)& r x w & r w z)) = (∀ x. (∼p(a) | p(x) | (∃ z. ∃ w. p(z)& r x w & r w z)) & (∼p(a) | ∼(∃ y. p(y)& r x y) | (∃ z. ∃ w. p(z)& r x w & r w z))) by blast Problem 39 lemma ∼ (∃ x. ∀ y. F y x = (∼ F y y)) by blast Problem 40. AMENDED 265 lemma (∃ y. ∀ x. F x y = F x x) −−> ∼ (∀ x. ∃ y. ∀ z. F z y = (∼ F z x)) by blast Problem 41 lemma (∀ z. ∃ y. ∀ x. f x y = (f x z & ∼ f x x)) −−> ∼ (∃ z. ∀ x. f x z) by blast Problem 42 lemma ∼ (∃ y. ∀ x. p x y = (∼ (∃ z. p x z & p z x))) by blast Problem 43!! lemma (∀ x:: 0a. ∀ y:: 0a. q x y = (∀ z. p z x = (p z y::bool))) −−> (∀ x. (∀ y. q x y = (q y x::bool))) by blast Problem 44 lemma (∀ x. f (x) −−> (∃ y. g(y)& h x y &(∃ y. g(y)& ∼ h x y))) & (∃ x. j (x)&(∀ y. g(y) −−> h x y)) −−> (∃ x. j (x)& ∼f (x)) by blast Problem 45 lemma (∀ x. f (x)&(∀ y. g(y)& h x y −−> j x y) −−> (∀ y. g(y)& h x y −−> k(y))) & ∼ (∃ y. l(y)& k(y)) & (∃ x. f (x)&(∀ y. h x y −−> l(y)) &(∀ y. g(y)& h x y −−> j x y)) −−> (∃ x. f (x)& ∼ (∃ y. g(y)& h x y)) by blast 39.1.5 Problems (mainly) involving equality or functions Problem 48 lemma (a=b | c=d)&(a=c | b=d) −−> a=d | b=c by blast Problem 49 NOT PROVED AUTOMATICALLY. Hard because it involves substitution for Vars the type constraint ensures that x,y,z have the same type as a,b,u. lemma (∃ x y:: 0a. ∀ z. z=x | z=y)& P(a)& P(b)&(∼a=b) −−> (∀ u:: 0a. P(u)) by metis 266 Problem 50. (What has this to do with equality?) lemma (∀ x. P a x | (∀ y. P x y)) −−> (∃ x. ∀ y. P x y) by blast Problem 51 lemma (∃ z w. ∀ x y. P x y = (x=z & y=w)) −−> (∃ z. ∀ x. ∃ w. (∀ y. P x y = (y=w)) = (x=z)) by blast Problem 52. Almost the same as 51. lemma (∃ z w. ∀ x y. P x y = (x=z & y=w)) −−> (∃ w. ∀ y. ∃ z. (∀ x. P x y = (x=z)) = (y=w)) by blast Problem 55 Non-equational version, from Manthey and Bry, CADE-9 (Springer, 1988). fast DISCOVERS who killed Agatha. schematic-goal lives(agatha)& lives(butler)& lives(charles)& (killed agatha agatha | killed butler agatha | killed charles agatha)& (∀ x y. killed x y −−> hates x y & ∼richer x y)& (∀ x. hates agatha x −−> ∼hates charles x)& (hates agatha agatha & hates agatha charles)& (∀ x. lives(x)& ∼richer x agatha −−> hates butler x)& (∀ x. hates agatha x −−> hates butler x)& (∀ x. ∼hates x agatha | ∼hates x butler | ∼hates x charles) −−> killed ?who agatha by fast Problem 56 lemma (∀ x. (∃ y. P(y)& x=f (y)) −−> P(x)) = (∀ x. P(x) −−> P(f (x))) by blast Problem 57 lemma P (f a b)(f b c)& P (f b c)(f a c)& (∀ x y z. P x y & P y z −−> P x z) −−> P (f a b)(f a c) by blast Problem 58 NOT PROVED AUTOMATICALLY lemma (∀ x y. f (x)=g(y)) −−> (∀ x y. f (f (x))=f (g(y))) by (fast intro: arg-cong [of concl: f ]) Problem 59 lemma (∀ x. P(x) = (∼P(f (x)))) −−> (∃ x. P(x)& ∼P(f (x))) by blast Problem 60 267 lemma ∀ x. P x (f x) = (∃ y. (∀ z. P z y −−> P z (f x)) & P x y) by blast Problem 62 as corrected in JAR 18 (1997), page 135 lemma (∀ x. p a &(p x −−> p(f x)) −−> p(f (f x))) = (∀ x. (∼ p a | p x | p(f (f x))) & (∼ p a | ∼ p(f x) | p(f (f x)))) by blast From Davis, Obvious Logical Inferences, IJCAI-81, 530-531 fast indeed copes! lemma (∀ x. F (x)& ∼G(x) −−> (∃ y. H (x,y)& J (y))) & (∃ x. K (x)& F (x)&(∀ y. H (x,y) −−> K (y))) & (∀ x. K (x) −−> ∼G(x)) −−> (∃ x. K (x)& J (x)) by fast From Rudnicki, Obvious Inferences, JAR 3 (1987), 383-393. It does seem obvious! lemma (∀ x. F (x)& ∼G(x) −−> (∃ y. H (x,y)& J (y))) & (∃ x. K (x)& F (x)&(∀ y. H (x,y) −−> K (y))) & (∀ x. K (x) −−> ∼G(x)) −−> (∃ x. K (x) −−> ∼G(x)) by fast Attributed to Lewis Carroll by S. G. Pulman. The first or last assumption can be deleted. lemma (∀ x. honest(x)& industrious(x) −−> healthy(x)) & ∼ (∃ x. grocer(x)& healthy(x)) & (∀ x. industrious(x)& grocer(x) −−> honest(x)) & (∀ x. cyclist(x) −−> industrious(x)) & (∀ x. ∼healthy(x)& cyclist(x) −−> ∼honest(x)) −−> (∀ x. grocer(x) −−> ∼cyclist(x)) by blast lemma (∀ x y. R(x,y) | R(y,x)) & (∀ x y. S(x,y)& S(y,x) −−> x=y)& (∀ x y. R(x,y) −−> S(x,y)) −−> (∀ x y. S(x,y) −−> R(x,y)) by blast 39.2 Model Elimination Prover Trying out meson with arguments lemma x < y & y < z −−> ∼ (z < (x::nat)) by (meson order-less-irrefl order-less-trans) The ”small example” from Bezem, Hendriks and de Nivelle, Automatic Proof Construction in Type Theory Using Resolution, JAR 29: 3-4 (2002), pages 253-275 lemma (∀ x y z. R(x,y)& R(y,z) −−> R(x,z)) & 268 (∀ x. ∃ y. R(x,y)) −−> ∼ (∀ x. P x = (∀ y. R(x,y) −−> ∼ P y)) by (tactichMeson.safe-best-meson-tac @{context} 1 i) — In contrast, meson is SLOW: 7.6s on griffon 39.2.1 Pelletier’s examples 1 lemma (P −−> Q) = (∼Q −−> ∼P) by blast 2 lemma (∼ ∼ P) = P by blast 3 lemma ∼(P−−>Q) −−> (Q−−>P) by blast 4 lemma (∼P−−>Q) = (∼Q −−> P) by blast 5 lemma ((P|Q)−−>(P|R)) −−> (P|(Q−−>R)) by blast 6 lemma P | ∼ P by blast 7 lemma P | ∼ ∼ ∼ P by blast 8. Peirce’s law lemma ((P−−>Q) −−> P) −−> P by blast 9 lemma ((P|Q)&(∼P|Q)&(P| ∼Q)) −−> ∼ (∼P | ∼Q) by blast 10 lemma (Q−−>R)&(R−−>P&Q)&(P−−>Q|R) −−> (P=Q) by blast 269 11. Proved in each direction (incorrectly, says Pelletier!!) lemma P=(P::bool) by blast 12. ”Dijkstra’s law” lemma ((P = Q) = R) = (P = (Q = R)) by blast 13. Distributive law lemma (P | (Q & R)) = ((P | Q)&(P | R)) by blast 14 lemma (P = Q) = ((Q | ∼P)&(∼Q|P)) by blast 15 lemma (P −−> Q) = (∼P | Q) by blast 16 lemma (P−−>Q) | (Q−−>P) by blast 17 lemma ((P &(Q−−>R))−−>S) = ((∼P | Q | S)&(∼P | ∼R | S)) by blast 39.2.2 Classical Logic: examples with quantifiers lemma (∀ x. P x & Q x) = ((∀ x. P x)&(∀ x. Q x)) by blast lemma (∃ x. P −−> Q x) = (P −−> (∃ x. Q x)) by blast lemma (∃ x. P x −−> Q) = ((∀ x. P x) −−> Q) by blast lemma ((∀ x. P x) | Q) = (∀ x. P x | Q) by blast lemma (∀ x. P x −−> P(f x)) & P d −−> P(f (f (f d))) by blast Needs double instantiation of EXISTS lemma ∃ x. P x −−> P a & P b 270 by blast lemma ∃ z. P z −−> (∀ x. P x) by blast From a paper by Claire Quigley lemma ∃ y. ((P c & Q y) | (∃ z. ∼ Q z)) | (∃ x. ∼ P x & Q d) by fast 39.2.3 Hard examples with quantifiers Problem 18 lemma ∃ y. ∀ x. P y −−> P x by blast Problem 19 lemma ∃ x. ∀ y z. (P y −−> Q z) −−> (P x −−> Q x) by blast Problem 20 lemma (∀ x y. ∃ z. ∀ w. (P x & Q y −−> R z & S w)) −−> (∃ x y. P x & Q y) −−> (∃ z. R z) by blast Problem 21 lemma (∃ x. P −−> Q x)&(∃ x. Q x −−> P) −−> (∃ x. P=Q x) by blast Problem 22 lemma (∀ x. P = Q x) −−> (P = (∀ x. Q x)) by blast Problem 23 lemma (∀ x. P | Q x) = (P | (∀ x. Q x)) by blast Problem 24 lemma ∼(∃ x. S x & Q x)&(∀ x. P x −−> Q x | R x)& (∼(∃ x. P x) −−> (∃ x. Q x)) & (∀ x. Q x | R x −−> S x) −−> (∃ x. P x & R x) by blast Problem 25 lemma (∃ x. P x)& (∀ x. L x −−> ∼ (M x & R x)) & (∀ x. P x −−> (M x & L x)) & 271 ((∀ x. P x −−> Q x) | (∃ x. P x & R x)) −−> (∃ x. Q x & P x) by blast Problem 26; has 24 Horn clauses lemma ((∃ x. p x) = (∃ x. q x)) & (∀ x. ∀ y. p x & q y −−> (r x = s y)) −−> ((∀ x. p x −−> r x) = (∀ x. q x −−> s x)) by blast Problem 27; has 13 Horn clauses lemma (∃ x. P x & ∼Q x)& (∀ x. P x −−> R x)& (∀ x. M x & L x −−> P x)& ((∃ x. R x & ∼ Q x) −−> (∀ x. L x −−> ∼ R x)) −−> (∀ x. M x −−> ∼L x) by blast Problem 28. AMENDED; has 14 Horn clauses lemma (∀ x. P x −−> (∀ x. Q x)) & ((∀ x. Q x | R x) −−> (∃ x. Q x & S x)) & ((∃ x. S x) −−> (∀ x. L x −−> M x)) −−> (∀ x. P x & L x −−> M x) by blast Problem 29. Essentially the same as Principia Mathematica *11.71. 62 Horn clauses lemma (∃ x. F x)&(∃ y. G y) −−> ( ((∀ x. F x −−> H x)&(∀ y. G y −−> J y)) = (∀ x y. F x & G y −−> H x & J y)) by blast Problem 30 lemma (∀ x. P x | Q x −−> ∼ R x)&(∀ x. (Q x −−> ∼ S x) −−> P x & R x) −−> (∀ x. S x) by blast Problem 31; has 10 Horn clauses; first negative clauses is useless lemma ∼(∃ x. P x &(Q x | R x)) & (∃ x. L x & P x)& (∀ x. ∼ R x −−> M x) −−> (∃ x. L x & M x) by blast Problem 32 lemma (∀ x. P x &(Q x | R x)−−>S x)& (∀ x. S x & R x −−> L x)& 272 (∀ x. M x −−> R x) −−> (∀ x. P x & M x −−> L x) by blast Problem 33; has 55 Horn clauses lemma (∀ x. P a &(P x −−> P b)−−>P c) = (∀ x. (∼P a | P x | P c)&(∼P a | ∼P b | P c)) by blast Problem 34: Andrews’s challenge has 924 Horn clauses lemma ((∃ x. ∀ y. p x = p y) = ((∃ x. q x) = (∀ y. p y))) = ((∃ x. ∀ y. q x = q y) = ((∃ x. p x) = (∀ y. q y))) by blast Problem 35 lemma ∃ x y. P x y −−> (∀ u v. P u v) by blast Problem 36; has 15 Horn clauses lemma (∀ x. ∃ y. J x y)&(∀ x. ∃ y. G x y)& (∀ x y. J x y | G x y −−> (∀ z. J y z | G y z −−> H x z)) −−> (∀ x. ∃ y. H x y) by blast Problem 37; has 10 Horn clauses lemma (∀ z. ∃ w. ∀ x. ∃ y. (P x z −−> P y w)& P y z &(P y w −−> (∃ u. Q u w))) & (∀ x z. ∼P x z −−> (∃ y. Q y z)) & ((∃ x y. Q x y) −−> (∀ x. R x x)) −−> (∀ x. ∃ y. R x y) by blast — causes unification tracing messages Problem 38 Quite hard: 422 Horn clauses!! lemma (∀ x. p a &(p x −−> (∃ y. p y & r x y)) −−> (∃ z. ∃ w. p z & r x w & r w z)) = (∀ x. (∼p a | p x | (∃ z. ∃ w. p z & r x w & r w z)) & (∼p a | ∼(∃ y. p y & r x y) | (∃ z. ∃ w. p z & r x w & r w z))) by blast Problem 39 lemma ∼ (∃ x. ∀ y. F y x = (∼F y y)) by blast Problem 40. AMENDED lemma (∃ y. ∀ x. F x y = F x x) 273 −−> ∼ (∀ x. ∃ y. ∀ z. F z y = (∼F z x)) by blast Problem 41 lemma (∀ z. (∃ y. (∀ x. f x y = (f x z & ∼ f x x)))) −−> ∼ (∃ z. ∀ x. f x z) by blast Problem 42 lemma ∼ (∃ y. ∀ x. p x y = (∼ (∃ z. p x z & p z x))) by blast Problem 43 NOW PROVED AUTOMATICALLY!! lemma (∀ x. ∀ y. q x y = (∀ z. p z x = (p z y::bool))) −−> (∀ x. (∀ y. q x y = (q y x::bool))) by blast Problem 44: 13 Horn clauses; 7-step proof lemma (∀ x. f x −−> (∃ y. g y & h x y &(∃ y. g y & ∼ h x y))) & (∃ x. j x &(∀ y. g y −−> h x y)) −−> (∃ x. j x & ∼f x) by blast Problem 45; has 27 Horn clauses; 54-step proof lemma (∀ x. f x &(∀ y. g y & h x y −−> j x y) −−> (∀ y. g y & h x y −−> k y)) & ∼ (∃ y. l y & k y)& (∃ x. f x &(∀ y. h x y −−> l y) &(∀ y. g y & h x y −−> j x y)) −−> (∃ x. f x & ∼ (∃ y. g y & h x y)) by blast Problem 46; has 26 Horn clauses; 21-step proof lemma (∀ x. f x &(∀ y. f y & h y x −−> g y) −−> g x)& ((∃ x. f x & ∼g x) −−> (∃ x. f x & ∼g x &(∀ y. f y & ∼g y −−> j x y))) & (∀ x y. f x & f y & h x y −−> ∼j y x) −−> (∀ x. f x −−> g x) by blast Problem 47. Schubert’s Steamroller. 26 clauses; 63 Horn clauses. 87094 inferences so far. Searching to depth 36 lemma (∀ x. wolf x −→ animal x)&(∃ x. wolf x)& (∀ x. fox x −→ animal x)&(∃ x. fox x)& (∀ x. bird x −→ animal x)&(∃ x. bird x)& (∀ x. caterpillar x −→ animal x)&(∃ x. caterpillar x)& (∀ x. snail x −→ animal x)&(∃ x. snail x)& 274 (∀ x. grain x −→ plant x)&(∃ x. grain x)& (∀ x. animal x −→ ((∀ y. plant y −→ eats x y) ∨ (∀ y. animal y & smaller-than y x & (∃ z. plant z & eats y z) −→ eats x y))) & (∀ x y. bird y &(snail x ∨ caterpillar x) −→ smaller-than x y)& (∀ x y. bird x & fox y −→ smaller-than x y)& (∀ x y. fox x & wolf y −→ smaller-than x y)& (∀ x y. wolf x &(fox y ∨ grain y) −→ ∼eats x y)& (∀ x y. bird x & caterpillar y −→ eats x y)& (∀ x y. bird x & snail y −→ ∼eats x y)& (∀ x. (caterpillar x ∨ snail x) −→ (∃ y. plant y & eats x y)) −→ (∃ x y. animal x & animal y &(∃ z. grain z & eats y z & eats x y)) by (tactichMeson.safe-best-meson-tac @{context} 1 i) — Nearly twice as fast as meson, which performs iterative deepening rather than best-first search The Los problem. Circulated by John Harrison lemma (∀ x y z. P x y & P y z −−> P x z)& (∀ x y z. Q x y & Q y z −−> Q x z)& (∀ x y. P x y −−> P y x)& (∀ x y. P x y | Q x y) −−> (∀ x y. P x y) | (∀ x y. Q x y) by meson A similar example, suggested by Johannes Schumann and credited to Pel- letier lemma (∀ x y z. P x y −−> P y z −−> P x z) −−> (∀ x y z. Q x y −−> Q y z −−> Q x z) −−> (∀ x y. Q x y −−> Q y x) −−> (∀ x y. P x y | Q x y) −−> (∀ x y. P x y) | (∀ x y. Q x y) by meson Problem 50. What has this to do with equality? lemma (∀ x. P a x | (∀ y. P x y)) −−> (∃ x. ∀ y. P x y) by blast Problem 54: NOT PROVED lemma (∀ y:: 0a. ∃ z. ∀ x. F x z = (x=y)) −−> ∼ (∃ w. ∀ x. F x w = (∀ u. F x u −−> (∃ y. F y u & ∼ (∃ z. F z u & F z y)))) oops Problem 55 Non-equational version, from Manthey and Bry, CADE-9 (Springer, 1988). meson cannot report who killed Agatha. lemma lives agatha & lives butler & lives charles & (killed agatha agatha | killed butler agatha | killed charles agatha)& 275 (∀ x y. killed x y −−> hates x y & ∼richer x y)& (∀ x. hates agatha x −−> ∼hates charles x)& (hates agatha agatha & hates agatha charles)& (∀ x. lives x & ∼richer x agatha −−> hates butler x)& (∀ x. hates agatha x −−> hates butler x)& (∀ x. ∼hates x agatha | ∼hates x butler | ∼hates x charles) −−> (∃ x. killed x agatha) by meson Problem 57 lemma P (f a b)(f b c)& P (f b c)(f a c)& (∀ x y z. P x y & P y z −−> P x z) −−> P (f a b)(f a c) by blast Problem 58: Challenge found on info-hol lemma ∀ P Q R x. ∃ v w. ∀ y z. P x & Q y −−> (P v | R w)&(R z −−> Q v) by blast Problem 59 lemma (∀ x. P x = (∼P(f x))) −−> (∃ x. P x & ∼P(f x)) by blast Problem 60 lemma ∀ x. P x (f x) = (∃ y. (∀ z. P z y −−> P z (f x)) & P x y) by blast Problem 62 as corrected in JAR 18 (1997), page 135 lemma (∀ x. p a &(p x −−> p(f x)) −−> p(f (f x))) = (∀ x. (∼ p a | p x | p(f (f x))) & (∼ p a | ∼ p(f x) | p(f (f x)))) by blast * Charles Morgan’s problems * lemma assumes a: ∀ x y. T (i x(i y x)) and b: ∀ x y z. T (i (i x (i y z)) (i (i x y)(i x z))) and c: ∀ x y. T (i (i (n x)(n y)) (i y x)) and c 0: ∀ x y. T (i (i y x)(i (n x)(n y))) and d: ∀ x y. T (i x y)& T x −−> T y shows True proof − from a b d have ∀ x. T (i x x) by blast from a b c d have ∀ x. T (i x (n(n x))) — Problem 66 by metis from a b c d have ∀ x. T (i (n(n x)) x) — Problem 67 by meson — 4.9s on griffon. 51061 inferences, depth 21 from a b c 0 d have ∀ x. T (i x (n(n x))) 276 — Problem 68: not proved. Listed as satisfiable in TPTP (LCL078-1) oops Problem 71, as found in TPTP (SYN007+1.005) lemma p1 = (p2 = (p3 = (p4 = (p5 = (p1 = (p2 = (p3 = (p4 = p5 )))))))) by blast end 40 Set Theory examples: Cantor’s Theorem, Schr¨oder- Bernstein Theorem, etc. theory Set-Theory imports Main begin These two are cited in Benzmueller and Kohlhase’s system description of LEO, CADE-15, 1998 (pages 139-143) as theorems LEO could not prove. lemma (X = Y ∪ Z ) = (Y ⊆ X ∧ Z ⊆ X ∧ (∀ V . Y ⊆ V ∧ Z ⊆ V −→ X ⊆ V )) by blast lemma (X = Y ∩ Z ) = (X ⊆ Y ∧ X ⊆ Z ∧ (∀ V . V ⊆ Y ∧ V ⊆ Z −→ V ⊆ X )) by blast Trivial example of term synthesis: apparently hard for some provers! schematic-goal a 6= b =⇒ a ∈ ?X ∧ b ∈/ ?X by blast 40.1 Examples for the blast paper lemma (S x ∈ C . f x ∪ g x) = S (f ‘ C ) ∪ S (g ‘ C ) — Union-image, called Un-Union-image in Main HOL by blast lemma (T x ∈ C . f x ∩ g x) = T (f ‘ C ) ∩ T (g ‘ C ) — Inter-image, called Int-Inter-image in Main HOL by blast lemma singleton-example-1 : VS:: 0a set set. ∀ x ∈ S. ∀ y ∈ S. x ⊆ y =⇒ ∃ z. S ⊆ {z} by blast lemma singleton-example-2 : ∀ x ∈ S. S S ⊆ x =⇒ ∃ z. S ⊆ {z} — Variant of the problem above. by blast 277 lemma ∃ !x. f (g x) = x =⇒ ∃ !y. g (f y) = y — A unique fixpoint theorem — fast/best/meson all fail. by metis 40.2 Cantor’s Theorem: There is no surjection from a set to its powerset lemma cantor1 : ¬ (∃ f :: 0a ⇒ 0a set. ∀ S. ∃ x. f x = S) — Requires best-first search because it is undirectional. by best schematic-goal ∀ f :: 0a ⇒ 0a set. ∀ x. f x 6= ?S f — This form displays the diagonal term. by best schematic-goal ?S ∈/ range (f :: 0a ⇒ 0a set) — This form exploits the set constructs. by (rule notI , erule rangeE, best) schematic-goal ?S ∈/ range (f :: 0a ⇒ 0a set) — Or just this! by best 40.3 The Schr¨oder-BernsteinTheorem lemma disj-lemma: − (f ‘ X ) = g 0 ‘ (−X ) =⇒ f a = g 0 b =⇒ a ∈ X =⇒ b ∈ X by blast lemma surj-if-then-else: −(f ‘ X ) = g 0 ‘ (−X ) =⇒ surj (λz. if z ∈ X then f z else g 0 z) by (simp add: surj-def ) blast lemma bij-if-then-else: inj-on f X =⇒ inj-on g 0 (−X ) =⇒ −(f ‘ X ) = g 0 ‘ (−X ) =⇒ h = (λz. if z ∈ X then f z else g 0 z) =⇒ inj h ∧ surj h apply (unfold inj-on-def ) apply (simp add: surj-if-then-else) apply (blast dest: disj-lemma sym) done lemma decomposition: ∃ X . X = − (g ‘ (− (f ‘ X ))) apply (rule exI ) apply (rule lfp-unfold) apply (rule monoI , blast) done theorem Schroeder-Bernstein: inj (f :: 0a ⇒ 0b) =⇒ inj (g :: 0b ⇒ 0a) 278 =⇒ ∃ h:: 0a ⇒ 0b. inj h ∧ surj h apply (rule decomposition [where f =f and g=g, THEN exE]) apply (rule-tac x = (λz. if z ∈ x then f z else inv g z) in exI ) — The term above can be synthesized by a sufficiently detailed proof. apply (rule bij-if-then-else) apply (rule-tac [4 ] refl) apply (rule-tac [2 ] inj-on-inv-into) apply (erule subset-inj-on [OF - subset-UNIV ]) apply blast apply (erule ssubst, subst double-complement, erule image-inv-f-f [symmetric]) done 40.4 A simple party theorem At any party there are two people who know the same number of people. Provided the party consists of at least two people and the knows relation is symmetric. Knowing yourself does not count — otherwise knows needs to be reflexive. (From Freek Wiedijk’s talk at TPHOLs 2007.) lemma equal-number-of-acquaintances: assumes Domain R <= A and sym R and card A ≥ 2 shows ¬ inj-on (%a. card(R ‘‘ {a} − {a})) A proof − let ?N = %a. card(R ‘‘ {a} − {a}) let ?n = card A have finite A using hcard A ≥ 2 i by(auto intro:ccontr) have 0 : R ‘‘ A <= A using hsym Ri hDomain R <= Ai unfolding Domain-unfold sym-def by blast have h: ALL a:A. R ‘‘ {a} <= A using 0 by blast hence 1 : ALL a:A. finite(R ‘‘ {a}) using hfinite Ai by(blast intro: finite-subset) have sub: ?N ‘ A <= {0 .. 279 hence a ∈/ R ‘‘ {b} by (metis Image-singleton-iff assms(2 ) sym-def ) hence 3 : R ‘‘ {b} − {b} <= A − {a,b} using 0 ab by blast have 4 : finite (A − {a,b}) using hfinite Ai by simp have ?N b <= ?n − 2 using ab ha6=bi hfinite Ai card-mono[OF 4 3 ] by simp then show False using Nb hcard A ≥ 2 i by arith qed qed From W. W. Bledsoe and Guohui Feng, SET-VAR. JAR 11 (3), 1993, pages 293-314. Isabelle can prove the easy examples without any special mechanisms, but it can’t prove the hard ones. lemma ∃ A. (∀ x ∈ A. x ≤ (0 ::int)) — Example 1, page 295. by force lemma D ∈ F =⇒ ∃ G. ∀ A ∈ G. ∃ B ∈ F . A ⊆ B — Example 2. by force lemma P a =⇒ ∃ A. (∀ x ∈ A. P x) ∧ (∃ y. y ∈ A) — Example 3. by force lemma a < b ∧ b < (c::int) =⇒ ∃ A. a ∈/ A ∧ b ∈ A ∧ c ∈/ A — Example 4. by auto — slow lemma P (f b) =⇒ ∃ s A. (∀ x ∈ A. P x) ∧ f s ∈ A — Example 5, page 298. by force lemma P (f b) =⇒ ∃ s A. (∀ x ∈ A. P x) ∧ f s ∈ A — Example 6. by force lemma ∃ A. a ∈/ A — Example 7. by force lemma (∀ u v. u < (0 ::int) −→ u 6= |v|) −→ (∃ A::int set. −2 ∈ A &(∀ y. |y| ∈/ A)) — Example 8 needs a small hint. by force — not blast, which can’t simplify −2 < 0 Example 9 omitted (requires the reals). The paper has no Example 10! 280 lemma (∀ A. 0 ∈ A ∧ (∀ x ∈ A. Suc x ∈ A) −→ n ∈ A) ∧ P 0 ∧ (∀ x. P x −→ P (Suc x)) −→ P n — Example 11: needs a hint. by(metis nat.induct) lemma (∀ A. (0 , 0 ) ∈ A ∧ (∀ x y. (x, y) ∈ A −→ (Suc x, Suc y) ∈ A) −→ (n, m) ∈ A) ∧ P n −→ P m — Example 12. by auto lemma (∀ x. (∃ u. x = 2 ∗ u) = (¬ (∃ v. Suc x = 2 ∗ v))) −→ (∃ A. ∀ x. (x ∈ A) = (Suc x ∈/ A)) — Example EO1: typo in article, and with the obvious fix it seems to require arithmetic reasoning. apply clarify apply (rule-tac x = {x. ∃ u. x = 2 ∗ u} in exI , auto) apply metis+ done end 41 Examples and regression tests for automated termination proofs theory Termination imports Main ∼∼/src/HOL/Library/Multiset begin 41.1 Manually giving termination relations using relation and measure function sum :: nat ⇒ nat ⇒ nat where sum i N = (if i > N then 0 else i + sum (Suc i) N ) by pat-completeness auto termination by (relation measure (λ(i,N ). N + 1 − i)) auto function foo :: nat ⇒ nat ⇒ nat where foo i N = (if i > N then (if N = 0 then 0 else foo 0 (N − 1 )) else i + foo (Suc i) N ) by pat-completeness auto termination by (relation measures [λ(i, N ). N , λ(i,N ). N + 1 − i]) auto 281 41.2 lexicographic-order: Trivial examples The fun command uses the method lexicographic-order by default, so it is not explicitly invoked. fun identity :: nat ⇒ nat where identity n = n fun yaSuc :: nat ⇒ nat where yaSuc 0 = 0 | yaSuc (Suc n) = Suc (yaSuc n) 41.3 Examples on natural numbers fun bin :: (nat ∗ nat) ⇒ nat where bin (0 , 0 ) = 1 | bin (Suc n, 0 ) = 0 | bin (0 , Suc m) = 0 | bin (Suc n, Suc m) = bin (n, m) + bin (Suc n, m) fun t :: (nat ∗ nat) ⇒ nat where t (0 ,n) = 0 | t (n,0 ) = 0 | t (Suc n, Suc m) = (if (n mod 2 = 0 ) then (t (Suc n, m)) else (t (n, Suc m))) fun k :: (nat ∗ nat) ∗ (nat ∗ nat) ⇒ nat where k ((0 ,0 ),(0 ,0 )) = 0 | k ((Suc z, y), (u,v)) = k((z, y), (u, v)) | k ((0 , Suc y), (u,v)) = k((1 , y), (u, v)) | k ((0 ,0 ), (Suc u, v)) = k((1 , 1 ), (u, v)) | k ((0 ,0 ), (0 , Suc v)) = k((1 ,1 ), (1 ,v)) fun gcd2 :: nat ⇒ nat ⇒ nat where gcd2 x 0 = x | gcd2 0 y = y | gcd2 (Suc x)(Suc y) = (if x < y then gcd2 (Suc x)(y − x) else gcd2 (x − y)(Suc y)) fun ack :: (nat ∗ nat) ⇒ nat where ack (0 , m) = Suc m 282 | ack (Suc n, 0 ) = ack(n, 1 ) | ack (Suc n, Suc m) = ack (n, ack (Suc n, m)) fun greedy :: nat ∗ nat ∗ nat ∗ nat ∗ nat => nat where greedy (Suc a, Suc b, Suc c, Suc d, Suc e) = (if (a < 10 ) then greedy (Suc a, Suc b, c, d + 2 , Suc e) else (if (a < 20 ) then greedy (Suc a, b, Suc c, d, Suc e) else (if (a < 30 ) then greedy (Suc a, b, Suc c, d, Suc e) else (if (a < 40 ) then greedy (Suc a, b, Suc c, d, Suc e) else (if (a < 50 ) then greedy (Suc a, b, Suc c, d, Suc e) else (if (a < 60 ) then greedy (a, Suc b, Suc c, d, Suc e) else (if (a < 70 ) then greedy (a, Suc b, Suc c, d, Suc e) else (if (a < 80 ) then greedy (a, Suc b, Suc c, d, Suc e) else (if (a < 90 ) then greedy (Suc a, Suc b, Suc c, d, e) else greedy (Suc a, Suc b, Suc c, d, e)))))))))) | greedy (a, b, c, d, e) = 0 fun blowup :: nat => nat => nat => nat => nat => nat => nat => nat => nat => nat where blowup 0 0 0 0 0 0 0 0 0 = 0 | blowup 0 0 0 0 0 0 0 0 (Suc i) = Suc (blowup i i i i i i i i i) | blowup 0 0 0 0 0 0 0 (Suc h) i = Suc (blowup h h h h h h h h i) | blowup 0 0 0 0 0 0 (Suc g) h i = Suc (blowup g g g g g g g h i) | blowup 0 0 0 0 0 (Suc f ) g h i = Suc (blowup f f f f f f g h i) | blowup 0 0 0 0 (Suc e) f g h i = Suc (blowup e e e e e f g h i) | blowup 0 0 0 (Suc d) e f g h i = Suc (blowup d d d d e f g h i) | blowup 0 0 (Suc c) d e f g h i = Suc (blowup c c c d e f g h i) | blowup 0 (Suc b) c d e f g h i = Suc (blowup b b c d e f g h i) | blowup (Suc a) b c d e f g h i = Suc (blowup a b c d e f g h i) 41.4 Simple examples with other datatypes than nat, e.g. trees and lists datatype tree = Node | Branch tree tree fun g-tree :: tree ∗ tree ⇒ tree where g-tree (Node, Node) = Node | g-tree (Node, Branch a b) = Branch Node (g-tree (a,b)) | g-tree (Branch a b, Node) = Branch (g-tree (a,Node)) b | g-tree (Branch a b, Branch c d) = Branch (g-tree (a,c)) (g-tree (b,d)) fun acklist :: 0a list ∗ 0a list ⇒ 0a list where 283 acklist ([], m) = ((hd m)#m) | acklist (n#ns, []) = acklist (ns, [n]) | acklist ((n#ns), (m#ms)) = acklist (ns, acklist ((n#ns), ms)) 41.5 Examples with mutual recursion fun evn od :: nat ⇒ bool where evn 0 = True | od 0 = False | evn (Suc n) = od (Suc n) | od (Suc n) = evn n fun sizechange-f :: 0a list => 0a list => 0a list and sizechange-g :: 0a list => 0a list => 0a list => 0a list where sizechange-f i x = (if i=[] then x else sizechange-g (tl i) x i) | sizechange-g a b c = sizechange-f a (b @ c) fun pedal :: nat => nat => nat => nat and coast :: nat => nat => nat => nat where pedal 0 m c = c | pedal n 0 c = c | pedal n m c = (if n < m then coast (n − 1 )(m − 1 )(c + m) else pedal (n − 1 ) m (c + m)) | coast n m c = (if n < m then coast n (m − 1 )(c + n) else pedal n m (c + n)) 41.6 Refined analysis: The size-change method Unsolvable for lexicographic-order function fun1 :: nat ∗ nat ⇒ nat where fun1 (0 ,0 ) = 1 | fun1 (0 , Suc b) = 0 | fun1 (Suc a, 0 ) = 0 | fun1 (Suc a, Suc b) = fun1 (b, a) by pat-completeness auto termination by size-change lexicographic-order can do the following, but it is much slower. function 284 prod :: nat => nat => nat => nat and eprod :: nat => nat => nat => nat and oprod :: nat => nat => nat => nat where prod x y z = (if y mod 2 = 0 then eprod x y z else oprod x y z) | oprod x y z = eprod x (y − 1 )(z+x) | eprod x y z = (if y=0 then z else prod (2 ∗x)(y div 2 ) z) by pat-completeness auto termination by size-change Permutations of arguments: function perm :: nat ⇒ nat ⇒ nat ⇒ nat where perm m n r = (if r > 0 then perm m (r − 1 ) n else if n > 0 then perm r (n − 1 ) m else m) by auto termination by size-change Artificial examples and regression tests: function fun2 :: nat ⇒ nat ⇒ nat ⇒ nat where fun2 x y z = (if x > 1000 ∧ z > 0 then fun2 (min x y) y (z − 1 ) else if y > 0 ∧ x > 100 then fun2 x (y − 1 )(2 ∗ z) else if z > 0 then fun2 (min y (z − 1 )) x x else 0 ) by pat-completeness auto termination by size-change — requires Multiset definition negate :: int ⇒ int where negate i = − i function fun3 :: int => nat where fun3 i = (if i < 0 then fun3 (negate i) else if i = 0 then 0 else fun3 (i − 1 )) by (pat-completeness) auto termination apply size-change apply (simp add: negate-def ) 285 apply size-change done end 42 Coherent Logic Problems theory Coherent imports Main begin 42.1 Equivalence of two versions of Pappus’ Axiom no-notation comp (infixl o 55 ) and relcomp (infixr O 75 ) lemma p1p2 : assumes col a b c l ∧ col d e f m and col b f g n ∧ col c e g o and col b d h p ∧ col a e h q and col c d i r ∧ col a f i s and el n o =⇒ goal and el p q =⇒ goal and el s r =⇒ goal and VA. el A A =⇒ pl g A =⇒ pl h A =⇒ pl i A =⇒ goal and VABCD. col A B C D =⇒ pl A D and VABCD. col A B C D =⇒ pl B D and VABCD. col A B C D =⇒ pl C D and VAB. pl A B =⇒ ep A A and VAB. ep A B =⇒ ep B A and VABC . ep A B =⇒ ep B C =⇒ ep A C and VAB. pl A B =⇒ el B B and VAB. el A B =⇒ el B A and VABC . el A B =⇒ el B C =⇒ el A C and VABC . ep A B =⇒ pl B C =⇒ pl A C and VABC . pl A B =⇒ el B C =⇒ pl A C and VABCDEFGHIJKLMNOPQ. col A B C D =⇒ col E F G H =⇒ col B G I J =⇒ col C F I K =⇒ col B E L M =⇒ col A F L N =⇒ col C E O P =⇒ col A G O Q =⇒ (∃ R. col I L O R) ∨ pl A H ∨ pl B H ∨ pl C H ∨ pl E D ∨ pl F D ∨ pl G D and VABCD. pl A B =⇒ pl A C =⇒ pl D B =⇒ pl D C =⇒ ep A D ∨ el BC and VAB. ep A A =⇒ ep B B =⇒ ∃ C . pl A C ∧ pl B C shows goal using assms by coherent 286 lemma p2p1 : assumes col a b c l ∧ col d e f m and col b f g n ∧ col c e g o and col b d h p ∧ col a e h q and col c d i r ∧ col a f i s and pl a m =⇒ goal and pl b m =⇒ goal and pl c m =⇒ goal and pl d l =⇒ goal and pl e l =⇒ goal and pl f l =⇒ goal and VA. pl g A =⇒ pl h A =⇒ pl i A =⇒ goal and VABCD. col A B C D =⇒ pl A D and VABCD. col A B C D =⇒ pl B D and VABCD. col A B C D =⇒ pl C D and VAB. pl A B =⇒ ep A A and VAB. ep A B =⇒ ep B A and VABC . ep A B =⇒ ep B C =⇒ ep A C and VAB. pl A B =⇒ el B B and VAB. el A B =⇒ el B A and VABC . el A B =⇒ el B C =⇒ el A C and VABC . ep A B =⇒ pl B C =⇒ pl A C and VABC . pl A B =⇒ el B C =⇒ pl A C and VABCDEFGHIJKLMNOPQ. col A B C J =⇒ col D E F K =⇒ col B F G L =⇒ col C E G M =⇒ col B D H N =⇒ col A E H O =⇒ col C D I P =⇒ col A F I Q =⇒ (∃ R. col G H I R) ∨ el L M ∨ el N O ∨ el P Q and VABCD. pl C A =⇒ pl C B =⇒ pl D A =⇒ pl D B =⇒ ep C D ∨ el AB and VABC . ep A A =⇒ ep B B =⇒ ∃ C . pl A C ∧ pl B C shows goal using assms by coherent 42.2 Preservation of the Diamond Property under reflexive closure lemma diamond: assumes reflexive-rewrite a b reflexive-rewrite a c and VA. reflexive-rewrite b A =⇒ reflexive-rewrite c A =⇒ goal and VA. equalish A A and VAB. equalish A B =⇒ equalish B A and VABC . equalish A B =⇒ reflexive-rewrite B C =⇒ reflexive-rewrite A C and VAB. equalish A B =⇒ reflexive-rewrite A B and VAB. rewrite A B =⇒ reflexive-rewrite A B and VAB. reflexive-rewrite A B =⇒ equalish A B ∨ rewrite A B and VABC . rewrite A B =⇒ rewrite A C =⇒ ∃ D. rewrite B D ∧ rewrite C D shows goal using assms 287 by coherent end 43 Some examples for Presburger Arithmetic theory PresburgerEx imports Presburger begin lemma Vm n ja ia. [[¬ m ≤ j ; ¬ (n::nat) ≤ i;(e::nat) 6= 0 ; Suc j ≤ ja]] =⇒ ∃ m. ∀ ja ia. m ≤ ja −→ (if j = ja ∧ i = ia then e else 0 ) = 0 by presburger lemma (0 ::nat) < emBits mod 8 =⇒ 8 + emBits div 8 ∗ 8 − emBits = 8 − emBits mod 8 by presburger lemma (0 ::nat) < emBits mod 8 =⇒ 8 + emBits div 8 ∗ 8 − emBits = 8 − emBits mod 8 by presburger theorem (∀ (y::int). 3 dvd y) ==> ∀ (x::int). b < x −−> a ≤ x by presburger theorem !! (y::int)(z::int)(n::int). 3 dvd z ==> 2 dvd (y::int) ==> (∃ (x::int). 2 ∗x = y)&(∃ (k::int). 3 ∗k = z) by presburger theorem !! (y::int)(z::int) n. Suc(n::nat) < 6 ==> 3 dvd z ==> 2 dvd (y::int) ==> (∃ (x::int). 2 ∗x = y)&(∃ (k::int). 3 ∗k = z) by presburger theorem ∀ (x::nat). ∃ (y::nat). (0 ::nat) ≤ 5 −−> y = 5 + x by presburger Slow: about 7 seconds on a 1.6GHz machine. theorem ∀ (x::nat). ∃ (y::nat). y = 5 + x | x div 6 + 1 = 2 by presburger theorem ∃ (x::int). 0 < x by presburger theorem ∀ (x::int) y. x < y −−> 2 ∗ x + 1 < 2 ∗ y by presburger theorem ∀ (x::int) y. 2 ∗ x + 1 6= 2 ∗ y by presburger theorem ∃ (x::int) y. 0 < x & 0 ≤ y & 3 ∗ x − 5 ∗ y = 1 by presburger 288 theorem ∼ (∃ (x::int)(y::int)(z::int). 4 ∗x + (−6 ::int)∗y = 1 ) by presburger theorem ∀ (x::int). b < x −−> a ≤ x apply (presburger elim) oops theorem ∼ (∃ (x::int). False) by presburger theorem ∀ (x::int). (a::int) < 3 ∗ x −−> b < 3 ∗ x apply (presburger elim) oops theorem ∀ (x::int). (2 dvd x) −−> (∃ (y::int). x = 2 ∗y) by presburger theorem ∀ (x::int). (2 dvd x) −−> (∃ (y::int). x = 2 ∗y) by presburger theorem ∀ (x::int). (2 dvd x) = (∃ (y::int). x = 2 ∗y) by presburger theorem ∀ (x::int). ((2 dvd x) = (∀ (y::int). x 6= 2 ∗y + 1 )) by presburger theorem ∼ (∀ (x::int). ((2 dvd x) = (∀ (y::int). x 6= 2 ∗y+1 ) | (∃ (q::int)(u::int) i. 3 ∗i + 2 ∗q − u < 17 ) −−> 0 < x | ((∼ 3 dvd x) &(x + 8 = 0 )))) by presburger theorem ∼ (∀ (i::int). 4 ≤ i −−> (∃ x y. 0 ≤ x & 0 ≤ y & 3 ∗ x + 5 ∗ y = i)) by presburger theorem ∀ (i::int). 8 ≤ i −−> (∃ x y. 0 ≤ x & 0 ≤ y & 3 ∗ x + 5 ∗ y = i) by presburger theorem ∃ (j ::int). ∀ i. j ≤ i −−> (∃ x y. 0 ≤ x & 0 ≤ y & 3 ∗ x + 5 ∗ y = i) by presburger theorem ∼ (∀ j (i::int). j ≤ i −−> (∃ x y. 0 ≤ x & 0 ≤ y & 3 ∗ x + 5 ∗ y = i)) by presburger Slow: about 5 seconds on a 1.6GHz machine. theorem (∃ m::nat. n = 2 ∗ m) −−> (n + 1 ) div 2 = n div 2 by presburger This following theorem proves that all solutions to the recurrence relation 289 xi+2 = |xi+1| − xi are periodic with period 9. The example was brought to our attention by John Harrison. It does does not require Presburger arithmetic but merely quantifier-free linear arithmetic and holds for the rationals as well. Warning: it takes (in 2006) over 4.2 minutes! lemma [[ x3 = |x2 | − x1 ; x4 = |x3 | − x2 ; x5 = |x4 | − x3 ; x6 = |x5 | − x4 ; x7 = |x6 | − x5 ; x8 = |x7 | − x6 ; x9 = |x8 | − x7 ; x10 = |x9 | − x8 ; x11 = |x10 | − x9 ]] =⇒ x1 = x10 & x2 = (x11 ::int) by arith end 44 Generic reflection and reification theory Reflection imports Main begin ML-file ∼∼/src/HOL/Tools/reflection.ML method-setup reify = h Attrib.thms −− Scan.option (Scan.lift (Args.$$$ () |−− Args.term −−| Scan.lift (Args.$$$ ))) >> (fn (user-eqs, to) => fn ctxt => SIMPLE-METHOD 0 (Reflection.default-reify-tac ctxt user-eqs to)) i partial automatic reification method-setup reflection = h let fun keyword k = Scan.lift (Args.$$$ k −− Args.colon) >> K (); val onlyN = only; val rulesN = rules; val any-keyword = keyword onlyN || keyword rulesN ; val thms = Scan.repeats (Scan.unless any-keyword Attrib.multi-thm); val terms = thms >> map (Thm.term-of o Drule.dest-term); in thms −− Scan.optional (keyword rulesN |−− thms) [] −− Scan.option (keyword onlyN |−− Args.term) >> (fn ((user-eqs, user-thms), to) => fn ctxt => SIMPLE-METHOD 0 (Reflection.default-reflection-tac ctxt user-thms user-eqs to)) end i partial automatic reflection end 290 45 Examples for generic reflection and reification theory Reflection-Examples imports Complex-Main ∼∼/src/HOL/Library/Reflection begin This theory presents two methods: reify and reflection Consider an HOL type σ, the structure of which is not recongnisable on the theory level. This is the case of bool, arithmetical terms such as int, real etc . . . In order to implement a simplification on terms of type σ we often need its structure. Traditionnaly such simplifications are written in ML, proofs are synthesized. An other strategy is to declare an HOL datatype τ and an HOL function (the interpretation) that maps elements of τ to elements of σ. The functionality of reify then is, given a term t of type σ, to compute a term s of type τ. For this it needs equations for the interpretation. N.B: All the interpretations supported by reify must have the type 0a list ⇒ τ ⇒ σ. The method reify can also be told which subterm of the current subgoal should be reified. The general call for reify is reify eqs (t), where eqs are the defining equations of the interpretation and (t) is an optional parameter which specifies the subterm to which reification should be applied to. If (t) is abscent, reify tries to reify the whole subgoal. The method reflection uses reify and has a very similar signature: reflection corr-thm eqs (t). Here again eqs and (t) are as described above and corr-thm is a theorem proving I vs (f t) = I vs t. We assume that I is the interpreta- tion and f is some useful and executable simplification of type τ ⇒ τ. The method reflection applies reification and hence the theorem t = I xs s and hence using corr-thm derives t = I xs (f s). It then uses normalization by equational rewriting to prove f s = s 0 which almost finishes the proof of t = t 0 where I xs s 0 = t 0. Example 1 : Propositional formulae and NNF. The type fm represents simple propositional formulae: datatype form = TrueF | FalseF | Less nat nat | And form form | Or form form | Neg form | ExQ form primrec interp :: form ⇒ ( 0a::ord) list ⇒ bool where interp TrueF vs ←→ True | interp FalseF vs ←→ False | interp (Less i j ) vs ←→ vs ! i < vs ! j | interp (And f1 f2 ) vs ←→ interp f1 vs ∧ interp f2 vs | interp (Or f1 f2 ) vs ←→ interp f1 vs ∨ interp f2 vs | interp (Neg f ) vs ←→ ¬ interp f vs 291 | interp (ExQ f ) vs ←→ (∃ v. interp f (v # vs)) lemmas interp-reify-eqs = interp.simps declare interp-reify-eqs [reify] lemma ∃ x. x < y ∧ x < z apply reify oops datatype fm = And fm fm | Or fm fm | Imp fm fm | Iff fm fm | NOT fm | At nat primrec Ifm :: fm ⇒ bool list ⇒ bool where Ifm (At n) vs ←→ vs ! n | Ifm (And p q) vs ←→ Ifm p vs ∧ Ifm q vs | Ifm (Or p q) vs ←→ Ifm p vs ∨ Ifm q vs | Ifm (Imp p q) vs ←→ Ifm p vs −→ Ifm q vs | Ifm (Iff p q) vs ←→ Ifm p vs = Ifm q vs | Ifm (NOT p) vs ←→ ¬ Ifm p vs lemma Q −→ (D ∧ F ∧ ((¬ D) ∧ (¬ F ))) apply (reify Ifm.simps) oops Method reify maps a bool to an fm. For this it needs the semantics of fm, i.e. the rewrite rules in Ifm.simps. You can also just pick up a subterm to reify. lemma Q −→ (D ∧ F ∧ ((¬ D) ∧ (¬ F ))) apply (reify Ifm.simps (((¬ D) ∧ (¬ F )))) oops Let’s perform NNF. This is a version that tends to generate disjunctions primrec fmsize :: fm ⇒ nat where fmsize (At n) = 1 | fmsize (NOT p) = 1 + fmsize p | fmsize (And p q) = 1 + fmsize p + fmsize q | fmsize (Or p q) = 1 + fmsize p + fmsize q | fmsize (Imp p q) = 2 + fmsize p + fmsize q | fmsize (Iff p q) = 2 + 2 ∗ fmsize p + 2 ∗ fmsize q lemma [measure-function]: is-measure fmsize .. fun nnf :: fm ⇒ fm where nnf (At n) = At n | nnf (And p q) = And (nnf p)(nnf q) 292 | nnf (Or p q) = Or (nnf p)(nnf q) | nnf (Imp p q) = Or (nnf (NOT p)) (nnf q) | nnf (Iff p q) = Or (And (nnf p)(nnf q)) (And (nnf (NOT p)) (nnf (NOT q))) | nnf (NOT (And p q)) = Or (nnf (NOT p)) (nnf (NOT q)) | nnf (NOT (Or p q)) = And (nnf (NOT p)) (nnf (NOT q)) | nnf (NOT (Imp p q)) = And (nnf p)(nnf (NOT q)) | nnf (NOT (Iff p q)) = Or (And (nnf p)(nnf (NOT q))) (And (nnf (NOT p)) (nnf q)) | nnf (NOT (NOT p)) = nnf p | nnf (NOT p) = NOT p The correctness theorem of nnf : it preserves the semantics of fm lemma nnf [reflection]: Ifm (nnf p) vs = Ifm p vs by (induct p rule: nnf .induct) auto Now let’s perform NNF using our nnf function defined above. First to the whole subgoal. lemma A 6= B ∧ (B −→ A 6= (B ∨ C ∧ (B −→ A ∨ D))) −→ A ∨ B ∧ D apply (reflection Ifm.simps) oops Now we specify on which subterm it should be applied lemma A 6= B ∧ (B −→ A 6= (B ∨ C ∧ (B −→ A ∨ D))) −→ A ∨ B ∧ D apply (reflection Ifm.simps only: B ∨ C ∧ (B −→ A ∨ D)) oops Example 2: Simple arithmetic formulae The type num reflects linear expressions over natural number datatype num = C nat | Add num num | Mul nat num | Var nat | CN nat nat num This is just technical to make recursive definitions easier. primrec num-size :: num ⇒ nat where num-size (C c) = 1 | num-size (Var n) = 1 | num-size (Add a b) = 1 + num-size a + num-size b | num-size (Mul c a) = 1 + num-size a | num-size (CN n c a) = 4 + num-size a lemma [measure-function]: is-measure num-size .. The semantics of num primrec Inum:: num ⇒ nat list ⇒ nat where Inum-C : Inum (C i) vs = i 293 | Inum-Var: Inum (Var n) vs = vs!n | Inum-Add: Inum (Add s t) vs = Inum s vs + Inum t vs | Inum-Mul: Inum (Mul c t) vs = c ∗ Inum t vs | Inum-CN : Inum (CN n c t) vs = c∗(vs!n) + Inum t vs Let’s reify some nat expressions . . . lemma 4 ∗ (2 ∗ x + (y::nat)) + f a 6= 0 apply (reify Inum.simps (4 ∗ (2 ∗ x + (y::nat)) + f a)) oops We’re in a bad situation! x, y and f have been recongnized as constants, which is correct but does not correspond to our intuition of the constructor C. It should encapsulate constants, i.e. numbers, i.e. numerals. So let’s leave the Inum-C equation at the end and see what happens . . . lemma 4 ∗ (2 ∗ x + (y::nat)) 6= 0 apply (reify Inum-Var Inum-Add Inum-Mul Inum-CN Inum-C (4 ∗ (2 ∗ x + (y::nat)))) oops Hm, let’s specialize Inum-C with numerals. lemma Inum-number: Inum (C (numeral t)) vs = numeral t by simp lemmas Inum-eqs = Inum-Var Inum-Add Inum-Mul Inum-CN Inum-number Second attempt lemma 1 ∗ (2 ∗ x + (y::nat)) 6= 0 apply (reify Inum-eqs (1 ∗ (2 ∗ x + (y::nat)))) oops That was fine, so let’s try another one . . . lemma 1 ∗ (2 ∗ x + (y::nat) + 0 + 1 ) 6= 0 apply (reify Inum-eqs (1 ∗ (2 ∗ x + (y::nat) + 0 + 1 ))) oops Oh!! 0 is not a variable . . . Oh! 0 is not a numeral . . . thing. The same for 1. So let’s add those equations, too. lemma Inum-01 : Inum (C 0 ) vs = 0 Inum (C 1 ) vs = 1 Inum (C (Suc n)) vs = Suc n by simp-all lemmas Inum-eqs 0= Inum-eqs Inum-01 Third attempt: lemma 1 ∗ (2 ∗ x + (y::nat) + 0 + 1 ) 6= 0 apply (reify Inum-eqs 0 (1 ∗ (2 ∗ x + (y::nat) + 0 + 1 ))) oops 294 Okay, let’s try reflection. Some simplifications on Reflection-Examples.num follow. You can skim until the main theorem linum. fun lin-add :: num ⇒ num ⇒ num where lin-add (CN n1 c1 r1 )(CN n2 c2 r2 ) = (if n1 = n2 then (let c = c1 + c2 in (if c = 0 then lin-add r1 r2 else CN n1 c (lin-add r1 r2 ))) else if n1 ≤ n2 then (CN n1 c1 (lin-add r1 (CN n2 c2 r2 ))) else (CN n2 c2 (lin-add (CN n1 c1 r1 ) r2 ))) | lin-add (CN n1 c1 r1 ) t = CN n1 c1 (lin-add r1 t) | lin-add t (CN n2 c2 r2 ) = CN n2 c2 (lin-add t r2 ) | lin-add (C b1 )(C b2 ) = C (b1 + b2 ) | lin-add a b = Add a b lemma lin-add: Inum (lin-add t s) bs = Inum (Add t s) bs apply (induct t s rule: lin-add.induct, simp-all add: Let-def ) apply (case-tac c1 +c2 = 0 ,case-tac n1 ≤ n2 , simp-all) apply (case-tac n1 = n2 , simp-all add: algebra-simps) done fun lin-mul :: num ⇒ nat ⇒ num where lin-mul (C j ) i = C (i ∗ j ) | lin-mul (CN n c a) i = (if i=0 then (C 0 ) else CN n (i ∗ c)(lin-mul a i)) | lin-mul t i = (Mul i t) lemma lin-mul: Inum (lin-mul t i) bs = Inum (Mul i t) bs by (induct t i rule: lin-mul.induct)(auto simp add: algebra-simps) fun linum:: num ⇒ num where linum (C b) = C b | linum (Var n) = CN n 1 (C 0 ) | linum (Add t s) = lin-add (linum t)(linum s) | linum (Mul c t) = lin-mul (linum t) c | linum (CN n c t) = lin-add (linum (Mul c (Var n))) (linum t) lemma linum [reflection]: Inum (linum t) bs = Inum t bs by (induct t rule: linum.induct)(simp-all add: lin-mul lin-add) Now we can use linum to simplify nat terms using reflection lemma Suc (Suc 1 ) ∗ (x + Suc 1 ∗ y) = 3 ∗ x + 6 ∗ y apply (reflection Inum-eqs 0 only: Suc (Suc 1 ) ∗ (x + Suc 1 ∗ y)) oops 295 Let’s lift this to formulae and see what happens datatype aform = Lt num num | Eq num num | Ge num num | NEq num num | Conj aform aform | Disj aform aform | NEG aform | T | F primrec linaformsize:: aform ⇒ nat where linaformsize T = 1 | linaformsize F = 1 | linaformsize (Lt a b) = 1 | linaformsize (Ge a b) = 1 | linaformsize (Eq a b) = 1 | linaformsize (NEq a b) = 1 | linaformsize (NEG p) = 2 + linaformsize p | linaformsize (Conj p q) = 1 + linaformsize p + linaformsize q | linaformsize (Disj p q) = 1 + linaformsize p + linaformsize q lemma [measure-function]: is-measure linaformsize .. primrec is-aform :: aform => nat list => bool where is-aform T vs = True | is-aform F vs = False | is-aform (Lt a b) vs = (Inum a vs < Inum b vs) | is-aform (Eq a b) vs = (Inum a vs = Inum b vs) | is-aform (Ge a b) vs = (Inum a vs ≥ Inum b vs) | is-aform (NEq a b) vs = (Inum a vs 6= Inum b vs) | is-aform (NEG p) vs = (¬ (is-aform p vs)) | is-aform (Conj p q) vs = (is-aform p vs ∧ is-aform q vs) | is-aform (Disj p q) vs = (is-aform p vs ∨ is-aform q vs) Let’s reify and do reflection lemma (3 ::nat) ∗ x + t < 0 ∧ (2 ∗ x + y 6= 17 ) apply (reify Inum-eqs 0 is-aform.simps) oops Note that reification handles several interpretations at the same time lemma (3 ::nat) ∗ x + t < 0 ∧ x ∗ x + t ∗ x + 3 + 1 = z ∗ t ∗ 4 ∗ z ∨ x + x + 1 < 0 apply (reflection Inum-eqs 0 is-aform.simps only: x + x + 1 ) oops For reflection we now define a simple transformation on aform: NNF + linum on atoms fun linaform:: aform ⇒ aform where linaform (Lt s t) = Lt (linum s)(linum t) | linaform (Eq s t) = Eq (linum s)(linum t) 296 | linaform (Ge s t) = Ge (linum s)(linum t) | linaform (NEq s t) = NEq (linum s)(linum t) | linaform (Conj p q) = Conj (linaform p)(linaform q) | linaform (Disj p q) = Disj (linaform p)(linaform q) | linaform (NEG T ) = F | linaform (NEG F ) = T | linaform (NEG (Lt a b)) = Ge a b | linaform (NEG (Ge a b)) = Lt a b | linaform (NEG (Eq a b)) = NEq a b | linaform (NEG (NEq a b)) = Eq a b | linaform (NEG (NEG p)) = linaform p | linaform (NEG (Conj p q)) = Disj (linaform (NEG p)) (linaform (NEG q)) | linaform (NEG (Disj p q)) = Conj (linaform (NEG p)) (linaform (NEG q)) | linaform p = p lemma linaform: is-aform (linaform p) vs = is-aform p vs by (induct p rule: linaform.induct)(auto simp add: linum) lemma (Suc (Suc (Suc 0 )) ∗ ((x::nat) + Suc (Suc 0 )) + Suc (Suc (Suc 0 )) ∗ (Suc (Suc (Suc 0 ))) ∗ ((x::nat) + Suc (Suc 0 ))) < 0 ∧ Suc 0 + Suc 0 < 0 apply (reflection Inum-eqs 0 is-aform.simps rules: linaform) oops declare linaform [reflection] lemma (Suc (Suc (Suc 0 )) ∗ ((x::nat) + Suc (Suc 0 )) + Suc (Suc (Suc 0 )) ∗ (Suc (Suc (Suc 0 ))) ∗ ((x::nat) + Suc (Suc 0 ))) < 0 ∧ Suc 0 + Suc 0 < 0 apply (reflection Inum-eqs 0 is-aform.simps) oops We now give an example where interpretaions have zero or more than only one envornement of different types and show that automatic reification also deals with bindings datatype rb = BC bool | BAnd rb rb | BOr rb rb primrec Irb :: rb ⇒ bool where Irb (BC p) ←→ p | Irb (BAnd s t) ←→ Irb s ∧ Irb t | Irb (BOr s t) ←→ Irb s ∨ Irb t lemma A ∧ (B ∨ D ∧ B) ∧ A ∧ (B ∨ D ∧ B) ∨ A ∧ (B ∨ D ∧ B) ∨ A ∧ (B ∨ D ∧ B) apply (reify Irb.simps) oops datatype rint = IC int | IVar nat | IAdd rint rint | IMult rint rint | INeg rint | ISub rint rint 297 primrec Irint :: rint ⇒ int list ⇒ int where Irint-Var: Irint (IVar n) vs = vs ! n | Irint-Neg: Irint (INeg t) vs = − Irint t vs | Irint-Add: Irint (IAdd s t) vs = Irint s vs + Irint t vs | Irint-Sub: Irint (ISub s t) vs = Irint s vs − Irint t vs | Irint-Mult: Irint (IMult s t) vs = Irint s vs ∗ Irint t vs | Irint-C : Irint (IC i) vs = i lemma Irint-C0 : Irint (IC 0 ) vs = 0 by simp lemma Irint-C1 : Irint (IC 1 ) vs = 1 by simp lemma Irint-Cnumeral: Irint (IC (numeral x)) vs = numeral x by simp lemmas Irint-simps = Irint-Var Irint-Neg Irint-Add Irint-Sub Irint-Mult Irint-C0 Irint-C1 Irint-Cnumeral lemma (3 ::int) ∗ x + y ∗ y − 9 + (− z) = 0 apply (reify Irint-simps ((3 ::int) ∗ x + y ∗ y − 9 + (− z))) oops datatype rlist = LVar nat | LEmpty | LCons rint rlist | LAppend rlist rlist primrec Irlist :: rlist ⇒ int list ⇒ int list list ⇒ int list where Irlist (LEmpty) is vs = [] | Irlist (LVar n) is vs = vs ! n | Irlist (LCons i t) is vs = Irint i is # Irlist t is vs | Irlist (LAppend s t) is vs = Irlist s is vs @ Irlist t is vs lemma [(1 ::int)] = [] apply (reify Irlist.simps Irint-simps ([1 ] :: int list)) oops lemma ([(3 ::int) ∗ x + y ∗ y − 9 + (− z)] @ []) @ xs = [y ∗ y − z − 9 + (3 ::int) ∗ x] apply (reify Irlist.simps Irint-simps (([(3 ::int) ∗ x + y ∗ y − 9 + (− z)] @ []) @ xs)) oops datatype rnat = NC nat| NVar nat| NSuc rnat | NAdd rnat rnat | NMult rnat rnat | NNeg rnat | NSub rnat rnat | Nlgth rlist primrec Irnat :: rnat ⇒ int list ⇒ int list list ⇒ nat list ⇒ nat 298 where Irnat-Suc: Irnat (NSuc t) is ls vs = Suc (Irnat t is ls vs) | Irnat-Var: Irnat (NVar n) is ls vs = vs ! n | Irnat-Neg: Irnat (NNeg t) is ls vs = 0 | Irnat-Add: Irnat (NAdd s t) is ls vs = Irnat s is ls vs + Irnat t is ls vs | Irnat-Sub: Irnat (NSub s t) is ls vs = Irnat s is ls vs − Irnat t is ls vs | Irnat-Mult: Irnat (NMult s t) is ls vs = Irnat s is ls vs ∗ Irnat t is ls vs | Irnat-lgth: Irnat (Nlgth rxs) is ls vs = length (Irlist rxs is ls) | Irnat-C : Irnat (NC i) is ls vs = i lemma Irnat-C0 : Irnat (NC 0 ) is ls vs = 0 by simp lemma Irnat-C1 : Irnat (NC 1 ) is ls vs = 1 by simp lemma Irnat-Cnumeral: Irnat (NC (numeral x)) is ls vs = numeral x by simp lemmas Irnat-simps = Irnat-Suc Irnat-Var Irnat-Neg Irnat-Add Irnat-Sub Irnat-Mult Irnat-lgth Irnat-C0 Irnat-C1 Irnat-Cnumeral lemma Suc n ∗ length (([(3 ::int) ∗ x + y ∗ y − 9 + (− z)] @ []) @ xs) = length xs apply (reify Irnat-simps Irlist.simps Irint-simps (Suc n ∗ length (([(3 ::int) ∗ x + y ∗ y − 9 + (− z)] @ []) @ xs))) oops datatype rifm = RT | RF | RVar nat | RNLT rnat rnat | RNILT rnat rint | RNEQ rnat rnat | RAnd rifm rifm | ROr rifm rifm | RImp rifm rifm| RIff rifm rifm | RNEX rifm | RIEX rifm | RLEX rifm | RNALL rifm | RIALL rifm | RLALL rifm | RBEX rifm | RBALL rifm primrec Irifm :: rifm ⇒ bool list ⇒ int list ⇒ (int list) list ⇒ nat list ⇒ bool where Irifm RT ps is ls ns ←→ True | Irifm RF ps is ls ns ←→ False | Irifm (RVar n) ps is ls ns ←→ ps ! n | Irifm (RNLT s t) ps is ls ns ←→ Irnat s is ls ns < Irnat t is ls ns | Irifm (RNILT s t) ps is ls ns ←→ int (Irnat s is ls ns) < Irint t is | Irifm (RNEQ s t) ps is ls ns ←→ Irnat s is ls ns = Irnat t is ls ns | Irifm (RAnd p q) ps is ls ns ←→ Irifm p ps is ls ns ∧ Irifm q ps is ls ns | Irifm (ROr p q) ps is ls ns ←→ Irifm p ps is ls ns ∨ Irifm q ps is ls ns | Irifm (RImp p q) ps is ls ns ←→ Irifm p ps is ls ns −→ Irifm q ps is ls ns | Irifm (RIff p q) ps is ls ns ←→ Irifm p ps is ls ns = Irifm q ps is ls ns | Irifm (RNEX p) ps is ls ns ←→ (∃ x. Irifm p ps is ls (x # ns)) 299 | Irifm (RIEX p) ps is ls ns ←→ (∃ x. Irifm p ps (x # is) ls ns) | Irifm (RLEX p) ps is ls ns ←→ (∃ x. Irifm p ps is (x # ls) ns) | Irifm (RBEX p) ps is ls ns ←→ (∃ x. Irifm p (x # ps) is ls ns) | Irifm (RNALL p) ps is ls ns ←→ (∀ x. Irifm p ps is ls (x#ns)) | Irifm (RIALL p) ps is ls ns ←→ (∀ x. Irifm p ps (x # is) ls ns) | Irifm (RLALL p) ps is ls ns ←→ (∀ x. Irifm p ps is (x#ls) ns) | Irifm (RBALL p) ps is ls ns ←→ (∀ x. Irifm p (x # ps) is ls ns) lemma ∀ x. ∃ n. ((Suc n) ∗ length (([(3 ::int) ∗ x + f t ∗ y − 9 + (− z)] @ []) @ xs) = length xs) ∧ m < 5 ∗n − length (xs @[2 ,3 ,4 ,x∗z + 8 − y]) −→ (∃ p. ∀ q. p ∧ q −→ r) apply (reify Irifm.simps Irnat-simps Irlist.simps Irint-simps) oops An example for equations containing type variables datatype prod = Zero | One | Var nat | Mul prod prod | Pw prod nat | PNM nat nat prod primrec Iprod :: prod ⇒ ( 0a::linordered-idom) list ⇒ 0a where Iprod Zero vs = 0 | Iprod One vs = 1 | Iprod (Var n) vs = vs ! n | Iprod (Mul a b) vs = Iprod a vs ∗ Iprod b vs | Iprod (Pw a n) vs = Iprod a vs ˆ n | Iprod (PNM n k t) vs = (vs ! n) ˆ k ∗ Iprod t vs datatype sgn = Pos prod | Neg prod | ZeroEq prod | NZeroEq prod | Tr | F | Or sgn sgn | And sgn sgn primrec Isgn :: sgn ⇒ ( 0a::linordered-idom) list ⇒ bool where Isgn Tr vs ←→ True | Isgn F vs ←→ False | Isgn (ZeroEq t) vs ←→ Iprod t vs = 0 | Isgn (NZeroEq t) vs ←→ Iprod t vs 6= 0 | Isgn (Pos t) vs ←→ Iprod t vs > 0 | Isgn (Neg t) vs ←→ Iprod t vs < 0 | Isgn (And p q) vs ←→ Isgn p vs ∧ Isgn q vs | Isgn (Or p q) vs ←→ Isgn p vs ∨ Isgn q vs lemmas eqs = Isgn.simps Iprod.simps lemma (x:: 0a::{linordered-idom}) ˆ 4 ∗ y ∗ z ∗ y ˆ 2 ∗ z ˆ 23 > 0 apply (reify eqs) oops end 300 46 Factorial (semi)rings theory Factorial-Ring imports Main ∼∼/src/HOL/GCD ∼∼/src/HOL/Library/Multiset begin 46.1 Irreducible and prime elements context comm-semiring-1 begin definition irreducible :: 0a ⇒ bool where irreducible p ←→ p 6= 0 ∧ ¬p dvd 1 ∧ (∀ a b. p = a ∗ b −→ a dvd 1 ∨ b dvd 1 ) lemma not-irreducible-zero [simp]: ¬irreducible 0 by (simp add: irreducible-def ) lemma irreducible-not-unit: irreducible p =⇒ ¬p dvd 1 by (simp add: irreducible-def ) lemma not-irreducible-one [simp]: ¬irreducible 1 by (simp add: irreducible-def ) lemma irreducibleI : p 6= 0 =⇒ ¬p dvd 1 =⇒ (Va b. p = a ∗ b =⇒ a dvd 1 ∨ b dvd 1 ) =⇒ irreducible p by (simp add: irreducible-def ) lemma irreducibleD: irreducible p =⇒ p = a ∗ b =⇒ a dvd 1 ∨ b dvd 1 by (simp add: irreducible-def ) definition prime-elem :: 0a ⇒ bool where prime-elem p ←→ p 6= 0 ∧ ¬p dvd 1 ∧ (∀ a b. p dvd (a ∗ b) −→ p dvd a ∨ p dvd b) lemma not-prime-elem-zero [simp]: ¬prime-elem 0 by (simp add: prime-elem-def ) lemma prime-elem-not-unit: prime-elem p =⇒ ¬p dvd 1 by (simp add: prime-elem-def ) lemma prime-elemI : p 6= 0 =⇒ ¬p dvd 1 =⇒ (Va b. p dvd (a ∗ b) =⇒ p dvd a ∨ p dvd b) =⇒ prime-elem p by (simp add: prime-elem-def ) lemma prime-elem-dvd-multD: 301 prime-elem p =⇒ p dvd (a ∗ b) =⇒ p dvd a ∨ p dvd b by (simp add: prime-elem-def ) lemma prime-elem-dvd-mult-iff : prime-elem p =⇒ p dvd (a ∗ b) ←→ p dvd a ∨ p dvd b by (auto simp: prime-elem-def ) lemma not-prime-elem-one [simp]: ¬ prime-elem 1 by (auto dest: prime-elem-not-unit) lemma prime-elem-not-zeroI : assumes prime-elem p shows p 6= 0 using assms by (auto intro: ccontr) lemma prime-elem-dvd-power: prime-elem p =⇒ p dvd x ˆ n =⇒ p dvd x by (induction n)(auto dest: prime-elem-dvd-multD intro: dvd-trans[of - 1 ]) lemma prime-elem-dvd-power-iff : prime-elem p =⇒ n > 0 =⇒ p dvd x ˆ n ←→ p dvd x by (auto dest: prime-elem-dvd-power intro: dvd-trans) lemma prime-elem-imp-nonzero [simp]: ASSUMPTION (prime-elem x) =⇒ x 6= 0 unfolding ASSUMPTION-def by (rule prime-elem-not-zeroI ) lemma prime-elem-imp-not-one [simp]: ASSUMPTION (prime-elem x) =⇒ x 6= 1 unfolding ASSUMPTION-def by auto end context algebraic-semidom begin lemma prime-elem-imp-irreducible: assumes prime-elem p shows irreducible p proof (rule irreducibleI ) fix a b assume p-eq: p = a ∗ b with assms have nz: a 6= 0 b 6= 0 by auto from p-eq have p dvd a ∗ b by simp with hprime-elem pi have p dvd a ∨ p dvd b by (rule prime-elem-dvd-multD) with hp = a ∗ bi have a ∗ b dvd 1 ∗ b ∨ a ∗ b dvd a ∗ 1 by auto thus a dvd 1 ∨ b dvd 1 by (simp only: dvd-times-left-cancel-iff [OF nz(1 )] dvd-times-right-cancel-iff [OF 302 nz(2 )]) qed (insert assms, simp-all add: prime-elem-def ) lemma (in algebraic-semidom) unit-imp-no-irreducible-divisors: assumes is-unit x irreducible p shows ¬p dvd x proof (rule notI ) assume p dvd x with his-unit x i have is-unit p by (auto intro: dvd-trans) with hirreducible pi show False by (simp add: irreducible-not-unit) qed lemma unit-imp-no-prime-divisors: assumes is-unit x prime-elem p shows ¬p dvd x using unit-imp-no-irreducible-divisors[OF assms(1 ) prime-elem-imp-irreducible[OF assms(2 )]] . lemma prime-elem-mono: assumes prime-elem p ¬q dvd 1 q dvd p shows prime-elem q proof − from hq dvd pi obtain r where r: p = q ∗ r by (elim dvdE) hence p dvd q ∗ r by simp with hprime-elem pi have p dvd q ∨ p dvd r by (rule prime-elem-dvd-multD) hence p dvd q proof assume p dvd r then obtain s where s: r = p ∗ s by (elim dvdE) from r have p ∗ 1 = p ∗ (q ∗ s) by (subst (asm) s)(simp add: mult-ac) with hprime-elem pi have q dvd 1 by (subst (asm) mult-cancel-left) auto with h¬q dvd 1 i show ?thesis by contradiction qed show ?thesis proof (rule prime-elemI ) fix a b assume q dvd (a ∗ b) with hp dvd q i have p dvd (a ∗ b) by (rule dvd-trans) with hprime-elem pi have p dvd a ∨ p dvd b by (rule prime-elem-dvd-multD) with hq dvd pi show q dvd a ∨ q dvd b by (blast intro: dvd-trans) qed (insert assms, auto) qed lemma irreducibleD 0: assumes irreducible a b dvd a shows a dvd b ∨ is-unit b 303 proof − from assms obtain c where c: a = b ∗ c by (elim dvdE) from irreducibleD[OF assms(1 ) this] have is-unit b ∨ is-unit c . thus ?thesis by (auto simp: c mult-unit-dvd-iff ) qed lemma irreducibleI 0: assumes a 6= 0 ¬is-unit a Vb. b dvd a =⇒ a dvd b ∨ is-unit b shows irreducible a proof (rule irreducibleI ) fix b c assume a-eq: a = b ∗ c hence a dvd b ∨ is-unit b by (intro assms) simp-all thus is-unit b ∨ is-unit c proof assume a dvd b hence b ∗ c dvd b ∗ 1 by (simp add: a-eq) moreover from ha 6= 0 i a-eq have b 6= 0 by auto ultimately show ?thesis by (subst (asm) dvd-times-left-cancel-iff ) auto qed blast qed (simp-all add: assms(1 ,2 )) lemma irreducible-altdef : irreducible x ←→ x 6= 0 ∧ ¬is-unit x ∧ (∀ b. b dvd x −→ x dvd b ∨ is-unit b) using irreducibleI 0[of x] irreducibleD 0[of x] irreducible-not-unit[of x] by auto lemma prime-elem-multD: assumes prime-elem (a ∗ b) shows is-unit a ∨ is-unit b proof − from assms have a 6= 0 b 6= 0 by (auto dest!: prime-elem-not-zeroI ) moreover from assms prime-elem-dvd-multD [of a ∗ b] have a ∗ b dvd a ∨ a ∗ b dvd b by auto ultimately show ?thesis using dvd-times-left-cancel-iff [of a b 1 ] dvd-times-right-cancel-iff [of b a 1 ] by auto qed lemma prime-elemD2 : assumes prime-elem p and a dvd p and ¬ is-unit a shows p dvd a proof − from ha dvd pi obtain b where p = a ∗ b .. with hprime-elem pi prime-elem-multD h¬ is-unit a i have is-unit b by auto with hp = a ∗ bi show ?thesis by (auto simp add: mult-unit-dvd-iff ) qed 304 lemma prime-elem-dvd-prod-msetE: assumes prime-elem p assumes dvd: p dvd prod-mset A obtains a where a ∈# A and p dvd a proof − from dvd have ∃ a. a ∈# A ∧ p dvd a proof (induct A) case empty then show ?case using hprime-elem pi by (simp add: prime-elem-not-unit) next case (add a A) then have p dvd a ∗ prod-mset A by simp with hprime-elem pi consider (A) p dvd prod-mset A | (B) p dvd a by (blast dest: prime-elem-dvd-multD) then show ?case proof cases case B then show ?thesis by auto next case A with add.hyps obtain b where b ∈# A p dvd b by auto then show ?thesis by auto qed qed with that show thesis by blast qed context begin private lemma prime-elem-powerD: assumes prime-elem (p ˆ n) shows prime-elem p ∧ n = 1 proof (cases n) case (Suc m) note assms also from Suc have p ˆ n = p ∗ pˆm by simp finally have is-unit p ∨ is-unit (pˆm) by (rule prime-elem-multD) moreover from assms have ¬is-unit p by (simp add: prime-elem-def is-unit-power-iff ) ultimately have is-unit (p ˆ m) by simp with h¬is-unit pi have m = 0 by (simp add: is-unit-power-iff ) with Suc assms show ?thesis by simp qed (insert assms, simp-all) lemma prime-elem-power-iff : prime-elem (p ˆ n) ←→ prime-elem p ∧ n = 1 by (auto dest: prime-elem-powerD) end 305 lemma irreducible-mult-unit-left: is-unit a =⇒ irreducible (a ∗ p) ←→ irreducible p by (auto simp: irreducible-altdef mult.commute[of a] is-unit-mult-iff mult-unit-dvd-iff dvd-mult-unit-iff ) lemma prime-elem-mult-unit-left: is-unit a =⇒ prime-elem (a ∗ p) ←→ prime-elem p by (auto simp: prime-elem-def mult.commute[of a] is-unit-mult-iff mult-unit-dvd-iff ) lemma prime-elem-dvd-cases: assumes pk: p∗k dvd m∗n and p: prime-elem p shows (∃ x. k dvd x∗n ∧ m = p∗x) ∨ (∃ y. k dvd m∗y ∧ n = p∗y) proof − have p dvd m∗n using dvd-mult-left pk by blast then consider p dvd m | p dvd n using p prime-elem-dvd-mult-iff by blast then show ?thesis proof cases case 1 then obtain a where m = p ∗ a by (metis dvd-mult-div-cancel) then have ∃ x. k dvd x ∗ n ∧ m = p ∗ x using p pk by (auto simp: mult.assoc) then show ?thesis .. next case 2 then obtain b where n = p ∗ b by (metis dvd-mult-div-cancel) with p pk have ∃ y. k dvd m∗y ∧ n = p∗y by (metis dvd-mult-right dvd-times-left-cancel-iff mult.left-commute mult-zero-left) then show ?thesis .. qed qed lemma prime-elem-power-dvd-prod: assumes pc: pˆc dvd m∗n and p: prime-elem p shows ∃ a b. a+b = c ∧ pˆa dvd m ∧ pˆb dvd n using pc proof (induct c arbitrary: m n) case 0 show ?case by simp next case (Suc c) consider x where pˆc dvd x∗n m = p∗x | y where pˆc dvd m∗y n = p∗y using prime-elem-dvd-cases [of - pˆc, OF - p] Suc.prems by force then show ?case proof cases case (1 x) with Suc.hyps[of x n] obtain a b where a + b = c ∧ p ˆ a dvd x ∧ p ˆ b dvd n by blast with 1 have Suc a + b = Suc c ∧ p ˆ Suc a dvd m ∧ p ˆ b dvd n by (auto intro: mult-dvd-mono) thus ?thesis by blast next 306 case (2 y) with Suc.hyps[of m y] obtain a b where a + b = c ∧ p ˆ a dvd m ∧ p ˆ b dvd y by blast with 2 have a + Suc b = Suc c ∧ p ˆ a dvd m ∧ p ˆ Suc b dvd n by (auto intro: mult-dvd-mono) with Suc.hyps [of m y] show ∃ a b. a + b = Suc c ∧ p ˆ a dvd m ∧ p ˆ b dvd n by force qed qed lemma prime-elem-power-dvd-cases: assumes p ˆ c dvd m ∗ n and a + b = Suc c and prime-elem p shows p ˆ a dvd m ∨ p ˆ b dvd n proof − from assms obtain r s where r + s = c ∧ p ˆ r dvd m ∧ p ˆ s dvd n by (blast dest: prime-elem-power-dvd-prod) moreover with assms have a ≤ r ∨ b ≤ s by arith ultimately show ?thesis by (auto intro: power-le-dvd) qed lemma prime-elem-not-unit 0 [simp]: ASSUMPTION (prime-elem x) =⇒ ¬is-unit x unfolding ASSUMPTION-def by (rule prime-elem-not-unit) lemma prime-elem-dvd-power-iff : assumes prime-elem p shows p dvd a ˆ n ←→ p dvd a ∧ n > 0 using assms by (induct n)(auto dest: prime-elem-not-unit prime-elem-dvd-multD) lemma prime-power-dvd-multD: assumes prime-elem p assumes p ˆ n dvd a ∗ b and n > 0 and ¬ p dvd a shows p ˆ n dvd b using hp ˆ n dvd a ∗ bi and hn > 0 i proof (induct n arbitrary: b) case 0 then show ?case by simp next case (Suc n) show ?case proof (cases n = 0 ) case True with Suc hprime-elem pi h¬ p dvd a i show ?thesis by (simp add: prime-elem-dvd-mult-iff ) next case False then have n > 0 by simp from hprime-elem pi have p 6= 0 by auto from Suc.prems have ∗: p ∗ p ˆ n dvd a ∗ b by simp 307 then have p dvd a ∗ b by (rule dvd-mult-left) with Suc hprime-elem pi h¬ p dvd a i have p dvd b by (simp add: prime-elem-dvd-mult-iff ) moreover define c where c = b div p ultimately have b: b = p ∗ c by simp with ∗ have p ∗ p ˆ n dvd p ∗ (a ∗ c) by (simp add: ac-simps) with hp 6= 0 i have p ˆ n dvd a ∗ c by simp with Suc.hyps hn > 0 i have p ˆ n dvd c by blast with hp 6= 0 i show ?thesis by (simp add: b) qed qed end 46.2 Generalized primes: normalized prime elements context normalization-semidom begin lemma irreducible-normalized-divisors: assumes irreducible x y dvd x normalize y = y shows y = 1 ∨ y = normalize x proof − from assms have is-unit y ∨ x dvd y by (auto simp: irreducible-altdef ) thus ?thesis proof (elim disjE) assume is-unit y hence normalize y = 1 by (simp add: is-unit-normalize) with assms show ?thesis by simp next assume x dvd y with hy dvd x i have normalize y = normalize x by (rule associatedI ) with assms show ?thesis by simp qed qed lemma irreducible-normalize-iff [simp]: irreducible (normalize x) = irreducible x using irreducible-mult-unit-left[of 1 div unit-factor x x] by (cases x = 0 )(simp-all add: unit-div-commute) lemma prime-elem-normalize-iff [simp]: prime-elem (normalize x) = prime-elem x using prime-elem-mult-unit-left[of 1 div unit-factor x x] by (cases x = 0 )(simp-all add: unit-div-commute) 308 lemma prime-elem-associated: assumes prime-elem p and prime-elem q and q dvd p shows normalize q = normalize p using hq dvd pi proof (rule associatedI ) from hprime-elem q i have ¬ is-unit q by (auto simp add: prime-elem-not-unit) with hprime-elem pi hq dvd pi show p dvd q by (blast intro: prime-elemD2 ) qed definition prime :: 0a ⇒ bool where prime p ←→ prime-elem p ∧ normalize p = p lemma not-prime-0 [simp]: ¬prime 0 by (simp add: prime-def ) lemma not-prime-unit: is-unit x =⇒ ¬prime x using prime-elem-not-unit[of x] by (auto simp add: prime-def ) lemma not-prime-1 [simp]: ¬prime 1 by (simp add: not-prime-unit) lemma primeI : prime-elem x =⇒ normalize x = x =⇒ prime x by (simp add: prime-def ) lemma prime-imp-prime-elem [dest]: prime p =⇒ prime-elem p by (simp add: prime-def ) lemma normalize-prime: prime p =⇒ normalize p = p by (simp add: prime-def ) lemma prime-normalize-iff [simp]: prime (normalize p) ←→ prime-elem p by (auto simp add: prime-def ) lemma prime-power-iff : prime (p ˆ n) ←→ prime p ∧ n = 1 by (auto simp: prime-def prime-elem-power-iff ) lemma prime-imp-nonzero [simp]: ASSUMPTION (prime x) =⇒ x 6= 0 unfolding ASSUMPTION-def prime-def by auto lemma prime-imp-not-one [simp]: ASSUMPTION (prime x) =⇒ x 6= 1 unfolding ASSUMPTION-def by auto lemma prime-not-unit 0 [simp]: ASSUMPTION (prime x) =⇒ ¬is-unit x unfolding ASSUMPTION-def prime-def by auto 309 lemma prime-normalize 0 [simp]: ASSUMPTION (prime x) =⇒ normalize x = x unfolding ASSUMPTION-def prime-def by simp lemma unit-factor-prime: prime x =⇒ unit-factor x = 1 using unit-factor-normalize[of x] unfolding prime-def by auto lemma unit-factor-prime 0 [simp]: ASSUMPTION (prime x) =⇒ unit-factor x = 1 unfolding ASSUMPTION-def by (rule unit-factor-prime) lemma prime-imp-prime-elem 0 [simp]: ASSUMPTION (prime x) =⇒ prime-elem x by (simp add: prime-def ASSUMPTION-def ) lemma prime-dvd-multD: prime p =⇒ p dvd a ∗ b =⇒ p dvd a ∨ p dvd b by (intro prime-elem-dvd-multD) simp-all lemma prime-dvd-mult-iff [simp]: prime p =⇒ p dvd a ∗ b ←→ p dvd a ∨ p dvd b by (auto dest: prime-dvd-multD) lemma prime-dvd-power: prime p =⇒ p dvd x ˆ n =⇒ p dvd x by (auto dest!: prime-elem-dvd-power simp: prime-def ) lemma prime-dvd-power-iff : prime p =⇒ n > 0 =⇒ p dvd x ˆ n ←→ p dvd x by (subst prime-elem-dvd-power-iff ) simp-all lemma prime-dvd-prod-mset-iff : prime p =⇒ p dvd prod-mset A ←→ (∃ x. x ∈# A ∧ p dvd x) by (induction A)(simp-all add: prime-elem-dvd-mult-iff prime-imp-prime-elem, blast+) lemma primes-dvd-imp-eq: assumes prime p prime q p dvd q shows p = q proof − from assms have irreducible q by (simp add: prime-elem-imp-irreducible prime-def ) 0 from irreducibleD [OF this hp dvd q i] assms have q dvd p by simp with hp dvd q i have normalize p = normalize q by (rule associatedI ) with assms show p = q by simp qed lemma prime-dvd-prod-mset-primes-iff : assumes prime p Vq. q ∈# A =⇒ prime q shows p dvd prod-mset A ←→ p ∈# A proof − from assms(1 ) have p dvd prod-mset A ←→ (∃ x. x ∈# A ∧ p dvd x) by (rule 310 prime-dvd-prod-mset-iff ) also from assms have ... ←→ p ∈# A by (auto dest: primes-dvd-imp-eq) finally show ?thesis . qed lemma prod-mset-primes-dvd-imp-subset: assumes prod-mset A dvd prod-mset B Vp. p ∈# A =⇒ prime p Vp. p ∈# B =⇒ prime p shows A ⊆# B using assms proof (induction A arbitrary: B) case empty thus ?case by simp next case (add p A B) hence p: prime p by simp define B 0 where B 0 = B − {#p#} from add.prems have p dvd prod-mset B by (simp add: dvd-mult-left) with add.prems have p ∈# B by (subst (asm)(2 ) prime-dvd-prod-mset-primes-iff ) simp-all hence B: B = B 0 + {#p#} by (simp add: B 0-def ) from add.prems p have A ⊆# B 0 by (intro add.IH )(simp-all add: B) thus ?case by (simp add: B) qed lemma normalize-prod-mset-primes: (Vp. p ∈# A =⇒ prime p) =⇒ normalize (prod-mset A) = prod-mset A proof (induction A) case (add p A) hence prime p by simp hence normalize p = p by simp with add show ?case by (simp add: normalize-mult) qed simp-all lemma prod-mset-dvd-prod-mset-primes-iff : assumes Vx. x ∈# A =⇒ prime x Vx. x ∈# B =⇒ prime x shows prod-mset A dvd prod-mset B ←→ A ⊆# B using assms by (auto intro: prod-mset-subset-imp-dvd prod-mset-primes-dvd-imp-subset) lemma is-unit-prod-mset-primes-iff : assumes Vx. x ∈# A =⇒ prime x shows is-unit (prod-mset A) ←→ A = {#} by (auto simp add: is-unit-prod-mset-iff ) (meson all-not-in-conv assms not-prime-unit set-mset-eq-empty-iff ) lemma prod-mset-primes-irreducible-imp-prime: assumes irred: irreducible (prod-mset A) assumes A: Vx. x ∈# A =⇒ prime x assumes B: Vx. x ∈# B =⇒ prime x 311 assumes C : Vx. x ∈# C =⇒ prime x assumes dvd: prod-mset A dvd prod-mset B ∗ prod-mset C shows prod-mset A dvd prod-mset B ∨ prod-mset A dvd prod-mset C proof − from dvd have prod-mset A dvd prod-mset (B + C ) by simp with ABC have subset: A ⊆# B + C by (subst (asm) prod-mset-dvd-prod-mset-primes-iff ) auto define A1 and A2 where A1 = A ∩# B and A2 = A − A1 have A = A1 + A2 unfolding A1-def A2-def by (rule sym, intro subset-mset.add-diff-inverse) simp-all from subset have A1 ⊆# B A2 ⊆# C by (auto simp: A1-def A2-def Multiset.subset-eq-diff-conv Multiset.union-commute) from hA = A1 + A2 i have prod-mset A = prod-mset A1 ∗ prod-mset A2 by simp from irred and this have is-unit (prod-mset A1 ) ∨ is-unit (prod-mset A2 ) by (rule irreducibleD) with A have A1 = {#} ∨ A2 = {#} unfolding A1-def A2-def by (subst (asm)(1 2 ) is-unit-prod-mset-primes-iff )(auto dest: Multiset.in-diffD) with dvd hA = A1 + A2 i hA1 ⊆# B i hA2 ⊆# C i show ?thesis by (auto intro: prod-mset-subset-imp-dvd) qed lemma prod-mset-primes-finite-divisor-powers: assumes A: Vx. x ∈# A =⇒ prime x assumes B: Vx. x ∈# B =⇒ prime x assumes A 6= {#} shows finite {n. prod-mset A ˆ n dvd prod-mset B} proof − from hA 6= {#}i obtain x where x: x ∈# A by blast define m where m = count B x have {n. prod-mset A ˆ n dvd prod-mset B} ⊆ {..m} proof safe fix n assume dvd: prod-mset A ˆ n dvd prod-mset B from x have x ˆ n dvd prod-mset A ˆ n by (intro dvd-power-same dvd-prod-mset) also note dvd also have x ˆ n = prod-mset (replicate-mset n x) by simp finally have replicate-mset n x ⊆# B by (rule prod-mset-primes-dvd-imp-subset)(insert A B x, simp-all split: if-splits) thus n ≤ m by (simp add: count-le-replicate-mset-subset-eq m-def ) qed moreover have finite {..m} by simp ultimately show ?thesis by (rule finite-subset) qed end 312 46.3 In a semiring with GCD, each irreducible element is a prime elements context semiring-gcd begin lemma irreducible-imp-prime-elem-gcd: assumes irreducible x shows prime-elem x proof (rule prime-elemI ) fix a b assume x dvd a ∗ b from dvd-productE[OF this] obtain y z where yz: x = y ∗ z y dvd a z dvd b . from hirreducible x i and hx = y ∗ z i have is-unit y ∨ is-unit z by (rule irre- ducibleD) with yz show x dvd a ∨ x dvd b by (auto simp: mult-unit-dvd-iff mult-unit-dvd-iff 0) qed (insert assms, auto simp: irreducible-not-unit) lemma prime-elem-imp-coprime: assumes prime-elem p ¬p dvd n shows coprime p n proof (rule coprimeI ) fix d assume d dvd p d dvd n show is-unit d proof (rule ccontr) assume ¬is-unit d from hprime-elem pi and hd dvd pi and this have p dvd d by (rule prime-elemD2 ) from this and hd dvd n i have p dvd n by (rule dvd-trans) with h¬p dvd n i show False by contradiction qed qed lemma prime-imp-coprime: assumes prime p ¬p dvd n shows coprime p n using assms by (simp add: prime-elem-imp-coprime) lemma prime-elem-imp-power-coprime: prime-elem p =⇒ ¬p dvd a =⇒ coprime a (p ˆ m) by (auto intro!: coprime-exp dest: prime-elem-imp-coprime simp: gcd.commute) lemma prime-imp-power-coprime: prime p =⇒ ¬p dvd a =⇒ coprime a (p ˆ m) by (simp add: prime-elem-imp-power-coprime) lemma prime-elem-divprod-pow: assumes p: prime-elem p and ab: coprime a b and pab: pˆn dvd a ∗ b shows pˆn dvd a ∨ pˆn dvd b using assms 313 proof − from ab p have ¬p dvd a ∨ ¬p dvd b by (auto simp: coprime prime-elem-def ) with p have coprime (pˆn) a ∨ coprime (pˆn) b by (auto intro: prime-elem-imp-coprime coprime-exp-left) with pab show ?thesis by (auto intro: coprime-dvd-mult simp: mult-ac) qed lemma primes-coprime: prime p =⇒ prime q =⇒ p 6= q =⇒ coprime p q using prime-imp-coprime primes-dvd-imp-eq by blast end 46.4 Factorial semirings: algebraic structures with unique prime factorizations class factorial-semiring = normalization-semidom + assumes prime-factorization-exists: x 6= 0 =⇒ ∃ A. (∀ x. x ∈# A −→ prime-elem x) ∧ prod-mset A = normalize x Alternative characterization lemma (in normalization-semidom) factorial-semiring-altI-aux: assumes finite-divisors: Vx. x 6= 0 =⇒ finite {y. y dvd x ∧ normalize y = y} assumes irreducible-imp-prime-elem: Vx. irreducible x =⇒ prime-elem x assumes x 6= 0 shows ∃ A. (∀ x. x ∈# A −→ prime-elem x) ∧ prod-mset A = normalize x using hx 6= 0 i proof (induction card {b. b dvd x ∧ normalize b = b} arbitrary: x rule: less-induct) case (less a) let ?fctrs = λa. {b. b dvd a ∧ normalize b = b} show ?case proof (cases is-unit a) case True thus ?thesis by (intro exI [of - {#}]) (auto simp: is-unit-normalize) next case False show ?thesis proof (cases ∃ b. b dvd a ∧ ¬is-unit b ∧ ¬a dvd b) case False with h¬is-unit a i less.prems have irreducible a by (auto simp: irreducible-altdef ) hence prime-elem a by (rule irreducible-imp-prime-elem) thus ?thesis by (intro exI [of - {#normalize a#}]) auto next case True then guess b by (elim exE conjE) note b = this from b have ?fctrs b ⊆ ?fctrs a by (auto intro: dvd-trans) moreover from b have normalize a ∈/ ?fctrs b normalize a ∈ ?fctrs a by 314 simp-all hence ?fctrs b 6= ?fctrs a by blast ultimately have ?fctrs b ⊂ ?fctrs a by (subst subset-not-subset-eq) blast with finite-divisors[OF ha 6= 0 i] have card (?fctrs b) < card (?fctrs a) by (rule psubset-card-mono) moreover from ha 6= 0 i b have b 6= 0 by auto ultimately have ∃ A. (∀ x. x ∈# A −→ prime-elem x) ∧ prod-mset A = normalize b by (intro less) auto then guess A .. note A = this define c where c = a div b from b have c: a = b ∗ c by (simp add: c-def ) from less.prems c have c 6= 0 by auto from b c have ?fctrs c ⊆ ?fctrs a by (auto intro: dvd-trans) moreover have normalize a ∈/ ?fctrs c proof safe assume normalize a dvd c hence b ∗ c dvd 1 ∗ c by (simp add: c) hence b dvd 1 by (subst (asm) dvd-times-right-cancel-iff ) fact+ with b show False by simp qed with hnormalize a ∈ ?fctrs a i have ?fctrs a 6= ?fctrs c by blast ultimately have ?fctrs c ⊂ ?fctrs a by (subst subset-not-subset-eq) blast with finite-divisors[OF ha 6= 0 i] have card (?fctrs c) < card (?fctrs a) by (rule psubset-card-mono) with hc 6= 0 i have ∃ A. (∀ x. x ∈# A −→ prime-elem x) ∧ prod-mset A = normalize c by (intro less) auto then guess B .. note B = this from AB show ?thesis by (intro exI [of - A + B]) (auto simp: c normalize-mult) qed qed qed lemma factorial-semiring-altI : assumes finite-divisors: Vx:: 0a. x 6= 0 =⇒ finite {y. y dvd x ∧ normalize y = y} assumes irreducible-imp-prime: Vx:: 0a. irreducible x =⇒ prime-elem x shows OFCLASS( 0a :: normalization-semidom, factorial-semiring-class) by intro-classes (rule factorial-semiring-altI-aux[OF assms]) Properties context factorial-semiring begin lemma prime-factorization-exists 0: assumes x 6= 0 315 obtains A where Vx. x ∈# A =⇒ prime x prod-mset A = normalize x proof − from prime-factorization-exists[OF assms] obtain A where A: Vx. x ∈# A =⇒ prime-elem x prod-mset A = normalize x by blast define A 0 where A 0 = image-mset normalize A have prod-mset A 0 = normalize (prod-mset A) by (simp add: A 0-def normalize-prod-mset) also note A(2 ) finally have prod-mset A 0 = normalize x by simp moreover from A(1 ) have ∀ x. x ∈# A 0 −→ prime x by (auto simp: prime-def A 0-def ) ultimately show ?thesis by (intro that[of A 0]) blast qed lemma irreducible-imp-prime-elem: assumes irreducible x shows prime-elem x proof (rule prime-elemI ) fix a b assume dvd: x dvd a ∗ b from assms have x 6= 0 by auto show x dvd a ∨ x dvd b proof (cases a = 0 ∨ b = 0 ) case False hence a 6= 0 b 6= 0 by blast+ note nz = hx 6= 0 i this from nz[THEN prime-factorization-exists 0] guess ABC . note ABC = this from assms ABC have irreducible (prod-mset A) by simp from dvd prod-mset-primes-irreducible-imp-prime[of A B C , OF this ABC (1 ,3 ,5 )] ABC (2 ,4 ,6 ) show ?thesis by (simp add: normalize-mult [symmetric]) qed auto qed (insert assms, simp-all add: irreducible-def ) lemma finite-divisor-powers: assumes y 6= 0 ¬is-unit x shows finite {n. x ˆ n dvd y} proof (cases x = 0 ) case True with assms have {n. x ˆ n dvd y} = {0 } by (auto simp: power-0-left) thus ?thesis by simp next case False note nz = this hy 6= 0 i from nz[THEN prime-factorization-exists 0] guess AB . note AB = this from AB assms have A 6= {#} by (auto simp: normalize-1-iff ) from AB(2 ,4 ) prod-mset-primes-finite-divisor-powers [of A B, OF AB(1 ,3 ) this] show ?thesis by (simp add: normalize-power [symmetric]) qed 316 lemma finite-prime-divisors: assumes x 6= 0 shows finite {p. prime p ∧ p dvd x} proof − from prime-factorization-exists 0[OF assms] guess A . note A = this have {p. prime p ∧ p dvd x} ⊆ set-mset A proof safe fix p assume p: prime p and dvd: p dvd x from dvd have p dvd normalize x by simp also from A have normalize x = prod-mset A by simp finally show p ∈# A using p A by (subst (asm) prime-dvd-prod-mset-primes-iff ) qed moreover have finite (set-mset A) by simp ultimately show ?thesis by (rule finite-subset) qed lemma prime-elem-iff-irreducible: prime-elem x ←→ irreducible x by (blast intro: irreducible-imp-prime-elem prime-elem-imp-irreducible) lemma prime-divisor-exists: assumes a 6= 0 ¬is-unit a shows ∃ b. b dvd a ∧ prime b proof − from prime-factorization-exists 0[OF assms(1 )] guess A . note A = this moreover from A and assms have A 6= {#} by auto then obtain x where x ∈# A by blast with A(1 ) have ∗: x dvd prod-mset A prime x by (auto simp: dvd-prod-mset) with A have x dvd a by simp with ∗ show ?thesis by blast qed lemma prime-divisors-induct [case-names zero unit factor]: assumes P 0 Vx. is-unit x =⇒ P x Vp x. prime p =⇒ P x =⇒ P (p ∗ x) shows P x proof (cases x = 0 ) case False from prime-factorization-exists 0[OF this] guess A . note A = this from A(1 ) have P (unit-factor x ∗ prod-mset A) proof (induction A) case (add p A) from add.prems have prime p by simp moreover from add.prems have P (unit-factor x ∗ prod-mset A) by (intro add.IH ) simp-all ultimately have P (p ∗ (unit-factor x ∗ prod-mset A)) by (rule assms(3 )) thus ?case by (simp add: mult-ac) qed (simp-all add: assms False) with A show ?thesis by simp qed (simp-all add: assms(1 )) 317 lemma no-prime-divisors-imp-unit: assumes a 6= 0 Vb. b dvd a =⇒ normalize b = b =⇒ ¬ prime-elem b shows is-unit a proof (rule ccontr) assume ¬is-unit a from prime-divisor-exists[OF assms(1 ) this] guess b by (elim exE conjE) with assms(2 )[of b] show False by (simp add: prime-def ) qed lemma prime-divisorE: assumes a 6= 0 and ¬ is-unit a obtains p where prime p and p dvd a using assms no-prime-divisors-imp-unit unfolding prime-def by blast definition multiplicity :: 0a ⇒ 0a ⇒ nat where multiplicity p x = (if finite {n. p ˆ n dvd x} then Max {n. p ˆ n dvd x} else 0 ) lemma multiplicity-dvd: p ˆ multiplicity p x dvd x proof (cases finite {n. p ˆ n dvd x}) case True hence multiplicity p x = Max {n. p ˆ n dvd x} by (simp add: multiplicity-def ) also have ... ∈ {n. p ˆ n dvd x} by (rule Max-in)(auto intro!: True exI [of - 0 ::nat]) finally show ?thesis by simp qed (simp add: multiplicity-def ) lemma multiplicity-dvd 0: n ≤ multiplicity p x =⇒ p ˆ n dvd x by (rule dvd-trans[OF le-imp-power-dvd multiplicity-dvd]) context fixes x p :: 0a assumes xp: x 6= 0 ¬is-unit p begin lemma multiplicity-eq-Max: multiplicity p x = Max {n. p ˆ n dvd x} using finite-divisor-powers[OF xp] by (simp add: multiplicity-def ) lemma multiplicity-geI : assumes p ˆ n dvd x shows multiplicity p x ≥ n proof − from assms have n ≤ Max {n. p ˆ n dvd x} by (intro Max-ge finite-divisor-powers xp) simp-all thus ?thesis by (subst multiplicity-eq-Max) qed lemma multiplicity-lessI : assumes ¬p ˆ n dvd x 318 shows multiplicity p x < n proof (rule ccontr) assume ¬(n > multiplicity p x) hence p ˆ n dvd x by (intro multiplicity-dvd 0) simp with assms show False by contradiction qed lemma power-dvd-iff-le-multiplicity: p ˆ n dvd x ←→ n ≤ multiplicity p x using multiplicity-geI [of n] multiplicity-lessI [of n] by (cases p ˆ n dvd x) auto lemma multiplicity-eq-zero-iff : shows multiplicity p x = 0 ←→ ¬p dvd x using power-dvd-iff-le-multiplicity[of 1 ] by auto lemma multiplicity-gt-zero-iff : shows multiplicity p x > 0 ←→ p dvd x using power-dvd-iff-le-multiplicity[of 1 ] by auto lemma multiplicity-decompose: ¬p dvd (x div p ˆ multiplicity p x) proof assume ∗: p dvd x div p ˆ multiplicity p x have x = x div p ˆ multiplicity p x ∗ (p ˆ multiplicity p x) using multiplicity-dvd[of p x] by simp also from ∗ have x div p ˆ multiplicity p x = (x div p ˆ multiplicity p x div p) ∗ p by simp also have x div p ˆ multiplicity p x div p ∗ p ∗ p ˆ multiplicity p x = x div p ˆ multiplicity p x div p ∗ p ˆ Suc (multiplicity p x) by (simp add: mult-assoc) also have p ˆ Suc (multiplicity p x) dvd ... by (rule dvd-triv-right) finally show False by (subst (asm) power-dvd-iff-le-multiplicity) simp qed lemma multiplicity-decompose 0: obtains y where x = p ˆ multiplicity p x ∗ y ¬p dvd y using that[of x div p ˆ multiplicity p x] by (simp add: multiplicity-decompose multiplicity-dvd) end lemma multiplicity-zero [simp]: multiplicity p 0 = 0 by (simp add: multiplicity-def ) lemma prime-elem-multiplicity-eq-zero-iff : prime-elem p =⇒ x 6= 0 =⇒ multiplicity p x = 0 ←→ ¬p dvd x by (rule multiplicity-eq-zero-iff ) simp-all lemma prime-multiplicity-other: 319 assumes prime p prime q p 6= q shows multiplicity p q = 0 using assms by (subst prime-elem-multiplicity-eq-zero-iff )(auto dest: primes-dvd-imp-eq) lemma prime-multiplicity-gt-zero-iff : prime-elem p =⇒ x 6= 0 =⇒ multiplicity p x > 0 ←→ p dvd x by (rule multiplicity-gt-zero-iff ) simp-all lemma multiplicity-unit-left: is-unit p =⇒ multiplicity p x = 0 by (simp add: multiplicity-def is-unit-power-iff unit-imp-dvd) lemma multiplicity-unit-right: assumes is-unit x shows multiplicity p x = 0 proof (cases is-unit p ∨ x = 0 ) case False with multiplicity-lessI [of x p 1 ] this assms show ?thesis by (auto dest: dvd-unit-imp-unit) qed (auto simp: multiplicity-unit-left) lemma multiplicity-one [simp]: multiplicity p 1 = 0 by (rule multiplicity-unit-right) simp-all lemma multiplicity-eqI : assumes p ˆ n dvd x ¬p ˆ Suc n dvd x shows multiplicity p x = n proof − consider x = 0 | is-unit p | x 6= 0 ¬is-unit p by blast thus ?thesis proof cases assume xp: x 6= 0 ¬is-unit p from xp assms(1 ) have multiplicity p x ≥ n by (intro multiplicity-geI ) moreover from assms(2 ) xp have multiplicity p x < Suc n by (intro multiplicity-lessI ) ultimately show ?thesis by simp next assume is-unit p hence is-unit (p ˆ Suc n) by (simp add: is-unit-power-iff del: power-Suc) hence p ˆ Suc n dvd x by (rule unit-imp-dvd) with h¬p ˆ Suc n dvd x i show ?thesis by contradiction qed (insert assms, simp-all) qed context fixes x p :: 0a assumes xp: x 6= 0 ¬is-unit p begin 320 lemma multiplicity-times-same: assumes p 6= 0 shows multiplicity p (p ∗ x) = Suc (multiplicity p x) proof (rule multiplicity-eqI ) show p ˆ Suc (multiplicity p x) dvd p ∗ x by (auto intro!: mult-dvd-mono multiplicity-dvd) from xp assms show ¬ p ˆ Suc (Suc (multiplicity p x)) dvd p ∗ x using power-dvd-iff-le-multiplicity[OF xp, of Suc (multiplicity p x)] by simp qed end lemma multiplicity-same-power 0: multiplicity p (p ˆ n) = (if p = 0 ∨ is-unit p then 0 else n) proof − consider p = 0 | is-unit p |p 6= 0 ¬is-unit p by blast thus ?thesis proof cases assume p 6= 0 ¬is-unit p thus ?thesis by (induction n)(simp-all add: multiplicity-times-same) qed (simp-all add: power-0-left multiplicity-unit-left) qed lemma multiplicity-same-power: p 6= 0 =⇒ ¬is-unit p =⇒ multiplicity p (p ˆ n) = n by (simp add: multiplicity-same-power 0) lemma multiplicity-prime-elem-times-other: assumes prime-elem p ¬p dvd q shows multiplicity p (q ∗ x) = multiplicity p x proof (cases x = 0 ) case False show ?thesis proof (rule multiplicity-eqI ) have 1 ∗ p ˆ multiplicity p x dvd q ∗ x by (intro mult-dvd-mono multiplicity-dvd) simp-all thus p ˆ multiplicity p x dvd q ∗ x by simp next define n where n = multiplicity p x from assms have ¬is-unit p by simp from multiplicity-decompose 0[OF False this] guess y . note y = this [folded n-def ] from y have p ˆ Suc n dvd q ∗ x ←→ p ˆ n ∗ p dvd p ˆ n ∗ (q ∗ y) by (simp add: mult-ac) also from assms have ... ←→ p dvd q ∗ y by simp also have ... ←→ p dvd q ∨ p dvd y by (rule prime-elem-dvd-mult-iff ) fact+ also from assms y have ... ←→ False by simp finally show ¬(p ˆ Suc n dvd q ∗ x) by blast qed 321 qed simp-all lemma multiplicity-self : assumes p 6= 0 ¬is-unit p shows multiplicity p p = 1 proof − from assms have multiplicity p p = Max {n. p ˆ n dvd p} by (simp add: multiplicity-eq-Max) also from assms have p ˆ n dvd p ←→ n ≤ 1 for n using dvd-power-iff [of p n 1 ] by auto hence {n. p ˆ n dvd p} = {..1 } by auto also have ... = {0 ,1 } by auto finally show ?thesis by simp qed lemma multiplicity-times-unit-left: assumes is-unit c shows multiplicity (c ∗ p) x = multiplicity p x proof − from assms have {n. (c ∗ p) ˆ n dvd x} = {n. p ˆ n dvd x} by (subst mult.commute)(simp add: mult-unit-dvd-iff power-mult-distrib is-unit-power-iff ) thus ?thesis by (simp add: multiplicity-def ) qed lemma multiplicity-times-unit-right: assumes is-unit c shows multiplicity p (c ∗ x) = multiplicity p x proof − from assms have {n. p ˆ n dvd c ∗ x} = {n. p ˆ n dvd x} by (subst mult.commute)(simp add: dvd-mult-unit-iff ) thus ?thesis by (simp add: multiplicity-def ) qed lemma multiplicity-normalize-left [simp]: multiplicity (normalize p) x = multiplicity p x proof (cases p = 0 ) case [simp]: False have normalize p = (1 div unit-factor p) ∗ p by (simp add: unit-div-commute is-unit-unit-factor) also have multiplicity ... x = multiplicity p x by (rule multiplicity-times-unit-left)(simp add: is-unit-unit-factor) finally show ?thesis . qed simp-all lemma multiplicity-normalize-right [simp]: multiplicity p (normalize x) = multiplicity p x proof (cases x = 0 ) case [simp]: False have normalize x = (1 div unit-factor x) ∗ x 322 by (simp add: unit-div-commute is-unit-unit-factor) also have multiplicity p ... = multiplicity p x by (rule multiplicity-times-unit-right)(simp add: is-unit-unit-factor) finally show ?thesis . qed simp-all lemma multiplicity-prime [simp]: prime-elem p =⇒ multiplicity p p = 1 by (rule multiplicity-self ) auto lemma multiplicity-prime-power [simp]: prime-elem p =⇒ multiplicity p (p ˆ n) = n by (subst multiplicity-same-power 0) auto lift-definition prime-factorization :: 0a ⇒ 0a multiset is λx p. if prime p then multiplicity p x else 0 unfolding multiset-def proof clarify fix x :: 0a show finite {p. 0 < (if prime p then multiplicity p x else 0 )} (is finite ?A) proof (cases x = 0 ) case False from False have ?A ⊆ {p. prime p ∧ p dvd x} by (auto simp: multiplicity-gt-zero-iff ) moreover from False have finite {p. prime p ∧ p dvd x} by (rule finite-prime-divisors) ultimately show ?thesis by (rule finite-subset) qed simp-all qed abbreviation prime-factors :: 0a ⇒ 0a set where prime-factors a ≡ set-mset (prime-factorization a) lemma count-prime-factorization-nonprime: ¬prime p =⇒ count (prime-factorization x) p = 0 by transfer simp lemma count-prime-factorization-prime: prime p =⇒ count (prime-factorization x) p = multiplicity p x by transfer simp lemma count-prime-factorization: count (prime-factorization x) p = (if prime p then multiplicity p x else 0 ) by transfer simp lemma dvd-imp-multiplicity-le: assumes a dvd b b 6= 0 shows multiplicity p a ≤ multiplicity p b proof (cases is-unit p) case False 323 with assms show ?thesis by (intro multiplicity-geI )(auto intro: dvd-trans[OF multiplicity-dvd 0 assms(1 )]) qed (insert assms, auto simp: multiplicity-unit-left) lemma prime-factorization-0 [simp]: prime-factorization 0 = {#} by (simp add: multiset-eq-iff count-prime-factorization) lemma prime-factorization-empty-iff : prime-factorization x = {#} ←→ x = 0 ∨ is-unit x proof assume ∗: prime-factorization x = {#} { assume x: x 6= 0 ¬is-unit x { fix p assume p: prime p have count (prime-factorization x) p = 0 by (simp add: ∗) also from p have count (prime-factorization x) p = multiplicity p x by (rule count-prime-factorization-prime) also from x p have ... = 0 ←→ ¬p dvd x by (simp add: multiplicity-eq-zero-iff ) finally have ¬p dvd x . } with prime-divisor-exists[OF x] have False by blast } thus x = 0 ∨ is-unit x by blast next assume x = 0 ∨ is-unit x thus prime-factorization x = {#} proof assume x: is-unit x { fix p assume p: prime p from p x have multiplicity p x = 0 by (subst multiplicity-eq-zero-iff ) (auto simp: multiplicity-eq-zero-iff dest: unit-imp-no-prime-divisors) } thus ?thesis by (simp add: multiset-eq-iff count-prime-factorization) qed simp-all qed lemma prime-factorization-unit: assumes is-unit x shows prime-factorization x = {#} proof (rule multiset-eqI ) fix p :: 0a show count (prime-factorization x) p = count {#} p proof (cases prime p) case True with assms have multiplicity p x = 0 by (subst multiplicity-eq-zero-iff ) 324 (auto simp: multiplicity-eq-zero-iff dest: unit-imp-no-prime-divisors) with True show ?thesis by (simp add: count-prime-factorization-prime) qed (simp-all add: count-prime-factorization-nonprime) qed lemma prime-factorization-1 [simp]: prime-factorization 1 = {#} by (simp add: prime-factorization-unit) lemma prime-factorization-times-prime: assumes x 6= 0 prime p shows prime-factorization (p ∗ x) = {#p#} + prime-factorization x proof (rule multiset-eqI ) fix q :: 0a consider ¬prime q | p = q | prime q p 6= q by blast thus count (prime-factorization (p ∗ x)) q = count ({#p#} + prime-factorization x) q proof cases assume q: prime q p 6= q with assms primes-dvd-imp-eq[of q p] have ¬q dvd p by auto with q assms show ?thesis by (simp add: multiplicity-prime-elem-times-other count-prime-factorization) qed (insert assms, auto simp: count-prime-factorization multiplicity-times-same) qed lemma prod-mset-prime-factorization: assumes x 6= 0 shows prod-mset (prime-factorization x) = normalize x using assms by (induction x rule: prime-divisors-induct) (simp-all add: prime-factorization-unit prime-factorization-times-prime is-unit-normalize normalize-mult) lemma in-prime-factors-iff : p ∈ prime-factors x ←→ x 6= 0 ∧ p dvd x ∧ prime p proof − have p ∈ prime-factors x ←→ count (prime-factorization x) p > 0 by simp also have ... ←→ x 6= 0 ∧ p dvd x ∧ prime p by (subst count-prime-factorization, cases x = 0 ) (auto simp: multiplicity-eq-zero-iff multiplicity-gt-zero-iff ) finally show ?thesis . qed lemma in-prime-factors-imp-prime [intro]: p ∈ prime-factors x =⇒ prime p by (simp add: in-prime-factors-iff ) lemma in-prime-factors-imp-dvd [dest]: p ∈ prime-factors x =⇒ p dvd x by (simp add: in-prime-factors-iff ) 325 lemma prime-factorsI : x 6= 0 =⇒ prime p =⇒ p dvd x =⇒ p ∈ prime-factors x by (auto simp: in-prime-factors-iff ) lemma prime-factors-dvd: x 6= 0 =⇒ prime-factors x = {p. prime p ∧ p dvd x} by (auto intro: prime-factorsI ) lemma prime-factors-multiplicity: prime-factors n = {p. prime p ∧ multiplicity p n > 0 } by (cases n = 0 )(auto simp add: prime-factors-dvd prime-multiplicity-gt-zero-iff ) lemma prime-factorization-prime: assumes prime p shows prime-factorization p = {#p#} proof (rule multiset-eqI ) fix q :: 0a consider ¬prime q | q = p | prime q q 6= p by blast thus count (prime-factorization p) q = count {#p#} q by cases (insert assms, auto dest: primes-dvd-imp-eq simp: count-prime-factorization multiplicity-self multiplicity-eq-zero-iff ) qed lemma prime-factorization-prod-mset-primes: assumes Vp. p ∈# A =⇒ prime p shows prime-factorization (prod-mset A) = A using assms proof (induction A) case (add p A) from add.prems[of 0 ] have 0 ∈/# A by auto hence prod-mset A 6= 0 by auto with add show ?case by (simp-all add: mult-ac prime-factorization-times-prime Multiset.union-commute) qed simp-all lemma prime-factorization-cong: normalize x = normalize y =⇒ prime-factorization x = prime-factorization y by (simp add: multiset-eq-iff count-prime-factorization multiplicity-normalize-right [of - x, symmetric] multiplicity-normalize-right [of - y, symmetric] del: multiplicity-normalize-right) lemma prime-factorization-unique: assumes x 6= 0 y 6= 0 shows prime-factorization x = prime-factorization y ←→ normalize x = nor- malize y proof assume prime-factorization x = prime-factorization y 326 hence prod-mset (prime-factorization x) = prod-mset (prime-factorization y) by simp with assms show normalize x = normalize y by (simp add: prod-mset-prime-factorization) qed (rule prime-factorization-cong) lemma prime-factorization-mult: assumes x 6= 0 y 6= 0 shows prime-factorization (x ∗ y) = prime-factorization x + prime-factorization y proof − have prime-factorization (prod-mset (prime-factorization (x ∗ y))) = prime-factorization (prod-mset (prime-factorization x + prime-factorization y)) by (simp add: prod-mset-prime-factorization assms normalize-mult) also have prime-factorization (prod-mset (prime-factorization (x ∗ y))) = prime-factorization (x ∗ y) by (rule prime-factorization-prod-mset-primes)(simp-all add: in-prime-factors-imp-prime) also have prime-factorization (prod-mset (prime-factorization x + prime-factorization y)) = prime-factorization x + prime-factorization y by (rule prime-factorization-prod-mset-primes)(auto simp: in-prime-factors-imp-prime) finally show ?thesis . qed lemma prime-elem-multiplicity-mult-distrib: assumes prime-elem p x 6= 0 y 6= 0 shows multiplicity p (x ∗ y) = multiplicity p x + multiplicity p y proof − have multiplicity p (x ∗ y) = count (prime-factorization (x ∗ y)) (normalize p) by (subst count-prime-factorization-prime)(simp-all add: assms) also from assms have prime-factorization (x ∗ y) = prime-factorization x + prime-factorization y by (intro prime-factorization-mult) also have count ... (normalize p) = count (prime-factorization x)(normalize p) + count (prime-factorization y) (normalize p) by simp also have ... = multiplicity p x + multiplicity p y by (subst (1 2 ) count-prime-factorization-prime)(simp-all add: assms) finally show ?thesis . qed lemma prime-elem-multiplicity-prod-mset-distrib: assumes prime-elem p 0 ∈/# A shows multiplicity p (prod-mset A) = sum-mset (image-mset (multiplicity p) A) using assms by (induction A)(auto simp: prime-elem-multiplicity-mult-distrib) 327 lemma prime-elem-multiplicity-power-distrib: assumes prime-elem p x 6= 0 shows multiplicity p (x ˆ n) = n ∗ multiplicity p x using assms prime-elem-multiplicity-prod-mset-distrib [of p replicate-mset n x] by simp lemma prime-elem-multiplicity-prod-distrib: assumes prime-elem p 0 ∈/ f ‘ A finite A shows multiplicity p (prod f A) = (P x∈A. multiplicity p (f x)) proof − have multiplicity p (prod f A) = (P x∈#mset-set A. multiplicity p (f x)) using assms by (subst prod-unfold-prod-mset) (simp-all add: prime-elem-multiplicity-prod-mset-distrib sum-unfold-sum-mset multiset.map-comp o-def ) also from hfinite Ai have ... = (P x∈A. multiplicity p (f x)) by (induction A rule: finite-induct) simp-all finally show ?thesis . qed lemma multiplicity-distinct-prime-power: prime p =⇒ prime q =⇒ p 6= q =⇒ multiplicity p (q ˆ n) = 0 by (subst prime-elem-multiplicity-power-distrib)(auto simp: prime-multiplicity-other) lemma prime-factorization-prime-power: prime p =⇒ prime-factorization (p ˆ n) = replicate-mset n p by (induction n) (simp-all add: prime-factorization-mult prime-factorization-prime Multiset.union-commute) lemma prime-decomposition: unit-factor x ∗ prod-mset (prime-factorization x) = x by (cases x = 0 )(simp-all add: prod-mset-prime-factorization) lemma prime-factorization-subset-iff-dvd: assumes [simp]: x 6= 0 y 6= 0 shows prime-factorization x ⊆# prime-factorization y ←→ x dvd y proof − have x dvd y ←→ prod-mset (prime-factorization x) dvd prod-mset (prime-factorization y) by (simp add: prod-mset-prime-factorization) also have ... ←→ prime-factorization x ⊆# prime-factorization y by (auto intro!: prod-mset-primes-dvd-imp-subset prod-mset-subset-imp-dvd) finally show ?thesis .. qed lemma prime-factorization-subset-imp-dvd: x 6= 0 =⇒ (prime-factorization x ⊆# prime-factorization y) =⇒ x dvd y by (cases y = 0 )(simp-all add: prime-factorization-subset-iff-dvd) 328 lemma prime-factorization-divide: assumes b dvd a shows prime-factorization (a div b) = prime-factorization a − prime-factorization b proof (cases a = 0 ) case [simp]: False from assms have [simp]: b 6= 0 by auto have prime-factorization ((a div b) ∗ b) = prime-factorization (a div b) + prime-factorization b by (intro prime-factorization-mult)(insert assms, auto elim!: dvdE) with assms show ?thesis by simp qed simp-all lemma zero-not-in-prime-factors [simp]: 0 ∈/ prime-factors x by (auto dest: in-prime-factors-imp-prime) lemma prime-prime-factors: prime p =⇒ prime-factors p = {p} by (drule prime-factorization-prime) simp lemma prod-prime-factors: assumes x 6= 0 shows (Q p ∈ prime-factors x. p ˆ multiplicity p x) = normalize x proof − have normalize x = prod-mset (prime-factorization x) by (simp add: prod-mset-prime-factorization assms) also have ... = (Q p ∈ prime-factors x. p ˆ count (prime-factorization x) p) by (subst prod-mset-multiplicity) simp-all also have ... = (Q p ∈ prime-factors x. p ˆ multiplicity p x) by (intro prod.cong) (simp-all add: assms count-prime-factorization-prime in-prime-factors-imp-prime) finally show ?thesis .. qed lemma prime-factorization-unique 00: assumes S-eq: S = {p. 0 < f p} and finite S and S: ∀ p∈S. prime p normalize n = (Q p∈S. p ˆ f p) shows S = prime-factors n ∧ (∀ p. prime p −→ f p = multiplicity p n) proof define A where A = Abs-multiset f from hfinite S i S(1 ) have (Q p∈S. p ˆ f p) 6= 0 by auto with S(2 ) have nz: n 6= 0 by auto from S-eq hfinite S i have count-A: count A x = f x for x unfolding A-def by (subst multiset.Abs-multiset-inverse)(simp-all add: multiset-def ) from S-eq count-A have set-mset-A: set-mset A = S by (simp only: set-mset-def ) from S(2 ) have normalize n = (Q p∈S. p ˆ f p) . also have ... = prod-mset A by (simp add: prod-mset-multiplicity S-eq set-mset-A 329 count-A) also from nz have normalize n = prod-mset (prime-factorization n) by (simp add: prod-mset-prime-factorization) finally have prime-factorization (prod-mset A) = prime-factorization (prod-mset (prime-factorization n)) by simp also from S(1 ) have prime-factorization (prod-mset A) = A by (intro prime-factorization-prod-mset-primes)(auto simp: set-mset-A) also have prime-factorization (prod-mset (prime-factorization n)) = prime-factorization n by (intro prime-factorization-prod-mset-primes) auto finally show S = prime-factors n by (simp add: set-mset-A [symmetric]) show (∀ p. prime p −→ f p = multiplicity p n) proof safe fix p :: 0a assume p: prime p have multiplicity p n = multiplicity p (normalize n) by simp also have normalize n = prod-mset A by (simp add: prod-mset-multiplicity S-eq set-mset-A count-A S) also from p set-mset-A S(1 ) have multiplicity p ... = sum-mset (image-mset (multiplicity p) A) by (intro prime-elem-multiplicity-prod-mset-distrib) auto also from S(1 ) p have image-mset (multiplicity p) A = image-mset (λq. if p = q then 1 else 0 ) A by (intro image-mset-cong)(auto simp: set-mset-A multiplicity-self prime-multiplicity-other) also have sum-mset ... = f p by (simp add: sum-mset-delta 0 count-A) finally show f p = multiplicity p n .. qed qed lemma prime-factors-product: x 6= 0 =⇒ y 6= 0 =⇒ prime-factors (x ∗ y) = prime-factors x ∪ prime-factors y by (simp add: prime-factorization-mult) lemma dvd-prime-factors [intro]: y 6= 0 =⇒ x dvd y =⇒ prime-factors x ⊆ prime-factors y by (intro set-mset-mono, subst prime-factorization-subset-iff-dvd) auto lemma multiplicity-le-imp-dvd: assumes x 6= 0 Vp. prime p =⇒ multiplicity p x ≤ multiplicity p y shows x dvd y proof (cases y = 0 ) case False from assms this have prime-factorization x ⊆# prime-factorization y by (intro mset-subset-eqI )(auto simp: count-prime-factorization) with assms False show ?thesis by (subst (asm) prime-factorization-subset-iff-dvd) qed auto 330 lemma dvd-multiplicity-eq: x 6= 0 =⇒ y 6= 0 =⇒ x dvd y ←→ (∀ p. multiplicity p x ≤ multiplicity p y) by (auto intro: dvd-imp-multiplicity-le multiplicity-le-imp-dvd) lemma multiplicity-eq-imp-eq: assumes x 6= 0 y 6= 0 assumes Vp. prime p =⇒ multiplicity p x = multiplicity p y shows normalize x = normalize y using assms by (intro associatedI multiplicity-le-imp-dvd) simp-all lemma prime-factorization-unique 0: assumes ∀ p ∈# M . prime p ∀ p ∈# N . prime p (Q i ∈# M . i) = (Q i ∈# N . i) shows M = N proof − have prime-factorization (Q i ∈# M . i) = prime-factorization (Q i ∈# N . i) by (simp only: assms) also from assms have prime-factorization (Q i ∈# M . i) = M by (subst prime-factorization-prod-mset-primes) simp-all also from assms have prime-factorization (Q i ∈# N . i) = N by (subst prime-factorization-prod-mset-primes) simp-all finally show ?thesis . qed lemma multiplicity-cong: (Vr. p ˆ r dvd a ←→ p ˆ r dvd b) =⇒ multiplicity p a = multiplicity p b by (simp add: multiplicity-def ) lemma not-dvd-imp-multiplicity-0 : assumes ¬p dvd x shows multiplicity p x = 0 proof − from assms have multiplicity p x < 1 by (intro multiplicity-lessI ) auto thus ?thesis by simp qed 46.5 GCD and LCM computation with unique factorizations definition gcd-factorial a b = (if a = 0 then normalize b else if b = 0 then normalize a else prod-mset (prime-factorization a ∩# prime-factorization b)) definition lcm-factorial a b = (if a = 0 ∨ b = 0 then 0 else prod-mset (prime-factorization a ∪# prime-factorization b)) definition Gcd-factorial A = (if A ⊆ {0 } then 0 else prod-mset (Inf (prime-factorization ‘ (A − {0 })))) 331 definition Lcm-factorial A = (if A = {} then 1 else if 0 ∈/ A ∧ subset-mset.bdd-above (prime-factorization ‘ (A − {0 })) then prod-mset (Sup (prime-factorization ‘ A)) else 0 ) lemma prime-factorization-gcd-factorial: assumes [simp]: a 6= 0 b 6= 0 shows prime-factorization (gcd-factorial a b) = prime-factorization a ∩# prime-factorization b proof − have prime-factorization (gcd-factorial a b) = prime-factorization (prod-mset (prime-factorization a ∩# prime-factorization b)) by (simp add: gcd-factorial-def ) also have ... = prime-factorization a ∩# prime-factorization b by (subst prime-factorization-prod-mset-primes) auto finally show ?thesis . qed lemma prime-factorization-lcm-factorial: assumes [simp]: a 6= 0 b 6= 0 shows prime-factorization (lcm-factorial a b) = prime-factorization a ∪# prime-factorization b proof − have prime-factorization (lcm-factorial a b) = prime-factorization (prod-mset (prime-factorization a ∪# prime-factorization b)) by (simp add: lcm-factorial-def ) also have ... = prime-factorization a ∪# prime-factorization b by (subst prime-factorization-prod-mset-primes) auto finally show ?thesis . qed lemma prime-factorization-Gcd-factorial: assumes ¬A ⊆ {0 } shows prime-factorization (Gcd-factorial A) = Inf (prime-factorization ‘ (A − {0 })) proof − from assms obtain x where x: x ∈ A − {0 } by auto hence Inf (prime-factorization ‘ (A − {0 })) ⊆# prime-factorization x by (intro subset-mset.cInf-lower) simp-all hence ∀ y. y ∈# Inf (prime-factorization ‘ (A − {0 })) −→ y ∈ prime-factors x by (auto dest: mset-subset-eqD) with in-prime-factors-imp-prime[of - x] have ∀ p. p ∈# Inf (prime-factorization ‘ (A − {0 })) −→ prime p by blast with assms show ?thesis by (simp add: Gcd-factorial-def prime-factorization-prod-mset-primes) 332 qed lemma prime-factorization-Lcm-factorial: assumes 0 ∈/ A subset-mset.bdd-above (prime-factorization ‘ A) shows prime-factorization (Lcm-factorial A) = Sup (prime-factorization ‘ A) proof (cases A = {}) case True hence prime-factorization ‘ A = {} by auto also have Sup ... = {#} by (simp add: Sup-multiset-empty) finally show ?thesis by (simp add: Lcm-factorial-def ) next case False have ∀ y. y ∈# Sup (prime-factorization ‘ A) −→ prime y by (auto simp: in-Sup-multiset-iff assms) with assms False show ?thesis by (simp add: Lcm-factorial-def prime-factorization-prod-mset-primes) qed lemma gcd-factorial-commute: gcd-factorial a b = gcd-factorial b a by (simp add: gcd-factorial-def multiset-inter-commute) lemma gcd-factorial-dvd1 : gcd-factorial a b dvd a proof (cases a = 0 ∨ b = 0 ) case False hence gcd-factorial a b 6= 0 by (auto simp: gcd-factorial-def ) with False show ?thesis by (subst prime-factorization-subset-iff-dvd [symmetric]) (auto simp: prime-factorization-gcd-factorial) qed (auto simp: gcd-factorial-def ) lemma gcd-factorial-dvd2 : gcd-factorial a b dvd b by (subst gcd-factorial-commute)(rule gcd-factorial-dvd1 ) lemma normalize-gcd-factorial: normalize (gcd-factorial a b) = gcd-factorial a b proof − have normalize (prod-mset (prime-factorization a ∩# prime-factorization b)) = prod-mset (prime-factorization a ∩# prime-factorization b) by (intro normalize-prod-mset-primes) auto thus ?thesis by (simp add: gcd-factorial-def ) qed lemma gcd-factorial-greatest: c dvd gcd-factorial a b if c dvd a c dvd b for a b c proof (cases a = 0 ∨ b = 0 ) case False with that have [simp]: c 6= 0 by auto let ?p = prime-factorization from that False have ?p c ⊆# ?p a ?p c ⊆# ?p b by (simp-all add: prime-factorization-subset-iff-dvd) hence prime-factorization c ⊆# 333 prime-factorization (prod-mset (prime-factorization a ∩# prime-factorization b)) using False by (subst prime-factorization-prod-mset-primes) auto with False show ?thesis by (auto simp: gcd-factorial-def prime-factorization-subset-iff-dvd [symmetric]) qed (auto simp: gcd-factorial-def that) lemma lcm-factorial-gcd-factorial: lcm-factorial a b = normalize (a ∗ b) div gcd-factorial a b for a b proof (cases a = 0 ∨ b = 0 ) case False let ?p = prime-factorization from False have prod-mset (?p (a ∗ b)) div gcd-factorial a b = prod-mset (?p a + ?p b − ?p a ∩# ?p b) by (subst prod-mset-diff )(auto simp: lcm-factorial-def gcd-factorial-def prime-factorization-mult subset-mset.le-infI1 ) also from False have prod-mset (?p (a ∗ b)) = normalize (a ∗ b) by (intro prod-mset-prime-factorization) simp-all also from False have prod-mset (?p a + ?p b − ?p a ∩# ?p b) = lcm-factorial a b by (simp add: union-diff-inter-eq-sup lcm-factorial-def ) finally show ?thesis .. qed (auto simp: lcm-factorial-def ) lemma normalize-Gcd-factorial: normalize (Gcd-factorial A) = Gcd-factorial A proof (cases A ⊆ {0 }) case False then obtain x where x ∈ A x 6= 0 by blast hence Inf (prime-factorization ‘ (A − {0 })) ⊆# prime-factorization x by (intro subset-mset.cInf-lower) auto hence prime p if p ∈# Inf (prime-factorization ‘ (A − {0 })) for p using that by (auto dest: mset-subset-eqD) with False show ?thesis by (auto simp add: Gcd-factorial-def normalize-prod-mset-primes) qed (simp-all add: Gcd-factorial-def ) lemma Gcd-factorial-eq-0-iff : Gcd-factorial A = 0 ←→ A ⊆ {0 } by (auto simp: Gcd-factorial-def in-Inf-multiset-iff split: if-splits) lemma Gcd-factorial-dvd: assumes x ∈ A shows Gcd-factorial A dvd x proof (cases x = 0 ) case False with assms have prime-factorization (Gcd-factorial A) = Inf (prime-factorization ‘ (A − {0 })) by (intro prime-factorization-Gcd-factorial) auto 334 also from False assms have ... ⊆# prime-factorization x by (intro subset-mset.cInf-lower) auto finally show ?thesis by (subst (asm) prime-factorization-subset-iff-dvd) (insert assms False, auto simp: Gcd-factorial-eq-0-iff ) qed simp-all lemma Gcd-factorial-greatest: assumes Vy. y ∈ A =⇒ x dvd y shows x dvd Gcd-factorial A proof (cases A ⊆ {0 }) case False from False obtain y where y ∈ A y 6= 0 by auto with assms[of y] have nz: x 6= 0 by auto from nz assms have prime-factorization x ⊆# prime-factorization y if y ∈ A − {0 } for y using that by (subst prime-factorization-subset-iff-dvd) auto with False have prime-factorization x ⊆# Inf (prime-factorization ‘ (A − {0 })) by (intro subset-mset.cInf-greatest) auto also from False have ... = prime-factorization (Gcd-factorial A) by (rule prime-factorization-Gcd-factorial [symmetric]) finally show ?thesis by (subst (asm) prime-factorization-subset-iff-dvd) (insert nz False, auto simp: Gcd-factorial-eq-0-iff ) qed (simp-all add: Gcd-factorial-def ) lemma normalize-Lcm-factorial: normalize (Lcm-factorial A) = Lcm-factorial A proof (cases subset-mset.bdd-above (prime-factorization ‘ A)) case True hence normalize (prod-mset (Sup (prime-factorization ‘ A))) = prod-mset (Sup (prime-factorization ‘ A)) by (intro normalize-prod-mset-primes) (auto simp: in-Sup-multiset-iff ) with True show ?thesis by (simp add: Lcm-factorial-def ) qed (auto simp: Lcm-factorial-def ) lemma Lcm-factorial-eq-0-iff : Lcm-factorial A = 0 ←→ 0 ∈ A ∨ ¬subset-mset.bdd-above (prime-factorization ‘A) by (auto simp: Lcm-factorial-def in-Sup-multiset-iff ) lemma dvd-Lcm-factorial: assumes x ∈ A shows x dvd Lcm-factorial A proof (cases 0 ∈/ A ∧ subset-mset.bdd-above (prime-factorization ‘ A)) case True with assms have [simp]: 0 ∈/ A x 6= 0 A 6= {} by auto 335 from assms True have prime-factorization x ⊆# Sup (prime-factorization ‘ A) by (intro subset-mset.cSup-upper) auto also have ... = prime-factorization (Lcm-factorial A) by (rule prime-factorization-Lcm-factorial [symmetric]) (insert True, simp-all) finally show ?thesis by (subst (asm) prime-factorization-subset-iff-dvd) (insert True, auto simp: Lcm-factorial-eq-0-iff ) qed (insert assms, auto simp: Lcm-factorial-def ) lemma Lcm-factorial-least: assumes Vy. y ∈ A =⇒ y dvd x shows Lcm-factorial A dvd x proof − consider A = {} | 0 ∈ A | x = 0 | A 6= {} 0 ∈/ A x 6= 0 by blast thus ?thesis proof cases assume ∗: A 6= {} 0 ∈/ A x 6= 0 hence nz: x 6= 0 if x ∈ A for x using that by auto from ∗ have bdd: subset-mset.bdd-above (prime-factorization ‘ A) by (intro subset-mset.bdd-aboveI [of - prime-factorization x]) (auto simp: prime-factorization-subset-iff-dvd nz dest: assms) have prime-factorization (Lcm-factorial A) = Sup (prime-factorization ‘ A) by (rule prime-factorization-Lcm-factorial) fact+ also from ∗ have ... ⊆# prime-factorization x by (intro subset-mset.cSup-least) (auto simp: prime-factorization-subset-iff-dvd nz dest: assms) finally show ?thesis by (subst (asm) prime-factorization-subset-iff-dvd) (insert ∗ bdd, auto simp: Lcm-factorial-eq-0-iff ) qed (auto simp: Lcm-factorial-def dest: assms) qed lemmas gcd-lcm-factorial = gcd-factorial-dvd1 gcd-factorial-dvd2 gcd-factorial-greatest normalize-gcd-factorial lcm-factorial-gcd-factorial normalize-Gcd-factorial Gcd-factorial-dvd Gcd-factorial-greatest normalize-Lcm-factorial dvd-Lcm-factorial Lcm-factorial-least end class factorial-semiring-gcd = factorial-semiring + gcd + Gcd + assumes gcd-eq-gcd-factorial: gcd a b = gcd-factorial a b and lcm-eq-lcm-factorial: lcm a b = lcm-factorial a b and Gcd-eq-Gcd-factorial: Gcd A = Gcd-factorial A and Lcm-eq-Lcm-factorial: Lcm A = Lcm-factorial A begin lemma prime-factorization-gcd: assumes [simp]: a 6= 0 b 6= 0 336 shows prime-factorization (gcd a b) = prime-factorization a ∩# prime-factorization b by (simp add: gcd-eq-gcd-factorial prime-factorization-gcd-factorial) lemma prime-factorization-lcm: assumes [simp]: a 6= 0 b 6= 0 shows prime-factorization (lcm a b) = prime-factorization a ∪# prime-factorization b by (simp add: lcm-eq-lcm-factorial prime-factorization-lcm-factorial) lemma prime-factorization-Gcd: assumes Gcd A 6= 0 shows prime-factorization (Gcd A) = Inf (prime-factorization ‘ (A − {0 })) using assms by (simp add: prime-factorization-Gcd-factorial Gcd-eq-Gcd-factorial Gcd-factorial-eq-0-iff ) lemma prime-factorization-Lcm: assumes Lcm A 6= 0 shows prime-factorization (Lcm A) = Sup (prime-factorization ‘ A) using assms by (simp add: prime-factorization-Lcm-factorial Lcm-eq-Lcm-factorial Lcm-factorial-eq-0-iff ) subclass semiring-gcd by (standard, unfold gcd-eq-gcd-factorial lcm-eq-lcm-factorial) (rule gcd-lcm-factorial; assumption)+ subclass semiring-Gcd by (standard, unfold Gcd-eq-Gcd-factorial Lcm-eq-Lcm-factorial) (rule gcd-lcm-factorial; assumption)+ lemma assumes x 6= 0 y 6= 0 shows gcd-eq-factorial 0: gcd x y = (Q p ∈ prime-factors x ∩ prime-factors y. p ˆ min (multiplicity p x)(multiplicity p y)) (is - = ?rhs1 ) and lcm-eq-factorial 0: lcm x y = (Q p ∈ prime-factors x ∪ prime-factors y. p ˆ max (multiplicity p x)(multiplicity p y)) (is - = ?rhs2 ) proof − have gcd x y = gcd-factorial x y by (rule gcd-eq-gcd-factorial) also have ... = ?rhs1 by (auto simp: gcd-factorial-def assms prod-mset-multiplicity count-prime-factorization-prime dest: in-prime-factors-imp-prime intro!: prod.cong) finally show gcd x y = ?rhs1 . have lcm x y = lcm-factorial x y by (rule lcm-eq-lcm-factorial) also have ... = ?rhs2 by (auto simp: lcm-factorial-def assms prod-mset-multiplicity count-prime-factorization-prime dest: in-prime-factors-imp-prime intro!: 337 prod.cong) finally show lcm x y = ?rhs2 . qed lemma assumes x 6= 0 y 6= 0 prime p shows multiplicity-gcd: multiplicity p (gcd x y) = min (multiplicity p x) (multiplicity p y) and multiplicity-lcm: multiplicity p (lcm x y) = max (multiplicity p x) (multiplicity p y) proof − have gcd x y = gcd-factorial x y by (rule gcd-eq-gcd-factorial) also from assms have multiplicity p ... = min (multiplicity p x)(multiplicity p y) by (simp add: count-prime-factorization-prime [symmetric] prime-factorization-gcd-factorial) finally show multiplicity p (gcd x y) = min (multiplicity p x)(multiplicity p y) . have lcm x y = lcm-factorial x y by (rule lcm-eq-lcm-factorial) also from assms have multiplicity p ... = max (multiplicity p x)(multiplicity p y) by (simp add: count-prime-factorization-prime [symmetric] prime-factorization-lcm-factorial) finally show multiplicity p (lcm x y) = max (multiplicity p x)(multiplicity p y) . qed lemma gcd-lcm-distrib: gcd x (lcm y z) = lcm (gcd x y)(gcd x z) proof (cases x = 0 ∨ y = 0 ∨ z = 0 ) case True thus ?thesis by (auto simp: lcm-proj1-if-dvd lcm-proj2-if-dvd) next case False hence normalize (gcd x (lcm y z)) = normalize (lcm (gcd x y)(gcd x z)) by (intro associatedI prime-factorization-subset-imp-dvd) (auto simp: lcm-eq-0-iff prime-factorization-gcd prime-factorization-lcm subset-mset.inf-sup-distrib1 ) thus ?thesis by simp qed lemma lcm-gcd-distrib: lcm x (gcd y z) = gcd (lcm x y)(lcm x z) proof (cases x = 0 ∨ y = 0 ∨ z = 0 ) case True thus ?thesis by (auto simp: lcm-proj1-if-dvd lcm-proj2-if-dvd) next case False hence normalize (lcm x (gcd y z)) = normalize (gcd (lcm x y)(lcm x z)) 338 by (intro associatedI prime-factorization-subset-imp-dvd) (auto simp: lcm-eq-0-iff prime-factorization-gcd prime-factorization-lcm subset-mset.sup-inf-distrib1 ) thus ?thesis by simp qed end class factorial-ring-gcd = factorial-semiring-gcd + idom begin subclass ring-gcd .. subclass idom-divide .. end end 47 Abstract euclidean algorithm theory Euclidean-Algorithm imports ∼∼/src/HOL/GCD Factorial-Ring begin A Euclidean semiring is a semiring upon which the Euclidean algorithm can be implemented. It must provide: • division with remainder • a size function such that size (a mod b) < size b for any b 6= (0 :: 0a) The existence of these functions makes it possible to derive gcd and lcm functions for any Euclidean semiring. class euclidean-semiring = semiring-modulo + normalization-semidom + fixes euclidean-size :: 0a ⇒ nat assumes size-0 [simp]: euclidean-size 0 = 0 assumes mod-size-less: b 6= 0 =⇒ euclidean-size (a mod b) < euclidean-size b assumes size-mult-mono: b 6= 0 =⇒ euclidean-size a ≤ euclidean-size (a ∗ b) begin lemma mod-0 [simp]: 0 mod a = 0 using div-mult-mod-eq [of 0 a] by simp lemma dvd-mod-iff : assumes k dvd n 339 shows (k dvd m mod n) = (k dvd m) proof − from assms have (k dvd m mod n) ←→ (k dvd ((m div n) ∗ n + m mod n)) by (simp add: dvd-add-right-iff ) also have (m div n) ∗ n + m mod n = m using div-mult-mod-eq [of m n] by simp finally show ?thesis . qed lemma mod-0-imp-dvd: assumes a mod b = 0 shows b dvd a proof − have b dvd ((a div b) ∗ b) by simp also have (a div b) ∗ b = a using div-mult-mod-eq [of a b] by (simp add: assms) finally show ?thesis . qed lemma euclidean-size-normalize [simp]: euclidean-size (normalize a) = euclidean-size a proof (cases a = 0 ) case True then show ?thesis by simp next case [simp]: False have euclidean-size (normalize a) ≤ euclidean-size (normalize a ∗ unit-factor a) by (rule size-mult-mono) simp moreover have euclidean-size a ≤ euclidean-size (a ∗ (1 div unit-factor a)) by (rule size-mult-mono) simp ultimately show ?thesis by simp qed lemma euclidean-division: fixes a :: 0a and b :: 0a assumes b 6= 0 obtains s and t where a = s ∗ b + t and euclidean-size t < euclidean-size b proof − from div-mult-mod-eq [of a b] have a = a div b ∗ b + a mod b by simp with that and assms show ?thesis by (auto simp add: mod-size-less) qed lemma dvd-euclidean-size-eq-imp-dvd: assumes a 6= 0 and b-dvd-a: b dvd a and size-eq: euclidean-size a = euclidean-size b 340 shows a dvd b proof (rule ccontr) assume ¬ a dvd b hence b mod a 6= 0 using mod-0-imp-dvd[of b a] by blast then have b mod a 6= 0 by (simp add: mod-eq-0-iff-dvd) from b-dvd-a have b-dvd-mod: b dvd b mod a by (simp add: dvd-mod-iff ) from b-dvd-mod obtain c where b mod a = b ∗ c unfolding dvd-def by blast with hb mod a 6= 0 i have c 6= 0 by auto with hb mod a = b ∗ ci have euclidean-size (b mod a) ≥ euclidean-size b using size-mult-mono by force moreover from h¬ a dvd bi and ha 6= 0 i have euclidean-size (b mod a) < euclidean-size a using mod-size-less by blast ultimately show False using size-eq by simp qed lemma size-mult-mono 0: b 6= 0 =⇒ euclidean-size a ≤ euclidean-size (b ∗ a) by (subst mult.commute)(rule size-mult-mono) lemma euclidean-size-times-unit: assumes is-unit a shows euclidean-size (a ∗ b) = euclidean-size b proof (rule antisym) from assms have [simp]: a 6= 0 by auto thus euclidean-size (a ∗ b) ≥ euclidean-size b by (rule size-mult-mono 0) from assms have is-unit (1 div a) by simp hence 1 div a 6= 0 by (intro notI ) simp-all hence euclidean-size (a ∗ b) ≤ euclidean-size ((1 div a) ∗ (a ∗ b)) by (rule size-mult-mono 0) also from assms have (1 div a) ∗ (a ∗ b) = b by (simp add: algebra-simps unit-div-mult-swap) finally show euclidean-size (a ∗ b) ≤ euclidean-size b . qed lemma euclidean-size-unit: is-unit a =⇒ euclidean-size a = euclidean-size 1 using euclidean-size-times-unit[of a 1 ] by simp lemma unit-iff-euclidean-size: is-unit a ←→ euclidean-size a = euclidean-size 1 ∧ a 6= 0 proof safe assume A: a 6= 0 and B: euclidean-size a = euclidean-size 1 show is-unit a by (rule dvd-euclidean-size-eq-imp-dvd[OF A - B]) simp-all qed (auto intro: euclidean-size-unit) lemma euclidean-size-times-nonunit: assumes a 6= 0 b 6= 0 ¬is-unit a shows euclidean-size b < euclidean-size (a ∗ b) proof (rule ccontr) assume ¬euclidean-size b < euclidean-size (a ∗ b) 341 with size-mult-mono 0[OF assms(1 ), of b] have eq: euclidean-size (a ∗ b) = euclidean-size b by simp have a ∗ b dvd b by (rule dvd-euclidean-size-eq-imp-dvd[OF - - eq]) (insert assms, simp-all) hence a ∗ b dvd 1 ∗ b by simp with hb 6= 0 i have is-unit a by (subst (asm) dvd-times-right-cancel-iff ) with assms(3 ) show False by contradiction qed lemma dvd-imp-size-le: assumes a dvd b b 6= 0 shows euclidean-size a ≤ euclidean-size b using assms by (auto elim!: dvdE simp: size-mult-mono) lemma dvd-proper-imp-size-less: assumes a dvd b ¬b dvd a b 6= 0 shows euclidean-size a < euclidean-size b proof − from assms(1 ) obtain c where b = a ∗ c by (erule dvdE) hence z: b = c ∗ a by (simp add: mult.commute) from z assms have ¬is-unit c by (auto simp: mult.commute mult-unit-dvd-iff ) with z assms show ?thesis by (auto intro!: euclidean-size-times-nonunit simp:) qed function gcd-eucl :: 0a ⇒ 0a ⇒ 0a where gcd-eucl a b = (if b = 0 then normalize a else gcd-eucl b (a mod b)) by pat-completeness simp termination by (relation measure (euclidean-size ◦ snd)) (simp-all add: mod-size-less) declare gcd-eucl.simps [simp del] lemma gcd-eucl-induct [case-names zero mod]: assumes H1 : Vb. P b 0 and H2 : Va b. b 6= 0 =⇒ P b (a mod b) =⇒ P a b shows P a b proof (induct a b rule: gcd-eucl.induct) case (1 a b) show ?case proof (cases b = 0 ) case True then show P a b by simp (rule H1 ) next case False then have P b (a mod b) by (rule 1 .hyps) with hb 6= 0 i show P a b by (blast intro: H2 ) 342 qed qed definition lcm-eucl :: 0a ⇒ 0a ⇒ 0a where lcm-eucl a b = normalize (a ∗ b) div gcd-eucl a b definition Lcm-eucl :: 0a set ⇒ 0a — Somewhat complicated definition of Lcm that has the advantage of working for infinite sets as well where Lcm-eucl A = (if ∃ l. l 6= 0 ∧ (∀ a∈A. a dvd l) then let l = SOME l. l 6= 0 ∧ (∀ a∈A. a dvd l) ∧ euclidean-size l = (LEAST n. ∃ l. l 6= 0 ∧ (∀ a∈A. a dvd l) ∧ euclidean-size l = n) in normalize l else 0 ) definition Gcd-eucl :: 0a set ⇒ 0a where Gcd-eucl A = Lcm-eucl {d. ∀ a∈A. d dvd a} declare Lcm-eucl-def Gcd-eucl-def [code del] lemma gcd-eucl-0 : gcd-eucl a 0 = normalize a by (simp add: gcd-eucl.simps [of a 0 ]) lemma gcd-eucl-0-left: gcd-eucl 0 a = normalize a by (simp-all add: gcd-eucl-0 gcd-eucl.simps [of 0 a]) lemma gcd-eucl-non-0 : b 6= 0 =⇒ gcd-eucl a b = gcd-eucl b (a mod b) by (simp add: gcd-eucl.simps [of a b] gcd-eucl.simps [of b 0 ]) lemma gcd-eucl-dvd1 [iff ]: gcd-eucl a b dvd a and gcd-eucl-dvd2 [iff ]: gcd-eucl a b dvd b by (induct a b rule: gcd-eucl-induct) (simp-all add: gcd-eucl-0 gcd-eucl-non-0 dvd-mod-iff ) lemma normalize-gcd-eucl [simp]: normalize (gcd-eucl a b) = gcd-eucl a b by (induct a b rule: gcd-eucl-induct)(simp-all add: gcd-eucl-0 gcd-eucl-non-0 ) lemma gcd-eucl-greatest: fixes k a b :: 0a shows k dvd a =⇒ k dvd b =⇒ k dvd gcd-eucl a b proof (induct a b rule: gcd-eucl-induct) case (zero a) from zero(1 ) show ?case by (rule dvd-trans)(simp add: gcd-eucl-0 ) next 343 case (mod a b) then show ?case by (simp add: gcd-eucl-non-0 dvd-mod-iff ) qed lemma gcd-euclI : fixes gcd :: 0a ⇒ 0a ⇒ 0a assumes d dvd a d dvd b normalize d = d Vk. k dvd a =⇒ k dvd b =⇒ k dvd d shows gcd-eucl a b = d by (rule associated-eqI )(simp-all add: gcd-eucl-greatest assms) lemma eq-gcd-euclI : fixes gcd :: 0a ⇒ 0a ⇒ 0a assumes Va b. gcd a b dvd a Va b. gcd a b dvd b Va b. normalize (gcd a b) = gcd a b Va b k. k dvd a =⇒ k dvd b =⇒ k dvd gcd a b shows gcd = gcd-eucl by (intro ext, rule associated-eqI )(simp-all add: gcd-eucl-greatest assms) lemma gcd-eucl-zero [simp]: gcd-eucl a b = 0 ←→ a = 0 ∧ b = 0 by (metis dvd-0-left dvd-refl gcd-eucl-dvd1 gcd-eucl-dvd2 gcd-eucl-greatest)+ lemma dvd-Lcm-eucl [simp]: a ∈ A =⇒ a dvd Lcm-eucl A and Lcm-eucl-least:(Va. a ∈ A =⇒ a dvd b) =⇒ Lcm-eucl A dvd b and unit-factor-Lcm-eucl [simp]: unit-factor (Lcm-eucl A) = (if Lcm-eucl A = 0 then 0 else 1 ) proof − have (∀ a∈A. a dvd Lcm-eucl A) ∧ (∀ l 0. (∀ a∈A. a dvd l 0) −→ Lcm-eucl A dvd l 0) ∧ unit-factor (Lcm-eucl A) = (if Lcm-eucl A = 0 then 0 else 1 )(is ?thesis) proof (cases ∃ l. l 6= 0 ∧ (∀ a∈A. a dvd l)) case False hence Lcm-eucl A = 0 by (auto simp: Lcm-eucl-def ) with False show ?thesis by auto next case True then obtain l 0 where l 0-props: l 0 6= 0 ∧ (∀ a∈A. a dvd l 0) by blast define n where n = (LEAST n. ∃ l. l 6= 0 ∧ (∀ a∈A. a dvd l) ∧ euclidean-size l = n) define l where l = (SOME l. l 6= 0 ∧ (∀ a∈A. a dvd l) ∧ euclidean-size l = n) have ∃ l. l 6= 0 ∧ (∀ a∈A. a dvd l) ∧ euclidean-size l = n apply (subst n-def ) apply (rule LeastI [of - euclidean-size l 0]) apply (rule exI [of - l 0]) apply (simp add: l 0-props) 344 done from someI-ex[OF this] have l 6= 0 and ∀ a∈A. a dvd l and euclidean-size l = n unfolding l-def by simp-all { fix l 0 assume ∀ a∈A. a dvd l 0 0 with h∀ a∈A. a dvd l i have ∀ a∈A. a dvd gcd-eucl l l by (auto intro: gcd-eucl-greatest) 0 moreover from hl 6= 0 i have gcd-eucl l l 6= 0 by simp ultimately have ∃ b. b 6= 0 ∧ (∀ a∈A. a dvd b) ∧ euclidean-size b = euclidean-size (gcd-eucl l l 0) by (intro exI [of - gcd-eucl l l 0], auto) hence euclidean-size (gcd-eucl l l 0) ≥ n by (subst n-def )(rule Least-le) moreover have euclidean-size (gcd-eucl l l 0) ≤ n proof − have gcd-eucl l l 0 dvd l by simp then obtain a where l = gcd-eucl l l 0 ∗ a unfolding dvd-def by blast with hl 6= 0 i have a 6= 0 by auto hence euclidean-size (gcd-eucl l l 0) ≤ euclidean-size (gcd-eucl l l 0 ∗ a) by (rule size-mult-mono) 0 0 also have gcd-eucl l l ∗ a = l using hl = gcd-eucl l l ∗ a i .. also note heuclidean-size l = n i finally show euclidean-size (gcd-eucl l l 0) ≤ n . qed ultimately have ∗: euclidean-size l = euclidean-size (gcd-eucl l l 0) by (intro le-antisym, simp-all add: heuclidean-size l = n i) 0 from hl 6= 0 i have l dvd gcd-eucl l l by (rule dvd-euclidean-size-eq-imp-dvd)(auto simp add: ∗) hence l dvd l 0 by (rule dvd-trans[OF - gcd-eucl-dvd2 ]) } with h(∀ a∈A. a dvd l)i and unit-factor-is-unit[OF hl 6= 0 i] and hl 6= 0 i have (∀ a∈A. a dvd normalize l) ∧ (∀ l 0. (∀ a∈A. a dvd l 0) −→ normalize l dvd l 0) ∧ unit-factor (normalize l) = (if normalize l = 0 then 0 else 1 ) by (auto simp: unit-simps) also from True have normalize l = Lcm-eucl A by (simp add: Lcm-eucl-def Let-def n-def l-def ) finally show ?thesis . qed note A = this {fix a assume a ∈ A then show a dvd Lcm-eucl A using A by blast} {fix b assume Va. a ∈ A =⇒ a dvd b then show Lcm-eucl A dvd b using A by blast} from A show unit-factor (Lcm-eucl A) = (if Lcm-eucl A = 0 then 0 else 1 ) by blast qed 345 lemma normalize-Lcm-eucl [simp]: normalize (Lcm-eucl A) = Lcm-eucl A proof (cases Lcm-eucl A = 0 ) case True then show ?thesis by simp next case False have unit-factor (Lcm-eucl A) ∗ normalize (Lcm-eucl A) = Lcm-eucl A by (fact unit-factor-mult-normalize) with False show ?thesis by simp qed lemma eq-Lcm-euclI : fixes lcm :: 0a set ⇒ 0a assumes VA a. a ∈ A =⇒ a dvd lcm A and VA c. (Va. a ∈ A =⇒ a dvd c) =⇒ lcm A dvd c VA. normalize (lcm A) = lcm A shows lcm = Lcm-eucl by (intro ext, rule associated-eqI )(auto simp: assms intro: Lcm-eucl-least) lemma Gcd-eucl-dvd: a ∈ A =⇒ Gcd-eucl A dvd a unfolding Gcd-eucl-def by (auto intro: Lcm-eucl-least) lemma Gcd-eucl-greatest:(Vx. x ∈ A =⇒ d dvd x) =⇒ d dvd Gcd-eucl A unfolding Gcd-eucl-def by auto lemma normalize-Gcd-eucl [simp]: normalize (Gcd-eucl A) = Gcd-eucl A by (simp add: Gcd-eucl-def ) lemma Lcm-euclI : assumes Vx. x ∈ A =⇒ x dvd d Vd 0. (Vx. x ∈ A =⇒ x dvd d 0) =⇒ d dvd d 0 normalize d = d shows Lcm-eucl A = d proof − have normalize (Lcm-eucl A) = normalize d by (intro associatedI )(auto intro: dvd-Lcm-eucl Lcm-eucl-least assms) thus ?thesis by (simp add: assms) qed lemma Gcd-euclI : assumes Vx. x ∈ A =⇒ d dvd x Vd 0. (Vx. x ∈ A =⇒ d 0 dvd x) =⇒ d 0 dvd d normalize d = d shows Gcd-eucl A = d proof − have normalize (Gcd-eucl A) = normalize d by (intro associatedI )(auto intro: Gcd-eucl-dvd Gcd-eucl-greatest assms) thus ?thesis by (simp add: assms) qed lemmas lcm-gcd-eucl-facts = 346 gcd-eucl-dvd1 gcd-eucl-dvd2 gcd-eucl-greatest normalize-gcd-eucl lcm-eucl-def Gcd-eucl-def Gcd-eucl-dvd Gcd-eucl-greatest normalize-Gcd-eucl dvd-Lcm-eucl Lcm-eucl-least normalize-Lcm-eucl lemma normalized-factors-product: {p. p dvd a ∗ b ∧ normalize p = p} = (λ(x,y). x ∗ y) ‘ ({p. p dvd a ∧ normalize p = p} × {p. p dvd b ∧ normalize p = p}) proof safe fix p assume p: p dvd a ∗ b normalize p = p interpret semiring-gcd 1 0 op ∗ gcd-eucl lcm-eucl op div op + op − normalize unit-factor by standard (rule lcm-gcd-eucl-facts; assumption)+ from dvd-productE[OF p(1 )] guess x y . note xy = this define x 0 y 0 where x 0 = normalize x and y 0 = normalize y have p = x 0 ∗ y 0 by (subst p(2 )[symmetric]) (simp add: xy x 0-def y 0-def normalize-mult) moreover from xy have normalize x 0 = x 0 normalize y 0 = y 0 x 0 dvd a y 0 dvd b by (simp-all add: x 0-def y 0-def ) ultimately show p ∈ (λ(x, y). x ∗ y) ‘ ({p. p dvd a ∧ normalize p = p} × {p. p dvd b ∧ normalize p = p}) by blast qed (auto simp: normalize-mult mult-dvd-mono) subclass factorial-semiring proof (standard, rule factorial-semiring-altI-aux) fix x assume x 6= 0 thus finite {p. p dvd x ∧ normalize p = p} proof (induction euclidean-size x arbitrary: x rule: less-induct) case (less x) show ?case proof (cases ∃ y. y dvd x ∧ ¬x dvd y ∧ ¬is-unit y) case False have {p. p dvd x ∧ normalize p = p} ⊆ {1 , normalize x} proof fix p assume p: p ∈ {p. p dvd x ∧ normalize p = p} with False have is-unit p ∨ x dvd p by blast thus p ∈ {1 , normalize x} proof (elim disjE) assume is-unit p hence normalize p = 1 by (simp add: is-unit-normalize) with p show ?thesis by simp next assume x dvd p with p have normalize p = normalize x by (intro associatedI ) simp-all with p show ?thesis by simp qed 347 qed moreover have finite ... by simp ultimately show ?thesis by (rule finite-subset) next case True then obtain y where y: y dvd x ¬x dvd y ¬is-unit y by blast define z where z = x div y let ?fctrs = λx. {p. p dvd x ∧ normalize p = p} from y have x: x = y ∗ z by (simp add: z-def ) with less.prems have y 6= 0 z 6= 0 by auto from x y have ¬is-unit z by (auto simp: mult-unit-dvd-iff ) have ?fctrs x = (λ(p,p 0). p ∗ p 0) ‘ (?fctrs y × ?fctrs z) by (subst x)(rule normalized-factors-product) also have ¬y ∗ z dvd y ∗ 1 ¬y ∗ z dvd 1 ∗ z by (subst dvd-times-left-cancel-iff dvd-times-right-cancel-iff ; fact)+ hence finite ((λ(p,p 0). p ∗ p 0) ‘ (?fctrs y × ?fctrs z)) by (intro finite-imageI finite-cartesian-product less dvd-proper-imp-size-less) (auto simp: x) finally show ?thesis . qed qed next interpret semiring-gcd 1 0 op ∗ gcd-eucl lcm-eucl op div op + op − normalize unit-factor by standard (rule lcm-gcd-eucl-facts; assumption)+ fix p assume p: irreducible p thus prime-elem p by (rule irreducible-imp-prime-elem-gcd) qed lemma gcd-eucl-eq-gcd-factorial: gcd-eucl = gcd-factorial by (intro ext gcd-euclI gcd-lcm-factorial) lemma lcm-eucl-eq-lcm-factorial: lcm-eucl = lcm-factorial by (intro ext)(simp add: lcm-eucl-def lcm-factorial-gcd-factorial gcd-eucl-eq-gcd-factorial) lemma Gcd-eucl-eq-Gcd-factorial: Gcd-eucl = Gcd-factorial by (intro ext Gcd-euclI gcd-lcm-factorial) lemma Lcm-eucl-eq-Lcm-factorial: Lcm-eucl = Lcm-factorial by (intro ext Lcm-euclI gcd-lcm-factorial) lemmas eucl-eq-factorial = gcd-eucl-eq-gcd-factorial lcm-eucl-eq-lcm-factorial Gcd-eucl-eq-Gcd-factorial Lcm-eucl-eq-Lcm-factorial end class euclidean-ring = euclidean-semiring + idom 348 begin function euclid-ext-aux :: 0a ⇒ - where euclid-ext-aux r 0 r s 0 s t 0 t = ( if r = 0 then let c = 1 div unit-factor r 0 in (s 0 ∗ c, t 0 ∗ c, normalize r 0) else let q = r 0 div r in euclid-ext-aux r (r 0 mod r) s (s 0 − q ∗ s) t (t 0 − q ∗ t)) by auto termination by (relation measure (λ(-,b,-,-,-,-). euclidean-size b)) (simp-all add: mod-size-less) declare euclid-ext-aux.simps [simp del] lemma euclid-ext-aux-correct: assumes gcd-eucl r 0 r = gcd-eucl a b assumes s 0 ∗ a + t 0 ∗ b = r 0 assumes s ∗ a + t ∗ b = r shows case euclid-ext-aux r 0 r s 0 s t 0 t of (x,y,c) ⇒ x ∗ a + y ∗ b = c ∧ c = gcd-eucl a b (is ?P (euclid-ext-aux r 0 r s 0 s t 0 t)) using assms proof (induction r 0 r s 0 s t 0 t rule: euclid-ext-aux.induct) case (1 r 0 r s 0 s t 0 t) show ?case proof (cases r = 0 ) case True hence euclid-ext-aux r 0 r s 0 s t 0 t = (s 0 div unit-factor r 0, t 0 div unit-factor r 0, normalize r 0) by (subst euclid-ext-aux.simps)(simp add: Let-def ) also have ?P ... proof safe have s 0 div unit-factor r 0 ∗ a + t 0 div unit-factor r 0 ∗ b = (s 0 ∗ a + t 0 ∗ b) div unit-factor r 0 by (cases r 0 = 0 )(simp-all add: unit-div-commute) also have s 0 ∗ a + t 0 ∗ b = r 0 by fact also have ... div unit-factor r 0 = normalize r 0 by simp finally show s 0 div unit-factor r 0 ∗ a + t 0 div unit-factor r 0 ∗ b = normalize r 0 . next from 1 .prems True show normalize r 0 = gcd-eucl a b by (simp add: gcd-eucl-0 ) qed finally show ?thesis . next case False hence euclid-ext-aux r 0 r s 0 s t 0 t = euclid-ext-aux r (r 0 mod r) s (s 0 − r 0 div r ∗ s) t (t 0 − r 0 div r ∗ t) by (subst euclid-ext-aux.simps)(simp add: Let-def ) also from 1 .prems False have ?P ... 349 proof (intro 1 .IH ) have (s 0 − r 0 div r ∗ s) ∗ a + (t 0 − r 0 div r ∗ t) ∗ b = (s 0 ∗ a + t 0 ∗ b) − r 0 div r ∗ (s ∗ a + t ∗ b) by (simp add: algebra-simps) also have s 0 ∗ a + t 0 ∗ b = r 0 by fact also have s ∗ a + t ∗ b = r by fact also have r 0 − r 0 div r ∗ r = r 0 mod r using div-mult-mod-eq [of r 0 r] by (simp add: algebra-simps) finally show (s 0 − r 0 div r ∗ s) ∗ a + (t 0 − r 0 div r ∗ t) ∗ b = r 0 mod r . qed (auto simp: gcd-eucl-non-0 algebra-simps minus-mod-eq-div-mult [symmetric]) finally show ?thesis . qed qed definition euclid-ext where euclid-ext a b = euclid-ext-aux a b 1 0 0 1 lemma euclid-ext-0 : euclid-ext a 0 = (1 div unit-factor a, 0 , normalize a) by (simp add: euclid-ext-def euclid-ext-aux.simps) lemma euclid-ext-left-0 : euclid-ext 0 a = (0 , 1 div unit-factor a, normalize a) by (simp add: euclid-ext-def euclid-ext-aux.simps) lemma euclid-ext-correct 0: case euclid-ext a b of (x,y,c) ⇒ x ∗ a + y ∗ b = c ∧ c = gcd-eucl a b unfolding euclid-ext-def by (rule euclid-ext-aux-correct) simp-all lemma euclid-ext-gcd-eucl: (case euclid-ext a b of (x,y,c) ⇒ c) = gcd-eucl a b using euclid-ext-correct 0[of a b] by (simp add: case-prod-unfold) definition euclid-ext 0 where euclid-ext 0 a b = (case euclid-ext a b of (x, y, -) ⇒ (x, y)) lemma euclid-ext 0-correct 0: case euclid-ext 0 a b of (x,y) ⇒ x ∗ a + y ∗ b = gcd-eucl a b using euclid-ext-correct 0[of a b] by (simp add: case-prod-unfold euclid-ext 0-def ) lemma euclid-ext 0-0 : euclid-ext 0 a 0 = (1 div unit-factor a, 0 ) by (simp add: euclid-ext 0-def euclid-ext-0 ) lemma euclid-ext 0-left-0 : euclid-ext 0 0 a = (0 , 1 div unit-factor a) by (simp add: euclid-ext 0-def euclid-ext-left-0 ) end class euclidean-semiring-gcd = euclidean-semiring + gcd + Gcd + assumes gcd-gcd-eucl: gcd = gcd-eucl and lcm-lcm-eucl: lcm = lcm-eucl 350 assumes Gcd-Gcd-eucl: Gcd = Gcd-eucl and Lcm-Lcm-eucl: Lcm = Lcm-eucl begin subclass semiring-gcd by standard (simp-all add: gcd-gcd-eucl gcd-eucl-greatest lcm-lcm-eucl lcm-eucl-def ) subclass semiring-Gcd by standard (auto simp: Gcd-Gcd-eucl Lcm-Lcm-eucl Gcd-eucl-def intro: Lcm-eucl-least) subclass factorial-semiring-gcd proof fix a b show gcd a b = gcd-factorial a b by (rule sym, rule gcdI )(rule gcd-lcm-factorial; assumption)+ thus lcm a b = lcm-factorial a b by (simp add: lcm-factorial-gcd-factorial lcm-gcd) next fix A show Gcd A = Gcd-factorial A by (rule sym, rule GcdI )(rule gcd-lcm-factorial; assumption)+ show Lcm A = Lcm-factorial A by (rule sym, rule LcmI )(rule gcd-lcm-factorial; assumption)+ qed lemma gcd-non-0 : b 6= 0 =⇒ gcd a b = gcd b (a mod b) unfolding gcd-gcd-eucl by (fact gcd-eucl-non-0 ) lemmas gcd-0 = gcd-0-right lemmas dvd-gcd-iff = gcd-greatest-iff lemmas gcd-greatest-iff = dvd-gcd-iff lemma gcd-mod1 [simp]: gcd (a mod b) b = gcd a b by (rule gcdI , metis dvd-mod-iff gcd-dvd1 gcd-dvd2 , simp-all add: gcd-greatest dvd-mod-iff ) lemma gcd-mod2 [simp]: gcd a (b mod a) = gcd a b by (rule gcdI , simp, metis dvd-mod-iff gcd-dvd1 gcd-dvd2 , simp-all add: gcd-greatest dvd-mod-iff ) lemma euclidean-size-gcd-le1 [simp]: assumes a 6= 0 shows euclidean-size (gcd a b) ≤ euclidean-size a proof − have gcd a b dvd a by (rule gcd-dvd1 ) then obtain c where A: a = gcd a b ∗ c unfolding dvd-def by blast with ha 6= 0 i show ?thesis by (subst (2 ) A, intro size-mult-mono) auto 351 qed lemma euclidean-size-gcd-le2 [simp]: b 6= 0 =⇒ euclidean-size (gcd a b) ≤ euclidean-size b by (subst gcd.commute, rule euclidean-size-gcd-le1 ) lemma euclidean-size-gcd-less1 : assumes a 6= 0 and ¬a dvd b shows euclidean-size (gcd a b) < euclidean-size a proof (rule ccontr) assume ¬euclidean-size (gcd a b) < euclidean-size a with ha 6= 0 i have A: euclidean-size (gcd a b) = euclidean-size a by (intro le-antisym, simp-all) have a dvd gcd a b by (rule dvd-euclidean-size-eq-imp-dvd)(simp-all add: assms A) hence a dvd b using dvd-gcdD2 by blast with h¬a dvd bi show False by contradiction qed lemma euclidean-size-gcd-less2 : assumes b 6= 0 and ¬b dvd a shows euclidean-size (gcd a b) < euclidean-size b using assms by (subst gcd.commute, rule euclidean-size-gcd-less1 ) lemma euclidean-size-lcm-le1 : assumes a 6= 0 and b 6= 0 shows euclidean-size a ≤ euclidean-size (lcm a b) proof − have a dvd lcm a b by (rule dvd-lcm1 ) then obtain c where A: lcm a b = a ∗ c .. with ha 6= 0 i and hb 6= 0 i have c 6= 0 by (auto simp: lcm-eq-0-iff ) then show ?thesis by (subst A, intro size-mult-mono) qed lemma euclidean-size-lcm-le2 : a 6= 0 =⇒ b 6= 0 =⇒ euclidean-size b ≤ euclidean-size (lcm a b) using euclidean-size-lcm-le1 [of b a] by (simp add: ac-simps) lemma euclidean-size-lcm-less1 : assumes b 6= 0 and ¬b dvd a shows euclidean-size a < euclidean-size (lcm a b) proof (rule ccontr) from assms have a 6= 0 by auto assume ¬euclidean-size a < euclidean-size (lcm a b) with ha 6= 0 i and hb 6= 0 i have euclidean-size (lcm a b) = euclidean-size a by (intro le-antisym, simp, intro euclidean-size-lcm-le1 ) with assms have lcm a b dvd a by (rule-tac dvd-euclidean-size-eq-imp-dvd)(auto simp: lcm-eq-0-iff ) hence b dvd a by (rule lcm-dvdD2 ) 352 with h¬b dvd a i show False by contradiction qed lemma euclidean-size-lcm-less2 : assumes a 6= 0 and ¬a dvd b shows euclidean-size b < euclidean-size (lcm a b) using assms euclidean-size-lcm-less1 [of a b] by (simp add: ac-simps) lemma Lcm-eucl-set [code]: Lcm-eucl (set xs) = foldl lcm-eucl 1 xs by (simp add: Lcm-Lcm-eucl [symmetric] lcm-lcm-eucl Lcm-set) lemma Gcd-eucl-set [code]: Gcd-eucl (set xs) = foldl gcd-eucl 0 xs by (simp add: Gcd-Gcd-eucl [symmetric] gcd-gcd-eucl Gcd-set) end A Euclidean ring is a Euclidean semiring with additive inverses. It provides a few more lemmas; in particular, Bezout’s lemma holds for any Euclidean ring. class euclidean-ring-gcd = euclidean-semiring-gcd + idom begin subclass euclidean-ring .. subclass ring-gcd .. subclass factorial-ring-gcd .. lemma euclid-ext-gcd [simp]: (case euclid-ext a b of (-, - , t) ⇒ t) = gcd a b using euclid-ext-correct 0[of a b] by (simp add: case-prod-unfold Let-def gcd-gcd-eucl) lemma euclid-ext-gcd 0 [simp]: euclid-ext a b = (r, s, t) =⇒ t = gcd a b by (insert euclid-ext-gcd[of a b], drule (1 ) subst, simp) lemma euclid-ext-correct: case euclid-ext a b of (x,y,c) ⇒ x ∗ a + y ∗ b = c ∧ c = gcd a b using euclid-ext-correct 0[of a b] by (simp add: gcd-gcd-eucl case-prod-unfold) lemma euclid-ext 0-correct: fst (euclid-ext 0 a b) ∗ a + snd (euclid-ext 0 a b) ∗ b = gcd a b using euclid-ext-correct 0[of a b] by (simp add: gcd-gcd-eucl case-prod-unfold euclid-ext 0-def ) lemma bezout: ∃ s t. s ∗ a + t ∗ b = gcd a b using euclid-ext 0-correct by blast 353 end 47.1 Typical instances instantiation nat :: euclidean-semiring begin definition [simp]: euclidean-size-nat = (id :: nat ⇒ nat) instance by standard simp-all end instantiation int :: euclidean-ring begin definition [simp]: euclidean-size-int = (nat ◦ abs :: int ⇒ nat) instance by standard (auto simp add: abs-mult nat-mult-distrib split: abs-split) end instance nat :: euclidean-semiring-gcd proof show [simp]: gcd = (gcd-eucl :: nat ⇒ -) Lcm = (Lcm-eucl :: nat set ⇒ -) by (simp-all add: eq-gcd-euclI eq-Lcm-euclI ) show lcm = (lcm-eucl :: nat ⇒ -) Gcd = (Gcd-eucl :: nat set ⇒ -) by (intro ext, simp add: lcm-eucl-def lcm-nat-def Gcd-nat-def Gcd-eucl-def )+ qed instance int :: euclidean-ring-gcd proof show [simp]: gcd = (gcd-eucl :: int ⇒ -) Lcm = (Lcm-eucl :: int set ⇒ -) by (simp-all add: eq-gcd-euclI eq-Lcm-euclI ) show lcm = (lcm-eucl :: int ⇒ -) Gcd = (Gcd-eucl :: int set ⇒ -) by (intro ext, simp add: lcm-eucl-def lcm-altdef-int semiring-Gcd-class.Gcd-Lcm Gcd-eucl-def abs-mult)+ qed end 48 Primes theory Primes imports ∼∼/src/HOL/Binomial Euclidean-Algorithm begin 354 declare [[coercion int]] declare [[coercion-enabled]] lemma prime-elem-nat-iff : prime-elem (n :: nat) ←→ (1 < n ∧ (∀ m. m dvd n −→ m = 1 ∨ m = n)) proof safe assume ∗: prime-elem n from ∗ have n 6= 0 n 6= 1 by (intro notI , simp del: One-nat-def )+ thus n > 1 by (cases n) simp-all fix m assume m: m dvd n m 6= n from ∗ hm dvd n i have n dvd m ∨ is-unit m by (intro irreducibleD 0 prime-elem-imp-irreducible) with m show m = 1 by (auto dest: dvd-antisym) next assume n > 1 ∀ m. m dvd n −→ m = 1 ∨ m = n thus prime-elem n by (auto simp: prime-elem-iff-irreducible irreducible-altdef ) qed lemma prime-nat-iff-prime-elem: prime (n :: nat) ←→ prime-elem n by (simp add: prime-def ) lemma prime-nat-iff : prime (n :: nat) ←→ (1 < n ∧ (∀ m. m dvd n −→ m = 1 ∨ m = n)) by (simp add: prime-nat-iff-prime-elem prime-elem-nat-iff ) lemma prime-elem-int-nat-transfer: prime-elem (n::int) ←→ prime-elem (nat (abs n)) proof assume prime-elem n thus prime-elem (nat (abs n)) by (auto simp: prime-elem-def nat-dvd-iff ) next assume prime-elem (nat (abs n)) thus prime-elem n by (auto simp: dvd-int-unfold-dvd-nat prime-elem-def abs-mult nat-mult-distrib) qed lemma prime-elem-nat-int-transfer [simp]: prime-elem (int n) ←→ prime-elem n by (auto simp: prime-elem-int-nat-transfer) lemma prime-nat-int-transfer [simp]: prime (int n) ←→ prime n by (auto simp: prime-elem-int-nat-transfer prime-def ) lemma prime-int-nat-transfer: prime (n::int) ←→ n ≥ 0 ∧ prime (nat n) by (auto simp: prime-elem-int-nat-transfer prime-def ) 355 lemma prime-int-iff : prime (n::int) ←→ (1 < n ∧ (∀ m. m ≥ 0 ∧ m dvd n −→ m = 1 ∨ m = n)) proof (intro iffI conjI allI impI ;(elim conjE)?) assume ∗: prime n hence irred: irreducible n by (simp add: prime-elem-imp-irreducible) from ∗ have n ≥ 0 n 6= 0 n 6= 1 by (auto simp: prime-def zabs-def not-less split: if-splits) thus n > 1 by presburger fix m assume m dvd n hm ≥ 0 i with irred have m dvd 1 ∨ n dvd m by (auto simp: irreducible-altdef ) with hm dvd n i hm ≥ 0 i hn > 1 i show m = 1 ∨ m = n using associated-iff-dvd[of m n] by auto next assume n: 1 < n ∀ m. m ≥ 0 ∧ m dvd n −→ m = 1 ∨ m = n hence nat n > 1 by simp moreover have ∀ m. m dvd nat n −→ m = 1 ∨ m = nat n proof (intro allI impI ) fix m assume m dvd nat n with hn > 1 i have int m dvd n by (auto simp: int-dvd-iff ) with n(2 ) have int m = 1 ∨ int m = n by auto thus m = 1 ∨ m = nat n by auto qed ultimately show prime n unfolding prime-int-nat-transfer prime-nat-iff by auto qed lemma prime-nat-not-dvd: assumes prime p p > n n 6= (1 ::nat) shows ¬n dvd p proof assume n dvd p from assms(1 ) have irreducible p by (simp add: prime-elem-imp-irreducible) 0 from irreducibleD [OF this hn dvd pi] hn dvd pi hp > n i assms show False by (cases n = 0 )(auto dest!: dvd-imp-le) qed lemma prime-int-not-dvd: assumes prime p p > n n > (1 ::int) shows ¬n dvd p proof assume n dvd p from assms(1 ) have irreducible p by (simp add: prime-elem-imp-irreducible) 0 from irreducibleD [OF this hn dvd pi] hn dvd pi hp > n i assms show False by (auto dest!: zdvd-imp-le) qed lemma prime-odd-nat: prime p =⇒ p > (2 ::nat) =⇒ odd p by (intro prime-nat-not-dvd) auto 356 lemma prime-odd-int: prime p =⇒ p > (2 ::int) =⇒ odd p by (intro prime-int-not-dvd) auto lemma prime-ge-0-int: prime p =⇒ p ≥ (0 ::int) unfolding prime-int-iff by auto lemma prime-gt-0-nat: prime p =⇒ p > (0 ::nat) unfolding prime-nat-iff by auto lemma prime-gt-0-int: prime p =⇒ p > (0 ::int) unfolding prime-int-iff by auto lemma prime-ge-1-nat: prime p =⇒ p ≥ (1 ::nat) unfolding prime-nat-iff by auto lemma prime-ge-Suc-0-nat: prime p =⇒ p ≥ Suc 0 unfolding prime-nat-iff by auto lemma prime-ge-1-int: prime p =⇒ p ≥ (1 ::int) unfolding prime-int-iff by auto lemma prime-gt-1-nat: prime p =⇒ p > (1 ::nat) unfolding prime-nat-iff by auto lemma prime-gt-Suc-0-nat: prime p =⇒ p > Suc 0 unfolding prime-nat-iff by auto lemma prime-gt-1-int: prime p =⇒ p > (1 ::int) unfolding prime-int-iff by auto lemma prime-ge-2-nat: prime p =⇒ p ≥ (2 ::nat) unfolding prime-nat-iff by auto lemma prime-ge-2-int: prime p =⇒ p ≥ (2 ::int) unfolding prime-int-iff by auto lemma prime-int-altdef : prime p = (1 < p ∧ (∀ m::int. m ≥ 0 −→ m dvd p −→ m = 1 ∨ m = p)) unfolding prime-int-iff by blast lemma not-prime-eq-prod-nat: assumes m > 1 ¬prime (m::nat) shows ∃ n k. n = m ∗ k ∧ 1 < m ∧ m < n ∧ 1 < k ∧ k < n using assms irreducible-altdef [of m] by (auto simp: prime-elem-iff-irreducible prime-def irreducible-altdef ) 357 48.0.1 Make prime naively executable lemma Suc-0-not-prime-nat [simp]: ∼prime (Suc 0 ) unfolding One-nat-def [symmetric] by (rule not-prime-1 ) lemma prime-nat-iff 0: prime (p :: nat) ←→ p > 1 ∧ (∀ n ∈ {1 <.. 1 and ∗: ∀ n∈{1 <.. 1 i have m 6= 0 by (intro notI ) auto hence m ≥ 1 by simp moreover from hm dvd pi and ∗ have m ∈/ {1 <.. 1 i have m ≤ 1 ∨ m = p by (auto dest: dvd-imp-le) ultimately show m = 1 ∨ m = p by simp qed fact+ qed (auto simp: prime-nat-iff ) lemma prime-nat-code [code-unfold]: (prime :: nat ⇒ bool) = (λp. p > 1 ∧ (∀ n ∈ {1 <.. 1 ∧ (∀ n ∈ {1 <.. 1 ∧ (∀ n ∈ {1 <.. 1 ∧ (∀ n ∈ set [2 .. 1 ∧ (∀ n ∈ {2 .. 358 declare prime-int-nat-transfer[of numeral m for m, simp] A bit of regression testing: lemma prime(97 ::nat) by simp lemma prime(997 ::nat) by eval lemma prime(97 ::int) by simp lemma prime(997 ::int) by eval lemma prime-factor-nat: n 6= (1 ::nat) =⇒ ∃ p. prime p ∧ p dvd n using prime-divisor-exists[of n] by (cases n = 0 )(auto intro: exI [of - 2 ::nat]) 48.1 Infinitely many primes lemma next-prime-bound: ∃ p::nat. prime p ∧ n < p ∧ p ≤ fact n + 1 proof− have f1 : fact n + 1 6= (1 ::nat) using fact-ge-1 [of n, where 0a=nat] by arith from prime-factor-nat [OF f1 ] obtain p :: nat where prime p and p dvd fact n + 1 by auto then have p ≤ fact n + 1 apply (intro dvd-imp-le) apply auto done { assume p ≤ n from hprime pi have p ≥ 1 by (cases p, simp-all) with hp <= n i have p dvd fact n by (intro dvd-fact) with hp dvd fact n + 1 i have p dvd fact n + 1 − fact n by (rule dvd-diff-nat) then have p dvd 1 by simp then have p <= 1 by auto moreover from hprime pi have p > 1 using prime-nat-iff by blast ultimately have False by auto} then have n < p by presburger with hprime pi and hp <= fact n + 1 i show ?thesis by auto qed lemma bigger-prime: ∃ p. prime p ∧ p > (n::nat) using next-prime-bound by auto lemma primes-infinite: ¬ (finite {(p::nat). prime p}) proof assume finite {(p::nat). prime p} with Max-ge have (EX b. (ALL x : {(p::nat). prime p}. x <= b)) by auto then obtain b where ALL (x::nat). prime x −→ x <= b by auto with bigger-prime [of b] show False 359 by auto qed 48.2 Powers of Primes Versions for type nat only lemma prime-product: fixes p::nat assumes prime (p ∗ q) shows p = 1 ∨ q = 1 proof − from assms have 1 < p ∗ q and P: Vm. m dvd p ∗ q =⇒ m = 1 ∨ m = p ∗ q unfolding prime-nat-iff by auto from h1 < p ∗ q i have p 6= 0 by (cases p) auto then have Q: p = p ∗ q ←→ q = 1 by auto have p dvd p ∗ q by simp then have p = 1 ∨ p = p ∗ q by (rule P) then show ?thesis by (simp add: Q) qed lemma prime-power-mult-nat: fixes p::nat assumes p: prime p and xy: x ∗ y = p ˆ k shows ∃ i j . x = p ˆi ∧ y = pˆ j using xy proof(induct k arbitrary: x y) case 0 thus ?case apply simp by (rule exI [where x=0 ], simp) next case (Suc k x y) from Suc.prems have pxy: p dvd x∗y by auto from prime-dvd-multD [OF p pxy] have pxyc: p dvd x ∨ p dvd y . from p have p0 : p 6= 0 by − (rule ccontr, simp) {assume px: p dvd x then obtain d where d: x = p∗d unfolding dvd-def by blast from Suc.prems d have p∗d∗y = pˆSuc k by simp hence th: d∗y = pˆk using p0 by simp from Suc.hyps[OF th] obtain i j where ij : d = pˆi y = pˆj by blast with d have x = pˆSuc i by simp with ij (2 ) have ?case by blast} moreover {assume px: p dvd y then obtain d where d: y = p∗d unfolding dvd-def by blast from Suc.prems d have p∗d∗x = pˆSuc k by (simp add: mult.commute) hence th: d∗x = pˆk using p0 by simp from Suc.hyps[OF th] obtain i j where ij : d = pˆi x = pˆj by blast with d have y = pˆSuc i by simp with ij (2 ) have ?case by blast} 360 ultimately show ?case using pxyc by blast qed lemma prime-power-exp-nat: fixes p::nat assumes p: prime p and n: n 6= 0 and xn: xˆn = pˆk shows ∃ i. x = pˆi using n xn proof(induct n arbitrary: k) case 0 thus ?case by simp next case (Suc n k) hence th: x∗xˆn = pˆk by simp {assume n = 0 with Suc have ?case by simp (rule exI [where x=k], simp)} moreover {assume n: n 6= 0 from prime-power-mult-nat[OF p th] obtain i j where ij : x = pˆi xˆn = pˆj by blast from Suc.hyps[OF n ij (2 )] have ?case .} ultimately show ?case by blast qed lemma divides-primepow-nat: fixes p::nat assumes p: prime p shows d dvd pˆk ←→ (∃ i. i ≤ k ∧ d = p ˆi) proof assume H : d dvd pˆk then obtain e where e: d∗e = pˆk unfolding dvd-def apply (auto simp add: mult.commute) by blast from prime-power-mult-nat[OF p e] obtain i j where ij : d = pˆi e=pˆj by blast from e ij have pˆ(i + j ) = pˆk by (simp add: power-add) hence i + j = k using p prime-gt-1-nat power-inject-exp[of p i+j k] by simp hence i ≤ k by arith with ij (1 ) show ∃ i≤k. d = p ˆ i by blast next {fix i assume H : i ≤ k d = pˆi then obtain j where j : k = i + j by (metis le-add-diff-inverse) hence pˆk = pˆj ∗d using H (2 ) by (simp add: power-add) hence d dvd pˆk unfolding dvd-def by auto} thus ∃ i≤k. d = p ˆ i =⇒ d dvd p ˆ k by blast qed 48.3 Chinese Remainder Theorem Variants lemma bezout-gcd-nat: fixes a::nat shows ∃ x y. a ∗ x − b ∗ y = gcd a b ∨ b ∗ x − a ∗ y = gcd a b using bezout-nat[of a b] by (metis bezout-nat diff-add-inverse gcd-add-mult gcd.commute 361 gcd-nat.right-neutral mult-0 ) lemma gcd-bezout-sum-nat: fixes a::nat assumes a ∗ x + b ∗ y = d shows gcd a b dvd d proof− let ?g = gcd a b have dv: ?g dvd a∗x ?g dvd b ∗ y by simp-all from dvd-add[OF dv] assms show ?thesis by auto qed A binary form of the Chinese Remainder Theorem. lemma chinese-remainder: fixes a::nat assumes ab: coprime a b and a: a 6= 0 and b: b 6= 0 shows ∃ x q1 q2 . x = u + q1 ∗ a ∧ x = v + q2 ∗ b proof− from bezout-add-strong-nat[OF a, of b] bezout-add-strong-nat[OF b, of a] obtain d1 x1 y1 d2 x2 y2 where dxy1 : d1 dvd a d1 dvd b a ∗ x1 = b ∗ y1 + d1 and dxy2 : d2 dvd b d2 dvd a b ∗ x2 = a ∗ y2 + d2 by blast then have d12 : d1 = 1 d2 =1 by (metis ab coprime-nat)+ let ?x = v ∗ a ∗ x1 + u ∗ b ∗ x2 let ?q1 = v ∗ x1 + u ∗ y2 let ?q2 = v ∗ y1 + u ∗ x2 from dxy2 (3 )[simplified d12 ] dxy1 (3 )[simplified d12 ] have ?x = u + ?q1 ∗ a ?x = v + ?q2 ∗ b by algebra+ thus ?thesis by blast qed Primality lemma coprime-bezout-strong: fixes a::nat assumes coprime a b b 6= 1 shows ∃ x y. a ∗ x = b ∗ y + 1 by (metis assms bezout-nat gcd-nat.left-neutral) lemma bezout-prime: assumes p: prime p and pa: ¬ p dvd a shows ∃ x y. a∗x = Suc (p∗y) proof − have ap: coprime a p by (metis gcd.commute p pa prime-imp-coprime) moreover from p have p 6= 1 by auto ultimately have ∃ x y. a ∗ x = p ∗ y + 1 by (rule coprime-bezout-strong) then show ?thesis by simp 362 qed 48.4 Multiplicity and primality for natural numbers and in- tegers lemma prime-factors-gt-0-nat: p ∈ prime-factors x =⇒ p > (0 ::nat) by (simp add: in-prime-factors-imp-prime prime-gt-0-nat) lemma prime-factors-gt-0-int: p ∈ prime-factors x =⇒ p > (0 ::int) by (simp add: in-prime-factors-imp-prime prime-gt-0-int) lemma prime-factors-ge-0-int [elim]: fixes n :: int shows p ∈ prime-factors n =⇒ p ≥ 0 by (drule prime-factors-gt-0-int) simp lemma prod-mset-prime-factorization-int: fixes n :: int assumes n > 0 shows prod-mset (prime-factorization n) = n using assms by (simp add: prod-mset-prime-factorization) lemma prime-factorization-exists-nat: n > 0 =⇒ (∃ M . (∀ p::nat ∈ set-mset M . prime p) ∧ n = (Q i ∈# M . i)) using prime-factorization-exists[of n] by (auto simp: prime-def ) lemma prod-mset-prime-factorization-nat [simp]: (n::nat) > 0 =⇒ prod-mset (prime-factorization n) = n by (subst prod-mset-prime-factorization) simp-all lemma prime-factorization-nat: n > (0 ::nat) =⇒ n = (Q p ∈ prime-factors n. p ˆ multiplicity p n) by (simp add: prod-prime-factors) lemma prime-factorization-int: n > (0 ::int) =⇒ n = (Q p ∈ prime-factors n. p ˆ multiplicity p n) by (simp add: prod-prime-factors) lemma prime-factorization-unique-nat: fixes f :: nat ⇒ - assumes S-eq: S = {p. 0 < f p} and finite S and S: ∀ p∈S. prime p n = (Q p∈S. p ˆ f p) shows S = prime-factors n ∧ (∀ p. prime p −→ f p = multiplicity p n) using assms by (intro prime-factorization-unique 00) auto lemma prime-factorization-unique-int: 363 fixes f :: int ⇒ - assumes S-eq: S = {p. 0 < f p} and finite S and S: ∀ p∈S. prime p abs n = (Q p∈S. p ˆ f p) shows S = prime-factors n ∧ (∀ p. prime p −→ f p = multiplicity p n) using assms by (intro prime-factorization-unique 00) auto lemma prime-factors-characterization-nat: S = {p. 0 < f (p::nat)} =⇒ finite S =⇒ ∀ p∈S. prime p =⇒ n = (Q p∈S. p ˆ f p) =⇒ prime-factors n = S by (rule prime-factorization-unique-nat [THEN conjunct1 , symmetric]) lemma prime-factors-characterization 0-nat: finite {p. 0 < f (p::nat)} =⇒ (∀ p. 0 < f p −→ prime p) =⇒ prime-factors (Q p | 0 < f p. p ˆ f p) = {p. 0 < f p} by (rule prime-factors-characterization-nat) auto lemma prime-factors-characterization-int: S = {p. 0 < f (p::int)} =⇒ finite S =⇒ ∀ p∈S. prime p =⇒ abs n = (Q p∈S. p ˆ f p) =⇒ prime-factors n = S by (rule prime-factorization-unique-int [THEN conjunct1 , symmetric]) lemma abs-prod: abs (prod f A :: 0a :: linordered-idom) = prod (λx. abs (f x)) A by (cases finite A, induction A rule: finite-induct)(simp-all add: abs-mult) lemma primes-characterization 0-int [rule-format]: finite {p. p ≥ 0 ∧ 0 < f (p::int)} =⇒ ∀ p. 0 < f p −→ prime p =⇒ prime-factors (Q p | p ≥ 0 ∧ 0 < f p. p ˆ f p) = {p. p ≥ 0 ∧ 0 < f p} by (rule prime-factors-characterization-int)(auto simp: abs-prod prime-ge-0-int) lemma multiplicity-characterization-nat: S = {p. 0 < f (p::nat)} =⇒ finite S =⇒ ∀ p∈S. prime p =⇒ prime p =⇒ n = (Q p∈S. p ˆ f p) =⇒ multiplicity p n = f p by (frule prime-factorization-unique-nat [of S f n, THEN conjunct2 , rule-format, symmetric]) auto lemma multiplicity-characterization 0-nat: finite {p. 0 < f (p::nat)} −→ (∀ p. 0 < f p −→ prime p) −→ prime p −→ multiplicity p (Q p | 0 < f p. p ˆ f p) = f p by (intro impI , rule multiplicity-characterization-nat) auto lemma multiplicity-characterization-int: S = {p. 0 < f (p::int)} =⇒ finite S =⇒ ∀ p∈S. prime p =⇒ prime p =⇒ n = (Q p∈S. p ˆ f p) =⇒ multiplicity p n = f p by (frule prime-factorization-unique-int [of S f n, THEN conjunct2 , rule-format, symmetric]) 364 (auto simp: abs-prod power-abs prime-ge-0-int intro!: prod.cong) lemma multiplicity-characterization 0-int [rule-format]: finite {p. p ≥ 0 ∧ 0 < f (p::int)} =⇒ (∀ p. 0 < f p −→ prime p) =⇒ prime p =⇒ multiplicity p (Q p | p ≥ 0 ∧ 0 < f p. p ˆ f p) = f p by (rule multiplicity-characterization-int)(auto simp: prime-ge-0-int) lemma multiplicity-one-nat [simp]: multiplicity p (Suc 0 ) = 0 unfolding One-nat-def [symmetric] by (rule multiplicity-one) lemma multiplicity-eq-nat: fixes x and y::nat assumes x > 0 y > 0 Vp. prime p =⇒ multiplicity p x = multiplicity p y shows x = y using multiplicity-eq-imp-eq[of x y] assms by simp lemma multiplicity-eq-int: fixes x y :: int assumes x > 0 y > 0 Vp. prime p =⇒ multiplicity p x = multiplicity p y shows x = y using multiplicity-eq-imp-eq[of x y] assms by simp lemma multiplicity-prod-prime-powers: assumes finite S Vx. x ∈ S =⇒ prime x prime p shows multiplicity p (Q p ∈ S. p ˆ f p) = (if p ∈ S then f p else 0 ) proof − define g where g = (λx. if x ∈ S then f x else 0 ) define A where A = Abs-multiset g have {x. g x > 0 } ⊆ S by (auto simp: g-def ) from finite-subset[OF this assms(1 )] have [simp]: g : multiset by (simp add: multiset-def ) from assms have count-A: count A x = g x for x unfolding A-def by simp have set-mset-A: set-mset A = {x∈S. f x > 0 } unfolding set-mset-def count-A by (auto simp: g-def ) with assms have prime: prime x if x ∈# A for x using that by auto from set-mset-A assms have (Q p ∈ S. p ˆ f p) = (Q p ∈ S. p ˆ g p) by (intro prod.cong)(auto simp: g-def ) also from set-mset-A assms have ... = (Q p ∈ set-mset A. p ˆ g p) by (intro prod.mono-neutral-right)(auto simp: g-def set-mset-A) also have ... = prod-mset A by (auto simp: prod-mset-multiplicity count-A set-mset-A intro!: prod.cong) also from assms have multiplicity p ... = sum-mset (image-mset (multiplicity p) A) by (subst prime-elem-multiplicity-prod-mset-distrib)(auto dest: prime) also from assms have image-mset (multiplicity p) A = image-mset (λx. if x = p then 1 else 0 ) A by (intro image-mset-cong)(auto simp: prime-multiplicity-other dest: prime) 365 also have sum-mset ... = (if p ∈ S then f p else 0 ) by (simp add: sum-mset-delta count-A g-def ) finally show ?thesis . qed lemma prime-factorization-prod-mset: assumes 0 ∈/# A shows prime-factorization (prod-mset A) = S #(image-mset prime-factorization A) using assms by (induct A)(auto simp add: prime-factorization-mult) lemma prime-factors-prod: assumes finite A and 0 ∈/ f ‘ A shows prime-factors (prod f A) = UNION A (prime-factors ◦ f ) using assms by (simp add: prod-unfold-prod-mset prime-factorization-prod-mset) lemma prime-factors-fact: prime-factors (fact n) = {p ∈ {2 ..n}. prime p} (is ?M = ?N ) proof (rule set-eqI ) fix p { fix m :: nat assume p ∈ prime-factors m then have prime p and p dvd m by auto moreover assume m > 0 ultimately have 2 ≤ p and p ≤ m by (auto intro: prime-ge-2-nat dest: dvd-imp-le) moreover assume m ≤ n ultimately have 2 ≤ p and p ≤ n by (auto intro: order-trans) } note ∗ = this show p ∈ ?M ←→ p ∈ ?N by (auto simp add: fact-prod prime-factors-prod Suc-le-eq dest!: prime-prime-factors intro: ∗) qed lemma prime-dvd-fact-iff : assumes prime p shows p dvd fact n ←→ p ≤ n using assms by (auto simp add: prime-factorization-subset-iff-dvd [symmetric] prime-factorization-prime prime-factors-fact prime-ge-2-nat) lemmas prime-imp-coprime-nat = prime-imp-coprime[where ? 0a = nat] lemmas prime-imp-coprime-int = prime-imp-coprime[where ? 0a = int] lemmas prime-dvd-mult-nat = prime-dvd-mult-iff [where ? 0a = nat] lemmas prime-dvd-mult-int = prime-dvd-mult-iff [where ? 0a = int] lemmas prime-dvd-mult-eq-nat = prime-dvd-mult-iff [where ? 0a = nat] lemmas prime-dvd-mult-eq-int = prime-dvd-mult-iff [where ? 0a = int] 366 lemmas prime-dvd-power-nat = prime-dvd-power[where ? 0a = nat] lemmas prime-dvd-power-int = prime-dvd-power[where ? 0a = int] lemmas prime-dvd-power-nat-iff = prime-dvd-power-iff [where ? 0a = nat] lemmas prime-dvd-power-int-iff = prime-dvd-power-iff [where ? 0a = int] lemmas prime-imp-power-coprime-nat = prime-imp-power-coprime[where ? 0a = nat] lemmas prime-imp-power-coprime-int = prime-imp-power-coprime[where ? 0a = int] lemmas primes-coprime-nat = primes-coprime[where ? 0a = nat] lemmas primes-coprime-int = primes-coprime[where ? 0a = nat] lemmas prime-divprod-pow-nat = prime-elem-divprod-pow[where ? 0a = nat] lemmas prime-exp = prime-elem-power-iff [where ? 0a = nat] end 49 Square roots of primes are irrational theory Sqrt imports Complex-Main ∼∼/src/HOL/Number-Theory/Primes begin The square root of any prime number (including 2) is irrational. theorem sqrt-prime-irrational: assumes prime (p::nat) shows sqrt p ∈/ Q proof from hprime pi have p: 1 < p by (simp add: prime-nat-iff ) assume sqrt p ∈ Q then obtain m n :: nat where n: n 6= 0 and sqrt-rat: |sqrt p| = m / n and coprime m n by (rule Rats-abs-nat-div-natE) have eq: m2 = p ∗ n2 proof − from n and sqrt-rat have m = |sqrt p| ∗ n by simp then have m2 = (sqrt p)2 ∗ n2 by (auto simp add: power2-eq-square) also have (sqrt p)2 = p by simp also have ... ∗ n2 = p ∗ n2 by simp finally show ?thesis using of-nat-eq-iff by blast qed have p dvd m ∧ p dvd n proof from eq have p dvd m2 .. with hprime pi show p dvd m by (rule prime-dvd-power-nat) then obtain k where m = p ∗ k .. with eq have p ∗ n2 = p2 ∗ k 2 by (auto simp add: power2-eq-square ac-simps) with p have n2 = p ∗ k 2 by (simp add: power2-eq-square) then have p dvd n2 .. with hprime pi show p dvd n by (rule prime-dvd-power-nat) 367 qed then have p dvd gcd m n by simp with hcoprime m n i have p = 1 by simp with p show False by simp qed corollary sqrt-2-not-rat: sqrt 2 ∈/ Q using sqrt-prime-irrational[of 2 ] by simp 49.1 Variations Here is an alternative version of the main proof, using mostly linear forward- reasoning. While this results in less top-down structure, it is probably closer to proofs seen in mathematics. theorem assumes prime (p::nat) shows sqrt p ∈/ Q proof from hprime pi have p: 1 < p by (simp add: prime-nat-iff ) assume sqrt p ∈ Q then obtain m n :: nat where n: n 6= 0 and sqrt-rat: |sqrt p| = m / n and coprime m n by (rule Rats-abs-nat-div-natE) from n and sqrt-rat have m = |sqrt p| ∗ n by simp then have m2 = (sqrt p)2 ∗ n2 by (auto simp add: power2-eq-square) also have (sqrt p)2 = p by simp also have ... ∗ n2 = p ∗ n2 by simp finally have eq: m2 = p ∗ n2 using of-nat-eq-iff by blast then have p dvd m2 .. with hprime pi have dvd-m: p dvd m by (rule prime-dvd-power-nat) then obtain k where m = p ∗ k .. with eq have p ∗ n2 = p2 ∗ k 2 by (auto simp add: power2-eq-square ac-simps) with p have n2 = p ∗ k 2 by (simp add: power2-eq-square) then have p dvd n2 .. with hprime pi have p dvd n by (rule prime-dvd-power-nat) with dvd-m have p dvd gcd m n by (rule gcd-greatest) with hcoprime m n i have p = 1 by simp with p show False by simp qed Another old chestnut, which is a consequence of the irrationality of 2. lemma ∃ a b::real. a ∈/ Q ∧ b ∈/ Q ∧ a powr b ∈ Q (is ∃ a b. ?P a b) proof cases assume sqrt 2 powr sqrt 2 ∈ Q then have ?P (sqrt 2 )(sqrt 2 ) by (metis sqrt-2-not-rat) then show ?thesis by blast 368 next assume 1 : sqrt 2 powr sqrt 2 ∈/ Q have (sqrt 2 powr sqrt 2 ) powr sqrt 2 = 2 using powr-realpow [of - 2 ] by (simp add: powr-powr power2-eq-square [symmetric]) then have ?P (sqrt 2 powr sqrt 2 )(sqrt 2 ) by (metis 1 Rats-number-of sqrt-2-not-rat) then show ?thesis by blast qed end 50 Square roots of primes are irrational (script version) theory Sqrt-Script imports Complex-Main ∼∼/src/HOL/Number-Theory/Primes begin Contrast this linear Isabelle/Isar script with Markus Wenzel’s more mathe- matical version. 50.1 Preliminaries lemma prime-nonzero: prime (p::nat) =⇒ p 6= 0 by (force simp add: prime-nat-iff ) lemma prime-dvd-other-side: (n::nat) ∗ n = p ∗ (k ∗ k) =⇒ prime p =⇒ p dvd n apply (subgoal-tac p dvd n ∗ n, blast dest: prime-dvd-mult-nat) apply auto done lemma reduction: prime (p::nat) =⇒ 0 < k =⇒ k ∗ k = p ∗ (j ∗ j ) =⇒ k < p ∗ j ∧ 0 < j apply (rule ccontr) apply (simp add: linorder-not-less) apply (erule disjE) apply (frule mult-le-mono, assumption) apply auto apply (force simp add: prime-nat-iff ) done lemma rearrange:(j ::nat) ∗ (p ∗ j ) = k ∗ k =⇒ k ∗ k = p ∗ (j ∗ j ) by (simp add: ac-simps) lemma prime-not-square: prime (p::nat) =⇒ (Vk. 0 < k =⇒ m ∗ m 6= p ∗ (k ∗ k)) 369 apply (induct m rule: nat-less-induct) apply clarify apply (frule prime-dvd-other-side, assumption) apply (erule dvdE) apply (simp add: nat-mult-eq-cancel-disj prime-nonzero) apply (blast dest: rearrange reduction) done 50.2 Main theorem The square root of any prime number (including 2 ) is irrational. theorem prime-sqrt-irrational: prime (p::nat) =⇒ x ∗ x = real p =⇒ 0 ≤ x =⇒ x ∈/ Q apply (rule notI ) apply (erule Rats-abs-nat-div-natE) apply (simp del: of-nat-mult add: abs-if divide-eq-eq prime-not-square of-nat-mult [symmetric]) done lemmas two-sqrt-irrational = prime-sqrt-irrational [OF two-is-prime-nat] end 51 Type of finite sets defined as a subtype of sets theory FSet imports Main begin 51.1 Definition of the type typedef 0a fset = {A :: 0a set. finite A} morphisms fset Abs-fset by auto setup-lifting type-definition-fset 51.2 Basic operations and type class instantiations instantiation fset :: (finite) finite begin instance by (standard; transfer; simp) end instantiation fset :: (type) {bounded-lattice-bot, distrib-lattice, minus} begin lift-definition bot-fset :: 0a fset is {} parametric empty-transfer by simp 370 lift-definition less-eq-fset :: 0a fset ⇒ 0a fset ⇒ bool is subset-eq parametric subset-transfer . definition less-fset :: 0a fset ⇒ 0a fset ⇒ bool where xs < ys ≡ xs ≤ ys ∧ xs 6= (ys:: 0a fset) lemma less-fset-transfer[transfer-rule]: includes lifting-syntax assumes [transfer-rule]: bi-unique A shows ((pcr-fset A) ===> (pcr-fset A) ===> op =) op ⊂ op < unfolding less-fset-def [abs-def ] psubset-eq[abs-def ] by transfer-prover lift-definition sup-fset :: 0a fset ⇒ 0a fset ⇒ 0a fset is union parametric union-transfer by simp lift-definition inf-fset :: 0a fset ⇒ 0a fset ⇒ 0a fset is inter parametric inter-transfer by simp lift-definition minus-fset :: 0a fset ⇒ 0a fset ⇒ 0a fset is minus parametric Diff-transfer by simp instance by (standard; transfer; auto)+ end abbreviation fempty :: 0a fset ({||}) where {||} ≡ bot abbreviation fsubset-eq :: 0a fset ⇒ 0a fset ⇒ bool (infix |⊆| 50 ) where xs |⊆| ys ≡ xs ≤ ys abbreviation fsubset :: 0a fset ⇒ 0a fset ⇒ bool (infix |⊂| 50 ) where xs |⊂| ys ≡ xs < ys abbreviation funion :: 0a fset ⇒ 0a fset ⇒ 0a fset (infixl |∪| 65 ) where xs |∪| ys ≡ sup xs ys abbreviation finter :: 0a fset ⇒ 0a fset ⇒ 0a fset (infixl |∩| 65 ) where xs |∩| ys ≡ inf xs ys abbreviation fminus :: 0a fset ⇒ 0a fset ⇒ 0a fset (infixl |−| 65 ) where xs |−| ys ≡ minus xs ys instantiation fset :: (equal) equal begin definition HOL.equal A B ←→ A |⊆| B ∧ B |⊆| A instance by intro-classes (auto simp add: equal-fset-def ) end instantiation fset :: (type) conditionally-complete-lattice 371 begin context includes lifting-syntax begin lemma right-total-Inf-fset-transfer: assumes [transfer-rule]: bi-unique A and [transfer-rule]: right-total A shows (rel-set (rel-set A) ===> rel-set A) (λS. if finite (T S ∩ Collect (Domainp A)) then T S ∩ Collect (Domainp A) else {}) (λS. if finite (Inf S) then Inf S else {}) by transfer-prover lemma Inf-fset-transfer: assumes [transfer-rule]: bi-unique A and [transfer-rule]: bi-total A shows (rel-set (rel-set A) ===> rel-set A)(λA. if finite (Inf A) then Inf A else {}) (λA. if finite (Inf A) then Inf A else {}) by transfer-prover lift-definition Inf-fset :: 0a fset set ⇒ 0a fset is λA. if finite (Inf A) then Inf A else {} parametric right-total-Inf-fset-transfer Inf-fset-transfer by simp lemma Sup-fset-transfer: assumes [transfer-rule]: bi-unique A shows (rel-set (rel-set A) ===> rel-set A)(λA. if finite (Sup A) then Sup A else {}) (λA. if finite (Sup A) then Sup A else {}) by transfer-prover lift-definition Sup-fset :: 0a fset set ⇒ 0a fset is λA. if finite (Sup A) then Sup A else {} parametric Sup-fset-transfer by simp lemma finite-Sup: ∃ z. finite z ∧ (∀ a. a ∈ X −→ a ≤ z) =⇒ finite (Sup X ) by (auto intro: finite-subset) lemma transfer-bdd-below[transfer-rule]: (rel-set (pcr-fset op =) ===> op =) bdd-below bdd-below by auto end instance proof fix x z :: 0a fset fix X :: 0a fset set { assume x ∈ X bdd-below X 372 then show Inf X |⊆| x by transfer auto next assume X 6= {} (Vx. x ∈ X =⇒ z |⊆| x) then show z |⊆| Inf X by transfer (clarsimp, blast) next assume x ∈ X bdd-above X then obtain z where x ∈ X (Vx. x ∈ X =⇒ x |⊆| z) by (auto simp: bdd-above-def ) then show x |⊆| Sup X by transfer (auto intro!: finite-Sup) next assume X 6= {} (Vx. x ∈ X =⇒ x |⊆| z) then show Sup X |⊆| z by transfer (clarsimp, blast) } qed end instantiation fset :: (finite) complete-lattice begin lift-definition top-fset :: 0a fset is UNIV parametric right-total-UNIV-transfer UNIV-transfer by simp instance by (standard; transfer; auto) end instantiation fset :: (finite) complete-boolean-algebra begin lift-definition uminus-fset :: 0a fset ⇒ 0a fset is uminus parametric right-total-Compl-transfer Compl-transfer by simp instance by (standard; transfer)(simp-all add: Diff-eq) end abbreviation fUNIV :: 0a::finite fset where fUNIV ≡ top abbreviation fuminus :: 0a::finite fset ⇒ 0a fset (|−| - [81 ] 80 ) where |−| x ≡ uminus x declare top-fset.rep-eq[simp] 51.3 Other operations lift-definition finsert :: 0a ⇒ 0a fset ⇒ 0a fset is insert parametric Lifting-Set.insert-transfer 373 by simp syntax -insert-fset :: args => 0a fset ({|(-)|}) translations {|x, xs|} == CONST finsert x {|xs|} {|x|} == CONST finsert x {||} lift-definition fmember :: 0a ⇒ 0a fset ⇒ bool (infix |∈| 50 ) is Set.member parametric member-transfer . abbreviation notin-fset :: 0a ⇒ 0a fset ⇒ bool (infix |∈|/ 50 ) where x |∈|/ S ≡ ¬ (x |∈| S) context includes lifting-syntax begin lift-definition ffilter :: ( 0a ⇒ bool) ⇒ 0a fset ⇒ 0a fset is Set.filter parametric Lifting-Set.filter-transfer unfolding Set.filter-def by simp lift-definition fPow :: 0a fset ⇒ 0a fset fset is Pow parametric Pow-transfer by (simp add: finite-subset) lift-definition fcard :: 0a fset ⇒ nat is card parametric card-transfer . lift-definition fimage :: ( 0a ⇒ 0b) ⇒ 0a fset ⇒ 0b fset (infixr |‘| 90 ) is image parametric image-transfer by simp lift-definition fthe-elem :: 0a fset ⇒ 0a is the-elem . lift-definition fbind :: 0a fset ⇒ ( 0a ⇒ 0b fset) ⇒ 0b fset is Set.bind parametric bind-transfer by (simp add: Set.bind-def ) lift-definition ffUnion :: 0a fset fset ⇒ 0a fset is Union parametric Union-transfer by simp lift-definition fBall :: 0a fset ⇒ ( 0a ⇒ bool) ⇒ bool is Ball parametric Ball-transfer . lift-definition fBex :: 0a fset ⇒ ( 0a ⇒ bool) ⇒ bool is Bex parametric Bex-transfer . lift-definition ffold :: ( 0a ⇒ 0b ⇒ 0b) ⇒ 0b ⇒ 0a fset ⇒ 0b is Finite-Set.fold . lift-definition fset-of-list :: 0a list ⇒ 0a fset is set by (rule finite-set) 374 51.4 Transferred lemmas from Set.thy lemmas fset-eqI = set-eqI [Transfer.transferred] lemmas fset-eq-iff [no-atp] = set-eq-iff [Transfer.transferred] lemmas fBallI [intro!] = ballI [Transfer.transferred] lemmas fbspec[dest?] = bspec[Transfer.transferred] lemmas fBallE[elim] = ballE[Transfer.transferred] lemmas fBexI [intro] = bexI [Transfer.transferred] lemmas rev-fBexI [intro?] = rev-bexI [Transfer.transferred] lemmas fBexCI = bexCI [Transfer.transferred] lemmas fBexE[elim!] = bexE[Transfer.transferred] lemmas fBall-triv[simp] = ball-triv[Transfer.transferred] lemmas fBex-triv[simp] = bex-triv[Transfer.transferred] lemmas fBex-triv-one-point1 [simp] = bex-triv-one-point1 [Transfer.transferred] lemmas fBex-triv-one-point2 [simp] = bex-triv-one-point2 [Transfer.transferred] lemmas fBex-one-point1 [simp] = bex-one-point1 [Transfer.transferred] lemmas fBex-one-point2 [simp] = bex-one-point2 [Transfer.transferred] lemmas fBall-one-point1 [simp] = ball-one-point1 [Transfer.transferred] lemmas fBall-one-point2 [simp] = ball-one-point2 [Transfer.transferred] lemmas fBall-conj-distrib = ball-conj-distrib[Transfer.transferred] lemmas fBex-disj-distrib = bex-disj-distrib[Transfer.transferred] lemmas fBall-cong = ball-cong[Transfer.transferred] lemmas fBex-cong = bex-cong[Transfer.transferred] lemmas fsubsetI [intro!] = subsetI [Transfer.transferred] lemmas fsubsetD[elim, intro?] = subsetD[Transfer.transferred] lemmas rev-fsubsetD[no-atp,intro?] = rev-subsetD[Transfer.transferred] lemmas fsubsetCE[no-atp,elim] = subsetCE[Transfer.transferred] lemmas fsubset-eq[no-atp] = subset-eq[Transfer.transferred] lemmas contra-fsubsetD[no-atp] = contra-subsetD[Transfer.transferred] lemmas fsubset-refl = subset-refl[Transfer.transferred] lemmas fsubset-trans = subset-trans[Transfer.transferred] lemmas fset-rev-mp = set-rev-mp[Transfer.transferred] lemmas fset-mp = set-mp[Transfer.transferred] lemmas fsubset-not-fsubset-eq[code] = subset-not-subset-eq[Transfer.transferred] lemmas eq-fmem-trans = eq-mem-trans[Transfer.transferred] lemmas fsubset-antisym[intro!] = subset-antisym[Transfer.transferred] lemmas fequalityD1 = equalityD1 [Transfer.transferred] lemmas fequalityD2 = equalityD2 [Transfer.transferred] lemmas fequalityE = equalityE[Transfer.transferred] lemmas fequalityCE[elim] = equalityCE[Transfer.transferred] lemmas eqfset-imp-iff = eqset-imp-iff [Transfer.transferred] lemmas eqfelem-imp-iff = eqelem-imp-iff [Transfer.transferred] lemmas fempty-iff [simp] = empty-iff [Transfer.transferred] lemmas fempty-fsubsetI [iff ] = empty-subsetI [Transfer.transferred] lemmas equalsffemptyI = equals0I [Transfer.transferred] lemmas equalsffemptyD = equals0D[Transfer.transferred] lemmas fBall-fempty[simp] = ball-empty[Transfer.transferred] lemmas fBex-fempty[simp] = bex-empty[Transfer.transferred] lemmas fPow-iff [iff ] = Pow-iff [Transfer.transferred] lemmas fPowI = PowI [Transfer.transferred] 375 lemmas fPowD = PowD[Transfer.transferred] lemmas fPow-bottom = Pow-bottom[Transfer.transferred] lemmas fPow-top = Pow-top[Transfer.transferred] lemmas fPow-not-fempty = Pow-not-empty[Transfer.transferred] lemmas finter-iff [simp] = Int-iff [Transfer.transferred] lemmas finterI [intro!] = IntI [Transfer.transferred] lemmas finterD1 = IntD1 [Transfer.transferred] lemmas finterD2 = IntD2 [Transfer.transferred] lemmas finterE[elim!] = IntE[Transfer.transferred] lemmas funion-iff [simp] = Un-iff [Transfer.transferred] lemmas funionI1 [elim?] = UnI1 [Transfer.transferred] lemmas funionI2 [elim?] = UnI2 [Transfer.transferred] lemmas funionCI [intro!] = UnCI [Transfer.transferred] lemmas funionE[elim!] = UnE[Transfer.transferred] lemmas fminus-iff [simp] = Diff-iff [Transfer.transferred] lemmas fminusI [intro!] = DiffI [Transfer.transferred] lemmas fminusD1 = DiffD1 [Transfer.transferred] lemmas fminusD2 = DiffD2 [Transfer.transferred] lemmas fminusE[elim!] = DiffE[Transfer.transferred] lemmas finsert-iff [simp] = insert-iff [Transfer.transferred] lemmas finsertI1 = insertI1 [Transfer.transferred] lemmas finsertI2 = insertI2 [Transfer.transferred] lemmas finsertE[elim!] = insertE[Transfer.transferred] lemmas finsertCI [intro!] = insertCI [Transfer.transferred] lemmas fsubset-finsert-iff = subset-insert-iff [Transfer.transferred] lemmas finsert-ident = insert-ident[Transfer.transferred] lemmas fsingletonI [intro!,no-atp] = singletonI [Transfer.transferred] lemmas fsingletonD[dest!,no-atp] = singletonD[Transfer.transferred] lemmas fsingleton-iff = singleton-iff [Transfer.transferred] lemmas fsingleton-inject[dest!] = singleton-inject[Transfer.transferred] lemmas fsingleton-finsert-inj-eq[iff ,no-atp] = singleton-insert-inj-eq[Transfer.transferred] lemmas fsingleton-finsert-inj-eq 0[iff ,no-atp] = singleton-insert-inj-eq 0[Transfer.transferred] lemmas fsubset-fsingletonD = subset-singletonD[Transfer.transferred] lemmas fminus-single-finsert = Diff-single-insert[Transfer.transferred] lemmas fdoubleton-eq-iff = doubleton-eq-iff [Transfer.transferred] lemmas funion-fsingleton-iff = Un-singleton-iff [Transfer.transferred] lemmas fsingleton-funion-iff = singleton-Un-iff [Transfer.transferred] lemmas fimage-eqI [simp, intro] = image-eqI [Transfer.transferred] lemmas fimageI = imageI [Transfer.transferred] lemmas rev-fimage-eqI = rev-image-eqI [Transfer.transferred] lemmas fimageE[elim!] = imageE[Transfer.transferred] lemmas Compr-fimage-eq = Compr-image-eq[Transfer.transferred] lemmas fimage-funion = image-Un[Transfer.transferred] lemmas fimage-iff = image-iff [Transfer.transferred] lemmas fimage-fsubset-iff [no-atp] = image-subset-iff [Transfer.transferred] lemmas fimage-fsubsetI = image-subsetI [Transfer.transferred] lemmas fimage-ident[simp] = image-ident[Transfer.transferred] lemmas if-split-fmem1 = if-split-mem1 [Transfer.transferred] lemmas if-split-fmem2 = if-split-mem2 [Transfer.transferred] 376 lemmas pfsubsetI [intro!,no-atp] = psubsetI [Transfer.transferred] lemmas pfsubsetE[elim!,no-atp] = psubsetE[Transfer.transferred] lemmas pfsubset-finsert-iff = psubset-insert-iff [Transfer.transferred] lemmas pfsubset-eq = psubset-eq[Transfer.transferred] lemmas pfsubset-imp-fsubset = psubset-imp-subset[Transfer.transferred] lemmas pfsubset-trans = psubset-trans[Transfer.transferred] lemmas pfsubsetD = psubsetD[Transfer.transferred] lemmas pfsubset-fsubset-trans = psubset-subset-trans[Transfer.transferred] lemmas fsubset-pfsubset-trans = subset-psubset-trans[Transfer.transferred] lemmas pfsubset-imp-ex-fmem = psubset-imp-ex-mem[Transfer.transferred] lemmas fimage-fPow-mono = image-Pow-mono[Transfer.transferred] lemmas fimage-fPow-surj = image-Pow-surj [Transfer.transferred] lemmas fsubset-finsertI = subset-insertI [Transfer.transferred] lemmas fsubset-finsertI2 = subset-insertI2 [Transfer.transferred] lemmas fsubset-finsert = subset-insert[Transfer.transferred] lemmas funion-upper1 = Un-upper1 [Transfer.transferred] lemmas funion-upper2 = Un-upper2 [Transfer.transferred] lemmas funion-least = Un-least[Transfer.transferred] lemmas finter-lower1 = Int-lower1 [Transfer.transferred] lemmas finter-lower2 = Int-lower2 [Transfer.transferred] lemmas finter-greatest = Int-greatest[Transfer.transferred] lemmas fminus-fsubset = Diff-subset[Transfer.transferred] lemmas fminus-fsubset-conv = Diff-subset-conv[Transfer.transferred] lemmas fsubset-fempty[simp] = subset-empty[Transfer.transferred] lemmas not-pfsubset-fempty[iff ] = not-psubset-empty[Transfer.transferred] lemmas finsert-is-funion = insert-is-Un[Transfer.transferred] lemmas finsert-not-fempty[simp] = insert-not-empty[Transfer.transferred] lemmas fempty-not-finsert = empty-not-insert[Transfer.transferred] lemmas finsert-absorb = insert-absorb[Transfer.transferred] lemmas finsert-absorb2 [simp] = insert-absorb2 [Transfer.transferred] lemmas finsert-commute = insert-commute[Transfer.transferred] lemmas finsert-fsubset[simp] = insert-subset[Transfer.transferred] lemmas finsert-inter-finsert[simp] = insert-inter-insert[Transfer.transferred] lemmas finsert-disjoint[simp,no-atp] = insert-disjoint[Transfer.transferred] lemmas disjoint-finsert[simp,no-atp] = disjoint-insert[Transfer.transferred] lemmas fimage-fempty[simp] = image-empty[Transfer.transferred] lemmas fimage-finsert[simp] = image-insert[Transfer.transferred] lemmas fimage-constant = image-constant[Transfer.transferred] lemmas fimage-constant-conv = image-constant-conv[Transfer.transferred] lemmas fimage-fimage = image-image[Transfer.transferred] lemmas finsert-fimage[simp] = insert-image[Transfer.transferred] lemmas fimage-is-fempty[iff ] = image-is-empty[Transfer.transferred] lemmas fempty-is-fimage[iff ] = empty-is-image[Transfer.transferred] lemmas fimage-cong = image-cong[Transfer.transferred] lemmas fimage-finter-fsubset = image-Int-subset[Transfer.transferred] lemmas fimage-fminus-fsubset = image-diff-subset[Transfer.transferred] lemmas finter-absorb = Int-absorb[Transfer.transferred] lemmas finter-left-absorb = Int-left-absorb[Transfer.transferred] lemmas finter-commute = Int-commute[Transfer.transferred] 377 lemmas finter-left-commute = Int-left-commute[Transfer.transferred] lemmas finter-assoc = Int-assoc[Transfer.transferred] lemmas finter-ac = Int-ac[Transfer.transferred] lemmas finter-absorb1 = Int-absorb1 [Transfer.transferred] lemmas finter-absorb2 = Int-absorb2 [Transfer.transferred] lemmas finter-fempty-left = Int-empty-left[Transfer.transferred] lemmas finter-fempty-right = Int-empty-right[Transfer.transferred] lemmas disjoint-iff-fnot-equal = disjoint-iff-not-equal[Transfer.transferred] lemmas finter-funion-distrib = Int-Un-distrib[Transfer.transferred] lemmas finter-funion-distrib2 = Int-Un-distrib2 [Transfer.transferred] lemmas finter-fsubset-iff [no-atp, simp] = Int-subset-iff [Transfer.transferred] lemmas funion-absorb = Un-absorb[Transfer.transferred] lemmas funion-left-absorb = Un-left-absorb[Transfer.transferred] lemmas funion-commute = Un-commute[Transfer.transferred] lemmas funion-left-commute = Un-left-commute[Transfer.transferred] lemmas funion-assoc = Un-assoc[Transfer.transferred] lemmas funion-ac = Un-ac[Transfer.transferred] lemmas funion-absorb1 = Un-absorb1 [Transfer.transferred] lemmas funion-absorb2 = Un-absorb2 [Transfer.transferred] lemmas funion-fempty-left = Un-empty-left[Transfer.transferred] lemmas funion-fempty-right = Un-empty-right[Transfer.transferred] lemmas funion-finsert-left[simp] = Un-insert-left[Transfer.transferred] lemmas funion-finsert-right[simp] = Un-insert-right[Transfer.transferred] lemmas finter-finsert-left = Int-insert-left[Transfer.transferred] lemmas finter-finsert-left-ifffempty[simp] = Int-insert-left-if0 [Transfer.transferred] lemmas finter-finsert-left-if1 [simp] = Int-insert-left-if1 [Transfer.transferred] lemmas finter-finsert-right = Int-insert-right[Transfer.transferred] lemmas finter-finsert-right-ifffempty[simp] = Int-insert-right-if0 [Transfer.transferred] lemmas finter-finsert-right-if1 [simp] = Int-insert-right-if1 [Transfer.transferred] lemmas funion-finter-distrib = Un-Int-distrib[Transfer.transferred] lemmas funion-finter-distrib2 = Un-Int-distrib2 [Transfer.transferred] lemmas funion-finter-crazy = Un-Int-crazy[Transfer.transferred] lemmas fsubset-funion-eq = subset-Un-eq[Transfer.transferred] lemmas funion-fempty[iff ] = Un-empty[Transfer.transferred] lemmas funion-fsubset-iff [no-atp, simp] = Un-subset-iff [Transfer.transferred] lemmas funion-fminus-finter = Un-Diff-Int[Transfer.transferred] lemmas fminus-finter2 = Diff-Int2 [Transfer.transferred] lemmas funion-finter-assoc-eq = Un-Int-assoc-eq[Transfer.transferred] lemmas fBall-funion = ball-Un[Transfer.transferred] lemmas fBex-funion = bex-Un[Transfer.transferred] lemmas fminus-eq-fempty-iff [simp,no-atp] = Diff-eq-empty-iff [Transfer.transferred] lemmas fminus-cancel[simp] = Diff-cancel[Transfer.transferred] lemmas fminus-idemp[simp] = Diff-idemp[Transfer.transferred] lemmas fminus-triv = Diff-triv[Transfer.transferred] lemmas fempty-fminus[simp] = empty-Diff [Transfer.transferred] lemmas fminus-fempty[simp] = Diff-empty[Transfer.transferred] lemmas fminus-finsertffempty[simp,no-atp] = Diff-insert0 [Transfer.transferred] lemmas fminus-finsert = Diff-insert[Transfer.transferred] lemmas fminus-finsert2 = Diff-insert2 [Transfer.transferred] 378 lemmas finsert-fminus-if = insert-Diff-if [Transfer.transferred] lemmas finsert-fminus1 [simp] = insert-Diff1 [Transfer.transferred] lemmas finsert-fminus-single[simp] = insert-Diff-single[Transfer.transferred] lemmas finsert-fminus = insert-Diff [Transfer.transferred] lemmas fminus-finsert-absorb = Diff-insert-absorb[Transfer.transferred] lemmas fminus-disjoint[simp] = Diff-disjoint[Transfer.transferred] lemmas fminus-partition = Diff-partition[Transfer.transferred] lemmas double-fminus = double-diff [Transfer.transferred] lemmas funion-fminus-cancel[simp] = Un-Diff-cancel[Transfer.transferred] lemmas funion-fminus-cancel2 [simp] = Un-Diff-cancel2 [Transfer.transferred] lemmas fminus-funion = Diff-Un[Transfer.transferred] lemmas fminus-finter = Diff-Int[Transfer.transferred] lemmas funion-fminus = Un-Diff [Transfer.transferred] lemmas finter-fminus = Int-Diff [Transfer.transferred] lemmas fminus-finter-distrib = Diff-Int-distrib[Transfer.transferred] lemmas fminus-finter-distrib2 = Diff-Int-distrib2 [Transfer.transferred] lemmas fUNIV-bool[no-atp] = UNIV-bool[Transfer.transferred] lemmas fPow-fempty[simp] = Pow-empty[Transfer.transferred] lemmas fPow-finsert = Pow-insert[Transfer.transferred] lemmas funion-fPow-fsubset = Un-Pow-subset[Transfer.transferred] lemmas fPow-finter-eq[simp] = Pow-Int-eq[Transfer.transferred] lemmas fset-eq-fsubset = set-eq-subset[Transfer.transferred] lemmas fsubset-iff [no-atp] = subset-iff [Transfer.transferred] lemmas fsubset-iff-pfsubset-eq = subset-iff-psubset-eq[Transfer.transferred] lemmas all-not-fin-conv[simp] = all-not-in-conv[Transfer.transferred] lemmas ex-fin-conv = ex-in-conv[Transfer.transferred] lemmas fimage-mono = image-mono[Transfer.transferred] lemmas fPow-mono = Pow-mono[Transfer.transferred] lemmas finsert-mono = insert-mono[Transfer.transferred] lemmas funion-mono = Un-mono[Transfer.transferred] lemmas finter-mono = Int-mono[Transfer.transferred] lemmas fminus-mono = Diff-mono[Transfer.transferred] lemmas fin-mono = in-mono[Transfer.transferred] lemmas fthe-felem-eq[simp] = the-elem-eq[Transfer.transferred] lemmas fLeast-mono = Least-mono[Transfer.transferred] lemmas fbind-fbind = bind-bind[Transfer.transferred] lemmas fempty-fbind[simp] = empty-bind[Transfer.transferred] lemmas nonfempty-fbind-const = nonempty-bind-const[Transfer.transferred] lemmas fbind-const = bind-const[Transfer.transferred] lemmas ffmember-filter[simp] = member-filter[Transfer.transferred] lemmas fequalityI = equalityI [Transfer.transferred] lemmas fset-of-list-simps[simp] = set-simps[Transfer.transferred] lemmas fset-of-list-append[simp] = set-append[Transfer.transferred] lemmas fset-of-list-rev[simp] = set-rev[Transfer.transferred] lemmas fset-of-list-map[simp] = set-map[Transfer.transferred] 379 51.5 Additional lemmas 51.5.1 fsingleton lemmas fsingletonE = fsingletonD [elim-format] 51.5.2 femepty lemma fempty-ffilter[simp]: ffilter (λ-. False) A = {||} by transfer auto lemma femptyE [elim!]: a |∈| {||} =⇒ P by simp 51.5.3 fset lemmas fset-simps[simp] = bot-fset.rep-eq finsert.rep-eq lemma finite-fset [simp]: shows finite (fset S) by transfer simp lemmas fset-cong = fset-inject lemma filter-fset [simp]: shows fset (ffilter P xs) = Collect P ∩ fset xs by transfer auto lemma notin-fset: x |∈|/ S ←→ x ∈/ fset S by (simp add: fmember.rep-eq) lemmas inter-fset[simp] = inf-fset.rep-eq lemmas union-fset[simp] = sup-fset.rep-eq lemmas minus-fset[simp] = minus-fset.rep-eq 51.5.4 ffilter lemma subset-ffilter: ffilter P A |⊆| ffilter Q A = (∀ x. x |∈| A −→ P x −→ Q x) by transfer auto lemma eq-ffilter: (ffilter P A = ffilter Q A) = (∀ x. x |∈| A −→ P x = Q x) by transfer auto lemma pfsubset-ffilter: (Vx. x |∈| A =⇒ P x =⇒ Q x) =⇒ (x |∈| A & ¬ P x & Q x) =⇒ ffilter P A |⊂| ffilter Q A unfolding less-fset-def by (auto simp add: subset-ffilter eq-ffilter) 380 51.5.5 fset-of-list lemma fset-of-list-filter[simp]: fset-of-list (filter P xs) = ffilter P (fset-of-list xs) by transfer (auto simp: Set.filter-def ) lemma fset-of-list-subset[intro]: set xs ⊆ set ys =⇒ fset-of-list xs |⊆| fset-of-list ys by transfer simp lemma fset-of-list-elem:(x |∈| fset-of-list xs) ←→ (x ∈ set xs) by transfer simp 51.5.6 finsert lemma set-finsert: assumes x |∈| A obtains B where A = finsert x B and x |∈|/ B using assms by transfer (metis Set.set-insert finite-insert) lemma mk-disjoint-finsert: a |∈| A =⇒ ∃ B. A = finsert a B ∧ a |∈|/ B by (rule exI [where x = A |−| {|a|}]) blast 51.5.7 fimage lemma subset-fimage-iff :(B |⊆| f |‘|A) = (∃ AA. AA |⊆| A ∧ B = f |‘|AA) by transfer (metis mem-Collect-eq rev-finite-subset subset-image-iff ) 51.5.8 bounded quantification lemma bex-simps [simp, no-atp]: VAPQ. fBex A (λx. P x ∧ Q) = (fBex A P ∧ Q) VAPQ. fBex A (λx. P ∧ Q x) = (P ∧ fBex A Q) VP. fBex {||} P = False Va B P. fBex (finsert a B) P = (P a ∨ fBex B P) VA P f . fBex (f |‘| A) P = fBex A (λx. P (f x)) VAP. (¬ fBex A P) = fBall A (λx. ¬ P x) by auto lemma ball-simps [simp, no-atp]: VAPQ. fBall A (λx. P x ∨ Q) = (fBall A P ∨ Q) VAPQ. fBall A (λx. P ∨ Q x) = (P ∨ fBall A Q) VAPQ. fBall A (λx. P −→ Q x) = (P −→ fBall A Q) VAPQ. fBall A (λx. P x −→ Q) = (fBex A P −→ Q) VP. fBall {||} P = True Va B P. fBall (finsert a B) P = (P a ∧ fBall B P) VA P f . fBall (f |‘| A) P = fBall A (λx. P (f x)) VAP. (¬ fBall A P) = fBex A (λx. ¬ P x) by auto 381 lemma atomize-fBall: (Vx. x |∈| A ==> P x) == Trueprop (fBall A (λx. P x)) apply (simp only: atomize-all atomize-imp) apply (rule equal-intr-rule) by (transfer, simp)+ lemma fBall-mono[mono]: P ≤ Q =⇒ fBall S P ≤ fBall S Q by auto end 51.5.9 fcard lemma fcard-fempty: fcard {||} = 0 by transfer (rule card-empty) lemma fcard-finsert-disjoint: x |∈|/ A =⇒ fcard (finsert x A) = Suc (fcard A) by transfer (rule card-insert-disjoint) lemma fcard-finsert-if : fcard (finsert x A) = (if x |∈| A then fcard A else Suc (fcard A)) by transfer (rule card-insert-if ) lemma card-0-eq [simp, no-atp]: fcard A = 0 ←→ A = {||} by transfer (rule card-0-eq) lemma fcard-Suc-fminus1 : x |∈| A =⇒ Suc (fcard (A |−| {|x|})) = fcard A by transfer (rule card-Suc-Diff1 ) lemma fcard-fminus-fsingleton: x |∈| A =⇒ fcard (A |−| {|x|}) = fcard A − 1 by transfer (rule card-Diff-singleton) lemma fcard-fminus-fsingleton-if : fcard (A |−| {|x|}) = (if x |∈| A then fcard A − 1 else fcard A) by transfer (rule card-Diff-singleton-if ) lemma fcard-fminus-finsert[simp]: assumes a |∈| A and a |∈|/ B shows fcard (A |−| finsert a B) = fcard (A |−| B) − 1 using assms by transfer (rule card-Diff-insert) lemma fcard-finsert: fcard (finsert x A) = Suc (fcard (A |−| {|x|})) by transfer (rule card-insert) 382 lemma fcard-finsert-le: fcard A ≤ fcard (finsert x A) by transfer (rule card-insert-le) lemma fcard-mono: A |⊆| B =⇒ fcard A ≤ fcard B by transfer (rule card-mono) lemma fcard-seteq: A |⊆| B =⇒ fcard B ≤ fcard A =⇒ A = B by transfer (rule card-seteq) lemma pfsubset-fcard-mono: A |⊂| B =⇒ fcard A < fcard B by transfer (rule psubset-card-mono) lemma fcard-funion-finter: fcard A + fcard B = fcard (A |∪| B) + fcard (A |∩| B) by transfer (rule card-Un-Int) lemma fcard-funion-disjoint: A |∩| B = {||} =⇒ fcard (A |∪| B) = fcard A + fcard B by transfer (rule card-Un-disjoint) lemma fcard-funion-fsubset: B |⊆| A =⇒ fcard (A |−| B) = fcard A − fcard B by transfer (rule card-Diff-subset) lemma diff-fcard-le-fcard-fminus: fcard A − fcard B ≤ fcard(A |−| B) by transfer (rule diff-card-le-card-Diff ) lemma fcard-fminus1-less: x |∈| A =⇒ fcard (A |−| {|x|}) < fcard A by transfer (rule card-Diff1-less) lemma fcard-fminus2-less: x |∈| A =⇒ y |∈| A =⇒ fcard (A |−| {|x|} |−| {|y|}) < fcard A by transfer (rule card-Diff2-less) lemma fcard-fminus1-le: fcard (A |−| {|x|}) ≤ fcard A by transfer (rule card-Diff1-le) lemma fcard-pfsubset: A |⊆| B =⇒ fcard A < fcard B =⇒ A < B by transfer (rule card-psubset) 51.5.10 ffold context comp-fun-commute begin lemmas ffold-empty[simp] = fold-empty[Transfer.transferred] 383 lemma ffold-finsert [simp]: assumes x |∈|/ A shows ffold f z (finsert x A) = f x (ffold f z A) using assms by (transfer fixing: f )(rule fold-insert) lemma ffold-fun-left-comm: f x (ffold f z A) = ffold f (f x z) A by (transfer fixing: f )(rule fold-fun-left-comm) lemma ffold-finsert2 : x |∈|/ A =⇒ ffold f z (finsert x A) = ffold f (f x z) A by (transfer fixing: f )(rule fold-insert2 ) lemma ffold-rec: assumes x |∈| A shows ffold f z A = f x (ffold f z (A |−| {|x|})) using assms by (transfer fixing: f )(rule fold-rec) lemma ffold-finsert-fremove: ffold f z (finsert x A) = f x (ffold f z (A |−| {|x|})) by (transfer fixing: f )(rule fold-insert-remove) end lemma ffold-fimage: assumes inj-on g (fset A) shows ffold f z (g |‘| A) = ffold (f ◦ g) z A using assms by transfer 0 (rule fold-image) lemma ffold-cong: assumes comp-fun-commute f comp-fun-commute g Vx. x |∈| A =⇒ f x = g x and s = t and A = B shows ffold f s A = ffold g t B using assms by transfer (metis Finite-Set.fold-cong) context comp-fun-idem begin lemma ffold-finsert-idem: ffold f z (finsert x A) = f x (ffold f z A) by (transfer fixing: f )(rule fold-insert-idem) declare ffold-finsert [simp del] ffold-finsert-idem [simp] lemma ffold-finsert-idem2 : ffold f z (finsert x A) = ffold f (f x z) A by (transfer fixing: f )(rule fold-insert-idem2 ) end 384 51.6 Choice in fsets lemma fset-choice: assumes ∀ x. x |∈| A −→ (∃ y. P x y) shows ∃ f . ∀ x. x |∈| A −→ P x (f x) using assms by transfer metis 51.7 Induction and Cases rules for fsets lemma fset-exhaust [case-names empty insert, cases type: fset]: assumes fempty-case: S = {||} =⇒ P and finsert-case: Vx S 0. S = finsert x S 0 =⇒ P shows P using assms by transfer blast lemma fset-induct [case-names empty insert]: assumes fempty-case: P {||} and finsert-case: Vx S. PS =⇒ P (finsert x S) shows PS proof − note Domainp-forall-transfer[transfer-rule] show ?thesis using assms by transfer (auto intro: finite-induct) qed lemma fset-induct-stronger [case-names empty insert, induct type: fset]: assumes empty-fset-case: P {||} and insert-fset-case: Vx S. [[x |∈|/ S; PS]] =⇒ P (finsert x S) shows PS proof − note Domainp-forall-transfer[transfer-rule] show ?thesis using assms by transfer (auto intro: finite-induct) qed lemma fset-card-induct: assumes empty-fset-case: P {||} and card-fset-Suc-case: VST . Suc (fcard S) = (fcard T ) =⇒ PS =⇒ PT shows PS proof (induct S) case empty show P {||} by (rule empty-fset-case) next case (insert x S) have h: PS by fact have x |∈|/ S by fact then have Suc (fcard S) = fcard (finsert x S) by transfer auto 385 then show P (finsert x S) using h card-fset-Suc-case by simp qed lemma fset-strong-cases: obtains xs = {||} | ys x where x |∈|/ ys and xs = finsert x ys by transfer blast lemma fset-induct2 : P {||} {||} =⇒ (Vx xs. x |∈|/ xs =⇒ P (finsert x xs) {||}) =⇒ (Vy ys. y |∈|/ ys =⇒ P {||} (finsert y ys)) =⇒ (Vx xs y ys. [[P xs ys; x |∈|/ xs; y |∈|/ ys]] =⇒ P (finsert x xs)(finsert y ys)) =⇒ P xsa ysa apply (induct xsa arbitrary: ysa) apply (induct-tac x rule: fset-induct-stronger) apply simp-all apply (induct-tac xa rule: fset-induct-stronger) apply simp-all done 51.8 Setup for Lifting/Transfer 51.8.1 Relator and predicator properties lift-definition rel-fset :: ( 0a ⇒ 0b ⇒ bool) ⇒ 0a fset ⇒ 0b fset ⇒ bool is rel-set parametric rel-set-transfer . lemma rel-fset-alt-def : rel-fset R = (λAB. (∀ x.∃ y. x|∈|A −→ y|∈|B ∧ R x y) ∧ (∀ y. ∃ x. y|∈|B −→ x|∈|A ∧ R x y)) apply (rule ext)+ apply transfer 0 apply (subst rel-set-def [unfolded fun-eq-iff ]) by blast lemma finite-rel-set: assumes fin: finite X finite Z assumes R-S: rel-set (R OO S) XZ shows ∃ Y . finite Y ∧ rel-set R X Y ∧ rel-set S Y Z proof − obtain f where f : ∀ x∈X . R x (f x) ∧ (∃ z∈Z . S (f x) z) apply atomize-elim apply (subst bchoice-iff [symmetric]) using R-S[unfolded rel-set-def OO-def ] by blast obtain g where g: ∀ z∈Z . S (g z) z ∧ (∃ x∈X . R x (g z)) apply atomize-elim apply (subst bchoice-iff [symmetric]) using R-S[unfolded rel-set-def OO-def ] by blast 386 let ?Y = f ‘ X ∪ g ‘ Z have finite ?Y by (simp add: fin) moreover have rel-set R X ?Y unfolding rel-set-def using f g by clarsimp blast moreover have rel-set S ?Y Z unfolding rel-set-def using f g by clarsimp blast ultimately show ?thesis by metis qed 51.8.2 Transfer rules for the Transfer package Unconditional transfer rules context includes lifting-syntax begin lemmas fempty-transfer [transfer-rule] = empty-transfer[Transfer.transferred] lemma finsert-transfer [transfer-rule]: (A ===> rel-fset A ===> rel-fset A) finsert finsert unfolding rel-fun-def rel-fset-alt-def by blast lemma funion-transfer [transfer-rule]: (rel-fset A ===> rel-fset A ===> rel-fset A) funion funion unfolding rel-fun-def rel-fset-alt-def by blast lemma ffUnion-transfer [transfer-rule]: (rel-fset (rel-fset A) ===> rel-fset A) ffUnion ffUnion unfolding rel-fun-def rel-fset-alt-def by transfer (simp, fast) lemma fimage-transfer [transfer-rule]: ((A ===> B) ===> rel-fset A ===> rel-fset B) fimage fimage unfolding rel-fun-def rel-fset-alt-def by simp blast lemma fBall-transfer [transfer-rule]: (rel-fset A ===> (A ===> op =) ===> op =) fBall fBall unfolding rel-fset-alt-def rel-fun-def by blast lemma fBex-transfer [transfer-rule]: (rel-fset A ===> (A ===> op =) ===> op =) fBex fBex unfolding rel-fset-alt-def rel-fun-def by blast lemma fPow-transfer [transfer-rule]: (rel-fset A ===> rel-fset (rel-fset A)) fPow fPow unfolding rel-fun-def using Pow-transfer[unfolded rel-fun-def , rule-format, Transfer.transferred] 387 by blast lemma rel-fset-transfer [transfer-rule]: ((A ===> B ===> op =) ===> rel-fset A ===> rel-fset B ===> op =) rel-fset rel-fset unfolding rel-fun-def using rel-set-transfer[unfolded rel-fun-def ,rule-format, Transfer.transferred, where A = A and B = B] by simp lemma bind-transfer [transfer-rule]: (rel-fset A ===> (A ===> rel-fset B) ===> rel-fset B) fbind fbind unfolding rel-fun-def using bind-transfer[unfolded rel-fun-def , rule-format, Transfer.transferred] by blast Rules requiring bi-unique, bi-total or right-total relations lemma fmember-transfer [transfer-rule]: assumes bi-unique A shows (A ===> rel-fset A ===> op =) (op |∈|)(op |∈|) using assms unfolding rel-fun-def rel-fset-alt-def bi-unique-def by metis lemma finter-transfer [transfer-rule]: assumes bi-unique A shows (rel-fset A ===> rel-fset A ===> rel-fset A) finter finter using assms unfolding rel-fun-def using inter-transfer[unfolded rel-fun-def , rule-format, Transfer.transferred] by blast lemma fminus-transfer [transfer-rule]: assumes bi-unique A shows (rel-fset A ===> rel-fset A ===> rel-fset A)(op |−|)(op |−|) using assms unfolding rel-fun-def using Diff-transfer[unfolded rel-fun-def , rule-format, Transfer.transferred] by blast lemma fsubset-transfer [transfer-rule]: assumes bi-unique A shows (rel-fset A ===> rel-fset A ===> op =) (op |⊆|)(op |⊆|) using assms unfolding rel-fun-def using subset-transfer[unfolded rel-fun-def , rule-format, Transfer.transferred] by blast lemma fSup-transfer [transfer-rule]: bi-unique A =⇒ (rel-set (rel-fset A) ===> rel-fset A) Sup Sup unfolding rel-fun-def apply clarify apply transfer 0 using Sup-fset-transfer[unfolded rel-fun-def ] by blast 388 lemma fInf-transfer [transfer-rule]: assumes bi-unique A and bi-total A shows (rel-set (rel-fset A) ===> rel-fset A) Inf Inf using assms unfolding rel-fun-def apply clarify apply transfer 0 using Inf-fset-transfer[unfolded rel-fun-def ] by blast lemma ffilter-transfer [transfer-rule]: assumes bi-unique A shows ((A ===> op=) ===> rel-fset A ===> rel-fset A) ffilter ffilter using assms unfolding rel-fun-def using Lifting-Set.filter-transfer[unfolded rel-fun-def , rule-format, Transfer.transferred] by blast lemma card-transfer [transfer-rule]: bi-unique A =⇒ (rel-fset A ===> op =) fcard fcard unfolding rel-fun-def using card-transfer[unfolded rel-fun-def , rule-format, Transfer.transferred] by blast end lifting-update fset.lifting lifting-forget fset.lifting 51.9 BNF setup context includes fset.lifting begin lemma rel-fset-alt: rel-fset R a b ←→ (∀ t ∈ fset a. ∃ u ∈ fset b. R t u) ∧ (∀ t ∈ fset b. ∃ u ∈ fset a. R u t) by transfer (simp add: rel-set-def ) lemma fset-to-fset: finite A =⇒ fset (the-inv fset A) = A apply (rule f-the-inv-into-f [unfolded inj-on-def ]) apply (simp add: fset-inject) apply (rule range-eqI Abs-fset-inverse[symmetric] CollectI )+ . lemma rel-fset-aux: (∀ t ∈ fset a. ∃ u ∈ fset b. R t u) ∧ (∀ u ∈ fset b. ∃ t ∈ fset a. R t u) ←→ ((BNF-Def .Grp {a. fset a ⊆ {(a, b). R a b}} (fimage fst))−1−1 OO 389 BNF-Def .Grp {a. fset a ⊆ {(a, b). R a b}} (fimage snd)) a b (is ?L = ?R) proof assume ?L define R 0 where R 0 = the-inv fset (Collect (case-prod R) ∩ (fset a × fset b)) (is - = the-inv fset ?L 0) have finite ?L 0 by (intro finite-Int[OF disjI2 ] finite-cartesian-product)(transfer, simp)+ hence ∗: fset R 0 = ?L 0 unfolding R 0-def by (intro fset-to-fset) show ?R unfolding Grp-def relcompp.simps conversep.simps proof (intro CollectI case-prodI exI [of - a] exI [of - b] exI [of - R 0] conjI refl) 0 from ∗ show a = fimage fst R using conjunct1 [OF h?Li] by (transfer, auto simp add: image-def Int-def split: prod.splits) 0 from ∗ show b = fimage snd R using conjunct2 [OF h?Li] by (transfer, auto simp add: image-def Int-def split: prod.splits) qed (auto simp add: ∗) next assume ?R thus ?L unfolding Grp-def relcompp.simps conversep.simps apply (simp add: subset-eq Ball-def ) apply (rule conjI ) apply (transfer, clarsimp, metis snd-conv) by (transfer, clarsimp, metis fst-conv) qed bnf 0a fset map: fimage sets: fset bd: natLeq wits: {||} rel: rel-fset apply − apply transfer 0 apply simp apply transfer 0 apply force apply transfer apply force apply transfer 0 apply force apply (rule natLeq-card-order) apply (rule natLeq-cinfinite) apply transfer apply (metis ordLess-imp-ordLeq finite-iff-ordLess-natLeq) apply (fastforce simp: rel-fset-alt) apply (simp add: Grp-def relcompp.simps conversep.simps fun-eq-iff rel-fset-alt rel-fset-aux[unfolded OO-Grp-alt]) apply transfer apply simp done lemma rel-fset-fset: rel-set χ (fset A1 )(fset A2 ) = rel-fset χ A1 A2 by transfer (rule refl) end lemmas [simp] = fset.map-comp fset.map-id fset.set-map 390 51.10 Size setup context includes fset.lifting begin lift-definition size-fset :: ( 0a ⇒ nat) ⇒ 0a fset ⇒ nat is λf . sum (Suc ◦ f ) . end instantiation fset :: (type) size begin definition size-fset where size-fset-overloaded-def : size-fset = FSet.size-fset (λ-. 0 ) instance .. end lemmas size-fset-simps[simp] = size-fset-def [THEN meta-eq-to-obj-eq, THEN fun-cong, THEN fun-cong, unfolded map-fun-def comp-def id-apply] lemmas size-fset-overloaded-simps[simp] = size-fset-simps[of λ-. 0 , unfolded add-0-left add-0-right, folded size-fset-overloaded-def ] lemma fset-size-o-map: inj f =⇒ size-fset g ◦ fimage f = size-fset (g ◦ f ) apply (subst fun-eq-iff ) including fset.lifting by transfer (auto intro: sum.reindex-cong subset-inj-on) setup h BNF-LFP-Size.register-size-global @{type-name fset} @{const-name size-fset} @{thm size-fset-overloaded-def } @{thms size-fset-simps size-fset-overloaded-simps} @{thms fset-size-o-map} i lifting-update fset.lifting lifting-forget fset.lifting 51.11 Advanced relator customization lemma rel-set-rel-sum[simp]: rel-set (rel-sum χ ϕ) A1 A2 ←→ rel-set χ (Inl −‘ A1 )(Inl −‘ A2 ) ∧ rel-set ϕ (Inr −‘ A1 )(Inr −‘ A2 ) (is ?L ←→ ?Rl ∧ ?Rr) proof safe assume L: ?L show ?Rl unfolding rel-set-def Bex-def vimage-eq proof safe fix l1 assume Inl l1 ∈ A1 then obtain a2 where a2 : a2 ∈ A2 and rel-sum χ ϕ (Inl l1 ) a2 using L unfolding rel-set-def by auto then obtain l2 where a2 = Inl l2 ∧ χ l1 l2 by (cases a2 , auto) thus ∃ l2 . Inl l2 ∈ A2 ∧ χ l1 l2 using a2 by auto next fix l2 assume Inl l2 ∈ A2 then obtain a1 where a1 : a1 ∈ A1 and rel-sum χ ϕ a1 (Inl l2 ) 391 using L unfolding rel-set-def by auto then obtain l1 where a1 = Inl l1 ∧ χ l1 l2 by (cases a1 , auto) thus ∃ l1 . Inl l1 ∈ A1 ∧ χ l1 l2 using a1 by auto qed show ?Rr unfolding rel-set-def Bex-def vimage-eq proof safe fix r1 assume Inr r1 ∈ A1 then obtain a2 where a2 : a2 ∈ A2 and rel-sum χ ϕ (Inr r1 ) a2 using L unfolding rel-set-def by auto then obtain r2 where a2 = Inr r2 ∧ ϕ r1 r2 by (cases a2 , auto) thus ∃ r2 . Inr r2 ∈ A2 ∧ ϕ r1 r2 using a2 by auto next fix r2 assume Inr r2 ∈ A2 then obtain a1 where a1 : a1 ∈ A1 and rel-sum χ ϕ a1 (Inr r2 ) using L unfolding rel-set-def by auto then obtain r1 where a1 = Inr r1 ∧ ϕ r1 r2 by (cases a1 , auto) thus ∃ r1 . Inr r1 ∈ A1 ∧ ϕ r1 r2 using a1 by auto qed next assume Rl: ?Rl and Rr: ?Rr show ?L unfolding rel-set-def Bex-def vimage-eq proof safe fix a1 assume a1 : a1 ∈ A1 show ∃ a2 . a2 ∈ A2 ∧ rel-sum χ ϕ a1 a2 proof(cases a1 ) case (Inl l1 ) then obtain l2 where Inl l2 ∈ A2 ∧ χ l1 l2 using Rl a1 unfolding rel-set-def by blast thus ?thesis unfolding Inl by auto next case (Inr r1 ) then obtain r2 where Inr r2 ∈ A2 ∧ ϕ r1 r2 using Rr a1 unfolding rel-set-def by blast thus ?thesis unfolding Inr by auto qed next fix a2 assume a2 : a2 ∈ A2 show ∃ a1 . a1 ∈ A1 ∧ rel-sum χ ϕ a1 a2 proof(cases a2 ) case (Inl l2 ) then obtain l1 where Inl l1 ∈ A1 ∧ χ l1 l2 using Rl a2 unfolding rel-set-def by blast thus ?thesis unfolding Inl by auto next case (Inr r2 ) then obtain r1 where Inr r1 ∈ A1 ∧ ϕ r1 r2 using Rr a2 unfolding rel-set-def by blast thus ?thesis unfolding Inr by auto qed qed qed 51.12 Quickcheck setup Setup adapted from sets. 392 notation Quickcheck-Exhaustive.orelse (infixr orelse 55 ) definition (in term-syntax)[code-unfold]: valterm-femptyset = Code-Evaluation.valtermify ({||} :: ( 0a :: typerep) fset) definition (in term-syntax)[code-unfold]: valtermify-finsert x s = Code-Evaluation.valtermify finsert {·} (x :: ( 0a :: typerep ∗ -)) {·} s instantiation fset :: (exhaustive) exhaustive begin fun exhaustive-fset where exhaustive-fset f i = (if i = 0 then None else (f {||} orelse exhaustive-fset (λA. f A orelse Quickcheck-Exhaustive.exhaustive (λx. if x |∈| A then None else f (finsert x A)) (i − 1 )) (i − 1 ))) instance .. end instantiation fset :: (full-exhaustive) full-exhaustive begin fun full-exhaustive-fset where full-exhaustive-fset f i = (if i = 0 then None else (f valterm-femptyset orelse full-exhaustive-fset (λA. f A orelse Quickcheck-Exhaustive.full-exhaustive (λx. if fst x |∈| fst A then None else f (valtermify-finsert x A)) (i − 1 )) (i − 1 ))) instance .. end no-notation Quickcheck-Exhaustive.orelse (infixr orelse 55 ) notation scomp (infixl ◦→ 60 ) instantiation fset :: (random) random begin fun random-aux-fset :: natural ⇒ natural ⇒ natural × natural ⇒ ( 0a fset × (unit ⇒ term)) × natural × natural where random-aux-fset 0 j = Quickcheck-Random.collapse (Random.select-weight [(1 , Pair valterm-femptyset)]) | random-aux-fset (Code-Numeral.Suc i) j = Quickcheck-Random.collapse (Random.select-weight [(1 , Pair valterm-femptyset), (Code-Numeral.Suc i, Quickcheck-Random.random j ◦→ (λx. random-aux-fset i j ◦→ (λs. Pair 393 (valtermify-finsert x s))))]) lemma [code]: random-aux-fset i j = Quickcheck-Random.collapse (Random.select-weight [(1 , Pair valterm-femptyset), (i, Quickcheck-Random.random j ◦→ (λx. random-aux-fset (i − 1 ) j ◦→ (λs. Pair (valtermify-finsert x s))))]) proof (induct i rule: natural.induct) case zero show ?case by (subst select-weight-drop-zero[symmetric]) (simp add: less-natural-def ) next case (Suc i) show ?case by (simp only: random-aux-fset.simps Suc-natural-minus-one) qed definition random-fset i = random-aux-fset i i instance .. end no-notation scomp (infixl ◦→ 60 ) end theory Transfer-Debug imports Main ∼∼/src/HOL/Library/FSet begin context includes fset.lifting begin 51.13 1. A missing transfer rule declare fmember.transfer[transfer-rule del] fmember-transfer[transfer-rule del] lemma (A |⊆| B) = fBall A (λx. x |∈| B) apply transfer oops lemma (A |⊆| B) = fBall A (λx. x |∈| B) apply transfer-start 394 apply transfer-step oops lemma [transfer-rule]: bi-unique A =⇒ rel-fun A (rel-fun (pcr-fset A) op =) op ∈ op |∈| by (rule fmember.transfer) lemma (A |⊆| B) = fBall A (λx. x |∈| B) apply transfer-start apply transfer-step apply transfer-step+ apply transfer-end by blast lemma (A |⊆| B) = fBall A (λx. x |∈| B) by transfer blast 51.14 2. Unwanted instantiation of a transfer relation vari- able lemma finite (UNIV :: 0a::finite fset set) apply transfer oops lemma finite (UNIV :: 0a::finite fset set) apply transfer-start apply transfer-step back back apply transfer-step apply transfer-end by auto lemma finite (UNIV :: 0a::finite fset set) proof − note right-total-UNIV-transfer[transfer-rule] show ?thesis by transfer auto qed end lifting-forget fset.lifting 395 declare fmember-transfer[transfer-rule] end 52 Using the transfer method between nat and int theory Transfer-Int-Nat imports GCD begin 52.1 Correspondence relation definition ZN :: int ⇒ nat ⇒ bool where ZN = (λz n. z = of-nat n) 52.2 Transfer domain rules lemma Domainp-ZN [transfer-domain-rule]: Domainp ZN = (λx. x ≥ 0 ) unfolding ZN-def Domainp-iff [abs-def ] by (auto intro: zero-le-imp-eq-int) 52.3 Transfer rules context includes lifting-syntax begin lemma bi-unique-ZN [transfer-rule]: bi-unique ZN unfolding ZN-def bi-unique-def by simp lemma right-total-ZN [transfer-rule]: right-total ZN unfolding ZN-def right-total-def by simp lemma ZN-0 [transfer-rule]: ZN 0 0 unfolding ZN-def by simp lemma ZN-1 [transfer-rule]: ZN 1 1 unfolding ZN-def by simp lemma ZN-add [transfer-rule]: (ZN ===> ZN ===> ZN )(op +) (op +) unfolding rel-fun-def ZN-def by simp lemma ZN-mult [transfer-rule]: (ZN ===> ZN ===> ZN )(op ∗)(op ∗) unfolding rel-fun-def ZN-def by (simp add: of-nat-mult) lemma ZN-diff [transfer-rule]: (ZN ===> ZN ===> ZN ) tsub (op −) unfolding rel-fun-def ZN-def tsub-def by (simp add: of-nat-diff ) lemma ZN-power [transfer-rule]: (ZN ===> op = ===> ZN )(op ˆ)(op ˆ) unfolding rel-fun-def ZN-def by (simp add: of-nat-power) 396 lemma ZN-nat-id [transfer-rule]: (ZN ===> op =) nat id unfolding rel-fun-def ZN-def by simp lemma ZN-id-int [transfer-rule]: (ZN ===> op =) id int unfolding rel-fun-def ZN-def by simp lemma ZN-All [transfer-rule]: ((ZN ===> op =) ===> op =) (Ball {0 ..}) All unfolding rel-fun-def ZN-def by (auto dest: zero-le-imp-eq-int) lemma ZN-transfer-forall [transfer-rule]: ((ZN ===> op =) ===> op =) (transfer-bforall (λx. 0 ≤ x)) transfer-forall unfolding transfer-forall-def transfer-bforall-def unfolding rel-fun-def ZN-def by (auto dest: zero-le-imp-eq-int) lemma ZN-Ex [transfer-rule]: ((ZN ===> op =) ===> op =) (Bex {0 ..}) Ex unfolding rel-fun-def ZN-def Bex-def atLeast-iff by (metis zero-le-imp-eq-int of-nat-0-le-iff ) lemma ZN-le [transfer-rule]: (ZN ===> ZN ===> op =) (op ≤)(op ≤) unfolding rel-fun-def ZN-def by simp lemma ZN-less [transfer-rule]: (ZN ===> ZN ===> op =) (op <)(op <) unfolding rel-fun-def ZN-def by simp lemma ZN-eq [transfer-rule]: (ZN ===> ZN ===> op =) (op =) (op =) unfolding rel-fun-def ZN-def by simp lemma ZN-Suc [transfer-rule]: (ZN ===> ZN )(λx. x + 1 ) Suc unfolding rel-fun-def ZN-def by simp lemma ZN-numeral [transfer-rule]: (op = ===> ZN ) numeral numeral unfolding rel-fun-def ZN-def by simp lemma ZN-dvd [transfer-rule]: (ZN ===> ZN ===> op =) (op dvd)(op dvd) unfolding rel-fun-def ZN-def by (simp add: zdvd-int) lemma ZN-div [transfer-rule]: (ZN ===> ZN ===> ZN )(op div)(op div) unfolding rel-fun-def ZN-def by (simp add: zdiv-int) lemma ZN-mod [transfer-rule]: (ZN ===> ZN ===> ZN )(op mod)(op mod) unfolding rel-fun-def ZN-def by (simp add: zmod-int) lemma ZN-gcd [transfer-rule]: (ZN ===> ZN ===> ZN ) gcd gcd unfolding rel-fun-def ZN-def by (simp add: transfer-int-nat-gcd) lemma ZN-atMost [transfer-rule]: (ZN ===> rel-set ZN )(atLeastAtMost 0 ) atMost 397 unfolding rel-fun-def ZN-def rel-set-def by (clarsimp simp add: Bex-def , arith) lemma ZN-atLeastAtMost [transfer-rule]: (ZN ===> ZN ===> rel-set ZN ) atLeastAtMost atLeastAtMost unfolding rel-fun-def ZN-def rel-set-def by (clarsimp simp add: Bex-def , arith) lemma ZN-sum [transfer-rule]: bi-unique A =⇒ ((A ===> ZN ) ===> rel-set A ===> ZN ) sum sum apply (intro rel-funI ) apply (erule (1 ) bi-unique-rel-set-lemma) apply (simp add: sum.reindex int-sum ZN-def rel-fun-def ) apply (rule sum.cong) apply simp-all done For derived operations, we can use the transfer-prover method to help gen- erate transfer rules. lemma ZN-sum-list [transfer-rule]: (list-all2 ZN ===> ZN ) sum-list sum-list by transfer-prover end 52.4 Transfer examples lemma assumes Vi::int. 0 ≤ i =⇒ i + 0 = i shows Vi::nat. i + 0 = i apply transfer apply fact done lemma assumes Vi k::int. [[0 ≤ i; 0 ≤ k; i < k]] =⇒ ∃ j ∈{0 ..}. i + j = k shows Vi k::nat. i < k =⇒ ∃ j . i + j = k apply transfer apply fact done lemma assumes ∀ x∈{0 ::int..}. ∀ y∈{0 ..}. x ∗ y div y = x shows ∀ x y :: nat. x ∗ y div y = x apply transfer apply fact done lemma assumes Vm n::int. [[0 ≤ m; 0 ≤ n; m ∗ n = 0 ]] =⇒ m = 0 ∨ n = 0 398 shows m ∗ n = (0 ::nat) =⇒ m = 0 ∨ n = 0 apply transfer apply fact done lemma assumes ∀ x∈{0 ::int..}. ∃ y∈{0 ..}. ∃ z∈{0 ..}. x + 3 ∗ y = 5 ∗ z shows ∀ x::nat. ∃ y z. x + 3 ∗ y = 5 ∗ z apply transfer apply fact done The fixing option prevents generalization over the free variable n, allowing the local transfer rule to be used. lemma assumes [transfer-rule]: ZN x n assumes ∀ i∈{0 ..}. i < x −→ 2 ∗ i < 3 ∗ x shows ∀ i. i < n −→ 2 ∗ i < 3 ∗ n apply (transfer fixing: n) apply fact done lemma assumes gcd (2ˆi)(3ˆj ) = (1 ::int) shows gcd (2ˆi)(3ˆj ) = (1 ::nat) apply (transfer fixing: i j ) apply fact done lemma assumes Vx y z::int. [[0 ≤ x; 0 ≤ y; 0 ≤ z]] =⇒ sum-list [x, y, z] = 0 ←→ list-all (λx. x = 0 )[x, y, z] shows sum-list [x, y, z] = (0 ::nat) ←→ list-all (λx. x = 0 )[x, y, z] apply transfer apply fact done Quantifiers over higher types (e.g. nat list) are transferred to a readable formula thanks to the transfer domain rule Domainp ZN = op ≤ 0 lemma assumes Vxs::int list. list-all (λx. x ≥ 0 ) xs =⇒ (sum-list xs = 0 ) = list-all (λx. x = 0 ) xs shows sum-list xs = (0 ::nat) ←→ list-all (λx. x = 0 ) xs apply transfer apply fact done Equality on a higher type can be transferred if the relations involved are bi-unique. 399 lemma assumes Vxs::int list. [[list-all (λx. x ≥ 0 ) xs; xs 6= []]] =⇒ sum-list xs < sum-list (map (λx. x + 1 ) xs) shows xs 6= [] =⇒ sum-list xs < sum-list (map Suc xs) apply transfer apply fact done end 53 Various examples for transfer procedure theory Transfer-Ex imports Main Transfer-Int-Nat begin lemma ex1 :(x::nat) + y = y + x by auto lemma 0 ≤ (y::int) =⇒ 0 ≤ (x::int) =⇒ x + y = y + x by (fact ex1 [transferred]) lemma 0 ≤ (x::int) =⇒ 0 ≤ (y::int) =⇒ x + y = y + x by (fact ex1 [untransferred]) lemma ex2 :(a::nat) div b ∗ b + a mod b = a by (rule div-mult-mod-eq) lemma 0 ≤ (b::int) =⇒ 0 ≤ (a::int) =⇒ a div b ∗ b + a mod b = a by (fact ex2 [transferred]) lemma 0 ≤ (a::int) =⇒ 0 ≤ (b::int) =⇒ a div b ∗ b + a mod b = a by (fact ex2 [untransferred]) lemma ex3 : ALL (x::nat). ALL y. EX z. z >= x + y by auto lemma ∀ x≥0 ::int. ∀ y≥0 . ∃ z≥0 . x + y ≤ z by (fact ex3 [transferred nat-int]) lemma ∀ x::int∈{0 ..}. ∀ y∈{0 ..}. ∃ z∈{0 ..}. x + y ≤ z by (fact ex3 [untransferred]) lemma ex4 :(x::nat) >= y =⇒ (x − y) + y = x by auto 400 lemma 0 ≤ (x::int) =⇒ 0 ≤ (y::int) =⇒ y ≤ x =⇒ tsub x y + y = x by (fact ex4 [transferred]) lemma 0 ≤ (y::int) =⇒ 0 ≤ (x::int) =⇒ y ≤ x =⇒ tsub x y + y = x by (fact ex4 [untransferred]) lemma ex5 :(2 ::nat) ∗ P {..n} = n ∗ (n + 1 ) by (induct n rule: nat-induct, auto) lemma 0 ≤ (n::int) =⇒ 2 ∗ P {0 ..n} = n ∗ (n + 1 ) by (fact ex5 [transferred]) lemma 0 ≤ (n::int) =⇒ 2 ∗ P {0 ..n} = n ∗ (n + 1 ) by (fact ex5 [untransferred]) lemma 0 ≤ (n::nat) =⇒ 2 ∗ P {0 ..n} = n ∗ (n + 1 ) by (fact ex5 [transferred, transferred]) lemma 0 ≤ (n::nat) =⇒ 2 ∗ P {..n} = n ∗ (n + 1 ) by (fact ex5 [untransferred, Transfer.transferred]) end 54 Simple example for table-based implementa- tion of the reflexive transitive closure theory Transitive-Closure-Table-Ex imports ∼∼/src/HOL/Library/Transitive-Closure-Table begin datatype ty = A | B | C inductive test :: ty ⇒ ty ⇒ bool where test A B | test B A | test B C Invoking with the predicate compiler and the generic code generator code-pred test . values {x. test ∗∗ AC } values {x. test ∗∗ CA} values {x. test ∗∗ A x} values {x. test ∗∗ x C } 401 value test ∗∗ AC value test ∗∗ CA end 55 Divergence of the Harmonic Series theory HarmonicSeries imports Complex-Main begin 55.1 Abstract The following document presents a proof of the Divergence of Harmonic Series theorem formalised in the Isabelle/Isar theorem proving system. P∞ 1 Theorem: The series n=1 n does not converge to any number. Informal Proof: The informal proof is based on the following auxillary lem- mas: P2m 1 1 • aux: n=2m−1 n ≥ 2 P2M 1 PM P2m 1 • aux2: n=1 n = 1 + m=1 n=2m−1 n P2M 1 M From aux and aux2 we can deduce that n=1 n ≥ 1 + 2 for all M. Now P∞ 1 1 for contradiction, assume that n=1 n = s for some s. Because ∀n. n > 0 all the partial sums in the series must be less than s. However with our P2N 1 deduction above we can choose N > 2 ∗ s − 2 and thus n=1 n > s. This P∞ 1 leads to a contradiction and hence n=1 n is not summable. QED. 55.2 Formal Proof lemma two-pow-sub: 0 < m =⇒ (2 ::nat)ˆm − 2ˆ(m − 1 ) = 2ˆ(m − 1 ) by (induct m) auto We first prove the following auxillary lemma. This lemma simply states that 1 1 1 1 1 1 1 the finite sums: 2 , 3 + 4 , 5 + 6 + 7 + 8 etc. are all greater than or equal 1 to 2 . We do this by observing that each term in the sum is greater than or 1 1 1 1 1 1 1 equal to the last term, e.g. 3 > 4 and thus 3 + 4 > 4 + 4 = 2 . lemma harmonic-aux: ∀ m>0 . (P n∈{(2 ::nat)ˆ(m − 1 )+1 ..2ˆm}. 1 /real n) ≥ 1 /2 (is ∀ m>0 . (P n∈(?S m). 1 /real n) ≥ 1 /2 ) proof fix m::nat obtain tm where tmdef : tm = (2 ::nat)ˆm by simp 402 { assume mgt0 : 0 < m have Vx. x∈(?S m) =⇒ 1 /(real x) ≥ 1 /(real tm) proof − fix x::nat assume xs: x∈(?S m) have xgt0 : x>0 proof − from xs have x ≥ 2ˆ(m − 1 ) + 1 by auto moreover from mgt0 have 2ˆ(m − 1 ) + 1 ≥ (1 ::nat) by auto ultimately have x ≥ 1 by (rule xtrans) thus ?thesis by simp qed moreover from xs have x ≤ 2ˆm by auto ultimately have inverse (real x) ≥ inverse (real ((2 ::nat)ˆm)) by simp moreover from xgt0 have real x 6= 0 by simp then have inverse (real x) = 1 / (real x) by (rule nonzero-inverse-eq-divide) moreover from mgt0 have real tm 6= 0 by (simp add: tmdef ) then have inverse (real tm) = 1 / (real tm) by (rule nonzero-inverse-eq-divide) ultimately show 1 /(real x) ≥ 1 /(real tm) by (auto simp add: tmdef ) qed then have (P n∈(?S m). 1 / real n) ≥ (P n∈(?S m). 1 /(real tm)) by (rule sum-mono) moreover have (P n∈(?S m). 1 /(real tm)) = 1 /2 proof − have (P n∈(?S m). 1 /(real tm)) = (1 /(real tm))∗(P n∈(?S m). 1 ) by simp also have ... = ((1 /(real tm)) ∗ real (card (?S m))) by (simp add: real-of-card) also have ... = ((1 /(real tm)) ∗ real (tm − (2ˆ(m − 1 )))) by (simp add: tmdef ) also from mgt0 have ... = ((1 /(real tm)) ∗ real ((2 ::nat)ˆ(m − 1 ))) by (auto simp: tmdef dest: two-pow-sub) 403 also have ... = (real (2 ::nat))ˆ(m − 1 ) / (real (2 ::nat))ˆm by (simp add: tmdef ) also from mgt0 have ... = (real (2 ::nat))ˆ(m − 1 ) / (real (2 ::nat))ˆ((m − 1 ) + 1 ) by auto also have ... = 1 /2 by simp finally show ?thesis . qed ultimately have (P n∈(?S m). 1 / real n) ≥ 1 /2 by − (erule subst) } thus 0 < m −→ 1 / 2 ≤ (P n∈(?S m). 1 / real n) by simp qed We then show that the sum of a finite number of terms from the harmonic 1 1 series can be regrouped in increasing powers of 2. For example: 1 + 2 + 3 + 1 1 1 1 1 1 1 1 1 1 1 1 4 + 5 + 6 + 7 + 8 = 1 + ( 2 ) + ( 3 + 4 ) + ( 5 + 6 + 7 + 8 ). lemma harmonic-aux2 [rule-format]: 0 404 moreover { from mz have ?RHS (Suc M ) = ?RHS 1 by simp also have ... = (P n∈{((2 ::nat)ˆ0 )+1 ..2ˆ1 }. 1 /real n) + 1 by simp also have ... = (P n∈{2 ::nat..2 }. 1 /real n) + 1 by (auto simp: atLeastAtMost-singleton 0) also have ... = 1 /2 + 1 by simp finally have ?RHS (Suc M ) = 1 /2 + 1 by simp } ultimately show ?LHS (Suc M ) = ?RHS (Suc M ) by simp next assume mnz: M 6=0 then have mgtz: M >0 by simp with Suc have suc: (?LHS M ) = (?RHS M ) by blast have (?LHS (Suc M )) = ((?LHS M ) + (P n∈{(2 ::nat)ˆM +1 ..2ˆ(Suc M )}. 1 / real n)) proof − have {1 ..(2 ::nat)ˆ(Suc M )} = {1 ..(2 ::nat)ˆM }∪{(2 ::nat)ˆM +1 ..(2 ::nat)ˆ(Suc M )} by auto moreover have {1 ..(2 ::nat)ˆM }∩{(2 ::nat)ˆM +1 ..(2 ::nat)ˆ(Suc M )} = {} by auto moreover have finite {1 ..(2 ::nat)ˆM } and finite {(2 ::nat)ˆM +1 ..(2 ::nat)ˆ(Suc M )} by auto ultimately show ?thesis by (auto intro: sum.union-disjoint) qed moreover { have (?RHS (Suc M )) = (1 + (P m∈{1 ..M }. P n∈{(2 ::nat)ˆ(m − 1 )+1 ..2ˆm}. 1 /real n) + (P n∈{(2 ::nat)ˆ(Suc M − 1 )+1 ..2ˆ(Suc M )}. 1 /real n)) by simp also have ... = (?RHS M ) + (P n∈{(2 ::nat)ˆM +1 ..2ˆ(Suc M )}. 1 /real n) by simp also from suc have 405 ... = (?LHS M ) + (P n∈{(2 ::nat)ˆM +1 ..2ˆ(Suc M )}. 1 /real n) by simp finally have (?RHS (Suc M )) = ... by simp } ultimately show ?LHS (Suc M ) = ?RHS (Suc M ) by simp qed } thus ?case by simp qed Using harmonic-aux and harmonic-aux2 we now show that each group sum 1 is greater than or equal to 2 and thus the finite sum is bounded below by a value proportional to the number of elements we choose. lemma harmonic-aux3 [rule-format]: shows ∀ (M ::nat). (P n∈{1 ..(2 ::nat)ˆM }. 1 / real n) ≥ 1 + (real M )/2 (is ∀ M . ?P M ≥ -) proof (rule allI , cases) fix M ::nat assume M =0 then show ?P M ≥ 1 + (real M )/2 by simp next fix M ::nat assume M 6=0 then have M > 0 by simp then have (?P M ) = (1 + (P m∈{1 ..M }. P n∈{(2 ::nat)ˆ(m − 1 )+1 ..2ˆm}. 1 /real n)) by (rule harmonic-aux2 ) also have ... ≥ (1 + (P m∈{1 ..M }. 1 /2 )) proof − let ?f = (λx. 1 /2 ) let ?g = (λx. (P n∈{(2 ::nat)ˆ(x − 1 )+1 ..2ˆx}. 1 /real n)) from harmonic-aux have Vx. x∈{1 ..M } =⇒ ?f x ≤ ?g x by simp then have (P m∈{1 ..M }. ?g m) ≥ (P m∈{1 ..M }. ?f m) by (rule sum-mono) thus ?thesis by simp qed finally have (?P M ) ≥ (1 + (P m∈{1 ..M }. 1 /2 )) . moreover { have (P m∈{1 ..M }. (1 ::real)/2 ) = 1 /2 ∗ (P m∈{1 ..M }. 1 ) by auto also have ... = 1 /2 ∗(real (card {1 ..M })) by (simp only: real-of-card[symmetric]) also have ... = 1 /2 ∗(real M ) by simp 406 also have ... = (real M )/2 by simp finally have (P m∈{1 ..M }. (1 ::real)/2 ) = (real M )/2 . } ultimately show (?P M ) ≥ (1 + (real M )/2 ) by simp qed The final theorem shows that as we take more and more elements (see harmonic-aux3 ) we get an ever increasing sum. By assuming the sum con- verges, the lemma sum-less-suminf ( [[summable ?f ; ∀ m≥?n. (0 ::? 0a) < ?f m]] =⇒ sum ?f {.. ?s by linarith define j where j = (2 ::nat)ˆn have ∀ m≥j . 0 < ?f m by simp with sf have (P i 56 Examples for the ’refute’ command theory Refute-Examples imports ∼∼/src/HOL/Library/Refute begin refute-params [satsolver = cdclite] lemma P ∧ Q 407 apply (rule conjI ) refute [expect = genuine] 1 — refutes P refute [expect = genuine] 2 — refutes Q refute [expect = genuine] — equivalent to ’refute 1’ — here ’refute 3’ would cause an exception, since we only have 2 subgoals refute [maxsize = 5 , expect = genuine] — we can override parameters ... refute [satsolver = cdclite, expect = genuine] 2 — ... and specify a subgoal at the same time oops 56.1 Examples and Test Cases 56.1.1 Propositional logic lemma True refute [expect = none] by auto lemma False refute [expect = genuine] oops lemma P refute [expect = genuine] oops lemma ∼ P refute [expect = genuine] oops lemma P & Q refute [expect = genuine] oops lemma P | Q refute [expect = genuine] oops lemma P −→ Q refute [expect = genuine] oops lemma (P::bool) = Q refute [expect = genuine] oops lemma (P | Q) −→ (P & Q) refute [expect = genuine] oops 408 56.1.2 Predicate logic lemma P x y z refute [expect = genuine] oops lemma P x y −→ P y x refute [expect = genuine] oops lemma P (f (f x)) −→ P x −→ P (f x) refute [expect = genuine] oops 56.1.3 Equality lemma P = True refute [expect = genuine] oops lemma P = False refute [expect = genuine] oops lemma x = y refute [expect = genuine] oops lemma f x = g x refute [expect = genuine] oops lemma (f :: 0a⇒ 0b) = g refute [expect = genuine] oops lemma (f ::( 0d⇒ 0d)⇒( 0c⇒ 0d)) = g refute [expect = genuine] oops lemma distinct [a, b] apply simp refute [expect = genuine] oops 56.1.4 First-Order Logic lemma ∃ x. P x refute [expect = genuine] 409 oops lemma ∀ x. P x refute [expect = genuine] oops lemma ∃ !x. P x refute [expect = genuine] oops lemma Ex P refute [expect = genuine] oops lemma All P refute [expect = genuine] oops lemma Ex1 P refute [expect = genuine] oops lemma (∃ x. P x) −→ (∀ x. P x) refute [expect = genuine] oops lemma (∀ x. ∃ y. P x y) −→ (∃ y. ∀ x. P x y) refute [expect = genuine] oops lemma (∃ x. P x) −→ (∃ !x. P x) refute [expect = genuine] oops A true statement (also testing names of free and bound variables being identical) lemma (∀ x y. P x y −→ P y x) −→ (∀ x. P x y) −→ P y x refute [maxsize = 4 , expect = none] by fast ”A type has at most 4 elements.” lemma a=b | a=c | a=d | a=e | b=c | b=d | b=e | c=d | c=e | d=e refute [expect = genuine] oops lemma ∀ a b c d e. a=b | a=c | a=d | a=e | b=c | b=d | b=e | c=d | c=e | d=e refute [expect = genuine] oops 410 ”Every reflexive and symmetric relation is transitive.” lemma [[ ∀ x. P x x; ∀ x y. P x y −→ P y x ]] =⇒ P x y −→ P y z −→ P x z refute [expect = genuine] oops The ”Drinker’s theorem” ... lemma ∃ x. f x = g x −→ f = g refute [maxsize = 4 , expect = none] by (auto simp add: ext) ... and an incorrect version of it lemma (∃ x. f x = g x) −→ f = g refute [expect = genuine] oops ”Every function has a fixed point.” lemma ∃ x. f x = x refute [expect = genuine] oops ”Function composition is commutative.” lemma f (g x) = g (f x) refute [expect = genuine] oops ”Two functions that are equivalent wrt. the same predicate ’P’ are equal.” lemma ((P::( 0a⇒ 0b)⇒bool) f = P g) −→ (f x = g x) refute [expect = genuine] oops 56.1.5 Higher-Order Logic lemma ∃ P. P refute [expect = none] by auto lemma ∀ P. P refute [expect = genuine] oops lemma ∃ !P. P refute [expect = none] by auto lemma ∃ !P. P x refute [expect = genuine] oops 411 lemma PQ | Q x refute [expect = genuine] oops lemma x 6= All refute [expect = genuine] oops lemma x 6= Ex refute [expect = genuine] oops lemma x 6= Ex1 refute [expect = genuine] oops ”The transitive closure ’T’ of an arbitrary relation ’P’ is non-empty.” definition trans :: ( 0a ⇒ 0a ⇒ bool) ⇒ bool where trans P == (ALL x y z. P x y −→ P y z −→ P x z) definition subset :: ( 0a ⇒ 0a ⇒ bool) ⇒ ( 0a ⇒ 0a ⇒ bool) ⇒ bool where subset P Q == (ALL x y. P x y −→ Q x y) definition trans-closure :: ( 0a ⇒ 0a ⇒ bool) ⇒ ( 0a ⇒ 0a ⇒ bool) ⇒ bool where trans-closure P Q == (subset Q P)&(trans P)&(ALL R. subset Q R −→ trans R −→ subset P R) lemma trans-closure T P −→ (∃ x y. T x y) refute [expect = genuine] oops ”Every surjective function is invertible.” lemma (∀ y. ∃ x. y = f x) −→ (∃ g. ∀ x. g (f x) = x) refute [expect = genuine] oops ”Every invertible function is surjective.” lemma (∃ g. ∀ x. g (f x) = x) −→ (∀ y. ∃ x. y = f x) refute [expect = genuine] oops Every point is a fixed point of some function. lemma ∃ f . f x = x refute [maxsize = 4 , expect = none] apply (rule-tac x=λx. x in exI ) by simp Axiom of Choice: first an incorrect version ... 412 lemma (∀ x. ∃ y. P x y) −→ (∃ !f . ∀ x. P x (f x)) refute [expect = genuine] oops ... and now two correct ones lemma (∀ x. ∃ y. P x y) −→ (∃ f . ∀ x. P x (f x)) refute [maxsize = 4 , expect = none] by (simp add: choice) lemma (∀ x. ∃ !y. P x y) −→ (∃ !f . ∀ x. P x (f x)) refute [maxsize = 2 , expect = none] apply auto apply (simp add: ex1-implies-ex choice) by (fast intro: ext) 56.1.6 Meta-logic lemma !!x. P x refute [expect = genuine] oops lemma f x == g x refute [expect = genuine] oops lemma P =⇒ Q refute [expect = genuine] oops lemma [[ P; Q; R ]] =⇒ S refute [expect = genuine] oops lemma (x == Pure.all) =⇒ False refute [expect = genuine] oops lemma (x == (op ==)) =⇒ False refute [expect = genuine] oops lemma (x == (op =⇒)) =⇒ False refute [expect = genuine] oops 56.1.7 Schematic variables schematic-goal ?P refute [expect = none] by auto 413 schematic-goal x = ?y refute [expect = none] by auto 56.1.8 Abstractions lemma (λx. x) = (λx. y) refute [expect = genuine] oops lemma (λf . f x) = (λf . True) refute [expect = genuine] oops lemma (λx. x) = (λy. y) refute by simp 56.1.9 Sets lemma P (A:: 0a set) refute oops lemma P (A:: 0a set set) refute oops lemma {x. P x} = {y. P y} refute by simp lemma x : {x. P x} refute oops lemma P op: refute oops lemma P (op: x) refute oops lemma P Collect refute oops lemma A Un B = A Int B 414 refute oops lemma (A Int B) Un C = (A Un C ) Int B refute oops lemma Ball A P −→ Bex A P refute oops 56.1.10 undefined lemma undefined refute [expect = genuine] oops lemma P undefined refute [expect = genuine] oops lemma undefined x refute [expect = genuine] oops lemma undefined undefined refute [expect = genuine] oops 56.1.11 The lemma The P refute [expect = genuine] oops lemma P The refute [expect = genuine] oops lemma P (The P) refute [expect = genuine] oops lemma (THE x. x=y) = z refute [expect = genuine] oops lemma Ex P −→ P (The P) refute [expect = genuine] oops 415 56.1.12 Eps lemma Eps P refute [expect = genuine] oops lemma P Eps refute [expect = genuine] oops lemma P (Eps P) refute [expect = genuine] oops lemma (SOME x. x=y) = z refute [expect = genuine] oops lemma Ex P −→ P (Eps P) refute [maxsize = 3 , expect = none] by (auto simp add: someI ) 56.1.13 Subtypes (typedef), typedecl A completely unspecified non-empty subset of 0a: definition myTdef = insert (undefined:: 0a)(undefined:: 0a set) typedef 0a myTdef = myTdef :: 0a set unfolding myTdef-def by auto lemma (x:: 0a myTdef ) = y refute oops typedecl myTdecl definition T-bij = {(f :: 0a⇒ 0a). ∀ y. ∃ !x. f x = y} typedef 0a T-bij = T-bij :: ( 0a ⇒ 0a) set unfolding T-bij-def by auto lemma P (f ::(myTdecl myTdef ) T-bij ) refute oops 56.1.14 Inductive datatypes unit lemma P (x::unit) 416 refute [expect = genuine] oops lemma ∀ x::unit. P x refute [expect = genuine] oops lemma P () refute [expect = genuine] oops lemma P (case x of () ⇒ u) refute [expect = genuine] oops option lemma P (x:: 0a option) refute [expect = genuine] oops lemma ∀ x:: 0a option. P x refute [expect = genuine] oops lemma P None refute [expect = genuine] oops lemma P (Some x) refute [expect = genuine] oops lemma P (case x of None ⇒ n | Some u ⇒ s u) refute [expect = genuine] oops * lemma P (x:: 0a∗ 0b) refute [expect = genuine] oops lemma ∀ x:: 0a∗ 0b. P x refute [expect = genuine] oops lemma P (x, y) refute [expect = genuine] oops 417 lemma P (fst x) refute [expect = genuine] oops lemma P (snd x) refute [expect = genuine] oops lemma P Pair refute [expect = genuine] oops lemma P (case x of Pair a b ⇒ p a b) refute [expect = genuine] oops + lemma P (x:: 0a+ 0b) refute [expect = genuine] oops lemma ∀ x:: 0a+ 0b. P x refute [expect = genuine] oops lemma P (Inl x) refute [expect = genuine] oops lemma P (Inr x) refute [expect = genuine] oops lemma P Inl refute [expect = genuine] oops lemma P (case x of Inl a ⇒ l a | Inr b ⇒ r b) refute [expect = genuine] oops Non-recursive datatypes datatype T1 = A | B lemma P (x::T1 ) refute [expect = genuine] oops lemma ∀ x::T1 . P x 418 refute [expect = genuine] oops lemma PA refute [expect = genuine] oops lemma PB refute [expect = genuine] oops lemma rec-T1 a b A = a refute [expect = none] by simp lemma rec-T1 a b B = b refute [expect = none] by simp lemma P (rec-T1 a b x) refute [expect = genuine] oops lemma P (case x of A ⇒ a | B ⇒ b) refute [expect = genuine] oops datatype 0a T2 = C T1 | D 0a lemma P (x:: 0a T2 ) refute [expect = genuine] oops lemma ∀ x:: 0a T2 . P x refute [expect = genuine] oops lemma PD refute [expect = genuine] oops lemma rec-T2 c d (C x) = c x refute [maxsize = 4 , expect = none] by simp lemma rec-T2 c d (D x) = d x refute [maxsize = 4 , expect = none] by simp 419 lemma P (rec-T2 c d x) refute [expect = genuine] oops lemma P (case x of C u ⇒ c u | D v ⇒ d v) refute [expect = genuine] oops datatype ( 0a, 0b) T3 = E 0a ⇒ 0b lemma P (x::( 0a, 0b) T3 ) refute [expect = genuine] oops lemma ∀ x::( 0a, 0b) T3 . P x refute [expect = genuine] oops lemma PE refute [expect = genuine] oops lemma rec-T3 e (E x) = e x refute [maxsize = 2 , expect = none] by simp lemma P (rec-T3 e x) refute [expect = genuine] oops lemma P (case x of E f ⇒ e f ) refute [expect = genuine] oops Recursive datatypes nat lemma P (x::nat) refute [expect = potential] oops lemma ∀ x::nat. P x refute [expect = potential] oops lemma P (Suc 0 ) refute [expect = potential] oops lemma P Suc 420 refute [maxsize = 3 , expect = none] — Suc is a partial function (regardless of the size of the model), hence P Suc is undefined and no model will be found oops lemma rec-nat zero suc 0 = zero refute [expect = none] by simp lemma rec-nat zero suc (Suc x) = suc x (rec-nat zero suc x) refute [maxsize = 2 , expect = none] by simp lemma P (rec-nat zero suc x) refute [expect = potential] oops lemma P (case x of 0 ⇒ zero | Suc n ⇒ suc n) refute [expect = potential] oops ’a list lemma P (xs:: 0a list) refute [expect = potential] oops lemma ∀ xs:: 0a list. P xs refute [expect = potential] oops lemma P [x, y] refute [expect = potential] oops lemma rec-list nil cons [] = nil refute [maxsize = 3 , expect = none] by simp lemma rec-list nil cons (x#xs) = cons x xs (rec-list nil cons xs) refute [maxsize = 2 , expect = none] by simp lemma P (rec-list nil cons xs) refute [expect = potential] oops lemma P (case x of Nil ⇒ nil | Cons a b ⇒ cons a b) refute [expect = potential] oops 421 lemma (xs:: 0a list) = ys refute [expect = potential] oops lemma a # xs = b # xs refute [expect = potential] oops datatype BitList = BitListNil | Bit0 BitList | Bit1 BitList lemma P (x::BitList) refute [expect = potential] oops lemma ∀ x::BitList. P x refute [expect = potential] oops lemma P (Bit0 (Bit1 BitListNil)) refute [expect = potential] oops lemma rec-BitList nil bit0 bit1 BitListNil = nil refute [maxsize = 4 , expect = none] by simp lemma rec-BitList nil bit0 bit1 (Bit0 xs) = bit0 xs (rec-BitList nil bit0 bit1 xs) refute [maxsize = 2 , expect = none] by simp lemma rec-BitList nil bit0 bit1 (Bit1 xs) = bit1 xs (rec-BitList nil bit0 bit1 xs) refute [maxsize = 2 , expect = none] by simp lemma P (rec-BitList nil bit0 bit1 x) refute [expect = potential] oops 56.1.15 Examples involving special functions lemma card x = 0 refute [expect = potential] oops lemma finite x refute — no finite countermodel exists oops 422 lemma (x::nat) + y = 0 refute [expect = potential] oops lemma (x::nat) = x + x refute [expect = potential] oops lemma (x::nat) − y + y = x refute [expect = potential] oops lemma (x::nat) = x ∗ x refute [expect = potential] oops lemma (x::nat) < x + y refute [expect = potential] oops lemma xs @ [] = ys @ [] refute [expect = potential] oops lemma xs @ ys = ys @ xs refute [expect = potential] oops 56.1.16 Type classes and overloading A type class without axioms: class classA lemma P (x:: 0a::classA) refute [expect = genuine] oops An axiom with a type variable (denoting types which have at least two elements): class classC = assumes classC-ax: ∃ x y. x 6= y lemma P (x:: 0a::classC ) refute [expect = genuine] oops lemma ∃ x y. (x:: 0a::classC ) 6= y 423 oops A type class for which a constant is defined: class classD = fixes classD-const :: 0a ⇒ 0a assumes classD-ax: classD-const (classD-const x) = classD-const x lemma P (x:: 0a::classD) refute [expect = genuine] oops A type class with multiple superclasses: class classE = classC + classD lemma P (x:: 0a::classE) refute [expect = genuine] oops OFCLASS: lemma OFCLASS( 0a::type, type-class) refute [expect = none] by intro-classes lemma OFCLASS( 0a::classC , type-class) refute [expect = none] by intro-classes lemma OFCLASS( 0a::type, classC-class) refute [expect = genuine] oops Overloading: consts inverse :: 0a ⇒ 0a overloading inverse-bool ≡ inverse :: bool ⇒ bool begin definition inverse (b::bool) ≡ ¬ b end overloading inverse-set ≡ inverse :: 0a set ⇒ 0a set begin definition inverse (S:: 0a set) ≡ −S end overloading inverse-pair ≡ inverse :: 0a × 0b ⇒ 0a × 0b begin definition inverse-pair p ≡ (inverse (fst p), inverse (snd p)) end 424 lemma inverse b refute [expect = genuine] oops lemma P (inverse (S:: 0a set)) refute [expect = genuine] oops lemma P (inverse (p:: 0a× 0b)) refute [expect = genuine] oops Structured proofs lemma x = y proof cases assume x = y show ?thesis refute [expect = none] refute [no-assms, expect = genuine] refute [no-assms = false, expect = none] oops refute-params [satsolver = auto] end 57 Implementation of Association Lists theory AList imports Main begin context begin The operations preserve distinctness of keys and function clearjunk dis- tributes over them. Since clearjunk enforces distinctness of keys it can be used to establish the invariant, e.g. for inductive proofs. 57.1 update and updates qualified primrec update :: 0key ⇒ 0val ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where update k v [] = [(k, v)] | update k v (p # ps) = (if fst p = k then (k, v)# ps else p # update k v ps) lemma update-conv 0: map-of (update k v al) = (map-of al)(k7→v) 425 by (induct al)(auto simp add: fun-eq-iff ) corollary update-conv: map-of (update k v al) k 0 = ((map-of al)(k7→v)) k 0 by (simp add: update-conv 0) lemma dom-update: fst ‘ set (update k v al) = {k} ∪ fst ‘ set al by (induct al) auto lemma update-keys: map fst (update k v al) = (if k ∈ set (map fst al) then map fst al else map fst al @[k]) by (induct al) simp-all lemma distinct-update: assumes distinct (map fst al) shows distinct (map fst (update k v al)) using assms by (simp add: update-keys) lemma update-filter: a 6= k =⇒ update k v [q←ps. fst q 6= a] = [q←update k v ps. fst q 6= a] by (induct ps) auto lemma update-triv: map-of al k = Some v =⇒ update k v al = al by (induct al) auto lemma update-nonempty [simp]: update k v al 6= [] by (induct al) auto lemma update-eqD: update k v al = update k v 0 al 0 =⇒ v = v 0 proof (induct al arbitrary: al 0) case Nil then show ?case by (cases al 0)(auto split: if-split-asm) next case Cons then show ?case by (cases al 0)(auto split: if-split-asm) qed lemma update-last [simp]: update k v (update k v 0 al) = update k v al by (induct al) auto Note that the lists are not necessarily the same: update k v (update k 0 v 0 []) = [(k 0, v 0), (k, v)] and update k 0 v 0 (update k v []) = [(k, v), (k 0, v 0)]. lemma update-swap: k 6= k 0 =⇒ map-of (update k v (update k 0 v 0 al)) = map-of (update k 0 v 0 (update k v al)) by (simp add: update-conv 0 fun-eq-iff ) 426 lemma update-Some-unfold: map-of (update k v al) x = Some y ←→ x = k ∧ v = y ∨ x 6= k ∧ map-of al x = Some y by (simp add: update-conv 0 map-upd-Some-unfold) lemma image-update [simp]: x ∈/ A =⇒ map-of (update x y al) ‘A = map-of al ‘A by (simp add: update-conv 0) qualified definition updates :: 0key list ⇒ 0val list ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where updates ks vs = fold (case-prod update)(zip ks vs) lemma updates-simps [simp]: updates [] vs ps = ps updates ks [] ps = ps updates (k#ks)(v#vs) ps = updates ks vs (update k v ps) by (simp-all add: updates-def ) lemma updates-key-simp [simp]: updates (k # ks) vs ps = (case vs of [] ⇒ ps | v # vs ⇒ updates ks vs (update k v ps)) by (cases vs) simp-all lemma updates-conv 0: map-of (updates ks vs al) = (map-of al)(ks[7→]vs) proof − have map-of ◦ fold (case-prod update)(zip ks vs) = fold (λ(k, v) f . f (k 7→ v)) (zip ks vs) ◦ map-of by (rule fold-commute)(auto simp add: fun-eq-iff update-conv 0) then show ?thesis by (auto simp add: updates-def fun-eq-iff map-upds-fold-map-upd foldl-conv-fold split-def ) qed lemma updates-conv: map-of (updates ks vs al) k = ((map-of al)(ks[7→]vs)) k by (simp add: updates-conv 0) lemma distinct-updates: assumes distinct (map fst al) shows distinct (map fst (updates ks vs al)) proof − have distinct (fold (λ(k, v) al. if k ∈ set al then al else al @[k]) (zip ks vs)(map fst al)) by (rule fold-invariant [of zip ks vs λ-. True]) (auto intro: assms) moreover have map fst ◦ fold (case-prod update)(zip ks vs) = fold (λ(k, v) al. if k ∈ set al then al else al @[k]) (zip ks vs) ◦ map fst by (rule fold-commute)(simp add: update-keys split-def case-prod-beta comp-def ) ultimately show ?thesis 427 by (simp add: updates-def fun-eq-iff ) qed lemma updates-append1 [simp]: size ks < size vs =⇒ updates (ks@[k]) vs al = update k (vs!size ks)(updates ks vs al) by (induct ks arbitrary: vs al)(auto split: list.splits) lemma updates-list-update-drop[simp]: size ks ≤ i =⇒ i < size vs =⇒ updates ks (vs[i:=v]) al = updates ks vs al by (induct ks arbitrary: al vs i)(auto split: list.splits nat.splits) lemma update-updates-conv-if : map-of (updates xs ys (update x y al)) = map-of (if x ∈ set (take (length ys) xs) then updates xs ys al else (update x y (updates xs ys al))) by (simp add: updates-conv 0 update-conv 0 map-upd-upds-conv-if ) lemma updates-twist [simp]: k ∈/ set ks =⇒ map-of (updates ks vs (update k v al)) = map-of (update k v (updates ks vs al)) by (simp add: updates-conv 0 update-conv 0) lemma updates-apply-notin [simp]: k ∈/ set ks =⇒ map-of (updates ks vs al) k = map-of al k by (simp add: updates-conv) lemma updates-append-drop [simp]: size xs = size ys =⇒ updates (xs @ zs) ys al = updates xs ys al by (induct xs arbitrary: ys al)(auto split: list.splits) lemma updates-append2-drop [simp]: size xs = size ys =⇒ updates xs (ys @ zs) al = updates xs ys al by (induct xs arbitrary: ys al)(auto split: list.splits) 57.2 delete qualified definition delete :: 0key ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where delete-eq: delete k = filter (λ(k 0, -). k 6= k 0) lemma delete-simps [simp]: delete k [] = [] delete k (p # ps) = (if fst p = k then delete k ps else p # delete k ps) by (auto simp add: delete-eq) lemma delete-conv 0: map-of (delete k al) = (map-of al)(k := None) by (induct al)(auto simp add: fun-eq-iff ) 428 corollary delete-conv: map-of (delete k al) k 0 = ((map-of al)(k := None)) k 0 by (simp add: delete-conv 0) lemma delete-keys: map fst (delete k al) = removeAll k (map fst al) by (simp add: delete-eq removeAll-filter-not-eq filter-map split-def comp-def ) lemma distinct-delete: assumes distinct (map fst al) shows distinct (map fst (delete k al)) using assms by (simp add: delete-keys distinct-removeAll) lemma delete-id [simp]: k ∈/ fst ‘ set al =⇒ delete k al = al by (auto simp add: image-iff delete-eq filter-id-conv) lemma delete-idem: delete k (delete k al) = delete k al by (simp add: delete-eq) lemma map-of-delete [simp]: k 0 6= k =⇒ map-of (delete k al) k 0 = map-of al k 0 by (simp add: delete-conv 0) lemma delete-notin-dom: k ∈/ fst ‘ set (delete k al) by (auto simp add: delete-eq) lemma dom-delete-subset: fst ‘ set (delete k al) ⊆ fst ‘ set al by (auto simp add: delete-eq) lemma delete-update-same: delete k (update k v al) = delete k al by (induct al) simp-all lemma delete-update: k 6= l =⇒ delete l (update k v al) = update k v (delete l al) by (induct al) simp-all lemma delete-twist: delete x (delete y al) = delete y (delete x al) by (simp add: delete-eq conj-commute) lemma length-delete-le: length (delete k al) ≤ length al by (simp add: delete-eq) 57.3 update-with-aux and delete-aux qualified primrec update-with-aux :: 0val ⇒ 0key ⇒ ( 0val ⇒ 0val) ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where update-with-aux v k f [] = [(k, f v)] | update-with-aux v k f (p # ps) = (if (fst p = k) then (k, f (snd p)) # ps else p # update-with-aux v k f ps) The above delete traverses all the list even if it has found the key. This one does not have to keep going because is assumes the invariant that keys are 429 distinct. qualified fun delete-aux :: 0key ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where delete-aux k [] = [] | delete-aux k ((k 0, v)# xs) = (if k = k 0 then xs else (k 0, v)# delete-aux k xs) lemma map-of-update-with-aux 0: map-of (update-with-aux v k f ps) k 0 = ((map-of ps)(k 7→ (case map-of ps k of None ⇒ f v | Some v ⇒ f v))) k 0 by (induct ps) auto lemma map-of-update-with-aux: map-of (update-with-aux v k f ps) = (map-of ps)(k 7→ (case map-of ps k of None ⇒ f v | Some v ⇒ f v)) by (simp add: fun-eq-iff map-of-update-with-aux 0) lemma dom-update-with-aux: fst ‘ set (update-with-aux v k f ps) = {k} ∪ fst ‘ set ps by (induct ps) auto lemma distinct-update-with-aux [simp]: distinct (map fst (update-with-aux v k f ps)) = distinct (map fst ps) by (induct ps)(auto simp add: dom-update-with-aux) lemma set-update-with-aux: distinct (map fst xs) =⇒ set (update-with-aux v k f xs) = (set xs − {k} × UNIV ∪ {(k, f (case map-of xs k of None ⇒ v | Some v ⇒ v))}) by (induct xs)(auto intro: rev-image-eqI ) lemma set-delete-aux: distinct (map fst xs) =⇒ set (delete-aux k xs) = set xs − {k} × UNIV apply (induct xs) apply simp-all apply clarsimp apply (fastforce intro: rev-image-eqI ) done lemma dom-delete-aux: distinct (map fst ps) =⇒ fst ‘ set (delete-aux k ps) = fst ‘ set ps − {k} by (auto simp add: set-delete-aux) lemma distinct-delete-aux [simp]: distinct (map fst ps) =⇒ distinct (map fst (delete-aux k ps)) proof (induct ps) case Nil then show ?case by simp next 430 case (Cons a ps) obtain k 0 v where a: a = (k 0, v) by (cases a) show ?case proof (cases k 0 = k) case True with Cons a show ?thesis by simp next case False with Cons a have k 0 ∈/ fst ‘ set ps distinct (map fst ps) by simp-all with False a have k 0 ∈/ fst ‘ set (delete-aux k ps) by (auto dest!: dom-delete-aux[where k=k]) with Cons a show ?thesis by simp qed qed lemma map-of-delete-aux 0: distinct (map fst xs) =⇒ map-of (delete-aux k xs) = (map-of xs)(k := None) apply (induct xs) apply (fastforce simp add: map-of-eq-None-iff fun-upd-twist) apply (auto intro!: ext) apply (simp add: map-of-eq-None-iff ) done lemma map-of-delete-aux: distinct (map fst xs) =⇒ map-of (delete-aux k xs) k 0 = ((map-of xs)(k := None)) k 0 by (simp add: map-of-delete-aux 0) lemma delete-aux-eq-Nil-conv: delete-aux k ts = [] ←→ ts = [] ∨ (∃ v. ts = [(k, v)]) by (cases ts)(auto split: if-split-asm) 57.4 restrict qualified definition restrict :: 0key set ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where restrict-eq: restrict A = filter (λ(k, v). k ∈ A) lemma restr-simps [simp]: restrict A [] = [] restrict A (p#ps) = (if fst p ∈ A then p # restrict A ps else restrict A ps) by (auto simp add: restrict-eq) lemma restr-conv 0: map-of (restrict A al) = ((map-of al)|‘A) proof show map-of (restrict A al) k = ((map-of al)|‘A) k for k apply (induct al) 431 apply simp apply (cases k ∈ A) apply auto done qed corollary restr-conv: map-of (restrict A al) k = ((map-of al)|‘A) k by (simp add: restr-conv 0) lemma distinct-restr: distinct (map fst al) =⇒ distinct (map fst (restrict A al)) by (induct al)(auto simp add: restrict-eq) lemma restr-empty [simp]: restrict {} al = [] restrict A [] = [] by (induct al)(auto simp add: restrict-eq) lemma restr-in [simp]: x ∈ A =⇒ map-of (restrict A al) x = map-of al x by (simp add: restr-conv 0) lemma restr-out [simp]: x ∈/ A =⇒ map-of (restrict A al) x = None by (simp add: restr-conv 0) lemma dom-restr [simp]: fst ‘ set (restrict A al) = fst ‘ set al ∩ A by (induct al)(auto simp add: restrict-eq) lemma restr-upd-same [simp]: restrict (−{x})(update x y al) = restrict (−{x}) al by (induct al)(auto simp add: restrict-eq) lemma restr-restr [simp]: restrict A (restrict B al) = restrict (A∩B) al by (induct al)(auto simp add: restrict-eq) lemma restr-update[simp]: map-of (restrict D (update x y al)) = map-of ((if x ∈ D then (update x y (restrict (D−{x}) al)) else restrict D al)) by (simp add: restr-conv 0 update-conv 0) lemma restr-delete [simp]: delete x (restrict D al) = (if x ∈ D then restrict (D − {x}) al else restrict D al) apply (simp add: delete-eq restrict-eq) apply (auto simp add: split-def ) proof − have y 6= x ←→ x 6= y for y by auto then show [p ← al. fst p ∈ D ∧ x 6= fst p] = [p ← al. fst p ∈ D ∧ fst p 6= x] by simp assume x ∈/ D then have y ∈ D ←→ y ∈ D ∧ x 6= y for y 432 by auto then show [p ← al . fst p ∈ D ∧ x 6= fst p] = [p ← al . fst p ∈ D] by simp qed lemma update-restr: map-of (update x y (restrict D al)) = map-of (update x y (restrict (D − {x}) al)) by (simp add: update-conv 0 restr-conv 0)(rule fun-upd-restrict) lemma update-restr-conv [simp]: x ∈ D =⇒ map-of (update x y (restrict D al)) = map-of (update x y (restrict (D − {x}) al)) by (simp add: update-conv 0 restr-conv 0) lemma restr-updates [simp]: length xs = length ys =⇒ set xs ⊆ D =⇒ map-of (restrict D (updates xs ys al)) = map-of (updates xs ys (restrict (D − set xs) al)) by (simp add: updates-conv 0 restr-conv 0) lemma restr-delete-twist:(restrict A (delete a ps)) = delete a (restrict A ps) by (induct ps) auto 57.5 clearjunk qualified function clearjunk :: ( 0key × 0val) list ⇒ ( 0key × 0val) list where clearjunk [] = [] | clearjunk (p#ps) = p # clearjunk (delete (fst p) ps) by pat-completeness auto termination by (relation measure length)(simp-all add: less-Suc-eq-le length-delete-le) lemma map-of-clearjunk: map-of (clearjunk al) = map-of al by (induct al rule: clearjunk.induct)(simp-all add: fun-eq-iff ) lemma clearjunk-keys-set: set (map fst (clearjunk al)) = set (map fst al) by (induct al rule: clearjunk.induct)(simp-all add: delete-keys) lemma dom-clearjunk: fst ‘ set (clearjunk al) = fst ‘ set al using clearjunk-keys-set by simp lemma distinct-clearjunk [simp]: distinct (map fst (clearjunk al)) by (induct al rule: clearjunk.induct)(simp-all del: set-map add: clearjunk-keys-set delete-keys) lemma ran-clearjunk: ran (map-of (clearjunk al)) = ran (map-of al) 433 by (simp add: map-of-clearjunk) lemma ran-map-of : ran (map-of al) = snd ‘ set (clearjunk al) proof − have ran (map-of al) = ran (map-of (clearjunk al)) by (simp add: ran-clearjunk) also have ... = snd ‘ set (clearjunk al) by (simp add: ran-distinct) finally show ?thesis . qed lemma clearjunk-update: clearjunk (update k v al) = update k v (clearjunk al) by (induct al rule: clearjunk.induct)(simp-all add: delete-update) lemma clearjunk-updates: clearjunk (updates ks vs al) = updates ks vs (clearjunk al) proof − have clearjunk ◦ fold (case-prod update)(zip ks vs) = fold (case-prod update)(zip ks vs) ◦ clearjunk by (rule fold-commute)(simp add: clearjunk-update case-prod-beta o-def ) then show ?thesis by (simp add: updates-def fun-eq-iff ) qed lemma clearjunk-delete: clearjunk (delete x al) = delete x (clearjunk al) by (induct al rule: clearjunk.induct)(auto simp add: delete-idem delete-twist) lemma clearjunk-restrict: clearjunk (restrict A al) = restrict A (clearjunk al) by (induct al rule: clearjunk.induct)(auto simp add: restr-delete-twist) lemma distinct-clearjunk-id [simp]: distinct (map fst al) =⇒ clearjunk al = al by (induct al rule: clearjunk.induct) auto lemma clearjunk-idem: clearjunk (clearjunk al) = clearjunk al by simp lemma length-clearjunk: length (clearjunk al) ≤ length al proof (induct al rule: clearjunk.induct [case-names Nil Cons]) case Nil then show ?case by simp next case (Cons kv al) moreover have length (delete (fst kv) al) ≤ length al by (fact length-delete-le) ultimately have length (clearjunk (delete (fst kv) al)) ≤ length al by (rule order-trans) then show ?case by simp qed 434 lemma delete-map: assumes Vkv. fst (f kv) = fst kv shows delete k (map f ps) = map f (delete k ps) by (simp add: delete-eq filter-map comp-def split-def assms) lemma clearjunk-map: assumes Vkv. fst (f kv) = fst kv shows clearjunk (map f ps) = map f (clearjunk ps) by (induct ps rule: clearjunk.induct [case-names Nil Cons]) (simp-all add: clearjunk-delete delete-map assms) 57.6 map-ran definition map-ran :: ( 0key ⇒ 0val ⇒ 0val) ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where map-ran f = map (λ(k, v). (k, f k v)) lemma map-ran-simps [simp]: map-ran f [] = [] map-ran f ((k, v)# ps) = (k, f k v)# map-ran f ps by (simp-all add: map-ran-def ) lemma dom-map-ran: fst ‘ set (map-ran f al) = fst ‘ set al by (simp add: map-ran-def image-image split-def ) lemma map-ran-conv: map-of (map-ran f al) k = map-option (f k)(map-of al k) by (induct al) auto lemma distinct-map-ran: distinct (map fst al) =⇒ distinct (map fst (map-ran f al)) by (simp add: map-ran-def split-def comp-def ) lemma map-ran-filter: map-ran f [p←ps. fst p 6= a] = [p←map-ran f ps. fst p 6= a] by (simp add: map-ran-def filter-map split-def comp-def ) lemma clearjunk-map-ran: clearjunk (map-ran f al) = map-ran f (clearjunk al) by (simp add: map-ran-def split-def clearjunk-map) 57.7 merge qualified definition merge :: ( 0key × 0val) list ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where merge qs ps = foldr (λ(k, v). update k v) ps qs lemma merge-simps [simp]: merge qs [] = qs merge qs (p#ps) = update (fst p)(snd p)(merge qs ps) by (simp-all add: merge-def split-def ) 435 lemma merge-updates: merge qs ps = updates (rev (map fst ps)) (rev (map snd ps)) qs by (simp add: merge-def updates-def foldr-conv-fold zip-rev zip-map-fst-snd) lemma dom-merge: fst ‘ set (merge xs ys) = fst ‘ set xs ∪ fst ‘ set ys by (induct ys arbitrary: xs)(auto simp add: dom-update) lemma distinct-merge: distinct (map fst xs) =⇒ distinct (map fst (merge xs ys)) by (simp add: merge-updates distinct-updates) lemma clearjunk-merge: clearjunk (merge xs ys) = merge (clearjunk xs) ys by (simp add: merge-updates clearjunk-updates) lemma merge-conv 0: map-of (merge xs ys) = map-of xs ++ map-of ys proof − have map-of ◦ fold (case-prod update)(rev ys) = fold (λ(k, v) m. m(k 7→ v)) (rev ys) ◦ map-of by (rule fold-commute)(simp add: update-conv 0 case-prod-beta split-def fun-eq-iff ) then show ?thesis by (simp add: merge-def map-add-map-of-foldr foldr-conv-fold fun-eq-iff ) qed corollary merge-conv: map-of (merge xs ys) k = (map-of xs ++ map-of ys) k by (simp add: merge-conv 0) lemma merge-empty: map-of (merge [] ys) = map-of ys by (simp add: merge-conv 0) lemma merge-assoc [simp]: map-of (merge m1 (merge m2 m3 )) = map-of (merge (merge m1 m2 ) m3 ) by (simp add: merge-conv 0) lemma merge-Some-iff : map-of (merge m n) k = Some x ←→ map-of n k = Some x ∨ map-of n k = None ∧ map-of m k = Some x by (simp add: merge-conv 0 map-add-Some-iff ) lemmas merge-SomeD [dest!] = merge-Some-iff [THEN iffD1 ] lemma merge-find-right [simp]: map-of n k = Some v =⇒ map-of (merge m n) k = Some v by (simp add: merge-conv 0) lemma merge-None [iff ]: (map-of (merge m n) k = None) = (map-of n k = None ∧ map-of m k = None) by (simp add: merge-conv 0) lemma merge-upd [simp]: map-of (merge m (update k v n)) = map-of (update k 436 v (merge m n)) by (simp add: update-conv 0 merge-conv 0) lemma merge-updatess [simp]: map-of (merge m (updates xs ys n)) = map-of (updates xs ys (merge m n)) by (simp add: updates-conv 0 merge-conv 0) lemma merge-append: map-of (xs @ ys) = map-of (merge ys xs) by (simp add: merge-conv 0) 57.8 compose qualified function compose :: ( 0key × 0a) list ⇒ ( 0a × 0b) list ⇒ ( 0key × 0b) list where compose [] ys = [] | compose (x # xs) ys = (case map-of ys (snd x) of None ⇒ compose (delete (fst x) xs) ys | Some v ⇒ (fst x, v)# compose xs ys) by pat-completeness auto termination by (relation measure (length ◦ fst)) (simp-all add: less-Suc-eq-le length-delete-le) lemma compose-first-None [simp]: map-of xs k = None =⇒ map-of (compose xs ys) k = None by (induct xs ys rule: compose.induct)(auto split: option.splits if-split-asm) lemma compose-conv: map-of (compose xs ys) k = (map-of ys ◦m map-of xs) k proof (induct xs ys rule: compose.induct) case 1 then show ?case by simp next case (2 x xs ys) show ?case proof (cases map-of ys (snd x)) case None with 2 have hyp: map-of (compose (delete (fst x) xs) ys) k = (map-of ys ◦m map-of (delete (fst x) xs)) k by simp show ?thesis proof (cases fst x = k) case True from True delete-notin-dom [of k xs] have map-of (delete (fst x) xs) k = None by (simp add: map-of-eq-None-iff ) with hyp show ?thesis using True None by simp next 437 case False from False have map-of (delete (fst x) xs) k = map-of xs k by simp with hyp show ?thesis using False None by (simp add: map-comp-def ) qed next case (Some v) with 2 have map-of (compose xs ys) k = (map-of ys ◦m map-of xs) k by simp with Some show ?thesis by (auto simp add: map-comp-def ) qed qed 0 lemma compose-conv : map-of (compose xs ys) = (map-of ys ◦m map-of xs) by (rule ext)(rule compose-conv) lemma compose-first-Some [simp]: map-of xs k = Some v =⇒ map-of (compose xs ys) k = map-of ys v by (simp add: compose-conv) lemma dom-compose: fst ‘ set (compose xs ys) ⊆ fst ‘ set xs proof (induct xs ys rule: compose.induct) case 1 then show ?case by simp next case (2 x xs ys) show ?case proof (cases map-of ys (snd x)) case None with 2 .hyps have fst ‘ set (compose (delete (fst x) xs) ys) ⊆ fst ‘ set (delete (fst x) xs) by simp also have ... ⊆ fst ‘ set xs by (rule dom-delete-subset) finally show ?thesis using None by auto next case (Some v) with 2 .hyps have fst ‘ set (compose xs ys) ⊆ fst ‘ set xs by simp with Some show ?thesis by auto qed qed lemma distinct-compose: 438 assumes distinct (map fst xs) shows distinct (map fst (compose xs ys)) using assms proof (induct xs ys rule: compose.induct) case 1 then show ?case by simp next case (2 x xs ys) show ?case proof (cases map-of ys (snd x)) case None with 2 show ?thesis by simp next case (Some v) with 2 dom-compose [of xs ys] show ?thesis by auto qed qed lemma compose-delete-twist: compose (delete k xs) ys = delete k (compose xs ys) proof (induct xs ys rule: compose.induct) case 1 then show ?case by simp next case (2 x xs ys) show ?case proof (cases map-of ys (snd x)) case None with 2 have hyp: compose (delete k (delete (fst x) xs)) ys = delete k (compose (delete (fst x) xs) ys) by simp show ?thesis proof (cases fst x = k) case True with None hyp show ?thesis by (simp add: delete-idem) next case False from None False hyp show ?thesis by (simp add: delete-twist) qed next case (Some v) with 2 have hyp: compose (delete k xs) ys = delete k (compose xs ys) by simp with Some show ?thesis by simp qed qed 439 lemma compose-clearjunk: compose xs (clearjunk ys) = compose xs ys by (induct xs ys rule: compose.induct) (auto simp add: map-of-clearjunk split: option.splits) lemma clearjunk-compose: clearjunk (compose xs ys) = compose (clearjunk xs) ys by (induct xs rule: clearjunk.induct) (auto split: option.splits simp add: clearjunk-delete delete-idem compose-delete-twist) lemma compose-empty [simp]: compose xs [] = [] by (induct xs)(auto simp add: compose-delete-twist) lemma compose-Some-iff : (map-of (compose xs ys) k = Some v) ←→ (∃ k 0. map-of xs k = Some k 0 ∧ map-of ys k 0 = Some v) by (simp add: compose-conv map-comp-Some-iff ) lemma map-comp-None-iff : map-of (compose xs ys) k = None ←→ (map-of xs k = None ∨ (∃ k 0. map-of xs k = Some k 0 ∧ map-of ys k 0 = None)) by (simp add: compose-conv map-comp-None-iff ) 57.9 map-entry qualified fun map-entry :: 0key ⇒ ( 0val ⇒ 0val) ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where map-entry k f [] = [] | map-entry k f (p # ps) = (if fst p = k then (k, f (snd p)) # ps else p # map-entry k f ps) lemma map-of-map-entry: map-of (map-entry k f xs) = (map-of xs)(k := case map-of xs k of None ⇒ None | Some v 0 ⇒ Some (f v 0)) by (induct xs) auto lemma dom-map-entry: fst ‘ set (map-entry k f xs) = fst ‘ set xs by (induct xs) auto lemma distinct-map-entry: assumes distinct (map fst xs) shows distinct (map fst (map-entry k f xs)) using assms by (induct xs)(auto simp add: dom-map-entry) 57.10 map-default fun map-default :: 0key ⇒ 0val ⇒ ( 0val ⇒ 0val) ⇒ ( 0key × 0val) list ⇒ ( 0key × 0val) list where map-default k v f [] = [(k, v)] 440 | map-default k v f (p # ps) = (if fst p = k then (k, f (snd p)) # ps else p # map-default k v f ps) lemma map-of-map-default: map-of (map-default k v f xs) = (map-of xs)(k := case map-of xs k of None ⇒ Some v | Some v 0 ⇒ Some (f v 0)) by (induct xs) auto lemma dom-map-default: fst ‘ set (map-default k v f xs) = insert k (fst ‘ set xs) by (induct xs) auto lemma distinct-map-default: assumes distinct (map fst xs) shows distinct (map fst (map-default k v f xs)) using assms by (induct xs)(auto simp add: dom-map-default) end end 58 An abstract view on maps for code generation. theory Mapping imports Main begin 58.1 Parametricity transfer rules lemma map-of-foldr: map-of xs = foldr (λ(k, v) m. m(k 7→ v)) xs Map.empty using map-add-map-of-foldr [of Map.empty] by auto context includes lifting-syntax begin lemma empty-parametric:(A ===> rel-option B) Map.empty Map.empty by transfer-prover lemma lookup-parametric: ((A ===> B) ===> A ===> B)(λm k. m k)(λm k. m k) by transfer-prover lemma update-parametric: assumes [transfer-rule]: bi-unique A shows (A ===> B ===> (A ===> rel-option B) ===> A ===> rel-option B) (λk v m. m(k 7→ v)) (λk v m. m(k 7→ v)) by transfer-prover 441 lemma delete-parametric: assumes [transfer-rule]: bi-unique A shows (A ===> (A ===> rel-option B) ===> A ===> rel-option B) (λk m. m(k := None)) (λk m. m(k := None)) by transfer-prover lemma is-none-parametric [transfer-rule]: (rel-option A ===> HOL.eq) Option.is-none Option.is-none by (auto simp add: Option.is-none-def rel-fun-def rel-option-iff split: option.split) lemma dom-parametric: assumes [transfer-rule]: bi-total A shows ((A ===> rel-option B) ===> rel-set A) dom dom unfolding dom-def [abs-def ] Option.is-none-def [symmetric] by transfer-prover lemma map-of-parametric [transfer-rule]: assumes [transfer-rule]: bi-unique R1 shows (list-all2 (rel-prod R1 R2 ) ===> R1 ===> rel-option R2 ) map-of map-of unfolding map-of-def by transfer-prover lemma map-entry-parametric [transfer-rule]: assumes [transfer-rule]: bi-unique A shows (A ===> (B ===> B) ===> (A ===> rel-option B) ===> A ===> rel-option B) (λk f m. (case m k of None ⇒ m | Some v ⇒ m (k 7→ (f v)))) (λk f m. (case m k of None ⇒ m | Some v ⇒ m (k 7→ (f v)))) by transfer-prover lemma tabulate-parametric: assumes [transfer-rule]: bi-unique A shows (list-all2 A ===> (A ===> B) ===> A ===> rel-option B) (λks f . (map-of (map (λk. (k, f k)) ks))) (λks f . (map-of (map (λk. (k, f k)) ks))) by transfer-prover lemma bulkload-parametric: (list-all2 A ===> HOL.eq ===> rel-option A) (λxs k. if k < length xs then Some (xs ! k) else None) (λxs k. if k < length xs then Some (xs ! k) else None) proof fix xs ys assume list-all2 A xs ys then show (HOL.eq ===> rel-option A) (λk. if k < length xs then Some (xs ! k) else None) (λk. if k < length ys then Some (ys ! k) else None) apply induct 442 apply auto unfolding rel-fun-def apply clarsimp apply (case-tac xa) apply (auto dest: list-all2-lengthD list-all2-nthD) done qed lemma map-parametric: ((A ===> B) ===> (C ===> D) ===> (B ===> rel-option C ) ===> A ===> rel-option D) (λf g m. (map-option g ◦ m ◦ f )) (λf g m. (map-option g ◦ m ◦ f )) by transfer-prover lemma combine-with-key-parametric: ((A ===> B ===> B ===> B) ===> (A ===> rel-option B) ===> (A ===> rel-option B) ===> (A ===> rel-option B)) (λf m1 m2 x. combine-options (f x)(m1 x)(m2 x)) (λf m1 m2 x. combine-options (f x)(m1 x)(m2 x)) unfolding combine-options-def by transfer-prover lemma combine-parametric: ((B ===> B ===> B) ===> (A ===> rel-option B) ===> (A ===> rel-option B) ===> (A ===> rel-option B)) (λf m1 m2 x. combine-options f (m1 x)(m2 x)) (λf m1 m2 x. combine-options f (m1 x)(m2 x)) unfolding combine-options-def by transfer-prover end 58.2 Type definition and primitive operations typedef ( 0a, 0b) mapping = UNIV :: ( 0a * 0b) set morphisms rep Mapping .. setup-lifting type-definition-mapping lift-definition empty :: ( 0a, 0b) mapping is Map.empty parametric empty-parametric . lift-definition lookup :: ( 0a, 0b) mapping ⇒ 0a ⇒ 0b option is λm k. m k parametric lookup-parametric . definition lookup-default d m k = (case Mapping.lookup m k of None ⇒ d | Some v ⇒ v) declare [[code drop: Mapping.lookup]] setup hCode.add-eqn (Code.Equation, true)@{thm Mapping.lookup.abs-eq}i 443 lift-definition update :: 0a ⇒ 0b ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping is λk v m. m(k 7→ v) parametric update-parametric . lift-definition delete :: 0a ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping is λk m. m(k := None) parametric delete-parametric . lift-definition filter :: ( 0a ⇒ 0b ⇒ bool) ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping is λP m k. case m k of None ⇒ None | Some v ⇒ if P k v then Some v else None . lift-definition keys :: ( 0a, 0b) mapping ⇒ 0a set is dom parametric dom-parametric . lift-definition tabulate :: 0a list ⇒ ( 0a ⇒ 0b) ⇒ ( 0a, 0b) mapping is λks f . (map-of (List.map (λk. (k, f k)) ks)) parametric tabulate-parametric . lift-definition bulkload :: 0a list ⇒ (nat, 0a) mapping is λxs k. if k < length xs then Some (xs ! k) else None parametric bulkload-parametric . lift-definition map :: ( 0c ⇒ 0a) ⇒ ( 0b ⇒ 0d) ⇒ ( 0a, 0b) mapping ⇒ ( 0c, 0d) mapping is λf g m. (map-option g ◦ m ◦ f ) parametric map-parametric . lift-definition map-values :: ( 0c ⇒ 0a ⇒ 0b) ⇒ ( 0c, 0a) mapping ⇒ ( 0c, 0b) mapping is λf m x. map-option (f x)(m x) . lift-definition combine-with-key :: ( 0a ⇒ 0b ⇒ 0b ⇒ 0b) ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping is λf m1 m2 x. combine-options (f x)(m1 x)(m2 x) parametric combine-with-key-parametric . lift-definition combine :: ( 0b ⇒ 0b ⇒ 0b) ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping is λf m1 m2 x. combine-options f (m1 x)(m2 x) parametric combine-parametric . definition All-mapping m P ←→ (∀ x. case Mapping.lookup m x of None ⇒ True | Some y ⇒ P x y) declare [[code drop: map]] 58.3 Functorial structure functor map: map by (transfer, auto simp add: fun-eq-iff option.map-comp option.map-id)+ 444 58.4 Derived operations definition ordered-keys :: ( 0a::linorder, 0b) mapping ⇒ 0a list where ordered-keys m = (if finite (keys m) then sorted-list-of-set (keys m) else []) definition is-empty :: ( 0a, 0b) mapping ⇒ bool where is-empty m ←→ keys m = {} definition size :: ( 0a, 0b) mapping ⇒ nat where size m = (if finite (keys m) then card (keys m) else 0 ) definition replace :: 0a ⇒ 0b ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping where replace k v m = (if k ∈ keys m then update k v m else m) definition default :: 0a ⇒ 0b ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping where default k v m = (if k ∈ keys m then m else update k v m) Manual derivation of transfer rule is non-trivial lift-definition map-entry :: 0a ⇒ ( 0b ⇒ 0b) ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping is λk f m. (case m k of None ⇒ m | Some v ⇒ m (k 7→ (f v))) parametric map-entry-parametric . lemma map-entry-code [code]: map-entry k f m = (case lookup m k of None ⇒ m | Some v ⇒ update k (f v) m) by transfer rule definition map-default :: 0a ⇒ 0b ⇒ ( 0b ⇒ 0b) ⇒ ( 0a, 0b) mapping ⇒ ( 0a, 0b) mapping where map-default k v f m = map-entry k f (default k v m) definition of-alist :: ( 0k × 0v) list ⇒ ( 0k, 0v) mapping where of-alist xs = foldr (λ(k, v) m. update k v m) xs empty instantiation mapping :: (type, type) equal begin definition HOL.equal m1 m2 ←→ (∀ k. lookup m1 k = lookup m2 k) instance apply standard unfolding equal-mapping-def apply transfer apply auto 445 done end context includes lifting-syntax begin lemma [transfer-rule]: assumes [transfer-rule]: bi-total A and [transfer-rule]: bi-unique B shows (pcr-mapping A B ===> pcr-mapping A B ===> op=) HOL.eq HOL.equal unfolding equal by transfer-prover lemma of-alist-transfer [transfer-rule]: assumes [transfer-rule]: bi-unique R1 shows (list-all2 (rel-prod R1 R2 ) ===> pcr-mapping R1 R2 ) map-of of-alist unfolding of-alist-def [abs-def ] map-of-foldr [abs-def ] by transfer-prover end 58.5 Properties lemma mapping-eqI :(Vx. lookup m x = lookup m 0 x) =⇒ m = m 0 by transfer (simp add: fun-eq-iff ) lemma mapping-eqI 0: assumes Vx. x ∈ Mapping.keys m =⇒ Mapping.lookup-default d m x = Map- ping.lookup-default d m 0 x and Mapping.keys m = Mapping.keys m 0 shows m = m 0 proof (intro mapping-eqI ) show Mapping.lookup m x = Mapping.lookup m 0 x for x proof (cases Mapping.lookup m x) case None then have x ∈/ Mapping.keys m by transfer (simp add: dom-def ) then have x ∈/ Mapping.keys m 0 by (simp add: assms) then have Mapping.lookup m 0 x = None by transfer (simp add: dom-def ) with None show ?thesis by simp next case (Some y) then have A: x ∈ Mapping.keys m by transfer (simp add: dom-def ) then have x ∈ Mapping.keys m 0 by (simp add: assms) then have ∃ y 0. Mapping.lookup m 0 x = Some y 0 446 by transfer (simp add: dom-def ) with Some assms(1 )[OF A] show ?thesis by (auto simp add: lookup-default-def ) qed qed lemma lookup-update: lookup (update k v m) k = Some v by transfer simp lemma lookup-update-neq: k 6= k 0 =⇒ lookup (update k v m) k 0 = lookup m k 0 by transfer simp lemma lookup-update 0: Mapping.lookup (update k v m) k 0 = (if k = k 0 then Some v else lookup m k 0) by (auto simp: lookup-update lookup-update-neq) lemma lookup-empty: lookup empty k = None by transfer simp lemma lookup-filter: lookup (filter P m) k = (case lookup m k of None ⇒ None | Some v ⇒ if P k v then Some v else None) by transfer simp-all lemma lookup-map-values: lookup (map-values f m) k = map-option (f k)(lookup m k) by transfer simp-all lemma lookup-default-empty: lookup-default d empty k = d by (simp add: lookup-default-def lookup-empty) lemma lookup-default-update: lookup-default d (update k v m) k = v by (simp add: lookup-default-def lookup-update) lemma lookup-default-update-neq: k 6= k 0 =⇒ lookup-default d (update k v m) k 0 = lookup-default d m k 0 by (simp add: lookup-default-def lookup-update-neq) lemma lookup-default-update 0: lookup-default d (update k v m) k 0 = (if k = k 0 then v else lookup-default d m k 0) by (auto simp: lookup-default-update lookup-default-update-neq) lemma lookup-default-filter: lookup-default d (filter P m) k = (if P k (lookup-default d m k) then lookup-default d m k else d) by (simp add: lookup-default-def lookup-filter split: option.splits) 447 lemma lookup-default-map-values: lookup-default (f k d)(map-values f m) k = f k (lookup-default d m k) by (simp add: lookup-default-def lookup-map-values split: option.splits) lemma lookup-combine-with-key: Mapping.lookup (combine-with-key f m1 m2 ) x = combine-options (f x)(Mapping.lookup m1 x)(Mapping.lookup m2 x) by transfer (auto split: option.splits) lemma combine-altdef : combine f m1 m2 = combine-with-key (λ-. f ) m1 m2 by transfer 0 (rule refl) lemma lookup-combine: Mapping.lookup (combine f m1 m2 ) x = combine-options f (Mapping.lookup m1 x)(Mapping.lookup m2 x) by transfer (auto split: option.splits) lemma lookup-default-neutral-combine-with-key: assumes Vx. f k d x = x Vx. f k x d = x shows Mapping.lookup-default d (combine-with-key f m1 m2 ) k = f k (Mapping.lookup-default d m1 k)(Mapping.lookup-default d m2 k) by (auto simp: lookup-default-def lookup-combine-with-key assms split: option.splits) lemma lookup-default-neutral-combine: assumes Vx. f d x = x Vx. f x d = x shows Mapping.lookup-default d (combine f m1 m2 ) x = f (Mapping.lookup-default d m1 x)(Mapping.lookup-default d m2 x) by (auto simp: lookup-default-def lookup-combine assms split: option.splits) lemma lookup-map-entry: lookup (map-entry x f m) x = map-option f (lookup m x) by transfer (auto split: option.splits) lemma lookup-map-entry-neq: x 6= y =⇒ lookup (map-entry x f m) y = lookup m y by transfer (auto split: option.splits) lemma lookup-map-entry 0: lookup (map-entry x f m) y = (if x = y then map-option f (lookup m y) else lookup m y) by transfer (auto split: option.splits) lemma lookup-default: lookup (default x d m) x = Some (lookup-default d m x) unfolding lookup-default-def default-def by transfer (auto split: option.splits) lemma lookup-default-neq: x 6= y =⇒ lookup (default x d m) y = lookup m y unfolding lookup-default-def default-def by transfer (auto split: option.splits) 448 lemma lookup-default 0: lookup (default x d m) y = (if x = y then Some (lookup-default d m x) else lookup m y) unfolding lookup-default-def default-def by transfer (auto split: option.splits) lemma lookup-map-default: lookup (map-default x d f m) x = Some (f (lookup-default d m x)) unfolding lookup-default-def default-def by (simp add: map-default-def lookup-map-entry lookup-default lookup-default-def ) lemma lookup-map-default-neq: x 6= y =⇒ lookup (map-default x d f m) y = lookup m y unfolding lookup-default-def default-def by (simp add: map-default-def lookup-map-entry-neq lookup-default-neq) lemma lookup-map-default 0: lookup (map-default x d f m) y = (if x = y then Some (f (lookup-default d m x)) else lookup m y) unfolding lookup-default-def default-def by (simp add: map-default-def lookup-map-entry 0 lookup-default 0 lookup-default-def ) lemma lookup-tabulate: assumes distinct xs shows Mapping.lookup (Mapping.tabulate xs f ) x = (if x ∈ set xs then Some (f x) else None) using assms by transfer (auto simp: map-of-eq-None-iff o-def dest!: map-of-SomeD) lemma lookup-of-alist: Mapping.lookup (Mapping.of-alist xs) k = map-of xs k by transfer simp-all lemma keys-is-none-rep [code-unfold]: k ∈ keys m ←→ ¬ (Option.is-none (lookup m k)) by transfer (auto simp add: Option.is-none-def ) lemma update-update: update k v (update k w m) = update k v m k 6= l =⇒ update k v (update l w m) = update l w (update k v m) by (transfer; simp add: fun-upd-twist)+ lemma update-delete [simp]: update k v (delete k m) = update k v m by transfer simp lemma delete-update: delete k (update k v m) = delete k m k 6= l =⇒ delete k (update l v m) = update l v (delete k m) by (transfer; simp add: fun-upd-twist)+ 449 lemma delete-empty [simp]: delete k empty = empty by transfer simp lemma replace-update: k ∈/ keys m =⇒ replace k v m = m k ∈ keys m =⇒ replace k v m = update k v m by (transfer; auto simp add: replace-def fun-upd-twist)+ lemma map-values-update: map-values f (update k v m) = update k (f k v)(map-values f m) by transfer (simp-all add: fun-eq-iff ) lemma size-mono: finite (keys m 0) =⇒ keys m ⊆ keys m 0 =⇒ size m ≤ size m 0 unfolding size-def by (auto intro: card-mono) lemma size-empty [simp]: size empty = 0 unfolding size-def by transfer simp lemma size-update: finite (keys m) =⇒ size (update k v m) = (if k ∈ keys m then size m else Suc (size m)) unfolding size-def by transfer (auto simp add: insert-dom) lemma size-delete: size (delete k m) = (if k ∈ keys m then size m − 1 else size m) unfolding size-def by transfer simp lemma size-tabulate [simp]: size (tabulate ks f ) = length (remdups ks) unfolding size-def by transfer (auto simp add: map-of-map-restrict card-set comp-def ) lemma keys-filter: keys (filter P m) ⊆ keys m by transfer (auto split: option.splits) lemma size-filter: finite (keys m) =⇒ size (filter P m) ≤ size m by (intro size-mono keys-filter) lemma bulkload-tabulate: bulkload xs = tabulate [0 .. 450 lemma is-empty-replace [simp]: is-empty (replace k v m) ←→ is-empty m unfolding is-empty-def replace-def by transfer auto lemma is-empty-default [simp]: ¬ is-empty (default k v m) unfolding is-empty-def default-def by transfer auto lemma is-empty-map-entry [simp]: is-empty (map-entry k f m) ←→ is-empty m unfolding is-empty-def by transfer (auto split: option.split) lemma is-empty-map-values [simp]: is-empty (map-values f m) ←→ is-empty m unfolding is-empty-def by transfer (auto simp: fun-eq-iff ) lemma is-empty-map-default [simp]: ¬ is-empty (map-default k v f m) by (simp add: map-default-def ) lemma keys-dom-lookup: keys m = dom (Mapping.lookup m) by transfer rule lemma keys-empty [simp]: keys empty = {} by transfer simp lemma keys-update [simp]: keys (update k v m) = insert k (keys m) by transfer simp lemma keys-delete [simp]: keys (delete k m) = keys m − {k} by transfer simp lemma keys-replace [simp]: keys (replace k v m) = keys m unfolding replace-def by transfer (simp add: insert-absorb) lemma keys-default [simp]: keys (default k v m) = insert k (keys m) unfolding default-def by transfer (simp add: insert-absorb) lemma keys-map-entry [simp]: keys (map-entry k f m) = keys m by transfer (auto split: option.split) lemma keys-map-default [simp]: keys (map-default k v f m) = insert k (keys m) by (simp add: map-default-def ) lemma keys-map-values [simp]: keys (map-values f m) = keys m by transfer (simp-all add: dom-def ) lemma keys-combine-with-key [simp]: Mapping.keys (combine-with-key f m1 m2 ) = Mapping.keys m1 ∪ Mapping.keys m2 by transfer (auto simp: dom-def combine-options-def split: option.splits) lemma keys-combine [simp]: Mapping.keys (combine f m1 m2 ) = Mapping.keys m1 ∪ Mapping.keys m2 451 by (simp add: combine-altdef ) lemma keys-tabulate [simp]: keys (tabulate ks f ) = set ks by transfer (simp add: map-of-map-restrict o-def ) lemma keys-of-alist [simp]: keys (of-alist xs) = set (List.map fst xs) by transfer (simp-all add: dom-map-of-conv-image-fst) lemma keys-bulkload [simp]: keys (bulkload xs) = {0 .. 452 by (simp add: replace-def ) lemma ordered-keys-default [simp]: k ∈ keys m =⇒ ordered-keys (default k v m) = ordered-keys m finite (keys m) =⇒ k ∈/ keys m =⇒ ordered-keys (default k v m) = insort k (ordered-keys m) by (simp-all add: default-def ) lemma ordered-keys-map-entry [simp]: ordered-keys (map-entry k f m) = ordered-keys m by (simp add: ordered-keys-def ) lemma ordered-keys-map-default [simp]: k ∈ keys m =⇒ ordered-keys (map-default k v f m) = ordered-keys m finite (keys m) =⇒ k ∈/ keys m =⇒ ordered-keys (map-default k v f m) = insort k (ordered-keys m) by (simp-all add: map-default-def ) lemma ordered-keys-tabulate [simp]: ordered-keys (tabulate ks f ) = sort (remdups ks) by (simp add: ordered-keys-def sorted-list-of-set-sort-remdups) lemma ordered-keys-bulkload [simp]: ordered-keys (bulkload ks) = [0 .. 453 = k 0 ∨ P k 0 v 0) unfolding All-mapping-def proof safe assume ∀ x. case Mapping.lookup (Mapping.update k v m) x of None ⇒ True | Some y ⇒ P x y then have ∗: case Mapping.lookup (Mapping.update k v m) x of None ⇒ True | Some y ⇒ P x y for x by blast from ∗[of k] show P k v by (simp add: lookup-update) show case Mapping.lookup m x of None ⇒ True | Some v 0 ⇒ k = x ∨ P x v 0 for x using ∗[of x] by (auto simp add: lookup-update 0 split: if-splits option.splits) next assume P k v assume ∀ x. case Mapping.lookup m x of None ⇒ True | Some v 0 ⇒ k = x ∨ P x v 0 then have A: case Mapping.lookup m x of None ⇒ True | Some v 0 ⇒ k = x ∨ P x v 0 for x by blast show case Mapping.lookup (Mapping.update k v m) x of None ⇒ True | Some xa ⇒ P x xa for x 0 using hP k v i A[of x] by (auto simp: lookup-update split: option.splits) qed lemma All-mapping-update: P k v =⇒ All-mapping m (λk 0 v 0. k = k 0 ∨ P k 0 v 0) =⇒ All-mapping (Mapping.update k v m) P by (simp add: All-mapping-update-iff ) lemma All-mapping-filter-iff : All-mapping (filter P m) Q ←→ All-mapping m (λk v. P k v −→ Q k v) by (auto simp: All-mapping-def lookup-filter split: option.splits) lemma All-mapping-filter: All-mapping m Q =⇒ All-mapping (filter P m) Q by (auto simp: All-mapping-filter-iff intro: All-mapping-mono) lemma All-mapping-map-values: All-mapping (map-values f m) P ←→ All-mapping m (λk v. P k (f k v)) by (auto simp: All-mapping-def lookup-map-values split: option.splits) lemma All-mapping-tabulate:(∀ x∈set xs. P x (f x)) =⇒ All-mapping (Mapping.tabulate xs f ) P unfolding All-mapping-def apply (intro allI ) apply transfer apply (auto split: option.split dest!: map-of-SomeD) done 454 lemma All-mapping-alist: (Vk v. (k, v) ∈ set xs =⇒ P k v) =⇒ All-mapping (Mapping.of-alist xs) P by (auto simp: All-mapping-def lookup-of-alist dest!: map-of-SomeD split: op- tion.splits) lemma combine-empty [simp]: combine f Mapping.empty y = y combine f y Map- ping.empty = y by (transfer; force)+ lemma (in abel-semigroup) comm-monoid-set-combine: comm-monoid-set (combine f ) Mapping.empty by standard (transfer fixing: f , simp add: combine-options-ac[of f ] ac-simps)+ locale combine-mapping-abel-semigroup = abel-semigroup begin sublocale combine: comm-monoid-set combine f Mapping.empty by (rule comm-monoid-set-combine) lemma fold-combine-code: combine.F g (set xs) = foldr (λx. combine f (g x)) (remdups xs) Mapping.empty proof − have combine.F g (set xs) = foldr (λx. combine f (g x)) xs Mapping.empty if distinct xs for xs using that by (induction xs) simp-all from this[of remdups xs] show ?thesis by simp qed lemma keys-fold-combine: finite A =⇒ Mapping.keys (combine.F g A) = (S x∈A. Mapping.keys (g x)) by (induct A rule: finite-induct) simp-all end 58.6 Code generator setup hide-const (open) empty is-empty rep lookup lookup-default filter update delete ordered-keys keys size replace default map-entry map-default tabulate bulkload map map-values combine of-alist end 59 Implementation of mappings with Association Lists theory AList-Mapping imports AList Mapping 455 begin lift-definition Mapping :: ( 0a × 0b) list ⇒ ( 0a, 0b) mapping is map-of . code-datatype Mapping lemma lookup-Mapping [simp, code]: Mapping.lookup (Mapping xs) = map-of xs by transfer rule lemma keys-Mapping [simp, code]: Mapping.keys (Mapping xs) = set (map fst xs) by transfer (simp add: dom-map-of-conv-image-fst) lemma empty-Mapping [code]: Mapping.empty = Mapping [] by transfer simp lemma is-empty-Mapping [code]: Mapping.is-empty (Mapping xs) ←→ List.null xs by (cases xs)(simp-all add: is-empty-def null-def ) lemma update-Mapping [code]: Mapping.update k v (Mapping xs) = Mapping (AList.update k v xs) by transfer (simp add: update-conv 0) lemma delete-Mapping [code]: Mapping.delete k (Mapping xs) = Mapping (AList.delete k xs) by transfer (simp add: delete-conv 0) lemma ordered-keys-Mapping [code]: Mapping.ordered-keys (Mapping xs) = sort (remdups (map fst xs)) by (simp only: ordered-keys-def keys-Mapping sorted-list-of-set-sort-remdups) simp lemma size-Mapping [code]: Mapping.size (Mapping xs) = length (remdups (map fst xs)) by (simp add: size-def length-remdups-card-conv dom-map-of-conv-image-fst) lemma tabulate-Mapping [code]: Mapping.tabulate ks f = Mapping (map (λk. (k, f k)) ks) by transfer (simp add: map-of-map-restrict) lemma bulkload-Mapping [code]: Mapping.bulkload vs = Mapping (map (λn. (n, vs ! n)) [0 .. 456 proof − have ∗:(a, b) ∈ set xs =⇒ a ∈ fst ‘ set xs for a b xs by (auto simp add: image-def intro!: bexI ) show ?thesis apply transfer apply (auto intro!: map-of-eqI ) apply (auto dest!: map-of-eq-dom intro: ∗) done qed lemma map-values-Mapping [code]: Mapping.map-values f (Mapping xs) = Mapping (map (λ(x,y). (x, f x y)) xs) for f :: 0c ⇒ 0a ⇒ 0b and xs :: ( 0c × 0a) list apply transfer apply (rule ext) subgoal for f xs x by (induct xs) auto done lemma combine-with-key-code [code]: Mapping.combine-with-key f (Mapping xs)(Mapping ys) = Mapping.tabulate (remdups (map fst xs @ map fst ys)) (λx. the (combine-options (f x)(map-of xs x)(map-of ys x))) apply transfer apply (rule ext) apply (rule sym) subgoal for f xs ys x apply (cases map-of xs x; cases map-of ys x; simp) apply (force simp: map-of-eq-None-iff combine-options-def option.the-def o-def image-iff dest: map-of-SomeD split: option.splits)+ done done lemma combine-code [code]: Mapping.combine f (Mapping xs)(Mapping ys) = Mapping.tabulate (remdups (map fst xs @ map fst ys)) (λx. the (combine-options f (map-of xs x)(map-of ys x))) apply transfer apply (rule ext) apply (rule sym) subgoal for f xs ys x apply (cases map-of xs x; cases map-of ys x; simp) apply (force simp: map-of-eq-None-iff combine-options-def option.the-def o-def image-iff dest: map-of-SomeD split: option.splits)+ done done lemma map-of-filter-distinct: 457 assumes distinct (map fst xs) shows map-of (filter P xs) x = (case map-of xs x of None ⇒ None | Some y ⇒ if P (x,y) then Some y else None) using assms by (auto simp: map-of-eq-None-iff filter-map distinct-map-filter dest: map-of-SomeD simp del: map-of-eq-Some-iff intro!: map-of-is-SomeI split: option.splits) lemma filter-Mapping [code]: Mapping.filter P (Mapping xs) = Mapping (filter (λ(k,v). P k v)(AList.clearjunk xs)) apply transfer apply (rule ext) apply (subst map-of-filter-distinct) apply (simp-all add: map-of-clearjunk split: option.split) done lemma [code nbe]: HOL.equal (x :: ( 0a, 0b) mapping) x ←→ True by (fact equal-refl) end 60 A simple cookbook example how to eliminate choice in programs. theory Execute-Choice imports Main ∼∼/src/HOL/Library/AList-Mapping begin A trivial example: definition valuesum :: ( 0a, 0b :: ab-group-add) mapping ⇒ 0b where valuesum m = (P k ∈ Mapping.keys m. the (Mapping.lookup m k)) Not that instead of defining valuesum with choice, we define it directly and derive a description involving choice afterwards: lemma valuesum-rec: assumes fin: finite (dom (Mapping.lookup m)) shows valuesum m = (if Mapping.is-empty m then 0 else let l = (SOME l. l ∈ Mapping.keys m) in the (Mapping.lookup m l) + valuesum (Mapping.delete l m)) proof (cases Mapping.is-empty m) case True then show ?thesis by (simp add: is-empty-def keys-def valuesum-def ) next case False then have l: ∃ l. l ∈ dom (Mapping.lookup m) unfolding is-empty-def by transfer auto then have (let l = SOME l. l ∈ dom (Mapping.lookup m) in 458 the (Mapping.lookup m l) + (P k ∈ dom (Mapping.lookup m) − {l}. the (Mapping.lookup m k))) = (P k ∈ dom (Mapping.lookup m). the (Mapping.lookup m k)) proof (rule someI2-ex) fix l note fin moreover assume l ∈ dom (Mapping.lookup m) moreover obtain A where A = dom (Mapping.lookup m) − {l} by simp ultimately have dom (Mapping.lookup m) = insert l A and finite A and l ∈/ A by auto then show (let l = l in the (Mapping.lookup m l) + (P k ∈ dom (Mapping.lookup m) − {l}. the (Mapping.lookup m k))) = (P k ∈ dom (Mapping.lookup m). the (Mapping.lookup m k)) by simp qed then show ?thesis unfolding is-empty-def valuesum-def by transfer simp qed In the context of the else-branch we can show that the exact choice is irrel- vant; in practice, finding this point where choice becomes irrelevant is the most difficult thing! lemma valuesum-choice: finite (Mapping.keys M ) =⇒ x ∈ Mapping.keys M =⇒ y ∈ Mapping.keys M =⇒ the (Mapping.lookup M x) + valuesum (Mapping.delete x M ) = the (Mapping.lookup M y) + valuesum (Mapping.delete y M ) unfolding valuesum-def by transfer (simp add: sum-diff ) Given valuesum-rec as initial description, we stepwise refine it to something executable; first, we formally insert the constructor AList-Mapping.Mapping and split the one equation into two, where the second one provides the necessary context: lemma valuesum-rec-Mapping: shows [code]: valuesum (Mapping []) = 0 and valuesum (Mapping (x # xs)) = (let l = (SOME l. l ∈ Mapping.keys (Mapping (x # xs))) in the (Mapping.lookup (Mapping (x # xs)) l) + valuesum (Mapping.delete l (Mapping (x # xs)))) by (simp-all add: valuesum-rec finite-dom-map-of is-empty-Mapping null-def ) As a side effect the precondition disappears (but note this has nothing to do with choice!). The first equation deals with the uncritical empty case and can already be used for code generation. Using valuesum-choice, we are able to prove an executable version of value- sum: lemma valuesum-rec-exec [code]: valuesum (Mapping (x # xs)) = (let l = fst (hd (x # xs)) in 459 the (Mapping.lookup (Mapping (x # xs)) l) + valuesum (Mapping.delete l (Mapping (x # xs)))) proof − let ?M = Mapping (x # xs) let ?l1 = (SOME l. l ∈ Mapping.keys ?M ) let ?l2 = fst (hd (x # xs)) have finite (Mapping.keys ?M ) by (simp add: keys-Mapping) moreover have ?l1 ∈ Mapping.keys ?M by (rule someI )(auto simp add: keys-Mapping) moreover have ?l2 ∈ Mapping.keys ?M by (simp add: keys-Mapping) ultimately have the (Mapping.lookup ?M ?l1 ) + valuesum (Mapping.delete ?l1 ?M ) = the (Mapping.lookup ?M ?l2 ) + valuesum (Mapping.delete ?l2 ?M ) by (rule valuesum-choice) then show ?thesis by (simp add: valuesum-rec-Mapping) qed See how it works: value valuesum (Mapping [( 00abc 00, (42 ::int)), ( 00def 00, 1705 )]) end 61 Theory of Integration on real intervals theory Gauge-Integration imports Complex-Main begin Attention: This theory defines the Integration on real intervals. This is just a example theory for historical / expository interests. A better replacement is found in the Multivariate Analysis library. This defines the gauge integral on real vector spaces and in the Real Integral theory is a specialization to the integral on arbitrary real intervals. The Multivariate Analysis package also provides a better support for analysis on integrals. We follow John Harrison in formalizing the Gauge integral. 61.1 Gauges definition gauge :: [real set, real => real] => bool where gauge E g = (∀ x∈E. 0 < g(x)) 61.2 Gauge-fine divisions inductive fine :: [real ⇒ real, real × real, (real × real × real) list] ⇒ bool 460 for δ :: real ⇒ real where fine-Nil: fine δ (a, a) [] | fine-Cons: [[fine δ (b, c) D; a < b; a ≤ x; x ≤ b; b − a < δ x]] =⇒ fine δ (a, c) ((a, x, b)# D) lemmas fine-induct [induct set: fine] = fine.induct [of δ (a,b) D case-prod P, unfolded split-conv] for δ a b D P lemma fine-single: [[a < b; a ≤ x; x ≤ b; b − a < δ x]] =⇒ fine δ (a, b) [(a, x, b)] by (rule fine-Cons [OF fine-Nil]) lemma fine-append: [[fine δ (a, b) D; fine δ (b, c) D 0]] =⇒ fine δ (a, c)(D @ D 0) by (induct set: fine, simp, simp add: fine-Cons) lemma fine-imp-le: fine δ (a, b) D =⇒ a ≤ b by (induct set: fine, simp-all) lemma nonempty-fine-imp-less: [[fine δ (a, b) D; D 6= []]] =⇒ a < b apply (induct set: fine, simp) apply (drule fine-imp-le, simp) done lemma fine-Nil-iff : fine δ (a, b) [] ←→ a = b by (auto elim: fine.cases intro: fine.intros) lemma fine-same-iff : fine δ (a, a) D ←→ D = [] proof assume fine δ (a, a) D thus D = [] by (metis nonempty-fine-imp-less less-irrefl) next assume D = [] thus fine δ (a, a) D by (simp add: fine-Nil) qed lemma empty-fine-imp-eq: [[fine δ (a, b) D; D = []]] =⇒ a = b by (simp add: fine-Nil-iff ) lemma mem-fine: [[fine δ (a, b) D;(u, x, v) ∈ set D]] =⇒ u < v ∧ u ≤ x ∧ x ≤ v by (induct set: fine, simp, force) lemma mem-fine2 : [[fine δ (a, b) D;(u, z, v) ∈ set D]] =⇒ a ≤ u ∧ v ≤ b apply (induct arbitrary: z u v set: fine, auto) 461 apply (simp add: fine-imp-le) apply (erule order-trans [OF less-imp-le], simp) done lemma mem-fine3 : [[fine δ (a, b) D;(u, z, v) ∈ set D]] =⇒ v − u < δ z by (induct arbitrary: z u v set: fine) auto lemma BOLZANO: fixes P :: real ⇒ real ⇒ bool assumes 1 : a ≤ b assumes 2 : Va b c. [[P a b; P b c; a ≤ b; b ≤ c]] =⇒ P a c assumes 3 : Vx. ∃ d>0 . ∀ a b. a ≤ x & x ≤ b &(b−a) < d −→ P a b shows P a b using 1 2 3 by (rule Bolzano) We can always find a division that is fine wrt any gauge lemma fine-exists: assumes a ≤ b and gauge {a..b} δ shows ∃ D. fine δ (a, b) D proof − { fix u v :: real assume u ≤ v have a ≤ u =⇒ v ≤ b =⇒ ∃ D. fine δ (u, v) D apply (induct u v rule: BOLZANO, rule hu ≤ v i) apply (simp, fast intro: fine-append) apply (case-tac a ≤ x ∧ x ≤ b) apply (rule-tac x=δ x in exI ) apply (rule conjI ) apply (simp add: hgauge {a..b} δi [unfolded gauge-def ]) apply (clarify, rename-tac u v) apply (case-tac u = v) apply (fast intro: fine-Nil) apply (subgoal-tac u < v, fast intro: fine-single, simp) apply (rule-tac x=1 in exI , clarsimp) done } with ha ≤ bi show ?thesis by auto qed lemma fine-covers-all: assumes fine δ (a, c) D and a < x and x ≤ c shows ∃ N < length D. ∀ d t e. D ! N = (d,t,e) −→ d < x ∧ x ≤ e using assms proof (induct set: fine) case (2 b c D a t) thus ?case proof (cases b < x) case True with 2 obtain N where ∗: N < length D and ∗∗: D ! N = (d,t,e) =⇒ d < x ∧ x ≤ e for d t e by auto 462 hence Suc N < length ((a,t,b)#D) ∧ (∀ d t 0 e. ((a,t,b)#D)! Suc N = (d,t 0,e) −→ d < x ∧ x ≤ e) by auto thus ?thesis by auto next case False with 2 have 0 < length ((a,t,b)#D) ∧ (∀ d t 0 e. ((a,t,b)#D)! 0 = (d,t 0,e) −→ d < x ∧ x ≤ e) by auto thus ?thesis by auto qed qed auto lemma fine-append-split: assumes fine δ (a,b) D and D2 6= [] and D = D1 @ D2 shows fine δ (a,fst (hd D2 )) D1 (is ?fine1 ) and fine δ (fst (hd D2 ), b) D2 (is ?fine2 ) proof − from assms have ?fine1 ∧ ?fine2 proof (induct arbitrary: D1 D2 ) case (2 b c D a 0 x D1 D2 ) note induct = this thus ?case proof (cases D1 ) case Nil hence fst (hd D2 ) = a 0 using 2 by auto with fine-Cons[OF hfine δ (b,c) D i induct(3 ,4 ,5 )] Nil induct show ?thesis by (auto intro: fine-Nil) next case (Cons d1 D1 0) 0 with induct(2 )[OF hD2 6= []i, of D1 ] induct(8 ) have fine δ (b, fst (hd D2 )) D1 0 and fine δ (fst (hd D2 ), c) D2 and d1 = (a 0, x, b) by auto with fine-Cons[OF this(1 ) induct(3 ,4 ,5 ), OF induct(6 )] Cons show ?thesis by auto qed qed auto thus ?fine1 and ?fine2 by auto qed lemma fine-δ-expand: assumes fine δ (a,b) D and Vx. a ≤ x =⇒ x ≤ b =⇒ δ x ≤ δ 0 x shows fine δ 0 (a,b) D using assms proof induct case 1 show ?case by (rule fine-Nil) next case (2 b c D a x) show ?case 463 proof (rule fine-Cons) show fine δ 0 (b,c) D using 2 by auto from fine-imp-le[OF 2 (1 )] 2 (6 ) hx ≤ bi show b − a < δ 0 x using 2 (7 )[OF ha ≤ x i] by auto qed (auto simp add: 2 ) qed lemma fine-single-boundaries: assumes fine δ (a,b) D and D = [(d, t, e)] shows a = d ∧ b = e using assms proof induct case (2 b c D a x) hence D = [] and a = d and b = e by auto moreover from hfine δ (b,c) D i hD = []i have b = c by (rule empty-fine-imp-eq) ultimately show ?case by simp qed auto lemma fine-sum-list-eq-diff : fixes f :: real ⇒ real shows fine δ (a, b) D =⇒ (P (u, x, v)←D. f v − f u) = f b − f a by (induct set: fine) simp-all Lemmas about combining gauges lemma gauge-min: [| gauge(E) g1 ; gauge(E) g2 |] ==> gauge(E) (%x. min (g1 (x)) (g2 (x))) by (simp add: gauge-def ) lemma fine-min: fine (%x. min (g1 (x)) (g2 (x))) (a,b) D ==> fine(g1 )(a,b) D & fine(g2 )(a,b) D apply (erule fine.induct) apply (simp add: fine-Nil) apply (simp add: fine-Cons) done 61.3 Riemann sum definition rsum :: [(real × real × real) list, real ⇒ real] ⇒ real where rsum D f = (P (u, x, v)←D. f x ∗ (v − u)) lemma rsum-Nil [simp]: rsum [] f = 0 unfolding rsum-def by simp lemma rsum-Cons [simp]: rsum ((u, x, v)# D) f = f x ∗ (v − u) + rsum D f 464 unfolding rsum-def by simp lemma rsum-zero [simp]: rsum D (λx. 0 ) = 0 by (induct D, auto) lemma rsum-left-distrib: rsum D f ∗ c = rsum D (λx. f x ∗ c) by (induct D, auto simp add: algebra-simps) lemma rsum-right-distrib: c ∗ rsum D f = rsum D (λx. c ∗ f x) by (induct D, auto simp add: algebra-simps) lemma rsum-add: rsum D (λx. f x + g x) = rsum D f + rsum D g by (induct D, auto simp add: algebra-simps) lemma rsum-append: rsum (D1 @ D2 ) f = rsum D1 f + rsum D2 f unfolding rsum-def map-append sum-list-append .. 61.4 Gauge integrability (definite) definition Integral :: [(real∗real),real=>real,real] => bool where Integral = (%(a,b) f k. ∀ e > 0 . (∃ δ. gauge {a .. b} δ & (∀ D. fine δ (a,b) D −−> |rsum D f − k| < e))) lemma Integral-eq: Integral (a, b) f k ←→ (∀ e>0 . ∃ δ. gauge {a..b} δ ∧ (∀ D. fine δ (a,b) D −→ |rsum D f − k| < e)) unfolding Integral-def by simp lemma IntegralI : assumes Ve. 0 < e =⇒ ∃ δ. gauge {a..b} δ ∧ (∀ D. fine δ (a, b) D −→ |rsum D f − k| < e) shows Integral (a, b) f k using assms unfolding Integral-def by auto lemma IntegralE: assumes Integral (a, b) f k and 0 < e obtains δ where gauge {a..b} δ and ∀ D. fine δ (a, b) D −→ |rsum D f − k| < e using assms unfolding Integral-def by auto lemma Integral-def2 : Integral = (%(a,b) f k. ∀ e>0 . (∃ δ. gauge {a..b} δ & (∀ D. fine δ (a,b) D −−> |rsum D f − k| ≤ e))) unfolding Integral-def apply (safe intro!: ext) 465 apply (fast intro: less-imp-le) apply (drule-tac x=e/2 in spec) apply force done The integral is unique if it exists lemma Integral-unique: assumes le: a ≤ b assumes 1 : Integral (a, b) f k1 assumes 2 : Integral (a, b) f k2 shows k1 = k2 proof (rule ccontr) assume k1 6= k2 hence e: 0 < |k1 − k2 | / 2 by simp obtain d1 where gauge {a..b} d1 and d1 : ∀ D. fine d1 (a, b) D −→ |rsum D f − k1 | < |k1 − k2 | / 2 using 1 e by (rule IntegralE) obtain d2 where gauge {a..b} d2 and d2 : ∀ D. fine d2 (a, b) D −→ |rsum D f − k2 | < |k1 − k2 | / 2 using 2 e by (rule IntegralE) have gauge {a..b} (λx. min (d1 x)(d2 x)) using hgauge {a..b} d1 i and hgauge {a..b} d2 i by (rule gauge-min) then obtain D where fine (λx. min (d1 x)(d2 x)) (a, b) D using fine-exists [OF le] by fast hence fine d1 (a, b) D and fine d2 (a, b) D by (auto dest: fine-min) hence |rsum D f − k1 | < |k1 − k2 | / 2 and |rsum D f − k2 | < |k1 − k2 | / 2 using d1 d2 by simp-all hence |rsum D f − k1 | + |rsum D f − k2 | < |k1 − k2 | / 2 + |k1 − k2 | / 2 by (rule add-strict-mono) thus False by auto qed lemma Integral-zero: Integral(a,a) f 0 apply (rule IntegralI ) apply (rule-tac x = λx. 1 in exI ) apply (simp add: fine-same-iff gauge-def ) done lemma Integral-same-iff [simp]: Integral (a, a) f k ←→ k = 0 by (auto intro: Integral-zero Integral-unique) lemma Integral-zero-fun: Integral (a,b)(λx. 0 ) 0 apply (rule IntegralI ) apply (rule-tac x=λx. 1 in exI , simp add: gauge-def ) done lemma fine-rsum-const: fine δ (a,b) D =⇒ rsum D (λx. c) = (c ∗ (b − a)) 466 unfolding rsum-def by (induct set: fine, auto simp add: algebra-simps) lemma Integral-mult-const: a ≤ b =⇒ Integral(a,b)(λx. c)(c ∗ (b − a)) apply (cases a = b, simp) apply (rule IntegralI ) apply (rule-tac x = λx. b − a in exI ) apply (rule conjI , simp add: gauge-def ) apply (clarify) apply (subst fine-rsum-const, assumption, simp) done lemma Integral-eq-diff-bounds: a ≤ b =⇒ Integral(a,b)(λx. 1 )(b − a) using Integral-mult-const [of a b 1 ] by simp lemma Integral-mult: [| a ≤ b; Integral(a,b) f k |] ==> Integral(a,b) (%x. c ∗ f x)(c ∗ k) apply (auto simp add: order-le-less) apply (cases c = 0 , simp add: Integral-zero-fun) apply (rule IntegralI ) apply (erule-tac e=e / |c| in IntegralE, simp) apply (rule-tac x=δ in exI , clarify) apply (drule-tac x=D in spec, clarify) apply (simp add: pos-less-divide-eq abs-mult [symmetric] algebra-simps rsum-right-distrib) done lemma Integral-add: assumes Integral (a, b) f x1 assumes Integral (b, c) f x2 assumes a ≤ b and b ≤ c shows Integral (a, c) f (x1 + x2 ) proof (cases a < b ∧ b < c, rule IntegralI ) fix ε :: real assume 0 < ε hence 0 < ε / 2 by auto assume a < b ∧ b < c hence a < b and b < c by auto obtain δ1 where δ1-gauge: gauge {a..b} δ1 and I1 : fine δ1 (a,b) D =⇒ | rsum D f − x1 | < (ε / 2 ) for D using IntegralE [OF hIntegral (a, b) f x1 i h0 < ε/2 i] by auto obtain δ2 where δ2-gauge: gauge {b..c} δ2 and I2 : fine δ2 (b,c) D =⇒ | rsum D f − x2 | < (ε / 2 ) for D using IntegralE [OF hIntegral (b, c) f x2 i h0 < ε/2 i] by auto define δ where δ x = (if x < b then min (δ1 x)(b − x) 467 else if x = b then min (δ1 b)(δ2 b) else min (δ2 x)(x − b)) for x have gauge {a..c} δ using δ1-gauge δ2-gauge unfolding δ-def gauge-def by auto moreover { fix D :: (real × real × real) list assume fine: fine δ (a,c) D from fine-covers-all[OF this ha < bi hb ≤ ci] obtain N where N < length D and ∗: ∀ d t e. D ! N = (d, t, e) −→ d < b ∧ b ≤ e by auto obtain d t e where D-eq: D ! N = (d, t, e) by (cases D!N , auto) with ∗ have d < b and b ≤ e by auto have in-D:(d, t, e) ∈ set D using D-eq[symmetric] using hN < length D i by auto from mem-fine[OF fine in-D] have d < e and d ≤ t and t ≤ e by auto have t = b proof (rule ccontr) assume t 6= b with mem-fine3 [OF fine in-D] hb ≤ e i hd ≤ t i ht ≤ e i hd < bi δ-def show False by (cases t < b) auto qed let ?D1 = take N D let ?D2 = drop N D define D1 where D1 = take N D @ [(d, t, b)] define D2 where D2 = (if b = e then [] else [(b, t, e)]) @ drop (Suc N ) D from hd-drop-conv-nth[OF hN < length D i] have fst (hd ?D2 ) = d using hD ! N = (d, t, e)i by auto with fine-append-split[OF - - append-take-drop-id[symmetric]] have fine1 : fine δ (a,d) ?D1 and fine2 : fine δ (d,c) ?D2 using hN < length D i fine by auto have fine δ1 (a,b) D1 unfolding D1-def proof (rule fine-append) show fine δ1 (a, d) ?D1 proof (rule fine1 [THEN fine-δ-expand]) fix x assume a ≤ x x ≤ d hence x ≤ b using hd < bi hx ≤ d i by auto thus δ x ≤ δ1 x unfolding δ-def by auto qed have b − d < δ1 t 468 using mem-fine3 [OF fine in-D] δ-def hb ≤ e i ht = bi by auto from hd < bi hd ≤ t i ht = bi this show fine δ1 (d, b) [(d, t, b)] using fine-single by auto qed note rsum1 = I1 [OF this] have drop-split: drop N D = [D ! N ]@ drop (Suc N ) D using Cons-nth-drop-Suc[OF hN < length D i] by simp have fine2 : fine δ2 (e,c)(drop (Suc N ) D) proof (cases drop (Suc N ) D = []) case True note ∗ = fine2 [simplified drop-split True D-eq append-Nil2 ] have e = c using fine-single-boundaries[OF ∗ refl] by auto thus ?thesis unfolding True using fine-Nil by auto next case False note ∗ = fine-append-split[OF fine2 False drop-split] from fine-single-boundaries[OF ∗(1 )] have fst (hd (drop (Suc N ) D)) = e using D-eq by auto with ∗(2 ) have fine δ (e,c)(drop (Suc N ) D) by auto thus ?thesis proof (rule fine-δ-expand) fix x assume e ≤ x and x ≤ c thus δ x ≤ δ2 x using hb ≤ e i unfolding δ-def by auto qed qed have fine δ2 (b, c) D2 proof (cases e = b) case True thus ?thesis using fine2 by (simp add: D1-def D2-def ) next case False have e − b < δ2 b using mem-fine3 [OF fine in-D] δ-def hd < bi ht = bi by auto with False ht = bi hb ≤ e i show ?thesis using D2-def by (auto intro!: fine-append[OF - fine2 ] fine-single simp del: append-Cons) qed note rsum2 = I2 [OF this] have rsum D f = rsum (take N D) f + rsum [D ! N ] f + rsum (drop (Suc N ) D) f using rsum-append[symmetric] Cons-nth-drop-Suc[OF hN < length D i] by auto also have ... = rsum D1 f + rsum D2 f by (cases b = e, auto simp add: D1-def D2-def D-eq rsum-append algebra-simps) finally have |rsum D f − (x1 + x2 )| < ε 469 using add-strict-mono[OF rsum1 rsum2 ] by simp } ultimately show ∃ δ. gauge {a .. c} δ ∧ (∀ D. fine δ (a,c) D −→ |rsum D f − (x1 + x2 )| < ε) by blast next case False hence a = b ∨ b = c using ha ≤ bi and hb ≤ ci by auto thus ?thesis proof (rule disjE) assume a = b hence x1 = 0 using hIntegral (a, b) f x1 i by simp thus ?thesis using ha = bi hIntegral (b, c) f x2 i by simp next assume b = c hence x2 = 0 using hIntegral (b, c) f x2 i by simp thus ?thesis using hb = ci hIntegral (a, b) f x1 i by simp qed qed Fundamental theorem of calculus (Part I) ”Straddle Lemma” : Swartz and Thompson: AMM 95(7) 1988 lemma strad1 : fixes z x s e :: real assumes P:(Vz. z 6= x =⇒ |z − x| < s =⇒ |(f z − f x) / (z − x) − f 0 x| < e / 2 ) assumes |z − x| < s shows |f z − f x − f 0 x ∗ (z − x)| ≤ e / 2 ∗ |z − x| proof (cases z = x) case True then show ?thesis by simp next case False then have inverse (z − x) ∗ (f z − f x − f 0 x ∗ (z − x)) = (f z − f x) / (z − x) − f 0 x apply (subst mult.commute) apply (simp add: left-diff-distrib) apply (simp add: mult.assoc divide-inverse) apply (simp add: ring-distribs) done 0 moreover from False h|z − x| < s i have |(f z − f x) / (z − x) − f x| < e / 2 by (rule P) ultimately have |inverse (z − x)| ∗ (|f z − f x − f 0 x ∗ (z − x)| ∗ 2 ) ≤ |inverse (z − x)| ∗ (e ∗ |z − x|) using False by (simp del: abs-inverse add: abs-mult [symmetric] ac-simps) with False have |f z − f x − f 0 x ∗ (z − x)| ∗ 2 ≤ e ∗ |z − x| by simp then show ?thesis by simp qed 470 lemma lemma-straddle: assumes f 0: ∀ x. a ≤ x & x ≤ b −−> DERIV f x :> f 0(x) and 0 < e shows ∃ g. gauge {a..b} g & (∀ x u v. a ≤ u & u ≤ x & x ≤ v & v ≤ b &(v − u) < g(x) −−> |(f (v) − f (u)) − (f 0(x) ∗ (v − u))| ≤ e ∗ (v − u)) proof − have ∀ x∈{a..b}. (∃ d > 0 . ∀ u v. u ≤ x & x ≤ v &(v − u) < d −−> |(f (v) − f (u)) − (f 0(x) ∗ (v − u))| ≤ e ∗ (v − u)) proof (clarsimp) fix x :: real assume a ≤ x and x ≤ b with f 0 have DERIV f x :> f 0(x) by simp then have ∀ r>0 . ∃ s>0 . ∀ z. z 6= x ∧ |z − x| < s −→ |(f z − f x) / (z − x) − f 0 x| < r by (simp add: DERIV-iff2 LIM-eq) with h0 < e i obtain s where z 6= x =⇒ |z − x| < s =⇒ |(f z − f x) / (z − x) − f 0 x| < e/2 and 0 < s for z by (drule-tac x=e/2 in spec, auto) with strad1 [of x s f f 0 e] have strad: Vz. |z − x| < s =⇒ |f z − f x − f 0 x ∗ (z − x)| ≤ e/2 ∗ |z − x| by auto show ∃ d>0 . ∀ u v. u ≤ x ∧ x ≤ v ∧ v − u < d −→ |f v − f u − f 0 x ∗ (v − u)| ≤ e ∗ (v − u) proof (safe intro!: exI ) show 0 < s by fact next fix u v :: real assume u ≤ x and x ≤ v and v − u < s have |f v − f u − f 0 x ∗ (v − u)| = |(f v − f x − f 0 x ∗ (v − x)) + (f x − f u − f 0 x ∗ (x − u))| by (simp add: right-diff-distrib) also have ... ≤ |f v − f x − f 0 x ∗ (v − x)| + |f x − f u − f 0 x ∗ (x − u)| by (rule abs-triangle-ineq) also have ... = |f v − f x − f 0 x ∗ (v − x)| + |f u − f x − f 0 x ∗ (u − x)| by (simp add: right-diff-distrib) also have ... ≤ (e/2 ) ∗ |v − x| + (e/2 ) ∗ |u − x| using hu ≤ x i hx ≤ v i hv − u < s i by (intro add-mono strad, simp-all) also have ... ≤ e ∗ (v − u) / 2 + e ∗ (v − u) / 2 using hu ≤ x i hx ≤ v i h0 < e i by (intro add-mono, simp-all) also have ... = e ∗ (v − u) by simp finally show |f v − f u − f 0 x ∗ (v − u)| ≤ e ∗ (v − u) . qed qed thus ?thesis by (simp add: gauge-def )(drule bchoice, auto) qed lemma fundamental-theorem-of-calculus: 471 assumes a ≤ b assumes f 0: ∀ x. a ≤ x ∧ x ≤ b −→ DERIV f x :> f 0(x) shows Integral (a, b) f 0 (f (b) − f (a)) proof (cases a = b) assume a = b thus ?thesis by simp next assume a 6= b with ha ≤ bi have a < b by simp show ?thesis proof (simp add: Integral-def2 , clarify) fix e :: real assume 0 < e with ha < bi have 0 < e / (b − a) by simp from lemma-straddle [OF f 0 this] obtain δ where gauge {a..b} δ and δ: [[a ≤ u; u ≤ x; x ≤ v; v ≤ b; v − u < δ x]] =⇒ |f v − f u − f 0 x ∗ (v − u)| ≤ e ∗ (v − u) / (b − a) for x u v by auto have ∀ D. fine δ (a, b) D −→ |rsum D f 0 − (f b − f a)| ≤ e proof (clarify) fix D assume D: fine δ (a, b) D hence (P (u, x, v)←D. f v − f u) = f b − f a by (rule fine-sum-list-eq-diff ) hence |rsum D f 0 − (f b − f a)| = |rsum D f 0 − (P (u, x, v)←D. f v − f u)| by simp also have ... = |(P (u, x, v)←D. f v − f u) − rsum D f 0| by (rule abs-minus-commute) also have ... = |P (u, x, v)←D. (f v − f u) − f 0 x ∗ (v − u)| by (simp only: rsum-def sum-list-subtractf split-def ) also have ... ≤ (P (u, x, v)←D. |(f v − f u) − f 0 x ∗ (v − u)|) by (rule ord-le-eq-trans [OF sum-list-abs], simp add: o-def split-def ) also have ... ≤ (P (u, x, v)←D. (e / (b − a)) ∗ (v − u)) apply (rule sum-list-mono, clarify, rename-tac u x v) using D apply (simp add: δ mem-fine mem-fine2 mem-fine3 ) done also have ... = e using fine-sum-list-eq-diff [OF D, where f =λx. x] unfolding split-def sum-list-const-mult using ha < bi by simp finally show |rsum D f 0 − (f b − f a)| ≤ e . qed with hgauge {a..b} δi show ∃ δ. gauge {a..b} δ ∧ (∀ D. fine δ (a, b) D −→ |rsum D f 0 − (f b − f a)| ≤ e) by auto qed qed end 472 theory Dedekind-Real imports Complex-Main begin 62 Positive real numbers Could be generalized and moved to Groups lemma add-eq-exists: ∃ x. a+x = (b::rat) by (rule-tac x=b−a in exI , simp) definition cut :: rat set => bool where cut A = ({} ⊂ A & A < {r. 0 < r} & (∀ y ∈ A. ((∀ z. 0 473 using Rep-preal [of x] by simp definition psup :: preal set => preal where psup P = Abs-preal (S X ∈ P. Rep-preal X ) definition add-set :: [rat set,rat set] => rat set where add-set A B = {w. ∃ x ∈ A. ∃ y ∈ B. w = x + y} definition diff-set :: [rat set,rat set] => rat set where diff-set A B = {w. ∃ x. 0 < w & 0 < x & x ∈/ B & x + w ∈ A} definition mult-set :: [rat set,rat set] => rat set where mult-set A B = {w. ∃ x ∈ A. ∃ y ∈ B. w = x ∗ y} definition inverse-set :: rat set => rat set where inverse-set A = {x. ∃ y. 0 < x & x < y & inverse y ∈/ A} instantiation preal :: {ord, plus, minus, times, inverse, one} begin definition preal-less-def : R < S == Rep-preal R < Rep-preal S definition preal-le-def : R ≤ S == Rep-preal R ⊆ Rep-preal S definition preal-add-def : R + S == Abs-preal (add-set (Rep-preal R)(Rep-preal S)) definition preal-diff-def : R − S == Abs-preal (diff-set (Rep-preal R)(Rep-preal S)) definition preal-mult-def : R ∗ S == Abs-preal (mult-set (Rep-preal R)(Rep-preal S)) definition preal-inverse-def : inverse R == Abs-preal (inverse-set (Rep-preal R)) 474 definition R div S = R ∗ inverse (S::preal) definition preal-one-def : 1 == Abs-preal {x. 0 < x & x < 1 } instance .. end Reduces equality on abstractions to equality on representatives declare Abs-preal-inject [simp] declare Abs-preal-inverse [simp] lemma rat-mem-preal: 0 < q ==> cut {r::rat. 0 < r & r < q} by (simp add: cut-of-rat) lemma preal-nonempty: cut A ==> ∃ x∈A. 0 < x unfolding cut-def [abs-def ] by blast lemma preal-Ex-mem: cut A =⇒ ∃ x. x ∈ A apply (drule preal-nonempty) apply fast done lemma preal-imp-psubset-positives: cut A ==> A < {r. 0 < r} by (force simp add: cut-def ) lemma preal-exists-bound: cut A ==> ∃ x. 0 < x & x ∈/ A apply (drule preal-imp-psubset-positives) apply auto done lemma preal-exists-greater:[| cut A; y ∈ A |] ==> ∃ u ∈ A. y < u unfolding cut-def [abs-def ] by blast lemma preal-downwards-closed:[| cut A; y ∈ A; 0 < z; z < y |] ==> z ∈ A unfolding cut-def [abs-def ] by blast Relaxing the final premise lemma preal-downwards-closed 0: [| cut A; y ∈ A; 0 < z; z ≤ y |] ==> z ∈ A apply (simp add: order-le-less) apply (blast intro: preal-downwards-closed) done A positive fraction not in a positive real is an upper bound. Gleason p. 122 - Remark (1) lemma not-in-preal-ub: 475 assumes A: cut A and notx: x ∈/ A and y: y ∈ A and pos: 0 < x shows y < x proof (cases rule: linorder-cases) assume x 62.1 Properties of Ordering instance preal :: order proof fix w :: preal show w ≤ w by (simp add: preal-le-def ) next fix i j k :: preal assume i ≤ j and j ≤ k then show i ≤ k by (simp add: preal-le-def ) next fix z w :: preal assume z ≤ w and w ≤ z then show z = w by (simp add: preal-le-def Rep-preal-inject) next fix z w :: preal show z < w ←→ z ≤ w ∧ ¬ w ≤ z by (auto simp add: preal-le-def preal-less-def Rep-preal-inject) qed lemma preal-imp-pos:[|cut A; r ∈ A|] ==> 0 < r by (insert preal-imp-psubset-positives, blast) 476 instance preal :: linorder proof fix x y :: preal show x <= y | y <= x apply (auto simp add: preal-le-def ) apply (rule ccontr) apply (blast dest: not-in-Rep-preal-ub intro: preal-imp-pos [OF Rep-preal] elim: order-less-asym) done qed instantiation preal :: distrib-lattice begin definition (inf :: preal ⇒ preal ⇒ preal) = min definition (sup :: preal ⇒ preal ⇒ preal) = max instance by intro-classes (auto simp add: inf-preal-def sup-preal-def max-min-distrib2 ) end 62.2 Properties of Addition lemma preal-add-commute:(x::preal) + y = y + x apply (unfold preal-add-def add-set-def ) apply (rule-tac f = Abs-preal in arg-cong) apply (force simp add: add.commute) done Lemmas for proving that addition of two positive reals gives a positive real Part 1 of Dedekind sections definition lemma add-set-not-empty: [|cut A; cut B|] ==> {} ⊂ add-set A B apply (drule preal-nonempty)+ apply (auto simp add: add-set-def ) done Part 2 of Dedekind sections definition. A structured version of this proof is preal-not-mem-mult-set-Ex below. lemma preal-not-mem-add-set-Ex: [|cut A; cut B|] ==> ∃ q>0 . q ∈/ add-set A B apply (insert preal-exists-bound [of A] preal-exists-bound [of B], auto) 477 apply (rule-tac x = x+xa in exI ) apply (simp add: add-set-def , clarify) apply (drule (3 ) not-in-preal-ub)+ apply (force dest: add-strict-mono) done lemma add-set-not-rat-set: assumes A: cut A and B: cut B shows add-set A B < {r. 0 < r} proof from preal-imp-pos [OF A] preal-imp-pos [OF B] show add-set A B ⊆ {r. 0 < r} by (force simp add: add-set-def ) next show add-set A B 6= {r. 0 < r} by (insert preal-not-mem-add-set-Ex [OF A B], blast) qed Part 3 of Dedekind sections definition lemma add-set-lemma3 : [|cut A; cut B; u ∈ add-set A B; 0 < z; z < u|] ==> z ∈ add-set A B proof (unfold add-set-def , clarify) fix x::rat and y::rat assume A: cut A and B: cut B and [simp]: 0 < z and zless: z < x + y and x: x ∈ A and y: y ∈ B have xpos [simp]: 0 478 next show x ∗ ?f ∈ A proof (rule preal-downwards-closed [OF A x]) show 0 < x ∗ ?f by (simp add: divide-inverse zero-less-mult-iff ) next show x ∗ ?f < x by (insert mult-strict-left-mono [OF fless xpos], simp) qed qed qed Part 4 of Dedekind sections definition lemma add-set-lemma4 : [|cut A; cut B; y ∈ add-set A B|] ==> ∃ u ∈ add-set A B. y < u apply (auto simp add: add-set-def ) apply (frule preal-exists-greater [of A], auto) apply (rule-tac x=u + ya in exI ) apply (auto intro: add-strict-left-mono) done lemma mem-add-set: [|cut A; cut B|] ==> cut (add-set A B) apply (simp (no-asm-simp) add: cut-def ) apply (blast intro!: add-set-not-empty add-set-not-rat-set add-set-lemma3 add-set-lemma4 ) done lemma preal-add-assoc: ((x::preal) + y) + z = x + (y + z) apply (simp add: preal-add-def mem-add-set Rep-preal) apply (force simp add: add-set-def ac-simps) done instance preal :: ab-semigroup-add proof fix a b c :: preal show (a + b) + c = a + (b + c) by (rule preal-add-assoc) show a + b = b + a by (rule preal-add-commute) qed 62.3 Properties of Multiplication Proofs essentially same as for addition lemma preal-mult-commute:(x::preal) ∗ y = y ∗ x apply (unfold preal-mult-def mult-set-def ) apply (rule-tac f = Abs-preal in arg-cong) apply (force simp add: mult.commute) done 479 Multiplication of two positive reals gives a positive real. Lemmas for proving positive reals multiplication set in preal Part 1 of Dedekind sections definition lemma mult-set-not-empty: [|cut A; cut B|] ==> {} ⊂ mult-set A B apply (insert preal-nonempty [of A] preal-nonempty [of B]) apply (auto simp add: mult-set-def ) done Part 2 of Dedekind sections definition lemma preal-not-mem-mult-set-Ex: assumes A: cut A and B: cut B shows ∃ q. 0 < q & q ∈/ mult-set A B proof − from preal-exists-bound [OF A] obtain x where 1 [simp]: 0 < x x ∈/ A by blast from preal-exists-bound [OF B] obtain y where 2 [simp]: 0 < y y ∈/ B by blast show ?thesis proof (intro exI conjI ) show 0 < x∗y by simp show x ∗ y ∈/ mult-set A B proof − { fix u::rat and v::rat assume u: u ∈ A and v: v ∈ B and xy: x∗y = u∗v moreover from A B 1 2 u v have u 480 intro: preal-imp-pos [OF A] preal-imp-pos [OF B] mult-pos-pos) show mult-set A B 6= {r. 0 < r} using preal-not-mem-mult-set-Ex [OF A B] by blast qed Part 3 of Dedekind sections definition lemma mult-set-lemma3 : [|cut A; cut B; u ∈ mult-set A B; 0 < z; z < u|] ==> z ∈ mult-set A B proof (unfold mult-set-def , clarify) fix x::rat and y::rat assume A: cut A and B: cut B and [simp]: 0 < z and zless: z < x ∗ y and x: x ∈ A and y: y ∈ B have [simp]: 0 Part 4 of Dedekind sections definition lemma mult-set-lemma4 : [|cut A; cut B; y ∈ mult-set A B|] ==> ∃ u ∈ mult-set A B. y < u apply (auto simp add: mult-set-def ) apply (frule preal-exists-greater [of A], auto) apply (rule-tac x=u ∗ ya in exI ) apply (auto intro: preal-imp-pos [of A] preal-imp-pos [of B] mult-strict-right-mono) done lemma mem-mult-set: 481 [|cut A; cut B|] ==> cut (mult-set A B) apply (simp (no-asm-simp) add: cut-def ) apply (blast intro!: mult-set-not-empty mult-set-not-rat-set mult-set-lemma3 mult-set-lemma4 ) done lemma preal-mult-assoc: ((x::preal) ∗ y) ∗ z = x ∗ (y ∗ z) apply (simp add: preal-mult-def mem-mult-set Rep-preal) apply (force simp add: mult-set-def ac-simps) done instance preal :: ab-semigroup-mult proof fix a b c :: preal show (a ∗ b) ∗ c = a ∗ (b ∗ c) by (rule preal-mult-assoc) show a ∗ b = b ∗ a by (rule preal-mult-commute) qed Positive real 1 is the multiplicative identity element lemma preal-mult-1 :(1 ::preal) ∗ z = z proof (induct z) fix A :: rat set assume A: cut A have {w. ∃ u. 0 < u ∧ u < 1 &(∃ v ∈ A. w = u ∗ v)} = A (is ?lhs = A) proof show ?lhs ⊆ A proof clarify fix x::rat and u::rat and v::rat assume upos: 0 482 by (simp add: pos-divide-less-eq vpos xlessv) show ∃ v 0∈A. x = (x / v) ∗ v 0 proof show x = (x/v)∗v by (simp add: divide-inverse mult.assoc vpos order-less-imp-not-eq2 ) show v ∈ A by fact qed qed qed qed thus 1 ∗ Abs-preal A = Abs-preal A by (simp add: preal-one-def preal-mult-def mult-set-def rat-mem-preal A) qed instance preal :: comm-monoid-mult by intro-classes (rule preal-mult-1 ) 62.4 Distribution of Multiplication across Addition lemma mem-Rep-preal-add-iff : (z ∈ Rep-preal(R+S)) = (∃ x ∈ Rep-preal R. ∃ y ∈ Rep-preal S. z = x + y) apply (simp add: preal-add-def mem-add-set Rep-preal) apply (simp add: add-set-def ) done lemma mem-Rep-preal-mult-iff : (z ∈ Rep-preal(R∗S)) = (∃ x ∈ Rep-preal R. ∃ y ∈ Rep-preal S. z = x ∗ y) apply (simp add: preal-mult-def mem-mult-set Rep-preal) apply (simp add: mult-set-def ) done lemma distrib-subset1 : Rep-preal (w ∗ (x + y)) ⊆ Rep-preal (w ∗ x + w ∗ y) apply (auto simp add: Bex-def mem-Rep-preal-add-iff mem-Rep-preal-mult-iff ) apply (force simp add: distrib-left) done lemma preal-add-mult-distrib-mean: assumes a: a ∈ Rep-preal w and b: b ∈ Rep-preal w and d: d ∈ Rep-preal x and e: e ∈ Rep-preal y shows ∃ c ∈ Rep-preal w. a ∗ d + b ∗ e = c ∗ (d + e) proof let ?c = (a∗d + b∗e)/(d+e) have [simp]: 0 483 have cpos: 0 < ?c by (simp add: zero-less-divide-iff zero-less-mult-iff pos-add-strict) show a ∗ d + b ∗ e = ?c ∗ (d + e) by (simp add: divide-inverse mult.assoc order-less-imp-not-eq2 ) show ?c ∈ Rep-preal w proof (cases rule: linorder-le-cases) assume a ≤ b hence ?c ≤ b by (simp add: pos-divide-le-eq distrib-left mult-right-mono order-less-imp-le) thus ?thesis by (rule preal-downwards-closed 0 [OF Rep-preal b cpos]) next assume b ≤ a hence ?c ≤ a by (simp add: pos-divide-le-eq distrib-left mult-right-mono order-less-imp-le) thus ?thesis by (rule preal-downwards-closed 0 [OF Rep-preal a cpos]) qed qed lemma distrib-subset2 : Rep-preal (w ∗ x + w ∗ y) ⊆ Rep-preal (w ∗ (x + y)) apply (auto simp add: Bex-def mem-Rep-preal-add-iff mem-Rep-preal-mult-iff ) apply (drule-tac w=w and x=x and y=y in preal-add-mult-distrib-mean, auto) done lemma preal-add-mult-distrib2 :(w ∗ ((x::preal) + y)) = (w ∗ x) + (w ∗ y) apply (rule Rep-preal-inject [THEN iffD1 ]) apply (rule equalityI [OF distrib-subset1 distrib-subset2 ]) done lemma preal-add-mult-distrib: (((x::preal) + y) ∗ w) = (x ∗ w) + (y ∗ w) by (simp add: preal-mult-commute preal-add-mult-distrib2 ) instance preal :: comm-semiring by intro-classes (rule preal-add-mult-distrib) 62.5 Existence of Inverse, a Positive Real lemma mem-inv-set-ex: assumes A: cut A shows ∃ x y. 0 < x & x < y & inverse y ∈/ A proof − from preal-exists-bound [OF A] obtain x where [simp]: 0 484 by (simp add: less-imp-inverse-less less-add-one) show inverse (inverse x) ∈/ A by (simp add: order-less-imp-not-eq2 ) qed qed Part 1 of Dedekind sections definition lemma inverse-set-not-empty: cut A ==> {} ⊂ inverse-set A apply (insert mem-inv-set-ex [of A]) apply (auto simp add: inverse-set-def ) done Part 2 of Dedekind sections definition lemma preal-not-mem-inverse-set-Ex: assumes A: cut A shows ∃ q. 0 < q & q ∈/ inverse-set A proof − from preal-nonempty [OF A] obtain x where x: x ∈ A and xpos [simp]: 0 485 apply (auto simp add: inverse-set-def ) apply (auto intro: order-less-trans) done Part 4 of Dedekind sections definition lemma inverse-set-lemma4 : [|cut A; y ∈ inverse-set A|] ==> ∃ u ∈ inverse-set A. y < u apply (auto simp add: inverse-set-def ) apply (drule dense [of y]) apply (blast intro: order-less-trans) done lemma mem-inverse-set: cut A ==> cut (inverse-set A) apply (simp (no-asm-simp) add: cut-def ) apply (blast intro!: inverse-set-not-empty inverse-set-not-rat-set inverse-set-lemma3 inverse-set-lemma4 ) done 62.6 Gleason’s Lemma 9-3.4, page 122 lemma Gleason9-34-exists: assumes A: cut A and ∀ x∈A. x + u ∈ A and 0 ≤ z shows ∃ b∈A. b + (of-int z) ∗ u ∈ A proof (cases z rule: int-cases) case (nonneg n) show ?thesis proof (simp add: nonneg, induct n) case 0 from preal-nonempty [OF A] show ?case by force next case (Suc k) then obtain b where b: b ∈ A b + of-nat k ∗ u ∈ A .. hence b + of-int (int k)∗u + u ∈ A by (simp add: assms) thus ?case by (force simp add: algebra-simps b) qed next case (neg n) with assms show ?thesis by simp qed lemma Gleason9-34-contra: assumes A: cut A shows [|∀ x∈A. x + u ∈ A; 0 < u; 0 < y; y ∈/ A|] ==> False proof (induct u, induct y) 486 fix a::int and b::int fix c::int and d::int assume bpos [simp]: 0 < b and dpos [simp]: 0 < d and closed: ∀ x∈A. x + (Fract c d) ∈ A and upos: 0 < Fract c d and ypos: 0 < Fract a b and notin: Fract a b ∈/ A have cpos [simp]: 0 < c by (simp add: zero-less-Fract-iff [OF dpos, symmetric] upos) have apos [simp]: 0 < a by (simp add: zero-less-Fract-iff [OF bpos, symmetric] ypos) let ?k = a∗d have frle: Fract a b ≤ Fract ?k 1 ∗ (Fract c d) proof − have ?thesis = ((a ∗ d ∗ b ∗ d) ≤ c ∗ b ∗ (a ∗ d ∗ b ∗ d)) by (simp add: order-less-imp-not-eq2 ac-simps) moreover have (1 ∗ (a ∗ d ∗ b ∗ d)) ≤ c ∗ b ∗ (a ∗ d ∗ b ∗ d) by (rule mult-mono, simp-all add: int-one-le-iff-zero-less zero-less-mult-iff order-less-imp-le) ultimately show ?thesis by simp qed have k: 0 ≤ ?k by (simp add: order-less-imp-le zero-less-mult-iff ) from Gleason9-34-exists [OF A closed k] obtain z where z: z ∈ A and mem: z + of-int ?k ∗ Fract c d ∈ A .. have less: z + of-int ?k ∗ Fract c d < Fract a b by (rule not-in-preal-ub [OF A notin mem ypos]) have 0 487 62.7 Gleason’s Lemma 9-3.6 lemma lemma-gleason9-36 : assumes A: cut A and x: 1 < x shows ∃ r ∈ A. r∗x ∈/ A proof − from preal-nonempty [OF A] obtain y where y: y ∈ A and ypos: 0 62.8 Existence of Inverse: Part 2 lemma mem-Rep-preal-inverse-iff : (z ∈ Rep-preal(inverse R)) = (0 < z ∧ (∃ y. z < y ∧ inverse y ∈/ Rep-preal R)) 488 apply (simp add: preal-inverse-def mem-inverse-set Rep-preal) apply (simp add: inverse-set-def ) done lemma Rep-preal-one: Rep-preal 1 = {x. 0 < x ∧ x < 1 } by (simp add: preal-one-def rat-mem-preal) lemma subset-inverse-mult-lemma: assumes xpos: 0 < x and xless: x < 1 shows ∃ r u y. 0 < r & r < y & inverse y ∈/ Rep-preal R & u ∈ Rep-preal R & x = r ∗ u proof − from xpos and xless have 1 < inverse x by (simp add: one-less-inverse-iff ) from lemma-gleason9-36 [OF Rep-preal this] obtain r where r: r ∈ Rep-preal R and notin: r ∗ (inverse x) ∈/ Rep-preal R .. have rpos: 0 489 have q < inverse y using rpos rless by (simp add: not-in-preal-ub [OF Rep-preal notin] q) hence r ∗ q < r/y using rpos by (simp add: divide-inverse mult-less-cancel-left) also have ... ≤ 1 using rpos rless by (simp add: pos-divide-le-eq) finally show ?thesis . qed lemma inverse-mult-subset: Rep-preal(inverse R ∗ R) ⊆ Rep-preal 1 apply (auto simp add: Bex-def Rep-preal-one mem-Rep-preal-inverse-iff mem-Rep-preal-mult-iff ) apply (simp add: zero-less-mult-iff preal-imp-pos [OF Rep-preal]) apply (blast intro: inverse-mult-subset-lemma) done lemma preal-mult-inverse: inverse R ∗ R = (1 ::preal) apply (rule Rep-preal-inject [THEN iffD1 ]) apply (rule equalityI [OF inverse-mult-subset subset-inverse-mult]) done lemma preal-mult-inverse-right: R ∗ inverse R = (1 ::preal) apply (rule preal-mult-commute [THEN subst]) apply (rule preal-mult-inverse) done Theorems needing Gleason9-34 lemma Rep-preal-self-subset: Rep-preal (R) ⊆ Rep-preal(R + S) proof fix r assume r: r ∈ Rep-preal R have rpos: 0 490 have r + y ∈ Rep-preal (R + S) using r y by (auto simp add: mem-Rep-preal-add-iff ) thus ?thesis using notin by blast qed lemma Rep-preal-sum-not-eq: Rep-preal (R + S) 6= Rep-preal(R) by (insert Rep-preal-sum-not-subset, blast) at last, Gleason prop. 9-3.5(iii) page 123 lemma preal-self-less-add-left:(R::preal) < R + S apply (unfold preal-less-def less-le) apply (simp add: Rep-preal-self-subset Rep-preal-sum-not-eq [THEN not-sym]) done 62.9 Subtraction for Positive Reals Gleason prop. 9-3.5(iv), page 123: proving A < B =⇒ ∃ D. A + D = B. We define the claimed D and show that it is a positive real Part 1 of Dedekind sections definition lemma diff-set-not-empty: R < S ==> {} ⊂ diff-set (Rep-preal S)(Rep-preal R) apply (auto simp add: preal-less-def diff-set-def elim!: equalityE) apply (frule-tac x1 = S in Rep-preal [THEN preal-exists-greater]) apply (drule preal-imp-pos [OF Rep-preal], clarify) apply (cut-tac a=x and b=u in add-eq-exists, force) done Part 2 of Dedekind sections definition lemma diff-set-nonempty: ∃ q. 0 < q & q ∈/ diff-set (Rep-preal S)(Rep-preal R) apply (cut-tac X = S in Rep-preal-exists-bound) apply (erule exE) apply (rule-tac x = x in exI , auto) apply (simp add: diff-set-def ) apply (auto dest: Rep-preal [THEN preal-downwards-closed]) done lemma diff-set-not-rat-set: diff-set (Rep-preal S)(Rep-preal R) < {r. 0 < r} (is ?lhs < ?rhs) proof show ?lhs ⊆ ?rhs by (auto simp add: diff-set-def ) show ?lhs 6= ?rhs using diff-set-nonempty by blast qed Part 3 of Dedekind sections definition lemma diff-set-lemma3 : [|R < S; u ∈ diff-set (Rep-preal S)(Rep-preal R); 0 < z; z < u|] 491 ==> z ∈ diff-set (Rep-preal S)(Rep-preal R) apply (auto simp add: diff-set-def ) apply (rule-tac x=x in exI ) apply (drule Rep-preal [THEN preal-downwards-closed], auto) done Part 4 of Dedekind sections definition lemma diff-set-lemma4 : [|R < S; y ∈ diff-set (Rep-preal S)(Rep-preal R)|] ==> ∃ u ∈ diff-set (Rep-preal S)(Rep-preal R). y < u apply (auto simp add: diff-set-def ) apply (drule Rep-preal [THEN preal-exists-greater], clarify) apply (cut-tac a=x+y and b=u in add-eq-exists, clarify) apply (rule-tac x=y+xa in exI ) apply (auto simp add: ac-simps) done lemma mem-diff-set: R < S ==> cut (diff-set (Rep-preal S)(Rep-preal R)) apply (unfold cut-def ) apply (blast intro!: diff-set-not-empty diff-set-not-rat-set diff-set-lemma3 diff-set-lemma4 ) done lemma mem-Rep-preal-diff-iff : R < S ==> (z ∈ Rep-preal(S−R)) = (∃ x. 0 < x & 0 < z & x ∈/ Rep-preal R & x + z ∈ Rep-preal S) apply (simp add: preal-diff-def mem-diff-set Rep-preal) apply (force simp add: diff-set-def ) done proving that R + D ≤ S lemma less-add-left-lemma: assumes Rless: R < S and a: a ∈ Rep-preal R and cb: c + b ∈ Rep-preal S and c ∈/ Rep-preal R and 0 < b and 0 < c shows a + b ∈ Rep-preal S proof − have 0 492 lemma less-add-left-le1 : R < (S::preal) ==> R + (S−R) ≤ S apply (auto simp add: Bex-def preal-le-def mem-Rep-preal-add-iff mem-Rep-preal-diff-iff ) apply (blast intro: less-add-left-lemma) done 62.10 proving that S ≤ R + D — trickier lemma lemma-sum-mem-Rep-preal-ex: x ∈ Rep-preal S ==> ∃ e. 0 < e & x + e ∈ Rep-preal S apply (drule Rep-preal [THEN preal-exists-greater], clarify) apply (cut-tac a=x and b=u in add-eq-exists, auto) done lemma less-add-left-lemma2 : assumes Rless: R < S and x: x ∈ Rep-preal S and xnot: x ∈/ Rep-preal R shows ∃ u v z. 0 < v & 0 < z & u ∈ Rep-preal R & z ∈/ Rep-preal R & z + v ∈ Rep-preal S & x = u + v proof − have xpos: 0 493 lemma less-add-left: R < (S::preal) ==> R + (S−R) = S by (blast intro: antisym [OF less-add-left-le1 less-add-left-le2 ]) lemma less-add-left-Ex: R < (S::preal) ==> ∃ D. R + D = S by (fast dest: less-add-left) lemma preal-add-less2-mono1 : R < (S::preal) ==> R + T < S + T apply (auto dest!: less-add-left-Ex simp add: preal-add-assoc) apply (rule-tac y1 = D in preal-add-commute [THEN subst]) apply (auto intro: preal-self-less-add-left simp add: preal-add-assoc [symmetric]) done lemma preal-add-less2-mono2 : R < (S::preal) ==> T + R < T + S by (auto intro: preal-add-less2-mono1 simp add: preal-add-commute [of T ]) lemma preal-add-right-less-cancel: R + T < S + T ==> R < (S::preal) apply (insert linorder-less-linear [of R S], auto) apply (drule-tac R = S and T = T in preal-add-less2-mono1 ) apply (blast dest: order-less-trans) done lemma preal-add-left-less-cancel: T + R < T + S ==> R < (S::preal) by (auto elim: preal-add-right-less-cancel simp add: preal-add-commute [of T ]) lemma preal-add-less-cancel-left [simp]: (T + (R::preal) < T + S) = (R < S) by (blast intro: preal-add-less2-mono2 preal-add-left-less-cancel) lemma preal-add-less-cancel-right [simp]: ((R::preal) + T < S + T ) = (R < S) using preal-add-less-cancel-left [symmetric, of R S T ] by (simp add: ac-simps) lemma preal-add-le-cancel-left [simp]: (T + (R::preal) ≤ T + S) = (R ≤ S) by (simp add: linorder-not-less [symmetric]) lemma preal-add-le-cancel-right [simp]: ((R::preal) + T ≤ S + T ) = (R ≤ S) using preal-add-le-cancel-left [symmetric, of R S T ] by (simp add: ac-simps) lemma preal-add-right-cancel:(R::preal) + T = S + T ==> R = S apply (insert linorder-less-linear [of R S], safe) apply (drule-tac [!] T = T in preal-add-less2-mono1 , auto) done lemma preal-add-left-cancel: C + A = C + B ==> A = (B::preal) by (auto intro: preal-add-right-cancel simp add: preal-add-commute) instance preal :: linordered-ab-semigroup-add proof fix a b c :: preal show a ≤ b =⇒ c + a ≤ c + b by (simp only: preal-add-le-cancel-left) 494 qed 62.11 Completeness of type preal Prove that supremum is a cut Part 1 of Dedekind sections definition lemma preal-sup-set-not-empty: P 6= {} ==> {} ⊂ (S X ∈ P. Rep-preal(X )) apply auto apply (cut-tac X = x in mem-Rep-preal-Ex, auto) done Part 2 of Dedekind sections definition lemma preal-sup-not-exists: ∀ X ∈ P. X ≤ Y ==> ∃ q. 0 < q & q ∈/ (S X ∈ P. Rep-preal(X )) apply (cut-tac X = Y in Rep-preal-exists-bound) apply (auto simp add: preal-le-def ) done lemma preal-sup-set-not-rat-set: ∀ X ∈ P. X ≤ Y ==> (S X ∈ P. Rep-preal(X )) < {r. 0 < r} apply (drule preal-sup-not-exists) apply (blast intro: preal-imp-pos [OF Rep-preal]) done Part 3 of Dedekind sections definition lemma preal-sup-set-lemma3 : [|P 6= {}; ∀ X ∈ P. X ≤ Y ; u ∈ (S X ∈ P. Rep-preal(X )); 0 < z; z < u|] ==> z ∈ (S X ∈ P. Rep-preal(X )) by (auto elim: Rep-preal [THEN preal-downwards-closed]) Part 4 of Dedekind sections definition lemma preal-sup-set-lemma4 : [|P 6= {}; ∀ X ∈ P. X ≤ Y ; y ∈ (S X ∈ P. Rep-preal(X )) |] ==> ∃ u ∈ (S X ∈ P. Rep-preal(X )). y < u by (blast dest: Rep-preal [THEN preal-exists-greater]) lemma preal-sup: [|P 6= {}; ∀ X ∈ P. X ≤ Y |] ==> cut (S X ∈ P. Rep-preal(X )) apply (unfold cut-def ) apply (blast intro!: preal-sup-set-not-empty preal-sup-set-not-rat-set preal-sup-set-lemma3 preal-sup-set-lemma4 ) done lemma preal-psup-le: [| ∀ X ∈ P. X ≤ Y ; x ∈ P |] ==> x ≤ psup P apply (simp (no-asm-simp) add: preal-le-def ) 495 apply (subgoal-tac P 6= {}) apply (auto simp add: psup-def preal-sup) done lemma psup-le-ub:[| P 6= {}; ∀ X ∈ P. X ≤ Y |] ==> psup P ≤ Y apply (simp (no-asm-simp) add: preal-le-def ) apply (simp add: psup-def preal-sup) apply (auto simp add: preal-le-def ) done Supremum property lemma preal-complete: [| P 6= {}; ∀ X ∈ P. X ≤ Y |] ==> (∃ X ∈ P. Z < X ) = (Z < psup P) apply (simp add: preal-less-def psup-def preal-sup) apply (auto simp add: preal-le-def ) apply (rename-tac U ) apply (cut-tac x = U and y = Z in linorder-less-linear) apply (auto simp add: preal-less-def ) done 63 Defining the Reals from the Positive Reals definition realrel :: ((preal ∗ preal) ∗ (preal ∗ preal)) set where realrel = {p. ∃ x1 y1 x2 y2 . p = ((x1 ,y1 ),(x2 ,y2 )) & x1 +y2 = x2 +y1 } definition Real = UNIV //realrel typedef real = Real morphisms Rep-Real Abs-Real unfolding Real-def by (auto simp add: quotient-def ) definition real-of-preal :: preal => real where real-of-preal m = Abs-Real (realrel ‘‘ {(m + 1 , 1 )}) instantiation real :: {zero, one, plus, minus, uminus, times, inverse, ord, abs, sgn} begin definition real-zero-def : 0 = Abs-Real(realrel‘‘{(1 , 1 )}) definition real-one-def : 1 = Abs-Real(realrel‘‘{(1 + 1 , 1 )}) definition real-add-def : z + w = 496 the-elem (S (x,y) ∈ Rep-Real(z). S (u,v) ∈ Rep-Real(w). { Abs-Real(realrel‘‘{(x+u, y+v)}) }) definition real-minus-def : − r = the-elem (S (x,y) ∈ Rep-Real(r). { Abs-Real(realrel‘‘{(y,x)}) }) definition real-diff-def : r − (s::real) = r + − s definition real-mult-def : z ∗ w = the-elem (S (x,y) ∈ Rep-Real(z). S (u,v) ∈ Rep-Real(w). { Abs-Real(realrel‘‘{(x∗u + y∗v, x∗v + y∗u)}) }) definition real-inverse-def : inverse (R::real) = (THE S. (R = 0 & S = 0 ) | S ∗ R = 1 ) definition real-divide-def : R div (S::real) = R ∗ inverse S definition real-le-def : z ≤ (w::real) ←→ (∃ x y u v. x+v ≤ u+y &(x,y) ∈ Rep-Real z &(u,v) ∈ Rep-Real w) definition real-less-def : x < (y::real) ←→ x ≤ y ∧ x 6= y definition real-abs-def : |r::real| = (if r < 0 then − r else r) definition real-sgn-def : sgn (x::real) = (if x=0 then 0 else if 0 63.1 Equivalence relation over positive reals lemma preal-trans-lemma: assumes x + y1 = x1 + y and x + y2 = x2 + y shows x1 + y2 = x2 + (y1 ::preal) proof − have (x1 + y2 ) + x = (x + y2 ) + x1 by (simp add: ac-simps) also have ... = (x2 + y) + x1 by (simp add: assms) also have ... = x2 + (x1 + y) by (simp add: ac-simps) 497 also have ... = x2 + (x + y1 ) by (simp add: assms) also have ... = (x2 + y1 ) + x by (simp add: ac-simps) finally have (x1 + y2 ) + x = (x2 + y1 ) + x . thus ?thesis by (rule preal-add-right-cancel) qed lemma realrel-iff [simp]: (((x1 ,y1 ),(x2 ,y2 )) ∈ realrel) = (x1 + y2 = x2 + y1 ) by (simp add: realrel-def ) lemma equiv-realrel: equiv UNIV realrel apply (auto simp add: equiv-def refl-on-def sym-def trans-def realrel-def ) apply (blast dest: preal-trans-lemma) done Reduces equality of equivalence classes to the Dedekind-Real.realrel relation: (Dedekind-Real.realrel ‘‘ {x} = Dedekind-Real.realrel ‘‘ {y}) = ((x, y) ∈ Dedekind-Real.realrel) lemmas equiv-realrel-iff = eq-equiv-class-iff [OF equiv-realrel UNIV-I UNIV-I ] declare equiv-realrel-iff [simp] lemma realrel-in-real [simp]: realrel‘‘{(x,y)}: Real by (simp add: Real-def realrel-def quotient-def , blast) declare Abs-Real-inject [simp] declare Abs-Real-inverse [simp] Case analysis on the representation of a real number as an equivalence class of pairs of positive reals. lemma eq-Abs-Real [case-names Abs-Real, cases type: real]: (!!x y. z = Abs-Real(realrel‘‘{(x,y)}) ==> P) ==> P apply (rule Rep-Real [of z, unfolded Real-def , THEN quotientE]) apply (drule arg-cong [where f =Abs-Real]) apply (auto simp add: Rep-Real-inverse) done 63.2 Addition and Subtraction lemma real-add-congruent2-lemma: [|a + ba = aa + b; ab + bc = ac + bb|] ==> a + ab + (ba + bc) = aa + ac + (b + (bb::preal)) apply (simp add: add.assoc) apply (rule add.left-commute [of ab, THEN ssubst]) apply (simp add: add.assoc [symmetric]) apply (simp add: ac-simps) done 498 lemma real-add: Abs-Real (realrel‘‘{(x,y)}) + Abs-Real (realrel‘‘{(u,v)}) = Abs-Real (realrel‘‘{(x+u, y+v)}) proof − have (λz w. (λ(x,y). (λ(u,v). {Abs-Real (realrel ‘‘ {(x+u, y+v)})}) w) z) respects2 realrel by (auto simp add: congruent2-def , blast intro: real-add-congruent2-lemma) thus ?thesis by (simp add: real-add-def UN-UN-split-split-eq UN-equiv-class2 [OF equiv-realrel equiv-realrel]) qed lemma real-minus: − Abs-Real(realrel‘‘{(x,y)}) = Abs-Real(realrel ‘‘ {(y,x)}) proof − have (λ(x,y). {Abs-Real (realrel‘‘{(y,x)})}) respects realrel by (auto simp add: congruent-def add.commute) thus ?thesis by (simp add: real-minus-def UN-equiv-class [OF equiv-realrel]) qed instance real :: ab-group-add proof fix x y z :: real show (x + y) + z = x + (y + z) by (cases x, cases y, cases z, simp add: real-add add.assoc) show x + y = y + x by (cases x, cases y, simp add: real-add add.commute) show 0 + x = x by (cases x, simp add: real-add real-zero-def ac-simps) show − x + x = 0 by (cases x, simp add: real-minus real-add real-zero-def add.commute) show x − y = x + − y by (simp add: real-diff-def ) qed 63.3 Multiplication lemma real-mult-congruent2-lemma: !!(x1 ::preal). [| x1 + y2 = x2 + y1 |] ==> x ∗ x1 + y ∗ y1 + (x ∗ y2 + y ∗ x2 ) = x ∗ x2 + y ∗ y2 + (x ∗ y1 + y ∗ x1 ) apply (simp add: add.left-commute add.assoc [symmetric]) apply (simp add: add.assoc distrib-left [symmetric]) apply (simp add: add.commute) done lemma real-mult-congruent2 : (%p1 p2 . 499 (%(x1 ,y1 ). (%(x2 ,y2 ). { Abs-Real (realrel‘‘{(x1 ∗x2 + y1 ∗y2 , x1 ∗y2 +y1 ∗x2 )}) }) p2 ) p1 ) respects2 realrel apply (rule congruent2-commuteI [OF equiv-realrel], clarify) apply (simp add: mult.commute add.commute) apply (auto simp add: real-mult-congruent2-lemma) done lemma real-mult: Abs-Real((realrel‘‘{(x1 ,y1 )})) ∗ Abs-Real((realrel‘‘{(x2 ,y2 )})) = Abs-Real(realrel ‘‘ {(x1 ∗x2 +y1 ∗y2 ,x1 ∗y2 +y1 ∗x2 )}) by (simp add: real-mult-def UN-UN-split-split-eq UN-equiv-class2 [OF equiv-realrel equiv-realrel real-mult-congruent2 ]) lemma real-mult-commute:(z::real) ∗ w = w ∗ z by (cases z, cases w, simp add: real-mult ac-simps) lemma real-mult-assoc: ((z1 ::real) ∗ z2 ) ∗ z3 = z1 ∗ (z2 ∗ z3 ) apply (cases z1 , cases z2 , cases z3 ) apply (simp add: real-mult algebra-simps) done lemma real-mult-1 :(1 ::real) ∗ z = z apply (cases z) apply (simp add: real-mult real-one-def algebra-simps) done lemma real-add-mult-distrib: ((z1 ::real) + z2 ) ∗ w = (z1 ∗ w) + (z2 ∗ w) apply (cases z1 , cases z2 , cases w) apply (simp add: real-add real-mult algebra-simps) done one and zero are distinct lemma real-zero-not-eq-one: 0 6= (1 ::real) proof − have (1 ::preal) < 1 + 1 by (simp add: preal-self-less-add-left) then show ?thesis by (simp add: real-zero-def real-one-def neq-iff ) qed instance real :: comm-ring-1 proof fix x y z :: real show (x ∗ y) ∗ z = x ∗ (y ∗ z) by (rule real-mult-assoc) show x ∗ y = y ∗ x by (rule real-mult-commute) show 1 ∗ x = x by (rule real-mult-1 ) show (x + y) ∗ z = x ∗ z + y ∗ z by (rule real-add-mult-distrib) show 0 6= (1 ::real) by (rule real-zero-not-eq-one) 500 qed 63.4 Inverse and Division lemma real-zero-iff : Abs-Real (realrel ‘‘ {(x, x)}) = 0 by (simp add: real-zero-def add.commute) Instead of using an existential quantifier and constructing the inverse within the proof, we could define the inverse explicitly. lemma real-mult-inverse-left-ex: x 6= 0 ==> ∃ y. y∗x = (1 ::real) apply (simp add: real-zero-def real-one-def , cases x) apply (cut-tac x = xa and y = y in linorder-less-linear) apply (auto dest!: less-add-left-Ex simp add: real-zero-iff ) apply (rule-tac x = Abs-Real (realrel‘‘{(1 , inverse (D) + 1 )}) in exI ) apply (rule-tac [2 ] x = Abs-Real (realrel‘‘{(inverse (D) + 1 , 1 )}) in exI ) apply (auto simp add: real-mult preal-mult-inverse-right algebra-simps) done lemma real-mult-inverse-left: x 6= 0 ==> inverse(x)∗x = (1 ::real) apply (simp add: real-inverse-def ) apply (drule real-mult-inverse-left-ex, safe) apply (rule theI , assumption, rename-tac z) apply (subgoal-tac (z ∗ x) ∗ y = z ∗ (x ∗ y)) apply (simp add: mult.commute) apply (rule mult.assoc) done 63.5 The Real Numbers form a Field instance real :: field proof fix x y z :: real show x 6= 0 ==> inverse x ∗ x = 1 by (rule real-mult-inverse-left) show x / y = x ∗ inverse y by (simp add: real-divide-def ) show inverse 0 = (0 ::real) by (simp add: real-inverse-def ) qed 63.6 The ≤ Ordering lemma real-le-refl: w ≤ (w::real) by (cases w, force simp add: real-le-def ) The arithmetic decision procedure is not set up for type preal. This lemma is currently unused, but it could simplify the proofs of the following two lemmas. 501 lemma preal-eq-le-imp-le: assumes eq: a+b = c+d and le: c ≤ a shows b ≤ (d::preal) proof − from le have c+d ≤ a+d by simp hence a+b ≤ a+d by (simp add: eq) thus b ≤ d by simp qed lemma real-le-lemma: assumes l: u1 + v2 ≤ u2 + v1 and x1 + v1 = u1 + y1 and x2 + v2 = u2 + y2 shows x1 + y2 ≤ x2 + (y1 ::preal) proof − have (x1 +v1 ) + (u2 +y2 ) = (u1 +y1 ) + (x2 +v2 ) by (simp add: assms) hence (x1 +y2 ) + (u2 +v1 ) = (x2 +y1 ) + (u1 +v2 ) by (simp add: ac-simps) also have ... ≤ (x2 +y1 ) + (u2 +v1 ) by (simp add: assms) finally show ?thesis by simp qed lemma real-le: (Abs-Real(realrel‘‘{(x1 ,y1 )}) ≤ Abs-Real(realrel‘‘{(x2 ,y2 )})) = (x1 + y2 ≤ x2 + y1 ) apply (simp add: real-le-def ) apply (auto intro: real-le-lemma) done lemma real-le-antisym:[| z ≤ w; w ≤ z |] ==> z = (w::real) by (cases z, cases w, simp add: real-le) lemma real-trans-lemma: assumes x + v ≤ u + y and u + v 0 ≤ u 0 + v and x2 + v2 = u2 + y2 shows x + v 0 ≤ u 0 + (y::preal) proof − have (x+v 0) + (u+v) = (x+v) + (u+v 0) by (simp add: ac-simps) also have ... ≤ (u+y) + (u+v 0) by (simp add: assms) also have ... ≤ (u+y) + (u 0+v) by (simp add: assms) also have ... = (u 0+y) + (u+v) by (simp add: ac-simps) finally show ?thesis by simp qed lemma real-le-trans:[| i ≤ j ; j ≤ k |] ==> i ≤ (k::real) apply (cases i, cases j , cases k) apply (simp add: real-le) apply (blast intro: real-trans-lemma) done 502 instance real :: order proof fix u v :: real show u < v ←→ u ≤ v ∧ ¬ v ≤ u by (auto simp add: real-less-def intro: real-le-antisym) qed (assumption | rule real-le-refl real-le-trans real-le-antisym)+ lemma real-le-linear:(z::real) ≤ w | w ≤ z apply (cases z, cases w) apply (auto simp add: real-le real-zero-def ac-simps) done instance real :: linorder by (intro-classes, rule real-le-linear) lemma real-le-eq-diff :(x ≤ y) = (x−y ≤ (0 ::real)) apply (cases x, cases y) apply (auto simp add: real-le real-zero-def real-diff-def real-add real-minus ac-simps) apply (simp-all add: add.assoc [symmetric]) done lemma real-add-left-mono: assumes le: x ≤ y shows z + x ≤ z + (y::real) proof − have z + x − (z + y) = (z + −z) + (x − y) by (simp add: algebra-simps) with le show ?thesis by (simp add: real-le-eq-diff [of x] real-le-eq-diff [of z+x]) qed lemma real-sum-gt-zero-less:(0 < S + (−W ::real)) ==> (W < S) by (simp add: linorder-not-le [symmetric] real-le-eq-diff [of S]) lemma real-less-sum-gt-zero:(W < S) ==> (0 < S + (−W ::real)) by (simp add: linorder-not-le [symmetric] real-le-eq-diff [of S]) lemma real-mult-order:[| 0 < x; 0 < y |] ==> (0 ::real) < x ∗ y apply (cases x, cases y) apply (simp add: linorder-not-le [where 0a = real, symmetric] linorder-not-le [where 0a = preal] real-zero-def real-le real-mult) — Reduce to the (simpler) ≤ relation apply (auto dest!: less-add-left-Ex simp add: algebra-simps preal-self-less-add-left) done 503 lemma real-mult-less-mono2 :[| (0 ::real) < z; x < y |] ==> z ∗ x < z ∗ y apply (rule real-sum-gt-zero-less) apply (drule real-less-sum-gt-zero [of x y]) apply (drule real-mult-order, assumption) apply (simp add: algebra-simps) done instantiation real :: distrib-lattice begin definition (inf :: real ⇒ real ⇒ real) = min definition (sup :: real ⇒ real ⇒ real) = max instance by standard (auto simp add: inf-real-def sup-real-def max-min-distrib2 ) end 63.7 The Reals Form an Ordered Field instance real :: linordered-field proof fix x y z :: real show x ≤ y ==> z + x ≤ z + y by (rule real-add-left-mono) show x < y ==> 0 < z ==> z ∗ x < z ∗ y by (rule real-mult-less-mono2 ) show |x| = (if x < 0 then −x else x) by (simp only: real-abs-def ) show sgn x = (if x=0 then 0 else if 0 The function real-of-preal requires many proofs, but it seems to be essential for proving completeness of the reals from that of the positive reals. lemma real-of-preal-add: real-of-preal ((x::preal) + y) = real-of-preal x + real-of-preal y by (simp add: real-of-preal-def real-add algebra-simps) lemma real-of-preal-mult: real-of-preal ((x::preal) ∗ y) = real-of-preal x∗ real-of-preal y by (simp add: real-of-preal-def real-mult algebra-simps) Gleason prop 9-4.4 p 127 lemma real-of-preal-trichotomy: ∃ m. (x::real) = real-of-preal m | x = 0 | x = −(real-of-preal m) apply (simp add: real-of-preal-def real-zero-def , cases x) apply (auto simp add: real-minus ac-simps) apply (cut-tac x = xa and y = y in linorder-less-linear) 504 apply (auto dest!: less-add-left-Ex simp add: add.assoc [symmetric]) done lemma real-of-preal-leD: real-of-preal m1 ≤ real-of-preal m2 ==> m1 ≤ m2 by (simp add: real-of-preal-def real-le) lemma real-of-preal-lessI : m1 < m2 ==> real-of-preal m1 < real-of-preal m2 by (auto simp add: real-of-preal-leD linorder-not-le [symmetric]) lemma real-of-preal-lessD: real-of-preal m1 < real-of-preal m2 ==> m1 < m2 by (simp add: real-of-preal-def real-le linorder-not-le [symmetric]) lemma real-of-preal-less-iff [simp]: (real-of-preal m1 < real-of-preal m2 ) = (m1 < m2 ) by (blast intro: real-of-preal-lessI real-of-preal-lessD) lemma real-of-preal-le-iff : (real-of-preal m1 ≤ real-of-preal m2 ) = (m1 ≤ m2 ) by (simp add: linorder-not-less [symmetric]) lemma real-of-preal-zero-less: 0 < real-of-preal m using preal-self-less-add-left [of 1 m] apply (auto simp add: real-zero-def real-of-preal-def real-less-def real-le-def ac-simps neq-iff ) apply (metis Rep-preal-self-subset add.commute preal-le-def ) done lemma real-of-preal-minus-less-zero: − real-of-preal m < 0 by (simp add: real-of-preal-zero-less) lemma real-of-preal-not-minus-gt-zero: ∼ 0 < − real-of-preal m proof − from real-of-preal-minus-less-zero show ?thesis by (blast dest: order-less-trans) qed 63.8 Theorems About the Ordering lemma real-gt-zero-preal-Ex:(0 < x) = (∃ y. x = real-of-preal y) apply (auto simp add: real-of-preal-zero-less) apply (cut-tac x = x in real-of-preal-trichotomy) apply (blast elim!: real-of-preal-not-minus-gt-zero [THEN notE]) done lemma real-gt-preal-preal-Ex: real-of-preal z < x ==> ∃ y. x = real-of-preal y by (blast dest!: real-of-preal-zero-less [THEN order-less-trans] 505 intro: real-gt-zero-preal-Ex [THEN iffD1 ]) lemma real-ge-preal-preal-Ex: real-of-preal z ≤ x ==> ∃ y. x = real-of-preal y by (blast dest: order-le-imp-less-or-eq real-gt-preal-preal-Ex) lemma real-less-all-preal: y ≤ 0 ==> ∀ x. y < real-of-preal x by (auto elim: order-le-imp-less-or-eq [THEN disjE] intro: real-of-preal-zero-less [THEN [2 ] order-less-trans] simp add: real-of-preal-zero-less) lemma real-less-all-real2 : ∼ 0 < y ==> ∀ x. y < real-of-preal x by (blast intro!: real-less-all-preal linorder-not-less [THEN iffD1 ]) 63.9 Completeness of Positive Reals Supremum property for the set of positive reals Let P be a non-empty set of positive reals, with an upper bound y. Then P has a least upper bound (written S). FIXME: Can the premise be weakened to ∀ x ∈ P. x≤ y? lemma posreal-complete: assumes positive-P: ∀ x ∈ P. (0 ::real) < x and not-empty-P: ∃ x. x ∈ P and upper-bound-Ex: ∃ y. ∀ x ∈ P. x show (∃ x∈P. y < x) = (y < real-of-preal (psup ?pP)) proof (cases 0 < y) assume neg-y: ¬ 0 < y show ?thesis proof assume ∃ x∈P. y < x have ∀ x. y < real-of-preal x using neg-y by (rule real-less-all-real2 ) thus y < real-of-preal (psup ?pP) .. next assume y < real-of-preal (psup ?pP) obtain x where x-in-P: x ∈ P using not-empty-P .. hence 0 < x using positive-P by simp hence y < x using neg-y by simp thus ∃ x ∈ P. y < x using x-in-P .. qed next assume pos-y: 0 < y 506 then obtain py where y-is-py: y = real-of-preal py by (auto simp add: real-gt-zero-preal-Ex) obtain a where a ∈ P using not-empty-P .. with positive-P have a-pos: 0 < a .. then obtain pa where a = real-of-preal pa by (auto simp add: real-gt-zero-preal-Ex) hence pa ∈ ?pP using ha ∈ P i by auto hence pP-not-empty: ?pP 6= {} by auto obtain sup where sup: ∀ x ∈ P. x < sup using upper-bound-Ex .. from this and ha ∈ P i have a < sup .. hence 0 < sup using a-pos by arith then obtain possup where sup = real-of-preal possup by (auto simp add: real-gt-zero-preal-Ex) hence ∀ X ∈ ?pP. X ≤ possup using sup by (auto simp add: real-of-preal-lessI ) with pP-not-empty have psup: VZ . (∃ X ∈ ?pP. Z < X ) = (Z < psup ?pP) by (rule preal-complete) show ?thesis proof assume ∃ x ∈ P. y < x then obtain x where x-in-P: x ∈ P and y-less-x: y < x .. hence 0 < x using pos-y by arith then obtain px where x-is-px: x = real-of-preal px by (auto simp add: real-gt-zero-preal-Ex) have py-less-X : ∃ X ∈ ?pP. py < X proof show py < px using y-is-py and x-is-px and y-less-x by (simp add: real-of-preal-lessI ) show px ∈ ?pP using x-in-P and x-is-px by simp qed have (∃ X ∈ ?pP. py < X ) ==> (py < psup ?pP) using psup by simp hence py < psup ?pP using py-less-X by simp thus y < real-of-preal (psup {w. real-of-preal w ∈ P}) using y-is-py and pos-y by (simp add: real-of-preal-lessI ) next assume y-less-psup: y < real-of-preal (psup ?pP) hence py < psup ?pP using y-is-py by (simp add: real-of-preal-lessI ) then obtain X where py-less-X : py < X and X-in-pP: X ∈ ?pP using psup by auto then obtain x where x-is-X : x = real-of-preal X 507 by (simp add: real-gt-zero-preal-Ex) hence y < x using py-less-X and y-is-py by (simp add: real-of-preal-lessI ) moreover have x ∈ P using x-is-X and X-in-pP by simp ultimately show ∃ x ∈ P. y < x .. qed qed qed Completeness lemma reals-complete: fixes S :: real set assumes notempty-S: ∃ X . X ∈ S and exists-Ub: bdd-above S shows ∃ x. (∀ s∈S. s ≤ x) ∧ (∀ y. (∀ s∈S. s ≤ y) −→ x ≤ y) proof − obtain X where X-in-S: X ∈ S using notempty-S .. obtain Y where Y-isUb: ∀ s∈S. s ≤ Y using exists-Ub by (auto simp: bdd-above-def ) let ?SHIFT = {z. ∃ x ∈S. z = x + (−X ) + 1 } ∩ {x. 0 < x} { fix x assume S-le-x: ∀ s∈S. s ≤ x { fix s assume s ∈ {z. ∃ x∈S. z = x + − X + 1 } hence ∃ x ∈ S. s = x + −X + 1 .. then obtain x1 where x1 : x1 ∈ S s = x1 + (−X ) + 1 .. then have x1 ≤ x using S-le-x by simp with x1 have s ≤ x + − X + 1 by arith } then have ∀ s∈?SHIFT . s ≤ x + (−X ) + 1 by auto } note S-Ub-is-SHIFT-Ub = this have ∗: ∀ s∈?SHIFT . s ≤ Y + (−X ) + 1 using Y-isUb by (rule S-Ub-is-SHIFT-Ub) have ∀ s∈?SHIFT . s < Y + (−X ) + 2 proof fix s assume s∈?SHIFT with ∗ have s ≤ Y + (−X ) + 1 by simp also have . . . < Y + (−X ) + 2 by simp finally show s < Y + (−X ) + 2 . qed moreover have ∀ y ∈ ?SHIFT . 0 < y by auto moreover have shifted-not-empty: ∃ u. u ∈ ?SHIFT using X-in-S and Y-isUb by auto 508 ultimately obtain t where t-is-Lub: ∀ y. (∃ x∈?SHIFT . y < x) = (y < t) using posreal-complete [of ?SHIFT ] unfolding bdd-above-def by blast show ?thesis proof show (∀ s∈S. s ≤ (t + X + (−1 ))) ∧ (∀ y. (∀ s∈S. s ≤ y) −→ (t + X + (−1 )) ≤ y) proof safe fix x assume ∀ s∈S. s ≤ x hence ∀ s∈?SHIFT . s ≤ x + (−X ) + 1 using S-Ub-is-SHIFT-Ub by simp then have ¬ x + (−X ) + 1 < t by (subst t-is-Lub[rule-format, symmetric]) (simp add: not-less) thus t + X + −1 ≤ x by arith next fix y assume y-in-S: y ∈ S obtain u where u-in-shift: u ∈ ?SHIFT using shifted-not-empty .. hence ∃ x ∈ S. u = x + − X + 1 by simp then obtain x where x-and-u: u = x + − X + 1 .. have u-le-t: u ≤ t proof (rule dense-le) fix x assume x < u then have x < t using u-in-shift t-is-Lub by auto then show x ≤ t by simp qed show y ≤ t + X + −1 proof cases assume y ≤ x moreover have x = u + X + − 1 using x-and-u by arith moreover have u + X + − 1 ≤ t + X + −1 using u-le-t by arith ultimately show y ≤ t + X + −1 by arith next assume ∼(y ≤ x) hence x-less-y: x < y by arith have x + (−X ) + 1 ∈ ?SHIFT using x-and-u and u-in-shift by simp hence 0 < x + (−X ) + 1 by simp hence 0 < y + (−X ) + 1 using x-less-y by arith hence ∗: y + (−X ) + 1 ∈ ?SHIFT using y-in-S by simp have y + (−X ) + 1 ≤ t proof (rule dense-le) fix x assume x < y + (−X ) + 1 then have x < t using ∗ t-is-Lub by auto then show x ≤ t by simp qed thus ?thesis by simp 509 qed qed qed qed 63.10 The Archimedean Property of the Reals theorem reals-Archimedean: fixes x :: real assumes x-pos: 0 < x shows ∃ n. inverse (of-nat (Suc n)) < x proof (rule ccontr) assume contr: ¬ ?thesis have ∀ n. x ∗ of-nat (Suc n) <= 1 proof fix n from contr have x ≤ inverse (of-nat (Suc n)) by (simp add: linorder-not-less) hence x ≤ (1 / (of-nat (Suc n))) by (simp add: inverse-eq-divide) moreover have (0 ::real) ≤ of-nat (Suc n) by (rule of-nat-0-le-iff ) ultimately have x ∗ of-nat (Suc n) ≤ (1 / of-nat (Suc n)) ∗ of-nat (Suc n) by (rule mult-right-mono) thus x ∗ of-nat (Suc n) ≤ 1 by (simp del: of-nat-Suc) qed hence 2 : bdd-above {z. ∃ n. z = x ∗ (of-nat (Suc n))} by (auto intro!: bdd-aboveI [of - 1 ]) have 1 : ∃ X . X ∈ {z. ∃ n. z = x∗ (of-nat (Suc n))} by auto obtain t where upper: Vz. z ∈ {z. ∃ n. z = x ∗ of-nat (Suc n)} =⇒ z ≤ t and least: Vy. (Va. a ∈ {z. ∃ n. z = x ∗ of-nat (Suc n)} =⇒ a ≤ y) =⇒ t ≤ y using reals-complete[OF 1 2 ] by auto have t ≤ t + − x proof (rule least) fix a assume a: a ∈ {z. ∃ n. z = x ∗ (of-nat (Suc n))} have ∀ n::nat. x ∗ of-nat n ≤ t + − x proof fix n have x ∗ of-nat (Suc n) ≤ t by (simp add: upper) hence x ∗ (of-nat n) + x ≤ t by (simp add: distrib-left) thus x ∗ (of-nat n) ≤ t + − x by arith qed hence ∀ m. x ∗ of-nat (Suc m) ≤ t + − x by (simp del: of-nat-Suc) with a show a ≤ t + − x by auto 510 qed thus False using x-pos by arith qed There must be other proofs, e.g. Suc of the largest integer in the cut repre- senting x. lemma reals-Archimedean2 : ∃ n. (x::real) < of-nat (n::nat) proof cases assume x ≤ 0 hence x < of-nat (1 ::nat) by simp thus ?thesis .. next assume ¬ x ≤ 0 hence x-greater-zero: 0 < x by simp hence 0 < inverse x by simp then obtain n where inverse (of-nat (Suc n)) < inverse x using reals-Archimedean by blast hence inverse (of-nat (Suc n)) ∗ x < inverse x ∗ x using x-greater-zero by (rule mult-strict-right-mono) hence inverse (of-nat (Suc n)) ∗ x < 1 using x-greater-zero by simp hence of-nat (Suc n) ∗ (inverse (of-nat (Suc n)) ∗ x) < of-nat (Suc n) ∗ 1 by (rule mult-strict-left-mono)(simp del: of-nat-Suc) hence x < of-nat (Suc n) by (simp add: algebra-simps del: of-nat-Suc) thus ∃ (n::nat). x < of-nat n .. qed instance real :: archimedean-field proof fix r :: real obtain n :: nat where r < of-nat n using reals-Archimedean2 .. then have r ≤ of-int (int n) by simp then show ∃ z. r ≤ of-int z .. qed end 64 Quicksort with function package theory Quicksort imports ∼∼/src/HOL/Library/Multiset begin context linorder begin 511 fun quicksort :: 0a list ⇒ 0a list where quicksort [] = [] | quicksort (x#xs) = quicksort [y←xs. ¬ x≤y]@[x]@ quicksort [y←xs. x≤y] lemma [code]: quicksort [] = [] quicksort (x#xs) = quicksort [y←xs. y 65 A Formulation of the Birthday Paradox theory Birthday-Paradox imports Main ∼∼/src/HOL/Binomial ∼∼/src/HOL/Library/FuncSet begin 66 Cardinality lemma card-product-dependent: assumes finite S assumes ∀ x ∈ S. finite (T x) shows card {(x, y). x ∈ S ∧ y ∈ T x} = (P x ∈ S. card (T x)) using card-SigmaI [OF assms, symmetric] by (auto intro!: arg-cong[where f =card] simp add: Sigma-def ) lemma card-extensional-funcset-inj-on: 512 assumes finite S finite T card S ≤ card T shows card {f ∈ extensional-funcset S T . inj-on f S} = fact (card T ) div (fact (card T − card S)) using assms proof (induct S arbitrary: T rule: finite-induct) case empty from this show ?case by (simp add: Collect-conv-if PiE-empty-domain) next case (insert x S) { fix x from hfinite T i have finite (T − {x}) by auto from hfinite S i this have finite (extensional-funcset S (T − {x})) by (rule finite-PiE) moreover have {f : extensional-funcset S (T − {x}). inj-on f S} ⊆ (extensional-funcset S (T − {x})) by auto ultimately have finite {f : extensional-funcset S (T − {x}). inj-on f S} by (auto intro: finite-subset) } note finite-delete = this from insert have hyps: ∀ y ∈ T . card ({g. g ∈ extensional-funcset S (T − {y}) ∧ inj-on g S}) = fact (card T − 1 ) div fact ((card T − 1 ) − card S)(is ∀ - ∈ T . - = ?k) by auto from extensional-funcset-extend-domain-inj-on-eq[OF hx ∈/ S i] have card {f . f : extensional-funcset (insert x S) T & inj-on f (insert x S)} = card ((%(y, g). g(x := y)) ‘ {(y, g). y : T & g : extensional-funcset S (T − {y})& inj-on g S}) by metis also from extensional-funcset-extend-domain-inj-onI [OF hx ∈/ S i, of T ] have ... = card {(y, g). y : T & g : extensional-funcset S (T − {y})& inj-on g S} by (simp add: card-image) also have card {(y, g). y ∈ T ∧ g ∈ extensional-funcset S (T − {y}) ∧ inj-on g S} = card {(y, g). y ∈ T ∧ g ∈ {f ∈ extensional-funcset S (T − {y}). inj-on f S}} by auto also from hfinite T i finite-delete have ... = (P y ∈ T . card {g. g ∈ extensional-funcset S (T − {y}) ∧ inj-on g S}) by (subst card-product-dependent) auto also from hyps have ... = (card T ) ∗ ?k by auto also have ... = card T ∗ fact (card T − 1 ) div fact (card T − card (insert x S)) using insert unfolding div-mult1-eq[of card T fact (card T − 1 )] by (simp add: fact-mod) also have ... = fact (card T ) div fact (card T − card (insert x S)) using insert by (simp add: fact-reduce[of card T ]) finally show ?case . qed lemma card-extensional-funcset-not-inj-on: assumes finite S finite T card S ≤ card T 513 shows card {f ∈ extensional-funcset S T . ¬ inj-on f S} = (card T ) ˆ (card S) − (fact (card T )) div (fact (card T − card S)) proof − have subset: {f : extensional-funcset S T . inj-on f S} <= extensional-funcset S T by auto from finite-subset[OF subset] assms have finite: finite {f : extensional-funcset ST . inj-on f S} by (auto intro!: finite-PiE) have {f ∈ extensional-funcset S T . ¬ inj-on f S} = extensional-funcset S T − {f ∈ extensional-funcset S T . inj-on f S} by auto from assms this finite subset show ?thesis by (simp add: card-Diff-subset card-PiE card-extensional-funcset-inj-on prod-constant) qed lemma prod-upto-nat-unfold: prod f {m..(n::nat)} = (if n < m then 1 else (if n = 0 then f 0 else f n ∗ prod f {m..(n − 1 )})) by auto (auto simp add: gr0-conv-Suc atLeastAtMostSuc-conv) 67 Birthday paradox lemma birthday-paradox: assumes card S = 23 card T = 365 shows 2 ∗ card {f ∈ extensional-funcset S T . ¬ inj-on f S} ≥ card (extensional-funcset ST ) proof − from hcard S = 23 i hcard T = 365 i have finite S finite T card S <= card T by (auto intro: card-ge-0-finite) from assms show ?thesis using card-PiE[OF hfinite S i, of λi. T ] hfinite S i card-extensional-funcset-not-inj-on[OF hfinite S i hfinite T i hcard S <= card T i] by (simp add: fact-div-fact prod-upto-nat-unfold prod-constant) qed end 68 Examples for the list comprehension to set com- prehension simproc theory List-to-Set-Comprehension-Examples imports Main begin Examples that show and test the simproc that rewrites list comprehensions applied to List.set to set comprehensions. 514 68.1 Some own examples for set (case ..) simpproc lemma set [(x, xs). x # xs <− as] = {(x, xs). x # xs ∈ set as} by auto lemma set [(x, y, ys). x # y # ys <− as] = {(x, y, ys). x # y # ys ∈ set as} by auto lemma set [(x, y, z, zs). x # y # z # zs <− as] = {(x, y, z, zs). x # y # z # zs ∈ set as} by auto lemma set [(zs, x, z, y). x #(y, z)# zs <− as] = {(zs, x, z, y). x #(y, z)# zs ∈ set as} by auto lemma set [(x, y). x # y <− zs, x = x 0] = {(x, y). x # y ∈ set zs & x = x 0} by auto 68.2 Existing examples from the List theory lemma set [(x,y,z). b] = {(x 0, y 0, z 0). x = x 0 & y = y 0 & z = z 0 & b} by auto lemma set [(x,y,z). x←xs] = {(x, y 0, z 0). x ∈ set xs & y 0 = y & z = z 0} by auto lemma set [e x y. x←xs, y←ys] = {z. ∃ x y. z = e x y & x ∈ set xs & y ∈ set ys} by auto lemma set [(x,y,z). xb] = {(x 0, y 0, z 0). x 0 = x & y 0 = y & z = z 0 & x < a & x>b} by auto lemma set [(x,y,z). x←xs, x>b] = {(x 0, y 0, z 0). y = y 0 & z = z 0 & x 0 ∈ set xs & x 0 > b} by auto lemma set [(x,y,z). x 515 lemma set [(x,y,z). xb, x=d] = {(x 0, y 0, z 0). x = x 0 & y = y 0 & z = z 0 & x < a & x > b & x = d} by auto lemma set [(x,y,z). xb, y←ys] = {(x 0, y, z 0). x = x 0 & y ∈ set ys & z = z 0 & x < a & x > b} by auto lemma set [(x,y,z). xb] = {(x 0,y 0,z 0). x 0 ∈ set xs & y = y 0 & z = z 0 & x < a & y > b} by auto lemma set [(x,y,z). xb, y b & y < a} by auto lemma set [(x,y,z). x←xs, x>b, y←ys] = {(x 0, y 0, z 0). z = z 0 & x 0 ∈ set xs & x 0 > b & y 0 ∈ set ys} by auto lemma set [(x,y,z). x←xs, y←ys,y>x] = {(x 0, y 0, z 0). z = z 0 & x 0 ∈ set xs & y 0 ∈ set ys & y 0 > x 0} by auto lemma set [(x,y,z). x←xs, y←ys,z←zs] = {(x 0, y 0, z 0). x 0 ∈ set xs & y 0 ∈ set ys & z 0 ∈ set zs} by auto end 69 Finite sequences theory Seq imports Main begin datatype 0a seq = Empty | Seq 0a 0a seq fun conc :: 0a seq ⇒ 0a seq ⇒ 0a seq where conc Empty ys = ys | conc (Seq x xs) ys = Seq x (conc xs ys) fun reverse :: 0a seq ⇒ 0a seq where 516 reverse Empty = Empty | reverse (Seq x xs) = conc (reverse xs)(Seq x Empty) lemma conc-empty: conc xs Empty = xs by (induct xs) simp-all lemma conc-assoc: conc (conc xs ys) zs = conc xs (conc ys zs) by (induct xs) simp-all lemma reverse-conc: reverse (conc xs ys) = conc (reverse ys)(reverse xs) by (induct xs)(simp-all add: conc-empty conc-assoc) lemma reverse-reverse: reverse (reverse xs) = xs by (induct xs)(simp-all add: reverse-conc) end 70 Testing of arithmetic simprocs theory Simproc-Tests imports Main begin This theory tests the various simprocs defined in ~~/src/HOL/Nat.thy and ~~/src/HOL/Numeral_Simprocs.thy. Many of the tests are derived from commented-out code originally found in ~~/src/HOL/Tools/numeral_simprocs.ML. 70.1 ML bindings ML h fun test ctxt ps = CHANGED (asm-simp-tac (put-simpset HOL-basic-ss ctxt addsimprocs ps) 1 ) i 70.2 Cancellation simprocs from Nat.thy notepad begin fix a b c d :: nat { assume b = Suc c have a + b = Suc (c + a) by (tactic htest @{context} [@{simproc nateq-cancel-sums}]i) fact next assume b < Suc c have a + b < Suc (c + a) by (tactic htest @{context} [@{simproc natless-cancel-sums}]i) fact next assume b ≤ Suc c have a + b ≤ Suc (c + a) by (tactic htest @{context} [@{simproc natle-cancel-sums}]i) fact next assume b − Suc c = d have a + b − Suc (c + a) = d 517 by (tactic htest @{context} [@{simproc natdiff-cancel-sums}]i) fact } end schematic-goal V(y::? 0b::size). size (?x::? 0a::size) ≤ size y + size ?x by (tactic htest @{context} [@{simproc natle-cancel-sums}]i)(rule le0 ) 70.3 Abelian group cancellation simprocs notepad begin fix a b c u :: 0a::ab-group-add { assume (a + 0 ) − (b + 0 ) = u have (a + c) − (b + c) = u by (tactic htest @{context} [@{simproc group-cancel-diff }]i) fact next assume a + 0 = b + 0 have a + c = b + c by (tactic htest @{context} [@{simproc group-cancel-eq}]i) fact } end 70.4 int-combine-numerals notepad begin fix a b c d oo uu i j k l u v w x y z :: 0a::comm-ring-1 { assume a + − b = u have (a + c) − (b + c) = u by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume 10 + (2 ∗ l + oo) = uu have l + 2 + 2 + 2 + (l + 2 ) + (oo + 2 ) = uu by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume −3 + (i + (j + k)) = y have (i + j + 12 + k) − 15 = y by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume 7 + (i + (j + k)) = y have (i + j + 12 + k) − 5 = y by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume −4 ∗ (u ∗ v) + (2 ∗ x + y) = w have (2 ∗x − (u∗v) + y) − v∗3 ∗u = w by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume 2 ∗ x ∗ u ∗ v + y = w have (2 ∗x∗u∗v + (u∗v)∗4 + y) − v∗u∗4 = w by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume 3 ∗ (u ∗ v) + (2 ∗ x ∗ u ∗ v + y) = w have (2 ∗x∗u∗v + (u∗v)∗4 + y) − v∗u = w 518 by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume −3 ∗ (u ∗ v) + (− (x ∗ u ∗ v) + − y) = w have u∗v − (x∗u∗v + (u∗v)∗4 + y) = w by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume a + − c = d have a + −(b+c) + b = d apply (simp only: minus-add-distrib) by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume −2 ∗ b + (a + − c) = d have a + −(b+c) − b = d apply (simp only: minus-add-distrib) by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume −7 + (i + (j + (k + (− u + − y)))) = z have (i + j + −2 + k) − (u + 5 + y) = z by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume −27 + (i + (j + k)) = y have (i + j + −12 + k) − 15 = y by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume 27 + (i + (j + k)) = y have (i + j + 12 + k) − −15 = y by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact next assume 3 + (i + (j + k)) = y have (i + j + −12 + k) − −15 = y by (tactic htest @{context} [@{simproc int-combine-numerals}]i) fact } end 70.5 inteq-cancel-numerals notepad begin fix i j k u vv w y z w 0 y 0 z 0 :: 0a::comm-ring-1 { assume u = 0 have 2 ∗u = u by (tactic htest @{context} [@{simproc inteq-cancel-numerals}]i) fact next assume i + (j + k) = 3 + (u + y) have (i + j + 12 + k) = u + 15 + y by (tactic htest @{context} [@{simproc inteq-cancel-numerals}]i) fact next assume 7 + (j + (i + k)) = y have (i + j ∗2 + 12 + k) = j + 5 + y 519 by (tactic htest @{context} [@{simproc inteq-cancel-numerals}]i) fact next assume u + (6 ∗z + (4 ∗y + 6 ∗w)) = 6 ∗z 0 + (4 ∗y 0 + (6 ∗w 0 + vv)) have 2 ∗y + 3 ∗z + 6 ∗w + 2 ∗y + 3 ∗z + 2 ∗u = 2 ∗y 0 + 3 ∗z 0 + 6 ∗w 0 + 2 ∗y 0 + 3 ∗z 0 + u + vv by (tactic htest @{context} [@{simproc int-combine-numerals}, @{simproc inteq-cancel-numerals}]i) fact } end 70.6 intless-cancel-numerals notepad begin fix b c i j k u y :: 0a::linordered-idom { assume y < 2 ∗ b have y − b < b by (tactic htest @{context} [@{simproc intless-cancel-numerals}]i) fact next assume c + y < 4 ∗ b have y − (3 ∗b + c) < b − 2 ∗c by (tactic htest @{context} [@{simproc intless-cancel-numerals}]i) fact next assume i + (j + k) < 8 + (u + y) have (i + j + −3 + k) < u + 5 + y by (tactic htest @{context} [@{simproc intless-cancel-numerals}]i) fact next assume 9 + (i + (j + k)) < u + y have (i + j + 3 + k) < u + −6 + y by (tactic htest @{context} [@{simproc intless-cancel-numerals}]i) fact } end 70.7 ring-eq-cancel-numeral-factor notepad begin fix x y :: 0a::{idom,ring-char-0 } { assume 3 ∗x = 4 ∗y have 9 ∗x = 12 ∗ y by (tactic htest @{context} [@{simproc ring-eq-cancel-numeral-factor}]i) fact next assume −3 ∗x = 4 ∗y have −99 ∗x = 132 ∗ y by (tactic htest @{context} [@{simproc ring-eq-cancel-numeral-factor}]i) fact next assume 111 ∗x = −44 ∗y have 999 ∗x = −396 ∗ y by (tactic htest @{context} [@{simproc ring-eq-cancel-numeral-factor}]i) fact next assume 11 ∗x = 9 ∗y have −99 ∗x = −81 ∗ y by (tactic htest @{context} [@{simproc ring-eq-cancel-numeral-factor}]i) fact next assume 2 ∗x = y have −2 ∗ x = −1 ∗ y by (tactic htest @{context} [@{simproc ring-eq-cancel-numeral-factor}]i) fact 520 next assume 2 ∗x = y have −2 ∗ x = −y by (tactic htest @{context} [@{simproc ring-eq-cancel-numeral-factor}]i) fact } end 70.8 int-div-cancel-numeral-factors notepad begin fix x y z :: 0a::{semiring-div,comm-ring-1 ,ring-char-0 } { assume (3 ∗x) div (4 ∗y) = z have (9 ∗x) div (12 ∗y) = z by (tactic htest @{context} [@{simproc int-div-cancel-numeral-factors}]i) fact next assume (−3 ∗x) div (4 ∗y) = z have (−99 ∗x) div (132 ∗y) = z by (tactic htest @{context} [@{simproc int-div-cancel-numeral-factors}]i) fact next assume (111 ∗x) div (−44 ∗y) = z have (999 ∗x) div (−396 ∗y) = z by (tactic htest @{context} [@{simproc int-div-cancel-numeral-factors}]i) fact next assume (11 ∗x) div (9 ∗y) = z have (−99 ∗x) div (−81 ∗y) = z by (tactic htest @{context} [@{simproc int-div-cancel-numeral-factors}]i) fact next assume (2 ∗x) div y = z have (−2 ∗ x) div (−1 ∗ y) = z by (tactic htest @{context} [@{simproc int-div-cancel-numeral-factors}]i) fact } end 70.9 ring-less-cancel-numeral-factor notepad begin fix x y :: 0a::linordered-idom { assume 3 ∗x < 4 ∗y have 9 ∗x < 12 ∗ y by (tactic htest @{context} [@{simproc ring-less-cancel-numeral-factor}]i) fact next assume −3 ∗x < 4 ∗y have −99 ∗x < 132 ∗ y by (tactic htest @{context} [@{simproc ring-less-cancel-numeral-factor}]i) fact next assume 111 ∗x < −44 ∗y have 999 ∗x < −396 ∗ y by (tactic htest @{context} [@{simproc ring-less-cancel-numeral-factor}]i) fact next assume 9 ∗y < 11 ∗x have −99 ∗x < −81 ∗ y by (tactic htest @{context} [@{simproc ring-less-cancel-numeral-factor}]i) fact next assume y < 2 ∗x have −2 ∗ x < −y by (tactic htest @{context} [@{simproc ring-less-cancel-numeral-factor}]i) fact next assume 23 ∗y < x have −x < −23 ∗ y 521 by (tactic htest @{context} [@{simproc ring-less-cancel-numeral-factor}]i) fact } end 70.10 ring-le-cancel-numeral-factor notepad begin fix x y :: 0a::linordered-idom { assume 3 ∗x ≤ 4 ∗y have 9 ∗x ≤ 12 ∗ y by (tactic htest @{context} [@{simproc ring-le-cancel-numeral-factor}]i) fact next assume −3 ∗x ≤ 4 ∗y have −99 ∗x ≤ 132 ∗ y by (tactic htest @{context} [@{simproc ring-le-cancel-numeral-factor}]i) fact next assume 111 ∗x ≤ −44 ∗y have 999 ∗x ≤ −396 ∗ y by (tactic htest @{context} [@{simproc ring-le-cancel-numeral-factor}]i) fact next assume 9 ∗y ≤ 11 ∗x have −99 ∗x ≤ −81 ∗ y by (tactic htest @{context} [@{simproc ring-le-cancel-numeral-factor}]i) fact next assume y ≤ 2 ∗x have −2 ∗ x ≤ −1 ∗ y by (tactic htest @{context} [@{simproc ring-le-cancel-numeral-factor}]i) fact next assume 23 ∗y ≤ x have −x ≤ −23 ∗ y by (tactic htest @{context} [@{simproc ring-le-cancel-numeral-factor}]i) fact next assume y ≤ 0 have 0 ≤ y ∗ −2 by (tactic htest @{context} [@{simproc ring-le-cancel-numeral-factor}]i) fact next assume − x ≤ y have − (2 ∗ x) ≤ 2 ∗y by (tactic htest @{context} [@{simproc ring-le-cancel-numeral-factor}]i) fact } end 70.11 divide-cancel-numeral-factor notepad begin fix x y z :: 0a::{field,ring-char-0 } { assume (3 ∗x) / (4 ∗y) = z have (9 ∗x) / (12 ∗ y) = z by (tactic htest @{context} [@{simproc divide-cancel-numeral-factor}]i) fact next assume (−3 ∗x) / (4 ∗y) = z have (−99 ∗x) / (132 ∗ y) = z by (tactic htest @{context} [@{simproc divide-cancel-numeral-factor}]i) fact next assume (111 ∗x) / (−44 ∗y) = z have (999 ∗x) / (−396 ∗ y) = z by (tactic htest @{context} [@{simproc divide-cancel-numeral-factor}]i) fact next assume (11 ∗x) / (9 ∗y) = z have (−99 ∗x) / (−81 ∗ y) = z 522 by (tactic htest @{context} [@{simproc divide-cancel-numeral-factor}]i) fact next assume (2 ∗x) / y = z have (−2 ∗ x) / (−1 ∗ y) = z by (tactic htest @{context} [@{simproc divide-cancel-numeral-factor}]i) fact } end 70.12 ring-eq-cancel-factor notepad begin fix a b c d k x y :: 0a::idom { assume k = 0 ∨ x = y have x∗k = k∗y by (tactic htest @{context} [@{simproc ring-eq-cancel-factor}]i) fact next assume k = 0 ∨ 1 = y have k = k∗y by (tactic htest @{context} [@{simproc ring-eq-cancel-factor}]i) fact next assume b = 0 ∨ a∗c = 1 have a∗(b∗c) = b by (tactic htest @{context} [@{simproc ring-eq-cancel-factor}]i) fact next assume a = 0 ∨ b = 0 ∨ c = d∗x have a∗(b∗c) = d∗b∗(x∗a) by (tactic htest @{context} [@{simproc ring-eq-cancel-factor}]i) fact next assume k = 0 ∨ x = y have x∗k = k∗y by (tactic htest @{context} [@{simproc ring-eq-cancel-factor}]i) fact next assume k = 0 ∨ 1 = y have k = k∗y by (tactic htest @{context} [@{simproc ring-eq-cancel-factor}]i) fact } end 70.13 int-div-cancel-factor notepad begin fix a b c d k uu x y :: 0a::semiring-div { assume (if k = 0 then 0 else x div y) = uu have (x∗k) div (k∗y) = uu by (tactic htest @{context} [@{simproc int-div-cancel-factor}]i) fact next assume (if k = 0 then 0 else 1 div y) = uu have (k) div (k∗y) = uu by (tactic htest @{context} [@{simproc int-div-cancel-factor}]i) fact next assume (if b = 0 then 0 else a ∗ c) = uu have (a∗(b∗c)) div b = uu by (tactic htest @{context} [@{simproc int-div-cancel-factor}]i) fact next assume (if a = 0 then 0 else if b = 0 then 0 else c div (d ∗ x)) = uu 523 have (a∗(b∗c)) div (d∗b∗(x∗a)) = uu by (tactic htest @{context} [@{simproc int-div-cancel-factor}]i) fact } end lemma shows a∗(b∗c)/(y∗z) = d∗(b:: 0a::linordered-field)∗(x∗a)/z oops — FIXME: need simproc to cover this case 70.14 divide-cancel-factor notepad begin fix a b c d k uu x y :: 0a::field { assume (if k = 0 then 0 else x / y) = uu have (x∗k) / (k∗y) = uu by (tactic htest @{context} [@{simproc divide-cancel-factor}]i) fact next assume (if k = 0 then 0 else 1 / y) = uu have (k) / (k∗y) = uu by (tactic htest @{context} [@{simproc divide-cancel-factor}]i) fact next assume (if b = 0 then 0 else a ∗ c) = uu have (a∗(b∗c)) / b = uu by (tactic htest @{context} [@{simproc divide-cancel-factor}]i) fact next assume (if a = 0 then 0 else if b = 0 then 0 else c / (d ∗ x)) = uu have (a∗(b∗c)) / (d∗b∗(x∗a)) = uu by (tactic htest @{context} [@{simproc divide-cancel-factor}]i) fact } end lemma fixes a b c d x y z :: 0a::linordered-field shows a∗(b∗c)/(y∗z) = d∗(b)∗(x∗a)/z oops — FIXME: need simproc to cover this case 70.15 linordered-ring-less-cancel-factor notepad begin fix x y z :: 0a::linordered-idom { assume 0 < z =⇒ x < y have 0 < z =⇒ x∗z < y∗z by (tactic htest @{context} [@{simproc linordered-ring-less-cancel-factor}]i) fact next assume 0 < z =⇒ x < y have 0 < z =⇒ x∗z < z∗y by (tactic htest @{context} [@{simproc linordered-ring-less-cancel-factor}]i) fact next assume 0 < z =⇒ x < y have 0 < z =⇒ z∗x < y∗z 524 by (tactic htest @{context} [@{simproc linordered-ring-less-cancel-factor}]i) fact next assume 0 < z =⇒ x < y have 0 < z =⇒ z∗x < z∗y by (tactic htest @{context} [@{simproc linordered-ring-less-cancel-factor}]i) fact next This simproc now uses the simplifier to prove that terms to be canceled are posi- tive/negative. assume z-pos: 0 < z assume x < y have z∗x < z∗y by (tactic hCHANGED (asm-simp-tac (put-simpset HOL-basic-ss @{context} addsimprocs [@{simproc linordered-ring-less-cancel-factor}] addsimps [@{thm z-pos}]) 1 )i) fact } end 70.16 linordered-ring-le-cancel-factor notepad begin fix x y z :: 0a::linordered-idom { assume 0 < z =⇒ x ≤ y have 0 < z =⇒ x∗z ≤ y∗z by (tactic htest @{context} [@{simproc linordered-ring-le-cancel-factor}]i) fact next assume 0 < z =⇒ x ≤ y have 0 < z =⇒ z∗x ≤ z∗y by (tactic htest @{context} [@{simproc linordered-ring-le-cancel-factor}]i) fact } end 70.17 field-combine-numerals notepad begin fix x y z uu :: 0a::{field,ring-char-0 } { assume 5 / 6 ∗ x = uu have x / 2 + x / 3 = uu by (tactic htest @{context} [@{simproc field-combine-numerals}]i) fact next assume 6 / 9 ∗ x + y = uu have x / 3 + y + x / 3 = uu by (tactic htest @{context} [@{simproc field-combine-numerals}]i) fact next assume 9 / 9 ∗ x = uu have 2 ∗ x / 3 + x / 3 = uu by (tactic htest @{context} [@{simproc field-combine-numerals}]i) fact next assume y + z = uu have x / 2 + y − 3 ∗ x / 6 + z = uu by (tactic htest @{context} [@{simproc field-combine-numerals}]i) fact next assume 1 / 15 ∗ x + y = uu 525 have 7 ∗ x / 5 + y − 4 ∗ x / 3 = uu by (tactic htest @{context} [@{simproc field-combine-numerals}]i) fact } end lemma fixes x :: 0a::{linordered-field} shows 2 /3 ∗ x + x / 3 = uu apply (tactic htest @{context} [@{simproc field-combine-numerals}]i)? oops — FIXME: test fails 70.18 nat-combine-numerals notepad begin fix i j k m n u :: nat { assume 4 ∗k = u have k + 3 ∗k = u by (tactic htest @{context} [@{simproc nat-combine-numerals}]i) fact next assume 4 ∗ Suc 0 + i = u have Suc (i + 3 ) = u by (tactic htest @{context} [@{simproc nat-combine-numerals}]i) fact next assume 4 ∗ Suc 0 + (i + (j + k)) = u have Suc (i + j + 3 + k) = u by (tactic htest @{context} [@{simproc nat-combine-numerals}]i) fact next assume 2 ∗ j + 4 ∗ k = u have k + j + 3 ∗k + j = u by (tactic htest @{context} [@{simproc nat-combine-numerals}]i) fact next assume 6 ∗ Suc 0 + (5 ∗ (i ∗ j ) + (4 ∗ k + i)) = u have Suc (j ∗i + i + k + 5 + 3 ∗k + i∗j ∗4 ) = u by (tactic htest @{context} [@{simproc nat-combine-numerals}]i) fact next assume 5 ∗ (m ∗ n) = u have (2 ∗n∗m) + (3 ∗(m∗n)) = u by (tactic htest @{context} [@{simproc nat-combine-numerals}]i) fact } end 70.19 nateq-cancel-numerals notepad begin fix i j k l oo u uu vv w y z w 0 y 0 z 0 :: nat { assume Suc 0 ∗ u = 0 have 2 ∗u = (u::nat) by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next assume Suc 0 ∗ u = Suc 0 have 2 ∗u = Suc (u) by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next 526 assume i + (j + k) = 3 ∗ Suc 0 + (u + y) have (i + j + 12 + k) = u + 15 + y by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next assume 7 ∗ Suc 0 + (i + (j + k)) = u + y have (i + j + 12 + k) = u + 5 + y by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next assume 11 ∗ Suc 0 + (i + (j + k)) = u + y have (i + j + 12 + k) = Suc (u + y) by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next assume i + (j + k) = 2 ∗ Suc 0 + (u + y) have (i + j + 5 + k) = Suc (Suc (Suc (Suc (Suc (Suc (Suc (u + y))))))) by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next assume Suc 0 ∗ u + (2 ∗ y + 3 ∗ z) = Suc 0 have 2 ∗y + 3 ∗z + 2 ∗u = Suc (u) by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next assume Suc 0 ∗ u + (2 ∗ y + (3 ∗ z + (6 ∗ w + (2 ∗ y + 3 ∗ z)))) = Suc 0 have 2 ∗y + 3 ∗z + 6 ∗w + 2 ∗y + 3 ∗z + 2 ∗u = Suc (u) by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next assume Suc 0 ∗ u + (2 ∗ y + (3 ∗ z + (6 ∗ w + (2 ∗ y + 3 ∗ z)))) = 2 ∗ y 0 + (3 ∗ z 0 + (6 ∗ w 0 + (2 ∗ y 0 + (3 ∗ z 0 + vv)))) have 2 ∗y + 3 ∗z + 6 ∗w + 2 ∗y + 3 ∗z + 2 ∗u = 2 ∗y 0 + 3 ∗z 0 + 6 ∗w 0 + 2 ∗y 0 + 3 ∗z 0 + u + vv by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact next assume 2 ∗ u + (2 ∗ z + (5 ∗ Suc 0 + 2 ∗ y)) = vv have 6 + 2 ∗y + 3 ∗z + 4 ∗u = Suc (vv + 2 ∗u + z) by (tactic htest @{context} [@{simproc nateq-cancel-numerals}]i) fact } end 70.20 natless-cancel-numerals notepad begin fix length :: 0a ⇒ nat and l1 l2 xs :: 0a and f :: nat ⇒ 0a fix c i j k l m oo u uu vv w y z w 0 y 0 z 0 :: nat { assume 0 < j have (2 ∗length xs < 2 ∗length xs + j ) by (tactic htest @{context} [@{simproc natless-cancel-numerals}]i) fact next assume 0 < j have (2 ∗length xs < length xs ∗ 2 + j ) by (tactic htest @{context} [@{simproc natless-cancel-numerals}]i) fact next assume i + (j + k) < u + y 527 have (i + j + 5 + k) < Suc (Suc (Suc (Suc (Suc (u + y))))) by (tactic htest @{context} [@{simproc natless-cancel-numerals}]i) fact next assume 0 < Suc 0 ∗ (m ∗ n) + u have (2 ∗n∗m) < (3 ∗(m∗n)) + u by (tactic htest @{context} [@{simproc natless-cancel-numerals}]i) fact } end 70.21 natle-cancel-numerals notepad begin fix length :: 0a ⇒ nat and l2 l3 :: 0a and f :: nat ⇒ 0a fix c e i j k l oo u uu vv w y z w 0 y 0 z 0 :: nat { assume u + y ≤ 36 ∗ Suc 0 + (i + (j + k)) have Suc (Suc (Suc (Suc (Suc (u + y))))) ≤ ((i + j ) + 41 + k) by (tactic htest @{context} [@{simproc natle-cancel-numerals}]i) fact next assume 5 ∗ Suc 0 + (case length (f c) of 0 ⇒ 0 | Suc k ⇒ k) = 0 have (Suc (Suc (Suc (Suc (Suc (Suc (case length (f c) of 0 => 0 | Suc k => k)))))) ≤ Suc 0 ) by (tactic htest @{context} [@{simproc natle-cancel-numerals}]i) fact next assume 6 + length l2 = 0 have Suc (Suc (Suc (Suc (Suc (Suc (length l1 + length l2 )))))) ≤ length l1 by (tactic htest @{context} [@{simproc natle-cancel-numerals}]i) fact next assume 5 + length l3 = 0 have ((Suc (Suc (Suc (Suc (Suc (length (compT P E A ST mxr e) + length l3 )))))) ≤ length (compT P E A ST mxr e)) by (tactic htest @{context} [@{simproc natle-cancel-numerals}]i) fact next assume 5 + length (compT P E (A ∪ A 0 e) ST mxr c) = 0 have ((Suc (Suc (Suc (Suc (Suc (length (compT P E A ST mxr e) + length (compT P E (A Un A 0 e) ST mxr c))))))) ≤ length (compT P E A ST mxr e)) by (tactic htest @{context} [@{simproc natle-cancel-numerals}]i) fact } end 70.22 natdiff-cancel-numerals notepad begin fix length :: 0a ⇒ nat and l2 l3 :: 0a and f :: nat ⇒ 0a fix c e i j k l oo u uu vv v w x y z zz w 0 y 0 z 0 :: nat { assume i + (j + k) − 3 ∗ Suc 0 = y have (i + j + 12 + k) − 15 = y by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume 7 ∗ Suc 0 + (i + (j + k)) − 0 = y have (i + j + 12 + k) − 5 = y by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact 528 next assume u − Suc 0 ∗ Suc 0 = y have Suc u − 2 = y by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume Suc 0 ∗ Suc 0 + u − 0 = y have Suc (Suc (Suc u)) − 2 = y by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume Suc 0 ∗ Suc 0 + (i + (j + k)) − 0 = y have (i + j + 2 + k) − 1 = y by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume i + (j + k) − Suc 0 ∗ Suc 0 = y have (i + j + 1 + k) − 2 = y by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume 2 ∗ x + y − 2 ∗ (u ∗ v) = w have (2 ∗x + (u∗v) + y) − v∗3 ∗u = w by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume 2 ∗ x ∗ u ∗ v + (5 + y) − 0 = w have (2 ∗x∗u∗v + 5 + (u∗v)∗4 + y) − v∗u∗4 = w by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume 3 ∗ (u ∗ v) + (2 ∗ x ∗ u ∗ v + y) − 0 = w have (2 ∗x∗u∗v + (u∗v)∗4 + y) − v∗u = w by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume 3 ∗ u + (2 + (2 ∗ x ∗ u ∗ v + y)) − 0 = w have Suc (Suc (2 ∗x∗u∗v + u∗4 + y)) − u = w by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume Suc (Suc 0 ∗ (u ∗ v)) − 0 = w have Suc ((u∗v)∗4 ) − v∗3 ∗u = w by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume 2 − 0 = w have Suc (Suc ((u∗v)∗3 )) − v∗3 ∗u = w by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume 17 ∗ Suc 0 + (i + (j + k)) − (u + y) = zz have (i + j + 32 + k) − (u + 15 + y) = zz by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact next assume u + y − 0 = v have Suc (Suc (Suc (Suc (Suc (u + y))))) − 5 = v by (tactic htest @{context} [@{simproc natdiff-cancel-numerals}]i) fact } end 529 70.23 Factor-cancellation simprocs for type nat nat-eq-cancel-factor, nat-less-cancel-factor, nat-le-cancel-factor, nat-divide-cancel-factor, and nat-dvd-cancel-factor. notepad begin fix a b c d k x y uu :: nat { assume k = 0 ∨ x = y have x∗k = k∗y by (tactic htest @{context} [@{simproc nat-eq-cancel-factor}]i) fact next assume k = 0 ∨ Suc 0 = y have k = k∗y by (tactic htest @{context} [@{simproc nat-eq-cancel-factor}]i) fact next assume b = 0 ∨ a ∗ c = Suc 0 have a∗(b∗c) = b by (tactic htest @{context} [@{simproc nat-eq-cancel-factor}]i) fact next assume a = 0 ∨ b = 0 ∨ c = d ∗ x have a∗(b∗c) = d∗b∗(x∗a) by (tactic htest @{context} [@{simproc nat-eq-cancel-factor}]i) fact next assume 0 < k ∧ x < y have x∗k < k∗y by (tactic htest @{context} [@{simproc nat-less-cancel-factor}]i) fact next assume 0 < k ∧ Suc 0 < y have k < k∗y by (tactic htest @{context} [@{simproc nat-less-cancel-factor}]i) fact next assume 0 < b ∧ a ∗ c < Suc 0 have a∗(b∗c) < b by (tactic htest @{context} [@{simproc nat-less-cancel-factor}]i) fact next assume 0 < a ∧ 0 < b ∧ c < d ∗ x have a∗(b∗c) < d∗b∗(x∗a) by (tactic htest @{context} [@{simproc nat-less-cancel-factor}]i) fact next assume 0 < k −→ x ≤ y have x∗k ≤ k∗y by (tactic htest @{context} [@{simproc nat-le-cancel-factor}]i) fact next assume 0 < k −→ Suc 0 ≤ y have k ≤ k∗y by (tactic htest @{context} [@{simproc nat-le-cancel-factor}]i) fact next assume 0 < b −→ a ∗ c ≤ Suc 0 have a∗(b∗c) ≤ b by (tactic htest @{context} [@{simproc nat-le-cancel-factor}]i) fact next assume 0 < a −→ 0 < b −→ c ≤ d ∗ x have a∗(b∗c) ≤ d∗b∗(x∗a) by (tactic htest @{context} [@{simproc nat-le-cancel-factor}]i) fact next assume (if k = 0 then 0 else x div y) = uu have (x∗k) div (k∗y) = uu by (tactic htest @{context} [@{simproc nat-div-cancel-factor}]i) fact next assume (if k = 0 then 0 else Suc 0 div y) = uu have k div (k∗y) = uu by (tactic htest @{context} [@{simproc nat-div-cancel-factor}]i) fact next 530 assume (if b = 0 then 0 else a ∗ c) = uu have (a∗(b∗c)) div (b) = uu by (tactic htest @{context} [@{simproc nat-div-cancel-factor}]i) fact next assume (if a = 0 then 0 else if b = 0 then 0 else c div (d ∗ x)) = uu have (a∗(b∗c)) div (d∗b∗(x∗a)) = uu by (tactic htest @{context} [@{simproc nat-div-cancel-factor}]i) fact next assume k = 0 ∨ x dvd y have (x∗k) dvd (k∗y) by (tactic htest @{context} [@{simproc nat-dvd-cancel-factor}]i) fact next assume k = 0 ∨ Suc 0 dvd y have k dvd (k∗y) by (tactic htest @{context} [@{simproc nat-dvd-cancel-factor}]i) fact next assume b = 0 ∨ a ∗ c dvd Suc 0 have (a∗(b∗c)) dvd (b) by (tactic htest @{context} [@{simproc nat-dvd-cancel-factor}]i) fact next assume b = 0 ∨ Suc 0 dvd a ∗ c have b dvd (a∗(b∗c)) by (tactic htest @{context} [@{simproc nat-dvd-cancel-factor}]i) fact next assume a = 0 ∨ b = 0 ∨ c dvd d ∗ x have (a∗(b∗c)) dvd (d∗b∗(x∗a)) by (tactic htest @{context} [@{simproc nat-dvd-cancel-factor}]i) fact } end 70.24 Numeral-cancellation simprocs for type nat notepad begin fix x y z :: nat { assume 3 ∗ x = 4 ∗ y have 9 ∗x = 12 ∗ y by (tactic htest @{context} [@{simproc nat-eq-cancel-numeral-factor}]i) fact next assume 3 ∗ x < 4 ∗ y have 9 ∗x < 12 ∗ y by (tactic htest @{context} [@{simproc nat-less-cancel-numeral-factor}]i) fact next assume 3 ∗ x ≤ 4 ∗ y have 9 ∗x ≤ 12 ∗ y by (tactic htest @{context} [@{simproc nat-le-cancel-numeral-factor}]i) fact next assume (3 ∗ x) div (4 ∗ y) = z have (9 ∗x) div (12 ∗ y) = z by (tactic htest @{context} [@{simproc nat-div-cancel-numeral-factor}]i) fact next assume (3 ∗ x) dvd (4 ∗ y) have (9 ∗x) dvd (12 ∗ y) by (tactic htest @{context} [@{simproc nat-dvd-cancel-numeral-factor}]i) fact } end 70.25 Integer numeral div/mod simprocs notepad begin have (10 ::int) div 3 = 3 531 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (10 ::int) mod 3 = 1 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (10 ::int) div −3 = −4 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (10 ::int) mod −3 = −2 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (−10 ::int) div 3 = −4 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (−10 ::int) mod 3 = 2 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (−10 ::int) div −3 = 3 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (−10 ::int) mod −3 = −1 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (8452 ::int) mod 3 = 1 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (59485 ::int) div 434 = 137 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have (1000006 ::int) mod 10 = 6 by (tactic htest @{context} [@{simproc numeral-divmod}]i) have 10000000 div 2 = (5000000 ::int) by (tactic htest @{context} [@{simproc numeral-divmod}]i) have 10000001 mod 2 = (1 ::int) by (tactic htest @{context} [@{simproc numeral-divmod}]i) have 10000055 div 32 = (312501 ::int) by (tactic htest @{context} [@{simproc numeral-divmod}]i) have 10000055 mod 32 = (23 ::int) by (tactic htest @{context} [@{simproc numeral-divmod}]i) have 100094 div 144 = (695 ::int) by (tactic htest @{context} [@{simproc numeral-divmod}]i) have 100094 mod 144 = (14 ::int) by (tactic htest @{context} [@{simproc numeral-divmod}]i) end end theory Executable-Relation imports Main begin 70.26 A dedicated type for relations 70.26.1 Definition of the dedicated type for relations typedef 0a rel = UNIV :: (( 0a ∗ 0a) set) set morphisms set-of-rel rel-of-set by simp setup-lifting type-definition-rel lift-definition Rel :: 0a set => ( 0a ∗ 0a) set => 0a rel is λ XR. Id-on X Un R . 532 70.26.2 Constant definitions on relations hide-const (open) converse relcomp rtrancl Image lift-definition member :: 0a ∗ 0a => 0a rel => bool is Set.member . lift-definition converse :: 0a rel => 0a rel is Relation.converse . lift-definition union :: 0a rel => 0a rel => 0a rel is Set.union . lift-definition relcomp :: 0a rel => 0a rel => 0a rel is Relation.relcomp . lift-definition rtrancl :: 0a rel => 0a rel is Transitive-Closure.rtrancl . lift-definition Image :: 0a rel => 0a set => 0a set is Relation.Image . 70.26.3 Code generation code-datatype Rel lemma [code]: member (x, y)(Rel X R) = ((x = y ∧ x : X ) ∨ (x, y): R) by transfer auto lemma [code]: converse (Rel X R) = Rel X (Rˆ−1 ) by transfer auto lemma [code]: union (Rel X R)(Rel Y S) = Rel (X Un Y )(R Un S) by transfer auto lemma [code]: relcomp (Rel X R)(Rel Y S) = Rel (X Int Y )(Set.filter (%(x, y). y : Y ) R Un (Set.filter (%(x, y). x : X ) S Un R O S)) by transfer (auto simp add: Id-on-eqI relcomp.simps) lemma [code]: rtrancl (Rel X R) = Rel UNIV (Rˆ+) apply transfer apply auto apply (metis Id-on-iff Un-commute UNIV-I rtrancl-Un-separatorE rtrancl-eq-or-trancl) by (metis in-rtrancl-UnI trancl-into-rtrancl) lemma [code]: Image (Rel X R) S = (X Int S) Un (R ‘‘ S) by transfer auto quickcheck-generator rel constructors: Rel 533 lemma member (x, (y :: nat)) (rtrancl (union R S)) =⇒ member (x, y)(union (rtrancl R)(rtrancl S)) quickcheck[exhaustive, expect = counterexample] oops end 71 A generic phantom type theory Phantom-Type imports Main begin datatype ( 0a, 0b) phantom = phantom (of-phantom: 0b) lemma type-definition-phantom 0: type-definition of-phantom phantom UNIV by(unfold-locales) simp-all lemma phantom-comp-of-phantom [simp]: phantom ◦ of-phantom = id and of-phantom-comp-phantom [simp]: of-phantom ◦ phantom = id by(simp-all add: o-def id-def ) syntax -Phantom :: type ⇒ logic ((1Phantom/(1 0(- 0)))) translations Phantom( 0t) => CONST phantom :: - ⇒ ( 0t, -) phantom typed-print-translation h let fun phantom-tr 0 ctxt (Type (@{type-name fun}, [-, Type (@{type-name phan- tom}, [T , -])])) ts = list-comb (Syntax.const @{syntax-const -Phantom} $ Syntax-Phases.term-of-typ ctxt T , ts) | phantom-tr 0 --- = raise Match; in [(@{const-syntax phantom}, phantom-tr 0)] end i lemma of-phantom-inject [simp]: of-phantom x = of-phantom y ←→ x = y by(cases x y rule: phantom.exhaust[case-product phantom.exhaust]) simp end 72 Cardinality of types theory Cardinality imports Phantom-Type 534 begin 72.1 Preliminary lemmas lemma (in type-definition) univ: UNIV = Abs ‘ A proof show Abs ‘ A ⊆ UNIV by (rule subset-UNIV ) show UNIV ⊆ Abs ‘ A proof fix x :: 0b have x = Abs (Rep x) by (rule Rep-inverse [symmetric]) moreover have Rep x ∈ A by (rule Rep) ultimately show x ∈ Abs ‘ A by (rule image-eqI ) qed qed lemma (in type-definition) card: card (UNIV :: 0b set) = card A by (simp add: univ card-image inj-on-def Abs-inject) lemma finite-range-Some: finite (range (Some :: 0a ⇒ 0a option)) = finite (UNIV :: 0a set) by(auto dest: finite-imageD intro: inj-Some) lemma infinite-literal: ¬ finite (UNIV :: String.literal set) proof − have inj STR by(auto intro: injI ) thus ?thesis by(auto simp add: type-definition.univ[OF type-definition-literal] infinite-UNIV-listI dest: finite-imageD) qed 72.2 Cardinalities of types syntax -type-card :: type => nat ((1CARD/(1 0(- 0)))) translations CARD( 0t) => CONST card (CONST UNIV :: 0t set) print-translation h let fun card-univ-tr 0 ctxt [Const (@{const-syntax UNIV }, Type (-, [T ]))] = Syntax.const @{syntax-const -type-card} $ Syntax-Phases.term-of-typ ctxt T in [(@{const-syntax card}, card-univ-tr 0)] end i lemma card-prod [simp]: CARD( 0a × 0b) = CARD( 0a) ∗ CARD( 0b) unfolding UNIV-Times-UNIV [symmetric] by (simp only: card-cartesian-product) lemma card-UNIV-sum: CARD( 0a + 0b) = (if CARD( 0a) 6= 0 ∧ CARD( 0b) 6= 0 then CARD( 0a) + CARD( 0b) else 0 ) 535 unfolding UNIV-Plus-UNIV [symmetric] by(auto simp add: card-eq-0-iff card-Plus simp del: UNIV-Plus-UNIV ) lemma card-sum [simp]: CARD( 0a + 0b) = CARD( 0a::finite) + CARD( 0b::finite) by(simp add: card-UNIV-sum) lemma card-UNIV-option: CARD( 0a option) = (if CARD( 0a) = 0 then 0 else CARD( 0a) + 1 ) proof − have (None :: 0a option) ∈/ range Some by clarsimp thus ?thesis by (simp add: UNIV-option-conv card-eq-0-iff finite-range-Some card-image) qed lemma card-option [simp]: CARD( 0a option) = Suc CARD( 0a::finite) by(simp add: card-UNIV-option) lemma card-UNIV-set: CARD( 0a set) = (if CARD( 0a) = 0 then 0 else 2 ˆ CARD( 0a)) by(simp add: Pow-UNIV [symmetric] card-eq-0-iff card-Pow del: Pow-UNIV ) lemma card-set [simp]: CARD( 0a set) = 2 ˆ CARD( 0a::finite) by(simp add: card-UNIV-set) lemma card-nat [simp]: CARD(nat) = 0 by (simp add: card-eq-0-iff ) lemma card-fun: CARD( 0a ⇒ 0b) = (if CARD( 0a) 6= 0 ∧ CARD( 0b) 6= 0 ∨ CARD( 0b) = 1 then CARD( 0b) ˆ CARD( 0a) else 0 ) proof − { assume 0 < CARD( 0a) and 0 < CARD( 0b) hence fina: finite (UNIV :: 0a set) and finb: finite (UNIV :: 0b set) by(simp-all only: card-ge-0-finite) from finite-distinct-list[OF finb] obtain bs where bs: set bs = (UNIV :: 0b set) and distb: distinct bs by blast from finite-distinct-list[OF fina] obtain as where as: set as = (UNIV :: 0a set) and dista: distinct as by blast have cb: CARD( 0b) = length bs unfolding bs[symmetric] distinct-card[OF distb] .. have ca: CARD( 0a) = length as unfolding as[symmetric] distinct-card[OF dista] .. let ?xs = map (λys. the o map-of (zip as ys)) (List.n-lists (length as) bs) have UNIV = set ?xs proof(rule UNIV-eq-I ) fix f :: 0a ⇒ 0b from as have f = the ◦ map-of (zip as (map f as)) by(auto simp add: map-of-zip-map) thus f ∈ set ?xs using bs by(auto simp add: set-n-lists) qed moreover have distinct ?xs unfolding distinct-map 536 proof(intro conjI distinct-n-lists distb inj-onI ) fix xs ys :: 0b list assume xs: xs ∈ set (List.n-lists (length as) bs) and ys: ys ∈ set (List.n-lists (length as) bs) and eq: the ◦ map-of (zip as xs) = the ◦ map-of (zip as ys) from xs ys have [simp]: length xs = length as length ys = length as by(simp-all add: length-n-lists-elem) have map-of (zip as xs) = map-of (zip as ys) proof fix x from as bs have ∃ y. map-of (zip as xs) x = Some y ∃ y. map-of (zip as ys) x = Some y by(simp-all add: map-of-zip-is-Some[symmetric]) with eq show map-of (zip as xs) x = map-of (zip as ys) x by(auto dest: fun-cong[where x=x]) qed with dista show xs = ys by(simp add: map-of-zip-inject) qed hence card (set ?xs) = length ?xs by(simp only: distinct-card) moreover have length ?xs = length bs ˆ length as by(simp add: length-n-lists) ultimately have CARD( 0a ⇒ 0b) = CARD( 0b) ˆ CARD( 0a) using cb ca by simp } moreover { assume cb: CARD( 0b) = 1 then obtain b where b: UNIV = {b :: 0b} by(auto simp add: card-Suc-eq) have eq: UNIV = {λx :: 0a. b :: 0b} proof(rule UNIV-eq-I ) fix x :: 0a ⇒ 0b { fix y have x y ∈ UNIV .. hence x y = b unfolding b by simp } thus x ∈ {λx. b} by(auto) qed have CARD( 0a ⇒ 0b) = 1 unfolding eq by simp } ultimately show ?thesis by(auto simp del: One-nat-def )(auto simp add: card-eq-0-iff dest: finite-fun-UNIVD2 finite-fun-UNIVD1 ) qed corollary finite-UNIV-fun: finite (UNIV :: ( 0a ⇒ 0b) set) ←→ finite (UNIV :: 0a set) ∧ finite (UNIV :: 0b set) ∨ CARD( 0b) = 1 (is ?lhs ←→ ?rhs) proof − have ?lhs ←→ CARD( 0a ⇒ 0b) > 0 by(simp add: card-gt-0-iff ) also have ... ←→ CARD( 0a) > 0 ∧ CARD( 0b) > 0 ∨ CARD( 0b) = 1 by(simp add: card-fun) also have ... = ?rhs by(simp add: card-gt-0-iff ) finally show ?thesis . 537 qed lemma card-literal: CARD(String.literal) = 0 by(simp add: card-eq-0-iff infinite-literal) 72.3 Classes with at least 1 and 2 Class finite already captures ”at least 1” lemma zero-less-card-finite [simp]: 0 < CARD( 0a::finite) unfolding neq0-conv [symmetric] by simp lemma one-le-card-finite [simp]: Suc 0 ≤ CARD( 0a::finite) by (simp add: less-Suc-eq-le [symmetric]) Class for cardinality ”at least 2” class card2 = finite + assumes two-le-card: 2 ≤ CARD( 0a) lemma one-less-card: Suc 0 < CARD( 0a::card2 ) using two-le-card [where 0a= 0a] by simp lemma one-less-int-card: 1 < int CARD( 0a::card2 ) using one-less-card [where 0a= 0a] by simp 72.4 A type class for deciding finiteness of types type-synonym 0a finite-UNIV = ( 0a, bool) phantom class finite-UNIV = fixes finite-UNIV :: ( 0a, bool) phantom assumes finite-UNIV : finite-UNIV = Phantom( 0a)(finite (UNIV :: 0a set)) lemma finite-UNIV-code [code-unfold]: finite (UNIV :: 0a :: finite-UNIV set) ←→ of-phantom (finite-UNIV :: 0a finite-UNIV ) by(simp add: finite-UNIV ) 72.5 A type class for computing the cardinality of types definition is-list-UNIV :: 0a list ⇒ bool where is-list-UNIV xs = (let c = CARD( 0a) in if c = 0 then False else size (remdups xs) = c) lemma is-list-UNIV-iff : is-list-UNIV xs ←→ set xs = UNIV by(auto simp add: is-list-UNIV-def Let-def card-eq-0-iff List.card-set[symmetric] dest: subst[where P=finite, OF - finite-set] card-eq-UNIV-imp-eq-UNIV ) type-synonym 0a card-UNIV = ( 0a, nat) phantom 538 class card-UNIV = finite-UNIV + fixes card-UNIV :: 0a card-UNIV assumes card-UNIV : card-UNIV = Phantom( 0a) CARD( 0a) 72.6 Instantiations for card-UNIV instantiation nat :: card-UNIV begin definition finite-UNIV = Phantom(nat) False definition card-UNIV = Phantom(nat) 0 instance by intro-classes (simp-all add: finite-UNIV-nat-def card-UNIV-nat-def ) end instantiation int :: card-UNIV begin definition finite-UNIV = Phantom(int) False definition card-UNIV = Phantom(int) 0 instance by intro-classes (simp-all add: card-UNIV-int-def finite-UNIV-int-def infinite-UNIV-int) end instantiation natural :: card-UNIV begin definition finite-UNIV = Phantom(natural) False definition card-UNIV = Phantom(natural) 0 instance by standard (auto simp add: finite-UNIV-natural-def card-UNIV-natural-def card-eq-0-iff type-definition.univ [OF type-definition-natural] natural-eq-iff dest!: finite-imageD intro: inj-onI ) end instantiation integer :: card-UNIV begin definition finite-UNIV = Phantom(integer) False definition card-UNIV = Phantom(integer) 0 instance by standard (auto simp add: finite-UNIV-integer-def card-UNIV-integer-def card-eq-0-iff type-definition.univ [OF type-definition-integer] infinite-UNIV-int dest!: finite-imageD intro: inj-onI ) end instantiation list :: (type) card-UNIV begin definition finite-UNIV = Phantom( 0a list) False definition card-UNIV = Phantom( 0a list) 0 instance by intro-classes (simp-all add: card-UNIV-list-def finite-UNIV-list-def infinite-UNIV-listI ) end instantiation unit :: card-UNIV begin definition finite-UNIV = Phantom(unit) True definition card-UNIV = Phantom(unit) 1 539 instance by intro-classes (simp-all add: card-UNIV-unit-def finite-UNIV-unit-def ) end instantiation bool :: card-UNIV begin definition finite-UNIV = Phantom(bool) True definition card-UNIV = Phantom(bool) 2 instance by(intro-classes)(simp-all add: card-UNIV-bool-def finite-UNIV-bool-def ) end instantiation char :: card-UNIV begin definition finite-UNIV = Phantom(char) True definition card-UNIV = Phantom(char) 256 instance by intro-classes (simp-all add: card-UNIV-char-def card-UNIV-char finite-UNIV-char-def ) end instantiation prod :: (finite-UNIV , finite-UNIV ) finite-UNIV begin definition finite-UNIV = Phantom( 0a × 0b) (of-phantom (finite-UNIV :: 0a finite-UNIV ) ∧ of-phantom (finite-UNIV :: 0b finite-UNIV )) instance by intro-classes (simp add: finite-UNIV-prod-def finite-UNIV finite-prod) end instantiation prod :: (card-UNIV , card-UNIV ) card-UNIV begin definition card-UNIV = Phantom( 0a × 0b) (of-phantom (card-UNIV :: 0a card-UNIV ) ∗ of-phantom (card-UNIV :: 0b card-UNIV )) instance by intro-classes (simp add: card-UNIV-prod-def card-UNIV ) end instantiation sum :: (finite-UNIV , finite-UNIV ) finite-UNIV begin definition finite-UNIV = Phantom( 0a + 0b) (of-phantom (finite-UNIV :: 0a finite-UNIV ) ∧ of-phantom (finite-UNIV :: 0b finite-UNIV )) instance by intro-classes (simp add: UNIV-Plus-UNIV [symmetric] finite-UNIV-sum-def finite-UNIV del: UNIV-Plus-UNIV ) end instantiation sum :: (card-UNIV , card-UNIV ) card-UNIV begin definition card-UNIV = Phantom( 0a + 0b) (let ca = of-phantom (card-UNIV :: 0a card-UNIV ); cb = of-phantom (card-UNIV :: 0b card-UNIV ) in if ca 6= 0 ∧ cb 6= 0 then ca + cb else 0 ) instance by intro-classes (auto simp add: card-UNIV-sum-def card-UNIV card-UNIV-sum) end instantiation fun :: (finite-UNIV , card-UNIV ) finite-UNIV begin definition finite-UNIV = Phantom( 0a ⇒ 0b) (let cb = of-phantom (card-UNIV :: 0b card-UNIV ) in cb = 1 ∨ of-phantom (finite-UNIV :: 0a finite-UNIV ) ∧ cb 6= 0 ) 540 instance by intro-classes (auto simp add: finite-UNIV-fun-def Let-def card-UNIV finite-UNIV finite-UNIV-fun card-gt-0-iff ) end instantiation fun :: (card-UNIV , card-UNIV ) card-UNIV begin definition card-UNIV = Phantom( 0a ⇒ 0b) (let ca = of-phantom (card-UNIV :: 0a card-UNIV ); cb = of-phantom (card-UNIV :: 0b card-UNIV ) in if ca 6= 0 ∧ cb 6= 0 ∨ cb = 1 then cb ˆ ca else 0 ) instance by intro-classes (simp add: card-UNIV-fun-def card-UNIV Let-def card-fun) end instantiation option :: (finite-UNIV ) finite-UNIV begin definition finite-UNIV = Phantom( 0a option)(of-phantom (finite-UNIV :: 0a finite-UNIV )) instance by intro-classes (simp add: finite-UNIV-option-def finite-UNIV ) end instantiation option :: (card-UNIV ) card-UNIV begin definition card-UNIV = Phantom( 0a option) (let c = of-phantom (card-UNIV :: 0a card-UNIV ) in if c 6= 0 then Suc c else 0 ) instance by intro-classes (simp add: card-UNIV-option-def card-UNIV card-UNIV-option) end instantiation String.literal :: card-UNIV begin definition finite-UNIV = Phantom(String.literal) False definition card-UNIV = Phantom(String.literal) 0 instance by intro-classes (simp-all add: card-UNIV-literal-def finite-UNIV-literal-def infinite-literal card-literal) end instantiation set :: (finite-UNIV ) finite-UNIV begin definition finite-UNIV = Phantom( 0a set)(of-phantom (finite-UNIV :: 0a finite-UNIV )) instance by intro-classes (simp add: finite-UNIV-set-def finite-UNIV Finite-Set.finite-set) end instantiation set :: (card-UNIV ) card-UNIV begin definition card-UNIV = Phantom( 0a set) (let c = of-phantom (card-UNIV :: 0a card-UNIV ) in if c = 0 then 0 else 2 ˆ c) instance by intro-classes (simp add: card-UNIV-set-def card-UNIV-set card-UNIV ) end lemma UNIV-finite-1 : UNIV = set [finite-1 .a1] by(auto intro: finite-1 .exhaust) lemma UNIV-finite-2 : UNIV = set [finite-2 .a1, finite-2 .a2] by(auto intro: finite-2 .exhaust) 541 lemma UNIV-finite-3 : UNIV = set [finite-3 .a1, finite-3 .a2, finite-3 .a3] by(auto intro: finite-3 .exhaust) lemma UNIV-finite-4 : UNIV = set [finite-4 .a1, finite-4 .a2, finite-4 .a3, finite-4 .a4] by(auto intro: finite-4 .exhaust) lemma UNIV-finite-5 : UNIV = set [finite-5 .a1, finite-5 .a2, finite-5 .a3, finite-5 .a4, finite-5 .a5] by(auto intro: finite-5 .exhaust) instantiation Enum.finite-1 :: card-UNIV begin definition finite-UNIV = Phantom(Enum.finite-1 ) True definition card-UNIV = Phantom(Enum.finite-1 ) 1 instance by intro-classes (simp-all add: UNIV-finite-1 card-UNIV-finite-1-def finite-UNIV-finite-1-def ) end instantiation Enum.finite-2 :: card-UNIV begin definition finite-UNIV = Phantom(Enum.finite-2 ) True definition card-UNIV = Phantom(Enum.finite-2 ) 2 instance by intro-classes (simp-all add: UNIV-finite-2 card-UNIV-finite-2-def finite-UNIV-finite-2-def ) end instantiation Enum.finite-3 :: card-UNIV begin definition finite-UNIV = Phantom(Enum.finite-3 ) True definition card-UNIV = Phantom(Enum.finite-3 ) 3 instance by intro-classes (simp-all add: UNIV-finite-3 card-UNIV-finite-3-def finite-UNIV-finite-3-def ) end instantiation Enum.finite-4 :: card-UNIV begin definition finite-UNIV = Phantom(Enum.finite-4 ) True definition card-UNIV = Phantom(Enum.finite-4 ) 4 instance by intro-classes (simp-all add: UNIV-finite-4 card-UNIV-finite-4-def finite-UNIV-finite-4-def ) end instantiation Enum.finite-5 :: card-UNIV begin definition finite-UNIV = Phantom(Enum.finite-5 ) True definition card-UNIV = Phantom(Enum.finite-5 ) 5 instance by intro-classes (simp-all add: UNIV-finite-5 card-UNIV-finite-5-def finite-UNIV-finite-5-def ) end 542 72.7 Code setup for sets Implement CARD( 0a) via card-UNIV-class.card-UNIV and provide imple- mentations for finite, card, op ⊆, and op =if the calling context already provides finite-UNIV and card-UNIV instances. If we implemented the lat- ter always via card-UNIV-class.card-UNIV, we would require instances of essentially all element types, i.e., a lot of instantiation proofs and – at run time – possibly slow dictionary constructions. context begin qualified definition card-UNIV 0 :: 0a card-UNIV where [code del]: card-UNIV 0 = Phantom( 0a) CARD( 0a) lemma CARD-code [code-unfold]: CARD( 0a) = of-phantom (card-UNIV 0 :: 0a card-UNIV ) by(simp add: card-UNIV 0-def ) lemma card-UNIV 0-code [code]: card-UNIV 0 = card-UNIV by(simp add: card-UNIV card-UNIV 0-def ) end lemma card-Compl: finite A =⇒ card (− A) = card (UNIV :: 0a set) − card (A :: 0a set) by (metis Compl-eq-Diff-UNIV card-Diff-subset top-greatest) context fixes xs :: 0a :: finite-UNIV list begin qualified definition finite 0 :: 0a set ⇒ bool where [simp, code del, code-abbrev]: finite 0 = finite lemma finite 0-code [code]: finite 0 (set xs) ←→ True finite 0 (List.coset xs) ←→ of-phantom (finite-UNIV :: 0a finite-UNIV ) by(simp-all add: card-gt-0-iff finite-UNIV ) end context fixes xs :: 0a :: card-UNIV list begin qualified definition card 0 :: 0a set ⇒ nat where [simp, code del, code-abbrev]: card 0 = card lemma card 0-code [code]: 543 card 0 (set xs) = length (remdups xs) card 0 (List.coset xs) = of-phantom (card-UNIV :: 0a card-UNIV ) − length (remdups xs) by(simp-all add: List.card-set card-Compl card-UNIV ) qualified definition subset 0 :: 0a set ⇒ 0a set ⇒ bool where [simp, code del, code-abbrev]: subset 0 = op ⊆ lemma subset 0-code [code]: subset 0 A (List.coset ys) ←→ (∀ y ∈ set ys. y ∈/ A) subset 0 (set ys) B ←→ (∀ y ∈ set ys. y ∈ B) subset 0 (List.coset xs)(set ys) ←→ (let n = CARD( 0a) in n > 0 ∧ card(set (xs @ ys)) = n) by(auto simp add: Let-def card-gt-0-iff dest: card-eq-UNIV-imp-eq-UNIV intro: arg-cong[where f =card]) (metis finite-compl finite-set rev-finite-subset) qualified definition eq-set :: 0a set ⇒ 0a set ⇒ bool where [simp, code del, code-abbrev]: eq-set = op = lemma eq-set-code [code]: fixes ys defines rhs ≡ let n = CARD( 0a) in if n = 0 then False else let xs 0 = remdups xs; ys 0 = remdups ys in length xs 0 + length ys 0 = n ∧ (∀ x ∈ set xs 0. x ∈/ set ys 0) ∧ (∀ y ∈ set ys 0. y ∈/ set xs 0) shows eq-set (List.coset xs)(set ys) ←→ rhs and eq-set (set ys)(List.coset xs) ←→ rhs and eq-set (set xs)(set ys) ←→ (∀ x ∈ set xs. x ∈ set ys) ∧ (∀ y ∈ set ys. y ∈ set xs) and eq-set (List.coset xs)(List.coset ys) ←→ (∀ x ∈ set xs. x ∈ set ys) ∧ (∀ y ∈ set ys. y ∈ set xs) proof goal-cases { case 1 show ?case (is ?lhs ←→ ?rhs) proof show ?rhs if ?lhs using that by (auto simp add: rhs-def Let-def List.card-set[symmetric] card-Un-Int[where A=set xs and B=− set xs] card-UNIV Compl-partition card-gt-0-iff dest: sym)(metis finite-compl finite-set) show ?lhs if ?rhs proof − have [[ ∀ y∈set xs. y ∈/ set ys; ∀ x∈set ys. x ∈/ set xs ]] =⇒ set xs ∩ set ys = {} by blast 544 with that show ?thesis by (auto simp add: rhs-def Let-def List.card-set[symmetric] card-UNIV card-gt-0-iff card-Un-Int[where A=set xs and B=set ys] dest: card-eq-UNIV-imp-eq-UNIV split: if-split-asm) qed qed } moreover case 2 ultimately show ?case unfolding eq-set-def by blast next case 3 show ?case unfolding eq-set-def List.coset-def by blast next case 4 show ?case unfolding eq-set-def List.coset-def by blast qed end Provide more informative exceptions than Match for non-rewritten cases. If generated code raises one these exceptions, then a code equation calls the mentioned operator for an element type that is not an instance of card-UNIV and is therefore not implemented via card-UNIV-class.card-UNIV. Con- strain the element type with sort card-UNIV to change this. lemma card-coset-error [code]: card (List.coset xs) = Code.abort (STR 00card (List.coset -) requires type class instance card-UNIV 00) (λ-. card (List.coset xs)) by(simp) lemma coset-subseteq-set-code [code]: List.coset xs ⊆ set ys ←→ (if xs = [] ∧ ys = [] then False else Code.abort (STR 00subset-eq (List.coset -)(List.set -) requires type class instance card-UNIV 00) (λ-. List.coset xs ⊆ set ys)) by simp notepad begin — test code setup have List.coset [True] = set [False] ∧ List.coset [] ⊆ List.set [True, False] ∧ finite (List.coset [True]) by eval end end 545 73 Almost everywhere constant functions theory FinFun imports Cardinality begin This theory defines functions which are constant except for finitely many points (FinFun) and introduces a type finfin along with a number of opera- tors for them. The code generator is set up such that such functions can be represented as data in the generated code and all operators are executable. For details, see Formalising FinFuns - Generating Code for Functions as Data by A. Lochbihler in TPHOLs 2009. 73.1 The map-default operation definition map-default :: 0b ⇒ ( 0a * 0b) ⇒ 0a ⇒ 0b where map-default b f a ≡ case f a of None ⇒ b | Some b 0 ⇒ b 0 lemma map-default-delete [simp]: map-default b (f (a := None)) = (map-default b f )(a := b) by(simp add: map-default-def fun-eq-iff ) lemma map-default-insert: map-default b (f (a 7→ b 0)) = (map-default b f )(a := b 0) by(simp add: map-default-def fun-eq-iff ) lemma map-default-empty [simp]: map-default b empty = (λa. b) by(simp add: fun-eq-iff map-default-def ) lemma map-default-inject: fixes g g 0 :: 0a * 0b assumes infin-eq: ¬ finite (UNIV :: 0a set) ∨ b = b 0 and fin: finite (dom g) and b: b ∈/ ran g and fin 0: finite (dom g 0) and b 0: b 0 ∈/ ran g 0 and eq 0: map-default b g = map-default b 0 g 0 shows b = b 0 g = g 0 proof − from infin-eq show bb 0: b = b 0 proof assume infin: ¬ finite (UNIV :: 0a set) from fin fin 0 have finite (dom g ∪ dom g 0) by auto with infin have UNIV − (dom g ∪ dom g 0) 6= {} by(auto dest: finite-subset) then obtain a where a: a ∈/ dom g ∪ dom g 0 by auto hence map-default b g a = b map-default b 0 g 0 a = b 0 by(auto simp add: map-default-def ) with eq 0 show b = b 0 by simp qed show g = g 0 546 proof fix x show g x = g 0 x proof(cases g x) case None hence map-default b g x = b by(simp add: map-default-def ) with bb 0 eq 0 have map-default b 0 g 0 x = b 0 by simp with b 0 have g 0 x = None by(simp add: map-default-def ran-def split: option.split-asm) with None show ?thesis by simp next case (Some c) with b have cb: c 6= b by(auto simp add: ran-def ) moreover from Some have map-default b g x = c by(simp add: map-default-def ) with eq 0 have map-default b 0 g 0 x = c by simp ultimately have g 0 x = Some c using b 0 bb 0 by(auto simp add: map-default-def split: option.splits) with Some show ?thesis by simp qed qed qed 73.2 The finfun type definition finfun = {f :: 0a⇒ 0b. ∃ b. finite {a. f a 6= b}} typedef ( 0a, 0b) finfun ((- ⇒f /-)[22 , 21 ] 21 ) = finfun :: ( 0a => 0b) set morphisms finfun-apply Abs-finfun proof − have ∃ f . finite {x. f x 6= undefined} proof show finite {x. (λy. undefined) x 6= undefined} by auto qed then show ?thesis unfolding finfun-def by auto qed type-notation finfun ((- ⇒f /-)[22 , 21 ] 21 ) setup-lifting type-definition-finfun lemma fun-upd-finfun: y(a := b) ∈ finfun ←→ y ∈ finfun proof − { fix b 0 have finite {a 0. (y(a := b)) a 0 6= b 0} = finite {a 0. y a 0 6= b 0} proof(cases b = b 0) case True hence {a 0. (y(a := b)) a 0 6= b 0} = {a 0. y a 0 6= b 0} − {a} by auto thus ?thesis by simp next 547 case False hence {a 0. (y(a := b)) a 0 6= b 0} = insert a {a 0. y a 0 6= b 0} by auto thus ?thesis by simp qed } thus ?thesis unfolding finfun-def by blast qed lemma const-finfun:(λx. a) ∈ finfun by(auto simp add: finfun-def ) lemma finfun-left-compose: assumes y ∈ finfun shows g ◦ y ∈ finfun proof − from assms obtain b where finite {a. y a 6= b} unfolding finfun-def by blast hence finite {c. g (y c) 6= g b} proof(induct {a. y a 6= b} arbitrary: y) case empty hence y = (λa. b) by(auto) thus ?case by(simp) next case (insert x F ) note IH = hVy. F = {a. y a 6= b} =⇒ finite {c. g (y c) 6= g b}i from hinsert x F = {a. y a 6= b}i hx ∈/ F i have F : F = {a. (y(x := b)) a 6= b} by(auto) show ?case proof(cases g (y x) = g b) case True hence {c. g ((y(x := b)) c) 6= g b} = {c. g (y c) 6= g b} by auto with IH [OF F ] show ?thesis by simp next case False hence {c. g (y c) 6= g b} = insert x {c. g ((y(x := b)) c) 6= g b} by auto with IH [OF F ] show ?thesis by(simp) qed qed thus ?thesis unfolding finfun-def by auto qed lemma assumes y ∈ finfun shows fst-finfun: fst ◦ y ∈ finfun and snd-finfun: snd ◦ y ∈ finfun proof − from assms obtain b c where bc: finite {a. y a 6= (b, c)} unfolding finfun-def by auto have {a. fst (y a) 6= b} ⊆ {a. y a 6= (b, c)} and {a. snd (y a) 6= c} ⊆ {a. y a 6= (b, c)} by auto hence finite {a. fst (y a) 6= b} 548 and finite {a. snd (y a) 6= c} using bc by(auto intro: finite-subset) thus fst ◦ y ∈ finfun snd ◦ y ∈ finfun unfolding finfun-def by auto qed lemma map-of-finfun: map-of xs ∈ finfun unfolding finfun-def by(induct xs)(auto simp add: Collect-neg-eq Collect-conj-eq Collect-imp-eq intro: finite-subset) lemma Diag-finfun:(λx. (f x, g x)) ∈ finfun ←→ f ∈ finfun ∧ g ∈ finfun by(auto intro: finite-subset simp add: Collect-neg-eq Collect-imp-eq Collect-conj-eq finfun-def ) lemma finfun-right-compose: assumes g: g ∈ finfun and inj : inj f shows g o f ∈ finfun proof − from g obtain b where b: finite {a. g a 6= b} unfolding finfun-def by blast moreover have f ‘ {a. g (f a) 6= b} ⊆ {a. g a 6= b} by auto moreover from inj have inj-on f {a. g (f a) 6= b} by(rule subset-inj-on) blast ultimately have finite {a. g (f a) 6= b} by(blast intro: finite-imageD[where f =f ] finite-subset) thus ?thesis unfolding finfun-def by auto qed lemma finfun-curry: assumes fin: f ∈ finfun shows curry f ∈ finfun curry f a ∈ finfun proof − from fin obtain c where c: finite {ab. f ab 6= c} unfolding finfun-def by blast moreover have {a. ∃ b. f (a, b) 6= c} = fst ‘ {ab. f ab 6= c} by(force) hence {a. curry f a 6= (λb. c)} = fst ‘ {ab. f ab 6= c} by(auto simp add: curry-def fun-eq-iff ) ultimately have finite {a. curry f a 6= (λb. c)} by simp thus curry f ∈ finfun unfolding finfun-def by blast have snd ‘ {ab. f ab 6= c} = {b. ∃ a. f (a, b) 6= c} by(force) hence {b. f (a, b) 6= c} ⊆ snd ‘ {ab. f ab 6= c} by auto hence finite {b. f (a, b) 6= c} by(rule finite-subset)(rule finite-imageI [OF c]) thus curry f a ∈ finfun unfolding finfun-def by auto qed bundle finfun begin lemmas [simp] = fst-finfun snd-finfun Abs-finfun-inverse finfun-apply-inverse Abs-finfun-inject finfun-apply-inject 549 Diag-finfun finfun-curry lemmas [iff ] = const-finfun fun-upd-finfun finfun-apply map-of-finfun lemmas [intro] = finfun-left-compose fst-finfun snd-finfun end lemma Abs-finfun-inject-finite: fixes x y :: 0a ⇒ 0b assumes fin: finite (UNIV :: 0a set) shows Abs-finfun x = Abs-finfun y ←→ x = y proof assume Abs-finfun x = Abs-finfun y moreover have x ∈ finfun y ∈ finfun unfolding finfun-def by(auto intro: finite-subset[OF - fin]) ultimately show x = y by(simp add: Abs-finfun-inject) qed simp lemma Abs-finfun-inject-finite-class: fixes x y :: ( 0a :: finite) ⇒ 0b shows Abs-finfun x = Abs-finfun y ←→ x = y using finite-UNIV by(simp add: Abs-finfun-inject-finite) lemma Abs-finfun-inj-finite: assumes fin: finite (UNIV :: 0a set) shows inj (Abs-finfun :: ( 0a ⇒ 0b) ⇒ 0a ⇒f 0b) proof(rule inj-onI ) fix x y :: 0a ⇒ 0b assume Abs-finfun x = Abs-finfun y moreover have x ∈ finfun y ∈ finfun unfolding finfun-def by(auto intro: finite-subset[OF - fin]) ultimately show x = y by(simp add: Abs-finfun-inject) qed lemma Abs-finfun-inverse-finite: fixes x :: 0a ⇒ 0b assumes fin: finite (UNIV :: 0a set) shows finfun-apply (Abs-finfun x) = x including finfun proof − from fin have x ∈ finfun by(auto simp add: finfun-def intro: finite-subset) thus ?thesis by simp qed lemma Abs-finfun-inverse-finite-class: fixes x :: ( 0a :: finite) ⇒ 0b 550 shows finfun-apply (Abs-finfun x) = x using finite-UNIV by(simp add: Abs-finfun-inverse-finite) lemma finfun-eq-finite-UNIV : finite (UNIV :: 0a set) =⇒ (finfun :: ( 0a ⇒ 0b) set) = UNIV unfolding finfun-def by(auto intro: finite-subset) lemma finfun-finite-UNIV-class: finfun = (UNIV :: ( 0a :: finite ⇒ 0b) set) by(simp add: finfun-eq-finite-UNIV ) lemma map-default-in-finfun: assumes fin: finite (dom f ) shows map-default b f ∈ finfun unfolding finfun-def proof(intro CollectI exI ) from fin show finite {a. map-default b f a 6= b} by(auto simp add: map-default-def dom-def Collect-conj-eq split: option.splits) qed lemma finfun-cases-map-default: obtains b g where f = Abs-finfun (map-default b g) finite (dom g) b ∈/ ran g proof − obtain y where f : f = Abs-finfun y and y: y ∈ finfun by(cases f ) from y obtain b where b: finite {a. y a 6= b} unfolding finfun-def by auto let ?g = (λa. if y a = b then None else Some (y a)) have map-default b ?g = y by(simp add: fun-eq-iff map-default-def ) with f have f = Abs-finfun (map-default b ?g) by simp moreover from b have finite (dom ?g) by(auto simp add: dom-def ) moreover have b ∈/ ran ?g by(auto simp add: ran-def ) ultimately show ?thesis by(rule that) qed 73.3 Kernel functions for type 0a ⇒f 0b lift-definition finfun-const :: 0b ⇒ 0a ⇒f 0b (K $/ - [0 ] 1 ) is λ b x. b by (rule const-finfun) lift-definition finfun-update :: 0a ⇒f 0b ⇒ 0a ⇒ 0b ⇒ 0a ⇒f 0b (- 0(- $:= - 0) [1000 ,0 ,0 ] 1000 ) is fun-upd by (simp add: fun-upd-finfun) lemma finfun-update-twist: a 6= a 0 =⇒ f (a $:= b)(a 0 $:= b 0) = f (a 0 $:= b 0)(a $:= b) by transfer (simp add: fun-upd-twist) lemma finfun-update-twice [simp]: f (a $:= b)(a $:= b 0) = f (a $:= b 0) by transfer simp 551 lemma finfun-update-const-same:(K $ b)(a $:= b) = (K $ b) by transfer (simp add: fun-eq-iff ) 73.4 Code generator setup definition finfun-update-code :: 0a ⇒f 0b ⇒ 0a ⇒ 0b ⇒ 0a ⇒f 0b where [simp, code del]: finfun-update-code = finfun-update code-datatype finfun-const finfun-update-code lemma finfun-update-const-code [code]: (K $ b)(a $:= b 0) = (if b = b 0 then (K $ b) else finfun-update-code (K $ b) a b 0) by(simp add: finfun-update-const-same) lemma finfun-update-update-code [code]: (finfun-update-code f a b)(a 0 $:= b 0) = (if a = a 0 then f (a $:= b 0) else finfun-update-code (f (a 0 $:= b 0)) a b) by(simp add: finfun-update-twist) 73.5 Setup for quickcheck quickcheck-generator finfun constructors: finfun-update-code, finfun-const :: 0b ⇒ 0a ⇒f 0b 73.6 finfun-update as instance of comp-fun-commute interpretation finfun-update: comp-fun-commute λa f . f (a :: 0a $:= b 0) including finfun proof fix a a 0 :: 0a show (λf . f (a $:= b 0)) ◦ (λf . f (a 0 $:= b 0)) = (λf . f (a 0 $:= b 0)) ◦ (λf . f (a $:= b 0)) proof fix b have (finfun-apply b)(a := b 0, a 0 := b 0) = (finfun-apply b)(a 0 := b 0, a := b 0) by(cases a = a 0)(auto simp add: fun-upd-twist) then have b(a $:= b 0)(a 0 $:= b 0) = b(a 0 $:= b 0)(a $:= b 0) by(auto simp add: finfun-update-def fun-upd-twist) then show ((λf . f (a $:= b 0)) ◦ (λf . f (a 0 $:= b 0))) b = ((λf . f (a 0 $:= b 0)) ◦ (λf . f (a $:= b 0))) b by (simp add: fun-eq-iff ) qed qed lemma fold-finfun-update-finite-univ: assumes fin: finite (UNIV :: 0a set) shows Finite-Set.fold (λa f . f (a $:= b 0)) (K $ b)(UNIV :: 0a set) = (K $ b 0) proof − { fix A :: 0a set from fin have finite A by(auto intro: finite-subset) 552 hence Finite-Set.fold (λa f . f (a $:= b 0)) (K $ b) A = Abs-finfun (λa. if a ∈ A then b 0 else b) proof(induct) case (insert x F ) have (λa. if a = x then b 0 else (if a ∈ F then b 0 else b)) = (λa. if a = x ∨ a ∈ F then b 0 else b) by(auto) with insert show ?case by(simp add: finfun-const-def fun-upd-def )(simp add: finfun-update-def Abs-finfun-inverse-finite[OF fin] fun-upd-def ) qed(simp add: finfun-const-def ) } thus ?thesis by(simp add: finfun-const-def ) qed 73.7 Default value for FinFuns definition finfun-default-aux :: ( 0a ⇒ 0b) ⇒ 0b where [code del]: finfun-default-aux f = (if finite (UNIV :: 0a set) then undefined else THE b. finite {a. f a 6= b}) lemma finfun-default-aux-infinite: fixes f :: 0a ⇒ 0b assumes infin: ¬ finite (UNIV :: 0a set) and fin: finite {a. f a 6= b} shows finfun-default-aux f = b proof − let ?B = {a. f a 6= b} from fin have (THE b. finite {a. f a 6= b}) = b proof(rule the-equality) fix b 0 assume finite {a. f a 6= b 0} (is finite ?B 0) with infin fin have UNIV − (?B 0 ∪ ?B) 6= {} by(auto dest: finite-subset) then obtain a where a: a ∈/ ?B 0 ∪ ?B by auto thus b 0 = b by auto qed thus ?thesis using infin by(simp add: finfun-default-aux-def ) qed lemma finite-finfun-default-aux: fixes f :: 0a ⇒ 0b assumes fin: f ∈ finfun shows finite {a. f a 6= finfun-default-aux f } proof(cases finite (UNIV :: 0a set)) case True thus ?thesis using fin by(auto simp add: finfun-def finfun-default-aux-def intro: finite-subset) next case False from fin obtain b where b: finite {a. f a 6= b} (is finite ?B) 553 unfolding finfun-def by blast with False show ?thesis by(simp add: finfun-default-aux-infinite) qed lemma finfun-default-aux-update-const: fixes f :: 0a ⇒ 0b assumes fin: f ∈ finfun shows finfun-default-aux (f (a := b)) = finfun-default-aux f proof(cases finite (UNIV :: 0a set)) case False from fin obtain b 0 where b 0: finite {a. f a 6= b 0} unfolding finfun-def by blast hence finite {a 0. (f (a := b)) a 0 6= b 0} proof(cases b = b 0 ∧ f a 6= b 0) case True hence {a. f a 6= b 0} = insert a {a 0. (f (a := b)) a 0 6= b 0} by auto thus ?thesis using b 0 by simp next case False moreover { assume b 6= b 0 hence {a 0. (f (a := b)) a 0 6= b 0} = insert a {a. f a 6= b 0} by auto hence ?thesis using b 0 by simp } moreover { assume b = b 0 f a = b 0 hence {a 0. (f (a := b)) a 0 6= b 0} = {a. f a 6= b 0} by auto hence ?thesis using b 0 by simp } ultimately show ?thesis by blast qed with False b 0 show ?thesis by(auto simp del: fun-upd-apply simp add: finfun-default-aux-infinite) next case True thus ?thesis by(simp add: finfun-default-aux-def ) qed lift-definition finfun-default :: 0a ⇒f 0b ⇒ 0b is finfun-default-aux . lemma finite-finfun-default: finite {a. finfun-apply f a 6= finfun-default f } by transfer (erule finite-finfun-default-aux) lemma finfun-default-const: finfun-default ((K $ b) :: 0a ⇒f 0b) = (if finite (UNIV :: 0a set) then undefined else b) by(transfer)(auto simp add: finfun-default-aux-infinite finfun-default-aux-def ) lemma finfun-default-update-const: finfun-default (f (a $:= b)) = finfun-default f by transfer (simp add: finfun-default-aux-update-const) lemma finfun-default-const-code [code]: finfun-default ((K $ c) :: 0a :: card-UNIV ⇒f 0b) = (if CARD( 0a) = 0 then c else 554 undefined) by(simp add: finfun-default-const) lemma finfun-default-update-code [code]: finfun-default (finfun-update-code f a b) = finfun-default f by(simp add: finfun-default-update-const) 73.8 Recursion combinator and well-formedness conditions definition finfun-rec :: ( 0b ⇒ 0c) ⇒ ( 0a ⇒ 0b ⇒ 0c ⇒ 0c) ⇒ ( 0a ⇒f 0b) ⇒ 0c where [code del]: finfun-rec cnst upd f ≡ let b = finfun-default f ; g = THE g. f = Abs-finfun (map-default b g) ∧ finite (dom g) ∧ b ∈/ ran g in Finite-Set.fold (λa. upd a (map-default b g a)) (cnst b)(dom g) locale finfun-rec-wf-aux = fixes cnst :: 0b ⇒ 0c and upd :: 0a ⇒ 0b ⇒ 0c ⇒ 0c assumes upd-const-same: upd a b (cnst b) = cnst b and upd-commute: a 6= a 0 =⇒ upd a b (upd a 0 b 0 c) = upd a 0 b 0 (upd a b c) and upd-idemp: b 6= b 0 =⇒ upd a b 00 (upd a b 0 (cnst b)) = upd a b 00 (cnst b) begin lemma upd-left-comm: comp-fun-commute (λa. upd a (f a)) by(unfold-locales)(auto intro: upd-commute simp add: fun-eq-iff ) lemma upd-upd-twice: upd a b 00 (upd a b 0 (cnst b)) = upd a b 00 (cnst b) by(cases b 6= b 0)(auto simp add: fun-upd-def upd-const-same upd-idemp) lemma map-default-update-const: assumes fin: finite (dom f ) and anf : a ∈/ dom f and fg: f ⊆m g shows upd a d (Finite-Set.fold (λa. upd a (map-default d g a)) (cnst d)(dom f )) = Finite-Set.fold (λa. upd a (map-default d g a)) (cnst d)(dom f ) proof − let ?upd = λa. upd a (map-default d g a) let ?fr = λA. Finite-Set.fold ?upd (cnst d) A interpret gwf : comp-fun-commute ?upd by(rule upd-left-comm) from fin anf fg show ?thesis proof(induct dom f arbitrary: f ) case empty from h{} = dom f i have f = empty by(auto simp add: dom-def ) thus ?case by(simp add: finfun-const-def upd-const-same) next 555 case (insert a 0 A) V note IH = h f . [[ A = dom f ; a ∈/ dom f ; f ⊆m g ]] =⇒ upd a d (?fr (dom f )) = ?fr (dom f )i 0 0 note fin = hfinite Ai note anf = ha ∈/ dom f i note a nA = ha ∈/ Ai 0 note domf = hinsert a A = dom f i note fg = hf ⊆m g i from domf obtain b where b: f a 0 = Some b by auto let ?f 0 = f (a 0 := None) have upd a d (?fr (insert a 0 A)) = upd a d (upd a 0 (map-default d g a 0)(?fr A)) by(subst gwf .fold-insert[OF fin a 0nA]) rule also from b fg have g a 0 = f a 0 by(auto simp add: map-le-def intro: domI dest: bspec) hence ga 0: map-default d g a 0 = map-default d f a 0 by(simp add: map-default-def ) also from anf domf have a 6= a 0 by auto note upd-commute[OF this] 0 0 0 0 also from domf a nA anf fg have a ∈/ dom ?f ?f ⊆m g and A: A = dom ?f by(auto simp add: ran-def map-le-def ) 0 0 note A also note IH [OF A ha ∈/ dom ?f i h?f ⊆m g i] also have upd a 0 (map-default d f a 0)(?fr (dom (f (a 0 := None)))) = ?fr (dom f ) unfolding domf [symmetric] gwf .fold-insert[OF fin a 0nA] ga 0 unfolding A .. also have insert a 0 (dom ?f 0) = dom f using domf by auto finally show ?case . qed qed lemma map-default-update-twice: assumes fin: finite (dom f ) and anf : a ∈/ dom f and fg: f ⊆m g shows upd a d 00 (upd a d 0 (Finite-Set.fold (λa. upd a (map-default d g a)) (cnst d)(dom f ))) = upd a d 00 (Finite-Set.fold (λa. upd a (map-default d g a)) (cnst d)(dom f )) proof − let ?upd = λa. upd a (map-default d g a) let ?fr = λA. Finite-Set.fold ?upd (cnst d) A interpret gwf : comp-fun-commute ?upd by(rule upd-left-comm) from fin anf fg show ?thesis proof(induct dom f arbitrary: f ) case empty from h{} = dom f i have f = empty by(auto simp add: dom-def ) thus ?case by(auto simp add: finfun-const-def finfun-update-def upd-upd-twice) next case (insert a 0 A) V 00 0 note IH = h f . [[A = dom f ; a ∈/ dom f ; f ⊆m g]] =⇒ upd a d (upd a d (?fr 00 (dom f ))) = upd a d (?fr (dom f ))i 0 0 note fin = hfinite Ai note anf = ha ∈/ dom f i note a nA = ha ∈/ Ai 0 note domf = hinsert a A = dom f i note fg = hf ⊆m g i 556 from domf obtain b where b: f a 0 = Some b by auto let ?f 0 = f (a 0 := None) let ?b 0 = case f a 0 of None ⇒ d | Some b ⇒ b from domf have upd a d 00 (upd a d 0 (?fr (dom f ))) = upd a d 00 (upd a d 0 (?fr (insert a 0 A))) by simp also note gwf .fold-insert[OF fin a 0nA] also from b fg have g a 0 = f a 0 by(auto simp add: map-le-def intro: domI dest: bspec) hence ga 0: map-default d g a 0 = map-default d f a 0 by(simp add: map-default-def ) also from anf domf have ana 0: a 6= a 0 by auto note upd-commute[OF this] also note upd-commute[OF ana 0] 0 0 0 0 also from domf a nA anf fg have a ∈/ dom ?f ?f ⊆m g and A: A = dom ?f by(auto simp add: ran-def map-le-def ) 0 0 note A also note IH [OF A ha ∈/ dom ?f i h?f ⊆m g i] also note upd-commute[OF ana 0[symmetric]] also note ga 0[symmetric] also note A[symmetric] also note gwf .fold-insert[symmetric, OF fin a 0nA] also note domf finally show ?case . qed qed lemma map-default-eq-id [simp]: map-default d ((λa. Some (f a)) |‘ {a. f a 6= d}) = f by(auto simp add: map-default-def restrict-map-def ) lemma finite-rec-cong1 : assumes f : comp-fun-commute f and g: comp-fun-commute g and fin: finite A and eq: Va. a ∈ A =⇒ f a = g a shows Finite-Set.fold f z A = Finite-Set.fold g z A proof − interpret f : comp-fun-commute f by(rule f ) interpret g: comp-fun-commute g by(rule g) { fix B assume BsubA: B ⊆ A with fin have finite B by(blast intro: finite-subset) hence B ⊆ A =⇒ Finite-Set.fold f z B = Finite-Set.fold g z B proof(induct) case empty thus ?case by simp next case (insert a B) note finB = hfinite B i note anB = ha ∈/ B i note sub = hinsert a B ⊆ Ai note IH = hB ⊆ A =⇒ Finite-Set.fold f z B = Finite-Set.fold g z B i from sub anB have BpsubA: B ⊂ A and BsubA: B ⊆ A and aA: a ∈ A by auto from IH [OF BsubA] eq[OF aA] finB anB show ?case by(auto) qed 557 with BsubA have Finite-Set.fold f z B = Finite-Set.fold g z B by blast } thus ?thesis by blast qed lemma finfun-rec-upd [simp]: finfun-rec cnst upd (f (a 0 $:= b 0)) = upd a 0 b 0 (finfun-rec cnst upd f ) including finfun proof − obtain b where b: b = finfun-default f by auto let ?the = λf g. f = Abs-finfun (map-default b g) ∧ finite (dom g) ∧ b ∈/ ran g obtain g where g: g = The (?the f ) by blast obtain y where f : f = Abs-finfun y and y: y ∈ finfun by (cases f ) from f y b have bfin: finite {a. y a 6= b} by(simp add: finfun-default-def finite-finfun-default-aux) let ?g = (λa. Some (y a)) |‘ {a. y a 6= b} from bfin have fing: finite (dom ?g) by auto have bran: b ∈/ ran ?g by(auto simp add: ran-def restrict-map-def ) have yg: y = map-default b ?g by simp have gg: g = ?g unfolding g proof(rule the-equality) from f y bfin show ?the f ?g by(auto)(simp add: restrict-map-def ran-def split: if-split-asm) next fix g 0 assume ?the f g 0 hence fin 0: finite (dom g 0) and ran 0: b ∈/ ran g 0 and eq: Abs-finfun (map-default b ?g) = Abs-finfun (map-default b g 0) using f yg by auto from fin 0 fing have map-default b ?g ∈ finfun map-default b g 0 ∈ finfun by(blast intro: map-default-in-finfun)+ with eq have map-default b ?g = map-default b g 0 by simp with fing bran fin 0 ran 0 show g 0 = ?g by(rule map-default-inject[OF disjI2 [OF refl], THEN sym]) qed show ?thesis proof(cases b 0 = b) case True note b 0b = True let ?g 0 = (λa. Some ((y(a 0 := b)) a)) |‘ {a. (y(a 0 := b)) a 6= b} from bfin b 0b have fing 0: finite (dom ?g 0) by(auto simp add: Collect-conj-eq Collect-imp-eq intro: finite-subset) have brang 0: b ∈/ ran ?g 0 by(auto simp add: ran-def restrict-map-def ) let ?b 0 = λa. case ?g 0 a of None ⇒ b | Some b ⇒ b let ?b = map-default b ?g from upd-left-comm upd-left-comm fing 0 558 have Finite-Set.fold (λa. upd a (?b 0 a)) (cnst b)(dom ?g 0) = Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g 0) by(rule finite-rec-cong1 )(auto simp add: restrict-map-def b 0b b map-default-def ) also interpret gwf : comp-fun-commute λa. upd a (?b a) by(rule upd-left-comm) have Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g 0) = upd a 0 b 0 (Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g)) proof(cases y a 0 = b) case True with b 0b have g 0: ?g 0 = ?g by(auto simp add: restrict-map-def ) from True have a 0ndomg: a 0 ∈/ dom ?g by auto from f b 0b b show ?thesis unfolding g 0 by(subst map-default-update-const[OF fing a 0ndomg map-le-refl, symmetric]) simp next case False hence domg: dom ?g = insert a 0 (dom ?g 0) by auto from False b 0b have a 0ndomg 0: a 0 ∈/ dom ?g 0 by auto have Finite-Set.fold (λa. upd a (?b a)) (cnst b)(insert a 0 (dom ?g 0)) = upd a 0 (?b a 0)(Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g 0)) using fing 0 a 0ndomg 0 unfolding b 0b by(rule gwf .fold-insert) hence upd a 0 b (Finite-Set.fold (λa. upd a (?b a)) (cnst b)(insert a 0 (dom ?g 0))) = upd a 0 b (upd a 0 (?b a 0)(Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g 0))) by simp 0 0 0 also from b b have g leg: ?g ⊆m ?g by(auto simp add: restrict-map-def map-le-def ) note map-default-update-twice[OF fing 0 a 0ndomg 0 this, of b ?b a 0 b] also note map-default-update-const[OF fing 0 a 0ndomg 0 g 0leg, of b] finally show ?thesis unfolding b 0b domg[unfolded b 0b] by(rule sym) qed also have The (?the (f (a 0 $:= b 0))) = ?g 0 proof(rule the-equality) from f y b b 0b brang 0 fing 0 show ?the (f (a 0 $:= b 0)) ?g 0 by(auto simp del: fun-upd-apply simp add: finfun-update-def ) next fix g 0 assume ?the (f (a 0 $:= b 0)) g 0 hence fin 0: finite (dom g 0) and ran 0: b ∈/ ran g 0 and eq: f (a 0 $:= b 0) = Abs-finfun (map-default b g 0) by(auto simp del: fun-upd-apply) from fin 0 fing 0 have map-default b g 0 ∈ finfun map-default b ?g 0 ∈ finfun by(blast intro: map-default-in-finfun)+ with eq f b 0b b have map-default b ?g 0 = map-default b g 0 by(simp del: fun-upd-apply add: finfun-update-def ) with fing 0 brang 0 fin 0 ran 0 show g 0 = ?g 0 by(rule map-default-inject[OF disjI2 [OF refl], THEN sym]) qed ultimately show ?thesis unfolding finfun-rec-def Let-def b gg[unfolded g b] using bfin b 0b b 559 by(simp only: finfun-default-update-const map-default-def ) next case False note b 0b = this let ?g 0 = ?g(a 0 7→ b 0) let ?b 0 = map-default b ?g 0 let ?b = map-default b ?g from fing have fing 0: finite (dom ?g 0) by auto from bran b 0b have bnrang 0: b ∈/ ran ?g 0 by(auto simp add: ran-def ) have ffmg 0: map-default b ?g 0 = y(a 0 := b 0) by(auto simp add: map-default-def restrict-map-def ) with f y have f-Abs: f (a 0 $:= b 0) = Abs-finfun (map-default b ?g 0) by(auto simp add: finfun-update-def ) have g 0: The (?the (f (a 0 $:= b 0))) = ?g 0 proof (rule the-equality) from fing 0 bnrang 0 f-Abs show ?the (f (a 0 $:= b 0)) ?g 0 by(auto simp add: finfun-update-def restrict-map-def ) next fix g 0 assume ?the (f (a 0 $:= b 0)) g 0 hence f 0: f (a 0 $:= b 0) = Abs-finfun (map-default b g 0) and fin 0: finite (dom g 0) and brang 0: b ∈/ ran g 0 by auto from fing 0 fin 0 have map-default b ?g 0 ∈ finfun map-default b g 0 ∈ finfun by(auto intro: map-default-in-finfun) with f 0 f-Abs have map-default b g 0 = map-default b ?g 0 by simp with fin 0 brang 0 fing 0 bnrang 0 show g 0 = ?g 0 by(rule map-default-inject[OF disjI2 [OF refl]]) qed have dom: dom (((λa. Some (y a)) |‘ {a. y a 6= b})(a 0 7→ b 0)) = insert a 0 (dom ((λa. Some (y a)) |‘ {a. y a 6= b})) by auto show ?thesis proof(cases y a 0 = b) case True hence a 0ndomg: a 0 ∈/ dom ?g by auto from f y b 0b True have yff : y = map-default b (?g 0 |‘ dom ?g) by(auto simp add: restrict-map-def map-default-def intro!: ext) hence f 0: f = Abs-finfun (map-default b (?g 0 |‘ dom ?g)) using f by simp interpret g 0wf : comp-fun-commute λa. upd a (?b 0 a) by(rule upd-left-comm) from upd-left-comm upd-left-comm fing have Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g) = Finite-Set.fold (λa. upd a (?b 0 a)) (cnst b)(dom ?g) by(rule finite-rec-cong1 )(auto simp add: restrict-map-def b 0b True map-default-def ) thus ?thesis unfolding finfun-rec-def Let-def finfun-default-update-const b[symmetric] unfolding g 0 g[symmetric] gg g 0wf .fold-insert[OF fing a 0ndomg, of cnst b, folded dom] by −(rule arg-cong2 [where f =upd a 0], simp-all add: map-default-def ) next case False 560 hence insert a 0 (dom ?g) = dom ?g by auto moreover { let ?g 00 = ?g(a 0 := None) let ?b 00 = map-default b ?g 00 from False have domg: dom ?g = insert a 0 (dom ?g 00) by auto from False have a 0ndomg 00: a 0 ∈/ dom ?g 00 by auto have fing 00: finite (dom ?g 00) by(rule finite-subset[OF - fing]) auto have bnrang 00: b ∈/ ran ?g 00 by(auto simp add: ran-def restrict-map-def ) interpret gwf : comp-fun-commute λa. upd a (?b a) by(rule upd-left-comm) interpret g 0wf : comp-fun-commute λa. upd a (?b 0 a) by(rule upd-left-comm) have upd a 0 b 0 (Finite-Set.fold (λa. upd a (?b a)) (cnst b)(insert a 0 (dom ?g 00))) = upd a 0 b 0 (upd a 0 (?b a 0)(Finite-Set.fold (λa. upd a (?b a)) (cnst b) (dom ?g 00))) unfolding gwf .fold-insert[OF fing 00 a 0ndomg 00] f .. 00 00 also have g leg: ?g |‘ dom ?g ⊆m ?g by(auto simp add: map-le-def ) have dom (?g |‘ dom ?g 00) = dom ?g 00 by auto note map-default-update-twice[where d=b and f = ?g |‘ dom ?g 00 and a=a 0 and d 0=?b a 0 and d 00=b 0 and g=?g, unfolded this, OF fing 00 a 0ndomg 00 g 00leg] also have b 0: b 0 = ?b 0 a 0 by(auto simp add: map-default-def ) from upd-left-comm upd-left-comm fing 00 have Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g 00) = Finite-Set.fold (λa. upd a (?b 0 a)) (cnst b)(dom ?g 00) by(rule finite-rec-cong1 )(auto simp add: restrict-map-def b 0b map-default-def ) with b 0 have upd a 0 b 0 (Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g 00)) = upd a 0 (?b 0 a 0)(Finite-Set.fold (λa. upd a (?b 0 a)) (cnst b)(dom ?g 00)) by simp also note g 0wf .fold-insert[OF fing 00 a 0ndomg 00, symmetric] finally have upd a 0 b 0 (Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g)) = Finite-Set.fold (λa. upd a (?b 0 a)) (cnst b)(dom ?g) unfolding domg . } ultimately have Finite-Set.fold (λa. upd a (?b 0 a)) (cnst b)(insert a 0 (dom ?g)) = upd a 0 b 0 (Finite-Set.fold (λa. upd a (?b a)) (cnst b)(dom ?g)) by simp thus ?thesis unfolding finfun-rec-def Let-def finfun-default-update-const b[symmetric] g[symmetric] g 0 dom[symmetric] using b 0b gg by(simp add: map-default-insert) qed qed qed end locale finfun-rec-wf = finfun-rec-wf-aux + assumes const-update-all: 561 finite (UNIV :: 0a set) =⇒ Finite-Set.fold (λa. upd a b 0)(cnst b)(UNIV :: 0a set) = cnst b 0 begin lemma finfun-rec-const [simp]: finfun-rec cnst upd (K $ c) = cnst c including finfun proof(cases finite (UNIV :: 0a set)) case False hence finfun-default ((K $ c) :: 0a ⇒f 0b) = c by(simp add: finfun-default-const) moreover have (THE g :: 0a * 0b. (K $ c) = Abs-finfun (map-default c g) ∧ finite (dom g) ∧ c ∈/ ran g) = empty proof (rule the-equality) show (K $ c) = Abs-finfun (map-default c empty) ∧ finite (dom empty) ∧ c ∈/ ran empty by(auto simp add: finfun-const-def ) next fix g :: 0a * 0b assume (K $ c) = Abs-finfun (map-default c g) ∧ finite (dom g) ∧ c ∈/ ran g hence g:(K $ c) = Abs-finfun (map-default c g) and fin: finite (dom g) and ran: c ∈/ ran g by blast+ from g map-default-in-finfun[OF fin, of c] have map-default c g = (λa. c) by(simp add: finfun-const-def ) moreover have map-default c empty = (λa. c) by simp ultimately show g = empty by−(rule map-default-inject[OF disjI2 [OF refl] fin ran], auto) qed ultimately show ?thesis by(simp add: finfun-rec-def ) next case True hence default: finfun-default ((K $ c) :: 0a ⇒f 0b) = undefined by(simp add: finfun-default-const) let ?the = λg :: 0a * 0b. (K $ c) = Abs-finfun (map-default undefined g) ∧ finite (dom g) ∧ undefined ∈/ ran g show ?thesis proof(cases c = undefined) case True have the: The ?the = empty proof (rule the-equality) from True show ?the empty by(auto simp add: finfun-const-def ) next fix g 0 assume ?the g 0 hence fg:(K $ c) = Abs-finfun (map-default undefined g 0) and fin: finite (dom g 0) and g: undefined ∈/ ran g 0 by simp-all from fin have map-default undefined g 0 ∈ finfun by(rule map-default-in-finfun) with fg have map-default undefined g 0 = (λa. c) by(auto simp add: finfun-const-def intro: Abs-finfun-inject[THEN iffD1 , symmetric]) with True show g 0 = empty 562 by −(rule map-default-inject(2 )[OF - fin g], auto) qed show ?thesis unfolding finfun-rec-def using hfinite UNIV i True unfolding Let-def the default by(simp) next case False have the: The ?the = (λa :: 0a. Some c) proof (rule the-equality) from False True show ?the (λa :: 0a. Some c) by(auto simp add: map-default-def [abs-def ] finfun-const-def dom-def ran-def ) next fix g 0 :: 0a * 0b assume ?the g 0 hence fg:(K $ c) = Abs-finfun (map-default undefined g 0) and fin: finite (dom g 0) and g: undefined ∈/ ran g 0 by simp-all from fin have map-default undefined g 0 ∈ finfun by(rule map-default-in-finfun) with fg have map-default undefined g 0 = (λa. c) by(auto simp add: finfun-const-def intro: Abs-finfun-inject[THEN iffD1 ]) with True False show g 0 = (λa:: 0a. Some c) by − (rule map-default-inject(2 )[OF - fin g], auto simp add: dom-def ran-def map-default-def [abs-def ]) qed show ?thesis unfolding finfun-rec-def using True False unfolding Let-def the default by(simp add: dom-def map-default-def const-update-all) qed qed end 73.9 Weak induction rule and case analysis for FinFuns lemma finfun-weak-induct [consumes 0 , case-names const update]: assumes const: Vb. P (K $ b) and update: Vf a b. P f =⇒ P (f (a $:= b)) shows P x including finfun proof(induct x rule: Abs-finfun-induct) case (Abs-finfun y) then obtain b where finite {a. y a 6= b} unfolding finfun-def by blast thus ?case using hy ∈ finfun i proof(induct {a. y a 6= b} arbitrary: y rule: finite-induct) case empty hence Va. y a = b by blast hence y = (λa. b) by(auto) hence Abs-finfun y = finfun-const b unfolding finfun-const-def by simp thus ?case by(simp add: const) next case (insert a A) note IH = hVy. [[ A = {a. y a 6= b}; y ∈ finfun ]] =⇒ P (Abs-finfun y)i 563 note y = hy ∈ finfun i with hinsert a A = {a. y a 6= b}i ha ∈/ Ai have A = {a 0. (y(a := b)) a 0 6= b} y(a := b) ∈ finfun by auto from IH [OF this] have P (finfun-update (Abs-finfun (y(a := b))) a (y a)) by(rule update) thus ?case using y unfolding finfun-update-def by simp qed qed lemma finfun-exhaust-disj :(∃ b. x = finfun-const b) ∨ (∃ f a b. x = finfun-update f a b) by(induct x rule: finfun-weak-induct) blast+ lemma finfun-exhaust: obtains b where x = (K $ b) | f a b where x = f (a $:= b) by(atomize-elim)(rule finfun-exhaust-disj ) lemma finfun-rec-unique: fixes f :: 0a ⇒f 0b ⇒ 0c assumes c: Vc. f (K $ c) = cnst c and u: Vg a b. f (g(a $:= b)) = upd g a b (f g) and c 0: Vc. f 0 (K $ c) = cnst c and u 0: Vg a b. f 0 (g(a $:= b)) = upd g a b (f 0 g) shows f = f 0 proof fix g :: 0a ⇒f 0b show f g = f 0 g by(induct g rule: finfun-weak-induct)(auto simp add: c u c 0 u 0) qed 73.10 Function application notation finfun-apply (infixl $ 999 ) interpretation finfun-apply-aux: finfun-rec-wf-aux λb. b λa 0 b c. if (a = a 0) then b else c by(unfold-locales) auto interpretation finfun-apply: finfun-rec-wf λb. b λa 0 b c. if (a = a 0) then b else c proof(unfold-locales) fix b 0 b :: 0a assume fin: finite (UNIV :: 0b set) { fix A :: 0b set interpret comp-fun-commute λa 0. If (a = a 0) b 0 by(rule finfun-apply-aux.upd-left-comm) from fin have finite A by(auto intro: finite-subset) hence Finite-Set.fold (λa 0. If (a = a 0) b 0) b A = (if a ∈ A then b 0 else b) by induct auto } from this[of UNIV ] show Finite-Set.fold (λa 0. If (a = a 0) b 0) b UNIV = b 0 by 564 simp qed lemma finfun-apply-def : op $ = (λf a. finfun-rec (λb. b)(λa 0 b c. if (a = a 0) then b else c) f ) proof(rule finfun-rec-unique) fix c show op $ (K $ c) = (λa. c) by(simp add: finfun-const.rep-eq) next fix g a b show op $ g(a $:= b) = (λc. if c = a then b else g $ c) by(auto simp add: finfun-update-def fun-upd-finfun Abs-finfun-inverse finfun-apply) qed auto lemma finfun-upd-apply: f (a $:= b) $ a 0 = (if a = a 0 then b else f $ a 0) and finfun-upd-apply-code [code]: (finfun-update-code f a b) $ a 0 = (if a = a 0 then b else f $ a 0) by(simp-all add: finfun-apply-def ) lemma finfun-const-apply [simp, code]: (K $ b) $ a = b by(simp add: finfun-apply-def ) lemma finfun-upd-apply-same [simp]: f (a $:= b) $ a = b by(simp add: finfun-upd-apply) lemma finfun-upd-apply-other [simp]: a 6= a 0 =⇒ f (a $:= b) $ a 0 = f $ a 0 by(simp add: finfun-upd-apply) lemma finfun-ext:(Va. f $ a = g $ a) =⇒ f = g by(auto simp add: finfun-apply-inject[symmetric]) lemma expand-finfun-eq:(f = g) = (op $ f = op $ g) by(auto intro: finfun-ext) lemma finfun-upd-triv [simp]: f (x $:= f $ x) = f by(simp add: expand-finfun-eq fun-eq-iff finfun-upd-apply) lemma finfun-const-inject [simp]: (K $ b) = (K $ b 0) ≡ b = b 0 by(simp add: expand-finfun-eq fun-eq-iff ) lemma finfun-const-eq-update: ((K $ b) = f (a $:= b 0)) = (b = b 0 ∧ (∀ a 0. a 6= a 0 −→ f $ a 0 = b)) by(auto simp add: expand-finfun-eq fun-eq-iff finfun-upd-apply) 73.11 Function composition definition finfun-comp :: ( 0a ⇒ 0b) ⇒ 0c ⇒f 0a ⇒ 0c ⇒f 0b (infixr ◦$ 55 ) where [code del]: g ◦$ f = finfun-rec (λb. (K $ g b)) (λa b c. c(a $:= g b)) f 565 notation (ASCII ) finfun-comp (infixr o$ 55 ) interpretation finfun-comp-aux: finfun-rec-wf-aux (λb. (K $ g b)) (λa b c. c(a $:= g b)) by(unfold-locales)(auto simp add: finfun-upd-apply intro: finfun-ext) interpretation finfun-comp: finfun-rec-wf (λb. (K $ g b)) (λa b c. c(a $:= g b)) proof fix b 0 b :: 0a assume fin: finite (UNIV :: 0c set) { fix A :: 0c set from fin have finite A by(auto intro: finite-subset) hence Finite-Set.fold (λ(a :: 0c) c. c(a $:= g b 0)) (K $ g b) A = Abs-finfun (λa. if a ∈ A then g b 0 else g b) by induct (simp-all add: finfun-const-def , auto simp add: finfun-update-def Abs-finfun-inverse-finite fun-upd-def Abs-finfun-inject-finite fun-eq-iff fin) } from this[of UNIV ] show Finite-Set.fold (λ(a :: 0c) c. c(a $:= g b 0)) (K $ g b) UNIV = (K $ g b 0) by(simp add: finfun-const-def ) qed lemma finfun-comp-const [simp, code]: g ◦$ (K $ c) = (K $ g c) by(simp add: finfun-comp-def ) lemma finfun-comp-update [simp]: g ◦$ (f (a $:= b)) = (g ◦$ f )(a $:= g b) and finfun-comp-update-code [code]: g ◦$ (finfun-update-code f a b) = finfun-update-code (g ◦$ f ) a (g b) by(simp-all add: finfun-comp-def ) lemma finfun-comp-apply [simp]: op $ (g ◦$ f ) = g ◦ op $ f by(induct f rule: finfun-weak-induct)(auto simp add: finfun-upd-apply) lemma finfun-comp-comp-collapse [simp]: f ◦$ g ◦$ h = (f ◦ g) ◦$ h by(induct h rule: finfun-weak-induct) simp-all lemma finfun-comp-const1 [simp]: (λx. c) ◦$ f = (K $ c) by(induct f rule: finfun-weak-induct)(auto intro: finfun-ext simp add: finfun-upd-apply) lemma finfun-comp-id1 [simp]: (λx. x) ◦$ f = f id ◦$ f = f by(induct f rule: finfun-weak-induct) auto lemma finfun-comp-conv-comp: g ◦$ f = Abs-finfun (g ◦ op $ f ) including finfun proof − have (λf . g ◦$ f ) = (λf . Abs-finfun (g ◦ op $ f )) proof(rule finfun-rec-unique) 566 { fix c show Abs-finfun (g ◦ op $ (K $ c)) = (K $ g c) by(simp add: finfun-comp-def o-def )(simp add: finfun-const-def ) } { fix g 0 a b show Abs-finfun (g ◦ op $ g 0(a $:= b)) = (Abs-finfun (g ◦ op $ g 0))(a $:= g b) proof − obtain y where y: y ∈ finfun and g 0: g 0 = Abs-finfun y by(cases g 0) moreover from g 0 have (g ◦ op $ g 0) ∈ finfun by(simp add: finfun-left-compose) moreover have g ◦ y(a := b) = (g ◦ y)(a := g b) by(auto) ultimately show ?thesis by(simp add: finfun-comp-def finfun-update-def ) qed } qed auto thus ?thesis by(auto simp add: fun-eq-iff ) qed definition finfun-comp2 :: 0b ⇒f 0c ⇒ ( 0a ⇒ 0b) ⇒ 0a ⇒f 0c (infixr $◦ 55 ) where [code del]: g $◦ f = Abs-finfun (op $ g ◦ f ) notation (ASCII ) finfun-comp2 (infixr $o 55 ) lemma finfun-comp2-const [code, simp]: finfun-comp2 (K $ c) f = (K $ c) including finfun by(simp add: finfun-comp2-def finfun-const-def comp-def ) lemma finfun-comp2-update: assumes inj : inj f shows finfun-comp2 (g(b $:= c)) f = (if b ∈ range f then (finfun-comp2 g f )(inv f b $:= c) else finfun-comp2 g f ) including finfun proof(cases b ∈ range f ) case True from inj have Vx. (op $ g)(f x := c) ◦ f = (op $ g ◦ f )(x := c) by(auto intro!: ext dest: injD) with inj True show ?thesis by(auto simp add: finfun-comp2-def finfun-update-def finfun-right-compose) next case False hence (op $ g)(b := c) ◦ f = op $ g ◦ f by(auto simp add: fun-eq-iff ) with False show ?thesis by(auto simp add: finfun-comp2-def finfun-update-def ) qed 73.12 Universal quantification definition finfun-All-except :: 0a list ⇒ 0a ⇒f bool ⇒ bool where [code del]: finfun-All-except A P ≡ ∀ a. a ∈ set A ∨ P $ a lemma finfun-All-except-const: finfun-All-except A (K $ b) ←→ b ∨ set A = UNIV by(auto simp add: finfun-All-except-def ) 567 lemma finfun-All-except-const-finfun-UNIV-code [code]: finfun-All-except A (K $ b) = (b ∨ is-list-UNIV A) by(simp add: finfun-All-except-const is-list-UNIV-iff ) lemma finfun-All-except-update: finfun-All-except A f (a $:= b) = ((a ∈ set A ∨ b) ∧ finfun-All-except (a # A) f ) by(fastforce simp add: finfun-All-except-def finfun-upd-apply) lemma finfun-All-except-update-code [code]: fixes a :: 0a :: card-UNIV shows finfun-All-except A (finfun-update-code f a b) = ((a ∈ set A ∨ b) ∧ finfun-All-except (a # A) f ) by(simp add: finfun-All-except-update) definition finfun-All :: 0a ⇒f bool ⇒ bool where finfun-All = finfun-All-except [] lemma finfun-All-const [simp]: finfun-All (K $ b) = b by(simp add: finfun-All-def finfun-All-except-def ) lemma finfun-All-update: finfun-All f (a $:= b) = (b ∧ finfun-All-except [a] f ) by(simp add: finfun-All-def finfun-All-except-update) lemma finfun-All-All: finfun-All P = All (op $ P) by(simp add: finfun-All-def finfun-All-except-def ) definition finfun-Ex :: 0a ⇒f bool ⇒ bool where finfun-Ex P = Not (finfun-All (Not ◦$ P)) lemma finfun-Ex-Ex: finfun-Ex P = Ex (op $ P) unfolding finfun-Ex-def finfun-All-All by simp lemma finfun-Ex-const [simp]: finfun-Ex (K $ b) = b by(simp add: finfun-Ex-def ) 73.13 A diagonal operator for FinFuns definition finfun-Diag :: 0a ⇒f 0b ⇒ 0a ⇒f 0c ⇒ 0a ⇒f ( 0b × 0c) ((1 0($-,/ -$ 0)) [0 , 0 ] 1000 ) where [code del]: ($f , g$) = finfun-rec (λb. Pair b ◦$ g)(λa b c. c(a $:= (b, g $ a))) f interpretation finfun-Diag-aux: finfun-rec-wf-aux λb. Pair b ◦$ g λa b c. c(a $:= (b, g $ a)) by(unfold-locales)(simp-all add: expand-finfun-eq fun-eq-iff finfun-upd-apply) interpretation finfun-Diag: finfun-rec-wf λb. Pair b ◦$ g λa b c. c(a $:= (b, g $ 568 a)) proof fix b 0 b :: 0a assume fin: finite (UNIV :: 0c set) { fix A :: 0c set interpret comp-fun-commute λa c. c(a $:= (b 0, g $ a)) by(rule finfun-Diag-aux.upd-left-comm) from fin have finite A by(auto intro: finite-subset) hence Finite-Set.fold (λa c. c(a $:= (b 0, g $ a))) (Pair b ◦$ g) A = Abs-finfun (λa. (if a ∈ A then b 0 else b, g $ a)) by(induct)(simp-all add: finfun-const-def finfun-comp-conv-comp o-def , auto simp add: finfun-update-def Abs-finfun-inverse-finite fun-upd-def Abs-finfun-inject-finite fun-eq-iff fin) } from this[of UNIV ] show Finite-Set.fold (λa c. c(a $:= (b 0, g $ a))) (Pair b ◦$ g) UNIV = Pair b 0 ◦$ g by(simp add: finfun-const-def finfun-comp-conv-comp o-def ) qed lemma finfun-Diag-const1 : ($K $ b, g$) = Pair b ◦$ g by(simp add: finfun-Diag-def ) Do not use ($K $ ?b, ?g$) = Pair ?b ◦$ ?g for the code generator because Pair b is injective, i.e. if g is free of redundant updates, there is no need to check for redundant updates as is done for op ◦$. lemma finfun-Diag-const-code [code]: ($K $ b, K $ c$) = (K $ (b, c)) ($K $ b, finfun-update-code g a c$) = finfun-update-code ($K $ b, g$) a (b, c) by(simp-all add: finfun-Diag-const1 ) lemma finfun-Diag-update1 : ($f (a $:= b), g$) = ($f , g$)(a $:= (b, g $ a)) and finfun-Diag-update1-code [code]: ($finfun-update-code f a b, g$) = ($f , g$)(a $:= (b, g $ a)) by(simp-all add: finfun-Diag-def ) lemma finfun-Diag-const2 : ($f , K $ c$) = (λb. (b, c)) ◦$ f by(induct f rule: finfun-weak-induct)(auto intro!: finfun-ext simp add: finfun-upd-apply finfun-Diag-const1 finfun-Diag-update1 ) lemma finfun-Diag-update2 : ($f , g(a $:= c)$) = ($f , g$)(a $:= (f $ a, c)) by(induct f rule: finfun-weak-induct)(auto intro!: finfun-ext simp add: finfun-upd-apply finfun-Diag-const1 finfun-Diag-update1 ) lemma finfun-Diag-const-const [simp]: ($K $ b, K $ c$) = (K $ (b, c)) by(simp add: finfun-Diag-const1 ) lemma finfun-Diag-const-update: ($K $ b, g(a $:= c)$) = ($K $ b, g$)(a $:= (b, c)) by(simp add: finfun-Diag-const1 ) lemma finfun-Diag-update-const: 569 ($f (a $:= b), K $ c$) = ($f , K $ c$)(a $:= (b, c)) by(simp add: finfun-Diag-def ) lemma finfun-Diag-update-update: ($f (a $:= b), g(a 0 $:= c)$) = (if a = a 0 then ($f , g$)(a $:= (b, c)) else ($f , g$)(a $:= (b, g $ a))(a 0 $:= (f $ a 0, c))) by(auto simp add: finfun-Diag-update1 finfun-Diag-update2 ) lemma finfun-Diag-apply [simp]: op $ ($f , g$) = (λx. (f $ x, g $ x)) by(induct f rule: finfun-weak-induct)(auto simp add: finfun-Diag-const1 finfun-Diag-update1 finfun-upd-apply) lemma finfun-Diag-conv-Abs-finfun: ($f , g$) = Abs-finfun ((λx. (f $ x, g $ x))) including finfun proof − have (λf :: 0a ⇒f 0b. ($f , g$)) = (λf . Abs-finfun ((λx. (f $ x, g $ x)))) proof(rule finfun-rec-unique) { fix c show Abs-finfun (λx. ((K $ c) $ x, g $ x)) = Pair c ◦$ g by(simp add: finfun-comp-conv-comp o-def finfun-const-def ) } { fix g 0 a b show Abs-finfun (λx. (g 0(a $:= b) $ x, g $ x)) = (Abs-finfun (λx. (g 0 $ x, g $ x)))(a $:= (b, g $ a)) by(auto simp add: finfun-update-def fun-eq-iff simp del: fun-upd-apply) simp } qed(simp-all add: finfun-Diag-const1 finfun-Diag-update1 ) thus ?thesis by(auto simp add: fun-eq-iff ) qed lemma finfun-Diag-eq: ($f , g$) = ($f 0, g 0$) ←→ f = f 0 ∧ g = g 0 by(auto simp add: expand-finfun-eq fun-eq-iff ) definition finfun-fst :: 0a ⇒f ( 0b × 0c) ⇒ 0a ⇒f 0b where [code]: finfun-fst f = fst ◦$ f lemma finfun-fst-const: finfun-fst (K $ bc) = (K $ fst bc) by(simp add: finfun-fst-def ) lemma finfun-fst-update: finfun-fst (f (a $:= bc)) = (finfun-fst f )(a $:= fst bc) and finfun-fst-update-code: finfun-fst (finfun-update-code f a bc) = (finfun-fst f )(a $:= fst bc) by(simp-all add: finfun-fst-def ) lemma finfun-fst-comp-conv: finfun-fst (f ◦$ g) = (fst ◦ f ) ◦$ g by(simp add: finfun-fst-def ) lemma finfun-fst-conv [simp]: finfun-fst ($f , g$) = f by(induct f rule: finfun-weak-induct)(simp-all add: finfun-Diag-const1 finfun-fst-comp-conv o-def finfun-Diag-update1 finfun-fst-update) 570 lemma finfun-fst-conv-Abs-finfun: finfun-fst = (λf . Abs-finfun (fst ◦ op $ f )) by(simp add: finfun-fst-def [abs-def ] finfun-comp-conv-comp) definition finfun-snd :: 0a ⇒f ( 0b × 0c) ⇒ 0a ⇒f 0c where [code]: finfun-snd f = snd ◦$ f lemma finfun-snd-const: finfun-snd (K $ bc) = (K $ snd bc) by(simp add: finfun-snd-def ) lemma finfun-snd-update: finfun-snd (f (a $:= bc)) = (finfun-snd f )(a $:= snd bc) and finfun-snd-update-code [code]: finfun-snd (finfun-update-code f a bc) = (finfun-snd f )(a $:= snd bc) by(simp-all add: finfun-snd-def ) lemma finfun-snd-comp-conv: finfun-snd (f ◦$ g) = (snd ◦ f ) ◦$ g by(simp add: finfun-snd-def ) lemma finfun-snd-conv [simp]: finfun-snd ($f , g$) = g apply(induct f rule: finfun-weak-induct) apply(auto simp add: finfun-Diag-const1 finfun-snd-comp-conv o-def finfun-Diag-update1 finfun-snd-update finfun-upd-apply intro: finfun-ext) done lemma finfun-snd-conv-Abs-finfun: finfun-snd = (λf . Abs-finfun (snd ◦ op $ f )) by(simp add: finfun-snd-def [abs-def ] finfun-comp-conv-comp) lemma finfun-Diag-collapse [simp]: ($finfun-fst f , finfun-snd f $) = f by(induct f rule: finfun-weak-induct)(simp-all add: finfun-fst-const finfun-snd-const finfun-fst-update finfun-snd-update finfun-Diag-update-update) 73.14 Currying for FinFuns definition finfun-curry :: ( 0a × 0b) ⇒f 0c ⇒ 0a ⇒f 0b ⇒f 0c where [code del]: finfun-curry = finfun-rec (finfun-const ◦ finfun-const)(λ(a, b) c f . f (a $:= (f $ a)(b $:= c))) interpretation finfun-curry-aux: finfun-rec-wf-aux finfun-const ◦ finfun-const λ(a, b) c f . f (a $:= (f $ a)(b $:= c)) apply(unfold-locales) apply(auto simp add: split-def finfun-update-twist finfun-upd-apply split-paired-all finfun-update-const-same) done interpretation finfun-curry: finfun-rec-wf finfun-const ◦ finfun-const λ(a, b) c f . f (a $:= (f $ a)(b $:= c)) proof(unfold-locales) fix b 0 b :: 0b 571 assume fin: finite (UNIV :: ( 0c × 0a) set) hence fin1 : finite (UNIV :: 0c set) and fin2 : finite (UNIV :: 0a set) unfolding UNIV-Times-UNIV [symmetric] by(fastforce dest: finite-cartesian-productD1 finite-cartesian-productD2 )+ note [simp] = Abs-finfun-inverse-finite[OF fin] Abs-finfun-inverse-finite[OF fin1 ] Abs-finfun-inverse-finite[OF fin2 ] { fix A :: ( 0c × 0a) set interpret comp-fun-commute λa :: 0c × 0a. (λ(a, b) c f . f (a $:= (f $ a)(b $:= c))) a b 0 by(rule finfun-curry-aux.upd-left-comm) from fin have finite A by(auto intro: finite-subset) hence Finite-Set.fold (λa :: 0c × 0a. (λ(a, b) c f . f (a $:= (f $ a)(b $:= c))) a b 0) ((finfun-const ◦ finfun-const) b) A = Abs-finfun (λa. Abs-finfun (λb 00. if (a, b 00) ∈ A then b 0 else b)) by induct (simp-all, auto simp add: finfun-update-def finfun-const-def split-def intro!: arg-cong[where f =Abs-finfun] ext) } from this[of UNIV ] show Finite-Set.fold (λa :: 0c × 0a. (λ(a, b) c f . f (a $:= (f $ a)(b $:= c))) a b 0) ((finfun-const ◦ finfun-const) b) UNIV = (finfun-const ◦ finfun-const) b 0 by(simp add: finfun-const-def ) qed lemma finfun-curry-const [simp, code]: finfun-curry (K $ c) = (K $ K $ c) by(simp add: finfun-curry-def ) lemma finfun-curry-update [simp]: finfun-curry (f ((a, b) $:= c)) = (finfun-curry f )(a $:= (finfun-curry f $ a)(b $:= c)) and finfun-curry-update-code [code]: finfun-curry (finfun-update-code f (a, b) c) = (finfun-curry f )(a $:= (finfun-curry f $ a)(b $:= c)) by(simp-all add: finfun-curry-def ) lemma finfun-Abs-finfun-curry: assumes fin: f ∈ finfun shows (λa. Abs-finfun (curry f a)) ∈ finfun including finfun proof − from fin obtain c where c: finite {ab. f ab 6= c} unfolding finfun-def by blast have {a. ∃ b. f (a, b) 6= c} = fst ‘ {ab. f ab 6= c} by(force) hence {a. curry f a 6= (λx. c)} = fst ‘ {ab. f ab 6= c} by(auto simp add: curry-def fun-eq-iff ) with fin c have finite {a. Abs-finfun (curry f a) 6= (K $ c)} by(simp add: finfun-const-def finfun-curry) thus ?thesis unfolding finfun-def by auto qed lemma finfun-curry-conv-curry: fixes f :: ( 0a × 0b) ⇒f 0c shows finfun-curry f = Abs-finfun (λa. Abs-finfun (curry (finfun-apply f ) a)) 572 including finfun proof − have finfun-curry = (λf :: ( 0a × 0b) ⇒f 0c. Abs-finfun (λa. Abs-finfun (curry (finfun-apply f ) a))) proof(rule finfun-rec-unique) fix c show finfun-curry (K $ c) = (K $ K $ c) by simp fix f a show finfun-curry (f (a $:= c)) = (finfun-curry f )(fst a $:= (finfun-curry f $ (fst a))(snd a $:= c)) by(cases a) simp show Abs-finfun (λa. Abs-finfun (curry (finfun-apply (K $ c)) a)) = (K $ K $ c) by(simp add: finfun-curry-def finfun-const-def curry-def ) fix g b show Abs-finfun (λaa. Abs-finfun (curry (op $ g(a $:= b)) aa)) = (Abs-finfun (λa. Abs-finfun (curry (op $ g) a)))( fst a $:= ((Abs-finfun (λa. Abs-finfun (curry (op $ g) a))) $ (fst a))(snd a $:= b)) by(cases a)(auto intro!: ext arg-cong[where f =Abs-finfun] simp add: finfun-curry-def finfun-update-def finfun-Abs-finfun-curry) qed thus ?thesis by(auto simp add: fun-eq-iff ) qed 73.15 Executable equality for FinFuns lemma eq-finfun-All-ext:(f = g) ←→ finfun-All ((λ(x, y). x = y) ◦$ ($f , g$)) by(simp add: expand-finfun-eq fun-eq-iff finfun-All-All o-def ) instantiation finfun :: ({card-UNIV ,equal},equal) equal begin definition eq-finfun-def [code]: HOL.equal f g ←→ finfun-All ((λ(x, y). x = y) ◦$ ($f , g$)) instance by(intro-classes)(simp add: eq-finfun-All-ext eq-finfun-def ) end lemma [code nbe]: HOL.equal (f :: - ⇒f -) f ←→ True by (fact equal-refl) 73.16 An operator that explicitly removes all redundant up- dates in the generated representations definition finfun-clearjunk :: 0a ⇒f 0b ⇒ 0a ⇒f 0b where [simp, code del]: finfun-clearjunk = id lemma finfun-clearjunk-const [code]: finfun-clearjunk (K $ b) = (K $ b) by simp lemma finfun-clearjunk-update [code]: 573 finfun-clearjunk (finfun-update-code f a b) = f (a $:= b) by simp 73.17 The domain of a FinFun as a FinFun definition finfun-dom :: ( 0a ⇒f 0b) ⇒ ( 0a ⇒f bool) where [code del]: finfun-dom f = Abs-finfun (λa. f $ a 6= finfun-default f ) lemma finfun-dom-const: finfun-dom ((K $ c) :: 0a ⇒f 0b) = (K $ finite (UNIV :: 0a set) ∧ c 6= undefined) unfolding finfun-dom-def finfun-default-const by(auto)(simp-all add: finfun-const-def ) finfun-dom raises an exception when called on a FinFun whose domain is a finite type. For such FinFuns, the default value (and as such the domain) is undefined. lemma finfun-dom-const-code [code]: finfun-dom ((K $ c) :: ( 0a :: card-UNIV ) ⇒f 0b) = (if CARD( 0a) = 0 then (K $ False) else Code.abort (STR 00finfun-dom called on finite type 00)(λ-. finfun-dom (K $ c))) by(simp add: finfun-dom-const card-UNIV card-eq-0-iff ) lemma finfun-dom-finfunI :(λa. f $ a 6= finfun-default f ) ∈ finfun using finite-finfun-default[of f ] by(simp add: finfun-def exI [where x=False]) lemma finfun-dom-update [simp]: finfun-dom (f (a $:= b)) = (finfun-dom f )(a $:= (b 6= finfun-default f )) including finfun unfolding finfun-dom-def finfun-update-def apply(simp add: finfun-default-update-const finfun-dom-finfunI ) apply(fold finfun-update.rep-eq) apply(simp add: finfun-upd-apply fun-eq-iff fun-upd-def finfun-default-update-const) done lemma finfun-dom-update-code [code]: finfun-dom (finfun-update-code f a b) = finfun-update-code (finfun-dom f ) a (b 6= finfun-default f ) by(simp) lemma finite-finfun-dom: finite {x. finfun-dom f $ x} proof(induct f rule: finfun-weak-induct) case (const b) thus ?case by (cases finite (UNIV :: 0a set) ∧ b 6= undefined) (auto simp add: finfun-dom-const UNIV-def [symmetric] Set.empty-def [symmetric]) next case (update f a b) have {x. finfun-dom f (a $:= b) $ x} = (if b = finfun-default f then {x. finfun-dom f $ x} − {a} else insert a {x. 574 finfun-dom f $ x}) by (auto simp add: finfun-upd-apply split: if-split-asm) thus ?case using update by simp qed 73.18 The domain of a FinFun as a sorted list definition finfun-to-list :: ( 0a :: linorder) ⇒f 0b ⇒ 0a list where finfun-to-list f = (THE xs. set xs = {x. finfun-dom f $ x} ∧ sorted xs ∧ distinct xs) lemma set-finfun-to-list [simp]: set (finfun-to-list f ) = {x. finfun-dom f $ x} (is ?thesis1 ) and sorted-finfun-to-list: sorted (finfun-to-list f )(is ?thesis2 ) and distinct-finfun-to-list: distinct (finfun-to-list f )(is ?thesis3 ) proof (atomize (full)) show ?thesis1 ∧ ?thesis2 ∧ ?thesis3 unfolding finfun-to-list-def by(rule theI 0)(rule finite-sorted-distinct-unique finite-finfun-dom)+ qed lemma finfun-const-False-conv-bot: op $ (K $ False) = bot by auto lemma finfun-const-True-conv-top: op $ (K $ True) = top by auto lemma finfun-to-list-const: finfun-to-list ((K $ c) :: ( 0a :: {linorder} ⇒f 0b)) = (if ¬ finite (UNIV :: 0a set) ∨ c = undefined then [] else THE xs. set xs = UNIV ∧ sorted xs ∧ distinct xs) by(auto simp add: finfun-to-list-def finfun-const-False-conv-bot finfun-const-True-conv-top finfun-dom-const) lemma finfun-to-list-const-code [code]: finfun-to-list ((K $ c) :: ( 0a :: {linorder, card-UNIV } ⇒f 0b)) = (if CARD( 0a) = 0 then [] else Code.abort (STR 00finfun-to-list called on finite type 00)(λ-. finfun-to-list ((K $ c) :: ( 0a ⇒f 0b)))) by(auto simp add: finfun-to-list-const card-UNIV card-eq-0-iff ) lemma remove1-insort-insert-same: x ∈/ set xs =⇒ remove1 x (insort-insert x xs) = xs by (metis insort-insert-insort remove1-insort) lemma finfun-dom-conv: finfun-dom f $ x ←→ f $ x 6= finfun-default f by(induct f rule: finfun-weak-induct)(auto simp add: finfun-dom-const finfun-default-const finfun-default-update-const finfun-upd-apply) 575 lemma finfun-to-list-update: finfun-to-list (f (a $:= b)) = (if b = finfun-default f then List.remove1 a (finfun-to-list f ) else List.insort-insert a (finfun-to-list f )) proof(subst finfun-to-list-def , rule the-equality) fix xs assume set xs = {x. finfun-dom f (a $:= b) $ x} ∧ sorted xs ∧ distinct xs hence eq: set xs = {x. finfun-dom f (a $:= b) $ x} and [simp]: sorted xs distinct xs by simp-all show xs = (if b = finfun-default f then remove1 a (finfun-to-list f ) else insort-insert a (finfun-to-list f )) proof(cases b = finfun-default f ) case [simp]: True show ?thesis proof(cases finfun-dom f $ a) case True have finfun-to-list f = insort-insert a xs unfolding finfun-to-list-def proof(rule the-equality) have set (insort-insert a xs) = insert a (set xs) by(simp add: set-insort-insert) also note eq also have insert a {x. finfun-dom f (a $:= b) $ x} = {x. finfun-dom f $ x} using True by(auto simp add: finfun-upd-apply split: if-split-asm) finally show 1 : set (insort-insert a xs) = {x. finfun-dom f $ x} ∧ sorted (insort-insert a xs) ∧ distinct (insort-insert a xs) by(simp add: sorted-insort-insert distinct-insort-insert) fix xs 0 assume set xs 0 = {x. finfun-dom f $ x} ∧ sorted xs 0 ∧ distinct xs 0 thus xs 0 = insort-insert a xs using 1 by(auto dest: sorted-distinct-set-unique) qed with eq True show ?thesis by(simp add: remove1-insort-insert-same) next case False hence f $ a = b by(auto simp add: finfun-dom-conv) hence f : f (a $:= b) = f by(simp add: expand-finfun-eq fun-eq-iff finfun-upd-apply) from eq have finfun-to-list f = xs unfolding f finfun-to-list-def by(auto elim: sorted-distinct-set-unique intro!: the-equality) with eq False show ?thesis unfolding f by(simp add: remove1-idem) qed next case False show ?thesis proof(cases finfun-dom f $ a) case True have finfun-to-list f = xs unfolding finfun-to-list-def 576 proof(rule the-equality) have finfun-dom f = finfun-dom f (a $:= b) using False True by(simp add: expand-finfun-eq fun-eq-iff finfun-upd-apply) with eq show 1 : set xs = {x. finfun-dom f $ x} ∧ sorted xs ∧ distinct xs by(simp del: finfun-dom-update) fix xs 0 assume set xs 0 = {x. finfun-dom f $ x} ∧ sorted xs 0 ∧ distinct xs 0 thus xs 0 = xs using 1 by(auto elim: sorted-distinct-set-unique) qed thus ?thesis using False True eq by(simp add: insort-insert-triv) next case False have finfun-to-list f = remove1 a xs unfolding finfun-to-list-def proof(rule the-equality) have set (remove1 a xs) = set xs − {a} by simp also note eq also have {x. finfun-dom f (a $:= b) $ x} − {a} = {x. finfun-dom f $ x} using False by(auto simp add: finfun-upd-apply split: if-split-asm) finally show 1 : set (remove1 a xs) = {x. finfun-dom f $ x} ∧ sorted (remove1 a xs) ∧ distinct (remove1 a xs) by(simp add: sorted-remove1 ) fix xs 0 assume set xs 0 = {x. finfun-dom f $ x} ∧ sorted xs 0 ∧ distinct xs 0 thus xs 0 = remove1 a xs using 1 by(blast intro: sorted-distinct-set-unique) qed thus ?thesis using False eq hb 6= finfun-default f i by (simp add: insort-insert-insort insort-remove1 ) qed qed qed (auto simp add: distinct-finfun-to-list sorted-finfun-to-list sorted-remove1 set-insort-insert sorted-insort-insert distinct-insort-insert finfun-upd-apply split: if-split-asm) lemma finfun-to-list-update-code [code]: finfun-to-list (finfun-update-code f a b) = (if b = finfun-default f then List.remove1 a (finfun-to-list f ) else List.insort-insert a (finfun-to-list f )) by(simp add: finfun-to-list-update) More type class instantiations lemma card-eq-1-iff : card A = 1 ←→ A 6= {} ∧ (∀ x∈A. ∀ y∈A. x = y) (is ?lhs ←→ ?rhs) proof assume ?lhs moreover { fix x y 577 assume A: x ∈ A y ∈ A and neq: x 6= y have finite A using h?lhs i by(simp add: card-ge-0-finite) from neq have 2 = card {x, y} by simp also have ... ≤ card A using A hfinite Ai by(auto intro: card-mono) finally have False using h?lhs i by simp } ultimately show ?rhs by auto next assume ?rhs hence A = {THE x. x ∈ A} by safe (auto intro: theI the-equality[symmetric]) also have card ... = 1 by simp finally show ?lhs . qed lemma card-UNIV-finfun: defines F == finfun :: ( 0a ⇒ 0b) set shows CARD( 0a ⇒f 0b) = (if CARD( 0a) 6= 0 ∧ CARD( 0b) 6= 0 ∨ CARD( 0b) = 1 then CARD( 0b) ˆ CARD( 0a) else 0 ) proof(cases 0 < CARD( 0a) ∧ 0 < CARD( 0b) ∨ CARD( 0b) = 1 ) case True from True have F = UNIV proof assume b: CARD( 0b) = 1 hence ∀ x :: 0b. x = undefined by(auto simp add: card-eq-1-iff simp del: One-nat-def ) thus ?thesis by(auto simp add: finfun-def F-def intro: exI [where x=undefined]) qed(auto simp add: finfun-def card-gt-0-iff F-def intro: finite-subset[where B=UNIV ]) moreover have CARD( 0a ⇒f 0b) = card F unfolding type-definition.Abs-image[OF type-definition-finfun, symmetric] by(auto intro!: card-image inj-onI simp add: Abs-finfun-inject F-def ) ultimately show ?thesis by(simp add: card-fun) next case False hence infinite: ¬ (finite (UNIV :: 0a set) ∧ finite (UNIV :: 0b set)) and b: CARD( 0b) 6= 1 by(simp-all add: card-eq-0-iff ) from b obtain b1 b2 :: 0b where b1 6= b2 by(auto simp add: card-eq-1-iff simp del: One-nat-def ) let ?f = λa a 0 :: 0a. if a = a 0 then b1 else b2 from infinite have ¬ finite (UNIV :: ( 0a ⇒f 0b) set) proof(rule contrapos-nn[OF - conjI ]) assume finite: finite (UNIV :: ( 0a ⇒f 0b) set) hence finite F unfolding type-definition.Abs-image[OF type-definition-finfun, symmetric] F-def by(rule finite-imageD)(auto intro: inj-onI simp add: Abs-finfun-inject) hence finite (range ?f ) by(rule finite-subset[rotated 1 ])(auto simp add: F-def finfun-def hb1 6= b2 i intro!: exI [where x=b2 ]) 578 thus finite (UNIV :: 0a set) by(rule finite-imageD)(auto intro: inj-onI simp add: fun-eq-iff hb1 6= b2 i split: if-split-asm) from finite have finite (range (λb. ((K $ b) :: 0a ⇒f 0b))) by(rule finite-subset[rotated 1 ]) simp thus finite (UNIV :: 0b set) by(rule finite-imageD)(auto intro!: inj-onI ) qed with False show ?thesis by auto qed lemma finite-UNIV-finfun: finite (UNIV :: ( 0a ⇒f 0b) set) ←→ (finite (UNIV :: 0a set) ∧ finite (UNIV :: 0b set) ∨ CARD( 0b) = 1 ) (is ?lhs ←→ ?rhs) proof − have ?lhs ←→ CARD( 0a ⇒f 0b) > 0 by(simp add: card-gt-0-iff ) also have ... ←→ CARD( 0a) > 0 ∧ CARD( 0b) > 0 ∨ CARD( 0b) = 1 by(simp add: card-UNIV-finfun) also have ... = ?rhs by(simp add: card-gt-0-iff ) finally show ?thesis . qed instantiation finfun :: (finite-UNIV , card-UNIV ) finite-UNIV begin definition finite-UNIV = Phantom( 0a ⇒f 0b) (let cb = of-phantom (card-UNIV :: 0b card-UNIV ) in cb = 1 ∨ of-phantom (finite-UNIV :: 0a finite-UNIV ) ∧ cb 6= 0 ) instance by intro-classes (auto simp add: finite-UNIV-finfun-def Let-def card-UNIV finite-UNIV finite-UNIV-finfun card-gt-0-iff ) end instantiation finfun :: (card-UNIV , card-UNIV ) card-UNIV begin definition card-UNIV = Phantom( 0a ⇒f 0b) (let ca = of-phantom (card-UNIV :: 0a card-UNIV ); cb = of-phantom (card-UNIV :: 0b card-UNIV ) in if ca 6= 0 ∧ cb 6= 0 ∨ cb = 1 then cb ˆ ca else 0 ) instance by intro-classes (simp add: card-UNIV-finfun-def card-UNIV Let-def card-UNIV-finfun) end 73.18.1 Bundles for concrete syntax bundle finfun-syntax begin type-notation finfun ((- ⇒f /-)[22 , 21 ] 21 ) 579 notation finfun-const (K $/ - [0 ] 1 ) and finfun-update (- 0(- $:= - 0)[1000 , 0 , 0 ] 1000 ) and finfun-apply (infixl $ 999 ) and finfun-comp (infixr ◦$ 55 ) and finfun-comp2 (infixr $◦ 55 ) and finfun-Diag ((1 0($-,/ -$ 0)) [0 , 0 ] 1000 ) notation (ASCII ) finfun-comp (infixr o$ 55 ) and finfun-comp2 (infixr $o 55 ) end bundle no-finfun-syntax begin no-type-notation finfun ((- ⇒f /-)[22 , 21 ] 21 ) no-notation finfun-const (K $/ - [0 ] 1 ) and finfun-update (- 0(- $:= - 0)[1000 , 0 , 0 ] 1000 ) and finfun-apply (infixl $ 999 ) and finfun-comp (infixr ◦$ 55 ) and finfun-comp2 (infixr $◦ 55 ) and finfun-Diag ((1 0($-,/ -$ 0)) [0 , 0 ] 1000 ) no-notation (ASCII ) finfun-comp (infixr o$ 55 ) and finfun-comp2 (infixr $o 55 ) end unbundle no-finfun-syntax end 74 Predicates modelled as FinFuns theory FinFunPred imports ∼∼/src/HOL/Library/FinFun begin unbundle finfun-syntax Instantiate FinFun predicates just like predicates 0 0 type-synonym a pred f = a ⇒f bool 580 instantiation finfun :: (type, ord) ord begin definition le-finfun-def [code del]: f ≤ g ←→ (∀ x. f $ x ≤ g $ x) definition [code del]: (f :: 0a ⇒f 0b) < g ←→ f ≤ g ∧ ¬ g ≤ f instance .. lemma le-finfun-code [code]: f ≤ g ←→ finfun-All ((λ(x, y). x ≤ y) ◦$ ($f , g$)) by(simp add: le-finfun-def finfun-All-All o-def ) end instance finfun :: (type, preorder) preorder by(intro-classes)(auto simp add: less-finfun-def le-finfun-def intro: order-trans) instance finfun :: (type, order) order by(intro-classes)(auto simp add: le-finfun-def order-antisym-conv intro: finfun-ext) instantiation finfun :: (type, order-bot) order-bot begin definition bot = finfun-const bot instance by(intro-classes)(simp add: bot-finfun-def le-finfun-def ) end lemma bot-finfun-apply [simp]: op $ bot = (λ-. bot) by(auto simp add: bot-finfun-def ) instantiation finfun :: (type, order-top) order-top begin definition top = finfun-const top instance by(intro-classes)(simp add: top-finfun-def le-finfun-def ) end lemma top-finfun-apply [simp]: op $ top = (λ-. top) by(auto simp add: top-finfun-def ) instantiation finfun :: (type, inf ) inf begin definition [code]: inf f g = (λ(x, y). inf x y) ◦$ ($f , g$) instance .. end lemma inf-finfun-apply [simp]: op $ (inf f g) = inf (op $ f )(op $ g) by(auto simp add: inf-finfun-def o-def inf-fun-def ) instantiation finfun :: (type, sup) sup begin definition [code]: sup f g = (λ(x, y). sup x y) ◦$ ($f , g$) instance .. 581 end lemma sup-finfun-apply [simp]: op $ (sup f g) = sup (op $ f )(op $ g) by(auto simp add: sup-finfun-def o-def sup-fun-def ) instance finfun :: (type, semilattice-inf ) semilattice-inf by(intro-classes)(simp-all add: inf-finfun-def le-finfun-def ) instance finfun :: (type, semilattice-sup) semilattice-sup by(intro-classes)(simp-all add: sup-finfun-def le-finfun-def ) instance finfun :: (type, lattice) lattice .. instance finfun :: (type, bounded-lattice) bounded-lattice by(intro-classes) instance finfun :: (type, distrib-lattice) distrib-lattice by(intro-classes)(simp add: sup-finfun-def inf-finfun-def expand-finfun-eq o-def sup-inf-distrib1 ) instantiation finfun :: (type, minus) minus begin definition f − g = case-prod (op −) ◦$ ($f , g$) instance .. end lemma minus-finfun-apply [simp]: op $ (f − g) = op $ f − op $ g by(simp add: minus-finfun-def o-def fun-diff-def ) instantiation finfun :: (type, uminus) uminus begin definition − A = uminus ◦$ A instance .. end lemma uminus-finfun-apply [simp]: op $ (− g) = − op $ g by(simp add: uminus-finfun-def o-def fun-Compl-def ) instance finfun :: (type, boolean-algebra) boolean-algebra by(intro-classes) (simp-all add: uminus-finfun-def inf-finfun-def expand-finfun-eq sup-fun-def inf-fun-def fun-Compl-def o-def inf-compl-bot sup-compl-top diff-eq) Replicate predicate operations for FinFuns 0 abbreviation finfun-empty :: a pred f ({}f ) where {}f ≡ bot 0 abbreviation finfun-UNIV :: a pred f where finfun-UNIV ≡ top 0 0 definition finfun-single :: a ⇒ a pred f where [code]: finfun-single x = finfun-empty(x $:= True) 582 lemma finfun-single-apply [simp]: finfun-single x $ y ←→ x = y by(simp add: finfun-single-def finfun-upd-apply) lemma [iff ]: shows finfun-single-neq-bot: finfun-single x 6= bot and bot-neq-finfun-single: bot 6= finfun-single x by(simp-all add: expand-finfun-eq fun-eq-iff ) lemma finfun-leI [intro!]: (!!x. A $ x =⇒ B $ x) =⇒ A ≤ B by(simp add: le-finfun-def ) lemma finfun-leD [elim]: [[ A ≤ B; A $ x ]] =⇒ B $ x by(simp add: le-finfun-def ) Bounded quantification. Warning: finfun-Ball and finfun-Ex may raise an exception, they should not be used for quickcheck 0 0 0 definition finfun-Ball-except :: a list ⇒ a pred f ⇒ ( a ⇒ bool) ⇒ bool where [code del]: finfun-Ball-except xs A P = (∀ a. A $ a −→ a ∈ set xs ∨ P a) lemma finfun-Ball-except-const: finfun-Ball-except xs (K $ b) P ←→ ¬ b ∨ set xs = UNIV ∨ Code.abort (STR 00finfun-ball-except 00)(λu. finfun-Ball-except xs (K $ b) P) by(auto simp add: finfun-Ball-except-def ) lemma finfun-Ball-except-const-finfun-UNIV-code [code]: finfun-Ball-except xs (K $ b) P ←→ ¬ b ∨ is-list-UNIV xs ∨ Code.abort (STR 00finfun-ball-except 00)(λu. finfun-Ball-except xs (K $ b) P) by(auto simp add: finfun-Ball-except-def is-list-UNIV-iff ) lemma finfun-Ball-except-update: finfun-Ball-except xs (A(a $:= b)) P = ((a ∈ set xs ∨ (b −→ P a)) ∧ finfun-Ball-except (a # xs) AP) by(fastforce simp add: finfun-Ball-except-def finfun-upd-apply split: if-split-asm) lemma finfun-Ball-except-update-code [code]: fixes a :: 0a :: card-UNIV shows finfun-Ball-except xs (finfun-update-code f a b) P = ((a ∈ set xs ∨ (b −→ P a)) ∧ finfun-Ball-except (a # xs) f P) by(simp add: finfun-Ball-except-update) 0 0 definition finfun-Ball :: a pred f ⇒ ( a ⇒ bool) ⇒ bool where [code del]: finfun-Ball A P = Ball {x. A $ x} P lemma finfun-Ball-code [code]: finfun-Ball = finfun-Ball-except [] by(auto intro!: ext simp add: finfun-Ball-except-def finfun-Ball-def ) 583 0 0 0 definition finfun-Bex-except :: a list ⇒ a pred f ⇒ ( a ⇒ bool) ⇒ bool where [code del]: finfun-Bex-except xs A P = (∃ a. A $ a ∧ a ∈/ set xs ∧ P a) lemma finfun-Bex-except-const: finfun-Bex-except xs (K $ b) P ←→ b ∧ set xs 6= UNIV ∧ Code.abort (STR 00finfun-Bex-except 00)(λu. finfun-Bex-except xs (K $ b) P) by(auto simp add: finfun-Bex-except-def ) lemma finfun-Bex-except-const-finfun-UNIV-code [code]: finfun-Bex-except xs (K $ b) P ←→ b ∧ ¬ is-list-UNIV xs ∧ Code.abort (STR 00finfun-Bex-except 00)(λu. finfun-Bex-except xs (K $ b) P) by(auto simp add: finfun-Bex-except-def is-list-UNIV-iff ) lemma finfun-Bex-except-update: finfun-Bex-except xs (A(a $:= b)) P ←→ (a ∈/ set xs ∧ b ∧ P a) ∨ finfun-Bex-except (a # xs) AP by(fastforce simp add: finfun-Bex-except-def finfun-upd-apply dest: bspec split: if-split-asm) lemma finfun-Bex-except-update-code [code]: fixes a :: 0a :: card-UNIV shows finfun-Bex-except xs (finfun-update-code f a b) P ←→ ((a ∈/ set xs ∧ b ∧ P a) ∨ finfun-Bex-except (a # xs) f P) by(simp add: finfun-Bex-except-update) 0 0 definition finfun-Bex :: a pred f ⇒ ( a ⇒ bool) ⇒ bool where [code del]: finfun-Bex A P = Bex {x. A $ x} P lemma finfun-Bex-code [code]: finfun-Bex = finfun-Bex-except [] by(auto intro!: ext simp add: finfun-Bex-except-def finfun-Bex-def ) Automatically replace predicate operations by finfun predicate operations where possible lemma iso-finfun-le [code-unfold]: op $ A ≤ op $ B ←→ A ≤ B by (metis le-finfun-def le-funD le-funI ) lemma iso-finfun-less [code-unfold]: op $ A < op $ B ←→ A < B by (metis iso-finfun-le less-finfun-def less-fun-def ) lemma iso-finfun-eq [code-unfold]: op $ A = op $ B ←→ A = B by(simp only: expand-finfun-eq) lemma iso-finfun-sup [code-unfold]: sup (op $ A)(op $ B) = op $ (sup A B) by(simp) lemma iso-finfun-disj [code-unfold]: 584 A $ x ∨ B $ x ←→ sup A B $ x by(simp add: sup-fun-def ) lemma iso-finfun-inf [code-unfold]: inf (op $ A)(op $ B) = op $ (inf A B) by(simp) lemma iso-finfun-conj [code-unfold]: A $ x ∧ B $ x ←→ inf A B $ x by(simp add: inf-fun-def ) lemma iso-finfun-empty-conv [code-unfold]: (λ-. False) = op $ {}f by simp lemma iso-finfun-UNIV-conv [code-unfold]: (λ-. True) = op $ finfun-UNIV by simp lemma iso-finfun-upd [code-unfold]: 0 fixes A :: a pred f shows (op $ A)(x := b) = op $ (A(x $:= b)) by(simp add: fun-eq-iff ) lemma iso-finfun-uminus [code-unfold]: 0 fixes A :: a pred f shows − op $ A = op $ (− A) by(simp) lemma iso-finfun-minus [code-unfold]: 0 fixes A :: a pred f shows op $ A − op $ B = op $ (A − B) by(simp) Do not declare the following two theorems as [code-unfold], because this causes quickcheck to fail frequently when bounded quantification is used which raises an exception. For code generation, the same problems occur, but then, no randomly generated FinFun is usually around. lemma iso-finfun-Ball-Ball: (∀ x. A $ x −→ P x) ←→ finfun-Ball A P by(simp add: finfun-Ball-def ) lemma iso-finfun-Bex-Bex: (∃ x. A $ x ∧ P x) ←→ finfun-Bex A P by(simp add: finfun-Bex-def ) Test code setup notepad begin have inf ((λ- :: nat. False)(1 := True, 2 := True)) ((λ-. True)(3 := False)) ≤ 585 sup ((λ-. False)(1 := True, 5 := True)) (− ((λ-. True)(2 := False, 3 := False))) by eval end declare iso-finfun-Ball-Ball[code-unfold] notepad begin have (∀ x. ((λ- :: nat. False)(1 := True, 2 := True)) x −→ x < 3 ) by eval end declare iso-finfun-Ball-Ball[code-unfold del] end 75 Examples for the set comprehension to point- free simproc theory Set-Comprehension-Pointfree-Examples imports Main begin declare [[simproc add: finite-Collect]] lemma finite (UNIV :: 0a set) ==> finite {p. EX x:: 0a. p = (x, x)} by simp lemma finite A ==> finite B ==> finite {f a b| a b. a : A ∧ b : B} by simp lemma finite B ==> finite A 0 ==> finite {f a b| a b. a : A ∧ a : A 0 ∧ b : B} by simp lemma finite A ==> finite B ==> finite {f a b| a b. a : A ∧ b : B ∧ b : B 0} by simp lemma finite A ==> finite B ==> finite C ==> finite {f a b c| a b c. a : A ∧ b : B ∧ c : C } by simp lemma finite A ==> finite B ==> finite C ==> finite D ==> finite {f a b c d| a b c d. a : A ∧ b : B ∧ c : C ∧ d : D} by simp 586 lemma finite A ==> finite B ==> finite C ==> finite D ==> finite E ==> finite {f a b c d e | a b c d e. a : A ∧ b : B ∧ c : C ∧ d : D ∧ e : E} by simp lemma finite A ==> finite B ==> finite C ==> finite D ==> finite E =⇒ finite {f a d c b e | e b c d a. b : B ∧ a : A ∧ e : E 0 ∧ c : C ∧ d : D ∧ e : E ∧ b : B 0} by simp lemma [[ finite A ; finite B ; finite C ; finite D ]] =⇒ finite ({f a b c d| a b c d. a : A ∧ b : B ∧ c : C ∧ d : D}) by simp lemma finite ((λ(a,b,c,d). f a b c d) ‘ (A × B × C × D)) =⇒ finite ({f a b c d| a b c d. a : A ∧ b : B ∧ c : C ∧ d : D}) by simp lemma finite S ==> finite {s 0. EX s:S. s 0 = f a e s} by simp lemma finite A ==> finite B ==> finite {f a b| a b. a : A ∧ b : B ∧ a ∈/ Z } by simp lemma finite A ==> finite B ==> finite R ==> finite {f a b x y| a b x y. a : A ∧ b : B ∧ (x,y) ∈ R} by simp lemma finite A ==> finite B ==> finite R ==> finite {f a b x y| a b x y. a : A ∧ (x,y) ∈ R ∧ b : B} by simp lemma finite A ==> finite B ==> finite R ==> finite {f a (x, b) y| y b x a. a : A ∧ (x,y) ∈ R ∧ b : B} by simp lemma finite A ==> finite AA ==> finite B ==> finite {f a b| a b. (a : A ∨ a : AA) ∧ b : B ∧ a ∈/ Z } by simp 587 lemma finite A1 ==> finite A2 ==> finite A3 ==> finite A4 ==> finite A5 ==> finite B ==> finite {f a b c | a b c. ((a : A1 ∧ a : A2 ) ∨ (a : A3 ∧ (a : A4 ∨ a : A5 ))) ∧ b : B ∧ a ∈/ Z } apply simp oops lemma finite B ==> finite {c. EX x. x : B & c = a ∗ x} by simp lemma finite A ==> finite B ==> finite {f a ∗ g b |a b. a : A & b : B} by simp lemma finite S ==> inj (%(x, y). g x y) ==> finite {f x y| x y. g x y : S} by (auto intro: finite-vimageI ) lemma finite A ==> finite S ==> inj (%(x, y). g x y) ==> finite {f x y z | x y z. g x y : S & z : A} by (auto intro: finite-vimageI ) lemma finite S ==> finite A ==> inj (%(x, y). g x y) ==> inj (%(x, y). h x y) ==> finite {f a b c d | a b c d. g a c : S & h b d : A} by (auto intro: finite-vimageI ) lemma assumes finite S shows finite {(a,b,c,d). ([a, b], [c, d]) : S} using assms by (auto intro!: finite-vimageI simp add: inj-on-def ) schematic-goal finite {x :: ? 0A ⇒ ? 0B ⇒ bool. ∃ a b. x = Pair-Rep a b} = finite ((λ(b :: ? 0B, a:: ? 0A). Pair-Rep a b) ‘ (UNIV × UNIV )) by simp declare [[simproc del: finite-Collect]] 76 Testing simproc in code generation definition union :: nat set => nat set => nat set where union A B = {x. x : A ∨ x : B} definition common-subsets :: nat set => nat set => nat set set 588 where common-subsets S1 S2 = {S. S ⊆ S1 ∧ S ⊆ S2 } definition products :: nat set => nat set => nat set where products A B = {c. EX a b. a : A & b : B & c = a ∗ b} export-code products in Haskell export-code union common-subsets products in Haskell end 77 Futures and parallel lists for code generated towards Isabelle/ML theory Parallel imports Main begin 77.1 Futures datatype 0a future = fork unit ⇒ 0a primrec join :: 0a future ⇒ 0a where join (fork f ) = f () lemma future-eqI [intro!]: assumes join f = join g shows f = g using assms by (cases f , cases g)(simp add: ext) code-printing type-constructor future * (Eval) - future | constant fork * (Eval) Future.fork | constant join * (Eval) Future.join code-reserved Eval Future future 77.2 Parallel lists definition map :: ( 0a ⇒ 0b) ⇒ 0a list ⇒ 0b list where [simp]: map = List.map definition forall :: ( 0a ⇒ bool) ⇒ 0a list ⇒ bool where forall = list-all lemma forall-all [simp]: forall P xs ←→ (∀ x∈set xs. P x) 589 by (simp add: forall-def list-all-iff ) definition exists :: ( 0a ⇒ bool) ⇒ 0a list ⇒ bool where exists = list-ex lemma exists-ex [simp]: exists P xs ←→ (∃ x∈set xs. P x) by (simp add: exists-def list-ex-iff ) code-printing constant map * (Eval) Par 0-List.map | constant forall * (Eval) Par 0-List.forall | constant exists * (Eval) Par 0-List.exists code-reserved Eval Par-List hide-const (open) fork join map exists forall end 78 Debugging facilities for code generated towards Isabelle/ML theory Debug imports Main begin context begin qualified definition trace :: String.literal ⇒ unit where [simp]: trace s = () qualified definition tracing :: String.literal ⇒ 0a ⇒ 0a where [simp]: tracing s = id lemma [code]: tracing s = (let u = trace s in id) by simp qualified definition flush :: 0a ⇒ unit where [simp]: flush x = () qualified definition flushing :: 0a ⇒ 0b ⇒ 0b where [simp]: flushing x = id lemma [code, code-unfold]: 590 flushing x = (let u = flush x in id) by simp qualified definition timing :: String.literal ⇒ ( 0a ⇒ 0b) ⇒ 0a ⇒ 0b where [simp]: timing s f x = f x end code-printing constant Debug.trace * (Eval) Output.tracing | constant Debug.flush * (Eval) Output.tracing/ (@{make 0-string} -) — note indirection via antiquotation | constant Debug.timing * (Eval) Timing.timeap 0-msg code-reserved Eval Output Timing end 79 A simple example demonstrating parallelism for code generated towards Isabelle/ML theory Parallel-Example imports Complex-Main ∼∼/src/HOL/Library/Parallel ∼∼/src/HOL/Library/Debug begin 79.1 Compute-intensive examples. 79.1.1 Fragments of the harmonic series definition harmonic :: nat ⇒ rat where harmonic n = sum-list (map (λn. 1 / of-nat n)[1 .. 79.1.2 The sieve of Erathostenes The attentive reader may relate this ad-hoc implementation to the arith- metic notion of prime numbers as a little exercise. primrec mark :: nat ⇒ nat ⇒ bool list ⇒ bool list where mark - - [] = [] | mark m n (p # ps) = (case n of 0 ⇒ False # mark m m ps | Suc n ⇒ p # mark m n ps) lemma length-mark [simp]: length (mark m n ps) = length ps by (induct ps arbitrary: n)(simp-all split: nat.split) function sieve :: nat ⇒ bool list ⇒ bool list where sieve m ps = (case dropWhile Not ps of [] ⇒ ps 591 | p#ps 0 ⇒ let n = m − length ps 0 in takeWhile Not ps @ p # sieve m (mark n n ps 0)) by pat-completeness auto termination — tuning of this proof is left as an exercise to the reader apply (relation measure (length ◦ snd)) apply rule apply (auto simp add: length-dropWhile-le) proof − fix ps qs q assume dropWhile Not ps = q # qs then have length (q # qs) = length (dropWhile Not ps) by simp then have length qs < length (dropWhile Not ps) by simp moreover have length (dropWhile Not ps) ≤ length ps by (simp add: length-dropWhile-le) ultimately show length qs < length ps by auto qed primrec natify :: nat ⇒ bool list ⇒ nat list where natify - [] = [] | natify n (p#ps) = (if p then n # natify (Suc n) ps else natify (Suc n) ps) primrec list-primes where list-primes (Suc n) = natify 1 (sieve n (False # replicate n True)) 79.1.3 Naive factorisation function factorise-from :: nat ⇒ nat ⇒ nat list where factorise-from k n = (if 1 < k ∧ k ≤ n then let (q, r) = Divides.divmod-nat n k in if r = 0 then k # factorise-from k q else factorise-from (Suc k) n else []) by pat-completeness auto termination factorise-from — tuning of this proof is left as an exercise to the reader term measure apply (relation measure (λ(k, n). 2 ∗ n − k)) apply (auto simp add: prod-eq-iff ) apply (case-tac k ≤ 2 ∗ q) apply (rule diff-less-mono) apply auto done definition factorise :: nat ⇒ nat list where factorise n = factorise-from 2 n 592 79.2 Concurrent computation via futures definition computation-harmonic :: unit ⇒ rat where computation-harmonic - = Debug.timing (STR 00harmonic example 00) harmonic 300 definition computation-primes :: unit ⇒ nat list where computation-primes - = Debug.timing (STR 00primes example 00) list-primes 4000 definition computation-future :: unit ⇒ nat list × rat where computation-future = Debug.timing (STR 00overall computation 00) (λ() ⇒ let c = Parallel.fork computation-harmonic in (computation-primes (), Parallel.join c)) value computation-future () definition computation-factorise :: nat ⇒ nat list where computation-factorise = Debug.timing (STR 00factorise 00) factorise definition computation-parallel :: unit ⇒ nat list list where computation-parallel - = Debug.timing (STR 00overall computation 00) (Parallel.map computation-factorise)[20000 ..<20100 ] value computation-parallel () end 80 Immutable Arrays with Code Generation theory IArray imports Main begin Immutable arrays are lists wrapped up in an additional constructor. There are no update operations. Hence code generation can safely implement this type by efficient target language arrays. Currently only SML is provided. Should be extended to other target languages and more operations. Note that arrays cannot be printed directly but only by turning them into lists first. Arrays could be converted back into lists for printing if they were wrapped up in an additional constructor. context begin datatype 0a iarray = IArray 0a list qualified primrec list-of :: 0a iarray ⇒ 0a list where list-of (IArray xs) = xs 593 qualified definition of-fun :: (nat ⇒ 0a) ⇒ nat ⇒ 0a iarray where [simp]: of-fun f n = IArray (map f [0 .. 80.1 Code Generation code-reserved SML Vector code-printing type-constructor iarray * (SML) - Vector.vector | constant IArray * (SML) Vector.fromList | constant IArray.all * (SML) Vector.all | constant IArray.exists * (SML) Vector.exists lemma [code]: size (as :: 0a iarray) = Suc (length (IArray.list-of as)) by (cases as) simp lemma [code]: size-iarray f as = Suc (size-list f (IArray.list-of as)) by (cases as) simp lemma [code]: rec-iarray f as = f (IArray.list-of as) by (cases as) simp lemma [code]: case-iarray f as = f (IArray.list-of as) by (cases as) simp lemma [code]: set-iarray as = set (IArray.list-of as) 594 by (cases as) auto lemma [code]: map-iarray f as = IArray (map f (IArray.list-of as)) by (cases as) auto lemma [code]: rel-iarray r as bs = list-all2 r (IArray.list-of as)(IArray.list-of bs) by (cases as, cases bs) auto lemma [code]: HOL.equal as bs ←→ HOL.equal (IArray.list-of as)(IArray.list-of bs) by (cases as, cases bs)(simp add: equal) context begin qualified primrec tabulate :: integer × (integer ⇒ 0a) ⇒ 0a iarray where tabulate (n, f ) = IArray (map (f ◦ integer-of-nat)[0 .. 595 begin qualified definition length 0 :: 0a iarray ⇒ integer where [code del, simp]: length 0 as = integer-of-nat (List.length (IArray.list-of as)) end lemma [code]: IArray.length 0 (IArray as) = integer-of-nat (List.length as) by simp lemma [code]: IArray.length as = nat-of-integer (IArray.length 0 as) by simp context term-syntax begin lemma [code]: Code-Evaluation.term-of (as :: 0a::typerep iarray) = Code-Evaluation.Const (STR 00IArray.iarray.IArray 00)(TYPEREP( 0a list ⇒ 0a iarray)) <·> (Code-Evaluation.term-of (IArray.list-of as)) by (subst term-of-anything) rule end code-printing constant IArray.length 0 * (SML) Vector.length end 81 Implementation of integer numbers by target- language integers theory Code-Target-Int imports ../GCD begin code-datatype int-of-integer declare [[code drop: integer-of-int]] context includes integer.lifting begin lemma [code]: integer-of-int (int-of-integer k) = k 596 by transfer rule lemma [code]: Int.Pos = int-of-integer ◦ integer-of-num by transfer (simp add: fun-eq-iff ) lemma [code]: Int.Neg = int-of-integer ◦ uminus ◦ integer-of-num by transfer (simp add: fun-eq-iff ) lemma [code-abbrev]: int-of-integer (numeral k) = Int.Pos k by transfer simp lemma [code-abbrev]: int-of-integer (− numeral k) = Int.Neg k by transfer simp lemma [code, symmetric, code-post]: 0 = int-of-integer 0 by transfer simp lemma [code, symmetric, code-post]: 1 = int-of-integer 1 by transfer simp lemma [code-post]: int-of-integer (− 1 ) = − 1 by simp lemma [code]: k + l = int-of-integer (of-int k + of-int l) by transfer simp lemma [code]: − k = int-of-integer (− of-int k) by transfer simp lemma [code]: k − l = int-of-integer (of-int k − of-int l) by transfer simp lemma [code]: Int.dup k = int-of-integer (Code-Numeral.dup (of-int k)) by transfer simp declare [[code drop: Int.sub]] lemma [code]: 597 k ∗ l = int-of-integer (of-int k ∗ of-int l) by simp lemma [code]: k div l = int-of-integer (of-int k div of-int l) by simp lemma [code]: k mod l = int-of-integer (of-int k mod of-int l) by simp lemma [code]: divmod m n = map-prod int-of-integer int-of-integer (divmod m n) unfolding prod-eq-iff divmod-def map-prod-def case-prod-beta fst-conv snd-conv by transfer simp lemma [code]: HOL.equal k l = HOL.equal (of-int k :: integer)(of-int l) by transfer (simp add: equal) lemma [code]: k ≤ l ←→ (of-int k :: integer) ≤ of-int l by transfer rule lemma [code]: k < l ←→ (of-int k :: integer) < of-int l by transfer rule declare [[code drop: gcd :: int ⇒ - lcm :: int ⇒ -]] lemma gcd-int-of-integer [code]: gcd (int-of-integer x)(int-of-integer y) = int-of-integer (gcd x y) by transfer rule lemma lcm-int-of-integer [code]: lcm (int-of-integer x)(int-of-integer y) = int-of-integer (lcm x y) by transfer rule end lemma (in ring-1 ) of-int-code-if : of-int k = (if k = 0 then 0 else if k < 0 then − of-int (− k) else let l = 2 ∗ of-int (k div 2 ); j = k mod 2 in if j = 0 then l else l + 1 ) proof − from div-mult-mod-eq have ∗: of-int k = of-int (k div 2 ∗ 2 + k mod 2 ) by 598 simp show ?thesis by (simp add: Let-def of-int-add [symmetric]) (simp add: ∗ mult.commute) qed declare of-int-code-if [code] lemma [code]: nat = nat-of-integer ◦ of-int including integer.lifting by transfer (simp add: fun-eq-iff ) code-identifier code-module Code-Target-Int * (SML) Arith and (OCaml) Arith and (Haskell) Arith end 82 Implementation of natural numbers by target- language integers theory Code-Target-Nat imports Code-Abstract-Nat begin 82.1 Implementation for nat context includes natural.lifting integer.lifting begin lift-definition Nat :: integer ⇒ nat is nat . lemma [code-post]: Nat 0 = 0 Nat 1 = 1 Nat (numeral k) = numeral k by (transfer, simp)+ lemma [code-abbrev]: integer-of-nat = of-nat by transfer rule lemma [code-unfold]: Int.nat (int-of-integer k) = nat-of-integer k by transfer rule 599 lemma [code abstype]: Code-Target-Nat.Nat (integer-of-nat n) = n by transfer simp lemma [code abstract]: integer-of-nat (nat-of-integer k) = max 0 k by transfer auto lemma [code-abbrev]: nat-of-integer (numeral k) = nat-of-num k by transfer (simp add: nat-of-num-numeral) lemma [code abstract]: integer-of-nat (nat-of-num n) = integer-of-num n by transfer (simp add: nat-of-num-numeral) lemma [code abstract]: integer-of-nat 0 = 0 by transfer simp lemma [code abstract]: integer-of-nat 1 = 1 by transfer simp lemma [code]: Suc n = n + 1 by simp lemma [code abstract]: integer-of-nat (m + n) = of-nat m + of-nat n by transfer simp lemma [code abstract]: integer-of-nat (m − n) = max 0 (of-nat m − of-nat n) by transfer simp lemma [code abstract]: integer-of-nat (m ∗ n) = of-nat m ∗ of-nat n by transfer (simp add: of-nat-mult) lemma [code abstract]: integer-of-nat (m div n) = of-nat m div of-nat n by transfer (simp add: zdiv-int) lemma [code abstract]: integer-of-nat (m mod n) = of-nat m mod of-nat n by transfer (simp add: zmod-int) lemma [code]: 600 Divides.divmod-nat m n = (m div n, m mod n) by (fact divmod-nat-div-mod) lemma [code]: divmod m n = map-prod nat-of-integer nat-of-integer (divmod m n) by (simp only: prod-eq-iff divmod-def map-prod-def case-prod-beta fst-conv snd-conv) (transfer, simp-all only: nat-div-distrib nat-mod-distrib zero-le-numeral nat-numeral) lemma [code]: HOL.equal m n = HOL.equal (of-nat m :: integer)(of-nat n) by transfer (simp add: equal) lemma [code]: m ≤ n ←→ (of-nat m :: integer) ≤ of-nat n by simp lemma [code]: m < n ←→ (of-nat m :: integer) < of-nat n by simp lemma num-of-nat-code [code]: num-of-nat = num-of-integer ◦ of-nat by transfer (simp add: fun-eq-iff ) end lemma (in semiring-1 ) of-nat-code-if : of-nat n = (if n = 0 then 0 else let (m, q) = Divides.divmod-nat n 2 ; m 0 = 2 ∗ of-nat m in if q = 0 then m 0 else m 0 + 1 ) proof − from div-mult-mod-eq have ∗: of-nat n = of-nat (n div 2 ∗ 2 + n mod 2 ) by simp show ?thesis by (simp add: Let-def divmod-nat-div-mod of-nat-add [symmetric]) (simp add: ∗ mult.commute of-nat-mult add.commute) qed declare of-nat-code-if [code] definition int-of-nat :: nat ⇒ int where [code-abbrev]: int-of-nat = of-nat lemma [code]: int-of-nat n = int-of-integer (of-nat n) by (simp add: int-of-nat-def ) 601 lemma [code abstract]: integer-of-nat (nat k) = max 0 (integer-of-int k) including integer.lifting by transfer auto lemma term-of-nat-code [code]: — Use nat-of-integer in term reconstruction instead of Code-Target-Nat.Nat such that reconstructed terms can be fed back to the code generator term-of-class.term-of n = Code-Evaluation.App (Code-Evaluation.Const (STR 00Code-Numeral.nat-of-integer 00) (typerep.Typerep (STR 00fun 00) [typerep.Typerep (STR 00Code-Numeral.integer 00) [], typerep.Typerep (STR 00Nat.nat 00) []])) (term-of-class.term-of (integer-of-nat n)) by (simp add: term-of-anything) lemma nat-of-integer-code-post [code-post]: nat-of-integer 0 = 0 nat-of-integer 1 = 1 nat-of-integer (numeral k) = numeral k including integer.lifting by (transfer, simp)+ code-identifier code-module Code-Target-Nat * (SML) Arith and (OCaml) Arith and (Haskell) Arith end 83 Implementation of natural and integer num- bers by target-language integers theory Code-Target-Numeral imports Code-Target-Int Code-Target-Nat begin end theory IArray-Examples imports ∼∼/src/HOL/Library/IArray ∼∼/src/HOL/Library/Code-Target-Numeral begin lemma IArray [True,False] !! 1 = False by eval lemma IArray.length (IArray [[],[]]) = 2 by eval lemma IArray.list-of (IArray [1 ,3 ::int]) = [1 ,3 ] 602 by eval lemma IArray.list-of (IArray.of-fun (%n. n∗n) 5 ) = [0 ,1 ,4 ,9 ,16 ] by eval lemma ¬ IArray.all (λx. x > 2 )(IArray [1 ,3 ::int]) by eval lemma IArray.exists (λx. x > 2 )(IArray [1 ,3 ::int]) by eval fun sum2 :: 0a::monoid-add iarray ⇒ nat ⇒ 0a ⇒ 0a where sum2 A n s = (if n=0 then s else sum2 A (n − 1 )(s + A!!(n − 1 ))) definition sum :: 0a::monoid-add iarray ⇒ 0a where sum A = sum2 A (IArray.length A) 0 lemma sum (IArray [1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ::int]) = 45 by eval end theory Simps-Case-Conv imports Main keywords simps-of-case case-of-simps :: thy-decl abbrevs simps-of-case = case-of-simps = begin ML-file simps-case-conv.ML end theory Simps-Case-Conv-Examples imports ∼∼/src/HOL/Library/Simps-Case-Conv begin 84 Tests for the Simps¡-¿Case conversion tools fun foo where foo (x # xs) Nil = 0 | foo (x # xs)(y # ys) = foo [] [] | foo Nil (y # ys) = 1 | foo Nil Nil = 3 fun bar where bar x 0 y = 0 + x | 603 bar x (Suc n) y = n + x definition split-rule-test :: ((nat => 0a) + ( 0b ∗ (( 0b => 0a) option))) => ( 0a => nat) => nat where split-rule-test x f = f (case x of Inl af ⇒ af 1 | Inr (b, None) => inv f 0 | Inr (b, Some g) => g b) definition test where test x y = (case x of None => (case y of [] => 1 | - # - => 2 ) | Some x => x) definition nosplit where nosplit x = x @(case x of [] ⇒ [1 ] | xs ⇒ xs) Function with complete, non-overlapping patterns case-of-simps foo-cases1 : foo.simps lemma fixes xs :: 0a list and ys :: 0b list shows foo xs ys = (case (xs, ys) of ( [], []) ⇒ 3 | ([], y # ys) ⇒ 1 | (x # xs, []) ⇒ 0 | (x # xs, y # ys) ⇒ foo ([] :: 0a list) ([] :: 0b list)) by (fact foo-cases1 ) Redundant equations are ignored case-of-simps foo-cases2 : foo.simps foo.simps lemma fixes xs :: 0a list and ys :: 0b list shows foo xs ys = (case (xs, ys) of ( [], []) ⇒ 3 | ([], y # ys) ⇒ 1 | (x # xs, []) ⇒ 0 | (x # xs, y # ys) ⇒ foo ([] :: 0a list) ([] :: 0b list)) by (fact foo-cases2 ) Variable patterns case-of-simps bar-cases: bar.simps print-theorems Case expression not at top level simps-of-case split-rule-test-simps: split-rule-test-def lemma split-rule-test (Inl x) f = f (x 1 ) split-rule-test (Inr (x, None)) f = f (inv f 0 ) split-rule-test (Inr (x, Some y)) f = f (y x) by (fact split-rule-test-simps)+ 604 Argument occurs both as case parameter and seperately simps-of-case nosplit-simps1 : nosplit-def lemma nosplit [] = [] @ [1 ] nosplit (x # xs) = (x # xs)@ x # xs by (fact nosplit-simps1 )+ Nested case expressions simps-of-case test-simps1 : test-def lemma test None [] = 1 test None (x # xs) = 2 test (Some x) y = x by (fact test-simps1 )+ Single-constructor patterns case-of-simps fst-conv-simps: fst-conv lemma fst x = (case x of (a,b) ⇒ a) by (fact fst-conv-simps) Partial split of case simps-of-case nosplit-simps2 : nosplit-def (splits: list.split) lemma nosplit [] = [] @ [1 ] nosplit (x # xs) = (x # xs)@ x # xs by (fact nosplit-simps1 )+ simps-of-case test-simps2 : test-def (splits: option.split) lemma test None y = (case y of [] ⇒ 1 | x # xs ⇒ 2 ) test (Some x) y = x by (fact test-simps2 )+ Reversal case-of-simps test-def1 : test-simps1 lemma test x y = (case (x,y) of (None, []) ⇒ 1 | (None, -#-) ⇒ 2 | (Some x, -) ⇒ x) by (fact test-def1 ) Case expressions on RHS case-of-simps test-def2 : test-simps2 lemma test xs y = (case (xs, y) of (None, []) ⇒ 1 | (None, x # xa) ⇒ 2 | (Some x, y) ⇒ x) by (fact test-def2 ) 605 Partial split of simps case-of-simps foo-cons-def : foo.simps(1 ,2 ) lemma fixes xs :: 0a list and ys :: 0b list shows foo (x # xs) ys = (case (x,xs,ys) of (-,-,[]) ⇒ 0 | (-,-,- # -) ⇒ foo ([] :: 0a list) ([] :: 0b list)) by (fact foo-cons-def ) end 85 Isabelle/ML basics theory ML imports Main begin 86 ML expressions The Isabelle command ML allows to embed Isabelle/ML source into the formal text. It is type-checked, compiled, and run within that environment. Note that side-effects should be avoided, unless the intention is to change global parameters of the run-time environment (rare). ML top-level bindings are managed within the theory context. ML h1 + 1 i ML hval a = 1 i ML hval b = 1 i ML hval c = a + bi 87 Antiquotations There are some language extensions (via antiquotations), as explained in the “Isabelle/Isar implementation manual”, chapter 0. ML hlength []i ML h@{assert} (length [] = 0 )i Formal entities from the surrounding context may be referenced as follows: term 1 + 1 — term within theory source ML h@{term 1 + 1 } (∗ term as symbolic ML datatype value ∗)i ML h@{term 1 + (1 ::int)}i 606 ML h (∗ formal source with position information ∗) val s = h1 + 1 i; (∗ read term via old−style string interface ∗) val t = Syntax.read-term @{context} (Syntax.implode-input s); i 88 Recursive ML evaluation ML h ML hML hval a = @{thm refl}ii; ML hval b = @{thm sym}i; val c = @{thm trans} val thms = [a, b, c]; i 89 IDE support ML embedded into the Isabelle environment is connected to the Prover IDE. Poly/ML provides: • precise positions for warnings / errors • markup for defining positions of identifiers • markup for inferred types of sub-expressions • pretty-printing of ML values with markup • completion of ML names • source-level debugger ML hfn i => fn list => length list + i i 90 Example: factorial and ackermann function in Isabelle/ML ML h fun factorial 0 = 1 | factorial n = n ∗ factorial (n − 1 ) i ML hfactorial 42 i ML hfactorial 10000 div factorial 9999 i 607 See http://mathworld.wolfram.com/AckermannFunction.html. ML h fun ackermann 0 n = n + 1 | ackermann m 0 = ackermann (m − 1 ) 1 | ackermann m n = ackermann (m − 1 )(ackermann m (n − 1 )) i ML htimeit (fn () => ackermann 3 10 )i 91 Parallel Isabelle/ML Future.fork/join/cancel manage parallel evaluation. Note that within Isabelle theory documents, the top-level command bound- ary may not be transgressed without special precautions. This is normally managed by the system when performing parallel proof checking. ML h val x = Future.fork (fn () => ackermann 3 10 ); val y = Future.fork (fn () => ackermann 3 10 ); val z = Future.join x + Future.join y i The Par_List module provides high-level combinators for parallel list oper- ations. ML htimeit (fn () => map (fn n => ackermann 3 n)(1 upto 10 ))i ML htimeit (fn () => Par-List.map (fn n => ackermann 3 n)(1 upto 10 ))i 92 Function specifications in Isabelle/HOL fun factorial :: nat ⇒ nat where factorial 0 = 1 | factorial (Suc n) = Suc n ∗ factorial n term factorial 4 — symbolic term value factorial 4 — evaluation via ML code generation in the background declare [[ML-source-trace]] ML h@{term factorial 4 }i — symbolic term in ML ML h@{code factorial}i — ML code from function specification fun ackermann :: nat ⇒ nat ⇒ nat where ackermann 0 n = n + 1 | ackermann (Suc m) 0 = ackermann m 1 | ackermann (Suc m)(Suc n) = ackermann m (ackermann (Suc m) n) 608 value ackermann 3 5 end theory Rewrite imports Main begin consts rewrite-HOLE :: 0a::{} ( ) ◊ lemma eta-expand: fixes f :: 0a::{} ⇒ 0b::{} shows f ≡ λx. f x . lemma rewr-imp: assumes PROP A ≡ PROP B shows (PROP A =⇒ PROP C ) ≡ (PROP B =⇒ PROP C ) apply (rule Pure.equal-intr-rule) apply (drule equal-elim-rule2 [OF assms]; assumption) apply (drule equal-elim-rule1 [OF assms]; assumption) done lemma imp-cong-eq: (PROP A =⇒ (PROP B =⇒ PROP C ) ≡ (PROP B 0 =⇒ PROP C 0)) ≡ ((PROP B =⇒ PROP A =⇒ PROP C ) ≡ (PROP B 0 =⇒ PROP A =⇒ PROP C 0)) apply (intro Pure.equal-intr-rule) apply (drule (1 ) cut-rl; drule Pure.equal-elim-rule1 Pure.equal-elim-rule2 ; assumption)+ apply (drule Pure.equal-elim-rule1 Pure.equal-elim-rule2 ; assumption)+ done ML-file cconv.ML ML-file rewrite.ML end theory Rewrite-Examples imports Main ∼∼/src/HOL/Library/Rewrite begin 93 The rewrite Proof Method by Example lemma fixes a::int and b::int and c::int assumes P (b + a) shows P (a + b) by (rewrite at a + b add.commute) 609 (rule assms) lemma fixes a b c :: int assumes f (a − a + (a − a)) + f ( 0 + c) = f 0 + f c shows f (a − a + (a − a)) + f ((a − a) + c) = f 0 + f c by (rewrite in f - + f = - diff-self ) fact ◊ lemma fixes a b c :: int assumes f (a − a + 0 ) + f ((a − a) + c) = f 0 + f c shows f (a − a + (a − a)) + f ((a − a) + c) = f 0 + f c by (rewrite at f (- + ) + f - = - diff-self ) fact ◊ lemma fixes a b c :: int assumes f ( 0 + (a − a)) + f ((a − a) + c) = f 0 + f c shows f (a − a + (a − a)) + f ((a − a) + c) = f 0 + f c by (rewrite in f ( + -) + - = - diff-self ) fact ◊ lemma fixes a b c :: int assumes f (a − a + 0 ) + f ((a − a) + c) = f 0 + f c shows f (a − a + (a − a)) + f ((a − a) + c) = f 0 + f c by (rewrite in f (- + ) + - = - diff-self ) fact ◊ lemma fixes x y :: nat showsx + y > c =⇒ y + x > c by (rewrite at > c add.commute) assumption ◊ lemma fixes x y :: nat assumes y + x > c =⇒ y + x > c shows x + y > c =⇒ y + x > c by (rewrite in asm add.commute) fact lemma fixes x y :: nat assumes y + x > c =⇒ y + x > c shows x + y > c =⇒ y + x > c by (rewrite in x + y > c at asm add.commute) fact lemma fixes x y :: nat assumes y + x > c =⇒ y + x > c shows x + y > c =⇒ y + x > c 610 by (rewrite at > c at asm add.commute) fact ◊ lemma assumes P {x::int. y + 1 = 1 + x} shows P {x::int. y + 1 = x + 1 } by (rewrite at x+1 in {x::int. } add.commute) fact ◊ lemma assumes P {x::int. y + 1 = 1 + x} shows P {x::int. y + 1 = x + 1 } by (rewrite at any-identifier-will-work+1 in {any-identifier-will-work::int. } add.commute) ◊ fact lemma assumes P {(x::nat, y::nat, z). x + z ∗ 3 = Q (λs t. s ∗ t + y − 3 )} shows P {(x::nat, y::nat, z). x + z ∗ 3 = Q (λs t. y + s ∗ t − 3 )} by (rewrite at b + d ∗ e in λ(a, b, c). - = Q (λd e. ) add.commute) fact ◊ lemma assumes PROP P ≡ PROP Q shows PROP R =⇒ PROP P =⇒ PROP Q by (rewrite at asm assms) lemma assumes PROP P ≡ PROP Q shows PROP R =⇒ PROP R =⇒ PROP P =⇒ PROP Q by (rewrite at asm assms) lemma assumes (PROP P =⇒ PROP Q) ≡ (PROP S =⇒ PROP R) shows PROP S =⇒ (PROP P =⇒ PROP Q) =⇒ PROP R apply (rewrite at asm assms) apply assumption done lemma test-theorem: fixes x :: nat shows x ≤ y =⇒ x ≥ y =⇒ x = y by (rule Orderings.order-antisym) lemma fixes f :: nat ⇒ nat 611 shows f x ≤ 0 =⇒ f x ≥ 0 =⇒ f x = 0 apply (rewrite at f x to 0 test-theorem) apply assumption apply assumption apply (rule refl) done lemma assumes rewr: PROP P =⇒ PROP Q =⇒ PROP R ≡ PROP R 0 assumes A1 : PROP S =⇒ PROP T =⇒ PROP U =⇒ PROP P assumes A2 : PROP S =⇒ PROP T =⇒ PROP U =⇒ PROP Q assumes C : PROP S =⇒ PROP R 0 =⇒ PROP T =⇒ PROP U =⇒ PROP V shows PROP S =⇒ PROP R =⇒ PROP T =⇒ PROP U =⇒ PROP V apply (rewrite at asm rewr) apply (fact A1 ) apply (fact A2 ) apply (fact C ) done fun f :: nat ⇒ nat where f n = n definition f-inv (I :: nat ⇒ bool) n ≡ f n lemma annotate-f : f = f-inv I by (simp add: f-inv-def fun-eq-iff ) lemma assumes P (λn. f-inv (λ-. True) n + 1 ) = x shows P (λn. f n + 1 ) = x by (rewrite to f-inv (λ-. True) annotate-f ) fact lemma assumes P (λn. f-inv (λx. n < x + 1 ) n + 1 ) = x shows P (λn. f n + 1 ) = x by (rewrite in λn. to f-inv (λx. n < x + 1 ) annotate-f ) fact ◊ lemma assumes P (λn. f-inv (λx. n < x + 1 ) n + 1 ) = x shows P (λn. f n + 1 ) = x by (rewrite in λabc. to f-inv (λx. abc < x + 1 ) annotate-f ) fact ◊ 612 lemma assumes P (2 + 1 ) shows Vx y. P (1 + 2 :: nat) by (rewrite in P (1 + 2 ) at for (x) add.commute) fact lemma assumes Vx y. P (y + x) shows Vx y. P (x + y :: nat) by (rewrite in P (x + -) at for (x y) add.commute) fact lemma assumes Vx y z. y + x + z = z + y + (x::int) shows Vx y z. x + y + z = z + y + (x::int) by (rewrite at x + y in x + y + z in for (x y z) add.commute) fact lemma assumes Vx y z. z + (x + y) = z + y + (x::int) shows Vx y z. x + y + z = z + y + (x::int) by (rewrite at (- + y) + z in for (y z) add.commute) fact lemma assumes Vx y z. x + y + z = y + z + (x::int) shows Vx y z. x + y + z = z + y + (x::int) by (rewrite at + - at - = in for () add.commute) fact ◊ ◊ lemma assumes eq: Vx. P x =⇒ g x = x assumes f1 : Vx. Q x =⇒ P x assumes f2 : Vx. Q x =⇒ x shows Vx. Q x =⇒ g x apply (rewrite at g x in for (x) eq) apply (fact f1 ) apply (fact f2 ) done lemma assumes (V(x::int). x < 1 + x) and (x::int) + 1 > x shows (V(x::int). x + 1 > x) =⇒ (x::int) + 1 > x by (rewrite at x + 1 in for (x) at asm add.commute) (rule assms) lemma assumes Va b. P ((a + 1 ) ∗ (1 + b)) shows Va b :: nat. P ((a + 1 ) ∗ (b + 1 )) apply (tactic h let 613 val (x, ctxt) = yield-singleton Variable.add-fixes x @{context} (∗ Note that the pattern order is reversed ∗) val pat = [ Rewrite.For [(x, SOME @{typ nat})], Rewrite.In, Rewrite.Term (@{const plus(nat)} $ Free (x, @{typ nat}) $ @{term 1 :: nat}, [])] val to = NONE in CCONVERSION (Rewrite.rewrite-conv ctxt (pat, to)@{thms add.commute}) 1 end i) apply (fact assms) done lemma assumes Q (λb :: int. P (λa. a + b)(λa. a + b)) shows Q (λb :: int. P (λa. a + b)(λa. b + a)) apply (tactic h let val (x, ctxt) = yield-singleton Variable.add-fixes x @{context} val pat = [ Rewrite.Concl, Rewrite.In, Rewrite.Term (Free (Q, (@{typ int} −−> TVar (( 0b,0 ), [])) −−> @{typ bool}) $ Abs (x, @{typ int}, Rewrite.mk-hole 1 (@{typ int} −−> TVar (( 0b,0 ), [])) $ Bound 0 ), [(x, @{typ int})]), Rewrite.In, Rewrite.Term (@{const plus(int)} $ Free (x, @{typ int}) $ Var ((c, 0 ), @{typ int}), []) ] val to = NONE in CCONVERSION (Rewrite.rewrite-conv ctxt (pat, to)@{thms add.commute}) 1 end i) apply (fact assms) done ML h val ct = @{cprop Q (λb :: int. P (λa. a + b)(λa. b + a))} val (x, ctxt) = yield-singleton Variable.add-fixes x @{context} val pat = [ Rewrite.Concl, Rewrite.In, Rewrite.Term (Free (Q, (@{typ int} −−> TVar (( 0b,0 ), [])) −−> @{typ bool}) $ Abs (x, @{typ int}, Rewrite.mk-hole 1 (@{typ int} −−> TVar (( 0b,0 ), [])) $ Bound 0 ), [(x, @{typ int})]), Rewrite.In, 614 Rewrite.Term (@{const plus(int)} $ Free (x, @{typ int}) $ Var ((c, 0 ), @{typ int}), []) ] val to = NONE val th = Rewrite.rewrite-conv ctxt (pat, to)@{thms add.commute} ct i 94 Regression tests ML h val ct = @{cterm (λb :: int. (λa. b + a))} val (x, ctxt) = yield-singleton Variable.add-fixes x @{context} val pat = [ Rewrite.In, Rewrite.Term (@{const plus(int)} $ Var ((c, 0 ), @{typ int}) $ Var ((c, 0 ), @{typ int}), []) ] val to = NONE val - = case try (Rewrite.rewrite-conv ctxt (pat, to)@{thms add.commute}) ct of NONE => () | - => error should not have matched anything i ML h Rewrite.params-pconv (Conv.all-conv |> K |> K )@{context} (Vartab.empty, []) @{cterm Vx. PROP A} i lemma assumes eq: PROP A =⇒ PROP B ≡ PROP C assumes f1 : PROP D =⇒ PROP A assumes f2 : PROP D =⇒ PROP C shows Vx. PROP D =⇒ PROP B apply (rewrite eq) apply (fact f1 ) apply (fact f2 ) done end 95 Examples for proof methods ”sat” and ”satx” theory SAT-Examples imports Main begin 615 lemma True by sat lemma a | ∼a by sat lemma (a | b)& ∼a =⇒ b by sat lemma (a & b) | (c & d) =⇒ (a & b) | (c & d) by sat lemma (a & b) | (c & d) =⇒ (a & b) | (c & d) by satx lemma (a & b | c & d)&(e & f | g & h) | (i & j | k & l)&(m & n | p & q) =⇒ (a & b | c & d)&(e & f | g & h) | (i & j | k & l)&(m & n | p & q) by sat lemma (a & b | c & d)&(e & f | g & h) | (i & j | k & l)&(m & n | p & q) =⇒ (a & b | c & d)&(e & f | g & h) | (i & j | k & l)&(m & n | p & q) by satx lemma P=P=P=P=P=P=P=P=P=P by sat lemma P=P=P=P=P=P=P=P=P=P by satx lemma !! a b c. [| a | b | c | d ; e | f | (a & d); ∼(a | (c & ∼c)) | b ; ∼(b &(x | ∼x)) | c ; ∼(d | False) | c ; ∼(c | (∼p &(p | (q & ∼q)))) |] ==> False by sat lemma !! a b c. [| a | b | c | d ; e | f | (a & d); ∼(a | (c & ∼c)) | b ; ∼(b &(x | ∼x)) | c ; ∼(d | False) | c ; ∼(c | (∼p &(p | (q & ∼q)))) |] ==> False by satx 616 eta-Equivalence lemma (ALL x. P x) | ∼ All P by sat declare [[sat-trace = false]] declare [[quick-and-dirty = false]] method-setup rawsat = h Scan.succeed (SIMPLE-METHOD 0 o SAT .rawsat-tac) i SAT solver (no preprocessing) lemma assumes 1 : ∼x0 and 2 : ∼x30 and 3 : ∼x29 and 4 : ∼x59 and 5 : x1 | x31 | x0 and 6 : x2 | x32 | x1 and 7 : x3 | x33 | x2 and 8 : x4 | x34 | x3 and 9 : x35 | x4 and 10 : x5 | x36 | x30 and 11 : x6 | x37 | x5 | x31 and 12 : x7 | x38 | x6 | x32 and 13 : x8 | x39 | x7 | x33 and 14 : x9 | x40 | x8 | x34 and 15 : x41 | x9 | x35 and 16 : x10 | x42 | x36 and 17 : x11 | x43 | x10 | x37 and 18 : x12 | x44 | x11 | x38 and 19 : x13 | x45 | x12 | x39 and 20 : x14 | x46 | x13 | x40 and 21 : x47 | x14 | x41 and 22 : x15 | x48 | x42 and 23 : x16 | x49 | x15 | x43 and 24 : x17 | x50 | x16 | x44 and 25 : x18 | x51 | x17 | x45 and 26 : x19 | x52 | x18 | x46 and 27 : x53 | x19 | x47 and 28 : x20 | x54 | x48 and 29 : x21 | x55 | x20 | x49 and 30 : x22 | x56 | x21 | x50 and 31 : x23 | x57 | x22 | x51 and 32 : x24 | x58 | x23 | x52 and 33 : x59 | x24 | x53 and 34 : x25 | x54 and 35 : x26 | x25 | x55 and 36 : x27 | x26 | x56 617 and 37 : x28 | x27 | x57 and 38 : x29 | x28 | x58 and 39 : ∼x1 | ∼x31 and 40 : ∼x1 | ∼x0 and 41 : ∼x31 | ∼x0 and 42 : ∼x2 | ∼x32 and 43 : ∼x2 | ∼x1 and 44 : ∼x32 | ∼x1 and 45 : ∼x3 | ∼x33 and 46 : ∼x3 | ∼x2 and 47 : ∼x33 | ∼x2 and 48 : ∼x4 | ∼x34 and 49 : ∼x4 | ∼x3 and 50 : ∼x34 | ∼x3 and 51 : ∼x35 | ∼x4 and 52 : ∼x5 | ∼x36 and 53 : ∼x5 | ∼x30 and 54 : ∼x36 | ∼x30 and 55 : ∼x6 | ∼x37 and 56 : ∼x6 | ∼x5 and 57 : ∼x6 | ∼x31 and 58 : ∼x37 | ∼x5 and 59 : ∼x37 | ∼x31 and 60 : ∼x5 | ∼x31 and 61 : ∼x7 | ∼x38 and 62 : ∼x7 | ∼x6 and 63 : ∼x7 | ∼x32 and 64 : ∼x38 | ∼x6 and 65 : ∼x38 | ∼x32 and 66 : ∼x6 | ∼x32 and 67 : ∼x8 | ∼x39 and 68 : ∼x8 | ∼x7 and 69 : ∼x8 | ∼x33 and 70 : ∼x39 | ∼x7 and 71 : ∼x39 | ∼x33 and 72 : ∼x7 | ∼x33 and 73 : ∼x9 | ∼x40 and 74 : ∼x9 | ∼x8 and 75 : ∼x9 | ∼x34 and 76 : ∼x40 | ∼x8 and 77 : ∼x40 | ∼x34 and 78 : ∼x8 | ∼x34 and 79 : ∼x41 | ∼x9 and 80 : ∼x41 | ∼x35 and 81 : ∼x9 | ∼x35 and 82 : ∼x10 | ∼x42 and 83 : ∼x10 | ∼x36 and 84 : ∼x42 | ∼x36 and 85 : ∼x11 | ∼x43 618 and 86 : ∼x11 | ∼x10 and 87 : ∼x11 | ∼x37 and 88 : ∼x43 | ∼x10 and 89 : ∼x43 | ∼x37 and 90 : ∼x10 | ∼x37 and 91 : ∼x12 | ∼x44 and 92 : ∼x12 | ∼x11 and 93 : ∼x12 | ∼x38 and 94 : ∼x44 | ∼x11 and 95 : ∼x44 | ∼x38 and 96 : ∼x11 | ∼x38 and 97 : ∼x13 | ∼x45 and 98 : ∼x13 | ∼x12 and 99 : ∼x13 | ∼x39 and 100 : ∼x45 | ∼x12 and 101 : ∼x45 | ∼x39 and 102 : ∼x12 | ∼x39 and 103 : ∼x14 | ∼x46 and 104 : ∼x14 | ∼x13 and 105 : ∼x14 | ∼x40 and 106 : ∼x46 | ∼x13 and 107 : ∼x46 | ∼x40 and 108 : ∼x13 | ∼x40 and 109 : ∼x47 | ∼x14 and 110 : ∼x47 | ∼x41 and 111 : ∼x14 | ∼x41 and 112 : ∼x15 | ∼x48 and 113 : ∼x15 | ∼x42 and 114 : ∼x48 | ∼x42 and 115 : ∼x16 | ∼x49 and 116 : ∼x16 | ∼x15 and 117 : ∼x16 | ∼x43 and 118 : ∼x49 | ∼x15 and 119 : ∼x49 | ∼x43 and 120 : ∼x15 | ∼x43 and 121 : ∼x17 | ∼x50 and 122 : ∼x17 | ∼x16 and 123 : ∼x17 | ∼x44 and 124 : ∼x50 | ∼x16 and 125 : ∼x50 | ∼x44 and 126 : ∼x16 | ∼x44 and 127 : ∼x18 | ∼x51 and 128 : ∼x18 | ∼x17 and 129 : ∼x18 | ∼x45 and 130 : ∼x51 | ∼x17 and 131 : ∼x51 | ∼x45 and 132 : ∼x17 | ∼x45 and 133 : ∼x19 | ∼x52 and 134 : ∼x19 | ∼x18 619 and 135 : ∼x19 | ∼x46 and 136 : ∼x52 | ∼x18 and 137 : ∼x52 | ∼x46 and 138 : ∼x18 | ∼x46 and 139 : ∼x53 | ∼x19 and 140 : ∼x53 | ∼x47 and 141 : ∼x19 | ∼x47 and 142 : ∼x20 | ∼x54 and 143 : ∼x20 | ∼x48 and 144 : ∼x54 | ∼x48 and 145 : ∼x21 | ∼x55 and 146 : ∼x21 | ∼x20 and 147 : ∼x21 | ∼x49 and 148 : ∼x55 | ∼x20 and 149 : ∼x55 | ∼x49 and 150 : ∼x20 | ∼x49 and 151 : ∼x22 | ∼x56 and 152 : ∼x22 | ∼x21 and 153 : ∼x22 | ∼x50 and 154 : ∼x56 | ∼x21 and 155 : ∼x56 | ∼x50 and 156 : ∼x21 | ∼x50 and 157 : ∼x23 | ∼x57 and 158 : ∼x23 | ∼x22 and 159 : ∼x23 | ∼x51 and 160 : ∼x57 | ∼x22 and 161 : ∼x57 | ∼x51 and 162 : ∼x22 | ∼x51 and 163 : ∼x24 | ∼x58 and 164 : ∼x24 | ∼x23 and 165 : ∼x24 | ∼x52 and 166 : ∼x58 | ∼x23 and 167 : ∼x58 | ∼x52 and 168 : ∼x23 | ∼x52 and 169 : ∼x59 | ∼x24 and 170 : ∼x59 | ∼x53 and 171 : ∼x24 | ∼x53 and 172 : ∼x25 | ∼x54 and 173 : ∼x26 | ∼x25 and 174 : ∼x26 | ∼x55 and 175 : ∼x25 | ∼x55 and 176 : ∼x27 | ∼x26 and 177 : ∼x27 | ∼x56 and 178 : ∼x26 | ∼x56 and 179 : ∼x28 | ∼x27 and 180 : ∼x28 | ∼x57 and 181 : ∼x27 | ∼x57 and 182 : ∼x29 | ∼x28 and 183 : ∼x29 | ∼x58 620 and 184 : ∼x28 | ∼x58 shows False using assms by rawsat — this is without CNF conversion lemma assumes 1 : x0 | x1 | x2 | x3 | x4 | x5 | x6 and 2 : x7 | x8 | x9 | x10 | x11 | x12 | x13 and 3 : x14 | x15 | x16 | x17 | x18 | x19 | x20 and 4 : x21 | x22 | x23 | x24 | x25 | x26 | x27 and 5 : x28 | x29 | x30 | x31 | x32 | x33 | x34 and 6 : x35 | x36 | x37 | x38 | x39 | x40 | x41 and 7 : x42 | x43 | x44 | x45 | x46 | x47 | x48 and 8 : x49 | x50 | x51 | x52 | x53 | x54 | x55 and 9 : ∼x0 | ∼x7 and 10 : ∼x0 | ∼x14 and 11 : ∼x0 | ∼x21 and 12 : ∼x0 | ∼x28 and 13 : ∼x0 | ∼x35 and 14 : ∼x0 | ∼x42 and 15 : ∼x0 | ∼x49 and 16 : ∼x7 | ∼x14 and 17 : ∼x7 | ∼x21 and 18 : ∼x7 | ∼x28 and 19 : ∼x7 | ∼x35 and 20 : ∼x7 | ∼x42 and 21 : ∼x7 | ∼x49 and 22 : ∼x14 | ∼x21 and 23 : ∼x14 | ∼x28 and 24 : ∼x14 | ∼x35 and 25 : ∼x14 | ∼x42 and 26 : ∼x14 | ∼x49 and 27 : ∼x21 | ∼x28 and 28 : ∼x21 | ∼x35 and 29 : ∼x21 | ∼x42 and 30 : ∼x21 | ∼x49 and 31 : ∼x28 | ∼x35 and 32 : ∼x28 | ∼x42 and 33 : ∼x28 | ∼x49 and 34 : ∼x35 | ∼x42 and 35 : ∼x35 | ∼x49 and 36 : ∼x42 | ∼x49 and 37 : ∼x1 | ∼x8 and 38 : ∼x1 | ∼x15 and 39 : ∼x1 | ∼x22 and 40 : ∼x1 | ∼x29 and 41 : ∼x1 | ∼x36 621 and 42 : ∼x1 | ∼x43 and 43 : ∼x1 | ∼x50 and 44 : ∼x8 | ∼x15 and 45 : ∼x8 | ∼x22 and 46 : ∼x8 | ∼x29 and 47 : ∼x8 | ∼x36 and 48 : ∼x8 | ∼x43 and 49 : ∼x8 | ∼x50 and 50 : ∼x15 | ∼x22 and 51 : ∼x15 | ∼x29 and 52 : ∼x15 | ∼x36 and 53 : ∼x15 | ∼x43 and 54 : ∼x15 | ∼x50 and 55 : ∼x22 | ∼x29 and 56 : ∼x22 | ∼x36 and 57 : ∼x22 | ∼x43 and 58 : ∼x22 | ∼x50 and 59 : ∼x29 | ∼x36 and 60 : ∼x29 | ∼x43 and 61 : ∼x29 | ∼x50 and 62 : ∼x36 | ∼x43 and 63 : ∼x36 | ∼x50 and 64 : ∼x43 | ∼x50 and 65 : ∼x2 | ∼x9 and 66 : ∼x2 | ∼x16 and 67 : ∼x2 | ∼x23 and 68 : ∼x2 | ∼x30 and 69 : ∼x2 | ∼x37 and 70 : ∼x2 | ∼x44 and 71 : ∼x2 | ∼x51 and 72 : ∼x9 | ∼x16 and 73 : ∼x9 | ∼x23 and 74 : ∼x9 | ∼x30 and 75 : ∼x9 | ∼x37 and 76 : ∼x9 | ∼x44 and 77 : ∼x9 | ∼x51 and 78 : ∼x16 | ∼x23 and 79 : ∼x16 | ∼x30 and 80 : ∼x16 | ∼x37 and 81 : ∼x16 | ∼x44 and 82 : ∼x16 | ∼x51 and 83 : ∼x23 | ∼x30 and 84 : ∼x23 | ∼x37 and 85 : ∼x23 | ∼x44 and 86 : ∼x23 | ∼x51 and 87 : ∼x30 | ∼x37 and 88 : ∼x30 | ∼x44 and 89 : ∼x30 | ∼x51 and 90 : ∼x37 | ∼x44 622 and 91 : ∼x37 | ∼x51 and 92 : ∼x44 | ∼x51 and 93 : ∼x3 | ∼x10 and 94 : ∼x3 | ∼x17 and 95 : ∼x3 | ∼x24 and 96 : ∼x3 | ∼x31 and 97 : ∼x3 | ∼x38 and 98 : ∼x3 | ∼x45 and 99 : ∼x3 | ∼x52 and 100 : ∼x10 | ∼x17 and 101 : ∼x10 | ∼x24 and 102 : ∼x10 | ∼x31 and 103 : ∼x10 | ∼x38 and 104 : ∼x10 | ∼x45 and 105 : ∼x10 | ∼x52 and 106 : ∼x17 | ∼x24 and 107 : ∼x17 | ∼x31 and 108 : ∼x17 | ∼x38 and 109 : ∼x17 | ∼x45 and 110 : ∼x17 | ∼x52 and 111 : ∼x24 | ∼x31 and 112 : ∼x24 | ∼x38 and 113 : ∼x24 | ∼x45 and 114 : ∼x24 | ∼x52 and 115 : ∼x31 | ∼x38 and 116 : ∼x31 | ∼x45 and 117 : ∼x31 | ∼x52 and 118 : ∼x38 | ∼x45 and 119 : ∼x38 | ∼x52 and 120 : ∼x45 | ∼x52 and 121 : ∼x4 | ∼x11 and 122 : ∼x4 | ∼x18 and 123 : ∼x4 | ∼x25 and 124 : ∼x4 | ∼x32 and 125 : ∼x4 | ∼x39 and 126 : ∼x4 | ∼x46 and 127 : ∼x4 | ∼x53 and 128 : ∼x11 | ∼x18 and 129 : ∼x11 | ∼x25 and 130 : ∼x11 | ∼x32 and 131 : ∼x11 | ∼x39 and 132 : ∼x11 | ∼x46 and 133 : ∼x11 | ∼x53 and 134 : ∼x18 | ∼x25 and 135 : ∼x18 | ∼x32 and 136 : ∼x18 | ∼x39 and 137 : ∼x18 | ∼x46 and 138 : ∼x18 | ∼x53 and 139 : ∼x25 | ∼x32 623 and 140 : ∼x25 | ∼x39 and 141 : ∼x25 | ∼x46 and 142 : ∼x25 | ∼x53 and 143 : ∼x32 | ∼x39 and 144 : ∼x32 | ∼x46 and 145 : ∼x32 | ∼x53 and 146 : ∼x39 | ∼x46 and 147 : ∼x39 | ∼x53 and 148 : ∼x46 | ∼x53 and 149 : ∼x5 | ∼x12 and 150 : ∼x5 | ∼x19 and 151 : ∼x5 | ∼x26 and 152 : ∼x5 | ∼x33 and 153 : ∼x5 | ∼x40 and 154 : ∼x5 | ∼x47 and 155 : ∼x5 | ∼x54 and 156 : ∼x12 | ∼x19 and 157 : ∼x12 | ∼x26 and 158 : ∼x12 | ∼x33 and 159 : ∼x12 | ∼x40 and 160 : ∼x12 | ∼x47 and 161 : ∼x12 | ∼x54 and 162 : ∼x19 | ∼x26 and 163 : ∼x19 | ∼x33 and 164 : ∼x19 | ∼x40 and 165 : ∼x19 | ∼x47 and 166 : ∼x19 | ∼x54 and 167 : ∼x26 | ∼x33 and 168 : ∼x26 | ∼x40 and 169 : ∼x26 | ∼x47 and 170 : ∼x26 | ∼x54 and 171 : ∼x33 | ∼x40 and 172 : ∼x33 | ∼x47 and 173 : ∼x33 | ∼x54 and 174 : ∼x40 | ∼x47 and 175 : ∼x40 | ∼x54 and 176 : ∼x47 | ∼x54 and 177 : ∼x6 | ∼x13 and 178 : ∼x6 | ∼x20 and 179 : ∼x6 | ∼x27 and 180 : ∼x6 | ∼x34 and 181 : ∼x6 | ∼x41 and 182 : ∼x6 | ∼x48 and 183 : ∼x6 | ∼x55 and 184 : ∼x13 | ∼x20 and 185 : ∼x13 | ∼x27 and 186 : ∼x13 | ∼x34 and 187 : ∼x13 | ∼x41 and 188 : ∼x13 | ∼x48 624 and 189 : ∼x13 | ∼x55 and 190 : ∼x20 | ∼x27 and 191 : ∼x20 | ∼x34 and 192 : ∼x20 | ∼x41 and 193 : ∼x20 | ∼x48 and 194 : ∼x20 | ∼x55 and 195 : ∼x27 | ∼x34 and 196 : ∼x27 | ∼x41 and 197 : ∼x27 | ∼x48 and 198 : ∼x27 | ∼x55 and 199 : ∼x34 | ∼x41 and 200 : ∼x34 | ∼x48 and 201 : ∼x34 | ∼x55 and 202 : ∼x41 | ∼x48 and 203 : ∼x41 | ∼x55 and 204 : ∼x48 | ∼x55 shows False using assms by rawsat — this is without CNF conversion Function benchmark takes the name of an existing DIMACS CNF file, parses this file, passes the problem to a SAT solver, and checks the proof of un- satisfiability found by the solver. The function measures the time spent on proof reconstruction (at least real time also includes time spent in the SAT solver), and additionally returns the number of resolution steps in the proof. ML h fun benchmark dimacsfile = let val prop-fm = SAT-Solver.read-dimacs-cnf-file (Path.explode dimacsfile) fun and-to-list (Prop-Logic.And (fm1 , fm2 )) acc = and-to-list fm2 (fm1 :: acc) | and-to-list fm acc = rev (fm :: acc) val clauses = and-to-list prop-fm [] val terms = map (HOLogic.mk-Trueprop o Prop-Logic.term-of-prop-formula) clauses val cterms = map (Thm.cterm-of @{context}) terms val start = Timing.start () val - = SAT .rawsat-thm @{context} cterms in (Timing.result start, ! SAT .counter) end; i end 625 96 A decision procedure for universal multivari- ate real arithmetic with addition, multiplica- tion and ordering using semidefinite program- ming theory Sum-of-Squares imports Complex-Main begin ML-file positivstellensatz.ML ML-file Sum-of-Squares/sum-of-squares.ML ML-file Sum-of-Squares/positivstellensatz-tools.ML ML-file Sum-of-Squares/sos-wrapper.ML end theory SOS imports ∼∼/src/HOL/Library/Sum-of-Squares begin lemma (3 ::real) ∗ x + 7 ∗ a < 4 & 3 < 2 ∗ x =⇒ a < 0 by sos lemma a1 ≥ 0 ∧ a2 ≥ 0 ∧ (a1 ∗ a1 + a2 ∗ a2 = b1 ∗ b1 + b2 ∗ b2 + 2 ) ∧ (a1 ∗ b1 + a2 ∗ b2 = 0 ) −→ a1 ∗ a2 − b1 ∗ b2 ≥ (0 ::real) by sos lemma (3 ::real) ∗ x + 7 ∗ a < 4 & 3 < 2 ∗ x −→ a < 0 by sos lemma (0 ::real) ≤ x ∧ x ≤ 1 ∧ 0 ≤ y ∧ y ≤ 1 −→ x 2 + y2 < 1 ∨ (x − 1 )2 + y2 < 1 ∨ x 2 + (y − 1 )2 < 1 ∨ (x − 1 )2 + (y − 1 )2 < 1 by sos lemma (0 ::real) ≤ x ∧ 0 ≤ y ∧ 0 ≤ z ∧ x + y + z ≤ 3 −→ x ∗ y + x ∗ z + y ∗ z ≥ 3 ∗ x ∗ y ∗ z by sos lemma (x::real)2 + y2 + z 2 = 1 −→ (x + y + z)2 ≤ 3 by sos lemma w 2 + x 2 + y2 + z 2 = 1 −→ (w + x + y + z)2 ≤ (4 ::real) by sos lemma (x::real) ≥ 1 ∧ y ≥ 1 −→ x ∗ y ≥ x + y − 1 626 by sos lemma (x::real) > 1 ∧ y > 1 −→ x ∗ y > x + y − 1 by sos lemma |x| ≤ 1 −→ |64 ∗ xˆ7 − 112 ∗ xˆ5 + 56 ∗ xˆ3 − 7 ∗ x| ≤ (1 ::real) by sos One component of denominator in dodecahedral example. lemma 2 ≤ x ∧ x ≤ 125841 / 50000 ∧ 2 ≤ y ∧ y ≤ 125841 / 50000 ∧ 2 ≤ z ∧ z ≤ 125841 / 50000 −→ 2 ∗ (x ∗ z + x ∗ y + y ∗ z) − (x ∗ x + y ∗ y + z ∗ z) ≥ (0 ::real) by sos Over a larger but simpler interval. lemma (2 ::real) ≤ x ∧ x ≤ 4 ∧ 2 ≤ y ∧ y ≤ 4 ∧ 2 ≤ z ∧ z ≤ 4 −→ 0 ≤ 2 ∗ (x ∗ z + x ∗ y + y ∗ z) − (x ∗ x + y ∗ y + z ∗ z) by sos We can do 12. I think 12 is a sharp bound; see PP’s certificate. lemma 2 ≤ (x::real) ∧ x ≤ 4 ∧ 2 ≤ y ∧ y ≤ 4 ∧ 2 ≤ z ∧ z ≤ 4 −→ 12 ≤ 2 ∗ (x ∗ z + x ∗ y + y ∗ z) − (x ∗ x + y ∗ y + z ∗ z) by sos Inequality from sci.math (see ”Leon-Sotelo, por favor”). lemma 0 ≤ (x::real) ∧ 0 ≤ y ∧ x ∗ y = 1 −→ x + y ≤ x 2 + y2 by sos lemma 0 ≤ (x::real) ∧ 0 ≤ y ∧ x ∗ y = 1 −→ x ∗ y ∗ (x + y) ≤ x 2 + y2 by sos lemma 0 ≤ (x::real) ∧ 0 ≤ y −→ x ∗ y ∗ (x + y)2 ≤ (x 2 + y2)2 by sos lemma (0 ::real) ≤ a ∧ 0 ≤ b ∧ 0 ≤ c ∧ c ∗ (2 ∗ a + b)ˆ3 / 27 ≤ x −→ c ∗ a2 ∗ b ≤ x by sos lemma (0 ::real) < x −→ 0 < 1 + x + x 2 by sos lemma (0 ::real) ≤ x −→ 0 < 1 + x + x 2 by sos lemma (0 ::real) < 1 + x 2 by sos lemma (0 ::real) ≤ 1 + 2 ∗ x + x 2 627 by sos lemma (0 ::real) < 1 + |x| by sos lemma (0 ::real) < 1 + (1 + x)2 ∗ |x| by sos lemma |(1 ::real) + x 2| = (1 ::real) + x 2 by sos lemma (3 ::real) ∗ x + 7 ∗ a < 4 ∧ 3 < 2 ∗ x −→ a < 0 by sos lemma (0 ::real) < x −→ 1 < y −→ y ∗ x ≤ z −→ x < z by sos lemma (1 ::real) < x −→ x 2 < y −→ 1 < y by sos lemma (b::real)2 < 4 ∗ a ∗ c −→ a ∗ x 2 + b ∗ x + c 6= 0 by sos lemma (b::real)2 < 4 ∗ a ∗ c −→ a ∗ x 2 + b ∗ x + c 6= 0 by sos lemma (a::real) ∗ x 2 + b ∗ x + c = 0 −→ b2 ≥ 4 ∗ a ∗ c by sos lemma (0 ::real) ≤ b ∧ 0 ≤ c ∧ 0 ≤ x ∧ 0 ≤ y ∧ x 2 = c ∧ y2 = a2 ∗ c + b −→ a ∗ c ≤ y ∗ x by sos lemma |x − z| ≤ e ∧ |y − z| ≤ e ∧ 0 ≤ u ∧ 0 ≤ v ∧ u + v = 1 −−> |(u ∗ x + v ∗ y) − z| ≤ (e::real) by sos lemma (x::real) − y − 2 ∗ xˆ4 = 0 ∧ 0 ≤ x ∧ x ≤ 2 ∧ 0 ≤ y ∧ y ≤ 3 −→ y2 − 7 ∗ y − 12 ∗ x + 17 ≥ 0 oops lemma (0 ::real) ≤ x −→ (1 + x + x 2) / (1 + x 2) ≤ 1 + x by sos lemma (0 ::real) ≤ x −→ 1 − x ≤ 1 / (1 + x + x 2) by sos lemma (x::real) ≤ 1 / 2 −→ − x − 2 ∗ x 2 ≤ − x / (1 − x) 628 by sos lemma 4 ∗ r 2 = p2 − 4 ∗ q ∧ r ≥ (0 ::real) ∧ x 2 + p ∗ x + q = 0 −→ 2 ∗ (x::real) = − p + 2 ∗ r ∨ 2 ∗ x = − p − 2 ∗ r by sos end theory SOS-Cert imports ∼∼/src/HOL/Library/Sum-of-Squares begin lemma (3 ::real) ∗ x + 7 ∗ a < 4 ∧ 3 < 2 ∗ x =⇒ a < 0 by (sos ((R<1 + (((A<1 ∗ R<1 ) ∗ (R<2 ∗ [1 ]ˆ2 )) + (((A<0 ∗ R<1 ) ∗ (R<3 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<14 ∗ [1 ]ˆ2 ))))))) lemma a1 ≥ 0 ∧ a2 ≥ 0 ∧ (a1 ∗ a1 + a2 ∗ a2 = b1 ∗ b1 + b2 ∗ b2 + 2 ) ∧ (a1 ∗ b1 + a2 ∗ b2 = 0 ) −→ a1 ∗ a2 − b1 ∗ b2 ≥ (0 ::real) by (sos (((A<0 ∗ R<1 ) + (([∼1 /2 ∗a1 ∗b2 + ∼1 /2 ∗a2 ∗b1 ] ∗ A=0 ) + (([∼1 /2 ∗a1 ∗a2 + 1 /2 ∗b1 ∗b2 ] ∗ A=1 ) + (((A<0 ∗ R<1 ) ∗ ((R<1 /2 ∗ [b2 ]ˆ2 ) + (R<1 /2 ∗ [b1 ]ˆ2 ))) + ((A<=0 ∗ (A<=1 ∗ R<1 )) ∗ ((R<1 /2 ∗ [b2 ]ˆ2 ) + ((R<1 /2 ∗ [b1 ]ˆ2 ) + ((R<1 /2 ∗ [a2 ]ˆ2 ) + (R<1 /2 ∗ [a1 ]ˆ2 ))))))))))) lemma (3 ::real) ∗ x + 7 ∗ a < 4 ∧ 3 < 2 ∗ x −→ a < 0 by (sos ((R<1 + (((A<1 ∗ R<1 ) ∗ (R<2 ∗ [1 ]ˆ2 )) + (((A<0 ∗ R<1 ) ∗ (R<3 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<14 ∗ [1 ]ˆ2 ))))))) lemma (0 ::real) ≤ x ∧ x ≤ 1 ∧ 0 ≤ y ∧ y ≤ 1 −→ x 2 + y2 < 1 ∨ (x − 1 )2 + y2 < 1 ∨ x 2 + (y − 1 )2 < 1 ∨ (x − 1 )2 + (y − 1 )2 < 1 by (sos ((R<1 + (((A<=3 ∗ (A<=4 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ (A<=7 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + (((A<=1 ∗ (A<=6 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ (A<=5 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )))))))) lemma (0 ::real) ≤ x ∧ 0 ≤ y ∧ 0 ≤ z ∧ x + y + z ≤ 3 −→ x ∗ y + x ∗ z + y ∗ z ≥ 3 ∗ x ∗ y ∗ z by (sos (((A<0 ∗ R<1 ) + (((A<0 ∗ R<1 ) ∗ (R<1 /2 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ R<1 ) ∗ (R<1 /2 ∗ [∼1 ∗x + y]ˆ2 )) + (((A<=1 ∗ R<1 ) ∗ (R<1 /2 ∗ [∼1 ∗x + z]ˆ2 )) + (((A<=1 ∗ (A<=2 ∗ (A<=3 ∗ R<1 ))) ∗ (R<1 /2 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ R<1 ) ∗ (R<1 /2 ∗ [∼1 ∗y + z]ˆ2 )) + (((A<=0 ∗ (A<=2 ∗ (A<=3 ∗ R<1 ))) ∗ (R<1 /2 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ (A<=1 ∗ (A<=3 ∗ R<1 ))) ∗ (R<1 /2 ∗ [1 ]ˆ2 ))))))))))) lemma (x::real)2 + y2 + z 2 = 1 −→ (x + y + z)2 ≤ 3 by (sos (((A<0 ∗ R<1 ) + (([∼3 ] ∗ A=0 ) + (R<1 ∗ ((R<2 ∗ [∼1 /2 ∗x + ∼1 /2 ∗y + z]ˆ2 ) + (R<3 /2 ∗ [∼1 ∗x + y]ˆ2 ))))))) 629 lemma w 2 + x 2 + y2 + z 2 = 1 −→ (w + x + y + z)2 ≤ (4 ::real) by (sos (((A<0 ∗ R<1 ) + (([∼4 ] ∗ A=0 ) + (R<1 ∗ ((R<3 ∗ [∼1 /3 ∗w + ∼1 /3 ∗x + ∼1 /3 ∗y + z]ˆ2 ) + ((R<8 /3 ∗ [∼1 /2 ∗w + ∼1 /2 ∗x + y]ˆ2 ) + (R<2 ∗ [∼1 ∗w + x]ˆ2 )))))))) lemma (x::real) ≥ 1 ∧ y ≥ 1 −→ x ∗ y ≥ x + y − 1 by (sos (((A<0 ∗ R<1 ) + ((A<=0 ∗ (A<=1 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 ))))) lemma (x::real) > 1 ∧ y > 1 −→ x ∗ y > x + y − 1 by (sos ((((A<0 ∗ A<1 ) ∗ R<1 ) + ((A<=0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 ))))) lemma |x| ≤ 1 −→ |64 ∗ xˆ7 − 112 ∗ xˆ5 + 56 ∗ xˆ3 − 7 ∗ x| ≤ (1 ::real) by (sos ((((A<0 ∗ R<1 ) + ((A<=1 ∗ R<1 ) ∗ (R<1 ∗ [∼8 ∗xˆ3 + ∼4 ∗xˆ2 + 4 ∗x + 1 ]ˆ2 )))) & ((((A<0 ∗ A<1 ) ∗ R<1 ) + ((A<=1 ∗ (A<0 ∗ R<1 )) ∗ (R<1 ∗ [8 ∗xˆ3 + ∼4 ∗xˆ2 + ∼4 ∗x + 1 ]ˆ2 )))))) One component of denominator in dodecahedral example. lemma 2 ≤ x ∧ x ≤ 125841 / 50000 ∧ 2 ≤ y ∧ y ≤ 125841 / 50000 ∧ 2 ≤ z ∧ z ≤ 125841 / 50000 −→ 2 ∗ (x ∗ z + x ∗ y + y ∗ z) − (x ∗ x + y ∗ y + z ∗ z) ≥ (0 ::real) by (sos (((A<0 ∗ R<1 ) + ((R<1 ∗ ((R<5749028157 /5000000000 ∗ [∼25000 /222477 ∗x + ∼25000 /222477 ∗y + ∼25000 /222477 ∗z + 1 ]ˆ2 ) + ((R<864067 /1779816 ∗ [419113 /864067 ∗x + 419113 /864067 ∗y + z]ˆ2 ) + ((R<320795 /864067 ∗ [419113 /1283180 ∗x + y]ˆ2 ) + (R<1702293 /5132720 ∗ [x]ˆ2 ))))) + (((A<=4 ∗ (A<=5 ∗ R<1 )) ∗ (R<3 /2 ∗ [1 ]ˆ2 )) + (((A<=3 ∗ (A<=5 ∗ R<1 )) ∗ (R<1 /2 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ (A<=4 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ (A<=3 ∗ R<1 )) ∗ (R<3 /2 ∗ [1 ]ˆ2 )) + (((A<=1 ∗ (A<=5 ∗ R<1 )) ∗ (R<1 /2 ∗ [1 ]ˆ2 )) + (((A<=1 ∗ (A<=3 ∗ R<1 )) ∗ (R<1 /2 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ (A<=4 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ (A<=2 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ (A<=1 ∗ R<1 )) ∗ (R<3 /2 ∗ [1 ]ˆ2 )))))))))))))) Over a larger but simpler interval. lemma (2 ::real) ≤ x ∧ x ≤ 4 ∧ 2 ≤ y ∧ y ≤ 4 ∧ 2 ≤ z ∧ z ≤ 4 −→ 0 ≤ 2 ∗ (x ∗ z + x ∗ y + y ∗ z) − (x ∗ x + y ∗ y + z ∗ z) by (sos ((R<1 + ((R<1 ∗ ((R<1 ∗ [∼1 /6 ∗x + ∼1 /6 ∗y + ∼1 /6 ∗z + 1 ]ˆ2 ) + ((R<1 /18 ∗ [∼1 /2 ∗x + ∼1 /2 ∗y + z]ˆ2 ) + (R<1 /24 ∗ [∼1 ∗x + y]ˆ2 )))) + (((A<0 ∗ R<1 ) ∗ (R<1 /12 ∗ [1 ]ˆ2 )) + (((A<=4 ∗ (A<=5 ∗ R<1 )) ∗ (R<1 /6 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ (A<=4 ∗ R<1 )) ∗ (R<1 /6 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ (A<=3 ∗ R<1 )) ∗ (R<1 /6 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ (A<=4 ∗ R<1 )) ∗ (R<1 /6 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ (A<=2 ∗ R<1 )) ∗ (R<1 /6 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ (A<=1 ∗ R<1 )) ∗ (R<1 /6 ∗ [1 ]ˆ2 )))))))))))) We can do 12. I think 12 is a sharp bound; see PP’s certificate. lemma 2 ≤ (x::real) ∧ x ≤ 4 ∧ 2 ≤ y ∧ y ≤ 4 ∧ 2 ≤ z ∧ z ≤ 4 −→ 12 ≤ 2 ∗ (x ∗ z + x ∗ y + y ∗ z) − (x ∗ x + y ∗ y + z ∗ z) by (sos (((A<0 ∗ R<1 ) + (((A<=4 ∗ R<1 ) ∗ (R<2 /3 ∗ [1 ]ˆ2 )) + (((A<=4 ∗ (A<=5 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + (((A<=3 ∗ (A<=4 ∗ R<1 )) ∗ (R<1 /3 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ R<1 ) ∗ (R<2 /3 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ (A<=5 ∗ R<1 )) ∗ (R<1 /3 ∗ [1 ]ˆ2 )) + (((A<=2 ∗ (A<=4 ∗ R<1 )) ∗ (R<8 /3 ∗ [1 ]ˆ2 )) + (((A<=2 630 ∗ (A<=3 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + (((A<=1 ∗ (A<=4 ∗ R<1 )) ∗ (R<1 /3 ∗ [1 ]ˆ2 )) + (((A<=1 ∗ (A<=2 ∗ R<1 )) ∗ (R<1 /3 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ R<1 ) ∗ (R<2 /3 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ (A<=5 ∗ R<1 )) ∗ (R<1 /3 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ (A<=4 ∗ R<1 )) ∗ (R<8 /3 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ (A<=3 ∗ R<1 )) ∗ (R<1 /3 ∗ [1 ]ˆ2 )) + (((A<=0 ∗ (A<=2 ∗ R<1 )) ∗ (R<8 /3 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ (A<=1 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 ))))))))))))))))))) Inequality from sci.math (see ”Leon-Sotelo, por favor”). lemma 0 ≤ (x::real) ∧ 0 ≤ y ∧ x ∗ y = 1 −→ x + y ≤ x 2 + y2 by (sos (((A<0 ∗ R<1 ) + (([1 ] ∗ A=0 ) + (R<1 ∗ ((R<1 ∗ [∼1 /2 ∗x + ∼1 /2 ∗y + 1 ]ˆ2 ) + (R<3 /4 ∗ [∼1 ∗x + y]ˆ2 ))))))) lemma 0 ≤ (x::real) ∧ 0 ≤ y ∧ x ∗ y = 1 −→ x ∗ y ∗ (x + y) ≤ x 2 + y2 by (sos (((A<0 ∗ R<1 ) + (([∼1 ∗x + ∼1 ∗y + 1 ] ∗ A=0 ) + (R<1 ∗ ((R<1 ∗ [∼1 /2 ∗x + ∼1 /2 ∗y + 1 ]ˆ2 ) + (R<3 /4 ∗ [∼1 ∗x + y]ˆ2 ))))))) lemma 0 ≤ (x::real) ∧ 0 ≤ y −→ x ∗ y ∗ (x + y)2 ≤ (x 2 + y2)2 by (sos (((A<0 ∗ R<1 ) + (R<1 ∗ ((R<1 ∗ [∼1 /2 ∗xˆ2 + yˆ2 + ∼1 /2 ∗x∗y]ˆ2 ) + (R<3 /4 ∗ [∼1 ∗xˆ2 + x∗y]ˆ2 )))))) lemma (0 ::real) ≤ a ∧ 0 ≤ b ∧ 0 ≤ c ∧ c ∗ (2 ∗ a + b)ˆ3 / 27 ≤ x −→ c ∗ a2 ∗ b ≤ x by (sos (((A<0 ∗ R<1 ) + (((A<=3 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )) + (((A<=1 ∗ (A<=2 ∗ R<1 )) ∗ (R<1 /27 ∗ [∼1 ∗a + b]ˆ2 )) + ((A<=0 ∗ (A<=2 ∗ R<1 )) ∗ (R<8 /27 ∗ [∼1 ∗a + b]ˆ2 ))))))) lemma (0 ::real) < x −→ 0 < 1 + x + x 2 by (sos ((R<1 + ((R<1 ∗ (R<1 ∗ [x]ˆ2 )) + (((A<0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 ))))))) lemma (0 ::real) ≤ x −→ 0 < 1 + x + x 2 by (sos ((R<1 + ((R<1 ∗ (R<1 ∗ [x]ˆ2 )) + (((A<=1 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 ))))))) lemma (0 ::real) < 1 + x 2 by (sos ((R<1 + ((R<1 ∗ (R<1 ∗ [x]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )))))) lemma (0 ::real) ≤ 1 + 2 ∗ x + x 2 by (sos (((A<0 ∗ R<1 ) + (R<1 ∗ (R<1 ∗ [x + 1 ]ˆ2 ))))) lemma (0 ::real) < 1 + |x| by (sos ((R<1 + (((A<=1 ∗ R<1 ) ∗ (R<1 /2 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<1 /2 ∗ [1 ]ˆ2 )))))) lemma (0 ::real) < 1 + (1 + x)2 ∗ |x| by (sos (((R<1 + (((A<=1 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<1 ∗ [x + 1 ]ˆ2 ))))) & ((R<1 + (((A<0 ∗ R<1 ) ∗ (R<1 ∗ [x + 1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 ))))))) 631 lemma |(1 ::real) + x 2| = (1 ::real) + x 2 by (sos (() & (((R<1 + ((R<1 ∗ (R<1 ∗ [x]ˆ2 )) + ((A<1 ∗ R<1 ) ∗ (R<1 /2 ∗ [1 ]ˆ2 ))))) & ((R<1 + ((R<1 ∗ (R<1 ∗ [x]ˆ2 )) + ((A<0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )))))))) lemma (3 ::real) ∗ x + 7 ∗ a < 4 ∧ 3 < 2 ∗ x −→ a < 0 by (sos ((R<1 + (((A<1 ∗ R<1 ) ∗ (R<2 ∗ [1 ]ˆ2 )) + (((A<0 ∗ R<1 ) ∗ (R<3 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<14 ∗ [1 ]ˆ2 ))))))) lemma (0 ::real) < x −→ 1 < y −→ y ∗ x ≤ z −→ x < z by (sos ((((A<0 ∗ A<1 ) ∗ R<1 ) + (((A<=1 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )))))) lemma (1 ::real) < x −→ x 2 < y −→ 1 < y by (sos ((((A<0 ∗ A<1 ) ∗ R<1 ) + ((R<1 ∗ ((R<1 /10 ∗ [∼2 ∗x + y + 1 ]ˆ2 ) + (R<1 /10 ∗ [∼1 ∗x + y]ˆ2 ))) + (((A<1 ∗ R<1 ) ∗ (R<1 /2 ∗ [1 ]ˆ2 )) + (((A<0 ∗ R<1 ) ∗ (R<1 ∗ [x]ˆ2 )) + (((A<=0 ∗ R<1 ) ∗ ((R<1 /10 ∗ [x + 1 ]ˆ2 ) + (R<1 /10 ∗ [x]ˆ2 ))) + (((A<=0 ∗ (A<1 ∗ R<1 )) ∗ (R<1 /5 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ (A<0 ∗ R<1 )) ∗ (R<1 /5 ∗ [1 ]ˆ2 )))))))))) lemma (b::real)2 < 4 ∗ a ∗ c −→ a ∗ x 2 + b ∗ x + c 6= 0 by (sos (((A<0 ∗ R<1 ) + (R<1 ∗ (R<1 ∗ [2 ∗a∗x + b]ˆ2 ))))) lemma (b::real)2 < 4 ∗ a ∗ c −→ a ∗ xˆ2 + b ∗ x + c 6= 0 by (sos (((A<0 ∗ R<1 ) + (R<1 ∗ (R<1 ∗ [2 ∗a∗x + b]ˆ2 ))))) lemma (a::real) ∗ x 2 + b ∗ x + c = 0 −→ b2 ≥ 4 ∗ a ∗ c by (sos (((A<0 ∗ R<1 ) + (R<1 ∗ (R<1 ∗ [2 ∗a∗x + b]ˆ2 ))))) lemma (0 ::real) ≤ b ∧ 0 ≤ c ∧ 0 ≤ x ∧ 0 ≤ y ∧ x 2 = c ∧ y2 = a2 ∗ c + b −→ a ∗ c ≤ y ∗ x by (sos (((A<0 ∗ (A<0 ∗ R<1 )) + (((A<=2 ∗ (A<=3 ∗ (A<0 ∗ R<1 ))) ∗ (R<2 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ (A<=1 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )))))) lemma |x − z| ≤ e ∧ |y − z| ≤ e ∧ 0 ≤ u ∧ 0 ≤ v ∧ u + v = 1 −→ |(u ∗ x + v ∗ y) − z| ≤ (e::real) by (sos ((((A<0 ∗ R<1 ) + (((A<=3 ∗ (A<=6 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=1 ∗ (A<=5 ∗ R<1 )) ∗ (R<1 ∗ [1 ]ˆ2 ))))) & ((((A<0 ∗ A<1 ) ∗ R<1 ) + (((A<=3 ∗ (A<=5 ∗ (A<0 ∗ R<1 ))) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=1 ∗ (A<=4 ∗ (A<0 ∗ R<1 ))) ∗ (R<1 ∗ [1 ]ˆ2 ))))))) lemma (x::real) − y − 2 ∗ xˆ4 = 0 ∧ 0 ≤ x ∧ x ≤ 2 ∧ 0 ≤ y ∧ y ≤ 3 −→ y2 − 7 ∗ y − 12 ∗ x + 17 ≥ 0 oops lemma (0 ::real) ≤ x −→ (1 + x + x 2) / (1 + x 2) ≤ 1 + x 632 by (sos (((((A<0 ∗ A<1 ) ∗ R<1 ) + ((A<=0 ∗ (A<0 ∗ R<1 )) ∗ (R<1 ∗ [x]ˆ2 )))) & ((R<1 + ((R<1 ∗ (R<1 ∗ [x]ˆ2 )) + ((A<0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 ))))))) lemma (0 ::real) ≤ x −→ 1 − x ≤ 1 / (1 + x + x 2) by (sos (((R<1 + (([∼4 /3 ] ∗ A=0 ) + ((R<1 ∗ ((R<1 /3 ∗ [3 /2 ∗x + 1 ]ˆ2 ) + (R<7 /12 ∗ [x]ˆ2 ))) + ((A<=0 ∗ R<1 ) ∗ (R<1 /3 ∗ [1 ]ˆ2 )))))) & (((((A<0 ∗ A<1 ) ∗ R<1 ) + ((A<=0 ∗ (A<0 ∗ R<1 )) ∗ (R<1 ∗ [x]ˆ2 )))) & ((R<1 + ((R<1 ∗ (R<1 ∗ [x]ˆ2 )) + (((A<0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 )) + ((A<=0 ∗ R<1 ) ∗ (R<1 ∗ [1 ]ˆ2 ))))))))) lemma (x::real) ≤ 1 / 2 −→ − x − 2 ∗ x 2 ≤ − x / (1 − x) by (sos ((((A<0 ∗ A<1 ) ∗ R<1 ) + ((A<=0 ∗ (A<0 ∗ R<1 )) ∗ (R<1 ∗ [x]ˆ2 ))))) lemma 4 ∗ r 2 = p2 − 4 ∗ q ∧ r ≥ (0 ::real) ∧ x 2 + p ∗ x + q = 0 −→ 2 ∗ (x::real) = − p + 2 ∗ r ∨ 2 ∗ x = − p − 2 ∗ r by (sos ((((((A<0 ∗ A<1 ) ∗ R<1 ) + ([∼4 ] ∗ A=0 ))) & ((((A<0 ∗ A<1 ) ∗ R<1 ) + ([4 ] ∗ A=0 )))) & (((((A<0 ∗ A<1 ) ∗ R<1 ) + ([4 ] ∗ A=0 ))) & ((((A<0 ∗ A<1 ) ∗ R<1 ) + ([∼4 ] ∗ A=0 )))))) end 97 Bertrand’s Ballot Theorem theory Ballot imports Complex-Main ∼∼/src/HOL/Library/FuncSet begin 97.1 Preliminaries lemma card-bij 0: assumes f ∈ A → B Vx. x ∈ A =⇒ g (f x) = x and g ∈ B → A Vx. x ∈ B =⇒ f (g x) = x shows card A = card B apply (rule bij-betw-same-card) apply (rule bij-betwI ) apply fact+ done 97.2 Formalization of Problem Statement 97.2.1 Basic Definitions datatype vote = A | B definition 633 all-countings a b = card {f ∈ {1 .. a + b} →E {A, B}. card {x ∈ {1 .. a + b}. f x = A} = a ∧ card {x ∈ {1 .. a + b}. f x = B} = b} definition valid-countings a b = card {f ∈{1 ..a+b} →E {A, B}. card {x∈{1 ..a+b}. f x = A} = a ∧ card {x∈{1 ..a+b}. f x = B} = b ∧ (∀ m∈{1 ..a+b}. card {x∈{1 ..m}. f x = A} > card {x∈{1 ..m}. f x = B})} 97.2.2 Equivalence with Set Cardinality lemma Collect-on-transfer: assumes rel-set R X Y shows rel-fun (rel-fun R op =) (rel-set R)(λP. {x∈X . P x})(λP. {y∈Y . P y}) using assms unfolding rel-fun-def rel-set-def by fast lemma rel-fun-trans: rel-fun P Q g g 0 =⇒ rel-fun R P f f 0 =⇒ rel-fun R Q (λx. g (f x)) (λy. g 0 (f 0 y)) by (auto simp: rel-fun-def ) lemma rel-fun-trans2 : rel-fun P1 (rel-fun P2 Q) g g 0 =⇒ rel-fun R P1 f1 f1 0 =⇒ rel-fun R P2 f2 f2 0 =⇒ rel-fun R Q (λx. g (f1 x)(f2 x)) (λy. g 0 (f1 0 y)(f2 0 y)) by (auto simp: rel-fun-def ) lemma rel-fun-trans2 0: rel-fun R (op =) f1 f1 0 =⇒ rel-fun R (op =) f2 f2 0 =⇒ rel-fun R (op =) (λx. g (f1 x)(f2 x)) (λy. g (f1 0 y)(f2 0 y)) by (auto simp: rel-fun-def ) lemma rel-fun-const: rel-fun R (op =) (λx. a)(λy. a) by auto lemma rel-fun-conj : rel-fun R (op =) f f 0 =⇒ rel-fun R (op =) g g 0 =⇒ rel-fun R (op =) (λx. f x ∧ g x)(λy. f 0 y ∧ g 0 y) by (auto simp: rel-fun-def ) lemma rel-fun-ball: (Vi. i ∈ I =⇒ rel-fun R (op =) (f i)(f 0 i)) =⇒ rel-fun R (op =) (λx. ∀ i∈I . f i x)(λy. ∀ i∈I . f 0 i y) by (auto simp: rel-fun-def rel-set-def ) lemma shows all-countings-set: all-countings a b = card {V ∈Pow {0 .. 634 and valid-countings-set: valid-countings a b = card {V ∈Pow {0 .. m − card ({0 .. define R where R f V ←→ V ⊆ {0 .. have f ∈ extensional {1 ..a + b} =⇒ ∃ V ∈Pow {0 .. have P: rel-fun R (rel-fun P op =) (λf x. f x = A)(λV y. y ∈ V ) by (auto simp: P-def R-def Suc-le-eq gr0-conv-Suc rel-fun-def ) have eq-B: x = B ←→ x 6= A for x by (cases x; simp) { fix f and m :: nat have card {x∈{1 ..m}. f x = B} = card ({1 ..m} − {x∈{1 ..m}. f x = A}) by (simp add: eq-B set-diff-eq cong: conj-cong) also have ... = m − card {x∈{1 ..m}. f x = A} by (subst card-Diff-subset) auto finally have card {x∈{1 ..m}. f x = B} = m − card {x∈{1 ..m}. f x = A} . } 635 note card-B = this note transfers = rel-fun-const card-transfer[THEN rel-funD, OF unique-R] rel-fun-conj rel-fun-ball Collect-on-transfer[THEN rel-funD, OF total-R] Collect-on-transfer[THEN rel-funD, OF total-P] rel-fun-trans[OF card-transfer, OF unique-P] rel-fun-trans[OF Collect-on-transfer[OF total-P]] rel-fun-trans2 0[where g=op =] rel-fun-trans2 0[where g=op <] rel-fun-trans2 0[where g=op −] have all-countings a b = card {f ∈ extensional {1 ..a + b}. card {x ∈ {1 ..a + b}. f x = A} = a} using card-B by (simp add: all-countings-def PiE-iff vote.nchotomy cong: conj-cong) also have ... = card {V ∈Pow {0 .. have valid-countings a b = card {f ∈extensional {1 ..a+b}. card {x∈{1 ..a+b}. f x = A} = a ∧ (∀ m∈{1 ..a+b}. card {x∈{1 ..m}. f x = A} > m − card {x∈{1 ..m}. f x = A})} using card-B by (simp add: valid-countings-def PiE-iff vote.nchotomy cong: conj-cong) also have ... = card {V ∈Pow {0 .. m − card {x∈{0 .. 97.3 Facts About valid-countings 97.3.1 Non-Recursive Cases lemma card-V-eq-a: V ⊆ {0 .. 636 lemma Ico-subset-finite: i ⊆ {a ..< b::nat} =⇒ finite i by (auto dest: finite-subset) lemma Icc-Suc2 : a ≤ b =⇒ {a..Suc b} = insert (Suc b) {a..b} by auto lemma Ico-Suc2 : a ≤ b =⇒ {a..