How to get the minimum value of a cost function, having two variable integration expression, in short time using python?

独自空忆成欢 提交于 2020-06-10 07:23:48

问题


I want to find the minimum value of the cost function T. The cost function T has an expression in two variables (Q and r). I also need to find values of Q and r at which the cost function T reaches the global minimum. (if multiple global minimum values - then all) The bounds of Q and r are : 0 < Q < 15000 ; 0 < r < 5000 Here are the equations

I am using Sympy library to generate the equations. and using the minimize function of scipy.optimize.minimize to find the minimum value. The code for the functions are:

from sympy import *
from scipy.optimize import root_scalar
mean, std = 291, 253
l = 7 #
m = 30
#Q = mean*(lead_time + shelf_life)
p = 5
w = 2
K = 100
c = 5
h = 0.001 #per unit per  day
x = symbols("x")
t = symbols("t")
r = symbols("r")
Q = symbols("Q")
#defining Cumulative distribution function
def cdf():
  cdf_eqn = (1/(std*sqrt(2*pi)))*exp(-(((t-mean)**2)/(2*std**2)))
  cdf = Integral(cdf_eqn, (t,-oo,x)).doit()
  return cdf
#defining Probability density function
def pdf():
  pdf = (1/(std*sqrt(2*pi)))*exp(-((( (x - mean)**2)/(2*std**2)))).doit()
  return pdf
pdf = pdf()
cdf = cdf()
#getting the equation in place
G = K + c*Q + w*(Integral(cdf , (x, 0, Q)) + Integral(cdf.subs(x, (r + Q - x))*cdf , (x, 0, r)))\
     + p*(mean*l - r + Integral(cdf , (x, 0, r)))
CL = (Q - r + mean*l - Integral(cdf , (x, 0, Q)) - Integral(cdf.subs(x, (r + Q - x))*cdf , (x, 0, r)) + Integral(cdf , (x, 0, r)))/mean  
I = h*(Q + r - mean*l - Integral(cdf , (x, 0, Q)) - Integral(cdf.subs(x, (r + Q - x))*cdf , (x, 0, r)) + Integral(cdf , (x, 0, r)))/2
#TC.free_symbols
#optimising the cost function
from  scipy import optimize
def f(params):
    r, Q = params 
    TC = G/CL + I
    return TC
initial_guess = [2500., 10000.]
result = optimize.minimize(f, initial_guess, tol=1e-6 )
if result.success:
    fitted_params = result.x
    print(fitted_params)
else:
    raise ValueError(result.message)

But it throws an error as below.

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in _approx_fprime_helper(xk, f, epsilon, args, f0)
    699             try:
--> 700                 df = df.item()
    701             except (ValueError, AttributeError):
AttributeError: 'Zero' object has no attribute 'item'
During handling of the above exception, another exception occurred:
ValueError                                Traceback (most recent call last)
5 frames
<ipython-input-6-e9bb4190fef5> in <module>()
     39     return TC
     40 initial_guess = [2500., 10000.]
---> 41 result = optimize.minimize(f, initial_guess, tol=1e-6 )
     42 if result.success:
     43     fitted_params = result.x
/usr/local/lib/python3.6/dist-packages/scipy/optimize/_minimize.py in minimize(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)
    602         return _minimize_cg(fun, x0, args, jac, callback, **options)
    603     elif meth == 'bfgs':
--> 604         return _minimize_bfgs(fun, x0, args, jac, callback, **options)
    605     elif meth == 'newton-cg':
    606         return _minimize_newtoncg(fun, x0, args, jac, hess, hessp, callback,
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in _minimize_bfgs(fun, x0, args, jac, callback, gtol, norm, eps, maxiter, disp, return_all, **unknown_options)
   1007     else:
   1008         grad_calls, myfprime = wrap_function(fprime, args)
-> 1009     gfk = myfprime(x0)
   1010     k = 0
   1011     N = len(x0)
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in function_wrapper(*wrapper_args)
    325     def function_wrapper(*wrapper_args):
    326         ncalls[0] += 1
--> 327         return function(*(wrapper_args + args))
    328 
    329     return ncalls, function_wrapper
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in approx_fprime(xk, f, epsilon, *args)
    763 
    764     """
--> 765     return _approx_fprime_helper(xk, f, epsilon, args=args)
    766 
    767 
/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py in _approx_fprime_helper(xk, f, epsilon, args, f0)
    700                 df = df.item()
    701             except (ValueError, AttributeError):
--> 702                 raise ValueError("The user-provided "
    703                                  "objective function must "
    704                                  "return a scalar value.")
ValueError: The user-provided objective function must return a scalar value.

Additionally, with other methods, it takes a long time to run, more than 30 minutes or so and ends up throwing an error. How can I find the global minima and also the values of Q and r in a very short time. Preferably 1-5 minutes or so.

Posting on behalf of my Friend


回答1:


Just a note for the future: in your function f, if you set r and Q to something, it does not change the SymPy expressions that you use afterwards since they were already previously defined for symbolic variables.

Your work seems heavily numerical and in fact, since your answers don't need symbols, you're probably better doing non-symbolic integration. SymPy is pure Python which can be slow especially for integration while SciPy is designed to be fast. That's why I converted everything to SciPy things:

from numpy import sqrt, pi, exp
from scipy import optimize
from scipy.integrate import quad

mean, std = 291, 253
l = 7
m = 30
# Q = mean*(lead_time + shelf_life)
p = 5
w = 2
K = 100
c = 5
h = 0.001  # per unit per  day


# defining Cumulative distribution function
def cdf(x):
    cdf_eqn = lambda t: (1 / (std * sqrt(2 * pi))) * exp(-(((t - mean) ** 2) / (2 * std ** 2)))
    cdf = quad(cdf_eqn, 0, x)[0]
    return cdf


# defining Probability density function
def pdf(x):
    return (1 / (std * sqrt(2 * pi))) * exp(-(((x - mean) ** 2) / (2 * std ** 2)))


# getting the equation in place
def G(r, Q):
    return K + c * Q \
           + w * (quad(cdf, 0, Q)[0] + quad(lambda x: cdf(r + Q - x) * cdf(x), 0, r)[0]) \
           + p * (mean * l - r + quad(cdf, 0, r)[0])


def CL(r, Q):
    return (Q - r + mean * l - quad(cdf, 0, Q)[0]
            - quad(lambda x: cdf(r + Q - x) * cdf(x), 0, r)[0]
            + quad(cdf, 0, r)[0]) / mean


def I(r, Q):
    return h * (Q + r - mean * l - quad(cdf, 0, Q)[0]
                - quad(lambda x: cdf(r + Q - x) * cdf(x), 0, r)[0]
                + quad(cdf, 0, r)[0]) / 2


def f(params):
    r, Q = params
    TC = G(r, Q)/CL(r, Q) + I(r, Q)
    return TC


initial_guess = [2500., 10000.]
result = optimize.minimize(f, initial_guess, bounds=[(0, 5000), (0, 15000)], tol=1e-3)
print(result)

Resulting in the following output in like 5 seconds:

      fun: 1468.2418886720357
 hess_inv: <2x2 LbfgsInvHessProduct with dtype=float64>
      jac: array([ 0.00750333, -0.00047748])
  message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
     nfev: 33
      nit: 7
   status: 0
  success: True
        x: array([0.        , 7.19223408])

quad is a super fast integral that's written in FORTRAN according to the documentation.

Maybe double check the functions in case I got the brackets wrong when retyping.



来源:https://stackoverflow.com/questions/62278195/how-to-get-the-minimum-value-of-a-cost-function-having-two-variable-integration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!