diff options
-rw-r--r-- | tactics/setoid_replace.ml | 1240 | ||||
-rw-r--r-- | tactics/setoid_replace.mli | 3 | ||||
-rw-r--r-- | theories/Setoids/Setoid.v | 372 |
3 files changed, 941 insertions, 674 deletions
diff --git a/tactics/setoid_replace.ml b/tactics/setoid_replace.ml index 4a44e72d2..a5f5f742d 100644 --- a/tactics/setoid_replace.ml +++ b/tactics/setoid_replace.ml @@ -33,21 +33,22 @@ open Constrintern let replace = ref (fun _ _ -> assert false) let register_replace f = replace := f -type setoid = - { set_a : constr; - set_aeq : constr; - set_th : constr - } - -type 'a setoid_class = - ACSetoid of 'a (*the equivalence relation of the setoid or the setoid*) - | ACLeibniz of constr (*the carrier of the setoid*) +type reflexive_relation = + { refl_a: constr ; + refl_aeq: constr; + refl_refl: constr; + refl_sym: constr option + } + +type 'a relation_class = + ACReflexive of 'a (* the relation of the reflexive_relation + or the reflexive_relation*) + | ACLeibniz of constr (* the carrier *) type 'a morphism = - { lem : constr; - args : 'a setoid_class list; - output : 'a setoid_class; - lem2 : constr option + { args : 'a relation_class list; + output : 'a relation_class; + lem : constr; } type funct = @@ -56,25 +57,27 @@ type funct = } type morphism_class = - ACMorphism of setoid morphism + ACMorphism of reflexive_relation morphism | ACFunction of funct -let subst_mps_in_setoid_class subst = +let subst_mps_in_relation_class subst = function - ACSetoid t -> ACSetoid (subst_mps subst t) + ACReflexive t -> ACReflexive (subst_mps subst t) | ACLeibniz t -> ACLeibniz (subst_mps subst t) -let constr_setoid_class_of_setoid_setoid_class = +let constr_relation_class_of_relation_relation_class = function - ACSetoid setoid -> ACSetoid setoid.set_aeq + ACReflexive relation -> ACReflexive relation.refl_aeq | ACLeibniz t -> ACLeibniz t let constr_of c = Constrintern.interp_constr Evd.empty (Global.env()) c let constant dir s = Coqlib.gen_constant "Setoid_replace" ("Setoids"::dir) s - -let global_constant dir s =Coqlib.gen_constant "Setoid_replace" ("Init"::dir) s +let init_constant dir s = Coqlib.gen_constant "Setoid_replace" ("Init"::dir) s +let reference dir s = Coqlib.gen_reference "Setoid_replace" ("Setoids"::dir) s +let eval_reference dir s = EvalConstRef (destConst (constant dir s)) +let eval_init_reference dir s = EvalConstRef (destConst (init_constant dir s)) let current_constant id = try @@ -82,134 +85,196 @@ let current_constant id = with Not_found -> anomaly ("Setoid: cannot find " ^ (string_of_id id)) -(* Setoid_theory *) +(* From Setoid.v *) +let coq_is_reflexive = lazy(constant ["Setoid"] "is_reflexive") + +let coq_Relation_Class = lazy(constant ["Setoid"] "Relation_Class") let coq_Setoid_Theory = lazy(constant ["Setoid"] "Setoid_Theory") +let coq_Morphism_Theory = lazy(constant ["Setoid"] "Morphism_Theory") +let coq_Build_Morphism_Theory= lazy(constant ["Setoid"] "Build_Morphism_Theory") + +let coq_Reflexive = lazy(constant ["Setoid"] "Reflexive") +let coq_Leibniz = lazy(constant ["Setoid"] "Leibniz") let coq_seq_refl = lazy(constant ["Setoid"] "Seq_refl") let coq_seq_sym = lazy(constant ["Setoid"] "Seq_sym") let coq_seq_trans = lazy(constant ["Setoid"] "Seq_trans") -let coq_fleche = lazy(constant ["Setoid"] "fleche") +let coq_singl = lazy(constant ["Setoid"] "singl") +let coq_cons = lazy(constant ["Setoid"] "cons") -(* Coq constants *) +let coq_equality_morphism_of_setoid_theory = + lazy(constant ["Setoid"] "equality_morphism_of_setoid_theory") +let coq_make_compatibility_goal = + lazy(constant ["Setoid"] "make_compatibility_goal") +let coq_make_compatibility_goal_ref = + lazy(reference ["Setoid"] "make_compatibility_goal") +let coq_make_compatibility_goal_aux_ref = + lazy(reference ["Setoid"] "make_compatibility_goal_aux") -let coqiff = lazy(global_constant ["Logic"] "iff") +let coq_App = lazy(constant ["Setoid"] "App") +let coq_Toreplace = lazy(constant ["Setoid"] "Toreplace") +let coq_Tokeep = lazy(constant ["Setoid"] "Tokeep") +let coq_Imp = lazy(constant ["Setoid"] "Imp") +let coq_fcl_singl = lazy(constant ["Setoid"] "fcl_singl") +let coq_fcl_cons = lazy(constant ["Setoid"] "fcl_cons") -let coqeq = lazy(global_constant ["Logic"] "eq") +let coq_setoid_rewrite = lazy(constant ["Setoid"] "setoid_rewrite") +let coq_proj2 = lazy(init_constant ["Logic"] "proj2") -let coqconj = lazy(global_constant ["Logic"] "conj") -let coqand = lazy(global_constant ["Logic"] "and") -let coqproj1 = lazy(global_constant ["Logic"] "proj1") -let coqproj2 = lazy(global_constant ["Logic"] "proj2") +let coq_morphism_theory_of_function = + lazy(constant ["Setoid"] "morphism_theory_of_function") +let coq_morphism_theory_of_predicate = + lazy(constant ["Setoid"] "morphism_theory_of_predicate") +let coq_relation_of_relation_class = + lazy(eval_reference ["Setoid"] "relation_of_relation_class") +let coq_interp = lazy(eval_reference ["Setoid"] "interp") +let coq_Morphism_Context_rect2 = + lazy(eval_reference ["Setoid"] "Morphism_Context_rect2") +let coq_iff = lazy(eval_init_reference ["Logic"] "iff") -(************************* Table of declared setoids **********************) +let coq_prop_relation = + lazy ( + ACReflexive { + refl_a = mkProp ; + refl_aeq = init_constant ["Logic"] "iff" ; + refl_refl = init_constant ["Logic"] "iff_refl"; + refl_sym = Some (init_constant ["Logic"] "iff_sym") + }) -(* Setoids are stored in a table which is synchronised with the Reset mechanism. *) +(************************* Table of declared relations **********************) + -let setoid_table = ref Gmap.empty +(* Relations are stored in a table which is synchronised with the Reset mechanism. *) -let setoid_table_add (s,th) = setoid_table := Gmap.add s th !setoid_table -let setoid_table_find s = Gmap.find s !setoid_table -let setoid_table_mem s = Gmap.mem s !setoid_table +let relation_table = ref Gmap.empty -let prsetoid s = - str "(" ++ prterm s.set_a ++ str "," ++ prterm s.set_aeq ++ str ")" +let relation_table_add (s,th) = relation_table := Gmap.add s th !relation_table +let relation_table_find s = Gmap.find s !relation_table +let relation_table_mem s = Gmap.mem s !relation_table -let prsetoid_class = +let prrelation s = + str "(" ++ prterm s.refl_a ++ str "," ++ prterm s.refl_aeq ++ str ")" + +let prrelation_class = function - ACSetoid eq -> - (try prsetoid (setoid_table_find eq) + ACReflexive eq -> + (try prrelation (relation_table_find eq) with Not_found -> + (*CSC: still "setoid" in the error message *) str "[[ Error: setoid on equality " ++ prterm eq ++ str " not found! ]]") | ACLeibniz ty -> prterm ty let prmorphism k m = prterm k ++ str ": " ++ - prlist_with_sep (fun () -> str " -> ") prsetoid_class m.args ++ - str " -> " ++ prsetoid_class m.output + prlist_with_sep (fun () -> str " -> ") prrelation_class m.args ++ + str " -> " ++ prrelation_class m.output -(* A function that gives back the only setoid on a given carrier *) +(* A function that gives back the only relation_class on a given carrier *) (*CSC: this implementation is really inefficient. I should define a new map to make it efficient. However, is this really worth of? *) -let default_setoid_for_carrier a = - let rng = Gmap.rng !setoid_table in - match List.filter (fun {set_a=set_a} -> set_a = a) rng with +let default_relation_for_carrier a = + let rng = Gmap.rng !relation_table in + match List.filter (fun {refl_a=refl_a} -> refl_a = a) rng with [] -> ACLeibniz a - | setoid::tl -> + | relation::tl -> if tl <> [] then msg_warning + (*CSC: still "setoid" in the error message *) (str "There are several setoids whose carrier is " ++ prterm a ++ - str ". The setoid " ++ prsetoid setoid ++ + str ". The setoid " ++ prrelation relation ++ str " is randomly chosen.") ; - ACSetoid setoid + ACReflexive relation -let setoid_morphism_of_constr_morphism = - let setoid_setoid_class_of_constr_setoid_class = +let relation_morphism_of_constr_morphism = + let relation_relation_class_of_constr_relation_class = function ACLeibniz t -> ACLeibniz t - | ACSetoid aeq -> - ACSetoid (try setoid_table_find aeq with Not_found -> assert false) + | ACReflexive aeq -> + ACReflexive (try relation_table_find aeq with Not_found -> assert false) in function mor -> - let args' = List.map setoid_setoid_class_of_constr_setoid_class mor.args in - let output' = setoid_setoid_class_of_constr_setoid_class mor.output in + let args' = List.map relation_relation_class_of_constr_relation_class mor.args in + let output' = relation_relation_class_of_constr_relation_class mor.output in {mor with args=args' ; output=output'} -let subst_setoid subst setoid = - let set_a' = subst_mps subst setoid.set_a in - let set_aeq' = subst_mps subst setoid.set_aeq in - let set_th' = subst_mps subst setoid.set_th in - if set_a' == setoid.set_a - && set_aeq' == setoid.set_aeq - && set_th' == setoid.set_th +let subst_relation subst relation = + let refl_a' = subst_mps subst relation.refl_a in + let refl_aeq' = subst_mps subst relation.refl_aeq in + let refl_refl' = subst_mps subst relation.refl_refl in + let refl_sym' = option_app (subst_mps subst) relation.refl_sym in + if refl_a' == relation.refl_a + && refl_aeq' == relation.refl_aeq + && refl_refl' == relation.refl_refl + && refl_sym' == relation.refl_sym then - setoid + relation else - { set_a = set_a' ; - set_aeq = set_aeq' ; - set_th = set_th' ; + { refl_a = refl_a' ; + refl_aeq = refl_aeq' ; + refl_refl = refl_refl' ; + refl_sym = refl_sym' } -let equiv_list () = List.map (fun x -> x.set_aeq) (Gmap.rng !setoid_table) +let equiv_list () = List.map (fun x -> x.refl_aeq) (Gmap.rng !relation_table) let _ = - Summary.declare_summary "setoid-table" - { Summary.freeze_function = (fun () -> !setoid_table); - Summary.unfreeze_function = (fun t -> setoid_table := t); - Summary.init_function = (fun () -> setoid_table := Gmap .empty); + Summary.declare_summary "relation-table" + { Summary.freeze_function = (fun () -> !relation_table); + Summary.unfreeze_function = (fun t -> relation_table := t); + Summary.init_function = (fun () -> relation_table := Gmap .empty); Summary.survive_module = true; Summary.survive_section = false } -(* Declare a new type of object in the environment : "setoid-theory". *) +(* Declare a new type of object in the environment : "relation-theory". *) -let (setoid_to_obj, obj_to_setoid)= +let (relation_to_obj, obj_to_relation)= let cache_set (_,(s, th)) = - if setoid_table_mem s then - begin - let old_setoid = setoid_table_find s in - msg_warning - (str "The setoid " ++ prsetoid th ++ str " is redeclared. " ++ - str "The new declaration justified by " ++ - prterm th.set_th ++ str " replaces the old declaration justified by "++ - prterm old_setoid.set_th ++ str ".") - end ; - setoid_table_add (s,th) + let th' = + if relation_table_mem s then + begin + let old_relation = relation_table_find s in + let th' = + {th with refl_sym = + match th.refl_sym with + None -> old_relation.refl_sym + | Some t -> Some t} in + (*CSC: still "setoid" in the error message *) + msg_warning + (str "The setoid " ++ prrelation th' ++ str " is redeclared. " ++ + str "The new declaration (reflevity proved by " ++ + prterm th'.refl_refl ++ + (match th'.refl_sym with + None -> str "" + | Some t -> str " and symmetry proved by " ++ prterm t) ++ + str ") replaces the old declaration (reflexivity proved by "++ + prterm old_relation.refl_refl ++ + (match old_relation.refl_sym with + None -> str "" + | Some t -> str " and symmetry proved by " ++ prterm t) ++ + str ").") ; + th' + end + else + th + in + relation_table_add (s,th') and subst_set (_,subst,(s,th as obj)) = let s' = subst_mps subst s in - let th' = subst_setoid subst th in + let th' = subst_relation subst th in if s' == s && th' == th then obj else - (s',th') + (s',th') and export_set x = Some x in - declare_object {(default_object "setoid-theory") with - cache_function = cache_set; - load_function = (fun i o -> cache_set o); - subst_function = subst_set; - classify_function = (fun (_,x) -> Substitute x); - export_function = export_set} + declare_object {(default_object "relation-theory") with + cache_function = cache_set; + load_function = (fun i o -> cache_set o); + subst_function = subst_set; + classify_function = (fun (_,x) -> Substitute x); + export_function = export_set} (******************************* Table of declared morphisms ********************) @@ -233,47 +298,25 @@ let morphism_table_add (m,c) = msg_warning (str "The morphism " ++ prmorphism m old_morph ++ str " is redeclared. " ++ str "The new declaration whose compatibility is granted by " ++ - prterm c.lem ++ - (match c.lem2 with None -> str "" | Some t-> str " and " ++ prterm t) - ++ str " replaces the old declaration whose" ++ + prterm c.lem ++ str " replaces the old declaration whose" ++ str " compatibility was granted by " ++ - prterm old_morph.lem ++ - (match old_morph.lem2 with - None -> str "" - | Some t-> str " and "++ prterm t) ++ str ".") + prterm old_morph.lem ++ str ".") with Not_found -> morphism_table := Gmap.add m (c::old) !morphism_table -let find_morphism_fleche () = - let fleche_constr = (Lazy.force coq_fleche) in - try - let mor = - List.find - (function {args=args; output=output} as morphism -> - output = ACSetoid (Lazy.force coqiff) && - List.for_all (function c -> c = ACSetoid (Lazy.force coqiff)) args) - (morphism_table_find fleche_constr) - in - setoid_morphism_of_constr_morphism mor - with - Not_found -> assert false - let subst_morph subst morph = let lem' = subst_mps subst morph.lem in - let args' = list_smartmap (subst_mps_in_setoid_class subst) morph.args in - let output' = subst_mps_in_setoid_class subst morph.output in - let lem2' = option_smartmap (subst_mps subst) morph.lem2 in + let args' = list_smartmap (subst_mps_in_relation_class subst) morph.args in + let output' = subst_mps_in_relation_class subst morph.output in if lem' == morph.lem && args' == morph.args && output' == morph.output - && lem2' == morph.lem2 then morph else - { lem = lem' ; - args = args' ; - output = output' ; - lem2 = lem2' + { args = args' ; + output = output' ; + lem = lem' } @@ -293,144 +336,65 @@ let (morphism_to_obj, obj_to_morphism)= let m' = subst_mps subst m in let c' = subst_morph subst c in if m' == m && c' == c then obj else - (m',c') + (m',c') and export_set x = Some x in declare_object {(default_object "morphism-definition") with - cache_function = cache_set; - load_function = (fun i o -> cache_set o); - subst_function = subst_set; - classify_function = (fun (_,x) -> Substitute x); - export_function = export_set} + cache_function = cache_set; + load_function = (fun i o -> cache_set o); + subst_function = subst_set; + classify_function = (fun (_,x) -> Substitute x); + export_function = export_set} -(************************** Printing setoids and morphisms **********************) +(************************** Printing relations and morphisms **********************) +(*CSC: still "setoids" in the name *) let print_setoids () = Gmap.iter - (fun k setoid -> - assert (k=setoid.set_aeq) ; - ppnl (str"Setoid " ++ prsetoid setoid ++ str"; equivalence relation properties granted by " ++ - prterm setoid.set_th)) - !setoid_table ; + (fun k relation -> + assert (k=relation.refl_aeq) ; + (*CSC: still "Setoid" in the error message *) + ppnl (str"Setoid " ++ prrelation relation ++ + str"; reflexivity granted by " ++ prterm relation.refl_refl ++ + (match relation.refl_sym with + None -> str "" + | Some t -> str " symmetry granted by " ++ prterm t))) + !relation_table ; Gmap.iter (fun k l -> List.iter - (fun ({lem=lem ; lem2=lem2} as mor) -> + (fun ({lem=lem} as mor) -> ppnl (str "Morphism " ++ prmorphism k mor ++ str ". Compatibility granted by " ++ - prterm lem ++ - (match lem2 with None -> str"" | Some t -> str " and " ++ prterm t) ++ - str ".")) + prterm lem ++ str ".")) l) !morphism_table ;; -(************************** Adding a setoid to the database *********************) - -(* Add a Setoid to the database after a type verification. *) - -let eq_lem_common_sign env a eq = - let na = named_hd env a Anonymous in - let ne = named_hd env eq Anonymous in - [(ne,None,mkApp (eq, [|(mkRel 3);(mkRel 2)|])); - (ne,None,mkApp (eq, [|(mkRel 4);(mkRel 3)|])); - (na,None,a);(na,None,a);(na,None,a);(na,None,a)] - -(* Proof of (a,b,c,d:A)(eq a b)->(eq c d)->(eq a c)->(eq b d) *) -let eq_lem_proof env a eq sym trans = - let sign = eq_lem_common_sign env a eq in - let ne = named_hd env eq Anonymous in - let sign = (ne,None,mkApp (eq, [|(mkRel 6);(mkRel 4)|]))::sign in - let ccl = mkApp (eq, [|(mkRel 6);(mkRel 4)|]) in - let body = - mkApp (trans, - [|(mkRel 6);(mkRel 7);(mkRel 4); - (mkApp (sym, [|(mkRel 7);(mkRel 6);(mkRel 3)|])); - (mkApp (trans, - [|(mkRel 7);(mkRel 5);(mkRel 4);(mkRel 1);(mkRel 2)|]))|]) in - let p = it_mkLambda_or_LetIn body sign in - let t = it_mkProd_or_LetIn ccl sign in - (p,t) - -(* Proof of (a,b,c,d:A)(eq a b)->(eq c d)->((eq a c)<->(eq b d)) *) -let eq_lem2_proof env a eq sym trans = - let sign = eq_lem_common_sign env a eq in - let ccl1 = - mkArrow - (mkApp (eq, [|(mkRel 6);(mkRel 4)|])) - (mkApp (eq, [|(mkRel 6);(mkRel 4)|])) in - let ccl2 = - mkArrow - (mkApp (eq, [|(mkRel 5);(mkRel 3)|])) - (mkApp (eq, [|(mkRel 7);(mkRel 5)|])) in - let ccl = mkApp (Lazy.force coqand, [|ccl1;ccl2|]) in - let body = - mkApp ((Lazy.force coqconj), - [|ccl1;ccl2; - lambda_create env - (mkApp (eq, [|(mkRel 6);(mkRel 4)|]), - (mkApp (trans, - [|(mkRel 6);(mkRel 7);(mkRel 4); - (mkApp (sym, [|(mkRel 7);(mkRel 6);(mkRel 3)|])); - (mkApp (trans, - [|(mkRel 7);(mkRel 5);(mkRel 4);(mkRel 1);(mkRel 2)|]))|]))); - lambda_create env - (mkApp (eq, [|(mkRel 5);(mkRel 3)|]), - (mkApp (trans, - [|(mkRel 7);(mkRel 6);(mkRel 5);(mkRel 3); - (mkApp (trans, - [|(mkRel 6);(mkRel 4);(mkRel 5);(mkRel 1); - (mkApp (sym, [|(mkRel 5);(mkRel 4);(mkRel 2)|]))|]))|])))|]) - in - let p = it_mkLambda_or_LetIn body sign in - let t = it_mkProd_or_LetIn ccl sign in - (p,t) - -let gen_eq_lem_name = - let i = ref 0 in - function () -> - incr i; - make_ident "setoid_eq_ext" (Some !i) - -let add_setoid a aeq th = - let env = Global.env () in - if (is_conv env Evd.empty (Typing.type_of env Evd.empty th) - (mkApp ((Lazy.force coq_Setoid_Theory), [| a; aeq |]))) - then (Lib.add_anonymous_leaf - (setoid_to_obj - (aeq, { set_a = a; - set_aeq = aeq; - set_th = th})); - let sym = mkApp ((Lazy.force coq_seq_sym), [|a; aeq; th|]) in - let trans = mkApp ((Lazy.force coq_seq_trans), [|a; aeq; th|]) in - let (eq_morph, eq_morph_typ) = eq_lem_proof env a aeq sym trans in - let (eq_morph2, eq_morph2_typ) = eq_lem2_proof env a aeq sym trans in - Options.if_verbose ppnl (prterm a ++str " is registered as a setoid"); - let eq_ext_name = gen_eq_lem_name () in - let eq_ext_name2 = gen_eq_lem_name () in - let _ = Declare.declare_constant eq_ext_name - ((DefinitionEntry {const_entry_body = eq_morph; - const_entry_type = Some eq_morph_typ; - const_entry_opaque = true}), - IsProof Lemma) in - let _ = Declare.declare_constant eq_ext_name2 - ((DefinitionEntry {const_entry_body = eq_morph2; - const_entry_type = Some eq_morph2_typ; - const_entry_opaque = true}), - IsProof Lemma) in - let eqmorph = (current_constant eq_ext_name) in - let eqmorph2 = (current_constant eq_ext_name2) in - (Lib.add_anonymous_leaf - (morphism_to_obj (aeq, - { lem = eqmorph; - args = [ACSetoid aeq; ACSetoid aeq]; - output = ACSetoid (Lazy.force coqiff); - lem2 = (Some eqmorph2)}))); - Options.if_verbose ppnl (prterm aeq ++str " is registered as a morphism")) - else errorlabstrm "Add Setoid" (str "Not a valid setoid theory") - -(* The vernac command "Add Setoid" *) -let add_setoid a aeq th = - add_setoid (constr_of a) (constr_of aeq) (constr_of th) +(************************** Adding a relation to the database *********************) + +let int_add_relation a aeq refl sym = + match refl with + None -> assert false (*CSC: unimplemented yet*) + | Some refl -> + let env = Global.env () in + if + (is_conv env Evd.empty (Typing.type_of env Evd.empty refl) + (mkApp ((Lazy.force coq_is_reflexive), [| a; aeq |]))) + then + Lib.add_anonymous_leaf + (relation_to_obj + (aeq, { refl_a = a; + refl_aeq = aeq; + refl_refl = refl; + refl_sym = sym})) + else + errorlabstrm "Add Relation Class" + (str "Not a valid proof of reflexivity") + +(* The vernac command "Add Relation ..." *) +let add_relation a aeq refl sym = + int_add_relation (constr_of a) (constr_of aeq) (option_app constr_of refl) + (option_app constr_of sym) (***************** Adding a morphism to the database ****************************) @@ -458,64 +422,33 @@ let check_is_dependent t n = else false in aux t 0 n -let gen_lem_name m = match kind_of_term m with - | Var id -> add_suffix id "_ext" - | Const kn -> add_suffix (id_of_label (label kn)) "_ext" - | Ind (kn, i) -> add_suffix (id_of_label (label kn)) ((string_of_int i)^"_ext") - | Construct ((kn,i),j) -> add_suffix - (id_of_label (label kn)) ((string_of_int i)^(string_of_int j)^"_ext") - | _ -> errorlabstrm "New Morphism" (str "The term " ++ prterm m ++ str "is not a known name") - -let gen_lemma_tail m args body n = - let l = (List.length args) in - let a1 = Array.create l (mkRel 0) in - let a2 = Array.create l (mkRel 0) in - let rec aux i n = function - | (ACSetoid _)::tl -> - a1.(i) <- (mkRel n); - a2.(i) <- (mkRel (n-1)); - aux (i+1) (n-2) tl - | (ACLeibniz _)::tl -> - a1.(i) <- (mkRel n); - a2.(i) <- (mkRel n); - aux (i+1) (n-1) tl - | [] -> () in - aux 0 n args; - if (match body with ACSetoid setoid when setoid.set_aeq = Lazy.force coqiff -> true | _ -> false) - then mkArrow (mkApp (m,a1)) (lift 1 (mkApp (m, a2))) - else - match body with - ACSetoid setoid -> - mkApp (setoid.set_aeq, [|(mkApp (m, a1)); (mkApp (m, a2))|]) - | ACLeibniz t -> - mkApp ((Lazy.force coqeq), [|t; (mkApp (m, a1)); (mkApp (m, a2))|]) - -let gen_lemma_middle m args body n = - let rec aux i n = - function - | [] -> gen_lemma_tail m args body n - | (ACSetoid setoid)::tl -> - let t = setoid.set_a in - mkArrow (mkApp (setoid.set_aeq, - [|(mkRel i); (mkRel (i-1))|])) (aux (i-1) (n+1) tl) - | (ACLeibniz t)::tl -> aux (i-1) n tl - in aux n n args - -let gen_compat_lemma env m body args = - let rec aux n = - function - (ACSetoid setoid)::tl -> - let t = setoid.set_a in - prod_create env (t,(prod_create env (t, (aux (n+2) tl)))) - | (ACLeibniz t)::tl -> - prod_create env (t, (aux (n+1) tl)) - | [] -> gen_lemma_middle m args body n - in aux 0 args +(*CSC: I do not like this very much. I would prefer relation classes + to be CIC objects. Keeping backward compatibility, however, is annoying. *) +let cic_relation_class_of_relation_class = + function + ACReflexive {refl_a = refl_a; refl_aeq = refl_aeq; refl_refl = refl_refl} -> + mkApp ((Lazy.force coq_Reflexive), [| refl_a ; refl_aeq; refl_refl |]) + | ACLeibniz t -> mkApp ((Lazy.force coq_Leibniz), [| t |]) + +let gen_compat_lemma_statement output args m = + let rec mk_signature = + function + [] -> assert false + | [last] -> + mkApp ((Lazy.force coq_singl), [| Lazy.force coq_Relation_Class; last |]) + | he::tl -> + mkApp ((Lazy.force coq_cons), + [| Lazy.force coq_Relation_Class; he ; mk_signature tl |]) + in + let output = cic_relation_class_of_relation_class output in + let args= mk_signature (List.map cic_relation_class_of_relation_class args) in + args, output, + mkApp ((Lazy.force coq_make_compatibility_goal), [| args ; output ; m |]) let new_morphism m id hook = let env = Global.env() in let typeofm = (Typing.type_of env Evd.empty m) in - let typ = (nf_betaiota typeofm) in (* nf_bdi avant, mais bug *) + let typ = (nf_betaiota typeofm) in let (argsrev, output) = (decompose_prod typ) in let args_ty = (List.map snd (List.rev argsrev)) in if (args_ty=[]) @@ -524,371 +457,420 @@ let new_morphism m id hook = else if (check_is_dependent typ (List.length args_ty)) then errorlabstrm "New Morphism" (str "The term " ++ prterm m ++ str" should not be a dependent product") - else ( - let args = List.map default_setoid_for_carrier args_ty in - let output = default_setoid_for_carrier output in - let lem = (gen_compat_lemma env m output args) in - new_edited id (m,args,output); - Pfedit.start_proof id (IsGlobal (Proof Lemma)) - (Declare.clear_proofs (Global.named_context ())) - lem hook; - (Options.if_verbose msg (Pfedit.pr_open_subgoals ()))) - -let rec sub_bool n = function - | [] -> [] - | (ACSetoid setoid)::tl -> (setoid, n)::(sub_bool (n-2) tl) - | (ACLeibniz _)::tl -> (sub_bool (n-1) tl) - -let gen_lemma_iff_tail m mext args n k = - let a1 = Array.create k (mkRel 0) in - let a2 = Array.create k (mkRel 0) in - let nb = List.length args in - let b1 = Array.create nb (mkRel 0) in - let b2 = Array.create nb (mkRel 0) in - let rec aux i j = function - |[] -> () - |(ACSetoid _)::tl -> - (a1.(i) <- (mkRel j); - a1.(i+1) <- (mkRel (j-1)); - a2.(i) <- (mkRel (j-1)); - a2.(i+1) <- (mkRel j); - aux (i+2) (j-2) tl) - |(ACLeibniz _)::tl -> - (a1.(i) <- (mkRel j); - a2.(i) <- (mkRel j); - aux (i+1) (j-1) tl) in - let rec aux2 i j = function - | ({set_a=a; set_th=th; set_aeq=aeq},p)::tl -> - a1.(i) <- (mkRel j); - a2.(i) <- mkApp ((Lazy.force coq_seq_sym), - [|a; aeq; th; (mkRel p); (mkRel (p-1)); (mkRel j)|]); - aux2 (i+1) (j-1) tl - | [] -> () in - let rec aux3 i j = function - | (ACSetoid _)::tl -> - b1.(i) <- (mkRel j); - b2.(i) <- (mkRel (j-1)); - aux3 (i+1) (j-2) tl - | (ACLeibniz _)::tl -> - b1.(i) <- (mkRel j); - b2.(i) <- (mkRel j); - aux3 (i+1) (j-1) tl - | [] -> () in - aux 0 k args; - aux2 n (k-n) (sub_bool k args); - aux3 0 k args; - mkApp ((Lazy.force coqconj), - [|(mkArrow (mkApp (m,b1)) (lift 1 (mkApp (m, b2)))); - (mkArrow (mkApp (m,b2)) (lift 1 (mkApp (m, b1)))); - (mkApp (mext, a1));(mkApp (mext, a2))|]) - -let gen_lemma_iff_middle env m mext args n = - let rec aux i k = - function - [] -> gen_lemma_iff_tail m mext args n k - | (ACSetoid setoid)::tl -> - lambda_create env - ((mkApp (setoid.set_aeq, [|(mkRel i); (mkRel (i-1))|])), - (aux (i-1) (k+1) tl)) - | (ACLeibniz t)::tl -> aux (i-1) k tl - in aux n n args - -let gen_lem_iff env m mext args = - let rec aux n = - function - (ACSetoid setoid)::tl -> - let t = setoid.set_a in - lambda_create env (t,(lambda_create env (t, (aux (n+2) tl)))) - | (ACLeibniz t)::tl -> - lambda_create env (t, (aux (n+1) tl)) - | [] -> gen_lemma_iff_middle env m mext args n - in aux 0 args - -let add_morphism lem_name (m,args,output) = - let env = Global.env() in - let mext = (current_constant lem_name) in - let args_constr= List.map constr_setoid_class_of_setoid_setoid_class args in - let output_constr = constr_setoid_class_of_setoid_setoid_class output in - (if (match output with ACSetoid setoid when setoid.set_aeq = Lazy.force coqiff -> true | _ -> false) - then - (let lem_2 = gen_lem_iff env m mext args in - let lem2_name = add_suffix lem_name "2" in - let _ = Declare.declare_constant lem2_name - ((DefinitionEntry {const_entry_body = lem_2; - const_entry_type = None; - const_entry_opaque = true}), - IsProof Lemma) in - let lem2 = (current_constant lem2_name) in - (Lib.add_anonymous_leaf - (morphism_to_obj (m, - { lem = mext; - args = args_constr; - output = output_constr; - lem2 = (Some lem2)}))); - Options.if_verbose message ((string_of_id lem2_name) ^ " is defined")) else - (Lib.add_anonymous_leaf - (morphism_to_obj (m, - { lem = mext; - args = args_constr; - output = output_constr; - lem2 = None})))); - Options.if_verbose ppnl (prterm m ++str " is registered as a morphism") + begin + let args = List.map default_relation_for_carrier args_ty in + let output = default_relation_for_carrier output in + let argsconstr,outputconstr,lem = + gen_compat_lemma_statement output args m + in + new_edited id (m,args,argsconstr,output,outputconstr); + Pfedit.start_proof id (IsGlobal (Proof Lemma)) + (Declare.clear_proofs (Global.named_context ())) + lem hook; + (* "unfold make_compatibility_goal" *) + Pfedit.by + (Tactics.unfold_constr + (Lazy.force coq_make_compatibility_goal_ref)) ; + (* "unfold make_compatibility_goal_aux" *) + Pfedit.by + (Tactics.unfold_constr + (Lazy.force coq_make_compatibility_goal_aux_ref)) ; + (* "simpl" *) + Pfedit.by Tactics.simpl_in_concl ; + Options.if_verbose msg (Pfedit.pr_open_subgoals ()); + end + +let add_morphism lemma_infos mor_name (m,args,output) = + let env = Global.env() in + begin + match lemma_infos with + None -> () (* the Morphism_Theory object has alrady been created *) + | Some (lem_name,argsconstr,outputconstr) -> + (* only the compatibility has been proved; we need to declare the + Morphism_Theory object *) + let mext = current_constant lem_name in + ignore ( + Declare.declare_constant mor_name + (DefinitionEntry + {const_entry_body = + mkApp ((Lazy.force coq_Build_Morphism_Theory), + [| argsconstr; outputconstr; m ; mext |]); + const_entry_type = None; + const_entry_opaque = false}, + IsDefinition)) + end ; + let mmor = current_constant mor_name in + let args_constr = + List.map constr_relation_class_of_relation_relation_class args in + let output_constr = constr_relation_class_of_relation_relation_class output in + Lib.add_anonymous_leaf + (morphism_to_obj (m, + { args = args_constr; + output = output_constr; + lem = mmor })); + Options.if_verbose ppnl (prterm m ++ str " is registered as a morphism") let morphism_hook stre ref = let pf_id = id_of_global ref in + let mor_id = id_of_string (string_of_id pf_id ^ "_morphism_theory") in + let (m,args,argsconstr,output,outputconstr) = what_edited pf_id in if (is_edited pf_id) then - (add_morphism pf_id (what_edited pf_id); no_more_edited pf_id) + add_morphism (Some (pf_id,argsconstr,outputconstr)) mor_id + (m,args,output); no_more_edited pf_id let new_named_morphism id m = new_morphism (constr_of m) id morphism_hook +(************************ Add Setoid ******************************************) + +(*CSC: I do not like this. I would prefer more self-describing constant names *) +let gen_morphism_name = + let i = ref 0 in + function () -> + incr i; + make_ident "morphism_of_setoid_equality" (Some !i) + +(* The vernac command "Add Setoid" *) +let add_setoid a aeq th = + let a = constr_of a in + let aeq = constr_of aeq in + let th = constr_of th in + let env = Global.env () in + if is_conv env Evd.empty (Typing.type_of env Evd.empty th) + (mkApp ((Lazy.force coq_Setoid_Theory), [| a; aeq |])) + then + begin + let refl = mkApp ((Lazy.force coq_seq_refl), [| a; aeq; th |]) in + let sym = mkApp ((Lazy.force coq_seq_sym), [| a; aeq; th |]) in + int_add_relation a aeq (Some refl) (Some sym) ; + let mor_name = gen_morphism_name () in + let _ = + Declare.declare_constant mor_name + (DefinitionEntry + {const_entry_body = + mkApp + ((Lazy.force coq_equality_morphism_of_setoid_theory), + [| a; aeq; th |]) ; + const_entry_type = None; + const_entry_opaque = false}, + IsDefinition) in + let aeq_rel = + ACReflexive + {refl_a = a ; refl_aeq = aeq ; refl_refl = refl ; refl_sym = (Some sym)} + in + add_morphism None mor_name + (aeq,[aeq_rel;aeq_rel],Lazy.force coq_prop_relation) + end + else + errorlabstrm "Add Setoid" (str "Not a valid setoid theory") + + (****************************** The tactic itself *******************************) type constr_with_marks = - | MApp of morphism_class Lazy.t * constr_with_marks array - | Toreplace of setoid - | Tokeep + | MApp of constr * morphism_class * constr_with_marks array + | Toreplace + | Tokeep of constr | Mimp of constr_with_marks * constr_with_marks let is_to_replace = function - | Tokeep -> false - | Toreplace _ -> true + | Tokeep _ -> false + | Toreplace -> true | MApp _ -> true | Mimp _ -> true let get_mark a = Array.fold_left (||) false (Array.map is_to_replace a) -exception Use_replace +type argument = + Toapply of constr (* apply the function to the argument *) + | Toexpand of name * types (* beta-expand the function w.r.t. an argument + of this type *) +let beta_expand c args_rev = + let rec to_expand = + function + [] -> [] + | (Toapply _)::tl -> to_expand tl + | (Toexpand (name,s))::tl -> (name,s)::(to_expand tl) in + let rec aux n = + function + [] -> [] + | (Toapply arg)::tl -> arg::(aux n tl) + | (Toexpand _)::tl -> (mkRel n)::(aux (n + 1) tl) + in + compose_lam (to_expand args_rev) + (mkApp (c, Array.of_list (List.rev (aux 1 args_rev)))) -let mark_occur gl hyp = +let relation_of_hypothesis_and_term_to_rewrite gl (_,h) t = + let hypt = pf_type_of gl h in + let (heq, hargs) = decompose_app hypt in + let rec get_all_but_last_two = + function + [] + | [_] -> assert false + | [_;_] -> [] + | he::tl -> he::(get_all_but_last_two tl) in + let aeq = mkApp (heq,(Array.of_list (get_all_but_last_two hargs))) in + try + relation_table_find aeq + with Not_found -> + (*CSC: still "setoid" in the error message *) + errorlabstrm "Setoid_rewrite" + (prterm aeq ++ str " is not a setoid equality.") + +let mark_occur t in_c = let rec aux t in_c = - if (eq_constr t in_c) then - let sa = - match hyp with - None -> - (match default_setoid_for_carrier (pf_type_of gl t) with - ACSetoid sa -> sa - | ACLeibniz _ -> raise Use_replace) - | Some h -> - let hypt = pf_type_of gl h in - let (heq, hargs) = decompose_app hypt in - let rec get_all_but_last_two = - function - [] - | [_] -> assert false - | [_;_] -> [] - | he::tl -> he::(get_all_but_last_two tl) in - let aeq = mkApp (heq,(Array.of_list (get_all_but_last_two hargs))) in - try - setoid_table_find aeq - with Not_found -> - errorlabstrm "Setoid_rewrite" - (prterm aeq ++ str " is not a setoid equality.") - in - Toreplace sa + if eq_constr t in_c then + Toreplace else match kind_of_term in_c with | App (c,al) -> - let a = Array.map (aux t) al in - let mor = - lazy - (try - begin - match morphism_table_find c with - [] -> assert false - | morphism::tl -> - if tl <> [] then - msg_warning - (str "There are several morphisms declared for " ++ - prterm c ++ - str ". The morphism " ++ prmorphism c morphism ++ - str " is randomly chosen.") ; - ACMorphism (setoid_morphism_of_constr_morphism morphism) - end - with Not_found -> - let env = Global.env() in - let typeofc = (Typing.type_of env Evd.empty c) in - let typ = nf_betaiota typeofc in - let (argsrev, output) = decompose_prod typ in - ACFunction - {f_args=List.rev (List.map snd argsrev); f_output=output}) - in - if (get_mark a) then MApp (mor,a) else Tokeep + let a = Array.map (aux t) al in + if not (get_mark a) then Tokeep in_c + else + let mor = + try + begin + match morphism_table_find c with + [] -> assert false + | morphism::tl -> + if tl <> [] then + msg_warning + (str "There are several morphisms declared for " ++ + prterm c ++ + str ". The morphism " ++ prmorphism c morphism ++ + str " is randomly chosen.") ; + Some + (ACMorphism + (relation_morphism_of_constr_morphism morphism)) + end + with Not_found -> None + in + (match mor with + Some mor -> MApp (c,mor,a) + | None -> + (* the tactic works only if the function type is + made of non-dependent products only. However, here we + can cheat a bit by partially istantiating c to match + the requirement when the arguments to be replaced are + bound by non-dependent products only. *) + let env = Global.env() in + let typeofc = (Typing.type_of env Evd.empty c) in + let typ = nf_betaiota typeofc in + let rec find_non_dependent_function env c c_args_rev typ + f_args_rev a_rev= + function + [] -> + let mor = + ACFunction {f_args=List.rev f_args_rev ; f_output=typ} in + let func = beta_expand c c_args_rev in + MApp (func,mor,Array.of_list (List.rev a_rev)) + | (he::tl) as a-> + let typnf = Reduction.whd_betadeltaiota env typ in + match kind_of_term typnf with + Cast (typ,_) -> + find_non_dependent_function env c c_args_rev typ + f_args_rev a_rev a + | Prod (name,s,t) -> + let env' = push_rel (name,None,s) env in + begin + match noccurn 1 t, he with + _, Tokeep arg -> + (* generic product, to keep *) + find_non_dependent_function + env' c ((Toapply arg)::c_args_rev) + (subst1 arg t) f_args_rev a_rev tl + | true, _ -> + (* non-dependent product, to replace *) + find_non_dependent_function + env' c ((Toexpand (name,s))::c_args_rev) + (lift 1 t) (s::f_args_rev) (he::a_rev) tl + | false, _ -> + (* dependent product, to replace *) + (*CSC: this limitation is due to the reflexive + implementation and it is hard to lift *) + errorlabstrm "Setoid_replace" + (str "Cannot rewrite in the argument of a " ++ + str "dependent product. If you need this " ++ + str "feature, please report to the authors.") + end + | _ -> assert false + in + find_non_dependent_function env c [] typ [] [] + (Array.to_list a)) | Prod (_, c1, c2) -> - if (dependent (mkRel 1) c2) - then Tokeep - else - let c1m = aux t c1 in - let c2m = aux t c2 in - if ((is_to_replace c1m)||(is_to_replace c2m)) - then (Mimp (c1m, c2m)) - else Tokeep - | _ -> Tokeep + if (dependent (mkRel 1) c2) + then Tokeep in_c + else + let c1m = aux t c1 in + let c2m = aux t c2 in + if ((is_to_replace c1m)||(is_to_replace c2m)) + then (Mimp (c1m, c2m)) + else Tokeep in_c + | _ -> Tokeep in_c + in aux t in_c + +let cic_morphism_context_list_of_list hole_relation = + let rec aux = + function + [] -> assert false + | [out,value] -> + mkApp ((Lazy.force coq_singl), [| Lazy.force coq_Relation_Class ; out |]), + mkApp ((Lazy.force coq_fcl_singl), [| hole_relation; out ; value |]) + | (out,value)::tl -> + let outtl, valuetl = aux tl in + mkApp ((Lazy.force coq_cons), + [| Lazy.force coq_Relation_Class ; out ; outtl |]), + mkApp ((Lazy.force coq_fcl_cons), + [| hole_relation ; out ; outtl ; value ; valuetl |]) in aux -let create_args ca ma args c1 c2 = - let rec aux i = function - | [] -> [] - | (ACSetoid _)::tl -> - if is_to_replace ma.(i) - then (replace_term c1 c2 ca.(i))::ca.(i)::(aux (i+1) tl) - else ca.(i)::ca.(i)::(aux (i+1) tl) - | (ACLeibniz _)::tl -> - if is_to_replace ma.(i) - then - let newarg = replace_term c1 c2 ca.(i) in - newarg::(aux (i+1) tl) - else ca.(i)::(aux (i+1) tl) - in - aux 0 args - -let res_tac sa c hyp glll = - let fin = match hyp with - | None -> Auto.full_trivial - | Some h -> - tclORELSE (tclTHEN (tclTRY (apply h)) (tclFAIL 0 "")) - (tclORELSE (tclTHEN (tclTRY (tclTHEN (apply (mkApp ((Lazy.force coq_seq_sym), [|sa.set_a; sa.set_aeq; sa.set_th|]))) (apply h))) (tclFAIL 0 "")) - Auto.full_trivial) +let rec cic_type_nelist_of_list = + function + [] -> assert false + | [value] -> + mkApp ((Lazy.force coq_singl), [| mkType (Termops.new_univ ()) ; value |]) + | value::tl -> + mkApp ((Lazy.force coq_cons), + [| mkType (Termops.new_univ ()); value; cic_type_nelist_of_list tl |]) + +let syntactic_but_representation_of_marked_but hole_relation = + let rec aux out = + function + MApp (f, m, args) -> + let morphism_theory, relations = + match m with + ACMorphism { args = args ; lem = lem } -> lem,args + | ACFunction { f_args = f_args ; f_output = f_output } -> + let mt = + if eq_constr out (cic_relation_class_of_relation_class + (Lazy.force coq_prop_relation)) + then + mkApp ((Lazy.force coq_morphism_theory_of_predicate), + [| cic_type_nelist_of_list f_args; f|]) + else + mkApp ((Lazy.force coq_morphism_theory_of_function), + [| cic_type_nelist_of_list f_args; f_output; f|]) + in + mt,List.map (fun x -> ACLeibniz x) f_args in + let cic_relations = + List.map cic_relation_class_of_relation_class relations in + let cic_args_relations,argst = + cic_morphism_context_list_of_list hole_relation + (List.combine cic_relations + (List.map2 (fun t v -> aux t v) cic_relations + (Array.to_list args))) + in + mkApp ((Lazy.force coq_App), + [|hole_relation ; cic_args_relations ; out ; morphism_theory ; argst|]) + | Toreplace -> + mkApp ((Lazy.force coq_Toreplace), [| hole_relation |]) + | Tokeep c -> + mkApp ((Lazy.force coq_Tokeep), [| hole_relation ; out ; c |]) + | Mimp (source, target) -> + mkApp ((Lazy.force coq_Imp), + [| hole_relation ; aux out source ; aux out target |]) + in aux + +let apply_coq_setoid_rewrite hole_relation c1 c2 (lft2rgt,h) m = + let {refl_aeq=hole_equality; refl_sym=hole_symmetry} = hole_relation in + let hole_relation = + cic_relation_class_of_relation_class (ACReflexive hole_relation) in + let prop_relation = + cic_relation_class_of_relation_class (Lazy.force coq_prop_relation) in + let hyp = + if lft2rgt then h else + match hole_symmetry with + Some sym -> + mkApp (sym, [| c2 ; c1 ; h |]) + | None -> + errorlabstrm "Setoid_rewrite" + (str "Rewriting from right to left not permitted since the " ++ + str "relation " ++ prterm hole_equality ++ str " is not known " ++ + str "to be symmetric. Either declare it as a symmetric " ++ + str "relation or use setoid_replace or (setoid_)rewrite from " ++ + str "left to right only.") + in + mkApp ((Lazy.force coq_setoid_rewrite), + [| hole_relation ; prop_relation ; c1 ; c2 ; + syntactic_but_representation_of_marked_but hole_relation + prop_relation m ; hyp |]) + +let relation_rewrite c1 c2 (lft2rgt,cl) gl = + let but = pf_concl gl in + let (hyp,c1,c2) = + let (cl',_) = Clenv.unify_to_subterm cl (c1,but) in + let c1 = Clenv.clenv_instance_term cl' c1 in + let c2 = Clenv.clenv_instance_term cl' c2 in + (lft2rgt,Clenv.clenv_instance_template cl'), c1, c2 + in + let input_relation = relation_of_hypothesis_and_term_to_rewrite gl hyp c1 in + let marked_but = mark_occur c1 but in + let th = + apply_coq_setoid_rewrite input_relation c1 c2 hyp marked_but in - tclORELSE (tclTHEN (tclTRY (apply (mkApp ((Lazy.force coq_seq_refl), [|sa.set_a; sa.set_aeq; sa.set_th;c|])))) (tclFAIL 0 "")) - (tclORELSE assumption - (tclORELSE (tclTHEN (tclTRY (apply (mkApp ((Lazy.force coq_seq_sym), [|sa.set_a; sa.set_aeq; sa.set_th|])))) assumption) - fin)) - -let id_res_tac (*c*) sa = - (apply (mkApp ((Lazy.force coq_seq_refl), [|sa.set_a; sa.set_aeq; sa.set_th(*; c*)|]))) - -(* An exception to catchs errors *) - -exception Nothing_found of constr;; - -(* special case of replace_where_needed_gen where all the arguments - are of class (ACLeibniz _) *) -let rec replace_where_needed hyp ca ma c1 c2 = - let rec aux i = function - | [] -> tclIDTAC - | he::tl -> - if is_to_replace he then - let dummy = mkProp in (* dummy will never be used *) + let thty = pf_type_of gl th in + let simplified_thty = + pf_unfoldn [[], Lazy.force coq_iff] gl + (pf_unfoldn [[], Lazy.force coq_relation_of_relation_class] gl thty) + in + let ty1,ty2 = + match destApplication simplified_thty with + (_ (*and*),[|ty1;ty2|]) -> ty1,ty2 + | _ -> assert false + in + let th' = mkApp ((Lazy.force coq_proj2), [|ty1; ty2; th|]) in + let hyp2 = Termops.replace_term c1 c2 but in + let simplified_thty' = mkProd (Anonymous, hyp2, lift 1 but) in + (*CSC: the next line does not work because simplified_thty' is not + used to generate the type of the new goals ;-( + Tactics.apply (mkCast (th',simplified_thty')) gl + Thus I am using the following longer (and less accurate) code *) tclTHENS - (!replace ca.(i) (replace_term c1 c2 ca.(i))) - [aux (i+1) tl; zapply (Some(ACLeibniz dummy)) false ca.(i) he c1 c2 hyp] - else - (aux (i+1) tl) - in - aux 0 ma -and replace_where_needed_gen hyp ca ma args c1 c2 = - let rec aux i = function - | [] -> tclIDTAC - | ((ACLeibniz _) as he)::tl -> - if is_to_replace ma.(i) then - tclTHENS - (!replace ca.(i) (replace_term c1 c2 ca.(i))) - [aux (i+1) tl ; zapply (Some he) false ca.(i) ma.(i) c1 c2 hyp ] - else - aux (i+1) tl - | (ACSetoid _)::tl -> aux (i+1) tl - in - aux 0 args -and create_tac_list i a al c1 c2 hyp = function - | [] -> [] - | (ACLeibniz _)::tl -> create_tac_list (i+1) a al c1 c2 hyp tl - | ((ACSetoid setoid) as he)::tl -> - if (is_to_replace a.(i)) - then (zapply (Some he) false al.(i) a.(i) c1 c2 hyp)::(create_tac_list (i+1) a al c1 c2 hyp tl) - else (id_res_tac (*al.(i)*) setoid)::(create_tac_list (i+1) a al c1 c2 hyp tl) - -and zapply close is_r gl gl_m c1 c2 hyp glll = - (match ((kind_of_term gl), gl_m) with - | ((App (c,al)),(MApp (m,a))) -> - (match Lazy.force m with - ACMorphism m -> - let args = Array.of_list (create_args al a m.args c1 c2) in - tclTHENS - (replace_where_needed_gen hyp al a m.args c1 c2) - [if is_r - then tclTHENS (apply (mkApp (m.lem, args))) - ((create_tac_list 0 a al c1 c2 hyp m.args)@[tclIDTAC]) - else - match m.lem2 with - None -> - tclTHENS (apply (mkApp (m.lem, args))) - (create_tac_list 0 a al c1 c2 hyp m.args) - | Some xom -> - tclTHENS (apply (mkApp (xom, args))) - (create_tac_list 0 a al c1 c2 hyp m.args)] - | ACFunction f -> - tclTHENS - (replace_where_needed hyp al (Array.to_list a) c1 c2) - [match close with - None -> tclIDTAC - | Some (ACLeibniz _) -> reflexivity - | Some (ACSetoid setoid) -> id_res_tac setoid]) - | ((Prod (_,hh, cc)),(Mimp (hhm, ccm))) -> - let al = [|hh; cc|] in - let a = [|hhm; ccm|] in - let fleche_constr = (Lazy.force coq_fleche) in - let fleche_cp = destConst fleche_constr in - let new_concl = (mkApp (fleche_constr, al)) in - let m = find_morphism_fleche () in - if is_r - then - let args = Array.of_list (create_args al a m.args c1 c2) in - tclTHEN (change_in_concl None new_concl) - (tclTHENS (apply (mkApp (m.lem, args))) - ((create_tac_list 0 a al c1 c2 hyp m.args)@[unfold_constr (ConstRef fleche_cp)])) - else - (zapply (Some m.output) is_r new_concl - (MApp (lazy (ACMorphism m),a)) c1 c2 hyp) - | (_, Toreplace setoid) -> - if is_r - then (match hyp with - | None -> errorlabstrm "Setoid_replace" - (str "You should use the tactic Replace here") - | Some h -> - let hypt = pf_type_of glll h in - let (heq, hargs) = decompose_app hypt in - let rec get_last_two = function - | [c1;c2] -> (c1, c2) - | x::y::z -> get_last_two (y::z) - | _ -> assert false in - let (hc1,hc2) = get_last_two hargs in - if c1 = hc1 - then - apply (mkApp (Lazy.force coqproj2,[|(mkArrow hc1 hc2);(mkArrow hc2 hc1);h|])) - else - apply (mkApp (Lazy.force coqproj1,[|(mkArrow hc1 hc2);(mkArrow hc2 hc1);h|])) - ) - else (res_tac setoid gl hyp glll) - | (_, Tokeep) -> (match hyp with - | None -> errorlabstrm "Setoid_replace" - (str "No replacable occurence of " ++ prterm c1 ++ str " found") - | Some _ ->errorlabstrm "Setoid_replace" - (str "No rewritable occurence of " ++ prterm c1 ++ str " found")) - | _ -> assert false) glll - -let setoid_replace c1 c2 hyp gl = - let but = (pf_concl gl) in - try - (zapply None true but (mark_occur gl hyp c1 but) c1 c2 hyp) gl - with - Use_replace -> (!replace c1 c2) gl + (Tactics.apply (mkCast (th',simplified_thty'))) + [Tactics.change_in_concl None hyp2] gl + (*CSC: this is another way to proceed, but the generated proof_term + would be much bigger than possible + Tactics.forward true Anonymous (mkCast (th',simplified_thty')) gl + (... followed by the application of the introduced hypothesis ...) + *) let general_s_rewrite lft2rgt c gl = - let ctype = pf_type_of gl c in - let (equiv, args) = decompose_app ctype in - let rec get_last_two = function - | [c1;c2] -> (c1, c2) - | x::y::z -> get_last_two (y::z) - | _ -> error "The term provided is not an equivalence" in - let (c1,c2) = get_last_two args in - if lft2rgt - then setoid_replace c1 c2 (Some c) gl - else setoid_replace c2 c1 (Some c) gl - -let setoid_replace c1 c2 = setoid_replace c1 c2 None + let (wc,_) = Evar_refiner.startWalk gl in + let ctype = pf_type_of gl c in + let eqclause = + Clenv.make_clenv_binding wc (c,ctype) Rawterm.NoBindings in + let (equiv, args) = + decompose_app (Clenv.clenv_instance_template_type eqclause) in + let rec get_last_two = function + | [c1;c2] -> (c1, c2) + | x::y::z -> get_last_two (y::z) + | _ -> error "The term provided is not an equivalence" in + let (c1,c2) = get_last_two args in + if lft2rgt + then relation_rewrite c1 c2 (lft2rgt,eqclause) gl + else relation_rewrite c2 c1 (lft2rgt,eqclause) gl + +exception Use_replace + +(*CSC: the name should be changed *) +let setoid_replace c1 c2 gl = + try + let relation = + match default_relation_for_carrier (pf_type_of gl c1) with + ACReflexive sa -> sa + | ACLeibniz _ -> raise Use_replace + in + let eq = mkApp (relation.refl_aeq, [| c1 ; c2 |]) in + tclTHENS (assert_tac false Anonymous eq) + [onLastHyp (fun id -> + tclTHEN + (general_s_rewrite true (mkVar id)) + (clear [id])); + Tacticals.tclIDTAC] gl + with + Use_replace -> (!replace c1 c2) gl let setoid_rewriteLR = general_s_rewrite true diff --git a/tactics/setoid_replace.mli b/tactics/setoid_replace.mli index 02046c55b..e41728ead 100644 --- a/tactics/setoid_replace.mli +++ b/tactics/setoid_replace.mli @@ -27,6 +27,9 @@ val setoid_rewriteRL : constr -> tactic val general_s_rewrite : bool -> constr -> tactic +val add_relation : + constr_expr -> constr_expr -> constr_expr option -> constr_expr option -> unit + val add_setoid : constr_expr -> constr_expr -> constr_expr -> unit val new_named_morphism : Names.identifier -> constr_expr -> unit diff --git a/theories/Setoids/Setoid.v b/theories/Setoids/Setoid.v index bca2bf9de..bf54f0567 100644 --- a/theories/Setoids/Setoid.v +++ b/theories/Setoids/Setoid.v @@ -1,3 +1,4 @@ + (************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) (* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *) @@ -8,64 +9,345 @@ (*i $Id$: i*) -Section Setoid. +Set Implicit Arguments. + +(* DEFINITIONS OF Relation_Class AND n-ARY Morphism_Theory *) + +Definition is_reflexive (A: Type) (Aeq: A -> A -> Prop) : Prop := + forall x:A, Aeq x x. + +Definition is_symmetric (A: Type) (Aeq: A -> A -> Prop) : Prop := + forall (x y:A), Aeq x y -> Aeq y x. + +Inductive Relation_Class : Type := + Reflexive : forall A Aeq, (@is_reflexive A Aeq) -> Relation_Class + | Leibniz : Type -> Relation_Class. + +Implicit Type Hole Out: Relation_Class. + +Definition carrier_of_relation_class : Relation_Class -> Type. + intro; case X; intros. + exact A. + exact T. +Defined. + +Inductive nelistT (A : Type) : Type := + singl : A -> (nelistT A) + | cons : A -> (nelistT A) -> (nelistT A). + +Implicit Type In: (nelistT Relation_Class). + +Definition function_type_of_morphism_signature : + (nelistT Relation_Class) -> Relation_Class -> Type. + intros In Out. + induction In. + exact (carrier_of_relation_class a -> carrier_of_relation_class Out). + exact (carrier_of_relation_class a -> IHIn). +Defined. + +Definition make_compatibility_goal_aux: + forall In Out + (f g: function_type_of_morphism_signature In Out), Prop. + intros; induction In; simpl in f, g. + induction a; destruct Out; simpl in f, g. + exact (forall (x1 x2: A), (Aeq x1 x2) -> (Aeq0 (f x1) (g x2))). + exact (forall (x1 x2: A), (Aeq x1 x2) -> f x1 = g x2). + exact (forall (x: T), (Aeq (f x) (g x))). + exact (forall (x: T), f x = g x). + induction a; simpl in f, g. + exact (forall (x1 x2: A), (Aeq x1 x2) -> IHIn (f x1) (g x2)). + exact (forall (x: T), IHIn (f x) (g x)). +Defined. + +Definition make_compatibility_goal := + (fun In Out f => make_compatibility_goal_aux In Out f f). + +Record Morphism_Theory In Out : Type := + {Function : function_type_of_morphism_signature In Out; + Compat : make_compatibility_goal In Out Function}. + +Definition list_of_Leibniz_of_list_of_types: + nelistT Type -> nelistT Relation_Class. + induction 1. + exact (singl (Leibniz a)). + exact (cons (Leibniz a) IHX). +Defined. + +(* every function is a morphism from Leibniz+ to Leibniz *) +Definition morphism_theory_of_function : + forall (In: nelistT Type) (Out: Type), + let In' := list_of_Leibniz_of_list_of_types In in + let Out' := Leibniz Out in + function_type_of_morphism_signature In' Out' -> + Morphism_Theory In' Out'. + intros. + exists X. + induction In; unfold make_compatibility_goal; simpl. + reflexivity. + intro; apply (IHIn (X x)). +Defined. + +(* THE Prop RELATION CLASS *) + +Add Relation Prop iff reflexivity proved by iff_refl symmetry proved by iff_sym. + +Definition Prop_Relation_Class : Relation_Class. + eapply (@Reflexive _ iff). + exact iff_refl. +Defined. + +(* every predicate is morphism from Leibniz+ to Prop_Relation_Class *) +Definition morphism_theory_of_predicate : + forall (In: nelistT Type), + let In' := list_of_Leibniz_of_list_of_types In in + function_type_of_morphism_signature In' Prop_Relation_Class -> + Morphism_Theory In' Prop_Relation_Class. + intros. + exists X. + induction In; unfold make_compatibility_goal; simpl. + intro; apply iff_refl. + intro; apply (IHIn (X x)). +Defined. + +(* THE CIC PART OF THE REFLEXIVE TACTIC (SETOID REWRITE) *) + +Inductive Morphism_Context Hole : Relation_Class -> Type := + App : forall In Out, + Morphism_Theory In Out -> Morphism_Context_List Hole In -> + Morphism_Context Hole Out + | Toreplace : Morphism_Context Hole Hole + | Tokeep : + forall (S: Relation_Class), + carrier_of_relation_class S -> Morphism_Context Hole S + | Imp : + Morphism_Context Hole Prop_Relation_Class -> + Morphism_Context Hole Prop_Relation_Class -> + Morphism_Context Hole Prop_Relation_Class +with Morphism_Context_List Hole: nelistT Relation_Class -> Type := + fcl_singl : + forall (S: Relation_Class), Morphism_Context Hole S -> + Morphism_Context_List Hole (singl S) + | fcl_cons : + forall (S: Relation_Class) (L: nelistT Relation_Class), + Morphism_Context Hole S -> Morphism_Context_List Hole L -> + Morphism_Context_List Hole (cons S L). + +Scheme Morphism_Context_rect2 := Induction for Morphism_Context Sort Type +with Morphism_Context_List_rect2 := Induction for Morphism_Context_List Sort Type. + +Inductive prodT (A B: Type) : Type := + pairT : A -> B -> prodT A B. + +Definition product_of_relation_class_list : nelistT Relation_Class -> Type. + induction 1. + exact (carrier_of_relation_class a). + exact (prodT (carrier_of_relation_class a) IHX). +Defined. -Variable A : Type. -Variable Aeq : A -> A -> Prop. +Definition relation_of_relation_class: + forall Out, + carrier_of_relation_class Out -> carrier_of_relation_class Out -> Prop. + destruct Out. + exact Aeq. + exact (@eq T). +Defined. -Record Setoid_Theory : Prop := +Definition relation_of_product_of_relation_class_list: + forall In, + product_of_relation_class_list In -> product_of_relation_class_list In -> Prop. + induction In. + exact (relation_of_relation_class a). + + simpl; intros. + destruct X; destruct X0. + exact (relation_of_relation_class a c c0 /\ IHIn p p0). +Defined. + +Definition apply_morphism: + forall In Out (m: function_type_of_morphism_signature In Out) + (args: product_of_relation_class_list In), carrier_of_relation_class Out. + intros. + induction In. + exact (m args). + simpl in m, args. + destruct args. + exact (IHIn (m c) p). +Defined. + +Theorem apply_morphism_compatibility: + forall In Out (m1 m2: function_type_of_morphism_signature In Out) + (args1 args2: product_of_relation_class_list In), + make_compatibility_goal_aux _ _ m1 m2 -> + relation_of_product_of_relation_class_list _ args1 args2 -> + relation_of_relation_class _ + (apply_morphism _ _ m1 args1) + (apply_morphism _ _ m2 args2). + intros. + induction In. + simpl; simpl in m1, m2, args1, args2, H0. + destruct a; destruct Out. + apply H; exact H0. + simpl; apply H; exact H0. + simpl; rewrite H0; apply H. + simpl; rewrite H0; apply H. + simpl in args1, args2, H0. + destruct args1; destruct args2; simpl. + destruct H0. + simpl in H. + destruct a; simpl in H. + apply IHIn. + apply H; exact H0. + exact H1. + rewrite H0; apply IHIn. + apply H. + exact H1. +Qed. + +Definition interp : + forall Hole Out, carrier_of_relation_class Hole -> + Morphism_Context Hole Out -> carrier_of_relation_class Out. + intros Hole Out H t. + elim t using + (@Morphism_Context_rect2 Hole (fun S _ => carrier_of_relation_class S) + (fun L fcl => product_of_relation_class_list L)); + intros. + exact (apply_morphism _ _ (Function m) X). + exact H. + exact c. + exact (X -> X0). + exact X. + split; [ exact X | exact X0 ]. +Defined. + +(*CSC: interp and interp_relation_class_list should be mutually defined, since + the proof term of each one contains the proof term of the other one. However + I cannot do that interactively (I should write the Fix by hand) *) +Definition interp_relation_class_list : + forall Hole (L: nelistT Relation_Class), carrier_of_relation_class Hole -> + Morphism_Context_List Hole L -> product_of_relation_class_list L. + intros Hole L H t. + elim t using + (@Morphism_Context_List_rect2 Hole (fun S _ => carrier_of_relation_class S) + (fun L fcl => product_of_relation_class_list L)); + intros. + exact (apply_morphism _ _ (Function m) X). + exact H. + exact c. + exact (X -> X0). + exact X. + split; [ exact X | exact X0 ]. +Defined. + +Theorem setoid_rewrite: + forall Hole Out (E1 E2: carrier_of_relation_class Hole) + (E: Morphism_Context Hole Out), + (relation_of_relation_class Hole E1 E2) -> + (relation_of_relation_class Out (interp E1 E) (interp E2 E)). + intros. + elim E using + (@Morphism_Context_rect2 Hole + (fun S E => relation_of_relation_class S (interp E1 E) (interp E2 E)) + (fun L fcl => + relation_of_product_of_relation_class_list _ + (interp_relation_class_list E1 fcl) + (interp_relation_class_list E2 fcl))); + intros. + change (relation_of_relation_class Out0 + (apply_morphism _ _ (Function m) (interp_relation_class_list E1 m0)) + (apply_morphism _ _ (Function m) (interp_relation_class_list E2 m0))). + apply apply_morphism_compatibility. + exact (Compat m). + exact H0. + + exact H. + + unfold interp, Morphism_Context_rect2. + (*CSC: reflexivity used here*) + destruct S. + apply i. + simpl; reflexivity. + + change + (relation_of_relation_class Prop_Relation_Class + (interp E1 m -> interp E1 m0) (interp E2 m -> interp E2 m0)). + simpl; simpl in H0, H1. + tauto. + + exact H0. + + change + (relation_of_relation_class _ (interp E1 m) (interp E2 m) /\ + relation_of_product_of_relation_class_list _ + (interp_relation_class_list E1 m0) (interp_relation_class_list E2 m0)). + split. + exact H0. + exact H1. +Qed. + +(* BEGIN OF UTILITY/BACKWARD COMPATIBILITY PART *) + +Record Setoid_Theory (A: Type) (Aeq: A -> A -> Prop) : Prop := {Seq_refl : forall x:A, Aeq x x; Seq_sym : forall x y:A, Aeq x y -> Aeq y x; Seq_trans : forall x y z:A, Aeq x y -> Aeq y z -> Aeq x z}. -End Setoid. +Definition relation_class_of_setoid_theory: + forall (A: Type) (Aeq: A -> A -> Prop), + Setoid_Theory Aeq -> Relation_Class. + intros. + apply (@Reflexive _ Aeq). + exact (Seq_refl H). +Defined. -Definition Prop_S : Setoid_Theory Prop iff. -split; [ exact iff_refl | exact iff_sym | exact iff_trans ]. -Qed. +Definition equality_morphism_of_setoid_theory: + forall (A: Type) (Aeq: A -> A -> Prop) (ST: Setoid_Theory Aeq), + let ASetoidClass := relation_class_of_setoid_theory ST in + (Morphism_Theory (cons ASetoidClass (singl ASetoidClass)) + Prop_Relation_Class). + intros. + exists Aeq. + pose (sym := Seq_sym ST); clearbody sym. + pose (trans := Seq_trans ST); clearbody trans. + (*CSC: symmetry and transitivity used here *) + unfold make_compatibility_goal; simpl; split; eauto. +Defined. -Add Setoid Prop iff Prop_S. +(* END OF UTILITY/BACKWARD COMPATIBILITY PART *) -Hint Resolve (Seq_refl Prop iff Prop_S): setoid. -Hint Resolve (Seq_sym Prop iff Prop_S): setoid. -Hint Resolve (Seq_trans Prop iff Prop_S): setoid. +(* A FEW EXAMPLES *) -Add Morphism or : or_ext. -intros. -inversion H1. -left. -inversion H. -apply (H3 H2). +Add Morphism iff : Iff_Morphism. + tauto. +Defined. -right. -inversion H0. -apply (H3 H2). -Qed. +(* impl IS A MORPHISM *) -Add Morphism and : and_ext. -intros. -inversion H1. -split. -inversion H. -apply (H4 H2). +Definition impl (A B: Prop) := A -> B. -inversion H0. -apply (H4 H3). -Qed. +Add Morphism impl : Impl_Morphism. +unfold impl; tauto. +Defined. -Add Morphism not : not_ext. -red in |- *; intros. -apply H0. -inversion H. -apply (H3 H1). -Qed. +(* and IS A MORPHISM *) -Definition fleche (A B:Prop) := A -> B. +Add Morphism and : And_Morphism. + tauto. +Defined. -Add Morphism fleche : fleche_ext. -unfold fleche in |- *. -intros. -inversion H0. -inversion H. -apply (H3 (H1 (H6 H2))). -Qed. +(* or IS A MORPHISM *) + +Add Morphism or : Or_Morphism. + tauto. +Defined. + +(* not IS A MORPHISM *) + +Add Morphism not : Not_Morphism. + tauto. +Defined. + +(* FOR BACKWARD COMPATIBILITY *) +Implicit Arguments Setoid_Theory []. +Implicit Arguments Seq_refl []. +Implicit Arguments Seq_sym []. +Implicit Arguments Seq_trans []. |