mixle.stats.directional.wrapped_normal module

Wrapped normal distribution – a Gaussian wrapped around the circle.

Wrapping X ~ N(mu, sigma^2) onto angles gives the wrapped normal WN(mu, sigma^2), the most common symmetric circular law and the maximum-entropy distribution for a fixed circular mean and resultant. Its density is the periodic sum of Gaussians,

f(theta; mu, sigma^2) = (1 / (sigma sqrt(2 pi))) sum_k exp(-(wrap(theta - mu) + 2 pi k)^2 / (2 sigma^2)),

which is uniform as sigma -> inf and concentrates at mu as sigma -> 0. Its first trigonometric moment is rho e^{i mu} with rho = exp(-sigma^2 / 2), so the mean direction and concentration are estimated in closed form from the mean resultant: mu = atan2(sum sin, sum cos) and sigma^2 = -2 log Rbar. It samples exactly by wrapping N(mu, sigma^2).

The density is summed over enough wraps (K set from sigma) that every retained Gaussian is machine-negligible past the window, which keeps the truncated sum strictly positive (unlike the trigonometric-series form, which can dip negative when truncated).

Reference: Mardia & Jupp, Directional Statistics (2000), sec. 3.5.7.

class WrappedNormalDistribution(mu, sigma2, name=None, keys=None)[source]

Bases: SequenceEncodableProbabilityDistribution

Wrapped normal distribution with mean direction mu and wrapped variance sigma2 > 0.

Parameters:
property K: int

Number of wraps summed on each side of the window.

density(x)[source]

Return the probability density at a single angle (radians).

Parameters:

x (float)

Return type:

float

log_density(x)[source]

Return the log-density at a single angle (radians).

Parameters:

x (float)

Return type:

float

seq_log_density(x)[source]

Return vectorized log-density for a sequence-encoded array of angles.

Parameters:

x (ndarray)

Return type:

ndarray

classmethod compute_capabilities()[source]

Describe backend support for generated wrapped-normal kernels.

classmethod compute_declaration()[source]

Return the structured compute declaration for wrapped normal distributions.

static backend_legacy_sufficient_statistics(x, params, engine)[source]

Per-row circular moments (sum_cos, sum_sin, count) — uses the engine trig tier.

Parameters:
Return type:

tuple[Any, …]

backend_seq_log_density(x, engine)[source]

Engine-neutral vectorized log-density: the (2K+1)-branch wrapped logsumexp on engine ops.

Parameters:
Return type:

Any

sampler(seed=None)[source]

Return a sampler that wraps N(mu, sigma2) onto the circle.

Parameters:

seed (int | None)

Return type:

WrappedNormalSampler

estimator(pseudo_count=None)[source]

Return a closed-form (mean-resultant) estimator for mu and sigma2.

Parameters:

pseudo_count (float | None)

Return type:

WrappedNormalEstimator

dist_to_encoder()[source]

Return the data encoder used by this distribution (the angle itself).

Return type:

WrappedNormalDataEncoder

class WrappedNormalSampler(dist, seed=None)[source]

Bases: DistributionSampler

Draw angles by wrapping N(mu, sigma2) around the circle.

Parameters:
  • dist (WrappedNormalDistribution)

  • seed (int | None)

sample(size=None)[source]

Draw one angle or an array of iid angles.

Parameters:

size (int | None)

Return type:

float | ndarray

class WrappedNormalAccumulator(name=None, keys=None)[source]

Bases: SequenceEncodableStatisticAccumulator

Accumulate the weighted circular resultant (sum cos, sum sin, count).

Parameters:
  • name (str | None)

  • keys (str | None)

update(x, weight, estimate)[source]

Accumulate one weighted circular resultant contribution.

Parameters:
  • x (float)

  • weight (float)

  • estimate (WrappedNormalDistribution | None)

Return type:

None

initialize(x, weight, rng)[source]

Initialize statistics from one angle.

Parameters:
Return type:

None

seq_update(x, weights, estimate)[source]

Accumulate circular resultant statistics from encoded angles.

Parameters:
Return type:

None

seq_initialize(x, weights, rng)[source]

Initialize statistics from encoded angles.

Parameters:
Return type:

None

combine(suff_stat)[source]

Merge another wrapped-normal sufficient-statistic tuple.

Parameters:

suff_stat (tuple[float, float, float])

Return type:

WrappedNormalAccumulator

value()[source]

Return cosine sum, sine sum, and total weight.

Return type:

tuple[float, float, float]

from_value(x)[source]

Replace accumulator contents from circular-resultant statistics.

Parameters:

x (tuple[float, float, float])

Return type:

WrappedNormalAccumulator

key_merge(stats_dict)[source]

Merge keyed statistics into stats_dict when keys are configured.

Parameters:

stats_dict (dict[str, Any])

Return type:

None

key_replace(stats_dict)[source]

Replace this accumulator from keyed statistics when available.

Parameters:

stats_dict (dict[str, Any])

Return type:

None

acc_to_encoder()[source]

Return the encoder used by this accumulator.

Return type:

WrappedNormalDataEncoder

class WrappedNormalAccumulatorFactory(name=None, keys=None)[source]

Bases: StatisticAccumulatorFactory

Factory for WrappedNormalAccumulator.

Parameters:
  • name (str | None)

  • keys (str | None)

make()[source]

Create a fresh wrapped-normal accumulator.

Return type:

WrappedNormalAccumulator

class WrappedNormalEstimator(sigma2_max=1.0e6, name=None, keys=None)[source]

Bases: ParameterEstimator

Estimate mu and sigma2 from the mean resultant (rho = exp(-sigma2/2)).

Parameters:
  • sigma2_max (float)

  • name (str | None)

  • keys (str | None)

accumulator_factory()[source]

Return an accumulator factory for circular-resultant statistics.

Return type:

WrappedNormalAccumulatorFactory

estimate(nobs, suff_stat)[source]

Estimate mean direction and variance from the mean resultant.

Parameters:
Return type:

WrappedNormalDistribution

class WrappedNormalDataEncoder[source]

Bases: DataSequenceEncoder

Encode angles as a float array (wrapped to (-pi, pi]).

seq_encode(x)[source]

Encode angles after wrapping them to (-pi, pi].

Parameters:

x (Sequence[float])

Return type:

ndarray