From 12cdacb66bcf333e2be4d5cda8a3427b544a2bf9 Mon Sep 17 00:00:00 2001 From: Ruaridh Williamson Date: Thu, 27 Feb 2020 09:50:47 +0000 Subject: [PATCH] :hammer: Refactor test to use MTZ TSP - This is a much harder model that is more likely to not be solved within the allowed time --- .../solvers/tests/checks/test_CPLEXDirect.py | 108 +++++++++++++++--- 1 file changed, 93 insertions(+), 15 deletions(-) diff --git a/pyomo/solvers/tests/checks/test_CPLEXDirect.py b/pyomo/solvers/tests/checks/test_CPLEXDirect.py index 6bd9e9d6ff2..7e4420cf894 100644 --- a/pyomo/solvers/tests/checks/test_CPLEXDirect.py +++ b/pyomo/solvers/tests/checks/test_CPLEXDirect.py @@ -8,10 +8,14 @@ # This software is distributed under the 3-clause BSD License. # ___________________________________________________________________________ +import sys +from itertools import product +from random import random, seed + import pyutilib.th as unittest -from pyomo.opt import * + from pyomo.environ import * -import sys +from pyomo.opt import * try: import cplex @@ -116,25 +120,99 @@ def test_infeasible_mip(self): @unittest.skipIf(not cplexpy_available, "The 'cplex' python bindings are not available") def test_no_solution_mip(self): - model = ConcreteModel() - model.S = RangeSet(0, 9) - model.P = list(range(10)) - model.X = Var(model.S, within=Binary) - model.C1 = Constraint(expr=summation(model.X) == 1) - model.C2 = Constraint(expr=model.X[0] >= 2) - model.O = Objective(expr=sum_product(model.P, model.X), sense=minimize) + def build_mtz_tsp_model(nodes, links, distances): + # Taken from examples/pyomo/callbacks/tsp.py + model = ConcreteModel() + + model.POINTS = Set(initialize=nodes, ordered=True) + model.POINTS_LESS_FIRST = Set(initialize=nodes[1:], ordered=True) + model.LINKS = Set(initialize=links, ordered=True) + model.LINKS_LESS_FIRST = Set( + initialize=[ + (i, j) for (i, j) in links if i in nodes[1:] and j in nodes[1:] + ], + ordered=True, + ) + + model.N = len(nodes) + model.d = Param(model.LINKS, initialize=distances) + + model.Z = Var(model.LINKS, domain=Binary) + model.FLOW = Var( + model.POINTS_LESS_FIRST, + domain=NonNegativeReals, + bounds=(0, model.N - 1), + ) + + model.InDegrees = Constraint( + model.POINTS, + rule=lambda m, i: sum( + model.Z[i, j] for (i_, j) in model.LINKS if i == i_ + ) + == 1, + ) + model.OutDegrees = Constraint( + model.POINTS, + rule=lambda m, i: sum( + model.Z[j, i] for (j, i_) in model.LINKS if i == i_ + ) + == 1, + ) + + model.FlowCon = Constraint( + model.LINKS_LESS_FIRST, + rule=lambda m, i, j: model.FLOW[i] - model.FLOW[j] + m.N * m.Z[i, j] + <= m.N - 1, + ) + + model.tour_length = Objective( + expr=sum_product(model.d, model.Z), sense=minimize + ) + return model with SolverFactory("cplex", solver_io="python") as opt: # Set the `options` such that CPLEX cannot determine the problem as infeasible within the time allowed - opt.options['timelimit'] = 0 - opt.options['preprocessing_presolve'] = 0 - opt.options['simplex_limits_iterations'] = 1 - opt.options['mip_limits_nodes'] = 1 + opt.options["dettimelimit"] = 1 + opt.options["lpmethod"] = 1 + opt.options["threads"] = 1 + + opt.options["mip_limits_nodes"] = 0 + opt.options["mip_limits_eachcutlimit"] = 0 + opt.options["mip_limits_cutsfactor"] = 0 + opt.options["mip_limits_auxrootthreads"] = -1 + + opt.options["preprocessing_presolve"] = 0 + opt.options["preprocessing_reduce"] = 0 + opt.options["preprocessing_relax"] = 0 + + opt.options["mip_strategy_heuristicfreq"] = -1 + opt.options["mip_strategy_presolvenode"] = -1 + opt.options["mip_strategy_probe"] = -1 + + opt.options["mip_cuts_mircut"] = -1 + opt.options["mip_cuts_implied"] = -1 + opt.options["mip_cuts_gomory"] = -1 + opt.options["mip_cuts_flowcovers"] = -1 + opt.options["mip_cuts_pathcut"] = -1 + opt.options["mip_cuts_liftproj"] = -1 + opt.options["mip_cuts_zerohalfcut"] = -1 + opt.options["mip_cuts_cliques"] = -1 + opt.options["mip_cuts_covers"] = -1 + + nodes = list(range(15)) + links = list((i, j) for i, j in product(nodes, nodes) if i != j) + + seed(0) + distances = {link: random() for link in links} + + model = build_mtz_tsp_model(nodes, links, distances) results = opt.solve(model) - self.assertEqual(results.solver.termination_condition, - TerminationCondition.noSolution) + self.assertEqual(results.solver.status, SolverStatus.warning) + self.assertEqual( + results.solver.termination_condition, TerminationCondition.noSolution + ) @unittest.skipIf(not cplexpy_available, "The 'cplex' python bindings are not available")