symop.modes.envelopes.gaussian_mixture

Gaussian mixtures of closed-form Gaussian time-domain envelopes.

This module defines GaussianMixtureEnvelope, a normalized mode descriptor formed as a linear combination of normalized closed-form Gaussian components (GaussianEnvelope).

Motivation

A single Gaussian envelope is often too restrictive to represent practical mode shapes (e.g., mildly asymmetric pulses, superpositions of separated lobes, or simple approximations to filtered / shaped wavepackets). A mixture of Gaussians provides a simple, numerically stable, and differentiable representation that still supports analytic overlaps when all components are in the same closed-form family.

Key properties

  • Each component is a normalized GaussianEnvelope in the "gaussian_closed" formalism.

  • The mixture itself is normalized such that \(\langle\zeta,\zeta\rangle=1\) (computed from closed-form pairwise overlaps).

  • Overlaps with another closed-form Gaussian envelope (single Gaussian or another mixture) are computed in closed form via finite sums.

  • Time and frequency evaluation are computed by linear superposition of the component evaluations.

Performance notes

  • Normalization and overlap between two mixtures both require pairwise overlaps. If the mixture has \(K\) components, normalization is \(O(K^2)\) and mixture-vs-mixture overlap is \(O(K^2)\). For small K this is typically negligible; for large K consider caching Gram matrices keyed by component signatures.

Fourier convention

This module follows the same Fourier convention as GaussianEnvelope:

\[Z(\omega) = \int_{-\infty}^{\infty} \zeta(t)\,e^{+i\omega t}\,dt.\]

The absolute overall scale of freq_eval() is intended to be consistent within the package, but should not be treated as a universal physical normalization unless the convention is standardized across all backends.

Examples

See examples/gaussian_mixture_overlap.py for: - plotting the time-domain envelope of a mixture, - overlap magnitude vs delay, - and the spectral intensity profile.

Classes

FitReport(tmin, tmax, n_samples, l2_rel, ...)

Diagnostics for a function-to-mixture fit.

GaussianMixtureEnvelope(components, weights)

Linear combination of normalized closed-form Gaussian envelopes.

class FitReport(tmin: float, tmax: float, n_samples: int, l2_rel: float, linf_rel: float, k_used: int) None

Bases: object

Diagnostics for a function-to-mixture fit.

Parameters:
tmin, tmax

Fit interval.

n_samples

Number of samples used in the fit.

l2_rel

Relative L2 error on the fit grid: ||f - f_hat||_2 / ||f||_2.

linf_rel

Relative max error on the fit grid: max|f - f_hat| / max|f|.

k_used

Number of Gaussian components used.

Notes

Errors are computed on the sampling grid used during fitting and are therefore fit-window dependent.

k_used: int
l2_rel: float
linf_rel: float
n_samples: int
tmax: float
tmin: float
class GaussianMixtureEnvelope(components: tuple[GaussianEnvelope, ...], weights: ndarray[tuple[Any, ...], dtype[complexfloating[Any, Any]]], report: FitReport | None = None) None

Bases: BaseEnvelope

Linear combination of normalized closed-form Gaussian envelopes.

A Gaussian mixture envelope is defined as a finite superposition

\[\zeta(t) = \sum_{k=1}^{K} c_k\,g_k(t),\]

where each \(g_k(t)\) is a normalized GaussianEnvelope (same closed-form Gaussian family), and the complex weights \(c_k\) are stored in weights.

Normalization

This class enforces that the mixture is a mode descriptor:

\[\langle \zeta, \zeta \rangle = 1.\]

Since \(\zeta\) is a superposition, its norm depends on pairwise overlaps:

\[\|\zeta\|^2 = \sum_{i=1}^{K}\sum_{j=1}^{K} \overline{c_i}\,c_j\,\langle g_i, g_j\rangle.\]

In __post_init__(), the provided weights are rescaled by

\[c_k \leftarrow \frac{c_k}{\sqrt{\|\zeta\|^2}}\]

using closed-form overlaps \(\langle g_i, g_j\rangle\).

Overlaps

If the other envelope is in the same closed-form Gaussian family, overlaps are computed without numerical quadrature.

  1. Mixture vs single Gaussian:

\[\langle \zeta, h\rangle = \sum_{i=1}^{K} \overline{c_i}\,\langle g_i, h\rangle.\]
  1. Mixture vs mixture:

\[\left\langle \sum_i c_i g_i,\ \sum_j d_j h_j \right\rangle = \sum_{i=1}^{K}\sum_{j=1}^{L} \overline{c_i}\,d_j\,\langle g_i, h_j\rangle.\]

Here \(\langle g_i, h_j\rangle\) is evaluated by GaussianEnvelope.overlap_gaussian_closed().

Time and frequency evaluation

Evaluation is performed by linear superposition:

\[\zeta(t) = \sum_k c_k g_k(t), \qquad Z(\omega) = \sum_k c_k G_k(\omega).\]

Heuristics

center_and_scale() returns a plotting/overlap heuristic. The center is a power-weighted average of component centers (\(|c_k|^2\) weights) and the scale is the maximum component \(\sigma_t\) (conservative window choice).

type components:

tuple[GaussianEnvelope, ...]

param components:

Tuple of component GaussianEnvelope objects. Must be non-empty.

type weights:

ndarray[tuple[Any, ...], dtype[complexfloating[Any, Any]]]

param weights:

Complex 1D numpy array of shape (K,). Length must match len(components). The array is copied/coerced to complex and then rescaled in __post_init__() to enforce unit norm.

type report:

FitReport | None

param report:

Optional FitReport describing how the mixture was obtained (for example from a fit of a target function on a chosen time interval).

raises ValueError:

If weights is not 1D, if lengths mismatch, if components are empty, or if the computed norm is non-positive / non-finite.

_abc_impl = <_abc._abc_data object>
static _norm2_closed(weights: ndarray[tuple[Any, ...], dtype[complexfloating[Any, Any]]], comps: tuple[GaussianEnvelope, ...]) float

Compute the squared norm of a Gaussian mixture in closed form.

For a mixture

\[\zeta(t) = \sum_{k=1}^{K} c_k g_k(t),\]

the squared norm is

\[\|\zeta\|^2 = \sum_{i=1}^{K}\sum_{j=1}^{K} \overline{c_i}\,c_j\,\langle g_i, g_j\rangle.\]

This helper evaluates that quantity using analytic pairwise overlaps between the component GaussianEnvelope objects.

Parameters:
Returns:

Real-valued squared norm of the mixture.

Return type:

float

Notes

The return value is the real part of the accumulated overlap sum. For physically consistent inputs this should be non-negative, up to small numerical error.

approx_signature(*, decimals: int = 12, ignore_global_phase: bool = False) tuple[object, ...]

Approximate signature with rounded floating parameters.

Parameters:
  • decimals (int) – Number of decimals to round to.

  • ignore_global_phase (bool) – If True, treat \(\phi_0\) as zero for grouping.

Returns:

Rounded/approximate signature tuple.

Return type:

Signature

center_and_scale() tuple[float, float]

Return plotting/overlap heuristics.

Returns:

  • center – Center time (\(\tau\)).

  • scale – Characteristic scale (\(\sigma_t\)).

Return type:

tuple[float, float]

components: tuple[GaussianEnvelope, ...]
delayed(dt: float) GaussianMixtureEnvelope

Return a copy delayed by dt.

Parameters:

dt (float) – Time shift to add to \(\tau\).

Returns:

Delayed envelope.

Return type:

GaussianMixtureEnvelope

formalism: ClassVar[Literal['generic', 'gaussian_closed']] = 'gaussian_closed'
freq_eval(w: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the frequency-domain spectrum \(Z(\omega)\).

This returns a GaussianMixture spectrum consistent with the time-domain definition used in time_eval(), up to an overall real scale factor.

Parameters:

w (ndarray[tuple[Any, ...], dtype[double]]) – Frequency grid (angular frequency \(\omega\)).

Returns:

Complex samples of the spectrum.

Return type:

RCArray

classmethod from_callable(func: Callable[[ndarray[tuple[Any, ...], dtype[float64]]], ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]], *, tmin: float, tmax: float, k: int, omega0: float = 0.0, n_samples: int = 2000, sigma: float | None = None) GaussianMixtureEnvelope

Fit a Gaussian-mixture envelope to a time-domain target field.

This constructor fits a complex-valued time-domain amplitude \(f(t)\) on a uniform grid over [tmin, tmax] using a linear combination of GaussianEnvelope basis functions:

\[f(t) \approx \sum_{j=1}^{K} c_j g_j(t).\]

The component centers are chosen uniformly across the fit interval, all components share the same carrier frequency omega0, and a common width sigma is used. If sigma is not provided, a simple window-based heuristic is used.

Parameters:
Returns:

Normalized Gaussian mixture with an attached fit report.

Return type:

GaussianMixtureEnvelope

Raises:

ValueError – If the fit configuration is invalid.

classmethod from_lorentzian(*, gamma: float, tau: float = 0.0, omega0: float = 0.0, phi0: float = 0.0, k: int = 8, n_samples: int = 2000, window_multiple: float = 8.0) GaussianMixtureEnvelope

Construct a Gaussian mixture approximation to a Lorentzian pulse.

This convenience constructor fits a Gaussian mixture to the time-domain target field

\[f(t) = e^{i\phi_0} \frac{1}{1 + \left(\frac{t-\tau}{\gamma}\right)^2} e^{i\omega_0 (t-\tau)}.\]

The fit is performed on a symmetric time window around \(\tau\):

\[[\,\tau - m\gamma,\ \tau + m\gamma\,],\]

where \(m\) is window_multiple.

Parameters:
  • gamma (float) – Lorentzian width parameter. Must be positive.

  • tau (float) – Center time of the pulse.

  • omega0 (float) – Carrier angular frequency.

  • phi0 (float) – Global phase offset.

  • k (int) – Number of Gaussian basis components used in the fit.

  • n_samples (int) – Number of time samples used for the fitting procedure.

  • window_multiple (float) – Half-window size expressed in multiples of gamma.

Returns:

Normalized Gaussian mixture approximating the Lorentzian target, with an attached fit report.

Return type:

GaussianMixtureEnvelope

Raises:

ValueError – If gamma is not positive.

Notes

This is a numerical approximation utility built on top of from_callable(). The resulting mixture is normalized as a mode descriptor after fitting.

overlap_gaussian_closed(other: SupportsGaussianClosedOverlap) complex

Compute the closed-form overlap with another Gaussian-closed envelope.

Supported cases are:

  1. Mixture vs single Gaussian:

\[\langle \zeta, h\rangle = \sum_i \overline{c_i}\,\langle g_i, h\rangle.\]
  1. Mixture vs mixture:

\[\left\langle \sum_i c_i g_i,\ \sum_j d_j h_j \right\rangle = \sum_i \sum_j \overline{c_i}\,d_j\,\langle g_i, h_j\rangle.\]

In both cases, pairwise overlaps are evaluated analytically using GaussianEnvelope.overlap_gaussian_closed().

Parameters:

other (SupportsGaussianClosedOverlap) – Another envelope in the same closed Gaussian formalism.

Returns:

Complex overlap \(\langle \text{self}, \text{other} \rangle\).

Return type:

complex

Raises:

TypeError – If other is not a supported Gaussian-closed envelope type.

Notes

This method supports overlaps with GaussianEnvelope and GaussianMixtureEnvelope.

phased(dphi: float) GaussianMixtureEnvelope

Return a copy with an added global phase.

Parameters:

dphi (float) – Phase increment to add to \(\phi_0\).

Returns:

Phased envelope.

Return type:

GaussianMixtureEnvelope

report: FitReport | None = None
property signature: tuple[object, ...]

Stable signature for caching/comparison.

time_eval(t: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the time-domain complex field \(\zeta(t)\).

Parameters:

t (ndarray[tuple[Any, ...], dtype[double]]) – Time grid.

Returns:

Complex samples of the field.

Return type:

RCArray

weights: ndarray[tuple[Any, ...], dtype[complexfloating[Any, Any]]]
Parameters: