# Pyomo CBC 1.#j error

I am using to solve my model Pyomo/CBC combination. But rarely, CBC Gap shows 1.#j and pyomo generate an error. Hence, it doesn't get solution. How can I solve this problem?

Screen output:

Result - Stopped on time limit

Objective value:                26848000.00000000
Lower bound:                    0.000
Gap:                            1.#J
Enumerated nodes:               336653
Total iterations:               620783
Time (CPU seconds):             62.14
Time (Wallclock seconds):       62.14

Total time (CPU seconds):       62.15   (Wallclock seconds):       62.15

ERROR:writeSql:could not convert string to float: '1.#J'
Traceback (most recent call last):
.
.
.
opt_success = opt.solve(model, tee=True)
File "C:\Users\python\AppData\Local\Programs\Python\Python37\lib\site-packages
\pyomo\opt\base\solvers.py", line 605, in solve
result = self._postsolve()
File "C:\Users\python\AppData\Local\Programs\Python\Python37\lib\site-packages
\pyomo\solvers\plugins\solvers\CBCplugin.py", line 870, in _postsolve
results = super(CBCSHELL, self)._postsolve()
File "C:\Users\python\AppData\Local\Programs\Python\Python37\lib\site-packages
\pyomo\opt\solver\shellcmd.py", line 270, in _postsolve
results = self.process_output(self._rc)
File "C:\Users\python\AppData\Local\Programs\Python\Python37\lib\site-packages
\pyomo\opt\solver\shellcmd.py", line 327, in process_output
results = self.process_logfile()
File "C:\Users\python\AppData\Local\Programs\Python\Python37\lib\site-packages
\pyomo\solvers\plugins\solvers\CBCplugin.py", line 563, in process_logfile
gap = float(tokens[1])
ValueError: could not convert string to float: '1.#J'
Error <class 'ValueError'> value could not convert string to float: '1.#J' diger
<traceback object at 0x000000000D0F0288>


My solution is changing CBCplugin.py related line with try-except. But I can not predict potential side effects on pyomo.

My answer: I changed CBCplugin.py, line 563:

 gap = float(tokens[1])


with:

  try:
gap = float(tokens[1])
except:
gap = 0.0


1.#J in C++ is the output obtained when printing a formatted double equal to infinity (1.#INF). See this related stackoverflow question.

The CBC gap is computed this way in CbcSolver.cpp:

if (babModel_->bestSolution()) {
sprintf(generalPrint + strlen(generalPrint),
"Gap:                            %.2f\n",
(babModel_->getObjValue() - babModel_->getBestPossibleObjValue()) / fabs(babModel_->getBestPossibleObjValue()));
}


If babModel_->getBestPossibleObjValue() is equal to 0.0, you will obtain a gap of 1.#INF which will then be formatted to 1.#J. This is also what other solvers do, see for example Gurobi MIPGap documentation which returns infinity in such case. Note that this matches your outputted lower bound of 0.000.

As for pyomo, returning a gap of 0 could be wrong in most cases, that is, unless the best solution is also 0. Returning some form of infinity, such as numpy.inf, could be the correct solution. Although I didn't check if pyomo would handle that gracefully. Looking quickly trough the other pyomo solver plugins, I don't see any handling of a MIP gap being anything other than a float, which seems problematic.