Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nl_writer does not cast Boolean variable values to [0, 1] #2928

Closed
mdealencar opened this issue Jul 31, 2023 · 0 comments · Fixed by #2953
Closed

nl_writer does not cast Boolean variable values to [0, 1] #2928

mdealencar opened this issue Jul 31, 2023 · 0 comments · Fixed by #2953

Comments

@mdealencar
Copy link

Summary

When using SCIP as the solver (possibly with other .nl file-based solvers as well), any initialized Boolean variable will make SCIP fail ("ERROR: expected double"). The obvious workaround is to declare the variable as Binary and explicitly cast (False, True) to (0, 1).

Steps to reproduce the issue

# adapted from knapsack-pyomo.py

import pyomo.environ as pyo

v = {'hammer':8, 'wrench':3, 'screwdriver':6, 'towel':11}
w = {'hammer':5, 'wrench':7, 'screwdriver':4, 'towel':3}
limit = 14
items = list(sorted(v.keys()))

# Create model
m = pyo.ConcreteModel()

# Variables
m.x = pyo.Var(items, within=pyo.Boolean, initialize=True)

# Objective
m.value = pyo.Objective(expr=sum(v[i]*m.x[i] for i in items), sense=pyo.maximize)

# Constraint
m.weight = pyo.Constraint(expr=sum(w[i]*m.x[i] for i in items) <= limit)

# Write .nl
m.write('knapsack.nl')

Which generates the file knapsack.nl:

g3 1 1 0        # problem unknown
 4 1 1 0 0      # vars, constraints, objectives, ranges, eqns
 0 0 0 0 0 0    # nonlinear constrs, objs; ccons: lin, nonlin, nd, nzlb
 0 0    # network constraints: nonlinear, linear
 0 0 0  # nonlinear vars in constraints, objectives, both
 0 0 0 1        # linear network variables; functions; arith, flags
 4 0 0 0 0      # discrete variables: binary, integer, nonlinear (b,c,o)
 4 4    # nonzeros in Jacobian, obj. gradient
 0 0    # max name lengths: constraints, variables
 0 0 0 0 0      # common exprs: b,c,o,c1,o1
C0
n0
O0 1
n0
x4
0 True
1 True
2 True
3 True
r
1 14
b
0 0 1
0 0 1
0 0 1
0 0 1
k3
1
2
3
J0 4
0 5
1 4
2 3
3 7
G0 4
0 8
1 6
2 11
3 3

Error Message

SCIP output to scip knapsack.nl -AMPL:

SCIP version 8.0.3 [precision: 8 byte] [memory: block] [mode: optimized] [LP solver: Soplex 6.0.3] [GitHash: 62fab8a2e3]
Copyright (C) 2002-2022 Konrad-Zuse-Zentrum fuer Informationstechnik Berlin (ZIB)

External libraries:
  Soplex 6.0.3         Linear Programming Solver developed at Zuse Institute Berlin (soplex.zib.de) [GitHash: f900e3d0]
  CppAD 20180000.0     Algorithmic Differentiation of C++ algorithms developed by B. Bell (github.com/coin-or/CppAD)
  ZLIB 1.2.13          General purpose compression library by J. Gailly and M. Adler (zlib.net)
  AMPL/MP 4e2d45c4     AMPL .nl file reader library (github.com/ampl/mp)
  PaPILO 2.1.2         parallel presolve for integer and linear optimization (github.com/scipopt/papilo) [GitHash: 2fe2543]
  bliss 0.77           Computing Graph Automorphism Groups by T. Junttila and P. Kaski (www.tcs.hut.fi/Software/bliss/)
  Ipopt 3.14.12        Interior Point Optimizer developed by A. Waechter et.al. (github.com/coin-or/Ipopt)

user parameter file <scip.set> not found - using default parameters
read problem <knapsack.nl>
============

[reader_nl.cpp:1355] ERROR: knapsack.nl:16:3: expected double
[scipshell.c:216] ERROR: Error <-2> in function call
[scipshell.c:272] ERROR: Error <-2> in function call
[scipshell.c:559] ERROR: Error <-2> in function call
SCIP Error (-2): read error

Information on your system

Pyomo version: 6.5.0
Python version: 3.10.10
Operating system: Windows 10
How Pyomo was installed (PyPI, conda, source): conda
Solver (if applicable): SCIP

Additional information

pyomo/repn/plugins/nl_writer.pynl_write.py uses calls to repr() extensively, mostly as f-strings (f'var {value!r}'). Since pyomo stores the values for boolean variables as numpy.bool_ type, the use of repr() alone is not adequate to write their values as SCIP-readable .nl files.

The above case can be fixed by replacing the code block starting at this line:

         _init_lines = [
             f'{var_idx} {info[0].value!r}{col_comments[var_idx]}\n'
             for var_idx, info in enumerate(variables)
             if info[0].value is not None
         ]

by this block:

         _init_lines = []
         for var_idx, info in enumerate(variables):
             if info[0].value is not None:
                 nonbool_value = info[0].value
                 if isinstance(nonbool_value, np.bool_):
                     nonbool_value = int(info[0].value)
                 _init_lines.append(f'{var_idx} {nonbool_value!r}{col_comments[var_idx]}\n')

This is probably not the way to fix this bug. Maybe Boolean variables need to be cast to Binary [0, 1] before calling the writer. Otherwise, there are likely other place in the writer code that would need changing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants