Source file lcr.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
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
(** Incremental verification of local confluence
by checking the joinability of critical pairs.
- CP(l-->r, p, g-->d) = { (s(r), s(l[d]_p) | s = mgu(l|_p,g) } is the critical
pair between l|_p and g.
- CP*(l-->r, g-->d) = U { CP(l-->r, p, g-->d) | p in FPos(l) }
- CP*(R,S) = U { CP*(l-->r, g-->d) | l-->r in R, g-->d in S }
The set of critical pairs of a rewrite system R is CP(R) = CP*(R,R).
We have CP(R U S) = CP*(R,R) U CP*(R,S) U CP*(S,R) U CP*(S,S).
As a consequence, assuming that we already checked the local confluence of R
and add a new set S of rules, we do not need to check CP*(R,R) again.
Warning: we currently do not take into account the rules having higher-order
pattern variables and critical pairs on AC symbols.
Remark: When trying to unify a subterm of a rule LHS with the LHS of another
rule, we need to rename the pattern variables of one of the LHS to avoid
name clashes. To this end, we use the [shift] function below which replaces
[Patt(i,n,_)] by [Patt(-i-1,n ^ "'",_)]. The printing function [subs] below
takes this into account. *)
open Core open Term open Print
open Timed
open Common open Error open Debug
open Lplib open Base open Extra
let log_cp = Logger.make 'k' "lcr " "local confluence"
let log_cp = log_cp.pp
(** [rule_of_pair ppf x] prints on [ppf] the pair of term [x] as a rule. *)
let rule_of_pair : (term * term) pp =
fun ppf (l,r) -> out ppf "%a ↪ %a" term l term r
(** [is_ho r] says if [r] uses higher-order variables. *)
let is_ho : rule -> bool = fun r ->
Array.exists (fun i -> i > 0) r.arities ||
let rec contains_abs t =
match unfold t with
| Abst _ | Prod _ | LLet _ -> raise Exit
| Appl(a,b) -> contains_abs a; contains_abs b
| _ -> ()
in try List.iter (contains_abs) r.lhs; false with Exit -> true
(** [is_definable s] says if [s] is definable and non opaque. *)
let is_definable : sym -> bool = fun s ->
(match s.sym_prop with Defin | Injec -> true | _ -> false)
&& not !(s.sym_opaq)
(** [rule_of_def s d] creates the rule [s --> d]. *)
let rule_of_def : sym -> term -> rule = fun s d ->
let rhs = Bindlib.unbox (Bindlib.bind_mvar [||] (Bindlib.box d)) in
{lhs=[]; rhs; arity=0; arities=[||]; vars=[||]; xvars_nb=0;
rule_pos=s.sym_pos}
(** [replace t p u] replaces the subterm of [t] at position [p] by [u]. *)
let replace : term -> subterm_pos -> term -> term = fun t p u ->
let rec replace t p =
match p with
| [] -> u
| 0::p ->
begin match unfold t with
| Appl(a,b) -> mk_Appl (replace a p, b)
| Abst(a,b) -> mk_Abst (replace a p, b)
| Prod(a,b) -> mk_Prod (replace a p, b)
| _ -> assert false
end
| 1::p ->
begin match unfold t with
| Appl(a,b) -> mk_Appl (a, replace b p)
| _ -> assert false
end
| _ -> assert false
in replace t (List.rev p)
(** [occurs i t] returns [true] iff [Patt(i,_,_)] is a subterm of [t]. *)
let occurs : int -> term -> bool = fun i ->
let rec occ t =
match unfold t with
| Patt(None,_,_) -> assert false
| Patt(Some j,_,_) -> i=j
| Vari _ | Symb _ -> false
| Appl(u,v) -> occ u || occ v
| Abst(a,b) | Prod(a,b) -> occ a || let _,b = Bindlib.unbind b in occ b
| Type -> assert false
| Kind -> assert false
| Meta _ -> assert false
| TEnv _ -> assert false
| Wild -> assert false
| Plac _ -> assert false
| TRef _ -> assert false
| LLet _ -> assert false
in occ
(** [shift t] replaces in [t] every pattern index i by -i-1. *)
let shift : term -> term =
let rec shift : term -> tbox = fun t ->
match unfold t with
| Vari x -> _Vari x
| Type -> _Type
| Kind -> _Kind
| Symb _ -> Bindlib.box t
| Prod(a,b) -> _Prod (shift a) (shift_binder b)
| Abst(a,b) -> _Abst (shift a) (shift_binder b)
| Appl(a,b) -> _Appl (shift a) (shift b)
| Meta(m,ts) -> _Meta m (Array.map shift ts)
| Patt(None,_,_) -> assert false
| Patt(Some i,n,ts) -> _Patt (Some(-i-1)) (n ^ "'") (Array.map shift ts)
| TEnv(te,ts) -> _TEnv (shift_tenv te) (Array.map shift ts)
| Wild -> _Wild
| Plac b -> _Plac b
| TRef r -> _TRef r
| LLet(a,t,b) -> _LLet (shift a) (shift t) (shift_binder b)
and shift_binder b =
let x, t = Bindlib.unbind b in Bindlib.bind_var x (shift t)
and shift_tenv : term_env -> tebox = function
| TE_Vari x -> _TE_Vari x
| TE_None -> _TE_None
| TE_Some _ -> assert false
in fun t -> Bindlib.unbox (shift t)
(** Type for pattern variable substitutions. *)
type subs = term IntMap.t
let subs : term IntMap.t pp =
let var ppf i = if i >= 0 then out ppf "$%d" i else out ppf "$%d'" (-i-1) in
D.map IntMap.iter var " ≔ " term "; "
(** [apply_subs s t] applies the pattern substitution [s] to [t]. *)
let apply_subs : subs -> term -> term = fun s t ->
let rec apply_subs t =
match unfold t with
| Patt(None, _, _) -> assert false
| Patt(Some i,_,[||]) ->
begin try IntMap.find i s with Not_found -> t end
| Patt(i,n,ts) -> mk_Patt (i, n, Array.map apply_subs ts)
| Vari _ | Symb _ | Type | Kind -> t
| Appl(u,v) -> mk_Appl (apply_subs u, apply_subs v)
| Abst(a,b) ->
let x,b = Bindlib.unbind b in
mk_Abst (apply_subs a, bind x lift (apply_subs b))
| Prod(a,b) ->
let x,b = Bindlib.unbind b in
mk_Prod (apply_subs a, bind x lift (apply_subs b))
| LLet(a,t,b) ->
let x,b = Bindlib.unbind b in
mk_LLet (apply_subs a, apply_subs t, bind x lift (apply_subs b))
| Meta(m,ts) -> mk_Meta (m, Array.map apply_subs ts)
| TEnv(te,ts) -> mk_TEnv (te, Array.map apply_subs ts)
| TRef _ -> assert false
| Wild -> assert false
| Plac _ -> assert false
in if IntMap.is_empty s then t else apply_subs t
(** Type of subterm iterators. *)
type iter = Pos.popt -> (sym -> subterm_pos -> term -> unit) -> term -> unit
(** [iter_subterms_eq pos f p t] iterates f on all subterms of [t] headed by a
defined function symbol. [p] is the position of [t] in reverse order. *)
let iter_subterms_from_pos : subterm_pos -> iter =
fun p _pos f t ->
let rec iter p t =
let h, _ = get_args t in
match unfold h with
| Symb s -> if is_definable s then iter_app s p t else iter_args p t
| Patt _
| Vari _ -> iter_args p t
| Abst(a,b)
| Prod(a,b) -> iter (0::p) a; let _,b = Bindlib.unbind b in iter (1::p) b
| Appl _ -> assert false
| Type -> assert false
| Kind -> assert false
| Meta _ -> assert false
| TEnv _ -> assert false
| Wild -> assert false
| Plac _ -> assert false
| TRef _ -> assert false
| LLet _ -> assert false
and iter_app s p t =
f s p t;
match unfold t with
| Appl(a,b) -> iter (1::p) b; iter_app s (0::p) a
| _ -> ()
and iter_args p t =
match unfold t with
| Appl(a,b) -> iter (1::p) b; iter_args (0::p) a
| _ -> ()
in iter p t
(** [iter_subterms_eq pos f t] iterates f on all subterms of [t] headed by a
defined function symbol. *)
let iter_subterms_eq : iter = iter_subterms_from_pos []
(** [iter_subterms pos f t] iterates f on all strict subterms of [t] headed by
a defined function symbol. *)
let iter_subterms : iter = fun pos f t ->
match unfold t with
| Symb _
| Patt _
| Vari _ -> ()
| Abst(a,b)
| Prod(a,b) ->
iter_subterms_from_pos [0] pos f a;
let _,b = Bindlib.unbind b in iter_subterms_from_pos [1] pos f b;
| Appl(a,b) ->
iter_subterms_from_pos [0] pos f a; iter_subterms_from_pos [1] pos f b;
| Type -> assert false
| Kind -> assert false
| Meta _ -> assert false
| TEnv _ -> assert false
| Wild -> assert false
| Plac _ -> assert false
| TRef _ -> assert false
| LLet _ -> assert false
(** [unif pos t u] returns [None] if [t] and [u] are not unifiable, and [Some
s] with [s] an idempotent mgu otherwise. Precondition: [l] and [r] must
have distinct indexes in Patt subterms. *)
let unif : Pos.popt -> term -> term -> term IntMap.t option =
fun _pos t u ->
let is_patt i = function Patt(Some j,_,_) -> j=i | _ -> false in
let exception NotUnifiable in
let rec unif s = function
| [] -> s
| (t, u)::l ->
if Logger.log_enabled() then
log_cp "unif %a ≡ %a with %a" term t term u subs s;
match unfold t, unfold u with
| Symb f, Symb g -> if f == g then unif s l else raise NotUnifiable
| Appl(a,b), Appl(c,d) -> unif s ((a,c)::(b,d)::l)
| Abst(a,b), Abst(c,d)
| Prod(a,b), Prod(c,d) ->
let x,b = Bindlib.unbind b in
let d = Bindlib.subst d (mk_Vari x) in
unif s ((a,c)::(b,d)::l)
| Vari x, Vari y ->
if Bindlib.eq_vars x y then unif s l else raise NotUnifiable
| Patt(None,_,_), _
| _, Patt(None,_,_) -> assert false
| Patt(Some i,_,ts), u
| u, Patt(Some i,_,ts) -> unif_patt s i ts u l
| Type, Type
| Kind, Kind -> unif s l
| Meta _, _ | _, Meta _ -> assert false
| TEnv _, _ | _, TEnv _ -> assert false
| Wild, _ | _, Wild -> assert false
| Plac _, _ | _, Plac _ -> assert false
| TRef _, _ | _, TRef _ -> assert false
| LLet _, _ | _, LLet _ -> assert false
| _ -> raise NotUnifiable
and unif_patt s i ts u l =
assert (Array.length ts = 0);
if is_patt i u then unif s l
else if occurs i u then raise NotUnifiable
else let s0 = IntMap.singleton i u in
let s' = IntMap.add i u (IntMap.map (apply_subs s0) s) in
let f (a,b) = apply_subs s' a, apply_subs s' b in
unif s' (List.map f l)
in try Some (unif IntMap.empty [t,u]) with NotUnifiable -> None
let _ =
let var i = mk_Patt (Some i, string_of_int i, [||]) in
let v0 = var 0
and v1 = var 1 in
let sym name =
create_sym [] Public Defin Eager false (Pos.none name) None
mk_Type [] in
let a_ = sym "a"
and b_ = sym "b"
and s_ = sym "s"
and f_ = sym "f" in
let app s ts = add_args (mk_Symb s) ts in
let a = app a_ []
and b = app b_ []
and s t = app s_ [t]
and f t u = app f_ [t; u] in
let open IntMap in
let unif = unif None in
assert (unif v0 v0 = Some empty);
assert (unif a a = Some empty);
assert (unif (s v0) v1 = Some (add 1 (s v0) empty));
assert (unif (f (s v0) v1) (f v1 (s v0)) = Some (add 1 (s v0) empty));
assert (unif a b = None);
assert (unif v0 (s v0) = None)
(** [can_handle sr] says if the sym_rule [sr] can be handled. *)
let can_handle : sym_rule -> bool = fun (s,r) ->
not (s.sym_mstrat = Sequen || is_modulo s || is_ho r)
(** [iter_rules h rs] iterates function [f] on every rule of [rs]. *)
let iter_rules : (rule -> unit) -> sym -> rule list -> unit = fun h ->
let rec iter = function
| r::rs -> if not (is_ho r) then h r; iter rs
| _ -> ()
in
fun s rs -> if not (is_modulo s) then iter rs
(** [iter_sym_rules h rs] iterates function [f] on every rule of [rs]. *)
let iter_sym_rules : (sym_rule -> unit) -> sym_rule list -> unit = fun h ->
let rec iter = function
| [] -> ()
| r::rs -> if can_handle r then h r; iter rs
in iter
(** [iter_rules_of_sym h s] iterates [f] on every rule of [s]. *)
let iter_rules_of_sym : (rule -> unit) -> sym -> unit = fun h s ->
if not (is_modulo s) then
match !(s.sym_def) with
| None -> List.iter (fun r -> if not (is_ho r) then h r) !(s.sym_rules)
| Some d -> h (rule_of_def s d)
(** Type of rule identifiers. Hack: we use the rule position to distinguish
between user-defined and generated rules (in completion), by giving a
unique negative start_line to every generated rule. *)
type rule_id = Pos.pos
(** [id_sym_rule r] returns the rule id of [r]. *)
let id_sym_rule : sym_rule -> rule_id = fun (_,r) ->
match r.rule_pos with Some p -> p | _ -> assert false
(** [new_rule_id()] generates a new unique rule id. *)
let new_rule_id : unit -> rule_id =
let open Stdlib in let n = ref 0 in fun () -> decr n;
{fname=None; start_line=(!n); start_col=0; end_line=0; end_col=0}
(** [is_generated i] says if [i] is a generated rule id. *)
let is_generated : rule_id -> bool = fun p -> p.start_line < 0
(** [int_of_rule_id i] returns a unique integer from [i]. /!\ [i] must be a
generated rule. *)
let int_of_rule_id : rule_id -> int = fun i ->
assert (is_generated i); i.start_line
(** Type of functions on critical pairs. *)
type cp_fun =
Pos.popt
-> rule_id -> term -> term
-> subterm_pos -> term
-> rule_id -> term -> term
-> subs
-> unit
(** Type of functions on critical pair candidates. *)
type cp_cand_fun =
Pos.popt
-> rule_id -> term -> term
-> subterm_pos -> term
-> rule_id -> term -> term
-> unit
(** [cp_cand_fun] turns a cp_fun into a cp_cand_fun. *)
let cp_cand_fun : cp_fun -> cp_cand_fun = fun h pos i l r p l_p j g d ->
Option.iter (h pos i l r p l_p j g d) (unif pos l_p g)
(** [iter_cps_with_rule iter_subterms h pos sr1 sr2] applies [h] on all the
critical pairs between all the subterms of the [sr1] LHS and the [sr2] LHS
using the iterator [iter_subterms]. *)
let iter_cps_with_rule :
iter -> cp_fun -> Pos.popt -> sym_rule -> sym_rule -> unit =
fun iter_subterms h pos lr gd ->
let l = lhs lr and r = rhs lr and g = lhs gd and d = rhs gd in
let l = shift l and r = shift r in
let i = id_sym_rule lr and j = id_sym_rule gd in
let f _ p l_p = cp_cand_fun h pos i l r p l_p j g d in
iter_subterms pos f l
(** [iter_cps_of_rules h pos rs] applies [h] on all the critical pairs of [rs]
with itself. *)
let iter_cps_of_rules : cp_fun -> Pos.popt -> sym_rule list -> unit =
fun h pos rs ->
let f r rs =
if can_handle r then begin
iter_cps_with_rule iter_subterms h pos r r;
iter_sym_rules (iter_cps_with_rule iter_subterms_eq h pos r) rs
end
in
List.iter_head_tail f rs
(** [typability_constraints pos t] returns [None] if [t] is not typable, and
[Some s] where [s] is a substitution implied by the typability of [t]. *)
let typability_constraints : Pos.popt -> term -> subs option = fun pos t ->
let open Stdlib in
let p = new_problem()
and p2m : meta IntMap.t ref = ref IntMap.empty
and m2p : (int * string) MetaMap.t ref = ref MetaMap.empty in
if Logger.log_enabled() then log_cp "typability_constraints %a" term t;
let rec patt_to_meta : term -> term = fun t ->
match unfold t with
| Patt(Some i,n,[||]) ->
let m =
match IntMap.find_opt i !p2m with
| Some m -> m
| None ->
let m_typ = LibMeta.fresh p mk_Type 0 in
let typ = mk_Meta(m_typ,[||]) in
let m = LibMeta.fresh p typ 0 in
p2m := IntMap.add i m !p2m; m2p := MetaMap.add m (i,n) !m2p; m
in mk_Meta(m,[||])
| Appl(a,b) -> mk_Appl_not_canonical(patt_to_meta a, patt_to_meta b)
| Symb _ | Vari _ -> t
| Abst(a,b) ->
let x,b = Bindlib.unbind b in
mk_Abst(patt_to_meta a, bind x lift_not_canonical (patt_to_meta b))
| _ -> assert false
in
let t = patt_to_meta t in
match Infer.infer_noexn p [] t with
| None -> if Logger.log_enabled() then log_cp "not typable"; None
| _ ->
let s2p : int SymMap.t ref = ref SymMap.empty in
let meta_to_sym : meta -> unit = fun m ->
try
let i,n = MetaMap.find m !m2p in
let s = create_sym (Sign.current_path())
Public Defin Eager false (Pos.none n) None mk_Kind [] in
let t = Bindlib.unbox (Bindlib.bind_mvar [||] (_Symb s)) in
Timed.(m.meta_value := Some t);
s2p := SymMap.add s i !s2p
with Not_found -> ()
in
MetaSet.iter meta_to_sym Timed.(!p).metas;
if Logger.log_enabled() then log_cp "meta_to_sym %a" problem p;
match Unif.solve_noexn ~type_check:false p with
| false ->
if Logger.log_enabled() then log_cp "unsolvable constraints"; None
| true ->
if Logger.log_enabled() then log_cp "after solve %a" problem p;
let rec sym_to_patt : term -> term = fun t ->
match unfold t with
| Symb s ->
begin match SymMap.find_opt s !s2p with
| Some i -> mk_Patt(Some i, s.sym_name, [||])
| None -> t
end
| Appl(a,b) -> mk_Appl_not_canonical(sym_to_patt a, sym_to_patt b)
| _ -> t
in
let rule_of_terms : term -> term -> sym_rule option = fun l r ->
match get_args_len l with
| Symb s, lhs, arity ->
let vars = [||] and rule_pos = Some (new_rule_id()) in
let rhs = Bindlib.unbox (Bindlib.bind_mvar vars (Bindlib.box r)) in
let r = {lhs; rhs; arity; arities=[||]; vars; xvars_nb=0; rule_pos} in
Some (s,r)
| _ -> None
in
let add_constr : sym_rule IntMap.t -> constr -> sym_rule IntMap.t =
fun rule_map (_,l,r) ->
let l,r = if Term.cmp l r > 0 then l,r else r,l in
match rule_of_terms l r with
| Some x ->
let i = id_sym_rule x in IntMap.add (int_of_rule_id i) x rule_map
| _ -> rule_map
in
let rule_map =
List.fold_left add_constr IntMap.empty Timed.(!p).unsolved in
let completion_step : sym_rule IntMap.t -> sym_rule IntMap.t =
fun rule_map ->
if Logger.log_enabled() then
log_cp "completion_step %a" (D.intmap sym_rule) rule_map;
let new_rule_map = ref rule_map and modified = ref false in
let remove_rule i =
new_rule_map := IntMap.remove (int_of_rule_id i) !new_rule_map;
modified := true
in
let add_rule l r =
match rule_of_terms l r with
| Some x ->
let i = id_sym_rule x in
new_rule_map := IntMap.add (int_of_rule_id i) x !new_rule_map;
modified := true
| None -> ()
in
let cp_fun _pos i l r p _l_p _j _g d s =
assert (s = IntMap.empty);
remove_rule i;
let l' = replace l p d in
match cmp l' r with
| 0 -> ()
| n when n > 0 -> add_rule l' r
| _ -> add_rule r l'
in
let rs = IntMap.fold (fun _ r rs -> r::rs) rule_map [] in
iter_cps_of_rules cp_fun pos rs;
if !modified then !new_rule_map else rule_map
in
let rec complete : sym_rule IntMap.t -> sym_rule IntMap.t =
fun rule_map ->
let new_rule_map = completion_step rule_map in
if new_rule_map == rule_map then rule_map else complete new_rule_map
in
let rule_map = complete rule_map in
let f _ ((s,_) as x) subs =
match SymMap.find_opt s !s2p with
| Some i -> IntMap.add i (sym_to_patt (rhs x)) subs
| None -> subs
in
let s = IntMap.fold f rule_map IntMap.empty in
if Logger.log_enabled() then log_cp "typing subs %a" subs s;
Some s
(** [check_cp pos _ l r p l_p _ g d s] checks that, if [l_p] and [g] are
unifiable with mgu [s], then [s(r)] and [s(l[d]_p)] are
joinable. Precondition: [l] and [r] must have distinct indexes in Patt
subterms. *)
let check_cp : cp_fun = fun pos _ l r p l_p _ g d s ->
if Logger.log_enabled() then
log_cp (Color.blu "check_cp \
@[<v>l ≔ %a@ r ≔ %a@ p ≔ %a@ l_p ≔ %a@ g ≔ %a@ d ≔ %a@ s ≔ %a@]")
term l term r subterm_pos p term l_p term g term d subs s;
let t = apply_subs s l in
match typability_constraints pos t with
| None -> ()
| Some s' ->
let t = apply_subs s' t in
let r1 = apply_subs s' (apply_subs s r)
and r2 = apply_subs s' (apply_subs s (replace l p d)) in
Console.out 2 "@[<v>Critical pair:@ \
t ≔ %a@ \
t ↪[] %a@ \
with %a@ \
t ↪%a %a@ \
with %a@]"
term t term r1 rule_of_pair (l,r)
subterm_pos p term r2 rule_of_pair (g,d);
if not (Eval.eq_modulo [] r1 r2) then
wrn pos "@[<v>Unjoinable critical pair:@ \
t ≔ %a@ \
t ↪[] %a ↪* %a@ \
with %a@ \
t ↪%a %a ↪* %a@ \
with %a@]"
term t term r1 term (Eval.snf [] r1) rule_of_pair (l,r)
subterm_pos p term r2 term (Eval.snf [] r2) rule_of_pair (g,d)
(** [check_cps_subterms_eq pos sr1] checks the critical pairs between
all the subterms of the [sr1] LHS and all the possible rule LHS's. *)
let check_cps_subterms_eq : Pos.popt -> sym_rule -> unit =
fun pos ((_,x) as lr) ->
let l = shift (lhs lr) and r = shift (rhs lr) in
let i = id_sym_rule lr in
let f s p l_p =
match !(s.sym_def) with
| Some d ->
let j = match s.sym_pos with Some p -> p | None -> assert false in
cp_cand_fun check_cp pos i l r p l_p j (mk_Symb s) d
| None ->
let h y =
let gd = (s, y) in let j = id_sym_rule gd in
cp_cand_fun check_cp pos i l r p l_p j (lhs gd) (rhs gd)
in
match p with
| [] -> let h y = if y != x then h y in iter_rules h s !(s.sym_rules);
| _ -> iter_rules h s !(s.sym_rules)
in
iter_subterms_eq pos f l
(** [check_cps_sign_with pos sign sym_map] checks all the critical pairs
between all the rules of the signature and [sym_map]. *)
let check_cps_sign_with : Pos.popt -> Sign.t -> rule list SymMap.t -> unit =
fun pos sign sym_map ->
let f s' rs' =
match SymMap.find_opt s' !(sign.Sign.sign_cp_pos) with
| None -> ()
| Some cps ->
let h (i,l,r,p,l_p) =
let h' r' =
let i = match i with Some p -> p | None -> assert false in
let gd = (s',r') in let j = id_sym_rule gd in
cp_cand_fun check_cp pos i l r p l_p j (lhs gd) (rhs gd)
in List.iter h' rs'
in
List.iter h cps
in
SymMap.iter f sym_map
(** [check_cps pos sign srs sym_map] checks all the critical pairs generated
by adding [srs]. *)
let check_cps :
Pos.popt -> Sign.t -> sym_rule list -> rule list SymMap.t -> unit =
fun pos sign srs sym_map ->
iter_cps_of_rules check_cp pos srs;
iter_sym_rules (check_cps_subterms_eq pos) srs;
check_cps_sign_with pos sign sym_map;
let f path str_map =
if path != Ghost.sign.sign_path && str_map <> StrMap.empty then
let sign =
try Path.Map.find path !Sign.loaded with Not_found -> assert false
in
check_cps_sign_with pos sign sym_map
in
Path.Map.iter f !(sign.sign_deps)
(** [update_cp_pos pos map rs] extends [map] by mapping every definable symbol
s' such that there is a rule l-->r of [rs] and a position p of l such that
l_p is headed by s' to (l,r,p,l_p). *)
let update_cp_pos : Pos.popt -> cp_pos list SymMap.t -> rule list SymMap.t ->
cp_pos list SymMap.t =
let add_elt : sym -> 'a -> 'a list SymMap.t -> 'a list SymMap.t =
fun s x map ->
let h = function None -> Some[x] | Some xs -> Some(x::xs) in
SymMap.update s h map
in
fun pos cp_pos_map rules_map ->
let open Stdlib in
let map = ref cp_pos_map in
let f s rs =
let h ({rule_pos=i;_} as r) =
let lr = (s,r) in let l = lhs lr and r = rhs lr in
let h' s' p l_p = map := add_elt s' (i,l,r,p,l_p) !map
in
iter_subterms_eq pos h' l
in
iter_rules h s rs
in
SymMap.iter f rules_map; !map