Source file fmSimplexIneqs.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
open AltErgoLib
open Format
open Options
module Q = Numbers.Q
open Inequalities
module Container : Inequalities.Container_SIG = struct
module Make
(P : Polynome.T with type r = Shostak.Combine.r)
: Inequalities.S with type p = P.t = struct
module X = Shostak.Combine
module FM = Inequalities.FM(P)
include FM
open Simplex
let dsimplex = ref false
module SCache =
Simplex_cache.MAKE(
struct
type t = X.r
let compare = X.hash_cmp
include X
end)
module MX = Shostak.MXH
module Ex = Explanation
let print_couple fmt (re, eps) =
fprintf fmt "(%s , %s)" (Q.to_string re) (Q.to_string eps)
let print_answer (vof,vals) =
let print fmt (l,v) =
fprintf fmt "L(%d) -> %a@," l print_couple v
in
Printer.print_dbg ~header:false
"vof = %a@ \
@[<v 2>assignement returned by the Simplex@ \
%a"
print_couple vof
(Printer.pp_list_no_space print) vals
let print_parsed_answer answer =
if get_debug_fm() then
match answer with
| Unsat { vof; vals; _ } ->
Printer.print_dbg
"I read: the simplex problem is not feasible (<=)";
print_answer (vof,vals)
| Eq_unsat ->
Printer.print_dbg
"I read: the simplex problem is not feasible (=)"
| Unbound { vof; vals; _ } ->
Printer.print_dbg
"I read: the simplex problem is not bounded";
print_answer (vof,vals)
| Max { vof; vals; _ } ->
Printer.print_dbg
"I read: the simplex problem has a solution";
print_answer (vof,vals)
let add_to_sum ld sum l_m =
List.fold_left
(fun sum (c, x) ->
let lp, ln = try MX.find x sum with Not_found -> [], [] in
if Q.sign c > 0 then MX.add x ((ld, c) :: lp, ln) sum
else MX.add x (lp, (ld, c) :: ln) sum
) sum l_m
let generalized_fm_projection (constrs : (int * t) list) =
List.fold_left
(fun (sum, ctt, lds) (ld, ineq) ->
let l_m, c = P.to_list ineq.ple0 in
assert (Q.is_int c);
if l_m == [] then begin
Printer.print_err "%a <= 0" P.print ineq.ple0;
assert false
end
else
let sum = add_to_sum ld sum l_m in
let ctt = (ld, c) :: ctt in
let lds = (ld, Q.one) :: lds in
sum, ctt, lds
)(MX.empty,[],[]) constrs
let polynomials_bounding_pb sum ctt lambdas =
let vars_elim_eqs =
MX.fold (fun x (l1,l2) acc -> (x,(l1,l2, Q.zero)) :: acc) sum [] in
let lds_gt_z = lambdas in
ctt, vars_elim_eqs, lds_gt_z
let monomial_bounding_pb sum ctt lambdas x sum_x is_pos =
let max_ctt, vars_elim, s_neq =
polynomials_bounding_pb sum ctt lambdas in
let lp, ln = sum_x in
let coef_x =(x, (lp, ln, if is_pos then Q.m_one else Q.one)) in
max_ctt, coef_x :: vars_elim, s_neq
let explain vals constrs =
List.fold_left
(fun expl (ld, (re,eps)) ->
if Q.compare re Q.zero = 0 &&
Q.compare eps Q.zero = 0 then expl
else
let { expl = ex ; _ } = List.assoc ld constrs in
Explanation.union expl ex
)Explanation.empty vals
let cpt = ref 0
let tighten_polynomials
add_ineqs are_eq acc sum ctt lambdas nb_constrs constrs =
if get_debug_fm() then
Printer.print_dbg ~flushed:false "tighten_polynomials@ ";
let max_ctt, equas, s_neq = polynomials_bounding_pb sum ctt lambdas in
let r_max_ctt,r_equas,r_s_neq = SCache.make_repr max_ctt equas s_neq in
let sim_res =
match SCache.already_registered r_max_ctt r_equas r_s_neq with
| None ->
if !dsimplex then
Printer.print_dbg ~flushed:false ~header:false
"Simplex poly in@ ";
incr cpt;
if !dsimplex then
Printer.print_dbg ~flushed:false ~header:false
"new simplex %d@ " !cpt;
let res = Simplex_Q.main max_ctt equas s_neq nb_constrs in
if !dsimplex then
Printer.print_dbg ~header:false "Simplex poly out";
SCache.register r_max_ctt r_equas r_s_neq !cpt res ;
res
| Some (n, res, ctt') ->
if SCache.MI.compare Q.compare r_max_ctt ctt' = 0 then begin
if !dsimplex then Printer.print_dbg
"reuse RESULTS of simplex %d" n;
res
end
else begin
if !dsimplex then
Printer.print_dbg "reuse simplex %d" n;
let res = Simplex_Q.partial_restart res max_ctt in
res
end
in
print_parsed_answer sim_res;
match sim_res with
| Unsat _ | Eq_unsat -> acc
| Unbound { vals; _ } ->
raise (Ex.Inconsistent (explain vals constrs, []))
| Max { vof = (re, eps); vals = vals; _ } ->
assert (Q.is_zero re);
let expl = explain vals constrs in
let cmp = Q.compare eps Q.zero in
if cmp > 0 then raise(Ex.Inconsistent (expl, []));
let dep =
List.fold_left
(fun dep (ld,(re_ld, eps_ld)) ->
assert (Q.is_zero re_ld);
if Q.is_zero eps_ld then dep
else
let ineq = List.assoc ld constrs in
match Util.MI.bindings ineq.dep with
[a, (n,p, is_le)] ->
assert (Q.is_one n && is_le);
assert (not (Util.MI.mem a dep));
Util.MI.add a (eps_ld, p, is_le) dep
| _ -> assert false
)Util.MI.empty vals
in
let ineq =
{
ple0 = P.create [] eps Ty.Tint;
is_le = true;
age = current_age();
expl = expl;
dep = dep;
}
in
add_ineqs are_eq acc None [ineq]
let tighten_monomial
add_ineqs are_eq acc x sum_x is_pos sum ctt lambdas nb_constrs constrs
=
if get_debug_fm() then
Printer.print_dbg ~flushed:false
"tighten_monomial %s%a "
(if is_pos then "+" else "-") X.print x;
let max_ctt, equas, s_neq =
monomial_bounding_pb sum ctt lambdas x sum_x is_pos in
let r_max_ctt,r_equas,r_s_neq = SCache.make_repr max_ctt equas s_neq in
let sim_res =
match SCache.already_registered_mon x r_max_ctt r_equas r_s_neq with
| None ->
if !dsimplex then
Printer.print_dbg ~flushed:false ~header:false
"Simplex monomes in@ ";
incr cpt;
if !dsimplex then
Printer.print_dbg ~flushed:false ~header:false
"new simplex %d@ " !cpt;
let res = Simplex_Q.main max_ctt equas s_neq nb_constrs in
if !dsimplex then
Printer.print_dbg ~header:false
"Simplex monomes out";
SCache.register_mon x r_max_ctt r_equas r_s_neq !cpt res ;
res
| Some (n, res, ctt') ->
if SCache.MI.compare Q.compare r_max_ctt ctt' = 0 then begin
if !dsimplex then
Printer.print_dbg ~header:false
"reuse RESULTS of simplex %d" n;
res
end
else begin
if !dsimplex then
Printer.print_dbg ~header:false
"reuse simplex %d" n;
let res = Simplex_Q.partial_restart res max_ctt in
res
end
in
print_parsed_answer sim_res;
match sim_res with
| Unsat _ | Eq_unsat -> acc
| Unbound { vals; _ } ->
raise (Ex.Inconsistent (explain vals constrs, []))
| Max { vof = (vof, eps); vals; _} ->
assert (Q.is_zero eps);
let expl = explain vals constrs in
let dep =
List.fold_left
(fun dep (ld,(re_ld, eps_ld)) ->
assert (Q.is_zero eps_ld);
if Q.is_zero re_ld then dep
else
let ineq = List.assoc ld constrs in
match Util.MI.bindings ineq.dep with
[a, (n,p, is_le)] ->
assert (Q.is_one n && is_le);
assert (not (Util.MI.mem a dep));
Util.MI.add a (re_ld, p, is_le) dep
| _ -> assert false
)Util.MI.empty vals
in
let mon_coef = if is_pos then Q.one else Q.m_one in
let ineq =
{
ple0 = P.create [mon_coef, x] vof Ty.Tint;
is_le = true;
age = current_age();
expl = expl;
dep = dep;
}
in
add_ineqs are_eq acc None [ineq]
let tighten_monomials add_ineqs are_eq acc sum ctt lds nb_ctrs ctrs =
MX.fold
(fun x sum_x acc ->
let sum = MX.remove x sum in
let acc =
tighten_monomial
add_ineqs are_eq acc x sum_x true sum ctt lds nb_ctrs ctrs in
let acc =
tighten_monomial
add_ineqs are_eq acc x sum_x false sum ctt lds nb_ctrs ctrs in
acc
)sum acc
let fm_simplex add_ineqs are_eq acc constrs nb_constrs =
let print fmt (id, { ple0 ; _ }) =
fprintf fmt "%d) %a <= 0" id P.print ple0 in
if get_debug_fm () then
Printer.print_dbg
"begin fm-simplex: nb_constrs = %d@ %a"
nb_constrs
(Printer.pp_list_no_space print) constrs;
let sum, ctt, lambdas = generalized_fm_projection constrs in
let acc =
if MX.is_empty sum then acc
else
let acc =
tighten_polynomials
add_ineqs are_eq acc sum ctt lambdas nb_constrs constrs in
if Options.get_tighten_vars() then
tighten_monomials
add_ineqs are_eq acc sum ctt lambdas nb_constrs constrs
else acc
in
if get_debug_fm () then
Printer.print_dbg "end fm-simplex";
acc
let list_of_mineqs mp =
let nb_ineqs = MP.cardinal mp in
let cpt = ref (nb_ineqs + 1) in
let ctrs =
MINEQS.fold
(fun _ (ineq, _) ctrs ->
decr cpt;
(!cpt, ineq) :: ctrs
)mp []
in
ctrs, nb_ineqs
let is_rat_poly p = match P.type_info p with
| Ty.Tint -> false
| Ty.Treal -> true
| _ -> assert false
let check_is_rat mp =
let is_rat = ref true in
begin
try MINEQS.iter (fun p _ -> is_rat := is_rat_poly p; raise Exit) mp
with Exit -> ()
end;
let is_rat = !is_rat in
assert
(MINEQS.fold (fun p _ z -> z && is_rat == is_rat_poly p) mp true);
is_rat
let fmSimplex add_ineqs are_eq acc mp =
if check_is_rat mp then fourierMotzkin add_ineqs are_eq acc mp
else
let constrs, nb_constrs = list_of_mineqs mp in
fm_simplex add_ineqs are_eq acc constrs nb_constrs
let available = fmSimplex
end
end
let () =
Inequalities.set_current
(module Container : Inequalities.Container_SIG)