Search code examples
pythonarraysboundsscipy-optimizescipy-optimize-minimize

Setting bounds of a specific array subset of x0 scipy python


I need to set different bounds for each subset of the x0 array in scipy.optimize.minimize() function.

This is what I tried so far:

    x0 = np.zeros(20)
    
    # disp = x0[0:5]
    # w = x0[5:10]
    # qi = x0[10:15]
    # qai = x0[15:20]
    
    #bonds
    bnds = (((-np.inf, np.inf) for i in x0[0:5]), ((0, 1) for i in x0[5:10]), ((0, np.inf) for i in x0[10:15]), ((int(-1000000), int(100000000)) for i in x0[15:20]))

cons = [{'type': 'ineq', 'fun': lambda x: x[10:15] - lotMin * x[5:10]},
        {'type': 'eq', 'fun': lambda x: x[15:20] - x[10:15] / arrot},
        {'type': 'ineq', 'fun': lambda x: x[0:5]},
        {'type': 'ineq', 'fun': lambda x: x[15:20] - D},
        {'type': 'ineq', 'fun': lambda x: -(x[10:15] - M * x[5:10])},
        {'type': 'ineq', 'fun': lambda x: x[10:15] - x[5:10]},
        {'type': 'eq', 'fun': lambda x: x[0:5] - Disp_0 - x[10:15] + D}]

res = minimize(fun=lambda x: sum(x[0:4]*ho)+co*sum(x[5:9]), constraints=cons, x0=x0, bounds=bnds,
               method='SLSQP', options=dict(ftol=1e-6))

This is the error I get:

Traceback (most recent call last):
  File "C:\Users\davide.tamagnini.con\AppData\Roaming\JetBrains\PyCharmCE2021.1\scratches\scratch_1.py", line 84, in <module>
    res = minimize(fun=lambda x: sum(x[0:4]*ho)+co*sum(x[5:9]), constraints=cons, x0=x0, bounds=bnds,
  File "C:\Python\Python395\lib\site-packages\scipy\optimize\_minimize.py", line 627, in minimize
    return _minimize_slsqp(fun, x0, args, jac, bounds,
  File "C:\Python\Python395\lib\site-packages\scipy\optimize\slsqp.py", line 259, in _minimize_slsqp
    new_bounds = old_bound_to_new(bounds)
  File "C:\Python\Python395\lib\site-packages\scipy\optimize\_constraints.py", line 323, in old_bound_to_new
    lb, ub = zip(*bounds)
ValueError: too many values to unpack (expected 2)

Did anyone encounter the same problem?

Thanks in advance, Davide


Solution

  • As already mentioned in the comments, bounds is required to be a sequence of tuples. Hence, you could do something like this:

    # Bounds
    bnds = []
    for i, _ in enumerate(x0):
        if i <= 4:
            bnds.append((-np.inf, np.inf))
        elif 5 <= i <= 9:
            bnds.append((0, np.inf))
        else:
            bnds.append(-1000000, 100000000)