Sync python notebook
cmd: ./tools/generate_all_notebooks.sh
This commit is contained in:
@@ -162,14 +162,13 @@
|
||||
" Each collection may be selected more than one time.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" item_collections: a list of item collections. Each item collection is a\n",
|
||||
" list of integers [#item0, ..., #itemN-1], where #itemK is the number\n",
|
||||
" of times item #K appears in the collection, and N is the number of\n",
|
||||
" distinct items.\n",
|
||||
" max_num_collections: an integer, the maximum number of item collections\n",
|
||||
" that may be selected (counting repetitions of the same collection).\n",
|
||||
" item_collections: a list of item collections. Each item collection is a list\n",
|
||||
" of integers [#item0, ..., #itemN-1], where #itemK is the number of times\n",
|
||||
" item #K appears in the collection, and N is the number of distinct items.\n",
|
||||
" max_num_collections: an integer, the maximum number of item collections that\n",
|
||||
" may be selected (counting repetitions of the same collection).\n",
|
||||
" ideal_item_ratios: A list of N float which sums to 1.0: the K-th element is\n",
|
||||
" the ideal ratio of item #K in the whole aggregated selection.\n",
|
||||
" the ideal ratio of item #K in the whole aggregated selection.\n",
|
||||
"\n",
|
||||
" Returns:\n",
|
||||
" A pair (objective value, list of pairs (item collection, num_selections)),\n",
|
||||
@@ -246,10 +245,10 @@
|
||||
" \"\"\"Computes the optimal schedule for the installation input.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" demand: a list of \"appointment types\". Each \"appointment type\" is\n",
|
||||
" a triple (ideal_ratio_pct, name, duration_minutes), where\n",
|
||||
" ideal_ratio_pct is the ideal percentage (in [0..100.0]) of that\n",
|
||||
" type of appointment among all appointments scheduled.\n",
|
||||
" demand: a list of \"appointment types\". Each \"appointment type\" is a triple\n",
|
||||
" (ideal_ratio_pct, name, duration_minutes), where ideal_ratio_pct is the\n",
|
||||
" ideal percentage (in [0..100.0]) of that type of appointment among all\n",
|
||||
" appointments scheduled.\n",
|
||||
"\n",
|
||||
" Returns:\n",
|
||||
" The same output type as EnumerateAllKnapsacksWithRepetition.\n",
|
||||
|
||||
@@ -83,21 +83,25 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import argparse\n",
|
||||
"import collections\n",
|
||||
"import time\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"from ortools.linear_solver import pywraplp\n",
|
||||
"from google.protobuf import text_format\n",
|
||||
"from ortools.linear_solver.python import model_builder as mb\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"PARSER = argparse.ArgumentParser()\n",
|
||||
"class FLAGS: pass\n",
|
||||
"\n",
|
||||
"_OUTPUT_PROTO = flags.DEFINE_string(\n",
|
||||
" 'output_proto', '', 'Output file to write the cp_model proto to.')\n",
|
||||
"_PARAMS = flags.DEFINE_string(\n",
|
||||
" 'params',\n",
|
||||
" 'num_search_workers:8,log_search_progress:true,max_time_in_seconds:10',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
"_SOLVER = flags.DEFINE_string(\n",
|
||||
" 'solver', 'sat', 'Method used to solve: sat, mip.')\n",
|
||||
"\n",
|
||||
"PARSER.add_argument(\n",
|
||||
" '--solver', default='sat', help='Method used to solve: sat, mip.')\n",
|
||||
"PARSER.add_argument(\n",
|
||||
" '--output_proto_file',\n",
|
||||
" default='',\n",
|
||||
" help='Output file to write the cp_model proto to.')\n",
|
||||
"\n",
|
||||
"DESIRED_LENGTHS = [\n",
|
||||
" 2490, 3980, 2490, 3980, 2391, 2391, 2391, 596, 596, 596, 2456, 2456, 3018,\n",
|
||||
@@ -175,7 +179,7 @@
|
||||
" return states, transitions\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file):\n",
|
||||
"def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file: str, params: str):\n",
|
||||
" \"\"\"Solve the cutting stock with arc-flow and the CP-SAT solver.\"\"\"\n",
|
||||
" items = regroup_and_count(DESIRED_LENGTHS)\n",
|
||||
" print('Items:', items)\n",
|
||||
@@ -243,16 +247,14 @@
|
||||
"\n",
|
||||
" # Output model proto to file.\n",
|
||||
" if output_proto_file:\n",
|
||||
" output_file = open(output_proto_file, 'w')\n",
|
||||
" output_file.write(str(model.Proto()))\n",
|
||||
" output_file.close()\n",
|
||||
" model.ExportToFile(output_proto_file)\n",
|
||||
"\n",
|
||||
" # Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" if params:\n",
|
||||
" text_format.Parse(params, solver.parameters)\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
" solver.parameters.num_search_workers = 8\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
" print(solver.ResponseStats())\n",
|
||||
" solver.Solve(model)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def solve_cutting_stock_with_arc_flow_and_mip():\n",
|
||||
@@ -273,9 +275,7 @@
|
||||
" item_coeffs = collections.defaultdict(list)\n",
|
||||
"\n",
|
||||
" start_time = time.time()\n",
|
||||
" solver = pywraplp.Solver.CreateSolver('cbc')\n",
|
||||
" if not solver:\n",
|
||||
" return\n",
|
||||
" model = mb.ModelBuilder()\n",
|
||||
"\n",
|
||||
" objective_vars = []\n",
|
||||
" objective_coeffs = []\n",
|
||||
@@ -283,7 +283,7 @@
|
||||
" var_index = 0\n",
|
||||
" for outgoing, incoming, item_index, card in transitions:\n",
|
||||
" count = items[item_index][1]\n",
|
||||
" count_var = solver.IntVar(\n",
|
||||
" count_var = model.new_int_var(\n",
|
||||
" 0, count, 'a%i_i%i_f%i_t%i_c%i' % (var_index, item_index, incoming,\n",
|
||||
" outgoing, card))\n",
|
||||
" var_index += 1\n",
|
||||
@@ -295,7 +295,7 @@
|
||||
" for state_index, state in enumerate(states):\n",
|
||||
" if state_index == 0:\n",
|
||||
" continue\n",
|
||||
" exit_var = solver.IntVar(0, num_items, 'e%i' % state_index)\n",
|
||||
" exit_var = model.new_int_var(0, num_items, 'e%i' % state_index)\n",
|
||||
" outgoing_vars[state_index].append(exit_var)\n",
|
||||
" incoming_sink_vars.append(exit_var)\n",
|
||||
" price = price_usage(state, POSSIBLE_CAPACITIES)\n",
|
||||
@@ -304,44 +304,47 @@
|
||||
"\n",
|
||||
" # Flow conservation\n",
|
||||
" for state_index in range(1, len(states)):\n",
|
||||
" solver.Add(\n",
|
||||
" sum(incoming_vars[state_index]) == sum(outgoing_vars[state_index]))\n",
|
||||
" model.add(\n",
|
||||
" mb.LinearExpr.sum(incoming_vars[state_index]) == mb.LinearExpr.sum(\n",
|
||||
" outgoing_vars[state_index]))\n",
|
||||
"\n",
|
||||
" # Flow going out of the source must go in the sink\n",
|
||||
" solver.Add(sum(outgoing_vars[0]) == sum(incoming_sink_vars))\n",
|
||||
" model.add(\n",
|
||||
" mb.LinearExpr.sum(outgoing_vars[0]) == mb.LinearExpr.sum(\n",
|
||||
" incoming_sink_vars))\n",
|
||||
"\n",
|
||||
" # Items must be placed\n",
|
||||
" for item_index, size_and_count in enumerate(items):\n",
|
||||
" num_arcs = len(item_vars[item_index])\n",
|
||||
" solver.Add(\n",
|
||||
" sum(item_vars[item_index][i] * item_coeffs[item_index][i]\n",
|
||||
" for i in range(num_arcs)) == size_and_count[1])\n",
|
||||
" model.add(\n",
|
||||
" mb.LinearExpr.sum([item_vars[item_index][i] * item_coeffs[item_index][i]\n",
|
||||
" for i in range(num_arcs)]) == size_and_count[1])\n",
|
||||
"\n",
|
||||
" # Objective is the sum of waste\n",
|
||||
" solver.Minimize(\n",
|
||||
" sum(objective_vars[i] * objective_coeffs[i]\n",
|
||||
" for i in range(len(objective_vars))))\n",
|
||||
" solver.EnableOutput()\n",
|
||||
" model.minimize(np.dot(objective_vars, objective_coeffs))\n",
|
||||
"\n",
|
||||
" status = solver.Solve()\n",
|
||||
" solver = mb.ModelSolver('scip')\n",
|
||||
" solver.enable_output(True)\n",
|
||||
" status = solver.solve(model)\n",
|
||||
"\n",
|
||||
" ### Output the solution.\n",
|
||||
" if status == pywraplp.Solver.OPTIMAL:\n",
|
||||
" if status == mb.SolveStatus.OPTIMAL or status == mb.SolveStatus.FEASIBLE:\n",
|
||||
" print('Objective value = %f found in %.2f s' %\n",
|
||||
" (solver.Objective().Value(), time.time() - start_time))\n",
|
||||
" (solver.objective_value, time.time() - start_time))\n",
|
||||
" else:\n",
|
||||
" print('No solution')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(args):\n",
|
||||
"def main(_):\n",
|
||||
" \"\"\"Main function\"\"\"\n",
|
||||
" if args.solver == 'sat':\n",
|
||||
" solve_cutting_stock_with_arc_flow_and_sat(args.output_proto_file)\n",
|
||||
" if _SOLVER.value == 'sat':\n",
|
||||
" solve_cutting_stock_with_arc_flow_and_sat(_OUTPUT_PROTO.value,\n",
|
||||
" _PARAMS.value)\n",
|
||||
" else: # 'mip'\n",
|
||||
" solve_cutting_stock_with_arc_flow_and_mip()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main(PARSER.parse_args())\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "google",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Copyright 2022 Google LLC."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "apache",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"you may not use this file except in compliance with the License.\n",
|
||||
"You may obtain a copy of the License at\n",
|
||||
"\n",
|
||||
" http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"\n",
|
||||
"Unless required by applicable law or agreed to in writing, software\n",
|
||||
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"See the License for the specific language governing permissions and\n",
|
||||
"limitations under the License.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "basename",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# assignment2_sat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "link",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<table align=\"left\">\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/examples/assignment2_sat.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
||||
"</td>\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://github.com/google/or-tools/blob/main/examples/python/assignment2_sat.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
||||
"</td>\n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "doc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "install",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install ortools"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2010-2022 Google LLC\n",
|
||||
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"# you may not use this file except in compliance with the License.\n",
|
||||
"# You may obtain a copy of the License at\n",
|
||||
"#\n",
|
||||
"# http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"#\n",
|
||||
"# Unless required by applicable law or agreed to in writing, software\n",
|
||||
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"# See the License for the specific language governing permissions and\n",
|
||||
"# limitations under the License.\n",
|
||||
"\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\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,\n",
|
||||
" 120, 36, 73], [45, 110, 95, 115, 104, 83, 37,\n",
|
||||
" 71], [60, 105, 80, 75, 59, 62, 93,\n",
|
||||
" 88], [45, 65, 110, 95, 47, 31, 81, 34],\n",
|
||||
" [38, 51, 107, 41, 69, 99, 115,\n",
|
||||
" 48], [47, 85, 57, 71, 92, 77, 109,\n",
|
||||
" 36], [39, 63, 97, 49, 118, 56,\n",
|
||||
" 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",
|
||||
"\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(x[i][j] * cost[i][j]\n",
|
||||
" 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 = ',\n",
|
||||
" 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 s' % solver.WallTime())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -72,8 +72,7 @@
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Solve an assignment problem with combination constraints on workers.\n",
|
||||
"\n"
|
||||
"Solve an assignment problem with combination constraints on workers.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -83,20 +82,19 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def solve_assignment():\n",
|
||||
" \"\"\"Solve the assignment problem.\"\"\"\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",
|
||||
" cost = [[90, 76, 75, 70, 50, 74], [35, 85, 55, 65, 48, 101],\n",
|
||||
" [125, 95, 90, 105, 59, 120], [45, 110, 95, 115, 104, 83],\n",
|
||||
" [60, 105, 80, 75, 59, 62], [45, 65, 110, 95, 47, 31],\n",
|
||||
" [38, 51, 107, 41, 69, 99], [47, 85, 57, 71, 92, 77],\n",
|
||||
" [39, 63, 97, 49, 118, 56], [47, 101, 71, 60, 88, 109],\n",
|
||||
" [17, 39, 103, 64, 61, 92], [101, 45, 83, 59, 92, 27]]\n",
|
||||
"\n",
|
||||
" group1 = [\n",
|
||||
" [0, 0, 1, 1], # Workers 2, 3\n",
|
||||
@@ -133,7 +131,8 @@
|
||||
"\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
" # Variables\n",
|
||||
" selected = [[model.NewBoolVar('x[%i,%i]' % (i, j)) for j in all_tasks]\n",
|
||||
" selected = [[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",
|
||||
@@ -162,7 +161,8 @@
|
||||
"\n",
|
||||
" # Objective\n",
|
||||
" model.Minimize(\n",
|
||||
" sum(selected[i][j] * cost[i][j] for j in all_tasks\n",
|
||||
" sum(selected[i][j] * cost[i][j]\n",
|
||||
" for j in all_tasks\n",
|
||||
" for i in all_workers))\n",
|
||||
"\n",
|
||||
" # Solve and output solution.\n",
|
||||
@@ -186,7 +186,13 @@
|
||||
" print(' - wall time : %f s' % solver.WallTime())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"solve_assignment()\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" solve_assignment()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -77,9 +77,7 @@
|
||||
"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",
|
||||
"\n"
|
||||
"be in that group.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -89,6 +87,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -130,7 +129,11 @@
|
||||
" print(']')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" \"\"\"Solves a group balancing problem.\"\"\"\n",
|
||||
"\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" # Data.\n",
|
||||
" num_groups = 10\n",
|
||||
" num_items = 100\n",
|
||||
@@ -219,7 +222,8 @@
|
||||
"\n",
|
||||
" # Compute the maximum number of colors in a group.\n",
|
||||
" max_color = num_items_per_group // min_items_of_same_color_per_group\n",
|
||||
" # Redundant contraint: The problem does not solve in reasonable time without it.\n",
|
||||
"\n",
|
||||
" # Redundant constraint, it helps with solving time.\n",
|
||||
" if max_color < num_colors:\n",
|
||||
" for g in all_groups:\n",
|
||||
" model.Add(\n",
|
||||
@@ -228,9 +232,9 @@
|
||||
" # Minimize epsilon\n",
|
||||
" model.Minimize(e)\n",
|
||||
"\n",
|
||||
" model.ExportToFile('balance_group_sat.pbtxt')\n",
|
||||
"\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" # solver.parameters.log_search_progress = True\n",
|
||||
" solver.parameters.num_workers = 16\n",
|
||||
" solution_printer = SolutionPrinter(values, colors, all_groups, all_items,\n",
|
||||
" item_in_group)\n",
|
||||
" status = solver.Solve(model, solution_printer)\n",
|
||||
|
||||
@@ -100,11 +100,51 @@
|
||||
"\n",
|
||||
"_OUTPUT_PROTO = flags.DEFINE_string(\n",
|
||||
" 'output_proto', '', 'Output file to write the cp_model proto to.')\n",
|
||||
"_PARAMS = flags.DEFINE_string('params',\n",
|
||||
" 'num_search_workers:8,log_search_progress:true',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
"_INSTANCE = flags.DEFINE_integer('instance', 1, 'Instance to select (1, 2, 3).',\n",
|
||||
" 1, 3)\n",
|
||||
"_PARAMS = flags.DEFINE_string(\n",
|
||||
" 'params',\n",
|
||||
" 'num_search_workers:16,log_search_progress:true,max_time_in_seconds:30',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
"_INSTANCE = flags.DEFINE_integer('instance', 0,\n",
|
||||
" 'Instance to select (0, 1, 2, 3).', 0, 3)\n",
|
||||
"\n",
|
||||
"SAMPLE_SHIFTS_TINY = [\n",
|
||||
" #\n",
|
||||
" # column description:\n",
|
||||
" # - shift id\n",
|
||||
" # - shift start time as hh:mm string (for logging and readability purposes)\n",
|
||||
" # - shift end time as hh:mm string (for logging and readability purposes)\n",
|
||||
" # - shift start minute\n",
|
||||
" # - shift end minute\n",
|
||||
" # - shift duration in minutes\n",
|
||||
" #\n",
|
||||
" [1, '08:00', '09:05', 480, 545, 65],\n",
|
||||
" [2, '08:00', '08:35', 480, 515, 35],\n",
|
||||
" [3, '08:11', '09:41', 491, 581, 90],\n",
|
||||
" [4, '08:28', '08:50', 508, 530, 22],\n",
|
||||
" [5, '08:35', '08:45', 515, 525, 10],\n",
|
||||
" [6, '08:40', '08:50', 520, 530, 10],\n",
|
||||
" [7, '09:03', '10:28', 543, 628, 85],\n",
|
||||
" [8, '09:23', '09:49', 563, 589, 26],\n",
|
||||
" [9, '09:30', '09:40', 570, 580, 10],\n",
|
||||
" [10, '09:57', '10:20', 597, 620, 23],\n",
|
||||
" [11, '10:09', '11:03', 609, 663, 54],\n",
|
||||
" [12, '10:20', '10:30', 620, 630, 10],\n",
|
||||
" [13, '11:00', '11:10', 660, 670, 10],\n",
|
||||
" [14, '11:45', '12:24', 705, 744, 39],\n",
|
||||
" [15, '12:18', '13:00', 738, 780, 42],\n",
|
||||
" [16, '13:18', '14:44', 798, 884, 86],\n",
|
||||
" [17, '13:53', '14:49', 833, 889, 56],\n",
|
||||
" [18, '14:03', '14:50', 843, 890, 47],\n",
|
||||
" [19, '14:28', '15:15', 868, 915, 47],\n",
|
||||
" [20, '14:30', '15:41', 870, 941, 71],\n",
|
||||
" [21, '14:48', '15:35', 888, 935, 47],\n",
|
||||
" [22, '15:03', '15:50', 903, 950, 47],\n",
|
||||
" [23, '15:28', '16:54', 928, 1014, 86],\n",
|
||||
" [24, '15:38', '16:25', 938, 985, 47],\n",
|
||||
" [25, '15:40', '15:56', 940, 956, 16],\n",
|
||||
" [26, '15:58', '16:45', 958, 1005, 47],\n",
|
||||
" [27, '16:04', '17:30', 964, 1050, 86],\n",
|
||||
"] # yapf:disable\n",
|
||||
"\n",
|
||||
"SAMPLE_SHIFTS_SMALL = [\n",
|
||||
" #\n",
|
||||
@@ -1730,7 +1770,6 @@
|
||||
" [1355, '00:57', '01:07', 1497, 1507, 10]\n",
|
||||
"] # yapf:disable\n",
|
||||
"\n",
|
||||
"# pytype: disable=wrong-arg-types\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def bus_driver_scheduling(minimize_drivers, max_num_drivers):\n",
|
||||
@@ -1755,7 +1794,9 @@
|
||||
" The objective value of the model.\n",
|
||||
" \"\"\"\n",
|
||||
" shifts = None\n",
|
||||
" if _INSTANCE.value == 1:\n",
|
||||
" if _INSTANCE.value == 0:\n",
|
||||
" shifts = SAMPLE_SHIFTS_TINY\n",
|
||||
" elif _INSTANCE.value == 1:\n",
|
||||
" shifts = SAMPLE_SHIFTS_SMALL\n",
|
||||
" elif _INSTANCE.value == 2:\n",
|
||||
" shifts = SAMPLE_SHIFTS_MEDIUM\n",
|
||||
|
||||
@@ -73,10 +73,11 @@
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"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",
|
||||
"Each item has a color and a value. We want the sum of values of each group to be\n",
|
||||
"as close to the average as possible. Furthermore, if one color is an a group, at\n",
|
||||
"least k items with this color must be in that group.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -87,78 +88,95 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import math\n",
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"# Data\n",
|
||||
"\n",
|
||||
"max_quantities = [\n",
|
||||
" [\"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",
|
||||
"def chemical_balance():\n",
|
||||
" \"\"\"Solves the chemical balance problem.\"\"\"\n",
|
||||
" # Data\n",
|
||||
" max_quantities = [\n",
|
||||
" [\"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",
|
||||
"\n",
|
||||
"chemical_set = [\n",
|
||||
" [\"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",
|
||||
" chemical_set = [\n",
|
||||
" [\"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",
|
||||
"\n",
|
||||
"NUM_PRODUCTS = len(max_quantities)\n",
|
||||
"ALL_PRODUCTS = range(NUM_PRODUCTS)\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",
|
||||
" num_sets = len(chemical_set)\n",
|
||||
" all_sets = range(num_sets)\n",
|
||||
"\n",
|
||||
"# Model\n",
|
||||
" # Model\n",
|
||||
"\n",
|
||||
"model = cp_model.CpModel()\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
"\n",
|
||||
"# Scale quantities by 100.\n",
|
||||
"max_set = [\n",
|
||||
" int(\n",
|
||||
" math.ceil(\n",
|
||||
" min(max_quantities[q][1] * 1000 / chemical_set[s][q + 1]\n",
|
||||
" for q in ALL_PRODUCTS if chemical_set[s][q + 1] != 0)))\n",
|
||||
" for s in ALL_SETS\n",
|
||||
"]\n",
|
||||
" # Scale quantities by 100.\n",
|
||||
" max_set = [\n",
|
||||
" int(\n",
|
||||
" math.ceil(\n",
|
||||
" 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",
|
||||
"\n",
|
||||
"set_vars = [model.NewIntVar(0, max_set[s], f\"set_{s}\") for s in ALL_SETS]\n",
|
||||
" set_vars = [model.NewIntVar(0, max_set[s], f\"set_{s}\") for s in all_sets]\n",
|
||||
"\n",
|
||||
"epsilon = model.NewIntVar(0, 10000000, \"epsilon\")\n",
|
||||
" epsilon = model.NewIntVar(0, 10000000, \"epsilon\")\n",
|
||||
"\n",
|
||||
"for p in ALL_PRODUCTS:\n",
|
||||
" model.Add(\n",
|
||||
" 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(\n",
|
||||
" sum(int(chemical_set[s][p + 1] * 10) * set_vars[s]\n",
|
||||
" for s in ALL_SETS) >= int(max_quantities[p][1] * 10000) - epsilon)\n",
|
||||
" for p in all_products:\n",
|
||||
" model.Add(\n",
|
||||
" sum(\n",
|
||||
" 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(\n",
|
||||
" sum(\n",
|
||||
" 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",
|
||||
" model.Minimize(epsilon)\n",
|
||||
"\n",
|
||||
"# Creates a solver and solves.\n",
|
||||
"solver = cp_model.CpSolver()\n",
|
||||
"status = solver.Solve(model)\n",
|
||||
"print(f\"Status = {solver.StatusName(status)}\")\n",
|
||||
"# The objective value of the solution.\n",
|
||||
"print(f\"Optimal objective value = {solver.ObjectiveValue() / 10000.0}\")\n",
|
||||
" # Creates a solver and solves.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
" print(f\"Status = {solver.StatusName(status)}\")\n",
|
||||
" # The objective value of the solution.\n",
|
||||
" print(f\"Optimal objective value = {solver.ObjectiveValue() / 10000.0}\")\n",
|
||||
"\n",
|
||||
"for s in ALL_SETS:\n",
|
||||
" print(f\" {chemical_set[s][0]} = {solver.Value(set_vars[s]) / 1000.0}\", 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(\n",
|
||||
" solver.Value(set_vars[s]) / 1000.0 * chemical_set[s][p + 1]\n",
|
||||
" for s in ALL_SETS)\n",
|
||||
" print(f\"{name}: {quantity} out of {max_quantity}\")\n",
|
||||
" for s in all_sets:\n",
|
||||
" print(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(\n",
|
||||
" solver.Value(set_vars[s]) / 1000.0 * chemical_set[s][p + 1]\n",
|
||||
" for s in all_sets)\n",
|
||||
" print(f\"{name}: {quantity} out of {max_quantity}\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError(\"Too many command-line arguments.\")\n",
|
||||
" chemical_balance()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -72,8 +72,7 @@
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Cluster 40 cities in 4 equal groups to minimize sum of crossed distances.\n",
|
||||
"\n"
|
||||
"Cluster 40 cities in 4 equal groups to minimize sum of crossed distances.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -83,6 +82,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -127,10 +127,10 @@
|
||||
" [10084, 20956, 14618, 12135, 38935, 8306, 9793, 2615, 5850, 10467, 9918, 14568, 13907, 11803, 11750, 13657, 6901, 23862, 16125, 14748, 12981, 11624, 21033, 15358, 24144, 10304, 10742, 9094, 8042, 7408, 4580, 4072, 8446, 20543, 26181, 7668, 2747, 0, 3330, 5313],\n",
|
||||
" [13026, 23963, 17563, 14771, 42160, 11069, 12925, 5730, 8778, 13375, 11235, 14366, 13621, 11188, 10424, 11907, 5609, 21861, 13624, 11781, 9718, 8304, 17737, 12200, 20816, 7330, 7532, 6117, 4735, 4488, 2599, 3355, 7773, 22186, 27895, 9742, 726, 3330, 0, 2042],\n",
|
||||
" [15056, 25994, 19589, 16743, 44198, 13078, 14967, 7552, 10422, 14935, 11891, 14002, 13225, 10671, 9475, 10633, 5084, 20315, 11866, 9802, 7682, 6471, 15720, 10674, 18908, 6204, 6000, 5066, 3039, 3721, 3496, 4772, 8614, 23805, 29519, 11614, 2749, 5313, 2042, 0],\n",
|
||||
" ] # yapf: disable\n",
|
||||
"] # yapf: disable\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
"def clustering_sat():\n",
|
||||
" \"\"\"Entry point of the program.\"\"\"\n",
|
||||
" num_nodes = len(distance_matrix)\n",
|
||||
" print('Num nodes =', num_nodes)\n",
|
||||
@@ -155,16 +155,17 @@
|
||||
"\n",
|
||||
" # Number of neighborss:\n",
|
||||
" for n in range(num_nodes):\n",
|
||||
" model.Add(sum(neighbors[m, n] for m in range(n)) + \n",
|
||||
" sum(neighbors[n, m] for m in range(n + 1, num_nodes)) ==\n",
|
||||
" group_size - 1)\n",
|
||||
" \n",
|
||||
" model.Add(\n",
|
||||
" sum(neighbors[m, n] for m in range(n)) +\n",
|
||||
" sum(neighbors[n, m]\n",
|
||||
" for m in range(n + 1, num_nodes)) == group_size - 1)\n",
|
||||
"\n",
|
||||
" # Enforce transivity on all triplets.\n",
|
||||
" for n1 in range(num_nodes - 2):\n",
|
||||
" for n2 in range(n1 + 1, num_nodes - 1):\n",
|
||||
" for n3 in range(n2 + 1, num_nodes):\n",
|
||||
" model.Add(\n",
|
||||
" neighbors[n1, n3] + neighbors[n2, n3] + neighbors[n1, n2] != 2)\n",
|
||||
" model.Add(neighbors[n1, n3] + neighbors[n2, n3] +\n",
|
||||
" neighbors[n1, n2] != 2)\n",
|
||||
"\n",
|
||||
" # Redundant constraints on total sum of neighborss.\n",
|
||||
" model.Add(sum(obj_vars) == num_groups * group_size * (group_size - 1) // 2)\n",
|
||||
@@ -181,18 +182,25 @@
|
||||
" status = solver.Solve(model)\n",
|
||||
" print(solver.ResponseStats())\n",
|
||||
"\n",
|
||||
" visited = set()\n",
|
||||
" for g in range(num_groups):\n",
|
||||
" for n in range(num_nodes):\n",
|
||||
" if not n in visited:\n",
|
||||
" visited.add(n)\n",
|
||||
" output = str(n)\n",
|
||||
" for o in range(n + 1, num_nodes):\n",
|
||||
" if solver.BooleanValue(neighbors[n, o]):\n",
|
||||
" visited.add(o)\n",
|
||||
" output += ' ' + str(o)\n",
|
||||
" print('Group', g, ':', output)\n",
|
||||
" break\n",
|
||||
" if status == cp_model.FEASIBLE or status == cp_model.OPTIMAL:\n",
|
||||
" visited = set()\n",
|
||||
" for g in range(num_groups):\n",
|
||||
" for n in range(num_nodes):\n",
|
||||
" if n not in visited:\n",
|
||||
" visited.add(n)\n",
|
||||
" output = str(n)\n",
|
||||
" for o in range(n + 1, num_nodes):\n",
|
||||
" if solver.BooleanValue(neighbors[n, o]):\n",
|
||||
" visited.add(o)\n",
|
||||
" output += ' ' + str(o)\n",
|
||||
" print('Group', g, ':', output)\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" clustering_sat()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -72,8 +72,7 @@
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Fill a 60x50 rectangle by a minimum number of non-overlapping squares.\n",
|
||||
"\n"
|
||||
"Fill a 60x50 rectangle by a minimum number of non-overlapping squares.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -83,6 +82,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -144,11 +144,12 @@
|
||||
" model.Add(x_starts[i] <= x_starts[i + 1]).OnlyEnforceIf(same)\n",
|
||||
"\n",
|
||||
" # Symmetry breaking 2: first square in one quadrant.\n",
|
||||
" model.Add(x_starts[0] < (size_x + 1)// 2)\n",
|
||||
" model.Add(x_starts[0] < (size_x + 1) // 2)\n",
|
||||
" model.Add(y_starts[0] < (size_y + 1) // 2)\n",
|
||||
"\n",
|
||||
" # Creates a solver and solves.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" solver.parameters.num_workers = 8\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
" print('%s found in %0.2fs' % (solver.StatusName(status), solver.WallTime()))\n",
|
||||
"\n",
|
||||
@@ -172,10 +173,16 @@
|
||||
" return status == cp_model.OPTIMAL\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"for num_squares in range(1, 15):\n",
|
||||
" print('Trying with size =', num_squares)\n",
|
||||
" if cover_rectangle(num_squares):\n",
|
||||
" break\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" for num_squares in range(1, 15):\n",
|
||||
" print('Trying with size =', num_squares)\n",
|
||||
" if cover_rectangle(num_squares):\n",
|
||||
" break\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
157
examples/notebook/examples/cryptarithm_sat.ipynb
Normal file
157
examples/notebook/examples/cryptarithm_sat.ipynb
Normal file
@@ -0,0 +1,157 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "google",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Copyright 2022 Google LLC."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "apache",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"you may not use this file except in compliance with the License.\n",
|
||||
"You may obtain a copy of the License at\n",
|
||||
"\n",
|
||||
" http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"\n",
|
||||
"Unless required by applicable law or agreed to in writing, software\n",
|
||||
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"See the License for the specific language governing permissions and\n",
|
||||
"limitations under the License.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "basename",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# cryptarithm_sat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "link",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<table align=\"left\">\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/examples/cryptarithm_sat.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
||||
"</td>\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://github.com/google/or-tools/blob/main/examples/python/cryptarithm_sat.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
||||
"</td>\n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "doc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "install",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install ortools"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Use CP-SAT to solve a simple cryptarithmetic problem: SEND+MORE=MONEY.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def send_more_money():\n",
|
||||
" \"\"\"Solve the cryptarithmic puzzle SEND+MORE=MONEY.\n",
|
||||
" \"\"\"\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
"\n",
|
||||
" # Create variables.\n",
|
||||
" # Since s is a leading digit, it can't be 0.\n",
|
||||
" s = model.NewIntVar(1, 9, 's')\n",
|
||||
" e = model.NewIntVar(0, 9, 'e')\n",
|
||||
" n = model.NewIntVar(0, 9, 'n')\n",
|
||||
" d = model.NewIntVar(0, 9, 'd')\n",
|
||||
" # Since m is a leading digit, it can't be 0.\n",
|
||||
" m = model.NewIntVar(1, 9, 'm')\n",
|
||||
" o = model.NewIntVar(0, 9, 'o')\n",
|
||||
" r = model.NewIntVar(0, 9, 'r')\n",
|
||||
" y = model.NewIntVar(0, 9, 'y')\n",
|
||||
"\n",
|
||||
" # Create carry variables. c0 is true if the first column of addends carries\n",
|
||||
" # a 1, c2 is true if the second column carries a 1, and so on.\n",
|
||||
" c0 = model.NewBoolVar('c0')\n",
|
||||
" c1 = model.NewBoolVar('c1')\n",
|
||||
" c2 = model.NewBoolVar('c2')\n",
|
||||
" c3 = model.NewBoolVar('c3')\n",
|
||||
"\n",
|
||||
" # Force all letters to take on different values.\n",
|
||||
" model.AddAllDifferent(s, e, n, d, m, o, r, y)\n",
|
||||
"\n",
|
||||
" # Column 0:\n",
|
||||
" model.Add(c0 == m)\n",
|
||||
"\n",
|
||||
" # Column 1:\n",
|
||||
" model.Add(c1 + s + m == o + 10 * c0)\n",
|
||||
"\n",
|
||||
" # Column 2:\n",
|
||||
" model.Add(c2 + e + o == n + 10 * c1)\n",
|
||||
"\n",
|
||||
" # Column 3:\n",
|
||||
" model.Add(c3 + n + r == e + 10 * c2)\n",
|
||||
"\n",
|
||||
" # Column 4:\n",
|
||||
" model.Add(d + e == y + 10 * c3)\n",
|
||||
"\n",
|
||||
" # Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" if solver.Solve(model) == cp_model.OPTIMAL:\n",
|
||||
" print('Optimal solution found!')\n",
|
||||
" print('s:', solver.Value(s))\n",
|
||||
" print('e:', solver.Value(e))\n",
|
||||
" print('n:', solver.Value(n))\n",
|
||||
" print('d:', solver.Value(d))\n",
|
||||
" print('m:', solver.Value(m))\n",
|
||||
" print('o:', solver.Value(o))\n",
|
||||
" print('r:', solver.Value(r))\n",
|
||||
" print('y:', solver.Value(y))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(_):\n",
|
||||
" send_more_money()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -91,7 +91,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ortools.sat.python import visualization\n",
|
||||
"from ortools.sat.colab import visualization\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
|
||||
@@ -80,7 +80,6 @@
|
||||
"The idea is to put marks on a rule such that all differences\n",
|
||||
"between all marks are all different. The objective is to minimize the length\n",
|
||||
"of the rule.\n",
|
||||
"see: https://en.wikipedia.org/wiki/Golomb_ruler\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
@@ -95,73 +94,50 @@
|
||||
"\n",
|
||||
"class FLAGS: pass\n",
|
||||
"\n",
|
||||
"FLAGS.order = 8 # Order of the ruler.\n",
|
||||
"\n",
|
||||
"def solve_golomb_ruler(order):\n",
|
||||
"def main(_):\n",
|
||||
" # Create the solver.\n",
|
||||
" solver = pywrapcp.Solver('golomb ruler')\n",
|
||||
"\n",
|
||||
" var_max = order * order\n",
|
||||
" all_vars = list(range(0, order))\n",
|
||||
" size = 8\n",
|
||||
" var_max = size * size\n",
|
||||
" all_vars = list(range(0, size))\n",
|
||||
"\n",
|
||||
" marks = [solver.IntVar(0, var_max, f'marks_{i}') for i in all_vars]\n",
|
||||
" marks = [solver.IntVar(0, var_max, 'marks_%d' % i) for i in all_vars]\n",
|
||||
"\n",
|
||||
" objective = solver.Minimize(marks[size - 1], 1)\n",
|
||||
"\n",
|
||||
" solver.Add(marks[0] == 0)\n",
|
||||
" for i in range(order - 2):\n",
|
||||
" solver.Add(marks[i + 1] > marks[i])\n",
|
||||
"\n",
|
||||
" # We expand the creation of the diff array to avoid a pylint warning.\n",
|
||||
" diffs = []\n",
|
||||
" for i in range(order - 1):\n",
|
||||
" for j in range(i + 1, order):\n",
|
||||
" for i in range(size - 1):\n",
|
||||
" for j in range(i + 1, size):\n",
|
||||
" diffs.append(marks[j] - marks[i])\n",
|
||||
" solver.Add(solver.AllDifferent(diffs))\n",
|
||||
"\n",
|
||||
" # symmetry breaking\n",
|
||||
" if order > 2:\n",
|
||||
" solver.Add(marks[order - 1] - marks[order - 2] > marks[1] - marks[0])\n",
|
||||
" solver.Add(marks[size - 1] - marks[size - 2] > marks[1] - marks[0])\n",
|
||||
" for i in range(size - 2):\n",
|
||||
" solver.Add(marks[i + 1] > marks[i])\n",
|
||||
"\n",
|
||||
" # objective\n",
|
||||
" objective = solver.Minimize(marks[order - 1], 1)\n",
|
||||
"\n",
|
||||
" # Solve the model.\n",
|
||||
" solution = solver.Assignment()\n",
|
||||
" for mark in marks:\n",
|
||||
" solution.Add(mark)\n",
|
||||
" for diff in diffs:\n",
|
||||
" solution.Add(diff)\n",
|
||||
" solution.Add(marks[size - 1])\n",
|
||||
" collector = solver.AllSolutionCollector(solution)\n",
|
||||
"\n",
|
||||
" solver.Solve(\n",
|
||||
" solver.Phase(\n",
|
||||
" marks,\n",
|
||||
" solver.CHOOSE_FIRST_UNBOUND,\n",
|
||||
" solver.ASSIGN_MIN_VALUE),\n",
|
||||
" [objective, collector])\n",
|
||||
"\n",
|
||||
" # Print solution.\n",
|
||||
" solver.Phase(marks, solver.CHOOSE_FIRST_UNBOUND,\n",
|
||||
" solver.ASSIGN_MIN_VALUE), [objective, collector])\n",
|
||||
" for i in range(0, collector.SolutionCount()):\n",
|
||||
" obj_value = collector.Value(i, marks[order - 1])\n",
|
||||
" print(f'Solution #{i}: value = {obj_value}')\n",
|
||||
" for idx, var in enumerate(marks):\n",
|
||||
" print(f'mark[{idx}]: {collector.Value(i, var)}')\n",
|
||||
" intervals = [collector.Value(i, diff) for diff in diffs]\n",
|
||||
" intervals.sort()\n",
|
||||
" print(f'intervals: {intervals}')\n",
|
||||
"\n",
|
||||
" print('Statistics:')\n",
|
||||
" print(f'- conflicts: {collector.Failures(i)}')\n",
|
||||
" print(f'- branches : {collector.Branches(i)}')\n",
|
||||
" print(f'- wall time: {collector.WallTime(i)}ms\\n')\n",
|
||||
"\n",
|
||||
" print('Global Statistics:')\n",
|
||||
" print(f'- total conflicts: {solver.Failures()}')\n",
|
||||
" print(f'- total branches : {solver.Branches()}')\n",
|
||||
" print(f'- total wall time: {solver.WallTime()}ms\\n')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(_=None):\n",
|
||||
" solve_golomb_ruler(FLAGS.order)\n",
|
||||
" obj_value = collector.Value(i, marks[size - 1])\n",
|
||||
" time = collector.WallTime(i)\n",
|
||||
" branches = collector.Branches(i)\n",
|
||||
" failures = collector.Failures(i)\n",
|
||||
" print(('Solution #%i: value = %i, failures = %i, branches = %i,'\n",
|
||||
" 'time = %i ms') % (i, obj_value, failures, branches, time))\n",
|
||||
" time = solver.WallTime()\n",
|
||||
" branches = solver.Branches()\n",
|
||||
" failures = solver.Failures()\n",
|
||||
" print(('Total run : failures = %i, branches = %i, time = %i ms' %\n",
|
||||
" (failures, branches, time)))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -91,15 +91,19 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from google.protobuf import text_format\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"class FLAGS: pass\n",
|
||||
"_ORDER = flags.DEFINE_integer('order', 8, 'Order of the ruler.')\n",
|
||||
"_PARAMS = flags.DEFINE_string(\n",
|
||||
" 'params',\n",
|
||||
" 'num_search_workers:16,log_search_progress:true,max_time_in_seconds:45',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
"\n",
|
||||
"FLAGS.order = 8 # Order of the ruler.\n",
|
||||
"FLAGS.params = 'max_time_in_seconds:10.0' # Sat solver parameters.\n",
|
||||
"\n",
|
||||
"def solve_golomb_ruler(order, params):\n",
|
||||
" \"\"\"Solve the Golomb ruler problem.\"\"\"\n",
|
||||
" # Create the model.\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
"\n",
|
||||
@@ -150,8 +154,10 @@
|
||||
" print(f'- wall time: {solver.WallTime()}s\\n')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(_=None):\n",
|
||||
" solve_golomb_ruler(FLAGS.order, FLAGS.params)\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" solve_golomb_ruler(_ORDER.value, _PARAMS.value)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ortools.sat.python import visualization\n",
|
||||
"from ortools.sat.colab import visualization\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
"\n",
|
||||
"pywrapinit.CppBridge.InitLogging('integer_programming.py')\n",
|
||||
"cpp_flags = pywrapinit.CppFlags()\n",
|
||||
"cpp_flags.logtostderr = True\n",
|
||||
"cpp_flags.stderrthreshold = 0\n",
|
||||
"cpp_flags.log_prefix = False\n",
|
||||
"pywrapinit.CppBridge.SetFlags(cpp_flags)\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
"source": [
|
||||
"import collections\n",
|
||||
"\n",
|
||||
"from ortools.sat.python import visualization\n",
|
||||
"from ortools.sat.colab import visualization\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import collections\n",
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -214,7 +215,13 @@
|
||||
" print(' - wall time : %f s' % solver.WallTime())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"jobshop_with_maintenance()\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" jobshop_with_maintenance()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -99,8 +99,9 @@
|
||||
" 'output_proto', '', 'Output file to write the cp_model proto to.')\n",
|
||||
"_PARAMS = flags.DEFINE_string(\n",
|
||||
" 'params',\n",
|
||||
" 'num_search_workers:16,log_search_progress:true,max_time_in_seconds:10.0',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
" 'num_search_workers:16,log_search_progress:true,max_time_in_seconds:45',\n",
|
||||
" 'Sat solver parameters.',\n",
|
||||
")\n",
|
||||
"_MODEL = flags.DEFINE_string('model', 'rotation',\n",
|
||||
" '\\'duplicate\\' or \\'rotation\\' or \\'optional\\'')\n",
|
||||
"\n",
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
"from typing import Sequence\n",
|
||||
"\n",
|
||||
"from google.protobuf import text_format\n",
|
||||
"\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"_INPUT = flags.DEFINE_string('input', '', 'Input file to parse and solve.')\n",
|
||||
@@ -108,7 +109,6 @@
|
||||
" 'output_proto', '', 'Output file to write the cp_model proto to.')\n",
|
||||
"_MODEL = flags.DEFINE_string('model', 'boolean',\n",
|
||||
" 'Model used: boolean, scheduling, greedy')\n",
|
||||
"# pytype: disable=wrong-arg-types\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class SectionInfo(object):\n",
|
||||
@@ -326,14 +326,14 @@
|
||||
" for t in all_tasks:\n",
|
||||
" model.AddHint(assign[t, hint[t]], 1)\n",
|
||||
"\n",
|
||||
" if FLAGS.output_proto:\n",
|
||||
" print(f'Writing proto to {FLAGS.output_proto}')\n",
|
||||
" model.ExportToFile(FLAGS.output_proto)\n",
|
||||
" if _OUTPUT_PROTO.value:\n",
|
||||
" print(f'Writing proto to {_OUTPUT_PROTO.value}')\n",
|
||||
" model.ExportToFile(_OUTPUT_PROTO.value)\n",
|
||||
"\n",
|
||||
" # Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" if FLAGS.params:\n",
|
||||
" text_format.Parse(FLAGS.params, solver.parameters)\n",
|
||||
" if _PARAMS.value:\n",
|
||||
" text_format.Parse(_PARAMS.value, solver.parameters)\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
" solver.Solve(model)\n",
|
||||
"\n",
|
||||
@@ -388,32 +388,29 @@
|
||||
" for t in all_tasks:\n",
|
||||
" model.AddHint(pods[t], hint[t])\n",
|
||||
"\n",
|
||||
" if FLAGS.output_proto:\n",
|
||||
" print(f'Writing proto to{FLAGS.output_proto}')\n",
|
||||
" model.ExportToFile(FLAGS.output_proto)\n",
|
||||
" if _OUTPUT_PROTO.value:\n",
|
||||
" print(f'Writing proto to{_OUTPUT_PROTO.value}')\n",
|
||||
" model.ExportToFile(_OUTPUT_PROTO.value)\n",
|
||||
"\n",
|
||||
" # Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" if FLAGS.params:\n",
|
||||
" text_format.Parse(FLAGS.params, solver.parameters)\n",
|
||||
" if _PARAMS.value:\n",
|
||||
" text_format.Parse(_PARAMS.value, solver.parameters)\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
" solver.parameters.exploit_all_precedences = True # Helps with the lower bound.\n",
|
||||
" solver.Solve(model)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" if FLAGS.input == '':\n",
|
||||
" raise app.UsageError('Missing input file.')\n",
|
||||
"\n",
|
||||
" model = read_model(FLAGS.input)\n",
|
||||
" model = read_model(_INPUT.value)\n",
|
||||
" print_stats(model)\n",
|
||||
" greedy_solution = solve_model_greedily(model)\n",
|
||||
"\n",
|
||||
" if FLAGS.model == 'boolean':\n",
|
||||
" if _MODEL.value == 'boolean':\n",
|
||||
" solve_boolean_model(model, greedy_solution)\n",
|
||||
" elif FLAGS.model == 'scheduling':\n",
|
||||
" elif _MODEL.value == 'scheduling':\n",
|
||||
" solve_scheduling_model(model, greedy_solution)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
|
||||
@@ -87,10 +87,11 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.graph.python import linear_sum_assignment\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def RunAssignmentOn4x4Matrix():\n",
|
||||
"def run_assignment_on_4x4_matrix():\n",
|
||||
" \"\"\"Test linear sum assignment on a 4x4 matrix.\"\"\"\n",
|
||||
" num_sources = 4\n",
|
||||
" num_targets = 4\n",
|
||||
@@ -117,8 +118,10 @@
|
||||
" 'Some input costs are too large and may cause an integer overflow.')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(_=None):\n",
|
||||
" RunAssignmentOn4x4Matrix()\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" run_assignment_on_4x4_matrix()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -93,10 +93,12 @@
|
||||
"from google.protobuf import text_format\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"class FLAGS: pass\n",
|
||||
"_OUTPUT_PROTO = flags.DEFINE_string(\n",
|
||||
" 'output_proto', '', 'Output file to write the cp_model proto to.')\n",
|
||||
"_PARAMS = flags.DEFINE_string('params',\n",
|
||||
" 'num_search_workers:8,log_search_progress:true',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
"\n",
|
||||
"FLAGS.output_proto = '' # Output file to write the cp_model proto to.\n",
|
||||
"FLAGS.params = 'num_search_workers:8,log_search_progress:true' # Sat solver parameters.\n",
|
||||
"\n",
|
||||
"def add_neighbor(size, x, y, z, dx, dy, dz, model, index_map, position_to_rank,\n",
|
||||
" arcs):\n",
|
||||
@@ -206,7 +208,7 @@
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" escape_the_maze(FLAGS.params, FLAGS.output_proto)\n",
|
||||
" escape_the_maze(_PARAMS.value, _OUTPUT_PROTO.value)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -93,10 +93,13 @@
|
||||
"from google.protobuf import text_format\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"class FLAGS: pass\n",
|
||||
"_PARAMS = flags.DEFINE_string('params',\n",
|
||||
" 'num_search_workers:16, max_time_in_seconds:30',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
"_PROTO_FILE = flags.DEFINE_string(\n",
|
||||
" 'proto_file', '', 'If not empty, output the proto to this file.')\n",
|
||||
"\n",
|
||||
"FLAGS.params = 'num_search_workers:16, max_time_in_seconds:30' # Sat solver parameters.\n",
|
||||
"FLAGS.proto_file = '' # If not empty, output the proto to this file.\n",
|
||||
"# Recipes\n",
|
||||
"CROISSANT = 'croissant'\n",
|
||||
"APPLE_PIE = 'apple pie'\n",
|
||||
"BRIOCHE = 'brioche'\n",
|
||||
@@ -339,8 +342,8 @@
|
||||
"\n",
|
||||
" # Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" if FLAGS.params:\n",
|
||||
" text_format.Parse(FLAGS.params, solver.parameters)\n",
|
||||
" if _PARAMS.value:\n",
|
||||
" text_format.Parse(_PARAMS.value, solver.parameters)\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
"\n",
|
||||
|
||||
177
examples/notebook/examples/nqueens_sat.ipynb
Normal file
177
examples/notebook/examples/nqueens_sat.ipynb
Normal file
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "google",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Copyright 2022 Google LLC."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "apache",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"you may not use this file except in compliance with the License.\n",
|
||||
"You may obtain a copy of the License at\n",
|
||||
"\n",
|
||||
" http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"\n",
|
||||
"Unless required by applicable law or agreed to in writing, software\n",
|
||||
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"See the License for the specific language governing permissions and\n",
|
||||
"limitations under the License.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "basename",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# nqueens_sat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "link",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<table align=\"left\">\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/examples/nqueens_sat.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
||||
"</td>\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://github.com/google/or-tools/blob/main/examples/python/nqueens_sat.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
||||
"</td>\n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "doc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "install",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install ortools"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"CP/SAT model for the N-queens problem.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"_SIZE = flags.DEFINE_integer('size', 8, 'Number of queens.')\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",
|
||||
"\n",
|
||||
" def SolutionCount(self):\n",
|
||||
" return self.__solution_count\n",
|
||||
"\n",
|
||||
" def on_solution_callback(self):\n",
|
||||
" current_time = time.time()\n",
|
||||
" print('Solution %i, time = %f s' %\n",
|
||||
" (self.__solution_count, current_time - self.__start_time))\n",
|
||||
" self.__solution_count += 1\n",
|
||||
"\n",
|
||||
" all_queens = range(len(self.__queens))\n",
|
||||
" for i in all_queens:\n",
|
||||
" 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",
|
||||
" else:\n",
|
||||
" print('_', end=' ')\n",
|
||||
" print()\n",
|
||||
" print()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(_):\n",
|
||||
" board_size = _SIZE.value\n",
|
||||
"\n",
|
||||
" ### Creates the solver.\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
"\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",
|
||||
"\n",
|
||||
" ### Creates the constraints.\n",
|
||||
"\n",
|
||||
" # All columns must be different because the indices of queens are all\n",
|
||||
" # different, so we just add the all different constraint on the rows.\n",
|
||||
" model.AddAllDifferent(queens)\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",
|
||||
"\n",
|
||||
" ### Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" solution_printer = NQueenSolutionPrinter(queens)\n",
|
||||
" # Enumerate all solutions.\n",
|
||||
" solver.parameters.enumerate_all_solutions = True\n",
|
||||
" # Solve.\n",
|
||||
" solver.Solve(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 s' % solver.WallTime())\n",
|
||||
" print(' - solutions found : %i' % solution_printer.SolutionCount())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -82,8 +82,10 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"DISTANCE_MATRIX = [\n",
|
||||
" [0, 10938, 4542, 2835, 29441, 2171, 1611, 9208, 9528, 11111, 16120, 22606, 22127, 20627, 21246, 23387, 16697, 33609, 26184, 24772, 22644, 20655, 30492, 23296, 32979, 18141, 19248, 17129, 17192, 15645, 12658, 11210, 12094, 13175, 18162, 4968, 12308, 10084, 13026, 15056],\n",
|
||||
" [10938, 0, 6422, 9742, 18988, 12974, 11216, 19715, 19004, 18271, 25070, 31971, 31632, 30571, 31578, 33841, 27315, 43964, 36944, 35689, 33569, 31481, 41360, 33760, 43631, 28730, 29976, 27803, 28076, 26408, 23504, 22025, 22000, 13197, 14936, 15146, 23246, 20956, 23963, 25994],\n",
|
||||
@@ -125,13 +127,14 @@
|
||||
" [10084, 20956, 14618, 12135, 38935, 8306, 9793, 2615, 5850, 10467, 9918, 14568, 13907, 11803, 11750, 13657, 6901, 23862, 16125, 14748, 12981, 11624, 21033, 15358, 24144, 10304, 10742, 9094, 8042, 7408, 4580, 4072, 8446, 20543, 26181, 7668, 2747, 0, 3330, 5313],\n",
|
||||
" [13026, 23963, 17563, 14771, 42160, 11069, 12925, 5730, 8778, 13375, 11235, 14366, 13621, 11188, 10424, 11907, 5609, 21861, 13624, 11781, 9718, 8304, 17737, 12200, 20816, 7330, 7532, 6117, 4735, 4488, 2599, 3355, 7773, 22186, 27895, 9742, 726, 3330, 0, 2042],\n",
|
||||
" [15056, 25994, 19589, 16743, 44198, 13078, 14967, 7552, 10422, 14935, 11891, 14002, 13225, 10671, 9475, 10633, 5084, 20315, 11866, 9802, 7682, 6471, 15720, 10674, 18908, 6204, 6000, 5066, 3039, 3721, 3496, 4772, 8614, 23805, 29519, 11614, 2749, 5313, 2042, 0],\n",
|
||||
"] # yapf: disable\n",
|
||||
"] # yapf: disable\n",
|
||||
"\n",
|
||||
"MAX_DISTANCE = 80_000\n",
|
||||
"\n",
|
||||
"VISIT_VALUES = [60_000, 50_000, 40_000, 30_000] * (len(DISTANCE_MATRIX) // 4)\n",
|
||||
"VISIT_VALUES[0] = 0\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Create a console solution printer.\n",
|
||||
"def print_solution(solver, visited_nodes, used_arcs, num_nodes):\n",
|
||||
" \"\"\"Prints solution on console.\"\"\"\n",
|
||||
@@ -167,7 +170,8 @@
|
||||
" plan_output += f'Value collected: {value_collected}/{sum(VISIT_VALUES)}\\n'\n",
|
||||
" print(plan_output)\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
"\n",
|
||||
"def prize_collecting_tsp():\n",
|
||||
" \"\"\"Entry point of the program.\"\"\"\n",
|
||||
" num_nodes = len(DISTANCE_MATRIX)\n",
|
||||
" all_nodes = range(num_nodes)\n",
|
||||
@@ -208,10 +212,10 @@
|
||||
" model.Add(visited_nodes[0] == 1)\n",
|
||||
"\n",
|
||||
" # limit the route distance\n",
|
||||
" model.Add(sum(used_arcs[i, j] * DISTANCE_MATRIX[i][j]\n",
|
||||
" for i in all_nodes\n",
|
||||
" for j in all_nodes) <= MAX_DISTANCE)\n",
|
||||
"\n",
|
||||
" model.Add(\n",
|
||||
" sum(used_arcs[i, j] * DISTANCE_MATRIX[i][j]\n",
|
||||
" for i in all_nodes\n",
|
||||
" for j in all_nodes) <= MAX_DISTANCE)\n",
|
||||
"\n",
|
||||
" # Maximize visited node values minus the travelled distance.\n",
|
||||
" model.Maximize(\n",
|
||||
@@ -222,13 +226,18 @@
|
||||
" # To benefit from the linearization of the circuit constraint.\n",
|
||||
" solver.parameters.max_time_in_seconds = 15.0\n",
|
||||
" solver.parameters.num_search_workers = 8\n",
|
||||
" # solver.parameters.log_search_progress = True\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
"\n",
|
||||
" solver.Solve(model)\n",
|
||||
" #print(solver.ResponseStats())\n",
|
||||
" print_solution(solver, visited_nodes, used_arcs, num_nodes)\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
" if status == cp_model.FEASIBLE or status == cp_model.OPTIMAL:\n",
|
||||
" print_solution(solver, visited_nodes, used_arcs, num_nodes)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" prize_collecting_tsp()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Simple prize collecting TSP problem with a max distance.\n"
|
||||
"Simple prize collecting VRP problem with a max distance.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -82,8 +82,10 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"DISTANCE_MATRIX = [\n",
|
||||
" [0, 10938, 4542, 2835, 29441, 2171, 1611, 9208, 9528, 11111, 16120, 22606, 22127, 20627, 21246, 23387, 16697, 33609, 26184, 24772, 22644, 20655, 30492, 23296, 32979, 18141, 19248, 17129, 17192, 15645, 12658, 11210, 12094, 13175, 18162, 4968, 12308, 10084, 13026, 15056],\n",
|
||||
" [10938, 0, 6422, 9742, 18988, 12974, 11216, 19715, 19004, 18271, 25070, 31971, 31632, 30571, 31578, 33841, 27315, 43964, 36944, 35689, 33569, 31481, 41360, 33760, 43631, 28730, 29976, 27803, 28076, 26408, 23504, 22025, 22000, 13197, 14936, 15146, 23246, 20956, 23963, 25994],\n",
|
||||
@@ -125,13 +127,14 @@
|
||||
" [10084, 20956, 14618, 12135, 38935, 8306, 9793, 2615, 5850, 10467, 9918, 14568, 13907, 11803, 11750, 13657, 6901, 23862, 16125, 14748, 12981, 11624, 21033, 15358, 24144, 10304, 10742, 9094, 8042, 7408, 4580, 4072, 8446, 20543, 26181, 7668, 2747, 0, 3330, 5313],\n",
|
||||
" [13026, 23963, 17563, 14771, 42160, 11069, 12925, 5730, 8778, 13375, 11235, 14366, 13621, 11188, 10424, 11907, 5609, 21861, 13624, 11781, 9718, 8304, 17737, 12200, 20816, 7330, 7532, 6117, 4735, 4488, 2599, 3355, 7773, 22186, 27895, 9742, 726, 3330, 0, 2042],\n",
|
||||
" [15056, 25994, 19589, 16743, 44198, 13078, 14967, 7552, 10422, 14935, 11891, 14002, 13225, 10671, 9475, 10633, 5084, 20315, 11866, 9802, 7682, 6471, 15720, 10674, 18908, 6204, 6000, 5066, 3039, 3721, 3496, 4772, 8614, 23805, 29519, 11614, 2749, 5313, 2042, 0],\n",
|
||||
"] # yapf: disable\n",
|
||||
"] # yapf: disable\n",
|
||||
"\n",
|
||||
"MAX_DISTANCE = 80_000\n",
|
||||
"\n",
|
||||
"VISIT_VALUES = [60_000, 50_000, 40_000, 30_000] * (len(DISTANCE_MATRIX) // 4)\n",
|
||||
"VISIT_VALUES[0] = 0\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Create a console solution printer.\n",
|
||||
"def print_solution(solver, visited_nodes, used_arcs, num_nodes, num_vehicles):\n",
|
||||
" \"\"\"Prints solution on console.\"\"\"\n",
|
||||
@@ -140,7 +143,10 @@
|
||||
" for node in range(num_nodes):\n",
|
||||
" if node == 0:\n",
|
||||
" continue\n",
|
||||
" is_visited = sum([solver.BooleanValue(visited_nodes[v][node]) for v in range(num_vehicles)])\n",
|
||||
" is_visited = sum([\n",
|
||||
" solver.BooleanValue(visited_nodes[v][node])\n",
|
||||
" for v in range(num_vehicles)\n",
|
||||
" ])\n",
|
||||
" if not is_visited:\n",
|
||||
" dropped_nodes += f' {node}({VISIT_VALUES[node]})'\n",
|
||||
" print(dropped_nodes)\n",
|
||||
@@ -175,7 +181,8 @@
|
||||
" print(f'Total Distance: {total_distance}m')\n",
|
||||
" print(f'Total Value collected: {total_value_collected}/{sum(VISIT_VALUES)}')\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
"\n",
|
||||
"def prize_collecting_vrp():\n",
|
||||
" \"\"\"Entry point of the program.\"\"\"\n",
|
||||
" num_nodes = len(DISTANCE_MATRIX)\n",
|
||||
" num_vehicles = 4\n",
|
||||
@@ -220,13 +227,15 @@
|
||||
" model.Add(visited_nodes[v][0] == 1)\n",
|
||||
"\n",
|
||||
" # limit the route distance\n",
|
||||
" model.Add(sum(used_arcs[v][i, j] * DISTANCE_MATRIX[i][j]\n",
|
||||
" for i in all_nodes\n",
|
||||
" for j in all_nodes) <= MAX_DISTANCE)\n",
|
||||
" model.Add(\n",
|
||||
" sum(used_arcs[v][i, j] * DISTANCE_MATRIX[i][j]\n",
|
||||
" for i in all_nodes\n",
|
||||
" for j in all_nodes) <= MAX_DISTANCE)\n",
|
||||
"\n",
|
||||
" # Each node is visited at most once\n",
|
||||
" for node in range(1, num_nodes):\n",
|
||||
" model.AddAtMostOne([visited_nodes[v][node] for v in range(num_vehicles)])\n",
|
||||
" model.AddAtMostOne(\n",
|
||||
" [visited_nodes[v][node] for v in range(num_vehicles)])\n",
|
||||
"\n",
|
||||
" # Maximize visited node values minus the travelled distance.\n",
|
||||
" model.Maximize(\n",
|
||||
@@ -236,15 +245,18 @@
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" solver.parameters.num_search_workers = 8\n",
|
||||
" solver.parameters.max_time_in_seconds = 15.0\n",
|
||||
" # solver.parameters.log_search_progress = True\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
"\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
" if status == cp_model.FEASIBLE or status == cp_model.OPTIMAL:\n",
|
||||
" print(f'search returned with the status {solver.StatusName(status)}')\n",
|
||||
" print_solution(solver, visited_nodes, used_arcs,\n",
|
||||
" num_nodes, num_vehicles)\n",
|
||||
" else:\n",
|
||||
" print(solver.ResponseStats())\n",
|
||||
" print_solution(solver, visited_nodes, used_arcs, num_nodes,\n",
|
||||
" num_vehicles)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" prize_collecting_vrp()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -82,11 +82,12 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.graph.python import max_flow\n",
|
||||
"from ortools.graph.python import min_cost_flow\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def MaxFlow():\n",
|
||||
"def max_flow_api():\n",
|
||||
" \"\"\"MaxFlow simple interface example.\"\"\"\n",
|
||||
" print('MaxFlow on a simple network.')\n",
|
||||
" tails = [0, 0, 0, 0, 1, 2, 3, 3, 4]\n",
|
||||
@@ -107,7 +108,7 @@
|
||||
" print('There was an issue with the max flow input.')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def MinCostFlow():\n",
|
||||
"def min_cost_flow_api():\n",
|
||||
" \"\"\"MinCostFlow simple interface example.\n",
|
||||
"\n",
|
||||
" Note that this example is actually a linear sum assignment example and will\n",
|
||||
@@ -140,9 +141,11 @@
|
||||
" print('There was an issue with the min cost flow input.')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(_=None):\n",
|
||||
" MaxFlow()\n",
|
||||
" MinCostFlow()\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" max_flow_api()\n",
|
||||
" min_cost_flow_api()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -573,8 +573,7 @@
|
||||
" # Write model to file.\n",
|
||||
" if proto_file:\n",
|
||||
" print(f'Writing proto to{proto_file}')\n",
|
||||
" with open(proto_file, 'w') as text_file:\n",
|
||||
" text_file.write(str(model))\n",
|
||||
" model.ExportToFile(proto_file)\n",
|
||||
"\n",
|
||||
" # Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
|
||||
@@ -124,8 +124,8 @@
|
||||
" soft_max, hard_max, max_cost, prefix):\n",
|
||||
" \"\"\"Sequence constraint on true variables with soft and hard bounds.\n",
|
||||
"\n",
|
||||
" This constraint looks at every maximal contiguous sequence of variables\n",
|
||||
" assigned to true. It forbids sequence of length < hard_min or > hard_max.\n",
|
||||
" This constraint look at every maximal contiguous sequence of variables\n",
|
||||
" assigned to true. If forbids sequence of length < hard_min or > hard_max.\n",
|
||||
" Then it creates penalty terms if the length is < soft_min or > soft_max.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
|
||||
@@ -82,25 +82,20 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import argparse\n",
|
||||
"\n",
|
||||
"from typing import Sequence\n",
|
||||
"from google.protobuf import text_format\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"#----------------------------------------------------------------------------\n",
|
||||
"# Command line arguments.\n",
|
||||
"PARSER = argparse.ArgumentParser()\n",
|
||||
"PARSER.add_argument(\n",
|
||||
" '--output_proto_file',\n",
|
||||
" default='',\n",
|
||||
" help='Output file to write the cp_model'\n",
|
||||
" 'proto to.')\n",
|
||||
"PARSER.add_argument('--params', default='', help='Sat solver parameters.')\n",
|
||||
"PARSER.add_argument(\n",
|
||||
" '--preprocess_times',\n",
|
||||
" default=True,\n",
|
||||
" type=bool,\n",
|
||||
" help='Preprocess setup times and durations')\n",
|
||||
"_OUTPUT_PROTO = flags.DEFINE_string(\n",
|
||||
" 'output_proto', '', 'Output file to write the cp_model proto to.')\n",
|
||||
"_PARAMS = flags.DEFINE_string(\n",
|
||||
" 'params',\n",
|
||||
" 'num_search_workers:16,log_search_progress:true,max_time_in_seconds:45',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
"_PREPROCESS = flags.DEFINE_bool('--preprocess_times', True,\n",
|
||||
" 'Preprocess setup times and durations')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"#----------------------------------------------------------------------------\n",
|
||||
@@ -119,11 +114,11 @@
|
||||
" self.__solution_count += 1\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(args):\n",
|
||||
"def single_machine_scheduling():\n",
|
||||
" \"\"\"Solves a complex single machine jobshop scheduling problem.\"\"\"\n",
|
||||
"\n",
|
||||
" parameters = args.params\n",
|
||||
" output_proto_file = args.output_proto_file\n",
|
||||
" parameters = _PARAMS.value\n",
|
||||
" output_proto_file = _OUTPUT_PROTO.value\n",
|
||||
"\n",
|
||||
" #----------------------------------------------------------------------------\n",
|
||||
" # Data.\n",
|
||||
@@ -217,7 +212,7 @@
|
||||
"\n",
|
||||
" #----------------------------------------------------------------------------\n",
|
||||
" # Preprocess.\n",
|
||||
" if args.preprocess_times:\n",
|
||||
" if _PREPROCESS.value:\n",
|
||||
" for job_id in all_jobs:\n",
|
||||
" min_incoming_setup = min(\n",
|
||||
" setup_times[j][job_id] for j in range(num_jobs + 1))\n",
|
||||
@@ -245,7 +240,8 @@
|
||||
" #----------------------------------------------------------------------------\n",
|
||||
" # Compute a maximum makespan greedily.\n",
|
||||
" horizon = sum(job_durations) + sum(\n",
|
||||
" max(setup_times[i][j] for i in range(num_jobs + 1))\n",
|
||||
" max(setup_times[i][j]\n",
|
||||
" for i in range(num_jobs + 1))\n",
|
||||
" for j in range(num_jobs))\n",
|
||||
" print('Greedy horizon =', horizon)\n",
|
||||
"\n",
|
||||
@@ -302,8 +298,8 @@
|
||||
" model.Add(starts[j] == ends[i] +\n",
|
||||
" setup_times[i + 1][j]).OnlyEnforceIf(lit)\n",
|
||||
" else:\n",
|
||||
" model.Add(starts[j] >=\n",
|
||||
" ends[i] + setup_times[i + 1][j]).OnlyEnforceIf(lit)\n",
|
||||
" model.Add(starts[j] >= ends[i] +\n",
|
||||
" setup_times[i + 1][j]).OnlyEnforceIf(lit)\n",
|
||||
"\n",
|
||||
" model.AddCircuit(arcs)\n",
|
||||
"\n",
|
||||
@@ -329,19 +325,23 @@
|
||||
" #----------------------------------------------------------------------------\n",
|
||||
" # Solve.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" solver.parameters.max_time_in_seconds = 60 * 60 * 2\n",
|
||||
" if parameters:\n",
|
||||
" text_format.Merge(parameters, solver.parameters)\n",
|
||||
" text_format.Parse(parameters, solver.parameters)\n",
|
||||
" solution_printer = SolutionPrinter()\n",
|
||||
" solver.Solve(model, solution_printer)\n",
|
||||
" print(solver.ResponseStats())\n",
|
||||
" for job_id in all_jobs:\n",
|
||||
" print('job %i starts at %i end ends at %i' %\n",
|
||||
" (job_id, solver.Value(starts[job_id]),\n",
|
||||
" solver.Value(ends[job_id])))\n",
|
||||
" print(\n",
|
||||
" 'job %i starts at %i end ends at %i' %\n",
|
||||
" (job_id, solver.Value(starts[job_id]), solver.Value(ends[job_id])))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main(PARSER.parse_args())\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" single_machine_scheduling()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
191
examples/notebook/examples/spread_robots_sat.ipynb
Normal file
191
examples/notebook/examples/spread_robots_sat.ipynb
Normal file
@@ -0,0 +1,191 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "google",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Copyright 2022 Google LLC."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "apache",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"you may not use this file except in compliance with the License.\n",
|
||||
"You may obtain a copy of the License at\n",
|
||||
"\n",
|
||||
" http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"\n",
|
||||
"Unless required by applicable law or agreed to in writing, software\n",
|
||||
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"See the License for the specific language governing permissions and\n",
|
||||
"limitations under the License.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "basename",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# spread_robots_sat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "link",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<table align=\"left\">\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/examples/spread_robots_sat.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
||||
"</td>\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://github.com/google/or-tools/blob/main/examples/python/spread_robots_sat.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
||||
"</td>\n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "doc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "install",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install ortools"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Maximize the minimum of pairwise distances between n robots in a square space.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import math\n",
|
||||
"from typing import Sequence\n",
|
||||
"from google.protobuf import text_format\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"_NUM_ROBOTS = flags.DEFINE_integer('num_robots', 8,\n",
|
||||
" 'Number of robots to place.')\n",
|
||||
"_ROOM_SIZE = flags.DEFINE_integer('room_size', 20,\n",
|
||||
" 'Size of the square room where robots are.')\n",
|
||||
"_PARAMS = flags.DEFINE_string(\n",
|
||||
" 'params',\n",
|
||||
" 'num_search_workers:16, max_time_in_seconds:20',\n",
|
||||
" 'Sat solver parameters.',\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def spread_robots(num_robots: int, room_size: int, params: str):\n",
|
||||
" \"\"\"Optimize robots placement.\"\"\"\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
"\n",
|
||||
" # Create the list of coordinates (x, y) for each robot.\n",
|
||||
" x = [model.NewIntVar(1, room_size, f'x_{i}') for i in range(num_robots)]\n",
|
||||
" y = [model.NewIntVar(1, room_size, f'y_{i}') for i in range(num_robots)]\n",
|
||||
"\n",
|
||||
" # The specification of the problem is to maximize the minimum euclidian\n",
|
||||
" # distance between any two robots. Unfortunately, the euclidian distance\n",
|
||||
" # uses the square root operation which is not defined on integer variables.\n",
|
||||
" # To work around, we will create a min_square_distance variable, then we make\n",
|
||||
" # sure that its value is less than the square of the euclidian distance\n",
|
||||
" # between any two robots.\n",
|
||||
" #\n",
|
||||
" # This encoding has a low precision. To improve the precision, we will scale\n",
|
||||
" # the domain of the min_square_distance variable by a constant factor, then\n",
|
||||
" # multiply the square of the euclidian distance between two robots by the same\n",
|
||||
" # factor.\n",
|
||||
" #\n",
|
||||
" # we create a scaled_min_square_distance variable with a domain of\n",
|
||||
" # [0..scaling * max euclidian distance**2] such that\n",
|
||||
" # forall i:\n",
|
||||
" # scaled_min_square_distance <= scaling * (x_diff_sq[i] + y_diff_sq[i])\n",
|
||||
" scaling = 1000\n",
|
||||
" scaled_min_square_distance = model.NewIntVar(0, 2 * scaling * room_size**2,\n",
|
||||
" 'scaled_min_square_distance')\n",
|
||||
"\n",
|
||||
" # Build intermediate variables and get the list of squared distances on\n",
|
||||
" # each dimension.\n",
|
||||
" for i in range(num_robots - 1):\n",
|
||||
" for j in range(i + 1, num_robots):\n",
|
||||
" # Compute the distance on each dimension between robot i and robot j.\n",
|
||||
" x_diff = model.NewIntVar(-room_size, room_size, f'x_diff{i}')\n",
|
||||
" y_diff = model.NewIntVar(-room_size, room_size, f'y_diff{i}')\n",
|
||||
" model.Add(x_diff == x[i] - x[j])\n",
|
||||
" model.Add(y_diff == y[i] - y[j])\n",
|
||||
"\n",
|
||||
" # Compute the square of the previous differences.\n",
|
||||
" x_diff_sq = model.NewIntVar(0, room_size**2, f'x_diff_sq{i}')\n",
|
||||
" y_diff_sq = model.NewIntVar(0, room_size**2, f'y_diff_sq{i}')\n",
|
||||
" model.AddMultiplicationEquality(x_diff_sq, x_diff, x_diff)\n",
|
||||
" model.AddMultiplicationEquality(y_diff_sq, y_diff, y_diff)\n",
|
||||
"\n",
|
||||
" # We just need to be <= to the scaled square distance as we are\n",
|
||||
" # maximizing the min distance, which is equivalent as maximizing the min\n",
|
||||
" # square distance.\n",
|
||||
" model.Add(scaled_min_square_distance <= scaling *\n",
|
||||
" (x_diff_sq + y_diff_sq))\n",
|
||||
"\n",
|
||||
" # Naive symmetry breaking.\n",
|
||||
" for i in range(1, num_robots):\n",
|
||||
" model.Add(x[0] <= x[i])\n",
|
||||
" model.Add(y[0] <= y[i])\n",
|
||||
"\n",
|
||||
" # Objective\n",
|
||||
" model.Maximize(scaled_min_square_distance)\n",
|
||||
"\n",
|
||||
" # Creates a solver and solves the model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" if params:\n",
|
||||
" text_format.Parse(params, solver.parameters)\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
"\n",
|
||||
" # Prints the solution.\n",
|
||||
" if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n",
|
||||
" print(f'Spread {num_robots} with a min pairwise distance of'\n",
|
||||
" f' {math.sqrt(solver.ObjectiveValue() / scaling)}')\n",
|
||||
" for i in range(num_robots):\n",
|
||||
" print(f'robot {i}: x={solver.Value(x[i])} y={solver.Value(y[i])}')\n",
|
||||
" else:\n",
|
||||
" print('No solution found.')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
"\n",
|
||||
" spread_robots(_NUM_ROBOTS.value, _ROOM_SIZE.value, _PARAMS.value)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -86,15 +86,13 @@
|
||||
"import collections\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"from ortools.linear_solver import pywraplp\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"_PROBLEM = flags.DEFINE_integer('problem', 2, 'Problem id to solve.')\n",
|
||||
"_BREAK_SYMMETRIES = flags.DEFINE_boolean(\n",
|
||||
" 'break_symmetries', True, 'Break symmetries between equivalent orders.')\n",
|
||||
"_SOLVER = flags.DEFINE_string(\n",
|
||||
" 'solver', 'mip_column', 'Method used to solve: sat, sat_table, sat_column, '\n",
|
||||
" 'mip_column.')\n",
|
||||
" 'solver', 'sat_column', 'Method used to solve: sat, sat_table, sat_column.')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def build_problem(problem_id):\n",
|
||||
@@ -736,70 +734,6 @@
|
||||
" print('No solution')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def steel_mill_slab_with_mip_column_generation(problem):\n",
|
||||
" \"\"\"Solves the Steel Mill Slab Problem.\"\"\"\n",
|
||||
" ### Load problem.\n",
|
||||
" (num_slabs, capacities, _, orders) = build_problem(problem)\n",
|
||||
"\n",
|
||||
" num_orders = len(orders)\n",
|
||||
" num_capacities = len(capacities)\n",
|
||||
" all_orders = range(len(orders))\n",
|
||||
" print('Solving steel mill with %i orders, %i slabs, and %i capacities' %\n",
|
||||
" (num_orders, num_slabs, num_capacities - 1))\n",
|
||||
"\n",
|
||||
" # Compute auxiliary data.\n",
|
||||
" widths = [x[0] for x in orders]\n",
|
||||
" colors = [x[1] for x in orders]\n",
|
||||
" max_capacity = max(capacities)\n",
|
||||
" loss_array = [\n",
|
||||
" min(x for x in capacities if x >= c) - c for c in range(max_capacity +\n",
|
||||
" 1)\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" ### Model problem.\n",
|
||||
"\n",
|
||||
" # Generate all valid slabs (columns)\n",
|
||||
" unsorted_valid_slabs = collect_valid_slabs_dp(capacities, colors, widths,\n",
|
||||
" loss_array)\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",
|
||||
" all_valid_slabs = range(len(valid_slabs))\n",
|
||||
"\n",
|
||||
" # create model and decision variables.\n",
|
||||
" start_time = time.time()\n",
|
||||
" solver = pywraplp.Solver.CreateSolver('SCIP')\n",
|
||||
" if not solver:\n",
|
||||
" return\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]\n",
|
||||
" for i in all_valid_slabs\n",
|
||||
" if valid_slabs[i][order]) == 1)\n",
|
||||
"\n",
|
||||
" # Redundant constraint (sum of loads == sum of 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(\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 %.2f s' %\n",
|
||||
" (solver.Objective().Value(), time.time() - start_time))\n",
|
||||
" else:\n",
|
||||
" print('No solution')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(_):\n",
|
||||
" if _SOLVER.value == 'sat':\n",
|
||||
" steel_mill_slab(_PROBLEM.value, _BREAK_SYMMETRIES.value)\n",
|
||||
@@ -808,8 +742,8 @@
|
||||
" _BREAK_SYMMETRIES.value)\n",
|
||||
" elif _SOLVER.value == 'sat_column':\n",
|
||||
" steel_mill_slab_with_column_generation(_PROBLEM.value)\n",
|
||||
" else: # 'mip_column'\n",
|
||||
" steel_mill_slab_with_mip_column_generation(_PROBLEM.value)\n",
|
||||
" else:\n",
|
||||
" print(f'Unknown model {_SOLVER.value}')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -73,9 +73,9 @@
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"CP-SAT model for task allocation problem.\n",
|
||||
"see\n",
|
||||
"http://yetanothermathprogrammingconsultant.blogspot.com/2018/09/minizinc-cpsat-vs-mip.html\n",
|
||||
"\n",
|
||||
"see http://yetanothermathprogrammingconsultant.blogspot.com/2018/09/minizinc-\n",
|
||||
"cpsat-vs-mip.html\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
@@ -86,213 +86,263 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
"def task_allocation_sat():\n",
|
||||
" \"\"\"Solves the task allocation problem.\"\"\"\n",
|
||||
" # Availability matrix.\n",
|
||||
" available = [[\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 1, 1\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 1, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 1\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 1\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,\n",
|
||||
" 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 1, 1\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,\n",
|
||||
" 1, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0\n",
|
||||
" ]]\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 1, 1, 1, 1, 1, 1, 1, 1\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,\n",
|
||||
" 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 1, 1, 1, 1, 1, 1, 1, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,\n",
|
||||
" 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,\n",
|
||||
" 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 1, 1, 1, 1, 1, 1, 1, 1, 1\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 1, 1, 1, 1, 1, 1, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,\n",
|
||||
" 1, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,\n",
|
||||
" 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,\n",
|
||||
" 1, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n",
|
||||
" ]]\n",
|
||||
"\n",
|
||||
" ntasks = len(available)\n",
|
||||
" nslots = len(available[0])\n",
|
||||
@@ -315,15 +365,18 @@
|
||||
"\n",
|
||||
" for task in all_tasks:\n",
|
||||
" model.Add(\n",
|
||||
" sum(assign[(task, slot)] for slot in all_slots\n",
|
||||
" sum(assign[(task, slot)]\n",
|
||||
" for slot in all_slots\n",
|
||||
" if available[task][slot] == 1) == 1)\n",
|
||||
"\n",
|
||||
" for slot in all_slots:\n",
|
||||
" model.Add(\n",
|
||||
" sum(assign[(task, slot)] for task in all_tasks\n",
|
||||
" sum(assign[(task, slot)]\n",
|
||||
" for task in all_tasks\n",
|
||||
" if available[task][slot] == 1) <= capacity)\n",
|
||||
" model.AddBoolOr([\n",
|
||||
" assign[(task, slot)] for task in all_tasks\n",
|
||||
" assign[(task, slot)]\n",
|
||||
" for task in all_tasks\n",
|
||||
" if available[task][slot] == 1\n",
|
||||
" ]).OnlyEnforceIf(slot_used[slot])\n",
|
||||
" for task in all_tasks:\n",
|
||||
@@ -343,7 +396,7 @@
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" # Uses the portfolion of heuristics.\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
" solver.parameters.num_search_workers = 6\n",
|
||||
" solver.parameters.num_search_workers = 16\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
"\n",
|
||||
" print('Statistics')\n",
|
||||
@@ -352,6 +405,12 @@
|
||||
" print(' - wall time : %f s' % solver.WallTime())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" task_allocation_sat()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
|
||||
@@ -72,8 +72,7 @@
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Tasks and workers to group assignment to average sum(cost) / #workers\n",
|
||||
"\n"
|
||||
"Tasks and workers to group assignment to average sum(cost) / #workers.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -83,6 +82,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -187,6 +187,15 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"tasks_and_workers_assignment_sat()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" tasks_and_workers_assignment_sat()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -72,8 +72,7 @@
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Simple travelling salesman problem between cities.\n",
|
||||
"\n"
|
||||
"Simple travelling salesman problem between cities.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -85,7 +84,6 @@
|
||||
"source": [
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"DISTANCE_MATRIX = [\n",
|
||||
" [0, 10938, 4542, 2835, 29441, 2171, 1611, 9208, 9528, 11111, 16120, 22606, 22127, 20627, 21246, 23387, 16697, 33609, 26184, 24772, 22644, 20655, 30492, 23296, 32979, 18141, 19248, 17129, 17192, 15645, 12658, 11210, 12094, 13175, 18162, 4968, 12308, 10084, 13026, 15056],\n",
|
||||
" [10938, 0, 6422, 9742, 18988, 12974, 11216, 19715, 19004, 18271, 25070, 31971, 31632, 30571, 31578, 33841, 27315, 43964, 36944, 35689, 33569, 31481, 41360, 33760, 43631, 28730, 29976, 27803, 28076, 26408, 23504, 22025, 22000, 13197, 14936, 15146, 23246, 20956, 23963, 25994],\n",
|
||||
@@ -127,7 +125,7 @@
|
||||
" [10084, 20956, 14618, 12135, 38935, 8306, 9793, 2615, 5850, 10467, 9918, 14568, 13907, 11803, 11750, 13657, 6901, 23862, 16125, 14748, 12981, 11624, 21033, 15358, 24144, 10304, 10742, 9094, 8042, 7408, 4580, 4072, 8446, 20543, 26181, 7668, 2747, 0, 3330, 5313],\n",
|
||||
" [13026, 23963, 17563, 14771, 42160, 11069, 12925, 5730, 8778, 13375, 11235, 14366, 13621, 11188, 10424, 11907, 5609, 21861, 13624, 11781, 9718, 8304, 17737, 12200, 20816, 7330, 7532, 6117, 4735, 4488, 2599, 3355, 7773, 22186, 27895, 9742, 726, 3330, 0, 2042],\n",
|
||||
" [15056, 25994, 19589, 16743, 44198, 13078, 14967, 7552, 10422, 14935, 11891, 14002, 13225, 10671, 9475, 10633, 5084, 20315, 11866, 9802, 7682, 6471, 15720, 10674, 18908, 6204, 6000, 5066, 3039, 3721, 3496, 4772, 8614, 23805, 29519, 11614, 2749, 5313, 2042, 0],\n",
|
||||
" ] # yapf: disable\n",
|
||||
"] # yapf: disable\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
|
||||
@@ -72,8 +72,7 @@
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Solves a simple shift scheduling problem.\n",
|
||||
"\n"
|
||||
"Solves a simple shift scheduling problem.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -83,6 +82,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -106,8 +106,9 @@
|
||||
" 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, self.__possible_schedules[self.Value(\n",
|
||||
" self.__selected_schedules[i])])\n",
|
||||
" print(\n",
|
||||
" ' - vendor %i: ' % i, self.__possible_schedules[self.Value(\n",
|
||||
" self.__selected_schedules[i])])\n",
|
||||
" print()\n",
|
||||
"\n",
|
||||
" for j in range(self.__num_hours):\n",
|
||||
@@ -121,7 +122,7 @@
|
||||
" return self.__solution_count\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
"def vendor_scheduling_sat():\n",
|
||||
" \"\"\"Create the shift scheduling model and solve it.\"\"\"\n",
|
||||
" # Create the model.\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
@@ -139,12 +140,12 @@
|
||||
" # 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,\n",
|
||||
" 8], [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,\n",
|
||||
" 4], [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 2,\n",
|
||||
" 5], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 4],\n",
|
||||
" [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4,\n",
|
||||
" 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]]\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",
|
||||
@@ -204,8 +205,14 @@
|
||||
" print(' - conflicts : %i' % solver.NumConflicts())\n",
|
||||
" print(' - branches : %i' % solver.NumBranches())\n",
|
||||
" print(' - wall time : %f s' % solver.WallTime())\n",
|
||||
" print(\n",
|
||||
" ' - number of solutions found: %i' % solution_printer.solution_count())\n",
|
||||
" print(' - number of solutions found: %i' %\n",
|
||||
" solution_printer.solution_count())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
" vendor_scheduling_sat()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"from typing import Sequence\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -138,11 +139,8 @@
|
||||
" return self.__solution_count\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def BuildData():\n",
|
||||
" #\n",
|
||||
" # Data\n",
|
||||
" #\n",
|
||||
"\n",
|
||||
"def build_data():\n",
|
||||
" \"\"\"Build the data model.\"\"\"\n",
|
||||
" # Easy problem (from the paper)\n",
|
||||
" # num_tables = 2\n",
|
||||
" # table_capacity = 10\n",
|
||||
@@ -155,23 +153,23 @@
|
||||
"\n",
|
||||
" # Connection matrix: who knows who, and how strong\n",
|
||||
" # is the relation\n",
|
||||
" C = [[1, 50, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0], [50, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0], [1, 1, 1, 50, 1, 1, 1, 1, 10, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0], [1, 1, 50, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 1, 1, 1, 50, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0], [1, 1, 1, 1, 50, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0], [1, 1, 1, 1, 1, 1, 1, 50, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 1, 1, 1, 1, 50, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0], [1, 1, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 50, 1, 1, 1, 1, 1, 1],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1\n",
|
||||
" ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1\n",
|
||||
" ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]]\n",
|
||||
" connections = [[1, 50, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [50, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 1, 50, 1, 1, 1, 1, 10, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 50, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 1, 1, 1, 50, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 1, 1, 50, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 1, 1, 1, 1, 1, 50, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 1, 1, 1, 1, 50, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [1, 1, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 50, 1, 1, 1, 1, 1, 1],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 1, 1, 1, 1, 1, 1, 1],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1],\n",
|
||||
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]]\n",
|
||||
"\n",
|
||||
" # Names of the guests. B: Bride side, G: Groom side\n",
|
||||
" names = [\n",
|
||||
@@ -180,13 +178,15 @@
|
||||
" \"Lee (G)\", \"Annika (G)\", \"Carl (G)\", \"Colin (G)\", \"Shirley (G)\",\n",
|
||||
" \"DeAnn (G)\", \"Lori (G)\"\n",
|
||||
" ]\n",
|
||||
" return num_tables, table_capacity, min_known_neighbors, C, names\n",
|
||||
" return num_tables, table_capacity, min_known_neighbors, connections, names\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def solve_with_discrete_model():\n",
|
||||
" num_tables, table_capacity, min_known_neighbors, C, names = BuildData()\n",
|
||||
" \"\"\"Discrete approach.\"\"\"\n",
|
||||
" num_tables, table_capacity, min_known_neighbors, connections, names = build_data(\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" num_guests = len(C)\n",
|
||||
" num_guests = len(connections)\n",
|
||||
"\n",
|
||||
" all_tables = range(num_tables)\n",
|
||||
" all_guests = range(num_guests)\n",
|
||||
@@ -200,8 +200,8 @@
|
||||
" seats = {}\n",
|
||||
" for t in all_tables:\n",
|
||||
" for g in all_guests:\n",
|
||||
" seats[(t, g)] = model.NewBoolVar(\"guest %i seats on table %i\" % (g,\n",
|
||||
" t))\n",
|
||||
" seats[(t,\n",
|
||||
" g)] = model.NewBoolVar(\"guest %i seats on table %i\" % (g, t))\n",
|
||||
"\n",
|
||||
" colocated = {}\n",
|
||||
" for g1 in range(num_guests - 1):\n",
|
||||
@@ -218,9 +218,10 @@
|
||||
"\n",
|
||||
" # Objective\n",
|
||||
" model.Maximize(\n",
|
||||
" sum(C[g1][g2] * colocated[g1, g2]\n",
|
||||
" for g1 in range(num_guests - 1) for g2 in range(g1 + 1, num_guests)\n",
|
||||
" if C[g1][g2] > 0))\n",
|
||||
" sum(connections[g1][g2] * colocated[g1, g2]\n",
|
||||
" for g1 in range(num_guests - 1)\n",
|
||||
" for g2 in range(g1 + 1, num_guests)\n",
|
||||
" if connections[g1][g2] > 0))\n",
|
||||
"\n",
|
||||
" #\n",
|
||||
" # Constraints\n",
|
||||
@@ -248,8 +249,8 @@
|
||||
"\n",
|
||||
" # Link colocated and same_table.\n",
|
||||
" model.Add(\n",
|
||||
" sum(same_table[(g1, g2, t)]\n",
|
||||
" for t in all_tables) == colocated[(g1, g2)])\n",
|
||||
" sum(same_table[(g1, g2, t)] for t in all_tables) == colocated[(\n",
|
||||
" g1, g2)])\n",
|
||||
"\n",
|
||||
" # Min known neighbors rule.\n",
|
||||
" for g in all_guests:\n",
|
||||
@@ -257,12 +258,11 @@
|
||||
" sum(same_table[(g, g2, t)]\n",
|
||||
" for g2 in range(g + 1, num_guests)\n",
|
||||
" for t in all_tables\n",
|
||||
" if C[g][g2] > 0) +\n",
|
||||
" if connections[g][g2] > 0) +\n",
|
||||
" sum(same_table[(g1, g, t)]\n",
|
||||
" for g1 in range(g)\n",
|
||||
" for t in all_tables\n",
|
||||
" if C[g1][g] > 0)\n",
|
||||
" >= min_known_neighbors)\n",
|
||||
" if connections[g1][g] > 0) >= min_known_neighbors)\n",
|
||||
"\n",
|
||||
" # Symmetry breaking. First guest seats on the first table.\n",
|
||||
" model.Add(seats[(0, 0)] == 1)\n",
|
||||
@@ -279,7 +279,13 @@
|
||||
" print(\" - num solutions: %i\" % solution_printer.num_solutions())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"solve_with_discrete_model()\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError(\"Too many command-line arguments.\")\n",
|
||||
" solve_with_discrete_model()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
187
examples/notebook/examples/weighted_latency_problem_sat.ipynb
Normal file
187
examples/notebook/examples/weighted_latency_problem_sat.ipynb
Normal file
@@ -0,0 +1,187 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "google",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Copyright 2022 Google LLC."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "apache",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"you may not use this file except in compliance with the License.\n",
|
||||
"You may obtain a copy of the License at\n",
|
||||
"\n",
|
||||
" http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"\n",
|
||||
"Unless required by applicable law or agreed to in writing, software\n",
|
||||
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"See the License for the specific language governing permissions and\n",
|
||||
"limitations under the License.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "basename",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# weighted_latency_problem_sat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "link",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<table align=\"left\">\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/examples/weighted_latency_problem_sat.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
||||
"</td>\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://github.com/google/or-tools/blob/main/examples/python/weighted_latency_problem_sat.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
||||
"</td>\n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "doc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "install",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install ortools"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Solve a random Weighted Latency problem with the CP-SAT solver.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"from typing import Sequence\n",
|
||||
"from google.protobuf import text_format\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"_NUM_NODES = flags.DEFINE_integer('num_nodes', 12, 'Number of nodes to visit.')\n",
|
||||
"_GRID_SIZE = flags.DEFINE_integer('grid_size', 20,\n",
|
||||
" 'Size of the grid where nodes are.')\n",
|
||||
"_PROFIT_RANGE = flags.DEFINE_integer('profit_range', 50, 'Range of profit.')\n",
|
||||
"_SEED = flags.DEFINE_integer('seed', 0, 'Random seed.')\n",
|
||||
"_PARAMS = flags.DEFINE_string('params',\n",
|
||||
" 'num_search_workers:16, max_time_in_seconds:5',\n",
|
||||
" 'Sat solver parameters.')\n",
|
||||
"_PROTO_FILE = flags.DEFINE_string(\n",
|
||||
" 'proto_file', '', 'If not empty, output the proto to this file.')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def build_model():\n",
|
||||
" \"\"\"Create the nodes and the profit.\"\"\"\n",
|
||||
" random.seed(_SEED.value)\n",
|
||||
" x = []\n",
|
||||
" y = []\n",
|
||||
" x.append(random.randint(0, _GRID_SIZE.value))\n",
|
||||
" y.append(random.randint(0, _GRID_SIZE.value))\n",
|
||||
" for _ in range(_NUM_NODES.value):\n",
|
||||
" x.append(random.randint(0, _GRID_SIZE.value))\n",
|
||||
" y.append(random.randint(0, _GRID_SIZE.value))\n",
|
||||
"\n",
|
||||
" profits = []\n",
|
||||
" profits.append(0)\n",
|
||||
" for _ in range(_NUM_NODES.value):\n",
|
||||
" profits.append(random.randint(1, _PROFIT_RANGE.value))\n",
|
||||
" sum_of_profits = sum(profits)\n",
|
||||
" profits = [p / sum_of_profits for p in profits]\n",
|
||||
"\n",
|
||||
" return x, y, profits\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def solve_with_cp_sat(x, y, profits):\n",
|
||||
" \"\"\"Solves the problem with the CP-SAT solver.\"\"\"\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
"\n",
|
||||
" # because of the manhattan distance, the sum of distances is bounded by this.\n",
|
||||
" horizon = _GRID_SIZE.value * 2 * _NUM_NODES.value\n",
|
||||
" times = [\n",
|
||||
" model.NewIntVar(0, horizon, f'x_{i}')\n",
|
||||
" for i in range(_NUM_NODES.value + 1)\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" # Node 0 is the start node.\n",
|
||||
" model.Add(times[0] == 0)\n",
|
||||
"\n",
|
||||
" # Create the circuit constraint.\n",
|
||||
" arcs = []\n",
|
||||
" for i in range(_NUM_NODES.value + 1):\n",
|
||||
" for j in range(_NUM_NODES.value + 1):\n",
|
||||
" if i == j:\n",
|
||||
" continue\n",
|
||||
" # We use a manhattan distance between nodes.\n",
|
||||
" distance = abs(x[i] - x[j]) + abs(y[i] - y[j])\n",
|
||||
" lit = model.NewBoolVar(f'{i}_to_{j}')\n",
|
||||
" arcs.append((i, j, lit))\n",
|
||||
"\n",
|
||||
" # Add transitions between nodes.\n",
|
||||
" if i == 0:\n",
|
||||
" # Initial transition\n",
|
||||
" model.Add(times[j] == distance).OnlyEnforceIf(lit)\n",
|
||||
" elif j != 0:\n",
|
||||
" # We do not care for the last transition.\n",
|
||||
" model.Add(times[j] == times[i] + distance).OnlyEnforceIf(lit)\n",
|
||||
" model.AddCircuit(arcs)\n",
|
||||
"\n",
|
||||
" model.Minimize(cp_model.LinearExpr.WeightedSum(times, profits))\n",
|
||||
"\n",
|
||||
" if _PROTO_FILE.value:\n",
|
||||
" model.ExportToFile(_PROTO_FILE.value)\n",
|
||||
"\n",
|
||||
" # Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" if _PARAMS.value:\n",
|
||||
" text_format.Parse(_PARAMS.value, solver.parameters)\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
" solver.Solve(model)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main(argv: Sequence[str]) -> None:\n",
|
||||
" if len(argv) > 1:\n",
|
||||
" raise app.UsageError('Too many command-line arguments.')\n",
|
||||
"\n",
|
||||
" x, y, profits = build_model()\n",
|
||||
" solve_with_cp_sat(x, y, profits)\n",
|
||||
" # TODO(user): Implement routing model.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"main()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,241 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "google",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Copyright 2022 Google LLC."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "apache",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"you may not use this file except in compliance with the License.\n",
|
||||
"You may obtain a copy of the License at\n",
|
||||
"\n",
|
||||
" http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"\n",
|
||||
"Unless required by applicable law or agreed to in writing, software\n",
|
||||
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"See the License for the specific language governing permissions and\n",
|
||||
"limitations under the License.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "basename",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# worker_schedule_sat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "link",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<table align=\"left\">\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/main/examples/notebook/examples/worker_schedule_sat.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
||||
"</td>\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://github.com/google/or-tools/blob/main/examples/python/worker_schedule_sat.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/main/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
||||
"</td>\n",
|
||||
"</table>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "doc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "install",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install ortools"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Copyright 2010-2022 Google LLC\n",
|
||||
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"# you may not use this file except in compliance with the License.\n",
|
||||
"# You may obtain a copy of the License at\n",
|
||||
"#\n",
|
||||
"# http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"#\n",
|
||||
"# Unless required by applicable law or agreed to in writing, software\n",
|
||||
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"# See the License for the specific language governing permissions and\n",
|
||||
"# limitations under the License.\n",
|
||||
"\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def schedule():\n",
|
||||
"\n",
|
||||
" # Input data.\n",
|
||||
" positions = [\n",
|
||||
" 1, 2, 8, 10, 5, 3, 4, 3, 6, 6, 4, 5, 4, 3, 4, 4, 3, 4, 2, 1, 0, 0, 0, 0,\n",
|
||||
" 1, 2, 9, 9, 4, 3, 4, 3, 5, 4, 5, 2, 5, 6, 6, 7, 4, 2, 1, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 2, 7, 6, 5, 2, 4, 4, 6, 6, 4, 5, 5, 5, 7, 5, 4, 4, 2, 3, 1, 0, 0, 0,\n",
|
||||
" 1, 2, 9, 7, 2, 2, 4, 2, 4, 5, 3, 2, 6, 7, 5, 6, 4, 4, 2, 1, 0, 0, 0, 0,\n",
|
||||
" 2, 2, 8, 8, 6, 3, 3, 3, 10, 9, 6, 3, 3, 4, 5, 4, 5, 4, 2, 1, 0, 0, 0, 0,\n",
|
||||
" 1, 2, 9, 5, 5, 4, 5, 2, 5, 7, 5, 3, 4, 8, 4, 4, 2, 3, 1, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 2, 10, 5, 5, 4, 5, 2, 4, 6, 7, 4, 4, 5, 4, 4, 3, 3, 2, 1, 0, 0, 0, 0\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" possible_shifts = [[\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 40\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 40\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 2, 40\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 3, 40\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 4, 0\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 5, 16\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 6, 16\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 7, 16\n",
|
||||
" ], [\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,\n",
|
||||
" 8, 40\n",
|
||||
" ]]\n",
|
||||
"\n",
|
||||
" # Useful numbers.\n",
|
||||
" num_slots = len(positions)\n",
|
||||
" all_slots = range(num_slots)\n",
|
||||
"\n",
|
||||
" num_shifts = len(possible_shifts)\n",
|
||||
" all_shifts = range(num_shifts)\n",
|
||||
"\n",
|
||||
" min_number_of_workers = [5 * x for x in positions]\n",
|
||||
" num_workers = 300\n",
|
||||
"\n",
|
||||
" # Model the problem.\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
"\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(\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",
|
||||
"\n",
|
||||
" # Link the objective.\n",
|
||||
" model.Add(sum(workers_per_shift) == objective)\n",
|
||||
"\n",
|
||||
" # Minimize.\n",
|
||||
" model.Minimize(objective)\n",
|
||||
"\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" status = solver.Solve(model)\n",
|
||||
"\n",
|
||||
" if status == cp_model.OPTIMAL:\n",
|
||||
" print('Objective value = %i' % solver.ObjectiveValue())\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",
|
||||
"\n",
|
||||
"\n",
|
||||
"schedule()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -82,20 +82,21 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"from ortools.linear_solver.python import model_builder\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" # Data\n",
|
||||
" costs = [\n",
|
||||
" costs = np.array([\n",
|
||||
" [90, 80, 75, 70],\n",
|
||||
" [35, 85, 55, 65],\n",
|
||||
" [125, 95, 90, 95],\n",
|
||||
" [45, 110, 95, 115],\n",
|
||||
" [50, 100, 90, 100],\n",
|
||||
" ]\n",
|
||||
" num_workers = len(costs)\n",
|
||||
" num_tasks = len(costs[0])\n",
|
||||
" ])\n",
|
||||
" num_workers, num_tasks = costs.shape\n",
|
||||
"\n",
|
||||
" # Solver\n",
|
||||
" # Create the model.\n",
|
||||
@@ -104,26 +105,19 @@
|
||||
" # Variables\n",
|
||||
" # x[i, j] is an array of 0-1 variables, which will be 1\n",
|
||||
" # if worker i is assigned to task j.\n",
|
||||
" x = {}\n",
|
||||
" for i in range(num_workers):\n",
|
||||
" for j in range(num_tasks):\n",
|
||||
" x[i, j] = model.new_bool_var(f'x_{i}_{j}')\n",
|
||||
" x = model.new_bool_var_array(shape=[num_workers, num_tasks], name='x')\n",
|
||||
"\n",
|
||||
" # Constraints\n",
|
||||
" # Each worker is assigned to at most 1 task.\n",
|
||||
" for i in range(num_workers):\n",
|
||||
" model.add(sum(x[i, j] for j in range(num_tasks)) <= 1)\n",
|
||||
" model.add(np.sum(x[i, :]) <= 1)\n",
|
||||
"\n",
|
||||
" # Each task is assigned to exactly one worker.\n",
|
||||
" for j in range(num_tasks):\n",
|
||||
" model.add(sum(x[i, j] for i in range(num_workers)) == 1)\n",
|
||||
" model.add(np.sum(x[:, j]) == 1)\n",
|
||||
"\n",
|
||||
" # Objective\n",
|
||||
" objective_expr = 0\n",
|
||||
" for i in range(num_workers):\n",
|
||||
" for j in range(num_tasks):\n",
|
||||
" objective_expr += costs[i][j] * x[i, j]\n",
|
||||
" model.minimize(objective_expr)\n",
|
||||
" model.minimize(np.dot(x.flatten(), costs.flatten()))\n",
|
||||
"\n",
|
||||
" # Create the solver with the CP-SAT backend, and solve the model.\n",
|
||||
" solver = model_builder.ModelSolver('sat')\n",
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"from ortools.linear_solver.python import model_builder\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -99,35 +101,31 @@
|
||||
"\n",
|
||||
"def main():\n",
|
||||
" data = create_data_model()\n",
|
||||
" num_items = len(data['items'])\n",
|
||||
" num_bins = len(data['bins'])\n",
|
||||
"\n",
|
||||
" # Create the model.\n",
|
||||
" model = model_builder.ModelBuilder()\n",
|
||||
"\n",
|
||||
" # Variables\n",
|
||||
" # x[i, j] = 1 if item i is packed in bin j.\n",
|
||||
" x = {}\n",
|
||||
" for i in data['items']:\n",
|
||||
" for j in data['bins']:\n",
|
||||
" x[(i, j)] = model.new_bool_var(f'x_{i}_{j}')\n",
|
||||
" x = model.new_bool_var_array(shape=[num_items, num_bins], name='x')\n",
|
||||
"\n",
|
||||
" # y[j] = 1 if bin j is used.\n",
|
||||
" y = {}\n",
|
||||
" for j in data['bins']:\n",
|
||||
" y[j] = model.new_bool_var(f'y_{j}')\n",
|
||||
" y = model.new_bool_var_array(shape=[num_bins], name='y')\n",
|
||||
"\n",
|
||||
" # Constraints\n",
|
||||
" # Each item must be in exactly one bin.\n",
|
||||
" for i in data['items']:\n",
|
||||
" model.add(sum(x[i, j] for j in data['bins']) == 1)\n",
|
||||
" model.add(np.sum(x[i, :]) == 1)\n",
|
||||
"\n",
|
||||
" # The amount packed in each bin cannot exceed its capacity.\n",
|
||||
" for j in data['bins']:\n",
|
||||
" model.add(\n",
|
||||
" sum(x[(i, j)] * data['weights'][i] for i in data['items']) <= y[j] *\n",
|
||||
" data['bin_capacity'])\n",
|
||||
" np.dot(x[:, j], data['weights']) <= data['bin_capacity'] * y[j])\n",
|
||||
"\n",
|
||||
" # Objective: minimize the number of bins used.\n",
|
||||
" model.minimize(model_builder.LinearExpr.sum([y[j] for j in data['bins']]))\n",
|
||||
" model.minimize(np.sum(y))\n",
|
||||
"\n",
|
||||
" # Create the solver with the CP-SAT backend, and solve the model.\n",
|
||||
" solver = model_builder.ModelSolver('sat')\n",
|
||||
|
||||
@@ -95,10 +95,10 @@
|
||||
" y = model.NewBoolVar('y')\n",
|
||||
" p = model.NewBoolVar('p')\n",
|
||||
"\n",
|
||||
" # x and y implies p, rewrite as not(x and y) or p\n",
|
||||
" # x and y implies p, rewrite as not(x and y) or p.\n",
|
||||
" model.AddBoolOr(x.Not(), y.Not(), p)\n",
|
||||
"\n",
|
||||
" # p implies x and y, expanded into two implication\n",
|
||||
" # p implies x and y, expanded into two implications.\n",
|
||||
" model.AddImplication(p, x)\n",
|
||||
" model.AddImplication(p, y)\n",
|
||||
"\n",
|
||||
|
||||
@@ -67,6 +67,18 @@
|
||||
"!pip install ortools"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "description",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Non linear example.\n",
|
||||
"\n",
|
||||
"Finds a rectangle with maximum available area for given perimeter using\n",
|
||||
"AddMultiplicationEquality().\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -74,36 +86,20 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#!/usr/bin/env python3\n",
|
||||
"# Copyright 2010-2022 Google LLC\n",
|
||||
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
|
||||
"# you may not use this file except in compliance with the License.\n",
|
||||
"# You may obtain a copy of the License at\n",
|
||||
"#\n",
|
||||
"# http://www.apache.org/licenses/LICENSE-2.0\n",
|
||||
"#\n",
|
||||
"# Unless required by applicable law or agreed to in writing, software\n",
|
||||
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
|
||||
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
|
||||
"# See the License for the specific language governing permissions and\n",
|
||||
"# limitations under the License.\n",
|
||||
"\n",
|
||||
"# Finds a rectangle with maximum available area for given perimeter\n",
|
||||
"# using AddMultiplicationEquality\n",
|
||||
"\n",
|
||||
"from ortools.sat.python import cp_model\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def NonLinearSat():\n",
|
||||
"def non_linear_sat():\n",
|
||||
" \"\"\"Non linear sample.\"\"\"\n",
|
||||
" perimeter = 20\n",
|
||||
"\n",
|
||||
" model = cp_model.CpModel()\n",
|
||||
"\n",
|
||||
" x = model.NewIntVar(0, perimeter, \"x\")\n",
|
||||
" y = model.NewIntVar(0, perimeter, \"y\")\n",
|
||||
" x = model.NewIntVar(0, perimeter, 'x')\n",
|
||||
" y = model.NewIntVar(0, perimeter, 'y')\n",
|
||||
" model.Add(2 * (x + y) == perimeter)\n",
|
||||
"\n",
|
||||
" area = model.NewIntVar(0, perimeter * perimeter, \"s\")\n",
|
||||
" area = model.NewIntVar(0, perimeter * perimeter, 's')\n",
|
||||
" model.AddMultiplicationEquality(area, x, y)\n",
|
||||
"\n",
|
||||
" model.Maximize(area)\n",
|
||||
@@ -120,7 +116,7 @@
|
||||
" print('No solution found.')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"NonLinearSat()\n",
|
||||
"non_linear_sat()\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user