1 | :- module(difference_logic_solver, [init_idl_solver/1, | |
2 | register_constraint/2, | |
3 | register_constraints/2, | |
4 | solve_idl_conj/2, | |
5 | is_idl_constraint/1, | |
6 | get_solver_result/2, | |
7 | get_all_solutions_on_bt/2, | |
8 | try_candidate_bounds/3, | |
9 | get_registered_vars/2, | |
10 | get_unsat_core/1, | |
11 | infer_constraints_for_idl_solver/2, | |
12 | negate_dl_constraint/2, | |
13 | remove_unsat_core/0]). | |
14 | ||
15 | :- use_module(library(lists), [select/3]). | |
16 | :- use_module(library(plunit)). | |
17 | ||
18 | :- use_module(probsrc(preferences), [set_preference/2]). | |
19 | :- use_module(probsrc(bsyntaxtree), [conjunct_predicates/2, conjunction_to_list/2]). | |
20 | :- use_module(cdclt_solver('difference_logic/ast_to_difference_logic')). | |
21 | ||
22 | :- dynamic predecessor/2, negative_weight/0, contains_zero/0, constraint_store/3, unsat_core/1. | |
23 | :- volatile predecessor/2, negative_weight/0, contains_zero/0, constraint_store/3, unsat_core/1. | |
24 | ||
25 | % A graph based solver for difference logic, i.e., constraints of the form Minuend - Subtrahend <= Constant. | |
26 | % Each node represents a variable. For a constraint x-y<=c a weighted edge (y,c,x) is added, while not(x-y<=c) yields | |
27 | % the edge (x,-c-1,y). | |
28 | % A difference logic constraint system is satisfiable if its corresponding graph does not contain a negative cycle. | |
29 | % If satisfiable, the shortest path to a variable yields its solution. | |
30 | % Otherwise, the conjunction of constraints corresponding to the edges of the negative cycle are an unsat core. | |
31 | % Note: Integer inequality has to be rewritten beforehand since it yields a disjunction in difference logic. | |
32 | ||
33 | %% solve_idl_conj(+Pred, -Result). | |
34 | solve_idl_conj(Pred, Result) :- | |
35 | init_idl_solver(GraphMut), | |
36 | conjunction_to_list(Pred, ConjList), | |
37 | ( register_constraints(GraphMut, ConjList), | |
38 | !, | |
39 | get_solver_result(GraphMut, Result) | |
40 | ; get_solver_result(GraphMut, TResult), | |
41 | TResult == contradiction_found, | |
42 | !, | |
43 | get_unsat_core(Core), | |
44 | Result = contradiction_found(Core) | |
45 | ; Result = no_solution_found(no_idl_constraint) | |
46 | ). | |
47 | ||
48 | %% init_idl_solver. | |
49 | init_idl_solver(GraphMut) :- | |
50 | create_mutable(graph(nodes([]),edges([]),shortest_paths([])), GraphMut), | |
51 | set_preference(normalize_ast, true), | |
52 | retractall(predecessor(_,_)), | |
53 | retractall(unsat_core(_)), | |
54 | retractall(constraint_store(_,_,_)), | |
55 | retractall(negative_weight), | |
56 | retractall(contains_zero). | |
57 | ||
58 | negate_dl_constraint(b(equal(A,B),pred,Info), NegDL) :- | |
59 | !, | |
60 | NegDL = b(not_equal(A,B),pred,Info). | |
61 | negate_dl_constraint(b(not_equal(A,B),pred,Info), NegDL) :- | |
62 | !, | |
63 | NegDL = b(equal(A,B),pred,Info). | |
64 | negate_dl_constraint(b(negation(Constraint),pred,[]), Constraint). | |
65 | negate_dl_constraint(Constraint, b(negation(Constraint),pred,[])). | |
66 | ||
67 | %% get_registered_vars(+GraphMut, -Vars). | |
68 | get_registered_vars(GraphMut, Vars) :- | |
69 | get_mutable(graph(nodes(Vars),_,_), GraphMut). | |
70 | ||
71 | %% register_constraints(+GraphMut, +ListOfConstraints). | |
72 | register_constraints(_, []). | |
73 | register_constraints(GraphMut, [Constraint|T]) :- | |
74 | register_constraint(GraphMut, Constraint), | |
75 | register_constraints(GraphMut, T). | |
76 | ||
77 | %% register_constraint(+GraphMut, +Constraint). | |
78 | % Accepted top level operators are <,<=,= and its negations. | |
79 | % Fails if constraint can not be transformed to difference logic | |
80 | % or produces a contradiction with existing constraints. | |
81 | register_constraint(GraphMut, Constraint) :- | |
82 | %write('Register Constraint..'),nl, | |
83 | %translate:print_bexpr(Constraint),nl, | |
84 | ( is_idl_constraint(Constraint) | |
85 | -> register_idl_constraint(GraphMut, Constraint), | |
86 | solve_incremental_constraint(GraphMut, Constraint) | |
87 | ; rewrite_to_idl(Constraint, DLConstraints), | |
88 | register_constraints_from_conj_list(GraphMut, DLConstraints), | |
89 | solve_incremental_list(GraphMut, DLConstraints) | |
90 | ). | |
91 | ||
92 | %% relax_edge_cond(+GraphMut, +In, +Out, +Weight, -ND). | |
93 | relax_edge_cond(GraphMut, In, Out, Weight, ND) :- | |
94 | get_mutable(graph(_,_,shortest_paths(SPs)), GraphMut), | |
95 | member((In,DIn), SPs), | |
96 | member((Out,DOut), SPs), | |
97 | ND is DIn + Weight, | |
98 | ND < DOut. | |
99 | ||
100 | %% relax_node_distance(+GraphMut, +In, +Out, +ND, -DiffToOld). | |
101 | relax_node_distance(GraphMut, In, Out, ND, DiffToOld) :- | |
102 | assert_distance(GraphMut, Out, ND, DiffToOld), | |
103 | assert_predecessor(Out, In). | |
104 | ||
105 | solve_incremental_constraint(GraphMut, DLConstraint) :- | |
106 | get_edge_from_dl_constraint(DLConstraint, In, Out, Weight), | |
107 | solve_incremental(GraphMut, In, Out, Weight). | |
108 | ||
109 | solve_incremental_list(_, []). | |
110 | solve_incremental_list(GraphMut, [DLConstraint|T]) :- | |
111 | solve_incremental_constraint(GraphMut, DLConstraint), | |
112 | solve_incremental_list(GraphMut, T). | |
113 | ||
114 | %% solve_incremental(+In, +Out, +Weight). | |
115 | % Update shortest paths while searching for a negative cycle. | |
116 | solve_incremental(_, _, _, _) :- | |
117 | % no negative cycle without a negative weight | |
118 | \+ negative_weight. | |
119 | solve_incremental(GraphMut, In, Out, Weight) :- | |
120 | negative_weight, | |
121 | detect_negative_cycle_inc(GraphMut, [], In, Out, Weight, NegativeCycle), | |
122 | ( NegativeCycle == none | |
123 | -> % shortest paths stored in dis/2 are a solution | |
124 | true | |
125 | ; get_unsat_core_from_negative_cycle(GraphMut, NegativeCycle, UnsatCore), | |
126 | %nl, write('Unsat Core: '), nl,translate:print_bexpr(UnsatCore),nl, | |
127 | %writeq(UnsatCore),nl, | |
128 | asserta(unsat_core(UnsatCore)), | |
129 | fail | |
130 | ). | |
131 | ||
132 | %% get_edge_from_dl_constraint(+Node, -In, -Out, -Weight). | |
133 | get_edge_from_dl_constraint(b(less_equal(Sub,Constant),pred,_), In, Out, Weight) :- | |
134 | % edge (y,c,x) for x-y<=c | |
135 | get_id_names_from_idl_minus(Sub, Out, In), | |
136 | get_int_value(Constant, Weight). | |
137 | get_edge_from_dl_constraint(b(negation(Constraint),pred,_), In, Out, Weight) :- | |
138 | % edge (x,-c-1,y) for not(x-y<=c) | |
139 | Constraint = b(less_equal(Sub,Constant),pred,_), | |
140 | get_id_names_from_idl_minus(Sub, In, Out), | |
141 | get_int_value(Constant, TWeight), | |
142 | Weight is TWeight * -1 - 1. | |
143 | ||
144 | get_id_names_from_idl_minus(b(minus(Id1,Id2),integer,_), In, Out) :- | |
145 | Id1 = b(identifier(In),integer,_), | |
146 | Id2 = b(identifier(Out),integer,_). | |
147 | ||
148 | %% get_all_solutions_on_bt(+GraphMut, -SolverResult). | |
149 | get_all_solutions_on_bt(GraphMut, SolverResult) :- | |
150 | % TO DO: randomized enumeration order, log upper and lower bounded vars? | |
151 | get_solver_result(GraphMut, TSolverResult), | |
152 | TSolverResult = solution(Bindings), | |
153 | ( SolverResult = TSolverResult | |
154 | ; exclude_solution_bt(GraphMut, Bindings), | |
155 | get_all_solutions_on_bt(GraphMut, SolverResult) | |
156 | ). | |
157 | ||
158 | exclude_solution_bt(GraphMut, [binding(VarName,int(Val),_)|T]) :- | |
159 | % register inequality constraint VarName /= Val with choicepoint since rewriting yields a disjunction | |
160 | % i.e., x/=c -> x-_zero<=c-1 or _zero-x<=-c-1 | |
161 | ( exclude_solution_from_binding(GraphMut, VarName, Val) | |
162 | ; remove_unsat_core, | |
163 | Val1 is Val * -1, | |
164 | % equality | |
165 | LEQ1 = b(less_equal(b(minus(b(identifier(VarName),integer,[]),b(identifier('_zero'),integer,[])),integer,[]),b(integer(Val),integer,[])),pred,[]), | |
166 | LEQ2 = b(less_equal(b(minus(b(identifier('_zero'),integer,[]),b(identifier(VarName),integer,[])),integer,[]),b(integer(Val1),integer,[])),pred,[]), | |
167 | register_constraints(GraphMut, [LEQ1,LEQ2]), | |
168 | exclude_solution_bt(GraphMut, T) | |
169 | ). | |
170 | ||
171 | exclude_solution_from_binding(GraphMut, VarName, Val) :- | |
172 | DisjVal1 is Val - 1, | |
173 | DisjVal2 is Val * -1 - 1, | |
174 | VarId = b(identifier(VarName),integer,[]), | |
175 | ZeroId = b(identifier('_zero'),integer,[]), | |
176 | Disj1 = b(less_equal(b(minus(VarId,ZeroId),integer,[]),b(integer(DisjVal1),integer,[])),pred,[]), | |
177 | Disj2 = b(less_equal(b(minus(ZeroId,VarId),integer,[]),b(integer(DisjVal2),integer,[])),pred,[]), | |
178 | ( remove_unsat_core, | |
179 | register_constraint(GraphMut, Disj1) | |
180 | ; remove_unsat_core, | |
181 | register_constraint(GraphMut, Disj2) | |
182 | ). | |
183 | ||
184 | %% try_candidate_bounds(+GraphMut, +CandidateTuples, -SolverResult). | |
185 | % Try candidate bounds obtained by syntactic analysis of non idl constraints when backtracking from ProB to IDL solver. | |
186 | % CandidateTuples is a list of tuples of variable and possible bounding values. | |
187 | try_candidate_bounds(GraphMut, CandidateTuples, SolverResult) :- | |
188 | try_candidate_bounds(GraphMut, none, CandidateTuples, Diff-Diff, SolverResult). | |
189 | ||
190 | % Successively try one value for each variable with choicepoints to find all combinations on backtracking. | |
191 | try_candidate_bounds(GraphMut, Solution, [], L-Diff, SolverResult) :- | |
192 | Diff = [], | |
193 | L \== [], | |
194 | try_candidate_bounds(GraphMut, Solution, L, NDiff-NDiff, SolverResult). | |
195 | try_candidate_bounds(GraphMut, Solution, [(_,[])|T], L-Diff, SolverResult) :- | |
196 | try_candidate_bounds(GraphMut, Solution, T, L-Diff, SolverResult). | |
197 | try_candidate_bounds(GraphMut, none, [(VarName,[Val|TVals])|T], L-Diff, SolverResult) :- | |
198 | % x=val | |
199 | LEQ1 = b(less_equal(b(minus(b(identifier(VarName),integer,[]),b(identifier('_zero'),integer,[])),integer,[]),b(integer(Val),integer,[])),pred,[]), | |
200 | NVal is Val * -1, | |
201 | LEQ2 = b(less_equal(b(minus(b(identifier('_zero'),integer,[]),b(identifier(VarName),integer,[])),integer,[]),b(integer(NVal),integer,[])),pred,[]), | |
202 | remove_unsat_core, | |
203 | register_constraints(GraphMut, [LEQ1,LEQ2]), | |
204 | get_solver_result(GraphMut, TSolverResult), | |
205 | TSolverResult = solution(_), | |
206 | ( SolverResult = TSolverResult | |
207 | ; Diff = [(VarName,TVals)|NDiff], | |
208 | try_candidate_bounds(GraphMut, TSolverResult, T, L-NDiff, SolverResult) | |
209 | ). | |
210 | try_candidate_bounds(GraphMut, Solution, [(VarName,[Val|TVals])|T], L-Diff, SolverResult) :- | |
211 | ( Solution == none | |
212 | ; ground(Solution), | |
213 | Solution = solution(Bindings), | |
214 | member(binding(VarName,int(OldVal),_), Bindings), | |
215 | Val < OldVal | |
216 | ), | |
217 | Val1 is Val - 1, | |
218 | % x<val | |
219 | LEQ = b(less_equal(b(minus(b(identifier(VarName),integer,[]),b(identifier('_zero'),integer,[])),integer,[]),b(integer(Val1),integer,[])),pred,[]), | |
220 | remove_unsat_core, | |
221 | register_constraint(GraphMut, LEQ), | |
222 | get_solver_result(GraphMut, TSolverResult), | |
223 | TSolverResult = solution(_), | |
224 | ( SolverResult = TSolverResult | |
225 | ; Diff = [(VarName,TVals)|NDiff], | |
226 | try_candidate_bounds(GraphMut, TSolverResult, T, L-NDiff, SolverResult) | |
227 | ). | |
228 | try_candidate_bounds(GraphMut, Solution, [(VarName,[Val|TVals])|T], L-Diff, SolverResult) :- | |
229 | ( Solution == none | |
230 | ; ground(Solution), | |
231 | Solution = solution(Bindings), | |
232 | member(binding(VarName,int(OldVal),_), Bindings), | |
233 | Val > OldVal | |
234 | ), | |
235 | Val1 is Val * -1 - 1, | |
236 | % x>val | |
237 | LEQ = b(less_equal(b(minus(b(identifier('_zero'),integer,[]),b(identifier(VarName),integer,[])),integer,[]),b(integer(Val1),integer,[])),pred,[]), | |
238 | remove_unsat_core, | |
239 | register_constraint(GraphMut, LEQ), | |
240 | get_solver_result(GraphMut, TSolverResult), | |
241 | TSolverResult = solution(_), | |
242 | ( SolverResult = TSolverResult | |
243 | ; Diff = [(VarName,TVals)|NDiff], | |
244 | try_candidate_bounds(GraphMut, TSolverResult, T, L-NDiff, SolverResult) | |
245 | ). | |
246 | try_candidate_bounds(GraphMut, Solution, [(VarName,[_|TVals])|T], L-Diff, SolverResult) :- | |
247 | Diff = [(VarName,TVals)|NDiff], | |
248 | try_candidate_bounds(GraphMut, Solution, T, L-NDiff, SolverResult). | |
249 | ||
250 | remove_unsat_core :- | |
251 | retract(unsat_core(_)), | |
252 | !. | |
253 | remove_unsat_core. | |
254 | ||
255 | %% get_solver_result(+GraphMut, -SolverResult). | |
256 | get_solver_result(_, SolverResult) :- | |
257 | unsat_core(_), | |
258 | !, | |
259 | SolverResult = contradiction_found. | |
260 | get_solver_result(GraphMut, SolverResult) :- | |
261 | get_mutable(graph(_,_,shortest_paths(SPs)), GraphMut), | |
262 | shortest_paths_to_bindings(SPs, [], TempBindings), % TO DO: shift at the same time? | |
263 | ground(TempBindings), | |
264 | possibly_shift_solution_for_zero(TempBindings, Bindings),!, | |
265 | SolverResult = solution(Bindings). | |
266 | ||
267 | shortest_paths_to_bindings([], Acc, Acc). | |
268 | shortest_paths_to_bindings([(VarName,Val)|T], Acc, Bindings) :- | |
269 | number_to_atom(Val, ValAtom), | |
270 | shortest_paths_to_bindings(T, [binding(VarName,int(Val),ValAtom)|Acc], Bindings). | |
271 | ||
272 | %% detect_negative_cycle_inc(+GraphMut, +Queue, +In, +Out, +Weight, -NegativeCycle). | |
273 | % Incremental negative cycle detection and shortest path computation as suggested by Chao Wang et al. | |
274 | % Queue is sorted by maximal node value changes. | |
275 | detect_negative_cycle_inc(GraphMut, Queue, In, Out, Weight, NegativeCycle) :- | |
276 | ( relax_edge_cond(GraphMut, In, Out, Weight, NDOut) | |
277 | -> relax_node_distance(GraphMut, In, Out, NDOut, DiffToOld), | |
278 | insertion_sort(Queue, Out, DiffToOld, NQueue) | |
279 | ; NQueue = Queue | |
280 | ), | |
281 | detect_negative_cycle_inc(GraphMut, In, Out, NQueue, NegativeCycle). | |
282 | ||
283 | detect_negative_cycle_inc(_, _, _, [], none). | |
284 | detect_negative_cycle_inc(GraphMut, StartIn, StartOut, [(CurNode,_)|T], NegativeCycle) :- | |
285 | get_adjacent_edges(GraphMut, CurNode, Adjacent), | |
286 | detect_negative_cycle_inc_process_edges(GraphMut, StartIn, StartOut, Adjacent, T, NQueue, TNegativeCycle), | |
287 | (TNegativeCycle \== none | |
288 | -> NegativeCycle = TNegativeCycle | |
289 | ; detect_negative_cycle_inc(GraphMut, StartIn, StartOut, NQueue, NegativeCycle) | |
290 | ). | |
291 | ||
292 | detect_negative_cycle_inc_process_edges(_, _, _, [], Queue, Queue, none). | |
293 | detect_negative_cycle_inc_process_edges(GraphMut, StartIn, StartOut, [(In,Weight,Out,_)|T], Queue, NQueue, NegativeCycle) :- | |
294 | ( relax_edge_cond(GraphMut, In, Out, Weight, NDOut) | |
295 | -> ( (In == StartIn, Out == StartOut) | |
296 | -> get_negative_cycle_from_predecessors(Out, NegativeCycle) | |
297 | ; relax_node_distance(GraphMut, In, Out, NDOut, DiffToOld), | |
298 | insertion_sort(Queue, Out, DiffToOld, TQueue), | |
299 | detect_negative_cycle_inc_process_edges(GraphMut, StartIn, StartOut, T, TQueue, NQueue, NegativeCycle) | |
300 | ) | |
301 | ; detect_negative_cycle_inc_process_edges(GraphMut, StartIn, StartOut, T, Queue, NQueue, NegativeCycle) | |
302 | ). | |
303 | ||
304 | get_adjacent_edges(GraphMut, Node, Adjacent) :- | |
305 | get_mutable(graph(_,edges(Edges),_), GraphMut), | |
306 | memberchk(Node:TAdjacent, Edges), | |
307 | !, | |
308 | Adjacent = TAdjacent. | |
309 | get_adjacent_edges(_, _, []). | |
310 | ||
311 | %% get_negative_cycle_from_predecessors(+Out, -NegativeCycle). | |
312 | get_negative_cycle_from_predecessors(Out, NegativeCycle) :- | |
313 | get_negative_cycle_from_predecessors(Out, Out, [], NegativeCycle). | |
314 | ||
315 | get_negative_cycle_from_predecessors(Start, Start, Acc, Acc) :- | |
316 | Acc \== []. | |
317 | get_negative_cycle_from_predecessors(Start, CurNode, Acc, NegativeCycle) :- | |
318 | retract(predecessor(CurNode, PreNode)), | |
319 | get_negative_cycle_from_predecessors(Start, PreNode, [PreNode|Acc], NegativeCycle). | |
320 | ||
321 | %% get_unsat_core_from_negative_cycle(+GraphMut, +NegativeCycle, -UnsatCore). | |
322 | % Conjunct the constraints corresponding to the negative cycle in the constraint graph. | |
323 | get_unsat_core_from_negative_cycle(GraphMut, [SrcNode|T], UnsatCore) :- | |
324 | get_mutable(graph(_,edges(Edges),_), GraphMut), | |
325 | get_unsat_core_from_negative_cycle(Edges, [SrcNode|T], SrcNode, [], UnsatCoreList), | |
326 | conjunct_predicates(UnsatCoreList, UnsatCore), !. | |
327 | ||
328 | %% get_unsat_core_from_negative_cycle(+Edges, +NegativeCycleNodes, +SrcNode, +Acc, -UnsatCoreList). | |
329 | get_unsat_core_from_negative_cycle(Edges, [CurNode], SrcNode, Acc, NewAcc) :- | |
330 | !, | |
331 | member(CurNode:Adjacent, Edges), | |
332 | member((CurNode,_,SrcNode,DLConstraint), Adjacent), | |
333 | get_original_constraint(DLConstraint, Constraint), | |
334 | %nl,write('Constraint: '), nl, translate:print_bexpr(DLConstraint),nl, | |
335 | %write('Original Constraint: '), nl, translate:print_bexpr(Constraint),nl, | |
336 | NewAcc = [Constraint|Acc]. | |
337 | get_unsat_core_from_negative_cycle(Edges, [CurNode,NextNode|T], SrcNode, Acc, UnsatCoreList) :- | |
338 | member(CurNode:Adjacent, Edges), | |
339 | member((CurNode,_,NextNode,DLConstraint), Adjacent), | |
340 | get_original_constraint(DLConstraint, Constraint), | |
341 | %nl,write('Constraint: '), nl, translate:print_bexpr(DLConstraint),nl, | |
342 | %write('Original Constraint: '), nl, translate:print_bexpr(Constraint),nl, | |
343 | get_unsat_core_from_negative_cycle(Edges, [NextNode|T], SrcNode, [Constraint|Acc], UnsatCoreList). | |
344 | ||
345 | get_original_constraint(b(_,_,Info), Constraint) :- | |
346 | member(idl_origin(TConstraint), Info), | |
347 | !, | |
348 | Constraint = TConstraint. | |
349 | get_original_constraint(b(negation(b(_,_,Info)),_,_), Constraint) :- | |
350 | member(idl_origin(TConstraint), Info), | |
351 | !, | |
352 | Constraint = b(negation(TConstraint),pred,[]). | |
353 | get_original_constraint(DLConstraint, DLConstraint) :- | |
354 | is_idl_constraint(DLConstraint). | |
355 | ||
356 | %% get_unsat_core(-UnsatCore). | |
357 | % Return asserted unsat core or fail. | |
358 | get_unsat_core(UnsatCore) :- | |
359 | unsat_core(UnsatCore). | |
360 | ||
361 | %% possibly_shift_solution_for_zero(+TempBindings, -Bindings). | |
362 | % Constraints of the form x<=c are transformed to x-_zero<=c where _zero is an artificial variable | |
363 | % which is not part of the solution. If _zero is used, the resulting solution has to be shifted by -_zero for each variable | |
364 | % so that _zero=0 holds. | |
365 | possibly_shift_solution_for_zero(TempBindings, Bindings) :- | |
366 | \+ contains_zero, | |
367 | !, | |
368 | Bindings = TempBindings. | |
369 | possibly_shift_solution_for_zero(TempBindings, Bindings) :- | |
370 | select(binding('_zero',int(ZeroVal),_), TempBindings, Rest), | |
371 | ( ZeroVal == 0 | |
372 | -> Bindings = Rest | |
373 | ; shift_solution(ZeroVal, Rest, [], Bindings) | |
374 | ). | |
375 | ||
376 | %% shift_solution(+ZeroVal, +TempBindings, +Acc, -Shifted). | |
377 | shift_solution(_, [], Acc, Acc). | |
378 | shift_solution(ZeroVal, [binding(VarName,int(Value),_)|T], Acc, Shifted) :- | |
379 | NValue is Value - ZeroVal, | |
380 | number_to_atom(NValue, NValueAtom), | |
381 | shift_solution(ZeroVal, T, [binding(VarName,int(NValue),NValueAtom)|Acc], Shifted). | |
382 | ||
383 | number_to_atom(Number, Atom) :- | |
384 | number_codes(Number, Codes), | |
385 | atom_codes(Atom, Codes). | |
386 | ||
387 | register_constraints_from_conj_list(_, []). | |
388 | register_constraints_from_conj_list(GraphMut, [DLConstraint|T]) :- | |
389 | register_idl_constraint(GraphMut, DLConstraint), | |
390 | register_constraints_from_conj_list(GraphMut, T). | |
391 | ||
392 | register_idl_constraint(GraphMut, DLConstraint) :- | |
393 | ( DLConstraint = b(less_equal(b(minus(Minuend,Subtrahend),integer,_),Constant),pred,_), | |
394 | Pol = pos | |
395 | ; DLConstraint = b(negation(b(less_equal(b(minus(Minuend,Subtrahend),integer,_),Constant),pred,_)),pred,_), | |
396 | Pol = neg | |
397 | ), | |
398 | get_int_value(Constant, Value), | |
399 | get_int_var_name(Minuend, MinuendVar), | |
400 | get_int_var_name(Subtrahend, SubtrahendVar), | |
401 | register_node_for_var(GraphMut, MinuendVar), | |
402 | register_node_for_var(GraphMut, SubtrahendVar), | |
403 | add_edge_for_polarity(GraphMut, Pol, DLConstraint, MinuendVar, SubtrahendVar, Value). | |
404 | ||
405 | add_edge_for_polarity(GraphMut, pos, DLConstraint, MinuendVar, SubtrahendVar, Value) :- | |
406 | % edge (y,c,x) for x-y<=c | |
407 | add_edge(GraphMut, DLConstraint, SubtrahendVar, MinuendVar, Value), | |
408 | bt_asserta(constraint_store(SubtrahendVar,MinuendVar,DLConstraint)). | |
409 | add_edge_for_polarity(GraphMut, neg, DLConstraint, MinuendVar, SubtrahendVar, Value) :- | |
410 | % edge (x,-c-1,y) for not(x-y<=c) | |
411 | NValue is Value * -1 - 1, | |
412 | add_edge(GraphMut, DLConstraint, MinuendVar, SubtrahendVar, NValue), | |
413 | bt_asserta(constraint_store(MinuendVar,SubtrahendVar,DLConstraint)). | |
414 | ||
415 | /*print_graph(GraphMut) :- | |
416 | get_mutable(graph(nodes(Nodes),edges(Edges),shortest_paths(SPs)), GraphMut), | |
417 | format("Graph:~nNodes: ~w~nEdges: ~w~nShortest Paths: ~w~n~n", [Nodes,Edges,SPs]).*/ | |
418 | ||
419 | %% add_edge(+GraphMut, +DLConstraint, +In, +Out, +Value). | |
420 | % Possibly replace edge since there can be only one edge between two nodes in integer difference logic. | |
421 | % For instance, x-y<=2 => x-y<=3. | |
422 | add_edge(GraphMut, DLConstraint, In, Out, Value) :- | |
423 | get_mutable(graph(Nodes,edges(Edges),SPs), GraphMut), | |
424 | add_to_edges(Edges, DLConstraint, In, Out, Value, NewEdges), | |
425 | update_mutable(graph(Nodes,edges(NewEdges),SPs), GraphMut). | |
426 | ||
427 | add_to_edges(Edges, DLConstraint, In, Out, Value, NewEdges) :- | |
428 | select(In:Adjacent, Edges, REdges), | |
429 | !, | |
430 | ( select((In,OldValue,Out,_), Adjacent, RAdjacent) | |
431 | -> ( Value < OldValue | |
432 | -> NewEdges = [In:[(In,Value,Out,DLConstraint)|RAdjacent]|REdges], | |
433 | register_negative_weight(Value) | |
434 | ; NewEdges = Edges | |
435 | ) | |
436 | ; NewEdges = [In:[(In,Value,Out,DLConstraint)|Adjacent]|REdges], | |
437 | register_negative_weight(Value) | |
438 | ). | |
439 | add_to_edges(Edges, DLConstraint, In, Out, Value, NewEdges) :- | |
440 | NewEdges = [In:[(In,Value,Out,DLConstraint)]|Edges], | |
441 | register_negative_weight(Value). | |
442 | ||
443 | %% assert_contains_zero. | |
444 | assert_contains_zero :- | |
445 | \+ contains_zero, | |
446 | !, | |
447 | bt_asserta(contains_zero). | |
448 | assert_contains_zero. | |
449 | ||
450 | %% register_negative_weight(+Value). | |
451 | register_negative_weight(Value) :- | |
452 | \+ negative_weight, | |
453 | Value < 0, | |
454 | !, | |
455 | bt_asserta(negative_weight). | |
456 | register_negative_weight(_). | |
457 | ||
458 | %% register_node_for_var(+GraphMut, +VarName). | |
459 | register_node_for_var(GraphMut, VarName) :- | |
460 | get_mutable(graph(nodes(Nodes),_,_), GraphMut), | |
461 | member(VarName, Nodes), | |
462 | !. | |
463 | register_node_for_var(GraphMut, VarName) :- | |
464 | ( VarName == '_zero' | |
465 | -> assert_contains_zero | |
466 | ; true | |
467 | ), | |
468 | get_mutable(graph(nodes(Nodes),Edges,shortest_paths(SPs)), GraphMut), | |
469 | update_mutable(graph(nodes([VarName|Nodes]),Edges,shortest_paths([(VarName,0)|SPs])), GraphMut). | |
470 | ||
471 | is_idl_constraint(Constraint) :- | |
472 | ( Constraint = b(less_equal(Sub,Constant),pred,_) | |
473 | ; Constraint = b(negation(b(less_equal(Sub,Constant),pred,_)),pred,_) | |
474 | ), | |
475 | Sub = b(minus(Id1,Id2),integer,_), | |
476 | get_int_value(Constant, _), | |
477 | Id1 = b(identifier(_),integer,_), | |
478 | Id2 = b(identifier(_),integer,_). | |
479 | ||
480 | %% get_int_var_name(+IdentifierAst, -VarName). | |
481 | get_int_var_name(b(identifier(VarName),integer,_), VarName). | |
482 | ||
483 | %% insertion_sort(+List, +Node, +DiffToOld, -Sorted) :- | |
484 | % Sort by largest change in distance. | |
485 | insertion_sort([], Node, Dist, [(Node,Dist)]). | |
486 | insertion_sort([(Node1,Dist1)|T], Node, Dist, Sorted) :- | |
487 | Dist1 < Dist, | |
488 | !, | |
489 | Sorted = [(Node,Dist),(Node1,Dist1)|T]. | |
490 | insertion_sort([(Node1,Dist1)|T], Node, Dist, [(Node1,Dist1)|NT]) :- | |
491 | insertion_sort(T, Node, Dist, NT). | |
492 | ||
493 | assert_distance(GraphMut, Node, NDNode, DiffToOld) :- | |
494 | get_mutable(graph(Nodes,Edges,shortest_paths(SPs)), GraphMut), | |
495 | select((Node,Old), SPs, Rest), | |
496 | NewSPs = [(Node,NDNode)|Rest], | |
497 | update_mutable(graph(Nodes,Edges,shortest_paths(NewSPs)), GraphMut), | |
498 | DiffToOld is Old - NDNode. | |
499 | ||
500 | assert_predecessor(Node, PreNode) :- | |
501 | bt_retract(predecessor(Node,_)), | |
502 | bt_asserta(predecessor(Node,PreNode)). | |
503 | assert_predecessor(Node, PreNode) :- | |
504 | \+ predecessor(Node,_), | |
505 | bt_asserta(predecessor(Node,PreNode)). | |
506 | ||
507 | bt_asserta(Term) :- | |
508 | asserta(Term); (retract(Term), fail). | |
509 | ||
510 | bt_retract(Assertion) :- | |
511 | ( retract(Assertion) | |
512 | -> ( true | |
513 | ; asserta(Assertion), | |
514 | fail | |
515 | ) | |
516 | ; fail | |
517 | ). | |
518 | ||
519 | % TO DO: are there more constraints? x:{1,3,7}? | |
520 | infer_constraints_for_idl_solver(MemberNat, [Constraint]) :- | |
521 | % x:NAT -> _zero-x <= 0 | |
522 | % x:NAT1 -> _zero-x <= -1 | |
523 | MemberNat = b(member(Id,Natural),pred,_), | |
524 | Id = b(identifier(_),integer,_), | |
525 | ( Natural = b(integer_set('NATURAL'),set(integer),_), | |
526 | Constraint = b(less_equal(b(minus(b(identifier('_zero'),integer,[]),Id),integer,[]),b(integer(0),integer,[])),pred,[idl_origin(MemberNat)]) | |
527 | ; Natural = b(integer_set('NATURAL1'),set(integer),_), | |
528 | Constraint = b(less_equal(b(minus(b(identifier('_zero'),integer,[]),Id),integer,[]),b(integer(-1),integer,[])),pred,[idl_origin(MemberNat)]) | |
529 | ). | |
530 | infer_constraints_for_idl_solver(MemberInterval, [LEQ1,LEQ2]) :- | |
531 | % x:min..max -> _zero-x<=-min & x<=max | |
532 | MemberInterval = b(member(Id,Interval),pred,_), | |
533 | Id = b(identifier(_),integer,_), | |
534 | Interval = b(interval(Min,Max),set(integer),_), | |
535 | Min = b(integer(MinVal),integer,MinInfo), | |
536 | Max = b(integer(_),integer,_), | |
537 | MinVal1 is MinVal * -1, | |
538 | LEQ1 = b(less_equal(b(minus(b(identifier('_zero'),integer,[]), Id),integer,[]),b(integer(MinVal1),integer,MinInfo)),pred,[idl_origin(MemberInterval)]), | |
539 | LEQ2 = b(less_equal(b(minus(Id,b(identifier('_zero'),integer,[])),integer,[]),Max),pred,[idl_origin(MemberInterval)]). | |
540 | infer_constraints_for_idl_solver(EqualCard, [Constraint]) :- | |
541 | % x=card(s) -> _zero-x<=0 | |
542 | % x=size(s) -> _zero-x<=0 | |
543 | ( EqualCard = b(equal(Id,CardOrSize),pred,_) | |
544 | ; EqualCard = b(equal(CardOrSize,Id),pred,_) | |
545 | ), | |
546 | Id = b(identifier(_),integer,_), | |
547 | ( CardOrSize = b(card(_),integer,_) | |
548 | ; CardOrSize = b(size(_),integer,_) | |
549 | ), | |
550 | Constraint = b(less_equal(b(minus(b(identifier('_zero'),integer,[]), Id),integer,[]),b(integer(0),integer,[])),pred,[idl_origin(EqualCard)]). | |
551 | ||
552 | ||
553 | :- begin_tests(difference_logic_solver). | |
554 | ||
555 | test(simple_sat1, [nondet]) :- | |
556 | init_idl_solver(GraphMut), | |
557 | % a-c<=1 & c-b<=-3 | |
558 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(c),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
559 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(c),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(-3),integer,[])),pred,[])), | |
560 | !, | |
561 | get_solver_result(GraphMut, Res), | |
562 | ground(Res), | |
563 | Res = solution(Bindings), | |
564 | member(binding(a,int(-2),'-2'), Bindings), | |
565 | member(binding(b,int(0),'0'), Bindings), | |
566 | member(binding(c,int(-3),'-3'), Bindings), | |
567 | \+ get_unsat_core(_). | |
568 | ||
569 | test(simple_sat2, [nondet]) :- | |
570 | init_idl_solver(GraphMut), | |
571 | % a-c<=-1 & c-b<=3 | |
572 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(c),integer,[])),integer,[]),b(integer(-1),integer,[])),pred,[])), | |
573 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(c),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(3),integer,[])),pred,[])), | |
574 | !, | |
575 | get_solver_result(GraphMut, Res), | |
576 | ground(Res), | |
577 | Res = solution(Bindings), | |
578 | member(binding(a,int(-1),'-1'), Bindings), | |
579 | member(binding(b,int(0),'0'), Bindings), | |
580 | member(binding(c,int(0),'0'), Bindings), | |
581 | \+ get_unsat_core(_). | |
582 | ||
583 | test(simple_sat3, [nondet]) :- | |
584 | init_idl_solver(GraphMut), | |
585 | % a-c<=1 & c-b<=3 | |
586 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(c),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
587 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(c),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(3),integer,[])),pred,[])), | |
588 | !, | |
589 | get_solver_result(GraphMut, Res), | |
590 | ground(Res), | |
591 | Res = solution(Bindings), | |
592 | member(binding(a,int(0),'0'), Bindings), | |
593 | member(binding(b,int(0),'0'), Bindings), | |
594 | member(binding(c,int(0),'0'), Bindings), | |
595 | \+ get_unsat_core(_). | |
596 | ||
597 | test(simple_sat4, [nondet]) :- | |
598 | init_idl_solver(GraphMut), | |
599 | % a-1<=1 & 3<=b & 2<=b-1 | |
600 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(integer(1),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
601 | register_constraint(GraphMut, b(less_equal(b(integer(3),integer,[]),b(identifier(b),integer,[])),pred,[])), | |
602 | register_constraint(GraphMut, b(less_equal(b(integer(2),integer,[]),b(minus(b(identifier(b),integer,[]),b(integer(1),integer,[])),integer,[])),pred,[])), | |
603 | !, | |
604 | get_solver_result(GraphMut, Res), | |
605 | ground(Res), | |
606 | Res = solution(Bindings), | |
607 | member(binding(a,int(2),'2'), Bindings), | |
608 | member(binding(b,int(3),'3'), Bindings), | |
609 | \+ get_unsat_core(_). | |
610 | ||
611 | test(simple_sat_introduce_zero, [nondet]) :- | |
612 | init_idl_solver(GraphMut), | |
613 | % a-b<=-1 & a<=-1 | |
614 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(-1),integer,[])),pred,[])), | |
615 | register_constraint(GraphMut, b(less_equal(b(identifier(a),integer,[]),b(integer(-1),integer,[])),pred,[])), | |
616 | !, | |
617 | get_solver_result(GraphMut, Res), | |
618 | ground(Res), | |
619 | Res = solution(Bindings), | |
620 | member(binding(a,int(-1),'-1'), Bindings), | |
621 | member(binding(b,int(0),'0'), Bindings), | |
622 | \+ get_unsat_core(_). | |
623 | ||
624 | test(simple_sat_rewrite_equality, [nondet]) :- | |
625 | init_idl_solver(GraphMut), | |
626 | % a-b<=-1 & a=1 | |
627 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(-1),integer,[])),pred,[])), | |
628 | register_constraint(GraphMut, b(equal(b(identifier(a),integer,[]),b(integer(1),integer,[])),pred,[])), | |
629 | !, | |
630 | get_solver_result(GraphMut, Res), | |
631 | Res = solution(Bindings), | |
632 | member(binding(a,int(1),'1'), Bindings), | |
633 | member(binding(b,int(2),'2'), Bindings), | |
634 | \+ get_unsat_core(_). | |
635 | ||
636 | test(simple_sat_all_solutions_single_var, [nondet]) :- | |
637 | init_idl_solver(GraphMut), | |
638 | % all solutions for x>0 & x<5 | |
639 | register_constraint(GraphMut, b(greater(b(identifier(x),integer,[]),b(integer(0),integer,[])),pred,[])), | |
640 | register_constraint(GraphMut, b(less(b(identifier(x),integer,[]),b(integer(10),integer,[])),pred,[])), | |
641 | !, | |
642 | findall(Res, get_all_solutions_on_bt(GraphMut, Res), SolverResults), | |
643 | SolverResults == [solution([binding(x,int(1),'1')]),solution([binding(x,int(2),'2')]),solution([binding(x,int(3),'3')]),solution([binding(x,int(4),'4')]),solution([binding(x,int(5),'5')]),solution([binding(x,int(6),'6')]),solution([binding(x,int(7),'7')]),solution([binding(x,int(8),'8')]),solution([binding(x,int(9),'9')])]. | |
644 | ||
645 | test(simple_sat_all_solutions_two_vars, [nondet]) :- | |
646 | init_idl_solver(GraphMut), | |
647 | % all solutions for x>0 & x<4 & y>0 & y<4 | |
648 | register_constraint(GraphMut, b(greater(b(identifier(x),integer,[]),b(integer(0),integer,[])),pred,[])), | |
649 | register_constraint(GraphMut, b(less(b(identifier(x),integer,[]),b(integer(4),integer,[])),pred,[])), | |
650 | register_constraint(GraphMut, b(greater(b(identifier(y),integer,[]),b(integer(0),integer,[])),pred,[])), | |
651 | register_constraint(GraphMut, b(less(b(identifier(y),integer,[]),b(integer(4),integer,[])),pred,[])), | |
652 | !, | |
653 | findall(Res, get_all_solutions_on_bt(GraphMut, Res), SolverResults), | |
654 | length(SolverResults, Length), | |
655 | Length == 9, | |
656 | SolverResults == [solution([binding(y,int(1),'1'),binding(x,int(1),'1')]),solution([binding(y,int(2),'2'),binding(x,int(2),'2')]),solution([binding(y,int(3),'3'),binding(x,int(3),'3')]),solution([binding(x,int(2),'2'),binding(y,int(3),'3')]),solution([binding(x,int(1),'1'),binding(y,int(3),'3')]),solution([binding(x,int(1),'1'),binding(y,int(2),'2')]),solution([binding(y,int(2),'2'),binding(x,int(3),'3')]),solution([binding(y,int(1),'1'),binding(x,int(2),'2')]),solution([binding(y,int(1),'1'),binding(x,int(3),'3')])]. | |
657 | ||
658 | test(simple_sat_all_solutions_two_vars_subtraction, [nondet]) :- | |
659 | init_idl_solver(GraphMut), | |
660 | % all solutions for x>0 & x<10 & y>0 & y<10 & x-y>5 | |
661 | register_constraint(GraphMut, b(greater(b(identifier(x),integer,[]),b(integer(0),integer,[])),pred,[])), | |
662 | register_constraint(GraphMut, b(less(b(identifier(x),integer,[]),b(integer(10),integer,[])),pred,[])), | |
663 | register_constraint(GraphMut, b(greater(b(identifier(y),integer,[]),b(integer(0),integer,[])),pred,[])), | |
664 | register_constraint(GraphMut, b(less(b(identifier(y),integer,[]),b(integer(10),integer,[])),pred,[])), | |
665 | register_constraint(GraphMut, b(greater(b(minus(b(identifier(x),integer,[]),b(identifier(y),integer,[])),integer,[]),b(integer(5),integer,[])),pred,[])), | |
666 | !, | |
667 | findall(Res, get_all_solutions_on_bt(GraphMut, Res), SolverResults), | |
668 | length(SolverResults, Length), | |
669 | Length == 6, | |
670 | SolverResults == [solution([binding(y,int(1),'1'),binding(x,int(7),'7')]),solution([binding(y,int(2),'2'),binding(x,int(8),'8')]),solution([binding(y,int(3),'3'),binding(x,int(9),'9')]),solution([binding(y,int(2),'2'),binding(x,int(9),'9')]),solution([binding(y,int(1),'1'),binding(x,int(8),'8')]),solution([binding(y,int(1),'1'),binding(x,int(9),'9')])]. | |
671 | ||
672 | test(simple_unsat1, [nondet]) :- | |
673 | init_idl_solver(GraphMut), | |
674 | % a-c<=1 & c-b<=-3 & b-a<=1 | |
675 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(c),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
676 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(c),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(-3),integer,[])),pred,[])), | |
677 | \+ register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(b),integer,[]),b(identifier(a),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
678 | !, | |
679 | get_solver_result(GraphMut, Res), | |
680 | Res == contradiction_found, | |
681 | get_unsat_core(UnsatCore), | |
682 | UnsatCore = b(conjunct(b(conjunct(b(less_equal(b(minus(b(identifier(b),integer,_),b(identifier(a),integer,_)),integer,_),b(integer(1),integer,_)),pred,_),b(less_equal(b(minus(b(identifier(a),integer,_),b(identifier(c),integer,_)),integer,_),b(integer(1),integer,_)),pred,_)),pred,_),b(less_equal(b(minus(b(identifier(c),integer,_),b(identifier(b),integer,_)),integer,_),b(integer(-3),integer,_)),pred,_)),pred,_). | |
683 | ||
684 | test(simple_unsat2, [nondet]) :- | |
685 | init_idl_solver(GraphMut), | |
686 | % c-c<=1 & a-c<=1 & c-b<=-3 & b-a<=1 | |
687 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(c),integer,[]),b(identifier(c),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
688 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(c),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
689 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(c),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(-3),integer,[])),pred,[])), | |
690 | \+ register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(b),integer,[]),b(identifier(a),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
691 | !, | |
692 | get_solver_result(GraphMut, Res), | |
693 | Res == contradiction_found, | |
694 | get_unsat_core(UnsatCore), | |
695 | % c-c<=1 is not part of the unsat core | |
696 | UnsatCore = b(conjunct(b(conjunct(b(less_equal(b(minus(b(identifier(b),integer,_),b(identifier(a),integer,_)),integer,_),b(integer(1),integer,_)),pred,_),b(less_equal(b(minus(b(identifier(a),integer,_),b(identifier(c),integer,_)),integer,_),b(integer(1),integer,_)),pred,_)),pred,_),b(less_equal(b(minus(b(identifier(c),integer,_),b(identifier(b),integer,_)),integer,_),b(integer(-3),integer,_)),pred,_)),pred,_). | |
697 | ||
698 | test(simple_unsat_negation, [nondet]) :- | |
699 | init_idl_solver(GraphMut), | |
700 | % a-b<=-1 & a<=-1 & b<=10 & not(a<=-1) | |
701 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(-1),integer,[])),pred,[])), | |
702 | register_constraint(GraphMut, b(less_equal(b(identifier(a),integer,[]),b(integer(-1),integer,[])),pred,[])), | |
703 | register_constraint(GraphMut, b(less_equal(b(identifier(b),integer,[]),b(integer(10),integer,[])),pred,[])), | |
704 | \+ register_constraint(GraphMut, b(negation(b(less_equal(b(identifier(a),integer,[]),b(integer(-1),integer,[])),pred,[])),pred,[])), | |
705 | !, | |
706 | get_solver_result(GraphMut, Res), | |
707 | Res = contradiction_found, | |
708 | get_unsat_core(UnsatCore), | |
709 | % not(a<=-1) & a<=-1 | |
710 | UnsatCore = b(conjunct(b(negation(b(less_equal(b(identifier(a),integer,_),b(integer(-1),integer,_)),pred,_)),pred,_),b(less_equal(b(identifier(a),integer,_),b(integer(-1),integer,_)),pred,_)),pred,_). | |
711 | ||
712 | test(simple_unsat_negation_rewrite_beforehand, [nondet]) :- | |
713 | init_idl_solver(GraphMut), | |
714 | % we receive the same unsat core containing the original constraints when rewriting constraints before registering them | |
715 | % a-b<=-1 & a<=-1 & b<=10 & not(a<=-1) | |
716 | C2 = b(less_equal(b(identifier(a),integer,[]),b(integer(-1),integer,[])),pred,[]), | |
717 | C3 = b(less_equal(b(identifier(b),integer,[]),b(integer(10),integer,[])),pred,[]), | |
718 | C4 = b(negation(b(less_equal(b(identifier(a),integer,[]),b(integer(-1),integer,[])),pred,[])),pred,[]), | |
719 | rewrite_to_idl(C2, C2IdlConjList), | |
720 | rewrite_to_idl(C3, C3IdlConjList), | |
721 | rewrite_to_idl(C4, C4IdlConjList), | |
722 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(-1),integer,[])),pred,[])), | |
723 | register_constraints(GraphMut, C2IdlConjList), | |
724 | register_constraints(GraphMut, C3IdlConjList), | |
725 | \+ register_constraints(GraphMut, C4IdlConjList), | |
726 | !, | |
727 | get_solver_result(GraphMut, Res), | |
728 | Res = contradiction_found, | |
729 | get_unsat_core(UnsatCore), | |
730 | % not(a<=-1) & a<=-1 | |
731 | UnsatCore = b(conjunct(b(negation(b(less_equal(b(identifier(a),integer,_),b(integer(-1),integer,_)),pred,_)),pred,_),b(less_equal(b(identifier(a),integer,_),b(integer(-1),integer,_)),pred,_)),pred,_). | |
732 | ||
733 | :- end_tests(difference_logic_solver). | |
734 | ||
735 | :- begin_tests(dynamic_state). | |
736 | ||
737 | empty_graph_state(GraphMut) :- | |
738 | \+ negative_weight, | |
739 | \+ contains_zero, | |
740 | get_mutable(graph(nodes([]),edges([]),shortest_paths([])), GraphMut), | |
741 | \+ constraint_store(_,_,_). | |
742 | ||
743 | test(register_constraint_undone_on_bt1, []) :- | |
744 | init_idl_solver(GraphMut), | |
745 | empty_graph_state(GraphMut), | |
746 | Constraint = b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[]), | |
747 | ( register_constraint(GraphMut, Constraint), | |
748 | get_mutable(graph(nodes(Nodes),edges(Edges),shortest_paths(SPs)), GraphMut), | |
749 | memberchk(a, Nodes), | |
750 | memberchk(b, Nodes), | |
751 | memberchk(b:[(b,1,a,_)], Edges), | |
752 | memberchk((a,0), SPs), | |
753 | memberchk((b,0), SPs), | |
754 | constraint_store(b,a,Constraint), | |
755 | \+ negative_weight, | |
756 | \+ contains_zero, | |
757 | fail | |
758 | ; empty_graph_state(GraphMut) | |
759 | ). | |
760 | ||
761 | test(register_constraint_undone_on_bt2, []) :- | |
762 | init_idl_solver(GraphMut), | |
763 | empty_graph_state(GraphMut), | |
764 | Constraint = b(less_equal(b(identifier(a),integer,[]),b(integer(-1),integer,[])),pred,[]), | |
765 | ( register_constraint(GraphMut, Constraint), | |
766 | get_mutable(graph(nodes(Nodes),edges(Edges),shortest_paths(SPs)), GraphMut), | |
767 | memberchk(a, Nodes), | |
768 | memberchk('_zero', Nodes), | |
769 | memberchk('_zero':[('_zero',-1,a,_)], Edges), | |
770 | memberchk((a,-1), SPs), | |
771 | memberchk(('_zero',0), SPs), | |
772 | constraint_store('_zero',a,b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier('_zero'),integer,[])),integer,[]),b(integer(-1),integer,[])),pred,[])), | |
773 | negative_weight, | |
774 | contains_zero, | |
775 | fail | |
776 | ; empty_graph_state(GraphMut) | |
777 | ). | |
778 | ||
779 | test(register_constraint_overwrite_old, [nondet]) :- | |
780 | init_idl_solver(GraphMut), | |
781 | empty_graph_state(GraphMut), | |
782 | % a-b<=2 is replaced by a-b<=1 | |
783 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(2),integer,[])),pred,[])), | |
784 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
785 | get_mutable(graph(nodes(_),edges(Edges),shortest_paths(SPs)), GraphMut), | |
786 | memberchk('b':[('b',1,a,_)], Edges), | |
787 | memberchk((a,0), SPs), | |
788 | memberchk((b,0), SPs). | |
789 | ||
790 | test(register_constraint_overwrite_old_undone_on_bt, [nondet]) :- | |
791 | init_idl_solver(GraphMut), | |
792 | empty_graph_state(GraphMut), | |
793 | % a-b<=2 is replaced by a-b<=1 but effect is undone on backtracking | |
794 | register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(2),integer,[])),pred,[])), | |
795 | ( register_constraint(GraphMut, b(less_equal(b(minus(b(identifier(a),integer,[]),b(identifier(b),integer,[])),integer,[]),b(integer(1),integer,[])),pred,[])), | |
796 | fail | |
797 | ; get_mutable(graph(nodes(_),edges(Edges),shortest_paths(SPs)), GraphMut), | |
798 | memberchk('b':[('b',2,a,_)], Edges), | |
799 | memberchk((a,0), SPs), | |
800 | memberchk((b,0), SPs) | |
801 | ). | |
802 | ||
803 | :- end_tests(dynamic_state). |