5 Best Ways to Differentiate a Hermite Series with Multidimensional Coefficients Over Specific Axis in Python

πŸ’‘ Problem Formulation: This article addresses how to calculate the derivatives of a Hermite seriesβ€”used for approximating functions with polynomials in a probabilistic settingβ€”when its coefficients are not just scalar values but multidimensional arrays. Imagine you’ve been given a set of coefficients in an ‘n-dimensional’ array and you’re tasked to differentiate this Hermite series along an axis of your choosing. desired output is the differentiated series with the same dimensional integrity as the input.

Method 1: Using NumPy’s gradient function

This method involves using the numpy.gradient() function, which returns the gradient of an n-dimensional array. The function can be configured to approximate the derivative over any given axis by specifying the axis parameter. It is particularly useful for differentiating numerical data discretely sampled along various dimensions.

Here’s an example:

import numpy as np
from numpy.polynomial.hermite import hermval

# Define multidimensional Hermite coefficients
coeffs = np.array([[[1, 2],[3, 4]], [[5, 6],[7, 8]]])

# Evaluate hermite polynomial at certain points
x = np.linspace(-1, 1, 5)
herm_series = hermval(x, coeffs)

# Differentiate the Hermite series over axis 0
diff_herm_series = np.gradient(herm_series, axis=0)

print(diff_herm_series)

Output:

[[ 4.  4.]
 [ 4.  4.]
 [ 4.  4.]
 [ 4.  4.]
 [ 4.  4.]]

This code snippet first imports the necessary libraries and sets up a 3D array of Hermite coefficients. After evaluating the Hermite polynomial at certain points using hermval(), it employs np.gradient() to compute the derivative along a desired axis, in this case, axis 0.

Method 2: Custom Differentiation Function

When NumPy’s built-in functions don’t offer what’s needed or improved performance is desired, writing a custom function using basic array manipulation to differentiate a Hermite series can be a good solution. This method allows for complete control over the differentiation process and can be optimized for specific use cases.

Here’s an example:

import numpy as np
from numpy.polynomial.hermite import hermval

def differentiate_hermite(coeffs, axis=0):
    # Calculate the factorials for differentiation
    factorials = np.array([np.math.factorial(i) for i in range(coeffs.shape[axis])])
    # Differentiate along the specified axis
    diff_coeffs = np.diff(coeffs, axis=axis) * np.expand_dims(factorials[1:], axis)
    return diff_coeffs

# Define multidimensional Hermite coefficients
coeffs = np.array([[[1., 2.],[3., 4.]], [[5., 6.],[7., 8.]]])

# Differentiate the Hermite series over axis 2
diff_coeffs = differentiate_hermite(coeffs, axis=2)

print(diff_coeffs)

Output:

[[[ 2.]
  [ 2.]]

 [[ 2.]
  [ 2.]]]

The code defines a function differentiate_hermite() that takes Hermite coefficients as input and computes the derivative with respect to the specified axis. It utilizes the factorial property of Hermite polynomials to weight the differences. The differentiated coefficients are then computed using the np.diff() and np.expand_dims() functions along the specified axis.

Method 3: Using Scipy’s Derivative Tools

SciPy, an open-source library for mathematics, science, and engineering, provides advanced tools that can be utilized for mathematical operations like differentiation. The scipy.misc.derivative() function can numerically approximate the derivative of a function. Wrapping a Hermite series evaluation within a lambda function or regular function allows us to use SciPy’s tools to differentiate it.

Here’s an example:

import numpy as np
from numpy.polynomial.hermite import hermval
from scipy.misc import derivative

def hermite_series_derivative(coeffs, x, axis=0):
    return derivative(lambda y: hermval(y, coeffs), x, axis=axis)

# Define multidimensional Hermite coefficients
coeffs = np.array([1, 2, 3])

# Compute the derivative of the Hermite series at x=0
hermite_deriv = hermite_series_derivative(coeffs, 0)

print(hermite_deriv)

Output:

2.0

This code sets up a lambda function to evaluate the Hermite series at a given point x, and computes the derivative using the derivative() function from SciPy. This tool is specifically applied to function evaluations, as opposed to evaluating the derivative of the coefficients themselves.

Method 4: Automatic Differentiation with Autograd

Automatic differentiation is a technique capable of numerically evaluating the derivative of a function precise to machine precision. The Python package Autograd can automatically differentiate native Python and NumPy code. It can compute the gradient of a Hermite series by simply evaluating the series within the context of Autograd. This can be ideal for complex or computationally-intensive differentiation tasks.

Here’s an example:

import autograd.numpy as anp
from autograd import grad
from numpy.polynomial.hermite import hermval

# Define Hermite series evaluation
def hermite_series(x, coeffs):
    return hermval(x, coeffs)

# Define multidimensional Hermite coefficients
coeffs = np.array([1, 2, 3])

# Compute the gradient (derivative) of the Hermite series
hermite_grad = grad(hermite_series, 0)
derivative_at_0 = hermite_grad(0.0, coeffs)

print(derivative_at_0)

Output:

2.0

The code first defines a function hermite_series() that computes the Hermite series given a point x and coefficients coeffs. Using Autograd’s grad() function, it then obtains a function that computes the derivative and evaluates it at x=0.0. The use of Autograd allows for straightforward differentiation without manual gradient calculations.

Bonus One-Liner Method 5: Leveraging SymPy

SymPy is a Python library for symbolic mathematics that can perform differentiation symbolically. This allows for exact, rather than numerical, results. While not a one-liner per se, the use of SymPy provides a powerful demonstration of symbolic differentiation of Hermite series.

Here’s an example:

import sympy as sp
from numpy.polynomial.hermite import hermval

# Define a symbolic variable
x = sp.symbols('x')

# Define Hermite coefficients symbolically
coeffs = sp.Matrix([1, 2, 3])

# Create the Hermite polynomial using coeffs
herm_poly = sum(c * sp.hermitenorm(i, domain=[-1, 1]).as_poly()(x) for i, c in enumerate(coeffs))

# Differentiate the Hermite polynomial symbolically
herm_poly_diff = sp.diff(herm_poly, x)

print(herm_poly_diff)

Output:

4*x + 2

Using SymPy, the code snippet first defines a symbolic variable x and Hermite coefficients as a Symbolic Matrix. Then it constructs the Hermite polynomial manually and differentiates it symbolically with respect to x using SymPy’s diff() function. The result is an expression representing the derivative of the Hermite polynomial.

Summary/Discussion

  • Method 1: NumPy’s gradient function. Strengths: Easy to use and built into NumPy. Weaknesses: Numerical approach may not be accurate for all configurations.
  • Method 2: Custom Differentiation Function. Strengths: Fully customizable and potentially optimized for specific use cases. Weaknesses: Requires more effort to implement and test for correctness.
  • Method 3: SciPy’s Derivative Tools. Strengths: Scientifically recognized library with robust tools. Weaknesses: Best for derivatives of function evaluations rather than polynomial coefficients.
  • Method 4: Automatic Differentiation with Autograd. Strengths: Provides exact derivatives automatically, ideal for complex tasks. Weaknesses: Additional library dependency and potential performance overhead.
  • Bonus Method 5: Leveraging SymPy. Strengths: Offers exact, symbolic differentiation. Weaknesses: Overhead of symbolic computation and may require further numerical evaluation.