This section describes the original constraint programming solver, which has been replaced by the superior CP-SAT solver.
The following sections describe how to solve the example described in the CP-SAT section, this time using the original CP solver. If you insist on using the original CP solver, you can browse the the API reference. Note that the original CP solver is the foundation of the routing library, and its API may be necessary to customize a routing model.
Import the libraries
The following code imports the required library.
Python
from ortools.constraint_solver import pywrapcp
C++
#include <ostream> #include <string> #include "ortools/constraint_solver/constraint_solver.h"
Java
import com.google.ortools.Loader; import com.google.ortools.constraintsolver.DecisionBuilder; import com.google.ortools.constraintsolver.IntVar; import com.google.ortools.constraintsolver.Solver; import java.util.logging.Logger;
C#
using System; using Google.OrTools.ConstraintSolver;
Declare the solver
The following code declares the solver.
Python
solver = pywrapcp.Solver("CPSimple")
C++
Solver solver("CpSimple");
Java
Solver solver = new Solver("CpSimple");
C#
Solver solver = new Solver("CpSimple");
Create the variables
The following code creates the variables for the problem.
The solver creates three variables, x, y, and z, each of which can take on the values 0, 1, or 2.
Python
num_vals = 3 x = solver.IntVar(0, num_vals - 1, "x") y = solver.IntVar(0, num_vals - 1, "y") z = solver.IntVar(0, num_vals - 1, "z")
C++
const int64_t num_vals = 3; IntVar* const x = solver.MakeIntVar(0, num_vals - 1, "x"); IntVar* const y = solver.MakeIntVar(0, num_vals - 1, "y"); IntVar* const z = solver.MakeIntVar(0, num_vals - 1, "z");
Java
final long numVals = 3; final IntVar x = solver.makeIntVar(0, numVals - 1, "x"); final IntVar y = solver.makeIntVar(0, numVals - 1, "y"); final IntVar z = solver.makeIntVar(0, numVals - 1, "z");
C#
const long numVals = 3; IntVar x = solver.MakeIntVar(0, numVals - 1, "x"); IntVar y = solver.MakeIntVar(0, numVals - 1, "y"); IntVar z = solver.MakeIntVar(0, numVals - 1, "z");
Create the constraint
The following code creates the constraint x ≠ y
.
Python
solver.Add(x != y) print("Number of constraints: ", solver.Constraints())
C++
solver.AddConstraint(solver.MakeAllDifferent({x, y})); LOG(INFO) << "Number of constraints: " << std::to_string(solver.constraints());
Java
solver.addConstraint(solver.makeAllDifferent(new IntVar[] {x, y})); logger.info("Number of constraints: " + solver.constraints());
C#
solver.Add(solver.MakeAllDifferent(new IntVar[] { x, y })); Console.WriteLine($"Number of constraints: {solver.Constraints()}");
Call the solver
The following code calls the solver.
The decision builder is the main input to the original CP solver. It contains the following:
vars
— An array containing the variables for the problem.- A rule for choosing the next variable to assign a value to.
- A rule for choosing the next value to assign to that variable.
See Decision builder for details.
Python
decision_builder = solver.Phase( [x, y, z], solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE )
C++
DecisionBuilder* const db = solver.MakePhase( {x, y, z}, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE);
Java
final DecisionBuilder db = solver.makePhase( new IntVar[] {x, y, z}, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);
C#
DecisionBuilder db = solver.MakePhase(new IntVar[] { x, y, z }, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE);
Print the solution
The code for the solution printer, which displays each solution as the solver finds it, is shown in the following section.
Because there's more than one solution to our problem, one can iterate through
the solutions with a while solver.NextSolution()
loop. (Note that this works
differently than the solution printer for the CP-SAT solver).
Python
count = 0 solver.NewSearch(decision_builder) while solver.NextSolution(): count += 1 solution = f"Solution {count}:\n" for var in [x, y, z]: solution += f" {var.Name()} = {var.Value()}" print(solution) solver.EndSearch() print(f"Number of solutions found: {count}")
C++
int count = 0; solver.NewSearch(db); while (solver.NextSolution()) { ++count; LOG(INFO) << "Solution " << count << ":" << std::endl << " x=" << x->Value() << " y=" << y->Value() << " z=" << z->Value(); } solver.EndSearch(); LOG(INFO) << "Number of solutions found: " << solver.solutions();
Java
int count = 0; solver.newSearch(db); while (solver.nextSolution()) { ++count; logger.info( String.format("Solution: %d\n x=%d y=%d z=%d", count, x.value(), y.value(), z.value())); } solver.endSearch(); logger.info("Number of solutions found: " + solver.solutions());
C#
int count = 0; solver.NewSearch(db); while (solver.NextSolution()) { ++count; Console.WriteLine($"Solution: {count}\n x={x.Value()} y={y.Value()} z={z.Value()}"); } solver.EndSearch(); Console.WriteLine($"Number of solutions found: {solver.Solutions()}");
Results returned by the solver
Here are the 18 solutions found by the solver:
Number of constraints: 1 Solution 1: x = 0 y = 1 z = 0 Solution 2: x = 0 y = 1 z = 1 Solution 3: x = 0 y = 1 z = 2 Solution 4: x = 0 y = 2 z = 0 Solution 5: x = 0 y = 2 z = 1 Solution 6: x = 0 y = 2 z = 2 Solution 7: x = 1 y = 0 z = 0 Solution 8: x = 1 y = 0 z = 1 Solution 9: x = 1 y = 0 z = 2 Solution 10: x = 1 y = 2 z = 0 Solution 11: x = 1 y = 2 z = 1 Solution 12: x = 1 y = 2 z = 2 Solution 13: x = 2 y = 0 z = 0 Solution 14: x = 2 y = 0 z = 1 Solution 15: x = 2 y = 0 z = 2 Solution 16: x = 2 y = 1 z = 0 Solution 17: x = 2 y = 1 z = 1 Solution 18: x = 2 y = 1 z = 2 Number of solutions found: 18 Advanced usage: Problem solved in 2 ms Memory usage: 13918208 bytes
Complete program
Here are the complete programs for the example using the original CP solver.
Python
"""Simple Constraint optimization example.""" from ortools.constraint_solver import pywrapcp def main(): """Entry point of the program.""" # Instantiate the solver. solver = pywrapcp.Solver("CPSimple") # Create the variables. num_vals = 3 x = solver.IntVar(0, num_vals - 1, "x") y = solver.IntVar(0, num_vals - 1, "y") z = solver.IntVar(0, num_vals - 1, "z") # Constraint 0: x != y. solver.Add(x != y) print("Number of constraints: ", solver.Constraints()) # Solve the problem. decision_builder = solver.Phase( [x, y, z], solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE ) # Print solution on console. count = 0 solver.NewSearch(decision_builder) while solver.NextSolution(): count += 1 solution = f"Solution {count}:\n" for var in [x, y, z]: solution += f" {var.Name()} = {var.Value()}" print(solution) solver.EndSearch() print(f"Number of solutions found: {count}") print("Advanced usage:") print(f"Problem solved in {solver.WallTime()}ms") print(f"Memory usage: {pywrapcp.Solver.MemoryUsage()}bytes") if __name__ == "__main__": main()
C++
#include <ostream> #include <string> #include "ortools/constraint_solver/constraint_solver.h" namespace operations_research { void SimpleCpProgram() { // Instantiate the solver. Solver solver("CpSimple"); // Create the variables. const int64_t num_vals = 3; IntVar* const x = solver.MakeIntVar(0, num_vals - 1, "x"); IntVar* const y = solver.MakeIntVar(0, num_vals - 1, "y"); IntVar* const z = solver.MakeIntVar(0, num_vals - 1, "z"); // Constraint 0: x != y.. solver.AddConstraint(solver.MakeAllDifferent({x, y})); LOG(INFO) << "Number of constraints: " << std::to_string(solver.constraints()); // Solve the problem. DecisionBuilder* const db = solver.MakePhase( {x, y, z}, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE); // Print solution on console. int count = 0; solver.NewSearch(db); while (solver.NextSolution()) { ++count; LOG(INFO) << "Solution " << count << ":" << std::endl << " x=" << x->Value() << " y=" << y->Value() << " z=" << z->Value(); } solver.EndSearch(); LOG(INFO) << "Number of solutions found: " << solver.solutions(); LOG(INFO) << "Advanced usage:" << std::endl << "Problem solved in " << std::to_string(solver.wall_time()) << "ms" << std::endl << "Memory usage: " << std::to_string(Solver::MemoryUsage()) << "bytes"; } } // namespace operations_research int main(int /*argc*/, char* /*argv*/[]) { operations_research::SimpleCpProgram(); return EXIT_SUCCESS; }
Java
package com.google.ortools.constraintsolver.samples; import com.google.ortools.Loader; import com.google.ortools.constraintsolver.DecisionBuilder; import com.google.ortools.constraintsolver.IntVar; import com.google.ortools.constraintsolver.Solver; import java.util.logging.Logger; /** Simple CP Program.*/ public class SimpleCpProgram { private SimpleCpProgram() {} private static final Logger logger = Logger.getLogger(SimpleCpProgram.class.getName()); public static void main(String[] args) throws Exception { Loader.loadNativeLibraries(); // Instantiate the solver. Solver solver = new Solver("CpSimple"); // Create the variables. final long numVals = 3; final IntVar x = solver.makeIntVar(0, numVals - 1, "x"); final IntVar y = solver.makeIntVar(0, numVals - 1, "y"); final IntVar z = solver.makeIntVar(0, numVals - 1, "z"); // Constraint 0: x != y.. solver.addConstraint(solver.makeAllDifferent(new IntVar[] {x, y})); logger.info("Number of constraints: " + solver.constraints()); // Solve the problem. final DecisionBuilder db = solver.makePhase( new IntVar[] {x, y, z}, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // Print solution on console. int count = 0; solver.newSearch(db); while (solver.nextSolution()) { ++count; logger.info( String.format("Solution: %d\n x=%d y=%d z=%d", count, x.value(), y.value(), z.value())); } solver.endSearch(); logger.info("Number of solutions found: " + solver.solutions()); logger.info(String.format("Advanced usage:\nProblem solved in %d ms\nMemory usage: %d bytes", solver.wallTime(), Solver.memoryUsage())); } }
C#
using System; using Google.OrTools.ConstraintSolver; /// <summary> /// This is a simple CP program. /// </summary> public class SimpleCpProgram { public static void Main(String[] args) { // Instantiate the solver. Solver solver = new Solver("CpSimple"); // Create the variables. const long numVals = 3; IntVar x = solver.MakeIntVar(0, numVals - 1, "x"); IntVar y = solver.MakeIntVar(0, numVals - 1, "y"); IntVar z = solver.MakeIntVar(0, numVals - 1, "z"); // Constraint 0: x != y.. solver.Add(solver.MakeAllDifferent(new IntVar[] { x, y })); Console.WriteLine($"Number of constraints: {solver.Constraints()}"); // Solve the problem. DecisionBuilder db = solver.MakePhase(new IntVar[] { x, y, z }, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // Print solution on console. int count = 0; solver.NewSearch(db); while (solver.NextSolution()) { ++count; Console.WriteLine($"Solution: {count}\n x={x.Value()} y={y.Value()} z={z.Value()}"); } solver.EndSearch(); Console.WriteLine($"Number of solutions found: {solver.Solutions()}"); Console.WriteLine("Advanced usage:"); Console.WriteLine($"Problem solved in {solver.WallTime()}ms"); Console.WriteLine($"Memory usage: {Solver.MemoryUsage()}bytes"); } }
Decision builder
The main input to the original CP solver is the decision builder, which contains the variables for the problem and sets options for the solver.
The code example in the previous section creates a decision builder
using the Phase
method (corresponding to the C++ method
MakePhase
.
The term Phase refers to a phase of the search. In this simple example, there is just one phase, but for more complex problems, the decision builder can have more than one phase, so that the solver can employ different search strategies from one phase to the next.
The Phase
method has three input parameters:
vars
— An array containing the variables for the problem, which in this case is[x, y, z]
.IntVarStrategy
— The rule for choosing the next unbound variable to assign a value. Here, the code uses the defaultCHOOSE_FIRST_UNBOUND
, which means that at each step, the solver selects the first unbound variable in the order they occur in the variable array passed to thePhase
method.IntValueStrategy
— The rule for choosing the next value to assign to a variable. Here the code uses the defaultASSIGN_MIN_VALUE
, which selects the smallest value that hasn't already been tried for the variable. This assigns values in increasing order. Another option isASSIGN_MAX_VALUE
, in which case the solver would assign values in decreasing order.