Sync python notebook

cmd: ./tools/generate_all_notebooks.sh
This commit is contained in:
Mizux Seiha
2023-03-10 09:19:51 +01:00
parent de1b3cba7a
commit 5425dedcfb
43 changed files with 2155 additions and 1636 deletions

View File

@@ -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",

View File

@@ -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"
]
}

View File

@@ -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
}

View File

@@ -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"
]
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -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"
]
}

View File

@@ -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",

View File

@@ -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"
]
}

View 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
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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"
]
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View 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
}

View File

@@ -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"

View File

@@ -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",

View File

@@ -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

View File

@@ -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",

View File

@@ -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",

View File

@@ -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"
]
}

View 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
}

View File

@@ -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",

View File

@@ -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"
]

View File

@@ -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"
]
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -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"
]
}

View 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
}

View File

@@ -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
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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"
]
}