@rocicorp/zero 1.11.0-canary.24 → 1.11.0-canary.26
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/out/shared/src/centroid.d.ts +0 -1
- package/out/shared/src/centroid.d.ts.map +1 -1
- package/out/shared/src/centroid.js +1 -4
- package/out/shared/src/centroid.js.map +1 -1
- package/out/shared/src/hash.d.ts.map +1 -1
- package/out/shared/src/hash.js +32 -7
- package/out/shared/src/hash.js.map +1 -1
- package/out/shared/src/tdigest.d.ts +10 -0
- package/out/shared/src/tdigest.d.ts.map +1 -1
- package/out/shared/src/tdigest.js +147 -63
- package/out/shared/src/tdigest.js.map +1 -1
- package/out/z2s/src/compiler.d.ts.map +1 -1
- package/out/z2s/src/compiler.js +9 -5
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +7 -3
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +18 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +66 -12
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration-lite.js +5 -3
- package/out/zero-cache/src/db/migration-lite.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +17 -12
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/server/replicator.js +18 -8
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +38 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.js +27 -10
- package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js +30 -14
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +19 -11
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +8 -4
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js +20 -8
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +2 -2
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +10 -9
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +26 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +47 -12
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/http-service.d.ts +1 -1
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts +28 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +94 -31
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config-v5.yml +1 -0
- package/out/zero-cache/src/services/litestream/wal-keeper.d.ts +33 -0
- package/out/zero-cache/src/services/litestream/wal-keeper.d.ts.map +1 -0
- package/out/zero-cache/src/services/litestream/wal-keeper.js +49 -0
- package/out/zero-cache/src/services/litestream/wal-keeper.js.map +1 -0
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +3 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +5 -2
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts +3 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js +5 -2
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +16 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.js +70 -27
- package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +16 -8
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +8 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +51 -9
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +25 -9
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +76 -38
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +20 -2
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +108 -40
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +1 -106
- package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.js +5 -20
- package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +10 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +18 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +17 -16
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/pg-data-type.d.ts +2 -0
- package/out/zero-cache/src/types/pg-data-type.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg-data-type.js +6 -1
- package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
- package/out/zero-cache/src/types/row-key.d.ts +1 -15
- package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
- package/out/zero-cache/src/types/row-key.js +1 -3
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +15 -7
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-client/src/client/context.d.ts +1 -1
- package/out/zero-client/src/client/context.d.ts.map +1 -1
- package/out/zero-client/src/client/context.js +2 -1
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts +5 -4
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +1 -1
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.js +1 -1
- package/out/zero-client/src/client/keys.d.ts.map +1 -1
- package/out/zero-client/src/client/keys.js +19 -1
- package/out/zero-client/src/client/keys.js.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.d.ts +1 -1
- package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.d.ts.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.d.ts +2 -2
- package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.js +2 -6
- package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +4 -2
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/query-manager.d.ts +9 -0
- package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/query-manager.js +3 -3
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.js +1 -1
- package/out/zero-client/src/mod.d.ts +1 -1
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-protocol/src/down.d.ts +27 -27
- package/out/zero-server/src/closable-db-transaction.d.ts +16 -0
- package/out/zero-server/src/closable-db-transaction.d.ts.map +1 -0
- package/out/zero-server/src/closable-db-transaction.js +31 -0
- package/out/zero-server/src/closable-db-transaction.js.map +1 -0
- package/out/zero-server/src/custom.d.ts +6 -4
- package/out/zero-server/src/custom.d.ts.map +1 -1
- package/out/zero-server/src/custom.js +9 -3
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.d.ts +1 -1
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +13 -1
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +90 -44
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +1 -0
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +28 -22
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zql/src/mutate/custom.d.ts +29 -0
- package/out/zql/src/mutate/custom.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.js.map +1 -1
- package/out/zql/src/mutate/mutator-registry.js +1 -1
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/mutate/mutator.d.ts +2 -2
- package/out/zql/src/mutate/mutator.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.d.ts +7 -1
- package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +22 -4
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zqlite/src/resolve-scalar-subqueries.d.ts +3 -1
- package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +1 -1
- package/out/zqlite/src/resolve-scalar-subqueries.js +1 -0
- package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"centroid.d.ts","sourceRoot":"","sources":["../../../../shared/src/centroid.ts"],"names":[],"mappings":"AAIA,qBAAa,QAAQ;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAGvC;IAED,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAWrB;CACF;AAED,qEAAqE;AACrE,MAAM,MAAM,YAAY,GAAG,QAAQ,EAAE,CAAC
|
|
1
|
+
{"version":3,"file":"centroid.d.ts","sourceRoot":"","sources":["../../../../shared/src/centroid.ts"],"names":[],"mappings":"AAIA,qBAAa,QAAQ;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAGvC;IAED,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAWrB;CACF;AAED,qEAAqE;AACrE,MAAM,MAAM,YAAY,GAAG,QAAQ,EAAE,CAAC"}
|
|
@@ -17,10 +17,7 @@ var Centroid = class {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
-
function sortCentroidList(centroids) {
|
|
21
|
-
centroids.sort((a, b) => a.mean - b.mean);
|
|
22
|
-
}
|
|
23
20
|
//#endregion
|
|
24
|
-
export { Centroid
|
|
21
|
+
export { Centroid };
|
|
25
22
|
|
|
26
23
|
//# sourceMappingURL=centroid.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"centroid.js","names":[],"sources":["../../../../shared/src/centroid.ts"],"sourcesContent":["// Apache License 2.0\n// https://github.com/influxdata/tdigest\n\n// Centroid average position of all points in a shape\nexport class Centroid {\n mean: number;\n weight: number;\n\n constructor(mean: number, weight: number) {\n this.mean = mean;\n this.weight = weight;\n }\n\n add(r: Centroid): void {\n if (r.weight < 0) {\n throw new Error('centroid weight cannot be less than zero');\n }\n if (this.weight !== 0) {\n this.weight += r.weight;\n this.mean += (r.weight * (r.mean - this.mean)) / this.weight;\n } else {\n this.weight = r.weight;\n this.mean = r.mean;\n }\n }\n}\n\n/** CentroidList is sorted by the mean of the centroid, ascending. */\nexport type CentroidList = Centroid[];\n
|
|
1
|
+
{"version":3,"file":"centroid.js","names":[],"sources":["../../../../shared/src/centroid.ts"],"sourcesContent":["// Apache License 2.0\n// https://github.com/influxdata/tdigest\n\n// Centroid average position of all points in a shape\nexport class Centroid {\n mean: number;\n weight: number;\n\n constructor(mean: number, weight: number) {\n this.mean = mean;\n this.weight = weight;\n }\n\n add(r: Centroid): void {\n if (r.weight < 0) {\n throw new Error('centroid weight cannot be less than zero');\n }\n if (this.weight !== 0) {\n this.weight += r.weight;\n this.mean += (r.weight * (r.mean - this.mean)) / this.weight;\n } else {\n this.weight = r.weight;\n this.mean = r.mean;\n }\n }\n}\n\n/** CentroidList is sorted by the mean of the centroid, ascending. */\nexport type CentroidList = Centroid[];\n"],"mappings":";AAIA,IAAa,WAAb,MAAsB;CACpB;CACA;CAEA,YAAY,MAAc,QAAgB;EACxC,KAAK,OAAO;EACZ,KAAK,SAAS;CAChB;CAEA,IAAI,GAAmB;EACrB,IAAI,EAAE,SAAS,GACb,MAAM,IAAI,MAAM,0CAA0C;EAE5D,IAAI,KAAK,WAAW,GAAG;GACrB,KAAK,UAAU,EAAE;GACjB,KAAK,QAAS,EAAE,UAAU,EAAE,OAAO,KAAK,QAAS,KAAK;EACxD,OAAO;GACL,KAAK,SAAS,EAAE;GAChB,KAAK,OAAO,EAAE;EAChB;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../../../shared/src/hash.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,GAAG,MAAO,MAAM,WAG5B,CAAC;AACF,eAAO,MAAM,GAAG,MAAO,MAAM,WAAe,CAAC;AAC7C,eAAO,MAAM,IAAI,MAAO,MAAM,WAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../../../shared/src/hash.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,GAAG,MAAO,MAAM,WAG5B,CAAC;AACF,eAAO,MAAM,GAAG,MAAO,MAAM,WAAe,CAAC;AAC7C,eAAO,MAAM,IAAI,MAAO,MAAM,WAAe,CAAC;AAgL9C,OAAO,EAAC,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAC,MAAM,eAAe,CAAC"}
|
package/out/shared/src/hash.js
CHANGED
|
@@ -12,6 +12,15 @@ var stripes = new Int32Array(MAX_WORDS * 4);
|
|
|
12
12
|
var digests = new Uint32Array(MAX_WORDS);
|
|
13
13
|
var encoder;
|
|
14
14
|
/**
|
|
15
|
+
* Inputs of up to this many UTF-16 code units are UTF-8 encoded into a reused
|
|
16
|
+
* buffer: `TextEncoder#encode` allocates a fresh Uint8Array per call, which for
|
|
17
|
+
* a row-key-sized string cost several times the hashing itself. Longer inputs
|
|
18
|
+
* still allocate: there the allocation is a small share of the cost, and not
|
|
19
|
+
* worth keeping a buffer that size alive.
|
|
20
|
+
*/
|
|
21
|
+
var MAX_REUSED_UNITS = 4096;
|
|
22
|
+
var utf8;
|
|
23
|
+
/**
|
|
15
24
|
* xxHash32 over the UTF-8 bytes of `str` under seeds `0..words-1`, leaving the
|
|
16
25
|
* digests in `digests[0..words)`.
|
|
17
26
|
*
|
|
@@ -22,8 +31,16 @@ var encoder;
|
|
|
22
31
|
* used to delegate to, and what `hash.test.ts` checks it still matches.
|
|
23
32
|
*/
|
|
24
33
|
function digest(str, words) {
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
encoder ??= new TextEncoder();
|
|
35
|
+
let b;
|
|
36
|
+
let len;
|
|
37
|
+
if (str.length <= MAX_REUSED_UNITS) {
|
|
38
|
+
b = utf8 ??= new Uint8Array(3 * MAX_REUSED_UNITS);
|
|
39
|
+
len = encoder.encodeInto(str, b).written;
|
|
40
|
+
} else {
|
|
41
|
+
b = encoder.encode(str);
|
|
42
|
+
len = b.length;
|
|
43
|
+
}
|
|
27
44
|
for (let w = 0; w < words; w++) accs[w] = w + PRIME32_5 & 4294967295;
|
|
28
45
|
let offset = 0;
|
|
29
46
|
if (len >= 16) {
|
|
@@ -79,15 +96,23 @@ function digest(str, words) {
|
|
|
79
96
|
}
|
|
80
97
|
for (let w = 0; w < words; w++) digests[w] = avalanche32(accs[w]);
|
|
81
98
|
}
|
|
99
|
+
var wideView = /* @__PURE__ */ new DataView(/* @__PURE__ */ new ArrayBuffer(16));
|
|
82
100
|
/**
|
|
83
|
-
* A hash wider than 32 bits, folding
|
|
84
|
-
*
|
|
101
|
+
* A hash wider than 32 bits, folding the digests together highest seed first.
|
|
102
|
+
*
|
|
103
|
+
* Every bigint operation allocates its result, so folding word by word with a
|
|
104
|
+
* `BigInt()`, a shift and an add per word allocated up to 6 bigints for h64 and
|
|
105
|
+
* 12 for h128. Laying the words out big-endian and reading them back with
|
|
106
|
+
* `getBigUint64` allocates 1 and 4 for the same values.
|
|
85
107
|
*/
|
|
86
108
|
function wide(str, words) {
|
|
87
109
|
digest(str, words);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return
|
|
110
|
+
wideView.setUint32(0, digests[0]);
|
|
111
|
+
wideView.setUint32(4, digests[1]);
|
|
112
|
+
if (words === 2) return wideView.getBigUint64(0);
|
|
113
|
+
wideView.setUint32(8, digests[2]);
|
|
114
|
+
wideView.setUint32(12, digests[3]);
|
|
115
|
+
return wideView.getBigUint64(0) << 64n | wideView.getBigUint64(8);
|
|
91
116
|
}
|
|
92
117
|
//#endregion
|
|
93
118
|
export { h128, h32, h64 };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.js","names":[],"sources":["../../../../shared/src/hash.ts"],"sourcesContent":["import {\n avalanche32,\n PRIME32_1,\n PRIME32_2,\n PRIME32_3,\n PRIME32_4,\n PRIME32_5,\n round32,\n} from './xxhash32.ts';\n\nexport const h32 = (s: string) => {\n digest(s, 1);\n return digests[0];\n};\nexport const h64 = (s: string) => wide(s, 2);\nexport const h128 = (s: string) => wide(s, 4);\n\nconst MAX_WORDS = 4;\n\n// `digest` is synchronous and does not recurse, so these can be reused across\n// calls instead of allocated per call.\nconst accs = new Int32Array(MAX_WORDS);\nconst stripes = new Int32Array(MAX_WORDS * 4);\nconst digests = new Uint32Array(MAX_WORDS);\nlet encoder: TextEncoder | undefined;\n\n/**\n * xxHash32 over the UTF-8 bytes of `str` under seeds `0..words-1`, leaving the\n * digests in `digests[0..words)`.\n *\n * A seed only changes the initial accumulator values, so every word digests the\n * same input lanes. This walks the bytes once, advancing all `words` sets of\n * accumulators per lane, and UTF-8 encodes the string once. The result is\n * identical to `words` separate `xxHash32(str, i)` calls — which is what this\n * used to delegate to, and what `hash.test.ts` checks it still matches.\n */\nfunction digest(str: string, words: number): void {\n
|
|
1
|
+
{"version":3,"file":"hash.js","names":[],"sources":["../../../../shared/src/hash.ts"],"sourcesContent":["import {\n avalanche32,\n PRIME32_1,\n PRIME32_2,\n PRIME32_3,\n PRIME32_4,\n PRIME32_5,\n round32,\n} from './xxhash32.ts';\n\nexport const h32 = (s: string) => {\n digest(s, 1);\n return digests[0];\n};\nexport const h64 = (s: string) => wide(s, 2);\nexport const h128 = (s: string) => wide(s, 4);\n\nconst MAX_WORDS = 4;\n\n// `digest` is synchronous and does not recurse, so these can be reused across\n// calls instead of allocated per call.\nconst accs = new Int32Array(MAX_WORDS);\nconst stripes = new Int32Array(MAX_WORDS * 4);\nconst digests = new Uint32Array(MAX_WORDS);\nlet encoder: TextEncoder | undefined;\n\n/**\n * Inputs of up to this many UTF-16 code units are UTF-8 encoded into a reused\n * buffer: `TextEncoder#encode` allocates a fresh Uint8Array per call, which for\n * a row-key-sized string cost several times the hashing itself. Longer inputs\n * still allocate: there the allocation is a small share of the cost, and not\n * worth keeping a buffer that size alive.\n */\nconst MAX_REUSED_UNITS = 4096;\nlet utf8: Uint8Array | undefined;\n\n/**\n * xxHash32 over the UTF-8 bytes of `str` under seeds `0..words-1`, leaving the\n * digests in `digests[0..words)`.\n *\n * A seed only changes the initial accumulator values, so every word digests the\n * same input lanes. This walks the bytes once, advancing all `words` sets of\n * accumulators per lane, and UTF-8 encodes the string once. The result is\n * identical to `words` separate `xxHash32(str, i)` calls — which is what this\n * used to delegate to, and what `hash.test.ts` checks it still matches.\n */\nfunction digest(str: string, words: number): void {\n encoder ??= new TextEncoder();\n let b: Uint8Array;\n let len: number;\n if (str.length <= MAX_REUSED_UNITS) {\n // A UTF-16 code unit is at most 3 UTF-8 bytes (a surrogate pair is 2 units\n // and 4 bytes), so the whole string always fits. Bytes past `len` are left\n // over from earlier calls and never read.\n b = utf8 ??= new Uint8Array(3 * MAX_REUSED_UNITS);\n len = encoder.encodeInto(str, b).written;\n } else {\n b = encoder.encode(str);\n len = b.length;\n }\n\n for (let w = 0; w < words; w++) {\n accs[w] = (w + PRIME32_5) & 0xffffffff;\n }\n\n let offset = 0;\n\n /*\n Step 2. Process stripes\n A stripe is a contiguous segment of 16 bytes, evenly divided into 4 lanes\n of 4 bytes each, each lane updating its own accumulator. Inputs shorter\n than a stripe skip straight to step 4 with a single accumulator.\n */\n if (len >= 16) {\n for (let w = 0; w < words; w++) {\n const base = w << 2;\n stripes[base] = (w + PRIME32_1 + PRIME32_2) & 0xffffffff;\n stripes[base + 1] = (w + PRIME32_2) & 0xffffffff;\n stripes[base + 2] = w;\n stripes[base + 3] = (w - PRIME32_1) & 0xffffffff;\n }\n\n const limit = len - 16;\n for (; offset <= limit; offset += 16) {\n const l0 =\n b[offset] |\n (b[offset + 1] << 8) |\n (b[offset + 2] << 16) |\n (b[offset + 3] << 24);\n const l1 =\n b[offset + 4] |\n (b[offset + 5] << 8) |\n (b[offset + 6] << 16) |\n (b[offset + 7] << 24);\n const l2 =\n b[offset + 8] |\n (b[offset + 9] << 8) |\n (b[offset + 10] << 16) |\n (b[offset + 11] << 24);\n const l3 =\n b[offset + 12] |\n (b[offset + 13] << 8) |\n (b[offset + 14] << 16) |\n (b[offset + 15] << 24);\n for (let w = 0; w < words; w++) {\n const base = w << 2;\n stripes[base] = round32(stripes[base], l0);\n stripes[base + 1] = round32(stripes[base + 1], l1);\n stripes[base + 2] = round32(stripes[base + 2], l2);\n stripes[base + 3] = round32(stripes[base + 3], l3);\n }\n }\n\n /*\n Step 3. Accumulator convergence\n acc = (acc1 <<< 1) + (acc2 <<< 7) + (acc3 <<< 12) + (acc4 <<< 18);\n */\n for (let w = 0; w < words; w++) {\n const base = w << 2;\n const s0 = stripes[base];\n const s1 = stripes[base + 1];\n const s2 = stripes[base + 2];\n const s3 = stripes[base + 3];\n accs[w] =\n (((s0 << 1) | (s0 >>> 31)) +\n ((s1 << 7) | (s1 >>> 25)) +\n ((s2 << 12) | (s2 >>> 20)) +\n ((s3 << 18) | (s3 >>> 14))) &\n 0xffffffff;\n }\n }\n\n // Step 4. Add input length.\n for (let w = 0; w < words; w++) {\n accs[w] = (accs[w] + len) & 0xffffffff;\n }\n\n // Step 5. Consume the remaining input, 4 bytes at a time and then 1 at a time.\n const limit4 = len - 4;\n for (; offset <= limit4; offset += 4) {\n const laneN0 = b[offset] + (b[offset + 1] << 8);\n const laneN1 = b[offset + 2] + (b[offset + 3] << 8);\n const laneP = laneN0 * PRIME32_3 + ((laneN1 * PRIME32_3) << 16);\n for (let w = 0; w < words; w++) {\n let acc = (accs[w] + laneP) | 0;\n acc = (acc << 17) | (acc >>> 15);\n accs[w] = Math.imul(acc, PRIME32_4);\n }\n }\n\n for (; offset < len; ++offset) {\n const lane = b[offset];\n for (let w = 0; w < words; w++) {\n let acc = (accs[w] + Math.imul(lane, PRIME32_5)) | 0;\n acc = (acc << 11) | (acc >>> 21);\n accs[w] = Math.imul(acc, PRIME32_1);\n }\n }\n\n // Step 6. Final mix (avalanche). The Uint32Array store turns any negatives\n // back into a positive number.\n for (let w = 0; w < words; w++) {\n digests[w] = avalanche32(accs[w]);\n }\n}\n\nconst wideView = new DataView(new ArrayBuffer(16));\n\n/**\n * A hash wider than 32 bits, folding the digests together highest seed first.\n *\n * Every bigint operation allocates its result, so folding word by word with a\n * `BigInt()`, a shift and an add per word allocated up to 6 bigints for h64 and\n * 12 for h128. Laying the words out big-endian and reading them back with\n * `getBigUint64` allocates 1 and 4 for the same values.\n */\nfunction wide(str: string, words: 2 | 4): bigint {\n digest(str, words);\n wideView.setUint32(0, digests[0]);\n wideView.setUint32(4, digests[1]);\n if (words === 2) {\n return wideView.getBigUint64(0);\n }\n wideView.setUint32(8, digests[2]);\n wideView.setUint32(12, digests[3]);\n return (wideView.getBigUint64(0) << 64n) | wideView.getBigUint64(8);\n}\n\n// Re-exported for zero-protocol's AST hash, which cannot import xxhash32.ts\n// directly without tripping a tsc 7.0.2 bug (see the import comment in\n// zero-protocol/src/query-hash-visitor.ts).\nexport {avalanche32, PRIME32_1, PRIME32_5, round32} from './xxhash32.ts';\n"],"mappings":"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"}
|
|
@@ -8,6 +8,12 @@ export interface ReadonlyTDigest {
|
|
|
8
8
|
export declare class TDigest {
|
|
9
9
|
#private;
|
|
10
10
|
readonly compression: number;
|
|
11
|
+
/**
|
|
12
|
+
* A digest keeps roughly `compression` centroids, and buffers up to eight
|
|
13
|
+
* times as many values between merges. The Go original defaults to 1000;
|
|
14
|
+
* 100 keeps p50, p95 and p99 within about 0.5% for a tenth of the memory
|
|
15
|
+
* and serialized size, which is plenty for the inspector's percentiles.
|
|
16
|
+
*/
|
|
11
17
|
constructor(compression?: number);
|
|
12
18
|
/**
|
|
13
19
|
* fromJSON creates a TDigest from a JSON-serializable representation.
|
|
@@ -15,6 +21,10 @@ export declare class TDigest {
|
|
|
15
21
|
*/
|
|
16
22
|
static fromJSON(data: Readonly<TDigestJSON>): TDigest;
|
|
17
23
|
reset(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Adds a value with the given weight.
|
|
26
|
+
* Weights which are not a number or are <= 0 are ignored, as are NaN means.
|
|
27
|
+
*/
|
|
18
28
|
add(mean: number, weight?: number): void;
|
|
19
29
|
/** AddCentroidList can quickly add multiple centroids. */
|
|
20
30
|
addCentroidList(centroidList: CentroidList): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tdigest.d.ts","sourceRoot":"","sources":["../../../../shared/src/tdigest.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,QAAQ,
|
|
1
|
+
{"version":3,"file":"tdigest.d.ts","sourceRoot":"","sources":["../../../../shared/src/tdigest.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,QAAQ,EAAE,KAAK,YAAY,EAAC,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,qBAAqB,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC;AAcD,qBAAa,OAAO;;IAClB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAqB7B;;;;;OAKG;IACH,YAAY,WAAW,GAAE,MAAY,EAOpC;IAED;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,OAAO,CASpD;IAED,KAAK,IAAI,IAAI,CASZ;IAED;;;OAGG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU,GAAG,IAAI,CAiB1C;IAED,0DAA0D;IAC1D,eAAe,CAAC,YAAY,EAAE,YAAY,QAIzC;IAED;;;OAGG;IACH,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI,CAE7B;IAED;;;;QAII;IACJ,KAAK,CAAC,EAAE,EAAE,OAAO,QAShB;IAiHD;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,GAAE,YAAiB,GAAG,YAAY,CAO7C;IAED,KAAK,IAAI,MAAM,CAMd;IAED;;;OAGG;IACH,MAAM,IAAI,WAAW,CAOpB;IA6BD,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAqC1B;IAED;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CA2ErB;CAgBF;AAID,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB3D"}
|
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
import { binarySearch } from "./binary-search.js";
|
|
2
|
-
import { Centroid
|
|
2
|
+
import { Centroid } from "./centroid.js";
|
|
3
3
|
//#region ../shared/src/tdigest.ts
|
|
4
|
+
/** Initial capacity of the buffer of unprocessed values. */
|
|
5
|
+
var INITIAL_CAPACITY = 16;
|
|
4
6
|
var TDigest = class TDigest {
|
|
5
7
|
compression;
|
|
6
|
-
#maxProcessed;
|
|
7
8
|
#maxUnprocessed;
|
|
8
|
-
|
|
9
|
-
#
|
|
9
|
+
/** Means of the processed centroids, ascending. */
|
|
10
|
+
#means;
|
|
11
|
+
/** Weights of the processed centroids, parallel to `#means`. */
|
|
12
|
+
#weights;
|
|
13
|
+
/** Means of the values added since the last `#process`, in order. */
|
|
14
|
+
#unprocessedMeans;
|
|
15
|
+
/** Weights of the unprocessed values, parallel to `#unprocessedMeans`. */
|
|
16
|
+
#unprocessedWeights;
|
|
17
|
+
#unprocessedCount;
|
|
10
18
|
#cumulative;
|
|
11
19
|
#processedWeight;
|
|
12
20
|
#unprocessedWeight;
|
|
13
21
|
#min;
|
|
14
22
|
#max;
|
|
15
|
-
|
|
23
|
+
/**
|
|
24
|
+
* A digest keeps roughly `compression` centroids, and buffers up to eight
|
|
25
|
+
* times as many values between merges. The Go original defaults to 1000;
|
|
26
|
+
* 100 keeps p50, p95 and p99 within about 0.5% for a tenth of the memory
|
|
27
|
+
* and serialized size, which is plenty for the inspector's percentiles.
|
|
28
|
+
*/
|
|
29
|
+
constructor(compression = 100) {
|
|
16
30
|
this.compression = compression;
|
|
17
|
-
this.#maxProcessed = processedSize(0, this.compression);
|
|
18
31
|
this.#maxUnprocessed = unprocessedSize(0, this.compression);
|
|
32
|
+
const capacity = Math.min(INITIAL_CAPACITY, this.#maxUnprocessed + 1);
|
|
33
|
+
this.#unprocessedMeans = new Float64Array(capacity);
|
|
34
|
+
this.#unprocessedWeights = new Float64Array(capacity);
|
|
19
35
|
this.reset();
|
|
20
36
|
}
|
|
21
37
|
/**
|
|
@@ -29,30 +45,39 @@ var TDigest = class TDigest {
|
|
|
29
45
|
return digest;
|
|
30
46
|
}
|
|
31
47
|
reset() {
|
|
32
|
-
this.#
|
|
33
|
-
this.#
|
|
48
|
+
this.#means = [];
|
|
49
|
+
this.#weights = [];
|
|
50
|
+
this.#unprocessedCount = 0;
|
|
34
51
|
this.#cumulative = [];
|
|
35
52
|
this.#processedWeight = 0;
|
|
36
53
|
this.#unprocessedWeight = 0;
|
|
37
54
|
this.#min = Number.MAX_VALUE;
|
|
38
55
|
this.#max = -Number.MAX_VALUE;
|
|
39
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Adds a value with the given weight.
|
|
59
|
+
* Weights which are not a number or are <= 0 are ignored, as are NaN means.
|
|
60
|
+
*/
|
|
40
61
|
add(mean, weight = 1) {
|
|
41
|
-
|
|
62
|
+
if (Number.isNaN(mean) || weight <= 0 || !Number.isFinite(weight)) return;
|
|
63
|
+
const n = this.#unprocessedCount;
|
|
64
|
+
if (n === this.#unprocessedMeans.length) this.#grow();
|
|
65
|
+
this.#unprocessedMeans[n] = mean;
|
|
66
|
+
this.#unprocessedWeights[n] = weight;
|
|
67
|
+
this.#unprocessedCount = n + 1;
|
|
68
|
+
this.#unprocessedWeight += weight;
|
|
69
|
+
if (this.#unprocessedCount > this.#maxUnprocessed) this.#process();
|
|
42
70
|
}
|
|
43
71
|
/** AddCentroidList can quickly add multiple centroids. */
|
|
44
72
|
addCentroidList(centroidList) {
|
|
45
|
-
for (const c of centroidList) this.
|
|
73
|
+
for (const c of centroidList) this.add(c.mean, c.weight);
|
|
46
74
|
}
|
|
47
75
|
/**
|
|
48
76
|
* AddCentroid adds a single centroid.
|
|
49
77
|
* Weights which are not a number or are <= 0 are ignored, as are NaN means.
|
|
50
78
|
*/
|
|
51
79
|
addCentroid(c) {
|
|
52
|
-
|
|
53
|
-
this.#unprocessed.push(new Centroid(c.mean, c.weight));
|
|
54
|
-
this.#unprocessedWeight += c.weight;
|
|
55
|
-
if (this.#processed.length > this.#maxProcessed || this.#unprocessed.length > this.#maxUnprocessed) this.#process();
|
|
80
|
+
this.add(c.mean, c.weight);
|
|
56
81
|
}
|
|
57
82
|
/**
|
|
58
83
|
* Merges the supplied digest into this digest. Functionally equivalent to
|
|
@@ -61,35 +86,88 @@ var TDigest = class TDigest {
|
|
|
61
86
|
**/
|
|
62
87
|
merge(t2) {
|
|
63
88
|
t2.#process();
|
|
64
|
-
|
|
89
|
+
const means = t2.#means;
|
|
90
|
+
const weights = t2.#weights;
|
|
91
|
+
for (let i = 0; i < means.length; i++) this.add(means[i], weights[i]);
|
|
92
|
+
}
|
|
93
|
+
/** Doubles the unprocessed buffer, up to what `add` lets it hold. */
|
|
94
|
+
#grow() {
|
|
95
|
+
const capacity = Math.min(this.#unprocessedMeans.length * 2, this.#maxUnprocessed + 1);
|
|
96
|
+
const means = new Float64Array(capacity);
|
|
97
|
+
means.set(this.#unprocessedMeans);
|
|
98
|
+
this.#unprocessedMeans = means;
|
|
99
|
+
const weights = new Float64Array(capacity);
|
|
100
|
+
weights.set(this.#unprocessedWeights);
|
|
101
|
+
this.#unprocessedWeights = weights;
|
|
65
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Merges the unprocessed values into the centroids: walks both in order of
|
|
105
|
+
* mean, folding each into the last centroid while that stays within its
|
|
106
|
+
* size limit, and starting a new centroid otherwise.
|
|
107
|
+
*/
|
|
66
108
|
#process() {
|
|
67
|
-
if (this.#
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
if (this.#unprocessedCount === 0) return;
|
|
110
|
+
const [newMeans, newWeights] = this.#sortedUnprocessed();
|
|
111
|
+
const oldMeans = this.#means;
|
|
112
|
+
const oldWeights = this.#weights;
|
|
113
|
+
const n = newMeans.length;
|
|
114
|
+
const p = oldMeans.length;
|
|
115
|
+
this.#unprocessedCount = 0;
|
|
116
|
+
this.#processedWeight += this.#unprocessedWeight;
|
|
117
|
+
this.#unprocessedWeight = 0;
|
|
118
|
+
const total = this.#processedWeight;
|
|
119
|
+
const means = [];
|
|
120
|
+
const weights = [];
|
|
121
|
+
let mean = 0;
|
|
122
|
+
let weight = 0;
|
|
123
|
+
let soFar = 0;
|
|
124
|
+
let limit = 0;
|
|
125
|
+
let i = 0;
|
|
126
|
+
let j = 0;
|
|
127
|
+
while (i < n || j < p) {
|
|
128
|
+
let m;
|
|
129
|
+
let w;
|
|
130
|
+
if (i < n && (j === p || newMeans[i] <= oldMeans[j])) {
|
|
131
|
+
m = newMeans[i];
|
|
132
|
+
w = newWeights[i++];
|
|
133
|
+
} else {
|
|
134
|
+
m = oldMeans[j];
|
|
135
|
+
w = oldWeights[j++];
|
|
136
|
+
}
|
|
137
|
+
if (soFar + w <= limit) {
|
|
138
|
+
weight += w;
|
|
139
|
+
mean += w * (m - mean) / weight;
|
|
140
|
+
} else {
|
|
141
|
+
if (weight > 0) {
|
|
142
|
+
means.push(mean);
|
|
143
|
+
weights.push(weight);
|
|
87
144
|
}
|
|
145
|
+
const k = this.#integratedLocation(soFar / total);
|
|
146
|
+
limit = total * this.#integratedQ(k + 1);
|
|
147
|
+
mean = m;
|
|
148
|
+
weight = w;
|
|
88
149
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
150
|
+
soFar += w;
|
|
151
|
+
}
|
|
152
|
+
means.push(mean);
|
|
153
|
+
weights.push(weight);
|
|
154
|
+
this.#means = means;
|
|
155
|
+
this.#weights = weights;
|
|
156
|
+
this.#min = Math.min(this.#min, means[0]);
|
|
157
|
+
this.#max = Math.max(this.#max, means.at(-1));
|
|
158
|
+
}
|
|
159
|
+
/** The unprocessed means and weights, sorted by mean. */
|
|
160
|
+
#sortedUnprocessed() {
|
|
161
|
+
const n = this.#unprocessedCount;
|
|
162
|
+
const means = this.#unprocessedMeans.subarray(0, n);
|
|
163
|
+
const weights = this.#unprocessedWeights.subarray(0, n);
|
|
164
|
+
if (isSorted(means)) return [means, weights];
|
|
165
|
+
if (allEqual(weights)) {
|
|
166
|
+
means.sort();
|
|
167
|
+
return [means, weights];
|
|
92
168
|
}
|
|
169
|
+
const order = Array.from(means, (_, k) => k).sort((a, b) => means[a] - means[b]);
|
|
170
|
+
return [Float64Array.from(order, (k) => means[k]), Float64Array.from(order, (k) => weights[k])];
|
|
93
171
|
}
|
|
94
172
|
/**
|
|
95
173
|
* Centroids returns a copy of processed centroids.
|
|
@@ -100,7 +178,9 @@ var TDigest = class TDigest {
|
|
|
100
178
|
*/
|
|
101
179
|
centroids(cl = []) {
|
|
102
180
|
this.#process();
|
|
103
|
-
|
|
181
|
+
const result = [...cl];
|
|
182
|
+
for (let i = 0; i < this.#means.length; i++) result.push(new Centroid(this.#means[i], this.#weights[i]));
|
|
183
|
+
return result;
|
|
104
184
|
}
|
|
105
185
|
count() {
|
|
106
186
|
this.#process();
|
|
@@ -113,37 +193,37 @@ var TDigest = class TDigest {
|
|
|
113
193
|
toJSON() {
|
|
114
194
|
this.#process();
|
|
115
195
|
const data = [this.compression];
|
|
116
|
-
for (
|
|
196
|
+
for (let i = 0; i < this.#means.length; i++) data.push(this.#means[i], this.#weights[i]);
|
|
117
197
|
return data;
|
|
118
198
|
}
|
|
119
199
|
#updateCumulative() {
|
|
120
200
|
if (this.#cumulative.length > 0 && this.#cumulative.at(-1) === this.#processedWeight) return;
|
|
121
|
-
const n = this.#
|
|
201
|
+
const n = this.#means.length + 1;
|
|
122
202
|
if (this.#cumulative.length > n) this.#cumulative.length = n;
|
|
123
203
|
let prev = 0;
|
|
124
|
-
for (let i = 0; i < this.#
|
|
125
|
-
const cur = this.#
|
|
204
|
+
for (let i = 0; i < this.#means.length; i++) {
|
|
205
|
+
const cur = this.#weights[i];
|
|
126
206
|
this.#cumulative[i] = prev + cur / 2;
|
|
127
207
|
prev += cur;
|
|
128
208
|
}
|
|
129
|
-
this.#cumulative[this.#
|
|
209
|
+
this.#cumulative[this.#means.length] = prev;
|
|
130
210
|
}
|
|
131
211
|
quantile(q) {
|
|
132
212
|
this.#process();
|
|
133
213
|
this.#updateCumulative();
|
|
134
|
-
if (q < 0 || q > 1 || this.#
|
|
135
|
-
if (this.#
|
|
214
|
+
if (q < 0 || q > 1 || this.#means.length === 0) return NaN;
|
|
215
|
+
if (this.#means.length === 1) return this.#means[0];
|
|
136
216
|
const index = q * this.#processedWeight;
|
|
137
|
-
if (index <= this.#
|
|
217
|
+
if (index <= this.#weights[0] / 2) return this.#min + 2 * index / this.#weights[0] * (this.#means[0] - this.#min);
|
|
138
218
|
const lower = binarySearch(this.#cumulative.length, (i) => -this.#cumulative[i] + index);
|
|
139
219
|
if (lower + 1 !== this.#cumulative.length) {
|
|
140
220
|
const z1 = index - this.#cumulative[lower - 1];
|
|
141
221
|
const z2 = this.#cumulative[lower] - index;
|
|
142
|
-
return weightedAverage(this.#
|
|
222
|
+
return weightedAverage(this.#means[lower - 1], z2, this.#means[lower], z1);
|
|
143
223
|
}
|
|
144
|
-
const z1 = index - this.#processedWeight - this.#
|
|
145
|
-
const z2 = this.#
|
|
146
|
-
return weightedAverage(this.#
|
|
224
|
+
const z1 = index - this.#processedWeight - this.#weights[lower - 1] / 2;
|
|
225
|
+
const z2 = this.#weights[lower - 1] / 2 - z1;
|
|
226
|
+
return weightedAverage(this.#means.at(-1), z1, this.#max, z2);
|
|
147
227
|
}
|
|
148
228
|
/**
|
|
149
229
|
* CDF returns the cumulative distribution function for a given value x.
|
|
@@ -151,7 +231,7 @@ var TDigest = class TDigest {
|
|
|
151
231
|
cdf(x) {
|
|
152
232
|
this.#process();
|
|
153
233
|
this.#updateCumulative();
|
|
154
|
-
switch (this.#
|
|
234
|
+
switch (this.#means.length) {
|
|
155
235
|
case 0: return 0;
|
|
156
236
|
case 1: {
|
|
157
237
|
const width = this.#max - this.#min;
|
|
@@ -163,19 +243,19 @@ var TDigest = class TDigest {
|
|
|
163
243
|
}
|
|
164
244
|
if (x <= this.#min) return 0;
|
|
165
245
|
if (x >= this.#max) return 1;
|
|
166
|
-
const m0 = this.#
|
|
246
|
+
const m0 = this.#means[0];
|
|
167
247
|
if (x <= m0) {
|
|
168
|
-
if (m0 - this.#min > 0) return (x - this.#min) / (m0 - this.#min) * this.#
|
|
248
|
+
if (m0 - this.#min > 0) return (x - this.#min) / (m0 - this.#min) * this.#weights[0] / this.#processedWeight / 2;
|
|
169
249
|
return 0;
|
|
170
250
|
}
|
|
171
|
-
const mn = this.#
|
|
251
|
+
const mn = this.#means.at(-1);
|
|
172
252
|
if (x >= mn) {
|
|
173
|
-
if (this.#max - mn > 0) return 1 - (this.#max - x) / (this.#max - mn) * this.#
|
|
253
|
+
if (this.#max - mn > 0) return 1 - (this.#max - x) / (this.#max - mn) * this.#weights.at(-1) / this.#processedWeight / 2;
|
|
174
254
|
return 1;
|
|
175
255
|
}
|
|
176
|
-
const upper = binarySearch(this.#
|
|
177
|
-
const z1 = x - this.#
|
|
178
|
-
const z2 = this.#
|
|
256
|
+
const upper = binarySearch(this.#means.length, (i) => x - this.#means[i] || 1);
|
|
257
|
+
const z1 = x - this.#means[upper - 1];
|
|
258
|
+
const z2 = this.#means[upper] - x;
|
|
179
259
|
return weightedAverage(this.#cumulative[upper - 1], z2, this.#cumulative[upper], z1) / this.#processedWeight;
|
|
180
260
|
}
|
|
181
261
|
#integratedQ(k) {
|
|
@@ -185,6 +265,14 @@ var TDigest = class TDigest {
|
|
|
185
265
|
return this.compression * (Math.asin(2 * q - 1) + Math.PI / 2) / Math.PI;
|
|
186
266
|
}
|
|
187
267
|
};
|
|
268
|
+
function isSorted(values) {
|
|
269
|
+
for (let i = 1; i < values.length; i++) if (values[i] < values[i - 1]) return false;
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
function allEqual(values) {
|
|
273
|
+
for (let i = 1; i < values.length; i++) if (values[i] !== values[0]) return false;
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
188
276
|
function weightedAverage(x1, w1, x2, w2) {
|
|
189
277
|
if (x1 <= x2) return weightedAverageSorted(x1, w1, x2, w2);
|
|
190
278
|
return weightedAverageSorted(x2, w2, x1, w1);
|
|
@@ -193,10 +281,6 @@ function weightedAverageSorted(x1, w1, x2, w2) {
|
|
|
193
281
|
const x = (x1 * w1 + x2 * w2) / (w1 + w2);
|
|
194
282
|
return Math.max(x1, Math.min(x, x2));
|
|
195
283
|
}
|
|
196
|
-
function processedSize(size, compression) {
|
|
197
|
-
if (size === 0) return Math.ceil(compression) * 2;
|
|
198
|
-
return size;
|
|
199
|
-
}
|
|
200
284
|
function unprocessedSize(size, compression) {
|
|
201
285
|
if (size === 0) return Math.ceil(compression) * 8;
|
|
202
286
|
return size;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tdigest.js","names":["#maxProcessed","#maxUnprocessed","#processed","#unprocessed","#cumulative","#processedWeight","#unprocessedWeight","#min","#max","#process","#integratedQ","#integratedLocation","#updateCumulative"],"sources":["../../../../shared/src/tdigest.ts"],"sourcesContent":["// Apache License 2.0\n// https://github.com/influxdata/tdigest\n\nimport {binarySearch} from './binary-search.ts';\nimport {Centroid, sortCentroidList, type CentroidList} from './centroid.ts';\nimport type {TDigestJSON} from './tdigest-schema.ts';\n\nexport interface ReadonlyTDigest {\n readonly count: () => number;\n readonly quantile: (q: number) => number;\n readonly cdf: (x: number) => number;\n}\n\n// TDigest is a data structure for accurate on-line accumulation of\n// rank-based statistics such as quantiles and trimmed means.\nexport class TDigest {\n readonly compression: number;\n\n #maxProcessed: number;\n #maxUnprocessed: number;\n #processed!: CentroidList;\n #unprocessed!: CentroidList;\n #cumulative!: number[];\n #processedWeight!: number;\n #unprocessedWeight!: number;\n #min!: number;\n #max!: number;\n\n constructor(compression: number = 1000) {\n this.compression = compression;\n this.#maxProcessed = processedSize(0, this.compression);\n this.#maxUnprocessed = unprocessedSize(0, this.compression);\n this.reset();\n }\n\n /**\n * fromJSON creates a TDigest from a JSON-serializable representation.\n * The data should be an object with compression and centroids array.\n */\n static fromJSON(data: Readonly<TDigestJSON>): TDigest {\n const digest = new TDigest(data[0]);\n if (data.length % 2 !== 1) {\n throw new Error('Invalid centroids array');\n }\n for (let i = 1; i < data.length; i += 2) {\n digest.add(data[i], data[i + 1]);\n }\n return digest;\n }\n\n reset(): void {\n this.#processed = [];\n this.#unprocessed = [];\n this.#cumulative = [];\n this.#processedWeight = 0;\n this.#unprocessedWeight = 0;\n this.#min = Number.MAX_VALUE;\n this.#max = -Number.MAX_VALUE;\n }\n\n add(mean: number, weight: number = 1) {\n this.addCentroid(new Centroid(mean, weight));\n }\n\n /** AddCentroidList can quickly add multiple centroids. */\n addCentroidList(centroidList: CentroidList) {\n for (const c of centroidList) {\n this.addCentroid(c);\n }\n }\n\n /**\n * AddCentroid adds a single centroid.\n * Weights which are not a number or are <= 0 are ignored, as are NaN means.\n */\n addCentroid(c: Centroid): void {\n if (\n Number.isNaN(c.mean) ||\n c.weight <= 0 ||\n Number.isNaN(c.weight) ||\n !Number.isFinite(c.weight)\n ) {\n return;\n }\n\n this.#unprocessed.push(new Centroid(c.mean, c.weight));\n this.#unprocessedWeight += c.weight;\n\n if (\n this.#processed.length > this.#maxProcessed ||\n this.#unprocessed.length > this.#maxUnprocessed\n ) {\n this.#process();\n }\n }\n\n /**\n * Merges the supplied digest into this digest. Functionally equivalent to\n * calling t.AddCentroidList(t2.Centroids(nil)), but avoids making an extra\n * copy of the CentroidList.\n **/\n merge(t2: TDigest) {\n t2.#process();\n this.addCentroidList(t2.#processed);\n }\n\n #process() {\n if (\n this.#unprocessed.length > 0 ||\n this.#processed.length > this.#maxProcessed\n ) {\n // Append all processed centroids to the unprocessed list and sort\n this.#unprocessed.push(...this.#processed);\n sortCentroidList(this.#unprocessed);\n\n // Reset processed list with first centroid\n this.#processed.length = 0;\n this.#processed.push(this.#unprocessed[0]);\n\n this.#processedWeight += this.#unprocessedWeight;\n this.#unprocessedWeight = 0;\n let soFar = this.#unprocessed[0].weight;\n let limit = this.#processedWeight * this.#integratedQ(1);\n for (let i = 1; i < this.#unprocessed.length; i++) {\n const centroid = this.#unprocessed[i];\n const projected = soFar + centroid.weight;\n if (projected <= limit) {\n soFar = projected;\n // oxlint-disable-next-line typescript/no-non-null-assertion\n this.#processed.at(-1)!.add(centroid);\n } else {\n const k1 = this.#integratedLocation(soFar / this.#processedWeight);\n limit = this.#processedWeight * this.#integratedQ(k1 + 1);\n soFar += centroid.weight;\n this.#processed.push(centroid);\n }\n }\n this.#min = Math.min(this.#min, this.#processed[0].mean);\n // oxlint-disable-next-line typescript/no-non-null-assertion\n this.#max = Math.max(this.#max, this.#processed.at(-1)!.mean);\n this.#unprocessed.length = 0;\n }\n }\n\n /**\n * Centroids returns a copy of processed centroids.\n * Useful when aggregating multiple t-digests.\n *\n * Centroids are appended to the passed CentroidList; if you're re-using a\n * buffer, be sure to pass cl[:0].\n */\n centroids(cl: CentroidList = []): CentroidList {\n this.#process();\n return [...cl, ...this.#processed];\n }\n\n count(): number {\n this.#process();\n\n // this.process always updates this.processedWeight to the total count of all\n // centroids, so we don't need to re-count here.\n return this.#processedWeight;\n }\n\n /**\n * toJSON returns a JSON-serializable representation of the digest.\n * This processes the digest and returns an object with compression and centroid data.\n */\n toJSON(): TDigestJSON {\n this.#process();\n const data: TDigestJSON = [this.compression];\n for (const centroid of this.#processed) {\n data.push(centroid.mean, centroid.weight);\n }\n return data;\n }\n\n #updateCumulative() {\n // Weight can only increase, so the final cumulative value will always be\n // either equal to, or less than, the total weight. If they are the same,\n // then nothing has changed since the last update.\n if (\n this.#cumulative.length > 0 &&\n this.#cumulative.at(-1) === this.#processedWeight\n ) {\n return;\n }\n const n = this.#processed.length + 1;\n if (this.#cumulative.length > n) {\n this.#cumulative.length = n;\n }\n\n let prev = 0;\n for (let i = 0; i < this.#processed.length; i++) {\n const centroid = this.#processed[i];\n const cur = centroid.weight;\n this.#cumulative[i] = prev + cur / 2;\n prev += cur;\n }\n this.#cumulative[this.#processed.length] = prev;\n }\n\n // Quantile returns the (approximate) quantile of\n // the distribution. Accepted values for q are between 0 and 1.\n // Returns NaN if Count is zero or bad inputs.\n quantile(q: number): number {\n this.#process();\n this.#updateCumulative();\n if (q < 0 || q > 1 || this.#processed.length === 0) {\n return NaN;\n }\n if (this.#processed.length === 1) {\n return this.#processed[0].mean;\n }\n const index = q * this.#processedWeight;\n if (index <= this.#processed[0].weight / 2) {\n return (\n this.#min +\n ((2 * index) / this.#processed[0].weight) *\n (this.#processed[0].mean - this.#min)\n );\n }\n\n const lower = binarySearch(\n this.#cumulative.length,\n (i: number) => -this.#cumulative[i] + index,\n );\n\n if (lower + 1 !== this.#cumulative.length) {\n const z1 = index - this.#cumulative[lower - 1];\n const z2 = this.#cumulative[lower] - index;\n return weightedAverage(\n this.#processed[lower - 1].mean,\n z2,\n this.#processed[lower].mean,\n z1,\n );\n }\n\n const z1 =\n index - this.#processedWeight - this.#processed[lower - 1].weight / 2;\n const z2 = this.#processed[lower - 1].weight / 2 - z1;\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return weightedAverage(this.#processed.at(-1)!.mean, z1, this.#max, z2);\n }\n\n /**\n * CDF returns the cumulative distribution function for a given value x.\n */\n cdf(x: number): number {\n this.#process();\n this.#updateCumulative();\n switch (this.#processed.length) {\n case 0:\n return 0;\n case 1: {\n const width = this.#max - this.#min;\n if (x <= this.#min) {\n return 0;\n }\n if (x >= this.#max) {\n return 1;\n }\n if (x - this.#min <= width) {\n // min and max are too close together to do any viable interpolation\n return 0.5;\n }\n return (x - this.#min) / width;\n }\n }\n\n if (x <= this.#min) {\n return 0;\n }\n if (x >= this.#max) {\n return 1;\n }\n const m0 = this.#processed[0].mean;\n // Left Tail\n if (x <= m0) {\n if (m0 - this.#min > 0) {\n return (\n (((x - this.#min) / (m0 - this.#min)) * this.#processed[0].weight) /\n this.#processedWeight /\n 2\n );\n }\n return 0;\n }\n // Right Tail\n // oxlint-disable-next-line typescript/no-non-null-assertion\n const mn = this.#processed.at(-1)!.mean;\n if (x >= mn) {\n if (this.#max - mn > 0) {\n return (\n 1 -\n (((this.#max - x) / (this.#max - mn)) *\n // oxlint-disable-next-line typescript/no-non-null-assertion\n this.#processed.at(-1)!.weight) /\n this.#processedWeight /\n 2\n );\n }\n return 1;\n }\n\n const upper = binarySearch(\n this.#processed.length,\n // Treat equals as greater than, so we can use the upper index\n // This is equivalent to:\n // i => this.#processed[i].mean > x ? -1 : 1,\n i => x - this.#processed[i].mean || 1,\n );\n\n const z1 = x - this.#processed[upper - 1].mean;\n const z2 = this.#processed[upper].mean - x;\n return (\n weightedAverage(\n this.#cumulative[upper - 1],\n z2,\n this.#cumulative[upper],\n z1,\n ) / this.#processedWeight\n );\n }\n\n #integratedQ(k: number): number {\n return (\n (Math.sin(\n (Math.min(k, this.compression) * Math.PI) / this.compression -\n Math.PI / 2,\n ) +\n 1) /\n 2\n );\n }\n\n #integratedLocation(q: number): number {\n return (this.compression * (Math.asin(2 * q - 1) + Math.PI / 2)) / Math.PI;\n }\n}\n\n// Calculate number of bytes needed for a tdigest of size c,\n// where c is the compression value\nexport function byteSizeForCompression(comp: number): number {\n const c = comp | 0;\n // // A centroid is 2 float64s, so we need 16 bytes for each centroid\n // float_size := 8\n // centroid_size := 2 * float_size\n\n // // Unprocessed and processed can grow up to length c\n // unprocessed_size := centroid_size * c\n // processed_size := unprocessed_size\n\n // // the cumulative field can also be of length c, but each item is a single float64\n // cumulative_size := float_size * c // <- this could also be unprocessed_size / 2\n\n // return unprocessed_size + processed_size + cumulative_size\n\n // // or, more succinctly:\n // return float_size * c * 5\n\n // or even more succinctly\n return c * 40;\n}\n\nfunction weightedAverage(\n x1: number,\n w1: number,\n x2: number,\n w2: number,\n): number {\n if (x1 <= x2) {\n return weightedAverageSorted(x1, w1, x2, w2);\n }\n return weightedAverageSorted(x2, w2, x1, w1);\n}\n\nfunction weightedAverageSorted(\n x1: number,\n w1: number,\n x2: number,\n w2: number,\n): number {\n const x = (x1 * w1 + x2 * w2) / (w1 + w2);\n return Math.max(x1, Math.min(x, x2));\n}\n\nfunction processedSize(size: number, compression: number): number {\n if (size === 0) {\n return Math.ceil(compression) * 2;\n }\n return size;\n}\n\nfunction unprocessedSize(size: number, compression: number): number {\n if (size === 0) {\n return Math.ceil(compression) * 8;\n }\n return size;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tdigest.js","names":["#maxUnprocessed","#unprocessedMeans","#unprocessedWeights","#means","#weights","#unprocessedCount","#cumulative","#processedWeight","#unprocessedWeight","#min","#max","#grow","#process","#sortedUnprocessed","#integratedLocation","#integratedQ","#updateCumulative"],"sources":["../../../../shared/src/tdigest.ts"],"sourcesContent":["// Apache License 2.0\n// https://github.com/influxdata/tdigest\n\nimport {binarySearch} from './binary-search.ts';\nimport {Centroid, type CentroidList} from './centroid.ts';\nimport type {TDigestJSON} from './tdigest-schema.ts';\n\nexport interface ReadonlyTDigest {\n readonly count: () => number;\n readonly quantile: (q: number) => number;\n readonly cdf: (x: number) => number;\n}\n\n/** Initial capacity of the buffer of unprocessed values. */\nconst INITIAL_CAPACITY = 16;\n\n// TDigest is a data structure for accurate on-line accumulation of\n// rank-based statistics such as quantiles and trimmed means.\n//\n// Unlike the Go original, centroids are kept as parallel arrays of means and\n// weights rather than as objects, so adding a value allocates nothing. New\n// values are buffered in a Float64Array and sorted with its native numeric\n// sort instead of Array.prototype.sort with a comparator. On an engine\n// without a JIT, such as Hermes in React Native, calling the comparator for\n// every comparison is what made adding values expensive.\nexport class TDigest {\n readonly compression: number;\n\n readonly #maxUnprocessed: number;\n\n /** Means of the processed centroids, ascending. */\n #means!: number[];\n /** Weights of the processed centroids, parallel to `#means`. */\n #weights!: number[];\n\n /** Means of the values added since the last `#process`, in order. */\n #unprocessedMeans: Float64Array;\n /** Weights of the unprocessed values, parallel to `#unprocessedMeans`. */\n #unprocessedWeights: Float64Array;\n #unprocessedCount!: number;\n\n #cumulative!: number[];\n #processedWeight!: number;\n #unprocessedWeight!: number;\n #min!: number;\n #max!: number;\n\n /**\n * A digest keeps roughly `compression` centroids, and buffers up to eight\n * times as many values between merges. The Go original defaults to 1000;\n * 100 keeps p50, p95 and p99 within about 0.5% for a tenth of the memory\n * and serialized size, which is plenty for the inspector's percentiles.\n */\n constructor(compression: number = 100) {\n this.compression = compression;\n this.#maxUnprocessed = unprocessedSize(0, this.compression);\n const capacity = Math.min(INITIAL_CAPACITY, this.#maxUnprocessed + 1);\n this.#unprocessedMeans = new Float64Array(capacity);\n this.#unprocessedWeights = new Float64Array(capacity);\n this.reset();\n }\n\n /**\n * fromJSON creates a TDigest from a JSON-serializable representation.\n * The data should be an object with compression and centroids array.\n */\n static fromJSON(data: Readonly<TDigestJSON>): TDigest {\n const digest = new TDigest(data[0]);\n if (data.length % 2 !== 1) {\n throw new Error('Invalid centroids array');\n }\n for (let i = 1; i < data.length; i += 2) {\n digest.add(data[i], data[i + 1]);\n }\n return digest;\n }\n\n reset(): void {\n this.#means = [];\n this.#weights = [];\n this.#unprocessedCount = 0;\n this.#cumulative = [];\n this.#processedWeight = 0;\n this.#unprocessedWeight = 0;\n this.#min = Number.MAX_VALUE;\n this.#max = -Number.MAX_VALUE;\n }\n\n /**\n * Adds a value with the given weight.\n * Weights which are not a number or are <= 0 are ignored, as are NaN means.\n */\n add(mean: number, weight: number = 1): void {\n if (Number.isNaN(mean) || weight <= 0 || !Number.isFinite(weight)) {\n return;\n }\n\n const n = this.#unprocessedCount;\n if (n === this.#unprocessedMeans.length) {\n this.#grow();\n }\n this.#unprocessedMeans[n] = mean;\n this.#unprocessedWeights[n] = weight;\n this.#unprocessedCount = n + 1;\n this.#unprocessedWeight += weight;\n\n if (this.#unprocessedCount > this.#maxUnprocessed) {\n this.#process();\n }\n }\n\n /** AddCentroidList can quickly add multiple centroids. */\n addCentroidList(centroidList: CentroidList) {\n for (const c of centroidList) {\n this.add(c.mean, c.weight);\n }\n }\n\n /**\n * AddCentroid adds a single centroid.\n * Weights which are not a number or are <= 0 are ignored, as are NaN means.\n */\n addCentroid(c: Centroid): void {\n this.add(c.mean, c.weight);\n }\n\n /**\n * Merges the supplied digest into this digest. Functionally equivalent to\n * calling t.AddCentroidList(t2.Centroids(nil)), but avoids making an extra\n * copy of the CentroidList.\n **/\n merge(t2: TDigest) {\n t2.#process();\n // #process replaces the arrays rather than changing them, so these stay\n // intact even if t2 is this digest.\n const means = t2.#means;\n const weights = t2.#weights;\n for (let i = 0; i < means.length; i++) {\n this.add(means[i], weights[i]);\n }\n }\n\n /** Doubles the unprocessed buffer, up to what `add` lets it hold. */\n #grow(): void {\n const capacity = Math.min(\n this.#unprocessedMeans.length * 2,\n this.#maxUnprocessed + 1,\n );\n const means = new Float64Array(capacity);\n means.set(this.#unprocessedMeans);\n this.#unprocessedMeans = means;\n const weights = new Float64Array(capacity);\n weights.set(this.#unprocessedWeights);\n this.#unprocessedWeights = weights;\n }\n\n /**\n * Merges the unprocessed values into the centroids: walks both in order of\n * mean, folding each into the last centroid while that stays within its\n * size limit, and starting a new centroid otherwise.\n */\n #process() {\n if (this.#unprocessedCount === 0) {\n return;\n }\n const [newMeans, newWeights] = this.#sortedUnprocessed();\n const oldMeans = this.#means;\n const oldWeights = this.#weights;\n const n = newMeans.length;\n const p = oldMeans.length;\n this.#unprocessedCount = 0;\n this.#processedWeight += this.#unprocessedWeight;\n this.#unprocessedWeight = 0;\n const total = this.#processedWeight;\n\n const means: number[] = [];\n const weights: number[] = [];\n // The centroid being built, kept in locals rather than in the arrays,\n // which is markedly faster without a JIT. Its weight is 0 until the first\n // value.\n let mean = 0;\n let weight = 0;\n let soFar = 0;\n // A limit of 0 makes the first value start a centroid, whose limit then\n // comes from the same formula as every other's. With soFar at 0 that is\n // integratedQ(1): integratedLocation(0) is exactly 0, since\n // Math.asin(-1) is -Math.PI / 2.\n let limit = 0;\n let i = 0;\n let j = 0;\n while (i < n || j < p) {\n // On a tie the new value goes first, as in the original, which appended\n // the old centroids to the new values and sorted them with a stable sort.\n let m: number;\n let w: number;\n if (i < n && (j === p || newMeans[i] <= oldMeans[j])) {\n m = newMeans[i];\n w = newWeights[i++];\n } else {\n m = oldMeans[j];\n w = oldWeights[j++];\n }\n if (soFar + w <= limit) {\n // Same arithmetic as Centroid.add.\n weight += w;\n mean += (w * (m - mean)) / weight;\n } else {\n if (weight > 0) {\n means.push(mean);\n weights.push(weight);\n }\n const k = this.#integratedLocation(soFar / total);\n limit = total * this.#integratedQ(k + 1);\n mean = m;\n weight = w;\n }\n soFar += w;\n }\n means.push(mean);\n weights.push(weight);\n\n this.#means = means;\n this.#weights = weights;\n this.#min = Math.min(this.#min, means[0]);\n // oxlint-disable-next-line typescript/no-non-null-assertion\n this.#max = Math.max(this.#max, means.at(-1)!);\n }\n\n /** The unprocessed means and weights, sorted by mean. */\n #sortedUnprocessed(): [Float64Array, Float64Array] {\n const n = this.#unprocessedCount;\n const means = this.#unprocessedMeans.subarray(0, n);\n const weights = this.#unprocessedWeights.subarray(0, n);\n // fromJSON and merge add centroids in order of mean.\n if (isSorted(means)) {\n return [means, weights];\n }\n // With one weight for all the values, sorting the means alone keeps every\n // value with its weight, and the native numeric sort needs no comparator.\n if (allEqual(weights)) {\n means.sort();\n return [means, weights];\n }\n // A stable sort, so values with equal means stay in the order added.\n const order = Array.from(means, (_, k) => k).sort(\n (a, b) => means[a] - means[b],\n );\n return [\n Float64Array.from(order, k => means[k]),\n Float64Array.from(order, k => weights[k]),\n ];\n }\n\n /**\n * Centroids returns a copy of processed centroids.\n * Useful when aggregating multiple t-digests.\n *\n * Centroids are appended to the passed CentroidList; if you're re-using a\n * buffer, be sure to pass cl[:0].\n */\n centroids(cl: CentroidList = []): CentroidList {\n this.#process();\n const result = [...cl];\n for (let i = 0; i < this.#means.length; i++) {\n result.push(new Centroid(this.#means[i], this.#weights[i]));\n }\n return result;\n }\n\n count(): number {\n this.#process();\n\n // this.process always updates this.processedWeight to the total count of all\n // centroids, so we don't need to re-count here.\n return this.#processedWeight;\n }\n\n /**\n * toJSON returns a JSON-serializable representation of the digest.\n * This processes the digest and returns an object with compression and centroid data.\n */\n toJSON(): TDigestJSON {\n this.#process();\n const data: TDigestJSON = [this.compression];\n for (let i = 0; i < this.#means.length; i++) {\n data.push(this.#means[i], this.#weights[i]);\n }\n return data;\n }\n\n #updateCumulative() {\n // Weight can only increase, so the final cumulative value will always be\n // either equal to, or less than, the total weight. If they are the same,\n // then nothing has changed since the last update.\n if (\n this.#cumulative.length > 0 &&\n this.#cumulative.at(-1) === this.#processedWeight\n ) {\n return;\n }\n const n = this.#means.length + 1;\n if (this.#cumulative.length > n) {\n this.#cumulative.length = n;\n }\n\n let prev = 0;\n for (let i = 0; i < this.#means.length; i++) {\n const cur = this.#weights[i];\n this.#cumulative[i] = prev + cur / 2;\n prev += cur;\n }\n this.#cumulative[this.#means.length] = prev;\n }\n\n // Quantile returns the (approximate) quantile of\n // the distribution. Accepted values for q are between 0 and 1.\n // Returns NaN if Count is zero or bad inputs.\n quantile(q: number): number {\n this.#process();\n this.#updateCumulative();\n if (q < 0 || q > 1 || this.#means.length === 0) {\n return NaN;\n }\n if (this.#means.length === 1) {\n return this.#means[0];\n }\n const index = q * this.#processedWeight;\n if (index <= this.#weights[0] / 2) {\n return (\n this.#min +\n ((2 * index) / this.#weights[0]) * (this.#means[0] - this.#min)\n );\n }\n\n const lower = binarySearch(\n this.#cumulative.length,\n (i: number) => -this.#cumulative[i] + index,\n );\n\n if (lower + 1 !== this.#cumulative.length) {\n const z1 = index - this.#cumulative[lower - 1];\n const z2 = this.#cumulative[lower] - index;\n return weightedAverage(\n this.#means[lower - 1],\n z2,\n this.#means[lower],\n z1,\n );\n }\n\n const z1 = index - this.#processedWeight - this.#weights[lower - 1] / 2;\n const z2 = this.#weights[lower - 1] / 2 - z1;\n // oxlint-disable-next-line typescript/no-non-null-assertion\n return weightedAverage(this.#means.at(-1)!, z1, this.#max, z2);\n }\n\n /**\n * CDF returns the cumulative distribution function for a given value x.\n */\n cdf(x: number): number {\n this.#process();\n this.#updateCumulative();\n switch (this.#means.length) {\n case 0:\n return 0;\n case 1: {\n const width = this.#max - this.#min;\n if (x <= this.#min) {\n return 0;\n }\n if (x >= this.#max) {\n return 1;\n }\n if (x - this.#min <= width) {\n // min and max are too close together to do any viable interpolation\n return 0.5;\n }\n return (x - this.#min) / width;\n }\n }\n\n if (x <= this.#min) {\n return 0;\n }\n if (x >= this.#max) {\n return 1;\n }\n const m0 = this.#means[0];\n // Left Tail\n if (x <= m0) {\n if (m0 - this.#min > 0) {\n return (\n (((x - this.#min) / (m0 - this.#min)) * this.#weights[0]) /\n this.#processedWeight /\n 2\n );\n }\n return 0;\n }\n // Right Tail\n // oxlint-disable-next-line typescript/no-non-null-assertion\n const mn = this.#means.at(-1)!;\n if (x >= mn) {\n if (this.#max - mn > 0) {\n return (\n 1 -\n (((this.#max - x) / (this.#max - mn)) *\n // oxlint-disable-next-line typescript/no-non-null-assertion\n this.#weights.at(-1)!) /\n this.#processedWeight /\n 2\n );\n }\n return 1;\n }\n\n const upper = binarySearch(\n this.#means.length,\n // Treat equals as greater than, so we can use the upper index\n // This is equivalent to:\n // i => this.#means[i] > x ? -1 : 1,\n i => x - this.#means[i] || 1,\n );\n\n const z1 = x - this.#means[upper - 1];\n const z2 = this.#means[upper] - x;\n return (\n weightedAverage(\n this.#cumulative[upper - 1],\n z2,\n this.#cumulative[upper],\n z1,\n ) / this.#processedWeight\n );\n }\n\n #integratedQ(k: number): number {\n return (\n (Math.sin(\n (Math.min(k, this.compression) * Math.PI) / this.compression -\n Math.PI / 2,\n ) +\n 1) /\n 2\n );\n }\n\n #integratedLocation(q: number): number {\n return (this.compression * (Math.asin(2 * q - 1) + Math.PI / 2)) / Math.PI;\n }\n}\n\n// Calculate number of bytes needed for a tdigest of size c,\n// where c is the compression value\nexport function byteSizeForCompression(comp: number): number {\n const c = comp | 0;\n // // A centroid is 2 float64s, so we need 16 bytes for each centroid\n // float_size := 8\n // centroid_size := 2 * float_size\n\n // // Unprocessed and processed can grow up to length c\n // unprocessed_size := centroid_size * c\n // processed_size := unprocessed_size\n\n // // the cumulative field can also be of length c, but each item is a single float64\n // cumulative_size := float_size * c // <- this could also be unprocessed_size / 2\n\n // return unprocessed_size + processed_size + cumulative_size\n\n // // or, more succinctly:\n // return float_size * c * 5\n\n // or even more succinctly\n return c * 40;\n}\n\nfunction isSorted(values: Float64Array): boolean {\n for (let i = 1; i < values.length; i++) {\n if (values[i] < values[i - 1]) {\n return false;\n }\n }\n return true;\n}\n\nfunction allEqual(values: Float64Array): boolean {\n for (let i = 1; i < values.length; i++) {\n if (values[i] !== values[0]) {\n return false;\n }\n }\n return true;\n}\n\nfunction weightedAverage(\n x1: number,\n w1: number,\n x2: number,\n w2: number,\n): number {\n if (x1 <= x2) {\n return weightedAverageSorted(x1, w1, x2, w2);\n }\n return weightedAverageSorted(x2, w2, x1, w1);\n}\n\nfunction weightedAverageSorted(\n x1: number,\n w1: number,\n x2: number,\n w2: number,\n): number {\n const x = (x1 * w1 + x2 * w2) / (w1 + w2);\n return Math.max(x1, Math.min(x, x2));\n}\n\nfunction unprocessedSize(size: number, compression: number): number {\n if (size === 0) {\n return Math.ceil(compression) * 8;\n }\n return size;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../z2s/src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAQ7C,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAExD,OAAO,KAAK,EACV,GAAG,EACH,KAAK,EAEL,kBAAkB,EAElB,WAAW,EAEX,QAAQ,EACR,eAAe,EAEhB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,uCAAuC,CAAC;AACxE,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,2BAA2B,CAAC;AAUtD,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,YAAY,CAAC;IAErB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAQF,wBAAgB,OAAO,CACrB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,GAAG,EACR,MAAM,CAAC,EAAE,MAAM,GACd,QAAQ,CAgBV;AAiDD,wBAAgB,KAAK,CACnB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAC5B,QAAQ,CAWV;AAUD,wBAAgB,OAAO,CACrB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,QAAQ,GAAG,SAAS,EAC7B,KAAK,EAAE,KAAK,GACX,QAAQ,CAoBV;AAED,wBAAgB,KAAK,CACnB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,OAAO,EAAE,QAAQ,GAAG,SAAS,EAC7B,KAAK,EAAE,KAAK,GACX,QAAQ,CA4CV;AA2KD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,CAAC,UAAU,EAAE,KAAK,KAAK,QAAQ,CAiBjC;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../z2s/src/compiler.ts"],"names":[],"mappings":"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"}
|