From 5425dedcfbb22cb74c636c1374a9b5ad684b1eb5 Mon Sep 17 00:00:00 2001 From: Mizux Seiha Date: Fri, 10 Mar 2023 09:19:51 +0100 Subject: [PATCH] Sync python notebook cmd: ./tools/generate_all_notebooks.sh --- examples/notebook/examples/appointments.ipynb | 21 +- .../examples/arc_flow_cutting_stock_sat.ipynb | 79 +- .../notebook/examples/assignment2_sat.ipynb | 164 --- .../assignment_with_constraints_sat.ipynb | 32 +- .../notebook/examples/balance_group_sat.ipynb | 18 +- .../examples/bus_driver_scheduling_sat.ipynb | 55 +- .../examples/chemical_balance_sat.ipynb | 166 +-- .../notebook/examples/clustering_sat.ipynb | 52 +- .../examples/cover_rectangle_sat.ipynb | 21 +- .../notebook/examples/cryptarithm_sat.ipynb | 157 +++ .../examples/gate_scheduling_sat.ipynb | 2 +- examples/notebook/examples/golomb8.ipynb | 76 +- examples/notebook/examples/golomb_sat.ipynb | 16 +- examples/notebook/examples/hidato_sat.ipynb | 2 +- .../examples/integer_programming.ipynb | 2 +- .../notebook/examples/jobshop_ft06_sat.ipynb | 2 +- .../jobshop_with_maintenance_sat.ipynb | 9 +- .../notebook/examples/knapsack_2d_sat.ipynb | 5 +- .../examples/line_balancing_sat.ipynb | 31 +- .../examples/linear_assignment_api.ipynb | 9 +- .../notebook/examples/maze_escape_sat.ipynb | 10 +- .../no_wait_baking_scheduling_sat.ipynb | 13 +- examples/notebook/examples/nqueens_sat.ipynb | 177 +++ .../examples/prize_collecting_tsp_sat.ipynb | 29 +- .../examples/prize_collecting_vrp_sat.ipynb | 40 +- .../notebook/examples/pyflow_example.ipynb | 13 +- examples/notebook/examples/qubo_sat.ipynb | 1177 +++++++++-------- examples/notebook/examples/rcpsp_sat.ipynb | 3 +- .../examples/shift_scheduling_sat.ipynb | 4 +- ...ing_with_setup_release_due_dates_sat.ipynb | 56 +- .../notebook/examples/spread_robots_sat.ipynb | 191 +++ .../examples/steel_mill_slab_sat.ipynb | 72 +- .../examples/task_allocation_sat.ipynb | 467 ++++--- .../tasks_and_workers_assignment_sat.ipynb | 13 +- examples/notebook/examples/tsp_sat.ipynb | 6 +- .../examples/vendor_scheduling_sat.ipynb | 33 +- .../examples/wedding_optimal_chart_sat.ipynb | 78 +- .../weighted_latency_problem_sat.ipynb | 187 +++ .../examples/worker_schedule_sat.ipynb | 241 ---- .../linear_solver/assignment_mb.ipynb | 24 +- .../linear_solver/bin_packing_mb.ipynb | 20 +- .../sat/boolean_product_sample_sat.ipynb | 4 +- examples/notebook/sat/non_linear_sat.ipynb | 40 +- 43 files changed, 2168 insertions(+), 1649 deletions(-) delete mode 100644 examples/notebook/examples/assignment2_sat.ipynb create mode 100644 examples/notebook/examples/cryptarithm_sat.ipynb create mode 100644 examples/notebook/examples/nqueens_sat.ipynb create mode 100644 examples/notebook/examples/spread_robots_sat.ipynb create mode 100644 examples/notebook/examples/weighted_latency_problem_sat.ipynb delete mode 100644 examples/notebook/examples/worker_schedule_sat.ipynb diff --git a/examples/notebook/examples/appointments.ipynb b/examples/notebook/examples/appointments.ipynb index 6953f00c5f3..20cb6a090c7 100644 --- a/examples/notebook/examples/appointments.ipynb +++ b/examples/notebook/examples/appointments.ipynb @@ -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", diff --git a/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb b/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb index 91a6669ea5d..f92a246280b 100644 --- a/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb +++ b/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb @@ -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" ] } diff --git a/examples/notebook/examples/assignment2_sat.ipynb b/examples/notebook/examples/assignment2_sat.ipynb deleted file mode 100644 index 0521472becd..00000000000 --- a/examples/notebook/examples/assignment2_sat.ipynb +++ /dev/null @@ -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": [ - "\n", - "\n", - "\n", - "
\n", - "Run in Google Colab\n", - "\n", - "View source on GitHub\n", - "
" - ] - }, - { - "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 -} diff --git a/examples/notebook/examples/assignment_with_constraints_sat.ipynb b/examples/notebook/examples/assignment_with_constraints_sat.ipynb index 420f2988c2b..2490af8d1fa 100644 --- a/examples/notebook/examples/assignment_with_constraints_sat.ipynb +++ b/examples/notebook/examples/assignment_with_constraints_sat.ipynb @@ -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" ] } diff --git a/examples/notebook/examples/balance_group_sat.ipynb b/examples/notebook/examples/balance_group_sat.ipynb index 154294ce0bf..db8e1b4c49f 100644 --- a/examples/notebook/examples/balance_group_sat.ipynb +++ b/examples/notebook/examples/balance_group_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/bus_driver_scheduling_sat.ipynb b/examples/notebook/examples/bus_driver_scheduling_sat.ipynb index 79697a1e94b..53e475dc116 100644 --- a/examples/notebook/examples/bus_driver_scheduling_sat.ipynb +++ b/examples/notebook/examples/bus_driver_scheduling_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/chemical_balance_sat.ipynb b/examples/notebook/examples/chemical_balance_sat.ipynb index f789cc43323..a0026571751 100644 --- a/examples/notebook/examples/chemical_balance_sat.ipynb +++ b/examples/notebook/examples/chemical_balance_sat.ipynb @@ -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", - "\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", - "\n", - "NUM_SETS = len(chemical_set)\n", - "ALL_SETS = range(NUM_SETS)\n", - "\n", - "# Model\n", - "\n", - "model = cp_model.CpModel()\n", - "\n", - "# Scale quantities by 100.\n", - "max_set = [\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", - "\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", - "\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", - "\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", - "\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", + "\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", + "\n", + " num_products = len(max_quantities)\n", + " all_products = range(num_products)\n", + "\n", + " num_sets = len(chemical_set)\n", + " all_sets = range(num_sets)\n", + "\n", + " # Model\n", + "\n", + " model = cp_model.CpModel()\n", + "\n", + " # Scale quantities by 100.\n", + " max_set = [\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", + "\n", + " epsilon = model.NewIntVar(0, 10000000, \"epsilon\")\n", + "\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", + "\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}\",\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" ] } diff --git a/examples/notebook/examples/clustering_sat.ipynb b/examples/notebook/examples/clustering_sat.ipynb index 247fe99995c..a3e67892dfb 100644 --- a/examples/notebook/examples/clustering_sat.ipynb +++ b/examples/notebook/examples/clustering_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/cover_rectangle_sat.ipynb b/examples/notebook/examples/cover_rectangle_sat.ipynb index 127ed277465..a84e0eebdef 100644 --- a/examples/notebook/examples/cover_rectangle_sat.ipynb +++ b/examples/notebook/examples/cover_rectangle_sat.ipynb @@ -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" ] } diff --git a/examples/notebook/examples/cryptarithm_sat.ipynb b/examples/notebook/examples/cryptarithm_sat.ipynb new file mode 100644 index 00000000000..7b5cf93a59a --- /dev/null +++ b/examples/notebook/examples/cryptarithm_sat.ipynb @@ -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": [ + "\n", + "\n", + "\n", + "
\n", + "Run in Google Colab\n", + "\n", + "View source on GitHub\n", + "
" + ] + }, + { + "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 +} diff --git a/examples/notebook/examples/gate_scheduling_sat.ipynb b/examples/notebook/examples/gate_scheduling_sat.ipynb index cecab1eada0..23fee0520d3 100644 --- a/examples/notebook/examples/gate_scheduling_sat.ipynb +++ b/examples/notebook/examples/gate_scheduling_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/golomb8.ipynb b/examples/notebook/examples/golomb8.ipynb index 2a307a601aa..cd41ed63016 100644 --- a/examples/notebook/examples/golomb8.ipynb +++ b/examples/notebook/examples/golomb8.ipynb @@ -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, 'marks_%d' % i) for i in all_vars]\n", "\n", - " marks = [solver.IntVar(0, var_max, f'marks_{i}') for i in all_vars]\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", - "\n", - " # objective\n", - " objective = solver.Minimize(marks[order - 1], 1)\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", - " # 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", diff --git a/examples/notebook/examples/golomb_sat.ipynb b/examples/notebook/examples/golomb_sat.ipynb index 77f307f1212..0902a6667d0 100644 --- a/examples/notebook/examples/golomb_sat.ipynb +++ b/examples/notebook/examples/golomb_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/hidato_sat.ipynb b/examples/notebook/examples/hidato_sat.ipynb index dbac98ff373..5738d1ca065 100644 --- a/examples/notebook/examples/hidato_sat.ipynb +++ b/examples/notebook/examples/hidato_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/integer_programming.ipynb b/examples/notebook/examples/integer_programming.ipynb index 07aa06be7cc..4a641552e11 100644 --- a/examples/notebook/examples/integer_programming.ipynb +++ b/examples/notebook/examples/integer_programming.ipynb @@ -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", diff --git a/examples/notebook/examples/jobshop_ft06_sat.ipynb b/examples/notebook/examples/jobshop_ft06_sat.ipynb index ba868594270..8ac074f9ffd 100644 --- a/examples/notebook/examples/jobshop_ft06_sat.ipynb +++ b/examples/notebook/examples/jobshop_ft06_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb b/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb index e96af0fa398..3663569250d 100644 --- a/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb +++ b/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb @@ -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" ] } diff --git a/examples/notebook/examples/knapsack_2d_sat.ipynb b/examples/notebook/examples/knapsack_2d_sat.ipynb index 605d7f78b89..008d034df72 100644 --- a/examples/notebook/examples/knapsack_2d_sat.ipynb +++ b/examples/notebook/examples/knapsack_2d_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/line_balancing_sat.ipynb b/examples/notebook/examples/line_balancing_sat.ipynb index cd4b22b41d4..b1ca8ec316e 100644 --- a/examples/notebook/examples/line_balancing_sat.ipynb +++ b/examples/notebook/examples/line_balancing_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/linear_assignment_api.ipynb b/examples/notebook/examples/linear_assignment_api.ipynb index 11441f85c78..67db00c4825 100644 --- a/examples/notebook/examples/linear_assignment_api.ipynb +++ b/examples/notebook/examples/linear_assignment_api.ipynb @@ -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", diff --git a/examples/notebook/examples/maze_escape_sat.ipynb b/examples/notebook/examples/maze_escape_sat.ipynb index 83228b1ab01..4e50020510c 100644 --- a/examples/notebook/examples/maze_escape_sat.ipynb +++ b/examples/notebook/examples/maze_escape_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb b/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb index 4c2fa78ac07..ba553a817c6 100644 --- a/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb +++ b/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/nqueens_sat.ipynb b/examples/notebook/examples/nqueens_sat.ipynb new file mode 100644 index 00000000000..0a115099b40 --- /dev/null +++ b/examples/notebook/examples/nqueens_sat.ipynb @@ -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": [ + "\n", + "\n", + "\n", + "
\n", + "Run in Google Colab\n", + "\n", + "View source on GitHub\n", + "
" + ] + }, + { + "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 +} diff --git a/examples/notebook/examples/prize_collecting_tsp_sat.ipynb b/examples/notebook/examples/prize_collecting_tsp_sat.ipynb index 4cefaa7dce3..8df28cecf3e 100644 --- a/examples/notebook/examples/prize_collecting_tsp_sat.ipynb +++ b/examples/notebook/examples/prize_collecting_tsp_sat.ipynb @@ -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,12 +226,17 @@ " # 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", + " 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", - " solver.Solve(model)\n", - " #print(solver.ResponseStats())\n", - " print_solution(solver, visited_nodes, used_arcs, num_nodes)\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", diff --git a/examples/notebook/examples/prize_collecting_vrp_sat.ipynb b/examples/notebook/examples/prize_collecting_vrp_sat.ipynb index 2fd056da7f7..8dfb6d7e18e 100644 --- a/examples/notebook/examples/prize_collecting_vrp_sat.ipynb +++ b/examples/notebook/examples/prize_collecting_vrp_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/pyflow_example.ipynb b/examples/notebook/examples/pyflow_example.ipynb index 1396ed6a6d6..7a86a8f870b 100644 --- a/examples/notebook/examples/pyflow_example.ipynb +++ b/examples/notebook/examples/pyflow_example.ipynb @@ -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", diff --git a/examples/notebook/examples/qubo_sat.ipynb b/examples/notebook/examples/qubo_sat.ipynb index fbe890b15f3..551f2a39f24 100644 --- a/examples/notebook/examples/qubo_sat.ipynb +++ b/examples/notebook/examples/qubo_sat.ipynb @@ -72,8 +72,7 @@ "id": "description", "metadata": {}, "source": [ - "Solves a Qubo program using the CP-SAT solver.\n", - "\n" + "Solves a Qubo program using the CP-SAT solver.\n" ] }, { @@ -83,538 +82,640 @@ "metadata": {}, "outputs": [], "source": [ - "import time\n", - "\n", + "from typing import Sequence\n", "from ortools.sat.python import cp_model\n", "\n", - "RAW_DATA = [[\n", - " 0, 0, 49.774821, -59.5968886, -46.0773896, 0, -65.166109, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 47.0957778, 15.259961, -98.7983264, 0, 0, 0, -20.7757184, 0,\n", - " 87.2645672, 0, -22.7888772, 0, 0, 0, -40.4980904, -19.7307486, -23.222078,\n", - " 0, -77.5263128, 0, 0, 56.6204008, 0, 0, 0, 0, 0, 0, 0, 31.378421, 0,\n", - " 97.3441448, 35.1309806, 0, 0, -40.5727886, -50.7308566, 0, 0, -69.9304568,\n", - " 0, 38.5385914, 0, -22.1243232, 0, 0, 0, 0, -62.5102538, 8.0801276,\n", - " 46.7998066, -2.3292106, 0, 0, 0, 8.774031, 0, 0, -65.6505736\n", - "], [\n", - " -67.2935466, -64.4354852, -96.6712204, 0, 0, -60.7812272, 0, 0, 0, 0, 0,\n", - " -7.9966864, 0, 0, 0, 0, 0, 0, 0, 89.7672338, 0, 0, 0, 0, 98.9607046, 0,\n", - " 28.6714432, 0, 0, 0, -26.2738856, 0, 0, 68.363956, 0, 0, 0, 0, 54.7406868,\n", - " 0, 0, 0, 0, 94.2320734, 0, 0, 0, 0, 0, 0, 0, 0, -2.9647794, 39.7161716,\n", - " -54.7931288, 0, 0, 0, 0, -47.2284892, 0, 0, 0, -8.6421808, -35.399612, 0, 0,\n", - " 62.1912668, 0, -6.8930716, 0, 0, -17.0801284, 0, 0, 68.6533416\n", - "], [\n", - " 0, 0, 0, 81.165396, 83.773254, 0, -25.1603, 0, 0, 50.225725, 0, -3.8242274,\n", - " 0, 0, 36.2078566, 0, 0, 0, 0, 0, 0, 0, 0, 15.551432, 0, 0, -33.6446236, 0,\n", - " 0, 0, 36.6171324, 0, 0, 0, 0, 67.9591934, 0, 22.1428016, 0, -27.2961928, 0,\n", - " 0, 0, -97.4961564, 90.4062526, 0, 0, 0, -90.0532814, 0, 98.8332924, 0, 0,\n", - " -13.8994926, 0, 17.1962884, 0, 0, 0, -55.1654678, 0, 0, 0, 85.829554, 0,\n", - " -37.971164, 64.233136, -17.9943296, 0, 0, 0, 0, -67.7509796, 0, 0,\n", - " 10.0750712\n", - "], [\n", - " 0, 37.2783148, 0, 0, 0, 36.4959506, 0, 0, 0, 0, 0, 0, 61.201323, 0,\n", - " 14.4328522, 48.4078064, 0, 0, 0, 0, 0, 0, 0, -47.0969056, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 26.720439, 0, 0, 62.1987576, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, -65.2085246, 0, 0, 0, 0, 0, 0, 73.3019432, -14.3431238, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 2.1565846, 0, 0, 0.7733644, 0, 5.9090456, 0, -39.7724192\n", - "], [\n", - " 0, 0, 0, 0, -24.4555532, 0, 0, -5.5484574, 0, 25.4685054, 0.7906104,\n", - " 4.273133, 0, 52.12973, 0, -12.8040828, 0, 0, 81.888381, 64.0713498, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 62.9088768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20.869713,\n", - " 0, 0, -71.5835872, 0, 0, 80.7237808, 0, 0, 0, 0, -60.1883708, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 85.0393326, 23.6045316, -18.8849834, 0, 0, 0, -90.8065188,\n", - " -9.5037982, 14.3196654, 0, -28.9290306, 0, 0, -41.5575766\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -8.9478934, 0,\n", - " -83.6040618, 0, 0, 0, 0, -14.3874822, 77.2528714, 0, 0, 99.2966066, 0,\n", - " 21.7889114, -37.7629282, 0, -11.6026582, 0, 0, 0, 0, 74.422603, 0, 0,\n", - " -79.239245, -31.9686324, 0, 0, 0, 0, 0, 0, -29.8797178, 0, 0, 85.2723062, 0,\n", - " 0, -8.8031188, 0, 0, -20.043565, 0, 0, -70.733454, 0, -94.7231762,\n", - " -85.4584516, 0, 0, 0, 0, -27.6068624, 0, -79.787783, 0, 0, -55.1894266\n", - "], [\n", - " 1.9374354, 0, 1.4807184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 61.298952, 0, 0, 0, -90.5702054, 0, 67.381115, 0, -68.684637, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 93.7807934, 0, 8.8213302, -15.9020466, 0, 0, 0, 0, 23.8157662, 0,\n", - " 0, 0, 0, 0, 0, 0, 67.3461972, 0, 0, 0, 0, 0, 43.3263744, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 87.7149706, 0, 0, 0, -18.5133574, -30.0338992\n", - "], [\n", - " 6.3937798, 78.7697644, 28.4485838, 0, 0, 0.1352466, 0, 0, 74.5767122,\n", - " -13.8340168, 0, 0, 0, 77.2929426, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17.9243834,\n", - " 0, 0, 82.2239878, 0, 0, 0, 0, 64.3440016, 90.109577, 46.8926522, -2.4494366,\n", - " 0, 84.7413412, 0, 0, -4.216108, 0, 0, -79.8684776, 0, 0, 74.8706758,\n", - " -64.4518992, 0, 0, 0, 0, -34.4895004, 0, 0, 0, -74.1158858, -37.7803516, 0,\n", - " 0, 0, 0, 0, 80.0054296, 0, 0, 0, 0, 0, 0, 0, 0, -84.5832026, 0, 0,\n", - " 71.2540694\n", - "], [\n", - " 0, 0, 0, 0, -74.9257454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 14.9675444, 0, 0, 0, 0, 0, -27.5236912, 0, 0, -80.4993438, 0, -81.8494538,\n", - " 0, 0, 0, 0, 0, -18.6802002, 0, 0, 0, 0, 0, 0, 0, 61.4131076, 0, 0,\n", - " -55.1421034, 0, 0, -18.576761, 72.3500914, 0, 0, 0, 0, 0, 0, -23.6460116,\n", - " 43.1258024, 0, 93.701872, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -86.5772554\n", - "], [\n", - " 0, 0, 93.0762916, 0, 0, 0, 0, 0, 0, 0, -37.2663938, 86.8303764, 0, 0, 0,\n", - " -51.9596226, 0, 35.6722618, -91.438259, 0, 0, -70.6277108, 0, -82.9146992,\n", - " 58.0327648, 0, 0, 0, 0, 0, 0, 0, 0, 13.3727302, 0, 0, 0, 23.5719942, 0,\n", - " -21.5445476, 74.1541634, 60.6365036, 97.4447708, 0, 0, 0, 0, 82.5869498, 0,\n", - " 85.1132108, 0, 0, 0, 0, 0, 0, 97.4012534, 0, 0, 0, 0, -45.1504048,\n", - " 1.0619934, 59.7140264, 0, 0, 0, 0, 0, 4.177461, 0, 0, 0, -75.7039276, 0,\n", - " 0.0421338\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -71.171869, 0, 0, 8.685266, 0, 0, 0, 0,\n", - " 33.9089574, 0, -31.6154498, 0, 0, 0, 0, 0, 5.3182746, 0, 0, 0, 0, 0, 0,\n", - " 3.0361166, -10.364305, 0, 0, 0, 0, 0, 0, 0, 0, -83.9738444, 0, 0,\n", - " -7.9170212, 0, 0, 0, -28.7575682, 0, 0, 0, -29.9216686, 0, 0, 83.4050918,\n", - " -39.5247364, -6.7028846, 0, 0, 0, -23.6080482, 0, 0, 0, 0, 0, 0, -18.380154,\n", - " 46.9252306, 0, 0, 26.1618372, 99.6235254\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 52.008307, 0, 0, 0, 0, 0, 92.4974102, -76.3015714, 0,\n", - " 0, 0, 0, 0, 0, 0, -56.4879132, 0, 0, 0, 50.1473938, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 40.2219566, 0, 0, 0, 84.5162074, 0, 0, 0, -73.3030606, 0, -10.9258316, 0, 0,\n", - " 0, 0, 97.5496436, -70.5026182, 0, 62.3611696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 96.4362226, 0, 0, 0, 0, 0, 0, 0, -6.0104764, 15.7466756\n", - "], [\n", - " -38.7678174, 0, 0, 0, 0, 10.5238486, 0, 0, 0, 31.6876676, 79.6111978, 0, 0,\n", - " 0, 0, 45.7314046, 0, 0, 0, -10.0125122, 0, 93.3170242, -96.4566224,\n", - " -5.853298, 0, -82.2848728, 0, 0, 0, 0, 0, 0, 0, 43.3427638, 24.6186934, 0,\n", - " 44.859548, 0, -63.8196424, 0, 32.6630616, 41.48423, 0, -42.9613722, 0, 0,\n", - " -68.8954844, 0, 0, 0, 0, 0, 0, 0, 0, 27.7424034, -33.4867534, -49.1827758,\n", - " 0, 18.7014116, 0, 0, 59.049662, 0, 0, 0, 0, 0, 0, -29.6305028, 0, 0, 0, 0,\n", - " 0, 98.2266078\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -14.6583468, 0, -74.4490466, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, -94.9604028, 0, 0, -48.28403, -41.3534342, 0, 0, 0, 62.9532972, 0,\n", - " 0, 4.030284, 0, -60.478996, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, -46.5887848, 39.4565458, 0, 0, 0, 0, 0, 0, 0, -48.5071236, 0, 0, 0,\n", - " 41.8640204, 0, 0, 0, 74.271524, 0, 15.5769242, 0, -61.4793904, 52.4500934\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50.8387116, 0, 46.490051, 0, -54.9751352, 0,\n", - " 43.0696416, 0, 0, 0, 0, 80.5337704, 0, 0, -16.0325234, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 63.186351, 0, 0, 0, 0, 0, 75.2218604, -27.3783446, 0, 0, 0, 0,\n", - " -85.021934, 60.9043202, 55.7344594, 0, 41.1687556, 0, 5.574124, 0, 0,\n", - " -5.0028254, -40.2614834, 0, 0, 0, 0, 0, 0, 22.207679, 0, 0, 0, 0, 0,\n", - " 65.0504204, 0, -61.4580018, -90.137276, 19.2277196, 0, 0, -73.8615034\n", - "], [\n", - " 0, 0, 0, 0, 0, -21.3303052, -75.4586018, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 84.6730538, -3.4478344, 0, -76.083503, 19.9372656,\n", - " -38.9938322, 0, 0, 36.0135034, 0, -56.8457144, 0, 0, 63.4198336, 0, 0, 0, 0,\n", - " 0, -63.4419798, 28.5629988, 0, 0, 0, 0, 38.8001126, 0, 0, 47.2148438, 0,\n", - " -19.256673, -24.8778354, -47.8193252, 0, 0, -38.7279908, 0, 0, 0,\n", - " -34.5546658, 0, -96.7675822, 0, 0, 0, 0, 0, 0, 0, 0, 27.9437518\n", - "], [\n", - " 0, -17.8703906, 0, 0, -47.2114204, 0, -73.3595682, 66.668341, 0, 0, 0, 0,\n", - " 30.250278, 0, -40.452007, 0, 0, 0, 0, 0, -37.5013244, 34.3045856, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12.898457, -15.2838318, 0, 0,\n", - " 0, 0, 0, 16.333021, 0, 72.0452526, 0, 2.285458, 0, 0, 0, 0, -17.8073046, 0,\n", - " 0, 0, 81.7271146, 0, 0, -17.7174538, 0, -62.6694996, 8.7298318, 0, 0, 0, 0,\n", - " 0, 0, -27.1131974, 0, -68.0964272\n", - "], [\n", - " 0, 0, 0, 0, -22.1791216, 16.588597, -19.4545486, 0, -74.8318248,\n", - " -74.4252462, 0, 0, 0, -46.1656546, 0, 0, -21.1620788, 0, -25.6883764, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 34.5550634, 0, 0, 0, 0, 93.8894398, 0, -30.961635, 0,\n", - " 0, 0, 0, 0, 78.594791, 0, 0, -63.3427616, 52.6543374, 0, 0, 38.4578962, 0,\n", - " 0, -56.5589394, 0, 0, 0.6873802, 0, -83.496155, 0, 0, 0, 13.0737006, 0,\n", - " -41.7343216, 71.8170636, 69.0276666, 0, 0, 57.722026, 0, 0, -93.1746526, 0,\n", - " 0, 0, 0, -49.9838934\n", - "], [\n", - " 0, 4.2310134, -77.9001854, -57.1049418, 0, 53.3411444, 0, 0, 62.3456148, 0,\n", - " 0, 68.2636062, 0, 0, -97.5234598, 0, 87.5610236, 0, 0, 0, 0, -77.3855948, 0,\n", - " 0, -90.724008, 28.2231562, 0, 53.026918, 0, 0, 0, -76.15995, 0, 0, 0,\n", - " 15.413813, 0, 0, 0, 0, 0, 0, 0, 0, 13.0272308, 0, 0, -23.9738128,\n", - " 38.7553414, 0, 30.9290494, -35.5982432, 0, 0, 0, -45.1103148, 0, 0, 0,\n", - " 70.158022, 0, 0, 0, 0, 0, 54.120183, 0, 0, 0, -41.9285314, 0, 0, 0, 0,\n", - " 14.1035676, 33.7857218\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 63.3716696, 0, 0, 0, 0, 0, 24.0919054, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 11.3748388, 0, 0, 95.3405052, 93.4694228, 0, 0, -45.255791, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, -1.0475536, 60.84603, 0, 0, -10.47761, 0, 26.1100158,\n", - " -51.9159084, 0, 0, 0, 0, 0, 0, -65.6123578, 0, -91.0146766, 0, 0, 0, 0, 0,\n", - " 0, 0, -21.2845524, 0, 35.7297864, 0, 0, 0, 0, 0, 0, 15.911098, 0, 0,\n", - " -12.9287238\n", - "], [\n", - " 0, 0, 4.6786386, 0, 0, 1.6495644, 0, 0, 0, 26.96434, 0, 0, 0, 58.7515752, 0,\n", - " 0, 0, -47.6494254, 0, -54.2669514, 72.894442, 0, 0, 95.889445, 0,\n", - " 68.8888298, -66.11831, 0, -23.7891422, 79.7630012, 0, 0, 0, -63.9280642, 0,\n", - " 0, 0, 0, -32.1729936, 0, 0, -44.1408756, 0, 0, 0, 0, -43.6440432, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 9.0521906, 0, 0, -26.1975436, 0, 45.9278082, 0, 0, 29.678958,\n", - " 0, 0, 0, 0, 0, 5.9131246, -82.314248, 0, -56.8775976, -43.6011182, 0,\n", - " -28.0599468\n", - "], [\n", - " 44.0699428, 0, -0.2569744, 0, 0, 0, 10.53932, 0, -89.8739242, 0, 0, 0, 0,\n", - " -39.5334882, -60.036911, 96.86551, 0, -59.6306248, 0, 76.9520134, 0, 0, 0,\n", - " 0, 0, 55.2369732, 0, 0, 0, 0, -41.8466046, 0, 0, -5.291202, 0, -18.5051634,\n", - " 0, 0, 0, 0, 0, 47.1813778, 92.5194464, 90.690835, 56.7657076, 0, 0, 0,\n", - " -42.1944794, 0, 0, 0, -69.1124266, 0, 0, 0, 0, 0, 0, 0, -14.4018142,\n", - " -36.9699736, 0, 0, 0, 0, 0, 0, 41.4981516, -1.5870996, 0, -73.7309526,\n", - " -68.2179518, 0, 5.1895272, -29.7117264\n", - "], [\n", - " 90.3158852, 54.7711894, 0, 0, 0, 0, 0, 0, 0, -92.2564004, -20.8178774, 0,\n", - " 17.3192726, 0, 2.5685474, 0, 0, 0, 0, -21.96248, 0, -83.8507778, 0, 0, 0, 0,\n", - " -81.769375, 0, 0, 0, -73.8973162, 0, 0, 0, 0, 0, 0, -96.8790628, 0,\n", - " -29.2883476, 0, 0, -73.2399312, 0, 0, 0, 56.465223, 0, -10.1549238, 0, 0,\n", - " 44.7135732, 0, 0, 0, 0, -37.8912668, 61.0703958, 0, 0, 0, 94.563183,\n", - " 2.1777518, 0, 0, 0, 0, 0, 0, 69.8987148, 0, 0, 0, 58.5987754, 0, -73.701682\n", - "], [\n", - " 0, 25.7383596, 0, 43.2784374, 0, 0, 0, 0, 0, 0, 0, 65.3498334, 0,\n", - " -51.6680898, 0, 0, 0, -32.4960916, 0, -61.8512302, 0, 0, 0, 0, 66.0087116,\n", - " 0, 0, 0, 0, 0, -69.5971312, -68.5339006, 0, -87.9115714, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 13.6412636, 0, -33.3575526, 0, -34.6876284, 0, 0, 0, 0,\n", - " 0, -5.195929, 0, 0, 0, 0, 0, 0, -62.551799, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -85.6796076, 0, -69.9796424\n", - "], [\n", - " 0, -67.7487338, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -89.686036, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35.3396338, -51.2668318, 0, 0,\n", - " -9.4925338, 0, 0, 0, 0, 0, 0, 0, 0, -74.049299, 0, 0, 0, 6.669526, 0, 0, 0,\n", - " 0, 82.3839076, 0, 0, 0, -63.2986138, 0, 0, 0, 29.4639612, 0, 0, -75.2754458,\n", - " 0, 0, 10.6058324, 83.9439366, 48.4539264, 0, 0, 0, 0, 8.6922024, 17.82273\n", - "], [\n", - " -12.5659444, 0, 0, 0, 0, 0, -16.0039068, 0, 0, 0, 0, -64.5579896, 0,\n", - " 25.3425712, 0, 0, 0, 0, -73.3525686, 0, 0, 0, 41.4534476, 0, 0, 35.6355928,\n", - " 82.0438356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16.5500598, 0, 17.4573382,\n", - " -30.4230828, 68.6250598, 0, 0, -70.7101786, 0, 0, 0, 0, 0, 19.070679, 0, 0,\n", - " 0, 0, 0, 0, 0, -69.0034118, 0, -32.8881618, 0, 99.6116696, -41.8557658,\n", - " -36.91302, 0, 0, 0, 0, 0, 25.1313946, 0, 0, 0, 0, 0, 66.1785624\n", - "], [\n", - " -28.5551034, -60.2641954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11.4765054, 0, 0, 0, 0,\n", - " 0, 0, 78.1818898, 0, 0, 0, 0, 34.0574966, 0, 0, 0, 3.3327304, 0, 0, 0, 0, 0,\n", - " 0, 0, -25.4031686, -6.4345882, 0, 0, 0, 0, 0, 70.724926, 0, 0, 0, 0, 0, 0,\n", - " -34.578727, 0, 0, 0, 0, 73.4821434, 0, 0, 0, 0, -78.7097278, 0, 0, 0,\n", - " -56.0390914, -77.1810362, 95.2972308, 0, -88.304829, 0, -11.4076234, 0, 0,\n", - " 0, 0, 0, -53.8368524\n", - "], [\n", - " 0, 0, 53.7291982, 0, 0, 0, 0, 0, 0, 0, 0, 90.7870612, -66.2974882, 0,\n", - " -92.2201462, -15.7252186, 0, 0, 0, 0, 0, -25.4072904, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 32.8926792, 36.9923848, 0, 0, 0, 0, 33.293754, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 5.689557, 0, 0, 89.5416534, 40.4300196, 0, 0, 2.8394972,\n", - " 90.7550328, 0, 0, 71.835872, 30.8157976, -96.7796296, 0, 44.1461388, 0, 0,\n", - " -32.5545222, 0, 75.597677, 0, 0, 0, 0, 33.146892\n", - "], [\n", - " 0, -36.157067, 0, 0, -0.4087578, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13.1871604, 0,\n", - " 60.6086354, 84.4235272, 0, 0, 89.0383032, 0, 0, 0, -43.0195992, 0,\n", - " -99.31608, 0, -64.2154682, 0, 0, 0, 76.5304532, 0, 0, 0, 0, 0, 82.052369, 0,\n", - " -72.450166, 0, 0, 0, 23.4129134, 0, 0, 0, 0, 0, 0, 0, 0, 53.3291088, 0, 0,\n", - " 0, 73.435697, 87.3597806, 0, -94.1974698, 0, 0, 0, 0, 59.0496292, 0, 0, 0,\n", - " -13.8506028, 0, 0, -42.6003178, 0, 0, 55.1715212\n", - "], [\n", - " 0, 0, 0, -67.8709314, 0, 0, 0, 0, 0, 0, 0, -9.678326, 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, -28.014314, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, -36.8865788, 0, 0, -98.739389, 0, 0, 0, 0, 0, 0, -86.2168946, 0,\n", - " 44.1228816, 0, 0, 0, 0, 0, 0, -36.6609072, 0, 0, 0, 0, 18.3461886,\n", - " 98.9990466, 30.4109678, 0, 0, 0, -39.2683046\n", - "], [\n", - " -49.3558704, 0, 0, -31.3665258, 0, 0, 0, 0, 0, 0, 1.7897898, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, -15.7715374, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -50.0629034, 0, 0, 0, 0, 0, 0, 0, 35.8856254, 0, -51.062155, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 78.136688, 0, 0, 0, 0, -41.5917514, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 73.1472674, 0, -77.9015418\n", - "], [\n", - " 0, -6.5048614, -28.611729, 0, 0, -97.9680564, 33.7007078, -70.5347856, 0,\n", - " 17.197908, 0, 19.8776858, -24.4246618, 0, 0, 53.363481, 0, 0, 0,\n", - " -44.7872848, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -74.0599438, -81.2162694,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -68.6473592, 0,\n", - " 39.894997, 0, 0, -38.5305628, 0, -5.244101, 0, 0, 46.6040974, 2.4384956, 0,\n", - " 0, -26.8264528, 0, 0, -98.5537452, 2.6463192, 0, 0, 0, 0.4769732\n", - "], [\n", - " 0, 0, 0, 0, -52.7430298, 1.8510158, -39.691072, 0, 0, 0, 0, 0, 95.6497418,\n", - " 0, 0, -48.04896, 0, -26.6728378, 0, 0, 0, 0, 0, -12.3921976, -65.5861706, 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", - " -57.9815088, 0, 77.6808808, 0, 0, 0, 94.6506526, 0, 0, 0, 55.8427672, 0, 0,\n", - " -0.6995066, 0, -78.3071326, 0, 0, 0, 0, 0, 0, 0, 0, 0, -67.9654476\n", - "], [\n", - " 0, -23.0019946, 0, 0, 95.4877116, 0, 0, 0, 0, 0, -36.573767, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90.1862622, -36.4728966, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86.6126918, 0, 0, 0, 0, 0, 0, 0,\n", - " -80.1067184, 0, 31.8472788, 27.496628, -66.6206162, 0, 0, 9.1957296, 0,\n", - " 37.2257526, 0, 0, 0, 0, 0, 0, 0, -39.1637322, 0, 0, 74.4924622\n", - "], [\n", - " 0, 0, -25.4147588, 6.2424662, 0, 0, 0, 0, 0, 0, 92.5623938, -92.810452, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, -45.0048688, 0, 0, -32.1678062, 0, 0, 0, 9.8719598,\n", - " -33.7145476, -16.3449354, 0, 70.462643, 0, 0, 14.5356206, 0, 0, 0, 0,\n", - " -95.1218374, 0, 0, 0, 0, -0.8077516, 0, 0, 0, 0, 0, 53.7434994, 0, 0, 0, 0,\n", - " 0, 5.376533, 0, 0, 0, 0, 0, 0, -1.125953, 75.3929928, 0, 0, 0, 0, 0,\n", - " -17.8555478, 0, 0, 87.130332, -46.977091\n", - "], [\n", - " -57.0064908, 0, -61.469472, 0, 0, 94.2906142, 0, 10.1214686, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 90.8859632, 0, -31.3550928, 25.4391198, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, -30.6974596, 0, 16.8162692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -40.946388,\n", - " -23.914437, -39.0760436, 0, 0, 12.4664916, 0, 0, 0, 59.3854694, 0, 0,\n", - " -79.029102, 0, 48.0444832, 0, 0, 0, 0, 0, 0, 0, -34.447419, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, -42.8371356\n", - "], [\n", - " -46.3742298, 0, 0, 0, 0, 6.4096268, 0, 0, 0, 0, 0, 0, 0, 0, 53.7055136,\n", - " 41.0589284, 0, 0, 0, 0, 0, 0, -59.494163, 78.2644798, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 3.5467882, 0, 0, 0, 0, 0, -33.8146284, 0, 81.1209896, 0, 0,\n", - " 0, 0, 0, 0, -59.120982, 0, 0, 0, 0, 20.5082176, 0, 0, -32.2137818,\n", - " 41.6679682, 98.4426286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18.7911844\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,\n", - " 22.5196126, -44.92426, 0, 0, 0, 0, -78.1154748, 95.3654376, 0, 0, 0,\n", - " -42.4266782, 73.3850132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94.1878774,\n", - " 90.3854666, 0, 0, 0, 0, 0, -15.9053536, -74.9423846, 47.214, 0, 0, 7.477562,\n", - " 0, 46.2206928, 19.1508454, 41.6978146, 39.03286, 0, 0, 0, 0, 0, -14.259302,\n", - " 0, 54.0542232, 0, 0, 44.5438142\n", - "], [\n", - " 95.3632006, 43.6928354, 75.8291588, -81.2577418, 0, 0, -91.248437, 0, 0,\n", - " 22.476879, -77.967431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.0308978, -22.0727056, 0,\n", - " 0, 0, 0, 0, 0, 0, 17.126454, 0, -45.7583606, 0, 0, 32.9187018, 0, 0, 0, 0,\n", - " 0, -58.6847152, 0, 0, 39.113676, 0, 0, 0, 0, 0, 0, -80.1176538, 0,\n", - " -86.9570556, 0, 0, 0, -9.3462492, 0, 49.3616864, 0, 60.4773586, 0, 0,\n", - " 48.9766746, 17.5735282, 75.126033, 0, -50.8306992, 0, 0, 61.3438194, 0, 0,\n", - " -95.9051914, 0, 25.6497354\n", - "], [\n", - " -89.5581772, 0, 0, 0, 0, -37.7576814, 0, 0, 0, -50.475431, 0, 0, 0, 0,\n", - " -75.575654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.7066106, 0, 0, 0, 68.702018, 0, 0,\n", - " 44.2841378, 0, 0, 0, 0, 0, 0, 0, 42.4183476, 80.6872178, 72.028214, 0, 0, 0,\n", - " -50.6912368, 0, 0, 0, 53.1913708, 0, 0, 0, 0, -50.0798868, 0, 0, 0, 0, 0, 0,\n", - " -99.54189, 0, 0, 0, 0, 87.8828622, 7.144766, 0, 0, 0, 71.8161494,\n", - " 91.0414654, 0, 0, -7.240427\n", - "], [\n", - " 0, -73.397517, 0, 0, 0, 0, -42.4633614, 0, 0, 0, 0, -2.3988294, -60.1970288,\n", - " -31.1370786, -16.4428054, 0, -86.5694254, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -33.759363, 0, 88.9440556, 0, 0, 0, 48.8687358, 0, 0, 60.1841648, 0, 0,\n", - " 81.5798018, 0, 0, 0, 0, 22.265044, 0, 0, 0, 0, -98.612946, 0, 0, 0,\n", - " -49.44052, 0, 46.9606012, 0, 0, 0, -23.7990468, 0, 0, 0, 0, -72.1702852, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 26.2623134, 0, -17.3386012\n", - "], [\n", - " 0, 16.4596174, 0, 0, 0, 0, -85.6599392, 0, 0, 0, 0, 0, 0, 93.708794, 0,\n", - " -37.5698758, 0, 0, 0, 0, 0, 0, -82.8927936, 0, 82.4183808, 0, 0, 0, 0, 0, 0,\n", - " 55.028266, 0, 0, 11.3484192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -60.7651522, -4.822581, 0, 29.0627604, 0, 0, 61.7042716, 41.5363722,\n", - " 73.9967868, 0, 0, 0, 0, 50.2308124, 0, 33.8231702, 0, 0, 0, 0, 0,\n", - " -14.7226996, 14.5401778, 0, -72.8145596, 19.9220286, -76.4609286\n", - "], [\n", - " 11.1687196, 0, 0, 0, 0, 0, 0, 0, -37.365205, 0, 0, 0, 52.0314298, 0,\n", - " -58.0558462, 0, 0, 18.6738906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 59.6046802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -26.5944948, 0, 0, 0,\n", - " 77.0271992, 46.521059, 61.8258634, 0, 0, 36.079546, 0, -14.3080494, 0,\n", - " -50.1618478, 0, 0, 95.9445656, 0, 0, 0, 0, 0, 0, 0, 0, 0, -53.478982,\n", - " -90.3623976, 0, 0, -37.1575466\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 78.882051, 0, 0, 57.8056512, 7.2056626, 0, 2.822132,\n", - " 40.311822, 0, 0, 0, 83.8935006, 0, 0, 91.2774482, 3.160849, 91.7410132, 0,\n", - " 0, 0, 0, 0, 2.7544652, 0, 0, 0, 0, 0, 16.8419108, 0, 0, 84.1171174, 0,\n", - " 21.3119752, -69.869284, 0, 0, 0, 0, 0, 92.1087118, 0, 0, 0, 0, 34.3473744,\n", - " 21.9890278, 0, -36.3139526, 0, 0, 0, 0, 0, 25.613497, -2.989159, 0, 0, 0, 0,\n", - " -49.2456622, 0, 0, 27.3140788, 0, 49.210258, 0, 0, -90.6896972\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, -56.1947046, 0, 0, 52.6617176, 61.6283016, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, -34.0759312, 0, 92.0200254, 0, 0, -9.7999914, 0, 0, 34.0572616,\n", - " 0, 0, 0, 0, 0, 59.7637334, 0, 0, 0, 0, 0, 43.5437732, 29.9690024, 0, 0,\n", - " 93.9438036, 0, 0, 0, 52.3867986, 0, 0, 0, 38.0567542, 0, -63.9851954, 0,\n", - " 73.1679634, 0, 0, -28.6636244, 0, 0, 0, 0, 0, 39.2894916, 0, -28.4364668, 0,\n", - " 0, 0, 0, 0, 0, 0, -32.2899456\n", - "], [\n", - " 15.3399588, 0, 0, 0, 0, 0, 0, -66.2540916, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 14.7613734, 0, 0, 0, -32.9550622, 0, 0, -17.2710502, 0, 0, 0,\n", - " -66.7611862, 76.5708962, 93.3868072, 12.036471, 0, 0, 0, -74.2189184, 0, 0,\n", - " 0, 0, 58.0343866, 0, 71.0145124, 0, 0, 0, 0, 0, 0, 0, 80.7131208, 0,\n", - " -49.5191686, 40.2489602, 0, 0, 39.9664558, 0, 0, 0, 0, 0, 0, 51.704979, 0,\n", - " 20.9209752, 0, 0, -63.5800814\n", - "], [\n", - " 0, 0, 35.1676872, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8.326191, 0, 0, 0,\n", - " -42.1405488, 0, 0, 0, 0, -64.9203894, 0, 0, 0, 86.5653072, 0, 17.1250418, 0,\n", - " 15.224998, -32.788739, 0, 0, 0, 13.1550612, 0, 0, 0, 93.3049176, 65.5504482,\n", - " 0, 35.8126186, -16.2474202, 0, -76.7788518, -51.9001008, 0, -89.725966,\n", - " 53.4895596, 0, 0, 0, 0, 0, 0, 0, 0, 0, -82.6077236, 0, 0, 0, -57.075872,\n", - " -52.5166376, 99.9479554, 0, 0, -89.7491862, 0, 18.6163306, 0, 29.1454254\n", - "], [\n", - " -18.8864514, 0, 0, 0, 0, 0, -46.6968628, -83.8123266, 0, 0, 0, 0, 0, 0,\n", - " -91.631792, 0, 0, 0, 0, -57.3455082, 66.459894, 0, 0, 0, -73.9341878, 0, 0,\n", - " 0, 81.8859882, 0, 0, 0, 0, 0, 28.0747908, 0, 0, 99.7796988, 0, 87.0296656,\n", - " 0, 0, 43.7722526, -60.65313, 98.6287198, 0, 20.8634118, 0, 0, 25.6519386,\n", - " 0.4939554, 0, 0, 0, 0, 0, 0, 0, 0, -74.9266526, 0, 0, -25.4234142, 0,\n", - " -91.054582, 0, -42.534282, 0, 0, 0, 0, 0, 0, 0, 0, 12.1491094\n", - "], [\n", - " 0, -90.5331764, 0, 0, 0, 0, 0, -8.1166918, 0, 0, 0, 0, 0, -34.0013692,\n", - " 21.9272646, 0, 0, 0, 0, 0, 93.2245032, 0, 21.8275426, 0, 0, 0, 38.5279608,\n", - " -6.0022692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39.644863, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, -93.7962256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11.5363598,\n", - " 70.354452, 0, 0, 0, 32.2282298, 0, 36.659058, 0, 0, 53.992344\n", - "], [\n", - " -74.4430478, 0, 0, -93.4496218, 14.6437598, 0, 0, 0, -33.8297902, 0, 0, 0,\n", - " 0, 0, 0, -35.949213, 0, 0, -93.1678628, 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", - " -22.8806328, 0, 0, 0, 0, 0, 0, 0, 45.1466816, 88.4821604, 0, 0, -49.7769388,\n", - " 0, 0, 0, 0, 0, 0, 53.6290382, -40.4388272\n", - "], [\n", - " 71.2065308, 94.4966808, 0, 0, 0, 0, -84.2404402, 0, 0, 0, 0, 0, 61.7641462,\n", - " 0, 0, 0, -0.608018, -94.7698384, 0, 0, 0, 0, -3.4562834, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, -26.0708126, -73.3657794, 26.6482556, 0, 0, 0, 0,\n", - " 0, 0, -66.9699546, -98.6726948, 0, 0, -25.4137958, 0, -88.7254432,\n", - " -81.2735544, 0, -23.3081526, 0, -51.8917252, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -52.3004828, 0, 0, 0, 0, 67.8542398, 0, -67.7489638, 32.2212522\n", - "], [\n", - " 0, 77.0252092, 0, 0, 0, 0, 0, -85.3271924, 0, 0, 0, -2.9308596, 0,\n", - " 83.448547, 0, 4.7835886, 0, 0, 0, 0, 76.590577, 0, 0, 0, 0, 0, 86.0180794,\n", - " 0, 0, -88.4030016, 0, 0, 0, -13.770426, 57.6068646, 0, 0, 0, 0, 0,\n", - " 12.6896788, 0, 0, 0, -78.1078136, -92.3074796, 0, 0, 0, 0, -94.3200626, 0,\n", - " 0, -7.987837, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52.7655986, 0, -78.2727176,\n", - " 0, 74.4309632, 48.3867546, -85.4142468, 0, 91.3888914, -6.0372808,\n", - " 51.1643348\n", - "], [\n", - " -77.4193002, 0, 0, 0, 0, 0, 0, 0, 41.0846988, -78.3265056, 0, 0, 0, 0, 0, 0,\n", - " 0, -20.408123, 10.7055032, 0, -19.5848354, 0, -32.624054, 0, 47.333306, 0,\n", - " -41.6545398, 0, 0, 0, 0, 0, 46.8131656, 0, 52.5387768, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, -75.3511542, 0, 0, 0, 0, -27.6140242, 0, 0, -63.3032372, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, -93.1854838, 0, 0, 0, 0, 32.3353436, -75.8659438, 89.852816, 0,\n", - " 9.7044216, 0, 94.9239572, 0, -57.0391726, 25.4894998\n", - "], [\n", - " 0, 0, 0, -27.2226392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -89.0780816, 0, 0,\n", - " 0, 0, 6.6342408, 0, 0, 92.3634346, -41.5559582, 0, 0, 0, 0, 0, 0,\n", - " -4.3499792, 18.9554522, 0, 29.992962, 0, 0, 0, 0, 0, 0, 0, 0, -51.9952794,\n", - " -40.3571344, 0, -61.0098328, 0, 0, 0, 0, 71.8571838, 97.3056784, 0, 0,\n", - " 27.798026, 0, 0, 20.3198544, 0, 0, 0, -82.1043534, 0, 0, 0, 0, 0,\n", - " 55.2807134, 0, 0, 0, 0, -90.8562594, -43.2271604\n", - "], [\n", - " 0, 0, 0, 0, 0, 15.2015056, 18.3740448, -11.2614058, 0, 0, 0, 0, 0,\n", - " 53.0086248, 0, -91.038908, 0, 0, 88.2707986, 3.2580272, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 88.8189254, 0, 0, 0, 0, -3.742353, 0, 0, 0, -41.4198488, 90.0966416, 0,\n", - " -22.474875, 0, -25.610863, -79.5943706, 0, 0, 0, 0, 0, 0, 0, -3.5616438, 0,\n", - " 0, 0, 88.5984932, 0, 0, 0, 0, 0, 0, 0, 22.4398688, 0, 0, 0, 0, 0, 0, 0,\n", - " -63.7422676, 0, 0, 0, -82.7150752\n", - "], [\n", - " 0, 0, 75.634243, -60.420708, 0, 0, 0, 0.8383984, 0, 0, -72.2791914, 0, 0, 0,\n", - " 17.1476022, 0, 0, -14.5930276, 9.4352026, 0, -30.1475326, 0, -53.7249052, 0,\n", - " 19.3293368, 0, 0, 0, -80.867335, 0, -3.344608, 71.3546388, -91.098817, 0, 0,\n", - " 0, -26.83234, 0, 3.7009, 0, 0, 0, 0, 0, 28.4006138, 0, 0, 57.1433046,\n", - " 14.4086186, 0, 0, 0, 49.5828354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17.0012008, 0,\n", - " 30.5581294, -98.7868224, 0, 0, 0, 70.0467486, -9.4444084, 0, 19.9250998, 0,\n", - " 0, -79.4970662\n", - "], [\n", - " 0, 54.0067274, 0, 0, 0, 37.9936634, 0, -20.1071476, -58.981429, 0, 0,\n", - " -83.9927614, 0, 0, 0, 0, 0, 0, -70.8571636, 0, 0, 68.4686496, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, -8.1687508, 0, 0, 16.6835288, -10.1286606, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 86.4747972, 0, -34.6316042, 0.9788672, 0, 0, -41.4513542,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, -28.4021576, -74.9076708, 0, -5.0425708, 0, 0, 0,\n", - " 78.9139852, -50.7082204, 0, 34.0684852, 28.2502302\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 57.544994, 0, 0, -22.4411072, 0, -94.2568866,\n", - " -80.7849138, 0, 0, -10.0010618, 33.3160792, 0, 0, 0, 0, 0, 0, -82.6811248,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -11.0390072, 0, 0, 32.0523166, 0, -80.6937396,\n", - " 0, -94.2671164, 0, 0, -16.2170198, 0, 0, 0, -5.7387768, 0, 0, 0, 0,\n", - " -83.6048238, 0, 0, 0, 0, 0, 0, 33.6877392, 0, -41.9784856, 0, 0, 0,\n", - " -50.6512854, 0, 78.737702, 0, 0, 0, 0, 0, 9.0618996\n", - "], [\n", - " 0, 0, 0, 0, 0, -94.8072128, 0, 21.9767716, 0, 0, 0, 57.7817378, 35.3840102,\n", - " 0, 0, 0, 60.4679182, -94.9978498, 0, -18.9377882, -42.3270372, 0, 0, 0, 0,\n", - " -3.9058912, 0, 0, 44.440235, 0, 0.41471, 0, 0, -88.0148602, 53.9755254, 0,\n", - " 0, 74.7772774, -19.633854, -66.6129164, -25.4637816, -13.1642082, 0, 0, 0,\n", - " 0, 57.6068044, 0, 0, -75.9060014, 24.0447026, 0, 0, 29.9750648, 0, 0, 0,\n", - " -54.938857, -4.4090126, 0, 0, 0, 0, 0, 0, -57.1202194, 0, -11.130658, 0, 0,\n", - " 95.6177756, -78.5403868, 0, 0, 30.4589622, -93.6950296\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -50.308444, 0, 0, 0, 0, 0, 0, 0, -20.3462364,\n", - " 0, 0, 25.6081088, 0, 0, 0, 0, 0, 0, 90.9877902, 0, -56.0922542, 99.2456868,\n", - " 0, 45.4316172, 0, 70.1339288, -54.576692, 0, 0, 0, -73.6910292, 0, 0, 0, 0,\n", - " 0, 0, 38.6032202, 0, 0, 0, 60.7387286, 0, 0, 0, 0, 0, 0, 0, 0, 95.207832, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58.4721284\n", - "], [\n", - " 0.3163476, 0, 0, 13.0918568, 5.13089, 0, 40.7266308, 0, 0, 0, 0, 0,\n", - " -98.7077428, 0, 81.000503, 0, 0, 76.3945372, 0, 0, 0, 0, 0, 0, -10.2289084,\n", - " -70.592702, 0, 0, 0, 0, 0, 0, 69.59571, 0, 0, 0, 0, 0, -61.4746908,\n", - " 53.4041094, 0, 90.4397278, -33.1874988, 0, 0, 71.5512744, 5.846105, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56.7568638, 0, 0, 66.7588344, 0, 0, 0,\n", - " 99.284785, 0, 0, 0, 0, 0, 0, -99.2850048, -85.4466004\n", - "], [\n", - " 0, 0, -34.544278, 0, 0, -36.135124, -33.4259354, 0, 0, -60.4256326, 0,\n", - " 44.7734168, 0, 0, 0, 0, -88.6744704, 0, 0, 0, 0, 0, 0, 0, 0, -95.3752508,\n", - " 4.596855, 85.2924422, 70.9081648, 22.0390844, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 1.6872456, 0, 0, 0, 0, 0, 0, 0, -37.4782422, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 4.7642096, 0, 0, -33.6313218, 0, 0, 72.977526, 0, 0, 0, 0, 0, 0, 2.5063252,\n", - " 0, 0, 0, 0, 0, -64.8677902\n", - "], [\n", - " 0, 0, 0, 3.718989, 0, 0, 49.3814782, 77.868826, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -49.7008846, 0, 4.696494, 0, 0, 0, 0, 0, 0, 0, -59.4928602, 0, 0, 0, 0, 0,\n", - " 82.6840644, -0.996624, -15.8014198, -93.098215, 0, 0, 41.2709314, 0,\n", - " -90.9633198, -56.911012, 0, 0, 0, 0, 0, 0, 0, 0, 0, -26.02585, 0, 0, 0, 0,\n", - " 0, 0, 61.2353938, 0, 0, 0, 0, 21.376448, 0, 0, 0, 0, 0, 0, 0, 97.0578858, 0,\n", - " 0, 0, 5.1265226\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -19.5643656, 0, 0,\n", - " -92.0307416, 0, 0, 0, 0, 55.003856, 0, 0, -20.4708104, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54.4588824, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -57.0182252, 0, 0, -48.3222128, 0, 0, 0, -41.1121382, 0, 0, 0, 0, 0, 0,\n", - " -12.2773602, 0, -28.6924808, 50.0415338\n", - "], [\n", - " 0, 0, 0, -73.9719246, 0, 0, 0, 0, 0, 0, 0, 39.4110332, 0, 0, -21.6757132, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74.8739354, 0, 0,\n", - " -52.9210426, 0, 46.7750368, 63.6311858, 0, 0, 0, 0, 25.5310902, 0,\n", - " -3.0369126, 0, 32.5437816, 0, 0, 78.9107496, 32.0416448, 0, 0, 15.9408846,\n", - " 0, 0, 0, 0, -67.7582854, -52.6103086, 0, 0, 0, 0, 0, 0, 11.8676176, 0, 0,\n", - " -41.8820812, 43.608357, 0, 0, -64.3752572\n", - "], [\n", - " 0, -15.1648222, -57.5273074, -94.2919124, -3.0777222, -77.345826,\n", - " 91.2777856, 0, 0, 0, 0, 13.5044774, 0, 0, 0, 0, 0, 0, 0, 0, 33.5509618, 0,\n", - " 0, -33.291092, -60.3050638, 0, 0, 0, 94.610171, 0, 0, 0, 0, 0, 0,\n", - " -47.270154, -81.403122, 0, 0, 47.829269, 0, 0, 0, 0, -47.4699122, 0, 0,\n", - " -31.0161918, 0, 0, -54.993563, -9.6544012, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -17.0644648, 0, 0, 0, 0, 0, 0, 49.0555938, -82.4686508, 0, 0, 97.7299292, 0,\n", - " 0, -93.1718028\n", - "], [\n", - " 0, 0, 0, 45.5639954, 0, 0, 0, 0, 0, 92.3127826, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, -5.8746296, 22.9079182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 25.2727812, 0, 0, 0, 0, 0, 0, 65.0012614, 0, 67.4376806, 0, 0, 14.0298002,\n", - " 0, 0, 0, 0, 0, 33.432514, 43.000429, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20.2757068,\n", - " 4.0567932, 0, 0, -15.8737758, 0, 0, 0, 0, 29.8957398, 50.0218946, 17.0262346\n", - "], [\n", - " 46.1658228, 19.630724, 0, 0, 0, 0, 0, 80.6073204, 24.5091878, 0, 0, 0,\n", - " 73.9258848, 0, 0, 0, -98.2044476, 0, 0, 0, 0, -59.2213968, 0, -70.1450004,\n", - " 0, 0, 0, 42.4721292, 0, -73.0346074, 0, 67.9829686, 0, 0, 0, 0, 6.6597886,\n", - " 39.7215082, 0, 0, 0, 52.505292, 95.9204336, 0, 0, 5.8797776, 0, 0, 0,\n", - " 36.0738246, 0, -15.2667614, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50.963131, 0, 0, 0,\n", - " 49.3354032, 13.7868492, 0, 77.3708062, 26.0888548, 0, 0, 0, 0, -60.0881692,\n", - " 24.2459968\n", - "], [\n", - " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56.562023, 0, 0, 24.9145996, 0, 0, 0, 0,\n", - " 32.8196724, -75.8879774, -12.4005106, 0, 0, 0, 0, -18.824482, -45.0330046,\n", - " 0, 0, -47.5493022, 0, 0, 0, 8.1879572, 0, 0, 4.5700222, -28.6731266, 0, 0,\n", - " 0, 0, -83.2735948, 5.4624948, 0, 0, 0, 0, 0, 0, 0, 83.664375, -52.8630198,\n", - " 58.5805764, 0, 0, 0, 45.5781336, 0, 0, -1.9768322, 0, 0, 0, 0, 91.1151128,\n", - " 0, 0, 0, 0, 0, 0, -65.5158586, 0, -22.12762\n", - "], [\n", - " 0, 0, 0, 0, 0, -50.8301006, 0, -57.183698, -24.666489, 43.0557936, 0, 0, 0,\n", - " -44.0812116, 0, 0, 0, 97.1670056, 0, 0, 0, 0, 83.4511366, 0, -96.8912356,\n", - " -6.1095452, 87.6643268, 0, 0, 0, -32.5223614, 0, 0, 0, 0, -18.5596964, 0,\n", - " 56.1790224, 0, 25.6035684, 0, 0, 0, 0, -46.8740154, 0, 0, 0, 0, 0, 0, 0,\n", - " -44.4329434, -34.719678, 85.6384822, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 48.9669952, 0, 0, 0, 0, 0, 0, 0, 0, 0, -28.2571694\n", - "], [\n", - " 0, 0, 0, 0, 42.1192158, 18.3800218, 0, 0, 33.4475094, 0, -39.4713432, 0,\n", - " 54.9744572, 0, -6.6305664, 79.0252374, 77.6908818, -61.5099746, 0, 0,\n", - " 38.4501814, 0, 0, -96.4250704, -27.809694, -34.9250884, 63.2997728, 0,\n", - " -98.8800042, 0, -7.682428, 0, 0, 0, 0, 0, 0, 7.7256608, 0, 48.5546152, 0, 0,\n", - " 0, 0, 0, 0, -58.963373, 0, 0, 0, 0, 0, 86.5062664, 7.0006556, 0, 0, 0, 0, 0,\n", - " 0, 3.1958572, 0, -46.2861844, 0, 0, 0, 0, 30.0710902, 46.6948898, 0,\n", - " 68.4681908, 0, 0, 0, 0, -51.3930766\n", - "], [\n", - " 7.1969236, 0, -79.6160432, -39.947334, -15.2636342, 0, 10.0645898,\n", - " -57.8968238, -31.9945476, 0, 91.5839662, -52.777566, 0, 0, 0, 0,\n", - " -40.9252974, 0, 0, 0, -45.5113982, 70.585349, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " -66.2523308, 0, 0, 0, 0, 0, 0, 0, 0, 85.7454324, -7.1148372, 0, 93.6584844,\n", - " 0, 0, 0, 0, 0, 0, -8.0414788, 0, 0, 0, 0, 51.3263388, 0, 0, 79.892422, 0, 0,\n", - " -64.6934098, 0, 0, -45.9577622, 0, 0, 0, -46.8290526, 0, 48.2417506, 0, 0,\n", - " 0, 0, -2.4115812, -50.7156922\n", - "], [\n", - " 62.9870494, -81.5584552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53.7333104, 0,\n", - " 50.6438202, -57.7938262, 0, 0, 0, 0, -78.1108892, 0, 0, 0, 0, 0, 0, 0,\n", - " 87.6584692, 0, 58.2960112, -17.5355398, 12.0497204, -60.5414862, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 38.586472, -19.7940052, 94.423359, -89.557933, 0, 0,\n", - " -77.0715722, 0, -87.707166, 70.8585278, 0, 9.0616914, 91.333051, 0, 0, 0,\n", - " 5.8166112, 0, 24.7793442, -51.000038, 0, 0, 0, 0, 0, 0, 79.9657776,\n", - " 97.4969126, 0, 0, 0, 0, -73.8994394\n", - "], [\n", - " 10.133741, 0, 0, 0, 95.6910336, 0, 0, 0, 0, -22.6696236, 0, 0, 0, 0,\n", - " 15.137996, 35.7088464, 0, -16.1971956, 0, -29.4834358, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, 0, 0, 0, 0, -89.868739, 24.0040126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 40.7292396, 35.7709458, 0, 34.690347, 22.3083532, 0, 0, 0, 0, 0,\n", - " -48.4224164, 0, 0, 0, 0, 91.7670744, 0, 0, 69.4045014, 0, 60.5937114,\n", - " -38.9993134, 0, 0, 0, 0, 0, 55.4599018, 0, 86.689944\n", - "], [\n", - " 0, 0, -24.842169, -52.997003, 0, 0, 0, 0, 0, 0, 0, 5.9075842, 0, 0,\n", - " -91.1447252, -5.3147106, 0, 0, 0, 4.4670454, 34.97343, 0, 0, 0, 0, 0, 0, 0,\n", - " 0, 0, 0, -5.3957052, 0, 0, 0, 0, -19.2118838, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 64.9559324, 0, 0, -10.0586402, 0, -74.8523334, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", - " 84.8495464, 0, 0, 0, 0, 0, 0, 33.0825986, 46.995148, 0, 0, 0, -4.243203, 0,\n", - " 0, -24.0124188\n", - "]]\n", + "RAW_DATA = [\n", + " [\n", + " 0, 0, 49.774821, -59.5968886, -46.0773896, 0, -65.166109, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 47.0957778, 15.259961, -98.7983264, 0, 0, 0, -20.7757184,\n", + " 0, 87.2645672, 0, -22.7888772, 0, 0, 0, -40.4980904, -19.7307486,\n", + " -23.222078, 0, -77.5263128, 0, 0, 56.6204008, 0, 0, 0, 0, 0, 0, 0,\n", + " 31.378421, 0, 97.3441448, 35.1309806, 0, 0, -40.5727886, -50.7308566, 0,\n", + " 0, -69.9304568, 0, 38.5385914, 0, -22.1243232, 0, 0, 0, 0, -62.5102538,\n", + " 8.0801276, 46.7998066, -2.3292106, 0, 0, 0, 8.774031, 0, 0, -65.6505736\n", + " ],\n", + " [\n", + " -67.2935466, -64.4354852, -96.6712204, 0, 0, -60.7812272, 0, 0, 0, 0, 0,\n", + " -7.9966864, 0, 0, 0, 0, 0, 0, 0, 89.7672338, 0, 0, 0, 0, 98.9607046, 0,\n", + " 28.6714432, 0, 0, 0, -26.2738856, 0, 0, 68.363956, 0, 0, 0, 0,\n", + " 54.7406868, 0, 0, 0, 0, 94.2320734, 0, 0, 0, 0, 0, 0, 0, 0, -2.9647794,\n", + " 39.7161716, -54.7931288, 0, 0, 0, 0, -47.2284892, 0, 0, 0, -8.6421808,\n", + " -35.399612, 0, 0, 62.1912668, 0, -6.8930716, 0, 0, -17.0801284, 0, 0,\n", + " 68.6533416\n", + " ],\n", + " [\n", + " 0, 0, 0, 81.165396, 83.773254, 0, -25.1603, 0, 0, 50.225725, 0,\n", + " -3.8242274, 0, 0, 36.2078566, 0, 0, 0, 0, 0, 0, 0, 0, 15.551432, 0, 0,\n", + " -33.6446236, 0, 0, 0, 36.6171324, 0, 0, 0, 0, 67.9591934, 0, 22.1428016,\n", + " 0, -27.2961928, 0, 0, 0, -97.4961564, 90.4062526, 0, 0, 0, -90.0532814,\n", + " 0, 98.8332924, 0, 0, -13.8994926, 0, 17.1962884, 0, 0, 0, -55.1654678,\n", + " 0, 0, 0, 85.829554, 0, -37.971164, 64.233136, -17.9943296, 0, 0, 0, 0,\n", + " -67.7509796, 0, 0, 10.0750712\n", + " ],\n", + " [\n", + " 0, 37.2783148, 0, 0, 0, 36.4959506, 0, 0, 0, 0, 0, 0, 61.201323, 0,\n", + " 14.4328522, 48.4078064, 0, 0, 0, 0, 0, 0, 0, -47.0969056, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 26.720439, 0, 0, 62.1987576, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, -65.2085246, 0, 0, 0, 0, 0, 0, 73.3019432, -14.3431238, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 2.1565846, 0, 0, 0.7733644, 0, 5.9090456, 0,\n", + " -39.7724192\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, -24.4555532, 0, 0, -5.5484574, 0, 25.4685054, 0.7906104,\n", + " 4.273133, 0, 52.12973, 0, -12.8040828, 0, 0, 81.888381, 64.0713498, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62.9088768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 20.869713, 0, 0, -71.5835872, 0, 0, 80.7237808, 0, 0, 0, 0, -60.1883708,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 85.0393326, 23.6045316, -18.8849834, 0, 0, 0,\n", + " -90.8065188, -9.5037982, 14.3196654, 0, -28.9290306, 0, 0, -41.5575766\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -8.9478934, 0,\n", + " -83.6040618, 0, 0, 0, 0, -14.3874822, 77.2528714, 0, 0, 99.2966066, 0,\n", + " 21.7889114, -37.7629282, 0, -11.6026582, 0, 0, 0, 0, 74.422603, 0, 0,\n", + " -79.239245, -31.9686324, 0, 0, 0, 0, 0, 0, -29.8797178, 0, 0,\n", + " 85.2723062, 0, 0, -8.8031188, 0, 0, -20.043565, 0, 0, -70.733454, 0,\n", + " -94.7231762, -85.4584516, 0, 0, 0, 0, -27.6068624, 0, -79.787783, 0, 0,\n", + " -55.1894266\n", + " ],\n", + " [\n", + " 1.9374354, 0, 1.4807184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 61.298952, 0, 0, 0, -90.5702054, 0, 67.381115, 0, -68.684637, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 93.7807934, 0, 8.8213302, -15.9020466, 0, 0, 0, 0,\n", + " 23.8157662, 0, 0, 0, 0, 0, 0, 0, 67.3461972, 0, 0, 0, 0, 0, 43.3263744,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87.7149706, 0, 0, 0, -18.5133574,\n", + " -30.0338992\n", + " ],\n", + " [\n", + " 6.3937798, 78.7697644, 28.4485838, 0, 0, 0.1352466, 0, 0, 74.5767122,\n", + " -13.8340168, 0, 0, 0, 77.2929426, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 17.9243834, 0, 0, 82.2239878, 0, 0, 0, 0, 64.3440016, 90.109577,\n", + " 46.8926522, -2.4494366, 0, 84.7413412, 0, 0, -4.216108, 0, 0,\n", + " -79.8684776, 0, 0, 74.8706758, -64.4518992, 0, 0, 0, 0, -34.4895004, 0,\n", + " 0, 0, -74.1158858, -37.7803516, 0, 0, 0, 0, 0, 80.0054296, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, -84.5832026, 0, 0, 71.2540694\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, -74.9257454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 14.9675444, 0, 0, 0, 0, 0, -27.5236912, 0, 0, -80.4993438, 0,\n", + " -81.8494538, 0, 0, 0, 0, 0, -18.6802002, 0, 0, 0, 0, 0, 0, 0,\n", + " 61.4131076, 0, 0, -55.1421034, 0, 0, -18.576761, 72.3500914, 0, 0, 0, 0,\n", + " 0, 0, -23.6460116, 43.1258024, 0, 93.701872, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, -86.5772554\n", + " ],\n", + " [\n", + " 0, 0, 93.0762916, 0, 0, 0, 0, 0, 0, 0, -37.2663938, 86.8303764, 0, 0, 0,\n", + " -51.9596226, 0, 35.6722618, -91.438259, 0, 0, -70.6277108, 0,\n", + " -82.9146992, 58.0327648, 0, 0, 0, 0, 0, 0, 0, 0, 13.3727302, 0, 0, 0,\n", + " 23.5719942, 0, -21.5445476, 74.1541634, 60.6365036, 97.4447708, 0, 0, 0,\n", + " 0, 82.5869498, 0, 85.1132108, 0, 0, 0, 0, 0, 0, 97.4012534, 0, 0, 0, 0,\n", + " -45.1504048, 1.0619934, 59.7140264, 0, 0, 0, 0, 0, 4.177461, 0, 0, 0,\n", + " -75.7039276, 0, 0.0421338\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -71.171869, 0, 0, 8.685266, 0, 0, 0, 0,\n", + " 33.9089574, 0, -31.6154498, 0, 0, 0, 0, 0, 5.3182746, 0, 0, 0, 0, 0, 0,\n", + " 3.0361166, -10.364305, 0, 0, 0, 0, 0, 0, 0, 0, -83.9738444, 0, 0,\n", + " -7.9170212, 0, 0, 0, -28.7575682, 0, 0, 0, -29.9216686, 0, 0,\n", + " 83.4050918, -39.5247364, -6.7028846, 0, 0, 0, -23.6080482, 0, 0, 0, 0,\n", + " 0, 0, -18.380154, 46.9252306, 0, 0, 26.1618372, 99.6235254\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 52.008307, 0, 0, 0, 0, 0, 92.4974102, -76.3015714,\n", + " 0, 0, 0, 0, 0, 0, 0, -56.4879132, 0, 0, 0, 50.1473938, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 40.2219566, 0, 0, 0, 84.5162074, 0, 0, 0, -73.3030606, 0,\n", + " -10.9258316, 0, 0, 0, 0, 97.5496436, -70.5026182, 0, 62.3611696, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96.4362226, 0, 0, 0, 0, 0, 0, 0,\n", + " -6.0104764, 15.7466756\n", + " ],\n", + " [\n", + " -38.7678174, 0, 0, 0, 0, 10.5238486, 0, 0, 0, 31.6876676, 79.6111978, 0,\n", + " 0, 0, 0, 45.7314046, 0, 0, 0, -10.0125122, 0, 93.3170242, -96.4566224,\n", + " -5.853298, 0, -82.2848728, 0, 0, 0, 0, 0, 0, 0, 43.3427638, 24.6186934,\n", + " 0, 44.859548, 0, -63.8196424, 0, 32.6630616, 41.48423, 0, -42.9613722,\n", + " 0, 0, -68.8954844, 0, 0, 0, 0, 0, 0, 0, 0, 27.7424034, -33.4867534,\n", + " -49.1827758, 0, 18.7014116, 0, 0, 59.049662, 0, 0, 0, 0, 0, 0,\n", + " -29.6305028, 0, 0, 0, 0, 0, 98.2266078\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -14.6583468, 0, -74.4490466, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, -94.9604028, 0, 0, -48.28403, -41.3534342, 0, 0, 0,\n", + " 62.9532972, 0, 0, 4.030284, 0, -60.478996, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, -46.5887848, 39.4565458, 0, 0, 0, 0, 0, 0, 0,\n", + " -48.5071236, 0, 0, 0, 41.8640204, 0, 0, 0, 74.271524, 0, 15.5769242, 0,\n", + " -61.4793904, 52.4500934\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50.8387116, 0, 46.490051, 0, -54.9751352,\n", + " 0, 43.0696416, 0, 0, 0, 0, 80.5337704, 0, 0, -16.0325234, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 63.186351, 0, 0, 0, 0, 0, 75.2218604, -27.3783446, 0, 0, 0, 0,\n", + " -85.021934, 60.9043202, 55.7344594, 0, 41.1687556, 0, 5.574124, 0, 0,\n", + " -5.0028254, -40.2614834, 0, 0, 0, 0, 0, 0, 22.207679, 0, 0, 0, 0, 0,\n", + " 65.0504204, 0, -61.4580018, -90.137276, 19.2277196, 0, 0, -73.8615034\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, -21.3303052, -75.4586018, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 84.6730538, -3.4478344, 0, -76.083503,\n", + " 19.9372656, -38.9938322, 0, 0, 36.0135034, 0, -56.8457144, 0, 0,\n", + " 63.4198336, 0, 0, 0, 0, 0, -63.4419798, 28.5629988, 0, 0, 0, 0,\n", + " 38.8001126, 0, 0, 47.2148438, 0, -19.256673, -24.8778354, -47.8193252,\n", + " 0, 0, -38.7279908, 0, 0, 0, -34.5546658, 0, -96.7675822, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 27.9437518\n", + " ],\n", + " [\n", + " 0, -17.8703906, 0, 0, -47.2114204, 0, -73.3595682, 66.668341, 0, 0, 0,\n", + " 0, 30.250278, 0, -40.452007, 0, 0, 0, 0, 0, -37.5013244, 34.3045856, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12.898457,\n", + " -15.2838318, 0, 0, 0, 0, 0, 16.333021, 0, 72.0452526, 0, 2.285458, 0, 0,\n", + " 0, 0, -17.8073046, 0, 0, 0, 81.7271146, 0, 0, -17.7174538, 0,\n", + " -62.6694996, 8.7298318, 0, 0, 0, 0, 0, 0, -27.1131974, 0, -68.0964272\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, -22.1791216, 16.588597, -19.4545486, 0, -74.8318248,\n", + " -74.4252462, 0, 0, 0, -46.1656546, 0, 0, -21.1620788, 0, -25.6883764, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 34.5550634, 0, 0, 0, 0, 93.8894398, 0,\n", + " -30.961635, 0, 0, 0, 0, 0, 78.594791, 0, 0, -63.3427616, 52.6543374, 0,\n", + " 0, 38.4578962, 0, 0, -56.5589394, 0, 0, 0.6873802, 0, -83.496155, 0, 0,\n", + " 0, 13.0737006, 0, -41.7343216, 71.8170636, 69.0276666, 0, 0, 57.722026,\n", + " 0, 0, -93.1746526, 0, 0, 0, 0, -49.9838934\n", + " ],\n", + " [\n", + " 0, 4.2310134, -77.9001854, -57.1049418, 0, 53.3411444, 0, 0, 62.3456148,\n", + " 0, 0, 68.2636062, 0, 0, -97.5234598, 0, 87.5610236, 0, 0, 0, 0,\n", + " -77.3855948, 0, 0, -90.724008, 28.2231562, 0, 53.026918, 0, 0, 0,\n", + " -76.15995, 0, 0, 0, 15.413813, 0, 0, 0, 0, 0, 0, 0, 0, 13.0272308, 0, 0,\n", + " -23.9738128, 38.7553414, 0, 30.9290494, -35.5982432, 0, 0, 0,\n", + " -45.1103148, 0, 0, 0, 70.158022, 0, 0, 0, 0, 0, 54.120183, 0, 0, 0,\n", + " -41.9285314, 0, 0, 0, 0, 14.1035676, 33.7857218\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 63.3716696, 0, 0, 0, 0, 0, 24.0919054, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 11.3748388, 0, 0, 95.3405052, 93.4694228, 0, 0,\n", + " -45.255791, 0, 0, 0, 0, 0, 0, 0, 0, -1.0475536, 60.84603, 0, 0,\n", + " -10.47761, 0, 26.1100158, -51.9159084, 0, 0, 0, 0, 0, 0, -65.6123578, 0,\n", + " -91.0146766, 0, 0, 0, 0, 0, 0, 0, -21.2845524, 0, 35.7297864, 0, 0, 0,\n", + " 0, 0, 0, 15.911098, 0, 0, -12.9287238\n", + " ],\n", + " [\n", + " 0, 0, 4.6786386, 0, 0, 1.6495644, 0, 0, 0, 26.96434, 0, 0, 0,\n", + " 58.7515752, 0, 0, 0, -47.6494254, 0, -54.2669514, 72.894442, 0, 0,\n", + " 95.889445, 0, 68.8888298, -66.11831, 0, -23.7891422, 79.7630012, 0, 0,\n", + " 0, -63.9280642, 0, 0, 0, 0, -32.1729936, 0, 0, -44.1408756, 0, 0, 0, 0,\n", + " -43.6440432, 0, 0, 0, 0, 0, 0, 0, 0, 9.0521906, 0, 0, -26.1975436, 0,\n", + " 45.9278082, 0, 0, 29.678958, 0, 0, 0, 0, 0, 5.9131246, -82.314248, 0,\n", + " -56.8775976, -43.6011182, 0, -28.0599468\n", + " ],\n", + " [\n", + " 44.0699428, 0, -0.2569744, 0, 0, 0, 10.53932, 0, -89.8739242, 0, 0, 0,\n", + " 0, -39.5334882, -60.036911, 96.86551, 0, -59.6306248, 0, 76.9520134, 0,\n", + " 0, 0, 0, 0, 55.2369732, 0, 0, 0, 0, -41.8466046, 0, 0, -5.291202, 0,\n", + " -18.5051634, 0, 0, 0, 0, 0, 47.1813778, 92.5194464, 90.690835,\n", + " 56.7657076, 0, 0, 0, -42.1944794, 0, 0, 0, -69.1124266, 0, 0, 0, 0, 0,\n", + " 0, 0, -14.4018142, -36.9699736, 0, 0, 0, 0, 0, 0, 41.4981516,\n", + " -1.5870996, 0, -73.7309526, -68.2179518, 0, 5.1895272, -29.7117264\n", + " ],\n", + " [\n", + " 90.3158852, 54.7711894, 0, 0, 0, 0, 0, 0, 0, -92.2564004, -20.8178774,\n", + " 0, 17.3192726, 0, 2.5685474, 0, 0, 0, 0, -21.96248, 0, -83.8507778, 0,\n", + " 0, 0, 0, -81.769375, 0, 0, 0, -73.8973162, 0, 0, 0, 0, 0, 0,\n", + " -96.8790628, 0, -29.2883476, 0, 0, -73.2399312, 0, 0, 0, 56.465223, 0,\n", + " -10.1549238, 0, 0, 44.7135732, 0, 0, 0, 0, -37.8912668, 61.0703958, 0,\n", + " 0, 0, 94.563183, 2.1777518, 0, 0, 0, 0, 0, 0, 69.8987148, 0, 0, 0,\n", + " 58.5987754, 0, -73.701682\n", + " ],\n", + " [\n", + " 0, 25.7383596, 0, 43.2784374, 0, 0, 0, 0, 0, 0, 0, 65.3498334, 0,\n", + " -51.6680898, 0, 0, 0, -32.4960916, 0, -61.8512302, 0, 0, 0, 0,\n", + " 66.0087116, 0, 0, 0, 0, 0, -69.5971312, -68.5339006, 0, -87.9115714, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13.6412636, 0, -33.3575526, 0,\n", + " -34.6876284, 0, 0, 0, 0, 0, -5.195929, 0, 0, 0, 0, 0, 0, -62.551799, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, -85.6796076, 0, -69.9796424\n", + " ],\n", + " [\n", + " 0, -67.7487338, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -89.686036, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35.3396338, -51.2668318, 0, 0,\n", + " -9.4925338, 0, 0, 0, 0, 0, 0, 0, 0, -74.049299, 0, 0, 0, 6.669526, 0, 0,\n", + " 0, 0, 82.3839076, 0, 0, 0, -63.2986138, 0, 0, 0, 29.4639612, 0, 0,\n", + " -75.2754458, 0, 0, 10.6058324, 83.9439366, 48.4539264, 0, 0, 0, 0,\n", + " 8.6922024, 17.82273\n", + " ],\n", + " [\n", + " -12.5659444, 0, 0, 0, 0, 0, -16.0039068, 0, 0, 0, 0, -64.5579896, 0,\n", + " 25.3425712, 0, 0, 0, 0, -73.3525686, 0, 0, 0, 41.4534476, 0, 0,\n", + " 35.6355928, 82.0438356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16.5500598, 0,\n", + " 17.4573382, -30.4230828, 68.6250598, 0, 0, -70.7101786, 0, 0, 0, 0, 0,\n", + " 19.070679, 0, 0, 0, 0, 0, 0, 0, -69.0034118, 0, -32.8881618, 0,\n", + " 99.6116696, -41.8557658, -36.91302, 0, 0, 0, 0, 0, 25.1313946, 0, 0, 0,\n", + " 0, 0, 66.1785624\n", + " ],\n", + " [\n", + " -28.5551034, -60.2641954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11.4765054, 0, 0,\n", + " 0, 0, 0, 0, 78.1818898, 0, 0, 0, 0, 34.0574966, 0, 0, 0, 3.3327304, 0,\n", + " 0, 0, 0, 0, 0, 0, -25.4031686, -6.4345882, 0, 0, 0, 0, 0, 70.724926, 0,\n", + " 0, 0, 0, 0, 0, -34.578727, 0, 0, 0, 0, 73.4821434, 0, 0, 0, 0,\n", + " -78.7097278, 0, 0, 0, -56.0390914, -77.1810362, 95.2972308, 0,\n", + " -88.304829, 0, -11.4076234, 0, 0, 0, 0, 0, -53.8368524\n", + " ],\n", + " [\n", + " 0, 0, 53.7291982, 0, 0, 0, 0, 0, 0, 0, 0, 90.7870612, -66.2974882, 0,\n", + " -92.2201462, -15.7252186, 0, 0, 0, 0, 0, -25.4072904, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 32.8926792, 36.9923848, 0, 0, 0, 0, 33.293754, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 5.689557, 0, 0, 89.5416534, 40.4300196, 0, 0,\n", + " 2.8394972, 90.7550328, 0, 0, 71.835872, 30.8157976, -96.7796296, 0,\n", + " 44.1461388, 0, 0, -32.5545222, 0, 75.597677, 0, 0, 0, 0, 33.146892\n", + " ],\n", + " [\n", + " 0, -36.157067, 0, 0, -0.4087578, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13.1871604,\n", + " 0, 60.6086354, 84.4235272, 0, 0, 89.0383032, 0, 0, 0, -43.0195992, 0,\n", + " -99.31608, 0, -64.2154682, 0, 0, 0, 76.5304532, 0, 0, 0, 0, 0,\n", + " 82.052369, 0, -72.450166, 0, 0, 0, 23.4129134, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 53.3291088, 0, 0, 0, 73.435697, 87.3597806, 0, -94.1974698, 0, 0, 0, 0,\n", + " 59.0496292, 0, 0, 0, -13.8506028, 0, 0, -42.6003178, 0, 0, 55.1715212\n", + " ],\n", + " [\n", + " 0, 0, 0, -67.8709314, 0, 0, 0, 0, 0, 0, 0, -9.678326, 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, -28.014314, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, -36.8865788, 0, 0, -98.739389, 0, 0, 0, 0, 0, 0,\n", + " -86.2168946, 0, 44.1228816, 0, 0, 0, 0, 0, 0, -36.6609072, 0, 0, 0, 0,\n", + " 18.3461886, 98.9990466, 30.4109678, 0, 0, 0, -39.2683046\n", + " ],\n", + " [\n", + " -49.3558704, 0, 0, -31.3665258, 0, 0, 0, 0, 0, 0, 1.7897898, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, -15.7715374, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -50.0629034, 0, 0, 0, 0, 0, 0, 0, 35.8856254, 0, -51.062155, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 78.136688, 0, 0, 0, 0, -41.5917514, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 73.1472674, 0, -77.9015418\n", + " ],\n", + " [\n", + " 0, -6.5048614, -28.611729, 0, 0, -97.9680564, 33.7007078, -70.5347856,\n", + " 0, 17.197908, 0, 19.8776858, -24.4246618, 0, 0, 53.363481, 0, 0, 0,\n", + " -44.7872848, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -74.0599438,\n", + " -81.2162694, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -68.6473592, 0, 39.894997, 0, 0, -38.5305628, 0, -5.244101, 0, 0,\n", + " 46.6040974, 2.4384956, 0, 0, -26.8264528, 0, 0, -98.5537452, 2.6463192,\n", + " 0, 0, 0, 0.4769732\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, -52.7430298, 1.8510158, -39.691072, 0, 0, 0, 0, 0,\n", + " 95.6497418, 0, 0, -48.04896, 0, -26.6728378, 0, 0, 0, 0, 0, -12.3921976,\n", + " -65.5861706, 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, -57.9815088, 0, 77.6808808, 0, 0, 0, 94.6506526, 0, 0, 0,\n", + " 55.8427672, 0, 0, -0.6995066, 0, -78.3071326, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -67.9654476\n", + " ],\n", + " [\n", + " 0, -23.0019946, 0, 0, 95.4877116, 0, 0, 0, 0, 0, -36.573767, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90.1862622, -36.4728966, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86.6126918, 0, 0, 0, 0, 0, 0,\n", + " 0, -80.1067184, 0, 31.8472788, 27.496628, -66.6206162, 0, 0, 9.1957296,\n", + " 0, 37.2257526, 0, 0, 0, 0, 0, 0, 0, -39.1637322, 0, 0, 74.4924622\n", + " ],\n", + " [\n", + " 0, 0, -25.4147588, 6.2424662, 0, 0, 0, 0, 0, 0, 92.5623938, -92.810452,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, -45.0048688, 0, 0, -32.1678062, 0, 0, 0,\n", + " 9.8719598, -33.7145476, -16.3449354, 0, 70.462643, 0, 0, 14.5356206, 0,\n", + " 0, 0, 0, -95.1218374, 0, 0, 0, 0, -0.8077516, 0, 0, 0, 0, 0, 53.7434994,\n", + " 0, 0, 0, 0, 0, 5.376533, 0, 0, 0, 0, 0, 0, -1.125953, 75.3929928, 0, 0,\n", + " 0, 0, 0, -17.8555478, 0, 0, 87.130332, -46.977091\n", + " ],\n", + " [\n", + " -57.0064908, 0, -61.469472, 0, 0, 94.2906142, 0, 10.1214686, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 90.8859632, 0, -31.3550928, 25.4391198, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, -30.6974596, 0, 16.8162692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -40.946388, -23.914437, -39.0760436, 0, 0, 12.4664916, 0, 0, 0,\n", + " 59.3854694, 0, 0, -79.029102, 0, 48.0444832, 0, 0, 0, 0, 0, 0, 0,\n", + " -34.447419, 0, 0, 0, 0, 0, 0, 0, 0, 0, -42.8371356\n", + " ],\n", + " [\n", + " -46.3742298, 0, 0, 0, 0, 6.4096268, 0, 0, 0, 0, 0, 0, 0, 0, 53.7055136,\n", + " 41.0589284, 0, 0, 0, 0, 0, 0, -59.494163, 78.2644798, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 3.5467882, 0, 0, 0, 0, 0, -33.8146284, 0, 81.1209896,\n", + " 0, 0, 0, 0, 0, 0, -59.120982, 0, 0, 0, 0, 20.5082176, 0, 0, -32.2137818,\n", + " 41.6679682, 98.4426286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 18.7911844\n", + " ],\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,\n", + " 22.5196126, -44.92426, 0, 0, 0, 0, -78.1154748, 95.3654376, 0, 0, 0,\n", + " -42.4266782, 73.3850132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94.1878774,\n", + " 90.3854666, 0, 0, 0, 0, 0, -15.9053536, -74.9423846, 47.214, 0, 0,\n", + " 7.477562, 0, 46.2206928, 19.1508454, 41.6978146, 39.03286, 0, 0, 0, 0,\n", + " 0, -14.259302, 0, 54.0542232, 0, 0, 44.5438142\n", + " ],\n", + " [\n", + " 95.3632006, 43.6928354, 75.8291588, -81.2577418, 0, 0, -91.248437, 0, 0,\n", + " 22.476879, -77.967431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.0308978,\n", + " -22.0727056, 0, 0, 0, 0, 0, 0, 0, 17.126454, 0, -45.7583606, 0, 0,\n", + " 32.9187018, 0, 0, 0, 0, 0, -58.6847152, 0, 0, 39.113676, 0, 0, 0, 0, 0,\n", + " 0, -80.1176538, 0, -86.9570556, 0, 0, 0, -9.3462492, 0, 49.3616864, 0,\n", + " 60.4773586, 0, 0, 48.9766746, 17.5735282, 75.126033, 0, -50.8306992, 0,\n", + " 0, 61.3438194, 0, 0, -95.9051914, 0, 25.6497354\n", + " ],\n", + " [\n", + " -89.5581772, 0, 0, 0, 0, -37.7576814, 0, 0, 0, -50.475431, 0, 0, 0, 0,\n", + " -75.575654, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6.7066106, 0, 0, 0, 68.702018, 0,\n", + " 0, 44.2841378, 0, 0, 0, 0, 0, 0, 0, 42.4183476, 80.6872178, 72.028214,\n", + " 0, 0, 0, -50.6912368, 0, 0, 0, 53.1913708, 0, 0, 0, 0, -50.0798868, 0,\n", + " 0, 0, 0, 0, 0, -99.54189, 0, 0, 0, 0, 87.8828622, 7.144766, 0, 0, 0,\n", + " 71.8161494, 91.0414654, 0, 0, -7.240427\n", + " ],\n", + " [\n", + " 0, -73.397517, 0, 0, 0, 0, -42.4633614, 0, 0, 0, 0, -2.3988294,\n", + " -60.1970288, -31.1370786, -16.4428054, 0, -86.5694254, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, -33.759363, 0, 88.9440556, 0, 0, 0, 48.8687358, 0, 0, 60.1841648,\n", + " 0, 0, 81.5798018, 0, 0, 0, 0, 22.265044, 0, 0, 0, 0, -98.612946, 0, 0,\n", + " 0, -49.44052, 0, 46.9606012, 0, 0, 0, -23.7990468, 0, 0, 0, 0,\n", + " -72.1702852, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26.2623134, 0, -17.3386012\n", + " ],\n", + " [\n", + " 0, 16.4596174, 0, 0, 0, 0, -85.6599392, 0, 0, 0, 0, 0, 0, 93.708794, 0,\n", + " -37.5698758, 0, 0, 0, 0, 0, 0, -82.8927936, 0, 82.4183808, 0, 0, 0, 0,\n", + " 0, 0, 55.028266, 0, 0, 11.3484192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, -60.7651522, -4.822581, 0, 29.0627604, 0, 0, 61.7042716,\n", + " 41.5363722, 73.9967868, 0, 0, 0, 0, 50.2308124, 0, 33.8231702, 0, 0, 0,\n", + " 0, 0, -14.7226996, 14.5401778, 0, -72.8145596, 19.9220286, -76.4609286\n", + " ],\n", + " [\n", + " 11.1687196, 0, 0, 0, 0, 0, 0, 0, -37.365205, 0, 0, 0, 52.0314298, 0,\n", + " -58.0558462, 0, 0, 18.6738906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 59.6046802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -26.5944948, 0, 0, 0,\n", + " 77.0271992, 46.521059, 61.8258634, 0, 0, 36.079546, 0, -14.3080494, 0,\n", + " -50.1618478, 0, 0, 95.9445656, 0, 0, 0, 0, 0, 0, 0, 0, 0, -53.478982,\n", + " -90.3623976, 0, 0, -37.1575466\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 78.882051, 0, 0, 57.8056512, 7.2056626, 0,\n", + " 2.822132, 40.311822, 0, 0, 0, 83.8935006, 0, 0, 91.2774482, 3.160849,\n", + " 91.7410132, 0, 0, 0, 0, 0, 2.7544652, 0, 0, 0, 0, 0, 16.8419108, 0, 0,\n", + " 84.1171174, 0, 21.3119752, -69.869284, 0, 0, 0, 0, 0, 92.1087118, 0, 0,\n", + " 0, 0, 34.3473744, 21.9890278, 0, -36.3139526, 0, 0, 0, 0, 0, 25.613497,\n", + " -2.989159, 0, 0, 0, 0, -49.2456622, 0, 0, 27.3140788, 0, 49.210258, 0,\n", + " 0, -90.6896972\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, -56.1947046, 0, 0, 52.6617176, 61.6283016, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, -34.0759312, 0, 92.0200254, 0, 0, -9.7999914, 0, 0,\n", + " 34.0572616, 0, 0, 0, 0, 0, 59.7637334, 0, 0, 0, 0, 0, 43.5437732,\n", + " 29.9690024, 0, 0, 93.9438036, 0, 0, 0, 52.3867986, 0, 0, 0, 38.0567542,\n", + " 0, -63.9851954, 0, 73.1679634, 0, 0, -28.6636244, 0, 0, 0, 0, 0,\n", + " 39.2894916, 0, -28.4364668, 0, 0, 0, 0, 0, 0, 0, -32.2899456\n", + " ],\n", + " [\n", + " 15.3399588, 0, 0, 0, 0, 0, 0, -66.2540916, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 14.7613734, 0, 0, 0, -32.9550622, 0, 0, -17.2710502,\n", + " 0, 0, 0, -66.7611862, 76.5708962, 93.3868072, 12.036471, 0, 0, 0,\n", + " -74.2189184, 0, 0, 0, 0, 58.0343866, 0, 71.0145124, 0, 0, 0, 0, 0, 0, 0,\n", + " 80.7131208, 0, -49.5191686, 40.2489602, 0, 0, 39.9664558, 0, 0, 0, 0, 0,\n", + " 0, 51.704979, 0, 20.9209752, 0, 0, -63.5800814\n", + " ],\n", + " [\n", + " 0, 0, 35.1676872, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8.326191, 0, 0,\n", + " 0, -42.1405488, 0, 0, 0, 0, -64.9203894, 0, 0, 0, 86.5653072, 0,\n", + " 17.1250418, 0, 15.224998, -32.788739, 0, 0, 0, 13.1550612, 0, 0, 0,\n", + " 93.3049176, 65.5504482, 0, 35.8126186, -16.2474202, 0, -76.7788518,\n", + " -51.9001008, 0, -89.725966, 53.4895596, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -82.6077236, 0, 0, 0, -57.075872, -52.5166376, 99.9479554, 0, 0,\n", + " -89.7491862, 0, 18.6163306, 0, 29.1454254\n", + " ],\n", + " [\n", + " -18.8864514, 0, 0, 0, 0, 0, -46.6968628, -83.8123266, 0, 0, 0, 0, 0, 0,\n", + " -91.631792, 0, 0, 0, 0, -57.3455082, 66.459894, 0, 0, 0, -73.9341878, 0,\n", + " 0, 0, 81.8859882, 0, 0, 0, 0, 0, 28.0747908, 0, 0, 99.7796988, 0,\n", + " 87.0296656, 0, 0, 43.7722526, -60.65313, 98.6287198, 0, 20.8634118, 0,\n", + " 0, 25.6519386, 0.4939554, 0, 0, 0, 0, 0, 0, 0, 0, -74.9266526, 0, 0,\n", + " -25.4234142, 0, -91.054582, 0, -42.534282, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 12.1491094\n", + " ],\n", + " [\n", + " 0, -90.5331764, 0, 0, 0, 0, 0, -8.1166918, 0, 0, 0, 0, 0, -34.0013692,\n", + " 21.9272646, 0, 0, 0, 0, 0, 93.2245032, 0, 21.8275426, 0, 0, 0,\n", + " 38.5279608, -6.0022692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 39.644863, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -93.7962256, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 11.5363598, 70.354452, 0, 0, 0, 32.2282298, 0,\n", + " 36.659058, 0, 0, 53.992344\n", + " ],\n", + " [\n", + " -74.4430478, 0, 0, -93.4496218, 14.6437598, 0, 0, 0, -33.8297902, 0, 0,\n", + " 0, 0, 0, 0, -35.949213, 0, 0, -93.1678628, 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, -22.8806328, 0, 0, 0, 0, 0, 0, 0, 45.1466816, 88.4821604, 0, 0,\n", + " -49.7769388, 0, 0, 0, 0, 0, 0, 53.6290382, -40.4388272\n", + " ],\n", + " [\n", + " 71.2065308, 94.4966808, 0, 0, 0, 0, -84.2404402, 0, 0, 0, 0, 0,\n", + " 61.7641462, 0, 0, 0, -0.608018, -94.7698384, 0, 0, 0, 0, -3.4562834, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -26.0708126, -73.3657794,\n", + " 26.6482556, 0, 0, 0, 0, 0, 0, -66.9699546, -98.6726948, 0, 0,\n", + " -25.4137958, 0, -88.7254432, -81.2735544, 0, -23.3081526, 0,\n", + " -51.8917252, 0, 0, 0, 0, 0, 0, 0, 0, -52.3004828, 0, 0, 0, 0,\n", + " 67.8542398, 0, -67.7489638, 32.2212522\n", + " ],\n", + " [\n", + " 0, 77.0252092, 0, 0, 0, 0, 0, -85.3271924, 0, 0, 0, -2.9308596, 0,\n", + " 83.448547, 0, 4.7835886, 0, 0, 0, 0, 76.590577, 0, 0, 0, 0, 0,\n", + " 86.0180794, 0, 0, -88.4030016, 0, 0, 0, -13.770426, 57.6068646, 0, 0, 0,\n", + " 0, 0, 12.6896788, 0, 0, 0, -78.1078136, -92.3074796, 0, 0, 0, 0,\n", + " -94.3200626, 0, 0, -7.987837, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 52.7655986, 0, -78.2727176, 0, 74.4309632, 48.3867546, -85.4142468, 0,\n", + " 91.3888914, -6.0372808, 51.1643348\n", + " ],\n", + " [\n", + " -77.4193002, 0, 0, 0, 0, 0, 0, 0, 41.0846988, -78.3265056, 0, 0, 0, 0,\n", + " 0, 0, 0, -20.408123, 10.7055032, 0, -19.5848354, 0, -32.624054, 0,\n", + " 47.333306, 0, -41.6545398, 0, 0, 0, 0, 0, 46.8131656, 0, 52.5387768, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, -75.3511542, 0, 0, 0, 0, -27.6140242, 0, 0,\n", + " -63.3032372, 0, 0, 0, 0, 0, 0, 0, 0, -93.1854838, 0, 0, 0, 0,\n", + " 32.3353436, -75.8659438, 89.852816, 0, 9.7044216, 0, 94.9239572, 0,\n", + " -57.0391726, 25.4894998\n", + " ],\n", + " [\n", + " 0, 0, 0, -27.2226392, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -89.0780816,\n", + " 0, 0, 0, 0, 6.6342408, 0, 0, 92.3634346, -41.5559582, 0, 0, 0, 0, 0, 0,\n", + " -4.3499792, 18.9554522, 0, 29.992962, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -51.9952794, -40.3571344, 0, -61.0098328, 0, 0, 0, 0, 71.8571838,\n", + " 97.3056784, 0, 0, 27.798026, 0, 0, 20.3198544, 0, 0, 0, -82.1043534, 0,\n", + " 0, 0, 0, 0, 55.2807134, 0, 0, 0, 0, -90.8562594, -43.2271604\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 15.2015056, 18.3740448, -11.2614058, 0, 0, 0, 0, 0,\n", + " 53.0086248, 0, -91.038908, 0, 0, 88.2707986, 3.2580272, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 88.8189254, 0, 0, 0, 0, -3.742353, 0, 0, 0, -41.4198488,\n", + " 90.0966416, 0, -22.474875, 0, -25.610863, -79.5943706, 0, 0, 0, 0, 0, 0,\n", + " 0, -3.5616438, 0, 0, 0, 88.5984932, 0, 0, 0, 0, 0, 0, 0, 22.4398688, 0,\n", + " 0, 0, 0, 0, 0, 0, -63.7422676, 0, 0, 0, -82.7150752\n", + " ],\n", + " [\n", + " 0, 0, 75.634243, -60.420708, 0, 0, 0, 0.8383984, 0, 0, -72.2791914, 0,\n", + " 0, 0, 17.1476022, 0, 0, -14.5930276, 9.4352026, 0, -30.1475326, 0,\n", + " -53.7249052, 0, 19.3293368, 0, 0, 0, -80.867335, 0, -3.344608,\n", + " 71.3546388, -91.098817, 0, 0, 0, -26.83234, 0, 3.7009, 0, 0, 0, 0, 0,\n", + " 28.4006138, 0, 0, 57.1433046, 14.4086186, 0, 0, 0, 49.5828354, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 17.0012008, 0, 30.5581294, -98.7868224, 0, 0, 0,\n", + " 70.0467486, -9.4444084, 0, 19.9250998, 0, 0, -79.4970662\n", + " ],\n", + " [\n", + " 0, 54.0067274, 0, 0, 0, 37.9936634, 0, -20.1071476, -58.981429, 0, 0,\n", + " -83.9927614, 0, 0, 0, 0, 0, 0, -70.8571636, 0, 0, 68.4686496, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, -8.1687508, 0, 0, 16.6835288, -10.1286606, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 86.4747972, 0, -34.6316042, 0.9788672, 0, 0,\n", + " -41.4513542, 0, 0, 0, 0, 0, 0, 0, 0, -28.4021576, -74.9076708, 0,\n", + " -5.0425708, 0, 0, 0, 78.9139852, -50.7082204, 0, 34.0684852, 28.2502302\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 57.544994, 0, 0, -22.4411072, 0, -94.2568866,\n", + " -80.7849138, 0, 0, -10.0010618, 33.3160792, 0, 0, 0, 0, 0, 0,\n", + " -82.6811248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -11.0390072, 0, 0,\n", + " 32.0523166, 0, -80.6937396, 0, -94.2671164, 0, 0, -16.2170198, 0, 0, 0,\n", + " -5.7387768, 0, 0, 0, 0, -83.6048238, 0, 0, 0, 0, 0, 0, 33.6877392, 0,\n", + " -41.9784856, 0, 0, 0, -50.6512854, 0, 78.737702, 0, 0, 0, 0, 0,\n", + " 9.0618996\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, -94.8072128, 0, 21.9767716, 0, 0, 0, 57.7817378,\n", + " 35.3840102, 0, 0, 0, 60.4679182, -94.9978498, 0, -18.9377882,\n", + " -42.3270372, 0, 0, 0, 0, -3.9058912, 0, 0, 44.440235, 0, 0.41471, 0, 0,\n", + " -88.0148602, 53.9755254, 0, 0, 74.7772774, -19.633854, -66.6129164,\n", + " -25.4637816, -13.1642082, 0, 0, 0, 0, 57.6068044, 0, 0, -75.9060014,\n", + " 24.0447026, 0, 0, 29.9750648, 0, 0, 0, -54.938857, -4.4090126, 0, 0, 0,\n", + " 0, 0, 0, -57.1202194, 0, -11.130658, 0, 0, 95.6177756, -78.5403868, 0,\n", + " 0, 30.4589622, -93.6950296\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -50.308444, 0, 0, 0, 0, 0, 0, 0,\n", + " -20.3462364, 0, 0, 25.6081088, 0, 0, 0, 0, 0, 0, 90.9877902, 0,\n", + " -56.0922542, 99.2456868, 0, 45.4316172, 0, 70.1339288, -54.576692, 0, 0,\n", + " 0, -73.6910292, 0, 0, 0, 0, 0, 0, 38.6032202, 0, 0, 0, 60.7387286, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 95.207832, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 58.4721284\n", + " ],\n", + " [\n", + " 0.3163476, 0, 0, 13.0918568, 5.13089, 0, 40.7266308, 0, 0, 0, 0, 0,\n", + " -98.7077428, 0, 81.000503, 0, 0, 76.3945372, 0, 0, 0, 0, 0, 0,\n", + " -10.2289084, -70.592702, 0, 0, 0, 0, 0, 0, 69.59571, 0, 0, 0, 0, 0,\n", + " -61.4746908, 53.4041094, 0, 90.4397278, -33.1874988, 0, 0, 71.5512744,\n", + " 5.846105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56.7568638, 0, 0,\n", + " 66.7588344, 0, 0, 0, 99.284785, 0, 0, 0, 0, 0, 0, -99.2850048,\n", + " -85.4466004\n", + " ],\n", + " [\n", + " 0, 0, -34.544278, 0, 0, -36.135124, -33.4259354, 0, 0, -60.4256326, 0,\n", + " 44.7734168, 0, 0, 0, 0, -88.6744704, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -95.3752508, 4.596855, 85.2924422, 70.9081648, 22.0390844, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 1.6872456, 0, 0, 0, 0, 0, 0, 0, -37.4782422, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 4.7642096, 0, 0, -33.6313218, 0, 0, 72.977526, 0, 0, 0, 0,\n", + " 0, 0, 2.5063252, 0, 0, 0, 0, 0, -64.8677902\n", + " ],\n", + " [\n", + " 0, 0, 0, 3.718989, 0, 0, 49.3814782, 77.868826, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -49.7008846, 0, 4.696494, 0, 0, 0, 0, 0, 0, 0, -59.4928602, 0, 0, 0, 0,\n", + " 0, 82.6840644, -0.996624, -15.8014198, -93.098215, 0, 0, 41.2709314, 0,\n", + " -90.9633198, -56.911012, 0, 0, 0, 0, 0, 0, 0, 0, 0, -26.02585, 0, 0, 0,\n", + " 0, 0, 0, 61.2353938, 0, 0, 0, 0, 21.376448, 0, 0, 0, 0, 0, 0, 0,\n", + " 97.0578858, 0, 0, 0, 5.1265226\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -19.5643656, 0,\n", + " 0, -92.0307416, 0, 0, 0, 0, 55.003856, 0, 0, -20.4708104, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54.4588824, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, -57.0182252, 0, 0, -48.3222128, 0, 0, 0, -41.1121382, 0, 0, 0, 0, 0,\n", + " 0, -12.2773602, 0, -28.6924808, 50.0415338\n", + " ],\n", + " [\n", + " 0, 0, 0, -73.9719246, 0, 0, 0, 0, 0, 0, 0, 39.4110332, 0, 0,\n", + " -21.6757132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 74.8739354, 0, 0, -52.9210426, 0, 46.7750368, 63.6311858, 0, 0, 0, 0,\n", + " 25.5310902, 0, -3.0369126, 0, 32.5437816, 0, 0, 78.9107496, 32.0416448,\n", + " 0, 0, 15.9408846, 0, 0, 0, 0, -67.7582854, -52.6103086, 0, 0, 0, 0, 0,\n", + " 0, 11.8676176, 0, 0, -41.8820812, 43.608357, 0, 0, -64.3752572\n", + " ],\n", + " [\n", + " 0, -15.1648222, -57.5273074, -94.2919124, -3.0777222, -77.345826,\n", + " 91.2777856, 0, 0, 0, 0, 13.5044774, 0, 0, 0, 0, 0, 0, 0, 0, 33.5509618,\n", + " 0, 0, -33.291092, -60.3050638, 0, 0, 0, 94.610171, 0, 0, 0, 0, 0, 0,\n", + " -47.270154, -81.403122, 0, 0, 47.829269, 0, 0, 0, 0, -47.4699122, 0, 0,\n", + " -31.0161918, 0, 0, -54.993563, -9.6544012, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -17.0644648, 0, 0, 0, 0, 0, 0, 49.0555938, -82.4686508, 0, 0,\n", + " 97.7299292, 0, 0, -93.1718028\n", + " ],\n", + " [\n", + " 0, 0, 0, 45.5639954, 0, 0, 0, 0, 0, 92.3127826, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, -5.8746296, 22.9079182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 25.2727812, 0, 0, 0, 0, 0, 0, 65.0012614, 0, 67.4376806, 0, 0,\n", + " 14.0298002, 0, 0, 0, 0, 0, 33.432514, 43.000429, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 20.2757068, 4.0567932, 0, 0, -15.8737758, 0, 0, 0, 0, 29.8957398,\n", + " 50.0218946, 17.0262346\n", + " ],\n", + " [\n", + " 46.1658228, 19.630724, 0, 0, 0, 0, 0, 80.6073204, 24.5091878, 0, 0, 0,\n", + " 73.9258848, 0, 0, 0, -98.2044476, 0, 0, 0, 0, -59.2213968, 0,\n", + " -70.1450004, 0, 0, 0, 42.4721292, 0, -73.0346074, 0, 67.9829686, 0, 0,\n", + " 0, 0, 6.6597886, 39.7215082, 0, 0, 0, 52.505292, 95.9204336, 0, 0,\n", + " 5.8797776, 0, 0, 0, 36.0738246, 0, -15.2667614, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 50.963131, 0, 0, 0, 49.3354032, 13.7868492, 0, 77.3708062,\n", + " 26.0888548, 0, 0, 0, 0, -60.0881692, 24.2459968\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56.562023, 0, 0, 24.9145996, 0, 0, 0,\n", + " 0, 32.8196724, -75.8879774, -12.4005106, 0, 0, 0, 0, -18.824482,\n", + " -45.0330046, 0, 0, -47.5493022, 0, 0, 0, 8.1879572, 0, 0, 4.5700222,\n", + " -28.6731266, 0, 0, 0, 0, -83.2735948, 5.4624948, 0, 0, 0, 0, 0, 0, 0,\n", + " 83.664375, -52.8630198, 58.5805764, 0, 0, 0, 45.5781336, 0, 0,\n", + " -1.9768322, 0, 0, 0, 0, 91.1151128, 0, 0, 0, 0, 0, 0, -65.5158586, 0,\n", + " -22.12762\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 0, -50.8301006, 0, -57.183698, -24.666489, 43.0557936, 0, 0,\n", + " 0, -44.0812116, 0, 0, 0, 97.1670056, 0, 0, 0, 0, 83.4511366, 0,\n", + " -96.8912356, -6.1095452, 87.6643268, 0, 0, 0, -32.5223614, 0, 0, 0, 0,\n", + " -18.5596964, 0, 56.1790224, 0, 25.6035684, 0, 0, 0, 0, -46.8740154, 0,\n", + " 0, 0, 0, 0, 0, 0, -44.4329434, -34.719678, 85.6384822, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 48.9669952, 0, 0, 0, 0, 0, 0, 0, 0, 0, -28.2571694\n", + " ],\n", + " [\n", + " 0, 0, 0, 0, 42.1192158, 18.3800218, 0, 0, 33.4475094, 0, -39.4713432, 0,\n", + " 54.9744572, 0, -6.6305664, 79.0252374, 77.6908818, -61.5099746, 0, 0,\n", + " 38.4501814, 0, 0, -96.4250704, -27.809694, -34.9250884, 63.2997728, 0,\n", + " -98.8800042, 0, -7.682428, 0, 0, 0, 0, 0, 0, 7.7256608, 0, 48.5546152,\n", + " 0, 0, 0, 0, 0, 0, -58.963373, 0, 0, 0, 0, 0, 86.5062664, 7.0006556, 0,\n", + " 0, 0, 0, 0, 0, 3.1958572, 0, -46.2861844, 0, 0, 0, 0, 30.0710902,\n", + " 46.6948898, 0, 68.4681908, 0, 0, 0, 0, -51.3930766\n", + " ],\n", + " [\n", + " 7.1969236, 0, -79.6160432, -39.947334, -15.2636342, 0, 10.0645898,\n", + " -57.8968238, -31.9945476, 0, 91.5839662, -52.777566, 0, 0, 0, 0,\n", + " -40.9252974, 0, 0, 0, -45.5113982, 70.585349, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " -66.2523308, 0, 0, 0, 0, 0, 0, 0, 0, 85.7454324, -7.1148372, 0,\n", + " 93.6584844, 0, 0, 0, 0, 0, 0, -8.0414788, 0, 0, 0, 0, 51.3263388, 0, 0,\n", + " 79.892422, 0, 0, -64.6934098, 0, 0, -45.9577622, 0, 0, 0, -46.8290526,\n", + " 0, 48.2417506, 0, 0, 0, 0, -2.4115812, -50.7156922\n", + " ],\n", + " [\n", + " 62.9870494, -81.5584552, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53.7333104, 0,\n", + " 50.6438202, -57.7938262, 0, 0, 0, 0, -78.1108892, 0, 0, 0, 0, 0, 0, 0,\n", + " 87.6584692, 0, 58.2960112, -17.5355398, 12.0497204, -60.5414862, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 38.586472, -19.7940052, 94.423359, -89.557933, 0, 0,\n", + " -77.0715722, 0, -87.707166, 70.8585278, 0, 9.0616914, 91.333051, 0, 0,\n", + " 0, 5.8166112, 0, 24.7793442, -51.000038, 0, 0, 0, 0, 0, 0, 79.9657776,\n", + " 97.4969126, 0, 0, 0, 0, -73.8994394\n", + " ],\n", + " [\n", + " 10.133741, 0, 0, 0, 95.6910336, 0, 0, 0, 0, -22.6696236, 0, 0, 0, 0,\n", + " 15.137996, 35.7088464, 0, -16.1971956, 0, -29.4834358, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, 0, 0, 0, 0, -89.868739, 24.0040126, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 40.7292396, 35.7709458, 0, 34.690347, 22.3083532, 0, 0, 0, 0, 0,\n", + " -48.4224164, 0, 0, 0, 0, 91.7670744, 0, 0, 69.4045014, 0, 60.5937114,\n", + " -38.9993134, 0, 0, 0, 0, 0, 55.4599018, 0, 86.689944\n", + " ],\n", + " [\n", + " 0, 0, -24.842169, -52.997003, 0, 0, 0, 0, 0, 0, 0, 5.9075842, 0, 0,\n", + " -91.1447252, -5.3147106, 0, 0, 0, 4.4670454, 34.97343, 0, 0, 0, 0, 0, 0,\n", + " 0, 0, 0, 0, -5.3957052, 0, 0, 0, 0, -19.2118838, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 64.9559324, 0, 0, -10.0586402, 0, -74.8523334, 0, 0, 0, 0, 0, 0, 0, 0,\n", + " 0, 84.8495464, 0, 0, 0, 0, 0, 0, 33.0825986, 46.995148, 0, 0, 0,\n", + " -4.243203, 0, 0, -24.0124188\n", + " ]\n", + "]\n", + "\n", "\n", "def solve_qubo():\n", " \"\"\"Solve the Qubo problem.\"\"\"\n", @@ -649,7 +750,6 @@ " obj_vars.append(variables[i])\n", " obj_coeffs.append(self_coeff)\n", "\n", - "\n", " model.Minimize(\n", " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", "\n", @@ -657,11 +757,18 @@ " solver = cp_model.CpSolver()\n", " solver.parameters.num_search_workers = 16\n", " solver.parameters.log_search_progress = True\n", + " solver.parameters.max_time_in_seconds = 30\n", " solver.Solve(model)\n", "\n", "\n", - "solve_qubo()\n", - " \n" + "def main(argv: Sequence[str]) -> None:\n", + " if len(argv) > 1:\n", + " raise app.UsageError('Too many command-line arguments.')\n", + " solve_qubo()\n", + "\n", + "\n", + "main()\n", + "\n" ] } ], diff --git a/examples/notebook/examples/rcpsp_sat.ipynb b/examples/notebook/examples/rcpsp_sat.ipynb index 24dc7dfe2de..308613978ca 100644 --- a/examples/notebook/examples/rcpsp_sat.ipynb +++ b/examples/notebook/examples/rcpsp_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/shift_scheduling_sat.ipynb b/examples/notebook/examples/shift_scheduling_sat.ipynb index 45fed71ad6a..95ae9d09689 100644 --- a/examples/notebook/examples/shift_scheduling_sat.ipynb +++ b/examples/notebook/examples/shift_scheduling_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/single_machine_scheduling_with_setup_release_due_dates_sat.ipynb b/examples/notebook/examples/single_machine_scheduling_with_setup_release_due_dates_sat.ipynb index 684b1ac9ad6..ffb383ab653 100644 --- a/examples/notebook/examples/single_machine_scheduling_with_setup_release_due_dates_sat.ipynb +++ b/examples/notebook/examples/single_machine_scheduling_with_setup_release_due_dates_sat.ipynb @@ -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", + "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(PARSER.parse_args())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/spread_robots_sat.ipynb b/examples/notebook/examples/spread_robots_sat.ipynb new file mode 100644 index 00000000000..0d72c04ddec --- /dev/null +++ b/examples/notebook/examples/spread_robots_sat.ipynb @@ -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": [ + "\n", + "\n", + "\n", + "
\n", + "Run in Google Colab\n", + "\n", + "View source on GitHub\n", + "
" + ] + }, + { + "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 +} diff --git a/examples/notebook/examples/steel_mill_slab_sat.ipynb b/examples/notebook/examples/steel_mill_slab_sat.ipynb index e0cf38eaddc..677a8f92637 100644 --- a/examples/notebook/examples/steel_mill_slab_sat.ipynb +++ b/examples/notebook/examples/steel_mill_slab_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/task_allocation_sat.ipynb b/examples/notebook/examples/task_allocation_sat.ipynb index 683a231134c..986dfe664da 100644 --- a/examples/notebook/examples/task_allocation_sat.ipynb +++ b/examples/notebook/examples/task_allocation_sat.ipynb @@ -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" ] diff --git a/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb b/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb index dfa33c0df61..d6946484e92 100644 --- a/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb +++ b/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb @@ -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" ] } diff --git a/examples/notebook/examples/tsp_sat.ipynb b/examples/notebook/examples/tsp_sat.ipynb index a1f47e1b6ef..dfcae4ed6ab 100644 --- a/examples/notebook/examples/tsp_sat.ipynb +++ b/examples/notebook/examples/tsp_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/vendor_scheduling_sat.ipynb b/examples/notebook/examples/vendor_scheduling_sat.ipynb index a6f0c1e1606..c28f0184472 100644 --- a/examples/notebook/examples/vendor_scheduling_sat.ipynb +++ b/examples/notebook/examples/vendor_scheduling_sat.ipynb @@ -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", diff --git a/examples/notebook/examples/wedding_optimal_chart_sat.ipynb b/examples/notebook/examples/wedding_optimal_chart_sat.ipynb index e46e0e139ad..fa4db04dd9e 100644 --- a/examples/notebook/examples/wedding_optimal_chart_sat.ipynb +++ b/examples/notebook/examples/wedding_optimal_chart_sat.ipynb @@ -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" ] } diff --git a/examples/notebook/examples/weighted_latency_problem_sat.ipynb b/examples/notebook/examples/weighted_latency_problem_sat.ipynb new file mode 100644 index 00000000000..0c131d27128 --- /dev/null +++ b/examples/notebook/examples/weighted_latency_problem_sat.ipynb @@ -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": [ + "\n", + "\n", + "\n", + "
\n", + "Run in Google Colab\n", + "\n", + "View source on GitHub\n", + "
" + ] + }, + { + "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 +} diff --git a/examples/notebook/examples/worker_schedule_sat.ipynb b/examples/notebook/examples/worker_schedule_sat.ipynb deleted file mode 100644 index f13cea61bf8..00000000000 --- a/examples/notebook/examples/worker_schedule_sat.ipynb +++ /dev/null @@ -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": [ - "\n", - "\n", - "\n", - "
\n", - "Run in Google Colab\n", - "\n", - "View source on GitHub\n", - "
" - ] - }, - { - "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 -} diff --git a/examples/notebook/linear_solver/assignment_mb.ipynb b/examples/notebook/linear_solver/assignment_mb.ipynb index 9260147b1b6..354c45a4375 100644 --- a/examples/notebook/linear_solver/assignment_mb.ipynb +++ b/examples/notebook/linear_solver/assignment_mb.ipynb @@ -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", diff --git a/examples/notebook/linear_solver/bin_packing_mb.ipynb b/examples/notebook/linear_solver/bin_packing_mb.ipynb index f1942d1034b..b993b3acb24 100644 --- a/examples/notebook/linear_solver/bin_packing_mb.ipynb +++ b/examples/notebook/linear_solver/bin_packing_mb.ipynb @@ -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", diff --git a/examples/notebook/sat/boolean_product_sample_sat.ipynb b/examples/notebook/sat/boolean_product_sample_sat.ipynb index 377e2381378..85b7b73b1f1 100644 --- a/examples/notebook/sat/boolean_product_sample_sat.ipynb +++ b/examples/notebook/sat/boolean_product_sample_sat.ipynb @@ -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", diff --git a/examples/notebook/sat/non_linear_sat.ipynb b/examples/notebook/sat/non_linear_sat.ipynb index e156b6547fa..68ed4f838f8 100644 --- a/examples/notebook/sat/non_linear_sat.ipynb +++ b/examples/notebook/sat/non_linear_sat.ipynb @@ -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" ] }