diff options
| author | barras | 2006-09-26 11:18:22 +0000 |
|---|---|---|
| committer | barras | 2006-09-26 11:18:22 +0000 |
| commit | 351a500eada776832ac9b09657e42f5d6cd7210f (patch) | |
| tree | af45a745540e1154eab8955c17e03cbbe2e6b878 /contrib/setoid_ring/newring.ml4 | |
| parent | 5155de9ee4bd01127a57c36cebbd01c5d903d048 (diff) | |
mise a jour du nouveau ring et ajout du nouveau field, avant renommages
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@9178 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'contrib/setoid_ring/newring.ml4')
| -rw-r--r-- | contrib/setoid_ring/newring.ml4 | 978 |
1 files changed, 787 insertions, 191 deletions
diff --git a/contrib/setoid_ring/newring.ml4 b/contrib/setoid_ring/newring.ml4 index f35b457a58..7526cc8a6e 100644 --- a/contrib/setoid_ring/newring.ml4 +++ b/contrib/setoid_ring/newring.ml4 @@ -16,6 +16,7 @@ open Names open Term open Closure open Environ +open Libnames open Tactics open Rawterm open Tacticals @@ -27,11 +28,120 @@ open Setoid_replace open Proof_type open Coqlib open Tacmach -open Ppconstr open Mod_subst open Tacinterp open Libobject open Printer +open Declare +open Decl_kinds +open Entries + +(****************************************************************************) +(* controlled reduction *) + +let mark_arg i c = mkEvar(i,[|c|]);; +let unmark_arg f c = + match destEvar c with + | (i,[|c|]) -> f i c + | _ -> assert false;; + +type protect_flag = Eval|Prot|Rec ;; + +let tag_arg tag_rec map i c = + match map i with + Eval -> inject c + | Prot -> mk_atom c + | Rec -> if i = -1 then inject c else tag_rec c + +let rec mk_clos_but f_map t = + match f_map t with + | Some map -> tag_arg (mk_clos_but f_map) map (-1) t + | None -> + (match kind_of_term t with + App(f,args) -> mk_clos_app_but f_map f args 0 + | _ -> mk_atom t) + +and mk_clos_app_but f_map f args n = + if n >= Array.length args then mk_atom(mkApp(f, args)) + else + let fargs, args' = array_chop n args in + let f' = mkApp(f,fargs) in + match f_map f' with + Some map -> + mk_clos_deep + (fun _ -> unmark_arg (tag_arg (mk_clos_but f_map) map)) + (Esubst.ESID 0) + (mkApp (mark_arg (-1) f', Array.mapi mark_arg args')) + | None -> mk_clos_app_but f_map f args (n+1) +;; + +let interp_map l c = + try + let (im,am) = List.assoc c l in + Some(fun i -> + if List.mem i im then Eval + else if List.mem i am then Prot + else if i = -1 then Eval + else Rec) + with Not_found -> None + +let interp_map l t = + try Some(List.assoc t l) with Not_found -> None + +let protect_maps = ref ([]:(string*(constr->'a)) list) +let add_map s m = protect_maps := (s,m) :: !protect_maps +let lookup_map map = + try List.assoc map !protect_maps + with Not_found -> + errorlabstrm"lookup_map"(str"map "++qs map++str"not found") + +let protect_red map env sigma c = + kl (create_clos_infos betadeltaiota env) + (mk_clos_but (lookup_map map c) c);; + +let protect_tac map = + Tactics.reduct_option (protect_red map,DEFAULTcast) None ;; + +let protect_tac_in map id = + Tactics.reduct_option (protect_red map,DEFAULTcast) (Some(([],id),InHyp));; + + +TACTIC EXTEND protect_fv + [ "protect_fv" string(map) "in" ident(id) ] -> + [ protect_tac_in map id ] +| [ "protect_fv" string(map) ] -> + [ protect_tac map ] +END;; + +(****************************************************************************) + +let closed_term t l = + let l = List.map constr_of_global l in + let cs = List.fold_right Quote.ConstrSet.add l Quote.ConstrSet.empty in + if Quote.closed_under cs t then tclIDTAC else tclFAIL 0 (mt()) +;; + +TACTIC EXTEND closed_term + [ "closed_term" constr(t) "[" ne_reference_list(l) "]" ] -> + [ closed_term t l ] +END +;; +(* +let closed_term_ast l = + TacFun([Some(id_of_string"t")], + TacAtom(dummy_loc,TacExtend(dummy_loc,"closed_term", + [Genarg.in_gen Genarg.wit_constr (mkVar(id_of_string"t")); + Genarg.in_gen (Genarg.wit_list1 Genarg.wit_ref) l]))) +*) +let closed_term_ast l = + let l = List.map (fun gr -> ArgArg(dummy_loc,gr)) l in + TacFun([Some(id_of_string"t")], + TacAtom(dummy_loc,TacExtend(dummy_loc,"closed_term", + [Genarg.in_gen Genarg.globwit_constr (RVar(dummy_loc,id_of_string"t"),None); + Genarg.in_gen (Genarg.wit_list1 Genarg.globwit_ref) l]))) +(* +let _ = add_tacdef false ((dummy_loc,id_of_string"ring_closed_term" +*) (****************************************************************************) (* Library linking *) @@ -40,11 +150,15 @@ let contrib_name = "setoid_ring" let ring_dir = ["Coq";contrib_name] -let setoids_dir = ["Coq";"Setoids"] let ring_modules = [ring_dir@["BinList"];ring_dir@["Ring_th"];ring_dir@["Pol"]; - ring_dir@["Ring_tac"];ring_dir@["ZRing_th"]] -let stdlib_modules = [setoids_dir@["Setoid"]] + ring_dir@["Ring_tac"];ring_dir@["Field_tac"];ring_dir@["ZRing_th"]] +let stdlib_modules = + [["Coq";"Setoids";"Setoid"]; + ["Coq";"ZArith";"BinInt"]; + ["Coq";"ZArith";"Zbool"]; + ["Coq";"NArith";"BinNat"]; + ["Coq";"NArith";"BinPos"]] let coq_constant c = lazy (Coqlib.gen_constant_in_modules "Ring" stdlib_modules c) @@ -66,23 +180,18 @@ let carg c = TacDynamic(dummy_loc,Pretyping.constr_in c) let mk_cst l s = lazy (Coqlib.gen_constant "newring" l s);; let pol_cst s = mk_cst [contrib_name;"Pol"] s ;; -let ic c = - let env = Global.env() and sigma = Evd.empty in - Constrintern.interp_constr sigma env c - - (* Ring theory *) (* almost_ring defs *) let coq_almost_ring_theory = ring_constant "almost_ring_theory" let coq_ring_lemma1 = ring_constant "ring_correct" -let coq_ring_lemma2 = ring_constant "Pphi_dev_ok'" +let coq_ring_lemma2 = ring_constant "Pphi_dev_ok" let ring_comp1 = ring_constant "ring_id_correct" -let ring_comp2 = ring_constant "ring_rw_id_correct'" +let ring_comp2 = ring_constant "ring_rw_id_correct" let ring_abs1 = ringtac_constant "Zpol" "ring_gen_correct" -let ring_abs2 = ringtac_constant "Zpol" "ring_rw_gen_correct'" +let ring_abs2 = ringtac_constant "Zpol" "ring_rw_gen_correct" let sring_abs1 = ringtac_constant "Npol" "ring_gen_correct" -let sring_abs2 = ringtac_constant "Npol" "ring_rw_gen_correct'" +let sring_abs2 = ringtac_constant "Npol" "ring_rw_gen_correct" (* setoid and morphism utilities *) let coq_mk_Setoid = coq_constant "Build_Setoid_Theory" @@ -105,148 +214,138 @@ let coq_SRsub = ring_constant "SRsub" let coq_SRopp = ring_constant "SRopp" let coq_SReqe_Reqe = ring_constant "SReqe_Reqe" -let ltac_setoid_ring = ltac"Make_ring_tac" -let ltac_setoid_ring_rewrite = ltac"Make_ring_rw_list" +let ltac_setoid_ring = ltac"Ring" +let ltac_setoid_ring_rewrite = ltac"Ring_simplify" let ltac_inv_morphZ = zltac"inv_gen_phiZ" let ltac_inv_morphN = zltac"inv_gen_phiN" -let coq_cons = ring_constant "cons" -let coq_nil = ring_constant "nil" + +let list_dir = ["Lists";"List"] +(* let list_dir =[contrib_name;"BinList"] *) +let coq_cons = mk_cst list_dir "cons" +let coq_nil = mk_cst list_dir "nil" let lapp f args = mkApp(Lazy.force f,args) let dest_rel t = match kind_of_term t with App(f,args) when Array.length args >= 2 -> - mkApp(f,Array.sub args 0 (Array.length args - 2)) - | _ -> failwith "cannot find relation" - -(****************************************************************************) -(* controlled reduction *) - -let mark_arg i c = mkEvar(i,[|c|]);; -let unmark_arg f c = - match destEvar c with - | (i,[|c|]) -> f i c - | _ -> assert false;; - -type protect_flag = Eval|Prot|Rec ;; - -let tag_arg tag_rec map i c = - match map i with - Eval -> inject c - | Prot -> mk_atom c - | Rec -> if i = -1 then inject c else tag_rec c - -let rec mk_clos_but f_map t = - match f_map t with - | Some map -> tag_arg (mk_clos_but f_map) map (-1) t - | None -> - (match kind_of_term t with - App(f,args) -> mk_clos_app_but f_map f args 0 - (* unspecified constants are evaluated *) - | _ -> inject t) - -and mk_clos_app_but f_map f args n = - if n >= Array.length args then inject(mkApp(f, args)) - else - let fargs, args' = array_chop n args in - let f' = mkApp(f,fargs) in - match f_map f' with - Some map -> - mk_clos_deep - (fun _ -> unmark_arg (tag_arg (mk_clos_but f_map) map)) - (Esubst.ESID 0) - (mkApp (mark_arg (-1) f', Array.mapi mark_arg args')) - | None -> mk_clos_app_but f_map f args (n+1) -;; - -let interp_map l c = - try - let (im,am) = List.assoc c l in - Some(fun i -> - if List.mem i im then Eval - else if List.mem i am then Prot - else if i = -1 then Eval - else Rec) - with Not_found -> None - -let interp_map l t = - try Some(List.assoc t l) with Not_found -> None - -let arg_map = - [mk_cst [contrib_name;"BinList"] "cons",(function -1->Eval|2->Rec|_->Prot); - mk_cst [contrib_name;"BinList"] "nil", (function -1->Eval|_ -> Prot); - (* Pphi_dev: evaluate polynomial and coef operations, protect - ring operations and make recursive call on morphism and var map *) - pol_cst "Pphi_dev", (function -1|6|7|8|11->Eval|9|10->Rec|_->Prot); - (* PEeval: evaluate polynomial, protect ring operations - and make recursive call on morphism and var map *) - pol_cst "PEeval", (function -1|9->Eval|7|8->Rec|_->Prot); - (* Do not evaluate ring operations... *) - ring_constant "gen_phiZ", (function -1|6->Eval|_->Prot); - ring_constant "gen_phiN", (function -1|5->Eval|_->Prot); -];; + (mkApp(f,Array.sub args 0 (Array.length args - 2)), + args.(Array.length args - 2), + args.(Array.length args - 1)) + | _ -> error "ring: cannot find relation" (* Equality: do not evaluate but make recursive call on both sides *) -let is_ring_thm req = +let map_with_eq arg_map c = + let (req,_,_) = dest_rel c in interp_map ((req,(function -1->Prot|_->Rec)):: List.map (fun (c,map) -> (Lazy.force c,map)) arg_map) ;; -let protect_red env sigma c = - let req = dest_rel c in - kl (create_clos_infos betadeltaiota env) - (mk_clos_but (is_ring_thm req) c);; +let _ = add_map "ring" + (map_with_eq + [coq_cons,(function -1->Eval|2->Rec|_->Prot); + coq_nil, (function -1->Eval|_ -> Prot); + (* Pphi_dev: evaluate polynomial and coef operations, protect + ring operations and make recursive call on the var map *) + pol_cst "Pphi_dev", (function -1|6|7|8|9|11->Eval|10->Rec|_->Prot); + (* PEeval: evaluate morphism and polynomial, protect ring + operations and make recursive call on the var map *) + pol_cst "PEeval", (function -1|7|9->Eval|8->Rec|_->Prot)]);; + +let ic c = + let env = Global.env() and sigma = Evd.empty in + Constrintern.interp_constr sigma env c -let protect_tac = - Tactics.reduct_option (protect_red,DEFAULTcast) None ;; +let ty c = Typing.type_of (Global.env()) Evd.empty c -let protect_tac_in id = - Tactics.reduct_option (protect_red,DEFAULTcast) (Some(([],id),InHyp));; +let decl_constant na c = + mkConst(declare_constant (id_of_string na) (DefinitionEntry + { const_entry_body = c; + const_entry_type = None; + const_entry_opaque = true; + const_entry_boxed = true}, + IsProof Lemma)) -TACTIC EXTEND protect_fv - [ "protect_fv" "in" ident(id) ] -> - [ protect_tac_in id ] -| [ "protect_fv" ] -> - [ protect_tac ] -END;; +let ltac_call tac args = + TacArg(TacCall(dummy_loc, ArgArg(dummy_loc, Lazy.force tac),args)) (****************************************************************************) (* Ring database *) -let ty c = Typing.type_of (Global.env()) Evd.empty c - - type ring_info = { ring_carrier : types; ring_req : constr; ring_cst_tac : glob_tactic_expr; ring_lemma1 : constr; - ring_lemma2 : constr } + ring_lemma2 : constr; + ring_pre_tac : glob_tactic_expr; + ring_post_tac : glob_tactic_expr } module Cmap = Map.Make(struct type t = constr let compare = compare end) let from_carrier = ref Cmap.empty let from_relation = ref Cmap.empty +let from_name = ref Spmap.empty + +let ring_for_carrier r = Cmap.find r !from_carrier +let ring_for_relation rel = Cmap.find rel !from_relation +let ring_lookup_by_name ref = + Spmap.find (Nametab.locate_obj (snd(qualid_of_reference ref))) !from_name + + +let find_ring_structure env sigma l cl oname = + match oname, l with + Some rf, _ -> + (try ring_lookup_by_name rf + with Not_found -> + errorlabstrm "ring" + (str "found no ring named "++pr_reference rf)) + | None, t::cl' -> + let ty = Retyping.get_type_of env sigma t in + let check c = + let ty' = Retyping.get_type_of env sigma c in + if not (Reductionops.is_conv env sigma ty ty') then + errorlabstrm "ring" + (str"arguments of ring_simplify do not have all the same type") + in + List.iter check cl'; + (try ring_for_carrier ty + with Not_found -> + errorlabstrm "ring" + (str"cannot find a declared ring structure over"++ + spc()++str"\""++pr_constr ty++str"\"")) + | None, [] -> + let (req,_,_) = dest_rel cl in + (try ring_for_relation req + with Not_found -> + errorlabstrm "ring" + (str"cannot find a declared ring structure for equality"++ + spc()++str"\""++pr_constr req++str"\"")) let _ = Summary.declare_summary "tactic-new-ring-table" - { Summary.freeze_function = (fun () -> !from_carrier,!from_relation); + { Summary.freeze_function = + (fun () -> !from_carrier,!from_relation,!from_name); Summary.unfreeze_function = - (fun (ct,rt) -> from_carrier := ct; from_relation := rt); + (fun (ct,rt,nt) -> + from_carrier := ct; from_relation := rt; from_name := nt); Summary.init_function = - (fun () -> from_carrier := Cmap.empty; from_relation := Cmap.empty); + (fun () -> + from_carrier := Cmap.empty; from_relation := Cmap.empty; + from_name := Spmap.empty); Summary.survive_module = false; Summary.survive_section = false } -let add_entry _ e = - let _ = ty e.ring_lemma1 in +let add_entry (sp,_kn) e = +(* let _ = ty e.ring_lemma1 in let _ = ty e.ring_lemma2 in +*) from_carrier := Cmap.add e.ring_carrier e !from_carrier; - from_relation := Cmap.add e.ring_req e !from_relation + from_relation := Cmap.add e.ring_req e !from_relation; + from_name := Spmap.add sp e !from_name let subst_th (_,subst,th) = @@ -255,17 +354,23 @@ let subst_th (_,subst,th) = let thm1' = subst_mps subst th.ring_lemma1 in let thm2' = subst_mps subst th.ring_lemma2 in let tac'= subst_tactic subst th.ring_cst_tac in + let pretac'= subst_tactic subst th.ring_pre_tac in + let posttac'= subst_tactic subst th.ring_post_tac in if c' == th.ring_carrier && eq' == th.ring_req && thm1' == th.ring_lemma1 && thm2' == th.ring_lemma2 && - tac' == th.ring_cst_tac then th + tac' == th.ring_cst_tac && + pretac' == th.ring_pre_tac && + posttac' == th.ring_post_tac then th else { ring_carrier = c'; ring_req = eq'; ring_cst_tac = tac'; ring_lemma1 = thm1'; - ring_lemma2 = thm2' } + ring_lemma2 = thm2'; + ring_pre_tac = pretac'; + ring_post_tac = posttac' } let (theory_to_obj, obj_to_theory) = @@ -280,10 +385,6 @@ let (theory_to_obj, obj_to_theory) = export_function = export_th } -let ring_for_carrier r = Cmap.find r !from_carrier - -let ring_for_relation rel = Cmap.find rel !from_relation - let setoid_of_relation r = lapp coq_mk_Setoid [|r.rel_a; r.rel_aeq; @@ -293,14 +394,16 @@ let op_morph r add mul opp req m1 m2 m3 = lapp coq_mk_reqe [| r; add; mul; opp; req; m1; m2; m3 |] let op_smorph r add mul req m1 m2 = - lapp coq_SReqe_Reqe - [| r;add;mul;req;lapp coq_mk_seqe [| r; add; mul; req; m1; m2 |]|] + lapp coq_mk_seqe [| r; add; mul; req; m1; m2 |] + +let smorph2morph r add mul req sm = + lapp coq_SReqe_Reqe [| r;add;mul;req;sm|] let sr_sub r add = lapp coq_SRsub [|r;add|] let sr_opp r = lapp coq_SRopp [|r|] -let dest_morphism kind th sth = - let th_typ = Retyping.get_type_of (Global.env()) Evd.empty th in +let dest_morphism env sigma kind th sth = + let th_typ = Retyping.get_type_of env sigma th in match kind_of_term th_typ with App(f,[|_;_;_;_;_;_;_;_;c;czero;cone;cadd;cmul;csub;copp;ceqb;phi|]) when f = Lazy.force coq_ring_morph -> @@ -311,16 +414,21 @@ let dest_morphism kind th sth = lapp coq_SRmorph_Rmorph [|r;zero;one;add;mul;req;sth;c;czero;cone;cadd;cmul;ceqb;phi;th|]in (th,[|c;czero;cone;cadd;cmul;cadd;sr_opp c;ceqb;phi|]) - | _ -> failwith "bad ring_morph lemma" + | _ -> error "bad ring_morph lemma" -let dest_eq_test th = - let th_typ = Retyping.get_type_of (Global.env()) Evd.empty th in +let dest_eq_test env sigma th = + let th_typ = Retyping.get_type_of env sigma th in match decompose_prod th_typ with (_,h)::_,_ -> (match snd(destApplication h) with - [|_;lhs;_|] -> fst(destApplication lhs) - | _ -> failwith "bad lemma for decidability of equality") - | _ -> failwith "bad lemma for decidability of equality" + [|_;lhs;_|] -> + let (f,args) = destApplication lhs in + if Array.length args < 2 then + error "bad lemma for decidability of equality" + else + mkApp(f,Array.sub args 0 (Array.length args -2)) + | _ -> error "bad lemma for decidability of equality") + | _ -> error "bad lemma for decidability of equality" let default_ring_equality is_semi (r,add,mul,opp,req) = let is_setoid = function @@ -348,7 +456,10 @@ let default_ring_equality is_semi (r,add,mul,opp,req) = error "ring multiplication should be declared as a morphism" in let op_morph = if is_semi <> Some true then - (let opp_m = default_morphism ~filter:is_endomorphism opp in + (let opp_m = + try default_morphism ~filter:is_endomorphism opp + with Not_found -> + error "ring opposite should be declared as a morphism" in let op_morph = op_morph r add mul opp req add_m.lem mul_m.lem opp_m.lem in msgnl @@ -372,8 +483,8 @@ let build_setoid_params is_semi r add mul opp req eqth = Some th -> th | None -> default_ring_equality is_semi (r,add,mul,opp,req) -let dest_ring th_spec = - let th_typ = Retyping.get_type_of (Global.env()) Evd.empty th_spec in +let dest_ring env sigma th_spec = + let th_typ = Retyping.get_type_of env sigma th_spec in match kind_of_term th_typ with App(f,[|r;zero;one;add;mul;sub;opp;req|]) when f = Lazy.force coq_almost_ring_theory -> @@ -403,42 +514,91 @@ type coeff_spec = type cst_tac_spec = CstTac of raw_tactic_expr - | Closed of constr list - - -let add_theory name rth eqth morphth cst_tac = - Coqlib.check_required_library ["Coq";"setoid_ring";"Ring_tac"]; - let (kind,r,zero,one,add,mul,sub,opp,req) = dest_ring rth in + | Closed of reference list + +(* +let ring_equiv_constant c = + lazy (Coqlib.gen_constant_in_modules "Ring" [ring_dir@["Ring_equiv"]] c) +let ring_def_eqb_ok = ring_equiv_constant "default_eqb_ok" +let ring_equiv2 = ring_equiv_constant "ring_equiv2" +let sring_equiv2 = ring_equiv_constant "sring_equiv2" +let ring_m_plus = ring_constant "Radd_ext" +let ring_m_mul = ring_constant "Rmul_ext" +let ring_m_opp = ring_constant "Ropp_ext" + +let old_morph is_semi r add mul opp req morph = + { Ring.plusm = lapp ring_m_plus [|r;add;mul;opp;req;morph|]; + Ring.multm = lapp ring_m_mul [|r;add;mul;opp;req;morph|]; + Ring.oppm = + if is_semi then None + else Some (lapp ring_m_opp [|r;add;mul;opp;req;morph|]) + } + +let add_old_theory env sigma is_semi is_setoid + r zero one add mul sub opp req rth sth ops_morph morphth = +(try + let opp_o = if is_semi then None else Some opp in + let (is_abs, eqb_ok) = + match morphth with + Computational c -> (false, c) + | _ -> (true, lapp ring_def_eqb_ok [|r|]) in + let eqb = dest_eq_test env sigma eqb_ok in + let rth = + if is_setoid then failwith "not impl" + else + if is_semi then + lapp sring_equiv2 [|r;zero;one;add;mul;rth;eqb;eqb_ok|] + else + lapp ring_equiv2 [|r;zero;one;add;mul;sub;opp;rth;eqb;eqb_ok|] in + Ring.add_theory (not is_semi) is_abs is_setoid r + (Some req) (Some sth) + (if is_setoid then Some(old_morph is_semi r add mul opp req ops_morph) + else None) + add mul one zero opp_o eqb rth Quote.ConstrSet.empty +with _ -> + prerr_endline "Warning: could not add old ring structure") +*) + +let add_theory name rth eqth morphth cst_tac (pre,post) = + let env = Global.env() in + let sigma = Evd.empty in + let (kind,r,zero,one,add,mul,sub,opp,req) = dest_ring env sigma rth in let (sth,morph) = build_setoid_params kind r add mul opp req eqth in let args0 = [|r;zero;one;add;mul;sub;opp;req;sth;morph|] in + let args0' = [|r;zero;one;add;mul;req;sth;morph|] in let (lemma1,lemma2) = match morphth with | Computational c -> - let reqb = dest_eq_test c in + let reqb = dest_eq_test env sigma c in let rth = build_almost_ring kind r zero one add mul sub opp req sth morph rth in let args = Array.append args0 [|rth;reqb;c|] in (lapp ring_comp1 args, lapp ring_comp2 args) | Morphism m -> - let (m,args1) = dest_morphism kind m sth in + let (m,args1) = dest_morphism env sigma kind m sth in let rth = build_almost_ring kind r zero one add mul sub opp req sth morph rth in let args = Array.concat [args0;[|rth|]; args1; [|m|]] in (lapp coq_ring_lemma1 args, lapp coq_ring_lemma2 args) | Abstract -> - Coqlib.check_required_library ["Coq";"setoid_ring";"ZRing_th"]; - let args1 = Array.append args0 [|rth|] in + (try check_required_library (ring_dir@["Ring"]) + with UserError _ -> + error "You must require \"Ring\" to declare an abstract ring"); (match kind with None -> error "an almost_ring cannot be abstract" | Some true -> + let args1 = Array.append args0' [|rth|] in (lapp sring_abs1 args1, lapp sring_abs2 args1) | Some false -> + let args1 = Array.append args0 [|rth|] in (lapp ring_abs1 args1, lapp ring_abs2 args1)) in + let lemma1 = decl_constant (string_of_id name^"_ring_lemma1") lemma1 in + let lemma2 = decl_constant (string_of_id name^"_ring_lemma2") lemma2 in let cst_tac = match cst_tac with Some (CstTac t) -> Tacinterp.glob_tactic t - | Some (Closed lc) -> failwith "TODO" + | Some (Closed lc) -> closed_term_ast (List.map Nametab.global lc) | None -> (match kind with Some true -> @@ -448,6 +608,14 @@ let add_theory name rth eqth morphth cst_tac = let t = ArgArg(dummy_loc, Lazy.force ltac_inv_morphZ) in TacArg(TacCall(dummy_loc,t,List.map carg [zero;one;add;mul;opp])) | _ -> error"a tactic must be specified for an almost_ring") in + let pretac = + match pre with + Some t -> Tacinterp.glob_tactic t + | _ -> TacId [] in + let posttac = + match post with + Some t -> Tacinterp.glob_tactic t + | _ -> TacId [] in let _ = Lib.add_leaf name (theory_to_obj @@ -455,71 +623,499 @@ let add_theory name rth eqth morphth cst_tac = ring_req = req; ring_cst_tac = cst_tac; ring_lemma1 = lemma1; - ring_lemma2 = lemma2 }) in + ring_lemma2 = lemma2; + ring_pre_tac = pretac; + ring_post_tac = posttac }) in + (* old ring theory *) +(* let _ = + match kind with + Some is_semi -> + add_old_theory env sigma is_semi (eqth <> None) + r zero one add mul sub opp req rth sth morph morphth + | _ -> () in +*) () -VERNAC ARGUMENT EXTEND ring_coefs -| [ "Computational" constr(c)] -> [ Computational (ic c) ] -| [ "Abstract" ] -> [ Abstract ] -| [ "Coefficients" constr(m)] -> [ Morphism (ic m) ] -| [ ] -> [ Abstract ] +type ring_mod = + Ring_kind of coeff_spec + | Const_tac of cst_tac_spec + | Pre_tac of raw_tactic_expr + | Post_tac of raw_tactic_expr + | Setoid of Topconstr.constr_expr * Topconstr.constr_expr + +VERNAC ARGUMENT EXTEND ring_mod + | [ "decidable" constr(eq_test) ] -> [ Ring_kind(Computational (ic eq_test)) ] + | [ "abstract" ] -> [ Ring_kind Abstract ] + | [ "morphism" constr(morph) ] -> [ Ring_kind(Morphism (ic morph)) ] + | [ "constants" "[" tactic(cst_tac) "]" ] -> [ Const_tac(CstTac cst_tac) ] + | [ "closed" "[" ne_global_list(l) "]" ] -> [ Const_tac(Closed l) ] + | [ "preprocess" "[" tactic(pre) "]" ] -> [ Pre_tac pre ] + | [ "postprocess" "[" tactic(post) "]" ] -> [ Post_tac post ] + | [ "setoid" constr(sth) constr(ext) ] -> [ Setoid(sth,ext) ] END -VERNAC ARGUMENT EXTEND ring_cst_tac -| [ "Constant" tactic(c)] -> [ Some(CstTac c) ] -| [ "[" ne_constr_list(l) "]" ] -> [ Some(Closed (List.map ic l)) ] -| [ ] -> [ None ] -END +let set_once s r v = + if !r = None then r := Some v else error (s^" cannot be set twice") + +let process_ring_mods l = + let kind = ref None in + let set = ref None in + let cst_tac = ref None in + let pre = ref None in + let post = ref None in + List.iter(function + Ring_kind k -> set_once "ring kind" kind k + | Const_tac t -> set_once "tactic recognizing constants" cst_tac t + | Pre_tac t -> set_once "preprocess tactic" pre t + | Post_tac t -> set_once "postprocess tactic" post t + | Setoid(sth,ext) -> set_once "setoid" set (ic sth,ic ext)) l; + let k = match !kind with Some k -> k | None -> Abstract in + (k, !set, !cst_tac, !pre, !post) VERNAC COMMAND EXTEND AddSetoidRing -| [ "Add" "New" "Ring" ident(id) ":" constr(t) ring_coefs(c) - "Setoid" constr(e) constr(m) ring_cst_tac(tac) ] -> - [ add_theory id (ic t) (Some (ic e, ic m)) c tac ] -| [ "Add" "New" "Ring" ident(id) ":" constr(t) ring_coefs(c) - ring_cst_tac(tac) ] -> - [ add_theory id (ic t) None c tac ] + | [ "Add" "Ring" ident(id) ":" constr(t) ring_mods(l) ] -> + [ let (k,set,cst,pre,post) = process_ring_mods l in + add_theory id (ic t) set k cst (pre,post) ] END - (*****************************************************************************) (* The tactics consist then only in a lookup in the ring database and call the appropriate ltac. *) let ring gl = - let req = dest_rel (pf_concl gl) in - let e = - try ring_for_relation req - with Not_found -> - errorlabstrm "ring" - (str"cannot find a declared ring structure for equality"++ - spc()++str"\""++pr_constr req++str"\"") in - Tacinterp.eval_tactic - (TacArg(TacCall(dummy_loc, - ArgArg(dummy_loc, Lazy.force ltac_setoid_ring), - Tacexp e.ring_cst_tac:: - List.map carg [e.ring_lemma1;e.ring_lemma2;e.ring_req]))) - gl - -let ring_rewrite rl = - let ty = Retyping.get_type_of (Global.env()) Evd.empty (List.hd rl) in - let e = - try ring_for_carrier ty - with Not_found -> - errorlabstrm "ring" - (str"cannot find a declared ring structure over"++ - spc()++str"\""++pr_constr ty++str"\"") in - let rl = List.fold_right (fun x l -> lapp coq_cons [|ty;x;l|]) rl - (lapp coq_nil [|ty|]) in + let env = pf_env gl in + let sigma = project gl in + let e = find_ring_structure env sigma [] (pf_concl gl) None in + let main_tac = + ltac_call ltac_setoid_ring + (Tacexp e.ring_cst_tac:: List.map carg [e.ring_lemma1;e.ring_req]) in + Tacinterp.eval_tactic (TacThen(e.ring_pre_tac,main_tac)) gl + +let ring_rewrite rl gl = + let env = pf_env gl in + let sigma = project gl in + let e = find_ring_structure env sigma rl (pf_concl gl) None in + let rl = + match rl with + [] -> let (_,t1,t2) = dest_rel (pf_concl gl) in [t1;t2] + | _ -> rl in + let rl = List.fold_right + (fun x l -> lapp coq_cons [|e.ring_carrier;x;l|]) rl + (lapp coq_nil [|e.ring_carrier|]) in + let main_tac = + ltac_call ltac_setoid_ring_rewrite + (Tacexp e.ring_cst_tac::List.map carg [e.ring_lemma2;e.ring_req;rl]) in Tacinterp.eval_tactic - (TacArg(TacCall(dummy_loc, - ArgArg(dummy_loc, Lazy.force ltac_setoid_ring_rewrite), - Tacexp e.ring_cst_tac::List.map carg [e.ring_lemma2;e.ring_req;rl]))) - -let setoid_ring = function - | [] -> ring - | l -> ring_rewrite l + (TacThen(e.ring_pre_tac,TacThen(main_tac,e.ring_post_tac))) gl TACTIC EXTEND setoid_ring - [ "setoid" "ring" constr_list(l) ] -> [ setoid_ring l ] + [ "ring" ] -> [ ring ] +| [ "ring_simplify" constr_list(l) ] -> [ ring_rewrite l ] +END + +(***********************************************************************) +let fld_cst s = mk_cst [contrib_name;"NewField"] s ;; + +let field_modules = List.map + (fun f -> ["Coq";contrib_name;f]) + ["NewField";"Field_tac"] + +let new_field_path = + make_dirpath (List.map id_of_string ["Field_tac";contrib_name;"Coq"]) + +let field_constant c = + lazy (Coqlib.gen_constant_in_modules "Field" field_modules c) + +let field_ltac s = + lazy(make_kn (MPfile new_field_path) (make_dirpath []) (mk_label s)) + +let field_lemma = field_constant "Fnorm_correct2" +let field_simplify_eq_lemma = field_constant "Field_simplify_eq_correct" +let field_simplify_lemma = field_constant "Pphi_dev_div_ok" + +let afield_theory = field_constant "almost_field_theory" +let field_theory = field_constant "field_theory" +let sfield_theory = field_constant "semi_field_theory" +let field_Rth = field_constant "AF_AR" + +let field_tac = field_ltac "Make_field_tac" +let field_simplify_eq_tac = field_ltac "Make_field_simplify_eq_tac" +let field_simplify_tac = field_ltac "Make_field_simplify_tac" + + +let _ = add_map "field" + (map_with_eq + [coq_cons,(function -1->Eval|2->Rec|_->Prot); + coq_nil, (function -1->Eval|_ -> Prot); + (* Pphi_dev: evaluate polynomial and coef operations, protect + ring operations and make recursive call on the var map *) + pol_cst "Pphi_dev", (function -1|6|7|8|9|11->Eval|10->Rec|_->Prot); + (* PEeval: evaluate morphism and polynomial, protect ring + operations and make recursive call on the var map *) + pol_cst "PEeval", (function -1|7|9->Eval|8->Rec|_->Prot); +(* fld_cst "FEeval", (function -1|9|11->Eval|10->Rec|_->Prot);*) + (* PCond: evaluate morphism and denum list, protect ring + operations and make recursive call on the var map *) + fld_cst "PCond", (function -1|8|10->Eval|9->Rec|_->Prot)]);; + + +let dest_field env sigma th_spec = + let th_typ = Retyping.get_type_of env sigma th_spec in + match kind_of_term th_typ with + | App(f,[|r;zero;one;add;mul;sub;opp;div;inv;req|]) + when f = Lazy.force afield_theory -> + let rth = lapp field_Rth + [|r;zero;one;add;mul;sub;opp;div;inv;req;th_spec|] in + (None,r,zero,one,add,mul,sub,opp,div,inv,req,rth) + | App(f,[|r;zero;one;add;mul;sub;opp;div;inv;req|]) + when f = Lazy.force field_theory -> + let rth = + lapp (field_constant"F_R") + [|r;zero;one;add;mul;sub;opp;div;inv;req;th_spec|] in + (Some false,r,zero,one,add,mul,sub,opp,div,inv,req,rth) + | App(f,[|r;zero;one;add;mul;div;inv;req|]) + when f = Lazy.force sfield_theory -> + let rth = lapp (field_constant"SF_SR") + [|r;zero;one;add;mul;div;inv;req;th_spec|] in + (Some true,r,zero,one,add,mul,sr_sub r add,sr_opp r,div,inv,req,rth) + | _ -> error "bad field structure" + +let build_almost_field + kind r zero one add mul sub opp div inv req sth morph th = + match kind with + None -> th + | Some true -> + lapp (field_constant "SF2AF") + [|r;zero;one;add;mul;div;inv;req;sth;th|] + | Some false -> + lapp (field_constant "F2AF") + [|r;zero;one;add;mul;sub;opp;div;inv;req;sth;morph;th|] + +type field_info = + { field_carrier : types; + field_req : constr; + field_cst_tac : glob_tactic_expr; + field_ok : constr; + field_simpl_eq_ok : constr; + field_simpl_ok : constr; + field_cond : constr; + field_pre_tac : glob_tactic_expr; + field_post_tac : glob_tactic_expr } + +let field_from_carrier = ref Cmap.empty +let field_from_relation = ref Cmap.empty +let field_from_name = ref Spmap.empty + + +let field_for_carrier r = Cmap.find r !field_from_carrier +let field_for_relation rel = Cmap.find rel !field_from_relation +let field_lookup_by_name ref = + Spmap.find (Nametab.locate_obj (snd(qualid_of_reference ref))) + !field_from_name + + +let find_field_structure env sigma l cl oname = + check_required_library (ring_dir@["Field_tac"]); + match oname, l with + Some rf, _ -> + (try field_lookup_by_name rf + with Not_found -> + errorlabstrm "field" + (str "found no field named "++pr_reference rf)) + | None, t::cl' -> + let ty = Retyping.get_type_of env sigma t in + let check c = + let ty' = Retyping.get_type_of env sigma c in + if not (Reductionops.is_conv env sigma ty ty') then + errorlabstrm "field" + (str"arguments of field_simplify do not have all the same type") + in + List.iter check cl'; + (try field_for_carrier ty + with Not_found -> + errorlabstrm "field" + (str"cannot find a declared field structure over"++ + spc()++str"\""++pr_constr ty++str"\"")) + | None, [] -> + let (req,_,_) = dest_rel cl in + (try field_for_relation req + with Not_found -> + errorlabstrm "field" + (str"cannot find a declared field structure for equality"++ + spc()++str"\""++pr_constr req++str"\"")) + +let _ = + Summary.declare_summary "tactic-new-field-table" + { Summary.freeze_function = + (fun () -> !field_from_carrier,!field_from_relation,!field_from_name); + Summary.unfreeze_function = + (fun (ct,rt,nt) -> + field_from_carrier := ct; field_from_relation := rt; + field_from_name := nt); + Summary.init_function = + (fun () -> + field_from_carrier := Cmap.empty; field_from_relation := Cmap.empty; + field_from_name := Spmap.empty); + Summary.survive_module = false; + Summary.survive_section = false } + +let add_field_entry (sp,_kn) e = + let _ = ty e.field_ok in + let _ = ty e.field_simpl_eq_ok in + let _ = ty e.field_simpl_ok in + let _ = ty e.field_cond in + field_from_carrier := Cmap.add e.field_carrier e !field_from_carrier; + field_from_relation := Cmap.add e.field_req e !field_from_relation; + field_from_name := Spmap.add sp e !field_from_name + + +let subst_th (_,subst,th) = + let c' = subst_mps subst th.field_carrier in + let eq' = subst_mps subst th.field_req in + let thm1' = subst_mps subst th.field_ok in + let thm2' = subst_mps subst th.field_simpl_eq_ok in + let thm3' = subst_mps subst th.field_simpl_ok in + let thm4' = subst_mps subst th.field_cond in + let tac'= subst_tactic subst th.field_cst_tac in + let pretac'= subst_tactic subst th.field_pre_tac in + let posttac'= subst_tactic subst th.field_post_tac in + if c' == th.field_carrier && + eq' == th.field_req && + thm1' == th.field_ok && + thm2' == th.field_simpl_eq_ok && + thm3' == th.field_simpl_ok && + thm4' == th.field_cond && + tac' == th.field_cst_tac && + pretac' == th.field_pre_tac && + posttac' == th.field_post_tac then th + else + { field_carrier = c'; + field_req = eq'; + field_cst_tac = tac'; + field_ok = thm1'; + field_simpl_eq_ok = thm2'; + field_simpl_ok = thm3'; + field_cond = thm4'; + field_pre_tac = pretac'; + field_post_tac = posttac' } + + +let (ftheory_to_obj, obj_to_ftheory) = + let cache_th (name,th) = add_field_entry name th + and export_th x = Some x in + declare_object + {(default_object "tactic-new-field-theory") with + open_function = (fun i o -> if i=1 then cache_th o); + cache_function = cache_th; + subst_function = subst_th; + classify_function = (fun (_,x) -> Substitute x); + export_function = export_th } + +let default_field_equality r inv req = + let is_setoid = function + {rel_refl=Some _; rel_sym=Some _;rel_trans=Some _} -> true + | _ -> false in + match default_relation_for_carrier ~filter:is_setoid r with + Leibniz _ -> + mkApp((Coqlib.build_coq_eq_data()).congr,[|r;r;inv|]) + | Relation rel -> + let is_endomorphism = function + { args=args } -> List.for_all + (function (var,Relation rel) -> + var=None && eq_constr req rel + | _ -> false) args in + let inv_m = + try default_morphism ~filter:is_endomorphism inv + with Not_found -> + error "field inverse should be declared as a morphism" in + inv_m.lem + + +let n_morph r zero one add mul = +[|Lazy.force(coq_constant"N"); +Lazy.force(coq_constant"N0"); +lapp(coq_constant"Npos")[|Lazy.force(coq_constant"xH")|]; +Lazy.force(coq_constant"Nplus"); +Lazy.force(coq_constant"Nmult"); +Lazy.force(coq_constant"Nminus"); +Lazy.force(coq_constant"Nopp"); +Lazy.force(ring_constant"Neq_bool"); +lapp(ring_constant"gen_phiN")[|r;zero;one;add;mul|] +|] +let z_morph r zero one add mul opp = +[|Lazy.force(coq_constant"Z"); +Lazy.force(coq_constant"Z0"); +lapp(coq_constant"Zpos")[|Lazy.force(coq_constant"xH")|]; +Lazy.force(coq_constant"Zplus"); +Lazy.force(coq_constant"Zmult"); +Lazy.force(coq_constant"Zminus"); +Lazy.force(coq_constant"Zopp"); +Lazy.force(coq_constant"Zeq_bool"); +lapp(ring_constant"gen_phiZ")[|r;zero;one;add;mul;opp|] +|] + +let add_field_theory name fth eqth morphth cst_tac inj (pre,post) = + let env = Global.env() in + let sigma = Evd.empty in + let (kind,r,zero,one,add,mul,sub,opp,div,inv,req,rth) = + dest_field env sigma fth in + let (sth,morph) = build_setoid_params None r add mul opp req eqth in + let eqth = Some(sth,morph) in + let _ = add_theory name rth eqth morphth cst_tac (None,None) in + let afth = build_almost_field + kind r zero one add mul sub opp div inv req sth morph fth in + let inv_m = default_field_equality r inv req in + let args0 = + [|r;zero;one;add;mul;sub;opp;div;inv;req;sth;morph;inv_m;afth|] in + let args0' = + [|r;zero;one;add;mul;sub;opp;div;inv;req;sth;morph;afth|] in + let (m,args1) = + match morphth with + Computational c -> + let reqb = dest_eq_test env sigma c in + let idphi = ring_constant "IDphi" in + let idmorph = lapp (ring_constant "IDmorph") + [|r;zero;one;add;mul;sub;opp;req;sth;reqb;c|] in + (idmorph,[|r;zero;one;add;mul;sub;opp;reqb;lapp idphi [|r|]|]) + | Morphism m -> + dest_morphism env sigma kind m sth + | Abstract -> + (match kind with + None -> error "an almost_field cannot be abstract" + | Some true -> + (lapp(ring_constant"gen_phiN_morph") + [|r;zero;one;add;mul;req;sth;morph;rth|], + n_morph r zero one add mul) + | Some false -> + (lapp(ring_constant"gen_phiZ_morph") + [|r;zero;one;add;mul;sub;opp;req;sth;morph;rth|], + z_morph r zero one add mul opp)) in + let args = Array.concat [args0;args1;[|m|]] in + let args' = Array.concat [args0';args1;[|m|]] in + let lemma1 = lapp field_lemma args in + let lemma2 = lapp field_simplify_eq_lemma args in + let lemma3 = lapp field_simplify_lemma args in + let lemma1 = decl_constant (string_of_id name^"_field_lemma1") lemma1 in + let lemma2 = decl_constant (string_of_id name^"_field_lemma2") lemma2 in + let lemma3 = decl_constant (string_of_id name^"_field_lemma3") lemma3 in + let cond_lemma = + match inj with + | Some thm -> + lapp (field_constant"Pcond_simpl_complete") + (Array.append args' [|thm|]) + | None -> lapp (field_constant"Pcond_simpl_gen") args' in + let cond_lemma = decl_constant (string_of_id name^"_lemma4") cond_lemma in + let cst_tac = match cst_tac with + Some (CstTac t) -> Tacinterp.glob_tactic t + | Some (Closed lc) -> closed_term_ast (List.map Nametab.global lc) + | None -> + (match kind with + Some true -> + let t = ArgArg(dummy_loc,Lazy.force ltac_inv_morphN) in + TacArg(TacCall(dummy_loc,t,List.map carg [zero;one;add;mul])) + | Some false -> + let t = ArgArg(dummy_loc, Lazy.force ltac_inv_morphZ) in + TacArg(TacCall(dummy_loc,t,List.map carg [zero;one;add;mul;opp])) + | _ -> error"a tactic must be specified for an almost_ring") in + let pretac = + match pre with + Some t -> Tacinterp.glob_tactic t + | _ -> TacId [] in + let posttac = + match post with + Some t -> Tacinterp.glob_tactic t + | _ -> TacId [] in + let _ = + Lib.add_leaf name + (ftheory_to_obj + { field_carrier = r; + field_req = req; + field_cst_tac = cst_tac; + field_ok = lemma1; + field_simpl_eq_ok = lemma2; + field_simpl_ok = lemma3; + field_cond = cond_lemma; + field_pre_tac = pretac; + field_post_tac = posttac }) in () + +type field_mod = + Ring_mod of ring_mod + | Inject of Topconstr.constr_expr + +VERNAC ARGUMENT EXTEND field_mod + | [ ring_mod(m) ] -> [ Ring_mod m ] + | [ "infinite" constr(inj) ] -> [ Inject inj ] +END + +let process_field_mods l = + let kind = ref None in + let set = ref None in + let cst_tac = ref None in + let pre = ref None in + let post = ref None in + let inj = ref None in + List.iter(function + Ring_mod(Ring_kind k) -> set_once "field kind" kind k + | Ring_mod(Const_tac t) -> + set_once "tactic recognizing constants" cst_tac t + | Ring_mod(Pre_tac t) -> set_once "preprocess tactic" pre t + | Ring_mod(Post_tac t) -> set_once "postprocess tactic" post t + | Ring_mod(Setoid(sth,ext)) -> set_once "setoid" set (ic sth,ic ext) + | Inject i -> set_once "infinite property" inj (ic i)) l; + let k = match !kind with Some k -> k | None -> Abstract in + (k, !set, !inj, !cst_tac, !pre, !post) + +VERNAC COMMAND EXTEND AddSetoidField +| [ "Add" "Field" ident(id) ":" constr(t) field_mods(l) ] -> + [ let (k,set,inj,cst_tac,pre,post) = process_field_mods l in + add_field_theory id (ic t) set k cst_tac inj (pre,post) ] END +let field gl = + let env = pf_env gl in + let sigma = project gl in + let e = find_field_structure env sigma [] (pf_concl gl) None in + let main_tac = + ltac_call field_tac + [carg e.field_ok;carg e.field_cond; + carg e.field_req; Tacexp e.field_cst_tac] in + Tacinterp.eval_tactic + (TacThen(e.field_pre_tac,TacThen(main_tac,e.field_post_tac))) gl + +let field_simplify_eq gl = + let env = pf_env gl in + let sigma = project gl in + let e = find_field_structure env sigma [] (pf_concl gl) None in + let main_tac = + ltac_call field_simplify_eq_tac + [carg e.field_simpl_eq_ok;carg e.field_cond; + carg e.field_req; Tacexp e.field_cst_tac] in + Tacinterp.eval_tactic + (TacThen(e.field_pre_tac,TacThen(main_tac,e.field_post_tac))) gl + +let field_simplify rl gl = + let env = pf_env gl in + let sigma = project gl in + let e = find_field_structure env sigma rl (pf_concl gl) None in + let rl = + match rl with + [] -> let (_,t1,t2) = dest_rel (pf_concl gl) in [t1;t2] + | _ -> rl in + let rl = List.fold_right + (fun x l -> lapp coq_cons [|e.field_carrier;x;l|]) rl + (lapp coq_nil [|e.field_carrier|]) in + let main_tac = + ltac_call field_simplify_tac + [carg e.field_simpl_ok;carg e.field_cond; + carg e.field_req; Tacexp e.field_cst_tac; + carg rl] in + Tacinterp.eval_tactic + (TacThen(e.field_pre_tac,TacThen(main_tac,e.field_post_tac))) gl + +TACTIC EXTEND setoid_field + [ "field" ] -> [ field ] +END +TACTIC EXTEND setoid_field_simplify + [ "field_simplify_eq" ] -> [ field_simplify_eq ] +| [ "field_simplify" constr_list(l) ] -> [ field_simplify l ] +END |
