diff --git a/ortools/constraint_solver/README.md b/ortools/constraint_solver/README.md index dd81854575..c1d157ec4f 100644 --- a/ortools/constraint_solver/README.md +++ b/ortools/constraint_solver/README.md @@ -1,28 +1,33 @@ # Constraint Programming (CP) and Routing Solver -This directory contains a Constraint Programming (CP) solver and a Vehicle Routing solver. +This directory contains a Constraint Programming (CP) solver and a Vehicle +Routing solver. ## CP solver -[Constraint Programming](http://en.wikipedia.org/wiki/Constraint_programming) is a technology -issued from IA and used in Operations Research. +[Constraint Programming](http://en.wikipedia.org/wiki/Constraint_programming) is +a technology issued from IA and used in Operations Research. To begin, skim -* [constraint_solver.h](constraint_solver.h): -The point of entry for all constraint programming users. -* [constraint_solveri.h](constraint_solveri.h): -An additional file that helps extending the constraint programming library. + +* [constraint_solver.h](../constraint_solver/constraint_solver.h): +Declaration of the core objects for the constraint solver. +* [constraint_solveri.h](../constraint_solver/constraint_solveri.h): +Collection of objects used to extend the Constraint Solver library. ### Parameters -* [solver_parameters.proto](solver_parameters.proto): -The CP solver parameters. -* [search_limit.proto](search_limit.proto): -Holds parameters to limit the search space within the CP solver, which is important for performance. + +* [solver_parameters.proto](../constraint_solver/solver_parameters.proto): +This file contains protocol buffers for all parameters of the CP solver. +* [search_limit.proto](../constraint_solver/search_limit.proto): +Holds parameters to limit the search space within the CP solver, which is +important for performance. ### Solution -* [assignment.proto](assignment.proto): + +* [assignment.proto](../constraint_solver/assignment.proto): Holds the solution of a CP problem. -* [demon_profiler.proto](demon_profiler.proto): +* [demon_profiler.proto](../constraint_solver/demon_profiler.proto): Holds the timeline and execution profile of constraints and demons (daemons). ## Routing solver @@ -31,18 +36,26 @@ Holds the timeline and execution profile of constraints and demons (daemons). extension that is implemented on top of the CP solver library. To begin, skim -* [routing.h](routing.h): -The point of entry for routing problems. + +* [routing.h](../constraint_solver/routing.h): +The vehicle routing library lets one model and solve generic vehicle routing +problems ranging from the Traveling Salesman Problem to more complex problems +such as the Capacitated Vehicle Routing Problem with Time Windows. +* [routing_flags.h](../constraint_solver/routing_flags.h) ### Parameters -* [routing_parameters.proto](routing_parameters.proto): + +* [routing_parameters.proto](../constraint_solver/routing_parameters.proto): The Vehicle Routing solver parameters. +* [routing_enums.proto](../constraint_solver/routing_enums.proto): +Enums used to define routing parameters. ### Solution + * [assignment.proto](assignment.proto): Holds the solution of a Routing problem. -### Recipes +## Recipes You can find a set of code recipes in -[the documentation directory](doc/routing.md). +[the documentation directory](doc/README.md). diff --git a/ortools/constraint_solver/doc/CP.md b/ortools/constraint_solver/doc/CP.md new file mode 100644 index 0000000000..93ea001f11 --- /dev/null +++ b/ortools/constraint_solver/doc/CP.md @@ -0,0 +1,163 @@ +# Using the CP solver + + +## Documentation structure + +OR-Tools comes with lots of constraint programming samples given in C++, Python, +Java and .Net. Each language have different requirements for the code samples. + +## Basic example + +### C++ code samples + +```cpp +#include "ortools/constraint_solver/constraint_solver.h" + +namespace operations_research { + +void SimpleCpProgram() { + // Instantiate the solver. + Solver solver("CpSimple"); + + // Create the variables. + const int64 num_vals = 3; + IntVar* const x = solver.MakeIntVar(0, num_vals - 1, "x"); + IntVar* const y = solver.MakeIntVar(0, num_vals - 1, "y"); + IntVar* const z = solver.MakeIntVar(0, num_vals - 1, "z"); + + // Constraint 0: x != y.. + solver.AddConstraint(solver.MakeAllDifferent({x, y})); + LOG(INFO) << "Number of constraints: " + << std::to_string(solver.constraints()); + + // Solve the problem. + DecisionBuilder* const db = solver.MakePhase( + {x, y, z}, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE); + + // Print solution on console. + int count = 0; + solver.NewSearch(db); + while (solver.NextSolution()) { + ++count; + LOG(INFO) << "Solution " << count << ":" << std::endl + << " x=" << x->Value() << " y=" << y->Value() + << " z=" << z->Value(); + } + solver.EndSearch(); + LOG(INFO) << "Number of solutions found: " << solver.solutions(); + + LOG(INFO) << "Advanced usage:" << std::endl + << "Problem solved in " << std::to_string(solver.wall_time()) + << "ms" << std::endl + << "Memory usage: " << std::to_string(Solver::MemoryUsage()) + << "bytes"; +} + +} // namespace operations_research + +int main(int argc, char** argv) { + operations_research::SimpleCpProgram(); + return EXIT_SUCCESS; +} +``` + +### Python code samples + +```python +"""Simple Constraint optimization example.""" + +from __future__ import print_function +from ortools.constraint_solver import pywrapcp + + +def main(): + """Entry point of the program.""" + # Instantiate the solver. + solver = pywrapcp.Solver('CPSimple') + + # Create the variables. + num_vals = 3 + x = solver.IntVar(0, num_vals - 1, 'x') + y = solver.IntVar(0, num_vals - 1, 'y') + z = solver.IntVar(0, num_vals - 1, 'z') + + # Constraint 0: x != y. + solver.Add(x != y) + print('Number of constraints: ', solver.Constraints()) + + # Solve the problem. + decision_builder = solver.Phase([x, y, z], solver.CHOOSE_FIRST_UNBOUND, + solver.ASSIGN_MIN_VALUE) + + # Print solution on console. + count = 0 + solver.NewSearch(decision_builder) + while solver.NextSolution(): + count += 1 + solution = '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') + +if __name__ == '__main__': + main() +``` + +### Java code samples + +```java +``` + +### .Net code samples + + +```cs +using System; +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"); + + // Create the variables. + const long numVals = 3; + IntVar x = solver.MakeIntVar(0, numVals - 1, "x"); + IntVar y = solver.MakeIntVar(0, numVals - 1, "y"); + IntVar z = solver.MakeIntVar(0, numVals - 1, "z"); + + // Constraint 0: x != y.. + solver.Add(solver.MakeAllDifferent(new IntVar[]{x, y})); + Console.WriteLine($"Number of constraints: {solver.Constraints()}"); + + // Solve the problem. + DecisionBuilder db = solver.MakePhase( + new IntVar[]{x, y, z}, + Solver.CHOOSE_FIRST_UNBOUND, + Solver.ASSIGN_MIN_VALUE); + + // Print solution on console. + int count = 0; + solver.NewSearch(db); + while (solver.NextSolution()) { + ++count; + Console.WriteLine($"Solution: {count}\n x={x.Value()} y={y.Value()} z={z.Value()}"); + } + solver.EndSearch(); + Console.WriteLine($"Number of solutions found: {solver.Solutions()}"); + + Console.WriteLine("Advanced usage:"); + Console.WriteLine($"Problem solved in {solver.WallTime()}ms"); + Console.WriteLine($"Memory usage: {Solver.MemoryUsage()}bytes"); + } +} +``` diff --git a/ortools/constraint_solver/doc/pdp.md b/ortools/constraint_solver/doc/PDP.md similarity index 99% rename from ortools/constraint_solver/doc/pdp.md rename to ortools/constraint_solver/doc/PDP.md index 289fd84d25..e4eb418511 100644 --- a/ortools/constraint_solver/doc/pdp.md +++ b/ortools/constraint_solver/doc/PDP.md @@ -12,6 +12,7 @@ Solution with the default Policy (ANY): ![solution](vrp_pickup_delivery_solution.svg) Samples: + * [vrp_pickup_delivery.cc](../samples/vrp_pickup_delivery.cc) * [vrp_pickup_delivery.py](../samples/vrp_pickup_delivery.py) * [VrpPickupDelivery.java](../samples/VrpPickupDelivery.java) @@ -22,6 +23,7 @@ Solution with the FIFO Policy: ![solution](vrp_pickup_delivery_fifo_solution.svg) Samples: + * [vrp_pickup_delivery_fifo.cc](../samples/vrp_pickup_delivery_fifo.cc) * [vrp_pickup_delivery_fifo.py](../samples/vrp_pickup_delivery_fifo.py) * [VrpPickupDeliveryFifo.java](../samples/VrpPickupDeliveryFifo.java) @@ -32,6 +34,7 @@ Solution with the LIFO Policy: ![solution](vrp_pickup_delivery_lifo_solution.svg) Samples: + * [vrp_pickup_delivery_lifo.cc](../samples/vrp_pickup_delivery_lifo.cc) * [vrp_pickup_delivery_lifo.py](../samples/vrp_pickup_delivery_lifo.py) * [VrpPickupDeliveryLifo.java](../samples/VrpPickupDeliveryLifo.java) diff --git a/ortools/constraint_solver/doc/README.md b/ortools/constraint_solver/doc/README.md new file mode 100644 index 0000000000..c7f136dd2a --- /dev/null +++ b/ortools/constraint_solver/doc/README.md @@ -0,0 +1,18 @@ +# Overview + +You can find here, the documentation for the two following Or-Tools components. + +* [CP Solver](CP.md) + + Constraint programming (CP), is the name given to identifying feasible + solutions out of a very large set of candidates, where the problem can be + modeled in terms of arbitrary constraints. + + **note:** We **strongly recommend** using the [CP-SAT solver](../../sat) + rather than the original CP solver. + +* [Routing Solver](ROUTING.md) + + A specialized library for identifying best vehicle routes given constraints. + + This library extensiond is implemented on top of the CP Solver library. diff --git a/ortools/constraint_solver/doc/ROUTING.md b/ortools/constraint_solver/doc/ROUTING.md new file mode 100644 index 0000000000..1b598042e3 --- /dev/null +++ b/ortools/constraint_solver/doc/ROUTING.md @@ -0,0 +1,223 @@ +# Using the Vehicle Routing solver + + +## Documentation structure + +This document presents modeling recipes for the Vehicle routing solver. +These are grouped by type: + +* [Travelling Salesman Problem](TSP.md) +* [Vehicle Routing Problem](VRP.md) +* [Pickup and Delivery Problem](PDP.md) + +OR-Tools comes with lots of vehicle routing samples given in C++, Python, Java +and .Net. Each language have different requirements for the code samples. + +## Basic example + +### C++ code samples + +```cpp +#include +#include "ortools/constraint_solver/routing.h" +#include "ortools/constraint_solver/routing_enums.pb.h" +#include "ortools/constraint_solver/routing_index_manager.h" +#include "ortools/constraint_solver/routing_parameters.h" + +namespace operations_research { + +void SimpleRoutingProgram() { + // Instantiate the data problem. + int num_location = 5; + int num_vehicles = 1; + RoutingIndexManager::NodeIndex depot{0}; + + // Create Routing Index Manager + RoutingIndexManager manager(num_location, num_vehicles, depot); + + // Create Routing Model. + RoutingModel routing(manager); + + // Define cost of each arc. + int distance_call_index = routing.RegisterTransitCallback( + [&manager](int64 from_index, int64 to_index) -> int64 { + // Convert from routing variable Index to user NodeIndex. + auto from_node = manager.IndexToNode(from_index).value(); + auto to_node = manager.IndexToNode(to_index).value(); + return std::abs(to_node - from_node); + }); + routing.SetArcCostEvaluatorOfAllVehicles(distance_call_index); + + // Setting first solution heuristic. + RoutingSearchParameters searchParameters = DefaultRoutingSearchParameters(); + searchParameters.set_first_solution_strategy( + FirstSolutionStrategy::PATH_CHEAPEST_ARC); + + // Solve the problem. + const Assignment* solution = routing.SolveWithParameters(searchParameters); + + // Print solution on console. + LOG(INFO) << "Objective: " << solution->ObjectiveValue(); + // Inspect solution. + int64 index = routing.Start(0); + LOG(INFO) << "Route for Vehicle 0:"; + int64 route_distance{0}; + std::ostringstream route; + while (routing.IsEnd(index) == false) { + route << manager.IndexToNode(index).value() << " -> "; + int64 previous_index = index; + index = solution->Value(routing.NextVar(index)); + route_distance += + routing.GetArcCostForVehicle(previous_index, index, int64{0}); + } + LOG(INFO) << route.str() << manager.IndexToNode(index).value(); + LOG(INFO) << "Distance of the route: " << route_distance << "m"; +} + +} // namespace operations_research + +int main(int argc, char** argv) { + operations_research::SimpleRoutingProgram(); + return EXIT_SUCCESS; +} +``` + +### Python code samples + +```python +"""Vehicle Routing example.""" + +from __future__ import print_function +from ortools.constraint_solver import routing_enums_pb2 +from ortools.constraint_solver import pywrapcp +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 + + # Create the routing index manager. + manager = pywrapcp.RoutingIndexManager( + num_locations, + num_vehicles, + depot) + + # 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) + + # Define cost of each arc. + routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index) + + # Setting first solution heuristic. + search_parameters = pywrapcp.DefaultRoutingSearchParameters() + search_parameters.first_solution_strategy = ( + routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member + + # 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() +``` + +### Java code samples + +```java +``` + +### .Net code samples + + +```cs +using System; +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; + + // Create Routing Index Manager + RoutingIndexManager manager = new RoutingIndexManager( + numLocation, + numVehicles, + depot); + + // 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); + }); + + // 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; + + // 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); + } + Console.WriteLine("{0}", manager.IndexToNode(index)); + Console.WriteLine("Distance of the route: {0}m", route_distance); + } +} +``` + +## Misc +Images have been generated using [routing_svg.py](routing_svg.py) through bash + script [generate_svg.sh](generate_svg.sh). diff --git a/ortools/constraint_solver/doc/tsp.md b/ortools/constraint_solver/doc/TSP.md similarity index 86% rename from ortools/constraint_solver/doc/tsp.md rename to ortools/constraint_solver/doc/TSP.md index c21379749d..81314c8621 100644 --- a/ortools/constraint_solver/doc/tsp.md +++ b/ortools/constraint_solver/doc/TSP.md @@ -2,9 +2,10 @@ ## Introduction -The Vehicle Routing solver can be used to solve a TSP. +The Vehicle Routing solver can be used to solve a Travelling Salesman Problem +(TSP). -## Travelling Salesman Problem +## Using Locations Data Problem: ![problem](tsp.svg) @@ -12,6 +13,7 @@ Solution: ![solution](tsp_solution.svg) Samples: + * [tsp.cc](../samples/tsp.cc) * [tsp.py](../samples/tsp.py) * [Tsp.java](../samples/Tsp.java) @@ -25,6 +27,7 @@ Solution: ![solution](tsp_distance_matrix_solution.svg) Samples: + * [tsp_distance_matrix.cc](../samples/tsp_distance_matrix.cc) * [tsp_distance_matrix.py](../samples/tsp_distance_matrix.py) * [TspDistanceMatrix.java](../samples/TspDistanceMatrix.java) diff --git a/ortools/constraint_solver/doc/vrp.md b/ortools/constraint_solver/doc/VRP.md similarity index 99% rename from ortools/constraint_solver/doc/vrp.md rename to ortools/constraint_solver/doc/VRP.md index 494e17b7b7..a5151cf7c2 100644 --- a/ortools/constraint_solver/doc/vrp.md +++ b/ortools/constraint_solver/doc/VRP.md @@ -12,6 +12,7 @@ Solution: ![solution](vrp_solution.svg) Samples: + * [vrp.cc](../samples/vrp.cc) * [vrp.py](../samples/vrp.py) * [Vrp.java](../samples/Vrp.java) @@ -25,6 +26,7 @@ Solution: ![solution](vrp_global_span_solution.svg) Samples: + * [vrp_global_span.cc](../samples/vrp_global_span.cc) * [vrp_global_span.py](../samples/vrp_global_span.py) * [VrpGlobalSpan.java](../samples/VrpGlobalSpan.java) @@ -38,6 +40,7 @@ Solution: ![solution](vrp_capacity_solution.svg) Samples: + * [vrp_capacity.cc](../samples/vrp_capacity.cc) * [vrp_capacity.py](../samples/vrp_capacity.py) * [VrpCapacity.java](../samples/VrpCapacity.java) @@ -51,6 +54,7 @@ Solution: ![solution](vrp_drop_nodes_solution.svg) Samples: + * [vrp_drop_nodes.cc](../samples/vrp_drop_nodes.cc) * [vrp_drop_nodes.py](../samples/vrp_drop_nodes.py) * [VrpDropNodes.java](../samples/VrpDropNodes.java) @@ -64,6 +68,7 @@ Solution: ![solution](vrp_starts_ends_solution.svg) Samples: + * [vrp_starts_ends.cc](../samples/vrp_starts_ends.cc) * [vrp_starts_ends.py](../samples/vrp_starts_ends.py) * [VrpStartsEnds.java](../samples/VrpStartsEnds.java) @@ -77,6 +82,7 @@ Solution: ![solution](vrp_time_windows_solution.svg) Samples: + * [vrp_time_windows.cc](../samples/vrp_time_windows.cc) * [vrp_time_windows.py](../samples/vrp_time_windows.py) * [VrpTimeWindows.java](../samples/VrpTimeWindows.java) @@ -90,6 +96,7 @@ Solution: ![solution](vrp_resources_solution.svg) Samples: + * [vrp_resources.cc](../samples/vrp_resources.cc) * [vrp_resources.py](../samples/vrp_resources.py) * [VrpResources.java](../samples/VrpResources.java) diff --git a/ortools/constraint_solver/doc/cp.md b/ortools/constraint_solver/doc/cp.md deleted file mode 100644 index 056c4484f8..0000000000 --- a/ortools/constraint_solver/doc/cp.md +++ /dev/null @@ -1,28 +0,0 @@ -# Using the CP solver - -## Table of Contents - -OR-Tools comes with lots of constraint programming samples given in C++, Python, Java -and .Net. Each language have different requirements for the code samples. - -## Searching for one solution - -### C++ code samples -```cpp -../samples/simple_cp_program.cc -``` - -### Python code samples -```python -../samples/simple_cp_program.py -``` - -### Java code samples -```java -../samples/SimpleCpProgram.java -``` - -### .Net code samples -```cs -../samples/SimpleCpProgram.cs -``` diff --git a/ortools/constraint_solver/doc/routing.md b/ortools/constraint_solver/doc/routing.md deleted file mode 100644 index 2a9fcc5073..0000000000 --- a/ortools/constraint_solver/doc/routing.md +++ /dev/null @@ -1,28 +0,0 @@ -# Using the Vehicle Routing solver - -## Table of Contents - -This document presents modeling recipes for the Vehicle routing solver. These are grouped by type: -* [Travelling Salesman Problem](tsp.md) -* [Vehicle Routing Problem](vrp.md) -* [Pickup and Delivery Problem](pdp.md) - -OR-Tools comes with lots of vehicle routing samples given in C++, Python, Java -and .Net. Each language have different requirements for the code samples. - -## Searching for one solution - -### C++ code samples -[simple_routing_program.cc](../samples/simple_routing_program.cc) - -### Python code samples -[simple_routing_program.py](../samples/simple_routing_program.py) - -### Java code samples -[SimpleRoutingProgram.java](../samples/SimpleRoutingProgram.java) - -### .Net code samples -[SimpleRoutingProgram.cs](../samples/SimpleRoutingProgram.cs) - -## Misc -Images have been generated using [routing_svg.py](routing_svg.py) through bash script [generate_svg.sh](generate_svg.sh). diff --git a/ortools/constraint_solver/doc/routing_svg.py b/ortools/constraint_solver/doc/routing_svg.py index ef0adcab12..debc964e36 100755 --- a/ortools/constraint_solver/doc/routing_svg.py +++ b/ortools/constraint_solver/doc/routing_svg.py @@ -1,6 +1,4 @@ -#!/usr/bin/env python3 -# This Python file uses the following encoding: utf-8 -# Copyright 2018 Google LLC +# Copyright 2010-2018 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 @@ -19,13 +17,13 @@ from __future__ import print_function import argparse from ortools.constraint_solver import pywrapcp from ortools.constraint_solver import routing_enums_pb2 - # [END import] # [START data_model] class DataModel: # pylint: disable=too-many-instance-attributes """Stores the data for the problem.""" + def __init__(self, args): # Locations in block units locations = \ @@ -148,20 +146,28 @@ class DataModel: # pylint: disable=too-many-instance-attributes (10, 15), # 15 (5, 15), # 16 ] - if args['drop_nodes'] is True: + 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],] + [1, 6], + [2, 10], + [4, 3], + [5, 9], + [7, 8], + [15, 11], + [13, 12], + [16, 14], + ] - if args['tsp'] is True: + if args['tsp']: self._num_vehicles = 1 else: self._num_vehicles = 4 self._vehicle_capacities = [15, 15, 15, 15] - if args['resources'] is True: + if args['resources']: self._vehicle_load_time = 5 self._vehicle_unload_time = 5 @@ -247,10 +253,10 @@ class DataModel: # pylint: disable=too-many-instance-attributes # Printer # ########### class GoogleColorPalette(): - """Google color codes palette""" + """Google color codes palette.""" def __init__(self): - """Initialize Google ColorPalette""" + """Initialize Google ColorPalette.""" self._colors = [('blue', r'#4285F4'), ('red', r'#EA4335'), ('yellow', r'#FBBC05'), ('green', r'#34A853'), ('black', r'#101010'), ('white', r'#FFFFFF')] @@ -297,7 +303,7 @@ class SVG(): @staticmethod def definitions(colors): - """Writes definitions""" + """Writes definitions.""" print(r'') print(r'') @@ -307,8 +313,8 @@ class SVG(): 'refX="8" refY="8" markerUnits="strokeWidth" markerWidth="5" markerHeight="5" ' 'orient="auto">'.format(colorname=color[0])) print( - r' '. - format(color=color[1])) + r' ' + .format(color=color[1])) print(r' ') print(r'') @@ -448,7 +454,7 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes 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) + # color = self._color_palette.value(vehicle_idx) loc = self._data.locations[start] self._svg.draw_circle(loc, self._radius, self._stroke_width, color, 'white') @@ -464,7 +470,7 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes """Draws all the locations but the depot.""" print(r'') color = self._color_palette.value_from_name('blue') - if self._args['starts_ends'] is False: + if not self._args['starts_ends']: for idx, loc in enumerate(self._data.locations): if idx == self._data.depot: continue @@ -491,7 +497,7 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes 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))) + # color = self._color_palette.value(int(math.log(demand, 2))) self._svg.draw_text(demand, position, self._radius, 'none', color) def draw_pickups_deliveries(self): @@ -539,8 +545,8 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes 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_circle(loc, self._radius, self._stroke_width, color, + 'white') self._svg.draw_text(node_idx, loc, self._radius, 'none', color) def routes(self): @@ -566,7 +572,7 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes # First print route previous_loc_idx = None for loc_idx in route: - if previous_loc_idx != None and previous_loc_idx != loc_idx: + if previous_loc_idx 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) @@ -589,7 +595,7 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes self.draw_route(route, color, colorname) def tw_routes(self): - """Creates the route time window list from the assignment""" + """Creates the route time window list from the assignment.""" if self._assignment is None: print('') return [] @@ -598,7 +604,7 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes 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)) + # index = self._assignment.Value(self._routing.NextVar(index)) loc_route = [] tw_route = [] while True: @@ -616,16 +622,16 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes 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; + """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)]) + x + y for x, y in zip(loc, [ + self._radius * is_start, self._radius * ( + 1.8 + route_idx) + ]) ] is_start = 1 else: @@ -634,12 +640,14 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes 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) + '[{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""" + """Draws the time window routes.""" print(r'') for route_idx, loc_tw in enumerate(self.tw_routes()): print(r''.format(route_idx)) @@ -647,35 +655,31 @@ class SVGPrinter(): # pylint: disable=too-many-instance-attributes 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""" + """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 self._args['solution'] is False: - if self._args['pickup_delivery'] is True: + 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'] is True: + if self._args['starts_ends']: self.draw_depots() else: self.draw_depot() - if self._args['capacity'] is True: + if self._args['capacity']: self.draw_demands() - if self._args['drop_nodes'] is True: + if self._args['drop_nodes']: self.draw_demands() - if (self._args['time_windows'] is True) or (self._args['resources'] is True): + if self._args['time_windows'] or self._args['resources']: self.draw_time_windows() - if (( - (self._args['time_windows'] is True) or - (self._args['resources'] is True) - ) and ( - self._args['solution'] is True) - ): + if ((self._args['time_windows'] or self._args['resources']) and + self._args['solution']): self.draw_tw_routes() self._svg.footer() @@ -744,7 +748,7 @@ def main(): # pylint: disable=too-many-locals,too-many-branches data = DataModel(args) # [END data] - if args['solution'] is False: + if not args['solution']: # Print svg on cout printer = SVGPrinter(args, data) printer.print_to_console() @@ -752,7 +756,7 @@ def main(): # pylint: disable=too-many-locals,too-many-branches # Create the routing index manager. # [START index_manager] - if args['starts_ends'] is True: + if args['starts_ends']: manager = pywrapcp.RoutingIndexManager( len(data.locations), data.num_vehicles, data.starts, data.ends) else: @@ -796,29 +800,29 @@ def main(): # pylint: disable=too-many-locals,too-many-branches demand_callback_index = routing.RegisterUnaryTransitCallback( demand_callback) - if (args['time_windows'] is True) or (args['resources'] is True): + if args['time_windows'] or args['resources']: routing.SetArcCostEvaluatorOfAllVehicles(time_callback_index) else: routing.SetArcCostEvaluatorOfAllVehicles(distance_callback_index) - if (args['global_span'] is True) or (args['pickup_delivery'] is True): + 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'] is True) or (args['drop_nodes'] is True): + if args['capacity'] or args['drop_nodes']: routing.AddDimensionWithVehicleCapacity( demand_callback_index, 0, data.vehicle_capacities, True, 'Capacity') - if args['drop_nodes'] is True: + 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'] is True: + if args['pickup_delivery']: dimension_name = 'Distance' routing.AddDimension(distance_callback_index, 0, 3000, True, dimension_name) @@ -834,14 +838,14 @@ def main(): # pylint: disable=too-many-locals,too-many-branches routing.solver().Add( distance_dimension.CumulVar(pickup_index) <= distance_dimension.CumulVar(delivery_index)) - if args['fifo'] is True: + if args['fifo']: routing.SetPickupAndDeliveryPolicyOfAllVehicles( pywrapcp.RoutingModel.FIFO) - if args['lifo'] is True: + if args['lifo']: routing.SetPickupAndDeliveryPolicyOfAllVehicles( pywrapcp.RoutingModel.LIFO) - if args['starts_ends'] is True: + if args['starts_ends']: dimension_name = 'Distance' routing.AddDimension(distance_callback_index, 0, 2000, True, dimension_name) @@ -849,11 +853,11 @@ def main(): # pylint: disable=too-many-locals,too-many-branches distance_dimension.SetGlobalSpanCostCoefficient(100) time = 'Time' - if (args['time_windows'] is True) or (args['resources'] is True): + 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 + # 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 @@ -861,8 +865,8 @@ def main(): # pylint: disable=too-many-locals,too-many-branches 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 + # 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] @@ -872,41 +876,37 @@ def main(): # pylint: disable=too-many-locals,too-many-branches # 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))) + routing.AddVariableMinimizedByFinalizer( + time_dimension.CumulVar(routing.End(vehicle_id))) + routing.AddVariableMinimizedByFinalizer( + time_dimension.CumulVar(routing.Start(vehicle_id))) - if args['resources'] is True: + 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 ') - ) + # 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')) + 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 args['pickup_delivery'] is False: + if not args['pickup_delivery']: search_parameters.first_solution_strategy = ( routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) else: diff --git a/ortools/constraint_solver/samples/tsp.py b/ortools/constraint_solver/samples/tsp.py index c465e5acd6..b2f3afe806 100755 --- a/ortools/constraint_solver/samples/tsp.py +++ b/ortools/constraint_solver/samples/tsp.py @@ -21,7 +21,6 @@ http://en.wikipedia.org/wiki/Travelling_salesman_problem. from __future__ import print_function from ortools.constraint_solver import routing_enums_pb2 from ortools.constraint_solver import pywrapcp - # [END import] diff --git a/ortools/constraint_solver/samples/vrp_resources.py b/ortools/constraint_solver/samples/vrp_resources.py index 0f16c29f4f..2478265665 100644 --- a/ortools/constraint_solver/samples/vrp_resources.py +++ b/ortools/constraint_solver/samples/vrp_resources.py @@ -17,7 +17,6 @@ from __future__ import print_function from ortools.constraint_solver import routing_enums_pb2 from ortools.constraint_solver import pywrapcp - # [END import]