Pyomo / pyomo

An object-oriented algebraic modeling language in Python for structured optimization problems.
https://www.pyomo.org
Other
2.01k stars 516 forks source link

Bug in pyomo/repn/linear.py #2862

Closed strahl21 closed 1 year ago

strahl21 commented 1 year ago

Summary

Solve a quadratic program (or QCQP) using cplex/gurobi with exponents that are written using floats, rather than integers

Steps to reproduce the issue

Use m.x1**2.0 instead of m.x1**2

$ python example.py
# example.py
from pyomo.environ import *

model = m = ConcreteModel()

m.x1 = Var(within=Reals, bounds=(0,10), initialize=0)

m.obj = Objective(sense=minimize, expr= (m.x1**2.0 + m.x1 - 2))

opt = SolverFactory('cplex')
opt.solve(m, tee=True)

Error Message

$ # Output message here, including entire stack trace, if available
Traceback (most recent call last):
  File "/home/will/Documents/research-minlp/mindtpy/pyomo/Lin_repn_bug/ex1223_solve_linear.py", line 28, in <module>
    opt.solve(m, tee=True)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/opt/base/solvers.py", line 597, in solve
    self._presolve(*args, **kwds)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/solvers/plugins/solvers/CPLEX.py", line 354, in _presolve
    ILMLicensedSystemCallSolver._presolve(self, *args, **kwds)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/opt/solver/shellcmd.py", line 224, in _presolve
    OptSolver._presolve(self, *args, **kwds)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/opt/base/solvers.py", line 706, in _presolve
    ) = self._convert_problem(
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/opt/base/solvers.py", line 757, in _convert_problem
    return convert_problem(
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/opt/base/convert.py", line 99, in convert_problem
    problem_files, symbol_map = converter.apply(*tmp, **tmpkw)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/solvers/plugins/converter/model.py", line 78, in apply
    (problem_filename, symbol_map_id) = instance.write(
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/core/base/block.py", line 1983, in write
    (filename, smap) = problem_writer(self, filename, solver_capability, io_options)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/repn/plugins/lp_writer.py", line 207, in __call__
    info = self.write(model, FILE, **io_options)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/repn/plugins/lp_writer.py", line 240, in write
    return _LPWriter_impl(ostream, config).write(model)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/repn/plugins/lp_writer.py", line 350, in write
    repn = objective_visitor.walk_expression(obj.expr)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/core/expr/visitor.py", line 269, in walk_expression
    result = self._process_node(root, RECURSION_LIMIT)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/core/expr/visitor.py", line 422, in _process_node_bex
    data.append(self._process_node(child, recursion_limit))
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/core/expr/visitor.py", line 435, in _process_node_bex
    return self.exitNode(node, data)
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/repn/linear.py", line 893, in exitNode
    return self.exit_node_dispatcher[(node.__class__, *map(itemgetter(0), data))](
  File "/home/will/anaconda3/envs/pyomoMinlp/lib/python3.9/site-packages/pyomo/repn/linear.py", line 342, in _handle_pow_ANY_constant
    for i in range(1, exp):
TypeError: 'float' object cannot be interpreted as an integer

Information on your system

Pyomo version: 6.6.1 Python version: 3.9 Operating system: Ubuntu 22.04 How Pyomo was installed (PyPI, conda, source): conda Solver (if applicable): cplex, also noticed the same issue with gurobi. Ipopt and baron had no issues

Additional information

I edited the source code (pyomo/repn/linear.py:342) with for i in range(1, int(exp)): and that prevents the error and should be correct because of the check in the condition.

jsiirola commented 1 year ago

Thank you for the detailed report. One question (for all, but especially @michaelbynum, @emma58): should we support an "integer tolerance" here? That is, should we treat x**2.0000001 as x**2 (and then expand the product term)?

michaelbynum commented 1 year ago

No. This is one spot I think we definitely do not want tolerances. It is exactly equal to an integer or it is not an integer. If it should be an integer, the user should make sure it is one.

jsiirola commented 1 year ago

I agree - but wanted to check