forked from OCamlPro/alt-ergo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsatml_frontend.ml
More file actions
1411 lines (1276 loc) · 47.2 KB
/
Copy pathsatml_frontend.ml
File metadata and controls
1411 lines (1276 loc) · 47.2 KB
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) 2013-2024 --- 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 X = Shostak.Combine
module Make (Th : Theory.S) : Sat_solver_sig.S = struct
module SAT = Satml.Make(Th)
module Inst = Instances.Make(Th)
module Ex = Explanation
module E = Expr
module ME = E.Map
module SE = E.Set
module Atom = Satml_types.Atom
module FF = Satml_types.Flat_Formula
let reset_refs () = Steps.reset_steps ()
type guards = {
mutable current_guard: E.t;
stack_guard: E.t Stack.t;
}
type t = {
satml : SAT.t;
mutable ff_hcons_env : FF.hcons_env;
mutable nb_mrounds : int;
mutable last_forced_normal : int;
mutable last_forced_greedy : int;
mutable gamma : (int * FF.t option) ME.t;
mutable conj : (int * SE.t) FF.Map.t;
mutable abstr_of_axs : (FF.t * Atom.atom) ME.t;
mutable axs_of_abstr : (E.t * Atom.atom) ME.t;
mutable proxies : FF.proxies;
mutable inst : Inst.t;
mutable skolems : E.gformula ME.t; (* key <-> f *)
add_inst : E.t -> bool;
guards : guards;
mutable last_saved_model : Models.t Lazy.t option;
mutable last_saved_objectives : Objective.Model.t option;
mutable unknown_reason : Sat_solver_sig.unknown_reason option;
(** The reason why satml raised [I_dont_know] if it does; [None] by
default. *)
mutable declare_top : Id.typed list;
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 empty_guards () = {
current_guard = Expr.vrai;
stack_guard = Stack.create ();
}
let init_guards () =
let guards = empty_guards () in
Stack.push Expr.vrai guards.stack_guard;
guards
let empty ?(selector=fun _ -> true) () =
let ff_hcons_env = FF.empty_hcons_env () in
{ gamma = ME.empty;
satml = SAT.create (FF.atom_hcons_env ff_hcons_env);
ff_hcons_env ;
nb_mrounds = 0;
last_forced_normal = 0;
last_forced_greedy = 0;
conj = FF.Map.empty;
abstr_of_axs = ME.empty;
axs_of_abstr = ME.empty;
proxies = FF.empty_proxies;
inst = Inst.empty;
skolems = ME.empty;
guards = init_guards ();
add_inst = selector;
last_saved_model = None;
last_saved_objectives = None;
unknown_reason = None;
declare_top = [];
declare_tail = Stack.create ();
}
exception Sat
exception Unsat of Explanation.t
exception I_dont_know
let i_dont_know env ur =
env.unknown_reason <- Some ur;
raise I_dont_know
exception IUnsat of t * Explanation.t
let mk_gf f =
{ E.ff = f;
trigger_depth = max_int;
nb_reductions = 0;
origin_name = "<none>";
age = 0;
lem = None;
mf = false;
gf = false;
gdist = -1;
hdist = -1;
from_terms = [];
theory_elim = true;
}
(*BISECT-IGNORE-BEGIN*)
module Debug = struct
open Printer
let pred_def f =
if Options.get_debug_sat () then
print_dbg
~module_name:"Satml_frontend" ~function_name:"pred_def"
"I assume a predicate: %a" E.print f
let unsat gf =
if Options.get_debug_sat () then
print_dbg
~module_name:"Satml_frontend" ~function_name:"unsat"
"unsat of %a ?" E.print gf.E.ff
let assume gf =
let { E.ff = f; lem; from_terms = terms; _ } = gf in
if Options.get_debug_sat () then begin
match E.form_view f with
| E.Unit _ -> ()
| E.Clause _ ->
print_dbg ~module_name:"Satml_frontend" ~function_name:"assume"
"I assume a clause %a" E.print f
| E.Lemma _ ->
print_dbg ~module_name:"Satml_frontend" ~function_name:"assume"
"I assume a [%d-atom] lemma: %a"
(E.size f) E.print f
| 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 ~module_name:"Satml_frontend" ~function_name:"assume"
"@[<v 0>I assume a literal (%s : %a) %a@,\
================================================@]"
n E.print_list terms E.print a;
| E.Skolem _ ->
print_dbg ~module_name:"Satml_frontend" ~function_name:"assume"
"I assume a skolem %a" E.print f
| E.Let _ ->
print_dbg ~module_name:"Satml_frontend" ~function_name:"assume"
"I assume a let-In %a" E.print f
| E.Iff _ ->
print_dbg ~module_name:"Satml_frontend" ~function_name:"assume"
"I assume an equivalence %a" E.print f
| E.Xor _ ->
print_dbg ~module_name:"Satml_frontend" ~function_name:"assume"
"I assume a neg-equivalence/Xor %a" E.print f
end
let simplified_form f f' =
if Options.(get_debug_sat () && get_verbose ()) then
print_dbg
~module_name:"Satml_frontend" ~function_name:"simplified_form"
"@[<v 2>Simplified form of: %a@,is: %a@]"
E.print f
FF.print f'
(* unused --
let cnf_form f unit non_unit =
if get_debug_sat () && get_verbose () then begin
print_dbg "[sat] CFF form of: %a" FF.print f;
print_dbg " is:";
List.iter
(List.iter (fun a ->
print_dbg "UNIT: %a" Atom.pr_atom a))
unit;
List.iter
(fun c ->
print_dbg "CLAUSE: ";
List.iter (fun a ->
print_dbg "%a or " Atom.pr_atom a) c;
)non_unit
end
*)
let model fmt env =
if Options.get_debug_sat () then
let model = SAT.boolean_model env.satml in
let print fmt a =
Format.fprintf fmt " %f | %a@,"
(Atom.weight a)
Atom.pr_atom a
in
Format.fprintf fmt
"@[<v 2>(2) satML's model:@,%a@]"
(pp_list_no_space print) (List.rev model)
let new_instances mode env =
if Options.get_debug_sat () then begin
print_dbg ~flushed:false
~module_name:"Satml_frontend" ~function_name:"new_instances"
"@[<v 2>I GENERATE NEW INSTANCES (%s)#################@,\
@[<v 2>(1) ground problem:@,"
mode;
FF.Map.iter (fun f (md, _) ->
print_dbg ~flushed:false ~header:false
"-> %d : %a@," md FF.print f) env.conj;
print_dbg ~header:false "@]@,%a"
model env;
end
(* unused --
let generated_instances l =
if get_verbose () && get_debug_sat () then begin
print_dbg "[new_instances] %d generated" (List.length l);
List.iter (fun { E.ff = f; origin_name; _ } ->
print_dbg " instance(origin = %s): %a" origin_name E.print f;
) l
end
*)
(* unused --
let trivial_fact p inst =
if get_verbose () && get_debug_sat () then begin
if inst then
print_dbg "already known instance: %a" E.print p
else
print_dbg "already known skolem: %a" E.print p
end
*)
(* unused --
let generated_skolems l =
if get_verbose () && get_debug_sat () then begin
print_dbg "[new_skolems] %d generated" (List.length l);
List.iter (fun { E.ff = f; _ } ->
print_dbg " skolem: %a" E.print f) l
end
*)
let atoms_from_sat_branch f =
if Options.(get_verbose () && get_debug_sat ()) then
print_dbg
~module_name:"Satml_frontend" ~function_name:"atoms_from_sat_branch"
"[extract_and_add_terms from] %a" FF.print f
let add_terms_of src terms =
if Options.(get_verbose () && get_debug_sat ()) then begin
print_dbg ~flushed:false ~module_name:"Satml_frontend"
~function_name:"add_terms_of"
"@[<v 2>[%s] add_terms_of:@," src;
SE.iter (fun e ->
print_dbg ~flushed:false ~header:false
">> %a@," E.print e) terms;
print_dbg ~header:false "@]"
end
(* unused --
let axiom_def f =
if get_debug_sat () then
print_dbg
(asprintf "[sat] I assume an axiom: %a" E.print f)
*)
let internal_axiom_def f a at =
if Options.get_debug_sat () then
print_dbg
~module_name:"Satml_frontend" ~function_name:"internal_axiom_def"
"I assume an internal axiom: %a <-> %a@,\
at of a is %a"
E.print a E.print f
Atom.pr_atom at
(* unused --
let in_mk_theories_instances () =
if Options.get_debug_fpa() > 0 || get_debug_sat() then
print_dbg
"[sat] entering mk_theories_instances:"
*)
(* unused --
let out_mk_theories_instances normal_exit =
if Options.get_debug_fpa() > 0 || get_debug_sat() then
if normal_exit then
print_dbg "[sat] normal exit of mk_theories_instances."
else
print_dbg "exit mk_theories_instances with Inconsistency."
*)
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:"Satml_frontend" ~function_name:"theory_instance"
"@[<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 make_explanation _ = Ex.empty
(*
if get_debug_sat () then
fprintf fmt "make_explanation of %d clauses@." (List.length lc);
List.fold_left
(fun ex ({ST.form = f} as c) ->
if get_debug_sat () then
fprintf fmt "unsat_core: %a@." Atom.pr_clause c;
Ex.union (Ex.singleton (Ex.Dep f)) ex
)Ex.empty lc*)
let selector env f orig =
(Options.get_cdcl_tableaux () || 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
(* <begin> copied from sat_solvers.ml *)
let reduce_filters acc (hyp, gf, dep) =
Debug.print_theory_instance hyp gf;
let clause =
List.fold_left
(fun tmp f ->
(* we cannot reduce like in DfsSAT *)
E.mk_or (E.neg f) tmp false
)gf.E.ff hyp
in
({gf with E.ff=clause}, dep) :: acc
let mk_theories_instances do_syntactic_matching _remove_clauses env acc =
let t_match = Inst.matching_terms_info env.inst in
let tbox = SAT.current_tbox env.satml in
let _tbox, l =
Th.theories_instances
~do_syntactic_matching t_match tbox (selector env) env.nb_mrounds 0
[@ocaml.ppwarning "TODO: modifications made in tbox are lost! improve?"]
in
List.fold_left reduce_filters acc l, (match l with [] -> false | _ -> true)
let syntactic_th_inst remove_clauses env acc =
mk_theories_instances true remove_clauses env acc
let semantic_th_inst_rec =
let rec aux_rec remove_clauses env rnd acc =
let acc, inst_made = mk_theories_instances false remove_clauses env acc in
if not inst_made || rnd <= 1 then acc
else aux_rec remove_clauses env (rnd - 1) acc
in
fun remove_clauses env rnd acc ->
aux_rec remove_clauses env rnd acc
let mk_theories_inst_rec env rnd =
let acc, _ = syntactic_th_inst false env [] in
semantic_th_inst_rec false env rnd acc
(* <end> copied from sat_solvers.ml *)
let literals_of_ex ex =
Ex.fold_atoms
(fun e acc ->
match e with
| Ex.Literal a -> a :: acc
| Ex.Dep _ | Ex.RootDep _ -> acc
(* for debug/profiling/proofs, ignore them *)
| Ex.Bj _ | Ex.Fresh _ -> assert false
) ex []
let mround menv env acc =
let tbox = SAT.current_tbox env.satml in
let gd2, ngd2 =
Inst.m_predicates menv env.inst tbox (selector env) env.nb_mrounds
in
let l2 = List.rev_append (List.rev gd2) ngd2 in
if Options.get_profiling() then Profiling.instances l2;
let gd1, ngd1 =
Inst.m_lemmas menv env.inst tbox (selector env) env.nb_mrounds
in
let l1 = List.rev_append (List.rev gd1) ngd1 in
if Options.get_profiling() then Profiling.instances l1;
let l = ((List.rev_append l2 l1) : (E.gformula * Explanation.t) list) in
let th_insts = mk_theories_inst_rec env 10 in
let l = List.rev_append th_insts l in
List.fold_left
(fun acc (gf, dep) ->
match literals_of_ex dep with
| [] ->
(* Toplevel assertions from [axiom_def] have no literals *)
gf :: acc
| [{ Atom.lit; _ }] -> (
(* Instantiations from [internal_axiom_def] are justified by a
single syntaxic literal (from [axs_of_abstr]) *)
match Shostak.Literal.view lit with
| LTerm lit ->
{gf with
E.ff =
E.mk_or gf.E.ff (E.neg lit) false} :: acc
| LSem _ -> assert false
)
| _ -> assert false
)acc l
let pred_def env f name dep _loc =
(* dep currently not used. No unsat-cores in satML yet *)
Debug.pred_def f;
let guard = env.guards.current_guard in
env.inst <- Inst.add_predicate env.inst ~guard ~name (mk_gf f) dep
let axiom_def env gf ex =
env.inst <- Inst.add_lemma env.inst gf ex
let internal_axiom_def ax a at inst =
Debug.internal_axiom_def ax a at;
let gax = mk_gf ax in
let ex = Ex.singleton (Ex.Literal at) in
Inst.add_lemma inst gax ex
let register_abstraction env new_abstr_vars (f, (af, at)) =
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg
~module_name:"Satml_frontend" ~function_name:"register_abstraction"
"abstraction of %a is %a" E.print f FF.print af;
let lat =
match Shostak.Literal.view @@ Atom.literal at with
| LTerm at -> at
| LSem _ ->
(* Abstractions are always fresh expressions, so `at` is always a
syntaxic literal *)
assert false
in
let new_abstr_vars =
if not (Atom.is_true at) then at :: new_abstr_vars else new_abstr_vars
in
assert (not (ME.mem f env.abstr_of_axs));
assert (not (ME.mem lat env.axs_of_abstr));
let () =
if not (Atom.eq_atom at Atom.vrai_atom || Atom.eq_atom at Atom.faux_atom)
then
begin
env.abstr_of_axs <- ME.add f (af, at) env.abstr_of_axs;
env.axs_of_abstr <- ME.add lat (f, at) env.axs_of_abstr
end
in
if Atom.level at = 0 then (* at is necessarily assigned if lvl = 0 *)
if Atom.is_true at then
let () = axiom_def env (mk_gf f) Ex.empty in
new_abstr_vars
else begin
assert (Atom.is_true (Atom.neg at));
assert false (* FF.simplify invariant: should not happen *)
end
else begin
(* FF.simplify invariant: should not happen *)
assert (Atom.level at < 0);
let ded = match E.neg f |> E.form_view with
| E.Skolem q -> E.skolemize q
| E.Unit _ | E.Clause _ | E.Literal _ | E.Lemma _
| E.Let _ | E.Iff _ | E.Xor _ -> assert false
in
(*XXX TODO: internal skolems*)
let f = E.mk_or lat ded false in
let nlat = E.neg lat in
(* semantics: nlat ==> f *)
env.skolems <- ME.add nlat (mk_gf f) env.skolems;
new_abstr_vars
end
let expand_skolems env acc sa inst_quantif =
List.fold_left
(fun acc a ->
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg
~module_name:"Satml_frontend" ~function_name:"expand_skolems"
"expand skolem of %a" E.print a;
try
if inst_quantif a then
let { E.ff = f; _ } as gf = ME.find a env.skolems in
if not (Options.get_cdcl_tableaux ()) && ME.mem f env.gamma then
acc
else
gf :: acc
else
acc
with Not_found -> acc
) acc sa
let inst_env_from_atoms env acc sa inst_quantif =
List.fold_left
(fun (inst, acc) a ->
let gf = mk_gf E.vrai in
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg
~module_name:"Satml_frontend" ~function_name:"inst_env_from_atoms"
"terms_of_atom %a" E.print a;
let inst = Inst.add_terms inst (E.max_ground_terms_of_lit a) gf in
(* ax <-> a, if ax exists in axs_of_abstr *)
try
let ax, at = ME.find a env.axs_of_abstr in
if inst_quantif a then
internal_axiom_def ax a at inst, acc
else
inst, acc
with Not_found -> inst, acc
) (env.inst, acc) sa
(* unused --
let take_max aux l =
let ((lvl, _, ind) ,_) as acc =
List.fold_left (fun ((mz,_) as acc) f ->
match aux f with
| None -> acc
| Some (m, l) ->
if cmp_tuples m mz > 0 then (m, l) else acc
)((-1, -.1., -1), []) l
in
if lvl = -1 && ind = -1 then None
else Some acc
*)
(* unused --
let take_min aux l =
let ((lvl, _, ind) ,_) as acc =
List.fold_left (fun ((mz,_) as acc) f ->
match aux f with
| None -> acc
| Some (m, l) ->
if cmp_tuples m mz < 0 then (m, l) else acc
)((max_int, -.1., max_int), []) l
in
if lvl = max_int && ind = max_int then None
else Some acc
*)
let rec take_normal aux l =
match l with
[] -> None
| a::l ->
match aux a with
| None -> take_normal aux l
| (Some _) as v -> v
let atoms_from_sat_branches =
let rec atoms_from_sat_branch f =
match FF.view f with
| FF.UNIT at ->
if not (Atom.is_true at) then None
else
Some [
match Shostak.Literal.view @@ Atom.literal at with
| LTerm at -> at
| LSem _ ->
(* Flat formulas only contain syntaxic literals. *)
assert false
]
| FF.AND l ->
begin
try
let acc =
List.fold_left (fun lz f ->
match atoms_from_sat_branch f with
| None -> raise Exit
| Some l -> List.rev_append l lz
) [] l
in
Some acc
with Exit -> None
end
| FF.OR l ->
take_normal atoms_from_sat_branch l
in
fun env ->
FF.Map.fold
(fun f _ sa ->
Debug.atoms_from_sat_branch f;
match atoms_from_sat_branch f with
| None -> assert false
| Some l -> List.fold_left (fun sa a -> SE.add a sa) sa l
) env.conj SE.empty
module SA = Satml_types.Atom.Set
let atoms_from_lazy_sat =
let rec add_reasons_graph _todo _done =
match _todo with
[] -> _done
| a::_todo ->
if SA.mem a _done then add_reasons_graph _todo _done
else
let _todo =
List.fold_left
(fun _todo a -> (Atom.neg a) :: _todo)
_todo (Atom.reason_atoms a)
in
add_reasons_graph _todo (SA.add a _done)
in
fun ~frugal env ->
let sa = SAT.instantiation_context env.satml env.ff_hcons_env in
let sa =
if frugal then sa
else add_reasons_graph (SA.elements sa) SA.empty
in
let add_elit a s =
match Shostak.Literal.view @@ Atom.literal a with
| LTerm a -> SE.add a s
| LSem _ -> s
in
SA.fold add_elit sa SE.empty
let atoms_from_lazy_greedy env =
let aux accu ff =
let sf =
try FF.Map.find ff env.conj |> snd
with Not_found ->
if FF.equal ff FF.vrai then SE.empty
else begin
Printer.print_err
"%a not found in env.conj" FF.print ff;
assert false
end
in
SE.fold (E.atoms_rec_of_form ~only_ground:false) sf accu
in
let accu =
FF.Map.fold
(fun ff _ accu -> aux accu ff)
(SAT.known_lazy_formulas env.satml) SE.empty
in
SE.union (atoms_from_lazy_sat ~frugal:true env)
(*otherwise, we loose atoms that abstract internal axioms *)
(aux accu FF.vrai)
[@ocaml.ppwarning
"improve terms / atoms extraction in lazy/non-lazy \
and greedy/non-greedy mode. Separate atoms from terms !"]
let atoms_from_bmodel env =
ME.fold (fun f _ sa -> (E.atoms_rec_of_form ~only_ground:false) f sa)
env.gamma SE.empty
let instantiation_context env ~greedy_round ~frugal =
let sa = match greedy_round, Options.get_cdcl_tableaux_inst () with
| false, false -> atoms_from_sat_branches env
| false, true -> atoms_from_lazy_sat ~frugal env
| true , false -> atoms_from_bmodel env
| true, true -> atoms_from_lazy_greedy env
in
let inst_quantif =
if Options.get_cdcl_tableaux_inst () then
let frugal = atoms_from_lazy_sat ~frugal:true env in
(fun a -> SE.mem a frugal)
else
(fun _ -> true)
in
SE.elements sa, inst_quantif
[@ocaml.ppwarning "Issue for greedy: terms inside lemmas not extracted"]
let terms_from_dec_proc env =
let terms = Th.extract_ground_terms (SAT.current_tbox env.satml) in
Debug.add_terms_of "terms_from_dec_proc" terms;
let gf = mk_gf E.vrai in
Inst.add_terms env.inst terms gf
let instantiate_ground_preds env acc sa =
List.fold_left
(fun acc a ->
match Inst.ground_pred_defn a env.inst with
| Some (guard, res, _dep) ->
(* To be correct in incremental mode, we'll generate the
formula "guard -> (a -> res)" *)
let tmp = E.mk_imp a res in
let tmp = E.mk_imp guard tmp in
(mk_gf tmp) :: acc
| None ->
acc
)acc sa
[@ocaml.ppwarning "!!! Possibles issues du to replacement of atoms \
that are facts with TRUE by mk_lit (and simplify)"]
let new_instances use_cs env sa inst_quantif acc =
let inst, acc = inst_env_from_atoms env acc sa inst_quantif in
let inst = terms_from_dec_proc {env with inst=inst} in
mround use_cs {env with inst = inst} acc
type pending = {
seen_f : SE.t;
activate : FF.Set.t;
new_vars : Atom.var list;
unit : Atom.atom list list;
nunit : Atom.atom list list;
new_abstr_vars : Atom.atom list;
updated : bool;
}
let pre_assume env acc gf =
let { E.ff = f; _ } = gf in
if Options.(get_debug_sat () && get_verbose ()) then
Printer.print_dbg
~module_name:"Satml_frontend" ~function_name:"pre_assume"
"Entry of pre_assume: Given %a" E.print f;
if SE.mem f acc.seen_f then acc
else
let acc = {acc with seen_f = SE.add f acc.seen_f} in
try
let _, ff = ME.find f env.gamma in
match ff with
| None ->
acc
[@ocaml.ppwarning "TODO: should be assert failure?"]
| Some ff ->
if SAT.exists_in_lazy_cnf env.satml ff then acc
else
{acc with
activate = FF.Set.add ff acc.activate;
updated = true}
with Not_found ->
Debug.assume gf;
match E.form_view f with
| E.Lemma _ ->
let ff = FF.vrai in
let _, old_sf =
try FF.Map.find ff env.conj with Not_found -> 0, SE.empty
in
env.gamma <- ME.add f (env.nb_mrounds, None) env.gamma;
env.conj <- FF.Map.add ff (env.nb_mrounds, SE.add f old_sf) env.conj;
(* This assert is not true assert (dec_lvl = 0); *)
axiom_def env gf Ex.empty;
{acc with updated = true}
| E.Unit _ | E.Clause _ | E.Literal _ | E.Skolem _
| E.Let _ | E.Iff _ | E.Xor _ ->
let ff, axs, new_vars =
FF.simplify env.ff_hcons_env f
(fun f -> ME.find f env.abstr_of_axs) acc.new_vars
in
let acc = {acc with new_vars = new_vars} in
let cnf_is_in_cdcl = FF.Map.mem ff env.conj in
let _, old_sf =
try FF.Map.find ff env.conj with Not_found -> 0, SE.empty
in
env.gamma <- ME.add f (env.nb_mrounds, Some ff) env.gamma;
env.conj <- FF.Map.add ff (env.nb_mrounds, SE.add f old_sf) env.conj;
Debug.simplified_form f ff;
let new_abstr_vars =
List.fold_left (register_abstraction env) acc.new_abstr_vars axs
in
let acc = { acc with new_abstr_vars } in
if FF.equal ff FF.vrai then acc
else
if cnf_is_in_cdcl then
(* this means that there exists another E.t that is
equivalent to f. These two formulas have the same ff *)
if SAT.exists_in_lazy_cnf env.satml ff then acc
else
{acc with
activate = FF.Set.add ff acc.activate;
updated = true}
else
let ff_abstr,new_proxies,proxies_mp, new_vars =
FF.cnf_abstr env.ff_hcons_env ff env.proxies acc.new_vars
in
env.proxies <- proxies_mp;
let nunit =
List.fold_left FF.expand_proxy_defn acc.nunit new_proxies
in
let acc =
{acc with
new_vars;
nunit;
unit = [ff_abstr] :: acc.unit;
activate = FF.Set.add ff acc.activate;
updated = true
}
in
acc
let cdcl_assume env pending ~dec_lvl =
let { seen_f; activate; new_vars; unit; nunit; updated; _ } = pending in
(*
fprintf fmt "pending : %d distinct forms@." (SE.cardinal seen_f);
fprintf fmt "pending : %d to activate@." (SFF.cardinal activate);
fprintf fmt "pending : %d new vars@." (List.length new_vars);
fprintf fmt "pending : %d unit cnf@." (List.length unit);
fprintf fmt "pending : %d non-unit cnf@." (List.length nunit);
fprintf fmt "pending : updated = %b@." updated;
*)
if SE.is_empty seen_f then begin
assert (FF.Set.is_empty activate);
assert (new_vars == []);
assert (unit == []);
assert (nunit == []);
assert (not updated);
end
else
try
let f = E.vrai
[@ocaml.ppwarning "TODO: should fix for unsat cores generation"]
in
SAT.set_new_proxies env.satml env.proxies;
let nbv = FF.nb_made_vars env.ff_hcons_env in
let unit, nunit = SAT.new_vars env.satml ~nbv new_vars unit nunit in
(*update_lazy_cnf done inside assume at the right place *)
SAT.assume env.satml unit nunit f ~cnumber:0 activate ~dec_lvl;
with
| Satml.Unsat (lc) -> raise (IUnsat (env, make_explanation lc))
| Satml.Sat -> assert false
let assume_aux_bis ~dec_lvl env l : bool * Atom.atom list =
let pending = {
seen_f = SE.empty; activate = FF.Set.empty;
new_vars = []; unit = []; nunit = []; updated = false;
new_abstr_vars = [];
}
in
(*fprintf fmt "@.assume aux: %d@." (List.length l);*)
let pending = List.fold_left (pre_assume env) pending l in
cdcl_assume env pending ~dec_lvl;
pending.updated, pending.new_abstr_vars
let rec assume_aux ~dec_lvl env l =
let updated, new_abstr_vars = assume_aux_bis ~dec_lvl env l in
let elit a =
match Shostak.Literal.view @@ Atom.literal a with
| LTerm a -> a
| LSem _ ->
(* This is only called on newly added skolems, which are always
syntaxic literals *)
assert false
in
let bot_abstr_vars = (* try to immediately expand newly added skolems *)
List.fold_left (fun acc at ->
let neg_at = Atom.neg at in
if Atom.is_true neg_at then (elit neg_at) :: acc else acc
)[] new_abstr_vars
in
match bot_abstr_vars with
| [] -> updated
| _ ->
let res = expand_skolems env [] bot_abstr_vars (fun _ -> true) in
if res == [] then updated
else
let updated' = assume_aux ~dec_lvl env res in
updated || updated'
let frugal_mconf () =
let open Options in
{Util.nb_triggers = get_nb_triggers ();
no_ematching = get_no_ematching();
triggers_var = get_triggers_var ();
use_cs = false;
backward = Util.Normal;
greedy = false;
}
let normal_mconf () =
let open Options in
{Util.nb_triggers = Stdlib.max 2 (get_nb_triggers () * 2);
no_ematching = get_no_ematching();
triggers_var = get_triggers_var ();
use_cs = false;
backward = Util.Normal;
greedy = false;
}
let greedy_mconf () =
let open Options in
{Util.nb_triggers = Stdlib.max 10 (get_nb_triggers () * 10);
no_ematching = false;
triggers_var = get_triggers_var ();
use_cs = true;
backward = Util.Normal;
greedy = true;
}
let greedier_mconf () =
let open Options in
{Util.nb_triggers = Stdlib.max 10 (get_nb_triggers () * 10);
no_ematching = false;
triggers_var = true;
use_cs = true;
backward = Util.Normal;
greedy = true;
}
let do_instantiation env sa inst_quantif mconf msg ~dec_lvl =
Debug.new_instances msg env;
let l = instantiate_ground_preds env [] sa in
let l = expand_skolems env l sa inst_quantif in
let l = new_instances mconf env sa inst_quantif l in
assume_aux ~dec_lvl env l
type instantiation_strat =
| Auto
| Force_normal
| Force_greedy
let instantiation env inst_strat dec_lvl =
let nb_mrounds = env.nb_mrounds in
match inst_strat with
| Force_normal ->
let mconf = frugal_mconf () in (* take frugal_mconf if normal is forced *)
env.last_forced_normal <- nb_mrounds;
let sa, inst_quantif =
instantiation_context env ~greedy_round:false ~frugal:false in
do_instantiation env sa inst_quantif mconf "normal-inst (forced)" ~dec_lvl
| Force_greedy ->
let mconf = normal_mconf () in (*take normal_mconf if greedy is forced*)
env.last_forced_greedy <- nb_mrounds;
let sa, inst_quantif =
instantiation_context env ~greedy_round:true ~frugal:true in
do_instantiation env sa inst_quantif mconf "greedy-inst (forced)" ~dec_lvl
| Auto ->
List.fold_left
(fun updated (mconf, debug, greedy_round, frugal) ->
if updated then updated
(* TODO: stop here with an exception *)
else
let sa, inst_quantif =
instantiation_context env ~greedy_round ~frugal in
do_instantiation env sa inst_quantif mconf debug ~dec_lvl
)
false
(match Options.get_instantiation_heuristic () with
| INormal ->
[ frugal_mconf (), "frugal-inst", false, true ;
normal_mconf (), "normal-inst", false, false ]
| IAuto ->
[ frugal_mconf (), "frugal-inst", false, true ;
normal_mconf (), "normal-inst", false, false;
greedier_mconf (), "greedier-inst", true, false]
| IGreedy ->
[ greedy_mconf (), "greedy-inst", true , false;
greedier_mconf (), "greedier-inst", true, false])
let do_case_split env policy =
match SAT.do_case_split env.satml policy with
| C_none -> ()
| C_bool _ -> assert false
| C_theory expl -> raise (Ex.Inconsistent (expl, []))
let may_update_last_saved_model env compute =