diff options
author | msozeau <msozeau@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2009-04-27 16:50:42 +0000 |
---|---|---|
committer | msozeau <msozeau@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2009-04-27 16:50:42 +0000 |
commit | e9667ab2ee2b05e54030345668c13fa363a399d9 (patch) | |
tree | d157af03964c8eff15b28fb7a587fc9c8d420d4b | |
parent | 94affd965c1554d2ad10654e9832fcdb2a024daf (diff) |
- Implementation of a new typeclasses eauto procedure based on success
and failure continuations, allowing to do safe cuts correctly.
- Fix bug #2097 by suppressing useless nf_evars calls.
- Improve the proof search strategy used by rewrite for subrelations and
fix some hints.
Up to 20% speed improvement in setoid-intensive files.
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@12110 85f007b7-540e-0410-9357-904b9bb8a0f7
-rw-r--r-- | pretyping/typeclasses.ml | 5 | ||||
-rw-r--r-- | tactics/class_tactics.ml4 | 348 | ||||
-rw-r--r-- | tactics/rewrite.ml4 | 124 | ||||
-rw-r--r-- | theories/Classes/Init.v | 2 | ||||
-rw-r--r-- | theories/Classes/Morphisms.v | 87 | ||||
-rw-r--r-- | theories/Classes/Morphisms_Prop.v | 14 | ||||
-rw-r--r-- | theories/Classes/RelationClasses.v | 10 |
7 files changed, 404 insertions, 186 deletions
diff --git a/pretyping/typeclasses.ml b/pretyping/typeclasses.ml index 56b78715a..219f9d127 100644 --- a/pretyping/typeclasses.ml +++ b/pretyping/typeclasses.ml @@ -332,9 +332,8 @@ let solve_instanciations_problem = ref (fun _ _ _ _ _ -> assert false) let solve_instanciation_problem = ref (fun _ _ _ -> assert false) let resolve_typeclasses ?(onlyargs=false) ?(split=true) ?(fail=true) env evd = - if not (has_typeclasses ( evd)) then evd - else - !solve_instanciations_problem env (Evarutil.nf_evar_defs evd) onlyargs split fail + if not (has_typeclasses evd) then evd + else !solve_instanciations_problem env evd onlyargs split fail let resolve_one_typeclass env evm t = !solve_instanciation_problem env evm t diff --git a/tactics/class_tactics.ml4 b/tactics/class_tactics.ml4 index 31ffc8897..3c3ff4984 100644 --- a/tactics/class_tactics.ml4 +++ b/tactics/class_tactics.ml4 @@ -46,6 +46,59 @@ let typeclasses_db = "typeclass_instances" let _ = Auto.auto_init := (fun () -> Auto.create_hint_db false typeclasses_db full_transparent_state true) +exception Found of evar_map + +let is_dependent ev evm = + Evd.fold (fun ev' evi dep -> + if ev = ev' then dep + else dep || occur_evar ev evi.evar_concl) + evm false + +let valid goals p res_sigma l = + let evm = + List.fold_left2 + (fun sigma (ev, evi) prf -> + let cstr, obls = Refiner.extract_open_proof !res_sigma prf in + if not (Evd.is_defined sigma ev) then + Evd.define ev cstr sigma + else sigma) + !res_sigma goals l + in raise (Found evm) + +let evars_to_goals p evm = + let goals, evm' = + Evd.fold + (fun ev evi (gls, evm') -> + if evi.evar_body = Evar_empty + && Typeclasses.is_resolvable evi + (* && not (is_dependent ev evm) *) + && p ev evi then ((ev,evi) :: gls, Evd.add evm' ev (Typeclasses.mark_unresolvable evi)) else + (gls, Evd.add evm' ev evi)) + evm ([], Evd.empty) + in + if goals = [] then None + else + let goals = List.rev goals in + Some (goals, evm') + +let run_with_evars_to_goals p cont evm = + match evars_to_goals p evm with + | None -> None + | Some (goals, evm') -> + let gls = { it = List.map snd goals; sigma = evm' } in + let res_sigma = ref evm' in + let gls', valid' = cont (gls, valid goals p res_sigma) in + res_sigma := Evarutil.nf_evars (sig_sig gls'); + try ignore(valid' []); assert(false) + with Found evm' -> + Some (Evarutil.nf_evar_defs (Evd.evars_reset_evd evm' evm)) + +let solve_remaining_evars tac gl = + let res = run_with_evars_to_goals (fun ev evi -> Typeclasses.is_class_evar evi) tac (project gl) in + match res with + | None -> tclIDTAC gl + | Some res -> Refiner.tclEVARS res gl + (** Typeclasses instance search tactic / eauto *) let intersects s t = @@ -74,12 +127,23 @@ let unify_e_resolve flags (c,clenv) gls = let clenv' = connect_clenv gls clenv in let clenv' = clenv_unique_resolver false ~flags clenv' gls in Clenvtac.clenv_refine true ~with_classes:false clenv' gls - + let unify_resolve flags (c,clenv) gls = let clenv' = connect_clenv gls clenv in let clenv' = clenv_unique_resolver false ~flags clenv' gls in Clenvtac.clenv_refine false ~with_classes:false clenv' gls +(** Hack to properly solve dependent evars that are typeclasses *) + +let forward_typeclasses_eauto = ref (fun gl -> failwith "Undefined forward_typeclasses_eauto") +let typeclasses_evars gl = solve_remaining_evars !forward_typeclasses_eauto gl + +let unify_e_resolve flags (c,clenv) = + unify_e_resolve flags (c, clenv) + +let unify_resolve flags (c,clenv) = + unify_resolve flags (c, clenv) + let flags_of_state st = {auto_unif_flags with modulo_conv_on_closed_terms = Some st; modulo_delta = st} @@ -171,7 +235,15 @@ let is_dep gl gls = let evs' = Evarutil.evars_of_term gl.evar_concl in intersects evs evs') false gls - + +let is_ground gl = + Evarutil.is_ground_term (project gl) (pf_concl gl) + +let nb_empty_evars s = + Evd.fold (fun ev evi acc -> if evi.evar_body = Evar_empty then succ acc else acc) s 0 + +let pr_ev evs ev = Printer.pr_constr_env (Evd.evar_env ev) (Evarutil.nf_evar evs ev.Evd.evar_concl) + module SearchProblem = struct type state = search_state @@ -179,8 +251,6 @@ module SearchProblem = struct let debug = ref false let success s = sig_it (fst s.tacres) = [] - - let pr_ev evs ev = Printer.pr_constr_env (Evd.evar_env ev) (Evarutil.nf_evar evs ev.Evd.evar_concl) let pr_goals gls = let evars = Evarutil.nf_evars (Refiner.project gls) in @@ -199,8 +269,6 @@ module SearchProblem = struct with e when catchable e -> aux tacl in aux l - let nb_empty_evars s = - Evd.fold (fun ev evi acc -> if evi.evar_body = Evar_empty then succ acc else acc) s 0 (* Ordering of states is lexicographic on depth (greatest first) then priority (lowest pri means higher priority), then number of remaining goals. *) @@ -220,35 +288,33 @@ module SearchProblem = struct [] else let (cut, do_cut, ldb as hdldb) = List.hd s.localdb in + Option.iter (fun r -> r := true) do_cut; if !cut then (* let {it=gls; sigma=sigma} = fst s.tacres in *) (* msg (str"cut:" ++ pr_ev sigma (List.hd gls) ++ str"\n"); *) [] - else begin - let {it=gl; sigma=sigma} = fst s.tacres in - Option.iter (fun r -> -(* msg (str"do cut:" ++ pr_ev sigma (List.hd gl) ++ str"\n"); *) - r := true) do_cut; -(* let sigma = Evarutil.nf_evars sigma in *) - let gl = List.map (Evarutil.nf_evar_info sigma) gl in - let nbgl = List.length gl in -(* let gl' = { it = gl ; sigma = sigma } in *) -(* let tacres' = gl', snd s.tacres in *) + else + begin + let {it=gl; sigma=sigma} = fst s.tacres in + (* let sigma = Evarutil.nf_evars sigma in *) +(* let gl = List.map (Evarutil.nf_evar_info sigma) gl in *) + let nbgl = List.length gl in + (* let gl' = { it = gl ; sigma = sigma } in *) + (* let tacres' = gl', snd s.tacres in *) let new_db, localdb = - let tl = List.tl s.localdb in hdldb, tl -(* match tl with *) -(* | [] -> hdldb, tl *) -(* | (cut', do', ldb') :: rest -> *) -(* if not (is_dep (List.hd gl) (List.tl gl)) then *) -(* let fresh = ref false in *) -(* if do' = None then ( *) -(* (\* msg (str"adding a cut:" ++ pr_ev sigma (List.hd gl) ++ str"\n"); *\) *) -(* (fresh, None, ldb), (cut', Some fresh, ldb') :: rest *) -(* ) else ( *) -(* (\* msg (str"keeping the previous cut:" ++ pr_ev sigma (List.hd gl) ++ str"\n"); *\) *) -(* (cut', None, ldb), tl ) *) -(* else hdldb, tl *) - in let localdb = new_db :: localdb in + let tl = List.tl s.localdb in + match tl with + | [] -> hdldb, tl + | (cut', do', ldb') :: rest -> + if Evarutil.is_ground_term sigma (List.hd gl).evar_concl (* not (is_dep (List.hd gl) (List.tl gl)) *) then + let fresh = ref false in + ((* msg (str"adding a cut:" ++ pr_ev sigma (List.hd gl) ++ str"\n"); *) + (fresh, do', ldb), (cut', Some fresh, ldb') :: rest) + else ( + msg (str"not ground:" ++ pr_ev sigma (List.hd gl) ++ str"\n"); + hdldb, tl) + in + let localdb = new_db :: localdb in let intro_tac = List.map (fun ((lgls,_) as res,pri,pp) -> @@ -282,14 +348,130 @@ module SearchProblem = struct List.map possible_resolve l in List.sort compare (intro_tac @ rec_tacs) - end - + end + let pp s = msg (hov 0 (str " depth=" ++ int s.depth ++ spc () ++ s.last_tactic ++ str "\n")) end +type validation = evar_map -> proof_tree list -> proof_tree + +type autoinfo = { hints : Auto.hint_db; auto_depth: int; auto_last_tac: std_ppcmds } +type autogoal = goal * autoinfo +type 'ans fk = unit -> 'ans +type ('a,'ans) sk = 'a -> 'ans fk -> 'ans +type 'a tac = { skft : 'ans. ('a,'ans) sk -> 'ans fk -> autogoal sigma -> 'ans } + +type auto_result = autogoal list sigma * validation + +type atac = auto_result tac + +let lift_tactic tac (f : goal list sigma -> autoinfo -> autogoal list sigma) : 'a tac = + { skft = fun sk fk {it = gl,hints; sigma=s} -> + let res = try Some (tac {it=gl; sigma=s}) with e when catchable e -> None in + match res with + | Some (gls,v) -> sk (f gls hints, fun _ -> v) fk + | None -> fk () } + +let intro_tac : atac = + lift_tactic Tactics.intro + (fun {it = gls; sigma = s} info -> + let gls' = + List.map (fun g' -> + let env = evar_env g' in + let hint = make_resolve_hyp env s (List.hd (evar_context g')) in + let ldb = Hint_db.add_list hint info.hints in + (g', { info with hints = ldb; auto_last_tac = str"intro" })) gls + in {it = gls'; sigma = s}) + +let id_tac : atac = + { skft = fun sk fk {it = gl; sigma = s} -> + sk ({it = [gl]; sigma = s}, fun _ pfs -> List.hd pfs) fk } + +(* Ordering of states is lexicographic on the number of remaining goals. *) +let compare (pri, _, (res, _)) (pri', _, (res', _)) = + let nbgoals s = + List.length (sig_it s) + nb_empty_evars (sig_sig s) + in + let pri = pri - pri' in + if pri <> 0 then pri + else nbgoals res - nbgoals res' + +let or_tac (x : 'a tac) (y : 'a tac) : 'a tac = + { skft = fun sk fk gls -> x.skft sk (fun () -> y.skft sk fk gls) gls } + +let solve_tac (x : 'a tac) : 'a tac = + { skft = fun sk fk gls -> x.skft (fun ({it = gls},_ as res) fk -> if gls = [] then sk res fk else fk ()) fk gls } + +let hints_tac hints = + { skft = fun sk fk {it = gl,info; sigma = s} -> + if !SearchProblem.debug then msgnl (str"depth=" ++ int info.auto_depth ++ str": " ++ info.auto_last_tac + ++ spc () ++ str "->" ++ spc () ++ pr_ev s gl); + let possible_resolve ((lgls,v) as res, pri, pp) = + (pri, pp, res) + in + let tacs = + let poss = e_possible_resolve hints info.hints gl.evar_concl in + let l = + Util.list_map_append (fun (tac, pri, pptac) -> + try [tac {it = gl; sigma = s}, pri, pptac] with e when catchable e -> []) + poss + in + List.map possible_resolve l + in + let tacs = List.sort compare tacs in + let info = { info with auto_depth = succ info.auto_depth } in + let rec aux = function + | (_, pp, ({it = gls; sigma = s}, v)) :: tl -> + if !SearchProblem.debug then msgnl (str"depth=" ++ int info.auto_depth ++ str": " ++ pp + ++ spc () ++ str"succeeded on" ++ spc () ++ pr_ev s gl); + let fk = + (fun () -> if !SearchProblem.debug then msgnl (str"backtracked after " ++ pp ++ spc () ++ str"failed"); + aux tl) + in + let glsv = {it = List.map (fun g -> g, { info with auto_last_tac = pp }) gls; sigma = s}, fun _ -> v in + sk glsv fk + | [] -> fk () + in aux tacs } + +let then_list (second : atac) (sk : (auto_result, 'a) sk) : (auto_result, 'a) sk = + let rec aux s (acc : (autogoal list * validation) list) fk = function + | (gl,info) :: gls -> + second.skft (fun ({it=gls';sigma=s'},v') fk' -> + let fk'' = if gls' = [] && Evarutil.is_ground_term s gl.evar_concl then + (if !SearchProblem.debug then msgnl (str"no backtrack on" ++ pr_ev s gl); fk) else fk' in + aux s' ((gls',v')::acc) fk'' gls) fk {it = (gl,info); sigma = s} + | [] -> Some (List.rev acc, s, fk) + in fun ({it = gls; sigma = s},v) fk -> + let rec aux' = function + | None -> fk () + | Some (res, s', fk') -> + let goals' = List.concat (List.map (fun (gls,v) -> gls) res) in + let v' s' pfs' : proof_tree = + let (newpfs, rest) = List.fold_left (fun (newpfs,pfs') (gls,v) -> + let before, after = list_split_at (List.length gls) pfs' in + (v s' before :: newpfs, after)) + ([], pfs') res + in assert(rest = []); v s' (List.rev newpfs) + in sk ({it = goals'; sigma = s'}, v') (fun () -> aux' (fk' ())) + in aux' (aux s [] (fun () -> None) gls) + +let then_tac (first : atac) (second : atac) : atac = + { skft = fun sk fk -> first.skft (then_list second sk) fk } + +let run_tac (t : 'a tac) (gl : autogoal sigma) : auto_result option = + t.skft (fun x _ -> Some x) (fun _ -> None) gl + +let run_list_tac (t : 'a tac) p goals (gl : autogoal list sigma) : auto_result option = + (then_list t (fun x _ -> Some x)) + (gl, fun s pfs -> valid goals p (ref s) pfs) + (fun _ -> None) + +let rec fix (t : 'a tac) : 'a tac = + then_tac t { skft = fun sk fk -> (fix t).skft sk fk } + module Search = Explore.Make(SearchProblem) let make_initial_state n gls dblist localdbs = @@ -303,8 +485,7 @@ let make_initial_state n gls dblist localdbs = let e_depth_search debug s = let tac = if debug then (SearchProblem.debug := true; Search.debug_depth_first) else Search.depth_first in - let s = tac s in - s.tacres + let s = tac s in s.tacres let e_breadth_search debug s = try @@ -335,6 +516,44 @@ let make_resolve_hyp env sigma st flags pri (id, _, cty) = [make_exact_entry pri; make_apply_entry env sigma flags pri] else [] +let make_autogoal ?(st=full_transparent_state) g = + let sign = pf_hyps g in + let hintlist = list_map_append (pf_apply make_resolve_hyp g st (true,false,false) None) sign in + let hints = Hint_db.add_list hintlist (Hint_db.empty st true) in + (g.it, { hints = hints ; auto_depth = 0; auto_last_tac = mt() }) + +let make_autogoals ?(st=full_transparent_state) gs evm' = + { it = List.map (fun g -> make_autogoal ~st {it = snd g; sigma = evm'}) gs; sigma = evm' } + +let run_on_evars ?(st=full_transparent_state) p evm tac = + match evars_to_goals p evm with + | None -> raise Not_found + | Some (goals, evm') -> + match run_list_tac tac p goals (make_autogoals ~st goals evm') with + | None -> raise Not_found + | Some (gls, v) -> + try ignore(v (sig_sig gls) []); assert(false) + with Found evm' -> + Some (Evd.evars_reset_evd evm' evm) + +let eauto hints g = + let tac = fix (hints_tac hints) in + let gl = { it = make_autogoal g; sigma = project g } in + match run_tac tac gl with + | None -> raise Not_found + | Some ({it = goals; sigma = s}, valid) -> + {it = List.map fst goals; sigma = s}, valid s + +let real_eauto st hints p evd = + let tac = fix (hints_tac hints) in + run_on_evars ~st p evd tac + +TACTIC EXTEND ContEauto + | [ "conteauto" "with" ne_preident_list(l) ] -> [ fun gl -> + try eauto (List.map Auto.searchtable_map l) gl + with Not_found -> tclFAIL 0 (str" Continuation-based eauto failed") gl ] +END + let make_local_hint_db st eapply lems g = let sign = pf_hyps g in let hintlist = list_map_append (pf_apply make_resolve_hyp g st (eapply,false,false) None) sign in @@ -366,44 +585,19 @@ let typeclasses_eauto debug n lems gls = let db = searchtable_map typeclasses_db in e_search_auto debug n lems (Hint_db.transparent_state db) [db] gls -exception Found of evar_map +let resolve_all_evars_once debug (mode, depth) p evd = + match run_with_evars_to_goals p (typeclasses_eauto debug (mode, depth) []) evd with + | None -> evd + | Some res -> res -let valid goals p res_sigma l = - let evm = - List.fold_left2 - (fun sigma (ev, evi) prf -> - let cstr, obls = Refiner.extract_open_proof !res_sigma prf in - if not (Evd.is_defined sigma ev) then - Evd.define ev cstr sigma - else sigma) - !res_sigma goals l - in raise (Found evm) +let resolve_all_evars_once debug (mode, depth) p evd = + let db = searchtable_map typeclasses_db in + match real_eauto (Hint_db.transparent_state db) [db] p evd with + | None -> raise Not_found + | Some res -> res -let is_dependent ev evm = - Evd.fold (fun ev' evi dep -> - if ev = ev' then dep - else dep || occur_evar ev evi.evar_concl) - evm false - -let resolve_all_evars_once debug (mode, depth) env p evd = - let evm = evd in - let goals, evm' = - Evd.fold - (fun ev evi (gls, evm') -> - if evi.evar_body = Evar_empty - && Typeclasses.is_resolvable evi -(* && not (is_dependent ev evm) *) - && p ev evi then ((ev,evi) :: gls, Evd.add evm' ev (Typeclasses.mark_unresolvable evi)) else - (gls, Evd.add evm' ev evi)) - evm ([], Evd.empty) - in - let goals = List.rev goals in - let gls = { it = List.map snd goals; sigma = evm' } in - let res_sigma = ref evm' in - let gls', valid' = typeclasses_eauto debug (mode, depth) [] (gls, valid goals p res_sigma) in - res_sigma := Evarutil.nf_evars (sig_sig gls'); - try ignore(valid' []); assert(false) - with Found evm' -> Evarutil.nf_evar_defs (Evd.evars_reset_evd evm' evd) +let _ = + forward_typeclasses_eauto := (typeclasses_eauto false (true, default_eauto_depth) []) exception FoundTerm of constr @@ -452,7 +646,7 @@ let resolve_all_evars debug m env p oevd do_split fail = let rec aux n p evd = if has_undefined p oevm evd then if n > 0 then - let evd' = resolve_all_evars_once debug m env p evd in + let evd' = resolve_all_evars_once debug m p evd in aux (pred n) p evd' else None else Some evd @@ -460,7 +654,7 @@ let resolve_all_evars debug m env p oevd do_split fail = let rec docomp evd = function | [] -> evd | comp :: comps -> - let res = try aux 3 (p comp) evd with Not_found -> None in + let res = try aux 1 (p comp) evd with Not_found -> None in match res with | None -> if fail then @@ -542,6 +736,7 @@ END VERNAC COMMAND EXTEND Typeclasses_Settings | [ "Typeclasses" "eauto" ":=" debug(d) search_mode(s) depth(depth) ] -> [ + SearchProblem.debug := d; let mode = match s with Some t -> t | None -> true in let depth = match depth with Some i -> i | None -> default_eauto_depth in Typeclasses.solve_instanciations_problem := @@ -667,4 +862,13 @@ TACTIC EXTEND varify ] END +TACTIC EXTEND not_evar + [ "not_evar" constr(ty) ] -> [ + match kind_of_term ty with + | Evar _ -> tclFAIL 0 (str"Evar") + | _ -> tclIDTAC ] +END + + + diff --git a/tactics/rewrite.ml4 b/tactics/rewrite.ml4 index 5f19d08de..216beab54 100644 --- a/tactics/rewrite.ml4 +++ b/tactics/rewrite.ml4 @@ -112,6 +112,8 @@ let default_relation = lazy (gen_constant ["Classes"; "SetoidTactics"] "DefaultR let subrelation = lazy (gen_constant ["Classes"; "RelationClasses"] "subrelation") let is_subrelation = lazy (gen_constant ["Classes"; "RelationClasses"] "is_subrelation") +let do_subrelation = lazy (gen_constant ["Classes"; "Morphisms"] "do_subrelation") +let apply_subrelation = lazy (gen_constant ["Classes"; "Morphisms"] "apply_subrelation") let coq_relation = lazy (gen_constant ["Relations";"Relation_Definitions"] "relation") let mk_relation a = mkApp (Lazy.force coq_relation, [| a |]) @@ -160,50 +162,49 @@ let split_head = function hd :: tl -> hd, tl | [] -> assert(false) -let build_signature isevars env m (cstrs : 'a option list) (finalcstr : 'a Lazy.t option) (f : 'a -> constr) = - let new_evar isevars env t = - Evarutil.e_new_evar isevars env +let build_signature evars env m (cstrs : 'a option list) (finalcstr : 'a Lazy.t option) (f : 'a -> constr) = + let new_evar evars env t = + Evarutil.new_evar evars env (* ~src:(dummy_loc, ImplicitArg (ConstRef (Lazy.force respectful), (n, Some na))) *) t in - let mk_relty ty obj = + let mk_relty evars ty obj = match obj with | None -> let relty = mk_relation ty in - new_evar isevars env relty - | Some x -> f x + new_evar evars env relty + | Some x -> evars, f x in - let rec aux env ty l = - let t = Reductionops.whd_betadeltaiota env ( !isevars) ty in + let rec aux env evars ty l = + let t = Reductionops.whd_betadeltaiota env evars ty in match kind_of_term t, l with | Prod (na, ty, b), obj :: cstrs -> if dependent (mkRel 1) b then - let (b, arg, evars) = aux (Environ.push_rel (na, None, ty) env) b cstrs in - let ty = Reductionops.nf_betaiota ( !isevars) ty in + let (evars, b, arg, cstrs) = aux (Environ.push_rel (na, None, ty) env) evars b cstrs in + let ty = Reductionops.nf_betaiota evars ty in let pred = mkLambda (na, ty, b) in let liftarg = mkLambda (na, ty, arg) in let arg' = mkApp (Lazy.force forall_relation, [| ty ; pred ; liftarg |]) in - mkProd(na, ty, b), arg', (ty, None) :: evars + evars, mkProd(na, ty, b), arg', (ty, None) :: cstrs else - let (b', arg, evars) = aux env (subst1 mkProp b) cstrs in - let ty = Reductionops.nf_betaiota( !isevars) ty in - let relty = mk_relty ty obj in + let (evars, b', arg, cstrs) = aux env evars (subst1 mkProp b) cstrs in + let ty = Reductionops.nf_betaiota evars ty in + let evars, relty = mk_relty evars ty obj in let newarg = mkApp (Lazy.force respectful, [| ty ; b' ; relty ; arg |]) in - mkProd(na, ty, b), newarg, (ty, Some relty) :: evars + evars, mkProd(na, ty, b), newarg, (ty, Some relty) :: cstrs | _, obj :: _ -> anomaly "build_signature: not enough products" | _, [] -> (match finalcstr with None -> - let t = Reductionops.nf_betaiota( !isevars) ty in - let rel = mk_relty t None in - t, rel, [t, Some rel] + let t = Reductionops.nf_betaiota evars ty in + let evars, rel = mk_relty evars t None in + evars, t, rel, [t, Some rel] | Some codom -> let (t, rel) = Lazy.force codom in - t, rel, [t, Some rel]) - in aux env m cstrs - + evars, t, rel, [t, Some rel]) + in aux env evars m cstrs + let proper_proof env evars carrier relation x = - let goal = - mkApp (Lazy.force proper_proxy_type, [| carrier ; relation; x |]) - in Evarutil.e_new_evar evars env goal + let goal = mkApp (Lazy.force proper_proxy_type, [| carrier ; relation; x |]) + in Evarutil.new_evar evars env goal let find_class_proof proof_type proof_method env evars carrier relation = try @@ -410,53 +411,63 @@ type rewrite_result = rewrite_result_info option type strategy = Environ.env -> evar_defs -> constr -> types -> constr option -> evar_defs -> rewrite_result option + +let resolve_subrelation env sigma car rel rel' res = + if eq_constr rel rel' then res + else +(* try let evd' = Evarconv.the_conv_x env rel rel' res.rew_evars in *) +(* { res with rew_evars = evd' } *) +(* with NotConvertible -> *) + let app = mkApp (Lazy.force subrelation, [|car; rel; rel'|]) in + let evars, subrel = Evarutil.new_evar res.rew_evars env app in + { res with + rew_prf = mkApp (subrel, [| res.rew_from ; res.rew_to ; res.rew_prf |]); + rew_rel = rel'; + rew_evars = evars } + let resolve_morphism env sigma oldt m ?(fnewt=fun x -> x) args args' cstr evars = - let morph_instance, proj, sigargs, m', args, args' = + let evars, morph_instance, proj, sigargs, m', args, args' = let first = try (array_find args' (fun i b -> b <> None)) with Not_found -> raise (Invalid_argument "resolve_morphism") in let morphargs, morphobjs = array_chop first args in let morphargs', morphobjs' = array_chop first args' in let appm = mkApp(m, morphargs) in let appmtype = Typing.type_of env sigma appm in - let cstrs = List.map (function None -> None | Some r -> Some (r.rew_car, r.rew_rel)) (Array.to_list morphobjs') in - let appmtype', signature, sigargs = build_signature evars env appmtype cstrs cstr (fun (a,r) -> r) in + let cstrs = List.map (Option.map (fun r -> r.rew_car, r.rew_rel)) (Array.to_list morphobjs') in + (* Desired signature *) + let evars, appmtype', signature, sigargs = build_signature evars env appmtype cstrs cstr (fun (a,r) -> r) in + (* Actual signature found *) let cl_args = [| appmtype' ; signature ; appm |] in let app = mkApp (Lazy.force proper_type, cl_args) in - let morph = Evarutil.e_new_evar evars env app in - morph, morph, sigargs, appm, morphobjs, morphobjs' + let env' = Environ.push_named + (id_of_string "do_subrelation", Some (Lazy.force do_subrelation), Lazy.force apply_subrelation) + env + in + let evars, morph = Evarutil.new_evar evars env' app in + evars, morph, morph, sigargs, appm, morphobjs, morphobjs' in - let projargs, respars, typeargs = + let projargs, evars, respars, typeargs = array_fold_left2 - (fun (acc, sigargs, typeargs') x y -> + (fun (acc, evars, sigargs, typeargs') x y -> let (carrier, relation), sigargs = split_head sigargs in match relation with | Some relation -> (match y with | None -> - let proof = proper_proof env evars carrier relation x in - [ proof ; x ; x ] @ acc, sigargs, x :: typeargs' + let evars, proof = proper_proof env evars carrier relation x in + [ proof ; x ; x ] @ acc, evars, sigargs, x :: typeargs' | Some r -> - [ r.rew_prf; r.rew_to; x ] @ acc, sigargs, r.rew_to :: typeargs') + [ r.rew_prf; r.rew_to; x ] @ acc, evars, sigargs, r.rew_to :: typeargs') | None -> if y <> None then error "Cannot rewrite the argument of a dependent function"; - x :: acc, sigargs, x :: typeargs') - ([], sigargs, []) args args' + x :: acc, evars, sigargs, x :: typeargs') + ([], evars, sigargs, []) args args' in let proof = applistc proj (List.rev projargs) in let newt = applistc m' (List.rev typeargs) in match respars with - [ a, Some r ] -> (proof, (a, r, oldt, fnewt newt)) + [ a, Some r ] -> evars, proof, a, r, oldt, fnewt newt | _ -> assert(false) - -let resolve_subrelation env sigma car rel rel' res = - if convertible env sigma rel rel' then res - else - let app = mkApp (Lazy.force subrelation, [|car; rel; rel'|]) in - let evars, subrel = Evarutil.new_evar res.rew_evars env app in - { res with - rew_prf = mkApp (subrel, [| res.rew_from ; res.rew_to ; res.rew_prf |]); - rew_rel = rel'; - rew_evars = evars } let apply_constraint env sigma car rel cstr res = match cstr with @@ -505,7 +516,7 @@ let subterm all flags (s : strategy) : strategy = else let res = s env sigma arg (Typing.type_of env sigma arg) None evars in match res with - | Some None -> (None :: acc, evars, Some false) + | Some None -> (None :: acc, evars, if progress = None then Some false else progress) | Some (Some r) -> (Some r :: acc, r.rew_evars, Some true) | None -> (None :: acc, evars, progress)) ([], evars, success) args @@ -515,10 +526,9 @@ let subterm all flags (s : strategy) : strategy = | Some false -> Some None | Some true -> let args' = Array.of_list (List.rev args') in - let evarsref = ref evars' in - let (prf, (car, rel, c1, c2)) = resolve_morphism env sigma t m args args' cstr' evarsref in + let evars', prf, car, rel, c1, c2 = resolve_morphism env sigma t m args args' cstr' evars' in let res = { rew_car = ty; rew_rel = rel; rew_from = c1; - rew_to = c2; rew_prf = prf; rew_evars = !evarsref } in + rew_to = c2; rew_prf = prf; rew_evars = evars' } in Some (Some res) in if flags.on_morphisms then @@ -1113,14 +1123,15 @@ let build_morphism_signature m = | _ -> [] in aux t in - let t', sig_, evars = build_signature isevars env t cstrs None snd in + let evars, t', sig_, cstrs = build_signature !isevars env t cstrs None snd in + let _ = isevars := evars in let _ = List.iter (fun (ty, rel) -> Option.iter (fun rel -> let default = mkApp (Lazy.force default_relation, [| ty; rel |]) in ignore (Evarutil.e_new_evar isevars env default)) rel) - evars + cstrs in let morph = mkApp (Lazy.force proper_type, [| t; sig_; m |]) @@ -1132,15 +1143,14 @@ let build_morphism_signature m = let default_morphism sign m = let env = Global.env () in - let isevars = ref Evd.empty in let t = Typing.type_of env Evd.empty m in - let _, sign, evars = - build_signature isevars env t (fst sign) (snd sign) (fun (ty, rel) -> rel) + let evars, _, sign, cstrs = + build_signature Evd.empty env t (fst sign) (snd sign) (fun (ty, rel) -> rel) in let morph = mkApp (Lazy.force proper_type, [| t; sign; m |]) in - let mor = resolve_one_typeclass env !isevars morph in + let mor = resolve_one_typeclass env evars morph in mor, proper_projection mor morph let add_setoid binders a aeq t n = diff --git a/theories/Classes/Init.v b/theories/Classes/Init.v index a2a90978d..7d6e1de1e 100644 --- a/theories/Classes/Init.v +++ b/theories/Classes/Init.v @@ -19,7 +19,7 @@ Require Import Coq.Program.Basics. -Typeclasses Opaque id const flip compose arrow impl iff. +Typeclasses Opaque id const flip compose arrow impl iff not all. (** The unconvertible typeclass, to test that two objects of the same type are actually different. *) diff --git a/theories/Classes/Morphisms.v b/theories/Classes/Morphisms.v index 65d6687ea..6029b7cf1 100644 --- a/theories/Classes/Morphisms.v +++ b/theories/Classes/Morphisms.v @@ -1,4 +1,4 @@ -(* -*- coq-prog-name: "~/research/coq/trunk/bin/coqtop.byte"; coq-prog-args: ("-emacs-U" "-top" "Coq.Classes.Morphisms"); compile-command: "make -C ../.. -j3 TIME='time -p'" -*- *) +(* -*- coq-prog-name: "~/research/coq/trunk/bin/coqtop.byte"; coq-prog-args: ("-emacs-U" "-top" "Coq.Classes.Morphisms"); compile-command: "make -C ../.. TIME='time -p'" -*- *) (************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) (* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *) @@ -135,25 +135,18 @@ Proof. intros. apply sub. apply mor. Qed. -Instance proper_subrelation_proper : - Proper (subrelation ++> @eq _ ==> impl) (@Proper A). -Proof. reduce. subst. firstorder. Qed. - -(** We use an external tactic to manage the application of subrelation, which is otherwise - always applicable. We allow its use only once per branch. *) - -Inductive subrelation_done : Prop := did_subrelation : subrelation_done. +CoInductive apply_subrelation : Prop := do_subrelation. -Inductive normalization_done : Prop := did_normalization. - -Ltac subrelation_tac := - match goal with - | [ _ : subrelation_done |- _ ] => fail 1 - | [ |- @Proper _ _ _ ] => let H := fresh "H" in - set(H:=did_subrelation) ; eapply @subrelation_proper +Ltac proper_subrelation := + match goal with + [ H : apply_subrelation |- _ ] => clear H ; eapply @subrelation_proper end. -Hint Extern 5 (@Proper _ _ _) => subrelation_tac : typeclass_instances. +Hint Extern 4 (@Proper _ ?H _) => proper_subrelation : typeclass_instances. + +Instance proper_subrelation_proper : + Proper (subrelation ++> @eq _ ==> impl) (@Proper A). +Proof. reduce. subst. firstorder. Qed. (** Essential subrelation instances for [iff], [impl] and [pointwise_relation]. *) @@ -195,7 +188,7 @@ Program Instance flip_proper contravariant in the first argument, covariant in the second. *) Program Instance trans_contra_co_morphism - `(Transitive A R) : Proper (R --> R ++> impl) R. + `(Transitive A R) : Proper (R --> R ++> impl) R | 6. Next Obligation. Proof with auto. @@ -214,7 +207,7 @@ Program Instance trans_contra_inv_impl_morphism Qed. Program Instance trans_co_impl_morphism - `(Transitive A R) : Proper (R ==> impl) (R x) | 3. + `(Transitive A R) : Proper (R ++> impl) (R x) | 3. Next Obligation. Proof with auto. @@ -222,7 +215,7 @@ Program Instance trans_co_impl_morphism Qed. Program Instance trans_sym_co_inv_impl_morphism - `(PER A R) : Proper (R ==> inverse impl) (R x) | 2. + `(PER A R) : Proper (R ++> inverse impl) (R x) | 3. Next Obligation. Proof with auto. @@ -230,7 +223,7 @@ Program Instance trans_sym_co_inv_impl_morphism Qed. Program Instance trans_sym_contra_impl_morphism - `(PER A R) : Proper (R --> impl) (R x) | 2. + `(PER A R) : Proper (R --> impl) (R x) | 3. Next Obligation. Proof with auto. @@ -238,7 +231,7 @@ Program Instance trans_sym_contra_impl_morphism Qed. Program Instance per_partial_app_morphism - `(PER A R) : Proper (R ==> iff) (R x) | 1. + `(PER A R) : Proper (R ==> iff) (R x) | 2. Next Obligation. Proof with auto. @@ -252,7 +245,7 @@ Program Instance per_partial_app_morphism to get an [R y z] goal. *) Program Instance trans_co_eq_inv_impl_morphism - `(Transitive A R) : Proper (R ==> (@eq A) ==> inverse impl) R | 2. + `(Transitive A R) : Proper (R ==> (@eq A) ==> inverse impl) R | 3. Next Obligation. Proof with auto. @@ -261,7 +254,7 @@ Program Instance trans_co_eq_inv_impl_morphism (** Every Symmetric and Transitive relation gives rise to an equivariant morphism. *) -Program Instance PER_morphism `(PER A R) : Proper (R ==> R ==> iff) R | 1. +Program Instance PER_morphism `(PER A R) : Proper (R ==> R ==> iff) R | 2. Next Obligation. Proof with auto. @@ -320,14 +313,18 @@ Qed. Class ProperProxy {A} (R : relation A) (m : A) : Prop := proper_proxy : R m m. -Instance reflexive_proper_proxy - `(Reflexive A R) (x : A) : ProperProxy R x | 1. +Lemma eq_proper_proxy A (x : A) : ProperProxy (@eq A) x. +Proof. firstorder. Qed. + +Lemma reflexive_proper_proxy `(Reflexive A R) (x : A) : ProperProxy R x. Proof. firstorder. Qed. -Instance proper_proper_proxy - `(Proper A R x) : ProperProxy R x | 2. +Lemma proper_proper_proxy `(Proper A R x) : ProperProxy R x. Proof. firstorder. Qed. +Hint Extern 1 (ProperProxy _ _) => apply eq_proper_proxy || eapply @reflexive_proper_proxy : typeclass_instances. +(* Hint Extern 2 (ProperProxy ?R _) => not_evar R ; eapply @proper_proper_proxy : typeclass_instances. *) + (** [R] is Reflexive, hence we can build the needed proof. *) Lemma Reflexive_partial_app_morphism `(Proper (A -> B) (R ==> R') m, ProperProxy A R x) : @@ -338,6 +335,8 @@ Class Params {A : Type} (of : A) (arity : nat). Class PartialApplication. +CoInductive normalization_done : Prop := did_normalization. + Ltac partial_application_tactic := let rec do_partial_apps H m := match m with @@ -364,7 +363,6 @@ Ltac partial_application_tactic := do_partial H v' m in match goal with - | [ _ : subrelation_done |- _ ] => fail 1 | [ _ : normalization_done |- _ ] => fail 1 | [ _ : @Params _ _ _ |- _ ] => fail 1 | [ |- @Proper ?T _ (?m ?x) ] => @@ -424,8 +422,12 @@ Proof. firstorder. Qed. Lemma inverse2 `(subrelation A R R') : subrelation R (inverse (inverse R')). Proof. firstorder. Qed. -Hint Extern 1 (subrelation (flip _) _) => eapply @inverse1 : typeclass_instances. -Hint Extern 1 (subrelation _ (flip _)) => eapply @inverse2 : typeclass_instances. +Hint Extern 1 (subrelation (flip (flip _)) _) => eapply @inverse1 : typeclass_instances. +Hint Extern 1 (subrelation _ (flip (flip _))) => eapply @inverse2 : typeclass_instances. + +(** That's if and only if *) +Instance eq_subrelation `(Reflexive A R) : subrelation (@eq A) R. +Proof. simpl_relation. Qed. (** Once we have normalized, we will apply this instance to simplify the problem. *) @@ -446,22 +448,19 @@ Proof. apply H0. Qed. -Lemma proper_releq_proper `(Normalizes A R R', Proper _ R' m) : Proper R m. +Lemma proper_normalizes_proper `(Proper A R0 m, Normalizes A R0 R1) : Proper R1 m. Proof. - intros. - - pose proper as r. - pose normalizes as norm. - setoid_rewrite norm. + intros A R0 m H R' H'. + red in H, H'. setoid_rewrite <- H'. assumption. Qed. -Ltac proper_normalization := +Ltac proper_normalization := match goal with - | [ _ : subrelation_done |- _ ] => fail 1 | [ _ : normalization_done |- _ ] => fail 1 - | [ |- @Proper _ _ _ ] => let H := fresh "H" in - set(H:=did_normalization) ; eapply @proper_releq_proper + | [ _ : apply_subrelation |- _ ] => fail 1 + | [ |- @Proper _ ?R _ ] => let H := fresh "H" in + set(H:=did_normalization) ; eapply @proper_normalizes_proper end. Hint Extern 6 (@Proper _ _ _) => proper_normalization : typeclass_instances. @@ -472,11 +471,13 @@ Lemma reflexive_proper `{Reflexive A R} (x : A) : Proper R x. Proof. firstorder. Qed. +Lemma proper_eq A (x : A) : Proper (@eq A) x. +Proof. intros. apply reflexive_proper. Qed. + Ltac proper_reflexive := match goal with | [ _ : normalization_done |- _ ] => fail 1 - | [ _ : subrelation_done |- _ ] => fail 1 - | [ |- @Proper _ _ _ ] => eapply @reflexive_proper + | [ |- @Proper _ _ _ ] => apply proper_eq || eapply @reflexive_proper end. Hint Extern 7 (@Proper _ _ _) => proper_reflexive : typeclass_instances. diff --git a/theories/Classes/Morphisms_Prop.v b/theories/Classes/Morphisms_Prop.v index b62e7d413..1373e1952 100644 --- a/theories/Classes/Morphisms_Prop.v +++ b/theories/Classes/Morphisms_Prop.v @@ -21,7 +21,7 @@ Require Import Coq.Program.Tactics. (** Logical negation. *) Program Instance not_impl_morphism : - Proper (impl --> impl) not. + Proper (impl --> impl) not | 1. Program Instance not_iff_morphism : Proper (iff ++> iff) not. @@ -29,7 +29,7 @@ Program Instance not_iff_morphism : (** Logical conjunction. *) Program Instance and_impl_morphism : - Proper (impl ==> impl ==> impl) and. + Proper (impl ==> impl ==> impl) and | 1. Program Instance and_iff_morphism : Proper (iff ==> iff ==> iff) and. @@ -37,7 +37,7 @@ Program Instance and_iff_morphism : (** Logical disjunction. *) Program Instance or_impl_morphism : - Proper (impl ==> impl ==> impl) or. + Proper (impl ==> impl ==> impl) or | 1. Program Instance or_iff_morphism : Proper (iff ==> iff ==> iff) or. @@ -62,7 +62,7 @@ Program Instance ex_iff_morphism {A : Type} : Proper (pointwise_relation A iff = Qed. Program Instance ex_impl_morphism {A : Type} : - Proper (pointwise_relation A impl ==> impl) (@ex A). + Proper (pointwise_relation A impl ==> impl) (@ex A) | 1. Next Obligation. Proof. @@ -71,7 +71,7 @@ Program Instance ex_impl_morphism {A : Type} : Qed. Program Instance ex_inverse_impl_morphism {A : Type} : - Proper (pointwise_relation A (inverse impl) ==> inverse impl) (@ex A). + Proper (pointwise_relation A (inverse impl) ==> inverse impl) (@ex A) | 1. Next Obligation. Proof. @@ -89,7 +89,7 @@ Program Instance all_iff_morphism {A : Type} : Qed. Program Instance all_impl_morphism {A : Type} : - Proper (pointwise_relation A impl ==> impl) (@all A). + Proper (pointwise_relation A impl ==> impl) (@all A) | 1. Next Obligation. Proof. @@ -98,7 +98,7 @@ Program Instance all_impl_morphism {A : Type} : Qed. Program Instance all_inverse_impl_morphism {A : Type} : - Proper (pointwise_relation A (inverse impl) ==> inverse impl) (@all A). + Proper (pointwise_relation A (inverse impl) ==> inverse impl) (@all A) | 1. Next Obligation. Proof. diff --git a/theories/Classes/RelationClasses.v b/theories/Classes/RelationClasses.v index 88fba1a30..681bd90a9 100644 --- a/theories/Classes/RelationClasses.v +++ b/theories/Classes/RelationClasses.v @@ -43,7 +43,9 @@ Class Reflexive {A} (R : relation A) := reflexivity : forall x, R x x. Class Irreflexive {A} (R : relation A) := - irreflexivity :> Reflexive (complement R). + irreflexivity : Reflexive (complement R). + +Hint Extern 1 (Reflexive (complement _)) => eapply @irreflexivity : typeclasses_instances. Class Symmetric {A} (R : relation A) := symmetry : forall x y, R x y -> R y x. @@ -70,8 +72,10 @@ Hint Extern 4 => solve_relation : relations. (** We can already dualize all these properties. *) -Program Instance flip_Reflexive `(Reflexive A R) : Reflexive (flip R) := - reflexivity (R:=R). +Program Lemma flip_Reflexive `(Reflexive A R) : Reflexive (flip R). +Proof. tauto. Qed. + +Hint Extern 3 (Reflexive (flip _)) => apply flip_Reflexive : typeclass_instances. Program Instance flip_Irreflexive `(Irreflexive A R) : Irreflexive (flip R) := irreflexivity (R:=R). |