Differentiation API¶
The public differentiation interface. All functions are importable directly
from dualpy.
Primitives¶
dualpy.jvp(func, primals, tangents)
¶
Evaluate func and its Jacobian-vector product in one forward pass.
This is the most fundamental forward-mode AD primitive. It seeds a dual number with the given tangent vector and propagates both the primal computation and the directional derivative simultaneously.
When used inside another differentiation call (nested differentiation), the tangent seed is automatically wrapped so that forward-over-forward second derivatives work correctly.
primals may also be a tuple or list of arrays for multi-argument functions, in which case tangents must be a matching sequence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
primals
|
array_like or tuple/list thereof
|
The point at which to evaluate func. A tuple or list activates multi-argument mode where each element is a separate positional argument. |
required |
tangents
|
array_like or tuple/list thereof
|
The tangent (seed) vector(s). Must match the structure and shapes of primals. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
primal_out |
ndarray
|
The result of |
tangent_out |
ndarray
|
The Jacobian-vector product evaluated at primals. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If primals and tangents have mismatched shapes. |
Examples:
Single-argument:
>>> import numpy as np
>>> from dualpy import jvp
>>> f = lambda x: np.stack([x[0]**2, x[0] * x[1]])
>>> primal_out, tangent_out = jvp(f, np.array([2.0, 3.0]), np.array([1.0, 0.0]))
>>> primal_out
array([4., 6.])
>>> tangent_out
array([4., 3.])
Multi-argument:
First-order¶
dualpy.jacobian(func, argnums=0, *, v=None)
¶
Compute the Jacobian of func, or a Jacobian-vector product.
Wraps func so that each call evaluates both the function and its
full Jacobian using forward-mode automatic differentiation with dual
numbers. Inputs and outputs may be arrays of any shape.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
argnums
|
int or tuple[int, ...]
|
Positional index (or indices) of the argument(s) to differentiate
with respect to. Defaults to |
0
|
v
|
ndarray or None
|
Direction array for a Jacobian-vector product (JVP). When provided, the returned function computes the directional derivative along v instead of the full Jacobian. Must have the same shape as the differentiated argument. |
None
|
Returns:
| Type | Description |
|---|---|
callable
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If v and the differentiated argument have mismatched shapes. |
Notes
When building multi-element outputs inside func, use
np.stack([...]) rather than np.array([...]). Due to a
limitation in NumPy's dispatch mechanism, np.array does not
correctly propagate derivative information through lists of
intermediate results, which leads to slower fallback behavior and
a UserWarning. np.stack does not have this limitation.
Examples:
>>> import numpy as np
>>> from dualpy import jacobian
>>> f = lambda x: np.stack([x[0]**2, x[0] * x[1]])
>>> jacobian(f)(np.array([2.0, 3.0]))
array([[4., 0.],
[3., 2.]])
Multi-argument with argnums:
dualpy.derivative(func, argnums=0)
¶
Compute the derivative of a scalar function f: R -> R.
A thin wrapper around :func:jacobian that enforces the scalar-in,
scalar-out contract and returns a plain scalar rather than a 1x1
Jacobian.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
argnums
|
int or tuple[int, ...]
|
Positional index (or indices) of the argument(s) to differentiate
with respect to. Defaults to |
0
|
Returns:
| Type | Description |
|---|---|
callable
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a differentiated argument is not a scalar (use :func: |
Examples:
>>> import numpy as np
>>> from dualpy import derivative
>>> df = derivative(np.sin)
>>> df(0.0) # cos(0) = 1
1.0
Multi-argument:
dualpy.gradient(func, argnums=0, *, v=None)
¶
Compute the gradient of a scalar-valued function.
A thin wrapper around :func:jacobian that enforces the scalar-output
contract. The input x may be an array of any shape; the gradient
will have the same shape. When a direction array v is given,
returns the directional derivative ∇f · v instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
argnums
|
int or tuple[int, ...]
|
Positional index (or indices) of the argument(s) to differentiate
with respect to. Defaults to |
0
|
v
|
ndarray or None
|
Direction array for a directional derivative. Must have the same
shape as the differentiated argument. When provided, the returned
function computes |
None
|
Returns:
| Type | Description |
|---|---|
callable
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If func is not scalar-valued. Use :func: |
Examples:
>>> import numpy as np
>>> from dualpy import gradient
>>> f = lambda x: x[0]**2 + x[1]**2
>>> gradient(f)(np.array([3.0, 4.0]))
array([6., 8.])
Multi-argument:
>>> g = lambda x, y: np.sum(x**2) + y**2
>>> gradient(g, argnums=0)(np.array([3.0, 4.0]), 1.0)
array([6., 8.])
Directional derivative along the first axis:
Higher-order¶
dualpy.nth_derivative(func, n, argnums=0)
¶
Compute the n-th derivative of a scalar function f: R -> R.
Composes :func:derivative n times, using nested dual numbers for
exact higher-order derivatives.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
n
|
int
|
The order of differentiation. Must be non-negative.
|
required |
argnums
|
int or tuple[int, ...]
|
Positional index (or indices) of the argument(s) to differentiate
with respect to. Defaults to |
0
|
Returns:
| Type | Description |
|---|---|
callable
|
|
Examples:
>>> import numpy as np
>>> from dualpy import nth_derivative
>>> f = lambda x: x ** 4
>>> nth_derivative(f, 3)(1.0) # f'''(x) = 24x, at x=1
24.0
Cyclic derivatives of sine:
dualpy.hessian(func, argnums=0)
¶
Compute the Hessian of a scalar-valued function.
Uses nested forward-mode AD by composing :func:jacobian with
:func:gradient, giving exact second derivatives without finite
differences. For an input of shape s, the Hessian is a tensor
of shape s + s.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
argnums
|
int or tuple of exactly 2 ints
|
When an |
0
|
Returns:
| Type | Description |
|---|---|
callable
|
|
Examples:
>>> import numpy as np
>>> from dualpy import hessian
>>> f = lambda x: x[0]**2 + 3*x[1]**2
>>> hessian(f)(np.array([1.0, 1.0]))
array([[2., 0.],
[0., 6.]])
Mixed partial Hessian:
dualpy.hvp(func, v, argnums=0)
¶
Compute the Hessian-vector product H(x) · v without forming H.
Uses forward-over-forward AD: differentiates the directional derivative
∇f(x) · v with respect to x, giving H(x) · v in O(n) time
rather than the O(n²) cost of forming the full Hessian.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
v
|
ndarray
|
Direction vector. Must have the same shape as the differentiated argument. |
required |
argnums
|
int
|
Positional index of the argument to differentiate with respect to.
Defaults to |
0
|
Returns:
| Type | Description |
|---|---|
callable
|
|
Examples:
>>> import numpy as np
>>> from dualpy import hvp
>>> f = lambda x: x[0]**2 + 3*x[1]**2
>>> hvp(f, np.array([1.0, 0.0]))(np.array([1.0, 1.0]))
array([2., 0.])
Equivalent to hessian(f)(x) @ v, but O(n) instead of O(n²):
Vector calculus¶
dualpy.curl(func)
¶
Compute the curl of a vector field F: R^3 -> R^3.
Defined only for three-dimensional vector fields. Computes the full
Jacobian via :func:jacobian and extracts the curl components::
curl(F) = [∂F₃/∂x₂ , ∂F₂/∂x₃,
∂F₁/∂x₃ , ∂F₃/∂x₁,
∂F₂/∂x₁ , ∂F₁/∂x₂]
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
Returns:
| Type | Description |
|---|---|
callable
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If x does not have exactly 3 elements. |
Examples:
dualpy.divergence(func)
¶
Compute the divergence of a vector field F: R^n -> R^n.
The divergence is the trace of the Jacobian: div(F) = Σᵢ ∂Fᵢ/∂xᵢ.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
Returns:
| Type | Description |
|---|---|
callable
|
|
Examples:
dualpy.laplacian(func)
¶
Compute the Laplacian of a scalar-valued function.
The Laplacian is the sum of unmixed second partial derivatives:
Δf = Σᵢ ∂²f/∂xᵢ². Computed via :func:hessian, which uses
nested forward-mode AD for exact second derivatives. The input may
be an array of any shape.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
func
|
callable
|
A function |
required |
Returns:
| Type | Description |
|---|---|
callable
|
|
Examples: