cleanup examples/python
This commit is contained in:
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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__':
|
||||
|
||||
Reference in New Issue
Block a user