python: Regenerate all notebooks
This commit is contained in:
@@ -74,7 +74,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#!/usr/bin/env python\n",
|
||||
"#!/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",
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#!/usr/bin/env python\n",
|
||||
"#!/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",
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#!/usr/bin/env python\n",
|
||||
"#!/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",
|
||||
|
||||
@@ -180,15 +180,14 @@
|
||||
"\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",
|
||||
"manager = pywrapcp.RoutingIndexManager(len(data['time_matrix']),\n",
|
||||
" data['num_vehicles'], data['depot'])\n",
|
||||
"# [END index_manager]\n",
|
||||
"\n",
|
||||
"# Create Routing Model.\n",
|
||||
"# [START routing_model]\n",
|
||||
"routing = pywrapcp.RoutingModel(manager)\n",
|
||||
"\n",
|
||||
"# [END routing_model]\n",
|
||||
"\n",
|
||||
"# Create and register a transit callback.\n",
|
||||
|
||||
@@ -110,28 +110,28 @@
|
||||
" 468, 776, 662\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480,\n",
|
||||
" 674, 1016, 868, 1210\n",
|
||||
" 548, 0, 684, 308, 194, 502, 730, 354, 696, 742, 1084, 594, 480, 674,\n",
|
||||
" 1016, 868, 1210\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 776, 684, 0, 992, 878, 502, 274, 810, 468, 742, 400, 1278, 1164,\n",
|
||||
" 1130, 788, 1552, 754\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628,\n",
|
||||
" 822, 1164, 560, 1358\n",
|
||||
" 696, 308, 992, 0, 114, 650, 878, 502, 844, 890, 1232, 514, 628, 822,\n",
|
||||
" 1164, 560, 1358\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514,\n",
|
||||
" 708, 1050, 674, 1244\n",
|
||||
" 582, 194, 878, 114, 0, 536, 764, 388, 730, 776, 1118, 400, 514, 708,\n",
|
||||
" 1050, 674, 1244\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 274, 502, 502, 650, 536, 0, 228, 308, 194, 240, 582, 776, 662, 628,\n",
|
||||
" 514, 1050, 708\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890,\n",
|
||||
" 856, 514, 1278, 480\n",
|
||||
" 502, 730, 274, 878, 764, 228, 0, 536, 194, 468, 354, 1004, 890, 856,\n",
|
||||
" 514, 1278, 480\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 194, 354, 810, 502, 388, 308, 536, 0, 342, 388, 730, 468, 354, 320,\n",
|
||||
@@ -154,12 +154,12 @@
|
||||
" 308, 650, 274, 844\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0,\n",
|
||||
" 194, 536, 388, 730\n",
|
||||
" 388, 480, 1164, 628, 514, 662, 890, 354, 696, 422, 764, 114, 0, 194,\n",
|
||||
" 536, 388, 730\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194,\n",
|
||||
" 0, 342, 422, 536\n",
|
||||
" 354, 674, 1130, 822, 708, 628, 856, 320, 662, 388, 730, 308, 194, 0,\n",
|
||||
" 342, 422, 536\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" 468, 1016, 788, 1164, 1050, 514, 514, 662, 320, 274, 388, 650, 536,\n",
|
||||
@@ -197,6 +197,7 @@
|
||||
" data['num_vehicles'] = 4\n",
|
||||
" data['depot'] = 0\n",
|
||||
" return data\n",
|
||||
"\n",
|
||||
"# [END data_model]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -234,6 +235,7 @@
|
||||
" 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",
|
||||
"\n",
|
||||
"# [END solution_printer]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -245,15 +247,14 @@
|
||||
"\n",
|
||||
"# Create the routing index manager.\n",
|
||||
"# [START index_manager]\n",
|
||||
"manager = pywrapcp.RoutingIndexManager(\n",
|
||||
" len(data['distance_matrix']),\n",
|
||||
" data['num_vehicles'],\n",
|
||||
" data['depot'])\n",
|
||||
"manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),\n",
|
||||
" data['num_vehicles'], data['depot'])\n",
|
||||
"# [END index_manager]\n",
|
||||
"\n",
|
||||
"# Create Routing Model.\n",
|
||||
"# [START routing_model]\n",
|
||||
"routing = pywrapcp.RoutingModel(manager)\n",
|
||||
"\n",
|
||||
"# [END routing_model]\n",
|
||||
"\n",
|
||||
"# Create and register a transit callback.\n",
|
||||
@@ -308,7 +309,6 @@
|
||||
"dim_two = routing.GetDimensionOrDie('Two')\n",
|
||||
"\n",
|
||||
"# force depot Slack to be value since we don't have any predecessor...\n",
|
||||
"# Slack(Depot) = value(Depot)\n",
|
||||
"for v in range(manager.GetNumberOfVehicles()):\n",
|
||||
" start = routing.Start(v)\n",
|
||||
" dim_one.SlackVar(start).SetValue(data['value'][0])\n",
|
||||
|
||||
@@ -1965,18 +1965,18 @@
|
||||
" model.Add(working_times[d] >= min_working_time)\n",
|
||||
"\n",
|
||||
" # Create circuit constraint.\n",
|
||||
" model.Add(sum(outgoing_source_literals) == 1)\n",
|
||||
" model.AddExactlyOne(outgoing_source_literals)\n",
|
||||
" for s in range(num_shifts):\n",
|
||||
" model.Add(sum(outgoing_literals[s]) == 1)\n",
|
||||
" model.Add(sum(incoming_literals[s]) == 1)\n",
|
||||
" model.Add(sum(incoming_sink_literals) == 1)\n",
|
||||
" model.AddExactlyOne(outgoing_literals[s])\n",
|
||||
" model.AddExactlyOne(incoming_literals[s])\n",
|
||||
" model.AddExactlyOne(incoming_sink_literals)\n",
|
||||
"\n",
|
||||
" # Each shift is covered.\n",
|
||||
" for s in range(num_shifts):\n",
|
||||
" model.Add(sum(performed[d, s] for d in range(num_drivers)) == 1)\n",
|
||||
" model.AddExactlyOne(performed[d, s] for d in range(num_drivers))\n",
|
||||
" # Globally, each node has one incoming and one outgoing literal\n",
|
||||
" model.Add(sum(shared_incoming_literals[s]) == 1)\n",
|
||||
" model.Add(sum(shared_outgoing_literals[s]) == 1)\n",
|
||||
" model.AddExactlyOne(shared_incoming_literals[s])\n",
|
||||
" model.AddExactlyOne(shared_outgoing_literals[s])\n",
|
||||
"\n",
|
||||
" # Symmetry breaking\n",
|
||||
"\n",
|
||||
@@ -1998,7 +1998,7 @@
|
||||
" model.Add(\n",
|
||||
" cp_model.LinearExpr.Sum(working_times) == total_driving_time +\n",
|
||||
" num_drivers * (setup_time + cleanup_time) +\n",
|
||||
" cp_model.LinearExpr.ScalProd(delay_literals, delay_weights))\n",
|
||||
" cp_model.LinearExpr.WeightedSum(delay_literals, delay_weights))\n",
|
||||
"\n",
|
||||
" if minimize_drivers:\n",
|
||||
" # Minimize the number of working drivers\n",
|
||||
@@ -2007,7 +2007,7 @@
|
||||
" # Minimize the sum of delays between tasks, which in turns minimize the\n",
|
||||
" # sum of working times as the total driving time is fixed\n",
|
||||
" model.Minimize(\n",
|
||||
" cp_model.LinearExpr.ScalProd(delay_literals, delay_weights))\n",
|
||||
" cp_model.LinearExpr.WeightedSum(delay_literals, delay_weights))\n",
|
||||
"\n",
|
||||
" if not minimize_drivers and FLAGS.output_proto:\n",
|
||||
" print('Writing proto to %s' % FLAGS.output_proto)\n",
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
" presences[(job_id, task_id, alt_id)] = l_presence\n",
|
||||
"\n",
|
||||
" # Select exactly one presence variable.\n",
|
||||
" model.Add(sum(l_presences) == 1)\n",
|
||||
" model.AddExactlyOne(l_presences)\n",
|
||||
" else:\n",
|
||||
" intervals_per_resources[task[0][1]].append(interval)\n",
|
||||
" presences[(job_id, task_id, 0)] = model.NewConstant(1)\n",
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
" model.AddNoOverlap2D(x_intervals, y_intervals)\n",
|
||||
"\n",
|
||||
" ## Objective.\n",
|
||||
" model.Maximize(cp_model.DoubleLinearExpr.ScalProd(is_used, item_values))\n",
|
||||
" model.Maximize(cp_model.LinearExpr.WeightedSum(is_used, item_values))\n",
|
||||
"\n",
|
||||
" # Output proto to file.\n",
|
||||
" if FLAGS.output_proto:\n",
|
||||
@@ -293,7 +293,7 @@
|
||||
" model.AddNoOverlap2D(x_intervals, y_intervals)\n",
|
||||
"\n",
|
||||
" ## Objective.\n",
|
||||
" model.Maximize(cp_model.DoubleLinearExpr.ScalProd(is_used, item_values))\n",
|
||||
" model.Maximize(cp_model.LinearExpr.WeightedSum(is_used, item_values))\n",
|
||||
"\n",
|
||||
" # Output proto to file.\n",
|
||||
" if FLAGS.output_proto:\n",
|
||||
@@ -388,7 +388,7 @@
|
||||
" rotated = model.NewBoolVar(f'rotated_{i}')\n",
|
||||
"\n",
|
||||
" ### Exactly one state must be chosen.\n",
|
||||
" model.Add(not_selected + no_rotation + rotated == 1)\n",
|
||||
" model.AddExactlyOne(not_selected, no_rotation, rotated)\n",
|
||||
"\n",
|
||||
" ### Define height and width according to the state.\n",
|
||||
" dim1 = item_widths[i]\n",
|
||||
@@ -406,7 +406,7 @@
|
||||
" model.AddNoOverlap2D(x_intervals, y_intervals)\n",
|
||||
"\n",
|
||||
" # Objective.\n",
|
||||
" model.Maximize(cp_model.DoubleLinearExpr.ScalProd(is_used, item_values))\n",
|
||||
" model.Maximize(cp_model.LinearExpr.WeightedSum(is_used, item_values))\n",
|
||||
"\n",
|
||||
" # Output proto to file.\n",
|
||||
" if FLAGS.output_proto:\n",
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
" sum_of_vars = sum([x1, x2, x3])\n",
|
||||
" c2 = solver.Add(sum_of_vars <= 100.0, 'OtherConstraintName')\n",
|
||||
"\n",
|
||||
" SolveAndPrint(solver, [x1, x2, x3], [c0, c1, c2])\n",
|
||||
" SolveAndPrint(solver, [x1, x2, x3], [c0, c1, c2], optimization_problem_type != 'PDLP')\n",
|
||||
" # Print a linear expression's solution value.\n",
|
||||
" print('Sum of vars: %s = %s' % (sum_of_vars, sum_of_vars.solution_value()))\n",
|
||||
"\n",
|
||||
@@ -162,10 +162,11 @@
|
||||
" c2.SetCoefficient(x2, 2)\n",
|
||||
" c2.SetCoefficient(x3, 6)\n",
|
||||
"\n",
|
||||
" SolveAndPrint(solver, [x1, x2, x3], [c0, c1, c2])\n",
|
||||
" SolveAndPrint(solver, [x1, x2, x3], [c0, c1, c2],\n",
|
||||
" optimization_problem_type != 'PDLP')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def SolveAndPrint(solver, variable_list, constraint_list):\n",
|
||||
"def SolveAndPrint(solver, variable_list, constraint_list, is_precise):\n",
|
||||
" \"\"\"Solve the problem and print the solution.\"\"\"\n",
|
||||
" print('Number of variables = %d' % solver.NumVariables())\n",
|
||||
" print('Number of constraints = %d' % solver.NumConstraints())\n",
|
||||
@@ -177,7 +178,8 @@
|
||||
"\n",
|
||||
" # The solution looks legit (when using solvers others than\n",
|
||||
" # GLOP_LINEAR_PROGRAMMING, verifying the solution is highly recommended!).\n",
|
||||
" assert solver.VerifySolution(1e-7, True)\n",
|
||||
" if is_precise:\n",
|
||||
" assert solver.VerifySolution(1e-7, True)\n",
|
||||
"\n",
|
||||
" print('Problem solved in %f milliseconds' % solver.wall_time())\n",
|
||||
"\n",
|
||||
@@ -203,10 +205,12 @@
|
||||
"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",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -626,7 +626,7 @@
|
||||
" for i in range(num_vars - 1):\n",
|
||||
" x_i = variables[i]\n",
|
||||
" for j in range(i + 1, num_vars):\n",
|
||||
" coeff = int((RAW_DATA[i][j] + RAW_DATA[j][i]) * 1000.0)\n",
|
||||
" coeff = RAW_DATA[i][j] + RAW_DATA[j][i]\n",
|
||||
" if coeff == 0.0:\n",
|
||||
" continue\n",
|
||||
" x_j = variables[j]\n",
|
||||
@@ -638,7 +638,7 @@
|
||||
" obj_coeffs.append(coeff)\n",
|
||||
"\n",
|
||||
" for i in all_vars:\n",
|
||||
" self_coeff = int((RAW_DATA[i][i] + RAW_DATA[i][-1]) * 1000.0)\n",
|
||||
" self_coeff = RAW_DATA[i][i] + RAW_DATA[i][-1]\n",
|
||||
" if self_coeff != 0.0:\n",
|
||||
" obj_vars.append(variables[i])\n",
|
||||
" obj_coeffs.append(self_coeff)\n",
|
||||
@@ -646,16 +646,12 @@
|
||||
"\n",
|
||||
" model.Minimize(\n",
|
||||
" sum(obj_vars[i] * obj_coeffs[i] for i in range(len(obj_vars))))\n",
|
||||
" # Patch the scaling factor of the objective.\n",
|
||||
" model.Proto().objective.scaling_factor = 1.0 / 1000.0\n",
|
||||
" print(model.ModelStats())\n",
|
||||
"\n",
|
||||
" ### Solve model.\n",
|
||||
" solver = cp_model.CpSolver()\n",
|
||||
" solver.parameters.num_search_workers = 8\n",
|
||||
" solver.parameters.num_search_workers = 16\n",
|
||||
" solver.parameters.log_search_progress = True\n",
|
||||
" solver.Solve(model)\n",
|
||||
" print(solver.ResponseStats())\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
|
||||
@@ -215,7 +215,7 @@
|
||||
" ]\n",
|
||||
"\n",
|
||||
" # Exactly one recipe must be performed.\n",
|
||||
" model.Add(cp_model.LinearExpr.Sum(literals) == 1)\n",
|
||||
" model.AddExactlyOne(literals)\n",
|
||||
"\n",
|
||||
" else:\n",
|
||||
" literals = [1]\n",
|
||||
@@ -300,7 +300,7 @@
|
||||
" m2]\n",
|
||||
" s2 = task_starts[next_id]\n",
|
||||
" p2 = task_to_presence_literals[next_id][m2]\n",
|
||||
" model.Add(s1 + delay <= s2).OnlyEnforceIf([p1, p2])\n",
|
||||
" model.Add(s1 + delay <= s2).OnlyEnforceIf(p1, p2)\n",
|
||||
" else:\n",
|
||||
" # Normal dependencies (task ends before the start of successors).\n",
|
||||
" for t in all_active_tasks:\n",
|
||||
|
||||
@@ -291,11 +291,11 @@
|
||||
" # Request: (employee, shift, day, weight)\n",
|
||||
" # A negative weight indicates that the employee desire this assignment.\n",
|
||||
" requests = [\n",
|
||||
" # Employee 3 wants the first Saturday off.\n",
|
||||
" # Employee 3 does not want to work on the first Saturday (negative weight for the Off shift).\n",
|
||||
" (3, 0, 5, -2),\n",
|
||||
" # Employee 5 wants a night shift on the second Thursday.\n",
|
||||
" # Employee 5 wants a night shift on the second Thursday (negative weight).\n",
|
||||
" (5, 3, 10, -2),\n",
|
||||
" # Employee 2 does not want a night shift on the first Friday.\n",
|
||||
" # Employee 2 does not want a night shift on the first Friday (positive weight).\n",
|
||||
" (2, 3, 4, 4)\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
@@ -364,7 +364,7 @@
|
||||
" # Exactly one shift per day.\n",
|
||||
" for e in range(num_employees):\n",
|
||||
" for d in range(num_days):\n",
|
||||
" model.Add(sum(work[e, s, d] for s in range(num_shifts)) == 1)\n",
|
||||
" model.AddExactlyOne(work[e, s, d] for s in range(num_shifts))\n",
|
||||
"\n",
|
||||
" # Fixed assignments.\n",
|
||||
" for e, s, d in fixed_assignments:\n",
|
||||
|
||||
@@ -416,7 +416,7 @@
|
||||
"\n",
|
||||
" # Orders are assigned to one slab.\n",
|
||||
" for o in all_orders:\n",
|
||||
" model.Add(sum(assign[o]) == 1)\n",
|
||||
" model.AddExactlyOne(assign[o])\n",
|
||||
"\n",
|
||||
" # Redundant constraint (sum of loads == sum of widths).\n",
|
||||
" model.Add(sum(loads) == sum(widths))\n",
|
||||
@@ -599,7 +599,7 @@
|
||||
"\n",
|
||||
" # Orders are assigned to one slab.\n",
|
||||
" for o in all_orders:\n",
|
||||
" model.Add(sum(assign[o]) == 1)\n",
|
||||
" model.AddExactlyOne(assign[o])\n",
|
||||
"\n",
|
||||
" # Redundant constraint (sum of loads == sum of widths).\n",
|
||||
" model.Add(sum(loads) == sum(widths))\n",
|
||||
|
||||
@@ -115,11 +115,11 @@
|
||||
"\n",
|
||||
" # AllDifferent on rows.\n",
|
||||
" for i in line:\n",
|
||||
" model.AddAllDifferent([grid[(i, j)] for j in line])\n",
|
||||
" model.AddAllDifferent(grid[(i, j)] for j in line)\n",
|
||||
"\n",
|
||||
" # AllDifferent on columns.\n",
|
||||
" for j in line:\n",
|
||||
" model.AddAllDifferent([grid[(i, j)] for i in line])\n",
|
||||
" model.AddAllDifferent(grid[(i, j)] for i in line)\n",
|
||||
"\n",
|
||||
" # AllDifferent on cells.\n",
|
||||
" for i in cell:\n",
|
||||
|
||||
@@ -149,13 +149,12 @@
|
||||
" lucky_strike = model.NewIntVar(1, 5, 'lucky strike')\n",
|
||||
" parliaments = model.NewIntVar(1, 5, 'parliaments')\n",
|
||||
"\n",
|
||||
" model.AddAllDifferent([red, green, yellow, blue, ivory])\n",
|
||||
" model.AddAllDifferent(\n",
|
||||
" [englishman, spaniard, japanese, ukrainian, norwegian])\n",
|
||||
" model.AddAllDifferent([dog, snails, fox, zebra, horse])\n",
|
||||
" model.AddAllDifferent([tea, coffee, water, milk, fruit_juice])\n",
|
||||
" model.AddAllDifferent(\n",
|
||||
" [parliaments, kools, chesterfields, lucky_strike, old_gold])\n",
|
||||
" model.AddAllDifferent(red, green, yellow, blue, ivory)\n",
|
||||
" model.AddAllDifferent(englishman, spaniard, japanese, ukrainian, norwegian)\n",
|
||||
" model.AddAllDifferent(dog, snails, fox, zebra, horse)\n",
|
||||
" model.AddAllDifferent(tea, coffee, water, milk, fruit_juice)\n",
|
||||
" model.AddAllDifferent(parliaments, kools, chesterfields, lucky_strike,\n",
|
||||
" old_gold)\n",
|
||||
"\n",
|
||||
" model.Add(englishman == red)\n",
|
||||
" model.Add(spaniard == dog)\n",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"id": "basename",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# assignment_linear_assignment"
|
||||
"# assignment_linear_sum_assignment"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -41,10 +41,10 @@
|
||||
"source": [
|
||||
"<table align=\"left\">\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/master/examples/notebook/graph/assignment_linear_assignment.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/master/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
||||
"<a href=\"https://colab.research.google.com/github/google/or-tools/blob/master/examples/notebook/graph/assignment_linear_sum_assignment.ipynb\"><img src=\"https://raw.githubusercontent.com/google/or-tools/master/tools/colab_32px.png\"/>Run in Google Colab</a>\n",
|
||||
"</td>\n",
|
||||
"<td>\n",
|
||||
"<a href=\"https://github.com/google/or-tools/blob/master/ortools/graph/samples/assignment_linear_assignment.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/master/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
||||
"<a href=\"https://github.com/google/or-tools/blob/master/ortools/graph/samples/assignment_linear_sum_assignment.py\"><img src=\"https://raw.githubusercontent.com/google/or-tools/master/tools/github_32px.png\"/>View source on GitHub</a>\n",
|
||||
"</td>\n",
|
||||
"</table>"
|
||||
]
|
||||
@@ -110,6 +110,8 @@
|
||||
" [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",
|
||||
"\n",
|
||||
"# Allowed groups of workers:\n",
|
||||
@@ -137,93 +139,113 @@
|
||||
" [8, 10],\n",
|
||||
" [8, 11],\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"allowed_groups = []\n",
|
||||
"for workers_g1 in group1:\n",
|
||||
" for workers_g2 in group2:\n",
|
||||
" for workers_g3 in group3:\n",
|
||||
" allowed_groups.append(workers_g1 + workers_g2 + workers_g3)\n",
|
||||
"# [END allowed_groups]\n",
|
||||
"\n",
|
||||
"# [START solves]\n",
|
||||
"min_val = 1e6\n",
|
||||
"total_time = 0\n",
|
||||
"for group in allowed_groups:\n",
|
||||
" res = assignment(costs, group)\n",
|
||||
" status_tmp = res[0]\n",
|
||||
" solver_tmp = res[1]\n",
|
||||
" x_tmp = res[2]\n",
|
||||
" if status_tmp == pywraplp.Solver.OPTIMAL or status_tmp == pywraplp.Solver.FEASIBLE:\n",
|
||||
" if solver_tmp.Objective().Value() < min_val:\n",
|
||||
" min_val = solver_tmp.Objective().Value()\n",
|
||||
" min_group = group\n",
|
||||
" min_solver = solver_tmp\n",
|
||||
" min_x = x_tmp\n",
|
||||
" total_time += solver_tmp.WallTime()\n",
|
||||
"# [END solves]\n",
|
||||
"# Solver.\n",
|
||||
"# [START solver]\n",
|
||||
"# Create the mip solver with the SCIP backend.\n",
|
||||
"solver = pywraplp.Solver.CreateSolver('SCIP')\n",
|
||||
"# [END solver]\n",
|
||||
"\n",
|
||||
"# Print best solution.\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 min_val < 1e6:\n",
|
||||
" print(f'Total cost = {min_solver.Objective().Value()}\\n')\n",
|
||||
" num_tasks = len(costs[0])\n",
|
||||
" for worker in min_group:\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 min_x[worker, task].solution_value() > 0.5:\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",
|
||||
" f' Cost: {costs[worker][task]}')\n",
|
||||
"else:\n",
|
||||
" print('No solution found.')\n",
|
||||
"print(f'Time = {total_time} ms')\n",
|
||||
"# [END print_solution]\n",
|
||||
"\n",
|
||||
"def assignment(costs, group):\n",
|
||||
" \"\"\"Solve the assignment problem for one allowed group combinaison.\"\"\"\n",
|
||||
" num_tasks = len(costs[1])\n",
|
||||
" # Solver\n",
|
||||
" # [START solver]\n",
|
||||
" # Create the mip solver with the SCIP backend.\n",
|
||||
" solver = pywraplp.Solver.CreateSolver('SCIP')\n",
|
||||
" # [END solver]\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 group:\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 group:\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(solver.Sum([x[worker, task] for worker in group]) == 1)\n",
|
||||
" # [END constraints]\n",
|
||||
"\n",
|
||||
" # Objective\n",
|
||||
" # [START objective]\n",
|
||||
" objective_terms = []\n",
|
||||
" for worker in group:\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",
|
||||
" return [status, solver, x]\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -152,13 +152,15 @@
|
||||
"# Print solution.\n",
|
||||
"# [START print_solution]\n",
|
||||
"if status == pywraplp.Solver.OPTIMAL or status == pywraplp.Solver.FEASIBLE:\n",
|
||||
" print('Total cost = ', solver.Objective().Value(), '\\n')\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('Worker %d assigned to task %d. Cost = %d' %\n",
|
||||
" (i, j, costs[i][j]))\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",
|
||||
"\n"
|
||||
]
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
"x = {}\n",
|
||||
"for worker in range(num_workers):\n",
|
||||
" for task in range(num_tasks):\n",
|
||||
" x[worker, task] = solver.IntVar(0, 1, f'x[{worker},{task}]')\n",
|
||||
" x[worker, task] = solver.BoolVar(f'x[{worker},{task}]')\n",
|
||||
"# [END variables]\n",
|
||||
"\n",
|
||||
"# Constraints\n",
|
||||
@@ -170,7 +170,7 @@
|
||||
" 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",
|
||||
" f' Cost: {costs[worker][task]}')\n",
|
||||
"else:\n",
|
||||
" print('No solution found.')\n",
|
||||
"# [END print_solution]\n",
|
||||
|
||||
@@ -158,11 +158,11 @@
|
||||
"# [START constraints]\n",
|
||||
"# Each worker is assigned to at most one task.\n",
|
||||
"for worker in range(num_workers):\n",
|
||||
" model.Add(sum(x[worker, task] for task in range(num_tasks)) <= 1)\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.Add(sum(x[worker, task] for worker in range(num_workers)) == 1)\n",
|
||||
" model.AddExactlyOne(x[worker, task] for worker in range(num_workers))\n",
|
||||
"# [END constraints]\n",
|
||||
"\n",
|
||||
"# [START assignments]\n",
|
||||
|
||||
@@ -126,11 +126,11 @@
|
||||
"# [START constraints]\n",
|
||||
"# Each worker is assigned to at most one task.\n",
|
||||
"for i in range(num_workers):\n",
|
||||
" model.Add(sum(x[i][j] for j in range(num_tasks)) <= 1)\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.Add(sum(x[i][j] for i in range(num_workers)) == 1)\n",
|
||||
" model.AddExactlyOne(x[i][j] for i in range(num_workers))\n",
|
||||
"# [END constraints]\n",
|
||||
"\n",
|
||||
"# Objective\n",
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
"\n",
|
||||
"# Each task is assigned to exactly one worker.\n",
|
||||
"for task in range(num_tasks):\n",
|
||||
" model.Add(sum(x[worker, task] for worker in range(num_workers)) == 1)\n",
|
||||
" model.AddExactlyOne(x[worker, task] for worker in range(num_workers))\n",
|
||||
"# [END constraints]\n",
|
||||
"\n",
|
||||
"# Objective\n",
|
||||
|
||||
@@ -130,11 +130,11 @@
|
||||
"# [START constraints]\n",
|
||||
"# Each worker is assigned to at most one task.\n",
|
||||
"for worker in range(num_workers):\n",
|
||||
" model.Add(sum(x[worker, task] for task in range(num_tasks)) <= 1)\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.Add(sum(x[worker, task] for worker in range(num_workers)) == 1)\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",
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
" p = model.NewBoolVar('p')\n",
|
||||
"\n",
|
||||
" # x and y implies p, rewrite as not(x and y) or p\n",
|
||||
" model.AddBoolOr([x.Not(), y.Not(), p])\n",
|
||||
" model.AddBoolOr(x.Not(), y.Not(), p)\n",
|
||||
"\n",
|
||||
" # p implies x and y, expanded into two implication\n",
|
||||
" model.AddImplication(p, x)\n",
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
"# [START constraints]\n",
|
||||
"# Each item is assigned to at most one bin.\n",
|
||||
"for i in data['all_items']:\n",
|
||||
" model.Add(sum(x[i, b] for b in data['all_bins']) <= 1)\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",
|
||||
|
||||
@@ -151,8 +151,8 @@
|
||||
"# 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",
|
||||
"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",
|
||||
"\n",
|
||||
"# Solve the model.\n",
|
||||
|
||||
@@ -124,14 +124,14 @@
|
||||
"# [START exactly_one_nurse]\n",
|
||||
"for d in all_days:\n",
|
||||
" for s in all_shifts:\n",
|
||||
" model.Add(sum(shifts[(n, d, s)] for n in all_nurses) == 1)\n",
|
||||
" 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.Add(sum(shifts[(n, d, s)] for s in all_shifts) <= 1)\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",
|
||||
|
||||
@@ -144,12 +144,12 @@
|
||||
" a_overlaps_b = model.NewBoolVar('a_overlaps_b')\n",
|
||||
"\n",
|
||||
" # Option a: using only clauses\n",
|
||||
" model.AddBoolOr([a_after_b, b_after_a, a_overlaps_b])\n",
|
||||
" model.AddBoolOr(a_after_b, b_after_a, a_overlaps_b)\n",
|
||||
" model.AddImplication(a_after_b, a_overlaps_b.Not())\n",
|
||||
" model.AddImplication(b_after_a, a_overlaps_b.Not())\n",
|
||||
"\n",
|
||||
" # Option b: using a sum() == 1.\n",
|
||||
" # model.Add(a_after_b + b_after_a + a_overlaps_b == 1)\n",
|
||||
" # Option b: using an exactly one constraint.\n",
|
||||
" # model.AddExactlyOne(a_after_b, b_after_a, a_overlaps_b)\n",
|
||||
"\n",
|
||||
" # Search for start values in increasing order for the two intervals.\n",
|
||||
" model.AddDecisionStrategy([start_var_a, start_var_b], cp_model.CHOOSE_FIRST,\n",
|
||||
|
||||
@@ -101,15 +101,15 @@
|
||||
" b = model.NewBoolVar('b')\n",
|
||||
"\n",
|
||||
" # First version using a half-reified bool and.\n",
|
||||
" model.AddBoolAnd([x, y.Not()]).OnlyEnforceIf(b)\n",
|
||||
" model.AddBoolAnd(x, y.Not()).OnlyEnforceIf(b)\n",
|
||||
"\n",
|
||||
" # Second version using implications.\n",
|
||||
" model.AddImplication(b, x)\n",
|
||||
" model.AddImplication(b, y.Not())\n",
|
||||
"\n",
|
||||
" # Third version using bool or.\n",
|
||||
" model.AddBoolOr([b.Not(), x])\n",
|
||||
" model.AddBoolOr([b.Not(), y.Not()])\n",
|
||||
" model.AddBoolOr(b.Not(), x)\n",
|
||||
" model.AddBoolOr(b.Not(), y.Not())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"ReifiedSampleSat()\n",
|
||||
|
||||
@@ -137,14 +137,14 @@
|
||||
"# [START exactly_one_nurse]\n",
|
||||
"for d in all_days:\n",
|
||||
" for s in all_shifts:\n",
|
||||
" model.Add(sum(shifts[(n, d, s)] for n in all_nurses) == 1)\n",
|
||||
" 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.Add(sum(shifts[(n, d, s)] for s in all_shifts) <= 1)\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",
|
||||
|
||||
@@ -148,8 +148,8 @@
|
||||
" model.Add(x == 7).OnlyEnforceIf(b3)\n",
|
||||
" model.Add(expr == 3).OnlyEnforceIf(b3)\n",
|
||||
"\n",
|
||||
" # At least one bi is true. (we could use a sum == 1).\n",
|
||||
" model.AddBoolOr([b0, b2, b3])\n",
|
||||
" # At least one bi is true. (we could use an exactly one constraint).\n",
|
||||
" model.AddBoolOr(b0, b2, b3)\n",
|
||||
"\n",
|
||||
" # Search for x values in increasing order.\n",
|
||||
" model.AddDecisionStrategy([x], cp_model.CHOOSE_FIRST,\n",
|
||||
|
||||
Reference in New Issue
Block a user