From dc0d0f69655c7109c0d02ecf2d3b443dd7a470ea Mon Sep 17 00:00:00 2001 From: Gabriel Carneiro Date: Wed, 6 Aug 2025 15:18:01 -0300 Subject: [PATCH 1/3] Add LpBinaryVariable and LpIntegerVariable classes Introduce new classes for binary and integer variables, extending LpVariable. Added related tests to ensure correct behavior, including bounds handling for integer variables. --- pulp/pulp.py | 18 ++++++++++++++++++ pulp/tests/test_pulp.py | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/pulp/pulp.py b/pulp/pulp.py index 0e086753..df8ae910 100644 --- a/pulp/pulp.py +++ b/pulp/pulp.py @@ -718,6 +718,24 @@ def unfixValue(self): self.bounds(self._lowbound_original, self._upbound_original) +class LpBinaryVariable(LpVariable): + """ + This class models an LP Binary Variable with the specified associated parameters + """ + + def __init__(self, name: str, **kwargs): + LpVariable.__init__(self, name=name, cat=const.LpBinary, **kwargs) + + +class LpIntegerVariable(LpVariable): + """ + This class models an LP Integer Variable with the specified associated parameters + """ + + def __init__(self, name: str, **kwargs): + LpVariable.__init__(self, name=name, cat=const.LpInteger, **kwargs) + + class LpAffineExpression(dict): """ A linear combination of :class:`LpVariables`. diff --git a/pulp/tests/test_pulp.py b/pulp/tests/test_pulp.py index a0782104..7875c039 100644 --- a/pulp/tests/test_pulp.py +++ b/pulp/tests/test_pulp.py @@ -14,9 +14,11 @@ from pulp import ( FixedElasticSubProblem, LpAffineExpression, + LpBinaryVariable, LpConstraint, LpConstraintVar, LpFractionConstraint, + LpIntegerVariable, LpProblem, LpVariable, PulpSolverError, @@ -1869,6 +1871,17 @@ def test_decimal_815_addinplace(self): second_expression_2 = x * m2 - 6 - y self.assertEqual(str(second_expression_2), "8.1*x - y - 6.0") + def test_lp_binary_variable(self): + self.assertTrue(LpBinaryVariable("x").isBinary()) + self.assertTrue(LpBinaryVariable("x").isInteger()) + + def test_lp_integer_variable(self): + self.assertTrue(LpIntegerVariable("x").isInteger()) + + def test_lp_integer_variable_with_bounds(self): + self.assertEqual(LpIntegerVariable("x", lowBound=0).lowBound, 0) + self.assertEqual(LpIntegerVariable("x", upBound=10).upBound, 10) + class PULP_CBC_CMDTest(BaseSolverTest.PuLPTest): solveInst = solvers.PULP_CBC_CMD From 7eea1535a93ada61ce84c2ce8a1491609f132649 Mon Sep 17 00:00:00 2001 From: Gabriel Carneiro Date: Wed, 6 Aug 2025 15:34:16 -0300 Subject: [PATCH 2/3] Add support for setting initial values for LpVariable Previously, LpVariable did not allow specifying an initial value directly. Corresponding test cases have been added to ensure correct functionality. --- pulp/pulp.py | 3 +++ pulp/tests/test_pulp.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/pulp/pulp.py b/pulp/pulp.py index df8ae910..3a1d3337 100644 --- a/pulp/pulp.py +++ b/pulp/pulp.py @@ -274,12 +274,15 @@ def __init__( upBound: Optional[float] = None, cat: str = const.LpContinuous, e=None, + varValue=None, ): LpElement.__init__(self, name) self._lowbound_original = self.lowBound = lowBound self._upbound_original = self.upBound = upBound self.cat = cat self.varValue = None + if varValue is not None: + self.setInitialValue(val=varValue) self.dj = None if cat == const.LpBinary: self._lowbound_original = self.lowBound = 0 diff --git a/pulp/tests/test_pulp.py b/pulp/tests/test_pulp.py index 7875c039..248ff74b 100644 --- a/pulp/tests/test_pulp.py +++ b/pulp/tests/test_pulp.py @@ -1882,6 +1882,12 @@ def test_lp_integer_variable_with_bounds(self): self.assertEqual(LpIntegerVariable("x", lowBound=0).lowBound, 0) self.assertEqual(LpIntegerVariable("x", upBound=10).upBound, 10) + def test_lp_variable_with_0_as_initial_value(self): + self.assertEqual(LpVariable("x", varValue=0).varValue, 0) + + def test_lp_variable_with_10_as_initial_value(self): + self.assertEqual(LpVariable("x", varValue=10).varValue, 10) + class PULP_CBC_CMDTest(BaseSolverTest.PuLPTest): solveInst = solvers.PULP_CBC_CMD From 696b3dcda2825fc73923580b877d361f6d2a5309 Mon Sep 17 00:00:00 2001 From: Gabriel Carneiro Date: Wed, 6 Aug 2025 15:40:22 -0300 Subject: [PATCH 3/3] Refactor variable instantiation to include varValue in `fromDataclass`. Updated the variable instantiation to set `varValue` directly in the constructor. --- pulp/pulp.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pulp/pulp.py b/pulp/pulp.py index 3a1d3337..cd905792 100644 --- a/pulp/pulp.py +++ b/pulp/pulp.py @@ -333,10 +333,13 @@ def fromDataclass(cls, mps: mpslp.MPSVariable): :rtype: :LpVariable """ var = cls( - name=mps.name, lowBound=mps.lowBound, upBound=mps.upBound, cat=mps.cat + name=mps.name, + lowBound=mps.lowBound, + upBound=mps.upBound, + cat=mps.cat, + varValue=mps.varValue, ) var.dj = mps.dj - var.varValue = mps.varValue return var def toDict(self) -> dict[str, Any]: