From f0f65fee9ad4753f644ab74804fa681d7023dfbf Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Sun, 30 Dec 2018 18:12:26 +0100 Subject: [PATCH] small polish --- examples/python/steel_mill_slab_sat.py | 91 ++++++++++++++------------ 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/examples/python/steel_mill_slab_sat.py b/examples/python/steel_mill_slab_sat.py index 14a9d03792..041b0e7b1c 100644 --- a/examples/python/steel_mill_slab_sat.py +++ b/examples/python/steel_mill_slab_sat.py @@ -10,6 +10,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. +"""Solves the Stell Mill Slab problem with 4 different techniques.""" from __future__ import print_function import argparse @@ -291,22 +292,6 @@ class SteelMillSlabSolutionPrinter(cp_model.CpSolverSolutionCallback): print(line) -class SolutionPrinterWithObjective(cp_model.CpSolverSolutionCallback): - """Print intermediate solutions.""" - - def __init__(self): - cp_model.CpSolverSolutionCallback.__init__(self) - self.__solution_count = 0 - self.__start_time = time.time() - - def on_solution_callback(self): - current_time = time.time() - print('Solution %i, time = %f s, objective = %i' % - (self.__solution_count, current_time - self.__start_time, - self.ObjectiveValue())) - self.__solution_count += 1 - - def steel_mill_slab(problem, break_symmetries, output_proto): """Solves the Steel Mill Slab Problem.""" ### Load problem. @@ -347,12 +332,14 @@ def steel_mill_slab(problem, break_symmetries, output_proto): for s in all_slabs ] color_is_in_slab = [[ - model.NewBoolVar('color_%i_in_slab_%i' % (c + 1, s)) for c in all_colors + model.NewBoolVar('color_%i_in_slab_%i' % (c + 1, s)) + for c in all_colors ] for s in all_slabs] # Compute load of all slabs. for s in all_slabs: - model.Add(sum(assign[o][s] * widths[o] for o in all_orders) == loads[s]) + model.Add( + sum(assign[o][s] * widths[o] for o in all_orders) == loads[s]) # Orders are assigned to one slab. for o in all_orders: @@ -438,13 +425,14 @@ def steel_mill_slab(problem, break_symmetries, output_proto): ### Solve model. solver = cp_model.CpSolver() - status = solver.Solve(model) + solver.parameters.num_search_workers = 8 + objective_printer = cp_model.ObjectiveSolutionPrinter() + status = solver.SolveWithSolutionCallback(model, objective_printer) ### Output the solution. if status == cp_model.OPTIMAL: - print('Loss = %i, time = %f s, %i conflicts' % - (solver.ObjectiveValue(), solver.WallTime(), - solver.NumConflicts())) + print('Loss = %i, time = %f s, %i conflicts' % ( + solver.ObjectiveValue(), solver.WallTime(), solver.NumConflicts())) else: print('No solution') @@ -476,7 +464,9 @@ def collect_valid_slabs(capacities, colors, widths, loss_array, all_colors): assign = [model.NewBoolVar('assign_%i' % o) for o in all_orders] load = model.NewIntVar(0, max_capacity, 'load') - color_in_slab = [model.NewBoolVar('color_%i' % (c + 1)) for c in all_colors] + color_in_slab = [ + model.NewBoolVar('color_%i' % (c + 1)) for c in all_colors + ] # Compute load. model.Add(sum(assign[o] * widths[o] for o in all_orders) == load) @@ -496,12 +486,24 @@ def collect_valid_slabs(capacities, colors, widths, loss_array, all_colors): loss = model.NewIntVar(0, max(loss_array), 'loss') model.AddElement(load, loss_array, loss) + model.AddDecisionStrategy(assign, cp_model.CHOOSE_FIRST, + cp_model.SELECT_MAX_VALUE) + ### Solve model and collect columns. - print('Collect Valid Slabs...DONE') + print('Collect Valid Slabs...START') + start_time = time.time() + solver = cp_model.CpSolver() + + # Add solution callback to store all possible slab templates. collector = AllSolutionsCollector(assign + [loss, load]) + + # Force solver to follow the decision strategy exactly. + solver.parameters.search_branching = cp_model.FIXED_SEARCH + solver.SearchForAllSolutions(model, collector) - print('Collect Valid Slabs...DONE') + run_time = time.time() - start_time + print('Collect Valid Slabs...DONE in %.2f s' % run_time) return collector.all_solutions() @@ -535,7 +537,9 @@ def steel_mill_slab_with_valid_slabs(problem, break_symmetries, output_proto): assign = [[ model.NewBoolVar('assign_%i_to_slab_%i' % (o, s)) for s in all_slabs ] for o in all_orders] - loads = [model.NewIntVar(0, max_capacity, 'load_%i' % s) for s in all_slabs] + loads = [ + model.NewIntVar(0, max_capacity, 'load_%i' % s) for s in all_slabs + ] losses = [model.NewIntVar(0, max_loss, 'loss_%i' % s) for s in all_slabs] unsorted_valid_slabs = collect_valid_slabs(capacities, colors, widths, @@ -548,8 +552,8 @@ def steel_mill_slab_with_valid_slabs(problem, break_symmetries, output_proto): for s in all_slabs: model.AddAllowedAssignments( - [assign[o][s] - for o in all_orders] + [losses[s], loads[s]], valid_slabs) + [assign[o][s] for o in all_orders] + [losses[s], loads[s]], + valid_slabs) # Orders are assigned to one slab. for o in all_orders: @@ -590,7 +594,8 @@ def steel_mill_slab_with_valid_slabs(problem, break_symmetries, output_proto): for w, os in local_width_to_order.items(): if len(os) > 1: for p in range(len(os) - 1): - ordered_equivalent_orders.append((os[p], os[p + 1])) + ordered_equivalent_orders.append((os[p], + os[p + 1])) for w, os in width_to_unique_color_order.items(): if len(os) > 1: for p in range(len(os) - 1): @@ -628,15 +633,15 @@ def steel_mill_slab_with_valid_slabs(problem, break_symmetries, output_proto): ### Solve model. solver = cp_model.CpSolver() + solver.num_search_workers = 8 solution_printer = SteelMillSlabSolutionPrinter(orders, assign, loads, losses) status = solver.SolveWithSolutionCallback(model, solution_printer) ### Output the solution. if status == cp_model.OPTIMAL: - print('Loss = %i, time = %f s, %i conflicts' % - (solver.ObjectiveValue(), solver.WallTime(), - solver.NumConflicts())) + print('Loss = %i, time = %.2f s, %i conflicts' % ( + solver.ObjectiveValue(), solver.WallTime(), solver.NumConflicts())) else: print('No solution') @@ -680,7 +685,8 @@ def steel_mill_slab_with_column_generation(problem, output_proto): for o in all_orders: model.Add( - sum(selected[i] for i in all_valid_slabs if valid_slabs[i][o]) == 1) + sum(selected[i] for i in all_valid_slabs + if valid_slabs[i][o]) == 1) # Redundant constraint (sum of loads == sum of widths). model.Add( @@ -690,8 +696,8 @@ def steel_mill_slab_with_column_generation(problem, output_proto): # Objective. max_loss = max(valid_slabs[i][-2] for i in all_valid_slabs) obj = model.NewIntVar(0, num_slabs * max_loss, 'obj') - model.Add( - obj == sum(selected[i] * valid_slabs[i][-2] for i in all_valid_slabs)) + model.Add(obj == sum( + selected[i] * valid_slabs[i][-2] for i in all_valid_slabs)) model.Minimize(obj) print('Model created') @@ -704,14 +710,14 @@ def steel_mill_slab_with_column_generation(problem, output_proto): ### Solve model. solver = cp_model.CpSolver() - solution_printer = SolutionPrinterWithObjective() + solver.parameters.num_search_workers = 8 + solution_printer = cp_model.ObjectiveSolutionPrinter() status = solver.SolveWithSolutionCallback(model, solution_printer) ### Output the solution. - if status == cp_model.OPTIMAL: - print('Loss = %i, time = %f s, %i conflicts' % - (solver.ObjectiveValue(), solver.WallTime(), - solver.NumConflicts())) + if status in (cp_model.OPTIMAL, cp_model.FEASIBLE): + print('Loss = %i, time = %.2f s, %i conflicts' % ( + solver.ObjectiveValue(), solver.WallTime(), solver.NumConflicts())) else: print('No solution') @@ -753,7 +759,8 @@ def steel_mill_slab_with_mip_column_generation(problem): (num_valid_slabs, generate - start)) # create model and decision variables. - solver = pywraplp.Solver('Steel', pywraplp.Solver.BOP_INTEGER_PROGRAMMING) + solver = pywraplp.Solver('Steel', + pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING) selected = [ solver.IntVar(0.0, 1.0, 'selected_%i' % i) for i in all_valid_slabs ] @@ -776,7 +783,7 @@ def steel_mill_slab_with_mip_column_generation(problem): ### Output the solution. if status == pywraplp.Solver.OPTIMAL: - print('Objective value = %f found in %f s' % + print('Objective value = %f found in %.2f s' % (solver.Objective().Value(), time.time() - generate)) else: print('No solution')