pythonscipynumerical-integrationquad

Complicated nested integrals in terms of python scipy.integrate


I want to write the following complicated function using python scipy.integrate:enter image description here

where \phi and \Phi are the pdf and cdf of the standard normal respectively and the sum i != 1,2 is over the thetas in *theta, and the product s != 1,i,2 is over the thetas in *theta that is not theta_i

To make things simpler, I break down the problem into a few easier pieces by defining a few more functions:

enter image description here

And here is what I have tried:

import scipy.integrate as integrate
from scipy.integrate import nquad
from scipy.stats import norm
import math
import numpy as np

def f(v, u, t1, ti, t2, *theta):
  prod = 1
  for t in theta:
    prod = prod * (1 - norm.cdf(u + t2 - t))
  return norm.pdf(v) * norm.cdf(v + ti - t1) * prod

def g(v, u, t1, t2, *theta):
  S = 0
  for ti in theta:
    S = S + integrate.quad(f, -np.inf, u + t2 - ti, args=(u, t1, ti, t2, *theta))[0]
  return S * norm.pdf(u)

def P(t1, t2, *theta):
  return integrate.quad(g, -np.inf, np.inf, args=(t1, t2, *theta))[0]

But it doens't work because I think in the definition of P the integral is integrating w.r.t. the first variable, namely v but we should be integrating u but I don't know how we can do that.

Is there any quick way to do it?

For checking, here is what the correct P would produce:

P(0.2, 0.1, 0.3, 0.4) = 0.08856347190679764

P(0.2, 0.1, 0.4, 0.3, 0.5) = 0.06094233268837703

Solution

  • The first thing I did was move prod outside of f since it isn't a function of v. I realized that your prod includes the ti term, so I added a check for ts (renamed from t) equal to ti.

    You also have way too many variables for your functions. g is a function of u and the thetas and f is a function of v and the thetas, so they don't both need u and v.

    This isn't the most efficient code, but it works.

    from scipy.integrate import quad
    from scipy.stats import norm
    import numpy as np
    
    def f(v, t1, ti):
      return norm.pdf(v) * norm.cdf(v + ti - t1)
    
    def g(u, t1, t2, *theta):
      S = 0
      for ti in theta:
          prod = 1
          for ts in theta:
              if ts != ti:
                  prod *= (1 - norm.cdf(u + t2 - ts))
          S += prod*quad(f, -np.inf, u + t2 - ti, args=(t1, ti))[0]
      return S * norm.pdf(u)
    
    def P(t1, t2, *theta):
      return quad(g, -np.inf, np.inf, args=(t1, t2, *theta))[0]
    
    print(P(0.2, 0.1, 0.3, 0.4))            # 0.08856347187084088
    print(P(0.2, 0.1, 0.4, 0.3, 0.5))       # 0.060942332693157915