File: fcl_fdArray.ml

package info (click to toggle)
facile 1.1.4-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 716 kB
  • sloc: ml: 6,862; makefile: 90
file content (310 lines) | stat: -rw-r--r-- 10,623 bytes parent folder | download
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
(***********************************************************************)
(*                                                                     *)
(*                           FaCiLe                                    *)
(*                 A Functional Constraint Library                     *)
(*                                                                     *)
(*            Nicolas Barnier, Pascal Brisset, LOG, CENA               *)
(*                                                                     *)
(* Copyright 2004 CENA. All rights reserved. This file is distributed  *)
(* under the terms of the GNU Lesser General Public License.           *)
(***********************************************************************)
(* $Id: fcl_fdArray.ml,v 1.25 2004/08/12 15:22:07 barnier Exp $ *)
open Fcl_var
open Fcl_arith
module C = Fcl_cstr

let new_min_array xs x =
  let n = Array.length xs in
  let name = "FdArray.min" in
  let delay c =
    Array.iter (fun x -> delay [Fd.on_min; Fd.on_max] x c) xs;
    delay [Fd.on_min; Fd.on_max] x c
  and update _ =
    (* Try to decide which one is the smallest *)
    let smallest = ref 0 and min_smallest = ref (Fd.min xs.(0)) in
    for i = 1 to n - 1 do
      let min_i = Fd.min xs.(i) in
      if min_i < !min_smallest then begin
	smallest := i; min_smallest := min_i end
    done;
    let max_smallest = Fd.max xs.(!smallest) in
    try
      for i = 0 to n - 1 do
	if i <> !smallest && Fd.min xs.(i) < max_smallest then raise Exit
      done;
      Fcl_cstr.post (fd2e x =~ fd2e xs.(!smallest));
      true
    with Exit ->
      (* All the xs are greater than the min of min *)
      let minx = Fd.min x in
      let x_ge_min xi =
	match Fd.value xi with
	  Val v -> if minx > v then Fcl_stak.fail name
	| Unk a ->
	    if minx > Attr.min a then
	      Fd.refine xi (Fcl_domain.remove_low minx (Attr.dom a)) in
      Array.iter x_ge_min xs;
      (* smallest min of xs <= x <= smallest max of xs *)
      let smallest_max =
	Array.fold_left
	  (fun r xi -> Fcl_misc.Operators.min (Fd.max xi) r) max_int xs in
      match Fd.value x with
	Val x ->
	  if not (!min_smallest <= x && x <= smallest_max) then
	    Fcl_stak.fail name
	  else false
      | Unk a ->
	  let d =
	    Fcl_domain.remove_low_up !min_smallest smallest_max (Attr.dom a) in
	  Fd.refine x d;
	  false in
  C.create ~name update delay


let new_max_array xs x =
  let n = Array.length xs in
  let name = "FdArray.max" in
  let delay c =
    Array.iter (fun x -> delay [Fd.on_min; Fd.on_max] x c) xs;
    delay [Fd.on_min; Fd.on_max] x c
  and update _ =
    (* Try to decide which one is the greatest *)
    let greatest = ref 0 and max_greatest = ref (Fd.max xs.(0)) in
    for i = 1 to n - 1 do
      let max_i = Fd.max xs.(i) in
      if max_i > !max_greatest then begin
	greatest := i; max_greatest := max_i
      end
    done;
    let min_greatest = Fd.min xs.(!greatest) in
    try
      for i = 0 to n - 1 do
	if i <> !greatest && Fd.max xs.(i) > min_greatest then
	  raise Exit
      done; (* We have found the greatest element *)
      Fcl_cstr.post (fd2e x =~ fd2e xs.(!greatest));
      true
    with
      Exit ->
	(* All the xs are smaller than the max of max *)
      	let maxx = Fd.max x in
      	let x_leq_max xi =
	  match Fd.value xi with
	    Val v -> if not (maxx >= v) then Fcl_stak.fail name
	  | Unk a ->
	      if not (Fd.max x >= Attr.max a) then
	      	Fd.refine xi (Fcl_domain.remove_up maxx (Attr.dom a)) in
	Array.iter x_leq_max xs;
	(* greatest min of xs <= x <= greatest max of xs *)
      	let greatest_min =
	  Array.fold_left
	    (fun r xi -> Fcl_misc.Operators.max (Fd.min xi) r) min_int xs in
	begin
	  match Fd.value x with
	    Val x -> assert (x >= greatest_min)
      	  | Unk a ->
	      let d =
		Fcl_domain.remove_low_up greatest_min (Fd.max xs.(!greatest))
		  (Attr.dom a) in
	      Fd.refine x d
	end;
	false
  in
  
  C.create ~name update delay

let min_cstr xs x =
  if Array.length xs = 0 then invalid_arg "FdArray.min_cstr";
  (* To prevent array modifications by the user *)
  let xs = Array.copy xs in
  new_min_array xs x

let min xs =
  if Array.length xs = 1 then xs.(0) else
  let x = Fd.create Fcl_domain.int in
  let c = min_cstr xs x in
  Fcl_cstr.post c;
  x

let max_cstr xs x =
  if Array.length xs = 0 then invalid_arg "FdArray.max_cstr";
  (* To prevent array modifications by the user *)
  let xs = Array.copy xs in
  new_max_array xs x

let max xs =
  if Array.length xs = 1 then xs.(0) else
  let x = Fd.create Fcl_domain.int in
  let c = max_cstr xs x in
  Fcl_cstr.post c;
  x

open Printf

let domain_of var = 
  match Fd.value var with
    Val x -> Fcl_domain.interval x x
  | Unk d -> Attr.dom d

let new_element index array value =
  let n = Array.length array in
  let name = "FdArray.get" in

  let bound_index i =
    assert(i >= 0 && i < n);
    Fcl_debug.call 'e' (fun s -> fprintf s "%s: bound_index=%d\n" name i);
    Fcl_cstr.post (fd2e value =~ fd2e array.(i));
    Fcl_debug.call 'e' (fun s -> fprintf s "value=%a\n" Fd.fprint value);
    true in

  let delay x =
    delay [Fd.on_refine] index x;
    delay [Fd.on_refine] value x;
    Array.iter (fun v -> delay [Fd.on_refine] v x) array
  and update _ =
    Fcl_debug.call 'e' (fun s -> fprintf s "[|%a|].(%a) = %a\n" (fun s -> Array.iter (fun v -> fprintf s "%a " Fd.fprint v)) array Fd.fprint index Fd.fprint value);
    let dom_value = domain_of value in
    let index_to_keep = ref []
    and new_dom_value = ref Fcl_domain.empty in
    match Fd.value index with
      Val i ->
	bound_index i
    | Unk index_ ->
	Fcl_domain.iter
	  (fun i ->
	    let inter = Fcl_domain.intersection (domain_of array.(i)) dom_value in
	    if not (Fcl_domain.is_empty inter) then begin
	      index_to_keep := i :: !index_to_keep;
	      new_dom_value := Fcl_domain.union inter !new_dom_value
	    end) (Attr.dom index_);
	Fd.refine index (Fcl_domain.unsafe_create (List.rev !index_to_keep));
	match Fd.value index with
	  Val i ->
	    bound_index i
    	| Unk _index_ ->
	    begin
	      match Fd.value value with
	      	Val _ -> Fcl_debug.call 'e' (fun s -> fprintf s "After: [|%a|].(%a) = %a\n" (fun s -> Array.iter (fun v -> fprintf s "%a " Fd.fprint v)) array Fd.fprint index Fd.fprint value) (* Something more to do ? *)
	      | Unk _ ->
		  Fd.refine value !new_dom_value;
		  Fcl_debug.call 'e' (fun s -> fprintf s "After: [|%a|].(%a) = %a\n" (fun s -> Array.iter (fun v -> fprintf s "%a " Fd.fprint v)) array Fd.fprint index Fd.fprint value) 
	    end; 
	    false in

  let init () =
    begin match Fd.value index with
      Val i ->
	if i >= 0 && i < n then ignore (bound_index i)
	else Fcl_stak.fail (name ^ ": index out of bound")
    | Unk index_attr ->
	Fd.refine index
	  (Fcl_domain.intersection
	     (Fcl_domain.interval 0 (n-1)) (Attr.dom index_attr)) end;
    ignore (update 0) in

  C.create ~name ~init update delay

(* Acces to an array of integers *)
let new_element_of_ints index array value =
  let n = Array.length array in
  assert(0 <= Fd.min index && Fd.max index < n);

  let bound_index i =
    assert(i >= 0 && i < n);
    Fcl_debug.call 'e' (fun s -> fprintf s "Element: bound_index=%d\n" i);
    Fd.unify value array.(i);
    Fcl_debug.call 'e' (fun s -> fprintf s "value=%a\n" Fd.fprint value);
    true in

  let index_size = Fcl_stak.ref 0 in

  let name = "FdArray.get_ints"
  and delay x =
    delay [Fd.on_refine] index x;
    delay [Fd.on_refine] value x
  and update _ =
    let index_has_changed = Fd.size index <> Fcl_stak.get index_size in
    Fcl_debug.call 'e' (fun s -> fprintf s "[|%a|].(%a) = %a\n" (fun s -> Array.iter (fun v -> fprintf s "%d " v)) array Fd.fprint index Fd.fprint value);
    let dom_value = domain_of value in
    match Fd.value index with
      Val i -> bound_index i
    | Unk index_ ->
    	let index_to_keep = ref []
    	and new_values = ref [] in
	Fcl_domain.iter
	  (fun i ->
	    if Fcl_domain.member array.(i) dom_value then begin
	      index_to_keep := i :: !index_to_keep;
	      new_values := array.(i) :: !new_values end)
	  (Attr.dom index_);
	let new_dom_index =
	  Fcl_domain.unsafe_create (List.rev !index_to_keep) in
	Fd.refine index new_dom_index;
	Fcl_stak.set index_size (Fcl_domain.size new_dom_index);
	match Fd.value index with
	  Val i ->
	    bound_index i
    	| Unk _index_ ->
	    if index_has_changed then
	      match Fd.value value with
	      	Val _ -> (* index already has the correct domain; finished*)
		  Fcl_debug.call 'e' (fun s -> fprintf s "After: [|%a|].(%a) = %a\n" (fun s -> Array.iter (fun v -> fprintf s "%d " v)) array Fd.fprint index Fd.fprint value);
		  true
	      | Unk _ ->
		  Fd.refine value (Fcl_domain.create !new_values);
		  Fcl_debug.call 'e' (fun s -> fprintf s "After: [|%a|].(%a) = %a\n" (fun s -> Array.iter (fun v -> fprintf s "%d " v)) array Fd.fprint index Fd.fprint value);
		  Fd.size value = 1
	    else false in

  let init () =
    begin match Fd.value index with
      Val i ->
	if i >= 0 && i < n then ignore (bound_index i)
	else Fcl_stak.fail (name ^ ": index out of bound")
    | Unk index_attr ->
	Fd.refine index
	  (Fcl_domain.intersection
	     (Fcl_domain.interval 0 (n-1)) (Attr.dom index_attr)) end;
    ignore (update 0) in

  C.create ~name ~init update delay


let array_forall p a =
  let n = Array.length a in
  try
    for i = 0 to n-1 do if not (p a.(i)) then raise Exit done; true
  with Exit -> false

let get_cstr array index value =
  let n = Array.length array in
  if n = 0 then invalid_arg "FdArray.get_cstr: empty array";
  match Fd.value index with
    Val i ->
      if 0 <= i && i < n then fd2e value =~ fd2e array.(i) else Fcl_cstr.zero
  | _ ->
      if array_forall (fun x -> not (Fd.is_var x)) array then
	let ints = Array.map Fd.int_value array in (* Only integers *)
	if array_forall (fun x -> x = ints.(0)) ints then (* All equal ! *)
	  Fcl_var.Fd.unify_cstr value ints.(0)
	else new_element_of_ints index ints value
      else new_element index array value

let get array index =
  match Fd.value index with
    Val i -> (* Index connu *)
      if i >= 0 && i < Array.length array then array.(i)
      else Fcl_stak.fail "FdArray.get: index out of bound"
  | _ ->
      let (mi, ma) =
      	Array.fold_left
	  (fun (mi, ma) e ->
	    (Stdlib.min mi (Fd.min e), Stdlib.max ma (Fd.max e)))
	  (max_int, min_int) array in
      if mi = ma then Fd.int mi else
      let value = Fd.create (Fcl_domain.interval mi ma) in
      (* To prevent array modifications by the user *)
      let array = Array.copy array in
      Fcl_cstr.post (get_cstr array index value);
      value