-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathfun_sat.ml
1897 lines (1734 loc) · 65.9 KB
/
fun_sat.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
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(**************************************************************************)
(* *)
(* Alt-Ergo: The SMT Solver For Software Verification *)
(* Copyright (C) --- OCamlPro SAS *)
(* *)
(* This file is distributed under the terms of OCamlPro *)
(* Non-Commercial Purpose License, version 1. *)
(* *)
(* As an exception, Alt-Ergo Club members at the Gold level can *)
(* use this file under the terms of the Apache Software License *)
(* version 2.0. *)
(* *)
(* --------------------------------------------------------------- *)
(* *)
(* The Alt-Ergo theorem prover *)
(* *)
(* Sylvain Conchon, Evelyne Contejean, Francois Bobot *)
(* Mohamed Iguernelala, Stephane Lescuyer, Alain Mebsout *)
(* *)
(* CNRS - INRIA - Universite Paris Sud *)
(* *)
(* --------------------------------------------------------------- *)
(* *)
(* More details can be found in the directory licenses/ *)
(* *)
(**************************************************************************)
module E = Expr
module SE = E.Set
module ME = E.Map
module Ex = Explanation
let src = Logs.Src.create ~doc:"Sat" __MODULE__
module Log = (val Logs.src_log src : Logs.LOG)
module Make (Th : Theory.S) = struct
module Inst = Instances.Make(Th)
module CDCL = Satml_frontend_hybrid.Make(Th)
exception No_suitable_decision
exception Propagate of E.gformula * Explanation.t
let is_fact_in_CDCL cdcl f =
match CDCL.is_true cdcl f with
| None -> false
| Some (ex,lvl) ->
assert (lvl <> 0 || Ex.has_no_bj (Lazy.force ex));
lvl = 0
module Heuristics = struct
type t =
{
mp : float ME.t;
(* valeur de l'increment pour l'activite des variables *)
var_inc : float;
(* inverse du facteur d'acitivte des vars, vaut 1/0.999 par defaut *)
var_decay : float;
}
let empty () =
{
mp = ME.empty;
var_inc = 1.;
var_decay = 1. /. 0.95;
}
let bump_activity ({ mp; var_inc; _ } as env) expl =
let stable = ref true in
let mp =
SE.fold
(fun f mp ->
let w = var_inc +. try ME.find f mp with Not_found -> 0. in
stable := !stable && (Float.compare w 1e100) <= 0;
ME.add f w mp
)(Ex.bj_formulas_of expl) mp
in
let mp =
if !stable then mp
else ME.fold (fun f w acc -> ME.add f (w *. 1e-100) acc) mp ME.empty
in
{ env with mp = mp; var_inc = var_inc *. env.var_decay }
let choose delta env cdcl =
let dec, no_dec =
if Options.get_no_decisions_on_is_empty () then delta, []
else
List.partition
(fun (a, _,_,_) -> Options.get_can_decide_on a.E.origin_name) delta
in
let dec =
List.rev_map
(fun ((a,b,_,_) as e) ->
if Options.get_tableaux_cdcl () && is_fact_in_CDCL cdcl a.E.ff then
raise (Propagate (a, Ex.empty));
if Options.get_tableaux_cdcl () && is_fact_in_CDCL cdcl b.E.ff then
raise (Propagate (b, Ex.empty));
e, (try (ME.find a.E.ff env.mp) with Not_found -> 0.), a.E.gf
) dec
in
if Options.get_tableaux_cdcl () then
(* force propagate modulo satML *)
List.iter
(fun (a, b, _, _) ->
match CDCL.is_true cdcl a.E.ff with
| Some (ex, _lvl) -> raise (Propagate (a, Lazy.force ex))
| None ->
match CDCL.is_true cdcl b.E.ff with
| Some (ex, _lvl) -> raise (Propagate (b, Lazy.force ex))
| None -> ()
)no_dec;
let dec =
List.fast_sort
(fun (_, x1, b1) (_, x2, b2) ->
let c = Bool.compare b2 b1 in
if c <> 0 then c
else Float.compare x2 x1
)dec
in
(*
match l with
| [] -> assert false
*)
match dec with
| [] -> raise No_suitable_decision
| (e, _, _) :: r ->
let delta =
List.fold_left (fun acc (e, _, _) -> e :: acc) no_dec (List.rev r)
in
e, delta
end
type refs = {
unit_facts : (E.gformula * Ex.t) ME.t
}
type guards = {
current_guard: E.t;
stack_elt: (E.t * refs) Stack.t;
guards: (E.gformula * Ex.t) ME.t;
}
type t = {
(* The field gamma contains the current Boolean model (true formulas) of
the SAT. Each assumed formula is mapped to a tuple (gf, ex, dlvl, plvl),
where:
- gf is the rich form of the formula
- ex is the explanation associated to the formula
- dlvl is the decision level where the formula was assumed to true
- plvl is the propagation level (w.r.t. dlvl) of the formula.
It forms with dlvl a total ordering on the formulas in gamma.
*)
gamma : (E.gformula * Ex.t * int * int) ME.t;
nb_related_to_goal : int;
nb_related_to_hypo : int;
nb_related_to_both : int;
nb_unrelated : int;
cdcl : CDCL.t ref;
tcp_cache : Th_util.answer ME.t;
delta : (E.gformula * E.gformula * Ex.t * bool) list;
decisions : int ME.t;
dlevel : int;
plevel : int;
ilevel : int;
tbox : Th.t;
unit_tbox : Th.t; (* theory env of facts at level 0 *)
inst : Inst.t;
heuristics : Heuristics.t ref;
model_gen_phase : bool ref;
guards : guards;
add_inst: E.t -> bool;
unit_facts_cache : (E.gformula * Ex.t) ME.t ref;
last_saved_model : Models.t Lazy.t option ref;
unknown_reason : Sat_solver_sig.unknown_reason option;
declare_top : Id.typed list ref;
declare_tail : Id.typed list Stack.t;
(** Stack of the declared symbols by the user. The field [declare_top]
is the top of the stack and [declare_tail] is tail. In particular, this
stack is never empty. *)
}
let reset_refs () =
Steps.reset_steps ()
let save_guard_and_refs env new_guard =
let refs = {unit_facts = !(env.unit_facts_cache)} in
Stack.push (new_guard,refs) env.guards.stack_elt;
Steps.push_steps ()
let restore_guards_and_refs env =
let guard,refs = Stack.pop env.guards.stack_elt in
Steps.pop_steps ();
{ env with
unit_facts_cache = ref refs.unit_facts}, guard
exception Sat of t
exception Unsat of Explanation.t
exception I_dont_know of t
exception IUnsat of Ex.t * SE.t list
let i_dont_know env ur =
raise (I_dont_know {env with unknown_reason = Some ur})
(*BISECT-IGNORE-BEGIN*)
module Debug = struct
open Printer
let print_nb_related env =
if Options.get_verbose () then
print_dbg ~module_name:"Fun_sat" ~function_name:"print_nb_related"
"@[<v 0>----------------------------------------------------@ \
nb_related_to_both = %d@ \
nb_related_to_goal = %d@ \
nb_related_to_hypo = %d@ \
nb_unrelated = %d@ \
----------------------------------------------------@]"
env.nb_related_to_both
env.nb_related_to_goal
env.nb_related_to_hypo
env.nb_unrelated
let propagations (env, bcp, tcp, ap_delta, lits) =
if Options.get_debug_sat () then
print_dbg ~module_name:"Fun_sat" ~function_name:"propagations"
"|lits| = %d, B = %b, T = %b, \
|Delta| = %d, |ap_Delta| = %d"
(List.length lits) bcp tcp
(List.length env.delta)
(List.length ap_delta)
let is_it_unsat gf =
let s =
match E.form_view gf.E.ff with
| E.Lemma _ -> "lemma"
| E.Clause _ -> "clause"
| E.Unit _ -> "conjunction"
| E.Skolem _ -> "skolem"
| E.Literal _ -> "literal"
| E.Iff _ -> "iff"
| E.Xor _ -> "xor"
| E.Let _ -> "let"
in
if Options.get_verbose () && Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"is_it_unsat"
"the following %s is unsat ? :@ %a"
s E.print gf.E.ff
let pred_def f =
if Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"pred_def"
"I assume a predicate: %a" E.print f
let unsat_rec dep =
if Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"unsat_rec"
"unsat_rec : %a" Ex.print dep
let assume gf dep env =
if Options.get_debug_sat () then
let { E.ff = f; lem; from_terms = terms; _ } = gf in
print_dbg ~flushed:false
~module_name:"Fun_sat" ~function_name:"assume"
"at level (%d, %d) I assume a @ " env.dlevel env.plevel;
begin match E.form_view f with
| E.Literal a ->
let n = match lem with
| None -> ""
| Some ff -> begin
match E.form_view ff with
| E.Lemma xx -> xx.E.name
| E.Unit _ | E.Clause _ | E.Literal _ | E.Skolem _
| E.Let _ | E.Iff _ | E.Xor _ -> ""
end
in
print_dbg ~header:false
"LITERAL (%s : %a) %a@ "
n E.print_list terms E.print a
| E.Unit _ ->
print_dbg ~header:false "conjunction"
| E.Clause _ ->
print_dbg ~header:false "clause %a" E.print f
| E.Lemma _ ->
print_dbg ~header:false "%d-atom lemma \"%a\"" (E.size f) E.print f
| E.Skolem _ ->
print_dbg ~header:false "skolem %a" E.print f
| E.Let _ ->
print_dbg ~header:false "let-in %a" E.print f
| E.Iff _ ->
print_dbg ~header:false "equivalence %a" E.print f
| E.Xor _ ->
print_dbg ~header:false "neg-equivalence/xor %a" E.print f
end;
if Options.get_verbose () then
print_dbg ~header:false
"with explanations : %a" Explanation.print dep
let unsat () =
if Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"unsat"
"unsat"
let decide f env =
if Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"decide"
"I decide: at level (%d, %d), on %a"
env.dlevel env.plevel E.print f
let instantiate env =
if Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"instanciate"
"I instantiate at level (%d, %d). Inst level = %d"
env.dlevel env.plevel env.ilevel
let backtracking f env =
if Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"backtracking"
"backtrack: at level (%d, %d), and assume not %a"
env.dlevel env.plevel E.print f
let backjumping f env =
if Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"backjumping"
"backjump: at level (%d, %d), I ignore the case %a"
env.dlevel env.plevel E.print f
let elim _ _ =
if Options.(get_debug_sat () && get_verbose ()) then
print_dbg
~module_name:"Fun_sat" ~function_name:"elim"
"elim"
let red _ _ =
if Options.(get_debug_sat () && get_verbose ()) then
print_dbg
~module_name:"Fun_sat" ~function_name:"red"
"red"
(* let delta d =
print_dbg ~debug:(get_verbose () || get_debug_sat ())
"[sat] - Delta ---------------------";
List.iter (fun (f1, f2, ex) ->
print_dbg ~debug:(get_verbose () || get_debug_sat ())
"(%a or %a), %a"
E.print f1.E.ff E.print f2.E.ff Ex.print ex) d;
print_dbg ~debug:(get_verbose () || get_debug_sat ())
"[sat] --------------------- Delta -" *)
let gamma g =
if Options.(get_debug_sat () && get_verbose ()) then begin
print_dbg ~module_name:"Fun_sat" ~function_name:"gamma"
"@[<v 0>--- GAMMA ---------------------@ ";
ME.iter (fun f (_, ex, dlvl, plvl) ->
print_dbg ~header:false
"(%d, %d) %a \t->\t%a@ "
dlvl plvl E.print f Ex.print ex) g;
print_dbg ~header:false
" - / GAMMA ---------------------@]";
end
let bottom classes =
if Options.get_bottom_classes () then
print_dbg "bottom:%a@?" E.print_tagged_classes classes
let inconsistent expl env =
if Options.get_debug_sat () then
print_dbg
~module_name:"Fun_sat" ~function_name:"inconsistent"
"inconsistent at level (%d, %d), reason : %a"
env.dlevel env.plevel Ex.print expl
let in_mk_theories_instances () =
if Options.(get_debug_fpa() > 0 || get_debug_sat ()) then
print_dbg
~module_name:"Fun_sat" ~function_name:"in_mk_theories_instances"
"entering mk_theories_instances:"
let out_mk_theories_instances normal_exit =
if Options.(get_debug_fpa () > 0 || get_debug_sat ()) then
print_dbg
~module_name:"Fun_sat" ~function_name:"out_mk_theories_instances"
(if normal_exit then
"normal exit of mk_theories_instances."
else
"exit mk_theories_instances with Inconsist.")
let print_f_conj fmt hyp =
match hyp with
| [] -> Format.fprintf fmt "True";
| e::l ->
Format.fprintf fmt "%a" E.print e;
List.iter (fun f -> Format.fprintf fmt " /\\ %a" E.print f) l
let print_theory_instance hyp gf =
if Options.get_debug_fpa() > 1 || Options.get_debug_sat() then
print_dbg
~module_name:"Fun_sat" ~function_name:"print_theory_instances"
"@[<v 2>@ %s >@ \
hypotheses: %a@ \
conclusion: %a@]"
(E.name_of_lemma_opt gf.E.lem)
print_f_conj hyp
E.print gf.E.ff
end
(*BISECT-IGNORE-END*)
let selector env f orig =
not (ME.mem f env.gamma)
&& begin match E.form_view orig with
| E.Lemma _ -> env.add_inst orig
| E.Unit _ | E.Clause _ | E.Literal _ | E.Skolem _
| E.Let _ | E.Iff _ | E.Xor _ -> true
end
let inst_predicates mconf env inst tbox selector ilvl =
try Inst.m_predicates mconf inst tbox selector ilvl
with Ex.Inconsistent (expl, classes) ->
Debug.inconsistent expl env;
Options.tool_req 2 "TR-Sat-Conflict-2";
env.heuristics := Heuristics.bump_activity !(env.heuristics) expl;
raise (IUnsat (expl, classes))
let inst_lemmas mconf env inst tbox selector ilvl =
try Inst.m_lemmas mconf inst tbox selector ilvl
with Ex.Inconsistent (expl, classes) ->
Debug.inconsistent expl env;
Options.tool_req 2 "TR-Sat-Conflict-2";
env.heuristics := Heuristics.bump_activity !(env.heuristics) expl;
raise (IUnsat (expl, classes))
(* sat-solver *)
let mk_gf f name mf gf =
{ E.ff = f;
origin_name = name;
gdist = -1;
hdist = -1;
nb_reductions = 0;
trigger_depth = max_int;
age= 0;
lem= None;
from_terms = [];
mf= mf;
gf= gf;
theory_elim = true; }
(* hybrid functions*)
let print_decisions_in_the_sats msg env =
if Options.(get_tableaux_cdcl () && get_verbose ()) then begin
Printer.print_dbg ~flushed:false ~module_name:"Fun_sat"
~function_name:"print_decisions_in_the_sats"
"@[<v 0>-----------------------------------------------------@ \
>> %s@ \
decisions in DfsSAT are:@ "
msg;
let l = ME.bindings env.decisions in
let l = List.fast_sort (fun (_,i) (_,j) -> j - i) l in
List.iter
(fun (f, i) ->
Printer.print_dbg ~flushed:false ~header:false
"%d -> %a@ " i E.print f
)l;
Printer.print_dbg ~flushed:false ~header:false
"decisions in satML are:@ ";
List.iter
(fun (i, f) ->
Printer.print_dbg ~flushed:false ~header:false
"%d -> %a@ " i E.print f
)(CDCL.get_decisions !(env.cdcl));
Printer.print_dbg ~header:false
"-----------------------------------------------------@]"
end
let cdcl_same_decisions env =
if Options.get_tableaux_cdcl () then begin
let cdcl_decs = CDCL.get_decisions !(env.cdcl) in
let ok = ref true in
let decs =
List.fold_left
(fun decs (i, d) ->
try
let j = ME.find d decs in
assert (i = j);
ME.remove d decs
with Not_found ->
ok := false;
Printer.print_err
"Ouch! Decision %a is only in satML!@,\
nb decisions in DfsSAT: %d\
nb decisions in satML: %d"
E.print d
(ME.cardinal env.decisions)
(List.length cdcl_decs);
decs
)env.decisions cdcl_decs
in
if decs != ME.empty then begin
Printer.print_err "Ouch! Some decisions are only in DfsSAT";
ok := false;
end;
!ok
end
else true
let cdcl_known_decisions ex env =
Ex.fold_atoms
(fun e b ->
match e with
| Ex.Bj f -> b && ME.mem f env.decisions
| _ -> b
)ex true
let shift gamma ex acc0 =
let l =
Ex.fold_atoms
(fun e acc ->
match e with
| Ex.Bj f ->
let dec =
try let _,_,dec,_ = ME.find f gamma in dec
with Not_found -> max_int
in
(f, dec) :: acc
| _ ->
acc
)ex []
in
(* try to keep the decision ordering *)
let l = List.fast_sort (fun (_,i) (_,j) -> j - i) l in
List.fold_left (fun acc (f, _) -> E.mk_imp f acc) acc0 l
let cdcl_assume delay env l =
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg
~module_name:"Fun_sat" ~function_name:"cdcl_assume" "";
let gamma = env.gamma in
try
let l =
List.rev_map
(fun ((gf, ex) as e) ->
if Ex.has_no_bj ex then e
else {gf with E.ff = shift gamma ex gf.E.ff}, Ex.empty
)(List.rev l)
in
env.cdcl := CDCL.assume delay !(env.cdcl) l
with
| CDCL.Bottom (ex, l, cdcl) ->
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg
~module_name:"Fun_sat" ~function_name:"cdcl_assume"
"conflict";
env.cdcl := cdcl;
assert (cdcl_known_decisions ex env);
raise (IUnsat(ex, l))
let cdcl_decide env f dlvl =
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg
~module_name:"Fun_sat" ~function_name:"cdcl_decide" "";
try
env.cdcl := CDCL.decide !(env.cdcl) f dlvl
with
| CDCL.Bottom (ex, l, _cdcl) ->
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg
~module_name:"Fun_sat" ~function_name:"cdcl_decide"
"conflict";
assert (cdcl_known_decisions ex env);
(* no need to save cdcl here *)
raise (IUnsat(ex, l))
| e ->
Printer.print_err "%s" (Printexc.to_string e);
assert false
let cdcl_forget_decision env f lvl =
try
env.cdcl := CDCL.forget_decision !(env.cdcl) f lvl
with
| _ ->
Printer.print_err
"@[<v 2>cdcl_backjump error:@,%s@]"
(Printexc.get_backtrace ());
assert false
let cdcl_learn_clause delay env ex acc0 =
let f = shift env.gamma ex acc0 in
let ff = mk_gf f "<cdcl_learn_clause>" true true in
cdcl_assume delay env [ff, Ex.empty]
let profile_conflicting_instances exp =
if Options.get_profiling () then
SE.iter
(fun f ->
match E.form_view f with
| E.Lemma { E.name; loc; _ } ->
Profiling.conflicting_instance name loc
| E.Unit _ | E.Clause _ | E.Literal _ | E.Skolem _
| E.Let _ | E.Iff _ | E.Xor _ -> ()
)(Ex.formulas_of exp)
let do_case_split env origin =
try
if Options.get_debug_sat () then
Printer.print_dbg
~module_name:"Fun_sat" ~function_name:"do_case_split"
"performing case-split";
let tbox, new_terms = Th.do_case_split env.tbox origin in
let inst =
Inst.add_terms env.inst new_terms (mk_gf E.vrai "" false false) in
{env with tbox = tbox; inst = inst}
with Ex.Inconsistent (expl, classes) ->
Debug.inconsistent expl env;
Options.tool_req 2 "TR-Sat-Conflict-2";
env.heuristics := Heuristics.bump_activity !(env.heuristics) expl;
raise (IUnsat (expl, classes))
let b_elim f env =
try
let _ = ME.find f env.gamma in
Options.tool_req 2 "TR-Sat-Bcp-Elim-1";
if Options.get_profiling() then Profiling.elim true;
true
with Not_found -> false
let update_unit_facts env ff dep =
let f = ff.E.ff in
if Options.get_sat_learning ()
&& not (ME.mem f !(env.unit_facts_cache)) then
begin
assert (Ex.has_no_bj dep);
env.unit_facts_cache := ME.add f (ff, dep) !(env.unit_facts_cache)
end
let learn_clause ({ gamma; _ } as env) ff0 dep =
if Options.get_sat_learning () then
let fl, dep =
Ex.fold_atoms
(fun e (l, ex) ->
match e with
| Ex.Bj f ->
let d =
try let _,_,d,_ = ME.find f gamma in d
with Not_found -> max_int
in
(E.neg f, d) :: l, ex
| _ -> l, Ex.add_fresh e ex
)dep ([], Ex.empty)
in
let fl = List.fast_sort (fun (_, d1) (_,d2) -> d1 - d2) fl in
let f =
List.fold_left
(fun acc (f, _) -> E.mk_or f acc false)
ff0.E.ff fl
in
update_unit_facts env {ff0 with E.ff=f} dep
let query_of tcp_cache tmp_cache ff a env =
try ME.find a !tcp_cache
with Not_found ->
try ME.find a !tmp_cache
with Not_found ->
assert (E.is_ground a);
match Th.query a env.tbox with
| None -> tmp_cache := ME.add a None !tmp_cache; None
| Some (ex,_) as y ->
if Options.get_tableaux_cdcl () then
cdcl_learn_clause true env ex (ff.E.ff);
learn_clause env ff ex;
tcp_cache := ME.add a y !tcp_cache; y
let th_elim tcp_cache tmp_cache ff env =
match E.form_view ff.E.ff with
| E.Literal a ->
let ans = query_of tcp_cache tmp_cache ff a env in
if ans != None then
begin
Options.tool_req 2 "TR-Sat-Bcp-Elim-2";
if Options.get_profiling() then Profiling.elim false;
end;
ans
| E.Unit _ | E.Clause _ | E.Lemma _ | E.Skolem _
| E.Let _ | E.Iff _ | E.Xor _ -> None
let red tcp_cache tmp_cache ff env tcp =
let nf = E.neg ff.E.ff in
let nff = {ff with E.ff = nf} in
try
let _, ex = ME.find nf !(env.unit_facts_cache) in
Some(ex, []), true
with Not_found ->
try
let _, ex, _, _ = ME.find nf env.gamma in
let r = Some (ex, Th.cl_extract env.tbox) in
Options.tool_req 2 "TR-Sat-Bcp-Red-1";
r, true
with Not_found ->
if not tcp then None, false
else match E.form_view nf with
| E.Literal a ->
let ans = query_of tcp_cache tmp_cache nff a env in
if ans != None then Options.tool_req 2 "TR-Sat-Bcp-Red-2";
ans, false
| E.Unit _ | E.Clause _ | E.Lemma _ | E.Skolem _
| E.Let _ | E.Iff _ | E.Xor _ -> None, false
let red tcp_cache tmp_cache ff env tcp =
match red tcp_cache tmp_cache ff env tcp with
| (Some _, _) as ans -> ans
| None, b ->
if not (Options.get_tableaux_cdcl ()) then
None, b
else
match CDCL.is_true !(env.cdcl) (E.neg ff.E.ff) with
| Some (ex, _lvl) ->
let ex = Lazy.force ex in
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg "red thanks to satML";
assert (cdcl_known_decisions ex env);
Some(ex, []), true
| None ->
None, b
let add_dep f dep =
match E.form_view f with
| E.Literal _ ->
if not (Options.get_unsat_core ()) || Ex.mem (Ex.Bj f) dep then dep
else Ex.union (Ex.singleton (Ex.Dep f)) dep
| E.Clause _ ->
if Options.get_unsat_core () then Ex.union (Ex.singleton (Ex.Dep f)) dep
else dep
| E.Unit _ | E.Lemma _ | E.Skolem _ | E.Let _ | E.Iff _ | E.Xor _ -> dep
let rec add_dep_of_formula f dep =
let dep = add_dep f dep in
match E.form_view f with
| E.Unit (f1, f2) ->
if not (Options.get_unsat_core ()) then dep
else add_dep_of_formula f2 (add_dep_of_formula f1 dep)
| E.Lemma _ | E.Clause _ | E.Literal _ | E.Skolem _
| E.Let _ | E.Iff _ | E.Xor _ -> dep
(* currently:
=> this is not done modulo theories
=> unit_facts_cache not taken into account *)
let update_distances =
let aux gf ff =
let gdist = max ff.E.gdist gf.E.gdist in
let hdist = max ff.E.hdist gf.E.hdist in
let gdist = if gdist < 0 then gdist else gdist + 1 in
let hdist = if hdist < 0 then hdist else hdist + 1 in
{gf with E.gdist; hdist}
in
fun env gf red ->
let nf = E.neg red in
try let ff, _ = ME.find nf !(env.unit_facts_cache) in aux gf ff
with Not_found ->
try let ff, _, _, _ = ME.find nf env.gamma in aux gf ff
with Not_found -> gf
let do_bcp env tcp tcp_cache tmp_cache delta acc =
let tcp = tcp && not (Options.get_no_tcp ()) in
List.fold_left
(fun (cl,u)
((({ E.ff = f1; _ } as gf1), ({ E.ff = f2; _ } as gf2), d, _) as fd) ->
Debug.elim gf1 gf2;
if b_elim f1 env || b_elim f2 env then (cl,u)
else
try
if not tcp then raise Exit;
assert (gf1.E.theory_elim == gf2.E.theory_elim);
let u =
match th_elim tcp_cache tmp_cache gf1 env,
th_elim tcp_cache tmp_cache gf2 env with
| None, None -> raise Exit
| Some _, _ | _, Some _ when gf1.E.theory_elim -> u
| Some _, Some _ ->
u (* eliminate if both are true ? why ? *)
(*(gf1, Ex.union d d1) :: (gf2, Ex.union d d2) :: u*)
| Some (d1, _), _ -> (gf1, Ex.union d d1) :: u
| _, Some (d2, _) -> (gf2, Ex.union d d2) :: u
in
cl, u
with Exit ->
begin
Debug.red gf1 gf2;
match
red tcp_cache tmp_cache gf1 env tcp,
red tcp_cache tmp_cache gf2 env tcp
with
| (Some (d1, c1), b1) , (Some (d2, c2), b2) ->
if Options.get_profiling() then Profiling.bcp_conflict b1 b2;
let expl = Ex.union (Ex.union d d1) d2 in
let c = List.rev_append c1 c2 in
raise (Ex.Inconsistent (expl, c))
| (Some(d1, _), b) , (None, _) ->
if Options.get_profiling() then Profiling.red b;
let gf2 =
{gf2 with E.nb_reductions = gf2.E.nb_reductions + 1} in
let gf2 = update_distances env gf2 f1 in
cl, (gf2,Ex.union d d1) :: u
| (None, _) , (Some(d2, _),b) ->
if Options.get_profiling() then Profiling.red b;
let gf1 =
{gf1 with E.nb_reductions = gf1.E.nb_reductions + 1} in
let gf1 = update_distances env gf1 f2 in
cl, (gf1,Ex.union d d2) :: u
| (None, _) , (None, _) -> fd::cl , u
end
) acc delta
let theory_assume env facts =
Options.tool_req 2 "TR-Sat-Assume-Lit";
if facts == [] then env
else
let facts, ufacts, inst, mf, gf =
List.fold_left
(fun (facts, ufacts, inst, mf, gf) (a, ff, ex, dlvl, plvl) ->
if not (E.is_ground a) then begin
Printer.print_err
"%a is not ground" E.print a;
assert false
end;
let alit = Shostak.Literal.make (LTerm a) in
let facts = (alit, Th_util.Other, ex, dlvl, plvl) :: facts in
let ufacts =
if Ex.has_no_bj ex then
(alit, Th_util.Other, ex, dlvl, plvl) :: ufacts
else ufacts
in
if not ff.E.mf then begin
Printer.print_err
"%a" E.print ff.E.ff;
assert false
end;
let inst =
if ff.E.mf then Inst.add_terms inst (E.max_terms_of_lit a) ff
else inst
in
facts, ufacts, inst, mf || ff.E.mf, gf || ff.E.gf
)([], [], env.inst, false, false) facts
in
let utbox, _, _ = (* assume unit facts in the theory *)
if ufacts != [] && env.dlevel > 0 then
try Th.assume ~ordered:false ufacts env.unit_tbox
with Ex.Inconsistent (reason, _) as e ->
assert (Ex.has_no_bj reason);
if Options.get_profiling() then Profiling.theory_conflict();
if Options.get_debug_sat () then
Printer.print_dbg
~module_name:"Fun_sat" ~function_name:"theory_assume"
"solved by unit_tbox";
raise e
else env.unit_tbox, SE.empty, 0
in
let tbox, new_terms, cpt =
try Th.assume facts env.tbox
with Ex.Inconsistent _ as e ->
if Options.get_profiling() then Profiling.theory_conflict();
raise e
in
let utbox = if env.dlevel = 0 then tbox else utbox in
let inst = Inst.add_terms inst new_terms (mk_gf E.vrai "" mf gf) in
Steps.incr (Th_assumed cpt);
{ env with tbox = tbox; unit_tbox = utbox; inst = inst }
let propagations ((env, bcp, tcp, ap_delta, lits) as result) =
let env = theory_assume env lits in
let env = do_case_split env Util.AfterTheoryAssume in
Debug.propagations result;
let tcp_cache = ref env.tcp_cache in
let tmp_cache = ref ME.empty in
let acc =
if bcp then do_bcp env tcp tcp_cache tmp_cache env.delta ([], [])
else env.delta, [] (* no even bcp for old clauses *)
in
(*both bcp and tcp set to true for new clauses*)
let delta, unit = do_bcp env true tcp_cache tmp_cache ap_delta acc in
{env with delta = delta; tcp_cache = !tcp_cache}, unit
let update_nb_related t ff =
let gdist = ff.E.gdist in
let hdist = ff.E.hdist in
match gdist >= 0, hdist >= 0 with
| true , false -> {t with nb_related_to_goal = t.nb_related_to_goal + 1}
| false, true -> {t with nb_related_to_hypo = t.nb_related_to_hypo + 1}
| false, false -> {t with nb_unrelated = t.nb_unrelated + 1}
| true , true ->
(* update these three counter to simplify comparaisons
in the rest of the module: both+1 imples goal+1 *)
{t with
nb_related_to_both = t.nb_related_to_both + 1;
nb_related_to_goal = t.nb_related_to_goal + 1;
nb_related_to_hypo = t.nb_related_to_hypo + 1}
let rec asm_aux acc list =
List.fold_left
(fun
((env, _bcp, tcp, ap_delta, lits) as acc)
({ E.ff = f; _ } as ff, dep) ->
Options.exec_thread_yield ();
let dep = add_dep f dep in
let dep_gamma = add_dep_of_formula f dep in
(* propagate all unit facts to cache *)
if Options.get_sat_learning () && Ex.has_no_bj dep_gamma then
update_unit_facts env ff dep_gamma;
Debug.gamma env.gamma;
(try
let _, ex_nf, _, _ = ME.find (E.neg f) env.gamma in
Options.tool_req 2 "TR-Sat-Conflict-1";
if Options.get_profiling() then Profiling.bool_conflict ();
let exx = Ex.union dep_gamma ex_nf in
(*
missing VSID, but we have regressions when it is activated
env.heuristics := Heuristics.bump_activity !(env.heuristics) exx;*)
raise (IUnsat (exx, Th.cl_extract env.tbox))
with Not_found -> ());
if ME.mem f env.gamma then begin
Options.tool_req 2 "TR-Sat-Remove";
acc
end
else
let env =
if ff.E.mf && Options.get_greedy () then
{ env with inst=
Inst.add_terms
env.inst (E.max_ground_terms_rec_of_form f) ff }
else env
in
Debug.assume ff dep env;
let env =
{ env with
gamma = ME.add f (ff,dep_gamma,env.dlevel,env.plevel) env.gamma;
plevel = env.plevel + 1;
}
in
let env = update_nb_related env ff in
match E.form_view f with
| E.Iff (f1, f2) ->
let g = E.elim_iff f1 f2 ~with_conj:true in
if Options.get_tableaux_cdcl () then begin
let f_imp_g = E.mk_imp f g in
(* correct to put <-> ?*)
cdcl_assume false env [{ff with E.ff=f_imp_g}, Ex.empty]
end;
asm_aux (env, true, tcp, ap_delta, lits) [{ff with E.ff = g}, dep]
| E.Xor (f1, f2) ->
let g = E.elim_iff f1 f2 ~with_conj:false |> E.neg in
if Options.get_tableaux_cdcl () then begin
let f_imp_g = E.mk_imp f g in
(* should do something similar for Let ? *)
cdcl_assume false env [{ff with E.ff=f_imp_g}, Ex.empty]
end;
asm_aux (env, true, tcp, ap_delta, lits) [{ff with E.ff = g}, dep]
| E.Unit (f1, f2) ->
Options.tool_req 2 "TR-Sat-Assume-U";
let lst = [{ff with E.ff=f1},dep ; {ff with E.ff=f2},dep] in
asm_aux (env, true, tcp, ap_delta, lits) lst
| E.Clause(f1,f2,is_impl) ->
Options.tool_req 2 "TR-Sat-Assume-C";
let p1 = {ff with E.ff=f1} in
let p2 = {ff with E.ff=f2} in
let p1, p2 =
if is_impl || E.size f1 <= E.size f2 then p1, p2 else p2, p1
in
env, true, tcp, (p1,p2,dep,is_impl)::ap_delta, lits
| E.Lemma _ ->
Options.tool_req 2 "TR-Sat-Assume-Ax";
let inst_env = Inst.add_lemma env.inst ff dep in
if Options.get_tableaux_cdcl () then