@buley/hexgrid-3d 3.0.1 → 3.2.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 (209) hide show
  1. package/dist/HexGridEnhanced.d.ts +15 -0
  2. package/dist/HexGridEnhanced.d.ts.map +1 -0
  3. package/dist/HexGridEnhanced.js +1 -0
  4. package/dist/Snapshot.d.ts +594 -0
  5. package/dist/Snapshot.d.ts.map +1 -0
  6. package/dist/Snapshot.js +757 -0
  7. package/dist/adapters/DashAdapter.d.ts +18 -0
  8. package/dist/adapters/DashAdapter.d.ts.map +1 -0
  9. package/dist/adapters/DashAdapter.js +42 -0
  10. package/dist/adapters.d.ts +53 -0
  11. package/dist/adapters.d.ts.map +1 -0
  12. package/dist/adapters.js +14 -0
  13. package/dist/algorithms/AdvancedStatistics.d.ts +52 -0
  14. package/dist/algorithms/AdvancedStatistics.d.ts.map +1 -0
  15. package/dist/algorithms/AdvancedStatistics.js +307 -0
  16. package/dist/algorithms/BayesianStatistics.d.ts +86 -0
  17. package/dist/algorithms/BayesianStatistics.d.ts.map +1 -0
  18. package/dist/algorithms/BayesianStatistics.js +263 -0
  19. package/dist/algorithms/FlowField.d.ts +55 -0
  20. package/dist/algorithms/FlowField.d.ts.map +1 -0
  21. package/dist/algorithms/FlowField.js +80 -0
  22. package/dist/algorithms/FlowField3D.d.ts +166 -0
  23. package/dist/algorithms/FlowField3D.d.ts.map +1 -0
  24. package/dist/algorithms/FlowField3D.js +327 -0
  25. package/dist/algorithms/FluidEngineFactory.d.ts +15 -0
  26. package/dist/algorithms/FluidEngineFactory.d.ts.map +1 -0
  27. package/dist/algorithms/FluidEngineFactory.js +41 -0
  28. package/dist/algorithms/FluidSimulation.d.ts +41 -0
  29. package/dist/algorithms/FluidSimulation.d.ts.map +1 -0
  30. package/dist/algorithms/FluidSimulation.js +74 -0
  31. package/dist/algorithms/FluidSimulation3D.d.ts +137 -0
  32. package/dist/algorithms/FluidSimulation3D.d.ts.map +1 -0
  33. package/dist/algorithms/FluidSimulation3D.js +464 -0
  34. package/dist/algorithms/FluidSimulation3DGPU.d.ts +41 -0
  35. package/dist/algorithms/FluidSimulation3DGPU.d.ts.map +1 -0
  36. package/dist/algorithms/FluidSimulation3DGPU.js +328 -0
  37. package/dist/algorithms/FluidSimulationWebNN.d.ts +56 -0
  38. package/dist/algorithms/FluidSimulationWebNN.d.ts.map +1 -0
  39. package/dist/algorithms/FluidSimulationWebNN.js +84 -0
  40. package/dist/algorithms/GraphAlgorithms.d.ts +48 -0
  41. package/dist/algorithms/GraphAlgorithms.d.ts.map +1 -0
  42. package/dist/algorithms/GraphAlgorithms.js +122 -0
  43. package/dist/algorithms/OutlierDetection.d.ts +49 -0
  44. package/dist/algorithms/OutlierDetection.d.ts.map +1 -0
  45. package/dist/algorithms/OutlierDetection.js +284 -0
  46. package/dist/algorithms/ParticleSystem.d.ts +36 -0
  47. package/dist/algorithms/ParticleSystem.d.ts.map +1 -0
  48. package/dist/algorithms/ParticleSystem.js +59 -0
  49. package/dist/algorithms/ParticleSystem3D.d.ts +206 -0
  50. package/dist/algorithms/ParticleSystem3D.d.ts.map +1 -0
  51. package/dist/algorithms/ParticleSystem3D.js +371 -0
  52. package/dist/algorithms/index.d.ts +16 -0
  53. package/dist/algorithms/index.d.ts.map +1 -0
  54. package/{src/algorithms/index.ts → dist/algorithms/index.js} +0 -2
  55. package/dist/compat.d.ts +24 -0
  56. package/dist/compat.d.ts.map +1 -0
  57. package/dist/compat.js +88 -0
  58. package/dist/components/HexGrid.d.ts +5 -0
  59. package/dist/components/HexGrid.d.ts.map +1 -0
  60. package/dist/components/HexGrid.js +39 -0
  61. package/dist/components/NarrationOverlay.d.ts +16 -0
  62. package/dist/components/NarrationOverlay.d.ts.map +1 -0
  63. package/dist/components/NarrationOverlay.js +132 -0
  64. package/{src/components/index.ts → dist/components/index.d.ts} +1 -1
  65. package/dist/components/index.d.ts.map +1 -0
  66. package/dist/components/index.js +1 -0
  67. package/dist/features.d.ts +54 -0
  68. package/dist/features.d.ts.map +1 -0
  69. package/dist/features.js +74 -0
  70. package/dist/index.d.ts +12 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +17 -0
  73. package/dist/lib/narration.d.ts +12 -0
  74. package/dist/lib/narration.d.ts.map +1 -0
  75. package/dist/lib/narration.js +8 -0
  76. package/dist/lib/stats-tracker.d.ts +7 -0
  77. package/dist/lib/stats-tracker.d.ts.map +1 -0
  78. package/dist/lib/stats-tracker.js +22 -0
  79. package/dist/lib/theme-colors.d.ts +7 -0
  80. package/dist/lib/theme-colors.d.ts.map +1 -0
  81. package/dist/lib/theme-colors.js +10 -0
  82. package/dist/math/HexCoordinates.d.ts +140 -0
  83. package/dist/math/HexCoordinates.d.ts.map +1 -0
  84. package/dist/math/HexCoordinates.js +741 -0
  85. package/dist/math/Matrix4.d.ts +9 -0
  86. package/dist/math/Matrix4.d.ts.map +1 -0
  87. package/dist/math/Matrix4.js +19 -0
  88. package/dist/math/Quaternion.d.ts +11 -0
  89. package/dist/math/Quaternion.d.ts.map +1 -0
  90. package/dist/math/Quaternion.js +23 -0
  91. package/dist/math/SpatialIndex.d.ts +34 -0
  92. package/dist/math/SpatialIndex.d.ts.map +1 -0
  93. package/dist/math/SpatialIndex.js +75 -0
  94. package/dist/math/Vector3.d.ts +110 -0
  95. package/dist/math/Vector3.d.ts.map +1 -0
  96. package/dist/math/Vector3.js +426 -0
  97. package/dist/math/index.d.ts +11 -0
  98. package/dist/math/index.d.ts.map +1 -0
  99. package/{src/math/index.ts → dist/math/index.js} +0 -1
  100. package/dist/note-adapter.d.ts +44 -0
  101. package/dist/note-adapter.d.ts.map +1 -0
  102. package/dist/note-adapter.js +86 -0
  103. package/dist/ontology-adapter.d.ts +13 -0
  104. package/dist/ontology-adapter.d.ts.map +1 -0
  105. package/dist/ontology-adapter.js +65 -0
  106. package/dist/stores/index.d.ts +2 -0
  107. package/dist/stores/index.d.ts.map +1 -0
  108. package/dist/stores/uiStore.d.ts +18 -0
  109. package/dist/stores/uiStore.d.ts.map +1 -0
  110. package/dist/stores/uiStore.js +77 -0
  111. package/dist/types/index.d.ts +4 -0
  112. package/dist/types/index.d.ts.map +1 -0
  113. package/dist/types/index.js +1 -0
  114. package/dist/types.d.ts +126 -0
  115. package/dist/types.d.ts.map +1 -0
  116. package/dist/types.js +4 -0
  117. package/dist/utils/image-utils.d.ts +13 -0
  118. package/dist/utils/image-utils.d.ts.map +1 -0
  119. package/dist/utils/image-utils.js +23 -0
  120. package/dist/wasm/HexGridWasmWrapper.d.ts +131 -0
  121. package/dist/wasm/HexGridWasmWrapper.d.ts.map +1 -0
  122. package/dist/wasm/HexGridWasmWrapper.js +610 -0
  123. package/dist/wasm/index.d.ts +7 -0
  124. package/dist/wasm/index.d.ts.map +1 -0
  125. package/{src/wasm/index.ts → dist/wasm/index.js} +0 -1
  126. package/dist/webgpu/WebGPUContext.d.ts +20 -0
  127. package/dist/webgpu/WebGPUContext.d.ts.map +1 -0
  128. package/dist/webgpu/WebGPUContext.js +60 -0
  129. package/dist/webnn/WebNNContext.d.ts +38 -0
  130. package/dist/webnn/WebNNContext.d.ts.map +1 -0
  131. package/dist/webnn/WebNNContext.js +66 -0
  132. package/dist/workers/hexgrid-math.d.ts +79 -0
  133. package/dist/workers/hexgrid-math.d.ts.map +1 -0
  134. package/dist/workers/hexgrid-math.js +136 -0
  135. package/dist/workers/hexgrid-worker.worker.d.ts +35 -0
  136. package/dist/workers/hexgrid-worker.worker.d.ts.map +1 -0
  137. package/dist/workers/hexgrid-worker.worker.js +2014 -0
  138. package/package.json +20 -7
  139. package/.eslintrc.json +0 -28
  140. package/build_log.txt +0 -500
  141. package/build_src_log.txt +0 -8
  142. package/examples/basic-usage.tsx +0 -52
  143. package/public/hexgrid-worker.js +0 -2475
  144. package/rust/Cargo.toml +0 -41
  145. package/rust/src/lib.rs +0 -740
  146. package/rust/src/math.rs +0 -574
  147. package/rust/src/spatial.rs +0 -245
  148. package/rust/src/statistics.rs +0 -496
  149. package/site/.eslintrc.json +0 -3
  150. package/site/DEPLOYMENT.md +0 -196
  151. package/site/INDEX.md +0 -127
  152. package/site/QUICK_START.md +0 -86
  153. package/site/README.md +0 -85
  154. package/site/SITE_SUMMARY.md +0 -180
  155. package/site/next.config.js +0 -12
  156. package/site/package.json +0 -26
  157. package/site/src/app/docs/page.tsx +0 -272
  158. package/site/src/app/examples/page.tsx +0 -151
  159. package/site/src/app/globals.css +0 -160
  160. package/site/src/app/layout.tsx +0 -39
  161. package/site/src/app/page.tsx +0 -235
  162. package/site/tsconfig.json +0 -29
  163. package/site/vercel.json +0 -6
  164. package/src/HexGridEnhanced.ts +0 -16
  165. package/src/Snapshot.ts +0 -1607
  166. package/src/adapters/DashAdapter.ts +0 -57
  167. package/src/adapters.ts +0 -63
  168. package/src/algorithms/AdvancedStatistics.ts +0 -362
  169. package/src/algorithms/BayesianStatistics.ts +0 -348
  170. package/src/algorithms/FlowField.ts +0 -150
  171. package/src/algorithms/FlowField3D.ts +0 -573
  172. package/src/algorithms/FluidEngineFactory.ts +0 -44
  173. package/src/algorithms/FluidSimulation.ts +0 -115
  174. package/src/algorithms/FluidSimulation3D.ts +0 -664
  175. package/src/algorithms/FluidSimulation3DGPU.ts +0 -402
  176. package/src/algorithms/FluidSimulationWebNN.ts +0 -141
  177. package/src/algorithms/GraphAlgorithms.ts +0 -191
  178. package/src/algorithms/OutlierDetection.ts +0 -425
  179. package/src/algorithms/ParticleSystem.ts +0 -95
  180. package/src/algorithms/ParticleSystem3D.ts +0 -567
  181. package/src/compat.ts +0 -96
  182. package/src/components/HexGrid.tsx +0 -61
  183. package/src/components/NarrationOverlay.tsx +0 -309
  184. package/src/features.ts +0 -125
  185. package/src/index.ts +0 -30
  186. package/src/lib/narration.ts +0 -17
  187. package/src/lib/stats-tracker.ts +0 -25
  188. package/src/lib/theme-colors.ts +0 -12
  189. package/src/math/HexCoordinates.ts +0 -863
  190. package/src/math/Matrix4.ts +0 -25
  191. package/src/math/Quaternion.ts +0 -37
  192. package/src/math/SpatialIndex.ts +0 -114
  193. package/src/math/Vector3.ts +0 -540
  194. package/src/note-adapter.ts +0 -132
  195. package/src/ontology-adapter.ts +0 -84
  196. package/src/stores/uiStore.ts +0 -85
  197. package/src/types/index.ts +0 -3
  198. package/src/types/shared-utils.d.ts +0 -10
  199. package/src/types/wgsl.d.ts +0 -4
  200. package/src/types.ts +0 -164
  201. package/src/utils/image-utils.ts +0 -28
  202. package/src/wasm/HexGridWasmWrapper.ts +0 -801
  203. package/src/webgpu/WebGPUContext.ts +0 -71
  204. package/src/webgpu/shaders/fluid_sim.wgsl +0 -140
  205. package/src/webnn/WebNNContext.ts +0 -99
  206. package/src/workers/hexgrid-math.ts +0 -182
  207. package/src/workers/hexgrid-worker.worker.ts +0 -2781
  208. package/tsconfig.json +0 -26
  209. /package/{src/stores/index.ts → dist/stores/index.js} +0 -0
@@ -1,57 +0,0 @@
1
- /**
2
- * Adapter for Zero-Copy Data Sync between Dash 2.0 and HexGrid-3D.
3
- *
4
- * This adapter subscribes to a Dash "LiveQuery" which returns pointers to shared memory (SharedArrayBuffer)
5
- * or Float32Arrays. It then syncs this data directly to the HexGridWasm instance.
6
- */
7
-
8
- // Placeholder types until we link the actual Dash package
9
- interface DashQueryHandle {
10
- ptr: number;
11
- size: number;
12
- buffer: SharedArrayBuffer | ArrayBuffer;
13
- }
14
-
15
- export class DashAdapter {
16
- private dash: any; // Will be typed when we link @buley/dash
17
-
18
- constructor(dashInstance: any) {
19
- this.dash = dashInstance;
20
- }
21
-
22
- /**
23
- * Subscribe to a semantic query in Dash and sync results to HexGrid.
24
- *
25
- * @param query The vector search query
26
- * @param gridInstance The WASM instance of the HexGrid
27
- */
28
- bindSemanticSearch(query: string, particleSystem: any) {
29
- console.log('[DashAdapter] Binding semantic search:', query);
30
-
31
- // Hypothetical Zero-Copy API from Dash 2.0
32
- if (this.dash.liveQueryPtr) {
33
- this.dash.liveQueryPtr(`SELECT embedding FROM dash_vec_idx WHERE embedding MATCH '${query}'`).subscribe((handle: DashQueryHandle) => {
34
- console.log(`[DashAdapter] Received ${handle.size} bytes from Dash.`);
35
-
36
- // Assume the handle.buffer contains [pos, color, scale] interleaved or tightly packed
37
- // For this MVP, we treat it as just positions
38
- const floatView = new Float32Array(handle.buffer);
39
-
40
- // Zero-Copy Injection logic would go here
41
- // We can't strictly "inject" one buffer into 3 separate Float32Arrays unless they are contiguous in the SAB
42
- // or we create views into offsets.
43
-
44
- // Hypothetical offset logic:
45
- const count = handle.size / 4 / 7; // pos + color + scale = 3+3+1 = 7 floats
46
-
47
- // particleSystem.setSharedBuffers({
48
- // positions: floatView.subarray(0, count * 3),
49
- // colors: floatView.subarray(count * 3, count * 6),
50
- // scales: floatView.subarray(count * 6, count * 7)
51
- // });
52
- });
53
- } else {
54
- console.warn('[DashAdapter] Dash instance does not support Zero-Copy liveQueryPtr yet.');
55
- }
56
- }
57
- }
package/src/adapters.ts DELETED
@@ -1,63 +0,0 @@
1
- /**
2
- * Type-safe adapter pattern for converting domain objects to GridItems
3
- */
4
-
5
- import type { GridItem } from './types';
6
-
7
- /**
8
- * Options for adapter conversion
9
- */
10
- export interface AdapterOptions {
11
- /**
12
- * Custom velocity calculation override
13
- */
14
- velocity?: number;
15
- /**
16
- * Custom visual URL override
17
- */
18
- visualUrl?: string;
19
- /**
20
- * Additional metadata to merge
21
- */
22
- metadata?: Record<string, unknown>;
23
- }
24
-
25
- /**
26
- * Type-safe adapter for converting domain objects to GridItems
27
- */
28
- export interface ItemAdapter<T> {
29
- /**
30
- * Convert a domain object to a GridItem
31
- */
32
- toGridItem(data: T, options?: AdapterOptions): GridItem<T>;
33
- /**
34
- * Extract the original domain object from a GridItem
35
- */
36
- fromGridItem(item: GridItem<T>): T;
37
- /**
38
- * Calculate velocity for the item (optional)
39
- */
40
- calculateVelocity?(data: T): number;
41
- /**
42
- * Extract visual URL for the item (optional)
43
- */
44
- extractVisualUrl?(data: T): string | undefined;
45
- }
46
-
47
- /**
48
- * Helper to create adapters for common patterns
49
- */
50
- export function createAdapter<T>(config: {
51
- type: string;
52
- toGridItem: (data: T, options?: AdapterOptions) => GridItem<T>;
53
- fromGridItem: (item: GridItem<T>) => T;
54
- calculateVelocity?: (data: T) => number;
55
- extractVisualUrl?: (data: T) => string | undefined;
56
- }): ItemAdapter<T> {
57
- return {
58
- toGridItem: config.toGridItem,
59
- fromGridItem: config.fromGridItem,
60
- calculateVelocity: config.calculateVelocity,
61
- extractVisualUrl: config.extractVisualUrl,
62
- };
63
- }
@@ -1,362 +0,0 @@
1
- export interface TrendResult {
2
- slope: number;
3
- direction: 'increasing' | 'decreasing' | 'stable';
4
- rSquared?: number;
5
- }
6
-
7
- export function giniCoefficient(values: number[]): number {
8
- if (values.length === 0) return 0;
9
- const sorted = [...values].sort((a, b) => a - b);
10
- const total = sorted.reduce((sum, val) => sum + val, 0);
11
- if (total === 0) return 0;
12
- const n = sorted.length;
13
- let cumulative = 0;
14
- for (let i = 0; i < n; i++) {
15
- cumulative += (i + 1) * sorted[i];
16
- }
17
- return (2 * cumulative) / (n * total) - (n + 1) / n;
18
- }
19
-
20
- export function theilIndex(values: number[]): number {
21
- if (values.length === 0) return 0;
22
- const avg = values.reduce((sum, val) => sum + val, 0) / values.length;
23
- if (avg === 0) return 0;
24
- return (
25
- values.reduce((sum, val) => {
26
- const ratio = val / avg;
27
- return sum + (ratio === 0 ? 0 : ratio * Math.log(ratio));
28
- }, 0) / values.length
29
- );
30
- }
31
-
32
- export function atkinsonIndex(values: number[], epsilon: number): number {
33
- if (values.length === 0) return 0;
34
- const avg = values.reduce((sum, val) => sum + val, 0) / values.length;
35
- if (avg === 0) return 0;
36
- if (epsilon === 1) {
37
- const geomMean = Math.exp(
38
- values.reduce((sum, val) => sum + Math.log(Math.max(val, 1e-9)), 0) /
39
- values.length
40
- );
41
- return 1 - geomMean / avg;
42
- }
43
- const meanPower =
44
- values.reduce((sum, val) => sum + Math.pow(val, 1 - epsilon), 0) /
45
- values.length;
46
- const eq = Math.pow(meanPower, 1 / (1 - epsilon));
47
- return 1 - eq / avg;
48
- }
49
-
50
- export function paretoRatio(
51
- values: number[],
52
- topFraction: number
53
- ): {
54
- ratioHeld: number;
55
- paretoIndex: number;
56
- } {
57
- if (values.length === 0) return { ratioHeld: 0, paretoIndex: 0 };
58
- const sorted = [...values].sort((a, b) => b - a);
59
- const total = sorted.reduce((sum, val) => sum + val, 0);
60
- if (total === 0) return { ratioHeld: 0, paretoIndex: 0 };
61
- const topCount = Math.max(1, Math.floor(values.length * topFraction));
62
- const topSum = sorted.slice(0, topCount).reduce((sum, val) => sum + val, 0);
63
- return { ratioHeld: topSum / total, paretoIndex: topFraction };
64
- }
65
-
66
- export function zipfCoefficient(values: number[]): number {
67
- if (values.length === 0) return 0;
68
- const sorted = [...values].sort((a, b) => b - a);
69
- const total = sorted.reduce((sum, val) => sum + val, 0);
70
- if (total === 0) return 0;
71
- return sorted.reduce((sum, val, idx) => sum + val / (idx + 1), 0) / total;
72
- }
73
-
74
- export function herfindahlIndex(values: number[]): number {
75
- if (values.length === 0) return 0;
76
- const total = values.reduce((sum, val) => sum + val, 0);
77
- if (total === 0) return 0;
78
- return values.reduce((sum, val) => {
79
- const share = val / total;
80
- return sum + share * share;
81
- }, 0);
82
- }
83
-
84
- export function shannonEntropy(values: number[]): number {
85
- if (values.length === 0) return 0;
86
- const total = values.reduce((sum, val) => sum + val, 0);
87
- if (total === 0) return 0;
88
- return values.reduce((sum, val) => {
89
- const p = val / total;
90
- return p === 0 ? sum : sum - p * Math.log2(p);
91
- }, 0);
92
- }
93
-
94
- export function normalizedEntropy(values: number[]): number {
95
- if (values.length === 0) return 0;
96
- const entropy = shannonEntropy(values);
97
- const maxEntropy = Math.log2(values.length || 1);
98
- return maxEntropy === 0 ? 0 : entropy / maxEntropy;
99
- }
100
-
101
- export function renyiEntropy(values: number[], alpha: number): number {
102
- if (values.length === 0) return 0;
103
- const total = values.reduce((sum, val) => sum + val, 0);
104
- if (total === 0) return 0;
105
- const sum = values.reduce((acc, val) => {
106
- const p = val / total;
107
- return acc + Math.pow(p, alpha);
108
- }, 0);
109
- return (1 / (1 - alpha)) * Math.log2(sum || 1);
110
- }
111
-
112
- export function tsallisEntropy(values: number[], q: number): number {
113
- if (values.length === 0) return 0;
114
- const total = values.reduce((sum, val) => sum + val, 0);
115
- if (total === 0) return 0;
116
- const sum = values.reduce((acc, val) => {
117
- const p = val / total;
118
- return acc + Math.pow(p, q);
119
- }, 0);
120
- return (1 - sum) / (q - 1);
121
- }
122
-
123
- export function detectTrend(values: number[]): TrendResult {
124
- if (values.length < 2) {
125
- return { slope: 0, direction: 'stable', rSquared: 0 };
126
- }
127
- const n = values.length;
128
- const xMean = (n - 1) / 2;
129
- const yMean = values.reduce((sum, v) => sum + v, 0) / n;
130
- let num = 0;
131
- let den = 0;
132
- let ssRes = 0;
133
- let ssTot = 0;
134
-
135
- for (let i = 0; i < n; i++) {
136
- const dx = i - xMean;
137
- num += dx * (values[i] - yMean);
138
- den += dx * dx;
139
- }
140
- const slope = den === 0 ? 0 : num / den;
141
- const intercept = yMean - slope * xMean;
142
-
143
- // Calculate R-squared
144
- for (let i = 0; i < n; i++) {
145
- const predicted = slope * i + intercept;
146
- ssRes += Math.pow(values[i] - predicted, 2);
147
- ssTot += Math.pow(values[i] - yMean, 2);
148
- }
149
- const rSquared = ssTot === 0 ? 0 : 1 - ssRes / ssTot;
150
-
151
- const direction =
152
- slope > 0.1 ? 'increasing' : slope < -0.1 ? 'decreasing' : 'stable';
153
- return { slope, direction, rSquared };
154
- }
155
-
156
- export function detectChangePoints(values: number[]): number[] {
157
- if (values.length < 3) return [];
158
- const changes: number[] = [];
159
- const avg = values.reduce((sum, val) => sum + val, 0) / values.length;
160
- const variance =
161
- values.reduce((sum, val) => sum + (val - avg) ** 2, 0) / values.length;
162
- const threshold = Math.sqrt(variance) * 1.5;
163
- for (let i = 1; i < values.length; i++) {
164
- if (Math.abs(values[i] - values[i - 1]) > threshold) {
165
- changes.push(i);
166
- }
167
- }
168
- return changes;
169
- }
170
-
171
- export function movingAverage(values: number[], windowSize: number): number[] {
172
- if (values.length === 0) return [];
173
- const result: number[] = [];
174
- for (let i = 0; i < values.length; i++) {
175
- const start = Math.max(0, i - windowSize + 1);
176
- const window = values.slice(start, i + 1);
177
- const avg = window.reduce((sum, val) => sum + val, 0) / window.length;
178
- result.push(avg);
179
- }
180
- return result;
181
- }
182
-
183
- export function exponentialMovingAverage(
184
- values: number[],
185
- alpha: number
186
- ): number[] {
187
- if (values.length === 0) return [];
188
- const result: number[] = [];
189
- let current = values[0] ?? 0;
190
- result.push(current);
191
- for (let i = 1; i < values.length; i++) {
192
- current = alpha * values[i] + (1 - alpha) * current;
193
- result.push(current);
194
- }
195
- return result;
196
- }
197
-
198
- export function predictWinner(values: number[]): number {
199
- if (values.length === 0) return 0;
200
- const max = Math.max(...values);
201
- return values.indexOf(max);
202
- }
203
-
204
- export function sparkline(values: number[]): string {
205
- if (values.length === 0) return '';
206
- const min = Math.min(...values);
207
- const max = Math.max(...values);
208
- const range = max - min || 1;
209
- const ticks = '▁▂▃▄▅▆▇█';
210
- return values
211
- .map((value) => {
212
- const idx = Math.round(((value - min) / range) * (ticks.length - 1));
213
- return ticks[idx] ?? ticks[0];
214
- })
215
- .join('');
216
- }
217
-
218
- export function sparklineSvg(
219
- values: number[],
220
- width: number = 100,
221
- height: number = 20
222
- ): string {
223
- if (values.length === 0) return '';
224
- const min = Math.min(...values);
225
- const max = Math.max(...values);
226
- const range = max - min || 1;
227
- const step = width / Math.max(1, values.length - 1);
228
- return values
229
- .map((value, index) => {
230
- const x = index * step;
231
- const y = height - ((value - min) / range) * height;
232
- return `${index === 0 ? 'M' : 'L'}${x},${y}`;
233
- })
234
- .join(' ');
235
- }
236
-
237
- // KL Divergence (Kullback-Leibler)
238
- export function klDivergence(p: number[], q: number[]): number {
239
- if (p.length !== q.length || p.length === 0) return 0;
240
- return p.reduce((sum, pi, i) => {
241
- if (pi === 0) return sum;
242
- const qi = q[i] ?? 1e-10;
243
- return sum + pi * Math.log2(pi / qi);
244
- }, 0);
245
- }
246
-
247
- // JS Divergence (Jensen-Shannon)
248
- export function jsDivergence(p: number[], q: number[]): number {
249
- if (p.length !== q.length || p.length === 0) return 0;
250
- const m = p.map((pi, i) => (pi + (q[i] ?? 0)) / 2);
251
- return (klDivergence(p, m) + klDivergence(q, m)) / 2;
252
- }
253
-
254
- // Bhattacharyya Coefficient
255
- export function bhattacharyyaCoefficient(p: number[], q: number[]): number {
256
- if (p.length !== q.length || p.length === 0) return 0;
257
- return p.reduce((sum, pi, i) => {
258
- const qi = q[i] ?? 0;
259
- return sum + Math.sqrt(pi * qi);
260
- }, 0);
261
- }
262
-
263
- // Hellinger Distance
264
- export function hellingerDistance(p: number[], q: number[]): number {
265
- if (p.length !== q.length || p.length === 0) return 0;
266
- const bc = bhattacharyyaCoefficient(p, q);
267
- return Math.sqrt(1 - bc);
268
- }
269
-
270
- // Double Exponential Smoothing (Holt's method)
271
- export function doubleExponentialSmoothing(
272
- values: number[],
273
- alpha: number = 0.3,
274
- beta: number = 0.1
275
- ): number[] {
276
- if (values.length === 0) return [];
277
- const result: number[] = [];
278
- let level = values[0] ?? 0;
279
- let trend = 0;
280
-
281
- result.push(level);
282
-
283
- for (let i = 1; i < values.length; i++) {
284
- const prevLevel = level;
285
- level = alpha * values[i] + (1 - alpha) * (level + trend);
286
- trend = beta * (level - prevLevel) + (1 - beta) * trend;
287
- result.push(level + trend);
288
- }
289
-
290
- return result;
291
- }
292
-
293
- // Euler Characteristic (simplified for 2D)
294
- export function eulerCharacteristic(
295
- vertices: number,
296
- edges: number,
297
- faces: number
298
- ): number {
299
- return vertices - edges + faces;
300
- }
301
-
302
- // Estimate Betti Numbers (simplified - returns basic topological invariants)
303
- export function estimateBettiNumbers(complex: {
304
- vertices: number;
305
- edges: number;
306
- faces: number;
307
- }): { b0: number; b1: number } {
308
- const euler = eulerCharacteristic(
309
- complex.vertices,
310
- complex.edges,
311
- complex.faces
312
- );
313
- // Simplified: b0 = number of connected components (assume 1 for now)
314
- // b1 = edges - vertices + 1 (for a connected graph)
315
- const b0 = 1;
316
- const b1 = Math.max(0, complex.edges - complex.vertices + 1);
317
- return { b0, b1 };
318
- }
319
-
320
- // Compactness measure
321
- export function compactness(area: number, perimeter: number): number {
322
- if (perimeter === 0) return 0;
323
- // 4π * area / perimeter^2 (circularity measure)
324
- return (4 * Math.PI * area) / (perimeter * perimeter);
325
- }
326
-
327
- // Territory Statistics
328
- export interface TerritoryStats {
329
- totalTerritories: number;
330
- averageSize: number;
331
- largestTerritory: number;
332
- smallestTerritory: number;
333
- compactness: number;
334
- }
335
-
336
- export function computeTerritoryStats(
337
- territories: Array<{ area: number; perimeter: number }>
338
- ): TerritoryStats {
339
- if (territories.length === 0) {
340
- return {
341
- totalTerritories: 0,
342
- averageSize: 0,
343
- largestTerritory: 0,
344
- smallestTerritory: 0,
345
- compactness: 0,
346
- };
347
- }
348
-
349
- const sizes = territories.map((t) => t.area);
350
- const totalSize = sizes.reduce((sum, s) => sum + s, 0);
351
- const avgCompactness =
352
- territories.reduce((sum, t) => sum + compactness(t.area, t.perimeter), 0) /
353
- territories.length;
354
-
355
- return {
356
- totalTerritories: territories.length,
357
- averageSize: totalSize / territories.length,
358
- largestTerritory: Math.max(...sizes),
359
- smallestTerritory: Math.min(...sizes),
360
- compactness: avgCompactness,
361
- };
362
- }