diff --git a/examples/notebook/algorithms/knapsack.ipynb b/examples/notebook/algorithms/knapsack.ipynb index 80dc92ae26..76e1a70980 100644 --- a/examples/notebook/algorithms/knapsack.ipynb +++ b/examples/notebook/algorithms/knapsack.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "A simple knapsack problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,67 +82,46 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"A simple knapsack problem.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.algorithms import pywrapknapsack_solver\n", - "# [END import]\n", "\n", "\n", - "# Create the solver.\n", - "# [START solver]\n", - "solver = pywrapknapsack_solver.KnapsackSolver(\n", - " pywrapknapsack_solver.KnapsackSolver.\n", - " KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, 'KnapsackExample')\n", - "# [END solver]\n", + "def main():\n", + " # Create the solver.\n", + " solver = pywrapknapsack_solver.KnapsackSolver(\n", + " pywrapknapsack_solver.KnapsackSolver.\n", + " KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, 'KnapsackExample')\n", "\n", - "# [START data]\n", - "values = [\n", - " 360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, 38, 48, 147,\n", - " 78, 256, 63, 17, 120, 164, 432, 35, 92, 110, 22, 42, 50, 323, 514, 28,\n", - " 87, 73, 78, 15, 26, 78, 210, 36, 85, 189, 274, 43, 33, 10, 19, 389, 276,\n", - " 312\n", - "]\n", - "weights = [[\n", - " 7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, 42, 9, 0,\n", - " 42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, 7, 29, 93, 44, 71,\n", - " 3, 86, 66, 31, 65, 0, 79, 20, 65, 52, 13\n", - "]]\n", - "capacities = [850]\n", - "# [END data]\n", + " values = [\n", + " 360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, 38, 48, 147,\n", + " 78, 256, 63, 17, 120, 164, 432, 35, 92, 110, 22, 42, 50, 323, 514, 28,\n", + " 87, 73, 78, 15, 26, 78, 210, 36, 85, 189, 274, 43, 33, 10, 19, 389, 276,\n", + " 312\n", + " ]\n", + " weights = [[\n", + " 7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, 42, 9, 0,\n", + " 42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, 7, 29, 93, 44, 71,\n", + " 3, 86, 66, 31, 65, 0, 79, 20, 65, 52, 13\n", + " ]]\n", + " capacities = [850]\n", "\n", - "# [START solve]\n", - "solver.Init(values, weights, capacities)\n", - "computed_value = solver.Solve()\n", - "# [END solve]\n", + " solver.Init(values, weights, capacities)\n", + " computed_value = solver.Solve()\n", "\n", - "# [START print_solution]\n", - "packed_items = []\n", - "packed_weights = []\n", - "total_weight = 0\n", - "print('Total value =', computed_value)\n", - "for i in range(len(values)):\n", - " if solver.BestSolutionContains(i):\n", - " packed_items.append(i)\n", - " packed_weights.append(weights[0][i])\n", - " total_weight += weights[0][i]\n", - "print('Total weight:', total_weight)\n", - "print('Packed items:', packed_items)\n", - "print('Packed_weights:', packed_weights)\n", - "# [END print_solution]\n", + " packed_items = []\n", + " packed_weights = []\n", + " total_weight = 0\n", + " print('Total value =', computed_value)\n", + " for i in range(len(values)):\n", + " if solver.BestSolutionContains(i):\n", + " packed_items.append(i)\n", + " packed_weights.append(weights[0][i])\n", + " total_weight += weights[0][i]\n", + " print('Total weight:', total_weight)\n", + " print('Packed items:', packed_items)\n", + " print('Packed_weights:', packed_weights)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/algorithms/simple_knapsack_program.ipynb b/examples/notebook/algorithms/simple_knapsack_program.ipynb index df73119d23..de7cf21d02 100644 --- a/examples/notebook/algorithms/simple_knapsack_program.ipynb +++ b/examples/notebook/algorithms/simple_knapsack_program.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "A simple knapsack problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,57 +82,36 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"A simple knapsack problem.\"\"\"\n", - "# [START import]\n", "from ortools.algorithms import pywrapknapsack_solver\n", - "# [END import]\n", "\n", "\n", - "# Create the solver.\n", - "# [START solver]\n", - "solver = pywrapknapsack_solver.KnapsackSolver(\n", - " pywrapknapsack_solver.KnapsackSolver.\n", - " KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER, \"test\")\n", - "# [END solver]\n", + "def main():\n", + " # Create the solver.\n", + " solver = pywrapknapsack_solver.KnapsackSolver(\n", + " pywrapknapsack_solver.KnapsackSolver.\n", + " KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER, \"test\")\n", "\n", - "# [START data]\n", - "weights = [[\n", - " 565, 406, 194, 130, 435, 367, 230, 315, 393, 125, 670, 892, 600, 293,\n", - " 712, 147, 421, 255\n", - "]]\n", - "capacities = [850]\n", - "values = weights[0]\n", - "# [END data]\n", + " weights = [[\n", + " 565, 406, 194, 130, 435, 367, 230, 315, 393, 125, 670, 892, 600, 293,\n", + " 712, 147, 421, 255\n", + " ]]\n", + " capacities = [850]\n", + " values = weights[0]\n", "\n", - "# [START solve]\n", - "solver.Init(values, weights, capacities)\n", - "computed_value = solver.Solve()\n", - "# [END solve]\n", + " solver.Init(values, weights, capacities)\n", + " computed_value = solver.Solve()\n", "\n", - "# [START print_solution]\n", - "packed_items = [\n", - " x for x in range(0, len(weights[0])) if solver.BestSolutionContains(x)\n", - "]\n", - "packed_weights = [weights[0][i] for i in packed_items]\n", + " packed_items = [\n", + " x for x in range(0, len(weights[0])) if solver.BestSolutionContains(x)\n", + " ]\n", + " packed_weights = [weights[0][i] for i in packed_items]\n", "\n", - "print(\"Packed items: \", packed_items)\n", - "print(\"Packed weights: \", packed_weights)\n", - "print(\"Total weight (same as total value): \", computed_value)\n", - "# [END print_solution]\n", + " print(\"Packed items: \", packed_items)\n", + " print(\"Packed weights: \", packed_weights)\n", + " print(\"Total weight (same as total value): \", computed_value)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/cp_is_fun_cp.ipynb b/examples/notebook/constraint_solver/cp_is_fun_cp.ipynb index 27b36dcb3f..ae4c0d1fa5 100644 --- a/examples/notebook/constraint_solver/cp_is_fun_cp.ipynb +++ b/examples/notebook/constraint_solver/cp_is_fun_cp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,19 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Cryptarithmetic puzzle.\n", + "\n", + "First attempt to solve equation CP + IS + FUN = TRUE\n", + "where each letter represents a unique digit.\n", + "\n", + "This problem has 72 different solutions in base 10.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,85 +87,58 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Cryptarithmetic puzzle.\n", - "\n", - "First attempt to solve equation CP + IS + FUN = TRUE\n", - "where each letter represents a unique digit.\n", - "\n", - "This problem has 72 different solutions in base 10.\n", - "\"\"\"\n", - "# [START import]\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# Constraint programming engine\n", - "# [START solver]\n", - "solver = pywrapcp.Solver('CP is fun!')\n", - "# [END solver]\n", + "def main():\n", + " # Constraint programming engine\n", + " solver = pywrapcp.Solver('CP is fun!')\n", "\n", - "# [START variables]\n", - "base = 10\n", + " base = 10\n", "\n", - "# Decision variables.\n", - "digits = list(range(0, base))\n", - "digits_without_zero = list(range(1, base))\n", - "c = solver.IntVar(digits_without_zero, 'C')\n", - "p = solver.IntVar(digits, 'P')\n", - "i = solver.IntVar(digits_without_zero, 'I')\n", - "s = solver.IntVar(digits, 'S')\n", - "f = solver.IntVar(digits_without_zero, 'F')\n", - "u = solver.IntVar(digits, 'U')\n", - "n = solver.IntVar(digits, 'N')\n", - "t = solver.IntVar(digits_without_zero, 'T')\n", - "r = solver.IntVar(digits, 'R')\n", - "e = solver.IntVar(digits, 'E')\n", + " # Decision variables.\n", + " digits = list(range(0, base))\n", + " digits_without_zero = list(range(1, base))\n", + " c = solver.IntVar(digits_without_zero, 'C')\n", + " p = solver.IntVar(digits, 'P')\n", + " i = solver.IntVar(digits_without_zero, 'I')\n", + " s = solver.IntVar(digits, 'S')\n", + " f = solver.IntVar(digits_without_zero, 'F')\n", + " u = solver.IntVar(digits, 'U')\n", + " n = solver.IntVar(digits, 'N')\n", + " t = solver.IntVar(digits_without_zero, 'T')\n", + " r = solver.IntVar(digits, 'R')\n", + " e = solver.IntVar(digits, 'E')\n", "\n", - "# We need to group variables in a list to use the constraint AllDifferent.\n", - "letters = [c, p, i, s, f, u, n, t, r, e]\n", + " # We need to group variables in a list to use the constraint AllDifferent.\n", + " letters = [c, p, i, s, f, u, n, t, r, e]\n", "\n", - "# Verify that we have enough digits.\n", - "assert base >= len(letters)\n", - "# [END variables]\n", + " # Verify that we have enough digits.\n", + " assert base >= len(letters)\n", "\n", - "# Define constraints.\n", - "# [START constraints]\n", - "solver.Add(solver.AllDifferent(letters))\n", + " # Define constraints.\n", + " solver.Add(solver.AllDifferent(letters))\n", "\n", - "# CP + IS + FUN = TRUE\n", - "solver.Add(p + s + n + base * (c + i + u) + base * base * f == e +\n", - " base * u + base * base * r + base * base * base * t)\n", - "# [END constraints]\n", + " # CP + IS + FUN = TRUE\n", + " solver.Add(p + s + n + base * (c + i + u) + base * base * f == e +\n", + " base * u + base * base * r + base * base * base * t)\n", "\n", - "# [START solve]\n", - "solution_count = 0\n", - "db = solver.Phase(letters, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "solver.NewSearch(db)\n", - "while solver.NextSolution():\n", - " print(letters)\n", - " # Is CP + IS + FUN = TRUE?\n", - " assert (base * c.Value() + p.Value() + base * i.Value() + s.Value() +\n", - " base * base * f.Value() + base * u.Value() +\n", - " n.Value() == base * base * base * t.Value() +\n", - " base * base * r.Value() + base * u.Value() + e.Value())\n", - " solution_count += 1\n", - "solver.EndSearch()\n", - "print(f'Number of solutions found: {solution_count}')\n", - "# [END solve]\n", + " solution_count = 0\n", + " db = solver.Phase(letters, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + " solver.NewSearch(db)\n", + " while solver.NextSolution():\n", + " print(letters)\n", + " # Is CP + IS + FUN = TRUE?\n", + " assert (base * c.Value() + p.Value() + base * i.Value() + s.Value() +\n", + " base * base * f.Value() + base * u.Value() +\n", + " n.Value() == base * base * base * t.Value() +\n", + " base * base * r.Value() + base * u.Value() + e.Value())\n", + " solution_count += 1\n", + " solver.EndSearch()\n", + " print(f'Number of solutions found: {solution_count}')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/cvrp.ipynb b/examples/notebook/constraint_solver/cvrp.ipynb index 8ef5cacc8a..739a1d2aa4 100644 --- a/examples/notebook/constraint_solver/cvrp.ipynb +++ b/examples/notebook/constraint_solver/cvrp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,28 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# This Python file uses the following encoding: utf-8\n", - "# Copyright 2015 Tin Arm Engineering AB\n", - "# Copyright 2018 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", - "\"\"\"Capacitated Vehicle Routing Problem (CVRP).\n", + "Capacitated Vehicle Routing Problem (CVRP).\n", "\n", " This is a sample using the routing library python wrapper to solve a CVRP\n", " problem.\n", @@ -97,9 +80,17 @@ " http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n", "\n", " Distances are in meters.\n", - "\"\"\"\n", - "\n", "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from functools import partial\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -234,38 +225,42 @@ "########\n", "# Main #\n", "########\n", - "\"\"\"Entry point of the program\"\"\"\n", - "# Instantiate the data problem.\n", - "data = create_data_model()\n", + "def main():\n", + " \"\"\"Entry point of the program\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager\n", - "manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n", - " data['num_vehicles'], data['depot'])\n", + " # Create the routing index manager\n", + " manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Define weight of each edge\n", - "distance_evaluator = routing.RegisterTransitCallback(\n", - " partial(create_distance_evaluator(data), manager))\n", - "routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator)\n", + " # Define weight of each edge\n", + " distance_evaluator = routing.RegisterTransitCallback(\n", + " partial(create_distance_evaluator(data), manager))\n", + " routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator)\n", "\n", - "# Add Capacity constraint\n", - "demand_evaluator_index = routing.RegisterUnaryTransitCallback(\n", - " partial(create_demand_evaluator(data), manager))\n", - "add_capacity_constraints(routing, data, demand_evaluator_index)\n", + " # Add Capacity constraint\n", + " demand_evaluator_index = routing.RegisterUnaryTransitCallback(\n", + " partial(create_demand_evaluator(data), manager))\n", + " add_capacity_constraints(routing, data, demand_evaluator_index)\n", "\n", - "# Setting first solution heuristic (cheapest addition).\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(1)\n", + " # Setting first solution heuristic (cheapest addition).\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(1)\n", "\n", - "# Solve the problem.\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", - "print_solution(data, routing, manager, assignment)\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", + " print_solution(data, routing, manager, assignment)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/cvrp_reload.ipynb b/examples/notebook/constraint_solver/cvrp_reload.ipynb index e58a98e926..80e2e1682e 100644 --- a/examples/notebook/constraint_solver/cvrp_reload.ipynb +++ b/examples/notebook/constraint_solver/cvrp_reload.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,28 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# This Python file uses the following encoding: utf-8\n", - "# Copyright 2015 Tin Arm Engineering AB\n", - "# Copyright 2018 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", - "\"\"\"Capacitated Vehicle Routing Problem (CVRP).\n", + "Capacitated Vehicle Routing Problem (CVRP).\n", "\n", " This is a sample using the routing library python wrapper to solve a CVRP\n", " problem while allowing multiple trips, i.e., vehicles can return to a depot\n", @@ -116,9 +99,17 @@ " new nodes introduced, to avoid schedules having spurious transits through\n", " those new nodes unless it's necessary to reload. This consideration is taken\n", " into account in `create_distance_evaluator()`.\n", - "\"\"\"\n", - "\n", "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from functools import partial\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -415,49 +406,53 @@ "########\n", "# Main #\n", "########\n", - "\"\"\"Entry point of the program\"\"\"\n", - "# Instantiate the data problem.\n", - "data = create_data_model()\n", + "def main():\n", + " \"\"\"Entry point of the program\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager\n", - "manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n", - " data['num_vehicles'], data['depot'])\n", + " # Create the routing index manager\n", + " manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Define weight of each edge\n", - "distance_evaluator_index = routing.RegisterTransitCallback(\n", - " partial(create_distance_evaluator(data), manager))\n", - "routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n", + " # Define weight of each edge\n", + " distance_evaluator_index = routing.RegisterTransitCallback(\n", + " partial(create_distance_evaluator(data), manager))\n", + " routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n", "\n", - "# Add Distance constraint to minimize the longuest route\n", - "add_distance_dimension(routing, manager, data, distance_evaluator_index)\n", + " # Add Distance constraint to minimize the longuest route\n", + " add_distance_dimension(routing, manager, data, distance_evaluator_index)\n", "\n", - "# Add Capacity constraint\n", - "demand_evaluator_index = routing.RegisterUnaryTransitCallback(\n", - " partial(create_demand_evaluator(data), manager))\n", - "add_capacity_constraints(routing, manager, data, demand_evaluator_index)\n", + " # Add Capacity constraint\n", + " demand_evaluator_index = routing.RegisterUnaryTransitCallback(\n", + " partial(create_demand_evaluator(data), manager))\n", + " add_capacity_constraints(routing, manager, data, demand_evaluator_index)\n", "\n", - "# Add Time Window constraint\n", - "time_evaluator_index = routing.RegisterTransitCallback(\n", - " partial(create_time_evaluator(data), manager))\n", - "add_time_window_constraints(routing, manager, data, time_evaluator_index)\n", + " # Add Time Window constraint\n", + " time_evaluator_index = routing.RegisterTransitCallback(\n", + " partial(create_time_evaluator(data), manager))\n", + " add_time_window_constraints(routing, manager, data, time_evaluator_index)\n", "\n", - "# Setting first solution heuristic (cheapest addition).\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(3)\n", + " # Setting first solution heuristic (cheapest addition).\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(3)\n", "\n", - "# Solve the problem.\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "else:\n", - " print(\"No solution found !\")\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + " else:\n", + " print(\"No solution found !\")\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/cvrptw.ipynb b/examples/notebook/constraint_solver/cvrptw.ipynb index fac014b931..ba2e1ce342 100644 --- a/examples/notebook/constraint_solver/cvrptw.ipynb +++ b/examples/notebook/constraint_solver/cvrptw.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,29 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# This Python file uses the following encoding: utf-8\n", - "# Copyright 2015 Tin Arm Engineering AB\n", - "# Copyright 2018 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", - "# [START program]\n", - "\"\"\"Capacitated Vehicle Routing Problem with Time Windows (CVRPTW).\n", + "Capacitated Vehicle Routing Problem with Time Windows (CVRPTW).\n", "\n", " This is a sample using the routing library python wrapper to solve a CVRPTW\n", " problem.\n", @@ -98,16 +80,21 @@ " http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n", "\n", " Distances are in meters and time in minutes.\n", - "\"\"\"\n", - "\n", - "# [START import]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from functools import partial\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -154,7 +141,6 @@ " data['vehicle_speed'] = 83 # Travel speed: 5km/h converted in m/min\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", "#######################\n", @@ -275,7 +261,6 @@ " #routing.AddToAssignment(time_dimension.SlackVar(self.routing.End(vehicle_id)))\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, assignment): # pylint:disable=too-many-locals\n", " \"\"\"Prints assignment on console\"\"\"\n", " print(f'Objective: {assignment.ObjectiveValue()}')\n", @@ -321,74 +306,57 @@ " print('Total Distance of all routes: {0}m'.format(total_distance))\n", " print('Total Load of all routes: {}'.format(total_load))\n", " print('Total Time of all routes: {0}min'.format(total_time))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the Capacitated VRP with time windows.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the Capacitated VRP with time windows.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", - "# [END routing_model]\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Define weight of each edge.\n", - "# [START transit_callback]\n", - "distance_evaluator_index = routing.RegisterTransitCallback(\n", - " partial(create_distance_evaluator(data), manager))\n", - "# [END transit_callback]\n", + " # Define weight of each edge.\n", + " distance_evaluator_index = routing.RegisterTransitCallback(\n", + " partial(create_distance_evaluator(data), manager))\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n", "\n", - "# Add Capacity constraint.\n", - "# [START capacity_constraint]\n", - "demand_evaluator_index = routing.RegisterUnaryTransitCallback(\n", - " partial(create_demand_evaluator(data), manager))\n", - "add_capacity_constraints(routing, data, demand_evaluator_index)\n", - "# [END capacity_constraint]\n", + " # Add Capacity constraint.\n", + " demand_evaluator_index = routing.RegisterUnaryTransitCallback(\n", + " partial(create_demand_evaluator(data), manager))\n", + " add_capacity_constraints(routing, data, demand_evaluator_index)\n", "\n", - "# Add Time Window constraint.\n", - "# [START time_constraint]\n", - "time_evaluator_index = routing.RegisterTransitCallback(\n", - " partial(create_time_evaluator(data), manager))\n", - "add_time_window_constraints(routing, manager, data, time_evaluator_index)\n", - "# [END time_constraint]\n", + " # Add Time Window constraint.\n", + " time_evaluator_index = routing.RegisterTransitCallback(\n", + " partial(create_time_evaluator(data), manager))\n", + " add_time_window_constraints(routing, manager, data, time_evaluator_index)\n", "\n", - "# Setting first solution heuristic (cheapest addition).\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(2)\n", - "search_parameters.log_search = True\n", - "# [END parameters]\n", + " # Setting first solution heuristic (cheapest addition).\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(2)\n", + " search_parameters.log_search = True\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(manager, routing, solution)\n", - "else:\n", - " print('No solution found!')\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(manager, routing, solution)\n", + " else:\n", + " print('No solution found!')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/cvrptw_break.ipynb b/examples/notebook/constraint_solver/cvrptw_break.ipynb index 711be7ff9c..a6e1fefa08 100644 --- a/examples/notebook/constraint_solver/cvrptw_break.ipynb +++ b/examples/notebook/constraint_solver/cvrptw_break.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,27 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Capacitated Vehicle Routing Problem with Time Windows (CVRPTW).\n", + "Capacitated Vehicle Routing Problem with Time Windows (CVRPTW).\n", "\n", " This is a sample using the routing library python wrapper to solve a CVRPTW\n", " problem.\n", @@ -96,16 +80,21 @@ " http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n", "\n", " Distances are in meters and time in minutes.\n", - "\"\"\"\n", - "\n", - "# [START import]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import functools\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -153,7 +142,6 @@ " data['vehicle_speed'] = 83 # Travel speed: 5km/h converted in m/min\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", "def manhattan_distance(position_1, position_2):\n", @@ -274,7 +262,6 @@ " # be added to the assignment.\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, assignment): # pylint:disable=too-many-locals\n", " \"\"\"Prints assignment on console.\"\"\"\n", " print('Objective: {}'.format(assignment.ObjectiveValue()))\n", @@ -328,75 +315,70 @@ " print('Total Distance of all routes: {0}m'.format(total_distance))\n", " print('Total Load of all routes: {}'.format(total_load))\n", " print('Total Time of all routes: {0}min'.format(total_time))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager\n", - "manager = pywrapcp.RoutingIndexManager(data['numlocations_'],\n", - " data['num_vehicles'], data['depot'])\n", + " # Create the routing index manager\n", + " manager = pywrapcp.RoutingIndexManager(data['numlocations_'],\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Define weight of each edge\n", - "distance_evaluator_index = routing.RegisterTransitCallback(\n", - " functools.partial(create_distance_evaluator(data), manager))\n", - "routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n", + " # Define weight of each edge\n", + " distance_evaluator_index = routing.RegisterTransitCallback(\n", + " functools.partial(create_distance_evaluator(data), manager))\n", + " routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n", "\n", - "# Add Capacity constraint\n", - "demand_evaluator_index = routing.RegisterUnaryTransitCallback(\n", - " functools.partial(create_demand_evaluator(data), manager))\n", - "add_capacity_constraints(routing, data, demand_evaluator_index)\n", + " # Add Capacity constraint\n", + " demand_evaluator_index = routing.RegisterUnaryTransitCallback(\n", + " functools.partial(create_demand_evaluator(data), manager))\n", + " add_capacity_constraints(routing, data, demand_evaluator_index)\n", "\n", - "# Add Time Window constraint\n", - "time_evaluator_index = routing.RegisterTransitCallback(\n", - " functools.partial(create_time_evaluator(data), manager))\n", - "add_time_window_constraints(routing, manager, data, time_evaluator_index)\n", + " # Add Time Window constraint\n", + " time_evaluator_index = routing.RegisterTransitCallback(\n", + " functools.partial(create_time_evaluator(data), manager))\n", + " add_time_window_constraints(routing, manager, data, time_evaluator_index)\n", "\n", - "# Add breaks\n", - "time_dimension = routing.GetDimensionOrDie('Time')\n", - "node_visit_transit = {}\n", - "for index in range(routing.Size()):\n", - " node = manager.IndexToNode(index)\n", - " node_visit_transit[index] = int(data['demands'][node] *\n", - " data['time_per_demand_unit'])\n", + " # Add breaks\n", + " time_dimension = routing.GetDimensionOrDie('Time')\n", + " node_visit_transit = {}\n", + " for index in range(routing.Size()):\n", + " node = manager.IndexToNode(index)\n", + " node_visit_transit[index] = int(data['demands'][node] *\n", + " data['time_per_demand_unit'])\n", "\n", - "break_intervals = {}\n", - "for v in range(data['num_vehicles']):\n", - " vehicle_break = data['breaks'][v]\n", - " break_intervals[v] = [\n", - " routing.solver().FixedDurationIntervalVar(15, 100, vehicle_break[0],\n", - " vehicle_break[1],\n", - " f'Break for vehicle {v}')\n", - " ]\n", - " time_dimension.SetBreakIntervalsOfVehicle(break_intervals[v], v,\n", - " node_visit_transit.values())\n", + " break_intervals = {}\n", + " for v in range(data['num_vehicles']):\n", + " vehicle_break = data['breaks'][v]\n", + " break_intervals[v] = [\n", + " routing.solver().FixedDurationIntervalVar(15, 100, vehicle_break[0],\n", + " vehicle_break[1],\n", + " f'Break for vehicle {v}')\n", + " ]\n", + " time_dimension.SetBreakIntervalsOfVehicle(break_intervals[v], v,\n", + " node_visit_transit.values())\n", "\n", - "# Setting first solution heuristic (cheapest addition).\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n", - "# [END parameters]\n", + " # Setting first solution heuristic (cheapest addition).\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if assignment:\n", - " print_solution(data, manager, routing, assignment)\n", - "else:\n", - " print('No solution found!')\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if assignment:\n", + " print_solution(data, manager, routing, assignment)\n", + " else:\n", + " print('No solution found!')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/nqueens_cp.ipynb b/examples/notebook/constraint_solver/nqueens_cp.ipynb index ee7e6e8679..a7a4401b85 100644 --- a/examples/notebook/constraint_solver/nqueens_cp.ipynb +++ b/examples/notebook/constraint_solver/nqueens_cp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "OR-Tools solution to the N-queens problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,82 +82,61 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"OR-Tools solution to the N-queens problem.\"\"\"\n", - "# [START import]\n", "import sys\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# Creates the solver.\n", - "# [START solver]\n", - "solver = pywrapcp.Solver('n-queens')\n", - "# [END solver]\n", + "def main(board_size):\n", + " # Creates the solver.\n", + " solver = pywrapcp.Solver('n-queens')\n", "\n", - "# Creates the variables.\n", - "# [START variables]\n", - "# The array index is the column, and the value is the row.\n", - "queens = [\n", - " solver.IntVar(0, board_size - 1, f'x{i}') for i in range(board_size)\n", - "]\n", - "# [END variables]\n", + " # Creates the variables.\n", + " # The array index is the column, and the value is the row.\n", + " queens = [\n", + " solver.IntVar(0, board_size - 1, f'x{i}') for i in range(board_size)\n", + " ]\n", "\n", - "# Creates the constraints.\n", - "# [START constraints]\n", - "# All rows must be different.\n", - "solver.Add(solver.AllDifferent(queens))\n", + " # Creates the constraints.\n", + " # All rows must be different.\n", + " solver.Add(solver.AllDifferent(queens))\n", "\n", - "# No two queens can be on the same diagonal.\n", - "solver.Add(solver.AllDifferent([queens[i] + i for i in range(board_size)]))\n", - "solver.Add(solver.AllDifferent([queens[i] - i for i in range(board_size)]))\n", - "# [END constraints]\n", + " # No two queens can be on the same diagonal.\n", + " solver.Add(solver.AllDifferent([queens[i] + i for i in range(board_size)]))\n", + " solver.Add(solver.AllDifferent([queens[i] - i for i in range(board_size)]))\n", "\n", - "# [START db]\n", - "db = solver.Phase(queens, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "# [END db]\n", + " db = solver.Phase(queens, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "# [START solve]\n", - "# Iterates through the solutions, displaying each.\n", - "num_solutions = 0\n", - "solver.NewSearch(db)\n", - "while solver.NextSolution():\n", - " # Displays the solution just computed.\n", - " for i in range(board_size):\n", - " for j in range(board_size):\n", - " if queens[j].Value() == i:\n", - " # There is a queen in column j, row i.\n", - " print('Q', end=' ')\n", - " else:\n", - " print('_', end=' ')\n", + " # Iterates through the solutions, displaying each.\n", + " num_solutions = 0\n", + " solver.NewSearch(db)\n", + " while solver.NextSolution():\n", + " # Displays the solution just computed.\n", + " for i in range(board_size):\n", + " for j in range(board_size):\n", + " if queens[j].Value() == 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", - " print()\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", - "# [END solve]\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", "\n", - "# Statistics.\n", - "# [START statistics]\n", - "print('\\nStatistics')\n", - "print(f' failures: {solver.Failures()}')\n", - "print(f' branches: {solver.Branches()}')\n", - "print(f' wall time: {solver.WallTime()} ms')\n", - "print(f' Solutions found: {num_solutions}')\n", - "# [END statistics]\n", + " # Statistics.\n", + " print('\\nStatistics')\n", + " print(f' failures: {solver.Failures()}')\n", + " print(f' branches: {solver.Branches()}')\n", + " print(f' wall time: {solver.WallTime()} ms')\n", + " print(f' Solutions found: {num_solutions}')\n", + "\n", + "\n", + "# By default, solve the 8x8 problem.\n", + "size = 8\n", + "if len(sys.argv) > 1:\n", + " size = int(sys.argv[1])\n", + "main(size)\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/simple_cp_program.ipynb b/examples/notebook/constraint_solver/simple_cp_program.ipynb index acf973b2fd..8fc5d5379f 100644 --- a/examples/notebook/constraint_solver/simple_cp_program.ipynb +++ b/examples/notebook/constraint_solver/simple_cp_program.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Constraint optimization example.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,72 +82,46 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Constraint optimization example.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the solver.\n", - "# [START solver]\n", - "solver = pywrapcp.Solver('CPSimple')\n", - "# [END solver]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the solver.\n", + " solver = pywrapcp.Solver('CPSimple')\n", "\n", - "# Create the variables.\n", - "# [START variables]\n", - "num_vals = 3\n", - "x = solver.IntVar(0, num_vals - 1, 'x')\n", - "y = solver.IntVar(0, num_vals - 1, 'y')\n", - "z = solver.IntVar(0, num_vals - 1, 'z')\n", - "# [END variables]\n", + " # Create the variables.\n", + " num_vals = 3\n", + " x = solver.IntVar(0, num_vals - 1, 'x')\n", + " y = solver.IntVar(0, num_vals - 1, 'y')\n", + " z = solver.IntVar(0, num_vals - 1, 'z')\n", "\n", - "# Constraint 0: x != y.\n", - "# [START constraints]\n", - "solver.Add(x != y)\n", - "print('Number of constraints: ', solver.Constraints())\n", - "# [END constraints]\n", + " # Constraint 0: x != y.\n", + " solver.Add(x != y)\n", + " print('Number of constraints: ', solver.Constraints())\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "decision_builder = solver.Phase([x, y, z], solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " decision_builder = solver.Phase([x, y, z], solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "count = 0\n", - "solver.NewSearch(decision_builder)\n", - "while solver.NextSolution():\n", - " count += 1\n", - " solution = 'Solution {}:\\n'.format(count)\n", - " for var in [x, y, z]:\n", - " solution += ' {} = {}'.format(var.Name(), var.Value())\n", - " print(solution)\n", - "solver.EndSearch()\n", - "print('Number of solutions found: ', count)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " count = 0\n", + " solver.NewSearch(decision_builder)\n", + " while solver.NextSolution():\n", + " count += 1\n", + " solution = 'Solution {}:\\n'.format(count)\n", + " for var in [x, y, z]:\n", + " solution += ' {} = {}'.format(var.Name(), var.Value())\n", + " print(solution)\n", + " solver.EndSearch()\n", + " print('Number of solutions found: ', count)\n", "\n", - "# [START advanced]\n", - "print('Advanced usage:')\n", - "print('Problem solved in ', solver.WallTime(), 'ms')\n", - "print('Memory usage: ', pywrapcp.Solver.MemoryUsage(), 'bytes')\n", - "# [END advanced]\n", + " print('Advanced usage:')\n", + " print('Problem solved in ', solver.WallTime(), 'ms')\n", + " print('Memory usage: ', pywrapcp.Solver.MemoryUsage(), 'bytes')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/simple_routing_program.ipynb b/examples/notebook/constraint_solver/simple_routing_program.ipynb index 2586e78082..48b7b9dcab 100644 --- a/examples/notebook/constraint_solver/simple_routing_program.ipynb +++ b/examples/notebook/constraint_solver/simple_routing_program.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Vehicle Routing example.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,91 +82,61 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicle Routing example.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "num_locations = 5\n", - "num_vehicles = 1\n", - "depot = 0\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " num_locations = 5\n", + " num_vehicles = 1\n", + " depot = 0\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(num_locations, num_vehicles, depot)\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(num_locations, num_vehicles, depot)\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the absolute difference between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to user NodeIndex.\n", - " from_node = int(manager.IndexToNode(from_index))\n", - " to_node = int(manager.IndexToNode(to_index))\n", - " return abs(to_node - from_node)\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the absolute difference between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to user NodeIndex.\n", + " from_node = int(manager.IndexToNode(from_index))\n", + " to_node = int(manager.IndexToNode(to_index))\n", + " return abs(to_node - from_node)\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) # pylint: disable=no-member\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "print('Objective: {}'.format(assignment.ObjectiveValue()))\n", - "index = routing.Start(0)\n", - "plan_output = 'Route for vehicle 0:\\n'\n", - "route_distance = 0\n", - "while not routing.IsEnd(index):\n", - " plan_output += '{} -> '.format(manager.IndexToNode(index))\n", - " previous_index = index\n", - " index = assignment.Value(routing.NextVar(index))\n", - " route_distance += routing.GetArcCostForVehicle(previous_index, index, 0)\n", - "plan_output += '{}\\n'.format(manager.IndexToNode(index))\n", - "plan_output += 'Distance of the route: {}m\\n'.format(route_distance)\n", - "print(plan_output)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " print('Objective: {}'.format(assignment.ObjectiveValue()))\n", + " index = routing.Start(0)\n", + " plan_output = 'Route for vehicle 0:\\n'\n", + " route_distance = 0\n", + " while not routing.IsEnd(index):\n", + " plan_output += '{} -> '.format(manager.IndexToNode(index))\n", + " previous_index = index\n", + " index = assignment.Value(routing.NextVar(index))\n", + " route_distance += routing.GetArcCostForVehicle(previous_index, index, 0)\n", + " plan_output += '{}\\n'.format(manager.IndexToNode(index))\n", + " plan_output += 'Distance of the route: {}m\\n'.format(route_distance)\n", + " print(plan_output)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/tsp.ipynb b/examples/notebook/constraint_solver/tsp.ipynb index c69208ad72..c47ecf3f49 100644 --- a/examples/notebook/constraint_solver/tsp.ipynb +++ b/examples/notebook/constraint_solver/tsp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,18 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Travelling Salesman Problem.\n", + "\n", + "A description of the problem can be found here:\n", + "http://en.wikipedia.org/wiki/Travelling_salesperson_problem.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,33 +86,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Travelling Salesman Problem.\n", - "\n", - "A description of the problem can be found here:\n", - "http://en.wikipedia.org/wiki/Travelling_salesperson_problem.\n", - "\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -120,10 +109,8 @@ " data['num_vehicles'] = 1\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START distance_callback]\n", "def create_distance_callback(data, manager):\n", " \"\"\"Creates callback to return distance between points.\"\"\"\n", " distances_ = {}\n", @@ -147,10 +134,8 @@ " return distances_[from_node][to_node]\n", "\n", " return distance_callback\n", - " # [END distance_callback]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, assignment):\n", " \"\"\"Prints assignment on console.\"\"\"\n", " print('Objective: {}'.format(assignment.ObjectiveValue()))\n", @@ -165,54 +150,41 @@ " plan_output += ' {}\\n'.format(manager.IndexToNode(index))\n", " plan_output += 'Distance of the route: {}m\\n'.format(route_distance)\n", " print(plan_output)\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['locations']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['locations']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", - "# [END routing_model]\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "distance_callback = create_distance_callback(data, manager)\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " # Create and register a transit callback.\n", + " distance_callback = create_distance_callback(data, manager)\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if assignment:\n", - " print_solution(manager, routing, assignment)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if assignment:\n", + " print_solution(manager, routing, assignment)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/tsp_circuit_board.ipynb b/examples/notebook/constraint_solver/tsp_circuit_board.ipynb index 0dc48e8892..c3e533304c 100644 --- a/examples/notebook/constraint_solver/tsp_circuit_board.ipynb +++ b/examples/notebook/constraint_solver/tsp_circuit_board.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Travelling Salesperson Problem (TSP) on a circuit board.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,30 +82,11 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Travelling Salesperson Problem (TSP) on a circuit board.\"\"\"\n", - "\n", - "# [START import]\n", "import math\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -154,10 +143,8 @@ " data['num_vehicles'] = 1\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START distance_callback]\n", "def compute_euclidean_distance_matrix(locations):\n", " \"\"\"Creates callback to return distance between points.\"\"\"\n", " distances = {}\n", @@ -172,10 +159,8 @@ " math.hypot((from_node[0] - to_node[0]),\n", " (from_node[1] - to_node[1]))))\n", " return distances\n", - " # [END distance_callback]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print('Objective: {}'.format(solution.ObjectiveValue()))\n", @@ -190,61 +175,48 @@ " plan_output += ' {}\\n'.format(manager.IndexToNode(index))\n", " print(plan_output)\n", " plan_output += 'Objective: {}m\\n'.format(route_distance)\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['locations']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['locations']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", - "# [END routing_model]\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [START transit_callback]\n", - "distance_matrix = compute_euclidean_distance_matrix(data['locations'])\n", + " distance_matrix = compute_euclidean_distance_matrix(data['locations'])\n", "\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return distance_matrix[from_node][to_node]\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return distance_matrix[from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/tsp_cities.ipynb b/examples/notebook/constraint_solver/tsp_cities.ipynb index 1b93bad0e8..5a5bb06739 100644 --- a/examples/notebook/constraint_solver/tsp_cities.ipynb +++ b/examples/notebook/constraint_solver/tsp_cities.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Travelling Salesperson Problem (TSP) between cities.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Travelling Salesperson Problem (TSP) between cities.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -118,10 +107,8 @@ " data['num_vehicles'] = 1\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print('Objective: {} miles'.format(solution.ObjectiveValue()))\n", @@ -136,60 +123,47 @@ " plan_output += ' {}\\n'.format(manager.IndexToNode(index))\n", " print(plan_output)\n", " plan_output += 'Route distance: {}miles\\n'.format(route_distance)\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/tsp_distance_matrix.ipynb b/examples/notebook/constraint_solver/tsp_distance_matrix.ipynb index 263bd55930..abada7d4e6 100644 --- a/examples/notebook/constraint_solver/tsp_distance_matrix.ipynb +++ b/examples/notebook/constraint_solver/tsp_distance_matrix.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Travelling Salesman Problem.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Travelling Salesman Problem.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -173,10 +162,8 @@ " data['num_vehicles'] = 1\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print('Objective: {}'.format(solution.ObjectiveValue()))\n", @@ -191,61 +178,48 @@ " plan_output += ' {}\\n'.format(manager.IndexToNode(index))\n", " plan_output += 'Distance of the route: {}m\\n'.format(route_distance)\n", " print(plan_output)\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp.ipynb b/examples/notebook/constraint_solver/vrp.ipynb index 7e54c00810..89ad8fc2fc 100644 --- a/examples/notebook/constraint_solver/vrp.ipynb +++ b/examples/notebook/constraint_solver/vrp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,27 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Vehicles Routing Problem (VRP).\n", + "Simple Vehicles Routing Problem (VRP).\n", "\n", " This is a sample using the routing library python wrapper to solve a VRP\n", " problem.\n", @@ -96,15 +80,20 @@ " http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n", "\n", " Distances are in meters.\n", - "\"\"\"\n", - "\n", - "# [START import]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -181,10 +170,8 @@ " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -205,63 +192,50 @@ " total_distance += route_distance\n", " print('Total Distance of all routes: {}m'.format(total_distance))\n", "\n", - "# [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "else:\n", - " print('No solution found !')\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + " else:\n", + " print('No solution found !')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_breaks.ipynb b/examples/notebook/constraint_solver/vrp_breaks.ipynb index 4664f84ec5..2bb568662b 100644 --- a/examples/notebook/constraint_solver/vrp_breaks.ipynb +++ b/examples/notebook/constraint_solver/vrp_breaks.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,27 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicle Routing Problem (VRP) with breaks.\n", + "Vehicle Routing Problem (VRP) with breaks.\n", "\n", " This is a sample using the routing library python wrapper to solve a VRP\n", " problem.\n", @@ -96,15 +80,20 @@ " http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n", "\n", " Durations are in minutes.\n", - "\"\"\"\n", - "\n", - "# [START import]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -134,10 +123,8 @@ " data['service_time'][data['depot']] = 0\n", " assert len(data['time_matrix']) == len(data['service_time'])\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -169,103 +156,88 @@ " print(plan_output)\n", " total_time += solution.Value(time_var)\n", " print(f'Total time of all routes: {total_time}min')\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the VRP with time windows.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the VRP with time windows.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def time_callback(from_index, to_index):\n", - " \"\"\"Returns the travel time + service time between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to time matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['time_matrix'][from_node][to_node] + data['service_time'][\n", - " from_node]\n", + " # Create and register a transit callback.\n", + " def time_callback(from_index, to_index):\n", + " \"\"\"Returns the travel time + service time between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to time matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['time_matrix'][from_node][to_node] + data['service_time'][\n", + " from_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Time Windows constraint.\n", - "time = 'Time'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 10, # needed optional waiting time to place break\n", - " 180, # maximum time per vehicle\n", - " True, # Force start cumul to zero.\n", - " time)\n", - "time_dimension = routing.GetDimensionOrDie(time)\n", - "time_dimension.SetGlobalSpanCostCoefficient(10)\n", + " # Add Time Windows constraint.\n", + " time = 'Time'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 10, # needed optional waiting time to place break\n", + " 180, # maximum time per vehicle\n", + " True, # Force start cumul to zero.\n", + " time)\n", + " time_dimension = routing.GetDimensionOrDie(time)\n", + " time_dimension.SetGlobalSpanCostCoefficient(10)\n", "\n", - "# Breaks\n", - "# [START break_constraint]\n", - "# warning: Need a pre-travel array using the solver's index order.\n", - "node_visit_transit = [0] * routing.Size()\n", - "for index in range(routing.Size()):\n", - " node = manager.IndexToNode(index)\n", - " node_visit_transit[index] = data['service_time'][node]\n", + " # Breaks\n", + " # warning: Need a pre-travel array using the solver's index order.\n", + " node_visit_transit = [0] * routing.Size()\n", + " for index in range(routing.Size()):\n", + " node = manager.IndexToNode(index)\n", + " node_visit_transit[index] = data['service_time'][node]\n", "\n", - "break_intervals = {}\n", - "for v in range(manager.GetNumberOfVehicles()):\n", - " break_intervals[v] = [\n", - " routing.solver().FixedDurationIntervalVar(\n", - " 50, # start min\n", - " 60, # start max\n", - " 10, # duration: 10 min\n", - " False, # optional: no\n", - " f'Break for vehicle {v}')\n", - " ]\n", - " time_dimension.SetBreakIntervalsOfVehicle(\n", - " break_intervals[v], # breaks\n", - " v, # vehicle index\n", - " node_visit_transit)\n", - "# [END break_constraint]\n", + " break_intervals = {}\n", + " for v in range(manager.GetNumberOfVehicles()):\n", + " break_intervals[v] = [\n", + " routing.solver().FixedDurationIntervalVar(\n", + " 50, # start min\n", + " 60, # start max\n", + " 10, # duration: 10 min\n", + " False, # optional: no\n", + " f'Break for vehicle {v}')\n", + " ]\n", + " time_dimension.SetBreakIntervalsOfVehicle(\n", + " break_intervals[v], # breaks\n", + " v, # vehicle index\n", + " node_visit_transit)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "# search_parameters.log_search = True\n", - "search_parameters.time_limit.FromSeconds(2)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " # search_parameters.log_search = True\n", + " search_parameters.time_limit.FromSeconds(2)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(manager, routing, solution)\n", - "else:\n", - " print('No solution found !')\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(manager, routing, solution)\n", + " else:\n", + " print('No solution found !')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_breaks_from_start.ipynb b/examples/notebook/constraint_solver/vrp_breaks_from_start.ipynb index c7993d1308..82294b75c6 100644 --- a/examples/notebook/constraint_solver/vrp_breaks_from_start.ipynb +++ b/examples/notebook/constraint_solver/vrp_breaks_from_start.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,27 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicles Routing Problem (VRP) with breaks relative to the vehicle start time.\n", + "Vehicles Routing Problem (VRP) with breaks relative to the vehicle start time.\n", " Each vehicles start at T:15min, T:30min, T:45min and T:60min respectively.\n", "\n", " Each vehicle must perform a break lasting 5 minutes,\n", @@ -97,15 +81,20 @@ " between [45+25,45+45] i.e. in the range [70, 90].\n", "\n", " Durations are in minutes.\n", - "\"\"\"\n", - "\n", - "# [START import]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -135,10 +124,8 @@ " data['service_time'][data['depot']] = 0\n", " assert len(data['time_matrix']) == len(data['service_time'])\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -173,105 +160,90 @@ " print(f'Time of the route: {route_time}min\\n')\n", " total_time += route_time\n", " print(f'Total time of all routes: {total_time}min')\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the VRP with time windows.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the VRP with time windows.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(\n", - " len(data['time_matrix']),\n", - " data['num_vehicles'],\n", - " data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(\n", + " len(data['time_matrix']),\n", + " data['num_vehicles'],\n", + " data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", - "# [END routing_model]\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def time_callback(from_index, to_index):\n", - " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to time matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['time_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def time_callback(from_index, to_index):\n", + " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to time matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['time_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Time Windows constraint.\n", - "time = 'Time'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 10, # need optional waiting time to place break\n", - " 180, # maximum time per vehicle\n", - " False, # Don't force start cumul to zero.\n", - " time)\n", - "time_dimension = routing.GetDimensionOrDie(time)\n", - "time_dimension.SetGlobalSpanCostCoefficient(10)\n", + " # Add Time Windows constraint.\n", + " time = 'Time'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 10, # need optional waiting time to place break\n", + " 180, # maximum time per vehicle\n", + " False, # Don't force start cumul to zero.\n", + " time)\n", + " time_dimension = routing.GetDimensionOrDie(time)\n", + " time_dimension.SetGlobalSpanCostCoefficient(10)\n", "\n", - "# Each vehicle start with a 15min delay\n", - "for vehicle_id in range(manager.GetNumberOfVehicles()):\n", - " index = routing.Start(vehicle_id)\n", - " time_dimension.CumulVar(index).SetValue((vehicle_id + 1) * 15)\n", + " # Each vehicle start with a 15min delay\n", + " for vehicle_id in range(manager.GetNumberOfVehicles()):\n", + " index = routing.Start(vehicle_id)\n", + " time_dimension.CumulVar(index).SetValue((vehicle_id + 1) * 15)\n", "\n", - "# Add breaks\n", - "# [START break_constraint]\n", - "# warning: Need a pre-travel array using the solver's index order.\n", - "node_visit_transit = [0] * routing.Size()\n", - "for index in range(routing.Size()):\n", - " node = manager.IndexToNode(index)\n", - " node_visit_transit[index] = data['service_time'][node]\n", + " # Add breaks\n", + " # warning: Need a pre-travel array using the solver's index order.\n", + " node_visit_transit = [0] * routing.Size()\n", + " for index in range(routing.Size()):\n", + " node = manager.IndexToNode(index)\n", + " node_visit_transit[index] = data['service_time'][node]\n", "\n", - "# Add a break lasting 5 minutes, start between 25 and 45 minutes after route start\n", - "for v in range(manager.GetNumberOfVehicles()):\n", - " start_var = time_dimension.CumulVar(routing.Start(v))\n", - " break_start = routing.solver().Sum([routing.solver().IntVar(25, 45), start_var])\n", + " # Add a break lasting 5 minutes, start between 25 and 45 minutes after route start\n", + " for v in range(manager.GetNumberOfVehicles()):\n", + " start_var = time_dimension.CumulVar(routing.Start(v))\n", + " break_start = routing.solver().Sum([routing.solver().IntVar(25, 45), start_var])\n", "\n", - " break_intervals = [\n", - " routing.solver().FixedDurationIntervalVar(\n", - " break_start, 5, 'Break for vehicle {}'.format(v))\n", - " ]\n", - " time_dimension.SetBreakIntervalsOfVehicle(break_intervals, v, node_visit_transit)\n", - "# [END break_constraint]\n", + " break_intervals = [\n", + " routing.solver().FixedDurationIntervalVar(\n", + " break_start, 5, 'Break for vehicle {}'.format(v))\n", + " ]\n", + " time_dimension.SetBreakIntervalsOfVehicle(break_intervals, v, node_visit_transit)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "# search_parameters.log_search = True\n", - "search_parameters.time_limit.FromSeconds(2)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " # search_parameters.log_search = True\n", + " search_parameters.time_limit.FromSeconds(2)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(manager, routing, solution)\n", - "else:\n", - " print('No solution found !')\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(manager, routing, solution)\n", + " else:\n", + " print('No solution found !')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_capacity.ipynb b/examples/notebook/constraint_solver/vrp_capacity.ipynb index e34d4880e7..1b73061f21 100644 --- a/examples/notebook/constraint_solver/vrp_capacity.ipynb +++ b/examples/notebook/constraint_solver/vrp_capacity.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Capacited Vehicles Routing Problem (CVRP).\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Capacited Vehicles Routing Problem (CVRP).\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -170,17 +159,13 @@ " 536, 194, 798, 0\n", " ],\n", " ]\n", - " # [START demands_capacities]\n", " data['demands'] = [0, 1, 1, 2, 4, 2, 4, 8, 8, 1, 2, 1, 2, 4, 4, 8, 8]\n", " data['vehicle_capacities'] = [15, 15, 15, 15]\n", - " # [END demands_capacities]\n", " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -208,83 +193,68 @@ " total_load += route_load\n", " print('Total distance of all routes: {}m'.format(total_distance))\n", " print('Total load of all routes: {}'.format(total_load))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the CVRP problem.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the CVRP problem.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# [END arc_cost]\n", "\n", - "# Add Capacity constraint.\n", - "# [START capacity_constraint]\n", - "def demand_callback(from_index):\n", - " \"\"\"Returns the demand of the node.\"\"\"\n", - " # Convert from routing variable Index to demands NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " return data['demands'][from_node]\n", + " # Add Capacity constraint.\n", + " def demand_callback(from_index):\n", + " \"\"\"Returns the demand of the node.\"\"\"\n", + " # Convert from routing variable Index to demands NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " return data['demands'][from_node]\n", "\n", - "demand_callback_index = routing.RegisterUnaryTransitCallback(\n", - " demand_callback)\n", - "routing.AddDimensionWithVehicleCapacity(\n", - " demand_callback_index,\n", - " 0, # null capacity slack\n", - " data['vehicle_capacities'], # vehicle maximum capacities\n", - " True, # start cumul to zero\n", - " 'Capacity')\n", - "# [END capacity_constraint]\n", + " demand_callback_index = routing.RegisterUnaryTransitCallback(\n", + " demand_callback)\n", + " routing.AddDimensionWithVehicleCapacity(\n", + " demand_callback_index,\n", + " 0, # null capacity slack\n", + " data['vehicle_capacities'], # vehicle maximum capacities\n", + " True, # start cumul to zero\n", + " 'Capacity')\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(1)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(1)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_drop_nodes.ipynb b/examples/notebook/constraint_solver/vrp_drop_nodes.ipynb index ca21831c62..0353098f13 100644 --- a/examples/notebook/constraint_solver/vrp_drop_nodes.ipynb +++ b/examples/notebook/constraint_solver/vrp_drop_nodes.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Capacited Vehicles Routing Problem (CVRP).\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Capacited Vehicles Routing Problem (CVRP).\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -170,17 +159,13 @@ " 536, 194, 798, 0\n", " ],\n", " ]\n", - " # [START demands_capacities]\n", " data['demands'] = [0, 1, 1, 3, 6, 3, 6, 8, 8, 1, 2, 1, 2, 6, 6, 8, 8]\n", " data['vehicle_capacities'] = [15, 15, 15, 15]\n", - " # [END demands_capacities]\n", " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, assignment):\n", " \"\"\"Prints assignment on console.\"\"\"\n", " print(f'Objective: {assignment.ObjectiveValue()}')\n", @@ -217,87 +202,72 @@ " total_load += route_load\n", " print('Total Distance of all routes: {}m'.format(total_distance))\n", " print('Total Load of all routes: {}'.format(total_load))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the CVRP problem.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the CVRP problem.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# [END arc_cost]\n", "\n", - "# Add Capacity constraint.\n", - "# [START capacity_constraint]\n", - "def demand_callback(from_index):\n", - " \"\"\"Returns the demand of the node.\"\"\"\n", - " # Convert from routing variable Index to demands NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " return data['demands'][from_node]\n", + " # Add Capacity constraint.\n", + " def demand_callback(from_index):\n", + " \"\"\"Returns the demand of the node.\"\"\"\n", + " # Convert from routing variable Index to demands NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " return data['demands'][from_node]\n", "\n", - "demand_callback_index = routing.RegisterUnaryTransitCallback(\n", - " demand_callback)\n", - "routing.AddDimensionWithVehicleCapacity(\n", - " demand_callback_index,\n", - " 0, # null capacity slack\n", - " data['vehicle_capacities'], # vehicle maximum capacities\n", - " True, # start cumul to zero\n", - " 'Capacity')\n", - "# Allow to drop nodes.\n", - "penalty = 1000\n", - "for node in range(1, len(data['distance_matrix'])):\n", - " routing.AddDisjunction([manager.NodeToIndex(node)], penalty)\n", - "# [END capacity_constraint]\n", + " demand_callback_index = routing.RegisterUnaryTransitCallback(\n", + " demand_callback)\n", + " routing.AddDimensionWithVehicleCapacity(\n", + " demand_callback_index,\n", + " 0, # null capacity slack\n", + " data['vehicle_capacities'], # vehicle maximum capacities\n", + " True, # start cumul to zero\n", + " 'Capacity')\n", + " # Allow to drop nodes.\n", + " penalty = 1000\n", + " for node in range(1, len(data['distance_matrix'])):\n", + " routing.AddDisjunction([manager.NodeToIndex(node)], penalty)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(1)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(1)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if assignment:\n", - " print_solution(data, manager, routing, assignment)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if assignment:\n", + " print_solution(data, manager, routing, assignment)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_global_span.ipynb b/examples/notebook/constraint_solver/vrp_global_span.ipynb index 5d46922ece..65e3a74bef 100644 --- a/examples/notebook/constraint_solver/vrp_global_span.ipynb +++ b/examples/notebook/constraint_solver/vrp_global_span.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,27 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Vehicles Routing Problem (VRP).\n", + "Simple Vehicles Routing Problem (VRP).\n", "\n", " This is a sample using the routing library python wrapper to solve a VRP\n", " problem.\n", @@ -96,15 +80,20 @@ " http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n", "\n", " Distances are in meters.\n", - "\"\"\"\n", - "\n", - "# [START import]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -181,10 +170,8 @@ " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -205,76 +192,61 @@ " max_route_distance = max(route_distance, max_route_distance)\n", " print('Maximum of the route distances: {}m'.format(max_route_distance))\n", "\n", - "# [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " 3000, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(100)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " 3000, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "else:\n", - " print('No solution found !')\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + " else:\n", + " print('No solution found !')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_initial_routes.ipynb b/examples/notebook/constraint_solver/vrp_initial_routes.ipynb index 6498e2f842..8958dc65a0 100644 --- a/examples/notebook/constraint_solver/vrp_initial_routes.ipynb +++ b/examples/notebook/constraint_solver/vrp_initial_routes.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Vehicles Routing Problem (VRP).\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,28 +82,9 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicles Routing Problem (VRP).\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -169,21 +158,17 @@ " 536, 194, 798, 0\n", " ],\n", " ]\n", - " # [START initial_routes]\n", " data['initial_routes'] = [\n", " [8, 16, 14, 13, 12, 11],\n", " [3, 4, 9, 10],\n", " [15, 1],\n", " [7, 5, 2, 6],\n", " ]\n", - " # [END initial_routes]\n", " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -204,81 +189,64 @@ " max_route_distance = max(route_distance, max_route_distance)\n", " print('Maximum of the route distances: {}m'.format(max_route_distance))\n", "\n", - "# [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the CVRP problem.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the CVRP problem.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " 3000, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(100)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " 3000, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# [START print_initial_solution]\n", - "initial_solution = routing.ReadAssignmentFromRoutes(data['initial_routes'],\n", - " True)\n", - "print('Initial solution:')\n", - "print_solution(data, manager, routing, initial_solution)\n", - "# [END print_initial_solution]\n", + " initial_solution = routing.ReadAssignmentFromRoutes(data['initial_routes'],\n", + " True)\n", + " print('Initial solution:')\n", + " print_solution(data, manager, routing, initial_solution)\n", "\n", - "# Set default search parameters.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "# [END parameters]\n", + " # Set default search parameters.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveFromAssignmentWithParameters(\n", - " initial_solution, search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveFromAssignmentWithParameters(\n", + " initial_solution, search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print('Solution after search:')\n", - " print_solution(data, manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print('Solution after search:')\n", + " print_solution(data, manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_node_max.ipynb b/examples/notebook/constraint_solver/vrp_node_max.ipynb index ccde33d905..e1a51f3bc1 100644 --- a/examples/notebook/constraint_solver/vrp_node_max.ipynb +++ b/examples/notebook/constraint_solver/vrp_node_max.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,18 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Vehicles Routing Problem (VRP).\n", + "\n", + "Each route as an associated objective cost equal to the max node value along the\n", + "road multiply by a constant factor (4200)\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,33 +86,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicles Routing Problem (VRP).\n", - "\n", - "Each route as an associated objective cost equal to the max node value along the\n", - "road multiply by a constant factor (4200)\n", - "\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -198,10 +187,8 @@ " data['depot'] = 0\n", " return data\n", "\n", - "# [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -236,148 +223,133 @@ " max_route_distance = max(route_distance, max_route_distance)\n", " print('Maximum of the route distances: {}m'.format(max_route_distance))\n", "\n", - "# [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the CVRP problem.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the CVRP problem.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " 3_000, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(10)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " 3_000, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(10)\n", "\n", - "# Max Node value Constraint.\n", - "# Dimension One will be used to compute the max node value up to the node in\n", - "# the route and store the result in the SlackVar of the node.\n", - "routing.AddConstantDimensionWithSlack(\n", - " 0, # transit 0\n", - " 42 * 16, # capacity: be able to store PEAK*ROUTE_LENGTH in worst case\n", - " 42, # slack_max: to be able to store peak in slack\n", - " True, # Fix StartCumulToZero not really matter here\n", - " 'One')\n", - "dim_one = routing.GetDimensionOrDie('One')\n", + " # Max Node value Constraint.\n", + " # Dimension One will be used to compute the max node value up to the node in\n", + " # the route and store the result in the SlackVar of the node.\n", + " routing.AddConstantDimensionWithSlack(\n", + " 0, # transit 0\n", + " 42 * 16, # capacity: be able to store PEAK*ROUTE_LENGTH in worst case\n", + " 42, # slack_max: to be able to store peak in slack\n", + " True, # Fix StartCumulToZero not really matter here\n", + " 'One')\n", + " dim_one = routing.GetDimensionOrDie('One')\n", "\n", - "# Dimension Two will be used to store the max node value in the route end node\n", - "# CumulVar so we can use it as an objective cost.\n", - "routing.AddConstantDimensionWithSlack(\n", - " 0, # transit 0\n", - " 42 * 16, # capacity: be able to have PEAK value in CumulVar(End)\n", - " 42, # slack_max: to be able to store peak in slack\n", - " True, # Fix StartCumulToZero YES here\n", - " 'Two')\n", - "dim_two = routing.GetDimensionOrDie('Two')\n", + " # Dimension Two will be used to store the max node value in the route end node\n", + " # CumulVar so we can use it as an objective cost.\n", + " routing.AddConstantDimensionWithSlack(\n", + " 0, # transit 0\n", + " 42 * 16, # capacity: be able to have PEAK value in CumulVar(End)\n", + " 42, # slack_max: to be able to store peak in slack\n", + " True, # Fix StartCumulToZero YES here\n", + " 'Two')\n", + " dim_two = routing.GetDimensionOrDie('Two')\n", "\n", - "# force depot Slack to be value since we don't have any predecessor...\n", - "for v in range(manager.GetNumberOfVehicles()):\n", - " start = routing.Start(v)\n", - " dim_one.SlackVar(start).SetValue(data['value'][0])\n", - " routing.AddToAssignment(dim_one.SlackVar(start))\n", - "\n", - " dim_two.SlackVar(start).SetValue(data['value'][0])\n", - " routing.AddToAssignment(dim_two.SlackVar(start))\n", - "\n", - "# Step by step relation\n", - "# Slack(N) = max( Slack(N-1) , value(N) )\n", - "solver = routing.solver()\n", - "for node in range(1, 17):\n", - " index = manager.NodeToIndex(node)\n", - " routing.AddToAssignment(dim_one.SlackVar(index))\n", - " routing.AddToAssignment(dim_two.SlackVar(index))\n", - " test = []\n", + " # force depot Slack to be value since we don't have any predecessor...\n", " for v in range(manager.GetNumberOfVehicles()):\n", - " previous_index = routing.Start(v)\n", - " cond = routing.NextVar(previous_index) == index\n", - " value = solver.Max(dim_one.SlackVar(previous_index),\n", - " data['value'][node])\n", - " test.append((cond * value).Var())\n", - " for previous in range(1, 17):\n", - " previous_index = manager.NodeToIndex(previous)\n", - " cond = routing.NextVar(previous_index) == index\n", - " value = solver.Max(dim_one.SlackVar(previous_index),\n", - " data['value'][node])\n", - " test.append((cond * value).Var())\n", - " solver.Add(solver.Sum(test) == dim_one.SlackVar(index))\n", + " start = routing.Start(v)\n", + " dim_one.SlackVar(start).SetValue(data['value'][0])\n", + " routing.AddToAssignment(dim_one.SlackVar(start))\n", "\n", - "# relation between dimensions, copy last node Slack from dim ONE to dim TWO\n", - "for node in range(1, 17):\n", - " index = manager.NodeToIndex(node)\n", - " values = []\n", + " dim_two.SlackVar(start).SetValue(data['value'][0])\n", + " routing.AddToAssignment(dim_two.SlackVar(start))\n", + "\n", + " # Step by step relation\n", + " # Slack(N) = max( Slack(N-1) , value(N) )\n", + " solver = routing.solver()\n", + " for node in range(1, 17):\n", + " index = manager.NodeToIndex(node)\n", + " routing.AddToAssignment(dim_one.SlackVar(index))\n", + " routing.AddToAssignment(dim_two.SlackVar(index))\n", + " test = []\n", + " for v in range(manager.GetNumberOfVehicles()):\n", + " previous_index = routing.Start(v)\n", + " cond = routing.NextVar(previous_index) == index\n", + " value = solver.Max(dim_one.SlackVar(previous_index),\n", + " data['value'][node])\n", + " test.append((cond * value).Var())\n", + " for previous in range(1, 17):\n", + " previous_index = manager.NodeToIndex(previous)\n", + " cond = routing.NextVar(previous_index) == index\n", + " value = solver.Max(dim_one.SlackVar(previous_index),\n", + " data['value'][node])\n", + " test.append((cond * value).Var())\n", + " solver.Add(solver.Sum(test) == dim_one.SlackVar(index))\n", + "\n", + " # relation between dimensions, copy last node Slack from dim ONE to dim TWO\n", + " for node in range(1, 17):\n", + " index = manager.NodeToIndex(node)\n", + " values = []\n", + " for v in range(manager.GetNumberOfVehicles()):\n", + " next_index = routing.End(v)\n", + " cond = routing.NextVar(index) == next_index\n", + " value = dim_one.SlackVar(index)\n", + " values.append((cond * value).Var())\n", + " solver.Add(solver.Sum(values) == dim_two.SlackVar(index))\n", + "\n", + " # Should force all others dim_two slack var to zero...\n", " for v in range(manager.GetNumberOfVehicles()):\n", - " next_index = routing.End(v)\n", - " cond = routing.NextVar(index) == next_index\n", - " value = dim_one.SlackVar(index)\n", - " values.append((cond * value).Var())\n", - " solver.Add(solver.Sum(values) == dim_two.SlackVar(index))\n", + " end = routing.End(v)\n", + " dim_two.SetCumulVarSoftUpperBound(end, 0, 4200)\n", "\n", - "# Should force all others dim_two slack var to zero...\n", - "for v in range(manager.GetNumberOfVehicles()):\n", - " end = routing.End(v)\n", - " dim_two.SetCumulVarSoftUpperBound(end, 0, 4200)\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " # search_parameters.log_search = True\n", + " search_parameters.time_limit.FromSeconds(5)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "# search_parameters.log_search = True\n", - "search_parameters.time_limit.FromSeconds(5)\n", - "# [END parameters]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + " else:\n", + " print('No solution found !')\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "else:\n", - " print('No solution found !')\n", - "# [END print_solution]\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb b/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb index 7926cb85d7..2e3417fa7c 100644 --- a/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb +++ b/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,27 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Sample to better understand Node/Index relation.\n", + "Sample to better understand Node/Index relation.\n", "\n", "This script generate few markdown tables to better understand\n", "the relation between nodes and indices.\n", @@ -110,64 +94,76 @@ "* Allways use routing.Start(), routing.End(), manager.IndexToNode() or manager.NodeToIndex().\n", "* Location node is not necessarily equal to its index.\n", "* To loop through ALL indices use manager.GetNumberOfIndices() (Python) or manager::num_indices() (C++)\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "locations = 17\n", - "starts = [5, 5, 7, 8]\n", - "ends = [1, 2, 4, 4]\n", - "vehicles = len(starts)\n", - "assert len(starts) == len(ends)\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " locations = 17\n", + " starts = [5, 5, 7, 8]\n", + " ends = [1, 2, 4, 4]\n", + " vehicles = len(starts)\n", + " assert len(starts) == len(ends)\n", "\n", - "manager = pywrapcp.RoutingIndexManager(locations, vehicles, starts, ends)\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " manager = pywrapcp.RoutingIndexManager(locations, vehicles, starts, ends)\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "print('Starts/Ends:')\n", - "header = '| |'\n", - "separator = '|---|'\n", - "v_starts = '| start |'\n", - "v_ends = '| end |'\n", - "for v in range(manager.GetNumberOfVehicles()):\n", - " header += f' vehicle {v} |'\n", - " separator += '---|'\n", - " v_starts += f' {starts[v]} |'\n", - " v_ends += f' {ends[v]} |'\n", - "print(header)\n", - "print(separator)\n", - "print(v_starts)\n", - "print(v_ends)\n", + " print('Starts/Ends:')\n", + " header = '| |'\n", + " separator = '|---|'\n", + " v_starts = '| start |'\n", + " v_ends = '| end |'\n", + " for v in range(manager.GetNumberOfVehicles()):\n", + " header += f' vehicle {v} |'\n", + " separator += '---|'\n", + " v_starts += f' {starts[v]} |'\n", + " v_ends += f' {ends[v]} |'\n", + " print(header)\n", + " print(separator)\n", + " print(v_starts)\n", + " print(v_ends)\n", "\n", - "print('\\nNodes:')\n", - "print('| locations | manager.GetNumberOfNodes | manager.GetNumberOfIndices | routing.nodes | routing.Size |')\n", - "print('|---|---|---|---|---|')\n", - "print(f'| {locations} | {manager.GetNumberOfNodes()} | {manager.GetNumberOfIndices()} | {routing.nodes()} | {routing.Size()} |')\n", + " print('\\nNodes:')\n", + " print('| locations | manager.GetNumberOfNodes | manager.GetNumberOfIndices | routing.nodes | routing.Size |')\n", + " print('|---|---|---|---|---|')\n", + " print(f'| {locations} | {manager.GetNumberOfNodes()} | {manager.GetNumberOfIndices()} | {routing.nodes()} | {routing.Size()} |')\n", "\n", - "print('\\nLocations:')\n", - "print('| node | index | routing.IsStart | routing.IsEnd |')\n", - "print('|---|---|---|---|')\n", - "for node in range(manager.GetNumberOfNodes()):\n", - " if node in starts or node in ends:\n", - " continue\n", - " index = manager.NodeToIndex(node)\n", - " print(\n", - " f'| {node} | {index} | {routing.IsStart(index)} | {routing.IsEnd(index)} |'\n", - " )\n", + " print('\\nLocations:')\n", + " print('| node | index | routing.IsStart | routing.IsEnd |')\n", + " print('|---|---|---|---|')\n", + " for node in range(manager.GetNumberOfNodes()):\n", + " if node in starts or node in ends:\n", + " continue\n", + " index = manager.NodeToIndex(node)\n", + " print(\n", + " f'| {node} | {index} | {routing.IsStart(index)} | {routing.IsEnd(index)} |'\n", + " )\n", "\n", - "print('\\nStart/End:')\n", - "print('| vehicle | Start/end | node | index | routing.IsStart | routing.IsEnd |')\n", - "print('|---|---|---|---|---|---|')\n", - "for v in range(manager.GetNumberOfVehicles()):\n", - " start_index = routing.Start(v)\n", - " start_node = manager.IndexToNode(start_index)\n", - " print(f'| {v} | start | {start_node} | {start_index} | {routing.IsStart(start_index)} | {routing.IsEnd(start_index)} |')\n", - "for v in range(manager.GetNumberOfVehicles()):\n", - " end_index = routing.End(v)\n", - " end_node = manager.IndexToNode(end_index)\n", - " print(f'| {v} | end | {end_node} | {end_index} | {routing.IsStart(end_index)} | {routing.IsEnd(end_index)} |')\n", + " print('\\nStart/End:')\n", + " print('| vehicle | Start/end | node | index | routing.IsStart | routing.IsEnd |')\n", + " print('|---|---|---|---|---|---|')\n", + " for v in range(manager.GetNumberOfVehicles()):\n", + " start_index = routing.Start(v)\n", + " start_node = manager.IndexToNode(start_index)\n", + " print(f'| {v} | start | {start_node} | {start_index} | {routing.IsStart(start_index)} | {routing.IsEnd(start_index)} |')\n", + " for v in range(manager.GetNumberOfVehicles()):\n", + " end_index = routing.End(v)\n", + " end_node = manager.IndexToNode(end_index)\n", + " print(f'| {v} | end | {end_node} | {end_index} | {routing.IsStart(end_index)} | {routing.IsEnd(end_index)} |')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_pickup_delivery.ipynb b/examples/notebook/constraint_solver/vrp_pickup_delivery.ipynb index 6029a9fe38..b6e944fb5a 100644 --- a/examples/notebook/constraint_solver/vrp_pickup_delivery.ipynb +++ b/examples/notebook/constraint_solver/vrp_pickup_delivery.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Pickup Delivery Problem (PDP).\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Pickup Delivery Problem (PDP).\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -170,7 +159,6 @@ " 536, 194, 798, 0\n", " ],\n", " ]\n", - " # [START pickups_deliveries]\n", " data['pickups_deliveries'] = [\n", " [1, 6],\n", " [2, 10],\n", @@ -181,14 +169,11 @@ " [13, 12],\n", " [16, 14],\n", " ]\n", - " # [END pickups_deliveries]\n", " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -208,84 +193,69 @@ " print(plan_output)\n", " total_distance += route_distance\n", " print('Total Distance of all routes: {}m'.format(total_distance))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the manhattan distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Define cost of each arc.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the manhattan distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " 3000, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(100)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " 3000, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# Define Transportation Requests.\n", - "# [START pickup_delivery_constraint]\n", - "for request in data['pickups_deliveries']:\n", - " pickup_index = manager.NodeToIndex(request[0])\n", - " delivery_index = manager.NodeToIndex(request[1])\n", - " routing.AddPickupAndDelivery(pickup_index, delivery_index)\n", - " routing.solver().Add(\n", - " routing.VehicleVar(pickup_index) == routing.VehicleVar(\n", - " delivery_index))\n", - " routing.solver().Add(\n", - " distance_dimension.CumulVar(pickup_index) <=\n", - " distance_dimension.CumulVar(delivery_index))\n", - "# [END pickup_delivery_constraint]\n", + " # Define Transportation Requests.\n", + " for request in data['pickups_deliveries']:\n", + " pickup_index = manager.NodeToIndex(request[0])\n", + " delivery_index = manager.NodeToIndex(request[1])\n", + " routing.AddPickupAndDelivery(pickup_index, delivery_index)\n", + " routing.solver().Add(\n", + " routing.VehicleVar(pickup_index) == routing.VehicleVar(\n", + " delivery_index))\n", + " routing.solver().Add(\n", + " distance_dimension.CumulVar(pickup_index) <=\n", + " distance_dimension.CumulVar(delivery_index))\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_pickup_delivery_fifo.ipynb b/examples/notebook/constraint_solver/vrp_pickup_delivery_fifo.ipynb index 79691afb74..3808f10bb2 100644 --- a/examples/notebook/constraint_solver/vrp_pickup_delivery_fifo.ipynb +++ b/examples/notebook/constraint_solver/vrp_pickup_delivery_fifo.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Pickup Delivery Problem (PDP).\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Pickup Delivery Problem (PDP).\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -170,7 +159,6 @@ " 536, 194, 798, 0\n", " ],\n", " ]\n", - " # [START pickups_deliveries]\n", " data['pickups_deliveries'] = [\n", " [1, 6],\n", " [2, 10],\n", @@ -181,14 +169,11 @@ " [13, 12],\n", " [16, 14],\n", " ]\n", - " # [END pickups_deliveries]\n", " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, assignment):\n", " \"\"\"Prints assignment on console.\"\"\"\n", " print(f'Objective: {assignment.ObjectiveValue()}')\n", @@ -208,86 +193,71 @@ " print(plan_output)\n", " total_distance += route_distance\n", " print('Total Distance of all routes: {}m'.format(total_distance))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the manhattan distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Define cost of each arc.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the manhattan distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " 3000, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(100)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " 3000, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# Define Transportation Requests.\n", - "# [START pickup_delivery_constraint]\n", - "for request in data['pickups_deliveries']:\n", - " pickup_index = manager.NodeToIndex(request[0])\n", - " delivery_index = manager.NodeToIndex(request[1])\n", - " routing.AddPickupAndDelivery(pickup_index, delivery_index)\n", - " routing.solver().Add(\n", - " routing.VehicleVar(pickup_index) == routing.VehicleVar(\n", - " delivery_index))\n", - " routing.solver().Add(\n", - " distance_dimension.CumulVar(pickup_index) <=\n", - " distance_dimension.CumulVar(delivery_index))\n", - "routing.SetPickupAndDeliveryPolicyOfAllVehicles(\n", - " pywrapcp.RoutingModel.PICKUP_AND_DELIVERY_FIFO)\n", - "# [END pickup_delivery_constraint]\n", + " # Define Transportation Requests.\n", + " for request in data['pickups_deliveries']:\n", + " pickup_index = manager.NodeToIndex(request[0])\n", + " delivery_index = manager.NodeToIndex(request[1])\n", + " routing.AddPickupAndDelivery(pickup_index, delivery_index)\n", + " routing.solver().Add(\n", + " routing.VehicleVar(pickup_index) == routing.VehicleVar(\n", + " delivery_index))\n", + " routing.solver().Add(\n", + " distance_dimension.CumulVar(pickup_index) <=\n", + " distance_dimension.CumulVar(delivery_index))\n", + " routing.SetPickupAndDeliveryPolicyOfAllVehicles(\n", + " pywrapcp.RoutingModel.PICKUP_AND_DELIVERY_FIFO)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if assignment:\n", - " print_solution(data, manager, routing, assignment)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if assignment:\n", + " print_solution(data, manager, routing, assignment)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_pickup_delivery_lifo.ipynb b/examples/notebook/constraint_solver/vrp_pickup_delivery_lifo.ipynb index 47121ef265..b8efb3ea97 100644 --- a/examples/notebook/constraint_solver/vrp_pickup_delivery_lifo.ipynb +++ b/examples/notebook/constraint_solver/vrp_pickup_delivery_lifo.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Pickup Delivery Problem (PDP).\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Pickup Delivery Problem (PDP).\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -170,7 +159,6 @@ " 536, 194, 798, 0\n", " ],\n", " ]\n", - " # [START pickups_deliveries]\n", " data['pickups_deliveries'] = [\n", " [1, 6],\n", " [2, 10],\n", @@ -181,14 +169,11 @@ " [13, 12],\n", " [16, 14],\n", " ]\n", - " # [END pickups_deliveries]\n", " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, assignment):\n", " \"\"\"Prints assignment on console.\"\"\"\n", " print(f'Objective: {assignment.ObjectiveValue()}')\n", @@ -208,86 +193,71 @@ " print(plan_output)\n", " total_distance += route_distance\n", " print('Total Distance of all routes: {}m'.format(total_distance))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the manhattan distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Define cost of each arc.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the manhattan distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " 3000, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(100)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " 3000, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# Define Transportation Requests.\n", - "# [START pickup_delivery_constraint]\n", - "for request in data['pickups_deliveries']:\n", - " pickup_index = manager.NodeToIndex(request[0])\n", - " delivery_index = manager.NodeToIndex(request[1])\n", - " routing.AddPickupAndDelivery(pickup_index, delivery_index)\n", - " routing.solver().Add(\n", - " routing.VehicleVar(pickup_index) == routing.VehicleVar(\n", - " delivery_index))\n", - " routing.solver().Add(\n", - " distance_dimension.CumulVar(pickup_index) <=\n", - " distance_dimension.CumulVar(delivery_index))\n", - "routing.SetPickupAndDeliveryPolicyOfAllVehicles(\n", - " pywrapcp.RoutingModel.PICKUP_AND_DELIVERY_LIFO)\n", - "# [END pickup_delivery_constraint]\n", + " # Define Transportation Requests.\n", + " for request in data['pickups_deliveries']:\n", + " pickup_index = manager.NodeToIndex(request[0])\n", + " delivery_index = manager.NodeToIndex(request[1])\n", + " routing.AddPickupAndDelivery(pickup_index, delivery_index)\n", + " routing.solver().Add(\n", + " routing.VehicleVar(pickup_index) == routing.VehicleVar(\n", + " delivery_index))\n", + " routing.solver().Add(\n", + " distance_dimension.CumulVar(pickup_index) <=\n", + " distance_dimension.CumulVar(delivery_index))\n", + " routing.SetPickupAndDeliveryPolicyOfAllVehicles(\n", + " pywrapcp.RoutingModel.PICKUP_AND_DELIVERY_LIFO)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PARALLEL_CHEAPEST_INSERTION)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if assignment:\n", - " print_solution(data, manager, routing, assignment)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if assignment:\n", + " print_solution(data, manager, routing, assignment)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_resources.ipynb b/examples/notebook/constraint_solver/vrp_resources.ipynb index 3bb851396d..a81b7cc946 100644 --- a/examples/notebook/constraint_solver/vrp_resources.ipynb +++ b/examples/notebook/constraint_solver/vrp_resources.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Vehicles Routing Problem (VRP) with Resource Constraints.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicles Routing Problem (VRP) with Resource Constraints.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -139,17 +128,13 @@ " (5, 15), # 16\n", " ]\n", " data['num_vehicles'] = 4\n", - " # [START resources_data]\n", " data['vehicle_load_time'] = 5\n", " data['vehicle_unload_time'] = 5\n", " data['depot_capacity'] = 2\n", - " # [END resources_data]\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -173,119 +158,98 @@ " print(plan_output)\n", " total_time += solution.Min(time_var)\n", " print('Total time of all routes: {}min'.format(total_time))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the VRP with time windows.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the VRP with time windows.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def time_callback(from_index, to_index):\n", - " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to time matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['time_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def time_callback(from_index, to_index):\n", + " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to time matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['time_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Time Windows constraint.\n", - "# [START time_windows_constraint]\n", - "time = 'Time'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 60, # allow waiting time\n", - " 60, # maximum time per vehicle\n", - " False, # Don't force start cumul to zero.\n", - " time)\n", - "time_dimension = routing.GetDimensionOrDie(time)\n", - "# Add time window constraints for each location except depot.\n", - "for location_idx, time_window in enumerate(data['time_windows']):\n", - " if location_idx == 0:\n", - " continue\n", - " index = manager.NodeToIndex(location_idx)\n", - " time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])\n", - "# Add time window constraints for each vehicle start node.\n", - "for vehicle_id in range(data['num_vehicles']):\n", - " index = routing.Start(vehicle_id)\n", - " time_dimension.CumulVar(index).SetRange(data['time_windows'][0][0],\n", - " data['time_windows'][0][1])\n", - "# [END time_windows_constraint]\n", + " # Add Time Windows constraint.\n", + " time = 'Time'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 60, # allow waiting time\n", + " 60, # maximum time per vehicle\n", + " False, # Don't force start cumul to zero.\n", + " time)\n", + " time_dimension = routing.GetDimensionOrDie(time)\n", + " # Add time window constraints for each location except depot.\n", + " for location_idx, time_window in enumerate(data['time_windows']):\n", + " if location_idx == 0:\n", + " continue\n", + " index = manager.NodeToIndex(location_idx)\n", + " time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])\n", + " # Add time window constraints for each vehicle start node.\n", + " for vehicle_id in range(data['num_vehicles']):\n", + " index = routing.Start(vehicle_id)\n", + " time_dimension.CumulVar(index).SetRange(data['time_windows'][0][0],\n", + " data['time_windows'][0][1])\n", "\n", - "# Add resource constraints at the depot.\n", - "# [START depot_load_time]\n", - "solver = routing.solver()\n", - "intervals = []\n", - "for i in range(data['num_vehicles']):\n", - " # Add time windows at start of routes\n", - " intervals.append(\n", - " solver.FixedDurationIntervalVar(\n", - " time_dimension.CumulVar(routing.Start(i)),\n", - " data['vehicle_load_time'], 'depot_interval'))\n", - " # Add time windows at end of routes.\n", - " intervals.append(\n", - " solver.FixedDurationIntervalVar(\n", - " time_dimension.CumulVar(routing.End(i)),\n", - " data['vehicle_unload_time'], 'depot_interval'))\n", - "# [END depot_load_time]\n", + " # Add resource constraints at the depot.\n", + " solver = routing.solver()\n", + " intervals = []\n", + " for i in range(data['num_vehicles']):\n", + " # Add time windows at start of routes\n", + " intervals.append(\n", + " solver.FixedDurationIntervalVar(\n", + " time_dimension.CumulVar(routing.Start(i)),\n", + " data['vehicle_load_time'], 'depot_interval'))\n", + " # Add time windows at end of routes.\n", + " intervals.append(\n", + " solver.FixedDurationIntervalVar(\n", + " time_dimension.CumulVar(routing.End(i)),\n", + " data['vehicle_unload_time'], 'depot_interval'))\n", "\n", - "# [START depot_capacity]\n", - "depot_usage = [1 for i in range(len(intervals))]\n", - "solver.Add(\n", - " solver.Cumulative(intervals, depot_usage, data['depot_capacity'],\n", - " 'depot'))\n", - "# [END depot_capacity]\n", + " depot_usage = [1 for i in range(len(intervals))]\n", + " solver.Add(\n", + " solver.Cumulative(intervals, depot_usage, data['depot_capacity'],\n", + " 'depot'))\n", "\n", - "# Instantiate route start and end times to produce feasible times.\n", - "# [START depot_start_end_times]\n", - "for i in range(data['num_vehicles']):\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " time_dimension.CumulVar(routing.Start(i)))\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " time_dimension.CumulVar(routing.End(i)))\n", - "# [END depot_start_end_times]\n", + " # Instantiate route start and end times to produce feasible times.\n", + " for i in range(data['num_vehicles']):\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " time_dimension.CumulVar(routing.Start(i)))\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " time_dimension.CumulVar(routing.End(i)))\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "# [END print_solution]\n", - "else:\n", - " print('No solution found !')\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + " else:\n", + " print('No solution found !')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_starts_ends.ipynb b/examples/notebook/constraint_solver/vrp_starts_ends.ipynb index d7a16dec9d..1ca21670f2 100644 --- a/examples/notebook/constraint_solver/vrp_starts_ends.ipynb +++ b/examples/notebook/constraint_solver/vrp_starts_ends.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple Vehicles Routing Problem.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple Vehicles Routing Problem.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -171,15 +160,11 @@ " ],\n", " ]\n", " data['num_vehicles'] = 4\n", - " # [START starts_ends]\n", " data['starts'] = [1, 2, 15, 16]\n", " data['ends'] = [0, 0, 0, 0]\n", - " # [END starts_ends]\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -199,75 +184,60 @@ " print(plan_output)\n", " max_route_distance = max(route_distance, max_route_distance)\n", " print('Maximum of the route distances: {}m'.format(max_route_distance))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", - " data['num_vehicles'], data['starts'],\n", - " data['ends'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n", + " data['num_vehicles'], data['starts'],\n", + " data['ends'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['distance_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['distance_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " 2000, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(100)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " 2000, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_time_windows.ipynb b/examples/notebook/constraint_solver/vrp_time_windows.ipynb index 6630f3411b..555a5472d6 100644 --- a/examples/notebook/constraint_solver/vrp_time_windows.ipynb +++ b/examples/notebook/constraint_solver/vrp_time_windows.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Vehicles Routing Problem (VRP) with Time Windows.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicles Routing Problem (VRP) with Time Windows.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -141,10 +130,8 @@ " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -168,95 +155,78 @@ " print(plan_output)\n", " total_time += solution.Min(time_var)\n", " print('Total time of all routes: {}min'.format(total_time))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the VRP with time windows.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the VRP with time windows.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def time_callback(from_index, to_index):\n", - " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to time matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['time_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def time_callback(from_index, to_index):\n", + " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to time matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['time_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Time Windows constraint.\n", - "# [START time_windows_constraint]\n", - "time = 'Time'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 30, # allow waiting time\n", - " 30, # maximum time per vehicle\n", - " False, # Don't force start cumul to zero.\n", - " time)\n", - "time_dimension = routing.GetDimensionOrDie(time)\n", - "# Add time window constraints for each location except depot.\n", - "for location_idx, time_window in enumerate(data['time_windows']):\n", - " if location_idx == data['depot']:\n", - " continue\n", - " index = manager.NodeToIndex(location_idx)\n", - " time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])\n", - "# Add time window constraints for each vehicle start node.\n", - "depot_idx = data['depot']\n", - "for vehicle_id in range(data['num_vehicles']):\n", - " index = routing.Start(vehicle_id)\n", - " time_dimension.CumulVar(index).SetRange(\n", - " data['time_windows'][depot_idx][0],\n", - " data['time_windows'][depot_idx][1])\n", - "# [END time_windows_constraint]\n", + " # Add Time Windows constraint.\n", + " time = 'Time'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 30, # allow waiting time\n", + " 30, # maximum time per vehicle\n", + " False, # Don't force start cumul to zero.\n", + " time)\n", + " time_dimension = routing.GetDimensionOrDie(time)\n", + " # Add time window constraints for each location except depot.\n", + " for location_idx, time_window in enumerate(data['time_windows']):\n", + " if location_idx == data['depot']:\n", + " continue\n", + " index = manager.NodeToIndex(location_idx)\n", + " time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])\n", + " # Add time window constraints for each vehicle start node.\n", + " depot_idx = data['depot']\n", + " for vehicle_id in range(data['num_vehicles']):\n", + " index = routing.Start(vehicle_id)\n", + " time_dimension.CumulVar(index).SetRange(\n", + " data['time_windows'][depot_idx][0],\n", + " data['time_windows'][depot_idx][1])\n", "\n", - "# Instantiate route start and end times to produce feasible times.\n", - "# [START depot_start_end_times]\n", - "for i in range(data['num_vehicles']):\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " time_dimension.CumulVar(routing.Start(i)))\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " time_dimension.CumulVar(routing.End(i)))\n", - "# [END depot_start_end_times]\n", + " # Instantiate route start and end times to produce feasible times.\n", + " for i in range(data['num_vehicles']):\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " time_dimension.CumulVar(routing.Start(i)))\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " time_dimension.CumulVar(routing.End(i)))\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_time_windows_per_vehicles.ipynb b/examples/notebook/constraint_solver/vrp_time_windows_per_vehicles.ipynb index 75ec678957..91172e27f3 100644 --- a/examples/notebook/constraint_solver/vrp_time_windows_per_vehicles.ipynb +++ b/examples/notebook/constraint_solver/vrp_time_windows_per_vehicles.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,27 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicles Routing Problem (VRP) with Time Window (TW) per vehicle.\n", + "Vehicles Routing Problem (VRP) with Time Window (TW) per vehicle.\n", "\n", " All time are in minutes using 0am as origin\n", " e.g. 8am = 480, 11am = 660, 1pm = 780 ...\n", @@ -103,15 +87,20 @@ " location: [17-32] vehicle: 1 TW: [660, 780] (11am-1pm)\n", " location: [33-48] vehicle: 2 TW: [780, 900] (1pm-3pm)\n", " location: [49-64] vehicle: 3 TW: [900, 1020] (3pm-5pm)\n", - "\"\"\"\n", - "\n", - "# [START import]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -137,10 +126,8 @@ " data['num_vehicles'] = 4\n", " data['depot'] = 0\n", " return data\n", - " # [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, assignment):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {assignment.ObjectiveValue()}')\n", @@ -189,138 +176,121 @@ " print(plan_output)\n", " total_time += duration\n", " print(f'Total duration of all routes: {total_time}min')\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the VRP with time windows.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the VRP with time windows.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(\n", - " 1 + 16*4, # number of locations\n", - " data['num_vehicles'],\n", - " data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(\n", + " 1 + 16*4, # number of locations\n", + " data['num_vehicles'],\n", + " data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def time_callback(from_index, to_index):\n", - " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to time matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " # since our matrix is 17x17 map duplicated node to original one to\n", - " # retrieve the travel time\n", - " while from_node > 16:\n", - " from_node = from_node - 16;\n", - " while to_node > 16:\n", - " to_node = to_node - 16;\n", - " # add service of 25min for each location (except depot)\n", - " service_time = 0\n", - " if from_node != data['depot']:\n", - " service_time = 25\n", - " return data['time_matrix'][from_node][to_node] + service_time\n", + " # Create and register a transit callback.\n", + " def time_callback(from_index, to_index):\n", + " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to time matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " # since our matrix is 17x17 map duplicated node to original one to\n", + " # retrieve the travel time\n", + " while from_node > 16:\n", + " from_node = from_node - 16;\n", + " while to_node > 16:\n", + " to_node = to_node - 16;\n", + " # add service of 25min for each location (except depot)\n", + " service_time = 0\n", + " if from_node != data['depot']:\n", + " service_time = 25\n", + " return data['time_matrix'][from_node][to_node] + service_time\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Time Windows constraint.\n", - "# [START time_windows_constraint]\n", - "time = 'Time'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # allow waiting time (0 min)\n", - " 1020, # maximum time per vehicle (9 hours)\n", - " False, # Don't force start cumul to zero.\n", - " time)\n", - "time_dimension = routing.GetDimensionOrDie(time)\n", - "# Add time window constraints for each location except depot.\n", - "for location_idx in range(17):\n", - " if location_idx == data['depot']:\n", - " continue\n", - " # Vehicle 0 location TW: [9am, 11am]\n", - " index_0 = manager.NodeToIndex(location_idx)\n", - " time_dimension.CumulVar(index_0).SetRange(540, 660)\n", - " routing.VehicleVar(index_0).SetValues([-1, 0])\n", + " # Add Time Windows constraint.\n", + " time = 'Time'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # allow waiting time (0 min)\n", + " 1020, # maximum time per vehicle (9 hours)\n", + " False, # Don't force start cumul to zero.\n", + " time)\n", + " time_dimension = routing.GetDimensionOrDie(time)\n", + " # Add time window constraints for each location except depot.\n", + " for location_idx in range(17):\n", + " if location_idx == data['depot']:\n", + " continue\n", + " # Vehicle 0 location TW: [9am, 11am]\n", + " index_0 = manager.NodeToIndex(location_idx)\n", + " time_dimension.CumulVar(index_0).SetRange(540, 660)\n", + " routing.VehicleVar(index_0).SetValues([-1, 0])\n", "\n", - " # Vehicle 1 location TW: [11am, 1pm]\n", - " index_1 = manager.NodeToIndex(location_idx+16*1)\n", - " time_dimension.CumulVar(index_1).SetRange(660, 780)\n", - " routing.VehicleVar(index_1).SetValues([-1, 1])\n", + " # Vehicle 1 location TW: [11am, 1pm]\n", + " index_1 = manager.NodeToIndex(location_idx+16*1)\n", + " time_dimension.CumulVar(index_1).SetRange(660, 780)\n", + " routing.VehicleVar(index_1).SetValues([-1, 1])\n", "\n", - " # Vehicle 2 location TW: [1pm, 3pm]\n", - " index_2 = manager.NodeToIndex(location_idx+16*2)\n", - " time_dimension.CumulVar(index_2).SetRange(780, 900)\n", - " routing.VehicleVar(index_2).SetValues([-1, 2])\n", + " # Vehicle 2 location TW: [1pm, 3pm]\n", + " index_2 = manager.NodeToIndex(location_idx+16*2)\n", + " time_dimension.CumulVar(index_2).SetRange(780, 900)\n", + " routing.VehicleVar(index_2).SetValues([-1, 2])\n", "\n", - " # Vehicle 3 location TW: [3pm, 5pm]\n", - " index_3 = manager.NodeToIndex(location_idx+16*3)\n", - " time_dimension.CumulVar(index_3).SetRange(900, 1020)\n", - " routing.VehicleVar(index_3).SetValues([-1, 3])\n", + " # Vehicle 3 location TW: [3pm, 5pm]\n", + " index_3 = manager.NodeToIndex(location_idx+16*3)\n", + " time_dimension.CumulVar(index_3).SetRange(900, 1020)\n", + " routing.VehicleVar(index_3).SetValues([-1, 3])\n", "\n", - " # Add Disjunction so only one node among duplicate is visited\n", - " penalty = 100_000 # Give solver strong incentive to visit one node\n", - " routing.AddDisjunction([index_0, index_1, index_2, index_3], penalty, 1)\n", + " # Add Disjunction so only one node among duplicate is visited\n", + " penalty = 100_000 # Give solver strong incentive to visit one node\n", + " routing.AddDisjunction([index_0, index_1, index_2, index_3], penalty, 1)\n", "\n", - "# Add time window constraints for each vehicle start node.\n", - "depot_idx = data['depot']\n", - "for vehicle_id in range(data['num_vehicles']):\n", - " index = routing.Start(vehicle_id)\n", - " time_dimension.CumulVar(index).SetRange(480, 1020) # (8am, 5pm)\n", + " # Add time window constraints for each vehicle start node.\n", + " depot_idx = data['depot']\n", + " for vehicle_id in range(data['num_vehicles']):\n", + " index = routing.Start(vehicle_id)\n", + " time_dimension.CumulVar(index).SetRange(480, 1020) # (8am, 5pm)\n", "\n", - "# Add time window constraints for each vehicle end node.\n", - "depot_idx = data['depot']\n", - "for vehicle_id in range(data['num_vehicles']):\n", - " index = routing.End(vehicle_id)\n", - " time_dimension.CumulVar(index).SetRange(480, 1020) # (8am, 5pm)\n", - "# [END time_windows_constraint]\n", + " # Add time window constraints for each vehicle end node.\n", + " depot_idx = data['depot']\n", + " for vehicle_id in range(data['num_vehicles']):\n", + " index = routing.End(vehicle_id)\n", + " time_dimension.CumulVar(index).SetRange(480, 1020) # (8am, 5pm)\n", "\n", - "# Instantiate route start and end times to produce feasible times.\n", - "# [START depot_start_end_times]\n", - "for i in range(data['num_vehicles']):\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " time_dimension.CumulVar(routing.Start(i)))\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " time_dimension.CumulVar(routing.End(i)))\n", - "# [END depot_start_end_times]\n", + " # Instantiate route start and end times to produce feasible times.\n", + " for i in range(data['num_vehicles']):\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " time_dimension.CumulVar(routing.Start(i)))\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " time_dimension.CumulVar(routing.End(i)))\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(1)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(1)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if assignment:\n", - " print_solution(manager, routing, assignment)\n", - "else:\n", - " print(\"no solution found !\")\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if assignment:\n", + " print_solution(manager, routing, assignment)\n", + " else:\n", + " print(\"no solution found !\")\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_tokens.ipynb b/examples/notebook/constraint_solver/vrp_tokens.ipynb index e99eab261f..0b37df8695 100644 --- a/examples/notebook/constraint_solver/vrp_tokens.ipynb +++ b/examples/notebook/constraint_solver/vrp_tokens.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple VRP with special locations which need to be visited at end of the route.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,25 +82,8 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Simple VRP with special locations which need to be visited at end of the route.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", "def create_data_model():\n", @@ -159,85 +150,85 @@ " print('Total token of all routes: {}'.format(total_token))\n", "\n", "\n", - "\"\"\"Solve the CVRP problem.\"\"\"\n", - "# Instantiate the data problem.\n", - "data = create_data_model()\n", + "def main():\n", + " \"\"\"Solve the CVRP problem.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "manager = pywrapcp.RoutingIndexManager(len(data['tokens']),\n", - " data['num_vehicles'], data['depot'])\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['tokens']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Create and register a transit callback.\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " del from_index\n", - " del to_index\n", - " return 10\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " del from_index\n", + " del to_index\n", + " return 10\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # null slack\n", - " 3000, # maximum distance per vehicle\n", - " True, # start cumul to zero\n", - " 'distance')\n", - "distance_dimension = routing.GetDimensionOrDie('distance')\n", - "distance_dimension.SetGlobalSpanCostCoefficient(100)\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # null slack\n", + " 3000, # maximum distance per vehicle\n", + " True, # start cumul to zero\n", + " 'distance')\n", + " distance_dimension = routing.GetDimensionOrDie('distance')\n", + " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# Define cost of each arc.\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Token constraint.\n", - "def token_callback(from_index):\n", - " \"\"\"Returns the number of token consumed by the node.\"\"\"\n", - " # Convert from routing variable Index to tokens NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " return data['tokens'][from_node]\n", + " # Add Token constraint.\n", + " def token_callback(from_index):\n", + " \"\"\"Returns the number of token consumed by the node.\"\"\"\n", + " # Convert from routing variable Index to tokens NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " return data['tokens'][from_node]\n", "\n", - "token_callback_index = routing.RegisterUnaryTransitCallback(token_callback)\n", - "routing.AddDimensionWithVehicleCapacity(\n", - " token_callback_index,\n", - " 0, # null capacity slack\n", - " data['vehicle_tokens'], # vehicle maximum tokens\n", - " False, # start cumul to zero\n", - " 'Token')\n", - "# Add constraint: special node can only be visited if token remaining is zero\n", - "token_dimension = routing.GetDimensionOrDie('Token')\n", - "for node in range(1, 6):\n", - " index = manager.NodeToIndex(node)\n", - " routing.solver().Add(token_dimension.CumulVar(index) == 0)\n", + " token_callback_index = routing.RegisterUnaryTransitCallback(token_callback)\n", + " routing.AddDimensionWithVehicleCapacity(\n", + " token_callback_index,\n", + " 0, # null capacity slack\n", + " data['vehicle_tokens'], # vehicle maximum tokens\n", + " False, # start cumul to zero\n", + " 'Token')\n", + " # Add constraint: special node can only be visited if token remaining is zero\n", + " token_dimension = routing.GetDimensionOrDie('Token')\n", + " for node in range(1, 6):\n", + " index = manager.NodeToIndex(node)\n", + " routing.solver().Add(token_dimension.CumulVar(index) == 0)\n", "\n", - "# Instantiate route start and end times to produce feasible times.\n", - "# [START depot_start_end_times]\n", - "for i in range(manager.GetNumberOfVehicles()):\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " token_dimension.CumulVar(routing.Start(i)))\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " token_dimension.CumulVar(routing.End(i)))\n", - "# [END depot_start_end_times]\n", + " # Instantiate route start and end times to produce feasible times.\n", + " for i in range(manager.GetNumberOfVehicles()):\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " token_dimension.CumulVar(routing.Start(i)))\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " token_dimension.CumulVar(routing.End(i)))\n", "\n", - "# Setting first solution heuristic.\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(1)\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(1)\n", "\n", - "# Solve the problem.\n", - "solution = routing.SolveWithParameters(search_parameters)\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(manager, routing, solution)\n", - "else:\n", - " print('No solution found !')\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(manager, routing, solution)\n", + " else:\n", + " print('No solution found !')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrp_with_time_limit.ipynb b/examples/notebook/constraint_solver/vrp_with_time_limit.ipynb index 2b593cc022..52103d61ff 100644 --- a/examples/notebook/constraint_solver/vrp_with_time_limit.ipynb +++ b/examples/notebook/constraint_solver/vrp_with_time_limit.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Vehicles Routing Problem (VRP).\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Vehicles Routing Problem (VRP).\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(manager, routing, solution):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {solution.ObjectiveValue()}')\n", @@ -116,77 +105,62 @@ " print(plan_output)\n", " max_route_distance = max(route_distance, max_route_distance)\n", " print('Maximum of the route distances: {}m'.format(max_route_distance))\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the CVRP problem.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "num_locations = 20\n", - "num_vehicles = 5\n", - "depot = 0\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the CVRP problem.\"\"\"\n", + " # Instantiate the data problem.\n", + " num_locations = 20\n", + " num_vehicles = 5\n", + " depot = 0\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(num_locations, num_vehicles, depot)\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(num_locations, num_vehicles, depot)\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def distance_callback(from_index, to_index):\n", - " # pylint: disable=unused-argument\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " return 1\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " # pylint: disable=unused-argument\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " return 1\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " 3000, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(100)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " 3000, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.log_search = True\n", - "search_parameters.time_limit.FromSeconds(5)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.log_search = True\n", + " search_parameters.time_limit.FromSeconds(5)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(manager, routing, solution)\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(manager, routing, solution)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrpgs.ipynb b/examples/notebook/constraint_solver/vrpgs.ipynb index b7ba24c580..8279e9e152 100644 --- a/examples/notebook/constraint_solver/vrpgs.ipynb +++ b/examples/notebook/constraint_solver/vrpgs.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,28 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 Google LLC\n", - "# Copyright 2015 Tin Arm Engineering AB\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", - "# [START program]\n", - "\"\"\"Simple Vehicles Routing Problem (VRP).\n", + "Simple Vehicles Routing Problem (VRP).\n", "\n", " This is a sample using the routing library python wrapper to solve a VRP\n", " problem.\n", @@ -97,16 +80,21 @@ " http://en.wikipedia.org/wiki/Vehicle_routing_problem.\n", "\n", " Distances are in meters.\n", - "\"\"\"\n", - "\n", - "# [START import]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import functools\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -140,10 +128,8 @@ " data['depot'] = 0\n", " return data\n", "\n", - "# [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(data, manager, routing, assignment):\n", " \"\"\"Prints solution on console.\"\"\"\n", " print(f'Objective: {assignment.ObjectiveValue()}')\n", @@ -164,7 +150,6 @@ " total_distance += route_distance\n", " print('Total Distance of all routes: {}m'.format(total_distance))\n", "\n", - "# [END solution_printer]\n", "\n", "\n", "#######################\n", @@ -214,58 +199,44 @@ " distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(data['num_locations'],\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", - "# [END routing_model]\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Define weight of each edge\n", - "# [START transit_callback]\n", - "distance_evaluator_index = routing.RegisterTransitCallback(\n", - " functools.partial(create_distance_evaluator(data), manager))\n", - "# [END transit_callback]\n", + " # Define weight of each edge\n", + " distance_evaluator_index = routing.RegisterTransitCallback(\n", + " functools.partial(create_distance_evaluator(data), manager))\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator_index)\n", "\n", - "# Add Distance constraint.\n", - "# [START distance_constraint]\n", - "add_distance_dimension(routing, distance_evaluator_index)\n", - "# [END distance_constraint]\n", + " # Add Distance constraint.\n", + " add_distance_dimension(routing, distance_evaluator_index)\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "# [START print_solution]\n", - "if solution:\n", - " print_solution(data, manager, routing, solution)\n", - "else:\n", - " print('No solution found !')\n", - "# [END print_solution]\n", + " # Print solution on console.\n", + " if solution:\n", + " print_solution(data, manager, routing, solution)\n", + " else:\n", + " print('No solution found !')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/constraint_solver/vrptw_store_solution_data.ipynb b/examples/notebook/constraint_solver/vrptw_store_solution_data.ipynb index 752c088e03..7a54eaa191 100644 --- a/examples/notebook/constraint_solver/vrptw_store_solution_data.ipynb +++ b/examples/notebook/constraint_solver/vrptw_store_solution_data.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "VRPTW example that stores routes and cumulative data in an array.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,30 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"VRPTW example that stores routes and cumulative data in an array.\"\"\"\n", - "\n", - "# [START import]\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", - "# [END import]\n", "\n", "\n", - "# [START program_part1]\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -143,10 +131,8 @@ " data['depot'] = 0\n", " return data\n", "\n", - "# [END data_model]\n", "\n", "\n", - "# [START solution_printer]\n", "def print_solution(routes, cumul_data):\n", " \"\"\"Print the solution.\"\"\"\n", " total_time = 0\n", @@ -167,10 +153,8 @@ " route_str += 'Total time: {} min'.format(total_time)\n", " print(route_str)\n", "\n", - "# [END solution_printer]\n", "\n", "\n", - "# [START get_routes]\n", "def get_routes(solution, routing, manager):\n", " \"\"\"Get vehicle routes from a solution and store them in an array.\"\"\"\n", " # Get vehicle routes and store them in a two dimensional array whose\n", @@ -185,10 +169,8 @@ " routes.append(route)\n", " return routes\n", "\n", - "# [END get_routes]\n", "\n", "\n", - "# [START get_cumulative_data]\n", "def get_cumul_data(solution, routing, dimension):\n", " \"\"\"Get cumulative data from a dimension and store it in an array.\"\"\"\n", " # Returns an array cumul_data whose i,j entry contains the minimum and\n", @@ -209,96 +191,79 @@ " cumul_data.append(route_data)\n", " return cumul_data\n", "\n", - "# [END get_cumulative_data]\n", "\n", "\n", - "\"\"\"Solve the VRP with time windows.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", + "def main():\n", + " \"\"\"Solve the VRP with time windows.\"\"\"\n", + " # Instantiate the data problem.\n", + " data = create_data_model()\n", "\n", - "# Create the routing index manager.\n", - "# [START index_manager]\n", - "manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n", - " data['num_vehicles'], data['depot'])\n", - "# [END index_manager]\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n", + " data['num_vehicles'], data['depot'])\n", "\n", - "# Create Routing Model.\n", - "# [START routing_model]\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create Routing Model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# [END routing_model]\n", "\n", - "# Create and register a transit callback.\n", - "# [START transit_callback]\n", - "def time_callback(from_index, to_index):\n", - " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to time matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return data['time_matrix'][from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def time_callback(from_index, to_index):\n", + " \"\"\"Returns the travel time between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to time matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return data['time_matrix'][from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", - "# [END transit_callback]\n", + " transit_callback_index = routing.RegisterTransitCallback(time_callback)\n", "\n", - "# Define cost of each arc.\n", - "# [START arc_cost]\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", - "# [END arc_cost]\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Add Time Windows constraint.\n", - "# [START time_windows_constraint]\n", - "time = 'Time'\n", + " # Add Time Windows constraint.\n", + " time = 'Time'\n", "\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 30, # allow waiting time\n", - " 30, # maximum time per vehicle\n", - " False, # Don't force cumulative time to be 0 at start of routes.\n", - " time)\n", - "time_dimension = routing.GetDimensionOrDie(time)\n", - "# Add time window constraints for each location except depot.\n", - "for location_idx, time_window in enumerate(data['time_windows']):\n", - " if location_idx == 0:\n", - " continue\n", - " index = manager.NodeToIndex(location_idx)\n", - " time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])\n", - "# Add time window constraints for each vehicle start node.\n", - "for vehicle_id in range(data['num_vehicles']):\n", - " index = routing.Start(vehicle_id)\n", - " time_dimension.CumulVar(index).SetRange(data['time_windows'][0][0],\n", - " data['time_windows'][0][1])\n", - "# [END time_windows_constraint]\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 30, # allow waiting time\n", + " 30, # maximum time per vehicle\n", + " False, # Don't force cumulative time to be 0 at start of routes.\n", + " time)\n", + " time_dimension = routing.GetDimensionOrDie(time)\n", + " # Add time window constraints for each location except depot.\n", + " for location_idx, time_window in enumerate(data['time_windows']):\n", + " if location_idx == 0:\n", + " continue\n", + " index = manager.NodeToIndex(location_idx)\n", + " time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1])\n", + " # Add time window constraints for each vehicle start node.\n", + " for vehicle_id in range(data['num_vehicles']):\n", + " index = routing.Start(vehicle_id)\n", + " time_dimension.CumulVar(index).SetRange(data['time_windows'][0][0],\n", + " data['time_windows'][0][1])\n", "\n", - "# Instantiate route start and end times to produce feasible times.\n", - "# [START depot_start_end_times]\n", - "for i in range(data['num_vehicles']):\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " time_dimension.CumulVar(routing.Start(i)))\n", - " routing.AddVariableMinimizedByFinalizer(\n", - " time_dimension.CumulVar(routing.End(i)))\n", - "# [END depot_start_end_times]\n", + " # Instantiate route start and end times to produce feasible times.\n", + " for i in range(data['num_vehicles']):\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " time_dimension.CumulVar(routing.Start(i)))\n", + " routing.AddVariableMinimizedByFinalizer(\n", + " time_dimension.CumulVar(routing.End(i)))\n", "\n", - "# Setting first solution heuristic.\n", - "# [START parameters]\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# [END parameters]\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - "# Solve the problem.\n", - "# [START solve]\n", - "solution = routing.SolveWithParameters(search_parameters)\n", - "# [END solve]\n", + " # Solve the problem.\n", + " solution = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if solution:\n", - " routes = get_routes(solution, routing, manager)\n", - " cumul_data = get_cumul_data(solution, routing, time_dimension)\n", - " print_solution(routes, cumul_data)\n", - "# [END print_solution]\n", + " # Print solution.\n", + " if solution:\n", + " routes = get_routes(solution, routing, manager)\n", + " cumul_data = get_cumul_data(solution, routing, time_dimension)\n", + " print_solution(routes, cumul_data)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/3_jugs_mip.ipynb b/examples/notebook/contrib/3_jugs_mip.ipynb index 2931c49a9f..0d84b2c363 100644 --- a/examples/notebook/contrib/3_jugs_mip.ipynb +++ b/examples/notebook/contrib/3_jugs_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " 3 jugs problem using MIP in Google or-tools.\n", "\n", @@ -101,138 +86,158 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "print('Solver: ', sol)\n", + " print('Solver: ', sol)\n", "\n", - "# using GLPK\n", - "if sol == 'GLPK':\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", - "else:\n", - " # Using CBC\n", - " solver = pywraplp.Solver('CoinsGridCBC',\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", - "\n", - "#\n", - "# data\n", - "#\n", - "n = 15\n", - "start = 0 # start node\n", - "end = 14 # end node\n", - "M = 999 # a large number\n", - "\n", - "nodes = [\n", - " '8,0,0', # start\n", - " '5,0,3',\n", - " '5,3,0',\n", - " '2,3,3',\n", - " '2,5,1',\n", - " '7,0,1',\n", - " '7,1,0',\n", - " '4,1,3',\n", - " '3,5,0',\n", - " '3,2,3',\n", - " '6,2,0',\n", - " '6,0,2',\n", - " '1,5,2',\n", - " '1,4,3',\n", - " '4,4,0' # goal!\n", - "]\n", - "\n", - "# distance\n", - "d = [[M, 1, M, M, M, M, M, M, 1, M, M, M, M, M, M],\n", - " [M, M, 1, M, M, M, M, M, M, M, M, M, M, M, M],\n", - " [M, M, M, 1, M, M, M, M, 1, M, M, M, M, M, M],\n", - " [M, M, M, M, 1, M, M, M, M, M, M, M, M, M, M],\n", - " [M, M, M, M, M, 1, M, M, 1, M, M, M, M, M, M],\n", - " [M, M, M, M, M, M, 1, M, M, M, M, M, M, M, M],\n", - " [M, M, M, M, M, M, M, 1, 1, M, M, M, M, M, M],\n", - " [M, M, M, M, M, M, M, M, M, M, M, M, M, M, 1],\n", - " [M, M, M, M, M, M, M, M, M, 1, M, M, M, M, M],\n", - " [M, 1, M, M, M, M, M, M, M, M, 1, M, M, M, M],\n", - " [M, M, M, M, M, M, M, M, M, M, M, 1, M, M, M],\n", - " [M, 1, M, M, M, M, M, M, M, M, M, M, 1, M, M],\n", - " [M, M, M, M, M, M, M, M, M, M, M, M, M, 1, M],\n", - " [M, 1, M, M, M, M, M, M, M, M, M, M, M, M, 1],\n", - " [M, M, M, M, M, M, M, M, M, M, M, M, M, M, M]]\n", - "\n", - "#\n", - "# variables\n", - "#\n", - "\n", - "# requirements (right hand statement)\n", - "rhs = [solver.IntVar(-1, 1, 'rhs[%i]' % i) for i in range(n)]\n", - "\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[i, j] = solver.IntVar(0, 1, 'x[%i,%i]' % (i, j))\n", - "\n", - "out_flow = [solver.IntVar(0, 1, 'out_flow[%i]' % i) for i in range(n)]\n", - "in_flow = [solver.IntVar(0, 1, 'in_flow[%i]' % i) for i in range(n)]\n", - "\n", - "# length of path, to be minimized\n", - "z = solver.Sum(\n", - " [d[i][j] * x[i, j] for i in range(n) for j in range(n) if d[i][j] < M])\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "for i in range(n):\n", - " if i == start:\n", - " solver.Add(rhs[i] == 1)\n", - " elif i == end:\n", - " solver.Add(rhs[i] == -1)\n", + " # using GLPK\n", + " if sol == 'GLPK':\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", " else:\n", - " solver.Add(rhs[i] == 0)\n", + " # Using CBC\n", + " solver = pywraplp.Solver('CoinsGridCBC',\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "# outflow constraint\n", - "for i in range(n):\n", - " solver.Add(\n", - " out_flow[i] == solver.Sum([x[i, j] for j in range(n) if d[i][j] < M]))\n", + " #\n", + " # data\n", + " #\n", + " n = 15\n", + " start = 0 # start node\n", + " end = 14 # end node\n", + " M = 999 # a large number\n", "\n", - "# inflow constraint\n", - "for j in range(n):\n", - " solver.Add(\n", - " in_flow[j] == solver.Sum([x[i, j] for i in range(n) if d[i][j] < M]))\n", + " nodes = [\n", + " '8,0,0', # start\n", + " '5,0,3',\n", + " '5,3,0',\n", + " '2,3,3',\n", + " '2,5,1',\n", + " '7,0,1',\n", + " '7,1,0',\n", + " '4,1,3',\n", + " '3,5,0',\n", + " '3,2,3',\n", + " '6,2,0',\n", + " '6,0,2',\n", + " '1,5,2',\n", + " '1,4,3',\n", + " '4,4,0' # goal!\n", + " ]\n", "\n", - "# inflow = outflow\n", - "for i in range(n):\n", - " solver.Add(out_flow[i] - in_flow[i] == rhs[i])\n", + " # distance\n", + " d = [[M, 1, M, M, M, M, M, M, 1, M, M, M, M, M, M],\n", + " [M, M, 1, M, M, M, M, M, M, M, M, M, M, M, M],\n", + " [M, M, M, 1, M, M, M, M, 1, M, M, M, M, M, M],\n", + " [M, M, M, M, 1, M, M, M, M, M, M, M, M, M, M],\n", + " [M, M, M, M, M, 1, M, M, 1, M, M, M, M, M, M],\n", + " [M, M, M, M, M, M, 1, M, M, M, M, M, M, M, M],\n", + " [M, M, M, M, M, M, M, 1, 1, M, M, M, M, M, M],\n", + " [M, M, M, M, M, M, M, M, M, M, M, M, M, M, 1],\n", + " [M, M, M, M, M, M, M, M, M, 1, M, M, M, M, M],\n", + " [M, 1, M, M, M, M, M, M, M, M, 1, M, M, M, M],\n", + " [M, M, M, M, M, M, M, M, M, M, M, 1, M, M, M],\n", + " [M, 1, M, M, M, M, M, M, M, M, M, M, 1, M, M],\n", + " [M, M, M, M, M, M, M, M, M, M, M, M, M, 1, M],\n", + " [M, 1, M, M, M, M, M, M, M, M, M, M, M, M, 1],\n", + " [M, M, M, M, M, M, M, M, M, M, M, M, M, M, M]]\n", "\n", - "# objective\n", - "objective = solver.Minimize(z)\n", + " #\n", + " # variables\n", + " #\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", + " # requirements (right hand statement)\n", + " rhs = [solver.IntVar(-1, 1, 'rhs[%i]' % i) for i in range(n)]\n", "\n", - "print()\n", - "print('z: ', int(solver.Objective().Value()))\n", + " x = {}\n", + " for i in range(n):\n", + " for j in range(n):\n", + " x[i, j] = solver.IntVar(0, 1, 'x[%i,%i]' % (i, j))\n", "\n", - "t = start\n", - "while t != end:\n", - " print(nodes[t], '->', end=' ')\n", + " out_flow = [solver.IntVar(0, 1, 'out_flow[%i]' % i) for i in range(n)]\n", + " in_flow = [solver.IntVar(0, 1, 'in_flow[%i]' % i) for i in range(n)]\n", + "\n", + " # length of path, to be minimized\n", + " z = solver.Sum(\n", + " [d[i][j] * x[i, j] for i in range(n) for j in range(n) if d[i][j] < M])\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " for i in range(n):\n", + " if i == start:\n", + " solver.Add(rhs[i] == 1)\n", + " elif i == end:\n", + " solver.Add(rhs[i] == -1)\n", + " else:\n", + " solver.Add(rhs[i] == 0)\n", + "\n", + " # outflow constraint\n", + " for i in range(n):\n", + " solver.Add(\n", + " out_flow[i] == solver.Sum([x[i, j] for j in range(n) if d[i][j] < M]))\n", + "\n", + " # inflow constraint\n", " for j in range(n):\n", - " if x[t, j].SolutionValue() == 1:\n", - " print(nodes[j])\n", - " t = j\n", - " break\n", + " solver.Add(\n", + " in_flow[j] == solver.Sum([x[i, j] for i in range(n) if d[i][j] < M]))\n", "\n", - "print()\n", - "print('walltime :', solver.WallTime(), 'ms')\n", - "if sol == 'CBC':\n", - " print('iterations:', solver.Iterations())\n", + " # inflow = outflow\n", + " for i in range(n):\n", + " solver.Add(out_flow[i] - in_flow[i] == rhs[i])\n", + "\n", + " # objective\n", + " objective = solver.Minimize(z)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", + "\n", + " print()\n", + " print('z: ', int(solver.Objective().Value()))\n", + "\n", + " t = start\n", + " while t != end:\n", + " print(nodes[t], '->', end=' ')\n", + " for j in range(n):\n", + " if x[t, j].SolutionValue() == 1:\n", + " print(nodes[j])\n", + " t = j\n", + " break\n", + "\n", + " print()\n", + " print('walltime :', solver.WallTime(), 'ms')\n", + " if sol == 'CBC':\n", + " print('iterations:', solver.Iterations())\n", + "\n", + "\n", + "\n", + "sol = 'CBC'\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/3_jugs_regular.ipynb b/examples/notebook/contrib/3_jugs_regular.ipynb index 74addaf5ce..f7f829e96c 100644 --- a/examples/notebook/contrib/3_jugs_regular.ipynb +++ b/examples/notebook/contrib/3_jugs_regular.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " 3 jugs problem using regular constraint in Google CP Solver.\n", "\n", @@ -121,8 +106,16 @@ " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", "\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "from collections import defaultdict\n", "\n", @@ -196,137 +189,147 @@ " a[i + 1] == solver.Element(d2_flatten, ((a[i]) * S) + (x[i] - 1)))\n", "\n", "\n", + "def main(n):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('3 jugs problem using regular constraint')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('3 jugs problem using regular constraint')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# the DFA (for regular)\n", - "n_states = 14\n", - "input_max = 15\n", - "initial_state = 1 # 0 is for the failing state\n", - "accepting_states = [15]\n", + " # the DFA (for regular)\n", + " n_states = 14\n", + " input_max = 15\n", + " initial_state = 1 # 0 is for the failing state\n", + " accepting_states = [15]\n", "\n", - "##\n", - "# Manually crafted DFA\n", - "# (from the adjacency matrix used in the other models)\n", - "##\n", - "# transition_fn = [\n", - "# # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5\n", - "# [0, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0], # 1\n", - "# [0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # 2\n", - "# [0, 0, 0, 4, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0], # 3\n", - "# [0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # 4\n", - "# [0, 0, 0, 0, 0, 6, 0, 0, 9, 0, 0, 0, 0, 0, 0], # 5\n", - "# [0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0], # 6\n", - "# [0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0], # 7\n", - "# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15], # 8\n", - "# [0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0], # 9\n", - "# [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0], # 10\n", - "# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0], # 11\n", - "# [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0], # 12\n", - "# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0], # 13\n", - "# [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15], # 14\n", - "# # 15\n", - "# ]\n", + " ##\n", + " # Manually crafted DFA\n", + " # (from the adjacency matrix used in the other models)\n", + " ##\n", + " # transition_fn = [\n", + " # # 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5\n", + " # [0, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0], # 1\n", + " # [0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # 2\n", + " # [0, 0, 0, 4, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0], # 3\n", + " # [0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # 4\n", + " # [0, 0, 0, 0, 0, 6, 0, 0, 9, 0, 0, 0, 0, 0, 0], # 5\n", + " # [0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0], # 6\n", + " # [0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0], # 7\n", + " # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15], # 8\n", + " # [0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0], # 9\n", + " # [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0], # 10\n", + " # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0], # 11\n", + " # [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0], # 12\n", + " # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0], # 13\n", + " # [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15], # 14\n", + " # # 15\n", + " # ]\n", "\n", - "#\n", - "# However, the DFA is easy to create from adjacency lists.\n", - "#\n", - "states = [\n", - " [2, 9], # state 1\n", - " [3], # state 2\n", - " [4, 9], # state 3\n", - " [5], # state 4\n", - " [6, 9], # state 5\n", - " [7], # state 6\n", - " [8, 9], # state 7\n", - " [15], # state 8\n", - " [10], # state 9\n", - " [11], # state 10\n", - " [12], # state 11\n", - " [13], # state 12\n", - " [14], # state 13\n", - " [15] # state 14\n", - "]\n", + " #\n", + " # However, the DFA is easy to create from adjacency lists.\n", + " #\n", + " states = [\n", + " [2, 9], # state 1\n", + " [3], # state 2\n", + " [4, 9], # state 3\n", + " [5], # state 4\n", + " [6, 9], # state 5\n", + " [7], # state 6\n", + " [8, 9], # state 7\n", + " [15], # state 8\n", + " [10], # state 9\n", + " [11], # state 10\n", + " [12], # state 11\n", + " [13], # state 12\n", + " [14], # state 13\n", + " [15] # state 14\n", + " ]\n", "\n", - "transition_fn = []\n", - "for i in range(n_states):\n", - " row = []\n", - " for j in range(1, input_max + 1):\n", - " if j in states[i]:\n", - " row.append(j)\n", - " else:\n", - " row.append(0)\n", - " transition_fn.append(row)\n", + " transition_fn = []\n", + " for i in range(n_states):\n", + " row = []\n", + " for j in range(1, input_max + 1):\n", + " if j in states[i]:\n", + " row.append(j)\n", + " else:\n", + " row.append(0)\n", + " transition_fn.append(row)\n", "\n", - "#\n", - "# The name of the nodes, for printing\n", - "# the solution.\n", - "#\n", - "nodes = [\n", - " '8,0,0', # 1 start\n", - " '5,0,3', # 2\n", - " '5,3,0', # 3\n", - " '2,3,3', # 4\n", - " '2,5,1', # 5\n", - " '7,0,1', # 6\n", - " '7,1,0', # 7\n", - " '4,1,3', # 8\n", - " '3,5,0', # 9\n", - " '3,2,3', # 10\n", - " '6,2,0', # 11\n", - " '6,0,2', # 12\n", - " '1,5,2', # 13\n", - " '1,4,3', # 14\n", - " '4,4,0' # 15 goal\n", - "]\n", + " #\n", + " # The name of the nodes, for printing\n", + " # the solution.\n", + " #\n", + " nodes = [\n", + " '8,0,0', # 1 start\n", + " '5,0,3', # 2\n", + " '5,3,0', # 3\n", + " '2,3,3', # 4\n", + " '2,5,1', # 5\n", + " '7,0,1', # 6\n", + " '7,1,0', # 7\n", + " '4,1,3', # 8\n", + " '3,5,0', # 9\n", + " '3,2,3', # 10\n", + " '6,2,0', # 11\n", + " '6,0,2', # 12\n", + " '1,5,2', # 13\n", + " '1,4,3', # 14\n", + " '4,4,0' # 15 goal\n", + " ]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(1, input_max, 'x[%i]' % i) for i in range(n)]\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(1, input_max, 'x[%i]' % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "regular(x, n_states, input_max, transition_fn, initial_state,\n", - " accepting_states)\n", + " #\n", + " # constraints\n", + " #\n", + " regular(x, n_states, input_max, transition_fn, initial_state,\n", + " accepting_states)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "x_val = []\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " x_val = [1] + [x[i].Value() for i in range(n)]\n", - " print('x:', x_val)\n", - " for i in range(1, n + 1):\n", - " print('%s -> %s' % (nodes[x_val[i - 1] - 1], nodes[x_val[i] - 1]))\n", + " num_solutions = 0\n", + " x_val = []\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " x_val = [1] + [x[i].Value() for i in range(n)]\n", + " print('x:', x_val)\n", + " for i in range(1, n + 1):\n", + " print('%s -> %s' % (nodes[x_val[i - 1] - 1], nodes[x_val[i] - 1]))\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", "\n", - "if num_solutions > 0:\n", - " print()\n", - " print('num_solutions:', num_solutions)\n", - " print('failures:', solver.Failures())\n", - " print('branches:', solver.Branches())\n", - " print('WallTime:', solver.WallTime(), 'ms')\n", + " if num_solutions > 0:\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", - "# return the solution (or an empty array)\n", - "return x_val\n", + " # return the solution (or an empty array)\n", + " return x_val\n", "\n", "\n", "# Search for a minimum solution by increasing\n", - "# the length of the state array." + "# the length of the state array.\n", + "for n in range(1, 15):\n", + " result = main(n)\n", + " result_len = len(result)\n", + " if result_len:\n", + " print()\n", + " print('Found a solution of length %i:' % result_len, result)\n", + " print()\n", + " break\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/a_round_of_golf.ipynb b/examples/notebook/contrib/a_round_of_golf.ipynb index 8720434ac4..2ff0afcd88 100644 --- a/examples/notebook/contrib/a_round_of_golf.ipynb +++ b/examples/notebook/contrib/a_round_of_golf.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " A Round of Golf puzzle (Dell Logic Puzzles) in Google CP Solver.\n", "\n", @@ -138,103 +123,115 @@ " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", "\n", - "\"\"\"\n", - "\n", "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"All interval\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"All interval\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", - "[Jack, Bill, Paul, Frank] = [i for i in range(n)]\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", + " [Jack, Bill, Paul, Frank] = [i for i in range(n)]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "last_name = [solver.IntVar(0, n - 1, \"last_name[%i]\" % i) for i in range(n)]\n", - "[Green, Clubb, Sands, Carter] = last_name\n", + " #\n", + " # declare variables\n", + " #\n", + " last_name = [solver.IntVar(0, n - 1, \"last_name[%i]\" % i) for i in range(n)]\n", + " [Green, Clubb, Sands, Carter] = last_name\n", "\n", - "job = [solver.IntVar(0, n - 1, \"job[%i]\" % i) for i in range(n)]\n", - "[cook, maintenance_man, clerk, caddy] = job\n", + " job = [solver.IntVar(0, n - 1, \"job[%i]\" % i) for i in range(n)]\n", + " [cook, maintenance_man, clerk, caddy] = job\n", "\n", - "score = [solver.IntVar(70, 85, \"score[%i]\" % i) for i in range(n)]\n", + " score = [solver.IntVar(70, 85, \"score[%i]\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(last_name))\n", - "solver.Add(solver.AllDifferent(job))\n", - "solver.Add(solver.AllDifferent(score))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(last_name))\n", + " solver.Add(solver.AllDifferent(job))\n", + " solver.Add(solver.AllDifferent(score))\n", "\n", - "# 1. Bill, who is not the maintenance man, plays golf often and had\n", - "# the lowest score of the foursome.\n", - "solver.Add(Bill != maintenance_man)\n", - "solver.Add(score[Bill] < score[Jack])\n", - "solver.Add(score[Bill] < score[Paul])\n", - "solver.Add(score[Bill] < score[Frank])\n", + " # 1. Bill, who is not the maintenance man, plays golf often and had\n", + " # the lowest score of the foursome.\n", + " solver.Add(Bill != maintenance_man)\n", + " solver.Add(score[Bill] < score[Jack])\n", + " solver.Add(score[Bill] < score[Paul])\n", + " solver.Add(score[Bill] < score[Frank])\n", "\n", - "# 2. Mr. Clubb, who isn't Paul, hit several balls into the woods and\n", - "# scored ten strokes more than the pro-shop clerk.\n", - "solver.Add(Clubb != Paul)\n", - "solver.Add(solver.Element(score, Clubb) == solver.Element(score, clerk) + 10)\n", + " # 2. Mr. Clubb, who isn't Paul, hit several balls into the woods and\n", + " # scored ten strokes more than the pro-shop clerk.\n", + " solver.Add(Clubb != Paul)\n", + " solver.Add(solver.Element(score, Clubb) == solver.Element(score, clerk) + 10)\n", "\n", - "# 3. In some order, Frank and the caddy scored four and seven more\n", - "# strokes than Mr. Sands.\n", - "solver.Add(Frank != caddy)\n", - "solver.Add(Frank != Sands)\n", - "solver.Add(caddy != Sands)\n", + " # 3. In some order, Frank and the caddy scored four and seven more\n", + " # strokes than Mr. Sands.\n", + " solver.Add(Frank != caddy)\n", + " solver.Add(Frank != Sands)\n", + " solver.Add(caddy != Sands)\n", "\n", - "b3_a_1 = solver.IsEqualVar(solver.Element(score, Sands) + 4, score[Frank])\n", - "b3_a_2 = solver.IsEqualVar(\n", - " solver.Element(score, caddy),\n", - " solver.Element(score, Sands) + 7)\n", + " b3_a_1 = solver.IsEqualVar(solver.Element(score, Sands) + 4, score[Frank])\n", + " b3_a_2 = solver.IsEqualVar(\n", + " solver.Element(score, caddy),\n", + " solver.Element(score, Sands) + 7)\n", "\n", - "b3_b_1 = solver.IsEqualVar(solver.Element(score, Sands) + 7, score[Frank])\n", - "b3_b_2 = solver.IsEqualVar(\n", - " solver.Element(score, caddy),\n", - " solver.Element(score, Sands) + 4)\n", + " b3_b_1 = solver.IsEqualVar(solver.Element(score, Sands) + 7, score[Frank])\n", + " b3_b_2 = solver.IsEqualVar(\n", + " solver.Element(score, caddy),\n", + " solver.Element(score, Sands) + 4)\n", "\n", - "solver.Add((b3_a_1 * b3_a_2) + (b3_b_1 * b3_b_2) == 1)\n", + " solver.Add((b3_a_1 * b3_a_2) + (b3_b_1 * b3_b_2) == 1)\n", "\n", - "# 4. Mr. Carter thought his score of 78 was one of his better games,\n", - "# even though Frank's score was lower.\n", - "solver.Add(Frank != Carter)\n", - "solver.Add(solver.Element(score, Carter) == 78)\n", - "solver.Add(score[Frank] < solver.Element(score, Carter))\n", + " # 4. Mr. Carter thought his score of 78 was one of his better games,\n", + " # even though Frank's score was lower.\n", + " solver.Add(Frank != Carter)\n", + " solver.Add(solver.Element(score, Carter) == 78)\n", + " solver.Add(score[Frank] < solver.Element(score, Carter))\n", "\n", - "# 5. None of the four scored exactly 81 strokes.\n", - "[solver.Add(score[i] != 81) for i in range(n)]\n", + " # 5. None of the four scored exactly 81 strokes.\n", + " [solver.Add(score[i] != 81) for i in range(n)]\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(last_name)\n", - "solution.Add(job)\n", - "solution.Add(score)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(last_name)\n", + " solution.Add(job)\n", + " solution.Add(score)\n", "\n", - "db = solver.Phase(last_name + job + score, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.INT_VALUE_DEFAULT)\n", + " db = solver.Phase(last_name + job + score, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"last_name:\", [last_name[i].Value() for i in range(n)])\n", - " print(\"job :\", [job[i].Value() for i in range(n)])\n", - " print(\"score :\", [score[i].Value() for i in range(n)])\n", - " num_solutions += 1\n", - " print()\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"last_name:\", [last_name[i].Value() for i in range(n)])\n", + " print(\"job :\", [job[i].Value() for i in range(n)])\n", + " print(\"score :\", [score[i].Value() for i in range(n)])\n", + " num_solutions += 1\n", + " print()\n", "\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/all_interval.ipynb b/examples/notebook/contrib/all_interval.ipynb index b2485cee8c..ec286d5b93 100644 --- a/examples/notebook/contrib/all_interval.ipynb +++ b/examples/notebook/contrib/all_interval.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " All interval problem in Google CP Solver.\n", "\n", @@ -124,65 +109,79 @@ " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", "\n", - "\"\"\"\n", - "\n", "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(n=12):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"All interval\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"All interval\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"n:\", n)\n", + " #\n", + " # data\n", + " #\n", + " print(\"n:\", n)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(1, n, \"x[%i]\" % i) for i in range(n)]\n", - "diffs = [solver.IntVar(1, n - 1, \"diffs[%i]\" % i) for i in range(n - 1)]\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(1, n, \"x[%i]\" % i) for i in range(n)]\n", + " diffs = [solver.IntVar(1, n - 1, \"diffs[%i]\" % i) for i in range(n - 1)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", - "solver.Add(solver.AllDifferent(diffs))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", + " solver.Add(solver.AllDifferent(diffs))\n", "\n", - "for k in range(n - 1):\n", - " solver.Add(diffs[k] == abs(x[k + 1] - x[k]))\n", + " for k in range(n - 1):\n", + " solver.Add(diffs[k] == abs(x[k + 1] - x[k]))\n", "\n", - "# symmetry breaking\n", - "solver.Add(x[0] < x[n - 1])\n", - "solver.Add(diffs[0] < diffs[1])\n", + " # symmetry breaking\n", + " solver.Add(x[0] < x[n - 1])\n", + " solver.Add(diffs[0] < diffs[1])\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(diffs)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(diffs)\n", "\n", - "db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + " db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"x:\", [x[i].Value() for i in range(n)])\n", - " print(\"diffs:\", [diffs[i].Value() for i in range(n - 1)])\n", - " num_solutions += 1\n", - " print()\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"x:\", [x[i].Value() for i in range(n)])\n", + " print(\"diffs:\", [diffs[i].Value() for i in range(n - 1)])\n", + " num_solutions += 1\n", + " print()\n", "\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "n = 12\n" + "\n", + "n = 12\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "main(n)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/alldifferent_except_0.ipynb b/examples/notebook/contrib/alldifferent_except_0.ipynb index 9a2826093d..c8fa4af119 100644 --- a/examples/notebook/contrib/alldifferent_except_0.ipynb +++ b/examples/notebook/contrib/alldifferent_except_0.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " All different except 0 Google CP Solver.\n", "\n", @@ -122,9 +107,17 @@ " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", "\n", - "\"\"\"\n", - "\n", "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "#\n", @@ -153,47 +146,51 @@ " ]\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Alldifferent except 0\")\n", + "def main(unused_argv):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Alldifferent except 0\")\n", "\n", - "# data\n", - "n = 7\n", + " # data\n", + " n = 7\n", "\n", - "# declare variables\n", - "x = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", - "# Number of zeros.\n", - "z = solver.Sum([x[i] == 0 for i in range(n)]).VarWithName(\"z\")\n", + " # declare variables\n", + " x = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", + " # Number of zeros.\n", + " z = solver.Sum([x[i] == 0 for i in range(n)]).VarWithName(\"z\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "alldifferent_except_0(solver, x)\n", + " #\n", + " # constraints\n", + " #\n", + " alldifferent_except_0(solver, x)\n", "\n", - "# we require 2 0's\n", - "solver.Add(z == 2)\n", + " # we require 2 0's\n", + " solver.Add(z == 2)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([x[i] for i in range(n)])\n", - "solution.Add(z)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([x[i] for i in range(n)])\n", + " solution.Add(z)\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase([x[i] for i in range(n)], solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE), [collector])\n", + " collector = solver.AllSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase([x[i] for i in range(n)], solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE), [collector])\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "for s in range(num_solutions):\n", - " print(\"x:\", [collector.Value(s, x[i]) for i in range(n)])\n", - " print(\"z:\", collector.Value(s, z))\n", - " print()\n", + " num_solutions = collector.SolutionCount()\n", + " for s in range(num_solutions):\n", + " print(\"x:\", [collector.Value(s, x[i]) for i in range(n)])\n", + " print(\"z:\", collector.Value(s, z))\n", + " print()\n", "\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/alphametic.ipynb b/examples/notebook/contrib/alphametic.ipynb index c2f47acbe2..d852b8bd87 100644 --- a/examples/notebook/contrib/alphametic.ipynb +++ b/examples/notebook/contrib/alphametic.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Generic alphametic solver in Google CP Solver.\n", "\n", @@ -117,99 +102,109 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "import re\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(problem_str=\"SEND+MORE=MONEY\", base=10):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Send most money\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Send most money\")\n", "\n", - "# data\n", - "print(\"\\nproblem:\", problem_str)\n", + " # data\n", + " print(\"\\nproblem:\", problem_str)\n", "\n", - "# convert to array.\n", - "problem = re.split(\"[\\s+=]\", problem_str)\n", + " # convert to array.\n", + " problem = re.split(\"[\\s+=]\", problem_str)\n", "\n", - "p_len = len(problem)\n", - "print(\"base:\", base)\n", + " p_len = len(problem)\n", + " print(\"base:\", base)\n", "\n", - "# create the lookup table: list of (digit : ix)\n", - "a = sorted(set(\"\".join(problem)))\n", - "n = len(a)\n", - "lookup = dict(list(zip(a, list(range(n)))))\n", + " # create the lookup table: list of (digit : ix)\n", + " a = sorted(set(\"\".join(problem)))\n", + " n = len(a)\n", + " lookup = dict(list(zip(a, list(range(n)))))\n", "\n", - "# length of each number\n", - "lens = list(map(len, problem))\n", + " # length of each number\n", + " lens = list(map(len, problem))\n", "\n", - "#\n", - "# declare variables\n", - "#\n", + " #\n", + " # declare variables\n", + " #\n", "\n", - "# the digits\n", - "x = [solver.IntVar(0, base - 1, \"x[%i]\" % i) for i in range(n)]\n", - "# the sums of each number (e.g. the three numbers SEND, MORE, MONEY)\n", - "sums = [solver.IntVar(1, 10**(lens[i]) - 1) for i in range(p_len)]\n", + " # the digits\n", + " x = [solver.IntVar(0, base - 1, \"x[%i]\" % i) for i in range(n)]\n", + " # the sums of each number (e.g. the three numbers SEND, MORE, MONEY)\n", + " sums = [solver.IntVar(1, 10**(lens[i]) - 1) for i in range(p_len)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", "\n", - "ix = 0\n", - "for prob in problem:\n", - " this_len = len(prob)\n", - "\n", - " # sum all the digits with proper exponents to a number\n", - " solver.Add(\n", - " sums[ix] == solver.Sum([(base**i) * x[lookup[prob[this_len - i - 1]]]\n", - " for i in range(this_len)[::-1]]))\n", - " # leading digits must be > 0\n", - " solver.Add(x[lookup[prob[0]]] > 0)\n", - " ix += 1\n", - "\n", - "# the last number is the sum of the previous numbers\n", - "solver.Add(solver.Sum([sums[i] for i in range(p_len - 1)]) == sums[-1])\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(sums)\n", - "\n", - "db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"\\nsolution #%i\" % num_solutions)\n", - " for i in range(n):\n", - " print(a[i], \"=\", x[i].Value())\n", - " print()\n", + " ix = 0\n", " for prob in problem:\n", - " for p in prob:\n", - " print(p, end=\" \")\n", + " this_len = len(prob)\n", + "\n", + " # sum all the digits with proper exponents to a number\n", + " solver.Add(\n", + " sums[ix] == solver.Sum([(base**i) * x[lookup[prob[this_len - i - 1]]]\n", + " for i in range(this_len)[::-1]]))\n", + " # leading digits must be > 0\n", + " solver.Add(x[lookup[prob[0]]] > 0)\n", + " ix += 1\n", + "\n", + " # the last number is the sum of the previous numbers\n", + " solver.Add(solver.Sum([sums[i] for i in range(p_len - 1)]) == sums[-1])\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(sums)\n", + "\n", + " db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"\\nsolution #%i\" % num_solutions)\n", + " for i in range(n):\n", + " print(a[i], \"=\", x[i].Value())\n", " print()\n", - " print()\n", - " for prob in problem:\n", - " for p in prob:\n", - " print(x[lookup[p]].Value(), end=\" \")\n", + " for prob in problem:\n", + " for p in prob:\n", + " print(p, end=\" \")\n", + " print()\n", + " print()\n", + " for prob in problem:\n", + " for p in prob:\n", + " print(x[lookup[p]].Value(), end=\" \")\n", + " print()\n", + "\n", + " print(\"sums:\", [sums[i].Value() for i in range(p_len)])\n", " print()\n", "\n", - " print(\"sums:\", [sums[i].Value() for i in range(p_len)])\n", - " print()\n", + " print(\"\\nnum_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print(\"\\nnum_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "def test_problems(base=10):\n", " problems = [\n", @@ -223,7 +218,17 @@ "\n", "\n", "problem = \"SEND+MORE=MONEY\"\n", - "base = 10\n" + "base = 10\n", + "if len(sys.argv) > 1:\n", + " problem = sys.argv[1]\n", + "if len(sys.argv) > 2:\n", + " base = int(sys.argv[2])\n", + "\n", + "if problem == \"TEST\" or problem == \"test\":\n", + " test_problems(base)\n", + "else:\n", + " main(problem, base)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/assignment.ipynb b/examples/notebook/contrib/assignment.ipynb index bb13613a90..4c55219fd6 100644 --- a/examples/notebook/contrib/assignment.ipynb +++ b/examples/notebook/contrib/assignment.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Assignment problem in Google CP Solver.\n", "\n", @@ -104,94 +89,106 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"n-queens\")\n", + "def main(cost, rows, cols):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"n-queens\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# declare variables\n", - "total_cost = solver.IntVar(0, 100, \"total_cost\")\n", - "x = []\n", - "for i in range(rows):\n", - " t = []\n", - " for j in range(cols):\n", - " t.append(solver.IntVar(0, 1, \"x[%i,%i]\" % (i, j)))\n", - " x.append(t)\n", - "x_flat = [x[i][j] for i in range(rows) for j in range(cols)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# total_cost\n", - "solver.Add(total_cost == solver.Sum(\n", - " [solver.ScalProd(x_row, cost_row) for (x_row, cost_row) in zip(x, cost)]))\n", - "\n", - "# exacly one assignment per row, all rows must be assigned\n", - "[\n", - " solver.Add(solver.Sum([x[row][j]\n", - " for j in range(cols)]) == 1)\n", - " for row in range(rows)\n", - "]\n", - "\n", - "# zero or one assignments per column\n", - "[\n", - " solver.Add(solver.Sum([x[i][col]\n", - " for i in range(rows)]) <= 1)\n", - " for col in range(cols)\n", - "]\n", - "\n", - "objective = solver.Minimize(total_cost, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x_flat)\n", - "solution.Add(total_cost)\n", - "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(x_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"total_cost:\", total_cost.Value())\n", + " # declare variables\n", + " total_cost = solver.IntVar(0, 100, \"total_cost\")\n", + " x = []\n", " for i in range(rows):\n", + " t = []\n", " for j in range(cols):\n", - " print(x[i][j].Value(), end=\" \")\n", + " t.append(solver.IntVar(0, 1, \"x[%i,%i]\" % (i, j)))\n", + " x.append(t)\n", + " x_flat = [x[i][j] for i in range(rows) for j in range(cols)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # total_cost\n", + " solver.Add(total_cost == solver.Sum(\n", + " [solver.ScalProd(x_row, cost_row) for (x_row, cost_row) in zip(x, cost)]))\n", + "\n", + " # exacly one assignment per row, all rows must be assigned\n", + " [\n", + " solver.Add(solver.Sum([x[row][j]\n", + " for j in range(cols)]) == 1)\n", + " for row in range(rows)\n", + " ]\n", + "\n", + " # zero or one assignments per column\n", + " [\n", + " solver.Add(solver.Sum([x[i][col]\n", + " for i in range(rows)]) <= 1)\n", + " for col in range(cols)\n", + " ]\n", + "\n", + " objective = solver.Minimize(total_cost, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x_flat)\n", + " solution.Add(total_cost)\n", + "\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(x_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"total_cost:\", total_cost.Value())\n", + " for i in range(rows):\n", + " for j in range(cols):\n", + " print(x[i][j].Value(), end=\" \")\n", + " print()\n", " print()\n", + "\n", + " for i in range(rows):\n", + " print(\"Task:\", i, end=\" \")\n", + " for j in range(cols):\n", + " if x[i][j].Value() == 1:\n", + " print(\" is done by \", j)\n", + " print()\n", + "\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", + "\n", " print()\n", - "\n", - " for i in range(rows):\n", - " print(\"Task:\", i, end=\" \")\n", - " for j in range(cols):\n", - " if x[i][j].Value() == 1:\n", - " print(\" is done by \", j)\n", - " print()\n", - "\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", "\n", "# Problem instance\n", "# hakank: I added the fifth column to make it more\n", - "# interestingrows = 4\n", + "# interesting\n", + "rows = 4\n", "cols = 5\n", "cost = [[14, 5, 8, 7, 15], [2, 12, 6, 5, 3], [7, 8, 3, 9, 7], [2, 4, 6, 10, 1]]\n", + "\n", + "main(cost, rows, cols)\n", "\n" ] } diff --git a/examples/notebook/contrib/assignment6_mip.ipynb b/examples/notebook/contrib/assignment6_mip.ipynb index 26fba5741c..c405a2c19e 100644 --- a/examples/notebook/contrib/assignment6_mip.ipynb +++ b/examples/notebook/contrib/assignment6_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Assignment problem using MIP in Google or-tools.\n", "\n", @@ -113,112 +98,132 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", - "print('Solver: ', sol)\n", + " # Create the solver.\n", + " print('Solver: ', sol)\n", "\n", - "# using GLPK\n", - "if sol == 'GLPK':\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", - "else:\n", - " # Using CBC\n", - " solver = pywraplp.Solver('CoinsGridCBC',\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " # using GLPK\n", + " if sol == 'GLPK':\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", + " else:\n", + " # Using CBC\n", + " solver = pywraplp.Solver('CoinsGridCBC',\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# number of agents\n", - "m = 8\n", + " # number of agents\n", + " m = 8\n", "\n", - "# number of tasks\n", - "n = 8\n", + " # number of tasks\n", + " n = 8\n", "\n", - "# set of agents\n", - "I = list(range(m))\n", + " # set of agents\n", + " I = list(range(m))\n", "\n", - "# set of tasks\n", - "J = list(range(n))\n", + " # set of tasks\n", + " J = list(range(n))\n", "\n", - "# cost of allocating task j to agent i\n", - "# \"\"\"\n", - "# These data correspond to an example from [Christofides].\n", - "#\n", - "# Optimal solution is 76\n", - "# \"\"\"\n", - "c = [[13, 21, 20, 12, 8, 26, 22, 11], [12, 36, 25, 41, 40, 11, 4, 8],\n", - " [35, 32, 13, 36, 26, 21, 13, 37], [34, 54, 7, 8, 12, 22, 11, 40],\n", - " [21, 6, 45, 18, 24, 34, 12, 48], [42, 19, 39, 15, 14, 16, 28, 46],\n", - " [16, 34, 38, 3, 34, 40, 22, 24], [26, 20, 5, 17, 45, 31, 37, 43]]\n", + " # cost of allocating task j to agent i\n", + " # \"\"\"\n", + " # These data correspond to an example from [Christofides].\n", + " #\n", + " # Optimal solution is 76\n", + " # \"\"\"\n", + " c = [[13, 21, 20, 12, 8, 26, 22, 11], [12, 36, 25, 41, 40, 11, 4, 8],\n", + " [35, 32, 13, 36, 26, 21, 13, 37], [34, 54, 7, 8, 12, 22, 11, 40],\n", + " [21, 6, 45, 18, 24, 34, 12, 48], [42, 19, 39, 15, 14, 16, 28, 46],\n", + " [16, 34, 38, 3, 34, 40, 22, 24], [26, 20, 5, 17, 45, 31, 37, 43]]\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "# For the output: the assignment as task number.\n", - "assigned = [solver.IntVar(0, 10000, 'assigned[%i]' % j) for j in J]\n", + " # For the output: the assignment as task number.\n", + " assigned = [solver.IntVar(0, 10000, 'assigned[%i]' % j) for j in J]\n", "\n", - "costs = [solver.IntVar(0, 10000, 'costs[%i]' % i) for i in I]\n", + " costs = [solver.IntVar(0, 10000, 'costs[%i]' % i) for i in I]\n", "\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[i, j] = solver.IntVar(0, 1, 'x[%i,%i]' % (i, j))\n", + " x = {}\n", + " for i in range(n):\n", + " for j in range(n):\n", + " x[i, j] = solver.IntVar(0, 1, 'x[%i,%i]' % (i, j))\n", "\n", - "# total cost, to be minimized\n", - "z = solver.Sum([c[i][j] * x[i, j] for i in I for j in J])\n", + " # total cost, to be minimized\n", + " z = solver.Sum([c[i][j] * x[i, j] for i in I for j in J])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "# each agent can perform at most one task\n", - "for i in I:\n", - " solver.Add(solver.Sum([x[i, j] for j in J]) <= 1)\n", + " #\n", + " # constraints\n", + " #\n", + " # each agent can perform at most one task\n", + " for i in I:\n", + " solver.Add(solver.Sum([x[i, j] for j in J]) <= 1)\n", "\n", - "# each task must be assigned exactly to one agent\n", - "for j in J:\n", - " solver.Add(solver.Sum([x[i, j] for i in I]) == 1)\n", - "\n", - "# to which task and what cost is person i assigned (for output in MiniZinc)\n", - "for i in I:\n", - " solver.Add(assigned[i] == solver.Sum([j * x[i, j] for j in J]))\n", - " solver.Add(costs[i] == solver.Sum([c[i][j] * x[i, j] for j in J]))\n", - "\n", - "# objective\n", - "objective = solver.Minimize(z)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", - "\n", - "print()\n", - "print('z: ', int(solver.Objective().Value()))\n", - "\n", - "print('Assigned')\n", - "for j in J:\n", - " print(int(assigned[j].SolutionValue()), end=' ')\n", - "print()\n", - "\n", - "print('Matrix:')\n", - "for i in I:\n", + " # each task must be assigned exactly to one agent\n", " for j in J:\n", - " print(int(x[i, j].SolutionValue()), end=' ')\n", - " print()\n", - "print()\n", + " solver.Add(solver.Sum([x[i, j] for i in I]) == 1)\n", "\n", - "print()\n", - "print('walltime :', solver.WallTime(), 'ms')\n", - "if sol == 'CBC':\n", - " print('iterations:', solver.Iterations())\n", + " # to which task and what cost is person i assigned (for output in MiniZinc)\n", + " for i in I:\n", + " solver.Add(assigned[i] == solver.Sum([j * x[i, j] for j in J]))\n", + " solver.Add(costs[i] == solver.Sum([c[i][j] * x[i, j] for j in J]))\n", + "\n", + " # objective\n", + " objective = solver.Minimize(z)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", + "\n", + " print()\n", + " print('z: ', int(solver.Objective().Value()))\n", + "\n", + " print('Assigned')\n", + " for j in J:\n", + " print(int(assigned[j].SolutionValue()), end=' ')\n", + " print()\n", + "\n", + " print('Matrix:')\n", + " for i in I:\n", + " for j in J:\n", + " print(int(x[i, j].SolutionValue()), end=' ')\n", + " print()\n", + " print()\n", + "\n", + " print()\n", + " print('walltime :', solver.WallTime(), 'ms')\n", + " if sol == 'CBC':\n", + " print('iterations:', solver.Iterations())\n", + "\n", + "\n", + "\n", + "sol = 'CBC'\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/bacp.ipynb b/examples/notebook/contrib/bacp.ipynb index 440013c7d2..cb658bd77c 100644 --- a/examples/notebook/contrib/bacp.ipynb +++ b/examples/notebook/contrib/bacp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -124,41 +124,45 @@ " return (credits, nb_periods, prereq)\n", "\n", "\n", - "#------------------solver and variable declaration-------------\n", + "def main(args):\n", + " #------------------solver and variable declaration-------------\n", "\n", - "credits, nb_periods, prereq = ReadData(args.data)\n", - "nb_courses = len(credits)\n", + " credits, nb_periods, prereq = ReadData(args.data)\n", + " nb_courses = len(credits)\n", "\n", - "solver = pywrapcp.Solver('Balanced Academic Curriculum Problem')\n", + " solver = pywrapcp.Solver('Balanced Academic Curriculum Problem')\n", "\n", - "x = [\n", - " solver.IntVar(0, nb_periods - 1, 'x' + str(i)) for i in range(nb_courses)\n", - "]\n", - "load_vars = [\n", - " solver.IntVar(0, sum(credits), 'load_vars' + str(i))\n", - " for i in range(nb_periods)\n", - "]\n", + " x = [\n", + " solver.IntVar(0, nb_periods - 1, 'x' + str(i)) for i in range(nb_courses)\n", + " ]\n", + " load_vars = [\n", + " solver.IntVar(0, sum(credits), 'load_vars' + str(i))\n", + " for i in range(nb_periods)\n", + " ]\n", "\n", - "#-------------------post of the constraints--------------\n", + " #-------------------post of the constraints--------------\n", "\n", - "# Bin Packing.\n", - "BinPacking(solver, x, credits, load_vars)\n", - "# Add dependencies.\n", - "for i, j in prereq:\n", - " solver.Add(x[i] < x[j])\n", + " # Bin Packing.\n", + " BinPacking(solver, x, credits, load_vars)\n", + " # Add dependencies.\n", + " for i, j in prereq:\n", + " solver.Add(x[i] < x[j])\n", "\n", - "#----------------Objective-------------------------------\n", + " #----------------Objective-------------------------------\n", "\n", - "objective_var = solver.Max(load_vars)\n", - "objective = solver.Minimize(objective_var, 1)\n", + " objective_var = solver.Max(load_vars)\n", + " objective = solver.Minimize(objective_var, 1)\n", "\n", - "#------------start the search and optimization-----------\n", + " #------------start the search and optimization-----------\n", "\n", - "db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.INT_VALUE_DEFAULT)\n", + " db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.INT_VALUE_DEFAULT)\n", "\n", - "search_log = solver.SearchLog(100000, objective_var)\n", - "solver.Solve(db, [objective, search_log])\n", + " search_log = solver.SearchLog(100000, objective_var)\n", + " solver.Solve(db, [objective, search_log])\n", + "\n", + "\n", + "main(parser.parse_args())\n", "\n" ] } diff --git a/examples/notebook/contrib/blending.ipynb b/examples/notebook/contrib/blending.ipynb index 665a41aa4b..7104a78bbb 100644 --- a/examples/notebook/contrib/blending.ipynb +++ b/examples/notebook/contrib/blending.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Blending problem in Google or-tools.\n", "\n", @@ -95,120 +80,140 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "print('Solver: ', sol)\n", + " print('Solver: ', sol)\n", "\n", - "# using GLPK\n", - "if sol == 'GLPK':\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", - "else:\n", - " # Using CBC\n", - " solver = pywraplp.Solver('CoinsGridCBC',\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " # using GLPK\n", + " if sol == 'GLPK':\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", + " else:\n", + " # Using CBC\n", + " solver = pywraplp.Solver('CoinsGridCBC',\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "#\n", - "# data\n", - "#\n", - "NbMetals = 3\n", - "NbRaw = 2\n", - "NbScrap = 2\n", - "NbIngo = 1\n", - "Metals = list(range(NbMetals))\n", - "Raws = list(range(NbRaw))\n", - "Scraps = list(range(NbScrap))\n", - "Ingos = list(range(NbIngo))\n", + " #\n", + " # data\n", + " #\n", + " NbMetals = 3\n", + " NbRaw = 2\n", + " NbScrap = 2\n", + " NbIngo = 1\n", + " Metals = list(range(NbMetals))\n", + " Raws = list(range(NbRaw))\n", + " Scraps = list(range(NbScrap))\n", + " Ingos = list(range(NbIngo))\n", "\n", - "CostMetal = [22, 10, 13]\n", - "CostRaw = [6, 5]\n", - "CostScrap = [7, 8]\n", - "CostIngo = [9]\n", - "Low = [0.05, 0.30, 0.60]\n", - "Up = [0.10, 0.40, 0.80]\n", - "PercRaw = [[0.20, 0.01], [0.05, 0], [0.05, 0.30]]\n", - "PercScrap = [[0, 0.01], [0.60, 0], [0.40, 0.70]]\n", - "PercIngo = [[0.10], [0.45], [0.45]]\n", - "Alloy = 71\n", + " CostMetal = [22, 10, 13]\n", + " CostRaw = [6, 5]\n", + " CostScrap = [7, 8]\n", + " CostIngo = [9]\n", + " Low = [0.05, 0.30, 0.60]\n", + " Up = [0.10, 0.40, 0.80]\n", + " PercRaw = [[0.20, 0.01], [0.05, 0], [0.05, 0.30]]\n", + " PercScrap = [[0, 0.01], [0.60, 0], [0.40, 0.70]]\n", + " PercIngo = [[0.10], [0.45], [0.45]]\n", + " Alloy = 71\n", "\n", - "#\n", - "# variables\n", - "#\n", - "p = [solver.NumVar(0, solver.Infinity(), 'p[%i]' % i) for i in Metals]\n", - "r = [solver.NumVar(0, solver.Infinity(), 'r[%i]' % i) for i in Raws]\n", - "s = [solver.NumVar(0, solver.Infinity(), 's[%i]' % i) for i in Scraps]\n", - "ii = [solver.IntVar(0, solver.Infinity(), 'ii[%i]' % i) for i in Ingos]\n", - "metal = [\n", - " solver.NumVar(Low[j] * Alloy, Up[j] * Alloy, 'metal[%i]' % j)\n", - " for j in Metals\n", - "]\n", + " #\n", + " # variables\n", + " #\n", + " p = [solver.NumVar(0, solver.Infinity(), 'p[%i]' % i) for i in Metals]\n", + " r = [solver.NumVar(0, solver.Infinity(), 'r[%i]' % i) for i in Raws]\n", + " s = [solver.NumVar(0, solver.Infinity(), 's[%i]' % i) for i in Scraps]\n", + " ii = [solver.IntVar(0, solver.Infinity(), 'ii[%i]' % i) for i in Ingos]\n", + " metal = [\n", + " solver.NumVar(Low[j] * Alloy, Up[j] * Alloy, 'metal[%i]' % j)\n", + " for j in Metals\n", + " ]\n", "\n", - "z = solver.NumVar(0, solver.Infinity(), 'z')\n", + " z = solver.NumVar(0, solver.Infinity(), 'z')\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "solver.Add(z == solver.Sum([CostMetal[i] * p[i] for i in Metals]) +\n", - " solver.Sum([CostRaw[i] * r[i] for i in Raws]) +\n", - " solver.Sum([CostScrap[i] * s[i] for i in Scraps]) +\n", - " solver.Sum([CostIngo[i] * ii[i] for i in Ingos]))\n", + " solver.Add(z == solver.Sum([CostMetal[i] * p[i] for i in Metals]) +\n", + " solver.Sum([CostRaw[i] * r[i] for i in Raws]) +\n", + " solver.Sum([CostScrap[i] * s[i] for i in Scraps]) +\n", + " solver.Sum([CostIngo[i] * ii[i] for i in Ingos]))\n", "\n", - "for j in Metals:\n", - " solver.Add(\n", - " metal[j] == p[j] + solver.Sum([PercRaw[j][k] * r[k] for k in Raws]) +\n", - " solver.Sum([PercScrap[j][k] * s[k] for k in Scraps]) +\n", - " solver.Sum([PercIngo[j][k] * ii[k] for k in Ingos]))\n", + " for j in Metals:\n", + " solver.Add(\n", + " metal[j] == p[j] + solver.Sum([PercRaw[j][k] * r[k] for k in Raws]) +\n", + " solver.Sum([PercScrap[j][k] * s[k] for k in Scraps]) +\n", + " solver.Sum([PercIngo[j][k] * ii[k] for k in Ingos]))\n", "\n", - "solver.Add(solver.Sum(metal) == Alloy)\n", + " solver.Add(solver.Sum(metal) == Alloy)\n", "\n", - "objective = solver.Minimize(z)\n", + " objective = solver.Minimize(z)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", "\n", - "print()\n", + " print()\n", "\n", - "print('z = ', solver.Objective().Value())\n", - "print('Metals')\n", - "for i in Metals:\n", - " print(p[i].SolutionValue(), end=' ')\n", - "print()\n", + " print('z = ', solver.Objective().Value())\n", + " print('Metals')\n", + " for i in Metals:\n", + " print(p[i].SolutionValue(), end=' ')\n", + " print()\n", "\n", - "print('Raws')\n", - "for i in Raws:\n", - " print(r[i].SolutionValue(), end=' ')\n", - "print()\n", + " print('Raws')\n", + " for i in Raws:\n", + " print(r[i].SolutionValue(), end=' ')\n", + " print()\n", "\n", - "print('Scraps')\n", - "for i in Scraps:\n", - " print(s[i].SolutionValue(), end=' ')\n", - "print()\n", + " print('Scraps')\n", + " for i in Scraps:\n", + " print(s[i].SolutionValue(), end=' ')\n", + " print()\n", "\n", - "print('Ingos')\n", - "for i in Ingos:\n", - " print(ii[i].SolutionValue(), end=' ')\n", - "print()\n", + " print('Ingos')\n", + " for i in Ingos:\n", + " print(ii[i].SolutionValue(), end=' ')\n", + " print()\n", "\n", - "print('Metals')\n", - "for i in Metals:\n", - " print(metal[i].SolutionValue(), end=' ')\n", - "print()\n", + " print('Metals')\n", + " for i in Metals:\n", + " print(metal[i].SolutionValue(), end=' ')\n", + " print()\n", "\n", - "print()\n", + " print()\n", "\n", - "print('walltime :', solver.WallTime(), 'ms')\n", - "if sol == 'CBC':\n", - " print('iterations:', solver.Iterations())\n", + " print('walltime :', solver.WallTime(), 'ms')\n", + " if sol == 'CBC':\n", + " print('iterations:', solver.Iterations())\n", + "\n", + "\n", + "sol = 'CBC'\n", + "\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/broken_weights.ipynb b/examples/notebook/contrib/broken_weights.ipynb index 0605d0ca49..358006b701 100644 --- a/examples/notebook/contrib/broken_weights.ipynb +++ b/examples/notebook/contrib/broken_weights.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Broken weights problem in Google CP Solver.\n", "\n", @@ -120,91 +105,107 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(m=40, n=4):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Broken weights')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Broken weights')\n", "\n", - "#\n", - "# data\n", - "#\n", - "print('total weight (m):', m)\n", - "print('number of pieces (n):', n)\n", - "print()\n", - "\n", - "#\n", - "# variables\n", - "#\n", - "weights = [solver.IntVar(1, m, 'weights[%i]' % j) for j in range(n)]\n", - "x = {}\n", - "for i in range(m):\n", - " for j in range(n):\n", - " x[i, j] = solver.IntVar(-1, 1, 'x[%i,%i]' % (i, j))\n", - "x_flat = [x[i, j] for i in range(m) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# symmetry breaking\n", - "for j in range(1, n):\n", - " solver.Add(weights[j - 1] < weights[j])\n", - "\n", - "solver.Add(solver.SumEquality(weights, m))\n", - "\n", - "# Check that all weights from 1 to 40 can be made.\n", - "#\n", - "# Since all weights can be on either side\n", - "# of the side of the scale we allow either\n", - "# -1, 0, or 1 or the weights, assuming that\n", - "# -1 is the weights on the left and 1 is on the right.\n", - "#\n", - "for i in range(m):\n", - " solver.Add(i + 1 == solver.Sum([weights[j] * x[i, j] for j in range(n)]))\n", - "\n", - "# objective\n", - "objective = solver.Minimize(weights[n - 1], 1)\n", - "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(weights + x_flat, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "search_log = solver.SearchLog(1)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('weights: ', end=' ')\n", - " for w in [weights[j].Value() for j in range(n)]:\n", - " print('%3i ' % w, end=' ')\n", + " #\n", + " # data\n", + " #\n", + " print('total weight (m):', m)\n", + " print('number of pieces (n):', n)\n", " print()\n", - " print('-' * 30)\n", + "\n", + " #\n", + " # variables\n", + " #\n", + " weights = [solver.IntVar(1, m, 'weights[%i]' % j) for j in range(n)]\n", + " x = {}\n", " for i in range(m):\n", - " print('weight %2i:' % (i + 1), end=' ')\n", " for j in range(n):\n", - " print('%3i ' % x[i, j].Value(), end=' ')\n", + " x[i, j] = solver.IntVar(-1, 1, 'x[%i,%i]' % (i, j))\n", + " x_flat = [x[i, j] for i in range(m) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # symmetry breaking\n", + " for j in range(1, n):\n", + " solver.Add(weights[j - 1] < weights[j])\n", + "\n", + " solver.Add(solver.SumEquality(weights, m))\n", + "\n", + " # Check that all weights from 1 to 40 can be made.\n", + " #\n", + " # Since all weights can be on either side\n", + " # of the side of the scale we allow either\n", + " # -1, 0, or 1 or the weights, assuming that\n", + " # -1 is the weights on the left and 1 is on the right.\n", + " #\n", + " for i in range(m):\n", + " solver.Add(i + 1 == solver.Sum([weights[j] * x[i, j] for j in range(n)]))\n", + "\n", + " # objective\n", + " objective = solver.Minimize(weights[n - 1], 1)\n", + "\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(weights + x_flat, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " search_log = solver.SearchLog(1)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('weights: ', end=' ')\n", + " for w in [weights[j].Value() for j in range(n)]:\n", + " print('%3i ' % w, end=' ')\n", + " print()\n", + " print('-' * 30)\n", + " for i in range(m):\n", + " print('weight %2i:' % (i + 1), end=' ')\n", + " for j in range(n):\n", + " print('%3i ' % x[i, j].Value(), end=' ')\n", + " print()\n", " print()\n", " print()\n", - "print()\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", + "\n", + " print('num_solutions:', num_solutions)\n", + " print('failures :', solver.Failures())\n", + " print('branches :', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures :', solver.Failures())\n", - "print('branches :', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", "\n", "m = 40\n", - "n = 4\n" + "n = 4\n", + "if len(sys.argv) > 1:\n", + " m = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " n = int(sys.argv[2])\n", + "main(m, n)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/bus_schedule.ipynb b/examples/notebook/contrib/bus_schedule.ipynb index 88fae9fce9..22920717e4 100644 --- a/examples/notebook/contrib/bus_schedule.ipynb +++ b/examples/notebook/contrib/bus_schedule.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Bus scheduling in Google CP Solver.\n", "\n", @@ -107,74 +92,90 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(num_buses_check=0):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Bus scheduling\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Bus scheduling\")\n", "\n", - "# data\n", - "time_slots = 6\n", - "demands = [8, 10, 7, 12, 4, 4]\n", - "max_num = sum(demands)\n", + " # data\n", + " time_slots = 6\n", + " demands = [8, 10, 7, 12, 4, 4]\n", + " max_num = sum(demands)\n", "\n", - "# declare variables\n", - "x = [solver.IntVar(0, max_num, \"x%i\" % i) for i in range(time_slots)]\n", - "num_buses = solver.IntVar(0, max_num, \"num_buses\")\n", + " # declare variables\n", + " x = [solver.IntVar(0, max_num, \"x%i\" % i) for i in range(time_slots)]\n", + " num_buses = solver.IntVar(0, max_num, \"num_buses\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(num_buses == solver.Sum(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(num_buses == solver.Sum(x))\n", "\n", - "# Meet the demands for this and the next time slot\n", - "for i in range(time_slots - 1):\n", - " solver.Add(x[i] + x[i + 1] >= demands[i])\n", + " # Meet the demands for this and the next time slot\n", + " for i in range(time_slots - 1):\n", + " solver.Add(x[i] + x[i + 1] >= demands[i])\n", "\n", - "# The demand \"around the clock\"\n", - "solver.Add(x[time_slots - 1] + x[0] == demands[time_slots - 1])\n", + " # The demand \"around the clock\"\n", + " solver.Add(x[time_slots - 1] + x[0] == demands[time_slots - 1])\n", "\n", - "if num_buses_check > 0:\n", - " solver.Add(num_buses == num_buses_check)\n", + " if num_buses_check > 0:\n", + " solver.Add(num_buses == num_buses_check)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(num_buses)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(num_buses)\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "cargs = [collector]\n", + " collector = solver.AllSolutionCollector(solution)\n", + " cargs = [collector]\n", "\n", - "# objective\n", - "if num_buses_check == 0:\n", - " objective = solver.Minimize(num_buses, 1)\n", - " cargs.extend([objective])\n", + " # objective\n", + " if num_buses_check == 0:\n", + " objective = solver.Minimize(num_buses, 1)\n", + " cargs.extend([objective])\n", "\n", - "solver.Solve(\n", - " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE),\n", - " cargs)\n", + " solver.Solve(\n", + " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE),\n", + " cargs)\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "num_buses_check_value = 0\n", - "for s in range(num_solutions):\n", - " print(\"x:\", [collector.Value(s, x[i]) for i in range(len(x))], end=\" \")\n", - " num_buses_check_value = collector.Value(s, num_buses)\n", - " print(\" num_buses:\", num_buses_check_value)\n", + " num_solutions = collector.SolutionCount()\n", + " num_buses_check_value = 0\n", + " for s in range(num_solutions):\n", + " print(\"x:\", [collector.Value(s, x[i]) for i in range(len(x))], end=\" \")\n", + " num_buses_check_value = collector.Value(s, num_buses)\n", + " print(\" num_buses:\", num_buses_check_value)\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print()\n", - "if num_buses_check == 0:\n", - " return num_buses_check_value\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print()\n", + " if num_buses_check == 0:\n", + " return num_buses_check_value\n", + "\n", + "\n", + "print(\"Check for minimun number of buses\")\n", + "num_buses_check = main()\n", + "print(\"... got \", num_buses_check, \"buses\")\n", + "print(\"All solutions:\")\n", + "main(num_buses_check)\n", "\n" ] } diff --git a/examples/notebook/contrib/car.ipynb b/examples/notebook/contrib/car.ipynb index d2af5a9375..725a75eafe 100644 --- a/examples/notebook/contrib/car.ipynb +++ b/examples/notebook/contrib/car.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Car sequencing in Google CP Solver.\n", "\n", @@ -102,111 +87,125 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(num_sol=3):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Car sequence\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Car sequence\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "nbCars = 6\n", - "nbOptions = 5\n", - "nbSlots = 10\n", + " #\n", + " # data\n", + " #\n", + " nbCars = 6\n", + " nbOptions = 5\n", + " nbSlots = 10\n", "\n", - "Cars = list(range(nbCars))\n", - "Options = list(range(nbOptions))\n", - "Slots = list(range(nbSlots))\n", + " Cars = list(range(nbCars))\n", + " Options = list(range(nbOptions))\n", + " Slots = list(range(nbSlots))\n", "\n", - "# car 0 1 2 3 4 5\n", - "demand = [1, 1, 2, 2, 2, 2]\n", + " # car 0 1 2 3 4 5\n", + " demand = [1, 1, 2, 2, 2, 2]\n", "\n", - "option = [\n", - " # car 0 1 2 3 4 5\n", - " [1, 0, 0, 0, 1, 1], # option 1\n", - " [0, 0, 1, 1, 0, 1], # option 2\n", - " [1, 0, 0, 0, 1, 0], # option 3\n", - " [1, 1, 0, 1, 0, 0], # option 4\n", - " [0, 0, 1, 0, 0, 0] # option 5\n", - "]\n", + " option = [\n", + " # car 0 1 2 3 4 5\n", + " [1, 0, 0, 0, 1, 1], # option 1\n", + " [0, 0, 1, 1, 0, 1], # option 2\n", + " [1, 0, 0, 0, 1, 0], # option 3\n", + " [1, 1, 0, 1, 0, 0], # option 4\n", + " [0, 0, 1, 0, 0, 0] # option 5\n", + " ]\n", "\n", - "capacity = [(1, 2), (2, 3), (1, 3), (2, 5), (1, 5)]\n", + " capacity = [(1, 2), (2, 3), (1, 3), (2, 5), (1, 5)]\n", "\n", - "optionDemand = [\n", - " sum([demand[j] * option[i][j] for j in Cars]) for i in Options\n", - "]\n", + " optionDemand = [\n", + " sum([demand[j] * option[i][j] for j in Cars]) for i in Options\n", + " ]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "slot = [solver.IntVar(0, nbCars - 1, \"slot[%i]\" % i) for i in Slots]\n", - "setup = {}\n", - "for i in Options:\n", - " for j in Slots:\n", - " setup[(i, j)] = solver.IntVar(0, 1, \"setup[%i,%i]\" % (i, j))\n", - "setup_flat = [setup[i, j] for i in Options for j in Slots]\n", + " #\n", + " # declare variables\n", + " #\n", + " slot = [solver.IntVar(0, nbCars - 1, \"slot[%i]\" % i) for i in Slots]\n", + " setup = {}\n", + " for i in Options:\n", + " for j in Slots:\n", + " setup[(i, j)] = solver.IntVar(0, 1, \"setup[%i,%i]\" % (i, j))\n", + " setup_flat = [setup[i, j] for i in Options for j in Slots]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for c in Cars:\n", - " b = [solver.IsEqualCstVar(slot[s], c) for s in Slots]\n", - " solver.Add(solver.Sum(b) == demand[c])\n", + " #\n", + " # constraints\n", + " #\n", + " for c in Cars:\n", + " b = [solver.IsEqualCstVar(slot[s], c) for s in Slots]\n", + " solver.Add(solver.Sum(b) == demand[c])\n", + "\n", + " for o in Options:\n", + " for s in range(0, nbSlots - capacity[o][1] + 1):\n", + " b = [setup[o, j] for j in range(s, s + capacity[o][1] - 1)]\n", + " solver.Add(solver.Sum(b) <= capacity[o][0])\n", "\n", - "for o in Options:\n", - " for s in range(0, nbSlots - capacity[o][1] + 1):\n", - " b = [setup[o, j] for j in range(s, s + capacity[o][1] - 1)]\n", - " solver.Add(solver.Sum(b) <= capacity[o][0])\n", - "\n", - "for o in Options:\n", - " for s in Slots:\n", - " solver.Add(setup[(o, s)] == solver.Element(option[o], slot[s]))\n", - "\n", - "for o in Options:\n", - " for i in range(optionDemand[o]):\n", - " s_range = list(range(0, nbSlots - (i + 1) * capacity[o][1]))\n", - " ss = [setup[o, s] for s in s_range]\n", - " cc = optionDemand[o] - (i + 1) * capacity[o][0]\n", - " if len(ss) > 0 and cc >= 0:\n", - " solver.Add(solver.Sum(ss) >= cc)\n", - "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(slot + setup_flat, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"slot:%s\" % \",\".join([str(slot[i].Value()) for i in Slots]))\n", - " print(\"setup:\")\n", " for o in Options:\n", - " print(\"%i/%i:\" % (capacity[o][0], capacity[o][1]), end=\" \")\n", " for s in Slots:\n", - " print(setup[o, s].Value(), end=\" \")\n", + " solver.Add(setup[(o, s)] == solver.Element(option[o], slot[s]))\n", + "\n", + " for o in Options:\n", + " for i in range(optionDemand[o]):\n", + " s_range = list(range(0, nbSlots - (i + 1) * capacity[o][1]))\n", + " ss = [setup[o, s] for s in s_range]\n", + " cc = optionDemand[o] - (i + 1) * capacity[o][0]\n", + " if len(ss) > 0 and cc >= 0:\n", + " solver.Add(solver.Sum(ss) >= cc)\n", + "\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(slot + setup_flat, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"slot:%s\" % \",\".join([str(slot[i].Value()) for i in Slots]))\n", + " print(\"setup:\")\n", + " for o in Options:\n", + " print(\"%i/%i:\" % (capacity[o][0], capacity[o][1]), end=\" \")\n", + " for s in Slots:\n", + " print(setup[o, s].Value(), end=\" \")\n", + " print()\n", " print()\n", + " num_solutions += 1\n", + "\n", + " if num_solutions >= num_sol:\n", + " break\n", + "\n", + " solver.EndSearch()\n", + "\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - " if num_solutions >= num_sol:\n", - " break\n", "\n", - "solver.EndSearch()\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "\n", - "num_sol = 3\n" + "num_sol = 3\n", + "if len(sys.argv) > 1:\n", + " num_sol = int(sys.argv[1])\n", + "main(num_sol)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/check_dependencies.ipynb b/examples/notebook/contrib/check_dependencies.ipynb index 8be581fa79..a63a304dc8 100644 --- a/examples/notebook/contrib/check_dependencies.ipynb +++ b/examples/notebook/contrib/check_dependencies.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -116,6 +116,77 @@ " directory = dirname(directory)\n", " return directory\n", "\n", + "\n", + "parser = OptionParser(\"Log level\")\n", + "parser.add_option(\n", + " \"-l\",\n", + " \"--log\",\n", + " type=\"string\",\n", + " help=\n", + " \"Available levels are CRITICAL (3), ERROR (2), WARNING (1), INFO (0), DEBUG (-1)\",\n", + " default=\"INFO\")\n", + "options, args = parser.parse_args()\n", + "\n", + "try:\n", + " loglevel = getattr(logging, options.log.upper())\n", + "except AttributeError:\n", + " loglevel = {\n", + " 3: logging.CRITICAL,\n", + " 2: logging.ERROR,\n", + " 1: logging.WARNING,\n", + " 0: logging.INFO,\n", + " -1: logging.DEBUG,\n", + " }[int(options.log)]\n", + "\n", + "logging.basicConfig(\n", + " format=\"[%(levelname)s] %(message)s\", stream=sys.stdout, level=loglevel)\n", + "\n", + "logging.info(\"Python path : \" + sys.executable)\n", + "logging.info(\"Python version : \" + sys.version)\n", + "logging.info(\"sys.path : \" + str(sys.path))\n", + "ortools_project_path = n_dirname(\n", + " 3, abspath(inspect.getfile(inspect.currentframe())))\n", + "\n", + "#try to import ortools\n", + "try:\n", + " import ortools\n", + "except ImportError:\n", + " logging.error(notinstalled(\"ortools\"))\n", + " raise SystemExit\n", + "\n", + "#check if we're using ortools from the sources or it's binded by pypi's module\n", + "ortools_module_file = inspect.getfile(ortools)\n", + "ortools_module_path = n_dirname(3, ortools_module_file)\n", + "if (ortools_module_path == ortools_project_path):\n", + " logging.info(\"Or-tools is imported from : \" + ortools_module_file)\n", + "else:\n", + " log_error_and_exit(wrong_module(ortools_module_file, \"ortools\"))\n", + "\n", + "# Check if python can load the libraries' modules\n", + "# this is useful when the library architecture is not compatbile with the python executable,\n", + "# or when the library's dependencies are not available or not compatible.\n", + "from ortools.constraint_solver import _pywrapcp\n", + "from ortools.linear_solver import _pywraplp\n", + "from ortools.algorithms import _pywrapknapsack_solver\n", + "from ortools.graph import _pywrapgraph\n", + "\n", + "#try to import protobuf\n", + "try:\n", + " import google.protobuf\n", + "except ImportError:\n", + " log_error_and_exit(notinstalled(\"protobuf\"))\n", + "\n", + "#check if we're using protobuf from the sources or it's binded by pypi's module\n", + "protobuf_module_file = inspect.getfile(google.protobuf)\n", + "protobuf_module_path = n_dirname(7, protobuf_module_file)\n", + "if (protobuf_module_path == ortools_project_path):\n", + " logging.info(\"Protobuf is imported from : \" + protobuf_module_file)\n", + "else:\n", + " log_error_and_exit(wrong_module(protobuf_module_file, \"protobuf\"))\n", + "\n", + "#Check if the protobuf modules were successfully generated\n", + "from google.protobuf import descriptor as _descriptor\n", + "from google.protobuf import descriptor_pb2\n", "\n" ] } diff --git a/examples/notebook/contrib/circuit.ipynb b/examples/notebook/contrib/circuit.ipynb index 4cc1baf592..287073905c 100644 --- a/examples/notebook/contrib/circuit.ipynb +++ b/examples/notebook/contrib/circuit.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Decomposition of the circuit constraint in Google CP Solver.\n", "\n", @@ -115,9 +100,17 @@ " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", "\n", - "\"\"\"\n", - "\n", "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -158,46 +151,53 @@ " solver.Add(z[n - 1] == 0)\n", "\n", "\n", + "def main(n=5):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Send most money\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Send most money\")\n", "\n", - "# data\n", - "print(\"n:\", n)\n", + " # data\n", + " print(\"n:\", n)\n", "\n", - "# declare variables\n", - "# Note: domain should be 0..n-1\n", - "x = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", + " # declare variables\n", + " # Note: domain should be 0..n-1\n", + " x = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "circuit(solver, x)\n", + " #\n", + " # constraints\n", + " #\n", + " circuit(solver, x)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", + " collector = solver.AllSolutionCollector(solution)\n", "\n", - "solver.Solve(\n", - " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE),\n", - " [collector])\n", + " solver.Solve(\n", + " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE),\n", + " [collector])\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "for s in range(num_solutions):\n", - " print(\"x:\", [collector.Value(s, x[i]) for i in range(len(x))])\n", + " num_solutions = collector.SolutionCount()\n", + " for s in range(num_solutions):\n", + " print(\"x:\", [collector.Value(s, x[i]) for i in range(len(x))])\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print()\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print()\n", "\n", - "n = 5\n" + "\n", + "n = 5\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "\n", + "main(n)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/coins3.ipynb b/examples/notebook/contrib/coins3.ipynb index 42d41911ab..69e25b0792 100644 --- a/examples/notebook/contrib/coins3.ipynb +++ b/examples/notebook/contrib/coins3.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Coin application in Google CP Solver.\n", "\n", @@ -111,67 +96,79 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", - "\n", "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Coins\")\n", + "def main():\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Coins\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 6 # number of different coins\n", - "variables = [1, 2, 5, 10, 25, 50]\n", + " #\n", + " # data\n", + " #\n", + " n = 6 # number of different coins\n", + " variables = [1, 2, 5, 10, 25, 50]\n", "\n", - "# declare variables\n", - "x = [solver.IntVar(0, 99, \"x%i\" % i) for i in range(n)]\n", - "num_coins = solver.IntVar(0, 99, \"num_coins\")\n", + " # declare variables\n", + " x = [solver.IntVar(0, 99, \"x%i\" % i) for i in range(n)]\n", + " num_coins = solver.IntVar(0, 99, \"num_coins\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# number of used coins, to be minimized\n", - "solver.Add(num_coins == solver.Sum(x))\n", + " # number of used coins, to be minimized\n", + " solver.Add(num_coins == solver.Sum(x))\n", "\n", - "# Check that all changes from 1 to 99 can be made.\n", - "for j in range(1, 100):\n", - " tmp = [solver.IntVar(0, 99, \"b%i\" % i) for i in range(n)]\n", - " solver.Add(solver.ScalProd(tmp, variables) == j)\n", - " [solver.Add(tmp[i] <= x[i]) for i in range(n)]\n", + " # Check that all changes from 1 to 99 can be made.\n", + " for j in range(1, 100):\n", + " tmp = [solver.IntVar(0, 99, \"b%i\" % i) for i in range(n)]\n", + " solver.Add(solver.ScalProd(tmp, variables) == j)\n", + " [solver.Add(tmp[i] <= x[i]) for i in range(n)]\n", "\n", - "# objective\n", - "objective = solver.Minimize(num_coins, 1)\n", + " # objective\n", + " objective = solver.Minimize(num_coins, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(num_coins)\n", - "solution.AddObjective(num_coins)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(num_coins)\n", + " solution.AddObjective(num_coins)\n", "\n", - "db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MAX,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MAX,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"x: \", [x[i].Value() for i in range(n)])\n", + " print(\"num_coins:\", num_coins.Value())\n", + " print()\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", "\n", - "solver.NewSearch(db, [objective])\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"x: \", [x[i].Value() for i in range(n)])\n", - " print(\"num_coins:\", num_coins.Value())\n", " print()\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/coins_grid.ipynb b/examples/notebook/contrib/coins_grid.ipynb index 598c637c8b..8259840a24 100644 --- a/examples/notebook/contrib/coins_grid.ipynb +++ b/examples/notebook/contrib/coins_grid.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", " Coins grid problem in Google CP Solver.\n", "\n", " Problem from\n", @@ -125,67 +110,87 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Coins grid\")\n", - "# data\n", + "def main(n, c):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Coins grid\")\n", + " # data\n", "\n", - "print(\"n: \", n)\n", - "print(\"c: \", c)\n", + " print(\"n: \", n)\n", + " print(\"c: \", c)\n", "\n", - "# declare variables\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[(i, j)] = solver.BoolVar(\"x %i %i\" % (i, j))\n", + " # declare variables\n", + " x = {}\n", + " for i in range(n):\n", + " for j in range(n):\n", + " x[(i, j)] = solver.BoolVar(\"x %i %i\" % (i, j))\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# sum rows/columns == c\n", - "for i in range(n):\n", - " solver.Add(solver.SumEquality([x[(i, j)] for j in range(n)], c)) # sum rows\n", - " solver.Add(solver.SumEquality([x[(j, i)] for j in range(n)], c)) # sum cols\n", + " # sum rows/columns == c\n", + " for i in range(n):\n", + " solver.Add(solver.SumEquality([x[(i, j)] for j in range(n)], c)) # sum rows\n", + " solver.Add(solver.SumEquality([x[(j, i)] for j in range(n)], c)) # sum cols\n", "\n", - "# quadratic horizonal distance var\n", - "objective_var = solver.Sum(\n", - " [x[(i, j)] * (i - j) * (i - j) for i in range(n) for j in range(n)])\n", + " # quadratic horizonal distance var\n", + " objective_var = solver.Sum(\n", + " [x[(i, j)] * (i - j) * (i - j) for i in range(n) for j in range(n)])\n", "\n", - "# objective\n", - "objective = solver.Minimize(objective_var, 1)\n", + " # objective\n", + " objective = solver.Minimize(objective_var, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([x[(i, j)] for i in range(n) for j in range(n)])\n", - "solution.AddObjective(objective_var)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([x[(i, j)] for i in range(n) for j in range(n)])\n", + " solution.AddObjective(objective_var)\n", "\n", - "# last solutions\n", - "collector = solver.LastSolutionCollector(solution)\n", - "search_log = solver.SearchLog(1000000, objective_var)\n", - "restart = solver.ConstantRestart(300)\n", - "solver.Solve(\n", - " solver.Phase([x[(i, j)] for i in range(n) for j in range(n)],\n", - " solver.CHOOSE_RANDOM, solver.ASSIGN_MAX_VALUE),\n", - " [collector, search_log, objective])\n", + " # last solutions\n", + " collector = solver.LastSolutionCollector(solution)\n", + " search_log = solver.SearchLog(1000000, objective_var)\n", + " restart = solver.ConstantRestart(300)\n", + " solver.Solve(\n", + " solver.Phase([x[(i, j)] for i in range(n) for j in range(n)],\n", + " solver.CHOOSE_RANDOM, solver.ASSIGN_MAX_VALUE),\n", + " [collector, search_log, objective])\n", "\n", - "print(\"objective:\", collector.ObjectiveValue(0))\n", - "for i in range(n):\n", - " for j in range(n):\n", - " print(collector.Value(0, x[(i, j)]), end=\" \")\n", + " print(\"objective:\", collector.ObjectiveValue(0))\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(collector.Value(0, x[(i, j)]), end=\" \")\n", + " print()\n", " print()\n", - "print()\n", "\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "# data\n", + "n = 5 # the grid size\n", + "c = 2 # number of coins per row/column\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " c = int(sys.argv[2])\n", + "\n", + "main(n, c)\n", "\n" ] } diff --git a/examples/notebook/contrib/coins_grid_mip.ipynb b/examples/notebook/contrib/coins_grid_mip.ipynb index f30c3f427a..3777fc78ef 100644 --- a/examples/notebook/contrib/coins_grid_mip.ipynb +++ b/examples/notebook/contrib/coins_grid_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Coins grid problem in Google CP Solver.\n", "\n", @@ -114,62 +99,74 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.linear_solver import pywraplp\n", "\n", "\n", - "# Create the solver.\n", + "def main(unused_argv):\n", + " # Create the solver.\n", "\n", - "# using CBC\n", - "solver = pywraplp.Solver('CoinsGridCBC',\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " # using CBC\n", + " solver = pywraplp.Solver('CoinsGridCBC',\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "# Using CLP\n", - "# solver = pywraplp.Solver('CoinsGridCLP',\n", - "# pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " # Using CLP\n", + " # solver = pywraplp.Solver('CoinsGridCLP',\n", + " # pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "# data\n", - "n = 31 # the grid size\n", - "c = 14 # number of coins per row/column\n", + " # data\n", + " n = 31 # the grid size\n", + " c = 14 # number of coins per row/column\n", "\n", - "# declare variables\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[(i, j)] = solver.IntVar(0, 1, 'x[%i,%i]' % (i, j))\n", + " # declare variables\n", + " x = {}\n", + " for i in range(n):\n", + " for j in range(n):\n", + " x[(i, j)] = solver.IntVar(0, 1, 'x[%i,%i]' % (i, j))\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# sum rows/columns == c\n", - "for i in range(n):\n", - " solver.Add(solver.Sum([x[(i, j)] for j in range(n)]) == c) # sum rows\n", - " solver.Add(solver.Sum([x[(j, i)] for j in range(n)]) == c) # sum cols\n", + " # sum rows/columns == c\n", + " for i in range(n):\n", + " solver.Add(solver.Sum([x[(i, j)] for j in range(n)]) == c) # sum rows\n", + " solver.Add(solver.Sum([x[(j, i)] for j in range(n)]) == c) # sum cols\n", "\n", - "# quadratic horizonal distance var\n", - "objective_var = solver.Sum(\n", - " [x[(i, j)] * (i - j) * (i - j) for i in range(n) for j in range(n)])\n", + " # quadratic horizonal distance var\n", + " objective_var = solver.Sum(\n", + " [x[(i, j)] * (i - j) * (i - j) for i in range(n) for j in range(n)])\n", "\n", - "# objective\n", - "objective = solver.Minimize(objective_var)\n", + " # objective\n", + " objective = solver.Minimize(objective_var)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", "\n", - "for i in range(n):\n", - " for j in range(n):\n", - " # int representation\n", - " print(int(x[(i, j)].SolutionValue()), end=' ')\n", + " for i in range(n):\n", + " for j in range(n):\n", + " # int representation\n", + " print(int(x[(i, j)].SolutionValue()), end=' ')\n", + " print()\n", " print()\n", - "print()\n", "\n", - "print()\n", - "print('walltime :', solver.WallTime(), 'ms')\n", - "# print 'iterations:', solver.Iterations()\n", + " print()\n", + " print('walltime :', solver.WallTime(), 'ms')\n", + " # print 'iterations:', solver.Iterations()\n", + "\n", + "\n", + "main('coin grids')\n", "\n" ] } diff --git a/examples/notebook/contrib/coloring_ip.ipynb b/examples/notebook/contrib/coloring_ip.ipynb index b1edc06228..27db650479 100644 --- a/examples/notebook/contrib/coloring_ip.ipynb +++ b/examples/notebook/contrib/coloring_ip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Simple coloring problem using MIP in Google CP Solver.\n", "\n", @@ -110,105 +95,125 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "print('Solver: ', sol)\n", + " print('Solver: ', sol)\n", "\n", - "if sol == 'GLPK':\n", - " # using GLPK\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", - "else:\n", - " # Using CBC\n", - " solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " if sol == 'GLPK':\n", + " # using GLPK\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", + " else:\n", + " # Using CBC\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# max number of colors\n", - "# [we know that 4 suffices for normal maps]\n", - "nc = 5\n", + " # max number of colors\n", + " # [we know that 4 suffices for normal maps]\n", + " nc = 5\n", "\n", - "# number of nodes\n", - "n = 11\n", - "# set of nodes\n", - "V = list(range(n))\n", + " # number of nodes\n", + " n = 11\n", + " # set of nodes\n", + " V = list(range(n))\n", "\n", - "num_edges = 20\n", + " num_edges = 20\n", "\n", - "#\n", - "# Neighbours\n", - "#\n", - "# This data correspond to the instance myciel3.col from:\n", - "# http://mat.gsia.cmu.edu/COLOR/instances.html\n", - "#\n", - "# Note: 1-based (adjusted below)\n", - "E = [[1, 2], [1, 4], [1, 7], [1, 9], [2, 3], [2, 6], [2, 8], [3, 5], [3, 7],\n", - " [3, 10], [4, 5], [4, 6], [4, 10], [5, 8], [5, 9], [6, 11], [7, 11],\n", - " [8, 11], [9, 11], [10, 11]]\n", + " #\n", + " # Neighbours\n", + " #\n", + " # This data correspond to the instance myciel3.col from:\n", + " # http://mat.gsia.cmu.edu/COLOR/instances.html\n", + " #\n", + " # Note: 1-based (adjusted below)\n", + " E = [[1, 2], [1, 4], [1, 7], [1, 9], [2, 3], [2, 6], [2, 8], [3, 5], [3, 7],\n", + " [3, 10], [4, 5], [4, 6], [4, 10], [5, 8], [5, 9], [6, 11], [7, 11],\n", + " [8, 11], [9, 11], [10, 11]]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", + " #\n", + " # declare variables\n", + " #\n", "\n", - "# x[i,c] = 1 means that node i is assigned color c\n", - "x = {}\n", - "for v in V:\n", - " for j in range(nc):\n", - " x[v, j] = solver.IntVar(0, 1, 'v[%i,%i]' % (v, j))\n", + " # x[i,c] = 1 means that node i is assigned color c\n", + " x = {}\n", + " for v in V:\n", + " for j in range(nc):\n", + " x[v, j] = solver.IntVar(0, 1, 'v[%i,%i]' % (v, j))\n", "\n", - "# u[c] = 1 means that color c is used, i.e. assigned to some node\n", - "u = [solver.IntVar(0, 1, 'u[%i]' % i) for i in range(nc)]\n", + " # u[c] = 1 means that color c is used, i.e. assigned to some node\n", + " u = [solver.IntVar(0, 1, 'u[%i]' % i) for i in range(nc)]\n", "\n", - "# number of colors used, to minimize\n", - "obj = solver.Sum(u)\n", + " # number of colors used, to minimize\n", + " obj = solver.Sum(u)\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# each node must be assigned exactly one color\n", - "for i in V:\n", - " solver.Add(solver.Sum([x[i, c] for c in range(nc)]) == 1)\n", + " # each node must be assigned exactly one color\n", + " for i in V:\n", + " solver.Add(solver.Sum([x[i, c] for c in range(nc)]) == 1)\n", "\n", - "# adjacent nodes cannot be assigned the same color\n", - "# (and adjust to 0-based)\n", - "for i in range(num_edges):\n", - " for c in range(nc):\n", - " solver.Add(x[E[i][0] - 1, c] + x[E[i][1] - 1, c] <= u[c])\n", + " # adjacent nodes cannot be assigned the same color\n", + " # (and adjust to 0-based)\n", + " for i in range(num_edges):\n", + " for c in range(nc):\n", + " solver.Add(x[E[i][0] - 1, c] + x[E[i][1] - 1, c] <= u[c])\n", "\n", - "# objective\n", - "objective = solver.Minimize(obj)\n", + " # objective\n", + " objective = solver.Minimize(obj)\n", "\n", - "#\n", - "# solution\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution\n", + " #\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('number of colors:', int(solver.Objective().Value()))\n", - "print('colors used:', [int(u[i].SolutionValue()) for i in range(nc)])\n", - "print()\n", + " print()\n", + " print('number of colors:', int(solver.Objective().Value()))\n", + " print('colors used:', [int(u[i].SolutionValue()) for i in range(nc)])\n", + " print()\n", "\n", - "for v in V:\n", - " print('v%i' % v, ' color ', end=' ')\n", - " for c in range(nc):\n", - " if int(x[v, c].SolutionValue()) == 1:\n", - " print(c)\n", + " for v in V:\n", + " print('v%i' % v, ' color ', end=' ')\n", + " for c in range(nc):\n", + " if int(x[v, c].SolutionValue()) == 1:\n", + " print(c)\n", "\n", - "print()\n", - "print('WallTime:', solver.WallTime())\n", - "if sol == 'CBC':\n", - " print('iterations:', solver.Iterations())\n", + " print()\n", + " print('WallTime:', solver.WallTime())\n", + " if sol == 'CBC':\n", + " print('iterations:', solver.Iterations())\n", + "\n", + "\n", + "\n", + "sol = 'CBC'\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/combinatorial_auction2.ipynb b/examples/notebook/contrib/combinatorial_auction2.ipynb index 99dd17c949..621bbb2cd6 100644 --- a/examples/notebook/contrib/combinatorial_auction2.ipynb +++ b/examples/notebook/contrib/combinatorial_auction2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", - "\"\"\"Combinatorial auction in Google CP Solver.\n", + "Combinatorial auction in Google CP Solver.\n", "\n", " This is a more general model for the combinatorial example\n", " in the Numberjack Tutorial, pages 9 and 24 (slides 19/175 and\n", @@ -102,80 +87,92 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from collections import *\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Problem\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Problem\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "N = 5\n", + " #\n", + " # data\n", + " #\n", + " N = 5\n", "\n", - "# the items for each bid\n", - "items = [\n", - " [0, 1], # A,B\n", - " [0, 2], # A, C\n", - " [1, 3], # B,D\n", - " [1, 2, 3], # B,C,D\n", - " [0] # A\n", - "]\n", - "# collect the bids for each item\n", - "items_t = defaultdict(list)\n", + " # the items for each bid\n", + " items = [\n", + " [0, 1], # A,B\n", + " [0, 2], # A, C\n", + " [1, 3], # B,D\n", + " [1, 2, 3], # B,C,D\n", + " [0] # A\n", + " ]\n", + " # collect the bids for each item\n", + " items_t = defaultdict(list)\n", "\n", - "# [items_t.setdefault(j,[]).append(i) for i in range(N) for j in items[i] ]\n", - "# nicer:\n", - "[items_t[j].append(i) for i in range(N) for j in items[i]]\n", + " # [items_t.setdefault(j,[]).append(i) for i in range(N) for j in items[i] ]\n", + " # nicer:\n", + " [items_t[j].append(i) for i in range(N) for j in items[i]]\n", "\n", - "bid_amount = [10, 20, 30, 40, 14]\n", + " bid_amount = [10, 20, 30, 40, 14]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "X = [solver.BoolVar(\"x%i\" % i) for i in range(N)]\n", - "obj = solver.IntVar(0, 100, \"obj\")\n", + " #\n", + " # declare variables\n", + " #\n", + " X = [solver.BoolVar(\"x%i\" % i) for i in range(N)]\n", + " obj = solver.IntVar(0, 100, \"obj\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(obj == solver.ScalProd(X, bid_amount))\n", - "for item in items_t:\n", - " solver.Add(solver.Sum([X[bid] for bid in items_t[item]]) <= 1)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(obj == solver.ScalProd(X, bid_amount))\n", + " for item in items_t:\n", + " solver.Add(solver.Sum([X[bid] for bid in items_t[item]]) <= 1)\n", "\n", - "# objective\n", - "objective = solver.Maximize(obj, 1)\n", + " # objective\n", + " objective = solver.Maximize(obj, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(X)\n", - "solution.Add(obj)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(X)\n", + " solution.Add(obj)\n", "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(X, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(X, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"X:\", [X[i].Value() for i in range(N)])\n", + " print(\"obj:\", obj.Value())\n", + " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", - "solver.NewSearch(db, [objective])\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"X:\", [X[i].Value() for i in range(N)])\n", - " print(\"obj:\", obj.Value())\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/contiguity_regular.ipynb b/examples/notebook/contrib/contiguity_regular.ipynb index e8eea4e2c8..66408f2480 100644 --- a/examples/notebook/contrib/contiguity_regular.ipynb +++ b/examples/notebook/contrib/contiguity_regular.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Global constraint contiguity using regularin Google CP Solver.\n", "\n", @@ -113,8 +98,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "#\n", @@ -187,63 +180,67 @@ " a[i + 1] == solver.Element(d2_flatten, ((a[i]) * S) + (x[i] - 1)))\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Global contiguity using regular')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Global contiguity using regular')\n", "\n", - "#\n", - "# data\n", - "#\n", - "# the DFA (for regular)\n", - "n_states = 3\n", - "input_max = 2\n", - "initial_state = 1 # 0 is for the failing state\n", + " #\n", + " # data\n", + " #\n", + " # the DFA (for regular)\n", + " n_states = 3\n", + " input_max = 2\n", + " initial_state = 1 # 0 is for the failing state\n", "\n", - "# all states are accepting states\n", - "accepting_states = [1, 2, 3]\n", + " # all states are accepting states\n", + " accepting_states = [1, 2, 3]\n", "\n", - "# The regular expression 0*1*0*\n", - "transition_fn = [\n", - " [1, 2], # state 1 (start): input 0 -> state 1, input 1 -> state 2 i.e. 0*\n", - " [3, 2], # state 2: 1*\n", - " [3, 0], # state 3: 0*\n", - "]\n", + " # The regular expression 0*1*0*\n", + " transition_fn = [\n", + " [1, 2], # state 1 (start): input 0 -> state 1, input 1 -> state 2 i.e. 0*\n", + " [3, 2], # state 2: 1*\n", + " [3, 0], # state 3: 0*\n", + " ]\n", "\n", - "n = 7\n", + " n = 7\n", "\n", - "#\n", - "# declare variables\n", - "#\n", + " #\n", + " # declare variables\n", + " #\n", "\n", - "# We use 1..2 and subtract 1 in the solution\n", - "reg_input = [solver.IntVar(1, 2, 'x[%i]' % i) for i in range(n)]\n", + " # We use 1..2 and subtract 1 in the solution\n", + " reg_input = [solver.IntVar(1, 2, 'x[%i]' % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", - " accepting_states)\n", + " #\n", + " # constraints\n", + " #\n", + " regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", + " accepting_states)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(reg_input, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(reg_input, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " # Note: here we subract 1 from the solution\n", - " print('reg_input:', [int(reg_input[i].Value() - 1) for i in range(n)])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " # Note: here we subract 1 from the solution\n", + " print('reg_input:', [int(reg_input[i].Value() - 1) for i in range(n)])\n", "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('wall_time:', solver.WallTime(), 'ms')\n", + " solver.EndSearch()\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('wall_time:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/costas_array.ipynb b/examples/notebook/contrib/costas_array.ipynb index 9af88293ea..2046b42f1b 100644 --- a/examples/notebook/contrib/costas_array.ipynb +++ b/examples/notebook/contrib/costas_array.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Costas array in Google CP Solver.\n", "\n", @@ -133,109 +118,123 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(n=6):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Costas array\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Costas array\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"n:\", n)\n", + " #\n", + " # data\n", + " #\n", + " print(\"n:\", n)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "costas = [solver.IntVar(1, n, \"costas[%i]\" % i) for i in range(n)]\n", - "differences = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " differences[(i, j)] = solver.IntVar(-n + 1, n - 1,\n", - " \"differences[%i,%i]\" % (i, j))\n", - "differences_flat = [differences[i, j] for i in range(n) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# Fix the values in the lower triangle in the\n", - "# difference matrix to -n+1. This removes variants\n", - "# of the difference matrix for the the same Costas array.\n", - "for i in range(n):\n", - " for j in range(i + 1):\n", - " solver.Add(differences[i, j] == -n + 1)\n", - "\n", - "# hakank: All the following constraints are from\n", - "# Barry O'Sullivans's original model.\n", - "#\n", - "solver.Add(solver.AllDifferent(costas))\n", - "\n", - "# \"How do the positions in the Costas array relate\n", - "# to the elements of the distance triangle.\"\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if i < j:\n", - " solver.Add(differences[(i, j)] == costas[j] - costas[j - i - 1])\n", - "\n", - "# \"All entries in a particular row of the difference\n", - "# triangle must be distint.\"\n", - "for i in range(n - 2):\n", - " solver.Add(\n", - " solver.AllDifferent([differences[i, j] for j in range(n) if j > i]))\n", - "\n", - "#\n", - "# \"All the following are redundant - only here to speed up search.\"\n", - "#\n", - "\n", - "# \"We can never place a 'token' in the same row as any other.\"\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if i < j:\n", - " solver.Add(differences[i, j] != 0)\n", - "\n", - "for k in range(2, n):\n", - " for l in range(2, n):\n", - " if k < l:\n", - " solver.Add(differences[k - 2, l - 1] + differences[k, l] ==\n", - " differences[k - 1, l - 1] + differences[k - 1, l])\n", - "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(costas + differences_flat, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"costas:\", [costas[i].Value() for i in range(n)])\n", - " print(\"differences:\")\n", + " #\n", + " # declare variables\n", + " #\n", + " costas = [solver.IntVar(1, n, \"costas[%i]\" % i) for i in range(n)]\n", + " differences = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " v = differences[i, j].Value()\n", - " if v == -n + 1:\n", - " print(\" \", end=\" \")\n", - " else:\n", - " print(\"%2d\" % v, end=\" \")\n", + " differences[(i, j)] = solver.IntVar(-n + 1, n - 1,\n", + " \"differences[%i,%i]\" % (i, j))\n", + " differences_flat = [differences[i, j] for i in range(n) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # Fix the values in the lower triangle in the\n", + " # difference matrix to -n+1. This removes variants\n", + " # of the difference matrix for the the same Costas array.\n", + " for i in range(n):\n", + " for j in range(i + 1):\n", + " solver.Add(differences[i, j] == -n + 1)\n", + "\n", + " # hakank: All the following constraints are from\n", + " # Barry O'Sullivans's original model.\n", + " #\n", + " solver.Add(solver.AllDifferent(costas))\n", + "\n", + " # \"How do the positions in the Costas array relate\n", + " # to the elements of the distance triangle.\"\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if i < j:\n", + " solver.Add(differences[(i, j)] == costas[j] - costas[j - i - 1])\n", + "\n", + " # \"All entries in a particular row of the difference\n", + " # triangle must be distint.\"\n", + " for i in range(n - 2):\n", + " solver.Add(\n", + " solver.AllDifferent([differences[i, j] for j in range(n) if j > i]))\n", + "\n", + " #\n", + " # \"All the following are redundant - only here to speed up search.\"\n", + " #\n", + "\n", + " # \"We can never place a 'token' in the same row as any other.\"\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if i < j:\n", + " solver.Add(differences[i, j] != 0)\n", + "\n", + " for k in range(2, n):\n", + " for l in range(2, n):\n", + " if k < l:\n", + " solver.Add(differences[k - 2, l - 1] + differences[k, l] ==\n", + " differences[k - 1, l - 1] + differences[k - 1, l])\n", + "\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(costas + differences_flat, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"costas:\", [costas[i].Value() for i in range(n)])\n", + " print(\"differences:\")\n", + " for i in range(n):\n", + " for j in range(n):\n", + " v = differences[i, j].Value()\n", + " if v == -n + 1:\n", + " print(\" \", end=\" \")\n", + " else:\n", + " print(\"%2d\" % v, end=\" \")\n", + " print()\n", " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", + "\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "\n", - "n = 6\n" + "n = 6\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "main(n)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/covering_opl.ipynb b/examples/notebook/contrib/covering_opl.ipynb index 2602fb3114..ae9e626a46 100644 --- a/examples/notebook/contrib/covering_opl.ipynb +++ b/examples/notebook/contrib/covering_opl.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Set covering problem in Google CP Solver.\n", "\n", @@ -129,87 +114,99 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Set covering\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Set covering\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "nb_workers = 32\n", - "Workers = list(range(nb_workers))\n", - "num_tasks = 15\n", - "Tasks = list(range(num_tasks))\n", + " #\n", + " # data\n", + " #\n", + " nb_workers = 32\n", + " Workers = list(range(nb_workers))\n", + " num_tasks = 15\n", + " Tasks = list(range(num_tasks))\n", "\n", - "# Which worker is qualified for each task.\n", - "# Note: This is 1-based and will be made 0-base below.\n", - "Qualified = [[1, 9, 19, 22, 25, 28, 31],\n", - " [2, 12, 15, 19, 21, 23, 27, 29, 30, 31, 32],\n", - " [3, 10, 19, 24, 26, 30, 32], [4, 21, 25, 28, 32],\n", - " [5, 11, 16, 22, 23, 27, 31], [6, 20, 24, 26, 30, 32],\n", - " [7, 12, 17, 25, 30, 31], [8, 17, 20, 22, 23],\n", - " [9, 13, 14, 26, 29, 30, 31], [10, 21, 25, 31, 32],\n", - " [14, 15, 18, 23, 24, 27, 30, 32], [18, 19, 22, 24, 26, 29, 31],\n", - " [11, 20, 25, 28, 30, 32], [16, 19, 23, 31],\n", - " [9, 18, 26, 28, 31, 32]]\n", + " # Which worker is qualified for each task.\n", + " # Note: This is 1-based and will be made 0-base below.\n", + " Qualified = [[1, 9, 19, 22, 25, 28, 31],\n", + " [2, 12, 15, 19, 21, 23, 27, 29, 30, 31, 32],\n", + " [3, 10, 19, 24, 26, 30, 32], [4, 21, 25, 28, 32],\n", + " [5, 11, 16, 22, 23, 27, 31], [6, 20, 24, 26, 30, 32],\n", + " [7, 12, 17, 25, 30, 31], [8, 17, 20, 22, 23],\n", + " [9, 13, 14, 26, 29, 30, 31], [10, 21, 25, 31, 32],\n", + " [14, 15, 18, 23, 24, 27, 30, 32], [18, 19, 22, 24, 26, 29, 31],\n", + " [11, 20, 25, 28, 30, 32], [16, 19, 23, 31],\n", + " [9, 18, 26, 28, 31, 32]]\n", "\n", - "Cost = [\n", - " 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5,\n", - " 5, 6, 6, 6, 7, 8, 9\n", - "]\n", + " Cost = [\n", + " 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5,\n", + " 5, 6, 6, 6, 7, 8, 9\n", + " ]\n", "\n", - "#\n", - "# variables\n", - "#\n", - "Hire = [solver.IntVar(0, 1, \"Hire[%i]\" % w) for w in Workers]\n", - "total_cost = solver.IntVar(0, nb_workers * sum(Cost), \"total_cost\")\n", + " #\n", + " # variables\n", + " #\n", + " Hire = [solver.IntVar(0, 1, \"Hire[%i]\" % w) for w in Workers]\n", + " total_cost = solver.IntVar(0, nb_workers * sum(Cost), \"total_cost\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(total_cost == solver.ScalProd(Hire, Cost))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(total_cost == solver.ScalProd(Hire, Cost))\n", "\n", - "for j in Tasks:\n", - " # Sum the cost for hiring the qualified workers\n", - " # (also, make 0-base)\n", - " b = solver.Sum([Hire[c - 1] for c in Qualified[j]])\n", - " solver.Add(b >= 1)\n", + " for j in Tasks:\n", + " # Sum the cost for hiring the qualified workers\n", + " # (also, make 0-base)\n", + " b = solver.Sum([Hire[c - 1] for c in Qualified[j]])\n", + " solver.Add(b >= 1)\n", "\n", - "# objective: Minimize total cost\n", - "objective = solver.Minimize(total_cost, 1)\n", + " # objective: Minimize total cost\n", + " objective = solver.Minimize(total_cost, 1)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(Hire, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(Hire, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db, [objective])\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"Total cost\", total_cost.Value())\n", + " print(\"We should hire these workers: \", end=\" \")\n", + " for w in Workers:\n", + " if Hire[w].Value() == 1:\n", + " print(w, end=\" \")\n", + " print()\n", + " print()\n", + "\n", + " solver.EndSearch()\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"Total cost\", total_cost.Value())\n", - " print(\"We should hire these workers: \", end=\" \")\n", - " for w in Workers:\n", - " if Hire[w].Value() == 1:\n", - " print(w, end=\" \")\n", - " print()\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/crew.ipynb b/examples/notebook/contrib/crew.ipynb index 975c18be4d..bdc2a11006 100644 --- a/examples/notebook/contrib/crew.ipynb +++ b/examples/notebook/contrib/crew.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Crew allocation problem in Google CP Solver.\n", "\n", @@ -111,172 +96,187 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(sols=1):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Crew\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Crew\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "names = [\n", - " \"Tom\", \"David\", \"Jeremy\", \"Ron\", \"Joe\", \"Bill\", \"Fred\", \"Bob\", \"Mario\",\n", - " \"Ed\", \"Carol\", \"Janet\", \"Tracy\", \"Marilyn\", \"Carolyn\", \"Cathy\", \"Inez\",\n", - " \"Jean\", \"Heather\", \"Juliet\"\n", - "]\n", + " #\n", + " # data\n", + " #\n", + " names = [\n", + " \"Tom\", \"David\", \"Jeremy\", \"Ron\", \"Joe\", \"Bill\", \"Fred\", \"Bob\", \"Mario\",\n", + " \"Ed\", \"Carol\", \"Janet\", \"Tracy\", \"Marilyn\", \"Carolyn\", \"Cathy\", \"Inez\",\n", + " \"Jean\", \"Heather\", \"Juliet\"\n", + " ]\n", "\n", - "num_persons = len(names) # number of persons\n", + " num_persons = len(names) # number of persons\n", "\n", - "attributes = [\n", - " # steward, hostess, french, spanish, german\n", - " [1, 0, 0, 0, 1], # Tom = 1\n", - " [1, 0, 0, 0, 0], # David = 2\n", - " [1, 0, 0, 0, 1], # Jeremy = 3\n", - " [1, 0, 0, 0, 0], # Ron = 4\n", - " [1, 0, 0, 1, 0], # Joe = 5\n", - " [1, 0, 1, 1, 0], # Bill = 6\n", - " [1, 0, 0, 1, 0], # Fred = 7\n", - " [1, 0, 0, 0, 0], # Bob = 8\n", - " [1, 0, 0, 1, 1], # Mario = 9\n", - " [1, 0, 0, 0, 0], # Ed = 10\n", - " [0, 1, 0, 0, 0], # Carol = 11\n", - " [0, 1, 0, 0, 0], # Janet = 12\n", - " [0, 1, 0, 0, 0], # Tracy = 13\n", - " [0, 1, 0, 1, 1], # Marilyn = 14\n", - " [0, 1, 0, 0, 0], # Carolyn = 15\n", - " [0, 1, 0, 0, 0], # Cathy = 16\n", - " [0, 1, 1, 1, 1], # Inez = 17\n", - " [0, 1, 1, 0, 0], # Jean = 18\n", - " [0, 1, 0, 1, 1], # Heather = 19\n", - " [0, 1, 1, 0, 0] # Juliet = 20\n", - "]\n", + " attributes = [\n", + " # steward, hostess, french, spanish, german\n", + " [1, 0, 0, 0, 1], # Tom = 1\n", + " [1, 0, 0, 0, 0], # David = 2\n", + " [1, 0, 0, 0, 1], # Jeremy = 3\n", + " [1, 0, 0, 0, 0], # Ron = 4\n", + " [1, 0, 0, 1, 0], # Joe = 5\n", + " [1, 0, 1, 1, 0], # Bill = 6\n", + " [1, 0, 0, 1, 0], # Fred = 7\n", + " [1, 0, 0, 0, 0], # Bob = 8\n", + " [1, 0, 0, 1, 1], # Mario = 9\n", + " [1, 0, 0, 0, 0], # Ed = 10\n", + " [0, 1, 0, 0, 0], # Carol = 11\n", + " [0, 1, 0, 0, 0], # Janet = 12\n", + " [0, 1, 0, 0, 0], # Tracy = 13\n", + " [0, 1, 0, 1, 1], # Marilyn = 14\n", + " [0, 1, 0, 0, 0], # Carolyn = 15\n", + " [0, 1, 0, 0, 0], # Cathy = 16\n", + " [0, 1, 1, 1, 1], # Inez = 17\n", + " [0, 1, 1, 0, 0], # Jean = 18\n", + " [0, 1, 0, 1, 1], # Heather = 19\n", + " [0, 1, 1, 0, 0] # Juliet = 20\n", + " ]\n", "\n", - "# The columns are in the following order:\n", - "# staff : Overall number of cabin crew needed\n", - "# stewards : How many stewards are required\n", - "# hostesses : How many hostesses are required\n", - "# french : How many French speaking employees are required\n", - "# spanish : How many Spanish speaking employees are required\n", - "# german : How many German speaking employees are required\n", - "required_crew = [\n", - " [4, 1, 1, 1, 1, 1], # Flight 1\n", - " [5, 1, 1, 1, 1, 1], # Flight 2\n", - " [5, 1, 1, 1, 1, 1], # ..\n", - " [6, 2, 2, 1, 1, 1],\n", - " [7, 3, 3, 1, 1, 1],\n", - " [4, 1, 1, 1, 1, 1],\n", - " [5, 1, 1, 1, 1, 1],\n", - " [6, 1, 1, 1, 1, 1],\n", - " [6, 2, 2, 1, 1, 1], # ...\n", - " [7, 3, 3, 1, 1, 1] # Flight 10\n", - "]\n", + " # The columns are in the following order:\n", + " # staff : Overall number of cabin crew needed\n", + " # stewards : How many stewards are required\n", + " # hostesses : How many hostesses are required\n", + " # french : How many French speaking employees are required\n", + " # spanish : How many Spanish speaking employees are required\n", + " # german : How many German speaking employees are required\n", + " required_crew = [\n", + " [4, 1, 1, 1, 1, 1], # Flight 1\n", + " [5, 1, 1, 1, 1, 1], # Flight 2\n", + " [5, 1, 1, 1, 1, 1], # ..\n", + " [6, 2, 2, 1, 1, 1],\n", + " [7, 3, 3, 1, 1, 1],\n", + " [4, 1, 1, 1, 1, 1],\n", + " [5, 1, 1, 1, 1, 1],\n", + " [6, 1, 1, 1, 1, 1],\n", + " [6, 2, 2, 1, 1, 1], # ...\n", + " [7, 3, 3, 1, 1, 1] # Flight 10\n", + " ]\n", "\n", - "num_flights = len(required_crew) # number of flights\n", + " num_flights = len(required_crew) # number of flights\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "crew = {}\n", - "for i in range(num_flights):\n", - " for j in range(num_persons):\n", - " crew[(i, j)] = solver.IntVar(0, 1, \"crew[%i,%i]\" % (i, j))\n", - "crew_flat = [\n", - " crew[(i, j)] for i in range(num_flights) for j in range(num_persons)\n", - "]\n", - "\n", - "# number of working persons\n", - "num_working = solver.IntVar(1, num_persons, \"num_working\")\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# number of working persons\n", - "solver.Add(num_working == solver.Sum([\n", - " solver.IsGreaterOrEqualCstVar(\n", - " solver.Sum([crew[(f, p)]\n", - " for f in range(num_flights)]), 1)\n", - " for p in range(num_persons)\n", - "]))\n", - "\n", - "for f in range(num_flights):\n", - " # size of crew\n", - " tmp = [crew[(f, i)] for i in range(num_persons)]\n", - " solver.Add(solver.Sum(tmp) == required_crew[f][0])\n", - "\n", - " # attributes and requirements\n", - " for j in range(5):\n", - " tmp = [attributes[i][j] * crew[(f, i)] for i in range(num_persons)]\n", - " solver.Add(solver.Sum(tmp) >= required_crew[f][j + 1])\n", - "\n", - "# after a flight, break for at least two flights\n", - "for f in range(num_flights - 2):\n", - " for i in range(num_persons):\n", - " solver.Add(crew[f, i] + crew[f + 1, i] + crew[f + 2, i] <= 1)\n", - "\n", - "# extra contraint: all must work at least two of the flights\n", - "# for i in range(num_persons):\n", - "# [solver.Add(solver.Sum([crew[f,i] for f in range(num_flights)]) >= 2) ]\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(crew_flat)\n", - "solution.Add(num_working)\n", - "\n", - "db = solver.Phase(crew_flat, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "#\n", - "# result\n", - "#\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"Solution #%i\" % num_solutions)\n", - " print(\"Number working:\", num_working.Value())\n", + " #\n", + " # declare variables\n", + " #\n", + " crew = {}\n", " for i in range(num_flights):\n", " for j in range(num_persons):\n", - " print(crew[i, j].Value(), end=\" \")\n", - " print()\n", - " print()\n", + " crew[(i, j)] = solver.IntVar(0, 1, \"crew[%i,%i]\" % (i, j))\n", + " crew_flat = [\n", + " crew[(i, j)] for i in range(num_flights) for j in range(num_persons)\n", + " ]\n", "\n", - " print(\"Flights:\")\n", - " for flight in range(num_flights):\n", - " print(\"Flight\", flight, \"persons:\", end=\" \")\n", - " for person in range(num_persons):\n", - " if crew[flight, person].Value() == 1:\n", - " print(names[person], end=\" \")\n", - " print()\n", - " print()\n", + " # number of working persons\n", + " num_working = solver.IntVar(1, num_persons, \"num_working\")\n", "\n", - " print(\"Crew:\")\n", - " for person in range(num_persons):\n", - " print(\"%-10s flights\" % names[person], end=\" \")\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # number of working persons\n", + " solver.Add(num_working == solver.Sum([\n", + " solver.IsGreaterOrEqualCstVar(\n", + " solver.Sum([crew[(f, p)]\n", + " for f in range(num_flights)]), 1)\n", + " for p in range(num_persons)\n", + " ]))\n", + "\n", + " for f in range(num_flights):\n", + " # size of crew\n", + " tmp = [crew[(f, i)] for i in range(num_persons)]\n", + " solver.Add(solver.Sum(tmp) == required_crew[f][0])\n", + "\n", + " # attributes and requirements\n", + " for j in range(5):\n", + " tmp = [attributes[i][j] * crew[(f, i)] for i in range(num_persons)]\n", + " solver.Add(solver.Sum(tmp) >= required_crew[f][j + 1])\n", + "\n", + " # after a flight, break for at least two flights\n", + " for f in range(num_flights - 2):\n", + " for i in range(num_persons):\n", + " solver.Add(crew[f, i] + crew[f + 1, i] + crew[f + 2, i] <= 1)\n", + "\n", + " # extra contraint: all must work at least two of the flights\n", + " # for i in range(num_persons):\n", + " # [solver.Add(solver.Sum([crew[f,i] for f in range(num_flights)]) >= 2) ]\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(crew_flat)\n", + " solution.Add(num_working)\n", + "\n", + " db = solver.Phase(crew_flat, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " #\n", + " # result\n", + " #\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"Solution #%i\" % num_solutions)\n", + " print(\"Number working:\", num_working.Value())\n", + " for i in range(num_flights):\n", + " for j in range(num_persons):\n", + " print(crew[i, j].Value(), end=\" \")\n", + " print()\n", + " print()\n", + "\n", + " print(\"Flights:\")\n", " for flight in range(num_flights):\n", - " if crew[flight, person].Value() == 1:\n", - " print(flight, end=\" \")\n", + " print(\"Flight\", flight, \"persons:\", end=\" \")\n", + " for person in range(num_persons):\n", + " if crew[flight, person].Value() == 1:\n", + " print(names[person], end=\" \")\n", + " print()\n", " print()\n", + "\n", + " print(\"Crew:\")\n", + " for person in range(num_persons):\n", + " print(\"%-10s flights\" % names[person], end=\" \")\n", + " for flight in range(num_flights):\n", + " if crew[flight, person].Value() == 1:\n", + " print(flight, end=\" \")\n", + " print()\n", + " print()\n", + "\n", + " if num_solutions >= sols:\n", + " break\n", + " solver.EndSearch()\n", + "\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - " if num_solutions >= sols:\n", - " break\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "num_solutions_to_show = 1\n", + "if (len(sys.argv) > 1):\n", + " num_solutions_to_show = int(sys.argv[1])\n", "\n", - "num_solutions_to_show = 1\n" + "main(num_solutions_to_show)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/crossword2.ipynb b/examples/notebook/contrib/crossword2.ipynb index d2162e66dc..6928087458 100644 --- a/examples/notebook/contrib/crossword2.ipynb +++ b/examples/notebook/contrib/crossword2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Crosswords in Google CP Solver.\n", "\n", @@ -130,133 +115,143 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Problem\")\n", + "def main():\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Problem\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "alpha = \"_abcdefghijklmnopqrstuvwxyz\"\n", - "a = 1\n", - "b = 2\n", - "c = 3\n", - "d = 4\n", - "e = 5\n", - "f = 6\n", - "g = 7\n", - "h = 8\n", - "i = 9\n", - "j = 10\n", - "k = 11\n", - "l = 12\n", - "m = 13\n", - "n = 14\n", - "o = 15\n", - "p = 16\n", - "q = 17\n", - "r = 18\n", - "s = 19\n", - "t = 20\n", - "u = 21\n", - "v = 22\n", - "w = 23\n", - "x = 24\n", - "y = 25\n", - "z = 26\n", + " #\n", + " # data\n", + " #\n", + " alpha = \"_abcdefghijklmnopqrstuvwxyz\"\n", + " a = 1\n", + " b = 2\n", + " c = 3\n", + " d = 4\n", + " e = 5\n", + " f = 6\n", + " g = 7\n", + " h = 8\n", + " i = 9\n", + " j = 10\n", + " k = 11\n", + " l = 12\n", + " m = 13\n", + " n = 14\n", + " o = 15\n", + " p = 16\n", + " q = 17\n", + " r = 18\n", + " s = 19\n", + " t = 20\n", + " u = 21\n", + " v = 22\n", + " w = 23\n", + " x = 24\n", + " y = 25\n", + " z = 26\n", "\n", - "num_words = 15\n", - "word_len = 5\n", - "AA = [\n", - " [h, o, s, e, s], # HOSES\n", - " [l, a, s, e, r], # LASER\n", - " [s, a, i, l, s], # SAILS\n", - " [s, h, e, e, t], # SHEET\n", - " [s, t, e, e, r], # STEER\n", - " [h, e, e, l, 0], # HEEL\n", - " [h, i, k, e, 0], # HIKE\n", - " [k, e, e, l, 0], # KEEL\n", - " [k, n, o, t, 0], # KNOT\n", - " [l, i, n, e, 0], # LINE\n", - " [a, f, t, 0, 0], # AFT\n", - " [a, l, e, 0, 0], # ALE\n", - " [e, e, l, 0, 0], # EEL\n", - " [l, e, e, 0, 0], # LEE\n", - " [t, i, e, 0, 0] # TIE\n", - "]\n", + " num_words = 15\n", + " word_len = 5\n", + " AA = [\n", + " [h, o, s, e, s], # HOSES\n", + " [l, a, s, e, r], # LASER\n", + " [s, a, i, l, s], # SAILS\n", + " [s, h, e, e, t], # SHEET\n", + " [s, t, e, e, r], # STEER\n", + " [h, e, e, l, 0], # HEEL\n", + " [h, i, k, e, 0], # HIKE\n", + " [k, e, e, l, 0], # KEEL\n", + " [k, n, o, t, 0], # KNOT\n", + " [l, i, n, e, 0], # LINE\n", + " [a, f, t, 0, 0], # AFT\n", + " [a, l, e, 0, 0], # ALE\n", + " [e, e, l, 0, 0], # EEL\n", + " [l, e, e, 0, 0], # LEE\n", + " [t, i, e, 0, 0] # TIE\n", + " ]\n", "\n", - "num_overlapping = 12\n", - "overlapping = [\n", - " [0, 2, 1, 0], # s\n", - " [0, 4, 2, 0], # s\n", - " [3, 1, 1, 2], # i\n", - " [3, 2, 4, 0], # k\n", - " [3, 3, 2, 2], # e\n", - " [6, 0, 1, 3], # l\n", - " [6, 1, 4, 1], # e\n", - " [6, 2, 2, 3], # e\n", - " [7, 0, 5, 1], # l\n", - " [7, 2, 1, 4], # s\n", - " [7, 3, 4, 2], # e\n", - " [7, 4, 2, 4] # r\n", - "]\n", + " num_overlapping = 12\n", + " overlapping = [\n", + " [0, 2, 1, 0], # s\n", + " [0, 4, 2, 0], # s\n", + " [3, 1, 1, 2], # i\n", + " [3, 2, 4, 0], # k\n", + " [3, 3, 2, 2], # e\n", + " [6, 0, 1, 3], # l\n", + " [6, 1, 4, 1], # e\n", + " [6, 2, 2, 3], # e\n", + " [7, 0, 5, 1], # l\n", + " [7, 2, 1, 4], # s\n", + " [7, 3, 4, 2], # e\n", + " [7, 4, 2, 4] # r\n", + " ]\n", "\n", - "n = 8\n", + " n = 8\n", "\n", - "# declare variables\n", - "A = {}\n", - "for I in range(num_words):\n", - " for J in range(word_len):\n", - " A[(I, J)] = solver.IntVar(0, 26, \"A(%i,%i)\" % (I, J))\n", + " # declare variables\n", + " A = {}\n", + " for I in range(num_words):\n", + " for J in range(word_len):\n", + " A[(I, J)] = solver.IntVar(0, 26, \"A(%i,%i)\" % (I, J))\n", "\n", - "A_flat = [A[(I, J)] for I in range(num_words) for J in range(word_len)]\n", - "E = [solver.IntVar(0, num_words, \"E%i\" % I) for I in range(n)]\n", + " A_flat = [A[(I, J)] for I in range(num_words) for J in range(word_len)]\n", + " E = [solver.IntVar(0, num_words, \"E%i\" % I) for I in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(E))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(E))\n", "\n", - "for I in range(num_words):\n", - " for J in range(word_len):\n", - " solver.Add(A[(I, J)] == AA[I][J])\n", + " for I in range(num_words):\n", + " for J in range(word_len):\n", + " solver.Add(A[(I, J)] == AA[I][J])\n", "\n", - "for I in range(num_overlapping):\n", - " # This is what I would do:\n", - " # solver.Add(A[(E[overlapping[I][0]], overlapping[I][1])] == A[(E[overlapping[I][2]], overlapping[I][3])])\n", + " for I in range(num_overlapping):\n", + " # This is what I would do:\n", + " # solver.Add(A[(E[overlapping[I][0]], overlapping[I][1])] == A[(E[overlapping[I][2]], overlapping[I][3])])\n", "\n", - " # But we must use Element explicitly\n", - " solver.Add(\n", - " solver.Element(A_flat, E[overlapping[I][0]] * word_len +\n", - " overlapping[I][1]) == solver\n", - " .Element(A_flat, E[overlapping[I][2]] * word_len + overlapping[I][3]))\n", + " # But we must use Element explicitly\n", + " solver.Add(\n", + " solver.Element(A_flat, E[overlapping[I][0]] * word_len +\n", + " overlapping[I][1]) == solver\n", + " .Element(A_flat, E[overlapping[I][2]] * word_len + overlapping[I][3]))\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(E)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(E)\n", "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(E + A_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(E + A_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(E)\n", - " print_solution(A, E, alpha, n, word_len)\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(E)\n", + " print_solution(A, E, alpha, n, word_len)\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", + "\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "def print_solution(A, E, alpha, n, word_len):\n", " for ee in range(n):\n", @@ -264,6 +259,8 @@ " print(\"\".join(\n", " [\"%s\" % (alpha[A[ee, ii].Value()]) for ii in range(word_len)]))\n", "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/crypta.ipynb b/examples/notebook/contrib/crypta.ipynb index b35f9f7d3e..fe1823e09d 100644 --- a/examples/notebook/contrib/crypta.ipynb +++ b/examples/notebook/contrib/crypta.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Cryptarithmetic puzzle in Google CP Solver.\n", "\n", @@ -117,72 +102,84 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Crypta\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Crypta\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "#\n", - "# variables\n", - "#\n", - "LD = [solver.IntVar(0, 9, \"LD[%i]\" % i) for i in range(0, 10)]\n", - "A, B, C, D, E, F, G, H, I, J = LD\n", + " #\n", + " # variables\n", + " #\n", + " LD = [solver.IntVar(0, 9, \"LD[%i]\" % i) for i in range(0, 10)]\n", + " A, B, C, D, E, F, G, H, I, J = LD\n", "\n", - "Sr1 = solver.IntVar(0, 1, \"Sr1\")\n", - "Sr2 = solver.IntVar(0, 1, \"Sr2\")\n", + " Sr1 = solver.IntVar(0, 1, \"Sr1\")\n", + " Sr2 = solver.IntVar(0, 1, \"Sr2\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(LD))\n", - "solver.Add(B >= 1)\n", - "solver.Add(D >= 1)\n", - "solver.Add(G >= 1)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(LD))\n", + " solver.Add(B >= 1)\n", + " solver.Add(D >= 1)\n", + " solver.Add(G >= 1)\n", "\n", - "solver.Add(A + 10 * E + 100 * J + 1000 * B + 10000 * B + 100000 * E +\n", - " 1000000 * F + E + 10 * J + 100 * E + 1000 * F + 10000 * G +\n", - " 100000 * A + 1000000 * F == F + 10 * E + 100 * E + 1000 * H +\n", - " 10000 * I + 100000 * F + 1000000 * B + 10000000 * Sr1)\n", + " solver.Add(A + 10 * E + 100 * J + 1000 * B + 10000 * B + 100000 * E +\n", + " 1000000 * F + E + 10 * J + 100 * E + 1000 * F + 10000 * G +\n", + " 100000 * A + 1000000 * F == F + 10 * E + 100 * E + 1000 * H +\n", + " 10000 * I + 100000 * F + 1000000 * B + 10000000 * Sr1)\n", "\n", - "solver.Add(C + 10 * F + 100 * H + 1000 * A + 10000 * I + 100000 * I +\n", - " 1000000 * J + F + 10 * I + 100 * B + 1000 * D + 10000 * I +\n", - " 100000 * D + 1000000 * C + Sr1 == J + 10 * F + 100 * A + 1000 * F +\n", - " 10000 * H + 100000 * D + 1000000 * D + 10000000 * Sr2)\n", + " solver.Add(C + 10 * F + 100 * H + 1000 * A + 10000 * I + 100000 * I +\n", + " 1000000 * J + F + 10 * I + 100 * B + 1000 * D + 10000 * I +\n", + " 100000 * D + 1000000 * C + Sr1 == J + 10 * F + 100 * A + 1000 * F +\n", + " 10000 * H + 100000 * D + 1000000 * D + 10000000 * Sr2)\n", "\n", - "solver.Add(A + 10 * J + 100 * J + 1000 * I + 10000 * A + 100000 * B + B +\n", - " 10 * A + 100 * G + 1000 * F + 10000 * H + 100000 * D + Sr2 == C +\n", - " 10 * A + 100 * G + 1000 * E + 10000 * J + 100000 * G)\n", + " solver.Add(A + 10 * J + 100 * J + 1000 * I + 10000 * A + 100000 * B + B +\n", + " 10 * A + 100 * G + 1000 * F + 10000 * H + 100000 * D + Sr2 == C +\n", + " 10 * A + 100 * G + 1000 * E + 10000 * J + 100000 * G)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(LD, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(LD, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " str = \"ABCDEFGHIJ\"\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " for (letter, val) in [(str[i], LD[i].Value()) for i in range(len(LD))]:\n", + " print(\"%s: %i\" % (letter, val))\n", + " print()\n", + "\n", + " solver.EndSearch()\n", "\n", - "num_solutions = 0\n", - "str = \"ABCDEFGHIJ\"\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " for (letter, val) in [(str[i], LD[i].Value()) for i in range(len(LD))]:\n", - " print(\"%s: %i\" % (letter, val))\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/crypto.ipynb b/examples/notebook/contrib/crypto.ipynb index e879009850..2366781436 100644 --- a/examples/notebook/contrib/crypto.ipynb +++ b/examples/notebook/contrib/crypto.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Crypto problem in Google CP Solver.\n", "\n", @@ -116,95 +101,107 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Crypto problem\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Crypto problem\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "num_letters = 26\n", + " #\n", + " # data\n", + " #\n", + " num_letters = 26\n", "\n", - "BALLET = 45\n", - "CELLO = 43\n", - "CONCERT = 74\n", - "FLUTE = 30\n", - "FUGUE = 50\n", - "GLEE = 66\n", - "JAZZ = 58\n", - "LYRE = 47\n", - "OBOE = 53\n", - "OPERA = 65\n", - "POLKA = 59\n", - "QUARTET = 50\n", - "SAXOPHONE = 134\n", - "SCALE = 51\n", - "SOLO = 37\n", - "SONG = 61\n", - "SOPRANO = 82\n", - "THEME = 72\n", - "VIOLIN = 100\n", - "WALTZ = 34\n", + " BALLET = 45\n", + " CELLO = 43\n", + " CONCERT = 74\n", + " FLUTE = 30\n", + " FUGUE = 50\n", + " GLEE = 66\n", + " JAZZ = 58\n", + " LYRE = 47\n", + " OBOE = 53\n", + " OPERA = 65\n", + " POLKA = 59\n", + " QUARTET = 50\n", + " SAXOPHONE = 134\n", + " SCALE = 51\n", + " SOLO = 37\n", + " SONG = 61\n", + " SOPRANO = 82\n", + " THEME = 72\n", + " VIOLIN = 100\n", + " WALTZ = 34\n", "\n", - "#\n", - "# variables\n", - "#\n", - "LD = [solver.IntVar(1, num_letters, \"LD[%i]\" % i) for i in range(num_letters)]\n", - "A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z = LD\n", + " #\n", + " # variables\n", + " #\n", + " LD = [solver.IntVar(1, num_letters, \"LD[%i]\" % i) for i in range(num_letters)]\n", + " A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z = LD\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(LD))\n", - "solver.Add(B + A + L + L + E + T == BALLET)\n", - "solver.Add(C + E + L + L + O == CELLO)\n", - "solver.Add(C + O + N + C + E + R + T == CONCERT)\n", - "solver.Add(F + L + U + T + E == FLUTE)\n", - "solver.Add(F + U + G + U + E == FUGUE)\n", - "solver.Add(G + L + E + E == GLEE)\n", - "solver.Add(J + A + Z + Z == JAZZ)\n", - "solver.Add(L + Y + R + E == LYRE)\n", - "solver.Add(O + B + O + E == OBOE)\n", - "solver.Add(O + P + E + R + A == OPERA)\n", - "solver.Add(P + O + L + K + A == POLKA)\n", - "solver.Add(Q + U + A + R + T + E + T == QUARTET)\n", - "solver.Add(S + A + X + O + P + H + O + N + E == SAXOPHONE)\n", - "solver.Add(S + C + A + L + E == SCALE)\n", - "solver.Add(S + O + L + O == SOLO)\n", - "solver.Add(S + O + N + G == SONG)\n", - "solver.Add(S + O + P + R + A + N + O == SOPRANO)\n", - "solver.Add(T + H + E + M + E == THEME)\n", - "solver.Add(V + I + O + L + I + N == VIOLIN)\n", - "solver.Add(W + A + L + T + Z == WALTZ)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(LD))\n", + " solver.Add(B + A + L + L + E + T == BALLET)\n", + " solver.Add(C + E + L + L + O == CELLO)\n", + " solver.Add(C + O + N + C + E + R + T == CONCERT)\n", + " solver.Add(F + L + U + T + E == FLUTE)\n", + " solver.Add(F + U + G + U + E == FUGUE)\n", + " solver.Add(G + L + E + E == GLEE)\n", + " solver.Add(J + A + Z + Z == JAZZ)\n", + " solver.Add(L + Y + R + E == LYRE)\n", + " solver.Add(O + B + O + E == OBOE)\n", + " solver.Add(O + P + E + R + A == OPERA)\n", + " solver.Add(P + O + L + K + A == POLKA)\n", + " solver.Add(Q + U + A + R + T + E + T == QUARTET)\n", + " solver.Add(S + A + X + O + P + H + O + N + E == SAXOPHONE)\n", + " solver.Add(S + C + A + L + E == SCALE)\n", + " solver.Add(S + O + L + O == SOLO)\n", + " solver.Add(S + O + N + G == SONG)\n", + " solver.Add(S + O + P + R + A + N + O == SOPRANO)\n", + " solver.Add(T + H + E + M + E == THEME)\n", + " solver.Add(V + I + O + L + I + N == VIOLIN)\n", + " solver.Add(W + A + L + T + Z == WALTZ)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(LD, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.ASSIGN_CENTER_VALUE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(LD, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.ASSIGN_CENTER_VALUE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " str = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " for (letter, val) in [(str[i], LD[i].Value()) for i in range(num_letters)]:\n", + " print(\"%s: %i\" % (letter, val))\n", + " print()\n", + "\n", + " solver.EndSearch()\n", "\n", - "num_solutions = 0\n", - "str = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " for (letter, val) in [(str[i], LD[i].Value()) for i in range(num_letters)]:\n", - " print(\"%s: %i\" % (letter, val))\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/curious_set_of_integers.ipynb b/examples/notebook/contrib/curious_set_of_integers.ipynb index d2c32b4bb3..7229c48603 100644 --- a/examples/notebook/contrib/curious_set_of_integers.ipynb +++ b/examples/notebook/contrib/curious_set_of_integers.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Crypto problem in Google CP Solver.\n", "\n", @@ -132,8 +117,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", @@ -142,59 +135,63 @@ " solver.Add(x[i] <= x[i + 1])\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Curious set of integers\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Curious set of integers\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 5\n", - "max_val = 10000\n", + " #\n", + " # data\n", + " #\n", + " n = 5\n", + " max_val = 10000\n", "\n", - "#\n", - "# variables\n", - "#\n", - "x = [solver.IntVar(0, max_val, \"x[%i]\" % i) for i in range(n)]\n", + " #\n", + " # variables\n", + " #\n", + " x = [solver.IntVar(0, max_val, \"x[%i]\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", - "decreasing(solver, x)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", + " decreasing(solver, x)\n", "\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if i != j:\n", - " p = solver.IntVar(0, max_val, \"p[%i,%i]\" % (i, j))\n", - " solver.Add(p * p - 1 == (x[i] * x[j]))\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if i != j:\n", + " p = solver.IntVar(0, max_val, \"p[%i,%i]\" % (i, j))\n", + " solver.Add(p * p - 1 == (x[i] * x[j]))\n", "\n", - "# This is the original problem:\n", - "# Which is the fifth number?\n", - "v = [1, 3, 8, 120]\n", - "b = [solver.IsMemberVar(x[i], v) for i in range(n)]\n", - "solver.Add(solver.Sum(b) == 4)\n", + " # This is the original problem:\n", + " # Which is the fifth number?\n", + " v = [1, 3, 8, 120]\n", + " b = [solver.IsMemberVar(x[i], v) for i in range(n)]\n", + " solver.Add(solver.Sum(b) == 4)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"x:\", [int(x[i].Value()) for i in range(n)])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"x:\", [int(x[i].Value()) for i in range(n)])\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/debruijn_binary.ipynb b/examples/notebook/contrib/debruijn_binary.ipynb index 8695f7bb56..06aa1118bb 100644 --- a/examples/notebook/contrib/debruijn_binary.ipynb +++ b/examples/notebook/contrib/debruijn_binary.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " de Bruijn sequences in Google CP Solver.\n", "\n", @@ -115,8 +100,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -129,134 +122,145 @@ " s == solver.Sum([(base**(tlen - i - 1)) * t[i] for i in range(tlen)]))\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"de Bruijn sequences\")\n", + "def main(base=2, n=3, m=8):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"de Bruijn sequences\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "# base = 2 # the base to use, i.e. the alphabet 0..n-1\n", - "# n = 3 # number of bits to use (n = 4 -> 0..base^n-1 = 0..2^4 -1, i.e. 0..15)\n", - "# m = base**n # the length of the sequence. For \"arbitrary\" de Bruijn\n", - "# sequences\n", + " #\n", + " # data\n", + " #\n", + " # base = 2 # the base to use, i.e. the alphabet 0..n-1\n", + " # n = 3 # number of bits to use (n = 4 -> 0..base^n-1 = 0..2^4 -1, i.e. 0..15)\n", + " # m = base**n # the length of the sequence. For \"arbitrary\" de Bruijn\n", + " # sequences\n", "\n", - "# base = 4\n", - "# n = 4\n", - "# m = base**n\n", + " # base = 4\n", + " # n = 4\n", + " # m = base**n\n", "\n", - "# harder problem\n", - "#base = 13\n", - "#n = 4\n", - "#m = 52\n", + " # harder problem\n", + " #base = 13\n", + " #n = 4\n", + " #m = 52\n", "\n", - "# for n = 4 with different value of base\n", - "# base = 2 0.030 seconds 16 failures\n", - "# base = 3 0.041 108\n", - "# base = 4 0.070 384\n", - "# base = 5 0.231 1000\n", - "# base = 6 0.736 2160\n", - "# base = 7 2.2 seconds 4116\n", - "# base = 8 6 seconds 7168\n", - "# base = 9 16 seconds 11664\n", - "# base = 10 42 seconds 18000\n", - "# base = 6\n", - "# n = 4\n", - "# m = base**n\n", + " # for n = 4 with different value of base\n", + " # base = 2 0.030 seconds 16 failures\n", + " # base = 3 0.041 108\n", + " # base = 4 0.070 384\n", + " # base = 5 0.231 1000\n", + " # base = 6 0.736 2160\n", + " # base = 7 2.2 seconds 4116\n", + " # base = 8 6 seconds 7168\n", + " # base = 9 16 seconds 11664\n", + " # base = 10 42 seconds 18000\n", + " # base = 6\n", + " # n = 4\n", + " # m = base**n\n", "\n", - "# if True then ensure that the number of occurrences of 0..base-1 is\n", - "# the same (and if m mod base = 0)\n", - "check_same_gcc = True\n", + " # if True then ensure that the number of occurrences of 0..base-1 is\n", + " # the same (and if m mod base = 0)\n", + " check_same_gcc = True\n", "\n", - "print(\"base: %i n: %i m: %i\" % (base, n, m))\n", - "if check_same_gcc:\n", - " print(\"Checks gcc\")\n", + " print(\"base: %i n: %i m: %i\" % (base, n, m))\n", + " if check_same_gcc:\n", + " print(\"Checks gcc\")\n", "\n", - "# declare variables\n", - "x = [solver.IntVar(0, (base**n) - 1, \"x%i\" % i) for i in range(m)]\n", - "binary = {}\n", - "for i in range(m):\n", - " for j in range(n):\n", - " binary[(i, j)] = solver.IntVar(0, base - 1, \"x_%i_%i\" % (i, j))\n", + " # declare variables\n", + " x = [solver.IntVar(0, (base**n) - 1, \"x%i\" % i) for i in range(m)]\n", + " binary = {}\n", + " for i in range(m):\n", + " for j in range(n):\n", + " binary[(i, j)] = solver.IntVar(0, base - 1, \"x_%i_%i\" % (i, j))\n", "\n", - "bin_code = [solver.IntVar(0, base - 1, \"bin_code%i\" % i) for i in range(m)]\n", + " bin_code = [solver.IntVar(0, base - 1, \"bin_code%i\" % i) for i in range(m)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "#solver.Add(solver.AllDifferent([x[i] for i in range(m)]))\n", - "solver.Add(solver.AllDifferent(x))\n", + " #\n", + " # constraints\n", + " #\n", + " #solver.Add(solver.AllDifferent([x[i] for i in range(m)]))\n", + " solver.Add(solver.AllDifferent(x))\n", "\n", - "# converts x <-> binary\n", - "for i in range(m):\n", - " t = [solver.IntVar(0, base - 1, \"t_%i\" % j) for j in range(n)]\n", - " toNum(solver, t, x[i], base)\n", - " for j in range(n):\n", - " solver.Add(binary[(i, j)] == t[j])\n", + " # converts x <-> binary\n", + " for i in range(m):\n", + " t = [solver.IntVar(0, base - 1, \"t_%i\" % j) for j in range(n)]\n", + " toNum(solver, t, x[i], base)\n", + " for j in range(n):\n", + " solver.Add(binary[(i, j)] == t[j])\n", "\n", - "# the de Bruijn condition\n", - "# the first elements in binary[i] is the same as the last\n", - "# elements in binary[i-i]\n", - "for i in range(1, m - 1):\n", - " for j in range(1, n - 1):\n", - " solver.Add(binary[(i - 1, j)] == binary[(i, j - 1)])\n", + " # the de Bruijn condition\n", + " # the first elements in binary[i] is the same as the last\n", + " # elements in binary[i-i]\n", + " for i in range(1, m - 1):\n", + " for j in range(1, n - 1):\n", + " solver.Add(binary[(i - 1, j)] == binary[(i, j - 1)])\n", "\n", - "# ... and around the corner\n", - "for j in range(1, n):\n", - " solver.Add(binary[(m - 1, j)] == binary[(0, j - 1)])\n", + " # ... and around the corner\n", + " for j in range(1, n):\n", + " solver.Add(binary[(m - 1, j)] == binary[(0, j - 1)])\n", "\n", - "# converts binary -> bin_code\n", - "for i in range(m):\n", - " solver.Add(bin_code[i] == binary[(i, 0)])\n", + " # converts binary -> bin_code\n", + " for i in range(m):\n", + " solver.Add(bin_code[i] == binary[(i, 0)])\n", "\n", - "# extra: ensure that all the numbers in the de Bruijn sequence\n", - "# (bin_code) has the same occurrences (if check_same_gcc is True\n", - "# and mathematically possible)\n", - "gcc = [solver.IntVar(0, m, \"gcc%i\" % i) for i in range(base)]\n", - "solver.Add(solver.Distribute(bin_code, list(range(base)), gcc))\n", - "if check_same_gcc and m % base == 0:\n", - " for i in range(1, base):\n", - " solver.Add(gcc[i] == gcc[i - 1])\n", + " # extra: ensure that all the numbers in the de Bruijn sequence\n", + " # (bin_code) has the same occurrences (if check_same_gcc is True\n", + " # and mathematically possible)\n", + " gcc = [solver.IntVar(0, m, \"gcc%i\" % i) for i in range(base)]\n", + " solver.Add(solver.Distribute(bin_code, list(range(base)), gcc))\n", + " if check_same_gcc and m % base == 0:\n", + " for i in range(1, base):\n", + " solver.Add(gcc[i] == gcc[i - 1])\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([x[i] for i in range(m)])\n", - "solution.Add([bin_code[i] for i in range(m)])\n", - "# solution.Add([binary[(i,j)] for i in range(m) for j in range(n)])\n", - "solution.Add([gcc[i] for i in range(base)])\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([x[i] for i in range(m)])\n", + " solution.Add([bin_code[i] for i in range(m)])\n", + " # solution.Add([binary[(i,j)] for i in range(m) for j in range(n)])\n", + " solution.Add([gcc[i] for i in range(base)])\n", "\n", - "db = solver.Phase([x[i] for i in range(m)] + [bin_code[i] for i in range(m)],\n", - " solver.CHOOSE_MIN_SIZE_LOWEST_MAX, solver.ASSIGN_MIN_VALUE)\n", + " db = solver.Phase([x[i] for i in range(m)] + [bin_code[i] for i in range(m)],\n", + " solver.CHOOSE_MIN_SIZE_LOWEST_MAX, solver.ASSIGN_MIN_VALUE)\n", "\n", - "num_solutions = 0\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"\\nSolution %i\" % num_solutions)\n", - " print(\"x:\", [int(x[i].Value()) for i in range(m)])\n", - " print(\"gcc:\", [int(gcc[i].Value()) for i in range(base)])\n", - " print(\"de Bruijn sequence:\", [int(bin_code[i].Value()) for i in range(m)])\n", - " # for i in range(m):\n", - " # for j in range(n):\n", - " # print binary[(i,j)].Value(),\n", - " # print\n", - " # print\n", - "solver.EndSearch()\n", + " num_solutions = 0\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"\\nSolution %i\" % num_solutions)\n", + " print(\"x:\", [int(x[i].Value()) for i in range(m)])\n", + " print(\"gcc:\", [int(gcc[i].Value()) for i in range(base)])\n", + " print(\"de Bruijn sequence:\", [int(bin_code[i].Value()) for i in range(m)])\n", + " # for i in range(m):\n", + " # for j in range(n):\n", + " # print binary[(i,j)].Value(),\n", + " # print\n", + " # print\n", + " solver.EndSearch()\n", "\n", - "if num_solutions == 0:\n", - " print(\"No solution found\")\n", + " if num_solutions == 0:\n", + " print(\"No solution found\")\n", + "\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "base = 2\n", "n = 3\n", - "m = base**n\n" + "m = base**n\n", + "if len(sys.argv) > 1:\n", + " base = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " n = int(sys.argv[2])\n", + "if len(sys.argv) > 3:\n", + " m = int(sys.argv[3])\n", + "\n", + "main(base, n, m)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/diet1.ipynb b/examples/notebook/contrib/diet1.ipynb index 7a4750b943..3a8ab98cda 100644 --- a/examples/notebook/contrib/diet1.ipynb +++ b/examples/notebook/contrib/diet1.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Simple diet problem in Google CP Solver.\n", "\n", @@ -117,58 +102,70 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.sat.python import cp_model\n", "\n", "\n", - "# Create the solver.\n", - "model = cp_model.CpModel()\n", + "def main(unused_argv):\n", + " # Create the solver.\n", + " model = cp_model.CpModel()\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", - "price = [50, 20, 30, 80] # in cents\n", - "limits = [500, 6, 10, 8] # requirements for each nutrition type\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", + " price = [50, 20, 30, 80] # in cents\n", + " limits = [500, 6, 10, 8] # requirements for each nutrition type\n", "\n", - "# nutritions for each product\n", - "calories = [400, 200, 150, 500]\n", - "chocolate = [3, 2, 0, 0]\n", - "sugar = [2, 2, 4, 4]\n", - "fat = [2, 4, 1, 5]\n", + " # nutritions for each product\n", + " calories = [400, 200, 150, 500]\n", + " chocolate = [3, 2, 0, 0]\n", + " sugar = [2, 2, 4, 4]\n", + " fat = [2, 4, 1, 5]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [model.NewIntVar(0, 100, \"x%d\" % i) for i in range(n)]\n", - "cost = model.NewIntVar(0, 10000, \"cost\")\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [model.NewIntVar(0, 100, \"x%d\" % i) for i in range(n)]\n", + " cost = model.NewIntVar(0, 10000, \"cost\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "model.Add(sum(x[i] * calories[i] for i in range(n)) >= limits[0])\n", - "model.Add(sum(x[i] * chocolate[i] for i in range(n)) >= limits[1])\n", - "model.Add(sum(x[i] * sugar[i] for i in range(n)) >= limits[2])\n", - "model.Add(sum(x[i] * fat[i] for i in range(n)) >= limits[3])\n", + " #\n", + " # constraints\n", + " #\n", + " model.Add(sum(x[i] * calories[i] for i in range(n)) >= limits[0])\n", + " model.Add(sum(x[i] * chocolate[i] for i in range(n)) >= limits[1])\n", + " model.Add(sum(x[i] * sugar[i] for i in range(n)) >= limits[2])\n", + " model.Add(sum(x[i] * fat[i] for i in range(n)) >= limits[3])\n", "\n", - "# objective\n", - "model.Minimize(cost)\n", + " # objective\n", + " model.Minimize(cost)\n", "\n", - "# Solve model.\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", + " # Solve model.\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", "\n", - "# Output solution.\n", - "if status == cp_model.OPTIMAL:\n", - " print(\"cost:\", solver.ObjectiveValue())\n", - " print([(\"abcdefghij\" [i], solver.Value(x[i])) for i in range(n)])\n", - " print()\n", - " print(' - status : %s' % solver.StatusName(status))\n", - " print(' - conflicts : %i' % solver.NumConflicts())\n", - " print(' - branches : %i' % solver.NumBranches())\n", - " print(' - wall time : %f ms' % solver.WallTime())\n", - " print()\n", + " # Output solution.\n", + " if status == cp_model.OPTIMAL:\n", + " print(\"cost:\", solver.ObjectiveValue())\n", + " print([(\"abcdefghij\" [i], solver.Value(x[i])) for i in range(n)])\n", + " print()\n", + " print(' - status : %s' % solver.StatusName(status))\n", + " print(' - conflicts : %i' % solver.NumConflicts())\n", + " print(' - branches : %i' % solver.NumBranches())\n", + " print(' - wall time : %f ms' % solver.WallTime())\n", + " print()\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/diet1_b.ipynb b/examples/notebook/contrib/diet1_b.ipynb index 426841ad6d..69429b2808 100644 --- a/examples/notebook/contrib/diet1_b.ipynb +++ b/examples/notebook/contrib/diet1_b.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Simple diet problem in Google CP Solver.\n", "\n", @@ -119,66 +104,78 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Diet\")\n", + "def main(unused_argv):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Diet\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", - "price = [50, 20, 30, 80] # in cents\n", - "limits = [500, 6, 10, 8] # requirements for each nutrition type\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", + " price = [50, 20, 30, 80] # in cents\n", + " limits = [500, 6, 10, 8] # requirements for each nutrition type\n", "\n", - "# nutritions for each product\n", - "calories = [400, 200, 150, 500]\n", - "chocolate = [3, 2, 0, 0]\n", - "sugar = [2, 2, 4, 4]\n", - "fat = [2, 4, 1, 5]\n", + " # nutritions for each product\n", + " calories = [400, 200, 150, 500]\n", + " chocolate = [3, 2, 0, 0]\n", + " sugar = [2, 2, 4, 4]\n", + " fat = [2, 4, 1, 5]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(0, 100, \"x%d\" % i) for i in range(n)]\n", - "cost = solver.IntVar(0, 10000, \"cost\")\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(0, 100, \"x%d\" % i) for i in range(n)]\n", + " cost = solver.IntVar(0, 10000, \"cost\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.ScalProd(x, calories) >= limits[0])\n", - "solver.Add(solver.ScalProd(x, chocolate) >= limits[1])\n", - "solver.Add(solver.ScalProd(x, sugar) >= limits[2])\n", - "solver.Add(solver.ScalProd(x, fat) >= limits[3])\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.ScalProd(x, calories) >= limits[0])\n", + " solver.Add(solver.ScalProd(x, chocolate) >= limits[1])\n", + " solver.Add(solver.ScalProd(x, sugar) >= limits[2])\n", + " solver.Add(solver.ScalProd(x, fat) >= limits[3])\n", "\n", - "# objective\n", - "objective = solver.Minimize(cost, 1)\n", + " # objective\n", + " objective = solver.Minimize(cost, 1)\n", "\n", - "#\n", - "# solution\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.AddObjective(cost)\n", - "solution.Add(x)\n", + " #\n", + " # solution\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.AddObjective(cost)\n", + " solution.Add(x)\n", "\n", - "# last solution since it's a minimization problem\n", - "collector = solver.LastSolutionCollector(solution)\n", - "search_log = solver.SearchLog(100, cost)\n", - "solver.Solve(\n", - " solver.Phase(x + [cost], solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE),\n", - " [objective, search_log, collector])\n", + " # last solution since it's a minimization problem\n", + " collector = solver.LastSolutionCollector(solution)\n", + " search_log = solver.SearchLog(100, cost)\n", + " solver.Solve(\n", + " solver.Phase(x + [cost], solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE),\n", + " [objective, search_log, collector])\n", "\n", - "# get the first (and only) solution\n", - "print(\"cost:\", collector.ObjectiveValue(0))\n", - "print([(\"abcdefghij\" [i], collector.Value(0, x[i])) for i in range(n)])\n", - "print()\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print()\n", + " # get the first (and only) solution\n", + " print(\"cost:\", collector.ObjectiveValue(0))\n", + " print([(\"abcdefghij\" [i], collector.Value(0, x[i])) for i in range(n)])\n", + " print()\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print()\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/diet1_mip.ipynb b/examples/notebook/contrib/diet1_mip.ipynb index 1a51693031..36a4690fed 100644 --- a/examples/notebook/contrib/diet1_mip.ipynb +++ b/examples/notebook/contrib/diet1_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Simple diet problem using MIP in Google CP Solver.\n", "\n", @@ -108,68 +93,88 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "print('Solver: ', sol)\n", + " print('Solver: ', sol)\n", "\n", - "if sol == 'GLPK':\n", - " # using GLPK\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", - "else:\n", - " # Using CBC\n", - " solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " if sol == 'GLPK':\n", + " # using GLPK\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", + " else:\n", + " # Using CBC\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", - "price = [50, 20, 30, 80] # in cents\n", - "limits = [500, 6, 10, 8] # requirements for each nutrition type\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", + " price = [50, 20, 30, 80] # in cents\n", + " limits = [500, 6, 10, 8] # requirements for each nutrition type\n", "\n", - "# nutritions for each product\n", - "calories = [400, 200, 150, 500]\n", - "chocolate = [3, 2, 0, 0]\n", - "sugar = [2, 2, 4, 4]\n", - "fat = [2, 4, 1, 5]\n", + " # nutritions for each product\n", + " calories = [400, 200, 150, 500]\n", + " chocolate = [3, 2, 0, 0]\n", + " sugar = [2, 2, 4, 4]\n", + " fat = [2, 4, 1, 5]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(0, 100, 'x%d' % i) for i in range(n)]\n", - "cost = solver.Sum([x[i] * price[i] for i in range(n)])\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(0, 100, 'x%d' % i) for i in range(n)]\n", + " cost = solver.Sum([x[i] * price[i] for i in range(n)])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.Sum([x[i] * calories[i] for i in range(n)]) >= limits[0])\n", - "solver.Add(solver.Sum([x[i] * chocolate[i] for i in range(n)]) >= limits[1])\n", - "solver.Add(solver.Sum([x[i] * sugar[i] for i in range(n)]) >= limits[2])\n", - "solver.Add(solver.Sum([x[i] * fat[i] for i in range(n)]) >= limits[3])\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.Sum([x[i] * calories[i] for i in range(n)]) >= limits[0])\n", + " solver.Add(solver.Sum([x[i] * chocolate[i] for i in range(n)]) >= limits[1])\n", + " solver.Add(solver.Sum([x[i] * sugar[i] for i in range(n)]) >= limits[2])\n", + " solver.Add(solver.Sum([x[i] * fat[i] for i in range(n)]) >= limits[3])\n", "\n", - "# objective\n", - "objective = solver.Minimize(cost)\n", + " # objective\n", + " objective = solver.Minimize(cost)\n", "\n", - "#\n", - "# solution\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution\n", + " #\n", + " solver.Solve()\n", "\n", - "print('Cost:', solver.Objective().Value())\n", - "print([int(x[i].SolutionValue()) for i in range(n)])\n", + " print('Cost:', solver.Objective().Value())\n", + " print([int(x[i].SolutionValue()) for i in range(n)])\n", "\n", - "print()\n", - "print('WallTime:', solver.WallTime())\n", - "if sol == 'CBC':\n", - " print('iterations:', solver.Iterations())\n", + " print()\n", + " print('WallTime:', solver.WallTime())\n", + " if sol == 'CBC':\n", + " print('iterations:', solver.Iterations())\n", + "\n", + "\n", + "\n", + "sol = 'CBC'\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/discrete_tomography.ipynb b/examples/notebook/contrib/discrete_tomography.ipynb index deb2351015..87414228af 100644 --- a/examples/notebook/contrib/discrete_tomography.ipynb +++ b/examples/notebook/contrib/discrete_tomography.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Discrete tomography in Google CP Solver.\n", "\n", @@ -127,79 +112,89 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(row_sums=\"\", col_sums=\"\"):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"n-queens\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"n-queens\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "if row_sums == \"\":\n", - " print(\"Using default problem instance\")\n", - " row_sums = [0, 0, 8, 2, 6, 4, 5, 3, 7, 0, 0]\n", - " col_sums = [0, 0, 7, 1, 6, 3, 4, 5, 2, 7, 0, 0]\n", + " #\n", + " # data\n", + " #\n", + " if row_sums == \"\":\n", + " print(\"Using default problem instance\")\n", + " row_sums = [0, 0, 8, 2, 6, 4, 5, 3, 7, 0, 0]\n", + " col_sums = [0, 0, 7, 1, 6, 3, 4, 5, 2, 7, 0, 0]\n", "\n", - "r = len(row_sums)\n", - "c = len(col_sums)\n", + " r = len(row_sums)\n", + " c = len(col_sums)\n", "\n", - "# declare variables\n", - "x = []\n", - "for i in range(r):\n", - " t = []\n", - " for j in range(c):\n", - " t.append(solver.IntVar(0, 1, \"x[%i,%i]\" % (i, j)))\n", - " x.append(t)\n", - "x_flat = [x[i][j] for i in range(r) for j in range(c)]\n", + " # declare variables\n", + " x = []\n", + " for i in range(r):\n", + " t = []\n", + " for j in range(c):\n", + " t.append(solver.IntVar(0, 1, \"x[%i,%i]\" % (i, j)))\n", + " x.append(t)\n", + " x_flat = [x[i][j] for i in range(r) for j in range(c)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "[\n", - " solver.Add(solver.Sum([x[i][j]\n", - " for j in range(c)]) == row_sums[i])\n", - " for i in range(r)\n", - "]\n", - "[\n", - " solver.Add(solver.Sum([x[i][j]\n", - " for i in range(r)]) == col_sums[j])\n", - " for j in range(c)\n", - "]\n", + " #\n", + " # constraints\n", + " #\n", + " [\n", + " solver.Add(solver.Sum([x[i][j]\n", + " for j in range(c)]) == row_sums[i])\n", + " for i in range(r)\n", + " ]\n", + " [\n", + " solver.Add(solver.Sum([x[i][j]\n", + " for i in range(r)]) == col_sums[j])\n", + " for j in range(c)\n", + " ]\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x_flat)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x_flat)\n", "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(x_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(x_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print_solution(x, r, c, row_sums, col_sums)\n", + " print()\n", + "\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print_solution(x, r, c, row_sums, col_sums)\n", " print()\n", - "\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", "\n", "#\n", "# Print solution\n", "#\n", "\n", + "\n", "def print_solution(x, rows, cols, row_sums, col_sums):\n", " print(\" \", end=\" \")\n", " for j in range(cols):\n", @@ -227,6 +222,14 @@ "\n", " return [row_sums, col_sums]\n", "\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " print(\"Problem instance from\", file)\n", + " [row_sums, col_sums] = read_problem(file)\n", + " main(row_sums, col_sums)\n", + "else:\n", + " main()\n", "\n" ] } diff --git a/examples/notebook/contrib/divisible_by_9_through_1.ipynb b/examples/notebook/contrib/divisible_by_9_through_1.ipynb index 8843650145..62ba85887c 100644 --- a/examples/notebook/contrib/divisible_by_9_through_1.ipynb +++ b/examples/notebook/contrib/divisible_by_9_through_1.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Divisible by 9 through 1 puzzle in Google CP Solver.\n", "\n", @@ -125,8 +110,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -179,64 +172,78 @@ " s == solver.Sum([(base**(tlen - i - 1)) * t[i] for i in range(tlen)]))\n", "\n", "\n", + "def main(base=10):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Divisible by 9 through 1\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Divisible by 9 through 1\")\n", "\n", - "# data\n", - "m = base**(base - 1) - 1\n", - "n = base - 1\n", + " # data\n", + " m = base**(base - 1) - 1\n", + " n = base - 1\n", "\n", - "digits_str = \"_0123456789ABCDEFGH\"\n", + " digits_str = \"_0123456789ABCDEFGH\"\n", "\n", - "print(\"base:\", base)\n", + " print(\"base:\", base)\n", "\n", - "# declare variables\n", + " # declare variables\n", "\n", - "# the digits\n", - "x = [solver.IntVar(1, base - 1, \"x[%i]\" % i) for i in range(n)]\n", + " # the digits\n", + " x = [solver.IntVar(1, base - 1, \"x[%i]\" % i) for i in range(n)]\n", "\n", - "# the numbers, t[0] contains the answer\n", - "t = [solver.IntVar(0, m, \"t[%i]\" % i) for i in range(n)]\n", + " # the numbers, t[0] contains the answer\n", + " t = [solver.IntVar(0, m, \"t[%i]\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", "\n", - "for i in range(n):\n", - " mm = base - i - 1\n", - " toNum(solver, [x[j] for j in range(mm)], t[i], base)\n", - " my_mod(solver, t[i], mm, 0)\n", + " for i in range(n):\n", + " mm = base - i - 1\n", + " toNum(solver, [x[j] for j in range(mm)], t[i], base)\n", + " my_mod(solver, t[i], mm, 0)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(t)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(t)\n", "\n", - "db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + " db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"x: \", [x[i].Value() for i in range(n)])\n", - " print(\"t: \", [t[i].Value() for i in range(n)])\n", - " print(\"number base 10: %i base %i: %s\" % (t[0].Value(), base, \"\".join(\n", - " [digits_str[x[i].Value() + 1] for i in range(n)])))\n", - " print()\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"x: \", [x[i].Value() for i in range(n)])\n", + " print(\"t: \", [t[i].Value() for i in range(n)])\n", + " print(\"number base 10: %i base %i: %s\" % (t[0].Value(), base, \"\".join(\n", + " [digits_str[x[i].Value() + 1] for i in range(n)])))\n", + " print()\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", + "\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "base = 10\n", "default_base = 10\n", - "max_base = 16\n" + "max_base = 16\n", + "if len(sys.argv) > 1:\n", + " base = int(sys.argv[1])\n", + " if base > max_base:\n", + " print(\"Sorry, max allowed base is %i. Setting base to %i...\" %\n", + " (max_base, default_base))\n", + " base = default_base\n", + "main(base)\n", + "\n", + "# for base in range(2, 17):\n", + "# print\n", + "# main(base)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/dudeney.ipynb b/examples/notebook/contrib/dudeney.ipynb index 3355dc6173..962e845c5d 100644 --- a/examples/notebook/contrib/dudeney.ipynb +++ b/examples/notebook/contrib/dudeney.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -114,6 +114,8 @@ " print('#fails:', solver.Failures())\n", " print('time:', solver.WallTime(), 'ms')\n", "\n", + "\n", + "dudeney(6)\n", "\n" ] } diff --git a/examples/notebook/contrib/einav_puzzle.ipynb b/examples/notebook/contrib/einav_puzzle.ipynb index 89a2736f7c..eb428a2f81 100644 --- a/examples/notebook/contrib/einav_puzzle.ipynb +++ b/examples/notebook/contrib/einav_puzzle.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " A programming puzzle from Einav in Google CP Solver.\n", "\n", @@ -136,137 +121,149 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Einav puzzle')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Einav puzzle')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# small problem\n", - "# rows = 3;\n", - "# cols = 3;\n", - "# data = [\n", - "# [ 33, 30, -10],\n", - "# [-16, 19, 9],\n", - "# [-17, -12, -14]\n", - "# ]\n", + " # small problem\n", + " # rows = 3;\n", + " # cols = 3;\n", + " # data = [\n", + " # [ 33, 30, -10],\n", + " # [-16, 19, 9],\n", + " # [-17, -12, -14]\n", + " # ]\n", "\n", - "# Full problem\n", - "rows = 27\n", - "cols = 9\n", - "data = [[33, 30, 10, -6, 18, -7, -11, 23, -6],\n", - " [16, -19, 9, -26, -8, -19, -8, -21, -14],\n", - " [17, 12, -14, 31, -30, 13, -13, 19, 16],\n", - " [-6, -11, 1, 17, -12, -4, -7, 14, -21],\n", - " [18, -31, 34, -22, 17, -19, 20, 24, 6],\n", - " [33, -18, 17, -15, 31, -5, 3, 27, -3],\n", - " [-18, -20, -18, 31, 6, 4, -2, -12, 24],\n", - " [27, 14, 4, -29, -3, 5, -29, 8, -12],\n", - " [-15, -7, -23, 23, -9, -8, 6, 8, -12],\n", - " [33, -23, -19, -4, -8, -7, 11, -12, 31],\n", - " [-20, 19, -15, -30, 11, 32, 7, 14, -5],\n", - " [-23, 18, -32, -2, -31, -7, 8, 24, 16],\n", - " [32, -4, -10, -14, -6, -1, 0, 23, 23],\n", - " [25, 0, -23, 22, 12, 28, -27, 15, 4],\n", - " [-30, -13, -16, -3, -3, -32, -3, 27, -31],\n", - " [22, 1, 26, 4, -2, -13, 26, 17, 14],\n", - " [-9, -18, 3, -20, -27, -32, -11, 27, 13],\n", - " [-17, 33, -7, 19, -32, 13, -31, -2, -24],\n", - " [-31, 27, -31, -29, 15, 2, 29, -15, 33],\n", - " [-18, -23, 15, 28, 0, 30, -4, 12, -32],\n", - " [-3, 34, 27, -25, -18, 26, 1, 34, 26],\n", - " [-21, -31, -10, -13, -30, -17, -12, -26, 31],\n", - " [23, -31, -19, 21, -17, -10, 2, -23, 23],\n", - " [-3, 6, 0, -3, -32, 0, -10, -25, 14],\n", - " [-19, 9, 14, -27, 20, 15, -5, -27, 18],\n", - " [11, -6, 24, 7, -17, 26, 20, -31, -25],\n", - " [-25, 4, -16, 30, 33, 23, -4, -4, 23]]\n", + " # Full problem\n", + " rows = 27\n", + " cols = 9\n", + " data = [[33, 30, 10, -6, 18, -7, -11, 23, -6],\n", + " [16, -19, 9, -26, -8, -19, -8, -21, -14],\n", + " [17, 12, -14, 31, -30, 13, -13, 19, 16],\n", + " [-6, -11, 1, 17, -12, -4, -7, 14, -21],\n", + " [18, -31, 34, -22, 17, -19, 20, 24, 6],\n", + " [33, -18, 17, -15, 31, -5, 3, 27, -3],\n", + " [-18, -20, -18, 31, 6, 4, -2, -12, 24],\n", + " [27, 14, 4, -29, -3, 5, -29, 8, -12],\n", + " [-15, -7, -23, 23, -9, -8, 6, 8, -12],\n", + " [33, -23, -19, -4, -8, -7, 11, -12, 31],\n", + " [-20, 19, -15, -30, 11, 32, 7, 14, -5],\n", + " [-23, 18, -32, -2, -31, -7, 8, 24, 16],\n", + " [32, -4, -10, -14, -6, -1, 0, 23, 23],\n", + " [25, 0, -23, 22, 12, 28, -27, 15, 4],\n", + " [-30, -13, -16, -3, -3, -32, -3, 27, -31],\n", + " [22, 1, 26, 4, -2, -13, 26, 17, 14],\n", + " [-9, -18, 3, -20, -27, -32, -11, 27, 13],\n", + " [-17, 33, -7, 19, -32, 13, -31, -2, -24],\n", + " [-31, 27, -31, -29, 15, 2, 29, -15, 33],\n", + " [-18, -23, 15, 28, 0, 30, -4, 12, -32],\n", + " [-3, 34, 27, -25, -18, 26, 1, 34, 26],\n", + " [-21, -31, -10, -13, -30, -17, -12, -26, 31],\n", + " [23, -31, -19, 21, -17, -10, 2, -23, 23],\n", + " [-3, 6, 0, -3, -32, 0, -10, -25, 14],\n", + " [-19, 9, 14, -27, 20, 15, -5, -27, 18],\n", + " [11, -6, 24, 7, -17, 26, 20, -31, -25],\n", + " [-25, 4, -16, 30, 33, 23, -4, -4, 23]]\n", "\n", - "#\n", - "# variables\n", - "#\n", - "x = {}\n", - "for i in range(rows):\n", - " for j in range(cols):\n", - " x[i, j] = solver.IntVar(-100, 100, 'x[%i,%i]' % (i, j))\n", - "\n", - "x_flat = [x[i, j] for i in range(rows) for j in range(cols)]\n", - "\n", - "row_sums = [solver.IntVar(0, 300, 'row_sums(%i)' % i) for i in range(rows)]\n", - "col_sums = [solver.IntVar(0, 300, 'col_sums(%i)' % j) for j in range(cols)]\n", - "\n", - "row_signs = [solver.IntVar([-1, 1], 'row_signs(%i)' % i) for i in range(rows)]\n", - "col_signs = [solver.IntVar([-1, 1], 'col_signs(%i)' % j) for j in range(cols)]\n", - "\n", - "# total sum: to be minimized\n", - "total_sum = solver.IntVar(0, 1000, 'total_sum')\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(rows):\n", - " for j in range(cols):\n", - " solver.Add(x[i, j] == data[i][j] * row_signs[i] * col_signs[j])\n", - "\n", - "total_sum_a = [\n", - " data[i][j] * row_signs[i] * col_signs[j]\n", - " for i in range(rows)\n", - " for j in range(cols)\n", - "]\n", - "solver.Add(total_sum == solver.Sum(total_sum_a))\n", - "\n", - "# row sums\n", - "for i in range(rows):\n", - " s = [row_signs[i] * col_signs[j] * data[i][j] for j in range(cols)]\n", - " solver.Add(row_sums[i] == solver.Sum(s))\n", - "\n", - "# column sums\n", - "for j in range(cols):\n", - " s = [row_signs[i] * col_signs[j] * data[i][j] for i in range(rows)]\n", - " solver.Add(col_sums[j] == solver.Sum(s))\n", - "\n", - "# objective\n", - "objective = solver.Minimize(total_sum, 1)\n", - "\n", - "#\n", - "# search and result\n", - "#\n", - "# Note: The order of the variables makes a big difference.\n", - "# If row_signs are before col_sign it is much slower.\n", - "db = solver.Phase(col_signs + row_signs, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.ASSIGN_MAX_VALUE)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('total_sum:', total_sum.Value())\n", - " print('row_sums:', [row_sums[i].Value() for i in range(rows)])\n", - " print('col_sums:', [col_sums[j].Value() for j in range(cols)])\n", - " print('row_signs:', [row_signs[i].Value() for i in range(rows)])\n", - " print('col_signs:', [col_signs[j].Value() for j in range(cols)])\n", - " print('x:')\n", + " #\n", + " # variables\n", + " #\n", + " x = {}\n", " for i in range(rows):\n", " for j in range(cols):\n", - " print('%3i' % x[i, j].Value(), end=' ')\n", + " x[i, j] = solver.IntVar(-100, 100, 'x[%i,%i]' % (i, j))\n", + "\n", + " x_flat = [x[i, j] for i in range(rows) for j in range(cols)]\n", + "\n", + " row_sums = [solver.IntVar(0, 300, 'row_sums(%i)' % i) for i in range(rows)]\n", + " col_sums = [solver.IntVar(0, 300, 'col_sums(%i)' % j) for j in range(cols)]\n", + "\n", + " row_signs = [solver.IntVar([-1, 1], 'row_signs(%i)' % i) for i in range(rows)]\n", + " col_signs = [solver.IntVar([-1, 1], 'col_signs(%i)' % j) for j in range(cols)]\n", + "\n", + " # total sum: to be minimized\n", + " total_sum = solver.IntVar(0, 1000, 'total_sum')\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " for i in range(rows):\n", + " for j in range(cols):\n", + " solver.Add(x[i, j] == data[i][j] * row_signs[i] * col_signs[j])\n", + "\n", + " total_sum_a = [\n", + " data[i][j] * row_signs[i] * col_signs[j]\n", + " for i in range(rows)\n", + " for j in range(cols)\n", + " ]\n", + " solver.Add(total_sum == solver.Sum(total_sum_a))\n", + "\n", + " # row sums\n", + " for i in range(rows):\n", + " s = [row_signs[i] * col_signs[j] * data[i][j] for j in range(cols)]\n", + " solver.Add(row_sums[i] == solver.Sum(s))\n", + "\n", + " # column sums\n", + " for j in range(cols):\n", + " s = [row_signs[i] * col_signs[j] * data[i][j] for i in range(rows)]\n", + " solver.Add(col_sums[j] == solver.Sum(s))\n", + "\n", + " # objective\n", + " objective = solver.Minimize(total_sum, 1)\n", + "\n", + " #\n", + " # search and result\n", + " #\n", + " # Note: The order of the variables makes a big difference.\n", + " # If row_signs are before col_sign it is much slower.\n", + " db = solver.Phase(col_signs + row_signs, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.ASSIGN_MAX_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('total_sum:', total_sum.Value())\n", + " print('row_sums:', [row_sums[i].Value() for i in range(rows)])\n", + " print('col_sums:', [col_sums[j].Value() for j in range(cols)])\n", + " print('row_signs:', [row_signs[i].Value() for i in range(rows)])\n", + " print('col_signs:', [col_signs[j].Value() for j in range(cols)])\n", + " print('x:')\n", + " for i in range(rows):\n", + " for j in range(cols):\n", + " print('%3i' % x[i, j].Value(), end=' ')\n", + " print()\n", " print()\n", + "\n", + " solver.EndSearch()\n", + "\n", " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/einav_puzzle2.ipynb b/examples/notebook/contrib/einav_puzzle2.ipynb index 88a74fbedb..24ef4e4f1c 100644 --- a/examples/notebook/contrib/einav_puzzle2.ipynb +++ b/examples/notebook/contrib/einav_puzzle2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " A programming puzzle from Einav in Google CP Solver.\n", "\n", @@ -137,130 +122,142 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Einav puzzle\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Einav puzzle\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# small problem\n", - "# rows = 3;\n", - "# cols = 3;\n", - "# data = [\n", - "# [ 33, 30, -10],\n", - "# [-16, 19, 9],\n", - "# [-17, -12, -14]\n", - "# ]\n", + " # small problem\n", + " # rows = 3;\n", + " # cols = 3;\n", + " # data = [\n", + " # [ 33, 30, -10],\n", + " # [-16, 19, 9],\n", + " # [-17, -12, -14]\n", + " # ]\n", "\n", - "# Full problem\n", - "rows = 27\n", - "cols = 9\n", - "data = [[33, 30, 10, -6, 18, -7, -11, 23, -6],\n", - " [16, -19, 9, -26, -8, -19, -8, -21, -14],\n", - " [17, 12, -14, 31, -30, 13, -13, 19, 16],\n", - " [-6, -11, 1, 17, -12, -4, -7, 14, -21],\n", - " [18, -31, 34, -22, 17, -19, 20, 24, 6],\n", - " [33, -18, 17, -15, 31, -5, 3, 27, -3],\n", - " [-18, -20, -18, 31, 6, 4, -2, -12, 24],\n", - " [27, 14, 4, -29, -3, 5, -29, 8, -12],\n", - " [-15, -7, -23, 23, -9, -8, 6, 8, -12],\n", - " [33, -23, -19, -4, -8, -7, 11, -12, 31],\n", - " [-20, 19, -15, -30, 11, 32, 7, 14, -5],\n", - " [-23, 18, -32, -2, -31, -7, 8, 24, 16],\n", - " [32, -4, -10, -14, -6, -1, 0, 23, 23],\n", - " [25, 0, -23, 22, 12, 28, -27, 15, 4],\n", - " [-30, -13, -16, -3, -3, -32, -3, 27, -31],\n", - " [22, 1, 26, 4, -2, -13, 26, 17, 14],\n", - " [-9, -18, 3, -20, -27, -32, -11, 27, 13],\n", - " [-17, 33, -7, 19, -32, 13, -31, -2, -24],\n", - " [-31, 27, -31, -29, 15, 2, 29, -15, 33],\n", - " [-18, -23, 15, 28, 0, 30, -4, 12, -32],\n", - " [-3, 34, 27, -25, -18, 26, 1, 34, 26],\n", - " [-21, -31, -10, -13, -30, -17, -12, -26, 31],\n", - " [23, -31, -19, 21, -17, -10, 2, -23, 23],\n", - " [-3, 6, 0, -3, -32, 0, -10, -25, 14],\n", - " [-19, 9, 14, -27, 20, 15, -5, -27, 18],\n", - " [11, -6, 24, 7, -17, 26, 20, -31, -25],\n", - " [-25, 4, -16, 30, 33, 23, -4, -4, 23]]\n", + " # Full problem\n", + " rows = 27\n", + " cols = 9\n", + " data = [[33, 30, 10, -6, 18, -7, -11, 23, -6],\n", + " [16, -19, 9, -26, -8, -19, -8, -21, -14],\n", + " [17, 12, -14, 31, -30, 13, -13, 19, 16],\n", + " [-6, -11, 1, 17, -12, -4, -7, 14, -21],\n", + " [18, -31, 34, -22, 17, -19, 20, 24, 6],\n", + " [33, -18, 17, -15, 31, -5, 3, 27, -3],\n", + " [-18, -20, -18, 31, 6, 4, -2, -12, 24],\n", + " [27, 14, 4, -29, -3, 5, -29, 8, -12],\n", + " [-15, -7, -23, 23, -9, -8, 6, 8, -12],\n", + " [33, -23, -19, -4, -8, -7, 11, -12, 31],\n", + " [-20, 19, -15, -30, 11, 32, 7, 14, -5],\n", + " [-23, 18, -32, -2, -31, -7, 8, 24, 16],\n", + " [32, -4, -10, -14, -6, -1, 0, 23, 23],\n", + " [25, 0, -23, 22, 12, 28, -27, 15, 4],\n", + " [-30, -13, -16, -3, -3, -32, -3, 27, -31],\n", + " [22, 1, 26, 4, -2, -13, 26, 17, 14],\n", + " [-9, -18, 3, -20, -27, -32, -11, 27, 13],\n", + " [-17, 33, -7, 19, -32, 13, -31, -2, -24],\n", + " [-31, 27, -31, -29, 15, 2, 29, -15, 33],\n", + " [-18, -23, 15, 28, 0, 30, -4, 12, -32],\n", + " [-3, 34, 27, -25, -18, 26, 1, 34, 26],\n", + " [-21, -31, -10, -13, -30, -17, -12, -26, 31],\n", + " [23, -31, -19, 21, -17, -10, 2, -23, 23],\n", + " [-3, 6, 0, -3, -32, 0, -10, -25, 14],\n", + " [-19, 9, 14, -27, 20, 15, -5, -27, 18],\n", + " [11, -6, 24, 7, -17, 26, 20, -31, -25],\n", + " [-25, 4, -16, 30, 33, 23, -4, -4, 23]]\n", "\n", - "#\n", - "# variables\n", - "#\n", - "x = {}\n", - "for i in range(rows):\n", - " for j in range(cols):\n", - " x[i, j] = solver.IntVar(-100, 100, \"x[%i,%i]\" % (i, j))\n", - "\n", - "x_flat = [x[i, j] for i in range(rows) for j in range(cols)]\n", - "\n", - "row_signs = [solver.IntVar([-1, 1], \"row_signs(%i)\" % i) for i in range(rows)]\n", - "col_signs = [solver.IntVar([-1, 1], \"col_signs(%i)\" % j) for j in range(cols)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(rows):\n", - " for j in range(cols):\n", - " solver.Add(x[i, j] == data[i][j] * row_signs[i] * col_signs[j])\n", - "\n", - "total_sum = solver.Sum([x[i, j] for i in range(rows) for j in range(cols)])\n", - "\n", - "#\n", - "# Note: In einav_puzzle.py row_sums and col_sums are decision variables.\n", - "#\n", - "\n", - "# row sums\n", - "row_sums = [\n", - " solver.Sum([x[i, j] for j in range(cols)]).Var() for i in range(rows)\n", - "]\n", - "# >= 0\n", - "for i in range(rows):\n", - " row_sums[i].SetMin(0)\n", - "\n", - "# column sums\n", - "col_sums = [\n", - " solver.Sum([x[i, j] for i in range(rows)]).Var() for j in range(cols)\n", - "]\n", - "for j in range(cols):\n", - " col_sums[j].SetMin(0)\n", - "\n", - "# objective\n", - "objective = solver.Minimize(total_sum, 1)\n", - "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(col_signs + row_signs, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.ASSIGN_MAX_VALUE)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"Sum =\", objective.Best())\n", - " print(\"row_sums:\", [row_sums[i].Value() for i in range(rows)])\n", - " print(\"col_sums:\", [col_sums[j].Value() for j in range(cols)])\n", + " #\n", + " # variables\n", + " #\n", + " x = {}\n", " for i in range(rows):\n", " for j in range(cols):\n", - " print(\"%3i\" % x[i, j].Value(), end=\" \")\n", + " x[i, j] = solver.IntVar(-100, 100, \"x[%i,%i]\" % (i, j))\n", + "\n", + " x_flat = [x[i, j] for i in range(rows) for j in range(cols)]\n", + "\n", + " row_signs = [solver.IntVar([-1, 1], \"row_signs(%i)\" % i) for i in range(rows)]\n", + " col_signs = [solver.IntVar([-1, 1], \"col_signs(%i)\" % j) for j in range(cols)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " for i in range(rows):\n", + " for j in range(cols):\n", + " solver.Add(x[i, j] == data[i][j] * row_signs[i] * col_signs[j])\n", + "\n", + " total_sum = solver.Sum([x[i, j] for i in range(rows) for j in range(cols)])\n", + "\n", + " #\n", + " # Note: In einav_puzzle.py row_sums and col_sums are decision variables.\n", + " #\n", + "\n", + " # row sums\n", + " row_sums = [\n", + " solver.Sum([x[i, j] for j in range(cols)]).Var() for i in range(rows)\n", + " ]\n", + " # >= 0\n", + " for i in range(rows):\n", + " row_sums[i].SetMin(0)\n", + "\n", + " # column sums\n", + " col_sums = [\n", + " solver.Sum([x[i, j] for i in range(rows)]).Var() for j in range(cols)\n", + " ]\n", + " for j in range(cols):\n", + " col_sums[j].SetMin(0)\n", + "\n", + " # objective\n", + " objective = solver.Minimize(total_sum, 1)\n", + "\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(col_signs + row_signs, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.ASSIGN_MAX_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"Sum =\", objective.Best())\n", + " print(\"row_sums:\", [row_sums[i].Value() for i in range(rows)])\n", + " print(\"col_sums:\", [col_sums[j].Value() for j in range(cols)])\n", + " for i in range(rows):\n", + " for j in range(cols):\n", + " print(\"%3i\" % x[i, j].Value(), end=\" \")\n", + " print()\n", " print()\n", + "\n", + " solver.EndSearch()\n", + "\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/eq10.ipynb b/examples/notebook/contrib/eq10.ipynb index a8ec97ecf1..fe395c42cb 100644 --- a/examples/notebook/contrib/eq10.ipynb +++ b/examples/notebook/contrib/eq10.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Eq 10 in Google CP Solver.\n", "\n", @@ -100,79 +85,91 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Eq 10\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Eq 10\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 7\n", + " #\n", + " # data\n", + " #\n", + " n = 7\n", "\n", - "#\n", - "# variables\n", - "#\n", - "X = [solver.IntVar(0, 10, \"X(%i)\" % i) for i in range(n)]\n", - "X1, X2, X3, X4, X5, X6, X7 = X\n", + " #\n", + " # variables\n", + " #\n", + " X = [solver.IntVar(0, 10, \"X(%i)\" % i) for i in range(n)]\n", + " X1, X2, X3, X4, X5, X6, X7 = X\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(0 + 98527 * X1 + 34588 * X2 + 5872 * X3 + 59422 * X5 +\n", - " 65159 * X7 == 1547604 + 30704 * X4 + 29649 * X6)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(0 + 98527 * X1 + 34588 * X2 + 5872 * X3 + 59422 * X5 +\n", + " 65159 * X7 == 1547604 + 30704 * X4 + 29649 * X6)\n", "\n", - "solver.Add(0 + 98957 * X2 + 83634 * X3 + 69966 * X4 + 62038 * X5 +\n", - " 37164 * X6 + 85413 * X7 == 1823553 + 93989 * X1)\n", + " solver.Add(0 + 98957 * X2 + 83634 * X3 + 69966 * X4 + 62038 * X5 +\n", + " 37164 * X6 + 85413 * X7 == 1823553 + 93989 * X1)\n", "\n", - "solver.Add(900032 + 10949 * X1 + 77761 * X2 + 67052 * X5 == 0 + 80197 * X3 +\n", - " 61944 * X4 + 92964 * X6 + 44550 * X7)\n", + " solver.Add(900032 + 10949 * X1 + 77761 * X2 + 67052 * X5 == 0 + 80197 * X3 +\n", + " 61944 * X4 + 92964 * X6 + 44550 * X7)\n", "\n", - "solver.Add(0 + 73947 * X1 + 84391 * X3 + 81310 * X5 == 1164380 + 96253 * X2 +\n", - " 44247 * X4 + 70582 * X6 + 33054 * X7)\n", + " solver.Add(0 + 73947 * X1 + 84391 * X3 + 81310 * X5 == 1164380 + 96253 * X2 +\n", + " 44247 * X4 + 70582 * X6 + 33054 * X7)\n", "\n", - "solver.Add(0 + 13057 * X3 + 42253 * X4 + 77527 * X5 + 96552 * X7 == 1185471 +\n", - " 60152 * X1 + 21103 * X2 + 97932 * X6)\n", + " solver.Add(0 + 13057 * X3 + 42253 * X4 + 77527 * X5 + 96552 * X7 == 1185471 +\n", + " 60152 * X1 + 21103 * X2 + 97932 * X6)\n", "\n", - "solver.Add(1394152 + 66920 * X1 + 55679 * X4 == 0 + 64234 * X2 + 65337 * X3 +\n", - " 45581 * X5 + 67707 * X6 + 98038 * X7)\n", + " solver.Add(1394152 + 66920 * X1 + 55679 * X4 == 0 + 64234 * X2 + 65337 * X3 +\n", + " 45581 * X5 + 67707 * X6 + 98038 * X7)\n", "\n", - "solver.Add(0 + 68550 * X1 + 27886 * X2 + 31716 * X3 + 73597 * X4 +\n", - " 38835 * X7 == 279091 + 88963 * X5 + 76391 * X6)\n", + " solver.Add(0 + 68550 * X1 + 27886 * X2 + 31716 * X3 + 73597 * X4 +\n", + " 38835 * X7 == 279091 + 88963 * X5 + 76391 * X6)\n", "\n", - "solver.Add(0 + 76132 * X2 + 71860 * X3 + 22770 * X4 + 68211 * X5 +\n", - " 78587 * X6 == 480923 + 48224 * X1 + 82817 * X7)\n", + " solver.Add(0 + 76132 * X2 + 71860 * X3 + 22770 * X4 + 68211 * X5 +\n", + " 78587 * X6 == 480923 + 48224 * X1 + 82817 * X7)\n", "\n", - "solver.Add(519878 + 94198 * X2 + 87234 * X3 + 37498 * X4 == 0 + 71583 * X1 +\n", - " 25728 * X5 + 25495 * X6 + 70023 * X7)\n", + " solver.Add(519878 + 94198 * X2 + 87234 * X3 + 37498 * X4 == 0 + 71583 * X1 +\n", + " 25728 * X5 + 25495 * X6 + 70023 * X7)\n", "\n", - "solver.Add(361921 + 78693 * X1 + 38592 * X5 + 38478 * X6 == 0 + 94129 * X2 +\n", - " 43188 * X3 + 82528 * X4 + 69025 * X7)\n", + " solver.Add(361921 + 78693 * X1 + 38592 * X5 + 38478 * X6 == 0 + 94129 * X2 +\n", + " 43188 * X3 + 82528 * X4 + 69025 * X7)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(X, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(X, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"X:\", [X[i].Value() for i in range(n)])\n", + " print()\n", + "\n", + " solver.EndSearch()\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"X:\", [X[i].Value() for i in range(n)])\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/eq20.ipynb b/examples/notebook/contrib/eq20.ipynb index 5b7ba9fbc0..63cf9ab870 100644 --- a/examples/notebook/contrib/eq20.ipynb +++ b/examples/notebook/contrib/eq20.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Eq 20 in Google CP Solver.\n", "\n", @@ -100,90 +85,102 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Eq 20\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Eq 20\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 7\n", + " #\n", + " # data\n", + " #\n", + " n = 7\n", "\n", - "#\n", - "# variables\n", - "#\n", - "X = [solver.IntVar(0, 10, \"X(%i)\" % i) for i in range(n)]\n", - "X0, X1, X2, X3, X4, X5, X6 = X\n", + " #\n", + " # variables\n", + " #\n", + " X = [solver.IntVar(0, 10, \"X(%i)\" % i) for i in range(n)]\n", + " X0, X1, X2, X3, X4, X5, X6 = X\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(-76706 * X0 + 98205 * X1 + 23445 * X2 + 67921 * X3 + 24111 * X4 +\n", - " -48614 * X5 + -41906 * X6 == 821228)\n", - "solver.Add(87059 * X0 + -29101 * X1 + -5513 * X2 + -21219 * X3 + 22128 * X4 +\n", - " 7276 * X5 + 57308 * X6 == 22167)\n", - "solver.Add(-60113 * X0 + 29475 * X1 + 34421 * X2 + -76870 * X3 + 62646 * X4 +\n", - " 29278 * X5 + -15212 * X6 == 251591)\n", - "solver.Add(49149 * X0 + 52871 * X1 + -7132 * X2 + 56728 * X3 + -33576 * X4 +\n", - " -49530 * X5 + -62089 * X6 == 146074)\n", - "solver.Add(-10343 * X0 + 87758 * X1 + -11782 * X2 + 19346 * X3 + 70072 * X4 +\n", - " -36991 * X5 + 44529 * X6 == 740061)\n", - "solver.Add(85176 * X0 + -95332 * X1 + -1268 * X2 + 57898 * X3 + 15883 * X4 +\n", - " 50547 * X5 + 83287 * X6 == 373854)\n", - "solver.Add(-85698 * X0 + 29958 * X1 + 57308 * X2 + 48789 * X3 + -78219 * X4 +\n", - " 4657 * X5 + 34539 * X6 == 249912)\n", - "solver.Add(-67456 * X0 + 84750 * X1 + -51553 * X2 + 21239 * X3 + 81675 * X4 +\n", - " -99395 * X5 + -4254 * X6 == 277271)\n", - "solver.Add(94016 * X0 + -82071 * X1 + 35961 * X2 + 66597 * X3 + -30705 * X4 +\n", - " -44404 * X5 + -38304 * X6 == 25334)\n", - "solver.Add(-60301 * X0 + 31227 * X1 + 93951 * X2 + 73889 * X3 + 81526 * X4 +\n", - " -72702 * X5 + 68026 * X6 == 1410723)\n", - "solver.Add(-16835 * X0 + 47385 * X1 + 97715 * X2 + -12640 * X3 + 69028 * X4 +\n", - " 76212 * X5 + -81102 * X6 == 1244857)\n", - "solver.Add(-43277 * X0 + 43525 * X1 + 92298 * X2 + 58630 * X3 + 92590 * X4 +\n", - " -9372 * X5 + -60227 * X6 == 1503588)\n", - "solver.Add(-64919 * X0 + 80460 * X1 + 90840 * X2 + -59624 * X3 + -75542 * X4 +\n", - " 25145 * X5 + -47935 * X6 == 18465)\n", - "solver.Add(-45086 * X0 + 51830 * X1 + -4578 * X2 + 96120 * X3 + 21231 * X4 +\n", - " 97919 * X5 + 65651 * X6 == 1198280)\n", - "solver.Add(85268 * X0 + 54180 * X1 + -18810 * X2 + -48219 * X3 + 6013 * X4 +\n", - " 78169 * X5 + -79785 * X6 == 90614)\n", - "solver.Add(8874 * X0 + -58412 * X1 + 73947 * X2 + 17147 * X3 + 62335 * X4 +\n", - " 16005 * X5 + 8632 * X6 == 752447)\n", - "solver.Add(71202 * X0 + -11119 * X1 + 73017 * X2 + -38875 * X3 + -14413 * X4 +\n", - " -29234 * X5 + 72370 * X6 == 129768)\n", - "solver.Add(1671 * X0 + -34121 * X1 + 10763 * X2 + 80609 * X3 + 42532 * X4 +\n", - " 93520 * X5 + -33488 * X6 == 915683)\n", - "solver.Add(51637 * X0 + 67761 * X1 + 95951 * X2 + 3834 * X3 + -96722 * X4 +\n", - " 59190 * X5 + 15280 * X6 == 533909)\n", - "solver.Add(-16105 * X0 + 62397 * X1 + -6704 * X2 + 43340 * X3 + 95100 * X4 +\n", - " -68610 * X5 + 58301 * X6 == 876370)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(-76706 * X0 + 98205 * X1 + 23445 * X2 + 67921 * X3 + 24111 * X4 +\n", + " -48614 * X5 + -41906 * X6 == 821228)\n", + " solver.Add(87059 * X0 + -29101 * X1 + -5513 * X2 + -21219 * X3 + 22128 * X4 +\n", + " 7276 * X5 + 57308 * X6 == 22167)\n", + " solver.Add(-60113 * X0 + 29475 * X1 + 34421 * X2 + -76870 * X3 + 62646 * X4 +\n", + " 29278 * X5 + -15212 * X6 == 251591)\n", + " solver.Add(49149 * X0 + 52871 * X1 + -7132 * X2 + 56728 * X3 + -33576 * X4 +\n", + " -49530 * X5 + -62089 * X6 == 146074)\n", + " solver.Add(-10343 * X0 + 87758 * X1 + -11782 * X2 + 19346 * X3 + 70072 * X4 +\n", + " -36991 * X5 + 44529 * X6 == 740061)\n", + " solver.Add(85176 * X0 + -95332 * X1 + -1268 * X2 + 57898 * X3 + 15883 * X4 +\n", + " 50547 * X5 + 83287 * X6 == 373854)\n", + " solver.Add(-85698 * X0 + 29958 * X1 + 57308 * X2 + 48789 * X3 + -78219 * X4 +\n", + " 4657 * X5 + 34539 * X6 == 249912)\n", + " solver.Add(-67456 * X0 + 84750 * X1 + -51553 * X2 + 21239 * X3 + 81675 * X4 +\n", + " -99395 * X5 + -4254 * X6 == 277271)\n", + " solver.Add(94016 * X0 + -82071 * X1 + 35961 * X2 + 66597 * X3 + -30705 * X4 +\n", + " -44404 * X5 + -38304 * X6 == 25334)\n", + " solver.Add(-60301 * X0 + 31227 * X1 + 93951 * X2 + 73889 * X3 + 81526 * X4 +\n", + " -72702 * X5 + 68026 * X6 == 1410723)\n", + " solver.Add(-16835 * X0 + 47385 * X1 + 97715 * X2 + -12640 * X3 + 69028 * X4 +\n", + " 76212 * X5 + -81102 * X6 == 1244857)\n", + " solver.Add(-43277 * X0 + 43525 * X1 + 92298 * X2 + 58630 * X3 + 92590 * X4 +\n", + " -9372 * X5 + -60227 * X6 == 1503588)\n", + " solver.Add(-64919 * X0 + 80460 * X1 + 90840 * X2 + -59624 * X3 + -75542 * X4 +\n", + " 25145 * X5 + -47935 * X6 == 18465)\n", + " solver.Add(-45086 * X0 + 51830 * X1 + -4578 * X2 + 96120 * X3 + 21231 * X4 +\n", + " 97919 * X5 + 65651 * X6 == 1198280)\n", + " solver.Add(85268 * X0 + 54180 * X1 + -18810 * X2 + -48219 * X3 + 6013 * X4 +\n", + " 78169 * X5 + -79785 * X6 == 90614)\n", + " solver.Add(8874 * X0 + -58412 * X1 + 73947 * X2 + 17147 * X3 + 62335 * X4 +\n", + " 16005 * X5 + 8632 * X6 == 752447)\n", + " solver.Add(71202 * X0 + -11119 * X1 + 73017 * X2 + -38875 * X3 + -14413 * X4 +\n", + " -29234 * X5 + 72370 * X6 == 129768)\n", + " solver.Add(1671 * X0 + -34121 * X1 + 10763 * X2 + 80609 * X3 + 42532 * X4 +\n", + " 93520 * X5 + -33488 * X6 == 915683)\n", + " solver.Add(51637 * X0 + 67761 * X1 + 95951 * X2 + 3834 * X3 + -96722 * X4 +\n", + " 59190 * X5 + 15280 * X6 == 533909)\n", + " solver.Add(-16105 * X0 + 62397 * X1 + -6704 * X2 + 43340 * X3 + 95100 * X4 +\n", + " -68610 * X5 + 58301 * X6 == 876370)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(X, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(X, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"X:\", [X[i].Value() for i in range(n)])\n", + " print()\n", + "\n", + " solver.EndSearch()\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"X:\", [X[i].Value() for i in range(n)])\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/fill_a_pix.ipynb b/examples/notebook/contrib/fill_a_pix.ipynb index 251f2e3df9..ff5d85ba58 100644 --- a/examples/notebook/contrib/fill_a_pix.ipynb +++ b/examples/notebook/contrib/fill_a_pix.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Fill-a-Pix problem in Google CP Solver.\n", "\n", @@ -124,8 +109,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -142,88 +135,90 @@ "]\n", "\n", "\n", + "def main(puzzle='', n=''):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Fill-a-Pix')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Fill-a-Pix')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# Set default problem\n", - "if puzzle == '':\n", - " puzzle = default_puzzle\n", - " n = default_n\n", - "else:\n", - " print('n:', n)\n", + " # Set default problem\n", + " if puzzle == '':\n", + " puzzle = default_puzzle\n", + " n = default_n\n", + " else:\n", + " print('n:', n)\n", "\n", - "# for the neighbors of 'this' cell\n", - "S = [-1, 0, 1]\n", + " # for the neighbors of 'this' cell\n", + " S = [-1, 0, 1]\n", "\n", - "# print problem instance\n", - "print('Problem:')\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if puzzle[i][j] == X:\n", - " sys.stdout.write('.')\n", - " else:\n", - " sys.stdout.write(str(puzzle[i][j]))\n", - " print()\n", - "print()\n", - "\n", - "#\n", - "# declare variables\n", - "#\n", - "pict = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " pict[(i, j)] = solver.IntVar(0, 1, 'pict %i %i' % (i, j))\n", - "\n", - "pict_flat = [pict[i, j] for i in range(n) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if puzzle[i][j] > X:\n", - " # this cell is the sum of all the surrounding cells\n", - " solver.Add(puzzle[i][j] == solver.Sum([\n", - " pict[i + a, j + b]\n", - " for a in S\n", - " for b in S\n", - " if i + a >= 0 and j + b >= 0 and i + a < n and j + b < n\n", - " ]))\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(pict_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "print('Solution:')\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", + " # print problem instance\n", + " print('Problem:')\n", " for i in range(n):\n", - " row = [str(pict[i, j].Value()) for j in range(n)]\n", " for j in range(n):\n", - " if row[j] == '0':\n", - " row[j] = ' '\n", + " if puzzle[i][j] == X:\n", + " sys.stdout.write('.')\n", " else:\n", - " row[j] = '#'\n", - " print(''.join(row))\n", + " sys.stdout.write(str(puzzle[i][j]))\n", + " print()\n", " print()\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " #\n", + " # declare variables\n", + " #\n", + " pict = {}\n", + " for i in range(n):\n", + " for j in range(n):\n", + " pict[(i, j)] = solver.IntVar(0, 1, 'pict %i %i' % (i, j))\n", + "\n", + " pict_flat = [pict[i, j] for i in range(n) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if puzzle[i][j] > X:\n", + " # this cell is the sum of all the surrounding cells\n", + " solver.Add(puzzle[i][j] == solver.Sum([\n", + " pict[i + a, j + b]\n", + " for a in S\n", + " for b in S\n", + " if i + a >= 0 and j + b >= 0 and i + a < n and j + b < n\n", + " ]))\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(pict_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " print('Solution:')\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " for i in range(n):\n", + " row = [str(pict[i, j].Value()) for j in range(n)]\n", + " for j in range(n):\n", + " if row[j] == '0':\n", + " row[j] = ' '\n", + " else:\n", + " row[j] = '#'\n", + " print(''.join(row))\n", + " print()\n", + "\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", "\n", "#\n", "# Read a problem instance from a file\n", - "#def read_problem(file):\n", + "#\n", + "def read_problem(file):\n", " f = open(file, 'r')\n", " n = int(f.readline())\n", " puzzle = []\n", @@ -239,6 +234,14 @@ " puzzle.append(row)\n", " return [puzzle, n]\n", "\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " print('Problem instance from', file)\n", + " [puzzle, n] = read_problem(file)\n", + " main(puzzle, n)\n", + "else:\n", + " main()\n", "\n" ] } diff --git a/examples/notebook/contrib/furniture_moving.ipynb b/examples/notebook/contrib/furniture_moving.ipynb index 7c6f456a4e..1f4cfa2d80 100644 --- a/examples/notebook/contrib/furniture_moving.ipynb +++ b/examples/notebook/contrib/furniture_moving.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Moving furnitures (scheduling) problem in Google CP Solver.\n", "\n", @@ -109,8 +94,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -155,95 +148,99 @@ " solver.Add(b <= sum(r))\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Furniture moving\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Furniture moving\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", - "duration = [30, 10, 15, 15]\n", - "demand = [3, 1, 3, 2]\n", - "upper_limit = 160\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", + " duration = [30, 10, 15, 15]\n", + " demand = [3, 1, 3, 2]\n", + " upper_limit = 160\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "start_times = [\n", - " solver.IntVar(0, upper_limit, \"start_times[%i]\" % i) for i in range(n)\n", - "]\n", - "end_times = [\n", - " solver.IntVar(0, upper_limit * 2, \"end_times[%i]\" % i) for i in range(n)\n", - "]\n", - "end_time = solver.IntVar(0, upper_limit * 2, \"end_time\")\n", + " #\n", + " # declare variables\n", + " #\n", + " start_times = [\n", + " solver.IntVar(0, upper_limit, \"start_times[%i]\" % i) for i in range(n)\n", + " ]\n", + " end_times = [\n", + " solver.IntVar(0, upper_limit * 2, \"end_times[%i]\" % i) for i in range(n)\n", + " ]\n", + " end_time = solver.IntVar(0, upper_limit * 2, \"end_time\")\n", "\n", - "# number of needed resources, to be minimized\n", - "num_resources = solver.IntVar(0, 10, \"num_resources\")\n", + " # number of needed resources, to be minimized\n", + " num_resources = solver.IntVar(0, 10, \"num_resources\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(n):\n", - " solver.Add(end_times[i] == start_times[i] + duration[i])\n", + " #\n", + " # constraints\n", + " #\n", + " for i in range(n):\n", + " solver.Add(end_times[i] == start_times[i] + duration[i])\n", "\n", - "solver.Add(end_time == solver.Max(end_times))\n", + " solver.Add(end_time == solver.Max(end_times))\n", "\n", - "my_cumulative(solver, start_times, duration, demand, num_resources)\n", + " my_cumulative(solver, start_times, duration, demand, num_resources)\n", "\n", - "#\n", - "# Some extra constraints to play with\n", - "#\n", + " #\n", + " # Some extra constraints to play with\n", + " #\n", "\n", - "# all tasks must end within an hour\n", - "# solver.Add(end_time <= 60)\n", + " # all tasks must end within an hour\n", + " # solver.Add(end_time <= 60)\n", "\n", - "# All tasks should start at time 0\n", - "# for i in range(n):\n", - "# solver.Add(start_times[i] == 0)\n", + " # All tasks should start at time 0\n", + " # for i in range(n):\n", + " # solver.Add(start_times[i] == 0)\n", "\n", - "# limitation of the number of people\n", - "# solver.Add(num_resources <= 3)\n", + " # limitation of the number of people\n", + " # solver.Add(num_resources <= 3)\n", "\n", - "#\n", - "# objective\n", - "#\n", - "# objective = solver.Minimize(end_time, 1)\n", - "objective = solver.Minimize(num_resources, 1)\n", + " #\n", + " # objective\n", + " #\n", + " # objective = solver.Minimize(end_time, 1)\n", + " objective = solver.Minimize(num_resources, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(start_times)\n", - "solution.Add(end_times)\n", - "solution.Add(end_time)\n", - "solution.Add(num_resources)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(start_times)\n", + " solution.Add(end_times)\n", + " solution.Add(end_time)\n", + " solution.Add(num_resources)\n", "\n", - "db = solver.Phase(start_times, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " db = solver.Phase(start_times, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " #\n", + " # result\n", + " #\n", + " solver.NewSearch(db, [objective])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"num_resources:\", num_resources.Value())\n", + " print(\"start_times :\", [start_times[i].Value() for i in range(n)])\n", + " print(\"duration :\", [duration[i] for i in range(n)])\n", + " print(\"end_times :\", [end_times[i].Value() for i in range(n)])\n", + " print(\"end_time :\", end_time.Value())\n", + " print()\n", + "\n", + " solver.EndSearch()\n", "\n", - "#\n", - "# result\n", - "#\n", - "solver.NewSearch(db, [objective])\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"num_resources:\", num_resources.Value())\n", - " print(\"start_times :\", [start_times[i].Value() for i in range(n)])\n", - " print(\"duration :\", [duration[i] for i in range(n)])\n", - " print(\"end_times :\", [end_times[i].Value() for i in range(n)])\n", - " print(\"end_time :\", end_time.Value())\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/futoshiki.ipynb b/examples/notebook/contrib/futoshiki.ipynb index 13a67f3d22..7eb52f5695 100644 --- a/examples/notebook/contrib/futoshiki.ipynb +++ b/examples/notebook/contrib/futoshiki.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Futoshiki problem in Google CP Solver.\n", "\n", @@ -118,77 +103,86 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(values, lt):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Futoshiki problem\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Futoshiki problem\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "size = len(values)\n", - "RANGE = list(range(size))\n", - "NUMQD = list(range(len(lt)))\n", + " #\n", + " # data\n", + " #\n", + " size = len(values)\n", + " RANGE = list(range(size))\n", + " NUMQD = list(range(len(lt)))\n", "\n", - "#\n", - "# variables\n", - "#\n", - "field = {}\n", - "for i in RANGE:\n", - " for j in RANGE:\n", - " field[i, j] = solver.IntVar(1, size, \"field[%i,%i]\" % (i, j))\n", - "field_flat = [field[i, j] for i in RANGE for j in RANGE]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "# set initial values\n", - "for row in RANGE:\n", - " for col in RANGE:\n", - " if values[row][col] > 0:\n", - " solver.Add(field[row, col] == values[row][col])\n", - "\n", - "# all rows have to be different\n", - "for row in RANGE:\n", - " solver.Add(solver.AllDifferent([field[row, col] for col in RANGE]))\n", - "\n", - "# all columns have to be different\n", - "for col in RANGE:\n", - " solver.Add(solver.AllDifferent([field[row, col] for row in RANGE]))\n", - "\n", - "# all < constraints are satisfied\n", - "# Also: make 0-based\n", - "for i in NUMQD:\n", - " solver.Add(\n", - " field[lt[i][0] - 1, lt[i][1] - 1] < field[lt[i][2] - 1, lt[i][3] - 1])\n", - "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(field_flat, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", + " #\n", + " # variables\n", + " #\n", + " field = {}\n", " for i in RANGE:\n", " for j in RANGE:\n", - " print(field[i, j].Value(), end=\" \")\n", + " field[i, j] = solver.IntVar(1, size, \"field[%i,%i]\" % (i, j))\n", + " field_flat = [field[i, j] for i in RANGE for j in RANGE]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " # set initial values\n", + " for row in RANGE:\n", + " for col in RANGE:\n", + " if values[row][col] > 0:\n", + " solver.Add(field[row, col] == values[row][col])\n", + "\n", + " # all rows have to be different\n", + " for row in RANGE:\n", + " solver.Add(solver.AllDifferent([field[row, col] for col in RANGE]))\n", + "\n", + " # all columns have to be different\n", + " for col in RANGE:\n", + " solver.Add(solver.AllDifferent([field[row, col] for row in RANGE]))\n", + "\n", + " # all < constraints are satisfied\n", + " # Also: make 0-based\n", + " for i in NUMQD:\n", + " solver.Add(\n", + " field[lt[i][0] - 1, lt[i][1] - 1] < field[lt[i][2] - 1, lt[i][3] - 1])\n", + "\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(field_flat, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " for i in RANGE:\n", + " for j in RANGE:\n", + " print(field[i, j].Value(), end=\" \")\n", + " print()\n", " print()\n", - " print()\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", "\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", "\n", "#\n", @@ -202,7 +196,8 @@ "#\n", "# Futoshiki instance, by Andras Salamon\n", "# specify the numbers in the grid\n", - "#values1 = [[0, 0, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0],\n", + "#\n", + "values1 = [[0, 0, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0],\n", " [0, 0, 0, 0, 0]]\n", "\n", "# [i1,j1, i2,j2] requires that values[i1,j1] < values[i2,j2]\n", @@ -226,6 +221,11 @@ "# Note: 1-based\n", "lt2 = [[1, 2, 1, 1], [1, 4, 1, 3], [1, 5, 1, 4], [4, 4, 4, 5], [5, 1, 5, 2],\n", " [5, 2, 5, 3]]\n", + "\n", + "print(\"Problem 1\")\n", + "main(values1, lt1)\n", + "print(\"\\nProblem 2\")\n", + "main(values2, lt2)\n", "\n" ] } diff --git a/examples/notebook/contrib/game_theory_taha.ipynb b/examples/notebook/contrib/game_theory_taha.ipynb index a3e80c0624..8aded34f82 100644 --- a/examples/notebook/contrib/game_theory_taha.ipynb +++ b/examples/notebook/contrib/game_theory_taha.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Game theory in Google or-tools.\n", "\n", @@ -97,87 +82,106 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "# using GLPK\n", - "if sol == 'GLPK':\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", - "else:\n", - " # Using CLP\n", - " solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", + " # using GLPK\n", + " if sol == 'GLPK':\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", + " else:\n", + " # Using CLP\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", "\n", - "# data\n", - "rows = 3\n", - "cols = 3\n", + " # data\n", + " rows = 3\n", + " cols = 3\n", "\n", - "game = [[3.0, -1.0, -3.0], [-2.0, 4.0, -1.0], [-5.0, -6.0, 2.0]]\n", + " game = [[3.0, -1.0, -3.0], [-2.0, 4.0, -1.0], [-5.0, -6.0, 2.0]]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", + " #\n", + " # declare variables\n", + " #\n", "\n", - "#\n", - "# row player\n", - "#\n", - "x1 = [solver.NumVar(0, 1, 'x1[%i]' % i) for i in range(rows)]\n", + " #\n", + " # row player\n", + " #\n", + " x1 = [solver.NumVar(0, 1, 'x1[%i]' % i) for i in range(rows)]\n", "\n", - "v = solver.NumVar(-2, 2, 'v')\n", + " v = solver.NumVar(-2, 2, 'v')\n", "\n", - "for i in range(rows):\n", - " solver.Add(v - solver.Sum([x1[j] * game[j][i] for j in range(cols)]) <= 0)\n", + " for i in range(rows):\n", + " solver.Add(v - solver.Sum([x1[j] * game[j][i] for j in range(cols)]) <= 0)\n", "\n", - "solver.Add(solver.Sum(x1) == 1)\n", + " solver.Add(solver.Sum(x1) == 1)\n", "\n", - "objective = solver.Maximize(v)\n", + " objective = solver.Maximize(v)\n", "\n", - "solver.Solve()\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('row player:')\n", - "print('v = ', solver.Objective().Value())\n", - "print('Strategies: ')\n", - "for i in range(rows):\n", - " print(x1[i].SolutionValue(), end=' ')\n", - "print()\n", - "print()\n", + " print()\n", + " print('row player:')\n", + " print('v = ', solver.Objective().Value())\n", + " print('Strategies: ')\n", + " for i in range(rows):\n", + " print(x1[i].SolutionValue(), end=' ')\n", + " print()\n", + " print()\n", "\n", - "#\n", - "# For column player:\n", - "#\n", - "x2 = [solver.NumVar(0, 1, 'x2[%i]' % i) for i in range(cols)]\n", + " #\n", + " # For column player:\n", + " #\n", + " x2 = [solver.NumVar(0, 1, 'x2[%i]' % i) for i in range(cols)]\n", "\n", - "v2 = solver.NumVar(-2, 2, 'v2')\n", + " v2 = solver.NumVar(-2, 2, 'v2')\n", "\n", - "for i in range(cols):\n", - " solver.Add(v2 - solver.Sum([x2[j] * game[i][j] for j in range(rows)]) >= 0)\n", + " for i in range(cols):\n", + " solver.Add(v2 - solver.Sum([x2[j] * game[i][j] for j in range(rows)]) >= 0)\n", "\n", - "solver.Add(solver.Sum(x2) == 1)\n", + " solver.Add(solver.Sum(x2) == 1)\n", "\n", - "objective = solver.Minimize(v2)\n", + " objective = solver.Minimize(v2)\n", "\n", - "solver.Solve()\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('column player:')\n", - "print('v2 = ', solver.Objective().Value())\n", - "print('Strategies: ')\n", - "for i in range(rows):\n", - " print(x2[i].SolutionValue(), end=' ')\n", - "print()\n", + " print()\n", + " print('column player:')\n", + " print('v2 = ', solver.Objective().Value())\n", + " print('Strategies: ')\n", + " for i in range(rows):\n", + " print(x2[i].SolutionValue(), end=' ')\n", + " print()\n", "\n", - "print()\n", - "print('walltime :', solver.WallTime(), 'ms')\n", - "print('iterations:', solver.Iterations())\n", - "print()\n", + " print()\n", + " print('walltime :', solver.WallTime(), 'ms')\n", + " print('iterations:', solver.Iterations())\n", + " print()\n", + "\n", + "\n", + "sol = 'CBC'\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/grocery.ipynb b/examples/notebook/contrib/grocery.ipynb index 5a14cb6ee2..30648cf0b0 100644 --- a/examples/notebook/contrib/grocery.ipynb +++ b/examples/notebook/contrib/grocery.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Grocery problem in Google CP Solver.\n", "\n", @@ -109,58 +94,70 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "from functools import reduce\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Grocery\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Grocery\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", - "c = 711\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", + " c = 711\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "item = [solver.IntVar(0, c, \"item[%i]\" % i) for i in range(n)]\n", + " #\n", + " # declare variables\n", + " #\n", + " item = [solver.IntVar(0, c, \"item[%i]\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.Sum(item) == c)\n", - "solver.Add(reduce(lambda x, y: x * y, item) == c * 100**3)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.Sum(item) == c)\n", + " solver.Add(reduce(lambda x, y: x * y, item) == c * 100**3)\n", "\n", - "# symmetry breaking\n", - "for i in range(1, n):\n", - " solver.Add(item[i - 1] < item[i])\n", + " # symmetry breaking\n", + " for i in range(1, n):\n", + " solver.Add(item[i - 1] < item[i])\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(item, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(item, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"item:\", [item[i].Value() for i in range(n)])\n", + " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"item:\", [item[i].Value() for i in range(n)])\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/hidato.ipynb b/examples/notebook/contrib/hidato.ipynb index b7fbd8f22d..7a0a43755c 100644 --- a/examples/notebook/contrib/hidato.ipynb +++ b/examples/notebook/contrib/hidato.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", " Hidato puzzle in Google CP Solver.\n", "\n", " http://www.shockwave.com/gamelanding/hidato.jsp\n", @@ -113,154 +98,164 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"hidato\")\n", + "def main(r, c):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"hidato\")\n", "\n", - "# data\n", - "# Simple problem\n", - "if r == 3 and c == 3:\n", - " puzzle = [[6, 0, 9], [0, 2, 8], [1, 0, 0]]\n", + " # data\n", + " # Simple problem\n", + " if r == 3 and c == 3:\n", + " puzzle = [[6, 0, 9], [0, 2, 8], [1, 0, 0]]\n", "\n", - "if r == 7 and c == 7:\n", - " puzzle = [[0, 44, 41, 0, 0, 0, 0], [0, 43, 0, 28, 29, 0, 0],\n", - " [0, 1, 0, 0, 0, 33, 0], [0, 2, 25, 4, 34, 0, 36],\n", - " [49, 16, 0, 23, 0, 0, 0], [0, 19, 0, 0, 12, 7, 0],\n", - " [0, 0, 0, 14, 0, 0, 0]]\n", + " if r == 7 and c == 7:\n", + " puzzle = [[0, 44, 41, 0, 0, 0, 0], [0, 43, 0, 28, 29, 0, 0],\n", + " [0, 1, 0, 0, 0, 33, 0], [0, 2, 25, 4, 34, 0, 36],\n", + " [49, 16, 0, 23, 0, 0, 0], [0, 19, 0, 0, 12, 7, 0],\n", + " [0, 0, 0, 14, 0, 0, 0]]\n", "\n", - "# Problems from the book:\n", - "# Gyora Bededek: \"Hidato: 2000 Pure Logic Puzzles\"\n", + " # Problems from the book:\n", + " # Gyora Bededek: \"Hidato: 2000 Pure Logic Puzzles\"\n", "\n", - "# Problem 1 (Practice)\n", - "# r = 5\n", - "# c = r\n", - "# puzzle = [\n", - "# [ 0, 0,20, 0, 0],\n", - "# [ 0, 0, 0,16,18],\n", - "# [22, 0,15, 0, 0],\n", - "# [23, 0, 1,14,11],\n", - "# [ 0,25, 0, 0,12],\n", - "# ]\n", + " # Problem 1 (Practice)\n", + " # r = 5\n", + " # c = r\n", + " # puzzle = [\n", + " # [ 0, 0,20, 0, 0],\n", + " # [ 0, 0, 0,16,18],\n", + " # [22, 0,15, 0, 0],\n", + " # [23, 0, 1,14,11],\n", + " # [ 0,25, 0, 0,12],\n", + " # ]\n", "\n", - "# Problem 2 (Practice)\n", - "if r == 5 and c == 5:\n", - " puzzle = [\n", - " [0, 0, 0, 0, 14],\n", - " [0, 18, 12, 0, 0],\n", - " [0, 0, 17, 4, 5],\n", - " [0, 0, 7, 0, 0],\n", - " [9, 8, 25, 1, 0],\n", - " ]\n", + " # Problem 2 (Practice)\n", + " if r == 5 and c == 5:\n", + " puzzle = [\n", + " [0, 0, 0, 0, 14],\n", + " [0, 18, 12, 0, 0],\n", + " [0, 0, 17, 4, 5],\n", + " [0, 0, 7, 0, 0],\n", + " [9, 8, 25, 1, 0],\n", + " ]\n", "\n", - "# Problem 3 (Beginner)\n", - "if r == 6 and c == 6:\n", - " puzzle = [[0, 26, 0, 0, 0, 18], [0, 0, 27, 0, 0, 19], [31, 23, 0, 0, 14, 0],\n", - " [0, 33, 8, 0, 15, 1], [0, 0, 0, 5, 0, 0], [35, 36, 0, 10, 0, 0]]\n", + " # Problem 3 (Beginner)\n", + " if r == 6 and c == 6:\n", + " puzzle = [[0, 26, 0, 0, 0, 18], [0, 0, 27, 0, 0, 19], [31, 23, 0, 0, 14, 0],\n", + " [0, 33, 8, 0, 15, 1], [0, 0, 0, 5, 0, 0], [35, 36, 0, 10, 0, 0]]\n", "\n", - "# Problem 15 (Intermediate)\n", - "# Note: This takes very long time to solve...\n", - "if r == 8 and c == 8:\n", - " puzzle = [[64, 0, 0, 0, 0, 0, 0, 0], [1, 63, 0, 59, 15, 57, 53, 0],\n", - " [0, 4, 0, 14, 0, 0, 0, 0], [3, 0, 11, 0, 20, 19, 0, 50],\n", - " [0, 0, 0, 0, 22, 0, 48, 40], [9, 0, 0, 32, 23, 0, 0, 41],\n", - " [27, 0, 0, 0, 36, 0, 46, 0], [28, 30, 0, 35, 0, 0, 0, 0]]\n", + " # Problem 15 (Intermediate)\n", + " # Note: This takes very long time to solve...\n", + " if r == 8 and c == 8:\n", + " puzzle = [[64, 0, 0, 0, 0, 0, 0, 0], [1, 63, 0, 59, 15, 57, 53, 0],\n", + " [0, 4, 0, 14, 0, 0, 0, 0], [3, 0, 11, 0, 20, 19, 0, 50],\n", + " [0, 0, 0, 0, 22, 0, 48, 40], [9, 0, 0, 32, 23, 0, 0, 41],\n", + " [27, 0, 0, 0, 36, 0, 46, 0], [28, 30, 0, 35, 0, 0, 0, 0]]\n", "\n", - "print_game(puzzle, r, c)\n", + " print_game(puzzle, r, c)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = {}\n", - "for i in range(r):\n", - " for j in range(c):\n", - " x[(i, j)] = solver.IntVar(1, r * c, \"dice(%i,%i)\" % (i, j))\n", - "x_flat = [x[(i, j)] for i in range(r) for j in range(c)]\n", + " #\n", + " # declare variables\n", + " #\n", + " x = {}\n", + " for i in range(r):\n", + " for j in range(c):\n", + " x[(i, j)] = solver.IntVar(1, r * c, \"dice(%i,%i)\" % (i, j))\n", + " x_flat = [x[(i, j)] for i in range(r) for j in range(c)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x_flat))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x_flat))\n", "\n", - "#\n", - "# Fill in the clues\n", - "#\n", - "for i in range(r):\n", - " for j in range(c):\n", - " if puzzle[i][j] > 0:\n", - " solver.Add(x[(i, j)] == puzzle[i][j])\n", + " #\n", + " # Fill in the clues\n", + " #\n", + " for i in range(r):\n", + " for j in range(c):\n", + " if puzzle[i][j] > 0:\n", + " solver.Add(x[(i, j)] == puzzle[i][j])\n", "\n", - "# From the numbers k = 1 to r*c-1, find this position,\n", - "# and then the position of k+1\n", - "for k in range(1, r * c):\n", - " i = solver.IntVar(0, r)\n", - " j = solver.IntVar(0, c)\n", - " a = solver.IntVar(-1, 1)\n", - " b = solver.IntVar(-1, 1)\n", + " # From the numbers k = 1 to r*c-1, find this position,\n", + " # and then the position of k+1\n", + " for k in range(1, r * c):\n", + " i = solver.IntVar(0, r)\n", + " j = solver.IntVar(0, c)\n", + " a = solver.IntVar(-1, 1)\n", + " b = solver.IntVar(-1, 1)\n", "\n", - " # 1) First: fix \"this\" k\n", - " # 2) and then find the position of the next value (k+1)\n", - " # solver.Add(k == x[(i,j)])\n", - " solver.Add(k == solver.Element(x_flat, i * c + j))\n", - " # solver.Add(k + 1 == x[(i+a,j+b)])\n", - " solver.Add(k + 1 == solver.Element(x_flat, (i + a) * c + (j + b)))\n", + " # 1) First: fix \"this\" k\n", + " # 2) and then find the position of the next value (k+1)\n", + " # solver.Add(k == x[(i,j)])\n", + " solver.Add(k == solver.Element(x_flat, i * c + j))\n", + " # solver.Add(k + 1 == x[(i+a,j+b)])\n", + " solver.Add(k + 1 == solver.Element(x_flat, (i + a) * c + (j + b)))\n", "\n", - " solver.Add(i + a >= 0)\n", - " solver.Add(j + b >= 0)\n", - " solver.Add(i + a < r)\n", - " solver.Add(j + b < c)\n", + " solver.Add(i + a >= 0)\n", + " solver.Add(j + b >= 0)\n", + " solver.Add(i + a < r)\n", + " solver.Add(j + b < c)\n", "\n", - " # solver.Add(((a != 0) | (b != 0)))\n", - " a_nz = solver.BoolVar()\n", - " b_nz = solver.BoolVar()\n", - " solver.Add(a_nz == solver.IsDifferentCstVar(a, 0))\n", - " solver.Add(b_nz == solver.IsDifferentCstVar(b, 0))\n", - " solver.Add(a_nz + b_nz >= 1)\n", + " # solver.Add(((a != 0) | (b != 0)))\n", + " a_nz = solver.BoolVar()\n", + " b_nz = solver.BoolVar()\n", + " solver.Add(a_nz == solver.IsDifferentCstVar(a, 0))\n", + " solver.Add(b_nz == solver.IsDifferentCstVar(b, 0))\n", + " solver.Add(a_nz + b_nz >= 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x_flat)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x_flat)\n", "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(\n", - " x_flat,\n", - " # solver.INT_VAR_DEFAULT\n", - " # solver.INT_VAR_SIMPLE\n", - " # solver.CHOOSE_RANDOM\n", - " # solver.CHOOSE_MIN_SIZE_LOWEST_MIN\n", - " # solver.CHOOSE_MIN_SIZE_HIGHEST_MIN\n", - " # solver.CHOOSE_MIN_SIZE_LOWEST_MAX\n", - " # solver.CHOOSE_MIN_SIZE_HIGHEST_MAX\n", - " # solver.CHOOSE_PATH\n", - " solver.CHOOSE_FIRST_UNBOUND,\n", - " # solver.INT_VALUE_DEFAULT\n", - " # solver.INT_VALUE_SIMPLE\n", - " # solver.ASSIGN_MAX_VALUE\n", - " # solver.ASSIGN_RANDOM_VALUE\n", - " # solver.ASSIGN_CENTER_VALUE\n", - " solver.ASSIGN_MIN_VALUE)\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(\n", + " x_flat,\n", + " # solver.INT_VAR_DEFAULT\n", + " # solver.INT_VAR_SIMPLE\n", + " # solver.CHOOSE_RANDOM\n", + " # solver.CHOOSE_MIN_SIZE_LOWEST_MIN\n", + " # solver.CHOOSE_MIN_SIZE_HIGHEST_MIN\n", + " # solver.CHOOSE_MIN_SIZE_LOWEST_MAX\n", + " # solver.CHOOSE_MIN_SIZE_HIGHEST_MAX\n", + " # solver.CHOOSE_PATH\n", + " solver.CHOOSE_FIRST_UNBOUND,\n", + " # solver.INT_VALUE_DEFAULT\n", + " # solver.INT_VALUE_SIMPLE\n", + " # solver.ASSIGN_MAX_VALUE\n", + " # solver.ASSIGN_RANDOM_VALUE\n", + " # solver.ASSIGN_CENTER_VALUE\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"\\nSolution:\", num_solutions)\n", + " print_board(x, r, c)\n", + " print()\n", + "\n", + " solver.EndSearch()\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"\\nSolution:\", num_solutions)\n", - " print_board(x, r, c)\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "def print_board(x, rows, cols):\n", " for i in range(rows):\n", @@ -275,6 +270,16 @@ " print(\"% 2s\" % game[i][j], end=\" \")\n", " print(\"\")\n", "\n", + "\n", + "# data\n", + "r = 3\n", + "c = r\n", + "if len(sys.argv) > 1:\n", + " r = int(sys.argv[1])\n", + " c = r\n", + "if len(sys.argv) > 2:\n", + " c = int(sys.argv[2])\n", + "main(r, c)\n", "\n" ] } diff --git a/examples/notebook/contrib/just_forgotten.ipynb b/examples/notebook/contrib/just_forgotten.ipynb index b56edb6839..9a91d0e5fc 100644 --- a/examples/notebook/contrib/just_forgotten.ipynb +++ b/examples/notebook/contrib/just_forgotten.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Just forgotten puzzle (Enigma 1517) in Google CP Solver.\n", "\n", @@ -118,70 +103,82 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Just forgotten\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Just forgotten\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "rows = 4\n", - "cols = 10\n", - "# The four tries\n", - "a = [[9, 4, 6, 2, 1, 5, 7, 8, 3, 0], [8, 6, 0, 4, 3, 9, 1, 2, 5, 7],\n", - " [1, 6, 4, 0, 2, 9, 7, 8, 5, 3], [6, 8, 2, 4, 3, 1, 9, 0, 7, 5]]\n", + " #\n", + " # data\n", + " #\n", + " rows = 4\n", + " cols = 10\n", + " # The four tries\n", + " a = [[9, 4, 6, 2, 1, 5, 7, 8, 3, 0], [8, 6, 0, 4, 3, 9, 1, 2, 5, 7],\n", + " [1, 6, 4, 0, 2, 9, 7, 8, 5, 3], [6, 8, 2, 4, 3, 1, 9, 0, 7, 5]]\n", "\n", - "#\n", - "# variables\n", - "#\n", - "x = [solver.IntVar(0, 9, \"x[%i]\" % j) for j in range(cols)]\n", + " #\n", + " # variables\n", + " #\n", + " x = [solver.IntVar(0, 9, \"x[%i]\" % j) for j in range(cols)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", "\n", - "for r in range(rows):\n", - " b = [solver.IsEqualCstVar(x[c], a[r][c]) for c in range(cols)]\n", - " solver.Add(solver.Sum(b) == 4)\n", + " for r in range(rows):\n", + " b = [solver.IsEqualCstVar(x[c], a[r][c]) for c in range(cols)]\n", + " solver.Add(solver.Sum(b) == 4)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " xval = [x[j].Value() for j in range(cols)]\n", - " print(\"Account number:\")\n", - " for j in range(cols):\n", - " print(\"%i \" % xval[j], end=\" \")\n", - " print()\n", - " print(\"\\nThe four tries, where '!' represents a correct digit:\")\n", - " for i in range(rows):\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " xval = [x[j].Value() for j in range(cols)]\n", + " print(\"Account number:\")\n", " for j in range(cols):\n", - " check = \" \"\n", - " if a[i][j] == xval[j]:\n", - " check = \"!\"\n", - " print(\"%i%s\" % (a[i][j], check), end=\" \")\n", + " print(\"%i \" % xval[j], end=\" \")\n", + " print()\n", + " print(\"\\nThe four tries, where '!' represents a correct digit:\")\n", + " for i in range(rows):\n", + " for j in range(cols):\n", + " check = \" \"\n", + " if a[i][j] == xval[j]:\n", + " check = \"!\"\n", + " print(\"%i%s\" % (a[i][j], check), end=\" \")\n", + " print()\n", " print()\n", " print()\n", - "print()\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", "\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/kakuro.ipynb b/examples/notebook/contrib/kakuro.ipynb index 57be57c271..4e77d46cde 100644 --- a/examples/notebook/contrib/kakuro.ipynb +++ b/examples/notebook/contrib/kakuro.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Kakuru puzzle in Google CP Solver.\n", "\n", @@ -128,8 +113,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -152,101 +145,105 @@ " solver.Add(solver.Sum([x[i[0] - 1, i[1] - 1] for i in cc]) == res)\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Kakuro\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Kakuro\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# size of matrix\n", - "n = 7\n", + " # size of matrix\n", + " n = 7\n", "\n", - "# segments\n", - "# [sum, [segments]]\n", - "# Note: 1-based\n", - "problem = [[16, [1, 1], [1, 2]], [24, [1, 5], [1, 6], [1, 7]],\n", - " [17, [2, 1], [2, 2]], [29, [2, 4], [2, 5], [2, 6], [2, 7]],\n", - " [35, [3, 1], [3, 2], [3, 3], [3, 4], [3, 5]], [7, [4, 2], [4, 3]],\n", - " [8, [4, 5], [4, 6]], [16, [5, 3], [5, 4], [5, 5], [5, 6], [5, 7]],\n", - " [21, [6, 1], [6, 2], [6, 3], [6, 4]], [5, [6, 6], [6, 7]],\n", - " [6, [7, 1], [7, 2], [7, 3]], [3, [7, 6], [7, 7]],\n", - " [23, [1, 1], [2, 1], [3, 1]], [30, [1, 2], [2, 2], [3, 2], [4, 2]],\n", - " [27, [1, 5], [2, 5], [3, 5], [4, 5], [5, 5]], [12, [1, 6], [2, 6]],\n", - " [16, [1, 7], [2, 7]], [17, [2, 4], [3, 4]],\n", - " [15, [3, 3], [4, 3], [5, 3], [6, 3], [7, 3]],\n", - " [12, [4, 6], [5, 6], [6, 6], [7, 6]], [7, [5, 4], [6, 4]],\n", - " [7, [5, 7], [6, 7], [7, 7]], [11, [6, 1], [7, 1]],\n", - " [10, [6, 2], [7, 2]]]\n", + " # segments\n", + " # [sum, [segments]]\n", + " # Note: 1-based\n", + " problem = [[16, [1, 1], [1, 2]], [24, [1, 5], [1, 6], [1, 7]],\n", + " [17, [2, 1], [2, 2]], [29, [2, 4], [2, 5], [2, 6], [2, 7]],\n", + " [35, [3, 1], [3, 2], [3, 3], [3, 4], [3, 5]], [7, [4, 2], [4, 3]],\n", + " [8, [4, 5], [4, 6]], [16, [5, 3], [5, 4], [5, 5], [5, 6], [5, 7]],\n", + " [21, [6, 1], [6, 2], [6, 3], [6, 4]], [5, [6, 6], [6, 7]],\n", + " [6, [7, 1], [7, 2], [7, 3]], [3, [7, 6], [7, 7]],\n", + " [23, [1, 1], [2, 1], [3, 1]], [30, [1, 2], [2, 2], [3, 2], [4, 2]],\n", + " [27, [1, 5], [2, 5], [3, 5], [4, 5], [5, 5]], [12, [1, 6], [2, 6]],\n", + " [16, [1, 7], [2, 7]], [17, [2, 4], [3, 4]],\n", + " [15, [3, 3], [4, 3], [5, 3], [6, 3], [7, 3]],\n", + " [12, [4, 6], [5, 6], [6, 6], [7, 6]], [7, [5, 4], [6, 4]],\n", + " [7, [5, 7], [6, 7], [7, 7]], [11, [6, 1], [7, 1]],\n", + " [10, [6, 2], [7, 2]]]\n", "\n", - "num_p = len(problem)\n", + " num_p = len(problem)\n", "\n", - "# The blanks\n", - "# Note: 1-based\n", - "blanks = [[1, 3], [1, 4], [2, 3], [3, 6], [3, 7], [4, 1], [4, 4], [4, 7],\n", - " [5, 1], [5, 2], [6, 5], [7, 4], [7, 5]]\n", - "num_blanks = len(blanks)\n", + " # The blanks\n", + " # Note: 1-based\n", + " blanks = [[1, 3], [1, 4], [2, 3], [3, 6], [3, 7], [4, 1], [4, 4], [4, 7],\n", + " [5, 1], [5, 2], [6, 5], [7, 4], [7, 5]]\n", + " num_blanks = len(blanks)\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "# the set\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[i, j] = solver.IntVar(0, 9, \"x[%i,%i]\" % (i, j))\n", - "\n", - "x_flat = [x[i, j] for i in range(n) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# fill the blanks with 0\n", - "for i in range(num_blanks):\n", - " solver.Add(x[blanks[i][0] - 1, blanks[i][1] - 1] == 0)\n", - "\n", - "for i in range(num_p):\n", - " segment = problem[i][1::]\n", - " res = problem[i][0]\n", - "\n", - " # sum this segment\n", - " calc(segment, x, res)\n", - "\n", - " # all numbers in this segment must be distinct\n", - " segment = [x[p[0] - 1, p[1] - 1] for p in segment]\n", - " solver.Add(solver.AllDifferent(segment))\n", - "\n", - "#\n", - "# search and solution\n", - "#\n", - "db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", + " # the set\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " val = x[i, j].Value()\n", - " if val > 0:\n", - " print(val, end=\" \")\n", - " else:\n", - " print(\" \", end=\" \")\n", + " x[i, j] = solver.IntVar(0, 9, \"x[%i,%i]\" % (i, j))\n", + "\n", + " x_flat = [x[i, j] for i in range(n) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # fill the blanks with 0\n", + " for i in range(num_blanks):\n", + " solver.Add(x[blanks[i][0] - 1, blanks[i][1] - 1] == 0)\n", + "\n", + " for i in range(num_p):\n", + " segment = problem[i][1::]\n", + " res = problem[i][0]\n", + "\n", + " # sum this segment\n", + " calc(segment, x, res)\n", + "\n", + " # all numbers in this segment must be distinct\n", + " segment = [x[p[0] - 1, p[1] - 1] for p in segment]\n", + " solver.Add(solver.AllDifferent(segment))\n", + "\n", + " #\n", + " # search and solution\n", + " #\n", + " db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " for i in range(n):\n", + " for j in range(n):\n", + " val = x[i, j].Value()\n", + " if val > 0:\n", + " print(val, end=\" \")\n", + " else:\n", + " print(\" \", end=\" \")\n", + " print()\n", + "\n", " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/kenken2.ipynb b/examples/notebook/contrib/kenken2.ipynb index 216627cf73..3939c64cd5 100644 --- a/examples/notebook/contrib/kenken2.ipynb +++ b/examples/notebook/contrib/kenken2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " KenKen puzzle in Google CP Solver.\n", "\n", @@ -129,8 +114,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -182,86 +175,90 @@ " solver.Add(this_sum + this_prod >= 1)\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"KenKen\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"KenKen\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# size of matrix\n", - "n = 6\n", + " # size of matrix\n", + " n = 6\n", "\n", - "# For a better view of the problem, see\n", - "# http://en.wikipedia.org/wiki/File:KenKenProblem.svg\n", + " # For a better view of the problem, see\n", + " # http://en.wikipedia.org/wiki/File:KenKenProblem.svg\n", "\n", - "# hints\n", - "# [sum, [segments]]\n", - "# Note: 1-based\n", - "problem = [[11, [[1, 1], [2, 1]]], [2, [[1, 2], [1, 3]]],\n", - " [20, [[1, 4], [2, 4]]], [6, [[1, 5], [1, 6], [2, 6], [3, 6]]],\n", - " [3, [[2, 2], [2, 3]]], [3, [[2, 5], [3, 5]]],\n", - " [240, [[3, 1], [3, 2], [4, 1], [4, 2]]], [6, [[3, 3], [3, 4]]],\n", - " [6, [[4, 3], [5, 3]]], [7, [[4, 4], [5, 4], [5, 5]]],\n", - " [30, [[4, 5], [4, 6]]], [6, [[5, 1], [5, 2]]],\n", - " [9, [[5, 6], [6, 6]]], [8, [[6, 1], [6, 2], [6, 3]]],\n", - " [2, [[6, 4], [6, 5]]]]\n", + " # hints\n", + " # [sum, [segments]]\n", + " # Note: 1-based\n", + " problem = [[11, [[1, 1], [2, 1]]], [2, [[1, 2], [1, 3]]],\n", + " [20, [[1, 4], [2, 4]]], [6, [[1, 5], [1, 6], [2, 6], [3, 6]]],\n", + " [3, [[2, 2], [2, 3]]], [3, [[2, 5], [3, 5]]],\n", + " [240, [[3, 1], [3, 2], [4, 1], [4, 2]]], [6, [[3, 3], [3, 4]]],\n", + " [6, [[4, 3], [5, 3]]], [7, [[4, 4], [5, 4], [5, 5]]],\n", + " [30, [[4, 5], [4, 6]]], [6, [[5, 1], [5, 2]]],\n", + " [9, [[5, 6], [6, 6]]], [8, [[6, 1], [6, 2], [6, 3]]],\n", + " [2, [[6, 4], [6, 5]]]]\n", "\n", - "num_p = len(problem)\n", + " num_p = len(problem)\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "# the set\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[i, j] = solver.IntVar(1, n, \"x[%i,%i]\" % (i, j))\n", - "\n", - "x_flat = [x[i, j] for i in range(n) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# all rows and columns must be unique\n", - "for i in range(n):\n", - " row = [x[i, j] for j in range(n)]\n", - " solver.Add(solver.AllDifferent(row))\n", - "\n", - " col = [x[j, i] for j in range(n)]\n", - " solver.Add(solver.AllDifferent(col))\n", - "\n", - "# calculate the segments\n", - "for (res, segment) in problem:\n", - " calc(segment, x, res)\n", - "\n", - "#\n", - "# search and solution\n", - "#\n", - "db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", + " # the set\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " print(x[i, j].Value(), end=\" \")\n", + " x[i, j] = solver.IntVar(1, n, \"x[%i,%i]\" % (i, j))\n", + "\n", + " x_flat = [x[i, j] for i in range(n) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # all rows and columns must be unique\n", + " for i in range(n):\n", + " row = [x[i, j] for j in range(n)]\n", + " solver.Add(solver.AllDifferent(row))\n", + "\n", + " col = [x[j, i] for j in range(n)]\n", + " solver.Add(solver.AllDifferent(col))\n", + "\n", + " # calculate the segments\n", + " for (res, segment) in problem:\n", + " calc(segment, x, res)\n", + "\n", + " #\n", + " # search and solution\n", + " #\n", + " db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(x[i, j].Value(), end=\" \")\n", + " print()\n", + "\n", " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/killer_sudoku.ipynb b/examples/notebook/contrib/killer_sudoku.ipynb index 33ce388d3a..543c1d4404 100644 --- a/examples/notebook/contrib/killer_sudoku.ipynb +++ b/examples/notebook/contrib/killer_sudoku.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Killer Sudoku in Google CP Solver.\n", "\n", @@ -141,8 +126,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -162,101 +155,105 @@ " solver.Add(solver.AllDifferent(cage))\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Killer Sudoku\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Killer Sudoku\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# size of matrix\n", - "n = 9\n", + " # size of matrix\n", + " n = 9\n", "\n", - "# For a better view of the problem, see\n", - "# http://en.wikipedia.org/wiki/File:Killersudoku_color.svg\n", + " # For a better view of the problem, see\n", + " # http://en.wikipedia.org/wiki/File:Killersudoku_color.svg\n", "\n", - "# hints\n", - "# [sum, [segments]]\n", - "# Note: 1-based\n", - "problem = [[3, [[1, 1], [1, 2]]], [15, [[1, 3], [1, 4], [1, 5]]],\n", - " [22, [[1, 6], [2, 5], [2, 6], [3, 5]]], [4, [[1, 7], [2, 7]]],\n", - " [16, [[1, 8], [2, 8]]], [15, [[1, 9], [2, 9], [3, 9], [4, 9]]],\n", - " [25, [[2, 1], [2, 2], [3, 1], [3, 2]]], [17, [[2, 3], [2, 4]]],\n", - " [9, [[3, 3], [3, 4], [4, 4]]], [8, [[3, 6], [4, 6], [5, 6]]],\n", - " [20, [[3, 7], [3, 8], [4, 7]]], [6, [[4, 1], [5, 1]]],\n", - " [14, [[4, 2], [4, 3]]], [17, [[4, 5], [5, 5], [6, 5]]],\n", - " [17, [[4, 8], [5, 7], [5, 8]]], [13, [[5, 2], [5, 3], [6, 2]]],\n", - " [20, [[5, 4], [6, 4], [7, 4]]], [12, [[5, 9], [6, 9]]],\n", - " [27, [[6, 1], [7, 1], [8, 1], [9, 1]]],\n", - " [6, [[6, 3], [7, 2], [7, 3]]], [20, [[6, 6], [7, 6], [7, 7]]],\n", - " [6, [[6, 7], [6, 8]]], [10, [[7, 5], [8, 4], [8, 5], [9, 4]]],\n", - " [14, [[7, 8], [7, 9], [8, 8], [8, 9]]], [8, [[8, 2], [9, 2]]],\n", - " [16, [[8, 3], [9, 3]]], [15, [[8, 6], [8, 7]]],\n", - " [13, [[9, 5], [9, 6], [9, 7]]], [17, [[9, 8], [9, 9]]]]\n", + " # hints\n", + " # [sum, [segments]]\n", + " # Note: 1-based\n", + " problem = [[3, [[1, 1], [1, 2]]], [15, [[1, 3], [1, 4], [1, 5]]],\n", + " [22, [[1, 6], [2, 5], [2, 6], [3, 5]]], [4, [[1, 7], [2, 7]]],\n", + " [16, [[1, 8], [2, 8]]], [15, [[1, 9], [2, 9], [3, 9], [4, 9]]],\n", + " [25, [[2, 1], [2, 2], [3, 1], [3, 2]]], [17, [[2, 3], [2, 4]]],\n", + " [9, [[3, 3], [3, 4], [4, 4]]], [8, [[3, 6], [4, 6], [5, 6]]],\n", + " [20, [[3, 7], [3, 8], [4, 7]]], [6, [[4, 1], [5, 1]]],\n", + " [14, [[4, 2], [4, 3]]], [17, [[4, 5], [5, 5], [6, 5]]],\n", + " [17, [[4, 8], [5, 7], [5, 8]]], [13, [[5, 2], [5, 3], [6, 2]]],\n", + " [20, [[5, 4], [6, 4], [7, 4]]], [12, [[5, 9], [6, 9]]],\n", + " [27, [[6, 1], [7, 1], [8, 1], [9, 1]]],\n", + " [6, [[6, 3], [7, 2], [7, 3]]], [20, [[6, 6], [7, 6], [7, 7]]],\n", + " [6, [[6, 7], [6, 8]]], [10, [[7, 5], [8, 4], [8, 5], [9, 4]]],\n", + " [14, [[7, 8], [7, 9], [8, 8], [8, 9]]], [8, [[8, 2], [9, 2]]],\n", + " [16, [[8, 3], [9, 3]]], [15, [[8, 6], [8, 7]]],\n", + " [13, [[9, 5], [9, 6], [9, 7]]], [17, [[9, 8], [9, 9]]]]\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "# the set\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[i, j] = solver.IntVar(1, n, \"x[%i,%i]\" % (i, j))\n", - "\n", - "x_flat = [x[i, j] for i in range(n) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# all rows and columns must be unique\n", - "for i in range(n):\n", - " row = [x[i, j] for j in range(n)]\n", - " solver.Add(solver.AllDifferent(row))\n", - "\n", - " col = [x[j, i] for j in range(n)]\n", - " solver.Add(solver.AllDifferent(col))\n", - "\n", - "# cells\n", - "for i in range(2):\n", - " for j in range(2):\n", - " cell = [\n", - " x[r, c]\n", - " for r in range(i * 3, i * 3 + 3)\n", - " for c in range(j * 3, j * 3 + 3)\n", - " ]\n", - " solver.Add(solver.AllDifferent(cell))\n", - "\n", - "# calculate the segments\n", - "for (res, segment) in problem:\n", - " calc(segment, x, res)\n", - "\n", - "#\n", - "# search and solution\n", - "#\n", - "db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", + " # the set\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " print(x[i, j].Value(), end=\" \")\n", + " x[i, j] = solver.IntVar(1, n, \"x[%i,%i]\" % (i, j))\n", + "\n", + " x_flat = [x[i, j] for i in range(n) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # all rows and columns must be unique\n", + " for i in range(n):\n", + " row = [x[i, j] for j in range(n)]\n", + " solver.Add(solver.AllDifferent(row))\n", + "\n", + " col = [x[j, i] for j in range(n)]\n", + " solver.Add(solver.AllDifferent(col))\n", + "\n", + " # cells\n", + " for i in range(2):\n", + " for j in range(2):\n", + " cell = [\n", + " x[r, c]\n", + " for r in range(i * 3, i * 3 + 3)\n", + " for c in range(j * 3, j * 3 + 3)\n", + " ]\n", + " solver.Add(solver.AllDifferent(cell))\n", + "\n", + " # calculate the segments\n", + " for (res, segment) in problem:\n", + " calc(segment, x, res)\n", + "\n", + " #\n", + " # search and solution\n", + " #\n", + " db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(x[i, j].Value(), end=\" \")\n", + " print()\n", + "\n", " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/knapsack_cp.ipynb b/examples/notebook/contrib/knapsack_cp.ipynb index 0105384cf9..13443e9359 100644 --- a/examples/notebook/contrib/knapsack_cp.ipynb +++ b/examples/notebook/contrib/knapsack_cp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Knapsack problem in Google CP Solver.\n", "\n", @@ -95,8 +80,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", @@ -110,55 +103,59 @@ " return [x, z]\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"knapsack_cp\")\n", + "def main(values, weights, n):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"knapsack_cp\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"values:\", values)\n", - "print(\"weights:\", weights)\n", - "print(\"n:\", n)\n", - "print()\n", - "\n", - "# declare variables\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "[x, z] = knapsack(solver, values, weights, n)\n", - "\n", - "# objective\n", - "objective = solver.Maximize(z, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(z)\n", - "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"x:\", [x[i].Value() for i in range(len(values))])\n", - " print(\"z:\", z.Value())\n", + " #\n", + " # data\n", + " #\n", + " print(\"values:\", values)\n", + " print(\"weights:\", weights)\n", + " print(\"n:\", n)\n", " print()\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " # declare variables\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " [x, z] = knapsack(solver, values, weights, n)\n", + "\n", + " # objective\n", + " objective = solver.Maximize(z, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(z)\n", + "\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"x:\", [x[i].Value() for i in range(len(values))])\n", + " print(\"z:\", z.Value())\n", + " print()\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", + "\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", "\n", "values = [15, 100, 90, 60, 40, 15, 10, 1, 12, 12, 100]\n", "weights = [2, 20, 20, 30, 40, 30, 60, 10, 21, 12, 2]\n", "n = 102\n", + "\n", + "main(values, weights, n)\n", "\n" ] } diff --git a/examples/notebook/contrib/knapsack_mip.ipynb b/examples/notebook/contrib/knapsack_mip.ipynb index 0870953e53..4758f28f28 100644 --- a/examples/notebook/contrib/knapsack_mip.ipynb +++ b/examples/notebook/contrib/knapsack_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Knapsack problem using MIP in Google or-tools.\n", "\n", @@ -95,80 +80,100 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "print('Solver: ', sol)\n", + " print('Solver: ', sol)\n", "\n", - "# using GLPK\n", - "if sol == 'GLPK':\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", - "else:\n", - " # Using CBC\n", - " solver = pywraplp.Solver('CoinsGridCBC',\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " # using GLPK\n", + " if sol == 'GLPK':\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", + " else:\n", + " # Using CBC\n", + " solver = pywraplp.Solver('CoinsGridCBC',\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "#\n", - "# data\n", - "#\n", - "nb_items = 12\n", - "nb_resources = 7\n", - "items = list(range(nb_items))\n", - "resources = list(range(nb_resources))\n", + " #\n", + " # data\n", + " #\n", + " nb_items = 12\n", + " nb_resources = 7\n", + " items = list(range(nb_items))\n", + " resources = list(range(nb_resources))\n", "\n", - "capacity = [18209, 7692, 1333, 924, 26638, 61188, 13360]\n", - "value = [96, 76, 56, 11, 86, 10, 66, 86, 83, 12, 9, 81]\n", - "use = [[19, 1, 10, 1, 1, 14, 152, 11, 1, 1, 1, 1],\n", - " [0, 4, 53, 0, 0, 80, 0, 4, 5, 0, 0, 0],\n", - " [4, 660, 3, 0, 30, 0, 3, 0, 4, 90, 0, 0],\n", - " [7, 0, 18, 6, 770, 330, 7, 0, 0, 6, 0, 0],\n", - " [0, 20, 0, 4, 52, 3, 0, 0, 0, 5, 4, 0],\n", - " [0, 0, 40, 70, 4, 63, 0, 0, 60, 0, 4, 0],\n", - " [0, 32, 0, 0, 0, 5, 0, 3, 0, 660, 0, 9]]\n", + " capacity = [18209, 7692, 1333, 924, 26638, 61188, 13360]\n", + " value = [96, 76, 56, 11, 86, 10, 66, 86, 83, 12, 9, 81]\n", + " use = [[19, 1, 10, 1, 1, 14, 152, 11, 1, 1, 1, 1],\n", + " [0, 4, 53, 0, 0, 80, 0, 4, 5, 0, 0, 0],\n", + " [4, 660, 3, 0, 30, 0, 3, 0, 4, 90, 0, 0],\n", + " [7, 0, 18, 6, 770, 330, 7, 0, 0, 6, 0, 0],\n", + " [0, 20, 0, 4, 52, 3, 0, 0, 0, 5, 4, 0],\n", + " [0, 0, 40, 70, 4, 63, 0, 0, 60, 0, 4, 0],\n", + " [0, 32, 0, 0, 0, 5, 0, 3, 0, 660, 0, 9]]\n", "\n", - "max_value = max(capacity)\n", + " max_value = max(capacity)\n", "\n", - "#\n", - "# variables\n", - "#\n", - "take = [solver.IntVar(0, max_value, 'take[%i]' % j) for j in items]\n", + " #\n", + " # variables\n", + " #\n", + " take = [solver.IntVar(0, max_value, 'take[%i]' % j) for j in items]\n", "\n", - "# total cost, to be maximized\n", - "z = solver.Sum([value[i] * take[i] for i in items])\n", + " # total cost, to be maximized\n", + " z = solver.Sum([value[i] * take[i] for i in items])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for r in resources:\n", - " solver.Add(solver.Sum([use[r][i] * take[i] for i in items]) <= capacity[r])\n", + " #\n", + " # constraints\n", + " #\n", + " for r in resources:\n", + " solver.Add(solver.Sum([use[r][i] * take[i] for i in items]) <= capacity[r])\n", "\n", - "# objective\n", - "objective = solver.Maximize(z)\n", + " # objective\n", + " objective = solver.Maximize(z)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('z: ', int(solver.Objective().Value()))\n", + " print()\n", + " print('z: ', int(solver.Objective().Value()))\n", "\n", - "print('take:', end=' ')\n", - "for i in items:\n", - " print(int(take[i].SolutionValue()), end=' ')\n", - "print()\n", + " print('take:', end=' ')\n", + " for i in items:\n", + " print(int(take[i].SolutionValue()), end=' ')\n", + " print()\n", "\n", - "print()\n", - "print('walltime :', solver.WallTime(), 'ms')\n", - "if sol == 'CBC':\n", - " print('iterations:', solver.Iterations())\n", + " print()\n", + " print('walltime :', solver.WallTime(), 'ms')\n", + " if sol == 'CBC':\n", + " print('iterations:', solver.Iterations())\n", + "\n", + "\n", + "\n", + "sol = 'CBC'\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/labeled_dice.ipynb b/examples/notebook/contrib/labeled_dice.ipynb index 4fb7122e78..6208d613fb 100644 --- a/examples/notebook/contrib/labeled_dice.ipynb +++ b/examples/notebook/contrib/labeled_dice.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Labeled dice problem in Google CP Solver.\n", "\n", @@ -120,90 +105,102 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Labeled dice\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Labeled dice\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", - "m = 24\n", - "A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, Y = (\n", - " list(range(m)))\n", - "letters = [\n", - " \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\",\n", - " \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"Y\"\n", - "]\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", + " m = 24\n", + " A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, Y = (\n", + " list(range(m)))\n", + " letters = [\n", + " \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\",\n", + " \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"Y\"\n", + " ]\n", "\n", - "num_words = 13\n", - "words = [[B, U, O, Y], [C, A, V, E], [C, E, L, T], [F, L, U, B], [F, O, R, K],\n", - " [H, E, M, P], [J, U, D, Y], [J, U, N, K], [L, I, M, N], [Q, U, I, P],\n", - " [S, W, A, G], [V, I, S, A], [W, I, S, H]]\n", + " num_words = 13\n", + " words = [[B, U, O, Y], [C, A, V, E], [C, E, L, T], [F, L, U, B], [F, O, R, K],\n", + " [H, E, M, P], [J, U, D, Y], [J, U, N, K], [L, I, M, N], [Q, U, I, P],\n", + " [S, W, A, G], [V, I, S, A], [W, I, S, H]]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "dice = [solver.IntVar(0, n - 1, \"dice[%i]\" % i) for i in range(m)]\n", + " #\n", + " # declare variables\n", + " #\n", + " dice = [solver.IntVar(0, n - 1, \"dice[%i]\" % i) for i in range(m)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# the letters in a word must be on a different die\n", - "for i in range(num_words):\n", - " solver.Add(solver.AllDifferent([dice[words[i][j]] for j in range(n)]))\n", - "\n", - "# there must be exactly 6 letters of each die\n", - "for i in range(n):\n", - " b = [solver.IsEqualCstVar(dice[j], i) for j in range(m)]\n", - " solver.Add(solver.Sum(b) == 6)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(dice)\n", - "\n", - "db = solver.Phase(dice, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", - "\n", - "#\n", - "# result\n", - "#\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " # print \"dice:\", [(letters[i],dice[i].Value()) for i in range(m)]\n", - " for d in range(n):\n", - " print(\"die %i:\" % d, end=\" \")\n", - " for i in range(m):\n", - " if dice[i].Value() == d:\n", - " print(letters[i], end=\" \")\n", - " print()\n", - "\n", - " print(\"The words with the cube label:\")\n", + " # the letters in a word must be on a different die\n", " for i in range(num_words):\n", - " for j in range(n):\n", - " print(\n", - " \"%s (%i)\" % (letters[words[i][j]], dice[words[i][j]].Value()),\n", - " end=\" \")\n", + " solver.Add(solver.AllDifferent([dice[words[i][j]] for j in range(n)]))\n", + "\n", + " # there must be exactly 6 letters of each die\n", + " for i in range(n):\n", + " b = [solver.IsEqualCstVar(dice[j], i) for j in range(m)]\n", + " solver.Add(solver.Sum(b) == 6)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(dice)\n", + "\n", + " db = solver.Phase(dice, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " #\n", + " # result\n", + " #\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " # print \"dice:\", [(letters[i],dice[i].Value()) for i in range(m)]\n", + " for d in range(n):\n", + " print(\"die %i:\" % d, end=\" \")\n", + " for i in range(m):\n", + " if dice[i].Value() == d:\n", + " print(letters[i], end=\" \")\n", + " print()\n", + "\n", + " print(\"The words with the cube label:\")\n", + " for i in range(num_words):\n", + " for j in range(n):\n", + " print(\n", + " \"%s (%i)\" % (letters[words[i][j]], dice[words[i][j]].Value()),\n", + " end=\" \")\n", + " print()\n", + "\n", " print()\n", "\n", + " solver.EndSearch()\n", + "\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/langford.ipynb b/examples/notebook/contrib/langford.ipynb index dba4bac16a..7c49bb3583 100644 --- a/examples/notebook/contrib/langford.ipynb +++ b/examples/notebook/contrib/langford.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Langford's number problem in Google CP Solver.\n", "\n", @@ -117,66 +102,83 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(k=8, num_sol=0):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Langford\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Langford\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"k:\", k)\n", - "p = list(range(2 * k))\n", + " #\n", + " # data\n", + " #\n", + " print(\"k:\", k)\n", + " p = list(range(2 * k))\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "position = [solver.IntVar(0, 2 * k - 1, \"position[%i]\" % i) for i in p]\n", - "solution = [solver.IntVar(1, k, \"position[%i]\" % i) for i in p]\n", + " #\n", + " # declare variables\n", + " #\n", + " position = [solver.IntVar(0, 2 * k - 1, \"position[%i]\" % i) for i in p]\n", + " solution = [solver.IntVar(1, k, \"position[%i]\" % i) for i in p]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(position))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(position))\n", "\n", - "for i in range(1, k + 1):\n", - " solver.Add(position[i + k - 1] == position[i - 1] + i + 1)\n", - " solver.Add(solver.Element(solution, position[i - 1]) == i)\n", - " solver.Add(solver.Element(solution, position[k + i - 1]) == i)\n", + " for i in range(1, k + 1):\n", + " solver.Add(position[i + k - 1] == position[i - 1] + i + 1)\n", + " solver.Add(solver.Element(solution, position[i - 1]) == i)\n", + " solver.Add(solver.Element(solution, position[k + i - 1]) == i)\n", "\n", - "# symmetry breaking\n", - "solver.Add(solution[0] < solution[2 * k - 1])\n", + " # symmetry breaking\n", + " solver.Add(solution[0] < solution[2 * k - 1])\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(position, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(position, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"solution:\", \",\".join([str(solution[i].Value()) for i in p]))\n", - " num_solutions += 1\n", - " if num_sol > 0 and num_solutions >= num_sol:\n", - " break\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"solution:\", \",\".join([str(solution[i].Value()) for i in p]))\n", + " num_solutions += 1\n", + " if num_sol > 0 and num_solutions >= num_sol:\n", + " break\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", + "\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "k = 8\n", - "num_sol = 0\n" + "num_sol = 0\n", + "if len(sys.argv) > 1:\n", + " k = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " num_sol = int(sys.argv[2])\n", + "\n", + "main(k, num_sol)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/least_diff.ipynb b/examples/notebook/contrib/least_diff.ipynb index 7008125b85..716a38bba4 100644 --- a/examples/notebook/contrib/least_diff.ipynb +++ b/examples/notebook/contrib/least_diff.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Least diff problem in Google CP Solver.\n", "\n", @@ -110,79 +95,91 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_cp_solver/\n", - "\"\"\"\n", + " http://www.hakank.org/google_cp_solver/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Least diff\")\n", + "def main(unused_argv):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Least diff\")\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "digits = list(range(0, 10))\n", - "a = solver.IntVar(digits, \"a\")\n", - "b = solver.IntVar(digits, \"b\")\n", - "c = solver.IntVar(digits, \"c\")\n", - "d = solver.IntVar(digits, \"d\")\n", - "e = solver.IntVar(digits, \"e\")\n", + " #\n", + " # declare variables\n", + " #\n", + " digits = list(range(0, 10))\n", + " a = solver.IntVar(digits, \"a\")\n", + " b = solver.IntVar(digits, \"b\")\n", + " c = solver.IntVar(digits, \"c\")\n", + " d = solver.IntVar(digits, \"d\")\n", + " e = solver.IntVar(digits, \"e\")\n", "\n", - "f = solver.IntVar(digits, \"f\")\n", - "g = solver.IntVar(digits, \"g\")\n", - "h = solver.IntVar(digits, \"h\")\n", - "i = solver.IntVar(digits, \"i\")\n", - "j = solver.IntVar(digits, \"j\")\n", + " f = solver.IntVar(digits, \"f\")\n", + " g = solver.IntVar(digits, \"g\")\n", + " h = solver.IntVar(digits, \"h\")\n", + " i = solver.IntVar(digits, \"i\")\n", + " j = solver.IntVar(digits, \"j\")\n", "\n", - "letters = [a, b, c, d, e, f, g, h, i, j]\n", + " letters = [a, b, c, d, e, f, g, h, i, j]\n", "\n", - "digit_vector = [10000, 1000, 100, 10, 1]\n", - "x = solver.ScalProd(letters[0:5], digit_vector)\n", - "y = solver.ScalProd(letters[5:], digit_vector)\n", - "diff = x - y\n", + " digit_vector = [10000, 1000, 100, 10, 1]\n", + " x = solver.ScalProd(letters[0:5], digit_vector)\n", + " y = solver.ScalProd(letters[5:], digit_vector)\n", + " diff = x - y\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(diff > 0)\n", - "solver.Add(solver.AllDifferent(letters))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(diff > 0)\n", + " solver.Add(solver.AllDifferent(letters))\n", "\n", - "# objective\n", - "objective = solver.Minimize(diff, 1)\n", + " # objective\n", + " objective = solver.Minimize(diff, 1)\n", "\n", - "#\n", - "# solution\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(letters)\n", - "solution.Add(x)\n", - "solution.Add(y)\n", - "solution.Add(diff)\n", + " #\n", + " # solution\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(letters)\n", + " solution.Add(x)\n", + " solution.Add(y)\n", + " solution.Add(diff)\n", "\n", - "# last solution since it's a minimization problem\n", - "collector = solver.LastSolutionCollector(solution)\n", - "search_log = solver.SearchLog(100, diff)\n", - "# Note: I'm not sure what CHOOSE_PATH do, but it is fast:\n", - "# find the solution in just 4 steps\n", - "solver.Solve(\n", - " solver.Phase(letters, solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE),\n", - " [objective, search_log, collector])\n", + " # last solution since it's a minimization problem\n", + " collector = solver.LastSolutionCollector(solution)\n", + " search_log = solver.SearchLog(100, diff)\n", + " # Note: I'm not sure what CHOOSE_PATH do, but it is fast:\n", + " # find the solution in just 4 steps\n", + " solver.Solve(\n", + " solver.Phase(letters, solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE),\n", + " [objective, search_log, collector])\n", "\n", - "# get the first (and only) solution\n", + " # get the first (and only) solution\n", "\n", - "xval = collector.Value(0, x)\n", - "yval = collector.Value(0, y)\n", - "diffval = collector.Value(0, diff)\n", - "print(\"x:\", xval)\n", - "print(\"y:\", yval)\n", - "print(\"diff:\", diffval)\n", - "print(xval, \"-\", yval, \"=\", diffval)\n", - "print([(\"abcdefghij\" [i], collector.Value(0, letters[i])) for i in range(10)])\n", - "print()\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print()\n", + " xval = collector.Value(0, x)\n", + " yval = collector.Value(0, y)\n", + " diffval = collector.Value(0, diff)\n", + " print(\"x:\", xval)\n", + " print(\"y:\", yval)\n", + " print(\"diff:\", diffval)\n", + " print(xval, \"-\", yval, \"=\", diffval)\n", + " print([(\"abcdefghij\" [i], collector.Value(0, letters[i])) for i in range(10)])\n", + " print()\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print()\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/least_square.ipynb b/examples/notebook/contrib/least_square.ipynb index b05cd7cd33..515e399803 100644 --- a/examples/notebook/contrib/least_square.ipynb +++ b/examples/notebook/contrib/least_square.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Least square optimization problem in Google or-tools.\n", "\n", @@ -98,69 +83,89 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "# using GLPK\n", - "if sol == 'GLPK':\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", - "else:\n", - " # Using CLP\n", - " solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", + " # using GLPK\n", + " if sol == 'GLPK':\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", + " else:\n", + " # Using CLP\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", "\n", - "# data\n", - "# number of points\n", - "num = 14\n", + " # data\n", + " # number of points\n", + " num = 14\n", "\n", - "# temperature\n", - "t = [20, 30, 80, 125, 175, 225, 275, 325, 360, 420, 495, 540, 630, 700]\n", + " # temperature\n", + " t = [20, 30, 80, 125, 175, 225, 275, 325, 360, 420, 495, 540, 630, 700]\n", "\n", - "# percentage gas\n", - "F = [\n", - " 0.0, 5.8, 14.7, 31.6, 43.2, 58.3, 78.4, 89.4, 96.4, 99.1, 99.5, 99.9,\n", - " 100.0, 100.0\n", - "]\n", + " # percentage gas\n", + " F = [\n", + " 0.0, 5.8, 14.7, 31.6, 43.2, 58.3, 78.4, 89.4, 96.4, 99.1, 99.5, 99.9,\n", + " 100.0, 100.0\n", + " ]\n", "\n", - "p = 4\n", + " p = 4\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "a = [solver.NumVar(-100, 100, 'a[%i]' % i) for i in range(p + 1)]\n", + " #\n", + " # declare variables\n", + " #\n", + " a = [solver.NumVar(-100, 100, 'a[%i]' % i) for i in range(p + 1)]\n", "\n", - "# to minimize\n", - "z = solver.Sum([\n", - " (F[i] - (sum([a[j] * t[i]**j for j in range(p + 1)]))) for i in range(num)\n", - "])\n", + " # to minimize\n", + " z = solver.Sum([\n", + " (F[i] - (sum([a[j] * t[i]**j for j in range(p + 1)]))) for i in range(num)\n", + " ])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.Sum([20**i * a[i] for i in range(p + 1)]) == 0)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.Sum([20**i * a[i] for i in range(p + 1)]) == 0)\n", "\n", - "solver.Add((a[0] + sum([700.0**j * a[j] for j in range(1, p + 1)])) == 100.0)\n", + " solver.Add((a[0] + sum([700.0**j * a[j] for j in range(1, p + 1)])) == 100.0)\n", "\n", - "for i in range(num):\n", - " solver.Add(\n", - " solver.Sum([j * a[j] * t[i]**(j - 1) for j in range(p + 1)]) >= 0)\n", + " for i in range(num):\n", + " solver.Add(\n", + " solver.Sum([j * a[j] * t[i]**(j - 1) for j in range(p + 1)]) >= 0)\n", "\n", - "objective = solver.Minimize(z)\n", + " objective = solver.Minimize(z)\n", "\n", - "solver.Solve()\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('z = ', solver.Objective().Value())\n", - "for i in range(p + 1):\n", - " print(a[i].SolutionValue(), end=' ')\n", - "print()\n", + " print()\n", + " print('z = ', solver.Objective().Value())\n", + " for i in range(p + 1):\n", + " print(a[i].SolutionValue(), end=' ')\n", + " print()\n", + "\n", + "\n", + "\n", + "sol = 'CBC'\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/lectures.ipynb b/examples/notebook/contrib/lectures.ipynb index c46e884b65..398fb2c756 100644 --- a/examples/notebook/contrib/lectures.ipynb +++ b/examples/notebook/contrib/lectures.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Lectures problem in Google CP Solver.\n", "\n", @@ -117,80 +102,92 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Lectures')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Lectures')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "#\n", - "# The schedule requirements:\n", - "# lecture a cannot be held at the same time as b\n", - "# Note: 1-based\n", - "g = [[1, 2], [1, 4], [3, 5], [2, 6], [4, 5], [5, 6], [1, 6]]\n", + " #\n", + " # The schedule requirements:\n", + " # lecture a cannot be held at the same time as b\n", + " # Note: 1-based\n", + " g = [[1, 2], [1, 4], [3, 5], [2, 6], [4, 5], [5, 6], [1, 6]]\n", "\n", - "# number of nodes\n", - "n = 6\n", + " # number of nodes\n", + " n = 6\n", "\n", - "# number of edges\n", - "edges = len(g)\n", + " # number of edges\n", + " edges = len(g)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "v = [solver.IntVar(0, n - 1, 'v[%i]' % i) for i in range(n)]\n", + " #\n", + " # declare variables\n", + " #\n", + " v = [solver.IntVar(0, n - 1, 'v[%i]' % i) for i in range(n)]\n", "\n", - "# maximum color, to minimize\n", - "# Note: since Python is 0-based, the\n", - "# number of colors is +1\n", - "max_c = solver.IntVar(0, n - 1, 'max_c')\n", + " # maximum color, to minimize\n", + " # Note: since Python is 0-based, the\n", + " # number of colors is +1\n", + " max_c = solver.IntVar(0, n - 1, 'max_c')\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(max_c == solver.Max(v))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(max_c == solver.Max(v))\n", "\n", - "# ensure that there are no clashes\n", - "# also, adjust to 0-base\n", - "for i in range(edges):\n", - " solver.Add(v[g[i][0] - 1] != v[g[i][1] - 1])\n", + " # ensure that there are no clashes\n", + " # also, adjust to 0-base\n", + " for i in range(edges):\n", + " solver.Add(v[g[i][0] - 1] != v[g[i][1] - 1])\n", "\n", - "# symmetry breaking:\n", - "# - v0 has the color 0,\n", - "# - v1 has either color 0 or 1\n", - "solver.Add(v[0] == 0)\n", - "solver.Add(v[1] <= 1)\n", + " # symmetry breaking:\n", + " # - v0 has the color 0,\n", + " # - v1 has either color 0 or 1\n", + " solver.Add(v[0] == 0)\n", + " solver.Add(v[1] <= 1)\n", "\n", - "# objective\n", - "objective = solver.Minimize(max_c, 1)\n", + " # objective\n", + " objective = solver.Minimize(max_c, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(v, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.ASSIGN_CENTER_VALUE)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(v, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.ASSIGN_CENTER_VALUE)\n", "\n", - "solver.NewSearch(db, [objective])\n", + " solver.NewSearch(db, [objective])\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('max_c:', max_c.Value() + 1, 'colors')\n", - " print('v:', [v[i].Value() for i in range(n)])\n", - " print()\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('max_c:', max_c.Value() + 1, 'colors')\n", + " print('v:', [v[i].Value() for i in range(n)])\n", + " print()\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/magic_sequence_sat.ipynb b/examples/notebook/contrib/magic_sequence_sat.ipynb index a81378c3fe..24f188fa5e 100644 --- a/examples/notebook/contrib/magic_sequence_sat.ipynb +++ b/examples/notebook/contrib/magic_sequence_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve the magic sequence problem with the CP-SAT solver.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,52 +83,41 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2018 Gergo Rozner\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", - "\"\"\"Solve the magic sequence problem with the CP-SAT solver.\"\"\"\n", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", - "\"\"\"Magic sequence problem.\"\"\"\n", - "n = 100\n", - "values = range(n)\n", + "def main():\n", + " \"\"\"Magic sequence problem.\"\"\"\n", + " n = 100\n", + " values = range(n)\n", "\n", - "model = cp_model.CpModel()\n", + " model = cp_model.CpModel()\n", "\n", - "x = [model.NewIntVar(0, n, 'x%i' % i) for i in values]\n", + " x = [model.NewIntVar(0, n, 'x%i' % i) for i in values]\n", "\n", - "for k in values:\n", - " tmp_array = []\n", - " for i in values:\n", - " tmp_var = model.NewBoolVar('')\n", - " model.Add(x[i] == k).OnlyEnforceIf(tmp_var)\n", - " model.Add(x[i] != k).OnlyEnforceIf(tmp_var.Not())\n", - " tmp_array.append(tmp_var)\n", - " model.Add(sum(tmp_array) == x[k])\n", + " for k in values:\n", + " tmp_array = []\n", + " for i in values:\n", + " tmp_var = model.NewBoolVar('')\n", + " model.Add(x[i] == k).OnlyEnforceIf(tmp_var)\n", + " model.Add(x[i] != k).OnlyEnforceIf(tmp_var.Not())\n", + " tmp_array.append(tmp_var)\n", + " model.Add(sum(tmp_array) == x[k])\n", "\n", - "# Redundant constraint.\n", - "model.Add(sum(x) == n)\n", + " # Redundant constraint.\n", + " model.Add(sum(x) == n)\n", "\n", - "solver = cp_model.CpSolver()\n", - "# No solution printer, this problem has only 1 solution.\n", - "solver.parameters.log_search_progress = True\n", - "solver.Solve(model)\n", - "print(solver.ResponseStats())\n", - "for k in values:\n", - " print('x[%i] = %i ' % (k, solver.Value(x[k])), end='')\n", - "print()\n", + " solver = cp_model.CpSolver()\n", + " # No solution printer, this problem has only 1 solution.\n", + " solver.parameters.log_search_progress = True\n", + " solver.Solve(model)\n", + " print(solver.ResponseStats())\n", + " for k in values:\n", + " print('x[%i] = %i ' % (k, solver.Value(x[k])), end='')\n", + " print()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/magic_square.ipynb b/examples/notebook/contrib/magic_square.ipynb index 7283183323..396b6a649e 100644 --- a/examples/notebook/contrib/magic_square.ipynb +++ b/examples/notebook/contrib/magic_square.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Magic squares in Google CP Solver.\n", "\n", @@ -95,88 +80,105 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"n-queens\")\n", + "def main(n, limit):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"n-queens\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[(i, j)] = solver.IntVar(1, n * n, \"x(%i,%i)\" % (i, j))\n", - "x_flat = [x[(i, j)] for i in range(n) for j in range(n)]\n", - "\n", - "# the sum\n", - "# s = ( n * (n*n + 1)) / 2\n", - "s = solver.IntVar(1, n * n * n, \"s\")\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "# solver.Add(s == ( n * (n*n + 1)) / 2)\n", - "\n", - "solver.Add(solver.AllDifferent(x_flat))\n", - "\n", - "[solver.Add(solver.Sum([x[(i, j)] for j in range(n)]) == s) for i in range(n)]\n", - "[solver.Add(solver.Sum([x[(i, j)] for i in range(n)]) == s) for j in range(n)]\n", - "\n", - "solver.Add(solver.Sum([x[(i, i)] for i in range(n)]) == s) # diag 1\n", - "solver.Add(solver.Sum([x[(i, n - i - 1)] for i in range(n)]) == s) # diag 2\n", - "\n", - "# symmetry breaking\n", - "# solver.Add(x[(0,0)] == 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x_flat)\n", - "solution.Add(s)\n", - "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(\n", - " x_flat,\n", - " # solver.INT_VAR_DEFAULT,\n", - " solver.CHOOSE_FIRST_UNBOUND,\n", - " # solver.CHOOSE_MIN_SIZE_LOWEST_MAX,\n", - "\n", - " # solver.ASSIGN_MIN_VALUE\n", - " solver.ASSIGN_CENTER_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"s:\", s.Value())\n", + " #\n", + " # declare variables\n", + " #\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " print(\"%2i\" % x[(i, j)].Value(), end=\" \")\n", + " x[(i, j)] = solver.IntVar(1, n * n, \"x(%i,%i)\" % (i, j))\n", + " x_flat = [x[(i, j)] for i in range(n) for j in range(n)]\n", + "\n", + " # the sum\n", + " # s = ( n * (n*n + 1)) / 2\n", + " s = solver.IntVar(1, n * n * n, \"s\")\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " # solver.Add(s == ( n * (n*n + 1)) / 2)\n", + "\n", + " solver.Add(solver.AllDifferent(x_flat))\n", + "\n", + " [solver.Add(solver.Sum([x[(i, j)] for j in range(n)]) == s) for i in range(n)]\n", + " [solver.Add(solver.Sum([x[(i, j)] for i in range(n)]) == s) for j in range(n)]\n", + "\n", + " solver.Add(solver.Sum([x[(i, i)] for i in range(n)]) == s) # diag 1\n", + " solver.Add(solver.Sum([x[(i, n - i - 1)] for i in range(n)]) == s) # diag 2\n", + "\n", + " # symmetry breaking\n", + " # solver.Add(x[(0,0)] == 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x_flat)\n", + " solution.Add(s)\n", + "\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(\n", + " x_flat,\n", + " # solver.INT_VAR_DEFAULT,\n", + " solver.CHOOSE_FIRST_UNBOUND,\n", + " # solver.CHOOSE_MIN_SIZE_LOWEST_MAX,\n", + "\n", + " # solver.ASSIGN_MIN_VALUE\n", + " solver.ASSIGN_CENTER_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"s:\", s.Value())\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(\"%2i\" % x[(i, j)].Value(), end=\" \")\n", + " print()\n", + "\n", " print()\n", + " num_solutions += 1\n", + " if num_solutions > limit:\n", + " break\n", + " solver.EndSearch()\n", "\n", " print()\n", - " num_solutions += 1\n", - " if num_solutions > limit:\n", - " break\n", - "solver.EndSearch()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "n = 4\n", - "limit=100\n" + "limit=100\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " limit = int(sys.argv[2])\n", + "\n", + "main(n, limit)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/magic_square_and_cards.ipynb b/examples/notebook/contrib/magic_square_and_cards.ipynb index 8bfdf7e799..b52852ac4e 100644 --- a/examples/notebook/contrib/magic_square_and_cards.ipynb +++ b/examples/notebook/contrib/magic_square_and_cards.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Magic squares and cards problem in Google CP Solver.\n", "\n", @@ -101,83 +86,97 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"n-queens\")\n", + "def main(n=3):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"n-queens\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "# n = 3\n", + " #\n", + " # data\n", + " #\n", + " # n = 3\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[(i, j)] = solver.IntVar(1, 13, \"x(%i,%i)\" % (i, j))\n", - "x_flat = [x[(i, j)] for i in range(n) for j in range(n)]\n", - "\n", - "s = solver.IntVar(1, 13 * 4, \"s\")\n", - "counts = [solver.IntVar(0, 4, \"counts(%i)\" % i) for i in range(14)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.Distribute(x_flat, list(range(14)), counts))\n", - "\n", - "# the standard magic square constraints (sans all_different)\n", - "[solver.Add(solver.Sum([x[(i, j)] for j in range(n)]) == s) for i in range(n)]\n", - "[solver.Add(solver.Sum([x[(i, j)] for i in range(n)]) == s) for j in range(n)]\n", - "\n", - "solver.Add(solver.Sum([x[(i, i)] for i in range(n)]) == s) # diag 1\n", - "solver.Add(solver.Sum([x[(i, n - i - 1)] for i in range(n)]) == s) # diag 2\n", - "\n", - "# redundant constraint\n", - "solver.Add(solver.Sum(counts) == n * n)\n", - "\n", - "# objective\n", - "objective = solver.Maximize(s, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x_flat)\n", - "solution.Add(s)\n", - "solution.Add(counts)\n", - "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(x_flat, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MAX_VALUE)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"s:\", s.Value())\n", - " print(\"counts:\", [counts[i].Value() for i in range(14)])\n", + " #\n", + " # declare variables\n", + " #\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " print(x[(i, j)].Value(), end=\" \")\n", + " x[(i, j)] = solver.IntVar(1, 13, \"x(%i,%i)\" % (i, j))\n", + " x_flat = [x[(i, j)] for i in range(n) for j in range(n)]\n", + "\n", + " s = solver.IntVar(1, 13 * 4, \"s\")\n", + " counts = [solver.IntVar(0, 4, \"counts(%i)\" % i) for i in range(14)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.Distribute(x_flat, list(range(14)), counts))\n", + "\n", + " # the standard magic square constraints (sans all_different)\n", + " [solver.Add(solver.Sum([x[(i, j)] for j in range(n)]) == s) for i in range(n)]\n", + " [solver.Add(solver.Sum([x[(i, j)] for i in range(n)]) == s) for j in range(n)]\n", + "\n", + " solver.Add(solver.Sum([x[(i, i)] for i in range(n)]) == s) # diag 1\n", + " solver.Add(solver.Sum([x[(i, n - i - 1)] for i in range(n)]) == s) # diag 2\n", + "\n", + " # redundant constraint\n", + " solver.Add(solver.Sum(counts) == n * n)\n", + "\n", + " # objective\n", + " objective = solver.Maximize(s, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x_flat)\n", + " solution.Add(s)\n", + " solution.Add(counts)\n", + "\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(x_flat, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MAX_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"s:\", s.Value())\n", + " print(\"counts:\", [counts[i].Value() for i in range(14)])\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(x[(i, j)].Value(), end=\" \")\n", + " print()\n", + "\n", " print()\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", "\n", " print()\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", - "n = 3\n" + "n = 3\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "main(n)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/magic_square_mip.ipynb b/examples/notebook/contrib/magic_square_mip.ipynb index 9b2dfa7c10..a02fcb4923 100644 --- a/examples/notebook/contrib/magic_square_mip.ipynb +++ b/examples/notebook/contrib/magic_square_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Magic square (integer programming) in Google or-tools.\n", "\n", @@ -115,8 +100,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", @@ -127,135 +120,154 @@ "#\n", "\n", "\n", + "def main(n=3, sol='CBC', use_output_matrix=0):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "print('Solver: ', sol)\n", + " print('Solver: ', sol)\n", "\n", - "# using GLPK\n", - "if sol == 'GLPK':\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", - "else:\n", - " # Using CLP\n", - " solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " # using GLPK\n", + " if sol == 'GLPK':\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", + " else:\n", + " # Using CLP\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "#\n", - "# data\n", - "#\n", - "print('n = ', n)\n", + " #\n", + " # data\n", + " #\n", + " print('n = ', n)\n", "\n", - "# range_n = range(1, n+1)\n", - "range_n = list(range(0, n))\n", + " # range_n = range(1, n+1)\n", + " range_n = list(range(0, n))\n", "\n", - "N = n * n\n", - "range_N = list(range(1, N + 1))\n", + " N = n * n\n", + " range_N = list(range(1, N + 1))\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "# x[i,j,k] = 1 means that cell (i,j) contains integer k\n", - "x = {}\n", - "for i in range_n:\n", + " # x[i,j,k] = 1 means that cell (i,j) contains integer k\n", + " x = {}\n", + " for i in range_n:\n", + " for j in range_n:\n", + " for k in range_N:\n", + " x[i, j, k] = solver.IntVar(0, 1, 'x[%i,%i,%i]' % (i, j, k))\n", + "\n", + " # For output. Much slower....\n", + " if use_output_matrix == 1:\n", + " print('Using an output matrix')\n", + " square = {}\n", + " for i in range_n:\n", + " for j in range_n:\n", + " square[i, j] = solver.IntVar(1, n * n, 'square[%i,%i]' % (i, j))\n", + "\n", + " # the magic sum\n", + " s = solver.IntVar(1, n * n * n, 's')\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # each cell must be assigned exactly one integer\n", + " for i in range_n:\n", + " for j in range_n:\n", + " solver.Add(solver.Sum([x[i, j, k] for k in range_N]) == 1)\n", + "\n", + " # each integer must be assigned exactly to one cell\n", + " for k in range_N:\n", + " solver.Add(solver.Sum([x[i, j, k] for i in range_n for j in range_n]) == 1)\n", + "\n", + " # # the sum in each row must be the magic sum\n", + " for i in range_n:\n", + " solver.Add(\n", + " solver.Sum([k * x[i, j, k] for j in range_n for k in range_N]) == s)\n", + "\n", + " # # the sum in each column must be the magic sum\n", " for j in range_n:\n", - " for k in range_N:\n", - " x[i, j, k] = solver.IntVar(0, 1, 'x[%i,%i,%i]' % (i, j, k))\n", + " solver.Add(\n", + " solver.Sum([k * x[i, j, k] for i in range_n for k in range_N]) == s)\n", "\n", - "# For output. Much slower....\n", - "if use_output_matrix == 1:\n", - " print('Using an output matrix')\n", - " square = {}\n", - " for i in range_n:\n", - " for j in range_n:\n", - " square[i, j] = solver.IntVar(1, n * n, 'square[%i,%i]' % (i, j))\n", - "\n", - "# the magic sum\n", - "s = solver.IntVar(1, n * n * n, 's')\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# each cell must be assigned exactly one integer\n", - "for i in range_n:\n", - " for j in range_n:\n", - " solver.Add(solver.Sum([x[i, j, k] for k in range_N]) == 1)\n", - "\n", - "# each integer must be assigned exactly to one cell\n", - "for k in range_N:\n", - " solver.Add(solver.Sum([x[i, j, k] for i in range_n for j in range_n]) == 1)\n", - "\n", - "# # the sum in each row must be the magic sum\n", - "for i in range_n:\n", + " # # the sum in the diagonal must be the magic sum\n", " solver.Add(\n", - " solver.Sum([k * x[i, j, k] for j in range_n for k in range_N]) == s)\n", + " solver.Sum([k * x[i, i, k] for i in range_n for k in range_N]) == s)\n", "\n", - "# # the sum in each column must be the magic sum\n", - "for j in range_n:\n", - " solver.Add(\n", - " solver.Sum([k * x[i, j, k] for i in range_n for k in range_N]) == s)\n", + " # # the sum in the co-diagonal must be the magic sum\n", + " if range_n[0] == 1:\n", + " # for range_n = 1..n\n", + " solver.Add(\n", + " solver.Sum([k * x[i, n - i + 1, k]\n", + " for i in range_n\n", + " for k in range_N]) == s)\n", + " else:\n", + " # for range_n = 0..n-1\n", + " solver.Add(\n", + " solver.Sum([k * x[i, n - i - 1, k]\n", + " for i in range_n\n", + " for k in range_N]) == s)\n", "\n", - "# # the sum in the diagonal must be the magic sum\n", - "solver.Add(\n", - " solver.Sum([k * x[i, i, k] for i in range_n for k in range_N]) == s)\n", + " # for output\n", + " if use_output_matrix == 1:\n", + " for i in range_n:\n", + " for j in range_n:\n", + " solver.Add(\n", + " square[i, j] == solver.Sum([k * x[i, j, k] for k in range_N]))\n", "\n", - "# # the sum in the co-diagonal must be the magic sum\n", - "if range_n[0] == 1:\n", - " # for range_n = 1..n\n", - " solver.Add(\n", - " solver.Sum([k * x[i, n - i + 1, k]\n", - " for i in range_n\n", - " for k in range_N]) == s)\n", - "else:\n", - " # for range_n = 0..n-1\n", - " solver.Add(\n", - " solver.Sum([k * x[i, n - i - 1, k]\n", - " for i in range_n\n", - " for k in range_N]) == s)\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", "\n", - "# for output\n", - "if use_output_matrix == 1:\n", - " for i in range_n:\n", - " for j in range_n:\n", - " solver.Add(\n", - " square[i, j] == solver.Sum([k * x[i, j, k] for k in range_N]))\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", - "\n", - "print()\n", - "\n", - "print('s: ', int(s.SolutionValue()))\n", - "if use_output_matrix == 1:\n", - " for i in range_n:\n", - " for j in range_n:\n", - " print(int(square[i, j].SolutionValue()), end=' ')\n", - " print()\n", " print()\n", - "else:\n", + "\n", + " print('s: ', int(s.SolutionValue()))\n", + " if use_output_matrix == 1:\n", + " for i in range_n:\n", + " for j in range_n:\n", + " print(int(square[i, j].SolutionValue()), end=' ')\n", + " print()\n", + " print()\n", + " else:\n", + " for i in range_n:\n", + " for j in range_n:\n", + " print(\n", + " sum([int(k * x[i, j, k].SolutionValue()) for k in range_N]),\n", + " ' ',\n", + " end=' ')\n", + " print()\n", + "\n", + " print('\\nx:')\n", " for i in range_n:\n", " for j in range_n:\n", - " print(\n", - " sum([int(k * x[i, j, k].SolutionValue()) for k in range_N]),\n", - " ' ',\n", - " end=' ')\n", - " print()\n", + " for k in range_N:\n", + " print(int(x[i, j, k].SolutionValue()), end=' ')\n", + " print()\n", "\n", - "print('\\nx:')\n", - "for i in range_n:\n", - " for j in range_n:\n", - " for k in range_N:\n", - " print(int(x[i, j, k].SolutionValue()), end=' ')\n", - " print()\n", + " print()\n", + " print('walltime :', solver.WallTime(), 'ms')\n", + " if sol == 'CBC':\n", + " print('iterations:', solver.Iterations())\n", "\n", - "print()\n", - "print('walltime :', solver.WallTime(), 'ms')\n", - "if sol == 'CBC':\n", - " print('iterations:', solver.Iterations())\n", + "\n", + "n = 3\n", + "sol = 'CBC'\n", + "use_output_matrix = 0\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "\n", + "if len(sys.argv) > 2:\n", + " sol = sys.argv[2]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "if len(sys.argv) > 3:\n", + " use_output_matrix = int(sys.argv[3])\n", + "\n", + "main(n, sol, use_output_matrix)\n", "\n" ] } diff --git a/examples/notebook/contrib/map.ipynb b/examples/notebook/contrib/map.ipynb index f6c0750b63..c20e3657f7 100644 --- a/examples/notebook/contrib/map.ipynb +++ b/examples/notebook/contrib/map.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Map coloring problem in Google CP Solver.\n", "\n", @@ -106,72 +91,84 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Map coloring\")\n", + "def main():\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Map coloring\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "Belgium = 0\n", - "Denmark = 1\n", - "France = 2\n", - "Germany = 3\n", - "Netherlands = 4\n", - "Luxembourg = 5\n", + " #\n", + " # data\n", + " #\n", + " Belgium = 0\n", + " Denmark = 1\n", + " France = 2\n", + " Germany = 3\n", + " Netherlands = 4\n", + " Luxembourg = 5\n", "\n", - "n = 6\n", - "max_num_colors = 4\n", + " n = 6\n", + " max_num_colors = 4\n", "\n", - "# declare variables\n", - "color = [solver.IntVar(1, max_num_colors, \"x%i\" % i) for i in range(n)]\n", + " # declare variables\n", + " color = [solver.IntVar(1, max_num_colors, \"x%i\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(color[Belgium] == 1) # Symmetry breaking\n", - "solver.Add(color[France] != color[Belgium])\n", - "solver.Add(color[France] != color[Luxembourg])\n", - "solver.Add(color[France] != color[Germany])\n", - "solver.Add(color[Luxembourg] != color[Germany])\n", - "solver.Add(color[Luxembourg] != color[Belgium])\n", - "solver.Add(color[Belgium] != color[Netherlands])\n", - "solver.Add(color[Belgium] != color[Germany])\n", - "solver.Add(color[Germany] != color[Netherlands])\n", - "solver.Add(color[Germany] != color[Denmark])\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(color[Belgium] == 1) # Symmetry breaking\n", + " solver.Add(color[France] != color[Belgium])\n", + " solver.Add(color[France] != color[Luxembourg])\n", + " solver.Add(color[France] != color[Germany])\n", + " solver.Add(color[Luxembourg] != color[Germany])\n", + " solver.Add(color[Luxembourg] != color[Belgium])\n", + " solver.Add(color[Belgium] != color[Netherlands])\n", + " solver.Add(color[Belgium] != color[Germany])\n", + " solver.Add(color[Germany] != color[Netherlands])\n", + " solver.Add(color[Germany] != color[Denmark])\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([color[i] for i in range(n)])\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([color[i] for i in range(n)])\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "# collector = solver.FirstSolutionCollector(solution)\n", - "# search_log = solver.SearchLog(100, x[0])\n", - "solver.Solve(\n", - " solver.Phase([color[i] for i in range(n)], solver.INT_VAR_SIMPLE,\n", - " solver.ASSIGN_MIN_VALUE), [collector])\n", + " collector = solver.AllSolutionCollector(solution)\n", + " # collector = solver.FirstSolutionCollector(solution)\n", + " # search_log = solver.SearchLog(100, x[0])\n", + " solver.Solve(\n", + " solver.Phase([color[i] for i in range(n)], solver.INT_VAR_SIMPLE,\n", + " solver.ASSIGN_MIN_VALUE), [collector])\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "print(\"num_solutions: \", num_solutions)\n", - "if num_solutions > 0:\n", - " for s in range(num_solutions):\n", - " colorval = [collector.Value(s, color[i]) for i in range(n)]\n", - " print(\"color:\", colorval)\n", + " num_solutions = collector.SolutionCount()\n", + " print(\"num_solutions: \", num_solutions)\n", + " if num_solutions > 0:\n", + " for s in range(num_solutions):\n", + " colorval = [collector.Value(s, color[i]) for i in range(n)]\n", + " print(\"color:\", colorval)\n", "\n", - " print()\n", - " print(\"num_solutions:\", num_solutions)\n", - " print(\"failures:\", solver.Failures())\n", - " print(\"branches:\", solver.Branches())\n", - " print(\"WallTime:\", solver.WallTime())\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "else:\n", - " print(\"No solutions found\")\n", + " else:\n", + " print(\"No solutions found\")\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/marathon2.ipynb b/examples/notebook/contrib/marathon2.ipynb index a37f4dbcb5..1946e366a4 100644 --- a/examples/notebook/contrib/marathon2.ipynb +++ b/examples/notebook/contrib/marathon2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Marathon puzzle in Google CP Solver.\n", "\n", @@ -120,88 +105,100 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Marathon')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Marathon')\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 6\n", + " #\n", + " # data\n", + " #\n", + " n = 6\n", "\n", - "runners_str = [\n", - " 'Dominique', 'Ignace', 'Naren', 'Olivier', 'Philippe', 'Pascal'\n", - "]\n", + " runners_str = [\n", + " 'Dominique', 'Ignace', 'Naren', 'Olivier', 'Philippe', 'Pascal'\n", + " ]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "runners = [solver.IntVar(1, n, 'runners[%i]' % i) for i in range(n)]\n", - "Dominique, Ignace, Naren, Olivier, Philippe, Pascal = runners\n", + " #\n", + " # declare variables\n", + " #\n", + " runners = [solver.IntVar(1, n, 'runners[%i]' % i) for i in range(n)]\n", + " Dominique, Ignace, Naren, Olivier, Philippe, Pascal = runners\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(runners))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(runners))\n", "\n", - "# a: Olivier not last\n", - "solver.Add(Olivier != n)\n", + " # a: Olivier not last\n", + " solver.Add(Olivier != n)\n", "\n", - "# b: Dominique, Pascal and Ignace before Naren and Olivier\n", - "solver.Add(Dominique < Naren)\n", - "solver.Add(Dominique < Olivier)\n", - "solver.Add(Pascal < Naren)\n", - "solver.Add(Pascal < Olivier)\n", - "solver.Add(Ignace < Naren)\n", - "solver.Add(Ignace < Olivier)\n", + " # b: Dominique, Pascal and Ignace before Naren and Olivier\n", + " solver.Add(Dominique < Naren)\n", + " solver.Add(Dominique < Olivier)\n", + " solver.Add(Pascal < Naren)\n", + " solver.Add(Pascal < Olivier)\n", + " solver.Add(Ignace < Naren)\n", + " solver.Add(Ignace < Olivier)\n", "\n", - "# c: Dominique better than third\n", - "solver.Add(Dominique < 3)\n", + " # c: Dominique better than third\n", + " solver.Add(Dominique < 3)\n", "\n", - "# d: Philippe is among the first four\n", - "solver.Add(Philippe <= 4)\n", + " # d: Philippe is among the first four\n", + " solver.Add(Philippe <= 4)\n", "\n", - "# e: Ignace neither second nor third\n", - "solver.Add(Ignace != 2)\n", - "solver.Add(Ignace != 3)\n", + " # e: Ignace neither second nor third\n", + " solver.Add(Ignace != 2)\n", + " solver.Add(Ignace != 3)\n", "\n", - "# f: Pascal three places earlier than Naren\n", - "solver.Add(Pascal + 3 == Naren)\n", + " # f: Pascal three places earlier than Naren\n", + " solver.Add(Pascal + 3 == Naren)\n", "\n", - "# g: Neither Ignace nor Dominique on fourth position\n", - "solver.Add(Ignace != 4)\n", - "solver.Add(Dominique != 4)\n", + " # g: Neither Ignace nor Dominique on fourth position\n", + " solver.Add(Ignace != 4)\n", + " solver.Add(Dominique != 4)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(runners, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.ASSIGN_CENTER_VALUE)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(runners, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.ASSIGN_CENTER_VALUE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " runners_val = [runners[i].Value() for i in range(n)]\n", - " print('runners:', runners_val)\n", - " print('Places:')\n", - " for i in range(1, n + 1):\n", - " for j in range(n):\n", - " if runners_val[j] == i:\n", - " print('%i: %s' % (i, runners_str[j]))\n", - " print()\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " runners_val = [runners[i].Value() for i in range(n)]\n", + " print('runners:', runners_val)\n", + " print('Places:')\n", + " for i in range(1, n + 1):\n", + " for j in range(n):\n", + " if runners_val[j] == i:\n", + " print('%i: %s' % (i, runners_str[j]))\n", + " print()\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/max_flow_taha.ipynb b/examples/notebook/contrib/max_flow_taha.ipynb index 4bb3a6a88d..ec10b80b5b 100644 --- a/examples/notebook/contrib/max_flow_taha.ipynb +++ b/examples/notebook/contrib/max_flow_taha.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Max flow problem in Google CP Solver.\n", "\n", @@ -101,93 +86,105 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Max flow problem, Taha')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Max flow problem, Taha')\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 5\n", - "start = 0\n", - "end = n - 1\n", + " #\n", + " # data\n", + " #\n", + " n = 5\n", + " start = 0\n", + " end = n - 1\n", "\n", - "nodes = list(range(n))\n", + " nodes = list(range(n))\n", "\n", - "# cost matrix\n", - "c = [[0, 20, 30, 10, 0], [0, 0, 40, 0, 30], [0, 0, 0, 10, 20],\n", - " [0, 0, 5, 0, 20], [0, 0, 0, 0, 0]]\n", + " # cost matrix\n", + " c = [[0, 20, 30, 10, 0], [0, 0, 40, 0, 30], [0, 0, 0, 10, 20],\n", + " [0, 0, 5, 0, 20], [0, 0, 0, 0, 0]]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = {}\n", - "for i in nodes:\n", - " for j in nodes:\n", - " x[i, j] = solver.IntVar(0, c[i][j], 'x[%i,%i]' % (i, j))\n", - "\n", - "x_flat = [x[i, j] for i in nodes for j in nodes]\n", - "out_flow = [solver.IntVar(0, 10000, 'out_flow[%i]' % i) for i in nodes]\n", - "in_flow = [solver.IntVar(0, 10000, 'in_flow[%i]' % i) for i in nodes]\n", - "\n", - "total = solver.IntVar(0, 10000, 'z')\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "cost_sum = solver.Sum([x[start, j] for j in nodes if c[start][j] > 0])\n", - "solver.Add(total == cost_sum)\n", - "\n", - "for i in nodes:\n", - " in_flow_sum = solver.Sum([x[j, i] for j in nodes if c[j][i] > 0])\n", - " solver.Add(in_flow[i] == in_flow_sum)\n", - "\n", - " out_flow_sum = solver.Sum([x[i, j] for j in nodes if c[i][j] > 0])\n", - " solver.Add(out_flow[i] == out_flow_sum)\n", - "\n", - "# in_flow == out_flow\n", - "for i in nodes:\n", - " if i != start and i != end:\n", - " solver.Add(out_flow[i] - in_flow[i] == 0)\n", - "\n", - "s1 = [x[i, start] for i in nodes if c[i][start] > 0]\n", - "if len(s1) > 0:\n", - " solver.Add(solver.Sum([x[i, start] for i in nodes if c[i][start] > 0] == 0))\n", - "\n", - "s2 = [x[end, j] for j in nodes if c[end][j] > 0]\n", - "if len(s2) > 0:\n", - " solver.Add(solver.Sum([x[end, j] for j in nodes if c[end][j] > 0]) == 0)\n", - "\n", - "# objective: maximize total cost\n", - "objective = solver.Maximize(total, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.ASSIGN_MAX_VALUE)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('total:', total.Value())\n", - " print('in_flow:', [in_flow[i].Value() for i in nodes])\n", - " print('out_flow:', [out_flow[i].Value() for i in nodes])\n", + " #\n", + " # declare variables\n", + " #\n", + " x = {}\n", " for i in nodes:\n", " for j in nodes:\n", - " print('%2i' % x[i, j].Value(), end=' ')\n", - " print()\n", - " print()\n", + " x[i, j] = solver.IntVar(0, c[i][j], 'x[%i,%i]' % (i, j))\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " x_flat = [x[i, j] for i in nodes for j in nodes]\n", + " out_flow = [solver.IntVar(0, 10000, 'out_flow[%i]' % i) for i in nodes]\n", + " in_flow = [solver.IntVar(0, 10000, 'in_flow[%i]' % i) for i in nodes]\n", + "\n", + " total = solver.IntVar(0, 10000, 'z')\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " cost_sum = solver.Sum([x[start, j] for j in nodes if c[start][j] > 0])\n", + " solver.Add(total == cost_sum)\n", + "\n", + " for i in nodes:\n", + " in_flow_sum = solver.Sum([x[j, i] for j in nodes if c[j][i] > 0])\n", + " solver.Add(in_flow[i] == in_flow_sum)\n", + "\n", + " out_flow_sum = solver.Sum([x[i, j] for j in nodes if c[i][j] > 0])\n", + " solver.Add(out_flow[i] == out_flow_sum)\n", + "\n", + " # in_flow == out_flow\n", + " for i in nodes:\n", + " if i != start and i != end:\n", + " solver.Add(out_flow[i] - in_flow[i] == 0)\n", + "\n", + " s1 = [x[i, start] for i in nodes if c[i][start] > 0]\n", + " if len(s1) > 0:\n", + " solver.Add(solver.Sum([x[i, start] for i in nodes if c[i][start] > 0] == 0))\n", + "\n", + " s2 = [x[end, j] for j in nodes if c[end][j] > 0]\n", + " if len(s2) > 0:\n", + " solver.Add(solver.Sum([x[end, j] for j in nodes if c[end][j] > 0]) == 0)\n", + "\n", + " # objective: maximize total cost\n", + " objective = solver.Maximize(total, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.ASSIGN_MAX_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('total:', total.Value())\n", + " print('in_flow:', [in_flow[i].Value() for i in nodes])\n", + " print('out_flow:', [out_flow[i].Value() for i in nodes])\n", + " for i in nodes:\n", + " for j in nodes:\n", + " print('%2i' % x[i, j].Value(), end=' ')\n", + " print()\n", + " print()\n", + "\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/max_flow_winston1.ipynb b/examples/notebook/contrib/max_flow_winston1.ipynb index 8fc44b8975..a125d72c9d 100644 --- a/examples/notebook/contrib/max_flow_winston1.ipynb +++ b/examples/notebook/contrib/max_flow_winston1.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Max flow problem in Google CP Solver.\n", "\n", @@ -101,111 +86,123 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Max flow problem, Winston')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Max flow problem, Winston')\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 5\n", - "nodes = list(range(n))\n", + " #\n", + " # data\n", + " #\n", + " n = 5\n", + " nodes = list(range(n))\n", "\n", - "# the arcs\n", - "# Note:\n", - "# This is 1-based to be compatible with other\n", - "# implementations.\n", - "arcs1 = [[1, 2], [1, 3], [2, 3], [2, 4], [3, 5], [4, 5], [5, 1]]\n", + " # the arcs\n", + " # Note:\n", + " # This is 1-based to be compatible with other\n", + " # implementations.\n", + " arcs1 = [[1, 2], [1, 3], [2, 3], [2, 4], [3, 5], [4, 5], [5, 1]]\n", "\n", - "# convert arcs to 0-based\n", - "arcs = []\n", - "for (a_from, a_to) in arcs1:\n", - " a_from -= 1\n", - " a_to -= 1\n", - " arcs.append([a_from, a_to])\n", + " # convert arcs to 0-based\n", + " arcs = []\n", + " for (a_from, a_to) in arcs1:\n", + " a_from -= 1\n", + " a_to -= 1\n", + " arcs.append([a_from, a_to])\n", "\n", - "num_arcs = len(arcs)\n", + " num_arcs = len(arcs)\n", "\n", - "# capacities\n", - "cap = [2, 3, 3, 4, 2, 1, 100]\n", + " # capacities\n", + " cap = [2, 3, 3, 4, 2, 1, 100]\n", "\n", - "# convert arcs to matrix\n", - "# for sanity checking below\n", - "mat = {}\n", - "for i in nodes:\n", - " for j in nodes:\n", - " c = 0\n", - " for k in range(num_arcs):\n", - " if arcs[k][0] == i and arcs[k][1] == j:\n", - " c = 1\n", - " mat[i, j] = c\n", - "\n", - "#\n", - "# declare variables\n", - "#\n", - "flow = {}\n", - "for i in nodes:\n", - " for j in nodes:\n", - " flow[i, j] = solver.IntVar(0, 200, 'flow %i %i' % (i, j))\n", - "\n", - "flow_flat = [flow[i, j] for i in nodes for j in nodes]\n", - "\n", - "z = solver.IntVar(0, 10000, 'z')\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(z == flow[n - 1, 0])\n", - "\n", - "# capacity of arcs\n", - "for i in range(num_arcs):\n", - " solver.Add(flow[arcs[i][0], arcs[i][1]] <= cap[i])\n", - "\n", - "# inflows == outflows\n", - "for i in nodes:\n", - " s1 = solver.Sum([\n", - " flow[arcs[k][0], arcs[k][1]] for k in range(num_arcs) if arcs[k][1] == i\n", - " ])\n", - " s2 = solver.Sum([\n", - " flow[arcs[k][0], arcs[k][1]] for k in range(num_arcs) if arcs[k][0] == i\n", - " ])\n", - " solver.Add(s1 == s2)\n", - "\n", - "# sanity: just arcs with connections can have a flow\n", - "for i in nodes:\n", - " for j in nodes:\n", - " if mat[i, j] == 0:\n", - " solver.Add(flow[i, j] == 0)\n", - "\n", - "# objective: maximize z\n", - "objective = solver.Maximize(z, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(flow_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('z:', z.Value())\n", + " # convert arcs to matrix\n", + " # for sanity checking below\n", + " mat = {}\n", " for i in nodes:\n", " for j in nodes:\n", - " print(flow[i, j].Value(), end=' ')\n", - " print()\n", - " print()\n", + " c = 0\n", + " for k in range(num_arcs):\n", + " if arcs[k][0] == i and arcs[k][1] == j:\n", + " c = 1\n", + " mat[i, j] = c\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " #\n", + " # declare variables\n", + " #\n", + " flow = {}\n", + " for i in nodes:\n", + " for j in nodes:\n", + " flow[i, j] = solver.IntVar(0, 200, 'flow %i %i' % (i, j))\n", + "\n", + " flow_flat = [flow[i, j] for i in nodes for j in nodes]\n", + "\n", + " z = solver.IntVar(0, 10000, 'z')\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(z == flow[n - 1, 0])\n", + "\n", + " # capacity of arcs\n", + " for i in range(num_arcs):\n", + " solver.Add(flow[arcs[i][0], arcs[i][1]] <= cap[i])\n", + "\n", + " # inflows == outflows\n", + " for i in nodes:\n", + " s1 = solver.Sum([\n", + " flow[arcs[k][0], arcs[k][1]] for k in range(num_arcs) if arcs[k][1] == i\n", + " ])\n", + " s2 = solver.Sum([\n", + " flow[arcs[k][0], arcs[k][1]] for k in range(num_arcs) if arcs[k][0] == i\n", + " ])\n", + " solver.Add(s1 == s2)\n", + "\n", + " # sanity: just arcs with connections can have a flow\n", + " for i in nodes:\n", + " for j in nodes:\n", + " if mat[i, j] == 0:\n", + " solver.Add(flow[i, j] == 0)\n", + "\n", + " # objective: maximize z\n", + " objective = solver.Maximize(z, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(flow_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('z:', z.Value())\n", + " for i in nodes:\n", + " for j in nodes:\n", + " print(flow[i, j].Value(), end=' ')\n", + " print()\n", + " print()\n", + "\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/minesweeper.ipynb b/examples/notebook/contrib/minesweeper.ipynb index c17d676425..71e44fd03e 100644 --- a/examples/notebook/contrib/minesweeper.ipynb +++ b/examples/notebook/contrib/minesweeper.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Minesweeper in Google CP Solver.\n", "\n", @@ -136,8 +121,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -150,115 +143,117 @@ " [0, 1, X, 4, X, X, X, 3], [0, 1, 2, X, 2, 3, X, 2]]\n", "\n", "\n", + "def main(game=\"\", r=\"\", c=\"\"):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Minesweeper\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Minesweeper\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# Set default problem\n", - "if game == \"\":\n", - " game = default_game\n", - " r = default_r\n", - " c = default_c\n", - "else:\n", - " print(\"rows:\", r, \" cols:\", c)\n", + " # Set default problem\n", + " if game == \"\":\n", + " game = default_game\n", + " r = default_r\n", + " c = default_c\n", + " else:\n", + " print(\"rows:\", r, \" cols:\", c)\n", "\n", - "#\n", - "# Default problem from \"Some Minesweeper Configurations\",page 3\n", - "# (same as problem instance minesweeper_config3.txt)\n", - "# It has 4 solutions\n", - "#\n", - "# r = 8\n", - "# c = 8\n", - "# X = -1\n", - "# game = [\n", - "# [2,3,X,2,2,X,2,1],\n", - "# [X,X,4,X,X,4,X,2],\n", - "# [X,X,X,X,X,X,4,X],\n", - "# [X,5,X,6,X,X,X,2],\n", - "# [2,X,X,X,5,5,X,2],\n", - "# [1,3,4,X,X,X,4,X],\n", - "# [0,1,X,4,X,X,X,3],\n", - "# [0,1,2,X,2,3,X,2]\n", - "# ]\n", + " #\n", + " # Default problem from \"Some Minesweeper Configurations\",page 3\n", + " # (same as problem instance minesweeper_config3.txt)\n", + " # It has 4 solutions\n", + " #\n", + " # r = 8\n", + " # c = 8\n", + " # X = -1\n", + " # game = [\n", + " # [2,3,X,2,2,X,2,1],\n", + " # [X,X,4,X,X,4,X,2],\n", + " # [X,X,X,X,X,X,4,X],\n", + " # [X,5,X,6,X,X,X,2],\n", + " # [2,X,X,X,5,5,X,2],\n", + " # [1,3,4,X,X,X,4,X],\n", + " # [0,1,X,4,X,X,X,3],\n", + " # [0,1,2,X,2,3,X,2]\n", + " # ]\n", "\n", - "S = [-1, 0, 1] # for the neighbors of \"this\" cell\n", + " S = [-1, 0, 1] # for the neighbors of \"this\" cell\n", "\n", - "# print problem instance\n", - "print(\"Problem:\")\n", - "for i in range(r):\n", - " for j in range(c):\n", - " if game[i][j] == X:\n", - " print(\"X\", end=\" \")\n", - " else:\n", - " print(game[i][j], end=\" \")\n", - " print()\n", - "print()\n", - "\n", - "# declare variables\n", - "mines = {}\n", - "for i in range(r):\n", - " for j in range(c):\n", - " mines[(i, j)] = solver.IntVar(0, 1, \"mines %i %i\" % (i, j))\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(r):\n", - " for j in range(c):\n", - " if game[i][j] >= 0:\n", - " solver.Add(mines[i, j] == 0)\n", - " # this cell is the sum of all the surrounding cells\n", - " solver.Add(game[i][j] == solver.Sum([\n", - " mines[i + a, j + b]\n", - " for a in S\n", - " for b in S\n", - " if i + a >= 0 and j + b >= 0 and i + a < r and j + b < c\n", - " ]))\n", - " if game[i][j] > X:\n", - " # This cell cannot be a mine\n", - " solver.Add(mines[i, j] == 0)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([mines[(i, j)] for i in range(r) for j in range(c)])\n", - "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase([mines[(i, j)] for i in range(r) for j in range(c)],\n", - " solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE), [collector])\n", - "\n", - "num_solutions = collector.SolutionCount()\n", - "print(\"num_solutions: \", num_solutions)\n", - "if num_solutions > 0:\n", - " for s in range(num_solutions):\n", - " minesval = [\n", - " collector.Value(s, mines[(i, j)]) for i in range(r) for j in range(c)\n", - " ]\n", - " for i in range(r):\n", - " for j in range(c):\n", - " print(minesval[i * c + j], end=\" \")\n", - " print()\n", + " # print problem instance\n", + " print(\"Problem:\")\n", + " for i in range(r):\n", + " for j in range(c):\n", + " if game[i][j] == X:\n", + " print(\"X\", end=\" \")\n", + " else:\n", + " print(game[i][j], end=\" \")\n", " print()\n", - "\n", " print()\n", - " print(\"num_solutions:\", num_solutions)\n", - " print(\"failures:\", solver.Failures())\n", - " print(\"branches:\", solver.Branches())\n", - " print(\"WallTime:\", solver.WallTime())\n", "\n", - "else:\n", - " print(\"No solutions found\")\n", + " # declare variables\n", + " mines = {}\n", + " for i in range(r):\n", + " for j in range(c):\n", + " mines[(i, j)] = solver.IntVar(0, 1, \"mines %i %i\" % (i, j))\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " for i in range(r):\n", + " for j in range(c):\n", + " if game[i][j] >= 0:\n", + " solver.Add(mines[i, j] == 0)\n", + " # this cell is the sum of all the surrounding cells\n", + " solver.Add(game[i][j] == solver.Sum([\n", + " mines[i + a, j + b]\n", + " for a in S\n", + " for b in S\n", + " if i + a >= 0 and j + b >= 0 and i + a < r and j + b < c\n", + " ]))\n", + " if game[i][j] > X:\n", + " # This cell cannot be a mine\n", + " solver.Add(mines[i, j] == 0)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([mines[(i, j)] for i in range(r) for j in range(c)])\n", + "\n", + " collector = solver.AllSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase([mines[(i, j)] for i in range(r) for j in range(c)],\n", + " solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE), [collector])\n", + "\n", + " num_solutions = collector.SolutionCount()\n", + " print(\"num_solutions: \", num_solutions)\n", + " if num_solutions > 0:\n", + " for s in range(num_solutions):\n", + " minesval = [\n", + " collector.Value(s, mines[(i, j)]) for i in range(r) for j in range(c)\n", + " ]\n", + " for i in range(r):\n", + " for j in range(c):\n", + " print(minesval[i * c + j], end=\" \")\n", + " print()\n", + " print()\n", + "\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + " else:\n", + " print(\"No solutions found\")\n", "\n", "\n", "#\n", "# Read a problem instance from a file\n", - "#def read_problem(file):\n", + "#\n", + "def read_problem(file):\n", " f = open(file, \"r\")\n", " rows = int(f.readline())\n", " cols = int(f.readline())\n", @@ -292,6 +287,15 @@ " print(game[i][j], end=\" \")\n", " print(\"\")\n", "\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " print(\"Problem instance from\", file)\n", + " [game, rows, cols] = read_problem(file)\n", + " # print_game(game, rows, cols)\n", + " main(game, rows, cols)\n", + "else:\n", + " main()\n", "\n" ] } diff --git a/examples/notebook/contrib/mr_smith.ipynb b/examples/notebook/contrib/mr_smith.ipynb index fdfa62b6d0..57181af7ff 100644 --- a/examples/notebook/contrib/mr_smith.ipynb +++ b/examples/notebook/contrib/mr_smith.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Mr Smith in Google CP Solver.\n", "\n", @@ -120,74 +105,86 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Mr Smith problem')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Mr Smith problem')\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 5\n", + " #\n", + " # data\n", + " #\n", + " n = 5\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(0, 1, 'x[%i]' % i) for i in range(n)]\n", - "Mr_Smith, Mrs_Smith, Matt, John, Tim = x\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(0, 1, 'x[%i]' % i) for i in range(n)]\n", + " Mr_Smith, Mrs_Smith, Matt, John, Tim = x\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "#\n", - "# I've kept the MiniZinc constraints for clarity\n", - "# and debugging.\n", - "#\n", + " #\n", + " # I've kept the MiniZinc constraints for clarity\n", + " # and debugging.\n", + " #\n", "\n", - "# If Mr Smith comes then his wife will come too.\n", - "# (Mr_Smith -> Mrs_Smith)\n", - "solver.Add(Mr_Smith - Mrs_Smith <= 0)\n", + " # If Mr Smith comes then his wife will come too.\n", + " # (Mr_Smith -> Mrs_Smith)\n", + " solver.Add(Mr_Smith - Mrs_Smith <= 0)\n", "\n", - "# At least one of their two sons Matt and John will come.\n", - "# (Matt \\/ John)\n", - "solver.Add(Matt + John >= 1)\n", + " # At least one of their two sons Matt and John will come.\n", + " # (Matt \\/ John)\n", + " solver.Add(Matt + John >= 1)\n", "\n", - "# Either Mrs Smith or Tim will come but not both.\n", - "# bool2int(Mrs_Smith) + bool2int(Tim) = 1 /\\\n", - "# (Mrs_Smith xor Tim)\n", - "solver.Add(Mrs_Smith + Tim == 1)\n", + " # Either Mrs Smith or Tim will come but not both.\n", + " # bool2int(Mrs_Smith) + bool2int(Tim) = 1 /\\\n", + " # (Mrs_Smith xor Tim)\n", + " solver.Add(Mrs_Smith + Tim == 1)\n", "\n", - "# Either Tim and John will come or neither will come.\n", - "# (Tim = John)\n", - "solver.Add(Tim == John)\n", + " # Either Tim and John will come or neither will come.\n", + " # (Tim = John)\n", + " solver.Add(Tim == John)\n", "\n", - "# If Matt comes /\\ then John and his father will also come.\n", - "# (Matt -> (John /\\ Mr_Smith))\n", - "solver.Add(Matt - (John * Mr_Smith) <= 0)\n", + " # If Matt comes /\\ then John and his father will also come.\n", + " # (Matt -> (John /\\ Mr_Smith))\n", + " solver.Add(Matt - (John * Mr_Smith) <= 0)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('x:', [x[i].Value() for i in range(n)])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('x:', [x[i].Value() for i in range(n)])\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/nonogram_default_search.ipynb b/examples/notebook/contrib/nonogram_default_search.ipynb index d276045155..3577069cfd 100644 --- a/examples/notebook/contrib/nonogram_default_search.ipynb +++ b/examples/notebook/contrib/nonogram_default_search.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com, lperron@google.com\n", - "#\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", + "\n", "\n", " Nonogram (Painting by numbers) in Google CP Solver.\n", "\n", @@ -113,8 +98,16 @@ " Brunetti, Sara & Daurat, Alain (2003)\n", " 'An algorithm reconstructing convex lattice sets'\n", " http://geodisi.u-strasbg.fr/~daurat/papiers/tomoqconv.pdf\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -175,81 +168,82 @@ " accepting_states))\n", "\n", "\n", + "def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Nonogram')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Nonogram')\n", "\n", - "#\n", - "# variables\n", - "#\n", - "board = {}\n", - "for i in range(rows):\n", - " for j in range(cols):\n", - " board[i, j] = solver.IntVar(0, 1, 'board[%i, %i]' % (i, j))\n", - "\n", - "board_flat = [board[i, j] for i in range(rows) for j in range(cols)]\n", - "\n", - "# Flattened board for labeling.\n", - "# This labeling was inspired by a suggestion from\n", - "# Pascal Van Hentenryck about my (hakank's) Comet\n", - "# nonogram model.\n", - "board_label = []\n", - "if rows * row_rule_len < cols * col_rule_len:\n", + " #\n", + " # variables\n", + " #\n", + " board = {}\n", " for i in range(rows):\n", " for j in range(cols):\n", - " board_label.append(board[i, j])\n", - "else:\n", - " for j in range(cols):\n", + " board[i, j] = solver.IntVar(0, 1, 'board[%i, %i]' % (i, j))\n", + "\n", + " board_flat = [board[i, j] for i in range(rows) for j in range(cols)]\n", + "\n", + " # Flattened board for labeling.\n", + " # This labeling was inspired by a suggestion from\n", + " # Pascal Van Hentenryck about my (hakank's) Comet\n", + " # nonogram model.\n", + " board_label = []\n", + " if rows * row_rule_len < cols * col_rule_len:\n", " for i in range(rows):\n", - " board_label.append(board[i, j])\n", + " for j in range(cols):\n", + " board_label.append(board[i, j])\n", + " else:\n", + " for j in range(cols):\n", + " for i in range(rows):\n", + " board_label.append(board[i, j])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(rows):\n", - " check_rule(row_rules[i], [board[i, j] for j in range(cols)])\n", - "\n", - "for j in range(cols):\n", - " check_rule(col_rules[j], [board[i, j] for i in range(rows)])\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "parameters = pywrapcp.DefaultPhaseParameters()\n", - "parameters.heuristic_period = 200000\n", - "\n", - "db = solver.DefaultPhase(board_label, parameters)\n", - "\n", - "print('before solver, wall time = ', solver.WallTime(), 'ms')\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print()\n", - " num_solutions += 1\n", + " #\n", + " # constraints\n", + " #\n", " for i in range(rows):\n", - " row = [board[i, j].Value() for j in range(cols)]\n", - " row_pres = []\n", - " for j in row:\n", - " if j == 1:\n", - " row_pres.append('#')\n", - " else:\n", - " row_pres.append(' ')\n", - " print(' ', ''.join(row_pres))\n", + " check_rule(row_rules[i], [board[i, j] for j in range(cols)])\n", "\n", + " for j in range(cols):\n", + " check_rule(col_rules[j], [board[i, j] for i in range(rows)])\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " parameters = pywrapcp.DefaultPhaseParameters()\n", + " parameters.heuristic_period = 200000\n", + "\n", + " db = solver.DefaultPhase(board_label, parameters)\n", + "\n", + " print('before solver, wall time = ', solver.WallTime(), 'ms')\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print()\n", + " num_solutions += 1\n", + " for i in range(rows):\n", + " row = [board[i, j].Value() for j in range(cols)]\n", + " row_pres = []\n", + " for j in row:\n", + " if j == 1:\n", + " row_pres.append('#')\n", + " else:\n", + " row_pres.append(' ')\n", + " print(' ', ''.join(row_pres))\n", + "\n", + " print()\n", + " print(' ', '-' * cols)\n", + "\n", + " if num_solutions >= 2:\n", + " print('2 solutions is enough...')\n", + " break\n", + "\n", + " solver.EndSearch()\n", " print()\n", - " print(' ', '-' * cols)\n", - "\n", - " if num_solutions >= 2:\n", - " print('2 solutions is enough...')\n", - " break\n", - "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", "\n", "#\n", @@ -257,7 +251,8 @@ "#\n", "# From http://twan.home.fmf.nl/blog/haskell/Nonograms.details\n", "# The lambda picture\n", - "#rows = 12\n", + "#\n", + "rows = 12\n", "row_rule_len = 3\n", "row_rules = [[0, 0, 2], [0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 3],\n", " [0, 0, 3], [0, 2, 2], [0, 2, 1], [2, 2, 1], [0, 2, 3], [0, 2, 2]]\n", @@ -266,6 +261,11 @@ "col_rule_len = 2\n", "col_rules = [[2, 1], [1, 3], [2, 4], [3, 4], [0, 4], [0, 3], [0, 3], [0, 3],\n", " [0, 2], [0, 2]]\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " exec(compile(open(file).read(), file, 'exec'))\n", + "main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules)\n", "\n" ] } diff --git a/examples/notebook/contrib/nonogram_regular.ipynb b/examples/notebook/contrib/nonogram_regular.ipynb index d1343f7b87..28c44be4ed 100644 --- a/examples/notebook/contrib/nonogram_regular.ipynb +++ b/examples/notebook/contrib/nonogram_regular.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Nonogram (Painting by numbers) in Google CP Solver.\n", "\n", @@ -139,8 +124,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -300,82 +293,83 @@ " accepting_states)\n", "\n", "\n", + "def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Regular test')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Regular test')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "#\n", - "# variables\n", - "#\n", - "board = {}\n", - "for i in range(rows):\n", - " for j in range(cols):\n", - " board[i, j] = solver.IntVar(1, 2, 'board[%i,%i]' % (i, j))\n", - "board_flat = [board[i, j] for i in range(rows) for j in range(cols)]\n", - "\n", - "# Flattened board for labeling.\n", - "# This labeling was inspired by a suggestion from\n", - "# Pascal Van Hentenryck about my Comet nonogram model.\n", - "board_label = []\n", - "if rows * row_rule_len < cols * col_rule_len:\n", + " #\n", + " # variables\n", + " #\n", + " board = {}\n", " for i in range(rows):\n", " for j in range(cols):\n", - " board_label.append(board[i, j])\n", - "else:\n", - " for j in range(cols):\n", + " board[i, j] = solver.IntVar(1, 2, 'board[%i,%i]' % (i, j))\n", + " board_flat = [board[i, j] for i in range(rows) for j in range(cols)]\n", + "\n", + " # Flattened board for labeling.\n", + " # This labeling was inspired by a suggestion from\n", + " # Pascal Van Hentenryck about my Comet nonogram model.\n", + " board_label = []\n", + " if rows * row_rule_len < cols * col_rule_len:\n", " for i in range(rows):\n", - " board_label.append(board[i, j])\n", + " for j in range(cols):\n", + " board_label.append(board[i, j])\n", + " else:\n", + " for j in range(cols):\n", + " for i in range(rows):\n", + " board_label.append(board[i, j])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(rows):\n", - " check_rule([row_rules[i][j] for j in range(row_rule_len)],\n", - " [board[i, j] for j in range(cols)])\n", - "\n", - "for j in range(cols):\n", - " check_rule([col_rules[j][k] for k in range(col_rule_len)],\n", - " [board[i, j] for i in range(rows)])\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print()\n", - " num_solutions += 1\n", + " #\n", + " # constraints\n", + " #\n", " for i in range(rows):\n", - " row = [board[i, j].Value() - 1 for j in range(cols)]\n", - " row_pres = []\n", - " for j in row:\n", - " if j == 1:\n", - " row_pres.append('#')\n", - " else:\n", - " row_pres.append(' ')\n", - " print(' ', ''.join(row_pres))\n", + " check_rule([row_rules[i][j] for j in range(row_rule_len)],\n", + " [board[i, j] for j in range(cols)])\n", "\n", + " for j in range(cols):\n", + " check_rule([col_rules[j][k] for k in range(col_rule_len)],\n", + " [board[i, j] for i in range(rows)])\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print()\n", + " num_solutions += 1\n", + " for i in range(rows):\n", + " row = [board[i, j].Value() - 1 for j in range(cols)]\n", + " row_pres = []\n", + " for j in row:\n", + " if j == 1:\n", + " row_pres.append('#')\n", + " else:\n", + " row_pres.append(' ')\n", + " print(' ', ''.join(row_pres))\n", + "\n", + " print()\n", + " print(' ', '-' * cols)\n", + "\n", + " if num_solutions >= 2:\n", + " print('2 solutions is enough...')\n", + " break\n", + "\n", + " solver.EndSearch()\n", " print()\n", - " print(' ', '-' * cols)\n", - "\n", - " if num_solutions >= 2:\n", - " print('2 solutions is enough...')\n", - " break\n", - "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", "\n", "#\n", @@ -383,7 +377,8 @@ "#\n", "# From http://twan.home.fmf.nl/blog/haskell/Nonograms.details\n", "# The lambda picture\n", - "#rows = 12\n", + "#\n", + "rows = 12\n", "row_rule_len = 3\n", "row_rules = [[0, 0, 2], [0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 3],\n", " [0, 0, 3], [0, 2, 2], [0, 2, 1], [2, 2, 1], [0, 2, 3], [0, 2, 2]]\n", @@ -392,6 +387,11 @@ "col_rule_len = 2\n", "col_rules = [[2, 1], [1, 3], [2, 4], [3, 4], [0, 4], [0, 3], [0, 3], [0, 3],\n", " [0, 2], [0, 2]]\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " exec(compile(open(file).read(), file, 'exec'))\n", + "main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules)\n", "\n" ] } diff --git a/examples/notebook/contrib/nonogram_table.ipynb b/examples/notebook/contrib/nonogram_table.ipynb index 980f14fdcf..01e08fe2fd 100644 --- a/examples/notebook/contrib/nonogram_table.ipynb +++ b/examples/notebook/contrib/nonogram_table.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Nonogram (Painting by numbers) in Google CP Solver.\n", "\n", @@ -139,8 +124,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -296,82 +289,83 @@ " accepting_states)\n", "\n", "\n", + "def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Regular test')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Regular test')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "#\n", - "# variables\n", - "#\n", - "board = {}\n", - "for i in range(rows):\n", - " for j in range(cols):\n", - " board[i, j] = solver.IntVar(1, 2, 'board[%i, %i]' % (i, j))\n", - "board_flat = [board[i, j] for i in range(rows) for j in range(cols)]\n", - "\n", - "# Flattened board for labeling.\n", - "# This labeling was inspired by a suggestion from\n", - "# Pascal Van Hentenryck about my Comet nonogram model.\n", - "board_label = []\n", - "if rows * row_rule_len < cols * col_rule_len:\n", + " #\n", + " # variables\n", + " #\n", + " board = {}\n", " for i in range(rows):\n", " for j in range(cols):\n", - " board_label.append(board[i, j])\n", - "else:\n", - " for j in range(cols):\n", + " board[i, j] = solver.IntVar(1, 2, 'board[%i, %i]' % (i, j))\n", + " board_flat = [board[i, j] for i in range(rows) for j in range(cols)]\n", + "\n", + " # Flattened board for labeling.\n", + " # This labeling was inspired by a suggestion from\n", + " # Pascal Van Hentenryck about my Comet nonogram model.\n", + " board_label = []\n", + " if rows * row_rule_len < cols * col_rule_len:\n", " for i in range(rows):\n", - " board_label.append(board[i, j])\n", + " for j in range(cols):\n", + " board_label.append(board[i, j])\n", + " else:\n", + " for j in range(cols):\n", + " for i in range(rows):\n", + " board_label.append(board[i, j])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(rows):\n", - " check_rule([row_rules[i][j] for j in range(row_rule_len)],\n", - " [board[i, j] for j in range(cols)])\n", - "\n", - "for j in range(cols):\n", - " check_rule([col_rules[j][k] for k in range(col_rule_len)],\n", - " [board[i, j] for i in range(rows)])\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print()\n", - " num_solutions += 1\n", + " #\n", + " # constraints\n", + " #\n", " for i in range(rows):\n", - " row = [board[i, j].Value() - 1 for j in range(cols)]\n", - " row_pres = []\n", - " for j in row:\n", - " if j == 1:\n", - " row_pres.append('#')\n", - " else:\n", - " row_pres.append(' ')\n", - " print(' ', ''.join(row_pres))\n", + " check_rule([row_rules[i][j] for j in range(row_rule_len)],\n", + " [board[i, j] for j in range(cols)])\n", "\n", + " for j in range(cols):\n", + " check_rule([col_rules[j][k] for k in range(col_rule_len)],\n", + " [board[i, j] for i in range(rows)])\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print()\n", + " num_solutions += 1\n", + " for i in range(rows):\n", + " row = [board[i, j].Value() - 1 for j in range(cols)]\n", + " row_pres = []\n", + " for j in row:\n", + " if j == 1:\n", + " row_pres.append('#')\n", + " else:\n", + " row_pres.append(' ')\n", + " print(' ', ''.join(row_pres))\n", + "\n", + " print()\n", + " print(' ', '-' * cols)\n", + "\n", + " if num_solutions >= 2:\n", + " print('2 solutions is enough...')\n", + " break\n", + "\n", + " solver.EndSearch()\n", " print()\n", - " print(' ', '-' * cols)\n", - "\n", - " if num_solutions >= 2:\n", - " print('2 solutions is enough...')\n", - " break\n", - "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", "\n", "#\n", @@ -379,7 +373,8 @@ "#\n", "# From http://twan.home.fmf.nl/blog/haskell/Nonograms.details\n", "# The lambda picture\n", - "#rows = 12\n", + "#\n", + "rows = 12\n", "row_rule_len = 3\n", "row_rules = [[0, 0, 2], [0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 3],\n", " [0, 0, 3], [0, 2, 2], [0, 2, 1], [2, 2, 1], [0, 2, 3], [0, 2, 2]]\n", @@ -388,6 +383,11 @@ "col_rule_len = 2\n", "col_rules = [[2, 1], [1, 3], [2, 4], [3, 4], [0, 4], [0, 3], [0, 3], [0, 3],\n", " [0, 2], [0, 2]]\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " exec(compile(open(file).read(), file, 'exec'))\n", + "main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules)\n", "\n" ] } diff --git a/examples/notebook/contrib/nonogram_table2.ipynb b/examples/notebook/contrib/nonogram_table2.ipynb index 90a04becef..4b19c14d53 100644 --- a/examples/notebook/contrib/nonogram_table2.ipynb +++ b/examples/notebook/contrib/nonogram_table2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Nonogram (Painting by numbers) in Google CP Solver.\n", "\n", @@ -139,8 +124,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -201,77 +194,78 @@ " accepting_states))\n", "\n", "\n", + "def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Regular test')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Regular test')\n", "\n", - "#\n", - "# variables\n", - "#\n", - "board = {}\n", - "for i in range(rows):\n", - " for j in range(cols):\n", - " board[i, j] = solver.IntVar(0, 1, 'board[%i, %i]' % (i, j))\n", - "board_flat = [board[i, j] for i in range(rows) for j in range(cols)]\n", - "\n", - "# Flattened board for labeling.\n", - "# This labeling was inspired by a suggestion from\n", - "# Pascal Van Hentenryck about my Comet nonogram model.\n", - "board_label = []\n", - "if rows * row_rule_len < cols * col_rule_len:\n", + " #\n", + " # variables\n", + " #\n", + " board = {}\n", " for i in range(rows):\n", " for j in range(cols):\n", - " board_label.append(board[i, j])\n", - "else:\n", - " for j in range(cols):\n", + " board[i, j] = solver.IntVar(0, 1, 'board[%i, %i]' % (i, j))\n", + " board_flat = [board[i, j] for i in range(rows) for j in range(cols)]\n", + "\n", + " # Flattened board for labeling.\n", + " # This labeling was inspired by a suggestion from\n", + " # Pascal Van Hentenryck about my Comet nonogram model.\n", + " board_label = []\n", + " if rows * row_rule_len < cols * col_rule_len:\n", " for i in range(rows):\n", - " board_label.append(board[i, j])\n", + " for j in range(cols):\n", + " board_label.append(board[i, j])\n", + " else:\n", + " for j in range(cols):\n", + " for i in range(rows):\n", + " board_label.append(board[i, j])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(rows):\n", - " check_rule(row_rules[i], [board[i, j] for j in range(cols)])\n", - "\n", - "for j in range(cols):\n", - " check_rule(col_rules[j], [board[i, j] for i in range(rows)])\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "print('before solver, wall time = ', solver.WallTime(), 'ms')\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print()\n", - " num_solutions += 1\n", + " #\n", + " # constraints\n", + " #\n", " for i in range(rows):\n", - " row = [board[i, j].Value() for j in range(cols)]\n", - " row_pres = []\n", - " for j in row:\n", - " if j == 1:\n", - " row_pres.append('#')\n", - " else:\n", - " row_pres.append(' ')\n", - " print(' ', ''.join(row_pres))\n", + " check_rule(row_rules[i], [board[i, j] for j in range(cols)])\n", "\n", + " for j in range(cols):\n", + " check_rule(col_rules[j], [board[i, j] for i in range(rows)])\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " print('before solver, wall time = ', solver.WallTime(), 'ms')\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print()\n", + " num_solutions += 1\n", + " for i in range(rows):\n", + " row = [board[i, j].Value() for j in range(cols)]\n", + " row_pres = []\n", + " for j in row:\n", + " if j == 1:\n", + " row_pres.append('#')\n", + " else:\n", + " row_pres.append(' ')\n", + " print(' ', ''.join(row_pres))\n", + "\n", + " print()\n", + " print(' ', '-' * cols)\n", + "\n", + " if num_solutions >= 2:\n", + " print('2 solutions is enough...')\n", + " break\n", + "\n", + " solver.EndSearch()\n", " print()\n", - " print(' ', '-' * cols)\n", - "\n", - " if num_solutions >= 2:\n", - " print('2 solutions is enough...')\n", - " break\n", - "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", "\n", "#\n", @@ -279,7 +273,8 @@ "#\n", "# From http://twan.home.fmf.nl/blog/haskell/Nonograms.details\n", "# The lambda picture\n", - "#rows = 12\n", + "#\n", + "rows = 12\n", "row_rule_len = 3\n", "row_rules = [[0, 0, 2], [0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 3],\n", " [0, 0, 3], [0, 2, 2], [0, 2, 1], [2, 2, 1], [0, 2, 3], [0, 2, 2]]\n", @@ -288,6 +283,11 @@ "col_rule_len = 2\n", "col_rules = [[2, 1], [1, 3], [2, 4], [3, 4], [0, 4], [0, 3], [0, 3], [0, 3],\n", " [0, 2], [0, 2]]\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " exec(compile(open(file).read(), file, 'exec'))\n", + "main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules)\n", "\n" ] } diff --git a/examples/notebook/contrib/nontransitive_dice.ipynb b/examples/notebook/contrib/nontransitive_dice.ipynb index 137582ea1e..d0a359db22 100644 --- a/examples/notebook/contrib/nontransitive_dice.ipynb +++ b/examples/notebook/contrib/nontransitive_dice.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Nontransitive dice in Google CP Solver.\n", "\n", @@ -140,141 +125,160 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(m=3, n=6, minimize_val=0):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Nontransitive dice\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Nontransitive dice\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"number of dice:\", m)\n", - "print(\"number of sides:\", n)\n", + " #\n", + " # data\n", + " #\n", + " print(\"number of dice:\", m)\n", + " print(\"number of sides:\", n)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", + " #\n", + " # declare variables\n", + " #\n", "\n", - "dice = {}\n", - "for i in range(m):\n", - " for j in range(n):\n", - " dice[(i, j)] = solver.IntVar(1, n * 2, \"dice(%i,%i)\" % (i, j))\n", - "dice_flat = [dice[(i, j)] for i in range(m) for j in range(n)]\n", - "\n", - "comp = {}\n", - "for i in range(m):\n", - " for j in range(2):\n", - " comp[(i, j)] = solver.IntVar(0, n * n, \"comp(%i,%i)\" % (i, j))\n", - "comp_flat = [comp[(i, j)] for i in range(m) for j in range(2)]\n", - "\n", - "# The following variables are for summaries or objectives\n", - "gap = [solver.IntVar(0, n * n, \"gap(%i)\" % i) for i in range(m)]\n", - "gap_sum = solver.IntVar(0, m * n * n, \"gap_sum\")\n", - "\n", - "max_val = solver.IntVar(0, n * 2, \"max_val\")\n", - "max_win = solver.IntVar(0, n * n, \"max_win\")\n", - "\n", - "# number of occurrences of each value of the dice\n", - "counts = [solver.IntVar(0, n * m, \"counts(%i)\" % i) for i in range(n * 2 + 1)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# number of occurrences for each number\n", - "solver.Add(solver.Distribute(dice_flat, list(range(n * 2 + 1)), counts))\n", - "\n", - "solver.Add(max_win == solver.Max(comp_flat))\n", - "solver.Add(max_val == solver.Max(dice_flat))\n", - "\n", - "# order of the number of each die, lowest first\n", - "[\n", - " solver.Add(dice[(i, j)] <= dice[(i, j + 1)])\n", - " for i in range(m)\n", - " for j in range(n - 1)\n", - "]\n", - "\n", - "# nontransitivity\n", - "[comp[i, 0] > comp[i, 1] for i in range(m)],\n", - "\n", - "# probability gap\n", - "[solver.Add(gap[i] == comp[i, 0] - comp[i, 1]) for i in range(m)]\n", - "[solver.Add(gap[i] > 0) for i in range(m)]\n", - "solver.Add(gap_sum == solver.Sum(gap))\n", - "\n", - "# and now we roll...\n", - "# Number of wins for [A vs B, B vs A]\n", - "for d in range(m):\n", - " b1 = [\n", - " solver.IsGreaterVar(dice[d % m, r1], dice[(d + 1) % m, r2])\n", - " for r1 in range(n)\n", - " for r2 in range(n)\n", - " ]\n", - " solver.Add(comp[d % m, 0] == solver.Sum(b1))\n", - "\n", - " b2 = [\n", - " solver.IsGreaterVar(dice[(d + 1) % m, r1], dice[d % m, r2])\n", - " for r1 in range(n)\n", - " for r2 in range(n)\n", - " ]\n", - " solver.Add(comp[d % m, 1] == solver.Sum(b2))\n", - "\n", - "# objective\n", - "if minimize_val != 0:\n", - " print(\"Minimizing max_val\")\n", - " objective = solver.Minimize(max_val, 1)\n", - " # other experiments\n", - " # objective = solver.Maximize(max_win, 1)\n", - " # objective = solver.Maximize(gap_sum, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(dice_flat + comp_flat, solver.INT_VAR_DEFAULT,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "if minimize_val:\n", - " solver.NewSearch(db, [objective])\n", - "else:\n", - " solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"gap_sum:\", gap_sum.Value())\n", - " print(\"gap:\", [gap[i].Value() for i in range(m)])\n", - " print(\"max_val:\", max_val.Value())\n", - " print(\"max_win:\", max_win.Value())\n", - " print(\"dice:\")\n", + " dice = {}\n", " for i in range(m):\n", " for j in range(n):\n", - " print(dice[(i, j)].Value(), end=\" \")\n", - " print()\n", - " print(\"comp:\")\n", + " dice[(i, j)] = solver.IntVar(1, n * 2, \"dice(%i,%i)\" % (i, j))\n", + " dice_flat = [dice[(i, j)] for i in range(m) for j in range(n)]\n", + "\n", + " comp = {}\n", " for i in range(m):\n", " for j in range(2):\n", - " print(comp[(i, j)].Value(), end=\" \")\n", + " comp[(i, j)] = solver.IntVar(0, n * n, \"comp(%i,%i)\" % (i, j))\n", + " comp_flat = [comp[(i, j)] for i in range(m) for j in range(2)]\n", + "\n", + " # The following variables are for summaries or objectives\n", + " gap = [solver.IntVar(0, n * n, \"gap(%i)\" % i) for i in range(m)]\n", + " gap_sum = solver.IntVar(0, m * n * n, \"gap_sum\")\n", + "\n", + " max_val = solver.IntVar(0, n * 2, \"max_val\")\n", + " max_win = solver.IntVar(0, n * n, \"max_win\")\n", + "\n", + " # number of occurrences of each value of the dice\n", + " counts = [solver.IntVar(0, n * m, \"counts(%i)\" % i) for i in range(n * 2 + 1)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # number of occurrences for each number\n", + " solver.Add(solver.Distribute(dice_flat, list(range(n * 2 + 1)), counts))\n", + "\n", + " solver.Add(max_win == solver.Max(comp_flat))\n", + " solver.Add(max_val == solver.Max(dice_flat))\n", + "\n", + " # order of the number of each die, lowest first\n", + " [\n", + " solver.Add(dice[(i, j)] <= dice[(i, j + 1)])\n", + " for i in range(m)\n", + " for j in range(n - 1)\n", + " ]\n", + "\n", + " # nontransitivity\n", + " [comp[i, 0] > comp[i, 1] for i in range(m)],\n", + "\n", + " # probability gap\n", + " [solver.Add(gap[i] == comp[i, 0] - comp[i, 1]) for i in range(m)]\n", + " [solver.Add(gap[i] > 0) for i in range(m)]\n", + " solver.Add(gap_sum == solver.Sum(gap))\n", + "\n", + " # and now we roll...\n", + " # Number of wins for [A vs B, B vs A]\n", + " for d in range(m):\n", + " b1 = [\n", + " solver.IsGreaterVar(dice[d % m, r1], dice[(d + 1) % m, r2])\n", + " for r1 in range(n)\n", + " for r2 in range(n)\n", + " ]\n", + " solver.Add(comp[d % m, 0] == solver.Sum(b1))\n", + "\n", + " b2 = [\n", + " solver.IsGreaterVar(dice[(d + 1) % m, r1], dice[d % m, r2])\n", + " for r1 in range(n)\n", + " for r2 in range(n)\n", + " ]\n", + " solver.Add(comp[d % m, 1] == solver.Sum(b2))\n", + "\n", + " # objective\n", + " if minimize_val != 0:\n", + " print(\"Minimizing max_val\")\n", + " objective = solver.Minimize(max_val, 1)\n", + " # other experiments\n", + " # objective = solver.Maximize(max_win, 1)\n", + " # objective = solver.Maximize(gap_sum, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(dice_flat + comp_flat, solver.INT_VAR_DEFAULT,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " if minimize_val:\n", + " solver.NewSearch(db, [objective])\n", + " else:\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"gap_sum:\", gap_sum.Value())\n", + " print(\"gap:\", [gap[i].Value() for i in range(m)])\n", + " print(\"max_val:\", max_val.Value())\n", + " print(\"max_win:\", max_win.Value())\n", + " print(\"dice:\")\n", + " for i in range(m):\n", + " for j in range(n):\n", + " print(dice[(i, j)].Value(), end=\" \")\n", + " print()\n", + " print(\"comp:\")\n", + " for i in range(m):\n", + " for j in range(2):\n", + " print(comp[(i, j)].Value(), end=\" \")\n", + " print()\n", + " print(\"counts:\", [counts[i].Value() for i in range(n * 2 + 1)])\n", " print()\n", - " print(\"counts:\", [counts[i].Value() for i in range(n * 2 + 1)])\n", + "\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", + "\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - " num_solutions += 1\n", - "\n", - "solver.EndSearch()\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "m = 3 # number of dice\n", "n = 6 # number of sides of each die\n", - "minimize_val = 0 # Minimizing max value (0: no, 1: yes)\n" + "minimize_val = 0 # Minimizing max value (0: no, 1: yes)\n", + "if len(sys.argv) > 1:\n", + " m = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " n = int(sys.argv[2])\n", + "if len(sys.argv) > 3:\n", + " minimize_val = int(sys.argv[3])\n", + "\n", + "main(m, n, minimize_val)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/nqueens.ipynb b/examples/notebook/contrib/nqueens.ipynb index 5a45b6cdbf..c2d5248083 100644 --- a/examples/notebook/contrib/nqueens.ipynb +++ b/examples/notebook/contrib/nqueens.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " n-queens problem in Google CP Solver.\n", "\n", @@ -95,77 +80,89 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"n-queens\")\n", + "def main(n=8):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"n-queens\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "# n = 8 # size of board (n x n)\n", + " #\n", + " # data\n", + " #\n", + " # n = 8 # size of board (n x n)\n", "\n", - "# declare variables\n", - "q = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", + " # declare variables\n", + " q = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(q))\n", - "for i in range(n):\n", - " for j in range(i):\n", - " solver.Add(q[i] != q[j])\n", - " solver.Add(q[i] + i != q[j] + j)\n", - " solver.Add(q[i] - i != q[j] - j)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(q))\n", + " for i in range(n):\n", + " for j in range(i):\n", + " solver.Add(q[i] != q[j])\n", + " solver.Add(q[i] + i != q[j] + j)\n", + " solver.Add(q[i] - i != q[j] - j)\n", "\n", - "# for i in range(n):\n", - "# for j in range(i):\n", - "# solver.Add(abs(q[i]-q[j]) != abs(i-j))\n", + " # for i in range(n):\n", + " # for j in range(i):\n", + " # solver.Add(abs(q[i]-q[j]) != abs(i-j))\n", "\n", - "# symmetry breaking\n", - "# solver.Add(q[0] == 0)\n", + " # symmetry breaking\n", + " # solver.Add(q[0] == 0)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([q[i] for i in range(n)])\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([q[i] for i in range(n)])\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "# collector = solver.FirstSolutionCollector(solution)\n", - "# search_log = solver.SearchLog(100, x[0])\n", - "solver.Solve(\n", - " solver.Phase([q[i] for i in range(n)], solver.INT_VAR_SIMPLE,\n", - " solver.ASSIGN_MIN_VALUE), [collector])\n", + " collector = solver.AllSolutionCollector(solution)\n", + " # collector = solver.FirstSolutionCollector(solution)\n", + " # search_log = solver.SearchLog(100, x[0])\n", + " solver.Solve(\n", + " solver.Phase([q[i] for i in range(n)], solver.INT_VAR_SIMPLE,\n", + " solver.ASSIGN_MIN_VALUE), [collector])\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "print(\"num_solutions: \", num_solutions)\n", - "if num_solutions > 0:\n", - " for s in range(num_solutions):\n", - " qval = [collector.Value(s, q[i]) for i in range(n)]\n", - " print(\"q:\", qval)\n", - " for i in range(n):\n", - " for j in range(n):\n", - " if qval[i] == j:\n", - " print(\"Q\", end=\" \")\n", - " else:\n", - " print(\"_\", end=\" \")\n", + " num_solutions = collector.SolutionCount()\n", + " print(\"num_solutions: \", num_solutions)\n", + " if num_solutions > 0:\n", + " for s in range(num_solutions):\n", + " qval = [collector.Value(s, q[i]) for i in range(n)]\n", + " print(\"q:\", qval)\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if qval[i] == j:\n", + " print(\"Q\", end=\" \")\n", + " else:\n", + " print(\"_\", end=\" \")\n", + " print()\n", " print()\n", + "\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - " print()\n", - " print(\"num_solutions:\", num_solutions)\n", - " print(\"failures:\", solver.Failures())\n", - " print(\"branches:\", solver.Branches())\n", - " print(\"WallTime:\", solver.WallTime())\n", + " else:\n", + " print(\"No solutions found\")\n", "\n", - "else:\n", - " print(\"No solutions found\")\n", "\n", - "n = 8\n" + "n = 8\n", + "main(n)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/nqueens2.ipynb b/examples/notebook/contrib/nqueens2.ipynb index 07e08840fe..8dc1f76e20 100644 --- a/examples/notebook/contrib/nqueens2.ipynb +++ b/examples/notebook/contrib/nqueens2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " n-queens problem in Google CP Solver.\n", "\n", @@ -98,76 +83,90 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"n-queens\")\n", + "def main(n=8):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"n-queens\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "# n = 8 # size of board (n x n)\n", + " #\n", + " # data\n", + " #\n", + " # n = 8 # size of board (n x n)\n", "\n", - "# declare variables\n", - "q = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", + " # declare variables\n", + " q = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(q))\n", - "for i in range(n):\n", - " for j in range(i):\n", - " solver.Add(q[i] != q[j])\n", - " solver.Add(q[i] + i != q[j] + j)\n", - " solver.Add(q[i] - i != q[j] - j)\n", - "\n", - "# for i in range(n):\n", - "# for j in range(i):\n", - "# solver.Add(abs(q[i]-q[j]) != abs(i-j))\n", - "\n", - "# symmetry breaking\n", - "# solver.Add(q[0] == 0)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([q[i] for i in range(n)])\n", - "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(\n", - " [q[i] for i in range(n)],\n", - " # solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.CHOOSE_MIN_SIZE_LOWEST_MAX,\n", - " solver.ASSIGN_CENTER_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " qval = [q[i].Value() for i in range(n)]\n", - " print(\"q:\", qval)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(q))\n", " for i in range(n):\n", - " for j in range(n):\n", - " if qval[i] == j:\n", - " print(\"Q\", end=\" \")\n", - " else:\n", - " print(\"_\", end=\" \")\n", + " for j in range(i):\n", + " solver.Add(q[i] != q[j])\n", + " solver.Add(q[i] + i != q[j] + j)\n", + " solver.Add(q[i] - i != q[j] - j)\n", + "\n", + " # for i in range(n):\n", + " # for j in range(i):\n", + " # solver.Add(abs(q[i]-q[j]) != abs(i-j))\n", + "\n", + " # symmetry breaking\n", + " # solver.Add(q[0] == 0)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([q[i] for i in range(n)])\n", + "\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(\n", + " [q[i] for i in range(n)],\n", + " # solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.CHOOSE_MIN_SIZE_LOWEST_MAX,\n", + " solver.ASSIGN_CENTER_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " qval = [q[i].Value() for i in range(n)]\n", + " print(\"q:\", qval)\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if qval[i] == j:\n", + " print(\"Q\", end=\" \")\n", + " else:\n", + " print(\"_\", end=\" \")\n", + " print()\n", " print()\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", + "\n", " print()\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", - "n = 8\n" + "n = 8\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "main(n)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/nqueens3.ipynb b/examples/notebook/contrib/nqueens3.ipynb index 2061aaf47d..db71d282c6 100644 --- a/examples/notebook/contrib/nqueens3.ipynb +++ b/examples/notebook/contrib/nqueens3.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " n-queens problem in Google CP Solver.\n", "\n", @@ -100,71 +85,96 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"n-queens\")\n", + "def main(n=8, num_sol=0, print_sol=1):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"n-queens\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"n:\", n)\n", - "print(\"num_sol:\", num_sol)\n", - "print(\"print_sol:\", print_sol)\n", + " #\n", + " # data\n", + " #\n", + " print(\"n:\", n)\n", + " print(\"num_sol:\", num_sol)\n", + " print(\"print_sol:\", print_sol)\n", "\n", - "# declare variables\n", - "q = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", + " # declare variables\n", + " q = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(q))\n", - "solver.Add(solver.AllDifferent([q[i] + i for i in range(n)]))\n", - "solver.Add(solver.AllDifferent([q[i] - i for i in range(n)]))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(q))\n", + " solver.Add(solver.AllDifferent([q[i] + i for i in range(n)]))\n", + " solver.Add(solver.AllDifferent([q[i] - i for i in range(n)]))\n", "\n", - "# symmetry breaking\n", - "# solver.Add(q[0] == 0)\n", + " # symmetry breaking\n", + " # solver.Add(q[0] == 0)\n", "\n", - "#\n", - "# search\n", - "#\n", + " #\n", + " # search\n", + " #\n", "\n", - "db = solver.Phase(q, solver.CHOOSE_MIN_SIZE_LOWEST_MAX,\n", - " solver.ASSIGN_CENTER_VALUE)\n", + " db = solver.Phase(q, solver.CHOOSE_MIN_SIZE_LOWEST_MAX,\n", + " solver.ASSIGN_CENTER_VALUE)\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " if print_sol:\n", - " qval = [q[i].Value() for i in range(n)]\n", - " print(\"q:\", qval)\n", - " for i in range(n):\n", - " for j in range(n):\n", - " if qval[i] == j:\n", - " print(\"Q\", end=\" \")\n", - " else:\n", - " print(\"_\", end=\" \")\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " if print_sol:\n", + " qval = [q[i].Value() for i in range(n)]\n", + " print(\"q:\", qval)\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if qval[i] == j:\n", + " print(\"Q\", end=\" \")\n", + " else:\n", + " print(\"_\", end=\" \")\n", + " print()\n", " print()\n", - " print()\n", - " num_solutions += 1\n", - " if num_sol > 0 and num_solutions >= num_sol:\n", - " break\n", + " num_solutions += 1\n", + " if num_sol > 0 and num_solutions >= num_sol:\n", + " break\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", + "\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime(), \"ms\")\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime(), \"ms\")\n", "\n", "n = 8\n", "num_sol = 0\n", - "print_sol = 1\n" + "print_sol = 1\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " num_sol = int(sys.argv[2])\n", + "if len(sys.argv) > 3:\n", + " print_sol = int(sys.argv[3])\n", + "\n", + "main(n, num_sol, print_sol)\n", + "\n", + "# print_sol = False\n", + "# show_all = False\n", + "# for n in range(1000,1001):\n", + "# print\n", + "# main(n, num_sol, print_sol)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/nurse_rostering.ipynb b/examples/notebook/contrib/nurse_rostering.ipynb index 46464a4003..29507f47c7 100644 --- a/examples/notebook/contrib/nurse_rostering.ipynb +++ b/examples/notebook/contrib/nurse_rostering.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Nurse rostering in Google CP Solver.\n", "\n", @@ -102,8 +87,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "from collections import defaultdict\n", "\n", @@ -177,164 +170,168 @@ " a[i + 1] == solver.Element(d2_flatten, ((a[i]) * S) + (x[i] - 1)))\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Nurse rostering using regular')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Nurse rostering using regular')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# Note: If you change num_nurses or num_days,\n", - "# please also change the constraints\n", - "# on nurse_stat and/or day_stat.\n", - "num_nurses = 7\n", - "num_days = 14\n", + " # Note: If you change num_nurses or num_days,\n", + " # please also change the constraints\n", + " # on nurse_stat and/or day_stat.\n", + " num_nurses = 7\n", + " num_days = 14\n", "\n", - "day_shift = 1\n", - "night_shift = 2\n", - "off_shift = 3\n", - "shifts = [day_shift, night_shift, off_shift]\n", + " day_shift = 1\n", + " night_shift = 2\n", + " off_shift = 3\n", + " shifts = [day_shift, night_shift, off_shift]\n", "\n", - "# the DFA (for regular)\n", - "n_states = 6\n", - "input_max = 3\n", - "initial_state = 1 # 0 is for the failing state\n", - "accepting_states = [1, 2, 3, 4, 5, 6]\n", + " # the DFA (for regular)\n", + " n_states = 6\n", + " input_max = 3\n", + " initial_state = 1 # 0 is for the failing state\n", + " accepting_states = [1, 2, 3, 4, 5, 6]\n", "\n", - "transition_fn = [\n", - " # d,n,o\n", - " [2, 3, 1], # state 1\n", - " [4, 4, 1], # state 2\n", - " [4, 5, 1], # state 3\n", - " [6, 6, 1], # state 4\n", - " [6, 0, 1], # state 5\n", - " [0, 0, 1] # state 6\n", - "]\n", - "\n", - "days = ['d', 'n', 'o'] # for presentation\n", - "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = {}\n", - "for i in range(num_nurses):\n", - " for j in range(num_days):\n", - " x[i, j] = solver.IntVar(shifts, 'x[%i,%i]' % (i, j))\n", - "\n", - "x_flat = [x[i, j] for i in range(num_nurses) for j in range(num_days)]\n", - "\n", - "# summary of the nurses\n", - "nurse_stat = [\n", - " solver.IntVar(0, num_days, 'nurse_stat[%i]' % i)\n", - " for i in range(num_nurses)\n", - "]\n", - "\n", - "# summary of the shifts per day\n", - "day_stat = {}\n", - "for i in range(num_days):\n", - " for j in shifts:\n", - " day_stat[i, j] = solver.IntVar(0, num_nurses, 'day_stat[%i,%i]' % (i, j))\n", - "\n", - "day_stat_flat = [day_stat[i, j] for i in range(num_days) for j in shifts]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(num_nurses):\n", - " reg_input = [x[i, j] for j in range(num_days)]\n", - " regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", - " accepting_states)\n", - "\n", - "#\n", - "# Statistics and constraints for each nurse\n", - "#\n", - "for i in range(num_nurses):\n", - " # number of worked days (day or night shift)\n", - " b = [\n", - " solver.IsEqualCstVar(x[i, j], day_shift) + solver.IsEqualCstVar(\n", - " x[i, j], night_shift) for j in range(num_days)\n", + " transition_fn = [\n", + " # d,n,o\n", + " [2, 3, 1], # state 1\n", + " [4, 4, 1], # state 2\n", + " [4, 5, 1], # state 3\n", + " [6, 6, 1], # state 4\n", + " [6, 0, 1], # state 5\n", + " [0, 0, 1] # state 6\n", " ]\n", - " solver.Add(nurse_stat[i] == solver.Sum(b))\n", "\n", - " # Each nurse must work between 7 and 10\n", - " # days during this period\n", - " solver.Add(nurse_stat[i] >= 7)\n", - " solver.Add(nurse_stat[i] <= 10)\n", - "\n", - "#\n", - "# Statistics and constraints for each day\n", - "#\n", - "for j in range(num_days):\n", - " for t in shifts:\n", - " b = [solver.IsEqualCstVar(x[i, j], t) for i in range(num_nurses)]\n", - " solver.Add(day_stat[j, t] == solver.Sum(b))\n", + " days = ['d', 'n', 'o'] # for presentation\n", "\n", " #\n", - " # Some constraints for this day:\n", + " # declare variables\n", " #\n", - " # Note: We have a strict requirements of\n", - " # the number of shifts.\n", - " # Using atleast constraints is much harder\n", - " # in this model.\n", - " #\n", - " if j % 7 == 5 or j % 7 == 6:\n", - " # special constraints for the weekends\n", - " solver.Add(day_stat[j, day_shift] == 2)\n", - " solver.Add(day_stat[j, night_shift] == 1)\n", - " solver.Add(day_stat[j, off_shift] == 4)\n", - " else:\n", - " # workdays:\n", - "\n", - " # - exactly 3 on day shift\n", - " solver.Add(day_stat[j, day_shift] == 3)\n", - " # - exactly 2 on night\n", - " solver.Add(day_stat[j, night_shift] == 2)\n", - " # - exactly 1 off duty\n", - " solver.Add(day_stat[j, off_shift] == 2)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(day_stat_flat + x_flat + nurse_stat,\n", - " solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - "\n", + " x = {}\n", " for i in range(num_nurses):\n", - " print('Nurse%i: ' % i, end=' ')\n", - " this_day_stat = defaultdict(int)\n", " for j in range(num_days):\n", - " d = days[x[i, j].Value() - 1]\n", - " this_day_stat[d] += 1\n", - " print(d, end=' ')\n", - " print(\n", - " ' day_stat:', [(d, this_day_stat[d]) for d in this_day_stat], end=' ')\n", - " print('total:', nurse_stat[i].Value(), 'workdays')\n", - " print()\n", + " x[i, j] = solver.IntVar(shifts, 'x[%i,%i]' % (i, j))\n", "\n", - " print('Statistics per day:')\n", + " x_flat = [x[i, j] for i in range(num_nurses) for j in range(num_days)]\n", + "\n", + " # summary of the nurses\n", + " nurse_stat = [\n", + " solver.IntVar(0, num_days, 'nurse_stat[%i]' % i)\n", + " for i in range(num_nurses)\n", + " ]\n", + "\n", + " # summary of the shifts per day\n", + " day_stat = {}\n", + " for i in range(num_days):\n", + " for j in shifts:\n", + " day_stat[i, j] = solver.IntVar(0, num_nurses, 'day_stat[%i,%i]' % (i, j))\n", + "\n", + " day_stat_flat = [day_stat[i, j] for i in range(num_days) for j in shifts]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " for i in range(num_nurses):\n", + " reg_input = [x[i, j] for j in range(num_days)]\n", + " regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", + " accepting_states)\n", + "\n", + " #\n", + " # Statistics and constraints for each nurse\n", + " #\n", + " for i in range(num_nurses):\n", + " # number of worked days (day or night shift)\n", + " b = [\n", + " solver.IsEqualCstVar(x[i, j], day_shift) + solver.IsEqualCstVar(\n", + " x[i, j], night_shift) for j in range(num_days)\n", + " ]\n", + " solver.Add(nurse_stat[i] == solver.Sum(b))\n", + "\n", + " # Each nurse must work between 7 and 10\n", + " # days during this period\n", + " solver.Add(nurse_stat[i] >= 7)\n", + " solver.Add(nurse_stat[i] <= 10)\n", + "\n", + " #\n", + " # Statistics and constraints for each day\n", + " #\n", " for j in range(num_days):\n", - " print('Day%2i: ' % j, end=' ')\n", " for t in shifts:\n", - " print(day_stat[j, t].Value(), end=' ')\n", + " b = [solver.IsEqualCstVar(x[i, j], t) for i in range(num_nurses)]\n", + " solver.Add(day_stat[j, t] == solver.Sum(b))\n", + "\n", + " #\n", + " # Some constraints for this day:\n", + " #\n", + " # Note: We have a strict requirements of\n", + " # the number of shifts.\n", + " # Using atleast constraints is much harder\n", + " # in this model.\n", + " #\n", + " if j % 7 == 5 or j % 7 == 6:\n", + " # special constraints for the weekends\n", + " solver.Add(day_stat[j, day_shift] == 2)\n", + " solver.Add(day_stat[j, night_shift] == 1)\n", + " solver.Add(day_stat[j, off_shift] == 4)\n", + " else:\n", + " # workdays:\n", + "\n", + " # - exactly 3 on day shift\n", + " solver.Add(day_stat[j, day_shift] == 3)\n", + " # - exactly 2 on night\n", + " solver.Add(day_stat[j, night_shift] == 2)\n", + " # - exactly 1 off duty\n", + " solver.Add(day_stat[j, off_shift] == 2)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(day_stat_flat + x_flat + nurse_stat,\n", + " solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + "\n", + " for i in range(num_nurses):\n", + " print('Nurse%i: ' % i, end=' ')\n", + " this_day_stat = defaultdict(int)\n", + " for j in range(num_days):\n", + " d = days[x[i, j].Value() - 1]\n", + " this_day_stat[d] += 1\n", + " print(d, end=' ')\n", + " print(\n", + " ' day_stat:', [(d, this_day_stat[d]) for d in this_day_stat], end=' ')\n", + " print('total:', nurse_stat[i].Value(), 'workdays')\n", " print()\n", + "\n", + " print('Statistics per day:')\n", + " for j in range(num_days):\n", + " print('Day%2i: ' % j, end=' ')\n", + " for t in shifts:\n", + " print(day_stat[j, t].Value(), end=' ')\n", + " print()\n", + " print()\n", + "\n", + " # We just show 2 solutions\n", + " if num_solutions >= 2:\n", + " break\n", + "\n", + " solver.EndSearch()\n", " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", - " # We just show 2 solutions\n", - " if num_solutions >= 2:\n", - " break\n", "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/nurses_cp.ipynb b/examples/notebook/contrib/nurses_cp.ipynb index 99f306405a..e1c722cfb9 100644 --- a/examples/notebook/contrib/nurses_cp.ipynb +++ b/examples/notebook/contrib/nurses_cp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -78,175 +78,179 @@ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Creates the solver.\n", - "solver = pywrapcp.Solver(\"schedule_shifts\")\n", + "def main():\n", + " # Creates the solver.\n", + " solver = pywrapcp.Solver(\"schedule_shifts\")\n", "\n", - "num_nurses = 4\n", - "num_shifts = 4 # Nurse assigned to shift 0 means not working that day.\n", - "num_days = 7\n", - "# [START]\n", - "# Create shift variables.\n", - "shifts = {}\n", - "\n", - "for j in range(num_nurses):\n", - " for i in range(num_days):\n", - " shifts[(j, i)] = solver.IntVar(0, num_shifts - 1,\n", - " \"shifts(%i,%i)\" % (j, i))\n", - "shifts_flat = [\n", - " shifts[(j, i)] for j in range(num_nurses) for i in range(num_days)\n", - "]\n", - "\n", - "# Create nurse variables.\n", - "nurses = {}\n", - "\n", - "for j in range(num_shifts):\n", - " for i in range(num_days):\n", - " nurses[(j, i)] = solver.IntVar(0, num_nurses - 1,\n", - " \"shift%d day%d\" % (j, i))\n", - "# Set relationships between shifts and nurses.\n", - "for day in range(num_days):\n", - " nurses_for_day = [nurses[(j, day)] for j in range(num_shifts)]\n", + " num_nurses = 4\n", + " num_shifts = 4 # Nurse assigned to shift 0 means not working that day.\n", + " num_days = 7\n", + " # [START]\n", + " # Create shift variables.\n", + " shifts = {}\n", "\n", " for j in range(num_nurses):\n", - " s = shifts[(j, day)]\n", - " solver.Add(s.IndexOf(nurses_for_day) == j)\n", - "# Make assignments different on each day\n", - "for i in range(num_days):\n", - " solver.Add(solver.AllDifferent([shifts[(j, i)] for j in range(num_nurses)]))\n", - " solver.Add(solver.AllDifferent([nurses[(j, i)] for j in range(num_shifts)]))\n", - "# Each nurse works 5 or 6 days in a week.\n", - "for j in range(num_nurses):\n", - " solver.Add(solver.Sum([shifts[(j, i)] > 0 for i in range(num_days)]) >= 5)\n", - " solver.Add(solver.Sum([shifts[(j, i)] > 0 for i in range(num_days)]) <= 6)\n", - "# Create works_shift variables. works_shift[(i, j)] is True if nurse\n", - "# i works shift j at least once during the week.\n", - "works_shift = {}\n", + " for i in range(num_days):\n", + " shifts[(j, i)] = solver.IntVar(0, num_shifts - 1,\n", + " \"shifts(%i,%i)\" % (j, i))\n", + " shifts_flat = [\n", + " shifts[(j, i)] for j in range(num_nurses) for i in range(num_days)\n", + " ]\n", + "\n", + " # Create nurse variables.\n", + " nurses = {}\n", "\n", - "for i in range(num_nurses):\n", " for j in range(num_shifts):\n", - " works_shift[(i, j)] = solver.BoolVar(\"nurse%d shift%d\" % (i, j))\n", + " for i in range(num_days):\n", + " nurses[(j, i)] = solver.IntVar(0, num_nurses - 1,\n", + " \"shift%d day%d\" % (j, i))\n", + " # Set relationships between shifts and nurses.\n", + " for day in range(num_days):\n", + " nurses_for_day = [nurses[(j, day)] for j in range(num_shifts)]\n", "\n", - "for i in range(num_nurses):\n", - " for j in range(num_shifts):\n", - " solver.Add(works_shift[(\n", - " i, j)] == solver.Max([shifts[(i, k)] == j for k in range(num_days)]))\n", - "\n", - "# For each shift (other than 0), at most 2 nurses are assigned to that shift\n", - "# during the week.\n", - "for j in range(1, num_shifts):\n", - " solver.Add(\n", - " solver.Sum([works_shift[(i, j)] for i in range(num_nurses)]) <= 2)\n", - "# If s nurses works shifts 2 or 3 on, he must also work that shift the previous\n", - "# day or the following day.\n", - "solver.Add(\n", - " solver.Max(nurses[(2,\n", - " 0)] == nurses[(2,\n", - " 1)], nurses[(2,\n", - " 1)] == nurses[(2,\n", - " 2)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(2,\n", - " 1)] == nurses[(2,\n", - " 2)], nurses[(2,\n", - " 2)] == nurses[(2,\n", - " 3)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(2,\n", - " 2)] == nurses[(2,\n", - " 3)], nurses[(2,\n", - " 3)] == nurses[(2,\n", - " 4)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(2,\n", - " 3)] == nurses[(2,\n", - " 4)], nurses[(2,\n", - " 4)] == nurses[(2,\n", - " 5)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(2,\n", - " 4)] == nurses[(2,\n", - " 5)], nurses[(2,\n", - " 5)] == nurses[(2,\n", - " 6)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(2,\n", - " 5)] == nurses[(2,\n", - " 6)], nurses[(2,\n", - " 6)] == nurses[(2,\n", - " 0)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(2,\n", - " 6)] == nurses[(2,\n", - " 0)], nurses[(2,\n", - " 0)] == nurses[(2,\n", - " 1)]) == 1)\n", - "\n", - "solver.Add(\n", - " solver.Max(nurses[(3,\n", - " 0)] == nurses[(3,\n", - " 1)], nurses[(3,\n", - " 1)] == nurses[(3,\n", - " 2)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(3,\n", - " 1)] == nurses[(3,\n", - " 2)], nurses[(3,\n", - " 2)] == nurses[(3,\n", - " 3)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(3,\n", - " 2)] == nurses[(3,\n", - " 3)], nurses[(3,\n", - " 3)] == nurses[(3,\n", - " 4)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(3,\n", - " 3)] == nurses[(3,\n", - " 4)], nurses[(3,\n", - " 4)] == nurses[(3,\n", - " 5)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(3,\n", - " 4)] == nurses[(3,\n", - " 5)], nurses[(3,\n", - " 5)] == nurses[(3,\n", - " 6)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(3,\n", - " 5)] == nurses[(3,\n", - " 6)], nurses[(3,\n", - " 6)] == nurses[(3,\n", - " 0)]) == 1)\n", - "solver.Add(\n", - " solver.Max(nurses[(3,\n", - " 6)] == nurses[(3,\n", - " 0)], nurses[(3,\n", - " 0)] == nurses[(3,\n", - " 1)]) == 1)\n", - "# Create the decision builder.\n", - "db = solver.Phase(shifts_flat, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "# Create the solution collector.\n", - "solution = solver.Assignment()\n", - "solution.Add(shifts_flat)\n", - "collector = solver.AllSolutionCollector(solution)\n", - "\n", - "solver.Solve(db, [collector])\n", - "print(\"Solutions found:\", collector.SolutionCount())\n", - "print(\"Time:\", solver.WallTime(), \"ms\")\n", - "print()\n", - "# Display a few solutions picked at random.\n", - "a_few_solutions = [859, 2034, 5091, 7003]\n", - "\n", - "for sol in a_few_solutions:\n", - " print(\"Solution number\", sol, \"\\n\")\n", - "\n", - " for i in range(num_days):\n", - " print(\"Day\", i)\n", " for j in range(num_nurses):\n", - " print(\"Nurse\", j, \"assigned to task\",\n", - " collector.Value(sol, shifts[(j, i)]))\n", - " print()\n", + " s = shifts[(j, day)]\n", + " solver.Add(s.IndexOf(nurses_for_day) == j)\n", + " # Make assignments different on each day\n", + " for i in range(num_days):\n", + " solver.Add(solver.AllDifferent([shifts[(j, i)] for j in range(num_nurses)]))\n", + " solver.Add(solver.AllDifferent([nurses[(j, i)] for j in range(num_shifts)]))\n", + " # Each nurse works 5 or 6 days in a week.\n", + " for j in range(num_nurses):\n", + " solver.Add(solver.Sum([shifts[(j, i)] > 0 for i in range(num_days)]) >= 5)\n", + " solver.Add(solver.Sum([shifts[(j, i)] > 0 for i in range(num_days)]) <= 6)\n", + " # Create works_shift variables. works_shift[(i, j)] is True if nurse\n", + " # i works shift j at least once during the week.\n", + " works_shift = {}\n", + "\n", + " for i in range(num_nurses):\n", + " for j in range(num_shifts):\n", + " works_shift[(i, j)] = solver.BoolVar(\"nurse%d shift%d\" % (i, j))\n", + "\n", + " for i in range(num_nurses):\n", + " for j in range(num_shifts):\n", + " solver.Add(works_shift[(\n", + " i, j)] == solver.Max([shifts[(i, k)] == j for k in range(num_days)]))\n", + "\n", + " # For each shift (other than 0), at most 2 nurses are assigned to that shift\n", + " # during the week.\n", + " for j in range(1, num_shifts):\n", + " solver.Add(\n", + " solver.Sum([works_shift[(i, j)] for i in range(num_nurses)]) <= 2)\n", + " # If s nurses works shifts 2 or 3 on, he must also work that shift the previous\n", + " # day or the following day.\n", + " solver.Add(\n", + " solver.Max(nurses[(2,\n", + " 0)] == nurses[(2,\n", + " 1)], nurses[(2,\n", + " 1)] == nurses[(2,\n", + " 2)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(2,\n", + " 1)] == nurses[(2,\n", + " 2)], nurses[(2,\n", + " 2)] == nurses[(2,\n", + " 3)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(2,\n", + " 2)] == nurses[(2,\n", + " 3)], nurses[(2,\n", + " 3)] == nurses[(2,\n", + " 4)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(2,\n", + " 3)] == nurses[(2,\n", + " 4)], nurses[(2,\n", + " 4)] == nurses[(2,\n", + " 5)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(2,\n", + " 4)] == nurses[(2,\n", + " 5)], nurses[(2,\n", + " 5)] == nurses[(2,\n", + " 6)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(2,\n", + " 5)] == nurses[(2,\n", + " 6)], nurses[(2,\n", + " 6)] == nurses[(2,\n", + " 0)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(2,\n", + " 6)] == nurses[(2,\n", + " 0)], nurses[(2,\n", + " 0)] == nurses[(2,\n", + " 1)]) == 1)\n", + "\n", + " solver.Add(\n", + " solver.Max(nurses[(3,\n", + " 0)] == nurses[(3,\n", + " 1)], nurses[(3,\n", + " 1)] == nurses[(3,\n", + " 2)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(3,\n", + " 1)] == nurses[(3,\n", + " 2)], nurses[(3,\n", + " 2)] == nurses[(3,\n", + " 3)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(3,\n", + " 2)] == nurses[(3,\n", + " 3)], nurses[(3,\n", + " 3)] == nurses[(3,\n", + " 4)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(3,\n", + " 3)] == nurses[(3,\n", + " 4)], nurses[(3,\n", + " 4)] == nurses[(3,\n", + " 5)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(3,\n", + " 4)] == nurses[(3,\n", + " 5)], nurses[(3,\n", + " 5)] == nurses[(3,\n", + " 6)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(3,\n", + " 5)] == nurses[(3,\n", + " 6)], nurses[(3,\n", + " 6)] == nurses[(3,\n", + " 0)]) == 1)\n", + " solver.Add(\n", + " solver.Max(nurses[(3,\n", + " 6)] == nurses[(3,\n", + " 0)], nurses[(3,\n", + " 0)] == nurses[(3,\n", + " 1)]) == 1)\n", + " # Create the decision builder.\n", + " db = solver.Phase(shifts_flat, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + " # Create the solution collector.\n", + " solution = solver.Assignment()\n", + " solution.Add(shifts_flat)\n", + " collector = solver.AllSolutionCollector(solution)\n", + "\n", + " solver.Solve(db, [collector])\n", + " print(\"Solutions found:\", collector.SolutionCount())\n", + " print(\"Time:\", solver.WallTime(), \"ms\")\n", + " print()\n", + " # Display a few solutions picked at random.\n", + " a_few_solutions = [859, 2034, 5091, 7003]\n", + "\n", + " for sol in a_few_solutions:\n", + " print(\"Solution number\", sol, \"\\n\")\n", + "\n", + " for i in range(num_days):\n", + " print(\"Day\", i)\n", + " for j in range(num_nurses):\n", + " print(\"Nurse\", j, \"assigned to task\",\n", + " collector.Value(sol, shifts[(j, i)]))\n", + " print()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/olympic.ipynb b/examples/notebook/contrib/olympic.ipynb index a0696ae737..4c60823bc5 100644 --- a/examples/notebook/contrib/olympic.ipynb +++ b/examples/notebook/contrib/olympic.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Olympic puzzle in Google CP Solver.\n", "\n", @@ -129,8 +114,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -139,51 +132,55 @@ " solver.Add(z == abs(x - y))\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Olympic')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Olympic')\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 10\n", + " #\n", + " # data\n", + " #\n", + " n = 10\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "Vars = [solver.IntVar(1, n, 'Vars[%i]' % i) for i in range(n)]\n", - "X1, X2, X3, X4, X5, X6, X7, X8, X9, X10 = Vars\n", + " #\n", + " # declare variables\n", + " #\n", + " Vars = [solver.IntVar(1, n, 'Vars[%i]' % i) for i in range(n)]\n", + " X1, X2, X3, X4, X5, X6, X7, X8, X9, X10 = Vars\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(Vars))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(Vars))\n", "\n", - "solver.Add(X1 == 3)\n", - "minus(solver, X2, X3, X1)\n", - "minus(solver, X4, X5, X2)\n", - "minus(solver, X5, X6, X3)\n", - "minus(solver, X7, X8, X4)\n", - "minus(solver, X8, X9, X5)\n", - "minus(solver, X9, X10, X6)\n", + " solver.Add(X1 == 3)\n", + " minus(solver, X2, X3, X1)\n", + " minus(solver, X4, X5, X2)\n", + " minus(solver, X5, X6, X3)\n", + " minus(solver, X7, X8, X4)\n", + " minus(solver, X8, X9, X5)\n", + " minus(solver, X9, X10, X6)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(Vars, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(Vars, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('Vars:', [Vars[i].Value() for i in range(n)])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('Vars:', [Vars[i].Value() for i in range(n)])\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/organize_day.ipynb b/examples/notebook/contrib/organize_day.ipynb index bc9a4b5e08..f32ea638f3 100644 --- a/examples/notebook/contrib/organize_day.ipynb +++ b/examples/notebook/contrib/organize_day.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Organizing a day in Google CP Solver.\n", "\n", @@ -105,8 +90,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -121,68 +114,72 @@ " solver.Add(b1 + b2 >= 1)\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Organizing a day')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Organizing a day')\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", "\n", - "tasks = list(range(n))\n", - "work, mail, shop, bank = tasks\n", - "durations = [4, 1, 2, 1]\n", + " tasks = list(range(n))\n", + " work, mail, shop, bank = tasks\n", + " durations = [4, 1, 2, 1]\n", "\n", - "# task [i,0] must be finished before task [i,1]\n", - "before_tasks = [[bank, shop], [mail, work]]\n", + " # task [i,0] must be finished before task [i,1]\n", + " before_tasks = [[bank, shop], [mail, work]]\n", "\n", - "# the valid times of the day\n", - "begin = 9\n", - "end = 17\n", + " # the valid times of the day\n", + " begin = 9\n", + " end = 17\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "begins = [solver.IntVar(begin, end, 'begins[%i]% % i') for i in tasks]\n", - "ends = [solver.IntVar(begin, end, 'ends[%i]% % i') for i in tasks]\n", + " #\n", + " # declare variables\n", + " #\n", + " begins = [solver.IntVar(begin, end, 'begins[%i]% % i') for i in tasks]\n", + " ends = [solver.IntVar(begin, end, 'ends[%i]% % i') for i in tasks]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in tasks:\n", - " solver.Add(ends[i] == begins[i] + durations[i])\n", + " #\n", + " # constraints\n", + " #\n", + " for i in tasks:\n", + " solver.Add(ends[i] == begins[i] + durations[i])\n", "\n", - "for i in tasks:\n", - " for j in tasks:\n", - " if i < j:\n", - " no_overlap(solver, begins[i], durations[i], begins[j], durations[j])\n", + " for i in tasks:\n", + " for j in tasks:\n", + " if i < j:\n", + " no_overlap(solver, begins[i], durations[i], begins[j], durations[j])\n", "\n", - "# specific constraints\n", - "for (before, after) in before_tasks:\n", - " solver.Add(ends[before] <= begins[after])\n", + " # specific constraints\n", + " for (before, after) in before_tasks:\n", + " solver.Add(ends[before] <= begins[after])\n", "\n", - "solver.Add(begins[work] >= 11)\n", + " solver.Add(begins[work] >= 11)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(begins + ends, solver.INT_VAR_DEFAULT,\n", - " solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(begins + ends, solver.INT_VAR_DEFAULT,\n", + " solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('begins:', [begins[i].Value() for i in tasks])\n", - " print('ends:', [ends[i].Value() for i in tasks])\n", - " print()\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('begins:', [begins[i].Value() for i in tasks])\n", + " print('ends:', [ends[i].Value() for i in tasks])\n", + " print()\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/p_median.ipynb b/examples/notebook/contrib/p_median.ipynb index 83a52e7615..0cb3a2fddc 100644 --- a/examples/notebook/contrib/p_median.ipynb +++ b/examples/notebook/contrib/p_median.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " P-median problem in Google CP Solver.\n", "\n", @@ -107,89 +92,101 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('P-median problem')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('P-median problem')\n", "\n", - "#\n", - "# data\n", - "#\n", - "p = 2\n", + " #\n", + " # data\n", + " #\n", + " p = 2\n", "\n", - "num_customers = 4\n", - "customers = list(range(num_customers))\n", - "Albert, Bob, Chris, Daniel = customers\n", - "num_warehouses = 3\n", - "warehouses = list(range(num_warehouses))\n", - "Santa_Clara, San_Jose, Berkeley = warehouses\n", + " num_customers = 4\n", + " customers = list(range(num_customers))\n", + " Albert, Bob, Chris, Daniel = customers\n", + " num_warehouses = 3\n", + " warehouses = list(range(num_warehouses))\n", + " Santa_Clara, San_Jose, Berkeley = warehouses\n", "\n", - "demand = [100, 80, 80, 70]\n", - "distance = [[2, 10, 50], [2, 10, 52], [50, 60, 3], [40, 60, 1]]\n", + " demand = [100, 80, 80, 70]\n", + " distance = [[2, 10, 50], [2, 10, 52], [50, 60, 3], [40, 60, 1]]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "open = [solver.IntVar(warehouses, 'open[%i]% % i') for w in warehouses]\n", - "ship = {}\n", - "for c in customers:\n", - " for w in warehouses:\n", - " ship[c, w] = solver.IntVar(0, 1, 'ship[%i,%i]' % (c, w))\n", - "ship_flat = [ship[c, w] for c in customers for w in warehouses]\n", - "\n", - "z = solver.IntVar(0, 1000, 'z')\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "z_sum = solver.Sum([\n", - " demand[c] * distance[c][w] * ship[c, w]\n", - " for c in customers\n", - " for w in warehouses\n", - "])\n", - "solver.Add(z == z_sum)\n", - "\n", - "for c in customers:\n", - " s = solver.Sum([ship[c, w] for w in warehouses])\n", - " solver.Add(s == 1)\n", - "\n", - "solver.Add(solver.Sum(open) == p)\n", - "\n", - "for c in customers:\n", - " for w in warehouses:\n", - " solver.Add(ship[c, w] <= open[w])\n", - "\n", - "# objective\n", - "objective = solver.Minimize(z, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(open + ship_flat, solver.INT_VAR_DEFAULT,\n", - " solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('z:', z.Value())\n", - " print('open:', [open[w].Value() for w in warehouses])\n", + " #\n", + " # declare variables\n", + " #\n", + " open = [solver.IntVar(warehouses, 'open[%i]% % i') for w in warehouses]\n", + " ship = {}\n", " for c in customers:\n", " for w in warehouses:\n", - " print(ship[c, w].Value(), end=' ')\n", - " print()\n", - " print()\n", + " ship[c, w] = solver.IntVar(0, 1, 'ship[%i,%i]' % (c, w))\n", + " ship_flat = [ship[c, w] for c in customers for w in warehouses]\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " z = solver.IntVar(0, 1000, 'z')\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " z_sum = solver.Sum([\n", + " demand[c] * distance[c][w] * ship[c, w]\n", + " for c in customers\n", + " for w in warehouses\n", + " ])\n", + " solver.Add(z == z_sum)\n", + "\n", + " for c in customers:\n", + " s = solver.Sum([ship[c, w] for w in warehouses])\n", + " solver.Add(s == 1)\n", + "\n", + " solver.Add(solver.Sum(open) == p)\n", + "\n", + " for c in customers:\n", + " for w in warehouses:\n", + " solver.Add(ship[c, w] <= open[w])\n", + "\n", + " # objective\n", + " objective = solver.Minimize(z, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(open + ship_flat, solver.INT_VAR_DEFAULT,\n", + " solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('z:', z.Value())\n", + " print('open:', [open[w].Value() for w in warehouses])\n", + " for c in customers:\n", + " for w in warehouses:\n", + " print(ship[c, w].Value(), end=' ')\n", + " print()\n", + " print()\n", + "\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/pandigital_numbers.ipynb b/examples/notebook/contrib/pandigital_numbers.ipynb index 4a664e48f9..9e69bc8094 100644 --- a/examples/notebook/contrib/pandigital_numbers.ipynb +++ b/examples/notebook/contrib/pandigital_numbers.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Pandigital numbers in Google CP Solver.\n", "\n", @@ -134,8 +119,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -151,72 +144,74 @@ " s == solver.Sum([(base**(tlen - i - 1)) * t[i] for i in range(tlen)]))\n", "\n", "\n", + "def main(base=10, start=1, len1=1, len2=4):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Pandigital numbers\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Pandigital numbers\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "max_d = base - 1\n", - "x_len = max_d + 1 - start\n", - "max_num = base**4 - 1\n", + " #\n", + " # data\n", + " #\n", + " max_d = base - 1\n", + " x_len = max_d + 1 - start\n", + " max_num = base**4 - 1\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "num1 = solver.IntVar(0, max_num, \"num1\")\n", - "num2 = solver.IntVar(0, max_num, \"num2\")\n", - "res = solver.IntVar(0, max_num, \"res\")\n", + " #\n", + " # declare variables\n", + " #\n", + " num1 = solver.IntVar(0, max_num, \"num1\")\n", + " num2 = solver.IntVar(0, max_num, \"num2\")\n", + " res = solver.IntVar(0, max_num, \"res\")\n", "\n", - "x = [solver.IntVar(start, max_d, \"x[%i]\" % i) for i in range(x_len)]\n", + " x = [solver.IntVar(start, max_d, \"x[%i]\" % i) for i in range(x_len)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", "\n", - "toNum(solver, [x[i] for i in range(len1)], num1, base)\n", - "toNum(solver, [x[i] for i in range(len1, len1 + len2)], num2, base)\n", - "toNum(solver, [x[i] for i in range(len1 + len2, x_len)], res, base)\n", + " toNum(solver, [x[i] for i in range(len1)], num1, base)\n", + " toNum(solver, [x[i] for i in range(len1, len1 + len2)], num2, base)\n", + " toNum(solver, [x[i] for i in range(len1 + len2, x_len)], res, base)\n", "\n", - "solver.Add(num1 * num2 == res)\n", + " solver.Add(num1 * num2 == res)\n", "\n", - "# no number must start with 0\n", - "solver.Add(x[0] > 0)\n", - "solver.Add(x[len1] > 0)\n", - "solver.Add(x[len1 + len2] > 0)\n", + " # no number must start with 0\n", + " solver.Add(x[0] > 0)\n", + " solver.Add(x[len1] > 0)\n", + " solver.Add(x[len1 + len2] > 0)\n", "\n", - "# symmetry breaking\n", - "solver.Add(num1 < num2)\n", + " # symmetry breaking\n", + " solver.Add(num1 < num2)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(num1)\n", - "solution.Add(num2)\n", - "solution.Add(res)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(num1)\n", + " solution.Add(num2)\n", + " solution.Add(res)\n", "\n", - "db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT)\n", + " db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "solutions = []\n", - "while solver.NextSolution():\n", - " print_solution([x[i].Value() for i in range(x_len)], len1, len2, x_len)\n", - " num_solutions += 1\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " solutions = []\n", + " while solver.NextSolution():\n", + " print_solution([x[i].Value() for i in range(x_len)], len1, len2, x_len)\n", + " num_solutions += 1\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", + "\n", + " if 0 and num_solutions > 0:\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print()\n", "\n", - "if 0 and num_solutions > 0:\n", - " print()\n", - " print(\"num_solutions:\", num_solutions)\n", - " print(\"failures:\", solver.Failures())\n", - " print(\"branches:\", solver.Branches())\n", - " print(\"WallTime:\", solver.WallTime())\n", - " print()\n", "\n", "def print_solution(x, len1, len2, x_len):\n", " print(\"\".join([str(x[i]) for i in range(len1)]), \"*\", end=\" \")\n", @@ -225,7 +220,18 @@ "\n", "\n", "base = 10\n", - "start = 1\n" + "start = 1\n", + "if len(sys.argv) > 1:\n", + " base = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " start = int(sys.argv[2])\n", + "\n", + "x_len = base - 1 + 1 - start\n", + "for len1 in range(1 + (x_len)):\n", + " for len2 in range(1 + (x_len)):\n", + " if x_len > len1 + len2:\n", + " main(base, start, len1, len2)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/photo_problem.ipynb b/examples/notebook/contrib/photo_problem.ipynb index 8813d9175d..e6ce9d9adb 100644 --- a/examples/notebook/contrib/photo_problem.ipynb +++ b/examples/notebook/contrib/photo_problem.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Photo problem in Google CP Solver.\n", "\n", @@ -119,109 +104,123 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(show_all_max=0):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Photo problem\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Photo problem\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "persons = [\"Betty\", \"Chris\", \"Donald\", \"Fred\", \"Gary\", \"Mary\", \"Paul\"]\n", - "n = len(persons)\n", - "preferences = [\n", - " # 0 1 2 3 4 5 6\n", - " # B C D F G M P\n", - " [0, 0, 0, 0, 1, 1, 0], # Betty 0\n", - " [1, 0, 0, 0, 1, 0, 0], # Chris 1\n", - " [0, 0, 0, 0, 0, 0, 0], # Donald 2\n", - " [0, 0, 1, 0, 0, 1, 0], # Fred 3\n", - " [0, 0, 0, 0, 0, 0, 0], # Gary 4\n", - " [0, 0, 0, 0, 0, 0, 0], # Mary 5\n", - " [0, 0, 1, 1, 0, 0, 0] # Paul 6\n", - "]\n", + " #\n", + " # data\n", + " #\n", + " persons = [\"Betty\", \"Chris\", \"Donald\", \"Fred\", \"Gary\", \"Mary\", \"Paul\"]\n", + " n = len(persons)\n", + " preferences = [\n", + " # 0 1 2 3 4 5 6\n", + " # B C D F G M P\n", + " [0, 0, 0, 0, 1, 1, 0], # Betty 0\n", + " [1, 0, 0, 0, 1, 0, 0], # Chris 1\n", + " [0, 0, 0, 0, 0, 0, 0], # Donald 2\n", + " [0, 0, 1, 0, 0, 1, 0], # Fred 3\n", + " [0, 0, 0, 0, 0, 0, 0], # Gary 4\n", + " [0, 0, 0, 0, 0, 0, 0], # Mary 5\n", + " [0, 0, 1, 1, 0, 0, 0] # Paul 6\n", + " ]\n", "\n", - "print(\"\"\"Preferences:\n", - " 1. Betty wants to stand next to Gary and Mary.\n", - " 2. Chris wants to stand next to Betty and Gary.\n", - " 3. Fred wants to stand next to Mary and Donald.\n", - " 4. Paul wants to stand next to Fred and Donald.\n", - " \"\"\")\n", + " print(\"\"\"Preferences:\n", + " 1. Betty wants to stand next to Gary and Mary.\n", + " 2. Chris wants to stand next to Betty and Gary.\n", + " 3. Fred wants to stand next to Mary and Donald.\n", + " 4. Paul wants to stand next to Fred and Donald.\n", + " \"\"\")\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "positions = [solver.IntVar(0, n - 1, \"positions[%i]\" % i) for i in range(n)]\n", + " #\n", + " # declare variables\n", + " #\n", + " positions = [solver.IntVar(0, n - 1, \"positions[%i]\" % i) for i in range(n)]\n", "\n", - "# successful preferences\n", - "z = solver.IntVar(0, n * n, \"z\")\n", + " # successful preferences\n", + " z = solver.IntVar(0, n * n, \"z\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(positions))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(positions))\n", "\n", - "# calculate all the successful preferences\n", - "b = [\n", - " solver.IsEqualCstVar(abs(positions[i] - positions[j]), 1)\n", - " for i in range(n)\n", - " for j in range(n)\n", - " if preferences[i][j] == 1\n", - "]\n", - "solver.Add(z == solver.Sum(b))\n", + " # calculate all the successful preferences\n", + " b = [\n", + " solver.IsEqualCstVar(abs(positions[i] - positions[j]), 1)\n", + " for i in range(n)\n", + " for j in range(n)\n", + " if preferences[i][j] == 1\n", + " ]\n", + " solver.Add(z == solver.Sum(b))\n", "\n", - "#\n", - "# Symmetry breaking (from the Oz page):\n", - "# Fred is somewhere left of Betty\n", - "solver.Add(positions[3] < positions[0])\n", + " #\n", + " # Symmetry breaking (from the Oz page):\n", + " # Fred is somewhere left of Betty\n", + " solver.Add(positions[3] < positions[0])\n", "\n", - "# objective\n", - "objective = solver.Maximize(z, 1)\n", - "if show_all_max != 0:\n", - " print(\"Showing all maximum solutions (z == 6).\\n\")\n", - " solver.Add(z == 6)\n", + " # objective\n", + " objective = solver.Maximize(z, 1)\n", + " if show_all_max != 0:\n", + " print(\"Showing all maximum solutions (z == 6).\\n\")\n", + " solver.Add(z == 6)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(positions, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MAX_VALUE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(positions, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MAX_VALUE)\n", "\n", - "if show_all_max == 0:\n", - " solver.NewSearch(db, [objective])\n", - "else:\n", - " solver.NewSearch(db)\n", + " if show_all_max == 0:\n", + " solver.NewSearch(db, [objective])\n", + " else:\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"z:\", z.Value())\n", - " p = [positions[i].Value() for i in range(n)]\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"z:\", z.Value())\n", + " p = [positions[i].Value() for i in range(n)]\n", + "\n", + " print(\" \".join(\n", + " [persons[j] for i in range(n) for j in range(n) if p[j] == i]))\n", + " print(\"Successful preferences:\")\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if preferences[i][j] == 1 and abs(p[i] - p[j]) == 1:\n", + " print(\"\\t\", persons[i], persons[j])\n", + " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", - " print(\" \".join(\n", - " [persons[j] for i in range(n) for j in range(n) if p[j] == i]))\n", - " print(\"Successful preferences:\")\n", - " for i in range(n):\n", - " for j in range(n):\n", - " if preferences[i][j] == 1 and abs(p[i] - p[j]) == 1:\n", - " print(\"\\t\", persons[i], persons[j])\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "\n", - "show_all_max = 0 # show all maximal solutions\n" + "show_all_max = 0 # show all maximal solutions\n", + "if len(sys.argv) > 1:\n", + " show_all_max = 1\n", + "main(show_all_max)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/place_number_puzzle.ipynb b/examples/notebook/contrib/place_number_puzzle.ipynb index f60dcfa74a..beef14b47e 100644 --- a/examples/notebook/contrib/place_number_puzzle.ipynb +++ b/examples/notebook/contrib/place_number_puzzle.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Place number puzzle Google CP Solver.\n", "\n", @@ -113,61 +98,73 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Place number\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Place number\")\n", "\n", - "# data\n", - "m = 32\n", - "n = 8\n", - "# Note: this is 1-based for compatibility (and lazyness)\n", - "graph = [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 5], [2, 6], [3, 2],\n", - " [3, 4], [3, 6], [3, 7], [4, 1], [4, 3], [4, 6], [4, 7], [5, 2],\n", - " [5, 3], [5, 6], [5, 8], [6, 2], [6, 3], [6, 4], [6, 5], [6, 7],\n", - " [6, 8], [7, 3], [7, 4], [7, 6], [7, 8], [8, 5], [8, 6], [8, 7]]\n", + " # data\n", + " m = 32\n", + " n = 8\n", + " # Note: this is 1-based for compatibility (and lazyness)\n", + " graph = [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 5], [2, 6], [3, 2],\n", + " [3, 4], [3, 6], [3, 7], [4, 1], [4, 3], [4, 6], [4, 7], [5, 2],\n", + " [5, 3], [5, 6], [5, 8], [6, 2], [6, 3], [6, 4], [6, 5], [6, 7],\n", + " [6, 8], [7, 3], [7, 4], [7, 6], [7, 8], [8, 5], [8, 6], [8, 7]]\n", "\n", - "# declare variables\n", - "x = [solver.IntVar(1, n, \"x%i\" % i) for i in range(n)]\n", + " # declare variables\n", + " x = [solver.IntVar(1, n, \"x%i\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", - "for i in range(m):\n", - " # Note: make 0-based\n", - " solver.Add(abs(x[graph[i][0] - 1] - x[graph[i][1] - 1]) > 1)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", + " for i in range(m):\n", + " # Note: make 0-based\n", + " solver.Add(abs(x[graph[i][0] - 1] - x[graph[i][1] - 1]) > 1)\n", "\n", - "# symmetry breaking\n", - "solver.Add(x[0] < x[n - 1])\n", + " # symmetry breaking\n", + " solver.Add(x[0] < x[n - 1])\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", + " collector = solver.AllSolutionCollector(solution)\n", "\n", - "solver.Solve(\n", - " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE),\n", - " [collector])\n", + " solver.Solve(\n", + " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE),\n", + " [collector])\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "for s in range(num_solutions):\n", - " print(\"x:\", [collector.Value(s, x[i]) for i in range(len(x))])\n", + " num_solutions = collector.SolutionCount()\n", + " for s in range(num_solutions):\n", + " print(\"x:\", [collector.Value(s, x[i]) for i in range(len(x))])\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print()\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/post_office_problem2.ipynb b/examples/notebook/contrib/post_office_problem2.ipynb index a2ced90183..d2ef79a580 100644 --- a/examples/notebook/contrib/post_office_problem2.ipynb +++ b/examples/notebook/contrib/post_office_problem2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Post office problem in Google CP Solver.\n", "\n", @@ -127,77 +112,89 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Post office problem')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Post office problem')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "# days 0..6, monday 0\n", - "n = 7\n", - "days = list(range(n))\n", - "need = [17, 13, 15, 19, 14, 16, 11]\n", + " # days 0..6, monday 0\n", + " n = 7\n", + " days = list(range(n))\n", + " need = [17, 13, 15, 19, 14, 16, 11]\n", "\n", - "# Total cost for the 5 day schedule.\n", - "# Base cost per day is 100.\n", - "# Working saturday is 100 extra\n", - "# Working sunday is 200 extra.\n", - "cost = [500, 600, 800, 800, 800, 800, 700]\n", + " # Total cost for the 5 day schedule.\n", + " # Base cost per day is 100.\n", + " # Working saturday is 100 extra\n", + " # Working sunday is 200 extra.\n", + " cost = [500, 600, 800, 800, 800, 800, 700]\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "# No. of workers starting at day i\n", - "x = [solver.IntVar(0, 100, 'x[%i]' % i) for i in days]\n", + " # No. of workers starting at day i\n", + " x = [solver.IntVar(0, 100, 'x[%i]' % i) for i in days]\n", "\n", - "total_cost = solver.IntVar(0, 20000, 'total_cost')\n", - "num_workers = solver.IntVar(0, 100, 'num_workers')\n", + " total_cost = solver.IntVar(0, 20000, 'total_cost')\n", + " num_workers = solver.IntVar(0, 100, 'num_workers')\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(total_cost == solver.ScalProd(x, cost))\n", - "solver.Add(num_workers == solver.Sum(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(total_cost == solver.ScalProd(x, cost))\n", + " solver.Add(num_workers == solver.Sum(x))\n", "\n", - "for i in days:\n", - " s = solver.Sum(\n", - " [x[j] for j in days if j != (i + 5) % n and j != (i + 6) % n])\n", - " solver.Add(s >= need[i])\n", + " for i in days:\n", + " s = solver.Sum(\n", + " [x[j] for j in days if j != (i + 5) % n and j != (i + 6) % n])\n", + " solver.Add(s >= need[i])\n", "\n", - "# objective\n", - "objective = solver.Minimize(total_cost, 1)\n", + " # objective\n", + " objective = solver.Minimize(total_cost, 1)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db, [objective])\n", + " solver.NewSearch(db, [objective])\n", "\n", - "num_solutions = 0\n", + " num_solutions = 0\n", "\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('num_workers:', num_workers.Value())\n", - " print('total_cost:', total_cost.Value())\n", - " print('x:', [x[i].Value() for i in days])\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('num_workers:', num_workers.Value())\n", + " print('total_cost:', total_cost.Value())\n", + " print('x:', [x[i].Value() for i in days])\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime())\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/production.ipynb b/examples/notebook/contrib/production.ipynb index 19c3cf81ba..f0b6c648dd 100644 --- a/examples/notebook/contrib/production.ipynb +++ b/examples/notebook/contrib/production.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Production planning problem in Google or-tools.\n", "\n", @@ -95,90 +80,110 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol='CBC'):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "# using GLPK\n", - "if sol == 'GLPK':\n", - " solver = pywraplp.Solver('CoinsGridGLPK',\n", - " pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", - "else:\n", - " # Using CLP\n", - " solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", + " # using GLPK\n", + " if sol == 'GLPK':\n", + " solver = pywraplp.Solver('CoinsGridGLPK',\n", + " pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", + " else:\n", + " # Using CLP\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", "\n", - "#\n", - "# data\n", - "#\n", - "kluski = 0\n", - "capellini = 1\n", - "fettucine = 2\n", - "products = ['kluski', 'capellini', 'fettucine']\n", - "num_products = len(products)\n", + " #\n", + " # data\n", + " #\n", + " kluski = 0\n", + " capellini = 1\n", + " fettucine = 2\n", + " products = ['kluski', 'capellini', 'fettucine']\n", + " num_products = len(products)\n", "\n", - "flour = 0\n", - "eggs = 1\n", - "resources = ['flour', 'eggs']\n", - "num_resources = len(resources)\n", + " flour = 0\n", + " eggs = 1\n", + " resources = ['flour', 'eggs']\n", + " num_resources = len(resources)\n", "\n", - "consumption = [[0.5, 0.2], [0.4, 0.4], [0.3, 0.6]]\n", - "capacity = [20, 40]\n", - "demand = [100, 200, 300]\n", - "inside_cost = [0.6, 0.8, 0.3]\n", - "outside_cost = [0.8, 0.9, 0.4]\n", + " consumption = [[0.5, 0.2], [0.4, 0.4], [0.3, 0.6]]\n", + " capacity = [20, 40]\n", + " demand = [100, 200, 300]\n", + " inside_cost = [0.6, 0.8, 0.3]\n", + " outside_cost = [0.8, 0.9, 0.4]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "inside = [\n", - " solver.NumVar(0, 10000, 'inside[%i]' % p) for p in range(num_products)\n", - "]\n", - "outside = [\n", - " solver.NumVar(0, 10000, 'outside[%i]' % p) for p in range(num_products)\n", - "]\n", + " #\n", + " # declare variables\n", + " #\n", + " inside = [\n", + " solver.NumVar(0, 10000, 'inside[%i]' % p) for p in range(num_products)\n", + " ]\n", + " outside = [\n", + " solver.NumVar(0, 10000, 'outside[%i]' % p) for p in range(num_products)\n", + " ]\n", "\n", - "# to minimize\n", - "z = solver.Sum([\n", - " inside_cost[p] * inside[p] + outside_cost[p] * outside[p]\n", - " for p in range(num_products)\n", - "])\n", + " # to minimize\n", + " z = solver.Sum([\n", + " inside_cost[p] * inside[p] + outside_cost[p] * outside[p]\n", + " for p in range(num_products)\n", + " ])\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for r in range(num_resources):\n", - " solver.Add(\n", - " solver.Sum([consumption[p][r] * inside[p]\n", - " for p in range(num_products)]) <= capacity[r])\n", + " #\n", + " # constraints\n", + " #\n", + " for r in range(num_resources):\n", + " solver.Add(\n", + " solver.Sum([consumption[p][r] * inside[p]\n", + " for p in range(num_products)]) <= capacity[r])\n", "\n", - "for p in range(num_products):\n", - " solver.Add(inside[p] + outside[p] >= demand[p])\n", + " for p in range(num_products):\n", + " solver.Add(inside[p] + outside[p] >= demand[p])\n", "\n", - "objective = solver.Minimize(z)\n", + " objective = solver.Minimize(z)\n", "\n", - "solver.Solve()\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('z = ', solver.Objective().Value())\n", + " print()\n", + " print('z = ', solver.Objective().Value())\n", "\n", - "for p in range(num_products):\n", - " print(\n", - " products[p],\n", - " ': inside:',\n", - " inside[p].SolutionValue(),\n", - " '(ReducedCost:',\n", - " inside[p].ReducedCost(),\n", - " ')',\n", - " end=' ')\n", - " print('outside:', outside[p].SolutionValue(), ' (ReducedCost:',\n", - " outside[p].ReducedCost(), ')')\n", - "print()\n", + " for p in range(num_products):\n", + " print(\n", + " products[p],\n", + " ': inside:',\n", + " inside[p].SolutionValue(),\n", + " '(ReducedCost:',\n", + " inside[p].ReducedCost(),\n", + " ')',\n", + " end=' ')\n", + " print('outside:', outside[p].SolutionValue(), ' (ReducedCost:',\n", + " outside[p].ReducedCost(), ')')\n", + " print()\n", + "\n", + "\n", + "\n", + "sol = 'CBC'\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != 'GLPK' and sol != 'CBC':\n", + " print('Solver must be either GLPK or CBC')\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/project_scheduling_sat.ipynb b/examples/notebook/contrib/project_scheduling_sat.ipynb index 07aa0d1ac9..f3a4ecfe23 100644 --- a/examples/notebook/contrib/project_scheduling_sat.ipynb +++ b/examples/notebook/contrib/project_scheduling_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { diff --git a/examples/notebook/contrib/pyls_api.ipynb b/examples/notebook/contrib/pyls_api.ipynb index 15115862fe..49078c05a9 100644 --- a/examples/notebook/contrib/pyls_api.ipynb +++ b/examples/notebook/contrib/pyls_api.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -189,9 +189,13 @@ " print('Objective value = %d' % collector.ObjectiveValue(0))\n", "\n", "\n", - "Solve(0)\n", - "Solve(1)\n", - "Solve(2)\n", + "def main():\n", + " Solve(0)\n", + " Solve(1)\n", + " Solve(2)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/quasigroup_completion.ipynb b/examples/notebook/contrib/quasigroup_completion.ipynb index 068c2d1e94..14f1b691c5 100644 --- a/examples/notebook/contrib/quasigroup_completion.ipynb +++ b/examples/notebook/contrib/quasigroup_completion.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Quasigroup completion Google CP Solver.\n", "\n", @@ -126,8 +111,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -139,106 +132,108 @@ " [X, 4, X, X, X], [X, X, 5, X, 1]]\n", "\n", "\n", + "def main(puzzle=\"\", n=0):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Quasigroup completion\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Quasigroup completion\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "if puzzle == \"\":\n", - " puzzle = default_puzzle\n", - " n = default_n\n", + " if puzzle == \"\":\n", + " puzzle = default_puzzle\n", + " n = default_n\n", "\n", - "print(\"Problem:\")\n", - "print_game(puzzle, n, n)\n", + " print(\"Problem:\")\n", + " print_game(puzzle, n, n)\n", "\n", - "# declare variables\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[(i, j)] = solver.IntVar(1, n, \"x %i %i\" % (i, j))\n", - "\n", - "xflat = [x[(i, j)] for i in range(n) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "#\n", - "# set the clues\n", - "#\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if puzzle[i][j] > X:\n", - " solver.Add(x[i, j] == puzzle[i][j])\n", - "\n", - "#\n", - "# rows and columns must be different\n", - "#\n", - "for i in range(n):\n", - " solver.Add(solver.AllDifferent([x[i, j] for j in range(n)]))\n", - " solver.Add(solver.AllDifferent([x[j, i] for j in range(n)]))\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(xflat)\n", - "\n", - "# This version prints out the solution directly, and\n", - "# don't collect them as solver.FirstSolutionCollector(solution) do\n", - "# (db: DecisionBuilder)\n", - "db = solver.Phase(xflat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"Solution %i\" % num_solutions)\n", - " xval = [x[(i, j)].Value() for i in range(n) for j in range(n)]\n", + " # declare variables\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " print(xval[i * n + j], end=\" \")\n", + " x[(i, j)] = solver.IntVar(1, n, \"x %i %i\" % (i, j))\n", + "\n", + " xflat = [x[(i, j)] for i in range(n) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " #\n", + " # set the clues\n", + " #\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if puzzle[i][j] > X:\n", + " solver.Add(x[i, j] == puzzle[i][j])\n", + "\n", + " #\n", + " # rows and columns must be different\n", + " #\n", + " for i in range(n):\n", + " solver.Add(solver.AllDifferent([x[i, j] for j in range(n)]))\n", + " solver.Add(solver.AllDifferent([x[j, i] for j in range(n)]))\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(xflat)\n", + "\n", + " # This version prints out the solution directly, and\n", + " # don't collect them as solver.FirstSolutionCollector(solution) do\n", + " # (db: DecisionBuilder)\n", + " db = solver.Phase(xflat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"Solution %i\" % num_solutions)\n", + " xval = [x[(i, j)].Value() for i in range(n) for j in range(n)]\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(xval[i * n + j], end=\" \")\n", + " print()\n", " print()\n", + " solver.EndSearch()\n", + "\n", + " if num_solutions == 0:\n", + " print(\"No solutions found\")\n", + "\n", + " # # Note: AllSolution may take very much RAM, hence I choose to\n", + " # # show just the first solution.\n", + " # # collector = solver.AllSolutionCollector(solution)\n", + " # collector = solver.FirstSolutionCollector(solution)\n", + " # solver.Solve(solver.Phase([x[(i,j)] for i in range(n) for j in range(n)],\n", + " # solver.CHOOSE_FIRST_UNBOUND,\n", + " # solver.ASSIGN_MIN_VALUE),\n", + " # [collector])\n", + " #\n", + " # num_solutions = collector.SolutionCount()\n", + " # print \"\\nnum_solutions: \", num_solutions\n", + " # if num_solutions > 0:\n", + " # print \"\\nJust showing the first solution...\"\n", + " # for s in range(num_solutions):\n", + " # xval = [collector.Value(s, x[(i,j)]) for i in range(n) for j in range(n)]\n", + " # for i in range(n):\n", + " # for j in range(n):\n", + " # print xval[i*n+j],\n", + " # print\n", + " # print\n", + "\n", " print()\n", - "solver.EndSearch()\n", - "\n", - "if num_solutions == 0:\n", - " print(\"No solutions found\")\n", - "\n", - "# # Note: AllSolution may take very much RAM, hence I choose to\n", - "# # show just the first solution.\n", - "# # collector = solver.AllSolutionCollector(solution)\n", - "# collector = solver.FirstSolutionCollector(solution)\n", - "# solver.Solve(solver.Phase([x[(i,j)] for i in range(n) for j in range(n)],\n", - "# solver.CHOOSE_FIRST_UNBOUND,\n", - "# solver.ASSIGN_MIN_VALUE),\n", - "# [collector])\n", - "#\n", - "# num_solutions = collector.SolutionCount()\n", - "# print \"\\nnum_solutions: \", num_solutions\n", - "# if num_solutions > 0:\n", - "# print \"\\nJust showing the first solution...\"\n", - "# for s in range(num_solutions):\n", - "# xval = [collector.Value(s, x[(i,j)]) for i in range(n) for j in range(n)]\n", - "# for i in range(n):\n", - "# for j in range(n):\n", - "# print xval[i*n+j],\n", - "# print\n", - "# print\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", "\n", "#\n", "# Read a problem instance from a file\n", - "#def read_problem(file):\n", + "#\n", + "def read_problem(file):\n", " f = open(file, \"r\")\n", " n = int(f.readline())\n", " game = []\n", @@ -269,6 +264,15 @@ " print(\"% 2s\" % game[i][j], end=\" \")\n", " print(\"\")\n", "\n", + "\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " print(\"Problem instance from\", file)\n", + " [game, n] = read_problem(file)\n", + " main(game, n)\n", + "else:\n", + " main()\n", "\n" ] } diff --git a/examples/notebook/contrib/regular.ipynb b/examples/notebook/contrib/regular.ipynb index f0e4bbf406..91243b3905 100644 --- a/examples/notebook/contrib/regular.ipynb +++ b/examples/notebook/contrib/regular.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Global constraint regular in Google CP Solver.\n", "\n", @@ -111,8 +96,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", @@ -241,57 +234,61 @@ " return t_matrix\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Regular test')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Regular test')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "this_len = 10\n", - "pp = [3, 2, 1]\n", + " this_len = 10\n", + " pp = [3, 2, 1]\n", "\n", - "transition_fn = make_transition_matrix(pp)\n", - "n_states = len(transition_fn)\n", - "input_max = 2\n", + " transition_fn = make_transition_matrix(pp)\n", + " n_states = len(transition_fn)\n", + " input_max = 2\n", "\n", - "# Note: we use '1' and '2' (rather than 0 and 1)\n", - "# since 0 represents the failing state.\n", - "initial_state = 1\n", + " # Note: we use '1' and '2' (rather than 0 and 1)\n", + " # since 0 represents the failing state.\n", + " initial_state = 1\n", "\n", - "accepting_states = [n_states]\n", + " accepting_states = [n_states]\n", "\n", - "# declare variables\n", - "reg_input = [\n", - " solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len)\n", - "]\n", + " # declare variables\n", + " reg_input = [\n", + " solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len)\n", + " ]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", - " accepting_states)\n", + " #\n", + " # constraints\n", + " #\n", + " regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", + " accepting_states)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print('reg_input:', [reg_input[i].Value() - 1 for i in range(this_len)])\n", - " num_solutions += 1\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print('reg_input:', [reg_input[i].Value() - 1 for i in range(this_len)])\n", + " num_solutions += 1\n", "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " solver.EndSearch()\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/regular_table.ipynb b/examples/notebook/contrib/regular_table.ipynb index 5587988ae7..932713e7c4 100644 --- a/examples/notebook/contrib/regular_table.ipynb +++ b/examples/notebook/contrib/regular_table.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Global constraint regular in Google CP Solver.\n", "\n", @@ -111,8 +96,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", @@ -234,57 +227,61 @@ " return t_matrix\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Regular test')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Regular test')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "this_len = 10\n", - "pp = [3, 2, 1]\n", + " this_len = 10\n", + " pp = [3, 2, 1]\n", "\n", - "transition_fn = make_transition_matrix(pp)\n", - "n_states = len(transition_fn)\n", - "input_max = 2\n", + " transition_fn = make_transition_matrix(pp)\n", + " n_states = len(transition_fn)\n", + " input_max = 2\n", "\n", - "# Note: we use '1' and '2' (rather than 0 and 1)\n", - "# since 0 represents the failing state.\n", - "initial_state = 1\n", + " # Note: we use '1' and '2' (rather than 0 and 1)\n", + " # since 0 represents the failing state.\n", + " initial_state = 1\n", "\n", - "accepting_states = [n_states]\n", + " accepting_states = [n_states]\n", "\n", - "# declare variables\n", - "reg_input = [\n", - " solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len)\n", - "]\n", + " # declare variables\n", + " reg_input = [\n", + " solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len)\n", + " ]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", - " accepting_states)\n", + " #\n", + " # constraints\n", + " #\n", + " regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", + " accepting_states)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print('reg_input:', [reg_input[i].Value() - 1 for i in range(this_len)])\n", - " num_solutions += 1\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print('reg_input:', [reg_input[i].Value() - 1 for i in range(this_len)])\n", + " num_solutions += 1\n", "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " solver.EndSearch()\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/regular_table2.ipynb b/examples/notebook/contrib/regular_table2.ipynb index cc2da813c3..109e4c5a7b 100644 --- a/examples/notebook/contrib/regular_table2.ipynb +++ b/examples/notebook/contrib/regular_table2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Global constraint regular in Google CP Solver.\n", "\n", @@ -111,8 +96,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", @@ -218,57 +211,61 @@ " return t_matrix\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Regular test')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Regular test')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "this_len = 10\n", - "pp = [3, 2, 1]\n", + " this_len = 10\n", + " pp = [3, 2, 1]\n", "\n", - "transition_fn = make_transition_matrix(pp)\n", - "n_states = len(transition_fn)\n", - "input_max = 2\n", + " transition_fn = make_transition_matrix(pp)\n", + " n_states = len(transition_fn)\n", + " input_max = 2\n", "\n", - "# Note: we use '1' and '2' (rather than 0 and 1)\n", - "# since 0 represents the failing state.\n", - "initial_state = 1\n", + " # Note: we use '1' and '2' (rather than 0 and 1)\n", + " # since 0 represents the failing state.\n", + " initial_state = 1\n", "\n", - "accepting_states = [n_states]\n", + " accepting_states = [n_states]\n", "\n", - "# declare variables\n", - "reg_input = [\n", - " solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len)\n", - "]\n", + " # declare variables\n", + " reg_input = [\n", + " solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len)\n", + " ]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", - " accepting_states)\n", + " #\n", + " # constraints\n", + " #\n", + " regular(reg_input, n_states, input_max, transition_fn, initial_state,\n", + " accepting_states)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX,\n", + " solver.ASSIGN_MIN_VALUE)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print('reg_input:', [reg_input[i].Value() - 1 for i in range(this_len)])\n", - " num_solutions += 1\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print('reg_input:', [reg_input[i].Value() - 1 for i in range(this_len)])\n", + " num_solutions += 1\n", "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " solver.EndSearch()\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/rogo2.ipynb b/examples/notebook/contrib/rogo2.ipynb index 48b340ea82..06ae6e8ff9 100644 --- a/examples/notebook/contrib/rogo2.ipynb +++ b/examples/notebook/contrib/rogo2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Rogo puzzle solver in Google CP Solver.\n", "\n", @@ -118,128 +103,137 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "import re\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(problem, rows, cols, max_steps):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Rogo grid puzzle\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Rogo grid puzzle\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "W = 0\n", - "B = -1\n", - "print(\"rows: %i cols: %i max_steps: %i\" % (rows, cols, max_steps))\n", + " #\n", + " # data\n", + " #\n", + " W = 0\n", + " B = -1\n", + " print(\"rows: %i cols: %i max_steps: %i\" % (rows, cols, max_steps))\n", "\n", - "problem_flatten = [problem[i][j] for i in range(rows) for j in range(cols)]\n", - "max_point = max(problem_flatten)\n", - "print(\"max_point:\", max_point)\n", - "max_sum = sum(problem_flatten)\n", - "print(\"max_sum:\", max_sum)\n", - "print()\n", - "\n", - "#\n", - "# declare variables\n", - "#\n", - "\n", - "# the coordinates\n", - "x = [solver.IntVar(0, rows - 1, \"x[%i]\" % i) for i in range(max_steps)]\n", - "y = [solver.IntVar(0, cols - 1, \"y[%i]\" % i) for i in range(max_steps)]\n", - "\n", - "# the collected points\n", - "points = [\n", - " solver.IntVar(0, max_point, \"points[%i]\" % i) for i in range(max_steps)\n", - "]\n", - "\n", - "# objective: sum of points in the path\n", - "sum_points = solver.IntVar(0, max_sum)\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# all coordinates must be unique\n", - "for s in range(max_steps):\n", - " for t in range(s + 1, max_steps):\n", - " b1 = x[s] != x[t]\n", - " b2 = y[s] != y[t]\n", - " solver.Add(b1 + b2 >= 1)\n", - "\n", - "# calculate the points (to maximize)\n", - "for s in range(max_steps):\n", - " solver.Add(points[s] == solver.Element(problem_flatten, x[s] * cols + y[s]))\n", - "\n", - "solver.Add(sum_points == sum(points))\n", - "\n", - "# ensure that there are not black cells in\n", - "# the path\n", - "for s in range(max_steps):\n", - " solver.Add(solver.Element(problem_flatten, x[s] * cols + y[s]) != B)\n", - "\n", - "# get the path\n", - "for s in range(max_steps - 1):\n", - " solver.Add(abs(x[s] - x[s + 1]) + abs(y[s] - y[s + 1]) == 1)\n", - "\n", - "# close the path around the corner\n", - "solver.Add(abs(x[max_steps - 1] - x[0]) + abs(y[max_steps - 1] - y[0]) == 1)\n", - "\n", - "# symmetry breaking: the cell with lowest coordinates\n", - "# should be in the first step.\n", - "for i in range(1, max_steps):\n", - " solver.Add(x[0] * cols + y[0] < x[i] * cols + y[i])\n", - "\n", - "# symmetry breaking: second step is larger than\n", - "# first step\n", - "# solver.Add(x[0]*cols+y[0] < x[1]*cols+y[1])\n", - "\n", - "#\n", - "# objective\n", - "#\n", - "objective = solver.Maximize(sum_points, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "# db = solver.Phase(x + y,\n", - "# solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - "# solver.ASSIGN_MIN_VALUE)\n", - "\n", - "# Default search\n", - "parameters = pywrapcp.DefaultPhaseParameters()\n", - "\n", - "parameters.heuristic_period = 200000\n", - "# parameters.var_selection_schema = parameters.CHOOSE_MAX_SUM_IMPACT\n", - "parameters.var_selection_schema = parameters.CHOOSE_MAX_AVERAGE_IMPACT # <-\n", - "# parameters.var_selection_schema = parameters.CHOOSE_MAX_VALUE_IMPACT\n", - "\n", - "parameters.value_selection_schema = parameters.SELECT_MIN_IMPACT # <-\n", - "# parameters.value_selection_schema = parameters.SELECT_MAX_IMPACT\n", - "\n", - "# parameters.initialization_splits = 10\n", - "\n", - "db = solver.DefaultPhase(x + y, parameters)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"sum_points:\", sum_points.Value())\n", - " print(\"adding 1 to coords...\")\n", - " for s in range(max_steps):\n", - " print(\"%i %i\" % (x[s].Value() + 1, y[s].Value() + 1))\n", + " problem_flatten = [problem[i][j] for i in range(rows) for j in range(cols)]\n", + " max_point = max(problem_flatten)\n", + " print(\"max_point:\", max_point)\n", + " max_sum = sum(problem_flatten)\n", + " print(\"max_sum:\", max_sum)\n", " print()\n", "\n", - "print(\"\\nnum_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " #\n", + " # declare variables\n", + " #\n", + "\n", + " # the coordinates\n", + " x = [solver.IntVar(0, rows - 1, \"x[%i]\" % i) for i in range(max_steps)]\n", + " y = [solver.IntVar(0, cols - 1, \"y[%i]\" % i) for i in range(max_steps)]\n", + "\n", + " # the collected points\n", + " points = [\n", + " solver.IntVar(0, max_point, \"points[%i]\" % i) for i in range(max_steps)\n", + " ]\n", + "\n", + " # objective: sum of points in the path\n", + " sum_points = solver.IntVar(0, max_sum)\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # all coordinates must be unique\n", + " for s in range(max_steps):\n", + " for t in range(s + 1, max_steps):\n", + " b1 = x[s] != x[t]\n", + " b2 = y[s] != y[t]\n", + " solver.Add(b1 + b2 >= 1)\n", + "\n", + " # calculate the points (to maximize)\n", + " for s in range(max_steps):\n", + " solver.Add(points[s] == solver.Element(problem_flatten, x[s] * cols + y[s]))\n", + "\n", + " solver.Add(sum_points == sum(points))\n", + "\n", + " # ensure that there are not black cells in\n", + " # the path\n", + " for s in range(max_steps):\n", + " solver.Add(solver.Element(problem_flatten, x[s] * cols + y[s]) != B)\n", + "\n", + " # get the path\n", + " for s in range(max_steps - 1):\n", + " solver.Add(abs(x[s] - x[s + 1]) + abs(y[s] - y[s + 1]) == 1)\n", + "\n", + " # close the path around the corner\n", + " solver.Add(abs(x[max_steps - 1] - x[0]) + abs(y[max_steps - 1] - y[0]) == 1)\n", + "\n", + " # symmetry breaking: the cell with lowest coordinates\n", + " # should be in the first step.\n", + " for i in range(1, max_steps):\n", + " solver.Add(x[0] * cols + y[0] < x[i] * cols + y[i])\n", + "\n", + " # symmetry breaking: second step is larger than\n", + " # first step\n", + " # solver.Add(x[0]*cols+y[0] < x[1]*cols+y[1])\n", + "\n", + " #\n", + " # objective\n", + " #\n", + " objective = solver.Maximize(sum_points, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " # db = solver.Phase(x + y,\n", + " # solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " # solver.ASSIGN_MIN_VALUE)\n", + "\n", + " # Default search\n", + " parameters = pywrapcp.DefaultPhaseParameters()\n", + "\n", + " parameters.heuristic_period = 200000\n", + " # parameters.var_selection_schema = parameters.CHOOSE_MAX_SUM_IMPACT\n", + " parameters.var_selection_schema = parameters.CHOOSE_MAX_AVERAGE_IMPACT # <-\n", + " # parameters.var_selection_schema = parameters.CHOOSE_MAX_VALUE_IMPACT\n", + "\n", + " parameters.value_selection_schema = parameters.SELECT_MIN_IMPACT # <-\n", + " # parameters.value_selection_schema = parameters.SELECT_MAX_IMPACT\n", + "\n", + " # parameters.initialization_splits = 10\n", + "\n", + " db = solver.DefaultPhase(x + y, parameters)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"sum_points:\", sum_points.Value())\n", + " print(\"adding 1 to coords...\")\n", + " for s in range(max_steps):\n", + " print(\"%i %i\" % (x[s].Value() + 1, y[s].Value() + 1))\n", + " print()\n", + "\n", + " print(\"\\nnum_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", "\n", "# Default problem:\n", @@ -249,14 +243,19 @@ "#\n", "# This has 48 solutions with symmetries;\n", "# 4 when the path symmetry is removed.\n", - "#rows = 5\n", + "#\n", + "rows = 5\n", "cols = 9\n", "max_steps = 12\n", "W = 0\n", "B = -1\n", "problem = [[2, W, W, W, W, W, W, W, W], [W, 3, W, W, 1, W, W, 2, W],\n", " [W, W, W, W, W, W, B, W, 2], [W, W, 2, B, W, W, W, W, W],\n", - " [W, W, W, W, 2, W, W, 1, W]]\n" + " [W, W, W, W, 2, W, W, 1, W]]\n", + "if len(sys.argv) > 1:\n", + " exec(compile(open(sys.argv[1]).read(), sys.argv[1], \"exec\"))\n", + "main(problem, rows, cols, max_steps)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/rostering_with_travel.ipynb b/examples/notebook/contrib/rostering_with_travel.ipynb index a98c49d56e..aaa4f9a316 100644 --- a/examples/notebook/contrib/rostering_with_travel.ipynb +++ b/examples/notebook/contrib/rostering_with_travel.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -184,7 +184,11 @@ " print(' - wall time : %f ms' % solver.WallTime())\n", "\n", "\n", - "SolveRosteringWithTravel()\n", + "def main():\n", + " SolveRosteringWithTravel()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/safe_cracking.ipynb b/examples/notebook/contrib/safe_cracking.ipynb index 75efc03096..7118dce680 100644 --- a/examples/notebook/contrib/safe_cracking.ipynb +++ b/examples/notebook/contrib/safe_cracking.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Safe cracking puzzle in Google CP Solver.\n", "\n", @@ -118,60 +103,72 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Safe cracking puzzle')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Safe cracking puzzle')\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 9\n", - "digits = list(range(1, n + 1))\n", + " #\n", + " # data\n", + " #\n", + " n = 9\n", + " digits = list(range(1, n + 1))\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "LD = [solver.IntVar(digits, 'LD[%i]' % i) for i in range(n)]\n", - "C1, C2, C3, C4, C5, C6, C7, C8, C9 = LD\n", + " LD = [solver.IntVar(digits, 'LD[%i]' % i) for i in range(n)]\n", + " C1, C2, C3, C4, C5, C6, C7, C8, C9 = LD\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(LD))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(LD))\n", "\n", - "solver.Add(C4 - C6 == C7)\n", - "solver.Add(C1 * C2 * C3 == C8 + C9)\n", - "solver.Add(C2 + C3 + C6 < C8)\n", - "solver.Add(C9 < C8)\n", - "for i in range(n):\n", - " solver.Add(LD[i] != i + 1)\n", + " solver.Add(C4 - C6 == C7)\n", + " solver.Add(C1 * C2 * C3 == C8 + C9)\n", + " solver.Add(C2 + C3 + C6 < C8)\n", + " solver.Add(C9 < C8)\n", + " for i in range(n):\n", + " solver.Add(LD[i] != i + 1)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(LD, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(LD, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", + " num_solutions = 0\n", "\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('LD:', [LD[i].Value() for i in range(n)])\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('LD:', [LD[i].Value() for i in range(n)])\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/scheduling_speakers.ipynb b/examples/notebook/contrib/scheduling_speakers.ipynb index ffb8ed0151..5aeb02d36c 100644 --- a/examples/notebook/contrib/scheduling_speakers.ipynb +++ b/examples/notebook/contrib/scheduling_speakers.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Scheduling speakers problem in Google CP Solver.\n", "\n", @@ -102,64 +87,76 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Scheduling speakers')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Scheduling speakers')\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 6 # number of speakers\n", + " #\n", + " # data\n", + " #\n", + " n = 6 # number of speakers\n", "\n", - "# slots available to speak\n", - "available = [\n", - " # Reasoning:\n", - " [3, 4, 5, 6], # 2) the only one with 6 after speaker F -> 1\n", - " [3, 4], # 5) 3 or 4\n", - " [2, 3, 4, 5], # 3) only with 5 after F -> 1 and A -> 6\n", - " [2, 3, 4], # 4) only with 2 after C -> 5 and F -> 1\n", - " [3, 4], # 5) 3 or 4\n", - " [1, 2, 3, 4, 5, 6] # 1) the only with 1\n", - "]\n", + " # slots available to speak\n", + " available = [\n", + " # Reasoning:\n", + " [3, 4, 5, 6], # 2) the only one with 6 after speaker F -> 1\n", + " [3, 4], # 5) 3 or 4\n", + " [2, 3, 4, 5], # 3) only with 5 after F -> 1 and A -> 6\n", + " [2, 3, 4], # 4) only with 2 after C -> 5 and F -> 1\n", + " [3, 4], # 5) 3 or 4\n", + " [1, 2, 3, 4, 5, 6] # 1) the only with 1\n", + " ]\n", "\n", - "#\n", - "# variables\n", - "#\n", - "x = [solver.IntVar(1, n, 'x[%i]' % i) for i in range(n)]\n", + " #\n", + " # variables\n", + " #\n", + " x = [solver.IntVar(1, n, 'x[%i]' % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", "\n", - "for i in range(n):\n", - " solver.Add(solver.MemberCt(x[i], available[i]))\n", + " for i in range(n):\n", + " solver.Add(solver.MemberCt(x[i], available[i]))\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db)\n", + " solver.NewSearch(db)\n", "\n", - "num_solutions = 0\n", + " num_solutions = 0\n", "\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('x:', [x[i].Value() for i in range(n)])\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('x:', [x[i].Value() for i in range(n)])\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/scheduling_with_transitions_sat.ipynb b/examples/notebook/contrib/scheduling_with_transitions_sat.ipynb index 5e15e27b94..bf56218df9 100644 --- a/examples/notebook/contrib/scheduling_with_transitions_sat.ipynb +++ b/examples/notebook/contrib/scheduling_with_transitions_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,18 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Scheduling problem with transition time between tasks and transitions costs.\n", + "\n", + "@author: CSLiu2\n", + "\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,13 +86,6 @@ "metadata": {}, "outputs": [], "source": [ - "# -*- coding: utf-8 -*-\n", - "\"\"\"Scheduling problem with transition time between tasks and transitions costs.\n", - "\n", - "@author: CSLiu2\n", - "\"\"\"\n", - "\n", - "\n", "import argparse\n", "import collections\n", "\n", @@ -116,292 +121,296 @@ " self.__solution_count += 1\n", "\n", "\n", - "\"\"\"Solves the scheduling with transitions problem.\"\"\"\n", + "def main(args):\n", + " \"\"\"Solves the scheduling with transitions problem.\"\"\"\n", "\n", - "instance = args.problem_instance\n", - "parameters = args.params\n", - "output_proto = args.output_proto\n", + " instance = args.problem_instance\n", + " parameters = args.params\n", + " output_proto = args.output_proto\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Data.\n", - "small_jobs = [[[(100, 0, 'R6'), (2, 1, 'R6')]],\n", - " [[(2, 0, 'R3'), (100, 1, 'R3')]],\n", - " [[(100, 0, 'R1'), (16, 1, 'R1')]],\n", - " [[(1, 0, 'R1'), (38, 1, 'R1')]], [[(14, 0, 'R1'), (10, 1,\n", - " 'R1')]],\n", - " [[(16, 0, 'R3'), (17, 1, 'R3')]],\n", - " [[(14, 0, 'R3'), (14, 1, 'R3')]],\n", - " [[(14, 0, 'R3'), (15, 1, 'R3')]],\n", - " [[(14, 0, 'R3'), (13, 1, 'R3')]],\n", - " [[(100, 0, 'R1'), (38, 1, 'R1')]]]\n", + " #----------------------------------------------------------------------------\n", + " # Data.\n", + " small_jobs = [[[(100, 0, 'R6'), (2, 1, 'R6')]],\n", + " [[(2, 0, 'R3'), (100, 1, 'R3')]],\n", + " [[(100, 0, 'R1'), (16, 1, 'R1')]],\n", + " [[(1, 0, 'R1'), (38, 1, 'R1')]], [[(14, 0, 'R1'), (10, 1,\n", + " 'R1')]],\n", + " [[(16, 0, 'R3'), (17, 1, 'R3')]],\n", + " [[(14, 0, 'R3'), (14, 1, 'R3')]],\n", + " [[(14, 0, 'R3'), (15, 1, 'R3')]],\n", + " [[(14, 0, 'R3'), (13, 1, 'R3')]],\n", + " [[(100, 0, 'R1'), (38, 1, 'R1')]]]\n", "\n", - "large_jobs = [\n", - " [[(-1, 0, 'R1'), (10, 1, 'R1')]], [[(9, 0, 'R3'),\n", - " (22, 1, 'R3')]],\n", - " [[(-1, 0, 'R3'), (13, 1, 'R3')]], [[(-1, 0, 'R3'), (38, 1, 'R3')]],\n", - " [[(-1, 0, 'R3'), (38, 1, 'R3')]], [[(-1, 0, 'R3'), (16, 1, 'R3')]],\n", - " [[(-1, 0, 'R3'), (11, 1, 'R3')]], [[(-1, 0, 'R3'), (13, 1, 'R3')]],\n", - " [[(13, 0, 'R3'), (-1, 1, 'R3')]], [[(13, 0, 'R3'), (-1, 1, 'R3')]],\n", - " [[(-1, 0, 'R3'), (15, 1, 'R3')]], [[(12, 0, 'R1'), (-1, 1, 'R1')]],\n", - " [[(14, 0, 'R1'), (-1, 1, 'R1')]], [[(13, 0, 'R3'), (-1, 1, 'R3')]],\n", - " [[(-1, 0, 'R3'), (15, 1, 'R3')]], [[(14, 0, 'R1'), (-1, 1, 'R1')]],\n", - " [[(13, 0, 'R3'), (-1, 1, 'R3')]], [[(14, 0, 'R3'), (-1, 1, 'R3')]],\n", - " [[(13, 0, 'R1'), (-1, 1, 'R1')]], [[(15, 0, 'R1'), (-1, 1, 'R1')]],\n", - " [[(-1, 0, 'R2'), (16, 1, 'R2')]], [[(-1, 0, 'R2'), (16, 1, 'R2')]],\n", - " [[(-1, 0, 'R5'), (27, 1, 'R5')]], [[(-1, 0, 'R5'), (13, 1, 'R5')]],\n", - " [[(-1, 0, 'R5'), (13, 1, 'R5')]], [[(-1, 0, 'R5'), (13, 1, 'R5')]],\n", - " [[(13, 0, 'R1'), (-1, 1, 'R1')]], [[(-1, 0, 'R1'), (17, 1, 'R1')]],\n", - " [[(14, 0, 'R4'), (-1, 1, 'R4')]], [[(13, 0, 'R1'), (-1, 1, 'R1')]],\n", - " [[(16, 0, 'R4'), (-1, 1, 'R4')]], [[(16, 0, 'R4'), (-1, 1, 'R4')]],\n", - " [[(16, 0, 'R4'), (-1, 1, 'R4')]], [[(16, 0, 'R4'), (-1, 1, 'R4')]],\n", - " [[(13, 0, 'R1'), (-1, 1, 'R1')]], [[(13, 0, 'R1'), (-1, 1, 'R1')]],\n", - " [[(14, 0, 'R4'), (-1, 1, 'R4')]], [[(13, 0, 'R1'), (-1, 1, 'R1')]],\n", - " [[(12, 0, 'R1'), (-1, 1, 'R1')]], [[(14, 0, 'R4'), (-1, 1, 'R4')]],\n", - " [[(-1, 0, 'R5'), (14, 1, 'R5')]], [[(14, 0, 'R4'), (-1, 1, 'R4')]],\n", - " [[(14, 0, 'R4'), (-1, 1, 'R4')]], [[(14, 0, 'R4'), (-1, 1, 'R4')]],\n", - " [[(14, 0, 'R4'), (-1, 1, 'R4')]], [[(-1, 0, 'R1'), (21, 1, 'R1')]],\n", - " [[(-1, 0, 'R1'), (21, 1, 'R1')]], [[(-1, 0, 'R1'), (21, 1, 'R1')]],\n", - " [[(13, 0, 'R6'), (-1, 1, 'R6')]], [[(13, 0, 'R2'), (-1, 1, 'R2')]],\n", - " [[(-1, 0, 'R6'), (12, 1, 'R6')]], [[(13, 0, 'R1'), (-1, 1, 'R1')]],\n", - " [[(13, 0, 'R1'), (-1, 1, 'R1')]], [[(-1, 0, 'R6'), (14, 1, 'R6')]],\n", - " [[(-1, 0, 'R5'), (5, 1, 'R5')]], [[(3, 0, 'R2'), (-1, 1, 'R2')]],\n", - " [[(-1, 0, 'R1'), (21, 1, 'R1')]], [[(-1, 0, 'R1'), (21, 1, 'R1')]],\n", - " [[(-1, 0, 'R1'), (21, 1, 'R1')]], [[(-1, 0, 'R5'), (1, 1, 'R5')]],\n", - " [[(1, 0, 'R2'), (-1, 1, 'R2')]], [[(-1, 0, 'R2'), (19, 1, 'R2')]],\n", - " [[(13, 0, 'R4'), (-1, 1, 'R4')]], [[(12, 0, 'R4'), (-1, 1, 'R4')]],\n", - " [[(-1, 0, 'R3'), (2, 1, 'R3')]], [[(11, 0, 'R4'), (-1, 1, 'R4')]],\n", - " [[(6, 0, 'R6'), (-1, 1, 'R6')]], [[(6, 0, 'R6'), (-1, 1, 'R6')]],\n", - " [[(1, 0, 'R2'), (-1, 1, 'R2')]], [[(12, 0, 'R4'), (-1, 1, 'R4')]]\n", - "]\n", + " large_jobs = [\n", + " [[(-1, 0, 'R1'), (10, 1, 'R1')]], [[(9, 0, 'R3'),\n", + " (22, 1, 'R3')]],\n", + " [[(-1, 0, 'R3'), (13, 1, 'R3')]], [[(-1, 0, 'R3'), (38, 1, 'R3')]],\n", + " [[(-1, 0, 'R3'), (38, 1, 'R3')]], [[(-1, 0, 'R3'), (16, 1, 'R3')]],\n", + " [[(-1, 0, 'R3'), (11, 1, 'R3')]], [[(-1, 0, 'R3'), (13, 1, 'R3')]],\n", + " [[(13, 0, 'R3'), (-1, 1, 'R3')]], [[(13, 0, 'R3'), (-1, 1, 'R3')]],\n", + " [[(-1, 0, 'R3'), (15, 1, 'R3')]], [[(12, 0, 'R1'), (-1, 1, 'R1')]],\n", + " [[(14, 0, 'R1'), (-1, 1, 'R1')]], [[(13, 0, 'R3'), (-1, 1, 'R3')]],\n", + " [[(-1, 0, 'R3'), (15, 1, 'R3')]], [[(14, 0, 'R1'), (-1, 1, 'R1')]],\n", + " [[(13, 0, 'R3'), (-1, 1, 'R3')]], [[(14, 0, 'R3'), (-1, 1, 'R3')]],\n", + " [[(13, 0, 'R1'), (-1, 1, 'R1')]], [[(15, 0, 'R1'), (-1, 1, 'R1')]],\n", + " [[(-1, 0, 'R2'), (16, 1, 'R2')]], [[(-1, 0, 'R2'), (16, 1, 'R2')]],\n", + " [[(-1, 0, 'R5'), (27, 1, 'R5')]], [[(-1, 0, 'R5'), (13, 1, 'R5')]],\n", + " [[(-1, 0, 'R5'), (13, 1, 'R5')]], [[(-1, 0, 'R5'), (13, 1, 'R5')]],\n", + " [[(13, 0, 'R1'), (-1, 1, 'R1')]], [[(-1, 0, 'R1'), (17, 1, 'R1')]],\n", + " [[(14, 0, 'R4'), (-1, 1, 'R4')]], [[(13, 0, 'R1'), (-1, 1, 'R1')]],\n", + " [[(16, 0, 'R4'), (-1, 1, 'R4')]], [[(16, 0, 'R4'), (-1, 1, 'R4')]],\n", + " [[(16, 0, 'R4'), (-1, 1, 'R4')]], [[(16, 0, 'R4'), (-1, 1, 'R4')]],\n", + " [[(13, 0, 'R1'), (-1, 1, 'R1')]], [[(13, 0, 'R1'), (-1, 1, 'R1')]],\n", + " [[(14, 0, 'R4'), (-1, 1, 'R4')]], [[(13, 0, 'R1'), (-1, 1, 'R1')]],\n", + " [[(12, 0, 'R1'), (-1, 1, 'R1')]], [[(14, 0, 'R4'), (-1, 1, 'R4')]],\n", + " [[(-1, 0, 'R5'), (14, 1, 'R5')]], [[(14, 0, 'R4'), (-1, 1, 'R4')]],\n", + " [[(14, 0, 'R4'), (-1, 1, 'R4')]], [[(14, 0, 'R4'), (-1, 1, 'R4')]],\n", + " [[(14, 0, 'R4'), (-1, 1, 'R4')]], [[(-1, 0, 'R1'), (21, 1, 'R1')]],\n", + " [[(-1, 0, 'R1'), (21, 1, 'R1')]], [[(-1, 0, 'R1'), (21, 1, 'R1')]],\n", + " [[(13, 0, 'R6'), (-1, 1, 'R6')]], [[(13, 0, 'R2'), (-1, 1, 'R2')]],\n", + " [[(-1, 0, 'R6'), (12, 1, 'R6')]], [[(13, 0, 'R1'), (-1, 1, 'R1')]],\n", + " [[(13, 0, 'R1'), (-1, 1, 'R1')]], [[(-1, 0, 'R6'), (14, 1, 'R6')]],\n", + " [[(-1, 0, 'R5'), (5, 1, 'R5')]], [[(3, 0, 'R2'), (-1, 1, 'R2')]],\n", + " [[(-1, 0, 'R1'), (21, 1, 'R1')]], [[(-1, 0, 'R1'), (21, 1, 'R1')]],\n", + " [[(-1, 0, 'R1'), (21, 1, 'R1')]], [[(-1, 0, 'R5'), (1, 1, 'R5')]],\n", + " [[(1, 0, 'R2'), (-1, 1, 'R2')]], [[(-1, 0, 'R2'), (19, 1, 'R2')]],\n", + " [[(13, 0, 'R4'), (-1, 1, 'R4')]], [[(12, 0, 'R4'), (-1, 1, 'R4')]],\n", + " [[(-1, 0, 'R3'), (2, 1, 'R3')]], [[(11, 0, 'R4'), (-1, 1, 'R4')]],\n", + " [[(6, 0, 'R6'), (-1, 1, 'R6')]], [[(6, 0, 'R6'), (-1, 1, 'R6')]],\n", + " [[(1, 0, 'R2'), (-1, 1, 'R2')]], [[(12, 0, 'R4'), (-1, 1, 'R4')]]\n", + " ]\n", "\n", - "jobs = small_jobs if instance == 0 else large_jobs\n", + " jobs = small_jobs if instance == 0 else large_jobs\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Helper data.\n", - "num_jobs = len(jobs)\n", - "all_jobs = range(num_jobs)\n", - "num_machines = 2\n", - "all_machines = range(num_machines)\n", + " #----------------------------------------------------------------------------\n", + " # Helper data.\n", + " num_jobs = len(jobs)\n", + " all_jobs = range(num_jobs)\n", + " num_machines = 2\n", + " all_machines = range(num_machines)\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Model.\n", - "model = cp_model.CpModel()\n", + " #----------------------------------------------------------------------------\n", + " # Model.\n", + " model = cp_model.CpModel()\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Compute a maximum makespan greedily.\n", - "horizon = 0\n", - "for job in jobs:\n", - " for task in job:\n", - " max_task_duration = 0\n", - " for alternative in task:\n", - " max_task_duration = max(max_task_duration, alternative[0])\n", - " horizon += max_task_duration\n", + " #----------------------------------------------------------------------------\n", + " # Compute a maximum makespan greedily.\n", + " horizon = 0\n", + " for job in jobs:\n", + " for task in job:\n", + " max_task_duration = 0\n", + " for alternative in task:\n", + " max_task_duration = max(max_task_duration, alternative[0])\n", + " horizon += max_task_duration\n", "\n", - "print('Horizon = %i' % horizon)\n", + " print('Horizon = %i' % horizon)\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Global storage of variables.\n", - "intervals_per_machines = collections.defaultdict(list)\n", - "presences_per_machines = collections.defaultdict(list)\n", - "starts_per_machines = collections.defaultdict(list)\n", - "ends_per_machines = collections.defaultdict(list)\n", - "resources_per_machines = collections.defaultdict(list)\n", - "ranks_per_machines = collections.defaultdict(list)\n", + " #----------------------------------------------------------------------------\n", + " # Global storage of variables.\n", + " intervals_per_machines = collections.defaultdict(list)\n", + " presences_per_machines = collections.defaultdict(list)\n", + " starts_per_machines = collections.defaultdict(list)\n", + " ends_per_machines = collections.defaultdict(list)\n", + " resources_per_machines = collections.defaultdict(list)\n", + " ranks_per_machines = collections.defaultdict(list)\n", "\n", - "job_starts = {} # indexed by (job_id, task_id).\n", - "job_presences = {} # indexed by (job_id, task_id, alt_id).\n", - "job_ranks = {} # indexed by (job_id, task_id, alt_id).\n", - "job_ends = [] # indexed by job_id\n", + " job_starts = {} # indexed by (job_id, task_id).\n", + " job_presences = {} # indexed by (job_id, task_id, alt_id).\n", + " job_ranks = {} # indexed by (job_id, task_id, alt_id).\n", + " job_ends = [] # indexed by job_id\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Scan the jobs and create the relevant variables and intervals.\n", - "for job_id in all_jobs:\n", - " job = jobs[job_id]\n", - " num_tasks = len(job)\n", - " previous_end = None\n", - " for task_id in range(num_tasks):\n", - " task = job[task_id]\n", - "\n", - " min_duration = task[0][0]\n", - " max_duration = task[0][0]\n", - "\n", - " num_alternatives = len(task)\n", - " all_alternatives = range(num_alternatives)\n", - "\n", - " for alt_id in range(1, num_alternatives):\n", - " alt_duration = task[alt_id][0]\n", - " min_duration = min(min_duration, alt_duration)\n", - " max_duration = max(max_duration, alt_duration)\n", - "\n", - " # Create main interval for the task.\n", - " suffix_name = '_j%i_t%i' % (job_id, task_id)\n", - " start = model.NewIntVar(0, horizon, 'start' + suffix_name)\n", - " duration = model.NewIntVar(min_duration, max_duration,\n", - " 'duration' + suffix_name)\n", - " end = model.NewIntVar(0, horizon, 'end' + suffix_name)\n", - "\n", - " # Store the start for the solution.\n", - " job_starts[(job_id, task_id)] = start\n", - "\n", - " # Add precedence with previous task in the same job.\n", - " if previous_end:\n", - " model.Add(start >= previous_end)\n", - " previous_end = end\n", - "\n", - " # Create alternative intervals.\n", - " l_presences = []\n", - " for alt_id in all_alternatives:\n", - " ### add to link interval with eqp constraint.\n", - " ### process time = -1 cannot be processed at this machine.\n", - " if jobs[job_id][task_id][alt_id][0] == -1:\n", - " continue\n", - " alt_suffix = '_j%i_t%i_a%i' % (job_id, task_id, alt_id)\n", - " l_presence = model.NewBoolVar('presence' + alt_suffix)\n", - " l_start = model.NewIntVar(0, horizon, 'start' + alt_suffix)\n", - " l_duration = task[alt_id][0]\n", - " l_end = model.NewIntVar(0, horizon, 'end' + alt_suffix)\n", - " l_interval = model.NewOptionalIntervalVar(\n", - " l_start, l_duration, l_end, l_presence, 'interval' + alt_suffix)\n", - " l_rank = model.NewIntVar(-1, num_jobs, 'rank' + alt_suffix)\n", - " l_presences.append(l_presence)\n", - " l_machine = task[alt_id][1]\n", - " l_type = task[alt_id][2]\n", - "\n", - " # Link the master variables with the local ones.\n", - " model.Add(start == l_start).OnlyEnforceIf(l_presence)\n", - " model.Add(duration == l_duration).OnlyEnforceIf(l_presence)\n", - " model.Add(end == l_end).OnlyEnforceIf(l_presence)\n", - "\n", - " # Add the local variables to the right machine.\n", - " intervals_per_machines[l_machine].append(l_interval)\n", - " starts_per_machines[l_machine].append(l_start)\n", - " ends_per_machines[l_machine].append(l_end)\n", - " presences_per_machines[l_machine].append(l_presence)\n", - " resources_per_machines[l_machine].append(l_type)\n", - " ranks_per_machines[l_machine].append(l_rank)\n", - "\n", - " # Store the variables for the solution.\n", - " job_presences[(job_id, task_id, alt_id)] = l_presence\n", - " job_ranks[(job_id, task_id, alt_id)] = l_rank\n", - "\n", - " # Only one machine can process each lot.\n", - " model.Add(sum(l_presences) == 1)\n", - "\n", - " job_ends.append(previous_end)\n", - "\n", - "#----------------------------------------------------------------------------\n", - "# Create machines constraints nonoverlap process\n", - "for machine_id in all_machines:\n", - " intervals = intervals_per_machines[machine_id]\n", - " if len(intervals) > 1:\n", - " model.AddNoOverlap(intervals)\n", - "\n", - "#----------------------------------------------------------------------------\n", - "# Transition times and transition costs using a circuit constraint.\n", - "switch_literals = []\n", - "for machine_id in all_machines:\n", - " machine_starts = starts_per_machines[machine_id]\n", - " machine_ends = ends_per_machines[machine_id]\n", - " machine_presences = presences_per_machines[machine_id]\n", - " machine_resources = resources_per_machines[machine_id]\n", - " machine_ranks = ranks_per_machines[machine_id]\n", - " intervals = intervals_per_machines[machine_id]\n", - " arcs = []\n", - " num_machine_tasks = len(machine_starts)\n", - " all_machine_tasks = range(num_machine_tasks)\n", - "\n", - " for i in all_machine_tasks:\n", - " # Initial arc from the dummy node (0) to a task.\n", - " start_lit = model.NewBoolVar('')\n", - " arcs.append([0, i + 1, start_lit])\n", - " # If this task is the first, set both rank and start to 0.\n", - " model.Add(machine_ranks[i] == 0).OnlyEnforceIf(start_lit)\n", - " model.Add(machine_starts[i] == 0).OnlyEnforceIf(start_lit)\n", - " # Final arc from an arc to the dummy node.\n", - " arcs.append([i + 1, 0, model.NewBoolVar('')])\n", - " # Self arc if the task is not performed.\n", - " arcs.append([i + 1, i + 1, machine_presences[i].Not()])\n", - " model.Add(machine_ranks[i] == -1).OnlyEnforceIf(\n", - " machine_presences[i].Not())\n", - "\n", - " for j in all_machine_tasks:\n", - " if i == j:\n", - " continue\n", - "\n", - " lit = model.NewBoolVar('%i follows %i' % (j, i))\n", - " arcs.append([i + 1, j + 1, lit])\n", - " model.AddImplication(lit, machine_presences[i])\n", - " model.AddImplication(lit, machine_presences[j])\n", - "\n", - " # Maintain rank incrementally.\n", - " model.Add(machine_ranks[j] == machine_ranks[i] + 1).OnlyEnforceIf(lit)\n", - "\n", - " # Compute the transition time if task j is the successor of task i.\n", - " if machine_resources[i] != machine_resources[j]:\n", - " transition_time = 3\n", - " switch_literals.append(lit)\n", - " else:\n", - " transition_time = 0\n", - " # We add the reified transition to link the literals with the times\n", - " # of the tasks.\n", - " model.Add(machine_starts[j] == machine_ends[i] +\n", - " transition_time).OnlyEnforceIf(lit)\n", - " if arcs:\n", - " model.AddCircuit(arcs)\n", - "\n", - "#----------------------------------------------------------------------------\n", - "# Objective.\n", - "makespan = model.NewIntVar(0, horizon, 'makespan')\n", - "model.AddMaxEquality(makespan, job_ends)\n", - "makespan_weight = 1\n", - "transition_weight = 5\n", - "model.Minimize(makespan * makespan_weight +\n", - " sum(switch_literals) * transition_weight)\n", - "\n", - "#----------------------------------------------------------------------------\n", - "# Write problem to file.\n", - "if output_proto:\n", - " print('Writing proto to %s' % output_proto)\n", - " with open(output_proto, 'w') as text_file:\n", - " text_file.write(str(model))\n", - "\n", - "#----------------------------------------------------------------------------\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", - "solution_printer = SolutionPrinter(makespan)\n", - "status = solver.Solve(model, solution_printer)\n", - "\n", - "#----------------------------------------------------------------------------\n", - "# Print solution.\n", - "if status == cp_model.FEASIBLE or status == cp_model.OPTIMAL:\n", + " #----------------------------------------------------------------------------\n", + " # Scan the jobs and create the relevant variables and intervals.\n", " for job_id in all_jobs:\n", - " for task_id in range(len(jobs[job_id])):\n", - " start_value = solver.Value(job_starts[(job_id, task_id)])\n", - " machine = 0\n", - " duration = 0\n", - " select = 0\n", - " rank = -1\n", + " job = jobs[job_id]\n", + " num_tasks = len(job)\n", + " previous_end = None\n", + " for task_id in range(num_tasks):\n", + " task = job[task_id]\n", "\n", - " for alt_id in range(len(jobs[job_id][task_id])):\n", + " min_duration = task[0][0]\n", + " max_duration = task[0][0]\n", + "\n", + " num_alternatives = len(task)\n", + " all_alternatives = range(num_alternatives)\n", + "\n", + " for alt_id in range(1, num_alternatives):\n", + " alt_duration = task[alt_id][0]\n", + " min_duration = min(min_duration, alt_duration)\n", + " max_duration = max(max_duration, alt_duration)\n", + "\n", + " # Create main interval for the task.\n", + " suffix_name = '_j%i_t%i' % (job_id, task_id)\n", + " start = model.NewIntVar(0, horizon, 'start' + suffix_name)\n", + " duration = model.NewIntVar(min_duration, max_duration,\n", + " 'duration' + suffix_name)\n", + " end = model.NewIntVar(0, horizon, 'end' + suffix_name)\n", + "\n", + " # Store the start for the solution.\n", + " job_starts[(job_id, task_id)] = start\n", + "\n", + " # Add precedence with previous task in the same job.\n", + " if previous_end:\n", + " model.Add(start >= previous_end)\n", + " previous_end = end\n", + "\n", + " # Create alternative intervals.\n", + " l_presences = []\n", + " for alt_id in all_alternatives:\n", + " ### add to link interval with eqp constraint.\n", + " ### process time = -1 cannot be processed at this machine.\n", " if jobs[job_id][task_id][alt_id][0] == -1:\n", " continue\n", + " alt_suffix = '_j%i_t%i_a%i' % (job_id, task_id, alt_id)\n", + " l_presence = model.NewBoolVar('presence' + alt_suffix)\n", + " l_start = model.NewIntVar(0, horizon, 'start' + alt_suffix)\n", + " l_duration = task[alt_id][0]\n", + " l_end = model.NewIntVar(0, horizon, 'end' + alt_suffix)\n", + " l_interval = model.NewOptionalIntervalVar(\n", + " l_start, l_duration, l_end, l_presence, 'interval' + alt_suffix)\n", + " l_rank = model.NewIntVar(-1, num_jobs, 'rank' + alt_suffix)\n", + " l_presences.append(l_presence)\n", + " l_machine = task[alt_id][1]\n", + " l_type = task[alt_id][2]\n", "\n", - " if solver.BooleanValue(job_presences[(job_id, task_id, alt_id)]):\n", - " duration = jobs[job_id][task_id][alt_id][0]\n", - " machine = jobs[job_id][task_id][alt_id][1]\n", - " select = alt_id\n", - " rank = solver.Value(job_ranks[(job_id, task_id, alt_id)])\n", + " # Link the master variables with the local ones.\n", + " model.Add(start == l_start).OnlyEnforceIf(l_presence)\n", + " model.Add(duration == l_duration).OnlyEnforceIf(l_presence)\n", + " model.Add(end == l_end).OnlyEnforceIf(l_presence)\n", "\n", - " print(\n", - " ' Job %i starts at %i (alt %i, duration %i) with rank %i on machine %i'\n", - " % (job_id, start_value, select, duration, rank, machine))\n", + " # Add the local variables to the right machine.\n", + " intervals_per_machines[l_machine].append(l_interval)\n", + " starts_per_machines[l_machine].append(l_start)\n", + " ends_per_machines[l_machine].append(l_end)\n", + " presences_per_machines[l_machine].append(l_presence)\n", + " resources_per_machines[l_machine].append(l_type)\n", + " ranks_per_machines[l_machine].append(l_rank)\n", "\n", - " print('Solve status: %s' % solver.StatusName(status))\n", - " print('Objective value: %i' % solver.ObjectiveValue())\n", - " print('Makespan: %i' % solver.Value(makespan))\n", + " # Store the variables for the solution.\n", + " job_presences[(job_id, task_id, alt_id)] = l_presence\n", + " job_ranks[(job_id, task_id, alt_id)] = l_rank\n", + "\n", + " # Only one machine can process each lot.\n", + " model.Add(sum(l_presences) == 1)\n", + "\n", + " job_ends.append(previous_end)\n", + "\n", + " #----------------------------------------------------------------------------\n", + " # Create machines constraints nonoverlap process\n", + " for machine_id in all_machines:\n", + " intervals = intervals_per_machines[machine_id]\n", + " if len(intervals) > 1:\n", + " model.AddNoOverlap(intervals)\n", + "\n", + " #----------------------------------------------------------------------------\n", + " # Transition times and transition costs using a circuit constraint.\n", + " switch_literals = []\n", + " for machine_id in all_machines:\n", + " machine_starts = starts_per_machines[machine_id]\n", + " machine_ends = ends_per_machines[machine_id]\n", + " machine_presences = presences_per_machines[machine_id]\n", + " machine_resources = resources_per_machines[machine_id]\n", + " machine_ranks = ranks_per_machines[machine_id]\n", + " intervals = intervals_per_machines[machine_id]\n", + " arcs = []\n", + " num_machine_tasks = len(machine_starts)\n", + " all_machine_tasks = range(num_machine_tasks)\n", + "\n", + " for i in all_machine_tasks:\n", + " # Initial arc from the dummy node (0) to a task.\n", + " start_lit = model.NewBoolVar('')\n", + " arcs.append([0, i + 1, start_lit])\n", + " # If this task is the first, set both rank and start to 0.\n", + " model.Add(machine_ranks[i] == 0).OnlyEnforceIf(start_lit)\n", + " model.Add(machine_starts[i] == 0).OnlyEnforceIf(start_lit)\n", + " # Final arc from an arc to the dummy node.\n", + " arcs.append([i + 1, 0, model.NewBoolVar('')])\n", + " # Self arc if the task is not performed.\n", + " arcs.append([i + 1, i + 1, machine_presences[i].Not()])\n", + " model.Add(machine_ranks[i] == -1).OnlyEnforceIf(\n", + " machine_presences[i].Not())\n", + "\n", + " for j in all_machine_tasks:\n", + " if i == j:\n", + " continue\n", + "\n", + " lit = model.NewBoolVar('%i follows %i' % (j, i))\n", + " arcs.append([i + 1, j + 1, lit])\n", + " model.AddImplication(lit, machine_presences[i])\n", + " model.AddImplication(lit, machine_presences[j])\n", + "\n", + " # Maintain rank incrementally.\n", + " model.Add(machine_ranks[j] == machine_ranks[i] + 1).OnlyEnforceIf(lit)\n", + "\n", + " # Compute the transition time if task j is the successor of task i.\n", + " if machine_resources[i] != machine_resources[j]:\n", + " transition_time = 3\n", + " switch_literals.append(lit)\n", + " else:\n", + " transition_time = 0\n", + " # We add the reified transition to link the literals with the times\n", + " # of the tasks.\n", + " model.Add(machine_starts[j] == machine_ends[i] +\n", + " transition_time).OnlyEnforceIf(lit)\n", + " if arcs:\n", + " model.AddCircuit(arcs)\n", + "\n", + " #----------------------------------------------------------------------------\n", + " # Objective.\n", + " makespan = model.NewIntVar(0, horizon, 'makespan')\n", + " model.AddMaxEquality(makespan, job_ends)\n", + " makespan_weight = 1\n", + " transition_weight = 5\n", + " model.Minimize(makespan * makespan_weight +\n", + " sum(switch_literals) * transition_weight)\n", + "\n", + " #----------------------------------------------------------------------------\n", + " # Write problem to file.\n", + " if output_proto:\n", + " print('Writing proto to %s' % output_proto)\n", + " with open(output_proto, 'w') as text_file:\n", + " text_file.write(str(model))\n", + "\n", + " #----------------------------------------------------------------------------\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", + " solution_printer = SolutionPrinter(makespan)\n", + " status = solver.Solve(model, solution_printer)\n", + "\n", + " #----------------------------------------------------------------------------\n", + " # Print solution.\n", + " if status == cp_model.FEASIBLE or status == cp_model.OPTIMAL:\n", + " for job_id in all_jobs:\n", + " for task_id in range(len(jobs[job_id])):\n", + " start_value = solver.Value(job_starts[(job_id, task_id)])\n", + " machine = 0\n", + " duration = 0\n", + " select = 0\n", + " rank = -1\n", + "\n", + " for alt_id in range(len(jobs[job_id][task_id])):\n", + " if jobs[job_id][task_id][alt_id][0] == -1:\n", + " continue\n", + "\n", + " if solver.BooleanValue(job_presences[(job_id, task_id, alt_id)]):\n", + " duration = jobs[job_id][task_id][alt_id][0]\n", + " machine = jobs[job_id][task_id][alt_id][1]\n", + " select = alt_id\n", + " rank = solver.Value(job_ranks[(job_id, task_id, alt_id)])\n", + "\n", + " print(\n", + " ' Job %i starts at %i (alt %i, duration %i) with rank %i on machine %i'\n", + " % (job_id, start_value, select, duration, rank, machine))\n", + "\n", + " print('Solve status: %s' % solver.StatusName(status))\n", + " print('Objective value: %i' % solver.ObjectiveValue())\n", + " print('Makespan: %i' % solver.Value(makespan))\n", + "\n", + "\n", + "main(PARSER.parse_args())\n", "\n" ] } diff --git a/examples/notebook/contrib/school_scheduling_sat.ipynb b/examples/notebook/contrib/school_scheduling_sat.ipynb index ec1b5717c1..09199a9195 100644 --- a/examples/notebook/contrib/school_scheduling_sat.ipynb +++ b/examples/notebook/contrib/school_scheduling_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -211,38 +211,42 @@ " print('Found Solution!')\n", "\n", "\n", - "# DATA\n", - "subjects = ['English', 'Math', 'History']\n", - "levels = ['1-', '2-', '3-']\n", - "sections = ['A']\n", - "teachers = ['Mario', 'Elvis', 'Donald', 'Ian']\n", - "teachers_work_hours = [18, 12, 12, 18]\n", - "working_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']\n", - "periods = ['08:00-09:30', '09:45-11:15', '11:30-13:00']\n", - "curriculum = {\n", - " ('1-', 'English'): 3,\n", - " ('1-', 'Math'): 3,\n", - " ('1-', 'History'): 2,\n", - " ('2-', 'English'): 4,\n", - " ('2-', 'Math'): 2,\n", - " ('2-', 'History'): 2,\n", - " ('3-', 'English'): 2,\n", - " ('3-', 'Math'): 4,\n", - " ('3-', 'History'): 2\n", - "}\n", + "def main():\n", + " # DATA\n", + " subjects = ['English', 'Math', 'History']\n", + " levels = ['1-', '2-', '3-']\n", + " sections = ['A']\n", + " teachers = ['Mario', 'Elvis', 'Donald', 'Ian']\n", + " teachers_work_hours = [18, 12, 12, 18]\n", + " working_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']\n", + " periods = ['08:00-09:30', '09:45-11:15', '11:30-13:00']\n", + " curriculum = {\n", + " ('1-', 'English'): 3,\n", + " ('1-', 'Math'): 3,\n", + " ('1-', 'History'): 2,\n", + " ('2-', 'English'): 4,\n", + " ('2-', 'Math'): 2,\n", + " ('2-', 'History'): 2,\n", + " ('3-', 'English'): 2,\n", + " ('3-', 'Math'): 4,\n", + " ('3-', 'History'): 2\n", + " }\n", "\n", - "# Subject -> List of teachers who can teach it\n", - "specialties_idx_inverse = [\n", - " [1, 3], # English -> Elvis & Ian\n", - " [0, 3], # Math -> Mario & Ian\n", - " [2, 3] # History -> Donald & Ian\n", - "]\n", + " # Subject -> List of teachers who can teach it\n", + " specialties_idx_inverse = [\n", + " [1, 3], # English -> Elvis & Ian\n", + " [0, 3], # Math -> Mario & Ian\n", + " [2, 3] # History -> Donald & Ian\n", + " ]\n", "\n", - "problem = SchoolSchedulingProblem(\n", - " subjects, teachers, curriculum, specialties_idx_inverse, working_days,\n", - " periods, levels, sections, teachers_work_hours)\n", - "solver = SchoolSchedulingSatSolver(problem)\n", - "solver.solve()\n", + " problem = SchoolSchedulingProblem(\n", + " subjects, teachers, curriculum, specialties_idx_inverse, working_days,\n", + " periods, levels, sections, teachers_work_hours)\n", + " solver = SchoolSchedulingSatSolver(problem)\n", + " solver.solve()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/secret_santa.ipynb b/examples/notebook/contrib/secret_santa.ipynb index 3fc3435bbb..c58cf4256b 100644 --- a/examples/notebook/contrib/secret_santa.ipynb +++ b/examples/notebook/contrib/secret_santa.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Secret Santa problem in Google CP Solver.\n", "\n", @@ -133,58 +118,70 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Secret Santa problem')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Secret Santa problem')\n", "\n", - "#\n", - "# data\n", - "#\n", - "family = [1, 1, 1, 1, 2, 3, 3, 3, 3, 3, 4, 4]\n", - "num_families = max(family)\n", - "n = len(family)\n", + " #\n", + " # data\n", + " #\n", + " family = [1, 1, 1, 1, 2, 3, 3, 3, 3, 3, 4, 4]\n", + " num_families = max(family)\n", + " n = len(family)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(0, n - 1, 'x[%i]' % i) for i in range(n)]\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(0, n - 1, 'x[%i]' % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", "\n", - "# Can't be one own's Secret Santa\n", - "# Ensure that there are no fix-point in the array\n", - "for i in range(n):\n", - " solver.Add(x[i] != i)\n", + " # Can't be one own's Secret Santa\n", + " # Ensure that there are no fix-point in the array\n", + " for i in range(n):\n", + " solver.Add(x[i] != i)\n", "\n", - "# No Secret Santa to a person in the same family\n", - "for i in range(n):\n", - " solver.Add(family[i] != solver.Element(family, x[i]))\n", + " # No Secret Santa to a person in the same family\n", + " for i in range(n):\n", + " solver.Add(family[i] != solver.Element(family, x[i]))\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE)\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE)\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('x:', [x[i].Value() for i in range(n)])\n", - " print()\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('x:', [x[i].Value() for i in range(n)])\n", + " print()\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/secret_santa2.ipynb b/examples/notebook/contrib/secret_santa2.ipynb index c4c75b4717..b86cbab56f 100644 --- a/examples/notebook/contrib/secret_santa2.ipynb +++ b/examples/notebook/contrib/secret_santa2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Secret Santa problem II in Google CP Solver.\n", "\n", @@ -134,157 +119,173 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(singe=0):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Secret Santa problem II')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Secret Santa problem II')\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "#\n", - "# The matrix version of earlier rounds.\n", - "# M means that no earlier Santa has been assigned.\n", - "# Note: Ryan and Mia has the same recipient for years 3 and 4,\n", - "# and Ella and John has for year 4.\n", - "# This seems to be caused by modification of\n", - "# original data.\n", - "#\n", - "n_no_single = 8\n", - "M = n_no_single + 1\n", - "rounds_no_single = [\n", - " # N A R M El J L Ev\n", - " [0, M, 3, M, 1, 4, M, 2], # Noah\n", - " [M, 0, 4, 2, M, 3, M, 1], # Ava\n", - " [M, 2, 0, M, 1, M, 3, 4], # Ryan\n", - " [M, 1, M, 0, 2, M, 3, 4], # Mia\n", - " [M, 4, M, 3, 0, M, 1, 2], # Ella\n", - " [1, 4, 3, M, M, 0, 2, M], # John\n", - " [M, 3, M, 2, 4, 1, 0, M], # Lily\n", - " [4, M, 3, 1, M, 2, M, 0] # Evan\n", - "]\n", + " #\n", + " # The matrix version of earlier rounds.\n", + " # M means that no earlier Santa has been assigned.\n", + " # Note: Ryan and Mia has the same recipient for years 3 and 4,\n", + " # and Ella and John has for year 4.\n", + " # This seems to be caused by modification of\n", + " # original data.\n", + " #\n", + " n_no_single = 8\n", + " M = n_no_single + 1\n", + " rounds_no_single = [\n", + " # N A R M El J L Ev\n", + " [0, M, 3, M, 1, 4, M, 2], # Noah\n", + " [M, 0, 4, 2, M, 3, M, 1], # Ava\n", + " [M, 2, 0, M, 1, M, 3, 4], # Ryan\n", + " [M, 1, M, 0, 2, M, 3, 4], # Mia\n", + " [M, 4, M, 3, 0, M, 1, 2], # Ella\n", + " [1, 4, 3, M, M, 0, 2, M], # John\n", + " [M, 3, M, 2, 4, 1, 0, M], # Lily\n", + " [4, M, 3, 1, M, 2, M, 0] # Evan\n", + " ]\n", "\n", - "#\n", - "# Rounds with a single person (fake data)\n", - "#\n", - "n_with_single = 9\n", - "M = n_with_single + 1\n", - "rounds_single = [\n", - " # N A R M El J L Ev S\n", - " [0, M, 3, M, 1, 4, M, 2, 2], # Noah\n", - " [M, 0, 4, 2, M, 3, M, 1, 1], # Ava\n", - " [M, 2, 0, M, 1, M, 3, 4, 4], # Ryan\n", - " [M, 1, M, 0, 2, M, 3, 4, 3], # Mia\n", - " [M, 4, M, 3, 0, M, 1, 2, M], # Ella\n", - " [1, 4, 3, M, M, 0, 2, M, M], # John\n", - " [M, 3, M, 2, 4, 1, 0, M, M], # Lily\n", - " [4, M, 3, 1, M, 2, M, 0, M], # Evan\n", - " [1, 2, 3, 4, M, 2, M, M, 0] # Single\n", - "]\n", + " #\n", + " # Rounds with a single person (fake data)\n", + " #\n", + " n_with_single = 9\n", + " M = n_with_single + 1\n", + " rounds_single = [\n", + " # N A R M El J L Ev S\n", + " [0, M, 3, M, 1, 4, M, 2, 2], # Noah\n", + " [M, 0, 4, 2, M, 3, M, 1, 1], # Ava\n", + " [M, 2, 0, M, 1, M, 3, 4, 4], # Ryan\n", + " [M, 1, M, 0, 2, M, 3, 4, 3], # Mia\n", + " [M, 4, M, 3, 0, M, 1, 2, M], # Ella\n", + " [1, 4, 3, M, M, 0, 2, M, M], # John\n", + " [M, 3, M, 2, 4, 1, 0, M, M], # Lily\n", + " [4, M, 3, 1, M, 2, M, 0, M], # Evan\n", + " [1, 2, 3, 4, M, 2, M, M, 0] # Single\n", + " ]\n", "\n", - "if single == 1:\n", - " n = n_with_single\n", - " Noah, Ava, Ryan, Mia, Ella, John, Lily, Evan, Single = list(range(n))\n", - " rounds = rounds_single\n", - "else:\n", - " n = n_no_single\n", - " Noah, Ava, Ryan, Mia, Ella, John, Lily, Evan = list(range(n))\n", - " rounds = rounds_no_single\n", + " if single == 1:\n", + " n = n_with_single\n", + " Noah, Ava, Ryan, Mia, Ella, John, Lily, Evan, Single = list(range(n))\n", + " rounds = rounds_single\n", + " else:\n", + " n = n_no_single\n", + " Noah, Ava, Ryan, Mia, Ella, John, Lily, Evan = list(range(n))\n", + " rounds = rounds_no_single\n", "\n", - "M = n + 1\n", + " M = n + 1\n", "\n", - "persons = [\n", - " 'Noah', 'Ava', 'Ryan', 'Mia', 'Ella', 'John', 'Lily', 'Evan', 'Single'\n", - "]\n", + " persons = [\n", + " 'Noah', 'Ava', 'Ryan', 'Mia', 'Ella', 'John', 'Lily', 'Evan', 'Single'\n", + " ]\n", "\n", - "spouses = [\n", - " Ava, # Noah\n", - " Noah, # Ava\n", - " Mia, # Rya\n", - " Ryan, # Mia\n", - " John, # Ella\n", - " Ella, # John\n", - " Evan, # Lily\n", - " Lily, # Evan\n", - " -1 # Single has no spouse\n", - "]\n", + " spouses = [\n", + " Ava, # Noah\n", + " Noah, # Ava\n", + " Mia, # Rya\n", + " Ryan, # Mia\n", + " John, # Ella\n", + " Ella, # John\n", + " Evan, # Lily\n", + " Lily, # Evan\n", + " -1 # Single has no spouse\n", + " ]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "santas = [solver.IntVar(0, n - 1, 'santas[%i]' % i) for i in range(n)]\n", - "santa_distance = [\n", - " solver.IntVar(0, M, 'santa_distance[%i]' % i) for i in range(n)\n", - "]\n", + " #\n", + " # declare variables\n", + " #\n", + " santas = [solver.IntVar(0, n - 1, 'santas[%i]' % i) for i in range(n)]\n", + " santa_distance = [\n", + " solver.IntVar(0, M, 'santa_distance[%i]' % i) for i in range(n)\n", + " ]\n", "\n", - "# total of 'distance', to maximize\n", - "z = solver.IntVar(0, n * n * n, 'z')\n", + " # total of 'distance', to maximize\n", + " z = solver.IntVar(0, n * n * n, 'z')\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(santas))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(santas))\n", "\n", - "solver.Add(z == solver.Sum(santa_distance))\n", + " solver.Add(z == solver.Sum(santa_distance))\n", "\n", - "# Can't be one own's Secret Santa\n", - "# (i.e. ensure that there are no fix-point in the array.)\n", - "for i in range(n):\n", - " solver.Add(santas[i] != i)\n", - "\n", - "# no Santa for a spouses\n", - "for i in range(n):\n", - " if spouses[i] > -1:\n", - " solver.Add(santas[i] != spouses[i])\n", - "\n", - "# optimize 'distance' to earlier rounds:\n", - "for i in range(n):\n", - " solver.Add(santa_distance[i] == solver.Element(rounds[i], santas[i]))\n", - "\n", - "# cannot be a Secret Santa for the same person\n", - "# two years in a row.\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if rounds[i][j] == 1:\n", - " solver.Add(santas[i] != j)\n", - "\n", - "# objective\n", - "objective = solver.Maximize(z, 1)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "db = solver.Phase(santas, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", - " solver.ASSIGN_CENTER_VALUE)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('total distances:', z.Value())\n", - " print('santas:', [santas[i].Value() for i in range(n)])\n", + " # Can't be one own's Secret Santa\n", + " # (i.e. ensure that there are no fix-point in the array.)\n", " for i in range(n):\n", - " print('%s\\tis a Santa to %s (distance %i)' % \\\n", - " (persons[i],\n", - " persons[santas[i].Value()],\n", - " santa_distance[i].Value()))\n", - " # print 'distance:', [santa_distance[i].Value()\n", - " # for i in range(n)]\n", - " print()\n", + " solver.Add(santas[i] != i)\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " # no Santa for a spouses\n", + " for i in range(n):\n", + " if spouses[i] > -1:\n", + " solver.Add(santas[i] != spouses[i])\n", "\n", - "single = 0\n" + " # optimize 'distance' to earlier rounds:\n", + " for i in range(n):\n", + " solver.Add(santa_distance[i] == solver.Element(rounds[i], santas[i]))\n", + "\n", + " # cannot be a Secret Santa for the same person\n", + " # two years in a row.\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if rounds[i][j] == 1:\n", + " solver.Add(santas[i] != j)\n", + "\n", + " # objective\n", + " objective = solver.Maximize(z, 1)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " db = solver.Phase(santas, solver.CHOOSE_MIN_SIZE_LOWEST_MIN,\n", + " solver.ASSIGN_CENTER_VALUE)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('total distances:', z.Value())\n", + " print('santas:', [santas[i].Value() for i in range(n)])\n", + " for i in range(n):\n", + " print('%s\\tis a Santa to %s (distance %i)' % \\\n", + " (persons[i],\n", + " persons[santas[i].Value()],\n", + " santa_distance[i].Value()))\n", + " # print 'distance:', [santa_distance[i].Value()\n", + " # for i in range(n)]\n", + " print()\n", + "\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "single = 0\n", + "print('Secret Santas without single')\n", + "main(single)\n", + "print('\\nSecret Santas with single:')\n", + "single = 1\n", + "main(single)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/send_more_money_any_base.ipynb b/examples/notebook/contrib/send_more_money_any_base.ipynb index a747ec6968..e0b99b5e2e 100644 --- a/examples/notebook/contrib/send_more_money_any_base.ipynb +++ b/examples/notebook/contrib/send_more_money_any_base.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " SEND+MORE=MONEY in 'any' base in Google CP Solver.\n", "\n", @@ -115,66 +100,83 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(base=10):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Send most money')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Send most money')\n", "\n", - "# data\n", - "print('base:', base)\n", + " # data\n", + " print('base:', base)\n", "\n", - "# declare variables\n", - "s = solver.IntVar(0, base - 1, 's')\n", - "e = solver.IntVar(0, base - 1, 'e')\n", - "n = solver.IntVar(0, base - 1, 'n')\n", - "d = solver.IntVar(0, base - 1, 'd')\n", - "m = solver.IntVar(0, base - 1, 'm')\n", - "o = solver.IntVar(0, base - 1, 'o')\n", - "r = solver.IntVar(0, base - 1, 'r')\n", - "y = solver.IntVar(0, base - 1, 'y')\n", + " # declare variables\n", + " s = solver.IntVar(0, base - 1, 's')\n", + " e = solver.IntVar(0, base - 1, 'e')\n", + " n = solver.IntVar(0, base - 1, 'n')\n", + " d = solver.IntVar(0, base - 1, 'd')\n", + " m = solver.IntVar(0, base - 1, 'm')\n", + " o = solver.IntVar(0, base - 1, 'o')\n", + " r = solver.IntVar(0, base - 1, 'r')\n", + " y = solver.IntVar(0, base - 1, 'y')\n", "\n", - "x = [s, e, n, d, m, o, r, y]\n", + " x = [s, e, n, d, m, o, r, y]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", - "solver.Add(\n", - " s * base**3 + e * base**2 + n * base + d + m * base**3 + o * base**2 +\n", - " r * base + e == m * base**4 + o * base**3 + n * base**2 + e * base + y,)\n", - "solver.Add(s > 0)\n", - "solver.Add(m > 0)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", + " solver.Add(\n", + " s * base**3 + e * base**2 + n * base + d + m * base**3 + o * base**2 +\n", + " r * base + e == m * base**4 + o * base**3 + n * base**2 + e * base + y,)\n", + " solver.Add(s > 0)\n", + " solver.Add(m > 0)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", + " collector = solver.AllSolutionCollector(solution)\n", "\n", - "solver.Solve(\n", - " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE),\n", - " [collector])\n", + " solver.Solve(\n", + " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE),\n", + " [collector])\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "money_val = 0\n", - "for s in range(num_solutions):\n", - " print('x:', [collector.Value(s, x[i]) for i in range(len(x))])\n", + " num_solutions = collector.SolutionCount()\n", + " money_val = 0\n", + " for s in range(num_solutions):\n", + " print('x:', [collector.Value(s, x[i]) for i in range(len(x))])\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime())\n", - "print()\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime())\n", + " print()\n", "\n", - "base = 10\n" + "\n", + "base = 10\n", + "# for base in range(10,30):\n", + "# main(base)\n", + "if len(sys.argv) > 1:\n", + " base = int(sys.argv[1])\n", + "\n", + "main(base)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/send_most_money.ipynb b/examples/notebook/contrib/send_most_money.ipynb index c653950fb7..8d9df8501d 100644 --- a/examples/notebook/contrib/send_most_money.ipynb +++ b/examples/notebook/contrib/send_most_money.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " SEND+MOST=MONEY in Google CP Solver.\n", "\n", @@ -112,77 +97,94 @@ " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", "\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(MONEY=0):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Send most money')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Send most money')\n", "\n", - "# data\n", + " # data\n", "\n", - "# declare variables\n", - "s = solver.IntVar(0, 9, 's')\n", - "e = solver.IntVar(0, 9, 'e')\n", - "n = solver.IntVar(0, 9, 'n')\n", - "d = solver.IntVar(0, 9, 'd')\n", - "m = solver.IntVar(0, 9, 'm')\n", - "o = solver.IntVar(0, 9, 'o')\n", - "t = solver.IntVar(0, 9, 't')\n", - "y = solver.IntVar(0, 9, 'y')\n", - "money = solver.IntVar(0, 100000, 'money')\n", + " # declare variables\n", + " s = solver.IntVar(0, 9, 's')\n", + " e = solver.IntVar(0, 9, 'e')\n", + " n = solver.IntVar(0, 9, 'n')\n", + " d = solver.IntVar(0, 9, 'd')\n", + " m = solver.IntVar(0, 9, 'm')\n", + " o = solver.IntVar(0, 9, 'o')\n", + " t = solver.IntVar(0, 9, 't')\n", + " y = solver.IntVar(0, 9, 'y')\n", + " money = solver.IntVar(0, 100000, 'money')\n", "\n", - "x = [s, e, n, d, m, o, t, y]\n", + " x = [s, e, n, d, m, o, t, y]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "if MONEY > 0:\n", - " solver.Add(money == MONEY)\n", + " #\n", + " # constraints\n", + " #\n", + " if MONEY > 0:\n", + " solver.Add(money == MONEY)\n", "\n", - "solver.Add(solver.AllDifferent(x))\n", - "solver.Add(money == m * 10000 + o * 1000 + n * 100 + e * 10 + y)\n", - "solver.Add(money > 0)\n", - "solver.Add(1000 * s + 100 * e + 10 * n + d + 1000 * m + 100 * o + 10 * s +\n", - " t == money)\n", - "solver.Add(s > 0)\n", - "solver.Add(m > 0)\n", + " solver.Add(solver.AllDifferent(x))\n", + " solver.Add(money == m * 10000 + o * 1000 + n * 100 + e * 10 + y)\n", + " solver.Add(money > 0)\n", + " solver.Add(1000 * s + 100 * e + 10 * n + d + 1000 * m + 100 * o + 10 * s +\n", + " t == money)\n", + " solver.Add(s > 0)\n", + " solver.Add(m > 0)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(money)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(money)\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "objective = solver.Maximize(money, 100)\n", - "cargs = [collector]\n", - "if MONEY == 0:\n", - " objective = solver.Maximize(money, 1)\n", - " cargs.extend([objective])\n", + " collector = solver.AllSolutionCollector(solution)\n", + " objective = solver.Maximize(money, 100)\n", + " cargs = [collector]\n", + " if MONEY == 0:\n", + " objective = solver.Maximize(money, 1)\n", + " cargs.extend([objective])\n", "\n", - "solver.Solve(\n", - " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE),\n", - " cargs)\n", + " solver.Solve(\n", + " solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE),\n", + " cargs)\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "money_val = 0\n", - "for s in range(num_solutions):\n", - " print('x:', [collector.Value(s, x[i]) for i in range(len(x))])\n", - " money_val = collector.Value(s, money)\n", - " print('money:', money_val)\n", - " print()\n", + " num_solutions = collector.SolutionCount()\n", + " money_val = 0\n", + " for s in range(num_solutions):\n", + " print('x:', [collector.Value(s, x[i]) for i in range(len(x))])\n", + " money_val = collector.Value(s, money)\n", + " print('money:', money_val)\n", + " print()\n", "\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime())\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime())\n", "\n", - "if MONEY == 0:\n", - " return money_val\n", + " if MONEY == 0:\n", + " return money_val\n", + "\n", + "\n", + "# First get the maximised MONEY, and then show all solutions for\n", + "# this value\n", + "print('Minimize money...')\n", + "money = main(0)\n", + "print('\\nCheck all solutions for money=%i' % money)\n", + "main(money)\n", "\n" ] } diff --git a/examples/notebook/contrib/seseman.ipynb b/examples/notebook/contrib/seseman.ipynb index d81dcb99f5..589e40f03a 100644 --- a/examples/notebook/contrib/seseman.ipynb +++ b/examples/notebook/contrib/seseman.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Seseman Convent problem in Google CP Solver.\n", "\n", @@ -127,83 +112,95 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Seseman Convent problem\")\n", + "def main(unused_argv):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Seseman Convent problem\")\n", "\n", - "# data\n", - "n = 3\n", - "border_sum = n * n\n", + " # data\n", + " n = 3\n", + " border_sum = n * n\n", "\n", - "# declare variables\n", - "total_sum = solver.IntVar(1, n * n * n * n, \"total_sum\")\n", - "# x[0..n-1,0..n-1]\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[(i, j)] = solver.IntVar(0, n * n, \"x %i %i\" % (i, j))\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "# zero all middle cells\n", - "for i in range(1, n - 1):\n", - " for j in range(1, n - 1):\n", - " solver.Add(x[(i, j)] == 0)\n", - "\n", - "# all borders must be >= 1\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if i == 0 or j == 0 or i == n - 1 or j == n - 1:\n", - " solver.Add(x[(i, j)] >= 1)\n", - "\n", - "# sum the borders (border_sum)\n", - "solver.Add(solver.Sum([x[(i, 0)] for i in range(n)]) == border_sum)\n", - "solver.Add(solver.Sum([x[(i, n - 1)] for i in range(n)]) == border_sum)\n", - "solver.Add(solver.Sum([x[(0, i)] for i in range(n)]) == border_sum)\n", - "solver.Add(solver.Sum([x[(n - 1, i)] for i in range(n)]) == border_sum)\n", - "\n", - "# total\n", - "solver.Add(\n", - " solver.Sum([x[(i, j)] for i in range(n) for j in range(n)]) == total_sum)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([x[(i, j)] for i in range(n) for j in range(n)])\n", - "solution.Add(total_sum)\n", - "\n", - "# all solutions\n", - "collector = solver.AllSolutionCollector(solution)\n", - "# search_log = solver.SearchLog(100, total_sum)\n", - "solver.Solve(\n", - " solver.Phase([x[(i, j)] for i in range(n) for j in range(n)],\n", - " solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE), [collector])\n", - "#[collector, search_log])\n", - "\n", - "num_solutions = collector.SolutionCount()\n", - "# print \"x:\", x\n", - "print(\"num_solutions:\", num_solutions)\n", - "print()\n", - "for s in range(num_solutions):\n", - " # print [collector.Value(s, x[(i,j)])\n", - " # for i in range(n) for j in range(n)]\n", - " print(\"total_sum:\", collector.Value(s, total_sum))\n", + " # declare variables\n", + " total_sum = solver.IntVar(1, n * n * n * n, \"total_sum\")\n", + " # x[0..n-1,0..n-1]\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " print(collector.Value(s, x[(i, j)]), end=\" \")\n", - " print()\n", - " print()\n", + " x[(i, j)] = solver.IntVar(0, n * n, \"x %i %i\" % (i, j))\n", "\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print(\"num_solutions:\", num_solutions)\n", + " #\n", + " # constraints\n", + " #\n", + " # zero all middle cells\n", + " for i in range(1, n - 1):\n", + " for j in range(1, n - 1):\n", + " solver.Add(x[(i, j)] == 0)\n", + "\n", + " # all borders must be >= 1\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if i == 0 or j == 0 or i == n - 1 or j == n - 1:\n", + " solver.Add(x[(i, j)] >= 1)\n", + "\n", + " # sum the borders (border_sum)\n", + " solver.Add(solver.Sum([x[(i, 0)] for i in range(n)]) == border_sum)\n", + " solver.Add(solver.Sum([x[(i, n - 1)] for i in range(n)]) == border_sum)\n", + " solver.Add(solver.Sum([x[(0, i)] for i in range(n)]) == border_sum)\n", + " solver.Add(solver.Sum([x[(n - 1, i)] for i in range(n)]) == border_sum)\n", + "\n", + " # total\n", + " solver.Add(\n", + " solver.Sum([x[(i, j)] for i in range(n) for j in range(n)]) == total_sum)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([x[(i, j)] for i in range(n) for j in range(n)])\n", + " solution.Add(total_sum)\n", + "\n", + " # all solutions\n", + " collector = solver.AllSolutionCollector(solution)\n", + " # search_log = solver.SearchLog(100, total_sum)\n", + " solver.Solve(\n", + " solver.Phase([x[(i, j)] for i in range(n) for j in range(n)],\n", + " solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE), [collector])\n", + " #[collector, search_log])\n", + "\n", + " num_solutions = collector.SolutionCount()\n", + " # print \"x:\", x\n", + " print(\"num_solutions:\", num_solutions)\n", + " print()\n", + " for s in range(num_solutions):\n", + " # print [collector.Value(s, x[(i,j)])\n", + " # for i in range(n) for j in range(n)]\n", + " print(\"total_sum:\", collector.Value(s, total_sum))\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(collector.Value(s, x[(i, j)]), end=\" \")\n", + " print()\n", + " print()\n", + "\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print(\"num_solutions:\", num_solutions)\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/seseman_b.ipynb b/examples/notebook/contrib/seseman_b.ipynb index 2f27f9ff75..cfb139fdb2 100644 --- a/examples/notebook/contrib/seseman_b.ipynb +++ b/examples/notebook/contrib/seseman_b.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Seseman Convent problem in Google CP Solver.\n", "\n", @@ -129,77 +114,89 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Seseman Convent problem\")\n", + "def main(unused_argv):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Seseman Convent problem\")\n", "\n", - "# data\n", - "n = 3\n", - "border_sum = n * n\n", + " # data\n", + " n = 3\n", + " border_sum = n * n\n", "\n", - "# declare variables\n", - "total_sum = solver.IntVar(1, n * n * n * n, \"total_sum\")\n", - "# x[0..n-1,0..n-1]\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[(i, j)] = solver.IntVar(0, n * n, \"x %i %i\" % (i, j))\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "# zero all middle cells\n", - "for i in range(1, n - 1):\n", - " for j in range(1, n - 1):\n", - " solver.Add(x[(i, j)] == 0)\n", - "\n", - "# all borders must be >= 1\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if i == 0 or j == 0 or i == n - 1 or j == n - 1:\n", - " solver.Add(x[(i, j)] >= 1)\n", - "\n", - "# sum the borders (border_sum)\n", - "solver.Add(solver.Sum([x[(i, 0)] for i in range(n)]) == border_sum)\n", - "solver.Add(solver.Sum([x[(i, n - 1)] for i in range(n)]) == border_sum)\n", - "solver.Add(solver.Sum([x[(0, i)] for i in range(n)]) == border_sum)\n", - "solver.Add(solver.Sum([x[(n - 1, i)] for i in range(n)]) == border_sum)\n", - "\n", - "# total\n", - "solver.Add(\n", - " solver.Sum([x[(i, j)] for i in range(n) for j in range(n)]) == total_sum)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([x[(i, j)] for i in range(n) for j in range(n)])\n", - "solution.Add(total_sum)\n", - "\n", - "db = solver.Phase([x[(i, j)] for i in range(n) for j in range(n)],\n", - " solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print(\"total_sum:\", total_sum.Value())\n", + " # declare variables\n", + " total_sum = solver.IntVar(1, n * n * n * n, \"total_sum\")\n", + " # x[0..n-1,0..n-1]\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " print(x[(i, j)].Value(), end=\" \")\n", - " print()\n", - " print()\n", + " x[(i, j)] = solver.IntVar(0, n * n, \"x %i %i\" % (i, j))\n", "\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " #\n", + " # constraints\n", + " #\n", + " # zero all middle cells\n", + " for i in range(1, n - 1):\n", + " for j in range(1, n - 1):\n", + " solver.Add(x[(i, j)] == 0)\n", + "\n", + " # all borders must be >= 1\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if i == 0 or j == 0 or i == n - 1 or j == n - 1:\n", + " solver.Add(x[(i, j)] >= 1)\n", + "\n", + " # sum the borders (border_sum)\n", + " solver.Add(solver.Sum([x[(i, 0)] for i in range(n)]) == border_sum)\n", + " solver.Add(solver.Sum([x[(i, n - 1)] for i in range(n)]) == border_sum)\n", + " solver.Add(solver.Sum([x[(0, i)] for i in range(n)]) == border_sum)\n", + " solver.Add(solver.Sum([x[(n - 1, i)] for i in range(n)]) == border_sum)\n", + "\n", + " # total\n", + " solver.Add(\n", + " solver.Sum([x[(i, j)] for i in range(n) for j in range(n)]) == total_sum)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([x[(i, j)] for i in range(n) for j in range(n)])\n", + " solution.Add(total_sum)\n", + "\n", + " db = solver.Phase([x[(i, j)] for i in range(n) for j in range(n)],\n", + " solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + "\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print(\"total_sum:\", total_sum.Value())\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(x[(i, j)].Value(), end=\" \")\n", + " print()\n", + " print()\n", + "\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/set_covering.ipynb b/examples/notebook/contrib/set_covering.ipynb index 727f3799e3..24db7224d9 100644 --- a/examples/notebook/contrib/set_covering.ipynb +++ b/examples/notebook/contrib/set_covering.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Set covering in Google CP Solver.\n", "\n", @@ -104,62 +89,74 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(unused_argv):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Set covering\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Set covering\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "min_distance = 15\n", - "num_cities = 6\n", + " #\n", + " # data\n", + " #\n", + " min_distance = 15\n", + " num_cities = 6\n", "\n", - "distance = [[0, 10, 20, 30, 30, 20], [10, 0, 25, 35, 20, 10],\n", - " [20, 25, 0, 15, 30, 20], [30, 35, 15, 0, 15, 25],\n", - " [30, 20, 30, 15, 0, 14], [20, 10, 20, 25, 14, 0]]\n", + " distance = [[0, 10, 20, 30, 30, 20], [10, 0, 25, 35, 20, 10],\n", + " [20, 25, 0, 15, 30, 20], [30, 35, 15, 0, 15, 25],\n", + " [30, 20, 30, 15, 0, 14], [20, 10, 20, 25, 14, 0]]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(0, 1, \"x[%i]\" % i) for i in range(num_cities)]\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(0, 1, \"x[%i]\" % i) for i in range(num_cities)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# objective to minimize\n", - "z = solver.Sum(x)\n", + " # objective to minimize\n", + " z = solver.Sum(x)\n", "\n", - "# ensure that all cities are covered\n", - "for i in range(num_cities):\n", - " b = [x[j] for j in range(num_cities) if distance[i][j] <= min_distance]\n", - " solver.Add(solver.SumGreaterOrEqual(b, 1))\n", + " # ensure that all cities are covered\n", + " for i in range(num_cities):\n", + " b = [x[j] for j in range(num_cities) if distance[i][j] <= min_distance]\n", + " solver.Add(solver.SumGreaterOrEqual(b, 1))\n", "\n", - "objective = solver.Minimize(z, 1)\n", + " objective = solver.Minimize(z, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.AddObjective(z)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.AddObjective(z)\n", "\n", - "collector = solver.LastSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase(x + [z], solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", - " [collector, objective])\n", + " collector = solver.LastSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase(x + [z], solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", + " [collector, objective])\n", "\n", - "print(\"z:\", collector.ObjectiveValue(0))\n", - "print(\"x:\", [collector.Value(0, x[i]) for i in range(num_cities)])\n", + " print(\"z:\", collector.ObjectiveValue(0))\n", + " print(\"x:\", [collector.Value(0, x[i]) for i in range(num_cities)])\n", "\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/set_covering2.ipynb b/examples/notebook/contrib/set_covering2.ipynb index 97292309b9..cdd73cf3f2 100644 --- a/examples/notebook/contrib/set_covering2.ipynb +++ b/examples/notebook/contrib/set_covering2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Set covering in Google CP Solver.\n", "\n", @@ -106,63 +91,75 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(unused_argv):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Set covering\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Set covering\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 8 # maximum number of corners\n", - "num_streets = 11 # number of connected streets\n", + " #\n", + " # data\n", + " #\n", + " n = 8 # maximum number of corners\n", + " num_streets = 11 # number of connected streets\n", "\n", - "# corners of each street\n", - "# Note: 1-based (handled below)\n", - "corner = [[1, 2], [2, 3], [4, 5], [7, 8], [6, 7], [2, 6], [1, 6], [4, 7],\n", - " [2, 4], [5, 8], [3, 5]]\n", + " # corners of each street\n", + " # Note: 1-based (handled below)\n", + " corner = [[1, 2], [2, 3], [4, 5], [7, 8], [6, 7], [2, 6], [1, 6], [4, 7],\n", + " [2, 4], [5, 8], [3, 5]]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(0, 1, \"x[%i]\" % i) for i in range(n)]\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(0, 1, \"x[%i]\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# number of telephones, to be minimized\n", - "z = solver.Sum(x)\n", + " # number of telephones, to be minimized\n", + " z = solver.Sum(x)\n", "\n", - "# ensure that all corners are covered\n", - "for i in range(num_streets):\n", - " # also, convert to 0-based\n", - " solver.Add(solver.SumGreaterOrEqual([x[j - 1] for j in corner[i]], 1))\n", + " # ensure that all corners are covered\n", + " for i in range(num_streets):\n", + " # also, convert to 0-based\n", + " solver.Add(solver.SumGreaterOrEqual([x[j - 1] for j in corner[i]], 1))\n", "\n", - "objective = solver.Minimize(z, 1)\n", + " objective = solver.Minimize(z, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.AddObjective(z)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.AddObjective(z)\n", "\n", - "collector = solver.LastSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", - " [collector, objective])\n", + " collector = solver.LastSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", + " [collector, objective])\n", "\n", - "print(\"z:\", collector.ObjectiveValue(0))\n", - "print(\"x:\", [collector.Value(0, x[i]) for i in range(n)])\n", + " print(\"z:\", collector.ObjectiveValue(0))\n", + " print(\"x:\", [collector.Value(0, x[i]) for i in range(n)])\n", "\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/set_covering3.ipynb b/examples/notebook/contrib/set_covering3.ipynb index 5b89b64075..6553e8fe7b 100644 --- a/examples/notebook/contrib/set_covering3.ipynb +++ b/examples/notebook/contrib/set_covering3.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Set covering in Google CP Solver.\n", "\n", @@ -119,78 +104,90 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(unused_argv):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Set covering\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Set covering\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "num_groups = 6\n", - "num_senators = 10\n", + " #\n", + " # data\n", + " #\n", + " num_groups = 6\n", + " num_senators = 10\n", "\n", - "# which group does a senator belong to?\n", - "belongs = [\n", - " [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], # 1 southern\n", - " [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], # 2 northern\n", - " [0, 1, 1, 0, 0, 0, 0, 1, 1, 1], # 3 liberals\n", - " [1, 0, 0, 0, 1, 1, 1, 0, 0, 0], # 4 conservative\n", - " [0, 0, 1, 1, 1, 1, 1, 0, 1, 0], # 5 democrats\n", - " [1, 1, 0, 0, 0, 0, 0, 1, 0, 1] # 6 republicans\n", - "]\n", + " # which group does a senator belong to?\n", + " belongs = [\n", + " [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], # 1 southern\n", + " [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], # 2 northern\n", + " [0, 1, 1, 0, 0, 0, 0, 1, 1, 1], # 3 liberals\n", + " [1, 0, 0, 0, 1, 1, 1, 0, 0, 0], # 4 conservative\n", + " [0, 0, 1, 1, 1, 1, 1, 0, 1, 0], # 5 democrats\n", + " [1, 1, 0, 0, 0, 0, 0, 1, 0, 1] # 6 republicans\n", + " ]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(0, 1, \"x[%i]\" % i) for i in range(num_senators)]\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(0, 1, \"x[%i]\" % i) for i in range(num_senators)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# number of assigned senators (to minimize)\n", - "z = solver.Sum(x)\n", + " # number of assigned senators (to minimize)\n", + " z = solver.Sum(x)\n", "\n", - "# ensure that each group is covered by at least\n", - "# one senator\n", - "for i in range(num_groups):\n", - " solver.Add(\n", - " solver.SumGreaterOrEqual(\n", - " [x[j] * belongs[i][j] for j in range(num_senators)], 1))\n", + " # ensure that each group is covered by at least\n", + " # one senator\n", + " for i in range(num_groups):\n", + " solver.Add(\n", + " solver.SumGreaterOrEqual(\n", + " [x[j] * belongs[i][j] for j in range(num_senators)], 1))\n", "\n", - "objective = solver.Minimize(z, 1)\n", + " objective = solver.Minimize(z, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.AddObjective(z)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.AddObjective(z)\n", "\n", - "collector = solver.LastSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", - " [collector, objective])\n", + " collector = solver.LastSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", + " [collector, objective])\n", "\n", - "print(\"z:\", collector.ObjectiveValue(0))\n", - "print(\"x:\", [collector.Value(0, x[i]) for i in range(num_senators)])\n", - "for j in range(num_senators):\n", - " if collector.Value(0, x[j]) == 1:\n", - " print(\"Senator\", j + 1, \"belongs to these groups:\", end=\" \")\n", - " for i in range(num_groups):\n", - " if belongs[i][j] == 1:\n", - " print(i + 1, end=\" \")\n", - " print()\n", + " print(\"z:\", collector.ObjectiveValue(0))\n", + " print(\"x:\", [collector.Value(0, x[i]) for i in range(num_senators)])\n", + " for j in range(num_senators):\n", + " if collector.Value(0, x[j]) == 1:\n", + " print(\"Senator\", j + 1, \"belongs to these groups:\", end=\" \")\n", + " for i in range(num_groups):\n", + " if belongs[i][j] == 1:\n", + " print(i + 1, end=\" \")\n", + " print()\n", "\n", - "print()\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print()\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/set_covering4.ipynb b/examples/notebook/contrib/set_covering4.ipynb index 96ec7616ea..b13138c9b2 100644 --- a/examples/notebook/contrib/set_covering4.ipynb +++ b/examples/notebook/contrib/set_covering4.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Set partition and set covering in Google CP Solver.\n", "\n", @@ -139,86 +124,102 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(set_partition=1):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Set partition and set covering\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Set partition and set covering\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "num_alternatives = 10\n", - "num_objects = 8\n", + " #\n", + " # data\n", + " #\n", + " num_alternatives = 10\n", + " num_objects = 8\n", "\n", - "# costs for the alternatives\n", - "costs = [19, 16, 18, 13, 15, 19, 15, 17, 16, 15]\n", + " # costs for the alternatives\n", + " costs = [19, 16, 18, 13, 15, 19, 15, 17, 16, 15]\n", "\n", - "# the alternatives, and their objects\n", - "a = [\n", - " # 1 2 3 4 5 6 7 8 the objects\n", - " [1, 0, 0, 0, 0, 1, 0, 0], # alternative 1\n", - " [0, 1, 0, 0, 0, 1, 0, 1], # alternative 2\n", - " [1, 0, 0, 1, 0, 0, 1, 0], # alternative 3\n", - " [0, 1, 1, 0, 1, 0, 0, 0], # alternative 4\n", - " [0, 1, 0, 0, 1, 0, 0, 0], # alternative 5\n", - " [0, 1, 1, 0, 0, 0, 0, 0], # alternative 6\n", - " [0, 1, 1, 1, 0, 0, 0, 0], # alternative 7\n", - " [0, 0, 0, 1, 1, 0, 0, 1], # alternative 8\n", - " [0, 0, 1, 0, 0, 1, 0, 1], # alternative 9\n", - " [1, 0, 0, 0, 0, 1, 1, 0] # alternative 10\n", - "]\n", + " # the alternatives, and their objects\n", + " a = [\n", + " # 1 2 3 4 5 6 7 8 the objects\n", + " [1, 0, 0, 0, 0, 1, 0, 0], # alternative 1\n", + " [0, 1, 0, 0, 0, 1, 0, 1], # alternative 2\n", + " [1, 0, 0, 1, 0, 0, 1, 0], # alternative 3\n", + " [0, 1, 1, 0, 1, 0, 0, 0], # alternative 4\n", + " [0, 1, 0, 0, 1, 0, 0, 0], # alternative 5\n", + " [0, 1, 1, 0, 0, 0, 0, 0], # alternative 6\n", + " [0, 1, 1, 1, 0, 0, 0, 0], # alternative 7\n", + " [0, 0, 0, 1, 1, 0, 0, 1], # alternative 8\n", + " [0, 0, 1, 0, 0, 1, 0, 1], # alternative 9\n", + " [1, 0, 0, 0, 0, 1, 1, 0] # alternative 10\n", + " ]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = [solver.IntVar(0, 1, \"x[%i]\" % i) for i in range(num_alternatives)]\n", + " #\n", + " # declare variables\n", + " #\n", + " x = [solver.IntVar(0, 1, \"x[%i]\" % i) for i in range(num_alternatives)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# sum the cost of the choosen alternative,\n", - "# to be minimized\n", - "z = solver.ScalProd(x, costs)\n", + " # sum the cost of the choosen alternative,\n", + " # to be minimized\n", + " z = solver.ScalProd(x, costs)\n", "\n", - "#\n", - "for j in range(num_objects):\n", - " if set_partition == 1:\n", - " solver.Add(\n", - " solver.SumEquality([x[i] * a[i][j] for i in range(num_alternatives)],\n", - " 1))\n", - " else:\n", - " solver.Add(\n", - " solver.SumGreaterOrEqual(\n", - " [x[i] * a[i][j] for i in range(num_alternatives)], 1))\n", + " #\n", + " for j in range(num_objects):\n", + " if set_partition == 1:\n", + " solver.Add(\n", + " solver.SumEquality([x[i] * a[i][j] for i in range(num_alternatives)],\n", + " 1))\n", + " else:\n", + " solver.Add(\n", + " solver.SumGreaterOrEqual(\n", + " [x[i] * a[i][j] for i in range(num_alternatives)], 1))\n", "\n", - "objective = solver.Minimize(z, 1)\n", + " objective = solver.Minimize(z, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.AddObjective(z)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.AddObjective(z)\n", "\n", - "collector = solver.LastSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase([x[i] for i in range(num_alternatives)],\n", - " solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", - " [collector, objective])\n", + " collector = solver.LastSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase([x[i] for i in range(num_alternatives)],\n", + " solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", + " [collector, objective])\n", "\n", - "print(\"z:\", collector.ObjectiveValue(0))\n", - "print(\n", - " \"selected alternatives:\",\n", - " [i + 1 for i in range(num_alternatives) if collector.Value(0, x[i]) == 1])\n", + " print(\"z:\", collector.ObjectiveValue(0))\n", + " print(\n", + " \"selected alternatives:\",\n", + " [i + 1 for i in range(num_alternatives) if collector.Value(0, x[i]) == 1])\n", "\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "print(\"Set partition:\")\n", + "main(1)\n", + "\n", + "print(\"\\nSet covering:\")\n", + "main(0)\n", "\n" ] } diff --git a/examples/notebook/contrib/set_covering_deployment.ipynb b/examples/notebook/contrib/set_covering_deployment.ipynb index b0cf8f08ff..615ad39c9f 100644 --- a/examples/notebook/contrib/set_covering_deployment.ipynb +++ b/examples/notebook/contrib/set_covering_deployment.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Set covering deployment in Google CP Solver\n", "\n", @@ -112,94 +97,106 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Set covering deployment\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Set covering deployment\")\n", "\n", - "#\n", - "# data\n", - "#\n", + " #\n", + " # data\n", + " #\n", "\n", - "countries = [\n", - " \"Alexandria\", \"Asia Minor\", \"Britain\", \"Byzantium\", \"Gaul\", \"Iberia\",\n", - " \"Rome\", \"Tunis\"\n", - "]\n", - "n = len(countries)\n", + " countries = [\n", + " \"Alexandria\", \"Asia Minor\", \"Britain\", \"Byzantium\", \"Gaul\", \"Iberia\",\n", + " \"Rome\", \"Tunis\"\n", + " ]\n", + " n = len(countries)\n", "\n", - "# the incidence matrix (neighbours)\n", - "mat = [[0, 1, 0, 1, 0, 0, 1, 1], [1, 0, 0, 1, 0, 0, 0, 0],\n", - " [0, 0, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0],\n", - " [0, 0, 1, 0, 0, 1, 1, 0], [0, 0, 1, 0, 1, 0, 1, 1],\n", - " [1, 0, 0, 1, 1, 1, 0, 1], [1, 0, 0, 0, 0, 1, 1, 0]]\n", + " # the incidence matrix (neighbours)\n", + " mat = [[0, 1, 0, 1, 0, 0, 1, 1], [1, 0, 0, 1, 0, 0, 0, 0],\n", + " [0, 0, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0],\n", + " [0, 0, 1, 0, 0, 1, 1, 0], [0, 0, 1, 0, 1, 0, 1, 1],\n", + " [1, 0, 0, 1, 1, 1, 0, 1], [1, 0, 0, 0, 0, 1, 1, 0]]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", + " #\n", + " # declare variables\n", + " #\n", "\n", - "# First army\n", - "X = [solver.IntVar(0, 1, \"X[%i]\" % i) for i in range(n)]\n", + " # First army\n", + " X = [solver.IntVar(0, 1, \"X[%i]\" % i) for i in range(n)]\n", "\n", - "# Second (reserv) army\n", - "Y = [solver.IntVar(0, 1, \"Y[%i]\" % i) for i in range(n)]\n", + " # Second (reserv) army\n", + " Y = [solver.IntVar(0, 1, \"Y[%i]\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# total number of armies\n", - "num_armies = solver.Sum([X[i] + Y[i] for i in range(n)])\n", + " # total number of armies\n", + " num_armies = solver.Sum([X[i] + Y[i] for i in range(n)])\n", "\n", - "#\n", - "# Constraint 1: There is always an army in a city\n", - "# (+ maybe a backup)\n", - "# Or rather: Is there a backup, there\n", - "# must be an an army\n", - "#\n", - "[solver.Add(X[i] >= Y[i]) for i in range(n)]\n", + " #\n", + " # Constraint 1: There is always an army in a city\n", + " # (+ maybe a backup)\n", + " # Or rather: Is there a backup, there\n", + " # must be an an army\n", + " #\n", + " [solver.Add(X[i] >= Y[i]) for i in range(n)]\n", "\n", - "#\n", - "# Constraint 2: There should always be an backup army near every city\n", - "#\n", - "for i in range(n):\n", - " neighbors = solver.Sum([Y[j] for j in range(n) if mat[i][j] == 1])\n", - " solver.Add(X[i] + neighbors >= 1)\n", + " #\n", + " # Constraint 2: There should always be an backup army near every city\n", + " #\n", + " for i in range(n):\n", + " neighbors = solver.Sum([Y[j] for j in range(n) if mat[i][j] == 1])\n", + " solver.Add(X[i] + neighbors >= 1)\n", "\n", - "objective = solver.Minimize(num_armies, 1)\n", + " objective = solver.Minimize(num_armies, 1)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(X)\n", - "solution.Add(Y)\n", - "solution.Add(num_armies)\n", - "solution.AddObjective(num_armies)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(X)\n", + " solution.Add(Y)\n", + " solution.Add(num_armies)\n", + " solution.AddObjective(num_armies)\n", "\n", - "collector = solver.LastSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase(X + Y, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", - " [collector, objective])\n", + " collector = solver.LastSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase(X + Y, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT),\n", + " [collector, objective])\n", "\n", - "print(\"num_armies:\", collector.ObjectiveValue(0))\n", - "print(\"X:\", [collector.Value(0, X[i]) for i in range(n)])\n", - "print(\"Y:\", [collector.Value(0, Y[i]) for i in range(n)])\n", + " print(\"num_armies:\", collector.ObjectiveValue(0))\n", + " print(\"X:\", [collector.Value(0, X[i]) for i in range(n)])\n", + " print(\"Y:\", [collector.Value(0, Y[i]) for i in range(n)])\n", "\n", - "for i in range(n):\n", - " if collector.Value(0, X[i]) == 1:\n", - " print(\"army:\", countries[i], end=\" \")\n", - " if collector.Value(0, Y[i]) == 1:\n", - " print(\"reserv army:\", countries[i], \" \")\n", - "print()\n", + " for i in range(n):\n", + " if collector.Value(0, X[i]) == 1:\n", + " print(\"army:\", countries[i], end=\" \")\n", + " if collector.Value(0, Y[i]) == 1:\n", + " print(\"reserv army:\", countries[i], \" \")\n", + " print()\n", "\n", - "print()\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print()\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/set_covering_skiena.ipynb b/examples/notebook/contrib/set_covering_skiena.ipynb index a26ae65143..36d35c7e2d 100644 --- a/examples/notebook/contrib/set_covering_skiena.ipynb +++ b/examples/notebook/contrib/set_covering_skiena.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Set covering in Google CP Solver.\n", "\n", @@ -112,81 +97,93 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Set covering Skiena')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Set covering Skiena')\n", "\n", - "#\n", - "# data\n", - "#\n", - "num_sets = 7\n", - "num_elements = 12\n", - "belongs = [\n", - " # 1 2 3 4 5 6 7 8 9 0 1 2 elements\n", - " [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # Set 1\n", - " [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], # 2\n", - " [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], # 3\n", - " [0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0], # 4\n", - " [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], # 5\n", - " [1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0], # 6\n", - " [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1] # 7\n", - "]\n", + " #\n", + " # data\n", + " #\n", + " num_sets = 7\n", + " num_elements = 12\n", + " belongs = [\n", + " # 1 2 3 4 5 6 7 8 9 0 1 2 elements\n", + " [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], # Set 1\n", + " [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], # 2\n", + " [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], # 3\n", + " [0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0], # 4\n", + " [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], # 5\n", + " [1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0], # 6\n", + " [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1] # 7\n", + " ]\n", "\n", - "#\n", - "# variables\n", - "#\n", - "x = [solver.IntVar(0, 1, 'x[%i]' % i) for i in range(num_sets)]\n", + " #\n", + " # variables\n", + " #\n", + " x = [solver.IntVar(0, 1, 'x[%i]' % i) for i in range(num_sets)]\n", "\n", - "# number of choosen sets\n", - "z = solver.IntVar(0, num_sets * 2, 'z')\n", + " # number of choosen sets\n", + " z = solver.IntVar(0, num_sets * 2, 'z')\n", "\n", - "# total number of elements in the choosen sets\n", - "tot_elements = solver.IntVar(0, num_sets * num_elements)\n", + " # total number of elements in the choosen sets\n", + " tot_elements = solver.IntVar(0, num_sets * num_elements)\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(z == solver.Sum(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(z == solver.Sum(x))\n", "\n", - "# all sets must be used\n", - "for j in range(num_elements):\n", - " s = solver.Sum([belongs[i][j] * x[i] for i in range(num_sets)])\n", - " solver.Add(s >= 1)\n", + " # all sets must be used\n", + " for j in range(num_elements):\n", + " s = solver.Sum([belongs[i][j] * x[i] for i in range(num_sets)])\n", + " solver.Add(s >= 1)\n", "\n", - "# number of used elements\n", - "solver.Add(tot_elements == solver.Sum([\n", - " x[i] * belongs[i][j] for i in range(num_sets) for j in range(num_elements)\n", - "]))\n", + " # number of used elements\n", + " solver.Add(tot_elements == solver.Sum([\n", + " x[i] * belongs[i][j] for i in range(num_sets) for j in range(num_elements)\n", + " ]))\n", "\n", - "# objective\n", - "objective = solver.Minimize(z, 1)\n", + " # objective\n", + " objective = solver.Minimize(z, 1)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db, [objective])\n", + " solver.NewSearch(db, [objective])\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('z:', z.Value())\n", - " print('tot_elements:', tot_elements.Value())\n", - " print('x:', [x[i].Value() for i in range(num_sets)])\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('z:', z.Value())\n", + " print('tot_elements:', tot_elements.Value())\n", + " print('x:', [x[i].Value() for i in range(num_sets)])\n", "\n", - "solver.EndSearch()\n", + " solver.EndSearch()\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/set_partition.ipynb b/examples/notebook/contrib/set_partition.ipynb index e42e954dfb..e3d9c225c5 100644 --- a/examples/notebook/contrib/set_partition.ipynb +++ b/examples/notebook/contrib/set_partition.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Set partition problem in Google CP Solver.\n", "\n", @@ -118,8 +103,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -143,101 +136,110 @@ " solver.Add(solver.Sum(b) == n)\n", "\n", "\n", + "def main(n=16, num_sets=2):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Set partition\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Set partition\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"n:\", n)\n", - "print(\"num_sets:\", num_sets)\n", - "print()\n", + " #\n", + " # data\n", + " #\n", + " print(\"n:\", n)\n", + " print(\"num_sets:\", num_sets)\n", + " print()\n", "\n", - "# Check sizes\n", - "assert n % num_sets == 0, \"Equal sets is not possible.\"\n", + " # Check sizes\n", + " assert n % num_sets == 0, \"Equal sets is not possible.\"\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "# the set\n", - "a = {}\n", - "for i in range(num_sets):\n", - " for j in range(n):\n", - " a[i, j] = solver.IntVar(0, 1, \"a[%i,%i]\" % (i, j))\n", - "\n", - "a_flat = [a[i, j] for i in range(num_sets) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# partition set\n", - "partition_sets(a, num_sets, n)\n", - "\n", - "for i in range(num_sets):\n", - " for j in range(i, num_sets):\n", - "\n", - " # same cardinality\n", - " solver.Add(\n", - " solver.Sum([a[i, k] for k in range(n)]) == solver.Sum(\n", - " [a[j, k] for k in range(n)]))\n", - "\n", - " # same sum\n", - " solver.Add(\n", - " solver.Sum([k * a[i, k] for k in range(n)]) == solver.Sum(\n", - " [k * a[j, k] for k in range(n)]))\n", - "\n", - " # same sum squared\n", - " solver.Add(\n", - " solver.Sum([(k * a[i, k]) * (k * a[i, k]) for k in range(n)]) ==\n", - " solver.Sum([(k * a[j, k]) * (k * a[j, k]) for k in range(n)]))\n", - "\n", - "# symmetry breaking for num_sets == 2\n", - "if num_sets == 2:\n", - " solver.Add(a[0, 0] == 1)\n", - "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(a_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " a_val = {}\n", + " # the set\n", + " a = {}\n", " for i in range(num_sets):\n", " for j in range(n):\n", - " a_val[i, j] = a[i, j].Value()\n", + " a[i, j] = solver.IntVar(0, 1, \"a[%i,%i]\" % (i, j))\n", "\n", - " sq = sum([(j + 1) * a_val[0, j] for j in range(n)])\n", - " print(\"sums:\", sq)\n", - " sq2 = sum([((j + 1) * a_val[0, j])**2 for j in range(n)])\n", - " print(\"sums squared:\", sq2)\n", + " a_flat = [a[i, j] for i in range(num_sets) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # partition set\n", + " partition_sets(a, num_sets, n)\n", "\n", " for i in range(num_sets):\n", - " if sum([a_val[i, j] for j in range(n)]):\n", - " print(i + 1, \":\", end=\" \")\n", + " for j in range(i, num_sets):\n", + "\n", + " # same cardinality\n", + " solver.Add(\n", + " solver.Sum([a[i, k] for k in range(n)]) == solver.Sum(\n", + " [a[j, k] for k in range(n)]))\n", + "\n", + " # same sum\n", + " solver.Add(\n", + " solver.Sum([k * a[i, k] for k in range(n)]) == solver.Sum(\n", + " [k * a[j, k] for k in range(n)]))\n", + "\n", + " # same sum squared\n", + " solver.Add(\n", + " solver.Sum([(k * a[i, k]) * (k * a[i, k]) for k in range(n)]) ==\n", + " solver.Sum([(k * a[j, k]) * (k * a[j, k]) for k in range(n)]))\n", + "\n", + " # symmetry breaking for num_sets == 2\n", + " if num_sets == 2:\n", + " solver.Add(a[0, 0] == 1)\n", + "\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(a_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " a_val = {}\n", + " for i in range(num_sets):\n", " for j in range(n):\n", - " if a_val[i, j] == 1:\n", - " print(j + 1, end=\" \")\n", - " print()\n", + " a_val[i, j] = a[i, j].Value()\n", + "\n", + " sq = sum([(j + 1) * a_val[0, j] for j in range(n)])\n", + " print(\"sums:\", sq)\n", + " sq2 = sum([((j + 1) * a_val[0, j])**2 for j in range(n)])\n", + " print(\"sums squared:\", sq2)\n", + "\n", + " for i in range(num_sets):\n", + " if sum([a_val[i, j] for j in range(n)]):\n", + " print(i + 1, \":\", end=\" \")\n", + " for j in range(n):\n", + " if a_val[i, j] == 1:\n", + " print(j + 1, end=\" \")\n", + " print()\n", + "\n", + " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "n = 16\n", - "num_sets = 2\n" + "num_sets = 2\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", + "if len(sys.argv) > 2:\n", + " num_sets = int(sys.argv[2])\n", + "\n", + "main(n, num_sets)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/sicherman_dice.ipynb b/examples/notebook/contrib/sicherman_dice.ipynb index 44c49debc1..a9790f6587 100644 --- a/examples/notebook/contrib/sicherman_dice.ipynb +++ b/examples/notebook/contrib/sicherman_dice.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Sicherman Dice in Google CP Solver.\n", "\n", @@ -132,81 +117,93 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Sicherman dice\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Sicherman dice\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 6\n", - "m = 10\n", + " #\n", + " # data\n", + " #\n", + " n = 6\n", + " m = 10\n", "\n", - "# standard distribution\n", - "standard_dist = [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]\n", + " # standard distribution\n", + " standard_dist = [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]\n", "\n", - "#\n", - "# declare variables\n", - "#\n", + " #\n", + " # declare variables\n", + " #\n", "\n", - "# the two dice\n", - "x1 = [solver.IntVar(0, m, \"x1(%i)\" % i) for i in range(n)]\n", - "x2 = [solver.IntVar(0, m, \"x2(%i)\" % i) for i in range(n)]\n", + " # the two dice\n", + " x1 = [solver.IntVar(0, m, \"x1(%i)\" % i) for i in range(n)]\n", + " x2 = [solver.IntVar(0, m, \"x2(%i)\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "# [solver.Add(standard_dist[k] == solver.Sum([x1[i] + x2[j] == k+2 for i in range(n) for j in range(n)]))\n", - "# for k in range(len(standard_dist))]\n", - "for k in range(len(standard_dist)):\n", - " tmp = [solver.BoolVar() for i in range(n) for j in range(n)]\n", - " for i in range(n):\n", - " for j in range(n):\n", - " solver.Add(tmp[i * n + j] == solver.IsEqualCstVar(x1[i] + x2[j], k + 2))\n", - " solver.Add(standard_dist[k] == solver.Sum(tmp))\n", + " #\n", + " # constraints\n", + " #\n", + " # [solver.Add(standard_dist[k] == solver.Sum([x1[i] + x2[j] == k+2 for i in range(n) for j in range(n)]))\n", + " # for k in range(len(standard_dist))]\n", + " for k in range(len(standard_dist)):\n", + " tmp = [solver.BoolVar() for i in range(n) for j in range(n)]\n", + " for i in range(n):\n", + " for j in range(n):\n", + " solver.Add(tmp[i * n + j] == solver.IsEqualCstVar(x1[i] + x2[j], k + 2))\n", + " solver.Add(standard_dist[k] == solver.Sum(tmp))\n", "\n", - "# symmetry breaking\n", - "[solver.Add(x1[i] <= x1[i + 1]) for i in range(n - 1)],\n", - "[solver.Add(x2[i] <= x2[i + 1]) for i in range(n - 1)],\n", - "[solver.Add(x1[i] <= x2[i]) for i in range(n - 1)],\n", + " # symmetry breaking\n", + " [solver.Add(x1[i] <= x1[i + 1]) for i in range(n - 1)],\n", + " [solver.Add(x2[i] <= x2[i + 1]) for i in range(n - 1)],\n", + " [solver.Add(x1[i] <= x2[i]) for i in range(n - 1)],\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x1)\n", - "solution.Add(x2)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x1)\n", + " solution.Add(x2)\n", "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(x1 + x2, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(x1 + x2, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"x1:\", [x1[i].Value() for i in range(n)])\n", + " print(\"x2:\", [x2[i].Value() for i in range(n)])\n", + " print()\n", + "\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"x1:\", [x1[i].Value() for i in range(n)])\n", - " print(\"x2:\", [x2[i].Value() for i in range(n)])\n", " print()\n", + " print(\"num_solutions:\", num_solutions, \"solver.solutions:\",\n", + " solver.Solutions())\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print(\"MemoryUsage:\", solver.MemoryUsage())\n", + " print(\"SearchDepth:\", solver.SearchDepth())\n", + " print(\"SolveDepth:\", solver.SolveDepth())\n", + " print(\"stamp:\", solver.Stamp())\n", + " print(\"solver\", solver)\n", "\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions, \"solver.solutions:\",\n", - " solver.Solutions())\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print(\"MemoryUsage:\", solver.MemoryUsage())\n", - "print(\"SearchDepth:\", solver.SearchDepth())\n", - "print(\"SolveDepth:\", solver.SolveDepth())\n", - "print(\"stamp:\", solver.Stamp())\n", - "print(\"solver\", solver)\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/ski_assignment.ipynb b/examples/notebook/contrib/ski_assignment.ipynb index c55a654e6d..e7b1c1bc11 100644 --- a/examples/notebook/contrib/ski_assignment.ipynb +++ b/examples/notebook/contrib/ski_assignment.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Ski assignment in Google CP Solver.\n", "\n", @@ -121,73 +106,85 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Ski assignment')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Ski assignment')\n", "\n", - "#\n", - "# data\n", - "#\n", - "num_skis = 6\n", - "num_skiers = 5\n", - "ski_heights = [1, 2, 5, 7, 13, 21]\n", - "skier_heights = [3, 4, 7, 11, 18]\n", + " #\n", + " # data\n", + " #\n", + " num_skis = 6\n", + " num_skiers = 5\n", + " ski_heights = [1, 2, 5, 7, 13, 21]\n", + " skier_heights = [3, 4, 7, 11, 18]\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "# which ski to choose for each skier\n", - "x = [solver.IntVar(0, num_skis - 1, 'x[%i]' % i) for i in range(num_skiers)]\n", - "z = solver.IntVar(0, sum(ski_heights), 'z')\n", + " # which ski to choose for each skier\n", + " x = [solver.IntVar(0, num_skis - 1, 'x[%i]' % i) for i in range(num_skiers)]\n", + " z = solver.IntVar(0, sum(ski_heights), 'z')\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(solver.AllDifferent(x))\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(solver.AllDifferent(x))\n", "\n", - "z_tmp = [\n", - " abs(solver.Element(ski_heights, x[i]) - skier_heights[i])\n", - " for i in range(num_skiers)\n", - "]\n", - "solver.Add(z == sum(z_tmp))\n", + " z_tmp = [\n", + " abs(solver.Element(ski_heights, x[i]) - skier_heights[i])\n", + " for i in range(num_skiers)\n", + " ]\n", + " solver.Add(z == sum(z_tmp))\n", "\n", - "# objective\n", - "objective = solver.Minimize(z, 1)\n", + " # objective\n", + " objective = solver.Minimize(z, 1)\n", "\n", - "#\n", - "# search and result\n", - "#\n", - "db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + " #\n", + " # search and result\n", + " #\n", + " db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", "\n", - "solver.NewSearch(db, [objective])\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + " print('total differences:', z.Value())\n", + " for i in range(num_skiers):\n", + " x_val = x[i].Value()\n", + " ski_height = ski_heights[x[i].Value()]\n", + " diff = ski_height - skier_heights[i]\n", + " print('Skier %i: Ski %i with length %2i (diff: %2i)' %\\\n", + " (i, x_val, ski_height, diff))\n", + " print()\n", + "\n", + " solver.EndSearch()\n", "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", - " print('total differences:', z.Value())\n", - " for i in range(num_skiers):\n", - " x_val = x[i].Value()\n", - " ski_height = ski_heights[x[i].Value()]\n", - " diff = ski_height - skier_heights[i]\n", - " print('Skier %i: Ski %i with length %2i (diff: %2i)' %\\\n", - " (i, x_val, ski_height, diff))\n", " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/slitherlink.ipynb b/examples/notebook/contrib/slitherlink.ipynb index 0c3bb2a882..6ce05565e6 100644 --- a/examples/notebook/contrib/slitherlink.ipynb +++ b/examples/notebook/contrib/slitherlink.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -357,6 +357,10 @@ " PrintSolution(data, h_arcs, v_arcs)\n", " solver.EndSearch()\n", "\n", + "\n", + "SlitherLink(small)\n", + "SlitherLink(medium)\n", + "SlitherLink(big)\n", "\n" ] } diff --git a/examples/notebook/contrib/sports_schedule_sat.ipynb b/examples/notebook/contrib/sports_schedule_sat.ipynb index 6fa359232d..cfe365535f 100644 --- a/examples/notebook/contrib/sports_schedule_sat.ipynb +++ b/examples/notebook/contrib/sports_schedule_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,28 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Based on sports_scheduling_sat.cc, Copyright 2010-2021 Google LLC\n", - "#\n", - "# Translated to Python by James E. Marca August 2019\n", - "#\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", - "\"\"\"Sports scheduling problem.\n", + "Sports scheduling problem.\n", "\n", "We want to solve the problem of scheduling of team matches in a\n", "double round robin tournament. Given a number of teams, we want\n", @@ -123,8 +106,16 @@ "\n", "For a version with pool constraints, plus tests, etc, see\n", "https://github.com/jmarca/sports_scheduling\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import argparse\n", "import os\n", "import re\n", @@ -538,105 +529,109 @@ " # print(' %s is %i' % (b.Name(), solver.Value(b)))\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "parser = argparse.ArgumentParser(\n", - " description='Solve sports league match play assignment problem')\n", - "parser.add_argument('-t,--teams',\n", - " type=int,\n", - " dest='num_teams',\n", - " default=10,\n", - " help='Number of teams in the league')\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " parser = argparse.ArgumentParser(\n", + " description='Solve sports league match play assignment problem')\n", + " parser.add_argument('-t,--teams',\n", + " type=int,\n", + " dest='num_teams',\n", + " default=10,\n", + " help='Number of teams in the league')\n", "\n", - "parser.add_argument(\n", - " '-d,--days',\n", - " type=int,\n", - " dest='num_matchdays',\n", - " default=2 * 10 - 2,\n", - " help=\n", - " 'Number of days on which matches are played. Default is enough days such that every team can play every other team, or (number of teams - 1)'\n", - ")\n", + " parser.add_argument(\n", + " '-d,--days',\n", + " type=int,\n", + " dest='num_matchdays',\n", + " default=2 * 10 - 2,\n", + " help=\n", + " 'Number of days on which matches are played. Default is enough days such that every team can play every other team, or (number of teams - 1)'\n", + " )\n", "\n", - "parser.add_argument(\n", - " '--matches_per_day',\n", - " type=int,\n", - " dest='num_matches_per_day',\n", - " default=10 - 1,\n", - " help=\n", - " 'Number of matches played per day. Default is number of teams divided by 2. If greater than the number of teams, then this implies some teams will play each other more than once. In that case, home and away should alternate between the teams in repeated matchups.'\n", - ")\n", + " parser.add_argument(\n", + " '--matches_per_day',\n", + " type=int,\n", + " dest='num_matches_per_day',\n", + " default=10 - 1,\n", + " help=\n", + " 'Number of matches played per day. Default is number of teams divided by 2. If greater than the number of teams, then this implies some teams will play each other more than once. In that case, home and away should alternate between the teams in repeated matchups.'\n", + " )\n", "\n", - "parser.add_argument(\n", - " '--csv',\n", - " type=str,\n", - " dest='csv',\n", - " default='output.csv',\n", - " help='A file to dump the team assignments. Default is output.csv')\n", + " parser.add_argument(\n", + " '--csv',\n", + " type=str,\n", + " dest='csv',\n", + " default='output.csv',\n", + " help='A file to dump the team assignments. Default is output.csv')\n", "\n", - "parser.add_argument(\n", - " '--timelimit',\n", - " type=int,\n", - " dest='time_limit',\n", - " default=60,\n", - " help='Maximum run time for solver, in seconds. Default is 60 seconds.')\n", + " parser.add_argument(\n", + " '--timelimit',\n", + " type=int,\n", + " dest='time_limit',\n", + " default=60,\n", + " help='Maximum run time for solver, in seconds. Default is 60 seconds.')\n", "\n", - "parser.add_argument(\n", - " '--cpu',\n", - " type=int,\n", - " dest='cpu',\n", - " help=\n", - " 'Number of workers (CPUs) to use for solver. Default is 6 or number of CPUs available, whichever is lower'\n", - ")\n", + " parser.add_argument(\n", + " '--cpu',\n", + " type=int,\n", + " dest='cpu',\n", + " help=\n", + " 'Number of workers (CPUs) to use for solver. Default is 6 or number of CPUs available, whichever is lower'\n", + " )\n", "\n", - "parser.add_argument('--debug',\n", - " action='store_true',\n", - " help=\"Turn on some print statements.\")\n", + " parser.add_argument('--debug',\n", + " action='store_true',\n", + " help=\"Turn on some print statements.\")\n", "\n", - "parser.add_argument(\n", - " '--max_home_stand',\n", - " type=int,\n", - " dest='max_home_stand',\n", - " default=2,\n", - " help=\n", - " \"Maximum consecutive home or away games. Default to 2, which means three home or away games in a row is forbidden.\"\n", - ")\n", + " parser.add_argument(\n", + " '--max_home_stand',\n", + " type=int,\n", + " dest='max_home_stand',\n", + " default=2,\n", + " help=\n", + " \"Maximum consecutive home or away games. Default to 2, which means three home or away games in a row is forbidden.\"\n", + " )\n", "\n", - "args = parser.parse_args()\n", + " args = parser.parse_args()\n", "\n", - "# set default for num_matchdays\n", - "num_matches_per_day = args.num_matches_per_day\n", - "if not num_matches_per_day:\n", - " num_matches_per_day = args.num_teams // 2\n", - "ncpu = 8\n", - "try:\n", - " ncpu = len(os.sched_getaffinity(0))\n", - "except AttributeError:\n", - " pass\n", - "cpu = args.cpu\n", - "if not cpu:\n", - " cpu = min(6, ncpu)\n", - " print('Setting number of search workers to %i' % cpu)\n", + " # set default for num_matchdays\n", + " num_matches_per_day = args.num_matches_per_day\n", + " if not num_matches_per_day:\n", + " num_matches_per_day = args.num_teams // 2\n", + " ncpu = 8\n", + " try:\n", + " ncpu = len(os.sched_getaffinity(0))\n", + " except AttributeError:\n", + " pass\n", + " cpu = args.cpu\n", + " if not cpu:\n", + " cpu = min(6, ncpu)\n", + " print('Setting number of search workers to %i' % cpu)\n", "\n", - "if cpu > ncpu:\n", - " print(\n", - " 'You asked for %i workers to be used, but the os only reports %i CPUs available. This might slow down processing'\n", - " % (cpu, ncpu))\n", - "\n", - "if cpu != 6:\n", - " # don't whinge at user if cpu is set to 6\n", - " if cpu < ncpu:\n", + " if cpu > ncpu:\n", " print(\n", - " 'Using %i workers, but there are %i CPUs available. You might get faster results by using the command line option --cpu %i, but be aware ORTools CP-SAT solver is tuned to 6 CPUs'\n", - " % (cpu, ncpu, ncpu))\n", + " 'You asked for %i workers to be used, but the os only reports %i CPUs available. This might slow down processing'\n", + " % (cpu, ncpu))\n", "\n", - " if cpu > 6:\n", - " print(\n", - " 'Using %i workers. Be aware ORTools CP-SAT solver is tuned to 6 CPUs'\n", - " % cpu)\n", + " if cpu != 6:\n", + " # don't whinge at user if cpu is set to 6\n", + " if cpu < ncpu:\n", + " print(\n", + " 'Using %i workers, but there are %i CPUs available. You might get faster results by using the command line option --cpu %i, but be aware ORTools CP-SAT solver is tuned to 6 CPUs'\n", + " % (cpu, ncpu, ncpu))\n", "\n", - "# assign_matches()\n", - "assign_matches(args.num_teams, args.num_matchdays, num_matches_per_day,\n", - " args.max_home_stand, args.time_limit, cpu, args.csv,\n", - " args.debug)\n", + " if cpu > 6:\n", + " print(\n", + " 'Using %i workers. Be aware ORTools CP-SAT solver is tuned to 6 CPUs'\n", + " % cpu)\n", + "\n", + " # assign_matches()\n", + " assign_matches(args.num_teams, args.num_matchdays, num_matches_per_day,\n", + " args.max_home_stand, args.time_limit, cpu, args.csv,\n", + " args.debug)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/stable_marriage.ipynb b/examples/notebook/contrib/stable_marriage.ipynb index aea0682848..712711b848 100644 --- a/examples/notebook/contrib/stable_marriage.ipynb +++ b/examples/notebook/contrib/stable_marriage.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Stable marriage problem in Google CP Solver.\n", "\n", @@ -111,104 +96,114 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(ranks, problem_name):\n", "\n", - "# Create the solver\n", - "solver = pywrapcp.Solver(\"Stable marriage\")\n", + " # Create the solver\n", + " solver = pywrapcp.Solver(\"Stable marriage\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"Problem name:\", problem_name)\n", + " #\n", + " # data\n", + " #\n", + " print(\"Problem name:\", problem_name)\n", "\n", - "rankMen = ranks[\"rankMen\"]\n", - "rankWomen = ranks[\"rankWomen\"]\n", + " rankMen = ranks[\"rankMen\"]\n", + " rankWomen = ranks[\"rankWomen\"]\n", "\n", - "n = len(rankMen)\n", + " n = len(rankMen)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "wife = [solver.IntVar(0, n - 1, \"wife[%i]\" % i) for i in range(n)]\n", - "husband = [solver.IntVar(0, n - 1, \"husband[%i]\" % i) for i in range(n)]\n", + " #\n", + " # declare variables\n", + " #\n", + " wife = [solver.IntVar(0, n - 1, \"wife[%i]\" % i) for i in range(n)]\n", + " husband = [solver.IntVar(0, n - 1, \"husband[%i]\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# forall(m in Men)\n", - "# cp.post(husband[wife[m]] == m);\n", - "for m in range(n):\n", - " solver.Add(solver.Element(husband, wife[m]) == m)\n", + " # forall(m in Men)\n", + " # cp.post(husband[wife[m]] == m);\n", + " for m in range(n):\n", + " solver.Add(solver.Element(husband, wife[m]) == m)\n", "\n", - "# forall(w in Women)\n", - "# cp.post(wife[husband[w]] == w);\n", - "for w in range(n):\n", - " solver.Add(solver.Element(wife, husband[w]) == w)\n", + " # forall(w in Women)\n", + " # cp.post(wife[husband[w]] == w);\n", + " for w in range(n):\n", + " solver.Add(solver.Element(wife, husband[w]) == w)\n", "\n", - "# forall(m in Men, o in Women)\n", - "# cp.post(rankMen[m,o] < rankMen[m, wife[m]] => rankWomen[o,husband[o]] <\n", - "# rankWomen[o,m]);\n", - "for m in range(n):\n", - " for o in range(n):\n", - " b1 = solver.IsGreaterCstVar(\n", - " solver.Element(rankMen[m], wife[m]), rankMen[m][o])\n", - " b2 = (\n", - " solver.IsLessCstVar(\n", - " solver.Element(rankWomen[o], husband[o]), rankWomen[o][m]))\n", - " solver.Add(b1 - b2 <= 0)\n", + " # forall(m in Men, o in Women)\n", + " # cp.post(rankMen[m,o] < rankMen[m, wife[m]] => rankWomen[o,husband[o]] <\n", + " # rankWomen[o,m]);\n", + " for m in range(n):\n", + " for o in range(n):\n", + " b1 = solver.IsGreaterCstVar(\n", + " solver.Element(rankMen[m], wife[m]), rankMen[m][o])\n", + " b2 = (\n", + " solver.IsLessCstVar(\n", + " solver.Element(rankWomen[o], husband[o]), rankWomen[o][m]))\n", + " solver.Add(b1 - b2 <= 0)\n", "\n", - "# forall(w in Women, o in Men)\n", - "# cp.post(rankWomen[w,o] < rankWomen[w,husband[w]] => rankMen[o,wife[o]] <\n", - "# rankMen[o,w]);\n", - "for w in range(n):\n", - " for o in range(n):\n", - " b1 = solver.IsGreaterCstVar(\n", - " solver.Element(rankWomen[w], husband[w]), rankWomen[w][o])\n", - " b2 = solver.IsLessCstVar(\n", - " solver.Element(rankMen[o], wife[o]), rankMen[o][w])\n", - " solver.Add(b1 - b2 <= 0)\n", + " # forall(w in Women, o in Men)\n", + " # cp.post(rankWomen[w,o] < rankWomen[w,husband[w]] => rankMen[o,wife[o]] <\n", + " # rankMen[o,w]);\n", + " for w in range(n):\n", + " for o in range(n):\n", + " b1 = solver.IsGreaterCstVar(\n", + " solver.Element(rankWomen[w], husband[w]), rankWomen[w][o])\n", + " b2 = solver.IsLessCstVar(\n", + " solver.Element(rankMen[o], wife[o]), rankMen[o][w])\n", + " solver.Add(b1 - b2 <= 0)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(wife)\n", - "solution.Add(husband)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(wife)\n", + " solution.Add(husband)\n", "\n", - "db = solver.Phase(wife + husband, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " db = solver.Phase(wife + husband, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " solutions = []\n", + " while solver.NextSolution():\n", + " # solutions.append([x[i].Value() for i in range(x_len)])\n", + " print(\"wife : \", [wife[i].Value() for i in range(n)])\n", + " print(\"husband: \", [husband[i].Value() for i in range(n)])\n", + " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "solutions = []\n", - "while solver.NextSolution():\n", - " # solutions.append([x[i].Value() for i in range(x_len)])\n", - " print(\"wife : \", [wife[i].Value() for i in range(n)])\n", - " print(\"husband: \", [husband[i].Value() for i in range(n)])\n", " print()\n", - " num_solutions += 1\n", - "\n", - "solver.EndSearch()\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print(\"#############\")\n", - "print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + " print(\"#############\")\n", + " print()\n", "\n", "\n", "#\n", "# From Van Hentenryck's OPL book\n", - "#van_hentenryck = {\n", + "#\n", + "van_hentenryck = {\n", " \"rankWomen\": [[1, 2, 4, 3, 5], [3, 5, 1, 2, 4], [5, 4, 2, 1, 3],\n", " [1, 3, 5, 4, 2], [4, 2, 3, 5, 1]],\n", " \"rankMen\": [[5, 1, 2, 4, 3], [4, 1, 3, 2, 5], [5, 3, 2, 4, 1],\n", @@ -252,6 +247,11 @@ " \"rankMen\": [[1, 4, 2, 5, 6, 3], [3, 4, 6, 1, 5, 2], [1, 6, 4, 2, 3, 5],\n", " [6, 5, 3, 4, 2, 1], [3, 1, 2, 4, 5, 6], [2, 3, 1, 6, 5, 4]]\n", "}\n", + "\n", + "main(van_hentenryck, \"Van Hentenryck\")\n", + "main(mathworld, \"MathWorld\")\n", + "main(problem3, \"Problem 3\")\n", + "main(problem4, \"Problem4\")\n", "\n" ] } diff --git a/examples/notebook/contrib/stable_marriage_sat.ipynb b/examples/notebook/contrib/stable_marriage_sat.ipynb index 88bfaa1f8a..cd3648401f 100644 --- a/examples/notebook/contrib/stable_marriage_sat.ipynb +++ b/examples/notebook/contrib/stable_marriage_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves the stable marriage problem in CP-SAT.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,20 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2018 Gergo Rozner\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", - "\"\"\"Solves the stable marriage problem in CP-SAT.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", @@ -111,66 +105,85 @@ " return self.__solution_count\n", "\n", "\n", - "mrank = ranks[\"rankMen\"]\n", - "wrank = ranks[\"rankWomen\"]\n", + "def main(ranks, pair_num):\n", + " mrank = ranks[\"rankMen\"]\n", + " wrank = ranks[\"rankWomen\"]\n", "\n", - "n = pair_num\n", + " n = pair_num\n", "\n", - "model = cp_model.CpModel()\n", + " model = cp_model.CpModel()\n", "\n", - "wife = [model.NewIntVar(0, n - 1, \"wife[%i]\" % i) for i in range(n)]\n", - "husband = [model.NewIntVar(0, n - 1, \"husband[%i]\" % i) for i in range(n)]\n", + " wife = [model.NewIntVar(0, n - 1, \"wife[%i]\" % i) for i in range(n)]\n", + " husband = [model.NewIntVar(0, n - 1, \"husband[%i]\" % i) for i in range(n)]\n", "\n", - "for m in range(n):\n", - " model.AddElement(wife[m], husband, m)\n", - "\n", - "for w in range(n):\n", - " model.AddElement(husband[w], wife, w)\n", - "\n", - "#mrank[w][m] < mrank[w][husband[w]] => wrank[m][wife[m]] < wrank[m][w]\n", - "for w in range(n):\n", " for m in range(n):\n", - " husband_rank = model.NewIntVar(1, n, \"\")\n", - " model.AddElement(husband[w], mrank[w], husband_rank)\n", + " model.AddElement(wife[m], husband, m)\n", "\n", - " wife_rank = model.NewIntVar(1, n, \"\")\n", - " model.AddElement(wife[m], wrank[m], wife_rank)\n", - "\n", - " husband_dominated = model.NewBoolVar(\"\")\n", - " model.Add(mrank[w][m] < husband_rank).OnlyEnforceIf(husband_dominated)\n", - " model.Add(mrank[w][m] >= husband_rank).OnlyEnforceIf(\n", - " husband_dominated.Not())\n", - "\n", - " wife_dominates = model.NewBoolVar(\"\")\n", - " model.Add(wife_rank < wrank[m][w]).OnlyEnforceIf(wife_dominates)\n", - " model.Add(wife_rank >= wrank[m][w]).OnlyEnforceIf(wife_dominates.Not())\n", - "\n", - " model.AddImplication(husband_dominated, wife_dominates)\n", - "\n", - "#wrank[m][w] < wrank[m][wife[m]] => mrank[w][husband[w]] < mrank[w][m]\n", - "for m in range(n):\n", " for w in range(n):\n", - " wife_rank = model.NewIntVar(1, n, \"\")\n", - " model.AddElement(wife[m], wrank[m], wife_rank)\n", + " model.AddElement(husband[w], wife, w)\n", "\n", - " husband_rank = model.NewIntVar(1, n, \"\")\n", - " model.AddElement(husband[w], mrank[w], husband_rank)\n", + " #mrank[w][m] < mrank[w][husband[w]] => wrank[m][wife[m]] < wrank[m][w]\n", + " for w in range(n):\n", + " for m in range(n):\n", + " husband_rank = model.NewIntVar(1, n, \"\")\n", + " model.AddElement(husband[w], mrank[w], husband_rank)\n", "\n", - " wife_dominated = model.NewBoolVar(\"\")\n", - " model.Add(wrank[m][w] < wife_rank).OnlyEnforceIf(wife_dominated)\n", - " model.Add(wrank[m][w] >= wife_rank).OnlyEnforceIf(wife_dominated.Not())\n", + " wife_rank = model.NewIntVar(1, n, \"\")\n", + " model.AddElement(wife[m], wrank[m], wife_rank)\n", "\n", - " husband_dominates = model.NewBoolVar(\"\")\n", - " model.Add(husband_rank < mrank[w][m]).OnlyEnforceIf(husband_dominates)\n", - " model.Add(husband_rank >= mrank[w][m]).OnlyEnforceIf(\n", - " husband_dominates.Not())\n", + " husband_dominated = model.NewBoolVar(\"\")\n", + " model.Add(mrank[w][m] < husband_rank).OnlyEnforceIf(husband_dominated)\n", + " model.Add(mrank[w][m] >= husband_rank).OnlyEnforceIf(\n", + " husband_dominated.Not())\n", "\n", - " model.AddImplication(wife_dominated, husband_dominates)\n", + " wife_dominates = model.NewBoolVar(\"\")\n", + " model.Add(wife_rank < wrank[m][w]).OnlyEnforceIf(wife_dominates)\n", + " model.Add(wife_rank >= wrank[m][w]).OnlyEnforceIf(wife_dominates.Not())\n", "\n", - "solver = cp_model.CpSolver()\n", - "solution_printer = SolutionPrinter(wife, husband)\n", - "solver.parameters.enumerate_all_solutions = True\n", - "solver.Solve(model, solution_printer)\n", + " model.AddImplication(husband_dominated, wife_dominates)\n", + "\n", + " #wrank[m][w] < wrank[m][wife[m]] => mrank[w][husband[w]] < mrank[w][m]\n", + " for m in range(n):\n", + " for w in range(n):\n", + " wife_rank = model.NewIntVar(1, n, \"\")\n", + " model.AddElement(wife[m], wrank[m], wife_rank)\n", + "\n", + " husband_rank = model.NewIntVar(1, n, \"\")\n", + " model.AddElement(husband[w], mrank[w], husband_rank)\n", + "\n", + " wife_dominated = model.NewBoolVar(\"\")\n", + " model.Add(wrank[m][w] < wife_rank).OnlyEnforceIf(wife_dominated)\n", + " model.Add(wrank[m][w] >= wife_rank).OnlyEnforceIf(wife_dominated.Not())\n", + "\n", + " husband_dominates = model.NewBoolVar(\"\")\n", + " model.Add(husband_rank < mrank[w][m]).OnlyEnforceIf(husband_dominates)\n", + " model.Add(husband_rank >= mrank[w][m]).OnlyEnforceIf(\n", + " husband_dominates.Not())\n", + "\n", + " model.AddImplication(wife_dominated, husband_dominates)\n", + "\n", + " solver = cp_model.CpSolver()\n", + " solution_printer = SolutionPrinter(wife, husband)\n", + " solver.parameters.enumerate_all_solutions = True\n", + " solver.Solve(model, solution_printer)\n", + "\n", + "\n", + "rankings1 = {\n", + " \"rankMen\": [[1, 2, 3, 4], [4, 3, 2, 1], [1, 2, 3, 4], [3, 4, 1, 2]],\n", + " \"rankWomen\": [[1, 2, 3, 4], [2, 1, 3, 4], [1, 4, 3, 2], [4, 3, 1, 2]]\n", + "}\n", + "\n", + "rankings2 = {\n", + " \"rankMen\": [[1, 5, 4, 6, 2, 3], [4, 1, 5, 2, 6, 3], [6, 4, 2, 1, 5, 3],\n", + " [1, 5, 2, 4, 3, 6], [4, 2, 1, 5, 6, 3], [2, 6, 3, 5, 1, 4]],\n", + " \"rankWomen\": [[1, 4, 2, 5, 6, 3], [3, 4, 6, 1, 5, 2], [1, 6, 4, 2, 3, 5],\n", + " [6, 5, 3, 4, 2, 1], [3, 1, 2, 4, 5, 6], [2, 3, 1, 6, 5, 4]]\n", + "}\n", + "\n", + "problem = rankings2\n", + "couple_count = len(problem[\"rankMen\"])\n", + "\n", + "main(problem, couple_count)\n", "\n" ] } diff --git a/examples/notebook/contrib/steel.ipynb b/examples/notebook/contrib/steel.ipynb index afcaddbe7a..85f57e3e34 100644 --- a/examples/notebook/contrib/steel.ipynb +++ b/examples/notebook/contrib/steel.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -217,46 +217,50 @@ " return 'SteelMillDecisionBuilder(' + str(self.__x) + ')'\n", "\n", "\n", - "#------------------solver and variable declaration-------------\n", - "(nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) =\\\n", - " ReadData(args.data)\n", - "nb_colors = len(color_orders)\n", - "solver = pywrapcp.Solver('Steel Mill Slab')\n", - "x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) for i in range(nb_slabs)]\n", - "load_vars = [\n", - " solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i))\n", - " for i in range(nb_slabs)\n", - "]\n", + "def main(args):\n", + " #------------------solver and variable declaration-------------\n", + " (nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) =\\\n", + " ReadData(args.data)\n", + " nb_colors = len(color_orders)\n", + " solver = pywrapcp.Solver('Steel Mill Slab')\n", + " x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) for i in range(nb_slabs)]\n", + " load_vars = [\n", + " solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i))\n", + " for i in range(nb_slabs)\n", + " ]\n", "\n", - "#-------------------post of the constraints--------------\n", + " #-------------------post of the constraints--------------\n", "\n", - "# Bin Packing.\n", - "BinPacking(solver, x, weights, load_vars)\n", - "# At most two colors per slab.\n", - "for s in range(nb_slabs):\n", - " solver.Add(\n", - " solver.SumLessOrEqual([\n", - " solver.Max([solver.IsEqualCstVar(x[c], s)\n", - " for c in o])\n", - " for o in color_orders\n", - " ], 2))\n", + " # Bin Packing.\n", + " BinPacking(solver, x, weights, load_vars)\n", + " # At most two colors per slab.\n", + " for s in range(nb_slabs):\n", + " solver.Add(\n", + " solver.SumLessOrEqual([\n", + " solver.Max([solver.IsEqualCstVar(x[c], s)\n", + " for c in o])\n", + " for o in color_orders\n", + " ], 2))\n", "\n", - "#----------------Objective-------------------------------\n", + " #----------------Objective-------------------------------\n", "\n", - "objective_var = \\\n", - " solver.Sum([load_vars[s].IndexOf(loss) for s in range(nb_slabs)]).Var()\n", - "objective = solver.Minimize(objective_var, 1)\n", + " objective_var = \\\n", + " solver.Sum([load_vars[s].IndexOf(loss) for s in range(nb_slabs)]).Var()\n", + " objective = solver.Minimize(objective_var, 1)\n", "\n", - "#------------start the search and optimization-----------\n", + " #------------start the search and optimization-----------\n", "\n", - "db = SteelDecisionBuilder(x, nb_slabs, weights, loss, load_vars)\n", - "search_log = solver.SearchLog(100000, objective_var)\n", - "global_limit = solver.TimeLimit(args.time_limit)\n", - "solver.NewSearch(db, [objective, search_log, global_limit])\n", - "while solver.NextSolution():\n", - " print('Objective:', objective_var.Value(),\\\n", - " 'check:', sum(loss[load_vars[s].Min()] for s in range(nb_slabs)))\n", - "solver.EndSearch()\n", + " db = SteelDecisionBuilder(x, nb_slabs, weights, loss, load_vars)\n", + " search_log = solver.SearchLog(100000, objective_var)\n", + " global_limit = solver.TimeLimit(args.time_limit)\n", + " solver.NewSearch(db, [objective, search_log, global_limit])\n", + " while solver.NextSolution():\n", + " print('Objective:', objective_var.Value(),\\\n", + " 'check:', sum(loss[load_vars[s].Min()] for s in range(nb_slabs)))\n", + " solver.EndSearch()\n", + "\n", + "\n", + "main(parser.parse_args())\n", "\n" ] } diff --git a/examples/notebook/contrib/steel_lns.ipynb b/examples/notebook/contrib/steel_lns.ipynb index 3a36a89186..601f5feeb4 100644 --- a/examples/notebook/contrib/steel_lns.ipynb +++ b/examples/notebook/contrib/steel_lns.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -258,77 +258,81 @@ "# ----------- Main Function -----------\n", "\n", "\n", - "# ----- solver and variable declaration -----\n", - "(nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) =\\\n", - " ReadData(args.data)\n", - "nb_colors = len(color_orders)\n", - "solver = pywrapcp.Solver('Steel Mill Slab')\n", - "x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) for i in range(nb_slabs)]\n", - "load_vars = [\n", - " solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i))\n", - " for i in range(nb_slabs)\n", - "]\n", + "def main(args):\n", + " # ----- solver and variable declaration -----\n", + " (nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) =\\\n", + " ReadData(args.data)\n", + " nb_colors = len(color_orders)\n", + " solver = pywrapcp.Solver('Steel Mill Slab')\n", + " x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) for i in range(nb_slabs)]\n", + " load_vars = [\n", + " solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i))\n", + " for i in range(nb_slabs)\n", + " ]\n", "\n", - "# ----- post of the constraints -----\n", + " # ----- post of the constraints -----\n", "\n", - "# Bin Packing.\n", - "BinPacking(solver, x, weights, load_vars)\n", - "# At most two colors per slab.\n", - "for s in range(nb_slabs):\n", - " solver.Add(\n", - " solver.SumLessOrEqual([\n", - " solver.Max([solver.IsEqualCstVar(x[c], s)\n", - " for c in o])\n", - " for o in color_orders\n", - " ], 2))\n", + " # Bin Packing.\n", + " BinPacking(solver, x, weights, load_vars)\n", + " # At most two colors per slab.\n", + " for s in range(nb_slabs):\n", + " solver.Add(\n", + " solver.SumLessOrEqual([\n", + " solver.Max([solver.IsEqualCstVar(x[c], s)\n", + " for c in o])\n", + " for o in color_orders\n", + " ], 2))\n", "\n", - "# ----- Objective -----\n", + " # ----- Objective -----\n", "\n", - "objective_var = \\\n", - " solver.Sum([load_vars[s].IndexOf(loss) for s in range(nb_slabs)]).Var()\n", - "objective = solver.Minimize(objective_var, 1)\n", + " objective_var = \\\n", + " solver.Sum([load_vars[s].IndexOf(loss) for s in range(nb_slabs)]).Var()\n", + " objective = solver.Minimize(objective_var, 1)\n", "\n", - "# ----- start the search and optimization -----\n", + " # ----- start the search and optimization -----\n", "\n", - "assign_db = SteelDecisionBuilder(x, nb_slabs, weights, loss, load_vars)\n", - "first_solution = solver.Assignment()\n", - "first_solution.Add(x)\n", - "first_solution.AddObjective(objective_var)\n", - "store_db = solver.StoreAssignment(first_solution)\n", - "first_solution_db = solver.Compose([assign_db, store_db])\n", - "print('searching for initial solution,', end=' ')\n", - "solver.Solve(first_solution_db)\n", - "print('initial cost =', first_solution.ObjectiveValue())\n", + " assign_db = SteelDecisionBuilder(x, nb_slabs, weights, loss, load_vars)\n", + " first_solution = solver.Assignment()\n", + " first_solution.Add(x)\n", + " first_solution.AddObjective(objective_var)\n", + " store_db = solver.StoreAssignment(first_solution)\n", + " first_solution_db = solver.Compose([assign_db, store_db])\n", + " print('searching for initial solution,', end=' ')\n", + " solver.Solve(first_solution_db)\n", + " print('initial cost =', first_solution.ObjectiveValue())\n", "\n", - "# To search a fragment, we use a basic randomized decision builder.\n", - "# We can also use assign_db instead of inner_db.\n", - "inner_db = solver.Phase(x, solver.CHOOSE_RANDOM, solver.ASSIGN_MIN_VALUE)\n", - "# The most important aspect is to limit the time exploring each fragment.\n", - "inner_limit = solver.FailuresLimit(args.lns_fail_limit)\n", - "continuation_db = solver.SolveOnce(inner_db, [inner_limit])\n", + " # To search a fragment, we use a basic randomized decision builder.\n", + " # We can also use assign_db instead of inner_db.\n", + " inner_db = solver.Phase(x, solver.CHOOSE_RANDOM, solver.ASSIGN_MIN_VALUE)\n", + " # The most important aspect is to limit the time exploring each fragment.\n", + " inner_limit = solver.FailuresLimit(args.lns_fail_limit)\n", + " continuation_db = solver.SolveOnce(inner_db, [inner_limit])\n", "\n", - "# Now, we create the LNS objects.\n", - "rand = random.Random()\n", - "rand.seed(args.lns_random_seed)\n", - "local_search_operator = SteelRandomLns(x, rand, args.lns_fragment_size)\n", - "# This is in fact equivalent to the following predefined LNS operator:\n", - "# local_search_operator = solver.RandomLNSOperator(x,\n", - "# args.lns_fragment_size,\n", - "# args.lns_random_seed)\n", - "local_search_parameters = solver.LocalSearchPhaseParameters(\n", - " objective_var, local_search_operator, continuation_db)\n", - "local_search_db = solver.LocalSearchPhase(first_solution,\n", - " local_search_parameters)\n", - "global_limit = solver.TimeLimit(args.time_limit)\n", + " # Now, we create the LNS objects.\n", + " rand = random.Random()\n", + " rand.seed(args.lns_random_seed)\n", + " local_search_operator = SteelRandomLns(x, rand, args.lns_fragment_size)\n", + " # This is in fact equivalent to the following predefined LNS operator:\n", + " # local_search_operator = solver.RandomLNSOperator(x,\n", + " # args.lns_fragment_size,\n", + " # args.lns_random_seed)\n", + " local_search_parameters = solver.LocalSearchPhaseParameters(\n", + " objective_var, local_search_operator, continuation_db)\n", + " local_search_db = solver.LocalSearchPhase(first_solution,\n", + " local_search_parameters)\n", + " global_limit = solver.TimeLimit(args.time_limit)\n", "\n", - "print('using LNS to improve the initial solution')\n", + " print('using LNS to improve the initial solution')\n", "\n", - "search_log = solver.SearchLog(100000, objective_var)\n", - "solver.NewSearch(local_search_db, [objective, search_log, global_limit])\n", - "while solver.NextSolution():\n", - " print('Objective:', objective_var.Value(),\\\n", - " 'check:', sum(loss[load_vars[s].Min()] for s in range(nb_slabs)))\n", - "solver.EndSearch()\n", + " search_log = solver.SearchLog(100000, objective_var)\n", + " solver.NewSearch(local_search_db, [objective, search_log, global_limit])\n", + " while solver.NextSolution():\n", + " print('Objective:', objective_var.Value(),\\\n", + " 'check:', sum(loss[load_vars[s].Min()] for s in range(nb_slabs)))\n", + " solver.EndSearch()\n", + "\n", + "\n", + "main(parser.parse_args())\n", "\n" ] } diff --git a/examples/notebook/contrib/stigler_contrib.ipynb b/examples/notebook/contrib/stigler_contrib.ipynb index 07e7f23e9a..7cf68f7e9d 100644 --- a/examples/notebook/contrib/stigler_contrib.ipynb +++ b/examples/notebook/contrib/stigler_contrib.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Original Stigler's 1939 diet problem Google or-tools.\n", "\n", @@ -191,227 +176,247 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(sol=\"CBC\"):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "print(\"Solver: \", sol)\n", + " print(\"Solver: \", sol)\n", "\n", - "# using GLPK\n", - "if sol == \"GLPK\":\n", - " solver = pywraplp.Solver(\"CoinsGridGLPK\",\n", - " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", - "else:\n", - " # Using CLP\n", - " solver = pywraplp.Solver(\"CoinsGridCLP\",\n", - " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", + " # using GLPK\n", + " if sol == \"GLPK\":\n", + " solver = pywraplp.Solver(\"CoinsGridGLPK\",\n", + " pywraplp.Solver.GLPK_MIXED_INTEGER_PROGRAMMING)\n", + " else:\n", + " # Using CLP\n", + " solver = pywraplp.Solver(\"CoinsGridCLP\",\n", + " pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING)\n", "\n", - "#\n", - "# data\n", - "#\n", - "# commodities\n", - "num_commodities = 77\n", - "C = list(range(num_commodities))\n", + " #\n", + " # data\n", + " #\n", + " # commodities\n", + " num_commodities = 77\n", + " C = list(range(num_commodities))\n", "\n", - "# days in a year\n", - "days = 365.25\n", + " # days in a year\n", + " days = 365.25\n", "\n", - "# nutrients\n", - "num_nutrients = 9\n", - "N = list(range(num_nutrients))\n", + " # nutrients\n", + " num_nutrients = 9\n", + " N = list(range(num_nutrients))\n", "\n", - "nutrients = [\n", - " \"calories\", # Calories, unit = 1000\n", - " \"protein\", # Protein, unit = grams\n", - " \"calcium\", # Calcium, unit = grams\n", - " \"iron\", # Iron, unit = milligrams\n", - " \"vitaminA\", # Vitamin A, unit = 1000 International Units\n", - " \"thiamine\", # Thiamine, Vit. B1, unit = milligrams\n", - " \"riboflavin\", # Riboflavin, Vit. B2, unit = milligrams\n", - " \"niacin\", # Niacin (Nicotinic Acid), unit = milligrams\n", - " \"ascorbicAcid\" # Ascorbic Acid, Vit. C, unit = milligrams\n", - "]\n", + " nutrients = [\n", + " \"calories\", # Calories, unit = 1000\n", + " \"protein\", # Protein, unit = grams\n", + " \"calcium\", # Calcium, unit = grams\n", + " \"iron\", # Iron, unit = milligrams\n", + " \"vitaminA\", # Vitamin A, unit = 1000 International Units\n", + " \"thiamine\", # Thiamine, Vit. B1, unit = milligrams\n", + " \"riboflavin\", # Riboflavin, Vit. B2, unit = milligrams\n", + " \"niacin\", # Niacin (Nicotinic Acid), unit = milligrams\n", + " \"ascorbicAcid\" # Ascorbic Acid, Vit. C, unit = milligrams\n", + " ]\n", "\n", - "commodities = [[\"Wheat Flour (Enriched)\", \"10 lb.\"], [\"Macaroni\", \"1 lb.\"],\n", - " [\"Wheat Cereal (Enriched)\",\n", - " \"28 oz.\"], [\"Corn Flakes\", \"8 oz.\"], [\"Corn Meal\", \"1 lb.\"],\n", - " [\"Hominy Grits\", \"24 oz.\"], [\"Rice\", \"1 lb.\"],\n", - " [\"Rolled Oats\", \"1 lb.\"], [\"White Bread (Enriched)\", \"1 lb.\"],\n", - " [\"Whole Wheat Bread\", \"1 lb.\"], [\"Rye Bread\", \"1 lb.\"],\n", - " [\"Pound Cake\", \"1 lb.\"], [\"Soda Crackers\", \"1 lb.\"],\n", - " [\"Milk\", \"1 qt.\"], [\"Evaporated Milk (can)\", \"14.5 oz.\"],\n", - " [\"Butter\", \"1 lb.\"], [\"Oleomargarine\", \"1 lb.\"],\n", - " [\"Eggs\", \"1 doz.\"], [\"Cheese (Cheddar)\", \"1 lb.\"],\n", - " [\"Cream\", \"1/2 pt.\"], [\"Peanut Butter\", \"1 lb.\"],\n", - " [\"Mayonnaise\", \"1/2 pt.\"], [\"Crisco\", \"1 lb.\"],\n", - " [\"Lard\", \"1 lb.\"], [\"Sirloin Steak\", \"1 lb.\"],\n", - " [\"Round Steak\", \"1 lb.\"], [\"Rib Roast\", \"1 lb.\"],\n", - " [\"Chuck Roast\", \"1 lb.\"], [\"Plate\", \"1 lb.\"],\n", - " [\"Liver (Beef)\", \"1 lb.\"], [\"Leg of Lamb\", \"1 lb.\"],\n", - " [\"Lamb Chops (Rib)\", \"1 lb.\"], [\"Pork Chops\", \"1 lb.\"],\n", - " [\"Pork Loin Roast\", \"1 lb.\"], [\"Bacon\", \"1 lb.\"],\n", - " [\"Ham - smoked\", \"1 lb.\"], [\"Salt Pork\", \"1 lb.\"],\n", - " [\"Roasting Chicken\", \"1 lb.\"], [\"Veal Cutlets\", \"1 lb.\"],\n", - " [\"Salmon, Pink (can)\", \"16 oz.\"], [\"Apples\", \"1 lb.\"],\n", - " [\"Bananas\", \"1 lb.\"], [\"Lemons\", \"1 doz.\"],\n", - " [\"Oranges\", \"1 doz.\"], [\"Green Beans\", \"1 lb.\"],\n", - " [\"Cabbage\", \"1 lb.\"], [\"Carrots\", \"1 bunch\"],\n", - " [\"Celery\", \"1 stalk\"], [\"Lettuce\", \"1 head\"],\n", - " [\"Onions\", \"1 lb.\"], [\"Potatoes\", \"15 lb.\"],\n", - " [\"Spinach\", \"1 lb.\"], [\"Sweet Potatoes\", \"1 lb.\"],\n", - " [\"Peaches (can)\", \"No. 2 1/2\"], [\"Pears (can)\", \"No. 2 1/2,\"],\n", - " [\"Pineapple (can)\", \"No. 2 1/2\"], [\"Asparagus (can)\", \"No. 2\"],\n", - " [\"Grean Beans (can)\", \"No. 2\"],\n", - " [\"Pork and Beans (can)\", \"16 oz.\"], [\"Corn (can)\", \"No. 2\"],\n", - " [\"Peas (can)\", \"No. 2\"], [\"Tomatoes (can)\", \"No. 2\"],\n", - " [\"Tomato Soup (can)\", \"10 1/2 oz.\"],\n", - " [\"Peaches, Dried\", \"1 lb.\"], [\"Prunes, Dried\", \"1 lb.\"],\n", - " [\"Raisins, Dried\", \"15 oz.\"], [\"Peas, Dried\", \"1 lb.\"],\n", - " [\"Lima Beans, Dried\", \"1 lb.\"], [\"Navy Beans, Dried\", \"1 lb.\"],\n", - " [\"Coffee\", \"1 lb.\"], [\"Tea\", \"1/4 lb.\"], [\"Cocoa\", \"8 oz.\"],\n", - " [\"Chocolate\", \"8 oz.\"], [\"Sugar\", \"10 lb.\"],\n", - " [\"Corn Sirup\", \"24 oz.\"], [\"Molasses\", \"18 oz.\"],\n", - " [\"Strawberry Preserve\", \"1 lb.\"]]\n", + " commodities = [[\"Wheat Flour (Enriched)\", \"10 lb.\"], [\"Macaroni\", \"1 lb.\"],\n", + " [\"Wheat Cereal (Enriched)\",\n", + " \"28 oz.\"], [\"Corn Flakes\", \"8 oz.\"], [\"Corn Meal\", \"1 lb.\"],\n", + " [\"Hominy Grits\", \"24 oz.\"], [\"Rice\", \"1 lb.\"],\n", + " [\"Rolled Oats\", \"1 lb.\"], [\"White Bread (Enriched)\", \"1 lb.\"],\n", + " [\"Whole Wheat Bread\", \"1 lb.\"], [\"Rye Bread\", \"1 lb.\"],\n", + " [\"Pound Cake\", \"1 lb.\"], [\"Soda Crackers\", \"1 lb.\"],\n", + " [\"Milk\", \"1 qt.\"], [\"Evaporated Milk (can)\", \"14.5 oz.\"],\n", + " [\"Butter\", \"1 lb.\"], [\"Oleomargarine\", \"1 lb.\"],\n", + " [\"Eggs\", \"1 doz.\"], [\"Cheese (Cheddar)\", \"1 lb.\"],\n", + " [\"Cream\", \"1/2 pt.\"], [\"Peanut Butter\", \"1 lb.\"],\n", + " [\"Mayonnaise\", \"1/2 pt.\"], [\"Crisco\", \"1 lb.\"],\n", + " [\"Lard\", \"1 lb.\"], [\"Sirloin Steak\", \"1 lb.\"],\n", + " [\"Round Steak\", \"1 lb.\"], [\"Rib Roast\", \"1 lb.\"],\n", + " [\"Chuck Roast\", \"1 lb.\"], [\"Plate\", \"1 lb.\"],\n", + " [\"Liver (Beef)\", \"1 lb.\"], [\"Leg of Lamb\", \"1 lb.\"],\n", + " [\"Lamb Chops (Rib)\", \"1 lb.\"], [\"Pork Chops\", \"1 lb.\"],\n", + " [\"Pork Loin Roast\", \"1 lb.\"], [\"Bacon\", \"1 lb.\"],\n", + " [\"Ham - smoked\", \"1 lb.\"], [\"Salt Pork\", \"1 lb.\"],\n", + " [\"Roasting Chicken\", \"1 lb.\"], [\"Veal Cutlets\", \"1 lb.\"],\n", + " [\"Salmon, Pink (can)\", \"16 oz.\"], [\"Apples\", \"1 lb.\"],\n", + " [\"Bananas\", \"1 lb.\"], [\"Lemons\", \"1 doz.\"],\n", + " [\"Oranges\", \"1 doz.\"], [\"Green Beans\", \"1 lb.\"],\n", + " [\"Cabbage\", \"1 lb.\"], [\"Carrots\", \"1 bunch\"],\n", + " [\"Celery\", \"1 stalk\"], [\"Lettuce\", \"1 head\"],\n", + " [\"Onions\", \"1 lb.\"], [\"Potatoes\", \"15 lb.\"],\n", + " [\"Spinach\", \"1 lb.\"], [\"Sweet Potatoes\", \"1 lb.\"],\n", + " [\"Peaches (can)\", \"No. 2 1/2\"], [\"Pears (can)\", \"No. 2 1/2,\"],\n", + " [\"Pineapple (can)\", \"No. 2 1/2\"], [\"Asparagus (can)\", \"No. 2\"],\n", + " [\"Grean Beans (can)\", \"No. 2\"],\n", + " [\"Pork and Beans (can)\", \"16 oz.\"], [\"Corn (can)\", \"No. 2\"],\n", + " [\"Peas (can)\", \"No. 2\"], [\"Tomatoes (can)\", \"No. 2\"],\n", + " [\"Tomato Soup (can)\", \"10 1/2 oz.\"],\n", + " [\"Peaches, Dried\", \"1 lb.\"], [\"Prunes, Dried\", \"1 lb.\"],\n", + " [\"Raisins, Dried\", \"15 oz.\"], [\"Peas, Dried\", \"1 lb.\"],\n", + " [\"Lima Beans, Dried\", \"1 lb.\"], [\"Navy Beans, Dried\", \"1 lb.\"],\n", + " [\"Coffee\", \"1 lb.\"], [\"Tea\", \"1/4 lb.\"], [\"Cocoa\", \"8 oz.\"],\n", + " [\"Chocolate\", \"8 oz.\"], [\"Sugar\", \"10 lb.\"],\n", + " [\"Corn Sirup\", \"24 oz.\"], [\"Molasses\", \"18 oz.\"],\n", + " [\"Strawberry Preserve\", \"1 lb.\"]]\n", "\n", - "# price and weight are the two first columns\n", - "data = [\n", - " [36.0, 12600.0, 44.7, 1411.0, 2.0, 365.0, 0.0, 55.4, 33.3, 441.0, 0.0],\n", - " [14.1, 3217.0, 11.6, 418.0, 0.7, 54.0, 0.0, 3.2, 1.9, 68.0, 0.0],\n", - " [24.2, 3280.0, 11.8, 377.0, 14.4, 175.0, 0.0, 14.4, 8.8, 114.0, 0.0],\n", - " [7.1, 3194.0, 11.4, 252.0, 0.1, 56.0, 0.0, 13.5, 2.3, 68.0, 0.0],\n", - " [4.6, 9861.0, 36.0, 897.0, 1.7, 99.0, 30.9, 17.4, 7.9, 106.0, 0.0],\n", - " [8.5, 8005.0, 28.6, 680.0, 0.8, 80.0, 0.0, 10.6, 1.6, 110.0, 0.0],\n", - " [7.5, 6048.0, 21.2, 460.0, 0.6, 41.0, 0.0, 2.0, 4.8, 60.0, 0.0],\n", - " [7.1, 6389.0, 25.3, 907.0, 5.1, 341.0, 0.0, 37.1, 8.9, 64.0, 0.0],\n", - " [7.9, 5742.0, 15.6, 488.0, 2.5, 115.0, 0.0, 13.8, 8.5, 126.0, 0.0],\n", - " [9.1, 4985.0, 12.2, 484.0, 2.7, 125.0, 0.0, 13.9, 6.4, 160.0, 0.0],\n", - " [9.2, 4930.0, 12.4, 439.0, 1.1, 82.0, 0.0, 9.9, 3.0, 66.0, 0.0],\n", - " [24.8, 1829.0, 8.0, 130.0, 0.4, 31.0, 18.9, 2.8, 3.0, 17.0, 0.0],\n", - " [15.1, 3004.0, 12.5, 288.0, 0.5, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n", - " [11.0, 8867.0, 6.1, 310.0, 10.5, 18.0, 16.8, 4.0, 16.0, 7.0, 177.0],\n", - " [6.7, 6035.0, 8.4, 422.0, 15.1, 9.0, 26.0, 3.0, 23.5, 11.0, 60.0],\n", - " [20.8, 1473.0, 10.8, 9.0, 0.2, 3.0, 44.2, 0.0, 0.2, 2.0, 0.0],\n", - " [16.1, 2817.0, 20.6, 17.0, 0.6, 6.0, 55.8, 0.2, 0.0, 0.0, 0.0],\n", - " [32.6, 1857.0, 2.9, 238.0, 1.0, 52.0, 18.6, 2.8, 6.5, 1.0, 0.0],\n", - " [24.2, 1874.0, 7.4, 448.0, 16.4, 19.0, 28.1, 0.8, 10.3, 4.0, 0.0],\n", - " [14.1, 1689.0, 3.5, 49.0, 1.7, 3.0, 16.9, 0.6, 2.5, 0.0, 17.0],\n", - " [17.9, 2534.0, 15.7, 661.0, 1.0, 48.0, 0.0, 9.6, 8.1, 471.0, 0.0],\n", - " [16.7, 1198.0, 8.6, 18.0, 0.2, 8.0, 2.7, 0.4, 0.5, 0.0, 0.0],\n", - " [20.3, 2234.0, 20.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n", - " [9.8, 4628.0, 41.7, 0.0, 0.0, 0.0, 0.2, 0.0, 0.5, 5.0, 0.0],\n", - " [39.6, 1145.0, 2.9, 166.0, 0.1, 34.0, 0.2, 2.1, 2.9, 69.0, 0.0],\n", - " [36.4, 1246.0, 2.2, 214.0, 0.1, 32.0, 0.4, 2.5, 2.4, 87.0, 0.0],\n", - " [29.2, 1553.0, 3.4, 213.0, 0.1, 33.0, 0.0, 0.0, 2.0, 0.0, 0.0],\n", - " [22.6, 2007.0, 3.6, 309.0, 0.2, 46.0, 0.4, 1.0, 4.0, 120.0, 0.0],\n", - " [14.6, 3107.0, 8.5, 404.0, 0.2, 62.0, 0.0, 0.9, 0.0, 0.0, 0.0],\n", - " [26.8, 1692.0, 2.2, 333.0, 0.2, 139.0, 169.2, 6.4, 50.8, 316.0, 525.0],\n", - " [27.6, 1643.0, 3.1, 245.0, 0.1, 20.0, 0.0, 2.8, 3.0, 86.0, 0.0],\n", - " [36.6, 1239.0, 3.3, 140.0, 0.1, 15.0, 0.0, 1.7, 2.7, 54.0, 0.0],\n", - " [30.7, 1477.0, 3.5, 196.0, 0.2, 80.0, 0.0, 17.4, 2.7, 60.0, 0.0],\n", - " [24.2, 1874.0, 4.4, 249.0, 0.3, 37.0, 0.0, 18.2, 3.6, 79.0, 0.0],\n", - " [25.6, 1772.0, 10.4, 152.0, 0.2, 23.0, 0.0, 1.8, 1.8, 71.0, 0.0],\n", - " [27.4, 1655.0, 6.7, 212.0, 0.2, 31.0, 0.0, 9.9, 3.3, 50.0, 0.0],\n", - " [16.0, 2835.0, 18.8, 164.0, 0.1, 26.0, 0.0, 1.4, 1.8, 0.0, 0.0],\n", - " [30.3, 1497.0, 1.8, 184.0, 0.1, 30.0, 0.1, 0.9, 1.8, 68.0, 46.0],\n", - " [42.3, 1072.0, 1.7, 156.0, 0.1, 24.0, 0.0, 1.4, 2.4, 57.0, 0.0],\n", - " [13.0, 3489.0, 5.8, 705.0, 6.8, 45.0, 3.5, 1.0, 4.9, 209.0, 0.0],\n", - " [4.4, 9072.0, 5.8, 27.0, 0.5, 36.0, 7.3, 3.6, 2.7, 5.0, 544.0],\n", - " [6.1, 4982.0, 4.9, 60.0, 0.4, 30.0, 17.4, 2.5, 3.5, 28.0, 498.0],\n", - " [26.0, 2380.0, 1.0, 21.0, 0.5, 14.0, 0.0, 0.5, 0.0, 4.0, 952.0],\n", - " [30.9, 4439.0, 2.2, 40.0, 1.1, 18.0, 11.1, 3.6, 1.3, 10.0, 1993.0],\n", - " [7.1, 5750.0, 2.4, 138.0, 3.7, 80.0, 69.0, 4.3, 5.8, 37.0, 862.0],\n", - " [3.7, 8949.0, 2.6, 125.0, 4.0, 36.0, 7.2, 9.0, 4.5, 26.0, 5369.0],\n", - " [4.7, 6080.0, 2.7, 73.0, 2.8, 43.0, 188.5, 6.1, 4.3, 89.0, 608.0],\n", - " [7.3, 3915.0, 0.9, 51.0, 3.0, 23.0, 0.9, 1.4, 1.4, 9.0, 313.0],\n", - " [8.2, 2247.0, 0.4, 27.0, 1.1, 22.0, 112.4, 1.8, 3.4, 11.0, 449.0],\n", - " [3.6, 11844.0, 5.8, 166.0, 3.8, 59.0, 16.6, 4.7, 5.9, 21.0, 1184.0],\n", - " [34.0, 16810.0, 14.3, 336.0, 1.8, 118.0, 6.7, 29.4, 7.1, 198.0, 2522.0],\n", - " [8.1, 4592.0, 1.1, 106.0, 0.0, 138.0, 918.4, 5.7, 13.8, 33.0, 2755.0],\n", - " [5.1, 7649.0, 9.6, 138.0, 2.7, 54.0, 290.7, 8.4, 5.4, 83.0, 1912.0],\n", - " [16.8, 4894.0, 3.7, 20.0, 0.4, 10.0, 21.5, 0.5, 1.0, 31.0, 196.0],\n", - " [20.4, 4030.0, 3.0, 8.0, 0.3, 8.0, 0.8, 0.8, 0.8, 5.0, 81.0],\n", - " [21.3, 3993.0, 2.4, 16.0, 0.4, 8.0, 2.0, 2.8, 0.8, 7.0, 399.0],\n", - " [27.7, 1945.0, 0.4, 33.0, 0.3, 12.0, 16.3, 1.4, 2.1, 17.0, 272.0],\n", - " [10.0, 5386.0, 1.0, 54.0, 2.0, 65.0, 53.9, 1.6, 4.3, 32.0, 431.0],\n", - " [7.1, 6389.0, 7.5, 364.0, 4.0, 134.0, 3.5, 8.3, 7.7, 56.0, 0.0],\n", - " [10.4, 5452.0, 5.2, 136.0, 0.2, 16.0, 12.0, 1.6, 2.7, 42.0, 218.0],\n", - " [13.8, 4109.0, 2.3, 136.0, 0.6, 45.0, 34.9, 4.9, 2.5, 37.0, 370.0],\n", - " [8.6, 6263.0, 1.3, 63.0, 0.7, 38.0, 53.2, 3.4, 2.5, 36.0, 1253.0],\n", - " [7.6, 3917.0, 1.6, 71.0, 0.6, 43.0, 57.9, 3.5, 2.4, 67.0, 862.0],\n", - " [15.7, 2889.0, 8.5, 87.0, 1.7, 173.0, 86.8, 1.2, 4.3, 55.0, 57.0],\n", - " [9.0, 4284.0, 12.8, 99.0, 2.5, 154.0, 85.7, 3.9, 4.3, 65.0, 257.0],\n", - " [9.4, 4524.0, 13.5, 104.0, 2.5, 136.0, 4.5, 6.3, 1.4, 24.0, 136.0],\n", - " [7.9, 5742.0, 20.0, 1367.0, 4.2, 345.0, 2.9, 28.7, 18.4, 162.0, 0.0],\n", - " [8.9, 5097.0, 17.4, 1055.0, 3.7, 459.0, 5.1, 26.9, 38.2, 93.0, 0.0],\n", - " [5.9, 7688.0, 26.9, 1691.0, 11.4, 792.0, 0.0, 38.4, 24.6, 217.0, 0.0],\n", - " [22.4, 2025.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.0, 5.1, 50.0, 0.0],\n", - " [17.4, 652.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.3, 42.0, 0.0],\n", - " [8.6, 2637.0, 8.7, 237.0, 3.0, 72.0, 0.0, 2.0, 11.9, 40.0, 0.0],\n", - " [16.2, 1400.0, 8.0, 77.0, 1.3, 39.0, 0.0, 0.9, 3.4, 14.0, 0.0],\n", - " [51.7, 8773.0, 34.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n", - " [13.7, 4996.0, 14.7, 0.0, 0.5, 74.0, 0.0, 0.0, 0.0, 5.0, 0.0],\n", - " [13.6, 3752.0, 9.0, 0.0, 10.3, 244.0, 0.0, 1.9, 7.5, 146.0, 0.0],\n", - " [20.5, 2213.0, 6.4, 11.0, 0.4, 7.0, 0.2, 0.2, 0.4, 3.0, 0.0]\n", - "]\n", + " # price and weight are the two first columns\n", + " data = [\n", + " [36.0, 12600.0, 44.7, 1411.0, 2.0, 365.0, 0.0, 55.4, 33.3, 441.0, 0.0],\n", + " [14.1, 3217.0, 11.6, 418.0, 0.7, 54.0, 0.0, 3.2, 1.9, 68.0, 0.0],\n", + " [24.2, 3280.0, 11.8, 377.0, 14.4, 175.0, 0.0, 14.4, 8.8, 114.0, 0.0],\n", + " [7.1, 3194.0, 11.4, 252.0, 0.1, 56.0, 0.0, 13.5, 2.3, 68.0, 0.0],\n", + " [4.6, 9861.0, 36.0, 897.0, 1.7, 99.0, 30.9, 17.4, 7.9, 106.0, 0.0],\n", + " [8.5, 8005.0, 28.6, 680.0, 0.8, 80.0, 0.0, 10.6, 1.6, 110.0, 0.0],\n", + " [7.5, 6048.0, 21.2, 460.0, 0.6, 41.0, 0.0, 2.0, 4.8, 60.0, 0.0],\n", + " [7.1, 6389.0, 25.3, 907.0, 5.1, 341.0, 0.0, 37.1, 8.9, 64.0, 0.0],\n", + " [7.9, 5742.0, 15.6, 488.0, 2.5, 115.0, 0.0, 13.8, 8.5, 126.0, 0.0],\n", + " [9.1, 4985.0, 12.2, 484.0, 2.7, 125.0, 0.0, 13.9, 6.4, 160.0, 0.0],\n", + " [9.2, 4930.0, 12.4, 439.0, 1.1, 82.0, 0.0, 9.9, 3.0, 66.0, 0.0],\n", + " [24.8, 1829.0, 8.0, 130.0, 0.4, 31.0, 18.9, 2.8, 3.0, 17.0, 0.0],\n", + " [15.1, 3004.0, 12.5, 288.0, 0.5, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n", + " [11.0, 8867.0, 6.1, 310.0, 10.5, 18.0, 16.8, 4.0, 16.0, 7.0, 177.0],\n", + " [6.7, 6035.0, 8.4, 422.0, 15.1, 9.0, 26.0, 3.0, 23.5, 11.0, 60.0],\n", + " [20.8, 1473.0, 10.8, 9.0, 0.2, 3.0, 44.2, 0.0, 0.2, 2.0, 0.0],\n", + " [16.1, 2817.0, 20.6, 17.0, 0.6, 6.0, 55.8, 0.2, 0.0, 0.0, 0.0],\n", + " [32.6, 1857.0, 2.9, 238.0, 1.0, 52.0, 18.6, 2.8, 6.5, 1.0, 0.0],\n", + " [24.2, 1874.0, 7.4, 448.0, 16.4, 19.0, 28.1, 0.8, 10.3, 4.0, 0.0],\n", + " [14.1, 1689.0, 3.5, 49.0, 1.7, 3.0, 16.9, 0.6, 2.5, 0.0, 17.0],\n", + " [17.9, 2534.0, 15.7, 661.0, 1.0, 48.0, 0.0, 9.6, 8.1, 471.0, 0.0],\n", + " [16.7, 1198.0, 8.6, 18.0, 0.2, 8.0, 2.7, 0.4, 0.5, 0.0, 0.0],\n", + " [20.3, 2234.0, 20.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n", + " [9.8, 4628.0, 41.7, 0.0, 0.0, 0.0, 0.2, 0.0, 0.5, 5.0, 0.0],\n", + " [39.6, 1145.0, 2.9, 166.0, 0.1, 34.0, 0.2, 2.1, 2.9, 69.0, 0.0],\n", + " [36.4, 1246.0, 2.2, 214.0, 0.1, 32.0, 0.4, 2.5, 2.4, 87.0, 0.0],\n", + " [29.2, 1553.0, 3.4, 213.0, 0.1, 33.0, 0.0, 0.0, 2.0, 0.0, 0.0],\n", + " [22.6, 2007.0, 3.6, 309.0, 0.2, 46.0, 0.4, 1.0, 4.0, 120.0, 0.0],\n", + " [14.6, 3107.0, 8.5, 404.0, 0.2, 62.0, 0.0, 0.9, 0.0, 0.0, 0.0],\n", + " [26.8, 1692.0, 2.2, 333.0, 0.2, 139.0, 169.2, 6.4, 50.8, 316.0, 525.0],\n", + " [27.6, 1643.0, 3.1, 245.0, 0.1, 20.0, 0.0, 2.8, 3.0, 86.0, 0.0],\n", + " [36.6, 1239.0, 3.3, 140.0, 0.1, 15.0, 0.0, 1.7, 2.7, 54.0, 0.0],\n", + " [30.7, 1477.0, 3.5, 196.0, 0.2, 80.0, 0.0, 17.4, 2.7, 60.0, 0.0],\n", + " [24.2, 1874.0, 4.4, 249.0, 0.3, 37.0, 0.0, 18.2, 3.6, 79.0, 0.0],\n", + " [25.6, 1772.0, 10.4, 152.0, 0.2, 23.0, 0.0, 1.8, 1.8, 71.0, 0.0],\n", + " [27.4, 1655.0, 6.7, 212.0, 0.2, 31.0, 0.0, 9.9, 3.3, 50.0, 0.0],\n", + " [16.0, 2835.0, 18.8, 164.0, 0.1, 26.0, 0.0, 1.4, 1.8, 0.0, 0.0],\n", + " [30.3, 1497.0, 1.8, 184.0, 0.1, 30.0, 0.1, 0.9, 1.8, 68.0, 46.0],\n", + " [42.3, 1072.0, 1.7, 156.0, 0.1, 24.0, 0.0, 1.4, 2.4, 57.0, 0.0],\n", + " [13.0, 3489.0, 5.8, 705.0, 6.8, 45.0, 3.5, 1.0, 4.9, 209.0, 0.0],\n", + " [4.4, 9072.0, 5.8, 27.0, 0.5, 36.0, 7.3, 3.6, 2.7, 5.0, 544.0],\n", + " [6.1, 4982.0, 4.9, 60.0, 0.4, 30.0, 17.4, 2.5, 3.5, 28.0, 498.0],\n", + " [26.0, 2380.0, 1.0, 21.0, 0.5, 14.0, 0.0, 0.5, 0.0, 4.0, 952.0],\n", + " [30.9, 4439.0, 2.2, 40.0, 1.1, 18.0, 11.1, 3.6, 1.3, 10.0, 1993.0],\n", + " [7.1, 5750.0, 2.4, 138.0, 3.7, 80.0, 69.0, 4.3, 5.8, 37.0, 862.0],\n", + " [3.7, 8949.0, 2.6, 125.0, 4.0, 36.0, 7.2, 9.0, 4.5, 26.0, 5369.0],\n", + " [4.7, 6080.0, 2.7, 73.0, 2.8, 43.0, 188.5, 6.1, 4.3, 89.0, 608.0],\n", + " [7.3, 3915.0, 0.9, 51.0, 3.0, 23.0, 0.9, 1.4, 1.4, 9.0, 313.0],\n", + " [8.2, 2247.0, 0.4, 27.0, 1.1, 22.0, 112.4, 1.8, 3.4, 11.0, 449.0],\n", + " [3.6, 11844.0, 5.8, 166.0, 3.8, 59.0, 16.6, 4.7, 5.9, 21.0, 1184.0],\n", + " [34.0, 16810.0, 14.3, 336.0, 1.8, 118.0, 6.7, 29.4, 7.1, 198.0, 2522.0],\n", + " [8.1, 4592.0, 1.1, 106.0, 0.0, 138.0, 918.4, 5.7, 13.8, 33.0, 2755.0],\n", + " [5.1, 7649.0, 9.6, 138.0, 2.7, 54.0, 290.7, 8.4, 5.4, 83.0, 1912.0],\n", + " [16.8, 4894.0, 3.7, 20.0, 0.4, 10.0, 21.5, 0.5, 1.0, 31.0, 196.0],\n", + " [20.4, 4030.0, 3.0, 8.0, 0.3, 8.0, 0.8, 0.8, 0.8, 5.0, 81.0],\n", + " [21.3, 3993.0, 2.4, 16.0, 0.4, 8.0, 2.0, 2.8, 0.8, 7.0, 399.0],\n", + " [27.7, 1945.0, 0.4, 33.0, 0.3, 12.0, 16.3, 1.4, 2.1, 17.0, 272.0],\n", + " [10.0, 5386.0, 1.0, 54.0, 2.0, 65.0, 53.9, 1.6, 4.3, 32.0, 431.0],\n", + " [7.1, 6389.0, 7.5, 364.0, 4.0, 134.0, 3.5, 8.3, 7.7, 56.0, 0.0],\n", + " [10.4, 5452.0, 5.2, 136.0, 0.2, 16.0, 12.0, 1.6, 2.7, 42.0, 218.0],\n", + " [13.8, 4109.0, 2.3, 136.0, 0.6, 45.0, 34.9, 4.9, 2.5, 37.0, 370.0],\n", + " [8.6, 6263.0, 1.3, 63.0, 0.7, 38.0, 53.2, 3.4, 2.5, 36.0, 1253.0],\n", + " [7.6, 3917.0, 1.6, 71.0, 0.6, 43.0, 57.9, 3.5, 2.4, 67.0, 862.0],\n", + " [15.7, 2889.0, 8.5, 87.0, 1.7, 173.0, 86.8, 1.2, 4.3, 55.0, 57.0],\n", + " [9.0, 4284.0, 12.8, 99.0, 2.5, 154.0, 85.7, 3.9, 4.3, 65.0, 257.0],\n", + " [9.4, 4524.0, 13.5, 104.0, 2.5, 136.0, 4.5, 6.3, 1.4, 24.0, 136.0],\n", + " [7.9, 5742.0, 20.0, 1367.0, 4.2, 345.0, 2.9, 28.7, 18.4, 162.0, 0.0],\n", + " [8.9, 5097.0, 17.4, 1055.0, 3.7, 459.0, 5.1, 26.9, 38.2, 93.0, 0.0],\n", + " [5.9, 7688.0, 26.9, 1691.0, 11.4, 792.0, 0.0, 38.4, 24.6, 217.0, 0.0],\n", + " [22.4, 2025.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.0, 5.1, 50.0, 0.0],\n", + " [17.4, 652.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.3, 42.0, 0.0],\n", + " [8.6, 2637.0, 8.7, 237.0, 3.0, 72.0, 0.0, 2.0, 11.9, 40.0, 0.0],\n", + " [16.2, 1400.0, 8.0, 77.0, 1.3, 39.0, 0.0, 0.9, 3.4, 14.0, 0.0],\n", + " [51.7, 8773.0, 34.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n", + " [13.7, 4996.0, 14.7, 0.0, 0.5, 74.0, 0.0, 0.0, 0.0, 5.0, 0.0],\n", + " [13.6, 3752.0, 9.0, 0.0, 10.3, 244.0, 0.0, 1.9, 7.5, 146.0, 0.0],\n", + " [20.5, 2213.0, 6.4, 11.0, 0.4, 7.0, 0.2, 0.2, 0.4, 3.0, 0.0]\n", + " ]\n", "\n", - "# recommended daily allowance for a moderately active man\n", - "allowance = [3.0, 70.0, 0.8, 12.0, 5.0, 1.8, 2.7, 18.0, 75.0]\n", + " # recommended daily allowance for a moderately active man\n", + " allowance = [3.0, 70.0, 0.8, 12.0, 5.0, 1.8, 2.7, 18.0, 75.0]\n", "\n", - "#\n", - "# variables\n", - "#\n", - "x = [solver.NumVar(0, 1000, \"x[%i]\" % i) for i in C]\n", - "x_cost = [solver.NumVar(0, 1000, \"x_cost[%i]\" % i) for i in C]\n", - "quant = [solver.NumVar(0, 1000, \"quant[%i]\" % i) for i in C]\n", + " #\n", + " # variables\n", + " #\n", + " x = [solver.NumVar(0, 1000, \"x[%i]\" % i) for i in C]\n", + " x_cost = [solver.NumVar(0, 1000, \"x_cost[%i]\" % i) for i in C]\n", + " quant = [solver.NumVar(0, 1000, \"quant[%i]\" % i) for i in C]\n", "\n", - "# total food bill\n", - "total_cost = solver.NumVar(0, 1000, \"total_cost\")\n", + " # total food bill\n", + " total_cost = solver.NumVar(0, 1000, \"total_cost\")\n", "\n", - "# cost per day, to minimize\n", - "cost = solver.Sum(x)\n", + " # cost per day, to minimize\n", + " cost = solver.Sum(x)\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(total_cost == days * cost) # cost per year\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(total_cost == days * cost) # cost per year\n", "\n", - "for c in C:\n", - " solver.Add(x_cost[c] == days * x[c])\n", - " solver.Add(quant[c] == 100.0 * days * x[c] / data[c][0])\n", + " for c in C:\n", + " solver.Add(x_cost[c] == days * x[c])\n", + " solver.Add(quant[c] == 100.0 * days * x[c] / data[c][0])\n", "\n", - "# nutrient balance\n", - "for n in range(2, num_nutrients + 2):\n", - " solver.Add(solver.Sum([data[c][n] * x[c] for c in C]) >= allowance[n - 2])\n", + " # nutrient balance\n", + " for n in range(2, num_nutrients + 2):\n", + " solver.Add(solver.Sum([data[c][n] * x[c] for c in C]) >= allowance[n - 2])\n", "\n", - "objective = solver.Minimize(cost)\n", + " objective = solver.Minimize(cost)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", "\n", - "print()\n", + " print()\n", "\n", - "print(\"Cost = %0.2f\" % solver.Objective().Value())\n", - "# print 'Cost:', cost.SolutionValue()\n", - "print(\"Total cost: %0.2f\" % total_cost.SolutionValue())\n", - "print()\n", - "for i in C:\n", - " if x[i].SolutionValue() > 0:\n", - " print(\"%-21s %-11s %0.2f %0.2f\" %\n", - " (commodities[i][0], commodities[i][1], x_cost[i].SolutionValue(),\n", - " quant[i].SolutionValue()))\n", + " print(\"Cost = %0.2f\" % solver.Objective().Value())\n", + " # print 'Cost:', cost.SolutionValue()\n", + " print(\"Total cost: %0.2f\" % total_cost.SolutionValue())\n", + " print()\n", + " for i in C:\n", + " if x[i].SolutionValue() > 0:\n", + " print(\"%-21s %-11s %0.2f %0.2f\" %\n", + " (commodities[i][0], commodities[i][1], x_cost[i].SolutionValue(),\n", + " quant[i].SolutionValue()))\n", "\n", - "print()\n", + " print()\n", "\n", - "print(\"walltime :\", solver.WallTime(), \"ms\")\n", - "if sol == \"CBC\":\n", - " print(\"iterations:\", solver.Iterations())\n", + " print(\"walltime :\", solver.WallTime(), \"ms\")\n", + " if sol == \"CBC\":\n", + " print(\"iterations:\", solver.Iterations())\n", + "\n", + "\n", + "sol = \"CBC\"\n", + "\n", + "if len(sys.argv) > 1:\n", + " sol = sys.argv[1]\n", + " if sol != \"GLPK\" and sol != \"CBC\":\n", + " print(\"Solver must be either GLPK or CBC\")\n", + " sys.exit(1)\n", + "\n", + "main(sol)\n", "\n" ] } diff --git a/examples/notebook/contrib/strimko2.ipynb b/examples/notebook/contrib/strimko2.ipynb index 700a687787..d526712333 100644 --- a/examples/notebook/contrib/strimko2.ipynb +++ b/examples/notebook/contrib/strimko2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", - "\"\"\"Strimko problem in Google CP Solver.\n", + "Strimko problem in Google CP Solver.\n", "\n", " From\n", " 360: A New Twist on Latin Squares\n", @@ -116,96 +101,113 @@ " * Gecode: http://hakank.org/gecode/strimko2.cpp\n", "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", - " See my other Google CP Solver models: http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " See my other Google CP Solver models: http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(streams='', placed=''):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Strimko')\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Strimko')\n", "\n", - "#\n", - "# default problem\n", - "#\n", - "if streams == '':\n", - " streams = [[1, 1, 2, 2, 2, 2, 2], [1, 1, 2, 3, 3, 3, 2],\n", - " [1, 4, 1, 3, 3, 5, 5], [4, 4, 3, 1, 3, 5, 5],\n", - " [4, 6, 6, 6, 7, 7, 5], [6, 4, 6, 4, 5, 5, 7],\n", - " [6, 6, 4, 7, 7, 7, 7]]\n", + " #\n", + " # default problem\n", + " #\n", + " if streams == '':\n", + " streams = [[1, 1, 2, 2, 2, 2, 2], [1, 1, 2, 3, 3, 3, 2],\n", + " [1, 4, 1, 3, 3, 5, 5], [4, 4, 3, 1, 3, 5, 5],\n", + " [4, 6, 6, 6, 7, 7, 5], [6, 4, 6, 4, 5, 5, 7],\n", + " [6, 6, 4, 7, 7, 7, 7]]\n", "\n", - " # Note: This is 1-based\n", - " placed = [[2, 1, 1], [2, 3, 7], [2, 5, 6], [2, 7, 4], [3, 2, 7], [3, 6, 1],\n", - " [4, 1, 4], [4, 7, 5], [5, 2, 2], [5, 6, 6]]\n", + " # Note: This is 1-based\n", + " placed = [[2, 1, 1], [2, 3, 7], [2, 5, 6], [2, 7, 4], [3, 2, 7], [3, 6, 1],\n", + " [4, 1, 4], [4, 7, 5], [5, 2, 2], [5, 6, 6]]\n", "\n", - "n = len(streams)\n", - "num_placed = len(placed)\n", + " n = len(streams)\n", + " num_placed = len(placed)\n", "\n", - "print('n:', n)\n", + " print('n:', n)\n", "\n", - "#\n", - "# variables\n", - "#\n", + " #\n", + " # variables\n", + " #\n", "\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[i, j] = solver.IntVar(1, n, 'x[%i,%i]' % (i, j))\n", - "\n", - "x_flat = [x[i, j] for i in range(n) for j in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# all rows and columns must be unique, i.e. a Latin Square\n", - "for i in range(n):\n", - " row = [x[i, j] for j in range(n)]\n", - " solver.Add(solver.AllDifferent(row))\n", - "\n", - " col = [x[j, i] for j in range(n)]\n", - " solver.Add(solver.AllDifferent(col))\n", - "\n", - "#\n", - "# streams\n", - "#\n", - "for s in range(1, n + 1):\n", - " tmp = [x[i, j] for i in range(n) for j in range(n) if streams[i][j] == s]\n", - " solver.Add(solver.AllDifferent(tmp))\n", - "\n", - "#\n", - "# placed\n", - "#\n", - "for i in range(num_placed):\n", - " # note: also adjust to 0-based\n", - " solver.Add(x[placed[i][0] - 1, placed[i][1] - 1] == placed[i][2])\n", - "\n", - "#\n", - "# search and solution\n", - "#\n", - "db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " print(x[i, j].Value(), end=' ')\n", + " x[i, j] = solver.IntVar(1, n, 'x[%i,%i]' % (i, j))\n", + "\n", + " x_flat = [x[i, j] for i in range(n) for j in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # all rows and columns must be unique, i.e. a Latin Square\n", + " for i in range(n):\n", + " row = [x[i, j] for j in range(n)]\n", + " solver.Add(solver.AllDifferent(row))\n", + "\n", + " col = [x[j, i] for j in range(n)]\n", + " solver.Add(solver.AllDifferent(col))\n", + "\n", + " #\n", + " # streams\n", + " #\n", + " for s in range(1, n + 1):\n", + " tmp = [x[i, j] for i in range(n) for j in range(n) if streams[i][j] == s]\n", + " solver.Add(solver.AllDifferent(tmp))\n", + "\n", + " #\n", + " # placed\n", + " #\n", + " for i in range(num_placed):\n", + " # note: also adjust to 0-based\n", + " solver.Add(x[placed[i][0] - 1, placed[i][1] - 1] == placed[i][2])\n", + "\n", + " #\n", + " # search and solution\n", + " #\n", + " db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " for i in range(n):\n", + " for j in range(n):\n", + " print(x[i, j].Value(), end=' ')\n", + " print()\n", + "\n", " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", " print()\n", - " num_solutions += 1\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + "if len(sys.argv) > 1:\n", + " problem_file = sys.argv[1]\n", + " exec(compile(open(problem_file).read(), problem_file, 'exec'))\n", + " main(streams, placed)\n", + "else:\n", + " main()\n", "\n" ] } diff --git a/examples/notebook/contrib/subset_sum.ipynb b/examples/notebook/contrib/subset_sum.ipynb index e640b8630a..4473ca1990 100644 --- a/examples/notebook/contrib/subset_sum.ipynb +++ b/examples/notebook/contrib/subset_sum.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Subset sum problem in Google CP Solver.\n", "\n", @@ -112,8 +97,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -129,53 +122,59 @@ " return x, ss\n", "\n", "\n", + "def main(coins, total):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"n-queens\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"n-queens\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"coins:\", coins)\n", - "print(\"total:\", total)\n", - "print()\n", - "\n", - "#\n", - "# declare variables\n", - "#\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "x, ss = subset_sum(solver, coins, total)\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x)\n", - "solution.Add(ss)\n", - "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"ss:\", ss.Value())\n", - " print(\"x: \", [x[i].Value() for i in range(len(x))])\n", + " #\n", + " # data\n", + " #\n", + " print(\"coins:\", coins)\n", + " print(\"total:\", total)\n", " print()\n", - " num_solutions += 1\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " #\n", + " # declare variables\n", + " #\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + " x, ss = subset_sum(solver, coins, total)\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x)\n", + " solution.Add(ss)\n", + "\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"ss:\", ss.Value())\n", + " print(\"x: \", [x[i].Value() for i in range(len(x))])\n", + " print()\n", + " num_solutions += 1\n", + " solver.EndSearch()\n", + "\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", "\n", "coins = [16, 17, 23, 24, 39, 40]\n", - "total = 100\n" + "total = 100\n", + "if len(sys.argv) > 1:\n", + " total = int(sys.argv[1])\n", + "main(coins, total)\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/survo_puzzle.ipynb b/examples/notebook/contrib/survo_puzzle.ipynb index 21b1d55be4..f59e018338 100644 --- a/examples/notebook/contrib/survo_puzzle.ipynb +++ b/examples/notebook/contrib/survo_puzzle.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Survo puzzle Google CP Solver.\n", "\n", @@ -133,93 +118,103 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(r=0, c=0, rowsums=[], colsums=[], game=[]):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Survo puzzle\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Survo puzzle\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "if r == 0:\n", - " r = 3\n", - " c = 4\n", - " rowsums = [30, 18, 30]\n", - " colsums = [27, 16, 10, 25]\n", - " game = [[0, 6, 0, 0], [8, 0, 0, 0], [0, 0, 3, 0]]\n", + " #\n", + " # data\n", + " #\n", + " if r == 0:\n", + " r = 3\n", + " c = 4\n", + " rowsums = [30, 18, 30]\n", + " colsums = [27, 16, 10, 25]\n", + " game = [[0, 6, 0, 0], [8, 0, 0, 0], [0, 0, 3, 0]]\n", "\n", - "print(\"r:\", r, \"c:\", c)\n", + " print(\"r:\", r, \"c:\", c)\n", + "\n", + " # declare variables\n", + " x = {}\n", + " for i in range(r):\n", + " for j in range(c):\n", + " x[(i, j)] = solver.IntVar(1, r * c, \"x %i %i\" % (i, j))\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " #\n", + " # set the clues\n", + " #\n", + " for i in range(r):\n", + " for j in range(c):\n", + " if game[i][j] > 0:\n", + " solver.Add(x[i, j] == game[i][j])\n", + "\n", + " xflat = [x[(i, j)] for i in range(r) for j in range(c)]\n", + " solver.Add(solver.AllDifferent(xflat))\n", + " #\n", + " # calculate rowsums and colsums\n", + " #\n", + " for i in range(r):\n", + " solver.Add(rowsums[i] == solver.Sum([x[i, j] for j in range(c)]))\n", "\n", - "# declare variables\n", - "x = {}\n", - "for i in range(r):\n", " for j in range(c):\n", - " x[(i, j)] = solver.IntVar(1, r * c, \"x %i %i\" % (i, j))\n", + " solver.Add(colsums[j] == solver.Sum([x[i, j] for i in range(r)]))\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([x[(i, j)] for i in range(r) for j in range(c)])\n", "\n", - "#\n", - "# set the clues\n", - "#\n", - "for i in range(r):\n", - " for j in range(c):\n", - " if game[i][j] > 0:\n", - " solver.Add(x[i, j] == game[i][j])\n", + " collector = solver.AllSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase(xflat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE),\n", + " [collector])\n", "\n", - "xflat = [x[(i, j)] for i in range(r) for j in range(c)]\n", - "solver.Add(solver.AllDifferent(xflat))\n", - "#\n", - "# calculate rowsums and colsums\n", - "#\n", - "for i in range(r):\n", - " solver.Add(rowsums[i] == solver.Sum([x[i, j] for j in range(c)]))\n", + " num_solutions = collector.SolutionCount()\n", + " print(\"\\nnum_solutions: \", num_solutions)\n", + " if num_solutions > 0:\n", + " for s in range(num_solutions):\n", + " xval = [collector.Value(s, x[(i, j)]) for i in range(r) for j in range(c)]\n", "\n", - "for j in range(c):\n", - " solver.Add(colsums[j] == solver.Sum([x[i, j] for i in range(r)]))\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([x[(i, j)] for i in range(r) for j in range(c)])\n", - "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase(xflat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE),\n", - " [collector])\n", - "\n", - "num_solutions = collector.SolutionCount()\n", - "print(\"\\nnum_solutions: \", num_solutions)\n", - "if num_solutions > 0:\n", - " for s in range(num_solutions):\n", - " xval = [collector.Value(s, x[(i, j)]) for i in range(r) for j in range(c)]\n", - "\n", - " for i in range(r):\n", - " for j in range(c):\n", - " print(\"%2i\" % (xval[i * c + j]), end=\" \")\n", + " for i in range(r):\n", + " for j in range(c):\n", + " print(\"%2i\" % (xval[i * c + j]), end=\" \")\n", + " print()\n", " print()\n", + "\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - " print()\n", - " print(\"num_solutions:\", num_solutions)\n", - " print(\"failures:\", solver.Failures())\n", - " print(\"branches:\", solver.Branches())\n", - " print(\"WallTime:\", solver.WallTime())\n", - "\n", - "else:\n", - " print(\"No solutions found\")\n", + " else:\n", + " print(\"No solutions found\")\n", "\n", "\n", "#\n", "# Read a problem instance from a file\n", - "#def read_problem(file):\n", + "#\n", + "def read_problem(file):\n", " f = open(file, \"r\")\n", " r = int(f.readline())\n", " c = int(f.readline())\n", @@ -237,6 +232,13 @@ " game.append(row)\n", " return [r, c, rowsums, colsums, game]\n", "\n", + "\n", + "if len(sys.argv) > 1:\n", + " file = sys.argv[1]\n", + " [r, c, rowsums, colsums, game] = read_problem(file)\n", + " main(r, c, rowsums, colsums, game)\n", + "else:\n", + " main()\n", "\n" ] } diff --git a/examples/notebook/contrib/toNum.ipynb b/examples/notebook/contrib/toNum.ipynb index 0741474f7b..dd2ebfaaf1 100644 --- a/examples/notebook/contrib/toNum.ipynb +++ b/examples/notebook/contrib/toNum.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " toNum in Google CP Solver.\n", "\n", @@ -96,8 +81,16 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "#\n", @@ -111,47 +104,51 @@ " s == solver.Sum([(base**(tlen - i - 1)) * t[i] for i in range(tlen)]))\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"toNum test\")\n", + "def main(unused_argv):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"toNum test\")\n", "\n", - "# data\n", - "n = 4\n", - "base = 10\n", + " # data\n", + " n = 4\n", + " base = 10\n", "\n", - "# declare variables\n", - "x = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", - "y = solver.IntVar(0, 10**n - 1, \"y\")\n", + " # declare variables\n", + " x = [solver.IntVar(0, n - 1, \"x%i\" % i) for i in range(n)]\n", + " y = solver.IntVar(0, 10**n - 1, \"y\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "# solver.Add(solver.AllDifferent([x[i] for i in range(n)]))\n", - "solver.Add(solver.AllDifferent(x))\n", - "# solver.Add(x[0] > 0) # just for fun\n", + " #\n", + " # constraints\n", + " #\n", + " # solver.Add(solver.AllDifferent([x[i] for i in range(n)]))\n", + " solver.Add(solver.AllDifferent(x))\n", + " # solver.Add(x[0] > 0) # just for fun\n", "\n", - "toNum(solver, x, y, base)\n", + " toNum(solver, x, y, base)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([x[i] for i in range(n)])\n", - "solution.Add(y)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([x[i] for i in range(n)])\n", + " solution.Add(y)\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "solver.Solve(\n", - " solver.Phase([x[i] for i in range(n)], solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE), [collector])\n", + " collector = solver.AllSolutionCollector(solution)\n", + " solver.Solve(\n", + " solver.Phase([x[i] for i in range(n)], solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE), [collector])\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "for s in range(num_solutions):\n", - " print(\"x:\", [collector.Value(s, x[i]) for i in range(n)])\n", - " print(\"y:\", collector.Value(s, y))\n", - " print()\n", + " num_solutions = collector.SolutionCount()\n", + " for s in range(num_solutions):\n", + " print(\"x:\", [collector.Value(s, x[i]) for i in range(n)])\n", + " print(\"y:\", collector.Value(s, y))\n", + " print()\n", "\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", + "\n", + "\n", + "main(\"cp sample\")\n", "\n" ] } diff --git a/examples/notebook/contrib/traffic_lights.ipynb b/examples/notebook/contrib/traffic_lights.ipynb index b65b3e74fc..ec6cef2243 100644 --- a/examples/notebook/contrib/traffic_lights.ipynb +++ b/examples/notebook/contrib/traffic_lights.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Traffic lights problem in Google CP Solver.\n", "\n", @@ -143,63 +128,75 @@ " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", " http://www.hakank.org/google_or_tools/\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(base=10, start=1, len1=1, len2=4):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Traffic lights\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Traffic lights\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 4\n", - "r, ry, g, y = list(range(n))\n", - "lights = [\"r\", \"ry\", \"g\", \"y\"]\n", + " #\n", + " # data\n", + " #\n", + " n = 4\n", + " r, ry, g, y = list(range(n))\n", + " lights = [\"r\", \"ry\", \"g\", \"y\"]\n", "\n", - "# The allowed combinations\n", - "allowed = []\n", - "allowed.extend([(r, r, g, g), (ry, r, y, r), (g, g, r, r), (y, r, ry, r)])\n", + " # The allowed combinations\n", + " allowed = []\n", + " allowed.extend([(r, r, g, g), (ry, r, y, r), (g, g, r, r), (y, r, ry, r)])\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "V = [solver.IntVar(0, n - 1, \"V[%i]\" % i) for i in range(n)]\n", - "P = [solver.IntVar(0, n - 1, \"P[%i]\" % i) for i in range(n)]\n", + " #\n", + " # declare variables\n", + " #\n", + " V = [solver.IntVar(0, n - 1, \"V[%i]\" % i) for i in range(n)]\n", + " P = [solver.IntVar(0, n - 1, \"P[%i]\" % i) for i in range(n)]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if j == (1 + i) % n:\n", - " solver.Add(solver.AllowedAssignments((V[i], P[i], V[j], P[j]), allowed))\n", - "\n", - "#\n", - "# Search and result\n", - "#\n", - "db = solver.Phase(V + P, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", + " #\n", + " # constraints\n", + " #\n", " for i in range(n):\n", - " print(\"%+2s %+2s\" % (lights[V[i].Value()], lights[P[i].Value()]), end=\" \")\n", + " for j in range(n):\n", + " if j == (1 + i) % n:\n", + " solver.Add(solver.AllowedAssignments((V[i], P[i], V[j], P[j]), allowed))\n", + "\n", + " #\n", + " # Search and result\n", + " #\n", + " db = solver.Phase(V + P, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " for i in range(n):\n", + " print(\"%+2s %+2s\" % (lights[V[i].Value()], lights[P[i].Value()]), end=\" \")\n", + " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", + "\n", + " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", " print()\n", - " num_solutions += 1\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", - "print()\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/vendor_scheduling.ipynb b/examples/notebook/contrib/vendor_scheduling.ipynb index 810fa9cc31..555fbe89f5 100644 --- a/examples/notebook/contrib/vendor_scheduling.ipynb +++ b/examples/notebook/contrib/vendor_scheduling.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -77,98 +77,102 @@ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('Vendors scheduling')\n", + "def main():\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('Vendors scheduling')\n", "\n", - "#\n", - "# data\n", - "#\n", - "num_vendors = 9\n", - "num_hours = 10\n", - "num_work_types = 1\n", + " #\n", + " # data\n", + " #\n", + " num_vendors = 9\n", + " num_hours = 10\n", + " num_work_types = 1\n", "\n", - "trafic = [100, 500, 100, 200, 320, 300, 200, 220, 300, 120]\n", - "max_trafic_per_vendor = 100\n", + " trafic = [100, 500, 100, 200, 320, 300, 200, 220, 300, 120]\n", + " max_trafic_per_vendor = 100\n", "\n", - "# Last columns are :\n", - "# index_of_the_schedule, sum of worked hours (per work type).\n", - "# The index is useful for branching.\n", - "possible_schedules = [[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 8],\n", - " [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 4],\n", - " [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 2, 5],\n", - " [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 4],\n", - " [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 3],\n", - " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]]\n", + " # Last columns are :\n", + " # index_of_the_schedule, sum of worked hours (per work type).\n", + " # The index is useful for branching.\n", + " possible_schedules = [[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 8],\n", + " [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 4],\n", + " [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 2, 5],\n", + " [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 4],\n", + " [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 3],\n", + " [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]]\n", "\n", - "num_possible_schedules = len(possible_schedules)\n", - "selected_schedules = []\n", - "vendors_stat = []\n", - "hours_stat = []\n", + " num_possible_schedules = len(possible_schedules)\n", + " selected_schedules = []\n", + " vendors_stat = []\n", + " hours_stat = []\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = {}\n", - "\n", - "for i in range(num_vendors):\n", - " tmp = []\n", - " for j in range(num_hours):\n", - " x[i, j] = solver.IntVar(0, num_work_types, 'x[%i,%i]' % (i, j))\n", - " tmp.append(x[i, j])\n", - " selected_schedule = solver.IntVar(0, num_possible_schedules - 1,\n", - " 's[%i]' % i)\n", - " hours = solver.IntVar(0, num_hours, 'h[%i]' % i)\n", - " selected_schedules.append(selected_schedule)\n", - " vendors_stat.append(hours)\n", - " tmp.append(selected_schedule)\n", - " tmp.append(hours)\n", - "\n", - " solver.Add(solver.AllowedAssignments(tmp, possible_schedules))\n", - "\n", - "#\n", - "# Statistics and constraints for each hour\n", - "#\n", - "for j in range(num_hours):\n", - " workers = solver.Sum([x[i, j] for i in range(num_vendors)]).Var()\n", - " hours_stat.append(workers)\n", - " solver.Add(workers * max_trafic_per_vendor >= trafic[j])\n", - "\n", - "#\n", - "# Redundant constraint: sort selected_schedules\n", - "#\n", - "for i in range(num_vendors - 1):\n", - " solver.Add(selected_schedules[i] <= selected_schedules[i + 1])\n", - "\n", - "#\n", - "# Search\n", - "#\n", - "db = solver.Phase(selected_schedules, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " num_solutions += 1\n", + " #\n", + " # declare variables\n", + " #\n", + " x = {}\n", "\n", " for i in range(num_vendors):\n", - " print('Vendor %i: ' % i,\n", - " possible_schedules[selected_schedules[i].Value()])\n", - " print()\n", + " tmp = []\n", + " for j in range(num_hours):\n", + " x[i, j] = solver.IntVar(0, num_work_types, 'x[%i,%i]' % (i, j))\n", + " tmp.append(x[i, j])\n", + " selected_schedule = solver.IntVar(0, num_possible_schedules - 1,\n", + " 's[%i]' % i)\n", + " hours = solver.IntVar(0, num_hours, 'h[%i]' % i)\n", + " selected_schedules.append(selected_schedule)\n", + " vendors_stat.append(hours)\n", + " tmp.append(selected_schedule)\n", + " tmp.append(hours)\n", "\n", - " print('Statistics per day:')\n", + " solver.Add(solver.AllowedAssignments(tmp, possible_schedules))\n", + "\n", + " #\n", + " # Statistics and constraints for each hour\n", + " #\n", " for j in range(num_hours):\n", - " print('Day%2i: ' % j, end=' ')\n", - " print(hours_stat[j].Value(), end=' ')\n", - " print()\n", - " print()\n", + " workers = solver.Sum([x[i, j] for i in range(num_vendors)]).Var()\n", + " hours_stat.append(workers)\n", + " solver.Add(workers * max_trafic_per_vendor >= trafic[j])\n", "\n", - "solver.EndSearch()\n", - "print()\n", - "print('num_solutions:', num_solutions)\n", - "print('failures:', solver.Failures())\n", - "print('branches:', solver.Branches())\n", - "print('WallTime:', solver.WallTime(), 'ms')\n", + " #\n", + " # Redundant constraint: sort selected_schedules\n", + " #\n", + " for i in range(num_vendors - 1):\n", + " solver.Add(selected_schedules[i] <= selected_schedules[i + 1])\n", + "\n", + " #\n", + " # Search\n", + " #\n", + " db = solver.Phase(selected_schedules, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + "\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " num_solutions += 1\n", + "\n", + " for i in range(num_vendors):\n", + " print('Vendor %i: ' % i,\n", + " possible_schedules[selected_schedules[i].Value()])\n", + " print()\n", + "\n", + " print('Statistics per day:')\n", + " for j in range(num_hours):\n", + " print('Day%2i: ' % j, end=' ')\n", + " print(hours_stat[j].Value(), end=' ')\n", + " print()\n", + " print()\n", + "\n", + " solver.EndSearch()\n", + " print()\n", + " print('num_solutions:', num_solutions)\n", + " print('failures:', solver.Failures())\n", + " print('branches:', solver.Branches())\n", + " print('WallTime:', solver.WallTime(), 'ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/volsay.ipynb b/examples/notebook/contrib/volsay.ipynb index d1225db78e..0cac7535b9 100644 --- a/examples/notebook/contrib/volsay.ipynb +++ b/examples/notebook/contrib/volsay.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Volsay problem in Google or-tools.\n", "\n", @@ -95,49 +80,61 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(unused_argv):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "# using GLPK\n", - "#solver = pywraplp.Solver('CoinsGridGLPK',\n", - "# pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", + " # using GLPK\n", + " #solver = pywraplp.Solver('CoinsGridGLPK',\n", + " # pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", "\n", - "# Using CLP\n", - "solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", + " # Using CLP\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", "\n", - "# data\n", + " # data\n", "\n", - "# declare variables\n", - "Gas = solver.NumVar(0, 100000, 'Gas')\n", - "Chloride = solver.NumVar(0, 100000, 'Cloride')\n", + " # declare variables\n", + " Gas = solver.NumVar(0, 100000, 'Gas')\n", + " Chloride = solver.NumVar(0, 100000, 'Cloride')\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(Gas + Chloride <= 50)\n", - "solver.Add(3 * Gas + 4 * Chloride <= 180)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(Gas + Chloride <= 50)\n", + " solver.Add(3 * Gas + 4 * Chloride <= 180)\n", "\n", - "# objective\n", - "objective = solver.Maximize(40 * Gas + 50 * Chloride)\n", + " # objective\n", + " objective = solver.Maximize(40 * Gas + 50 * Chloride)\n", "\n", - "print('NumConstraints:', solver.NumConstraints())\n", + " print('NumConstraints:', solver.NumConstraints())\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('objective = ', solver.Objective().Value())\n", - "print('Gas = ', Gas.SolutionValue(), 'ReducedCost =', Gas.ReducedCost())\n", - "print('Chloride:', Chloride.SolutionValue(), 'ReducedCost =',\n", - " Chloride.ReducedCost())\n", + " print()\n", + " print('objective = ', solver.Objective().Value())\n", + " print('Gas = ', Gas.SolutionValue(), 'ReducedCost =', Gas.ReducedCost())\n", + " print('Chloride:', Chloride.SolutionValue(), 'ReducedCost =',\n", + " Chloride.ReducedCost())\n", + "\n", + "\n", + "main('Volsay')\n", "\n" ] } diff --git a/examples/notebook/contrib/volsay2.ipynb b/examples/notebook/contrib/volsay2.ipynb index 5b69eb91f0..0f5c315bff 100644 --- a/examples/notebook/contrib/volsay2.ipynb +++ b/examples/notebook/contrib/volsay2.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Volsay problem in Google or-tools.\n", "\n", @@ -96,56 +81,68 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(unused_argv):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "# using GLPK\n", - "# solver = pywraplp.Solver('CoinsGridGLPK',\n", - "# pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", + " # using GLPK\n", + " # solver = pywraplp.Solver('CoinsGridGLPK',\n", + " # pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", "\n", - "# Using CLP\n", - "solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", + " # Using CLP\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", "\n", - "# data\n", - "num_products = 2\n", - "Gas = 0\n", - "Chloride = 1\n", + " # data\n", + " num_products = 2\n", + " Gas = 0\n", + " Chloride = 1\n", "\n", - "products = ['Gas', 'Chloride']\n", + " products = ['Gas', 'Chloride']\n", "\n", - "# declare variables\n", - "production = [\n", - " solver.NumVar(0, 100000, 'production[%i]' % i)\n", - " for i in range(num_products)\n", - "]\n", + " # declare variables\n", + " production = [\n", + " solver.NumVar(0, 100000, 'production[%i]' % i)\n", + " for i in range(num_products)\n", + " ]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(production[Gas] + production[Chloride] <= 50)\n", - "solver.Add(3 * production[Gas] + 4 * production[Chloride] <= 180)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(production[Gas] + production[Chloride] <= 50)\n", + " solver.Add(3 * production[Gas] + 4 * production[Chloride] <= 180)\n", "\n", - "# objective\n", - "objective = solver.Maximize(40 * production[Gas] + 50 * production[Chloride])\n", + " # objective\n", + " objective = solver.Maximize(40 * production[Gas] + 50 * production[Chloride])\n", "\n", - "print('NumConstraints:', solver.NumConstraints())\n", + " print('NumConstraints:', solver.NumConstraints())\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('objective = ', solver.Objective().Value())\n", - "for i in range(num_products):\n", - " print(products[i], '=', production[i].SolutionValue(), end=' ')\n", - " print('ReducedCost = ', production[i].ReducedCost())\n", + " print()\n", + " print('objective = ', solver.Objective().Value())\n", + " for i in range(num_products):\n", + " print(products[i], '=', production[i].SolutionValue(), end=' ')\n", + " print('ReducedCost = ', production[i].ReducedCost())\n", + "\n", + "\n", + "main('Volsay')\n", "\n" ] } diff --git a/examples/notebook/contrib/volsay3.ipynb b/examples/notebook/contrib/volsay3.ipynb index 1cdd39324f..32547c283f 100644 --- a/examples/notebook/contrib/volsay3.ipynb +++ b/examples/notebook/contrib/volsay3.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2011 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Volsay problem in Google or-tools.\n", "\n", @@ -96,69 +81,81 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.linear_solver import pywraplp\n", "\n", "\n", + "def main(unused_argv):\n", "\n", - "# Create the solver.\n", + " # Create the solver.\n", "\n", - "# using GLPK\n", - "# solver = pywraplp.Solver('CoinsGridGLPK',\n", - "# pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", + " # using GLPK\n", + " # solver = pywraplp.Solver('CoinsGridGLPK',\n", + " # pywraplp.Solver.GLPK_LINEAR_PROGRAMMING)\n", "\n", - "# Using CLP\n", - "solver = pywraplp.Solver('CoinsGridCLP',\n", - " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", + " # Using CLP\n", + " solver = pywraplp.Solver('CoinsGridCLP',\n", + " pywraplp.Solver.CLP_LINEAR_PROGRAMMING)\n", "\n", - "# data\n", - "num_products = 2\n", + " # data\n", + " num_products = 2\n", "\n", - "products = ['Gas', 'Chloride']\n", - "components = ['nitrogen', 'hydrogen', 'chlorine']\n", + " products = ['Gas', 'Chloride']\n", + " components = ['nitrogen', 'hydrogen', 'chlorine']\n", "\n", - "demand = [[1, 3, 0], [1, 4, 1]]\n", - "profit = [30, 40]\n", - "stock = [50, 180, 40]\n", + " demand = [[1, 3, 0], [1, 4, 1]]\n", + " profit = [30, 40]\n", + " stock = [50, 180, 40]\n", "\n", - "# declare variables\n", - "production = [\n", - " solver.NumVar(0, 100000, 'production[%i]' % i)\n", - " for i in range(num_products)\n", - "]\n", + " # declare variables\n", + " production = [\n", + " solver.NumVar(0, 100000, 'production[%i]' % i)\n", + " for i in range(num_products)\n", + " ]\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "for c in range(len(components)):\n", - " solver.Add(\n", - " solver.Sum([demand[p][c] * production[p]\n", - " for p in range(len(products))]) <= stock[c])\n", + " #\n", + " # constraints\n", + " #\n", + " for c in range(len(components)):\n", + " solver.Add(\n", + " solver.Sum([demand[p][c] * production[p]\n", + " for p in range(len(products))]) <= stock[c])\n", "\n", - "# objective\n", - "# Note: there is no support for solver.ScalProd in the LP/IP interface\n", - "objective = solver.Maximize(\n", - " solver.Sum([production[p] * profit[p] for p in range(num_products)]))\n", + " # objective\n", + " # Note: there is no support for solver.ScalProd in the LP/IP interface\n", + " objective = solver.Maximize(\n", + " solver.Sum([production[p] * profit[p] for p in range(num_products)]))\n", "\n", - "print('NumConstraints:', solver.NumConstraints())\n", - "print('NumVariables:', solver.NumVariables())\n", - "print()\n", + " print('NumConstraints:', solver.NumConstraints())\n", + " print('NumVariables:', solver.NumVariables())\n", + " print()\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solver.Solve()\n", + " #\n", + " # solution and search\n", + " #\n", + " solver.Solve()\n", "\n", - "print()\n", - "print('objective = ', solver.Objective().Value())\n", - "for i in range(num_products):\n", - " print(products[i], '=', production[i].SolutionValue(), end=' ')\n", - " print('ReducedCost = ', production[i].ReducedCost())\n", + " print()\n", + " print('objective = ', solver.Objective().Value())\n", + " for i in range(num_products):\n", + " print(products[i], '=', production[i].SolutionValue(), end=' ')\n", + " print('ReducedCost = ', production[i].ReducedCost())\n", "\n", - "print()\n", - "print('walltime :', solver.WallTime(), 'ms')\n", - "print('iterations:', solver.Iterations())\n", + " print()\n", + " print('walltime :', solver.WallTime(), 'ms')\n", + " print('iterations:', solver.Iterations())\n", + "\n", + "\n", + "main('Volsay')\n", "\n" ] } diff --git a/examples/notebook/contrib/wedding_optimal_chart.ipynb b/examples/notebook/contrib/wedding_optimal_chart.ipynb index 6a1bba0747..ffe01d105f 100644 --- a/examples/notebook/contrib/wedding_optimal_chart.ipynb +++ b/examples/notebook/contrib/wedding_optimal_chart.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -116,120 +116,124 @@ "\"\"\"\n", "\n", "\n", - "# Instantiate a CP solver.\n", - "parameters = pywrapcp.Solver.DefaultSolverParameters()\n", - "solver = pywrapcp.Solver(\"WeddingOptimalChart\", parameters)\n", + "def main():\n", + " # Instantiate a CP solver.\n", + " parameters = pywrapcp.Solver.DefaultSolverParameters()\n", + " solver = pywrapcp.Solver(\"WeddingOptimalChart\", parameters)\n", "\n", - "#\n", - "# Data\n", - "#\n", + " #\n", + " # Data\n", + " #\n", "\n", - "# Easy problem (from the paper)\n", - "# n = 2 # number of tables\n", - "# a = 10 # maximum number of guests a table can seat\n", - "# b = 1 # minimum number of people each guest knows at their table\n", + " # Easy problem (from the paper)\n", + " # n = 2 # number of tables\n", + " # a = 10 # maximum number of guests a table can seat\n", + " # b = 1 # minimum number of people each guest knows at their table\n", "\n", - "# Slightly harder problem (also from the paper)\n", - "n = 5 # number of tables\n", - "a = 4 # maximum number of guests a table can seat\n", - "b = 1 # minimum number of people each guest knows at their table\n", + " # Slightly harder problem (also from the paper)\n", + " n = 5 # number of tables\n", + " a = 4 # maximum number of guests a table can seat\n", + " b = 1 # minimum number of people each guest knows at their table\n", "\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, 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", + " # 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, 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", - " \"Deb (B)\", \"John (B)\", \"Martha (B)\", \"Travis (B)\", \"Allan (B)\",\n", - " \"Lois (B)\", \"Jayne (B)\", \"Brad (B)\", \"Abby (B)\", \"Mary Helen (G)\",\n", - " \"Lee (G)\", \"Annika (G)\", \"Carl (G)\", \"Colin (G)\", \"Shirley (G)\",\n", - " \"DeAnn (G)\", \"Lori (G)\"\n", - "]\n", + " # Names of the guests. B: Bride side, G: Groom side\n", + " names = [\n", + " \"Deb (B)\", \"John (B)\", \"Martha (B)\", \"Travis (B)\", \"Allan (B)\",\n", + " \"Lois (B)\", \"Jayne (B)\", \"Brad (B)\", \"Abby (B)\", \"Mary Helen (G)\",\n", + " \"Lee (G)\", \"Annika (G)\", \"Carl (G)\", \"Colin (G)\", \"Shirley (G)\",\n", + " \"DeAnn (G)\", \"Lori (G)\"\n", + " ]\n", "\n", - "m = len(C)\n", + " m = len(C)\n", "\n", - "NRANGE = range(n)\n", - "MRANGE = range(m)\n", + " NRANGE = range(n)\n", + " MRANGE = range(m)\n", "\n", - "#\n", - "# Decision variables\n", - "#\n", - "tables = [solver.IntVar(0, n - 1, \"x[%i]\" % i) for i in MRANGE]\n", + " #\n", + " # Decision variables\n", + " #\n", + " tables = [solver.IntVar(0, n - 1, \"x[%i]\" % i) for i in MRANGE]\n", "\n", - "z = solver.Sum([\n", - " C[j][k] * (tables[j] == tables[k])\n", - " for j in MRANGE\n", - " for k in MRANGE\n", - " if j < k\n", - "])\n", - "\n", - "#\n", - "# Constraints\n", - "#\n", - "for i in NRANGE:\n", - " minGuests = [(tables[j] == i) * (tables[k] == i)\n", - " for j in MRANGE\n", - " for k in MRANGE\n", - " if j < k and C[j][k] > 0]\n", - " solver.Add(solver.Sum(minGuests) >= b)\n", - "\n", - " maxGuests = [tables[j] == i for j in MRANGE]\n", - " solver.Add(solver.Sum(maxGuests) <= a)\n", - "\n", - "# Symmetry breaking\n", - "solver.Add(tables[0] == 0)\n", - "\n", - "#\n", - "# Objective\n", - "#\n", - "objective = solver.Maximize(z, 1)\n", - "\n", - "#\n", - "# Search\n", - "#\n", - "db = solver.Phase(tables, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", - "\n", - "solver.NewSearch(db, [objective])\n", - "\n", - "while solver.NextSolution():\n", - " print(\"z:\", z)\n", - " print(\"Table: \")\n", - " for j in MRANGE:\n", - " print(tables[j].Value(), \" \")\n", - " print()\n", + " z = solver.Sum([\n", + " C[j][k] * (tables[j] == tables[k])\n", + " for j in MRANGE\n", + " for k in MRANGE\n", + " if j < k\n", + " ])\n", "\n", + " #\n", + " # Constraints\n", + " #\n", " for i in NRANGE:\n", - " print(\"Table %d: \" % i)\n", + " minGuests = [(tables[j] == i) * (tables[k] == i)\n", + " for j in MRANGE\n", + " for k in MRANGE\n", + " if j < k and C[j][k] > 0]\n", + " solver.Add(solver.Sum(minGuests) >= b)\n", + "\n", + " maxGuests = [tables[j] == i for j in MRANGE]\n", + " solver.Add(solver.Sum(maxGuests) <= a)\n", + "\n", + " # Symmetry breaking\n", + " solver.Add(tables[0] == 0)\n", + "\n", + " #\n", + " # Objective\n", + " #\n", + " objective = solver.Maximize(z, 1)\n", + "\n", + " #\n", + " # Search\n", + " #\n", + " db = solver.Phase(tables, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)\n", + "\n", + " solver.NewSearch(db, [objective])\n", + "\n", + " while solver.NextSolution():\n", + " print(\"z:\", z)\n", + " print(\"Table: \")\n", " for j in MRANGE:\n", - " if tables[j].Value() == i:\n", - " print(names[j] + \" \")\n", + " print(tables[j].Value(), \" \")\n", " print()\n", "\n", + " for i in NRANGE:\n", + " print(\"Table %d: \" % i)\n", + " for j in MRANGE:\n", + " if tables[j].Value() == i:\n", + " print(names[j] + \" \")\n", + " print()\n", + "\n", + " print()\n", + "\n", + " solver.EndSearch()\n", + "\n", " print()\n", + " print(\"Solutions: %d\" % solver.Solutions())\n", + " print(\"WallTime: %dms\" % solver.WallTime())\n", + " print(\"Failures: %d\" % solver.Failures())\n", + " print(\"Branches: %d\" % solver.Branches())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"Solutions: %d\" % solver.Solutions())\n", - "print(\"WallTime: %dms\" % solver.WallTime())\n", - "print(\"Failures: %d\" % solver.Failures())\n", - "print(\"Branches: %d\" % solver.Branches())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/who_killed_agatha.ipynb b/examples/notebook/contrib/who_killed_agatha.ipynb index 9cafce584c..ba4ee50b00 100644 --- a/examples/notebook/contrib/who_killed_agatha.ipynb +++ b/examples/notebook/contrib/who_killed_agatha.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Who killed agatha? (The Dreadsbury Mansion Murder Mystery) in Google CP\n", " Solver.\n", @@ -133,8 +118,16 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from collections import defaultdict\n", "\n", "from ortools.constraint_solver import pywrapcp\n", @@ -162,123 +155,131 @@ " print()\n", "\n", "\n", + "def main(the_killers):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Who killed agatha?\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Who killed agatha?\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "n = 3\n", - "agatha = 0\n", - "butler = 1\n", - "charles = 2\n", + " #\n", + " # data\n", + " #\n", + " n = 3\n", + " agatha = 0\n", + " butler = 1\n", + " charles = 2\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "the_killer = solver.IntVar(0, 2, \"the_killer\")\n", - "the_victim = solver.IntVar(0, 2, \"the_victim\")\n", + " #\n", + " # declare variables\n", + " #\n", + " the_killer = solver.IntVar(0, 2, \"the_killer\")\n", + " the_victim = solver.IntVar(0, 2, \"the_victim\")\n", "\n", - "hates = var_matrix_array(solver, n, n, 0, 1, \"hates\")\n", - "richer = var_matrix_array(solver, n, n, 0, 1, \"richer\")\n", + " hates = var_matrix_array(solver, n, n, 0, 1, \"hates\")\n", + " richer = var_matrix_array(solver, n, n, 0, 1, \"richer\")\n", "\n", - "hates_flat = flatten_matrix(solver, hates, n, n)\n", - "richer_flat = flatten_matrix(solver, richer, n, n)\n", + " hates_flat = flatten_matrix(solver, hates, n, n)\n", + " richer_flat = flatten_matrix(solver, richer, n, n)\n", "\n", - "#\n", - "# constraints\n", - "#\n", + " #\n", + " # constraints\n", + " #\n", "\n", - "# Agatha, the butler, and Charles live in Dreadsbury Mansion, and\n", - "# are the only ones to live there.\n", + " # Agatha, the butler, and Charles live in Dreadsbury Mansion, and\n", + " # are the only ones to live there.\n", "\n", - "# A killer always hates, and is no richer than his victim.\n", - "# solver.Add(hates[the_killer, the_victim] == 1)\n", - "solver.Add(solver.Element(hates_flat, the_killer * n + the_victim) == 1)\n", + " # A killer always hates, and is no richer than his victim.\n", + " # solver.Add(hates[the_killer, the_victim] == 1)\n", + " solver.Add(solver.Element(hates_flat, the_killer * n + the_victim) == 1)\n", "\n", - "# solver.Add(richer[the_killer, the_victim] == 0)\n", - "solver.Add(solver.Element(richer_flat, the_killer * n + the_victim) == 0)\n", + " # solver.Add(richer[the_killer, the_victim] == 0)\n", + " solver.Add(solver.Element(richer_flat, the_killer * n + the_victim) == 0)\n", "\n", - "# define the concept of richer: no one is richer than him-/herself\n", - "for i in range(n):\n", - " solver.Add(richer[i][i] == 0)\n", + " # define the concept of richer: no one is richer than him-/herself\n", + " for i in range(n):\n", + " solver.Add(richer[i][i] == 0)\n", "\n", - "# (contd...) if i is richer than j then j is not richer than i\n", - "# (i != j) => (richer[i,j] = 1) <=> (richer[j,i] = 0),\n", - "for i in range(n):\n", - " for j in range(n):\n", - " if i != j:\n", - " solver.Add((richer[i][j] == 1) == (richer[j][i] == 0))\n", + " # (contd...) if i is richer than j then j is not richer than i\n", + " # (i != j) => (richer[i,j] = 1) <=> (richer[j,i] = 0),\n", + " for i in range(n):\n", + " for j in range(n):\n", + " if i != j:\n", + " solver.Add((richer[i][j] == 1) == (richer[j][i] == 0))\n", "\n", - "# Charles hates noone that Agatha hates.\n", - "# forall i : Range .\n", - "# (hates[agatha, i] = 1) => (hates[charles, i] = 0),\n", - "for i in range(n):\n", - " solver.Add((hates[agatha][i] == 1) <= (hates[charles][i] == 0))\n", + " # Charles hates noone that Agatha hates.\n", + " # forall i : Range .\n", + " # (hates[agatha, i] = 1) => (hates[charles, i] = 0),\n", + " for i in range(n):\n", + " solver.Add((hates[agatha][i] == 1) <= (hates[charles][i] == 0))\n", "\n", - "# Agatha hates everybody except the butler.\n", - "solver.Add(hates[agatha][charles] == 1)\n", - "solver.Add(hates[agatha][agatha] == 1)\n", - "solver.Add(hates[agatha][butler] == 0)\n", + " # Agatha hates everybody except the butler.\n", + " solver.Add(hates[agatha][charles] == 1)\n", + " solver.Add(hates[agatha][agatha] == 1)\n", + " solver.Add(hates[agatha][butler] == 0)\n", "\n", - "# The butler hates everyone not richer than Aunt Agatha.\n", - "# forall i : Range .\n", - "# (richer[i, agatha] = 0) => (hates[butler, i] = 1),\n", - "for i in range(n):\n", - " solver.Add((richer[i][agatha] == 0) <= (hates[butler][i] == 1))\n", + " # The butler hates everyone not richer than Aunt Agatha.\n", + " # forall i : Range .\n", + " # (richer[i, agatha] = 0) => (hates[butler, i] = 1),\n", + " for i in range(n):\n", + " solver.Add((richer[i][agatha] == 0) <= (hates[butler][i] == 1))\n", "\n", - "# The butler hates everyone whom Agatha hates.\n", - "# forall i : Range .\n", - "# (hates[agatha, i] = 1) => (hates[butler, i] = 1),\n", - "for i in range(n):\n", - " solver.Add((hates[agatha][i] == 1) <= (hates[butler][i] == 1))\n", + " # The butler hates everyone whom Agatha hates.\n", + " # forall i : Range .\n", + " # (hates[agatha, i] = 1) => (hates[butler, i] = 1),\n", + " for i in range(n):\n", + " solver.Add((hates[agatha][i] == 1) <= (hates[butler][i] == 1))\n", "\n", - "# Noone hates everyone.\n", - "# forall i : Range .\n", - "# (sum j : Range . hates[i,j]) <= 2,\n", - "for i in range(n):\n", - " solver.Add(solver.Sum([hates[i][j] for j in range(n)]) <= 2)\n", + " # Noone hates everyone.\n", + " # forall i : Range .\n", + " # (sum j : Range . hates[i,j]) <= 2,\n", + " for i in range(n):\n", + " solver.Add(solver.Sum([hates[i][j] for j in range(n)]) <= 2)\n", "\n", - "# Who killed Agatha?\n", - "solver.Add(the_victim == agatha)\n", + " # Who killed Agatha?\n", + " solver.Add(the_victim == agatha)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(the_killer)\n", - "solution.Add(the_victim)\n", - "solution.Add(hates_flat)\n", - "solution.Add(richer_flat)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(the_killer)\n", + " solution.Add(the_victim)\n", + " solution.Add(hates_flat)\n", + " solution.Add(richer_flat)\n", "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(hates_flat + richer_flat, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(hates_flat + richer_flat, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"the_killer:\", the_killer.Value())\n", + " the_killers[the_killer.Value()] += 1\n", + " print(\"the_victim:\", the_victim.Value())\n", + " print(\"hates:\")\n", + " print_flat_matrix(hates_flat, n, n)\n", + " print(\"richer:\")\n", + " print_flat_matrix(richer_flat, n, n)\n", + " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"the_killer:\", the_killer.Value())\n", - " the_killers[the_killer.Value()] += 1\n", - " print(\"the_victim:\", the_victim.Value())\n", - " print(\"hates:\")\n", - " print_flat_matrix(hates_flat, n, n)\n", - " print(\"richer:\")\n", - " print_flat_matrix(richer_flat, n, n)\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", - "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", "\n", "the_killers = defaultdict(int)\n", - "p = [\"agatha\", \"butler\", \"charles\"]\n" + "p = [\"agatha\", \"butler\", \"charles\"]\n", + "main(the_killers)\n", + "\n", + "print(\"\\n\")\n", + "for k in the_killers:\n", + " print(\"the killer %s was choosen in %i solutions\" % (p[k], the_killers[k]))\n", + "\n" ] } ], diff --git a/examples/notebook/contrib/xkcd.ipynb b/examples/notebook/contrib/xkcd.ipynb index 72b06258b3..6028034178 100644 --- a/examples/notebook/contrib/xkcd.ipynb +++ b/examples/notebook/contrib/xkcd.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " xkcd problem (Knapsack) in Google CP Solver.\n", "\n", @@ -110,74 +95,86 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_cp_solver/\n", - "\"\"\"\n", + " http://www.hakank.org/google_cp_solver/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main():\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"xkcd knapsack\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"xkcd knapsack\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "num_prices = 6\n", - "# for price and total: multiplied by 100 to be able to use integers\n", - "price = [215, 275, 335, 355, 420, 580]\n", - "total = 1505\n", + " #\n", + " # data\n", + " #\n", + " num_prices = 6\n", + " # for price and total: multiplied by 100 to be able to use integers\n", + " price = [215, 275, 335, 355, 420, 580]\n", + " total = 1505\n", "\n", - "products = [\n", - " \"mixed fruit\", \"french fries\", \"side salad\", \"host wings\",\n", - " \"mozzarella sticks\", \"samples place\"\n", - "]\n", + " products = [\n", + " \"mixed fruit\", \"french fries\", \"side salad\", \"host wings\",\n", + " \"mozzarella sticks\", \"samples place\"\n", + " ]\n", "\n", - "# declare variables\n", + " # declare variables\n", "\n", - "# how many items of each dish\n", - "x = [solver.IntVar(0, 10, \"x%i\" % i) for i in range(num_prices)]\n", - "z = solver.IntVar(0, 1505, \"z\")\n", + " # how many items of each dish\n", + " x = [solver.IntVar(0, 10, \"x%i\" % i) for i in range(num_prices)]\n", + " z = solver.IntVar(0, 1505, \"z\")\n", "\n", - "#\n", - "# constraints\n", - "#\n", - "solver.Add(z == solver.Sum([x[i] * price[i] for i in range(num_prices)]))\n", - "solver.Add(z == total)\n", + " #\n", + " # constraints\n", + " #\n", + " solver.Add(z == solver.Sum([x[i] * price[i] for i in range(num_prices)]))\n", + " solver.Add(z == total)\n", "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add([x[i] for i in range(num_prices)])\n", - "solution.Add(z)\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add([x[i] for i in range(num_prices)])\n", + " solution.Add(z)\n", "\n", - "collector = solver.AllSolutionCollector(solution)\n", - "# collector = solver.FirstSolutionCollector(solution)\n", - "# search_log = solver.SearchLog(100, x[0])\n", - "solver.Solve(\n", - " solver.Phase([x[i] for i in range(num_prices)], solver.INT_VAR_SIMPLE,\n", - " solver.ASSIGN_MIN_VALUE), [collector])\n", + " collector = solver.AllSolutionCollector(solution)\n", + " # collector = solver.FirstSolutionCollector(solution)\n", + " # search_log = solver.SearchLog(100, x[0])\n", + " solver.Solve(\n", + " solver.Phase([x[i] for i in range(num_prices)], solver.INT_VAR_SIMPLE,\n", + " solver.ASSIGN_MIN_VALUE), [collector])\n", + "\n", + " num_solutions = collector.SolutionCount()\n", + " print(\"num_solutions: \", num_solutions)\n", + " if num_solutions > 0:\n", + " for s in range(num_solutions):\n", + " print(\"z:\", collector.Value(s, z) / 100.0)\n", + " xval = [collector.Value(s, x[i]) for i in range(num_prices)]\n", + " print(\"x:\", xval)\n", + " for i in range(num_prices):\n", + " if xval[i] > 0:\n", + " print(xval[i], \"of\", products[i], \":\", price[i] / 100.0)\n", + " print()\n", "\n", - "num_solutions = collector.SolutionCount()\n", - "print(\"num_solutions: \", num_solutions)\n", - "if num_solutions > 0:\n", - " for s in range(num_solutions):\n", - " print(\"z:\", collector.Value(s, z) / 100.0)\n", - " xval = [collector.Value(s, x[i]) for i in range(num_prices)]\n", - " print(\"x:\", xval)\n", - " for i in range(num_prices):\n", - " if xval[i] > 0:\n", - " print(xval[i], \"of\", products[i], \":\", price[i] / 100.0)\n", " print()\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - " print()\n", - " print(\"num_solutions:\", num_solutions)\n", - " print(\"failures:\", solver.Failures())\n", - " print(\"branches:\", solver.Branches())\n", - " print(\"WallTime:\", solver.WallTime())\n", + " else:\n", + " print(\"No solutions found\")\n", "\n", - "else:\n", - " print(\"No solutions found\")\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/contrib/young_tableaux.ipynb b/examples/notebook/contrib/young_tableaux.ipynb index ac31319f1a..fc727d4abe 100644 --- a/examples/notebook/contrib/young_tableaux.ipynb +++ b/examples/notebook/contrib/young_tableaux.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com\n", - "#\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", + "\n", "\n", " Young tableaux in Google CP Solver.\n", "\n", @@ -134,102 +119,117 @@ "\n", " This model was created by Hakan Kjellerstrand (hakank@gmail.com)\n", " Also see my other Google CP Solver models:\n", - " http://www.hakank.org/google_or_tools/\n", - "\"\"\"\n", + " http://www.hakank.org/google_or_tools/\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import sys\n", "from ortools.constraint_solver import pywrapcp\n", "\n", "\n", + "def main(n=5):\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver(\"Problem\")\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver(\"Problem\")\n", "\n", - "#\n", - "# data\n", - "#\n", - "print(\"n:\", n)\n", + " #\n", + " # data\n", + " #\n", + " print(\"n:\", n)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = {}\n", - "for i in range(n):\n", - " for j in range(n):\n", - " x[(i, j)] = solver.IntVar(1, n + 1, \"x(%i,%i)\" % (i, j))\n", - "\n", - "x_flat = [x[(i, j)] for i in range(n) for j in range(n)]\n", - "\n", - "# partition structure\n", - "p = [solver.IntVar(0, n + 1, \"p%i\" % i) for i in range(n)]\n", - "\n", - "#\n", - "# constraints\n", - "#\n", - "\n", - "# 1..n is used exactly once\n", - "for i in range(1, n + 1):\n", - " solver.Add(solver.Count(x_flat, i, 1))\n", - "\n", - "solver.Add(x[(0, 0)] == 1)\n", - "\n", - "# row wise\n", - "for i in range(n):\n", - " for j in range(1, n):\n", - " solver.Add(x[(i, j)] >= x[(i, j - 1)])\n", - "\n", - "# column wise\n", - "for j in range(n):\n", - " for i in range(1, n):\n", - " solver.Add(x[(i, j)] >= x[(i - 1, j)])\n", - "\n", - "# calculate the structure (the partition)\n", - "for i in range(n):\n", - " # MiniZinc/Zinc version:\n", - " # p[i] == sum(j in 1..n) (bool2int(x[i,j] <= n))\n", - "\n", - " b = [solver.IsLessOrEqualCstVar(x[(i, j)], n) for j in range(n)]\n", - " solver.Add(p[i] == solver.Sum(b))\n", - "\n", - "solver.Add(solver.Sum(p) == n)\n", - "\n", - "for i in range(1, n):\n", - " solver.Add(p[i - 1] >= p[i])\n", - "\n", - "#\n", - "# solution and search\n", - "#\n", - "solution = solver.Assignment()\n", - "solution.Add(x_flat)\n", - "solution.Add(p)\n", - "\n", - "# db: DecisionBuilder\n", - "db = solver.Phase(x_flat + p, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE)\n", - "\n", - "solver.NewSearch(db)\n", - "num_solutions = 0\n", - "while solver.NextSolution():\n", - " print(\"p:\", [p[i].Value() for i in range(n)])\n", - " print(\"x:\")\n", + " #\n", + " # declare variables\n", + " #\n", + " x = {}\n", " for i in range(n):\n", " for j in range(n):\n", - " val = x_flat[i * n + j].Value()\n", - " if val <= n:\n", - " print(val, end=\" \")\n", - " if p[i].Value() > 0:\n", - " print()\n", + " x[(i, j)] = solver.IntVar(1, n + 1, \"x(%i,%i)\" % (i, j))\n", + "\n", + " x_flat = [x[(i, j)] for i in range(n) for j in range(n)]\n", + "\n", + " # partition structure\n", + " p = [solver.IntVar(0, n + 1, \"p%i\" % i) for i in range(n)]\n", + "\n", + " #\n", + " # constraints\n", + " #\n", + "\n", + " # 1..n is used exactly once\n", + " for i in range(1, n + 1):\n", + " solver.Add(solver.Count(x_flat, i, 1))\n", + "\n", + " solver.Add(x[(0, 0)] == 1)\n", + "\n", + " # row wise\n", + " for i in range(n):\n", + " for j in range(1, n):\n", + " solver.Add(x[(i, j)] >= x[(i, j - 1)])\n", + "\n", + " # column wise\n", + " for j in range(n):\n", + " for i in range(1, n):\n", + " solver.Add(x[(i, j)] >= x[(i - 1, j)])\n", + "\n", + " # calculate the structure (the partition)\n", + " for i in range(n):\n", + " # MiniZinc/Zinc version:\n", + " # p[i] == sum(j in 1..n) (bool2int(x[i,j] <= n))\n", + "\n", + " b = [solver.IsLessOrEqualCstVar(x[(i, j)], n) for j in range(n)]\n", + " solver.Add(p[i] == solver.Sum(b))\n", + "\n", + " solver.Add(solver.Sum(p) == n)\n", + "\n", + " for i in range(1, n):\n", + " solver.Add(p[i - 1] >= p[i])\n", + "\n", + " #\n", + " # solution and search\n", + " #\n", + " solution = solver.Assignment()\n", + " solution.Add(x_flat)\n", + " solution.Add(p)\n", + "\n", + " # db: DecisionBuilder\n", + " db = solver.Phase(x_flat + p, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE)\n", + "\n", + " solver.NewSearch(db)\n", + " num_solutions = 0\n", + " while solver.NextSolution():\n", + " print(\"p:\", [p[i].Value() for i in range(n)])\n", + " print(\"x:\")\n", + " for i in range(n):\n", + " for j in range(n):\n", + " val = x_flat[i * n + j].Value()\n", + " if val <= n:\n", + " print(val, end=\" \")\n", + " if p[i].Value() > 0:\n", + " print()\n", + " print()\n", + " num_solutions += 1\n", + "\n", + " solver.EndSearch()\n", + "\n", " print()\n", - " num_solutions += 1\n", + " print(\"num_solutions:\", num_solutions)\n", + " print(\"failures:\", solver.Failures())\n", + " print(\"branches:\", solver.Branches())\n", + " print(\"WallTime:\", solver.WallTime())\n", "\n", - "solver.EndSearch()\n", "\n", - "print()\n", - "print(\"num_solutions:\", num_solutions)\n", - "print(\"failures:\", solver.Failures())\n", - "print(\"branches:\", solver.Branches())\n", - "print(\"WallTime:\", solver.WallTime())\n", + "n = 5\n", + "if len(sys.argv) > 1:\n", + " n = int(sys.argv[1])\n", "\n", - "n = 5\n" + "main(n)\n", + "\n" ] } ], diff --git a/examples/notebook/examples/appointments.ipynb b/examples/notebook/examples/appointments.ipynb index e3228e2ceb..52ff4c2628 100644 --- a/examples/notebook/examples/appointments.ipynb +++ b/examples/notebook/examples/appointments.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,20 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Appointment selection.\n", + "\n", + "This module maximizes the number of appointments that can\n", + "be fulfilled by a crew of installers while staying close to ideal\n", + "ratio of appointment types.\n", + "\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,40 +88,15 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Appointment selection.\n", - "\n", - "This module maximizes the number of appointments that can\n", - "be fulfilled by a crew of installers while staying close to ideal\n", - "ratio of appointment types.\n", - "\"\"\"\n", - "\n", - "# overloaded sum() clashes with pytype.\n", - "# pytype: disable=wrong-arg-types\n", - "\n", - "from absl import app\n", - "from absl import flags\n", "from ortools.linear_solver import pywraplp\n", "from ortools.sat.python import cp_model\n", "\n", - "FLAGS = flags.FLAGS\n", - "flags.DEFINE_integer('load_min', 480, 'Minimum load in minutes.')\n", - "flags.DEFINE_integer('load_max', 540, 'Maximum load in minutes.')\n", - "flags.DEFINE_integer('commute_time', 30, 'Commute time in minutes.')\n", - "flags.DEFINE_integer('num_workers', 98, 'Maximum number of workers.')\n", + "class FLAGS: pass\n", "\n", + "FLAGS.load_min = 480 # Minimum load in minutes.\n", + "FLAGS.load_max = 540 # Maximum load in minutes.\n", + "FLAGS.commute_time = 30 # Commute time in minutes.\n", + "FLAGS.num_workers = 98 # Maximum number of workers.\n", "\n", "class AllSolutionCollector(cp_model.CpSolverSolutionCallback):\n", " \"\"\"Stores all solutions.\"\"\"\n", @@ -280,39 +269,43 @@ " return output\n", "\n", "\n", - "demand = [(45.0, 'Type1', 90), (30.0, 'Type2', 120), (25.0, 'Type3', 180)]\n", - "print('*** input problem ***')\n", - "print('Appointments: ')\n", - "for a in demand:\n", - " print(' %.2f%% of %s : %d min' % (a[0], a[1], a[2]))\n", - "print('Commute time = %d' % FLAGS.commute_time)\n", - "print('Acceptable duration of a work day = [%d..%d]' %\n", - " (FLAGS.load_min, FLAGS.load_max))\n", - "print('%d workers' % FLAGS.num_workers)\n", - "selection = GetOptimalSchedule(demand)\n", - "print()\n", - "installed = 0\n", - "installed_per_type = {}\n", - "for a in demand:\n", - " installed_per_type[a[1]] = 0\n", + "def solve_appointments(_):\n", + " demand = [(45.0, 'Type1', 90), (30.0, 'Type2', 120), (25.0, 'Type3', 180)]\n", + " print('*** input problem ***')\n", + " print('Appointments: ')\n", + " for a in demand:\n", + " print(' %.2f%% of %s : %d min' % (a[0], a[1], a[2]))\n", + " print('Commute time = %d' % FLAGS.commute_time)\n", + " print('Acceptable duration of a work day = [%d..%d]' %\n", + " (FLAGS.load_min, FLAGS.load_max))\n", + " print('%d workers' % FLAGS.num_workers)\n", + " selection = GetOptimalSchedule(demand)\n", + " print()\n", + " installed = 0\n", + " installed_per_type = {}\n", + " for a in demand:\n", + " installed_per_type[a[1]] = 0\n", "\n", - "print('*** output solution ***')\n", - "for template in selection:\n", - " num_instances = template[0]\n", - " print('%d schedules with ' % num_instances)\n", - " for t in template[1]:\n", - " mult = t[0]\n", - " print(' %d installation of type %s' % (mult, t[1]))\n", - " installed += num_instances * mult\n", - " installed_per_type[t[1]] += num_instances * mult\n", + " print('*** output solution ***')\n", + " for template in selection:\n", + " num_instances = template[0]\n", + " print('%d schedules with ' % num_instances)\n", + " for t in template[1]:\n", + " mult = t[0]\n", + " print(' %d installation of type %s' % (mult, t[1]))\n", + " installed += num_instances * mult\n", + " installed_per_type[t[1]] += num_instances * mult\n", "\n", - "print()\n", - "print('%d installations planned' % installed)\n", - "for a in demand:\n", - " name = a[1]\n", - " per_type = installed_per_type[name]\n", - " print((' %d (%.2f%%) installations of type %s planned' %\n", - " (per_type, per_type * 100.0 / installed, name)))\n", + " print()\n", + " print('%d installations planned' % installed)\n", + " for a in demand:\n", + " name = a[1]\n", + " per_type = installed_per_type[name]\n", + " print((' %d (%.2f%%) installations of type %s planned' %\n", + " (per_type, per_type * 100.0 / installed, name)))\n", + "\n", + "\n", + "solve_appointments()\n", "\n" ] } diff --git a/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb b/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb index f1a8651cae..e81fb85396 100644 --- a/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb +++ b/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Cutting stock problem with the objective to minimize wasted space.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +83,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Cutting stock problem with the objective to minimize wasted space.\"\"\"\n", - "\n", - "\n", "import argparse\n", "import collections\n", "import time\n", @@ -338,11 +332,15 @@ " print('No solution')\n", "\n", "\n", - "\"\"\"Main function\"\"\"\n", - "if args.solver == 'sat':\n", - " solve_cutting_stock_with_arc_flow_and_sat(args.output_proto_file)\n", - "else: # 'mip'\n", - " solve_cutting_stock_with_arc_flow_and_mip()\n", + "def main(args):\n", + " \"\"\"Main function\"\"\"\n", + " if args.solver == 'sat':\n", + " solve_cutting_stock_with_arc_flow_and_sat(args.output_proto_file)\n", + " else: # 'mip'\n", + " solve_cutting_stock_with_arc_flow_and_mip()\n", + "\n", + "\n", + "main(PARSER.parse_args())\n", "\n" ] } diff --git a/examples/notebook/examples/assignment2_sat.ipynb b/examples/notebook/examples/assignment2_sat.ipynb index b3f54e1305..4dfc899cdb 100644 --- a/examples/notebook/examples/assignment2_sat.ipynb +++ b/examples/notebook/examples/assignment2_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -90,66 +90,70 @@ "from ortools.sat.python import cp_model\n", "\n", "\n", - "# Instantiate a cp model.\n", - "cost = [[90, 76, 75, 70, 50, 74, 12, 68], [35, 85, 55, 65, 48, 101, 70, 83],\n", - " [125, 95, 90, 105, 59,\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", + "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", + " 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", + " 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", - " if solver.Value(x[i][j]) == 1:\n", - " print('Worker ', i, ' assigned to task ', j, ' Cost = ',\n", - " cost[i][j])\n", + " t.append(model.NewBoolVar('x[%i,%i]' % (i, j)))\n", + " x.append(t)\n", "\n", - " print()\n", + " # Constraints\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", + " # 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" ] } diff --git a/examples/notebook/examples/assignment_with_constraints_sat.ipynb b/examples/notebook/examples/assignment_with_constraints_sat.ipynb index b7f4558b87..21ec3d5abb 100644 --- a/examples/notebook/examples/assignment_with_constraints_sat.ipynb +++ b/examples/notebook/examples/assignment_with_constraints_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve an assignment problem with combination constraints on workers.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +83,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Solve an assignment problem with combination constraints on workers.\"\"\"\n", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/examples/balance_group_sat.ipynb b/examples/notebook/examples/balance_group_sat.ipynb index 47bff70bab..d675f90558 100644 --- a/examples/notebook/examples/balance_group_sat.ipynb +++ b/examples/notebook/examples/balance_group_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,21 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "We are trying to group items in equal sized groups.\n", + "\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", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,27 +89,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"We are trying to group items in equal sized groups.\n", - "\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", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", @@ -136,118 +130,122 @@ " print(']')\n", "\n", "\n", - "# Data.\n", - "num_groups = 10\n", - "num_items = 100\n", - "num_colors = 3\n", - "min_items_of_same_color_per_group = 4\n", + "def main():\n", + " # Data.\n", + " num_groups = 10\n", + " num_items = 100\n", + " num_colors = 3\n", + " min_items_of_same_color_per_group = 4\n", "\n", - "all_groups = range(num_groups)\n", - "all_items = range(num_items)\n", - "all_colors = range(num_colors)\n", + " all_groups = range(num_groups)\n", + " all_items = range(num_items)\n", + " all_colors = range(num_colors)\n", "\n", - "# Values for each items.\n", - "values = [1 + i + (i * i // 200) for i in all_items]\n", - "# Color for each item (simple modulo).\n", - "colors = [i % num_colors for i in all_items]\n", + " # Values for each items.\n", + " values = [1 + i + (i * i // 200) for i in all_items]\n", + " # Color for each item (simple modulo).\n", + " colors = [i % num_colors for i in all_items]\n", "\n", - "sum_of_values = sum(values)\n", - "average_sum_per_group = sum_of_values // num_groups\n", + " sum_of_values = sum(values)\n", + " average_sum_per_group = sum_of_values // num_groups\n", "\n", - "num_items_per_group = num_items // num_groups\n", + " num_items_per_group = num_items // num_groups\n", "\n", - "# Collect all items in a given color.\n", - "items_per_color = {}\n", - "for c in all_colors:\n", - " items_per_color[c] = []\n", - " for i in all_items:\n", - " if colors[i] == c:\n", - " items_per_color[c].append(i)\n", - "\n", - "print('Model has %i items, %i groups, and %i colors' %\n", - " (num_items, num_groups, num_colors))\n", - "print(' average sum per group = %i' % average_sum_per_group)\n", - "\n", - "# Model.\n", - "\n", - "model = cp_model.CpModel()\n", - "\n", - "item_in_group = {}\n", - "for i in all_items:\n", - " for g in all_groups:\n", - " item_in_group[(i, g)] = model.NewBoolVar('item %d in group %d' %\n", - " (i, g))\n", - "\n", - "# Each group must have the same size.\n", - "for g in all_groups:\n", - " model.Add(\n", - " sum(item_in_group[(i, g)]\n", - " for i in all_items) == num_items_per_group)\n", - "\n", - "# One item must belong to exactly one group.\n", - "for i in all_items:\n", - " model.Add(sum(item_in_group[(i, g)] for g in all_groups) == 1)\n", - "\n", - "# The deviation of the sum of each items in a group against the average.\n", - "e = model.NewIntVar(0, 550, 'epsilon')\n", - "\n", - "# Constrain the sum of values in one group around the average sum per group.\n", - "for g in all_groups:\n", - " model.Add(\n", - " sum(item_in_group[(i, g)] * values[i]\n", - " for i in all_items) <= average_sum_per_group + e)\n", - " model.Add(\n", - " sum(item_in_group[(i, g)] * values[i]\n", - " for i in all_items) >= average_sum_per_group - e)\n", - "\n", - "# color_in_group variables.\n", - "color_in_group = {}\n", - "for g in all_groups:\n", + " # Collect all items in a given color.\n", + " items_per_color = {}\n", " for c in all_colors:\n", - " color_in_group[(c, g)] = model.NewBoolVar(\n", - " 'color %d is in group %d' % (c, g))\n", + " items_per_color[c] = []\n", + " for i in all_items:\n", + " if colors[i] == c:\n", + " items_per_color[c].append(i)\n", "\n", - "# Item is in a group implies its color is in that group.\n", - "for i in all_items:\n", - " for g in all_groups:\n", - " model.AddImplication(item_in_group[(i, g)],\n", - " color_in_group[(colors[i], g)])\n", + " print('Model has %i items, %i groups, and %i colors' %\n", + " (num_items, num_groups, num_colors))\n", + " print(' average sum per group = %i' % average_sum_per_group)\n", "\n", - "# If a color is in a group, it must contains at least\n", - "# min_items_of_same_color_per_group items from that color.\n", - "for c in all_colors:\n", - " for g in all_groups:\n", - " literal = color_in_group[(c, g)]\n", - " model.Add(\n", - " sum(item_in_group[(i, g)] for i in items_per_color[c]) >=\n", - " min_items_of_same_color_per_group).OnlyEnforceIf(literal)\n", + " # Model.\n", "\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", - "if max_color < num_colors:\n", + " model = cp_model.CpModel()\n", + "\n", + " item_in_group = {}\n", + " for i in all_items:\n", + " for g in all_groups:\n", + " item_in_group[(i, g)] = model.NewBoolVar('item %d in group %d' %\n", + " (i, g))\n", + "\n", + " # Each group must have the same size.\n", " for g in all_groups:\n", " model.Add(\n", - " sum(color_in_group[(c, g)] for c in all_colors) <= max_color)\n", + " sum(item_in_group[(i, g)]\n", + " for i in all_items) == num_items_per_group)\n", "\n", - "# Minimize epsilon\n", - "model.Minimize(e)\n", + " # One item must belong to exactly one group.\n", + " for i in all_items:\n", + " model.Add(sum(item_in_group[(i, g)] for g in all_groups) == 1)\n", "\n", - "model.ExportToFile('balance_group_sat.pbtxt')\n", + " # The deviation of the sum of each items in a group against the average.\n", + " e = model.NewIntVar(0, 550, 'epsilon')\n", "\n", - "solver = cp_model.CpSolver()\n", - "solution_printer = SolutionPrinter(values, colors, all_groups, all_items,\n", - " item_in_group)\n", - "status = solver.Solve(model, solution_printer)\n", + " # Constrain the sum of values in one group around the average sum per group.\n", + " for g in all_groups:\n", + " model.Add(\n", + " sum(item_in_group[(i, g)] * values[i]\n", + " for i in all_items) <= average_sum_per_group + e)\n", + " model.Add(\n", + " sum(item_in_group[(i, g)] * values[i]\n", + " for i in all_items) >= average_sum_per_group - e)\n", "\n", - "if status == cp_model.OPTIMAL:\n", - " print('Optimal epsilon: %i' % solver.ObjectiveValue())\n", - " print('Statistics')\n", - " print(' - conflicts : %i' % solver.NumConflicts())\n", - " print(' - branches : %i' % solver.NumBranches())\n", - " print(' - wall time : %f s' % solver.WallTime())\n", - "else:\n", - " print('No solution found')\n", + " # color_in_group variables.\n", + " color_in_group = {}\n", + " for g in all_groups:\n", + " for c in all_colors:\n", + " color_in_group[(c, g)] = model.NewBoolVar(\n", + " 'color %d is in group %d' % (c, g))\n", + "\n", + " # Item is in a group implies its color is in that group.\n", + " for i in all_items:\n", + " for g in all_groups:\n", + " model.AddImplication(item_in_group[(i, g)],\n", + " color_in_group[(colors[i], g)])\n", + "\n", + " # If a color is in a group, it must contains at least\n", + " # min_items_of_same_color_per_group items from that color.\n", + " for c in all_colors:\n", + " for g in all_groups:\n", + " literal = color_in_group[(c, g)]\n", + " model.Add(\n", + " sum(item_in_group[(i, g)] for i in items_per_color[c]) >=\n", + " min_items_of_same_color_per_group).OnlyEnforceIf(literal)\n", + "\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", + " if max_color < num_colors:\n", + " for g in all_groups:\n", + " model.Add(\n", + " sum(color_in_group[(c, g)] for c in all_colors) <= max_color)\n", + "\n", + " # Minimize epsilon\n", + " model.Minimize(e)\n", + "\n", + " model.ExportToFile('balance_group_sat.pbtxt')\n", + "\n", + " solver = cp_model.CpSolver()\n", + " solution_printer = SolutionPrinter(values, colors, all_groups, all_items,\n", + " item_in_group)\n", + " status = solver.Solve(model, solution_printer)\n", + "\n", + " if status == cp_model.OPTIMAL:\n", + " print('Optimal epsilon: %i' % solver.ObjectiveValue())\n", + " print('Statistics')\n", + " print(' - conflicts : %i' % solver.NumConflicts())\n", + " print(' - branches : %i' % solver.NumBranches())\n", + " print(' - wall time : %f s' % solver.WallTime())\n", + " else:\n", + " print('No solution found')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/bus_driver_scheduling_flow_sat.ipynb b/examples/notebook/examples/bus_driver_scheduling_flow_sat.ipynb index fd155d9235..b7b3f2e39c 100644 --- a/examples/notebook/examples/bus_driver_scheduling_flow_sat.ipynb +++ b/examples/notebook/examples/bus_driver_scheduling_flow_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,25 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"This model implements a bus driver scheduling problem.\n", + "This model implements a bus driver scheduling problem.\n", "\n", "Constraints:\n", "- max driving time per driver <= 9h\n", @@ -96,8 +82,16 @@ "- 10 min preparation time before the first shift\n", "- 15 min cleaning time after the last shift\n", "- 2 min waiting time after each shift for passenger boarding and alighting\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import argparse\n", "import collections\n", "import math\n", @@ -1881,19 +1875,23 @@ " return optimal_num_drivers\n", "\n", "\n", - "\"\"\"Optimize the bus driver allocation in two passes.\"\"\"\n", - "print('----------- first pass: minimize the number of drivers')\n", - "shifts = []\n", - "if args.instance == 1:\n", - " shifts = SAMPLE_SHIFTS_SMALL\n", - "elif args.instance == 2:\n", - " shifts = SAMPLE_SHIFTS_MEDIUM\n", - "elif args.instance == 3:\n", - " shifts = SAMPLE_SHIFTS_LARGE\n", - "num_drivers = find_minimum_number_of_drivers(shifts, args.params)\n", + "def main(args):\n", + " \"\"\"Optimize the bus driver allocation in two passes.\"\"\"\n", + " print('----------- first pass: minimize the number of drivers')\n", + " shifts = []\n", + " if args.instance == 1:\n", + " shifts = SAMPLE_SHIFTS_SMALL\n", + " elif args.instance == 2:\n", + " shifts = SAMPLE_SHIFTS_MEDIUM\n", + " elif args.instance == 3:\n", + " shifts = SAMPLE_SHIFTS_LARGE\n", + " num_drivers = find_minimum_number_of_drivers(shifts, args.params)\n", "\n", - "print('----------- second pass: minimize the sum of working times')\n", - "#bus_driver_scheduling(False, num_drivers)\n", + " print('----------- second pass: minimize the sum of working times')\n", + " #bus_driver_scheduling(False, num_drivers)\n", + "\n", + "\n", + "main(PARSER.parse_args())\n", "\n" ] } diff --git a/examples/notebook/examples/bus_driver_scheduling_sat.ipynb b/examples/notebook/examples/bus_driver_scheduling_sat.ipynb index 6aec20c939..40c874e338 100644 --- a/examples/notebook/examples/bus_driver_scheduling_sat.ipynb +++ b/examples/notebook/examples/bus_driver_scheduling_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"This model implements a bus driver scheduling problem.\n", + "This model implements a bus driver scheduling problem.\n", "\n", "Constraints:\n", "- max driving time per driver <= 9h\n", @@ -97,24 +82,27 @@ "- 10 min preparation time before the first shift\n", "- 15 min cleaning time after the last shift\n", "- 2 min waiting time after each shift for passenger boarding and alighting\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import collections\n", "import math\n", "\n", - "from absl import app\n", - "from absl import flags\n", "from google.protobuf import text_format\n", "from ortools.sat.python import cp_model\n", "\n", - "FLAGS = flags.FLAGS\n", - "\n", - "flags.DEFINE_string('output_proto', '',\n", - " 'Output file to write the cp_model proto to.')\n", - "flags.DEFINE_string('params', 'num_search_workers:8,log_search_progress:true',\n", - " 'Sat solver parameters.')\n", - "flags.DEFINE_integer('instance', 1, 'Instance to select (1, 2, 3).', 1, 3)\n", + "class FLAGS: pass\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", + "FLAGS.instance = 1 # Instance to select (1, 2, 3).\n", "SAMPLE_SHIFTS_SMALL = [\n", " #\n", " # column description:\n", @@ -2054,14 +2042,22 @@ " return int(solver.ObjectiveValue())\n", "\n", "\n", - "\"\"\"Optimize the bus driver allocation in two passes.\"\"\"\n", - "print('----------- first pass: minimize the number of drivers')\n", - "num_drivers = bus_driver_scheduling(True, -1)\n", - "if num_drivers == -1:\n", - " print('no solution found, skipping the final step')\n", - "else:\n", - " print('----------- second pass: minimize the sum of working times')\n", - " bus_driver_scheduling(False, num_drivers)\n", + "def solve_bus_driver_scheduling():\n", + " \"\"\"Optimize the bus driver allocation in two passes.\"\"\"\n", + " print('----------- first pass: minimize the number of drivers')\n", + " num_drivers = bus_driver_scheduling(True, -1)\n", + " if num_drivers == -1:\n", + " print('no solution found, skipping the final step')\n", + " else:\n", + " print('----------- second pass: minimize the sum of working times')\n", + " bus_driver_scheduling(False, num_drivers)\n", + "\n", + "\n", + "def main(_):\n", + " solve_bus_driver_scheduling()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/chemical_balance_lp.ipynb b/examples/notebook/examples/chemical_balance_lp.ipynb index a70afbd4a1..0247281b82 100644 --- a/examples/notebook/examples/chemical_balance_lp.ipynb +++ b/examples/notebook/examples/chemical_balance_lp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { diff --git a/examples/notebook/examples/chemical_balance_sat.ipynb b/examples/notebook/examples/chemical_balance_sat.ipynb index bd7e6aad1d..7fa3c186d3 100644 --- a/examples/notebook/examples/chemical_balance_sat.ipynb +++ b/examples/notebook/examples/chemical_balance_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { diff --git a/examples/notebook/examples/clustering_sat.ipynb b/examples/notebook/examples/clustering_sat.ipynb index cbd2742b3c..9c78f10a11 100644 --- a/examples/notebook/examples/clustering_sat.ipynb +++ b/examples/notebook/examples/clustering_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Cluster 40 cities in 4 equal groups to minimize sum of crossed distances.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +83,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Cluster 40 cities in 4 equal groups to minimize sum of crossed distances.\"\"\"\n", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", @@ -136,68 +130,72 @@ " ] # yapf: disable\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "num_nodes = len(distance_matrix)\n", - "print('Num nodes =', num_nodes)\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " num_nodes = len(distance_matrix)\n", + " print('Num nodes =', num_nodes)\n", "\n", - "# Number of groups to split the nodes, must divide num_nodes.\n", - "num_groups = 4\n", - "group_size = num_nodes // num_groups\n", + " # Number of groups to split the nodes, must divide num_nodes.\n", + " num_groups = 4\n", + " group_size = num_nodes // num_groups\n", "\n", - "# Model.\n", - "model = cp_model.CpModel()\n", + " # Model.\n", + " model = cp_model.CpModel()\n", "\n", - "# Variables.\n", - "neighbors = {}\n", - "obj_vars = []\n", - "obj_coeffs = []\n", - "for n1 in range(num_nodes - 1):\n", - " for n2 in range(n1 + 1, num_nodes):\n", - " same = model.NewBoolVar('neighbors_%i_%i' % (n1, n2))\n", - " neighbors[n1, n2] = same\n", - " obj_vars.append(same)\n", - " obj_coeffs.append(distance_matrix[n1][n2] + distance_matrix[n2][n1])\n", + " # Variables.\n", + " neighbors = {}\n", + " obj_vars = []\n", + " obj_coeffs = []\n", + " for n1 in range(num_nodes - 1):\n", + " for n2 in range(n1 + 1, num_nodes):\n", + " same = model.NewBoolVar('neighbors_%i_%i' % (n1, n2))\n", + " neighbors[n1, n2] = same\n", + " obj_vars.append(same)\n", + " obj_coeffs.append(distance_matrix[n1][n2] + distance_matrix[n2][n1])\n", "\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", - "# 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", - "\n", - "# Redundant constraints on total sum of neighborss.\n", - "model.Add(sum(obj_vars) == num_groups * group_size * (group_size - 1) // 2)\n", - "\n", - "# Minimize weighted sum of arcs.\n", - "model.Minimize(\n", - " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", - "\n", - "# Solve and print out the solution.\n", - "solver = cp_model.CpSolver()\n", - "solver.parameters.log_search_progress = True\n", - "solver.parameters.num_search_workers = 8\n", - "\n", - "status = solver.Solve(model)\n", - "print(solver.ResponseStats())\n", - "\n", - "visited = set()\n", - "for g in range(num_groups):\n", + " # Number of neighborss:\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", + " 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", + " # 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", + "\n", + " # Redundant constraints on total sum of neighborss.\n", + " model.Add(sum(obj_vars) == num_groups * group_size * (group_size - 1) // 2)\n", + "\n", + " # Minimize weighted sum of arcs.\n", + " model.Minimize(\n", + " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", + "\n", + " # Solve and print out the solution.\n", + " solver = cp_model.CpSolver()\n", + " solver.parameters.log_search_progress = True\n", + " solver.parameters.num_search_workers = 8\n", + "\n", + " 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", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/cover_rectangle_sat.ipynb b/examples/notebook/examples/cover_rectangle_sat.ipynb index 65e23099a7..24a5dd3be1 100644 --- a/examples/notebook/examples/cover_rectangle_sat.ipynb +++ b/examples/notebook/examples/cover_rectangle_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Fill a 72x37 rectangle by a minimum number of non-overlapping squares.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +83,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Fill a 72x37 rectangle by a minimum number of non-overlapping squares.\"\"\"\n", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/examples/cvrptw_plot.ipynb b/examples/notebook/examples/cvrptw_plot.ipynb index 6fd73f85f0..3b193ea378 100644 --- a/examples/notebook/examples/cvrptw_plot.ipynb +++ b/examples/notebook/examples/cvrptw_plot.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# This Python file uses the following encoding: utf-8\n", - "# Copyright 2015 Tin Arm Engineering AB\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", - "\"\"\"Capacitated Vehicle Routing Problem with Time Windows (and optional orders).\n", + "Capacitated Vehicle Routing Problem with Time Windows (and optional orders).\n", "\n", " This is a sample using the routing library python wrapper to solve a\n", " CVRPTW problem.\n", @@ -108,8 +93,16 @@ " The optimization engine uses local search to improve solutions, first\n", " solutions being generated using a cheapest addition heuristic.\n", " Numpy and Matplotlib are required for the problem creation and display.\n", - "\n", - "\"\"\"\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import os\n", "import numpy as np\n", "from matplotlib import pyplot as plt\n", @@ -650,178 +643,182 @@ " color=cmap(veh_number + 1))\n", "\n", "\n", - "# Create a set of customer, (and depot) stops.\n", - "customers = Customers(\n", - " num_stops=50,\n", - " min_demand=1,\n", - " max_demand=15,\n", - " box_size=40,\n", - " min_tw=3,\n", - " max_tw=6)\n", + "def main():\n", + " # Create a set of customer, (and depot) stops.\n", + " customers = Customers(\n", + " num_stops=50,\n", + " min_demand=1,\n", + " max_demand=15,\n", + " box_size=40,\n", + " min_tw=3,\n", + " max_tw=6)\n", "\n", - "# Create a list of inhomgenious vehicle capacities as integer units.\n", - "capacity = [50, 75, 100, 125, 150, 175, 200, 250]\n", + " # Create a list of inhomgenious vehicle capacities as integer units.\n", + " capacity = [50, 75, 100, 125, 150, 175, 200, 250]\n", "\n", - "# Create a list of inhomogeneous fixed vehicle costs.\n", - "cost = [int(100 + 2 * np.sqrt(c)) for c in capacity]\n", + " # Create a list of inhomogeneous fixed vehicle costs.\n", + " cost = [int(100 + 2 * np.sqrt(c)) for c in capacity]\n", "\n", - "# Create a set of vehicles, the number set by the length of capacity.\n", - "vehicles = Vehicles(capacity=capacity, cost=cost)\n", + " # Create a set of vehicles, the number set by the length of capacity.\n", + " vehicles = Vehicles(capacity=capacity, cost=cost)\n", "\n", - "# check to see that the problem is feasible, if we don't have enough\n", - "# vehicles to cover the demand, there is no point in going further.\n", - "assert (customers.get_total_demand() < vehicles.get_total_capacity())\n", + " # check to see that the problem is feasible, if we don't have enough\n", + " # vehicles to cover the demand, there is no point in going further.\n", + " assert (customers.get_total_demand() < vehicles.get_total_capacity())\n", "\n", - "# Set the starting nodes, and create a callback fn for the starting node.\n", - "start_fn = vehicles.return_starting_callback(\n", - " customers, sameStartFinish=False)\n", + " # Set the starting nodes, and create a callback fn for the starting node.\n", + " start_fn = vehicles.return_starting_callback(\n", + " customers, sameStartFinish=False)\n", "\n", - "# Create the routing index manager.\n", - "manager = pywrapcp.RoutingIndexManager(\n", - " customers.number, # int number\n", - " vehicles.number, # int number\n", - " vehicles.starts, # List of int start depot\n", - " vehicles.ends) # List of int end depot\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(\n", + " customers.number, # int number\n", + " vehicles.number, # int number\n", + " vehicles.starts, # List of int start depot\n", + " vehicles.ends) # List of int end depot\n", "\n", - "customers.set_manager(manager)\n", + " customers.set_manager(manager)\n", "\n", - "# Set model parameters\n", - "model_parameters = pywrapcp.DefaultRoutingModelParameters()\n", + " # Set model parameters\n", + " model_parameters = pywrapcp.DefaultRoutingModelParameters()\n", "\n", - "# The solver parameters can be accessed from the model parameters. For example :\n", - "# model_parameters.solver_parameters.CopyFrom(\n", - "# pywrapcp.Solver.DefaultSolverParameters())\n", - "# model_parameters.solver_parameters.trace_propagation = True\n", + " # The solver parameters can be accessed from the model parameters. For example :\n", + " # model_parameters.solver_parameters.CopyFrom(\n", + " # pywrapcp.Solver.DefaultSolverParameters())\n", + " # model_parameters.solver_parameters.trace_propagation = True\n", "\n", - "# Make the routing model instance.\n", - "routing = pywrapcp.RoutingModel(manager, model_parameters)\n", + " # Make the routing model instance.\n", + " routing = pywrapcp.RoutingModel(manager, model_parameters)\n", "\n", - "parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "# Setting first solution heuristic (cheapest addition).\n", - "parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "# Routing: forbids use of TSPOpt neighborhood, (this is the default behaviour)\n", - "parameters.local_search_operators.use_tsp_opt = pywrapcp.BOOL_FALSE\n", - "# Disabling Large Neighborhood Search, (this is the default behaviour)\n", - "parameters.local_search_operators.use_path_lns = pywrapcp.BOOL_FALSE\n", - "parameters.local_search_operators.use_inactive_lns = pywrapcp.BOOL_FALSE\n", + " parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " # Setting first solution heuristic (cheapest addition).\n", + " parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " # Routing: forbids use of TSPOpt neighborhood, (this is the default behaviour)\n", + " parameters.local_search_operators.use_tsp_opt = pywrapcp.BOOL_FALSE\n", + " # Disabling Large Neighborhood Search, (this is the default behaviour)\n", + " parameters.local_search_operators.use_path_lns = pywrapcp.BOOL_FALSE\n", + " parameters.local_search_operators.use_inactive_lns = pywrapcp.BOOL_FALSE\n", "\n", - "parameters.time_limit.seconds = 10\n", - "parameters.use_full_propagation = True\n", - "#parameters.log_search = True\n", + " parameters.time_limit.seconds = 10\n", + " parameters.use_full_propagation = True\n", + " #parameters.log_search = True\n", "\n", - "# Create callback fns for distances, demands, service and transit-times.\n", - "dist_fn = customers.return_dist_callback()\n", - "dist_fn_index = routing.RegisterTransitCallback(dist_fn)\n", + " # Create callback fns for distances, demands, service and transit-times.\n", + " dist_fn = customers.return_dist_callback()\n", + " dist_fn_index = routing.RegisterTransitCallback(dist_fn)\n", "\n", - "dem_fn = customers.return_dem_callback()\n", - "dem_fn_index = routing.RegisterUnaryTransitCallback(dem_fn)\n", + " dem_fn = customers.return_dem_callback()\n", + " dem_fn_index = routing.RegisterUnaryTransitCallback(dem_fn)\n", "\n", - "# Create and register a transit callback.\n", - "serv_time_fn = customers.make_service_time_call_callback()\n", - "transit_time_fn = customers.make_transit_time_callback()\n", - "def tot_time_fn(from_index, to_index):\n", + " # Create and register a transit callback.\n", + " serv_time_fn = customers.make_service_time_call_callback()\n", + " transit_time_fn = customers.make_transit_time_callback()\n", + " def tot_time_fn(from_index, to_index):\n", + " \"\"\"\n", + " The time function we want is both transit time and service time.\n", + " \"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return serv_time_fn(from_node, to_node) + transit_time_fn(from_node, to_node)\n", + "\n", + " tot_time_fn_index = routing.RegisterTransitCallback(tot_time_fn)\n", + "\n", + " # Set the cost function (distance callback) for each arc, homogeneous for\n", + " # all vehicles.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(dist_fn_index)\n", + "\n", + " # Set vehicle costs for each vehicle, not homogeneous.\n", + " for veh in vehicles.vehicles:\n", + " routing.SetFixedCostOfVehicle(veh.cost, int(veh.index))\n", + "\n", + " # Add a dimension for vehicle capacities\n", + " null_capacity_slack = 0\n", + " routing.AddDimensionWithVehicleCapacity(\n", + " dem_fn_index, # demand callback\n", + " null_capacity_slack,\n", + " capacity, # capacity array\n", + " True,\n", + " 'Capacity')\n", + " # Add a dimension for time and a limit on the total time_horizon\n", + " routing.AddDimension(\n", + " tot_time_fn_index, # total time function callback\n", + " customers.time_horizon,\n", + " customers.time_horizon,\n", + " True,\n", + " 'Time')\n", + "\n", + " time_dimension = routing.GetDimensionOrDie('Time')\n", + " for cust in customers.customers:\n", + " if cust.tw_open is not None:\n", + " time_dimension.CumulVar(manager.NodeToIndex(cust.index)).SetRange(\n", + " cust.tw_open.seconds, cust.tw_close.seconds)\n", " \"\"\"\n", - " The time function we want is both transit time and service time.\n", + " To allow the dropping of orders, we add disjunctions to all the customer\n", + " nodes. Each disjunction is a list of 1 index, which allows that customer to\n", + " be active or not, with a penalty if not. The penalty should be larger\n", + " than the cost of servicing that customer, or it will always be dropped!\n", " \"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return serv_time_fn(from_node, to_node) + transit_time_fn(from_node, to_node)\n", + " # To add disjunctions just to the customers, make a list of non-depots.\n", + " non_depot = set(range(customers.number))\n", + " non_depot.difference_update(vehicles.starts)\n", + " non_depot.difference_update(vehicles.ends)\n", + " penalty = 400000 # The cost for dropping a node from the plan.\n", + " nodes = [routing.AddDisjunction([manager.NodeToIndex(c)], penalty) for c in non_depot]\n", "\n", - "tot_time_fn_index = routing.RegisterTransitCallback(tot_time_fn)\n", + " # This is how you would implement partial routes if you already knew part\n", + " # of a feasible solution for example:\n", + " # partial = np.random.choice(list(non_depot), size=(4,5), replace=False)\n", "\n", - "# Set the cost function (distance callback) for each arc, homogeneous for\n", - "# all vehicles.\n", - "routing.SetArcCostEvaluatorOfAllVehicles(dist_fn_index)\n", + " # routing.CloseModel()\n", + " # partial_list = [partial[0,:].tolist(),\n", + " # partial[1,:].tolist(),\n", + " # partial[2,:].tolist(),\n", + " # partial[3,:].tolist(),\n", + " # [],[],[],[]]\n", + " # print(routing.ApplyLocksToAllVehicles(partial_list, False))\n", "\n", - "# Set vehicle costs for each vehicle, not homogeneous.\n", - "for veh in vehicles.vehicles:\n", - " routing.SetFixedCostOfVehicle(veh.cost, int(veh.index))\n", + " # Solve the problem !\n", + " assignment = routing.SolveWithParameters(parameters)\n", "\n", - "# Add a dimension for vehicle capacities\n", - "null_capacity_slack = 0\n", - "routing.AddDimensionWithVehicleCapacity(\n", - " dem_fn_index, # demand callback\n", - " null_capacity_slack,\n", - " capacity, # capacity array\n", - " True,\n", - " 'Capacity')\n", - "# Add a dimension for time and a limit on the total time_horizon\n", - "routing.AddDimension(\n", - " tot_time_fn_index, # total time function callback\n", - " customers.time_horizon,\n", - " customers.time_horizon,\n", - " True,\n", - " 'Time')\n", + " # The rest is all optional for saving, printing or plotting the solution.\n", + " if assignment:\n", + " ## save the assignment, (Google Protobuf format)\n", + " #save_file_base = os.path.realpath(__file__).split('.')[0]\n", + " #if routing.WriteAssignment(save_file_base + '_assignment.ass'):\n", + " # print('succesfully wrote assignment to file ' + save_file_base +\n", + " # '_assignment.ass')\n", "\n", - "time_dimension = routing.GetDimensionOrDie('Time')\n", - "for cust in customers.customers:\n", - " if cust.tw_open is not None:\n", - " time_dimension.CumulVar(manager.NodeToIndex(cust.index)).SetRange(\n", - " cust.tw_open.seconds, cust.tw_close.seconds)\n", - "\"\"\"\n", - " To allow the dropping of orders, we add disjunctions to all the customer\n", - "nodes. Each disjunction is a list of 1 index, which allows that customer to\n", - "be active or not, with a penalty if not. The penalty should be larger\n", - "than the cost of servicing that customer, or it will always be dropped!\n", - "\"\"\"\n", - "# To add disjunctions just to the customers, make a list of non-depots.\n", - "non_depot = set(range(customers.number))\n", - "non_depot.difference_update(vehicles.starts)\n", - "non_depot.difference_update(vehicles.ends)\n", - "penalty = 400000 # The cost for dropping a node from the plan.\n", - "nodes = [routing.AddDisjunction([manager.NodeToIndex(c)], penalty) for c in non_depot]\n", + " print('The Objective Value is {0}'.format(assignment.ObjectiveValue()))\n", "\n", - "# This is how you would implement partial routes if you already knew part\n", - "# of a feasible solution for example:\n", - "# partial = np.random.choice(list(non_depot), size=(4,5), replace=False)\n", + " plan_output, dropped = vehicle_output_string(manager, routing, assignment)\n", + " print(plan_output)\n", + " print('dropped nodes: ' + ', '.join(dropped))\n", "\n", - "# routing.CloseModel()\n", - "# partial_list = [partial[0,:].tolist(),\n", - "# partial[1,:].tolist(),\n", - "# partial[2,:].tolist(),\n", - "# partial[3,:].tolist(),\n", - "# [],[],[],[]]\n", - "# print(routing.ApplyLocksToAllVehicles(partial_list, False))\n", + " # you could print debug information like this:\n", + " # print(routing.DebugOutputAssignment(assignment, 'Capacity'))\n", "\n", - "# Solve the problem !\n", - "assignment = routing.SolveWithParameters(parameters)\n", + " vehicle_routes = {}\n", + " for veh in range(vehicles.number):\n", + " vehicle_routes[veh] = build_vehicle_route(manager, routing, assignment,\n", + " customers, veh)\n", "\n", - "# The rest is all optional for saving, printing or plotting the solution.\n", - "if assignment:\n", - " ## save the assignment, (Google Protobuf format)\n", - " #save_file_base = os.path.realpath(__file__).split('.')[0]\n", - " #if routing.WriteAssignment(save_file_base + '_assignment.ass'):\n", - " # print('succesfully wrote assignment to file ' + save_file_base +\n", - " # '_assignment.ass')\n", + " # Plotting of the routes in matplotlib.\n", + " fig = plt.figure()\n", + " ax = fig.add_subplot(111)\n", + " # Plot all the nodes as black dots.\n", + " clon, clat = zip(*[(c.lon, c.lat) for c in customers.customers])\n", + " ax.plot(clon, clat, 'k.')\n", + " # plot the routes as arrows\n", + " plot_vehicle_routes(vehicle_routes, ax, customers, vehicles)\n", + " plt.show()\n", "\n", - " print('The Objective Value is {0}'.format(assignment.ObjectiveValue()))\n", + " else:\n", + " print('No assignment')\n", "\n", - " plan_output, dropped = vehicle_output_string(manager, routing, assignment)\n", - " print(plan_output)\n", - " print('dropped nodes: ' + ', '.join(dropped))\n", "\n", - " # you could print debug information like this:\n", - " # print(routing.DebugOutputAssignment(assignment, 'Capacity'))\n", - "\n", - " vehicle_routes = {}\n", - " for veh in range(vehicles.number):\n", - " vehicle_routes[veh] = build_vehicle_route(manager, routing, assignment,\n", - " customers, veh)\n", - "\n", - " # Plotting of the routes in matplotlib.\n", - " fig = plt.figure()\n", - " ax = fig.add_subplot(111)\n", - " # Plot all the nodes as black dots.\n", - " clon, clat = zip(*[(c.lon, c.lat) for c in customers.customers])\n", - " ax.plot(clon, clat, 'k.')\n", - " # plot the routes as arrows\n", - " plot_vehicle_routes(vehicle_routes, ax, customers, vehicles)\n", - " plt.show()\n", - "\n", - "else:\n", - " print('No assignment')\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/flexible_job_shop_sat.ipynb b/examples/notebook/examples/flexible_job_shop_sat.ipynb index f2ba513666..655c394d7b 100644 --- a/examples/notebook/examples/flexible_job_shop_sat.ipynb +++ b/examples/notebook/examples/flexible_job_shop_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solves a flexible jobshop problems with the CP-SAT solver.\n", + "Solves a flexible jobshop problems with the CP-SAT solver.\n", "\n", "A jobshop is a standard scheduling problem when you must sequence a\n", "series of task_types on a set of machines. Each job contains one task_type per\n", @@ -96,11 +81,17 @@ "\n", "The objective is to minimize the maximum completion time of all\n", "jobs. This is called the makespan.\n", - "\"\"\"\n", - "\n", - "# overloaded sum() clashes with pytype.\n", - "# pytype: disable=wrong-arg-types\n", "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import collections\n", "\n", "from ortools.sat.python import cp_model\n", diff --git a/examples/notebook/examples/gate_scheduling_sat.ipynb b/examples/notebook/examples/gate_scheduling_sat.ipynb index 0d17177079..3d2e599093 100644 --- a/examples/notebook/examples/gate_scheduling_sat.ipynb +++ b/examples/notebook/examples/gate_scheduling_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Gate Scheduling problem.\n", + "Gate Scheduling problem.\n", "\n", "We have a set of jobs to perform (duration, width).\n", "We have two parallel machines that can perform this job.\n", @@ -96,133 +81,143 @@ "exceed a max_width.\n", "\n", "The objective is to minimize the max end time of all jobs.\n", - "\"\"\"\n", - "\n", - "from absl import app\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.sat.python import visualization\n", "from ortools.sat.python import cp_model\n", "\n", "\n", - "\"\"\"Solves the gate scheduling problem.\"\"\"\n", - "model = cp_model.CpModel()\n", + "def main(_):\n", + " \"\"\"Solves the gate scheduling problem.\"\"\"\n", + " model = cp_model.CpModel()\n", "\n", - "jobs = [\n", - " [3, 3], # [duration, width]\n", - " [2, 5],\n", - " [1, 3],\n", - " [3, 7],\n", - " [7, 3],\n", - " [2, 2],\n", - " [2, 2],\n", - " [5, 5],\n", - " [10, 2],\n", - " [4, 3],\n", - " [2, 6],\n", - " [1, 2],\n", - " [6, 8],\n", - " [4, 5],\n", - " [3, 7]\n", - "]\n", + " jobs = [\n", + " [3, 3], # [duration, width]\n", + " [2, 5],\n", + " [1, 3],\n", + " [3, 7],\n", + " [7, 3],\n", + " [2, 2],\n", + " [2, 2],\n", + " [5, 5],\n", + " [10, 2],\n", + " [4, 3],\n", + " [2, 6],\n", + " [1, 2],\n", + " [6, 8],\n", + " [4, 5],\n", + " [3, 7]\n", + " ]\n", "\n", - "max_width = 10\n", + " max_width = 10\n", "\n", - "horizon = sum(t[0] for t in jobs)\n", - "num_jobs = len(jobs)\n", - "all_jobs = range(num_jobs)\n", + " horizon = sum(t[0] for t in jobs)\n", + " num_jobs = len(jobs)\n", + " all_jobs = range(num_jobs)\n", "\n", - "intervals = []\n", - "intervals0 = []\n", - "intervals1 = []\n", - "performed = []\n", - "starts = []\n", - "ends = []\n", - "demands = []\n", - "\n", - "for i in all_jobs:\n", - " # Create main interval.\n", - " start = model.NewIntVar(0, horizon, 'start_%i' % i)\n", - " duration = jobs[i][0]\n", - " end = model.NewIntVar(0, horizon, 'end_%i' % i)\n", - " interval = model.NewIntervalVar(start, duration, end, 'interval_%i' % i)\n", - " starts.append(start)\n", - " intervals.append(interval)\n", - " ends.append(end)\n", - " demands.append(jobs[i][1])\n", - "\n", - " # Create an optional copy of interval to be executed on machine 0.\n", - " performed_on_m0 = model.NewBoolVar('perform_%i_on_m0' % i)\n", - " performed.append(performed_on_m0)\n", - " start0 = model.NewIntVar(0, horizon, 'start_%i_on_m0' % i)\n", - " end0 = model.NewIntVar(0, horizon, 'end_%i_on_m0' % i)\n", - " interval0 = model.NewOptionalIntervalVar(start0, duration, end0,\n", - " performed_on_m0,\n", - " 'interval_%i_on_m0' % i)\n", - " intervals0.append(interval0)\n", - "\n", - " # Create an optional copy of interval to be executed on machine 1.\n", - " start1 = model.NewIntVar(0, horizon, 'start_%i_on_m1' % i)\n", - " end1 = model.NewIntVar(0, horizon, 'end_%i_on_m1' % i)\n", - " interval1 = model.NewOptionalIntervalVar(start1, duration, end1,\n", - " performed_on_m0.Not(),\n", - " 'interval_%i_on_m1' % i)\n", - " intervals1.append(interval1)\n", - "\n", - " # We only propagate the constraint if the tasks is performed on the machine.\n", - " model.Add(start0 == start).OnlyEnforceIf(performed_on_m0)\n", - " model.Add(start1 == start).OnlyEnforceIf(performed_on_m0.Not())\n", - "\n", - "# Width constraint (modeled as a cumulative)\n", - "model.AddCumulative(intervals, demands, max_width)\n", - "\n", - "# Choose which machine to perform the jobs on.\n", - "model.AddNoOverlap(intervals0)\n", - "model.AddNoOverlap(intervals1)\n", - "\n", - "# Objective variable.\n", - "makespan = model.NewIntVar(0, horizon, 'makespan')\n", - "model.AddMaxEquality(makespan, ends)\n", - "model.Minimize(makespan)\n", - "\n", - "# Symmetry breaking.\n", - "model.Add(performed[0] == 0)\n", - "\n", - "# Solve model.\n", - "solver = cp_model.CpSolver()\n", - "solver.Solve(model)\n", - "\n", - "# Output solution.\n", - "if visualization.RunFromIPython():\n", - " output = visualization.SvgWrapper(solver.ObjectiveValue(), max_width,\n", - " 40.0)\n", - " output.AddTitle('Makespan = %i' % solver.ObjectiveValue())\n", - " color_manager = visualization.ColorManager()\n", - " color_manager.SeedRandomColor(0)\n", + " intervals = []\n", + " intervals0 = []\n", + " intervals1 = []\n", + " performed = []\n", + " starts = []\n", + " ends = []\n", + " demands = []\n", "\n", " for i in all_jobs:\n", - " performed_machine = 1 - solver.Value(performed[i])\n", - " start = solver.Value(starts[i])\n", - " d_x = jobs[i][0]\n", - " d_y = jobs[i][1]\n", - " s_y = performed_machine * (max_width - d_y)\n", - " output.AddRectangle(start, s_y, d_x, d_y,\n", - " color_manager.RandomColor(), 'black', 'j%i' % i)\n", + " # Create main interval.\n", + " start = model.NewIntVar(0, horizon, 'start_%i' % i)\n", + " duration = jobs[i][0]\n", + " end = model.NewIntVar(0, horizon, 'end_%i' % i)\n", + " interval = model.NewIntervalVar(start, duration, end, 'interval_%i' % i)\n", + " starts.append(start)\n", + " intervals.append(interval)\n", + " ends.append(end)\n", + " demands.append(jobs[i][1])\n", "\n", - " output.AddXScale()\n", - " output.AddYScale()\n", - " output.Display()\n", - "else:\n", - " print('Solution')\n", - " print(' - makespan = %i' % solver.ObjectiveValue())\n", - " for i in all_jobs:\n", - " performed_machine = 1 - solver.Value(performed[i])\n", - " start = solver.Value(starts[i])\n", - " print(' - Job %i starts at %i on machine %i' %\n", - " (i, start, performed_machine))\n", - " print('Statistics')\n", - " print(' - conflicts : %i' % solver.NumConflicts())\n", - " print(' - branches : %i' % solver.NumBranches())\n", - " print(' - wall time : %f s' % solver.WallTime())\n", + " # Create an optional copy of interval to be executed on machine 0.\n", + " performed_on_m0 = model.NewBoolVar('perform_%i_on_m0' % i)\n", + " performed.append(performed_on_m0)\n", + " start0 = model.NewIntVar(0, horizon, 'start_%i_on_m0' % i)\n", + " end0 = model.NewIntVar(0, horizon, 'end_%i_on_m0' % i)\n", + " interval0 = model.NewOptionalIntervalVar(start0, duration, end0,\n", + " performed_on_m0,\n", + " 'interval_%i_on_m0' % i)\n", + " intervals0.append(interval0)\n", + "\n", + " # Create an optional copy of interval to be executed on machine 1.\n", + " start1 = model.NewIntVar(0, horizon, 'start_%i_on_m1' % i)\n", + " end1 = model.NewIntVar(0, horizon, 'end_%i_on_m1' % i)\n", + " interval1 = model.NewOptionalIntervalVar(start1, duration, end1,\n", + " performed_on_m0.Not(),\n", + " 'interval_%i_on_m1' % i)\n", + " intervals1.append(interval1)\n", + "\n", + " # We only propagate the constraint if the tasks is performed on the machine.\n", + " model.Add(start0 == start).OnlyEnforceIf(performed_on_m0)\n", + " model.Add(start1 == start).OnlyEnforceIf(performed_on_m0.Not())\n", + "\n", + " # Width constraint (modeled as a cumulative)\n", + " model.AddCumulative(intervals, demands, max_width)\n", + "\n", + " # Choose which machine to perform the jobs on.\n", + " model.AddNoOverlap(intervals0)\n", + " model.AddNoOverlap(intervals1)\n", + "\n", + " # Objective variable.\n", + " makespan = model.NewIntVar(0, horizon, 'makespan')\n", + " model.AddMaxEquality(makespan, ends)\n", + " model.Minimize(makespan)\n", + "\n", + " # Symmetry breaking.\n", + " model.Add(performed[0] == 0)\n", + "\n", + " # Solve model.\n", + " solver = cp_model.CpSolver()\n", + " solver.Solve(model)\n", + "\n", + " # Output solution.\n", + " if visualization.RunFromIPython():\n", + " output = visualization.SvgWrapper(solver.ObjectiveValue(), max_width,\n", + " 40.0)\n", + " output.AddTitle('Makespan = %i' % solver.ObjectiveValue())\n", + " color_manager = visualization.ColorManager()\n", + " color_manager.SeedRandomColor(0)\n", + "\n", + " for i in all_jobs:\n", + " performed_machine = 1 - solver.Value(performed[i])\n", + " start = solver.Value(starts[i])\n", + " d_x = jobs[i][0]\n", + " d_y = jobs[i][1]\n", + " s_y = performed_machine * (max_width - d_y)\n", + " output.AddRectangle(start, s_y, d_x, d_y,\n", + " color_manager.RandomColor(), 'black', 'j%i' % i)\n", + "\n", + " output.AddXScale()\n", + " output.AddYScale()\n", + " output.Display()\n", + " else:\n", + " print('Solution')\n", + " print(' - makespan = %i' % solver.ObjectiveValue())\n", + " for i in all_jobs:\n", + " performed_machine = 1 - solver.Value(performed[i])\n", + " start = solver.Value(starts[i])\n", + " print(' - Job %i starts at %i on machine %i' %\n", + " (i, start, performed_machine))\n", + " print('Statistics')\n", + " print(' - conflicts : %i' % solver.NumConflicts())\n", + " print(' - branches : %i' % solver.NumBranches())\n", + " print(' - wall time : %f s' % solver.WallTime())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/golomb8.ipynb b/examples/notebook/examples/golomb8.ipynb index 4f15986c89..1548229063 100644 --- a/examples/notebook/examples/golomb8.ipynb +++ b/examples/notebook/examples/golomb8.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"This is the Golomb ruler problem.\n", + "This is the Golomb ruler problem.\n", "\n", "This model aims at maximizing radar interferences in a minimum space.\n", "It is known as the Golomb Ruler problem.\n", @@ -95,62 +80,91 @@ "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", - "\"\"\"\n", - "\n", - "from absl import app\n", - "from absl import flags\n", + "see: https://en.wikipedia.org/wiki/Golomb_ruler\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", - "FLAGS = flags.FLAGS\n", + "class FLAGS: pass\n", "\n", - "# We disable the following warning because it is a false positive on constraints\n", - "# like: solver.Add(x == 0)\n", - "# pylint: disable=g-explicit-bool-comparison\n", + "FLAGS.order = 8 # Order of the ruler.\n", + "\n", + "def solve_golomb_ruler(order):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('golomb ruler')\n", + "\n", + " var_max = order * order\n", + " all_vars = list(range(0, order))\n", + "\n", + " marks = [solver.IntVar(0, var_max, f'marks_{i}') for i in all_vars]\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", + " 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", + "\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", + " 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", + " 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", - "# Create the solver.\n", - "solver = pywrapcp.Solver('golomb ruler')\n", + "def main(_):\n", + " solve_golomb_ruler(FLAGS.order)\n", "\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", - "objective = solver.Minimize(marks[size - 1], 1)\n", - "\n", - "solver.Add(marks[0] == 0)\n", - "\n", - "# We expand the creation of the diff array to avoid a pylint warning.\n", - "diffs = []\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", - "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", - "solution = solver.Assignment()\n", - "solution.Add(marks[size - 1])\n", - "collector = solver.AllSolutionCollector(solution)\n", - "\n", - "solver.Solve(\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[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", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/golomb_sat.ipynb b/examples/notebook/examples/golomb_sat.ipynb new file mode 100644 index 0000000000..bf11a3bf17 --- /dev/null +++ b/examples/notebook/examples/golomb_sat.ipynb @@ -0,0 +1,165 @@ +{ + "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": [ + "# golomb_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": [ + "This is the Golomb ruler problem.\n", + "\n", + "This model aims at maximizing radar interferences in a minimum space.\n", + "It is known as the Golomb Ruler problem.\n", + "\n", + "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" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ + "from google.protobuf import text_format\n", + "from ortools.sat.python import cp_model\n", + "\n", + "class FLAGS: pass\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", + " # Create the model.\n", + " model = cp_model.CpModel()\n", + "\n", + " var_max = order * order\n", + " all_vars = list(range(0, order))\n", + "\n", + " marks = [model.NewIntVar(0, var_max, f'marks_{i}') for i in all_vars]\n", + "\n", + " model.Add(marks[0] == 0)\n", + " for i in range(order - 2):\n", + " model.Add(marks[i + 1] > marks[i])\n", + "\n", + " diffs = []\n", + " for i in range(order - 1):\n", + " for j in range(i + 1, order):\n", + " diff = model.NewIntVar(0, var_max, f'diff [{j},{i}]')\n", + " model.Add(diff == marks[j] - marks[i])\n", + " diffs.append(diff)\n", + " model.AddAllDifferent(diffs)\n", + "\n", + " # symmetry breaking\n", + " if order > 2:\n", + " model.Add(marks[order - 1] - marks[order - 2] > marks[1] - marks[0])\n", + "\n", + " # Objective\n", + " model.Minimize(marks[order - 1])\n", + "\n", + " # Solve the model.\n", + " solver = cp_model.CpSolver()\n", + " if params:\n", + " text_format.Parse(params, solver.parameters)\n", + " solution_printer = cp_model.ObjectiveSolutionPrinter()\n", + " print(f'Golomb ruler(order={order})')\n", + " status = solver.Solve(model, solution_printer)\n", + "\n", + " # Print solution.\n", + " print(f'status: {solver.StatusName(status)}')\n", + " if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):\n", + " for idx, var in enumerate(marks):\n", + " print(f'mark[{idx}]: {solver.Value(var)}')\n", + " intervals = [solver.Value(diff) for diff in diffs]\n", + " intervals.sort()\n", + " print(f'intervals: {intervals}')\n", + "\n", + " print('Statistics:')\n", + " print(f'- conflicts: {solver.NumConflicts()}')\n", + " print(f'- branches : {solver.NumBranches()}')\n", + " print(f'- wall time: {solver.WallTime()}s\\n')\n", + "\n", + "\n", + "def main(_):\n", + " solve_golomb_ruler(FLAGS.order, FLAGS.params)\n", + "\n", + "\n", + "main()\n", + "\n" + ] + } + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/notebook/examples/hidato_sat.ipynb b/examples/notebook/examples/hidato_sat.ipynb index cca0dc8565..d934e1fe68 100644 --- a/examples/notebook/examples/hidato_sat.ipynb +++ b/examples/notebook/examples/hidato_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves the Hidato problem with the CP-SAT solver.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,22 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solves the Hidato problem with the CP-SAT solver.\"\"\"\n", - "\n", - "from absl import app\n", "from ortools.sat.python import visualization\n", "from ortools.sat.python import cp_model\n", "\n", @@ -265,8 +257,12 @@ " print(' - wall time : %f s' % solver.WallTime())\n", "\n", "\n", - "for pb in range(1, 7):\n", - " solve_hidato(build_puzzle(pb), pb)\n", + "def main(_):\n", + " for pb in range(1, 7):\n", + " solve_hidato(build_puzzle(pb), pb)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/integer_programming.ipynb b/examples/notebook/examples/integer_programming.ipynb index e5620d30d0..7b60409220 100644 --- a/examples/notebook/examples/integer_programming.ipynb +++ b/examples/notebook/examples/integer_programming.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Integer programming examples that show how to use the APIs.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Integer programming examples that show how to use the APIs.\"\"\"\n", - "\n", "from ortools.linear_solver import pywraplp\n", "from ortools.init import pywrapinit\n", "\n", @@ -187,8 +180,17 @@ " RunIntegerExampleCppStyleAPI('Gurobi')\n", "\n", "\n", - "RunAllIntegerExampleNaturalLanguageAPI()\n", - "RunAllIntegerExampleCppStyleAPI()\n", + "def main():\n", + " RunAllIntegerExampleNaturalLanguageAPI()\n", + " RunAllIntegerExampleCppStyleAPI()\n", + "\n", + "\n", + "pywrapinit.CppBridge.InitLogging('integer_programming.py')\n", + "cpp_flags = pywrapinit.CppFlags()\n", + "cpp_flags.logtostderr = True\n", + "cpp_flags.log_prefix = False\n", + "pywrapinit.CppBridge.SetFlags(cpp_flags)\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/jobshop_ft06_distance_sat.ipynb b/examples/notebook/examples/jobshop_ft06_distance_sat.ipynb index 97552407b6..da68bab1c4 100644 --- a/examples/notebook/examples/jobshop_ft06_distance_sat.ipynb +++ b/examples/notebook/examples/jobshop_ft06_distance_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"This model implements a variation of the ft06 jobshop.\n", + "This model implements a variation of the ft06 jobshop.\n", "\n", "A jobshop is a standard scheduling problem when you must sequence a\n", "series of tasks on a set of machines. Each job contains one task per\n", @@ -99,8 +84,16 @@ "\n", "This variation introduces a minimum distance between all the jobs on each\n", "machine.\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import collections\n", "\n", "from ortools.sat.python import cp_model\n", diff --git a/examples/notebook/examples/jobshop_ft06_sat.ipynb b/examples/notebook/examples/jobshop_ft06_sat.ipynb index 37862aae64..acb5cbf5b7 100644 --- a/examples/notebook/examples/jobshop_ft06_sat.ipynb +++ b/examples/notebook/examples/jobshop_ft06_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"This model implements a simple jobshop named ft06.\n", + "This model implements a simple jobshop named ft06.\n", "\n", "A jobshop is a standard scheduling problem when you must sequence a\n", "series of task_types on a set of machines. Each job contains one task_type per\n", @@ -96,8 +81,16 @@ "\n", "The objective is to minimize the maximum completion time of all\n", "jobs. This is called the makespan.\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import collections\n", "\n", "from ortools.sat.python import visualization\n", diff --git a/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb b/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb index db60581f7f..bfe7091bb4 100644 --- a/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb +++ b/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Jobshop with maintenance tasks using the CP-SAT solver.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,20 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 Google\n", - "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", - "# you may not use this file except in compliance with the License.\n", - "# You may obtain a copy of the License at\n", - "#\n", - "# http://www.apache.org/licenses/LICENSE-2.0\n", - "#\n", - "# Unless required by applicable law or agreed to in writing, software\n", - "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", - "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", - "# See the License for the specific language governing permissions and\n", - "# limitations under the License.\n", - "\"\"\"Jobshop with maintenance tasks using the CP-SAT solver.\"\"\"\n", - "\n", "import collections\n", "from ortools.sat.python import cp_model\n", "\n", diff --git a/examples/notebook/examples/knapsack_2d_sat.ipynb b/examples/notebook/examples/knapsack_2d_sat.ipynb index bc92b9640f..27b9101e6a 100644 --- a/examples/notebook/examples/knapsack_2d_sat.ipynb +++ b/examples/notebook/examples/knapsack_2d_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,18 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solver a 2D rectangle knapsack problem.\n", + "\n", + "This code is adapted from\n", + "https://yetanothermathprogrammingconsultant.blogspot.com/2021/10/2d-knapsack-problem.html\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,45 +86,18 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solver a 2D rectangle knapsack problem.\n", - "\n", - "This code is adapted from\n", - "https://yetanothermathprogrammingconsultant.blogspot.com/2021/10/2d-knapsack-problem.html\n", - "\"\"\"\n", - "\n", "import io\n", - "\n", - "from absl import app\n", - "from absl import flags\n", "import numpy as np\n", "import pandas as pd\n", "\n", "from google.protobuf import text_format\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", - "FLAGS = flags.FLAGS\n", - "\n", - "flags.DEFINE_string('output_proto', '',\n", - " 'Output file to write the cp_model proto to.')\n", - "flags.DEFINE_string('params', 'num_search_workers:16,log_search_progress:true',\n", - " 'Sat solver parameters.')\n", - "flags.DEFINE_string('model', 'rotation',\n", - " '\\'duplicate\\' or \\'rotation\\' or \\'optional\\'')\n", + "class FLAGS: pass\n", "\n", + "FLAGS.output_proto = '' # Output file to write the cp_model proto to.\n", + "FLAGS.params = 'num_search_workers:16,log_search_progress:true' # Sat solver parameters.\n", + "FLAGS.model = 'rotation' # 'duplicate' or 'rotation' or 'optional'\n", "\n", "def build_data():\n", " \"\"\"Build the data frame.\"\"\"\n", @@ -436,14 +421,22 @@ " print(data)\n", "\n", "\n", - "\"\"\"Solve the problem with all models.\"\"\"\n", - "data, max_height, max_width = build_data()\n", - "if FLAGS.model == 'duplicate':\n", - " solve_with_duplicate_items(data, max_height, max_width)\n", - "elif FLAGS.model == 'optional':\n", - " solve_with_duplicate_optional_items(data, max_height, max_width)\n", - "else:\n", - " solve_with_rotations(data, max_height, max_width)\n", + "def solve_knapsack(model):\n", + " \"\"\"Solve the problem with all models.\"\"\"\n", + " data, max_height, max_width = build_data()\n", + " if model == 'duplicate':\n", + " solve_with_duplicate_items(data, max_height, max_width)\n", + " elif model == 'optional':\n", + " solve_with_duplicate_optional_items(data, max_height, max_width)\n", + " else:\n", + " solve_with_rotations(data, max_height, max_width)\n", + "\n", + "\n", + "def main(_):\n", + " solve_knapsack(FLAGS.model)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/linear_assignment_api.ipynb b/examples/notebook/examples/linear_assignment_api.ipynb index 6faef7c32b..912e47b182 100644 --- a/examples/notebook/examples/linear_assignment_api.ipynb +++ b/examples/notebook/examples/linear_assignment_api.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,19 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Test linear sum assignment on a 4x4 matrix.\n", + "\n", + " Example taken from:\n", + " http://www.ee.oulu.fi/~mpa/matreng/eem1_2-1.htm with kCost[0][1]\n", + " modified so the optimum solution is unique.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,27 +87,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Test linear sum assignment on a 4x4 matrix.\n", - "\n", - " Example taken from:\n", - " http://www.ee.oulu.fi/~mpa/matreng/eem1_2-1.htm with kCost[0][1]\n", - " modified so the optimum solution is unique.\n", - "\"\"\"\n", - "\n", - "from absl import app\n", "from ortools.graph.python import linear_sum_assignment\n", "\n", "\n", @@ -125,7 +117,11 @@ " 'Some input costs are too large and may cause an integer overflow.')\n", "\n", "\n", - "RunAssignmentOn4x4Matrix()\n", + "def main(_):\n", + " RunAssignmentOn4x4Matrix()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/linear_programming.ipynb b/examples/notebook/examples/linear_programming.ipynb index c08adbe946..dd2066921e 100644 --- a/examples/notebook/examples/linear_programming.ipynb +++ b/examples/notebook/examples/linear_programming.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Linear programming examples that show how to use the APIs.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Linear programming examples that show how to use the APIs.\"\"\"\n", - "\n", "from ortools.linear_solver import pywraplp\n", "\n", "\n", @@ -202,15 +195,19 @@ " (i, constraint.dual_value(), activities[constraint.index()])))\n", "\n", "\n", - "RunLinearExampleNaturalLanguageAPI('GLOP')\n", - "RunLinearExampleNaturalLanguageAPI('GLPK_LP')\n", - "RunLinearExampleNaturalLanguageAPI('CLP')\n", - "RunLinearExampleNaturalLanguageAPI('PDLP')\n", + "def main():\n", + " RunLinearExampleNaturalLanguageAPI('GLOP')\n", + " RunLinearExampleNaturalLanguageAPI('GLPK_LP')\n", + " RunLinearExampleNaturalLanguageAPI('CLP')\n", + " RunLinearExampleNaturalLanguageAPI('PDLP')\n", "\n", - "RunLinearExampleCppStyleAPI('GLOP')\n", - "RunLinearExampleCppStyleAPI('GLPK_LP')\n", - "RunLinearExampleCppStyleAPI('CLP')\n", - "RunLinearExampleCppStyleAPI('PDLP')\n", + " RunLinearExampleCppStyleAPI('GLOP')\n", + " RunLinearExampleCppStyleAPI('GLPK_LP')\n", + " RunLinearExampleCppStyleAPI('CLP')\n", + " RunLinearExampleCppStyleAPI('PDLP')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/magic_sequence_distribute.ipynb b/examples/notebook/examples/magic_sequence_distribute.ipynb index 4c0e600f1f..b46566a050 100644 --- a/examples/notebook/examples/magic_sequence_distribute.ipynb +++ b/examples/notebook/examples/magic_sequence_distribute.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Magic sequence problem.\n", + "Magic sequence problem.\n", "\n", "This models aims at building a sequence of numbers such that the number of\n", "occurrences of i in this sequence is equal to the value of the ith number.\n", @@ -95,36 +80,45 @@ "distribute().\n", "\n", "Usage: python magic_sequence_distribute.py NUMBER\n", - "\"\"\"\n", - "\n", - "from absl import app\n", - "from absl import flags\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.constraint_solver import pywrapcp\n", "\n", - "FLAGS = flags.FLAGS\n", + "class FLAGS: pass\n", + "\n", + "def main(argv):\n", + " # Create the solver.\n", + " solver = pywrapcp.Solver('magic sequence')\n", + "\n", + " # Create an array of IntVars to hold the answers.\n", + " size = int(argv[1]) if len(argv) > 1 else 100\n", + " all_values = list(range(0, size))\n", + " all_vars = [solver.IntVar(0, size, 'vars_%d' % i) for i in all_values]\n", + "\n", + " # The number of variables equal to j shall be the value of all_vars[j].\n", + " solver.Add(solver.Distribute(all_vars, all_values, all_vars))\n", + "\n", + " # The sum of all the values shall be equal to the size.\n", + " # (This constraint is redundant, but speeds up the search.)\n", + " solver.Add(solver.Sum(all_vars) == size)\n", + "\n", + " solver.NewSearch(\n", + " solver.Phase(all_vars, solver.CHOOSE_FIRST_UNBOUND,\n", + " solver.ASSIGN_MIN_VALUE))\n", + " solver.NextSolution()\n", + " print(all_vars)\n", + " solver.EndSearch()\n", "\n", "\n", - "# Create the solver.\n", - "solver = pywrapcp.Solver('magic sequence')\n", - "\n", - "# Create an array of IntVars to hold the answers.\n", - "size = int(argv[1]) if len(argv) > 1 else 100\n", - "all_values = list(range(0, size))\n", - "all_vars = [solver.IntVar(0, size, 'vars_%d' % i) for i in all_values]\n", - "\n", - "# The number of variables equal to j shall be the value of all_vars[j].\n", - "solver.Add(solver.Distribute(all_vars, all_values, all_vars))\n", - "\n", - "# The sum of all the values shall be equal to the size.\n", - "# (This constraint is redundant, but speeds up the search.)\n", - "solver.Add(solver.Sum(all_vars) == size)\n", - "\n", - "solver.NewSearch(\n", - " solver.Phase(all_vars, solver.CHOOSE_FIRST_UNBOUND,\n", - " solver.ASSIGN_MIN_VALUE))\n", - "solver.NextSolution()\n", - "print(all_vars)\n", - "solver.EndSearch()\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/maze_escape_sat.ipynb b/examples/notebook/examples/maze_escape_sat.ipynb index e60260763f..b3acdd11d0 100644 --- a/examples/notebook/examples/maze_escape_sat.ipynb +++ b/examples/notebook/examples/maze_escape_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,20 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Excape the maze while collecting treasures in order.\n", + "\n", + "The path must begin at the 'start' position, finish at the 'end' position,\n", + "visit all boxes in order, and walk on each block in a 4x4x4 map exactly once.\n", + "\n", + "Admissible moves are one step in one of the 6 directions:\n", + " x+, x-, y+, y-, z+(up), z-(down)\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,41 +88,15 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Excape the maze while collecting treasures in order.\n", - "\n", - "The path must begin at the 'start' position, finish at the 'end' position,\n", - "visit all boxes in order, and walk on each block in a 4x4x4 map exactly once.\n", - "\n", - "Admissible moves are one step in one of the 6 directions:\n", - " x+, x-, y+, y-, z+(up), z-(down)\n", - "\"\"\"\n", "from typing import Sequence\n", "\n", - "from absl import app\n", - "from absl import flags\n", "from google.protobuf import text_format\n", "from ortools.sat.python import cp_model\n", "\n", - "FLAGS = flags.FLAGS\n", - "\n", - "flags.DEFINE_string('output_proto', '',\n", - " 'Output file to write the cp_model proto to.')\n", - "flags.DEFINE_string('params', 'num_search_workers:8,log_search_progress:true',\n", - " 'Sat solver parameters.')\n", + "class FLAGS: pass\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", @@ -215,9 +203,13 @@ " print(path)\n", "\n", "\n", - "if len(argv) > 1:\n", - " raise app.UsageError('Too many command-line arguments.')\n", - "escape_the_maze(FLAGS.params, FLAGS.output_proto)\n", + "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", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb b/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb index e499c33d1e..2d58cfec7a 100644 --- a/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb +++ b/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,20 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Scheduling cooking tasks in a bakery using no-wait jobshop scheduling.\n", + "\n", + "We are scheduling a full day of baking:\n", + " - Work starts at 4am.\n", + " - The shop closes at 10PM.\n", + " - Durations are in minutes. Time starts at midnight.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,43 +88,15 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Scheduling cooking tasks in a bakery using no-wait jobshop scheduling.\n", - "\n", - "We are scheduling a full day of baking:\n", - " - Work starts at 4am.\n", - " - The shop closes at 10PM.\n", - " - Durations are in minutes. Time starts at midnight.\n", - "\"\"\"\n", - "\n", "import collections\n", "from typing import Sequence\n", - "from absl import app\n", - "from absl import flags\n", - "\n", "from google.protobuf import text_format\n", "from ortools.sat.python import cp_model\n", "\n", - "FLAGS = flags.FLAGS\n", + "class FLAGS: pass\n", "\n", - "flags.DEFINE_string('params', 'num_search_workers:16, max_time_in_seconds:30',\n", - " 'Sat solver parameters.')\n", - "flags.DEFINE_string('proto_file', '',\n", - " 'If not empty, output the proto to this file.')\n", - "\n", - "# Recipes\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", "CROISSANT = 'croissant'\n", "APPLE_PIE = 'apple pie'\n", "BRIOCHE = 'brioche'\n", @@ -366,11 +352,15 @@ " print(f' {event_id} at {time // 60}:{time % 60:02}')\n", "\n", "\n", - "if len(argv) > 1:\n", - " raise app.UsageError('Too many command-line arguments.')\n", + "def main(argv: Sequence[str]) -> None:\n", + " if len(argv) > 1:\n", + " raise app.UsageError('Too many command-line arguments.')\n", "\n", - "recipes, resources, orders = set_up_data()\n", - "solve_with_cp_sat(recipes, resources, orders)\n", + " recipes, resources, orders = set_up_data()\n", + " solve_with_cp_sat(recipes, resources, orders)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/prize_collecting_tsp.ipynb b/examples/notebook/examples/prize_collecting_tsp.ipynb index 56ae0cbddb..94bf888f37 100644 --- a/examples/notebook/examples/prize_collecting_tsp.ipynb +++ b/examples/notebook/examples/prize_collecting_tsp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple prize collecting TSP problem with a max distance.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Simple prize collecting TSP problem with a max distance.\"\"\"\n", - "\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -173,67 +166,71 @@ " print(plan_output)\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "num_nodes = len(DISTANCE_MATRIX)\n", - "print(f'Num nodes = {num_nodes}')\n", - "num_vehicles = 1\n", - "depot = 0\n", - "all_nodes = range(num_nodes)\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " num_nodes = len(DISTANCE_MATRIX)\n", + " print(f'Num nodes = {num_nodes}')\n", + " num_vehicles = 1\n", + " depot = 0\n", + " all_nodes = range(num_nodes)\n", "\n", - "# Create the routing index manager.\n", - "manager = pywrapcp.RoutingIndexManager(\n", - " num_nodes,\n", - " num_vehicles,\n", - " depot)\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(\n", + " num_nodes,\n", + " num_vehicles,\n", + " depot)\n", "\n", - "# Create routing model.\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create routing model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Create and register a transit callback.\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return DISTANCE_MATRIX[from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return DISTANCE_MATRIX[from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Limit Vehicle distance.\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " MAX_DISTANCE, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "#distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "#distance_dimension.SetGlobalSpanCostCoefficient(100)\n", + " # Limit Vehicle distance.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " MAX_DISTANCE, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " #distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " #distance_dimension.SetGlobalSpanCostCoefficient(100)\n", "\n", - "# Allow to drop nodes.\n", - "for node in range(1, num_nodes):\n", - " routing.AddDisjunction(\n", - " [manager.NodeToIndex(node)],\n", - " VISIT_VALUES[node])\n", + " # Allow to drop nodes.\n", + " for node in range(1, num_nodes):\n", + " routing.AddDisjunction(\n", + " [manager.NodeToIndex(node)],\n", + " VISIT_VALUES[node])\n", "\n", - "# Setting first solution heuristic.\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(15)\n", - "#search_parameters.log_search = True\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(15)\n", + " #search_parameters.log_search = True\n", "\n", - "# Solve the problem.\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "if assignment:\n", - " print_solution(manager, routing, assignment)\n", + " # Print solution on console.\n", + " if assignment:\n", + " print_solution(manager, routing, assignment)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/prize_collecting_tsp_sat.ipynb b/examples/notebook/examples/prize_collecting_tsp_sat.ipynb index 83cc56755f..b805305f64 100644 --- a/examples/notebook/examples/prize_collecting_tsp_sat.ipynb +++ b/examples/notebook/examples/prize_collecting_tsp_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple prize collecting TSP problem with a max distance.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Simple prize collecting TSP problem with a max distance.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "DISTANCE_MATRIX = [\n", @@ -174,66 +167,70 @@ " plan_output += f'Value collected: {value_collected}/{sum(VISIT_VALUES)}\\n'\n", " print(plan_output)\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "num_nodes = len(DISTANCE_MATRIX)\n", - "all_nodes = range(num_nodes)\n", - "print(f'Num nodes = {num_nodes}')\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " num_nodes = len(DISTANCE_MATRIX)\n", + " all_nodes = range(num_nodes)\n", + " print(f'Num nodes = {num_nodes}')\n", "\n", - "# Model.\n", - "model = cp_model.CpModel()\n", + " # Model.\n", + " model = cp_model.CpModel()\n", "\n", - "obj_vars = []\n", - "obj_coeffs = []\n", - "visited_nodes = []\n", - "used_arcs = {}\n", + " obj_vars = []\n", + " obj_coeffs = []\n", + " visited_nodes = []\n", + " used_arcs = {}\n", "\n", - "# Create the circuit constraint.\n", - "arcs = []\n", - "for i in all_nodes:\n", - " is_visited = model.NewBoolVar(f'{i} is visited')\n", - " arcs.append([i, i, is_visited.Not()])\n", + " # Create the circuit constraint.\n", + " arcs = []\n", + " for i in all_nodes:\n", + " is_visited = model.NewBoolVar(f'{i} is visited')\n", + " arcs.append([i, i, is_visited.Not()])\n", "\n", - " obj_vars.append(is_visited)\n", - " obj_coeffs.append(VISIT_VALUES[i])\n", - " visited_nodes.append(is_visited)\n", + " obj_vars.append(is_visited)\n", + " obj_coeffs.append(VISIT_VALUES[i])\n", + " visited_nodes.append(is_visited)\n", "\n", - " for j in all_nodes:\n", - " if i == j:\n", - " used_arcs[i, j] = is_visited.Not()\n", - " continue\n", - " arc_is_used = model.NewBoolVar(f'{j} follows {i}')\n", - " arcs.append([i, j, arc_is_used])\n", + " for j in all_nodes:\n", + " if i == j:\n", + " used_arcs[i, j] = is_visited.Not()\n", + " continue\n", + " arc_is_used = model.NewBoolVar(f'{j} follows {i}')\n", + " arcs.append([i, j, arc_is_used])\n", "\n", - " obj_vars.append(arc_is_used)\n", - " obj_coeffs.append(-DISTANCE_MATRIX[i][j])\n", - " used_arcs[i, j] = arc_is_used\n", + " obj_vars.append(arc_is_used)\n", + " obj_coeffs.append(-DISTANCE_MATRIX[i][j])\n", + " used_arcs[i, j] = arc_is_used\n", "\n", - "model.AddCircuit(arcs)\n", + " model.AddCircuit(arcs)\n", "\n", - "# Node 0 must be visited.\n", - "model.Add(visited_nodes[0] == 1)\n", + " # Node 0 must be visited.\n", + " 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", + " # 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", "\n", - "# Maximize visited node values minus the travelled distance.\n", - "model.Maximize(\n", - " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", + " # Maximize visited node values minus the travelled distance.\n", + " model.Maximize(\n", + " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", "\n", - "# Solve and print out the solution.\n", - "solver = cp_model.CpSolver()\n", - "# To benefit from the linearization of the circuit constraint.\n", - "solver.parameters.linearization_level = 2\n", - "solver.parameters.max_time_in_seconds = 15.0\n", - "#solver.parameters.log_search_progress = True\n", + " # Solve and print out the solution.\n", + " solver = cp_model.CpSolver()\n", + " # To benefit from the linearization of the circuit constraint.\n", + " solver.parameters.linearization_level = 2\n", + " solver.parameters.max_time_in_seconds = 15.0\n", + " #solver.parameters.log_search_progress = True\n", "\n", - "solver.Solve(model)\n", - "#print(solver.ResponseStats())\n", - "print_solution(solver, visited_nodes, used_arcs, num_nodes)\n", + " solver.Solve(model)\n", + " #print(solver.ResponseStats())\n", + " print_solution(solver, visited_nodes, used_arcs, num_nodes)\n", "\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/prize_collecting_vrp.ipynb b/examples/notebook/examples/prize_collecting_vrp.ipynb index bf5d70e1a9..22dc55b39a 100644 --- a/examples/notebook/examples/prize_collecting_vrp.ipynb +++ b/examples/notebook/examples/prize_collecting_vrp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple prize collecting VRP problem with a max distance.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Simple prize collecting VRP problem with a max distance.\"\"\"\n", - "\n", "from ortools.constraint_solver import routing_enums_pb2\n", "from ortools.constraint_solver import pywrapcp\n", "\n", @@ -179,67 +172,71 @@ " print(f'Total Value collected: {total_value_collected}/{sum(VISIT_VALUES)}')\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "num_nodes = len(DISTANCE_MATRIX)\n", - "print(f'Num nodes = {num_nodes}')\n", - "num_vehicles = 4\n", - "depot = 0\n", - "all_nodes = range(num_nodes)\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " num_nodes = len(DISTANCE_MATRIX)\n", + " print(f'Num nodes = {num_nodes}')\n", + " num_vehicles = 4\n", + " depot = 0\n", + " all_nodes = range(num_nodes)\n", "\n", - "# Create the routing index manager.\n", - "manager = pywrapcp.RoutingIndexManager(\n", - " num_nodes,\n", - " num_vehicles,\n", - " depot)\n", + " # Create the routing index manager.\n", + " manager = pywrapcp.RoutingIndexManager(\n", + " num_nodes,\n", + " num_vehicles,\n", + " depot)\n", "\n", - "# Create routing model.\n", - "routing = pywrapcp.RoutingModel(manager)\n", + " # Create routing model.\n", + " routing = pywrapcp.RoutingModel(manager)\n", "\n", - "# Create and register a transit callback.\n", - "def distance_callback(from_index, to_index):\n", - " \"\"\"Returns the distance between the two nodes.\"\"\"\n", - " # Convert from routing variable Index to distance matrix NodeIndex.\n", - " from_node = manager.IndexToNode(from_index)\n", - " to_node = manager.IndexToNode(to_index)\n", - " return DISTANCE_MATRIX[from_node][to_node]\n", + " # Create and register a transit callback.\n", + " def distance_callback(from_index, to_index):\n", + " \"\"\"Returns the distance between the two nodes.\"\"\"\n", + " # Convert from routing variable Index to distance matrix NodeIndex.\n", + " from_node = manager.IndexToNode(from_index)\n", + " to_node = manager.IndexToNode(to_index)\n", + " return DISTANCE_MATRIX[from_node][to_node]\n", "\n", - "transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", + " transit_callback_index = routing.RegisterTransitCallback(distance_callback)\n", "\n", - "# Define cost of each arc.\n", - "routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", + " # Define cost of each arc.\n", + " routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)\n", "\n", - "# Limit Vehicle distance.\n", - "dimension_name = 'Distance'\n", - "routing.AddDimension(\n", - " transit_callback_index,\n", - " 0, # no slack\n", - " MAX_DISTANCE, # vehicle maximum travel distance\n", - " True, # start cumul to zero\n", - " dimension_name)\n", - "distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", - "distance_dimension.SetGlobalSpanCostCoefficient(1)\n", + " # Limit Vehicle distance.\n", + " dimension_name = 'Distance'\n", + " routing.AddDimension(\n", + " transit_callback_index,\n", + " 0, # no slack\n", + " MAX_DISTANCE, # vehicle maximum travel distance\n", + " True, # start cumul to zero\n", + " dimension_name)\n", + " distance_dimension = routing.GetDimensionOrDie(dimension_name)\n", + " distance_dimension.SetGlobalSpanCostCoefficient(1)\n", "\n", - "# Allow to drop nodes.\n", - "for node in range(1, num_nodes):\n", - " routing.AddDisjunction(\n", - " [manager.NodeToIndex(node)],\n", - " VISIT_VALUES[node])\n", + " # Allow to drop nodes.\n", + " for node in range(1, num_nodes):\n", + " routing.AddDisjunction(\n", + " [manager.NodeToIndex(node)],\n", + " VISIT_VALUES[node])\n", "\n", - "# Setting first solution heuristic.\n", - "search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - "search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", - "search_parameters.local_search_metaheuristic = (\n", - " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", - "search_parameters.time_limit.FromSeconds(15)\n", - "#search_parameters.log_search = True\n", + " # Setting first solution heuristic.\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + " search_parameters.local_search_metaheuristic = (\n", + " routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH)\n", + " search_parameters.time_limit.FromSeconds(15)\n", + " #search_parameters.log_search = True\n", "\n", - "# Solve the problem.\n", - "assignment = routing.SolveWithParameters(search_parameters)\n", + " # Solve the problem.\n", + " assignment = routing.SolveWithParameters(search_parameters)\n", "\n", - "# Print solution on console.\n", - "if assignment:\n", - " print_solution(manager, routing, assignment)\n", + " # Print solution on console.\n", + " if assignment:\n", + " print_solution(manager, routing, assignment)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/prize_collecting_vrp_sat.ipynb b/examples/notebook/examples/prize_collecting_vrp_sat.ipynb index 8b8341576c..ee6af4dbcb 100644 --- a/examples/notebook/examples/prize_collecting_vrp_sat.ipynb +++ b/examples/notebook/examples/prize_collecting_vrp_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple prize collecting TSP problem with a max distance.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Simple prize collecting TSP problem with a max distance.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "DISTANCE_MATRIX = [\n", @@ -182,73 +175,77 @@ " print(f'Total Distance: {total_distance}m')\n", " print(f'Total Value collected: {total_value_collected}/{sum(VISIT_VALUES)}')\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "num_nodes = len(DISTANCE_MATRIX)\n", - "num_vehicles = 4\n", - "print(f'Num nodes = {num_nodes}')\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " num_nodes = len(DISTANCE_MATRIX)\n", + " num_vehicles = 4\n", + " print(f'Num nodes = {num_nodes}')\n", "\n", - "# Model.\n", - "model = cp_model.CpModel()\n", + " # Model.\n", + " model = cp_model.CpModel()\n", "\n", - "obj_vars = []\n", - "obj_coeffs = []\n", - "visited_nodes = {}\n", - "used_arcs = {}\n", + " obj_vars = []\n", + " obj_coeffs = []\n", + " visited_nodes = {}\n", + " used_arcs = {}\n", "\n", - "# Create the circuit constraint.\n", - "all_nodes = range(num_nodes)\n", - "for v in range(num_vehicles):\n", - " visited_nodes[v] = []\n", - " used_arcs[v] = {}\n", - " arcs = []\n", - " for i in all_nodes:\n", - " is_visited = model.NewBoolVar(f'{i} is visited')\n", - " arcs.append([i, i, is_visited.Not()])\n", + " # Create the circuit constraint.\n", + " all_nodes = range(num_nodes)\n", + " for v in range(num_vehicles):\n", + " visited_nodes[v] = []\n", + " used_arcs[v] = {}\n", + " arcs = []\n", + " for i in all_nodes:\n", + " is_visited = model.NewBoolVar(f'{i} is visited')\n", + " arcs.append([i, i, is_visited.Not()])\n", "\n", - " obj_vars.append(is_visited)\n", - " obj_coeffs.append(VISIT_VALUES[i])\n", - " visited_nodes[v].append(is_visited)\n", + " obj_vars.append(is_visited)\n", + " obj_coeffs.append(VISIT_VALUES[i])\n", + " visited_nodes[v].append(is_visited)\n", "\n", - " for j in all_nodes:\n", - " if i == j:\n", - " used_arcs[v][i, j] = is_visited.Not()\n", - " continue\n", - " arc_is_used = model.NewBoolVar(f'{j} follows {i}')\n", - " arcs.append([i, j, arc_is_used])\n", + " for j in all_nodes:\n", + " if i == j:\n", + " used_arcs[v][i, j] = is_visited.Not()\n", + " continue\n", + " arc_is_used = model.NewBoolVar(f'{j} follows {i}')\n", + " arcs.append([i, j, arc_is_used])\n", "\n", - " obj_vars.append(arc_is_used)\n", - " obj_coeffs.append(-DISTANCE_MATRIX[i][j])\n", - " used_arcs[v][i, j] = arc_is_used\n", + " obj_vars.append(arc_is_used)\n", + " obj_coeffs.append(-DISTANCE_MATRIX[i][j])\n", + " used_arcs[v][i, j] = arc_is_used\n", "\n", - " model.AddCircuit(arcs)\n", + " model.AddCircuit(arcs)\n", "\n", - " # Node 0 must be visited.\n", - " model.Add(visited_nodes[v][0] == 1)\n", + " # Node 0 must be visited.\n", + " 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", + " # 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", "\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", + " # 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", "\n", - "# Maximize visited node values minus the travelled distance.\n", - "model.Maximize(\n", - " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", + " # Maximize visited node values minus the travelled distance.\n", + " model.Maximize(\n", + " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", "\n", - "# Solve and print out the solution.\n", - "solver = cp_model.CpSolver()\n", - "# To benefit from the linearization of the circuit constraint.\n", - "solver.parameters.linearization_level = 2\n", - "solver.parameters.max_time_in_seconds = 15.0\n", - "#solver.parameters.log_search_progress = True\n", + " # Solve and print out the solution.\n", + " solver = cp_model.CpSolver()\n", + " # To benefit from the linearization of the circuit constraint.\n", + " solver.parameters.linearization_level = 2\n", + " solver.parameters.max_time_in_seconds = 15.0\n", + " #solver.parameters.log_search_progress = True\n", "\n", - "solver.Solve(model)\n", - "#print(solver.ResponseStats())\n", - "print_solution(solver, visited_nodes, used_arcs, num_nodes, num_vehicles)\n", + " solver.Solve(model)\n", + " #print(solver.ResponseStats())\n", + " print_solution(solver, visited_nodes, used_arcs, num_nodes, num_vehicles)\n", "\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/pyflow_example.ipynb b/examples/notebook/examples/pyflow_example.ipynb index 470d57e35e..13d87c57df 100644 --- a/examples/notebook/examples/pyflow_example.ipynb +++ b/examples/notebook/examples/pyflow_example.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "MaxFlow and MinCostFlow examples.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,22 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"MaxFlow and MinCostFlow examples.\"\"\"\n", - "\n", - "from absl import app\n", "from ortools.graph.python import max_flow\n", "from ortools.graph.python import min_cost_flow\n", "\n", @@ -148,8 +140,12 @@ " print('There was an issue with the min cost flow input.')\n", "\n", "\n", - "MaxFlow()\n", - "MinCostFlow()\n", + "def main(_):\n", + " MaxFlow()\n", + " MinCostFlow()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/qubo_sat.ipynb b/examples/notebook/examples/qubo_sat.ipynb index 73c72414ab..486bc51f93 100644 --- a/examples/notebook/examples/qubo_sat.ipynb +++ b/examples/notebook/examples/qubo_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves a Qubo program using the CP-SAT solver.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,9 +83,6 @@ "metadata": {}, "outputs": [], "source": [ - "\"\"\"Solves a Qubo program using the CP-SAT solver.\"\"\"\n", - "\n", - "\n", "import time\n", "\n", "from ortools.sat.python import cp_model\n", @@ -653,7 +659,9 @@ " solver.parameters.log_search_progress = True\n", " solver.Solve(model)\n", "\n", - "\n" + "\n", + "solve_qubo()\n", + " \n" ] } ], diff --git a/examples/notebook/examples/random_tsp.ipynb b/examples/notebook/examples/random_tsp.ipynb index 2613492a52..4e1942aef7 100644 --- a/examples/notebook/examples/random_tsp.ipynb +++ b/examples/notebook/examples/random_tsp.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,25 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Traveling Salesman Sample.\n", + "Traveling Salesman Sample.\n", "\n", " This is a sample using the routing library python wrapper to solve a\n", " Traveling Salesman Problem.\n", @@ -96,8 +82,16 @@ " solutions being generated using a cheapest addition heuristic.\n", " Optionally one can randomly forbid a set of random connections between nodes\n", " (forbidden arcs).\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import argparse\n", "from functools import partial\n", "import random\n", @@ -160,63 +154,67 @@ " to_index)]\n", "\n", "\n", - "# Create routing model\n", - "if args.tsp_size > 0:\n", - " # TSP of size args.tsp_size\n", - " # Second argument = 1 to build a single tour (it's a TSP).\n", - " # Nodes are indexed from 0 to args_tsp_size - 1, by default the start of\n", - " # the route is node 0.\n", - " manager = pywrapcp.RoutingIndexManager(args.tsp_size, 1, 0)\n", - " routing = pywrapcp.RoutingModel(manager)\n", - " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", - " # Setting first solution heuristic (cheapest addition).\n", - " search_parameters.first_solution_strategy = (\n", - " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", + "def main(args):\n", + " # Create routing model\n", + " if args.tsp_size > 0:\n", + " # TSP of size args.tsp_size\n", + " # Second argument = 1 to build a single tour (it's a TSP).\n", + " # Nodes are indexed from 0 to args_tsp_size - 1, by default the start of\n", + " # the route is node 0.\n", + " manager = pywrapcp.RoutingIndexManager(args.tsp_size, 1, 0)\n", + " routing = pywrapcp.RoutingModel(manager)\n", + " search_parameters = pywrapcp.DefaultRoutingSearchParameters()\n", + " # Setting first solution heuristic (cheapest addition).\n", + " search_parameters.first_solution_strategy = (\n", + " routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)\n", "\n", - " # Setting the cost function.\n", - " # Put a callback to the distance accessor here. The callback takes two\n", - " # arguments (the from and to node indices) and returns the distance between\n", - " # these indices.\n", - " cost = 0\n", - " if args.tsp_use_random_matrix:\n", - " matrix = RandomMatrix(args.tsp_size, args.tsp_random_seed)\n", - " cost = routing.RegisterTransitCallback(\n", - " partial(matrix.Distance, manager))\n", - " else:\n", - " cost = routing.RegisterTransitCallback(partial(Distance, manager))\n", - " routing.SetArcCostEvaluatorOfAllVehicles(cost)\n", - " # Forbid node connections (randomly).\n", - " rand = random.Random()\n", - " rand.seed(args.tsp_random_seed)\n", - " forbidden_connections = 0\n", - " while forbidden_connections < args.tsp_random_forbidden_connections:\n", - " from_node = rand.randrange(args.tsp_size - 1)\n", - " to_node = rand.randrange(args.tsp_size - 1) + 1\n", - " if routing.NextVar(from_node).Contains(to_node):\n", - " print('Forbidding connection ' + str(from_node) + ' -> ' +\n", - " str(to_node))\n", - " routing.NextVar(from_node).RemoveValue(to_node)\n", - " forbidden_connections += 1\n", + " # Setting the cost function.\n", + " # Put a callback to the distance accessor here. The callback takes two\n", + " # arguments (the from and to node indices) and returns the distance between\n", + " # these indices.\n", + " cost = 0\n", + " if args.tsp_use_random_matrix:\n", + " matrix = RandomMatrix(args.tsp_size, args.tsp_random_seed)\n", + " cost = routing.RegisterTransitCallback(\n", + " partial(matrix.Distance, manager))\n", + " else:\n", + " cost = routing.RegisterTransitCallback(partial(Distance, manager))\n", + " routing.SetArcCostEvaluatorOfAllVehicles(cost)\n", + " # Forbid node connections (randomly).\n", + " rand = random.Random()\n", + " rand.seed(args.tsp_random_seed)\n", + " forbidden_connections = 0\n", + " while forbidden_connections < args.tsp_random_forbidden_connections:\n", + " from_node = rand.randrange(args.tsp_size - 1)\n", + " to_node = rand.randrange(args.tsp_size - 1) + 1\n", + " if routing.NextVar(from_node).Contains(to_node):\n", + " print('Forbidding connection ' + str(from_node) + ' -> ' +\n", + " str(to_node))\n", + " routing.NextVar(from_node).RemoveValue(to_node)\n", + " forbidden_connections += 1\n", "\n", - " # Solve, returns a solution if any.\n", - " assignment = routing.Solve()\n", - " if assignment:\n", - " # Solution cost.\n", - " print(assignment.ObjectiveValue())\n", - " # Inspect solution.\n", - " # Only one route here; otherwise iterate from 0 to routing.vehicles() - 1\n", - " route_number = 0\n", - " node = routing.Start(route_number)\n", - " route = ''\n", - " while not routing.IsEnd(node):\n", - " route += str(node) + ' -> '\n", - " node = assignment.Value(routing.NextVar(node))\n", - " route += '0'\n", - " print(route)\n", + " # Solve, returns a solution if any.\n", + " assignment = routing.Solve()\n", + " if assignment:\n", + " # Solution cost.\n", + " print(assignment.ObjectiveValue())\n", + " # Inspect solution.\n", + " # Only one route here; otherwise iterate from 0 to routing.vehicles() - 1\n", + " route_number = 0\n", + " node = routing.Start(route_number)\n", + " route = ''\n", + " while not routing.IsEnd(node):\n", + " route += str(node) + ' -> '\n", + " node = assignment.Value(routing.NextVar(node))\n", + " route += '0'\n", + " print(route)\n", + " else:\n", + " print('No solution found.')\n", " else:\n", - " print('No solution found.')\n", - "else:\n", - " print('Specify an instance greater than 0.')\n", + " print('Specify an instance greater than 0.')\n", + "\n", + "\n", + "main(parser.parse_args())\n", "\n" ] } diff --git a/examples/notebook/examples/rcpsp_sat.ipynb b/examples/notebook/examples/rcpsp_sat.ipynb index 26a4fbe613..03205b7d8d 100644 --- a/examples/notebook/examples/rcpsp_sat.ipynb +++ b/examples/notebook/examples/rcpsp_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Sat based solver for the RCPSP problems (see rcpsp.proto).\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,42 +82,20 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Sat based solver for the RCPSP problems (see rcpsp.proto).\"\"\"\n", - "\n", "import collections\n", "\n", - "from absl import app\n", - "from absl import flags\n", "from google.protobuf import text_format\n", "from ortools.sat.python import cp_model\n", "from ortools.scheduling import pywraprcpsp\n", "\n", - "FLAGS = flags.FLAGS\n", - "\n", - "flags.DEFINE_string('input', '', 'Input file to parse and solve.')\n", - "flags.DEFINE_string('output_proto', '',\n", - " 'Output file to write the cp_model proto to.')\n", - "flags.DEFINE_string('params', '', 'Sat solver parameters.')\n", - "flags.DEFINE_bool('use_interval_makespan', True,\n", - " 'Whether we encode the makespan using an interval or not.')\n", - "flags.DEFINE_integer('horizon', -1, 'Force horizon.')\n", - "flags.DEFINE_bool(\n", - " 'use_main_interval_for_tasks', True,\n", - " 'Creates a main interval for each task, and use it in precedences')\n", + "class FLAGS: pass\n", "\n", + "FLAGS.input = '' # Input file to parse and solve.\n", + "FLAGS.output_proto = '' # Output file to write the cp_model proto to.\n", + "FLAGS.params = '' # Sat solver parameters.\n", + "FLAGS.use_interval_makespan = True # Whether we encode the makespan using an interval or not.\n", + "FLAGS.horizon = -1 # Force horizon.\n", + "FLAGS.use_main_interval_for_tasks = True # Creates a main interval for each task, and use it in precedences\n", "\n", "def PrintProblemStatistics(problem):\n", " \"\"\"Display various statistics on the problem.\"\"\"\n", @@ -381,9 +367,13 @@ " solver.Solve(model)\n", "\n", "\n", - "rcpsp_parser = pywraprcpsp.RcpspParser()\n", - "rcpsp_parser.ParseFile(FLAGS.input)\n", - "SolveRcpsp(rcpsp_parser.Problem(), FLAGS.output_proto, FLAGS.params)\n", + "def main(_):\n", + " rcpsp_parser = pywraprcpsp.RcpspParser()\n", + " rcpsp_parser.ParseFile(FLAGS.input)\n", + " SolveRcpsp(rcpsp_parser.Problem(), FLAGS.output_proto, FLAGS.params)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/reallocate_sat.ipynb b/examples/notebook/examples/reallocate_sat.ipynb index 71e46b3206..8f60a38450 100644 --- a/examples/notebook/examples/reallocate_sat.ipynb +++ b/examples/notebook/examples/reallocate_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Reallocate production to smooth it over years.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,137 +83,126 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Reallocate production to smooth it over years.\"\"\"\n", - "\n", - "\n", "import collections\n", "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", + "def main():\n", "\n", - "# Data\n", - "data_0 = [\n", - " [107, 107, 107, 0, 0], # pr1\n", - " [0, 47, 47, 47, 0], # pr2\n", - " [10, 10, 10, 0, 0], # pr3\n", - " [0, 55, 55, 55, 55], # pr4\n", - "]\n", + " # Data\n", + " data_0 = [\n", + " [107, 107, 107, 0, 0], # pr1\n", + " [0, 47, 47, 47, 0], # pr2\n", + " [10, 10, 10, 0, 0], # pr3\n", + " [0, 55, 55, 55, 55], # pr4\n", + " ]\n", "\n", - "data_1 = [\n", - " [119444030, 0, 0, 0],\n", - " [34585586, 38358559, 31860661, 0],\n", - " [19654655, 21798799, 18106106, 0],\n", - " [298836792, 0, 0, 0],\n", - " [3713428, 4118530, 4107277, 3072018],\n", - " [6477273, 7183884, 5358471, 0],\n", - " [1485371, 1647412, 1642911, 1228807]\n", - "]\n", + " data_1 = [\n", + " [119444030, 0, 0, 0],\n", + " [34585586, 38358559, 31860661, 0],\n", + " [19654655, 21798799, 18106106, 0],\n", + " [298836792, 0, 0, 0],\n", + " [3713428, 4118530, 4107277, 3072018],\n", + " [6477273, 7183884, 5358471, 0],\n", + " [1485371, 1647412, 1642911, 1228807]\n", + " ]\n", "\n", - "data_2 = [\n", - " [1194440, 0, 0, 0],\n", - " [345855, 383585, 318606, 0],\n", - " [196546, 217987, 181061, 0],\n", - " [2988367, 0, 0, 0],\n", - " [37134, 41185, 41072, 30720],\n", - " [64772, 71838, 53584, 0],\n", - " [14853, 16474, 16429, 12288]\n", - "]\n", + " data_2 = [\n", + " [1194440, 0, 0, 0],\n", + " [345855, 383585, 318606, 0],\n", + " [196546, 217987, 181061, 0],\n", + " [2988367, 0, 0, 0],\n", + " [37134, 41185, 41072, 30720],\n", + " [64772, 71838, 53584, 0],\n", + " [14853, 16474, 16429, 12288]\n", + " ]\n", "\n", - "pr = data_0\n", + " pr = data_0\n", "\n", - "num_pr = len(pr)\n", - "num_years = len(pr[1])\n", - "total = sum(pr[p][y] for p in range(num_pr) for y in range(num_years))\n", - "avg = total // num_years\n", + " num_pr = len(pr)\n", + " num_years = len(pr[1])\n", + " total = sum(pr[p][y] for p in range(num_pr) for y in range(num_years))\n", + " avg = total // num_years\n", "\n", - "# Model\n", - "model = cp_model.CpModel()\n", + " # Model\n", + " model = cp_model.CpModel()\n", "\n", - "# Variables\n", - "delta = model.NewIntVar(0, total, 'delta')\n", + " # Variables\n", + " delta = model.NewIntVar(0, total, 'delta')\n", "\n", - "contributions_per_years = collections.defaultdict(list)\n", - "contributions_per_prs = collections.defaultdict(list)\n", - "all_contribs = {}\n", + " contributions_per_years = collections.defaultdict(list)\n", + " contributions_per_prs = collections.defaultdict(list)\n", + " all_contribs = {}\n", "\n", - "for p, inner_l in enumerate(pr):\n", - " for y, item in enumerate(inner_l):\n", - " if item != 0:\n", - " contrib = model.NewIntVar(0, total, 'r%d c%d' % (p, y))\n", - " contributions_per_years[y].append(contrib)\n", - " contributions_per_prs[p].append(contrib)\n", - " all_contribs[p, y] = contrib\n", + " for p, inner_l in enumerate(pr):\n", + " for y, item in enumerate(inner_l):\n", + " if item != 0:\n", + " contrib = model.NewIntVar(0, total, 'r%d c%d' % (p, y))\n", + " contributions_per_years[y].append(contrib)\n", + " contributions_per_prs[p].append(contrib)\n", + " all_contribs[p, y] = contrib\n", "\n", - "year_var = [\n", - " model.NewIntVar(0, total, 'y[%i]' % i) for i in range(num_years)\n", - "]\n", + " year_var = [\n", + " model.NewIntVar(0, total, 'y[%i]' % i) for i in range(num_years)\n", + " ]\n", "\n", - "# Constraints\n", + " # Constraints\n", "\n", - "# Maintain year_var.\n", - "for y in range(num_years):\n", - " model.Add(year_var[y] == sum(contributions_per_years[y]))\n", + " # Maintain year_var.\n", + " for y in range(num_years):\n", + " model.Add(year_var[y] == sum(contributions_per_years[y]))\n", "\n", - "# Fixed contributions per pr.\n", - "for p in range(num_pr):\n", - " model.Add(sum(pr[p]) == sum(contributions_per_prs[p]))\n", - "\n", - "# Link delta with variables.\n", - "for y in range(num_years):\n", - " model.Add(year_var[y] >= avg - delta)\n", - "\n", - "for y in range(num_years):\n", - " model.Add(year_var[y] <= avg + delta)\n", - "\n", - "# Solve and output\n", - "model.Minimize(delta)\n", - "\n", - "# Solve model.\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "\n", - "# Output solution.\n", - "if status == cp_model.OPTIMAL:\n", - " print('Data')\n", - " print(' - total = ', total)\n", - " print(' - year_average = ', avg)\n", - " print(' - number of projects = ', num_pr)\n", - " print(' - number of years = ', num_years)\n", - "\n", - " print(' - input production')\n", + " # Fixed contributions per pr.\n", " for p in range(num_pr):\n", - " for y in range(num_years):\n", - " if pr[p][y] == 0:\n", - " print(' ', end='')\n", - " else:\n", - " print('%10i' % pr[p][y], end='')\n", - " print()\n", + " model.Add(sum(pr[p]) == sum(contributions_per_prs[p]))\n", "\n", - " print('Solution')\n", - " for p in range(num_pr):\n", - " for y in range(num_years):\n", - " if pr[p][y] == 0:\n", - " print(' ', end='')\n", - " else:\n", - " print('%10i' % solver.Value(all_contribs[p, y]), end='')\n", - " print()\n", + " # Link delta with variables.\n", + " for y in range(num_years):\n", + " model.Add(year_var[y] >= avg - delta)\n", "\n", " for y in range(num_years):\n", - " print('%10i' % solver.Value(year_var[y]), end='')\n", - " print()\n", + " model.Add(year_var[y] <= avg + delta)\n", + "\n", + " # Solve and output\n", + " model.Minimize(delta)\n", + "\n", + " # Solve model.\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", + "\n", + " # Output solution.\n", + " if status == cp_model.OPTIMAL:\n", + " print('Data')\n", + " print(' - total = ', total)\n", + " print(' - year_average = ', avg)\n", + " print(' - number of projects = ', num_pr)\n", + " print(' - number of years = ', num_years)\n", + "\n", + " print(' - input production')\n", + " for p in range(num_pr):\n", + " for y in range(num_years):\n", + " if pr[p][y] == 0:\n", + " print(' ', end='')\n", + " else:\n", + " print('%10i' % pr[p][y], end='')\n", + " print()\n", + "\n", + " print('Solution')\n", + " for p in range(num_pr):\n", + " for y in range(num_years):\n", + " if pr[p][y] == 0:\n", + " print(' ', end='')\n", + " else:\n", + " print('%10i' % solver.Value(all_contribs[p, y]), end='')\n", + " print()\n", + "\n", + " for y in range(num_years):\n", + " print('%10i' % solver.Value(year_var[y]), end='')\n", + " print()\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/shift_scheduling_sat.ipynb b/examples/notebook/examples/shift_scheduling_sat.ipynb index 33e40a90a7..518f7ddfcc 100644 --- a/examples/notebook/examples/shift_scheduling_sat.ipynb +++ b/examples/notebook/examples/shift_scheduling_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Creates a shift scheduling problem and solves it.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,34 +82,13 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Creates a shift scheduling problem and solves it.\"\"\"\n", - "\n", - "from absl import app\n", - "from absl import flags\n", - "\n", - "from ortools.sat.python import cp_model\n", "from google.protobuf import text_format\n", + "from ortools.sat.python import cp_model\n", "\n", - "FLAGS = flags.FLAGS\n", - "\n", - "flags.DEFINE_string('output_proto', '',\n", - " 'Output file to write the cp_model proto to.')\n", - "flags.DEFINE_string('params', 'max_time_in_seconds:10.0',\n", - " 'Sat solver parameters.')\n", + "class FLAGS: pass\n", "\n", + "FLAGS.output_proto = '' # Output file to write the cp_model proto to.\n", + "FLAGS.params = 'max_time_in_seconds:10.0' # Sat solver parameters.\n", "\n", "def negated_bounded_span(works, start, length):\n", " \"\"\"Filters an isolated sub-sequence of variables assined to True.\n", @@ -496,7 +483,11 @@ " print(' - wall time : %f s' % solver.WallTime())\n", "\n", "\n", - "solve_shift_scheduling(FLAGS.params, FLAGS.output_proto)\n", + "def main(_):\n", + " solve_shift_scheduling(FLAGS.params, FLAGS.output_proto)\n", + "\n", + "\n", + "main()\n", "\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 83da089ad4..da797e6373 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 @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Single machine jobshop with setup times, release dates and due dates.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,20 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Single machine jobshop with setup times, release dates and due dates.\"\"\"\n", - "\n", "import argparse\n", "\n", "from google.protobuf import text_format\n", @@ -125,225 +119,229 @@ " self.__solution_count += 1\n", "\n", "\n", - "\"\"\"Solves a complex single machine jobshop scheduling problem.\"\"\"\n", + "def main(args):\n", + " \"\"\"Solves a complex single machine jobshop scheduling problem.\"\"\"\n", "\n", - "parameters = args.params\n", - "output_proto_file = args.output_proto_file\n", + " parameters = args.params\n", + " output_proto_file = args.output_proto_file\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Data.\n", + " #----------------------------------------------------------------------------\n", + " # Data.\n", "\n", - "job_durations = [\n", - " 2546, 8589, 5953, 3710, 3630, 3016, 4148, 8706, 1604, 5502, 9983, 6209,\n", - " 9920, 7860, 2176\n", - "]\n", + " job_durations = [\n", + " 2546, 8589, 5953, 3710, 3630, 3016, 4148, 8706, 1604, 5502, 9983, 6209,\n", + " 9920, 7860, 2176\n", + " ]\n", "\n", - "setup_times = [\n", - " [\n", - " 3559, 1638, 2000, 3676, 2741, 2439, 2406, 1526, 1600, 3356, 4324,\n", - " 1923, 3663, 4103, 2215\n", - " ],\n", - " [\n", - " 1442, 3010, 1641, 4490, 2060, 2143, 3376, 3891, 3513, 2855, 2653,\n", - " 1471, 2257, 1186, 2354\n", - " ],\n", - " [\n", - " 1728, 3583, 3243, 4080, 2191, 3644, 4023, 3510, 2135, 1346, 1410,\n", - " 3565, 3181, 1126, 4169\n", - " ],\n", - " [\n", - " 1291, 1703, 3103, 4001, 1712, 1137, 3341, 3485, 2557, 2435, 1972,\n", - " 1986, 1522, 4734, 2520\n", - " ],\n", - " [\n", - " 4134, 2200, 1502, 3995, 1277, 1808, 1020, 2078, 2999, 1605, 1697,\n", - " 2323, 2268, 2288, 4856\n", - " ],\n", - " [\n", - " 4974, 2480, 2492, 4088, 2587, 4652, 1478, 3942, 1222, 3305, 1206,\n", - " 1024, 2605, 3080, 3516\n", - " ],\n", - " [\n", - " 1903, 2584, 2104, 1609, 4745, 2691, 1539, 2544, 2499, 2074, 4793,\n", - " 1756, 2190, 1298, 2605\n", - " ],\n", - " [\n", - " 1407, 2536, 2296, 1769, 1449, 3386, 3046, 1180, 4132, 4783, 3386,\n", - " 3429, 2450, 3376, 3719\n", - " ],\n", - " [\n", - " 3026, 1637, 3628, 3096, 1498, 4947, 1912, 3703, 4107, 4730, 1805,\n", - " 2189, 1789, 1985, 3586\n", - " ],\n", - " [\n", - " 3940, 1342, 1601, 2737, 1748, 3771, 4052, 1619, 2558, 3782, 4383,\n", - " 3451, 4904, 1108, 1750\n", - " ],\n", - " [\n", - " 1348, 3162, 1507, 3936, 1453, 2953, 4182, 2968, 3134, 1042, 3175,\n", - " 2805, 4901, 1735, 1654\n", - " ],\n", - " [\n", - " 1099, 1711, 1245, 1067, 4343, 3407, 1108, 1784, 4803, 2342, 3377,\n", - " 2037, 3563, 1621, 2840\n", - " ],\n", - " [\n", - " 2573, 4222, 3164, 2563, 3231, 4731, 2395, 1033, 4795, 3288, 2335,\n", - " 4935, 4066, 1440, 4979\n", - " ],\n", - " [\n", - " 3321, 1666, 3573, 2377, 4649, 4600, 1065, 2475, 3658, 3374, 1138,\n", - " 4367, 4728, 3032, 2198\n", - " ],\n", - " [\n", - " 2986, 1180, 4095, 3132, 3987, 3880, 3526, 1460, 4885, 3827, 4945,\n", - " 4419, 3486, 3805, 3804\n", - " ],\n", - " [\n", - " 4163, 3441, 1217, 2941, 1210, 3794, 1779, 1904, 4255, 4967, 4003,\n", - " 3873, 1002, 2055, 4295\n", - " ],\n", - "]\n", + " setup_times = [\n", + " [\n", + " 3559, 1638, 2000, 3676, 2741, 2439, 2406, 1526, 1600, 3356, 4324,\n", + " 1923, 3663, 4103, 2215\n", + " ],\n", + " [\n", + " 1442, 3010, 1641, 4490, 2060, 2143, 3376, 3891, 3513, 2855, 2653,\n", + " 1471, 2257, 1186, 2354\n", + " ],\n", + " [\n", + " 1728, 3583, 3243, 4080, 2191, 3644, 4023, 3510, 2135, 1346, 1410,\n", + " 3565, 3181, 1126, 4169\n", + " ],\n", + " [\n", + " 1291, 1703, 3103, 4001, 1712, 1137, 3341, 3485, 2557, 2435, 1972,\n", + " 1986, 1522, 4734, 2520\n", + " ],\n", + " [\n", + " 4134, 2200, 1502, 3995, 1277, 1808, 1020, 2078, 2999, 1605, 1697,\n", + " 2323, 2268, 2288, 4856\n", + " ],\n", + " [\n", + " 4974, 2480, 2492, 4088, 2587, 4652, 1478, 3942, 1222, 3305, 1206,\n", + " 1024, 2605, 3080, 3516\n", + " ],\n", + " [\n", + " 1903, 2584, 2104, 1609, 4745, 2691, 1539, 2544, 2499, 2074, 4793,\n", + " 1756, 2190, 1298, 2605\n", + " ],\n", + " [\n", + " 1407, 2536, 2296, 1769, 1449, 3386, 3046, 1180, 4132, 4783, 3386,\n", + " 3429, 2450, 3376, 3719\n", + " ],\n", + " [\n", + " 3026, 1637, 3628, 3096, 1498, 4947, 1912, 3703, 4107, 4730, 1805,\n", + " 2189, 1789, 1985, 3586\n", + " ],\n", + " [\n", + " 3940, 1342, 1601, 2737, 1748, 3771, 4052, 1619, 2558, 3782, 4383,\n", + " 3451, 4904, 1108, 1750\n", + " ],\n", + " [\n", + " 1348, 3162, 1507, 3936, 1453, 2953, 4182, 2968, 3134, 1042, 3175,\n", + " 2805, 4901, 1735, 1654\n", + " ],\n", + " [\n", + " 1099, 1711, 1245, 1067, 4343, 3407, 1108, 1784, 4803, 2342, 3377,\n", + " 2037, 3563, 1621, 2840\n", + " ],\n", + " [\n", + " 2573, 4222, 3164, 2563, 3231, 4731, 2395, 1033, 4795, 3288, 2335,\n", + " 4935, 4066, 1440, 4979\n", + " ],\n", + " [\n", + " 3321, 1666, 3573, 2377, 4649, 4600, 1065, 2475, 3658, 3374, 1138,\n", + " 4367, 4728, 3032, 2198\n", + " ],\n", + " [\n", + " 2986, 1180, 4095, 3132, 3987, 3880, 3526, 1460, 4885, 3827, 4945,\n", + " 4419, 3486, 3805, 3804\n", + " ],\n", + " [\n", + " 4163, 3441, 1217, 2941, 1210, 3794, 1779, 1904, 4255, 4967, 4003,\n", + " 3873, 1002, 2055, 4295\n", + " ],\n", + " ]\n", "\n", - "due_dates = [\n", - " -1, -1, 28569, -1, 98104, 27644, 55274, 57364, -1, -1, 60875, 96637,\n", - " 77888, -1, -1\n", - "]\n", - "release_dates = [\n", - " 0, 0, 0, 0, 19380, 0, 0, 48657, 0, 27932, 0, 0, 24876, 0, 0\n", - "]\n", + " due_dates = [\n", + " -1, -1, 28569, -1, 98104, 27644, 55274, 57364, -1, -1, 60875, 96637,\n", + " 77888, -1, -1\n", + " ]\n", + " release_dates = [\n", + " 0, 0, 0, 0, 19380, 0, 0, 48657, 0, 27932, 0, 0, 24876, 0, 0\n", + " ]\n", "\n", - "precedences = [(0, 2), (1, 2)]\n", + " precedences = [(0, 2), (1, 2)]\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Helper data.\n", - "num_jobs = len(job_durations)\n", - "all_jobs = range(num_jobs)\n", + " #----------------------------------------------------------------------------\n", + " # Helper data.\n", + " num_jobs = len(job_durations)\n", + " all_jobs = range(num_jobs)\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Preprocess.\n", - "if args.preprocess_times:\n", + " #----------------------------------------------------------------------------\n", + " # Preprocess.\n", + " if args.preprocess_times:\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", + " if release_dates[job_id] != 0:\n", + " min_incoming_setup = min(min_incoming_setup,\n", + " release_dates[job_id])\n", + " if min_incoming_setup == 0:\n", + " continue\n", + "\n", + " print('job %i has a min incoming setup of %i' %\n", + " (job_id, min_incoming_setup))\n", + " # We can transfer some setup times to the duration of the job.\n", + " job_durations[job_id] += min_incoming_setup\n", + " # Decrease corresponding incoming setup times.\n", + " for j in range(num_jobs + 1):\n", + " setup_times[j][job_id] -= min_incoming_setup\n", + " # Adjust release dates if needed.\n", + " if release_dates[job_id] != 0:\n", + " release_dates[job_id] -= min_incoming_setup\n", + "\n", + " #----------------------------------------------------------------------------\n", + " # Model.\n", + " model = cp_model.CpModel()\n", + "\n", + " #----------------------------------------------------------------------------\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", + " for j in range(num_jobs))\n", + " print('Greedy horizon =', horizon)\n", + "\n", + " #----------------------------------------------------------------------------\n", + " # Global storage of variables.\n", + " intervals = []\n", + " starts = []\n", + " ends = []\n", + "\n", + " #----------------------------------------------------------------------------\n", + " # Scan the jobs and create the relevant variables and intervals.\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", - " if release_dates[job_id] != 0:\n", - " min_incoming_setup = min(min_incoming_setup,\n", - " release_dates[job_id])\n", - " if min_incoming_setup == 0:\n", - " continue\n", + " duration = job_durations[job_id]\n", + " release_date = release_dates[job_id]\n", + " due_date = due_dates[job_id] if due_dates[job_id] != -1 else horizon\n", + " print('job %2i: start = %5i, duration = %4i, end = %6i' %\n", + " (job_id, release_date, duration, due_date))\n", + " name_suffix = '_%i' % job_id\n", + " start = model.NewIntVar(release_date, due_date, 's' + name_suffix)\n", + " end = model.NewIntVar(release_date, due_date, 'e' + name_suffix)\n", + " interval = model.NewIntervalVar(start, duration, end, 'i' + name_suffix)\n", + " starts.append(start)\n", + " ends.append(end)\n", + " intervals.append(interval)\n", "\n", - " print('job %i has a min incoming setup of %i' %\n", - " (job_id, min_incoming_setup))\n", - " # We can transfer some setup times to the duration of the job.\n", - " job_durations[job_id] += min_incoming_setup\n", - " # Decrease corresponding incoming setup times.\n", - " for j in range(num_jobs + 1):\n", - " setup_times[j][job_id] -= min_incoming_setup\n", - " # Adjust release dates if needed.\n", - " if release_dates[job_id] != 0:\n", - " release_dates[job_id] -= min_incoming_setup\n", + " # No overlap constraint.\n", + " model.AddNoOverlap(intervals)\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Model.\n", - "model = cp_model.CpModel()\n", + " #----------------------------------------------------------------------------\n", + " # Transition times using a circuit constraint.\n", + " arcs = []\n", + " for i in all_jobs:\n", + " # Initial arc from the dummy node (0) to a task.\n", + " start_lit = model.NewBoolVar('')\n", + " arcs.append([0, i + 1, start_lit])\n", + " # If this task is the first, set to minimum starting time.\n", + " min_start_time = max(release_dates[i], setup_times[0][i])\n", + " model.Add(starts[i] == min_start_time).OnlyEnforceIf(start_lit)\n", + " # Final arc from an arc to the dummy node.\n", + " arcs.append([i + 1, 0, model.NewBoolVar('')])\n", "\n", - "#----------------------------------------------------------------------------\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", - " for j in range(num_jobs))\n", - "print('Greedy horizon =', horizon)\n", + " for j in all_jobs:\n", + " if i == j:\n", + " continue\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Global storage of variables.\n", - "intervals = []\n", - "starts = []\n", - "ends = []\n", + " lit = model.NewBoolVar('%i follows %i' % (j, i))\n", + " arcs.append([i + 1, j + 1, lit])\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Scan the jobs and create the relevant variables and intervals.\n", - "for job_id in all_jobs:\n", - " duration = job_durations[job_id]\n", - " release_date = release_dates[job_id]\n", - " due_date = due_dates[job_id] if due_dates[job_id] != -1 else horizon\n", - " print('job %2i: start = %5i, duration = %4i, end = %6i' %\n", - " (job_id, release_date, duration, due_date))\n", - " name_suffix = '_%i' % job_id\n", - " start = model.NewIntVar(release_date, due_date, 's' + name_suffix)\n", - " end = model.NewIntVar(release_date, due_date, 'e' + name_suffix)\n", - " interval = model.NewIntervalVar(start, duration, end, 'i' + name_suffix)\n", - " starts.append(start)\n", - " ends.append(end)\n", - " intervals.append(interval)\n", + " # We add the reified precedence to link the literal with the times of the\n", + " # two tasks.\n", + " # If release_dates[j] == 0, we can strenghten this precedence into an\n", + " # equality as we are minimizing the makespan.\n", + " if release_dates[j] == 0:\n", + " 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", "\n", - "# No overlap constraint.\n", - "model.AddNoOverlap(intervals)\n", + " model.AddCircuit(arcs)\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Transition times using a circuit constraint.\n", - "arcs = []\n", - "for i in all_jobs:\n", - " # Initial arc from the dummy node (0) to a task.\n", - " start_lit = model.NewBoolVar('')\n", - " arcs.append([0, i + 1, start_lit])\n", - " # If this task is the first, set to minimum starting time.\n", - " min_start_time = max(release_dates[i], setup_times[0][i])\n", - " model.Add(starts[i] == min_start_time).OnlyEnforceIf(start_lit)\n", - " # Final arc from an arc to the dummy node.\n", - " arcs.append([i + 1, 0, model.NewBoolVar('')])\n", + " #----------------------------------------------------------------------------\n", + " # Precedences.\n", + " for before, after in precedences:\n", + " print('job %i is after job %i' % (after, before))\n", + " model.Add(ends[before] <= starts[after])\n", "\n", - " for j in all_jobs:\n", - " if i == j:\n", - " continue\n", + " #----------------------------------------------------------------------------\n", + " # Objective.\n", + " makespan = model.NewIntVar(0, horizon, 'makespan')\n", + " model.AddMaxEquality(makespan, ends)\n", + " model.Minimize(makespan)\n", "\n", - " lit = model.NewBoolVar('%i follows %i' % (j, i))\n", - " arcs.append([i + 1, j + 1, lit])\n", + " #----------------------------------------------------------------------------\n", + " # Write problem to file.\n", + " if output_proto_file:\n", + " print('Writing proto to %s' % output_proto_file)\n", + " with open(output_proto_file, 'w') as text_file:\n", + " text_file.write(str(model))\n", "\n", - " # We add the reified precedence to link the literal with the times of the\n", - " # two tasks.\n", - " # If release_dates[j] == 0, we can strenghten this precedence into an\n", - " # equality as we are minimizing the makespan.\n", - " if release_dates[j] == 0:\n", - " 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", + " #----------------------------------------------------------------------------\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", + " 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", "\n", - "model.AddCircuit(arcs)\n", "\n", - "#----------------------------------------------------------------------------\n", - "# Precedences.\n", - "for before, after in precedences:\n", - " print('job %i is after job %i' % (after, before))\n", - " model.Add(ends[before] <= starts[after])\n", - "\n", - "#----------------------------------------------------------------------------\n", - "# Objective.\n", - "makespan = model.NewIntVar(0, horizon, 'makespan')\n", - "model.AddMaxEquality(makespan, ends)\n", - "model.Minimize(makespan)\n", - "\n", - "#----------------------------------------------------------------------------\n", - "# Write problem to file.\n", - "if output_proto_file:\n", - " print('Writing proto to %s' % output_proto_file)\n", - " with open(output_proto_file, 'w') as text_file:\n", - " text_file.write(str(model))\n", - "\n", - "#----------------------------------------------------------------------------\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", - "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", + "main(PARSER.parse_args())\n", "\n" ] } diff --git a/examples/notebook/examples/steel_mill_slab_sat.ipynb b/examples/notebook/examples/steel_mill_slab_sat.ipynb index 1fed25943b..5bad946bca 100644 --- a/examples/notebook/examples/steel_mill_slab_sat.ipynb +++ b/examples/notebook/examples/steel_mill_slab_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves the Stell Mill Slab problem with 4 different techniques.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,41 +83,17 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solves the Stell Mill Slab problem with 4 different techniques.\"\"\"\n", - "\n", - "# overloaded sum() clashes with pytype.\n", - "# pytype: disable=wrong-arg-types\n", - "\n", "import collections\n", "import time\n", "\n", - "from absl import app\n", - "from absl import flags\n", "from ortools.linear_solver import pywraplp\n", "from ortools.sat.python import cp_model\n", "\n", - "FLAGS = flags.FLAGS\n", - "\n", - "flags.DEFINE_integer('problem', 2, 'Problem id to solve.')\n", - "flags.DEFINE_boolean('break_symmetries', True,\n", - " 'Break symmetries between equivalent orders.')\n", - "flags.DEFINE_string(\n", - " 'solver', 'mip_column', 'Method used to solve: sat, sat_table, sat_column, '\n", - " 'mip_column.')\n", + "class FLAGS: pass\n", "\n", + "FLAGS.problem = 2 # Problem id to solve.\n", + "FLAGS.break_symmetries = True # Break symmetries between equivalent orders.\n", + "FLAGS.solver = 'mip_column' # Method used to solve: sat, sat_table, sat_column, mip_column.\n", "\n", "def build_problem(problem_id):\n", " \"\"\"Build problem data.\"\"\"\n", @@ -812,14 +797,18 @@ " print('No solution')\n", "\n", "\n", - "if FLAGS.solver == 'sat':\n", - " steel_mill_slab(FLAGS.problem, FLAGS.break_symmetries)\n", - "elif FLAGS.solver == 'sat_table':\n", - " steel_mill_slab_with_valid_slabs(FLAGS.problem, FLAGS.break_symmetries)\n", - "elif FLAGS.solver == 'sat_column':\n", - " steel_mill_slab_with_column_generation(FLAGS.problem)\n", - "else: # 'mip_column'\n", - " steel_mill_slab_with_mip_column_generation(FLAGS.problem)\n", + "def main(_):\n", + " if FLAGS.solver == 'sat':\n", + " steel_mill_slab(FLAGS.problem, FLAGS.break_symmetries)\n", + " elif FLAGS.solver == 'sat_table':\n", + " steel_mill_slab_with_valid_slabs(FLAGS.problem, FLAGS.break_symmetries)\n", + " elif FLAGS.solver == 'sat_column':\n", + " steel_mill_slab_with_column_generation(FLAGS.problem)\n", + " else: # 'mip_column'\n", + " steel_mill_slab_with_mip_column_generation(FLAGS.problem)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/sudoku_sat.ipynb b/examples/notebook/examples/sudoku_sat.ipynb index 797dac8ec8..529cfe7f89 100644 --- a/examples/notebook/examples/sudoku_sat.ipynb +++ b/examples/notebook/examples/sudoku_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "This model implements a sudoku solver.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"This model implements a sudoku solver.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/examples/task_allocation_sat.ipynb b/examples/notebook/examples/task_allocation_sat.ipynb index d83138959f..97397c593a 100644 --- a/examples/notebook/examples/task_allocation_sat.ipynb +++ b/examples/notebook/examples/task_allocation_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,18 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "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", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,287 +86,273 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"CP-SAT model for task allocation problem.\n", - "see\n", - "http://yetanothermathprogrammingconsultant.blogspot.com/2018/09/minizinc-cpsat-vs-mip.html\n", - "\"\"\"\n", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\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", + "def main():\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", - "ntasks = len(available)\n", - "nslots = len(available[0])\n", + " ntasks = len(available)\n", + " nslots = len(available[0])\n", "\n", - "# sets\n", - "all_tasks = range(ntasks)\n", - "all_slots = range(nslots)\n", + " # sets\n", + " all_tasks = range(ntasks)\n", + " all_slots = range(nslots)\n", "\n", - "# max tasks per time slot\n", - "capacity = 3\n", + " # max tasks per time slot\n", + " capacity = 3\n", "\n", - "# Model\n", - "model = cp_model.CpModel()\n", - "assign = {}\n", - "for task in all_tasks:\n", - " for slot in all_slots:\n", - " assign[(task, slot)] = model.NewBoolVar('x[%i][%i]' % (task, slot))\n", - "count = model.NewIntVar(0, nslots, 'count')\n", - "slot_used = [model.NewBoolVar('slot_used[%i]' % s) for s in all_slots]\n", - "\n", - "for task in all_tasks:\n", - " model.Add(\n", - " sum(assign[(task, slot)] 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", - " if available[task][slot] == 1) <= capacity)\n", - " model.AddBoolOr([\n", - " assign[(task, slot)] for task in all_tasks\n", - " if available[task][slot] == 1\n", - " ]).OnlyEnforceIf(slot_used[slot])\n", + " # Model\n", + " model = cp_model.CpModel()\n", + " assign = {}\n", " for task in all_tasks:\n", - " if available[task][slot] == 1:\n", - " model.AddImplication(slot_used[slot].Not(),\n", - " assign[(task, slot)].Not())\n", - " else:\n", - " model.Add(assign[(task, slot)] == 0)\n", + " for slot in all_slots:\n", + " assign[(task, slot)] = model.NewBoolVar('x[%i][%i]' % (task, slot))\n", + " count = model.NewIntVar(0, nslots, 'count')\n", + " slot_used = [model.NewBoolVar('slot_used[%i]' % s) for s in all_slots]\n", "\n", - "model.Add(count == sum(slot_used))\n", - "# Redundant constraint. This instance is easier if we add this constraint.\n", - "# model.Add(count >= (nslots + capacity - 1) // capacity)\n", + " for task in all_tasks:\n", + " model.Add(\n", + " sum(assign[(task, slot)] for slot in all_slots\n", + " if available[task][slot] == 1) == 1)\n", "\n", - "model.Minimize(count)\n", + " for slot in all_slots:\n", + " model.Add(\n", + " sum(assign[(task, slot)] 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", + " if available[task][slot] == 1\n", + " ]).OnlyEnforceIf(slot_used[slot])\n", + " for task in all_tasks:\n", + " if available[task][slot] == 1:\n", + " model.AddImplication(slot_used[slot].Not(),\n", + " assign[(task, slot)].Not())\n", + " else:\n", + " model.Add(assign[(task, slot)] == 0)\n", "\n", - "# Create a solver and solve the problem.\n", - "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", - "status = solver.Solve(model)\n", + " model.Add(count == sum(slot_used))\n", + " # Redundant constraint. This instance is easier if we add this constraint.\n", + " # model.Add(count >= (nslots + capacity - 1) // capacity)\n", "\n", - "print('Statistics')\n", - "print(' - status =', solver.StatusName(status))\n", - "print(' - optimal solution =', solver.ObjectiveValue())\n", - "print(' - wall time : %f s' % solver.WallTime())\n", + " model.Minimize(count)\n", + "\n", + " # Create a solver and solve the problem.\n", + " 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", + " status = solver.Solve(model)\n", + "\n", + " print('Statistics')\n", + " print(' - status =', solver.StatusName(status))\n", + " print(' - optimal solution =', solver.ObjectiveValue())\n", + " print(' - wall time : %f s' % solver.WallTime())\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 49f821d20d..0febe9ce2d 100644 --- a/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb +++ b/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Tasks and workers to group assignment to average sum(cost) / #workers\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +83,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Tasks and workers to group assignment to average sum(cost) / #workers\"\"\"\n", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/examples/transit_time.ipynb b/examples/notebook/examples/transit_time.ipynb index 6a3333db19..f0946e6b9b 100644 --- a/examples/notebook/examples/transit_time.ipynb +++ b/examples/notebook/examples/transit_time.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,20 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Display Transit Time\n", + " Distances are in meters and time in minutes.\n", + "\n", + " Manhattan average block: 750ft x 264ft -> 228m x 80m\n", + " src: https://nyti.ms/2GDoRIe \"NY Times: Know Your distance\"\n", + " here we use: 114m x 80m city block\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +88,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python\n", - "# This Python file uses the following encoding: utf-8\n", - "# Copyright 2015 Tin Arm Engineering AB\n", - "# Copyright 2018 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", - "\"\"\"Display Transit Time\n", - " Distances are in meters and time in minutes.\n", - "\n", - " Manhattan average block: 750ft x 264ft -> 228m x 80m\n", - " src: https://nyti.ms/2GDoRIe \"NY Times: Know Your distance\"\n", - " here we use: 114m x 80m city block\n", - "\"\"\"\n", - "\n", "from ortools.constraint_solver import pywrapcp\n", "from ortools.constraint_solver import routing_enums_pb2\n", "\n", @@ -274,25 +265,29 @@ "########\n", "# Main #\n", "########\n", - "\"\"\"Entry point of the program\"\"\"\n", - "# Instantiate the data problem.\n", - "data = DataProblem()\n", + "def main():\n", + " \"\"\"Entry point of the program\"\"\"\n", + " # Instantiate the data problem.\n", + " data = DataProblem()\n", "\n", - "# Print Transit Time\n", - "time_evaluator = CreateTimeEvaluator(data).time_evaluator\n", - "print('Route 0:')\n", - "print_transit_time([[0, 5], [5, 8], [8, 6], [6, 2], [2, 0]], time_evaluator)\n", + " # Print Transit Time\n", + " time_evaluator = CreateTimeEvaluator(data).time_evaluator\n", + " print('Route 0:')\n", + " print_transit_time([[0, 5], [5, 8], [8, 6], [6, 2], [2, 0]], time_evaluator)\n", "\n", - "print('Route 1:')\n", - "print_transit_time([[0, 9], [9, 14], [14, 16], [16, 10], [10, 0]],\n", - " time_evaluator)\n", + " print('Route 1:')\n", + " print_transit_time([[0, 9], [9, 14], [14, 16], [16, 10], [10, 0]],\n", + " time_evaluator)\n", "\n", - "print('Route 2:')\n", - "print_transit_time([[0, 12], [12, 13], [13, 15], [15, 11], [11, 0]],\n", - " time_evaluator)\n", + " print('Route 2:')\n", + " print_transit_time([[0, 12], [12, 13], [13, 15], [15, 11], [11, 0]],\n", + " time_evaluator)\n", "\n", - "print('Route 3:')\n", - "print_transit_time([[0, 7], [7, 4], [4, 3], [3, 1], [1, 0]], time_evaluator)\n", + " print('Route 3:')\n", + " print_transit_time([[0, 7], [7, 4], [4, 3], [3, 1], [1, 0]], time_evaluator)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/tsp_sat.ipynb b/examples/notebook/examples/tsp_sat.ipynb index 7d7967b9af..2251e0e823 100644 --- a/examples/notebook/examples/tsp_sat.ipynb +++ b/examples/notebook/examples/tsp_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple travelling salesman problem between cities.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +83,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Simple travelling salesman problem between cities.\"\"\"\n", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", @@ -136,65 +130,69 @@ " ] # yapf: disable\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "num_nodes = len(DISTANCE_MATRIX)\n", - "all_nodes = range(num_nodes)\n", - "print('Num nodes =', num_nodes)\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " num_nodes = len(DISTANCE_MATRIX)\n", + " all_nodes = range(num_nodes)\n", + " print('Num nodes =', num_nodes)\n", "\n", - "# Model.\n", - "model = cp_model.CpModel()\n", + " # Model.\n", + " model = cp_model.CpModel()\n", "\n", - "obj_vars = []\n", - "obj_coeffs = []\n", + " obj_vars = []\n", + " obj_coeffs = []\n", "\n", - "# Create the circuit constraint.\n", - "arcs = []\n", - "arc_literals = {}\n", - "for i in all_nodes:\n", - " for j in all_nodes:\n", - " if i == j:\n", - " continue\n", - "\n", - " lit = model.NewBoolVar('%i follows %i' % (j, i))\n", - " arcs.append([i, j, lit])\n", - " arc_literals[i, j] = lit\n", - "\n", - " obj_vars.append(lit)\n", - " obj_coeffs.append(DISTANCE_MATRIX[i][j])\n", - "\n", - "model.AddCircuit(arcs)\n", - "\n", - "# Minimize weighted sum of arcs. Because this s\n", - "model.Minimize(\n", - " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", - "\n", - "# Solve and print out the solution.\n", - "solver = cp_model.CpSolver()\n", - "solver.parameters.log_search_progress = True\n", - "# To benefit from the linearization of the circuit constraint.\n", - "solver.parameters.linearization_level = 2\n", - "\n", - "solver.Solve(model)\n", - "print(solver.ResponseStats())\n", - "\n", - "current_node = 0\n", - "str_route = '%i' % current_node\n", - "route_is_finished = False\n", - "route_distance = 0\n", - "while not route_is_finished:\n", + " # Create the circuit constraint.\n", + " arcs = []\n", + " arc_literals = {}\n", " for i in all_nodes:\n", - " if i == current_node:\n", - " continue\n", - " if solver.BooleanValue(arc_literals[current_node, i]):\n", - " str_route += ' -> %i' % i\n", - " route_distance += DISTANCE_MATRIX[current_node][i]\n", - " current_node = i\n", - " if current_node == 0:\n", - " route_is_finished = True\n", - " break\n", + " for j in all_nodes:\n", + " if i == j:\n", + " continue\n", "\n", - "print('Route:', str_route)\n", - "print('Travelled distance:', route_distance)\n", + " lit = model.NewBoolVar('%i follows %i' % (j, i))\n", + " arcs.append([i, j, lit])\n", + " arc_literals[i, j] = lit\n", + "\n", + " obj_vars.append(lit)\n", + " obj_coeffs.append(DISTANCE_MATRIX[i][j])\n", + "\n", + " model.AddCircuit(arcs)\n", + "\n", + " # Minimize weighted sum of arcs. Because this s\n", + " model.Minimize(\n", + " sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n", + "\n", + " # Solve and print out the solution.\n", + " solver = cp_model.CpSolver()\n", + " solver.parameters.log_search_progress = True\n", + " # To benefit from the linearization of the circuit constraint.\n", + " solver.parameters.linearization_level = 2\n", + "\n", + " solver.Solve(model)\n", + " print(solver.ResponseStats())\n", + "\n", + " current_node = 0\n", + " str_route = '%i' % current_node\n", + " route_is_finished = False\n", + " route_distance = 0\n", + " while not route_is_finished:\n", + " for i in all_nodes:\n", + " if i == current_node:\n", + " continue\n", + " if solver.BooleanValue(arc_literals[current_node, i]):\n", + " str_route += ' -> %i' % i\n", + " route_distance += DISTANCE_MATRIX[current_node][i]\n", + " current_node = i\n", + " if current_node == 0:\n", + " route_is_finished = True\n", + " break\n", + "\n", + " print('Route:', str_route)\n", + " print('Travelled distance:', route_distance)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/vendor_scheduling_sat.ipynb b/examples/notebook/examples/vendor_scheduling_sat.ipynb index e8e4c531fc..7228603815 100644 --- a/examples/notebook/examples/vendor_scheduling_sat.ipynb +++ b/examples/notebook/examples/vendor_scheduling_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,15 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves a simple shift scheduling problem.\n", + "\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +83,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Copyright 2010-2021 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", - "\"\"\"Solves a simple shift scheduling problem.\"\"\"\n", - "\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", @@ -127,90 +121,94 @@ " return self.__solution_count\n", "\n", "\n", - "\"\"\"Create the shift scheduling model and solve it.\"\"\"\n", - "# Create the model.\n", - "model = cp_model.CpModel()\n", + "def main():\n", + " \"\"\"Create the shift scheduling model and solve it.\"\"\"\n", + " # Create the model.\n", + " model = cp_model.CpModel()\n", "\n", - "#\n", - "# data\n", - "#\n", - "num_vendors = 9\n", - "num_hours = 10\n", - "num_work_types = 1\n", + " #\n", + " # data\n", + " #\n", + " num_vendors = 9\n", + " num_hours = 10\n", + " num_work_types = 1\n", "\n", - "traffic = [100, 500, 100, 200, 320, 300, 200, 220, 300, 120]\n", - "max_traffic_per_vendor = 100\n", + " traffic = [100, 500, 100, 200, 320, 300, 200, 220, 300, 120]\n", + " max_traffic_per_vendor = 100\n", "\n", - "# Last columns are :\n", - "# index_of_the_schedule, sum of worked hours (per work type).\n", - "# The index is useful for branching.\n", - "possible_schedules = [[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0,\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", + " # 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", "\n", - "num_possible_schedules = len(possible_schedules)\n", - "selected_schedules = []\n", - "vendors_stat = []\n", - "hours_stat = []\n", + " num_possible_schedules = len(possible_schedules)\n", + " selected_schedules = []\n", + " vendors_stat = []\n", + " hours_stat = []\n", "\n", - "# Auxiliary data\n", - "min_vendors = [t // max_traffic_per_vendor for t in traffic]\n", - "all_vendors = range(num_vendors)\n", - "all_hours = range(num_hours)\n", + " # Auxiliary data\n", + " min_vendors = [t // max_traffic_per_vendor for t in traffic]\n", + " all_vendors = range(num_vendors)\n", + " all_hours = range(num_hours)\n", "\n", - "#\n", - "# declare variables\n", - "#\n", - "x = {}\n", + " #\n", + " # declare variables\n", + " #\n", + " x = {}\n", "\n", - "for v in all_vendors:\n", - " tmp = []\n", + " for v in all_vendors:\n", + " tmp = []\n", + " for h in all_hours:\n", + " x[v, h] = model.NewIntVar(0, num_work_types, 'x[%i,%i]' % (v, h))\n", + " tmp.append(x[v, h])\n", + " selected_schedule = model.NewIntVar(0, num_possible_schedules - 1,\n", + " 's[%i]' % v)\n", + " hours = model.NewIntVar(0, num_hours, 'h[%i]' % v)\n", + " selected_schedules.append(selected_schedule)\n", + " vendors_stat.append(hours)\n", + " tmp.append(selected_schedule)\n", + " tmp.append(hours)\n", + "\n", + " model.AddAllowedAssignments(tmp, possible_schedules)\n", + "\n", + " #\n", + " # Statistics and constraints for each hour\n", + " #\n", " for h in all_hours:\n", - " x[v, h] = model.NewIntVar(0, num_work_types, 'x[%i,%i]' % (v, h))\n", - " tmp.append(x[v, h])\n", - " selected_schedule = model.NewIntVar(0, num_possible_schedules - 1,\n", - " 's[%i]' % v)\n", - " hours = model.NewIntVar(0, num_hours, 'h[%i]' % v)\n", - " selected_schedules.append(selected_schedule)\n", - " vendors_stat.append(hours)\n", - " tmp.append(selected_schedule)\n", - " tmp.append(hours)\n", + " workers = model.NewIntVar(0, 1000, 'workers[%i]' % h)\n", + " model.Add(workers == sum(x[v, h] for v in all_vendors))\n", + " hours_stat.append(workers)\n", + " model.Add(workers * max_traffic_per_vendor >= traffic[h])\n", "\n", - " model.AddAllowedAssignments(tmp, possible_schedules)\n", + " #\n", + " # Redundant constraint: sort selected_schedules\n", + " #\n", + " for v in range(num_vendors - 1):\n", + " model.Add(selected_schedules[v] <= selected_schedules[v + 1])\n", "\n", - "#\n", - "# Statistics and constraints for each hour\n", - "#\n", - "for h in all_hours:\n", - " workers = model.NewIntVar(0, 1000, 'workers[%i]' % h)\n", - " model.Add(workers == sum(x[v, h] for v in all_vendors))\n", - " hours_stat.append(workers)\n", - " model.Add(workers * max_traffic_per_vendor >= traffic[h])\n", + " # Solve model.\n", + " solver = cp_model.CpSolver()\n", + " solver.parameters.enumerate_all_solutions = True\n", + " solution_printer = SolutionPrinter(num_vendors, num_hours,\n", + " possible_schedules, selected_schedules,\n", + " hours_stat, min_vendors)\n", + " status = solver.Solve(model, solution_printer)\n", + " print('Status = %s' % solver.StatusName(status))\n", "\n", - "#\n", - "# Redundant constraint: sort selected_schedules\n", - "#\n", - "for v in range(num_vendors - 1):\n", - " model.Add(selected_schedules[v] <= selected_schedules[v + 1])\n", + " print('Statistics')\n", + " 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", "\n", - "# Solve model.\n", - "solver = cp_model.CpSolver()\n", - "solver.parameters.enumerate_all_solutions = True\n", - "solution_printer = SolutionPrinter(num_vendors, num_hours,\n", - " possible_schedules, selected_schedules,\n", - " hours_stat, min_vendors)\n", - "status = solver.Solve(model, solution_printer)\n", - "print('Status = %s' % solver.StatusName(status))\n", "\n", - "print('Statistics')\n", - "print(' - conflicts : %i' % solver.NumConflicts())\n", - "print(' - branches : %i' % solver.NumBranches())\n", - "print(' - wall time : %f s' % solver.WallTime())\n", - "print(\n", - " ' - number of solutions found: %i' % solution_printer.solution_count())\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/examples/wedding_optimal_chart_sat.ipynb b/examples/notebook/examples/wedding_optimal_chart_sat.ipynb index 6925412e31..831f5162b3 100644 --- a/examples/notebook/examples/wedding_optimal_chart_sat.ipynb +++ b/examples/notebook/examples/wedding_optimal_chart_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,27 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#\n", - "# Copyright 2018 Google.\n", - "#\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", - "\"\"\"Finding an optimal wedding seating chart.\n", + "Finding an optimal wedding seating chart.\n", "\n", "From\n", "Meghan L. Bellows and J. D. Luc Peterson\n", @@ -110,8 +94,16 @@ "\n", "Adapted from\n", "https://github.com/google/or-tools/blob/master/examples/csharp/wedding_optimal_chart.cs\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "import time\n", "from ortools.sat.python import cp_model\n", "\n", diff --git a/examples/notebook/examples/worker_schedule_sat.ipynb b/examples/notebook/examples/worker_schedule_sat.ipynb index a0e73587e6..e0948e4728 100644 --- a/examples/notebook/examples/worker_schedule_sat.ipynb +++ b/examples/notebook/examples/worker_schedule_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -229,6 +229,8 @@ " print(' - branches : %i' % solver.NumBranches())\n", " print(' - wall time : %f s' % solver.WallTime())\n", "\n", + "\n", + "schedule()\n", "\n" ] } diff --git a/examples/notebook/examples/zebra_sat.ipynb b/examples/notebook/examples/zebra_sat.ipynb index 197450735a..9f8a05d766 100644 --- a/examples/notebook/examples/zebra_sat.ipynb +++ b/examples/notebook/examples/zebra_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -68,26 +68,11 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "code", + "cell_type": "markdown", + "id": "description", "metadata": {}, - "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"This is the zebra problem as invented by Lewis Caroll.\n", + "This is the zebra problem as invented by Lewis Caroll.\n", "\n", "There are five houses.\n", "The Englishman lives in the red house.\n", @@ -107,8 +92,16 @@ "The Norwegian lives next to the blue house.\n", "\n", "Who owns a zebra and who drinks water?\n", - "\"\"\"\n", - "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "code", + "metadata": {}, + "outputs": [], + "source": [ "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/graph/assignment_linear_sum_assignment.ipynb b/examples/notebook/graph/assignment_linear_sum_assignment.ipynb index 4db6de46ed..d4f9168ec0 100644 --- a/examples/notebook/graph/assignment_linear_sum_assignment.ipynb +++ b/examples/notebook/graph/assignment_linear_sum_assignment.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve assignment problem using linear assignment solver." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,65 +82,42 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Solve assignment problem using linear assignment solver.\"\"\"\n", - "# [START import]\n", "from ortools.graph.python import linear_sum_assignment\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Linear Sum Assignment example.\"\"\"\n", - "# [START solver]\n", - "assignment = linear_sum_assignment.SimpleLinearSumAssignment()\n", - "# [END solver]\n", + "def main():\n", + " \"\"\"Linear Sum Assignment example.\"\"\"\n", + " assignment = linear_sum_assignment.SimpleLinearSumAssignment()\n", "\n", - "# [START data]\n", - "costs = [\n", - " [90, 76, 75, 70],\n", - " [35, 85, 55, 65],\n", - " [125, 95, 90, 105],\n", - " [45, 110, 95, 115],\n", - "]\n", - "num_workers = len(costs)\n", - "num_tasks = len(costs[0])\n", - "# [END data]\n", + " costs = [\n", + " [90, 76, 75, 70],\n", + " [35, 85, 55, 65],\n", + " [125, 95, 90, 105],\n", + " [45, 110, 95, 115],\n", + " ]\n", + " num_workers = len(costs)\n", + " num_tasks = len(costs[0])\n", "\n", - "# [START constraints]\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " if costs[worker][task]:\n", - " assignment.add_arc_with_cost(worker, task, costs[worker][task])\n", - "# [END constraints]\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " if costs[worker][task]:\n", + " assignment.add_arc_with_cost(worker, task, costs[worker][task])\n", "\n", - "# [START solve]\n", - "status = assignment.solve()\n", - "# [END solve]\n", + " status = assignment.solve()\n", "\n", - "# [START print_solution]\n", - "if status == assignment.OPTIMAL:\n", - " print(f'Total cost = {assignment.optimal_cost()}\\n')\n", - " for i in range(0, assignment.num_nodes()):\n", - " print(f'Worker {i} assigned to task {assignment.right_mate(i)}.' +\n", - " f' Cost = {assignment.assignment_cost(i)}')\n", - "elif status == assignment.INFEASIBLE:\n", - " print('No assignment is possible.')\n", - "elif status == assignment.POSSIBLE_OVERFLOW:\n", - " print(\n", - " 'Some input costs are too large and may cause an integer overflow.')\n", - "# [END print_solution]\n", + " if status == assignment.OPTIMAL:\n", + " print(f'Total cost = {assignment.optimal_cost()}\\n')\n", + " for i in range(0, assignment.num_nodes()):\n", + " print(f'Worker {i} assigned to task {assignment.right_mate(i)}.' +\n", + " f' Cost = {assignment.assignment_cost(i)}')\n", + " elif status == assignment.INFEASIBLE:\n", + " print('No assignment is possible.')\n", + " elif status == assignment.POSSIBLE_OVERFLOW:\n", + " print(\n", + " 'Some input costs are too large and may cause an integer overflow.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/graph/assignment_min_flow.ipynb b/examples/notebook/graph/assignment_min_flow.ipynb index 47162db69d..6c063fe056 100644 --- a/examples/notebook/graph/assignment_min_flow.ipynb +++ b/examples/notebook/graph/assignment_min_flow.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Linear assignment example." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,85 +82,62 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Linear assignment example.\"\"\"\n", - "# [START import]\n", "from ortools.graph.python import min_cost_flow\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Solving an Assignment Problem with MinCostFlow.\"\"\"\n", - "# [START solver]\n", - "# Instantiate a SimpleMinCostFlow solver.\n", - "smcf = min_cost_flow.SimpleMinCostFlow()\n", - "# [END solver]\n", + "def main():\n", + " \"\"\"Solving an Assignment Problem with MinCostFlow.\"\"\"\n", + " # Instantiate a SimpleMinCostFlow solver.\n", + " smcf = min_cost_flow.SimpleMinCostFlow()\n", "\n", - "# [START data]\n", - "# Define the directed graph for the flow.\n", - "start_nodes = [0, 0, 0, 0] + [\n", - " 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4\n", - "] + [5, 6, 7, 8]\n", - "end_nodes = [1, 2, 3, 4] + [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8\n", - " ] + [9, 9, 9, 9]\n", - "capacities = [1, 1, 1, 1] + [\n", - " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n", - "] + [1, 1, 1, 1]\n", - "costs = (\n", - " [0, 0, 0, 0] +\n", - " [90, 76, 75, 70, 35, 85, 55, 65, 125, 95, 90, 105, 45, 110, 95, 115] +\n", - " [0, 0, 0, 0])\n", + " # Define the directed graph for the flow.\n", + " start_nodes = [0, 0, 0, 0] + [\n", + " 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4\n", + " ] + [5, 6, 7, 8]\n", + " end_nodes = [1, 2, 3, 4] + [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8\n", + " ] + [9, 9, 9, 9]\n", + " capacities = [1, 1, 1, 1] + [\n", + " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n", + " ] + [1, 1, 1, 1]\n", + " costs = (\n", + " [0, 0, 0, 0] +\n", + " [90, 76, 75, 70, 35, 85, 55, 65, 125, 95, 90, 105, 45, 110, 95, 115] +\n", + " [0, 0, 0, 0])\n", "\n", - "source = 0\n", - "sink = 9\n", - "tasks = 4\n", - "supplies = [tasks, 0, 0, 0, 0, 0, 0, 0, 0, -tasks]\n", - "# [END data]\n", + " source = 0\n", + " sink = 9\n", + " tasks = 4\n", + " supplies = [tasks, 0, 0, 0, 0, 0, 0, 0, 0, -tasks]\n", "\n", - "# [START constraints]\n", - "# Add each arc.\n", - "for i in range(len(start_nodes)):\n", - " smcf.add_arc_with_capacity_and_unit_cost(start_nodes[i], end_nodes[i],\n", - " capacities[i], costs[i])\n", - "# Add node supplies.\n", - "for i in range(len(supplies)):\n", - " smcf.set_node_supply(i, supplies[i])\n", - "# [END constraints]\n", + " # Add each arc.\n", + " for i in range(len(start_nodes)):\n", + " smcf.add_arc_with_capacity_and_unit_cost(start_nodes[i], end_nodes[i],\n", + " capacities[i], costs[i])\n", + " # Add node supplies.\n", + " for i in range(len(supplies)):\n", + " smcf.set_node_supply(i, supplies[i])\n", "\n", - "# [START solve]\n", - "# Find the minimum cost flow between node 0 and node 10.\n", - "status = smcf.solve()\n", - "# [END solve]\n", + " # Find the minimum cost flow between node 0 and node 10.\n", + " status = smcf.solve()\n", "\n", - "# [START print_solution]\n", - "if status == smcf.OPTIMAL:\n", - " print('Total cost = ', smcf.optimal_cost())\n", - " print()\n", - " for arc in range(smcf.num_arcs()):\n", - " # Can ignore arcs leading out of source or into sink.\n", - " if smcf.tail(arc) != source and smcf.head(arc) != sink:\n", + " if status == smcf.OPTIMAL:\n", + " print('Total cost = ', smcf.optimal_cost())\n", + " print()\n", + " for arc in range(smcf.num_arcs()):\n", + " # Can ignore arcs leading out of source or into sink.\n", + " if smcf.tail(arc) != source and smcf.head(arc) != sink:\n", "\n", - " # Arcs in the solution have a flow value of 1. Their start and end nodes\n", - " # give an assignment of worker to task.\n", - " if smcf.flow(arc) > 0:\n", - " print('Worker %d assigned to task %d. Cost = %d' %\n", - " (smcf.tail(arc), smcf.head(arc), smcf.unit_cost(arc)))\n", - "else:\n", - " print('There was an issue with the min cost flow input.')\n", - " print(f'Status: {status}')\n", - "# [END print_solution]\n", + " # Arcs in the solution have a flow value of 1. Their start and end nodes\n", + " # give an assignment of worker to task.\n", + " if smcf.flow(arc) > 0:\n", + " print('Worker %d assigned to task %d. Cost = %d' %\n", + " (smcf.tail(arc), smcf.head(arc), smcf.unit_cost(arc)))\n", + " else:\n", + " print('There was an issue with the min cost flow input.')\n", + " print(f'Status: {status}')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/graph/balance_min_flow.ipynb b/examples/notebook/graph/balance_min_flow.ipynb index c8546743a7..40331bb47d 100644 --- a/examples/notebook/graph/balance_min_flow.ipynb +++ b/examples/notebook/graph/balance_min_flow.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Assignment with teams of workers." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,93 +82,70 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Assignment with teams of workers.\"\"\"\n", - "# [START import]\n", "from ortools.graph.python import min_cost_flow\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Solving an Assignment with teams of worker.\"\"\"\n", - "# [START solver]\n", - "smcf = min_cost_flow.SimpleMinCostFlow()\n", - "# [END solver]\n", + "def main():\n", + " \"\"\"Solving an Assignment with teams of worker.\"\"\"\n", + " smcf = min_cost_flow.SimpleMinCostFlow()\n", "\n", - "# [START data]\n", - "# Define the directed graph for the flow.\n", - "team_a = [1, 3, 5]\n", - "team_b = [2, 4, 6]\n", + " # Define the directed graph for the flow.\n", + " team_a = [1, 3, 5]\n", + " team_b = [2, 4, 6]\n", "\n", - "start_nodes = ([0, 0] + [11, 11, 11] + [12, 12, 12] + [\n", - " 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6\n", - "] + [7, 8, 9, 10])\n", - "end_nodes = ([11, 12] + team_a + team_b + [\n", - " 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8,\n", - " 9, 10\n", - "] + [13, 13, 13, 13])\n", - "capacities = ([2, 2] + [1, 1, 1] + [1, 1, 1] + [\n", - " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n", - "] + [1, 1, 1, 1])\n", - "costs = ([0, 0] + [0, 0, 0] + [0, 0, 0] + [\n", - " 90, 76, 75, 70, 35, 85, 55, 65, 125, 95, 90, 105, 45, 110, 95, 115, 60,\n", - " 105, 80, 75, 45, 65, 110, 95\n", - "] + [0, 0, 0, 0])\n", + " start_nodes = ([0, 0] + [11, 11, 11] + [12, 12, 12] + [\n", + " 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6\n", + " ] + [7, 8, 9, 10])\n", + " end_nodes = ([11, 12] + team_a + team_b + [\n", + " 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8, 9, 10, 7, 8,\n", + " 9, 10\n", + " ] + [13, 13, 13, 13])\n", + " capacities = ([2, 2] + [1, 1, 1] + [1, 1, 1] + [\n", + " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n", + " ] + [1, 1, 1, 1])\n", + " costs = ([0, 0] + [0, 0, 0] + [0, 0, 0] + [\n", + " 90, 76, 75, 70, 35, 85, 55, 65, 125, 95, 90, 105, 45, 110, 95, 115, 60,\n", + " 105, 80, 75, 45, 65, 110, 95\n", + " ] + [0, 0, 0, 0])\n", "\n", - "source = 0\n", - "sink = 13\n", - "tasks = 4\n", - "# Define an array of supplies at each node.\n", - "supplies = [tasks, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -tasks]\n", - "# [END data]\n", + " source = 0\n", + " sink = 13\n", + " tasks = 4\n", + " # Define an array of supplies at each node.\n", + " supplies = [tasks, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -tasks]\n", "\n", - "# [START constraints]\n", - "# Add each arc.\n", - "for i in range(0, len(start_nodes)):\n", - " smcf.add_arc_with_capacity_and_unit_cost(start_nodes[i], end_nodes[i],\n", - " capacities[i], costs[i])\n", + " # Add each arc.\n", + " for i in range(0, len(start_nodes)):\n", + " smcf.add_arc_with_capacity_and_unit_cost(start_nodes[i], end_nodes[i],\n", + " capacities[i], costs[i])\n", "\n", - "# Add node supplies.\n", - "for i in range(0, len(supplies)):\n", - " smcf.set_node_supply(i, supplies[i])\n", - "# [END constraints]\n", + " # Add node supplies.\n", + " for i in range(0, len(supplies)):\n", + " smcf.set_node_supply(i, supplies[i])\n", "\n", - "# [START solve]\n", - "# Find the minimum cost flow between node 0 and node 10.\n", - "status = smcf.solve()\n", - "# [END solve]\n", + " # Find the minimum cost flow between node 0 and node 10.\n", + " status = smcf.solve()\n", "\n", - "# [START print_solution]\n", - "if status == smcf.OPTIMAL:\n", - " smcf.solve()\n", - " print('Total cost = ', smcf.optimal_cost())\n", - " print()\n", - " for arc in range(smcf.num_arcs()):\n", - " # Can ignore arcs leading out of source or intermediate, or into sink.\n", - " if (smcf.tail(arc) != source and smcf.tail(arc) != 11 and\n", - " smcf.tail(arc) != 12 and smcf.head(arc) != sink):\n", + " if status == smcf.OPTIMAL:\n", + " smcf.solve()\n", + " print('Total cost = ', smcf.optimal_cost())\n", + " print()\n", + " for arc in range(smcf.num_arcs()):\n", + " # Can ignore arcs leading out of source or intermediate, or into sink.\n", + " if (smcf.tail(arc) != source and smcf.tail(arc) != 11 and\n", + " smcf.tail(arc) != 12 and smcf.head(arc) != sink):\n", "\n", - " # Arcs in the solution will have a flow value of 1.\n", - " # There start and end nodes give an assignment of worker to task.\n", - " if smcf.flow(arc) > 0:\n", - " print('Worker %d assigned to task %d. Cost = %d' %\n", - " (smcf.tail(arc), smcf.head(arc), smcf.unit_cost(arc)))\n", - "else:\n", - " print('There was an issue with the min cost flow input.')\n", - " print(f'Status: {status}')\n", - "# [END print_solution]\n", + " # Arcs in the solution will have a flow value of 1.\n", + " # There start and end nodes give an assignment of worker to task.\n", + " if smcf.flow(arc) > 0:\n", + " print('Worker %d assigned to task %d. Cost = %d' %\n", + " (smcf.tail(arc), smcf.head(arc), smcf.unit_cost(arc)))\n", + " else:\n", + " print('There was an issue with the min cost flow input.')\n", + " print(f'Status: {status}')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/graph/simple_max_flow_program.ipynb b/examples/notebook/graph/simple_max_flow_program.ipynb index 4887e5c9f1..7417dac559 100644 --- a/examples/notebook/graph/simple_max_flow_program.ipynb +++ b/examples/notebook/graph/simple_max_flow_program.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "From Taha 'Introduction to Operations Research', example 6.4-2." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,66 +82,43 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"From Taha 'Introduction to Operations Research', example 6.4-2.\"\"\"\n", - "# [START import]\n", "from ortools.graph.python import max_flow\n", - "# [END import]\n", "\n", "\n", - "\"\"\"MaxFlow simple interface example.\"\"\"\n", - "# [START solver]\n", - "# Instantiate a SimpleMaxFlow solver.\n", - "smf = max_flow.SimpleMaxFlow()\n", - "# [END solver]\n", + "def main():\n", + " \"\"\"MaxFlow simple interface example.\"\"\"\n", + " # Instantiate a SimpleMaxFlow solver.\n", + " smf = max_flow.SimpleMaxFlow()\n", "\n", - "# [START data]\n", - "# Define three parallel arrays: start_nodes, end_nodes, and the capacities\n", - "# between each pair. For instance, the arc from node 0 to node 1 has a\n", - "# capacity of 20.\n", - "start_nodes = [0, 0, 0, 1, 1, 2, 2, 3, 3]\n", - "end_nodes = [1, 2, 3, 2, 4, 3, 4, 2, 4]\n", - "capacities = [20, 30, 10, 40, 30, 10, 20, 5, 20]\n", - "# [END data]\n", + " # Define three parallel arrays: start_nodes, end_nodes, and the capacities\n", + " # between each pair. For instance, the arc from node 0 to node 1 has a\n", + " # capacity of 20.\n", + " start_nodes = [0, 0, 0, 1, 1, 2, 2, 3, 3]\n", + " end_nodes = [1, 2, 3, 2, 4, 3, 4, 2, 4]\n", + " capacities = [20, 30, 10, 40, 30, 10, 20, 5, 20]\n", "\n", - "# [START constraints]\n", - "# Add each arc.\n", - "for arc in zip(start_nodes, end_nodes, capacities):\n", - " smf.add_arc_with_capacity(arc[0], arc[1], arc[2])\n", - "# [END constraints]\n", + " # Add each arc.\n", + " for arc in zip(start_nodes, end_nodes, capacities):\n", + " smf.add_arc_with_capacity(arc[0], arc[1], arc[2])\n", "\n", - "# [START solve]\n", - "# Find the maximum flow between node 0 and node 4.\n", - "status = smf.solve(0, 4)\n", - "# [END solve]\n", + " # Find the maximum flow between node 0 and node 4.\n", + " status = smf.solve(0, 4)\n", "\n", - "# [START print_solution]\n", - "if status != smf.OPTIMAL:\n", - " print('There was an issue with the max flow input.')\n", - " print(f'Status: {status}')\n", - " exit(1)\n", - "print('Max flow:', smf.optimal_flow())\n", - "print('')\n", - "print(' Arc Flow / Capacity')\n", - "for i in range(smf.num_arcs()):\n", - " print('%1s -> %1s %3s / %3s' %\n", - " (smf.tail(i), smf.head(i), smf.flow(i), smf.capacity(i)))\n", - "print('Source side min-cut:', smf.get_source_side_min_cut())\n", - "print('Sink side min-cut:', smf.get_sink_side_min_cut())\n", - "# [END print_solution]\n", + " if status != smf.OPTIMAL:\n", + " print('There was an issue with the max flow input.')\n", + " print(f'Status: {status}')\n", + " exit(1)\n", + " print('Max flow:', smf.optimal_flow())\n", + " print('')\n", + " print(' Arc Flow / Capacity')\n", + " for i in range(smf.num_arcs()):\n", + " print('%1s -> %1s %3s / %3s' %\n", + " (smf.tail(i), smf.head(i), smf.flow(i), smf.capacity(i)))\n", + " print('Source side min-cut:', smf.get_source_side_min_cut())\n", + " print('Sink side min-cut:', smf.get_sink_side_min_cut())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/graph/simple_min_cost_flow_program.ipynb b/examples/notebook/graph/simple_min_cost_flow_program.ipynb index d2d02c57b8..c92cd85424 100644 --- a/examples/notebook/graph/simple_min_cost_flow_program.ipynb +++ b/examples/notebook/graph/simple_min_cost_flow_program.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "From Bradley, Hax and Maganti, 'Applied Mathematical Programming', figure 8.1." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,74 +82,51 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"From Bradley, Hax and Maganti, 'Applied Mathematical Programming', figure 8.1.\"\"\"\n", - "# [START import]\n", "from ortools.graph.python import min_cost_flow\n", - "# [END import]\n", "\n", "\n", - "\"\"\"MinCostFlow simple interface example.\"\"\"\n", - "# [START solver]\n", - "# Instantiate a SimpleMinCostFlow solver.\n", - "smcf = min_cost_flow.SimpleMinCostFlow()\n", - "# [END solver]\n", + "def main():\n", + " \"\"\"MinCostFlow simple interface example.\"\"\"\n", + " # Instantiate a SimpleMinCostFlow solver.\n", + " smcf = min_cost_flow.SimpleMinCostFlow()\n", "\n", - "# [START data]\n", - "# Define four parallel arrays: sources, destinations, capacities,\n", - "# and unit costs between each pair. For instance, the arc from node 0\n", - "# to node 1 has a capacity of 15.\n", - "start_nodes = [0, 0, 1, 1, 1, 2, 2, 3, 4]\n", - "end_nodes = [1, 2, 2, 3, 4, 3, 4, 4, 2]\n", - "capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5]\n", - "unit_costs = [4, 4, 2, 2, 6, 1, 3, 2, 3]\n", + " # Define four parallel arrays: sources, destinations, capacities,\n", + " # and unit costs between each pair. For instance, the arc from node 0\n", + " # to node 1 has a capacity of 15.\n", + " start_nodes = [0, 0, 1, 1, 1, 2, 2, 3, 4]\n", + " end_nodes = [1, 2, 2, 3, 4, 3, 4, 4, 2]\n", + " capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5]\n", + " unit_costs = [4, 4, 2, 2, 6, 1, 3, 2, 3]\n", "\n", - "# Define an array of supplies at each node.\n", - "supplies = [20, 0, 0, -5, -15]\n", - "# [END data]\n", + " # Define an array of supplies at each node.\n", + " supplies = [20, 0, 0, -5, -15]\n", "\n", - "# [START constraints]\n", - "# Add each arc.\n", - "for arc in zip(start_nodes, end_nodes, capacities, unit_costs):\n", - " smcf.add_arc_with_capacity_and_unit_cost(arc[0], arc[1], arc[2], arc[3])\n", + " # Add each arc.\n", + " for arc in zip(start_nodes, end_nodes, capacities, unit_costs):\n", + " smcf.add_arc_with_capacity_and_unit_cost(arc[0], arc[1], arc[2], arc[3])\n", "\n", - "# Add node supply.\n", - "for count, supply in enumerate(supplies):\n", - " smcf.set_node_supply(count, supply)\n", - "# [END constraints]\n", + " # Add node supply.\n", + " for count, supply in enumerate(supplies):\n", + " smcf.set_node_supply(count, supply)\n", "\n", - "# [START solve]\n", - "# Find the min cost flow.\n", - "status = smcf.solve()\n", - "# [END solve]\n", + " # Find the min cost flow.\n", + " status = smcf.solve()\n", "\n", - "# [START print_solution]\n", - "if status != smcf.OPTIMAL:\n", - " print('There was an issue with the min cost flow input.')\n", - " print(f'Status: {status}')\n", - " exit(1)\n", - "print('Minimum cost: ', smcf.optimal_cost())\n", - "print('')\n", - "print(' Arc Flow / Capacity Cost')\n", - "for i in range(smcf.num_arcs()):\n", - " cost = smcf.flow(i) * smcf.unit_cost(i)\n", - " print(\n", - " '%1s -> %1s %3s / %3s %3s' %\n", - " (smcf.tail(i), smcf.head(i), smcf.flow(i), smcf.capacity(i), cost))\n", - "# [END print_solution]\n", + " if status != smcf.OPTIMAL:\n", + " print('There was an issue with the min cost flow input.')\n", + " print(f'Status: {status}')\n", + " exit(1)\n", + " print('Minimum cost: ', smcf.optimal_cost())\n", + " print('')\n", + " print(' Arc Flow / Capacity Cost')\n", + " for i in range(smcf.num_arcs()):\n", + " cost = smcf.flow(i) * smcf.unit_cost(i)\n", + " print(\n", + " '%1s -> %1s %3s / %3s %3s' %\n", + " (smcf.tail(i), smcf.head(i), smcf.flow(i), smcf.capacity(i), cost))\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/assignment_groups_mip.ipynb b/examples/notebook/linear_solver/assignment_groups_mip.ipynb index 7d137af6e2..9705ec038c 100644 --- a/examples/notebook/linear_solver/assignment_groups_mip.ipynb +++ b/examples/notebook/linear_solver/assignment_groups_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve assignment problem for given group of workers." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,178 +82,147 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Solve assignment problem for given group of workers.\"\"\"\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data]\n", - "costs = [\n", - " [90, 76, 75, 70, 50, 74],\n", - " [35, 85, 55, 65, 48, 101],\n", - " [125, 95, 90, 105, 59, 120],\n", - " [45, 110, 95, 115, 104, 83],\n", - " [60, 105, 80, 75, 59, 62],\n", - " [45, 65, 110, 95, 47, 31],\n", - " [38, 51, 107, 41, 69, 99],\n", - " [47, 85, 57, 71, 92, 77],\n", - " [39, 63, 97, 49, 118, 56],\n", - " [47, 101, 71, 60, 88, 109],\n", - " [17, 39, 103, 64, 61, 92],\n", - " [101, 45, 83, 59, 92, 27],\n", - "]\n", - "num_workers = len(costs)\n", - "num_tasks = len(costs[0])\n", - "# [END data]\n", + "def main():\n", + " # Data\n", + " costs = [\n", + " [90, 76, 75, 70, 50, 74],\n", + " [35, 85, 55, 65, 48, 101],\n", + " [125, 95, 90, 105, 59, 120],\n", + " [45, 110, 95, 115, 104, 83],\n", + " [60, 105, 80, 75, 59, 62],\n", + " [45, 65, 110, 95, 47, 31],\n", + " [38, 51, 107, 41, 69, 99],\n", + " [47, 85, 57, 71, 92, 77],\n", + " [39, 63, 97, 49, 118, 56],\n", + " [47, 101, 71, 60, 88, 109],\n", + " [17, 39, 103, 64, 61, 92],\n", + " [101, 45, 83, 59, 92, 27],\n", + " ]\n", + " num_workers = len(costs)\n", + " num_tasks = len(costs[0])\n", "\n", - "# Allowed groups of workers:\n", - "# [START allowed_groups]\n", - "group1 = [ # Subgroups of workers 0 - 3\n", - " [2, 3],\n", - " [1, 3],\n", - " [1, 2],\n", - " [0, 1],\n", - " [0, 2],\n", - "]\n", + " # Allowed groups of workers:\n", + " group1 = [ # Subgroups of workers 0 - 3\n", + " [2, 3],\n", + " [1, 3],\n", + " [1, 2],\n", + " [0, 1],\n", + " [0, 2],\n", + " ]\n", "\n", - "group2 = [ # Subgroups of workers 4 - 7\n", - " [6, 7],\n", - " [5, 7],\n", - " [5, 6],\n", - " [4, 5],\n", - " [4, 7],\n", - "]\n", + " group2 = [ # Subgroups of workers 4 - 7\n", + " [6, 7],\n", + " [5, 7],\n", + " [5, 6],\n", + " [4, 5],\n", + " [4, 7],\n", + " ]\n", "\n", - "group3 = [ # Subgroups of workers 8 - 11\n", - " [10, 11],\n", - " [9, 11],\n", - " [9, 10],\n", - " [8, 10],\n", - " [8, 11],\n", - "]\n", - "# [END allowed_groups]\n", + " group3 = [ # Subgroups of workers 8 - 11\n", + " [10, 11],\n", + " [9, 11],\n", + " [9, 10],\n", + " [8, 10],\n", + " [8, 11],\n", + " ]\n", "\n", - "# Solver.\n", - "# [START solver]\n", - "# Create the mip solver with the SCIP backend.\n", - "solver = pywraplp.Solver.CreateSolver('SCIP')\n", - "# [END solver]\n", + " # Solver.\n", + " # Create the mip solver with the SCIP backend.\n", + " solver = pywraplp.Solver.CreateSolver('SCIP')\n", "\n", - "# Variables\n", - "# [START variables]\n", - "# x[worker, task] is an array of 0-1 variables, which will be 1\n", - "# if the worker is assigned to the task.\n", - "x = {}\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " x[worker, task] = solver.BoolVar(f'x[{worker},{task}]')\n", - "# [END variables]\n", - "\n", - "# Constraints\n", - "# [START constraints]\n", - "# The total size of the tasks each worker takes on is at most total_size_max.\n", - "for worker in range(num_workers):\n", - " solver.Add(\n", - " solver.Sum([x[worker, task] for task in range(num_tasks)]) <= 1)\n", - "\n", - "# Each task is assigned to exactly one worker.\n", - "for task in range(num_tasks):\n", - " solver.Add(\n", - " solver.Sum([x[worker, task] for worker in range(num_workers)]) == 1)\n", - "# [END constraints]\n", - "\n", - "# [START assignments]\n", - "# Create variables for each worker, indicating whether they work on some task.\n", - "work = {}\n", - "for worker in range(num_workers):\n", - " work[worker] = solver.BoolVar(f'work[{worker}]')\n", - "\n", - "for worker in range(num_workers):\n", - " solver.Add(work[worker] == solver.Sum(\n", - " [x[worker, task] for task in range(num_tasks)]))\n", - "\n", - "# Group1\n", - "constraint_g1 = solver.Constraint(1, 1)\n", - "for i in range(len(group1)):\n", - " # a*b can be transformed into 0 <= a + b - 2*p <= 1 with p in [0,1]\n", - " # p is True if a AND b, False otherwise\n", - " constraint = solver.Constraint(0, 1)\n", - " constraint.SetCoefficient(work[group1[i][0]], 1)\n", - " constraint.SetCoefficient(work[group1[i][1]], 1)\n", - " p = solver.BoolVar(f'g1_p{i}')\n", - " constraint.SetCoefficient(p, -2)\n", - "\n", - " constraint_g1.SetCoefficient(p, 1)\n", - "\n", - "# Group2\n", - "constraint_g2 = solver.Constraint(1, 1)\n", - "for i in range(len(group2)):\n", - " # a*b can be transformed into 0 <= a + b - 2*p <= 1 with p in [0,1]\n", - " # p is True if a AND b, False otherwise\n", - " constraint = solver.Constraint(0, 1)\n", - " constraint.SetCoefficient(work[group2[i][0]], 1)\n", - " constraint.SetCoefficient(work[group2[i][1]], 1)\n", - " p = solver.BoolVar(f'g2_p{i}')\n", - " constraint.SetCoefficient(p, -2)\n", - "\n", - " constraint_g2.SetCoefficient(p, 1)\n", - "\n", - "# Group3\n", - "constraint_g3 = solver.Constraint(1, 1)\n", - "for i in range(len(group3)):\n", - " # a*b can be transformed into 0 <= a + b - 2*p <= 1 with p in [0,1]\n", - " # p is True if a AND b, False otherwise\n", - " constraint = solver.Constraint(0, 1)\n", - " constraint.SetCoefficient(work[group3[i][0]], 1)\n", - " constraint.SetCoefficient(work[group3[i][1]], 1)\n", - " p = solver.BoolVar(f'g3_p{i}')\n", - " constraint.SetCoefficient(p, -2)\n", - "\n", - " constraint_g3.SetCoefficient(p, 1)\n", - "# [END assignments]\n", - "\n", - "# Objective\n", - "# [START objective]\n", - "objective_terms = []\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " objective_terms.append(costs[worker][task] * x[worker, task])\n", - "solver.Minimize(solver.Sum(objective_terms))\n", - "# [END objective]\n", - "\n", - "# Solve\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n", - " print(f'Total cost = {solver.Objective().Value()}\\n')\n", + " # Variables\n", + " # x[worker, task] is an array of 0-1 variables, which will be 1\n", + " # if the worker is assigned to the task.\n", + " x = {}\n", " for worker in range(num_workers):\n", " for task in range(num_tasks):\n", - " if x[worker, task].solution_value() > 0.5:\n", - " print(f'Worker {worker} assigned to task {task}.' +\n", - " f' Cost: {costs[worker][task]}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " x[worker, task] = solver.BoolVar(f'x[{worker},{task}]')\n", + "\n", + " # Constraints\n", + " # The total size of the tasks each worker takes on is at most total_size_max.\n", + " for worker in range(num_workers):\n", + " solver.Add(\n", + " solver.Sum([x[worker, task] for task in range(num_tasks)]) <= 1)\n", + "\n", + " # Each task is assigned to exactly one worker.\n", + " for task in range(num_tasks):\n", + " solver.Add(\n", + " solver.Sum([x[worker, task] for worker in range(num_workers)]) == 1)\n", + "\n", + " # Create variables for each worker, indicating whether they work on some task.\n", + " work = {}\n", + " for worker in range(num_workers):\n", + " work[worker] = solver.BoolVar(f'work[{worker}]')\n", + "\n", + " for worker in range(num_workers):\n", + " solver.Add(work[worker] == solver.Sum(\n", + " [x[worker, task] for task in range(num_tasks)]))\n", + "\n", + " # Group1\n", + " constraint_g1 = solver.Constraint(1, 1)\n", + " for i in range(len(group1)):\n", + " # a*b can be transformed into 0 <= a + b - 2*p <= 1 with p in [0,1]\n", + " # p is True if a AND b, False otherwise\n", + " constraint = solver.Constraint(0, 1)\n", + " constraint.SetCoefficient(work[group1[i][0]], 1)\n", + " constraint.SetCoefficient(work[group1[i][1]], 1)\n", + " p = solver.BoolVar(f'g1_p{i}')\n", + " constraint.SetCoefficient(p, -2)\n", + "\n", + " constraint_g1.SetCoefficient(p, 1)\n", + "\n", + " # Group2\n", + " constraint_g2 = solver.Constraint(1, 1)\n", + " for i in range(len(group2)):\n", + " # a*b can be transformed into 0 <= a + b - 2*p <= 1 with p in [0,1]\n", + " # p is True if a AND b, False otherwise\n", + " constraint = solver.Constraint(0, 1)\n", + " constraint.SetCoefficient(work[group2[i][0]], 1)\n", + " constraint.SetCoefficient(work[group2[i][1]], 1)\n", + " p = solver.BoolVar(f'g2_p{i}')\n", + " constraint.SetCoefficient(p, -2)\n", + "\n", + " constraint_g2.SetCoefficient(p, 1)\n", + "\n", + " # Group3\n", + " constraint_g3 = solver.Constraint(1, 1)\n", + " for i in range(len(group3)):\n", + " # a*b can be transformed into 0 <= a + b - 2*p <= 1 with p in [0,1]\n", + " # p is True if a AND b, False otherwise\n", + " constraint = solver.Constraint(0, 1)\n", + " constraint.SetCoefficient(work[group3[i][0]], 1)\n", + " constraint.SetCoefficient(work[group3[i][1]], 1)\n", + " p = solver.BoolVar(f'g3_p{i}')\n", + " constraint.SetCoefficient(p, -2)\n", + "\n", + " constraint_g3.SetCoefficient(p, 1)\n", + "\n", + " # Objective\n", + " objective_terms = []\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " objective_terms.append(costs[worker][task] * x[worker, task])\n", + " solver.Minimize(solver.Sum(objective_terms))\n", + "\n", + " # Solve\n", + " status = solver.Solve()\n", + "\n", + " # Print solution.\n", + " if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n", + " print(f'Total cost = {solver.Objective().Value()}\\n')\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " if x[worker, task].solution_value() > 0.5:\n", + " print(f'Worker {worker} assigned to task {task}.' +\n", + " f' Cost: {costs[worker][task]}')\n", + " else:\n", + " print('No solution found.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/assignment_mip.ipynb b/examples/notebook/linear_solver/assignment_mip.ipynb index 33939636a0..af0bc7e807 100644 --- a/examples/notebook/linear_solver/assignment_mip.ipynb +++ b/examples/notebook/linear_solver/assignment_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "MIP example that solves an assignment problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,94 +82,67 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"MIP example that solves an assignment problem.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data_model]\n", - "costs = [\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", - "# [END data_model]\n", + "def main():\n", + " # Data\n", + " costs = [\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", - "# Solver\n", - "# [START solver]\n", - "# Create the mip solver with the SCIP backend.\n", - "solver = pywraplp.Solver.CreateSolver('SCIP')\n", + " # Solver\n", + " # Create the mip solver with the SCIP backend.\n", + " solver = pywraplp.Solver.CreateSolver('SCIP')\n", "\n", - "# [END solver]\n", "\n", - "# Variables\n", - "# [START 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] = solver.IntVar(0, 1, '')\n", - "# [END variables]\n", - "\n", - "# Constraints\n", - "# [START constraints]\n", - "# Each worker is assigned to at most 1 task.\n", - "for i in range(num_workers):\n", - " solver.Add(solver.Sum([x[i, j] for j in range(num_tasks)]) <= 1)\n", - "\n", - "# Each task is assigned to exactly one worker.\n", - "for j in range(num_tasks):\n", - " solver.Add(solver.Sum([x[i, j] for i in range(num_workers)]) == 1)\n", - "# [END constraints]\n", - "\n", - "# Objective\n", - "# [START objective]\n", - "objective_terms = []\n", - "for i in range(num_workers):\n", - " for j in range(num_tasks):\n", - " objective_terms.append(costs[i][j] * x[i, j])\n", - "solver.Minimize(solver.Sum(objective_terms))\n", - "# [END objective]\n", - "\n", - "# Solve\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n", - " print(f'Total cost = {solver.Objective().Value()}\\n')\n", + " # 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", - " # Test if x[i,j] is 1 (with tolerance for floating point arithmetic).\n", - " if x[i, j].solution_value() > 0.5:\n", - " print(f'Worker {i} assigned to task {j}.' +\n", - " f' Cost: {costs[i][j]}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " x[i, j] = solver.IntVar(0, 1, '')\n", + "\n", + " # Constraints\n", + " # Each worker is assigned to at most 1 task.\n", + " for i in range(num_workers):\n", + " solver.Add(solver.Sum([x[i, j] for j in range(num_tasks)]) <= 1)\n", + "\n", + " # Each task is assigned to exactly one worker.\n", + " for j in range(num_tasks):\n", + " solver.Add(solver.Sum([x[i, j] for i in range(num_workers)]) == 1)\n", + "\n", + " # Objective\n", + " objective_terms = []\n", + " for i in range(num_workers):\n", + " for j in range(num_tasks):\n", + " objective_terms.append(costs[i][j] * x[i, j])\n", + " solver.Minimize(solver.Sum(objective_terms))\n", + "\n", + " # Solve\n", + " status = solver.Solve()\n", + "\n", + " # Print solution.\n", + " if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n", + " print(f'Total cost = {solver.Objective().Value()}\\n')\n", + " for i in range(num_workers):\n", + " for j in range(num_tasks):\n", + " # Test if x[i,j] is 1 (with tolerance for floating point arithmetic).\n", + " if x[i, j].solution_value() > 0.5:\n", + " print(f'Worker {i} assigned to task {j}.' +\n", + " f' Cost: {costs[i][j]}')\n", + " else:\n", + " print('No solution found.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/assignment_task_sizes_mip.ipynb b/examples/notebook/linear_solver/assignment_task_sizes_mip.ipynb index 0eecaf6a17..aa3fba7b1b 100644 --- a/examples/notebook/linear_solver/assignment_task_sizes_mip.ipynb +++ b/examples/notebook/linear_solver/assignment_task_sizes_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "MIP example that solves an assignment problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,106 +82,79 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"MIP example that solves an assignment problem.\"\"\"\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data]\n", - "costs = [\n", - " [90, 76, 75, 70, 50, 74, 12, 68],\n", - " [35, 85, 55, 65, 48, 101, 70, 83],\n", - " [125, 95, 90, 105, 59, 120, 36, 73],\n", - " [45, 110, 95, 115, 104, 83, 37, 71],\n", - " [60, 105, 80, 75, 59, 62, 93, 88],\n", - " [45, 65, 110, 95, 47, 31, 81, 34],\n", - " [38, 51, 107, 41, 69, 99, 115, 48],\n", - " [47, 85, 57, 71, 92, 77, 109, 36],\n", - " [39, 63, 97, 49, 118, 56, 92, 61],\n", - " [47, 101, 71, 60, 88, 109, 52, 90],\n", - "]\n", - "num_workers = len(costs)\n", - "num_tasks = len(costs[0])\n", + "def main():\n", + " # Data\n", + " costs = [\n", + " [90, 76, 75, 70, 50, 74, 12, 68],\n", + " [35, 85, 55, 65, 48, 101, 70, 83],\n", + " [125, 95, 90, 105, 59, 120, 36, 73],\n", + " [45, 110, 95, 115, 104, 83, 37, 71],\n", + " [60, 105, 80, 75, 59, 62, 93, 88],\n", + " [45, 65, 110, 95, 47, 31, 81, 34],\n", + " [38, 51, 107, 41, 69, 99, 115, 48],\n", + " [47, 85, 57, 71, 92, 77, 109, 36],\n", + " [39, 63, 97, 49, 118, 56, 92, 61],\n", + " [47, 101, 71, 60, 88, 109, 52, 90],\n", + " ]\n", + " num_workers = len(costs)\n", + " num_tasks = len(costs[0])\n", "\n", - "task_sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n", - "# Maximum total of task sizes for any worker\n", - "total_size_max = 15\n", - "# [END data]\n", + " task_sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n", + " # Maximum total of task sizes for any worker\n", + " total_size_max = 15\n", "\n", - "# Solver\n", - "# [START solver]\n", - "# Create the mip solver with the SCIP backend.\n", - "solver = pywraplp.Solver.CreateSolver('SCIP')\n", + " # Solver\n", + " # Create the mip solver with the SCIP backend.\n", + " solver = pywraplp.Solver.CreateSolver('SCIP')\n", "\n", - "# [END solver]\n", "\n", - "# Variables\n", - "# [START 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 worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " x[worker, task] = solver.BoolVar(f'x[{worker},{task}]')\n", - "# [END variables]\n", - "\n", - "# Constraints\n", - "# [START constraints]\n", - "# The total size of the tasks each worker takes on is at most total_size_max.\n", - "for worker in range(num_workers):\n", - " solver.Add(\n", - " solver.Sum([\n", - " task_sizes[task] * x[worker, task] for task in range(num_tasks)\n", - " ]) <= total_size_max)\n", - "\n", - "# Each task is assigned to exactly one worker.\n", - "for task in range(num_tasks):\n", - " solver.Add(\n", - " solver.Sum([x[worker, task] for worker in range(num_workers)]) == 1)\n", - "# [END constraints]\n", - "\n", - "# Objective\n", - "# [START objective]\n", - "objective_terms = []\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " objective_terms.append(costs[worker][task] * x[worker, task])\n", - "solver.Minimize(solver.Sum(objective_terms))\n", - "# [END objective]\n", - "\n", - "# Solve\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n", - " print(f'Total cost = {solver.Objective().Value()}\\n')\n", + " # 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 worker in range(num_workers):\n", " for task in range(num_tasks):\n", - " if x[worker, task].solution_value() > 0.5:\n", - " print(f'Worker {worker} assigned to task {task}.' +\n", - " f' Cost: {costs[worker][task]}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " x[worker, task] = solver.BoolVar(f'x[{worker},{task}]')\n", + "\n", + " # Constraints\n", + " # The total size of the tasks each worker takes on is at most total_size_max.\n", + " for worker in range(num_workers):\n", + " solver.Add(\n", + " solver.Sum([\n", + " task_sizes[task] * x[worker, task] for task in range(num_tasks)\n", + " ]) <= total_size_max)\n", + "\n", + " # Each task is assigned to exactly one worker.\n", + " for task in range(num_tasks):\n", + " solver.Add(\n", + " solver.Sum([x[worker, task] for worker in range(num_workers)]) == 1)\n", + "\n", + " # Objective\n", + " objective_terms = []\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " objective_terms.append(costs[worker][task] * x[worker, task])\n", + " solver.Minimize(solver.Sum(objective_terms))\n", + "\n", + " # Solve\n", + " status = solver.Solve()\n", + "\n", + " # Print solution.\n", + " if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n", + " print(f'Total cost = {solver.Objective().Value()}\\n')\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " if x[worker, task].solution_value() > 0.5:\n", + " print(f'Worker {worker} assigned to task {task}.' +\n", + " f' Cost: {costs[worker][task]}')\n", + " else:\n", + " print('No solution found.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/assignment_teams_mip.ipynb b/examples/notebook/linear_solver/assignment_teams_mip.ipynb index 6f5c8c0270..6a258c2c9a 100644 --- a/examples/notebook/linear_solver/assignment_teams_mip.ipynb +++ b/examples/notebook/linear_solver/assignment_teams_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "MIP example that solves an assignment problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,114 +82,87 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"MIP example that solves an assignment problem.\"\"\"\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data]\n", - "costs = [\n", - " [90, 76, 75, 70],\n", - " [35, 85, 55, 65],\n", - " [125, 95, 90, 105],\n", - " [45, 110, 95, 115],\n", - " [60, 105, 80, 75],\n", - " [45, 65, 110, 95],\n", - "]\n", - "num_workers = len(costs)\n", - "num_tasks = len(costs[0])\n", + "def main():\n", + " # Data\n", + " costs = [\n", + " [90, 76, 75, 70],\n", + " [35, 85, 55, 65],\n", + " [125, 95, 90, 105],\n", + " [45, 110, 95, 115],\n", + " [60, 105, 80, 75],\n", + " [45, 65, 110, 95],\n", + " ]\n", + " num_workers = len(costs)\n", + " num_tasks = len(costs[0])\n", "\n", - "team1 = [0, 2, 4]\n", - "team2 = [1, 3, 5]\n", - "# Maximum total of tasks for any team\n", - "team_max = 2\n", - "# [END data]\n", + " team1 = [0, 2, 4]\n", + " team2 = [1, 3, 5]\n", + " # Maximum total of tasks for any team\n", + " team_max = 2\n", "\n", - "# Solver\n", - "# [START solver]\n", - "# Create the mip solver with the SCIP backend.\n", - "solver = pywraplp.Solver.CreateSolver('SCIP')\n", - "# [END solver]\n", + " # Solver\n", + " # Create the mip solver with the SCIP backend.\n", + " solver = pywraplp.Solver.CreateSolver('SCIP')\n", "\n", - "# Variables\n", - "# [START 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 worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " x[worker, task] = solver.BoolVar(f'x[{worker},{task}]')\n", - "# [END variables]\n", - "\n", - "# Constraints\n", - "# [START constraints]\n", - "# Each worker is assigned at most 1 task.\n", - "for worker in range(num_workers):\n", - " solver.Add(\n", - " solver.Sum([x[worker, task] for task in range(num_tasks)]) <= 1)\n", - "\n", - "# Each task is assigned to exactly one worker.\n", - "for task in range(num_tasks):\n", - " solver.Add(\n", - " solver.Sum([x[worker, task] for worker in range(num_workers)]) == 1)\n", - "\n", - "# Each team takes at most two tasks.\n", - "team1_tasks = []\n", - "for worker in team1:\n", - " for task in range(num_tasks):\n", - " team1_tasks.append(x[worker, task])\n", - "solver.Add(solver.Sum(team1_tasks) <= team_max)\n", - "\n", - "team2_tasks = []\n", - "for worker in team2:\n", - " for task in range(num_tasks):\n", - " team2_tasks.append(x[worker, task])\n", - "solver.Add(solver.Sum(team2_tasks) <= team_max)\n", - "# [END constraints]\n", - "\n", - "# Objective\n", - "# [START objective]\n", - "objective_terms = []\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " objective_terms.append(costs[worker][task] * x[worker, task])\n", - "solver.Minimize(solver.Sum(objective_terms))\n", - "# [END objective]\n", - "\n", - "# Solve\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n", - " print(f'Total cost = {solver.Objective().Value()}\\n')\n", + " # 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 worker in range(num_workers):\n", " for task in range(num_tasks):\n", - " if x[worker, task].solution_value() > 0.5:\n", - " print(f'Worker {worker} assigned to task {task}.' +\n", - " f' Cost = {costs[worker][task]}')\n", - "else:\n", - " print('No solution found.')\n", - "print(f'Time = {solver.WallTime()} ms')\n", - "# [END print_solution]\n", + " x[worker, task] = solver.BoolVar(f'x[{worker},{task}]')\n", + "\n", + " # Constraints\n", + " # Each worker is assigned at most 1 task.\n", + " for worker in range(num_workers):\n", + " solver.Add(\n", + " solver.Sum([x[worker, task] for task in range(num_tasks)]) <= 1)\n", + "\n", + " # Each task is assigned to exactly one worker.\n", + " for task in range(num_tasks):\n", + " solver.Add(\n", + " solver.Sum([x[worker, task] for worker in range(num_workers)]) == 1)\n", + "\n", + " # Each team takes at most two tasks.\n", + " team1_tasks = []\n", + " for worker in team1:\n", + " for task in range(num_tasks):\n", + " team1_tasks.append(x[worker, task])\n", + " solver.Add(solver.Sum(team1_tasks) <= team_max)\n", + "\n", + " team2_tasks = []\n", + " for worker in team2:\n", + " for task in range(num_tasks):\n", + " team2_tasks.append(x[worker, task])\n", + " solver.Add(solver.Sum(team2_tasks) <= team_max)\n", + "\n", + " # Objective\n", + " objective_terms = []\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " objective_terms.append(costs[worker][task] * x[worker, task])\n", + " solver.Minimize(solver.Sum(objective_terms))\n", + "\n", + " # Solve\n", + " status = solver.Solve()\n", + "\n", + " # Print solution.\n", + " if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n", + " print(f'Total cost = {solver.Objective().Value()}\\n')\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " if x[worker, task].solution_value() > 0.5:\n", + " print(f'Worker {worker} assigned to task {task}.' +\n", + " f' Cost = {costs[worker][task]}')\n", + " else:\n", + " print('No solution found.')\n", + " print(f'Time = {solver.WallTime()} ms')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/basic_example.ipynb b/examples/notebook/linear_solver/basic_example.ipynb index 7094c3cc0b..0a5b325511 100644 --- a/examples/notebook/linear_solver/basic_example.ipynb +++ b/examples/notebook/linear_solver/basic_example.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Minimal example to call the GLOP solver." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,67 +82,48 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Minimal example to call the GLOP solver.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", "from ortools.init import pywrapinit\n", - "# [END import]\n", "\n", "\n", - "# [START solver]\n", - "# Create the linear solver with the GLOP backend.\n", - "solver = pywraplp.Solver.CreateSolver('GLOP')\n", - "# [END solver]\n", + "def main():\n", + " # Create the linear solver with the GLOP backend.\n", + " solver = pywraplp.Solver.CreateSolver('GLOP')\n", "\n", - "# [START variables]\n", - "# Create the variables x and y.\n", - "x = solver.NumVar(0, 1, 'x')\n", - "y = solver.NumVar(0, 2, 'y')\n", + " # Create the variables x and y.\n", + " x = solver.NumVar(0, 1, 'x')\n", + " y = solver.NumVar(0, 2, 'y')\n", "\n", - "print('Number of variables =', solver.NumVariables())\n", - "# [END variables]\n", + " print('Number of variables =', solver.NumVariables())\n", "\n", - "# [START constraints]\n", - "# Create a linear constraint, 0 <= x + y <= 2.\n", - "ct = solver.Constraint(0, 2, 'ct')\n", - "ct.SetCoefficient(x, 1)\n", - "ct.SetCoefficient(y, 1)\n", + " # Create a linear constraint, 0 <= x + y <= 2.\n", + " ct = solver.Constraint(0, 2, 'ct')\n", + " ct.SetCoefficient(x, 1)\n", + " ct.SetCoefficient(y, 1)\n", "\n", - "print('Number of constraints =', solver.NumConstraints())\n", - "# [END constraints]\n", + " print('Number of constraints =', solver.NumConstraints())\n", "\n", - "# [START objective]\n", - "# Create the objective function, 3 * x + y.\n", - "objective = solver.Objective()\n", - "objective.SetCoefficient(x, 3)\n", - "objective.SetCoefficient(y, 1)\n", - "objective.SetMaximization()\n", - "# [END objective]\n", + " # Create the objective function, 3 * x + y.\n", + " objective = solver.Objective()\n", + " objective.SetCoefficient(x, 3)\n", + " objective.SetCoefficient(y, 1)\n", + " objective.SetMaximization()\n", "\n", - "# [START solve]\n", - "solver.Solve()\n", - "# [END solve]\n", + " solver.Solve()\n", "\n", - "# [START print_solution]\n", - "print('Solution:')\n", - "print('Objective value =', objective.Value())\n", - "print('x =', x.solution_value())\n", - "print('y =', y.solution_value())\n", - "# [END print_solution]\n", + " print('Solution:')\n", + " print('Objective value =', objective.Value())\n", + " print('x =', x.solution_value())\n", + " print('y =', y.solution_value())\n", + "\n", + "\n", + "pywrapinit.CppBridge.InitLogging('basic_example.py')\n", + "cpp_flags = pywrapinit.CppFlags()\n", + "cpp_flags.logtostderr = True\n", + "cpp_flags.log_prefix = False\n", + "pywrapinit.CppBridge.SetFlags(cpp_flags)\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/bin_packing_mip.ipynb b/examples/notebook/linear_solver/bin_packing_mip.ipynb index 6bb05adaa7..55bc755917 100644 --- a/examples/notebook/linear_solver/bin_packing_mip.ipynb +++ b/examples/notebook/linear_solver/bin_packing_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve a simple bin packing problem using a MIP solver." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,28 +82,9 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solve a simple bin packing problem using a MIP solver.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# [START program_part1]\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Create the data for the example.\"\"\"\n", " data = {}\n", @@ -106,80 +95,67 @@ " data['bin_capacity'] = 100\n", " return data\n", "\n", - "# [END data_model]\n", "\n", "\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", - "# [END program_part1]\n", + "def main():\n", + " data = create_data_model()\n", "\n", - "# [START solver]\n", - "# Create the mip solver with the SCIP backend.\n", - "solver = pywraplp.Solver.CreateSolver('SCIP')\n", + " # Create the mip solver with the SCIP backend.\n", + " solver = pywraplp.Solver.CreateSolver('SCIP')\n", "\n", - "# [END solver]\n", "\n", - "# [START program_part2]\n", - "# [START variables]\n", - "# Variables\n", - "# x[i, j] = 1 if item i is packed in bin j.\n", - "x = {}\n", - "for i in data['items']:\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)] = solver.IntVar(0, 1, 'x_%i_%i' % (i, j))\n", + "\n", + " # y[j] = 1 if bin j is used.\n", + " y = {}\n", " for j in data['bins']:\n", - " x[(i, j)] = solver.IntVar(0, 1, 'x_%i_%i' % (i, j))\n", + " y[j] = solver.IntVar(0, 1, 'y[%i]' % j)\n", "\n", - "# y[j] = 1 if bin j is used.\n", - "y = {}\n", - "for j in data['bins']:\n", - " y[j] = solver.IntVar(0, 1, 'y[%i]' % j)\n", - "# [END variables]\n", + " # Constraints\n", + " # Each item must be in exactly one bin.\n", + " for i in data['items']:\n", + " solver.Add(sum(x[i, j] for j in data['bins']) == 1)\n", "\n", - "# [START constraints]\n", - "# Constraints\n", - "# Each item must be in exactly one bin.\n", - "for i in data['items']:\n", - " solver.Add(sum(x[i, j] for j in data['bins']) == 1)\n", - "\n", - "# The amount packed in each bin cannot exceed its capacity.\n", - "for j in data['bins']:\n", - " solver.Add(\n", - " sum(x[(i, j)] * data['weights'][i] for i in data['items']) <= y[j] *\n", - " data['bin_capacity'])\n", - "# [END constraints]\n", - "\n", - "# [START objective]\n", - "# Objective: minimize the number of bins used.\n", - "solver.Minimize(solver.Sum([y[j] for j in data['bins']]))\n", - "# [END objective]\n", - "\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", - "\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL:\n", - " num_bins = 0.\n", + " # The amount packed in each bin cannot exceed its capacity.\n", " for j in data['bins']:\n", - " if y[j].solution_value() == 1:\n", - " bin_items = []\n", - " bin_weight = 0\n", - " for i in data['items']:\n", - " if x[i, j].solution_value() > 0:\n", - " bin_items.append(i)\n", - " bin_weight += data['weights'][i]\n", - " if bin_weight > 0:\n", - " num_bins += 1\n", - " print('Bin number', j)\n", - " print(' Items packed:', bin_items)\n", - " print(' Total weight:', bin_weight)\n", - " print()\n", - " print()\n", - " print('Number of bins used:', num_bins)\n", - " print('Time = ', solver.WallTime(), ' milliseconds')\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + " solver.Add(\n", + " sum(x[(i, j)] * data['weights'][i] for i in data['items']) <= y[j] *\n", + " data['bin_capacity'])\n", + "\n", + " # Objective: minimize the number of bins used.\n", + " solver.Minimize(solver.Sum([y[j] for j in data['bins']]))\n", + "\n", + " status = solver.Solve()\n", + "\n", + " if status == pywraplp.Solver.OPTIMAL:\n", + " num_bins = 0.\n", + " for j in data['bins']:\n", + " if y[j].solution_value() == 1:\n", + " bin_items = []\n", + " bin_weight = 0\n", + " for i in data['items']:\n", + " if x[i, j].solution_value() > 0:\n", + " bin_items.append(i)\n", + " bin_weight += data['weights'][i]\n", + " if bin_weight > 0:\n", + " num_bins += 1\n", + " print('Bin number', j)\n", + " print(' Items packed:', bin_items)\n", + " print(' Total weight:', bin_weight)\n", + " print()\n", + " print()\n", + " print('Number of bins used:', num_bins)\n", + " print('Time = ', solver.WallTime(), ' milliseconds')\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/integer_programming_example.ipynb b/examples/notebook/linear_solver/integer_programming_example.ipynb index bfab2c3497..858c22a4bb 100644 --- a/examples/notebook/linear_solver/integer_programming_example.ipynb +++ b/examples/notebook/linear_solver/integer_programming_example.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Small example to illustrate solving a MIP problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,42 +82,20 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Small example to illustrate solving a MIP problem.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", "def IntegerProgrammingExample():\n", " \"\"\"Integer programming sample.\"\"\"\n", - " # [START solver]\n", " # Create the mip solver with the SCIP backend.\n", " solver = pywraplp.Solver.CreateSolver('SCIP')\n", "\n", - " # [END solver]\n", "\n", - " # [START variables]\n", " # x, y, and z are non-negative integer variables.\n", " x = solver.IntVar(0.0, solver.infinity(), 'x')\n", " y = solver.IntVar(0.0, solver.infinity(), 'y')\n", " z = solver.IntVar(0.0, solver.infinity(), 'z')\n", - " # [END variables]\n", "\n", - " # [START constraints]\n", " # 2*x + 7*y + 3*z <= 50\n", " constraint0 = solver.Constraint(-solver.infinity(), 50)\n", " constraint0.SetCoefficient(x, 2)\n", @@ -127,19 +113,15 @@ " constraint2.SetCoefficient(x, 5)\n", " constraint2.SetCoefficient(y, 2)\n", " constraint2.SetCoefficient(z, -6)\n", - " # [END constraints]\n", "\n", - " # [START objective]\n", " # Maximize 2*x + 2*y + 3*z\n", " objective = solver.Objective()\n", " objective.SetCoefficient(x, 2)\n", " objective.SetCoefficient(y, 2)\n", " objective.SetCoefficient(z, 3)\n", " objective.SetMaximization()\n", - " # [END objective]\n", "\n", " # Solve the problem and print the solution.\n", - " # [START print_solution]\n", " solver.Solve()\n", " # Print the objective value of the solution.\n", " print('Maximum objective function value = %d' % solver.Objective().Value())\n", @@ -147,11 +129,9 @@ " # Print the value of each variable in the solution.\n", " for variable in [x, y, z]:\n", " print('%s = %d' % (variable.name(), variable.solution_value()))\n", - " # [END print_solution]\n", "\n", "\n", "IntegerProgrammingExample()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/notebook/linear_solver/linear_programming_example.ipynb b/examples/notebook/linear_solver/linear_programming_example.ipynb index a156501851..45a8c17290 100644 --- a/examples/notebook/linear_solver/linear_programming_example.ipynb +++ b/examples/notebook/linear_solver/linear_programming_example.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Linear optimization example." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,42 +82,20 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Linear optimization example.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", "def LinearProgrammingExample():\n", " \"\"\"Linear programming sample.\"\"\"\n", " # Instantiate a Glop solver, naming it LinearExample.\n", - " # [START solver]\n", " solver = pywraplp.Solver.CreateSolver('GLOP')\n", - " # [END solver]\n", "\n", " # Create the two variables and let them take on any non-negative value.\n", - " # [START variables]\n", " x = solver.NumVar(0, solver.infinity(), 'x')\n", " y = solver.NumVar(0, solver.infinity(), 'y')\n", "\n", " print('Number of variables =', solver.NumVariables())\n", - " # [END variables]\n", "\n", - " # [START constraints]\n", " # Constraint 0: x + 2y <= 14.\n", " solver.Add(x + 2 * y <= 14.0)\n", "\n", @@ -120,19 +106,13 @@ " solver.Add(x - y <= 2.0)\n", "\n", " print('Number of constraints =', solver.NumConstraints())\n", - " # [END constraints]\n", "\n", - " # [START objective]\n", " # Objective function: 3x + 4y.\n", " solver.Maximize(3 * x + 4 * y)\n", - " # [END objective]\n", "\n", " # Solve the system.\n", - " # [START solve]\n", " status = solver.Solve()\n", - " # [END solve]\n", "\n", - " # [START print_solution]\n", " if status == pywraplp.Solver.OPTIMAL:\n", " print('Solution:')\n", " print('Objective value =', solver.Objective().Value())\n", @@ -140,17 +120,13 @@ " print('y =', y.solution_value())\n", " else:\n", " print('The problem does not have an optimal solution.')\n", - " # [END print_solution]\n", "\n", - " # [START advanced]\n", " print('\\nAdvanced usage:')\n", " print('Problem solved in %f milliseconds' % solver.wall_time())\n", " print('Problem solved in %d iterations' % solver.iterations())\n", - " # [END advanced]\n", "\n", "\n", "LinearProgrammingExample()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/notebook/linear_solver/mip_var_array.ipynb b/examples/notebook/linear_solver/mip_var_array.ipynb index 992a773559..2eac0e590a 100644 --- a/examples/notebook/linear_solver/mip_var_array.ipynb +++ b/examples/notebook/linear_solver/mip_var_array.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "MIP example that uses a variable array." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,28 +82,9 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"MIP example that uses a variable array.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# [START program_part1]\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Stores the data for the problem.\"\"\"\n", " data = {}\n", @@ -111,66 +100,53 @@ " data['num_constraints'] = 4\n", " return data\n", "\n", - "# [END data_model]\n", "\n", "\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", - "# [END program_part1]\n", - "# [START solver]\n", - "# Create the mip solver with the SCIP backend.\n", - "solver = pywraplp.Solver.CreateSolver('SCIP')\n", - "# [END solver]\n", + "def main():\n", + " data = create_data_model()\n", + " # Create the mip solver with the SCIP backend.\n", + " solver = pywraplp.Solver.CreateSolver('SCIP')\n", "\n", - "# [START program_part2]\n", - "# [START variables]\n", - "infinity = solver.infinity()\n", - "x = {}\n", - "for j in range(data['num_vars']):\n", - " x[j] = solver.IntVar(0, infinity, 'x[%i]' % j)\n", - "print('Number of variables =', solver.NumVariables())\n", - "# [END variables]\n", - "\n", - "# [START constraints]\n", - "for i in range(data['num_constraints']):\n", - " constraint = solver.RowConstraint(0, data['bounds'][i], '')\n", + " infinity = solver.infinity()\n", + " x = {}\n", " for j in range(data['num_vars']):\n", - " constraint.SetCoefficient(x[j], data['constraint_coeffs'][i][j])\n", - "print('Number of constraints =', solver.NumConstraints())\n", - "# In Python, you can also set the constraints as follows.\n", - "# for i in range(data['num_constraints']):\n", - "# constraint_expr = \\\n", - "# [data['constraint_coeffs'][i][j] * x[j] for j in range(data['num_vars'])]\n", - "# solver.Add(sum(constraint_expr) <= data['bounds'][i])\n", - "# [END constraints]\n", + " x[j] = solver.IntVar(0, infinity, 'x[%i]' % j)\n", + " print('Number of variables =', solver.NumVariables())\n", "\n", - "# [START objective]\n", - "objective = solver.Objective()\n", - "for j in range(data['num_vars']):\n", - " objective.SetCoefficient(x[j], data['obj_coeffs'][j])\n", - "objective.SetMaximization()\n", - "# In Python, you can also set the objective as follows.\n", - "# obj_expr = [data['obj_coeffs'][j] * x[j] for j in range(data['num_vars'])]\n", - "# solver.Maximize(solver.Sum(obj_expr))\n", - "# [END objective]\n", + " for i in range(data['num_constraints']):\n", + " constraint = solver.RowConstraint(0, data['bounds'][i], '')\n", + " for j in range(data['num_vars']):\n", + " constraint.SetCoefficient(x[j], data['constraint_coeffs'][i][j])\n", + " print('Number of constraints =', solver.NumConstraints())\n", + " # In Python, you can also set the constraints as follows.\n", + " # for i in range(data['num_constraints']):\n", + " # constraint_expr = \\\n", + " # [data['constraint_coeffs'][i][j] * x[j] for j in range(data['num_vars'])]\n", + " # solver.Add(sum(constraint_expr) <= data['bounds'][i])\n", "\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", - "\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL:\n", - " print('Objective value =', solver.Objective().Value())\n", + " objective = solver.Objective()\n", " for j in range(data['num_vars']):\n", - " print(x[j].name(), ' = ', x[j].solution_value())\n", - " print()\n", - " print('Problem solved in %f milliseconds' % solver.wall_time())\n", - " print('Problem solved in %d iterations' % solver.iterations())\n", - " print('Problem solved in %d branch-and-bound nodes' % solver.nodes())\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + " objective.SetCoefficient(x[j], data['obj_coeffs'][j])\n", + " objective.SetMaximization()\n", + " # In Python, you can also set the objective as follows.\n", + " # obj_expr = [data['obj_coeffs'][j] * x[j] for j in range(data['num_vars'])]\n", + " # solver.Maximize(solver.Sum(obj_expr))\n", + "\n", + " status = solver.Solve()\n", + "\n", + " if status == pywraplp.Solver.OPTIMAL:\n", + " print('Objective value =', solver.Objective().Value())\n", + " for j in range(data['num_vars']):\n", + " print(x[j].name(), ' = ', x[j].solution_value())\n", + " print()\n", + " print('Problem solved in %f milliseconds' % solver.wall_time())\n", + " print('Problem solved in %d iterations' % solver.iterations())\n", + " print('Problem solved in %d branch-and-bound nodes' % solver.nodes())\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/multiple_knapsack_mip.ipynb b/examples/notebook/linear_solver/multiple_knapsack_mip.ipynb index 835735e83e..73908936d7 100644 --- a/examples/notebook/linear_solver/multiple_knapsack_mip.ipynb +++ b/examples/notebook/linear_solver/multiple_knapsack_mip.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve a multiple knapsack problem using a MIP solver." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,109 +82,82 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Solve a multiple knapsack problem using a MIP solver.\"\"\"\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# [START data]\n", - "data = {}\n", - "data['weights'] = [\n", - " 48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36\n", - "]\n", - "data['values'] = [\n", - " 10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25\n", - "]\n", - "assert len(data['weights']) == len(data['values'])\n", - "data['num_items'] = len(data['weights'])\n", - "data['all_items'] = range(data['num_items'])\n", + "def main():\n", + " data = {}\n", + " data['weights'] = [\n", + " 48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36\n", + " ]\n", + " data['values'] = [\n", + " 10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25\n", + " ]\n", + " assert len(data['weights']) == len(data['values'])\n", + " data['num_items'] = len(data['weights'])\n", + " data['all_items'] = range(data['num_items'])\n", "\n", - "data['bin_capacities'] = [100, 100, 100, 100, 100]\n", - "data['num_bins'] = len(data['bin_capacities'])\n", - "data['all_bins'] = range(data['num_bins'])\n", - "# [END data]\n", + " data['bin_capacities'] = [100, 100, 100, 100, 100]\n", + " data['num_bins'] = len(data['bin_capacities'])\n", + " data['all_bins'] = range(data['num_bins'])\n", "\n", - "# Create the mip solver with the SCIP backend.\n", - "# [START solver]\n", - "solver = pywraplp.Solver.CreateSolver('SCIP')\n", - "if solver is None:\n", - " print('SCIP solver unavailable.')\n", - " return\n", - "# [END solver]\n", + " # Create the mip solver with the SCIP backend.\n", + " solver = pywraplp.Solver.CreateSolver('SCIP')\n", + " if solver is None:\n", + " print('SCIP solver unavailable.')\n", + " return\n", "\n", - "# Variables.\n", - "# [START variables]\n", - "# x[i, b] = 1 if item i is packed in bin b.\n", - "x = {}\n", - "for i in data['all_items']:\n", + " # Variables.\n", + " # x[i, b] = 1 if item i is packed in bin b.\n", + " x = {}\n", + " for i in data['all_items']:\n", + " for b in data['all_bins']:\n", + " x[i, b] = solver.BoolVar(f'x_{i}_{b}')\n", + "\n", + " # Constraints.\n", + " # Each item is assigned to at most one bin.\n", + " for i in data['all_items']:\n", + " solver.Add(sum(x[i, b] for b in data['all_bins']) <= 1)\n", + "\n", + " # The amount packed in each bin cannot exceed its capacity.\n", " for b in data['all_bins']:\n", - " x[i, b] = solver.BoolVar(f'x_{i}_{b}')\n", - "# [END variables]\n", + " solver.Add(\n", + " sum(x[i, b] * data['weights'][i]\n", + " for i in data['all_items']) <= data['bin_capacities'][b])\n", "\n", - "# Constraints.\n", - "# [START constraints]\n", - "# Each item is assigned to at most one bin.\n", - "for i in data['all_items']:\n", - " solver.Add(sum(x[i, b] for b in data['all_bins']) <= 1)\n", + " # Objective.\n", + " # Maximize total value of packed items.\n", + " objective = solver.Objective()\n", + " for i in data['all_items']:\n", + " for b in data['all_bins']:\n", + " objective.SetCoefficient(x[i, b], data['values'][i])\n", + " objective.SetMaximization()\n", "\n", - "# The amount packed in each bin cannot exceed its capacity.\n", - "for b in data['all_bins']:\n", - " solver.Add(\n", - " sum(x[i, b] * data['weights'][i]\n", - " for i in data['all_items']) <= data['bin_capacities'][b])\n", - "# [END constraints]\n", + " status = solver.Solve()\n", "\n", - "# Objective.\n", - "# [START objective]\n", - "# Maximize total value of packed items.\n", - "objective = solver.Objective()\n", - "for i in data['all_items']:\n", - " for b in data['all_bins']:\n", - " objective.SetCoefficient(x[i, b], data['values'][i])\n", - "objective.SetMaximization()\n", - "# [END objective]\n", + " if status == pywraplp.Solver.OPTIMAL:\n", + " print(f'Total packed value: {objective.Value()}')\n", + " total_weight = 0\n", + " for b in data['all_bins']:\n", + " print(f'Bin {b}')\n", + " bin_weight = 0\n", + " bin_value = 0\n", + " for i in data['all_items']:\n", + " if x[i, b].solution_value() > 0:\n", + " print(\n", + " f\"Item {i} weight: {data['weights'][i]} value: {data['values'][i]}\"\n", + " )\n", + " bin_weight += data['weights'][i]\n", + " bin_value += data['values'][i]\n", + " print(f'Packed bin weight: {bin_weight}')\n", + " print(f'Packed bin value: {bin_value}\\n')\n", + " total_weight += bin_weight\n", + " print(f'Total packed weight: {total_weight}')\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", "\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", "\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL:\n", - " print(f'Total packed value: {objective.Value()}')\n", - " total_weight = 0\n", - " for b in data['all_bins']:\n", - " print(f'Bin {b}')\n", - " bin_weight = 0\n", - " bin_value = 0\n", - " for i in data['all_items']:\n", - " if x[i, b].solution_value() > 0:\n", - " print(\n", - " f\"Item {i} weight: {data['weights'][i]} value: {data['values'][i]}\"\n", - " )\n", - " bin_weight += data['weights'][i]\n", - " bin_value += data['values'][i]\n", - " print(f'Packed bin weight: {bin_weight}')\n", - " print(f'Packed bin value: {bin_value}\\n')\n", - " total_weight += bin_weight\n", - " print(f'Total packed weight: {total_weight}')\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/simple_lp_program.ipynb b/examples/notebook/linear_solver/simple_lp_program.ipynb index 4e8402ac1a..dc82aeb5b0 100644 --- a/examples/notebook/linear_solver/simple_lp_program.ipynb +++ b/examples/notebook/linear_solver/simple_lp_program.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Minimal example to call the GLOP solver." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,74 +82,47 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Minimal example to call the GLOP solver.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# [START solver]\n", - "# Create the linear solver with the GLOP backend.\n", - "solver = pywraplp.Solver.CreateSolver('GLOP')\n", - "# [END solver]\n", + "def main():\n", + " # Create the linear solver with the GLOP backend.\n", + " solver = pywraplp.Solver.CreateSolver('GLOP')\n", "\n", - "# [START variables]\n", - "infinity = solver.infinity()\n", - "# Create the variables x and y.\n", - "x = solver.NumVar(0.0, infinity, 'x')\n", - "y = solver.NumVar(0.0, infinity, 'y')\n", + " infinity = solver.infinity()\n", + " # Create the variables x and y.\n", + " x = solver.NumVar(0.0, infinity, 'x')\n", + " y = solver.NumVar(0.0, infinity, 'y')\n", "\n", - "print('Number of variables =', solver.NumVariables())\n", - "# [END variables]\n", + " print('Number of variables =', solver.NumVariables())\n", "\n", - "# [START constraints]\n", - "# x + 7 * y <= 17.5.\n", - "solver.Add(x + 7 * y <= 17.5)\n", + " # x + 7 * y <= 17.5.\n", + " solver.Add(x + 7 * y <= 17.5)\n", "\n", - "# x <= 3.5.\n", - "solver.Add(x <= 3.5)\n", + " # x <= 3.5.\n", + " solver.Add(x <= 3.5)\n", "\n", - "print('Number of constraints =', solver.NumConstraints())\n", - "# [END constraints]\n", + " print('Number of constraints =', solver.NumConstraints())\n", "\n", - "# [START objective]\n", - "# Maximize x + 10 * y.\n", - "solver.Maximize(x + 10 * y)\n", - "# [END objective]\n", + " # Maximize x + 10 * y.\n", + " solver.Maximize(x + 10 * y)\n", "\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", + " status = solver.Solve()\n", "\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL:\n", - " print('Solution:')\n", - " print('Objective value =', solver.Objective().Value())\n", - " print('x =', x.solution_value())\n", - " print('y =', y.solution_value())\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + " if status == pywraplp.Solver.OPTIMAL:\n", + " print('Solution:')\n", + " print('Objective value =', solver.Objective().Value())\n", + " print('x =', x.solution_value())\n", + " print('y =', y.solution_value())\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", "\n", - "# [START advanced]\n", - "print('\\nAdvanced usage:')\n", - "print('Problem solved in %f milliseconds' % solver.wall_time())\n", - "print('Problem solved in %d iterations' % solver.iterations())\n", - "# [END advanced]\n", + " print('\\nAdvanced usage:')\n", + " print('Problem solved in %f milliseconds' % solver.wall_time())\n", + " print('Problem solved in %d iterations' % solver.iterations())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/simple_mip_program.ipynb b/examples/notebook/linear_solver/simple_mip_program.ipynb index 95f5d45139..38a161c53c 100644 --- a/examples/notebook/linear_solver/simple_mip_program.ipynb +++ b/examples/notebook/linear_solver/simple_mip_program.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Integer programming examples that show how to use the APIs." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,75 +82,48 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Integer programming examples that show how to use the APIs.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "# [START solver]\n", - "# Create the mip solver with the SCIP backend.\n", - "solver = pywraplp.Solver.CreateSolver('SCIP')\n", - "# [END solver]\n", + "def main():\n", + " # Create the mip solver with the SCIP backend.\n", + " solver = pywraplp.Solver.CreateSolver('SCIP')\n", "\n", - "# [START variables]\n", - "infinity = solver.infinity()\n", - "# x and y are integer non-negative variables.\n", - "x = solver.IntVar(0.0, infinity, 'x')\n", - "y = solver.IntVar(0.0, infinity, 'y')\n", + " infinity = solver.infinity()\n", + " # x and y are integer non-negative variables.\n", + " x = solver.IntVar(0.0, infinity, 'x')\n", + " y = solver.IntVar(0.0, infinity, 'y')\n", "\n", - "print('Number of variables =', solver.NumVariables())\n", - "# [END variables]\n", + " print('Number of variables =', solver.NumVariables())\n", "\n", - "# [START constraints]\n", - "# x + 7 * y <= 17.5.\n", - "solver.Add(x + 7 * y <= 17.5)\n", + " # x + 7 * y <= 17.5.\n", + " solver.Add(x + 7 * y <= 17.5)\n", "\n", - "# x <= 3.5.\n", - "solver.Add(x <= 3.5)\n", + " # x <= 3.5.\n", + " solver.Add(x <= 3.5)\n", "\n", - "print('Number of constraints =', solver.NumConstraints())\n", - "# [END constraints]\n", + " print('Number of constraints =', solver.NumConstraints())\n", "\n", - "# [START objective]\n", - "# Maximize x + 10 * y.\n", - "solver.Maximize(x + 10 * y)\n", - "# [END objective]\n", + " # Maximize x + 10 * y.\n", + " solver.Maximize(x + 10 * y)\n", "\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", + " status = solver.Solve()\n", "\n", - "# [START print_solution]\n", - "if status == pywraplp.Solver.OPTIMAL:\n", - " print('Solution:')\n", - " print('Objective value =', solver.Objective().Value())\n", - " print('x =', x.solution_value())\n", - " print('y =', y.solution_value())\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + " if status == pywraplp.Solver.OPTIMAL:\n", + " print('Solution:')\n", + " print('Objective value =', solver.Objective().Value())\n", + " print('x =', x.solution_value())\n", + " print('y =', y.solution_value())\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", "\n", - "# [START advanced]\n", - "print('\\nAdvanced usage:')\n", - "print('Problem solved in %f milliseconds' % solver.wall_time())\n", - "print('Problem solved in %d iterations' % solver.iterations())\n", - "print('Problem solved in %d branch-and-bound nodes' % solver.nodes())\n", - "# [END advanced]\n", + " print('\\nAdvanced usage:')\n", + " print('Problem solved in %f milliseconds' % solver.wall_time())\n", + " print('Problem solved in %d iterations' % solver.iterations())\n", + " print('Problem solved in %d branch-and-bound nodes' % solver.nodes())\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/linear_solver/stigler_diet.ipynb b/examples/notebook/linear_solver/stigler_diet.ipynb index 55efa43a39..2c6da1933f 100644 --- a/examples/notebook/linear_solver/stigler_diet.ipynb +++ b/examples/notebook/linear_solver/stigler_diet.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,17 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "The Stigler diet problem.\n", + "\n", + "A description of the problem can be found here:\n", + "https://en.wikipedia.org/wiki/Stigler_diet.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,296 +85,263 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"The Stigler diet problem.\n", - "\n", - "A description of the problem can be found here:\n", - "https://en.wikipedia.org/wiki/Stigler_diet.\n", - "\"\"\"\n", - "# [START import]\n", "from ortools.linear_solver import pywraplp\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Entry point of the program.\"\"\"\n", - "# Instantiate the data problem.\n", - "# [START data_model]\n", - "# Nutrient minimums.\n", - "nutrients = [\n", - " ['Calories (kcal)', 3],\n", - " ['Protein (g)', 70],\n", - " ['Calcium (g)', 0.8],\n", - " ['Iron (mg)', 12],\n", - " ['Vitamin A (KIU)', 5],\n", - " ['Vitamin B1 (mg)', 1.8],\n", - " ['Vitamin B2 (mg)', 2.7],\n", - " ['Niacin (mg)', 18],\n", - " ['Vitamin C (mg)', 75],\n", - "]\n", + "def main():\n", + " \"\"\"Entry point of the program.\"\"\"\n", + " # Instantiate the data problem.\n", + " # Nutrient minimums.\n", + " nutrients = [\n", + " ['Calories (kcal)', 3],\n", + " ['Protein (g)', 70],\n", + " ['Calcium (g)', 0.8],\n", + " ['Iron (mg)', 12],\n", + " ['Vitamin A (KIU)', 5],\n", + " ['Vitamin B1 (mg)', 1.8],\n", + " ['Vitamin B2 (mg)', 2.7],\n", + " ['Niacin (mg)', 18],\n", + " ['Vitamin C (mg)', 75],\n", + " ]\n", "\n", - "# Commodity, Unit, 1939 price (cents), Calories (kcal), Protein (g),\n", - "# Calcium (g), Iron (mg), Vitamin A (KIU), Vitamin B1 (mg), Vitamin B2 (mg),\n", - "# Niacin (mg), Vitamin C (mg)\n", - "data = [\n", - " [\n", - " 'Wheat Flour (Enriched)', '10 lb.', 36, 44.7, 1411, 2, 365, 0, 55.4,\n", - " 33.3, 441, 0\n", - " ],\n", - " ['Macaroni', '1 lb.', 14.1, 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0],\n", - " [\n", - " 'Wheat Cereal (Enriched)', '28 oz.', 24.2, 11.8, 377, 14.4, 175, 0,\n", - " 14.4, 8.8, 114, 0\n", - " ],\n", - " ['Corn Flakes', '8 oz.', 7.1, 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0],\n", - " [\n", - " 'Corn Meal', '1 lb.', 4.6, 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106,\n", - " 0\n", - " ],\n", - " [\n", - " 'Hominy Grits', '24 oz.', 8.5, 28.6, 680, 0.8, 80, 0, 10.6, 1.6,\n", - " 110, 0\n", - " ],\n", - " ['Rice', '1 lb.', 7.5, 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0],\n", - " ['Rolled Oats', '1 lb.', 7.1, 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0],\n", - " [\n", - " 'White Bread (Enriched)', '1 lb.', 7.9, 15.0, 488, 2.5, 115, 0,\n", - " 13.8, 8.5, 126, 0\n", - " ],\n", - " [\n", - " 'Whole Wheat Bread', '1 lb.', 9.1, 12.2, 484, 2.7, 125, 0, 13.9,\n", - " 6.4, 160, 0\n", - " ],\n", - " ['Rye Bread', '1 lb.', 9.1, 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0],\n", - " ['Pound Cake', '1 lb.', 24.8, 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0],\n", - " ['Soda Crackers', '1 lb.', 15.1, 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0],\n", - " ['Milk', '1 qt.', 11, 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177],\n", - " [\n", - " 'Evaporated Milk (can)', '14.5 oz.', 6.7, 8.4, 422, 15.1, 9, 26, 3,\n", - " 23.5, 11, 60\n", - " ],\n", - " ['Butter', '1 lb.', 30.8, 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0],\n", - " ['Oleomargarine', '1 lb.', 16.1, 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0],\n", - " ['Eggs', '1 doz.', 32.6, 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0],\n", - " [\n", - " 'Cheese (Cheddar)', '1 lb.', 24.2, 7.4, 448, 16.4, 19, 28.1, 0.8,\n", - " 10.3, 4, 0\n", - " ],\n", - " ['Cream', '1/2 pt.', 14.1, 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17],\n", - " [\n", - " 'Peanut Butter', '1 lb.', 17.9, 15.7, 661, 1.0, 48, 0, 9.6, 8.1,\n", - " 471, 0\n", - " ],\n", - " ['Mayonnaise', '1/2 pt.', 16.7, 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0],\n", - " ['Crisco', '1 lb.', 20.3, 20.1, 0, 0, 0, 0, 0, 0, 0, 0],\n", - " ['Lard', '1 lb.', 9.8, 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0],\n", - " [\n", - " 'Sirloin Steak', '1 lb.', 39.6, 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9,\n", - " 69, 0\n", - " ],\n", - " ['Round Steak', '1 lb.', 36.4, 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0],\n", - " ['Rib Roast', '1 lb.', 29.2, 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0],\n", - " ['Chuck Roast', '1 lb.', 22.6, 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0],\n", - " ['Plate', '1 lb.', 14.6, 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0],\n", - " [\n", - " 'Liver (Beef)', '1 lb.', 26.8, 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8,\n", - " 316, 525\n", - " ],\n", - " ['Leg of Lamb', '1 lb.', 27.6, 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0],\n", - " [\n", - " 'Lamb Chops (Rib)', '1 lb.', 36.6, 3.3, 140, 0.1, 15, 0, 1.7, 2.7,\n", - " 54, 0\n", - " ],\n", - " ['Pork Chops', '1 lb.', 30.7, 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0],\n", - " [\n", - " 'Pork Loin Roast', '1 lb.', 24.2, 4.4, 249, 0.3, 37, 0, 18.2, 3.6,\n", - " 79, 0\n", - " ],\n", - " ['Bacon', '1 lb.', 25.6, 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0],\n", - " ['Ham, smoked', '1 lb.', 27.4, 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0],\n", - " ['Salt Pork', '1 lb.', 16, 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0],\n", - " [\n", - " 'Roasting Chicken', '1 lb.', 30.3, 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8,\n", - " 68, 46\n", - " ],\n", - " ['Veal Cutlets', '1 lb.', 42.3, 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0],\n", - " [\n", - " 'Salmon, Pink (can)', '16 oz.', 13, 5.8, 705, 6.8, 45, 3.5, 1, 4.9,\n", - " 209, 0\n", - " ],\n", - " ['Apples', '1 lb.', 4.4, 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544],\n", - " ['Bananas', '1 lb.', 6.1, 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498],\n", - " ['Lemons', '1 doz.', 26, 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952],\n", - " ['Oranges', '1 doz.', 30.9, 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998],\n", - " ['Green Beans', '1 lb.', 7.1, 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862],\n", - " ['Cabbage', '1 lb.', 3.7, 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369],\n", - " ['Carrots', '1 bunch', 4.7, 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608],\n", - " ['Celery', '1 stalk', 7.3, 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313],\n", - " ['Lettuce', '1 head', 8.2, 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449],\n", - " ['Onions', '1 lb.', 3.6, 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184],\n", - " [\n", - " 'Potatoes', '15 lb.', 34, 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198,\n", - " 2522\n", - " ],\n", - " ['Spinach', '1 lb.', 8.1, 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755],\n", - " [\n", - " 'Sweet Potatoes', '1 lb.', 5.1, 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4,\n", - " 83, 1912\n", - " ],\n", - " [\n", - " 'Peaches (can)', 'No. 2 1/2', 16.8, 3.7, 20, 0.4, 10, 21.5, 0.5, 1,\n", - " 31, 196\n", - " ],\n", - " [\n", - " 'Pears (can)', 'No. 2 1/2', 20.4, 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5,\n", - " 81\n", - " ],\n", - " [\n", - " 'Pineapple (can)', 'No. 2 1/2', 21.3, 2.4, 16, 0.4, 8, 2, 2.8, 0.8,\n", - " 7, 399\n", - " ],\n", - " [\n", - " 'Asparagus (can)', 'No. 2', 27.7, 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1,\n", - " 17, 272\n", - " ],\n", - " [\n", - " 'Green Beans (can)', 'No. 2', 10, 1.0, 54, 2, 65, 53.9, 1.6, 4.3,\n", - " 32, 431\n", - " ],\n", - " [\n", - " 'Pork and Beans (can)', '16 oz.', 7.1, 7.5, 364, 4, 134, 3.5, 8.3,\n", - " 7.7, 56, 0\n", - " ],\n", - " ['Corn (can)', 'No. 2', 10.4, 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218],\n", - " [\n", - " 'Peas (can)', 'No. 2', 13.8, 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37,\n", - " 370\n", - " ],\n", - " [\n", - " 'Tomatoes (can)', 'No. 2', 8.6, 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5,\n", - " 36, 1253\n", - " ],\n", - " [\n", - " 'Tomato Soup (can)', '10 1/2 oz.', 7.6, 1.6, 71, 0.6, 43, 57.9, 3.5,\n", - " 2.4, 67, 862\n", - " ],\n", - " [\n", - " 'Peaches, Dried', '1 lb.', 15.7, 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3,\n", - " 55, 57\n", - " ],\n", - " [\n", - " 'Prunes, Dried', '1 lb.', 9, 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65,\n", - " 257\n", - " ],\n", - " [\n", - " 'Raisins, Dried', '15 oz.', 9.4, 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4,\n", - " 24, 136\n", - " ],\n", - " [\n", - " 'Peas, Dried', '1 lb.', 7.9, 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4,\n", - " 162, 0\n", - " ],\n", - " [\n", - " 'Lima Beans, Dried', '1 lb.', 8.9, 17.4, 1055, 3.7, 459, 5.1, 26.9,\n", - " 38.2, 93, 0\n", - " ],\n", - " [\n", - " 'Navy Beans, Dried', '1 lb.', 5.9, 26.9, 1691, 11.4, 792, 0, 38.4,\n", - " 24.6, 217, 0\n", - " ],\n", - " ['Coffee', '1 lb.', 22.4, 0, 0, 0, 0, 0, 4, 5.1, 50, 0],\n", - " ['Tea', '1/4 lb.', 17.4, 0, 0, 0, 0, 0, 0, 2.3, 42, 0],\n", - " ['Cocoa', '8 oz.', 8.6, 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0],\n", - " ['Chocolate', '8 oz.', 16.2, 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0],\n", - " ['Sugar', '10 lb.', 51.7, 34.9, 0, 0, 0, 0, 0, 0, 0, 0],\n", - " ['Corn Syrup', '24 oz.', 13.7, 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0],\n", - " ['Molasses', '18 oz.', 13.6, 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0],\n", - " [\n", - " 'Strawberry Preserves', '1 lb.', 20.5, 6.4, 11, 0.4, 7, 0.2, 0.2,\n", - " 0.4, 3, 0\n", - " ],\n", - "]\n", - "# [END data_model]\n", + " # Commodity, Unit, 1939 price (cents), Calories (kcal), Protein (g),\n", + " # Calcium (g), Iron (mg), Vitamin A (KIU), Vitamin B1 (mg), Vitamin B2 (mg),\n", + " # Niacin (mg), Vitamin C (mg)\n", + " data = [\n", + " [\n", + " 'Wheat Flour (Enriched)', '10 lb.', 36, 44.7, 1411, 2, 365, 0, 55.4,\n", + " 33.3, 441, 0\n", + " ],\n", + " ['Macaroni', '1 lb.', 14.1, 11.6, 418, 0.7, 54, 0, 3.2, 1.9, 68, 0],\n", + " [\n", + " 'Wheat Cereal (Enriched)', '28 oz.', 24.2, 11.8, 377, 14.4, 175, 0,\n", + " 14.4, 8.8, 114, 0\n", + " ],\n", + " ['Corn Flakes', '8 oz.', 7.1, 11.4, 252, 0.1, 56, 0, 13.5, 2.3, 68, 0],\n", + " [\n", + " 'Corn Meal', '1 lb.', 4.6, 36.0, 897, 1.7, 99, 30.9, 17.4, 7.9, 106,\n", + " 0\n", + " ],\n", + " [\n", + " 'Hominy Grits', '24 oz.', 8.5, 28.6, 680, 0.8, 80, 0, 10.6, 1.6,\n", + " 110, 0\n", + " ],\n", + " ['Rice', '1 lb.', 7.5, 21.2, 460, 0.6, 41, 0, 2, 4.8, 60, 0],\n", + " ['Rolled Oats', '1 lb.', 7.1, 25.3, 907, 5.1, 341, 0, 37.1, 8.9, 64, 0],\n", + " [\n", + " 'White Bread (Enriched)', '1 lb.', 7.9, 15.0, 488, 2.5, 115, 0,\n", + " 13.8, 8.5, 126, 0\n", + " ],\n", + " [\n", + " 'Whole Wheat Bread', '1 lb.', 9.1, 12.2, 484, 2.7, 125, 0, 13.9,\n", + " 6.4, 160, 0\n", + " ],\n", + " ['Rye Bread', '1 lb.', 9.1, 12.4, 439, 1.1, 82, 0, 9.9, 3, 66, 0],\n", + " ['Pound Cake', '1 lb.', 24.8, 8.0, 130, 0.4, 31, 18.9, 2.8, 3, 17, 0],\n", + " ['Soda Crackers', '1 lb.', 15.1, 12.5, 288, 0.5, 50, 0, 0, 0, 0, 0],\n", + " ['Milk', '1 qt.', 11, 6.1, 310, 10.5, 18, 16.8, 4, 16, 7, 177],\n", + " [\n", + " 'Evaporated Milk (can)', '14.5 oz.', 6.7, 8.4, 422, 15.1, 9, 26, 3,\n", + " 23.5, 11, 60\n", + " ],\n", + " ['Butter', '1 lb.', 30.8, 10.8, 9, 0.2, 3, 44.2, 0, 0.2, 2, 0],\n", + " ['Oleomargarine', '1 lb.', 16.1, 20.6, 17, 0.6, 6, 55.8, 0.2, 0, 0, 0],\n", + " ['Eggs', '1 doz.', 32.6, 2.9, 238, 1.0, 52, 18.6, 2.8, 6.5, 1, 0],\n", + " [\n", + " 'Cheese (Cheddar)', '1 lb.', 24.2, 7.4, 448, 16.4, 19, 28.1, 0.8,\n", + " 10.3, 4, 0\n", + " ],\n", + " ['Cream', '1/2 pt.', 14.1, 3.5, 49, 1.7, 3, 16.9, 0.6, 2.5, 0, 17],\n", + " [\n", + " 'Peanut Butter', '1 lb.', 17.9, 15.7, 661, 1.0, 48, 0, 9.6, 8.1,\n", + " 471, 0\n", + " ],\n", + " ['Mayonnaise', '1/2 pt.', 16.7, 8.6, 18, 0.2, 8, 2.7, 0.4, 0.5, 0, 0],\n", + " ['Crisco', '1 lb.', 20.3, 20.1, 0, 0, 0, 0, 0, 0, 0, 0],\n", + " ['Lard', '1 lb.', 9.8, 41.7, 0, 0, 0, 0.2, 0, 0.5, 5, 0],\n", + " [\n", + " 'Sirloin Steak', '1 lb.', 39.6, 2.9, 166, 0.1, 34, 0.2, 2.1, 2.9,\n", + " 69, 0\n", + " ],\n", + " ['Round Steak', '1 lb.', 36.4, 2.2, 214, 0.1, 32, 0.4, 2.5, 2.4, 87, 0],\n", + " ['Rib Roast', '1 lb.', 29.2, 3.4, 213, 0.1, 33, 0, 0, 2, 0, 0],\n", + " ['Chuck Roast', '1 lb.', 22.6, 3.6, 309, 0.2, 46, 0.4, 1, 4, 120, 0],\n", + " ['Plate', '1 lb.', 14.6, 8.5, 404, 0.2, 62, 0, 0.9, 0, 0, 0],\n", + " [\n", + " 'Liver (Beef)', '1 lb.', 26.8, 2.2, 333, 0.2, 139, 169.2, 6.4, 50.8,\n", + " 316, 525\n", + " ],\n", + " ['Leg of Lamb', '1 lb.', 27.6, 3.1, 245, 0.1, 20, 0, 2.8, 3.9, 86, 0],\n", + " [\n", + " 'Lamb Chops (Rib)', '1 lb.', 36.6, 3.3, 140, 0.1, 15, 0, 1.7, 2.7,\n", + " 54, 0\n", + " ],\n", + " ['Pork Chops', '1 lb.', 30.7, 3.5, 196, 0.2, 30, 0, 17.4, 2.7, 60, 0],\n", + " [\n", + " 'Pork Loin Roast', '1 lb.', 24.2, 4.4, 249, 0.3, 37, 0, 18.2, 3.6,\n", + " 79, 0\n", + " ],\n", + " ['Bacon', '1 lb.', 25.6, 10.4, 152, 0.2, 23, 0, 1.8, 1.8, 71, 0],\n", + " ['Ham, smoked', '1 lb.', 27.4, 6.7, 212, 0.2, 31, 0, 9.9, 3.3, 50, 0],\n", + " ['Salt Pork', '1 lb.', 16, 18.8, 164, 0.1, 26, 0, 1.4, 1.8, 0, 0],\n", + " [\n", + " 'Roasting Chicken', '1 lb.', 30.3, 1.8, 184, 0.1, 30, 0.1, 0.9, 1.8,\n", + " 68, 46\n", + " ],\n", + " ['Veal Cutlets', '1 lb.', 42.3, 1.7, 156, 0.1, 24, 0, 1.4, 2.4, 57, 0],\n", + " [\n", + " 'Salmon, Pink (can)', '16 oz.', 13, 5.8, 705, 6.8, 45, 3.5, 1, 4.9,\n", + " 209, 0\n", + " ],\n", + " ['Apples', '1 lb.', 4.4, 5.8, 27, 0.5, 36, 7.3, 3.6, 2.7, 5, 544],\n", + " ['Bananas', '1 lb.', 6.1, 4.9, 60, 0.4, 30, 17.4, 2.5, 3.5, 28, 498],\n", + " ['Lemons', '1 doz.', 26, 1.0, 21, 0.5, 14, 0, 0.5, 0, 4, 952],\n", + " ['Oranges', '1 doz.', 30.9, 2.2, 40, 1.1, 18, 11.1, 3.6, 1.3, 10, 1998],\n", + " ['Green Beans', '1 lb.', 7.1, 2.4, 138, 3.7, 80, 69, 4.3, 5.8, 37, 862],\n", + " ['Cabbage', '1 lb.', 3.7, 2.6, 125, 4.0, 36, 7.2, 9, 4.5, 26, 5369],\n", + " ['Carrots', '1 bunch', 4.7, 2.7, 73, 2.8, 43, 188.5, 6.1, 4.3, 89, 608],\n", + " ['Celery', '1 stalk', 7.3, 0.9, 51, 3.0, 23, 0.9, 1.4, 1.4, 9, 313],\n", + " ['Lettuce', '1 head', 8.2, 0.4, 27, 1.1, 22, 112.4, 1.8, 3.4, 11, 449],\n", + " ['Onions', '1 lb.', 3.6, 5.8, 166, 3.8, 59, 16.6, 4.7, 5.9, 21, 1184],\n", + " [\n", + " 'Potatoes', '15 lb.', 34, 14.3, 336, 1.8, 118, 6.7, 29.4, 7.1, 198,\n", + " 2522\n", + " ],\n", + " ['Spinach', '1 lb.', 8.1, 1.1, 106, 0, 138, 918.4, 5.7, 13.8, 33, 2755],\n", + " [\n", + " 'Sweet Potatoes', '1 lb.', 5.1, 9.6, 138, 2.7, 54, 290.7, 8.4, 5.4,\n", + " 83, 1912\n", + " ],\n", + " [\n", + " 'Peaches (can)', 'No. 2 1/2', 16.8, 3.7, 20, 0.4, 10, 21.5, 0.5, 1,\n", + " 31, 196\n", + " ],\n", + " [\n", + " 'Pears (can)', 'No. 2 1/2', 20.4, 3.0, 8, 0.3, 8, 0.8, 0.8, 0.8, 5,\n", + " 81\n", + " ],\n", + " [\n", + " 'Pineapple (can)', 'No. 2 1/2', 21.3, 2.4, 16, 0.4, 8, 2, 2.8, 0.8,\n", + " 7, 399\n", + " ],\n", + " [\n", + " 'Asparagus (can)', 'No. 2', 27.7, 0.4, 33, 0.3, 12, 16.3, 1.4, 2.1,\n", + " 17, 272\n", + " ],\n", + " [\n", + " 'Green Beans (can)', 'No. 2', 10, 1.0, 54, 2, 65, 53.9, 1.6, 4.3,\n", + " 32, 431\n", + " ],\n", + " [\n", + " 'Pork and Beans (can)', '16 oz.', 7.1, 7.5, 364, 4, 134, 3.5, 8.3,\n", + " 7.7, 56, 0\n", + " ],\n", + " ['Corn (can)', 'No. 2', 10.4, 5.2, 136, 0.2, 16, 12, 1.6, 2.7, 42, 218],\n", + " [\n", + " 'Peas (can)', 'No. 2', 13.8, 2.3, 136, 0.6, 45, 34.9, 4.9, 2.5, 37,\n", + " 370\n", + " ],\n", + " [\n", + " 'Tomatoes (can)', 'No. 2', 8.6, 1.3, 63, 0.7, 38, 53.2, 3.4, 2.5,\n", + " 36, 1253\n", + " ],\n", + " [\n", + " 'Tomato Soup (can)', '10 1/2 oz.', 7.6, 1.6, 71, 0.6, 43, 57.9, 3.5,\n", + " 2.4, 67, 862\n", + " ],\n", + " [\n", + " 'Peaches, Dried', '1 lb.', 15.7, 8.5, 87, 1.7, 173, 86.8, 1.2, 4.3,\n", + " 55, 57\n", + " ],\n", + " [\n", + " 'Prunes, Dried', '1 lb.', 9, 12.8, 99, 2.5, 154, 85.7, 3.9, 4.3, 65,\n", + " 257\n", + " ],\n", + " [\n", + " 'Raisins, Dried', '15 oz.', 9.4, 13.5, 104, 2.5, 136, 4.5, 6.3, 1.4,\n", + " 24, 136\n", + " ],\n", + " [\n", + " 'Peas, Dried', '1 lb.', 7.9, 20.0, 1367, 4.2, 345, 2.9, 28.7, 18.4,\n", + " 162, 0\n", + " ],\n", + " [\n", + " 'Lima Beans, Dried', '1 lb.', 8.9, 17.4, 1055, 3.7, 459, 5.1, 26.9,\n", + " 38.2, 93, 0\n", + " ],\n", + " [\n", + " 'Navy Beans, Dried', '1 lb.', 5.9, 26.9, 1691, 11.4, 792, 0, 38.4,\n", + " 24.6, 217, 0\n", + " ],\n", + " ['Coffee', '1 lb.', 22.4, 0, 0, 0, 0, 0, 4, 5.1, 50, 0],\n", + " ['Tea', '1/4 lb.', 17.4, 0, 0, 0, 0, 0, 0, 2.3, 42, 0],\n", + " ['Cocoa', '8 oz.', 8.6, 8.7, 237, 3, 72, 0, 2, 11.9, 40, 0],\n", + " ['Chocolate', '8 oz.', 16.2, 8.0, 77, 1.3, 39, 0, 0.9, 3.4, 14, 0],\n", + " ['Sugar', '10 lb.', 51.7, 34.9, 0, 0, 0, 0, 0, 0, 0, 0],\n", + " ['Corn Syrup', '24 oz.', 13.7, 14.7, 0, 0.5, 74, 0, 0, 0, 5, 0],\n", + " ['Molasses', '18 oz.', 13.6, 9.0, 0, 10.3, 244, 0, 1.9, 7.5, 146, 0],\n", + " [\n", + " 'Strawberry Preserves', '1 lb.', 20.5, 6.4, 11, 0.4, 7, 0.2, 0.2,\n", + " 0.4, 3, 0\n", + " ],\n", + " ]\n", "\n", - "# [START solver]\n", - "# Instantiate a Glop solver and naming it.\n", - "solver = pywraplp.Solver('StiglerDietExample',\n", - " pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)\n", - "# [END solver]\n", + " # Instantiate a Glop solver and naming it.\n", + " solver = pywraplp.Solver('StiglerDietExample',\n", + " pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)\n", "\n", - "# [START variables]\n", - "# Declare an array to hold our variables.\n", - "foods = [solver.NumVar(0.0, solver.infinity(), item[0]) for item in data]\n", + " # Declare an array to hold our variables.\n", + " foods = [solver.NumVar(0.0, solver.infinity(), item[0]) for item in data]\n", "\n", - "print('Number of variables =', solver.NumVariables())\n", - "# [END variables]\n", + " print('Number of variables =', solver.NumVariables())\n", "\n", - "# [START constraints]\n", - "# Create the constraints, one per nutrient.\n", - "constraints = []\n", - "for i, nutrient in enumerate(nutrients):\n", - " constraints.append(solver.Constraint(nutrient[1], solver.infinity()))\n", - " for j, item in enumerate(data):\n", - " constraints[i].SetCoefficient(foods[j], item[i + 3])\n", + " # Create the constraints, one per nutrient.\n", + " constraints = []\n", + " for i, nutrient in enumerate(nutrients):\n", + " constraints.append(solver.Constraint(nutrient[1], solver.infinity()))\n", + " for j, item in enumerate(data):\n", + " constraints[i].SetCoefficient(foods[j], item[i + 3])\n", "\n", - "print('Number of constraints =', solver.NumConstraints())\n", - "# [END constraints]\n", + " print('Number of constraints =', solver.NumConstraints())\n", "\n", - "# [START objective]\n", - "# Objective function: Minimize the sum of (price-normalized) foods.\n", - "objective = solver.Objective()\n", - "for food in foods:\n", - " objective.SetCoefficient(food, 1)\n", - "objective.SetMinimization()\n", - "# [END objective]\n", + " # Objective function: Minimize the sum of (price-normalized) foods.\n", + " objective = solver.Objective()\n", + " for food in foods:\n", + " objective.SetCoefficient(food, 1)\n", + " objective.SetMinimization()\n", "\n", - "# [START solve]\n", - "status = solver.Solve()\n", - "# [END solve]\n", + " status = solver.Solve()\n", "\n", - "# [START print_solution]\n", - "# Check that the problem has an optimal solution.\n", - "if status != solver.OPTIMAL:\n", - " print('The problem does not have an optimal solution!')\n", - " if status == solver.FEASIBLE:\n", - " print('A potentially suboptimal solution was found.')\n", - " else:\n", - " print('The solver could not solve the problem.')\n", - " exit(1)\n", + " # Check that the problem has an optimal solution.\n", + " if status != solver.OPTIMAL:\n", + " print('The problem does not have an optimal solution!')\n", + " if status == solver.FEASIBLE:\n", + " print('A potentially suboptimal solution was found.')\n", + " else:\n", + " print('The solver could not solve the problem.')\n", + " exit(1)\n", "\n", - "# Display the amounts (in dollars) to purchase of each food.\n", - "nutrients_result = [0] * len(nutrients)\n", - "print('\\nAnnual Foods:')\n", - "for i, food in enumerate(foods):\n", - " if food.solution_value() > 0.0:\n", - " print('{}: ${}'.format(data[i][0], 365. * food.solution_value()))\n", - " for j, _ in enumerate(nutrients):\n", - " nutrients_result[j] += data[i][j + 3] * food.solution_value()\n", - "print('\\nOptimal annual price: ${:.4f}'.format(365. * objective.Value()))\n", + " # Display the amounts (in dollars) to purchase of each food.\n", + " nutrients_result = [0] * len(nutrients)\n", + " print('\\nAnnual Foods:')\n", + " for i, food in enumerate(foods):\n", + " if food.solution_value() > 0.0:\n", + " print('{}: ${}'.format(data[i][0], 365. * food.solution_value()))\n", + " for j, _ in enumerate(nutrients):\n", + " nutrients_result[j] += data[i][j + 3] * food.solution_value()\n", + " print('\\nOptimal annual price: ${:.4f}'.format(365. * objective.Value()))\n", "\n", - "print('\\nNutrients per day:')\n", - "for i, nutrient in enumerate(nutrients):\n", - " print('{}: {:.2f} (min {})'.format(nutrient[0], nutrients_result[i],\n", - " nutrient[1]))\n", - "# [END print_solution]\n", + " print('\\nNutrients per day:')\n", + " for i, nutrient in enumerate(nutrients):\n", + " print('{}: {:.2f} (min {})'.format(nutrient[0], nutrients_result[i],\n", + " nutrient[1]))\n", "\n", - "# [START advanced]\n", - "print('\\nAdvanced usage:')\n", - "print('Problem solved in ', solver.wall_time(), ' milliseconds')\n", - "print('Problem solved in ', solver.iterations(), ' iterations')\n", - "# [END advanced]\n", + " print('\\nAdvanced usage:')\n", + " print('Problem solved in ', solver.wall_time(), ' milliseconds')\n", + " print('Problem solved in ', solver.iterations(), ' iterations')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/model_builder/assignment_mb.ipynb b/examples/notebook/model_builder/assignment_mb.ipynb index 5e22b00f20..0d18a8efdb 100644 --- a/examples/notebook/model_builder/assignment_mb.ipynb +++ b/examples/notebook/model_builder/assignment_mb.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "MIP example that solves an assignment problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,94 +82,68 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"MIP example that solves an assignment problem.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.model_builder.python import model_builder\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data_model]\n", - "costs = [\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", - "# [END data_model]\n", + "def main():\n", + " # Data\n", + " costs = [\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", - "# Solver\n", - "# Create the model.\n", - "model = model_builder.ModelBuilder()\n", - "# [END model]\n", + " # Solver\n", + " # Create the model.\n", + " model = model_builder.ModelBuilder()\n", "\n", - "# Variables\n", - "# [START 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", - "# [END variables]\n", - "\n", - "# Constraints\n", - "# [START 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", - "\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", - "# [END constraints]\n", - "\n", - "# Objective\n", - "# [START 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", - "# [END objective]\n", - "\n", - "# [START solve]\n", - "# Create the solver with the CP-SAT backend, and solve the model.\n", - "solver = model_builder.ModelSolver('sat')\n", - "status = solver.solve(model)\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if (status == model_builder.SolveStatus.OPTIMAL or\n", - " status == model_builder.SolveStatus.FEASIBLE):\n", - " print(f'Total cost = {solver.objective_value}\\n')\n", + " # 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", - " # Test if x[i,j] is 1 (with tolerance for floating point arithmetic).\n", - " if solver.value(x[i, j]) > 0.5:\n", - " print(f'Worker {i} assigned to task {j}.' +\n", - " f' Cost: {costs[i][j]}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " x[i, j] = model.new_bool_var(f'x_{i}_{j}')\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", + "\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", + "\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", + "\n", + " # Create the solver with the CP-SAT backend, and solve the model.\n", + " solver = model_builder.ModelSolver('sat')\n", + " status = solver.solve(model)\n", + "\n", + " # Print solution.\n", + " if (status == model_builder.SolveStatus.OPTIMAL or\n", + " status == model_builder.SolveStatus.FEASIBLE):\n", + " print(f'Total cost = {solver.objective_value}\\n')\n", + " for i in range(num_workers):\n", + " for j in range(num_tasks):\n", + " # Test if x[i,j] is 1 (with tolerance for floating point arithmetic).\n", + " if solver.value(x[i, j]) > 0.5:\n", + " print(f'Worker {i} assigned to task {j}.' +\n", + " f' Cost: {costs[i][j]}')\n", + " else:\n", + " print('No solution found.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/model_builder/bin_packing_mb.ipynb b/examples/notebook/model_builder/bin_packing_mb.ipynb index 98fc54a11b..898d237941 100644 --- a/examples/notebook/model_builder/bin_packing_mb.ipynb +++ b/examples/notebook/model_builder/bin_packing_mb.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve a simple bin packing problem using a MIP solver." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,28 +82,9 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solve a simple bin packing problem using a MIP solver.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.model_builder.python import model_builder\n", - "# [END import]\n", "\n", "\n", - "# [START program_part1]\n", - "# [START data_model]\n", "def create_data_model():\n", " \"\"\"Create the data for the example.\"\"\"\n", " data = {}\n", @@ -106,81 +95,68 @@ " data['bin_capacity'] = 100\n", " return data\n", "\n", - "# [END data_model]\n", "\n", "\n", - "# [START data]\n", - "data = create_data_model()\n", - "# [END data]\n", - "# [END program_part1]\n", + "def main():\n", + " data = create_data_model()\n", "\n", - "# [START solver]\n", - "# Create the model.\n", - "model = model_builder.ModelBuilder()\n", - "# [END solver]\n", + " # Create the model.\n", + " model = model_builder.ModelBuilder()\n", "\n", - "# [START program_part2]\n", - "# [START variables]\n", - "# Variables\n", - "# x[i, j] = 1 if item i is packed in bin j.\n", - "x = {}\n", - "for i in data['items']:\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", + "\n", + " # y[j] = 1 if bin j is used.\n", + " y = {}\n", " for j in data['bins']:\n", - " x[(i, j)] = model.new_bool_var(f'x_{i}_{j}')\n", + " y[j] = model.new_bool_var(f'y_{j}')\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", - "# [END variables]\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", "\n", - "# [START constraints]\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", - "\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", - "# [END constraints]\n", - "\n", - "# [START objective]\n", - "# Objective: minimize the number of bins used.\n", - "model.minimize(model_builder.LinearExpr.sum([y[j] for j in data['bins']]))\n", - "# [END objective]\n", - "\n", - "# [START solve]\n", - "# Create the solver with the CP-SAT backend, and solve the model.\n", - "solver = model_builder.ModelSolver('sat')\n", - "status = solver.solve(model)\n", - "# [END solve]\n", - "\n", - "# [START print_solution]\n", - "if status == model_builder.SolveStatus.OPTIMAL:\n", - " num_bins = 0.\n", + " # The amount packed in each bin cannot exceed its capacity.\n", " for j in data['bins']:\n", - " if solver.value(y[j]) == 1:\n", - " bin_items = []\n", - " bin_weight = 0\n", - " for i in data['items']:\n", - " if solver.value(x[i, j]) > 0:\n", - " bin_items.append(i)\n", - " bin_weight += data['weights'][i]\n", - " if bin_weight > 0:\n", - " num_bins += 1\n", - " print('Bin number', j)\n", - " print(' Items packed:', bin_items)\n", - " print(' Total weight:', bin_weight)\n", - " print()\n", - " print()\n", - " print('Number of bins used:', num_bins)\n", - " print('Time = ', solver.wall_time, ' seconds')\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + " model.add(\n", + " sum(x[(i, j)] * data['weights'][i] for i in data['items']) <= y[j] *\n", + " data['bin_capacity'])\n", + "\n", + " # Objective: minimize the number of bins used.\n", + " model.minimize(model_builder.LinearExpr.sum([y[j] for j in data['bins']]))\n", + "\n", + " # Create the solver with the CP-SAT backend, and solve the model.\n", + " solver = model_builder.ModelSolver('sat')\n", + " status = solver.solve(model)\n", + "\n", + " if status == model_builder.SolveStatus.OPTIMAL:\n", + " num_bins = 0.\n", + " for j in data['bins']:\n", + " if solver.value(y[j]) == 1:\n", + " bin_items = []\n", + " bin_weight = 0\n", + " for i in data['items']:\n", + " if solver.value(x[i, j]) > 0:\n", + " bin_items.append(i)\n", + " bin_weight += data['weights'][i]\n", + " if bin_weight > 0:\n", + " num_bins += 1\n", + " print('Bin number', j)\n", + " print(' Items packed:', bin_items)\n", + " print(' Total weight:', bin_weight)\n", + " print()\n", + " print()\n", + " print('Number of bins used:', num_bins)\n", + " print('Time = ', solver.wall_time, ' seconds')\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/model_builder/simple_lp_program_mb.ipynb b/examples/notebook/model_builder/simple_lp_program_mb.ipynb index 239243407f..604cf4ad4c 100644 --- a/examples/notebook/model_builder/simple_lp_program_mb.ipynb +++ b/examples/notebook/model_builder/simple_lp_program_mb.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Minimal example to call the GLOP solver using model_builder." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,79 +82,52 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Minimal example to call the GLOP solver using model_builder.\"\"\"\n", - "# [START import]\n", "import math\n", "\n", "from ortools.model_builder.python import model_builder\n", - "# [END import]\n", "\n", "\n", - "# [START model]\n", - "# Create the model.\n", - "model = model_builder.ModelBuilder()\n", - "# [END model]\n", + "def main():\n", + " # Create the model.\n", + " model = model_builder.ModelBuilder()\n", "\n", - "# [START variables]\n", - "# Create the variables x and y.\n", - "x = model.new_num_var(0.0, math.inf, 'x')\n", - "y = model.new_num_var(0.0, math.inf, 'y')\n", + " # Create the variables x and y.\n", + " x = model.new_num_var(0.0, math.inf, 'x')\n", + " y = model.new_num_var(0.0, math.inf, 'y')\n", "\n", - "print('Number of variables =', model.num_variables)\n", - "# [END variables]\n", + " print('Number of variables =', model.num_variables)\n", "\n", - "# [START constraints]\n", - "# x + 7 * y <= 17.5.\n", - "ct = model.add(x + 7 * y <= 17.5)\n", + " # x + 7 * y <= 17.5.\n", + " ct = model.add(x + 7 * y <= 17.5)\n", "\n", - "# x <= 3.5.\n", - "model.add(x <= 3.5)\n", + " # x <= 3.5.\n", + " model.add(x <= 3.5)\n", "\n", - "print('Number of constraints =', model.num_constraints)\n", - "# [END constraints]\n", + " print('Number of constraints =', model.num_constraints)\n", "\n", - "# [START objective]\n", - "# Maximize x + 10 * y.\n", - "model.maximize(x + 10 * y)\n", - "# [END objective]\n", + " # Maximize x + 10 * y.\n", + " model.maximize(x + 10 * y)\n", "\n", - "# [START solve]\n", - "# Create the solver with the GLOP backend, and solve the model.\n", - "solver = model_builder.ModelSolver('glop')\n", - "status = solver.solve(model)\n", - "# [END solve]\n", + " # Create the solver with the GLOP backend, and solve the model.\n", + " solver = model_builder.ModelSolver('glop')\n", + " status = solver.solve(model)\n", "\n", - "# [START print_solution]\n", - "if status == model_builder.SolveStatus.OPTIMAL:\n", - " print('Solution:')\n", - " print('Objective value =', solver.objective_value)\n", - " print('x =', solver.value(x))\n", - " print('y =', solver.value(y))\n", + " if status == model_builder.SolveStatus.OPTIMAL:\n", + " print('Solution:')\n", + " print('Objective value =', solver.objective_value)\n", + " print('x =', solver.value(x))\n", + " print('y =', solver.value(y))\n", "\n", - " print('dual_value(ct) =', solver.dual_value(ct))\n", - " print('reduced_cost(x) =', solver.reduced_cost(x))\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + " print('dual_value(ct) =', solver.dual_value(ct))\n", + " print('reduced_cost(x) =', solver.reduced_cost(x))\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", "\n", - "# [START advanced]\n", - "print('\\nAdvanced usage:')\n", - "print('Problem solved in %f seconds' % solver.wall_time)\n", - "# [END advanced]\n", + " print('\\nAdvanced usage:')\n", + " print('Problem solved in %f seconds' % solver.wall_time)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/model_builder/simple_mip_program_mb.ipynb b/examples/notebook/model_builder/simple_mip_program_mb.ipynb index dea1085d39..f0239a0ab8 100644 --- a/examples/notebook/model_builder/simple_mip_program_mb.ipynb +++ b/examples/notebook/model_builder/simple_mip_program_mb.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Integer programming examples that show how to use the APIs." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,76 +82,49 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Integer programming examples that show how to use the APIs.\"\"\"\n", - "# [START import]\n", "import math\n", "\n", "from ortools.model_builder.python import model_builder\n", - "# [END import]\n", "\n", "\n", - "# [START model]\n", - "# Create the model.\n", - "model = model_builder.ModelBuilder()\n", - "# [END model]\n", + "def main():\n", + " # Create the model.\n", + " model = model_builder.ModelBuilder()\n", "\n", - "# [START variables]\n", - "# x and y are integer non-negative variables.\n", - "x = model.new_int_var(0.0, math.inf, 'x')\n", - "y = model.new_int_var(0.0, math.inf, 'y')\n", + " # x and y are integer non-negative variables.\n", + " x = model.new_int_var(0.0, math.inf, 'x')\n", + " y = model.new_int_var(0.0, math.inf, 'y')\n", "\n", - "print('Number of variables =', model.num_variables)\n", - "# [END variables]\n", + " print('Number of variables =', model.num_variables)\n", "\n", - "# [START constraints]\n", - "# x + 7 * y <= 17.5.\n", - "model.add(x + 7 * y <= 17.5)\n", + " # x + 7 * y <= 17.5.\n", + " model.add(x + 7 * y <= 17.5)\n", "\n", - "# x <= 3.5.\n", - "model.add(x <= 3.5)\n", + " # x <= 3.5.\n", + " model.add(x <= 3.5)\n", "\n", - "print('Number of constraints =', model.num_constraints)\n", - "# [END constraints]\n", + " print('Number of constraints =', model.num_constraints)\n", "\n", - "# [START objective]\n", - "# Maximize x + 10 * y.\n", - "model.maximize(x + 10 * y)\n", - "# [END objective]\n", + " # Maximize x + 10 * y.\n", + " model.maximize(x + 10 * y)\n", "\n", - "# [START solve]\n", - "# Create the solver with the SCIP backend, and solve the model.\n", - "solver = model_builder.ModelSolver('scip')\n", - "status = solver.solve(model)\n", - "# [END solve]\n", + " # Create the solver with the SCIP backend, and solve the model.\n", + " solver = model_builder.ModelSolver('scip')\n", + " status = solver.solve(model)\n", "\n", - "# [START print_solution]\n", - "if status == model_builder.SolveStatus.OPTIMAL:\n", - " print('Solution:')\n", - " print('Objective value =', solver.objective_value)\n", - " print('x =', solver.value(x))\n", - " print('y =', solver.value(y))\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + " if status == model_builder.SolveStatus.OPTIMAL:\n", + " print('Solution:')\n", + " print('Objective value =', solver.objective_value)\n", + " print('x =', solver.value(x))\n", + " print('y =', solver.value(y))\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", "\n", - "# [START advanced]\n", - "print('\\nAdvanced usage:')\n", - "print('Problem solved in %f seconds' % solver.wall_time)\n", - "# [END advanced]\n", + " print('\\nAdvanced usage:')\n", + " print('Problem solved in %f seconds' % solver.wall_time)\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/assignment_groups_sat.ipynb b/examples/notebook/sat/assignment_groups_sat.ipynb index a8e94afcb6..f48706ce9e 100644 --- a/examples/notebook/sat/assignment_groups_sat.ipynb +++ b/examples/notebook/sat/assignment_groups_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve assignment problem for given group of workers." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,141 +82,110 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Solve assignment problem for given group of workers.\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data]\n", - "costs = [\n", - " [90, 76, 75, 70, 50, 74],\n", - " [35, 85, 55, 65, 48, 101],\n", - " [125, 95, 90, 105, 59, 120],\n", - " [45, 110, 95, 115, 104, 83],\n", - " [60, 105, 80, 75, 59, 62],\n", - " [45, 65, 110, 95, 47, 31],\n", - " [38, 51, 107, 41, 69, 99],\n", - " [47, 85, 57, 71, 92, 77],\n", - " [39, 63, 97, 49, 118, 56],\n", - " [47, 101, 71, 60, 88, 109],\n", - " [17, 39, 103, 64, 61, 92],\n", - " [101, 45, 83, 59, 92, 27],\n", - "]\n", - "num_workers = len(costs)\n", - "num_tasks = len(costs[0])\n", - "# [END data]\n", + "def main():\n", + " # Data\n", + " costs = [\n", + " [90, 76, 75, 70, 50, 74],\n", + " [35, 85, 55, 65, 48, 101],\n", + " [125, 95, 90, 105, 59, 120],\n", + " [45, 110, 95, 115, 104, 83],\n", + " [60, 105, 80, 75, 59, 62],\n", + " [45, 65, 110, 95, 47, 31],\n", + " [38, 51, 107, 41, 69, 99],\n", + " [47, 85, 57, 71, 92, 77],\n", + " [39, 63, 97, 49, 118, 56],\n", + " [47, 101, 71, 60, 88, 109],\n", + " [17, 39, 103, 64, 61, 92],\n", + " [101, 45, 83, 59, 92, 27],\n", + " ]\n", + " num_workers = len(costs)\n", + " num_tasks = len(costs[0])\n", "\n", - "# Allowed groups of workers:\n", - "# [START allowed_groups]\n", - "group1 = [\n", - " [0, 0, 1, 1], # Workers 2, 3\n", - " [0, 1, 0, 1], # Workers 1, 3\n", - " [0, 1, 1, 0], # Workers 1, 2\n", - " [1, 1, 0, 0], # Workers 0, 1\n", - " [1, 0, 1, 0], # Workers 0, 2\n", - "]\n", + " # Allowed groups of workers:\n", + " group1 = [\n", + " [0, 0, 1, 1], # Workers 2, 3\n", + " [0, 1, 0, 1], # Workers 1, 3\n", + " [0, 1, 1, 0], # Workers 1, 2\n", + " [1, 1, 0, 0], # Workers 0, 1\n", + " [1, 0, 1, 0], # Workers 0, 2\n", + " ]\n", "\n", - "group2 = [\n", - " [0, 0, 1, 1], # Workers 6, 7\n", - " [0, 1, 0, 1], # Workers 5, 7\n", - " [0, 1, 1, 0], # Workers 5, 6\n", - " [1, 1, 0, 0], # Workers 4, 5\n", - " [1, 0, 0, 1], # Workers 4, 7\n", - "]\n", + " group2 = [\n", + " [0, 0, 1, 1], # Workers 6, 7\n", + " [0, 1, 0, 1], # Workers 5, 7\n", + " [0, 1, 1, 0], # Workers 5, 6\n", + " [1, 1, 0, 0], # Workers 4, 5\n", + " [1, 0, 0, 1], # Workers 4, 7\n", + " ]\n", "\n", - "group3 = [\n", - " [0, 0, 1, 1], # Workers 10, 11\n", - " [0, 1, 0, 1], # Workers 9, 11\n", - " [0, 1, 1, 0], # Workers 9, 10\n", - " [1, 0, 1, 0], # Workers 8, 10\n", - " [1, 0, 0, 1], # Workers 8, 11\n", - "]\n", - "# [END allowed_groups]\n", + " group3 = [\n", + " [0, 0, 1, 1], # Workers 10, 11\n", + " [0, 1, 0, 1], # Workers 9, 11\n", + " [0, 1, 1, 0], # Workers 9, 10\n", + " [1, 0, 1, 0], # Workers 8, 10\n", + " [1, 0, 0, 1], # Workers 8, 11\n", + " ]\n", "\n", - "# Model\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + " # Model\n", + " model = cp_model.CpModel()\n", "\n", - "# Variables\n", - "# [START variables]\n", - "x = {}\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')\n", - "# [END variables]\n", - "\n", - "# Constraints\n", - "# [START constraints]\n", - "# Each worker is assigned to at most one task.\n", - "for worker in range(num_workers):\n", - " model.AddAtMostOne(x[worker, task] for task in range(num_tasks))\n", - "\n", - "# Each task is assigned to exactly one worker.\n", - "for task in range(num_tasks):\n", - " model.AddExactlyOne(x[worker, task] for worker in range(num_workers))\n", - "# [END constraints]\n", - "\n", - "# [START assignments]\n", - "# Create variables for each worker, indicating whether they work on some task.\n", - "work = {}\n", - "for worker in range(num_workers):\n", - " work[worker] = model.NewBoolVar(f'work[{worker}]')\n", - "\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " model.Add(work[worker] == sum(\n", - " x[worker, task] for task in range(num_tasks)))\n", - "\n", - "# Define the allowed groups of worders\n", - "model.AddAllowedAssignments([work[0], work[1], work[2], work[3]], group1)\n", - "model.AddAllowedAssignments([work[4], work[5], work[6], work[7]], group2)\n", - "model.AddAllowedAssignments([work[8], work[9], work[10], work[11]], group3)\n", - "# [END assignments]\n", - "\n", - "# Objective\n", - "# [START objective]\n", - "objective_terms = []\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " objective_terms.append(costs[worker][task] * x[worker, task])\n", - "model.Minimize(sum(objective_terms))\n", - "# [END objective]\n", - "\n", - "# Solve\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", - " print(f'Total cost = {solver.ObjectiveValue()}\\n')\n", + " # Variables\n", + " x = {}\n", " for worker in range(num_workers):\n", " for task in range(num_tasks):\n", - " if solver.BooleanValue(x[worker, task]):\n", - " print(f'Worker {worker} assigned to task {task}.' +\n", - " f' Cost = {costs[worker][task]}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')\n", + "\n", + " # Constraints\n", + " # Each worker is assigned to at most one task.\n", + " for worker in range(num_workers):\n", + " model.AddAtMostOne(x[worker, task] for task in range(num_tasks))\n", + "\n", + " # Each task is assigned to exactly one worker.\n", + " for task in range(num_tasks):\n", + " model.AddExactlyOne(x[worker, task] for worker in range(num_workers))\n", + "\n", + " # Create variables for each worker, indicating whether they work on some task.\n", + " work = {}\n", + " for worker in range(num_workers):\n", + " work[worker] = model.NewBoolVar(f'work[{worker}]')\n", + "\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " model.Add(work[worker] == sum(\n", + " x[worker, task] for task in range(num_tasks)))\n", + "\n", + " # Define the allowed groups of worders\n", + " model.AddAllowedAssignments([work[0], work[1], work[2], work[3]], group1)\n", + " model.AddAllowedAssignments([work[4], work[5], work[6], work[7]], group2)\n", + " model.AddAllowedAssignments([work[8], work[9], work[10], work[11]], group3)\n", + "\n", + " # Objective\n", + " objective_terms = []\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " objective_terms.append(costs[worker][task] * x[worker, task])\n", + " model.Minimize(sum(objective_terms))\n", + "\n", + " # Solve\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", + "\n", + " # Print solution.\n", + " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", + " print(f'Total cost = {solver.ObjectiveValue()}\\n')\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " if solver.BooleanValue(x[worker, task]):\n", + " print(f'Worker {worker} assigned to task {task}.' +\n", + " f' Cost = {costs[worker][task]}')\n", + " else:\n", + " print('No solution found.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/assignment_sat.ipynb b/examples/notebook/sat/assignment_sat.ipynb index 449a324dfc..dad8890502 100644 --- a/examples/notebook/sat/assignment_sat.ipynb +++ b/examples/notebook/sat/assignment_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve a simple assignment problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,93 +82,66 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solve a simple assignment problem.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data_model]\n", - "costs = [\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", - "# [END data_model]\n", + "def main():\n", + " # Data\n", + " costs = [\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", - "# Model\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + " # Model\n", + " model = cp_model.CpModel()\n", "\n", - "# Variables\n", - "# [START variables]\n", - "x = []\n", - "for i in range(num_workers):\n", - " t = []\n", + " # Variables\n", + " x = []\n", + " for i in range(num_workers):\n", + " t = []\n", + " for j in range(num_tasks):\n", + " t.append(model.NewBoolVar(f'x[{i},{j}]'))\n", + " x.append(t)\n", + "\n", + " # Constraints\n", + " # Each worker is assigned to at most one task.\n", + " for i in range(num_workers):\n", + " model.AddAtMostOne(x[i][j] for j in range(num_tasks))\n", + "\n", + " # Each task is assigned to exactly one worker.\n", " for j in range(num_tasks):\n", - " t.append(model.NewBoolVar(f'x[{i},{j}]'))\n", - " x.append(t)\n", - "# [END variables]\n", + " model.AddExactlyOne(x[i][j] for i in range(num_workers))\n", "\n", - "# Constraints\n", - "# [START constraints]\n", - "# Each worker is assigned to at most one task.\n", - "for i in range(num_workers):\n", - " model.AddAtMostOne(x[i][j] for j in range(num_tasks))\n", - "\n", - "# Each task is assigned to exactly one worker.\n", - "for j in range(num_tasks):\n", - " model.AddExactlyOne(x[i][j] for i in range(num_workers))\n", - "# [END constraints]\n", - "\n", - "# Objective\n", - "# [START objective]\n", - "objective_terms = []\n", - "for i in range(num_workers):\n", - " for j in range(num_tasks):\n", - " objective_terms.append(costs[i][j] * x[i][j])\n", - "model.Minimize(sum(objective_terms))\n", - "# [END objective]\n", - "\n", - "# Solve\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", - " print(f'Total cost = {solver.ObjectiveValue()}')\n", - " print()\n", + " # Objective\n", + " objective_terms = []\n", " for i in range(num_workers):\n", " for j in range(num_tasks):\n", - " if solver.BooleanValue(x[i][j]):\n", - " print(\n", - " f'Worker {i} assigned to task {j} Cost = {costs[i][j]}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " objective_terms.append(costs[i][j] * x[i][j])\n", + " model.Minimize(sum(objective_terms))\n", + "\n", + " # Solve\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", + "\n", + " # Print solution.\n", + " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", + " print(f'Total cost = {solver.ObjectiveValue()}')\n", + " print()\n", + " for i in range(num_workers):\n", + " for j in range(num_tasks):\n", + " if solver.BooleanValue(x[i][j]):\n", + " print(\n", + " f'Worker {i} assigned to task {j} Cost = {costs[i][j]}')\n", + " else:\n", + " print('No solution found.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/assignment_task_sizes_sat.ipynb b/examples/notebook/sat/assignment_task_sizes_sat.ipynb index 0ad0f993c5..c4333e7aca 100644 --- a/examples/notebook/sat/assignment_task_sizes_sat.ipynb +++ b/examples/notebook/sat/assignment_task_sizes_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve a simple assignment problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,101 +82,74 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Solve a simple assignment problem.\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data]\n", - "costs = [\n", - " [90, 76, 75, 70, 50, 74, 12, 68],\n", - " [35, 85, 55, 65, 48, 101, 70, 83],\n", - " [125, 95, 90, 105, 59, 120, 36, 73],\n", - " [45, 110, 95, 115, 104, 83, 37, 71],\n", - " [60, 105, 80, 75, 59, 62, 93, 88],\n", - " [45, 65, 110, 95, 47, 31, 81, 34],\n", - " [38, 51, 107, 41, 69, 99, 115, 48],\n", - " [47, 85, 57, 71, 92, 77, 109, 36],\n", - " [39, 63, 97, 49, 118, 56, 92, 61],\n", - " [47, 101, 71, 60, 88, 109, 52, 90],\n", - "]\n", - "num_workers = len(costs)\n", - "num_tasks = len(costs[0])\n", + "def main():\n", + " # Data\n", + " costs = [\n", + " [90, 76, 75, 70, 50, 74, 12, 68],\n", + " [35, 85, 55, 65, 48, 101, 70, 83],\n", + " [125, 95, 90, 105, 59, 120, 36, 73],\n", + " [45, 110, 95, 115, 104, 83, 37, 71],\n", + " [60, 105, 80, 75, 59, 62, 93, 88],\n", + " [45, 65, 110, 95, 47, 31, 81, 34],\n", + " [38, 51, 107, 41, 69, 99, 115, 48],\n", + " [47, 85, 57, 71, 92, 77, 109, 36],\n", + " [39, 63, 97, 49, 118, 56, 92, 61],\n", + " [47, 101, 71, 60, 88, 109, 52, 90],\n", + " ]\n", + " num_workers = len(costs)\n", + " num_tasks = len(costs[0])\n", "\n", - "task_sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n", - "# Maximum total of task sizes for any worker\n", - "total_size_max = 15\n", - "# [END data]\n", + " task_sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n", + " # Maximum total of task sizes for any worker\n", + " total_size_max = 15\n", "\n", - "# Model\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + " # Model\n", + " model = cp_model.CpModel()\n", "\n", - "# Variables\n", - "# [START variables]\n", - "x = {}\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')\n", - "# [END variables]\n", - "\n", - "# Constraints\n", - "# [START constraints]\n", - "# Each worker is assigned to at most one task.\n", - "for worker in range(num_workers):\n", - " model.Add(\n", - " sum(task_sizes[task] * x[worker, task]\n", - " for task in range(num_tasks)) <= total_size_max)\n", - "\n", - "# Each task is assigned to exactly one worker.\n", - "for task in range(num_tasks):\n", - " model.AddExactlyOne(x[worker, task] for worker in range(num_workers))\n", - "# [END constraints]\n", - "\n", - "# Objective\n", - "# [START objective]\n", - "objective_terms = []\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " objective_terms.append(costs[worker][task] * x[worker, task])\n", - "model.Minimize(sum(objective_terms))\n", - "# [END objective]\n", - "\n", - "# Solve\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", - " print(f'Total cost = {solver.ObjectiveValue()}\\n')\n", + " # Variables\n", + " x = {}\n", " for worker in range(num_workers):\n", " for task in range(num_tasks):\n", - " if solver.BooleanValue(x[worker, task]):\n", - " print(f'Worker {worker} assigned to task {task}.' +\n", - " f' Cost = {costs[worker][task]}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')\n", + "\n", + " # Constraints\n", + " # Each worker is assigned to at most one task.\n", + " for worker in range(num_workers):\n", + " model.Add(\n", + " sum(task_sizes[task] * x[worker, task]\n", + " for task in range(num_tasks)) <= total_size_max)\n", + "\n", + " # Each task is assigned to exactly one worker.\n", + " for task in range(num_tasks):\n", + " model.AddExactlyOne(x[worker, task] for worker in range(num_workers))\n", + "\n", + " # Objective\n", + " objective_terms = []\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " objective_terms.append(costs[worker][task] * x[worker, task])\n", + " model.Minimize(sum(objective_terms))\n", + "\n", + " # Solve\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", + "\n", + " # Print solution.\n", + " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", + " print(f'Total cost = {solver.ObjectiveValue()}\\n')\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " if solver.BooleanValue(x[worker, task]):\n", + " print(f'Worker {worker} assigned to task {task}.' +\n", + " f' Cost = {costs[worker][task]}')\n", + " else:\n", + " print('No solution found.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/assignment_teams_sat.ipynb b/examples/notebook/sat/assignment_teams_sat.ipynb index 84c815a478..643384006c 100644 --- a/examples/notebook/sat/assignment_teams_sat.ipynb +++ b/examples/notebook/sat/assignment_teams_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solve a simple assignment problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,109 +82,82 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Solve a simple assignment problem.\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# Data\n", - "# [START data]\n", - "costs = [\n", - " [90, 76, 75, 70],\n", - " [35, 85, 55, 65],\n", - " [125, 95, 90, 105],\n", - " [45, 110, 95, 115],\n", - " [60, 105, 80, 75],\n", - " [45, 65, 110, 95],\n", - "]\n", - "num_workers = len(costs)\n", - "num_tasks = len(costs[0])\n", + "def main():\n", + " # Data\n", + " costs = [\n", + " [90, 76, 75, 70],\n", + " [35, 85, 55, 65],\n", + " [125, 95, 90, 105],\n", + " [45, 110, 95, 115],\n", + " [60, 105, 80, 75],\n", + " [45, 65, 110, 95],\n", + " ]\n", + " num_workers = len(costs)\n", + " num_tasks = len(costs[0])\n", "\n", - "team1 = [0, 2, 4]\n", - "team2 = [1, 3, 5]\n", - "# Maximum total of tasks for any team\n", - "team_max = 2\n", - "# [END data]\n", + " team1 = [0, 2, 4]\n", + " team2 = [1, 3, 5]\n", + " # Maximum total of tasks for any team\n", + " team_max = 2\n", "\n", - "# Model\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + " # Model\n", + " model = cp_model.CpModel()\n", "\n", - "# Variables\n", - "# [START variables]\n", - "x = {}\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')\n", - "# [END variables]\n", - "\n", - "# Constraints\n", - "# [START constraints]\n", - "# Each worker is assigned to at most one task.\n", - "for worker in range(num_workers):\n", - " model.AddAtMostOne(x[worker, task] for task in range(num_tasks))\n", - "\n", - "# Each task is assigned to exactly one worker.\n", - "for task in range(num_tasks):\n", - " model.AddExactlyOne(x[worker, task] for worker in range(num_workers))\n", - "\n", - "# Each team takes at most two tasks.\n", - "team1_tasks = []\n", - "for worker in team1:\n", - " for task in range(num_tasks):\n", - " team1_tasks.append(x[worker, task])\n", - "model.Add(sum(team1_tasks) <= team_max)\n", - "\n", - "team2_tasks = []\n", - "for worker in team2:\n", - " for task in range(num_tasks):\n", - " team2_tasks.append(x[worker, task])\n", - "model.Add(sum(team2_tasks) <= team_max)\n", - "# [END constraints]\n", - "\n", - "# Objective\n", - "# [START objective]\n", - "objective_terms = []\n", - "for worker in range(num_workers):\n", - " for task in range(num_tasks):\n", - " objective_terms.append(costs[worker][task] * x[worker, task])\n", - "model.Minimize(sum(objective_terms))\n", - "# [END objective]\n", - "\n", - "# Solve\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", - "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", - " print(f'Total cost = {solver.ObjectiveValue()}\\n')\n", + " # Variables\n", + " x = {}\n", " for worker in range(num_workers):\n", " for task in range(num_tasks):\n", - " if solver.BooleanValue(x[worker, task]):\n", - " print(f'Worker {worker} assigned to task {task}.' +\n", - " f' Cost = {costs[worker][task]}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " x[worker, task] = model.NewBoolVar(f'x[{worker},{task}]')\n", + "\n", + " # Constraints\n", + " # Each worker is assigned to at most one task.\n", + " for worker in range(num_workers):\n", + " model.AddAtMostOne(x[worker, task] for task in range(num_tasks))\n", + "\n", + " # Each task is assigned to exactly one worker.\n", + " for task in range(num_tasks):\n", + " model.AddExactlyOne(x[worker, task] for worker in range(num_workers))\n", + "\n", + " # Each team takes at most two tasks.\n", + " team1_tasks = []\n", + " for worker in team1:\n", + " for task in range(num_tasks):\n", + " team1_tasks.append(x[worker, task])\n", + " model.Add(sum(team1_tasks) <= team_max)\n", + "\n", + " team2_tasks = []\n", + " for worker in team2:\n", + " for task in range(num_tasks):\n", + " team2_tasks.append(x[worker, task])\n", + " model.Add(sum(team2_tasks) <= team_max)\n", + "\n", + " # Objective\n", + " objective_terms = []\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " objective_terms.append(costs[worker][task] * x[worker, task])\n", + " model.Minimize(sum(objective_terms))\n", + "\n", + " # Solve\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", + "\n", + " # Print solution.\n", + " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", + " print(f'Total cost = {solver.ObjectiveValue()}\\n')\n", + " for worker in range(num_workers):\n", + " for task in range(num_tasks):\n", + " if solver.BooleanValue(x[worker, task]):\n", + " print(f'Worker {worker} assigned to task {task}.' +\n", + " f' Cost = {costs[worker][task]}')\n", + " else:\n", + " print('No solution found.')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/assumptions_sample_sat.ipynb b/examples/notebook/sat/assumptions_sample_sat.ipynb index 8e548731ba..8e71eab109 100644 --- a/examples/notebook/sat/assumptions_sample_sat.ipynb +++ b/examples/notebook/sat/assumptions_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample that solves a model and gets the infeasibility assumptions." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,65 +82,42 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2021 Xiang Chen\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", - "\"\"\"Code sample that solves a model and gets the infeasibility assumptions.\"\"\"\n", - "# [START program]\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Showcases assumptions.\"\"\"\n", - "# Creates the model.\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + "def main():\n", + " \"\"\"Showcases assumptions.\"\"\"\n", + " # Creates the model.\n", + " model = cp_model.CpModel()\n", "\n", - "# Creates the variables.\n", - "# [START variables]\n", - "x = model.NewIntVar(0, 10, 'x')\n", - "y = model.NewIntVar(0, 10, 'y')\n", - "z = model.NewIntVar(0, 10, 'z')\n", - "a = model.NewBoolVar('a')\n", - "b = model.NewBoolVar('b')\n", - "c = model.NewBoolVar('c')\n", - "# [END variables]\n", + " # Creates the variables.\n", + " x = model.NewIntVar(0, 10, 'x')\n", + " y = model.NewIntVar(0, 10, 'y')\n", + " z = model.NewIntVar(0, 10, 'z')\n", + " a = model.NewBoolVar('a')\n", + " b = model.NewBoolVar('b')\n", + " c = model.NewBoolVar('c')\n", "\n", - "# Creates the constraints.\n", - "# [START constraints]\n", - "model.Add(x > y).OnlyEnforceIf(a)\n", - "model.Add(y > z).OnlyEnforceIf(b)\n", - "model.Add(z > x).OnlyEnforceIf(c)\n", - "# [END constraints]\n", + " # Creates the constraints.\n", + " model.Add(x > y).OnlyEnforceIf(a)\n", + " model.Add(y > z).OnlyEnforceIf(b)\n", + " model.Add(z > x).OnlyEnforceIf(c)\n", "\n", - "# Add assumptions\n", - "model.AddAssumptions([a, b, c])\n", + " # Add assumptions\n", + " model.AddAssumptions([a, b, c])\n", "\n", - "# Creates a solver and solves.\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", + " # Creates a solver and solves.\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", "\n", - "# Print solution.\n", - "# [START print_solution]\n", - "print(f'Status = {solver.StatusName(status)}')\n", - "if status == cp_model.INFEASIBLE:\n", - " print('SufficientAssumptionsForInfeasibility = '\n", - " f'{solver.SufficientAssumptionsForInfeasibility()}')\n", - "# [END print_solution]\n", + " # Print solution.\n", + " print(f'Status = {solver.StatusName(status)}')\n", + " if status == cp_model.INFEASIBLE:\n", + " print('SufficientAssumptionsForInfeasibility = '\n", + " f'{solver.SufficientAssumptionsForInfeasibility()}')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/binpacking_problem_sat.ipynb b/examples/notebook/sat/binpacking_problem_sat.ipynb index f4a5716114..1a8799289d 100644 --- a/examples/notebook/sat/binpacking_problem_sat.ipynb +++ b/examples/notebook/sat/binpacking_problem_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves a binpacking problem using the CP-SAT solver.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solves a binpacking problem using the CP-SAT solver.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/bool_or_sample_sat.ipynb b/examples/notebook/sat/bool_or_sample_sat.ipynb index 4e9f91ec40..6cb4121230 100644 --- a/examples/notebook/sat/bool_or_sample_sat.ipynb +++ b/examples/notebook/sat/bool_or_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample to demonstrates a simple Boolean constraint.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample to demonstrates a simple Boolean constraint.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/boolean_product_sample_sat.ipynb b/examples/notebook/sat/boolean_product_sample_sat.ipynb index ac50d8ff59..7331e9961c 100644 --- a/examples/notebook/sat/boolean_product_sample_sat.ipynb +++ b/examples/notebook/sat/boolean_product_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample that encodes the product of two Boolean variables.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample that encodes the product of two Boolean variables.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/channeling_sample_sat.ipynb b/examples/notebook/sat/channeling_sample_sat.ipynb index b4b5e11ac3..d2bbcad1dc 100644 --- a/examples/notebook/sat/channeling_sample_sat.ipynb +++ b/examples/notebook/sat/channeling_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Link integer constraints together.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Link integer constraints together.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/copy_model_sample_sat.ipynb b/examples/notebook/sat/copy_model_sample_sat.ipynb index ce95c3357d..1080132a00 100644 --- a/examples/notebook/sat/copy_model_sample_sat.ipynb +++ b/examples/notebook/sat/copy_model_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Showcases deep copying of a model.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,54 +82,28 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Showcases deep copying of a model.\"\"\"\n", - "\n", - "# [START program]\n", "from ortools.sat.python import cp_model\n", "\n", "\n", "def CopyModelSat():\n", " \"\"\"Showcases printing intermediate solutions found during search.\"\"\"\n", " # Creates the model.\n", - " # [START model]\n", " model = cp_model.CpModel()\n", - " # [END model]\n", "\n", " # Creates the variables.\n", - " # [START variables]\n", " num_vals = 3\n", " x = model.NewIntVar(0, num_vals - 1, 'x')\n", " y = model.NewIntVar(0, num_vals - 1, 'y')\n", " z = model.NewIntVar(0, num_vals - 1, 'z')\n", - " # [END variables]\n", "\n", " # Creates the constraints.\n", - " # [START constraints]\n", " model.Add(x != y)\n", - " # [END constraints]\n", "\n", - " # [START objective]\n", " model.Maximize(x + 2 * y + 3 * z)\n", - " # [END objective]\n", "\n", " # Creates a solver and solves.\n", - " # [START solve]\n", " solver = cp_model.CpSolver()\n", " status = solver.Solve(model)\n", - " # [END solve]\n", "\n", " if status == cp_model.OPTIMAL:\n", " print('Optimal value of the original model: {}'.format(\n", @@ -143,7 +125,6 @@ "\n", "\n", "CopyModelSat()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/notebook/sat/cp_is_fun_sat.ipynb b/examples/notebook/sat/cp_is_fun_sat.ipynb index 4f48685fcf..3237755b22 100644 --- a/examples/notebook/sat/cp_is_fun_sat.ipynb +++ b/examples/notebook/sat/cp_is_fun_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,19 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Cryptarithmetic puzzle.\n", + "\n", + "First attempt to solve equation CP + IS + FUN = TRUE\n", + "where each letter represents a unique digit.\n", + "\n", + "This problem has 72 different solutions in base 10.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,33 +87,9 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Cryptarithmetic puzzle.\n", - "\n", - "First attempt to solve equation CP + IS + FUN = TRUE\n", - "where each letter represents a unique digit.\n", - "\n", - "This problem has 72 different solutions in base 10.\n", - "\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# [START solution_printer]\n", "class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):\n", " \"\"\"Print intermediate solutions.\"\"\"\n", "\n", @@ -117,64 +106,57 @@ "\n", " def solution_count(self):\n", " return self.__solution_count\n", - " # [END solution_printer]\n", "\n", "\n", - "\"\"\"Solve the CP+IS+FUN==TRUE cryptarithm.\"\"\"\n", - "# Constraint programming engine\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + "def main():\n", + " \"\"\"Solve the CP+IS+FUN==TRUE cryptarithm.\"\"\"\n", + " # Constraint programming engine\n", + " model = cp_model.CpModel()\n", "\n", - "# [START variables]\n", - "base = 10\n", + " base = 10\n", "\n", - "c = model.NewIntVar(1, base - 1, 'C')\n", - "p = model.NewIntVar(0, base - 1, 'P')\n", - "i = model.NewIntVar(1, base - 1, 'I')\n", - "s = model.NewIntVar(0, base - 1, 'S')\n", - "f = model.NewIntVar(1, base - 1, 'F')\n", - "u = model.NewIntVar(0, base - 1, 'U')\n", - "n = model.NewIntVar(0, base - 1, 'N')\n", - "t = model.NewIntVar(1, base - 1, 'T')\n", - "r = model.NewIntVar(0, base - 1, 'R')\n", - "e = model.NewIntVar(0, base - 1, 'E')\n", + " c = model.NewIntVar(1, base - 1, 'C')\n", + " p = model.NewIntVar(0, base - 1, 'P')\n", + " i = model.NewIntVar(1, base - 1, 'I')\n", + " s = model.NewIntVar(0, base - 1, 'S')\n", + " f = model.NewIntVar(1, base - 1, 'F')\n", + " u = model.NewIntVar(0, base - 1, 'U')\n", + " n = model.NewIntVar(0, base - 1, 'N')\n", + " t = model.NewIntVar(1, base - 1, 'T')\n", + " r = model.NewIntVar(0, base - 1, 'R')\n", + " e = model.NewIntVar(0, base - 1, 'E')\n", "\n", - "# We need to group variables in a list to use the constraint AllDifferent.\n", - "letters = [c, p, i, s, f, u, n, t, r, e]\n", + " # We need to group variables in a list to use the constraint AllDifferent.\n", + " letters = [c, p, i, s, f, u, n, t, r, e]\n", "\n", - "# Verify that we have enough digits.\n", - "assert base >= len(letters)\n", - "# [END variables]\n", + " # Verify that we have enough digits.\n", + " assert base >= len(letters)\n", "\n", - "# Define constraints.\n", - "# [START constraints]\n", - "model.AddAllDifferent(letters)\n", + " # Define constraints.\n", + " model.AddAllDifferent(letters)\n", "\n", - "# CP + IS + FUN = TRUE\n", - "model.Add(c * base + p + i * base + s + f * base * base + u * base +\n", - " n == t * base * base * base + r * base * base + u * base + e)\n", - "# [END constraints]\n", + " # CP + IS + FUN = TRUE\n", + " model.Add(c * base + p + i * base + s + f * base * base + u * base +\n", + " n == t * base * base * base + r * base * base + u * base + e)\n", "\n", - "# Creates a solver and solves the model.\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "solution_printer = VarArraySolutionPrinter(letters)\n", - "# Enumerate all solutions.\n", - "solver.parameters.enumerate_all_solutions = True\n", - "# Solve.\n", - "status = solver.Solve(model, solution_printer)\n", - "# [END solve]\n", + " # Creates a solver and solves the model.\n", + " solver = cp_model.CpSolver()\n", + " solution_printer = VarArraySolutionPrinter(letters)\n", + " # Enumerate all solutions.\n", + " solver.parameters.enumerate_all_solutions = True\n", + " # Solve.\n", + " status = solver.Solve(model, solution_printer)\n", "\n", - "# Statistics.\n", - "# [START statistics]\n", - "print('\\nStatistics')\n", - "print(f' status : {solver.StatusName(status)}')\n", - "print(f' conflicts: {solver.NumConflicts()}')\n", - "print(f' branches : {solver.NumBranches()}')\n", - "print(f' wall time: {solver.WallTime()} s')\n", - "print(f' sol found: {solution_printer.solution_count()}')\n", - "# [END statistics]\n", + " # Statistics.\n", + " print('\\nStatistics')\n", + " print(f' status : {solver.StatusName(status)}')\n", + " print(f' conflicts: {solver.NumConflicts()}')\n", + " print(f' branches : {solver.NumBranches()}')\n", + " print(f' wall time: {solver.WallTime()} s')\n", + " print(f' sol found: {solution_printer.solution_count()}')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/cp_sat_example.ipynb b/examples/notebook/sat/cp_sat_example.ipynb index 9bc96b6094..0132cefec4 100644 --- a/examples/notebook/sat/cp_sat_example.ipynb +++ b/examples/notebook/sat/cp_sat_example.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple solve." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,75 +82,48 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple solve.\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Minimal CP-SAT example to showcase calling the solver.\"\"\"\n", - "# Creates the model.\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + "def main():\n", + " \"\"\"Minimal CP-SAT example to showcase calling the solver.\"\"\"\n", + " # Creates the model.\n", + " model = cp_model.CpModel()\n", "\n", - "# Creates the variables.\n", - "# [START variables]\n", - "var_upper_bound = max(50, 45, 37)\n", - "x = model.NewIntVar(0, var_upper_bound, 'x')\n", - "y = model.NewIntVar(0, var_upper_bound, 'y')\n", - "z = model.NewIntVar(0, var_upper_bound, 'z')\n", - "# [END variables]\n", + " # Creates the variables.\n", + " var_upper_bound = max(50, 45, 37)\n", + " x = model.NewIntVar(0, var_upper_bound, 'x')\n", + " y = model.NewIntVar(0, var_upper_bound, 'y')\n", + " z = model.NewIntVar(0, var_upper_bound, 'z')\n", "\n", - "# Creates the constraints.\n", - "# [START constraints]\n", - "model.Add(2 * x + 7 * y + 3 * z <= 50)\n", - "model.Add(3 * x - 5 * y + 7 * z <= 45)\n", - "model.Add(5 * x + 2 * y - 6 * z <= 37)\n", - "# [END constraints]\n", + " # Creates the constraints.\n", + " model.Add(2 * x + 7 * y + 3 * z <= 50)\n", + " model.Add(3 * x - 5 * y + 7 * z <= 45)\n", + " model.Add(5 * x + 2 * y - 6 * z <= 37)\n", "\n", - "# [START objective]\n", - "model.Maximize(2 * x + 2 * y + 3 * z)\n", - "# [END objective]\n", + " model.Maximize(2 * x + 2 * y + 3 * z)\n", "\n", - "# Creates a solver and solves the model.\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", + " # Creates a solver and solves the model.\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", "\n", - "# [START print_solution]\n", - "if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", - " print(f'Maximum of objective function: {solver.ObjectiveValue()}\\n')\n", - " print(f'x = {solver.Value(x)}')\n", - " print(f'y = {solver.Value(y)}')\n", - " print(f'z = {solver.Value(z)}')\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", + " print(f'Maximum of objective function: {solver.ObjectiveValue()}\\n')\n", + " print(f'x = {solver.Value(x)}')\n", + " print(f'y = {solver.Value(y)}')\n", + " print(f'z = {solver.Value(z)}')\n", + " else:\n", + " print('No solution found.')\n", "\n", - "# Statistics.\n", - "# [START statistics]\n", - "print('\\nStatistics')\n", - "print(f' status : {solver.StatusName(status)}')\n", - "print(f' conflicts: {solver.NumConflicts()}')\n", - "print(f' branches : {solver.NumBranches()}')\n", - "print(f' wall time: {solver.WallTime()} s')\n", - "# [END statistics]\n", + " # Statistics.\n", + " print('\\nStatistics')\n", + " print(f' status : {solver.StatusName(status)}')\n", + " print(f' conflicts: {solver.NumConflicts()}')\n", + " print(f' branches : {solver.NumBranches()}')\n", + " print(f' wall time: {solver.WallTime()} s')\n", + "\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/earliness_tardiness_cost_sample_sat.ipynb b/examples/notebook/sat/earliness_tardiness_cost_sample_sat.ipynb index 61116aa247..60c61c317c 100644 --- a/examples/notebook/sat/earliness_tardiness_cost_sample_sat.ipynb +++ b/examples/notebook/sat/earliness_tardiness_cost_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Encodes an convex piecewise linear function.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Encodes an convex piecewise linear function.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/interval_sample_sat.ipynb b/examples/notebook/sat/interval_sample_sat.ipynb index 0635234b08..73d869b34f 100644 --- a/examples/notebook/sat/interval_sample_sat.ipynb +++ b/examples/notebook/sat/interval_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample to demonstrates how to build an interval.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample to demonstrates how to build an interval.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/literal_sample_sat.ipynb b/examples/notebook/sat/literal_sample_sat.ipynb index f4209a3b11..ce5cea3983 100644 --- a/examples/notebook/sat/literal_sample_sat.ipynb +++ b/examples/notebook/sat/literal_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample to demonstrate Boolean variable and literals.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample to demonstrate Boolean variable and literals.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/minimal_jobshop_sat.ipynb b/examples/notebook/sat/minimal_jobshop_sat.ipynb index db5bcb6e6f..a9aca0e8da 100644 --- a/examples/notebook/sat/minimal_jobshop_sat.ipynb +++ b/examples/notebook/sat/minimal_jobshop_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Minimal jobshop example." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,155 +82,126 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Minimal jobshop example.\"\"\"\n", - "# [START import]\n", "import collections\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "\"\"\"Minimal jobshop problem.\"\"\"\n", - "# Data.\n", - "# [START data]\n", - "jobs_data = [ # task = (machine_id, processing_time).\n", - " [(0, 3), (1, 2), (2, 2)], # Job0\n", - " [(0, 2), (2, 1), (1, 4)], # Job1\n", - " [(1, 4), (2, 3)] # Job2\n", - "]\n", + "def main():\n", + " \"\"\"Minimal jobshop problem.\"\"\"\n", + " # Data.\n", + " jobs_data = [ # task = (machine_id, processing_time).\n", + " [(0, 3), (1, 2), (2, 2)], # Job0\n", + " [(0, 2), (2, 1), (1, 4)], # Job1\n", + " [(1, 4), (2, 3)] # Job2\n", + " ]\n", "\n", - "machines_count = 1 + max(task[0] for job in jobs_data for task in job)\n", - "all_machines = range(machines_count)\n", - "# Computes horizon dynamically as the sum of all durations.\n", - "horizon = sum(task[1] for job in jobs_data for task in job)\n", - "# [END data]\n", + " machines_count = 1 + max(task[0] for job in jobs_data for task in job)\n", + " all_machines = range(machines_count)\n", + " # Computes horizon dynamically as the sum of all durations.\n", + " horizon = sum(task[1] for job in jobs_data for task in job)\n", "\n", - "# Create the model.\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + " # Create the model.\n", + " model = cp_model.CpModel()\n", "\n", - "# [START variables]\n", - "# Named tuple to store information about created variables.\n", - "task_type = collections.namedtuple('task_type', 'start end interval')\n", - "# Named tuple to manipulate solution information.\n", - "assigned_task_type = collections.namedtuple('assigned_task_type',\n", - " 'start job index duration')\n", + " # Named tuple to store information about created variables.\n", + " task_type = collections.namedtuple('task_type', 'start end interval')\n", + " # Named tuple to manipulate solution information.\n", + " assigned_task_type = collections.namedtuple('assigned_task_type',\n", + " 'start job index duration')\n", "\n", - "# Creates job intervals and add to the corresponding machine lists.\n", - "all_tasks = {}\n", - "machine_to_intervals = collections.defaultdict(list)\n", + " # Creates job intervals and add to the corresponding machine lists.\n", + " all_tasks = {}\n", + " machine_to_intervals = collections.defaultdict(list)\n", "\n", - "for job_id, job in enumerate(jobs_data):\n", - " for task_id, task in enumerate(job):\n", - " machine = task[0]\n", - " duration = task[1]\n", - " suffix = '_%i_%i' % (job_id, task_id)\n", - " start_var = model.NewIntVar(0, horizon, 'start' + suffix)\n", - " end_var = model.NewIntVar(0, horizon, 'end' + suffix)\n", - " interval_var = model.NewIntervalVar(start_var, duration, end_var,\n", - " 'interval' + suffix)\n", - " all_tasks[job_id, task_id] = task_type(start=start_var,\n", - " end=end_var,\n", - " interval=interval_var)\n", - " machine_to_intervals[machine].append(interval_var)\n", - "# [END variables]\n", - "\n", - "# [START constraints]\n", - "# Create and add disjunctive constraints.\n", - "for machine in all_machines:\n", - " model.AddNoOverlap(machine_to_intervals[machine])\n", - "\n", - "# Precedences inside a job.\n", - "for job_id, job in enumerate(jobs_data):\n", - " for task_id in range(len(job) - 1):\n", - " model.Add(all_tasks[job_id, task_id +\n", - " 1].start >= all_tasks[job_id, task_id].end)\n", - "# [END constraints]\n", - "\n", - "# [START objective]\n", - "# Makespan objective.\n", - "obj_var = model.NewIntVar(0, horizon, 'makespan')\n", - "model.AddMaxEquality(obj_var, [\n", - " all_tasks[job_id, len(job) - 1].end\n", - " for job_id, job in enumerate(jobs_data)\n", - "])\n", - "model.Minimize(obj_var)\n", - "# [END objective]\n", - "\n", - "# Creates the solver and solve.\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", - "\n", - "# [START print_solution]\n", - "if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", - " print('Solution:')\n", - " # Create one list of assigned tasks per machine.\n", - " assigned_jobs = collections.defaultdict(list)\n", " for job_id, job in enumerate(jobs_data):\n", " for task_id, task in enumerate(job):\n", " machine = task[0]\n", - " assigned_jobs[machine].append(\n", - " assigned_task_type(start=solver.Value(\n", - " all_tasks[job_id, task_id].start),\n", - " job=job_id,\n", - " index=task_id,\n", - " duration=task[1]))\n", + " duration = task[1]\n", + " suffix = '_%i_%i' % (job_id, task_id)\n", + " start_var = model.NewIntVar(0, horizon, 'start' + suffix)\n", + " end_var = model.NewIntVar(0, horizon, 'end' + suffix)\n", + " interval_var = model.NewIntervalVar(start_var, duration, end_var,\n", + " 'interval' + suffix)\n", + " all_tasks[job_id, task_id] = task_type(start=start_var,\n", + " end=end_var,\n", + " interval=interval_var)\n", + " machine_to_intervals[machine].append(interval_var)\n", "\n", - " # Create per machine output lines.\n", - " output = ''\n", + " # Create and add disjunctive constraints.\n", " for machine in all_machines:\n", - " # Sort by starting time.\n", - " assigned_jobs[machine].sort()\n", - " sol_line_tasks = 'Machine ' + str(machine) + ': '\n", - " sol_line = ' '\n", + " model.AddNoOverlap(machine_to_intervals[machine])\n", "\n", - " for assigned_task in assigned_jobs[machine]:\n", - " name = 'job_%i_task_%i' % (assigned_task.job,\n", - " assigned_task.index)\n", - " # Add spaces to output to align columns.\n", - " sol_line_tasks += '%-15s' % name\n", + " # Precedences inside a job.\n", + " for job_id, job in enumerate(jobs_data):\n", + " for task_id in range(len(job) - 1):\n", + " model.Add(all_tasks[job_id, task_id +\n", + " 1].start >= all_tasks[job_id, task_id].end)\n", "\n", - " start = assigned_task.start\n", - " duration = assigned_task.duration\n", - " sol_tmp = '[%i,%i]' % (start, start + duration)\n", - " # Add spaces to output to align columns.\n", - " sol_line += '%-15s' % sol_tmp\n", + " # Makespan objective.\n", + " obj_var = model.NewIntVar(0, horizon, 'makespan')\n", + " model.AddMaxEquality(obj_var, [\n", + " all_tasks[job_id, len(job) - 1].end\n", + " for job_id, job in enumerate(jobs_data)\n", + " ])\n", + " model.Minimize(obj_var)\n", "\n", - " sol_line += '\\n'\n", - " sol_line_tasks += '\\n'\n", - " output += sol_line_tasks\n", - " output += sol_line\n", + " # Creates the solver and solve.\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", "\n", - " # Finally print the solution found.\n", - " print(f'Optimal Schedule Length: {solver.ObjectiveValue()}')\n", - " print(output)\n", - "else:\n", - " print('No solution found.')\n", - "# [END print_solution]\n", + " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", + " print('Solution:')\n", + " # Create one list of assigned tasks per machine.\n", + " assigned_jobs = collections.defaultdict(list)\n", + " for job_id, job in enumerate(jobs_data):\n", + " for task_id, task in enumerate(job):\n", + " machine = task[0]\n", + " assigned_jobs[machine].append(\n", + " assigned_task_type(start=solver.Value(\n", + " all_tasks[job_id, task_id].start),\n", + " job=job_id,\n", + " index=task_id,\n", + " duration=task[1]))\n", "\n", - "# Statistics.\n", - "# [START statistics]\n", - "print('\\nStatistics')\n", - "print(' - conflicts: %i' % solver.NumConflicts())\n", - "print(' - branches : %i' % solver.NumBranches())\n", - "print(' - wall time: %f s' % solver.WallTime())\n", - "# [END statistics]\n", + " # Create per machine output lines.\n", + " output = ''\n", + " for machine in all_machines:\n", + " # Sort by starting time.\n", + " assigned_jobs[machine].sort()\n", + " sol_line_tasks = 'Machine ' + str(machine) + ': '\n", + " sol_line = ' '\n", + "\n", + " for assigned_task in assigned_jobs[machine]:\n", + " name = 'job_%i_task_%i' % (assigned_task.job,\n", + " assigned_task.index)\n", + " # Add spaces to output to align columns.\n", + " sol_line_tasks += '%-15s' % name\n", + "\n", + " start = assigned_task.start\n", + " duration = assigned_task.duration\n", + " sol_tmp = '[%i,%i]' % (start, start + duration)\n", + " # Add spaces to output to align columns.\n", + " sol_line += '%-15s' % sol_tmp\n", + "\n", + " sol_line += '\\n'\n", + " sol_line_tasks += '\\n'\n", + " output += sol_line_tasks\n", + " output += sol_line\n", + "\n", + " # Finally print the solution found.\n", + " print(f'Optimal Schedule Length: {solver.ObjectiveValue()}')\n", + " print(output)\n", + " else:\n", + " print('No solution found.')\n", + "\n", + " # Statistics.\n", + " print('\\nStatistics')\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" ] } diff --git a/examples/notebook/sat/multiple_knapsack_sat.ipynb b/examples/notebook/sat/multiple_knapsack_sat.ipynb index b8b8920a56..d7e3eeb384 100644 --- a/examples/notebook/sat/multiple_knapsack_sat.ipynb +++ b/examples/notebook/sat/multiple_knapsack_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves a multiple knapsack problem using the CP-SAT solver." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,107 +82,80 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Solves a multiple knapsack problem using the CP-SAT solver.\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# [START data]\n", - "data = {}\n", - "data['weights'] = [\n", - " 48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36\n", - "]\n", - "data['values'] = [\n", - " 10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25\n", - "]\n", - "assert len(data['weights']) == len(data['values'])\n", - "data['num_items'] = len(data['weights'])\n", - "data['all_items'] = range(data['num_items'])\n", + "def main():\n", + " data = {}\n", + " data['weights'] = [\n", + " 48, 30, 42, 36, 36, 48, 42, 42, 36, 24, 30, 30, 42, 36, 36\n", + " ]\n", + " data['values'] = [\n", + " 10, 30, 25, 50, 35, 30, 15, 40, 30, 35, 45, 10, 20, 30, 25\n", + " ]\n", + " assert len(data['weights']) == len(data['values'])\n", + " data['num_items'] = len(data['weights'])\n", + " data['all_items'] = range(data['num_items'])\n", "\n", - "data['bin_capacities'] = [100, 100, 100, 100, 100]\n", - "data['num_bins'] = len(data['bin_capacities'])\n", - "data['all_bins'] = range(data['num_bins'])\n", - "# [END data]\n", + " data['bin_capacities'] = [100, 100, 100, 100, 100]\n", + " data['num_bins'] = len(data['bin_capacities'])\n", + " data['all_bins'] = range(data['num_bins'])\n", "\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + " model = cp_model.CpModel()\n", "\n", - "# Variables.\n", - "# [START variables]\n", - "# x[i, b] = 1 if item i is packed in bin b.\n", - "x = {}\n", - "for i in data['all_items']:\n", + " # Variables.\n", + " # x[i, b] = 1 if item i is packed in bin b.\n", + " x = {}\n", + " for i in data['all_items']:\n", + " for b in data['all_bins']:\n", + " x[i, b] = model.NewBoolVar(f'x_{i}_{b}')\n", + "\n", + " # Constraints.\n", + " # Each item is assigned to at most one bin.\n", + " for i in data['all_items']:\n", + " model.AddAtMostOne(x[i, b] for b in data['all_bins'])\n", + "\n", + " # The amount packed in each bin cannot exceed its capacity.\n", " for b in data['all_bins']:\n", - " x[i, b] = model.NewBoolVar(f'x_{i}_{b}')\n", - "# [END variables]\n", + " model.Add(\n", + " sum(x[i, b] * data['weights'][i]\n", + " for i in data['all_items']) <= data['bin_capacities'][b])\n", "\n", - "# Constraints.\n", - "# [START constraints]\n", - "# Each item is assigned to at most one bin.\n", - "for i in data['all_items']:\n", - " model.AddAtMostOne(x[i, b] for b in data['all_bins'])\n", + " # Objective.\n", + " # Maximize total value of packed items.\n", + " objective = []\n", + " for i in data['all_items']:\n", + " for b in data['all_bins']:\n", + " objective.append(\n", + " cp_model.LinearExpr.Term(x[i, b], data['values'][i]))\n", + " model.Maximize(cp_model.LinearExpr.Sum(objective))\n", "\n", - "# The amount packed in each bin cannot exceed its capacity.\n", - "for b in data['all_bins']:\n", - " model.Add(\n", - " sum(x[i, b] * data['weights'][i]\n", - " for i in data['all_items']) <= data['bin_capacities'][b])\n", - "# [END constraints]\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", "\n", - "# Objective.\n", - "# [START objective]\n", - "# Maximize total value of packed items.\n", - "objective = []\n", - "for i in data['all_items']:\n", - " for b in data['all_bins']:\n", - " objective.append(\n", - " cp_model.LinearExpr.Term(x[i, b], data['values'][i]))\n", - "model.Maximize(cp_model.LinearExpr.Sum(objective))\n", - "# [END objective]\n", + " if status == cp_model.OPTIMAL:\n", + " print(f'Total packed value: {solver.ObjectiveValue()}')\n", + " total_weight = 0\n", + " for b in data['all_bins']:\n", + " print(f'Bin {b}')\n", + " bin_weight = 0\n", + " bin_value = 0\n", + " for i in data['all_items']:\n", + " if solver.Value(x[i, b]) > 0:\n", + " print(\n", + " f\"Item {i} weight: {data['weights'][i]} value: {data['values'][i]}\"\n", + " )\n", + " bin_weight += data['weights'][i]\n", + " bin_value += data['values'][i]\n", + " print(f'Packed bin weight: {bin_weight}')\n", + " print(f'Packed bin value: {bin_value}\\n')\n", + " total_weight += bin_weight\n", + " print(f'Total packed weight: {total_weight}')\n", + " else:\n", + " print('The problem does not have an optimal solution.')\n", "\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", "\n", - "# [START print_solution]\n", - "if status == cp_model.OPTIMAL:\n", - " print(f'Total packed value: {solver.ObjectiveValue()}')\n", - " total_weight = 0\n", - " for b in data['all_bins']:\n", - " print(f'Bin {b}')\n", - " bin_weight = 0\n", - " bin_value = 0\n", - " for i in data['all_items']:\n", - " if solver.Value(x[i, b]) > 0:\n", - " print(\n", - " f\"Item {i} weight: {data['weights'][i]} value: {data['values'][i]}\"\n", - " )\n", - " bin_weight += data['weights'][i]\n", - " bin_value += data['values'][i]\n", - " print(f'Packed bin weight: {bin_weight}')\n", - " print(f'Packed bin value: {bin_value}\\n')\n", - " total_weight += bin_weight\n", - " print(f'Total packed weight: {total_weight}')\n", - "else:\n", - " print('The problem does not have an optimal solution.')\n", - "# [END print_solution]\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/no_overlap_sample_sat.ipynb b/examples/notebook/sat/no_overlap_sample_sat.ipynb index bc4ba7237f..682a7d011e 100644 --- a/examples/notebook/sat/no_overlap_sample_sat.ipynb +++ b/examples/notebook/sat/no_overlap_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample to demonstrate how to build a NoOverlap constraint.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample to demonstrate how to build a NoOverlap constraint.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/nqueens_sat.ipynb b/examples/notebook/sat/nqueens_sat.ipynb index bc80762755..1898f7ef9f 100644 --- a/examples/notebook/sat/nqueens_sat.ipynb +++ b/examples/notebook/sat/nqueens_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "OR-Tools solution to the N-queens problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,29 +82,11 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"OR-Tools solution to the N-queens problem.\"\"\"\n", - "# [START import]\n", "import sys\n", "import time\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# [START solution_printer]\n", "class NQueenSolutionPrinter(cp_model.CpSolverSolutionCallback):\n", " \"\"\"Print intermediate solutions.\"\"\"\n", "\n", @@ -126,51 +116,48 @@ " print()\n", " print()\n", "\n", - "# [END solution_printer]\n", "\n", "\n", - "# Creates the solver.\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + "def main(board_size):\n", + " # Creates the solver.\n", + " model = cp_model.CpModel()\n", "\n", - "# Creates the variables.\n", - "# [START 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", - "# [END variables]\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", - "# [START constraints]\n", - "# All rows must be different.\n", - "model.AddAllDifferent(queens)\n", + " # Creates the constraints.\n", + " # All rows must be different.\n", + " model.AddAllDifferent(queens)\n", "\n", - "# All columns must be different because the indices of queens are all\n", - "# different.\n", + " # All columns must be different because the indices of queens are all\n", + " # different.\n", "\n", - "# No two queens can be on the same diagonal.\n", - "model.AddAllDifferent(queens[i] + i for i in range(board_size))\n", - "model.AddAllDifferent(queens[i] - i for i in range(board_size))\n", - "# [END constraints]\n", + " # No two queens can be on the same diagonal.\n", + " model.AddAllDifferent(queens[i] + i for i in range(board_size))\n", + " model.AddAllDifferent(queens[i] - i for i in range(board_size))\n", "\n", - "# Solve the model.\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "solution_printer = NQueenSolutionPrinter(queens)\n", - "solver.parameters.enumerate_all_solutions = True\n", - "solver.Solve(model, solution_printer)\n", - "# [END solve]\n", + " # Solve the model.\n", + " solver = cp_model.CpSolver()\n", + " solution_printer = NQueenSolutionPrinter(queens)\n", + " solver.parameters.enumerate_all_solutions = True\n", + " solver.Solve(model, solution_printer)\n", "\n", - "# Statistics.\n", - "# [START statistics]\n", - "print('\\nStatistics')\n", - "print(f' conflicts : {solver.NumConflicts()}')\n", - "print(f' branches : {solver.NumBranches()}')\n", - "print(f' wall time : {solver.WallTime()} s')\n", - "print(f' solutions found: {solution_printer.solution_count()}')\n", - "# [END statistics]\n", + " # Statistics.\n", + " print('\\nStatistics')\n", + " print(f' conflicts : {solver.NumConflicts()}')\n", + " print(f' branches : {solver.NumBranches()}')\n", + " print(f' wall time : {solver.WallTime()} s')\n", + " print(f' solutions found: {solution_printer.solution_count()}')\n", + "\n", + "\n", + "# By default, solve the 8x8 problem.\n", + "size = 8\n", + "if len(sys.argv) > 1:\n", + " size = int(sys.argv[1])\n", + "main(size)\n", "\n" ] } diff --git a/examples/notebook/sat/nurses_sat.ipynb b/examples/notebook/sat/nurses_sat.ipynb index daef758456..5010728096 100644 --- a/examples/notebook/sat/nurses_sat.ipynb +++ b/examples/notebook/sat/nurses_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Example of a simple nurse scheduling problem." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,146 +82,113 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Example of a simple nurse scheduling problem.\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# Data.\n", - "# [START data]\n", - "num_nurses = 4\n", - "num_shifts = 3\n", - "num_days = 3\n", - "all_nurses = range(num_nurses)\n", - "all_shifts = range(num_shifts)\n", - "all_days = range(num_days)\n", - "# [END data]\n", + "def main():\n", + " # Data.\n", + " num_nurses = 4\n", + " num_shifts = 3\n", + " num_days = 3\n", + " all_nurses = range(num_nurses)\n", + " all_shifts = range(num_shifts)\n", + " all_days = range(num_days)\n", "\n", - "# Creates the model.\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + " # Creates the model.\n", + " model = cp_model.CpModel()\n", "\n", - "# Creates shift variables.\n", - "# shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'.\n", - "# [START variables]\n", - "shifts = {}\n", - "for n in all_nurses:\n", + " # Creates shift variables.\n", + " # shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'.\n", + " shifts = {}\n", + " for n in all_nurses:\n", + " for d in all_days:\n", + " for s in all_shifts:\n", + " shifts[(n, d,\n", + " s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s))\n", + "\n", + " # Each shift is assigned to exactly one nurse in the schedule period.\n", " for d in all_days:\n", " for s in all_shifts:\n", - " shifts[(n, d,\n", - " s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s))\n", - "# [END variables]\n", + " model.AddExactlyOne(shifts[(n, d, s)] for n in all_nurses)\n", "\n", - "# Each shift is assigned to exactly one nurse in the schedule period.\n", - "# [START exactly_one_nurse]\n", - "for d in all_days:\n", - " for s in all_shifts:\n", - " model.AddExactlyOne(shifts[(n, d, s)] for n in all_nurses)\n", - "# [END exactly_one_nurse]\n", + " # Each nurse works at most one shift per day.\n", + " for n in all_nurses:\n", + " for d in all_days:\n", + " model.AddAtMostOne(shifts[(n, d, s)] for s in all_shifts)\n", "\n", - "# Each nurse works at most one shift per day.\n", - "# [START at_most_one_shift]\n", - "for n in all_nurses:\n", - " for d in all_days:\n", - " model.AddAtMostOne(shifts[(n, d, s)] for s in all_shifts)\n", - "# [END at_most_one_shift]\n", + " # Try to distribute the shifts evenly, so that each nurse works\n", + " # min_shifts_per_nurse shifts. If this is not possible, because the total\n", + " # number of shifts is not divisible by the number of nurses, some nurses will\n", + " # be assigned one more shift.\n", + " min_shifts_per_nurse = (num_shifts * num_days) // num_nurses\n", + " if num_shifts * num_days % num_nurses == 0:\n", + " max_shifts_per_nurse = min_shifts_per_nurse\n", + " else:\n", + " max_shifts_per_nurse = min_shifts_per_nurse + 1\n", + " for n in all_nurses:\n", + " num_shifts_worked = []\n", + " for d in all_days:\n", + " for s in all_shifts:\n", + " num_shifts_worked.append(shifts[(n, d, s)])\n", + " model.Add(min_shifts_per_nurse <= sum(num_shifts_worked))\n", + " model.Add(sum(num_shifts_worked) <= max_shifts_per_nurse)\n", "\n", - "# [START assign_nurses_evenly]\n", - "# Try to distribute the shifts evenly, so that each nurse works\n", - "# min_shifts_per_nurse shifts. If this is not possible, because the total\n", - "# number of shifts is not divisible by the number of nurses, some nurses will\n", - "# be assigned one more shift.\n", - "min_shifts_per_nurse = (num_shifts * num_days) // num_nurses\n", - "if num_shifts * num_days % num_nurses == 0:\n", - " max_shifts_per_nurse = min_shifts_per_nurse\n", - "else:\n", - " max_shifts_per_nurse = min_shifts_per_nurse + 1\n", - "for n in all_nurses:\n", - " num_shifts_worked = []\n", - " for d in all_days:\n", - " for s in all_shifts:\n", - " num_shifts_worked.append(shifts[(n, d, s)])\n", - " model.Add(min_shifts_per_nurse <= sum(num_shifts_worked))\n", - " model.Add(sum(num_shifts_worked) <= max_shifts_per_nurse)\n", - "# [END assign_nurses_evenly]\n", + " # Creates the solver and solve.\n", + " solver = cp_model.CpSolver()\n", + " solver.parameters.linearization_level = 0\n", + " # Enumerate all solutions.\n", + " solver.parameters.enumerate_all_solutions = True\n", "\n", - "# Creates the solver and solve.\n", - "# [START parameters]\n", - "solver = cp_model.CpSolver()\n", - "solver.parameters.linearization_level = 0\n", - "# Enumerate all solutions.\n", - "solver.parameters.enumerate_all_solutions = True\n", "\n", - "# [END parameters]\n", + " class NursesPartialSolutionPrinter(cp_model.CpSolverSolutionCallback):\n", + " \"\"\"Print intermediate solutions.\"\"\"\n", "\n", - "# [START solution_printer]\n", - "class NursesPartialSolutionPrinter(cp_model.CpSolverSolutionCallback):\n", - " \"\"\"Print intermediate solutions.\"\"\"\n", + " def __init__(self, shifts, num_nurses, num_days, num_shifts, limit):\n", + " cp_model.CpSolverSolutionCallback.__init__(self)\n", + " self._shifts = shifts\n", + " self._num_nurses = num_nurses\n", + " self._num_days = num_days\n", + " self._num_shifts = num_shifts\n", + " self._solution_count = 0\n", + " self._solution_limit = limit\n", "\n", - " def __init__(self, shifts, num_nurses, num_days, num_shifts, limit):\n", - " cp_model.CpSolverSolutionCallback.__init__(self)\n", - " self._shifts = shifts\n", - " self._num_nurses = num_nurses\n", - " self._num_days = num_days\n", - " self._num_shifts = num_shifts\n", - " self._solution_count = 0\n", - " self._solution_limit = limit\n", + " def on_solution_callback(self):\n", + " self._solution_count += 1\n", + " print('Solution %i' % self._solution_count)\n", + " for d in range(self._num_days):\n", + " print('Day %i' % d)\n", + " for n in range(self._num_nurses):\n", + " is_working = False\n", + " for s in range(self._num_shifts):\n", + " if self.Value(self._shifts[(n, d, s)]):\n", + " is_working = True\n", + " print(' Nurse %i works shift %i' % (n, s))\n", + " if not is_working:\n", + " print(' Nurse {} does not work'.format(n))\n", + " if self._solution_count >= self._solution_limit:\n", + " print('Stop search after %i solutions' % self._solution_limit)\n", + " self.StopSearch()\n", "\n", - " def on_solution_callback(self):\n", - " self._solution_count += 1\n", - " print('Solution %i' % self._solution_count)\n", - " for d in range(self._num_days):\n", - " print('Day %i' % d)\n", - " for n in range(self._num_nurses):\n", - " is_working = False\n", - " for s in range(self._num_shifts):\n", - " if self.Value(self._shifts[(n, d, s)]):\n", - " is_working = True\n", - " print(' Nurse %i works shift %i' % (n, s))\n", - " if not is_working:\n", - " print(' Nurse {} does not work'.format(n))\n", - " if self._solution_count >= self._solution_limit:\n", - " print('Stop search after %i solutions' % self._solution_limit)\n", - " self.StopSearch()\n", + " def solution_count(self):\n", + " return self._solution_count\n", "\n", - " def solution_count(self):\n", - " return self._solution_count\n", + " # Display the first five solutions.\n", + " solution_limit = 5\n", + " solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses,\n", + " num_days, num_shifts,\n", + " solution_limit)\n", "\n", - "# Display the first five solutions.\n", - "solution_limit = 5\n", - "solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses,\n", - " num_days, num_shifts,\n", - " solution_limit)\n", - "# [END solution_printer]\n", + " solver.Solve(model, solution_printer)\n", "\n", - "# [START solve]\n", - "solver.Solve(model, solution_printer)\n", - "# [END solve]\n", + " # Statistics.\n", + " print('\\nStatistics')\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.solution_count())\n", "\n", - "# Statistics.\n", - "# [START statistics]\n", - "print('\\nStatistics')\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.solution_count())\n", - "# [END statistics]\n", + "\n", + "main()\n", "\n" ] } diff --git a/examples/notebook/sat/optional_interval_sample_sat.ipynb b/examples/notebook/sat/optional_interval_sample_sat.ipynb index 6c1e37f727..809bb24f1d 100644 --- a/examples/notebook/sat/optional_interval_sample_sat.ipynb +++ b/examples/notebook/sat/optional_interval_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample to demonstrates how to build an optional interval.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample to demonstrates how to build an optional interval.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/overlapping_intervals_sample_sat.ipynb b/examples/notebook/sat/overlapping_intervals_sample_sat.ipynb index 1120382029..08459c7830 100644 --- a/examples/notebook/sat/overlapping_intervals_sample_sat.ipynb +++ b/examples/notebook/sat/overlapping_intervals_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample to demonstrates how to detect if two intervals overlap.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample to demonstrates how to detect if two intervals overlap.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/rabbits_and_pheasants_sat.ipynb b/examples/notebook/sat/rabbits_and_pheasants_sat.ipynb index 8630e6630e..e9dea1a52a 100644 --- a/examples/notebook/sat/rabbits_and_pheasants_sat.ipynb +++ b/examples/notebook/sat/rabbits_and_pheasants_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Rabbits and Pheasants quizz.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Rabbits and Pheasants quizz.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/ranking_sample_sat.ipynb b/examples/notebook/sat/ranking_sample_sat.ipynb index a7ad10d2af..39f882d8c4 100644 --- a/examples/notebook/sat/ranking_sample_sat.ipynb +++ b/examples/notebook/sat/ranking_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample to demonstrates how to rank intervals.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample to demonstrates how to rank intervals.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/reified_sample_sat.ipynb b/examples/notebook/sat/reified_sample_sat.ipynb index 095352fa54..7a121e4b3e 100644 --- a/examples/notebook/sat/reified_sample_sat.ipynb +++ b/examples/notebook/sat/reified_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple model with a reified constraint.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Simple model with a reified constraint.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/schedule_requests_sat.ipynb b/examples/notebook/sat/schedule_requests_sat.ipynb index 930b9c7970..a67fb8303e 100644 --- a/examples/notebook/sat/schedule_requests_sat.ipynb +++ b/examples/notebook/sat/schedule_requests_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Nurse scheduling problem with shift requests." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,138 +82,105 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Nurse scheduling problem with shift requests.\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", - "# This program tries to find an optimal assignment of nurses to shifts\n", - "# (3 shifts per day, for 7 days), subject to some constraints (see below).\n", - "# Each nurse can request to be assigned to specific shifts.\n", - "# The optimal assignment maximizes the number of fulfilled shift requests.\n", - "# [START data]\n", - "num_nurses = 5\n", - "num_shifts = 3\n", - "num_days = 7\n", - "all_nurses = range(num_nurses)\n", - "all_shifts = range(num_shifts)\n", - "all_days = range(num_days)\n", - "shift_requests = [[[0, 0, 1], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 1],\n", - " [0, 1, 0], [0, 0, 1]],\n", - " [[0, 0, 0], [0, 0, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0],\n", - " [0, 0, 0], [0, 0, 1]],\n", - " [[0, 1, 0], [0, 1, 0], [0, 0, 0], [1, 0, 0], [0, 0, 0],\n", - " [0, 1, 0], [0, 0, 0]],\n", - " [[0, 0, 1], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 0],\n", - " [1, 0, 0], [0, 0, 0]],\n", - " [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 0, 0], [1, 0, 0],\n", - " [0, 1, 0], [0, 0, 0]]]\n", - "# [END data]\n", + "def main():\n", + " # This program tries to find an optimal assignment of nurses to shifts\n", + " # (3 shifts per day, for 7 days), subject to some constraints (see below).\n", + " # Each nurse can request to be assigned to specific shifts.\n", + " # The optimal assignment maximizes the number of fulfilled shift requests.\n", + " num_nurses = 5\n", + " num_shifts = 3\n", + " num_days = 7\n", + " all_nurses = range(num_nurses)\n", + " all_shifts = range(num_shifts)\n", + " all_days = range(num_days)\n", + " shift_requests = [[[0, 0, 1], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 1],\n", + " [0, 1, 0], [0, 0, 1]],\n", + " [[0, 0, 0], [0, 0, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0],\n", + " [0, 0, 0], [0, 0, 1]],\n", + " [[0, 1, 0], [0, 1, 0], [0, 0, 0], [1, 0, 0], [0, 0, 0],\n", + " [0, 1, 0], [0, 0, 0]],\n", + " [[0, 0, 1], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 0],\n", + " [1, 0, 0], [0, 0, 0]],\n", + " [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 0, 0], [1, 0, 0],\n", + " [0, 1, 0], [0, 0, 0]]]\n", "\n", - "# Creates the model.\n", - "# [START model]\n", - "model = cp_model.CpModel()\n", - "# [END model]\n", + " # Creates the model.\n", + " model = cp_model.CpModel()\n", "\n", - "# Creates shift variables.\n", - "# shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'.\n", - "# [START variables]\n", - "shifts = {}\n", - "for n in all_nurses:\n", - " for d in all_days:\n", - " for s in all_shifts:\n", - " shifts[(n, d,\n", - " s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s))\n", - "# [END variables]\n", - "\n", - "# Each shift is assigned to exactly one nurse in .\n", - "# [START exactly_one_nurse]\n", - "for d in all_days:\n", - " for s in all_shifts:\n", - " model.AddExactlyOne(shifts[(n, d, s)] for n in all_nurses)\n", - "# [END exactly_one_nurse]\n", - "\n", - "# Each nurse works at most one shift per day.\n", - "# [START at_most_one_shift]\n", - "for n in all_nurses:\n", - " for d in all_days:\n", - " model.AddAtMostOne(shifts[(n, d, s)] for s in all_shifts)\n", - "# [END at_most_one_shift]\n", - "\n", - "# [START assign_nurses_evenly]\n", - "# Try to distribute the shifts evenly, so that each nurse works\n", - "# min_shifts_per_nurse shifts. If this is not possible, because the total\n", - "# number of shifts is not divisible by the number of nurses, some nurses will\n", - "# be assigned one more shift.\n", - "min_shifts_per_nurse = (num_shifts * num_days) // num_nurses\n", - "if num_shifts * num_days % num_nurses == 0:\n", - " max_shifts_per_nurse = min_shifts_per_nurse\n", - "else:\n", - " max_shifts_per_nurse = min_shifts_per_nurse + 1\n", - "for n in all_nurses:\n", - " num_shifts_worked = 0\n", - " for d in all_days:\n", - " for s in all_shifts:\n", - " num_shifts_worked += shifts[(n, d, s)]\n", - " model.Add(min_shifts_per_nurse <= num_shifts_worked)\n", - " model.Add(num_shifts_worked <= max_shifts_per_nurse)\n", - "# [END assign_nurses_evenly]\n", - "\n", - "# [START objective]\n", - "# pylint: disable=g-complex-comprehension\n", - "model.Maximize(\n", - " sum(shift_requests[n][d][s] * shifts[(n, d, s)] for n in all_nurses\n", - " for d in all_days for s in all_shifts))\n", - "# [END objective]\n", - "\n", - "# Creates the solver and solve.\n", - "# [START solve]\n", - "solver = cp_model.CpSolver()\n", - "status = solver.Solve(model)\n", - "# [END solve]\n", - "\n", - "# [START print_solution]\n", - "if status == cp_model.OPTIMAL:\n", - " print('Solution:')\n", - " for d in all_days:\n", - " print('Day', d)\n", - " for n in all_nurses:\n", + " # Creates shift variables.\n", + " # shifts[(n, d, s)]: nurse 'n' works shift 's' on day 'd'.\n", + " shifts = {}\n", + " for n in all_nurses:\n", + " for d in all_days:\n", " for s in all_shifts:\n", - " if solver.Value(shifts[(n, d, s)]) == 1:\n", - " if shift_requests[n][d][s] == 1:\n", - " print('Nurse', n, 'works shift', s, '(requested).')\n", - " else:\n", - " print('Nurse', n, 'works shift', s,\n", - " '(not requested).')\n", - " print()\n", - " print(f'Number of shift requests met = {solver.ObjectiveValue()}',\n", - " f'(out of {num_nurses * min_shifts_per_nurse})')\n", - "else:\n", - " print('No optimal solution found !')\n", - "# [END print_solution]\n", + " shifts[(n, d,\n", + " s)] = model.NewBoolVar('shift_n%id%is%i' % (n, d, s))\n", "\n", - "# Statistics.\n", - "# [START statistics]\n", - "print('\\nStatistics')\n", - "print(' - conflicts: %i' % solver.NumConflicts())\n", - "print(' - branches : %i' % solver.NumBranches())\n", - "print(' - wall time: %f s' % solver.WallTime())\n", - "# [END statistics]\n", + " # Each shift is assigned to exactly one nurse in .\n", + " for d in all_days:\n", + " for s in all_shifts:\n", + " model.AddExactlyOne(shifts[(n, d, s)] for n in all_nurses)\n", + "\n", + " # Each nurse works at most one shift per day.\n", + " for n in all_nurses:\n", + " for d in all_days:\n", + " model.AddAtMostOne(shifts[(n, d, s)] for s in all_shifts)\n", + "\n", + " # Try to distribute the shifts evenly, so that each nurse works\n", + " # min_shifts_per_nurse shifts. If this is not possible, because the total\n", + " # number of shifts is not divisible by the number of nurses, some nurses will\n", + " # be assigned one more shift.\n", + " min_shifts_per_nurse = (num_shifts * num_days) // num_nurses\n", + " if num_shifts * num_days % num_nurses == 0:\n", + " max_shifts_per_nurse = min_shifts_per_nurse\n", + " else:\n", + " max_shifts_per_nurse = min_shifts_per_nurse + 1\n", + " for n in all_nurses:\n", + " num_shifts_worked = 0\n", + " for d in all_days:\n", + " for s in all_shifts:\n", + " num_shifts_worked += shifts[(n, d, s)]\n", + " model.Add(min_shifts_per_nurse <= num_shifts_worked)\n", + " model.Add(num_shifts_worked <= max_shifts_per_nurse)\n", + "\n", + " # pylint: disable=g-complex-comprehension\n", + " model.Maximize(\n", + " sum(shift_requests[n][d][s] * shifts[(n, d, s)] for n in all_nurses\n", + " for d in all_days for s in all_shifts))\n", + "\n", + " # Creates the solver and solve.\n", + " solver = cp_model.CpSolver()\n", + " status = solver.Solve(model)\n", + "\n", + " if status == cp_model.OPTIMAL:\n", + " print('Solution:')\n", + " for d in all_days:\n", + " print('Day', d)\n", + " for n in all_nurses:\n", + " for s in all_shifts:\n", + " if solver.Value(shifts[(n, d, s)]) == 1:\n", + " if shift_requests[n][d][s] == 1:\n", + " print('Nurse', n, 'works shift', s, '(requested).')\n", + " else:\n", + " print('Nurse', n, 'works shift', s,\n", + " '(not requested).')\n", + " print()\n", + " print(f'Number of shift requests met = {solver.ObjectiveValue()}',\n", + " f'(out of {num_nurses * min_shifts_per_nurse})')\n", + " else:\n", + " print('No optimal solution found !')\n", + "\n", + " # Statistics.\n", + " print('\\nStatistics')\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" ] } diff --git a/examples/notebook/sat/scheduling_with_calendar_sample_sat.ipynb b/examples/notebook/sat/scheduling_with_calendar_sample_sat.ipynb index 6671c14537..2520e688dc 100644 --- a/examples/notebook/sat/scheduling_with_calendar_sample_sat.ipynb +++ b/examples/notebook/sat/scheduling_with_calendar_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample to demonstrate how an interval can span across a break.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample to demonstrate how an interval can span across a break.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/search_for_all_solutions_sample_sat.ipynb b/examples/notebook/sat/search_for_all_solutions_sample_sat.ipynb index 545a9b5adc..49ee896938 100644 --- a/examples/notebook/sat/search_for_all_solutions_sample_sat.ipynb +++ b/examples/notebook/sat/search_for_all_solutions_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample that solves a model and displays all solutions.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,26 +82,9 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample that solves a model and displays all solutions.\"\"\"\n", - "\n", - "# [START program]\n", "from ortools.sat.python import cp_model\n", "\n", "\n", - "# [START print_solution]\n", "class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback):\n", " \"\"\"Print intermediate solutions.\"\"\"\n", "\n", @@ -110,45 +101,35 @@ "\n", " def solution_count(self):\n", " return self.__solution_count\n", - " # [END print_solution]\n", "\n", "\n", "def SearchForAllSolutionsSampleSat():\n", " \"\"\"Showcases calling the solver to search for all solutions.\"\"\"\n", " # Creates the model.\n", - " # [START model]\n", " model = cp_model.CpModel()\n", - " # [END model]\n", "\n", " # Creates the variables.\n", - " # [START variables]\n", " num_vals = 3\n", " x = model.NewIntVar(0, num_vals - 1, 'x')\n", " y = model.NewIntVar(0, num_vals - 1, 'y')\n", " z = model.NewIntVar(0, num_vals - 1, 'z')\n", - " # [END variables]\n", "\n", " # Create the constraints.\n", - " # [START constraints]\n", " model.Add(x != y)\n", - " # [END constraints]\n", "\n", " # Create a solver and solve.\n", - " # [START solve]\n", " solver = cp_model.CpSolver()\n", " solution_printer = VarArraySolutionPrinter([x, y, z])\n", " # Enumerate all solutions.\n", " solver.parameters.enumerate_all_solutions = True\n", " # Solve.\n", " status = solver.Solve(model, solution_printer)\n", - " # [END solve]\n", "\n", " print('Status = %s' % solver.StatusName(status))\n", " print('Number of solutions found: %i' % solution_printer.solution_count())\n", "\n", "\n", "SearchForAllSolutionsSampleSat()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/notebook/sat/simple_sat_program.ipynb b/examples/notebook/sat/simple_sat_program.ipynb index 885aaae56a..66b59fc2eb 100644 --- a/examples/notebook/sat/simple_sat_program.ipynb +++ b/examples/notebook/sat/simple_sat_program.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Simple solve." + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,64 +82,36 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Simple solve.\"\"\"\n", - "# [START import]\n", "from ortools.sat.python import cp_model\n", - "# [END import]\n", "\n", "\n", "def SimpleSatProgram():\n", " \"\"\"Minimal CP-SAT example to showcase calling the solver.\"\"\"\n", " # Creates the model.\n", - " # [START model]\n", " model = cp_model.CpModel()\n", - " # [END model]\n", "\n", " # Creates the variables.\n", - " # [START variables]\n", " num_vals = 3\n", " x = model.NewIntVar(0, num_vals - 1, 'x')\n", " y = model.NewIntVar(0, num_vals - 1, 'y')\n", " z = model.NewIntVar(0, num_vals - 1, 'z')\n", - " # [END variables]\n", "\n", " # Creates the constraints.\n", - " # [START constraints]\n", " model.Add(x != y)\n", - " # [END constraints]\n", "\n", " # Creates a solver and solves the model.\n", - " # [START solve]\n", " solver = cp_model.CpSolver()\n", " status = solver.Solve(model)\n", - " # [END solve]\n", "\n", - " # [START print_solution]\n", " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n", " print('x = %i' % solver.Value(x))\n", " print('y = %i' % solver.Value(y))\n", " print('z = %i' % solver.Value(z))\n", " else:\n", " print('No solution found.')\n", - " # [END print_solution]\n", "\n", "\n", "SimpleSatProgram()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/notebook/sat/solution_hinting_sample_sat.ipynb b/examples/notebook/sat/solution_hinting_sample_sat.ipynb index 293775ac11..3f8b657f82 100644 --- a/examples/notebook/sat/solution_hinting_sample_sat.ipynb +++ b/examples/notebook/sat/solution_hinting_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample that solves a model using solution hinting.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,66 +82,39 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Code sample that solves a model using solution hinting.\"\"\"\n", - "\n", - "# [START program]\n", "from ortools.sat.python import cp_model\n", "\n", "\n", "def SolutionHintingSampleSat():\n", " \"\"\"Showcases solution hinting.\"\"\"\n", " # Creates the model.\n", - " # [START model]\n", " model = cp_model.CpModel()\n", - " # [END model]\n", "\n", " # Creates the variables.\n", - " # [START variables]\n", " num_vals = 3\n", " x = model.NewIntVar(0, num_vals - 1, 'x')\n", " y = model.NewIntVar(0, num_vals - 1, 'y')\n", " z = model.NewIntVar(0, num_vals - 1, 'z')\n", - " # [END variables]\n", "\n", " # Creates the constraints.\n", - " # [START constraints]\n", " model.Add(x != y)\n", - " # [END constraints]\n", "\n", - " # [START objective]\n", " model.Maximize(x + 2 * y + 3 * z)\n", - " # [END objective]\n", "\n", " # Solution hinting: x <- 1, y <- 2\n", " model.AddHint(x, 1)\n", " model.AddHint(y, 2)\n", "\n", " # Creates a solver and solves.\n", - " # [START solve]\n", " solver = cp_model.CpSolver()\n", " solution_printer = cp_model.VarArrayAndObjectiveSolutionPrinter([x, y, z])\n", " status = solver.Solve(model, solution_printer)\n", - " # [END solve]\n", "\n", " print('Status = %s' % solver.StatusName(status))\n", " print('Number of solutions found: %i' % solution_printer.solution_count())\n", "\n", "\n", "SolutionHintingSampleSat()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/notebook/sat/solve_and_print_intermediate_solutions_sample_sat.ipynb b/examples/notebook/sat/solve_and_print_intermediate_solutions_sample_sat.ipynb index 297bf2db82..0bccfad43a 100644 --- a/examples/notebook/sat/solve_and_print_intermediate_solutions_sample_sat.ipynb +++ b/examples/notebook/sat/solve_and_print_intermediate_solutions_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves an optimization problem and displays all intermediate solutions.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,27 +82,10 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Solves an optimization problem and displays all intermediate solutions.\"\"\"\n", - "\n", - "# [START program]\n", "from ortools.sat.python import cp_model\n", "\n", "\n", "# You need to subclass the cp_model.CpSolverSolutionCallback class.\n", - "# [START print_solution]\n", "class VarArrayAndObjectiveSolutionPrinter(cp_model.CpSolverSolutionCallback):\n", " \"\"\"Print intermediate solutions.\"\"\"\n", "\n", @@ -113,46 +104,34 @@ "\n", " def solution_count(self):\n", " return self.__solution_count\n", - " # [END print_solution]\n", "\n", "\n", "def SolveAndPrintIntermediateSolutionsSampleSat():\n", " \"\"\"Showcases printing intermediate solutions found during search.\"\"\"\n", " # Creates the model.\n", - " # [START model]\n", " model = cp_model.CpModel()\n", - " # [END model]\n", "\n", " # Creates the variables.\n", - " # [START variables]\n", " num_vals = 3\n", " x = model.NewIntVar(0, num_vals - 1, 'x')\n", " y = model.NewIntVar(0, num_vals - 1, 'y')\n", " z = model.NewIntVar(0, num_vals - 1, 'z')\n", - " # [END variables]\n", "\n", " # Creates the constraints.\n", - " # [START constraints]\n", " model.Add(x != y)\n", - " # [END constraints]\n", "\n", - " # [START objective]\n", " model.Maximize(x + 2 * y + 3 * z)\n", - " # [END objective]\n", "\n", " # Creates a solver and solves.\n", - " # [START solve]\n", " solver = cp_model.CpSolver()\n", " solution_printer = VarArrayAndObjectiveSolutionPrinter([x, y, z])\n", " status = solver.Solve(model, solution_printer)\n", - " # [END solve]\n", "\n", " print('Status = %s' % solver.StatusName(status))\n", " print('Number of solutions found: %i' % solution_printer.solution_count())\n", "\n", "\n", "SolveAndPrintIntermediateSolutionsSampleSat()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/notebook/sat/solve_with_time_limit_sample_sat.ipynb b/examples/notebook/sat/solve_with_time_limit_sample_sat.ipynb index dcedb54ee7..f7073fe536 100644 --- a/examples/notebook/sat/solve_with_time_limit_sample_sat.ipynb +++ b/examples/notebook/sat/solve_with_time_limit_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Solves a problem with a time limit.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,22 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Solves a problem with a time limit.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", @@ -120,7 +112,6 @@ "\n", "\n", "SolveWithTimeLimitSampleSat()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/notebook/sat/step_function_sample_sat.ipynb b/examples/notebook/sat/step_function_sample_sat.ipynb index 22eb67eddc..2ad66a97a3 100644 --- a/examples/notebook/sat/step_function_sample_sat.ipynb +++ b/examples/notebook/sat/step_function_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Implements a step function.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,21 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "\"\"\"Implements a step function.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", diff --git a/examples/notebook/sat/stop_after_n_solutions_sample_sat.ipynb b/examples/notebook/sat/stop_after_n_solutions_sample_sat.ipynb index 37a5a1e5a5..2a89974ffe 100644 --- a/examples/notebook/sat/stop_after_n_solutions_sample_sat.ipynb +++ b/examples/notebook/sat/stop_after_n_solutions_sample_sat.ipynb @@ -5,7 +5,7 @@ "id": "google", "metadata": {}, "source": [ - "##### Copyright 2021 Google LLC." + "##### Copyright 2022 Google LLC." ] }, { @@ -67,6 +67,14 @@ "!pip install ortools" ] }, + { + "cell_type": "markdown", + "id": "description", + "metadata": {}, + "source": [ + "Code sample that solves a model and displays a small number of solutions.\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -74,22 +82,6 @@ "metadata": {}, "outputs": [], "source": [ - "#!/usr/bin/env python3\n", - "# Copyright 2010-2021 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", - "# [START program]\n", - "\"\"\"Code sample that solves a model and displays a small number of solutions.\"\"\"\n", - "\n", "from ortools.sat.python import cp_model\n", "\n", "\n", @@ -138,7 +130,6 @@ "\n", "\n", "StopAfterNSolutionsSampleSat()\n", - "# [END program]\n", "\n" ] } diff --git a/examples/python/appointments.py b/examples/python/appointments.py old mode 100644 new mode 100755 index 0862205145..876ef6bede --- a/examples/python/appointments.py +++ b/examples/python/appointments.py @@ -11,6 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +# [START program] """Appointment selection. This module maximizes the number of appointments that can @@ -21,10 +22,12 @@ ratio of appointment types. # overloaded sum() clashes with pytype. # pytype: disable=wrong-arg-types +# [START import] from absl import app from absl import flags from ortools.linear_solver import pywraplp from ortools.sat.python import cp_model +# [END import] FLAGS = flags.FLAGS flags.DEFINE_integer('load_min', 480, 'Minimum load in minutes.') @@ -204,7 +207,7 @@ def GetOptimalSchedule(demand): return output -def main(_): +def solve_appointments(_): demand = [(45.0, 'Type1', 90), (30.0, 'Type2', 120), (25.0, 'Type3', 180)] print('*** input problem ***') print('Appointments: ') @@ -221,6 +224,7 @@ def main(_): for a in demand: installed_per_type[a[1]] = 0 + # [START print_solution] print('*** output solution ***') for template in selection: num_instances = template[0] @@ -238,7 +242,9 @@ def main(_): per_type = installed_per_type[name] print((' %d (%.2f%%) installations of type %s planned' % (per_type, per_type * 100.0 / installed, name))) + # [END print_solution] if __name__ == '__main__': - app.run(main) + app.run(solve_appointments) +# [END program] diff --git a/examples/python/bus_driver_scheduling_sat.py b/examples/python/bus_driver_scheduling_sat.py old mode 100644 new mode 100755 index 3ab717a43e..87cec6999c --- a/examples/python/bus_driver_scheduling_sat.py +++ b/examples/python/bus_driver_scheduling_sat.py @@ -1978,7 +1978,7 @@ def bus_driver_scheduling(minimize_drivers, max_num_drivers): return int(solver.ObjectiveValue()) -def main(_): +def solve_bus_driver_scheduling(): """Optimize the bus driver allocation in two passes.""" print('----------- first pass: minimize the number of drivers') num_drivers = bus_driver_scheduling(True, -1) @@ -1989,5 +1989,9 @@ def main(_): bus_driver_scheduling(False, num_drivers) +def main(_): + solve_bus_driver_scheduling() + + if __name__ == '__main__': app.run(main) diff --git a/examples/python/flexible_job_shop_sat.py b/examples/python/flexible_job_shop_sat.py old mode 100644 new mode 100755 diff --git a/examples/python/gate_scheduling_sat.py b/examples/python/gate_scheduling_sat.py old mode 100644 new mode 100755 diff --git a/examples/python/golomb8.py b/examples/python/golomb8.py old mode 100644 new mode 100755 index 9525d7c4a0..ae52de8f62 --- a/examples/python/golomb8.py +++ b/examples/python/golomb8.py @@ -19,6 +19,7 @@ It is known as the Golomb Ruler problem. The idea is to put marks on a rule such that all differences between all marks are all different. The objective is to minimize the length of the rule. +see: https://en.wikipedia.org/wiki/Golomb_ruler """ from absl import app @@ -26,56 +27,74 @@ from absl import flags from ortools.constraint_solver import pywrapcp FLAGS = flags.FLAGS - -# We disable the following warning because it is a false positive on constraints -# like: solver.Add(x == 0) -# pylint: disable=g-explicit-bool-comparison +flags.DEFINE_integer('order', 8, 'Order of the ruler.') -def main(_): +def solve_golomb_ruler(order): # Create the solver. solver = pywrapcp.Solver('golomb ruler') - size = 8 - var_max = size * size - all_vars = list(range(0, size)) + var_max = order * order + all_vars = list(range(0, order)) - marks = [solver.IntVar(0, var_max, 'marks_%d' % i) for i in all_vars] - - objective = solver.Minimize(marks[size - 1], 1) + marks = [solver.IntVar(0, var_max, f'marks_{i}') for i in all_vars] solver.Add(marks[0] == 0) + for i in range(order - 2): + solver.Add(marks[i + 1] > marks[i]) # We expand the creation of the diff array to avoid a pylint warning. diffs = [] - for i in range(size - 1): - for j in range(i + 1, size): + for i in range(order - 1): + for j in range(i + 1, order): diffs.append(marks[j] - marks[i]) solver.Add(solver.AllDifferent(diffs)) - solver.Add(marks[size - 1] - marks[size - 2] > marks[1] - marks[0]) - for i in range(size - 2): - solver.Add(marks[i + 1] > marks[i]) + # symmetry breaking + if order > 2: + solver.Add(marks[order - 1] - marks[order - 2] > marks[1] - marks[0]) + # objective + objective = solver.Minimize(marks[order - 1], 1) + + # Solve the model. solution = solver.Assignment() - solution.Add(marks[size - 1]) + for mark in marks: + solution.Add(mark) + for diff in diffs: + solution.Add(diff) collector = solver.AllSolutionCollector(solution) solver.Solve( - solver.Phase(marks, solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE), [objective, collector]) + solver.Phase( + marks, + solver.CHOOSE_FIRST_UNBOUND, + solver.ASSIGN_MIN_VALUE), + [objective, collector]) + + # Print solution. for i in range(0, collector.SolutionCount()): - obj_value = collector.Value(i, marks[size - 1]) - time = collector.WallTime(i) - branches = collector.Branches(i) - failures = collector.Failures(i) - print(('Solution #%i: value = %i, failures = %i, branches = %i,' - 'time = %i ms') % (i, obj_value, failures, branches, time)) - time = solver.WallTime() - branches = solver.Branches() - failures = solver.Failures() - print(('Total run : failures = %i, branches = %i, time = %i ms' % - (failures, branches, time))) + obj_value = collector.Value(i, marks[order - 1]) + print(f'Solution #{i}: value = {obj_value}') + for idx, var in enumerate(marks): + print(f'mark[{idx}]: {collector.Value(i, var)}') + intervals = [collector.Value(i, diff) for diff in diffs] + intervals.sort() + print(f'intervals: {intervals}') + + print('Statistics:') + print(f'- conflicts: {collector.Failures(i)}') + print(f'- branches : {collector.Branches(i)}') + print(f'- wall time: {collector.WallTime(i)}ms\n') + + print('Global Statistics:') + print(f'- total conflicts: {solver.Failures()}') + print(f'- total branches : {solver.Branches()}') + print(f'- total wall time: {solver.WallTime()}ms\n') + + +def main(_): + solve_golomb_ruler(FLAGS.order) if __name__ == '__main__': diff --git a/examples/python/golomb_sat.py b/examples/python/golomb_sat.py new file mode 100755 index 0000000000..f76e915ff2 --- /dev/null +++ b/examples/python/golomb_sat.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# Copyright 2010-2021 Google LLC +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""This is the Golomb ruler problem. + +This model aims at maximizing radar interferences in a minimum space. +It is known as the Golomb Ruler problem. + +The idea is to put marks on a rule such that all differences +between all marks are all different. The objective is to minimize the length +of the rule. +see: https://en.wikipedia.org/wiki/Golomb_ruler +""" + +from absl import app +from absl import flags + +from google.protobuf import text_format +from ortools.sat.python import cp_model + +FLAGS = flags.FLAGS +flags.DEFINE_integer('order', 8, 'Order of the ruler.') +flags.DEFINE_string('params', 'max_time_in_seconds:10.0', + 'Sat solver parameters.') + + +def solve_golomb_ruler(order, params): + # Create the model. + model = cp_model.CpModel() + + var_max = order * order + all_vars = list(range(0, order)) + + marks = [model.NewIntVar(0, var_max, f'marks_{i}') for i in all_vars] + + model.Add(marks[0] == 0) + for i in range(order - 2): + model.Add(marks[i + 1] > marks[i]) + + diffs = [] + for i in range(order - 1): + for j in range(i + 1, order): + diff = model.NewIntVar(0, var_max, f'diff [{j},{i}]') + model.Add(diff == marks[j] - marks[i]) + diffs.append(diff) + model.AddAllDifferent(diffs) + + # symmetry breaking + if order > 2: + model.Add(marks[order - 1] - marks[order - 2] > marks[1] - marks[0]) + + # Objective + model.Minimize(marks[order - 1]) + + # Solve the model. + solver = cp_model.CpSolver() + if params: + text_format.Parse(params, solver.parameters) + solution_printer = cp_model.ObjectiveSolutionPrinter() + print(f'Golomb ruler(order={order})') + status = solver.Solve(model, solution_printer) + + # Print solution. + print(f'status: {solver.StatusName(status)}') + if status in (cp_model.OPTIMAL, cp_model.FEASIBLE): + for idx, var in enumerate(marks): + print(f'mark[{idx}]: {solver.Value(var)}') + intervals = [solver.Value(diff) for diff in diffs] + intervals.sort() + print(f'intervals: {intervals}') + + print('Statistics:') + print(f'- conflicts: {solver.NumConflicts()}') + print(f'- branches : {solver.NumBranches()}') + print(f'- wall time: {solver.WallTime()}s\n') + + +def main(_): + solve_golomb_ruler(FLAGS.order, FLAGS.params) + + +if __name__ == '__main__': + app.run(main) diff --git a/examples/python/knapsack_2d_sat.py b/examples/python/knapsack_2d_sat.py old mode 100644 new mode 100755 index 304931d1fb..90c1028edc --- a/examples/python/knapsack_2d_sat.py +++ b/examples/python/knapsack_2d_sat.py @@ -18,14 +18,12 @@ https://yetanothermathprogrammingconsultant.blogspot.com/2021/10/2d-knapsack-pro """ import io - from absl import app from absl import flags import numpy as np import pandas as pd from google.protobuf import text_format - from ortools.sat.python import cp_model FLAGS = flags.FLAGS @@ -360,16 +358,20 @@ def solve_with_rotations(data, max_height, max_width): print(data) -def main(_): +def solve_knapsack(model): """Solve the problem with all models.""" data, max_height, max_width = build_data() - if FLAGS.model == 'duplicate': + if model == 'duplicate': solve_with_duplicate_items(data, max_height, max_width) - elif FLAGS.model == 'optional': + elif model == 'optional': solve_with_duplicate_optional_items(data, max_height, max_width) else: solve_with_rotations(data, max_height, max_width) +def main(_): + solve_knapsack(FLAGS.model) + + if __name__ == '__main__': app.run(main) diff --git a/examples/python/magic_sequence_distribute.py b/examples/python/magic_sequence_distribute.py old mode 100644 new mode 100755 diff --git a/examples/python/maze_escape_sat.py b/examples/python/maze_escape_sat.py old mode 100644 new mode 100755 diff --git a/examples/python/no_wait_baking_scheduling_sat.py b/examples/python/no_wait_baking_scheduling_sat.py old mode 100644 new mode 100755 diff --git a/examples/python/rcpsp_sat.py b/examples/python/rcpsp_sat.py old mode 100644 new mode 100755 index 9f059d35f2..1ff493a943 --- a/examples/python/rcpsp_sat.py +++ b/examples/python/rcpsp_sat.py @@ -22,17 +22,12 @@ from ortools.sat.python import cp_model from ortools.scheduling import pywraprcpsp FLAGS = flags.FLAGS - flags.DEFINE_string('input', '', 'Input file to parse and solve.') -flags.DEFINE_string('output_proto', '', - 'Output file to write the cp_model proto to.') +flags.DEFINE_string('output_proto', '', 'Output file to write the cp_model proto to.') flags.DEFINE_string('params', '', 'Sat solver parameters.') -flags.DEFINE_bool('use_interval_makespan', True, - 'Whether we encode the makespan using an interval or not.') +flags.DEFINE_bool('use_interval_makespan', True, 'Whether we encode the makespan using an interval or not.') flags.DEFINE_integer('horizon', -1, 'Force horizon.') -flags.DEFINE_bool( - 'use_main_interval_for_tasks', True, - 'Creates a main interval for each task, and use it in precedences') +flags.DEFINE_bool('use_main_interval_for_tasks', True, 'Creates a main interval for each task, and use it in precedences') def PrintProblemStatistics(problem): diff --git a/examples/python/shift_scheduling_sat.py b/examples/python/shift_scheduling_sat.py index cfd69a9a4d..e7d2972bcb 100755 --- a/examples/python/shift_scheduling_sat.py +++ b/examples/python/shift_scheduling_sat.py @@ -16,11 +16,10 @@ from absl import app from absl import flags -from ortools.sat.python import cp_model from google.protobuf import text_format +from ortools.sat.python import cp_model FLAGS = flags.FLAGS - flags.DEFINE_string('output_proto', '', 'Output file to write the cp_model proto to.') flags.DEFINE_string('params', 'max_time_in_seconds:10.0', diff --git a/examples/python/steel_mill_slab_sat.py b/examples/python/steel_mill_slab_sat.py old mode 100644 new mode 100755 index 3646aba573..282c82a293 --- a/examples/python/steel_mill_slab_sat.py +++ b/examples/python/steel_mill_slab_sat.py @@ -27,7 +27,7 @@ from ortools.sat.python import cp_model FLAGS = flags.FLAGS flags.DEFINE_integer('problem', 2, 'Problem id to solve.') -flags.DEFINE_boolean('break_symmetries', True, +flags.DEFINE_bool('break_symmetries', True, 'Break symmetries between equivalent orders.') flags.DEFINE_string( 'solver', 'mip_column', 'Method used to solve: sat, sat_table, sat_column, '