Skip to content

Loading…

fix constraint handling in SLSQP (ticket #1657) #210

Closed
wants to merge 3 commits into from

2 participants

@pv
SciPy member
pv commented

Looks good to me.

@dlax
SciPy member

Pushed: 0187673 .. 9923353

Also, does the bug have to be closed manually or is it automatic?

@dlax dlax closed this
@pv
SciPy member
pv commented

Manually, the Trac plugin does not know about pull requests.

@dlax
SciPy member
@pv
SciPy member
pv commented

You should now be able to.

@jnothman jnothman referenced this pull request
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 10, 2012
  1. @dlax
  2. @dlax
  3. @dlax

    BUG: use approx_jacobian instead of approx_fprime in SLSQP

    dlax committed
    The latter expects a scalar function whereas the former (now) works for
    both scalar and vector functions.
This page is out of date. Refresh to see the latest.
Showing with 42 additions and 7 deletions.
  1. +7 −7 scipy/optimize/slsqp.py
  2. +35 −0 scipy/optimize/tests/test_slsqp.py
View
14 scipy/optimize/slsqp.py
@@ -10,7 +10,7 @@
from scipy.optimize._slsqp import slsqp
from numpy import zeros, array, linalg, append, asfarray, concatenate, finfo, \
sqrt, vstack, exp, inf, where, isinf, atleast_1d
-from optimize import approx_fprime, wrap_function
+from optimize import wrap_function
__docformat__ = "restructuredtext en"
@@ -43,7 +43,7 @@ def approx_jacobian(x,func,epsilon,*args):
"""
x0 = asfarray(x)
- f0 = func(*((x0,)+args))
+ f0 = atleast_1d(func(*((x0,)+args)))
jac = zeros([len(x0),len(f0)])
dx = zeros(len(x0))
for i in range(len(x0)):
@@ -251,7 +251,7 @@ def _minimize_slsqp(func, x0, args=(), jac=None, bounds=None,
if cjac is None:
# approximate jacobian function
def cjac(x, *args):
- return approx_fprime(x, con['fun'], epsilon, *args)
+ return approx_jacobian(x, con['fun'], epsilon, *args)
# update constraints' dictionary
cons[ctype] += ({'fun' : con['fun'],
@@ -275,11 +275,11 @@ def cjac(x, *args):
# Wrap func
feval, func = wrap_function(func, args)
- # Wrap fprime, if provided, or approx_fprime if not
+ # Wrap fprime, if provided, or approx_jacobian if not
if fprime:
geval, fprime = wrap_function(fprime, args)
else:
- geval, fprime = wrap_function(approx_fprime, (func, epsilon))
+ geval, fprime = wrap_function(approx_jacobian, (func, epsilon))
# Transform x0 into an array.
x = asfarray(x0).flatten()
@@ -287,8 +287,8 @@ def cjac(x, *args):
# Set the parameters that SLSQP will need
# meq, mieq: number of equality and inequality constraints
- meq = sum(map(len, [c['fun'](x, *c['args']) for c in cons['eq']]))
- mieq = sum(map(len, [c['fun'](x, *c['args']) for c in cons['ineq']]))
+ meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['eq']]))
+ mieq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['ineq']]))
# m = The total number of constraints
m = meq + mieq
# la = The number of constraints, or 1 if there are no constraints
View
35 scipy/optimize/tests/test_slsqp.py
@@ -57,6 +57,14 @@ def fprime_eqcon(self, x, sign=1.0):
""" Equality constraint, derivative """
return np.array([[1, -1]])
+ def f_eqcon_scalar(self, x, sign=1.0):
+ """ Scalar equality constraint """
+ return self.f_eqcon(x, sign)[0]
+
+ def fprime_eqcon_scalar(self, x, sign=1.0):
+ """ Scalar equality constraint, derivative """
+ return self.fprime_eqcon(x, sign)[0].tolist()
+
def f_ieqcon(self, x, sign=1.0):
""" Inequality constraint """
return np.array([x[0] - x[1] - 1.0])
@@ -141,6 +149,21 @@ def test_minimize_equality_given2(self):
assert_(info['success'], info['message'])
assert_allclose(x, [1, 1])
+ def test_minimize_equality_given_cons_scalar(self):
+ """ \
+ Minimize with method='SLSQP': scalar equality constraint, given
+ jacobian for fun and const.
+ """
+ x, info = minimize(self.fun, [-1.0, 1.0], method='SLSQP',
+ jac=self.jac, args = (-1.0,),
+ constraints={'type': 'eq',
+ 'fun': self.f_eqcon_scalar,
+ 'args': (-1.0, ),
+ 'jac': self.fprime_eqcon_scalar},
+ options=self.opts, full_output=True)
+ assert_(info['success'], info['message'])
+ assert_allclose(x, [1, 1])
+
def test_minimize_inequality_given(self):
""" \
Minimize with method='SLSQP': inequality constraint, given jacobian.
@@ -254,5 +277,17 @@ def test_bound_equality_given2(self):
assert_(imode == 0, imode)
assert_array_almost_equal(x, [0.8, 0.8], decimal=3)
+ def test_scalar_constraints(self):
+ """ Ticket #1657 """
+ x = fmin_slsqp(lambda z: z**2, [3.],
+ ieqcons=[lambda z: z[0] - 1],
+ iprint=0)
+ assert_array_almost_equal(x, [1.])
+
+ x = fmin_slsqp(lambda z: z**2, [3.],
+ f_ieqcons=lambda z: [z[0] - 1],
+ iprint=0)
+ assert_array_almost_equal(x, [1.])
+
if __name__ == "__main__":
run_module_suite()
Something went wrong with that request. Please try again.