kumulant

RegressionTree

class RegressionTree<Row>(splitCandidates: List<Split<Row>>, config: RegressionTreeConfig = RegressionTreeConfig(), concurrency: Concurrency = Concurrency.None, leafArmFactory: () -> SeriesStat<WeightedVarianceResult> = { VarianceStat(concurrency) }, randomSeed: Int = 0)(source)

Online VFDT-style decision tree partitioning feature rows of type Row. Each leaf carries a weighted-variance accumulator; audit leaves additionally track pos/neg sub-arms per candidate split and, every RegressionTreeConfig.splitPeriod observations, evaluate them against the Hoeffding bound to decide whether to convert themselves into a RegressionSplitNode.

The engine is generic over the feature representation: it only ever inspects a row by calling Split.direction, so any feature type can drive growth by supplying its own Splits (e.g. a dense com.eignex.koblas.core.F64VectorView for the built-in stats, or a typed/constraint-coupled row from a downstream library). Wire-portable serialization of a snapshot is only meaningful for the com.eignex.koblas.core.F64VectorView case and lives in TreeRegressionResult.kt as VectorView-constrained extensions.

Internal split nodes hold no live arm; subtree aggregates (rootSnapshot, the value fields on the snapshot results) are derived by combining descendants at snapshot/merge time. The hot update path therefore touches exactly one arm: the leaf the observation routes to.

The growth algorithm itself is shared with ClassificationTree; both are thin facades over TreeGrowth, which they parameterise by their own node types.

Concurrency: leaf-arm updates run lock-free (the arms themselves honour concurrency). The split-conversion path; the only one that mutates tree structure; is serialised by a single per-tree lock, fired only every RegressionTreeConfig.splitPeriod observations per audit leaf. Pointer writes on the hot path are skipped when the child reference is unchanged, so the typical update is pure arm arithmetic.

Constructors

RegressionTree

constructor(splitCandidates: List<Split<Row>>, config: RegressionTreeConfig = RegressionTreeConfig(), concurrency: Concurrency = Concurrency.None, leafArmFactory: () -> SeriesStat<WeightedVarianceResult> = { VarianceStat(concurrency) }, randomSeed: Int = 0)(source)

Properties

nodeCount

Number of internal + leaf nodes currently in the tree.

Functions

findLeaf

Walk to the leaf row resolves to.

merge

Structurally merge other into this tree. other is consumed (its node references may be grafted into this tree) and must not be used afterwards. See TreeGrowth.mergeTree for the alignment rules.

predict

fun predict(row: Row): Double(source)

Mean of the leaf row resolves to.

prettyPrint

fun prettyPrint(indent: String = ""): String(source)

Render the tree as nested if (split) { ... } else { ... } text.

reset

fun reset()(source)

Reset to a single fresh leaf.

rootNode

Live root node, for snapshotting.

rootSnapshot

Aggregate snapshot at the root; derived by walking leaves and any RegressionSplitNode.carryover aggregates. Under concurrent updates with active growth, pointer races at split-time can leak observations into orphaned sub-arms; this walk is therefore best-effort and may drift by a few ULPs of the configured workload under contention. Single-threaded runs are exact.

update

fun update(row: Row, value: Double, weight: Double = 1.0)(source)

Fold an observation into the tree, possibly growing it.

Link copied to clipboard
fun RegressionTree<F64VectorView>.mergeSnapshot(other: TreeNodeResult)

Snapshot merge using only the immutable result. Mirrors RegressionTree.merge but the "other" side is a TreeNodeResult tree-of-results rather than a live tree. F64VectorView only, for the same reason snapshot is.