Shreyas
Shreyas

Reputation: 419

Scipy Minimize - Unable to minimize objective function

I am trying to optimise a function to find max value of rev_tot using scipy minimise. Here obj_data is a list of probabilities, prem is a constant and inc can take any real value. Following is the code I have written for the objective function :

import numpy as np
import pandas as pd
import scipy
from scipy.optimize import minimize

def objective(x,*args):

    prem = args[0]
    prob = args[1]
    inc = x[0]


    rev_tot = 0
    rev = 0
    del_p = 0.2*(1-np.exp(-2*(1-np.exp(-inc/400))))
    for i in range(len(prob)):
        rev = (prob[i]*(1+del_p)*prem) - inc
        rev_tot = rev_tot + rev
    return 1/rev_tot


prem = 3300
par = [0.9,0.1,0.5,0.4]
x0 = np.array([3]) # initial guess
solve = minimize(objective,x0,args=(prem,par),method='SLSQP')
solve.x

I want to find the inc value which will minimize 1/rev_tot(and thus maximising rev_tot. When I call:

minimize(objective,x0,args=(prem,par),method='SLSQP')

the function runs, but solve.x shows no change in initial value. I am unable to figure out why the minimisation is not happening.

Upvotes: 1

Views: 2732

Answers (1)

Mr. T
Mr. T

Reputation: 12410

Your problem is that the solver has to deal with tiny numbers due to your return 1/rev_tot. Hence changes over the x-axis are not well reflected in changes in y-values and the solver estimates that it has already converged:

import numpy as np
import pandas as pd
import scipy
from scipy.optimize import minimize

def objective(x,*args):

    prem = args[0]
    prob = args[1]
    inc = x[0]

    rev_tot = 0
    rev = 0
    del_p = 0.2*(1-np.exp(-2*(1-np.exp(-inc/400))))
    for i in range(len(prob)):
        rev = (prob[i]*(1+del_p)*prem) - inc
        rev_tot = rev_tot + rev
    return 1/rev_tot

prem = 3300
par = [0.9,0.1,0.5,0.4]
x0 = np.array([2]) # initial guess
solve = minimize(objective,x0,args=(prem,par),method='SLSQP')
x_min = solve.x
print(x_min)
#plot your function to visualize the outcome
x_func = np.linspace(1, 100, 1000)
y_func = []
for item in x_func:
    y_func.append((objective(np.asarray([item]), prem, par)))

y_min = objective(np.asarray([x_min]), prem, par)

plt.plot(x_func, y_func)
plt.plot(x_min, y_min, "ro")
plt.show()

Output:

[2.]

enter image description here

Solution 1)
Different solvers manage certain problems better than others. Change your solver to "Nelder-Mead". Output:

[63.07910156]

enter image description here

Solution 2)
Scale up your return value with return 1000000/rev_tot for solver "SLSQP". Output:

[63.07110511]

enter image description here

Upvotes: 4

Related Questions