Source file bddd.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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
(** In the following, we call a comb the bdd of a conjunction of
litterals (var). They provide the ordering in which litterals
appear in the bdds we manipulate.
*)
open Exp
open Value
open Constraint
type var_idx = int
open Sol_nb
(** snt Associates to a bdd the (absolute) number of solutions
contained in its lhs (then) and rhs (else) branches. Note that
adding those two numbers only give a number of solution that is
relative to which bdd points to it.
*)
module BddMap = struct
include Map.Make(struct type t = Bdd.t let compare = compare end)
end
type snt = (sol_nb * sol_nb) BddMap.t
type t = snt * Formula_to_bdd.t
let tbl_to_string (snt,f2b) =
(BddMap.fold
(fun bdd (sn1, sn2) acc ->
Printf.sprintf "%s; %i->%s,%s" acc
(Bdd.size bdd) (string_of_sol_nb sn1) (string_of_sol_nb sn2)
) snt "|bdd|->sol_number_left, sol_number_rigth: "
) ^ "\n" ^
(Formula_to_bdd.tbl_to_string f2b)
exception No_numeric_solution of t
let (clear : t -> t) =
fun (snt, bddt) ->
snt, Formula_to_bdd.clear_step bddt
let (formula_to_bdd : t -> Var.env_in -> Var.env -> string -> int ->
Exp.formula -> t * Bdd.t) =
fun (snt,bddt) input memory ctx_msg vl f ->
let bddt, bdd = Formula_to_bdd.f bddt input memory ctx_msg vl f in
(snt,bddt), bdd
let (index_to_linear_constraint : t -> int -> Constraint.t) =
fun (_,bddt) i ->
Formula_to_bdd.index_to_linear_constraint bddt i
let (get_index_from_linear_constraint : t -> Constraint.t -> int) =
fun (_,bddt) c ->
Formula_to_bdd.get_index_from_linear_constraint bddt c
let (num_to_gne: t -> Var.env_in -> Var.env -> string -> int -> Exp.num -> t * Gne.t) =
fun (snt,bddt) i l s vl n ->
let bddt, gne = Formula_to_bdd.num_to_gne bddt i l s vl n in
(snt,bddt), gne
let (eval_int_expr: t -> Exp.num -> string -> Var.env_in -> Var.env -> int ->
int option) =
fun (_snt,bddt) e msg input mem vl ->
Formula_to_bdd.eval_int_expr bddt e msg input mem vl
let (sol_number : t -> Bdd.t -> sol_nb * sol_nb) =
fun (snt,_) bdd ->
BddMap.find bdd snt
let (add_snt_entry : t -> Bdd.t -> sol_nb * sol_nb -> t) =
fun (snt,bddt) bdd sol_nb ->
BddMap.add bdd sol_nb snt, bddt
let (init_snt : unit -> t) =
fun () ->
let snt = BddMap.empty in
let f2bdd = Formula_to_bdd.init () in
let bdd_true = Bdd.dtrue () in
let bdd_false = Bdd.dfalse () in
let snt = BddMap.add (bdd_true) (one_sol, zero_sol) snt in
let snt = BddMap.add (bdd_false) (zero_sol, one_sol) snt in
snt,f2bdd
let (sol_number_exists : Bdd.t -> snt -> bool) =
fun bdd snt ->
BddMap.mem bdd snt
let rec (build_sol_nb_table_rec: Bdd.t -> Bdd.t -> t -> t * sol_nb) =
fun bdd comb t ->
let _ = assert (
not (Bdd.is_cst bdd) && (Bdd.topvar comb) = (Bdd.topvar bdd) )
in
try
let (nt, ne) = sol_number t bdd in
t, (add_sol_nb nt ne)
with Not_found ->
let t, nt = compute_absolute_sol_nb (Bdd.dthen bdd) comb t in
let (snt,bddt), ne = compute_absolute_sol_nb (Bdd.delse bdd) comb t in
let snt = BddMap.add bdd (nt, ne) snt in
(snt,bddt), (add_sol_nb nt ne)
and
(compute_absolute_sol_nb: Bdd.t -> Bdd.t -> t -> t * sol_nb) =
fun sub_bdd comb t ->
if Bdd.is_false sub_bdd then t, zero_sol
else if Bdd.is_true sub_bdd then
let sol_nb = if Bdd.is_true comb then one_sol else
two_power_of (Bdd.supportsize (Bdd.dthen comb))
in
t, sol_nb
else
let topvar = Bdd.topvar sub_bdd in
let rec
(count_missing_vars: Bdd.t -> var_idx -> int -> Bdd.t * int) =
fun comb var_idx cpt ->
let _ = assert (not (Bdd.is_cst comb)) in
let combvar = Bdd.topvar comb in
if var_idx = combvar
then (comb, cpt)
else count_missing_vars (Bdd.dthen comb) var_idx (cpt+1)
in
let (sub_comb, missing_vars_nb) = count_missing_vars (Bdd.dthen comb) topvar 0 in
let t, n0 = build_sol_nb_table_rec sub_bdd sub_comb t in
let factor = (two_power_of missing_vars_nb) in
let res = mult_sol_nb n0 factor in
t, res
(** [build_sol_nb_table bdd comb] build an internal table that
associates to each [bdd] its solution number. [comb] is a bdd made
of the the conjunctions of variables of [bdd] union the Boolean
variable to be generated (which migth not appear in [bdd]) ; it is
necessary because not all the variable to be generated appears
in the [bdd].
*)
let (build_sol_nb_table: t -> var list -> Bdd.t -> Bdd.t -> t) =
fun t _ bdd comb ->
if (sol_number_exists bdd (fst t)) then t else
let rec skip_unconstraint_bool_var_at_top comb v =
if Bdd.is_true comb then comb
else
let topvar = (Bdd.topvar comb) in
if v = topvar then comb
else skip_unconstraint_bool_var_at_top (Bdd.dthen comb) v
in
if Bdd.is_true bdd then
fst (build_sol_nb_table_rec bdd comb t)
else
let tvar = Bdd.topvar bdd in
let comb2 = skip_unconstraint_bool_var_at_top comb tvar in
fst (build_sol_nb_table_rec bdd comb2 t)
let (toss_up_one_var: Var.name -> Var.subst) =
fun var ->
let ran = Random.float 1. in
if (ran < 0.5) then (var, B(true)) else (var, B(false))
let (toss_up_one_var_index: Var.env_in -> Var.env -> int ->
string -> Formula_to_bdd.t -> var_idx -> Formula_to_bdd.t * Var.subst option) =
fun input memory vl ctx_msg bddt var_idx ->
let cstr = Formula_to_bdd.index_to_linear_constraint bddt var_idx in
match cstr with
Bv(v) -> (
match (Var.default v) with
| Some (Formu f) ->
let bddt, bdd = Formula_to_bdd.f bddt input memory ctx_msg vl f in
if Bdd.is_false bdd then bddt, Some((Var.name v), B false)
else if Bdd.is_true bdd then bddt, Some((Var.name v), B true)
else
(print_string (
"*** Default values should not depend on " ^
"controllable variables, \nwhich is the case of " ^
(formula_to_string f) ^ ", the default value of " ^
(Var.name v) ^ "\n");
exit 2
)
| Some (Numer _) -> assert false
| Some (Liste _l) -> assert false
| None -> bddt, Some(toss_up_one_var (Var.name v))
)
| _ -> bddt, None
(** A map with
- an accumulator
- a function returning an option,
- and where the None elements are removed from the resulting list
*)
let (list_map_acc_option: ('acc -> 'a -> 'acc * 'b option) -> 'acc -> 'a list ->
'acc * 'b list) =
fun f x l ->
let rec aux f x l =
match l with
[] -> x, []
| e::t ->
(match f x e with
x, None -> (aux f x t)
| x, Some(b) ->
let x, res = aux f x t in
x, b::res
)
in
let x, res = aux f x l in
x, res
let rec (draw_in_bdd_rec: t -> Var.env_in -> Var.env -> int ->
string -> Var.env * Store.t -> Bdd.t -> Bdd.t ->
t * Var.env * Store.t' * Store.p) =
fun (snt, bddt) input memory vl ctx_msg (sl, store) bdd comb ->
if
Bdd.is_true bdd
then
let (store_int, store_poly) =
try Store.switch_to_polyhedron_representation vl store
with Store.No_polyedral_solution -> raise (No_numeric_solution (snt,bddt))
in
let vars_index = Bdd.list_of_support comb in
let bddt, id = list_map_acc_option
(toss_up_one_var_index input memory vl ctx_msg)
bddt
vars_index
in
let sl = Value.OfIdent.add_list sl id in
(snt, bddt), sl, store_int, store_poly
else (
assert (not (Bdd.is_false bdd));
assert (sol_number_exists bdd snt);
let bddvar = Bdd.topvar bdd in
let cstr = Formula_to_bdd.index_to_linear_constraint bddt bddvar in
match cstr with
| Bv(var) ->
draw_in_bdd_rec_bool input memory vl ctx_msg var (sl, store) bdd comb (snt,bddt)
| EqZ(e) ->
draw_in_bdd_rec_eq input memory vl ctx_msg e (sl, store) bdd comb (snt,bddt)
| Ineq(ineq) ->
draw_in_bdd_rec_ineq input memory vl ctx_msg ineq (sl, store) bdd comb (snt,bddt)
)
and (draw_in_bdd_rec_bool: Var.env_in -> Var.env -> int -> string -> var ->
Var.env * Store.t -> Bdd.t -> Bdd.t -> t ->
t * Var.env * Store.t' * Store.p) =
fun input memory vl ctx_msg var (sl, store) bdd comb (snt, bddt) ->
let bddvar = Bdd.topvar bdd in
let topvar_comb = Bdd.topvar comb in
if bddvar <> topvar_comb then
let bddt, new_sl =
match toss_up_one_var_index input memory vl ctx_msg bddt topvar_comb with
bddt, Some(s) -> bddt, Value.OfIdent.add sl s
| bddt, None -> bddt, sl
in
draw_in_bdd_rec (snt,bddt) input memory vl ctx_msg (new_sl, store) bdd
(Bdd.dthen comb)
else
let (n, m) = sol_number (snt,bddt) bdd in
let _ =
if ((eq_sol_nb n zero_sol) && (eq_sol_nb m zero_sol))
then (
if vl > 3 then (print_string "BDD backtrack...\n"; flush stdout);
raise (No_numeric_solution (snt, bddt))
)
in
let (
bdd1, bool1, sol_nb1,
bdd2, bool2, sol_nb2
) =
let ran = Random.float 1.
and sol_nb_ratio = float_of_sol_nb (div_sol_nb n (add_sol_nb n m))
in
assert (not (Bdd.is_cst bdd));
if
ran < sol_nb_ratio
then
((Bdd.dthen bdd), true, n,
(Bdd.delse bdd), false, m )
else
((Bdd.delse bdd), false, m,
(Bdd.dthen bdd), true, n )
in
let (sl1, sl2, new_comb) =
(Value.OfIdent.add sl (Var.name var, B(bool1))),
(Value.OfIdent.add sl (Var.name var, B(bool2))),
(if Bdd.is_true comb then comb else Bdd.dthen comb)
in
try
if not (eq_sol_nb sol_nb1 zero_sol)
then (
assert (not (Bdd.is_false bdd1)) ;
draw_in_bdd_rec (snt,bddt) input memory vl ctx_msg (sl1, store) bdd1 new_comb)
else raise (No_numeric_solution (snt, bddt))
with
No_numeric_solution (snt, bddt) ->
if not (eq_sol_nb sol_nb2 zero_sol)
then (
assert (not (Bdd.is_false bdd1)) ;
draw_in_bdd_rec (snt,bddt) input memory vl ctx_msg (sl2, store) bdd2 new_comb)
else (
if vl > 3 then (print_string "BDD backtrack...\n"; flush stdout);
raise (No_numeric_solution (snt,bddt))
)
| e ->
print_string ((Printexc.to_string e) ^ "\n");
flush stdout;
assert false
and (draw_in_bdd_rec_ineq: Var.env_in -> Var.env -> int -> string -> Constraint.ineq ->
Var.env * Store.t -> Bdd.t ->
Bdd.t -> t -> t * Var.env * Store.t' * Store.p) =
fun input memory vl ctx_msg cstr (sl, store) bdd comb (snt,bddt) ->
let (n, m) = sol_number (snt,bddt) bdd in
let _ =
if ((eq_sol_nb n zero_sol) && (eq_sol_nb m zero_sol))
then (
if vl > 3 then (
print_string "BDD backtrack...\n";
flush stdout
);
raise (No_numeric_solution (snt,bddt))
)
in
let ran = Random.float 1. in
let cstr_neg = Constraint.neg_ineq cstr in
let (cstr1, bdd1, _sol_nb1, cstr2, bdd2, sol_nb2) =
if
ran < (float_of_sol_nb (div_sol_nb n (add_sol_nb n m)))
then
(cstr, (Bdd.dthen bdd), n, cstr_neg, (Bdd.delse bdd), m)
else
(cstr_neg, (Bdd.delse bdd), m, cstr, (Bdd.dthen bdd), n)
in
let store1 = Store.add_constraint store bddt (Ineq cstr1) in
try
if not (Store.is_store_satisfiable vl store1) then
raise (No_numeric_solution (snt,bddt));
draw_in_bdd_rec (snt,bddt) input memory vl ctx_msg (sl, store1) bdd1 comb
with
No_numeric_solution (snt,bddt) ->
let store2 = Store.add_constraint store bddt (Ineq cstr2) in
if
(not (eq_sol_nb sol_nb2 zero_sol))
&& Store.is_store_satisfiable vl store2
then
draw_in_bdd_rec (snt,bddt) input memory vl ctx_msg (sl, store2) bdd2 comb
else (
if vl > 3 then (
print_string "BDD backtrack...\n";
flush stdout
);
raise (No_numeric_solution(snt,bddt))
)
| e ->
print_string ((Printexc.to_string e) ^ "\n");
flush stdout;
assert false
and (draw_in_bdd_rec_eq: Var.env_in -> Var.env -> int -> string ->
Ne.t -> Var.env * Store.t ->
Bdd.t -> Bdd.t -> t -> t * Var.env * Store.t' * Store.p) =
fun input memory vl ctx_msg ne (sl, store) bdd comb (snt,bddt) ->
let (n, m) = sol_number (snt,bddt) bdd in
let _ =
if ((eq_sol_nb n zero_sol) && (eq_sol_nb m zero_sol))
then (
if vl > 3 then (
print_string "BDD backtrack...\n";
flush stdout
);
raise (No_numeric_solution (snt,bddt))
)
in
let ran0 = Random.float 1.
and ran = Random.float 1.
and cstr = (EqZ ne)
and not_cstr = (Ineq (GZ ne))
and not_cstr2 = (Ineq (GZ (Ne.neg_nexpr ne)))
in
let sol_nb_ratio = float_of_sol_nb (div_sol_nb n (add_sol_nb n m)) in
let (
cstr1, bdd1, sol_nb1,
cstr2, bdd2, sol_nb2,
cstr3, bdd3, sol_nb3) =
if
ran0 < 0.5
then
if
ran < sol_nb_ratio
then
(cstr, (Bdd.dthen bdd), n,
not_cstr, (Bdd.delse bdd), m,
not_cstr2, (Bdd.delse bdd), m)
else
(not_cstr, (Bdd.delse bdd), m,
cstr, (Bdd.dthen bdd), n,
not_cstr2, (Bdd.delse bdd), m)
else
if
ran < sol_nb_ratio
then
(cstr, (Bdd.dthen bdd), n,
not_cstr2, (Bdd.delse bdd), m,
not_cstr, (Bdd.delse bdd), m)
else
(not_cstr2, (Bdd.delse bdd), m,
cstr, (Bdd.dthen bdd), n,
not_cstr, (Bdd.delse bdd), m)
in
let store1 = Store.add_constraint store bddt cstr1 in
try
(
if
(not (Store.is_store_satisfiable vl store1)) || (sol_nb1 = zero_sol)
then
raise (No_numeric_solution (snt,bddt))
);
draw_in_bdd_rec (snt,bddt) input memory vl ctx_msg (sl, store1) bdd1 comb
with
No_numeric_solution (snt,bddt) ->
let store2 = Store.add_constraint store bddt cstr2 in
try
if
(not (Store.is_store_satisfiable vl store2)) || (sol_nb2 = zero_sol)
then
raise (No_numeric_solution (snt,bddt));
draw_in_bdd_rec (snt,bddt) input memory vl ctx_msg (sl, store2) bdd2 comb
with
No_numeric_solution (snt,bddt) ->
let store3 = Store.add_constraint store bddt cstr3 in
if
(not (Store.is_store_satisfiable vl store3)) || (sol_nb3 = zero_sol)
then (
if vl > 3 then (
print_string "BDD backtrack...\n";
flush stdout
);
raise (No_numeric_solution (snt,bddt))
);
draw_in_bdd_rec (snt,bddt) input memory vl ctx_msg (sl, store3) bdd3 comb
| e ->
print_string ((Printexc.to_string e) ^ "\n");
flush stdout;
assert false
let (draw_in_bdd: t ->
Var.env_in -> Var.env -> int -> string -> var list -> Bdd.t ->
Bdd.t -> t * Var.env * Store.t' * Store.p) =
fun t input memory vl ctx_msg num_vars_to_gen bdd comb ->
let t = build_sol_nb_table t num_vars_to_gen bdd comb in
draw_in_bdd_rec t input memory vl ctx_msg
(Value.OfIdent.empty, Store.create num_vars_to_gen) bdd comb