| 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). |