anar
anar

Reputation: 543

puLP solver error

I am trying to solve MILP in puLP (Python), and I keep getting the following error:

Traceback (most recent call last):
  File "main_lp.py", line 63, in <module>
    ans = solve_lp(C)
  File "/home/ashwin/Documents/Williams/f2014/math317_or/project/solve_lp.py", line 36, in solve_lp
    prob.solve()
  File "/usr/local/lib/python2.7/dist-packages/PuLP-1.5.6-py2.7.egg/pulp/pulp.py", line 1619, in solve
    status = solver.actualSolve(self, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/PuLP-1.5.6-py2.7.egg/pulp/solvers.py", line 1283, in actualSolve
    return self.solve_CBC(lp, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/PuLP-1.5.6-py2.7.egg/pulp/solvers.py", line 1346, in solve_CBC
    raise PulpSolverError("Pulp: Error while executing "+self.path)
pulp.solvers.PulpSolverError: Pulp: Error while executing /usr/local/lib/python2.7/dist-packages/PuLP-1.5.6-py2.7.egg/pulp/solverdir/cbc-32

For my linear programming problem, I am attempting to take sums of different vectors as the constraint, and I think I must have done that wrong somehow, because a much simpler problem works with no hitches. I have attached the code (C is an N by N numpy array).

def solve_lp(C):
    N = len(C)
    prob=LpProblem('Scheduling',LpMinimize)

    X = [[LpVariable('X' + str(i+1) + str(j+1), 0, C[i,j],LpBinary)
          for j in range(N)] for i in range(N)]
    X = np.array(X)
    X_o = [LpVariable('X0' + str(i), 0, None, LpBinary) for i in range(N)]
    X_t = [LpVariable('X' + str(i) + 't', 0, None, LpBinary) for i in range(N)]

    # Objective Function                                                                                                                                                
    ones_vec = list(np.ones(len(X_o)))
    prob += lpDot(ones_vec,X_o), 'Minimize Buses'

    # Constraints                                                                                                                                                       
    for i in range(N):
        row = list(X[i,:]) + [X_t[i]]
        ones_vec = list(np.ones(len(row)))
        prob += lpDot(ones_vec, row) == 1, 'Only one destination for ' + str(i)

    for j in range(N):
        col = list(X[:,j]) + [X_o[j]]
        ones_vec = list(np.ones(len(col)))
        prob += lpDot(ones_vec,col) == 1, 'Only one source for ' + str(j)

    prob.solve()
    return X, value(prob.objective)

Upvotes: 8

Views: 29184

Answers (10)

Szpilman
Szpilman

Reputation: 1

I had a similar problem, and after spending hours (running in both google colab and locally on jupyter notebook) and printing the variables I realized that duplicate LpVariables in my problem cause the error after changing the names, it worked without any error.

Upvotes: 0

Sibusiso
Sibusiso

Reputation: 1

On your LP problem remove NAN or nan from your equation that you want to solve

Upvotes: 0

Billal Naseem
Billal Naseem

Reputation: 116

I recently had the same error raised aswell. The reason this error code was raised in my case was that my data frame was not correctly populated. i incorrectly had NaN on the RHS on some of my constraints

What is had was something like:

Matrix = df.pivot(1st_dimension, 2nd_dimension, value)

This operation automatically puts NaN for the instances that are not in the original dataframe.

in my case the NaN'sare replaced with 0 which is what i was expecting it to be:

Matrix = Matrix.fillna(0)

Upvotes: 2

xiaoxia
xiaoxia

Reputation: 21

I had a similar problem, and indeed with duplicate LpVariable names just like levis501's answer and aleon answered.

my code was:

var = [[pulp.LpVariable(f'x{i}{j}', lowBound=0, cat=pulp.LpInteger) for j in range(col)] for i in range(row)]

when i=1 j=11, x would be x111, and when i=11 j=1, x also would be x111

I changed to:

var = [[pulp.LpVariable(f'x{i}_{j}', lowBound=0, cat=pulp.LpInteger) for j in range(col)] for i in range(row)]

After changing, it runs successfully.

Upvotes: 2

aleon
aleon

Reputation: 61

I think that you have duplicate LpVariable names. I just had the same problem and saw it thanks to levis501's answer. Here:

X = [[LpVariable('X' + str(i+1) + str(j+1), 0, C[i,j],LpBinary)
      for j in range(N)] for i in range(N)]

X contains some variables with the same name. For example for i = 0 and j = 10 you get 'X111', and for i = 10 and j = 0 you also get 'X111'.

Upvotes: 5

GrayOnGray
GrayOnGray

Reputation: 335

I had this problem today, and it was because the temporary files for CBC were trying to be written in a location whose path had spaces in it, and the command that pulp passes to subprocess.Popen() to run CBC does not use quotes, and thus the command was misinterpreted and CBC couldn't find the location to create temp files.

For this I found two solutions:

(1) Explicitly set a temporary file directory that doesn't have spaces in it,

pulp.LpSolverDefault.tmpDir = self.tmp_file_dir  # tmp_file_dir can't have spaces!
prob.solve()

or (2) don't use CBC (my problem is small)

prob.solve(pulp.GLPK_CMD())

I have a work-related constraint that a lot of my work is stuck in directories that have spaces.

Upvotes: 0

Pedro Esmeriz
Pedro Esmeriz

Reputation: 61

I recently had a similar problem due to Nan inputs in the model. I had the data in a DataFrame where some the cells should not bee converted to variables to improve performance. However, upon creating the objective function and the constraints, I noticed the presence of Nan and when I changed them it worked perfectly.

Upvotes: 6

T.S. Wolter
T.S. Wolter

Reputation: 11

I experienced the same issue when launching multiple instances of the LPSolver class. As fmars stated, the problem is that the path 'tmpSol' does not exist, which is defined in the following lines of code within the solvers.py file of pulp:

pid = os.getpid()
tmpLp = os.path.join(self.tmpDir, "%d-pulp.lp" % pid)
tmpMps = os.path.join(self.tmpDir, "%d-pulp.mps" % pid)
tmpSol = os.path.join(self.tmpDir, "%d-pulp.sol" % pid)

This bit of code appears in every solver. The problem is that these paths are deleted later on, but may coincide for different instances of the LPSolver class (as the variable pid is not unique).

The solution is to get a unique path for each instance of LPSolver, using, for example, the current time. Replacing the above lines by the following four will do the trick.

currentTime = time()
tmpLp = os.path.join(self.tmpDir, "%f3-pulp.lp" % currentTime)
tmpMps = os.path.join(self.tmpDir, "%f3-pulp.mps" % currentTime)
tmpSol = os.path.join(self.tmpDir, "%f3-pulp.sol" % currentTime)

Don't forget to

from time import time

Cheers, Tim

Upvotes: 1

fmars
fmars

Reputation: 147

I have met some similar problem which because of some PuLP's bug. When some problem is infeasible and the solver failed to solve the problem, PuLP raise an exception rather than return status equals to infeasible. Below is the reason.

(You may first want to check out latest codebase of PuLP because the line number you paste doesn't match the latest one. I'll explain based on latest one but you can look at yours very simply.)

https://github.com/coin-or/pulp/blob/master/src/pulp/solvers.py#L1405-L1406 This is where exception prompt.

   if not os.path.exists(tmpSol):
      raise PulpSolverError("Pulp: Error while executing "+self.path) 

tmpSol is the temporary file where stores the solution. If PuLP cannot find such solution file, it will throw the exception you saw. And the bug I mentioned above is, if the problem itself is infeasible, then PuLP won't be able to generate such temporary file. So it will always throw such exception.

One thing you can do is, send a pull request to PuLP repo and fix it. And a simple workaround is, rather than directly invoke

 prob.solve()

in your code, you should always do

try:
     prob.solve()
except Exception:
     logger.debug('Problem infeasible')

Upvotes: 0

levis501
levis501

Reputation: 4207

Make sure you don't have duplicate LpVariable names, and watch out for LpVariable names with the unsupported characters -+[] ->/ since all of those characters are silently converted to underscores _

Setting LpSolverDefault.msg = 1 before calling prob.solve() may help by printing the solvers output to the console.

Upvotes: 11

Related Questions