@reicek/neataptic-ts 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 (272) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +28 -0
  4. package/.github/workflows/ci.yml +41 -0
  5. package/.github/workflows/deploy-pages.yml +29 -0
  6. package/.github/workflows/manual_release_pipeline.yml +62 -0
  7. package/.github/workflows/publish.yml +85 -0
  8. package/.github/workflows/release_dispatch.yml +38 -0
  9. package/.travis.yml +5 -0
  10. package/CONTRIBUTING.md +92 -0
  11. package/LICENSE +24 -0
  12. package/ONNX_EXPORT.md +87 -0
  13. package/README.md +1173 -0
  14. package/RELEASE.md +54 -0
  15. package/dist-docs/package.json +1 -0
  16. package/dist-docs/scripts/generate-docs.d.ts +2 -0
  17. package/dist-docs/scripts/generate-docs.d.ts.map +1 -0
  18. package/dist-docs/scripts/generate-docs.js +536 -0
  19. package/dist-docs/scripts/generate-docs.js.map +1 -0
  20. package/dist-docs/scripts/render-docs-html.d.ts +2 -0
  21. package/dist-docs/scripts/render-docs-html.d.ts.map +1 -0
  22. package/dist-docs/scripts/render-docs-html.js +148 -0
  23. package/dist-docs/scripts/render-docs-html.js.map +1 -0
  24. package/docs/FOLDERS.md +14 -0
  25. package/docs/README.md +1173 -0
  26. package/docs/architecture/README.md +1391 -0
  27. package/docs/architecture/index.html +938 -0
  28. package/docs/architecture/network/README.md +1210 -0
  29. package/docs/architecture/network/index.html +908 -0
  30. package/docs/assets/ascii-maze.bundle.js +16542 -0
  31. package/docs/assets/ascii-maze.bundle.js.map +7 -0
  32. package/docs/index.html +1419 -0
  33. package/docs/methods/README.md +670 -0
  34. package/docs/methods/index.html +477 -0
  35. package/docs/multithreading/README.md +274 -0
  36. package/docs/multithreading/index.html +215 -0
  37. package/docs/multithreading/workers/README.md +23 -0
  38. package/docs/multithreading/workers/browser/README.md +39 -0
  39. package/docs/multithreading/workers/browser/index.html +70 -0
  40. package/docs/multithreading/workers/index.html +57 -0
  41. package/docs/multithreading/workers/node/README.md +33 -0
  42. package/docs/multithreading/workers/node/index.html +66 -0
  43. package/docs/neat/README.md +1284 -0
  44. package/docs/neat/index.html +906 -0
  45. package/docs/src/README.md +2659 -0
  46. package/docs/src/index.html +1579 -0
  47. package/jest.config.ts +32 -0
  48. package/package.json +99 -0
  49. package/plans/HyperMorphoNEAT.md +293 -0
  50. package/plans/ONNX_EXPORT_PLAN.md +46 -0
  51. package/scripts/generate-docs.ts +486 -0
  52. package/scripts/render-docs-html.ts +138 -0
  53. package/scripts/types.d.ts +2 -0
  54. package/src/README.md +2659 -0
  55. package/src/architecture/README.md +1391 -0
  56. package/src/architecture/activationArrayPool.ts +135 -0
  57. package/src/architecture/architect.ts +635 -0
  58. package/src/architecture/connection.ts +148 -0
  59. package/src/architecture/group.ts +406 -0
  60. package/src/architecture/layer.ts +804 -0
  61. package/src/architecture/network/README.md +1210 -0
  62. package/src/architecture/network/network.activate.ts +223 -0
  63. package/src/architecture/network/network.connect.ts +157 -0
  64. package/src/architecture/network/network.deterministic.ts +167 -0
  65. package/src/architecture/network/network.evolve.ts +426 -0
  66. package/src/architecture/network/network.gating.ts +186 -0
  67. package/src/architecture/network/network.genetic.ts +247 -0
  68. package/src/architecture/network/network.mutate.ts +624 -0
  69. package/src/architecture/network/network.onnx.ts +463 -0
  70. package/src/architecture/network/network.prune.ts +216 -0
  71. package/src/architecture/network/network.remove.ts +96 -0
  72. package/src/architecture/network/network.serialize.ts +309 -0
  73. package/src/architecture/network/network.slab.ts +262 -0
  74. package/src/architecture/network/network.standalone.ts +246 -0
  75. package/src/architecture/network/network.stats.ts +59 -0
  76. package/src/architecture/network/network.topology.ts +86 -0
  77. package/src/architecture/network/network.training.ts +1278 -0
  78. package/src/architecture/network.ts +1302 -0
  79. package/src/architecture/node.ts +1288 -0
  80. package/src/architecture/onnx.ts +3 -0
  81. package/src/config.ts +83 -0
  82. package/src/methods/README.md +670 -0
  83. package/src/methods/activation.ts +372 -0
  84. package/src/methods/connection.ts +31 -0
  85. package/src/methods/cost.ts +347 -0
  86. package/src/methods/crossover.ts +63 -0
  87. package/src/methods/gating.ts +43 -0
  88. package/src/methods/methods.ts +8 -0
  89. package/src/methods/mutation.ts +300 -0
  90. package/src/methods/rate.ts +257 -0
  91. package/src/methods/selection.ts +65 -0
  92. package/src/multithreading/README.md +274 -0
  93. package/src/multithreading/multi.ts +339 -0
  94. package/src/multithreading/workers/README.md +23 -0
  95. package/src/multithreading/workers/browser/README.md +39 -0
  96. package/src/multithreading/workers/browser/testworker.ts +99 -0
  97. package/src/multithreading/workers/node/README.md +33 -0
  98. package/src/multithreading/workers/node/testworker.ts +72 -0
  99. package/src/multithreading/workers/node/worker.ts +70 -0
  100. package/src/multithreading/workers/workers.ts +22 -0
  101. package/src/neat/README.md +1284 -0
  102. package/src/neat/neat.adaptive.ts +544 -0
  103. package/src/neat/neat.compat.ts +164 -0
  104. package/src/neat/neat.constants.ts +20 -0
  105. package/src/neat/neat.diversity.ts +217 -0
  106. package/src/neat/neat.evaluate.ts +328 -0
  107. package/src/neat/neat.evolve.ts +1026 -0
  108. package/src/neat/neat.export.ts +249 -0
  109. package/src/neat/neat.helpers.ts +235 -0
  110. package/src/neat/neat.lineage.ts +220 -0
  111. package/src/neat/neat.multiobjective.ts +260 -0
  112. package/src/neat/neat.mutation.ts +718 -0
  113. package/src/neat/neat.objectives.ts +157 -0
  114. package/src/neat/neat.pruning.ts +190 -0
  115. package/src/neat/neat.selection.ts +269 -0
  116. package/src/neat/neat.speciation.ts +460 -0
  117. package/src/neat/neat.species.ts +151 -0
  118. package/src/neat/neat.telemetry.exports.ts +469 -0
  119. package/src/neat/neat.telemetry.ts +933 -0
  120. package/src/neat/neat.types.ts +275 -0
  121. package/src/neat.ts +1042 -0
  122. package/src/neataptic.ts +10 -0
  123. package/test/architecture/activationArrayPool.capacity.test.ts +19 -0
  124. package/test/architecture/activationArrayPool.test.ts +46 -0
  125. package/test/architecture/connection.test.ts +290 -0
  126. package/test/architecture/group.test.ts +950 -0
  127. package/test/architecture/layer.test.ts +1535 -0
  128. package/test/architecture/network.pruning.test.ts +65 -0
  129. package/test/architecture/node.test.ts +1602 -0
  130. package/test/examples/asciiMaze/asciiMaze.e2e.test.ts +499 -0
  131. package/test/examples/asciiMaze/asciiMaze.ts +41 -0
  132. package/test/examples/asciiMaze/browser-entry.ts +164 -0
  133. package/test/examples/asciiMaze/browserLogger.ts +221 -0
  134. package/test/examples/asciiMaze/browserTerminalUtility.ts +48 -0
  135. package/test/examples/asciiMaze/colors.ts +119 -0
  136. package/test/examples/asciiMaze/dashboardManager.ts +968 -0
  137. package/test/examples/asciiMaze/evolutionEngine.ts +1248 -0
  138. package/test/examples/asciiMaze/fitness.ts +136 -0
  139. package/test/examples/asciiMaze/index.html +128 -0
  140. package/test/examples/asciiMaze/index.ts +26 -0
  141. package/test/examples/asciiMaze/interfaces.ts +235 -0
  142. package/test/examples/asciiMaze/mazeMovement.ts +996 -0
  143. package/test/examples/asciiMaze/mazeUtils.ts +278 -0
  144. package/test/examples/asciiMaze/mazeVision.ts +402 -0
  145. package/test/examples/asciiMaze/mazeVisualization.ts +585 -0
  146. package/test/examples/asciiMaze/mazes.ts +245 -0
  147. package/test/examples/asciiMaze/networkRefinement.ts +76 -0
  148. package/test/examples/asciiMaze/networkVisualization.ts +901 -0
  149. package/test/examples/asciiMaze/terminalUtility.ts +73 -0
  150. package/test/methods/activation.test.ts +1142 -0
  151. package/test/methods/connection.test.ts +146 -0
  152. package/test/methods/cost.test.ts +1123 -0
  153. package/test/methods/crossover.test.ts +202 -0
  154. package/test/methods/gating.test.ts +144 -0
  155. package/test/methods/mutation.test.ts +451 -0
  156. package/test/methods/optimizers.advanced.test.ts +80 -0
  157. package/test/methods/optimizers.behavior.test.ts +105 -0
  158. package/test/methods/optimizers.formula.test.ts +89 -0
  159. package/test/methods/rate.cosineWarmRestarts.test.ts +44 -0
  160. package/test/methods/rate.linearWarmupDecay.test.ts +41 -0
  161. package/test/methods/rate.reduceOnPlateau.test.ts +45 -0
  162. package/test/methods/rate.test.ts +684 -0
  163. package/test/methods/selection.test.ts +245 -0
  164. package/test/multithreading/activations.functions.test.ts +54 -0
  165. package/test/multithreading/multi.test.ts +290 -0
  166. package/test/multithreading/worker.node.process.test.ts +39 -0
  167. package/test/multithreading/workers.coverage.test.ts +36 -0
  168. package/test/multithreading/workers.dynamic.import.test.ts +8 -0
  169. package/test/neat/neat.adaptive.complexityBudget.test.ts +34 -0
  170. package/test/neat/neat.adaptive.criterion.complexity.test.ts +50 -0
  171. package/test/neat/neat.adaptive.mutation.strategy.test.ts +37 -0
  172. package/test/neat/neat.adaptive.operator.decay.test.ts +31 -0
  173. package/test/neat/neat.adaptive.phasedComplexity.test.ts +25 -0
  174. package/test/neat/neat.adaptive.pruning.test.ts +25 -0
  175. package/test/neat/neat.adaptive.targetSpecies.test.ts +43 -0
  176. package/test/neat/neat.additional.coverage.test.ts +126 -0
  177. package/test/neat/neat.advanced.enhancements.test.ts +85 -0
  178. package/test/neat/neat.advanced.test.ts +589 -0
  179. package/test/neat/neat.diversity.autocompat.test.ts +47 -0
  180. package/test/neat/neat.diversity.metrics.test.ts +21 -0
  181. package/test/neat/neat.diversity.stats.test.ts +44 -0
  182. package/test/neat/neat.enhancements.test.ts +79 -0
  183. package/test/neat/neat.entropy.ancestorAdaptive.test.ts +133 -0
  184. package/test/neat/neat.entropy.compat.csv.test.ts +108 -0
  185. package/test/neat/neat.evolution.pruning.test.ts +39 -0
  186. package/test/neat/neat.fastmode.autotune.test.ts +42 -0
  187. package/test/neat/neat.innovation.test.ts +134 -0
  188. package/test/neat/neat.lineage.antibreeding.test.ts +35 -0
  189. package/test/neat/neat.lineage.entropy.test.ts +56 -0
  190. package/test/neat/neat.lineage.inbreeding.test.ts +49 -0
  191. package/test/neat/neat.lineage.pressure.test.ts +29 -0
  192. package/test/neat/neat.multiobjective.adaptive.test.ts +57 -0
  193. package/test/neat/neat.multiobjective.dynamic.schedule.test.ts +46 -0
  194. package/test/neat/neat.multiobjective.dynamic.test.ts +31 -0
  195. package/test/neat/neat.multiobjective.fastsort.delegation.test.ts +51 -0
  196. package/test/neat/neat.multiobjective.prune.test.ts +39 -0
  197. package/test/neat/neat.multiobjective.test.ts +21 -0
  198. package/test/neat/neat.mutation.undefined.pool.test.ts +24 -0
  199. package/test/neat/neat.objective.events.test.ts +26 -0
  200. package/test/neat/neat.objective.importance.test.ts +21 -0
  201. package/test/neat/neat.objective.lifetimes.test.ts +33 -0
  202. package/test/neat/neat.offspring.allocation.test.ts +22 -0
  203. package/test/neat/neat.operator.bandit.test.ts +17 -0
  204. package/test/neat/neat.operator.phases.test.ts +38 -0
  205. package/test/neat/neat.pruneInactive.behavior.test.ts +54 -0
  206. package/test/neat/neat.reenable.adaptation.test.ts +18 -0
  207. package/test/neat/neat.rng.state.test.ts +22 -0
  208. package/test/neat/neat.spawn.add.test.ts +123 -0
  209. package/test/neat/neat.speciation.test.ts +96 -0
  210. package/test/neat/neat.species.allocation.telemetry.test.ts +26 -0
  211. package/test/neat/neat.species.history.csv.test.ts +24 -0
  212. package/test/neat/neat.telemetry.advanced.test.ts +226 -0
  213. package/test/neat/neat.telemetry.csv.lineage.test.ts +19 -0
  214. package/test/neat/neat.telemetry.parity.test.ts +42 -0
  215. package/test/neat/neat.telemetry.stream.test.ts +19 -0
  216. package/test/neat/neat.telemetry.test.ts +16 -0
  217. package/test/neat/neat.test.ts +422 -0
  218. package/test/neat/neat.utilities.test.ts +44 -0
  219. package/test/network/__suppress_console.ts +9 -0
  220. package/test/network/acyclic.topoorder.test.ts +17 -0
  221. package/test/network/checkpoint.metricshook.test.ts +36 -0
  222. package/test/network/error.handling.test.ts +581 -0
  223. package/test/network/evolution.test.ts +285 -0
  224. package/test/network/genetic.test.ts +208 -0
  225. package/test/network/learning.capability.test.ts +244 -0
  226. package/test/network/mutation.effects.test.ts +492 -0
  227. package/test/network/network.activate.test.ts +115 -0
  228. package/test/network/network.activateBatch.test.ts +30 -0
  229. package/test/network/network.deterministic.test.ts +64 -0
  230. package/test/network/network.evolve.branches.test.ts +75 -0
  231. package/test/network/network.evolve.multithread.branches.test.ts +83 -0
  232. package/test/network/network.evolve.test.ts +100 -0
  233. package/test/network/network.gating.removal.test.ts +93 -0
  234. package/test/network/network.mutate.additional.test.ts +145 -0
  235. package/test/network/network.mutate.edgecases.test.ts +101 -0
  236. package/test/network/network.mutate.test.ts +101 -0
  237. package/test/network/network.prune.earlyexit.test.ts +38 -0
  238. package/test/network/network.remove.errors.test.ts +45 -0
  239. package/test/network/network.slab.fallbacks.test.ts +22 -0
  240. package/test/network/network.stats.test.ts +45 -0
  241. package/test/network/network.training.advanced.test.ts +149 -0
  242. package/test/network/network.training.basic.test.ts +228 -0
  243. package/test/network/network.training.helpers.test.ts +183 -0
  244. package/test/network/onnx.export.test.ts +310 -0
  245. package/test/network/onnx.import.test.ts +129 -0
  246. package/test/network/pruning.topology.test.ts +282 -0
  247. package/test/network/regularization.determinism.test.ts +83 -0
  248. package/test/network/regularization.dropconnect.test.ts +17 -0
  249. package/test/network/regularization.dropconnect.validation.test.ts +18 -0
  250. package/test/network/regularization.stochasticdepth.test.ts +27 -0
  251. package/test/network/regularization.test.ts +843 -0
  252. package/test/network/regularization.weightnoise.test.ts +30 -0
  253. package/test/network/setupTests.ts +2 -0
  254. package/test/network/standalone.test.ts +332 -0
  255. package/test/network/structure.serialization.test.ts +660 -0
  256. package/test/training/training.determinism.mixed-precision.test.ts +134 -0
  257. package/test/training/training.earlystopping.test.ts +91 -0
  258. package/test/training/training.edge-cases.test.ts +91 -0
  259. package/test/training/training.extensions.test.ts +47 -0
  260. package/test/training/training.gradient.features.test.ts +110 -0
  261. package/test/training/training.gradient.refinements.test.ts +170 -0
  262. package/test/training/training.gradient.separate-bias.test.ts +41 -0
  263. package/test/training/training.optimizer.test.ts +48 -0
  264. package/test/training/training.plateau.smoothing.test.ts +58 -0
  265. package/test/training/training.smoothing.types.test.ts +174 -0
  266. package/test/training/training.train.options.coverage.test.ts +52 -0
  267. package/test/utils/console-helper.ts +76 -0
  268. package/test/utils/jest-setup.ts +60 -0
  269. package/test/utils/test-helpers.ts +175 -0
  270. package/tsconfig.docs.json +12 -0
  271. package/tsconfig.json +21 -0
  272. package/webpack.config.js +49 -0
@@ -0,0 +1,223 @@
1
+ import type Network from '../network';
2
+ import { activationArrayPool } from '../activationArrayPool';
3
+
4
+ /**
5
+ * Network activation helpers (forward pass utilities).
6
+ *
7
+ * This module provides progressively lower–overhead entry points for performing
8
+ * forward propagation through a {@link Network}. The emphasis is on:
9
+ * 1. Educative clarity – each step is documented so newcomers can follow the
10
+ * life‑cycle of a forward pass in a neural network graph.
11
+ * 2. Performance – fast paths avoid unnecessary allocation and bookkeeping when
12
+ * gradients / evolution traces are not needed.
13
+ * 3. Safety – pooled buffers are never exposed directly to the public API.
14
+ *
15
+ * Exported functions:
16
+ * - {@link noTraceActivate}: ultra‑light inference (no gradients, minimal allocation).
17
+ * - {@link activateRaw}: thin semantic alias around the canonical Network.activate path.
18
+ * - {@link activateBatch}: simple mini‑batch loop utility.
19
+ *
20
+ * Design terminology used below:
21
+ * - Topological order: a sequence of nodes such that all directed connections flow forward.
22
+ * - Slab: a contiguous typed‑array structure packing node activations for vectorized math.
23
+ * - Trace / gradient bookkeeping: auxiliary data (e.g. eligibility traces, derivative caches)
24
+ * required for training algorithms; skipped in inference‑only modes.
25
+ * - Pool: an object managing reusable arrays to reduce garbage collection pressure.
26
+ *
27
+ * @module network.activate
28
+ */
29
+
30
+ /**
31
+ * Perform a forward pass without creating or updating any training / gradient traces.
32
+ *
33
+ * This is the most allocation‑sensitive activation path. Internally it will attempt
34
+ * to leverage a compact "fast slab" routine (an optimized, vectorized broadcast over
35
+ * contiguous activation buffers) when the Network instance indicates that such a path
36
+ * is currently valid. If that attempt fails (for instance because the slab is stale
37
+ * after a structural mutation) execution gracefully falls back to a node‑by‑node loop.
38
+ *
39
+ * Algorithm outline:
40
+ * 1. (Optional) Refresh cached topological order if the network enforces acyclicity
41
+ * and a structural change marked the order as dirty.
42
+ * 2. Validate the input dimensionality.
43
+ * 3. Try the fast slab path; if it throws, continue with the standard path.
44
+ * 4. Acquire a pooled output buffer sized to the number of output neurons.
45
+ * 5. Iterate all nodes in their internal order:
46
+ * - Input nodes: directly assign provided input values.
47
+ * - Hidden nodes: compute activation via Node.noTraceActivate (no bookkeeping).
48
+ * - Output nodes: compute activation and store it (in sequence) inside the
49
+ * pooled output buffer.
50
+ * 6. Copy the pooled buffer into a fresh array (detaches user from the pool) and
51
+ * release the pooled buffer back to the pool.
52
+ *
53
+ * Complexity considerations:
54
+ * - Time: O(N + E) where N = number of nodes, E = number of inbound edges processed
55
+ * inside each Node.noTraceActivate call (not explicit here but inside the node).
56
+ * - Space: O(O) transient (O = number of outputs) due to the pooled output buffer.
57
+ *
58
+ * @param this - Bound {@link Network} instance.
59
+ * @param input - Flat numeric vector whose length must equal network.input.
60
+ * @returns Array of output neuron activations (length == network.output).
61
+ * @throws {Error} If the provided input vector length mismatches the network's input size.
62
+ * @example
63
+ * const out = net.noTraceActivate([0.1, 0.2, 0.3]);
64
+ * console.log(out); // => e.g. [0.5123, 0.0441]
65
+ * @remarks Safe for inference hot paths; not suitable when gradients / training traces are required.
66
+ */
67
+ export function noTraceActivate(this: Network, input: number[]): number[] {
68
+ /**
69
+ * Reference to the network instance cast to any so internal/private helper properties
70
+ * (underscored fields & fast path flags) can be accessed without TypeScript complaints.
71
+ */
72
+ const self = this as any;
73
+
74
+ // Step 1: Ensure that if we require an acyclic graph, our cached topological
75
+ // ordering of nodes is current. A fresh order guarantees deterministic forward propagation.
76
+ if (self._enforceAcyclic && self._topoDirty)
77
+ (this as any)._computeTopoOrder();
78
+
79
+ // Step 2: Basic validation – mismatched length typically indicates a user error.
80
+ if (!Array.isArray(input) || input.length !== this.input) {
81
+ throw new Error(
82
+ `Input size mismatch: expected ${this.input}, got ${
83
+ input ? (input as any).length : 'undefined'
84
+ }`
85
+ );
86
+ }
87
+
88
+ // Step 3: Attempt a zero‑allocation vectorized activation over a packed slab. We wrap
89
+ // the call in a try/catch to avoid penalizing typical paths with conditional prechecks.
90
+ if ((this as any)._canUseFastSlab(false)) {
91
+ try {
92
+ return (this as any)._fastSlabActivate(input);
93
+ } catch {
94
+ // Silent fallback – correctness first; performance is opportunistic here.
95
+ }
96
+ }
97
+
98
+ // Step 4: Acquire a pooled typed array (or array‑like) sized to the number of outputs.
99
+ /** Pooled buffer to collect output activations in order. */
100
+ /**
101
+ * Pooled activation output buffer sized to the number of output neurons; will be cloned
102
+ * into a plain array before returning to the caller to avoid external mutation of pooled memory.
103
+ */
104
+ const output = activationArrayPool.acquire(this.output);
105
+
106
+ // Maintain a manual write index to decouple node iteration order from output layout.
107
+ /**
108
+ * Sequential index into the pooled output buffer. Increments each time we process
109
+ * an output node so we produce a dense, zero‑gap array matching logical output order.
110
+ */
111
+ /** Sequential write index into the pooled output buffer. */
112
+ let outIndex = 0;
113
+
114
+ // Step 5: Iterate every node once. For hidden nodes we simply invoke noTraceActivate;
115
+ // its internal logic will read predecessor activations already set during earlier steps.
116
+ this.nodes.forEach((node, index) => {
117
+ // Input nodes: feed value directly from the corresponding slot in the provided input vector.
118
+ if (node.type === 'input') node.noTraceActivate(input[index]);
119
+ // Output nodes: compute their activation (which implicitly uses upstream hidden/input nodes) and store.
120
+ else if (node.type === 'output')
121
+ (output as any)[outIndex++] = node.noTraceActivate();
122
+ // Hidden nodes: just activate (value stored internally on the node itself).
123
+ else node.noTraceActivate();
124
+ });
125
+
126
+ // Step 6: Copy pooled buffer to a fresh standard array so external callers cannot mutate
127
+ // the pooled object after it's released (which would create hard‑to‑trace bugs).
128
+ /** Detached plain array containing final output activations. */
129
+ /** Final detached output activation vector. */
130
+ const result = Array.from(output as any) as number[];
131
+
132
+ // Always release pooled resources promptly to keep memory pressure low for future calls.
133
+ activationArrayPool.release(output);
134
+
135
+ return result;
136
+ }
137
+
138
+ /**
139
+ * Thin semantic alias to the network's main activation path.
140
+ *
141
+ * At present this simply forwards to {@link Network.activate}. The indirection is useful for:
142
+ * - Future differentiation between raw (immediate) activation and a mode that performs reuse /
143
+ * staged batching logic.
144
+ * - Providing a stable exported symbol for external tooling / instrumentation.
145
+ *
146
+ * @param this - Bound {@link Network} instance.
147
+ * @param input - Input vector (length == network.input).
148
+ * @param training - Whether to retain training traces / gradients (delegated downstream).
149
+ * @param maxActivationDepth - Guard against runaway recursion / cyclic activation attempts.
150
+ * @returns Implementation-defined result of Network.activate (typically an output vector).
151
+ * @example
152
+ * const y = net.activateRaw([0,1,0]);
153
+ * @remarks Keep this wrapper lightweight; heavy logic should live inside Network.activate itself.
154
+ */
155
+ export function activateRaw(
156
+ this: Network,
157
+ input: number[],
158
+ training = false,
159
+ maxActivationDepth = 1000
160
+ ): any {
161
+ /** Access internal flags / helpers (private-ish) via a loose cast. */
162
+ const self = this as any;
163
+
164
+ // If the network is not reusing activation arrays there's nothing special to do – delegate.
165
+ if (!self._reuseActivationArrays)
166
+ return (this as any).activate(input, training, maxActivationDepth);
167
+
168
+ // Even when reuse is enabled we currently still just delegate; hook point for future optimization.
169
+ return (this as any).activate(input, training, maxActivationDepth);
170
+ }
171
+
172
+ /**
173
+ * Activate the network over a mini‑batch (array) of input vectors, returning a 2‑D array of outputs.
174
+ *
175
+ * This helper simply loops, invoking {@link Network.activate} (or its bound variant) for each
176
+ * sample. It is intentionally naive: no attempt is made to fuse operations across the batch.
177
+ * For very large batch sizes or performance‑critical paths consider implementing a custom
178
+ * vectorized backend that exploits SIMD, GPU kernels, or parallel workers.
179
+ *
180
+ * Input validation occurs per row to surface the earliest mismatch with a descriptive index.
181
+ *
182
+ * @param this - Bound {@link Network} instance.
183
+ * @param inputs - Array of input vectors; each must have length == network.input.
184
+ * @param training - Whether each activation should keep training traces.
185
+ * @returns 2‑D array: outputs[i] is the activation result for inputs[i].
186
+ * @throws {Error} If inputs is not an array, or any contained vector has an incorrect length.
187
+ * @example
188
+ * const batchOut = net.activateBatch([[0,0,1],[1,0,0],[0,1,0]]);
189
+ * console.log(batchOut.length); // 3 rows
190
+ * @remarks For small batches this is perfectly adequate and clear.
191
+ */
192
+ export function activateBatch(
193
+ this: Network,
194
+ inputs: number[][],
195
+ training = false
196
+ ): number[][] {
197
+ // Global validation – ensure we can iterate as expected.
198
+ if (!Array.isArray(inputs))
199
+ throw new Error('inputs must be an array of input arrays');
200
+
201
+ /** Preallocate the output matrix at the correct height (one row per input). */
202
+ /** Output matrix (row-major) where each row corresponds to activation of one input vector. */
203
+ const out: number[][] = new Array(inputs.length);
204
+
205
+ // Iterate sequentially – early exit behavior (via throw) will surface the first invalid row.
206
+ for (let i = 0; i < inputs.length; i++) {
207
+ /** Current input vector under evaluation. */
208
+ /** Input vector at batch index i currently being processed. */
209
+ const x = inputs[i];
210
+ // Validate row dimensionality with a descriptive index for easier debugging.
211
+ if (!Array.isArray(x) || x.length !== this.input) {
212
+ throw new Error(
213
+ `Input[${i}] size mismatch: expected ${this.input}, got ${
214
+ x ? x.length : 'undefined'
215
+ }`
216
+ );
217
+ }
218
+ // Delegate to the network's activation (may perform tracing if training=true).
219
+ out[i] = (this as any).activate(x, training);
220
+ }
221
+
222
+ return out;
223
+ }
@@ -0,0 +1,157 @@
1
+ import type Network from '../network';
2
+ import Node from '../node';
3
+ import Connection from '../connection';
4
+
5
+ /**
6
+ * Network structural mutation helpers (connect / disconnect).
7
+ *
8
+ * This module centralizes the logic for adding and removing edges (connections) between
9
+ * nodes in a {@link Network}. By isolating the book‑keeping here we keep the primary
10
+ * Network class lean and ensure consistent handling of:
11
+ * - Acyclic constraints
12
+ * - Multiple low‑level connections returned by composite node operations
13
+ * - Gating & self‑connection invariants
14
+ * - Cache invalidation (topological order + packed activation slabs)
15
+ *
16
+ * Exported functions:
17
+ * - {@link connect}: Create one or more connections from a source node to a target node.
18
+ * - {@link disconnect}: Remove (at most) one direct connection from source to target.
19
+ *
20
+ * Key terminology:
21
+ * - Self‑connection: An edge where from === to (loop). Usually disallowed under acyclicity.
22
+ * - Gating: A mechanism where a third node modulates (gates) the weight / influence of a connection.
23
+ * - Slab: Packed typed‑array representation of connections for vectorized forward passes.
24
+ *
25
+ * @module network.connect
26
+ */
27
+
28
+ /**
29
+ * Create and register one (or multiple) directed connection objects between two nodes.
30
+ *
31
+ * Some node types (or future composite structures) may return several low‑level connections when
32
+ * their {@link Node.connect} is invoked (e.g., expanded recurrent templates). For that reason this
33
+ * function always treats the result as an array and appends each edge to the appropriate collection.
34
+ *
35
+ * Algorithm outline:
36
+ * 1. (Acyclic guard) If acyclicity is enforced and the source node appears after the target node in
37
+ * the network's node ordering, abort early and return an empty array (prevents back‑edge creation).
38
+ * 2. Delegate to sourceNode.connect(targetNode, weight) to build the raw Connection object(s).
39
+ * 3. For each created connection:
40
+ * a. If it's a self‑connection: either ignore (acyclic mode) or store in selfconns.
41
+ * b. Otherwise store in standard connections array.
42
+ * 4. If any connection was added, mark structural caches dirty (_topoDirty & _slabDirty) so lazy
43
+ * rebuild can occur before the next forward pass.
44
+ *
45
+ * Complexity:
46
+ * - Time: O(k) where k is the number of low‑level connections returned (typically 1).
47
+ * - Space: O(k) new Connection instances (delegated to Node.connect).
48
+ *
49
+ * Edge cases & invariants:
50
+ * - Acyclic mode silently refuses back‑edges instead of throwing (makes evolutionary search easier).
51
+ * - Self‑connections are skipped entirely when acyclicity is enforced.
52
+ * - Weight initialization policy is delegated to Node.connect if not explicitly provided.
53
+ *
54
+ * @param this - Bound {@link Network} instance.
55
+ * @param from - Source node (emits signal).
56
+ * @param to - Target node (receives signal).
57
+ * @param weight - Optional explicit initial weight value.
58
+ * @returns Array of created {@link Connection} objects (possibly empty if acyclicity rejected the edge).
59
+ * @example
60
+ * const [edge] = net.connect(nodeA, nodeB, 0.5);
61
+ * @remarks For bulk layer-to-layer wiring see higher-level utilities that iterate groups.
62
+ */
63
+ export function connect(
64
+ this: Network,
65
+ from: Node,
66
+ to: Node,
67
+ weight?: number
68
+ ): Connection[] {
69
+ // Step 1: Acyclic pre‑check – prevents cycles by disallowing edges that point "backwards" in order.
70
+ if (
71
+ (this as any)._enforceAcyclic &&
72
+ this.nodes.indexOf(from) > this.nodes.indexOf(to)
73
+ )
74
+ return [];
75
+
76
+ // Step 2: Delegate creation to the node. May return >1 low‑level connections (treat generically).
77
+ /** Array of new connection objects produced by the source node. */
78
+ const connections = from.connect(to, weight);
79
+
80
+ // Step 3: Register each new connection in the appropriate collection.
81
+ for (const c of connections) {
82
+ // c: individual low‑level connection
83
+ if (from !== to) {
84
+ // Standard edge (feed‑forward or recurrent) tracked in 'connections'.
85
+ this.connections.push(c);
86
+ } else {
87
+ // Self‑connection: only valid when acyclicity is not enforced.
88
+ if ((this as any)._enforceAcyclic) continue; // Skip silently to preserve invariant.
89
+ this.selfconns.push(c);
90
+ }
91
+ }
92
+
93
+ // Step 4: Invalidate caches if we materially changed structure (at least one edge added).
94
+ if (connections.length) {
95
+ (this as any)._topoDirty = true; // Topological ordering must be recomputed lazily.
96
+ (this as any)._slabDirty = true; // Packed connection slab requires rebuild for fast activation path.
97
+ }
98
+
99
+ return connections; // Return created edges so caller can inspect / further manipulate (e.g., gating).
100
+ }
101
+
102
+ /**
103
+ * Remove (at most) one directed connection from source 'from' to target 'to'.
104
+ *
105
+ * Only a single direct edge is removed because typical graph configurations maintain at most
106
+ * one logical connection between a given pair of nodes (excluding potential future multi‑edge
107
+ * semantics). If the target edge is gated we first call {@link Network.ungate} to maintain
108
+ * gating invariants (ensuring the gater node's internal gate list remains consistent).
109
+ *
110
+ * Algorithm outline:
111
+ * 1. Choose the correct list (selfconns vs connections) based on whether from === to.
112
+ * 2. Linear scan to find the first edge with matching endpoints.
113
+ * 3. If gated, ungate to detach gater bookkeeping.
114
+ * 4. Splice the edge out; exit loop (only one expected).
115
+ * 5. Delegate per‑node cleanup via from.disconnect(to) (clears reverse references, traces, etc.).
116
+ * 6. Mark structural caches dirty for lazy recomputation.
117
+ *
118
+ * Complexity:
119
+ * - Time: O(m) where m is length of the searched list (connections or selfconns).
120
+ * - Space: O(1) extra.
121
+ *
122
+ * Idempotence: If no such edge exists we still perform node-level disconnect and flag caches dirty –
123
+ * this conservative approach simplifies callers (they need not pre‑check existence).
124
+ *
125
+ * @param this - Bound {@link Network} instance.
126
+ * @param from - Source node.
127
+ * @param to - Target node.
128
+ * @example
129
+ * net.disconnect(nodeA, nodeB);
130
+ * @remarks For removing many edges consider higher‑level bulk utilities to avoid repeated scans.
131
+ */
132
+ export function disconnect(this: Network, from: Node, to: Node): void {
133
+ // Step 1: Select list to search: selfconns for loops, otherwise normal connections.
134
+ /** Candidate list of connections to inspect for removal. */
135
+ const list = from === to ? this.selfconns : this.connections;
136
+
137
+ // Step 2: Linear scan – lists are typically small relative to node count; acceptable trade‑off.
138
+ for (let i = 0; i < list.length; i++) {
139
+ /** Connection currently inspected. */
140
+ const c = list[i];
141
+ if (c.from === from && c.to === to) {
142
+ // Found target edge
143
+ // Step 3: If gated, maintain gating invariants by ungating before removal.
144
+ if (c.gater) this.ungate(c);
145
+ // Step 4: Remove and exit (only one expected between a pair of nodes).
146
+ list.splice(i, 1);
147
+ break;
148
+ }
149
+ }
150
+
151
+ // Step 5: Node-level cleanup (clears internal references, derivative / eligibility traces, etc.).
152
+ from.disconnect(to);
153
+
154
+ // Step 6: Structural mutation => mark caches dirty so next activation can rebuild fast-path artifacts.
155
+ (this as any)._topoDirty = true;
156
+ (this as any)._slabDirty = true;
157
+ }
@@ -0,0 +1,167 @@
1
+ import type Network from '../network';
2
+
3
+ /**
4
+ * Deterministic pseudo‑random number generation (PRNG) utilities for {@link Network}.
5
+ *
6
+ * Why this module exists:
7
+ * - Facilitates reproducible evolutionary runs / gradient training by allowing explicit seeding.
8
+ * - Centralizes RNG state management & snapshot/restore operations (useful for rollbacks or
9
+ * deterministic tests around mutation sequences).
10
+ * - Keeps the core Network class focused by extracting ancillary RNG concerns.
11
+ *
12
+ * Implementation notes:
13
+ * - Uses a small, fast 32‑bit xorshift / mix style generator (same semantics as the legacy inline version)
14
+ * combining an additive Weyl sequence step plus a few avalanche-style integer mixes.
15
+ * - Not cryptographically secure. Do not use for security / fairness sensitive applications.
16
+ * - Produces floating point numbers in [0,1) with 2^32 (~4.29e9) discrete possible mantissa states.
17
+ *
18
+ * Public surface:
19
+ * - {@link setSeed}: Initialize deterministic generator with a numeric seed.
20
+ * - {@link snapshotRNG}: Capture current training step + raw internal RNG state.
21
+ * - {@link restoreRNG}: Provide an externally saved RNG function (advanced) & clear stored state.
22
+ * - {@link getRNGState} / {@link setRNGState}: Low-level accessors for the internal 32‑bit state word.
23
+ * - {@link getRandomFn}: Retrieve the active random() function reference (primarily for tests / tooling).
24
+ *
25
+ * Design rationale:
26
+ * - Storing both a state integer (_rngState) and a function (_rand) allows hot-swapping alternative
27
+ * RNG implementations (e.g., for benchmarking or pluggable randomness strategies) without rewriting
28
+ * callsites inside Network algorithms.
29
+ *
30
+ * @module network.deterministic
31
+ */
32
+
33
+ /** Shape of an RNG snapshot object. */
34
+ export interface RNGSnapshot {
35
+ step: number | undefined;
36
+ state: number | undefined;
37
+ }
38
+
39
+ /**
40
+ * Seed the internal PRNG and install a deterministic random() implementation on the Network instance.
41
+ *
42
+ * Process:
43
+ * 1. Coerce the provided seed to an unsigned 32‑bit integer (>>> 0) for predictable wraparound behavior.
44
+ * 2. Define an inline closure that advances an internal 32‑bit state using:
45
+ * a. A Weyl increment (adding constant 0x6D2B79F5 each call) ensuring full-period traversal of
46
+ * the 32‑bit space when combined with mixing.
47
+ * b. Two rounds of xorshift / integer mixing (xor, shifts, multiplications) to decorrelate bits.
48
+ * c. Normalization to [0,1) by dividing the final 32‑bit unsigned integer by 2^32.
49
+ *
50
+ * Bit-mixing explanation (rough intuition):
51
+ * - XOR with shifted versions spreads high-order entropy to lower bits.
52
+ * - Multiplication (Math.imul) with carefully chosen odd constants introduces non-linear mixing.
53
+ * - The final right shift & xor avalanche aims to reduce sequential correlation.
54
+ *
55
+ * @param this - Bound {@link Network} instance.
56
+ * @param seed - Any finite number; only its lower 32 bits are used.
57
+ * @example
58
+ * net.setSeed(1234);
59
+ * const a = net.getRandomFn()(); // deterministic given the seed
60
+ * net.setSeed(1234);
61
+ * const b = net.getRandomFn()(); // a === b
62
+ */
63
+ export function setSeed(this: Network, seed: number): void {
64
+ // Store 32-bit unsigned state (bitwise ops in JS operate on signed 32-bit but we keep consistency via >>> 0).
65
+ (this as any)._rngState = seed >>> 0;
66
+ // Install PRNG closure referencing _rngState by name for mutation on each invocation.
67
+ (this as any)._rand = () => {
68
+ // Add Weyl constant (chosen odd constant) & coerce to uint32 wraparound.
69
+ (this as any)._rngState = ((this as any)._rngState + 0x6d2b79f5) >>> 0;
70
+ // First mix: xor with shifted self and multiply (Math.imul preserves 32-bit overflow semantics).
71
+ let r = Math.imul(
72
+ (this as any)._rngState ^ ((this as any)._rngState >>> 15),
73
+ 1 | (this as any)._rngState
74
+ );
75
+ // Second mix: avalanche style bit diffusion.
76
+ r ^= r + Math.imul(r ^ (r >>> 7), 61 | r);
77
+ // Final xor/shift; convert to unsigned, then scale to [0,1).
78
+ return ((r ^ (r >>> 14)) >>> 0) / 4294967296; // 2^32
79
+ };
80
+ }
81
+
82
+ /**
83
+ * Capture a snapshot of the RNG state together with the network's training step.
84
+ *
85
+ * Useful for implementing speculative evolutionary mutations where you may revert both the
86
+ * structural change and the randomness timeline if accepting/rejecting a candidate.
87
+ *
88
+ * @param this - Bound {@link Network} instance.
89
+ * @returns Object containing current training step & 32‑bit RNG state (both possibly undefined if unseeded).
90
+ * @example
91
+ * const snap = net.snapshotRNG();
92
+ * // ... perform operations
93
+ * net.setRNGState(snap.state!);
94
+ */
95
+ export function snapshotRNG(this: Network): RNGSnapshot {
96
+ return { step: (this as any)._trainingStep, state: (this as any)._rngState };
97
+ }
98
+
99
+ /**
100
+ * Restore a previously captured RNG function implementation (advanced usage).
101
+ *
102
+ * This does NOT rehydrate _rngState (it explicitly sets it to undefined). Intended for scenarios
103
+ * where a caller has customly serialized a full RNG closure or wants to inject a deterministic stub.
104
+ * If you only need to restore the raw state word produced by {@link snapshotRNG}, prefer
105
+ * {@link setRNGState} instead.
106
+ *
107
+ * @param this - Bound {@link Network} instance.
108
+ * @param fn - Function returning a pseudo‑random number in [0,1). Caller guarantees determinism if required.
109
+ * @example
110
+ * const original = net.getRandomFn();
111
+ * net.restoreRNG(() => 0.5); // force constant RNG for a test
112
+ * // ... test invariants ...
113
+ * net.restoreRNG(original); // restore
114
+ */
115
+ export function restoreRNG(this: Network, fn: () => number): void {
116
+ (this as any)._rand = fn;
117
+ (this as any)._rngState = undefined;
118
+ }
119
+
120
+ /**
121
+ * Get the current internal 32‑bit RNG state value.
122
+ *
123
+ * @param this - Bound {@link Network} instance.
124
+ * @returns Unsigned 32‑bit state integer or undefined if generator not yet seeded or was reset.
125
+ */
126
+ export function getRNGState(this: Network): number | undefined {
127
+ return (this as any)._rngState as number | undefined;
128
+ }
129
+
130
+ /**
131
+ * Explicitly set (override) the internal 32‑bit RNG state without changing the generator function.
132
+ *
133
+ * This is a low‑level operation; typical clients should call {@link setSeed}. Provided for advanced
134
+ * replay functionality where the same PRNG algorithm is assumed but you want to resume exactly at a
135
+ * known state word.
136
+ *
137
+ * @param this - Bound {@link Network} instance.
138
+ * @param state - Any finite number (only low 32 bits used). Ignored if not numeric.
139
+ */
140
+ export function setRNGState(this: Network, state: number): void {
141
+ if (typeof state === 'number') (this as any)._rngState = state >>> 0;
142
+ }
143
+
144
+ /**
145
+ * Retrieve the active random function reference (for testing, instrumentation, or swapping).
146
+ *
147
+ * Mutating the returned function's closure variables (if any) is not recommended; prefer using
148
+ * higher-level APIs (setSeed / restoreRNG) to manage state.
149
+ *
150
+ * @param this - Bound {@link Network} instance.
151
+ * @returns Function producing numbers in [0,1). May be undefined if never seeded (call setSeed first).
152
+ */
153
+ export function getRandomFn(this: Network): (() => number) | undefined {
154
+ return (this as any)._rand as () => number;
155
+ }
156
+
157
+ /**
158
+ * Default export bundle for convenient named imports.
159
+ */
160
+ export default {
161
+ setSeed,
162
+ snapshotRNG,
163
+ restoreRNG,
164
+ getRNGState,
165
+ setRNGState,
166
+ getRandomFn,
167
+ };