regenerate all notebooks
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
|
||||
@@ -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",
|
||||
|
||||
381
examples/notebook/constraint_solver/vrp_node_max.ipynb
Normal file
381
examples/notebook/constraint_solver/vrp_node_max.ipynb
Normal 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
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user