Scipy error Inequality constraints incompatible (Exit mode 4)

Viewed 2406

I'm solving an optimization problem to do a constrained nonlinear regression using experimental data. I use scipy minimize and it works with the original data, but it doesn't work when I do a simple data transformation. For the transformed data I use the excel solver solution for the same problem as the initial condition so it should work butcan't figure out why it doesn not. Please any help is appreciated. Thanks beforehand btw.

Here is the code with the original data (works) and the transformation (does not work)

import numpy as np
from scipy.optimize import Bounds, minimize

def yp(x, time, mode = 'fit'):
    y1 = x[0] + x[1]*time
    y2 = x[2] + (x[3] - x[2])*np.exp(-x[5]*(time - x[4])/(x[3] - x[2]))

    comparison = time < x[4]

    yp = y1*comparison + y2*(~comparison)
    if mode == 'fit':
        return yp
    elif mode == 'calc':
        return y1, y2
    else:
        print('Unsupported mode, returning default behavior for fitting data')
        return yp
    
def objective(x, time, y):
    ypred = yp(x, time)
    z = sum((ypred - y)**2)
    return z

#***********************
#Original data
#***********************
data_x = np.array([0,30,60,90,120,150,180,210,240,270,300,330,360,420,480,540,600,720,840])
data_y = np.array([11.06468023,10.03242418,9.771158736,8.873720137,8.618127786,
          8.397702515,7.581607582,7.131636821,6.537043245,6.358885017,
          5.898468977,5.25275811,4.983989976,4.141791045,2.602472349,
          2.07395813,1.078129376,0.551764193,0.480052971])

x0 = [11.5, -0.0211, 0.6, 3.26, 400, 0.01919]
lbound = [9, -0.1, 0.3, 1, 200, 0]
ubound = [14, -1e-5, 1, 4, 800, 0.1]
bounds = Bounds(lbound,ubound)

constraint = dict(type = 'ineq',
                 fun = lambda x: 0.1 - abs(x[0] + x[1]*x[4] - x[3]))

res = minimize(fun = objective,
             x0 = x0,
             args = (data_x, data_y),
             method = 'SLSQP',
             constraints = constraint,
             options = {'disp':True},
             bounds = bounds)

print(res)

Optimization terminated successfully    (Exit mode 0)
            Current function value: 0.6681037696841838
            Iterations: 20
            Function evaluations: 149
            Gradient evaluations: 20
     fun: 0.6681037696841838
     jac: array([ 1.19826198e-03,  5.93313336e-01,  9.38165262e-02,  6.77183270e-04,
        1.15633011e-05, -3.35602835e-02])
 message: 'Optimization terminated successfully'
    nfev: 149
     nit: 20
    njev: 20
  status: 0
 success: True
       x: array([ 1.06185481e+01, -1.59476490e-02,  3.00000000e-01,  3.86162000e+00,
        4.29964822e+02,  2.80661182e-02])
#***********************
#Transformed data
#***********************
data_y_rel = data_y/data_y[0]
x0_rel = [1, -0.00207571, 0.03, 0.359269446, 313.497571, 0.001970666]
lbound_rel = [1, -0.1, 0.03, 0.1, 200, 0]
ubound_rel = [1, -1e-5, 0.1, 0.4, 800, 0.1]
bounds_rel = Bounds(lbound_rel,ubound_rel)

constraint_rel = dict(type = 'ineq',
                 fun = lambda x: 0.01 - abs(x[0] + x[1]*x[4] - x[3]))

res_rel = minimize(fun = objective,
             x0 = x0_rel,
             args = (data_x, data_y_rel),
             method = 'SLSQP',
             constraints = constraint_rel,
             options = {'disp':True},
             bounds = bounds_rel)

print(res_rel)

Inequality constraints incompatible    (Exit mode 4)
            Current function value: 0.1593965203706159
            Iterations: 1
            Function evaluations: 7
            Gradient evaluations: 1
     fun: 0.1593965203706159
     jac: array([            nan, -2.88985475e+02, -1.53672213e-01, -1.13128023e+00,
       -1.58630125e-03,  5.45240970e+01])
 message: 'Inequality constraints incompatible'
    nfev: 7
     nit: 1
    njev: 1
  status: 4
 success: False
       x: array([ 1.00000000e+00, -2.07571000e-03,  3.00000000e-02,  3.59269446e-01,
        3.13497571e+02,  1.97066600e-03])
C:\Users\username\Anaconda3\lib\site-packages\scipy\optimize\_numdiff.py:519: RuntimeWarning: invalid value encountered in true_divide
  J_transposed[i] = df / dx
1 Answers

Changing the method from 'SLSQP' to 'trust-constr' worked for me. 'COBYLA' is also an option.

Related