regenerate all notebooks

This commit is contained in:
Mizux Seiha
2021-04-27 10:56:28 +02:00
parent c09432ee8e
commit d1a771677b
67 changed files with 777 additions and 230 deletions

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -80,7 +81,15 @@
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"# [START program]\n",
"\"\"\"Simple Vehicles Routing Problem.\"\"\"\n",
"\"\"\"Simple Vehicles Routing Problem (VRP).\n",
"\n",
" This is a sample using the routing library python wrapper to solve a VRP\n",
" problem.\n",
" A description of the problem can be found here:\n",
" http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n",
"\n",
" Distances are in meters.\n",
"\"\"\"\n",
"\n",
"# [START import]\n",
"from ortools.constraint_solver import routing_enums_pb2\n",
@@ -171,7 +180,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print('Objective: {}'.format(solution.ObjectiveValue()))\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" total_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",
@@ -188,7 +197,8 @@
" print(plan_output)\n",
" total_distance += route_distance\n",
" print('Total Distance of all routes: {}m'.format(total_distance))\n",
" # [END solution_printer]\n",
"\n",
"# [END solution_printer]\n",
"\n",
"\n",
"\"\"\"Entry point of the program.\"\"\"\n",
@@ -242,6 +252,8 @@
"# [START print_solution]\n",
"if solution:\n",
" print_solution(data, manager, routing, solution)\n",
"else:\n",
" print('No solution found !')\n",
"# [END print_solution]\n",
"\n"
]

View File

@@ -122,9 +122,10 @@
" [38, 43, 77, 28, 33, 52, 63, 37, 54, 40, 57, 13, 19, 21, 38, 0, 39],\n",
" [33, 60, 37, 67, 62, 35, 24, 42, 25, 23, 17, 42, 36, 26, 9, 39, 0],\n",
" ]\n",
" data['service_time'] = [15] * len(data['time_matrix']) # 15 min of service time\n",
" data['service_time'] = [15] * len(\n",
" data['time_matrix']) # 15 min of service time\n",
" data['service_time'][data['depot']] = 0\n",
" assert(len(data['time_matrix']) == len(data['service_time']))\n",
" assert len(data['time_matrix']) == len(data['service_time'])\n",
" return data\n",
" # [END data_model]\n",
"\n",
@@ -138,8 +139,9 @@
" intervals = solution.IntervalVarContainer()\n",
" for i in range(intervals.Size()):\n",
" brk = intervals.Element(i)\n",
" if brk.PerformedValue() == True:\n",
" print(f'{brk.Var().Name()}: Start({brk.StartValue()}) Duration({brk.DurationValue()})')\n",
" if brk.PerformedValue():\n",
" print(f'{brk.Var().Name()}: ' +\n",
" f'Start({brk.StartValue()}) Duration({brk.DurationValue()})')\n",
" else:\n",
" print(f'{brk.Var().Name()}: Unperformed')\n",
"\n",
@@ -150,10 +152,12 @@
" plan_output = f'Route for vehicle {vehicle_id}:\\n'\n",
" while not routing.IsEnd(index):\n",
" time_var = time_dimension.CumulVar(index)\n",
" plan_output += f'{manager.IndexToNode(index)} Time({solution.Value(time_var)}) -> '\n",
" plan_output += f'{manager.IndexToNode(index)} '\n",
" plan_output += f'Time({solution.Value(time_var)}) -> '\n",
" index = solution.Value(routing.NextVar(index))\n",
" time_var = time_dimension.CumulVar(index)\n",
" plan_output += f'{manager.IndexToNode(index)} Time({solution.Value(time_var)})\\n'\n",
" plan_output += f'{manager.IndexToNode(index)} '\n",
" plan_output += f'Time({solution.Value(time_var)})\\n'\n",
" plan_output += f'Time of the route: {solution.Value(time_var)}min\\n'\n",
" print(plan_output)\n",
" total_time += solution.Value(time_var)\n",
@@ -169,12 +173,14 @@
"\n",
"# Create the routing index manager.\n",
"# [START index_manager]\n",
"manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']), data['num_vehicles'], data['depot'])\n",
"manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n",
" data['num_vehicles'], data['depot'])\n",
"# [END index_manager]\n",
"\n",
"# Create Routing Model.\n",
"# [START routing_model]\n",
"routing = pywrapcp.RoutingModel(manager)\n",
"\n",
"# [END routing_model]\n",
"\n",
"# Create and register a transit callback.\n",
@@ -184,7 +190,8 @@
" # Convert from routing variable Index to time matrix NodeIndex.\n",
" from_node = manager.IndexToNode(from_index)\n",
" to_node = manager.IndexToNode(to_index)\n",
" return data['time_matrix'][from_node][to_node] + data['service_time'][from_node]\n",
" return data['time_matrix'][from_node][to_node] + data['service_time'][\n",
" from_node]\n",
"\n",
"transit_callback_index = routing.RegisterTransitCallback(time_callback)\n",
"# [END transit_callback]\n",
@@ -217,19 +224,18 @@
"for v in range(data['num_vehicles']):\n",
" break_intervals[v] = [\n",
" routing.solver().FixedDurationIntervalVar(\n",
" 50, # start min\n",
" 60, # start max\n",
" 10, # duration: 10 min\n",
" False, # optional: no\n",
" 50, # start min\n",
" 60, # start max\n",
" 10, # duration: 10 min\n",
" False, # optional: no\n",
" f'Break for vehicle {v}')\n",
" ]\n",
" time_dimension.SetBreakIntervalsOfVehicle(\n",
" break_intervals[v], # breaks\n",
" v, # vehicle index\n",
" node_visit_transit)\n",
" break_intervals[v], # breaks\n",
" v, # vehicle index\n",
" node_visit_transit)\n",
"# [END break_constraint]\n",
"\n",
"\n",
"# Setting first solution heuristic.\n",
"# [START parameters]\n",
"search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n",
@@ -237,7 +243,7 @@
" routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n",
"search_parameters.local_search_metaheuristic = (\n",
" routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n",
"#search_parameters.log_search = True\n",
"# search_parameters.log_search = True\n",
"search_parameters.time_limit.FromSeconds(2)\n",
"# [END parameters]\n",
"\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -175,6 +176,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" total_distance = 0\n",
" total_load = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -175,6 +176,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, assignment):\n",
" \"\"\"Prints assignment on console.\"\"\"\n",
" print(f'Objective: {assignment.ObjectiveValue()}')\n",
" # Display dropped nodes.\n",
" dropped_nodes = 'Dropped nodes:'\n",
" for node in range(routing.Size()):\n",

View File

@@ -81,7 +81,15 @@
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"# [START program]\n",
"\"\"\"Vehicles Routing Problem (VRP).\"\"\"\n",
"\"\"\"Simple Vehicles Routing Problem (VRP).\n",
"\n",
" This is a sample using the routing library python wrapper to solve a VRP\n",
" problem.\n",
" A description of the problem can be found here:\n",
" http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n",
"\n",
" Distances are in meters.\n",
"\"\"\"\n",
"\n",
"# [START import]\n",
"from ortools.constraint_solver import routing_enums_pb2\n",
@@ -172,6 +180,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" max_route_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",
@@ -192,7 +201,7 @@
"# [END solution_printer]\n",
"\n",
"\n",
"\"\"\"Solve the CVRP problem.\"\"\"\n",
"\"\"\"Entry point of the program.\"\"\"\n",
"# Instantiate the data problem.\n",
"# [START data]\n",
"data = create_data_model()\n",
@@ -256,6 +265,8 @@
"# [START print_solution]\n",
"if solution:\n",
" print_solution(data, manager, routing, solution)\n",
"else:\n",
" print('No solution found !')\n",
"# [END print_solution]\n",
"\n"
]

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -178,6 +179,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" max_route_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",

View File

@@ -0,0 +1,381 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### Copyright 2021 Google LLC."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"you may not use this file except in compliance with the License.\n",
"You may obtain a copy of the License at\n",
"\n",
" http://www.apache.org/licenses/LICENSE-2.0\n",
"\n",
"Unless required by applicable law or agreed to in writing, software\n",
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"See the License for the specific language governing permissions and\n",
"limitations under the License.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# vrp_node_max"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<table align=\"left\">\n",
"<td>\n",
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/master/examples/notebook/constraint_solver/vrp_node_max.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/master/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
"</td>\n",
"<td>\n",
"<a href=\"https://github.com/google/or-tools/blob/master/ortools/constraint_solver/samples/vrp_node_max.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/master/tools/github_32px.png\"/>View source on GitHub</a>\n",
"</td>\n",
"</table>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!pip install ortools"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
"# You may obtain a copy of the License at\n",
"#\n",
"# http://www.apache.org/licenses/LICENSE-2.0\n",
"#\n",
"# Unless required by applicable law or agreed to in writing, software\n",
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"# [START program]\n",
"\"\"\"Vehicles Routing Problem (VRP).\n",
"\n",
"Each route as an associated objective cost equal to the max node value along the\n",
"road multiply by a constant factor (4200)\n",
"\"\"\"\n",
"\n",
"# [START import]\n",
"from ortools.constraint_solver import routing_enums_pb2\n",
"from ortools.constraint_solver import pywrapcp\n",
"# [END import]\n",
"\n",
"\n",
"# [START data_model]\n",
"def create_data_model():\n",
" \"\"\"Stores the data for the problem.\"\"\"\n",
" data = {}\n",
" data['distance_matrix'] = [\n",
" [\n",
" 0, 548, 776, 696, 582, 274, 502, 194, 308, 194, 536, 502, 388, 354,\n",
" 468, 776, 662\n",
" ],\n",
" [\n",
" 548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480,\n",
" 674, 1016, 868, 1210\n",
" ],\n",
" [\n",
" 776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164,\n",
" 1130, 788, 1552, 754\n",
" ],\n",
" [\n",
" 696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628,\n",
" 822, 1164, 560, 1358\n",
" ],\n",
" [\n",
" 582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514,\n",
" 708, 1050, 674, 1244\n",
" ],\n",
" [\n",
" 274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628,\n",
" 514, 1050, 708\n",
" ],\n",
" [\n",
" 502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890,\n",
" 856, 514, 1278, 480\n",
" ],\n",
" [\n",
" 194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320,\n",
" 662, 742, 856\n",
" ],\n",
" [\n",
" 308, 696, 468, 844, 730, 194, 194, 342, 0, 274, 388, 810, 696, 662,\n",
" 320, 1084, 514\n",
" ],\n",
" [\n",
" 194, 742, 742, 890, 776, 240, 468, 388, 274, 0, 342, 536, 422, 388,\n",
" 274, 810, 468\n",
" ],\n",
" [\n",
" 536, 1084, 400, 1232, 1118, 582, 354, 730, 388, 342, 0, 878, 764,\n",
" 730, 388, 1152, 354\n",
" ],\n",
" [\n",
" 502, 594, 1278, 514, 400, 776, 1004, 468, 810, 536, 878, 0, 114,\n",
" 308, 650, 274, 844\n",
" ],\n",
" [\n",
" 388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0,\n",
" 194, 536, 388, 730\n",
" ],\n",
" [\n",
" 354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194,\n",
" 0, 342, 422, 536\n",
" ],\n",
" [\n",
" 468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536,\n",
" 342, 0, 764, 194\n",
" ],\n",
" [\n",
" 776, 868, 1552, 560, 674, 1050, 1278, 742, 1084, 810, 1152, 274,\n",
" 388, 422, 764, 0, 798\n",
" ],\n",
" [\n",
" 662, 1210, 754, 1358, 1244, 708, 480, 856, 514, 468, 354, 844, 730,\n",
" 536, 194, 798, 0\n",
" ],\n",
" ]\n",
" data['value'] = [\n",
" 0, # depot\n",
" 42, # 1\n",
" 42, # 2\n",
" 8, # 3\n",
" 8, # 4\n",
" 8, # 5\n",
" 8, # 6\n",
" 8, # 7\n",
" 8, # 8\n",
" 8, # 9\n",
" 8, # 10\n",
" 8, # 11\n",
" 8, # 12\n",
" 8, # 13\n",
" 8, # 14\n",
" 42, # 15\n",
" 42, # 16\n",
" ]\n",
" assert len(data['distance_matrix']) == len(data['value'])\n",
" data['num_vehicles'] = 4\n",
" data['depot'] = 0\n",
" return data\n",
"# [END data_model]\n",
"\n",
"\n",
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" max_route_distance = 0\n",
" dim_one = routing.GetDimensionOrDie('One')\n",
" dim_two = routing.GetDimensionOrDie('Two')\n",
"\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",
" plan_output = 'Route for vehicle {}:\\n'.format(vehicle_id)\n",
" route_distance = 0\n",
" while not routing.IsEnd(index):\n",
" one_var = dim_one.CumulVar(index)\n",
" one_slack_var = dim_one.SlackVar(index)\n",
" two_var = dim_two.CumulVar(index)\n",
" two_slack_var = dim_two.SlackVar(index)\n",
" plan_output += ' N:{0} one:({1},{2}) two:({3},{4}) -> '.format(\n",
" manager.IndexToNode(index), solution.Value(one_var),\n",
" solution.Value(one_slack_var), solution.Value(two_var),\n",
" solution.Value(two_slack_var))\n",
" previous_index = index\n",
" index = solution.Value(routing.NextVar(index))\n",
" route_distance += routing.GetArcCostForVehicle(\n",
" previous_index, index, vehicle_id)\n",
" one_var = dim_one.CumulVar(index)\n",
" two_var = dim_two.CumulVar(index)\n",
" plan_output += 'N:{0} one:{1} two:{2}\\n'.format(\n",
" manager.IndexToNode(index), solution.Value(one_var),\n",
" solution.Value(two_var))\n",
" plan_output += 'Distance of the route: {}m\\n'.format(route_distance)\n",
" print(plan_output)\n",
" max_route_distance = max(route_distance, max_route_distance)\n",
" print('Maximum of the route distances: {}m'.format(max_route_distance))\n",
"# [END solution_printer]\n",
"\n",
"\n",
"\"\"\"Solve the CVRP problem.\"\"\"\n",
"# Instantiate the data problem.\n",
"# [START data]\n",
"data = create_data_model()\n",
"# [END data]\n",
"\n",
"# Create the routing index manager.\n",
"# [START index_manager]\n",
"manager = pywrapcp.RoutingIndexManager(\n",
" len(data['distance_matrix']),\n",
" data['num_vehicles'],\n",
" data['depot'])\n",
"# [END index_manager]\n",
"\n",
"# Create Routing Model.\n",
"# [START routing_model]\n",
"routing = pywrapcp.RoutingModel(manager)\n",
"# [END routing_model]\n",
"\n",
"# Create and register a transit callback.\n",
"# [START transit_callback]\n",
"def distance_callback(from_index, to_index):\n",
" \"\"\"Returns the distance between the two nodes.\"\"\"\n",
" # Convert from routing variable Index to distance matrix NodeIndex.\n",
" from_node = manager.IndexToNode(from_index)\n",
" to_node = manager.IndexToNode(to_index)\n",
" return data['distance_matrix'][from_node][to_node]\n",
"\n",
"transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n",
"# [END transit_callback]\n",
"\n",
"# Define cost of each arc.\n",
"# [START arc_cost]\n",
"routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n",
"# [END arc_cost]\n",
"\n",
"# Add Distance constraint.\n",
"# [START distance_constraint]\n",
"dimension_name = 'Distance'\n",
"routing.AddDimension(\n",
" transit_callback_index,\n",
" 0, # no slack\n",
" 3_000, # vehicle maximum travel distance\n",
" True, # start cumul to zero\n",
" dimension_name)\n",
"distance_dimension = routing.GetDimensionOrDie(dimension_name)\n",
"distance_dimension.SetGlobalSpanCostCoefficient(10)\n",
"# [END distance_constraint]\n",
"\n",
"# Max Node value Constraint.\n",
"# Dimension One will be used to compute the max node value up to the node in\n",
"# the route and store the result in the SlackVar of the node.\n",
"routing.AddConstantDimensionWithSlack(\n",
" 0, # transit 0\n",
" 42 * 16, # capacity: be able to store PEAK*ROUTE_LENGTH in worst case\n",
" 42, # slack_max: to be able to store peak in slack\n",
" True, # Fix StartCumulToZero not really matter here\n",
" 'One')\n",
"dim_one = routing.GetDimensionOrDie('One')\n",
"\n",
"# Dimension Two will be used to store the max node value in the route end node\n",
"# CumulVar so we can use it as an objective cost.\n",
"routing.AddConstantDimensionWithSlack(\n",
" 0, # transit 0\n",
" 42 * 16, # capacity: be able to have PEAK value in CumulVar(End)\n",
" 42, # slack_max: to be able to store peak in slack\n",
" True, # Fix StartCumulToZero YES here\n",
" 'Two')\n",
"dim_two = routing.GetDimensionOrDie('Two')\n",
"\n",
"# force depot Slack to be value since we don't have any predecessor...\n",
"# Slack(Depot) = value(Depot)\n",
"for v in range(manager.GetNumberOfVehicles()):\n",
" start = routing.Start(v)\n",
" dim_one.SlackVar(start).SetValue(data['value'][0])\n",
" routing.AddToAssignment(dim_one.SlackVar(start))\n",
"\n",
" dim_two.SlackVar(start).SetValue(data['value'][0])\n",
" routing.AddToAssignment(dim_two.SlackVar(start))\n",
"\n",
"# Step by step relation\n",
"# Slack(N) = max( Slack(N-1) , value(N) )\n",
"solver = routing.solver()\n",
"for node in range(1, 17):\n",
" index = manager.NodeToIndex(node)\n",
" routing.AddToAssignment(dim_one.SlackVar(index))\n",
" routing.AddToAssignment(dim_two.SlackVar(index))\n",
" test = []\n",
" for v in range(manager.GetNumberOfVehicles()):\n",
" previous_index = routing.Start(v)\n",
" cond = routing.NextVar(previous_index) == index\n",
" value = solver.Max(dim_one.SlackVar(previous_index),\n",
" data['value'][node])\n",
" test.append((cond * value).Var())\n",
" for previous in range(1, 17):\n",
" previous_index = manager.NodeToIndex(previous)\n",
" cond = routing.NextVar(previous_index) == index\n",
" value = solver.Max(dim_one.SlackVar(previous_index),\n",
" data['value'][node])\n",
" test.append((cond * value).Var())\n",
" solver.Add(solver.Sum(test) == dim_one.SlackVar(index))\n",
"\n",
"# relation between dimensions, copy last node Slack from dim ONE to dim TWO\n",
"for node in range(1, 17):\n",
" index = manager.NodeToIndex(node)\n",
" values = []\n",
" for v in range(manager.GetNumberOfVehicles()):\n",
" next_index = routing.End(v)\n",
" cond = routing.NextVar(index) == next_index\n",
" value = dim_one.SlackVar(index)\n",
" values.append((cond * value).Var())\n",
" solver.Add(solver.Sum(values) == dim_two.SlackVar(index))\n",
"\n",
"# Should force all others dim_two slack var to zero...\n",
"for v in range(manager.GetNumberOfVehicles()):\n",
" end = routing.End(v)\n",
" dim_two.SetCumulVarSoftUpperBound(end, 0, 4200)\n",
"\n",
"# Setting first solution heuristic.\n",
"# [START parameters]\n",
"search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n",
"search_parameters.first_solution_strategy = (\n",
" routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n",
"search_parameters.local_search_metaheuristic = (\n",
" routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n",
"# search_parameters.log_search = True\n",
"search_parameters.time_limit.FromSeconds(5)\n",
"# [END parameters]\n",
"\n",
"# Solve the problem.\n",
"# [START solve]\n",
"solution = routing.SolveWithParameters(search_parameters)\n",
"# [END solve]\n",
"\n",
"# Print solution on console.\n",
"# [START print_solution]\n",
"if solution:\n",
" print_solution(data, manager, routing, solution)\n",
"else:\n",
" print('No solution found !')\n",
"# [END print_solution]\n",
"\n"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -183,6 +184,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" total_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -183,6 +184,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, assignment):\n",
" \"\"\"Prints assignment on console.\"\"\"\n",
" print(f'Objective: {assignment.ObjectiveValue()}')\n",
" total_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -183,6 +184,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, assignment):\n",
" \"\"\"Prints assignment on console.\"\"\"\n",
" print(f'Objective: {assignment.ObjectiveValue()}')\n",
" total_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -144,6 +145,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" time_dimension = routing.GetDimensionOrDie('Time')\n",
" total_time = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -174,6 +175,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" max_route_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",

View File

@@ -140,6 +140,7 @@
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" time_dimension = routing.GetDimensionOrDie('Time')\n",
" total_time = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",

View File

@@ -68,7 +68,7 @@
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2020 Google LLC\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
"# You may obtain a copy of the License at\n",
@@ -80,37 +80,38 @@
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"\"\"\"\n",
"Simple VRP with special locations which need to be visited at end of the route.\n",
"\"\"\"\n",
"\"\"\"Simple VRP with special locations which need to be visited at end of the route.\"\"\"\n",
"\n",
"# [START import]\n",
"from ortools.constraint_solver import routing_enums_pb2\n",
"from ortools.constraint_solver import pywrapcp\n",
"# [END import]\n",
"\n",
"\n",
"def create_data_model():\n",
" \"\"\"Stores the data for the problem.\"\"\"\n",
" data = {}\n",
" # Special location don't consume token, while regular one consume one\n",
" data['tokens'] = [\n",
" 0, # 0 depot\n",
" 0, # 1 special node\n",
" 0, # 2 special node\n",
" 0, # 3 special node\n",
" 0, # 4 special node\n",
" 0, # 5 special node\n",
" -1, # 6\n",
" -1, # 7\n",
" -1, # 8\n",
" -1, # 9\n",
" -1, # 10\n",
" -1, # 11\n",
" -1, # 12\n",
" -1, # 13\n",
" -1, # 14\n",
" -1, # 15\n",
" -1, # 16\n",
" -1, # 17\n",
" -1, # 18\n",
" 0, # 0 depot\n",
" 0, # 1 special node\n",
" 0, # 2 special node\n",
" 0, # 3 special node\n",
" 0, # 4 special node\n",
" 0, # 5 special node\n",
" -1, # 6\n",
" -1, # 7\n",
" -1, # 8\n",
" -1, # 9\n",
" -1, # 10\n",
" -1, # 11\n",
" -1, # 12\n",
" -1, # 13\n",
" -1, # 14\n",
" -1, # 15\n",
" -1, # 16\n",
" -1, # 17\n",
" -1, # 18\n",
" ]\n",
" # just need to be big enough, not a limiting factor\n",
" data['vehicle_tokens'] = [20, 20, 20, 20]\n",
@@ -121,6 +122,7 @@
"\n",
"def print_solution(manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" token_dimension = routing.GetDimensionOrDie('Token')\n",
" total_distance = 0\n",
" total_token = 0\n",
@@ -155,10 +157,8 @@
"data = create_data_model()\n",
"\n",
"# Create the routing index manager.\n",
"manager = pywrapcp.RoutingIndexManager(\n",
" len(data['tokens']),\n",
" data['num_vehicles'],\n",
" data['depot'])\n",
"manager = pywrapcp.RoutingIndexManager(len(data['tokens']),\n",
" data['num_vehicles'], data['depot'])\n",
"\n",
"# Create Routing Model.\n",
"routing = pywrapcp.RoutingModel(manager)\n",
@@ -166,9 +166,8 @@
"# Create and register a transit callback.\n",
"def distance_callback(from_index, to_index):\n",
" \"\"\"Returns the distance between the two nodes.\"\"\"\n",
" # Convert from routing variable Index to distance matrix NodeIndex.\n",
" from_node = manager.IndexToNode(from_index)\n",
" to_node = manager.IndexToNode(to_index)\n",
" del from_index\n",
" del to_index\n",
" return 10\n",
"\n",
"transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n",
@@ -178,8 +177,8 @@
" 0, # null slack\n",
" 3000, # maximum distance per vehicle\n",
" True, # start cumul to zero\n",
" \"distance\")\n",
"distance_dimension = routing.GetDimensionOrDie(\"distance\")\n",
" 'distance')\n",
"distance_dimension = routing.GetDimensionOrDie('distance')\n",
"distance_dimension.SetGlobalSpanCostCoefficient(100)\n",
"\n",
"# Define cost of each arc.\n",
@@ -195,9 +194,9 @@
"token_callback_index = routing.RegisterUnaryTransitCallback(token_callback)\n",
"routing.AddDimensionWithVehicleCapacity(\n",
" token_callback_index,\n",
" 0, # null capacity slack\n",
" data['vehicle_tokens'], # vehicle maximum tokens\n",
" False, # start cumul to zero\n",
" 0, # null capacity slack\n",
" data['vehicle_tokens'], # vehicle maximum tokens\n",
" False, # start cumul to zero\n",
" 'Token')\n",
"# Add constraint: special node can only be visited if token remaining is zero\n",
"token_dimension = routing.GetDimensionOrDie('Token')\n",
@@ -205,6 +204,14 @@
" index = manager.NodeToIndex(node)\n",
" routing.solver().Add(token_dimension.CumulVar(index) == 0)\n",
"\n",
"# Instantiate route start and end times to produce feasible times.\n",
"# [START depot_start_end_times]\n",
"for i in range(manager.GetNumberOfVehicles()):\n",
" routing.AddVariableMinimizedByFinalizer(\n",
" token_dimension.CumulVar(routing.Start(i)))\n",
" routing.AddVariableMinimizedByFinalizer(\n",
" token_dimension.CumulVar(routing.End(i)))\n",
"# [END depot_start_end_times]\n",
"\n",
"# Setting first solution heuristic.\n",
"search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n",
@@ -218,10 +225,12 @@
"solution = routing.SolveWithParameters(search_parameters)\n",
"\n",
"# Print solution on console.\n",
"# [START print_solution]\n",
"if solution:\n",
" print_solution(manager, routing, solution)\n",
"else:\n",
" print(\"No solution found !\")\n",
" print('No solution found !')\n",
"# [END print_solution]\n",
"\n"
]
}

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -91,6 +92,7 @@
"# [START solution_printer]\n",
"def print_solution(manager, routing, solution):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {solution.ObjectiveValue()}')\n",
" max_route_distance = 0\n",
" for vehicle_id in range(manager.GetNumberOfVehicles()):\n",
" index = routing.Start(vehicle_id)\n",

View File

@@ -67,10 +67,9 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python\n",
"# This Python file uses the following encoding: utf-8\n",
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Copyright 2015 Tin Arm Engineering AB\n",
"# Copyright 2018 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
"# You may obtain a copy of the License at\n",
@@ -82,7 +81,8 @@
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"\"\"\"Vehicle Routing Problem (VRP).\n",
"# [START program]\n",
"\"\"\"Simple Vehicles Routing Problem (VRP).\n",
"\n",
" This is a sample using the routing library python wrapper to solve a VRP\n",
" problem.\n",
@@ -92,73 +92,108 @@
" Distances are in meters.\n",
"\"\"\"\n",
"\n",
"\n",
"from functools import partial\n",
"\n",
"from ortools.constraint_solver import pywrapcp\n",
"# [START import]\n",
"import functools\n",
"from ortools.constraint_solver import routing_enums_pb2\n",
"from ortools.constraint_solver import pywrapcp\n",
"# [END import]\n",
"\n",
"\n",
"###########################\n",
"# Problem Data Definition #\n",
"###########################\n",
"# [START data_model]\n",
"def create_data_model():\n",
" \"\"\"Stores the data for the problem\"\"\"\n",
" \"\"\"Stores the data for the problem.\"\"\"\n",
" data = {}\n",
" # Locations in block unit\n",
" _locations = \\\n",
" [(4, 4), # depot\n",
" (2, 0), (8, 0), # locations to visit\n",
" (0, 1), (1, 1),\n",
" (5, 2), (7, 2),\n",
" (3, 3), (6, 3),\n",
" (5, 5), (8, 5),\n",
" (1, 6), (2, 6),\n",
" (3, 7), (6, 7),\n",
" (0, 8), (7, 8)]\n",
" locations_ = [\n",
" (4, 4), # depot\n",
" (2, 0),\n",
" (8, 0), # locations to visit\n",
" (0, 1),\n",
" (1, 1),\n",
" (5, 2),\n",
" (7, 2),\n",
" (3, 3),\n",
" (6, 3),\n",
" (5, 5),\n",
" (8, 5),\n",
" (1, 6),\n",
" (2, 6),\n",
" (3, 7),\n",
" (6, 7),\n",
" (0, 8),\n",
" (7, 8),\n",
" ]\n",
" # Compute locations in meters using the block dimension defined as follow\n",
" # Manhattan average block: 750ft x 264ft -> 228m x 80m\n",
" # here we use: 114m x 80m city block\n",
" # src: https://nyti.ms/2GDoRIe 'NY Times: Know Your distance'\n",
" data['locations'] = [(l[0] * 114, l[1] * 80) for l in _locations]\n",
" data['locations'] = [(l[0] * 114, l[1] * 80) for l in locations_]\n",
" data['num_locations'] = len(data['locations'])\n",
" data['num_vehicles'] = 4\n",
" data['depot'] = 0\n",
" return data\n",
"\n",
"# [END data_model]\n",
"\n",
"\n",
"# [START solution_printer]\n",
"def print_solution(data, manager, routing, assignment):\n",
" \"\"\"Prints solution on console.\"\"\"\n",
" print(f'Objective: {assignment.ObjectiveValue()}')\n",
" total_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",
" plan_output = 'Route for vehicle {}:\\n'.format(vehicle_id)\n",
" route_distance = 0\n",
" while not routing.IsEnd(index):\n",
" plan_output += ' {} ->'.format(manager.IndexToNode(index))\n",
" previous_index = index\n",
" index = assignment.Value(routing.NextVar(index))\n",
" route_distance += routing.GetArcCostForVehicle(\n",
" previous_index, index, vehicle_id)\n",
" plan_output += ' {}\\n'.format(manager.IndexToNode(index))\n",
" plan_output += 'Distance of the route: {}m\\n'.format(route_distance)\n",
" print(plan_output)\n",
" total_distance += route_distance\n",
" print('Total Distance of all routes: {}m'.format(total_distance))\n",
"\n",
"# [END solution_printer]\n",
"\n",
"\n",
"#######################\n",
"# Problem Constraints #\n",
"#######################\n",
"def manhattan_distance(position_1, position_2):\n",
" \"\"\"Computes the Manhattan distance between two points\"\"\"\n",
" return (\n",
" abs(position_1[0] - position_2[0]) + abs(position_1[1] - position_2[1]))\n",
" \"\"\"Computes the Manhattan distance between two points.\"\"\"\n",
" return (abs(position_1[0] - position_2[0]) +\n",
" abs(position_1[1] - position_2[1]))\n",
"\n",
"\n",
"def create_distance_evaluator(data):\n",
" \"\"\"Creates callback to return distance between points.\"\"\"\n",
" _distances = {}\n",
" distances_ = {}\n",
" # precompute distance between location to have distance callback in O(1)\n",
" for from_node in range(data['num_locations']):\n",
" _distances[from_node] = {}\n",
" distances_[from_node] = {}\n",
" for to_node in range(data['num_locations']):\n",
" if from_node == to_node:\n",
" _distances[from_node][to_node] = 0\n",
" distances_[from_node][to_node] = 0\n",
" else:\n",
" _distances[from_node][to_node] = (manhattan_distance(\n",
" distances_[from_node][to_node] = (manhattan_distance(\n",
" data['locations'][from_node], data['locations'][to_node]))\n",
"\n",
" def distance_evaluator(manager, from_node, to_node):\n",
" \"\"\"Returns the manhattan distance between the two nodes\"\"\"\n",
" return _distances[manager.IndexToNode(from_node)][manager.IndexToNode(\n",
" to_node)]\n",
" def distance_evaluator(manager, from_index, to_index):\n",
" \"\"\"Returns the manhattan distance between the two nodes.\"\"\"\n",
" # Convert from routing variable Index to distance matrix NodeIndex.\n",
" from_node = manager.IndexToNode(from_index)\n",
" to_node = manager.IndexToNode(to_index)\n",
" return distances_[from_node][to_node]\n",
"\n",
" return distance_evaluator\n",
"\n",
"\n",
"def add_distance_dimension(routing, distance_evaluator_index):\n",
" \"\"\"Add Global Span constraint\"\"\"\n",
" \"\"\"Add Global Span constraint.\"\"\"\n",
" distance = 'Distance'\n",
" routing.AddDimension(\n",
" distance_evaluator_index,\n",
@@ -172,57 +207,58 @@
" distance_dimension.SetGlobalSpanCostCoefficient(100)\n",
"\n",
"\n",
"###########\n",
"# Printer #\n",
"###########\n",
"def print_solution(data, routing, manager, assignment): # pylint:disable=too-many-locals\n",
" \"\"\"Prints assignment on console\"\"\"\n",
" print('Objective: {}'.format(assignment.ObjectiveValue()))\n",
" total_distance = 0\n",
" for vehicle_id in range(data['num_vehicles']):\n",
" index = routing.Start(vehicle_id)\n",
" plan_output = 'Route for vehicle {}:\\n'.format(vehicle_id)\n",
" distance = 0\n",
" while not routing.IsEnd(index):\n",
" plan_output += ' {} ->'.format(manager.IndexToNode(index))\n",
" previous_index = index\n",
" index = assignment.Value(routing.NextVar(index))\n",
" distance += routing.GetArcCostForVehicle(previous_index, index,\n",
" vehicle_id)\n",
" plan_output += ' {}\\n'.format(manager.IndexToNode(index))\n",
" plan_output += 'Distance of the route: {}m\\n'.format(distance)\n",
" print(plan_output)\n",
" total_distance += distance\n",
" print('Total Distance of all routes: {}m'.format(total_distance))\n",
"\n",
"\n",
"########\n",
"# Main #\n",
"########\n",
"\"\"\"Entry point of the program\"\"\"\n",
"\"\"\"Entry point of the program.\"\"\"\n",
"# Instantiate the data problem.\n",
"# [START data]\n",
"data = create_data_model()\n",
"# [END data]\n",
"\n",
"# Create the routing index manager\n",
"# Create the routing index manager.\n",
"# [START index_manager]\n",
"manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n",
" data['num_vehicles'], data['depot'])\n",
"# [END index_manager]\n",
"\n",
"# Create Routing Model\n",
"# Create Routing Model.\n",
"# [START routing_model]\n",
"routing = pywrapcp.RoutingModel(manager)\n",
"# [END routing_model]\n",
"\n",
"# Define weight of each edge\n",
"# [START transit_callback]\n",
"distance_evaluator_index = routing.RegisterTransitCallback(\n",
" partial(create_distance_evaluator(data), manager))\n",
"routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n",
"add_distance_dimension(routing, distance_evaluator_index)\n",
" functools.partial(create_distance_evaluator(data), manager))\n",
"# [END transit_callback]\n",
"\n",
"# Setting first solution heuristic (cheapest addition).\n",
"# Define cost of each arc.\n",
"# [START arc_cost]\n",
"routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n",
"# [END arc_cost]\n",
"\n",
"# Add Distance constraint.\n",
"# [START distance_constraint]\n",
"add_distance_dimension(routing, distance_evaluator_index)\n",
"# [END distance_constraint]\n",
"\n",
"# Setting first solution heuristic.\n",
"# [START parameters]\n",
"search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n",
"search_parameters.first_solution_strategy = (\n",
" routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n",
" routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n",
"# [END parameters]\n",
"\n",
"# Solve the problem.\n",
"assignment = routing.SolveWithParameters(search_parameters)\n",
"print_solution(data, routing, manager, assignment)\n",
"# [START solve]\n",
"solution = routing.SolveWithParameters(search_parameters)\n",
"# [END solve]\n",
"\n",
"# Print solution on console.\n",
"# [START print_solution]\n",
"if solution:\n",
" print_solution(data, manager, routing, solution)\n",
"else:\n",
" print('No solution found !')\n",
"# [END print_solution]\n",
"\n"
]
}

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -94,9 +94,9 @@
"import collections\n",
"import math\n",
"\n",
"from google.protobuf import text_format\n",
"from absl import app\n",
"from absl import flags\n",
"from google.protobuf import text_format\n",
"from ortools.sat.python import cp_model\n",
"\n",
"FLAGS = flags.FLAGS\n",

View File

@@ -79,9 +79,22 @@
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"\"\"\"Solves a flexible jobshop problems with the CP-SAT solver.\"\"\"\n",
"\"\"\"Solves a flexible jobshop problems with the CP-SAT solver.\n",
"\n",
"A jobshop is a standard scheduling problem when you must sequence a\n",
"series of task_types on a set of machines. Each job contains one task_type per\n",
"machine. The order of execution and the length of each job on each\n",
"machine is task_type dependent.\n",
"\n",
"The objective is to minimize the maximum completion time of all\n",
"jobs. This is called the makespan.\n",
"\"\"\"\n",
"\n",
"# overloaded sum() clashes with pytype.\n",
"# pytype: disable=wrong-arg-types\n",
"\n",
"import collections\n",
"\n",
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
@@ -102,18 +115,18 @@
"def flexible_jobshop():\n",
" \"\"\"Solve a small flexible jobshop problem.\"\"\"\n",
" # Data part.\n",
" jobs = [ # task = (processing_time, machine_id)\n",
" [ # Job 0\n",
" [(3, 0), (1, 1), (5, 2)], # task 0 with 3 alternatives\n",
" [(2, 0), (4, 1), (6, 2)], # task 1 with 3 alternatives\n",
" [(2, 0), (3, 1), (1, 2)], # task 2 with 3 alternatives\n",
" jobs = [ # task = (processing_time, machine_id)\n",
" [ # Job 0\n",
" [(3, 0), (1, 1), (5, 2)], # task 0 with 3 alternatives\n",
" [(2, 0), (4, 1), (6, 2)], # task 1 with 3 alternatives\n",
" [(2, 0), (3, 1), (1, 2)], # task 2 with 3 alternatives\n",
" ],\n",
" [ # Job 1\n",
" [ # Job 1\n",
" [(2, 0), (3, 1), (4, 2)],\n",
" [(1, 0), (5, 1), (4, 2)],\n",
" [(2, 0), (1, 1), (4, 2)],\n",
" ],\n",
" [ # Job 2\n",
" [ # Job 2\n",
" [(2, 0), (1, 1), (4, 2)],\n",
" [(2, 0), (3, 1), (4, 2)],\n",
" [(3, 0), (1, 1), (5, 2)],\n",
@@ -177,7 +190,7 @@
" starts[(job_id, task_id)] = start\n",
"\n",
" # Add precedence with previous task in the same job.\n",
" if previous_end:\n",
" if previous_end is not None:\n",
" model.Add(start >= previous_end)\n",
" previous_end = end\n",
"\n",

View File

@@ -82,11 +82,10 @@
"\"\"\"Sat based solver for the RCPSP problems (see rcpsp.proto).\"\"\"\n",
"\n",
"import collections\n",
"import time\n",
"\n",
"from google.protobuf import text_format\n",
"from absl import app\n",
"from absl import flags\n",
"from google.protobuf import text_format\n",
"from ortools.data import pywraprcpsp\n",
"from ortools.sat.python import cp_model\n",
"\n",
@@ -99,42 +98,62 @@
"flags.DEFINE_bool('use_interval_makespan', True,\n",
" 'Whether we encode the makespan using an interval or not.')\n",
"flags.DEFINE_integer('horizon', -1, 'Force horizon.')\n",
"flags.DEFINE_bool(\n",
" 'use_main_interval_for_tasks', True,\n",
" 'Creates a main interval for each task, and use it in precedences')\n",
"\n",
"\n",
"class SolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solution_count = 0\n",
" self.__start_time = time.time()\n",
"\n",
" def on_solution_callback(self):\n",
" current_time = time.time()\n",
" objective = self.ObjectiveValue()\n",
" print('Solution %i, time = %f s, objective = %i' %\n",
" (self.__solution_count, current_time - self.__start_time,\n",
" objective))\n",
" self.__solution_count += 1\n",
"\n",
"\n",
"def SolveRcpsp(problem, proto_file, params):\n",
" \"\"\"Parse and solve a given RCPSP problem in proto format.\"\"\"\n",
"def PrintProblemStatistics(problem):\n",
" \"\"\"Display various statistics on the problem.\"\"\"\n",
"\n",
" # Determine problem type.\n",
" problem_type = ('Resource Investment Problem'\n",
" if problem.is_resource_investment else 'RCPSP')\n",
"\n",
" num_resources = len(problem.resources)\n",
" num_tasks = len(problem.tasks) - 2 # 2 sentinels.\n",
" tasks_with_alternatives = 0\n",
" variable_duration_tasks = 0\n",
" tasks_with_delay = 0\n",
"\n",
" for task in problem.tasks:\n",
" if len(task.recipes) > 1:\n",
" tasks_with_alternatives += 1\n",
" duration_0 = task.recipes[0].duration\n",
" for recipe in task.recipes:\n",
" if recipe.duration != duration_0:\n",
" variable_duration_tasks += 1\n",
" break\n",
" if task.successor_delays:\n",
" tasks_with_delay += 1\n",
"\n",
" if problem.is_rcpsp_max:\n",
" problem_type += '/Max delay'\n",
" # We print 2 less tasks as these are sentinel tasks that are not counted in\n",
" # the description of the rcpsp models.\n",
" if problem.is_consumer_producer:\n",
" print('Solving %s with %i reservoir resources and %i tasks' %\n",
" (problem_type, len(problem.resources), len(problem.tasks) - 2))\n",
" print(f'Solving {problem_type} with:')\n",
" print(f' - {num_resources} reservoir resources')\n",
" print(f' - {num_tasks} tasks')\n",
" else:\n",
" print('Solving %s with %i resources and %i tasks' %\n",
" (problem_type, len(problem.resources), len(problem.tasks) - 2))\n",
" print(f'Solving {problem_type} with:')\n",
" print(f' - {num_resources} renewable resources')\n",
" print(f' - {num_tasks} tasks')\n",
" if tasks_with_alternatives:\n",
" print(\n",
" f' - {tasks_with_alternatives} tasks with alternative resources'\n",
" )\n",
" if variable_duration_tasks:\n",
" print(\n",
" f' - {variable_duration_tasks} tasks with variable durations'\n",
" )\n",
" if tasks_with_delay:\n",
" print(f' - {tasks_with_delay} tasks with successor delays')\n",
"\n",
"\n",
"def SolveRcpsp(problem, proto_file, params):\n",
" \"\"\"Parse and solve a given RCPSP problem in proto format.\"\"\"\n",
" PrintProblemStatistics(problem)\n",
"\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
@@ -156,7 +175,7 @@
" for rd in sd.recipe_delays:\n",
" for d in rd.min_delays:\n",
" horizon += abs(d)\n",
" print(' - horizon = %i' % horizon)\n",
" print(f' - horizon = {horizon}')\n",
"\n",
" # Containers used to build resources.\n",
" intervals_per_resource = collections.defaultdict(list)\n",
@@ -164,37 +183,33 @@
" presences_per_resource = collections.defaultdict(list)\n",
" starts_per_resource = collections.defaultdict(list)\n",
"\n",
" # Starts and ends for master interval variables.\n",
" # Starts and ends for each task (shared between all alternatives)\n",
" task_starts = {}\n",
" task_ends = {}\n",
"\n",
" # Containers for per-recipe per task variables.\n",
" alternatives_per_task = collections.defaultdict(list)\n",
" # Containers for per-recipe per task alternatives variables.\n",
" presences_per_task = collections.defaultdict(list)\n",
" starts_per_task = collections.defaultdict(list)\n",
" ends_per_task = collections.defaultdict(list)\n",
" durations_per_task = collections.defaultdict(list)\n",
"\n",
" one = model.NewIntVar(1, 1, 'one')\n",
" one = model.NewConstant(1)\n",
"\n",
" # Create tasks.\n",
" # Create tasks variables.\n",
" for t in all_active_tasks:\n",
" task = problem.tasks[t]\n",
"\n",
" if len(task.recipes) == 1:\n",
" # Create interval.\n",
" # Create main and unique interval.\n",
" recipe = task.recipes[0]\n",
" task_starts[t] = model.NewIntVar(0, horizon, 'start_of_task_%i' % t)\n",
" task_ends[t] = model.NewIntVar(0, horizon, 'end_of_task_%i' % t)\n",
" task_starts[t] = model.NewIntVar(0, horizon, f'start_of_task_{t}')\n",
" task_ends[t] = model.NewIntVar(0, horizon, f'end_of_task_{t}')\n",
" interval = model.NewIntervalVar(task_starts[t], recipe.duration,\n",
" task_ends[t], 'interval_%i' % t)\n",
" task_ends[t], f'interval_{t}')\n",
"\n",
" # Store for later.\n",
" alternatives_per_task[t].append(interval)\n",
" starts_per_task[t].append(task_starts[t])\n",
" ends_per_task[t].append(task_ends[t])\n",
" # Store as a single alternative for later.\n",
" presences_per_task[t].append(one)\n",
" durations_per_task[t].append(recipe.duration)\n",
"\n",
" # Register for resources.\n",
" # Register the interval in resources specified by the demands.\n",
" for i in range(len(recipe.demands)):\n",
" demand = recipe.demands[i]\n",
" res = recipe.resources[i]\n",
@@ -204,30 +219,29 @@
" else:\n",
" starts_per_resource[res].append(task_starts[t])\n",
" presences_per_resource[res].append(1)\n",
" else:\n",
" else: # Multiple alternative recipes.\n",
" all_recipes = range(len(task.recipes))\n",
"\n",
" # Compute duration range.\n",
" min_size = min(recipe.duration for recipe in task.recipes)\n",
" max_size = max(recipe.duration for recipe in task.recipes)\n",
" start = model.NewIntVar(0, horizon, f'start_of_task_{t}')\n",
" end = model.NewIntVar(0, horizon, f'end_of_task_{t}')\n",
"\n",
" # Store for precedences.\n",
" task_starts[t] = start\n",
" task_ends[t] = end\n",
"\n",
" # Create one optional interval per recipe.\n",
" for r in all_recipes:\n",
" recipe = task.recipes[r]\n",
" is_present = model.NewBoolVar('is_present_%i_r%i' % (t, r))\n",
" start = model.NewIntVar(0, horizon, 'start_%i_r%i' % (t, r))\n",
" end = model.NewIntVar(0, horizon, 'end_%i_r%i' % (t, r))\n",
" interval = model.NewOptionalIntervalVar(\n",
" start, recipe.duration, end, is_present,\n",
" 'interval_%i_r%i' % (t, r))\n",
" is_present = model.NewBoolVar(f'is_present_{t}_{r}')\n",
" interval = model.NewOptionalIntervalVar(start, recipe.duration,\n",
" end, is_present,\n",
" f'interval_{t}_{r}')\n",
"\n",
" # Store variables.\n",
" alternatives_per_task[t].append(interval)\n",
" starts_per_task[t].append(start)\n",
" ends_per_task[t].append(end)\n",
" # Store alternative variables.\n",
" presences_per_task[t].append(is_present)\n",
" durations_per_task[t].append(recipe.duration)\n",
"\n",
" # Register intervals in resources.\n",
" # Register the interval in resources specified by the demands.\n",
" for i in range(len(recipe.demands)):\n",
" demand = recipe.demands[i]\n",
" res = recipe.resources[i]\n",
@@ -238,23 +252,24 @@
" starts_per_resource[res].append(start)\n",
" presences_per_resource[res].append(is_present)\n",
"\n",
" # Create the master interval for the task.\n",
" task_starts[t] = model.NewIntVar(0, horizon, 'start_of_task_%i' % t)\n",
" task_ends[t] = model.NewIntVar(0, horizon, 'end_of_task_%i' % t)\n",
" duration = model.NewIntVar(min_size, max_size,\n",
" 'duration_of_task_%i' % t)\n",
" interval = model.NewIntervalVar(task_starts[t], duration,\n",
" task_ends[t], 'interval_%i' % t)\n",
"\n",
" # Link with optional per-recipe copies.\n",
" for r in all_recipes:\n",
" p = presences_per_task[t][r]\n",
" model.Add(\n",
" task_starts[t] == starts_per_task[t][r]).OnlyEnforceIf(p)\n",
" model.Add(task_ends[t] == ends_per_task[t][r]).OnlyEnforceIf(p)\n",
" model.Add(duration == task.recipes[r].duration).OnlyEnforceIf(p)\n",
" # Exactly one alternative must be performed.\n",
" model.Add(sum(presences_per_task[t]) == 1)\n",
"\n",
" # linear encoding of the duration.\n",
" min_duration = min(durations_per_task[t])\n",
" max_duration = max(durations_per_task[t])\n",
" shifted = [x - min_duration for x in durations_per_task[t]]\n",
"\n",
" duration = model.NewIntVar(min_duration, max_duration,\n",
" f'duration_of_task_{t}')\n",
" model.Add(\n",
" duration == min_duration +\n",
" cp_model.LinearExpr.ScalProd(presences_per_task[t], shifted))\n",
"\n",
" # We do not create a 'main' interval. Instead, we link start, end, and\n",
" # duration.\n",
" model.Add(start + duration == end)\n",
"\n",
" # Create makespan variable\n",
" makespan = model.NewIntVar(0, horizon, 'makespan')\n",
" interval_makespan = model.NewIntervalVar(\n",
@@ -263,6 +278,8 @@
"\n",
" # Add precedences.\n",
" if problem.is_rcpsp_max:\n",
" # In RCPSP/Max problem, precedences are given and max delay (possible\n",
" # negative) between the starts of two tasks.\n",
" for task_id in all_active_tasks:\n",
" task = problem.tasks[task_id]\n",
" num_modes = len(task.recipes)\n",
@@ -272,7 +289,7 @@
" delay_matrix = task.successor_delays[successor_index]\n",
" num_next_modes = len(problem.tasks[next_id].recipes)\n",
" for m1 in range(num_modes):\n",
" s1 = starts_per_task[task_id][m1]\n",
" s1 = task_starts[task_id]\n",
" p1 = presences_per_task[task_id][m1]\n",
" if next_id == num_tasks - 1:\n",
" delay = delay_matrix.recipe_delays[m1].min_delays[0]\n",
@@ -281,22 +298,21 @@
" for m2 in range(num_next_modes):\n",
" delay = delay_matrix.recipe_delays[m1].min_delays[\n",
" m2]\n",
" s2 = starts_per_task[next_id][m2]\n",
" s2 = task_starts[next_id]\n",
" p2 = presences_per_task[next_id][m2]\n",
" model.Add(s1 + delay <= s2).OnlyEnforceIf([p1, p2])\n",
" else: # Normal dependencies (task ends before the start of successors).\n",
" else:\n",
" # Normal dependencies (task ends before the start of successors).\n",
" for t in all_active_tasks:\n",
" for n in problem.tasks[t].successors:\n",
" if n == num_tasks - 1:\n",
" # TODO(user): I guess these are still useful, but we might want to\n",
" # experiment with removing them.\n",
" model.Add(task_ends[t] <= makespan)\n",
" else:\n",
" model.Add(task_ends[t] <= task_starts[n])\n",
"\n",
" # Containers for resource investment problems.\n",
" capacities = []\n",
" max_cost = 0\n",
" capacities = [] # Capacity variables for all resources.\n",
" max_cost = 0 # Upper bound on the investment cost.\n",
"\n",
" # Create resources.\n",
" for r in all_resources:\n",
@@ -307,7 +323,7 @@
"\n",
" if problem.is_resource_investment:\n",
" # RIP problems have only renewable resources.\n",
" capacity = model.NewIntVar(0, c, 'capacity_of_%i' % r)\n",
" capacity = model.NewIntVar(0, c, f'capacity_of_{r}')\n",
" model.AddCumulative(intervals_per_resource[r],\n",
" demands_per_resource[r], capacity)\n",
" capacities.append(capacity)\n",
@@ -345,7 +361,7 @@
" model.Minimize(objective)\n",
"\n",
" if proto_file:\n",
" print('Writing proto to %s' % proto_file)\n",
" print(f'Writing proto to{proto_file}')\n",
" with open(proto_file, 'w') as text_file:\n",
" text_file.write(str(model))\n",
"\n",
@@ -353,9 +369,8 @@
" solver = cp_model.CpSolver()\n",
" if params:\n",
" text_format.Parse(params, solver.parameters)\n",
" solution_printer = SolutionPrinter()\n",
" solver.SolveWithSolutionCallback(model, solution_printer)\n",
" print(solver.ResponseStats())\n",
" solver.parameters.log_search_progress = True\n",
" solver.Solve(model)\n",
"\n",
"\n",
"rcpsp_parser = pywraprcpsp.RcpspParser()\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2021 Xiang Chen\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
@@ -116,14 +117,14 @@
" for i in range(num_tasks - 1):\n",
" for j in range(i + 1, num_tasks):\n",
" tmp_array = [precedences[(i, j)], precedences[(j, i)]]\n",
" if presences[i] != 1:\n",
" if not cp_model.ObjectIsATrueLiteral(presences[i]):\n",
" tmp_array.append(presences[i].Not())\n",
" # Makes sure that if i is not performed, all precedences are false.\n",
" model.AddImplication(presences[i].Not(),\n",
" precedences[(i, j)].Not())\n",
" model.AddImplication(presences[i].Not(),\n",
" precedences[(j, i)].Not())\n",
" if presences[j] != 1:\n",
" if not cp_model.ObjectIsATrueLiteral(presences[j]):\n",
" tmp_array.append(presences[j].Not())\n",
" # Makes sure that if j is not performed, all precedences are false.\n",
" model.AddImplication(presences[j].Not(),\n",
@@ -192,10 +193,7 @@
" # Creates makespan variable.\n",
" makespan = model.NewIntVar(0, horizon, 'makespan')\n",
" for t in all_tasks:\n",
" if presences[t] == 1:\n",
" model.Add(ends[t] <= makespan)\n",
" else:\n",
" model.Add(ends[t] <= makespan).OnlyEnforceIf(presences[t])\n",
" model.Add(ends[t] <= makespan).OnlyEnforceIf(presences[t])\n",
"\n",
" # Minimizes makespan - fixed gain per tasks performed.\n",
" # As the fixed cost is less that the duration of the last interval,\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",

View File

@@ -67,6 +67,7 @@
"metadata": {},
"outputs": [],
"source": [
"#!/usr/bin/env python3\n",
"# Copyright 2010-2021 Google LLC\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",