diff --git a/.github/workflows/cmake_system_deps.yml b/.github/workflows/cmake_system_deps.yml
index 2172af0d61..a9b6e4dee8 100644
--- a/.github/workflows/cmake_system_deps.yml
+++ b/.github/workflows/cmake_system_deps.yml
@@ -36,5 +36,6 @@ jobs:
- name: Test Install
run: make --directory=cmake ${DISTRO}_${LANG}_install_test
-# TODO(mizux): Add macOS + brew job
-# TODO(mizux): Add Windows + choco/vcpkg job
+# TODO(user): Add macOS + brew job
+# TODO(user): Add Windows + choco/vcpkg job
+
diff --git a/cmake/python.cmake b/cmake/python.cmake
index d91789c2b0..46224d4467 100644
--- a/cmake/python.cmake
+++ b/cmake/python.cmake
@@ -389,6 +389,7 @@ if(BUILD_TESTING)
${PROJECT_SOURCE_DIR}/ortools/init/python/version_test.py.in
${PROJECT_BINARY_DIR}/python/version_test.py
@ONLY)
+
# run the tests within the virtualenv
add_test(NAME python_init_version_test
COMMAND ${VENV_Python3_EXECUTABLE} ${PROJECT_BINARY_DIR}/python/version_test.py)
diff --git a/cmake/samples/dotnet/CPSample.cs b/cmake/samples/dotnet/CPSample.cs
index acc5ca18f2..2adff51a46 100644
--- a/cmake/samples/dotnet/CPSample.cs
+++ b/cmake/samples/dotnet/CPSample.cs
@@ -1,3 +1,16 @@
+// Copyright 2010-2022 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
using System;
using Xunit;
diff --git a/cmake/samples/dotnet/LPSample.cs b/cmake/samples/dotnet/LPSample.cs
index 9de0277377..dd7910dec4 100644
--- a/cmake/samples/dotnet/LPSample.cs
+++ b/cmake/samples/dotnet/LPSample.cs
@@ -1,3 +1,16 @@
+// Copyright 2010-2022 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
using System;
using Xunit;
diff --git a/cmake/samples/dotnet/RoutingSample.cs b/cmake/samples/dotnet/RoutingSample.cs
index edd1bed20c..ce2cd8413a 100644
--- a/cmake/samples/dotnet/RoutingSample.cs
+++ b/cmake/samples/dotnet/RoutingSample.cs
@@ -1,3 +1,16 @@
+// Copyright 2010-2022 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
using System;
using Xunit;
diff --git a/cmake/samples/dotnet/SATSample.cs b/cmake/samples/dotnet/SATSample.cs
index 122df519a7..0cf6fcf076 100644
--- a/cmake/samples/dotnet/SATSample.cs
+++ b/cmake/samples/dotnet/SATSample.cs
@@ -1,3 +1,16 @@
+// Copyright 2010-2022 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
using System;
using Xunit;
diff --git a/cmake/samples/java/src/main/java/com/google/ortools/App.java b/cmake/samples/java/src/main/java/com/google/ortools/App.java
index b3fa4d82b2..64fe48d720 100644
--- a/cmake/samples/java/src/main/java/com/google/ortools/App.java
+++ b/cmake/samples/java/src/main/java/com/google/ortools/App.java
@@ -1,3 +1,16 @@
+// Copyright 2010-2022 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
package com.google.ortools;
/** Hello world! */
diff --git a/cmake/samples/java/src/test/java/com/google/ortools/AppTest.java b/cmake/samples/java/src/test/java/com/google/ortools/AppTest.java
index b14e396326..61dcde5b9e 100644
--- a/cmake/samples/java/src/test/java/com/google/ortools/AppTest.java
+++ b/cmake/samples/java/src/test/java/com/google/ortools/AppTest.java
@@ -1,3 +1,16 @@
+// Copyright 2010-2022 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
package com.google.ortools;
import junit.framework.Test;
diff --git a/cmake/samples/python/sample.py b/cmake/samples/python/sample.py
index 3e425b047f..063b5a8aee 100644
--- a/cmake/samples/python/sample.py
+++ b/cmake/samples/python/sample.py
@@ -1,3 +1,17 @@
+#!/usr/bin/env python3
+# Copyright 2010-2022 Google LLC
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
"""Sample to test or-tools installation."""
import ortools
# from ortools.algorithms import pywrapknapsack_solver
diff --git a/makefiles/docs/generate_image.sh b/makefiles/docs/generate_image.sh
index 5bd21128a3..f1edd7a072 100755
--- a/makefiles/docs/generate_image.sh
+++ b/makefiles/docs/generate_image.sh
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-#/usr/bin/env bash
set -ex
rm -f *.svg
diff --git a/ortools/base/BUILD.bazel b/ortools/base/BUILD.bazel
index a56d400caa..281a0a5205 100644
--- a/ortools/base/BUILD.bazel
+++ b/ortools/base/BUILD.bazel
@@ -202,6 +202,7 @@ cc_library(
hdrs = [
"file.h",
"helpers.h",
+ "options.h",
],
deps = [
":base",
diff --git a/ortools/base/options.h b/ortools/base/options.h
new file mode 100644
index 0000000000..1aa40990c4
--- /dev/null
+++ b/ortools/base/options.h
@@ -0,0 +1,19 @@
+// Copyright 2010-2022 Google LLC
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef OR_TOOLS_BASE_OPTIONS_H_
+#define OR_TOOLS_BASE_OPTIONS_H_
+
+#include "ortools/base/file.h"
+
+#endif // OR_TOOLS_BASE_OPTIONS_H_
diff --git a/ortools/constraint_solver/docs/CP.md b/ortools/constraint_solver/docs/CP.md
index 5b0e90e542..430415d217 100644
--- a/ortools/constraint_solver/docs/CP.md
+++ b/ortools/constraint_solver/docs/CP.md
@@ -68,49 +68,50 @@ int main(int argc, char** argv) {
### Python code samples
```python
+#!/usr/bin/env python3
"""Simple Constraint optimization example."""
from ortools.constraint_solver import pywrapcp
def main():
- """Entry point of the program."""
- # Instantiate the solver.
- solver = pywrapcp.Solver('CPSimple')
+ """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')
+ # 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())
+ # 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)
+ # 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 = 'Solution {}:\n'.format(count)
- for var in [x, y, z]:
- solution += ' {} = {}'.format(var.Name(), var.Value())
- print(solution)
- solver.EndSearch()
- print('Number of solutions found: ', count)
+ # Print solution on console.
+ count = 0
+ solver.NewSearch(decision_builder)
+ while solver.NextSolution():
+ count += 1
+ solution = 'Solution {}:\n'.format(count)
+ for var in [x, y, z]:
+ solution += ' {} = {}'.format(var.Name(), var.Value())
+ print(solution)
+ solver.EndSearch()
+ print('Number of solutions found: ', count)
- print('Advanced usage:')
- print('Problem solved in ', solver.WallTime(), 'ms')
- print('Memory usage: ', pywrapcp.Solver.MemoryUsage(), 'bytes')
+ print('Advanced usage:')
+ print('Problem solved in ', solver.WallTime(), 'ms')
+ print('Memory usage: ', pywrapcp.Solver.MemoryUsage(), 'bytes')
if __name__ == '__main__':
- main()
+ main()
```
### Java code samples
@@ -141,39 +142,32 @@ public class SimpleCpProgram {
final IntVar z = solver.makeIntVar(0, numVals - 1, "z");
// Constraint 0: x != y..
- solver.addConstraint(solver.makeAllDifferent(new IntVar[]{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);
+ 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()));
+ 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()));
+ logger.info(String.format("Advanced usage:\nProblem solved in %d ms\nMemory usage: %d bytes",
+ solver.wallTime(), Solver.memoryUsage()));
}
}
```
### .Net code samples
-
```cs
using System;
using Google.OrTools.ConstraintSolver;
@@ -181,38 +175,41 @@ using Google.OrTools.ConstraintSolver;
///
/// This is a simple CP program.
///
-public class SimpleCpProgram {
- public static void Main(String[] args) {
- // Instantiate the solver.
- Solver solver = new Solver("CpSimple");
+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");
+ // 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()}");
+ // 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);
+ // 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()}");
+ // 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");
}
- 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");
- }
}
```
diff --git a/ortools/constraint_solver/docs/ROUTING.md b/ortools/constraint_solver/docs/ROUTING.md
index 7bb360c2f0..fb7758c6d2 100644
--- a/ortools/constraint_solver/docs/ROUTING.md
+++ b/ortools/constraint_solver/docs/ROUTING.md
@@ -89,6 +89,7 @@ int main(int argc, char** argv) {
### Python code samples
```python
+#!/usr/bin/env python3
"""Vehicle Routing example."""
from ortools.constraint_solver import routing_enums_pb2
@@ -96,59 +97,57 @@ from ortools.constraint_solver import pywrapcp
def main():
- """Entry point of the program."""
- # Instantiate the data problem.
- num_locations = 5
- num_vehicles = 1
- depot = 0
+ """Entry point of the program."""
+ # Instantiate the data problem.
+ num_locations = 5
+ num_vehicles = 1
+ depot = 0
- # Create the routing index manager.
- manager = pywrapcp.RoutingIndexManager(
- num_locations,
- num_vehicles,
- depot)
+ # Create the routing index manager.
+ manager = pywrapcp.RoutingIndexManager(num_locations, num_vehicles, depot)
- # Create Routing Model.
- routing = pywrapcp.RoutingModel(manager)
+ # Create Routing Model.
+ routing = pywrapcp.RoutingModel(manager)
- # Create and register a transit callback.
- def distance_callback(from_index, to_index):
- """Returns the absolute difference between the two nodes."""
- # Convert from routing variable Index to user NodeIndex.
- from_node = int(manager.IndexToNode(from_index))
- to_node = int(manager.IndexToNode(to_index))
- return abs(to_node - from_node)
- transit_callback_index = routing.RegisterTransitCallback(distance_callback)
+ # Create and register a transit callback.
+ def distance_callback(from_index, to_index):
+ """Returns the absolute difference between the two nodes."""
+ # Convert from routing variable Index to user NodeIndex.
+ from_node = int(manager.IndexToNode(from_index))
+ to_node = int(manager.IndexToNode(to_index))
+ return abs(to_node - from_node)
- # Define cost of each arc.
- routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
+ transit_callback_index = routing.RegisterTransitCallback(distance_callback)
- # Setting first solution heuristic.
- search_parameters = pywrapcp.DefaultRoutingSearchParameters()
- search_parameters.first_solution_strategy = (
- routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member
+ # Define cost of each arc.
+ routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
- # Solve the problem.
- assignment = routing.SolveWithParameters(search_parameters)
+ # Setting first solution heuristic.
+ search_parameters = pywrapcp.DefaultRoutingSearchParameters()
+ search_parameters.first_solution_strategy = (
+ routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member
- # Print solution on console.
- print('Objective: {}'.format(assignment.ObjectiveValue()))
- index = routing.Start(0)
- plan_output = 'Route for vehicle 0:\n'
- route_distance = 0
- while not routing.IsEnd(index):
- plan_output += '{} -> '.format(manager.IndexToNode(index))
- previous_index = index
- index = assignment.Value(routing.NextVar(index))
- route_distance += routing.GetArcCostForVehicle(previous_index, index, 0)
- plan_output += '{}\n'.format(manager.IndexToNode(index))
- plan_output += 'Distance of the route: {}m\n'.format(route_distance)
- print(plan_output)
+ # Solve the problem.
+ assignment = routing.SolveWithParameters(search_parameters)
+
+ # Print solution on console.
+ print('Objective: {}'.format(assignment.ObjectiveValue()))
+ index = routing.Start(0)
+ plan_output = 'Route for vehicle 0:\n'
+ route_distance = 0
+ while not routing.IsEnd(index):
+ plan_output += '{} -> '.format(manager.IndexToNode(index))
+ previous_index = index
+ index = assignment.Value(routing.NextVar(index))
+ route_distance += routing.GetArcCostForVehicle(previous_index, index, 0)
+ plan_output += '{}\n'.format(manager.IndexToNode(index))
+ plan_output += 'Distance of the route: {}m\n'.format(route_distance)
+ print(plan_output)
if __name__ == '__main__':
- main()
+ main()
```
### Java code samples
@@ -158,18 +157,17 @@ package com.google.ortools.constraintsolver.samples;
import static java.lang.Math.abs;
import com.google.ortools.Loader;
-import com.google.ortools.constraintsolver.FirstSolutionStrategy;
-import com.google.ortools.constraintsolver.RoutingSearchParameters;
import com.google.ortools.constraintsolver.Assignment;
+import com.google.ortools.constraintsolver.FirstSolutionStrategy;
import com.google.ortools.constraintsolver.RoutingIndexManager;
import com.google.ortools.constraintsolver.RoutingModel;
+import com.google.ortools.constraintsolver.RoutingSearchParameters;
import com.google.ortools.constraintsolver.main;
import java.util.logging.Logger;
/** Minimal Routing example to showcase calling the solver.*/
public class SimpleRoutingProgram {
- private static final Logger logger =
- Logger.getLogger(SimpleRoutingProgram.class.getName());
+ private static final Logger logger = Logger.getLogger(SimpleRoutingProgram.class.getName());
public static void main(String[] args) throws Exception {
Loader.loadNativeLibraries();
@@ -185,8 +183,8 @@ public class SimpleRoutingProgram {
RoutingModel routing = new RoutingModel(manager);
// Create and register a transit callback.
- final int transitCallbackIndex = routing.registerTransitCallback(
- (long fromIndex, long toIndex) -> {
+ final int transitCallbackIndex =
+ routing.registerTransitCallback((long fromIndex, long toIndex) -> {
// Convert from routing variable Index to user NodeIndex.
int fromNode = manager.indexToNode(fromIndex);
int toNode = manager.indexToNode(toIndex);
@@ -236,53 +234,58 @@ using Google.OrTools.ConstraintSolver;
///
/// This is a sample using the routing library .Net wrapper.
///
-public class SimpleRoutingProgram {
- public static void Main(String[] args) {
- // Instantiate the data problem.
- const int numLocation = 5;
- const int numVehicles = 1;
- const int depot = 0;
+public class SimpleRoutingProgram
+{
+ public static void Main(String[] args)
+ {
+ // Instantiate the data problem.
+ const int numLocation = 5;
+ const int numVehicles = 1;
+ const int depot = 0;
- // Create Routing Index Manager
- RoutingIndexManager manager = new RoutingIndexManager(numLocation, numVehicles, depot);
+ // Create Routing Index Manager
+ RoutingIndexManager manager = new RoutingIndexManager(numLocation, numVehicles, depot);
- // Create Routing Model.
- RoutingModel routing = new RoutingModel(manager);
+ // Create Routing Model.
+ RoutingModel routing = new RoutingModel(manager);
- // Create and register a transit callback.
- int transitCallbackIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) => {
- // Convert from routing variable Index to distance matrix NodeIndex.
- var fromNode = manager.IndexToNode(fromIndex);
- var toNode = manager.IndexToNode(toIndex);
- return Math.Abs(toNode - fromNode);
- });
+ // Create and register a transit callback.
+ int transitCallbackIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) =>
+ {
+ // Convert from routing variable Index to
+ // distance matrix NodeIndex.
+ var fromNode = manager.IndexToNode(fromIndex);
+ var toNode = manager.IndexToNode(toIndex);
+ return Math.Abs(toNode - fromNode);
+ });
- // Define cost of each arc.
- routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
+ // Define cost of each arc.
+ routing.SetArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
- // Setting first solution heuristic.
- RoutingSearchParameters searchParameters =
- operations_research_constraint_solver.DefaultRoutingSearchParameters();
- searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;
+ // Setting first solution heuristic.
+ RoutingSearchParameters searchParameters =
+ operations_research_constraint_solver.DefaultRoutingSearchParameters();
+ searchParameters.FirstSolutionStrategy = FirstSolutionStrategy.Types.Value.PathCheapestArc;
- // Solve the problem.
- Assignment solution = routing.SolveWithParameters(searchParameters);
+ // Solve the problem.
+ Assignment solution = routing.SolveWithParameters(searchParameters);
- // Print solution on console.
- Console.WriteLine("Objective: {0}", solution.ObjectiveValue());
- // Inspect solution.
- long index = routing.Start(0);
- Console.WriteLine("Route for Vehicle 0:");
- long route_distance = 0;
- while (routing.IsEnd(index) == false) {
- Console.Write("{0} -> ", manager.IndexToNode((int)index));
- long previousIndex = index;
- index = solution.Value(routing.NextVar(index));
- route_distance += routing.GetArcCostForVehicle(previousIndex, index, 0);
+ // Print solution on console.
+ Console.WriteLine("Objective: {0}", solution.ObjectiveValue());
+ // Inspect solution.
+ long index = routing.Start(0);
+ Console.WriteLine("Route for Vehicle 0:");
+ long route_distance = 0;
+ while (routing.IsEnd(index) == false)
+ {
+ Console.Write("{0} -> ", manager.IndexToNode((int)index));
+ long previousIndex = index;
+ index = solution.Value(routing.NextVar(index));
+ route_distance += routing.GetArcCostForVehicle(previousIndex, index, 0);
+ }
+ Console.WriteLine("{0}", manager.IndexToNode(index));
+ Console.WriteLine("Distance of the route: {0}m", route_distance);
}
- Console.WriteLine("{0}", manager.IndexToNode(index));
- Console.WriteLine("Distance of the route: {0}m", route_distance);
- }
}
```
diff --git a/ortools/constraint_solver/docs/routing_svg.py b/ortools/constraint_solver/docs/routing_svg.py
index d5fb0e15b6..f9b6fcf8a0 100755
--- a/ortools/constraint_solver/docs/routing_svg.py
+++ b/ortools/constraint_solver/docs/routing_svg.py
@@ -10,7 +10,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-
"""Generate SVG for a Routing problem."""
# [START import]
@@ -22,883 +21,919 @@ from ortools.constraint_solver import routing_enums_pb2
# [START data_model]
class DataModel(object): # pylint: disable=too-many-instance-attributes
- """Stores the data for the problem."""
+ """Stores the data for the problem."""
- def __init__(self, args):
- # Locations in block units
- locations = [
- (4, 4), # depot
- (2, 0), (8, 0), # locations to visit
- (0, 1), (1, 1),
- (5, 2), (7, 2),
- (3, 3), (6, 3),
- (5, 5), (8, 5),
- (1, 6), (2, 6),
- (3, 7), (6, 7),
- (0, 8), (7, 8),
- ]
- # Convert locations in meters using a city block dimension of 114m x 80m.
- self._locations = [(l[0] * 114, l[1] * 80) for l in locations]
- self._distance_matrix = [
- [
- 0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354,
- 468, 776, 662
- ],
- [
- 548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674,
- 1016, 868, 1210
- ],
- [
- 776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164,
- 1130, 788, 1552, 754
- ],
- [
- 696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822,
- 1164, 560, 1358
- ],
- [
- 582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708,
- 1050, 674, 1244
- ],
- [
- 274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628,
- 514, 1050, 708
- ],
- [
- 502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856,
- 514, 1278, 480
- ],
- [
- 194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320,
- 662, 742, 856
- ],
- [
- 308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662,
- 320, 1084, 514
- ],
- [
- 194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388,
- 274, 810, 468
- ],
- [
- 536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764,
- 730, 388, 1152, 354
- ],
- [
- 502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114,
- 308, 650, 274, 844
- ],
- [
- 388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194,
- 536, 388, 730
- ],
- [
- 354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0,
- 342, 422, 536
- ],
- [
- 468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536,
- 342, 0, 764, 194
- ],
- [
- 776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274,
- 388, 422, 764, 0, 798
- ],
- [
- 662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730,
- 536, 194, 798, 0
- ],
- ]
- self._time_matrix = [
- [0, 6, 9, 8, 7, 3, 6, 2, 3, 2, 6, 6, 4, 4, 5, 9, 7],
- [6, 0, 8, 3, 2, 6, 8, 4, 8, 8, 13, 7, 5, 8, 12, 10, 14],
- [9, 8, 0, 11, 10, 6, 3, 9, 5, 8, 4, 15, 14, 13, 9, 18, 9],
- [8, 3, 11, 0, 1, 7, 10, 6, 10, 10, 14, 6, 7, 9, 14, 6, 16],
- [7, 2, 10, 1, 0, 6, 9, 4, 8, 9, 13, 4, 6, 8, 12, 8, 14],
- [3, 6, 6, 7, 6, 0, 2, 3, 2, 2, 7, 9, 7, 7, 6, 12, 8],
- [6, 8, 3, 10, 9, 2, 0, 6, 2, 5, 4, 12, 10, 10, 6, 15, 5],
- [2, 4, 9, 6, 4, 3, 6, 0, 4, 4, 8, 5, 4, 3, 7, 8, 10],
- [3, 8, 5, 10, 8, 2, 2, 4, 0, 3, 4, 9, 8, 7, 3, 13, 6],
- [2, 8, 8, 10, 9, 2, 5, 4, 3, 0, 4, 6, 5, 4, 3, 9, 5],
- [6, 13, 4, 14, 13, 7, 4, 8, 4, 4, 0, 10, 9, 8, 4, 13, 4],
- [6, 7, 15, 6, 4, 9, 12, 5, 9, 6, 10, 0, 1, 3, 7, 3, 10],
- [4, 5, 14, 7, 6, 7, 10, 4, 8, 5, 9, 1, 0, 2, 6, 4, 8],
- [4, 8, 13, 9, 8, 7, 10, 3, 7, 4, 8, 3, 2, 0, 4, 5, 6],
- [5, 12, 9, 14, 12, 6, 6, 7, 3, 3, 4, 7, 6, 4, 0, 9, 2],
- [9, 10, 18, 6, 8, 12, 15, 8, 13, 9, 13, 3, 4, 5, 9, 0, 9],
- [7, 14, 9, 16, 14, 8, 5, 10, 6, 5, 4, 10, 8, 6, 2, 9, 0],
- ]
- self._time_windows = [
- (0, 5), # depot
- (7, 12), # 1
- (10, 15), # 2
- (5, 14), # 3
- (5, 13), # 4
- (0, 5), # 5
- (5, 10), # 6
- (0, 10), # 7
- (5, 10), # 8
- (0, 5), # 9
- (10, 16), # 10
- (10, 15), # 11
- (0, 5), # 12
- (5, 10), # 13
- (7, 12), # 14
- (10, 15), # 15
- (5, 15), # 16
- ]
- if args['drop_nodes']:
- self._demands = [0, 1, 1, 3, 6, 3, 6, 8, 8, 1, 2, 1, 2, 6, 6, 8, 8]
- else:
- self._demands = [0, 1, 1, 2, 4, 2, 4, 8, 8, 1, 2, 1, 2, 4, 4, 8, 8]
- self._pickups_deliveries = [
- [1, 6],
- [2, 10],
- [4, 3],
- [5, 9],
- [7, 8],
- [15, 11],
- [13, 12],
- [16, 14],
- ]
+ def __init__(self, args):
+ # Locations in block units
+ locations = [
+ (4, 4), # depot
+ (2, 0),
+ (8, 0), # locations to visit
+ (0, 1),
+ (1, 1),
+ (5, 2),
+ (7, 2),
+ (3, 3),
+ (6, 3),
+ (5, 5),
+ (8, 5),
+ (1, 6),
+ (2, 6),
+ (3, 7),
+ (6, 7),
+ (0, 8),
+ (7, 8),
+ ]
+ # Convert locations in meters using a city block dimension of 114m x 80m.
+ self._locations = [(l[0] * 114, l[1] * 80) for l in locations]
+ self._distance_matrix = [
+ [
+ 0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388,
+ 354, 468, 776, 662
+ ],
+ [
+ 548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480,
+ 674, 1016, 868, 1210
+ ],
+ [
+ 776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278,
+ 1164, 1130, 788, 1552, 754
+ ],
+ [
+ 696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628,
+ 822, 1164, 560, 1358
+ ],
+ [
+ 582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514,
+ 708, 1050, 674, 1244
+ ],
+ [
+ 274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662,
+ 628, 514, 1050, 708
+ ],
+ [
+ 502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890,
+ 856, 514, 1278, 480
+ ],
+ [
+ 194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354,
+ 320, 662, 742, 856
+ ],
+ [
+ 308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696,
+ 662, 320, 1084, 514
+ ],
+ [
+ 194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422,
+ 388, 274, 810, 468
+ ],
+ [
+ 536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878,
+ 764, 730, 388, 1152, 354
+ ],
+ [
+ 502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0,
+ 114, 308, 650, 274, 844
+ ],
+ [
+ 388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0,
+ 194, 536, 388, 730
+ ],
+ [
+ 354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308,
+ 194, 0, 342, 422, 536
+ ],
+ [
+ 468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650,
+ 536, 342, 0, 764, 194
+ ],
+ [
+ 776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152,
+ 274, 388, 422, 764, 0, 798
+ ],
+ [
+ 662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844,
+ 730, 536, 194, 798, 0
+ ],
+ ]
+ self._time_matrix = [
+ [0, 6, 9, 8, 7, 3, 6, 2, 3, 2, 6, 6, 4, 4, 5, 9, 7],
+ [6, 0, 8, 3, 2, 6, 8, 4, 8, 8, 13, 7, 5, 8, 12, 10, 14],
+ [9, 8, 0, 11, 10, 6, 3, 9, 5, 8, 4, 15, 14, 13, 9, 18, 9],
+ [8, 3, 11, 0, 1, 7, 10, 6, 10, 10, 14, 6, 7, 9, 14, 6, 16],
+ [7, 2, 10, 1, 0, 6, 9, 4, 8, 9, 13, 4, 6, 8, 12, 8, 14],
+ [3, 6, 6, 7, 6, 0, 2, 3, 2, 2, 7, 9, 7, 7, 6, 12, 8],
+ [6, 8, 3, 10, 9, 2, 0, 6, 2, 5, 4, 12, 10, 10, 6, 15, 5],
+ [2, 4, 9, 6, 4, 3, 6, 0, 4, 4, 8, 5, 4, 3, 7, 8, 10],
+ [3, 8, 5, 10, 8, 2, 2, 4, 0, 3, 4, 9, 8, 7, 3, 13, 6],
+ [2, 8, 8, 10, 9, 2, 5, 4, 3, 0, 4, 6, 5, 4, 3, 9, 5],
+ [6, 13, 4, 14, 13, 7, 4, 8, 4, 4, 0, 10, 9, 8, 4, 13, 4],
+ [6, 7, 15, 6, 4, 9, 12, 5, 9, 6, 10, 0, 1, 3, 7, 3, 10],
+ [4, 5, 14, 7, 6, 7, 10, 4, 8, 5, 9, 1, 0, 2, 6, 4, 8],
+ [4, 8, 13, 9, 8, 7, 10, 3, 7, 4, 8, 3, 2, 0, 4, 5, 6],
+ [5, 12, 9, 14, 12, 6, 6, 7, 3, 3, 4, 7, 6, 4, 0, 9, 2],
+ [9, 10, 18, 6, 8, 12, 15, 8, 13, 9, 13, 3, 4, 5, 9, 0, 9],
+ [7, 14, 9, 16, 14, 8, 5, 10, 6, 5, 4, 10, 8, 6, 2, 9, 0],
+ ]
+ self._time_windows = [
+ (0, 5), # depot
+ (7, 12), # 1
+ (10, 15), # 2
+ (5, 14), # 3
+ (5, 13), # 4
+ (0, 5), # 5
+ (5, 10), # 6
+ (0, 10), # 7
+ (5, 10), # 8
+ (0, 5), # 9
+ (10, 16), # 10
+ (10, 15), # 11
+ (0, 5), # 12
+ (5, 10), # 13
+ (7, 12), # 14
+ (10, 15), # 15
+ (5, 15), # 16
+ ]
+ if args['drop_nodes']:
+ self._demands = [0, 1, 1, 3, 6, 3, 6, 8, 8, 1, 2, 1, 2, 6, 6, 8, 8]
+ else:
+ self._demands = [0, 1, 1, 2, 4, 2, 4, 8, 8, 1, 2, 1, 2, 4, 4, 8, 8]
+ self._pickups_deliveries = [
+ [1, 6],
+ [2, 10],
+ [4, 3],
+ [5, 9],
+ [7, 8],
+ [15, 11],
+ [13, 12],
+ [16, 14],
+ ]
- if args['tsp']:
- self._num_vehicles = 1
- else:
- self._num_vehicles = 4
- self._vehicle_capacities = [15, 15, 15, 15]
+ if args['tsp']:
+ self._num_vehicles = 1
+ else:
+ self._num_vehicles = 4
+ self._vehicle_capacities = [15, 15, 15, 15]
- if args['resources']:
- self._vehicle_load_time = 5
- self._vehicle_unload_time = 5
+ if args['resources']:
+ self._vehicle_load_time = 5
+ self._vehicle_unload_time = 5
- self._depot = 0
- self._depot_capacity = 2
- self._starts = [1, 2, 15, 16]
- self._ends = [0, 0, 0, 0]
+ self._depot = 0
+ self._depot_capacity = 2
+ self._starts = [1, 2, 15, 16]
+ self._ends = [0, 0, 0, 0]
- @property
- def locations(self):
- """Gets the locations."""
- return self._locations
+ @property
+ def locations(self):
+ """Gets the locations."""
+ return self._locations
- @property
- def distance_matrix(self):
- """Gets the distance matrix."""
- return self._distance_matrix
+ @property
+ def distance_matrix(self):
+ """Gets the distance matrix."""
+ return self._distance_matrix
- @property
- def time_matrix(self):
- """Gets the time matrix."""
- return self._time_matrix
+ @property
+ def time_matrix(self):
+ """Gets the time matrix."""
+ return self._time_matrix
- @property
- def time_windows(self):
- """Gets the time windows."""
- return self._time_windows
+ @property
+ def time_windows(self):
+ """Gets the time windows."""
+ return self._time_windows
- @property
- def demands(self):
- """Gets the locations demands."""
- return self._demands
+ @property
+ def demands(self):
+ """Gets the locations demands."""
+ return self._demands
- @property
- def pickups_deliveries(self):
- """Gets the pickups deliveries."""
- return self._pickups_deliveries
+ @property
+ def pickups_deliveries(self):
+ """Gets the pickups deliveries."""
+ return self._pickups_deliveries
- @property
- def num_vehicles(self):
- """Gets the number of vehicles."""
- return self._num_vehicles
+ @property
+ def num_vehicles(self):
+ """Gets the number of vehicles."""
+ return self._num_vehicles
- @property
- def vehicle_capacities(self):
- """Gets the capacity of each vehicles."""
- return self._vehicle_capacities
+ @property
+ def vehicle_capacities(self):
+ """Gets the capacity of each vehicles."""
+ return self._vehicle_capacities
- @property
- def vehicle_load_time(self):
- """Gets the load time of each vehicles."""
- return self._vehicle_load_time
+ @property
+ def vehicle_load_time(self):
+ """Gets the load time of each vehicles."""
+ return self._vehicle_load_time
- @property
- def vehicle_unload_time(self):
- """Gets the unload time of each vehicles."""
- return self._vehicle_unload_time
+ @property
+ def vehicle_unload_time(self):
+ """Gets the unload time of each vehicles."""
+ return self._vehicle_unload_time
- @property
- def depot_capacity(self):
- """Gets the depot capacity."""
- return self._depot_capacity
+ @property
+ def depot_capacity(self):
+ """Gets the depot capacity."""
+ return self._depot_capacity
- @property
- def depot(self):
- """Gets the depot node index."""
- return self._depot
+ @property
+ def depot(self):
+ """Gets the depot node index."""
+ return self._depot
- @property
- def starts(self):
- """Gets the start nodes indices."""
- return self._starts
+ @property
+ def starts(self):
+ """Gets the start nodes indices."""
+ return self._starts
- @property
- def ends(self):
- """Gets the end nodes indices."""
- return self._ends
+ @property
+ def ends(self):
+ """Gets the end nodes indices."""
+ return self._ends
- # [END data_model]
+ # [END data_model]
###########
# Printer #
###########
class GoogleColorPalette(object):
- """Google color codes palette."""
+ """Google color codes palette."""
- def __init__(self):
- """Initialize Google ColorPalette."""
- self._colors = [('blue', r'#4285F4'), ('red', r'#EA4335'),
- ('yellow', r'#FBBC05'), ('green', r'#34A853'),
- ('black', r'#101010'), ('white', r'#FFFFFF')]
+ def __init__(self):
+ """Initialize Google ColorPalette."""
+ self._colors = [('blue', r'#4285F4'), ('red', r'#EA4335'),
+ ('yellow', r'#FBBC05'), ('green', r'#34A853'),
+ ('black', r'#101010'), ('white', r'#FFFFFF')]
- def __getitem__(self, key):
- """Gets color name from idx."""
- return self._colors[key][0]
+ def __getitem__(self, key):
+ """Gets color name from idx."""
+ return self._colors[key][0]
- def __len__(self):
- """Gets the number of colors."""
- return len(self._colors)
+ def __len__(self):
+ """Gets the number of colors."""
+ return len(self._colors)
- @property
- def colors(self):
- """Gets the colors list."""
- return self._colors
+ @property
+ def colors(self):
+ """Gets the colors list."""
+ return self._colors
- def name(self, idx):
- """Return color name from idx."""
- return self._colors[idx][0]
+ def name(self, idx):
+ """Return color name from idx."""
+ return self._colors[idx][0]
- def value(self, idx):
- """Return color value from idx."""
- return self._colors[idx][1]
+ def value(self, idx):
+ """Return color value from idx."""
+ return self._colors[idx][1]
- def value_from_name(self, name):
- """Return color value from name."""
- return dict(self._colors)[name]
+ def value_from_name(self, name):
+ """Return color value from name."""
+ return dict(self._colors)[name]
class SVG(object):
- """SVG draw primitives."""
+ """SVG draw primitives."""
- @staticmethod
- def header(size, margin):
- """Writes header."""
- print(r'')
- @staticmethod
- def draw_line(position_1, position_2, size, fg_color):
- """Draws a line."""
- line_style = (r'style="stroke-width:{sz};stroke:{fg};fill:none"').format(
- sz=size, fg=fg_color)
- print(r''.format(
- x1=position_1[0],
- y1=position_1[1],
- x2=position_2[0],
- y2=position_2[1],
- style=line_style))
+ @staticmethod
+ def draw_line(position_1, position_2, size, fg_color):
+ """Draws a line."""
+ line_style = (
+ r'style="stroke-width:{sz};stroke:{fg};fill:none"').format(
+ sz=size, fg=fg_color)
+ print(
+ r''.format(
+ x1=position_1[0],
+ y1=position_1[1],
+ x2=position_2[0],
+ y2=position_2[1],
+ style=line_style))
- @staticmethod
- def draw_polyline(position_1, position_2, size, fg_color, colorname):
- """Draws a line with arrow maker in the middle."""
- polyline_style = (r'style="stroke-width:{sz};stroke:{fg};fill:none;'
- 'marker-mid:url(#arrow_{colorname})"').format(
- sz=size, fg=fg_color, colorname=colorname)
- print(r''.format(
- x1=position_1[0],
- y1=position_1[1],
- x2=(position_1[0] + position_2[0]) / 2,
- y2=(position_1[1] + position_2[1]) / 2,
- x3=position_2[0],
- y3=position_2[1],
- style=polyline_style))
+ @staticmethod
+ def draw_polyline(position_1, position_2, size, fg_color, colorname):
+ """Draws a line with arrow maker in the middle."""
+ polyline_style = (r'style="stroke-width:{sz};stroke:{fg};fill:none;'
+ 'marker-mid:url(#arrow_{colorname})"').format(
+ sz=size, fg=fg_color, colorname=colorname)
+ print(r''.
+ format(x1=position_1[0],
+ y1=position_1[1],
+ x2=(position_1[0] + position_2[0]) / 2,
+ y2=(position_1[1] + position_2[1]) / 2,
+ x3=position_2[0],
+ y3=position_2[1],
+ style=polyline_style))
- @staticmethod
- def draw_circle(position, radius, size, fg_color, bg_color='white'):
- """Print a circle."""
- circle_style = (r'style="stroke-width:{sz};stroke:{fg};fill:{bg}"').format(
- sz=size, fg=fg_color, bg=bg_color)
- print(r''.format(
- cx=position[0], cy=position[1], r=radius, style=circle_style))
+ @staticmethod
+ def draw_circle(position, radius, size, fg_color, bg_color='white'):
+ """Print a circle."""
+ circle_style = (
+ r'style="stroke-width:{sz};stroke:{fg};fill:{bg}"').format(
+ sz=size, fg=fg_color, bg=bg_color)
+ print(r''.format(
+ cx=position[0], cy=position[1], r=radius, style=circle_style))
- @staticmethod
- def draw_text(text, position, size, fg_color='none', bg_color='black'):
- """Print a middle centred text."""
- text_style = (r'style="text-anchor:middle;font-weight:bold;'
- 'font-size:{sz};stroke:{fg};fill:{bg}"').format(
- sz=size, fg=fg_color, bg=bg_color)
- print(r'{txt}'.format(
- x=position[0], y=position[1], dy=size / 3, style=text_style, txt=text))
+ @staticmethod
+ def draw_text(text, position, size, fg_color='none', bg_color='black'):
+ """Print a middle centred text."""
+ text_style = (r'style="text-anchor:middle;font-weight:bold;'
+ 'font-size:{sz};stroke:{fg};fill:{bg}"').format(
+ sz=size, fg=fg_color, bg=bg_color)
+ print(r'{txt}'.format(
+ x=position[0],
+ y=position[1],
+ dy=size / 3,
+ style=text_style,
+ txt=text))
class SVGPrinter(object): # pylint: disable=too-many-instance-attributes
- """Generate Problem as svg file to stdout."""
+ """Generate Problem as svg file to stdout."""
- # pylint: disable=too-many-arguments
- def __init__(self, args, data, manager=None, routing=None, assignment=None):
- """Initializes the printer."""
- self._args = args
- self._data = data
- self._manager = manager
- self._routing = routing
- self._assignment = assignment
- # Design variables
- self._color_palette = GoogleColorPalette()
- self._svg = SVG()
- # City block size 114mx80m
- self._radius = min(114, 80) / 3
- self._stroke_width = self._radius / 4
+ # pylint: disable=too-many-arguments
+ def __init__(self,
+ args,
+ data,
+ manager=None,
+ routing=None,
+ assignment=None):
+ """Initializes the printer."""
+ self._args = args
+ self._data = data
+ self._manager = manager
+ self._routing = routing
+ self._assignment = assignment
+ # Design variables
+ self._color_palette = GoogleColorPalette()
+ self._svg = SVG()
+ # City block size 114mx80m
+ self._radius = min(114, 80) / 3
+ self._stroke_width = self._radius / 4
- @property
- def data(self):
- """Gets the Data Model."""
- return self._data
+ @property
+ def data(self):
+ """Gets the Data Model."""
+ return self._data
- @property
- def manager(self):
- """Gets the RoutingIndexManager."""
- return self._manager
+ @property
+ def manager(self):
+ """Gets the RoutingIndexManager."""
+ return self._manager
- @property
- def routing(self):
- """Gets the Routing solver."""
- return self._routing
+ @property
+ def routing(self):
+ """Gets the Routing solver."""
+ return self._routing
- @property
- def assignment(self):
- """Gets the assignment."""
- return self._assignment
+ @property
+ def assignment(self):
+ """Gets the assignment."""
+ return self._assignment
- @property
- def color_palette(self):
- """Gets the color palette."""
- return self._color_palette
+ @property
+ def color_palette(self):
+ """Gets the color palette."""
+ return self._color_palette
- @property
- def svg(self):
- """Gets the svg."""
- return self._svg
+ @property
+ def svg(self):
+ """Gets the svg."""
+ return self._svg
- def draw_grid(self):
- """Draws the city grid."""
- print(r'')
- color = '#969696'
- # Horizontal streets
- for i in range(9):
- p_1 = [0, i * 80]
- p_2 = [8 * 114, p_1[1]]
- self._svg.draw_line(p_1, p_2, 2, color)
- # Vertical streets
- for i in range(9):
- p_1 = [i * 114, 0]
- p_2 = [p_1[0], 8 * 80]
- self._svg.draw_line(p_1, p_2, 2, color)
+ def draw_grid(self):
+ """Draws the city grid."""
+ print(r'')
+ color = '#969696'
+ # Horizontal streets
+ for i in range(9):
+ p_1 = [0, i * 80]
+ p_2 = [8 * 114, p_1[1]]
+ self._svg.draw_line(p_1, p_2, 2, color)
+ # Vertical streets
+ for i in range(9):
+ p_1 = [i * 114, 0]
+ p_2 = [p_1[0], 8 * 80]
+ self._svg.draw_line(p_1, p_2, 2, color)
- def draw_depot(self):
- """Draws the depot."""
- print(r'')
- color = self._color_palette.value_from_name('black')
- loc = self._data.locations[self._data.depot]
- self._svg.draw_circle(loc, self._radius, self._stroke_width, color, 'white')
- self._svg.draw_text(self._data.depot, loc, self._radius, 'none', color)
-
- def draw_depots(self):
- """Draws the depot."""
- print(r'')
- # print starts
- for vehicle_idx, start in enumerate(self._data.starts):
- del vehicle_idx
- color = self._color_palette.value_from_name('black')
- # color = self._color_palette.value(vehicle_idx)
- loc = self._data.locations[start]
- self._svg.draw_circle(loc, self._radius, self._stroke_width, color,
- 'white')
- self._svg.draw_text(start, loc, self._radius, 'none', color)
- # print end
- color = self._color_palette.value_from_name('black')
- loc = self._data.locations[0]
- self._svg.draw_circle(loc, self._radius, self._stroke_width, color, 'white')
- self._svg.draw_text(0, loc, self._radius, 'none', color)
-
- def draw_locations(self):
- """Draws all the locations but the depot."""
- print(r'')
- color = self._color_palette.value_from_name('blue')
- if not self._args['starts_ends']:
- for idx, loc in enumerate(self._data.locations):
- if idx == self._data.depot:
- continue
+ def draw_depot(self):
+ """Draws the depot."""
+ print(r'')
+ color = self._color_palette.value_from_name('black')
+ loc = self._data.locations[self._data.depot]
self._svg.draw_circle(loc, self._radius, self._stroke_width, color,
'white')
- self._svg.draw_text(idx, loc, self._radius, 'none', color)
- else:
- for idx, loc in enumerate(self._data.locations):
- if idx in self._data.starts + self._data.ends:
- continue
+ self._svg.draw_text(self._data.depot, loc, self._radius, 'none', color)
+
+ def draw_depots(self):
+ """Draws the depot."""
+ print(r'')
+ # print starts
+ for vehicle_idx, start in enumerate(self._data.starts):
+ del vehicle_idx
+ color = self._color_palette.value_from_name('black')
+ # color = self._color_palette.value(vehicle_idx)
+ loc = self._data.locations[start]
+ self._svg.draw_circle(loc, self._radius, self._stroke_width, color,
+ 'white')
+ self._svg.draw_text(start, loc, self._radius, 'none', color)
+ # print end
+ color = self._color_palette.value_from_name('black')
+ loc = self._data.locations[0]
self._svg.draw_circle(loc, self._radius, self._stroke_width, color,
'white')
- self._svg.draw_text(idx, loc, self._radius, 'none', color)
+ self._svg.draw_text(0, loc, self._radius, 'none', color)
- def draw_demands(self):
- """Draws all the demands."""
- print(r'')
- for idx, loc in enumerate(self._data.locations):
- if idx == self._data.depot:
- continue
- demand = self._data.demands[idx]
- position = [
- x + y for x, y in zip(loc, [self._radius * 1.2, self._radius * 1.1])
- ]
- color = self._color_palette.value_from_name('red')
- # color = self._color_palette.value(int(math.log(demand, 2)))
- self._svg.draw_text(demand, position, self._radius, 'none', color)
+ def draw_locations(self):
+ """Draws all the locations but the depot."""
+ print(r'')
+ color = self._color_palette.value_from_name('blue')
+ if not self._args['starts_ends']:
+ for idx, loc in enumerate(self._data.locations):
+ if idx == self._data.depot:
+ continue
+ self._svg.draw_circle(loc, self._radius, self._stroke_width,
+ color, 'white')
+ self._svg.draw_text(idx, loc, self._radius, 'none', color)
+ else:
+ for idx, loc in enumerate(self._data.locations):
+ if idx in self._data.starts + self._data.ends:
+ continue
+ self._svg.draw_circle(loc, self._radius, self._stroke_width,
+ color, 'white')
+ self._svg.draw_text(idx, loc, self._radius, 'none', color)
- def draw_pickups_deliveries(self):
- """Draws all pickups deliveries."""
- print(r'')
- colorname = 'red'
- color = self._color_palette.value_from_name(colorname)
- for pickup_delivery in self._data.pickups_deliveries:
- self._svg.draw_polyline(self._data.locations[pickup_delivery[0]],
- self._data.locations[pickup_delivery[1]],
- self._stroke_width, color, colorname)
+ def draw_demands(self):
+ """Draws all the demands."""
+ print(r'')
+ for idx, loc in enumerate(self._data.locations):
+ if idx == self._data.depot:
+ continue
+ demand = self._data.demands[idx]
+ position = [
+ x + y
+ for x, y in zip(loc, [self._radius * 1.2, self._radius * 1.1])
+ ]
+ color = self._color_palette.value_from_name('red')
+ # color = self._color_palette.value(int(math.log(demand, 2)))
+ self._svg.draw_text(demand, position, self._radius, 'none', color)
- def draw_time_windows(self):
- """Draws all the time windows."""
- print(r'')
- for idx, loc in enumerate(self._data.locations):
- if idx == self._data.depot:
- continue
- time_window = self._data.time_windows[idx]
- position = [
- x + y for x, y in zip(loc, [self._radius * 0, -self._radius * 1.6])
- ]
- color = self._color_palette.value_from_name('red')
- self._svg.draw_text(
- '[{t1},{t2}]'.format(t1=time_window[0], t2=time_window[1]), position,
- self._radius * 0.75, 'white', color)
+ def draw_pickups_deliveries(self):
+ """Draws all pickups deliveries."""
+ print(r'')
+ colorname = 'red'
+ color = self._color_palette.value_from_name(colorname)
+ for pickup_delivery in self._data.pickups_deliveries:
+ self._svg.draw_polyline(self._data.locations[pickup_delivery[0]],
+ self._data.locations[pickup_delivery[1]],
+ self._stroke_width, color, colorname)
+
+ def draw_time_windows(self):
+ """Draws all the time windows."""
+ print(r'')
+ for idx, loc in enumerate(self._data.locations):
+ if idx == self._data.depot:
+ continue
+ time_window = self._data.time_windows[idx]
+ position = [
+ x + y
+ for x, y in zip(loc, [self._radius * 0, -self._radius * 1.6])
+ ]
+ color = self._color_palette.value_from_name('red')
+ self._svg.draw_text(
+ '[{t1},{t2}]'.format(t1=time_window[0], t2=time_window[1]),
+ position, self._radius * 0.75, 'white', color)
##############
## ROUTES ##
##############
- def draw_drop_nodes(self):
- """Draws the dropped nodes."""
- print(r'')
- if self._assignment is None:
- print('')
- # Display dropped nodes.
- dropped_nodes = []
- for node in range(self._routing.Size()):
- if self._routing.IsStart(node) or self._routing.IsEnd(node):
- continue
- if self._assignment.Value(self._routing.NextVar(node)) == node:
- dropped_nodes.append(self._manager.IndexToNode(node))
- color = self._color_palette.value_from_name('black')
- for node_idx in dropped_nodes:
- loc = self._data.locations[node_idx]
- self._svg.draw_circle(loc, self._radius, self._stroke_width, color,
- 'white')
- self._svg.draw_text(node_idx, loc, self._radius, 'none', color)
+ def draw_drop_nodes(self):
+ """Draws the dropped nodes."""
+ print(r'')
+ if self._assignment is None:
+ print('')
+ # Display dropped nodes.
+ dropped_nodes = []
+ for node in range(self._routing.Size()):
+ if self._routing.IsStart(node) or self._routing.IsEnd(node):
+ continue
+ if self._assignment.Value(self._routing.NextVar(node)) == node:
+ dropped_nodes.append(self._manager.IndexToNode(node))
+ color = self._color_palette.value_from_name('black')
+ for node_idx in dropped_nodes:
+ loc = self._data.locations[node_idx]
+ self._svg.draw_circle(loc, self._radius, self._stroke_width, color,
+ 'white')
+ self._svg.draw_text(node_idx, loc, self._radius, 'none', color)
- def routes(self):
- """Creates the route list from the assignment."""
- if self._assignment is None:
- print('')
- return []
- routes = []
- for vehicle_id in range(self._data.num_vehicles):
- index = self._routing.Start(vehicle_id)
- route = []
- while not self._routing.IsEnd(index):
- node_index = self._manager.IndexToNode(index)
- route.append(node_index)
- index = self._assignment.Value(self._routing.NextVar(index))
- node_index = self._manager.IndexToNode(index)
- route.append(node_index)
- routes.append(route)
- return routes
+ def routes(self):
+ """Creates the route list from the assignment."""
+ if self._assignment is None:
+ print('')
+ return []
+ routes = []
+ for vehicle_id in range(self._data.num_vehicles):
+ index = self._routing.Start(vehicle_id)
+ route = []
+ while not self._routing.IsEnd(index):
+ node_index = self._manager.IndexToNode(index)
+ route.append(node_index)
+ index = self._assignment.Value(self._routing.NextVar(index))
+ node_index = self._manager.IndexToNode(index)
+ route.append(node_index)
+ routes.append(route)
+ return routes
- def draw_route(self, route, color, colorname):
- """Draws a Route."""
- # First print route
- previous_loc_idx = None
- for loc_idx in route:
- if previous_loc_idx is not None and previous_loc_idx != loc_idx:
- self._svg.draw_polyline(self._data.locations[previous_loc_idx],
- self._data.locations[loc_idx],
- self._stroke_width, color, colorname)
- previous_loc_idx = loc_idx
- # Then print location along the route
- for loc_idx in route:
- if loc_idx != self._data.depot:
- loc = self._data.locations[loc_idx]
- self._svg.draw_circle(loc, self._radius, self._stroke_width, color,
- 'white')
- self._svg.draw_text(loc_idx, loc, self._radius, 'none', color)
+ def draw_route(self, route, color, colorname):
+ """Draws a Route."""
+ # First print route
+ previous_loc_idx = None
+ for loc_idx in route:
+ if previous_loc_idx is not None and previous_loc_idx != loc_idx:
+ self._svg.draw_polyline(self._data.locations[previous_loc_idx],
+ self._data.locations[loc_idx],
+ self._stroke_width, color, colorname)
+ previous_loc_idx = loc_idx
+ # Then print location along the route
+ for loc_idx in route:
+ if loc_idx != self._data.depot:
+ loc = self._data.locations[loc_idx]
+ self._svg.draw_circle(loc, self._radius, self._stroke_width,
+ color, 'white')
+ self._svg.draw_text(loc_idx, loc, self._radius, 'none', color)
- def draw_routes(self):
- """Draws the routes."""
- print(r'')
- for route_idx, route in enumerate(self.routes()):
- print(r''.format(idx=route_idx))
- color = self._color_palette.value(route_idx)
- colorname = self._color_palette.name(route_idx)
- self.draw_route(route, color, colorname)
+ def draw_routes(self):
+ """Draws the routes."""
+ print(r'')
+ for route_idx, route in enumerate(self.routes()):
+ print(r''.format(idx=route_idx))
+ color = self._color_palette.value(route_idx)
+ colorname = self._color_palette.name(route_idx)
+ self.draw_route(route, color, colorname)
- def tw_routes(self):
- """Creates the route time window list from the assignment."""
- if self._assignment is None:
- print('')
- return []
- time_dimension = self._routing.GetDimensionOrDie('Time')
- loc_routes = []
- tw_routes = []
- for vehicle_id in range(self._data.num_vehicles):
- index = self._routing.Start(vehicle_id)
- # index = self._assignment.Value(self._routing.NextVar(index))
- loc_route = []
- tw_route = []
- while True:
- node_index = self._manager.IndexToNode(index)
- loc_route.append(node_index)
- time_var = time_dimension.CumulVar(index)
- t_min = self._assignment.Min(time_var)
- t_max = self._assignment.Max(time_var)
- tw_route.append((t_min, t_max))
- if self._routing.IsEnd(index):
- break
- index = self._assignment.Value(self._routing.NextVar(index))
- loc_routes.append(loc_route)
- tw_routes.append(tw_route)
- return zip(loc_routes, tw_routes)
+ def tw_routes(self):
+ """Creates the route time window list from the assignment."""
+ if self._assignment is None:
+ print('')
+ return []
+ time_dimension = self._routing.GetDimensionOrDie('Time')
+ loc_routes = []
+ tw_routes = []
+ for vehicle_id in range(self._data.num_vehicles):
+ index = self._routing.Start(vehicle_id)
+ # index = self._assignment.Value(self._routing.NextVar(index))
+ loc_route = []
+ tw_route = []
+ while True:
+ node_index = self._manager.IndexToNode(index)
+ loc_route.append(node_index)
+ time_var = time_dimension.CumulVar(index)
+ t_min = self._assignment.Min(time_var)
+ t_max = self._assignment.Max(time_var)
+ tw_route.append((t_min, t_max))
+ if self._routing.IsEnd(index):
+ break
+ index = self._assignment.Value(self._routing.NextVar(index))
+ loc_routes.append(loc_route)
+ tw_routes.append(tw_route)
+ return zip(loc_routes, tw_routes)
- def draw_tw_route(self, route_idx, locations, tw_route, color):
- """Draws the time windows for a Route."""
- is_start = -1
- for loc_idx, time_window in zip(locations, tw_route):
- loc = self._data.locations[loc_idx]
- if loc_idx == 0: # special case for depot
- position = [
- x + y for x, y in
- zip(loc,
- [self._radius * is_start, self._radius * (1.8 + route_idx)])
- ]
- is_start = 1
- else:
- position = [
- x + y for x, y in zip(loc, [self._radius * 0, self._radius * 1.8])
- ]
- self._svg.draw_text('[{t_min}]'.format(t_min=time_window[0]), position,
- self._radius * 0.75, 'white', color)
+ def draw_tw_route(self, route_idx, locations, tw_route, color):
+ """Draws the time windows for a Route."""
+ is_start = -1
+ for loc_idx, time_window in zip(locations, tw_route):
+ loc = self._data.locations[loc_idx]
+ if loc_idx == 0: # special case for depot
+ position = [
+ x + y for x, y in zip(loc, [
+ self._radius * is_start, self._radius *
+ (1.8 + route_idx)
+ ])
+ ]
+ is_start = 1
+ else:
+ position = [
+ x + y for x, y in zip(
+ loc, [self._radius * 0, self._radius * 1.8])
+ ]
+ self._svg.draw_text('[{t_min}]'.format(t_min=time_window[0]),
+ position, self._radius * 0.75, 'white', color)
- def draw_tw_routes(self):
- """Draws the time window routes."""
- print(r'')
- for route_idx, loc_tw in enumerate(self.tw_routes()):
- print(r''.format(route_idx))
- color = self._color_palette.value(route_idx)
- self.draw_tw_route(route_idx, loc_tw[0], loc_tw[1], color)
+ def draw_tw_routes(self):
+ """Draws the time window routes."""
+ print(r'')
+ for route_idx, loc_tw in enumerate(self.tw_routes()):
+ print(r''.format(route_idx))
+ color = self._color_palette.value(route_idx)
+ self.draw_tw_route(route_idx, loc_tw[0], loc_tw[1], color)
- def print_to_console(self):
- """Prints a full svg document on stdout."""
- margin = self._radius * 2 + 2
- size = [8 * 114, 8 * 80]
- self._svg.header(size, margin)
- self._svg.definitions(self._color_palette.colors)
- self.draw_grid()
- if not self._args['solution']:
- if self._args['pickup_delivery']:
- self.draw_pickups_deliveries()
- self.draw_locations()
- else:
- self.draw_routes()
- self.draw_drop_nodes()
- if self._args['starts_ends']:
- self.draw_depots()
- else:
- self.draw_depot()
- if self._args['capacity']:
- self.draw_demands()
- if self._args['drop_nodes']:
- self.draw_demands()
- if self._args['time_windows'] or self._args['resources']:
- self.draw_time_windows()
- if ((self._args['time_windows'] or self._args['resources']) and
- self._args['solution']):
- self.draw_tw_routes()
- self._svg.footer()
+ def print_to_console(self):
+ """Prints a full svg document on stdout."""
+ margin = self._radius * 2 + 2
+ size = [8 * 114, 8 * 80]
+ self._svg.header(size, margin)
+ self._svg.definitions(self._color_palette.colors)
+ self.draw_grid()
+ if not self._args['solution']:
+ if self._args['pickup_delivery']:
+ self.draw_pickups_deliveries()
+ self.draw_locations()
+ else:
+ self.draw_routes()
+ self.draw_drop_nodes()
+ if self._args['starts_ends']:
+ self.draw_depots()
+ else:
+ self.draw_depot()
+ if self._args['capacity']:
+ self.draw_demands()
+ if self._args['drop_nodes']:
+ self.draw_demands()
+ if self._args['time_windows'] or self._args['resources']:
+ self.draw_time_windows()
+ if ((self._args['time_windows'] or self._args['resources'])
+ and self._args['solution']):
+ self.draw_tw_routes()
+ self._svg.footer()
########
# Main #
########
def main(): # pylint: disable=too-many-locals,too-many-branches
- """Entry point of the program."""
- parser = argparse.ArgumentParser(description='Output VRP as svg image.')
- parser.add_argument(
- '-tsp', '--tsp', action='store_true', help='use 1 vehicle')
- parser.add_argument(
- '-vrp', '--vrp', action='store_true', help='use 4 vehicle')
- parser.add_argument(
- '-gs',
- '--global-span',
- action='store_true',
- help='use global span constraints')
- parser.add_argument(
- '-c', '--capacity', action='store_true', help='use capacity constraints')
- parser.add_argument(
- '-r',
- '--resources',
- action='store_true',
- help='use resources constraints')
- parser.add_argument(
- '-dn',
- '--drop-nodes',
- action='store_true',
- help='allow drop nodes (disjuntion constraints)')
- parser.add_argument(
- '-tw',
- '--time-windows',
- action='store_true',
- help='use time-window constraints')
- parser.add_argument(
- '-se',
- '--starts-ends',
- action='store_true',
- help='use multiple starts & ends')
- parser.add_argument(
- '-pd',
- '--pickup-delivery',
- action='store_true',
- help='use pickup & delivery constraints')
- parser.add_argument(
- '-fifo',
- '--fifo',
- action='store_true',
- help='use pickup & delivery FIFO Policy')
- parser.add_argument(
- '-lifo',
- '--lifo',
- action='store_true',
- help='use pickup & delivery LIFO Policy')
- parser.add_argument(
- '-s', '--solution', action='store_true', help='print solution')
- args = vars(parser.parse_args())
+ """Entry point of the program."""
+ parser = argparse.ArgumentParser(description='Output VRP as svg image.')
+ parser.add_argument('-tsp',
+ '--tsp',
+ action='store_true',
+ help='use 1 vehicle')
+ parser.add_argument('-vrp',
+ '--vrp',
+ action='store_true',
+ help='use 4 vehicle')
+ parser.add_argument('-gs',
+ '--global-span',
+ action='store_true',
+ help='use global span constraints')
+ parser.add_argument('-c',
+ '--capacity',
+ action='store_true',
+ help='use capacity constraints')
+ parser.add_argument('-r',
+ '--resources',
+ action='store_true',
+ help='use resources constraints')
+ parser.add_argument('-dn',
+ '--drop-nodes',
+ action='store_true',
+ help='allow drop nodes (disjuntion constraints)')
+ parser.add_argument('-tw',
+ '--time-windows',
+ action='store_true',
+ help='use time-window constraints')
+ parser.add_argument('-se',
+ '--starts-ends',
+ action='store_true',
+ help='use multiple starts & ends')
+ parser.add_argument('-pd',
+ '--pickup-delivery',
+ action='store_true',
+ help='use pickup & delivery constraints')
+ parser.add_argument('-fifo',
+ '--fifo',
+ action='store_true',
+ help='use pickup & delivery FIFO Policy')
+ parser.add_argument('-lifo',
+ '--lifo',
+ action='store_true',
+ help='use pickup & delivery LIFO Policy')
+ parser.add_argument('-s',
+ '--solution',
+ action='store_true',
+ help='print solution')
+ args = vars(parser.parse_args())
- # Instantiate the data problem.
- # [START data]
- data = DataModel(args)
- # [END data]
+ # Instantiate the data problem.
+ # [START data]
+ data = DataModel(args)
+ # [END data]
- if not args['solution']:
- # Print svg on cout
- printer = SVGPrinter(args, data)
+ if not args['solution']:
+ # Print svg on cout
+ printer = SVGPrinter(args, data)
+ printer.print_to_console()
+ return 0
+
+ # Create the routing index manager.
+ # [START index_manager]
+ if args['starts_ends']:
+ manager = pywrapcp.RoutingIndexManager(len(data.locations),
+ data.num_vehicles, data.starts,
+ data.ends)
+ else:
+ manager = pywrapcp.RoutingIndexManager(len(data.locations),
+ data.num_vehicles, data.depot)
+ # [END index_manager]
+
+ # Create Routing Model.
+ # [START routing_model]
+ routing = pywrapcp.RoutingModel(manager)
+
+ # [END routing_model]
+
+ # Register distance callback
+ def distance_callback(from_index, to_index):
+ """Returns the manhattan distance between the two nodes."""
+ # Convert from routing variable Index to distance matrix NodeIndex.
+ from_node = manager.IndexToNode(from_index)
+ to_node = manager.IndexToNode(to_index)
+ return data.distance_matrix[from_node][to_node]
+
+ distance_callback_index = routing.RegisterTransitCallback(
+ distance_callback)
+
+ # Register time callback
+ def time_callback(from_index, to_index):
+ """Returns the manhattan distance travel time between the two nodes."""
+ # Convert from routing variable Index to distance matrix NodeIndex.
+ from_node = manager.IndexToNode(from_index)
+ to_node = manager.IndexToNode(to_index)
+ return data.time_matrix[from_node][to_node]
+
+ time_callback_index = routing.RegisterTransitCallback(time_callback)
+
+ # Register demands callback
+ def demand_callback(from_index):
+ """Returns the demand of the node."""
+ # Convert from routing variable Index to demands NodeIndex.
+ from_node = manager.IndexToNode(from_index)
+ return data.demands[from_node]
+
+ demand_callback_index = routing.RegisterUnaryTransitCallback(
+ demand_callback)
+
+ if args['time_windows'] or args['resources']:
+ routing.SetArcCostEvaluatorOfAllVehicles(time_callback_index)
+ else:
+ routing.SetArcCostEvaluatorOfAllVehicles(distance_callback_index)
+
+ if args['global_span'] or args['pickup_delivery']:
+ dimension_name = 'Distance'
+ routing.AddDimension(distance_callback_index, 0, 3000, True,
+ dimension_name)
+ distance_dimension = routing.GetDimensionOrDie(dimension_name)
+ distance_dimension.SetGlobalSpanCostCoefficient(100)
+
+ if args['capacity'] or args['drop_nodes']:
+ routing.AddDimensionWithVehicleCapacity(demand_callback_index, 0,
+ data.vehicle_capacities, True,
+ 'Capacity')
+
+ if args['drop_nodes']:
+ # Allow to drop nodes.
+ penalty = 1000
+ for node in range(1, len(data.locations)):
+ routing.AddDisjunction([manager.NodeToIndex(node)], penalty)
+
+ if args['pickup_delivery']:
+ dimension_name = 'Distance'
+ routing.AddDimension(distance_callback_index, 0, 3000, True,
+ dimension_name)
+ distance_dimension = routing.GetDimensionOrDie(dimension_name)
+ distance_dimension.SetGlobalSpanCostCoefficient(100)
+ for request in data.pickups_deliveries:
+ pickup_index = manager.NodeToIndex(request[0])
+ delivery_index = manager.NodeToIndex(request[1])
+ routing.AddPickupAndDelivery(pickup_index, delivery_index)
+ routing.solver().Add(
+ routing.VehicleVar(pickup_index) == routing.VehicleVar(
+ delivery_index))
+ routing.solver().Add(
+ distance_dimension.CumulVar(pickup_index) <=
+ distance_dimension.CumulVar(delivery_index))
+ if args['fifo']:
+ routing.SetPickupAndDeliveryPolicyOfAllVehicles(
+ pywrapcp.RoutingModel.PICKUP_AND_DELIVERY_FIFO)
+ if args['lifo']:
+ routing.SetPickupAndDeliveryPolicyOfAllVehicles(
+ pywrapcp.RoutingModel.PICKUP_AND_DELIVERY_LIFO)
+
+ if args['starts_ends']:
+ dimension_name = 'Distance'
+ routing.AddDimension(distance_callback_index, 0, 2000, True,
+ dimension_name)
+ distance_dimension = routing.GetDimensionOrDie(dimension_name)
+ distance_dimension.SetGlobalSpanCostCoefficient(100)
+
+ time = 'Time'
+ if args['time_windows'] or args['resources']:
+ routing.AddDimension(time_callback_index, 30, 30, False, time)
+ time_dimension = routing.GetDimensionOrDie(time)
+ # Add time window constraints for each location except depot and 'copy' the
+ # slack var in the solution object (aka Assignment) to print it.
+ for location_idx, time_window in enumerate(data.time_windows):
+ if location_idx == 0:
+ continue
+ index = manager.NodeToIndex(location_idx)
+ time_dimension.CumulVar(index).SetRange(time_window[0],
+ time_window[1])
+ routing.AddToAssignment(time_dimension.SlackVar(index))
+ # Add time window constraints for each vehicle start node and 'copy' the
+ # slack var in the solution object (aka Assignment) to print it.
+ for vehicle_id in range(data.num_vehicles):
+ index = routing.Start(vehicle_id)
+ time_window = data.time_windows[0]
+ time_dimension.CumulVar(index).SetRange(time_window[0],
+ time_window[1])
+ routing.AddToAssignment(time_dimension.SlackVar(index))
+
+ # Instantiate route start and end times to produce feasible times.
+ for vehicle_id in range(data.num_vehicles):
+ routing.AddVariableMinimizedByFinalizer(
+ time_dimension.CumulVar(routing.End(vehicle_id)))
+ routing.AddVariableMinimizedByFinalizer(
+ time_dimension.CumulVar(routing.Start(vehicle_id)))
+
+ if args['resources']:
+ # Add resource constraints at the depot.
+ time_dimension = routing.GetDimensionOrDie(time)
+ solver = routing.solver()
+ intervals = []
+ for i in range(data.num_vehicles):
+ # Add loading time at start of routes
+ intervals.append(
+ solver.FixedDurationIntervalVar(
+ time_dimension.CumulVar(routing.Start(i)),
+ data.vehicle_load_time, 'depot_interval'))
+ # Add unloading time at end of routes.
+ intervals.append(
+ solver.FixedDurationIntervalVar(
+ time_dimension.CumulVar(routing.End(i)),
+ data.vehicle_unload_time, 'depot_interval '))
+
+ depot_usage = [1 for i in range(data.num_vehicles * 2)]
+ solver.AddConstraint(
+ solver.Cumulative(intervals, depot_usage, data.depot_capacity,
+ 'depot'))
+
+ # Setting first solution heuristic (cheapest addition).
+ search_parameters = pywrapcp.DefaultRoutingSearchParameters()
+ # pylint: disable=no-member
+ if not args['pickup_delivery']:
+ search_parameters.first_solution_strategy = (
+ routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
+ else:
+ search_parameters.first_solution_strategy = (
+ routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION
+ )
+
+ search_parameters.local_search_metaheuristic = (
+ routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
+ search_parameters.time_limit.FromSeconds(2)
+
+ # Solve the problem.
+ assignment = routing.SolveWithParameters(search_parameters)
+ # Print the solution.
+ printer = SVGPrinter(args, data, manager, routing, assignment)
printer.print_to_console()
return 0
- # Create the routing index manager.
- # [START index_manager]
- if args['starts_ends']:
- manager = pywrapcp.RoutingIndexManager(
- len(data.locations), data.num_vehicles, data.starts, data.ends)
- else:
- manager = pywrapcp.RoutingIndexManager(
- len(data.locations), data.num_vehicles, data.depot)
- # [END index_manager]
-
- # Create Routing Model.
- # [START routing_model]
- routing = pywrapcp.RoutingModel(manager)
-
- # [END routing_model]
-
- # Register distance callback
- def distance_callback(from_index, to_index):
- """Returns the manhattan distance between the two nodes."""
- # Convert from routing variable Index to distance matrix NodeIndex.
- from_node = manager.IndexToNode(from_index)
- to_node = manager.IndexToNode(to_index)
- return data.distance_matrix[from_node][to_node]
-
- distance_callback_index = routing.RegisterTransitCallback(distance_callback)
-
- # Register time callback
- def time_callback(from_index, to_index):
- """Returns the manhattan distance travel time between the two nodes."""
- # Convert from routing variable Index to distance matrix NodeIndex.
- from_node = manager.IndexToNode(from_index)
- to_node = manager.IndexToNode(to_index)
- return data.time_matrix[from_node][to_node]
-
- time_callback_index = routing.RegisterTransitCallback(time_callback)
-
- # Register demands callback
- def demand_callback(from_index):
- """Returns the demand of the node."""
- # Convert from routing variable Index to demands NodeIndex.
- from_node = manager.IndexToNode(from_index)
- return data.demands[from_node]
-
- demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
-
- if args['time_windows'] or args['resources']:
- routing.SetArcCostEvaluatorOfAllVehicles(time_callback_index)
- else:
- routing.SetArcCostEvaluatorOfAllVehicles(distance_callback_index)
-
- if args['global_span'] or args['pickup_delivery']:
- dimension_name = 'Distance'
- routing.AddDimension(distance_callback_index, 0, 3000, True, dimension_name)
- distance_dimension = routing.GetDimensionOrDie(dimension_name)
- distance_dimension.SetGlobalSpanCostCoefficient(100)
-
- if args['capacity'] or args['drop_nodes']:
- routing.AddDimensionWithVehicleCapacity(demand_callback_index, 0,
- data.vehicle_capacities, True,
- 'Capacity')
-
- if args['drop_nodes']:
- # Allow to drop nodes.
- penalty = 1000
- for node in range(1, len(data.locations)):
- routing.AddDisjunction([manager.NodeToIndex(node)], penalty)
-
- if args['pickup_delivery']:
- dimension_name = 'Distance'
- routing.AddDimension(distance_callback_index, 0, 3000, True, dimension_name)
- distance_dimension = routing.GetDimensionOrDie(dimension_name)
- distance_dimension.SetGlobalSpanCostCoefficient(100)
- for request in data.pickups_deliveries:
- pickup_index = manager.NodeToIndex(request[0])
- delivery_index = manager.NodeToIndex(request[1])
- routing.AddPickupAndDelivery(pickup_index, delivery_index)
- routing.solver().Add(
- routing.VehicleVar(pickup_index) == routing.VehicleVar(
- delivery_index))
- routing.solver().Add(
- distance_dimension.CumulVar(pickup_index) <=
- distance_dimension.CumulVar(delivery_index))
- if args['fifo']:
- routing.SetPickupAndDeliveryPolicyOfAllVehicles(
- pywrapcp.RoutingModel.PICKUP_AND_DELIVERY_FIFO)
- if args['lifo']:
- routing.SetPickupAndDeliveryPolicyOfAllVehicles(
- pywrapcp.RoutingModel.PICKUP_AND_DELIVERY_LIFO)
-
- if args['starts_ends']:
- dimension_name = 'Distance'
- routing.AddDimension(distance_callback_index, 0, 2000, True, dimension_name)
- distance_dimension = routing.GetDimensionOrDie(dimension_name)
- distance_dimension.SetGlobalSpanCostCoefficient(100)
-
- time = 'Time'
- if args['time_windows'] or args['resources']:
- routing.AddDimension(time_callback_index, 30, 30, False, time)
- time_dimension = routing.GetDimensionOrDie(time)
- # Add time window constraints for each location except depot and 'copy' the
- # slack var in the solution object (aka Assignment) to print it.
- for location_idx, time_window in enumerate(data.time_windows):
- if location_idx == 0:
- continue
- index = manager.NodeToIndex(location_idx)
- time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])
- routing.AddToAssignment(time_dimension.SlackVar(index))
- # Add time window constraints for each vehicle start node and 'copy' the
- # slack var in the solution object (aka Assignment) to print it.
- for vehicle_id in range(data.num_vehicles):
- index = routing.Start(vehicle_id)
- time_window = data.time_windows[0]
- time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])
- routing.AddToAssignment(time_dimension.SlackVar(index))
-
- # Instantiate route start and end times to produce feasible times.
- for vehicle_id in range(data.num_vehicles):
- routing.AddVariableMinimizedByFinalizer(
- time_dimension.CumulVar(routing.End(vehicle_id)))
- routing.AddVariableMinimizedByFinalizer(
- time_dimension.CumulVar(routing.Start(vehicle_id)))
-
- if args['resources']:
- # Add resource constraints at the depot.
- time_dimension = routing.GetDimensionOrDie(time)
- solver = routing.solver()
- intervals = []
- for i in range(data.num_vehicles):
- # Add loading time at start of routes
- intervals.append(
- solver.FixedDurationIntervalVar(
- time_dimension.CumulVar(routing.Start(i)), data.vehicle_load_time,
- 'depot_interval'))
- # Add unloading time at end of routes.
- intervals.append(
- solver.FixedDurationIntervalVar(
- time_dimension.CumulVar(routing.End(i)), data.vehicle_unload_time,
- 'depot_interval '))
-
- depot_usage = [1 for i in range(data.num_vehicles * 2)]
- solver.AddConstraint(
- solver.Cumulative(intervals, depot_usage, data.depot_capacity, 'depot'))
-
- # Setting first solution heuristic (cheapest addition).
- search_parameters = pywrapcp.DefaultRoutingSearchParameters()
- # pylint: disable=no-member
- if not args['pickup_delivery']:
- search_parameters.first_solution_strategy = (
- routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
- else:
- search_parameters.first_solution_strategy = (
- routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)
-
- search_parameters.local_search_metaheuristic = (
- routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)
- search_parameters.time_limit.FromSeconds(2)
-
- # Solve the problem.
- assignment = routing.SolveWithParameters(search_parameters)
- # Print the solution.
- printer = SVGPrinter(args, data, manager, routing, assignment)
- printer.print_to_console()
- return 0
-
if __name__ == '__main__':
- main()
+ main()
diff --git a/ortools/linear_solver/linear_solver_natural_api.py b/ortools/linear_solver/linear_solver_natural_api.py
index 1d949ab5a9..bee3cbc236 100644
--- a/ortools/linear_solver/linear_solver_natural_api.py
+++ b/ortools/linear_solver/linear_solver_natural_api.py
@@ -13,7 +13,7 @@
"""Patch to the python wrapper of ../linear_solver.h providing an algebraic API.
-This is directly imported, and use exclusively in ./linear_solver.swig. See that
+This is directly imported, and use exclusively in ./linear_solver.i. See that
file.
For examples leveraging the code defined here, see ./pywraplp_test.py and
../../../python/linear_programming.py.
diff --git a/ortools/linear_solver/proto_solver/highs_proto_solver.cc b/ortools/linear_solver/proto_solver/highs_proto_solver.cc
index 4f74ce7ff2..e3d5a40053 100644
--- a/ortools/linear_solver/proto_solver/highs_proto_solver.cc
+++ b/ortools/linear_solver/proto_solver/highs_proto_solver.cc
@@ -29,8 +29,7 @@
namespace operations_research {
-absl::StatusOr HighsSolveProto(MPModelRequest request,
- bool solve_as_a_mip) {
+absl::StatusOr HighsSolveProto(MPModelRequest request) {
return absl::UnimplementedError("Highs support is not yet implemented");
}
diff --git a/ortools/linear_solver/proto_solver/highs_proto_solver.h b/ortools/linear_solver/proto_solver/highs_proto_solver.h
index 67d7684d29..226dc13ed8 100644
--- a/ortools/linear_solver/proto_solver/highs_proto_solver.h
+++ b/ortools/linear_solver/proto_solver/highs_proto_solver.h
@@ -23,8 +23,7 @@
namespace operations_research {
// Solve the input MIP model with the HIGHS solver.
-absl::StatusOr HighsSolveProto(MPModelRequest request,
- bool solve_as_a_mip = true);
+absl::StatusOr HighsSolveProto(MPModelRequest request);
} // namespace operations_research
diff --git a/ortools/linear_solver/python/pywraplp_test.py b/ortools/linear_solver/python/pywraplp_test.py
index d098d9e3a8..c6d9491602 100755
--- a/ortools/linear_solver/python/pywraplp_test.py
+++ b/ortools/linear_solver/python/pywraplp_test.py
@@ -10,7 +10,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-"""Simple unit tests for python/linear_solver.swig. Not exhaustive."""
+"""Simple unit tests for python/linear_solver.i. Not exhaustive."""
import unittest
from ortools.linear_solver import linear_solver_pb2
diff --git a/ortools/lp_data/model_reader.cc b/ortools/lp_data/model_reader.cc
index c1096452a5..f7ddfd0e0b 100644
--- a/ortools/lp_data/model_reader.cc
+++ b/ortools/lp_data/model_reader.cc
@@ -17,6 +17,7 @@
#include "ortools/base/file.h"
#include "ortools/base/helpers.h"
+#include "ortools/base/options.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/lp_data/proto_utils.h"
#include "ortools/util/file_util.h"
diff --git a/ortools/pdlp/quadratic_program_io.cc b/ortools/pdlp/quadratic_program_io.cc
index cab6ec5057..69ccbe93ba 100644
--- a/ortools/pdlp/quadratic_program_io.cc
+++ b/ortools/pdlp/quadratic_program_io.cc
@@ -34,6 +34,7 @@
#include "ortools/base/helpers.h"
#include "ortools/base/logging.h"
#include "ortools/base/mathutil.h"
+#include "ortools/base/options.h"
#include "ortools/base/status_macros.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/linear_solver/model_exporter.h"
diff --git a/ortools/port/file.cc b/ortools/port/file.cc
index 5932649bb3..fa854ec047 100644
--- a/ortools/port/file.cc
+++ b/ortools/port/file.cc
@@ -27,6 +27,7 @@
#include "absl/time/clock.h"
#include "ortools/base/file.h"
#include "ortools/base/helpers.h"
+#include "ortools/base/options.h"
#endif // !defined(__PORTABLE_PLATFORM__)
namespace operations_research {
diff --git a/ortools/sat/cp_model_expand.cc b/ortools/sat/cp_model_expand.cc
index 8628f54914..fbad10f058 100644
--- a/ortools/sat/cp_model_expand.cc
+++ b/ortools/sat/cp_model_expand.cc
@@ -1712,7 +1712,7 @@ void ExpandSomeLinearOfSizeTwo(ConstraintProto* ct, PresolveContext* context) {
DCHECK(context->DomainContains(var2, value2)) << "value2 = " << value2;
DCHECK_EQ(coeff1 * value1 + coeff2 * value2,
infeasible_reachable_values.FixedValue());
- // TODO(user, fdid): Presolve if one or two variables are Boolean.
+ // TODO(user): Presolve if one or two variables are Boolean.
if (!context->HasVarValueEncoding(var1, value1, nullptr) || size1 == 2) {
return;
}
diff --git a/ortools/sat/cp_model_presolve.cc b/ortools/sat/cp_model_presolve.cc
index cef7ada116..a1b6016d26 100644
--- a/ortools/sat/cp_model_presolve.cc
+++ b/ortools/sat/cp_model_presolve.cc
@@ -2387,7 +2387,7 @@ bool CpModelPresolver::PresolveDiophantine(ConstraintProto* ct) {
return false;
}
}
- // TODO(user, demonet): Make sure the newly generated linear constraint
+ // TODO(user): Make sure the newly generated linear constraint
// satisfy our no-overflow precondition on the min/max activity.
// We should check that the model still satisfy conditions in
@@ -8950,7 +8950,7 @@ bool ModelCopy::ImportAndSimplifyConstraints(
ConstraintProto* new_ct = context_->working_model->add_constraints();
*new_ct = ct;
if (ignore_names) {
- // TODO(user, fdid): find a better way than copy then clear_name()?
+ // TODO(user): find a better way than copy then clear_name()?
new_ct->clear_name();
}
}
diff --git a/ortools/sat/cp_model_solver.cc b/ortools/sat/cp_model_solver.cc
index 45a434667a..3600fc85bf 100644
--- a/ortools/sat/cp_model_solver.cc
+++ b/ortools/sat/cp_model_solver.cc
@@ -33,6 +33,7 @@
#include "google/protobuf/text_format.h"
#include "ortools/base/file.h"
#include "ortools/base/helpers.h"
+#include "ortools/base/options.h"
#endif // __PORTABLE_PLATFORM__
#include "absl/base/thread_annotations.h"
#include "absl/container/btree_map.h"
@@ -2422,7 +2423,7 @@ class FeasibilityPumpSolver : public SubSolver {
deterministic_time_since_last_synchronize_ = 0.0;
}
- // TODO(user, fdid): Display feasibility pump statistics.
+ // TODO(user): Display feasibility pump statistics.
private:
SharedClasses* shared_;
diff --git a/ortools/sat/docs/README.md b/ortools/sat/docs/README.md
index a9207042a4..90e348e84d 100644
--- a/ortools/sat/docs/README.md
+++ b/ortools/sat/docs/README.md
@@ -43,34 +43,35 @@ The Python interface to the CP-SAT solver is implemented using two classes.
access the solution found by the solve.
```python
+#!/usr/bin/env python3
"""Simple solve."""
from ortools.sat.python import cp_model
def SimpleSatProgram():
- """Minimal CP-SAT example to showcase calling the solver."""
- # Creates the model.
- model = cp_model.CpModel()
+ """Minimal CP-SAT example to showcase calling the solver."""
+ # Creates the model.
+ model = cp_model.CpModel()
- # Creates the variables.
- num_vals = 3
- x = model.NewIntVar(0, num_vals - 1, 'x')
- y = model.NewIntVar(0, num_vals - 1, 'y')
- z = model.NewIntVar(0, num_vals - 1, 'z')
+ # Creates the variables.
+ num_vals = 3
+ x = model.NewIntVar(0, num_vals - 1, 'x')
+ y = model.NewIntVar(0, num_vals - 1, 'y')
+ z = model.NewIntVar(0, num_vals - 1, 'z')
- # Creates the constraints.
- model.Add(x != y)
+ # Creates the constraints.
+ model.Add(x != y)
- # Creates a solver and solves the model.
- solver = cp_model.CpSolver()
- status = solver.Solve(model)
+ # Creates a solver and solves the model.
+ solver = cp_model.CpSolver()
+ status = solver.Solve(model)
- if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
- print('x = %i' % solver.Value(x))
- print('y = %i' % solver.Value(y))
- print('z = %i' % solver.Value(z))
- else:
- print('No solution found.')
+ if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
+ print('x = %i' % solver.Value(x))
+ print('y = %i' % solver.Value(y))
+ print('z = %i' % solver.Value(z))
+ else:
+ print('No solution found.')
SimpleSatProgram()
@@ -139,9 +140,9 @@ The Java code implements the same interface as the Python code, with a
```java
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
+import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.IntVar;
/** Minimal CP-SAT example to showcase calling the solver. */
diff --git a/ortools/sat/docs/boolean_logic.md b/ortools/sat/docs/boolean_logic.md
index d4a6fc9925..93bd844ad3 100644
--- a/ortools/sat/docs/boolean_logic.md
+++ b/ortools/sat/docs/boolean_logic.md
@@ -47,18 +47,17 @@ negation of `x`.
### Python code
```python
-"""Code sample to demonstrate Boolean variable and literals."""
-
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def LiteralSampleSat():
- model = cp_model.CpModel()
- x = model.NewBoolVar('x')
- not_x = x.Not()
- print(x)
- print(not_x)
+ model = cp_model.CpModel()
+ x = model.NewBoolVar('x')
+ not_x = x.Not()
+ print(x)
+ print(not_x)
LiteralSampleSat()
@@ -98,10 +97,10 @@ int main() {
```java
package com.google.ortools.sat.samples;
+import com.google.ortools.Loader;
import com.google.ortools.sat.BoolVar;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.Literal;
-import com.google.ortools.Loader;
/** Code sample to demonstrate Boolean variable and literals. */
public class LiteralSampleSat {
@@ -147,19 +146,18 @@ constraints. For instance, we can add a constraint Or(x, not(y)).
### Python code
```python
-"""Code sample to demonstrates a simple Boolean constraint."""
-
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def BoolOrSampleSat():
- model = cp_model.CpModel()
+ model = cp_model.CpModel()
- x = model.NewBoolVar('x')
- y = model.NewBoolVar('y')
+ x = model.NewBoolVar('x')
+ y = model.NewBoolVar('y')
- model.AddBoolOr([x, y.Not()])
+ model.AddBoolOr([x, y.Not()])
BoolOrSampleSat()
@@ -256,29 +254,29 @@ then is written as Or(not b, x) and Or(not b, not y).
### Python code
```python
-"""Simple model with a reified constraint."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def ReifiedSampleSat():
- """Showcase creating a reified constraint."""
- model = cp_model.CpModel()
+ """Showcase creating a reified constraint."""
+ model = cp_model.CpModel()
- x = model.NewBoolVar('x')
- y = model.NewBoolVar('y')
- b = model.NewBoolVar('b')
+ x = model.NewBoolVar('x')
+ y = model.NewBoolVar('y')
+ b = model.NewBoolVar('b')
- # First version using a half-reified bool and.
- model.AddBoolAnd(x, y.Not()).OnlyEnforceIf(b)
+ # First version using a half-reified bool and.
+ model.AddBoolAnd(x, y.Not()).OnlyEnforceIf(b)
- # Second version using implications.
- model.AddImplication(b, x)
- model.AddImplication(b, y.Not())
+ # Second version using implications.
+ model.AddImplication(b, x)
+ model.AddImplication(b, y.Not())
- # Third version using bool or.
- model.AddBoolOr(b.Not(), x)
- model.AddBoolOr(b.Not(), y.Not())
+ # Third version using bool or.
+ model.AddBoolOr(b.Not(), x)
+ model.AddBoolOr(b.Not(), y.Not())
ReifiedSampleSat()
@@ -418,34 +416,33 @@ code samples output this truth table:
### Python code
```python
-"""Code sample that encodes the product of two Boolean variables."""
-
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def BooleanProductSampleSat():
- """Encoding of the product of two Boolean variables.
+ """Encoding of the product of two Boolean variables.
p == x * y, which is the same as p <=> x and y
"""
- model = cp_model.CpModel()
- x = model.NewBoolVar('x')
- y = model.NewBoolVar('y')
- p = model.NewBoolVar('p')
+ model = cp_model.CpModel()
+ x = model.NewBoolVar('x')
+ y = model.NewBoolVar('y')
+ p = model.NewBoolVar('p')
- # x and y implies p, rewrite as not(x and y) or p
- model.AddBoolOr(x.Not(), y.Not(), p)
+ # x and y implies p, rewrite as not(x and y) or p
+ model.AddBoolOr(x.Not(), y.Not(), p)
- # p implies x and y, expanded into two implication
- model.AddImplication(p, x)
- model.AddImplication(p, y)
+ # p implies x and y, expanded into two implication
+ model.AddImplication(p, x)
+ model.AddImplication(p, y)
- # Create a solver and solve.
- solver = cp_model.CpSolver()
- solution_printer = cp_model.VarArraySolutionPrinter([x, y, p])
- solver.parameters.enumerate_all_solutions = True
- solver.Solve(model, solution_printer)
+ # Create a solver and solve.
+ solver = cp_model.CpSolver()
+ solution_printer = cp_model.VarArraySolutionPrinter([x, y, p])
+ solver.parameters.enumerate_all_solutions = True
+ solver.Solve(model, solution_printer)
BooleanProductSampleSat()
diff --git a/ortools/sat/docs/channeling.md b/ortools/sat/docs/channeling.md
index e90b6ea89b..108d66de65 100644
--- a/ortools/sat/docs/channeling.md
+++ b/ortools/sat/docs/channeling.md
@@ -46,68 +46,67 @@ These are implemented using the `OnlyEnforceIf` method as shown below.
### Python code
```python
-"""Link integer constraints together."""
-
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
- """Print intermediate solutions."""
+ """Print intermediate solutions."""
- def __init__(self, variables):
- cp_model.CpSolverSolutionCallback.__init__(self)
- self.__variables = variables
- self.__solution_count = 0
+ def __init__(self, variables):
+ cp_model.CpSolverSolutionCallback.__init__(self)
+ self.__variables = variables
+ self.__solution_count = 0
- def on_solution_callback(self):
- self.__solution_count += 1
- for v in self.__variables:
- print('%s=%i' % (v, self.Value(v)), end=' ')
- print()
+ def on_solution_callback(self):
+ self.__solution_count += 1
+ for v in self.__variables:
+ print('%s=%i' % (v, self.Value(v)), end=' ')
+ print()
- def solution_count(self):
- return self.__solution_count
+ def solution_count(self):
+ return self.__solution_count
def ChannelingSampleSat():
- """Demonstrates how to link integer constraints together."""
+ """Demonstrates how to link integer constraints together."""
- # Create the CP-SAT model.
- model = cp_model.CpModel()
+ # Create the CP-SAT model.
+ model = cp_model.CpModel()
- # Declare our two primary variables.
- x = model.NewIntVar(0, 10, 'x')
- y = model.NewIntVar(0, 10, 'y')
+ # Declare our two primary variables.
+ x = model.NewIntVar(0, 10, 'x')
+ y = model.NewIntVar(0, 10, 'y')
- # Declare our intermediate boolean variable.
- b = model.NewBoolVar('b')
+ # Declare our intermediate boolean variable.
+ b = model.NewBoolVar('b')
- # Implement b == (x >= 5).
- model.Add(x >= 5).OnlyEnforceIf(b)
- model.Add(x < 5).OnlyEnforceIf(b.Not())
+ # Implement b == (x >= 5).
+ model.Add(x >= 5).OnlyEnforceIf(b)
+ model.Add(x < 5).OnlyEnforceIf(b.Not())
- # Create our two half-reified constraints.
- # First, b implies (y == 10 - x).
- model.Add(y == 10 - x).OnlyEnforceIf(b)
- # Second, not(b) implies y == 0.
- model.Add(y == 0).OnlyEnforceIf(b.Not())
+ # Create our two half-reified constraints.
+ # First, b implies (y == 10 - x).
+ model.Add(y == 10 - x).OnlyEnforceIf(b)
+ # Second, not(b) implies y == 0.
+ model.Add(y == 0).OnlyEnforceIf(b.Not())
- # Search for x values in increasing order.
- model.AddDecisionStrategy([x], cp_model.CHOOSE_FIRST,
- cp_model.SELECT_MIN_VALUE)
+ # Search for x values in increasing order.
+ model.AddDecisionStrategy([x], cp_model.CHOOSE_FIRST,
+ cp_model.SELECT_MIN_VALUE)
- # Create a solver and solve with a fixed search.
- solver = cp_model.CpSolver()
+ # Create a solver and solve with a fixed search.
+ solver = cp_model.CpSolver()
- # Force the solver to follow the decision strategy exactly.
- solver.parameters.search_branching = cp_model.FIXED_SEARCH
- # Enumerate all solutions.
- solver.parameters.enumerate_all_solutions = True
+ # Force the solver to follow the decision strategy exactly.
+ solver.parameters.search_branching = cp_model.FIXED_SEARCH
+ # Enumerate all solutions.
+ solver.parameters.enumerate_all_solutions = True
- # Search and print out all solutions.
- solution_printer = VarArraySolutionPrinter([x, y, b])
- solver.Solve(model, solution_printer)
+ # Search and print out all solutions.
+ solution_printer = VarArraySolutionPrinter([x, y, b])
+ solver.Solve(model, solution_printer)
ChannelingSampleSat()
@@ -118,8 +117,8 @@ ChannelingSampleSat()
```cpp
#include
-#include "ortools/base/logging.h"
#include "absl/types/span.h"
+#include "ortools/base/logging.h"
#include "ortools/sat/cp_model.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
@@ -184,14 +183,14 @@ int main() {
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.DecisionStrategyProto;
-import com.google.ortools.sat.SatParameters;
import com.google.ortools.sat.BoolVar;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
import com.google.ortools.sat.CpSolverSolutionCallback;
+import com.google.ortools.sat.DecisionStrategyProto;
import com.google.ortools.sat.IntVar;
import com.google.ortools.sat.LinearExpr;
+import com.google.ortools.sat.SatParameters;
/** Link integer constraints together. */
public class ChannelingSampleSat {
@@ -217,8 +216,7 @@ public class ChannelingSampleSat {
model.addEquality(vars[1], 0).onlyEnforceIf(b.not());
// Search for x values in increasing order.
- model.addDecisionStrategy(
- new IntVar[] {vars[0]},
+ model.addDecisionStrategy(new IntVar[] {vars[0]},
DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_FIRST,
DecisionStrategyProto.DomainReductionStrategy.SELECT_MIN_VALUE);
@@ -231,24 +229,22 @@ public class ChannelingSampleSat {
solver.getParameters().setEnumerateAllSolutions(true);
// Solve the problem with the printer callback.
- solver.solve(
- model,
- new CpSolverSolutionCallback() {
- public CpSolverSolutionCallback init(IntVar[] variables) {
- variableArray = variables;
- return this;
- }
+ solver.solve(model, new CpSolverSolutionCallback() {
+ public CpSolverSolutionCallback init(IntVar[] variables) {
+ variableArray = variables;
+ return this;
+ }
- @Override
- public void onSolutionCallback() {
- for (IntVar v : variableArray) {
- System.out.printf("%s=%d ", v.getName(), value(v));
- }
- System.out.println();
- }
+ @Override
+ public void onSolutionCallback() {
+ for (IntVar v : variableArray) {
+ System.out.printf("%s=%d ", v.getName(), value(v));
+ }
+ System.out.println();
+ }
- private IntVar[] variableArray;
- }.init(new IntVar[] {vars[0], vars[1], b}));
+ private IntVar[] variableArray;
+ }.init(new IntVar[] {vars[0], vars[1], b}));
}
}
```
@@ -358,70 +354,68 @@ variables together:
### Python code
```python
-"""Solves a binpacking problem using the CP-SAT solver."""
-
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
-
def BinpackingProblemSat():
- """Solves a bin-packing problem using the CP-SAT solver."""
- # Data.
- bin_capacity = 100
- slack_capacity = 20
- num_bins = 5
- all_bins = range(num_bins)
+ """Solves a bin-packing problem using the CP-SAT solver."""
+ # Data.
+ bin_capacity = 100
+ slack_capacity = 20
+ num_bins = 5
+ all_bins = range(num_bins)
- items = [(20, 6), (15, 6), (30, 4), (45, 3)]
- num_items = len(items)
- all_items = range(num_items)
+ items = [(20, 6), (15, 6), (30, 4), (45, 3)]
+ num_items = len(items)
+ all_items = range(num_items)
- # Model.
- model = cp_model.CpModel()
+ # Model.
+ model = cp_model.CpModel()
- # Main variables.
- x = {}
- for i in all_items:
- num_copies = items[i][1]
+ # Main variables.
+ x = {}
+ for i in all_items:
+ num_copies = items[i][1]
+ for b in all_bins:
+ x[(i, b)] = model.NewIntVar(0, num_copies, 'x_%i_%i' % (i, b))
+
+ # Load variables.
+ load = [model.NewIntVar(0, bin_capacity, 'load_%i' % b) for b in all_bins]
+
+ # Slack variables.
+ slacks = [model.NewBoolVar('slack_%i' % b) for b in all_bins]
+
+ # Links load and x.
for b in all_bins:
- x[(i, b)] = model.NewIntVar(0, num_copies, 'x_%i_%i' % (i, b))
+ model.Add(load[b] == sum(x[(i, b)] * items[i][0] for i in all_items))
- # Load variables.
- load = [model.NewIntVar(0, bin_capacity, 'load_%i' % b) for b in all_bins]
+ # Place all items.
+ for i in all_items:
+ model.Add(sum(x[(i, b)] for b in all_bins) == items[i][1])
- # Slack variables.
- slacks = [model.NewBoolVar('slack_%i' % b) for b in all_bins]
+ # Links load and slack through an equivalence relation.
+ safe_capacity = bin_capacity - slack_capacity
+ for b in all_bins:
+ # slack[b] => load[b] <= safe_capacity.
+ model.Add(load[b] <= safe_capacity).OnlyEnforceIf(slacks[b])
+ # not(slack[b]) => load[b] > safe_capacity.
+ model.Add(load[b] > safe_capacity).OnlyEnforceIf(slacks[b].Not())
- # Links load and x.
- for b in all_bins:
- model.Add(load[b] == sum(x[(i, b)] * items[i][0] for i in all_items))
+ # Maximize sum of slacks.
+ model.Maximize(sum(slacks))
- # Place all items.
- for i in all_items:
- model.Add(sum(x[(i, b)] for b in all_bins) == items[i][1])
-
- # Links load and slack through an equivalence relation.
- safe_capacity = bin_capacity - slack_capacity
- for b in all_bins:
- # slack[b] => load[b] <= safe_capacity.
- model.Add(load[b] <= safe_capacity).OnlyEnforceIf(slacks[b])
- # not(slack[b]) => load[b] > safe_capacity.
- model.Add(load[b] > safe_capacity).OnlyEnforceIf(slacks[b].Not())
-
- # Maximize sum of slacks.
- model.Maximize(sum(slacks))
-
- # Solves and prints out the solution.
- solver = cp_model.CpSolver()
- status = solver.Solve(model)
- print('Solve status: %s' % solver.StatusName(status))
- if status == cp_model.OPTIMAL:
- print('Optimal objective value: %i' % solver.ObjectiveValue())
- print('Statistics')
- print(' - conflicts : %i' % solver.NumConflicts())
- print(' - branches : %i' % solver.NumBranches())
- print(' - wall time : %f s' % solver.WallTime())
+ # Solves and prints out the solution.
+ solver = cp_model.CpSolver()
+ status = solver.Solve(model)
+ print('Solve status: %s' % solver.StatusName(status))
+ if status == cp_model.OPTIMAL:
+ print('Optimal objective value: %i' % solver.ObjectiveValue())
+ print('Statistics')
+ print(' - conflicts : %i' % solver.NumConflicts())
+ print(' - branches : %i' % solver.NumBranches())
+ print(' - wall time : %f s' % solver.WallTime())
BinpackingProblemSat()
@@ -524,9 +518,9 @@ int main() {
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
+import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.IntVar;
import com.google.ortools.sat.LinearExpr;
import com.google.ortools.sat.LinearExprBuilder;
diff --git a/ortools/sat/docs/integer_arithmetic.md b/ortools/sat/docs/integer_arithmetic.md
index 3491ac4ab2..c4078fa41d 100644
--- a/ortools/sat/docs/integer_arithmetic.md
+++ b/ortools/sat/docs/integer_arithmetic.md
@@ -148,29 +148,30 @@ rabbits and pheasants are there?
### Python code
```python
-"""Rabbits and Pheasants quizz."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def RabbitsAndPheasantsSat():
- """Solves the rabbits + pheasants problem."""
- model = cp_model.CpModel()
+ """Solves the rabbits + pheasants problem."""
+ model = cp_model.CpModel()
- r = model.NewIntVar(0, 100, 'r')
- p = model.NewIntVar(0, 100, 'p')
+ r = model.NewIntVar(0, 100, 'r')
+ p = model.NewIntVar(0, 100, 'p')
- # 20 heads.
- model.Add(r + p == 20)
- # 56 legs.
- model.Add(4 * r + 2 * p == 56)
+ # 20 heads.
+ model.Add(r + p == 20)
+ # 56 legs.
+ model.Add(4 * r + 2 * p == 56)
- # Solves and prints out the solution.
- solver = cp_model.CpSolver()
- status = solver.Solve(model)
+ # Solves and prints out the solution.
+ solver = cp_model.CpSolver()
+ status = solver.Solve(model)
- if status == cp_model.OPTIMAL:
- print('%i rabbits and %i pheasants' % (solver.Value(r), solver.Value(p)))
+ if status == cp_model.OPTIMAL:
+ print('%i rabbits and %i pheasants' %
+ (solver.Value(r), solver.Value(p)))
RabbitsAndPheasantsSat()
@@ -226,9 +227,9 @@ int main() {
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
+import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.IntVar;
import com.google.ortools.sat.LinearExpr;
@@ -290,7 +291,6 @@ public class RabbitsAndPheasantsSat
}
}
}
-
```
## Earliness-Tardiness cost function.
@@ -330,82 +330,81 @@ The following samples output:
### Python code
```python
-"""Encodes an convex piecewise linear function."""
-
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
- """Print intermediate solutions."""
+ """Print intermediate solutions."""
- def __init__(self, variables):
- cp_model.CpSolverSolutionCallback.__init__(self)
- self.__variables = variables
- self.__solution_count = 0
+ def __init__(self, variables):
+ cp_model.CpSolverSolutionCallback.__init__(self)
+ self.__variables = variables
+ self.__solution_count = 0
- def on_solution_callback(self):
- self.__solution_count += 1
- for v in self.__variables:
- print('%s=%i' % (v, self.Value(v)), end=' ')
- print()
+ def on_solution_callback(self):
+ self.__solution_count += 1
+ for v in self.__variables:
+ print('%s=%i' % (v, self.Value(v)), end=' ')
+ print()
- def solution_count(self):
- return self.__solution_count
+ def solution_count(self):
+ return self.__solution_count
def earliness_tardiness_cost_sample_sat():
- """Encode the piecewise linear expression."""
+ """Encode the piecewise linear expression."""
- earliness_date = 5 # ed.
- earliness_cost = 8
- lateness_date = 15 # ld.
- lateness_cost = 12
+ earliness_date = 5 # ed.
+ earliness_cost = 8
+ lateness_date = 15 # ld.
+ lateness_cost = 12
- # Model.
- model = cp_model.CpModel()
+ # Model.
+ model = cp_model.CpModel()
- # Declare our primary variable.
- x = model.NewIntVar(0, 20, 'x')
+ # Declare our primary variable.
+ x = model.NewIntVar(0, 20, 'x')
- # Create the expression variable and implement the piecewise linear function.
- #
- # \ /
- # \______/
- # ed ld
- #
- large_constant = 1000
- expr = model.NewIntVar(0, large_constant, 'expr')
+ # Create the expression variable and implement the piecewise linear function.
+ #
+ # \ /
+ # \______/
+ # ed ld
+ #
+ large_constant = 1000
+ expr = model.NewIntVar(0, large_constant, 'expr')
- # First segment.
- s1 = model.NewIntVar(-large_constant, large_constant, 's1')
- model.Add(s1 == earliness_cost * (earliness_date - x))
+ # First segment.
+ s1 = model.NewIntVar(-large_constant, large_constant, 's1')
+ model.Add(s1 == earliness_cost * (earliness_date - x))
- # Second segment.
- s2 = 0
+ # Second segment.
+ s2 = 0
- # Third segment.
- s3 = model.NewIntVar(-large_constant, large_constant, 's3')
- model.Add(s3 == lateness_cost * (x - lateness_date))
+ # Third segment.
+ s3 = model.NewIntVar(-large_constant, large_constant, 's3')
+ model.Add(s3 == lateness_cost * (x - lateness_date))
- # Link together expr and x through s1, s2, and s3.
- model.AddMaxEquality(expr, [s1, s2, s3])
+ # Link together expr and x through s1, s2, and s3.
+ model.AddMaxEquality(expr, [s1, s2, s3])
- # Search for x values in increasing order.
- model.AddDecisionStrategy([x], cp_model.CHOOSE_FIRST,
- cp_model.SELECT_MIN_VALUE)
+ # Search for x values in increasing order.
+ model.AddDecisionStrategy([x], cp_model.CHOOSE_FIRST,
+ cp_model.SELECT_MIN_VALUE)
- # Create a solver and solve with a fixed search.
- solver = cp_model.CpSolver()
+ # Create a solver and solve with a fixed search.
+ solver = cp_model.CpSolver()
- # Force the solver to follow the decision strategy exactly.
- solver.parameters.search_branching = cp_model.FIXED_SEARCH
- # Enumerate all solutions.
- solver.parameters.enumerate_all_solutions = True
+ # Force the solver to follow the decision strategy exactly.
+ solver.parameters.search_branching = cp_model.FIXED_SEARCH
+ # Enumerate all solutions.
+ solver.parameters.enumerate_all_solutions = True
- # Search and print out all solutions.
- solution_printer = VarArraySolutionPrinter([x, expr])
- solver.Solve(model, solution_printer)
+ # Search and print out all solutions.
+ solution_printer = VarArraySolutionPrinter([x, expr])
+ solver.Solve(model, solution_printer)
earliness_tardiness_cost_sample_sat()
@@ -418,8 +417,8 @@ earliness_tardiness_cost_sample_sat()
#include
-#include "ortools/base/logging.h"
#include "absl/types/span.h"
+#include "ortools/base/logging.h"
#include "ortools/sat/cp_model.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
@@ -487,13 +486,13 @@ int main() {
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.DecisionStrategyProto;
-import com.google.ortools.sat.SatParameters;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
import com.google.ortools.sat.CpSolverSolutionCallback;
+import com.google.ortools.sat.DecisionStrategyProto;
import com.google.ortools.sat.IntVar;
import com.google.ortools.sat.LinearExpr;
+import com.google.ortools.sat.SatParameters;
/** Encode the piecewise linear expression. */
public class EarlinessTardinessCostSampleSat {
@@ -523,20 +522,19 @@ public class EarlinessTardinessCostSampleSat {
// First segment: y == earlinessCost * (earlinessDate - x).
// Second segment: y = 0
// Third segment: y == latenessCost * (x - latenessDate).
- model.addMaxEquality(
- expr,
- new LinearExpr[] {
- LinearExpr.newBuilder()
- .addTerm(x, -earlinessCost)
- .add(earlinessCost * earlinessDate)
- .build(),
- LinearExpr.constant(0),
- LinearExpr.newBuilder().addTerm(x, latenessCost).add(-latenessCost * latenessDate).build()
- });
+ model.addMaxEquality(expr,
+ new LinearExpr[] {LinearExpr.newBuilder()
+ .addTerm(x, -earlinessCost)
+ .add(earlinessCost * earlinessDate)
+ .build(),
+ LinearExpr.constant(0),
+ LinearExpr.newBuilder()
+ .addTerm(x, latenessCost)
+ .add(-latenessCost * latenessDate)
+ .build()});
// Search for x values in increasing order.
- model.addDecisionStrategy(
- new IntVar[] {x},
+ model.addDecisionStrategy(new IntVar[] {x},
DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_FIRST,
DecisionStrategyProto.DomainReductionStrategy.SELECT_MIN_VALUE);
@@ -549,24 +547,22 @@ public class EarlinessTardinessCostSampleSat {
solver.getParameters().setEnumerateAllSolutions(true);
// Solve the problem with the printer callback.
- solver.solve(
- model,
- new CpSolverSolutionCallback() {
- public CpSolverSolutionCallback init(IntVar[] variables) {
- variableArray = variables;
- return this;
- }
+ solver.solve(model, new CpSolverSolutionCallback() {
+ public CpSolverSolutionCallback init(IntVar[] variables) {
+ variableArray = variables;
+ return this;
+ }
- @Override
- public void onSolutionCallback() {
- for (IntVar v : variableArray) {
- System.out.printf("%s=%d ", v.getName(), value(v));
- }
- System.out.println();
- }
+ @Override
+ public void onSolutionCallback() {
+ for (IntVar v : variableArray) {
+ System.out.printf("%s=%d ", v.getName(), value(v));
+ }
+ System.out.println();
+ }
- private IntVar[] variableArray;
- }.init(new IntVar[] {x, expr}));
+ private IntVar[] variableArray;
+ }.init(new IntVar[] {x, expr}));
}
}
```
@@ -676,85 +672,85 @@ The following samples output:
### Python code
```python
-"""Implements a step function."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
- """Print intermediate solutions."""
+ """Print intermediate solutions."""
- def __init__(self, variables):
- cp_model.CpSolverSolutionCallback.__init__(self)
- self.__variables = variables
- self.__solution_count = 0
+ def __init__(self, variables):
+ cp_model.CpSolverSolutionCallback.__init__(self)
+ self.__variables = variables
+ self.__solution_count = 0
- def on_solution_callback(self):
- self.__solution_count += 1
- for v in self.__variables:
- print('%s=%i' % (v, self.Value(v)), end=' ')
- print()
+ def on_solution_callback(self):
+ self.__solution_count += 1
+ for v in self.__variables:
+ print('%s=%i' % (v, self.Value(v)), end=' ')
+ print()
- def solution_count(self):
- return self.__solution_count
+ def solution_count(self):
+ return self.__solution_count
def step_function_sample_sat():
- """Encode the step function."""
+ """Encode the step function."""
- # Model.
- model = cp_model.CpModel()
+ # Model.
+ model = cp_model.CpModel()
- # Declare our primary variable.
- x = model.NewIntVar(0, 20, 'x')
+ # Declare our primary variable.
+ x = model.NewIntVar(0, 20, 'x')
- # Create the expression variable and implement the step function
- # Note it is not defined for x == 2.
- #
- # - 3
- # -- -- --------- 2
- # 1
- # -- --- 0
- # 0 ================ 20
- #
- expr = model.NewIntVar(0, 3, 'expr')
+ # Create the expression variable and implement the step function
+ # Note it is not defined for x == 2.
+ #
+ # - 3
+ # -- -- --------- 2
+ # 1
+ # -- --- 0
+ # 0 ================ 20
+ #
+ expr = model.NewIntVar(0, 3, 'expr')
- # expr == 0 on [5, 6] U [8, 10]
- b0 = model.NewBoolVar('b0')
- model.AddLinearExpressionInDomain(
- x, cp_model.Domain.FromIntervals([(5, 6), (8, 10)])).OnlyEnforceIf(b0)
- model.Add(expr == 0).OnlyEnforceIf(b0)
+ # expr == 0 on [5, 6] U [8, 10]
+ b0 = model.NewBoolVar('b0')
+ model.AddLinearExpressionInDomain(
+ x, cp_model.Domain.FromIntervals([(5, 6), (8, 10)])).OnlyEnforceIf(b0)
+ model.Add(expr == 0).OnlyEnforceIf(b0)
- # expr == 2 on [0, 1] U [3, 4] U [11, 20]
- b2 = model.NewBoolVar('b2')
- model.AddLinearExpressionInDomain(
- x, cp_model.Domain.FromIntervals([(0, 1), (3, 4),
- (11, 20)])).OnlyEnforceIf(b2)
- model.Add(expr == 2).OnlyEnforceIf(b2)
+ # expr == 2 on [0, 1] U [3, 4] U [11, 20]
+ b2 = model.NewBoolVar('b2')
+ model.AddLinearExpressionInDomain(
+ x, cp_model.Domain.FromIntervals([(0, 1), (3, 4),
+ (11, 20)])).OnlyEnforceIf(b2)
+ model.Add(expr == 2).OnlyEnforceIf(b2)
- # expr == 3 when x == 7
- b3 = model.NewBoolVar('b3')
- model.Add(x == 7).OnlyEnforceIf(b3)
- model.Add(expr == 3).OnlyEnforceIf(b3)
+ # expr == 3 when x == 7
+ b3 = model.NewBoolVar('b3')
+ model.Add(x == 7).OnlyEnforceIf(b3)
+ model.Add(expr == 3).OnlyEnforceIf(b3)
- # At least one bi is true. (we could use an exactly one constraint).
- model.AddBoolOr(b0, b2, b3)
+ # At least one bi is true. (we could use an exactly one constraint).
+ model.AddBoolOr(b0, b2, b3)
- # Search for x values in increasing order.
- model.AddDecisionStrategy([x], cp_model.CHOOSE_FIRST,
- cp_model.SELECT_MIN_VALUE)
+ # Search for x values in increasing order.
+ model.AddDecisionStrategy([x], cp_model.CHOOSE_FIRST,
+ cp_model.SELECT_MIN_VALUE)
- # Create a solver and solve with a fixed search.
- solver = cp_model.CpSolver()
+ # Create a solver and solve with a fixed search.
+ solver = cp_model.CpSolver()
- # Force the solver to follow the decision strategy exactly.
- solver.parameters.search_branching = cp_model.FIXED_SEARCH
- # Enumerate all solutions.
- solver.parameters.enumerate_all_solutions = True
+ # Force the solver to follow the decision strategy exactly.
+ solver.parameters.search_branching = cp_model.FIXED_SEARCH
+ # Enumerate all solutions.
+ solver.parameters.enumerate_all_solutions = True
- # Search and print out all solutions.
- solution_printer = VarArraySolutionPrinter([x, expr])
- solver.Solve(model, solution_printer)
+ # Search and print out all solutions.
+ solution_printer = VarArraySolutionPrinter([x, expr])
+ solver.Solve(model, solution_printer)
step_function_sample_sat()
@@ -767,9 +763,9 @@ step_function_sample_sat()
#include
+#include "absl/types/span.h"
#include "ortools/base/integral_types.h"
#include "ortools/base/logging.h"
-#include "absl/types/span.h"
#include "ortools/sat/cp_model.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
@@ -852,13 +848,13 @@ int main() {
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.DecisionStrategyProto;
-import com.google.ortools.sat.SatParameters;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
import com.google.ortools.sat.CpSolverSolutionCallback;
+import com.google.ortools.sat.DecisionStrategyProto;
import com.google.ortools.sat.IntVar;
import com.google.ortools.sat.Literal;
+import com.google.ortools.sat.SatParameters;
import com.google.ortools.util.Domain;
/** Link integer constraints together. */
@@ -884,8 +880,7 @@ public class StepFunctionSampleSat {
// expr == 0 on [5, 6] U [8, 10]
Literal b0 = model.newBoolVar("b0");
- model
- .addLinearExpressionInDomain(x, Domain.fromValues(new long[] {5, 6, 8, 9, 10}))
+ model.addLinearExpressionInDomain(x, Domain.fromValues(new long[] {5, 6, 8, 9, 10}))
.onlyEnforceIf(b0);
model.addEquality(expr, 0).onlyEnforceIf(b0);
@@ -906,8 +901,7 @@ public class StepFunctionSampleSat {
model.addBoolOr(new Literal[] {b0, b2, b3});
// Search for x values in increasing order.
- model.addDecisionStrategy(
- new IntVar[] {x},
+ model.addDecisionStrategy(new IntVar[] {x},
DecisionStrategyProto.VariableSelectionStrategy.CHOOSE_FIRST,
DecisionStrategyProto.DomainReductionStrategy.SELECT_MIN_VALUE);
@@ -920,24 +914,22 @@ public class StepFunctionSampleSat {
solver.getParameters().setEnumerateAllSolutions(true);
// Solve the problem with the printer callback.
- solver.solve(
- model,
- new CpSolverSolutionCallback() {
- public CpSolverSolutionCallback init(IntVar[] variables) {
- variableArray = variables;
- return this;
- }
+ solver.solve(model, new CpSolverSolutionCallback() {
+ public CpSolverSolutionCallback init(IntVar[] variables) {
+ variableArray = variables;
+ return this;
+ }
- @Override
- public void onSolutionCallback() {
- for (IntVar v : variableArray) {
- System.out.printf("%s=%d ", v.getName(), value(v));
- }
- System.out.println();
- }
+ @Override
+ public void onSolutionCallback() {
+ for (IntVar v : variableArray) {
+ System.out.printf("%s=%d ", v.getName(), value(v));
+ }
+ System.out.println();
+ }
- private IntVar[] variableArray;
- }.init(new IntVar[] {x, expr}));
+ private IntVar[] variableArray;
+ }.init(new IntVar[] {x, expr}));
}
}
```
diff --git a/ortools/sat/docs/model.md b/ortools/sat/docs/model.md
index 98b9da2697..8c781dfc79 100644
--- a/ortools/sat/docs/model.md
+++ b/ortools/sat/docs/model.md
@@ -89,38 +89,38 @@ Some remarks:
### Python code
```python
-"""Code sample that solves a model using solution hinting."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def SolutionHintingSampleSat():
- """Showcases solution hinting."""
- # Creates the model.
- model = cp_model.CpModel()
+ """Showcases solution hinting."""
+ # Creates the model.
+ model = cp_model.CpModel()
- # Creates the variables.
- num_vals = 3
- x = model.NewIntVar(0, num_vals - 1, 'x')
- y = model.NewIntVar(0, num_vals - 1, 'y')
- z = model.NewIntVar(0, num_vals - 1, 'z')
+ # Creates the variables.
+ num_vals = 3
+ x = model.NewIntVar(0, num_vals - 1, 'x')
+ y = model.NewIntVar(0, num_vals - 1, 'y')
+ z = model.NewIntVar(0, num_vals - 1, 'z')
- # Creates the constraints.
- model.Add(x != y)
+ # Creates the constraints.
+ model.Add(x != y)
- model.Maximize(x + 2 * y + 3 * z)
+ model.Maximize(x + 2 * y + 3 * z)
- # Solution hinting: x <- 1, y <- 2
- model.AddHint(x, 1)
- model.AddHint(y, 2)
+ # Solution hinting: x <- 1, y <- 2
+ model.AddHint(x, 1)
+ model.AddHint(y, 2)
- # Creates a solver and solves.
- solver = cp_model.CpSolver()
- solution_printer = cp_model.VarArrayAndObjectiveSolutionPrinter([x, y, z])
- status = solver.Solve(model, solution_printer)
+ # Creates a solver and solves.
+ solver = cp_model.CpSolver()
+ solution_printer = cp_model.VarArrayAndObjectiveSolutionPrinter([x, y, z])
+ status = solver.Solve(model, solution_printer)
- print('Status = %s' % solver.StatusName(status))
- print('Number of solutions found: %i' % solution_printer.solution_count())
+ print('Status = %s' % solver.StatusName(status))
+ print('Number of solutions found: %i' % solution_printer.solution_count())
SolutionHintingSampleSat()
@@ -321,48 +321,48 @@ illustrated in the following examples.
### Python code
```python
-"""Showcases deep copying of a model."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def CopyModelSat():
- """Showcases printing intermediate solutions found during search."""
- # Creates the model.
- model = cp_model.CpModel()
+ """Showcases printing intermediate solutions found during search."""
+ # Creates the model.
+ model = cp_model.CpModel()
- # Creates the variables.
- num_vals = 3
- x = model.NewIntVar(0, num_vals - 1, 'x')
- y = model.NewIntVar(0, num_vals - 1, 'y')
- z = model.NewIntVar(0, num_vals - 1, 'z')
+ # Creates the variables.
+ num_vals = 3
+ x = model.NewIntVar(0, num_vals - 1, 'x')
+ y = model.NewIntVar(0, num_vals - 1, 'y')
+ z = model.NewIntVar(0, num_vals - 1, 'z')
- # Creates the constraints.
- model.Add(x != y)
+ # Creates the constraints.
+ model.Add(x != y)
- model.Maximize(x + 2 * y + 3 * z)
+ model.Maximize(x + 2 * y + 3 * z)
- # Creates a solver and solves.
- solver = cp_model.CpSolver()
- status = solver.Solve(model)
+ # Creates a solver and solves.
+ solver = cp_model.CpSolver()
+ status = solver.Solve(model)
- if status == cp_model.OPTIMAL:
- print('Optimal value of the original model: {}'.format(
- solver.ObjectiveValue()))
+ if status == cp_model.OPTIMAL:
+ print('Optimal value of the original model: {}'.format(
+ solver.ObjectiveValue()))
- # Copy the model.
- copy = cp_model.CpModel()
- copy.CopyFrom(model)
+ # Copy the model.
+ copy = cp_model.CpModel()
+ copy.CopyFrom(model)
- copy_x = copy.GetIntVarFromProtoIndex(x.Index())
- copy_y = copy.GetIntVarFromProtoIndex(y.Index())
+ copy_x = copy.GetIntVarFromProtoIndex(x.Index())
+ copy_y = copy.GetIntVarFromProtoIndex(y.Index())
- copy.Add(copy_x + copy_y <= 1)
- status = solver.Solve(copy)
+ copy.Add(copy_x + copy_y <= 1)
+ status = solver.Solve(copy)
- if status == cp_model.OPTIMAL:
- print('Optimal value of the modified model: {}'.format(
- solver.ObjectiveValue()))
+ if status == cp_model.OPTIMAL:
+ print('Optimal value of the modified model: {}'.format(
+ solver.ObjectiveValue()))
CopyModelSat()
diff --git a/ortools/sat/docs/scheduling.md b/ortools/sat/docs/scheduling.md
index 3679f7309d..661310873d 100644
--- a/ortools/sat/docs/scheduling.md
+++ b/ortools/sat/docs/scheduling.md
@@ -64,35 +64,34 @@ Creating these intervals is illustrated in the following code snippets.
### Python code
```python
-"""Code sample to demonstrates how to build an interval."""
-
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def IntervalSampleSat():
- """Showcases how to build interval variables."""
- model = cp_model.CpModel()
- horizon = 100
+ """Showcases how to build interval variables."""
+ model = cp_model.CpModel()
+ horizon = 100
- # An interval can be created from three affine expressions.
- start_var = model.NewIntVar(0, horizon, 'start')
- duration = 10 # Python cp/sat code accept integer variables or constants.
- end_var = model.NewIntVar(0, horizon, 'end')
- interval_var = model.NewIntervalVar(start_var, duration, end_var + 2,
- 'interval')
+ # An interval can be created from three affine expressions.
+ start_var = model.NewIntVar(0, horizon, 'start')
+ duration = 10 # Python cp/sat code accept integer variables or constants.
+ end_var = model.NewIntVar(0, horizon, 'end')
+ interval_var = model.NewIntervalVar(start_var, duration, end_var + 2,
+ 'interval')
- print(f'interval = {repr(interval_var)}')
+ print(f'interval = {repr(interval_var)}')
- # If the size is fixed, a simpler version uses the start expression and the
- # size.
- fixed_size_interval_var = model.NewFixedSizeIntervalVar(
- start_var, 10, 'fixed_size_interval_var')
- print(f'fixed_size_interval_var = {repr(fixed_size_interval_var)}')
+ # If the size is fixed, a simpler version uses the start expression and the
+ # size.
+ fixed_size_interval_var = model.NewFixedSizeIntervalVar(
+ start_var, 10, 'fixed_size_interval_var')
+ print(f'fixed_size_interval_var = {repr(fixed_size_interval_var)}')
- # A fixed interval can be created using the same API.
- fixed_interval = model.NewFixedSizeIntervalVar(5, 10, 'fixed_interval')
- print(f'fixed_interval = {repr(fixed_interval)}')
+ # A fixed interval can be created using the same API.
+ fixed_interval = model.NewFixedSizeIntervalVar(5, 10, 'fixed_interval')
+ print(f'fixed_interval = {repr(fixed_interval)}')
IntervalSampleSat()
@@ -177,12 +176,8 @@ public class IntervalSampleSat {
// An interval can be created from three affine expressions.
IntVar startVar = model.newIntVar(0, horizon, "start");
IntVar endVar = model.newIntVar(0, horizon, "end");
- IntervalVar intervalVar =
- model.newIntervalVar(
- startVar,
- LinearExpr.constant(10),
- LinearExpr.newBuilder().add(endVar).add(2),
- "interval");
+ IntervalVar intervalVar = model.newIntervalVar(
+ startVar, LinearExpr.constant(10), LinearExpr.newBuilder().add(endVar).add(2), "interval");
System.out.println(intervalVar);
// If the size is fixed, a simpler version uses the start expression and the size.
@@ -237,36 +232,37 @@ understand these presence literals, and correctly ignore inactive intervals.
### Python code
```python
-"""Code sample to demonstrates how to build an optional interval."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def OptionalIntervalSampleSat():
- """Showcases how to build optional interval variables."""
- model = cp_model.CpModel()
- horizon = 100
+ """Showcases how to build optional interval variables."""
+ model = cp_model.CpModel()
+ horizon = 100
- # An interval can be created from three affine expressions.
- start_var = model.NewIntVar(0, horizon, 'start')
- duration = 10 # Python cp/sat code accept integer variables or constants.
- end_var = model.NewIntVar(0, horizon, 'end')
- presence_var = model.NewBoolVar('presence')
- interval_var = model.NewOptionalIntervalVar(start_var, duration, end_var + 2,
- presence_var, 'interval')
+ # An interval can be created from three affine expressions.
+ start_var = model.NewIntVar(0, horizon, 'start')
+ duration = 10 # Python cp/sat code accept integer variables or constants.
+ end_var = model.NewIntVar(0, horizon, 'end')
+ presence_var = model.NewBoolVar('presence')
+ interval_var = model.NewOptionalIntervalVar(start_var, duration,
+ end_var + 2, presence_var,
+ 'interval')
- print(f'interval = {repr(interval_var)}')
+ print(f'interval = {repr(interval_var)}')
- # If the size is fixed, a simpler version uses the start expression and the
- # size.
- fixed_size_interval_var = model.NewOptionalFixedSizeIntervalVar(
- start_var, 10, presence_var, 'fixed_size_interval_var')
- print(f'fixed_size_interval_var = {repr(fixed_size_interval_var)}')
+ # If the size is fixed, a simpler version uses the start expression and the
+ # size.
+ fixed_size_interval_var = model.NewOptionalFixedSizeIntervalVar(
+ start_var, 10, presence_var, 'fixed_size_interval_var')
+ print(f'fixed_size_interval_var = {repr(fixed_size_interval_var)}')
- # A fixed interval can be created using the same API.
- fixed_interval = model.NewOptionalFixedSizeIntervalVar(
- 5, 10, presence_var, 'fixed_interval')
- print(f'fixed_interval = {repr(fixed_interval)}')
+ # A fixed interval can be created using the same API.
+ fixed_interval = model.NewOptionalFixedSizeIntervalVar(
+ 5, 10, presence_var, 'fixed_interval')
+ print(f'fixed_interval = {repr(fixed_interval)}')
OptionalIntervalSampleSat()
@@ -350,13 +346,8 @@ public class OptionalIntervalSampleSat {
IntVar startVar = model.newIntVar(0, horizon, "start");
IntVar endVar = model.newIntVar(0, horizon, "end");
Literal presence = model.newBoolVar("presence");
- IntervalVar intervalVar =
- model.newOptionalIntervalVar(
- startVar,
- LinearExpr.constant(10),
- LinearExpr.newBuilder().add(endVar).add(2),
- presence,
- "interval");
+ IntervalVar intervalVar = model.newOptionalIntervalVar(startVar, LinearExpr.constant(10),
+ LinearExpr.newBuilder().add(endVar).add(2), presence, "interval");
System.out.println(intervalVar);
// If the size is fixed, a simpler version uses the start expression, the size and the literal.
@@ -416,58 +407,59 @@ weekends, making the final day as early as possible.
### Python code
```python
-"""Code sample to demonstrate how to build a NoOverlap constraint."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
def NoOverlapSampleSat():
- """No overlap sample with fixed activities."""
- model = cp_model.CpModel()
- horizon = 21 # 3 weeks.
+ """No overlap sample with fixed activities."""
+ model = cp_model.CpModel()
+ horizon = 21 # 3 weeks.
- # Task 0, duration 2.
- start_0 = model.NewIntVar(0, horizon, 'start_0')
- duration_0 = 2 # Python cp/sat code accepts integer variables or constants.
- end_0 = model.NewIntVar(0, horizon, 'end_0')
- task_0 = model.NewIntervalVar(start_0, duration_0, end_0, 'task_0')
- # Task 1, duration 4.
- start_1 = model.NewIntVar(0, horizon, 'start_1')
- duration_1 = 4 # Python cp/sat code accepts integer variables or constants.
- end_1 = model.NewIntVar(0, horizon, 'end_1')
- task_1 = model.NewIntervalVar(start_1, duration_1, end_1, 'task_1')
+ # Task 0, duration 2.
+ start_0 = model.NewIntVar(0, horizon, 'start_0')
+ duration_0 = 2 # Python cp/sat code accepts integer variables or constants.
+ end_0 = model.NewIntVar(0, horizon, 'end_0')
+ task_0 = model.NewIntervalVar(start_0, duration_0, end_0, 'task_0')
+ # Task 1, duration 4.
+ start_1 = model.NewIntVar(0, horizon, 'start_1')
+ duration_1 = 4 # Python cp/sat code accepts integer variables or constants.
+ end_1 = model.NewIntVar(0, horizon, 'end_1')
+ task_1 = model.NewIntervalVar(start_1, duration_1, end_1, 'task_1')
- # Task 2, duration 3.
- start_2 = model.NewIntVar(0, horizon, 'start_2')
- duration_2 = 3 # Python cp/sat code accepts integer variables or constants.
- end_2 = model.NewIntVar(0, horizon, 'end_2')
- task_2 = model.NewIntervalVar(start_2, duration_2, end_2, 'task_2')
+ # Task 2, duration 3.
+ start_2 = model.NewIntVar(0, horizon, 'start_2')
+ duration_2 = 3 # Python cp/sat code accepts integer variables or constants.
+ end_2 = model.NewIntVar(0, horizon, 'end_2')
+ task_2 = model.NewIntervalVar(start_2, duration_2, end_2, 'task_2')
- # Weekends.
- weekend_0 = model.NewIntervalVar(5, 2, 7, 'weekend_0')
- weekend_1 = model.NewIntervalVar(12, 2, 14, 'weekend_1')
- weekend_2 = model.NewIntervalVar(19, 2, 21, 'weekend_2')
+ # Weekends.
+ weekend_0 = model.NewIntervalVar(5, 2, 7, 'weekend_0')
+ weekend_1 = model.NewIntervalVar(12, 2, 14, 'weekend_1')
+ weekend_2 = model.NewIntervalVar(19, 2, 21, 'weekend_2')
- # No Overlap constraint.
- model.AddNoOverlap([task_0, task_1, task_2, weekend_0, weekend_1, weekend_2])
+ # No Overlap constraint.
+ model.AddNoOverlap(
+ [task_0, task_1, task_2, weekend_0, weekend_1, weekend_2])
- # Makespan objective.
- obj = model.NewIntVar(0, horizon, 'makespan')
- model.AddMaxEquality(obj, [end_0, end_1, end_2])
- model.Minimize(obj)
+ # Makespan objective.
+ obj = model.NewIntVar(0, horizon, 'makespan')
+ model.AddMaxEquality(obj, [end_0, end_1, end_2])
+ model.Minimize(obj)
- # Solve model.
- solver = cp_model.CpSolver()
- status = solver.Solve(model)
+ # Solve model.
+ solver = cp_model.CpSolver()
+ status = solver.Solve(model)
- if status == cp_model.OPTIMAL:
- # Print out makespan and the start times for all tasks.
- print('Optimal Schedule Length: %i' % solver.ObjectiveValue())
- print('Task 0 starts at %i' % solver.Value(start_0))
- print('Task 1 starts at %i' % solver.Value(start_1))
- print('Task 2 starts at %i' % solver.Value(start_2))
- else:
- print('Solver exited with nonoptimal status: %i' % status)
+ if status == cp_model.OPTIMAL:
+ # Print out makespan and the start times for all tasks.
+ print('Optimal Schedule Length: %i' % solver.ObjectiveValue())
+ print('Task 0 starts at %i' % solver.Value(start_0))
+ print('Task 1 starts at %i' % solver.Value(start_1))
+ print('Task 2 starts at %i' % solver.Value(start_2))
+ else:
+ print('Solver exited with nonoptimal status: %i' % status)
NoOverlapSampleSat()
@@ -480,8 +472,8 @@ NoOverlapSampleSat()
#include
-#include "ortools/base/logging.h"
#include "absl/types/span.h"
+#include "ortools/base/logging.h"
#include "ortools/sat/cp_model.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
@@ -563,9 +555,9 @@ int main() {
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
+import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.IntVar;
import com.google.ortools.sat.IntervalVar;
import com.google.ortools.sat.LinearExpr;
@@ -608,13 +600,10 @@ public class NoOverlapSampleSat {
// Makespan objective.
IntVar obj = model.newIntVar(0, horizon, "makespan");
- model.addMaxEquality(
- obj,
- new LinearExpr[] {
- LinearExpr.newBuilder().add(start0).add(duration0).build(),
- LinearExpr.newBuilder().add(start1).add(duration1).build(),
- LinearExpr.newBuilder().add(start2).add(duration2).build()
- });
+ model.addMaxEquality(obj,
+ new LinearExpr[] {LinearExpr.newBuilder().add(start0).add(duration0).build(),
+ LinearExpr.newBuilder().add(start1).add(duration1).build(),
+ LinearExpr.newBuilder().add(start2).add(duration2).build()});
model.minimize(obj);
// Creates a solver and solves the model.
@@ -718,14 +707,13 @@ number of other intervals that precede it.
### Python code
```python
-"""Code sample to demonstrates how to rank intervals."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
-
def RankTasks(model, starts, presences, ranks):
- """This method adds constraints and variables to links tasks and ranks.
+ """This method adds constraints and variables to links tasks and ranks.
This method assumes that all starts are disjoint, meaning that all tasks have
a strictly positive duration, and they appear in the same NoOverlap
@@ -738,118 +726,124 @@ def RankTasks(model, starts, presences, ranks):
ranks: The array of rank variables of all tasks.
"""
- num_tasks = len(starts)
- all_tasks = range(num_tasks)
+ num_tasks = len(starts)
+ all_tasks = range(num_tasks)
- # Creates precedence variables between pairs of intervals.
- precedences = {}
- for i in all_tasks:
- for j in all_tasks:
- if i == j:
- precedences[(i, j)] = presences[i]
- else:
- prec = model.NewBoolVar('%i before %i' % (i, j))
- precedences[(i, j)] = prec
- model.Add(starts[i] < starts[j]).OnlyEnforceIf(prec)
+ # Creates precedence variables between pairs of intervals.
+ precedences = {}
+ for i in all_tasks:
+ for j in all_tasks:
+ if i == j:
+ precedences[(i, j)] = presences[i]
+ else:
+ prec = model.NewBoolVar('%i before %i' % (i, j))
+ precedences[(i, j)] = prec
+ model.Add(starts[i] < starts[j]).OnlyEnforceIf(prec)
- # Treats optional intervals.
- for i in range(num_tasks - 1):
- for j in range(i + 1, num_tasks):
- tmp_array = [precedences[(i, j)], precedences[(j, i)]]
- if not cp_model.ObjectIsATrueLiteral(presences[i]):
- tmp_array.append(presences[i].Not())
- # Makes sure that if i is not performed, all precedences are false.
- model.AddImplication(presences[i].Not(), precedences[(i, j)].Not())
- model.AddImplication(presences[i].Not(), precedences[(j, i)].Not())
- if not cp_model.ObjectIsATrueLiteral(presences[j]):
- tmp_array.append(presences[j].Not())
- # Makes sure that if j is not performed, all precedences are false.
- model.AddImplication(presences[j].Not(), precedences[(i, j)].Not())
- model.AddImplication(presences[j].Not(), precedences[(j, i)].Not())
- # The following bool_or will enforce that for any two intervals:
- # i precedes j or j precedes i or at least one interval is not
- # performed.
- model.AddBoolOr(tmp_array)
- # Redundant constraint: it propagates early that at most one precedence
- # is true.
- model.AddImplication(precedences[(i, j)], precedences[(j, i)].Not())
- model.AddImplication(precedences[(j, i)], precedences[(i, j)].Not())
+ # Treats optional intervals.
+ for i in range(num_tasks - 1):
+ for j in range(i + 1, num_tasks):
+ tmp_array = [precedences[(i, j)], precedences[(j, i)]]
+ if not cp_model.ObjectIsATrueLiteral(presences[i]):
+ tmp_array.append(presences[i].Not())
+ # Makes sure that if i is not performed, all precedences are false.
+ model.AddImplication(presences[i].Not(),
+ precedences[(i, j)].Not())
+ model.AddImplication(presences[i].Not(),
+ precedences[(j, i)].Not())
+ if not cp_model.ObjectIsATrueLiteral(presences[j]):
+ tmp_array.append(presences[j].Not())
+ # Makes sure that if j is not performed, all precedences are false.
+ model.AddImplication(presences[j].Not(),
+ precedences[(i, j)].Not())
+ model.AddImplication(presences[j].Not(),
+ precedences[(j, i)].Not())
+ # The following bool_or will enforce that for any two intervals:
+ # i precedes j or j precedes i or at least one interval is not
+ # performed.
+ model.AddBoolOr(tmp_array)
+ # Redundant constraint: it propagates early that at most one precedence
+ # is true.
+ model.AddImplication(precedences[(i, j)], precedences[(j, i)].Not())
+ model.AddImplication(precedences[(j, i)], precedences[(i, j)].Not())
- # Links precedences and ranks.
- for i in all_tasks:
- model.Add(ranks[i] == sum(precedences[(j, i)] for j in all_tasks) - 1)
+ # Links precedences and ranks.
+ for i in all_tasks:
+ model.Add(ranks[i] == sum(precedences[(j, i)] for j in all_tasks) - 1)
def RankingSampleSat():
- """Ranks tasks in a NoOverlap constraint."""
+ """Ranks tasks in a NoOverlap constraint."""
- model = cp_model.CpModel()
- horizon = 100
- num_tasks = 4
- all_tasks = range(num_tasks)
+ model = cp_model.CpModel()
+ horizon = 100
+ num_tasks = 4
+ all_tasks = range(num_tasks)
- starts = []
- ends = []
- intervals = []
- presences = []
- ranks = []
+ starts = []
+ ends = []
+ intervals = []
+ presences = []
+ ranks = []
- # Creates intervals, half of them are optional.
- for t in all_tasks:
- start = model.NewIntVar(0, horizon, 'start_%i' % t)
- duration = t + 1
- end = model.NewIntVar(0, horizon, 'end_%i' % t)
- if t < num_tasks // 2:
- interval = model.NewIntervalVar(start, duration, end, 'interval_%i' % t)
- presence = True
- else:
- presence = model.NewBoolVar('presence_%i' % t)
- interval = model.NewOptionalIntervalVar(start, duration, end, presence,
- 'o_interval_%i' % t)
- starts.append(start)
- ends.append(end)
- intervals.append(interval)
- presences.append(presence)
-
- # Ranks = -1 if and only if the tasks is not performed.
- ranks.append(model.NewIntVar(-1, num_tasks - 1, 'rank_%i' % t))
-
- # Adds NoOverlap constraint.
- model.AddNoOverlap(intervals)
-
- # Adds ranking constraint.
- RankTasks(model, starts, presences, ranks)
-
- # Adds a constraint on ranks.
- model.Add(ranks[0] < ranks[1])
-
- # Creates makespan variable.
- makespan = model.NewIntVar(0, horizon, 'makespan')
- for t in all_tasks:
- model.Add(ends[t] <= makespan).OnlyEnforceIf(presences[t])
-
- # Minimizes makespan - fixed gain per tasks performed.
- # As the fixed cost is less that the duration of the last interval,
- # the solver will not perform the last interval.
- model.Minimize(2 * makespan - 7 * sum(presences[t] for t in all_tasks))
-
- # Solves the model model.
- solver = cp_model.CpSolver()
- status = solver.Solve(model)
-
- if status == cp_model.OPTIMAL:
- # Prints out the makespan and the start times and ranks of all tasks.
- print('Optimal cost: %i' % solver.ObjectiveValue())
- print('Makespan: %i' % solver.Value(makespan))
+ # Creates intervals, half of them are optional.
for t in all_tasks:
- if solver.Value(presences[t]):
- print('Task %i starts at %i with rank %i' % (t, solver.Value(starts[t]),
- solver.Value(ranks[t])))
- else:
- print('Task %i in not performed and ranked at %i' %
- (t, solver.Value(ranks[t])))
- else:
- print('Solver exited with nonoptimal status: %i' % status)
+ start = model.NewIntVar(0, horizon, 'start_%i' % t)
+ duration = t + 1
+ end = model.NewIntVar(0, horizon, 'end_%i' % t)
+ if t < num_tasks // 2:
+ interval = model.NewIntervalVar(start, duration, end,
+ 'interval_%i' % t)
+ presence = True
+ else:
+ presence = model.NewBoolVar('presence_%i' % t)
+ interval = model.NewOptionalIntervalVar(start, duration, end,
+ presence,
+ 'o_interval_%i' % t)
+ starts.append(start)
+ ends.append(end)
+ intervals.append(interval)
+ presences.append(presence)
+
+ # Ranks = -1 if and only if the tasks is not performed.
+ ranks.append(model.NewIntVar(-1, num_tasks - 1, 'rank_%i' % t))
+
+ # Adds NoOverlap constraint.
+ model.AddNoOverlap(intervals)
+
+ # Adds ranking constraint.
+ RankTasks(model, starts, presences, ranks)
+
+ # Adds a constraint on ranks.
+ model.Add(ranks[0] < ranks[1])
+
+ # Creates makespan variable.
+ makespan = model.NewIntVar(0, horizon, 'makespan')
+ for t in all_tasks:
+ model.Add(ends[t] <= makespan).OnlyEnforceIf(presences[t])
+
+ # Minimizes makespan - fixed gain per tasks performed.
+ # As the fixed cost is less that the duration of the last interval,
+ # the solver will not perform the last interval.
+ model.Minimize(2 * makespan - 7 * sum(presences[t] for t in all_tasks))
+
+ # Solves the model model.
+ solver = cp_model.CpSolver()
+ status = solver.Solve(model)
+
+ if status == cp_model.OPTIMAL:
+ # Prints out the makespan and the start times and ranks of all tasks.
+ print('Optimal cost: %i' % solver.ObjectiveValue())
+ print('Makespan: %i' % solver.Value(makespan))
+ for t in all_tasks:
+ if solver.Value(presences[t]):
+ print('Task %i starts at %i with rank %i' %
+ (t, solver.Value(starts[t]), solver.Value(ranks[t])))
+ else:
+ print('Task %i in not performed and ranked at %i' %
+ (t, solver.Value(ranks[t])))
+ else:
+ print('Solver exited with nonoptimal status: %i' % status)
RankingSampleSat()
@@ -863,8 +857,8 @@ RankingSampleSat()
#include
-#include "ortools/base/logging.h"
#include "absl/types/span.h"
+#include "ortools/base/logging.h"
#include "ortools/sat/cp_model.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
@@ -1015,10 +1009,10 @@ int main() {
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.BoolVar;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
+import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.IntVar;
import com.google.ortools.sat.IntervalVar;
import com.google.ortools.sat.LinearExpr;
@@ -1114,15 +1108,13 @@ public class RankingSampleSat {
int duration = t + 1;
ends[t] = model.newIntVar(0, horizon, "end_" + t);
if (t < numTasks / 2) {
- intervals[t] =
- model.newIntervalVar(
- starts[t], LinearExpr.constant(duration), ends[t], "interval_" + t);
+ intervals[t] = model.newIntervalVar(
+ starts[t], LinearExpr.constant(duration), ends[t], "interval_" + t);
presences[t] = trueLiteral;
} else {
presences[t] = model.newBoolVar("presence_" + t);
- intervals[t] =
- model.newOptionalIntervalVar(
- starts[t], LinearExpr.constant(duration), ends[t], presences[t], "o_interval_" + t);
+ intervals[t] = model.newOptionalIntervalVar(
+ starts[t], LinearExpr.constant(duration), ends[t], presences[t], "o_interval_" + t);
}
// The rank will be -1 iff the task is not performed.
@@ -1166,9 +1158,8 @@ public class RankingSampleSat {
System.out.println("Makespan: " + solver.value(makespan));
for (int t = 0; t < numTasks; ++t) {
if (solver.booleanValue(presences[t])) {
- System.out.printf(
- "Task %d starts at %d with rank %d%n",
- t, solver.value(starts[t]), solver.value(ranks[t]));
+ System.out.printf("Task %d starts at %d with rank %d%n", t, solver.value(starts[t]),
+ solver.value(ranks[t]));
} else {
System.out.printf(
"Task %d in not performed and ranked at %d%n", t, solver.value(ranks[t]));
@@ -1366,71 +1357,71 @@ The following code displays:
### Python code
```python
-"""Code sample to demonstrate how an interval can span across a break."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
- """Print intermediate solutions."""
+ """Print intermediate solutions."""
- def __init__(self, variables):
- cp_model.CpSolverSolutionCallback.__init__(self)
- self.__variables = variables
- self.__solution_count = 0
+ def __init__(self, variables):
+ cp_model.CpSolverSolutionCallback.__init__(self)
+ self.__variables = variables
+ self.__solution_count = 0
- def on_solution_callback(self):
- self.__solution_count += 1
- for v in self.__variables:
- print('%s=%i' % (v, self.Value(v)), end=' ')
- print()
+ def on_solution_callback(self):
+ self.__solution_count += 1
+ for v in self.__variables:
+ print('%s=%i' % (v, self.Value(v)), end=' ')
+ print()
- def solution_count(self):
- return self.__solution_count
+ def solution_count(self):
+ return self.__solution_count
def SchedulingWithCalendarSampleSat():
- """Interval spanning across a lunch break."""
- model = cp_model.CpModel()
+ """Interval spanning across a lunch break."""
+ model = cp_model.CpModel()
- # The data is the following:
- # Work starts at 8h, ends at 18h, with a lunch break between 13h and 14h.
- # We need to schedule a task that needs 3 hours of processing time.
- # Total duration can be 3 or 4 (if it spans the lunch break).
- #
- # Because the duration is at least 3 hours, work cannot start after 15h.
- # Because of the break, work cannot start at 13h.
+ # The data is the following:
+ # Work starts at 8h, ends at 18h, with a lunch break between 13h and 14h.
+ # We need to schedule a task that needs 3 hours of processing time.
+ # Total duration can be 3 or 4 (if it spans the lunch break).
+ #
+ # Because the duration is at least 3 hours, work cannot start after 15h.
+ # Because of the break, work cannot start at 13h.
- start = model.NewIntVarFromDomain(
- cp_model.Domain.FromIntervals([(8, 12), (14, 15)]), 'start')
- duration = model.NewIntVar(3, 4, 'duration')
- end = model.NewIntVar(8, 18, 'end')
- unused_interval = model.NewIntervalVar(start, duration, end, 'interval')
+ start = model.NewIntVarFromDomain(
+ cp_model.Domain.FromIntervals([(8, 12), (14, 15)]), 'start')
+ duration = model.NewIntVar(3, 4, 'duration')
+ end = model.NewIntVar(8, 18, 'end')
+ unused_interval = model.NewIntervalVar(start, duration, end, 'interval')
- # We have 2 states (spanning across lunch or not)
- across = model.NewBoolVar('across')
- non_spanning_hours = cp_model.Domain.FromValues([8, 9, 10, 14, 15])
- model.AddLinearExpressionInDomain(start, non_spanning_hours).OnlyEnforceIf(
- across.Not())
- model.AddLinearConstraint(start, 11, 12).OnlyEnforceIf(across)
- model.Add(duration == 3).OnlyEnforceIf(across.Not())
- model.Add(duration == 4).OnlyEnforceIf(across)
+ # We have 2 states (spanning across lunch or not)
+ across = model.NewBoolVar('across')
+ non_spanning_hours = cp_model.Domain.FromValues([8, 9, 10, 14, 15])
+ model.AddLinearExpressionInDomain(start, non_spanning_hours).OnlyEnforceIf(
+ across.Not())
+ model.AddLinearConstraint(start, 11, 12).OnlyEnforceIf(across)
+ model.Add(duration == 3).OnlyEnforceIf(across.Not())
+ model.Add(duration == 4).OnlyEnforceIf(across)
- # Search for x values in increasing order.
- model.AddDecisionStrategy([start], cp_model.CHOOSE_FIRST,
- cp_model.SELECT_MIN_VALUE)
+ # Search for x values in increasing order.
+ model.AddDecisionStrategy([start], cp_model.CHOOSE_FIRST,
+ cp_model.SELECT_MIN_VALUE)
- # Create a solver and solve with a fixed search.
- solver = cp_model.CpSolver()
+ # Create a solver and solve with a fixed search.
+ solver = cp_model.CpSolver()
- # Force the solver to follow the decision strategy exactly.
- solver.parameters.search_branching = cp_model.FIXED_SEARCH
- # Enumerate all solutions.
- solver.parameters.enumerate_all_solutions = True
+ # Force the solver to follow the decision strategy exactly.
+ solver.parameters.search_branching = cp_model.FIXED_SEARCH
+ # Enumerate all solutions.
+ solver.parameters.enumerate_all_solutions = True
- # Search and print all solutions.
- solution_printer = VarArraySolutionPrinter([start, duration, across])
- solver.Solve(model, solution_printer)
+ # Search and print all solutions.
+ solution_printer = VarArraySolutionPrinter([start, duration, across])
+ solver.Solve(model, solution_printer)
SchedulingWithCalendarSampleSat()
@@ -1472,86 +1463,86 @@ start_a=1 start_b=5 a_overlaps_b=0
### Python code
```python
-"""Code sample to demonstrates how to detect if two intervals overlap."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
- """Print intermediate solutions."""
+ """Print intermediate solutions."""
- def __init__(self, variables):
- cp_model.CpSolverSolutionCallback.__init__(self)
- self.__variables = variables
- self.__solution_count = 0
+ def __init__(self, variables):
+ cp_model.CpSolverSolutionCallback.__init__(self)
+ self.__variables = variables
+ self.__solution_count = 0
- def on_solution_callback(self):
- self.__solution_count += 1
- for v in self.__variables:
- print('%s=%i' % (v, self.Value(v)), end=' ')
- print()
+ def on_solution_callback(self):
+ self.__solution_count += 1
+ for v in self.__variables:
+ print('%s=%i' % (v, self.Value(v)), end=' ')
+ print()
- def solution_count(self):
- return self.__solution_count
+ def solution_count(self):
+ return self.__solution_count
def OverlappingIntervals():
- """Create the overlapping Boolean variables and enumerate all states."""
- model = cp_model.CpModel()
+ """Create the overlapping Boolean variables and enumerate all states."""
+ model = cp_model.CpModel()
- horizon = 7
+ horizon = 7
- # First interval.
- start_var_a = model.NewIntVar(0, horizon, 'start_a')
- duration_a = 3
- end_var_a = model.NewIntVar(0, horizon, 'end_a')
- unused_interval_var_a = model.NewIntervalVar(start_var_a, duration_a,
- end_var_a, 'interval_a')
+ # First interval.
+ start_var_a = model.NewIntVar(0, horizon, 'start_a')
+ duration_a = 3
+ end_var_a = model.NewIntVar(0, horizon, 'end_a')
+ unused_interval_var_a = model.NewIntervalVar(start_var_a, duration_a,
+ end_var_a, 'interval_a')
- # Second interval.
- start_var_b = model.NewIntVar(0, horizon, 'start_b')
- duration_b = 2
- end_var_b = model.NewIntVar(0, horizon, 'end_b')
- unused_interval_var_b = model.NewIntervalVar(start_var_b, duration_b,
- end_var_b, 'interval_b')
+ # Second interval.
+ start_var_b = model.NewIntVar(0, horizon, 'start_b')
+ duration_b = 2
+ end_var_b = model.NewIntVar(0, horizon, 'end_b')
+ unused_interval_var_b = model.NewIntervalVar(start_var_b, duration_b,
+ end_var_b, 'interval_b')
- # a_after_b Boolean variable.
- a_after_b = model.NewBoolVar('a_after_b')
- model.Add(start_var_a >= end_var_b).OnlyEnforceIf(a_after_b)
- model.Add(start_var_a < end_var_b).OnlyEnforceIf(a_after_b.Not())
+ # a_after_b Boolean variable.
+ a_after_b = model.NewBoolVar('a_after_b')
+ model.Add(start_var_a >= end_var_b).OnlyEnforceIf(a_after_b)
+ model.Add(start_var_a < end_var_b).OnlyEnforceIf(a_after_b.Not())
- # b_after_a Boolean variable.
- b_after_a = model.NewBoolVar('b_after_a')
- model.Add(start_var_b >= end_var_a).OnlyEnforceIf(b_after_a)
- model.Add(start_var_b < end_var_a).OnlyEnforceIf(b_after_a.Not())
+ # b_after_a Boolean variable.
+ b_after_a = model.NewBoolVar('b_after_a')
+ model.Add(start_var_b >= end_var_a).OnlyEnforceIf(b_after_a)
+ model.Add(start_var_b < end_var_a).OnlyEnforceIf(b_after_a.Not())
- # Result Boolean variable.
- a_overlaps_b = model.NewBoolVar('a_overlaps_b')
+ # Result Boolean variable.
+ a_overlaps_b = model.NewBoolVar('a_overlaps_b')
- # Option a: using only clauses
- model.AddBoolOr(a_after_b, b_after_a, a_overlaps_b)
- model.AddImplication(a_after_b, a_overlaps_b.Not())
- model.AddImplication(b_after_a, a_overlaps_b.Not())
+ # Option a: using only clauses
+ model.AddBoolOr(a_after_b, b_after_a, a_overlaps_b)
+ model.AddImplication(a_after_b, a_overlaps_b.Not())
+ model.AddImplication(b_after_a, a_overlaps_b.Not())
- # Option b: using an exactly one constraint.
- # model.AddExactlyOne(a_after_b, b_after_a, a_overlaps_b)
+ # Option b: using an exactly one constraint.
+ # model.AddExactlyOne(a_after_b, b_after_a, a_overlaps_b)
- # Search for start values in increasing order for the two intervals.
- model.AddDecisionStrategy([start_var_a, start_var_b], cp_model.CHOOSE_FIRST,
- cp_model.SELECT_MIN_VALUE)
+ # Search for start values in increasing order for the two intervals.
+ model.AddDecisionStrategy([start_var_a, start_var_b], cp_model.CHOOSE_FIRST,
+ cp_model.SELECT_MIN_VALUE)
- # Create a solver and solve with a fixed search.
- solver = cp_model.CpSolver()
+ # Create a solver and solve with a fixed search.
+ solver = cp_model.CpSolver()
- # Force the solver to follow the decision strategy exactly.
- solver.parameters.search_branching = cp_model.FIXED_SEARCH
- # Enumerate all solutions.
- solver.parameters.enumerate_all_solutions = True
+ # Force the solver to follow the decision strategy exactly.
+ solver.parameters.search_branching = cp_model.FIXED_SEARCH
+ # Enumerate all solutions.
+ solver.parameters.enumerate_all_solutions = True
- # Search and print out all solutions.
- solution_printer = VarArraySolutionPrinter(
- [start_var_a, start_var_b, a_overlaps_b])
- solver.Solve(model, solution_printer)
+ # Search and print out all solutions.
+ solution_printer = VarArraySolutionPrinter(
+ [start_var_a, start_var_b, a_overlaps_b])
+ solver.Solve(model, solution_printer)
OverlappingIntervals()
diff --git a/ortools/sat/docs/solver.md b/ortools/sat/docs/solver.md
index b17bc85c1c..36e50b376d 100644
--- a/ortools/sat/docs/solver.md
+++ b/ortools/sat/docs/solver.md
@@ -40,35 +40,36 @@ solver. The most useful one is the time limit.
### Specifying the time limit in Python
```python
+#!/usr/bin/env python3
"""Solves a problem with a time limit."""
from ortools.sat.python import cp_model
def SolveWithTimeLimitSampleSat():
- """Minimal CP-SAT example to showcase calling the solver."""
- # Creates the model.
- model = cp_model.CpModel()
- # Creates the variables.
- num_vals = 3
- x = model.NewIntVar(0, num_vals - 1, 'x')
- y = model.NewIntVar(0, num_vals - 1, 'y')
- z = model.NewIntVar(0, num_vals - 1, 'z')
- # Adds an all-different constraint.
- model.Add(x != y)
+ """Minimal CP-SAT example to showcase calling the solver."""
+ # Creates the model.
+ model = cp_model.CpModel()
+ # Creates the variables.
+ num_vals = 3
+ x = model.NewIntVar(0, num_vals - 1, 'x')
+ y = model.NewIntVar(0, num_vals - 1, 'y')
+ z = model.NewIntVar(0, num_vals - 1, 'z')
+ # Adds an all-different constraint.
+ model.Add(x != y)
- # Creates a solver and solves the model.
- solver = cp_model.CpSolver()
+ # Creates a solver and solves the model.
+ solver = cp_model.CpSolver()
- # Sets a time limit of 10 seconds.
- solver.parameters.max_time_in_seconds = 10.0
+ # Sets a time limit of 10 seconds.
+ solver.parameters.max_time_in_seconds = 10.0
- status = solver.Solve(model)
+ status = solver.Solve(model)
- if status == cp_model.OPTIMAL:
- print('x = %i' % solver.Value(x))
- print('y = %i' % solver.Value(y))
- print('z = %i' % solver.Value(z))
+ if status == cp_model.OPTIMAL:
+ print('x = %i' % solver.Value(x))
+ print('y = %i' % solver.Value(y))
+ print('z = %i' % solver.Value(z))
SolveWithTimeLimitSampleSat()
@@ -135,9 +136,9 @@ int main() {
package com.google.ortools.sat.samples;
import com.google.ortools.Loader;
-import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.CpModel;
import com.google.ortools.sat.CpSolver;
+import com.google.ortools.sat.CpSolverStatus;
import com.google.ortools.sat.IntVar;
/** Solves a problem with a time limit. */
@@ -210,7 +211,6 @@ public class SolveWithTimeLimitSampleSat
}
}
}
-
```
## Printing intermediate solutions
@@ -223,55 +223,55 @@ The exact implementation depends on the target language.
### Python code
```python
-"""Solves an optimization problem and displays all intermediate solutions."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
# You need to subclass the cp_model.CpSolverSolutionCallback class.
class VarArrayAndObjectiveSolutionPrinter(cp_model.CpSolverSolutionCallback):
- """Print intermediate solutions."""
+ """Print intermediate solutions."""
- def __init__(self, variables):
- cp_model.CpSolverSolutionCallback.__init__(self)
- self.__variables = variables
- self.__solution_count = 0
+ def __init__(self, variables):
+ cp_model.CpSolverSolutionCallback.__init__(self)
+ self.__variables = variables
+ self.__solution_count = 0
- def on_solution_callback(self):
- print('Solution %i' % self.__solution_count)
- print(' objective value = %i' % self.ObjectiveValue())
- for v in self.__variables:
- print(' %s = %i' % (v, self.Value(v)), end=' ')
- print()
- self.__solution_count += 1
+ def on_solution_callback(self):
+ print('Solution %i' % self.__solution_count)
+ print(' objective value = %i' % self.ObjectiveValue())
+ for v in self.__variables:
+ print(' %s = %i' % (v, self.Value(v)), end=' ')
+ print()
+ self.__solution_count += 1
- def solution_count(self):
- return self.__solution_count
+ def solution_count(self):
+ return self.__solution_count
def SolveAndPrintIntermediateSolutionsSampleSat():
- """Showcases printing intermediate solutions found during search."""
- # Creates the model.
- model = cp_model.CpModel()
+ """Showcases printing intermediate solutions found during search."""
+ # Creates the model.
+ model = cp_model.CpModel()
- # Creates the variables.
- num_vals = 3
- x = model.NewIntVar(0, num_vals - 1, 'x')
- y = model.NewIntVar(0, num_vals - 1, 'y')
- z = model.NewIntVar(0, num_vals - 1, 'z')
+ # Creates the variables.
+ num_vals = 3
+ x = model.NewIntVar(0, num_vals - 1, 'x')
+ y = model.NewIntVar(0, num_vals - 1, 'y')
+ z = model.NewIntVar(0, num_vals - 1, 'z')
- # Creates the constraints.
- model.Add(x != y)
+ # Creates the constraints.
+ model.Add(x != y)
- model.Maximize(x + 2 * y + 3 * z)
+ model.Maximize(x + 2 * y + 3 * z)
- # Creates a solver and solves.
- solver = cp_model.CpSolver()
- solution_printer = VarArrayAndObjectiveSolutionPrinter([x, y, z])
- status = solver.Solve(model, solution_printer)
+ # Creates a solver and solves.
+ solver = cp_model.CpSolver()
+ solution_printer = VarArrayAndObjectiveSolutionPrinter([x, y, z])
+ status = solver.Solve(model, solution_printer)
- print('Status = %s' % solver.StatusName(status))
- print('Number of solutions found: %i' % solution_printer.solution_count())
+ print('Status = %s' % solver.StatusName(status))
+ print('Number of solutions found: %i' % solution_printer.solution_count())
SolveAndPrintIntermediateSolutionsSampleSat()
@@ -483,53 +483,53 @@ To search for all solutions, use the Solve() method after setting the correct
parameter.
```python
-"""Code sample that solves a model and displays all solutions."""
+#!/usr/bin/env python3
from ortools.sat.python import cp_model
class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):
- """Print intermediate solutions."""
+ """Print intermediate solutions."""
- def __init__(self, variables):
- cp_model.CpSolverSolutionCallback.__init__(self)
- self.__variables = variables
- self.__solution_count = 0
+ def __init__(self, variables):
+ cp_model.CpSolverSolutionCallback.__init__(self)
+ self.__variables = variables
+ self.__solution_count = 0
- def on_solution_callback(self):
- self.__solution_count += 1
- for v in self.__variables:
- print('%s=%i' % (v, self.Value(v)), end=' ')
- print()
+ def on_solution_callback(self):
+ self.__solution_count += 1
+ for v in self.__variables:
+ print('%s=%i' % (v, self.Value(v)), end=' ')
+ print()
- def solution_count(self):
- return self.__solution_count
+ def solution_count(self):
+ return self.__solution_count
def SearchForAllSolutionsSampleSat():
- """Showcases calling the solver to search for all solutions."""
- # Creates the model.
- model = cp_model.CpModel()
+ """Showcases calling the solver to search for all solutions."""
+ # Creates the model.
+ model = cp_model.CpModel()
- # Creates the variables.
- num_vals = 3
- x = model.NewIntVar(0, num_vals - 1, 'x')
- y = model.NewIntVar(0, num_vals - 1, 'y')
- z = model.NewIntVar(0, num_vals - 1, 'z')
+ # Creates the variables.
+ num_vals = 3
+ x = model.NewIntVar(0, num_vals - 1, 'x')
+ y = model.NewIntVar(0, num_vals - 1, 'y')
+ z = model.NewIntVar(0, num_vals - 1, 'z')
- # Create the constraints.
- model.Add(x != y)
+ # Create the constraints.
+ model.Add(x != y)
- # Create a solver and solve.
- solver = cp_model.CpSolver()
- solution_printer = VarArraySolutionPrinter([x, y, z])
- # Enumerate all solutions.
- solver.parameters.enumerate_all_solutions = True
- # Solve.
- status = solver.Solve(model, solution_printer)
+ # Create a solver and solve.
+ solver = cp_model.CpSolver()
+ solution_printer = VarArraySolutionPrinter([x, y, z])
+ # Enumerate all solutions.
+ solver.parameters.enumerate_all_solutions = True
+ # Solve.
+ status = solver.Solve(model, solution_printer)
- print('Status = %s' % solver.StatusName(status))
- print('Number of solutions found: %i' % solution_printer.solution_count())
+ print('Status = %s' % solver.StatusName(status))
+ print('Number of solutions found: %i' % solution_printer.solution_count())
SearchForAllSolutionsSampleSat()
@@ -738,53 +738,54 @@ You can stop the search by calling StopSearch() inside of
CpSolverSolutionCallback.OnSolutionCallback().
```python
+#!/usr/bin/env python3
"""Code sample that solves a model and displays a small number of solutions."""
from ortools.sat.python import cp_model
class VarArraySolutionPrinterWithLimit(cp_model.CpSolverSolutionCallback):
- """Print intermediate solutions."""
+ """Print intermediate solutions."""
- def __init__(self, variables, limit):
- cp_model.CpSolverSolutionCallback.__init__(self)
- self.__variables = variables
- self.__solution_count = 0
- self.__solution_limit = limit
+ def __init__(self, variables, limit):
+ cp_model.CpSolverSolutionCallback.__init__(self)
+ self.__variables = variables
+ self.__solution_count = 0
+ self.__solution_limit = limit
- def on_solution_callback(self):
- self.__solution_count += 1
- for v in self.__variables:
- print('%s=%i' % (v, self.Value(v)), end=' ')
- print()
- if self.__solution_count >= self.__solution_limit:
- print('Stop search after %i solutions' % self.__solution_limit)
- self.StopSearch()
+ def on_solution_callback(self):
+ self.__solution_count += 1
+ for v in self.__variables:
+ print('%s=%i' % (v, self.Value(v)), end=' ')
+ print()
+ if self.__solution_count >= self.__solution_limit:
+ print('Stop search after %i solutions' % self.__solution_limit)
+ self.StopSearch()
- def solution_count(self):
- return self.__solution_count
+ def solution_count(self):
+ return self.__solution_count
def StopAfterNSolutionsSampleSat():
- """Showcases calling the solver to search for small number of solutions."""
- # Creates the model.
- model = cp_model.CpModel()
- # Creates the variables.
- num_vals = 3
- x = model.NewIntVar(0, num_vals - 1, 'x')
- y = model.NewIntVar(0, num_vals - 1, 'y')
- z = model.NewIntVar(0, num_vals - 1, 'z')
+ """Showcases calling the solver to search for small number of solutions."""
+ # Creates the model.
+ model = cp_model.CpModel()
+ # Creates the variables.
+ num_vals = 3
+ x = model.NewIntVar(0, num_vals - 1, 'x')
+ y = model.NewIntVar(0, num_vals - 1, 'y')
+ z = model.NewIntVar(0, num_vals - 1, 'z')
- # Create a solver and solve.
- solver = cp_model.CpSolver()
- solution_printer = VarArraySolutionPrinterWithLimit([x, y, z], 5)
- # Enumerate all solutions.
- solver.parameters.enumerate_all_solutions = True
- # Solve.
- status = solver.Solve(model, solution_printer)
- print('Status = %s' % solver.StatusName(status))
- print('Number of solutions found: %i' % solution_printer.solution_count())
- assert solution_printer.solution_count() == 5
+ # Create a solver and solve.
+ solver = cp_model.CpSolver()
+ solution_printer = VarArraySolutionPrinterWithLimit([x, y, z], 5)
+ # Enumerate all solutions.
+ solver.parameters.enumerate_all_solutions = True
+ # Solve.
+ status = solver.Solve(model, solution_printer)
+ print('Status = %s' % solver.StatusName(status))
+ print('Number of solutions found: %i' % solution_printer.solution_count())
+ assert solution_printer.solution_count() == 5
StopAfterNSolutionsSampleSat()
diff --git a/ortools/sat/drat_writer.cc b/ortools/sat/drat_writer.cc
index 25a4e76453..1d35261b11 100644
--- a/ortools/sat/drat_writer.cc
+++ b/ortools/sat/drat_writer.cc
@@ -19,6 +19,7 @@
#if !defined(__PORTABLE_PLATFORM__)
#include "ortools/base/file.h"
#include "ortools/base/helpers.h"
+#include "ortools/base/options.h"
#endif // !__PORTABLE_PLATFORM__
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
diff --git a/ortools/sat/sat_parameters.proto b/ortools/sat/sat_parameters.proto
index 586fb58572..b2ba2482f7 100644
--- a/ortools/sat/sat_parameters.proto
+++ b/ortools/sat/sat_parameters.proto
@@ -317,7 +317,7 @@ message SatParameters {
// Maximum number of conflicts allowed to solve a problem.
//
- // TODO(user,user): Maybe change the way the conflict limit is enforced?
+ // TODO(user): Maybe change the way the conflict limit is enforced?
// currently it is enforced on each independent internal SAT solve, rather
// than on the overall number of conflicts across all solves. So in the
// context of an optimization problem, this is not really usable directly by a
diff --git a/ortools/sat/synchronization.cc b/ortools/sat/synchronization.cc
index e5b472db50..74c0ee9bd1 100644
--- a/ortools/sat/synchronization.cc
+++ b/ortools/sat/synchronization.cc
@@ -29,6 +29,7 @@
#include "ortools/base/timer.h"
#if !defined(__PORTABLE_PLATFORM__)
#include "ortools/base/helpers.h"
+#include "ortools/base/options.h"
#endif // __PORTABLE_PLATFORM__
#include "absl/container/btree_map.h"
#include "absl/container/flat_hash_map.h"
diff --git a/ortools/sat/timetable_edgefinding.cc b/ortools/sat/timetable_edgefinding.cc
index fe6bb40306..11eda56ac3 100644
--- a/ortools/sat/timetable_edgefinding.cc
+++ b/ortools/sat/timetable_edgefinding.cc
@@ -298,7 +298,7 @@ bool TimeTableEdgeFinding::TimeTableEdgeFindingPass() {
// Enough energy to schedule max_task at its minimum start time?
//
- // TODO(user, fdid): In case of alternatives, for each fixed
+ // TODO(user): In case of alternatives, for each fixed
// size/demand pair, we can compute a new_start and use the min of them.
if (extra_energy_required_by_max_task <= available_energy) {
// If the test below is true, we know the max_task cannot fully