kumulant

FrugalMadStat

class FrugalMadStat(val stepSize: Double = StatDefaults.FRUGAL_QUANTILE_STEP_SIZE, val concurrency: Concurrency = Concurrency.None) : SeriesStat<MadResult> (source)

Constant-memory adaptive median and median absolute deviation estimates.

The first observation seeds the center and zero deviation. Each later update moves both estimates toward their targets by at most half stepSize, clamped to avoid overshooting. The deviation target is the absolute residual against the pre-update center. Constant steps forget earlier centers gradually; these estimates track a changing distribution rather than reconstructing its historical MAD.

Positive weights each count as one observation, as in com.eignex.kumulant.stat.quantile.FrugalQuantileStat. Zero and non-finite weights are inert; negative weights throw because the recurrence has no inverse. Choose stepSize in the input's units: larger steps adapt faster with more jitter.

Use cases: lightweight robust center/scale monitoring where bounded state and adaptation matter more than quantile accuracy. Use MadStat for digest-based historical estimates, observation weights, and digest-backed merging.

Memory: O(1); two estimates, an initialization flag, and a lock.

Update: O(1); two bounded adjustments, with no per-update allocation.

Concurrency: Body locked under any concurrent level. Updates, reads, and resets see a coherent pair; estimates remain sensitive to observation order. Merge adopts a nonempty remote pair while empty and otherwise averages both estimates equally, without reconstructing the combined distribution or its observation weights.

Constructors

FrugalMadStat

constructor(stepSize: Double = StatDefaults.FRUGAL_QUANTILE_STEP_SIZE, concurrency: Concurrency = Concurrency.None)(source)

Properties

concurrency

open override val concurrency: Concurrency(source)

Thread-safety mode fixed at construction. See Concurrency for the shared contract and the implementation's KDoc for its cell and lock strategy.

stepSize

Full step size in input units; each median adjustment is bounded by half this value.

Functions

create

open override fun create(concurrency: Concurrency? = null): FrugalMadStat(source)

Create an independent accumulator at the configured baseline. A null concurrency preserves this accumulator's mode; a non-null value overrides it. Modality subtypes narrow the return type to preserve the input shape.

merge

open override fun merge(values: MadResult, timestampNanos: Long = currentTimeNanos())(source)

Fold a compatible snapshot values into this accumulator at timestampNanos. Implementations document whether the combine is exact or approximate and which state the snapshot omits. The source accumulator is unaffected.

Time-dependent statistics, such as windows, place the snapshot at timestampNanos, which must share the clock the caller uses for updates and reads. Time-independent statistics ignore it.

read

open override fun read(timestampNanos: Long = currentTimeNanos()): MadResult(source)

Return the current result evaluated at timestampNanos. Time-independent statistics ignore the timestamp. Reading does not add an observation.

Snapshot consistency depends on the implementation's synchronisation. Locks protect coupled state under Concurrency.Strict and Concurrency.HighWrite; independently updated cells and JVM striped adders can still yield a best-effort snapshot. Concurrency.Relaxed permits drift across coupled cells.

reset

open override fun reset()(source)

Restore the configured baseline, including any prior seed. Preserves the configuration and concurrency.

Link copied to clipboard
open fun update(value: Double, weight: Double = 1.0)

Record value with weight at the current monotonic time.

open override fun update(value: Double, timestampNanos: Long, weight: Double = 1.0)

Record value with weight at timestampNanos.

Link copied to clipboard
open fun validateMerge(values: MadResult)

Validate values for merge without changing accumulator state. Containers validate every child before merging any of them. Successful validation checks compatibility; it does not make a concurrent merge transactional.

update

open override fun update(value: Double, timestampNanos: Long, weight: Double = 1.0)(source)

Record value with weight at timestampNanos.