Source file matching.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
open Basic
open Term
open Dtree
open Ac
let d_matching = Debug.register_flag "Matching"
exception NotUnifiable
exception NotSolvable
type te = term Lazy.t
type status = Unsolved | Solved of te | Partly of ac_ident * te list
type matching_problem = {
eq_problems : te eq_problem list array;
ac_problems : te list ac_problem list;
status : status array;
arities : int array;
}
let solve_miller (var : miller_var) (te : term) : term =
let depth = var.depth in
let arity = var.arity in
let mapping = var.mapping in
let subst l x n k =
mk_DB l x
(if n >= k + depth then n - depth + arity
else
let n' = mapping.(n - k) in
if n' < 0 then raise NotUnifiable else n' + k)
in
Subst.apply_subst subst 0 te
let solve (args : miller_var) (te : term) : term =
if args.arity = 0 then
try Subst.unshift args.depth te
with Subst.UnshiftExn -> raise NotUnifiable
else solve_miller args te
let apply_sol (sol : term) (args : miller_var) : term =
let vars_ar = Array.of_list args.vars in
let subst l x n k =
mk_DB l x
(if n - k < args.arity then vars_ar.(args.arity - 1 - n + k) + k else n)
in
Subst.apply_subst subst 0 sol
module type Reducer = sig
val snf : Signature.t -> term -> term
val whnf : Signature.t -> term -> term
val are_convertible : Signature.t -> term -> term -> bool
val constraint_convertibility :
Rule.constr -> Rule.rule_name -> Signature.t -> term -> term -> bool
end
module type Matcher = sig
val solve_problem :
Rule.rule_name ->
Signature.t ->
(int -> te) ->
(int -> te list) ->
pre_matching_problem ->
te LList.t option
end
module Make (R : Reducer) : Matcher = struct
let force_solve sg (args : miller_var) (t : te) =
if args.depth = 0 then t
else
let te = Lazy.force t in
Lazy.from_val
(try solve args te with NotUnifiable -> solve args (R.snf sg te))
let try_force_solve sg (args : miller_var) (t : te) =
try Some (force_solve sg args t) with NotUnifiable -> None
let lazy_add_n_lambdas n t =
if n = 0 then t else lazy (add_n_lambdas n (Lazy.force t))
let compute_sols (sol : term) : miller_var list -> term list =
let rec loop_vars acc = function
| [] -> acc
| mvar :: other_var_args ->
loop_vars (apply_sol sol mvar :: acc) other_var_args
in
loop_vars []
let compute_all_sols (sols : term list) : miller_var list -> term list =
let rec loop_sols acc args = function
| [] -> acc
| sol :: osols -> loop_sols (apply_sol sol args :: acc) args osols
in
let rec loop_term acc = function
| [] -> acc
| vars :: other_var_args ->
loop_term
(List.rev_append (loop_sols [] vars sols) acc)
other_var_args
in
loop_term []
let remove_sol sg (sol : term) (l : te list) : te list option =
let rec aux acc = function
| [] -> None
| hd :: tl ->
if R.are_convertible sg (Lazy.force hd) sol then
Some (List.rev_append acc tl)
else aux (hd :: acc) tl
in
aux [] l
let rec remove_sols_occs sg (sols : term list) (terms : te list) :
te list option =
match sols with
| [] -> Some terms
| sol :: tl -> bind_opt (remove_sols_occs sg tl) (remove_sol sg sol terms)
let filter_vars i = List.filter (fun (j, _) -> i != j)
let var_exists i = List.exists (fun (j, _) -> i == j)
let update_status status i s =
let nstat = Array.copy status in
nstat.(i) <- s; nstat
let get_occs i =
let rec aux acc = function
| [] -> acc
| (v, args) :: tl -> aux (if v == i then args :: acc else acc) tl
in
aux []
let update_ac_problems sg (i : int) (sol : te) :
te list ac_problem list -> te list ac_problem list option =
let rec update_ac acc = function
| [] -> Some (List.rev acc)
| p :: tl -> (
let d, aci, joks, vars, terms = p in
match get_occs i vars with
| [] -> update_ac (p :: acc) tl
| occs -> (
let sol = R.whnf sg (Lazy.force sol) in
let flat_sols =
force_flatten_AC_term (R.whnf sg) (R.are_convertible sg) aci sol
in
let sols = compute_all_sols flat_sols occs in
match remove_sols_occs sg sols terms with
| None -> None
| Some nterms ->
let nvars = filter_vars i vars in
if nvars = [] then
if nterms = [] || joks > 0 then
update_ac acc tl
else None
else
update_ac ((d, aci, joks, nvars, nterms) :: acc) tl))
in
update_ac []
let set_unsolved sg (pb : matching_problem) (i : int) (sol : te) =
match update_ac_problems sg i sol pb.ac_problems with
| None -> None
| Some ac_pbs ->
Some
{
pb with
ac_problems = ac_pbs;
status = update_status pb.status i (Solved sol);
}
let set_partly pb i (aci : ac_ident) =
assert (pb.status.(i) == Unsolved);
{pb with status = update_status pb.status i (Partly (aci, []))}
let close_partly sg pb i =
match pb.status.(i) with
| Partly (aci, terms) -> (
let rec update acc = function
| [] -> Some (List.rev acc)
| p :: tl ->
let d, aci', joks, vars, rhs = p in
if ac_ident_eq aci aci' && var_exists i vars then
match filter_vars i vars with
| [] -> if rhs = [] || joks > 0 then update acc tl else None
| filtered_vars ->
let a = (d, aci, joks, filtered_vars, rhs) in
update (a :: acc) tl
else update (p :: acc) tl
in
match update [] pb.ac_problems with
| None -> None
| Some ac_pbs ->
let nprob = {pb with ac_problems = ac_pbs} in
if terms = [] then
match aci with
| _, ACU neu ->
set_unsolved sg nprob i (Lazy.from_val neu)
| _ -> None
else
let sol =
Lazy.from_val (unflatten_AC aci (List.map Lazy.force terms))
in
set_unsolved sg nprob i sol)
| _ -> assert false
let add_partly sg (pb : matching_problem) (i : int) (sol : te) :
matching_problem option =
match pb.status.(i) with
| Partly (aci, terms) ->
let rec update_ac acc = function
| [] ->
let new_status =
update_status pb.status i (Partly (aci, sol :: terms))
in
Some {pb with ac_problems = List.rev acc; status = new_status}
| ((d, aci', joks, vars, terms) as p) :: tl ->
if ac_ident_eq aci aci' && var_exists i vars then
let sols = compute_sols (Lazy.force sol) (get_occs i vars) in
match remove_sols_occs sg sols terms with
| None -> None
| Some nterms ->
update_ac ((d, aci, joks, vars, nterms) :: acc) tl
else update_ac (p :: acc) tl
in
update_ac [] pb.ac_problems
| _ -> assert false
let fetch_var' pb x vars =
let score (i, _) =
match pb.status.(i) with
| Unsolved -> 0
| Partly (x', sols) ->
if ac_ident_eq x x' then 1 + List.length sols else max_int - 1
| Solved _ -> assert false
in
let aux (bv, bs) v =
let s = score v in
if s < bs then (v, s) else (bv, bs)
in
fst (List.fold_left aux ((-1, fo_var), max_int) vars)
let get_subst arities status =
let aux i = function
| Solved sol -> lazy_add_n_lambdas arities.(i) sol
| _ -> assert false
in
LList.of_array (Array.mapi aux status)
let solve_ac_problem sg =
let rec solve_next pb =
match pb.ac_problems with
| [] -> Some (get_subst pb.arities pb.status)
| (_, _, joks, [], terms) :: other_problems ->
if terms = [] || joks > 0 then
solve_next {pb with ac_problems = other_problems}
else None
| (_, ac_symb, _, vars, rhs) :: _ -> (
let x, args = fetch_var' pb ac_symb vars in
match pb.status.(x) with
| Partly (ac_symb', _) ->
assert (ac_ident_eq ac_symb ac_symb');
let rec try_add_terms = function
| [] -> try_solve_next (close_partly sg pb x)
| t :: tl -> (
let sol = try_force_solve sg args t in
let npb = bind_opt (add_partly sg pb x) sol in
match try_solve_next npb with
| None -> try_add_terms tl
| a -> a)
in
try_add_terms rhs
| Unsolved ->
let rec try_eq_terms = function
| t :: tl -> (
let sol = try_force_solve sg args t in
let npb = bind_opt (set_unsolved sg pb x) sol in
match try_solve_next npb with
| None -> try_eq_terms tl
| a -> a
)
| [] ->
solve_next (set_partly pb x ac_symb)
in
try_eq_terms rhs
| Solved _ -> assert false)
and try_solve_next pb = bind_opt solve_next pb in
solve_next
let ac_rearrange problems =
let ac_f j v t = (List.length v, -List.length t, j > 0) in
let comp (_, _, j1, v1, t1) (_, _, j2, v2, t2) =
compare (ac_f j1 v1 t1) (ac_f j2 v2 t2)
in
List.sort comp problems
let init_ac_problems sg status =
let whnfs = Array.make (Array.length status) None in
let whnfs i =
(match (whnfs.(i), status.(i)) with
| Some _, _ -> ()
| None, Solved soli -> whnfs.(i) <- Some (R.whnf sg (Lazy.force soli))
| _ -> ());
whnfs.(i)
in
let rec update_ac acc = function
| [] -> List.rev acc
| (d, aci, joks, vars, terms) :: tl -> (
let rec get_sols acc = function
| [] -> acc
| (v, args) :: tl ->
get_sols
(match whnfs v with
| Some sol ->
let flat_sols =
force_flatten_AC_term (R.whnf sg) (R.are_convertible sg)
aci sol
in
let sols =
List.map (fun sol -> apply_sol sol args) flat_sols
in
sols @ acc
| _ -> acc)
tl
in
match remove_sols_occs sg (get_sols [] vars) terms with
| None -> raise NotSolvable
| Some nterms ->
let nvars =
List.filter
(fun (v, _) ->
match status.(v) with Solved _ -> false | _ -> true)
vars
in
if nvars = [] then
if nterms = [] || joks > 0 then update_ac acc tl
else raise NotSolvable
else update_ac ((d, aci, joks, nvars, nterms) :: acc) tl)
in
update_ac []
let solve_problem rule_name sg from_stack from_stack_ac pb =
if pb.pm_ac_problems = [] then
let solve_eq = function
| [] -> assert false
| [(args, index_to_match)] ->
lazy_add_n_lambdas args.arity
(force_solve sg args (from_stack index_to_match))
| (args, rhs) :: other_pbs ->
let solu = Lazy.force (force_solve sg args (from_stack rhs)) in
List.iter
(fun (args, rhs) ->
let exp = apply_sol solu args in
if
not
(R.constraint_convertibility (rhs, exp) rule_name sg
(Lazy.force (from_stack rhs))
exp)
then raise NotSolvable)
other_pbs;
Lazy.from_val (add_n_lambdas args.arity solu)
in
try Some (LList.map solve_eq pb.pm_eq_problems)
with NotUnifiable | NotSolvable -> None
else
let solve_eq = function
| [] -> Unsolved
| (args, rhs) :: opbs ->
let solu = Lazy.force (force_solve sg args (from_stack rhs)) in
List.iter
(fun (args, rhs) ->
let exp = apply_sol solu args in
if
not
(R.constraint_convertibility (rhs, exp) rule_name sg
(Lazy.force (from_stack rhs))
exp)
then raise NotSolvable)
opbs;
Solved (Lazy.from_val solu)
in
try
let status = LList.map solve_eq pb.pm_eq_problems in
let status = Array.of_list (LList.lst status) in
let ac_problems =
List.map
(fun (d, aci, joks, vars, to_match) ->
(d, aci, joks, vars, from_stack_ac to_match))
pb.pm_ac_problems
in
let ac_pbs = init_ac_problems sg status ac_problems in
let pb =
{
arities = pb.pm_arity;
status;
ac_problems = ac_rearrange ac_pbs;
eq_problems = [||];
}
in
solve_ac_problem sg pb
with NotUnifiable | NotSolvable -> None
end