3

I have the following code:

def constraint(params):
    if abs(params[0] - 15) < 2 and abs(params[1] + 10) < 2:
        return -1
    else:
        return 0

def f(params):
    x, z = params
    if abs(x - 15) < 2 and abs(z + 10) < 2:
        return -9999999

    return (x - 15) ** 2 + (z + 10) ** 2 * numpy.sqrt(numpy.abs(numpy.sin(x)))

# Last: 15.00024144, -9.99939634

result = optimize.minimize(f, (-15, -15),
                           bounds=((-15.01, 15.01,), (-15.01, 15.01,),),
                           method="SLSQP",
                           options={'maxiter': 1024 * 1024},
                           jac=False,
                           constraints={
                               'type': 'ineq',
                               'fun': constraint,
                           })

print(result)
print(f(result.x))

And it gives the following result:

fun: -9999999.0
     jac: array([0., 0.])
 message: 'Optimization terminated successfully.'
    nfev: 12
     nit: 7
    njev: 3
  status: 0
 success: True
       x: array([ 15.01      , -11.60831378])
-9999999

The given values [ 15.01, -11.60831378] should be dropped by the constraint (and they were: if I add more verbose logging, I see that constraint function returns -1, but scipy ignores it. Why?

I'm pretty far from data science and maths, so I'm sorry for stupid mistakes if they are there.

artem
  • 13,833
  • 33
  • 102
  • 170

1 Answers1

3

To help the algorithm find the right direction, you need to separate your constraints:

def f(params):
    print(params)
    x, z = params
    if abs(x - 15) < 2 and abs(z + 10) < 2:
        return -9999999

    return (x - 15) ** 2 + (z + 10) ** 2 * numpy.sqrt(numpy.abs(numpy.sin(x)))

# Last: 15.00024144, -9.99939634

result = optimize.minimize(f, (-15, -15),
                           bounds=((-15.01, 15.01,), (-15.01, 15.01,),),
                           method="SLSQP",
                           options={'disp':True, 'maxiter': 1024 * 1024},
                           jac=False,
                           constraints=({
                               'type': 'ineq',
                               'fun': lambda params : abs(params[0] - 15) -2,
                           },
                           {
                               'type': 'ineq',
                               'fun': lambda params : abs(params[1] + 10) -2,
                           },)
        )

print(result)
print(f(result.x))

Gives:

Optimization terminated successfully.    (Exit mode 0)
            Current function value: 6.5928117149596535
            Iterations: 6
            Function evaluations: 24
            Gradient evaluations: 6
     fun: 6.5928117149596535
     jac: array([-1.2001152,  2.5928117])
 message: 'Optimization terminated successfully.'
    nfev: 24
     nit: 6
    njev: 6
  status: 0
 success: True
       x: array([13., -8.])
[13. -8.]
6.5928117149596535

Bingo!

Jacques Gaudin
  • 12,304
  • 3
  • 40
  • 64
  • @arts777 I realised there was a typo in the constraints, you can actually get the result with your original `f` function but Yakim had a point saying it's more sensible to put a large positive value as a default. – Jacques Gaudin May 26 '18 at 22:03