cleanup examples/python

This commit is contained in:
Laurent Perron
2023-03-03 18:55:16 +04:00
parent c957fd9798
commit 1d061ed19e
5 changed files with 51 additions and 111 deletions

View File

@@ -15,7 +15,7 @@
load(":code_samples.bzl", "code_sample_compile_py", "code_sample_py")
# code_sample_py("arc_flow_cutting_stock_sat") # using pywraplp
code_sample_py("arc_flow_cutting_stock_sat")
code_sample_py("assignment_with_constraints_sat")
@@ -65,7 +65,7 @@ code_sample_py("single_machine_scheduling_with_setup_release_due_dates_sat")
code_sample_py("spread_robots_sat")
# code_sample_py("steel_mill_slab_sat") # using pywraplp
code_sample_py("steel_mill_slab_sat")
code_sample_py("sudoku_sat")

View File

@@ -13,21 +13,27 @@
"""Cutting stock problem with the objective to minimize wasted space."""
import argparse
import collections
import time
import numpy as np
from ortools.linear_solver import pywraplp
from absl import app
from absl import flags
from google.protobuf import text_format
from ortools.linear_solver.python import model_builder as mb
from ortools.sat.python import cp_model
PARSER = argparse.ArgumentParser()
FLAGS = flags.FLAGS
_OUTPUT_PROTO = flags.DEFINE_string(
'output_proto', '', 'Output file to write the cp_model proto to.')
_PARAMS = flags.DEFINE_string(
'params',
'num_search_workers:8,log_search_progress:true,max_time_in_seconds:10',
'Sat solver parameters.')
_SOLVER = flags.DEFINE_string(
'solver', 'sat', 'Method used to solve: sat, mip.')
PARSER.add_argument(
'--solver', default='sat', help='Method used to solve: sat, mip.')
PARSER.add_argument(
'--output_proto_file',
default='',
help='Output file to write the cp_model proto to.')
DESIRED_LENGTHS = [
2490, 3980, 2490, 3980, 2391, 2391, 2391, 596, 596, 596, 2456, 2456, 3018,
@@ -105,7 +111,7 @@ def create_state_graph(items, max_capacity):
return states, transitions
def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file):
def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file: str, params: str):
"""Solve the cutting stock with arc-flow and the CP-SAT solver."""
items = regroup_and_count(DESIRED_LENGTHS)
print('Items:', items)
@@ -173,16 +179,14 @@ def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file):
# Output model proto to file.
if output_proto_file:
output_file = open(output_proto_file, 'w')
output_file.write(str(model.Proto()))
output_file.close()
model.ExportToFile(output_proto_file)
# Solve model.
solver = cp_model.CpSolver()
if params:
text_format.Parse(params, solver.parameters)
solver.parameters.log_search_progress = True
solver.parameters.num_search_workers = 8
status = solver.Solve(model)
print(solver.ResponseStats())
solver.Solve(model)
def solve_cutting_stock_with_arc_flow_and_mip():
@@ -203,9 +207,7 @@ def solve_cutting_stock_with_arc_flow_and_mip():
item_coeffs = collections.defaultdict(list)
start_time = time.time()
solver = pywraplp.Solver.CreateSolver('cbc')
if not solver:
return
model = mb.ModelBuilder()
objective_vars = []
objective_coeffs = []
@@ -213,7 +215,7 @@ def solve_cutting_stock_with_arc_flow_and_mip():
var_index = 0
for outgoing, incoming, item_index, card in transitions:
count = items[item_index][1]
count_var = solver.IntVar(
count_var = model.new_int_var(
0, count, 'a%i_i%i_f%i_t%i_c%i' % (var_index, item_index, incoming,
outgoing, card))
var_index += 1
@@ -225,7 +227,7 @@ def solve_cutting_stock_with_arc_flow_and_mip():
for state_index, state in enumerate(states):
if state_index == 0:
continue
exit_var = solver.IntVar(0, num_items, 'e%i' % state_index)
exit_var = model.new_int_var(0, num_items, 'e%i' % state_index)
outgoing_vars[state_index].append(exit_var)
incoming_sink_vars.append(exit_var)
price = price_usage(state, POSSIBLE_CAPACITIES)
@@ -234,42 +236,45 @@ def solve_cutting_stock_with_arc_flow_and_mip():
# Flow conservation
for state_index in range(1, len(states)):
solver.Add(
sum(incoming_vars[state_index]) == sum(outgoing_vars[state_index]))
model.add(
mb.LinearExpr.sum(incoming_vars[state_index]) == mb.LinearExpr.sum(
outgoing_vars[state_index]))
# Flow going out of the source must go in the sink
solver.Add(sum(outgoing_vars[0]) == sum(incoming_sink_vars))
model.add(
mb.LinearExpr.sum(outgoing_vars[0]) == mb.LinearExpr.sum(
incoming_sink_vars))
# Items must be placed
for item_index, size_and_count in enumerate(items):
num_arcs = len(item_vars[item_index])
solver.Add(
sum(item_vars[item_index][i] * item_coeffs[item_index][i]
for i in range(num_arcs)) == size_and_count[1])
model.add(
mb.LinearExpr.sum([item_vars[item_index][i] * item_coeffs[item_index][i]
for i in range(num_arcs)]) == size_and_count[1])
# Objective is the sum of waste
solver.Minimize(
sum(objective_vars[i] * objective_coeffs[i]
for i in range(len(objective_vars))))
solver.EnableOutput()
model.minimize(np.dot(objective_vars, objective_coeffs))
status = solver.Solve()
solver = mb.ModelSolver('scip')
solver.enable_output(True)
status = solver.solve(model)
### Output the solution.
if status == pywraplp.Solver.OPTIMAL:
if status == mb.SolveStatus.OPTIMAL or status == mb.SolveStatus.FEASIBLE:
print('Objective value = %f found in %.2f s' %
(solver.Objective().Value(), time.time() - start_time))
(solver.objective_value, time.time() - start_time))
else:
print('No solution')
def main(args):
def main(_):
"""Main function"""
if args.solver == 'sat':
solve_cutting_stock_with_arc_flow_and_sat(args.output_proto_file)
if _SOLVER.value == 'sat':
solve_cutting_stock_with_arc_flow_and_sat(_OUTPUT_PROTO.value,
_PARAMS.value)
else: # 'mip'
solve_cutting_stock_with_arc_flow_and_mip()
if __name__ == '__main__':
main(PARSER.parse_args())
app.run(main)

View File

@@ -16,6 +16,7 @@
load("@ortools_deps//:requirements.bzl", "requirement")
PYTHON_DEPS = [
"//ortools/linear_solver/python:model_builder",
"//ortools/sat/python:cp_model",
"//ortools/sat/colab:visualization",
requirement("absl-py"),
@@ -40,7 +41,7 @@ def code_sample_compile_py(name):
def code_sample_test_py(name):
native.py_test(
name = name + "_py_test",
size = "small",
size = "medium",
srcs = [name + ".py"],
main = name + ".py",
data = [

View File

@@ -506,8 +506,7 @@ def SolveRcpsp(problem,
# Write model to file.
if proto_file:
print(f'Writing proto to{proto_file}')
with open(proto_file, 'w') as text_file:
text_file.write(str(model))
model.ExportToFile(proto_file)
# Solve model.
solver = cp_model.CpSolver()

View File

@@ -20,15 +20,13 @@ import time
from absl import app
from absl import flags
from ortools.linear_solver import pywraplp
from ortools.sat.python import cp_model
_PROBLEM = flags.DEFINE_integer('problem', 2, 'Problem id to solve.')
_BREAK_SYMMETRIES = flags.DEFINE_boolean(
'break_symmetries', True, 'Break symmetries between equivalent orders.')
_SOLVER = flags.DEFINE_string(
'solver', 'mip_column', 'Method used to solve: sat, sat_table, sat_column, '
'mip_column.')
'solver', 'sat_column', 'Method used to solve: sat, sat_table, sat_column.')
def build_problem(problem_id):
@@ -670,69 +668,6 @@ def steel_mill_slab_with_column_generation(problem):
print('No solution')
def steel_mill_slab_with_mip_column_generation(problem):
"""Solves the Steel Mill Slab Problem."""
### Load problem.
(num_slabs, capacities, _, orders) = build_problem(problem)
num_orders = len(orders)
num_capacities = len(capacities)
all_orders = range(len(orders))
print('Solving steel mill with %i orders, %i slabs, and %i capacities' %
(num_orders, num_slabs, num_capacities - 1))
# Compute auxiliary data.
widths = [x[0] for x in orders]
colors = [x[1] for x in orders]
max_capacity = max(capacities)
loss_array = [
min(x for x in capacities if x >= c) - c for c in range(max_capacity +
1)
]
### Model problem.
# Generate all valid slabs (columns)
unsorted_valid_slabs = collect_valid_slabs_dp(capacities, colors, widths,
loss_array)
# Sort slab by descending load/loss. Remove duplicates.
valid_slabs = sorted(unsorted_valid_slabs,
key=lambda c: 1000 * c[-1] + c[-2])
all_valid_slabs = range(len(valid_slabs))
# create model and decision variables.
start_time = time.time()
solver = pywraplp.Solver('Steel',
pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING)
selected = [
solver.IntVar(0.0, 1.0, 'selected_%i' % i) for i in all_valid_slabs
]
for order in all_orders:
solver.Add(
sum(selected[i]
for i in all_valid_slabs
if valid_slabs[i][order]) == 1)
# Redundant constraint (sum of loads == sum of widths).
solver.Add(
sum(selected[i] * valid_slabs[i][-1]
for i in all_valid_slabs) == sum(widths))
# Objective.
solver.Minimize(
sum(selected[i] * valid_slabs[i][-2] for i in all_valid_slabs))
status = solver.Solve()
### Output the solution.
if status == pywraplp.Solver.OPTIMAL:
print('Objective value = %f found in %.2f s' %
(solver.Objective().Value(), time.time() - start_time))
else:
print('No solution')
def main(_):
if _SOLVER.value == 'sat':
steel_mill_slab(_PROBLEM.value, _BREAK_SYMMETRIES.value)
@@ -741,8 +676,8 @@ def main(_):
_BREAK_SYMMETRIES.value)
elif _SOLVER.value == 'sat_column':
steel_mill_slab_with_column_generation(_PROBLEM.value)
else: # 'mip_column'
steel_mill_slab_with_mip_column_generation(_PROBLEM.value)
else:
print(f'Unknown model {_SOLVER.value}')
if __name__ == '__main__':