@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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +28 -0
- package/.github/workflows/ci.yml +41 -0
- package/.github/workflows/deploy-pages.yml +29 -0
- package/.github/workflows/manual_release_pipeline.yml +62 -0
- package/.github/workflows/publish.yml +85 -0
- package/.github/workflows/release_dispatch.yml +38 -0
- package/.travis.yml +5 -0
- package/CONTRIBUTING.md +92 -0
- package/LICENSE +24 -0
- package/ONNX_EXPORT.md +87 -0
- package/README.md +1173 -0
- package/RELEASE.md +54 -0
- package/dist-docs/package.json +1 -0
- package/dist-docs/scripts/generate-docs.d.ts +2 -0
- package/dist-docs/scripts/generate-docs.d.ts.map +1 -0
- package/dist-docs/scripts/generate-docs.js +536 -0
- package/dist-docs/scripts/generate-docs.js.map +1 -0
- package/dist-docs/scripts/render-docs-html.d.ts +2 -0
- package/dist-docs/scripts/render-docs-html.d.ts.map +1 -0
- package/dist-docs/scripts/render-docs-html.js +148 -0
- package/dist-docs/scripts/render-docs-html.js.map +1 -0
- package/docs/FOLDERS.md +14 -0
- package/docs/README.md +1173 -0
- package/docs/architecture/README.md +1391 -0
- package/docs/architecture/index.html +938 -0
- package/docs/architecture/network/README.md +1210 -0
- package/docs/architecture/network/index.html +908 -0
- package/docs/assets/ascii-maze.bundle.js +16542 -0
- package/docs/assets/ascii-maze.bundle.js.map +7 -0
- package/docs/index.html +1419 -0
- package/docs/methods/README.md +670 -0
- package/docs/methods/index.html +477 -0
- package/docs/multithreading/README.md +274 -0
- package/docs/multithreading/index.html +215 -0
- package/docs/multithreading/workers/README.md +23 -0
- package/docs/multithreading/workers/browser/README.md +39 -0
- package/docs/multithreading/workers/browser/index.html +70 -0
- package/docs/multithreading/workers/index.html +57 -0
- package/docs/multithreading/workers/node/README.md +33 -0
- package/docs/multithreading/workers/node/index.html +66 -0
- package/docs/neat/README.md +1284 -0
- package/docs/neat/index.html +906 -0
- package/docs/src/README.md +2659 -0
- package/docs/src/index.html +1579 -0
- package/jest.config.ts +32 -0
- package/package.json +99 -0
- package/plans/HyperMorphoNEAT.md +293 -0
- package/plans/ONNX_EXPORT_PLAN.md +46 -0
- package/scripts/generate-docs.ts +486 -0
- package/scripts/render-docs-html.ts +138 -0
- package/scripts/types.d.ts +2 -0
- package/src/README.md +2659 -0
- package/src/architecture/README.md +1391 -0
- package/src/architecture/activationArrayPool.ts +135 -0
- package/src/architecture/architect.ts +635 -0
- package/src/architecture/connection.ts +148 -0
- package/src/architecture/group.ts +406 -0
- package/src/architecture/layer.ts +804 -0
- package/src/architecture/network/README.md +1210 -0
- package/src/architecture/network/network.activate.ts +223 -0
- package/src/architecture/network/network.connect.ts +157 -0
- package/src/architecture/network/network.deterministic.ts +167 -0
- package/src/architecture/network/network.evolve.ts +426 -0
- package/src/architecture/network/network.gating.ts +186 -0
- package/src/architecture/network/network.genetic.ts +247 -0
- package/src/architecture/network/network.mutate.ts +624 -0
- package/src/architecture/network/network.onnx.ts +463 -0
- package/src/architecture/network/network.prune.ts +216 -0
- package/src/architecture/network/network.remove.ts +96 -0
- package/src/architecture/network/network.serialize.ts +309 -0
- package/src/architecture/network/network.slab.ts +262 -0
- package/src/architecture/network/network.standalone.ts +246 -0
- package/src/architecture/network/network.stats.ts +59 -0
- package/src/architecture/network/network.topology.ts +86 -0
- package/src/architecture/network/network.training.ts +1278 -0
- package/src/architecture/network.ts +1302 -0
- package/src/architecture/node.ts +1288 -0
- package/src/architecture/onnx.ts +3 -0
- package/src/config.ts +83 -0
- package/src/methods/README.md +670 -0
- package/src/methods/activation.ts +372 -0
- package/src/methods/connection.ts +31 -0
- package/src/methods/cost.ts +347 -0
- package/src/methods/crossover.ts +63 -0
- package/src/methods/gating.ts +43 -0
- package/src/methods/methods.ts +8 -0
- package/src/methods/mutation.ts +300 -0
- package/src/methods/rate.ts +257 -0
- package/src/methods/selection.ts +65 -0
- package/src/multithreading/README.md +274 -0
- package/src/multithreading/multi.ts +339 -0
- package/src/multithreading/workers/README.md +23 -0
- package/src/multithreading/workers/browser/README.md +39 -0
- package/src/multithreading/workers/browser/testworker.ts +99 -0
- package/src/multithreading/workers/node/README.md +33 -0
- package/src/multithreading/workers/node/testworker.ts +72 -0
- package/src/multithreading/workers/node/worker.ts +70 -0
- package/src/multithreading/workers/workers.ts +22 -0
- package/src/neat/README.md +1284 -0
- package/src/neat/neat.adaptive.ts +544 -0
- package/src/neat/neat.compat.ts +164 -0
- package/src/neat/neat.constants.ts +20 -0
- package/src/neat/neat.diversity.ts +217 -0
- package/src/neat/neat.evaluate.ts +328 -0
- package/src/neat/neat.evolve.ts +1026 -0
- package/src/neat/neat.export.ts +249 -0
- package/src/neat/neat.helpers.ts +235 -0
- package/src/neat/neat.lineage.ts +220 -0
- package/src/neat/neat.multiobjective.ts +260 -0
- package/src/neat/neat.mutation.ts +718 -0
- package/src/neat/neat.objectives.ts +157 -0
- package/src/neat/neat.pruning.ts +190 -0
- package/src/neat/neat.selection.ts +269 -0
- package/src/neat/neat.speciation.ts +460 -0
- package/src/neat/neat.species.ts +151 -0
- package/src/neat/neat.telemetry.exports.ts +469 -0
- package/src/neat/neat.telemetry.ts +933 -0
- package/src/neat/neat.types.ts +275 -0
- package/src/neat.ts +1042 -0
- package/src/neataptic.ts +10 -0
- package/test/architecture/activationArrayPool.capacity.test.ts +19 -0
- package/test/architecture/activationArrayPool.test.ts +46 -0
- package/test/architecture/connection.test.ts +290 -0
- package/test/architecture/group.test.ts +950 -0
- package/test/architecture/layer.test.ts +1535 -0
- package/test/architecture/network.pruning.test.ts +65 -0
- package/test/architecture/node.test.ts +1602 -0
- package/test/examples/asciiMaze/asciiMaze.e2e.test.ts +499 -0
- package/test/examples/asciiMaze/asciiMaze.ts +41 -0
- package/test/examples/asciiMaze/browser-entry.ts +164 -0
- package/test/examples/asciiMaze/browserLogger.ts +221 -0
- package/test/examples/asciiMaze/browserTerminalUtility.ts +48 -0
- package/test/examples/asciiMaze/colors.ts +119 -0
- package/test/examples/asciiMaze/dashboardManager.ts +968 -0
- package/test/examples/asciiMaze/evolutionEngine.ts +1248 -0
- package/test/examples/asciiMaze/fitness.ts +136 -0
- package/test/examples/asciiMaze/index.html +128 -0
- package/test/examples/asciiMaze/index.ts +26 -0
- package/test/examples/asciiMaze/interfaces.ts +235 -0
- package/test/examples/asciiMaze/mazeMovement.ts +996 -0
- package/test/examples/asciiMaze/mazeUtils.ts +278 -0
- package/test/examples/asciiMaze/mazeVision.ts +402 -0
- package/test/examples/asciiMaze/mazeVisualization.ts +585 -0
- package/test/examples/asciiMaze/mazes.ts +245 -0
- package/test/examples/asciiMaze/networkRefinement.ts +76 -0
- package/test/examples/asciiMaze/networkVisualization.ts +901 -0
- package/test/examples/asciiMaze/terminalUtility.ts +73 -0
- package/test/methods/activation.test.ts +1142 -0
- package/test/methods/connection.test.ts +146 -0
- package/test/methods/cost.test.ts +1123 -0
- package/test/methods/crossover.test.ts +202 -0
- package/test/methods/gating.test.ts +144 -0
- package/test/methods/mutation.test.ts +451 -0
- package/test/methods/optimizers.advanced.test.ts +80 -0
- package/test/methods/optimizers.behavior.test.ts +105 -0
- package/test/methods/optimizers.formula.test.ts +89 -0
- package/test/methods/rate.cosineWarmRestarts.test.ts +44 -0
- package/test/methods/rate.linearWarmupDecay.test.ts +41 -0
- package/test/methods/rate.reduceOnPlateau.test.ts +45 -0
- package/test/methods/rate.test.ts +684 -0
- package/test/methods/selection.test.ts +245 -0
- package/test/multithreading/activations.functions.test.ts +54 -0
- package/test/multithreading/multi.test.ts +290 -0
- package/test/multithreading/worker.node.process.test.ts +39 -0
- package/test/multithreading/workers.coverage.test.ts +36 -0
- package/test/multithreading/workers.dynamic.import.test.ts +8 -0
- package/test/neat/neat.adaptive.complexityBudget.test.ts +34 -0
- package/test/neat/neat.adaptive.criterion.complexity.test.ts +50 -0
- package/test/neat/neat.adaptive.mutation.strategy.test.ts +37 -0
- package/test/neat/neat.adaptive.operator.decay.test.ts +31 -0
- package/test/neat/neat.adaptive.phasedComplexity.test.ts +25 -0
- package/test/neat/neat.adaptive.pruning.test.ts +25 -0
- package/test/neat/neat.adaptive.targetSpecies.test.ts +43 -0
- package/test/neat/neat.additional.coverage.test.ts +126 -0
- package/test/neat/neat.advanced.enhancements.test.ts +85 -0
- package/test/neat/neat.advanced.test.ts +589 -0
- package/test/neat/neat.diversity.autocompat.test.ts +47 -0
- package/test/neat/neat.diversity.metrics.test.ts +21 -0
- package/test/neat/neat.diversity.stats.test.ts +44 -0
- package/test/neat/neat.enhancements.test.ts +79 -0
- package/test/neat/neat.entropy.ancestorAdaptive.test.ts +133 -0
- package/test/neat/neat.entropy.compat.csv.test.ts +108 -0
- package/test/neat/neat.evolution.pruning.test.ts +39 -0
- package/test/neat/neat.fastmode.autotune.test.ts +42 -0
- package/test/neat/neat.innovation.test.ts +134 -0
- package/test/neat/neat.lineage.antibreeding.test.ts +35 -0
- package/test/neat/neat.lineage.entropy.test.ts +56 -0
- package/test/neat/neat.lineage.inbreeding.test.ts +49 -0
- package/test/neat/neat.lineage.pressure.test.ts +29 -0
- package/test/neat/neat.multiobjective.adaptive.test.ts +57 -0
- package/test/neat/neat.multiobjective.dynamic.schedule.test.ts +46 -0
- package/test/neat/neat.multiobjective.dynamic.test.ts +31 -0
- package/test/neat/neat.multiobjective.fastsort.delegation.test.ts +51 -0
- package/test/neat/neat.multiobjective.prune.test.ts +39 -0
- package/test/neat/neat.multiobjective.test.ts +21 -0
- package/test/neat/neat.mutation.undefined.pool.test.ts +24 -0
- package/test/neat/neat.objective.events.test.ts +26 -0
- package/test/neat/neat.objective.importance.test.ts +21 -0
- package/test/neat/neat.objective.lifetimes.test.ts +33 -0
- package/test/neat/neat.offspring.allocation.test.ts +22 -0
- package/test/neat/neat.operator.bandit.test.ts +17 -0
- package/test/neat/neat.operator.phases.test.ts +38 -0
- package/test/neat/neat.pruneInactive.behavior.test.ts +54 -0
- package/test/neat/neat.reenable.adaptation.test.ts +18 -0
- package/test/neat/neat.rng.state.test.ts +22 -0
- package/test/neat/neat.spawn.add.test.ts +123 -0
- package/test/neat/neat.speciation.test.ts +96 -0
- package/test/neat/neat.species.allocation.telemetry.test.ts +26 -0
- package/test/neat/neat.species.history.csv.test.ts +24 -0
- package/test/neat/neat.telemetry.advanced.test.ts +226 -0
- package/test/neat/neat.telemetry.csv.lineage.test.ts +19 -0
- package/test/neat/neat.telemetry.parity.test.ts +42 -0
- package/test/neat/neat.telemetry.stream.test.ts +19 -0
- package/test/neat/neat.telemetry.test.ts +16 -0
- package/test/neat/neat.test.ts +422 -0
- package/test/neat/neat.utilities.test.ts +44 -0
- package/test/network/__suppress_console.ts +9 -0
- package/test/network/acyclic.topoorder.test.ts +17 -0
- package/test/network/checkpoint.metricshook.test.ts +36 -0
- package/test/network/error.handling.test.ts +581 -0
- package/test/network/evolution.test.ts +285 -0
- package/test/network/genetic.test.ts +208 -0
- package/test/network/learning.capability.test.ts +244 -0
- package/test/network/mutation.effects.test.ts +492 -0
- package/test/network/network.activate.test.ts +115 -0
- package/test/network/network.activateBatch.test.ts +30 -0
- package/test/network/network.deterministic.test.ts +64 -0
- package/test/network/network.evolve.branches.test.ts +75 -0
- package/test/network/network.evolve.multithread.branches.test.ts +83 -0
- package/test/network/network.evolve.test.ts +100 -0
- package/test/network/network.gating.removal.test.ts +93 -0
- package/test/network/network.mutate.additional.test.ts +145 -0
- package/test/network/network.mutate.edgecases.test.ts +101 -0
- package/test/network/network.mutate.test.ts +101 -0
- package/test/network/network.prune.earlyexit.test.ts +38 -0
- package/test/network/network.remove.errors.test.ts +45 -0
- package/test/network/network.slab.fallbacks.test.ts +22 -0
- package/test/network/network.stats.test.ts +45 -0
- package/test/network/network.training.advanced.test.ts +149 -0
- package/test/network/network.training.basic.test.ts +228 -0
- package/test/network/network.training.helpers.test.ts +183 -0
- package/test/network/onnx.export.test.ts +310 -0
- package/test/network/onnx.import.test.ts +129 -0
- package/test/network/pruning.topology.test.ts +282 -0
- package/test/network/regularization.determinism.test.ts +83 -0
- package/test/network/regularization.dropconnect.test.ts +17 -0
- package/test/network/regularization.dropconnect.validation.test.ts +18 -0
- package/test/network/regularization.stochasticdepth.test.ts +27 -0
- package/test/network/regularization.test.ts +843 -0
- package/test/network/regularization.weightnoise.test.ts +30 -0
- package/test/network/setupTests.ts +2 -0
- package/test/network/standalone.test.ts +332 -0
- package/test/network/structure.serialization.test.ts +660 -0
- package/test/training/training.determinism.mixed-precision.test.ts +134 -0
- package/test/training/training.earlystopping.test.ts +91 -0
- package/test/training/training.edge-cases.test.ts +91 -0
- package/test/training/training.extensions.test.ts +47 -0
- package/test/training/training.gradient.features.test.ts +110 -0
- package/test/training/training.gradient.refinements.test.ts +170 -0
- package/test/training/training.gradient.separate-bias.test.ts +41 -0
- package/test/training/training.optimizer.test.ts +48 -0
- package/test/training/training.plateau.smoothing.test.ts +58 -0
- package/test/training/training.smoothing.types.test.ts +174 -0
- package/test/training/training.train.options.coverage.test.ts +52 -0
- package/test/utils/console-helper.ts +76 -0
- package/test/utils/jest-setup.ts +60 -0
- package/test/utils/test-helpers.ts +175 -0
- package/tsconfig.docs.json +12 -0
- package/tsconfig.json +21 -0
- 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
|
+
});
|