|
83 | 83 | "metadata": {}, |
84 | 84 | "outputs": [], |
85 | 85 | "source": [ |
86 | | - "import argparse\n", |
87 | 86 | "import collections\n", |
88 | 87 | "import time\n", |
| 88 | + "import numpy as np\n", |
89 | 89 | "\n", |
90 | | - "from ortools.linear_solver import pywraplp\n", |
| 90 | + "from google.protobuf import text_format\n", |
| 91 | + "from ortools.linear_solver.python import model_builder as mb\n", |
91 | 92 | "from ortools.sat.python import cp_model\n", |
92 | 93 | "\n", |
93 | | - "PARSER = argparse.ArgumentParser()\n", |
| 94 | + "class FLAGS: pass\n", |
| 95 | + "\n", |
| 96 | + "_OUTPUT_PROTO = flags.DEFINE_string(\n", |
| 97 | + " 'output_proto', '', 'Output file to write the cp_model proto to.')\n", |
| 98 | + "_PARAMS = flags.DEFINE_string(\n", |
| 99 | + " 'params',\n", |
| 100 | + " 'num_search_workers:8,log_search_progress:true,max_time_in_seconds:10',\n", |
| 101 | + " 'Sat solver parameters.')\n", |
| 102 | + "_SOLVER = flags.DEFINE_string(\n", |
| 103 | + " 'solver', 'sat', 'Method used to solve: sat, mip.')\n", |
94 | 104 | "\n", |
95 | | - "PARSER.add_argument(\n", |
96 | | - " '--solver', default='sat', help='Method used to solve: sat, mip.')\n", |
97 | | - "PARSER.add_argument(\n", |
98 | | - " '--output_proto_file',\n", |
99 | | - " default='',\n", |
100 | | - " help='Output file to write the cp_model proto to.')\n", |
101 | 105 | "\n", |
102 | 106 | "DESIRED_LENGTHS = [\n", |
103 | 107 | " 2490, 3980, 2490, 3980, 2391, 2391, 2391, 596, 596, 596, 2456, 2456, 3018,\n", |
|
175 | 179 | " return states, transitions\n", |
176 | 180 | "\n", |
177 | 181 | "\n", |
178 | | - "def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file):\n", |
| 182 | + "def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file: str, params: str):\n", |
179 | 183 | " \"\"\"Solve the cutting stock with arc-flow and the CP-SAT solver.\"\"\"\n", |
180 | 184 | " items = regroup_and_count(DESIRED_LENGTHS)\n", |
181 | 185 | " print('Items:', items)\n", |
|
243 | 247 | "\n", |
244 | 248 | " # Output model proto to file.\n", |
245 | 249 | " if output_proto_file:\n", |
246 | | - " output_file = open(output_proto_file, 'w')\n", |
247 | | - " output_file.write(str(model.Proto()))\n", |
248 | | - " output_file.close()\n", |
| 250 | + " model.ExportToFile(output_proto_file)\n", |
249 | 251 | "\n", |
250 | 252 | " # Solve model.\n", |
251 | 253 | " solver = cp_model.CpSolver()\n", |
| 254 | + " if params:\n", |
| 255 | + " text_format.Parse(params, solver.parameters)\n", |
252 | 256 | " solver.parameters.log_search_progress = True\n", |
253 | | - " solver.parameters.num_search_workers = 8\n", |
254 | | - " status = solver.Solve(model)\n", |
255 | | - " print(solver.ResponseStats())\n", |
| 257 | + " solver.Solve(model)\n", |
256 | 258 | "\n", |
257 | 259 | "\n", |
258 | 260 | "def solve_cutting_stock_with_arc_flow_and_mip():\n", |
|
273 | 275 | " item_coeffs = collections.defaultdict(list)\n", |
274 | 276 | "\n", |
275 | 277 | " start_time = time.time()\n", |
276 | | - " solver = pywraplp.Solver.CreateSolver('cbc')\n", |
277 | | - " if not solver:\n", |
278 | | - " return\n", |
| 278 | + " model = mb.ModelBuilder()\n", |
279 | 279 | "\n", |
280 | 280 | " objective_vars = []\n", |
281 | 281 | " objective_coeffs = []\n", |
282 | 282 | "\n", |
283 | 283 | " var_index = 0\n", |
284 | 284 | " for outgoing, incoming, item_index, card in transitions:\n", |
285 | 285 | " count = items[item_index][1]\n", |
286 | | - " count_var = solver.IntVar(\n", |
| 286 | + " count_var = model.new_int_var(\n", |
287 | 287 | " 0, count, 'a%i_i%i_f%i_t%i_c%i' % (var_index, item_index, incoming,\n", |
288 | 288 | " outgoing, card))\n", |
289 | 289 | " var_index += 1\n", |
|
295 | 295 | " for state_index, state in enumerate(states):\n", |
296 | 296 | " if state_index == 0:\n", |
297 | 297 | " continue\n", |
298 | | - " exit_var = solver.IntVar(0, num_items, 'e%i' % state_index)\n", |
| 298 | + " exit_var = model.new_int_var(0, num_items, 'e%i' % state_index)\n", |
299 | 299 | " outgoing_vars[state_index].append(exit_var)\n", |
300 | 300 | " incoming_sink_vars.append(exit_var)\n", |
301 | 301 | " price = price_usage(state, POSSIBLE_CAPACITIES)\n", |
|
304 | 304 | "\n", |
305 | 305 | " # Flow conservation\n", |
306 | 306 | " for state_index in range(1, len(states)):\n", |
307 | | - " solver.Add(\n", |
308 | | - " sum(incoming_vars[state_index]) == sum(outgoing_vars[state_index]))\n", |
| 307 | + " model.add(\n", |
| 308 | + " mb.LinearExpr.sum(incoming_vars[state_index]) == mb.LinearExpr.sum(\n", |
| 309 | + " outgoing_vars[state_index]))\n", |
309 | 310 | "\n", |
310 | 311 | " # Flow going out of the source must go in the sink\n", |
311 | | - " solver.Add(sum(outgoing_vars[0]) == sum(incoming_sink_vars))\n", |
| 312 | + " model.add(\n", |
| 313 | + " mb.LinearExpr.sum(outgoing_vars[0]) == mb.LinearExpr.sum(\n", |
| 314 | + " incoming_sink_vars))\n", |
312 | 315 | "\n", |
313 | 316 | " # Items must be placed\n", |
314 | 317 | " for item_index, size_and_count in enumerate(items):\n", |
315 | 318 | " num_arcs = len(item_vars[item_index])\n", |
316 | | - " solver.Add(\n", |
317 | | - " sum(item_vars[item_index][i] * item_coeffs[item_index][i]\n", |
318 | | - " for i in range(num_arcs)) == size_and_count[1])\n", |
| 319 | + " model.add(\n", |
| 320 | + " mb.LinearExpr.sum([item_vars[item_index][i] * item_coeffs[item_index][i]\n", |
| 321 | + " for i in range(num_arcs)]) == size_and_count[1])\n", |
319 | 322 | "\n", |
320 | 323 | " # Objective is the sum of waste\n", |
321 | | - " solver.Minimize(\n", |
322 | | - " sum(objective_vars[i] * objective_coeffs[i]\n", |
323 | | - " for i in range(len(objective_vars))))\n", |
324 | | - " solver.EnableOutput()\n", |
| 324 | + " model.minimize(np.dot(objective_vars, objective_coeffs))\n", |
325 | 325 | "\n", |
326 | | - " status = solver.Solve()\n", |
| 326 | + " solver = mb.ModelSolver('scip')\n", |
| 327 | + " solver.enable_output(True)\n", |
| 328 | + " status = solver.solve(model)\n", |
327 | 329 | "\n", |
328 | 330 | " ### Output the solution.\n", |
329 | | - " if status == pywraplp.Solver.OPTIMAL:\n", |
| 331 | + " if status == mb.SolveStatus.OPTIMAL or status == mb.SolveStatus.FEASIBLE:\n", |
330 | 332 | " print('Objective value = %f found in %.2f s' %\n", |
331 | | - " (solver.Objective().Value(), time.time() - start_time))\n", |
| 333 | + " (solver.objective_value, time.time() - start_time))\n", |
332 | 334 | " else:\n", |
333 | 335 | " print('No solution')\n", |
334 | 336 | "\n", |
335 | 337 | "\n", |
336 | | - "def main(args):\n", |
| 338 | + "def main(_):\n", |
337 | 339 | " \"\"\"Main function\"\"\"\n", |
338 | | - " if args.solver == 'sat':\n", |
339 | | - " solve_cutting_stock_with_arc_flow_and_sat(args.output_proto_file)\n", |
| 340 | + " if _SOLVER.value == 'sat':\n", |
| 341 | + " solve_cutting_stock_with_arc_flow_and_sat(_OUTPUT_PROTO.value,\n", |
| 342 | + " _PARAMS.value)\n", |
340 | 343 | " else: # 'mip'\n", |
341 | 344 | " solve_cutting_stock_with_arc_flow_and_mip()\n", |
342 | 345 | "\n", |
343 | 346 | "\n", |
344 | | - "main(PARSER.parse_args())\n", |
| 347 | + "main()\n", |
345 | 348 | "\n" |
346 | 349 | ] |
347 | 350 | } |
|
0 commit comments