pond-ts 0.53.1 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1175 -4
- package/README.md +25 -21
- package/dist/batch/aggregate-columns.d.ts +46 -7
- package/dist/batch/aggregate-columns.js +458 -105
- package/dist/batch/operators/arrow-types.d.ts +25 -0
- package/dist/batch/operators/arrow-types.js +180 -0
- package/dist/batch/operators/cumulative.js +82 -0
- package/dist/batch/operators/diff-rate.js +32 -0
- package/dist/batch/operators/flat-keys.d.ts +32 -0
- package/dist/batch/operators/flat-keys.js +103 -0
- package/dist/batch/operators/from-arrow.d.ts +96 -12
- package/dist/batch/operators/from-arrow.js +363 -23
- package/dist/batch/operators/ingest-columns.d.ts +15 -2
- package/dist/batch/operators/ingest-columns.js +211 -23
- package/dist/batch/operators/numeric-io.d.ts +114 -0
- package/dist/batch/operators/numeric-io.js +126 -0
- package/dist/batch/operators/to-arrow.d.ts +131 -0
- package/dist/batch/operators/to-arrow.js +169 -0
- package/dist/batch/operators/to-columns.d.ts +50 -0
- package/dist/batch/operators/to-columns.js +72 -0
- package/dist/batch/operators/value-rows.d.ts +58 -0
- package/dist/batch/operators/value-rows.js +164 -0
- package/dist/batch/time-series.d.ts +162 -17
- package/dist/batch/time-series.js +378 -51
- package/dist/batch/validate.d.ts +18 -0
- package/dist/batch/validate.js +18 -1
- package/dist/batch/value-series.d.ts +189 -11
- package/dist/batch/value-series.js +231 -16
- package/dist/index.d.ts +4 -2
- package/dist/reducers/avg.js +91 -4
- package/dist/reducers/blocked.d.ts +99 -0
- package/dist/reducers/blocked.js +178 -0
- package/dist/reducers/count.js +41 -0
- package/dist/reducers/max.js +57 -46
- package/dist/reducers/median.js +4 -1
- package/dist/reducers/min.js +57 -46
- package/dist/reducers/percentile.d.ts +25 -7
- package/dist/reducers/percentile.js +157 -27
- package/dist/reducers/stdev.js +68 -61
- package/dist/reducers/sum.js +68 -41
- package/dist/reducers/types.d.ts +31 -0
- package/dist/schema/index.d.ts +2 -1
- package/dist/schema/json.d.ts +65 -1
- package/dist/schema/value-io.d.ts +118 -0
- package/dist/schema/value-io.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -152,27 +152,31 @@ const points = series.sample({ reservoir: { size: 500 } }).toRows();
|
|
|
152
152
|
|
|
153
153
|
## Performance
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
155
|
+
Measured against three reference points (snapshot 2026-07-30; full tables,
|
|
156
|
+
methodology, and every losing number in the
|
|
157
|
+
[benchmark reference](website/docs/reference/benchmarks.mdx)):
|
|
158
|
+
|
|
159
|
+
- **vs pondjs** (the predecessor): faster on all 54 measurable shared
|
|
160
|
+
operations — geometric mean **20.7×**, `aggregate` up to 453×,
|
|
161
|
+
`median` 157×, and `select` / `rename` effectively instant (O(1)
|
|
162
|
+
column rebinds).
|
|
163
|
+
- **vs pandas** (500k-bar workload): roughly **even** — ahead on `ema`,
|
|
164
|
+
`mean`, `median` / `percentile`; behind ~1.1–1.9× on the rolling
|
|
165
|
+
studies. A five-study strategy pass runs 1.28× slower than pandas'
|
|
166
|
+
Cython kernels.
|
|
167
|
+
- **vs polars, single-threaded**: **ahead on composite studies**
|
|
168
|
+
(`bollinger` 0.53×, strategy stack 0.85×, `ema` 0.32× — lower is
|
|
169
|
+
pond-ts faster), behind 4–9× on whole-column reductions (the SIMD gap;
|
|
170
|
+
half-closed already by blocked summation) and on raw ingest, where
|
|
171
|
+
pond-ts front-loads validation the dataframe engines defer.
|
|
172
|
+
- **vs polars on all 10 cores**: behind ~3.5× on the strategy stack —
|
|
173
|
+
pond-ts has no parallelism today; a measured 2.42× worker-thread path
|
|
174
|
+
is on the roadmap (`[PND-PROCPAR]`).
|
|
175
|
+
|
|
176
|
+
The honest one-line version: the rewrite beat its predecessor by an order
|
|
177
|
+
of magnitude, holds its own per-core against the native engines on the
|
|
178
|
+
composite queries that dominate real workloads, and knows exactly where
|
|
179
|
+
it is behind. Run locally:
|
|
176
180
|
|
|
177
181
|
```sh
|
|
178
182
|
npm run build && node packages/core/bench/vs-pondjs.cjs
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { Column } from '../columnar/index.js';
|
|
2
|
-
import { Float64Column } from '../columnar/index.js';
|
|
1
|
+
import type { Column, ColumnSchema } from '../columnar/index.js';
|
|
2
|
+
import { ColumnarStore, Float64Column } from '../columnar/index.js';
|
|
3
|
+
import type { Interval } from '../core/interval.js';
|
|
3
4
|
import type { AggregateMap, AggregateOutputMap, AggregateReducer, RollingAlignment, ScalarKind, SeriesSchema } from '../schema/index.js';
|
|
4
5
|
/**
|
|
5
6
|
* Normalised column spec used by both batch and live aggregation paths.
|
|
@@ -35,10 +36,48 @@ export type AggregateColumnSpec = {
|
|
|
35
36
|
* same `mapping` shape produces the same schema.
|
|
36
37
|
*/
|
|
37
38
|
export declare function normalizeAggregateColumns<S extends SeriesSchema>(schema: S, mapping: AggregateMap<S> | AggregateOutputMap<S>): AggregateColumnSpec[];
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
/**
|
|
40
|
+
* **Columnar output for time-keyed `aggregate()` — [PND-IVLCOL].**
|
|
41
|
+
*
|
|
42
|
+
* Same gate and same bucket walk as the reduction fast path above, but
|
|
43
|
+
* the result is assembled as a `ColumnarStore` instead of a row array.
|
|
44
|
+
*
|
|
45
|
+
* **Why this exists.** `aggregate`'s output is interval-keyed, and the
|
|
46
|
+
* only construction door for an interval-keyed series used to be row
|
|
47
|
+
* intake — so the columnar fast path computed each bucket's answer in
|
|
48
|
+
* typed arrays, boxed it into a frozen `[Interval, …]` row, and then
|
|
49
|
+
* `new TimeSeries({ rows })` walked those rows straight back into
|
|
50
|
+
* columns. Measured on a 1M-row series at 16,667 buckets × 4 columns,
|
|
51
|
+
* that round trip cost **2.52 ms of a 5.01 ms call** — more than the
|
|
52
|
+
* reduction it was packaging. Writing the columns directly costs
|
|
53
|
+
* **0.09 ms** (spike: `spikes/columnar-wasm/bench/interval-columnar.mjs`).
|
|
54
|
+
*
|
|
55
|
+
* **Behaviour is identical, deliberately.** Trusted construction skips
|
|
56
|
+
* row intake, so every check row intake performed is performed here:
|
|
57
|
+
*
|
|
58
|
+
* - Cell kinds go through the *same* `assertCellKind` (shared, not
|
|
59
|
+
* copied), so a reducer that overflows to `Infinity` still raises the
|
|
60
|
+
* same `ValidationError` with the same message rather than silently
|
|
61
|
+
* landing a non-finite cell in a column flagged `allFinite`.
|
|
62
|
+
* - Numeric columns are stamped `allFinite: true` on the same
|
|
63
|
+
* justification the row path uses — every surviving cell was
|
|
64
|
+
* finite-checked above. Dropping that flag would be safe but would
|
|
65
|
+
* quietly deoptimise every downstream reduction of an aggregate
|
|
66
|
+
* result.
|
|
67
|
+
* - Missing cells (an empty bucket, or an all-missing one) set no
|
|
68
|
+
* validity bit, so they read back as `undefined` — **not** `NaN`. That
|
|
69
|
+
* is the sentinel decision this change forces, resolved in favour of
|
|
70
|
+
* preserving current behaviour exactly.
|
|
71
|
+
*
|
|
72
|
+
* The one row-intake check deliberately skipped is the non-decreasing
|
|
73
|
+
* key scan: `BoundedSequence` already validates its intervals as sorted,
|
|
74
|
+
* non-overlapping, and positive-duration at construction, so re-deriving
|
|
75
|
+
* it per bucket would be checking the same fact twice.
|
|
76
|
+
*
|
|
77
|
+
* Returns `null` for the same disqualifying mappings as before; the
|
|
78
|
+
* caller falls back to the unchanged row path.
|
|
79
|
+
*/
|
|
80
|
+
export declare function tryAggregateColumnarStore(begins: Float64Array, getColumn: (name: string) => Column | undefined, buckets: ReadonlyArray<Interval>, columns: ReadonlyArray<AggregateColumnSpec>, resultSchema: ColumnSchema): ColumnarStore | null;
|
|
42
81
|
/**
|
|
43
82
|
* **Columnar fast path for count-window `rolling()`** — the N-bar window
|
|
44
83
|
* financial studies compose on (SMA / Bollinger / rolling stats). When every
|
|
@@ -57,7 +96,7 @@ export declare function tryAggregateColumnarTimeKeyed<B extends {
|
|
|
57
96
|
* qualify: a custom-function reducer, a non-`'number'` output kind
|
|
58
97
|
* (`unique` / `samples` / `keep` over a non-number source / an explicit
|
|
59
98
|
* `kind` override), or a non-numeric / chunked / missing source column.
|
|
60
|
-
* All-or-nothing per call, matching {@link
|
|
99
|
+
* All-or-nothing per call, matching {@link tryAggregateColumnarStore}.
|
|
61
100
|
*
|
|
62
101
|
* Window shape replicates the generic count sweep exactly: rows are the unit
|
|
63
102
|
* (`count` is a bar count — no equal-key grouping), `lo` / `hi` are monotonic
|