summaryrefslogtreecommitdiffstats
path: root/testsuite/tests/misc-kb/kb.ml
blob: 5045a3188151d1268ced259b0bf445ec564daae2 (plain)
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
(***********************************************************************)
(*                                                                     *)
(*                                OCaml                                *)
(*                                                                     *)
(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
(*                                                                     *)
(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  under the terms of the Q Public License version 1.0.               *)
(*                                                                     *)
(***********************************************************************)

(* $Id$ *)

open Terms
open Equations

(****************** Critical pairs *********************)

(* All (u,subst) such that N/u (&var) unifies with M,
   with principal unifier subst *)

let rec super m = function
    Term(_,sons) as n ->
      let rec collate n = function
        [] -> []
      | son::rest ->
          List.map (fun (u, subst) -> (n::u, subst)) (super m son)
          @ collate (n+1) rest in
      let insides = collate 1 sons in
        begin try
          ([], unify m n) :: insides
        with Failure _ ->
          insides
        end
  | _ -> []


(* Ex :
let (m,_) = <<F(A,B)>>
and (n,_) = <<H(F(A,x),F(x,y))>> in super m n
==> [[1],[2,Term ("B",[])];                      x <- B
     [2],[2,Term ("A",[]); 1,Term ("B",[])]]     x <- A  y <- B
*)

(* All (u,subst), u&[], such that n/u unifies with m *)

let super_strict m = function
    Term(_,sons) ->
      let rec collate n = function
        [] -> []
      | son::rest ->
          List.map (fun (u, subst) -> (n::u, subst)) (super m son)
          @ collate (n+1) rest in
      collate 1 sons
    | _ -> []


(* Critical pairs of l1=r1 with l2=r2 *)
(* critical_pairs : term_pair -> term_pair -> term_pair list *)
let critical_pairs (l1,r1) (l2,r2) =
  let mk_pair (u,subst) =
     substitute subst (replace l2 u r1), substitute subst r2 in
  List.map mk_pair (super l1 l2)

(* Strict critical pairs of l1=r1 with l2=r2 *)
(* strict_critical_pairs : term_pair -> term_pair -> term_pair list *)
let strict_critical_pairs (l1,r1) (l2,r2) =
  let mk_pair (u,subst) =
    substitute subst (replace l2 u r1), substitute subst r2 in
  List.map mk_pair (super_strict l1 l2)


(* All critical pairs of eq1 with eq2 *)
let mutual_critical_pairs eq1 eq2 =
  (strict_critical_pairs eq1 eq2) @ (critical_pairs eq2 eq1)

(* Renaming of variables *)

let rename n (t1,t2) =
  let rec ren_rec = function
    Var k -> Var(k+n)
  | Term(op,sons) -> Term(op, List.map ren_rec sons) in
  (ren_rec t1, ren_rec t2)


(************************ Completion ******************************)

let deletion_message rule =
  print_string "Rule ";print_int rule.number; print_string " deleted";
  print_newline()


(* Generate failure message *)
let non_orientable (m,n) =
    pretty_term m; print_string " = "; pretty_term n; print_newline()


let rec partition p = function
    [] -> ([], [])
  | x::l -> let (l1, l2) = partition p l in
            if p x then (x::l1, l2) else (l1, x::l2)


let rec get_rule n = function
    [] -> raise Not_found
  | r::l -> if n = r.number then r else get_rule n l


(* Improved Knuth-Bendix completion procedure *)

let kb_completion greater =
  let rec kbrec j rules =
  let rec process failures (k,l) eqs =
(****
     print_string "***kb_completion "; print_int j; print_newline();
     pretty_rules rules;
     List.iter non_orientable failures;
     print_int k; print_string " "; print_int l; print_newline();
     List.iter non_orientable eqs;
***)
    match eqs with
      [] ->
        if k<l then next_criticals failures (k+1,l) else
        if l<j then next_criticals failures (1,l+1) else
        begin match failures with
            [] -> rules (* successful completion *)
          | _  -> print_string "Non-orientable equations :"; print_newline();
                  List.iter non_orientable failures;
                  failwith "kb_completion"
        end
    | (m,n)::eqs ->
        let m' = mrewrite_all rules m
        and n' = mrewrite_all rules n
        and enter_rule(left,right) =
          let new_rule = mk_rule (j+1) left right in
          pretty_rule new_rule;
          let left_reducible rule = reducible left rule.lhs in
          let (redl,irredl) = partition left_reducible rules in
          List.iter deletion_message redl;
          let right_reduce rule =
            mk_rule rule.number rule.lhs
                    (mrewrite_all (new_rule::rules) rule.rhs) in
          let irreds = List.map right_reduce irredl in
          let eqs' = List.map (fun rule -> (rule.lhs, rule.rhs)) redl in
          kbrec (j+1) (new_rule::irreds) [] (k,l) (eqs @ eqs' @ failures) in
(***
        print_string "--- Considering "; non_orientable (m', n');
***)
        if m' = n' then process failures (k,l) eqs else
        if greater(m',n') then enter_rule(m',n') else
        if greater(n',m') then enter_rule(n',m') else
        process ((m',n')::failures) (k,l) eqs

  and next_criticals failures (k,l) =
(****
    print_string "***next_criticals ";
    print_int k; print_string " "; print_int l ; print_newline();
****)
    try
      let rl = get_rule l rules in
      let el = (rl.lhs, rl.rhs) in
        if k=l then
          process failures (k,l)
                  (strict_critical_pairs el (rename rl.numvars el))
        else
          try
            let rk = get_rule k rules in
            let ek = (rk.lhs, rk.rhs) in
              process failures (k,l)
                      (mutual_critical_pairs el (rename rl.numvars ek))
          with Not_found -> next_criticals failures (k+1,l)
    with Not_found -> next_criticals failures (1,l+1)
  in process
  in kbrec


(* complete_rules is assumed locally confluent, and checked Noetherian with
  ordering greater, rules is any list of rules *)

let kb_complete greater complete_rules rules =
    let n = check_rules complete_rules
    and eqs = List.map (fun rule -> (rule.lhs, rule.rhs)) rules in
    let completed_rules =
      kb_completion greater n complete_rules [] (n,n) eqs in
    print_string "Canonical set found :"; print_newline();
    pretty_rules (List.rev completed_rules)