Source file assertBounds.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
module type S = sig
module Core : CoreSig.S
val var :
Core.t ->
?min:Core.bound ->
?max:Core.bound ->
Core.Var.t ->
Core.t * bool
val poly :
Core.t ->
Core.P.t ->
?min:Core.bound ->
?max:Core.bound ->
Core.Var.t ->
Core.t * bool
end
module Make(Core : CoreSig.S) : S with module Core = Core = struct
module Core = Core
module Result = Result.Make(Core)
open Core
let empty_info value = {
mini = None;
maxi = None;
value;
vstatus = ValueOK;
empty_dom = false;
}
let update_bound
(get_closer : R2.t -> R2.t)
(env : Core.t)
(bnd : bound option) =
match bnd with
| Some b when env.is_int ->
Some {b with bvalue = get_closer b.bvalue}
| other -> other
let update_min_bound = update_bound R2.ceiling
let update_max_bound = update_bound R2.floor
let new_status_basic stt fixme s info consistent_bnds =
let has_bad_value = info.vstatus != ValueOK in
match stt, consistent_bnds with
| UNSAT _, _ -> stt, fixme
| _, false ->
UNSAT s, SX.empty
| UNK, true ->
stt, if has_bad_value then SX.add s fixme else SX.remove s fixme
| SAT, _ ->
assert (fixme == SX.empty);
if has_bad_value then UNK, SX.add s fixme else stt, fixme
let assert_basic_var env x mini maxi =
let info, poly, changed =
try
let info, poly = MX.find x env.basic in
let info, chang1 = set_min_bound info mini in
let info, chang2 = set_max_bound info maxi in
info, poly, chang1 || chang2
with Not_found -> assert false
in
let status, fixme =
new_status_basic env.status env.fixme x info (consistent_bounds info)
in
{env with basic = MX.add x (info, poly) env.basic; status; fixme},
changed
let new_status_non_basic x stt fixme ({mini; maxi; value; _} as info) =
match stt with
| UNSAT _ -> stt, fixme
| SAT | UNK when consistent_bounds info ->
assert (not (violates_min_bound value mini));
assert (not (violates_max_bound value maxi));
assert (stt != SAT || fixme == SX.empty);
stt, fixme
| SAT | UNK ->
UNSAT x, SX.empty
let adapt_values_of_basic_vars env _old _new x use =
let {basic; _} = env in
let diff = R2.sub _new _old in
SX.fold
(fun s env ->
let info, p = try MX.find s basic with Not_found -> assert false in
let c_x = try P.find x p with Not_found -> assert false in
let info =
{info with value = R2.add info.value (R2.mult_by_const c_x diff)}
in
let info = ajust_status_of_basic info in
let status, fixme =
new_status_basic env.status env.fixme s info true
in
{env with status; fixme; basic = MX.add s (info, p) env.basic}
)use env
let assert_non_basic_var env x mini maxi =
let info, use =
try MX.find x env.non_basic
with Not_found -> empty_info R2.zero, SX.empty
in
let info, chang1 = set_min_bound info mini in
let info, chang2 = set_max_bound info maxi in
let old_val = info.value in
let info, changed = ajust_value_of_non_basic info in
let status, fixme = new_status_non_basic x env.status env.fixme info in
let env =
{env with
non_basic = MX.add x (info, use) env.non_basic; status; fixme}
in
let env =
if not changed then env
else adapt_values_of_basic_vars env old_val info.value x use
in
env, chang1 || chang2
let var env ?min ?max x =
debug "[entry of assert_var]" env (Result.get None);
check_invariants env (Result.get None);
let mini = update_min_bound env min in
let maxi = update_max_bound env max in
let env, changed =
if MX.mem x env.basic then
assert_basic_var env x mini maxi
else
assert_non_basic_var env x mini maxi
in
debug "[exit of assert_var]" env (Result.get None);
check_invariants env (Result.get None);
env, changed
let register_slake slk p env =
if MX.mem slk env.slake then env, false
else {env with slake = MX.add slk p env.slake}, true
let update_use is_fresh_slk x_status slk use =
match x_status with
| P.Exists ->
assert (SX.mem slk use);
use
| P.Removed ->
assert (SX.mem slk use);
SX.remove slk use
| P.New ->
assert (not is_fresh_slk || not (SX.mem slk use));
SX.add slk use
let update_use_list is_fresh modified_stt slk non_basic =
List.fold_left
(fun non_basic (x, x_status) ->
try
let i, u = MX.find x non_basic in
MX.add x (i, update_use is_fresh x_status slk u) non_basic
with Not_found -> assert false
)non_basic modified_stt
let normalize_polynomial is_fresh slk p env =
P.fold
(fun x c (q, env) ->
try
let info, use = MX.find x env.non_basic in
let new_q, x_status = P.accumulate x c q in
let use = update_use is_fresh x_status slk use in
new_q, {env with non_basic = MX.add x (info, use) env.non_basic}
with Not_found ->
try
let _ , p_of_x = MX.find x env.basic in
let new_q, modified_stt = P.append q c p_of_x in
new_q,
{env with
non_basic =
update_use_list is_fresh modified_stt slk env.non_basic}
with Not_found ->
let env, chang = assert_non_basic_var env x None None in
assert (not chang);
let new_q, x_status = P.replace x c q in
assert (x_status == P.New);
let info, use =
try MX.find x env.non_basic
with Not_found -> assert false
in
let use = update_use is_fresh x_status slk use in
new_q,
{ env with
non_basic = MX.add x (info, use) env.non_basic}
)p (P.empty, env)
let poly env p ?min ?max slk =
debug "[entry of assert_poly]" env (Result.get None);
check_invariants env (Result.get None);
assert (P.is_polynomial p);
let mini = update_min_bound env min in
let maxi = update_max_bound env max in
let env, is_fresh = register_slake slk p env in
let info, is_basic, env, change =
try
let info, use = MX.find slk env.non_basic in
assert (
let np, _ = normalize_polynomial is_fresh slk p env in
let zp, _ = P.accumulate slk R.m_one np in
P.is_empty zp
);
let info, chang1 = set_min_bound info mini in
let info, chang2 = set_max_bound info maxi in
let old_val = info.value in
let info, changed = ajust_value_of_non_basic info in
let env =
{env with non_basic = MX.add slk (info, use) env.non_basic}
in
let env =
if not changed then env
else adapt_values_of_basic_vars env old_val info.value slk use
in
info, false, env, chang1 || chang2
with Not_found ->
try
let info, poly = MX.find slk env.basic in
assert (
let np, _ = normalize_polynomial is_fresh slk p env in
P.equal np poly
);
let info, chang1 = set_min_bound info mini in
let info, chang2 = set_max_bound info maxi in
info, true, {env with basic = MX.add slk (info, poly) env.basic},
chang1 || chang2
with Not_found ->
assert (is_fresh);
let np, env = normalize_polynomial is_fresh slk p env in
let info = empty_info (evaluate_poly env np) in
let info, chang1 = set_min_bound info mini in
let info, chang2 = set_max_bound info maxi in
info, true, {env with basic = MX.add slk (info, np) env.basic},
chang1 || chang2
in
let status, fixme =
if is_basic then
new_status_basic env.status env.fixme slk info
(consistent_bounds info)
else
new_status_non_basic slk env.status env.fixme info
in
let env = {env with status; fixme } in
debug "[exit of assert_poly]" env (Result.get None);
check_invariants env (Result.get None);
env, change
end