7

I don't know how to pass additional arguments through the minimize function to the constraint dictionary. I can successfully pass additional arguments to the objective function.

Documentation on minimize function is here: http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html#scipy.optimize.minimize

The constraints argument is a dict that has a field 'args', where args is a sequence. I'm sure this is where I need to pass in the additional arguments but I don't know the syntax. The closest I have got is below:

from scipy.optimize import minimize
def f_to_min (x, p):
    return (p[0]*x[0]*x[0]+p[1]*x[1]*x[1]+p[2])

f_to_min([1,2],[1,1,1]) # test function to minimize

p=[] # define additional args to be passed to objective function
f_to_min_cons=({'type': 'ineq', 'fun': lambda x, p : x[0]+p[0], 'args': (p,)}) # define constraint

p0=np.array([1,1,1])
minimize(f_to_min, [1,2], args=(p0,), method='SLSQP', constraints=f_to_min_cons)

I get the following error

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-19-571500063c9e> in <module>()
      1 p0=np.array([1,1,1])
----> 2 minimize(f_to_min, [1,2], args=(p0,), method='SLSQP', constraints=f_to_min_cons)

C:\Python27\lib\site-packages\scipy\optimize\_minimize.pyc in minimize(fun, x0, args,     method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    356     elif meth == 'slsqp':
    357         return _minimize_slsqp(fun, x0, args, jac, bounds,
--> 358                                constraints, **options)
    359     else:
    360         raise ValueError('Unknown solver %s' % method)

C:\Python27\lib\site-packages\scipy\optimize\slsqp.pyc in _minimize_slsqp(func, x0,     args, jac, bounds, constraints, maxiter, ftol, iprint, disp, eps, **unknown_options)
    298     # meq, mieq: number of equality and inequality constraints
    299     meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in     cons['eq']]))
--> 300     mieq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in     cons['ineq']]))
    301     # m = The total number of constraints
    302     m = meq + mieq

<ipython-input-18-163ef1a4f6fb> in <lambda>(x, p)
----> 1 f_to_min_cons=({'type': 'ineq', 'fun': lambda x, p : x[0]+p[0], 'args': (p,)})

IndexError: list index out of range

I'm accessing the first element of the additional parameter so I shouldn't have an out of range error.

If you remove the constraints=f_to_min_cons argument from the minimize function then the code above works.

Cœur
  • 37,241
  • 25
  • 195
  • 267
user2121724
  • 79
  • 1
  • 1
  • 4
  • I have scipy 0.9 on this PC, so there is no `minimize` and I cannot test it. But you have a `p = []` in your code, hence the `index out of range` when you try to get `p[0]`. Change your `f_to_min_cons` definition so that it has `'args' : (p0,)` and you should be on your way. – Jaime Mar 01 '13 at 04:56
  • 1
    In addition to what @Jaime said already: there seems to be a syntax error in the code from the question: check the closing curly bracket *before* the `'args'` argument. – ev-br Mar 01 '13 at 09:50
  • Thanks for your comments. Yes, this does work. However, if I understand you correctly, I believe that p0 is not being passed through the minimize function to the constraint dictionary. i.e. If I were to change the minimize argument 'args'=(p0,) to 'args'=(p1,) then p1 would be used in the objective function, f_to_min, but p0 would be used in the the constraint dictionary. – user2121724 Mar 01 '13 at 22:10
  • Yes, you're right about the syntax error. I must have edited the post here by hand instead of copy-pasting from the Python code. Have updated. – user2121724 Mar 01 '13 at 22:13
  • Yes, that's exactly what I think is happening, which is also consistent with the `c['fun'](x, *c['args'])` in your error message: the `args` of `minimize` are not passed on to the constraint `'fun'`. – Jaime Mar 02 '13 at 05:05
  • 3
    Thanks again for your comment. Just to confirm. There is no way to pass additional arguments to the constraint functions from the minimize call. If so, I don't understand why the minimize function is set up in this way that additional arguments can be passed to the cost function but not to the constraint functions. – user2121724 Mar 02 '13 at 10:58
  • It actually makes sense the way they have it set up. There is absolutely no reason why the additional parameters to your cost function would be the same as the additional parameters to your constraint function(s) and I have solved many problems where this is the case. – PaxRomana99 Aug 08 '18 at 12:36

1 Answers1

2

The answer simply, is that p = [] has no elements and no length, and so p[0] is out of bounds.

The following, where we set p = [0], runs without error. What p should actually hold is of course, not something that we can answer with the information given.

import numpy as np

from scipy.optimize import minimize
def f_to_min (x, p):
    return (p[0]*x[0]*x[0]+p[1]*x[1]*x[1]+p[2])

f_to_min([1,2],[1,1,1]) # test function to minimize

p=[0] # define additional args to be passed to the constraint
f_to_min_cons=({'type': 'ineq', 'fun': lambda x, p : x[0]+p[0], 'args': (p,)},) # define constraint

p0=np.array([1,1,1]) # args to be passed to the objective function
minimize(f_to_min, [1,2], args=(p0,), method='SLSQP', constraints=f_to_min_cons)
DrM
  • 2,404
  • 15
  • 29
  • Your answer shows the key point that the args passed to the constraint are not the same as the args passed to the objective function, since one might erroneously assume both parameter lists may be identical and passed from minimize to both, constraint and objective function. In addition, the variables assigned must exist at the definition of the constraint. Anyway, for sake of completeness, please correct the comments in the code for ``p # passed to constraint`` and add one for ``p0 # passed to objective function``. – Dominik Kern Jun 08 '23 at 12:28