@mindpeeker/negentropy 0.1.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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/dist/errors.d.ts +12 -0
  4. package/dist/errors.d.ts.map +1 -0
  5. package/dist/errors.js +11 -0
  6. package/dist/errors.js.map +1 -0
  7. package/dist/estimators/entropy.d.ts +22 -0
  8. package/dist/estimators/entropy.d.ts.map +1 -0
  9. package/dist/estimators/entropy.js +78 -0
  10. package/dist/estimators/entropy.js.map +1 -0
  11. package/dist/estimators/frequency.d.ts +18 -0
  12. package/dist/estimators/frequency.d.ts.map +1 -0
  13. package/dist/estimators/frequency.js +57 -0
  14. package/dist/estimators/frequency.js.map +1 -0
  15. package/dist/estimators/negentropy.d.ts +62 -0
  16. package/dist/estimators/negentropy.d.ts.map +1 -0
  17. package/dist/estimators/negentropy.js +104 -0
  18. package/dist/estimators/negentropy.js.map +1 -0
  19. package/dist/estimators/pipeline.d.ts +25 -0
  20. package/dist/estimators/pipeline.d.ts.map +1 -0
  21. package/dist/estimators/pipeline.js +30 -0
  22. package/dist/estimators/pipeline.js.map +1 -0
  23. package/dist/estimators/vasicek.d.ts +18 -0
  24. package/dist/estimators/vasicek.d.ts.map +1 -0
  25. package/dist/estimators/vasicek.js +57 -0
  26. package/dist/estimators/vasicek.js.map +1 -0
  27. package/dist/estimators/windowed.d.ts +27 -0
  28. package/dist/estimators/windowed.d.ts.map +1 -0
  29. package/dist/estimators/windowed.js +66 -0
  30. package/dist/estimators/windowed.js.map +1 -0
  31. package/dist/experiment/batch.d.ts +15 -0
  32. package/dist/experiment/batch.d.ts.map +1 -0
  33. package/dist/experiment/batch.js +179 -0
  34. package/dist/experiment/batch.js.map +1 -0
  35. package/dist/experiment/composite.d.ts +12 -0
  36. package/dist/experiment/composite.d.ts.map +1 -0
  37. package/dist/experiment/composite.js +26 -0
  38. package/dist/experiment/composite.js.map +1 -0
  39. package/dist/experiment/registration.d.ts +20 -0
  40. package/dist/experiment/registration.d.ts.map +1 -0
  41. package/dist/experiment/registration.js +54 -0
  42. package/dist/experiment/registration.js.map +1 -0
  43. package/dist/experiment/session.d.ts +47 -0
  44. package/dist/experiment/session.d.ts.map +1 -0
  45. package/dist/experiment/session.js +245 -0
  46. package/dist/experiment/session.js.map +1 -0
  47. package/dist/experiment/types.d.ts +68 -0
  48. package/dist/experiment/types.d.ts.map +1 -0
  49. package/dist/experiment/types.js +2 -0
  50. package/dist/experiment/types.js.map +1 -0
  51. package/dist/extract/accounting.d.ts +52 -0
  52. package/dist/extract/accounting.d.ts.map +1 -0
  53. package/dist/extract/accounting.js +130 -0
  54. package/dist/extract/accounting.js.map +1 -0
  55. package/dist/extract/condition.d.ts +23 -0
  56. package/dist/extract/condition.d.ts.map +1 -0
  57. package/dist/extract/condition.js +50 -0
  58. package/dist/extract/condition.js.map +1 -0
  59. package/dist/extract/debias.d.ts +25 -0
  60. package/dist/extract/debias.d.ts.map +1 -0
  61. package/dist/extract/debias.js +80 -0
  62. package/dist/extract/debias.js.map +1 -0
  63. package/dist/extract/health.d.ts +44 -0
  64. package/dist/extract/health.d.ts.map +1 -0
  65. package/dist/extract/health.js +115 -0
  66. package/dist/extract/health.js.map +1 -0
  67. package/dist/extract/toeplitz.d.ts +19 -0
  68. package/dist/extract/toeplitz.d.ts.map +1 -0
  69. package/dist/extract/toeplitz.js +83 -0
  70. package/dist/extract/toeplitz.js.map +1 -0
  71. package/dist/index.d.ts +39 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +23 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/internal/bytes.d.ts +6 -0
  76. package/dist/internal/bytes.d.ts.map +1 -0
  77. package/dist/internal/bytes.js +36 -0
  78. package/dist/internal/bytes.js.map +1 -0
  79. package/dist/internal/kahan.d.ts +7 -0
  80. package/dist/internal/kahan.d.ts.map +1 -0
  81. package/dist/internal/kahan.js +15 -0
  82. package/dist/internal/kahan.js.map +1 -0
  83. package/dist/internal/prng.d.ts +7 -0
  84. package/dist/internal/prng.d.ts.map +1 -0
  85. package/dist/internal/prng.js +16 -0
  86. package/dist/internal/prng.js.map +1 -0
  87. package/dist/internal/special.d.ts +36 -0
  88. package/dist/internal/special.d.ts.map +1 -0
  89. package/dist/internal/special.js +258 -0
  90. package/dist/internal/special.js.map +1 -0
  91. package/dist/internal/welford.d.ts +13 -0
  92. package/dist/internal/welford.d.ts.map +1 -0
  93. package/dist/internal/welford.js +30 -0
  94. package/dist/internal/welford.js.map +1 -0
  95. package/dist/numerics.d.ts +32 -0
  96. package/dist/numerics.d.ts.map +1 -0
  97. package/dist/numerics.js +32 -0
  98. package/dist/numerics.js.map +1 -0
  99. package/dist/stats/calibration.d.ts +14 -0
  100. package/dist/stats/calibration.d.ts.map +1 -0
  101. package/dist/stats/calibration.js +41 -0
  102. package/dist/stats/calibration.js.map +1 -0
  103. package/dist/stats/cumdev.d.ts +15 -0
  104. package/dist/stats/cumdev.d.ts.map +1 -0
  105. package/dist/stats/cumdev.js +38 -0
  106. package/dist/stats/cumdev.js.map +1 -0
  107. package/dist/stats/network.d.ts +29 -0
  108. package/dist/stats/network.d.ts.map +1 -0
  109. package/dist/stats/network.js +119 -0
  110. package/dist/stats/network.js.map +1 -0
  111. package/dist/stats/pvalues.d.ts +11 -0
  112. package/dist/stats/pvalues.d.ts.map +1 -0
  113. package/dist/stats/pvalues.js +18 -0
  114. package/dist/stats/pvalues.js.map +1 -0
  115. package/dist/stats/trials.d.ts +34 -0
  116. package/dist/stats/trials.d.ts.map +1 -0
  117. package/dist/stats/trials.js +149 -0
  118. package/dist/stats/trials.js.map +1 -0
  119. package/dist/stats/zscores.d.ts +10 -0
  120. package/dist/stats/zscores.d.ts.map +1 -0
  121. package/dist/stats/zscores.js +26 -0
  122. package/dist/stats/zscores.js.map +1 -0
  123. package/dist/types.d.ts +61 -0
  124. package/dist/types.d.ts.map +1 -0
  125. package/dist/types.js +2 -0
  126. package/dist/types.js.map +1 -0
  127. package/package.json +46 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mindpeeker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # @mindpeeker/negentropy
2
+
3
+ Measure order in noise, and manufacture order from noise.
4
+
5
+ Companion to [`@mindpeeker/entropy`](../entropy): where entropy *sources*
6
+ randomness, negentropy asks two questions about it —
7
+
8
+ 1. **Is there any order in this noise, and when did it appear?**
9
+ GCP-style network statistics, information-theoretic negentropy estimators,
10
+ and a pre-registered experiment layer over live entropy streams.
11
+ 2. **How do I concentrate raw noise into uniform bits?**
12
+ Von Neumann/Peres debiasing, SP 800-90B vetted conditioning,
13
+ Toeplitz-hashing extraction, and honest min-entropy accounting.
14
+
15
+ Zero dependencies, browser-safe (only `Math`, typed arrays,
16
+ `crypto.subtle`), ESM. Every `@mindpeeker/entropy` provider works as an
17
+ input source *structurally* — the packages share a shape, not code:
18
+
19
+ ```ts
20
+ interface TrialSource {
21
+ readonly name: string
22
+ stream(opts?: { signal?: AbortSignal; chunkBytes?: number }): AsyncIterable<Uint8Array>
23
+ }
24
+ ```
25
+
26
+ > Erwin Schrödinger described life as feeding on "negative entropy";
27
+ > Léon Brillouin shortened it to *negentropy*. Here it is a number: how far
28
+ > a stream sits from maximal disorder, and how much usable order you can
29
+ > pull back out of it.
30
+
31
+ ## Detection: is there order in this noise?
32
+
33
+ The unit of analysis is the **trial** — the number of one-bits among
34
+ `bitsPerTrial` consecutive bits (default 200, the Global Consciousness
35
+ Project convention, so a trial is Binomial(200, ½): mean 100, variance 50).
36
+
37
+ ```ts
38
+ import {
39
+ trialsFromBytes, theoreticalCalibration, zScores,
40
+ netvar, devvar, interSourceCorrelation,
41
+ cumulativeDeviation, significanceEnvelope, stoufferZ,
42
+ } from '@mindpeeker/negentropy'
43
+
44
+ const series = trialsFromBytes(recordedBytes, 'anu')
45
+ const zs = zScores(series, theoreticalCalibration('anu'))
46
+ ```
47
+
48
+ Network statistics over step-aligned z-matrices from N sources:
49
+
50
+ | statistic | question it asks | null distribution |
51
+ |---|---|---|
52
+ | `netvar` | do the sources deviate *together*? (GCP standard) | χ²(steps) |
53
+ | `devvar` | is any source's variance off on its own? | χ²(steps × N) |
54
+ | `interSourceCorrelation` | are pairwise products elevated? | N(0, 1) |
55
+
56
+ `cumulativeDeviation(stoufferZs)` gives the classic cumsum(Z²−1) plot and
57
+ `significanceEnvelope(steps, p)` its exact χ²-quantile envelope. **The
58
+ envelope is pointwise**: an H0 path crosses it *somewhere* far more often
59
+ than p — only a pre-registered endpoint carries the stated significance.
60
+ (There is a test in this repo that proves that caveat by simulation.)
61
+
62
+ ### Negentropy estimators
63
+
64
+ J(x) = H(gaussian of equal variance) − H(x) ≥ 0, zero iff Gaussian —
65
+ "how far from maximally random":
66
+
67
+ - `negentropyKurtosis` — classic moment approximation (skew²/12 + exkurt²/48)
68
+ - `negentropyLogcosh`, `negentropyExp` — Hyvärinen contrasts with honestly
69
+ calibrated null z-scores (the delta-method variance under empirical
70
+ standardization, ~34× smaller than the naive Var[G] for logcosh; constants
71
+ frozen from mpmath). Positive z ⇒ sub-Gaussian, negative ⇒ super-Gaussian.
72
+ - `vasicekEntropy` / `negentropyVasicek` — m-spacings differential entropy,
73
+ validated against `scipy.stats.differential_entropy`
74
+ - `windowedNegentropy` — rolling "when did order appear?" stream whose
75
+ emissions exactly equal the batch estimator per slice
76
+
77
+ Lattice-valued data (bytes, trial sums) needs dithering first:
78
+ `ditheredTrialZ` (trials → continuous z) or `probitBytes`
79
+ (bytes → *exactly* standard normal under H0).
80
+
81
+ ### Experiment layer
82
+
83
+ ```ts
84
+ import { registerExperiment, session } from '@mindpeeker/negentropy'
85
+ import { drand, nistBeacon, cryptoProvider } from '@mindpeeker/entropy'
86
+
87
+ const registration = await registerExperiment({
88
+ trial: { clock: { mode: 'interval', intervalMs: 1000 } },
89
+ calibration: { trials: 600 }, // burn-in window, disjoint by construction
90
+ events: [{
91
+ id: 'meditation-1', label: 'group session 19:00–19:20',
92
+ statistic: 'netvar',
93
+ start: new Date('2026-07-08T19:00:00Z'), end: new Date('2026-07-08T19:20:00Z'),
94
+ }],
95
+ })
96
+
97
+ const live = session({
98
+ sources: [drand(), nistBeacon(), cryptoProvider()],
99
+ registration,
100
+ })
101
+ for await (const tick of live) {
102
+ render(tick.stouffer, tick.netvar, tick.cumdev, tick.activeEvents)
103
+ }
104
+ const result = live.stop() // batch-exact analysis + composite + archival series
105
+ ```
106
+
107
+ Sessions run in lock-step rounds (one trial per source per tick, bounded
108
+ memory), tolerate slow/dead sources with `missing: 'skip'`, and `stop()`
109
+ delegates to `analyzeTrials` — re-analyzing `result.series` later reproduces
110
+ the result exactly. `registerExperiment` freezes the config and embeds its
111
+ SHA-256 in the result: the pre-registration paper trail.
112
+
113
+ Batch equivalents: `analyzeBytes(recordings, config)` /
114
+ `analyzeTrials(series, config)`; multi-event runs combine via the Stouffer
115
+ `composite` (with `bonferroni` for individual-event claims).
116
+
117
+ ## Extraction: manufacture order from noise
118
+
119
+ ```ts
120
+ import {
121
+ vonNeumann, peres, peresRate, // debiasing (iid bits in!)
122
+ sha256Condition, hmacCondition, conditionStream, // SP 800-90B vetted
123
+ toeplitzExtractor, toeplitzOutputBits, // seeded strong extractor
124
+ ContinuousHealth, // RCT + APT, observational or strict
125
+ claimBytes, debiasAccounted, conditionAccounted, extractAccounted,
126
+ } from '@mindpeeker/negentropy'
127
+
128
+ // honest pipeline: claims only ever shrink, every step in the trace
129
+ let x = claimBytes(rawBytes, 2 /* measured bits/byte */, 'measured')
130
+ x = debiasAccounted(x, 'peres') // full credit under the iid assumption
131
+ x = await conditionAccounted(x) // h_out = min(h_in, 0.999·256)
132
+ // or: extractAccounted(x, toeplitzExtractor(seed, n, m)) — leftover hash lemma enforced
133
+ ```
134
+
135
+ - **Peres** debiasing recycles what von Neumann discards; rate → H(p)
136
+ (exact recurrence in `peresRate`). Verified *exhaustively*: over every
137
+ input at two biases, outputs of equal length are equiprobable.
138
+ - **Toeplitz** extraction is a strong extractor — the seed may be public,
139
+ but must be uniform and independent of the input.
140
+ - **Health tests** (SP 800-90B RCT/APT) run observationally by default
141
+ (alarms, keep going — the anomaly-logger stance) or `strict` (throw —
142
+ the randomness-supplier stance).
143
+
144
+ ## What this package will not tell you
145
+
146
+ Statistical tests can only *fail* a source — passing proves nothing about
147
+ physical unpredictability (any CSPRNG passes everything). The detection
148
+ module presents GCP-style methodology as neutral statistical tooling; the
149
+ underlying mind-matter hypothesis is contested, and nothing here settles
150
+ it. What the tooling does guarantee: exact null distributions (validated
151
+ against scipy/mpmath fixtures), pre-registration discipline, and honest
152
+ p-values either way.
153
+
154
+ ## Development
155
+
156
+ ```sh
157
+ bun test # fixtures are checked in — no Python needed
158
+ uv run scripts/fixtures/generate.py # regenerate fixtures (scipy/mpmath)
159
+ cd ../entropy && bun run demo:negentropy # live session demo over real providers
160
+ ```
@@ -0,0 +1,12 @@
1
+ export type NegentropyErrorCode = 'insufficient_data' | 'calibration_required' | 'invalid_window' | 'invalid_config' | 'source_ended' | 'source_failed' | 'health_test' | 'timeout' | 'aborted';
2
+ export interface NegentropyErrorOptions {
3
+ source?: string;
4
+ cause?: unknown;
5
+ }
6
+ export declare class NegentropyError extends Error {
7
+ readonly code: NegentropyErrorCode;
8
+ readonly source?: string;
9
+ readonly cause?: unknown;
10
+ constructor(code: NegentropyErrorCode, message: string, opts?: NegentropyErrorOptions);
11
+ }
12
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAC3B,mBAAmB,GACnB,sBAAsB,GACtB,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,GACd,eAAe,GACf,aAAa,GACb,SAAS,GACT,SAAS,CAAA;AAEb,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,SAAiB,KAAK,CAAC,EAAE,OAAO,CAAA;gBAEpB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,sBAA2B;CAM1F"}
package/dist/errors.js ADDED
@@ -0,0 +1,11 @@
1
+ export class NegentropyError extends Error {
2
+ code;
3
+ source;
4
+ constructor(code, message, opts = {}) {
5
+ super(message, opts.cause !== undefined ? { cause: opts.cause } : undefined);
6
+ this.name = 'NegentropyError';
7
+ this.code = code;
8
+ this.source = opts.source;
9
+ }
10
+ }
11
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAgBA,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,IAAI,CAAqB;IACzB,MAAM,CAAS;IAGxB,YAAY,IAAyB,EAAE,OAAe,EAAE,OAA+B,EAAE;QACvF,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC5E,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAC3B,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Entropy estimators over raw bytes/bits. These can only ever FAIL a source —
3
+ * passing proves nothing about physical unpredictability (any CSPRNG passes
4
+ * everything). Meaningful on RAW source output; whitened output looks perfect
5
+ * by construction.
6
+ */
7
+ export { toBits } from '../internal/bytes.js';
8
+ /** Shannon entropy in bits per byte (upper bound on min-entropy). */
9
+ export declare function shannonEntropy(data: Uint8Array): number;
10
+ /**
11
+ * NIST SP 800-90B §6.3.1 Most Common Value min-entropy estimate (bits/byte):
12
+ * upper-bounds the most common symbol's probability at 99% confidence.
13
+ */
14
+ export declare function mcvMinEntropy(data: Uint8Array): number;
15
+ /**
16
+ * NIST SP 800-90B §6.3.3 Markov min-entropy estimate for binary sequences,
17
+ * in bits per bit: the most probable 128-step path through the first-order
18
+ * transition model bounds per-bit entropy. Catches serial dependence that
19
+ * per-symbol counting misses (e.g. …010101… scores 0 here, 1.0 on MCV).
20
+ */
21
+ export declare function markovMinEntropyPerBit(bits: Uint8Array): number;
22
+ //# sourceMappingURL=entropy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy.d.ts","sourceRoot":"","sources":["../../src/estimators/entropy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAE7C,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAUvD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAMtD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAkC/D"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Entropy estimators over raw bytes/bits. These can only ever FAIL a source —
3
+ * passing proves nothing about physical unpredictability (any CSPRNG passes
4
+ * everything). Meaningful on RAW source output; whitened output looks perfect
5
+ * by construction.
6
+ */
7
+ export { toBits } from '../internal/bytes.js';
8
+ /** Shannon entropy in bits per byte (upper bound on min-entropy). */
9
+ export function shannonEntropy(data) {
10
+ const counts = new Array(256).fill(0);
11
+ for (const byte of data)
12
+ counts[byte] = counts[byte] + 1;
13
+ let h = 0;
14
+ for (const count of counts) {
15
+ if (count === 0)
16
+ continue;
17
+ const p = count / data.length;
18
+ h -= p * Math.log2(p);
19
+ }
20
+ return h;
21
+ }
22
+ /**
23
+ * NIST SP 800-90B §6.3.1 Most Common Value min-entropy estimate (bits/byte):
24
+ * upper-bounds the most common symbol's probability at 99% confidence.
25
+ */
26
+ export function mcvMinEntropy(data) {
27
+ const counts = new Array(256).fill(0);
28
+ for (const byte of data)
29
+ counts[byte] = counts[byte] + 1;
30
+ const pHat = Math.max(...counts) / data.length;
31
+ const pUpper = Math.min(1, pHat + 2.576 * Math.sqrt((pHat * (1 - pHat)) / (data.length - 1)));
32
+ return -Math.log2(pUpper);
33
+ }
34
+ /**
35
+ * NIST SP 800-90B §6.3.3 Markov min-entropy estimate for binary sequences,
36
+ * in bits per bit: the most probable 128-step path through the first-order
37
+ * transition model bounds per-bit entropy. Catches serial dependence that
38
+ * per-symbol counting misses (e.g. …010101… scores 0 here, 1.0 on MCV).
39
+ */
40
+ export function markovMinEntropyPerBit(bits) {
41
+ const n = bits.length;
42
+ if (n < 2)
43
+ return 0;
44
+ let ones = 0;
45
+ const transitions = [
46
+ [0, 0],
47
+ [0, 0],
48
+ ];
49
+ for (let i = 0; i < n; i++) {
50
+ if (bits[i] === 1)
51
+ ones++;
52
+ if (i < n - 1) {
53
+ const row = transitions[bits[i]];
54
+ row[bits[i + 1]] = row[bits[i + 1]] + 1;
55
+ }
56
+ }
57
+ const p1 = ones / n;
58
+ const p0 = 1 - p1;
59
+ const prob = (row, next) => {
60
+ const total = row[0] + row[1];
61
+ return total === 0 ? 0 : row[next] / total;
62
+ };
63
+ const log2 = (p) => (p > 0 ? Math.log2(p) : Number.NEGATIVE_INFINITY);
64
+ // dynamic program over the most probable 128-bit path (in log space)
65
+ let l0 = log2(p0);
66
+ let l1 = log2(p1);
67
+ for (let step = 1; step < 128; step++) {
68
+ const n0 = Math.max(l0 + log2(prob(transitions[0], 0)), l1 + log2(prob(transitions[1], 0)));
69
+ const n1 = Math.max(l0 + log2(prob(transitions[0], 1)), l1 + log2(prob(transitions[1], 1)));
70
+ l0 = n0;
71
+ l1 = n1;
72
+ }
73
+ const maxLog = Math.max(l0, l1);
74
+ if (!Number.isFinite(maxLog))
75
+ return 0;
76
+ return Math.min(1, Math.max(0, -maxLog / 128));
77
+ }
78
+ //# sourceMappingURL=entropy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entropy.js","sourceRoot":"","sources":["../../src/estimators/entropy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Chi-square statistic over the byte histogram (255 degrees of freedom),
3
+ * with an exact incomplete-gamma p-value.
4
+ */
5
+ export declare function chiSquareBytes(data: Uint8Array): {
6
+ statistic: number;
7
+ pValue: number;
8
+ };
9
+ /** ent-style lag-1 serial correlation coefficient over bytes (0 is ideal). */
10
+ export declare function serialCorrelation(data: Uint8Array): number;
11
+ /** Fraction of one-bits (0.5 is ideal) plus its z-score. */
12
+ export declare function monobit(bits: Uint8Array): {
13
+ onesFraction: number;
14
+ z: number;
15
+ };
16
+ /** Wald–Wolfowitz runs test z-score over the bit sequence. */
17
+ export declare function runsTest(bits: Uint8Array): number;
18
+ //# sourceMappingURL=frequency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frequency.d.ts","sourceRoot":"","sources":["../../src/estimators/frequency.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAOtF;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAc1D;AAED,4DAA4D;AAC5D,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAK7E;AAED,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAajD"}
@@ -0,0 +1,57 @@
1
+ import { chi2Sf } from '../internal/special.js';
2
+ /**
3
+ * Chi-square statistic over the byte histogram (255 degrees of freedom),
4
+ * with an exact incomplete-gamma p-value.
5
+ */
6
+ export function chiSquareBytes(data) {
7
+ const counts = new Array(256).fill(0);
8
+ for (const byte of data)
9
+ counts[byte] = counts[byte] + 1;
10
+ const expected = data.length / 256;
11
+ let statistic = 0;
12
+ for (const count of counts)
13
+ statistic += (count - expected) ** 2 / expected;
14
+ return { statistic, pValue: chi2Sf(statistic, 255) };
15
+ }
16
+ /** ent-style lag-1 serial correlation coefficient over bytes (0 is ideal). */
17
+ export function serialCorrelation(data) {
18
+ const n = data.length;
19
+ let sum = 0;
20
+ let sumSq = 0;
21
+ let sumLag = 0;
22
+ for (let i = 0; i < n; i++) {
23
+ const value = data[i];
24
+ sum += value;
25
+ sumSq += value * value;
26
+ sumLag += value * data[(i + 1) % n];
27
+ }
28
+ const numerator = n * sumLag - sum * sum;
29
+ const denominator = n * sumSq - sum * sum;
30
+ return denominator === 0 ? 1 : numerator / denominator;
31
+ }
32
+ /** Fraction of one-bits (0.5 is ideal) plus its z-score. */
33
+ export function monobit(bits) {
34
+ let ones = 0;
35
+ for (const bit of bits)
36
+ ones += bit;
37
+ const fraction = ones / bits.length;
38
+ return { onesFraction: fraction, z: (2 * ones - bits.length) / Math.sqrt(bits.length) };
39
+ }
40
+ /** Wald–Wolfowitz runs test z-score over the bit sequence. */
41
+ export function runsTest(bits) {
42
+ const n = bits.length;
43
+ let ones = 0;
44
+ let runs = 1;
45
+ for (let i = 0; i < n; i++) {
46
+ ones += bits[i];
47
+ if (i > 0 && bits[i] !== bits[i - 1])
48
+ runs++;
49
+ }
50
+ const zeros = n - ones;
51
+ if (ones === 0 || zeros === 0)
52
+ return Number.POSITIVE_INFINITY;
53
+ const expected = (2 * ones * zeros) / n + 1;
54
+ const variance = ((expected - 1) * (expected - 2)) / (n - 1);
55
+ return variance <= 0 ? 0 : (runs - expected) / Math.sqrt(variance);
56
+ }
57
+ //# sourceMappingURL=frequency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frequency.js","sourceRoot":"","sources":["../../src/estimators/frequency.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Scalar negentropy estimators: J(x) = H(gaussian of equal variance) − H(x),
3
+ * the canonical "how far from maximally random" measure — J ≥ 0, zero iff
4
+ * Gaussian. All estimators standardize internally with POPULATION moments
5
+ * (divide by n), so inputs need no preprocessing. Outputs of one family are
6
+ * comparable with each other, not across families (proportionality constants
7
+ * are set to 1).
8
+ */
9
+ /** Null constants E[G(ν)], Var[G(ν)] for ν ~ N(0,1) — frozen from mpmath (see fixtures). */
10
+ export declare const LOGCOSH_GAUSSIAN_MEAN = 0.37456720749143796;
11
+ export declare const LOGCOSH_GAUSSIAN_VARIANCE = 0.18976744917236543;
12
+ export declare const EXP_GAUSSIAN_MEAN: number;
13
+ export declare const EXP_GAUSSIAN_VARIANCE: number;
14
+ /**
15
+ * Asymptotic variance of √n·(E[G(y)] − E[G(ν)]) under H0 with EMPIRICAL
16
+ * standardization — the constant that actually calibrates the z detector.
17
+ * Delta method: Var[G(ν) − (b/2)(ν² − 1)] with b = E[ν·G′(ν)]. For logcosh
18
+ * this is ~34× smaller than Var[G(ν)]: standardization removes G's quadratic
19
+ * component almost entirely. Frozen from mpmath (see fixtures).
20
+ */
21
+ export declare const LOGCOSH_NULL_VARIANCE = 0.0063278669911599715;
22
+ export declare const EXP_NULL_VARIANCE = 0.014850269189625764;
23
+ export interface MomentNegentropy {
24
+ /** J ≈ skew²/12 + exkurt²/48 (nats, proportional). NaN when degenerate. */
25
+ j: number;
26
+ skew: number;
27
+ /** Excess kurtosis E[y⁴] − 3. */
28
+ exkurt: number;
29
+ n: number;
30
+ /** True when the input is constant — maximally ordered but not standardizable. */
31
+ degenerate: boolean;
32
+ }
33
+ /**
34
+ * Classic moment approximation (Jones–Sibson/Comon): J ≈ (1/12)E[y³]² +
35
+ * (1/48)(E[y⁴] − 3)². The y⁴ term makes it very outlier-sensitive — prefer
36
+ * the contrast estimators for heavy-tailed data. Null level: E[J] ≈ 1/n.
37
+ */
38
+ export declare function negentropyKurtosis(x: ArrayLike<number>): MomentNegentropy;
39
+ export interface ContrastNegentropy {
40
+ /** J ≈ (E[G(y)] − E[G(ν)])² (proportional). NaN when degenerate. */
41
+ j: number;
42
+ /**
43
+ * Null-calibrated detector: √n·(E[G(y)] − E[G(ν)])/√nullVariance ~ N(0,1)
44
+ * under H0 (the delta-method variance accounts for empirical
45
+ * standardization). Sign: ln cosh u ≈ u²/2 − u⁴/12, so E[G] ≈ ½ − kurt/12
46
+ * — POSITIVE z ⇒ sub-Gaussian (uniform, bimodal), NEGATIVE ⇒ super-Gaussian
47
+ * (heavy tails/peaked); same direction for the exp contrast.
48
+ */
49
+ z: number;
50
+ meanG: number;
51
+ n: number;
52
+ degenerate: boolean;
53
+ }
54
+ /**
55
+ * Hyvärinen's log-cosh contrast (a = 1, fixed — the null constants are
56
+ * a-specific). Robust general-purpose default; see `ContrastNegentropy.z`
57
+ * for the sign convention.
58
+ */
59
+ export declare function negentropyLogcosh(x: ArrayLike<number>): ContrastNegentropy;
60
+ /** Hyvärinen's Gaussian contrast G(u) = −exp(−u²/2) — most sensitive to peaked/super-Gaussian sources. */
61
+ export declare function negentropyExp(x: ArrayLike<number>): ContrastNegentropy;
62
+ //# sourceMappingURL=negentropy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"negentropy.d.ts","sourceRoot":"","sources":["../../src/estimators/negentropy.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,4FAA4F;AAC5F,eAAO,MAAM,qBAAqB,sBAAsB,CAAA;AACxD,eAAO,MAAM,yBAAyB,sBAAsB,CAAA;AAC5D,eAAO,MAAM,iBAAiB,EAAE,MAAsB,CAAA;AACtD,eAAO,MAAM,qBAAqB,EAAE,MAA+B,CAAA;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,wBAAwB,CAAA;AAC1D,eAAO,MAAM,iBAAiB,uBAAuB,CAAA;AA8BrD,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,CAAC,EAAE,MAAM,CAAA;IACT,IAAI,EAAE,MAAM,CAAA;IACZ,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,CAAC,EAAE,MAAM,CAAA;IACT,kFAAkF;IAClF,UAAU,EAAE,OAAO,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,gBAAgB,CAsBzE;AAED,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,CAAC,EAAE,MAAM,CAAA;IACT;;;;;;OAMG;IACH,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,CAAC,EAAE,MAAM,CAAA;IACT,UAAU,EAAE,OAAO,CAAA;CACpB;AA0BD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAE1E;AAED,0GAA0G;AAC1G,wBAAgB,aAAa,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAEtE"}
@@ -0,0 +1,104 @@
1
+ import { NegentropyError } from '../errors.js';
2
+ /**
3
+ * Scalar negentropy estimators: J(x) = H(gaussian of equal variance) − H(x),
4
+ * the canonical "how far from maximally random" measure — J ≥ 0, zero iff
5
+ * Gaussian. All estimators standardize internally with POPULATION moments
6
+ * (divide by n), so inputs need no preprocessing. Outputs of one family are
7
+ * comparable with each other, not across families (proportionality constants
8
+ * are set to 1).
9
+ */
10
+ /** Null constants E[G(ν)], Var[G(ν)] for ν ~ N(0,1) — frozen from mpmath (see fixtures). */
11
+ export const LOGCOSH_GAUSSIAN_MEAN = 0.37456720749143796;
12
+ export const LOGCOSH_GAUSSIAN_VARIANCE = 0.18976744917236543;
13
+ export const EXP_GAUSSIAN_MEAN = -Math.SQRT1_2; // exact: −1/√2
14
+ export const EXP_GAUSSIAN_VARIANCE = 1 / Math.sqrt(3) - 0.5; // exact: 1/√3 − ½
15
+ /**
16
+ * Asymptotic variance of √n·(E[G(y)] − E[G(ν)]) under H0 with EMPIRICAL
17
+ * standardization — the constant that actually calibrates the z detector.
18
+ * Delta method: Var[G(ν) − (b/2)(ν² − 1)] with b = E[ν·G′(ν)]. For logcosh
19
+ * this is ~34× smaller than Var[G(ν)]: standardization removes G's quadratic
20
+ * component almost entirely. Frozen from mpmath (see fixtures).
21
+ */
22
+ export const LOGCOSH_NULL_VARIANCE = 0.0063278669911599715;
23
+ export const EXP_NULL_VARIANCE = 0.014850269189625764;
24
+ const MIN_SAMPLES = 8;
25
+ function standardize(x) {
26
+ const n = x.length;
27
+ if (n < MIN_SAMPLES) {
28
+ throw new NegentropyError('insufficient_data', `negentropy estimators need ≥ ${MIN_SAMPLES} samples, got ${n}`);
29
+ }
30
+ let sum = 0;
31
+ for (let i = 0; i < n; i++)
32
+ sum += x[i];
33
+ const mean = sum / n;
34
+ let m2 = 0;
35
+ for (let i = 0; i < n; i++)
36
+ m2 += (x[i] - mean) ** 2;
37
+ const sd = Math.sqrt(m2 / n);
38
+ if (!(sd > 0))
39
+ return null;
40
+ const y = new Float64Array(n);
41
+ for (let i = 0; i < n; i++)
42
+ y[i] = (x[i] - mean) / sd;
43
+ return { y, mean, sd };
44
+ }
45
+ /**
46
+ * Classic moment approximation (Jones–Sibson/Comon): J ≈ (1/12)E[y³]² +
47
+ * (1/48)(E[y⁴] − 3)². The y⁴ term makes it very outlier-sensitive — prefer
48
+ * the contrast estimators for heavy-tailed data. Null level: E[J] ≈ 1/n.
49
+ */
50
+ export function negentropyKurtosis(x) {
51
+ const standardized = standardize(x);
52
+ if (!standardized) {
53
+ return { j: Number.NaN, skew: Number.NaN, exkurt: Number.NaN, n: x.length, degenerate: true };
54
+ }
55
+ const { y } = standardized;
56
+ let m3 = 0;
57
+ let m4 = 0;
58
+ for (const value of y) {
59
+ const cubed = value * value * value;
60
+ m3 += cubed;
61
+ m4 += cubed * value;
62
+ }
63
+ const skew = m3 / y.length;
64
+ const exkurt = m4 / y.length - 3;
65
+ return {
66
+ j: (skew * skew) / 12 + (exkurt * exkurt) / 48,
67
+ skew,
68
+ exkurt,
69
+ n: y.length,
70
+ degenerate: false,
71
+ };
72
+ }
73
+ function contrast(x, g, gaussianMean, nullVariance) {
74
+ const standardized = standardize(x);
75
+ if (!standardized) {
76
+ return { j: Number.NaN, z: Number.NaN, meanG: Number.NaN, n: x.length, degenerate: true };
77
+ }
78
+ const { y } = standardized;
79
+ let sum = 0;
80
+ for (const value of y)
81
+ sum += g(value);
82
+ const meanG = sum / y.length;
83
+ const delta = meanG - gaussianMean;
84
+ return {
85
+ j: delta * delta,
86
+ z: (Math.sqrt(y.length) * delta) / Math.sqrt(nullVariance),
87
+ meanG,
88
+ n: y.length,
89
+ degenerate: false,
90
+ };
91
+ }
92
+ /**
93
+ * Hyvärinen's log-cosh contrast (a = 1, fixed — the null constants are
94
+ * a-specific). Robust general-purpose default; see `ContrastNegentropy.z`
95
+ * for the sign convention.
96
+ */
97
+ export function negentropyLogcosh(x) {
98
+ return contrast(x, (u) => Math.log(Math.cosh(u)), LOGCOSH_GAUSSIAN_MEAN, LOGCOSH_NULL_VARIANCE);
99
+ }
100
+ /** Hyvärinen's Gaussian contrast G(u) = −exp(−u²/2) — most sensitive to peaked/super-Gaussian sources. */
101
+ export function negentropyExp(x) {
102
+ return contrast(x, (u) => -Math.exp((-u * u) / 2), EXP_GAUSSIAN_MEAN, EXP_NULL_VARIANCE);
103
+ }
104
+ //# sourceMappingURL=negentropy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"negentropy.js","sourceRoot":"","sources":["../../src/estimators/negentropy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { Calibration, TrialSeries } from '../types.js';
2
+ /**
3
+ * Bridges from lattice-valued randomness (bytes, trial sums) to the
4
+ * continuous-sample negentropy estimators. Dither noise comes from a seeded
5
+ * internal PRNG: deterministic per seed, and never drawn from the randomness
6
+ * under test.
7
+ */
8
+ export interface DitherOptions {
9
+ seed?: number;
10
+ }
11
+ /**
12
+ * Trial sums → z-scores + uniform dither over one lattice cell. The dithered
13
+ * variable is continuous, and its differential entropy equals the discrete
14
+ * entropy of the lattice variable (in lattice-spacing log units) — which is
15
+ * what makes Vasicek meaningful on trial data. Under H0 the result is
16
+ * approximately N(0, 1 + 1/(12·k/4)) with excess kurtosis −2/k + O(1/k²).
17
+ */
18
+ export declare function ditheredTrialZ(series: TrialSeries, cal: Calibration, opts?: DitherOptions): Float64Array;
19
+ /**
20
+ * Bytes → exactly standard normal samples under H0: u = (b + U(0,1))/256 is
21
+ * uniform when bytes are, and Φ⁻¹(u) is then exactly N(0,1). The exact-null
22
+ * mode — ideal for calibrating estimators and byte-level (non-trial) analysis.
23
+ */
24
+ export declare function probitBytes(bytes: Uint8Array, opts?: DitherOptions): Float64Array;
25
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/estimators/pipeline.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE3D;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,WAAW,EAChB,IAAI,GAAE,aAAkB,GACvB,YAAY,CAKd;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,aAAkB,GAAG,YAAY,CAKrF"}