1 /*
2 * Exposes Glucose API to SICStus Prolog
3 *
4 * Based on SWI Prolog Minisat Integration by
5 * Michael Codish, Vitaly Lagoon, Peter J. Stuckey
6 */
7
8 :- module(satsolver, [init_satsolver/0, sat/1, sat/2, bt_sat/1, multi_sat/3, b_sat/2]).
9
10 :- use_module('../../src/module_information.pl').
11 :- module_info(group,experimental).
12 :- module_info(description,'This is the interface between ProB and the Glucose SAT solver').
13
14 :- use_module(b_to_cnf).
15
16 :- use_module(library(lists), [maplist/2,maplist/3]).
17
18 foreign_resource('satsolver', [new_solver,solve,delete_solver,
19 add_clause,assign_model,get_model]).
20
21 foreign(new_solver, c, new_solver([-integer])).
22 foreign(solve, c, solve(+integer)).
23 foreign(delete_solver, c, delete_solver(+integer)).
24 foreign(add_clause, c, add_clause(+integer,+term)).
25 foreign(assign_model, c, assign_model(+integer,+term)).
26 foreign(get_model, c, get_model(+integer,+term)).
27
28 :- dynamic is_initialised/0.
29
30 init_satsolver :- is_initialised,!.
31 init_satsolver :-
32 catch(load_foreign_resource(library(satsolver)),_,(print('*** LOADING satsolver library failed'),nl,fail)),
33 assert(is_initialised).
34
35 b_sat(BFormula,State) :-
36 init_satsolver,
37 b_to_cnf(BFormula,State,CNF),!,
38 bt_sat(CNF).
39
40 sat(CNF):-
41 sat(CNF,Solved),!,
42 Solved=1.
43
44 sat([],1):-!.
45 sat([[]],0):-!.
46 sat(F,Solved):-
47 new_solver(SolverID),
48 setup_solver(SolverID),
49 (addCnf2Solver(SolverID,F,FVars)
50 -> (solve(SolverID)
51 -> assign_model(SolverID,[1|FVars]), Solved = 1
52 ; Solved = 0)
53 ; Solved=0),
54 delete_solver(SolverID),!.
55
56 bt_sat(F) :-
57 new_solver(SolverID),
58 bt_sat_aux(SolverID,F).
59
60 bt_sat_aux(SolverID,F) :-
61 setup_solver(SolverID),
62 addCnf2Solver(SolverID,F,FVars),
63 solve(SolverID),
64 get_model(SolverID,[_|Model]),
65 bt_sat(SolverID,FVars,Model).
66 bt_sat_aux(SolverID,_) :-
67 delete_solver(SolverID), fail.
68
69 bt_sat(SolverID,FVars,_Model) :-
70 assign_model(SolverID,[1|FVars]).
71 bt_sat(SolverID,FVars,Model) :-
72 add_negated_model(SolverID,Model),
73 solve(SolverID),
74 get_model(SolverID,[_|NewModel]),
75 bt_sat(SolverID,FVars,NewModel).
76
77 multi_sat([],_,1):-!.
78 multi_sat([[]],_,0):-!.
79 multi_sat(F,MaxSols,SolCount):-
80 new_solver(SolverID),
81 setup_solver(SolverID),
82 (addCnf2Solver(SolverID,F,FVars)
83 -> satMultiModels(SolverID,MaxSols,Models),
84 delete_solver(SolverID),!,
85 length(Models,SolCount),
86 (SolCount == 0 ; assignMultiSols(Models,FVars))
87 ; delete_solver(SolverID),!,SolCount=0),!.
88
89 satMultiModels(SolverID,MaxSols,Models):-
90 MaxSols > 0,!,
91 (solve(SolverID)
92 -> get_model(SolverID,[_|Model]),
93 Models=[Model|MoreModels],
94 MaxSols1 is MaxSols - 1,
95 ((MaxSols1 > 0, add_negated_model(SolverID,Model))
96 -> satMultiModels(SolverID,MaxSols1,MoreModels)
97 ; MoreModels=[])
98 ; Models=[]).
99 satMultiModels(_,_,[]):-!.
100
101 add_negated_model(SolverID,Model):-
102 maplist(neg,Model,NoAsgn),
103 add_clause(SolverID,NoAsgn).
104
105 neg(V,VN) :- VN is -V.
106
107 assignMultiSols(Models,FVars):-!,
108 length(FVars,VarLen),
109 length(SoFar,VarLen),
110 maplist(=([]),SoFar),!,
111 assignMultiSols(Models,SoFar,FVars).
112
113 assignMultiSols([],SoFar,SoFar):-!.
114 assignMultiSols([M|Models],SoFar,Vars):-!,
115 addModel2Vars(M,SoFar,NVars),!,
116 assignMultiSols(Models,NVars,Vars).
117
118 addModel2Vars([],[],[]).
119 addModel2Vars([M|Ms],[V|Vs],[[NV|V]|NVs]):-
120 (M>0 -> NV=1 ; NV= -1),
121 addModel2Vars(Ms,Vs,NVs).
122
123 addCnf2Solver(SolverID,Cnf,FVars):-
124 term_variables(Cnf,FVars),!,
125 \+ \+ (bind2index(FVars,3,FN),
126 add_cnf_clauses(Cnf,SolverID),
127 neg(FN,FNeg),
128 add_cnf_clauses([[FN,FNeg]],SolverID)).
129
130 add_cnf_clauses([Cl|Cls],SolverID):-!,
131 maplist(to_minisat_cl,Cl,MiniSatCl),
132 add_clause(SolverID,MiniSatCl),
133 add_cnf_clauses(Cls,SolverID).
134 add_cnf_clauses([],_):-!.
135
136 setup_solver(SolverID) :-
137 add_clause(SolverID,[1]), % true
138 add_clause(SolverID,[-2]).
139
140 to_minisat_cl(pred_true,1) :- !.
141 to_minisat_cl(pred_false,2) :- !.
142 to_minisat_cl(X,X).
143
144 bind2index([N|Ns],N,FN) :- N1 is N+1, bind2index(Ns,N1,FN).
145 bind2index([],N,FN):-!, FN is N - 1.