Closed moorepants closed 3 months ago
A call to scipy.sparse.vstack()
fails:
> /home/moorepants/src/cyipopt/cyipopt/scipy_interface.py(288)_get_sparse_jacobian_structure()
286 jacobians.append(coo_array(np.ones((con_val.size, x0.size))))
287 con_jac_is_sparse.append(False)
--> 288 J = scipy.sparse.vstack(jacobians)
289 return con_jac_is_sparse, J.row, J.col
290
ipdb> jacobians
[<4 sparse array of type '<class 'numpy.float64'>'
with 4 stored elements in COOrdinate format>, <4 sparse array of type '<class 'numpy.float64'>'
with 4 stored elements in COOrdinate format>]
In SciPy 1.12 it works:
ipdb> jacobians
[<1x4 sparse array of type '<class 'numpy.float64'>'
with 4 stored elements in COOrdinate format>, <1x4 sparse array of type '<class 'numpy.float64'>'
with 4 stored elements in COOrdinate format>]
ipdb> scipy.sparse.vstack(jacobians)
<2x4 sparse array of type '<class 'numpy.float64'>'
with 8 stored elements in COOrdinate format>
The list of two sparse column vectors is:
ipdb> jacobians[0].toarray()
array([[ 2., 10., 10., 2.]])
ipdb> jacobians[1].toarray()
array([[25., 5., 5., 25.]])
In SciPy 1.13.1 the shape of the jacobians is different:
ipdb> jacobians[0].toarray()
array([ 2., 10., 10., 2.])
ipdb> jacobians[1].toarray()
array([25., 5., 5., 25.])
ipdb> jacobians[0].shape
(4,)
ipdb> jacobians[1].shape
(4,)
Maybe the calls to coo_array()
are returning different dimensions than before:
def _get_sparse_jacobian_structure(constraints, x0):
con_jac_is_sparse = []
jacobians = []
x0 = np.asarray(x0)
if isinstance(constraints, dict):
constraints = (constraints, )
if len(constraints) == 0:
return [], [], []
for con in constraints:
con_jac = con.get('jac', False)
if con_jac:
if isinstance(con_jac, bool):
_, jac_val = con['fun'](x0, *con.get('args', []),
**con.get('kwargs', {}))
else:
jac_val = con_jac(x0, *con.get('args', []),
**con.get('kwargs', {}))
# check if dense or sparse
if isinstance(jac_val, coo_array):
jacobians.append(jac_val)
con_jac_is_sparse.append(True)
else:
# Creating the coo_array from jac_val would yield to
# wrong dimensions if some values in jac_val are zero,
# so we assume all values in jac_val are nonzero
jacobians.append(coo_array(np.ones_like(np.atleast_2d(jac_val))))
con_jac_is_sparse.append(False)
else:
# we approximate this jacobian later (=dense)
con_val = np.atleast_1d(con['fun'](x0, *con.get('args', []),
**con.get('kwargs', {})))
jacobians.append(coo_array(np.ones((con_val.size, x0.size))))
con_jac_is_sparse.append(False)
J = scipy.sparse.vstack(jacobians)
return con_jac_is_sparse, J.row, J.col
This seems to be the issue: https://github.com/scipy/scipy/issues/20415
Fixed in #257 , the tests were simply updated to work with scipy 1.13 when calling coo_array()
such that 2d arrays are passed in. No actual issue in the internal handling in cyipopt but users will have to give proper input (which changed without warning in SciPy 1.13).