287 lines
9.5 KiB
Plaintext
287 lines
9.5 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "google",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Copyright 2022 Google LLC."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "apache",
|
|
"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",
|
|
"id": "basename",
|
|
"metadata": {},
|
|
"source": [
|
|
"# crew"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "link",
|
|
"metadata": {},
|
|
"source": [
|
|
"<table align=\"left\">\n",
|
|
"<td>\n",
|
|
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/contrib/crew.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
|
"</td>\n",
|
|
"<td>\n",
|
|
"<a href=\"https://github.com/google/or-tools/blob/main/examples/contrib/crew.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
|
"</td>\n",
|
|
"</table>"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "doc",
|
|
"metadata": {},
|
|
"source": [
|
|
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "install",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"!pip install ortools"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "description",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n",
|
|
"\n",
|
|
" Crew allocation problem in Google CP Solver.\n",
|
|
"\n",
|
|
" From Gecode example crew\n",
|
|
" examples/crew.cc\n",
|
|
" '''\n",
|
|
" * Example: Airline crew allocation\n",
|
|
" *\n",
|
|
" * Assign 20 flight attendants to 10 flights. Each flight needs a certain\n",
|
|
" * number of cabin crew, and they have to speak certain languages.\n",
|
|
" * Every cabin crew member has two flights off after an attended flight.\n",
|
|
" *\n",
|
|
" '''\n",
|
|
"\n",
|
|
" Compare with the following models:\n",
|
|
" * MiniZinc: http://www.hakank.org/minizinc/crew.mzn\n",
|
|
" * Comet : http://www.hakank.org/comet/crew.co\n",
|
|
" * ECLiPSe : http://hakank.org/eclipse/crew.ecl\n",
|
|
" * SICStus : http://hakank.org/sicstus/crew.pl\n",
|
|
"\n",
|
|
"\n",
|
|
" This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n",
|
|
" Also see my other Google CP Solver models:\n",
|
|
" http://www.hakank.org/google_or_tools/\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "code",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import sys\n",
|
|
"from ortools.constraint_solver import pywrapcp\n",
|
|
"\n",
|
|
"\n",
|
|
"def main(sols=1):\n",
|
|
"\n",
|
|
" # Create the solver.\n",
|
|
" solver = pywrapcp.Solver(\"Crew\")\n",
|
|
"\n",
|
|
" #\n",
|
|
" # data\n",
|
|
" #\n",
|
|
" names = [\n",
|
|
" \"Tom\", \"David\", \"Jeremy\", \"Ron\", \"Joe\", \"Bill\", \"Fred\", \"Bob\", \"Mario\",\n",
|
|
" \"Ed\", \"Carol\", \"Janet\", \"Tracy\", \"Marilyn\", \"Carolyn\", \"Cathy\", \"Inez\",\n",
|
|
" \"Jean\", \"Heather\", \"Juliet\"\n",
|
|
" ]\n",
|
|
"\n",
|
|
" num_persons = len(names) # number of persons\n",
|
|
"\n",
|
|
" attributes = [\n",
|
|
" # steward, hostess, french, spanish, german\n",
|
|
" [1, 0, 0, 0, 1], # Tom = 1\n",
|
|
" [1, 0, 0, 0, 0], # David = 2\n",
|
|
" [1, 0, 0, 0, 1], # Jeremy = 3\n",
|
|
" [1, 0, 0, 0, 0], # Ron = 4\n",
|
|
" [1, 0, 0, 1, 0], # Joe = 5\n",
|
|
" [1, 0, 1, 1, 0], # Bill = 6\n",
|
|
" [1, 0, 0, 1, 0], # Fred = 7\n",
|
|
" [1, 0, 0, 0, 0], # Bob = 8\n",
|
|
" [1, 0, 0, 1, 1], # Mario = 9\n",
|
|
" [1, 0, 0, 0, 0], # Ed = 10\n",
|
|
" [0, 1, 0, 0, 0], # Carol = 11\n",
|
|
" [0, 1, 0, 0, 0], # Janet = 12\n",
|
|
" [0, 1, 0, 0, 0], # Tracy = 13\n",
|
|
" [0, 1, 0, 1, 1], # Marilyn = 14\n",
|
|
" [0, 1, 0, 0, 0], # Carolyn = 15\n",
|
|
" [0, 1, 0, 0, 0], # Cathy = 16\n",
|
|
" [0, 1, 1, 1, 1], # Inez = 17\n",
|
|
" [0, 1, 1, 0, 0], # Jean = 18\n",
|
|
" [0, 1, 0, 1, 1], # Heather = 19\n",
|
|
" [0, 1, 1, 0, 0] # Juliet = 20\n",
|
|
" ]\n",
|
|
"\n",
|
|
" # The columns are in the following order:\n",
|
|
" # staff : Overall number of cabin crew needed\n",
|
|
" # stewards : How many stewards are required\n",
|
|
" # hostesses : How many hostesses are required\n",
|
|
" # french : How many French speaking employees are required\n",
|
|
" # spanish : How many Spanish speaking employees are required\n",
|
|
" # german : How many German speaking employees are required\n",
|
|
" required_crew = [\n",
|
|
" [4, 1, 1, 1, 1, 1], # Flight 1\n",
|
|
" [5, 1, 1, 1, 1, 1], # Flight 2\n",
|
|
" [5, 1, 1, 1, 1, 1], # ..\n",
|
|
" [6, 2, 2, 1, 1, 1],\n",
|
|
" [7, 3, 3, 1, 1, 1],\n",
|
|
" [4, 1, 1, 1, 1, 1],\n",
|
|
" [5, 1, 1, 1, 1, 1],\n",
|
|
" [6, 1, 1, 1, 1, 1],\n",
|
|
" [6, 2, 2, 1, 1, 1], # ...\n",
|
|
" [7, 3, 3, 1, 1, 1] # Flight 10\n",
|
|
" ]\n",
|
|
"\n",
|
|
" num_flights = len(required_crew) # number of flights\n",
|
|
"\n",
|
|
" #\n",
|
|
" # declare variables\n",
|
|
" #\n",
|
|
" crew = {}\n",
|
|
" for i in range(num_flights):\n",
|
|
" for j in range(num_persons):\n",
|
|
" crew[(i, j)] = solver.IntVar(0, 1, \"crew[%i,%i]\" % (i, j))\n",
|
|
" crew_flat = [\n",
|
|
" crew[(i, j)] for i in range(num_flights) for j in range(num_persons)\n",
|
|
" ]\n",
|
|
"\n",
|
|
" # number of working persons\n",
|
|
" num_working = solver.IntVar(1, num_persons, \"num_working\")\n",
|
|
"\n",
|
|
" #\n",
|
|
" # constraints\n",
|
|
" #\n",
|
|
"\n",
|
|
" # number of working persons\n",
|
|
" solver.Add(num_working == solver.Sum([\n",
|
|
" solver.IsGreaterOrEqualCstVar(\n",
|
|
" solver.Sum([crew[(f, p)]\n",
|
|
" for f in range(num_flights)]), 1)\n",
|
|
" for p in range(num_persons)\n",
|
|
" ]))\n",
|
|
"\n",
|
|
" for f in range(num_flights):\n",
|
|
" # size of crew\n",
|
|
" tmp = [crew[(f, i)] for i in range(num_persons)]\n",
|
|
" solver.Add(solver.Sum(tmp) == required_crew[f][0])\n",
|
|
"\n",
|
|
" # attributes and requirements\n",
|
|
" for j in range(5):\n",
|
|
" tmp = [attributes[i][j] * crew[(f, i)] for i in range(num_persons)]\n",
|
|
" solver.Add(solver.Sum(tmp) >= required_crew[f][j + 1])\n",
|
|
"\n",
|
|
" # after a flight, break for at least two flights\n",
|
|
" for f in range(num_flights - 2):\n",
|
|
" for i in range(num_persons):\n",
|
|
" solver.Add(crew[f, i] + crew[f + 1, i] + crew[f + 2, i] <= 1)\n",
|
|
"\n",
|
|
" # extra contraint: all must work at least two of the flights\n",
|
|
" # for i in range(num_persons):\n",
|
|
" # [solver.Add(solver.Sum([crew[f,i] for f in range(num_flights)]) >= 2) ]\n",
|
|
"\n",
|
|
" #\n",
|
|
" # solution and search\n",
|
|
" #\n",
|
|
" solution = solver.Assignment()\n",
|
|
" solution.Add(crew_flat)\n",
|
|
" solution.Add(num_working)\n",
|
|
"\n",
|
|
" db = solver.Phase(crew_flat, solver.CHOOSE_FIRST_UNBOUND,\n",
|
|
" solver.ASSIGN_MIN_VALUE)\n",
|
|
"\n",
|
|
" #\n",
|
|
" # result\n",
|
|
" #\n",
|
|
" solver.NewSearch(db)\n",
|
|
" num_solutions = 0\n",
|
|
" while solver.NextSolution():\n",
|
|
" num_solutions += 1\n",
|
|
" print(\"Solution #%i\" % num_solutions)\n",
|
|
" print(\"Number working:\", num_working.Value())\n",
|
|
" for i in range(num_flights):\n",
|
|
" for j in range(num_persons):\n",
|
|
" print(crew[i, j].Value(), end=\" \")\n",
|
|
" print()\n",
|
|
" print()\n",
|
|
"\n",
|
|
" print(\"Flights:\")\n",
|
|
" for flight in range(num_flights):\n",
|
|
" print(\"Flight\", flight, \"persons:\", end=\" \")\n",
|
|
" for person in range(num_persons):\n",
|
|
" if crew[flight, person].Value() == 1:\n",
|
|
" print(names[person], end=\" \")\n",
|
|
" print()\n",
|
|
" print()\n",
|
|
"\n",
|
|
" print(\"Crew:\")\n",
|
|
" for person in range(num_persons):\n",
|
|
" print(\"%-10s flights\" % names[person], end=\" \")\n",
|
|
" for flight in range(num_flights):\n",
|
|
" if crew[flight, person].Value() == 1:\n",
|
|
" print(flight, end=\" \")\n",
|
|
" print()\n",
|
|
" print()\n",
|
|
"\n",
|
|
" if num_solutions >= sols:\n",
|
|
" break\n",
|
|
" solver.EndSearch()\n",
|
|
"\n",
|
|
" print()\n",
|
|
" print(\"num_solutions:\", num_solutions)\n",
|
|
" print(\"failures:\", solver.Failures())\n",
|
|
" print(\"branches:\", solver.Branches())\n",
|
|
" print(\"WallTime:\", solver.WallTime())\n",
|
|
"\n",
|
|
"\n",
|
|
"num_solutions_to_show = 1\n",
|
|
"if (len(sys.argv) > 1):\n",
|
|
" num_solutions_to_show = int(sys.argv[1])\n",
|
|
"\n",
|
|
"main(num_solutions_to_show)\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|