1 (************************************************************************)
2 (* v * The Coq Proof Assistant / The Coq Development Team *)
3 (* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
4 (* \VV/ **************************************************************)
5 (* // * This file is distributed under the terms of the *)
6 (* * GNU Lesser General Public License Version 2.1 *)
7 (************************************************************************)
9 (* $Id: setoid_replace.ml 8900 2006-06-06 14:40:27Z letouzey $ *)
12 match LibraryObjects.eq_URI () with
15 raise (ProofEngineTypes.Fail (lazy "You need to register the default equality first. Please use the \"default\" command"))
17 let replace = ref (fun _ _ -> assert false)
18 let register_replace f = replace := f
20 let general_rewrite = ref (fun _ _ -> assert false)
21 let register_general_rewrite f = general_rewrite := f
23 let prlist_with_sepi sep elem =
29 let e = elem n h and r = aux (n+1) t in
37 rel_refl: Cic.term option;
38 rel_sym: Cic.term option;
39 rel_trans : Cic.term option;
40 rel_quantifiers_no: int (* it helps unification *);
41 rel_X_relation_class: Cic.term;
42 rel_Xreflexive_relation_class: Cic.term
45 type 'a relation_class =
46 Relation of 'a (* the rel_aeq of the relation or the relation *)
47 | Leibniz of Cic.term option (* the carrier (if eq is partially instantiated)*)
50 { args : (bool option * 'a relation_class) list;
51 output : 'a relation_class;
53 morphism_theory : Cic.term
57 { f_args : Cic.term list;
62 ACMorphism of relation morphism
65 let constr_relation_class_of_relation_relation_class =
67 Relation relation -> Relation relation.rel_aeq
68 | Leibniz t -> Leibniz t
72 let constr_of c = Constrintern.interp_constr Evd.empty (Global.env()) c
76 let constant dir s = Coqlib.gen_constant "Setoid_replace" ("Setoids"::dir) s
77 *) let constant dir s = assert false
79 let gen_constant dir s = Coqlib.gen_constant "Setoid_replace" dir s
80 *) let gen_constant dir s = assert false
82 let reference dir s = Coqlib.gen_reference "Setoid_replace" ("Setoids"::dir) s
83 let eval_reference dir s = EvalConstRef (destConst (constant dir s))
84 *) let eval_reference dir s = assert false
86 let eval_init_reference dir s = EvalConstRef (destConst (gen_constant ("Init"::dir) s))
90 let current_constant id =
94 anomaly ("Setoid: cannot find " ^ (string_of_id id))
95 *) let current_constant id = assert false
100 (gen_constant ["Relations"; "Relation_Definitions"] "reflexive")
102 (gen_constant ["Relations"; "Relation_Definitions"] "symmetric")
104 (gen_constant ["Relations"; "Relation_Definitions"] "transitive")
106 (gen_constant ["Relations"; "Relation_Definitions"] "relation")
108 let coq_Relation_Class = (constant ["Setoid"] "Relation_Class")
109 let coq_Argument_Class = (constant ["Setoid"] "Argument_Class")
110 let coq_Setoid_Theory = (constant ["Setoid"] "Setoid_Theory")
111 let coq_Morphism_Theory = (constant ["Setoid"] "Morphism_Theory")
112 let coq_Build_Morphism_Theory= (constant ["Setoid"] "Build_Morphism_Theory")
113 let coq_Compat = (constant ["Setoid"] "Compat")
115 let coq_AsymmetricReflexive = (constant ["Setoid"] "AsymmetricReflexive")
116 let coq_SymmetricReflexive = (constant ["Setoid"] "SymmetricReflexive")
117 let coq_SymmetricAreflexive = (constant ["Setoid"] "SymmetricAreflexive")
118 let coq_AsymmetricAreflexive = (constant ["Setoid"] "AsymmetricAreflexive")
119 let coq_Leibniz = (constant ["Setoid"] "Leibniz")
121 let coq_RAsymmetric = (constant ["Setoid"] "RAsymmetric")
122 let coq_RSymmetric = (constant ["Setoid"] "RSymmetric")
123 let coq_RLeibniz = (constant ["Setoid"] "RLeibniz")
125 let coq_ASymmetric = (constant ["Setoid"] "ASymmetric")
126 let coq_AAsymmetric = (constant ["Setoid"] "AAsymmetric")
128 let coq_seq_refl = (constant ["Setoid"] "Seq_refl")
129 let coq_seq_sym = (constant ["Setoid"] "Seq_sym")
130 let coq_seq_trans = (constant ["Setoid"] "Seq_trans")
132 let coq_variance = (constant ["Setoid"] "variance")
133 let coq_Covariant = (constant ["Setoid"] "Covariant")
134 let coq_Contravariant = (constant ["Setoid"] "Contravariant")
135 let coq_Left2Right = (constant ["Setoid"] "Left2Right")
136 let coq_Right2Left = (constant ["Setoid"] "Right2Left")
137 let coq_MSNone = (constant ["Setoid"] "MSNone")
138 let coq_MSCovariant = (constant ["Setoid"] "MSCovariant")
139 let coq_MSContravariant = (constant ["Setoid"] "MSContravariant")
141 let coq_singl = (constant ["Setoid"] "singl")
142 let coq_cons = (constant ["Setoid"] "cons")
144 let coq_equality_morphism_of_asymmetric_areflexive_transitive_relation =
146 "equality_morphism_of_asymmetric_areflexive_transitive_relation")
147 let coq_equality_morphism_of_symmetric_areflexive_transitive_relation =
149 "equality_morphism_of_symmetric_areflexive_transitive_relation")
150 let coq_equality_morphism_of_asymmetric_reflexive_transitive_relation =
152 "equality_morphism_of_asymmetric_reflexive_transitive_relation")
153 let coq_equality_morphism_of_symmetric_reflexive_transitive_relation =
155 "equality_morphism_of_symmetric_reflexive_transitive_relation")
156 let coq_make_compatibility_goal =
157 (constant ["Setoid"] "make_compatibility_goal")
158 let coq_make_compatibility_goal_eval_ref =
159 (eval_reference ["Setoid"] "make_compatibility_goal")
160 let coq_make_compatibility_goal_aux_eval_ref =
161 (eval_reference ["Setoid"] "make_compatibility_goal_aux")
163 let coq_App = (constant ["Setoid"] "App")
164 let coq_ToReplace = (constant ["Setoid"] "ToReplace")
165 let coq_ToKeep = (constant ["Setoid"] "ToKeep")
166 let coq_ProperElementToKeep = (constant ["Setoid"] "ProperElementToKeep")
167 let coq_fcl_singl = (constant ["Setoid"] "fcl_singl")
168 let coq_fcl_cons = (constant ["Setoid"] "fcl_cons")
170 let coq_setoid_rewrite = (constant ["Setoid"] "setoid_rewrite")
171 let coq_proj1 = (gen_constant ["Init"; "Logic"] "proj1")
172 let coq_proj2 = (gen_constant ["Init"; "Logic"] "proj2")
173 let coq_unit = (gen_constant ["Init"; "Datatypes"] "unit")
174 let coq_tt = (gen_constant ["Init"; "Datatypes"] "tt")
175 let coq_eq = (gen_constant ["Init"; "Logic"] "eq")
177 let coq_morphism_theory_of_function =
178 (constant ["Setoid"] "morphism_theory_of_function")
179 let coq_morphism_theory_of_predicate =
180 (constant ["Setoid"] "morphism_theory_of_predicate")
181 let coq_relation_of_relation_class =
182 (eval_reference ["Setoid"] "relation_of_relation_class")
183 let coq_directed_relation_of_relation_class =
184 (eval_reference ["Setoid"] "directed_relation_of_relation_class")
185 let coq_interp = (eval_reference ["Setoid"] "interp")
186 let coq_Morphism_Context_rect2 =
187 (eval_reference ["Setoid"] "Morphism_Context_rect2")
188 let coq_iff = (gen_constant ["Init";"Logic"] "iff")
189 let coq_impl = (constant ["Setoid"] "impl")
192 (************************* Table of declared relations **********************)
195 (* Relations are stored in a table which is synchronised with the Reset mechanism. *)
198 Map.Make(struct type t = Cic.term let compare = Pervasives.compare end);;
200 let relation_table = ref Gmap.empty
202 let relation_table_add (s,th) = relation_table := Gmap.add s th !relation_table
203 let relation_table_find s = Gmap.find s !relation_table
204 let relation_table_mem s = Gmap.mem s !relation_table
207 "(" ^ CicPp.ppterm s.rel_a ^ "," ^ CicPp.ppterm s.rel_aeq ^ ")"
209 let prrelation_class =
212 (try prrelation (relation_table_find eq)
214 "[[ Error: " ^ CicPp.ppterm eq ^
215 " is not registered as a relation ]]")
216 | Leibniz (Some ty) -> CicPp.ppterm ty
217 | Leibniz None -> "_"
219 let prmorphism_argument_gen prrelation (variance,rel) =
223 | Some true -> " ++> "
224 | Some false -> " --> "
226 let prargument_class = prmorphism_argument_gen prrelation_class
228 let pr_morphism_signature (l,c) =
229 String.concat "" (List.map (prmorphism_argument_gen CicPp.ppterm) l) ^
233 CicPp.ppterm k ^ ": " ^
234 String.concat "" (List.map prargument_class m.args) ^
235 prrelation_class m.output
237 (* A function that gives back the only relation_class on a given carrier *)
238 (*CSC: this implementation is really inefficient. I should define a new
239 map to make it efficient. However, is this really worth of? *)
240 let default_relation_for_carrier ?(filter=fun _ -> true) a =
241 let rng = Gmap.fold (fun _ y acc -> y::acc) !relation_table [] in
242 match List.filter (fun ({rel_a=rel_a} as r) -> rel_a = a && filter r) rng with
243 [] -> Leibniz (Some a)
248 ("Warning: There are several relations on the carrier \"" ^
249 CicPp.ppterm a ^ "\". The relation " ^ prrelation relation ^
254 let find_relation_class rel =
255 try Relation (relation_table_find rel)
258 let default_eq = default_eq () in
259 match CicReduction.whd [] rel with
260 Cic.Appl [Cic.MutInd(uri,0,[]);ty]
261 when UriManager.eq uri default_eq -> Leibniz (Some ty)
262 | Cic.MutInd(uri,0,[]) when UriManager.eq uri default_eq -> Leibniz None
263 | _ -> raise Not_found
266 let coq_iff_relation = lazy (find_relation_class (Lazy.force coq_iff))
267 let coq_impl_relation = lazy (find_relation_class (Lazy.force coq_impl))
268 *) let coq_iff_relation = assert false let coq_impl_relation = assert false
270 let relation_morphism_of_constr_morphism =
271 let relation_relation_class_of_constr_relation_class =
273 Leibniz t -> Leibniz t
275 Relation (try relation_table_find aeq with Not_found -> assert false)
280 (fun (variance,rel) ->
281 variance, relation_relation_class_of_constr_relation_class rel
283 let output' = relation_relation_class_of_constr_relation_class mor.output in
284 {mor with args=args' ; output=output'}
287 Gmap.fold (fun _ y acc -> y.rel_aeq::acc) !relation_table []
289 (* Declare a new type of object in the environment : "relation-theory". *)
292 let (relation_to_obj, obj_to_relation)=
293 let cache_set (_,(s, th)) =
295 if relation_table_mem s then
297 let old_relation = relation_table_find s in
300 match th.rel_sym with
301 None -> old_relation.rel_sym
302 | Some t -> Some t} in
305 ("Warning: The relation " ^ prrelation th' ^
306 " is redeclared. The new declaration" ^
307 (match th'.rel_refl with
309 | Some t -> " (reflevity proved by " ^ CicPp.ppterm t) ^
310 (match th'.rel_sym with
313 (if th'.rel_refl = None then " (" else " and ") ^
314 "symmetry proved by " ^ CicPp.ppterm t) ^
315 (if th'.rel_refl <> None && th'.rel_sym <> None then
317 " replaces the old declaration" ^
318 (match old_relation.rel_refl with
320 | Some t -> " (reflevity proved by " ^ CicPp.ppterm t) ^
321 (match old_relation.rel_sym with
324 (if old_relation.rel_refl = None then
326 "symmetry proved by " ^ CicPp.ppterm t) ^
327 (if old_relation.rel_refl <> None && old_relation.rel_sym <> None
336 relation_table_add (s,th')
337 and export_set x = Some x
339 declare_object {(default_object "relation-theory") with
340 cache_function = cache_set;
341 load_function = (fun i o -> cache_set o);
342 subst_function = subst_set;
343 classify_function = (fun (_,x) -> Substitute x);
344 export_function = export_set}
347 (******************************* Table of declared morphisms ********************)
349 (* Setoids are stored in a table which is synchronised with the Reset mechanism. *)
351 let morphism_table = ref Gmap.empty
353 let morphism_table_find m = Gmap.find m !morphism_table
354 let morphism_table_add (m,c) =
357 morphism_table_find m
365 (function mor -> mor.args = c.args && mor.output = c.output) old
368 ("Warning: The morphism " ^ prmorphism m old_morph ^
370 "The new declaration whose compatibility is proved by " ^
371 CicPp.ppterm c.lem ^ " replaces the old declaration whose" ^
372 " compatibility was proved by " ^
373 CicPp.ppterm old_morph.lem ^ ".")
376 Not_found -> morphism_table := Gmap.add m (c::old) !morphism_table
378 let default_morphism ?(filter=fun _ -> true) m =
379 match List.filter filter (morphism_table_find m) with
380 [] -> raise Not_found
385 ("Warning: There are several morphisms associated to \"" ^
386 CicPp.ppterm m ^ "\". Morphism " ^ prmorphism m m1 ^
387 " is randomly chosen.");
389 relation_morphism_of_constr_morphism m1
391 (************************** Printing relations and morphisms **********************)
393 let print_setoids () =
396 assert (k=relation.rel_aeq) ;
397 prerr_endline ("Relation " ^ prrelation relation ^ ";" ^
398 (match relation.rel_refl with
400 | Some t -> " reflexivity proved by " ^ CicPp.ppterm t) ^
401 (match relation.rel_sym with
403 | Some t -> " symmetry proved by " ^ CicPp.ppterm t) ^
404 (match relation.rel_trans with
406 | Some t -> " transitivity proved by " ^ CicPp.ppterm t)))
411 (fun ({lem=lem} as mor) ->
412 prerr_endline ("Morphism " ^ prmorphism k mor ^
413 ". Compatibility proved by " ^
414 CicPp.ppterm lem ^ "."))
418 (***************** Adding a morphism to the database ****************************)
420 (* We maintain a table of the currently edited proofs of morphism lemma
421 in order to add them in the morphism_table when the user does Save *)
423 let edited = ref Gmap.empty
425 let new_edited id m =
426 edited := Gmap.add id m !edited
431 let no_more_edited id =
432 edited := Gmap.remove id !edited
438 let rec chop_aux acc = function
439 | (0, l2) -> (List.rev acc, l2)
440 | (n, (h::t)) -> chop_aux (h::acc) (pred n, t)
441 | (_, []) -> assert false
445 let compose_thing f l b =
449 | (n, ((v,t)::l), b) -> aux (n-1, l, f v t b)
452 aux (List.length l,l,b)
454 let compose_prod = compose_thing (fun v t b -> Cic.Prod (v,t,b))
455 let compose_lambda = compose_thing (fun v t b -> Cic.Lambda (v,t,b))
457 (* also returns the triple (args_ty_quantifiers_rev,real_args_ty,real_output)
458 where the args_ty and the output are delifted *)
459 let check_is_dependent n args_ty output =
460 let m = List.length args_ty - n in
461 let args_ty_quantifiers, args_ty = list_chop n args_ty in
464 Cic.Prod (n,s,t) when m > 0 ->
465 let t' = CicSubstitution.subst (Cic.Implicit None) (* dummy *) t in
467 let args,out = aux (m - 1) t' in s::args,out
469 raise (ProofEngineTypes.Fail (lazy
470 "The morphism is not a quantified non dependent product."))
473 let ty = compose_prod (List.rev args_ty) output in
474 let args_ty, output = aux m ty in
475 List.rev args_ty_quantifiers, args_ty, output
477 let cic_relation_class_of_X_relation typ value =
479 {rel_a=rel_a; rel_aeq=rel_aeq; rel_refl=Some refl; rel_sym=None} ->
480 Cic.Appl [coq_AsymmetricReflexive ; typ ; value ; rel_a ; rel_aeq; refl]
481 | {rel_a=rel_a; rel_aeq=rel_aeq; rel_refl=Some refl; rel_sym=Some sym} ->
482 Cic.Appl [coq_SymmetricReflexive ; typ ; rel_a ; rel_aeq; sym ; refl]
483 | {rel_a=rel_a; rel_aeq=rel_aeq; rel_refl=None; rel_sym=None} ->
484 Cic.Appl [coq_AsymmetricAreflexive ; typ ; value ; rel_a ; rel_aeq]
485 | {rel_a=rel_a; rel_aeq=rel_aeq; rel_refl=None; rel_sym=Some sym} ->
486 Cic.Appl [coq_SymmetricAreflexive ; typ ; rel_a ; rel_aeq; sym]
488 let cic_relation_class_of_X_relation_class typ value =
490 Relation {rel_X_relation_class=x_relation_class} ->
491 Cic.Appl [x_relation_class ; typ ; value]
492 | Leibniz (Some t) ->
493 Cic.Appl [coq_Leibniz ; typ ; t]
494 | Leibniz None -> assert false
497 let cic_precise_relation_class_of_relation =
499 {rel_a=rel_a; rel_aeq=rel_aeq; rel_refl=Some refl; rel_sym=None} ->
500 Cic.Appl [coq_RAsymmetric ; rel_a ; rel_aeq; refl]
501 | {rel_a=rel_a; rel_aeq=rel_aeq; rel_refl=Some refl; rel_sym=Some sym} ->
502 Cic.Appl [coq_RSymmetric ; rel_a ; rel_aeq; sym ; refl]
503 | {rel_a=rel_a; rel_aeq=rel_aeq; rel_refl=None; rel_sym=None} ->
504 Cic.Appl [coq_AAsymmetric ; rel_a ; rel_aeq]
505 | {rel_a=rel_a; rel_aeq=rel_aeq; rel_refl=None; rel_sym=Some sym} ->
506 Cic.Appl [coq_ASymmetric ; rel_a ; rel_aeq; sym]
508 let cic_precise_relation_class_of_relation_class =
511 {rel_aeq=rel_aeq; rel_Xreflexive_relation_class=lem; rel_refl=rel_refl }
513 rel_aeq,lem,not(rel_refl=None)
514 | Leibniz (Some t) ->
515 Cic.Appl [coq_eq ; t], Cic.Appl [coq_RLeibniz ; t], true
516 | Leibniz None -> assert false
518 let cic_relation_class_of_relation_class rel =
519 cic_relation_class_of_X_relation_class
522 let cic_argument_class_of_argument_class (variance,arg) =
523 let coq_variant_value =
525 None -> coq_Covariant (* dummy value, it won't be used *)
526 | Some true -> coq_Covariant
527 | Some false -> coq_Contravariant
529 cic_relation_class_of_X_relation_class coq_variance
530 coq_variant_value arg
532 let cic_arguments_of_argument_class_list args =
537 Cic.Appl [coq_singl ; coq_Argument_Class ; last]
539 Cic.Appl [coq_cons ; coq_Argument_Class ; he ; aux tl]
541 aux (List.map cic_argument_class_of_argument_class args)
543 let gen_compat_lemma_statement quantifiers_rev output args m =
544 let output = cic_relation_class_of_relation_class output in
545 let args = cic_arguments_of_argument_class_list args in
547 compose_prod quantifiers_rev
548 (Cic.Appl [coq_make_compatibility_goal ; args ; output ; m])
550 let morphism_theory_id_of_morphism_proof_id id =
551 id ^ "_morphism_theory"
554 let rec map_i_rec i = function
556 | x::l -> let v = f i x in v :: map_i_rec (i+1) l
560 (* apply_to_rels c [l1 ; ... ; ln] returns (c Rel1 ... reln) *)
561 let apply_to_rels c l =
564 let len = List.length l in
565 Cic.Appl (c::(list_map_i (fun i _ -> Cic.Rel (len - i)) 0 l))
567 let apply_to_relation subst rel =
568 if subst = [] then rel
570 let new_quantifiers_no = rel.rel_quantifiers_no - List.length subst in
571 assert (new_quantifiers_no >= 0) ;
572 { rel_a = Cic.Appl (rel.rel_a :: subst) ;
573 rel_aeq = Cic.Appl (rel.rel_aeq :: subst) ;
574 rel_refl = HExtlib.map_option (fun c -> Cic.Appl (c::subst)) rel.rel_refl ;
575 rel_sym = HExtlib.map_option (fun c -> Cic.Appl (c::subst)) rel.rel_sym;
576 rel_trans = HExtlib.map_option (fun c -> Cic.Appl (c::subst)) rel.rel_trans;
577 rel_quantifiers_no = new_quantifiers_no;
578 rel_X_relation_class = Cic.Appl (rel.rel_X_relation_class::subst);
579 rel_Xreflexive_relation_class =
580 Cic.Appl (rel.rel_Xreflexive_relation_class::subst) }
582 let add_morphism lemma_infos mor_name (m,quantifiers_rev,args,output) =
584 match lemma_infos with
586 (* the Morphism_Theory object has already been created *)
588 let len = List.length quantifiers_rev in
590 list_map_i (fun i _ -> Cic.Rel (len - i)) 0 quantifiers_rev
600 [e] -> v, Leibniz (Some e)
602 | Relation rel -> v, Relation (apply_to_relation subst rel)) args
604 compose_lambda quantifiers_rev
607 cic_arguments_of_argument_class_list applied_args;
608 cic_relation_class_of_relation_class output;
609 apply_to_rels (current_constant mor_name) quantifiers_rev])
610 | Some (lem_name,argsconstr,outputconstr) ->
611 (* only the compatibility has been proved; we need to declare the
612 Morphism_Theory object *)
613 let mext = current_constant lem_name in
616 Declare.declare_internal_constant mor_name
619 compose_lambda quantifiers_rev
621 [coq_Build_Morphism_Theory;
622 argsconstr; outputconstr; apply_to_rels m quantifiers_rev ;
623 apply_to_rels mext quantifiers_rev]);
624 const_entry_boxed = Options.boxed_definitions()},
625 IsDefinition Definition)) ;
626 *)ignore (assert false);
629 let mmor = current_constant mor_name in
632 (fun (variance,arg) ->
633 variance, constr_relation_class_of_relation_relation_class arg) args in
634 let output_constr = constr_relation_class_of_relation_relation_class output in
636 Lib.add_anonymous_leaf
638 { args = args_constr;
639 output = output_constr;
641 morphism_theory = mmor }));
642 *)let _ = mmor,args_constr,output_constr,lem in ignore (assert false);
643 (*COQ Options.if_verbose prerr_endline (CicPp.ppterm m ^ " is registered as a morphism") *) ()
645 let list_sub _ _ _ = assert false
647 (* first order matching with a bit of conversion *)
648 let unify_relation_carrier_with_type env rel t =
649 let raise_error quantifiers_no =
650 raise (ProofEngineTypes.Fail (lazy
651 ("One morphism argument or its output has type " ^ CicPp.ppterm t ^
652 " but the signature requires an argument of type \"" ^
653 CicPp.ppterm rel.rel_a ^ " " ^ String.concat " " (List.map (fun _ -> "?")
654 (Array.to_list (Array.make quantifiers_no 0))) ^ "\""))) in
657 Cic.Appl (he'::args') ->
658 let argsno = List.length args' - rel.rel_quantifiers_no in
659 let args1 = list_sub args' 0 argsno in
660 let args2 = list_sub args' argsno rel.rel_quantifiers_no in
661 if fst (CicReduction.are_convertible [] rel.rel_a (Cic.Appl (he'::args1)) CicUniv.empty_ugraph) then
664 raise_error rel.rel_quantifiers_no
666 if rel.rel_quantifiers_no = 0 && fst (CicReduction.are_convertible [] rel.rel_a t CicUniv.empty_ugraph) then
671 let evars,args,instantiated_rel_a =
672 let ty = CicTypeChecker.type_of_aux' [] [] rel.rel_a CicUniv.empty_ugraph in
673 let evd = Evd.create_evar_defs Evd.empty in
674 let evars,args,concl =
675 Clenv.clenv_environments_evars env evd
676 (Some rel.rel_quantifiers_no) ty
680 (match args with [] -> rel.rel_a | _ -> applist (rel.rel_a,args))
683 w_unify true (*??? or false? *) env Reduction.CONV (*??? or cumul? *)
684 ~mod_delta:true (*??? or true? *) t instantiated_rel_a evars in
686 List.map (Reductionops.nf_evar (Evd.evars_of evars')) args
692 apply_to_relation args rel
694 let unify_relation_class_carrier_with_type env rel t =
697 if fst (CicReduction.are_convertible [] t t' CicUniv.empty_ugraph) then
700 raise (ProofEngineTypes.Fail (lazy
701 ("One morphism argument or its output has type " ^ CicPp.ppterm t ^
702 " but the signature requires an argument of type " ^
704 | Leibniz None -> Leibniz (Some t)
705 | Relation rel -> Relation (unify_relation_carrier_with_type env rel t)
710 (* first order matching with a bit of conversion *)
711 (* Note: the type checking operations performed by the function could *)
712 (* be done once and for all abstracting the morphism structure using *)
713 (* the quantifiers. Would the new structure be more suited than the *)
714 (* existent one for other tasks to? (e.g. pretty printing would expose *)
715 (* much more information: is it ok or is it too much information?) *)
716 let unify_morphism_with_arguments gl (c,al)
717 {args=args; output=output; lem=lem; morphism_theory=morphism_theory} t
719 let allen = List.length al in
720 let argsno = List.length args in
721 if allen < argsno then raise Impossible; (* partial application *)
722 let quantifiers,al' = Util.list_chop (allen - argsno) al in
723 let c' = Cic.Appl (c::quantifiers) in
724 if dependent t c' then raise Impossible;
725 (* these are pf_type_of we could avoid *)
726 let al'_type = List.map (Tacmach.pf_type_of gl) al' in
730 var,unify_relation_class_carrier_with_type (pf_env gl) rel ty)
732 (* this is another pf_type_of we could avoid *)
733 let ty = Tacmach.pf_type_of gl (Cic.Appl (c::al)) in
734 let output' = unify_relation_class_carrier_with_type (pf_env gl) output ty in
735 let lem' = Cic.Appl (lem::quantifiers) in
736 let morphism_theory' = Cic.Appl (morphism_theory::quantifiers) in
737 ({args=args'; output=output'; lem=lem'; morphism_theory=morphism_theory'},
739 *) let unify_morphism_with_arguments _ _ _ _ = assert false
741 let new_morphism m signature id hook =
743 if Nametab.exists_cci (Lib.make_path id) or is_section_variable id then
744 raise (ProofEngineTypes.Fail (lazy (pr_id id ^ " already exists")))
746 let env = Global.env() in
747 let typeofm = Typing.type_of env Evd.empty m in
748 let typ = clos_norm_flags Closure.betaiotazeta empty_env Evd.empty typeofm in
749 let argsrev, output =
751 None -> decompose_prod typ
752 | Some (_,output') ->
753 (* the carrier of the relation output' can be a Prod ==>
754 we must uncurry on the fly output.
755 E.g: A -> B -> C vs A -> (B -> C)
756 args output args output
758 let rel = find_relation_class output' in
759 let rel_a,rel_quantifiers_no =
761 Relation rel -> rel.rel_a, rel.rel_quantifiers_no
762 | Leibniz (Some t) -> t, 0
763 | Leibniz None -> assert false in
765 clos_norm_flags Closure.betaiotazeta empty_env Evd.empty rel_a in
767 let _,output_rel_a_n = decompose_lam_n rel_quantifiers_no rel_a_n in
768 let argsrev,_ = decompose_prod output_rel_a_n in
769 let n = List.length argsrev in
770 let argsrev',_ = decompose_prod typ in
771 let m = List.length argsrev' in
772 decompose_prod_n (m - n) typ
773 with UserError(_,_) ->
774 (* decompose_lam_n failed. This may happen when rel_a is an axiom,
775 a constructor, an inductive type, etc. *)
778 let args_ty = List.rev argsrev in
779 let args_ty_len = List.length (args_ty) in
780 let args_ty_quantifiers_rev,args,args_instance,output,output_instance =
784 raise (ProofEngineTypes.Fail (lazy
785 ("The term " ^ CicPp.ppterm m ^ " has type " ^
786 CicPp.ppterm typeofm ^ " that is not a product."))) ;
787 ignore (check_is_dependent 0 args_ty output) ;
790 (fun (_,ty) -> None,default_relation_for_carrier ty) args_ty in
791 let output = default_relation_for_carrier output in
792 [],args,args,output,output
793 | Some (args,output') ->
795 let number_of_arguments = List.length args in
796 let number_of_quantifiers = args_ty_len - number_of_arguments in
797 if number_of_quantifiers < 0 then
798 raise (ProofEngineTypes.Fail (lazy
799 ("The morphism " ^ CicPp.ppterm m ^ " has type " ^
800 CicPp.ppterm typeofm ^ " that attends at most " ^ int args_ty_len ^
801 " arguments. The signature that you specified requires " ^
802 int number_of_arguments ^ " arguments.")))
805 (* the real_args_ty returned are already delifted *)
806 let args_ty_quantifiers_rev, real_args_ty, real_output =
807 check_is_dependent number_of_quantifiers args_ty output in
808 let quantifiers_rel_context =
809 List.map (fun (n,t) -> n,None,t) args_ty_quantifiers_rev in
810 let env = push_rel_context quantifiers_rel_context env in
811 let find_relation_class t real_t =
813 let rel = find_relation_class t in
814 rel, unify_relation_class_carrier_with_type env rel real_t
816 raise (ProofEngineTypes.Fail (lazy
817 ("Not a valid signature: " ^ CicPp.ppterm t ^
818 " is neither a registered relation nor the Leibniz " ^
821 let find_relation_class_v (variance,t) real_t =
822 let relation,relation_instance = find_relation_class t real_t in
823 match relation, variance with
825 | Relation {rel_sym = Some _}, None
826 | Relation {rel_sym = None}, Some _ ->
827 (variance, relation), (variance, relation_instance)
828 | Relation {rel_sym = None},None ->
829 raise (ProofEngineTypes.Fail (lazy
830 ("You must specify the variance in each argument " ^
831 "whose relation is asymmetric.")))
833 | Relation {rel_sym = Some _}, Some _ ->
834 raise (ProofEngineTypes.Fail (lazy
835 ("You cannot specify the variance of an argument " ^
836 "whose relation is symmetric.")))
838 let args, args_instance =
840 (List.map2 find_relation_class_v args real_args_ty) in
841 let output,output_instance= find_relation_class output' real_output in
842 args_ty_quantifiers_rev, args, args_instance, output, output_instance
845 let argsconstr,outputconstr,lem =
846 gen_compat_lemma_statement args_ty_quantifiers_rev output_instance
847 args_instance (apply_to_rels m args_ty_quantifiers_rev) in
848 (* "unfold make_compatibility_goal" *)
850 Reductionops.clos_norm_flags
851 (Closure.unfold_red (coq_make_compatibility_goal_eval_ref))
853 (* "unfold make_compatibility_goal_aux" *)
855 Reductionops.clos_norm_flags
856 (Closure.unfold_red(coq_make_compatibility_goal_aux_eval_ref))
859 let lem = Tacred.nf env Evd.empty lem in
860 if Lib.is_modtype () then
863 (Declare.declare_internal_constant id
864 (ParameterEntry lem, IsAssumption Logical)) ;
865 let mor_name = morphism_theory_id_of_morphism_proof_id id in
866 let lemma_infos = Some (id,argsconstr,outputconstr) in
867 add_morphism lemma_infos mor_name
868 (m,args_ty_quantifiers_rev,args,output)
873 (m,args_ty_quantifiers_rev,args,argsconstr,output,outputconstr);
874 Pfedit.start_proof id (Global, Proof Lemma)
875 (Declare.clear_proofs (Global.named_context ()))
877 Options.if_verbose msg (Printer.pr_open_subgoals ());
881 let morphism_hook _ ref =
883 let pf_id = id_of_global ref in
884 let mor_id = morphism_theory_id_of_morphism_proof_id pf_id in
885 let (m,quantifiers_rev,args,argsconstr,output,outputconstr) =
890 add_morphism (Some (pf_id,argsconstr,outputconstr)) mor_id
891 (m,quantifiers_rev,args,output) ;
896 type morphism_signature =
897 (bool option * Cic.term) list * Cic.term
899 let new_named_morphism id m sign =
900 new_morphism m sign id morphism_hook
902 (************************** Adding a relation to the database *********************)
906 let typ = Typing.type_of env Evd.empty a in
907 let a_quantifiers_rev,_ = Reduction.dest_arity env typ in
910 let check_eq env a_quantifiers_rev a aeq =
912 Sign.it_mkProd_or_LetIn
913 (Cic.Appl [coq_relation ; apply_to_rels a a_quantifiers_rev])
917 (is_conv env Evd.empty (Typing.type_of env Evd.empty aeq) typ)
919 raise (ProofEngineTypes.Fail (lazy
920 (CicPp.ppterm aeq ^ " should have type (" ^ CicPp.ppterm typ ^ ")")))
922 let check_property env a_quantifiers_rev a aeq strprop coq_prop t =
925 (is_conv env Evd.empty (Typing.type_of env Evd.empty t)
926 (Sign.it_mkProd_or_LetIn
929 apply_to_rels a a_quantifiers_rev ;
930 apply_to_rels aeq a_quantifiers_rev]) a_quantifiers_rev))
932 raise (ProofEngineTypes.Fail (lazy
933 ("Not a valid proof of " ^ strprop ^ ".")))
935 let check_refl env a_quantifiers_rev a aeq refl =
936 check_property env a_quantifiers_rev a aeq "reflexivity" coq_reflexive refl
938 let check_sym env a_quantifiers_rev a aeq sym =
939 check_property env a_quantifiers_rev a aeq "symmetry" coq_symmetric sym
941 let check_trans env a_quantifiers_rev a aeq trans =
942 check_property env a_quantifiers_rev a aeq "transitivity" coq_transitive trans
944 let int_add_relation id a aeq refl sym trans =
945 let env = Global.env () in
946 let a_quantifiers_rev = check_a env a in
947 check_eq env a_quantifiers_rev a aeq ;
948 option_iter (check_refl env a_quantifiers_rev a aeq) refl ;
949 option_iter (check_sym env a_quantifiers_rev a aeq) sym ;
950 option_iter (check_trans env a_quantifiers_rev a aeq) trans ;
951 let quantifiers_no = List.length a_quantifiers_rev in
958 rel_quantifiers_no = quantifiers_no;
959 rel_X_relation_class = Cic.Sort Cic.Prop; (* dummy value, overwritten below *)
960 rel_Xreflexive_relation_class = Cic.Sort Cic.Prop (* dummy value, overwritten below *)
962 let x_relation_class =
964 let len = List.length a_quantifiers_rev in
965 list_map_i (fun i _ -> Cic.Rel (len - i + 2)) 0 a_quantifiers_rev in
966 cic_relation_class_of_X_relation
967 (Cic.Rel 2) (Cic.Rel 1) (apply_to_relation subst aeq_rel) in
969 Declare.declare_internal_constant id
972 Sign.it_mkLambda_or_LetIn x_relation_class
973 ([ Name (id_of_string "v"),None,Cic.Rel 1;
974 Name (id_of_string "X"),None,Cic.Sort (Cic.Type (CicUniv.fresh ()))] @
976 const_entry_type = None;
977 const_entry_opaque = false;
978 const_entry_boxed = Options.boxed_definitions()},
979 IsDefinition Definition) in
980 let id_precise = id_of_string (string_of_id id ^ "_precise_relation_class") in
981 let xreflexive_relation_class =
983 let len = List.length a_quantifiers_rev in
984 list_map_i (fun i _ -> Cic.Rel (len - i)) 0 a_quantifiers_rev
986 cic_precise_relation_class_of_relation (apply_to_relation subst aeq_rel) in
988 Declare.declare_internal_constant id_precise
991 Sign.it_mkLambda_or_LetIn xreflexive_relation_class a_quantifiers_rev;
992 const_entry_type = None;
993 const_entry_opaque = false;
994 const_entry_boxed = Options.boxed_definitions() },
995 IsDefinition Definition) in
998 rel_X_relation_class = current_constant id;
999 rel_Xreflexive_relation_class = current_constant id_precise } in
1000 Lib.add_anonymous_leaf (relation_to_obj (aeq, aeq_rel)) ;
1001 Options.if_verbose prerr_endline (CicPp.ppterm aeq ^ " is registered as a relation");
1005 let mor_name = id_of_string (string_of_id id ^ "_morphism") in
1006 let a_instance = apply_to_rels a a_quantifiers_rev in
1007 let aeq_instance = apply_to_rels aeq a_quantifiers_rev in
1009 HExtlib.map_option (fun x -> apply_to_rels x a_quantifiers_rev) sym in
1011 HExtlib.map_option (fun x -> apply_to_rels x a_quantifiers_rev) refl in
1012 let trans_instance = apply_to_rels trans a_quantifiers_rev in
1013 let aeq_rel_class_and_var1, aeq_rel_class_and_var2, lemma, output =
1014 match sym_instance, refl_instance with
1016 (Some false, Relation aeq_rel),
1017 (Some true, Relation aeq_rel),
1019 [coq_equality_morphism_of_asymmetric_areflexive_transitive_relation;
1020 a_instance ; aeq_instance ; trans_instance],
1022 | None, Some refl_instance ->
1023 (Some false, Relation aeq_rel),
1024 (Some true, Relation aeq_rel),
1026 [coq_equality_morphism_of_asymmetric_reflexive_transitive_relation;
1027 a_instance ; aeq_instance ; refl_instance ; trans_instance],
1029 | Some sym_instance, None ->
1030 (None, Relation aeq_rel),
1031 (None, Relation aeq_rel),
1033 [coq_equality_morphism_of_symmetric_areflexive_transitive_relation;
1034 a_instance ; aeq_instance ; sym_instance ; trans_instance],
1036 | Some sym_instance, Some refl_instance ->
1037 (None, Relation aeq_rel),
1038 (None, Relation aeq_rel),
1040 [coq_equality_morphism_of_symmetric_reflexive_transitive_relation;
1041 a_instance ; aeq_instance ; refl_instance ; sym_instance ;
1045 Declare.declare_internal_constant mor_name
1047 {const_entry_body = Sign.it_mkLambda_or_LetIn lemma a_quantifiers_rev;
1048 const_entry_type = None;
1049 const_entry_opaque = false;
1050 const_entry_boxed = Options.boxed_definitions()},
1051 IsDefinition Definition)
1053 let a_quantifiers_rev =
1054 List.map (fun (n,b,t) -> assert (b = None); n,t) a_quantifiers_rev in
1055 add_morphism None mor_name
1056 (aeq,a_quantifiers_rev,[aeq_rel_class_and_var1; aeq_rel_class_and_var2],
1060 (* The vernac command "Add Relation ..." *)
1061 let add_relation id a aeq refl sym trans =
1063 int_add_relation id (constr_of a) (constr_of aeq) (HExtlib.map_option constr_of refl)
1064 (HExtlib.map_option constr_of sym) (HExtlib.map_option constr_of trans)
1067 (****************************** The tactic itself *******************************)
1076 | Right2Left -> "<-"
1078 type constr_with_marks =
1079 | MApp of Cic.term * morphism_class * constr_with_marks list * direction
1081 | ToKeep of Cic.term * relation relation_class * direction
1083 let is_to_replace = function
1089 List.fold_left (||) false (List.map is_to_replace a)
1091 let cic_direction_of_direction =
1093 Left2Right -> coq_Left2Right
1094 | Right2Left -> coq_Right2Left
1096 let opposite_direction =
1098 Left2Right -> Right2Left
1099 | Right2Left -> Left2Right
1101 let direction_of_constr_with_marks hole_direction =
1103 MApp (_,_,_,dir) -> cic_direction_of_direction dir
1104 | ToReplace -> hole_direction
1105 | ToKeep (_,_,dir) -> cic_direction_of_direction dir
1108 Toapply of Cic.term (* apply the function to the argument *)
1109 | Toexpand of Cic.name * Cic.term (* beta-expand the function w.r.t. an argument
1111 let beta_expand c args_rev =
1115 | (Toapply _)::tl -> to_expand tl
1116 | (Toexpand (name,s))::tl -> (name,s)::(to_expand tl) in
1120 | (Toapply arg)::tl -> arg::(aux n tl)
1121 | (Toexpand _)::tl -> (Cic.Rel n)::(aux (n + 1) tl)
1123 compose_lambda (to_expand args_rev)
1124 (Cic.Appl (c :: List.rev (aux 1 args_rev)))
1126 exception Optimize (* used to fall-back on the tactic for Leibniz equality *)
1128 let rec list_sep_last = function
1129 | [] -> assert false
1131 | hd::tl -> let (l,tl) = list_sep_last tl in (l,hd::tl)
1133 let relation_class_that_matches_a_constr caller_name new_goals hypt =
1136 Cic.Appl (heq::hargs) -> heq,hargs
1139 let rec get_all_but_last_two =
1143 raise (ProofEngineTypes.Fail (lazy (CicPp.ppterm hypt ^
1144 " is not a registered relation.")))
1146 | he::tl -> he::(get_all_but_last_two tl) in
1147 let all_aeq_args = get_all_but_last_two hargs in
1148 let rec find_relation l subst =
1149 let aeq = Cic.Appl (heq::l) in
1151 let rel = find_relation_class aeq in
1152 match rel,new_goals with
1154 assert (subst = []);
1155 raise Optimize (* let's optimize the proof term size *)
1156 | Leibniz (Some _), _ ->
1157 assert (subst = []);
1159 | Leibniz None, _ ->
1160 (* for well-typedness reasons it should have been catched by the
1161 previous guard in the previous iteration. *)
1163 | Relation rel,_ -> Relation (apply_to_relation subst rel)
1166 raise (ProofEngineTypes.Fail (lazy
1167 (CicPp.ppterm (Cic.Appl (aeq::all_aeq_args)) ^
1168 " is not a registered relation.")))
1170 let last,others = list_sep_last l in
1171 find_relation others (last::subst)
1173 find_relation all_aeq_args []
1175 (* rel1 is a subrelation of rel2 whenever
1176 forall x1 x2, rel1 x1 x2 -> rel2 x1 x2
1177 The Coq part of the tactic, however, needs rel1 == rel2.
1178 Hence the third case commented out.
1179 Note: accepting user-defined subtrelations seems to be the last
1180 useful generalization that does not go against the original spirit of
1183 let subrelation gl rel1 rel2 =
1184 match rel1,rel2 with
1185 Relation {rel_aeq=rel_aeq1}, Relation {rel_aeq=rel_aeq2} ->
1186 (*COQ Tacmach.pf_conv_x gl rel_aeq1 rel_aeq2*) assert false
1187 | Leibniz (Some t1), Leibniz (Some t2) ->
1188 (*COQ Tacmach.pf_conv_x gl t1 t2*) assert false
1190 | _, Leibniz None -> assert false
1191 (* This is the commented out case (see comment above)
1192 | Leibniz (Some t1), Relation {rel_a=t2; rel_refl = Some _} ->
1193 Tacmach.pf_conv_x gl t1 t2
1197 (* this function returns the list of new goals opened by a constr_with_marks *)
1198 let rec collect_new_goals =
1200 MApp (_,_,a,_) -> List.concat (List.map collect_new_goals a)
1202 | ToKeep (_,Leibniz _,_)
1203 | ToKeep (_,Relation {rel_refl=Some _},_) -> []
1204 | ToKeep (c,Relation {rel_aeq=aeq; rel_refl=None},_) -> [Cic.Appl[aeq;c;c]]
1206 (* two marked_constr are equivalent if they produce the same set of new goals *)
1207 let marked_constr_equiv_or_more_complex to_marked_constr gl c1 c2 =
1208 let glc1 = collect_new_goals (to_marked_constr c1) in
1209 let glc2 = collect_new_goals (to_marked_constr c2) in
1210 List.for_all (fun c -> List.exists (fun c' -> (*COQ pf_conv_x gl c c'*) assert false) glc1) glc2
1212 let pr_new_goals i c =
1213 let glc = collect_new_goals c in
1214 " " ^ string_of_int i ^ ") side conditions:" ^
1215 (if glc = [] then " no side conditions"
1219 (List.map (fun c -> " ... |- " ^ CicPp.ppterm c) glc)))
1221 (* given a list of constr_with_marks, it returns the list where
1222 constr_with_marks than open more goals than simpler ones in the list
1224 let elim_duplicates gl to_marked_constr =
1230 (marked_constr_equiv_or_more_complex to_marked_constr gl he) tl
1236 let filter_superset_of_new_goals gl new_goals l =
1240 (fun g -> List.exists ((*COQ pf_conv_x gl g*)assert false) (collect_new_goals c)) new_goals) l
1242 (* given the list of lists [ l1 ; ... ; ln ] it returns the list of lists
1243 [ c1 ; ... ; cn ] that is the cartesian product of the sets l1, ..., ln *)
1244 let cartesian_product gl a =
1248 | [he] -> List.map (fun e -> [e]) he
1252 (List.map (function e -> List.map (function l -> e :: l) tl') he)
1254 aux (List.map (elim_duplicates gl (fun x -> x)) a)
1256 let does_not_occur n t = assert false
1258 let mark_occur gl ~new_goals t in_c input_relation input_direction =
1259 let rec aux output_relation output_direction in_c =
1261 if input_direction = output_direction
1262 && subrelation gl input_relation output_relation then
1267 | Cic.Appl (c::al) ->
1268 let mors_and_cs_and_als =
1269 let mors_and_cs_and_als =
1270 let morphism_table_find c =
1271 try morphism_table_find c with Not_found -> [] in
1275 let c' = Cic.Appl (c::acc) in
1277 List.map (fun m -> m,c',al') (morphism_table_find c')
1279 let c' = Cic.Appl (c::acc) in
1280 let acc' = acc @ [he] in
1281 (List.map (fun m -> m,c',l) (morphism_table_find c')) @
1285 let mors_and_cs_and_als =
1287 (function (m,c,al) ->
1288 relation_morphism_of_constr_morphism m, c, al)
1289 mors_and_cs_and_als in
1290 let mors_and_cs_and_als =
1293 try (unify_morphism_with_arguments gl (c,al) m t) :: l
1294 with Impossible -> l
1295 ) [] mors_and_cs_and_als
1298 (fun (mor,_,_) -> subrelation gl mor.output output_relation)
1301 (* First we look for well typed morphisms *)
1304 (fun res (mor,c,al) ->
1306 let arguments = mor.args in
1307 let apply_variance_to_direction default_dir =
1310 | Some true -> output_direction
1311 | Some false -> opposite_direction output_direction
1314 (fun a (variance,relation) ->
1316 (apply_variance_to_direction Left2Right variance) a) @
1318 (apply_variance_to_direction Right2Left variance) a)
1321 let a' = cartesian_product gl a in
1324 if not (get_mark a) then
1325 ToKeep (in_c,output_relation,output_direction)
1327 MApp (c,ACMorphism mor,a,output_direction)) a') @ res
1328 ) [] mors_and_cs_and_als in
1329 (* Then we look for well typed functions *)
1331 (* the tactic works only if the function type is
1332 made of non-dependent products only. However, here we
1333 can cheat a bit by partially istantiating c to match
1334 the requirement when the arguments to be replaced are
1335 bound by non-dependent products only. *)
1336 let typeofc = (*COQ Tacmach.pf_type_of gl c*) assert false in
1337 let typ = (*COQ nf_betaiota typeofc*) let _ = typeofc in assert false in
1338 let rec find_non_dependent_function context c c_args_rev typ
1344 [ToKeep (in_c,output_relation,output_direction)]
1347 cartesian_product gl (List.rev a_rev)
1351 if not (get_mark a) then
1352 (ToKeep (in_c,output_relation,output_direction))::res
1355 match output_relation with
1356 Leibniz (Some typ') when (*COQ pf_conv_x gl typ typ'*) assert false ->
1358 | Leibniz None -> assert false
1359 | _ when output_relation = coq_iff_relation
1366 ACFunction{f_args=List.rev f_args_rev;f_output=typ} in
1367 let func = beta_expand c c_args_rev in
1368 (MApp (func,mor,a,output_direction))::res
1371 let typnf = (*COQ Reduction.whd_betadeltaiota env typ*) assert false in
1374 find_non_dependent_function context c c_args_rev typ
1376 | Cic.Prod (name,s,t) ->
1377 let context' = Some (name, Cic.Decl s)::context in
1379 (aux (Leibniz (Some s)) Left2Right he) @
1380 (aux (Leibniz (Some s)) Right2Left he) in
1383 let he0 = List.hd he in
1385 match does_not_occur 1 t, he0 with
1386 _, ToKeep (arg,_,_) ->
1387 (* invariant: if he0 = ToKeep (t,_,_) then every
1388 element in he is = ToKeep (t,_,_) *)
1392 ToKeep(arg',_,_) when (*COQpf_conv_x gl arg arg'*) assert false ->
1395 (* generic product, to keep *)
1396 find_non_dependent_function
1397 context' c ((Toapply arg)::c_args_rev)
1398 (CicSubstitution.subst arg t) f_args_rev a_rev tl
1400 (* non-dependent product, to replace *)
1401 find_non_dependent_function
1402 context' c ((Toexpand (name,s))::c_args_rev)
1403 (CicSubstitution.lift 1 t) (s::f_args_rev) (he::a_rev) tl
1405 (* dependent product, to replace *)
1406 (* This limitation is due to the reflexive
1407 implementation and it is hard to lift *)
1408 raise (ProofEngineTypes.Fail (lazy
1409 ("Cannot rewrite in the argument of a " ^
1410 "dependent product. If you need this " ^
1411 "feature, please report to the author.")))
1415 find_non_dependent_function (*COQ (Tacmach.pf_env gl) ci vuole il contesto*)(assert false) c [] typ [] []
1418 elim_duplicates gl (fun x -> x) (res_functions @ res_mors)
1419 | Cic.Prod (_, c1, c2) ->
1420 if (*COQ (dependent (Cic.Rel 1) c2)*) assert false
1422 raise (ProofEngineTypes.Fail (lazy
1423 ("Cannot rewrite in the type of a variable bound " ^
1424 "in a dependent product.")))
1426 let typeofc1 = (*COQ Tacmach.pf_type_of gl c1*) assert false in
1427 if not (*COQ (Tacmach.pf_conv_x gl typeofc1 (Cic.Sort Cic.Prop))*) (assert false) then
1428 (* to avoid this error we should introduce an impl relation
1429 whose first argument is Type instead of Prop. However,
1430 the type of the new impl would be Type -> Prop -> Prop
1431 that is no longer a Relation_Definitions.relation. Thus
1432 the Coq part of the tactic should be heavily modified. *)
1433 raise (ProofEngineTypes.Fail (lazy
1434 ("Rewriting in a product A -> B is possible only when A " ^
1435 "is a proposition (i.e. A is of type Prop). The type " ^
1436 CicPp.ppterm c1 ^ " has type " ^ CicPp.ppterm typeofc1 ^
1437 " that is not convertible to Prop.")))
1439 aux output_relation output_direction
1440 (Cic.Appl [coq_impl; c1 ; CicSubstitution.subst (Cic.Rel 1 (*dummy*)) c2])
1442 if (*COQ occur_term t in_c*) assert false then
1443 raise (ProofEngineTypes.Fail (lazy
1444 ("Trying to replace " ^ CicPp.ppterm t ^ " in " ^ CicPp.ppterm in_c ^
1445 " that is not an applicative context.")))
1447 [ToKeep (in_c,output_relation,output_direction)]
1449 let aux2 output_relation output_direction =
1451 (fun res -> output_relation,output_direction,res)
1452 (aux output_relation output_direction in_c) in
1454 (aux2 coq_iff_relation Right2Left) @
1455 (* This is the case of a proposition of signature A ++> iff or B --> iff *)
1456 (aux2 coq_iff_relation Left2Right) @
1457 (aux2 coq_impl_relation Right2Left) in
1458 let res = elim_duplicates gl (function (_,_,t) -> t) res in
1459 let res' = filter_superset_of_new_goals gl new_goals res in
1462 raise (ProofEngineTypes.Fail (lazy
1463 ("Either the term " ^ CicPp.ppterm t ^ " that must be " ^
1464 "rewritten occurs in a covariant position or the goal is not " ^
1465 "made of morphism applications only. You can replace only " ^
1466 "occurrences that are in a contravariant position and such that " ^
1467 "the context obtained by abstracting them is made of morphism " ^
1468 "applications only.")))
1470 raise (ProofEngineTypes.Fail (lazy
1471 ("No generated set of side conditions is a superset of those " ^
1472 "requested by the user. The generated sets of side conditions " ^
1474 prlist_with_sepi "\n"
1475 (fun i (_,_,mc) -> pr_new_goals i mc) res)))
1479 ("Warning: The application of the tactic is subject to one of " ^
1480 "the \nfollowing set of side conditions that the user needs " ^
1482 prlist_with_sepi "\n"
1483 (fun i (_,_,mc) -> pr_new_goals i mc) res' ^
1484 "\nThe first set is randomly chosen. Use the syntax " ^
1485 "\"setoid_rewrite ... generate side conditions ...\" to choose " ^
1486 "a different set.") ;
1489 let cic_morphism_context_list_of_list hole_relation hole_direction out_direction
1494 Cic.Appl [coq_MSNone ; dir ; dir']
1495 | (Some true,dir,dir') ->
1496 assert (dir = dir');
1497 Cic.Appl [coq_MSCovariant ; dir]
1498 | (Some false,dir,dir') ->
1499 assert (dir <> dir');
1500 Cic.Appl [coq_MSContravariant ; dir] in
1504 | [(variance,out),(value,direction)] ->
1505 Cic.Appl [coq_singl ; coq_Argument_Class ; out],
1508 hole_relation; hole_direction ; out ;
1509 direction ; out_direction ;
1510 check (variance,direction,out_direction) ; value]
1511 | ((variance,out),(value,direction))::tl ->
1512 let outtl, valuetl = aux tl in
1514 [coq_cons; coq_Argument_Class ; out ; outtl],
1517 hole_relation ; hole_direction ; out ; outtl ;
1518 direction ; out_direction ;
1519 check (variance,direction,out_direction) ;
1523 let rec cic_type_nelist_of_list =
1527 Cic.Appl [coq_singl; Cic.Sort (Cic.Type (CicUniv.fresh ())) ; value]
1530 [coq_cons; Cic.Sort (Cic.Type (CicUniv.fresh ())); value;
1531 cic_type_nelist_of_list tl]
1533 let syntactic_but_representation_of_marked_but hole_relation hole_direction =
1534 let rec aux out (rel_out,precise_out,is_reflexive) =
1536 MApp (f, m, args, direction) ->
1537 let direction = cic_direction_of_direction direction in
1538 let morphism_theory, relations =
1540 ACMorphism { args = args ; morphism_theory = morphism_theory } ->
1541 morphism_theory,args
1542 | ACFunction { f_args = f_args ; f_output = f_output } ->
1544 if (*COQ eq_constr out (cic_relation_class_of_relation_class
1545 coq_iff_relation)*) assert false
1548 [coq_morphism_theory_of_predicate;
1549 cic_type_nelist_of_list f_args; f]
1552 [coq_morphism_theory_of_function;
1553 cic_type_nelist_of_list f_args; f_output; f]
1555 mt,List.map (fun x -> None,Leibniz (Some x)) f_args in
1558 (fun (variance,r) ->
1561 cic_relation_class_of_relation_class r,
1562 cic_precise_relation_class_of_relation_class r
1564 let cic_args_relations,argst =
1565 cic_morphism_context_list_of_list hole_relation hole_direction direction
1567 (fun (variance,trel,t,precise_t) v ->
1568 (variance,cic_argument_class_of_argument_class (variance,trel)),
1570 direction_of_constr_with_marks hole_direction v)
1571 ) cic_relations args)
1575 hole_relation ; hole_direction ;
1576 cic_args_relations ; out ; direction ;
1577 morphism_theory ; argst]
1579 Cic.Appl [coq_ToReplace ; hole_relation ; hole_direction]
1580 | ToKeep (c,_,direction) ->
1581 let direction = cic_direction_of_direction direction in
1582 if is_reflexive then
1584 [coq_ToKeep ; hole_relation ; hole_direction ; precise_out ;
1588 let typ = Cic.Appl [rel_out ; c ; c] in
1589 Cic.Cast ((*COQ Evarutil.mk_new_meta ()*)assert false, typ)
1592 [coq_ProperElementToKeep ;
1593 hole_relation ; hole_direction; precise_out ;
1594 direction; c ; c_is_proper]
1597 let apply_coq_setoid_rewrite hole_relation prop_relation c1 c2 (direction,h)
1600 let hole_relation = cic_relation_class_of_relation_class hole_relation in
1601 let hyp,hole_direction = h,cic_direction_of_direction direction in
1602 let cic_prop_relation = cic_relation_class_of_relation_class prop_relation in
1603 let precise_prop_relation =
1604 cic_precise_relation_class_of_relation_class prop_relation
1607 [coq_setoid_rewrite;
1608 hole_relation ; hole_direction ; cic_prop_relation ;
1609 prop_direction ; c1 ; c2 ;
1610 syntactic_but_representation_of_marked_but hole_relation hole_direction
1611 cic_prop_relation precise_prop_relation m ; hyp]
1614 let check_evar_map_of_evars_defs evd =
1615 let metas = Evd.meta_list evd in
1616 let check_freemetas_is_empty rebus =
1619 if Evd.meta_defined evd m then () else
1620 raise (Logic.RefinerError (Logic.OccurMetaGoal rebus)))
1625 Evd.Cltyp (_,{Evd.rebus=rebus; Evd.freemetas=freemetas}) ->
1626 check_freemetas_is_empty rebus freemetas
1627 | Evd.Clval (_,{Evd.rebus=rebus1; Evd.freemetas=freemetas1},
1628 {Evd.rebus=rebus2; Evd.freemetas=freemetas2}) ->
1629 check_freemetas_is_empty rebus1 freemetas1 ;
1630 check_freemetas_is_empty rebus2 freemetas2
1634 (* For a correct meta-aware "rewrite in", we split unification
1635 apart from the actual rewriting (Pierre L, 05/04/06) *)
1637 (* [unification_rewrite] searchs a match for [c1] in [but] and then
1638 returns the modified objects (in particular [c1] and [c2]) *)
1640 let unification_rewrite c1 c2 cl but gl =
1644 (* ~mod_delta:false to allow to mark occurences that must not be
1645 rewritten simply by replacing them with let-defined definitions
1647 w_unify_to_subterm ~mod_delta:false (pf_env gl) (c1,but) cl.env
1649 Pretype_errors.PretypeError _ ->
1650 (* ~mod_delta:true to make Ring work (since it really
1651 exploits conversion) *)
1652 w_unify_to_subterm ~mod_delta:true (pf_env gl) (c1,but) cl.env
1654 let cl' = {cl with env = env' } in
1655 let c2 = Clenv.clenv_nf_meta cl' c2 in
1656 check_evar_map_of_evars_defs env' ;
1657 env',Clenv.clenv_value cl', c1, c2
1660 (* no unification is performed in this function. [sigma] is the
1661 substitution obtained from an earlier unification. *)
1663 let relation_rewrite_no_unif c1 c2 hyp ~new_goals sigma gl =
1664 let but = (*COQ pf_concl gl*) assert false in
1666 let input_relation =
1667 relation_class_that_matches_a_constr "Setoid_rewrite"
1668 new_goals ((*COQTyping.mtype_of (pf_env gl) sigma (snd hyp)*) assert false) in
1669 let output_relation,output_direction,marked_but =
1670 mark_occur gl ~new_goals c1 but input_relation (fst hyp) in
1671 let cic_output_direction = cic_direction_of_direction output_direction in
1672 let if_output_relation_is_iff gl =
1674 apply_coq_setoid_rewrite input_relation output_relation c1 c2 hyp
1675 cic_output_direction marked_but
1677 let new_but = (*COQ Termops.replace_term c1 c2 but*) assert false in
1678 let hyp1,hyp2,proj =
1679 match output_direction with
1680 Right2Left -> new_but, but, coq_proj1
1681 | Left2Right -> but, new_but, coq_proj2
1683 let impl1 = Cic.Prod (Cic.Anonymous, hyp2, CicSubstitution.lift 1 hyp1) in
1684 let impl2 = Cic.Prod (Cic.Anonymous, hyp1, CicSubstitution.lift 1 hyp2) in
1685 let th' = Cic.Appl [proj; impl2; impl1; th] in
1686 (*COQ Tactics.refine
1687 (Cic.Appl [th'; mkCast (Evarutil.mk_new_meta(), DEFAULTcast, new_but)])
1688 gl*) let _ = th' in assert false in
1689 let if_output_relation_is_if gl =
1691 apply_coq_setoid_rewrite input_relation output_relation c1 c2 hyp
1692 cic_output_direction marked_but
1694 let new_but = (*COQ Termops.replace_term c1 c2 but*) assert false in
1695 (*COQ Tactics.refine
1696 (Cic.Appl [th ; mkCast (Evarutil.mk_new_meta(), DEFAULTcast, new_but)])
1697 gl*) let _ = new_but,th in assert false in
1698 if output_relation = coq_iff_relation then
1699 if_output_relation_is_iff gl
1701 if_output_relation_is_if gl
1704 (*COQ !general_rewrite (fst hyp = Left2Right) (snd hyp) gl*) assert false
1706 let relation_rewrite c1 c2 (input_direction,cl) ~new_goals gl =
1707 let (sigma,cl,c1,c2) = unification_rewrite c1 c2 cl ((*COQ pf_concl gl*) assert false) gl in
1708 relation_rewrite_no_unif c1 c2 (input_direction,cl) ~new_goals sigma gl
1710 let analyse_hypothesis gl c =
1711 let ctype = (*COQ pf_type_of gl c*) assert false in
1712 let eqclause = (*COQ Clenv.make_clenv_binding gl (c,ctype) Rawterm.NoBindings*) let _ = ctype in assert false in
1713 let (equiv, args) = (*COQ decompose_app (Clenv.clenv_type eqclause)*) assert false in
1714 let rec split_last_two = function
1715 | [c1;c2] -> [],(c1, c2)
1717 let l,res = split_last_two (y::z) in x::l, res
1718 | _ -> raise (ProofEngineTypes.Fail (lazy "The term provided is not an equivalence")) in
1719 let others,(c1,c2) = split_last_two args in
1720 eqclause,Cic.Appl (equiv::others),c1,c2
1722 let general_s_rewrite lft2rgt c ~new_goals (*COQgl*) =
1724 let eqclause,_,c1,c2 = analyse_hypothesis gl c in
1726 relation_rewrite c1 c2 (Left2Right,eqclause) ~new_goals gl
1728 relation_rewrite c2 c1 (Right2Left,eqclause) ~new_goals gl
1731 let relation_rewrite_in id c1 c2 (direction,eqclause) ~new_goals gl =
1732 let hyp = (*COQ pf_type_of gl (mkVar id)*) assert false in
1733 (* first, we find a match for c1 in the hyp *)
1734 let (sigma,cl,c1,c2) = unification_rewrite c1 c2 eqclause hyp gl in
1735 (* since we will actually rewrite in the opposite direction, we also need
1736 to replace every occurrence of c2 (resp. c1) in hyp with something that
1737 is convertible but not syntactically equal. To this aim we introduce a
1738 let-in and then we will use the intro tactic to get rid of it.
1739 Quite tricky to do properly since c1 can occur in c2 or vice-versa ! *)
1740 let mangled_new_hyp =
1741 let hyp = CicSubstitution.lift 2 hyp in
1742 (* first, we backup every occurences of c1 in newly allocated (Rel 1) *)
1743 let hyp = (*COQ Termops.replace_term (CicSubstitution.lift 2 c1) (Cic.Rel 1) hyp*) let _ = hyp in assert false in
1744 (* then, we factorize every occurences of c2 into (Rel 2) *)
1745 let hyp = (*COQ Termops.replace_term (CicSubstitution.lift 2 c2) (Cic.Rel 2) hyp*) let _ = hyp in assert false in
1746 (* Now we substitute (Rel 1) (i.e. c1) for c2 *)
1747 let hyp = CicSubstitution.subst (CicSubstitution.lift 1 c2) hyp in
1748 (* Since CicSubstitution.subst has killed Rel 1 and decreased the other Rels,
1749 Rel 1 is now coding for c2, we can build the let-in factorizing c2 *)
1750 Cic.LetIn (Cic.Anonymous,c2,hyp)
1752 let new_hyp = (*COQ Termops.replace_term c1 c2 hyp*) assert false in
1753 let oppdir = opposite_direction direction in
1755 cut_replacing id new_hyp
1757 (tclTHEN (change_in_concl None mangled_new_hyp)
1759 (relation_rewrite_no_unif c2 c1 (oppdir,cl) ~new_goals sigma))))
1761 *) let _ = oppdir,new_hyp,mangled_new_hyp in assert false
1763 let general_s_rewrite_in id lft2rgt c ~new_goals (*COQgl*) =
1765 let eqclause,_,c1,c2 = analyse_hypothesis gl c in
1767 relation_rewrite_in id c1 c2 (Left2Right,eqclause) ~new_goals gl
1769 relation_rewrite_in id c2 c1 (Right2Left,eqclause) ~new_goals gl
1772 let setoid_replace relation c1 c2 ~new_goals (*COQgl*) =
1778 match find_relation_class rel with
1780 | Leibniz _ -> raise Optimize
1783 raise (ProofEngineTypes.Fail (lazy
1784 (CicPp.ppterm rel ^ " is not a registered relation."))))
1786 match default_relation_for_carrier ((*COQ pf_type_of gl c1*) assert false) with
1788 | Leibniz _ -> raise Optimize
1790 let eq_left_to_right = Cic.Appl [relation.rel_aeq; c1 ; c2] in
1791 let eq_right_to_left = Cic.Appl [relation.rel_aeq; c2 ; c1] in
1793 let replace dir eq =
1794 tclTHENS (assert_tac false Cic.Anonymous eq)
1795 [onLastHyp (fun id ->
1797 (general_s_rewrite dir (mkVar id) ~new_goals)
1802 (replace true eq_left_to_right) (replace false eq_right_to_left) gl
1803 *) let _ = eq_left_to_right,eq_right_to_left in assert false
1805 Optimize -> (*COQ (!replace c1 c2) gl*) assert false
1807 let setoid_replace_in id relation c1 c2 ~new_goals (*COQgl*) =
1809 let hyp = pf_type_of gl (mkVar id) in
1810 let new_hyp = Termops.replace_term c1 c2 hyp in
1811 cut_replacing id new_hyp
1812 (fun exact -> tclTHENLASTn
1813 (setoid_replace relation c2 c1 ~new_goals)
1814 [| exact; tclIDTAC |]) gl
1817 (* [setoid_]{reflexivity,symmetry,transitivity} tactics *)
1819 let setoid_reflexivity (*COQgl*) =
1821 let relation_class =
1822 relation_class_that_matches_a_constr "Setoid_reflexivity"
1823 [] ((*COQ pf_concl gl*) assert false) in
1824 match relation_class with
1825 Leibniz _ -> assert false (* since [] is empty *)
1827 match rel.rel_refl with
1829 raise (ProofEngineTypes.Fail (lazy
1830 ("The relation " ^ prrelation rel ^ " is not reflexive.")))
1831 | Some refl -> (*COQ apply refl gl*) assert false
1833 Optimize -> (*COQ reflexivity gl*) assert false
1835 let setoid_symmetry (*COQgl*) =
1837 let relation_class =
1838 relation_class_that_matches_a_constr "Setoid_symmetry"
1839 [] ((*COQ pf_concl gl*) assert false) in
1840 match relation_class with
1841 Leibniz _ -> assert false (* since [] is empty *)
1843 match rel.rel_sym with
1845 raise (ProofEngineTypes.Fail (lazy
1846 ("The relation " ^ prrelation rel ^ " is not symmetric.")))
1847 | Some sym -> (*COQ apply sym gl*) assert false
1849 Optimize -> (*COQ symmetry gl*) assert false
1851 let setoid_symmetry_in id (*COQgl*) =
1854 let _,he,c1,c2 = analyse_hypothesis gl (mkVar id) in
1855 Cic.Appl [he ; c2 ; c1]
1857 cut_replacing id new_hyp (tclTHEN setoid_symmetry) gl
1860 let setoid_transitivity c (*COQgl*) =
1862 let relation_class =
1863 relation_class_that_matches_a_constr "Setoid_transitivity"
1864 [] ((*COQ pf_concl gl*) assert false) in
1865 match relation_class with
1866 Leibniz _ -> assert false (* since [] is empty *)
1869 let ctyp = pf_type_of gl c in
1870 let rel' = unify_relation_carrier_with_type (pf_env gl) rel ctyp in
1871 match rel'.rel_trans with
1873 raise (ProofEngineTypes.Fail (lazy
1874 ("The relation " ^ prrelation rel ^ " is not transitive.")))
1876 let transty = nf_betaiota (pf_type_of gl trans) in
1878 Reductionops.decomp_n_prod (pf_env gl) Evd.empty 2 transty in
1880 match List.rev argsrev with
1881 _::(Name n2,None,_)::_ -> Rawterm.NamedHyp n2
1885 (trans, Rawterm.ExplicitBindings [ dummy_loc, binder, c ]) gl
1888 Optimize -> (*COQ transitivity c gl*) assert false
1892 Tactics.register_setoid_reflexivity setoid_reflexivity;;
1893 Tactics.register_setoid_symmetry setoid_symmetry;;
1894 Tactics.register_setoid_symmetry_in setoid_symmetry_in;;
1895 Tactics.register_setoid_transitivity setoid_transitivity;;