kumulant

schema.expr

The serializable expression AST behind the lambda-bound operations in com.eignex.kumulant.schema. When an operation needs a projection or a predicate that must travel on the wire rather than as a live Kotlin lambda, it carries one of these trees instead. The whole tree is serializable, so a filter or a transform round-trips as data and rebuilds an identical closure on the far side.

The three trees

There are three sealed hierarchies, one per result shape. ScalarExpr evaluates to a single number from an update's value, its paired second component, and the current vector. VectorExpr evaluates to a whole vector and backs the per-feature projection and scaling operations. BoolExpr evaluates to a boolean and drives filter predicates and the guards on conditional nodes. Each hierarchy is sealed, so serialization is closed and exhaustive: every node carries a discriminator and decoding can never land on an unknown shape.

Leaves and operators

The scalar leaves are the update value X, the paired second component Y, a vector coordinate V, and a literal Const. Arithmetic composes them with the ordinary operators and with dedicated nodes for the transcendental functions: powers, logs, exponentials, square roots, and absolute value. Comparisons between scalars produce a BoolExpr, and the boolean combinators join several predicates into one.

Sugar nodes

Common shapes have dedicated nodes so a serialized tree stays readable rather than ballooning into nested arithmetic. Standardizing, min-max scaling, centering, and range tests each have their own node, as does the multi-branch Switch and the conditional IfExpr. Vector projection has nodes for dot products, element selection, single-coordinate access, and a fold whose operator picks sum, min, max, or mean.

Anything that cannot be expressed as one of these nodes stays a live-only lambda on the com.eignex.kumulant.core.Stat side and is not wire-expressible. Reach for the lambda overloads of the filter and transform operations in com.eignex.kumulant.operation when that happens.

Types

Link copied to clipboard
@Serializable
sealed interface BoolExpr

Wire-serialisable AST for boolean predicates over the same input environment as ScalarExpr. Consumed by every spec-side filter operator and by IfExpr's condition slot.

Link copied to clipboard
@Serializable
@SerialName(value = "Center")
data object Center : ScalarExpr

Reads the center field of the feedback primary's snapshot. Requires the primary's result to implement HasCenterScale; raises IllegalStateException when evaluated without a primary, or when the primary's result does not expose a center.

Link copied to clipboard
@Serializable
@SerialName(value = "Const")
data class Const(val v: Double) : ScalarExpr

Wire spec for a constant scalar.

Link copied to clipboard
@Serializable
@SerialName(value = "High")
data object High : ScalarExpr

Reads the max field of the feedback primary's snapshot. Requires the primary's result to implement HasMinMax; raises IllegalStateException when evaluated without such a primary.

Link copied to clipboard
@Serializable
@SerialName(value = "IfExpr")
data class IfExpr(val cond: BoolExpr, val then: ScalarExpr, val otherwise: ScalarExpr) : ScalarExpr

Wire spec for a ternary if (cond) then else otherwise.

Link copied to clipboard
@Serializable
@SerialName(value = "In")
data class In(val of: ScalarExpr, val values: List<Double>) : BoolExpr

Membership test: of in values (exact equality). Use it to flatten chains of Eq predicates joined by Or; e.g. VIndex In listOf(0.0, 3.0).

Link copied to clipboard
@Serializable
@SerialName(value = "Low")
data object Low : ScalarExpr

Reads the min field of the feedback primary's snapshot. Requires the primary's result to implement HasMinMax; raises IllegalStateException when evaluated without such a primary.

Link copied to clipboard
@Serializable
@SerialName(value = "MinMax")
data class MinMax(val targetLow: Double = DEFAULT_TARGET_LOW, val targetHigh: Double = DEFAULT_TARGET_HIGH) : ScalarExpr

Min-max projection mapping X from [primary.min, primary.max] to [targetLow, targetHigh], emitting targetLow while the running range is still degenerate. Reusable AST sugar for the min-max-scaler pattern; requires a HasMinMax primary.

Link copied to clipboard
@Serializable
sealed interface ScalarExpr

Wire-serialisable AST for scalar expressions over the per-update input environment. The library uses these wherever a stat needs to apply a caller-supplied projection / weight / threshold expression that has to round-trip on the wire; weightBy, transform, the per-bin scaler projections, the WithFeedback op, the loss / pinball / quantile configurations.

Link copied to clipboard
@Serializable
@SerialName(value = "Scale")
data object Scale : ScalarExpr

Reads the scale field of the feedback primary's snapshot. Requires the primary's result to implement HasCenterScale; raises IllegalStateException when evaluated without a primary, or when the primary's result does not expose a scale.

Link copied to clipboard
@Serializable
@SerialName(value = "Standardize")
data object Standardize : ScalarExpr

Z-score projection: (X - Center) / Scale, emitting 0 when Scale is still zero. Reusable AST sugar for the standard-scaler pattern; requires a HasCenterScale primary.

Link copied to clipboard
@Serializable
@SerialName(value = "Switch")
data class Switch(val on: ScalarExpr, val cases: List<SwitchCase>, val otherwise: ScalarExpr) : ScalarExpr

Multi-way branch on a scalar key. Replaces nested IfExpr cascades. The first case whose SwitchCase.value equals on.eval(...) exactly wins; if none match, otherwise is returned.

Link copied to clipboard
@Serializable
@SerialName(value = "SwitchCase")
data class SwitchCase(val value: Double, val then: ScalarExpr)

One case of a Switch expression: when on evaluates to value (exact equality), the result is then. Exact double equality is fine for integer-valued keys like VIndex; not recommended for general continuous comparisons.

Link copied to clipboard
@Serializable
@SerialName(value = "V")
data class V(val index: Int) : ScalarExpr

v[index] - out-of-bounds throws at eval time.

Link copied to clipboard
@Serializable
sealed interface VectorExpr

Wire-serialisable AST for vector-valued expressions over the same input environment as ScalarExpr / BoolExpr. Used by the spec-side transformVector(VectorExpr) operator when the output is a fresh vector rather than a per-element transform.

Link copied to clipboard
@Serializable
enum VFoldOp : Enum<VFoldOp>

Reduction over the entire vector input. Distinct from element-level arithmetic (Add, Mul) - this collapses a DoubleArray of arbitrary length to a single scalar via the chosen operation.

Link copied to clipboard
@Serializable
@SerialName(value = "VIndex")
data object VIndex : ScalarExpr

In element-wise feedback contexts (vector / regression / paired), returns the coordinate index of the currently evaluating element as a Double. Outside such contexts (primary is not an IndexedResult), raises IllegalStateException.

Link copied to clipboard
@Serializable
@SerialName(value = "X")
data object X : ScalarExpr

Refers to the primary scalar input x.

Link copied to clipboard
@Serializable
@SerialName(value = "Y")
data object Y : ScalarExpr

Refers to the secondary scalar input y (paired stats only).

Functions

Link copied to clipboard

Absolute value of this expression.

Link copied to clipboard

True when every input to the update is finite, whichever modality the stat is.

Link copied to clipboard
infix fun BoolExpr.and(rhs: BoolExpr): BoolExpr

Short-circuiting conjunction.

Link copied to clipboard
operator fun ScalarExpr.div(rhs: ScalarExpr): ScalarExpr

Build Div of two expressions.

operator fun ScalarExpr.div(rhs: Double): ScalarExpr

Divide this expression by a literal rhs.

operator fun Double.div(rhs: ScalarExpr): ScalarExpr

Divide a literal receiver by an expression.

Link copied to clipboard
infix fun ScalarExpr.eq(rhs: ScalarExpr): BoolExpr

Exact equality (no tolerance).

infix fun ScalarExpr.eq(rhs: Double): BoolExpr

Exact equality against a literal (no tolerance).

Link copied to clipboard

e raised to this expression. Overflows to +Infinity well before Double runs out of range.

Link copied to clipboard
infix fun ScalarExpr.ge(rhs: ScalarExpr): BoolExpr

Greater-or-equal comparison.

infix fun ScalarExpr.ge(rhs: Double): BoolExpr

Greater-or-equal against a literal.

Link copied to clipboard
infix fun ScalarExpr.gt(rhs: ScalarExpr): BoolExpr

Strictly-greater-than comparison.

infix fun ScalarExpr.gt(rhs: Double): BoolExpr

Strictly-greater-than against a literal.

Link copied to clipboard

True when this expression falls within [min, max], both ends inclusive.

Link copied to clipboard

True when this expression evaluates to a finite number: not NaN, and not an infinity.

Link copied to clipboard

True when this expression evaluates to NaN.

Link copied to clipboard
infix fun ScalarExpr.le(rhs: ScalarExpr): BoolExpr

Less-or-equal comparison.

infix fun ScalarExpr.le(rhs: Double): BoolExpr

Less-or-equal against a literal.

Link copied to clipboard

Natural logarithm of this expression. ln(0) is -Infinity and a negative input gives NaN.

Link copied to clipboard
infix fun ScalarExpr.lt(rhs: ScalarExpr): BoolExpr

Strictly-less-than comparison.

infix fun ScalarExpr.lt(rhs: Double): BoolExpr

Strictly-less-than against a literal.

Link copied to clipboard

The larger of this expression and other.

The larger of this expression and a constant other.

Link copied to clipboard

The smaller of this expression and other.

The smaller of this expression and a constant other.

Link copied to clipboard

Build Sub of two expressions.

operator fun ScalarExpr.minus(rhs: Double): ScalarExpr

Subtract a literal rhs from this expression.

operator fun Double.minus(rhs: ScalarExpr): ScalarExpr

Subtract an expression from a literal receiver.

Link copied to clipboard
operator fun BoolExpr.not(): BoolExpr

Logical negation.

Link copied to clipboard
infix fun BoolExpr.or(rhs: BoolExpr): BoolExpr

Short-circuiting disjunction.

Link copied to clipboard
operator fun ScalarExpr.plus(rhs: ScalarExpr): ScalarExpr

Build Add of two expressions.

operator fun ScalarExpr.plus(rhs: Double): ScalarExpr

Add a literal rhs to this expression.

operator fun Double.plus(rhs: ScalarExpr): ScalarExpr

Add an expression to a literal receiver.

Link copied to clipboard

This expression raised to exponent.

This expression raised to a constant exponent.

Link copied to clipboard

Square root of this expression. A negative input gives NaN.

Link copied to clipboard

Build Mul of two expressions.

operator fun ScalarExpr.times(rhs: Double): ScalarExpr

Multiply this expression by a literal rhs.

operator fun Double.times(rhs: ScalarExpr): ScalarExpr

Multiply a literal receiver by an expression.

Link copied to clipboard

Unary minus: wraps in Neg.

Link copied to clipboard
fun vDot(weights: List<Double>): ScalarExpr

Weighted sum of the feature vector. weights must match the vector length at evaluation time.

fun vDot(vararg weights: Double): ScalarExpr

Weighted sum of the feature vector, varargs form.

Link copied to clipboard

Build an output vector by evaluating each expression in order; output length is exprs.size.

fun vectorOf(vararg exprs: ScalarExpr): VectorExpr

Build an output vector from expressions in order, varargs form.

Link copied to clipboard

Reduce the whole feature vector to one scalar with op.