| author | blanchet | 
| Mon, 06 Jun 2011 20:36:35 +0200 | |
| changeset 43201 | 0c9bf1a8e0d8 | 
| parent 42992 | 4fc15e3217eb | 
| child 43597 | b4a093e755db | 
| permissions | -rw-r--r-- | 
| 36898 | 1 | (* Title: HOL/Tools/SMT/z3_proof_tools.ML | 
| 2 | Author: Sascha Boehme, TU Muenchen | |
| 3 | ||
| 4 | Helper functions required for Z3 proof reconstruction. | |
| 5 | *) | |
| 6 | ||
| 7 | signature Z3_PROOF_TOOLS = | |
| 8 | sig | |
| 41172 
a17c2d669c40
the functions term_of and prop_of are also needed in earlier stages, not only for Z3 proof reconstruction, so they really belong in SMT_Utils
 boehmes parents: 
41123diff
changeset | 9 | (*modifying terms*) | 
| 36898 | 10 | val as_meta_eq: cterm -> cterm | 
| 11 | ||
| 41123 | 12 | (*theorem nets*) | 
| 40164 
57f5db2a48a3
added a mode to only filter assumptions used in a Z3 proof (in which no proof reconstruction is performed)
 boehmes parents: 
38864diff
changeset | 13 |   val thm_net_of: ('a -> thm) -> 'a list -> 'a Net.net
 | 
| 
57f5db2a48a3
added a mode to only filter assumptions used in a Z3 proof (in which no proof reconstruction is performed)
 boehmes parents: 
38864diff
changeset | 14 | val net_instance': ((thm -> thm option) -> 'a -> 'a option) -> 'a Net.net -> | 
| 
57f5db2a48a3
added a mode to only filter assumptions used in a Z3 proof (in which no proof reconstruction is performed)
 boehmes parents: 
38864diff
changeset | 15 | cterm -> 'a option | 
| 36898 | 16 | val net_instance: thm Net.net -> cterm -> thm option | 
| 17 | ||
| 41123 | 18 | (*proof combinators*) | 
| 36898 | 19 | val under_assumption: (thm -> thm) -> cterm -> thm | 
| 20 | val with_conv: conv -> (cterm -> thm) -> cterm -> thm | |
| 21 | val discharge: thm -> thm -> thm | |
| 22 | val varify: string list -> thm -> thm | |
| 23 | val unfold_eqs: Proof.context -> thm list -> conv | |
| 24 | val match_instantiate: (cterm -> cterm) -> cterm -> thm -> thm | |
| 25 | val by_tac: (int -> tactic) -> cterm -> thm | |
| 26 | val make_hyp_def: thm -> Proof.context -> thm * Proof.context | |
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 27 | val by_abstraction: int -> bool * bool -> Proof.context -> thm list -> | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 28 | (Proof.context -> cterm -> thm) -> cterm -> thm | 
| 36898 | 29 | |
| 41123 | 30 | (*a faster COMP*) | 
| 36898 | 31 | type compose_data | 
| 32 | val precompose: (cterm -> cterm list) -> thm -> compose_data | |
| 33 | val precompose2: (cterm -> cterm * cterm) -> thm -> compose_data | |
| 34 | val compose: compose_data -> thm -> thm | |
| 35 | ||
| 41123 | 36 | (*unfolding of 'distinct'*) | 
| 36898 | 37 | val unfold_distinct_conv: conv | 
| 38 | ||
| 41123 | 39 | (*simpset*) | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 40 | val add_simproc: Simplifier.simproc -> Context.generic -> Context.generic | 
| 36898 | 41 | val make_simpset: Proof.context -> thm list -> simpset | 
| 42 | end | |
| 43 | ||
| 44 | structure Z3_Proof_Tools: Z3_PROOF_TOOLS = | |
| 45 | struct | |
| 46 | ||
| 47 | ||
| 48 | ||
| 41172 
a17c2d669c40
the functions term_of and prop_of are also needed in earlier stages, not only for Z3 proof reconstruction, so they really belong in SMT_Utils
 boehmes parents: 
41123diff
changeset | 49 | (* modifying terms *) | 
| 36898 | 50 | |
| 41328 
6792a5c92a58
avoid ML structure aliases (especially single-letter abbreviations)
 boehmes parents: 
41281diff
changeset | 51 | fun as_meta_eq ct = | 
| 
6792a5c92a58
avoid ML structure aliases (especially single-letter abbreviations)
 boehmes parents: 
41281diff
changeset | 52 | uncurry SMT_Utils.mk_cequals (Thm.dest_binop (SMT_Utils.dest_cprop ct)) | 
| 36898 | 53 | |
| 54 | ||
| 55 | ||
| 56 | (* theorem nets *) | |
| 57 | ||
| 40164 
57f5db2a48a3
added a mode to only filter assumptions used in a Z3 proof (in which no proof reconstruction is performed)
 boehmes parents: 
38864diff
changeset | 58 | fun thm_net_of f xthms = | 
| 
57f5db2a48a3
added a mode to only filter assumptions used in a Z3 proof (in which no proof reconstruction is performed)
 boehmes parents: 
38864diff
changeset | 59 | let fun insert xthm = Net.insert_term (K false) (Thm.prop_of (f xthm), xthm) | 
| 
57f5db2a48a3
added a mode to only filter assumptions used in a Z3 proof (in which no proof reconstruction is performed)
 boehmes parents: 
38864diff
changeset | 60 | in fold insert xthms Net.empty end | 
| 36898 | 61 | |
| 62 | fun maybe_instantiate ct thm = | |
| 63 | try Thm.first_order_match (Thm.cprop_of thm, ct) | |
| 64 | |> Option.map (fn inst => Thm.instantiate inst thm) | |
| 65 | ||
| 42322 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 66 | local | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 67 | fun instances_from_net match f net ct = | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 68 | let | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 69 | val lookup = if match then Net.match_term else Net.unify_term | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 70 | val xthms = lookup net (Thm.term_of ct) | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 71 | fun first_of f ct = get_first (f (maybe_instantiate ct)) xthms | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 72 | fun first_of' f ct = | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 73 | let val thm = Thm.trivial ct | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 74 | in get_first (f (try (fn rule => rule COMP thm))) xthms end | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 75 | in (case first_of f ct of NONE => first_of' f ct | some_thm => some_thm) end | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 76 | in | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 77 | |
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 78 | fun net_instance' f = instances_from_net false f | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 79 | |
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 80 | val net_instance = instances_from_net true I | 
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 81 | |
| 
be1c32069daa
use unification instead of matching to find proper assertions (which might not match original assumptions due to lambda-lifting and introduction of fresh variables)
 boehmes parents: 
41899diff
changeset | 82 | end | 
| 36898 | 83 | |
| 84 | ||
| 85 | ||
| 86 | (* proof combinators *) | |
| 87 | ||
| 88 | fun under_assumption f ct = | |
| 41328 
6792a5c92a58
avoid ML structure aliases (especially single-letter abbreviations)
 boehmes parents: 
41281diff
changeset | 89 | let val ct' = SMT_Utils.mk_cprop ct | 
| 36898 | 90 | in Thm.implies_intr ct' (f (Thm.assume ct')) end | 
| 91 | ||
| 92 | fun with_conv conv prove ct = | |
| 93 | let val eq = Thm.symmetric (conv ct) | |
| 94 | in Thm.equal_elim eq (prove (Thm.lhs_of eq)) end | |
| 95 | ||
| 96 | fun discharge p pq = Thm.implies_elim pq p | |
| 97 | ||
| 98 | fun varify vars = Drule.generalize ([], vars) | |
| 99 | ||
| 100 | fun unfold_eqs _ [] = Conv.all_conv | |
| 101 | | unfold_eqs ctxt eqs = | |
| 36936 
c52d1c130898
incorporated further conversions and conversionals, after some minor tuning;
 wenzelm parents: 
36899diff
changeset | 102 | Conv.top_sweep_conv (K (Conv.rewrs_conv eqs)) ctxt | 
| 36898 | 103 | |
| 104 | fun match_instantiate f ct thm = | |
| 105 | Thm.instantiate (Thm.match (f (Thm.cprop_of thm), ct)) thm | |
| 106 | ||
| 107 | fun by_tac tac ct = Goal.norm_result (Goal.prove_internal [] ct (K (tac 1))) | |
| 108 | ||
| 41123 | 109 | (* | 
| 110 | |- c x == t x ==> P (c x) | |
| 111 | --------------------------- | |
| 112 | c == t |- P (c x) | |
| 113 | *) | |
| 36898 | 114 | fun make_hyp_def thm ctxt = | 
| 115 | let | |
| 116 | val (lhs, rhs) = Thm.dest_binop (Thm.cprem_of thm 1) | |
| 117 | val (cf, cvs) = Drule.strip_comb lhs | |
| 41328 
6792a5c92a58
avoid ML structure aliases (especially single-letter abbreviations)
 boehmes parents: 
41281diff
changeset | 118 | val eq = SMT_Utils.mk_cequals cf (fold_rev Thm.cabs cvs rhs) | 
| 36898 | 119 | fun apply cv th = | 
| 120 | Thm.combination th (Thm.reflexive cv) | |
| 121 | |> Conv.fconv_rule (Conv.arg_conv (Thm.beta_conversion false)) | |
| 122 | in | |
| 123 | yield_singleton Assumption.add_assumes eq ctxt | |
| 124 | |>> Thm.implies_elim thm o fold apply cvs | |
| 125 | end | |
| 126 | ||
| 127 | ||
| 128 | ||
| 129 | (* abstraction *) | |
| 130 | ||
| 131 | local | |
| 132 | ||
| 133 | fun abs_context ctxt = (ctxt, Termtab.empty, 1, false) | |
| 134 | ||
| 135 | fun context_of (ctxt, _, _, _) = ctxt | |
| 136 | ||
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 137 | fun replace (_, (cv, ct)) = Thm.forall_elim ct o Thm.forall_intr cv | 
| 36898 | 138 | |
| 139 | fun abs_instantiate (_, tab, _, beta_norm) = | |
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 140 | fold replace (Termtab.dest tab) #> | 
| 36898 | 141 | beta_norm ? Conv.fconv_rule (Thm.beta_conversion true) | 
| 142 | ||
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 143 | fun lambda_abstract cvs t = | 
| 36898 | 144 | let | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 145 | val frees = map Free (Term.add_frees t []) | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 146 | val cvs' = filter (fn cv => member (op aconv) frees (Thm.term_of cv)) cvs | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 147 | val vs = map (Term.dest_Free o Thm.term_of) cvs' | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 148 | in (Term.list_abs_free (vs, t), cvs') end | 
| 36898 | 149 | |
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 150 | fun fresh_abstraction (_, cvs) ct (cx as (ctxt, tab, idx, beta_norm)) = | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 151 | let val (t, cvs') = lambda_abstract cvs (Thm.term_of ct) | 
| 36898 | 152 | in | 
| 153 | (case Termtab.lookup tab t of | |
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 154 | SOME (cv, _) => (Drule.list_comb (cv, cvs'), cx) | 
| 36898 | 155 | | NONE => | 
| 156 | let | |
| 157 | val (n, ctxt') = yield_singleton Variable.variant_fixes "x" ctxt | |
| 41328 
6792a5c92a58
avoid ML structure aliases (especially single-letter abbreviations)
 boehmes parents: 
41281diff
changeset | 158 | val cv = SMT_Utils.certify ctxt' | 
| 
6792a5c92a58
avoid ML structure aliases (especially single-letter abbreviations)
 boehmes parents: 
41281diff
changeset | 159 | (Free (n, map SMT_Utils.typ_of cvs' ---> SMT_Utils.typ_of ct)) | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 160 | val cu = Drule.list_comb (cv, cvs') | 
| 36898 | 161 | val e = (t, (cv, fold_rev Thm.cabs cvs' ct)) | 
| 162 | val beta_norm' = beta_norm orelse not (null cvs') | |
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 163 | in (cu, (ctxt', Termtab.update e tab, idx + 1, beta_norm')) end) | 
| 36898 | 164 | end | 
| 165 | ||
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 166 | fun abs_comb f g dcvs ct = | 
| 36898 | 167 | let val (cf, cu) = Thm.dest_comb ct | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 168 | in f dcvs cf ##>> g dcvs cu #>> uncurry Thm.capply end | 
| 36898 | 169 | |
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 170 | fun abs_arg f = abs_comb (K pair) f | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 171 | |
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 172 | fun abs_args f dcvs ct = | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 173 | (case Thm.term_of ct of | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 174 | _ $ _ => abs_comb (abs_args f) f dcvs ct | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 175 | | _ => pair ct) | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 176 | |
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 177 | fun abs_list f g dcvs ct = | 
| 36898 | 178 | (case Thm.term_of ct of | 
| 179 |     Const (@{const_name Nil}, _) => pair ct
 | |
| 180 |   | Const (@{const_name Cons}, _) $ _ $ _ =>
 | |
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 181 | abs_comb (abs_arg f) (abs_list f g) dcvs ct | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 182 | | _ => g dcvs ct) | 
| 36898 | 183 | |
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 184 | fun abs_abs f (depth, cvs) ct = | 
| 36898 | 185 | let val (cv, cu) = Thm.dest_abs NONE ct | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 186 | in f (depth, cv :: cvs) cu #>> Thm.cabs cv end | 
| 36898 | 187 | |
| 41899 
83dd157ec9ab
finished and tested Z3 proof reconstruction for injective functions;
 boehmes parents: 
41328diff
changeset | 188 | val is_atomic = | 
| 
83dd157ec9ab
finished and tested Z3 proof reconstruction for injective functions;
 boehmes parents: 
41328diff
changeset | 189 | (fn Free _ => true | Var _ => true | Bound _ => true | _ => false) | 
| 36898 | 190 | |
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 191 | fun abstract depth (ext_logic, with_theories) = | 
| 36898 | 192 | let | 
| 193 | fun abstr1 cvs ct = abs_arg abstr cvs ct | |
| 194 | and abstr2 cvs ct = abs_comb abstr1 abstr cvs ct | |
| 195 | and abstr3 cvs ct = abs_comb abstr2 abstr cvs ct | |
| 196 | and abstr_abs cvs ct = abs_arg (abs_abs abstr) cvs ct | |
| 197 | ||
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 198 | and abstr (dcvs as (d, cvs)) ct = | 
| 36898 | 199 | (case Thm.term_of ct of | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 200 |         @{const Trueprop} $ _ => abstr1 dcvs ct
 | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 201 |       | @{const "==>"} $ _ $ _ => abstr2 dcvs ct
 | 
| 40579 
98ebd2300823
use the const antiquotation for constants (this checks that the constant is declared, whereas the more general term antiquotation treats undeclared names as free variable)
 boehmes parents: 
40274diff
changeset | 202 |       | @{const True} => pair ct
 | 
| 
98ebd2300823
use the const antiquotation for constants (this checks that the constant is declared, whereas the more general term antiquotation treats undeclared names as free variable)
 boehmes parents: 
40274diff
changeset | 203 |       | @{const False} => pair ct
 | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 204 |       | @{const Not} $ _ => abstr1 dcvs ct
 | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 205 |       | @{const HOL.conj} $ _ $ _ => abstr2 dcvs ct
 | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 206 |       | @{const HOL.disj} $ _ $ _ => abstr2 dcvs ct
 | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 207 |       | @{const HOL.implies} $ _ $ _ => abstr2 dcvs ct
 | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 208 |       | Const (@{const_name HOL.eq}, _) $ _ $ _ => abstr2 dcvs ct
 | 
| 40681 
872b08416fb4
be more precise: only treat constant 'distinct' applied to an explicit list as built-in
 boehmes parents: 
40663diff
changeset | 209 |       | Const (@{const_name distinct}, _) $ _ =>
 | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 210 | if ext_logic then abs_arg (abs_list abstr fresh_abstraction) dcvs ct | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 211 | else fresh_abstraction dcvs ct | 
| 36898 | 212 |       | Const (@{const_name If}, _) $ _ $ _ $ _ =>
 | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 213 | if ext_logic then abstr3 dcvs ct else fresh_abstraction dcvs ct | 
| 36898 | 214 |       | Const (@{const_name All}, _) $ _ =>
 | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 215 | if ext_logic then abstr_abs dcvs ct else fresh_abstraction dcvs ct | 
| 36898 | 216 |       | Const (@{const_name Ex}, _) $ _ =>
 | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 217 | if ext_logic then abstr_abs dcvs ct else fresh_abstraction dcvs ct | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 218 | | t => (fn cx => | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 219 | if is_atomic t orelse can HOLogic.dest_number t then (ct, cx) | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 220 | else if with_theories andalso | 
| 41328 
6792a5c92a58
avoid ML structure aliases (especially single-letter abbreviations)
 boehmes parents: 
41281diff
changeset | 221 | Z3_Interface.is_builtin_theory_term (context_of cx) t | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 222 | then abs_args abstr dcvs ct cx | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 223 | else if d = 0 then fresh_abstraction dcvs ct cx | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 224 | else | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 225 | (case Term.strip_comb t of | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 226 | (Const _, _) => abs_args abstr (d-1, cvs) ct cx | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 227 | | (Free _, _) => abs_args abstr (d-1, cvs) ct cx | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 228 | | _ => fresh_abstraction dcvs ct cx))) | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 229 | in abstr (depth, []) end | 
| 36898 | 230 | |
| 40579 
98ebd2300823
use the const antiquotation for constants (this checks that the constant is declared, whereas the more general term antiquotation treats undeclared names as free variable)
 boehmes parents: 
40274diff
changeset | 231 | val cimp = Thm.cterm_of @{theory} @{const "==>"}
 | 
| 
98ebd2300823
use the const antiquotation for constants (this checks that the constant is declared, whereas the more general term antiquotation treats undeclared names as free variable)
 boehmes parents: 
40274diff
changeset | 232 | |
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 233 | fun deepen depth f x = | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 234 | if depth = 0 then f depth x | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 235 | else (case try (f depth) x of SOME y => y | NONE => deepen (depth - 1) f x) | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 236 | |
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 237 | fun with_prems depth thms f ct = | 
| 40579 
98ebd2300823
use the const antiquotation for constants (this checks that the constant is declared, whereas the more general term antiquotation treats undeclared names as free variable)
 boehmes parents: 
40274diff
changeset | 238 | fold_rev (Thm.mk_binop cimp o Thm.cprop_of) thms ct | 
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 239 | |> deepen depth f | 
| 36898 | 240 | |> fold (fn prem => fn th => Thm.implies_elim th prem) thms | 
| 241 | ||
| 242 | in | |
| 243 | ||
| 42992 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 244 | fun by_abstraction depth mode ctxt thms prove = | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 245 | with_prems depth thms (fn d => fn ct => | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 246 | let val (cu, cx) = abstract d mode ct (abs_context ctxt) | 
| 
4fc15e3217eb
iteratively deepen abstractions to avoid rare Z3 proof reconstruction failures, e.g. when pulling if-then-else from below uninterpreted constants (suggested by Jasmin Christian Blanchette)
 boehmes parents: 
42322diff
changeset | 247 | in abs_instantiate cx (prove (context_of cx) cu) end) | 
| 36898 | 248 | |
| 249 | end | |
| 250 | ||
| 251 | ||
| 252 | ||
| 253 | (* a faster COMP *) | |
| 254 | ||
| 255 | type compose_data = cterm list * (cterm -> cterm list) * thm | |
| 256 | ||
| 257 | fun list2 (x, y) = [x, y] | |
| 258 | ||
| 259 | fun precompose f rule = (f (Thm.cprem_of rule 1), f, rule) | |
| 260 | fun precompose2 f rule = precompose (list2 o f) rule | |
| 261 | ||
| 262 | fun compose (cvs, f, rule) thm = | |
| 263 | discharge thm (Thm.instantiate ([], cvs ~~ f (Thm.cprop_of thm)) rule) | |
| 264 | ||
| 265 | ||
| 266 | ||
| 267 | (* unfolding of 'distinct' *) | |
| 268 | ||
| 269 | local | |
| 270 |   val set1 = @{lemma "x ~: set [] == ~False" by simp}
 | |
| 271 |   val set2 = @{lemma "x ~: set [x] == False" by simp}
 | |
| 272 |   val set3 = @{lemma "x ~: set [y] == x ~= y" by simp}
 | |
| 273 |   val set4 = @{lemma "x ~: set (x # ys) == False" by simp}
 | |
| 274 |   val set5 = @{lemma "x ~: set (y # ys) == x ~= y & x ~: set ys" by simp}
 | |
| 275 | ||
| 276 | fun set_conv ct = | |
| 36936 
c52d1c130898
incorporated further conversions and conversionals, after some minor tuning;
 wenzelm parents: 
36899diff
changeset | 277 | (Conv.rewrs_conv [set1, set2, set3, set4] else_conv | 
| 36898 | 278 | (Conv.rewr_conv set5 then_conv Conv.arg_conv set_conv)) ct | 
| 279 | ||
| 40681 
872b08416fb4
be more precise: only treat constant 'distinct' applied to an explicit list as built-in
 boehmes parents: 
40663diff
changeset | 280 |   val dist1 = @{lemma "distinct [] == ~False" by (simp add: distinct_def)}
 | 
| 
872b08416fb4
be more precise: only treat constant 'distinct' applied to an explicit list as built-in
 boehmes parents: 
40663diff
changeset | 281 |   val dist2 = @{lemma "distinct [x] == ~False" by (simp add: distinct_def)}
 | 
| 
872b08416fb4
be more precise: only treat constant 'distinct' applied to an explicit list as built-in
 boehmes parents: 
40663diff
changeset | 282 |   val dist3 = @{lemma "distinct (x # xs) == x ~: set xs & distinct xs"
 | 
| 40274 
6486c610a549
introduced SMT.distinct as a representation of the solvers' built-in predicate; check that SMT.distinct is always applied to an explicit list
 boehmes parents: 
40164diff
changeset | 283 | by (simp add: distinct_def)} | 
| 36898 | 284 | |
| 285 | fun binop_conv cv1 cv2 = Conv.combination_conv (Conv.arg_conv cv1) cv2 | |
| 286 | in | |
| 287 | fun unfold_distinct_conv ct = | |
| 36936 
c52d1c130898
incorporated further conversions and conversionals, after some minor tuning;
 wenzelm parents: 
36899diff
changeset | 288 | (Conv.rewrs_conv [dist1, dist2] else_conv | 
| 36898 | 289 | (Conv.rewr_conv dist3 then_conv binop_conv set_conv unfold_distinct_conv)) ct | 
| 290 | end | |
| 291 | ||
| 292 | ||
| 293 | ||
| 294 | (* simpset *) | |
| 295 | ||
| 296 | local | |
| 297 |   val antisym_le1 = mk_meta_eq @{thm order_class.antisym_conv}
 | |
| 298 |   val antisym_le2 = mk_meta_eq @{thm linorder_class.antisym_conv2}
 | |
| 299 |   val antisym_less1 = mk_meta_eq @{thm linorder_class.antisym_conv1}
 | |
| 300 |   val antisym_less2 = mk_meta_eq @{thm linorder_class.antisym_conv3}
 | |
| 301 | ||
| 302 | fun eq_prop t thm = HOLogic.mk_Trueprop t aconv Thm.prop_of thm | |
| 303 | fun dest_binop ((c as Const _) $ t $ u) = (c, t, u) | |
| 304 |     | dest_binop t = raise TERM ("dest_binop", [t])
 | |
| 305 | ||
| 306 | fun prove_antisym_le ss t = | |
| 307 | let | |
| 308 | val (le, r, s) = dest_binop t | |
| 309 |       val less = Const (@{const_name less}, Term.fastype_of le)
 | |
| 310 | val prems = Simplifier.prems_of_ss ss | |
| 311 | in | |
| 312 | (case find_first (eq_prop (le $ s $ r)) prems of | |
| 313 | NONE => | |
| 314 | find_first (eq_prop (HOLogic.mk_not (less $ r $ s))) prems | |
| 315 | |> Option.map (fn thm => thm RS antisym_less1) | |
| 316 | | SOME thm => SOME (thm RS antisym_le1)) | |
| 317 | end | |
| 318 | handle THM _ => NONE | |
| 319 | ||
| 320 | fun prove_antisym_less ss t = | |
| 321 | let | |
| 322 | val (less, r, s) = dest_binop (HOLogic.dest_not t) | |
| 323 |       val le = Const (@{const_name less_eq}, Term.fastype_of less)
 | |
| 324 | val prems = prems_of_ss ss | |
| 325 | in | |
| 326 | (case find_first (eq_prop (le $ r $ s)) prems of | |
| 327 | NONE => | |
| 328 | find_first (eq_prop (HOLogic.mk_not (less $ s $ r))) prems | |
| 329 | |> Option.map (fn thm => thm RS antisym_less2) | |
| 330 | | SOME thm => SOME (thm RS antisym_le2)) | |
| 331 | end | |
| 332 | handle THM _ => NONE | |
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 333 | |
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 334 |   val basic_simpset = HOL_ss addsimps @{thms field_simps}
 | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 335 |     addsimps [@{thm times_divide_eq_right}, @{thm times_divide_eq_left}]
 | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 336 |     addsimps @{thms arith_special} addsimps @{thms less_bin_simps}
 | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 337 |     addsimps @{thms le_bin_simps} addsimps @{thms eq_bin_simps}
 | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 338 |     addsimps @{thms add_bin_simps} addsimps @{thms succ_bin_simps}
 | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 339 |     addsimps @{thms minus_bin_simps} addsimps @{thms pred_bin_simps}
 | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 340 |     addsimps @{thms mult_bin_simps} addsimps @{thms iszero_simps}
 | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 341 |     addsimps @{thms array_rules}
 | 
| 41281 
679118e35378
removed odd decoration of built-in symbols as Vars (instead provide built-in desctructor functions along with their inverse functions);
 boehmes parents: 
41172diff
changeset | 342 |     addsimps @{thms term_true_def} addsimps @{thms term_false_def}
 | 
| 37151 | 343 |     addsimps @{thms z3div_def} addsimps @{thms z3mod_def}
 | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 344 | addsimprocs [ | 
| 38715 
6513ea67d95d
renamed Simplifier.simproc(_i) to Simplifier.simproc_global(_i) to emphasize that this is not the real thing;
 wenzelm parents: 
37151diff
changeset | 345 |       Simplifier.simproc_global @{theory} "fast_int_arith" [
 | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 346 | "(m::int) < n", "(m::int) <= n", "(m::int) = n"] (K Lin_Arith.simproc), | 
| 38715 
6513ea67d95d
renamed Simplifier.simproc(_i) to Simplifier.simproc_global(_i) to emphasize that this is not the real thing;
 wenzelm parents: 
37151diff
changeset | 347 |       Simplifier.simproc_global @{theory} "antisym_le" ["(x::'a::order) <= y"]
 | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 348 | (K prove_antisym_le), | 
| 38715 
6513ea67d95d
renamed Simplifier.simproc(_i) to Simplifier.simproc_global(_i) to emphasize that this is not the real thing;
 wenzelm parents: 
37151diff
changeset | 349 |       Simplifier.simproc_global @{theory} "antisym_less" ["~ (x::'a::linorder) < y"]
 | 
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 350 | (K prove_antisym_less)] | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 351 | |
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 352 | structure Simpset = Generic_Data | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 353 | ( | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 354 | type T = simpset | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 355 | val empty = basic_simpset | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 356 | val extend = I | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 357 | val merge = Simplifier.merge_ss | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 358 | ) | 
| 36898 | 359 | in | 
| 360 | ||
| 36899 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 361 | fun add_simproc simproc = Simpset.map (fn ss => ss addsimprocs [simproc]) | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 362 | |
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 363 | fun make_simpset ctxt rules = | 
| 
bcd6fce5bf06
layered SMT setup, adapted SMT clients, added further tests, made Z3 proof abstraction configurable
 boehmes parents: 
36898diff
changeset | 364 | Simplifier.context ctxt (Simpset.get (Context.Proof ctxt)) addsimps rules | 
| 36898 | 365 | |
| 366 | end | |
| 367 | ||
| 368 | end |