问题
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