update notebooks to remove main() method

This commit is contained in:
Laurent Perron
2018-09-05 14:27:48 +02:00
parent 466b2ee0e7
commit c0eac159c2
18 changed files with 1234 additions and 2296 deletions

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -24,72 +22,64 @@
"from __future__ import print_function\n",
"from ortools.sat.python import cp_model\n",
"\n",
"def main():\n",
" # Instantiate a cp model.\n",
" cost = [[90, 76, 75, 70, 50, 74, 12, 68],\n",
" [35, 85, 55, 65, 48, 101, 70, 83],\n",
" [125, 95, 90, 105, 59, 120, 36, 73],\n",
" [45, 110, 95, 115, 104, 83, 37, 71],\n",
" [60, 105, 80, 75, 59, 62, 93, 88],\n",
" [45, 65, 110, 95, 47, 31, 81, 34],\n",
" [38, 51, 107, 41, 69, 99, 115, 48],\n",
" [47, 85, 57, 71, 92, 77, 109, 36],\n",
" [39, 63, 97, 49, 118, 56, 92, 61],\n",
" [47, 101, 71, 60, 88, 109, 52, 90]]\n",
"\n",
"# Instantiate a cp model.\n",
"cost = [[90, 76, 75, 70, 50, 74, 12, 68], [35, 85, 55, 65, 48, 101, 70, 83], [\n",
" 125, 95, 90, 105, 59, 120, 36, 73\n",
"], [45, 110, 95, 115, 104, 83, 37, 71], [60, 105, 80, 75, 59, 62, 93, 88], [\n",
" 45, 65, 110, 95, 47, 31, 81, 34\n",
"], [38, 51, 107, 41, 69, 99, 115, 48], [47, 85, 57, 71, 92, 77, 109, 36],\n",
" [39, 63, 97, 49, 118, 56, 92, 61], [47, 101, 71, 60, 88, 109, 52, 90]]\n",
"\n",
" sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n",
" total_size_max = 15\n",
" num_workers = len(cost)\n",
" num_tasks = len(cost[1])\n",
" all_workers = range(num_workers)\n",
" all_tasks = range(num_tasks)\n",
"sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n",
"total_size_max = 15\n",
"num_workers = len(cost)\n",
"num_tasks = len(cost[1])\n",
"all_workers = range(num_workers)\n",
"all_tasks = range(num_tasks)\n",
"\n",
" model = cp_model.CpModel()\n",
" # Variables\n",
" total_cost = model.NewIntVar(0, 1000, 'total_cost')\n",
" x = []\n",
"model = cp_model.CpModel()\n",
"# Variables\n",
"total_cost = model.NewIntVar(0, 1000, 'total_cost')\n",
"x = []\n",
"for i in all_workers:\n",
" t = []\n",
" for j in all_tasks:\n",
" t.append(model.NewBoolVar('x[%i,%i]' % (i, j)))\n",
" x.append(t)\n",
"\n",
"# Constraints\n",
"\n",
"# Each task is assigned to at least one worker.\n",
"[model.Add(sum(x[i][j] for i in all_workers) >= 1) for j in all_tasks]\n",
"\n",
"# Total task size for each worker is at most total_size_max\n",
"for i in all_workers:\n",
" model.Add(sum(sizes[j] * x[i][j] for j in all_tasks) <= total_size_max)\n",
"\n",
"# Total cost\n",
"model.Add(total_cost == sum(\n",
" x[i][j] * cost[i][j] for j in all_tasks for i in all_workers))\n",
"model.Minimize(total_cost)\n",
"\n",
"solver = cp_model.CpSolver()\n",
"status = solver.Solve(model)\n",
"\n",
"if status == cp_model.OPTIMAL:\n",
" print('Total cost = %i' % solver.ObjectiveValue())\n",
" print()\n",
" for i in all_workers:\n",
" t = []\n",
" for j in all_tasks:\n",
" t.append(model.NewBoolVar('x[%i,%i]' % (i, j)))\n",
" x.append(t)\n",
" if solver.Value(x[i][j]) == 1:\n",
" print('Worker ', i, ' assigned to task ', j, ' Cost = ', cost[i][j])\n",
"\n",
" # Constraints\n",
" print()\n",
"\n",
" # Each task is assigned to at least one worker.\n",
" [model.Add(sum(x[i][j] for i in all_workers) >= 1) for j in all_tasks]\n",
"\n",
" # Total task size for each worker is at most total_size_max\n",
" for i in all_workers:\n",
" model.Add(sum(sizes[j] * x[i][j] for j in all_tasks) <= total_size_max)\n",
"\n",
" # Total cost\n",
" model.Add(total_cost ==\n",
" sum(x[i][j] * cost[i][j] for j in all_tasks for i in all_workers))\n",
" model.Minimize(total_cost)\n",
"\n",
" solver = cp_model.CpSolver()\n",
" status = solver.Solve(model)\n",
"\n",
" if status == cp_model.OPTIMAL:\n",
" print('Total cost = %i' % solver.ObjectiveValue())\n",
" print()\n",
" for i in all_workers:\n",
" for j in all_tasks:\n",
" if solver.Value(x[i][j]) == 1:\n",
" print('Worker ', i, ' assigned to task ', j, ' Cost = ', cost[i][j])\n",
"\n",
" print()\n",
"\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f ms' % solver.WallTime())\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" main()"
"print('Statistics')\n",
"print(' - conflicts : %i' % solver.NumConflicts())\n",
"print(' - branches : %i' % solver.NumBranches())\n",
"print(' - wall time : %f ms' % solver.WallTime())\n",
"\n"
]
}
],

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -23,102 +21,102 @@
"from __future__ import print_function\n",
"from ortools.sat.python import cp_model\n",
"\n",
"def main():\n",
" # Data.\n",
" cost = [[90, 76, 75, 70, 50, 74],\n",
" [35, 85, 55, 65, 48, 101],\n",
" [125, 95, 90, 105, 59, 120],\n",
" [45, 110, 95, 115, 104, 83],\n",
" [60, 105, 80, 75, 59, 62],\n",
" [45, 65, 110, 95, 47, 31],\n",
" [38, 51, 107, 41, 69, 99],\n",
" [47, 85, 57, 71, 92, 77],\n",
" [39, 63, 97, 49, 118, 56],\n",
" [47, 101, 71, 60, 88, 109],\n",
" [17, 39, 103, 64, 61, 92],\n",
" [101, 45, 83, 59, 92, 27]]\n",
"\n",
" group1 = [[0, 0, 1, 1], # Workers 2, 3\n",
" [0, 1, 0, 1], # Workers 1, 3\n",
" [0, 1, 1, 0], # Workers 1, 2\n",
" [1, 1, 0, 0], # Workers 0, 1\n",
" [1, 0, 1, 0]] # Workers 0, 2\n",
"# Data.\n",
"cost = [[90, 76, 75, 70, 50, 74], [35, 85, 55, 65, 48,\n",
" 101], [125, 95, 90, 105, 59, 120],\n",
" [45, 110, 95, 115, 104, 83], [60, 105, 80, 75, 59, 62], [\n",
" 45, 65, 110, 95, 47, 31\n",
" ], [38, 51, 107, 41, 69, 99], [47, 85, 57, 71,\n",
" 92, 77], [39, 63, 97, 49, 118, 56],\n",
" [47, 101, 71, 60, 88, 109], [17, 39, 103, 64, 61,\n",
" 92], [101, 45, 83, 59, 92, 27]]\n",
"\n",
" group2 = [[0, 0, 1, 1], # Workers 6, 7\n",
" [0, 1, 0, 1], # Workers 5, 7\n",
" [0, 1, 1, 0], # Workers 5, 6\n",
" [1, 1, 0, 0], # Workers 4, 5\n",
" [1, 0, 0, 1]] # Workers 4, 7\n",
"group1 = [\n",
" [0, 0, 1, 1], # Workers 2, 3\n",
" [0, 1, 0, 1], # Workers 1, 3\n",
" [0, 1, 1, 0], # Workers 1, 2\n",
" [1, 1, 0, 0], # Workers 0, 1\n",
" [1, 0, 1, 0]\n",
"] # Workers 0, 2\n",
"\n",
" group3 = [[0, 0, 1, 1], # Workers 10, 11\n",
" [0, 1, 0, 1], # Workers 9, 11\n",
" [0, 1, 1, 0], # Workers 9, 10\n",
" [1, 0, 1, 0], # Workers 8, 10\n",
" [1, 0, 0, 1]] # Workers 8, 11\n",
"group2 = [\n",
" [0, 0, 1, 1], # Workers 6, 7\n",
" [0, 1, 0, 1], # Workers 5, 7\n",
" [0, 1, 1, 0], # Workers 5, 6\n",
" [1, 1, 0, 0], # Workers 4, 5\n",
" [1, 0, 0, 1]\n",
"] # Workers 4, 7\n",
"\n",
"group3 = [\n",
" [0, 0, 1, 1], # Workers 10, 11\n",
" [0, 1, 0, 1], # Workers 9, 11\n",
" [0, 1, 1, 0], # Workers 9, 10\n",
" [1, 0, 1, 0], # Workers 8, 10\n",
" [1, 0, 0, 1]\n",
"] # Workers 8, 11\n",
"\n",
" sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n",
" total_size_max = 15\n",
" num_workers = len(cost)\n",
" num_tasks = len(cost[1])\n",
" all_workers = range(num_workers)\n",
" all_tasks = range(num_tasks)\n",
"sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n",
"total_size_max = 15\n",
"num_workers = len(cost)\n",
"num_tasks = len(cost[1])\n",
"all_workers = range(num_workers)\n",
"all_tasks = range(num_tasks)\n",
"\n",
" # Model.\n",
"# Model.\n",
"\n",
" model = cp_model.CpModel()\n",
" # Variables\n",
" total_cost = model.NewIntVar(0, 1000, 'total_cost')\n",
" x = [[model.NewBoolVar('x[%i,%i]' % (i, j)) for j in all_tasks]\n",
" for i in all_workers]\n",
" works = [model.NewBoolVar('works[%i]' % i) for i in all_workers]\n",
"model = cp_model.CpModel()\n",
"# Variables\n",
"total_cost = model.NewIntVar(0, 1000, 'total_cost')\n",
"x = [[model.NewBoolVar('x[%i,%i]' % (i, j))\n",
" for j in all_tasks]\n",
" for i in all_workers]\n",
"works = [model.NewBoolVar('works[%i]' % i) for i in all_workers]\n",
"\n",
" # Constraints\n",
"# Constraints\n",
"\n",
" # Link x and workers.\n",
" for i in range(num_workers):\n",
" model.AddMaxEquality(works[i], x[i])\n",
"# Link x and workers.\n",
"for i in range(num_workers):\n",
" model.AddMaxEquality(works[i], x[i])\n",
"\n",
" # Each task is assigned to at least one worker.\n",
" for j in all_tasks:\n",
" model.Add(sum(x[i][j] for i in all_workers) >= 1)\n",
"# Each task is assigned to at least one worker.\n",
"for j in all_tasks:\n",
" model.Add(sum(x[i][j] for i in all_workers) >= 1)\n",
"\n",
" # Total task size for each worker is at most total_size_max\n",
"# Total task size for each worker is at most total_size_max\n",
"for i in all_workers:\n",
" model.Add(sum(sizes[j] * x[i][j] for j in all_tasks) <= total_size_max)\n",
"\n",
"# Group constraints.\n",
"model.AddAllowedAssignments([works[0], works[1], works[2], works[3]], group1)\n",
"model.AddAllowedAssignments([works[4], works[5], works[6], works[7]], group2)\n",
"model.AddAllowedAssignments([works[8], works[9], works[10], works[11]],\n",
" group3)\n",
"\n",
"# Total cost\n",
"model.Add(total_cost == sum(\n",
" x[i][j] * cost[i][j] for j in all_tasks for i in all_workers))\n",
"model.Minimize(total_cost)\n",
"\n",
"# Solve and output solution.\n",
"solver = cp_model.CpSolver()\n",
"status = solver.Solve(model)\n",
"\n",
"if status == cp_model.OPTIMAL:\n",
" print('Total cost = %i' % solver.ObjectiveValue())\n",
" print()\n",
" for i in all_workers:\n",
" model.Add(sum(sizes[j] * x[i][j] for j in all_tasks) <= total_size_max)\n",
" for j in all_tasks:\n",
" if solver.Value(x[i][j]) == 1:\n",
" print('Worker ', i, ' assigned to task ', j, ' Cost = ', cost[i][j])\n",
"\n",
" # Group constraints.\n",
" model.AddAllowedAssignments([works[0], works[1], works[2], works[3]], group1)\n",
" model.AddAllowedAssignments([works[4], works[5], works[6], works[7]], group2)\n",
" model.AddAllowedAssignments([works[8], works[9], works[10], works[11]], group3)\n",
" print()\n",
"\n",
" # Total cost\n",
" model.Add(total_cost ==\n",
" sum(x[i][j] * cost[i][j] for j in all_tasks for i in all_workers))\n",
" model.Minimize(total_cost)\n",
"\n",
" # Solve and output solution.\n",
" solver = cp_model.CpSolver()\n",
" status = solver.Solve(model)\n",
"\n",
" if status == cp_model.OPTIMAL:\n",
" print('Total cost = %i' % solver.ObjectiveValue())\n",
" print()\n",
" for i in all_workers:\n",
" for j in all_tasks:\n",
" if solver.Value(x[i][j]) == 1:\n",
" print('Worker ', i, ' assigned to task ', j, ' Cost = ', cost[i][j])\n",
"\n",
" print()\n",
"\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f ms' % solver.WallTime())\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" main()"
"print('Statistics')\n",
"print(' - conflicts : %i' % solver.NumConflicts())\n",
"print(' - branches : %i' % solver.NumBranches())\n",
"print(' - wall time : %f ms' % solver.WallTime())\n",
"\n"
]
}
],

View File

@@ -0,0 +1,105 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\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",
"\n",
"# We are trying to group items in equal sized groups.\n",
"# Each item has a color and a value. We want the sum of values of each group to\n",
"# be as close to the average as possible.\n",
"# Furthermore, if one color is an a group, at least k items with this color must\n",
"# be in that group.\n",
"\n",
"from __future__ import print_function\n",
"from __future__ import division\n",
"\n",
"\n",
"from ortools.sat.python import cp_model\n",
"import math\n",
"\n",
"\n",
"# Data\n",
"\n",
"max_quantities = [ [\"N_Total\", 1944],\n",
" [\"P2O5\", 1166.4],\n",
" [\"K2O\", 1822.5],\n",
" [\"CaO\", 1458],\n",
" [\"MgO\", 486],\n",
" [\"Fe\", 9.7],\n",
" [\"B\", 2.4] ]\n",
"\n",
"chemical_set = [ [\"A\", 0, 0, 510, 540, 0, 0, 0],\n",
" [\"B\", 110, 0, 0, 0, 160, 0, 0],\n",
" [\"C\", 61, 149, 384, 0, 30, 1, 0.2],\n",
" [\"D\", 148, 70, 245, 0, 15, 1, 0.2],\n",
" [\"E\", 160, 158, 161, 0, 10, 1, 0.2] ]\n",
"\n",
"num_products = len(max_quantities)\n",
"all_products = range(num_products)\n",
"\n",
"num_sets = len(chemical_set)\n",
"all_sets = range(num_sets)\n",
"\n",
"# Model\n",
"\n",
"model = cp_model.CpModel()\n",
"\n",
"# Scale quantities by 100.\n",
"max_set = [int(math.ceil(min(max_quantities[q][1] * 1000 / chemical_set[s][q + 1]\n",
" for q in all_products\n",
" if chemical_set[s][q + 1] != 0)))\n",
" for s in all_sets]\n",
"\n",
"set_vars = [model.NewIntVar(0, max_set[s], 'set_%i' % s) for s in all_sets]\n",
"\n",
"epsilon = model.NewIntVar(0, 10000000, 'epsilon')\n",
"\n",
"for p in all_products:\n",
" model.Add(sum(int(chemical_set[s][p + 1] * 10) * set_vars[s]\n",
" for s in all_sets) <= int(max_quantities[p][1] * 10000))\n",
" model.Add(sum(int(chemical_set[s][p + 1] * 10) * set_vars[s]\n",
" for s in all_sets) >= int(max_quantities[p][1] * 10000) -\n",
" epsilon)\n",
"\n",
"model.Minimize(epsilon)\n",
"\n",
"# Creates a solver and solves.\n",
"solver = cp_model.CpSolver()\n",
"status = solver.Solve(model)\n",
"print('Status = %s' % solver.StatusName(status))\n",
"# The objective value of the solution.\n",
"print('Optimal objective value = %f' % (solver.ObjectiveValue() / 10000.0))\n",
"\n",
"for s in all_sets:\n",
" print(' %s = %f' % (chemical_set[s][0], solver.Value(set_vars[s]) / 1000.0),\n",
" end=' ')\n",
" print()\n",
"for p in all_products:\n",
" name = max_quantities[p][0]\n",
" max_quantity = max_quantities[p][1]\n",
" quantity = sum(solver.Value(set_vars[s]) / 1000.0 * chemical_set[s][p + 1]\n",
" for s in all_sets)\n",
" print('%s: %f out of %f' % (name, quantity, max_quantity))\n",
"\n"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
@@ -17,100 +17,282 @@
"# 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."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# limitations under the License.\n",
"\"\"\"SAT code samples used in documentation.\"\"\"\n",
"\n",
"from __future__ import absolute_import\n",
"from __future__ import division\n",
"from __future__ import print_function\n",
"\n",
"import collections\n",
"\n",
"from ortools.sat.python import cp_model"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def MinimalCpSat():\n",
" # Creates the model.\n",
" model = cp_model.CpModel()\n",
" # Creates the variables.\n",
" num_vals = 3\n",
" x = model.NewIntVar(0, num_vals - 1, \"x\")\n",
" y = model.NewIntVar(0, num_vals - 1, \"y\")\n",
" z = model.NewIntVar(0, num_vals - 1, \"z\")\n",
" # Create the constraints.\n",
" model.Add(x != y)\n",
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
"def CodeSample():\n",
" model = cp_model.CpModel()\n",
" x = model.NewBoolVar('x')\n",
" print(x)\n",
"\n",
"\n",
"def LiteralSample():\n",
" model = cp_model.CpModel()\n",
" x = model.NewBoolVar('x')\n",
" not_x = x.Not()\n",
" print(x)\n",
" print(not_x)\n",
"\n",
"\n",
"def BoolOrSample():\n",
" model = cp_model.CpModel()\n",
"\n",
" x = model.NewBoolVar('x')\n",
" y = model.NewBoolVar('y')\n",
"\n",
" model.AddBoolOr([x, y.Not()])\n",
"\n",
"\n",
"def ReifiedSample():\n",
" \"\"\"Showcase creating a reified constraint.\"\"\"\n",
" model = cp_model.CpModel()\n",
"\n",
" x = model.NewBoolVar('x')\n",
" y = model.NewBoolVar('y')\n",
" b = model.NewBoolVar('b')\n",
"\n",
" # First version using a half-reified bool and.\n",
" model.AddBoolAnd([x, y.Not()]).OnlyEnforceIf(b)\n",
"\n",
" # Second version using implications.\n",
" model.AddImplication(b, x)\n",
" model.AddImplication(b, y.Not())\n",
"\n",
" # Third version using bool or.\n",
" model.AddBoolOr([b.Not(), x])\n",
" model.AddBoolOr([b.Not(), y.Not()])\n",
"\n",
"\n",
"def RabbitsAndPheasants():\n",
" \"\"\"Solves the rabbits + pheasants problem.\"\"\"\n",
" model = cp_model.CpModel()\n",
"\n",
" r = model.NewIntVar(0, 100, 'r')\n",
" p = model.NewIntVar(0, 100, 'p')\n",
"\n",
" # 20 heads.\n",
" model.Add(r + p == 20)\n",
" # 56 legs.\n",
" model.Add(4 * r + 2 * p == 56)\n",
"\n",
" # Solves and prints out the solution.\n",
" solver = cp_model.CpSolver()\n",
" status = solver.Solve(model)\n",
"\n",
" if status == cp_model.FEASIBLE:\n",
" print('%i rabbits and %i pheasants' % (solver.Value(r), solver.Value(p)))\n",
"\n",
"\n",
"def BinpackingProblem():\n",
" \"\"\"Solves a bin-packing problem.\"\"\"\n",
" # Data.\n",
" bin_capacity = 100\n",
" slack_capacity = 20\n",
" num_bins = 10\n",
" all_bins = range(num_bins)\n",
"\n",
" items = [(20, 12), (15, 12), (30, 8), (45, 5)]\n",
" num_items = len(items)\n",
" all_items = range(num_items)\n",
"\n",
" # Model.\n",
" model = cp_model.CpModel()\n",
"\n",
" # Main variables.\n",
" x = {}\n",
" for i in all_items:\n",
" num_copies = items[i][1]\n",
" for b in all_bins:\n",
" x[(i, b)] = model.NewIntVar(0, num_copies, 'x_%i_%i' % (i, b))\n",
"\n",
" # Load variables.\n",
" load = [model.NewIntVar(0, bin_capacity, 'load_%i' % b) for b in all_bins]\n",
"\n",
" # Slack variables.\n",
" slacks = [model.NewBoolVar('slack_%i' % b) for b in all_bins]\n",
"\n",
" # Links load and x.\n",
" for b in all_bins:\n",
" model.Add(load[b] == sum(x[(i, b)] * items[i][0] for i in all_items))\n",
"\n",
" # Place all items.\n",
" for i in all_items:\n",
" model.Add(sum(x[(i, b)] for b in all_bins) == items[i][1])\n",
"\n",
" # Links load and slack through an equivalence relation.\n",
" safe_capacity = bin_capacity - slack_capacity\n",
" for b in all_bins:\n",
" # slack[b] => load[b] <= safe_capacity.\n",
" model.Add(load[b] <= safe_capacity).OnlyEnforceIf(slacks[b])\n",
" # not(slack[b]) => load[b] > safe_capacity.\n",
" model.Add(load[b] > safe_capacity).OnlyEnforceIf(slacks[b].Not())\n",
"\n",
" # Maximize sum of slacks.\n",
" model.Maximize(sum(slacks))\n",
"\n",
" # Solves and prints out the solution.\n",
" solver = cp_model.CpSolver()\n",
" status = solver.Solve(model)\n",
" print('Solve status: %s' % solver.StatusName(status))\n",
" if status == cp_model.OPTIMAL:\n",
" print('Optimal objective value: %i' % solver.ObjectiveValue())\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f s' % solver.WallTime())\n",
"\n",
"\n",
"def IntervalSample():\n",
" model = cp_model.CpModel()\n",
" horizon = 100\n",
" start_var = model.NewIntVar(0, horizon, 'start')\n",
" duration = 10 # Python cp/sat code accept integer variables or constants.\n",
" end_var = model.NewIntVar(0, horizon, 'end')\n",
" interval_var = model.NewIntervalVar(start_var, duration, end_var, 'interval')\n",
" print('start = %s, duration = %i, end = %s, interval = %s' %\n",
" (start_var, duration, end_var, interval_var))\n",
"\n",
"\n",
"def OptionalIntervalSample():\n",
" model = cp_model.CpModel()\n",
" horizon = 100\n",
" start_var = model.NewIntVar(0, horizon, 'start')\n",
" duration = 10 # Python cp/sat code accept integer variables or constants.\n",
" end_var = model.NewIntVar(0, horizon, 'end')\n",
" presence_var = model.NewBoolVar('presence')\n",
" interval_var = model.NewOptionalIntervalVar(start_var, duration, end_var,\n",
" presence_var, 'interval')\n",
" print('start = %s, duration = %i, end = %s, presence = %s, interval = %s' %\n",
" (start_var, duration, end_var, presence_var, interval_var))\n",
"\n",
"\n",
"def MinimalCpSat():\n",
" \"\"\"Minimal CP-SAT example to showcase calling the solver.\"\"\"\n",
" # Creates the model.\n",
" model = cp_model.CpModel()\n",
" # Creates the variables.\n",
" num_vals = 3\n",
" x = model.NewIntVar(0, num_vals - 1, 'x')\n",
" y = model.NewIntVar(0, num_vals - 1, 'y')\n",
" z = model.NewIntVar(0, num_vals - 1, 'z')\n",
" # Creates the constraints.\n",
" model.Add(x != y)\n",
"\n",
" # Creates a solver and solves the model.\n",
" solver = cp_model.CpSolver()\n",
" status = solver.Solve(model)\n",
"\n",
" if status == cp_model.FEASIBLE:\n",
" print('x = %i' % solver.Value(x))\n",
" print('y = %i' % solver.Value(y))\n",
" print('z = %i' % solver.Value(z))\n",
"\n",
"\n",
"def MinimalCpSatWithTimeLimit():\n",
" \"\"\"Minimal CP-SAT example to showcase calling the solver.\"\"\"\n",
" # Creates the model.\n",
" model = cp_model.CpModel()\n",
" # Creates the variables.\n",
" num_vals = 3\n",
" x = model.NewIntVar(0, num_vals - 1, 'x')\n",
" y = model.NewIntVar(0, num_vals - 1, 'y')\n",
" z = model.NewIntVar(0, num_vals - 1, 'z')\n",
" # Adds an all-different constraint.\n",
" model.Add(x != y)\n",
"\n",
" # Creates a solver and solves the model.\n",
" solver = cp_model.CpSolver()\n",
"\n",
" # Sets a time limit of 10 seconds.\n",
" solver.parameters.max_time_in_seconds = 10.0\n",
"\n",
" status = solver.Solve(model)\n",
"\n",
" if status == cp_model.FEASIBLE:\n",
" print('x = %i' % solver.Value(x))\n",
" print('y = %i' % solver.Value(y))\n",
" print('z = %i' % solver.Value(z))\n",
"\n",
"\n",
"# You need to subclass the cp_model.CpSolverSolutionCallback class.\n",
"class VarArrayAndObjectiveSolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self, variables):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__variables = variables\n",
" self.__solution_count = 0\n",
"\n",
" def OnSolutionCallback(self):\n",
" print('Solution %i' % self.__solution_count)\n",
" print(' objective value = %i' % self.ObjectiveValue())\n",
" for v in self.__variables:\n",
" print(' %s = %i' % (v, self.Value(v)), end=' ')\n",
" print()\n",
" self.__solution_count += 1\n",
"\n",
" def SolutionCount(self):\n",
" return self.__solution_count\n",
"\n",
"\n",
"def MinimalCpSatPrintIntermediateSolutions():\n",
" \"\"\"Showcases printing intermediate solutions found during search.\"\"\"\n",
" # Creates the model.\n",
" model = cp_model.CpModel()\n",
" # Creates the variables.\n",
" num_vals = 3\n",
" x = model.NewIntVar(0, num_vals - 1, 'x')\n",
" y = model.NewIntVar(0, num_vals - 1, 'y')\n",
" z = model.NewIntVar(0, num_vals - 1, 'z')\n",
" # Creates the constraints.\n",
" model.Add(x != y)\n",
" model.Maximize(x + 2 * y + 3 * z)\n",
"\n",
" # Creates a solver and solves.\n",
" solver = cp_model.CpSolver()\n",
" solution_printer = VarArrayAndObjectiveSolutionPrinter([x, y, z])\n",
" status = solver.SolveWithSolutionCallback(model, solution_printer)\n",
"\n",
" print('Status = %s' % solver.StatusName(status))\n",
" print('Number of solutions found: %i' % solution_printer.SolutionCount())\n",
"\n",
"\n",
" # Create a solver and solve.\n",
" solver = cp_model.CpSolver()\n",
" status = solver.Solve(model)\n",
" if status == cp_model.FEASIBLE:\n",
" print(\"x = %i\" % solver.Value(x))\n",
" print(\"y = %i\" % solver.Value(y))\n",
" print(\"z = %i\" % solver.Value(z))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x = 1\n",
"y = 0\n",
"z = 0\n"
]
}
],
"source": [
"MinimalCpSat()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self, variables):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__variables = variables\n",
" self.__solution_count = 0\n",
"\n",
" def NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" self.__solution_count += 1\n",
" for v in self.__variables:\n",
" print('%s=%i' % (v, self.Value(v)), end = ' ')\n",
" print('%s=%i' % (v, self.Value(v)), end=' ')\n",
" print()\n",
"\n",
" def SolutionCount(self):\n",
" return self.__solution_count\n",
"\n",
"\n",
"\n",
"\n",
"def MinimalCpSatAllSolutions():\n",
" \"\"\"Showcases calling the solver to search for all solutions.\"\"\"\n",
" # Creates the model.\n",
" model = cp_model.CpModel()\n",
"# Creates the variables.\n",
" # Creates the variables.\n",
" num_vals = 3\n",
" x = model.NewIntVar(0, num_vals - 1, \"x\")\n",
" y = model.NewIntVar(0, num_vals - 1, \"y\")\n",
" z = model.NewIntVar(0, num_vals - 1, \"z\")\n",
" x = model.NewIntVar(0, num_vals - 1, 'x')\n",
" y = model.NewIntVar(0, num_vals - 1, 'y')\n",
" z = model.NewIntVar(0, num_vals - 1, 'z')\n",
" # Create the constraints.\n",
" model.Add(x != y)\n",
"\n",
@@ -118,101 +300,36 @@
" solver = cp_model.CpSolver()\n",
" solution_printer = VarArraySolutionPrinter([x, y, z])\n",
" status = solver.SearchForAllSolutions(model, solution_printer)\n",
" print('Status = %s' % solver.StatusName(status))\n",
" print('Number of solutions found: %i' % solution_printer.SolutionCount())\n",
"\n",
"\n",
" print('Number of solutions found: %i' % solution_printer.SolutionCount())"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x=1 y=0 z=0 \n",
"x=2 y=0 z=0 \n",
"x=2 y=1 z=0 \n",
"x=2 y=1 z=1 \n",
"x=2 y=1 z=2 \n",
"x=2 y=0 z=2 \n",
"x=2 y=0 z=1 \n",
"x=1 y=0 z=1 \n",
"x=0 y=1 z=1 \n",
"x=0 y=1 z=2 \n",
"x=0 y=2 z=2 \n",
"x=1 y=2 z=2 \n",
"x=1 y=2 z=1 \n",
"x=1 y=2 z=0 \n",
"x=0 y=2 z=0 \n",
"x=0 y=1 z=0 \n",
"x=0 y=2 z=1 \n",
"x=1 y=0 z=2 \n",
"Number of solutions found: 18\n"
]
}
],
"source": [
"MinimalCpSatAllSolutions()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"def SolvingLinearProblem():\n",
" \"\"\"CP-SAT linear solver problem.\"\"\"\n",
" # Create a model.\n",
" model = cp_model.CpModel()\n",
"\n",
" # x and y are integer non-negative variables.\n",
" x = model.NewIntVar(0, 17, 'x')\n",
" y = model.NewIntVar(0, 17, 'y')\n",
" model.Add(2*x + 14*y <= 35)\n",
" model.Add(2*x <= 7)\n",
" obj_var = model.NewIntVar(0, 1000, \"obj_var\")\n",
" model.Add(obj_var == x + 10*y)\n",
" objective = model.Maximize(obj_var)\n",
" model.Add(2 * x + 14 * y <= 35)\n",
" model.Add(2 * x <= 7)\n",
" obj_var = model.NewIntVar(0, 1000, 'obj_var')\n",
" model.Add(obj_var == x + 10 * y)\n",
" model.Maximize(obj_var)\n",
"\n",
" # Create a solver and solve.\n",
" solver = cp_model.CpSolver()\n",
" status = solver.Solve(model)\n",
" if status == cp_model.OPTIMAL:\n",
" print(\"Objective value: %i\" % solver.ObjectiveValue())\n",
" print('Objective value: %i' % solver.ObjectiveValue())\n",
" print()\n",
" print('x= %i' % solver.Value(x))\n",
" print('y= %i' % solver.Value(y))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Objective value: 23\n",
"\n",
"x= 3\n",
"y= 2\n"
]
}
],
"source": [
"SolvingLinearProblem()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
" print('x= %i' % solver.Value(x))\n",
" print('y= %i' % solver.Value(y))\n",
"\n",
"\n",
"def MinimalJobShop():\n",
" \"\"\"Minimal jobshop problem.\"\"\"\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
"\n",
@@ -221,20 +338,17 @@
" all_machines = range(0, machines_count)\n",
" all_jobs = range(0, jobs_count)\n",
" # Define data.\n",
" machines = [[0, 1, 2],\n",
" [0, 2, 1],\n",
" [1, 2]]\n",
" machines = [[0, 1, 2], [0, 2, 1], [1, 2]]\n",
"\n",
" processing_times = [[3, 2, 2],\n",
" [2, 1, 4],\n",
" [4, 3]]\n",
" processing_times = [[3, 2, 2], [2, 1, 4], [4, 3]]\n",
" # Computes horizon.\n",
" horizon = 0\n",
" for job in all_jobs:\n",
" horizon += sum(processing_times[job])\n",
"\n",
" Task = collections.namedtuple('Task', 'start end interval')\n",
" AssignedTask = collections.namedtuple('AssignedTask', 'start job index')\n",
" task_type = collections.namedtuple('task_type', 'start end interval')\n",
" assigned_task_type = collections.namedtuple('assigned_task_type',\n",
" 'start job index')\n",
"\n",
" # Creates jobs.\n",
" all_tasks = {}\n",
@@ -245,9 +359,8 @@
" end_var = model.NewIntVar(0, horizon, 'end_%i_%i' % (job, index))\n",
" interval_var = model.NewIntervalVar(start_var, duration, end_var,\n",
" 'interval_%i_%i' % (job, index))\n",
" all_tasks[(job, index)] = Task(start=start_var,\n",
" end=end_var,\n",
" interval=interval_var)\n",
" all_tasks[(job, index)] = task_type(\n",
" start=start_var, end=end_var, interval=interval_var)\n",
"\n",
" # Creates sequence variables and add disjunctive constraints.\n",
" for machine in all_machines:\n",
@@ -261,14 +374,14 @@
" # Add precedence contraints.\n",
" for job in all_jobs:\n",
" for index in range(0, len(machines[job]) - 1):\n",
" model.Add(all_tasks[(job, index + 1)].start >=\n",
" all_tasks[(job, index)].end)\n",
" model.Add(all_tasks[(job, index + 1)].start >= all_tasks[(job,\n",
" index)].end)\n",
"\n",
" # Makespan objective.\n",
" obj_var = model.NewIntVar(0, horizon, 'makespan')\n",
" model.AddMaxEquality(\n",
" obj_var, [all_tasks[(job, len(machines[job]) - 1)].end\n",
" for job in all_jobs])\n",
" obj_var,\n",
" [all_tasks[(job, len(machines[job]) - 1)].end for job in all_jobs])\n",
" model.Minimize(obj_var)\n",
"\n",
" # Solve model.\n",
@@ -286,97 +399,75 @@
" for index in range(len(machines[job])):\n",
" machine = machines[job][index]\n",
" assigned_jobs[machine].append(\n",
" AssignedTask(start = solver.Value(all_tasks[(job, index)].start),\n",
" job = job, index = index))\n",
" assigned_task_type(\n",
" start=solver.Value(all_tasks[(job, index)].start),\n",
" job=job,\n",
" index=index))\n",
"\n",
" disp_col_width = 10\n",
" sol_line = \"\"\n",
" sol_line_tasks = \"\"\n",
" sol_line = ''\n",
" sol_line_tasks = ''\n",
"\n",
" print(\"Optimal Schedule\", \"\\n\")\n",
" print('Optimal Schedule', '\\n')\n",
"\n",
" for machine in all_machines:\n",
" # Sort by starting time.\n",
" assigned_jobs[machine].sort()\n",
" sol_line += \"Machine \" + str(machine) + \": \"\n",
" sol_line_tasks += \"Machine \" + str(machine) + \": \"\n",
" sol_line += 'Machine ' + str(machine) + ': '\n",
" sol_line_tasks += 'Machine ' + str(machine) + ': '\n",
"\n",
" for assigned_task in assigned_jobs[machine]:\n",
" name = 'job_%i_%i' % (assigned_task.job, assigned_task.index)\n",
" # Add spaces to output to align columns.\n",
" sol_line_tasks += name + \" \" * (disp_col_width - len(name))\n",
" # Add spaces to output to align columns.\n",
" sol_line_tasks += name + ' ' * (disp_col_width - len(name))\n",
" start = assigned_task.start\n",
" duration = processing_times[assigned_task.job][assigned_task.index]\n",
"\n",
" sol_tmp = \"[%i,%i]\" % (start, start + duration)\n",
" sol_tmp = '[%i,%i]' % (start, start + duration)\n",
" # Add spaces to output to align columns.\n",
" sol_line += sol_tmp + \" \" * (disp_col_width - len(sol_tmp))\n",
" sol_line += sol_tmp + ' ' * (disp_col_width - len(sol_tmp))\n",
"\n",
" sol_line += \"\\n\"\n",
" sol_line_tasks += \"\\n\"\n",
" sol_line += '\\n'\n",
" sol_line_tasks += '\\n'\n",
"\n",
" print(sol_line_tasks)\n",
" print(\"Time Intervals for Tasks\\n\")\n",
" print(sol_line)"
" print('Time Intervals for task_types\\n')\n",
" print(sol_line)\n",
"\n",
"\n",
"print('--- CodeSample ---')\n",
"CodeSample()\n",
"print('--- LiteralSample ---')\n",
"LiteralSample()\n",
"print('--- BoolOrSample ---')\n",
"BoolOrSample()\n",
"print('--- ReifiedSample ---')\n",
"ReifiedSample()\n",
"print('--- RabbitsAndPheasants ---')\n",
"RabbitsAndPheasants()\n",
"print('--- BinpackingProblem ---')\n",
"BinpackingProblem()\n",
"print('--- IntervalSample ---')\n",
"IntervalSample()\n",
"print('--- OptionalIntervalSample ---')\n",
"OptionalIntervalSample()\n",
"print('--- MinimalCpSat ---')\n",
"MinimalCpSat()\n",
"print('--- MinimalCpSatWithTimeLimit ---')\n",
"MinimalCpSatWithTimeLimit()\n",
"print('--- MinimalCpSatPrintIntermediateSolutions ---')\n",
"MinimalCpSatPrintIntermediateSolutions()\n",
"print('--- MinimalCpSatAllSolutions ---')\n",
"MinimalCpSatAllSolutions()\n",
"print('--- SolvingLinearProblem ---')\n",
"SolvingLinearProblem()\n",
"print('--- MinimalJobShop ---')\n",
"MinimalJobShop()\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Optimal Schedule Length: 11\n",
"\n",
"Optimal Schedule \n",
"\n",
"Machine 0: job_0_0 job_1_0 \n",
"Machine 1: job_2_0 job_0_1 job_1_2 \n",
"Machine 2: job_1_1 job_0_2 job_2_1 \n",
"\n",
"Time Intervals for Tasks\n",
"\n",
"Machine 0: [0,3] [3,5] \n",
"Machine 1: [0,4] [4,6] [7,11] \n",
"Machine 2: [5,6] [6,8] [8,11] \n",
"\n"
]
}
],
"source": [
"MinimalJobShop()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
}
},
"metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2011 Google\n",
@@ -20,9 +18,7 @@
"# 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",
"\"\"\"\n",
"Cryptarithmetic puzzle\n",
"\"\"\"Cryptarithmetic puzzle\n",
"\n",
"First attempt to solve equation CP + IS + FUN = TRUE\n",
"where each letter represents a unique digit.\n",
@@ -33,17 +29,19 @@
"from __future__ import print_function\n",
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
"class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self, variables):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__variables = variables\n",
" self.__solution_count = 0\n",
"\n",
" def NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" self.__solution_count += 1\n",
" for v in self.__variables:\n",
" print('%s=%i' % (v, self.Value(v)), end = ' ')\n",
" print('%s=%i' % (v, self.Value(v)), end=' ')\n",
" print()\n",
"\n",
" def SolutionCount(self):\n",
@@ -57,16 +55,16 @@
" # Constraint programming engine\n",
" model = cp_model.CpModel()\n",
"\n",
" c = model.NewIntVar(1, 9, 'C');\n",
" p = model.NewIntVar(0, 9, 'P');\n",
" i = model.NewIntVar(1, 9, 'I');\n",
" s = model.NewIntVar(0, 9, 'S');\n",
" f = model.NewIntVar(1, 9, 'F');\n",
" u = model.NewIntVar(0, 9, 'U');\n",
" n = model.NewIntVar(0, 9, 'N');\n",
" t = model.NewIntVar(1, 9, 'T');\n",
" r = model.NewIntVar(0, 9, 'R');\n",
" e = model.NewIntVar(0, 9, 'E');\n",
" c = model.NewIntVar(1, 9, 'C')\n",
" p = model.NewIntVar(0, 9, 'P')\n",
" i = model.NewIntVar(1, 9, 'I')\n",
" s = model.NewIntVar(0, 9, 'S')\n",
" f = model.NewIntVar(1, 9, 'F')\n",
" u = model.NewIntVar(0, 9, 'U')\n",
" n = model.NewIntVar(0, 9, 'N')\n",
" t = model.NewIntVar(1, 9, 'T')\n",
" r = model.NewIntVar(0, 9, 'R')\n",
" e = model.NewIntVar(0, 9, 'E')\n",
"\n",
" # We need to group variables in a list to use the constraint AllDifferent.\n",
" letters = [c, p, i, s, f, u, n, t, r, e]\n",
@@ -78,8 +76,8 @@
" model.AddAllDifferent(letters)\n",
"\n",
" # CP + IS + FUN = TRUE\n",
" model.Add(p + s + n + kBase * (c + i + u) + kBase * kBase * f ==\n",
" e + kBase * u + kBase * kBase * r + kBase * kBase * kBase * t)\n",
" model.Add(p + s + n + kBase * (c + i + u) + kBase * kBase * f == e +\n",
" kBase * u + kBase * kBase * r + kBase * kBase * kBase * t)\n",
"\n",
" solver = cp_model.CpSolver()\n",
" status = solver.Solve(model)\n",
@@ -96,9 +94,7 @@
" print(' - wall time : %f ms' % solver.WallTime())\n",
" print(' - solutions found : %i' % solution_printer.SolutionCount())\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" CPIsFun()"
"\n"
]
}
],

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -31,9 +29,10 @@
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solution_count = 0\n",
"\n",
" def NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" print('Solution %i, time = %f s, objective = %i' %\n",
" (self.__solution_count, self.WallTime(), self.ObjectiveValue()))\n",
" self.__solution_count += 1\n",
@@ -154,7 +153,7 @@
"# Solve model.\n",
"solver = cp_model.CpSolver()\n",
"solution_printer = SolutionPrinter()\n",
"status = solver.SolveWithSolutionObserver(model, solution_printer)\n",
"status = solver.SolveWithSolutionCallback(model, solution_printer)\n",
"\n",
"# Print final solution.\n",
"for job_id in all_jobs:\n",
@@ -177,7 +176,8 @@
"print('Statistics')\n",
"print(' - conflicts : %i' % solver.NumConflicts())\n",
"print(' - branches : %i' % solver.NumBranches())\n",
"print(' - wall time : %f s' % solver.WallTime())"
"print(' - wall time : %f s' % solver.WallTime())\n",
"\n"
]
}
],

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -20,7 +18,6 @@
"# 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",
"\"\"\"Gate Scheduling problem.\n",
"\n",
"We have a set of jobs to perform (duration, width).\n",
@@ -36,130 +33,109 @@
"from ortools.sat.python import visualization\n",
"\n",
"\n",
"def main():\n",
" model = cp_model.CpModel()\n",
"model = cp_model.CpModel()\n",
"\n",
" jobs = [[3, 3],\n",
" [2, 5],\n",
" [1, 3],\n",
" [3, 7],\n",
" [7, 3],\n",
" [2, 2],\n",
" [2, 2],\n",
" [5, 5],\n",
" [10, 2],\n",
" [4, 3],\n",
" [2, 6],\n",
" [1, 2],\n",
" [6, 8],\n",
" [4, 5],\n",
" [3, 7]]\n",
"jobs = [[3, 3], [2, 5], [1, 3], [3, 7], [7, 3], [2, 2], [2, 2], [5, 5],\n",
" [10, 2], [4, 3], [2, 6], [1, 2], [6, 8], [4, 5], [3, 7]]\n",
"\n",
" max_length = 10\n",
"max_length = 10\n",
"\n",
" horizon = sum(t[0] for t in jobs)\n",
" num_jobs = len(jobs)\n",
" all_jobs = range(num_jobs)\n",
"horizon = sum(t[0] for t in jobs)\n",
"num_jobs = len(jobs)\n",
"all_jobs = range(num_jobs)\n",
"\n",
" intervals = []\n",
" intervals0 = []\n",
" intervals1 = []\n",
" performed = []\n",
" starts = []\n",
" ends = []\n",
" demands = []\n",
"intervals = []\n",
"intervals0 = []\n",
"intervals1 = []\n",
"performed = []\n",
"starts = []\n",
"ends = []\n",
"demands = []\n",
"\n",
"for i in all_jobs:\n",
" # Create main interval.\n",
" start = model.NewIntVar(0, horizon, 'start_%i' % i)\n",
" duration = jobs[i][0]\n",
" end = model.NewIntVar(0, horizon, 'end_%i' % i)\n",
" interval = model.NewIntervalVar(start, duration, end, 'interval_%i' % i)\n",
" starts.append(start)\n",
" intervals.append(interval)\n",
" ends.append(end)\n",
" demands.append(jobs[i][1])\n",
"\n",
" performed_on_m0 = model.NewBoolVar('perform_%i_on_m0' % i)\n",
" performed.append(performed_on_m0)\n",
"\n",
" # Create an optional copy of interval to be executed on machine 0.\n",
" start0 = model.NewIntVar(0, horizon, 'start_%i_on_m0' % i)\n",
" end0 = model.NewIntVar(0, horizon, 'end_%i_on_m0' % i)\n",
" interval0 = model.NewOptionalIntervalVar(\n",
" start0, duration, end0, performed_on_m0, 'interval_%i_on_m0' % i)\n",
" intervals0.append(interval0)\n",
"\n",
" # Create an optional copy of interval to be executed on machine 1.\n",
" start1 = model.NewIntVar(0, horizon, 'start_%i_on_m1' % i)\n",
" end1 = model.NewIntVar(0, horizon, 'end_%i_on_m1' % i)\n",
" interval1 = model.NewOptionalIntervalVar(start1, duration, end1,\n",
" performed_on_m0.Not(),\n",
" 'interval_%i_on_m1' % i)\n",
" intervals1.append(interval1)\n",
"\n",
" # We only propagate the constraint if the tasks is performed on the machine.\n",
" model.Add(start0 == start).OnlyEnforceIf(performed_on_m0)\n",
" model.Add(start1 == start).OnlyEnforceIf(performed_on_m0.Not())\n",
"\n",
"# Max Length constraint (modeled as a cumulative)\n",
"model.AddCumulative(intervals, demands, max_length)\n",
"\n",
"# Choose which machine to perform the jobs on.\n",
"model.AddNoOverlap(intervals0)\n",
"model.AddNoOverlap(intervals1)\n",
"\n",
"# Objective variable.\n",
"makespan = model.NewIntVar(0, horizon, 'makespan')\n",
"model.AddMaxEquality(makespan, ends)\n",
"model.Minimize(makespan)\n",
"\n",
"# Symmetry breaking.\n",
"model.Add(performed[0] == 0)\n",
"\n",
"# Solve model.\n",
"solver = cp_model.CpSolver()\n",
"solver.Solve(model)\n",
"\n",
"# Output solution.\n",
"if visualization.RunFromIPython():\n",
" output = visualization.SvgWrapper(solver.ObjectiveValue(), max_length, 40.0)\n",
" output.AddTitle('Makespan = %i' % solver.ObjectiveValue())\n",
" color_manager = visualization.ColorManager()\n",
" color_manager.SeedRandomColor(0)\n",
"\n",
" for i in all_jobs:\n",
" # Create main interval.\n",
" start = model.NewIntVar(0, horizon, 'start_%i' % i)\n",
" duration = jobs[i][0]\n",
" end = model.NewIntVar(0, horizon, 'end_%i' % i)\n",
" interval = model.NewIntervalVar(start, duration, end, 'interval_%i' % i)\n",
" starts.append(start)\n",
" intervals.append(interval)\n",
" ends.append(end)\n",
" demands.append(jobs[i][1])\n",
" performed_machine = 1 - solver.Value(performed[i])\n",
" start = solver.Value(starts[i])\n",
" dx = jobs[i][0]\n",
" dy = jobs[i][1]\n",
" sy = performed_machine * (max_length - dy)\n",
" output.AddRectangle(start, sy, dx, dy, color_manager.RandomColor(),\n",
" 'black', 'j%i' % i)\n",
"\n",
" performed_on_m0 = model.NewBoolVar('perform_%i_on_m0' % i)\n",
" performed.append(performed_on_m0)\n",
"\n",
" # Create an optional copy of interval to be executed on machine 0.\n",
" start0 = model.NewOptionalIntVar(\n",
" 0, horizon, performed_on_m0, 'start_%i_on_m0' % i)\n",
" end0 = model.NewOptionalIntVar(\n",
" 0, horizon, performed_on_m0, 'end_%i_on_m0' % i)\n",
" interval0 = model.NewOptionalIntervalVar(\n",
" start0, duration, end0, performed_on_m0, 'interval_%i_on_m0' % i)\n",
" intervals0.append(interval0)\n",
"\n",
" # Create an optional copy of interval to be executed on machine 1.\n",
" start1 = model.NewOptionalIntVar(\n",
" 0, horizon, performed_on_m0.Not(), 'start_%i_on_m1' % i)\n",
" end1 = model.NewOptionalIntVar(\n",
" 0, horizon, performed_on_m0.Not(), 'end_%i_on_m1' % i)\n",
" interval1 = model.NewOptionalIntervalVar(\n",
" start1, duration, end1, performed_on_m0.Not(), 'interval_%i_on_m1' % i)\n",
" intervals1.append(interval1)\n",
"\n",
" # We only propagate the constraint if the tasks is performed on the machine.\n",
" model.Add(start0 == start).OnlyEnforceIf(performed_on_m0)\n",
" model.Add(start1 == start).OnlyEnforceIf(performed_on_m0.Not())\n",
"\n",
" # Max Length constraint (modeled as a cumulative)\n",
" model.AddCumulative(intervals, demands, max_length)\n",
"\n",
" # Choose which machine to perform the jobs on.\n",
" model.AddNoOverlap(intervals0)\n",
" model.AddNoOverlap(intervals1)\n",
"\n",
" # Objective variable.\n",
" makespan = model.NewIntVar(0, horizon, 'makespan')\n",
" model.AddMaxEquality(makespan, ends)\n",
" model.Minimize(makespan)\n",
"\n",
" # Symmetry breaking.\n",
" model.Add(performed[0] == 0)\n",
"\n",
" # Solve model.\n",
" solver = cp_model.CpSolver()\n",
" solver.Solve(model)\n",
"\n",
"\n",
" # Output solution.\n",
" if visualization.RunFromIPython():\n",
" output = visualization.SvgWrapper(solver.ObjectiveValue(), max_length, 40.0)\n",
" output.AddTitle('Makespan = %i' % solver.ObjectiveValue())\n",
" color_manager = visualization.ColorManager()\n",
" color_manager.SeedRandomColor(0)\n",
"\n",
" for i in all_jobs:\n",
" performed_machine = 1 - solver.Value(performed[i])\n",
" start = solver.Value(starts[i])\n",
" dx = jobs[i][0]\n",
" dy = jobs[i][1]\n",
" sy = performed_machine * (max_length - dy)\n",
" output.AddRectangle(start, sy, dx, dy, color_manager.RandomColor(),\n",
" 'black', 'j%i' % i)\n",
"\n",
" output.AddXScale()\n",
" output.AddYScale()\n",
" output.Display()\n",
" else:\n",
" print('Solution')\n",
" print(' - makespan = %i' % solver.ObjectiveValue())\n",
" for i in all_jobs:\n",
" performed_machine = 1 - solver.Value(performed[i])\n",
" start = solver.Value(starts[i])\n",
" print(' - Job %i starts at %i on machine %i' %\n",
" (i, start, performed_machine))\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f ms' % solver.WallTime())\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" main()"
" output.AddXScale()\n",
" output.AddYScale()\n",
" output.Display()\n",
"else:\n",
" print('Solution')\n",
" print(' - makespan = %i' % solver.ObjectiveValue())\n",
" for i in all_jobs:\n",
" performed_machine = 1 - solver.Value(performed[i])\n",
" start = solver.Value(starts[i])\n",
" print(' - Job %i starts at %i on machine %i' % (i, start,\n",
" performed_machine))\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f ms' % solver.WallTime())\n",
"\n"
]
}
],

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -38,11 +36,13 @@
" rows: the number of rows in the grid\n",
" cols: the number of columns in the grid\n",
" \"\"\"\n",
" return [(x * cols + y, (x + dx) * cols + (y + dy))\n",
" for x in range(rows) for y in range(cols)\n",
" for dx in (-1, 0, 1) for dy in (-1, 0, 1)\n",
" if (x + dx >= 0 and x + dx < rows and\n",
" y + dy >= 0 and y + dy < cols and (dx != 0 or dy != 0))]\n",
" return [\n",
" (x * cols + y, (x + dx) * cols + (y + dy)) for x in range(rows)\n",
" for y in range(cols) for dx in (-1, 0, 1)\n",
" for dy in (-1, 0, 1)\n",
" if (x + dx >= 0 and x + dx < rows and y + dy >= 0 and y + dy < cols and\n",
" (dx != 0 or dy != 0))\n",
" ]\n",
"\n",
"\n",
"def PrintSolution(positions, rows, cols):\n",
@@ -82,55 +82,37 @@
" puzzle = None\n",
" if problem == 1:\n",
" # Simple problem\n",
" puzzle = [[6, 0, 9],\n",
" [0, 2, 8],\n",
" [1, 0, 0]]\n",
" puzzle = [[6, 0, 9], [0, 2, 8], [1, 0, 0]]\n",
"\n",
" elif problem == 2:\n",
" puzzle = [[0, 44, 41, 0, 0, 0, 0],\n",
" [0, 43, 0, 28, 29, 0, 0],\n",
" [0, 1, 0, 0, 0, 33, 0],\n",
" [0, 2, 25, 4, 34, 0, 36],\n",
" [49, 16, 0, 23, 0, 0, 0],\n",
" [0, 19, 0, 0, 12, 7, 0],\n",
" [0, 0, 0, 14, 0, 0, 0]]\n",
" puzzle = [[0, 44, 41, 0, 0, 0, 0], [0, 43, 0, 28, 29, 0, 0],\n",
" [0, 1, 0, 0, 0, 33, 0], [0, 2, 25, 4, 34, 0, 36],\n",
" [49, 16, 0, 23, 0, 0, 0], [0, 19, 0, 0, 12, 7,\n",
" 0], [0, 0, 0, 14, 0, 0, 0]]\n",
"\n",
" elif problem == 3:\n",
" # Problems from the book:\n",
" # Gyora Bededek: \"Hidato: 2000 Pure Logic Puzzles\"\n",
" # Problem 1 (Practice)\n",
" puzzle = [[0, 0, 20, 0, 0],\n",
" [0, 0, 0, 16, 18],\n",
" [22, 0, 15, 0, 0],\n",
" [23, 0, 1, 14, 11],\n",
" [0, 25, 0, 0, 12]]\n",
" puzzle = [[0, 0, 20, 0, 0], [0, 0, 0, 16, 18], [22, 0, 15, 0, 0],\n",
" [23, 0, 1, 14, 11], [0, 25, 0, 0, 12]]\n",
"\n",
" elif problem == 4:\n",
" # problem 2 (Practice)\n",
" puzzle = [[0, 0, 0, 0, 14],\n",
" [0, 18, 12, 0, 0],\n",
" [0, 0, 17, 4, 5],\n",
" [0, 0, 7, 0, 0],\n",
" [9, 8, 25, 1, 0]]\n",
" puzzle = [[0, 0, 0, 0, 14], [0, 18, 12, 0, 0], [0, 0, 17, 4, 5],\n",
" [0, 0, 7, 0, 0], [9, 8, 25, 1, 0]]\n",
"\n",
" elif problem == 5:\n",
" # problem 3 (Beginner)\n",
" puzzle = [[0, 26, 0, 0, 0, 18],\n",
" [0, 0, 27, 0, 0, 19],\n",
" [31, 23, 0, 0, 14, 0],\n",
" [0, 33, 8, 0, 15, 1],\n",
" [0, 0, 0, 5, 0, 0],\n",
" [35, 36, 0, 10, 0, 0]]\n",
" puzzle = [[0, 26, 0, 0, 0, 18], [0, 0, 27, 0, 0, 19], [31, 23, 0, 0, 14, 0],\n",
" [0, 33, 8, 0, 15, 1], [0, 0, 0, 5, 0, 0], [35, 36, 0, 10, 0, 0]]\n",
" elif problem == 6:\n",
" # Problem 15 (Intermediate)\n",
" puzzle = [[64, 0, 0, 0, 0, 0, 0, 0],\n",
" [1, 63, 0, 59, 15, 57, 53, 0],\n",
" [0, 4, 0, 14, 0, 0, 0, 0],\n",
" [3, 0, 11, 0, 20, 19, 0, 50],\n",
" [0, 0, 0, 0, 22, 0, 48, 40],\n",
" [9, 0, 0, 32, 23, 0, 0, 41],\n",
" [27, 0, 0, 0, 36, 0, 46, 0],\n",
" [28, 30, 0, 35, 0, 0, 0, 0]]\n",
" puzzle = [[64, 0, 0, 0, 0, 0, 0, 0], [1, 63, 0, 59, 15, 57, 53, 0],\n",
" [0, 4, 0, 14, 0, 0, 0, 0], [3, 0, 11, 0, 20, 19, 0,\n",
" 50], [0, 0, 0, 0, 22, 0, 48, 40],\n",
" [9, 0, 0, 32, 23, 0, 0, 41], [27, 0, 0, 0, 36, 0, 46,\n",
" 0], [28, 30, 0, 35, 0, 0, 0, 0]]\n",
" return puzzle\n",
"\n",
"\n",
@@ -151,8 +133,7 @@
" #\n",
" # declare variables\n",
" #\n",
" positions = [model.NewIntVar(0, r * c - 1, 'p[%i]' % i)\n",
" for i in range(r * c)]\n",
" positions = [model.NewIntVar(0, r * c - 1, 'p[%i]' % i) for i in range(r * c)]\n",
"\n",
" #\n",
" # constraints\n",
@@ -194,20 +175,20 @@
" output.AddTitle('Puzzle %i solved in %f s' % (index, solver.WallTime()))\n",
" output.Display()\n",
" else:\n",
" PrintSolution([solver.Value(x) for x in positions], r, c,)\n",
" PrintSolution(\n",
" [solver.Value(x) for x in positions],\n",
" r,\n",
" c,\n",
" )\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f ms' % solver.WallTime())\n",
"\n",
"\n",
"def main():\n",
" for i in range(1, 7):\n",
" SolveHidato(BuildPuzzle(i), i)\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" main()"
"for i in range(1, 7):\n",
" SolveHidato(BuildPuzzle(i), i)\n",
"\n"
]
}
],

File diff suppressed because one or more lines are too long

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -20,17 +18,18 @@
"# 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",
"\"\"\"OR-tools solution to the N-queens problem.\"\"\"\n",
"from __future__ import print_function\n",
"import time\n",
"import sys\n",
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
"class NQueenSolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self, queens):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__queens = queens\n",
" self.__solution_count = 0\n",
" self.__start_time = time.time()\n",
@@ -38,10 +37,10 @@
" def SolutionCount(self):\n",
" return self.__solution_count\n",
"\n",
" def NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" current_time = time.time()\n",
" print('Solution %i, time = %f s' %\n",
" (self.__solution_count, current_time - self.__start_time))\n",
" print('Solution %i, time = %f s' % (self.__solution_count,\n",
" current_time - self.__start_time))\n",
" self.__solution_count += 1\n",
"\n",
" all_queens = range(len(self.__queens))\n",
@@ -49,62 +48,56 @@
" for j in all_queens:\n",
" if self.Value(self.__queens[j]) == i:\n",
" # There is a queen in column j, row i.\n",
" print('Q', end = ' ')\n",
" print('Q', end=' ')\n",
" else:\n",
" print('_', end = ' ')\n",
" print('_', end=' ')\n",
" print()\n",
" print()\n",
"\n",
"\n",
"def main(board_size):\n",
" # Creates the solver.\n",
" model = cp_model.CpModel()\n",
" # Creates the variables.\n",
" # The array index is the column, and the value is the row.\n",
" queens = [model.NewIntVar(0, board_size - 1, 'x%i' % i)\n",
" for i in range(board_size)]\n",
" # Creates the constraints.\n",
"# Creates the solver.\n",
"model = cp_model.CpModel()\n",
"# Creates the variables.\n",
"# The array index is the column, and the value is the row.\n",
"queens = [\n",
" model.NewIntVar(0, board_size - 1, 'x%i' % i) for i in range(board_size)\n",
"]\n",
"# Creates the constraints.\n",
"\n",
" # All rows must be different.\n",
" model.AddAllDifferent(queens)\n",
"# All rows must be different.\n",
"model.AddAllDifferent(queens)\n",
"\n",
" # All columns must be different because the indices of queens are all\n",
" # different.\n",
"# All columns must be different because the indices of queens are all\n",
"# different.\n",
"\n",
" # No two queens can be on the same diagonal.\n",
" diag1 = []\n",
" diag2 = []\n",
" for i in range(board_size):\n",
" q1 = model.NewIntVar(0, 2 * board_size, 'diag1_%i' % i)\n",
" q2 = model.NewIntVar(-board_size, board_size, 'diag2_%i' % i)\n",
" diag1.append(q1)\n",
" diag2.append(q2)\n",
" model.Add(q1 == queens[i] + i)\n",
" model.Add(q2 == queens[i] - i)\n",
" model.AddAllDifferent(diag1)\n",
" model.AddAllDifferent(diag2)\n",
"# No two queens can be on the same diagonal.\n",
"diag1 = []\n",
"diag2 = []\n",
"for i in range(board_size):\n",
" q1 = model.NewIntVar(0, 2 * board_size, 'diag1_%i' % i)\n",
" q2 = model.NewIntVar(-board_size, board_size, 'diag2_%i' % i)\n",
" diag1.append(q1)\n",
" diag2.append(q2)\n",
" model.Add(q1 == queens[i] + i)\n",
" model.Add(q2 == queens[i] - i)\n",
"model.AddAllDifferent(diag1)\n",
"model.AddAllDifferent(diag2)\n",
"\n",
" ### Solve model.\n",
" solver = cp_model.CpSolver()\n",
" solution_printer = NQueenSolutionPrinter(queens)\n",
" status = solver.SearchForAllSolutions(model, solution_printer)\n",
"### Solve model.\n",
"solver = cp_model.CpSolver()\n",
"solution_printer = NQueenSolutionPrinter(queens)\n",
"status = solver.SearchForAllSolutions(model, solution_printer)\n",
"\n",
" print()\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f ms' % solver.WallTime())\n",
" print(' - solutions found : %i' % solution_printer.SolutionCount())\n",
"print()\n",
"print('Statistics')\n",
"print(' - conflicts : %i' % solver.NumConflicts())\n",
"print(' - branches : %i' % solver.NumBranches())\n",
"print(' - wall time : %f ms' % solver.WallTime())\n",
"print(' - solutions found : %i' % solution_printer.SolutionCount())\n",
"\n",
"\n",
"# By default, solve the 8x8 problem.\n",
"board_size = 8\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" if len(sys.argv) > 1:\n",
" board_size = int(sys.argv[1])\n",
" main(board_size)"
"# By default, solve the 8x8 problem.board_size = 8\n",
"\n"
]
}
],

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -21,7 +19,6 @@
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"\n",
"\n",
"from __future__ import print_function\n",
"import sys\n",
"from ortools.sat.python import cp_model\n",
@@ -31,6 +28,7 @@
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self, shifts, num_nurses, num_days, num_shifts, sols):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__shifts = shifts\n",
" self.__num_nurses = num_nurses\n",
" self.__num_days = num_days\n",
@@ -38,7 +36,7 @@
" self.__solutions = set(sols)\n",
" self.__solution_count = 0\n",
"\n",
" def NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" self.__solution_count += 1\n",
" if self.__solution_count in self.__solutions:\n",
" print('Solution #%i' % self.__solution_count)\n",
@@ -54,91 +52,87 @@
" return self.__solution_count\n",
"\n",
"\n",
"def main():\n",
" # Data.\n",
" num_nurses = 4\n",
" num_shifts = 4 # Nurse assigned to shift 0 means not working that day.\n",
" num_days = 7\n",
" all_nurses = range(num_nurses)\n",
" all_shifts = range(num_shifts)\n",
" all_working_shifts = range(1, num_shifts)\n",
" all_days = range(num_days)\n",
"# Data.\n",
"num_nurses = 4\n",
"num_shifts = 4 # Nurse assigned to shift 0 means not working that day.\n",
"num_days = 7\n",
"all_nurses = range(num_nurses)\n",
"all_shifts = range(num_shifts)\n",
"all_working_shifts = range(1, num_shifts)\n",
"all_days = range(num_days)\n",
"\n",
" # Creates the model.\n",
" model = cp_model.CpModel()\n",
"# Creates the model.\n",
"model = cp_model.CpModel()\n",
"\n",
" # Creates shift variables.\n",
" # shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'.\n",
" shifts = {}\n",
" for n in all_nurses:\n",
" for d in all_days:\n",
" for s in all_shifts:\n",
" shifts[(n, d, s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s))\n",
"\n",
" # Makes assignments different on each day, that is each shift is assigned at\n",
" # most one nurse. As we have the same number of nurses and shifts, then each\n",
" # day, each shift is assigned to exactly one nurse.\n",
"# Creates shift variables.\n",
"# shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'.\n",
"shifts = {}\n",
"for n in all_nurses:\n",
" for d in all_days:\n",
" for s in all_shifts:\n",
" model.Add(sum(shifts[(n, d, s)] for n in all_nurses) == 1)\n",
" shifts[(n, d, s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s))\n",
"\n",
" # Nurses do 1 shift per day.\n",
" for n in all_nurses:\n",
"# Makes assignments different on each day, that is each shift is assigned at\n",
"# most one nurse. As we have the same number of nurses and shifts, then each\n",
"# day, each shift is assigned to exactly one nurse.\n",
"for d in all_days:\n",
" for s in all_shifts:\n",
" model.Add(sum(shifts[(n, d, s)] for n in all_nurses) == 1)\n",
"\n",
"# Nurses do 1 shift per day.\n",
"for n in all_nurses:\n",
" for d in all_days:\n",
" model.Add(sum(shifts[(n, d, s)] for s in all_shifts) == 1)\n",
"\n",
"# Each nurse works 5 or 6 days in a week.\n",
"# That is each nurse works shift 0 at most 2 times.\n",
"for n in all_nurses:\n",
" model.AddSumConstraint([shifts[(n, d, 0)] for d in all_days], 1, 2)\n",
"\n",
"# works_shift[(n, s)] is 1 if nurse n works shift s at least one day in\n",
"# the week.\n",
"works_shift = {}\n",
"for n in all_nurses:\n",
" for s in all_shifts:\n",
" works_shift[(n, s)] = model.NewBoolVar('works_shift_n%is%i' % (n, s))\n",
" model.AddMaxEquality(works_shift[(n, s)],\n",
" [shifts[(n, d, s)] for d in all_days])\n",
"\n",
"# For each shift, at most 2 nurses are assigned to that shift during the week.\n",
"for s in all_working_shifts:\n",
" model.Add(sum(works_shift[(n, s)] for n in all_nurses) <= 2)\n",
"\n",
"# If a nurse works shifts 2 or 3 on, she must also work that shift the\n",
"# previous day or the following day.\n",
"# This means that on a given day and shift, either she does not work that\n",
"# shift on that day, or she works that shift on the day before, or the day\n",
"# after.\n",
"for n in all_nurses:\n",
" for s in [2, 3]:\n",
" for d in all_days:\n",
" model.Add(sum(shifts[(n, d, s)] for s in all_shifts) == 1)\n",
" yesterday = (d - 1) % num_days\n",
" tomorrow = (d + 1) % num_days\n",
" model.AddBoolOr([\n",
" shifts[(n, yesterday, s)], shifts[(n, d, s)].Not(),\n",
" shifts[(n, tomorrow, s)]\n",
" ])\n",
"\n",
" # Each nurse works 5 or 6 days in a week.\n",
" # That is each nurse works shift 0 at most 2 times.\n",
" for n in all_nurses:\n",
" model.AddSumConstraint([shifts[(n, d, 0)] for d in all_days], 1, 2)\n",
"# Creates the solver and solve.\n",
"solver = cp_model.CpSolver()\n",
"# Display a few solutions picked at random.\n",
"a_few_solutions = [859, 2034, 5091, 7003]\n",
"solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses, num_days,\n",
" num_shifts, a_few_solutions)\n",
"status = solver.SearchForAllSolutions(model, solution_printer)\n",
"\n",
" # works_shift[(n, s)] is 1 if nurse n works shift s at least one day in\n",
" # the week.\n",
" works_shift = {}\n",
" for n in all_nurses:\n",
" for s in all_shifts:\n",
" works_shift[(n, s)] = model.NewBoolVar('works_shift_n%is%i' % (n, s))\n",
" model.AddMaxEquality(works_shift[(n, s)],\n",
" [shifts[(n, d, s)] for d in all_days])\n",
"\n",
" # For each shift, at most 2 nurses are assigned to that shift during the week.\n",
" for s in all_working_shifts:\n",
" model.Add(sum(works_shift[(n, s)] for n in all_nurses) <= 2)\n",
"\n",
" # If s nurses works shifts 2 or 3 on, she must also work that shift the\n",
" # previous day or the following day.\n",
" # This means that on a given day and shift, either she does not work that\n",
" # shift on that day, or she works that shift on the day before, or the day\n",
" # after.\n",
" for n in all_nurses:\n",
" for s in [2, 3]:\n",
" for d in all_days:\n",
" yesterday = (d - 1) % num_days\n",
" tomorrow = (d + 1) % num_days\n",
" model.AddBoolOr([shifts[(n, yesterday, s)], shifts[(n, d, s)].Not(),\n",
" shifts[(n, tomorrow, s)]])\n",
"\n",
"\n",
" # Creates the solver and solve.\n",
" solver = cp_model.CpSolver()\n",
" # Display a few solutions picked at random.\n",
" a_few_solutions = [859, 2034, 5091, 7003]\n",
" solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses,\n",
" num_days, num_shifts,\n",
" a_few_solutions)\n",
" status = solver.SearchForAllSolutions(model, solution_printer)\n",
"\n",
" # Statistics.\n",
" print()\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f ms' % solver.WallTime())\n",
" print(' - solutions found : %i' % solution_printer.SolutionCount())\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
" main()"
"# Statistics.\n",
"print()\n",
"print('Statistics')\n",
"print(' - conflicts : %i' % solver.NumConflicts())\n",
"print(' - branches : %i' % solver.NumBranches())\n",
"print(' - wall time : %f ms' % solver.WallTime())\n",
"print(' - solutions found : %i' % solution_printer.SolutionCount())\n",
"\n"
]
}
],

View File

@@ -6,32 +6,47 @@
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\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",
"\n",
"from __future__ import print_function\n",
"\n",
"import argparse\n",
"from collections import defaultdict\n",
"from ortools.sat.python import cp_model\n",
"from ortools.sat.python import visualization\n",
"from ortools.data import rcpsp_pb2\n",
"from ortools.data import pywraprcpsp\n",
"import time\n",
"\n",
"parser = argparse.ArgumentParser()\n",
"\n",
"parser.add_argument('--input', default = \"\",\n",
" help = 'Input file to parse and solve.')\n",
"parser.add_argument('--output_proto', default = \"\",\n",
" help = 'Output file to write the cp_model proto to.')\n",
"parser.add_argument(\n",
" '--input', default='', help='Input file to parse and solve.')\n",
"parser.add_argument(\n",
" '--output_proto',\n",
" default='',\n",
" help='Output file to write the cp_model proto to.')\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 NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" current_time = time.time()\n",
" objective = self.ObjectiveValue()\n",
" print('Solution %i, time = %f s, objective = %i' %\n",
@@ -41,17 +56,17 @@
"\n",
"def SolveRcpsp(problem, proto_file):\n",
" # Determine problem type.\n",
" problem_type = ('Resource investment' if problem.is_resource_investment\n",
" else 'RCPSP')\n",
" problem_type = ('Resource investment'\n",
" if problem.is_resource_investment else 'RCPSP')\n",
"\n",
" if problem.is_rcpsp_max:\n",
" problem_type += '/Max delay'\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)))\n",
" print('Solving %s with %i reservoir resources and %i tasks' %\n",
" (problem_type, len(problem.resources), len(problem.tasks)))\n",
" else:\n",
" print ('Solving %s with %i resources and %i tasks' % (\n",
" problem_type, len(problem.resources), len(problem.tasks)))\n",
" print('Solving %s with %i resources and %i tasks' %\n",
" (problem_type, len(problem.resources), len(problem.tasks)))\n",
"\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
@@ -129,10 +144,8 @@
" 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.NewOptionalIntVar(0, horizon, is_present,\n",
" 'start_%i_r%i' % (t, r))\n",
" end = model.NewOptionalIntVar(0, horizon, is_present,\n",
" 'end_%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, 'interval_%i_r%i' % (t, r))\n",
"\n",
@@ -157,8 +170,8 @@
" 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, 'duration_of_task_%i' % t)\n",
" interval = model.NewIntervalVar(task_starts[t], duration,\n",
" task_ends[t], 'interval_%i' % t)\n",
" interval = model.NewIntervalVar(task_starts[t], duration, task_ends[t],\n",
" 'interval_%i' % t)\n",
"\n",
" # Link with optional per-recipe copies.\n",
" for r in all_recipes:\n",
@@ -168,7 +181,6 @@
" model.Add(duration == task.recipes[r].duration).OnlyEnforceIf(p)\n",
" model.Add(sum(presences_per_task[t]) == 1)\n",
"\n",
"\n",
" # Create makespan variable\n",
" makespan = model.NewIntVar(0, horizon, 'makespan')\n",
"\n",
@@ -214,22 +226,23 @@
"\n",
" if problem.is_resource_investment:\n",
" capacity = model.NewIntVar(0, c, 'capacity_of_%i' % r)\n",
" model.AddCumulative(\n",
" intervals_per_resource[r], demands_per_resource[r], capacity)\n",
" model.AddCumulative(intervals_per_resource[r], demands_per_resource[r],\n",
" capacity)\n",
" capacities.append(capacity)\n",
" max_cost += c * resource.unit_cost\n",
" elif resource.renewable:\n",
" if intervals_per_resource[r]:\n",
" model.AddCumulative(\n",
" intervals_per_resource[r], demands_per_resource[r], c)\n",
" model.AddCumulative(intervals_per_resource[r], demands_per_resource[r],\n",
" c)\n",
" elif presences_per_resource[r]: # Non empty non renewable resource.\n",
" if problem.is_consumer_producer:\n",
" model.AddReservoirConstraint(\n",
" starts_per_resource[r], demands_per_resource[r],\n",
" resource.min_capacity, resource.max_capacity)\n",
" else:\n",
" model.Add(sum(presences_per_resource[r][i] * demands_per_resource[r][i]\n",
" for i in range(len(presences_per_resource[r]))) <= c)\n",
" model.Add(\n",
" sum(presences_per_resource[r][i] * demands_per_resource[r][i]\n",
" for i in range(len(presences_per_resource[r]))) <= c)\n",
"\n",
" # Objective.\n",
" if problem.is_resource_investment:\n",
@@ -250,7 +263,7 @@
" # Solve model.\n",
" solver = cp_model.CpSolver()\n",
" solution_printer = SolutionPrinter()\n",
" status = solver.SolveWithSolutionObserver(model, solution_printer)\n",
" status = solver.SolveWithSolutionCallback(model, solution_printer)\n",
" print('Solve status: %s' % solver.StatusName(status))\n",
" print('Optimal objective value: %i' % solver.ObjectiveValue())\n",
" print('Statistics')\n",
@@ -259,51 +272,15 @@
" print(' - wall time : %f s' % solver.WallTime())\n",
"\n",
"\n",
"def main(args):\n",
" parser = pywraprcpsp.RcpspParser()\n",
" parser.ParseFile(args.input)\n",
" problem = parser.Problem()\n",
" SolveRcpsp(problem, args.output_proto)\n",
" \n",
" \n",
"class FakeArgs(object):\n",
" def __init__(self):\n",
" self.output_proto = ''\n",
" self.input = '../data/rcpsp/single_mode/j301_1.sm'\n",
" \n",
"\n",
"if __name__ == '__main__':\n",
" arguments = FakeArgs() if visualization.RunFromIPython() else parser.parse_args()\n",
" main(arguments)"
"parser = pywraprcpsp.RcpspParser()\n",
"parser.ParseFile(args.input)\n",
"problem = parser.Problem()\n",
"SolveRcpsp(problem, args.output_proto)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.2"
}
},
"metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"from ortools.sat.python import cp_model\n",
@@ -123,67 +121,61 @@
" sum(teacher_courses[course, subject, t]\n",
" for t in all_teachers) == 1)\n",
"\n",
" # Solution collector\n",
" self.collector = None\n",
"\n",
" def solve(self):\n",
" print('Solving')\n",
" solver = cp_model.CpSolver()\n",
" solution_printer = SchoolSchedulingSatSolutionPrinter()\n",
" status = solver.SearchForAllSolutions(self.model, solution_printer)\n",
" status = solver.Solve(self.model)\n",
" print()\n",
" print('status', status)\n",
" print('Branches', solver.NumBranches())\n",
" print('Conflicts', solver.NumConflicts())\n",
" print('WallTime', solver.WallTime())\n",
"\n",
" def print_status(self):\n",
" pass\n",
"\n",
"\n",
"class SchoolSchedulingSatSolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
"\n",
" def NewSolution(self):\n",
" def __init__(self):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solution_count = 0\n",
"\n",
" def OnSolutionCallback(self):\n",
" print('Found Solution!')\n",
"\n",
"\n",
"def main():\n",
" # DATA\n",
" subjects = ['English', 'Math', 'History']\n",
" levels = ['1-', '2-', '3-']\n",
" sections = ['A']\n",
" teachers = ['Mario', 'Elvis', 'Donald', 'Ian']\n",
" teachers_work_hours = [18, 12, 12, 18]\n",
" working_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']\n",
" periods = ['08:00-09:30', '09:45-11:15', '11:30-13:00']\n",
" curriculum = {\n",
" ('1-', 'English'): 3,\n",
" ('1-', 'Math'): 3,\n",
" ('1-', 'History'): 2,\n",
" ('2-', 'English'): 4,\n",
" ('2-', 'Math'): 2,\n",
" ('2-', 'History'): 2,\n",
" ('3-', 'English'): 2,\n",
" ('3-', 'Math'): 4,\n",
" ('3-', 'History'): 2\n",
" }\n",
"# DATA\n",
"subjects = ['English', 'Math', 'History']\n",
"levels = ['1-', '2-', '3-']\n",
"sections = ['A']\n",
"teachers = ['Mario', 'Elvis', 'Donald', 'Ian']\n",
"teachers_work_hours = [18, 12, 12, 18]\n",
"working_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']\n",
"periods = ['08:00-09:30', '09:45-11:15', '11:30-13:00']\n",
"curriculum = {\n",
" ('1-', 'English'): 3,\n",
" ('1-', 'Math'): 3,\n",
" ('1-', 'History'): 2,\n",
" ('2-', 'English'): 4,\n",
" ('2-', 'Math'): 2,\n",
" ('2-', 'History'): 2,\n",
" ('3-', 'English'): 2,\n",
" ('3-', 'Math'): 4,\n",
" ('3-', 'History'): 2\n",
"}\n",
"\n",
" # Subject -> List of teachers who can teach it\n",
" specialties_idx_inverse = [\n",
" [1, 3], # English -> Elvis & Ian\n",
" [0, 3], # Math -> Mario & Ian\n",
" [2, 3] # History -> Donald & Ian\n",
" ]\n",
"# Subject -> List of teachers who can teach it\n",
"specialties_idx_inverse = [\n",
" [1, 3], # English -> Elvis & Ian\n",
" [0, 3], # Math -> Mario & Ian\n",
" [2, 3] # History -> Donald & Ian\n",
"]\n",
"\n",
" problem = SchoolSchedulingProblem(\n",
" subjects, teachers, curriculum, specialties_idx_inverse, working_days,\n",
" periods, levels, sections, teachers_work_hours)\n",
" solver = SchoolSchedulingSatSolver(problem)\n",
" solver.solve()\n",
" solver.print_status()\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" main()"
"problem = SchoolSchedulingProblem(\n",
" subjects, teachers, curriculum, specialties_idx_inverse, working_days,\n",
" periods, levels, sections, teachers_work_hours)\n",
"solver = SchoolSchedulingSatSolver(problem)\n",
"solver.solve()\n",
"\n"
]
}
],

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -22,25 +20,28 @@
"# limitations under the License.\n",
"\n",
"from __future__ import print_function\n",
"\n",
"import argparse\n",
"import time\n",
"from ortools.sat.python import cp_model\n",
"from ortools.linear_solver import pywraplp\n",
"import time\n",
"\n",
"parser = argparse.ArgumentParser()\n",
"\n",
"parser.add_argument('--problem', default = 2, type = int,\n",
" help = 'Problem id to solve.')\n",
"parser.add_argument('--break_symmetries', default = True, type = bool,\n",
" help = 'Break symmetries between equivalent orders.')\n",
"parser.add_argument(\n",
" '--solver', default = \"mip_column\",\n",
" help = 'Method used to solve: sat, sat_table, sat_column, mip_column.')\n",
"parser.add_argument('--output_proto', default = \"\",\n",
" help = 'Output file to write the cp_model proto to.')\n",
"\n",
"PARSER = argparse.ArgumentParser()\n",
"\n",
"PARSER.add_argument(\n",
" '--problem', default=2, type=int, help='Problem id to solve.')\n",
"PARSER.add_argument(\n",
" '--break_symmetries',\n",
" default=True,\n",
" type=bool,\n",
" help='Break symmetries between equivalent orders.')\n",
"PARSER.add_argument(\n",
" '--solver',\n",
" default='sat_table',\n",
" help='Method used to solve: sat, sat_table, sat_column, mip_column.')\n",
"PARSER.add_argument(\n",
" '--output_proto',\n",
" default='',\n",
" help='Output file to write the cp_model proto to.')\n",
"\n",
"def BuildProblem(problem_id):\n",
" \"\"\"Build problem data.\"\"\"\n",
@@ -261,11 +262,11 @@
"\n",
" return (num_slabs, capacities, num_colors, orders)\n",
"\n",
"\n",
"class SteelMillSlabSolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self, orders, assign, load, loss):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__orders = orders\n",
" self.__assign = assign\n",
" self.__load = load\n",
@@ -275,41 +276,40 @@
" self.__all_slabs = range(len(assign[0]))\n",
" self.__start_time = time.time()\n",
"\n",
" def NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" current_time = time.time()\n",
" objective = sum(self.Value(l) for l in self.__loss)\n",
" print('Solution %i, time = %f s, objective = %i' %\n",
" (self.__solution_count, current_time - self.__start_time, objective))\n",
" self.__solution_count += 1\n",
" orders_in_slab = [[o for o in self.__all_orders\n",
" if self.Value(self.__assign[o][s])]\n",
" for s in self.__all_slabs]\n",
" orders_in_slab = [[\n",
" o for o in self.__all_orders if self.Value(self.__assign[o][s])\n",
" ] for s in self.__all_slabs]\n",
" for s in self.__all_slabs:\n",
" if orders_in_slab[s]:\n",
" line = ' - slab %i, load = %i, loss = %i, orders = [' % (\n",
" s, self.Value(self.__load[s]), self.Value(self.__loss[s]))\n",
" for o in orders_in_slab[s]:\n",
" line += '#%i(w%i, c%i) ' % (\n",
" o, self.__orders[o][0], self.__orders[o][1])\n",
" line += '#%i(w%i, c%i) ' % (o, self.__orders[o][0],\n",
" self.__orders[o][1])\n",
" line += ']'\n",
" print(line)\n",
"\n",
"\n",
"class SolutionPrinterWithObjective(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 NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" current_time = time.time()\n",
" print('Solution %i, time = %f s, objective = %i' %\n",
" (self.__solution_count, current_time - self.__start_time,\n",
" self.ObjectiveValue()))\n",
" self.__solution_count += 1\n",
"\n",
"\n",
"def SteelMillSlab(problem, break_symmetries, output_proto):\n",
" \"\"\"Solves the Steel Mill Slab Problem.\"\"\"\n",
" ### Load problem.\n",
@@ -331,8 +331,9 @@
" min(x for x in capacities if x >= c) - c for c in range(max_capacity + 1)\n",
" ]\n",
" max_loss = max(loss_array)\n",
" orders_per_color = [[o for o in all_orders if colors[o] == c + 1]\n",
" for c in all_colors]\n",
" orders_per_color = [\n",
" [o for o in all_orders if colors[o] == c + 1] for c in all_colors\n",
" ]\n",
" unique_color_orders = [\n",
" o for o in all_orders if len(orders_per_color[colors[o] - 1]) == 1\n",
" ]\n",
@@ -447,28 +448,28 @@
" else:\n",
" print('No solution')\n",
"\n",
"\n",
"class AllSolutionsCollector(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Collect all solutions callback.\"\"\"\n",
"\n",
" def __init__(self, variables):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solutions = []\n",
" self.__variables = variables\n",
"\n",
" def NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" solution = [self.Value(v) for v in self.__variables]\n",
" self.__solutions.append(tuple(solution))\n",
"\n",
" def AllSolutions(self):\n",
" return self.__solutions\n",
"\n",
"\n",
"def CollectValidSlabs(capacities, colors, widths, loss_array, all_colors):\n",
" \"\"\"Collect valid columns (assign, loss) for one slab.\"\"\"\n",
" all_orders = range(len(colors))\n",
" max_capacity = max(capacities)\n",
" orders_per_color = [[o for o in all_orders if colors[o] == c + 1]\n",
" for c in all_colors]\n",
" all_orders = range(len(colors))\n",
" orders_per_color = [\n",
" [o for o in all_orders if colors[o] == c + 1] for c in all_colors\n",
" ]\n",
"\n",
" model = cp_model.CpModel()\n",
" assign = [model.NewBoolVar('assign_%i' % o) for o in all_orders]\n",
@@ -494,21 +495,14 @@
" loss = model.NewIntVar(0, max(loss_array), 'loss')\n",
" model.AddElement(load, loss_array, loss)\n",
"\n",
" print('Model created')\n",
"\n",
" # Output model proto to file.\n",
" if output_proto:\n",
" f = open(output_proto, 'w')\n",
" f.write(str(model.ModelProto()))\n",
" f.close()\n",
"\n",
" ### Solve model and collect columns.\n",
" print('Collect Valid Slabs...DONE')\n",
" solver = cp_model.CpSolver()\n",
" collector = AllSolutionsCollector(assign + [loss, load])\n",
" solver.SearchForAllSolutions(model, collector)\n",
" print('Collect Valid Slabs...DONE')\n",
" return collector.AllSolutions()\n",
"\n",
"\n",
"def SteelMillSlabWithValidSlabs(problem, break_symmetries, output_proto):\n",
" \"\"\"Solves the Steel Mill Slab Problem.\"\"\"\n",
" ### Load problem.\n",
@@ -544,15 +538,13 @@
" unsorted_valid_slabs = CollectValidSlabs(capacities, colors, widths,\n",
" loss_array, all_colors)\n",
" # Sort slab by descending load/loss. Remove duplicates.\n",
" valid_slabs = sorted(unsorted_valid_slabs,\n",
" key = lambda c : 1000 * c[-1] + c[-2])\n",
" valid_slabs = sorted(unsorted_valid_slabs, key=lambda c: 1000 * c[-1] + c[-2])\n",
" num_valid_slabs = len(valid_slabs)\n",
" print(' - %i valid slab combinations' % num_valid_slabs)\n",
"\n",
" for s in all_slabs:\n",
" model.AddAllowedAssignments(\n",
" [assign[o][s] for o in all_orders] + [losses[s], loads[s]],\n",
" valid_slabs)\n",
" [assign[o][s] for o in all_orders] + [losses[s], loads[s]], valid_slabs)\n",
"\n",
" # Orders are assigned to one slab.\n",
" for o in all_orders:\n",
@@ -570,8 +562,9 @@
" print('Breaking symmetries')\n",
" width_to_unique_color_order = {}\n",
" ordered_equivalent_orders = []\n",
" orders_per_color = [[o for o in all_orders if colors[o] == c + 1]\n",
" for c in all_colors]\n",
" orders_per_color = [\n",
" [o for o in all_orders if colors[o] == c + 1] for c in all_colors\n",
" ]\n",
" for c in all_colors:\n",
" colored_orders = orders_per_color[c]\n",
" if not colored_orders:\n",
@@ -632,7 +625,7 @@
" ### Solve model.\n",
" solver = cp_model.CpSolver()\n",
" solution_printer = SteelMillSlabSolutionPrinter(orders, assign, loads, losses)\n",
" status = solver.SolveWithSolutionObserver(model, solution_printer)\n",
" status = solver.SolveWithSolutionCallback(model, solution_printer)\n",
"\n",
" ### Output the solution.\n",
" if status == cp_model.OPTIMAL:\n",
@@ -641,7 +634,6 @@
" else:\n",
" print('No solution')\n",
"\n",
"\n",
"def SteelMillSlabWithColumnGeneration(problem, output_proto):\n",
" \"\"\"Solves the Steel Mill Slab Problem.\"\"\"\n",
" ### Load problem.\n",
@@ -669,8 +661,7 @@
" unsorted_valid_slabs = CollectValidSlabs(capacities, colors, widths,\n",
" loss_array, all_colors)\n",
" # Sort slab by descending load/loss. Remove duplicates.\n",
" valid_slabs = sorted(unsorted_valid_slabs,\n",
" key = lambda c : 1000 * c[-1] + c[-2])\n",
" valid_slabs = sorted(unsorted_valid_slabs, key=lambda c: 1000 * c[-1] + c[-2])\n",
" num_valid_slabs = len(valid_slabs)\n",
" all_valid_slabs = range(num_valid_slabs)\n",
" print(' - %i valid slab combinations' % num_valid_slabs)\n",
@@ -680,19 +671,19 @@
" selected = [model.NewBoolVar('selected_%i' % i) for i in all_valid_slabs]\n",
"\n",
" for o in all_orders:\n",
" model.Add(sum(selected[i] for i in all_valid_slabs\n",
" if valid_slabs[i][o]) == 1)\n",
"\n",
" model.Add(\n",
" sum(selected[i] for i in all_valid_slabs if valid_slabs[i][o]) == 1)\n",
"\n",
" # Redundant constraint (sum of loads == sum of widths).\n",
" model.Add(sum(selected[i] * valid_slabs[i][-1] for i in all_valid_slabs) ==\n",
" sum(widths))\n",
" model.Add(\n",
" sum(selected[i] * valid_slabs[i][-1]\n",
" for i in all_valid_slabs) == sum(widths))\n",
"\n",
" # Objective.\n",
" max_loss = max(valid_slabs[i][-2] for i in all_valid_slabs)\n",
" obj = model.NewIntVar(0, num_slabs * max_loss, 'obj')\n",
" model.Add(obj == sum(selected[i] * valid_slabs[i][-2]\n",
" for i in all_valid_slabs))\n",
" model.Add(obj == sum(\n",
" selected[i] * valid_slabs[i][-2] for i in all_valid_slabs))\n",
" model.Minimize(obj)\n",
"\n",
" print('Model created')\n",
@@ -706,7 +697,7 @@
" ### Solve model.\n",
" solver = cp_model.CpSolver()\n",
" solution_printer = SolutionPrinterWithObjective()\n",
" status = solver.SolveWithSolutionObserver(model, solution_printer)\n",
" status = solver.SolveWithSolutionCallback(model, solution_printer)\n",
"\n",
" ### Output the solution.\n",
" if status == cp_model.OPTIMAL:\n",
@@ -715,7 +706,6 @@
" else:\n",
" print('No solution')\n",
"\n",
"\n",
"def SteelMillSlabWithMipColumnGeneration(problem):\n",
" \"\"\"Solves the Steel Mill Slab Problem.\"\"\"\n",
" ### Load problem.\n",
@@ -744,57 +734,51 @@
" unsorted_valid_slabs = CollectValidSlabs(capacities, colors, widths,\n",
" loss_array, all_colors)\n",
" # Sort slab by descending load/loss. Remove duplicates.\n",
" valid_slabs = sorted(unsorted_valid_slabs,\n",
" key = lambda c : 1000 * c[-1] + c[-2])\n",
" valid_slabs = sorted(unsorted_valid_slabs, key=lambda c: 1000 * c[-1] + c[-2])\n",
" num_valid_slabs = len(valid_slabs)\n",
" all_valid_slabs = range(num_valid_slabs)\n",
" generate = time.time()\n",
" print(' - %i valid slab combinations generated in %f s' % (\n",
" num_valid_slabs, generate - start))\n",
" print(' - %i valid slab combinations generated in %f s' % (num_valid_slabs,\n",
" generate - start))\n",
"\n",
" # create model and decision variables.\n",
" solver = pywraplp.Solver('Steel',\n",
" pywraplp.Solver.BOP_INTEGER_PROGRAMMING)\n",
" selected = [solver.IntVar(0.0, 1.0, 'selected_%i' % i)\n",
" for i in all_valid_slabs]\n",
"\n",
" for o in all_orders:\n",
" solver.Add(sum(selected[i] for i in all_valid_slabs\n",
" if valid_slabs[i][o]) == 1)\n",
" solver = pywraplp.Solver('Steel', pywraplp.Solver.BOP_INTEGER_PROGRAMMING)\n",
" selected = [\n",
" solver.IntVar(0.0, 1.0, 'selected_%i' % i) for i in all_valid_slabs\n",
" ]\n",
"\n",
" for order in all_orders:\n",
" solver.Add(\n",
" sum(selected[i] for i in all_valid_slabs if valid_slabs[i][order]) == 1)\n",
"\n",
" # Redundant constraint (sum of loads == sum of widths).\n",
" solver.Add(sum(selected[i] * valid_slabs[i][-1] for i in all_valid_slabs) ==\n",
" sum(widths))\n",
" solver.Add(\n",
" sum(selected[i] * valid_slabs[i][-1]\n",
" for i in all_valid_slabs) == sum(widths))\n",
"\n",
" # Objective.\n",
" solver.Minimize(sum(selected[i] * valid_slabs[i][-2]\n",
" for i in all_valid_slabs))\n",
" solver.Minimize(\n",
" sum(selected[i] * valid_slabs[i][-2] for i in all_valid_slabs))\n",
"\n",
" status = solver.Solve()\n",
"\n",
" ### Output the solution.\n",
" if status == pywraplp.Solver.OPTIMAL:\n",
" print('Objective value = %f found in %f s' % (\n",
" solver.Objective().Value(), time.time() - generate))\n",
" print('Objective value = %f found in %f s' % (solver.Objective().Value(),\n",
" time.time() - generate))\n",
" else:\n",
" print('No solution')\n",
"\n",
"\n",
"def main(args):\n",
" if args.solver == 'sat':\n",
" SteelMillSlab(args.problem, args.break_symmetries, args.output_proto)\n",
" elif args.solver == 'sat_table':\n",
" SteelMillSlabWithValidSlabs(args.problem, args.break_symmetries,\n",
" args.output_proto)\n",
" elif args.solver == 'sat_column':\n",
" SteelMillSlabWithColumnGeneration(args.problem, args.output_proto)\n",
" else: # 'mip_column'\n",
" SteelMillSlabWithMipColumnGeneration(args.problem)\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" main(parser.parse_args())"
"'''Main function'''\n",
"if args.solver == 'sat':\n",
" SteelMillSlab(args.problem, args.break_symmetries, args.output_proto)\n",
"elif args.solver == 'sat_table':\n",
" SteelMillSlabWithValidSlabs(args.problem, args.break_symmetries,\n",
" args.output_proto)\n",
"elif args.solver == 'sat_column':\n",
" SteelMillSlabWithColumnGeneration(args.problem, args.output_proto)\n",
"else: # 'mip_column'\n",
" SteelMillSlabWithMipColumnGeneration(args.problem)\n"
]
}
],

View File

@@ -0,0 +1,155 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\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",
"\n",
"from __future__ import absolute_import\n",
"from __future__ import division\n",
"from __future__ import print_function\n",
"\n",
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
"class SolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self, num_vendors, num_hours, possible_schedules,\n",
" selected_schedules, hours_stat, min_vendors):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solution_count = 0\n",
" self.__num_vendors = num_vendors\n",
" self.__num_hours = num_hours\n",
" self.__possible_schedules = possible_schedules\n",
" self.__selected_schedules = selected_schedules\n",
" self.__hours_stat = hours_stat\n",
" self.__min_vendors = min_vendors\n",
"\n",
" def OnSolutionCallback(self):\n",
" self.__solution_count += 1\n",
" print ('Solution %i: ', self.__solution_count)\n",
" print(' min vendors:', self.__min_vendors)\n",
" for i in range(self.__num_vendors):\n",
" print(' - vendor %i: ' % i,\n",
" self.__possible_schedules[self.Value(self.__selected_schedules[i])])\n",
" print()\n",
"\n",
" for j in range(self.__num_hours):\n",
" print(' - # workers on day%2i: ' % j, end=' ')\n",
" print(self.Value(self.__hours_stat[j]), end=' ')\n",
" print()\n",
" print()\n",
"\n",
" def SolutionCount(self):\n",
" return self.__solution_count\n",
"\n",
"\n",
"def VendorScheduling():\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
"\n",
" #\n",
" # data\n",
" #\n",
" num_vendors = 9\n",
" num_hours = 10\n",
" num_work_types = 1\n",
"\n",
" traffic = [100, 500, 100, 200, 320, 300, 200, 220, 300, 120]\n",
" max_traffic_per_vendor = 100\n",
"\n",
" # Last columns are :\n",
" # index_of_the_schedule, sum of worked hours (per work type).\n",
" # The index is useful for branching.\n",
" possible_schedules = [[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 8],\n",
" [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 4],\n",
" [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 2, 5],\n",
" [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 4],\n",
" [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 3],\n",
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]]\n",
"\n",
" num_possible_schedules = len(possible_schedules)\n",
" selected_schedules = []\n",
" vendors_stat = []\n",
" hours_stat = []\n",
"\n",
"\n",
" # Auxiliary data\n",
" min_vendors = [t // max_traffic_per_vendor for t in traffic]\n",
" all_vendors = range(num_vendors)\n",
" all_hours = range(num_hours)\n",
"\n",
" #\n",
" # declare variables\n",
" #\n",
" x = {}\n",
"\n",
" for v in all_vendors:\n",
" tmp = []\n",
" for h in all_hours:\n",
" x[v, h] = model.NewIntVar(0, num_work_types, 'x[%i,%i]' % (v, h))\n",
" tmp.append(x[v, h])\n",
" selected_schedule = model.NewIntVar(0, num_possible_schedules - 1,\n",
" 's[%i]' % v)\n",
" hours = model.NewIntVar(0, num_hours, 'h[%i]' % v)\n",
" selected_schedules.append(selected_schedule)\n",
" vendors_stat.append(hours)\n",
" tmp.append(selected_schedule)\n",
" tmp.append(hours)\n",
"\n",
" model.AddAllowedAssignments(tmp, possible_schedules)\n",
"\n",
" #\n",
" # Statistics and constraints for each hour\n",
" #\n",
" for h in all_hours:\n",
" workers = model.NewIntVar(0, 1000, 'workers[%i]' %h)\n",
" model.Add(workers == sum(x[v, h] for v in all_vendors))\n",
" hours_stat.append(workers)\n",
" model.Add(workers * max_traffic_per_vendor >= traffic[h])\n",
"\n",
" #\n",
" # Redundant constraint: sort selected_schedules\n",
" #\n",
" for v in range(num_vendors - 1):\n",
" model.Add(selected_schedules[v] <= selected_schedules[v + 1])\n",
"\n",
" # Solve model.\n",
" solver = cp_model.CpSolver()\n",
" solution_printer = SolutionPrinter(num_vendors, num_hours, possible_schedules,\n",
" selected_schedules, hours_stat,\n",
" min_vendors)\n",
" status = solver.SearchForAllSolutions(model, solution_printer)\n",
" print('Status = %s' % solver.StatusName(status))\n",
"\n",
" print('Statistics')\n",
" print(' - conflicts : %i' % solver.NumConflicts())\n",
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f s' % solver.WallTime())\n",
" print(' - number of solutions found: %i' % solution_printer.SolutionCount())\n",
"\n",
"\n",
"VendorScheduling()\n",
"\n"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"#\n",
@@ -55,6 +53,7 @@
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
" def __init__(self, seats, names, num_tables, num_guests):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solution_count = 0\n",
" self.__start_time = time.time()\n",
" self.__seats = seats\n",
@@ -62,7 +61,7 @@
" self.__num_tables = num_tables\n",
" self.__num_guests = num_guests\n",
"\n",
" def NewSolution(self):\n",
" def OnSolutionCallback(self):\n",
" current_time = time.time()\n",
" objective = self.ObjectiveValue()\n",
" print(\"Solution %i, time = %f s, objective = %i\" %\n",
@@ -205,7 +204,7 @@
" ### Solve model.\n",
" solver = cp_model.CpSolver()\n",
" solution_printer = WeddingChartPrinter(seats, names, num_tables, num_guests)\n",
" status = solver.SolveWithSolutionObserver(model, solution_printer)\n",
" status = solver.SolveWithSolutionCallback(model, solution_printer)\n",
"\n",
" print(\"Statistics\")\n",
" print(\" - conflicts : %i\" % solver.NumConflicts())\n",
@@ -214,12 +213,8 @@
" print(\" - num solutions: %i\" % solution_printer.NumSolutions())\n",
"\n",
"\n",
"def main():\n",
" SolveWithDiscreteModel()\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
" main()"
"SolveWithDiscreteModel()\n",
"\n"
]
}
],

View File

@@ -3,9 +3,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"metadata": {},
"outputs": [],
"source": [
"# Copyright 2010-2017 Google\n",
@@ -124,13 +122,15 @@
" # Model the problem.\n",
" model = cp_model.CpModel()\n",
"\n",
" workers_per_shift = [model.NewIntVar(0, num_workers, 'shift[%i]' % i)\n",
" for i in all_shifts]\n",
" workers_per_shift = [\n",
" model.NewIntVar(0, num_workers, 'shift[%i]' % i) for i in all_shifts\n",
" ]\n",
"\n",
" # Satisfy min requirements.\n",
" for slot in all_slots:\n",
" model.Add(sum(workers_per_shift[shift] * possible_shifts[shift][slot]\n",
" for shift in all_shifts) >= min_number_of_workers[slot])\n",
" model.Add(\n",
" sum(workers_per_shift[shift] * possible_shifts[shift][slot]\n",
" for shift in all_shifts) >= min_number_of_workers[slot])\n",
"\n",
" # Create the objective variable.\n",
" objective = model.NewIntVar(0, num_workers, 'objective')\n",
@@ -152,9 +152,7 @@
" print(' - branches : %i' % solver.NumBranches())\n",
" print(' - wall time : %f ms' % solver.WallTime())\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" schedule()"
"\n"
]
}
],

View File

@@ -15,6 +15,8 @@ line_start = [c.lineno-1 for c in all_blocks]
line_start[0] = 0
lines = text.split('\n')
full_text = ''
for c_block, s, e in zip(all_blocks, line_start, line_start[1:]+[len(lines)]):
c_text = '\n'.join(lines[s:e])
if isinstance(c_block, ast.If) and c_block.test.comparators[0].s=='__main__':
@@ -23,16 +25,19 @@ for c_block, s, e in zip(all_blocks, line_start, line_start[1:]+[len(lines)]):
# remove start and de-indent lines
c_lines = lines[s+1:e]
spaces_to_delete = c_block.body[0].col_offset
fixed_lines = [n_line[spaces_to_delete:] if n_line.startswith(' '*spaces_to_delete)
fixed_lines = [n_line[spaces_to_delete:] if n_line.startswith(' '*spaces_to_delete)
else n_line for n_line in c_lines]
fixed_text = '\n'.join(fixed_lines)
print('Unwrapping main function')
nbook['cells'].append(v4.new_code_cell(fixed_text))
full_text += fixed_text
else:
print('appending', c_block)
nbook['cells'].append(v4.new_code_cell(c_text))
full_text += c_text + '\n'
jsonform = v4.writes(nbook) + "\n"
nbook['cells'].append(v4.new_code_cell(full_text))
jsonform = v4.writes(nbook) + '\n'
output = input
output = output.replace('.py', '.ipynb')
output = output.replace('examples/python', 'examples/notebook')