Search code examples
pythonoptimizationscipysympynumerical-integration

How to Put an indefinite Integral in an objective function Python


I have this objective function that I want to minimize in regards to 't', and in this function, there is an integral from 0 to t that has to be considered for the optimization. However, I have no Idea how to include this integral to my objective function. I've used simpy and scipy library for that but none of them seems to work. here is my code:

Cf= 100;
Cp=50;
  Eta=72.66585511711865;
  Beta=1.18609324
def R(t):
  return math.exp(-t/Eta)**Beta
def f(t):
  return (Beta/(Eta**Beta))*t**(Beta-1)*(math.exp(-t/Eta)**Beta)  
def M(t):
  return t*f(t)
import sympy as sp 
from scipy import *
import scipy.integrate
t = sp.Symbol('t') 
Mt=t*(Beta/(Eta**Beta))*t**(Beta-1)*(sp.exp(-t/Eta)**Beta);
intM=sp.integrate(Mt,t)
print(intM)
def C(t):
  return (Cp*R(t)+Cf*(1-R(t)))/(t*R(t)+ intM)
from scipy.optimize import minimize_scalar
res = minimize_scalar(C)
res

this gives me error " TypeError: cannot determine truth value of Relational" . in scipy.integrate.quad, I can't define my upper limit as 't'. And on the other hand, it won't work when I try to put the sp.integrate output to the objective function. I would be happy if u could help. thanks.


Solution

  • First up, you can't have an indefinite integral within an optimization routine, as that's defined up to a constant. Not a function, but a class of functions.

    But it looks like yours is a definite integral - you integrate it over some dummy variable, say, t', from t'=0 to t'=t. So that's perfectly fine, and you just have to do it.

    First, let's do your definite integral:

    intM = sp.integrate(Mt, (t, 0, t))
    # second arg is variable of integration, lower bound, upper bound
    # we can skip defining tprime, a mathematician would hate you for this but meh
    

    This still depends on t, so now let's turn it into a numerical function:

    intM_func = sp.lambdify(t, intM)
    # note how you can do intM_func(3) and get a number
    

    Then stick intM_func(t) rather than the symbolic intM into your C minimizable function and you should be good to go :)


    The full version that works for me:

    Cf = 100
    Cp = 50
    Eta = 72.66585511711865
    Beta = 1.18609324
    
    
    def R(t):
        return math.exp(-t / Eta) ** Beta
    
    
    def f(t):
        return (Beta / (Eta**Beta)) * t ** (Beta - 1) * (math.exp(-t / Eta) ** Beta)
    
    
    def M(t):
        return t * f(t)
    
    
    import sympy as sp
    from scipy import *
    import scipy.integrate
    
    t = sp.Symbol("t")
    Mt = t * (Beta / (Eta**Beta)) * t ** (Beta - 1) * (sp.exp(-t / Eta) ** Beta)
    intM = sp.integrate(Mt, (t, 0, t))
    intMfunc = sp.lambdify(t, intM)
    print(intM)
    
    
    import numpy as np
    def C(t):
        if t == 0:   # dodge a division-by-zero bullet
            return np.inf
        return (Cp * R(t) + Cf * (1 - R(t))) / (t * R(t) + intMfunc(t))
    
    
    from scipy.optimize import minimize_scalar
    
    res = minimize_scalar(C)
    print(res)
    

    And I get:

         fun: 1.5407809938973502
     message: '\nOptimization terminated successfully;\nThe returned value satisfies the termination criteria\n(using xtol = 1.48e-08 )'
        nfev: 61
         nit: 28
     success: True
           x: 2964.8614509894874
    

    as an output.