summaryrefslogtreecommitdiff
path: root/contrib/setoid_ring/newring.ml4
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/setoid_ring/newring.ml4')
-rw-r--r--contrib/setoid_ring/newring.ml4525
1 files changed, 525 insertions, 0 deletions
diff --git a/contrib/setoid_ring/newring.ml4 b/contrib/setoid_ring/newring.ml4
new file mode 100644
index 00000000..7041d7e8
--- /dev/null
+++ b/contrib/setoid_ring/newring.ml4
@@ -0,0 +1,525 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i camlp4deps: "parsing/grammar.cma" i*)
+
+(*i $Id: newring.ml4 7974 2006-02-01 19:02:09Z barras $ i*)
+
+open Pp
+open Util
+open Names
+open Term
+open Closure
+open Environ
+open Tactics
+open Rawterm
+open Tacticals
+open Tacexpr
+open Pcoq
+open Tactic
+open Constr
+open Setoid_replace
+open Proof_type
+open Coqlib
+open Tacmach
+open Ppconstr
+open Mod_subst
+open Tacinterp
+open Libobject
+open Printer
+
+(****************************************************************************)
+(* Library linking *)
+
+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"]]
+
+let coq_constant c =
+ lazy (Coqlib.gen_constant_in_modules "Ring" stdlib_modules c)
+let ring_constant c =
+ lazy (Coqlib.gen_constant_in_modules "Ring" ring_modules c)
+let ringtac_constant m c =
+ lazy (Coqlib.gen_constant_in_modules "Ring" [ring_dir@["ZRing_th";m]] c)
+
+let new_ring_path =
+ make_dirpath (List.map id_of_string ["Ring_tac";contrib_name;"Coq"])
+let ltac s =
+ lazy(make_kn (MPfile new_ring_path) (make_dirpath []) (mk_label s))
+let znew_ring_path =
+ make_dirpath (List.map id_of_string ["ZRing_th";contrib_name;"Coq"])
+let zltac s =
+ lazy(make_kn (MPfile znew_ring_path) (make_dirpath []) (mk_label s))
+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 ring_comp1 = ring_constant "ring_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 sring_abs1 = ringtac_constant "Npol" "ring_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"
+let coq_eq_setoid = ring_constant "Eqsth"
+let coq_eq_morph = ring_constant "Eq_ext"
+
+(* ring -> almost_ring utilities *)
+let coq_ring_theory = ring_constant "ring_theory"
+let coq_ring_morph = ring_constant "ring_morph"
+let coq_Rth_ARth = ring_constant "Rth_ARth"
+let coq_mk_reqe = ring_constant "mk_reqe"
+
+(* semi_ring -> almost_ring utilities *)
+let coq_semi_ring_theory = ring_constant "semi_ring_theory"
+let coq_SRth_ARth = ring_constant "SRth_ARth"
+let coq_sring_morph = ring_constant "semi_morph"
+let coq_SRmorph_Rmorph = ring_constant "SRmorph_Rmorph"
+let coq_mk_seqe = ring_constant "mk_seqe"
+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_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 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);
+];;
+
+(* Equality: do not evaluate but make recursive call on both sides *)
+let is_ring_thm req =
+ 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 protect_tac =
+ Tactics.reduct_option (protect_red,DEFAULTcast) None ;;
+
+let protect_tac_in id =
+ Tactics.reduct_option (protect_red,DEFAULTcast) (Some(id,[],InHyp));;
+
+
+TACTIC EXTEND protect_fv
+ [ "protect_fv" "in" ident(id) ] ->
+ [ protect_tac_in id ]
+| [ "protect_fv" ] ->
+ [ protect_tac ]
+END;;
+
+(****************************************************************************)
+(* 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 }
+
+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 _ =
+ Summary.declare_summary "tactic-new-ring-table"
+ { Summary.freeze_function = (fun () -> !from_carrier,!from_relation);
+ Summary.unfreeze_function =
+ (fun (ct,rt) -> from_carrier := ct; from_relation := rt);
+ Summary.init_function =
+ (fun () -> from_carrier := Cmap.empty; from_relation := Cmap.empty);
+ Summary.survive_module = false;
+ Summary.survive_section = false }
+
+let add_entry _ 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
+
+
+let subst_th (_,subst,th) =
+ let c' = subst_mps subst th.ring_carrier in
+ let eq' = subst_mps subst th.ring_req in
+ 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
+ if c' == th.ring_carrier &&
+ eq' == th.ring_req &&
+ thm1' == th.ring_lemma1 &&
+ thm2' == th.ring_lemma2 &&
+ tac' == th.ring_cst_tac then th
+ else
+ { ring_carrier = c';
+ ring_req = eq';
+ ring_cst_tac = tac';
+ ring_lemma1 = thm1';
+ ring_lemma2 = thm2' }
+
+
+let (theory_to_obj, obj_to_theory) =
+ let cache_th (name,th) = add_entry name th
+ and export_th x = Some x in
+ declare_object
+ {(default_object "tactic-new-ring-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 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;
+ out_some r.rel_refl; out_some r.rel_sym; out_some r.rel_trans |]
+
+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 |]|]
+
+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
+ 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 ->
+ (th,[|c;czero;cone;cadd;cmul;csub;copp;ceqb;phi|])
+ | App(f,[|r;zero;one;add;mul;req;c;czero;cone;cadd;cmul;ceqb;phi|])
+ when f = Lazy.force coq_sring_morph && kind=Some true->
+ let th =
+ 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"
+
+let dest_eq_test th =
+ let th_typ = Retyping.get_type_of (Global.env()) Evd.empty 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"
+
+let default_ring_equality is_semi (r,add,mul,opp,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 _ ->
+ let setoid = lapp coq_eq_setoid [|r|] in
+ let op_morph = lapp coq_eq_morph [|r;add;mul;opp|] in
+ (setoid,op_morph)
+ | Relation rel ->
+ let setoid = setoid_of_relation rel in
+ let is_endomorphism = function
+ { args=args } -> List.for_all
+ (function (var,Relation rel) ->
+ var=None && eq_constr req rel
+ | _ -> false) args in
+ let add_m =
+ try default_morphism ~filter:is_endomorphism add
+ with Not_found ->
+ error "ring addition should be declared as a morphism" in
+ let mul_m =
+ try default_morphism ~filter:is_endomorphism mul
+ with Not_found ->
+ 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 op_morph =
+ op_morph r add mul opp req add_m.lem mul_m.lem opp_m.lem in
+ msgnl
+ (str"Using setoid \""++pr_constr rel.rel_aeq++str"\""++spc()++
+ str"and morphisms \""++pr_constr add_m.morphism_theory++
+ str"\","++spc()++ str"\""++pr_constr mul_m.morphism_theory++
+ str"\""++spc()++str"and \""++pr_constr opp_m.morphism_theory++
+ str"\"");
+ op_morph)
+ else
+ (msgnl
+ (str"Using setoid \""++pr_constr rel.rel_aeq++str"\"" ++ spc() ++
+ str"and morphisms \""++pr_constr add_m.morphism_theory++
+ str"\""++spc()++str"and \""++
+ pr_constr mul_m.morphism_theory++str"\"");
+ op_smorph r add mul req add_m.lem mul_m.lem) in
+ (setoid,op_morph)
+
+let build_setoid_params is_semi r add mul opp req eqth =
+ match eqth with
+ 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
+ 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 ->
+ (None,r,zero,one,add,mul,sub,opp,req)
+ | App(f,[|r;zero;one;add;mul;req|])
+ when f = Lazy.force coq_semi_ring_theory ->
+ (Some true,r,zero,one,add,mul,sr_sub r add,sr_opp r,req)
+ | App(f,[|r;zero;one;add;mul;sub;opp;req|])
+ when f = Lazy.force coq_ring_theory ->
+ (Some false,r,zero,one,add,mul,sub,opp,req)
+ | _ -> error "bad ring structure"
+
+
+let build_almost_ring kind r zero one add mul sub opp req sth morph th =
+ match kind with
+ None -> th
+ | Some true ->
+ lapp coq_SRth_ARth [|r;zero;one;add;mul;req;sth;th|]
+ | Some false ->
+ lapp coq_Rth_ARth [|r;zero;one;add;mul;sub;opp;req;sth;morph;th|]
+
+
+type coeff_spec =
+ Computational of constr (* equality test *)
+ | Abstract (* coeffs = Z *)
+ | Morphism of constr (* general morphism *)
+
+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
+ 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 (lemma1,lemma2) =
+ match morphth with
+ | Computational c ->
+ let reqb = dest_eq_test 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 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
+ (match kind with
+ None -> error "an almost_ring cannot be abstract"
+ | Some true ->
+ (lapp sring_abs1 args1, lapp sring_abs2 args1)
+ | Some false ->
+ (lapp ring_abs1 args1, lapp ring_abs2 args1)) in
+ let cst_tac = match cst_tac with
+ Some (CstTac t) -> Tacinterp.glob_tactic t
+ | Some (Closed lc) -> failwith "TODO"
+ | None ->
+ (match kind with
+ Some true ->
+ let t = Genarg.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 = Genarg.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 _ =
+ Lib.add_leaf name
+ (theory_to_obj
+ { ring_carrier = r;
+ ring_req = req;
+ ring_cst_tac = cst_tac;
+ ring_lemma1 = lemma1;
+ ring_lemma2 = lemma2 }) in
+ ()
+
+VERNAC ARGUMENT EXTEND ring_coefs
+| [ "Computational" constr(c)] -> [ Computational (ic c) ]
+| [ "Abstract" ] -> [ Abstract ]
+| [ "Coefficients" constr(m)] -> [ Morphism (ic m) ]
+| [ ] -> [ Abstract ]
+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
+
+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 ]
+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,
+ Genarg.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
+ Tacinterp.eval_tactic
+ (TacArg(TacCall(dummy_loc,
+ Genarg.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
+
+TACTIC EXTEND setoid_ring
+ [ "setoid" "ring" constr_list(l) ] -> [ setoid_ring l ]
+END
+