Files
blender-easy-patch/utils/pulp/tests/test_pulp.py
小煜 ab91b120e6 feat: 初始化Easy Patch插件及依赖文件
- 添加Blender插件核心文件:__init__.py、ui.py、property.py、preference.py
- 添加插件工具模块:g.py、loop.py、generate_loop.py、const.py、op.py
- 添加翻译工具:utils/trans.py
- 添加PuLP线性规划库及其依赖文件,包括CBC求解器二进制文件
- 添加.gitignore和VSCode配置文件
2026-03-03 19:24:57 +08:00

1674 lines
62 KiB
Python

"""
Tests for pulp
"""
import os
import tempfile
from pulp.constants import PulpError
from pulp.apis import *
from pulp import LpVariable, LpProblem, lpSum, LpConstraintVar, LpFractionConstraint
from pulp import constants as const
from pulp.tests.bin_packing_problem import create_bin_packing_problem
from pulp.utilities import makeDict
import functools
import unittest
try:
import gurobipy as gp
except ImportError:
gp = None
# from: http://lpsolve.sourceforge.net/5.5/mps-format.htm
EXAMPLE_MPS_RHS56 = """NAME TESTPROB
ROWS
N COST
L LIM1
G LIM2
E MYEQN
COLUMNS
XONE COST 1 LIM1 1
XONE LIM2 1
YTWO COST 4 LIM1 1
YTWO MYEQN -1
ZTHREE COST 9 LIM2 1
ZTHREE MYEQN 1
RHS
RHS1 LIM1 5 LIM2 10
RHS1 MYEQN 7
BOUNDS
UP BND1 XONE 4
LO BND1 YTWO -1
UP BND1 YTWO 1
ENDATA
"""
def gurobi_test(test_item):
@functools.wraps(test_item)
def skip_wrapper(*args, **kwargs):
if gp is None:
raise unittest.SkipTest("No gurobipy, can't check license")
try:
test_item(*args, **kwargs)
except gp.GurobiError as ge:
# Skip the test if the failure was due to licensing
if ge.errno == gp.GRB.Error.SIZE_LIMIT_EXCEEDED:
raise unittest.SkipTest("Size-limited Gurobi license")
if ge.errno == gp.GRB.Error.NO_LICENSE:
raise unittest.SkipTest("No Gurobi license")
# Otherwise, let the error go through as-is
raise
return skip_wrapper
def dumpTestProblem(prob):
try:
prob.writeLP("debug.lp")
prob.writeMPS("debug.mps")
except:
print("(Failed to write the test problem.)")
class BaseSolverTest:
class PuLPTest(unittest.TestCase):
solveInst = None
def setUp(self):
self.solver = self.solveInst(msg=False)
if not self.solver.available():
self.skipTest(f"solver {self.solveInst} not available")
def tearDown(self):
for ext in ["mst", "log", "lp", "mps", "sol"]:
filename = f"{self._testMethodName}.{ext}"
try:
os.remove(filename)
except:
pass
pass
def test_pulp_001(self):
"""
Test that a variable is deleted when it is suptracted to 0
"""
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
c1 = x + y <= 5
c2 = c1 + z - z
print("\t Testing zero subtraction")
assert str(c2) # will raise an exception
def test_pulp_009(self):
# infeasible
prob = LpProblem("test09", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += (
lpSum([v for v in [x] if False]) >= 5,
"c1",
) # this is a 0 >=5 constraint
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing inconsistent lp solution")
# this was a problem with use_mps=false
if self.solver.__class__ in [PULP_CBC_CMD, COIN_CMD]:
pulpTestCheck(
prob,
self.solver,
[const.LpStatusInfeasible],
{x: 4, y: -1, z: 6, w: 0},
use_mps=False,
)
elif self.solver.__class__ in [CHOCO_CMD, MIPCL_CMD]:
# this error is not detected with mps and choco, MIPCL_CMD can only use mps files
pass
else:
pulpTestCheck(
prob,
self.solver,
[
const.LpStatusInfeasible,
const.LpStatusNotSolved,
const.LpStatusUndefined,
],
)
def test_pulp_010(self):
# Continuous
prob = LpProblem("test010", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing continuous LP solution")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)
def test_pulp_011(self):
# Continuous Maximisation
prob = LpProblem("test011", const.LpMaximize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing maximize continuous LP solution")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: 1, z: 8, w: 0}
)
def test_pulp_012(self):
# Unbounded
prob = LpProblem("test012", const.LpMaximize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z + w, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing unbounded continuous LP solution")
if self.solver.__class__ in [GUROBI, CPLEX_CMD, YAPOSIB, MOSEK, COPT]:
# These solvers report infeasible or unbounded
pulpTestCheck(
prob,
self.solver,
[const.LpStatusInfeasible, const.LpStatusUnbounded],
)
elif self.solver.__class__ in [COINMP_DLL, MIPCL_CMD]:
# COINMP_DLL is just plain wrong
# also MIPCL_CMD
print("\t\t Error in CoinMP and MIPCL_CMD: reports Optimal")
pulpTestCheck(prob, self.solver, [const.LpStatusOptimal])
elif self.solver.__class__ is GLPK_CMD:
# GLPK_CMD Does not report unbounded problems, correctly
pulpTestCheck(prob, self.solver, [const.LpStatusUndefined])
elif self.solver.__class__ in [GUROBI_CMD, SCIP_CMD, FSCIP_CMD, SCIP_PY]:
# GUROBI_CMD has a very simple interface
pulpTestCheck(prob, self.solver, [const.LpStatusNotSolved])
elif self.solver.__class__ in [CHOCO_CMD]:
# choco bounds all variables. Would not return unbounded status
pass
else:
pulpTestCheck(prob, self.solver, [const.LpStatusUnbounded])
def test_pulp_013(self):
# Long name
prob = LpProblem("test013", const.LpMinimize)
x = LpVariable("x" * 120, 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing Long Names")
if self.solver.__class__ in [
CPLEX_CMD,
GLPK_CMD,
GUROBI_CMD,
MIPCL_CMD,
SCIP_CMD,
FSCIP_CMD,
SCIP_PY,
HiGHS,
HiGHS_CMD,
XPRESS,
XPRESS_CMD,
]:
try:
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
except PulpError:
# these solvers should raise an error'
pass
else:
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
def test_pulp_014(self):
# repeated name
prob = LpProblem("test014", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("x", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing repeated Names")
if self.solver.__class__ in [
COIN_CMD,
COINMP_DLL,
PULP_CBC_CMD,
CPLEX_CMD,
CPLEX_PY,
GLPK_CMD,
GUROBI_CMD,
CHOCO_CMD,
MIPCL_CMD,
MOSEK,
SCIP_CMD,
FSCIP_CMD,
SCIP_PY,
HiGHS,
HiGHS_CMD,
XPRESS,
XPRESS_CMD,
XPRESS_PY,
]:
try:
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
except PulpError:
# these solvers should raise an error
pass
else:
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
def test_pulp_015(self):
# zero constraint
prob = LpProblem("test015", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
prob += lpSum([0, 0]) <= 0, "c5"
print("\t Testing zero constraint")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)
def test_pulp_016(self):
# zero objective
prob = LpProblem("test016", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
prob += lpSum([0, 0]) <= 0, "c5"
print("\t Testing zero objective")
pulpTestCheck(prob, self.solver, [const.LpStatusOptimal])
def test_pulp_017(self):
# variable as objective
prob = LpProblem("test017", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob.setObjective(x)
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
prob += lpSum([0, 0]) <= 0, "c5"
print("\t Testing LpVariable (not LpAffineExpression) objective")
pulpTestCheck(prob, self.solver, [const.LpStatusOptimal])
def test_pulp_018(self):
# Long name in lp
prob = LpProblem("test018", const.LpMinimize)
x = LpVariable("x" * 90, 0, 4)
y = LpVariable("y" * 90, -1, 1)
z = LpVariable("z" * 90, 0)
w = LpVariable("w" * 90, 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
if self.solver.__class__ in [PULP_CBC_CMD, COIN_CMD]:
print("\t Testing Long lines in LP")
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
use_mps=False,
)
def test_pulp_019(self):
# divide
prob = LpProblem("test019", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += (2 * x + 2 * y).__div__(2.0) <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing LpAffineExpression divide")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)
def test_pulp_020(self):
# MIP
prob = LpProblem("test020", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, None, const.LpInteger)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7.5, "c3"
print("\t Testing MIP solution")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 3, y: -0.5, z: 7}
)
def test_pulp_021(self):
# MIP with floats in objective
prob = LpProblem("test021", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, None, const.LpInteger)
prob += 1.1 * x + 4.1 * y + 9.1 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7.5, "c3"
print("\t Testing MIP solution with floats in objective")
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 3, y: -0.5, z: 7},
objective=64.95,
)
def test_pulp_022(self):
# Initial value
prob = LpProblem("test022", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, None, const.LpInteger)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7.5, "c3"
x.setInitialValue(3)
y.setInitialValue(-0.5)
z.setInitialValue(7)
if self.solver.name in [
"GUROBI",
"GUROBI_CMD",
"CPLEX_CMD",
"CPLEX_PY",
"COPT",
]:
self.solver.optionsDict["warmStart"] = True
print("\t Testing Initial value in MIP solution")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 3, y: -0.5, z: 7}
)
def test_pulp_023(self):
# Initial value (fixed)
prob = LpProblem("test023", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, None, const.LpInteger)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7.5, "c3"
solution = {x: 4, y: -0.5, z: 7}
for v in [x, y, z]:
v.setInitialValue(solution[v])
v.fixValue()
self.solver.optionsDict["warmStart"] = True
print("\t Testing fixing value in MIP solution")
pulpTestCheck(prob, self.solver, [const.LpStatusOptimal], solution)
def test_pulp_030(self):
# relaxed MIP
prob = LpProblem("test030", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, None, const.LpInteger)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7.5, "c3"
self.solver.mip = 0
print("\t Testing MIP relaxation")
if self.solver.__class__ in [
GUROBI_CMD,
CHOCO_CMD,
MIPCL_CMD,
SCIP_CMD,
FSCIP_CMD,
SCIP_PY,
]:
# these solvers do not let the problem be relaxed
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 3.0, y: -0.5, z: 7}
)
else:
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 3.5, y: -1, z: 6.5}
)
def test_pulp_040(self):
# Feasibility only
prob = LpProblem("test040", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, None, const.LpInteger)
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7.5, "c3"
print("\t Testing feasibility problem (no objective)")
pulpTestCheck(prob, self.solver, [const.LpStatusOptimal])
def test_pulp_050(self):
# Infeasible
prob = LpProblem("test050", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, 10)
prob += x + y <= 5.2, "c1"
prob += x + z >= 10.3, "c2"
prob += -y + z == 17.5, "c3"
print("\t Testing an infeasible problem")
if self.solver.__class__ is GLPK_CMD:
# GLPK_CMD return codes are not informative enough
pulpTestCheck(prob, self.solver, [const.LpStatusUndefined])
elif self.solver.__class__ in [GUROBI_CMD, FSCIP_CMD]:
# GUROBI_CMD Does not solve the problem
pulpTestCheck(prob, self.solver, [const.LpStatusNotSolved])
else:
pulpTestCheck(prob, self.solver, [const.LpStatusInfeasible])
def test_pulp_060(self):
# Integer Infeasible
prob = LpProblem("test060", const.LpMinimize)
x = LpVariable("x", 0, 4, const.LpInteger)
y = LpVariable("y", -1, 1, const.LpInteger)
z = LpVariable("z", 0, 10, const.LpInteger)
prob += x + y <= 5.2, "c1"
prob += x + z >= 10.3, "c2"
prob += -y + z == 7.4, "c3"
print("\t Testing an integer infeasible problem")
if self.solver.__class__ in [GLPK_CMD, COIN_CMD, PULP_CBC_CMD, MOSEK]:
# GLPK_CMD returns InfeasibleOrUnbounded
pulpTestCheck(
prob,
self.solver,
[const.LpStatusInfeasible, const.LpStatusUndefined],
)
elif self.solver.__class__ in [COINMP_DLL]:
# Currently there is an error in COINMP for problems where
# presolve eliminates too many variables
print("\t\t Error in CoinMP to be fixed, reports Optimal")
pulpTestCheck(prob, self.solver, [const.LpStatusOptimal])
elif self.solver.__class__ in [GUROBI_CMD, FSCIP_CMD]:
pulpTestCheck(prob, self.solver, [const.LpStatusNotSolved])
else:
pulpTestCheck(prob, self.solver, [const.LpStatusInfeasible])
def test_pulp_061(self):
# Integer Infeasible
prob = LpProblem("sample", const.LpMaximize)
dummy = LpVariable("dummy")
c1 = LpVariable("c1", 0, 1, const.LpBinary)
c2 = LpVariable("c2", 0, 1, const.LpBinary)
prob += dummy
prob += c1 + c2 == 2
prob += c1 <= 0
print("\t Testing another integer infeasible problem")
if self.solver.__class__ in [GUROBI_CMD, SCIP_CMD, FSCIP_CMD, SCIP_PY]:
pulpTestCheck(prob, self.solver, [const.LpStatusNotSolved])
elif self.solver.__class__ in [GLPK_CMD]:
# GLPK_CMD returns InfeasibleOrUnbounded
pulpTestCheck(
prob,
self.solver,
[const.LpStatusInfeasible, const.LpStatusUndefined],
)
else:
pulpTestCheck(prob, self.solver, [const.LpStatusInfeasible])
def test_pulp_070(self):
# Column Based modelling of test_pulp_1
prob = LpProblem("test070", const.LpMinimize)
obj = LpConstraintVar("obj")
# constraints
a = LpConstraintVar("C1", const.LpConstraintLE, 5)
b = LpConstraintVar("C2", const.LpConstraintGE, 10)
c = LpConstraintVar("C3", const.LpConstraintEQ, 7)
prob.setObjective(obj)
prob += a
prob += b
prob += c
# Variables
x = LpVariable("x", 0, 4, const.LpContinuous, obj + a + b)
y = LpVariable("y", -1, 1, const.LpContinuous, 4 * obj + a - c)
z = LpVariable("z", 0, None, const.LpContinuous, 9 * obj + b + c)
print("\t Testing column based modelling")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6}
)
def test_pulp_075(self):
# Column Based modelling of test_pulp_1 with empty constraints
prob = LpProblem("test075", const.LpMinimize)
obj = LpConstraintVar("obj")
# constraints
a = LpConstraintVar("C1", const.LpConstraintLE, 5)
b = LpConstraintVar("C2", const.LpConstraintGE, 10)
c = LpConstraintVar("C3", const.LpConstraintEQ, 7)
prob.setObjective(obj)
prob += a
prob += b
prob += c
# Variables
x = LpVariable("x", 0, 4, const.LpContinuous, obj + b)
y = LpVariable("y", -1, 1, const.LpContinuous, 4 * obj - c)
z = LpVariable("z", 0, None, const.LpContinuous, 9 * obj + b + c)
if self.solver.__class__ in [CPLEX_CMD, COINMP_DLL, YAPOSIB, PYGLPK]:
print("\t Testing column based modelling with empty constraints")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6}
)
def test_pulp_080(self):
"""
Test the reporting of dual variables slacks and reduced costs
"""
prob = LpProblem("test080", const.LpMinimize)
x = LpVariable("x", 0, 5)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
c1 = x + y <= 5
c2 = x + z >= 10
c3 = -y + z == 7
prob += x + 4 * y + 9 * z, "obj"
prob += c1, "c1"
prob += c2, "c2"
prob += c3, "c3"
if self.solver.__class__ in [
CPLEX_CMD,
COINMP_DLL,
PULP_CBC_CMD,
YAPOSIB,
PYGLPK,
]:
print("\t Testing dual variables and slacks reporting")
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
sol={x: 4, y: -1, z: 6},
reducedcosts={x: 0, y: 12, z: 0},
duals={"c1": 0, "c2": 1, "c3": 8},
slacks={"c1": 2, "c2": 0, "c3": 0},
)
def test_pulp_090(self):
# Column Based modelling of test_pulp_1 with a resolve
prob = LpProblem("test090", const.LpMinimize)
obj = LpConstraintVar("obj")
# constraints
a = LpConstraintVar("C1", const.LpConstraintLE, 5)
b = LpConstraintVar("C2", const.LpConstraintGE, 10)
c = LpConstraintVar("C3", const.LpConstraintEQ, 7)
prob.setObjective(obj)
prob += a
prob += b
prob += c
prob.setSolver(self.solver) # Variables
x = LpVariable("x", 0, 4, const.LpContinuous, obj + a + b)
y = LpVariable("y", -1, 1, const.LpContinuous, 4 * obj + a - c)
prob.resolve()
z = LpVariable("z", 0, None, const.LpContinuous, 9 * obj + b + c)
if self.solver.__class__ in [COINMP_DLL]:
print("\t Testing resolve of problem")
prob.resolve()
# difficult to check this is doing what we want as the resolve is
# overridden if it is not implemented
# test_pulp_Check(prob, self.solver, [const.LpStatusOptimal], {x:4, y:-1, z:6})
def test_pulp_100(self):
"""
Test the ability to sequentially solve a problem
"""
# set up a cubic feasible region
prob = LpProblem("test100", const.LpMinimize)
x = LpVariable("x", 0, 1)
y = LpVariable("y", 0, 1)
z = LpVariable("z", 0, 1)
obj1 = x + 0 * y + 0 * z
obj2 = 0 * x - 1 * y + 0 * z
prob += x <= 1, "c1"
if self.solver.__class__ in [COINMP_DLL, GUROBI]:
print("\t Testing Sequential Solves")
status = prob.sequentialSolve([obj1, obj2], solver=self.solver)
pulpTestCheck(
prob,
self.solver,
[[const.LpStatusOptimal, const.LpStatusOptimal]],
sol={x: 0, y: 1},
status=status,
)
def test_pulp_110(self):
"""
Test the ability to use fractional constraints
"""
prob = LpProblem("test110", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
prob += LpFractionConstraint(x, z, const.LpConstraintEQ, 0.5, name="c5")
print("\t Testing fractional constraints")
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 10 / 3.0, y: -1 / 3.0, z: 20 / 3.0, w: 0},
)
def test_pulp_120(self):
"""
Test the ability to use Elastic constraints
"""
prob = LpProblem("test120", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w")
prob += x + 4 * y + 9 * z + w, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob.extend((w >= -1).makeElasticSubProblem())
print("\t Testing elastic constraints (no change)")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: -1}
)
def test_pulp_121(self):
"""
Test the ability to use Elastic constraints
"""
prob = LpProblem("test121", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w")
prob += x + 4 * y + 9 * z + w, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob.extend((w >= -1).makeElasticSubProblem(proportionFreeBound=0.1))
print("\t Testing elastic constraints (freebound)")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: -1.1}
)
def test_pulp_122(self):
"""
Test the ability to use Elastic constraints (penalty unchanged)
"""
prob = LpProblem("test122", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w")
prob += x + 4 * y + 9 * z + w, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob.extend((w >= -1).makeElasticSubProblem(penalty=1.1))
print("\t Testing elastic constraints (penalty unchanged)")
pulpTestCheck(
prob, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: -1.0}
)
def test_pulp_123(self):
"""
Test the ability to use Elastic constraints (penalty unbounded)
"""
prob = LpProblem("test123", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w")
prob += x + 4 * y + 9 * z + w, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob.extend((w >= -1).makeElasticSubProblem(penalty=0.9))
print("\t Testing elastic constraints (penalty unbounded)")
if self.solver.__class__ in [
COINMP_DLL,
GUROBI,
CPLEX_CMD,
YAPOSIB,
MOSEK,
COPT,
]:
# COINMP_DLL Does not report unbounded problems, correctly
pulpTestCheck(
prob,
self.solver,
[const.LpStatusInfeasible, const.LpStatusUnbounded],
)
elif self.solver.__class__ is GLPK_CMD:
# GLPK_CMD Does not report unbounded problems, correctly
pulpTestCheck(prob, self.solver, [const.LpStatusUndefined])
elif self.solver.__class__ in [GUROBI_CMD, SCIP_CMD, FSCIP_CMD, SCIP_PY]:
pulpTestCheck(prob, self.solver, [const.LpStatusNotSolved])
elif self.solver.__class__ in [CHOCO_CMD]:
# choco bounds all variables. Would not return unbounded status
pass
else:
pulpTestCheck(prob, self.solver, [const.LpStatusUnbounded])
def test_msg_arg(self):
"""
Test setting the msg arg to True does not interfere with solve
"""
prob = LpProblem("test_msg_arg", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
data = prob.toDict()
var1, prob1 = LpProblem.fromDict(data)
x, y, z, w = (var1[name] for name in ["x", "y", "z", "w"])
if self.solver.name in ["HiGHS"]:
# HiGHS has issues with displaying output in Ubuntu
return
self.solver.msg = True
pulpTestCheck(
prob1, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)
def test_pulpTestAll(self):
"""
Test the availability of the function pulpTestAll
"""
print("\t Testing the availability of the function pulpTestAll")
from pulp import pulpTestAll
def test_export_dict_LP(self):
prob = LpProblem("test_export_dict_LP", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
data = prob.toDict()
var1, prob1 = LpProblem.fromDict(data)
x, y, z, w = (var1[name] for name in ["x", "y", "z", "w"])
print("\t Testing continuous LP solution - export dict")
pulpTestCheck(
prob1, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)
def test_export_dict_LP_no_obj(self):
prob = LpProblem("test_export_dict_LP_no_obj", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0, 0)
prob += x + y >= 5, "c1"
prob += x + z == 10, "c2"
prob += -y + z <= 7, "c3"
prob += w >= 0, "c4"
data = prob.toDict()
var1, prob1 = LpProblem.fromDict(data)
x, y, z, w = (var1[name] for name in ["x", "y", "z", "w"])
print("\t Testing export dict for LP")
pulpTestCheck(
prob1, self.solver, [const.LpStatusOptimal], {x: 4, y: 1, z: 6, w: 0}
)
def test_export_json_LP(self):
name = self._testMethodName
prob = LpProblem(name, const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
filename = name + ".json"
prob.toJson(filename, indent=4)
var1, prob1 = LpProblem.fromJson(filename)
try:
os.remove(filename)
except:
pass
x, y, z, w = (var1[name] for name in ["x", "y", "z", "w"])
print("\t Testing continuous LP solution - export JSON")
pulpTestCheck(
prob1, self.solver, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)
def test_export_dict_MIP(self):
import copy
prob = LpProblem("test_export_dict_MIP", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, None, const.LpInteger)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7.5, "c3"
data = prob.toDict()
data_backup = copy.deepcopy(data)
var1, prob1 = LpProblem.fromDict(data)
x, y, z = (var1[name] for name in ["x", "y", "z"])
print("\t Testing export dict MIP")
pulpTestCheck(
prob1, self.solver, [const.LpStatusOptimal], {x: 3, y: -0.5, z: 7}
)
# we also test that we have not modified the dictionary when importing it
self.assertDictEqual(data, data_backup)
def test_export_dict_max(self):
prob = LpProblem("test_export_dict_max", const.LpMaximize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
data = prob.toDict()
var1, prob1 = LpProblem.fromDict(data)
x, y, z, w = (var1[name] for name in ["x", "y", "z", "w"])
print("\t Testing maximize continuous LP solution")
pulpTestCheck(
prob1, self.solver, [const.LpStatusOptimal], {x: 4, y: 1, z: 8, w: 0}
)
def test_export_solver_dict_LP(self):
prob = LpProblem("test_export_dict_LP", const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
data = self.solver.toDict()
solver1 = getSolverFromDict(data)
print("\t Testing continuous LP solution - export solver dict")
pulpTestCheck(
prob, solver1, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)
def test_export_solver_json(self):
name = self._testMethodName
prob = LpProblem(name, const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
self.solver.mip = True
logFilename = name + ".log"
if self.solver.name == "CPLEX_CMD":
self.solver.optionsDict = dict(
gapRel=0.1,
gapAbs=1,
maxMemory=1000,
maxNodes=1,
threads=1,
logPath=logFilename,
warmStart=True,
)
elif self.solver.name in ["GUROBI_CMD", "COIN_CMD", "PULP_CBC_CMD"]:
self.solver.optionsDict = dict(
gapRel=0.1, gapAbs=1, threads=1, logPath=logFilename, warmStart=True
)
filename = name + ".json"
self.solver.toJson(filename, indent=4)
solver1 = getSolverFromJson(filename)
try:
os.remove(filename)
except:
pass
print("\t Testing continuous LP solution - export solver JSON")
pulpTestCheck(
prob, solver1, [const.LpStatusOptimal], {x: 4, y: -1, z: 6, w: 0}
)
def test_timeLimit(self):
name = self._testMethodName
prob = LpProblem(name, const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
self.solver.timeLimit = 20
# CHOCO has issues when given a time limit
print("\t Testing timeLimit argument")
if self.solver.name != "CHOCO_CMD":
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
def test_assignInvalidStatus(self):
print("\t Testing invalid status")
t = LpProblem("test")
Invalid = -100
self.assertRaises(const.PulpError, lambda: t.assignStatus(Invalid))
self.assertRaises(const.PulpError, lambda: t.assignStatus(0, Invalid))
def test_logPath(self):
name = self._testMethodName
prob = LpProblem(name, const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
logFilename = name + ".log"
self.solver.optionsDict["logPath"] = logFilename
if self.solver.name in [
"CPLEX_PY",
"CPLEX_CMD",
"GUROBI",
"GUROBI_CMD",
"PULP_CBC_CMD",
"COIN_CMD",
]:
print("\t Testing logPath argument")
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
if not os.path.exists(logFilename):
raise PulpError(f"Test failed for solver: {self.solver}")
if not os.path.getsize(logFilename):
raise PulpError(f"Test failed for solver: {self.solver}")
def test_makeDict_behavior(self):
"""
Test if makeDict is returning the expected value.
"""
headers = [["A", "B"], ["C", "D"]]
values = [[1, 2], [3, 4]]
target = {"A": {"C": 1, "D": 2}, "B": {"C": 3, "D": 4}}
dict_with_default = makeDict(headers, values, default=0)
dict_without_default = makeDict(headers, values)
print("\t Testing makeDict general behavior")
self.assertEqual(dict_with_default, target)
self.assertEqual(dict_without_default, target)
def test_makeDict_default_value(self):
"""
Test if makeDict is returning a default value when specified.
"""
headers = [["A", "B"], ["C", "D"]]
values = [[1, 2], [3, 4]]
dict_with_default = makeDict(headers, values, default=0)
dict_without_default = makeDict(headers, values)
print("\t Testing makeDict default value behavior")
# Check if a default value is passed
self.assertEqual(dict_with_default["X"]["Y"], 0)
# Check if a KeyError is raised
_func = lambda: dict_without_default["X"]["Y"]
self.assertRaises(KeyError, _func)
def test_importMPS_maximize(self):
name = self._testMethodName
prob = LpProblem(name, const.LpMaximize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
filename = name + ".mps"
prob.writeMPS(filename)
_vars, prob2 = LpProblem.fromMPS(filename, sense=prob.sense)
_dict1 = getSortedDict(prob)
_dict2 = getSortedDict(prob2)
print("\t Testing reading MPS files - maximize")
self.assertDictEqual(_dict1, _dict2)
def test_importMPS_noname(self):
name = self._testMethodName
prob = LpProblem("", const.LpMaximize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
filename = name + ".mps"
prob.writeMPS(filename)
_vars, prob2 = LpProblem.fromMPS(filename, sense=prob.sense)
_dict1 = getSortedDict(prob)
_dict2 = getSortedDict(prob2)
print("\t Testing reading MPS files - noname")
self.assertDictEqual(_dict1, _dict2)
def test_importMPS_integer(self):
name = self._testMethodName
prob = LpProblem(name, const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0, None, const.LpInteger)
prob += 1.1 * x + 4.1 * y + 9.1 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7.5, "c3"
filename = name + ".mps"
prob.writeMPS(filename)
_vars, prob2 = LpProblem.fromMPS(filename, sense=prob.sense)
_dict1 = getSortedDict(prob)
_dict2 = getSortedDict(prob2)
print("\t Testing reading MPS files - integer variable")
self.assertDictEqual(_dict1, _dict2)
def test_importMPS_binary(self):
name = self._testMethodName
prob = LpProblem(name, const.LpMaximize)
dummy = LpVariable("dummy")
c1 = LpVariable("c1", 0, 1, const.LpBinary)
c2 = LpVariable("c2", 0, 1, const.LpBinary)
prob += dummy
prob += c1 + c2 == 2
prob += c1 <= 0
filename = name + ".mps"
prob.writeMPS(filename)
_vars, prob2 = LpProblem.fromMPS(
filename, sense=prob.sense, dropConsNames=True
)
_dict1 = getSortedDict(prob, keyCons="constant")
_dict2 = getSortedDict(prob2, keyCons="constant")
print("\t Testing reading MPS files - binary variable, no constraint names")
self.assertDictEqual(_dict1, _dict2)
def test_importMPS_RHS_fields56(self):
"""Import MPS file with RHS definitions in fields 5 & 6."""
with tempfile.NamedTemporaryFile(delete=False) as h:
h.write(str.encode(EXAMPLE_MPS_RHS56))
_, problem = LpProblem.fromMPS(h.name)
os.unlink(h.name)
self.assertEqual(problem.constraints["LIM2"].constant, -10)
# def test_importMPS_2(self):
# name = self._testMethodName
# # filename = name + ".mps"
# filename = "/home/pchtsp/Downloads/test.mps"
# _vars, _prob = LpProblem.fromMPS(filename)
# _prob.solve()
# for k, v in _vars.items():
# print(k, v.value())
def test_unset_objective_value__is_valid(self):
"""Given a valid problem that does not converge,
assert that it is still categorised as valid.
"""
name = self._testMethodName
prob = LpProblem(name, const.LpMaximize)
x = LpVariable("x")
prob += 0 * x
prob += x >= 1
pulpTestCheck(prob, self.solver, [const.LpStatusOptimal])
self.assertTrue(prob.valid())
def test_unbounded_problem__is_not_valid(self):
"""Given an unbounded problem, where x will tend to infinity
to maximise the objective, assert that it is categorised
as invalid."""
name = self._testMethodName
prob = LpProblem(name, const.LpMaximize)
x = LpVariable("x")
prob += 1000 * x
prob += x >= 1
self.assertFalse(prob.valid())
def test_infeasible_problem__is_not_valid(self):
"""Given a problem where x cannot converge to any value
given conflicting constraints, assert that it is invalid."""
name = self._testMethodName
prob = LpProblem(name, const.LpMaximize)
x = LpVariable("x")
prob += 1 * x
prob += x >= 2 # Constraint x to be more than 2
prob += x <= 1 # Constraint x to be less than 1
if self.solver.name in ["GUROBI_CMD", "FSCIP_CMD"]:
pulpTestCheck(
prob,
self.solver,
[
const.LpStatusNotSolved,
const.LpStatusInfeasible,
const.LpStatusUndefined,
],
)
else:
pulpTestCheck(
prob,
self.solver,
[const.LpStatusInfeasible, const.LpStatusUndefined],
)
self.assertFalse(prob.valid())
def test_false_constraint(self):
prob = LpProblem(self._testMethodName, const.LpMinimize)
def add_const(prob):
prob += 0 - 3 == 0
self.assertRaises(TypeError, add_const, prob=prob)
@gurobi_test
def test_measuring_solving_time(self):
print("\t Testing measuring optimization time")
time_limit = 10
solver_settings = dict(
PULP_CBC_CMD=30,
COIN_CMD=30,
SCIP_CMD=30,
GUROBI_CMD=50,
CPLEX_CMD=50,
GUROBI=50,
HiGHS=50,
)
bins = solver_settings.get(self.solver.name)
if bins is None:
# not all solvers have timeLimit support
return
prob = create_bin_packing_problem(bins=bins, seed=99)
self.solver.timeLimit = time_limit
prob.solve(self.solver)
delta = 20
reported_time = prob.solutionTime
if self.solver.name in ["PULP_CBC_CMD", "COIN_CMD"]:
reported_time = prob.solutionCpuTime
self.assertAlmostEqual(
reported_time,
time_limit,
delta=delta,
msg=f"optimization time for solver {self.solver.name}",
)
self.assertTrue(prob.objective.value() is not None)
for v in prob.variables():
self.assertTrue(v.varValue is not None)
def test_invalid_var_names(self):
prob = LpProblem(self._testMethodName, const.LpMinimize)
x = LpVariable("a")
w = LpVariable("b")
y = LpVariable("g", -1, 1)
z = LpVariable("End")
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
print("\t Testing invalid var names")
if self.solver.name not in [
"GUROBI_CMD", # end is a key-word for LP files
]:
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
def test_LpVariable_indexs_param(self):
"""
Test that 'indexs' param continues to work
"""
prob = LpProblem(self._testMethodName, const.LpMinimize)
customers = [1, 2, 3]
agents = ["A", "B", "C"]
print("\t Testing 'indexs' param continues to work for LpVariable.dicts")
# explicit param creates a dict of type LpVariable
assign_vars = LpVariable.dicts(name="test", indexs=(customers, agents))
for k, v in assign_vars.items():
for a, b in v.items():
self.assertIsInstance(b, LpVariable)
# param by position creates a dict of type LpVariable
assign_vars = LpVariable.dicts("test", (customers, agents))
for k, v in assign_vars.items():
for a, b in v.items():
self.assertIsInstance(b, LpVariable)
print("\t Testing 'indexs' param continues to work for LpVariable.matrix")
# explicit param creates list of list of LpVariable
assign_vars_matrix = LpVariable.matrix(
name="test", indices=(customers, agents)
)
for a in assign_vars_matrix:
for b in a:
self.assertIsInstance(b, LpVariable)
# param by position creates list of list of LpVariable
assign_vars_matrix = LpVariable.matrix("test", (customers, agents))
for a in assign_vars_matrix:
for b in a:
self.assertIsInstance(b, LpVariable)
def test_LpVariable_indices_param(self):
"""
Test that 'indices' argument works
"""
prob = LpProblem(self._testMethodName, const.LpMinimize)
customers = [1, 2, 3]
agents = ["A", "B", "C"]
print("\t Testing 'indices' argument works in LpVariable.dicts")
# explicit param creates a dict of type LpVariable
assign_vars = LpVariable.dicts(name="test", indices=(customers, agents))
for k, v in assign_vars.items():
for a, b in v.items():
self.assertIsInstance(b, LpVariable)
print("\t Testing 'indices' param continues to work for LpVariable.matrix")
# explicit param creates list of list of LpVariable
assign_vars_matrix = LpVariable.matrix(
name="test", indices=(customers, agents)
)
for a in assign_vars_matrix:
for b in a:
self.assertIsInstance(b, LpVariable)
def test_LpVariable_indexs_deprecation_logic(self):
"""
Test that logic put in place for deprecation handling of indexs works
"""
print(
"\t Test that logic put in place for deprecation handling of indexs works"
)
prob = LpProblem(self._testMethodName, const.LpMinimize)
customers = [1, 2, 3]
agents = ["A", "B", "C"]
with self.assertRaises(TypeError):
# both variables
assign_vars_matrix = LpVariable.dicts(
name="test", indices=(customers, agents), indexs=(customers, agents)
)
with self.assertRaises(TypeError):
# no variables
assign_vars_matrix = LpVariable.dicts(name="test")
with self.assertWarns(DeprecationWarning):
assign_vars_matrix = LpVariable.dicts(
name="test", indexs=(customers, agents)
)
def test_parse_cplex_mipopt_solution(self):
"""
Ensures `readsol` can parse CPLEX mipopt solutions (see issue #508).
"""
from io import StringIO
print("\t Testing that `readsol` can parse CPLEX mipopt solution")
# Example solution generated by CPLEX mipopt solver
file_content = """<?xml version = "1.0" encoding="UTF-8" standalone="yes"?>
<CPLEXSolution version="1.2">
<header
problemName="mipopt_solution_example.lp"
solutionName="incumbent"
solutionIndex="-1"
objectiveValue="442"
solutionTypeValue="3"
solutionTypeString="primal"
solutionStatusValue="101"
solutionStatusString="integer optimal solution"
solutionMethodString="mip"
primalFeasible="1"
dualFeasible="1"
MIPNodes="25471"
MIPIterations="282516"
writeLevel="1"/>
<quality
epInt="1.0000000000000001e-05"
epRHS="9.9999999999999995e-07"
maxIntInfeas="8.8817841970012523e-16"
maxPrimalInfeas="0"
maxX="48"
maxSlack="141"/>
<linearConstraints>
<constraint name="C1" index="0" slack="0"/>
<constraint name="C2" index="1" slack="0"/>
</linearConstraints>
<variables>
<variable name="x" index="0" value="42"/>
<variable name="y" index="1" value="0"/>
</variables>
<objectiveValues>
<objective index="0" name="x" value="42"/>
</objectiveValues>
</CPLEXSolution>
"""
solution_file = StringIO(file_content)
# This call to `readsol` would crash for this solution format #508
_, _, reducedCosts, shadowPrices, _, _ = CPLEX_CMD().readsol(solution_file)
# Because mipopt solutions have no `reducedCost` fields
# it should be all None
self.assertTrue(all(c is None for c in reducedCosts.values()))
# Because mipopt solutions have no `shadowPrices` fields
# it should be all None
self.assertTrue(all(c is None for c in shadowPrices.values()))
def test_options_parsing_SCIP_HIGHS(self):
name = self._testMethodName
prob = LpProblem(name, const.LpMinimize)
x = LpVariable("x", 0, 4)
y = LpVariable("y", -1, 1)
z = LpVariable("z", 0)
w = LpVariable("w", 0)
prob += x + 4 * y + 9 * z, "obj"
prob += x + y <= 5, "c1"
prob += x + z >= 10, "c2"
prob += -y + z == 7, "c3"
prob += w >= 0, "c4"
# CHOCO has issues when given a time limit
print("\t Testing options parsing")
if self.solver.__class__ in [SCIP_CMD, FSCIP_CMD]:
self.solver.options = ["limits/time", 20]
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
elif self.solver.__class__ in [HiGHS_CMD]:
self.solver.options = ["time_limit", 20]
pulpTestCheck(
prob,
self.solver,
[const.LpStatusOptimal],
{x: 4, y: -1, z: 6, w: 0},
)
class PULP_CBC_CMDTest(BaseSolverTest.PuLPTest):
solveInst = PULP_CBC_CMD
class CPLEX_CMDTest(BaseSolverTest.PuLPTest):
solveInst = CPLEX_CMD
class CPLEX_PYTest(BaseSolverTest.PuLPTest):
solveInst = CPLEX_CMD
class XPRESS_CMDTest(BaseSolverTest.PuLPTest):
solveInst = XPRESS_CMD
class XPRESS_PyTest(BaseSolverTest.PuLPTest):
solveInst = XPRESS_PY
class COIN_CMDTest(BaseSolverTest.PuLPTest):
solveInst = COIN_CMD
class COINMP_DLLTest(BaseSolverTest.PuLPTest):
solveInst = COINMP_DLL
class GLPK_CMDTest(BaseSolverTest.PuLPTest):
solveInst = GLPK_CMD
class GUROBITest(BaseSolverTest.PuLPTest):
solveInst = GUROBI
class GUROBI_CMDTest(BaseSolverTest.PuLPTest):
solveInst = GUROBI_CMD
class PYGLPKTest(BaseSolverTest.PuLPTest):
solveInst = PYGLPK
class YAPOSIBTest(BaseSolverTest.PuLPTest):
solveInst = YAPOSIB
class CHOCO_CMDTest(BaseSolverTest.PuLPTest):
solveInst = CHOCO_CMD
class MIPCL_CMDTest(BaseSolverTest.PuLPTest):
solveInst = MIPCL_CMD
class MOSEKTest(BaseSolverTest.PuLPTest):
solveInst = MOSEK
class SCIP_CMDTest(BaseSolverTest.PuLPTest):
solveInst = SCIP_CMD
class FSCIP_CMDTest(BaseSolverTest.PuLPTest):
solveInst = FSCIP_CMD
class SCIP_PYTest(BaseSolverTest.PuLPTest):
solveInst = SCIP_PY
class HiGHS_PYTest(BaseSolverTest.PuLPTest):
solveInst = HiGHS
class HiGHS_CMDTest(BaseSolverTest.PuLPTest):
solveInst = HiGHS_CMD
class COPTTest(BaseSolverTest.PuLPTest):
solveInst = COPT
def pulpTestCheck(
prob,
solver,
okstatus,
sol=None,
reducedcosts=None,
duals=None,
slacks=None,
eps=10**-3,
status=None,
objective=None,
**kwargs,
):
if status is None:
status = prob.solve(solver, **kwargs)
if status not in okstatus:
dumpTestProblem(prob)
raise PulpError(
"Tests failed for solver {}:\nstatus == {} not in {}\nstatus == {} not in {}".format(
solver,
status,
okstatus,
const.LpStatus[status],
[const.LpStatus[s] for s in okstatus],
)
)
if sol is not None:
for v, x in sol.items():
if abs(v.varValue - x) > eps:
dumpTestProblem(prob)
raise PulpError(
"Tests failed for solver {}:\nvar {} == {} != {}".format(
solver, v, v.varValue, x
)
)
if reducedcosts:
for v, dj in reducedcosts.items():
if abs(v.dj - dj) > eps:
dumpTestProblem(prob)
raise PulpError(
"Tests failed for solver {}:\nTest failed: var.dj {} == {} != {}".format(
solver, v, v.dj, dj
)
)
if duals:
for cname, p in duals.items():
c = prob.constraints[cname]
if abs(c.pi - p) > eps:
dumpTestProblem(prob)
raise PulpError(
"Tests failed for solver {}:\nconstraint.pi {} == {} != {}".format(
solver, cname, c.pi, p
)
)
if slacks:
for cname, slack in slacks.items():
c = prob.constraints[cname]
if abs(c.slack - slack) > eps:
dumpTestProblem(prob)
raise PulpError(
"Tests failed for solver {}:\nconstraint.slack {} == {} != {}".format(
solver, cname, c.slack, slack
)
)
if objective is not None:
z = prob.objective.value()
if abs(z - objective) > eps:
dumpTestProblem(prob)
raise PulpError(
f"Tests failed for solver {solver}:\nobjective {z} != {objective}"
)
def getSortedDict(prob, keyCons="name", keyVars="name"):
_dict = prob.toDict()
_dict["constraints"].sort(key=lambda v: v[keyCons])
_dict["variables"].sort(key=lambda v: v[keyVars])
return _dict
if __name__ == "__main__":
unittest.main()