PuLP returns None for variables that have zero coefficients both in objective and constraints.
- Dominant language
- Python
- Stars
- 2.5k
- Forks
- 432
- PR merge metrics
- No merged PRs in 30d
Description
**Description:**
Consider a model where one or more variables are added to a constraint or the objective function but they all have zero coefficients everywhere in the model.
For example:
```
model.addConstraint( a * x + b * y >= c)
```
with `a`, `b`, `c` floats and `x`, and `y` LpVariables, and assume that `y` does not appear in the objective or in any other constraint apart from the one above.
If someone sets `b=0.0` before adding the constraint, then PuLP apparently omits `y` and invoking `y.value()` after solving the model will return None.
On the other hand, if one were to manually write an LP file with `y` listed among the variables but _without appearing in any constraint, or in the objective_, CBC would still write a feasible value for `y` in the solution file, usually the lower bound. (see MWE)
**Context:** I am writing a cutting plane model for dual optimization inside a lagrangian decomposition scheme. At the first iteration of the scheme the cutting plane has only one constraint, the first cut, and it can happen that one (dual) variable in the cut has an exact zero in the coefficient of the constraint. Then, querying the value of the variable after solving the model yields "None".
**Issue:** In general, this behaviour requires the user to be aware of which variables have zero coefficients everywhere in the model to avoid putting `None` where valid floats are expected.
On the other hand, for these "free" variables it is fine to return any feasible value, as it is already done by CBC and, IIRC, by other software like AMPL.
I thank you for your formidable work on PuLP and also for any help you may provide!
**MWE:**
Code:
```
from pulp import *
import sys
print(f"==> PuLP version:")
!{sys.executable} -m pip show pulp
problem = LpProblem(sense=LpMaximize)
z = LpVariable("z")
x = LpVariable("x",2,5)
y = LpVariable("y", 1,3)
problem.addConstraint(z+x+0.0*y <=1)
print("\n==>Solving problem as created in PuLP")
problem.writeLP("problem.lp")
problem.solve()
print("=>PuLP solution")
print(f"z={z.value()}")
print(f"x={x.value()}")
print(f"y={y.value()} <-- PROBLEM: this one is going to be None")
print("\n")
print("\n==> Solving problem manually written in LP format")
!cat problem2.lp
print("Calling CBC")
!cbc problem2.lp solve solu solution.txt
print("Solution computed by CBC")
!cat solution.txt
```
Output:
```==> PuLP version:
Name: PuLP
Version: 2.3
Summary: PuLP is an LP modeler written in python. PuLP can generate MPS or LP files and call GLPK, COIN CLP/CBC, CPLEX, and GUROBI to solve linear problems.
Home-page: https://github.com/coin-or/pulp
Author: J.S. Roy and S.A. Mitchell
Author-email: pulp@stuartmitchell.com
License: UNKNOWN
Location: /home/user/pyenv/experiments3.8/lib/python3.8/site-packages
Requires: amply
Required-by:
==>Solving problem as created in PuLP
=>PuLP solution
z=-1.0
x=2.0
y=None <-- PROBLEM: this one is going to be None
==> Solving problem manually written in LP format
\* NoName *\
Maximize
OBJ: z
Subject To
_C1: x + z <= 1
Bounds
1 <= y <= 3
2 <= x <= 5
z free
End
Calling CBC
Welcome to the CBC MILP Solver
Version: 2.9.9
Build Date: Aug 21 2017
command line - cbc problem2.lp solve solu solution.txt (default strategy 1)
### CoinLpIO::readLp(): Variable y does not appear in objective function or constraints
CoinLpIO::readLp(): Maximization problem reformulated as minimization
Presolve 0 (-1) rows, 0 (-3) columns and 0 (-2) elements
Empty problem - 0 rows, 0 columns and 0 elements
Optimal - objective value 1
After Postsolve, objective 1, infeasibilities - dual 0 (0), primal 0 (0)
Optimal objective 1 - 0 iterations time 0.002, Presolve 0.00
Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00
Solution computed by CBC
Optimal - objective value 1.00000000
0 z -1 0
1 x 2 1
2 y 1 0
```
Contributor guide
Assessment
This issue has not been assessed yet.