Sync g3 -> github

- java live-snippet still broken
This commit is contained in:
Corentin Le Molgat
2019-03-18 13:43:29 +01:00
parent 57f7ef8464
commit 3ea64697a4
12 changed files with 532 additions and 160 deletions

View File

@@ -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).

View File

@@ -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;
/// <summary>
/// This is a simple CP program.
/// </summary>
public class SimpleCpProgram {
public static void Main(String[] args) {
// Instantiate the solver.
Solver solver = new Solver("CpSimple");
// Create the variables.
const long numVals = 3;
IntVar x = solver.MakeIntVar(0, numVals - 1, "x");
IntVar y = solver.MakeIntVar(0, numVals - 1, "y");
IntVar z = solver.MakeIntVar(0, numVals - 1, "z");
// Constraint 0: x != y..
solver.Add(solver.MakeAllDifferent(new IntVar[]{x, y}));
Console.WriteLine($"Number of constraints: {solver.Constraints()}");
// Solve the problem.
DecisionBuilder db = solver.MakePhase(
new IntVar[]{x, y, z},
Solver.CHOOSE_FIRST_UNBOUND,
Solver.ASSIGN_MIN_VALUE);
// Print solution on console.
int count = 0;
solver.NewSearch(db);
while (solver.NextSolution()) {
++count;
Console.WriteLine($"Solution: {count}\n x={x.Value()} y={y.Value()} z={z.Value()}");
}
solver.EndSearch();
Console.WriteLine($"Number of solutions found: {solver.Solutions()}");
Console.WriteLine("Advanced usage:");
Console.WriteLine($"Problem solved in {solver.WallTime()}ms");
Console.WriteLine($"Memory usage: {Solver.MemoryUsage()}bytes");
}
}
```

View File

@@ -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)

View File

@@ -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.

View File

@@ -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 <cmath>
#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;
/// <summary>
/// This is a sample using the routing library .Net wrapper.
/// </summary>
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).

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
```

View File

@@ -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).

View File

@@ -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'<!-- Need this definition to make an arrow marker,'
' from https://www.w3.org/TR/svg-markers/ -->')
print(r'<defs>')
@@ -307,8 +313,8 @@ class SVG():
'refX="8" refY="8" markerUnits="strokeWidth" markerWidth="5" markerHeight="5" '
'orient="auto">'.format(colorname=color[0]))
print(
r' <path d="M 0 0 L 16 8 L 0 16 z" stroke="none" fill="{color}"/>'.
format(color=color[1]))
r' <path d="M 0 0 L 16 8 L 0 16 z" stroke="none" fill="{color}"/>'
.format(color=color[1]))
print(r' </marker>')
print(r'</defs>')
@@ -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'<!-- Print locations -->')
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('<!-- No solution found. -->')
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'<!-- Print time window routes -->')
for route_idx, loc_tw in enumerate(self.tw_routes()):
print(r'<!-- Print time window route {} -->'.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:

View File

@@ -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]

View File

@@ -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]