aboutsummaryrefslogtreecommitdiff
path: root/contrib/linear/kwc.ml
blob: 13a9b85400530e8886b821f0bda8bb66f47e6288 (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
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
(***********************************************************************)
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team    *)
(* <O___,, *        INRIA-Rocquencourt  &  LRI-CNRS-Orsay              *)
(*   \VV/  *************************************************************)
(*    //   *      This file is distributed under the terms of the      *)
(*         *       GNU Lesser General Public License Version 2.1       *)
(***********************************************************************)

(*i $Id$ i*)

open Util
open Names

open General
open Dpctypes
open Subst
open Unif
open Graph

(* Herbrand form *************)

let h_fun v ex f = 
  let lt = List.map (fun x -> VAR(x)) ex
  in subst v (APP (GLOB (SK v)::lt)) f

let free_her fv f = 
  let rec fh_rec f = function
       v::ll -> let f0 = subst v (APP [GLOB (SK v)]) f
                in fh_rec f0 ll
     | [] -> f
  in fh_rec f fv

let herbrand f = 
  let rec h_rec ex sign f = match f with
      ForAll(v,f1) -> if sign then (h_rec ex sign (h_fun v ex f1))
      	       	       	      else (h_rec (v::ex) sign f1)
    | Exists(v,f1) -> if sign then (h_rec (v::ex) sign f1)
      	       	       	      else (h_rec ex sign (h_fun v ex f1))
    | Neg(f1) -> let (e,h) = (h_rec ex ((not (sign))) f1)
                 in (e , Neg h)
    | Atom(s,lt) -> (ex,Atom(s,lt))
    | Imp(f1,f2) -> (let (ex1,h1) = (h_rec ex ((not (sign))) f1)
      	       	     and (ex2,h2) = (h_rec ex sign f2)
		     in (union ex1 ex2,Imp(h1,h2)))
    | Conj(f1,f2) -> (let (ex1,h1) = (h_rec ex sign f1)
      	       	      and (ex2,h2) = (h_rec ex sign f2)
		      in (union ex1 ex2,Conj(h1,h2)))
    | Disj(f1,f2) -> (let (ex1,h1) = (h_rec ex sign f1)
      	       	      and (ex2,h2) = (h_rec ex sign f2)
		      in (union ex1 ex2,Disj(h1,h2)))
  in let (ex,f0) = h_rec [] true f
  in let fv = free_var_formula f
  in (ex,free_her fv f0)

let separate f = 
  let n = ref 0 
  in let rec sep_rec f = match f with
       Atom((s,0),lt) -> n := !n+1;
       	       	     Atom((s,!n),lt)
     | Atom((s,_),_) -> anomaly "separate"
     | Neg(f1) -> Neg(sep_rec f1)
     | ForAll(s,f1) -> ForAll(s,sep_rec f1)
     | Exists(s,f1) -> Exists(s,sep_rec f1)
     | Imp(f1,f2)-> Imp(sep_rec f1,sep_rec f2)
     | Conj(f1,f2) -> Conj(sep_rec f1,sep_rec f2)
     | Disj(f1,f2) -> Disj(sep_rec f1,sep_rec f2)
  in sep_rec f

(* Searching for paths... *********)

let lit_conj f =  
  let rec lc_rec sign = function
      Atom(_,_) as a -> if sign then ([a],[],[]) else ([],[a],[])
    | Neg(f1) -> lc_rec ((not (sign))) f1
    | Conj(f1,f2) -> let (p1,n1,c1) = lc_rec sign f1
      	       	     and (p2,n2,c2) = lc_rec sign f2
		     in let c = if sign then [((f1,f2),(p1@n1,p2@n2))]
		                        else []
		     in (p1@p2,n1@n2,c@c1@c2)
    | Disj(f1,f2) -> let (p1,n1,c1) = lc_rec sign f1
      	       	     and (p2,n2,c2) = lc_rec sign f2
		     in let c = if sign then []
		                        else [((f1,f2),(p1@n1,p2@n2))]
		     in (p1@p2,n1@n2,c@c1@c2)
    | Imp(f1,f2) -> let (p1,n1,c1) = lc_rec ((not (sign))) f1
      	       	    and (p2,n2,c2) = lc_rec sign f2
		    in let c = if sign then []
		                       else [((f1,f2),(p1@n1,p2@n2))]
		    in (p1@p2,n1@n2,c@c1@c2)
    | _ -> raise Impossible_case
  in lc_rec true f


(* Finding all matches ********)

let mb p q =
  let rec mb_rec = function
      (_,(lf1,lf2))::ll -> ((not((  ((List.mem p lf1) & (List.mem q lf2))
      	       	       	      or ((List.mem q lf1) & (List.mem p lf2))))) )
			   & (mb_rec ll)
    | [] -> true
  in mb_rec


let all_matches pos neg lcj = 
  let rec all_matches_p (x,y) = function
      ((Atom (x_0,x_1)) as q::neg1) -> 
             let lm = try [((Atom (x,y)),q,unif_atoms (x,y) (x_0,x_1))] 
                      with Not_unifiable -> []
             in if mb (Atom (x,y)) q lcj then lm@(all_matches_p (x,y) neg1)
		                      else (all_matches_p (x,y) neg1)
    | _ -> []
  and all_matches_rec  = function
      ((Atom (x_0,x_1))::pos1) -> (all_matches_p (x_0,x_1) neg)@(all_matches_rec pos1)
    | _ -> []
  in all_matches_rec pos

(* combine_path P L : returns the least path containing all the matches
      	       	      in P and L. If no such path exists, it raises
		      CP_error *********)

exception CP_error

let rec lit_unicity = function
    (p::ll) -> if List.mem p ll then false else lit_unicity ll
  | [] -> true

let combine_path (m1,u1) (m2,u2) =
     let lm  = union m1 m2
  in let llt = List.map (fun (p,q,_) -> [p;q]) lm
  in let lt  = List.flatten llt
  in if lit_unicity lt 
     then let u = try up u1 u2 with Up_error -> raise CP_error
          in (lm , u)
     else raise CP_error

(* lit_in_matches : formula list -> (match list) -> bool *****)

let lit_in_matches lF ml = 
  let rec lim_rec  = function
      ((p,q,_)::mmll) -> if (List.mem p lF) or (List.mem q lF)
      	       	       	 then true
			 else lim_rec mmll
    | [] -> false
  in lim_rec ml

(* 16.III.94 *********)
(* Simple Depth First Search (p.138) *******)
(* NB : path = match list * unifier ********)

let rec matches_pos p = function
    ((p1,q,u) as m::mM) -> if p=p1 
      	       	       	   then [([m] , u)]@(matches_pos p mM)
			   else matches_pos p mM
  | [] -> [] 

let rec matches_neg q = function
    ((p,q1,u) as m::mM) -> if q=q1 
      	       	       	   then [([m] , u)]@(matches_neg q mM)
      	       	       	   else matches_neg q mM
  | [] -> [] 

let uncovered (ml,_) lcj = 
  let rec uncov_rec = function
      (((f1,f2),(lf1,lf2))::llccjj) ->
       	  let sat1 = lit_in_matches lf1 ml
       in let sat2 = lit_in_matches lf2 ml 
       in if sat1 & ((not (sat2)))
	  then (f2,lf2)::(uncov_rec llccjj)
	  else if sat2 & ((not (sat1)))
	       then (f1,lf1)::(uncov_rec llccjj)
	       else (uncov_rec llccjj)
    | [] -> []
  in uncov_rec lcj

let paths pos neg m lcj =
  let rec paths_rec = function
      ((_,_,u) as m_0::mM) -> (extend ([m_0],u))@(paths_rec mM)
    | [] -> []
  and extension p (f1,lf1) =
       let lm  = glue (List.map (fun x -> if List.mem x pos
      	                             then matches_pos x m
				     else matches_neg x m) lf1)
    in let rec ext_rec = function
         (l::ll) ->( try (combine_path p l)::(ext_rec ll)
	             with CP_error -> ext_rec ll
		   )
       | [] -> []
    in ext_rec lm
  and extend p = 
       let uc = uncovered p lcj
    in if uc = [] 
       then [p]
       else glue (List.map (fun x -> (glue (List.map extend (extension p x)))) uc)
  in paths_rec m

(* Dealing with cycles... ******)

let conj_graph lm lc lt =
  let rec nb_of_x = function
      (p::lpp) -> (try let q = List.assoc p lm in q::(nb_of_x lpp)
                   with Not_found -> nb_of_x lpp)
    | [] -> []
  and nb_rec x = function
      ((l1,l2)::lcc) -> 
          if List.mem x l1 
	  then (nb_of_x l2)@(nb_rec x lcc)
	  else if List.mem x l2 
	       then (nb_of_x l1)@(nb_rec x lcc)
	       else nb_rec x lcc
    | [] -> []
  and conj_graph_rec = function
      (p::ll) -> (p,nb_rec p lc)::(conj_graph_rec ll)
    | [] -> []
  in conj_graph_rec lt

let is_cyclic_path lcj (lmu,u) = 
     let lm = List.flatten (List.map (fun (p,q,_) -> [(p,q);(q,p)]) lmu)
  in let lc = List.map (fun (_,pl) -> pl) lcj
  in let lt = List.map (fun (p,_) -> p) lm
  in let g  = conj_graph lm lc lt
  in have_cycle g

let good_paths lcj lp = 
  let rec good_paths_rec = function
      (p::pp) -> if is_cyclic_path lcj p 
               then good_paths_rec pp
	       else p::(good_paths_rec pp)
    | [] -> []
  in good_paths_rec lp