To choose among the IntVar variables and the int64 values when branching, several variables and values selection primitives are available. As stated before (see the subsection The 2-steps approach in the previous section for more), the selection is done in two steps:
To construct the corresponding DecisionBuilder, use one of the MakePhase() factory methods. For instance:
DecisionBuilder* MakePhase(const std::vector<IntVar*>& vars,
IntVarStrategy var_str,
IntValueStrategy val_str);
The IntVarStrategy enum describes the available strategies to select the next branching variable at each node during a phase search:
Most of the strategies are self-explanatory except maybe for CHOOSE_PATH. This selection strategy is most convenient when you try to find simple paths (paths with no repeated vertices) in a solution and the variables correspond to nodes on the paths. When a variable i is bound (has been assigned a value), the path connects variable i to the next variable vars[i] as on the figure below:
We have
where corresponds to a variable that wasn’t assigned a value. We have , and . The next variable to be choosen will be and in this case . What happens if is assigned the value ? This strategy will pick up another unbounded variable.
In general, the selection CHOOSE_PATH will happen as follow:
- Try to extend an existing path: look for an unbound variable, to which some other variable points.
- If no such path is found, try to find a start node of a path: look for an unbound variable, to which no other variable can point.
- If everything else fails, pick the first unbound variable.
We will encounter paths again in third part of this manual, when we’ll discuss routing.
The IntValueStrategy enum describes the strategies available to select the next value(s) for the already chosen variable at each node during the search:
Just for fun, we have developed a SolverBenchmark class to test different search strategies. Statistics are recorded thanks to the SolverBenchmarkStats class. You can find both classes in the solver_benchmark.h header.
In phases1.cc, we test different combinations of the above strategies to find the variables and the values to branch on. You can try it for yourself and see that basically no predefined strategy really outperforms any other.
The program writes a report text file with the best statistics about the search of the CP Solver to solve the n-Queens Problem given a specified size. The text files have report_n.txt as name with n the size considered.
We summarize the results when we run the program with sizes , , and in the following table:
Best wall time: | Best branches: | |
---|---|---|
ChooseFirstUnbound - AssignMin | RandomSelector - AssignCenter | |
ChooseFirstUnbound - AssignMin | MinSizeLowestMinSelector - AssignMin | |
MinSizeHighestMinSelector - AssignCenter | MinSizeHighestMinSelector - AssignMin | |
MinSizeHighestMaxSelector - AssignCenter | MinSizeLowestMinSelector - AssignMin |
The most fun (and most efficient) way to use or-tools is to define your own selection strategies and search primitives. This is the subject of the next section.