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