1 (* Copyright (C) 2003-2005, HELM Team.
3 * This file is part of HELM, an Hypertextual, Electronic
4 * Library of Mathematics, developed at the Computer Science
5 * Department, University of Bologna, Italy.
7 * HELM is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * HELM is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with HELM; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 * For details, see the HELM World-Wide-Web page,
23 * http://cs.unibo.it/helm/.
28 module DTI = DoubleTypeInference
29 module TC = CicTypeChecker
31 module UM = UriManager
32 module Obj = LibraryObjects
33 module HObj = HelmLibraryObjects
36 module E = CicEnvironment
38 module Cl = CicClassify
39 module T = ProceduralTypes
40 module Cn = ProceduralConversion
43 sorts : (C.id, A.sort_kind) Hashtbl.t;
44 types : (C.id, A.anntypes) Hashtbl.t;
46 max_depth: int option;
53 (* helpers ******************************************************************)
57 let comp f g x = f (g x)
59 let cic = D.deannotate_term
61 let split2_last l1 l2 =
63 let n = pred (List.length l1) in
64 let before1, after1 = T.list_split n l1 in
65 let before2, after2 = T.list_split n l2 in
66 before1, before2, List.hd after1, List.hd after2
67 with Invalid_argument _ -> failwith "A2P.split2_last"
69 let string_of_head = function
71 | C.AConst _ -> "const"
72 | C.AMutInd _ -> "mutind"
73 | C.AMutConstruct _ -> "mutconstruct"
77 | C.ALambda _ -> "lambda"
78 | C.ALetIn _ -> "letin"
80 | C.ACoFix _ -> "cofix"
83 | C.AMutCase _ -> "mutcase"
85 | C.AImplicit _ -> "implict"
87 let clear st = {st with intros = []; ety = None}
89 let next st = {(clear st) with depth = succ st.depth}
92 if st.ety = None then {st with ety = ety} else st
94 let add st entry intro ety =
95 let st = set_ety st ety in
96 {st with context = entry :: st.context; intros = intro :: st.intros}
100 let msg = Printf.sprintf "Depth %u: " st.depth in
101 match st.max_depth with
103 | Some d -> if st.depth < d then true, msg else false, "DEPTH EXCEDED: "
104 with Invalid_argument _ -> failwith "A2P.test_depth"
106 let is_rewrite_right = function
107 | C.AConst (_, uri, []) ->
108 UM.eq uri HObj.Logic.eq_ind_r_URI || Obj.is_eq_ind_r_URI uri
111 let is_rewrite_left = function
112 | C.AConst (_, uri, []) ->
113 UM.eq uri HObj.Logic.eq_ind_URI || Obj.is_eq_ind_URI uri
116 let get_ind_name uri tno xcno =
118 let ts = match E.get_obj Un.empty_ugraph uri with
119 | C.InductiveDefinition (ts, _, _,_), _ -> ts
122 let tname, cs = match List.nth ts tno with
123 | (name, _, _, cs) -> name, cs
127 | Some cno -> fst (List.nth cs (pred cno))
128 with Invalid_argument _ -> failwith "A2P.get_ind_name"
130 let get_inner_types st v =
132 let id = Ut.id_of_annterm v in
133 try match Hashtbl.find st.types id with
134 | {A.annsynthesized = st; A.annexpected = Some et} -> Some (st, et)
135 | {A.annsynthesized = st; A.annexpected = None} -> Some (st, st)
136 with Not_found -> None
137 with Invalid_argument _ -> failwith "A2P.get_inner_types"
139 let get_inner_sort st v =
141 let id = Ut.id_of_annterm v in
142 try Hashtbl.find st.sorts id
143 with Not_found -> `Type (CicUniv.fresh())
144 with Invalid_argument _ -> failwith "A2P.get_sort"
146 (* proof construction *******************************************************)
148 let unused_premise = "UNUSED"
150 let defined_premise = "DEFINED"
152 let assumed_premise = "ASSUMED"
154 let expanded_premise = "EXPANDED"
157 let ty = C.AImplicit ("", None) in
158 let name i = Printf.sprintf "%s%u" expanded_premise i in
159 let lambda i t = C.ALambda ("", C.Name (name i), ty, t) in
160 let arg i n = T.mk_arel (n - i) (name i) in
162 if i >= n then f, a else aux (succ i) (comp f (lambda i)) (arg i n :: a)
164 let absts, args = aux 0 id [] in
165 match Cn.lift 1 n t with
166 | C.AAppl (id, ts) -> absts (C.AAppl (id, ts @ args))
167 | t -> absts (C.AAppl ("", t :: args))
169 let appl_expand n = function
170 | C.AAppl (id, ts) ->
171 let before, after = T.list_split (List.length ts + n) ts in
172 C.AAppl ("", C.AAppl (id, before) :: after)
175 let get_intro name t =
178 | C.Anonymous -> unused_premise
180 if DTI.does_not_occur 1 (cic t) then unused_premise else s
181 with Invalid_argument _ -> failwith "A2P.get_intro"
183 let mk_intros st script =
185 if st.intros = [] then script else
186 let count = List.length st.intros in
187 let p0 = T.Whd (count, "") in
188 let p1 = T.Intros (Some count, List.rev st.intros, "") in
190 | Some ety when Cn.need_whd count ety -> p0 :: p1 :: script
192 with Invalid_argument _ -> failwith "A2P.mk_intros"
194 let rec mk_atomic st dtext what =
195 if T.is_atomic what then [], what else
196 let name = defined_premise in
197 mk_fwd_proof st dtext name what, T.mk_arel 0 name
199 and mk_fwd_rewrite st dtext name tl direction =
200 let what, where = List.nth tl 5, List.nth tl 3 in
201 let rewrite premise =
202 let script, what = mk_atomic st dtext what in
203 T.Rewrite (direction, what, Some (premise, name), dtext) :: script
206 | C.ARel (_, _, _, binder) -> rewrite binder
208 assert (get_inner_sort st where = `Prop);
209 let pred, old = List.nth tl 2, List.nth tl 1 in
210 let pred_name = defined_premise in
211 let pred_text = "extracted" in
212 let p1 = T.LetIn (pred_name, pred, pred_text) in
213 let cut_name = assumed_premise in
214 let cut_type = C.AAppl ("", [T.mk_arel 0 pred_name; old]) in
216 let p2 = T.Cut (cut_name, cut_type, cut_text) in
217 let qs = [rewrite cut_name; mk_proof (next st) where] in
218 [T.Branch (qs, ""); p2; p1]
220 and mk_fwd_proof st dtext name = function
221 | C.AAppl (_, hd :: tl) as v ->
222 if is_rewrite_right hd then mk_fwd_rewrite st dtext name tl true else
223 if is_rewrite_left hd then mk_fwd_rewrite st dtext name tl false else
224 begin match get_inner_types st v with
226 let qs = [[T.Id ""]; mk_proof (next st) v] in
227 [T.Branch (qs, ""); T.Cut (name, ity, dtext)]
229 let ty, _ = TC.type_of_aux' [] st.context (cic hd) Un.empty_ugraph in
230 let (classes, rc) as h = Cl.classify st.context ty in
231 let text = Printf.sprintf "%u %s" (List.length classes) (Cl.to_string h) in
232 [T.LetIn (name, v, dtext ^ text)]
235 [T.LetIn (name, v, dtext)]
237 and mk_proof st = function
238 | C.ALambda (_, name, v, t) as what ->
239 let entry = Some (name, C.Decl (cic v)) in
240 let intro = get_intro name t in
241 let ety = match get_inner_types st what with
242 | Some (_, ety) -> Some ety
245 mk_proof (add st entry intro ety) t
246 | C.ALetIn (_, name, v, t) as what ->
247 let proceed, dtext = test_depth st in
248 let script = if proceed then
249 let entry = Some (name, C.Def (cic v, None)) in
250 let intro = get_intro name t in
251 let q = mk_proof (next (add st entry intro None)) t in
252 List.rev_append (mk_fwd_proof st dtext intro v) q
254 [T.Apply (what, dtext)]
257 | C.ARel _ as what ->
258 let _, dtext = test_depth st in
259 let text = "assumption" in
260 let script = [T.Apply (what, dtext ^ text)] in
262 | C.AMutConstruct _ as what ->
263 let _, dtext = test_depth st in
264 let script = [T.Apply (what, dtext)] in
266 | C.AAppl (_, hd :: tl) as t ->
267 let proceed, dtext = test_depth st in
268 let script = if proceed then
269 let ty, _ = TC.type_of_aux' [] st.context (cic hd) Un.empty_ugraph in
270 let (classes, rc) as h = Cl.classify st.context ty in
271 let decurry = List.length classes - List.length tl in
272 if decurry < 0 then mk_proof (clear st) (appl_expand decurry t) else
273 if decurry > 0 then mk_proof (clear st) (eta_expand decurry t) else
274 let synth = Cl.S.singleton 0 in
275 let text = Printf.sprintf "%u %s" (List.length classes) (Cl.to_string h) in
277 | Some (i, j) when i > 1 && i <= List.length classes ->
278 let classes, tl, _, what = split2_last classes tl in
279 let script, what = mk_atomic st dtext what in
280 let synth = Cl.S.add 1 synth in
281 let qs = mk_bkd_proofs (next st) synth classes tl in
282 if is_rewrite_right hd then
284 [T.Rewrite (false, what, None, dtext); T.Branch (qs, "")]
285 else if is_rewrite_left hd then
287 [T.Rewrite (true, what, None, dtext); T.Branch (qs, "")]
289 let using = Some hd in
291 [T.Elim (what, using, dtext ^ text); T.Branch (qs, "")]
293 let qs = mk_bkd_proofs (next st) synth classes tl in
294 let script, hd = mk_atomic st dtext hd in
296 [T.Apply (hd, dtext ^ text); T.Branch (qs, "")]
302 let text = Printf.sprintf "%s: %s" "UNEXPANDED" (string_of_head t) in
303 let script = [T.Note text] in
306 and mk_bkd_proofs st synth classes ts =
308 let _, dtext = test_depth st in
310 if Cl.overlaps synth inv then None else
311 if Cl.S.is_empty inv then Some (mk_proof st v) else
312 Some [T.Apply (v, dtext ^ "dependent")]
314 T.list_map2_filter aux classes ts
315 with Invalid_argument _ -> failwith "A2P.mk_bkd_proofs"
317 (* object costruction *******************************************************)
319 let is_theorem pars =
320 List.mem (`Flavour `Theorem) pars || List.mem (`Flavour `Fact) pars ||
321 List.mem (`Flavour `Remark) pars || List.mem (`Flavour `Lemma) pars
323 let mk_obj st = function
324 | C.AConstant (_, _, s, Some v, t, [], pars) when is_theorem pars ->
325 let ast = mk_proof (set_ety st (Some t)) v in
326 let count = T.count_steps 0 ast in
327 let text = Printf.sprintf "tactics: %u" count in
328 T.Theorem (s, t, text) :: ast @ [T.Qed ""]
330 failwith "not a theorem"
332 (* interface functions ******************************************************)
334 let acic2procedural ~ids_to_inner_sorts ~ids_to_inner_types ?depth prefix aobj =
336 sorts = ids_to_inner_sorts;
337 types = ids_to_inner_types;
345 HLog.debug "Level 2 transformation";
346 let steps = mk_obj st aobj in
347 HLog.debug "grafite rendering";
348 List.rev (T.render_steps [] steps)