I tried to make a code but it didn't give me what I expected, as I was expecting a value closer to the exact one.
import numpy as np
from scipy.special import roots_hermitenorm
def Gauss_hermite(func: callable, N: int) -> float:
"""
Numerically computes the integral of a function using Gauss quadrature
with Hermite polynomials.
Parameters:
func (callable): The function to be integrated.
N (int): The number of intervals for integration.
Returns:
float: Approximate value of the integral of 'func' over the interval
[a, b].
"""
# Determine zeros and weights using scipy
xx, ww = roots_hermitenorm(N)
# Compute the integral
integral = np.sum(ww * func(xx))
return integral
# Example usage
result = Gauss_hermite(lambda x: np.exp(-x**2), 2046)
expected = np.sqrt(np.pi)
print(f"Result: {result:.5f}")
print(f"Expected: {expected:.5f}")
which gives:
Result: 1.44720
Expected: 1.77245
Based on Gauss-Hermite Quadrature on Wikipedia, it looks like (conceptually) you want something like:
The quadrature formula is for evaluating the integrand weighted by
np.exp(-xx**2/2)(because the SciPy documentation says the polynomials are orthogonal with weight functionnp.exp(-x**2/2), notnp.exp(-x**2)), so you need to undo that weighting.This gives reasonable results for a lower-order polynomial (e.g.
64), but you'll run into numerical issues for orders like2048. So really, rather than changing the weights, it's better to change your integrand by dividing it bynp.exp(-x**2/2)analytically:If you have another integrand for which you can't remove the weighting so neatly, there are other tricks you can play to get around the numerical issues, or there are more appropriate quadrature rules to use, but that is a different question.
Change the weights:
Change the integrand: