@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,1142 @@
1
+ import Activation from '../../src/methods/activation';
2
+
3
+ describe('Activation', () => {
4
+ const epsilon = 1e-9; // Tolerance for floating point comparisons
5
+ const testValues = [-10, -1, -0.5, 0, 0.5, 1, 10]; // Common values to test
6
+ const stabilityTestValues = [-100, -30.1, -30, -10, 0, 10, 30, 30.1, 100]; // For functions needing stability checks
7
+
8
+ describe('logistic()', () => {
9
+ describe('when x = 1', () => {
10
+ it('returns correct logistic value', () => {
11
+ // Arrange
12
+ const x = 1;
13
+ const expected = 1 / (1 + Math.exp(-1));
14
+ // Act
15
+ const result = Activation.logistic(x);
16
+ // Assert
17
+ expect(result).toBeCloseTo(expected, epsilon);
18
+ });
19
+ it('returns correct logistic derivative', () => {
20
+ // Arrange
21
+ const x = 1;
22
+ const fx = 1 / (1 + Math.exp(-1));
23
+ const expected = fx * (1 - fx);
24
+ // Act
25
+ const result = Activation.logistic(x, true);
26
+ // Assert
27
+ expect(result).toBeCloseTo(expected, epsilon);
28
+ });
29
+ });
30
+ testValues.forEach((x) => {
31
+ describe(`Scenario: x=${x}`, () => {
32
+ it('logistic is greater than or equal to 0', () => {
33
+ // Arrange
34
+ // Act
35
+ const result = Activation.logistic(x);
36
+ // Assert
37
+ expect(result).toBeGreaterThanOrEqual(0);
38
+ });
39
+ it('logistic is less than or equal to 1', () => {
40
+ // Arrange
41
+ // Act
42
+ const result = Activation.logistic(x);
43
+ // Assert
44
+ expect(result).toBeLessThanOrEqual(1);
45
+ });
46
+ it('logistic matches expected value', () => {
47
+ // Arrange
48
+ const expected = 1 / (1 + Math.exp(-x));
49
+ // Act
50
+ const result = Activation.logistic(x);
51
+ // Assert
52
+ expect(result).toBeCloseTo(expected, epsilon);
53
+ });
54
+ it('logistic derivative is greater than or equal to 0', () => {
55
+ // Arrange
56
+ // Act
57
+ const result = Activation.logistic(x, true);
58
+ // Assert
59
+ expect(result).toBeGreaterThanOrEqual(0);
60
+ });
61
+ it('logistic derivative is less than or equal to 0.25', () => {
62
+ // Arrange
63
+ // Act
64
+ const result = Activation.logistic(x, true);
65
+ // Assert
66
+ expect(result).toBeLessThanOrEqual(0.25);
67
+ });
68
+ it('logistic derivative matches expected value', () => {
69
+ // Arrange
70
+ const fx = 1 / (1 + Math.exp(-x));
71
+ const expected = fx * (1 - fx);
72
+ // Act
73
+ const result = Activation.logistic(x, true);
74
+ // Assert
75
+ expect(result).toBeCloseTo(expected, epsilon);
76
+ });
77
+ });
78
+ });
79
+ });
80
+
81
+ describe('tanh()', () => {
82
+ testValues.forEach((x) => {
83
+ describe(`Scenario: x=${x}`, () => {
84
+ it('tanh is within [-1, 1]', () => {
85
+ // Arrange
86
+ const expected = Math.tanh(x);
87
+ // Act
88
+ const result = Activation.tanh(x);
89
+ // Assert
90
+ expect(result).toBeGreaterThanOrEqual(-1);
91
+ });
92
+ it('tanh is less than or equal to 1', () => {
93
+ // Arrange
94
+ const expected = Math.tanh(x);
95
+ // Act
96
+ const result = Activation.tanh(x);
97
+ // Assert
98
+ expect(result).toBeLessThanOrEqual(1);
99
+ });
100
+ it('tanh matches expected value', () => {
101
+ // Arrange
102
+ const expected = Math.tanh(x);
103
+ // Act
104
+ const result = Activation.tanh(x);
105
+ // Assert
106
+ expect(result).toBeCloseTo(expected, epsilon);
107
+ });
108
+ it('tanh derivative is within [0, 1]', () => {
109
+ // Arrange
110
+ const expected = 1 - Math.pow(Math.tanh(x), 2);
111
+ // Act
112
+ const result = Activation.tanh(x, true);
113
+ // Assert
114
+ expect(result).toBeGreaterThanOrEqual(0);
115
+ });
116
+ it('tanh derivative is less than or equal to 1', () => {
117
+ // Arrange
118
+ const expected = 1 - Math.pow(Math.tanh(x), 2);
119
+ // Act
120
+ const result = Activation.tanh(x, true);
121
+ // Assert
122
+ expect(result).toBeLessThanOrEqual(1);
123
+ });
124
+ it('tanh derivative matches expected value', () => {
125
+ // Arrange
126
+ const expected = 1 - Math.pow(Math.tanh(x), 2);
127
+ // Act
128
+ const result = Activation.tanh(x, true);
129
+ // Assert
130
+ expect(result).toBeCloseTo(expected, epsilon);
131
+ });
132
+ });
133
+ });
134
+ });
135
+
136
+ describe('identity()', () => {
137
+ testValues.forEach((x) => {
138
+ describe(`Scenario: x=${x}`, () => {
139
+ it('identity matches expected value', () => {
140
+ // Arrange
141
+ const expected = x;
142
+ // Act
143
+ const result = Activation.identity(x);
144
+ // Assert
145
+ expect(result).toBe(expected);
146
+ });
147
+ it('identity result is finite', () => {
148
+ // Arrange
149
+ // Act
150
+ const result = Activation.identity(x);
151
+ // Assert
152
+ expect(isFinite(result)).toBe(true);
153
+ });
154
+ it('identity derivative matches expected value', () => {
155
+ // Arrange
156
+ const expected = 1;
157
+ // Act
158
+ const result = Activation.identity(x, true);
159
+ // Assert
160
+ expect(result).toBe(expected);
161
+ });
162
+ });
163
+ });
164
+ });
165
+
166
+ describe('step()', () => {
167
+ describe('when x > 0', () => {
168
+ testValues
169
+ .filter((x) => x > 0)
170
+ .forEach((x) => {
171
+ describe(`Scenario: x=${x}`, () => {
172
+ it('step returns 1', () => {
173
+ // Arrange
174
+ // Act
175
+ const result = Activation.step(x);
176
+ // Assert
177
+ expect(result).toBe(1);
178
+ });
179
+ it('step derivative returns 0', () => {
180
+ // Arrange
181
+ // Act
182
+ const result = Activation.step(x, true);
183
+ // Assert
184
+ expect(result).toBe(0);
185
+ });
186
+ });
187
+ });
188
+ });
189
+ describe('when x <= 0', () => {
190
+ testValues
191
+ .filter((x) => x <= 0)
192
+ .forEach((x) => {
193
+ describe(`Scenario: x=${x}`, () => {
194
+ it('step returns 0', () => {
195
+ // Arrange
196
+ // Act
197
+ const result = Activation.step(x);
198
+ // Assert
199
+ expect(result).toBe(0);
200
+ });
201
+ it('step derivative returns 0', () => {
202
+ // Arrange
203
+ // Act
204
+ const result = Activation.step(x, true);
205
+ // Assert
206
+ expect(result).toBe(0);
207
+ });
208
+ });
209
+ });
210
+ });
211
+ });
212
+
213
+ describe('relu()', () => {
214
+ describe('when x > 0', () => {
215
+ testValues
216
+ .filter((x) => x > 0)
217
+ .forEach((x) => {
218
+ describe(`Scenario: x=${x}`, () => {
219
+ it('relu returns x', () => {
220
+ // Arrange
221
+ // Act
222
+ const result = Activation.relu(x);
223
+ // Assert
224
+ expect(result).toBeCloseTo(x, epsilon);
225
+ });
226
+ it('relu is greater than or equal to 0', () => {
227
+ // Arrange
228
+ // Act
229
+ const result = Activation.relu(x);
230
+ // Assert
231
+ expect(result).toBeGreaterThanOrEqual(0);
232
+ });
233
+ it('relu derivative returns 1', () => {
234
+ // Arrange
235
+ // Act
236
+ const result = Activation.relu(x, true);
237
+ // Assert
238
+ expect(result).toBe(1);
239
+ });
240
+ });
241
+ });
242
+ });
243
+ describe('when x <= 0', () => {
244
+ testValues
245
+ .filter((x) => x <= 0)
246
+ .forEach((x) => {
247
+ describe(`Scenario: x=${x}`, () => {
248
+ it('relu returns 0', () => {
249
+ // Arrange
250
+ // Act
251
+ const result = Activation.relu(x);
252
+ // Assert
253
+ expect(result).toBeCloseTo(0, epsilon);
254
+ });
255
+ it('relu is greater than or equal to 0', () => {
256
+ // Arrange
257
+ // Act
258
+ const result = Activation.relu(x);
259
+ // Assert
260
+ expect(result).toBeGreaterThanOrEqual(0);
261
+ });
262
+ it('relu derivative returns 0', () => {
263
+ // Arrange
264
+ // Act
265
+ const result = Activation.relu(x, true);
266
+ // Assert
267
+ expect(result).toBe(0);
268
+ });
269
+ });
270
+ });
271
+ });
272
+ });
273
+
274
+ describe('softsign()', () => {
275
+ testValues.forEach((x) => {
276
+ describe(`Scenario: x=${x}`, () => {
277
+ it('softsign is greater than -1', () => {
278
+ // Arrange
279
+ // Act
280
+ const result = Activation.softsign(x);
281
+ // Assert
282
+ expect(result).toBeGreaterThan(-1);
283
+ });
284
+ it('softsign is less than 1', () => {
285
+ // Arrange
286
+ // Act
287
+ const result = Activation.softsign(x);
288
+ // Assert
289
+ expect(result).toBeLessThan(1);
290
+ });
291
+ it('softsign matches expected value', () => {
292
+ // Arrange
293
+ const expected = x / (1 + Math.abs(x));
294
+ // Act
295
+ const result = Activation.softsign(x);
296
+ // Assert
297
+ expect(result).toBeCloseTo(expected, epsilon);
298
+ });
299
+ it('softsign derivative is greater than 0', () => {
300
+ // Arrange
301
+ // Act
302
+ const result = Activation.softsign(x, true);
303
+ // Assert
304
+ expect(result).toBeGreaterThan(0);
305
+ });
306
+ it('softsign derivative is less than or equal to 1', () => {
307
+ // Arrange
308
+ // Act
309
+ const result = Activation.softsign(x, true);
310
+ // Assert
311
+ expect(result).toBeLessThanOrEqual(1);
312
+ });
313
+ it('softsign derivative matches expected value', () => {
314
+ // Arrange
315
+ const expected = 1 / Math.pow(1 + Math.abs(x), 2);
316
+ // Act
317
+ const result = Activation.softsign(x, true);
318
+ // Assert
319
+ expect(result).toBeCloseTo(expected, epsilon);
320
+ });
321
+ });
322
+ });
323
+ });
324
+
325
+ describe('sinusoid()', () => {
326
+ testValues.forEach((x) => {
327
+ describe(`Scenario: x=${x}`, () => {
328
+ it('sinusoid is greater than or equal to -1', () => {
329
+ // Arrange
330
+ // Act
331
+ const result = Activation.sinusoid(x);
332
+ // Assert
333
+ expect(result).toBeGreaterThanOrEqual(-1);
334
+ });
335
+ it('sinusoid is less than or equal to 1', () => {
336
+ // Arrange
337
+ // Act
338
+ const result = Activation.sinusoid(x);
339
+ // Assert
340
+ expect(result).toBeLessThanOrEqual(1);
341
+ });
342
+ it('sinusoid matches expected value', () => {
343
+ // Arrange
344
+ const expected = Math.sin(x);
345
+ // Act
346
+ const result = Activation.sinusoid(x);
347
+ // Assert
348
+ expect(result).toBeCloseTo(expected, epsilon);
349
+ });
350
+ it('sinusoid derivative is greater than or equal to -1', () => {
351
+ // Arrange
352
+ // Act
353
+ const result = Activation.sinusoid(x, true);
354
+ // Assert
355
+ expect(result).toBeGreaterThanOrEqual(-1);
356
+ });
357
+ it('sinusoid derivative is less than or equal to 1', () => {
358
+ // Arrange
359
+ // Act
360
+ const result = Activation.sinusoid(x, true);
361
+ // Assert
362
+ expect(result).toBeLessThanOrEqual(1);
363
+ });
364
+ it('sinusoid derivative matches expected value', () => {
365
+ // Arrange
366
+ const expected = Math.cos(x);
367
+ // Act
368
+ const result = Activation.sinusoid(x, true);
369
+ // Assert
370
+ expect(result).toBeCloseTo(expected, epsilon);
371
+ });
372
+ });
373
+ });
374
+ });
375
+
376
+ describe('gaussian()', () => {
377
+ testValues.forEach((x) => {
378
+ describe(`Scenario: x=${x}`, () => {
379
+ it('gaussian is greater than 0', () => {
380
+ // Arrange
381
+ // Act
382
+ const result = Activation.gaussian(x);
383
+ // Assert
384
+ expect(result).toBeGreaterThan(0);
385
+ });
386
+ it('gaussian is less than or equal to 1', () => {
387
+ // Arrange
388
+ // Act
389
+ const result = Activation.gaussian(x);
390
+ // Assert
391
+ expect(result).toBeLessThanOrEqual(1);
392
+ });
393
+ it('gaussian matches expected value', () => {
394
+ // Arrange
395
+ const expected = Math.exp(-Math.pow(x, 2));
396
+ // Act
397
+ const result = Activation.gaussian(x);
398
+ // Assert
399
+ expect(result).toBeCloseTo(expected, epsilon);
400
+ });
401
+ it('gaussian derivative is greater than or equal to -maxDeriv', () => {
402
+ // Arrange
403
+ const maxDeriv = Math.sqrt(2 / Math.E);
404
+ // Act
405
+ const result = Activation.gaussian(x, true);
406
+ // Assert
407
+ expect(result).toBeGreaterThanOrEqual(-maxDeriv);
408
+ });
409
+ it('gaussian derivative is less than or equal to maxDeriv', () => {
410
+ // Arrange
411
+ const maxDeriv = Math.sqrt(2 / Math.E);
412
+ // Act
413
+ const result = Activation.gaussian(x, true);
414
+ // Assert
415
+ expect(result).toBeLessThanOrEqual(maxDeriv);
416
+ });
417
+ it('gaussian derivative matches expected value', () => {
418
+ // Arrange
419
+ const expected = -2 * x * Math.exp(-Math.pow(x, 2));
420
+ // Act
421
+ const result = Activation.gaussian(x, true);
422
+ // Assert
423
+ expect(result).toBeCloseTo(expected, epsilon);
424
+ });
425
+ });
426
+ });
427
+ });
428
+
429
+ describe('bentIdentity()', () => {
430
+ testValues.forEach((x) => {
431
+ describe(`Scenario: x=${x}`, () => {
432
+ it('bentIdentity matches expected value', () => {
433
+ // Arrange
434
+ const expected = (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x;
435
+ // Act
436
+ const result = Activation.bentIdentity(x);
437
+ // Assert
438
+ expect(result).toBeCloseTo(expected, epsilon);
439
+ });
440
+ it('bentIdentity result is finite', () => {
441
+ // Arrange
442
+ // Act
443
+ const result = Activation.bentIdentity(x);
444
+ // Assert
445
+ expect(isFinite(result)).toBe(true);
446
+ });
447
+ it('bentIdentity derivative is greater than or equal to 0.5', () => {
448
+ // Arrange
449
+ // Act
450
+ const result = Activation.bentIdentity(x, true);
451
+ // Assert
452
+ expect(result).toBeGreaterThanOrEqual(0.5);
453
+ });
454
+ it('bentIdentity derivative is less than 1.5', () => {
455
+ // Arrange
456
+ // Act
457
+ const result = Activation.bentIdentity(x, true);
458
+ // Assert
459
+ expect(result).toBeLessThan(1.5);
460
+ });
461
+ it('bentIdentity derivative matches expected value', () => {
462
+ // Arrange
463
+ const expected = x / (2 * Math.sqrt(Math.pow(x, 2) + 1)) + 1;
464
+ // Act
465
+ const result = Activation.bentIdentity(x, true);
466
+ // Assert
467
+ expect(result).toBeCloseTo(expected, epsilon);
468
+ });
469
+ });
470
+ });
471
+ });
472
+
473
+ describe('bipolar()', () => {
474
+ describe('when x > 0', () => {
475
+ testValues
476
+ .filter((x) => x > 0)
477
+ .forEach((x) => {
478
+ describe(`Scenario: x=${x}`, () => {
479
+ it('bipolar returns 1', () => {
480
+ // Arrange
481
+ // Act
482
+ const result = Activation.bipolar(x);
483
+ // Assert
484
+ expect(result).toBe(1);
485
+ });
486
+ it('bipolar derivative returns 0', () => {
487
+ // Arrange
488
+ // Act
489
+ const result = Activation.bipolar(x, true);
490
+ // Assert
491
+ expect(result).toBe(0);
492
+ });
493
+ });
494
+ });
495
+ });
496
+ describe('when x <= 0', () => {
497
+ testValues
498
+ .filter((x) => x <= 0)
499
+ .forEach((x) => {
500
+ describe(`Scenario: x=${x}`, () => {
501
+ it('bipolar returns -1', () => {
502
+ // Arrange
503
+ // Act
504
+ const result = Activation.bipolar(x);
505
+ // Assert
506
+ expect(result).toBe(-1);
507
+ });
508
+ it('bipolar derivative returns 0', () => {
509
+ // Arrange
510
+ // Act
511
+ const result = Activation.bipolar(x, true);
512
+ // Assert
513
+ expect(result).toBe(0);
514
+ });
515
+ });
516
+ });
517
+ });
518
+ });
519
+
520
+ describe('bipolarSigmoid()', () => {
521
+ testValues.forEach((x) => {
522
+ describe(`Scenario: x=${x}`, () => {
523
+ it('bipolarSigmoid is greater than -1', () => {
524
+ // Arrange
525
+ // Act
526
+ const result = Activation.bipolarSigmoid(x);
527
+ // Assert
528
+ expect(result).toBeGreaterThan(-1);
529
+ });
530
+ it('bipolarSigmoid is less than 1', () => {
531
+ // Arrange
532
+ // Act
533
+ const result = Activation.bipolarSigmoid(x);
534
+ // Assert
535
+ expect(result).toBeLessThan(1);
536
+ });
537
+ it('bipolarSigmoid matches expected value', () => {
538
+ // Arrange
539
+ const expected = Math.tanh(x);
540
+ // Act
541
+ const result = Activation.bipolarSigmoid(x);
542
+ // Assert
543
+ expect(result).toBeCloseTo(expected, epsilon);
544
+ });
545
+ it('bipolarSigmoid derivative is greater than or equal to 0', () => {
546
+ // Arrange
547
+ // Act
548
+ const result = Activation.bipolarSigmoid(x, true);
549
+ // Assert
550
+ expect(result).toBeGreaterThanOrEqual(0);
551
+ });
552
+ it('bipolarSigmoid derivative is less than or equal to 0.5', () => {
553
+ // Arrange
554
+ // Act
555
+ const result = Activation.bipolarSigmoid(x, true);
556
+ // Assert
557
+ expect(result).toBeLessThanOrEqual(0.5);
558
+ });
559
+ it('bipolarSigmoid derivative matches expected value', () => {
560
+ // Arrange
561
+ const d = 2 / (1 + Math.exp(-x)) - 1;
562
+ const expected = (1 / 2) * (1 + d) * (1 - d);
563
+ // Act
564
+ const result = Activation.bipolarSigmoid(x, true);
565
+ // Assert
566
+ expect(result).toBeCloseTo(expected, epsilon);
567
+ });
568
+ });
569
+ });
570
+ });
571
+
572
+ describe('hardTanh()', () => {
573
+ describe('when x > 1', () => {
574
+ testValues
575
+ .filter((x) => x > 1)
576
+ .forEach((x) => {
577
+ describe(`Scenario: x=${x}`, () => {
578
+ it('hardTanh returns 1', () => {
579
+ // Arrange
580
+ // Act
581
+ const result = Activation.hardTanh(x);
582
+ // Assert
583
+ expect(result).toBeCloseTo(1, epsilon);
584
+ });
585
+ it('hardTanh derivative returns 0', () => {
586
+ // Arrange
587
+ // Act
588
+ const result = Activation.hardTanh(x, true);
589
+ // Assert
590
+ expect(result).toBe(0);
591
+ });
592
+ });
593
+ });
594
+ });
595
+ describe('when x < -1', () => {
596
+ testValues
597
+ .filter((x) => x < -1)
598
+ .forEach((x) => {
599
+ describe(`Scenario: x=${x}`, () => {
600
+ it('hardTanh returns -1', () => {
601
+ // Arrange
602
+ // Act
603
+ const result = Activation.hardTanh(x);
604
+ // Assert
605
+ expect(result).toBeCloseTo(-1, epsilon);
606
+ });
607
+ it('hardTanh derivative returns 0', () => {
608
+ // Arrange
609
+ // Act
610
+ const result = Activation.hardTanh(x, true);
611
+ // Assert
612
+ expect(result).toBe(0);
613
+ });
614
+ });
615
+ });
616
+ });
617
+ describe('when -1 < x < 1', () => {
618
+ testValues
619
+ .filter((x) => x > -1 && x < 1)
620
+ .forEach((x) => {
621
+ describe(`Scenario: x=${x}`, () => {
622
+ it('hardTanh returns x', () => {
623
+ // Arrange
624
+ // Act
625
+ const result = Activation.hardTanh(x);
626
+ // Assert
627
+ expect(result).toBeCloseTo(x, epsilon);
628
+ });
629
+ it('hardTanh derivative returns 1', () => {
630
+ // Arrange
631
+ // Act
632
+ const result = Activation.hardTanh(x, true);
633
+ // Assert
634
+ expect(result).toBe(1);
635
+ });
636
+ });
637
+ });
638
+ });
639
+ describe('when x == -1 or x == 1', () => {
640
+ [-1, 1].forEach((x) => {
641
+ describe(`Scenario: x=${x}`, () => {
642
+ it(`hardTanh returns ${x}`, () => {
643
+ // Arrange
644
+ // Act
645
+ const result = Activation.hardTanh(x);
646
+ // Assert
647
+ expect(result).toBeCloseTo(x, epsilon);
648
+ });
649
+ it('hardTanh derivative returns 0 (boundary)', () => {
650
+ // Arrange
651
+ // Act
652
+ const result = Activation.hardTanh(x, true);
653
+ // Assert
654
+ expect(result).toBe(0);
655
+ });
656
+ });
657
+ });
658
+ });
659
+ });
660
+
661
+ describe('absolute()', () => {
662
+ describe('when x < 0', () => {
663
+ testValues
664
+ .filter((x) => x < 0)
665
+ .forEach((x) => {
666
+ describe(`Scenario: x=${x}`, () => {
667
+ it('absolute returns -x', () => {
668
+ // Arrange
669
+ // Act
670
+ const result = Activation.absolute(x);
671
+ // Assert
672
+ expect(result).toBeCloseTo(-x, epsilon);
673
+ });
674
+ it('absolute derivative returns -1', () => {
675
+ // Arrange
676
+ // Act
677
+ const result = Activation.absolute(x, true);
678
+ // Assert
679
+ expect(result).toBe(-1);
680
+ });
681
+ });
682
+ });
683
+ });
684
+ describe('when x > 0', () => {
685
+ testValues
686
+ .filter((x) => x > 0)
687
+ .forEach((x) => {
688
+ describe(`Scenario: x=${x}`, () => {
689
+ it('absolute returns x', () => {
690
+ // Arrange
691
+ // Act
692
+ const result = Activation.absolute(x);
693
+ // Assert
694
+ expect(result).toBeCloseTo(x, epsilon);
695
+ });
696
+ it('absolute derivative returns 1', () => {
697
+ // Arrange
698
+ // Act
699
+ const result = Activation.absolute(x, true);
700
+ // Assert
701
+ expect(result).toBe(1);
702
+ });
703
+ });
704
+ });
705
+ });
706
+ describe('when x == 0', () => {
707
+ it('absolute returns 0', () => {
708
+ // Arrange
709
+ // Act
710
+ const result = Activation.absolute(0);
711
+ // Assert
712
+ expect(result).toBe(0);
713
+ });
714
+ it('absolute derivative returns 1 (documented choice)', () => {
715
+ // Arrange
716
+ // Act
717
+ const result = Activation.absolute(0, true);
718
+ // Assert
719
+ expect(result).toBe(1);
720
+ });
721
+ });
722
+ });
723
+
724
+ describe('inverse()', () => {
725
+ testValues.forEach((x) => {
726
+ describe(`Scenario: x=${x}`, () => {
727
+ it('inverse returns 1 - x', () => {
728
+ // Arrange
729
+ const expected = 1 - x;
730
+ // Act
731
+ const result = Activation.inverse(x);
732
+ // Assert
733
+ expect(result).toBe(expected);
734
+ });
735
+ it('inverse result is finite', () => {
736
+ // Arrange
737
+ // Act
738
+ const result = Activation.inverse(x);
739
+ // Assert
740
+ expect(isFinite(result)).toBe(true);
741
+ });
742
+ it('inverse derivative returns -1', () => {
743
+ // Arrange
744
+ // Act
745
+ const result = Activation.inverse(x, true);
746
+ // Assert
747
+ expect(result).toBe(-1);
748
+ });
749
+ });
750
+ });
751
+ });
752
+
753
+ describe('selu()', () => {
754
+ const alpha = 1.6732632423543772848170429916717;
755
+ const scale = 1.0507009873554804934193349852946;
756
+ const lowerBound = -alpha * scale;
757
+
758
+ testValues.forEach((x) => {
759
+ describe(`Scenario: x=${x}`, () => {
760
+ it(`selu is within [${lowerBound.toFixed(2)}, inf)`, () => {
761
+ // Arrange
762
+ const fx = x > 0 ? x : alpha * Math.exp(x) - alpha;
763
+ const expected = fx * scale;
764
+ // Act
765
+ const result = Activation.selu(x);
766
+ // Assert
767
+ expect(result).toBeGreaterThanOrEqual(lowerBound - epsilon);
768
+ });
769
+ it('selu matches expected value', () => {
770
+ // Arrange
771
+ const fx = x > 0 ? x : alpha * Math.exp(x) - alpha;
772
+ const expected = fx * scale;
773
+ // Act
774
+ const result = Activation.selu(x);
775
+ // Assert
776
+ expect(result).toBeCloseTo(expected, epsilon);
777
+ });
778
+ it(`selu derivative is within (0, ${scale * alpha}]`, () => {
779
+ // Arrange
780
+ const fx = x > 0 ? x : alpha * Math.exp(x) - alpha;
781
+ const expected = x > 0 ? scale : (fx + alpha) * scale;
782
+ // Act
783
+ const result = Activation.selu(x, true);
784
+ // Assert
785
+ expect(result).toBeGreaterThan(0);
786
+ });
787
+ it(`selu derivative is less than or equal to ${scale * alpha}`, () => {
788
+ // Arrange
789
+ const fx = x > 0 ? x : alpha * Math.exp(x) - alpha;
790
+ const expected = x > 0 ? scale : (fx + alpha) * scale;
791
+ // Act
792
+ const result = Activation.selu(x, true);
793
+ // Assert
794
+ expect(result).toBeLessThanOrEqual(scale * alpha + epsilon);
795
+ });
796
+ it('selu derivative matches expected value', () => {
797
+ // Arrange
798
+ const fx = x > 0 ? x : alpha * Math.exp(x) - alpha;
799
+ const expected = x > 0 ? scale : (fx + alpha) * scale;
800
+ // Act
801
+ const result = Activation.selu(x, true);
802
+ // Assert
803
+ expect(result).toBeCloseTo(expected, epsilon);
804
+ });
805
+ });
806
+ });
807
+ });
808
+
809
+ describe('softplus()', () => {
810
+ stabilityTestValues.forEach((x) => {
811
+ describe(`Scenario: x=${x}`, () => {
812
+ it('softplus is within (0, inf)', () => {
813
+ // Arrange
814
+ const expected = Math.log(1 + Math.exp(x));
815
+ // Act
816
+ const result = Activation.softplus(x);
817
+ // Assert
818
+ if (expected === Infinity) {
819
+ expect(result).toBeCloseTo(x, epsilon); // Should approximate x for large positive x
820
+ } else if (expected === 0 && x < -50) {
821
+ expect(result).toBeCloseTo(0, epsilon); // Should approximate 0 for large negative x
822
+ } else {
823
+ expect(result).toBeCloseTo(expected, epsilon);
824
+ }
825
+ });
826
+ it('softplus matches expected value', () => {
827
+ // Arrange
828
+ const expected = Math.log(1 + Math.exp(x));
829
+ // Act
830
+ const result = Activation.softplus(x);
831
+ // Assert
832
+ if (expected !== Infinity && !(expected === 0 && x < -50)) {
833
+ expect(result).toBeCloseTo(expected, epsilon);
834
+ }
835
+ });
836
+ it('softplus derivative (logistic) is within (0, 1]', () => {
837
+ // Arrange
838
+ const expected = 1 / (1 + Math.exp(-x)); // Logistic
839
+ // Act
840
+ const result = Activation.softplus(x, true);
841
+ // Assert
842
+ expect(result).toBeGreaterThan(0);
843
+ });
844
+ it('softplus derivative (logistic) is less than or equal to 1', () => {
845
+ // Arrange
846
+ const expected = 1 / (1 + Math.exp(-x)); // Logistic
847
+ // Act
848
+ const result = Activation.softplus(x, true);
849
+ // Assert
850
+ expect(result).toBeLessThanOrEqual(1);
851
+ });
852
+ it('softplus derivative (logistic) matches expected value', () => {
853
+ // Arrange
854
+ const expected = 1 / (1 + Math.exp(-x)); // Logistic
855
+ // Act
856
+ const result = Activation.softplus(x, true);
857
+ // Assert
858
+ expect(result).toBeCloseTo(expected, epsilon);
859
+ });
860
+ });
861
+ });
862
+ });
863
+
864
+ describe('swish()', () => {
865
+ const lowerBound = -0.2784645; // Approximate minimum value
866
+ testValues.forEach((x) => {
867
+ describe(`Scenario: x=${x}`, () => {
868
+ it(`swish is within [${lowerBound.toFixed(3)}, inf)`, () => {
869
+ // Arrange
870
+ const sigmoid_x = 1 / (1 + Math.exp(-x));
871
+ const expected = x * sigmoid_x;
872
+ // Act
873
+ const result = Activation.swish(x);
874
+ // Assert
875
+ expect(result).toBeGreaterThanOrEqual(lowerBound - epsilon);
876
+ });
877
+ it('swish matches expected value', () => {
878
+ // Arrange
879
+ const sigmoid_x = 1 / (1 + Math.exp(-x));
880
+ const expected = x * sigmoid_x;
881
+ // Act
882
+ const result = Activation.swish(x);
883
+ // Assert
884
+ expect(result).toBeCloseTo(expected, epsilon);
885
+ });
886
+ it('swish derivative is within approx [-0.09, inf)', () => {
887
+ // Arrange
888
+ const sigmoid_x = 1 / (1 + Math.exp(-x));
889
+ const swish_x = x * sigmoid_x;
890
+ const expected = swish_x + sigmoid_x * (1 - swish_x);
891
+ // Act
892
+ const result = Activation.swish(x, true);
893
+ // Assert
894
+ expect(result).toBeGreaterThanOrEqual(-0.09 - epsilon);
895
+ });
896
+ it('swish derivative matches expected value', () => {
897
+ // Arrange
898
+ const sigmoid_x = 1 / (1 + Math.exp(-x));
899
+ const swish_x = x * sigmoid_x;
900
+ const expected = swish_x + sigmoid_x * (1 - swish_x);
901
+ // Act
902
+ const result = Activation.swish(x, true);
903
+ // Assert
904
+ expect(result).toBeCloseTo(expected, epsilon);
905
+ });
906
+ });
907
+ });
908
+ });
909
+
910
+ describe('gelu()', () => {
911
+ const lowerBound = -0.17; // Approximate minimum value
912
+ testValues.forEach((x) => {
913
+ describe(`Scenario: x=${x}`, () => {
914
+ it(`gelu approximation is within [${lowerBound.toFixed(
915
+ 2
916
+ )}, inf)`, () => {
917
+ // Arrange
918
+ const cdf =
919
+ 0.5 *
920
+ (1.0 +
921
+ Math.tanh(
922
+ Math.sqrt(2.0 / Math.PI) * (x + 0.044715 * Math.pow(x, 3))
923
+ ));
924
+ const expected = x * cdf;
925
+ // Act
926
+ const result = Activation.gelu(x);
927
+ // Assert
928
+ expect(result).toBeGreaterThanOrEqual(lowerBound - epsilon);
929
+ });
930
+ it('gelu approximation matches expected value', () => {
931
+ // Arrange
932
+ const cdf =
933
+ 0.5 *
934
+ (1.0 +
935
+ Math.tanh(
936
+ Math.sqrt(2.0 / Math.PI) * (x + 0.044715 * Math.pow(x, 3))
937
+ ));
938
+ const expected = x * cdf;
939
+ // Act
940
+ const result = Activation.gelu(x);
941
+ // Assert
942
+ expect(result).toBeCloseTo(expected, epsilon);
943
+ });
944
+ it('gelu approximation derivative is within approx [-0.16, inf)', () => {
945
+ // Arrange
946
+ const cdf =
947
+ 0.5 *
948
+ (1.0 +
949
+ Math.tanh(
950
+ Math.sqrt(2.0 / Math.PI) * (x + 0.044715 * Math.pow(x, 3))
951
+ ));
952
+ const intermediate =
953
+ Math.sqrt(2.0 / Math.PI) * (1.0 + 0.134145 * x * x);
954
+ const sech_arg =
955
+ Math.sqrt(2.0 / Math.PI) * (x + 0.044715 * Math.pow(x, 3));
956
+ const sech_val = 1.0 / Math.cosh(sech_arg);
957
+ const sech_sq = sech_val * sech_val;
958
+ const expected = cdf + x * 0.5 * intermediate * sech_sq;
959
+ // Act
960
+ const result = Activation.gelu(x, true);
961
+ // Assert
962
+ expect(result).toBeGreaterThanOrEqual(-0.16 - epsilon);
963
+ });
964
+ it('gelu approximation derivative matches expected value', () => {
965
+ // Arrange
966
+ const cdf =
967
+ 0.5 *
968
+ (1.0 +
969
+ Math.tanh(
970
+ Math.sqrt(2.0 / Math.PI) * (x + 0.044715 * Math.pow(x, 3))
971
+ ));
972
+ const intermediate =
973
+ Math.sqrt(2.0 / Math.PI) * (1.0 + 0.134145 * x * x);
974
+ const sech_arg =
975
+ Math.sqrt(2.0 / Math.PI) * (x + 0.044715 * Math.pow(x, 3));
976
+ const sech_val = 1.0 / Math.cosh(sech_arg);
977
+ const sech_sq = sech_val * sech_val;
978
+ const expected = cdf + x * 0.5 * intermediate * sech_sq;
979
+ // Act
980
+ const result = Activation.gelu(x, true);
981
+ // Assert
982
+ expect(result).toBeCloseTo(expected, epsilon);
983
+ });
984
+ });
985
+ });
986
+ });
987
+
988
+ describe('mish()', () => {
989
+ const lowerBound = -0.30884; // Approximate minimum value
990
+ stabilityTestValues.forEach((x) => {
991
+ describe(`Scenario: x=${x}`, () => {
992
+ it(`mish is within [${lowerBound.toFixed(3)}, inf)`, () => {
993
+ // Arrange
994
+ let sp_x: number;
995
+ if (x > 30) {
996
+ sp_x = x;
997
+ } else if (x < -30) {
998
+ sp_x = Math.exp(x);
999
+ } else {
1000
+ sp_x = Math.max(0, x) + Math.log(1 + Math.exp(-Math.abs(x)));
1001
+ }
1002
+ const expected = x * Math.tanh(sp_x);
1003
+ // Act
1004
+ const result = Activation.mish(x);
1005
+ // Assert
1006
+ expect(result).toBeGreaterThanOrEqual(lowerBound - epsilon);
1007
+ });
1008
+ it('mish matches expected value', () => {
1009
+ // Arrange
1010
+ let sp_x: number;
1011
+ if (x > 30) {
1012
+ sp_x = x;
1013
+ } else if (x < -30) {
1014
+ sp_x = Math.exp(x);
1015
+ } else {
1016
+ sp_x = Math.max(0, x) + Math.log(1 + Math.exp(-Math.abs(x)));
1017
+ }
1018
+ const expected = x * Math.tanh(sp_x);
1019
+ // Act
1020
+ const result = Activation.mish(x);
1021
+ // Assert
1022
+ expect(result).toBeCloseTo(expected, epsilon);
1023
+ });
1024
+ it('mish derivative matches expected value', () => {
1025
+ // Arrange
1026
+ let sp_x: number;
1027
+ if (x > 30) {
1028
+ sp_x = x;
1029
+ } else if (x < -30) {
1030
+ sp_x = Math.exp(x);
1031
+ } else {
1032
+ sp_x = Math.max(0, x) + Math.log(1 + Math.exp(-Math.abs(x)));
1033
+ }
1034
+ const tanh_sp_x = Math.tanh(sp_x);
1035
+ const sigmoid_x = 1 / (1 + Math.exp(-x));
1036
+ const sech_sp_x = 1.0 / Math.cosh(sp_x);
1037
+ const sech_sq_sp_x = sech_sp_x * sech_sp_x;
1038
+ const expected = tanh_sp_x + x * sech_sq_sp_x * sigmoid_x;
1039
+ // Act
1040
+ const result = Activation.mish(x, true);
1041
+ // Assert
1042
+ expect(result).toBeCloseTo(expected, epsilon);
1043
+ });
1044
+ it('mish derivative result is finite', () => {
1045
+ // Arrange
1046
+ let sp_x: number;
1047
+ if (x > 30) {
1048
+ sp_x = x;
1049
+ } else if (x < -30) {
1050
+ sp_x = Math.exp(x);
1051
+ } else {
1052
+ sp_x = Math.max(0, x) + Math.log(1 + Math.exp(-Math.abs(x)));
1053
+ }
1054
+ const tanh_sp_x = Math.tanh(sp_x);
1055
+ const sigmoid_x = 1 / (1 + Math.exp(-x));
1056
+ const sech_sp_x = 1.0 / Math.cosh(sp_x);
1057
+ const sech_sq_sp_x = sech_sp_x * sech_sp_x;
1058
+ const expected = tanh_sp_x + x * sech_sq_sp_x * sigmoid_x;
1059
+ // Act
1060
+ const result = Activation.mish(x, true);
1061
+ // Assert
1062
+ expect(isFinite(result)).toBe(true);
1063
+ });
1064
+ });
1065
+ });
1066
+ });
1067
+
1068
+ describe('Ambiguous Derivatives', () => {
1069
+ describe('ReLU derivative at 0', () => {
1070
+ it('returns 0 (documented choice)', () => {
1071
+ // Arrange
1072
+ // Act
1073
+ const result = Activation.relu(0, true);
1074
+ // Assert
1075
+ expect(result).toBe(0);
1076
+ });
1077
+ });
1078
+ describe('Absolute derivative at 0', () => {
1079
+ it('returns 1 (documented choice)', () => {
1080
+ // Arrange
1081
+ // Act
1082
+ const result = Activation.absolute(0, true);
1083
+ // Assert
1084
+ expect(result).toBe(1);
1085
+ });
1086
+ });
1087
+ });
1088
+
1089
+ describe('Custom Activation Registration', () => {
1090
+ let Activation: typeof import('../../src/methods/activation').default;
1091
+ let registerCustomActivation: (
1092
+ name: string,
1093
+ fn: (x: number, derivate?: boolean) => number
1094
+ ) => void;
1095
+ beforeEach(() => {
1096
+ Activation = require('../../src/methods/activation').default;
1097
+ registerCustomActivation = require('../../src/methods/activation')
1098
+ .registerCustomActivation;
1099
+ // Clean up any previous customFn
1100
+ if (Activation['customFn']) delete Activation['customFn'];
1101
+ });
1102
+ afterEach(() => {
1103
+ if (Activation['customFn']) delete Activation['customFn'];
1104
+ });
1105
+ describe('when registering a custom activation', () => {
1106
+ it('can register and use a custom activation function', () => {
1107
+ // Arrange
1108
+ registerCustomActivation(
1109
+ 'customFn',
1110
+ (x: number, derivate: boolean = false) => (derivate ? 42 : x * 2)
1111
+ );
1112
+ // Act
1113
+ const result = Activation['customFn'](3);
1114
+ // Assert
1115
+ expect(result).toBe(6);
1116
+ });
1117
+ it('custom activation derivative returns expected value', () => {
1118
+ // Arrange
1119
+ registerCustomActivation(
1120
+ 'customFn',
1121
+ (x: number, derivate: boolean = false) => (derivate ? 42 : x * 2)
1122
+ );
1123
+ // Act
1124
+ const result = Activation['customFn'](3, true);
1125
+ // Assert
1126
+ expect(result).toBe(42);
1127
+ });
1128
+ });
1129
+ });
1130
+
1131
+ // Add a dedicated describe for helper/utility methods if any exist in activation.ts
1132
+ describe('Helper and Utility Methods', () => {
1133
+ // Example: If there are utility functions in activation.ts, add their tests here
1134
+ // This is a placeholder for future utility/helper method tests
1135
+ it('should have a placeholder for utility/helper method tests', () => {
1136
+ // Arrange
1137
+ // Act
1138
+ // Assert
1139
+ expect(true).toBe(true);
1140
+ });
1141
+ });
1142
+ });