kumulant

kumulant API reference

Kumulant is a streaming machine-learning library for Kotlin Multiplatform. Every model runs online: feed observations into an accumulator one at a time, ask for a result whenever you want one, and memory stays bounded no matter how long the stream runs. Two accumulators of the same shape can be merged into one, so partial results from parallel workers stitch back together without re-reading inputs.

Mental model

Every accumulator implements com.eignex.kumulant.core.Stat. The contract is three verbs and one constant:

  • update(...) folds a single observation into the running state. The exact signature depends on the modality (see the stat package for the four modality interfaces).

  • read() materialises the current state as an immutable Result. Reads never mutate; call them as often as you like.

  • merge(snapshot) folds another accumulator's snapshot into this one. Snapshots are the merge unit, not live accumulators; that is what lets merge cross a process boundary.

  • concurrency: Concurrency records the thread-safety contract the stat was built for. See com.eignex.kumulant.core.Concurrency.

reset() returns the stat to its construction baseline. create() spawns a fresh accumulator with the same configuration, optionally overriding the concurrency mode.

val mean = MeanStat()
for (x in doubleArrayOf(1.0, 2.0, 3.0)) mean.update(x)
val snapshot = mean.read()
println(snapshot.mean) // 2.0

val peer = MeanStat()
for (x in doubleArrayOf(4.0, 5.0)) peer.update(x)
mean.merge(peer.read())
println(mean.read().mean) // 3.0

The compile-checked version of this example lives at com.eignex.kumulant.samples.basicMeanLifecycle, pulled into the rendered API docs via @sample directives on individual classes.

What's in the library

  • com.eignex.kumulant.core: the Stat and Result interfaces, the Concurrency enum, and the cross-cutting result traits.

  • com.eignex.kumulant.stat: concrete accumulators grouped by family: summary, quantile, cardinality, sketch, rate, decay, regression (with glm/ and tree/ subfamilies), score, calibration, anomaly, event, change, forecast.

  • com.eignex.kumulant.operation: composable wrappers that change how a stat sees its input (filtering, weighting, windowing, sampling, lagging) or how it reports its output (folding, transforming, projecting).

  • com.eignex.kumulant.schema: typed, named, wire-portable schemas. Declare a bag of stats once, materialise it into a live StatGroup, encode the schema to wire and rehydrate on the other side.

  • com.eignex.kumulant.bandit: multi-armed and contextual bandits built on the same Stat/Result foundation.

Conventions

  • Every concrete stat ships a sibling StatSpec data class (or data object for parameter-less stats) carrying configuration only. Specs are @Serializable with @SerialName discriminators matching the Kotlin class names, so polymorphic JSON / CBOR / Protobuf put the same type strings on the wire regardless of format.

  • Every public type has KDoc with a one-sentence summary, then **Use cases:**, **Memory:**, **Update:**, and **Concurrency:** sections. See com.eignex.kumulant.stat.summary.MeanStat for the canonical shape.

  • Results are immutable, sealed where it makes sense, and structurally comparable via equals/hashCode. The value that comes out of read() is the same value that goes into merge() over the wire.

Packages

Link copied to clipboard
common

Multi-armed and contextual bandits built on the same Stat / Result foundation as the rest of the library.

Link copied to clipboard
common

Contextual bandits: each round comes with a feature vector, and the reward depends on both the chosen arm and the context. Three families, covering linear / non-linear / non-parametric reward models plus the adversarial-expert case.

Link copied to clipboard
common

Indexless multi-armed bandits. Each round, the bandit picks one of K arms via choose(), the caller observes a reward, and update(arm, value, weight) folds it back into that arm's accumulator. No per-round feature vector; for that, see com.eignex.kumulant.bandit.contextual.

Link copied to clipboard
common

Foundation types every other package builds on. Everything else in the library imports from here: the modality interfaces, the result hierarchy, the cross-cutting result traits, and the concurrency contract.

Link copied to clipboard
common
nonJvm
Link copied to clipboard
common
Link copied to clipboard
common

Typed, named, wire-portable schemas for declaring bags of stats. A StatSchema does three things:

Link copied to clipboard
common

Concrete accumulators grouped by family. Each family lives in its own subpackage; this page is the navigation index.

Link copied to clipboard
common

Online anomaly detectors. All three primitives produce a score(x) method on their result so the same downstream pipeline can consume "how anomalous is this observation?" regardless of which detector generated it.

Link copied to clipboard
common

Probability calibration: diagnosing when a classifier's predicted probabilities are out of step with the empirical positive rate, and two complementary mappings that fix it.

Link copied to clipboard
common

Approximate distinct-count estimators. Both entries take a stream of opaque Long keys (com.eignex.kumulant.core.DiscreteStat) and answer "how many distinct keys have I seen?" in bounded memory. The right pre-step is to hash domain-specific keys through com.eignex.kumulant.math.hash64 / com.eignex.kumulant.math.Hasher64 so the input has uniform 64-bit entropy; value.hashCode().toLong() only provides 32 bits and skews the estimators on low-cardinality domains.

Link copied to clipboard
common

Drift detectors. Each member tracks a running statistic, applies a configurable threshold, and exposes an alarm flag on its result. The three differ in what they assume about the in-control state and how they decide a shift has occurred.

Link copied to clipboard
common

Time-weighted moments. Each observation enters the accumulator with a weight that shrinks toward zero with age, so older observations contribute less. Two parallel sub-families: timestamp-based decay (the Decaying* stats) and step-based EWMA (the Ewma* stats).

Link copied to clipboard
common

Stats whose output is discrete-temporal in shape: state transitions, dwell times, last-seen timestamps, level crossings, peak excursions. They share the streaming-stats discipline but their results carry counts of state changes and timestamps rather than numeric aggregates.

Link copied to clipboard
common

Predictive recurrences with multi-cell state. Their results expose forecast(steps) projections, distinguishing them from the decay family's running-moment shape.

Link copied to clipboard
common

Bounded-memory quantile estimators and histograms. Every entry trades a different precision-versus-cost knob: relative error guarantees, fixed-precision over a known range, reservoir sampling for raw values back, or constant memory at the cost of accuracy.

Link copied to clipboard
common

Throughput estimators. All three implement com.eignex.kumulant.core.HasRate, so a downstream consumer can pull rate (events per second) or per(duration) through one trait regardless of which underlying estimator produced the snapshot.

Link copied to clipboard
common

Family root for the regression-modality stats and the cross-cutting infrastructure they share. The single-output linear-model family lives in glm, the decision-tree and random-forest family in tree. What sits directly in this package is the small set of stats that don't fit either subfamily, plus the strategy types both rely on.

Link copied to clipboard
common

Generalised linear models; the linear-predictor-plus-link family. Every model in this package shares the shape eta = bias + x . weights followed by mu = link.invMean(eta); they differ in how the posterior over weights is maintained.

Link copied to clipboard
common

Online VFDT decision trees and random forests, plus the shared machinery they're built on. The package covers both regression (continuous y) and classification (y in [0, numClasses)) under one consistent shape.

Link copied to clipboard
common

Online evaluation metrics. Inputs are paired (prediction, truth) observations (or richer shapes for distributional metrics) and outputs are accuracy / discrimination / calibration / distributional summaries.

Link copied to clipboard
common

Structural queries on a stream that aren't shaped like a cardinality or a quantile. Four members; each answers a different question.

Link copied to clipboard
common

Exact running aggregates over a stream of scalars. Memory is constant in the stream length; updates are O(1); every entry merges cleanly across parallel workers via Chan-style parallel formulas or commuting cell arithmetic.