(X1 or neg X2 or X3 $= 1
.
This represents the clause X1 ∨ ¬ X2 ∨ X3.tent_init
to find an initial solution
conflict_constraints
and term_variables
to find a
variable to label
set_to_tent
to set the remaining variables to their
tentative values
prop_sat_1(Vars) :- Vars = [X1,X2,X3], tent_init(Vars), (X1 or neg X2 or X3 $= 1) r_conflict cs, (neg X1 or neg X2 $= 1) r_conflict cs, (X2 or neg X3 $= 1) r_conflict cs, min_conflicts(Vars). tent_init(List) :- ( foreach(Var,List) do Var tent_set 1 ). min_conflicts(Vars) :- conflict_constraints(cs,List), ( List = [] -> set_to_tent(Vars) ; List = [Constraint|_] -> term_variables(Constraint,[Var|_]), guess(Var), min_conflicts(Vars) ). guess(0). guess(1). set_to_tent(Term) :- Term tent_get Tent, Term = Tent. |
guess
is naive. Since the variable
occurs in a conflict constraint it would arguably be better to label
it to another value. This would be implemented as follows:
guess(Var) :- Var tent_get Value, ( Value = 0 -> (Var=1 ; Var=0) ; Value = 1 -> (Var=0 ; Var=1) ). |
before(TimePoint1,Interval,TimePoint2) :- TimePoint1+Interval #=< TimePoint2. |
TimePoint1
and TimePoint2
are variables (or numbers),
but we assume, for this example, that the
Interval
is a number.
This constraint can enforce a minimum separation between start times,
or a maximum separation (if the Interval
is negative). It can
also enforce constraints between end times, by adjusting the
Interval
to account for the task durations.
noclash(Start1,Duration1,Start2,_) :- Start2 #>= Start1+Duration1. noclash(Start1,_,Start2,Duration2) :- Start1 #>= Start2+Duration2. |
End
which is
constrained to come after all the tasks.
Ignoring the resource constraints, the temporal constraints are easily
handled by ic.
The optimal solution is obtained simply by posting the temporal
constraints and then instantiating each start
time to the lowest value in its domain.Start2 #>= Start1+Duration1
to ic.
On backtracking, the second clause will be unfolded instead.
:- lib(ic), lib(repair), lib(branch_and_bound). schedule(Starts,End) :- Starts = [S1,S2,...,End], Starts :: 0..1000, before(S2,5,S1), before(S1,8,End), ... noclash(S1,4,S2,8) r_conflict resource_cons, ... minimize(repair_ic(Starts),End). repair_ic(Starts) :- set_tent_to_min(Starts), conflict_constraints(resource_cons,List), ( List = [] -> set_to_tent(Starts) ; List = [Constraint|_] -> call(Constraint), repair_ic(Starts) ). set_tent_to_min(Vars) :- ( foreach(Var,Vars) do get_min(Var,Min), Var tent_set Min ). |
bridge_repair.pl
.
Repair naturally supports conflict minimisation. This algorithm can be combined with other solvers, such as ic, and with optimization.
Figure 13.3: Conflict Minimisation