@reicek/neataptic-ts 0.1.21 → 0.1.22
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/agents/boundary-mapper.agent.md +29 -0
- package/.github/agents/docs-scout.agent.md +29 -0
- package/.github/agents/plan-scout.agent.md +29 -0
- package/.github/agents/solid-split.agent.md +138 -0
- package/.github/copilot-instructions.md +103 -0
- package/package.json +6 -3
- package/plans/ES2023 migration +13 -8
- package/plans/Evolution_Training_Interoperability_Contracts.md +1 -1
- package/plans/Interactive_Examples_and_Learning_Path.md +10 -2
- package/plans/Memory_Optimization.md +3 -3
- package/plans/README.md +63 -0
- package/plans/Roadmap.md +15 -3
- package/plans/asciiMaze_SOLID_split.done.md +130 -0
- package/plans/flappy_bird_SOLID_split.done.md +67 -0
- package/scripts/assets/theme.css +221 -34
- package/scripts/copy-examples.mjs +9 -5
- package/scripts/export-onnx.mjs +3 -3
- package/scripts/generate-bench-tables.mjs +10 -10
- package/scripts/generate-bench-tables.ts +10 -10
- package/scripts/generate-docs.ts +1415 -449
- package/scripts/render-docs-html.ts +15 -8
- package/src/README.md +101 -223
- package/src/architecture/README.md +57 -185
- package/src/architecture/layer/README.md +38 -38
- package/src/architecture/network/README.md +33 -31
- package/src/architecture/network/activate/README.md +77 -77
- package/src/architecture/network/connect/README.md +15 -13
- package/src/architecture/network/deterministic/README.md +7 -7
- package/src/architecture/network/evolve/README.md +44 -44
- package/src/architecture/network/gating/README.md +20 -20
- package/src/architecture/network/genetic/README.md +51 -51
- package/src/architecture/network/mutate/README.md +97 -97
- package/src/architecture/network/onnx/README.md +264 -264
- package/src/architecture/network/prune/README.md +39 -39
- package/src/architecture/network/remove/README.md +26 -26
- package/src/architecture/network/serialize/README.md +56 -56
- package/src/architecture/network/slab/README.md +61 -61
- package/src/architecture/network/standalone/README.md +24 -24
- package/src/architecture/network/stats/README.md +9 -9
- package/src/architecture/network/topology/README.md +46 -46
- package/src/architecture/network/training/README.md +21 -21
- package/src/methods/README.md +9 -87
- package/src/multithreading/README.md +8 -77
- package/src/multithreading/workers/README.md +2 -2
- package/src/multithreading/workers/browser/README.md +0 -6
- package/src/multithreading/workers/node/README.md +0 -3
- package/src/neat/README.md +562 -568
- package/src/utils/README.md +18 -18
- package/test/examples/asciiMaze/README.md +59 -59
- package/test/examples/asciiMaze/asciiMaze.e2e.test.ts +14 -9
- package/test/examples/asciiMaze/browser-entry/README.md +196 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.abort.services.ts +95 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.constants.ts +23 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.curriculum.services.ts +115 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.globals.services.ts +106 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.host.services.ts +157 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.services.ts +14 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.ts +129 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.types.ts +120 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.utils.ts +98 -0
- package/test/examples/asciiMaze/browser-entry.ts +10 -576
- package/test/examples/asciiMaze/dashboardManager/README.md +276 -0
- package/test/examples/asciiMaze/dashboardManager/archive/README.md +16 -0
- package/test/examples/asciiMaze/dashboardManager/archive/dashboardManager.archive.services.ts +267 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.constants.ts +35 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.services.ts +103 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.ts +181 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.types.ts +267 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.utils.ts +254 -0
- package/test/examples/asciiMaze/dashboardManager/live/README.md +14 -0
- package/test/examples/asciiMaze/dashboardManager/live/dashboardManager.live.services.ts +264 -0
- package/test/examples/asciiMaze/dashboardManager/telemetry/README.md +47 -0
- package/test/examples/asciiMaze/dashboardManager/telemetry/dashboardManager.telemetry.services.ts +513 -0
- package/test/examples/asciiMaze/dashboardManager.ts +13 -2335
- package/test/examples/asciiMaze/evolutionEngine/README.md +1058 -0
- package/test/examples/asciiMaze/evolutionEngine/curriculumPhase.ts +90 -0
- package/test/examples/asciiMaze/evolutionEngine/engineState.constants.ts +36 -0
- package/test/examples/asciiMaze/evolutionEngine/engineState.ts +58 -513
- package/test/examples/asciiMaze/evolutionEngine/engineState.types.ts +212 -0
- package/test/examples/asciiMaze/evolutionEngine/engineState.utils.ts +301 -0
- package/test/examples/asciiMaze/evolutionEngine/evolutionEngine.types.ts +445 -0
- package/test/examples/asciiMaze/evolutionEngine/evolutionLoop.ts +81 -50
- package/test/examples/asciiMaze/evolutionEngine/optionsAndSetup.ts +2 -4
- package/test/examples/asciiMaze/evolutionEngine/populationDynamics.ts +17 -33
- package/test/examples/asciiMaze/evolutionEngine/populationPruning.ts +1 -1
- package/test/examples/asciiMaze/evolutionEngine/rngAndTiming.ts +1 -2
- package/test/examples/asciiMaze/evolutionEngine/sampling.ts +1 -1
- package/test/examples/asciiMaze/evolutionEngine/scratchPools.ts +2 -5
- package/test/examples/asciiMaze/evolutionEngine/setupHelpers.ts +30 -37
- package/test/examples/asciiMaze/evolutionEngine/telemetryMetrics.ts +16 -58
- package/test/examples/asciiMaze/evolutionEngine/trainingWarmStart.ts +2 -2
- package/test/examples/asciiMaze/evolutionEngine.ts +55 -55
- package/test/examples/asciiMaze/fitness.ts +2 -2
- package/test/examples/asciiMaze/fitness.types.ts +65 -0
- package/test/examples/asciiMaze/interfaces.ts +64 -1352
- package/test/examples/asciiMaze/mazeMovement/README.md +356 -0
- package/test/examples/asciiMaze/mazeMovement/finalization/README.md +49 -0
- package/test/examples/asciiMaze/mazeMovement/finalization/mazeMovement.finalization.ts +138 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.constants.ts +101 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.services.ts +230 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.ts +299 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.types.ts +185 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.utils.ts +153 -0
- package/test/examples/asciiMaze/mazeMovement/policy/README.md +91 -0
- package/test/examples/asciiMaze/mazeMovement/policy/mazeMovement.policy.ts +467 -0
- package/test/examples/asciiMaze/mazeMovement/runtime/README.md +95 -0
- package/test/examples/asciiMaze/mazeMovement/runtime/mazeMovement.runtime.ts +354 -0
- package/test/examples/asciiMaze/mazeMovement/shaping/README.md +124 -0
- package/test/examples/asciiMaze/mazeMovement/shaping/mazeMovement.shaping.ts +459 -0
- package/test/examples/asciiMaze/mazeMovement.ts +12 -2978
- package/test/examples/flappy_bird/Trace-20260309T191949.json +24124 -0
- package/test/examples/flappy_bird/browser-entry/README.md +1129 -0
- package/test/examples/flappy_bird/browser-entry/browser-entry.host.utils.ts +4 -324
- package/test/examples/flappy_bird/browser-entry/browser-entry.network-view.utils.ts +6 -399
- package/test/examples/flappy_bird/browser-entry/browser-entry.playback.utils.ts +1 -717
- package/test/examples/flappy_bird/browser-entry/browser-entry.spawn.utils.ts +11 -31
- package/test/examples/flappy_bird/browser-entry/browser-entry.visualization.utils.ts +15 -893
- package/test/examples/flappy_bird/browser-entry/host/README.md +307 -0
- package/test/examples/flappy_bird/browser-entry/host/host.resize.service.ts +1 -295
- package/test/examples/flappy_bird/browser-entry/host/host.ts +562 -6
- package/test/examples/flappy_bird/browser-entry/host/resize/README.md +274 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.constants.ts +31 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.services.ts +360 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.ts +117 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.types.ts +63 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.utils.ts +250 -0
- package/test/examples/flappy_bird/browser-entry/network-view/README.md +399 -0
- package/test/examples/flappy_bird/browser-entry/network-view/network-view.topology.utils.ts +255 -0
- package/test/examples/flappy_bird/browser-entry/network-view/network-view.ts +802 -7
- package/test/examples/flappy_bird/browser-entry/playback/README.md +684 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/README.md +277 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/README.md +770 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.cache.services.ts +178 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.constants.ts +107 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.geometry.utils.ts +518 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.math.utils.ts +117 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.pulse.utils.ts +233 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.services.ts +211 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.ts +48 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.types.ts +212 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.utils.ts +81 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.cache.services.ts +96 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.constants.ts +62 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.services.ts +244 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.ts +53 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.types.ts +68 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.utils.ts +100 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/README.md +310 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.service.ts +92 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.services.ts +272 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.types.ts +39 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.utils.ts +493 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.constants.ts +1 -1
- package/test/examples/flappy_bird/browser-entry/playback/playback.frame-render.service.ts +4 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.snapshot.utils.ts +44 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.starfield.service.ts +39 -122
- package/test/examples/flappy_bird/browser-entry/playback/playback.starfield.services.ts +272 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.starfield.types.ts +62 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.starfield.utils.ts +11 -4
- package/test/examples/flappy_bird/browser-entry/playback/playback.ts +409 -8
- package/test/examples/flappy_bird/browser-entry/playback/playback.types.ts +4 -12
- package/test/examples/flappy_bird/browser-entry/runtime/README.md +235 -0
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.evolution-launch.service.ts +45 -0
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.lifecycle.service.ts +81 -0
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.startup.service.ts +74 -0
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.ts +31 -121
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.types.ts +36 -0
- package/test/examples/flappy_bird/browser-entry/visualization/README.md +557 -0
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.constants.ts +110 -0
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.draw.service.ts +957 -19
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.legend.utils.ts +138 -3
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.topology.utils.ts +3 -27
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.ts +1 -23
- package/test/examples/flappy_bird/browser-entry/worker-channel/README.md +156 -0
- package/test/examples/flappy_bird/constants/README.md +1179 -0
- package/test/examples/flappy_bird/constants/constants.network-view.ts +24 -0
- package/test/examples/flappy_bird/constants/constants.palette.ts +7 -0
- package/test/examples/flappy_bird/constants/constants.starfield.ts +78 -3
- package/test/examples/flappy_bird/environment/README.md +143 -0
- package/test/examples/flappy_bird/environment/environment.observation.utils.ts +1 -19
- package/test/examples/flappy_bird/environment/environment.step.service.ts +3 -66
- package/test/examples/flappy_bird/evaluation/README.md +130 -0
- package/test/examples/flappy_bird/evaluation/evaluation.fitness.utils.ts +1 -1
- package/test/examples/flappy_bird/evaluation/evaluation.rollout.service.ts +5 -375
- package/test/examples/flappy_bird/evaluation/rollout/README.md +291 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.constants.ts +30 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.service.ts +58 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.services.ts +310 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.types.ts +56 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.utils.ts +368 -0
- package/test/examples/flappy_bird/flappy-evolution-worker/README.md +618 -0
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.playback.service.ts +7 -7
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.simulation.frame.service.ts +364 -0
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.simulation.types.ts +14 -0
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.simulation.utils.ts +4 -201
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.ts +184 -345
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.warm-start.service.ts +291 -0
- package/test/examples/flappy_bird/flappy.simulation.shared.utils.ts +5 -0
- package/test/examples/flappy_bird/simulation-shared/README.md +417 -0
- package/test/examples/flappy_bird/simulation-shared/observation/README.md +183 -0
- package/test/examples/flappy_bird/simulation-shared/observation/observation.features.utils.ts +301 -0
- package/test/examples/flappy_bird/simulation-shared/observation/observation.ts +9 -0
- package/test/examples/flappy_bird/simulation-shared/observation/observation.vector.utils.ts +59 -0
- package/test/examples/flappy_bird/simulation-shared/simulation-shared.observation.utils.ts +5 -403
- package/test/examples/flappy_bird/simulation-shared/simulation-shared.spawn.utils.ts +20 -6
- package/test/examples/flappy_bird/{evaluation/evaluation.statistics.utils.ts → simulation-shared/simulation-shared.statistics.utils.ts} +23 -8
- package/test/examples/flappy_bird/trainer/README.md +563 -0
- package/test/examples/flappy_bird/trainer/evaluation/README.md +199 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.constants.ts +9 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.services.ts +73 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.ts +165 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.types.ts +25 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.utils.ts +161 -0
- package/test/examples/flappy_bird/trainer/trainer.evaluation.service.ts +13 -0
- package/test/examples/flappy_bird/trainer/trainer.report.service.services.ts +181 -0
- package/test/examples/flappy_bird/trainer/trainer.report.service.ts +126 -0
- package/test/examples/flappy_bird/trainer/trainer.selection.utils.ts +89 -0
- package/test/examples/flappy_bird/trainer/trainer.ts +11 -553
- package/test/examples/flappy_bird/browser-entry/browser-entry.utils.ts +0 -12
- package/test/examples/flappy_bird/environment/environment.ts +0 -7
- package/test/examples/flappy_bird/evaluation/evaluation.ts +0 -7
- package/test/examples/flappy_bird/simulation-shared/simulation-shared.ts +0 -15
- package/test/examples/flappy_bird/trainer/trainer.statistics.utils.ts +0 -78
|
@@ -1,68 +1,3 @@
|
|
|
1
|
-
import Network from '../../../../src/architecture/network';
|
|
2
|
-
import {
|
|
3
|
-
FLAPPY_MONOSPACE_FONT_FAMILY,
|
|
4
|
-
FLAPPY_NEON_PALETTE,
|
|
5
|
-
FLAPPY_NETWORK_HEADER_FONT_SIZE_PX,
|
|
6
|
-
FLAPPY_NETWORK_HEADER_TEXT_COLOR,
|
|
7
|
-
FLAPPY_NETWORK_HIDDEN_NODE_STROKE_COLOR,
|
|
8
|
-
FLAPPY_NETWORK_LEGEND_BACKGROUND,
|
|
9
|
-
FLAPPY_NETWORK_LEGEND_BIAS_TITLE_COLOR,
|
|
10
|
-
FLAPPY_NETWORK_LEGEND_BOTTOM_PADDING_PX,
|
|
11
|
-
FLAPPY_NETWORK_LEGEND_COMPACT_FONT_SIZE_PX,
|
|
12
|
-
FLAPPY_NETWORK_LEGEND_COMPACT_HEIGHT_THRESHOLD_PX,
|
|
13
|
-
FLAPPY_NETWORK_LEGEND_COMPACT_ROW_HEIGHT_PX,
|
|
14
|
-
FLAPPY_NETWORK_LEGEND_COMPACT_SECTION_GAP_PX,
|
|
15
|
-
FLAPPY_NETWORK_LEGEND_COMPACT_SECTION_TITLE_HEIGHT_PX,
|
|
16
|
-
FLAPPY_NETWORK_LEGEND_COMPACT_WIDTH_PX,
|
|
17
|
-
FLAPPY_NETWORK_LEGEND_COMPACT_WIDTH_THRESHOLD_PX,
|
|
18
|
-
FLAPPY_NETWORK_LEGEND_CONNECTION_LINE_WIDTH_PX,
|
|
19
|
-
FLAPPY_NETWORK_LEGEND_CONNECTION_TITLE_COLOR,
|
|
20
|
-
FLAPPY_NETWORK_LEGEND_HEADER_COLOR,
|
|
21
|
-
FLAPPY_NETWORK_LEGEND_HEADER_HEIGHT_PX,
|
|
22
|
-
FLAPPY_NETWORK_LEGEND_MARGIN_PX,
|
|
23
|
-
FLAPPY_NETWORK_LEGEND_MIN_TOP_PX,
|
|
24
|
-
FLAPPY_NETWORK_LEGEND_REGULAR_FONT_SIZE_PX,
|
|
25
|
-
FLAPPY_NETWORK_LEGEND_REGULAR_ROW_HEIGHT_PX,
|
|
26
|
-
FLAPPY_NETWORK_LEGEND_REGULAR_SECTION_GAP_PX,
|
|
27
|
-
FLAPPY_NETWORK_LEGEND_REGULAR_SECTION_TITLE_HEIGHT_PX,
|
|
28
|
-
FLAPPY_NETWORK_LEGEND_REGULAR_WIDTH_PX,
|
|
29
|
-
FLAPPY_NETWORK_LEGEND_ROW_TEXT_COLOR,
|
|
30
|
-
FLAPPY_NETWORK_LEGEND_TARGET_TOP_PX,
|
|
31
|
-
FLAPPY_NETWORK_LEGEND_TOP_LEFT_THRESHOLD_PX,
|
|
32
|
-
FLAPPY_NETWORK_MIN_LABEL_HEIGHT_PX,
|
|
33
|
-
FLAPPY_NETWORK_NODE_LABEL_FONT_WEIGHT,
|
|
34
|
-
FLAPPY_NETWORK_NODE_LABEL_FILL_COLOR,
|
|
35
|
-
FLAPPY_NETWORK_NODE_LABEL_SIZE_RATIO,
|
|
36
|
-
FLAPPY_NETWORK_OUTPUT_NODE_GLOW_COLOR,
|
|
37
|
-
FLAPPY_NETWORK_OUTPUT_NODE_STROKE_COLOR,
|
|
38
|
-
FLAPPY_VIEWPORT_NETWORK_OVERLAY_HIDDEN_BREAKPOINT_PX,
|
|
39
|
-
} from '../constants/constants';
|
|
40
|
-
import { applyAlphaToHexColor, clamp } from './browser-entry.math.utils';
|
|
41
|
-
import type {
|
|
42
|
-
ColorLegendRow,
|
|
43
|
-
NetworkLegendLayout,
|
|
44
|
-
NetworkNodeDimensionsLike,
|
|
45
|
-
PositionedNetworkNodeLike,
|
|
46
|
-
VisualNetworkConnectionLike,
|
|
47
|
-
VisualNetworkNodeLike,
|
|
48
|
-
} from './browser-entry.types';
|
|
49
|
-
import type {
|
|
50
|
-
DynamicColorScale,
|
|
51
|
-
NetworkVisualizationColorScales,
|
|
52
|
-
} from './visualization/visualization.types';
|
|
53
|
-
import {
|
|
54
|
-
FLAPPY_NETWORK_DOTTED_CONNECTION_ALIGNMENT_EPSILON,
|
|
55
|
-
FLAPPY_NETWORK_DOTTED_CONNECTION_SQUARE_SIDE_PX,
|
|
56
|
-
FLAPPY_NETWORK_DOTTED_CONNECTION_STEP_COMPACT_RATIO,
|
|
57
|
-
FLAPPY_NETWORK_DOTTED_CONNECTION_WIDTH_SPACING_RATIO,
|
|
58
|
-
} from './visualization/visualization.constants';
|
|
59
|
-
import { assertFiniteLegendBound } from './visualization/visualization.errors';
|
|
60
|
-
import {
|
|
61
|
-
resolveNetworkVisualizationColorScales,
|
|
62
|
-
resolveTierColor,
|
|
63
|
-
} from './visualization/visualization.colors.utils';
|
|
64
|
-
import { formatNodeBiasLabel } from './visualization/visualization.topology.utils';
|
|
65
|
-
|
|
66
1
|
export {
|
|
67
2
|
createLogDivergingColorTiers,
|
|
68
3
|
resolveBiasRangeColor,
|
|
@@ -70,831 +5,18 @@ export {
|
|
|
70
5
|
resolveNetworkVisualizationColorScales,
|
|
71
6
|
resolveTierColor,
|
|
72
7
|
} from './visualization/visualization.colors.utils';
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
? scale.minimumValue
|
|
89
|
-
: scale.tiers[tierIndex - 1].upperBound;
|
|
90
|
-
return {
|
|
91
|
-
label: `${formatLegendBound(lowerBound)} <= ${symbol} <= ${formatLegendBound(tier.upperBound)}`,
|
|
92
|
-
color: tier.color,
|
|
93
|
-
minimumValue: lowerBound,
|
|
94
|
-
maximumValue: tier.upperBound,
|
|
95
|
-
};
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Resolves network legend layout from canvas constraints.
|
|
101
|
-
*
|
|
102
|
-
* @param context - Render context.
|
|
103
|
-
* @param connectionLegendRows - Connection legend rows.
|
|
104
|
-
* @param biasLegendRows - Bias legend rows.
|
|
105
|
-
* @returns Computed legend layout.
|
|
106
|
-
*/
|
|
107
|
-
export function resolveNetworkLegendLayout(
|
|
108
|
-
context: CanvasRenderingContext2D,
|
|
109
|
-
connectionLegendRows: ColorLegendRow[],
|
|
110
|
-
biasLegendRows: ColorLegendRow[],
|
|
111
|
-
): NetworkLegendLayout {
|
|
112
|
-
// Step 1: Resolve compact/regular legend mode from canvas constraints.
|
|
113
|
-
const compactLegend =
|
|
114
|
-
context.canvas.width < FLAPPY_NETWORK_LEGEND_COMPACT_WIDTH_THRESHOLD_PX ||
|
|
115
|
-
context.canvas.height < FLAPPY_NETWORK_LEGEND_COMPACT_HEIGHT_THRESHOLD_PX;
|
|
116
|
-
const legendWidthPx = compactLegend
|
|
117
|
-
? FLAPPY_NETWORK_LEGEND_COMPACT_WIDTH_PX
|
|
118
|
-
: FLAPPY_NETWORK_LEGEND_REGULAR_WIDTH_PX;
|
|
119
|
-
const legendHeaderHeightPx = FLAPPY_NETWORK_LEGEND_HEADER_HEIGHT_PX;
|
|
120
|
-
const legendSectionTitleHeightPx = compactLegend
|
|
121
|
-
? FLAPPY_NETWORK_LEGEND_COMPACT_SECTION_TITLE_HEIGHT_PX
|
|
122
|
-
: FLAPPY_NETWORK_LEGEND_REGULAR_SECTION_TITLE_HEIGHT_PX;
|
|
123
|
-
const legendRowHeightPx = compactLegend
|
|
124
|
-
? FLAPPY_NETWORK_LEGEND_COMPACT_ROW_HEIGHT_PX
|
|
125
|
-
: FLAPPY_NETWORK_LEGEND_REGULAR_ROW_HEIGHT_PX;
|
|
126
|
-
const legendSectionGapPx = compactLegend
|
|
127
|
-
? FLAPPY_NETWORK_LEGEND_COMPACT_SECTION_GAP_PX
|
|
128
|
-
: FLAPPY_NETWORK_LEGEND_REGULAR_SECTION_GAP_PX;
|
|
129
|
-
|
|
130
|
-
// Step 2: Compute full legend panel height from section and row geometry.
|
|
131
|
-
const legendBottomPaddingPx = FLAPPY_NETWORK_LEGEND_BOTTOM_PADDING_PX;
|
|
132
|
-
const legendHeightPx =
|
|
133
|
-
legendHeaderHeightPx +
|
|
134
|
-
legendSectionTitleHeightPx +
|
|
135
|
-
connectionLegendRows.length * legendRowHeightPx +
|
|
136
|
-
legendSectionGapPx +
|
|
137
|
-
legendSectionTitleHeightPx +
|
|
138
|
-
biasLegendRows.length * legendRowHeightPx +
|
|
139
|
-
legendBottomPaddingPx;
|
|
140
|
-
const legendMarginPx = FLAPPY_NETWORK_LEGEND_MARGIN_PX;
|
|
141
|
-
const preferTopLeft =
|
|
142
|
-
context.canvas.width < FLAPPY_NETWORK_LEGEND_TOP_LEFT_THRESHOLD_PX;
|
|
143
|
-
|
|
144
|
-
// Step 3: Clamp left/top placement to visible canvas bounds.
|
|
145
|
-
const maximumLeftPx = Math.max(
|
|
146
|
-
legendMarginPx,
|
|
147
|
-
context.canvas.width - legendWidthPx - legendMarginPx,
|
|
148
|
-
);
|
|
149
|
-
const legendLeftPx = preferTopLeft ? legendMarginPx : maximumLeftPx;
|
|
150
|
-
|
|
151
|
-
const maximumTopPx = Math.max(
|
|
152
|
-
legendMarginPx,
|
|
153
|
-
context.canvas.height - legendHeightPx - legendMarginPx,
|
|
154
|
-
);
|
|
155
|
-
const minimumTopPx = Math.min(FLAPPY_NETWORK_LEGEND_MIN_TOP_PX, maximumTopPx);
|
|
156
|
-
const targetTopPx = FLAPPY_NETWORK_LEGEND_TARGET_TOP_PX;
|
|
157
|
-
const legendTopPx = clamp(targetTopPx, minimumTopPx, maximumTopPx);
|
|
158
|
-
|
|
159
|
-
return {
|
|
160
|
-
compactLegend,
|
|
161
|
-
legendLeftPx,
|
|
162
|
-
legendTopPx,
|
|
163
|
-
legendWidthPx,
|
|
164
|
-
legendHeightPx,
|
|
165
|
-
legendHeaderHeightPx,
|
|
166
|
-
legendSectionTitleHeightPx,
|
|
167
|
-
legendRowHeightPx,
|
|
168
|
-
legendSectionGapPx,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Draws weighted connection lines.
|
|
174
|
-
*
|
|
175
|
-
* @param context - Render context.
|
|
176
|
-
* @param runtimeConnections - Runtime connection list.
|
|
177
|
-
* @param positionByNodeIndex - Node layout map.
|
|
178
|
-
* @returns Nothing.
|
|
179
|
-
*/
|
|
180
|
-
export function drawWeightedConnectionsLayerInternal(
|
|
181
|
-
context: CanvasRenderingContext2D,
|
|
182
|
-
runtimeConnections: VisualNetworkConnectionLike[],
|
|
183
|
-
positionByNodeIndex: Map<number, PositionedNetworkNodeLike>,
|
|
184
|
-
connectionScale: DynamicColorScale,
|
|
185
|
-
): void {
|
|
186
|
-
runtimeConnections.forEach((runtimeConnection) => {
|
|
187
|
-
const fromNodeIndex = runtimeConnection.from?.index;
|
|
188
|
-
const toNodeIndex = runtimeConnection.to?.index;
|
|
189
|
-
if (typeof fromNodeIndex !== 'number' || typeof toNodeIndex !== 'number') {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const fromPosition = positionByNodeIndex.get(fromNodeIndex);
|
|
194
|
-
const toPosition = positionByNodeIndex.get(toNodeIndex);
|
|
195
|
-
if (!fromPosition || !toPosition) {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const connectionWeight = runtimeConnection.weight ?? 0;
|
|
200
|
-
const connectionEnabled = runtimeConnection.enabled !== false;
|
|
201
|
-
const isNegativeConnection = connectionWeight < 0;
|
|
202
|
-
const baseColor = resolveTierColor(
|
|
203
|
-
connectionWeight,
|
|
204
|
-
connectionScale.tiers,
|
|
205
|
-
connectionScale.aboveTierColor,
|
|
206
|
-
);
|
|
207
|
-
const alphaValue = connectionEnabled ? 0.95 : 0.2;
|
|
208
|
-
const connectionColor = applyAlphaToHexColor(baseColor, alphaValue);
|
|
209
|
-
const resolvedLineWidthPx = FLAPPY_NETWORK_LEGEND_CONNECTION_LINE_WIDTH_PX;
|
|
210
|
-
|
|
211
|
-
if (isNegativeConnection) {
|
|
212
|
-
drawSquareDottedConnection(context, {
|
|
213
|
-
fromXPx: fromPosition.xPx,
|
|
214
|
-
fromYPx: fromPosition.yPx,
|
|
215
|
-
toXPx: toPosition.xPx,
|
|
216
|
-
toYPx: toPosition.yPx,
|
|
217
|
-
color: connectionColor,
|
|
218
|
-
lineWidthPx: resolvedLineWidthPx,
|
|
219
|
-
});
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
context.strokeStyle = connectionColor;
|
|
224
|
-
context.lineWidth = resolvedLineWidthPx;
|
|
225
|
-
context.setLineDash(connectionEnabled ? [] : [5, 4]);
|
|
226
|
-
context.beginPath();
|
|
227
|
-
context.moveTo(fromPosition.xPx, fromPosition.yPx);
|
|
228
|
-
context.lineTo(toPosition.xPx, toPosition.yPx);
|
|
229
|
-
context.stroke();
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
context.setLineDash([]);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Draws one connection as square dots along the segment.
|
|
237
|
-
*
|
|
238
|
-
* @param context - Render context.
|
|
239
|
-
* @param input - Segment and style input.
|
|
240
|
-
* @returns Nothing.
|
|
241
|
-
*/
|
|
242
|
-
function drawSquareDottedConnection(
|
|
243
|
-
context: CanvasRenderingContext2D,
|
|
244
|
-
input: {
|
|
245
|
-
fromXPx: number;
|
|
246
|
-
fromYPx: number;
|
|
247
|
-
toXPx: number;
|
|
248
|
-
toYPx: number;
|
|
249
|
-
color: string;
|
|
250
|
-
lineWidthPx: number;
|
|
251
|
-
},
|
|
252
|
-
): void {
|
|
253
|
-
const deltaXPx = input.toXPx - input.fromXPx;
|
|
254
|
-
const deltaYPx = input.toYPx - input.fromYPx;
|
|
255
|
-
const segmentLengthPx = Math.hypot(deltaXPx, deltaYPx);
|
|
256
|
-
if (segmentLengthPx <= 0) {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const squareSidePx = FLAPPY_NETWORK_DOTTED_CONNECTION_SQUARE_SIDE_PX;
|
|
261
|
-
const stepDistancePx = Math.max(
|
|
262
|
-
(squareSidePx + 2) * FLAPPY_NETWORK_DOTTED_CONNECTION_STEP_COMPACT_RATIO,
|
|
263
|
-
input.lineWidthPx *
|
|
264
|
-
FLAPPY_NETWORK_DOTTED_CONNECTION_WIDTH_SPACING_RATIO *
|
|
265
|
-
FLAPPY_NETWORK_DOTTED_CONNECTION_STEP_COMPACT_RATIO,
|
|
266
|
-
);
|
|
267
|
-
const directionXPx = deltaXPx / segmentLengthPx;
|
|
268
|
-
const directionYPx = deltaYPx / segmentLengthPx;
|
|
269
|
-
const halfSquareSidePx = squareSidePx * 0.5;
|
|
270
|
-
|
|
271
|
-
context.fillStyle = input.color;
|
|
272
|
-
|
|
273
|
-
// Step 1: Stamp dots at fixed step distances so spacing is consistent
|
|
274
|
-
// regardless of segment length.
|
|
275
|
-
for (
|
|
276
|
-
let traveledDistancePx = 0;
|
|
277
|
-
traveledDistancePx <= segmentLengthPx;
|
|
278
|
-
traveledDistancePx += stepDistancePx
|
|
279
|
-
) {
|
|
280
|
-
const centerXPx = input.fromXPx + directionXPx * traveledDistancePx;
|
|
281
|
-
const centerYPx = input.fromYPx + directionYPx * traveledDistancePx;
|
|
282
|
-
|
|
283
|
-
const axisAlignedCenterXPx =
|
|
284
|
-
Math.round(
|
|
285
|
-
centerXPx +
|
|
286
|
-
directionXPx * FLAPPY_NETWORK_DOTTED_CONNECTION_ALIGNMENT_EPSILON,
|
|
287
|
-
) -
|
|
288
|
-
Math.round(
|
|
289
|
-
directionXPx * FLAPPY_NETWORK_DOTTED_CONNECTION_ALIGNMENT_EPSILON,
|
|
290
|
-
);
|
|
291
|
-
const axisAlignedCenterYPx =
|
|
292
|
-
Math.round(
|
|
293
|
-
centerYPx +
|
|
294
|
-
directionYPx * FLAPPY_NETWORK_DOTTED_CONNECTION_ALIGNMENT_EPSILON,
|
|
295
|
-
) -
|
|
296
|
-
Math.round(
|
|
297
|
-
directionYPx * FLAPPY_NETWORK_DOTTED_CONNECTION_ALIGNMENT_EPSILON,
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
context.fillRect(
|
|
301
|
-
axisAlignedCenterXPx - halfSquareSidePx,
|
|
302
|
-
axisAlignedCenterYPx - halfSquareSidePx,
|
|
303
|
-
squareSidePx,
|
|
304
|
-
squareSidePx,
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Step 2: Ensure the segment endpoint is always represented.
|
|
309
|
-
if (segmentLengthPx > 0) {
|
|
310
|
-
context.fillRect(
|
|
311
|
-
Math.round(input.toXPx - halfSquareSidePx),
|
|
312
|
-
Math.round(input.toYPx - halfSquareSidePx),
|
|
313
|
-
squareSidePx,
|
|
314
|
-
squareSidePx,
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Draws all network nodes with bias labels.
|
|
321
|
-
*
|
|
322
|
-
* @param context - Render context.
|
|
323
|
-
* @param positionedNodes - Positioned nodes.
|
|
324
|
-
* @param nodeDimensions - Node dimensions.
|
|
325
|
-
* @returns Nothing.
|
|
326
|
-
*/
|
|
327
|
-
export function drawBiasNodesLayerInternal(
|
|
328
|
-
context: CanvasRenderingContext2D,
|
|
329
|
-
positionedNodes: PositionedNetworkNodeLike[],
|
|
330
|
-
nodeDimensions: NetworkNodeDimensionsLike,
|
|
331
|
-
biasScale: DynamicColorScale,
|
|
332
|
-
): void {
|
|
333
|
-
const minimumLabelHeightPx = FLAPPY_NETWORK_MIN_LABEL_HEIGHT_PX;
|
|
334
|
-
const halfNodeWidthPx = nodeDimensions.widthPx * 0.5;
|
|
335
|
-
const hiddenNodeVerticalPaddingPx = 2;
|
|
336
|
-
|
|
337
|
-
positionedNodes.forEach((positionedNode) => {
|
|
338
|
-
const nodeBias = positionedNode.node.bias;
|
|
339
|
-
const nodeLabel = formatNodeBiasLabel(nodeBias);
|
|
340
|
-
const isOutputNode = positionedNode.node.type === 'output';
|
|
341
|
-
const nodeFillColor = isOutputNode
|
|
342
|
-
? FLAPPY_NEON_PALETTE.currentRunText
|
|
343
|
-
: resolveTierColor(nodeBias, biasScale.tiers, biasScale.aboveTierColor);
|
|
344
|
-
const nodeStrokeColor = isOutputNode
|
|
345
|
-
? FLAPPY_NETWORK_OUTPUT_NODE_STROKE_COLOR
|
|
346
|
-
: FLAPPY_NETWORK_HIDDEN_NODE_STROKE_COLOR;
|
|
347
|
-
const nodeStrokeWidthPx = isOutputNode ? 2.1 : 1.3;
|
|
348
|
-
|
|
349
|
-
const maximumReadableLabelHeightPx = Math.max(
|
|
350
|
-
minimumLabelHeightPx,
|
|
351
|
-
Math.floor(nodeDimensions.heightPx),
|
|
352
|
-
);
|
|
353
|
-
const computedLabelHeightPx = Math.floor(
|
|
354
|
-
nodeDimensions.heightPx * FLAPPY_NETWORK_NODE_LABEL_SIZE_RATIO,
|
|
355
|
-
);
|
|
356
|
-
const labelHeightPx = clamp(
|
|
357
|
-
computedLabelHeightPx,
|
|
358
|
-
minimumLabelHeightPx,
|
|
359
|
-
maximumReadableLabelHeightPx,
|
|
360
|
-
);
|
|
361
|
-
context.font = `${FLAPPY_NETWORK_NODE_LABEL_FONT_WEIGHT} ${labelHeightPx}px ${FLAPPY_MONOSPACE_FONT_FAMILY}`;
|
|
362
|
-
// Set baseline BEFORE measuring so actualBoundingBoxAscent/Descent are
|
|
363
|
-
// relative to the alphabetic baseline — not a stale 'top' from prior draws.
|
|
364
|
-
context.textBaseline = 'alphabetic';
|
|
365
|
-
const labelMetrics = context.measureText(nodeLabel);
|
|
366
|
-
const labelAscentPx =
|
|
367
|
-
labelMetrics.actualBoundingBoxAscent || labelHeightPx * 0.72;
|
|
368
|
-
const labelDescentPx =
|
|
369
|
-
labelMetrics.actualBoundingBoxDescent || labelHeightPx * 0.28;
|
|
370
|
-
const measuredLabelHeightPx = Math.max(
|
|
371
|
-
minimumLabelHeightPx,
|
|
372
|
-
Math.ceil(labelAscentPx + labelDescentPx),
|
|
373
|
-
);
|
|
374
|
-
const resolvedNodeHeightPx = isOutputNode
|
|
375
|
-
? Math.max(4, nodeDimensions.heightPx - 2)
|
|
376
|
-
: Math.max(
|
|
377
|
-
4,
|
|
378
|
-
Math.min(
|
|
379
|
-
nodeDimensions.heightPx,
|
|
380
|
-
measuredLabelHeightPx + hiddenNodeVerticalPaddingPx,
|
|
381
|
-
),
|
|
382
|
-
);
|
|
383
|
-
const halfNodeHeightPx = resolvedNodeHeightPx * 0.5;
|
|
384
|
-
|
|
385
|
-
context.fillStyle = nodeFillColor;
|
|
386
|
-
context.strokeStyle = nodeStrokeColor;
|
|
387
|
-
context.lineWidth = nodeStrokeWidthPx;
|
|
388
|
-
context.shadowBlur = isOutputNode ? 7 : 0;
|
|
389
|
-
context.shadowColor = isOutputNode
|
|
390
|
-
? FLAPPY_NETWORK_OUTPUT_NODE_GLOW_COLOR
|
|
391
|
-
: 'transparent';
|
|
392
|
-
context.fillRect(
|
|
393
|
-
positionedNode.xPx - halfNodeWidthPx,
|
|
394
|
-
positionedNode.yPx - halfNodeHeightPx,
|
|
395
|
-
nodeDimensions.widthPx,
|
|
396
|
-
resolvedNodeHeightPx,
|
|
397
|
-
);
|
|
398
|
-
context.strokeRect(
|
|
399
|
-
positionedNode.xPx - halfNodeWidthPx,
|
|
400
|
-
positionedNode.yPx - halfNodeHeightPx,
|
|
401
|
-
nodeDimensions.widthPx,
|
|
402
|
-
resolvedNodeHeightPx,
|
|
403
|
-
);
|
|
404
|
-
context.shadowBlur = 0;
|
|
405
|
-
context.shadowColor = 'transparent';
|
|
406
|
-
|
|
407
|
-
if (isOutputNode) {
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
context.fillStyle = FLAPPY_NETWORK_NODE_LABEL_FILL_COLOR;
|
|
412
|
-
context.textAlign = 'center';
|
|
413
|
-
const labelBaselineYPx =
|
|
414
|
-
positionedNode.yPx + (labelAscentPx - labelDescentPx) * 0.5;
|
|
415
|
-
context.fillText(nodeLabel, positionedNode.xPx, labelBaselineYPx);
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Draws network architecture header text.
|
|
421
|
-
*
|
|
422
|
-
* @param context - Render context.
|
|
423
|
-
* @param architectureLabel - Header label.
|
|
424
|
-
* @returns Nothing.
|
|
425
|
-
*/
|
|
426
|
-
export function drawNetworkVisualizationHeaderInternal(
|
|
427
|
-
context: CanvasRenderingContext2D,
|
|
428
|
-
architectureLabel: string,
|
|
429
|
-
): void {
|
|
430
|
-
context.fillStyle = FLAPPY_NETWORK_HEADER_TEXT_COLOR;
|
|
431
|
-
context.font = `${FLAPPY_NETWORK_HEADER_FONT_SIZE_PX}px ${FLAPPY_MONOSPACE_FONT_FAMILY}`;
|
|
432
|
-
context.textAlign = 'left';
|
|
433
|
-
context.textBaseline = 'top';
|
|
434
|
-
const headerLines = architectureLabel.split('\n');
|
|
435
|
-
headerLines.forEach((headerLine, lineIndex) => {
|
|
436
|
-
context.fillText(headerLine, 8, 8 + lineIndex * 12);
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* Draws the color legend for connections and node bias values.
|
|
442
|
-
*
|
|
443
|
-
* @param context - Render context.
|
|
444
|
-
* @returns Nothing.
|
|
445
|
-
*/
|
|
446
|
-
export function drawNetworkColorLegendInternal(
|
|
447
|
-
context: CanvasRenderingContext2D,
|
|
448
|
-
architectureLabel: string,
|
|
449
|
-
colorScales: NetworkVisualizationColorScales,
|
|
450
|
-
): void {
|
|
451
|
-
const viewportWidthPx =
|
|
452
|
-
context.canvas.ownerDocument?.defaultView?.innerWidth ??
|
|
453
|
-
context.canvas.width;
|
|
454
|
-
if (viewportWidthPx < FLAPPY_VIEWPORT_NETWORK_OVERLAY_HIDDEN_BREAKPOINT_PX) {
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Step 1: Build legend row models for connection and bias tiers.
|
|
459
|
-
const connectionLegendRows = createColorLegendRows(
|
|
460
|
-
colorScales.connectionScale,
|
|
461
|
-
'w',
|
|
462
|
-
);
|
|
463
|
-
const biasLegendRows = createColorLegendRows(colorScales.biasScale, 'b');
|
|
464
|
-
const legendLayout = resolveNetworkLegendLayout(
|
|
465
|
-
context,
|
|
466
|
-
connectionLegendRows,
|
|
467
|
-
biasLegendRows,
|
|
468
|
-
);
|
|
469
|
-
|
|
470
|
-
// Step 2: Draw legend panel frame and header.
|
|
471
|
-
const {
|
|
472
|
-
compactLegend,
|
|
473
|
-
legendLeftPx,
|
|
474
|
-
legendTopPx,
|
|
475
|
-
legendWidthPx,
|
|
476
|
-
legendHeightPx,
|
|
477
|
-
legendHeaderHeightPx,
|
|
478
|
-
legendSectionTitleHeightPx,
|
|
479
|
-
legendRowHeightPx,
|
|
480
|
-
legendSectionGapPx,
|
|
481
|
-
} = legendLayout;
|
|
482
|
-
|
|
483
|
-
// Step 2: Draw architecture description directly above legend panel.
|
|
484
|
-
const architectureLines = architectureLabel.split('\n');
|
|
485
|
-
const architectureLineHeightPx = 12;
|
|
486
|
-
const architectureTextTopPx = Math.max(
|
|
487
|
-
4,
|
|
488
|
-
legendTopPx - architectureLines.length * architectureLineHeightPx - 4,
|
|
489
|
-
);
|
|
490
|
-
|
|
491
|
-
context.fillStyle = FLAPPY_NETWORK_HEADER_TEXT_COLOR;
|
|
492
|
-
context.font = `${FLAPPY_NETWORK_HEADER_FONT_SIZE_PX}px ${FLAPPY_MONOSPACE_FONT_FAMILY}`;
|
|
493
|
-
context.textAlign = 'left';
|
|
494
|
-
context.textBaseline = 'top';
|
|
495
|
-
architectureLines.forEach((architectureLine, lineIndex) => {
|
|
496
|
-
context.fillText(
|
|
497
|
-
architectureLine,
|
|
498
|
-
legendLeftPx + 8,
|
|
499
|
-
architectureTextTopPx + lineIndex * architectureLineHeightPx,
|
|
500
|
-
);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// Step 3: Draw legend panel frame and header.
|
|
504
|
-
context.fillStyle = FLAPPY_NETWORK_LEGEND_BACKGROUND;
|
|
505
|
-
context.strokeStyle = FLAPPY_NEON_PALETTE.statusText;
|
|
506
|
-
context.lineWidth = 1;
|
|
507
|
-
context.fillRect(legendLeftPx, legendTopPx, legendWidthPx, legendHeightPx);
|
|
508
|
-
context.strokeRect(legendLeftPx, legendTopPx, legendWidthPx, legendHeightPx);
|
|
509
|
-
|
|
510
|
-
context.fillStyle = FLAPPY_NETWORK_LEGEND_HEADER_COLOR;
|
|
511
|
-
context.font = `${compactLegend ? FLAPPY_NETWORK_LEGEND_COMPACT_FONT_SIZE_PX : FLAPPY_NETWORK_LEGEND_REGULAR_FONT_SIZE_PX}px ${FLAPPY_MONOSPACE_FONT_FAMILY}`;
|
|
512
|
-
context.textAlign = 'left';
|
|
513
|
-
context.textBaseline = 'top';
|
|
514
|
-
context.fillText('Legend', legendLeftPx + 8, legendTopPx + 6);
|
|
515
|
-
|
|
516
|
-
// Step 4: Draw connection-weight section and row entries.
|
|
517
|
-
context.fillStyle = FLAPPY_NETWORK_LEGEND_CONNECTION_TITLE_COLOR;
|
|
518
|
-
const connectionSectionTopPx = legendTopPx + legendHeaderHeightPx;
|
|
519
|
-
context.fillText(
|
|
520
|
-
'Connection weight',
|
|
521
|
-
legendLeftPx + 8,
|
|
522
|
-
connectionSectionTopPx,
|
|
523
|
-
);
|
|
524
|
-
|
|
525
|
-
connectionLegendRows.forEach((legendRow, legendRowIndex) => {
|
|
526
|
-
const rowTopPx =
|
|
527
|
-
connectionSectionTopPx +
|
|
528
|
-
legendSectionTitleHeightPx +
|
|
529
|
-
legendRowIndex * legendRowHeightPx;
|
|
530
|
-
const sampleStartXPx = legendLeftPx + 8;
|
|
531
|
-
const sampleEndXPx = legendLeftPx + 28;
|
|
532
|
-
const sampleYPx = rowTopPx + 4;
|
|
533
|
-
|
|
534
|
-
if (legendRow.maximumValue <= 0) {
|
|
535
|
-
drawSquareDottedConnection(context, {
|
|
536
|
-
fromXPx: sampleStartXPx,
|
|
537
|
-
fromYPx: sampleYPx,
|
|
538
|
-
toXPx: sampleEndXPx,
|
|
539
|
-
toYPx: sampleYPx,
|
|
540
|
-
color: legendRow.color,
|
|
541
|
-
lineWidthPx: FLAPPY_NETWORK_LEGEND_CONNECTION_LINE_WIDTH_PX,
|
|
542
|
-
});
|
|
543
|
-
} else {
|
|
544
|
-
context.strokeStyle = legendRow.color;
|
|
545
|
-
context.lineWidth = FLAPPY_NETWORK_LEGEND_CONNECTION_LINE_WIDTH_PX;
|
|
546
|
-
context.beginPath();
|
|
547
|
-
context.moveTo(sampleStartXPx, sampleYPx);
|
|
548
|
-
context.lineTo(sampleEndXPx, sampleYPx);
|
|
549
|
-
context.stroke();
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
context.fillStyle = FLAPPY_NETWORK_LEGEND_ROW_TEXT_COLOR;
|
|
553
|
-
context.fillText(legendRow.label, legendLeftPx + 32, rowTopPx - 1);
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
// Step 5: Draw node-bias section and row entries.
|
|
557
|
-
context.fillStyle = FLAPPY_NETWORK_LEGEND_BIAS_TITLE_COLOR;
|
|
558
|
-
const biasSectionTopPx =
|
|
559
|
-
connectionSectionTopPx +
|
|
560
|
-
legendSectionTitleHeightPx +
|
|
561
|
-
connectionLegendRows.length * legendRowHeightPx +
|
|
562
|
-
legendSectionGapPx;
|
|
563
|
-
context.fillText('Node bias', legendLeftPx + 8, biasSectionTopPx);
|
|
564
|
-
|
|
565
|
-
biasLegendRows.forEach((legendRow, legendRowIndex) => {
|
|
566
|
-
const rowTopPx =
|
|
567
|
-
biasSectionTopPx +
|
|
568
|
-
legendSectionTitleHeightPx +
|
|
569
|
-
legendRowIndex * legendRowHeightPx;
|
|
570
|
-
context.fillStyle = legendRow.color;
|
|
571
|
-
context.beginPath();
|
|
572
|
-
context.rect(legendLeftPx + 10, rowTopPx + 1, 6, 6);
|
|
573
|
-
context.fill();
|
|
574
|
-
|
|
575
|
-
context.fillStyle = FLAPPY_NETWORK_LEGEND_ROW_TEXT_COLOR;
|
|
576
|
-
context.fillText(legendRow.label, legendLeftPx + 22, rowTopPx - 1);
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
/**
|
|
581
|
-
* Resolves default legend layout from internal tier definitions.
|
|
582
|
-
*
|
|
583
|
-
* @param context - Render context.
|
|
584
|
-
* @returns Legend layout.
|
|
585
|
-
*/
|
|
586
|
-
export function resolveDefaultNetworkLegendLayoutInternal(
|
|
587
|
-
context: CanvasRenderingContext2D,
|
|
588
|
-
network: Network | undefined,
|
|
589
|
-
): NetworkLegendLayout {
|
|
590
|
-
const colorScales = resolveNetworkVisualizationColorScales(network);
|
|
591
|
-
const connectionLegendRows = createColorLegendRows(
|
|
592
|
-
colorScales.connectionScale,
|
|
593
|
-
'w',
|
|
594
|
-
);
|
|
595
|
-
const biasLegendRows = createColorLegendRows(colorScales.biasScale, 'b');
|
|
596
|
-
return resolveNetworkLegendLayout(
|
|
597
|
-
context,
|
|
598
|
-
connectionLegendRows,
|
|
599
|
-
biasLegendRows,
|
|
600
|
-
);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
/**
|
|
604
|
-
* Formats node bias labels with fixed sign and precision.
|
|
605
|
-
*
|
|
606
|
-
* @param nodeBias - Node bias value.
|
|
607
|
-
* @returns Label text.
|
|
608
|
-
*/
|
|
609
|
-
export function formatNodeBiasLabelInternal(nodeBias: number): string {
|
|
610
|
-
const roundedBias = Number.isFinite(nodeBias) ? nodeBias : 0;
|
|
611
|
-
return `${roundedBias >= 0 ? '+' : ''}${roundedBias.toFixed(2)}`;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
/**
|
|
615
|
-
* Resolves layered node groups for visualization.
|
|
616
|
-
*
|
|
617
|
-
* @param network - Runtime network instance.
|
|
618
|
-
* @param inputSize - Input count fallback.
|
|
619
|
-
* @param outputSize - Output count fallback.
|
|
620
|
-
* @returns Layered nodes for rendering.
|
|
621
|
-
*/
|
|
622
|
-
export function resolveNetworkVisualizationLayersInternal(
|
|
623
|
-
network: Network | undefined,
|
|
624
|
-
inputSize: number,
|
|
625
|
-
outputSize: number,
|
|
626
|
-
): VisualNetworkNodeLike[][] {
|
|
627
|
-
// Step 1: Build fallback two-layer structure when no network is available.
|
|
628
|
-
if (!network) {
|
|
629
|
-
return [
|
|
630
|
-
Array.from({ length: inputSize }, (_unusedValue, inputNodeIndex) => ({
|
|
631
|
-
index: inputNodeIndex,
|
|
632
|
-
type: 'input',
|
|
633
|
-
bias: 0,
|
|
634
|
-
})),
|
|
635
|
-
Array.from({ length: outputSize }, (_unusedValue, outputNodeIndex) => ({
|
|
636
|
-
index: inputSize + outputNodeIndex,
|
|
637
|
-
type: 'output',
|
|
638
|
-
bias: 0,
|
|
639
|
-
})),
|
|
640
|
-
];
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Step 2: Normalize runtime node shape into visualization node model.
|
|
644
|
-
const runtimeNodes = (
|
|
645
|
-
(network.nodes ?? []) as Array<{
|
|
646
|
-
index?: number;
|
|
647
|
-
type?: string;
|
|
648
|
-
bias?: number;
|
|
649
|
-
layer?: number;
|
|
650
|
-
}>
|
|
651
|
-
).map((runtimeNode, fallbackNodeIndex) => ({
|
|
652
|
-
index:
|
|
653
|
-
typeof runtimeNode.index === 'number'
|
|
654
|
-
? runtimeNode.index
|
|
655
|
-
: fallbackNodeIndex,
|
|
656
|
-
type: runtimeNode.type ?? 'hidden',
|
|
657
|
-
bias: runtimeNode.bias ?? 0,
|
|
658
|
-
layer: runtimeNode.layer,
|
|
659
|
-
}));
|
|
660
|
-
|
|
661
|
-
const inputAndConstantNodes = runtimeNodes
|
|
662
|
-
.filter(
|
|
663
|
-
(runtimeNode) =>
|
|
664
|
-
runtimeNode.type === 'input' || runtimeNode.type === 'constant',
|
|
665
|
-
)
|
|
666
|
-
.toSorted((leftNode, rightNode) => leftNode.index - rightNode.index);
|
|
667
|
-
|
|
668
|
-
const outputNodes = runtimeNodes
|
|
669
|
-
.filter((runtimeNode) => runtimeNode.type === 'output')
|
|
670
|
-
.toSorted((leftNode, rightNode) => leftNode.index - rightNode.index);
|
|
671
|
-
|
|
672
|
-
const hiddenNodes = runtimeNodes.filter(
|
|
673
|
-
(runtimeNode) =>
|
|
674
|
-
runtimeNode.type !== 'input' &&
|
|
675
|
-
runtimeNode.type !== 'constant' &&
|
|
676
|
-
runtimeNode.type !== 'output',
|
|
677
|
-
);
|
|
678
|
-
|
|
679
|
-
// Step 3: Resolve hidden-layer grouping (metadata first, topology fallback).
|
|
680
|
-
const hiddenLayersByMetadata = groupHiddenNodesByLayerMetadata(hiddenNodes);
|
|
681
|
-
const hiddenLayers =
|
|
682
|
-
hiddenLayersByMetadata.length > 0
|
|
683
|
-
? hiddenLayersByMetadata
|
|
684
|
-
: groupHiddenNodesByTopology(network, runtimeNodes, hiddenNodes);
|
|
685
|
-
|
|
686
|
-
const layeredNodes = [
|
|
687
|
-
inputAndConstantNodes,
|
|
688
|
-
...hiddenLayers,
|
|
689
|
-
outputNodes,
|
|
690
|
-
].filter((layerNodes) => layerNodes.length > 0);
|
|
691
|
-
|
|
692
|
-
// Step 4: Return layered representation with final fallback.
|
|
693
|
-
return layeredNodes.length > 0 ? layeredNodes : [runtimeNodes];
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* Groups hidden nodes by layer metadata.
|
|
698
|
-
*
|
|
699
|
-
* @param hiddenNodes - Hidden nodes.
|
|
700
|
-
* @returns Layer groups.
|
|
701
|
-
*/
|
|
702
|
-
function groupHiddenNodesByLayerMetadata(
|
|
703
|
-
hiddenNodes: VisualNetworkNodeLike[],
|
|
704
|
-
): VisualNetworkNodeLike[][] {
|
|
705
|
-
const hiddenNodesWithLayer = hiddenNodes.filter(
|
|
706
|
-
(hiddenNode) => typeof hiddenNode.layer === 'number',
|
|
707
|
-
);
|
|
708
|
-
if (hiddenNodesWithLayer.length === 0) {
|
|
709
|
-
return [];
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
const nodesByLayer = new Map<number, VisualNetworkNodeLike[]>();
|
|
713
|
-
hiddenNodesWithLayer.forEach((hiddenNode) => {
|
|
714
|
-
const layerIndex = hiddenNode.layer as number;
|
|
715
|
-
const existingLayerNodes = nodesByLayer.get(layerIndex) ?? [];
|
|
716
|
-
existingLayerNodes.push(hiddenNode);
|
|
717
|
-
nodesByLayer.set(layerIndex, existingLayerNodes);
|
|
718
|
-
});
|
|
719
|
-
|
|
720
|
-
return [...nodesByLayer.entries()]
|
|
721
|
-
.toSorted(
|
|
722
|
-
(leftLayerEntry, rightLayerEntry) =>
|
|
723
|
-
leftLayerEntry[0] - rightLayerEntry[0],
|
|
724
|
-
)
|
|
725
|
-
.map((layerEntry) =>
|
|
726
|
-
layerEntry[1].toSorted(
|
|
727
|
-
(leftNode, rightNode) => leftNode.index - rightNode.index,
|
|
728
|
-
),
|
|
729
|
-
);
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/**
|
|
733
|
-
* Groups hidden nodes by topology-derived depth.
|
|
734
|
-
*
|
|
735
|
-
* @param network - Runtime network.
|
|
736
|
-
* @param runtimeNodes - Runtime node list.
|
|
737
|
-
* @param hiddenNodes - Hidden node list.
|
|
738
|
-
* @returns Layer groups.
|
|
739
|
-
*/
|
|
740
|
-
function groupHiddenNodesByTopology(
|
|
741
|
-
network: Network,
|
|
742
|
-
runtimeNodes: VisualNetworkNodeLike[],
|
|
743
|
-
hiddenNodes: VisualNetworkNodeLike[],
|
|
744
|
-
): VisualNetworkNodeLike[][] {
|
|
745
|
-
if (hiddenNodes.length === 0) {
|
|
746
|
-
return [];
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
const hiddenDepthByNodeIndex = resolveHiddenNodeDepthByTopology(
|
|
750
|
-
runtimeNodes,
|
|
751
|
-
(network.connections ?? []) as VisualNetworkConnectionLike[],
|
|
752
|
-
);
|
|
753
|
-
const nodesByDepth = new Map<number, VisualNetworkNodeLike[]>();
|
|
754
|
-
|
|
755
|
-
hiddenNodes.forEach((hiddenNode) => {
|
|
756
|
-
const depth = hiddenDepthByNodeIndex.get(hiddenNode.index) ?? 1;
|
|
757
|
-
const existingDepthNodes = nodesByDepth.get(depth) ?? [];
|
|
758
|
-
existingDepthNodes.push(hiddenNode);
|
|
759
|
-
nodesByDepth.set(depth, existingDepthNodes);
|
|
760
|
-
});
|
|
761
|
-
|
|
762
|
-
return [...nodesByDepth.entries()]
|
|
763
|
-
.toSorted(
|
|
764
|
-
(leftDepthEntry, rightDepthEntry) =>
|
|
765
|
-
leftDepthEntry[0] - rightDepthEntry[0],
|
|
766
|
-
)
|
|
767
|
-
.map((depthEntry) =>
|
|
768
|
-
depthEntry[1].toSorted(
|
|
769
|
-
(leftNode, rightNode) => leftNode.index - rightNode.index,
|
|
770
|
-
),
|
|
771
|
-
);
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
/**
|
|
775
|
-
* Resolves hidden node depth map from topology.
|
|
776
|
-
*
|
|
777
|
-
* @param runtimeNodes - Runtime nodes.
|
|
778
|
-
* @param runtimeConnections - Runtime connections.
|
|
779
|
-
* @returns Depth map.
|
|
780
|
-
*/
|
|
781
|
-
function resolveHiddenNodeDepthByTopology(
|
|
782
|
-
runtimeNodes: VisualNetworkNodeLike[],
|
|
783
|
-
runtimeConnections: VisualNetworkConnectionLike[],
|
|
784
|
-
): Map<number, number> {
|
|
785
|
-
// Step 1: Initialize node map and adjacency bookkeeping containers.
|
|
786
|
-
const nodeByIndex = new Map<number, VisualNetworkNodeLike>(
|
|
787
|
-
runtimeNodes.map((runtimeNode) => [runtimeNode.index, runtimeNode]),
|
|
788
|
-
);
|
|
789
|
-
const outgoingTargetsByNode = new Map<number, number[]>();
|
|
790
|
-
const incomingEdgeCountByNode = new Map<number, number>();
|
|
791
|
-
|
|
792
|
-
nodeByIndex.forEach((_runtimeNode, runtimeNodeIndex) => {
|
|
793
|
-
outgoingTargetsByNode.set(runtimeNodeIndex, []);
|
|
794
|
-
incomingEdgeCountByNode.set(runtimeNodeIndex, 0);
|
|
795
|
-
});
|
|
796
|
-
|
|
797
|
-
// Step 2: Populate adjacency and incoming-degree counts from enabled edges.
|
|
798
|
-
runtimeConnections.forEach((runtimeConnection) => {
|
|
799
|
-
if (runtimeConnection.enabled === false) {
|
|
800
|
-
return;
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
const fromNodeIndex = runtimeConnection.from?.index;
|
|
804
|
-
const toNodeIndex = runtimeConnection.to?.index;
|
|
805
|
-
if (
|
|
806
|
-
typeof fromNodeIndex !== 'number' ||
|
|
807
|
-
typeof toNodeIndex !== 'number' ||
|
|
808
|
-
!nodeByIndex.has(fromNodeIndex) ||
|
|
809
|
-
!nodeByIndex.has(toNodeIndex) ||
|
|
810
|
-
fromNodeIndex === toNodeIndex
|
|
811
|
-
) {
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
const outgoingTargets = outgoingTargetsByNode.get(fromNodeIndex) ?? [];
|
|
816
|
-
outgoingTargets.push(toNodeIndex);
|
|
817
|
-
outgoingTargetsByNode.set(fromNodeIndex, outgoingTargets);
|
|
818
|
-
|
|
819
|
-
incomingEdgeCountByNode.set(
|
|
820
|
-
toNodeIndex,
|
|
821
|
-
(incomingEdgeCountByNode.get(toNodeIndex) ?? 0) + 1,
|
|
822
|
-
);
|
|
823
|
-
});
|
|
824
|
-
|
|
825
|
-
// Step 3: Run Kahn topological traversal to detect cycles and ordering.
|
|
826
|
-
const topologicalQueue = [...incomingEdgeCountByNode.entries()]
|
|
827
|
-
.filter((incomingEntry) => incomingEntry[1] === 0)
|
|
828
|
-
.map((incomingEntry) => incomingEntry[0]);
|
|
829
|
-
const topologicalOrder: number[] = [];
|
|
830
|
-
|
|
831
|
-
while (topologicalQueue.length > 0) {
|
|
832
|
-
const currentNodeIndex = topologicalQueue.shift();
|
|
833
|
-
if (typeof currentNodeIndex !== 'number') {
|
|
834
|
-
continue;
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
topologicalOrder.push(currentNodeIndex);
|
|
838
|
-
|
|
839
|
-
const outgoingTargets = outgoingTargetsByNode.get(currentNodeIndex) ?? [];
|
|
840
|
-
outgoingTargets.forEach((targetNodeIndex) => {
|
|
841
|
-
const remainingIncomingCount =
|
|
842
|
-
(incomingEdgeCountByNode.get(targetNodeIndex) ?? 0) - 1;
|
|
843
|
-
incomingEdgeCountByNode.set(targetNodeIndex, remainingIncomingCount);
|
|
844
|
-
if (remainingIncomingCount === 0) {
|
|
845
|
-
topologicalQueue.push(targetNodeIndex);
|
|
846
|
-
}
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
// Step 4: Fallback to flat hidden depth when cycles exist.
|
|
851
|
-
const hasCycles = topologicalOrder.length !== nodeByIndex.size;
|
|
852
|
-
if (hasCycles) {
|
|
853
|
-
return new Map<number, number>(
|
|
854
|
-
runtimeNodes
|
|
855
|
-
.filter((runtimeNode) => runtimeNode.type === 'hidden')
|
|
856
|
-
.map((runtimeNode) => [runtimeNode.index, 1]),
|
|
857
|
-
);
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
// Step 5: Propagate depth values through topological order.
|
|
861
|
-
const depthByNodeIndex = new Map<number, number>();
|
|
862
|
-
runtimeNodes.forEach((runtimeNode) => {
|
|
863
|
-
const baseDepth =
|
|
864
|
-
runtimeNode.type === 'input' || runtimeNode.type === 'constant' ? 0 : 1;
|
|
865
|
-
depthByNodeIndex.set(runtimeNode.index, baseDepth);
|
|
866
|
-
});
|
|
867
|
-
|
|
868
|
-
topologicalOrder.forEach((fromNodeIndex) => {
|
|
869
|
-
const fromDepth = depthByNodeIndex.get(fromNodeIndex) ?? 0;
|
|
870
|
-
const outgoingTargets = outgoingTargetsByNode.get(fromNodeIndex) ?? [];
|
|
871
|
-
outgoingTargets.forEach((toNodeIndex) => {
|
|
872
|
-
const nextDepth = Math.max(
|
|
873
|
-
depthByNodeIndex.get(toNodeIndex) ?? 1,
|
|
874
|
-
fromDepth + 1,
|
|
875
|
-
);
|
|
876
|
-
depthByNodeIndex.set(toNodeIndex, nextDepth);
|
|
877
|
-
});
|
|
878
|
-
});
|
|
879
|
-
|
|
880
|
-
// Step 6: Return hidden-node depth map only.
|
|
881
|
-
return new Map<number, number>(
|
|
882
|
-
runtimeNodes
|
|
883
|
-
.filter((runtimeNode) => runtimeNode.type === 'hidden')
|
|
884
|
-
.map((runtimeNode) => [
|
|
885
|
-
runtimeNode.index,
|
|
886
|
-
depthByNodeIndex.get(runtimeNode.index) ?? 1,
|
|
887
|
-
]),
|
|
888
|
-
);
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
/**
|
|
892
|
-
* Formats a legend bound with fixed precision.
|
|
893
|
-
*
|
|
894
|
-
* @param value - Numeric bound.
|
|
895
|
-
* @returns Formatted bound string.
|
|
896
|
-
*/
|
|
897
|
-
function formatLegendBound(value: number): string {
|
|
898
|
-
assertFiniteLegendBound(value);
|
|
899
|
-
return value.toFixed(2);
|
|
900
|
-
}
|
|
8
|
+
export {
|
|
9
|
+
drawBiasNodesLayer,
|
|
10
|
+
drawNetworkColorLegend,
|
|
11
|
+
drawNetworkVisualizationHeader,
|
|
12
|
+
drawWeightedConnectionsLayer,
|
|
13
|
+
} from './visualization/visualization.draw.service';
|
|
14
|
+
export {
|
|
15
|
+
createColorLegendRows,
|
|
16
|
+
resolveDefaultNetworkLegendLayout,
|
|
17
|
+
resolveNetworkLegendLayout,
|
|
18
|
+
} from './visualization/visualization.legend.utils';
|
|
19
|
+
export {
|
|
20
|
+
formatNodeBiasLabel,
|
|
21
|
+
resolveNetworkVisualizationLayers,
|
|
22
|
+
} from './visualization/visualization.topology.utils';
|