@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,285 @@
1
+ jest.setTimeout(10000);
2
+
3
+ import { Architect } from '../../src/neataptic';
4
+
5
+ describe('Async Evolution', () => {
6
+ describe('Scenario: valid dataset and reachable error', () => {
7
+ const dataset = [
8
+ { input: [0, 0], output: [0] },
9
+ { input: [0, 1], output: [1] },
10
+ { input: [1, 0], output: [1] },
11
+ { input: [1, 1], output: [0] },
12
+ ];
13
+ let net: any;
14
+ beforeEach(() => {
15
+ // Arrange
16
+ net = Architect.perceptron(2, 4, 1);
17
+ });
18
+ describe('when evolving', () => {
19
+ let result: any;
20
+ beforeEach(async () => {
21
+ // Act
22
+ result = await net.evolve(dataset, {
23
+ iterations: 2,
24
+ error: 0.5,
25
+ amount: 1,
26
+ threads: 1,
27
+ popsize: 2,
28
+ });
29
+ });
30
+ it('returns a result with error property', () => {
31
+ // Assert
32
+ expect(typeof result.error).toBe('number');
33
+ });
34
+ it('returns a result with iterations property', () => {
35
+ // Assert
36
+ expect(typeof result.iterations).toBe('number');
37
+ });
38
+ it('returns a result with time property', () => {
39
+ // Assert
40
+ expect(typeof result.time).toBe('number');
41
+ });
42
+ it('iterations is less than or equal to max', () => {
43
+ // Assert
44
+ expect(result.iterations).toBeLessThanOrEqual(2);
45
+ });
46
+ });
47
+ });
48
+
49
+ describe('Scenario: empty dataset', () => {
50
+ it('throws or rejects when dataset is empty', async () => {
51
+ // Arrange
52
+ const net = Architect.perceptron(2, 4, 1);
53
+ // Act & Assert
54
+ await expect(
55
+ net.evolve([], {
56
+ iterations: 2,
57
+ error: 0.5,
58
+ amount: 1,
59
+ threads: 1,
60
+ popsize: 2,
61
+ })
62
+ ).rejects.toThrow();
63
+ });
64
+ });
65
+
66
+ describe('Scenario: input/output size mismatch', () => {
67
+ describe('input size mismatch', () => {
68
+ it('throws or rejects when input size does not match', async () => {
69
+ // Arrange
70
+ const net = Architect.perceptron(2, 4, 1);
71
+ const dataset = [
72
+ { input: [0], output: [0] },
73
+ { input: [1], output: [1] },
74
+ ];
75
+ // Act & Assert
76
+ await expect(
77
+ net.evolve(dataset, {
78
+ iterations: 2,
79
+ error: 0.5,
80
+ amount: 1,
81
+ threads: 1,
82
+ popsize: 2,
83
+ })
84
+ ).rejects.toThrow();
85
+ });
86
+ });
87
+ describe('output size mismatch', () => {
88
+ it('throws or rejects when output size does not match', async () => {
89
+ // Arrange
90
+ const net = Architect.perceptron(2, 4, 1);
91
+ const dataset = [
92
+ { input: [0, 1], output: [0, 1] },
93
+ { input: [1, 0], output: [1, 0] },
94
+ ];
95
+ // Act & Assert
96
+ await expect(
97
+ net.evolve(dataset, {
98
+ iterations: 2,
99
+ error: 0.5,
100
+ amount: 1,
101
+ threads: 1,
102
+ popsize: 2,
103
+ })
104
+ ).rejects.toThrow();
105
+ });
106
+ });
107
+ });
108
+
109
+ describe('Scenario: missing stopping conditions', () => {
110
+ it('throws or rejects if neither iterations nor error is specified', async () => {
111
+ // Arrange
112
+ const net = Architect.perceptron(2, 4, 1);
113
+ const dataset = [
114
+ { input: [0, 0], output: [0] },
115
+ { input: [0, 1], output: [1] },
116
+ ];
117
+ // Act & Assert
118
+ await expect(net.evolve(dataset, {})).rejects.toThrow();
119
+ });
120
+ });
121
+
122
+ describe('Scenario: only error stopping condition', () => {
123
+ const dataset = [
124
+ { input: [0, 0], output: [0] },
125
+ { input: [0, 1], output: [1] },
126
+ { input: [1, 0], output: [1] },
127
+ { input: [1, 1], output: [0] },
128
+ ];
129
+ let net: any;
130
+ beforeEach(() => {
131
+ // Arrange
132
+ net = Architect.perceptron(2, 4, 1);
133
+ });
134
+ describe('when evolving with only error specified', () => {
135
+ let result: any;
136
+ beforeEach(async () => {
137
+ // Act
138
+ result = await net.evolve(dataset, {
139
+ error: 0.5,
140
+ amount: 1,
141
+ threads: 1,
142
+ popsize: 2,
143
+ });
144
+ });
145
+ it('returns a result with error property', () => {
146
+ // Assert
147
+ expect(typeof result.error).toBe('number');
148
+ });
149
+ it('returns a result with time property', () => {
150
+ // Assert
151
+ expect(typeof result.time).toBe('number');
152
+ });
153
+ it('returns a result with iterations property', () => {
154
+ // Assert
155
+ expect(typeof result.iterations).toBe('number');
156
+ });
157
+ });
158
+ });
159
+
160
+ describe('Scenario: evolution completes with no valid best genome', () => {
161
+ describe('when no valid best genome is found', () => {
162
+ let warnSpy: jest.SpyInstance;
163
+ beforeEach(() => {
164
+ // Spy
165
+ warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
166
+ });
167
+ afterEach(() => {
168
+ warnSpy.mockRestore();
169
+ });
170
+ it('warns if no valid best genome is found', async () => {
171
+ // Arrange
172
+ const net = Architect.perceptron(2, 4, 1);
173
+ // Act
174
+ await net.evolve([{ input: [0, 0], output: [0] }], {
175
+ iterations: 0,
176
+ error: 0.00000001,
177
+ amount: 1,
178
+ threads: 1,
179
+ popsize: 2,
180
+ });
181
+ // Assert
182
+ expect(warnSpy).toHaveBeenCalledWith(
183
+ expect.stringContaining(
184
+ 'Evolution completed without finding a valid best genome'
185
+ )
186
+ );
187
+ });
188
+ });
189
+ });
190
+
191
+ describe('Advanced Evolution Scenarios', () => {
192
+ const dataset = [
193
+ { input: [0, 0], output: [0] },
194
+ { input: [0, 1], output: [1] },
195
+ { input: [1, 0], output: [1] },
196
+ { input: [1, 1], output: [0] },
197
+ ];
198
+ describe('with POWER selection', () => {
199
+ it('returns a result with error property', async () => {
200
+ // Arrange
201
+ const net = Architect.perceptron(2, 4, 1);
202
+ // Act
203
+ const result = await net.evolve(dataset, {
204
+ iterations: 2,
205
+ error: 0.5,
206
+ amount: 1,
207
+ threads: 1,
208
+ popsize: 2,
209
+ selection: 'POWER',
210
+ });
211
+ // Assert
212
+ expect(typeof result.error).toBe('number');
213
+ });
214
+ });
215
+ describe('with FITNESS_PROPORTIONATE selection', () => {
216
+ it('returns a result with error property', async () => {
217
+ // Arrange
218
+ const net = Architect.perceptron(2, 4, 1);
219
+ // Act
220
+ const result = await net.evolve(dataset, {
221
+ iterations: 2,
222
+ error: 0.5,
223
+ amount: 1,
224
+ threads: 1,
225
+ popsize: 2,
226
+ selection: 'FITNESS_PROPORTIONATE',
227
+ });
228
+ // Assert
229
+ expect(typeof result.error).toBe('number');
230
+ });
231
+ });
232
+ describe('with TOURNAMENT selection', () => {
233
+ it('returns a result with error property', async () => {
234
+ // Arrange
235
+ const net = Architect.perceptron(2, 4, 1);
236
+ // Act
237
+ const result = await net.evolve(dataset, {
238
+ iterations: 2,
239
+ error: 0.5,
240
+ amount: 1,
241
+ threads: 1,
242
+ popsize: 2,
243
+ selection: { name: 'TOURNAMENT', size: 2, probability: 1 },
244
+ });
245
+ // Assert
246
+ expect(typeof result.error).toBe('number');
247
+ });
248
+ });
249
+ describe('with maxNodes constraint', () => {
250
+ it('returns a result with error property', async () => {
251
+ // Arrange
252
+ const net = Architect.perceptron(2, 4, 1);
253
+ // Act
254
+ const result = await net.evolve(dataset, {
255
+ iterations: 2,
256
+ error: 0.5,
257
+ amount: 1,
258
+ threads: 1,
259
+ popsize: 2,
260
+ maxNodes: 3,
261
+ });
262
+ // Assert
263
+ expect(typeof result.error).toBe('number');
264
+ });
265
+ });
266
+ describe('with empty population', () => {
267
+ it('returns a result with error property', async () => {
268
+ // Arrange
269
+ const net = Architect.perceptron(2, 4, 1);
270
+ // Force empty population
271
+ (net as any).population = [];
272
+ // Act
273
+ const result = await net.evolve(dataset, {
274
+ iterations: 2,
275
+ error: 0.5,
276
+ amount: 1,
277
+ threads: 1,
278
+ popsize: 0,
279
+ });
280
+ // Assert
281
+ expect(typeof result.error).toBe('number');
282
+ });
283
+ });
284
+ });
285
+ });
@@ -0,0 +1,208 @@
1
+ import { Architect, Network, methods } from '../../src/neataptic';
2
+
3
+ describe('Genetic Operations', () => {
4
+ describe('Crossover', () => {
5
+ describe('Scenario: equal fitness, different hidden node counts', () => {
6
+ let net1: Network;
7
+ let net2: Network;
8
+ let offspring: Network;
9
+ beforeEach(() => {
10
+ // Arrange
11
+ net1 = new Network(2, 1);
12
+ net2 = new Network(2, 1);
13
+ net1.mutate(methods.mutation.ADD_NODE);
14
+ net2.mutate(methods.mutation.ADD_NODE);
15
+ net2.mutate(methods.mutation.ADD_NODE);
16
+ net1.score = 1;
17
+ net2.score = 1;
18
+ // Act
19
+ offspring = Network.crossOver(net1, net2, true);
20
+ });
21
+ describe('offspring node count', () => {
22
+ it('is at least min of parents', () => {
23
+ // Assert
24
+ const minNodes = Math.min(net1.nodes.length, net2.nodes.length);
25
+ expect(offspring.nodes.length).toBeGreaterThanOrEqual(minNodes);
26
+ });
27
+ it('is at most max of parents', () => {
28
+ // Assert
29
+ const maxNodes = Math.max(net1.nodes.length, net2.nodes.length);
30
+ expect(offspring.nodes.length).toBeLessThanOrEqual(maxNodes);
31
+ });
32
+ });
33
+ });
34
+ describe('Scenario: fitter parent, different hidden node counts', () => {
35
+ let net1: Network;
36
+ let net2: Network;
37
+ let offspring: Network;
38
+ beforeEach(() => {
39
+ // Arrange
40
+ net1 = new Network(2, 1);
41
+ net2 = new Network(2, 1);
42
+ net1.mutate(methods.mutation.ADD_NODE);
43
+ net2.mutate(methods.mutation.ADD_NODE);
44
+ net2.mutate(methods.mutation.ADD_NODE);
45
+ net1.score = 1;
46
+ net2.score = 2;
47
+ // Act
48
+ offspring = Network.crossOver(net1, net2, false);
49
+ });
50
+ it('offspring node count matches fitter parent', () => {
51
+ // Assert
52
+ expect(offspring.nodes.length).toBe(net2.nodes.length);
53
+ });
54
+ });
55
+ describe('Scenario: input/output size mismatch', () => {
56
+ it('throws', () => {
57
+ // Arrange
58
+ const net1 = new Network(2, 1);
59
+ const net2 = new Network(3, 1);
60
+ // Act
61
+ const act = () => Network.crossOver(net1, net2);
62
+ // Assert
63
+ expect(act).toThrow();
64
+ });
65
+ });
66
+ describe('Scenario: output size mismatch', () => {
67
+ it('throws', () => {
68
+ // Arrange
69
+ const net1 = new Network(2, 1);
70
+ const net2 = new Network(2, 2);
71
+ // Act
72
+ const act = () => Network.crossOver(net1, net2);
73
+ // Assert
74
+ expect(act).toThrow();
75
+ });
76
+ });
77
+ describe('Scenario: input size mismatch', () => {
78
+ it('throws', () => {
79
+ // Arrange
80
+ const net1 = new Network(2, 1);
81
+ const net2 = new Network(3, 1);
82
+ // Act
83
+ const act = () => Network.crossOver(net1, net2);
84
+ // Assert
85
+ expect(act).toThrow();
86
+ });
87
+ });
88
+ describe('Scenario: both parents are undefined', () => {
89
+ it('throws', () => {
90
+ // Arrange
91
+ const originalWarn = console.warn;
92
+ console.warn = jest.fn(); // Suppress warning
93
+ // Act
94
+ const act = () => Network.crossOver(undefined as any, undefined as any);
95
+ // Assert
96
+ expect(act).toThrow();
97
+ console.warn = originalWarn;
98
+ });
99
+ });
100
+ describe('Scenario: both parents are null', () => {
101
+ it('throws', () => {
102
+ // Arrange
103
+ const originalWarn = console.warn;
104
+ console.warn = jest.fn(); // Suppress warning
105
+ // Act
106
+ const act = () => Network.crossOver(null as any, null as any);
107
+ // Assert
108
+ expect(act).toThrow();
109
+ console.warn = originalWarn;
110
+ });
111
+ });
112
+ describe('Scenario: both parents have no connections', () => {
113
+ let net1: Network;
114
+ let net2: Network;
115
+ let offspring: Network;
116
+ beforeEach(() => {
117
+ // Arrange
118
+ net1 = new Network(2, 1);
119
+ net1.connections = [];
120
+ net2 = new Network(2, 1);
121
+ net2.connections = [];
122
+ // Act
123
+ offspring = Network.crossOver(net1, net2, true);
124
+ });
125
+ it('offspring node count matches parents', () => {
126
+ // Assert
127
+ expect(offspring.nodes.length).toBe(net1.nodes.length);
128
+ });
129
+ });
130
+ describe('Scenario: identical parents', () => {
131
+ let net1: Network;
132
+ let net2: Network;
133
+ let offspring: Network;
134
+ beforeEach(() => {
135
+ // Arrange
136
+ net1 = new Network(2, 1);
137
+ net2 = new Network(2, 1);
138
+ // Act
139
+ offspring = Network.crossOver(net1, net2, true);
140
+ });
141
+ it('offspring node count matches parents', () => {
142
+ // Assert
143
+ expect(offspring.nodes.length).toBe(net1.nodes.length);
144
+ });
145
+ });
146
+ describe('Scenario: both parents have no hidden nodes', () => {
147
+ let net1: Network;
148
+ let net2: Network;
149
+ let offspring: Network;
150
+ beforeEach(() => {
151
+ // Arrange
152
+ net1 = new Network(2, 1);
153
+ net2 = new Network(2, 1);
154
+ // Act
155
+ offspring = Network.crossOver(net1, net2, true);
156
+ });
157
+ it('offspring node count matches parents', () => {
158
+ // Assert
159
+ expect(offspring.nodes.length).toBe(net1.nodes.length);
160
+ });
161
+ });
162
+ describe('Scenario: same score and same node count', () => {
163
+ let net1: Network;
164
+ let net2: Network;
165
+ let offspring: Network;
166
+ beforeEach(() => {
167
+ // Arrange
168
+ net1 = new Network(2, 1);
169
+ net2 = new Network(2, 1);
170
+ net1.score = 1;
171
+ net2.score = 1;
172
+ // Act
173
+ offspring = Network.crossOver(net1, net2, true);
174
+ });
175
+ it('offspring node count matches parents', () => {
176
+ // Assert
177
+ expect(offspring.nodes.length).toBe(net1.nodes.length);
178
+ });
179
+ });
180
+ });
181
+
182
+ describe('Advanced Crossover Scenarios', () => {
183
+ describe('Scenario: first parent is missing', () => {
184
+ it('throws', () => {
185
+ // Arrange
186
+ const originalWarn = console.warn;
187
+ console.warn = jest.fn(); // Suppress warning
188
+ // Act & Assert
189
+ expect(() =>
190
+ Network.crossOver(undefined as any, new Network(2, 1))
191
+ ).toThrow();
192
+ console.warn = originalWarn;
193
+ });
194
+ });
195
+ describe('Scenario: second parent is missing', () => {
196
+ it('throws', () => {
197
+ // Arrange
198
+ const originalWarn = console.warn;
199
+ console.warn = jest.fn(); // Suppress warning
200
+ // Act & Assert
201
+ expect(() =>
202
+ Network.crossOver(new Network(2, 1), undefined as any)
203
+ ).toThrow();
204
+ console.warn = originalWarn;
205
+ });
206
+ });
207
+ });
208
+ });