There are two methods to customize search in or-tools
The first one consists in using search phases:
slv.Phase(variables, var_heuristic, value_heuristic)
slv.INT_VAR_DEFAULT # Pick the first unbound variable
slv.INT_VALUE_DEFAULT # Assign min value
But there are many more possibilities!
For the variable selection, we have:
slv.CHOOSE_FIRST_UNBOUND
slv.CHOOSE_RANDOM
slv.CHOOSE_MIN_SIZE_LOWEST_MIN
slv.CHOOSE_MIN_SIZE_HIGHEST_MIN
slv.CHOOSE_MIN_SIZE_LOWEST_MAX
slv.CHOOSE_MIN_SIZE_HIGHEST_MAX
slv.CHOOSE_LOWEST_MIN
slv.CHOOSE_HIGHEST_MAX
slv.CHOOSE_MIN_SIZE
slv.CHOOSE_MAX_SIZE
slv.CHOOSE_MAX_REGRET_ON_MIN
MIN_SIZE
and MAX_SIZE
refer to the domain sizeFor the variable selection, we have:
slv.CHOOSE_FIRST_UNBOUND
slv.CHOOSE_RANDOM
slv.CHOOSE_MIN_SIZE_LOWEST_MIN
slv.CHOOSE_MIN_SIZE_HIGHEST_MIN
slv.CHOOSE_MIN_SIZE_LOWEST_MAX
slv.CHOOSE_MIN_SIZE_HIGHEST_MAX
slv.CHOOSE_LOWEST_MIN
slv.CHOOSE_HIGHEST_MAX
slv.CHOOSE_MIN_SIZE
slv.CHOOSE_MAX_SIZE
slv.CHOOSE_MAX_REGRET_ON_MIN
MIN_SIZE_...
strategies break ties using different criteriaFor the variable selection, we have:
slv.CHOOSE_FIRST_UNBOUND
slv.CHOOSE_RANDOM
slv.CHOOSE_MIN_SIZE_LOWEST_MIN
slv.CHOOSE_MIN_SIZE_HIGHEST_MIN
slv.CHOOSE_MIN_SIZE_LOWEST_MAX
slv.CHOOSE_MIN_SIZE_HIGHEST_MAX
slv.CHOOSE_LOWEST_MIN
slv.CHOOSE_HIGHEST_MAX
slv.CHOOSE_MIN_SIZE
slv.CHOOSE_MAX_SIZE
slv.CHOOSE_MAX_REGRET_ON_MIN
MAX_REGRET_ON_MIN
picks the variable with the largest difference...For the value selection, we have:
ASSIGN_MIN_VALUE
ASSIGN_MAX_VALUE
ASSIGN_RANDOM_VALUE
ASSIGN_CENTER_VALUE
SPLIT_LOWER_HALF
SPLIT_UPPER_HALF
SPLIT_...
strategies use the domain splitting schemeSearch phases on different variables can be combined:
db = slv.Compose([phase1, phase2, ...])
phase2
starts once all phase1
vars are assigned, and so onThe second method consists in writing a custom DecisionBuilder
class Example(pywrapcp.PyDecisionBuilder):
def __init__(self, vars):
pywrapcp.PyDecisionBuilder.__init__(self)
self.vars = vars
def Next(self, slv):
if [all vars are assigned]:
return None
else:
decision = [build decision object]
return decision
A decision builder should repeatedly return a decision object
There are several types of decision objects, including:
x=v∨x≠v
)slv.AssignVariableValue(var, value)
x≤v∨x>v
)slv.SplitVariableDomain(var, value, start_lower_half)
x=v
)slv.AssignVariableValueOrFail(var, value)
Let's consider the following problem (by Pierre Schaus)
Similarly to our production scheduling scenario:
n
product units to be producedUnlike in our production scheduling scenario:
We start from a given model:
The main constraints:
min
i
we keep track of the production time date_i
...succ_i
{\rm\scriptsize CIRCUIT}
constraint...We start from a given model:
The main constraints:
\begin{align}
\min \ & z = \text{ trans. cost } + \text{ stocking cost }\\
\text{subject to: }
& {\rm\scriptsize ALLDIFFERENT}(date) \\
& date_i \leq d_i & \forall i = 0..n \\
& {\rm\scriptsize CIRCUIT}(succ) \\
& date_i < date_{succ_i} & \forall i = 0..n-1 \\
& date_{n} = n_{periods}
\end{align}
{\rm\scriptsize CIRCUIT}
makes sure that the succ
variables form a cycle...n
We start from a given model:
The variable domains:
\begin{align}
& date_i \in \{0..n_{periods}\} & \forall i = 0..n \\
& succ_i \in \{0..n\} & \forall i = 0..n \\
\end{align}
The cost expressions:
\begin{align}
& \text{ trans. cost } = \sum_{i = 0..n-1} T_{i, succ_i} \\
& \text{ stocking cost } = c_{stocking} \sum_{i = 0..n-1} (d_i - date_i)
\end{align}
T_{i,j}
is the transition cost from unit i
to j
c_{stocking}
is the stocking costWe start from a given model:
Some symmetry breaking constraints:
\begin{align}
& date_i < date_j & \forall i, j = 0..n-1, i \neq j, p_i = p_j, d_i < d_j \\
& succ_j \neq i & \forall i, j = 0..n-1, i \neq j, p_i = p_j, d_i < d_j \\
& succ_i \neq i & \forall i = 0..n \\
\end{align}
Some general comments:
Objective: design a search strategy for the problem
Phase
DecisionBuilder
Some comments:
DecisionBuilder
written in Python is Objective: design a search strategy for the problem
Phase
DecisionBuilder
Some comments: