@winkjs/composer 0.0.2 → 0.4.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/LICENSE +1 -1
- package/README.md +42 -103
- package/package.json +53 -29
- package/src/composer.js +75 -0
- package/src/core/batch/aoo-encoder.js +148 -0
- package/src/core/batch/index.js +12 -0
- package/src/core/batch/sliding-window.js +91 -0
- package/src/core/codec/index.js +137 -0
- package/src/core/emitter-manager/mqtt/constants.js +102 -0
- package/src/core/emitter-manager/mqtt/emitter.js +780 -0
- package/src/core/emitter-manager/mqtt/index.js +190 -0
- package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
- package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
- package/src/core/emitter-manager/terminal/formatters.js +160 -0
- package/src/core/emitter-manager/terminal/index.js +341 -0
- package/src/core/env-vars.js +245 -0
- package/src/core/mqtt-protocol.js +47 -0
- package/src/core/partition-manager/index.js +7 -0
- package/src/core/partition-manager/init.js +44 -0
- package/src/core/partition-manager/introspect.js +15 -0
- package/src/core/partition-manager/publish-to.js +6 -0
- package/src/core/partition-manager/recompute.js +5 -0
- package/src/core/partition-manager/reset.js +5 -0
- package/src/core/partition-manager/update.js +264 -0
- package/src/core/partition-manager/validate-flow.js +157 -0
- package/src/core/semantics/digest.js +128 -0
- package/src/core/semantics/index.js +83 -0
- package/src/core/semantics/loader.js +571 -0
- package/src/core/semantics/schemas/asset-class-schema.js +218 -0
- package/src/core/semantics/schemas/column-schema.js +651 -0
- package/src/core/semantics/schemas/enum-schema.js +153 -0
- package/src/core/semantics/schemas/index.js +51 -0
- package/src/core/semantics/warnings.js +141 -0
- package/src/core/shutdown-manager/index.js +289 -0
- package/src/core/source-manager/csv/index.js +171 -0
- package/src/core/source-manager/csv/start.js +456 -0
- package/src/core/source-manager/mqtt/client.js +406 -0
- package/src/core/source-manager/mqtt/constants.js +147 -0
- package/src/core/source-manager/mqtt/dedup.js +244 -0
- package/src/core/source-manager/mqtt/index.js +260 -0
- package/src/core/source-manager/mqtt/status.js +546 -0
- package/src/core/source-manager/test-harness/comparator.js +226 -0
- package/src/core/source-manager/test-harness/field-generator.js +85 -0
- package/src/core/source-manager/test-harness/fuzz.js +87 -0
- package/src/core/source-manager/test-harness/index.js +115 -0
- package/src/core/source-manager/test-harness/prng.js +57 -0
- package/src/core/source-manager/test-harness/start.js +232 -0
- package/src/core/source-manager/test-harness/validate.js +213 -0
- package/src/core/storage-manager/questdb/assert-columns.js +120 -0
- package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
- package/src/core/storage-manager/questdb/index.js +1251 -0
- package/src/core/storage-manager/questdb/persist-plan.js +488 -0
- package/src/core/storage-manager/questdb/writers.js +142 -0
- package/src/core/test-utils/sealed-record.js +80 -0
- package/src/core/test-utils/soak-signature.js +149 -0
- package/src/core/test-utils/tcp-proxy.js +106 -0
- package/src/core/tunable/helpers.js +254 -0
- package/src/core/tunable/index.js +87 -0
- package/src/core/utils/console-formatter/index.js +207 -0
- package/src/core/utils/create-smart-store-as/index.js +98 -0
- package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
- package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
- package/src/core/utils/flow/index.js +5 -0
- package/src/core/utils/flow/make-collision-checker.js +23 -0
- package/src/core/utils/flow/to-kebab.js +20 -0
- package/src/core/utils/half-life/index.js +111 -0
- package/src/core/utils/node/disable.js +11 -0
- package/src/core/utils/node/enable.js +11 -0
- package/src/core/utils/node/execute-triggers.js +40 -0
- package/src/core/utils/node/index.js +10 -0
- package/src/core/utils/node/pause.js +11 -0
- package/src/core/utils/node/populate-predicate-inputs.js +14 -0
- package/src/core/utils/node/publish-nan.js +19 -0
- package/src/core/utils/node/reset-predicate-inputs.js +11 -0
- package/src/core/utils/node/unpause.js +11 -0
- package/src/core/utils/node/validate-spec.js +22 -0
- package/src/core/utils/options/resolve-field-keyed.js +115 -0
- package/src/core/utils/quantize/index.js +75 -0
- package/src/core/utils/stats/formulas.js +67 -0
- package/src/core/utils/stats/index.js +3 -0
- package/src/core/utils/validate/composer-validators.js +141 -0
- package/src/core/utils/validate/helpers.js +206 -0
- package/src/core/utils/validate/index.js +12 -0
- package/src/core/utils/validate/type-validators.js +538 -0
- package/src/core/utils/validate/validate.js +107 -0
- package/src/core/utils/validate/validators.js +177 -0
- package/src/core/wiring/assert-handle.js +57 -0
- package/src/core/wiring/assert-module.js +63 -0
- package/src/core/wiring/index.js +5 -0
- package/src/core/wiring/node-type-to-module.js +17 -0
- package/src/core/wiring/wire-emitters.js +256 -0
- package/src/core/wiring/wire-linear-graph.js +25 -0
- package/src/core/wiring/wire-node.js +157 -0
- package/src/core/wiring/wire-semantics.js +173 -0
- package/src/core/wiring/wire-storages.js +344 -0
- package/src/flow/check-output-collisions.js +93 -0
- package/src/flow/consts.js +9 -0
- package/src/flow/deep-clone-spec.js +64 -0
- package/src/flow/driver.js +171 -0
- package/src/flow/expand-single-input-array.js +76 -0
- package/src/flow/expand-template-spec.js +93 -0
- package/src/flow/flow-api-schemas.js +300 -0
- package/src/flow/flow.js +658 -0
- package/src/flow/for-each.js +225 -0
- package/src/flow/get-signature-pattern.js +31 -0
- package/src/flow/get-target-array.js +46 -0
- package/src/flow/inspect.js +67 -0
- package/src/flow/load-node-module.js +81 -0
- package/src/flow/make-node-method.js +112 -0
- package/src/flow/resolve-pick-by-field.js +77 -0
- package/src/flow/resolve-tunables.js +76 -0
- package/src/flow/run.js +392 -0
- package/src/flow/serialize.js +161 -0
- package/src/flow/signatures-schema.js +222 -0
- package/src/flow/spec-builder.js +65 -0
- package/src/flow/validate-triggers.js +250 -0
- package/src/flow/validate.js +261 -0
- package/src/nodes/accumulate/index.js +21 -0
- package/src/nodes/accumulate/init.js +48 -0
- package/src/nodes/accumulate/introspect.js +123 -0
- package/src/nodes/accumulate/publish-to.js +34 -0
- package/src/nodes/accumulate/recompute.js +27 -0
- package/src/nodes/accumulate/reset.js +25 -0
- package/src/nodes/accumulate/update.js +42 -0
- package/src/nodes/appraise/calibrate.js +64 -0
- package/src/nodes/appraise/decision.js +66 -0
- package/src/nodes/appraise/deviation.js +140 -0
- package/src/nodes/appraise/index.js +23 -0
- package/src/nodes/appraise/init.js +165 -0
- package/src/nodes/appraise/integrate.js +45 -0
- package/src/nodes/appraise/introspect.js +352 -0
- package/src/nodes/appraise/publish-to.js +93 -0
- package/src/nodes/appraise/receptor.js +69 -0
- package/src/nodes/appraise/recompute.js +79 -0
- package/src/nodes/appraise/reset.js +53 -0
- package/src/nodes/appraise/update.js +130 -0
- package/src/nodes/archive/csv/index.js +6 -0
- package/src/nodes/archive/csv/init.js +36 -0
- package/src/nodes/archive/csv/load.js +70 -0
- package/src/nodes/archive/csv/reset.js +14 -0
- package/src/nodes/archive/csv/simple-parser.js +216 -0
- package/src/nodes/archive/csv/test.js +173 -0
- package/src/nodes/archive/csv/update.js +63 -0
- package/src/nodes/butterworth-filter/index.js +18 -0
- package/src/nodes/butterworth-filter/init.js +184 -0
- package/src/nodes/butterworth-filter/introspect.js +228 -0
- package/src/nodes/butterworth-filter/publish-to.js +21 -0
- package/src/nodes/butterworth-filter/recompute.js +13 -0
- package/src/nodes/butterworth-filter/reset.js +30 -0
- package/src/nodes/butterworth-filter/update.js +38 -0
- package/src/nodes/categorize/index.js +19 -0
- package/src/nodes/categorize/init.js +58 -0
- package/src/nodes/categorize/introspect.js +177 -0
- package/src/nodes/categorize/publish-to.js +29 -0
- package/src/nodes/categorize/recompute.js +14 -0
- package/src/nodes/categorize/reset.js +16 -0
- package/src/nodes/categorize/update.js +53 -0
- package/src/nodes/controller/index.js +9 -0
- package/src/nodes/controller/init.js +55 -0
- package/src/nodes/controller/introspect.js +91 -0
- package/src/nodes/controller/publish-to.js +8 -0
- package/src/nodes/controller/recompute.js +9 -0
- package/src/nodes/controller/reset.js +17 -0
- package/src/nodes/controller/update.js +63 -0
- package/src/nodes/diff/index.js +19 -0
- package/src/nodes/diff/init.js +37 -0
- package/src/nodes/diff/introspect.js +132 -0
- package/src/nodes/diff/publish-to.js +21 -0
- package/src/nodes/diff/recompute.js +12 -0
- package/src/nodes/diff/reset.js +12 -0
- package/src/nodes/diff/update.js +37 -0
- package/src/nodes/digest-moments/formulas.js +12 -0
- package/src/nodes/digest-moments/index.js +14 -0
- package/src/nodes/digest-moments/init.js +67 -0
- package/src/nodes/digest-moments/introspect.js +154 -0
- package/src/nodes/digest-moments/publish-to.js +34 -0
- package/src/nodes/digest-moments/recompute.js +14 -0
- package/src/nodes/digest-moments/reset.js +14 -0
- package/src/nodes/digest-moments/update.js +120 -0
- package/src/nodes/dwell-time-tracker/index.js +14 -0
- package/src/nodes/dwell-time-tracker/init.js +59 -0
- package/src/nodes/dwell-time-tracker/introspect.js +137 -0
- package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
- package/src/nodes/dwell-time-tracker/recompute.js +8 -0
- package/src/nodes/dwell-time-tracker/reset.js +23 -0
- package/src/nodes/dwell-time-tracker/update.js +103 -0
- package/src/nodes/emit-if/helpers.js +94 -0
- package/src/nodes/emit-if/index.js +16 -0
- package/src/nodes/emit-if/init.js +67 -0
- package/src/nodes/emit-if/introspect.js +102 -0
- package/src/nodes/emit-if/publish-to.js +13 -0
- package/src/nodes/emit-if/recompute.js +12 -0
- package/src/nodes/emit-if/reset.js +27 -0
- package/src/nodes/emit-if/update.js +93 -0
- package/src/nodes/es-correlation/index.js +19 -0
- package/src/nodes/es-correlation/init.js +73 -0
- package/src/nodes/es-correlation/introspect.js +176 -0
- package/src/nodes/es-correlation/publish-to.js +32 -0
- package/src/nodes/es-correlation/recompute.js +56 -0
- package/src/nodes/es-correlation/reset.js +27 -0
- package/src/nodes/es-correlation/update.js +110 -0
- package/src/nodes/es-mean/index.js +20 -0
- package/src/nodes/es-mean/init.js +58 -0
- package/src/nodes/es-mean/introspect.js +129 -0
- package/src/nodes/es-mean/publish-to.js +19 -0
- package/src/nodes/es-mean/recompute.js +16 -0
- package/src/nodes/es-mean/reset.js +24 -0
- package/src/nodes/es-mean/update.js +69 -0
- package/src/nodes/es-pairwise-correlation/index.js +19 -0
- package/src/nodes/es-pairwise-correlation/init.js +98 -0
- package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
- package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
- package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
- package/src/nodes/es-pairwise-correlation/reset.js +29 -0
- package/src/nodes/es-pairwise-correlation/update.js +89 -0
- package/src/nodes/es-stats/index.js +21 -0
- package/src/nodes/es-stats/init.js +105 -0
- package/src/nodes/es-stats/introspect.js +157 -0
- package/src/nodes/es-stats/publish-to.js +42 -0
- package/src/nodes/es-stats/recompute.js +74 -0
- package/src/nodes/es-stats/reset.js +49 -0
- package/src/nodes/es-stats/update-envelope.js +44 -0
- package/src/nodes/es-stats/update-welford.js +64 -0
- package/src/nodes/es-stats/update.js +59 -0
- package/src/nodes/index.js +83 -0
- package/src/nodes/invert-flag/index.js +20 -0
- package/src/nodes/invert-flag/init.js +36 -0
- package/src/nodes/invert-flag/introspect.js +115 -0
- package/src/nodes/invert-flag/publish-to.js +23 -0
- package/src/nodes/invert-flag/recompute.js +12 -0
- package/src/nodes/invert-flag/reset.js +12 -0
- package/src/nodes/invert-flag/update.js +32 -0
- package/src/nodes/kalman1d/index.js +20 -0
- package/src/nodes/kalman1d/init.js +103 -0
- package/src/nodes/kalman1d/introspect.js +250 -0
- package/src/nodes/kalman1d/publish-to.js +34 -0
- package/src/nodes/kalman1d/recompute.js +23 -0
- package/src/nodes/kalman1d/reset.js +29 -0
- package/src/nodes/kalman1d/update.js +144 -0
- package/src/nodes/kernel/index.js +18 -0
- package/src/nodes/kernel/init.js +66 -0
- package/src/nodes/kernel/introspect.js +163 -0
- package/src/nodes/kernel/presets.js +74 -0
- package/src/nodes/kernel/publish-to.js +25 -0
- package/src/nodes/kernel/recompute.js +14 -0
- package/src/nodes/kernel/reset.js +20 -0
- package/src/nodes/kernel/update.js +69 -0
- package/src/nodes/lag/index.js +21 -0
- package/src/nodes/lag/init.js +87 -0
- package/src/nodes/lag/introspect.js +202 -0
- package/src/nodes/lag/publish-to.js +64 -0
- package/src/nodes/lag/recompute.js +33 -0
- package/src/nodes/lag/reset.js +49 -0
- package/src/nodes/lag/update.js +133 -0
- package/src/nodes/median3/index.js +19 -0
- package/src/nodes/median3/init.js +40 -0
- package/src/nodes/median3/introspect.js +116 -0
- package/src/nodes/median3/publish-to.js +21 -0
- package/src/nodes/median3/recompute.js +12 -0
- package/src/nodes/median3/reset.js +15 -0
- package/src/nodes/median3/update.js +58 -0
- package/src/nodes/moments-digest/copy-from.js +12 -0
- package/src/nodes/moments-digest/flush.js +17 -0
- package/src/nodes/moments-digest/index.js +132 -0
- package/src/nodes/moments-digest/init.js +84 -0
- package/src/nodes/moments-digest/introspect.js +122 -0
- package/src/nodes/moments-digest/prelude.js +28 -0
- package/src/nodes/moments-digest/publish-to.js +31 -0
- package/src/nodes/moments-digest/recompute.js +9 -0
- package/src/nodes/moments-digest/reset.js +20 -0
- package/src/nodes/moments-digest/update.js +182 -0
- package/src/nodes/node-names.js +67 -0
- package/src/nodes/page-hinkley/index.js +20 -0
- package/src/nodes/page-hinkley/init.js +66 -0
- package/src/nodes/page-hinkley/introspect.js +193 -0
- package/src/nodes/page-hinkley/publish-to.js +28 -0
- package/src/nodes/page-hinkley/recompute.js +14 -0
- package/src/nodes/page-hinkley/reset.js +23 -0
- package/src/nodes/page-hinkley/update.js +105 -0
- package/src/nodes/pass-if/index.js +21 -0
- package/src/nodes/pass-if/init.js +37 -0
- package/src/nodes/pass-if/introspect.js +93 -0
- package/src/nodes/pass-if/publish-to.js +15 -0
- package/src/nodes/pass-if/recompute.js +15 -0
- package/src/nodes/pass-if/reset.js +18 -0
- package/src/nodes/pass-if/update.js +37 -0
- package/src/nodes/persist-if/helpers.js +111 -0
- package/src/nodes/persist-if/index.js +9 -0
- package/src/nodes/persist-if/init.js +98 -0
- package/src/nodes/persist-if/introspect.js +106 -0
- package/src/nodes/persist-if/publish-to.js +21 -0
- package/src/nodes/persist-if/recompute.js +20 -0
- package/src/nodes/persist-if/reset.js +35 -0
- package/src/nodes/persist-if/update.js +112 -0
- package/src/nodes/persistence-check/index.js +14 -0
- package/src/nodes/persistence-check/init.js +38 -0
- package/src/nodes/persistence-check/introspect.js +144 -0
- package/src/nodes/persistence-check/publish-to.js +11 -0
- package/src/nodes/persistence-check/recompute.js +7 -0
- package/src/nodes/persistence-check/reset.js +12 -0
- package/src/nodes/persistence-check/update.js +57 -0
- package/src/nodes/process-index/index.js +15 -0
- package/src/nodes/process-index/init.js +48 -0
- package/src/nodes/process-index/introspect.js +182 -0
- package/src/nodes/process-index/publish-to.js +29 -0
- package/src/nodes/process-index/recompute.js +8 -0
- package/src/nodes/process-index/reset.js +8 -0
- package/src/nodes/process-index/update.js +75 -0
- package/src/nodes/ratio/index.js +14 -0
- package/src/nodes/ratio/init.js +37 -0
- package/src/nodes/ratio/introspect.js +155 -0
- package/src/nodes/ratio/publish-to.js +15 -0
- package/src/nodes/ratio/recompute.js +7 -0
- package/src/nodes/ratio/reset.js +7 -0
- package/src/nodes/ratio/update.js +47 -0
- package/src/nodes/sanitize/index.js +82 -0
- package/src/nodes/sanitize/init.js +82 -0
- package/src/nodes/sanitize/introspect.js +194 -0
- package/src/nodes/sanitize/publish-to.js +15 -0
- package/src/nodes/sanitize/recompute.js +8 -0
- package/src/nodes/sanitize/reset.js +14 -0
- package/src/nodes/sanitize/update.js +102 -0
- package/src/nodes/spike-guard/index.js +14 -0
- package/src/nodes/spike-guard/init.js +47 -0
- package/src/nodes/spike-guard/introspect.js +130 -0
- package/src/nodes/spike-guard/publish-to.js +35 -0
- package/src/nodes/spike-guard/recompute.js +14 -0
- package/src/nodes/spike-guard/reset.js +19 -0
- package/src/nodes/spike-guard/update.js +89 -0
- package/src/nodes/sse-emitter/index.js +7 -0
- package/src/nodes/sse-emitter/init.js +105 -0
- package/src/nodes/sse-emitter/introspect.js +134 -0
- package/src/nodes/sse-emitter/publish-to.js +6 -0
- package/src/nodes/sse-emitter/recompute.js +16 -0
- package/src/nodes/sse-emitter/reset.js +19 -0
- package/src/nodes/sse-emitter/update.js +69 -0
- package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
- package/src/nodes/sse-emitter/utils/build-message.js +31 -0
- package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
- package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
- package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
- package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
- package/src/nodes/state-change-detector/helpers.js +35 -0
- package/src/nodes/state-change-detector/index.js +12 -0
- package/src/nodes/state-change-detector/init.js +56 -0
- package/src/nodes/state-change-detector/introspect.js +146 -0
- package/src/nodes/state-change-detector/publish-to.js +20 -0
- package/src/nodes/state-change-detector/recompute.js +6 -0
- package/src/nodes/state-change-detector/reset.js +20 -0
- package/src/nodes/state-change-detector/update.js +97 -0
- package/src/nodes/sw-stats/index.js +14 -0
- package/src/nodes/sw-stats/init.js +51 -0
- package/src/nodes/sw-stats/introspect.js +131 -0
- package/src/nodes/sw-stats/publish-to.js +45 -0
- package/src/nodes/sw-stats/recompute.js +33 -0
- package/src/nodes/sw-stats/reset.js +15 -0
- package/src/nodes/sw-stats/update.js +39 -0
- package/src/nodes/swing-watch/index.js +17 -0
- package/src/nodes/swing-watch/init.js +144 -0
- package/src/nodes/swing-watch/introspect.js +188 -0
- package/src/nodes/swing-watch/publish-to.js +53 -0
- package/src/nodes/swing-watch/recompute.js +22 -0
- package/src/nodes/swing-watch/reset.js +55 -0
- package/src/nodes/swing-watch/update.js +767 -0
- package/src/nodes/tally/index.js +15 -0
- package/src/nodes/tally/init.js +32 -0
- package/src/nodes/tally/introspect.js +116 -0
- package/src/nodes/tally/publish-to.js +28 -0
- package/src/nodes/tally/recompute.js +10 -0
- package/src/nodes/tally/reset.js +10 -0
- package/src/nodes/tally/update.js +44 -0
- package/src/nodes/threshold/index.js +14 -0
- package/src/nodes/threshold/init.js +121 -0
- package/src/nodes/threshold/introspect.js +192 -0
- package/src/nodes/threshold/publish-to.js +11 -0
- package/src/nodes/threshold/recompute.js +8 -0
- package/src/nodes/threshold/reset.js +14 -0
- package/src/nodes/threshold/update.js +54 -0
- package/src/nodes/transform/helpers.js +39 -0
- package/src/nodes/transform/index.js +15 -0
- package/src/nodes/transform/init.js +35 -0
- package/src/nodes/transform/introspect.js +118 -0
- package/src/nodes/transform/publish-to.js +23 -0
- package/src/nodes/transform/recompute.js +12 -0
- package/src/nodes/transform/reset.js +11 -0
- package/src/nodes/transform/update.js +32 -0
- package/src/nodes/trend/compute-confidence.js +112 -0
- package/src/nodes/trend/index.js +14 -0
- package/src/nodes/trend/init.js +81 -0
- package/src/nodes/trend/introspect.js +151 -0
- package/src/nodes/trend/publish-to.js +22 -0
- package/src/nodes/trend/recompute.js +15 -0
- package/src/nodes/trend/reset.js +26 -0
- package/src/nodes/trend/update.js +93 -0
- package/src/nodes/tw-stats/copy-from.js +16 -0
- package/src/nodes/tw-stats/flush.js +12 -0
- package/src/nodes/tw-stats/index.js +41 -0
- package/src/nodes/tw-stats/init.js +92 -0
- package/src/nodes/tw-stats/introspect.js +171 -0
- package/src/nodes/tw-stats/publish-to.js +108 -0
- package/src/nodes/tw-stats/recompute.js +9 -0
- package/src/nodes/tw-stats/reset.js +16 -0
- package/src/nodes/tw-stats/update.js +113 -0
- package/src/nodes/unbalance/index.js +15 -0
- package/src/nodes/unbalance/init.js +59 -0
- package/src/nodes/unbalance/introspect.js +167 -0
- package/src/nodes/unbalance/publish-to.js +52 -0
- package/src/nodes/unbalance/recompute.js +11 -0
- package/src/nodes/unbalance/reset.js +10 -0
- package/src/nodes/unbalance/update.js +83 -0
- package/src/nodes/vector-distance/index.js +14 -0
- package/src/nodes/vector-distance/init.js +54 -0
- package/src/nodes/vector-distance/introspect.js +149 -0
- package/src/nodes/vector-distance/publish-to.js +35 -0
- package/src/nodes/vector-distance/recompute.js +11 -0
- package/src/nodes/vector-distance/reset.js +20 -0
- package/src/nodes/vector-distance/update.js +139 -0
- package/src/nodes/winnow/index.js +12 -0
- package/src/nodes/winnow/init.js +82 -0
- package/src/nodes/winnow/introspect.js +253 -0
- package/src/nodes/winnow/publish-to.js +51 -0
- package/src/nodes/winnow/recompute.js +14 -0
- package/src/nodes/winnow/reset.js +34 -0
- package/src/nodes/winnow/update.js +203 -0
- package/src/tools/training/features.js +227 -0
- package/src/tools/training/index.js +21 -0
- package/src/tools/training/logistic.js +238 -0
- package/src/tools/training/metrics.js +126 -0
- package/src/tools/training/scale.js +239 -0
- package/src/tools/training/validate.js +103 -0
- package/src/windowing/count-sliding/create.js +16 -0
- package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
- package/src/windowing/count-sliding/index.js +6 -0
- package/src/windowing/count-sliding/is-not-full.js +5 -0
- package/src/windowing/count-sliding/push.js +15 -0
- package/src/windowing/count-sliding/reset.js +11 -0
- package/src/windowing/count-sliding/size.js +5 -0
- package/src/windowing/time-sliding/create.js +25 -0
- package/src/windowing/time-sliding/push.js +42 -0
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -132
- package/docs/.nojekyll +0 -0
- package/docs/CONTRIBUTING.md +0 -134
- package/docs/README.md +0 -132
- package/docs/_coverpage.md +0 -26
- package/docs/_media/bg.png +0 -0
- package/docs/_media/wink-logo.png +0 -0
- package/docs/_navbar.md +0 -14
- package/docs/_sidebar.md +0 -2
- package/docs/index.html +0 -44
- package/eslint.config.js +0 -283
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Initializes esMean node state from a validated spec.
|
|
3
|
+
*
|
|
4
|
+
* Derives the smoothing factor (alpha) from the configured half-life,
|
|
5
|
+
* pre-computes the MAD alpha for adaptive tracking (half-life × 1.5 to
|
|
6
|
+
* dampen flapping), and allocates all state properties up-front on a
|
|
7
|
+
* prototype-free object — no allocations occur on the hot path.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { validateSpec } from '../../core/utils/node/index.js';
|
|
11
|
+
import * as introspect from './introspect.js';
|
|
12
|
+
import { halfLifeToAlpha } from '../../core/utils/half-life/index.js';
|
|
13
|
+
import { resolveScalar } from '../../core/utils/options/resolve-field-keyed.js';
|
|
14
|
+
|
|
15
|
+
const init = function ( spec ) {
|
|
16
|
+
// Validate against (updated) schema
|
|
17
|
+
validateSpec( spec, introspect );
|
|
18
|
+
|
|
19
|
+
const state = Object.create( null );
|
|
20
|
+
// Standard input parameter health flag during update: false means healthy
|
|
21
|
+
state.inputValidationFailed = false;
|
|
22
|
+
// Ensure node is enabled by default
|
|
23
|
+
state.disable = false;
|
|
24
|
+
state.pause = false;
|
|
25
|
+
|
|
26
|
+
// Required
|
|
27
|
+
state.x = spec.from.x;
|
|
28
|
+
|
|
29
|
+
// Config copy
|
|
30
|
+
state.stats = spec.stats;
|
|
31
|
+
|
|
32
|
+
// half-life based configuration (samples)
|
|
33
|
+
// Supports both direct: { halfLife: 20 } and field-keyed: { halfLife: { temp: 5, pressure: 20 } }
|
|
34
|
+
const halfLifeSpec = resolveScalar( spec.halfLife, state.x );
|
|
35
|
+
state.halfLife = ( typeof halfLifeSpec === 'number' ) ? halfLifeSpec : introspect.DEFAULT_OPTIONS.halfLife;
|
|
36
|
+
|
|
37
|
+
// Derive base alpha from half-life for hot-path math
|
|
38
|
+
state.alpha = halfLifeToAlpha( state.halfLife );
|
|
39
|
+
state.currentAlpha = state.alpha;
|
|
40
|
+
|
|
41
|
+
// New: adaptive half-life flag (renamed)
|
|
42
|
+
state.adaptiveHalfLife = !!spec.adaptiveHalfLife;
|
|
43
|
+
|
|
44
|
+
// Exponential smoothing of |innovation| (MAD-ish); alpha derived from main half-life
|
|
45
|
+
// Using a slightly longer half-life (×1.5) to avoid flapping under noise
|
|
46
|
+
state.madAlpha = halfLifeToAlpha( state.halfLife * 1.5 );
|
|
47
|
+
state.esAbsInnovation = null;
|
|
48
|
+
|
|
49
|
+
// State
|
|
50
|
+
state.esmValue = null;
|
|
51
|
+
state.isInitialized = false;
|
|
52
|
+
state.lastValue = null;
|
|
53
|
+
|
|
54
|
+
state.nodeType = introspect.getNodeType();
|
|
55
|
+
return state;
|
|
56
|
+
}; // init()
|
|
57
|
+
|
|
58
|
+
export default init;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Single source of truth for esMean node metadata.
|
|
3
|
+
*
|
|
4
|
+
* Exports supported stats, control methods, capabilities, default options,
|
|
5
|
+
* and the DSL spec schema used by both validation (init-time) and
|
|
6
|
+
* transpilation (DSL → spec). All getters return defensive copies.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { validators, composerValidators } from '../../core/utils/validate/index.js';
|
|
10
|
+
|
|
11
|
+
/** Single source of truth for what this plugin can do */
|
|
12
|
+
const SUPPORTED_STATS = [
|
|
13
|
+
'mean'
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
/** Human-readable descriptions (for introspection) */
|
|
17
|
+
const STAT_DESCRIPTIONS = {
|
|
18
|
+
mean: 'Exponentially Smoothed Mean'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Control methods available for triggers */
|
|
22
|
+
const SUPPORTED_CONTROL_METHODS = {
|
|
23
|
+
reset: 'Clears accumulated state and restarts computation',
|
|
24
|
+
enable: 'Enables node processing',
|
|
25
|
+
disable: 'Disables node processing',
|
|
26
|
+
pause: 'Pauses node processing while keeping state visible',
|
|
27
|
+
unpause: 'Resumes node processing after pause'
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** The type of this node */
|
|
31
|
+
const NODE_TYPE = 'ES Mean';
|
|
32
|
+
|
|
33
|
+
/** Node capabilities for documentation */
|
|
34
|
+
const CAPABILITIES = {
|
|
35
|
+
description: 'Computes exponentially smoothed mean for smoothing time series data',
|
|
36
|
+
features: [
|
|
37
|
+
'Half-life based smoothing (samples) for intuitive tuning',
|
|
38
|
+
'Optional adaptive half-life based on absolute innovation (robust MAD-ish estimator)',
|
|
39
|
+
'Numerically stable update form'
|
|
40
|
+
]
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Export functions for accessing metadata
|
|
44
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
45
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
46
|
+
export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
|
|
47
|
+
export const getNodeType = () => NODE_TYPE;
|
|
48
|
+
export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
|
|
49
|
+
|
|
50
|
+
// Spec default values
|
|
51
|
+
export const DEFAULT_OPTIONS = {
|
|
52
|
+
// ≈ alpha 0.2
|
|
53
|
+
halfLife: 3.1062837195053903
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// DSL Metadata for transpilation
|
|
57
|
+
const DSL_METADATA = {
|
|
58
|
+
// Spec schema for validation
|
|
59
|
+
specSchema: {
|
|
60
|
+
nodeType: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
required: true,
|
|
63
|
+
value: NODE_TYPE
|
|
64
|
+
},
|
|
65
|
+
name: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
required: true,
|
|
68
|
+
validator: validators.identifier,
|
|
69
|
+
error: 'Name must be a valid identifier'
|
|
70
|
+
},
|
|
71
|
+
from: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
required: true,
|
|
74
|
+
properties: {
|
|
75
|
+
x: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
required: true,
|
|
78
|
+
validator: validators.noSpaces,
|
|
79
|
+
error: 'Field name cannot contain spaces'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
halfLife: {
|
|
84
|
+
type: 'numberOrFieldKeyed',
|
|
85
|
+
required: false,
|
|
86
|
+
default: DEFAULT_OPTIONS.halfLife,
|
|
87
|
+
validator: composerValidators.halfLife,
|
|
88
|
+
error: 'halfLife must be > 0 and < 999999'
|
|
89
|
+
},
|
|
90
|
+
adaptiveHalfLife: {
|
|
91
|
+
type: 'boolean',
|
|
92
|
+
required: false,
|
|
93
|
+
default: false
|
|
94
|
+
},
|
|
95
|
+
stats: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
required: true,
|
|
98
|
+
propertyNames: SUPPORTED_STATS,
|
|
99
|
+
propertySchema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
required: true,
|
|
102
|
+
properties: {
|
|
103
|
+
storeAs: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
required: true,
|
|
106
|
+
minLength: 1,
|
|
107
|
+
validator: validators.identifier,
|
|
108
|
+
error: 'storeAs must be a valid identifier'
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// Cross-field validators
|
|
116
|
+
crossFieldValidators: [],
|
|
117
|
+
|
|
118
|
+
// How to build the spec from DSL params
|
|
119
|
+
buildSpec: ( name, x, stats, options ) => ( {
|
|
120
|
+
nodeType: NODE_TYPE,
|
|
121
|
+
name,
|
|
122
|
+
from: { x },
|
|
123
|
+
stats,
|
|
124
|
+
...options
|
|
125
|
+
} ),
|
|
126
|
+
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export const getDSLMetadata = () => ( { ...DSL_METADATA } );
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Copies the current EWMA estimate onto the message for
|
|
3
|
+
* downstream consumption. Propagates NaN when input validation has failed,
|
|
4
|
+
* ensuring downstream nodes see an explicit fault rather than stale data.
|
|
5
|
+
*/
|
|
6
|
+
import { publishNaN } from '../../core/utils/node/index.js';
|
|
7
|
+
|
|
8
|
+
const publishTo = function ( state, msg ) {
|
|
9
|
+
if ( state.disable ) return;
|
|
10
|
+
// Propagate NaN if unhealthy
|
|
11
|
+
if ( state.inputValidationFailed ) {
|
|
12
|
+
publishNaN( state, msg );
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
msg[ state.stats.mean.storeAs ] = state.esmValue;
|
|
17
|
+
}; // publishTo()
|
|
18
|
+
|
|
19
|
+
export default publishTo;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Recompute handler for the esMean node (intentional no-op).
|
|
3
|
+
*
|
|
4
|
+
* EWMA cannot be recomputed without the full observation history. The
|
|
5
|
+
* incremental update form is already numerically stable and bounded by
|
|
6
|
+
* the input range, so precision drift is not a concern.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const recompute = function () {
|
|
10
|
+
// It cannot be recomputed without full historical data.
|
|
11
|
+
// The incremental update form used is already numerically stable
|
|
12
|
+
// and bounded by input range, preventing unbounded error growth.
|
|
13
|
+
return true;
|
|
14
|
+
}; // recompute()
|
|
15
|
+
|
|
16
|
+
export default recompute;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Resets accumulated EWMA state to its pre-observation condition.
|
|
3
|
+
*
|
|
4
|
+
* Clears the estimate, initialization flag, adaptive innovation tracker, and
|
|
5
|
+
* last observed value. Restores currentAlpha to the base alpha derived at init,
|
|
6
|
+
* so the next observation seeds the estimate afresh.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const reset = function ( state ) {
|
|
10
|
+
state.esmValue = null;
|
|
11
|
+
state.isInitialized = false;
|
|
12
|
+
|
|
13
|
+
// Restore base alpha (derived from half-life at init)
|
|
14
|
+
state.currentAlpha = state.alpha;
|
|
15
|
+
|
|
16
|
+
// New adaptive state
|
|
17
|
+
state.esAbsInnovation = null;
|
|
18
|
+
|
|
19
|
+
state.lastValue = null;
|
|
20
|
+
|
|
21
|
+
return true;
|
|
22
|
+
}; // reset()
|
|
23
|
+
|
|
24
|
+
export default reset;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Hot-path EWMA computation for the esMean node.
|
|
3
|
+
*
|
|
4
|
+
* Applies the numerically stable incremental form: esmValue += α·(x − esmValue).
|
|
5
|
+
* When adaptive half-life is enabled, alpha is modulated per-message based on
|
|
6
|
+
* surprise — |innovation| relative to a MAD-estimated σ (σ ≈ 1.2533·E[|inno|],
|
|
7
|
+
* the normal-equivalence relation). A bounded boost keeps alpha within [base, 0.95],
|
|
8
|
+
* preventing degeneration to passthrough. Zero allocations; all reads from state.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Sensible fixed constants (hot path reads only)
|
|
12
|
+
const adaptGain = 0.2; // sensitivity of alpha to surprise (bounded map)
|
|
13
|
+
const epsilon = 1e-12; // numerical floor
|
|
14
|
+
|
|
15
|
+
const update = function ( state, msg ) {
|
|
16
|
+
if ( state.disable || state.pause ) return state;
|
|
17
|
+
const xVal = msg[ state.x ];
|
|
18
|
+
// Reset on each update
|
|
19
|
+
state.inputValidationFailed = false;
|
|
20
|
+
// Handle faults gracefully: ensure their isolation
|
|
21
|
+
if ( !Number.isFinite( xVal ) ) {
|
|
22
|
+
// Signals publishing NaN for all demanded `stats` in publishTo.
|
|
23
|
+
state.inputValidationFailed = true;
|
|
24
|
+
return state;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if ( state.isInitialized ) {
|
|
28
|
+
// Optional adaptive half-life
|
|
29
|
+
if ( state.adaptiveHalfLife ) {
|
|
30
|
+
// Innovation relative to current estimate
|
|
31
|
+
const innovation = xVal - state.esmValue;
|
|
32
|
+
|
|
33
|
+
// Exponential smoothing of |innovation| (MAD-ish); using precomputed alpha for hot path
|
|
34
|
+
const absInnovation = Math.abs( innovation );
|
|
35
|
+
state.esAbsInnovation = ( state.esAbsInnovation === null ) ?
|
|
36
|
+
absInnovation :
|
|
37
|
+
state.esAbsInnovation + ( state.madAlpha * ( absInnovation - state.esAbsInnovation ) );
|
|
38
|
+
|
|
39
|
+
// σ ≈ 1.2533 * E[ |innovation| ] (normal equivalence), robust & sqrt-free
|
|
40
|
+
const sigma = ( 1.2533 * state.esAbsInnovation ) + epsilon;
|
|
41
|
+
|
|
42
|
+
// Surprise (unitless)
|
|
43
|
+
const z = Math.abs( innovation ) / sigma;
|
|
44
|
+
|
|
45
|
+
// Bounded boost of alpha: base * ( 1 + gain * z / ( 1 + z ) )
|
|
46
|
+
const targetAlpha = state.alpha * ( 1 + ( adaptGain * ( z / ( 1 + z ) ) ) );
|
|
47
|
+
|
|
48
|
+
// Preserve Exponential smoothing behavior (never degenerate to passthrough)
|
|
49
|
+
state.currentAlpha = ( targetAlpha > 0.95 ) ? 0.95 : targetAlpha;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Numerically stable update
|
|
53
|
+
state.esmValue += state.currentAlpha * ( xVal - state.esmValue );
|
|
54
|
+
} else {
|
|
55
|
+
// Initialize
|
|
56
|
+
state.esmValue = xVal;
|
|
57
|
+
state.isInitialized = true;
|
|
58
|
+
|
|
59
|
+
// Initialize MAD tracker lazily when adaptive is enabled
|
|
60
|
+
if ( state.adaptiveHalfLife ) {
|
|
61
|
+
state.esAbsInnovation = 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
state.lastValue = xVal;
|
|
66
|
+
return state;
|
|
67
|
+
}; // update()
|
|
68
|
+
|
|
69
|
+
export default update;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Barrel module for the es-pairwise-correlation node. Re-exports
|
|
3
|
+
* lifecycle methods (init, update, reset, recompute, publishTo), shared control
|
|
4
|
+
* signals (disable, enable, pause, unpause), and all introspection metadata.
|
|
5
|
+
*/
|
|
6
|
+
// nodes/es-pairwise-correlation/index.js
|
|
7
|
+
|
|
8
|
+
export { default as init } from './init.js';
|
|
9
|
+
export { default as update } from './update.js';
|
|
10
|
+
export { default as reset } from './reset.js';
|
|
11
|
+
export { default as recompute } from './recompute.js';
|
|
12
|
+
export { default as publishTo } from './publish-to.js';
|
|
13
|
+
// Direct imports for common control functions
|
|
14
|
+
export { default as disable } from '../../core/utils/node/disable.js';
|
|
15
|
+
export { default as enable } from '../../core/utils/node/enable.js';
|
|
16
|
+
export { default as pause } from '../../core/utils/node/pause.js';
|
|
17
|
+
export { default as unpause } from '../../core/utils/node/unpause.js';
|
|
18
|
+
// Re-export everything from introspection.js
|
|
19
|
+
export * from './introspect.js';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Initializes es-pairwise-correlation node state from a validated spec.
|
|
3
|
+
* Derives the smoothing factor (alpha) from the configured half-life, pre-allocates
|
|
4
|
+
* all buffers (means, variances, covariances, correlations) on a prototype-free
|
|
5
|
+
* object — no allocations occur on the hot path.
|
|
6
|
+
*/
|
|
7
|
+
// nodes/es-pairwise-correlation/init.js
|
|
8
|
+
|
|
9
|
+
import { validateSpec } from '../../core/utils/node/index.js';
|
|
10
|
+
import * as introspect from './introspect.js';
|
|
11
|
+
import { halfLifeToAlpha, halfLifeToWarmupSamples } from '../../core/utils/half-life/index.js';
|
|
12
|
+
|
|
13
|
+
const fisherZCapDefault = 0.9999;
|
|
14
|
+
|
|
15
|
+
const init = function ( spec ) {
|
|
16
|
+
// Validate against updated schema (halfLife-based)
|
|
17
|
+
validateSpec( spec, introspect ); // uses specSchema from introspect.js
|
|
18
|
+
|
|
19
|
+
// Create state after validation passes
|
|
20
|
+
const state = Object.create( null );
|
|
21
|
+
// Standard input parameter health flag during update: false means healthy
|
|
22
|
+
state.inputValidationFailed = false;
|
|
23
|
+
// Ensure node is enabled by default
|
|
24
|
+
state.disable = false;
|
|
25
|
+
state.pause = false;
|
|
26
|
+
|
|
27
|
+
// ── Configuration ────────────────────────────────────────────────────────────
|
|
28
|
+
// Input variables
|
|
29
|
+
state.x = spec.from.x;
|
|
30
|
+
state.n = state.x.length;
|
|
31
|
+
state.pairCount = ( state.n * ( state.n - 1 ) ) / 2;
|
|
32
|
+
|
|
33
|
+
// For publishing
|
|
34
|
+
state.varNames = state.x.slice( 0 );
|
|
35
|
+
|
|
36
|
+
// Output mappings
|
|
37
|
+
state.stats = spec.stats; // guaranteed by validateSpec
|
|
38
|
+
|
|
39
|
+
// Half-life config (samples) → derive alpha for hot path
|
|
40
|
+
state.halfLife = spec.halfLife ?? introspect.DEFAULT_OPTIONS.halfLife;
|
|
41
|
+
state.alpha = halfLifeToAlpha( state.halfLife );
|
|
42
|
+
|
|
43
|
+
// Numerics
|
|
44
|
+
state.minVariance = spec.minVariance ?? introspect.DEFAULT_OPTIONS.minVariance;
|
|
45
|
+
|
|
46
|
+
// Warm-up: default to ~85% settled if not provided
|
|
47
|
+
state.minSamples = ( spec.minSamples === undefined ) ?
|
|
48
|
+
halfLifeToWarmupSamples( state.halfLife, 0.85 ) :
|
|
49
|
+
spec.minSamples;
|
|
50
|
+
|
|
51
|
+
// Fisher-Z toggle uses the same cap semantics as the pair node
|
|
52
|
+
state.fisherZCap = ( spec.fisherZT === true ) ? fisherZCapDefault : 1;
|
|
53
|
+
|
|
54
|
+
// ── State & preallocations (zero-alloc hot path) ─────────────────────────────
|
|
55
|
+
// Per-variable stats
|
|
56
|
+
state.means = new Float64Array( state.n );
|
|
57
|
+
state.variances = new Float64Array( state.n );
|
|
58
|
+
|
|
59
|
+
// Pairwise stats (upper triangle order)
|
|
60
|
+
state.covariances = new Float64Array( state.pairCount );
|
|
61
|
+
state.correlations = new Float64Array( state.pairCount );
|
|
62
|
+
|
|
63
|
+
// Optional Fisher-Z vector
|
|
64
|
+
if ( spec.fisherZT ) {
|
|
65
|
+
state.fisherZT = new Float64Array( state.pairCount );
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Workspaces
|
|
69
|
+
state.values = new Float64Array( state.n );
|
|
70
|
+
state.deltas = new Float64Array( state.n );
|
|
71
|
+
|
|
72
|
+
// O(1) variable index lookup
|
|
73
|
+
state.variableLookup = Object.create( null );
|
|
74
|
+
for ( let i = 0; i < state.n; i += 1 ) {
|
|
75
|
+
state.variableLookup[ state.x[ i ] ] = i;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Optional static pair names for debugging/visualization (precomputed)
|
|
79
|
+
if ( spec.stats?.pairNames ) {
|
|
80
|
+
const pairNames = new Array( state.pairCount );
|
|
81
|
+
let idx = 0;
|
|
82
|
+
for ( let i = 0; i < state.n; i += 1 ) {
|
|
83
|
+
for ( let j = i + 1; j < state.n; j += 1 ) {
|
|
84
|
+
pairNames[ idx ] = `${state.x[ i ]}-${state.x[ j ]}`;
|
|
85
|
+
idx += 1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
state.pairNames = pairNames;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Counters / identity
|
|
92
|
+
state.sampleCount = 0;
|
|
93
|
+
state.nodeType = introspect.getNodeType();
|
|
94
|
+
|
|
95
|
+
return state;
|
|
96
|
+
}; // init()
|
|
97
|
+
|
|
98
|
+
export default init;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Single source of truth for the es-pairwise-correlation node's
|
|
3
|
+
* supported stats, control methods, capabilities, default options, and DSL schema.
|
|
4
|
+
* All getters return defensive copies to prevent caller mutation.
|
|
5
|
+
*/
|
|
6
|
+
// nodes/es-pairwise-correlation/introspect.js
|
|
7
|
+
|
|
8
|
+
import { validators, composerValidators } from '../../core/utils/validate/index.js';
|
|
9
|
+
|
|
10
|
+
/** Single source of truth for what this plugin can do */
|
|
11
|
+
const SUPPORTED_STATS = [
|
|
12
|
+
'correlations', // Raw correlation coefficients vector
|
|
13
|
+
'fisherZT', // Fisher Z transformed correlations
|
|
14
|
+
'covariances', // Raw covariances vector
|
|
15
|
+
'pairNames', // Pair identifiers (e.g., "temp-pressure")
|
|
16
|
+
'varNames' // Original input variable names
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/** Human-readable descriptions (for introspection) */
|
|
20
|
+
const STAT_DESCRIPTIONS = {
|
|
21
|
+
correlations: 'Pairwise correlation coefficients (upper triangle)',
|
|
22
|
+
fisherZT: 'Fisher Z transformed correlation values',
|
|
23
|
+
covariances: 'Pairwise covariances (upper triangle)',
|
|
24
|
+
pairNames: 'Labels identifying each variable pair',
|
|
25
|
+
varNames: 'Original variable names in order'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** Control methods available for triggers */
|
|
29
|
+
const SUPPORTED_CONTROL_METHODS = {
|
|
30
|
+
reset: 'Clears accumulated state and restarts computation',
|
|
31
|
+
enable: 'Enables node processing',
|
|
32
|
+
disable: 'Disables node processing',
|
|
33
|
+
pause: 'Pauses node processing while keeping state visible',
|
|
34
|
+
unpause: 'Resumes node processing after pause'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** The type of this node */
|
|
38
|
+
const NODE_TYPE = 'ES Pairwise Correlation';
|
|
39
|
+
|
|
40
|
+
/** Node capabilities for documentation */
|
|
41
|
+
const CAPABILITIES = {
|
|
42
|
+
description: 'Computes all pairwise correlations between multiple variables using exponential smoothing',
|
|
43
|
+
features: [
|
|
44
|
+
'Single-pass correlation computation for up to 12 variables',
|
|
45
|
+
'Numerically stable exponentially smoothed (Welford-style) algorithm',
|
|
46
|
+
'Zero-allocation operation after initialization',
|
|
47
|
+
'Vector-native processing (no matrix overhead)',
|
|
48
|
+
'Cache-efficient memory layout',
|
|
49
|
+
'O(n²/2) optimal complexity for upper triangle',
|
|
50
|
+
'Fisher Z transformation support',
|
|
51
|
+
'Handles missing/invalid data gracefully',
|
|
52
|
+
'Half-life (samples) supported for intuitive tuning'
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Introspection accessors (return safe copies)
|
|
57
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
58
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
59
|
+
export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
|
|
60
|
+
export const getNodeType = () => NODE_TYPE;
|
|
61
|
+
// Deep-enough copy: clone root object and clone the features array
|
|
62
|
+
export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
|
|
63
|
+
|
|
64
|
+
/** Defaults (aligned with pair node) */
|
|
65
|
+
export const DEFAULT_OPTIONS = {
|
|
66
|
+
// halfLife roughly equivalent to alpha ≈ 0.05
|
|
67
|
+
halfLife: 13.5,
|
|
68
|
+
minVariance: 1e-12
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// DSL Metadata for transpilation
|
|
72
|
+
const DSL_METADATA = {
|
|
73
|
+
// Spec schema for validation
|
|
74
|
+
specSchema: {
|
|
75
|
+
nodeType: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
required: true,
|
|
78
|
+
value: NODE_TYPE
|
|
79
|
+
},
|
|
80
|
+
name: {
|
|
81
|
+
type: 'string',
|
|
82
|
+
required: true,
|
|
83
|
+
validator: validators.identifier,
|
|
84
|
+
error: 'Name must be a valid identifier'
|
|
85
|
+
},
|
|
86
|
+
from: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
required: true,
|
|
89
|
+
properties: {
|
|
90
|
+
x: {
|
|
91
|
+
type: 'array',
|
|
92
|
+
required: true,
|
|
93
|
+
minItems: 2,
|
|
94
|
+
maxItems: 12,
|
|
95
|
+
itemSchema: {
|
|
96
|
+
type: 'string',
|
|
97
|
+
validator: validators.noSpaces,
|
|
98
|
+
error: 'Field names cannot contain spaces'
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
halfLife: {
|
|
104
|
+
type: 'number',
|
|
105
|
+
required: false,
|
|
106
|
+
default: DEFAULT_OPTIONS.halfLife,
|
|
107
|
+
validator: composerValidators.halfLife,
|
|
108
|
+
error: 'halfLife must be > 0 and < 999999'
|
|
109
|
+
},
|
|
110
|
+
minSamples: {
|
|
111
|
+
type: 'number',
|
|
112
|
+
required: false,
|
|
113
|
+
default: 10,
|
|
114
|
+
integer: true,
|
|
115
|
+
min: 1,
|
|
116
|
+
validator: validators.positiveInteger,
|
|
117
|
+
error: 'Minimum samples must be a positive integer'
|
|
118
|
+
},
|
|
119
|
+
minVariance: {
|
|
120
|
+
type: 'number',
|
|
121
|
+
required: false,
|
|
122
|
+
default: 1e-12,
|
|
123
|
+
validator: validators.positive,
|
|
124
|
+
error: 'Minimum variance must be positive'
|
|
125
|
+
},
|
|
126
|
+
fisherZT: {
|
|
127
|
+
type: 'boolean',
|
|
128
|
+
required: false,
|
|
129
|
+
default: false
|
|
130
|
+
},
|
|
131
|
+
stats: {
|
|
132
|
+
type: 'object',
|
|
133
|
+
required: true,
|
|
134
|
+
minProperties: 1,
|
|
135
|
+
propertyNames: SUPPORTED_STATS,
|
|
136
|
+
propertySchema: {
|
|
137
|
+
type: 'object',
|
|
138
|
+
required: true,
|
|
139
|
+
properties: {
|
|
140
|
+
storeAs: {
|
|
141
|
+
type: 'string',
|
|
142
|
+
required: true,
|
|
143
|
+
minLength: 1,
|
|
144
|
+
validator: validators.identifier,
|
|
145
|
+
error: 'storeAs must be a valid identifier'
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// Cross-field validators
|
|
153
|
+
crossFieldValidators: [
|
|
154
|
+
{
|
|
155
|
+
fields: [ 'from.x' ],
|
|
156
|
+
validator: ( spec ) => {
|
|
157
|
+
const fields = spec.from.x;
|
|
158
|
+
const uniqueFields = new Set( fields );
|
|
159
|
+
return uniqueFields.size === fields.length;
|
|
160
|
+
},
|
|
161
|
+
error: 'Field names must be unique'
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
fields: [ 'fisherZT', 'stats.fisherZT' ],
|
|
165
|
+
validator: ( spec ) => {
|
|
166
|
+
// If fisherZT stat is requested, fisherZT must be enabled
|
|
167
|
+
if ( spec.stats && spec.stats.fisherZT ) {
|
|
168
|
+
return spec.fisherZT === true;
|
|
169
|
+
}
|
|
170
|
+
return true; // No fisherZT stat requested, so no constraint
|
|
171
|
+
},
|
|
172
|
+
error: 'stats.fisherZT requires fisherZT to be enabled'
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
|
|
176
|
+
// How to build the spec from DSL params
|
|
177
|
+
buildSpec: ( name, x, stats, options ) => ( {
|
|
178
|
+
nodeType: NODE_TYPE,
|
|
179
|
+
name,
|
|
180
|
+
from: { x },
|
|
181
|
+
stats,
|
|
182
|
+
...options
|
|
183
|
+
} ),
|
|
184
|
+
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export const getDSLMetadata = () => ( { ...DSL_METADATA } );
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Copies the current pairwise correlation estimates, covariances,
|
|
3
|
+
* Fisher Z values, and/or pair labels onto the message for downstream consumption.
|
|
4
|
+
* Propagates NaN when input validation has failed; gates output until minSamples
|
|
5
|
+
* is reached.
|
|
6
|
+
*/
|
|
7
|
+
// nodes/es-pairwise-correlation/publish-to.js
|
|
8
|
+
import { publishNaN } from '../../core/utils/node/index.js';
|
|
9
|
+
|
|
10
|
+
const publishTo = function ( state, msg ) {
|
|
11
|
+
if ( state.disable ) return;
|
|
12
|
+
// Propagate NaN if unhealthy
|
|
13
|
+
if ( state.inputValidationFailed ) {
|
|
14
|
+
publishNaN( state, msg );
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Don't publish until we have reliable estimates
|
|
18
|
+
if ( state.sampleCount < state.minSamples ) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Iterate only over configured stats
|
|
23
|
+
const stats = state.stats;
|
|
24
|
+
for ( const statName in stats ) {
|
|
25
|
+
if ( Object.prototype.hasOwnProperty.call( stats, statName ) ) {
|
|
26
|
+
msg[ stats[ statName ].storeAs ] = state[ statName ];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}; // publishTo()
|
|
30
|
+
|
|
31
|
+
export default publishTo;
|