haftmann@29650: (* Title: HOL/Library/reflection.ML haftmann@29650: Author: Amine Chaieb, TU Muenchen wenzelm@20319: wenzelm@20319: A trial for automatical reification. wenzelm@20319: *) wenzelm@20319: wenzelm@29269: signature REFLECTION = wenzelm@29269: sig wenzelm@20319: val genreify_tac: Proof.context -> thm list -> term option -> int -> tactic chaieb@23648: val reflection_tac: Proof.context -> thm list -> thm list -> term option -> int -> tactic haftmann@21878: val gen_reflection_tac: Proof.context -> (cterm -> thm) chaieb@23648: -> thm list -> thm list -> term option -> int -> tactic wenzelm@20319: end; wenzelm@20319: wenzelm@29269: structure Reflection : REFLECTION = wenzelm@29269: struct wenzelm@20319: haftmann@29650: val ext2 = @{thm ext2}; haftmann@29650: val nth_Cons_0 = @{thm nth_Cons_0}; haftmann@29650: val nth_Cons_Suc = @{thm nth_Cons_Suc}; wenzelm@21669: chaieb@20374: (* Make a congruence rule out of a defining equation for the interpretation *) chaieb@20374: (* th is one defining equation of f, i.e. chaieb@20374: th is "f (Cp ?t1 ... ?tn) = P(f ?t1, .., f ?tn)" *) chaieb@20374: (* Cp is a constructor pattern and P is a pattern *) chaieb@20374: chaieb@20374: (* The result is: chaieb@20374: [|?A1 = f ?t1 ; .. ; ?An= f ?tn |] ==> P (?A1, .., ?An) = f (Cp ?t1 .. ?tn) *) chaieb@20374: (* + the a list of names of the A1 .. An, Those are fresh in the ctxt*) chaieb@20374: hoelzl@31386: fun mk_congeq ctxt fs th = hoelzl@31386: let hoelzl@31386: val (f as Const(fN,fT)) = th |> prop_of |> HOLogic.dest_Trueprop |> HOLogic.dest_eq haftmann@29650: |> fst |> strip_comb |> fst chaieb@20374: val thy = ProofContext.theory_of ctxt chaieb@20374: val cert = Thm.cterm_of thy wenzelm@22568: val (((_,_),[th']), ctxt') = Variable.import_thms true [th] ctxt chaieb@20374: val (lhs, rhs) = HOLogic.dest_eq (HOLogic.dest_Trueprop (Thm.prop_of th')) hoelzl@31386: fun add_fterms (t as t1 $ t2) = wenzelm@29269: if exists (fn f => Term.could_unify (t |> strip_comb |> fst, f)) fs then insert (op aconv) t chaieb@20564: else add_fterms t1 #> add_fterms t2 hoelzl@31386: | add_fterms (t as Abs(xn,xT,t')) = wenzelm@29273: if exists_Const (fn (c, _) => c = fN) t then (fn _ => [t]) else (fn _ => []) chaieb@20374: | add_fterms _ = I chaieb@20374: val fterms = add_fterms rhs [] wenzelm@20797: val (xs, ctxt'') = Variable.variant_fixes (replicate (length fterms) "x") ctxt' chaieb@20374: val tys = map fastype_of fterms chaieb@20374: val vs = map Free (xs ~~ tys) chaieb@20374: val env = fterms ~~ vs hoelzl@31386: (* FIXME!!!!*) chaieb@20564: fun replace_fterms (t as t1 $ t2) = chaieb@20374: (case AList.lookup (op aconv) env t of chaieb@20374: SOME v => v chaieb@20564: | NONE => replace_fterms t1 $ replace_fterms t2) chaieb@20374: | replace_fterms t = (case AList.lookup (op aconv) env t of chaieb@20374: SOME v => v chaieb@20374: | NONE => t) hoelzl@31386: chaieb@20374: fun mk_def (Abs(x,xT,t),v) = HOLogic.mk_Trueprop ((HOLogic.all_const xT)$ Abs(x,xT,HOLogic.mk_eq(v$(Bound 0), t))) chaieb@20374: | mk_def (t, v) = HOLogic.mk_Trueprop (HOLogic.mk_eq (v, t)) chaieb@23605: fun tryext x = (x RS ext2 handle THM _ => x) chaieb@20374: val cong = (Goal.prove ctxt'' [] (map mk_def env) chaieb@20374: (HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, replace_fterms rhs))) hoelzl@31386: (fn x => LocalDefs.unfold_tac (#context x) (map tryext (#prems x)) chaieb@20374: THEN rtac th' 1)) RS sym hoelzl@31386: hoelzl@31386: val (cong' :: vars') = chaieb@20374: Variable.export ctxt'' ctxt (cong :: map (Drule.mk_term o cert) vs) chaieb@20374: val vs' = map (fst o fst o Term.dest_Var o Thm.term_of o Drule.dest_term) vars' hoelzl@31386: hoelzl@31386: in (vs', cong') end; wenzelm@20319: (* congs is a list of pairs (P,th) where th is a theorem for *) wenzelm@20319: (* [| f p1 = A1; ...; f pn = An|] ==> f (C p1 .. pn) = P *) wenzelm@20319: val FWD = curry (op OF); wenzelm@20319: wenzelm@20319: chaieb@20374: exception REIF of string; chaieb@20374: hoelzl@29834: fun dest_listT (Type ("List.list", [T])) = T; hoelzl@29834: hoelzl@31387: (* This modified version of divide_and_conquer allows the threading hoelzl@31387: of a state variable *) hoelzl@31387: fun divide_and_conquer' decomp (s, x) = hoelzl@31387: let val (ys, recomb) = decomp (s, x) hoelzl@31387: in recomb (Library.foldl_map (divide_and_conquer' decomp) ys) end; hoelzl@31387: hoelzl@31386: fun rearrange congs = hoelzl@31386: let hoelzl@31386: fun P (_, th) = hoelzl@31386: let val @{term "Trueprop"}$(Const ("op =",_) $l$_) = concl_of th hoelzl@31386: in can dest_Var l end hoelzl@31386: val (yes,no) = List.partition P congs hoelzl@31386: in no @ yes end hoelzl@29834: hoelzl@29834: fun genreif ctxt raw_eqs t = hoelzl@31386: let hoelzl@31387: fun index_of bds t = hoelzl@31386: let hoelzl@31386: val tt = HOLogic.listT (fastype_of t) hoelzl@31386: in hoelzl@31387: (case AList.lookup Type.could_unify bds tt of hoelzl@31386: NONE => error "index_of : type not found in environements!" hoelzl@31386: | SOME (tbs,tats) => hoelzl@31386: let hoelzl@31386: val i = find_index_eq t tats hoelzl@31386: val j = find_index_eq t tbs hoelzl@31387: in (if j = ~1 then hoelzl@31387: if i = ~1 hoelzl@31387: then (AList.update Type.could_unify (tt,(tbs,tats@[t])) bds, hoelzl@31386: length tbs + length tats) hoelzl@31387: else (bds, i) else (bds, j)) hoelzl@31386: end) hoelzl@31386: end; hoelzl@31386: hoelzl@31386: (* Generic decomp for reification : matches the actual term with the hoelzl@31386: rhs of one cong rule. The result of the matching guides the hoelzl@31386: proof synthesis: The matches of the introduced Variables A1 .. An are hoelzl@31386: processed recursively hoelzl@31386: The rest is instantiated in the cong rule,i.e. no reification is needed *) chaieb@20564: hoelzl@31386: (* da is the decomposition for atoms, ie. it returns ([],g) where g hoelzl@31386: returns the right instance f (AtC n) = t , where AtC is the Atoms hoelzl@31386: constructor and n is the number of the atom corresponding to t *) hoelzl@31387: fun decomp_genreif da cgns (bds, (t,ctxt)) = hoelzl@31386: let hoelzl@31386: val thy = ProofContext.theory_of ctxt chaieb@20374: val cert = cterm_of thy hoelzl@31387: fun tryabsdecomp (bds, (s,ctxt)) = hoelzl@31386: (case s of hoelzl@31386: Abs(xn,xT,ta) => ( hoelzl@31386: let hoelzl@31386: val ([xn],ctxt') = Variable.variant_fixes ["x"] ctxt hoelzl@31386: val (xn,ta) = variant_abs (xn,xT,ta) hoelzl@31386: val x = Free(xn,xT) hoelzl@31387: val bds = (case AList.lookup Type.could_unify bds (HOLogic.listT xT) hoelzl@31386: of NONE => error "tryabsdecomp: Type not found in the Environement" hoelzl@31386: | SOME (bsT,atsT) => hoelzl@31387: (AList.update Type.could_unify (HOLogic.listT xT, ((x::bsT), atsT)) bds)) hoelzl@31387: in ((bds, [(ta, ctxt')]), hoelzl@31387: fn (bds, [th]) => ( hoelzl@31387: (let val (bsT,asT) = the(AList.lookup Type.could_unify bds (HOLogic.listT xT)) hoelzl@31387: in AList.update Type.could_unify (HOLogic.listT xT,(tl bsT,asT)) bds hoelzl@31387: end), hoelzl@31387: hd (Variable.export ctxt' ctxt [(forall_intr (cert x) th) COMP allI]))) hoelzl@31386: end) hoelzl@31387: | _ => da (bds, (s,ctxt))) hoelzl@31386: in (case cgns of hoelzl@31387: [] => tryabsdecomp (bds, (t,ctxt)) hoelzl@31386: | ((vns,cong)::congs) => ((let hoelzl@31386: val cert = cterm_of thy hoelzl@31386: val certy = ctyp_of thy hoelzl@31386: val (tyenv, tmenv) = hoelzl@31386: Pattern.match thy hoelzl@31386: ((fst o HOLogic.dest_eq o HOLogic.dest_Trueprop) (concl_of cong), t) hoelzl@31386: (Envir.type_env (Envir.empty 0), Vartab.empty) hoelzl@31386: val (fnvs,invs) = List.partition (fn ((vn,_),_) => vn mem vns) (Vartab.dest tmenv) hoelzl@31386: val (fts,its) = hoelzl@31386: (map (snd o snd) fnvs, hoelzl@31386: map (fn ((vn,vi),(tT,t)) => (cert(Var ((vn,vi),tT)), cert t)) invs) hoelzl@31386: val ctyenv = map (fn ((vn,vi),(s,ty)) => (certy (TVar((vn,vi),s)), certy ty)) (Vartab.dest tyenv) hoelzl@31387: in ((bds, fts ~~ (replicate (length fts) ctxt)), hoelzl@31387: Library.apsnd (FWD (instantiate (ctyenv, its) cong))) hoelzl@31386: end) hoelzl@31387: handle MATCH => decomp_genreif da congs (bds, (t,ctxt)))) hoelzl@31386: end; chaieb@23648: chaieb@23648: (* looks for the atoms equation and instantiates it with the right number *) hoelzl@31387: fun mk_decompatom eqs (bds, (t,ctxt)) = ((bds, []), fn (bds, _) => hoelzl@31386: let hoelzl@31386: val tT = fastype_of t hoelzl@31386: fun isat eq = hoelzl@31386: let hoelzl@31386: val rhs = eq |> prop_of |> HOLogic.dest_Trueprop |> HOLogic.dest_eq |> snd hoelzl@31386: in exists_Const hoelzl@31386: (fn (n,ty) => n="List.nth" hoelzl@31386: andalso hoelzl@31387: AList.defined Type.could_unify bds (domain_type ty)) rhs hoelzl@31386: andalso Type.could_unify (fastype_of rhs, tT) hoelzl@31386: end hoelzl@31386: hoelzl@31386: fun get_nths t acc = hoelzl@31386: case t of hoelzl@31386: Const("List.nth",_)$vs$n => insert (fn ((a,_),(b,_)) => a aconv b) (t,(vs,n)) acc hoelzl@31386: | t1$t2 => get_nths t1 (get_nths t2 acc) hoelzl@31386: | Abs(_,_,t') => get_nths t' acc hoelzl@31386: | _ => acc chaieb@23548: hoelzl@31386: fun hoelzl@31387: tryeqs bds [] = error "Can not find the atoms equation" hoelzl@31387: | tryeqs bds (eq::eqs) = (( hoelzl@31386: let hoelzl@31386: val rhs = eq |> prop_of |> HOLogic.dest_Trueprop |> HOLogic.dest_eq |> snd hoelzl@31386: val nths = get_nths rhs [] hoelzl@31386: val (vss,ns) = fold_rev (fn (_,(vs,n)) => fn (vss,ns) => hoelzl@31386: (insert (op aconv) vs vss, insert (op aconv) n ns)) nths ([],[]) hoelzl@31386: val (vsns, ctxt') = Variable.variant_fixes (replicate (length vss) "vs") ctxt hoelzl@31386: val (xns, ctxt'') = Variable.variant_fixes (replicate (length nths) "x") ctxt' hoelzl@31386: val thy = ProofContext.theory_of ctxt'' hoelzl@31386: val cert = cterm_of thy hoelzl@31386: val certT = ctyp_of thy hoelzl@31386: val vsns_map = vss ~~ vsns hoelzl@31386: val xns_map = (fst (split_list nths)) ~~ xns hoelzl@31386: val subst = map (fn (nt, xn) => (nt, Var ((xn,0), fastype_of nt))) xns_map hoelzl@31386: val rhs_P = subst_free subst rhs hoelzl@31386: val (tyenv, tmenv) = Pattern.match hoelzl@31386: thy (rhs_P, t) hoelzl@31386: (Envir.type_env (Envir.empty 0), Vartab.empty) hoelzl@31386: val sbst = Envir.subst_vars (tyenv, tmenv) hoelzl@31386: val sbsT = Envir.typ_subst_TVars tyenv hoelzl@31386: val subst_ty = map (fn (n,(s,t)) => (certT (TVar (n, s)), certT t)) hoelzl@31386: (Vartab.dest tyenv) hoelzl@31386: val tml = Vartab.dest tmenv hoelzl@31386: val t's = map (fn xn => snd (valOf (AList.lookup (op =) tml (xn,0)))) xns (* FIXME : Express with sbst*) hoelzl@31387: val (bds, subst_ns) = Library.foldl_map hoelzl@31387: (fn (bds, (Const _ $ vs $ n, Var (xn0,T))) => hoelzl@31387: let hoelzl@31387: val name = snd (valOf (AList.lookup (op =) tml xn0)) hoelzl@31387: val (bds, idx) = index_of bds name hoelzl@31387: in (bds, (cert n, idx |> (HOLogic.mk_nat #> cert))) end) (bds, subst) hoelzl@31386: val subst_vs = hoelzl@31386: let hoelzl@31386: fun ty (Const _ $ (vs as Var (vsn,lT)) $ n, Var (xn0,T)) = (certT T, certT (sbsT T)) hoelzl@31386: fun h (Const _ $ (vs as Var (vsn,lT)) $ n, Var (xn0,T)) = hoelzl@31386: let hoelzl@31386: val cns = sbst (Const("List.list.Cons", T --> lT --> lT)) hoelzl@31386: val lT' = sbsT lT hoelzl@31387: val (bsT,asT) = the (AList.lookup Type.could_unify bds lT) hoelzl@31386: val vsn = valOf (AList.lookup (op =) vsns_map vs) hoelzl@31386: val cvs = cert (fold_rev (fn x => fn xs => cns$x$xs) bsT (Free (vsn, lT'))) hoelzl@31386: in (cert vs, cvs) end hoelzl@31386: in map h subst end hoelzl@31386: val cts = map (fn ((vn,vi),(tT,t)) => (cert(Var ((vn,vi),tT)), cert t)) hoelzl@31386: (fold (AList.delete (fn (((a: string),_),(b,_)) => a = b)) hoelzl@31386: (map (fn n => (n,0)) xns) tml) hoelzl@31386: val substt = hoelzl@31386: let val ih = Drule.cterm_rule (Thm.instantiate (subst_ty,[])) hoelzl@31386: in map (fn (v,t) => (ih v, ih t)) (subst_ns@subst_vs@cts) end hoelzl@31386: val th = (instantiate (subst_ty, substt) eq) RS sym hoelzl@31387: in (bds, hd (Variable.export ctxt'' ctxt [th])) end) hoelzl@31387: handle MATCH => tryeqs bds eqs) hoelzl@31387: in tryeqs bds (filter isat eqs) end); chaieb@20374: wenzelm@20319: (* Generic reification procedure: *) wenzelm@20319: (* creates all needed cong rules and then just uses the theorem synthesis *) chaieb@20564: hoelzl@31386: fun mk_congs ctxt raw_eqs = hoelzl@31386: let hoelzl@31386: val fs = fold_rev (fn eq => hoelzl@31386: insert (op =) (eq |> prop_of |> HOLogic.dest_Trueprop hoelzl@31386: |> HOLogic.dest_eq |> fst |> strip_comb hoelzl@31386: |> fst)) raw_eqs [] hoelzl@31386: val tys = fold_rev (fn f => fold (insert (op =)) (f |> fastype_of |> binder_types |> tl) hoelzl@31386: ) fs [] hoelzl@31386: val (vs, ctxt') = Variable.variant_fixes (replicate (length tys) "vs") ctxt hoelzl@31386: val thy = ProofContext.theory_of ctxt' hoelzl@31386: val cert = cterm_of thy hoelzl@31386: val vstys = map (fn (t,v) => (t,SOME (cert (Free(v,t))))) hoelzl@31386: (tys ~~ vs) hoelzl@31386: val is_Var = can dest_Var hoelzl@31386: fun insteq eq vs = hoelzl@31386: let hoelzl@31386: val subst = map (fn (v as Var(n,t)) => (cert v, (valOf o valOf) (AList.lookup (op =) vstys t))) hoelzl@31386: (filter is_Var vs) hoelzl@31386: in Thm.instantiate ([],subst) eq hoelzl@31386: end chaieb@20564: hoelzl@31387: val bds = AList.make (fn _ => ([],[])) tys hoelzl@31386: val eqs = map (fn eq => eq |> prop_of |> HOLogic.dest_Trueprop hoelzl@31386: |> HOLogic.dest_eq |> fst |> strip_comb |> snd |> tl hoelzl@31386: |> (insteq eq)) raw_eqs hoelzl@31386: val (ps,congs) = split_list (map (mk_congeq ctxt' fs) eqs) hoelzl@31387: in (bds, ps ~~ (Variable.export ctxt' ctxt congs)) hoelzl@31386: end hoelzl@31386: hoelzl@31387: val (bds, congs) = mk_congs ctxt raw_eqs hoelzl@31387: val congs = rearrange congs hoelzl@31387: val (bds, th) = divide_and_conquer' (decomp_genreif (mk_decompatom raw_eqs) congs) (bds, (t,ctxt)) hoelzl@31386: fun is_listVar (Var (_,t)) = can dest_listT t hoelzl@31386: | is_listVar _ = false hoelzl@31386: val vars = th |> prop_of |> HOLogic.dest_Trueprop |> HOLogic.dest_eq |> snd hoelzl@31386: |> strip_comb |> snd |> filter is_listVar hoelzl@31386: val cert = cterm_of (ProofContext.theory_of ctxt) hoelzl@31386: val cvs = map (fn (v as Var(n,t)) => (cert v, hoelzl@31387: the (AList.lookup Type.could_unify bds t) |> snd |> HOLogic.mk_list (dest_listT t) |> cert)) vars hoelzl@31386: val th' = instantiate ([], cvs) th hoelzl@31386: val t' = (fst o HOLogic.dest_eq o HOLogic.dest_Trueprop o prop_of) th' hoelzl@31386: val th'' = Goal.prove ctxt [] [] (HOLogic.mk_Trueprop (HOLogic.mk_eq (t, t'))) hoelzl@31386: (fn _ => simp_tac (local_simpset_of ctxt) 1) hoelzl@31386: in FWD trans [th'',th'] hoelzl@31386: end wenzelm@20319: chaieb@23648: chaieb@23648: fun genreflect ctxt conv corr_thms raw_eqs t = hoelzl@31386: let hoelzl@31386: val reifth = genreif ctxt raw_eqs t hoelzl@31386: fun trytrans [] = error "No suitable correctness theorem found" hoelzl@31386: | trytrans (th::ths) = hoelzl@31386: (FWD trans [reifth, th RS sym] handle THM _ => trytrans ths) hoelzl@31386: val th = trytrans corr_thms hoelzl@31386: val ft = (Thm.dest_arg1 o Thm.dest_arg o Thm.dest_arg o cprop_of) th hoelzl@31386: val rth = conv ft hoelzl@31386: in simplify (HOL_basic_ss addsimps raw_eqs addsimps [nth_Cons_0, nth_Cons_Suc]) hoelzl@31386: (simplify (HOL_basic_ss addsimps [rth]) th) hoelzl@31386: end wenzelm@20319: wenzelm@20319: fun genreify_tac ctxt eqs to i = (fn st => wenzelm@20319: let hoelzl@29805: fun P () = HOLogic.dest_Trueprop (List.nth (prems_of st, i - 1)) hoelzl@29805: val t = (case to of NONE => P () | SOME x => x) wenzelm@20319: val th = (genreif ctxt eqs t) RS ssubst wenzelm@20319: in rtac th i st wenzelm@20319: end); wenzelm@20319: wenzelm@20319: (* Reflection calls reification and uses the correctness *) wenzelm@20319: (* theorem assumed to be the dead of the list *) chaieb@23648: fun gen_reflection_tac ctxt conv corr_thms raw_eqs to i = (fn st => haftmann@21878: let haftmann@21878: val P = HOLogic.dest_Trueprop (nth (prems_of st) (i - 1)); haftmann@21878: val t = the_default P to; chaieb@23648: val th = genreflect ctxt conv corr_thms raw_eqs t haftmann@21878: RS ssubst; nipkow@23791: in (rtac th i THEN TRY(rtac TrueI i)) st end); haftmann@21878: nipkow@23791: fun reflection_tac ctxt = gen_reflection_tac ctxt Codegen.evaluation_conv; haftmann@30969: (*FIXME why Codegen.evaluation_conv? very specific...*) haftmann@29650: wenzelm@20797: end