10 exception Backtrack of string
13 let _very_verbose = true;;
14 (** Display measure of every term when printing problem *)
15 let _measure_of_terms = false;;
18 if _very_verbose then prerr_endline s
24 ; conv: i_var list (* the inerts that must converge *)
25 ; sigma: (int * nf) list (* the computed substitution *)
26 ; initialSpecialK: int
28 ; var_names : string list (* names of the original free variables *)
31 let label_of_problem {label} = label;;
33 let string_of_var l x =
36 with Failure "nth" -> "`" ^ string_of_int x
38 let string_of_term p t = print ~l:p.var_names (t :> nf);;
41 let first args p var f =
42 let rec aux k = function
44 raise (Backtrack ("no more alternatives for " ^ string_of_var p.var_names var))
48 prerr_endline (">>>>>> BACKTRACK (reason: " ^ s ^") measure=$ ");
49 (* prerr_endline("Now trying var="^string_of_var p.var_names var^" i="^string_of_int (i+1)); *)
50 if k = 0 then aux p.initialSpecialK is else aux (k-1) ii
51 in aux p.initialSpecialK args
53 let all_terms p = p.div :: p.conv ;;
55 let measure_of_term, measure_of_terms =
56 let rec aux = function
57 | `Bottom | `Pacman -> 0
58 | `Var(_,ar) -> if ar = min_int then 0 else max 0 ar (*assert (ar >= 0); ar*)
60 | `I(v,args) -> aux (`Var v) + aux_many (Listx.to_list args :> nf list)
61 and aux_many tms = List.fold_right ((+) ++ aux) tms 0 in
62 (fun t -> aux (t :> nf)), (fun l -> aux_many (l :> nf list))
65 let sum_arities p = measure_of_terms (all_terms p)
67 let problem_measure p = sum_arities p;;
68 let string_of_measure = string_of_int;;
70 let string_of_problem label ({freshno; div; conv} as p) =
71 let aux_measure_terms t = if _measure_of_terms then "(" ^ string_of_int (measure_of_term t) ^ ") " else "" in
72 let l = p.var_names in
75 "# DISPLAY PROBLEM (" ^ label ^ ") " ^ "measure=" ^ string_of_measure (problem_measure p);
78 "D " ^ aux_measure_terms div ^ print ~l (div :> nf);
80 @ List.map (fun t -> "C " ^ aux_measure_terms t ^ print ~l (t :> nf)) conv
85 let failwithProblem p reason =
86 print_endline (string_of_problem "FAIL" p);
90 let make_fresh_var p arity =
91 let freshno = p.freshno + 1 in
92 {p with freshno}, `Var(freshno,arity)
95 let make_fresh_vars p arities =
97 (fun arity (p, vars) -> let p, var = make_fresh_var p arity in p, var::vars)
104 let rec aux x = let x' = f x in if x <> x' then aux x' else x in aux
108 let subst_in_problem x inst ({div; conv} as p) =
109 prerr_endline ("# INST0: " ^ string_of_var p.var_names x ^ " := " ^ string_of_term p inst);
110 let div = subst false false x inst (div :> nf) in
111 let conv = List.map (subst false false x inst) (conv :> nf list) in
112 let conv = Util.filter_map (function `Lam _ | `Pacman -> None | `Bottom -> raise (Backtrack "bottom in conv") | #i_var as t -> Some t) conv in
114 | `Lam _ | `Pacman | `Var _ -> raise (Backtrack "lam in div")
115 | `Bottom -> `Finished p
116 | `I _ as div -> `Continue {p with div; conv}
119 exception Dangerous;;
121 let arity_of arities hd =
122 let pos,_,nargs = List.find (fun (_,hd',_) -> hd=hd') arities in
123 nargs + if pos = -1 then - 1 else 0
126 (* let rec dangerous arities showstoppers =
132 | `Match(t,_,liftno,bs,args) ->
133 (* CSC: XXX partial dependency on the encoding *)
135 `N _ -> List.iter (dangerous arities showstoppers) args
136 | `Match _ as t -> dangerous arities showstoppers t ; List.iter (dangerous arities showstoppers) args
137 | `Var(x,_) -> dangerous_inert arities showstoppers x args 2
138 | `I((x,_),args') -> dangerous_inert arities showstoppers x (Listx.to_list args' @ args) 2
140 | `I((k,_),args) -> dangerous_inert arities showstoppers k (Listx.to_list args) 0
142 and dangerous_inert arities showstoppers k args more_args =
143 List.iter (dangerous arities showstoppers) args ;
144 if List.mem k showstoppers then raise Dangerous else
146 let arity = arity_of arities k in
147 if List.length args + more_args > arity then raise Dangerous else ()
151 (* cut & paste from above *)
152 let rec dangerous_conv p arities showstoppers =
158 | `Match(t,_,liftno,bs,args) -> (
159 (* CSC: XXX partial dependency on the encoding *)
161 | `N _ -> List.iter (dangerous_conv p arities showstoppers) args
162 | `Match _ as t -> dangerous_conv p arities showstoppers t; List.iter (dangerous_conv p arities showstoppers) args
163 | `Var(x,_) -> dangerous_inert_conv p arities showstoppers x [] args 2
164 | `I((x,_),args') -> dangerous_inert_conv p arities showstoppers x (Listx.to_list args') args 2
165 ) with TriggerMatchReduction x -> (
166 match Util.find_opt (fun (n, t) -> if hd_of (List.nth p.ps n) = Some x then Some t else None) !bs with
170 | `Bottom -> raise Dangerous
171 | #nf_nob as t -> dangerous_conv p arities showstoppers t
175 | `I((k,_),args) -> dangerous_inert_conv p arities showstoppers k (Listx.to_list args) [] 0
177 and dangerous_inert_conv p arities showstoppers k args match_args more_args =
178 let all_args = args @ match_args in
179 List.iter (dangerous_conv p arities showstoppers) all_args;
180 let all_args = (all_args :> nf list) in
181 if List.mem k showstoppers then raise Dangerous else
183 let arity = arity_of arities k in
184 prerr_endline ("dangerous_inert_conv: ar=" ^ string_of_int arity ^ " k="^string_of_var p.var_names k ^ " listlenargs=" ^ (string_of_int (List.length args)) ^ " more_args=" ^ string_of_int more_args);
185 if more_args > 0 (* match argument*) && List.length args = arity then raise (TriggerMatchReduction k)
186 else if List.length all_args + more_args > arity then raise Dangerous else ()
190 (* inefficient algorithm *)
191 let rec edible p arities showstoppers =
192 let rec aux f showstoppers tms = function
194 | x::xs when List.exists (fun y -> hd_of x = Some y) showstoppers ->
195 (* se la testa di x e' uno show-stopper *)
196 let new_showstoppers = sort_uniq (showstoppers @ free_vars (x :> nf)) in
197 (* aggiungi tutte le variabili libere di x *)
198 if List.length showstoppers <> List.length new_showstoppers then
199 aux f new_showstoppers tms tms
201 aux f showstoppers tms xs
204 None -> aux f showstoppers tms xs
207 f showstoppers (x :> nf_nob) ;
208 aux f showstoppers tms xs
211 aux f (sort_uniq (h::showstoppers)) tms tms
213 let showstoppers = sort_uniq (aux (dangerous arities) showstoppers p.ps p.ps) in
214 let dangerous_conv = sort_uniq (aux (dangerous_conv p arities) showstoppers p.conv p.conv) in
216 (* prerr_endline ("dangerous_conv lenght:" ^ string_of_int (List.length dangerous_conv));
217 List.iter (fun l -> prerr_endline (String.concat " " (List.map (string_of_var p.var_names) l))) dangerous_conv; *)
219 let showstoppers' = showstoppers @ dangerous_conv in
220 let showstoppers' = sort_uniq (match p.div with
221 | None -> showstoppers'
223 if List.exists ((=) (hd_of_i_var div)) showstoppers'
224 then showstoppers' @ free_vars (div :> nf) else showstoppers') in
225 if showstoppers <> showstoppers' then edible p arities showstoppers' else showstoppers', dangerous_conv
228 let precompute_edible_data {ps; div} xs =
229 let aux t = match t with `Var _ -> 0 | `I(_, args) -> Listx.length args | `N _ -> assert false in
230 (fun l -> match div with
232 | Some div -> (-1, hd_of_i_var div, aux div) :: l)
234 let i, tm = Util.findi (fun y -> hd_of y = Some hd) ps in
239 (** Returns (p, showstoppers_step, showstoppers_eat) where:
240 - showstoppers_step are the heads occurring twice
241 in the same discriminating set
242 - showstoppers_eat are the heads in ps having different number
244 let critical_showstoppers p =
245 let p = super_simplify p in
246 let hd_of_div = match p.div with None -> [] | Some t -> [hd_of_i_var t] in
247 let showstoppers_step =
248 concat_map (fun bs ->
249 let heads = List.map (fun (i,_) -> List.nth p.ps i) !bs in
250 let heads = List.sort compare (hd_of_div @ filter_map hd_of heads) in
251 snd (split_duplicates heads)
253 if List.exists (fun t -> [hd_of t] = List.map (fun x -> Some x) hd_of_div) p.conv
254 then hd_of_div else [] in
255 let showstoppers_step = sort_uniq showstoppers_step in
256 let showstoppers_eat =
257 let heads_and_arities =
258 List.sort (fun (k,_) (h,_) -> compare k h)
259 (filter_map (function `Var(k,_) -> Some (k,0) | `I((k,_),args) -> Some (k,Listx.length args) | _ -> None ) p.ps) in
260 let rec multiple_arities =
264 | (x,i)::(y,j)::tl when x = y && i <> j ->
265 x::multiple_arities tl
266 | _::tl -> multiple_arities tl in
267 multiple_arities heads_and_arities in
269 let showstoppers_eat = sort_uniq showstoppers_eat in
270 let showstoppers_eat = List.filter
271 (fun x -> not (List.mem x showstoppers_step))
273 List.iter (fun v -> prerr_endline ("DANGEROUS STEP: " ^ (string_of_var p.var_names) v)) showstoppers_step;
274 List.iter (fun v -> prerr_endline ("DANGEROUS EAT: " ^ (string_of_var p.var_names) v)) showstoppers_eat;
275 p, showstoppers_step, showstoppers_eat
279 let ({ps} as p), showstoppers_step, showstoppers_eat = critical_showstoppers p in
280 let showstoppers = showstoppers_step @ showstoppers_eat in
281 let heads = List.sort compare (filter_map hd_of ps) in
282 let arities = precompute_edible_data p (uniq heads) in
283 let inedible, showstoppers_conv = edible p arities showstoppers in
284 let l = List.filter (fun (_,hd,_) -> not (List.mem hd inedible)) arities in
286 List.fold_left (fun p (pos,hd,nargs) -> if pos = -1 then p else
288 let inst = make_lams v nargs in
289 prerr_endline ("# [INST_IN_EAT] eating: " ^ string_of_var p.var_names hd ^ " := " ^ string_of_term p inst);
290 { p with sigma = p.sigma @ [hd,inst] }
292 (* to avoid applied numbers in safe positions that
293 trigger assert failures subst_in_problem x inst p*)
297 let j,_,_ = List.find (fun (_,hd,_) -> hd_of t = Some hd) l in
301 let p = match p.div with
304 if List.mem (hd_of_i_var div) inedible
307 let n = match div with `I(_,args) -> Listx.length args | `Var _ -> 0 in
308 let x = hd_of_i_var div in
309 let inst = make_lams `Bottom n in
310 subst_in_problem x inst p in
311 (*let dangerous_conv = showstoppers_conv in
312 prerr_endline ("dangerous_conv lenght:" ^ string_of_int (List.length dangerous_conv));
313 List.iter (fun l -> prerr_endline (String.concat " " (List.map (string_of_var p.var_names) l))) dangerous_conv; *)
315 List.map (function t ->
317 if let hd = hd_of t in hd <> None && not (List.mem (Util.option_get hd) showstoppers_conv) then t else (
318 (match t with | `Var _ -> raise Not_found | _ -> ());
319 let _ = List.find (fun h -> hd_of t = Some h) inedible in
321 with Not_found -> match hd_of t with
322 | None -> assert (t = convergent_dummy); t
324 prerr_endline ("FREEZING " ^ string_of_var p.var_names h);
332 match List.nth ps n with
337 let old_conv = p.conv in
338 let p = { p with ps; conv } in
339 if l <> [] || old_conv <> conv
340 then prerr_endline (string_of_problem "eat" p);
341 if List.for_all (function `N _ -> true | _ -> false) ps && p.div = None then
347 let safe_arity_of_var p x =
348 (* Compute the minimum number of arguments when x is in head
349 position at p.div or p.ps *)
351 | `Var(y,_) -> if x = y then 0 else max_int
352 | `I((y,_),args) -> if x = y then Listx.length args else max_int
354 let tms = ((match p.div with None -> [] | Some t -> [(t :> i_n_var)]) @ p.ps) in
355 List.fold_left (fun acc t -> Pervasives.min acc (aux t)) max_int tms
358 let instantiate p x perm n =
359 (* let n = (prerr_endline ("WARNING: using constant initialSpecialK=" ^ string_of_int p.initialSpecialK)); p.initialSpecialK in *)
360 let arities = Array.to_list (Array.make (n+1) min_int) in
361 let p,vars = make_fresh_vars p arities in
362 (* manual lifting of vars by perm in next line *)
363 let vars = List.map (function `Var (n,ar) -> `Var (n+perm,ar)) vars in
364 (* other_vars are the variables which are delayed and re-applied to the match *)
365 let other_vars = Array.mapi (fun n () -> `Var(n+1,min_int)) (Array.make (perm-1) ()) in
366 let other_vars = Array.to_list other_vars in
367 (* 666, since it will be replaced anyway during subst: *)
368 (* let inst = `Match(`I((0,min_int),args),(x,-666),perm,bs,other_vars) in *)
369 let inst = `I((0,min_int),Listx.from_list (vars @ other_vars)) in (* FIXME *)
370 (* Add a number of 'perm' leading lambdas *)
371 let inst = Array.fold_left (fun t () -> `Lam(false, t)) inst (Array.make perm ()) in
372 let p = {p with sigma=(x,inst)::p.sigma} in
373 subst_in_problem x inst p
376 let compute_special_k tms =
377 let rec aux k (t: nf) = Pervasives.max k (match t with
378 | `Lam(b,t) -> aux (k + if b then 1 else 0) t
379 | `I(n, tms) -> Listx.max (Listx.map (aux 0) (tms :> nf Listx.listx))
384 let rec aux' top t = match t with
385 | `Lam(_,t) -> aux' false t
386 | `I((_,ar), tms) -> max ar
387 (Listx.max (Listx.map (aux' false) (tms :> nf Listx.listx)))
391 Listx.max (Listx.map (aux 0) tms) + Listx.max (Listx.map (aux' true) tms)
394 (* let choose_step p =
395 let p, showstoppers_step, showstoppers_eat = critical_showstoppers p in
397 match showstoppers_step, showstoppers_eat with
399 prerr_endline ("INSTANTIATING (critical eat) : " ^ string_of_var p.var_names y); y
401 prerr_endline ("INSTANTIATING (critical step): " ^ string_of_var p.var_names x); x
404 (* Choose only variables still alive (with arity > 0) *)
405 List.sort compare (filter_map (
406 fun t -> match t with `Var _ -> None | x -> if arity_of_hd x <= 0 then None else hd_of x
407 ) ((match p.div with Some t -> [(t :> i_n_var)] | _ -> []) @ p.ps)) in
411 fst (List.find (((<) 0) ++ snd) (concat_map free_vars' (p.conv :> nf list)))
413 Not_found -> assert false)
415 prerr_endline ("INSTANTIATING TO EAT " ^ string_of_var p.var_names x);
417 let arity_of_x = Util.option_get (max_arity_tms x (all_terms p)) in
418 let safe_arity_of_x = safe_arity_of_var p x in
419 x, min arity_of_x safe_arity_of_x
422 let intersect l1 l2 =
423 let rec aux n l1 l2 = match l1, l2 with
425 | _, [] -> assert false
426 | x::xs, y::ys -> if x <> y then n :: aux (n+1) xs ys else aux (n+1) xs ys
427 in aux 1 (Listx.to_list l1) (Listx.to_list l2);;
429 exception Difference of int list;;
431 let hd, args, n = match p.div with `Var _ -> assert false | `I((x,_), l) -> x, l, Listx.length l in
432 let rec aux = function
433 | `Var _ | `Lam _ -> ()
434 | `Pacman | `Bottom -> assert false
437 if Listx.length args' >= n then
438 (let diff = intersect args args' in
439 raise (if diff = [] then Backtrack "div in conv" else Difference diff));
440 List.iter aux ((Listx.to_list args') :> nf list) in
442 List.iter aux (p.conv :> nf list) ;
443 `Finished {p with sigma=(hd,make_lams `Bottom n)::p.sigma}
445 Difference l -> `Continue (hd, l)
449 prerr_endline (string_of_problem "auto_eat" p);
450 (* prerr_endline "{{{{{{{{ Computing measure before auto_instantiate }}}}}}"; *)
452 | `Finished p -> prerr_endline "finished"; p
453 | `Continue (x,positions) ->
454 let m = problem_measure p in
455 first positions p x (fun p j k ->
456 match instantiate p x j k with
458 (* prerr_endline "{{{{{{{{ Computing measure inafter auto_instantiate }}}}}}"; *)
459 let delta = problem_measure p - m in
463 ("Measure did not decrease (+=" ^ string_of_int delta ^ ")"))
464 else prerr_endline ("$ Measure decreased: " ^ string_of_int delta);
469 (******************************************************************************)
470 let env_of_sigma freshno sigma =
477 e,Pure.lift (-n-1) (snd (List.find (fun (i,_) -> i = n) sigma)),[]
479 Not_found -> ([],Pure.V n,[]))::e
482 (* ************************************************************************** *)
485 | `CompleteSeparable of string
486 | `CompleteUnseparable of string
491 `Complete | `Uncomplete
493 | `Separable of (int * Num.nf) list
494 | `Unseparable of string
499 Console.print_hline();
500 prerr_endline (string_of_problem "main" p);
501 let p_finale = auto_eat p in
502 let freshno,sigma = p_finale.freshno, p_finale.sigma in
503 prerr_endline ("------- <DONE> ------ measure=. \n ");
504 List.iter (fun (x,inst) -> prerr_endline (string_of_var p_finale.var_names x ^ " := " ^ string_of_term p_finale inst)) sigma;
506 prerr_endline "---------<PURE>---------";
507 let scott_of_nf t = ToScott.scott_of_nf (t :> nf) in
508 let div = scott_of_nf p.div in
509 let conv = List.map scott_of_nf p.conv in
511 let sigma' = List.map (fun (x,inst) -> x, ToScott.scott_of_nf inst) sigma in
512 let e' = env_of_sigma freshno sigma' in
514 prerr_endline "--------<REDUCE>---------";
515 (* print_endline (Pure.print div); *)
516 let t = Pure.mwhd (e',div,[]) in
517 prerr_endline ("*:: " ^ (Pure.print t));
520 (* verbose ("_::: " ^ (Pure.print n)); *)
521 let t = Pure.mwhd (e',n,[]) in
522 verbose ("_:: " ^ (Pure.print t));
525 prerr_endline "-------- </DONE> --------";
529 let solve (p, todo) =
530 let completeness, to_run =
532 | `CompleteUnseparable s -> `Complete, `False s
533 | `CompleteSeparable _ -> `Complete, `True
534 | `Uncomplete -> `Uncomplete, `True in
535 completeness, match to_run with
536 | `False s -> `Unseparable s
541 Backtrack _ -> `Unseparable "backtrack"
544 let no_bombs_pacmans p =
545 not (List.exists (eta_subterm `Bottom) p.conv)
546 && not (eta_subterm `Pacman p.div)
550 if not (List.exists (eta_subterm p.div) p.conv) && no_bombs_pacmans p
551 then `CompleteSeparable "no bombs, pacmans and div"
552 (* il check seguente e' spostato nel parser e lancia un ParsingError *)
553 (* else if false (* TODO bombs or div fuori da lambda in ps@conv *)
554 then `CompleteUnseparable "bombs or div fuori da lambda in ps@conv" *)
558 let problem_of (label, div, conv, var_names) =
559 (* TODO: replace div with bottom in problem??? *)
560 let all_tms = div :: conv in
561 if all_tms = [] then failwith "problem_of: empty problem";
562 let initialSpecialK = compute_special_k (Listx.from_list (all_tms :> nf list)) in
563 let freshno = List.length var_names in
565 let p = {freshno; div; conv; sigma; initialSpecialK; var_names; label} in