Gcinbax Gcinbax - 5 months ago 24
Python Question

Scipy optimize.minimize function

I try to solve nonlinear programming task using scipy.optimize.minimize

max r
x1**2 + y1**2 <= (1-r)**2
(x1-x2)**2 + (y1-y2)**2 >= 4*r**2
0 <= r <= 1


So I've wrote next code:

r = np.linspace(0, 1, 100)
x1 = np.linspace(0, 1, 100)
y1 = np.linspace(0, 1, 100)
x2 = np.linspace(0, 1, 100)
y2 = np.linspace(0, 1, 100)


fun = lambda r: -r
cons = ({'type': 'ineq',
'fun': lambda x1, r: [x1[0] ** 2 + x1[1] ** 2 - (1 - r) ** 2],
'args': (r,)},
{'type': 'ineq',
'fun': lambda x2, r: [x2[0] ** 2 + x2[1] ** 2 - (1 - r) ** 2],
'args': (r,)},
{'type': 'ineq',
'fun': lambda x1, x2, r: [(x1[0] - x2[0]) ** 2 + (x1[1] - x2[1]) ** 2 - 4 * r ** 2],
'args': (x2, r,)})
bnds = ((0, 1), (-1, 1), (-1, 1), (-1, 1), (-1, 1))
x0 = [0, 0, 0, 0, 0]
minimize(fun, x0, bounds=bnds, constraints=cons)


But I've got next error

File "C:\Anaconda2\lib\site-packages\scipy\optimize\slsqp.py", line 377, in _minimize_slsqp
c = concatenate((c_eq, c_ieq))
ValueError: all the input arrays must have same number of dimensions


Please, help me to find out my mistakes and write correct code

UPD:
Thx to @unutbu i've understand how to build it correctly.

fun = lambda x: -x[0]
cons = ({'type': 'ineq',
'fun': lambda x: -x[1] ** 2 - x[2] ** 2 + (1 - x[0]) ** 2},
{'type': 'ineq',
'fun': lambda x: -x[3] ** 2 - x[4] ** 2 + (1 - x[0]) ** 2},
{'type': 'ineq',
'fun': lambda x: (x[1] - x[3]) ** 2 + (x[1] - x[4]) ** 2 - 4 * x[0] ** 2})
bnds = ((0, 1), (-1, 1), (-1, 1), (-1, 1), (-1, 1))
x0 = [0.5, 0.3, 0.5, 0.3, 0.5]
answer = minimize(fun, x0, bounds=bnds, constraints=cons)


In task of minimization we have to lead constraints to such form:

g(x) >= 0


that's why constraints look like in that way.

Answer

Your parameter space appears to be 5-dimensional. A point in your parameter space would be z = (r, x1, y1, x2, y2). Therefore the function to be minimized -- and also the constraint functions -- should accept a point z and return a scalar value.

Thus instead of

fun = lambda r: -r

use

def func(z):
    r, x1, y1, x2, y2 = z
    return -r

and instead of

lambda x1, r: [x1[0] ** 2 + x1[1] ** 2 - (1 - r) ** 2]

use

def con1(z):
    r, x1, y1, x2, y2 = z
    return x1**2 + y1**2 - (1-r)**2

and so on.


Note that simple constraints such as 0 <= r <= 1 can be handled by setting the bounds parameter instead of defining a constraint. And if the bounds for x1, y1, x2, y2 are from -1 to 1, then you might also want change

x1 = np.linspace(0, 1, 100)
...

to

x1 = np.linspace(-1, 1, 100)
...

However, the arrays r, x1, y1, x2, y2 are not needed to minimize func, so you could just as well eliminate them from the script entirely.


import numpy as np
import scipy.optimize as optimize

"""
max r
x1**2 + y1**2 <= (1-r)**2
(x1-x2)**2 + (y1-y2)**2 >= 4*r**2
0 <= r <= 1
"""

def func(z):
    r, x1, y1, x2, y2 = z
    return -r

def con1(z):
    r, x1, y1, x2, y2 = z
    return x1**2 + y1**2 - (1-r)**2

def con2(z):
    r, x1, y1, x2, y2 = z
    return 4*r**2 - (x1-x2)**2 - (y1-y2)**2 

cons = ({'type': 'ineq', 'fun': con1}, {'type': 'ineq', 'fun': con2},)
bnds = ((0, 1), (-1, 1), (-1, 1), (-1, 1), (-1, 1))
guess = [0, 0, 0, 0, 0]
result = optimize.minimize(func, guess, bounds=bnds, constraints=cons)
print(result)

yields

     fun: -1.0
     jac: array([-1.,  0.,  0.,  0.,  0.,  0.])
 message: 'Optimization terminated successfully.'
    nfev: 14
     nit: 2
    njev: 2
  status: 0
 success: True
       x: array([ 1.,  0.,  0.,  0.,  0.])
Comments