@reicek/neataptic-ts 0.1.25 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/.github/copilot-instructions.md +11 -0
  2. package/.github/skills/trace-analyzer-extension/SKILL.md +3 -3
  3. package/.github/skills/trace-analyzer-extension/assets/extension-checklist.md +1 -1
  4. package/.github/skills/trace-analyzer-extension/references/analyzer-extension-workflow.md +1 -1
  5. package/.github/skills/trace-audit-reporting/SKILL.md +3 -3
  6. package/.github/skills/trace-audit-reporting/references/trace-analysis-workflow.md +1 -1
  7. package/package.json +19 -13
  8. package/plans/Flappy_Bird_Folder_Documentation_Pass.md +4 -4
  9. package/plans/README.md +24 -0
  10. package/plans/Roadmap.md +62 -40
  11. package/plans/analyze-trace-solid-split.plans.md +66 -0
  12. package/plans/architecture-solid-split.plans.md +9 -15
  13. package/plans/asciiMaze-typescript-repair.plans.md +1 -1
  14. package/plans/generate-docs-solid-split.plans.md +87 -0
  15. package/plans/methods-docs.plans.md +25 -1
  16. package/plans/methods-solid-split.plans.md +14 -14
  17. package/plans/neat-docs.plans.md +9 -1
  18. package/plans/neat-test-surface-repair.plans.md +1 -1
  19. package/plans/render-docs-html-solid-split.plans.md +68 -0
  20. package/plans/src-no-explicit-any-cleanup.plans.md +1 -1
  21. package/plans/utils-docs.plans.md +6 -1
  22. package/scripts/analyze-trace/analyze-trace.analysis.ts +479 -0
  23. package/scripts/analyze-trace/analyze-trace.constants.ts +35 -0
  24. package/scripts/analyze-trace/analyze-trace.io.ts +69 -0
  25. package/scripts/analyze-trace/analyze-trace.report.ts +100 -0
  26. package/scripts/analyze-trace/analyze-trace.shared.ts +116 -0
  27. package/scripts/analyze-trace/analyze-trace.ts +45 -0
  28. package/scripts/analyze-trace/analyze-trace.types.ts +72 -0
  29. package/scripts/assets/theme.css +80 -23
  30. package/scripts/copy-examples.ts +239 -0
  31. package/scripts/export-onnx.ts +223 -0
  32. package/scripts/generate-bench-tables.ts +378 -37
  33. package/scripts/generate-docs/generate-docs.constants.ts +107 -0
  34. package/scripts/generate-docs/generate-docs.order.ts +355 -0
  35. package/scripts/generate-docs/generate-docs.state.ts +31 -0
  36. package/scripts/generate-docs/generate-docs.targets.ts +165 -0
  37. package/scripts/generate-docs/generate-docs.ts +63 -0
  38. package/scripts/generate-docs/generate-docs.types.ts +112 -0
  39. package/scripts/generate-docs/output/generate-docs.output.folder-index.utils.ts +167 -0
  40. package/scripts/generate-docs/output/generate-docs.output.ordering.utils.ts +353 -0
  41. package/scripts/generate-docs/output/generate-docs.output.readme.utils.ts +420 -0
  42. package/scripts/generate-docs/output/generate-docs.output.ts +123 -0
  43. package/scripts/generate-docs/output/generate-docs.output.warnings.utils.ts +219 -0
  44. package/scripts/generate-docs/symbols/generate-docs.symbols.collection.utils.ts +365 -0
  45. package/scripts/generate-docs/symbols/generate-docs.symbols.jsdoc.utils.ts +373 -0
  46. package/scripts/generate-docs/symbols/generate-docs.symbols.normalize.utils.ts +155 -0
  47. package/scripts/generate-docs/symbols/generate-docs.symbols.render.utils.ts +149 -0
  48. package/scripts/generate-docs/symbols/generate-docs.symbols.signature.utils.ts +289 -0
  49. package/scripts/generate-docs/symbols/generate-docs.symbols.ts +11 -0
  50. package/scripts/mermaid-cli.mjs +102 -22
  51. package/scripts/mermaid-cli.ts +736 -0
  52. package/scripts/render-docs-html/render-docs-html.assets.ts +54 -0
  53. package/scripts/render-docs-html/render-docs-html.mermaid.ts +245 -0
  54. package/scripts/{render-docs-html.sidebar.ts → render-docs-html/render-docs-html.navigation.ts} +141 -144
  55. package/scripts/render-docs-html/render-docs-html.pages.ts +333 -0
  56. package/scripts/render-docs-html/render-docs-html.shared.ts +333 -0
  57. package/scripts/render-docs-html/render-docs-html.types.ts +42 -0
  58. package/scripts/render-docs-html.ts +23 -587
  59. package/scripts/run-docs.ts +238 -0
  60. package/scripts/write-dist-docs-pkg.ts +40 -0
  61. package/src/README.md +75 -75
  62. package/src/architecture/connection/README.md +5 -5
  63. package/src/architecture/layer/README.md +508 -508
  64. package/src/architecture/network/README.md +1458 -1458
  65. package/src/architecture/network/activate/README.md +694 -694
  66. package/src/architecture/network/bootstrap/README.md +77 -77
  67. package/src/architecture/network/connect/README.md +74 -74
  68. package/src/architecture/network/deterministic/README.md +135 -135
  69. package/src/architecture/network/evolve/README.md +364 -364
  70. package/src/architecture/network/gating/README.md +130 -130
  71. package/src/architecture/network/genetic/README.md +399 -399
  72. package/src/architecture/network/mutate/README.md +897 -897
  73. package/src/architecture/network/onnx/README.md +720 -720
  74. package/src/architecture/network/onnx/export/README.md +728 -728
  75. package/src/architecture/network/onnx/export/layers/README.md +450 -450
  76. package/src/architecture/network/onnx/import/README.md +618 -618
  77. package/src/architecture/network/onnx/schema/README.md +32 -32
  78. package/src/architecture/network/prune/README.md +245 -245
  79. package/src/architecture/network/remove/README.md +135 -135
  80. package/src/architecture/network/runtime/README.md +106 -106
  81. package/src/architecture/network/serialize/README.md +542 -542
  82. package/src/architecture/network/slab/README.md +608 -608
  83. package/src/architecture/network/standalone/README.md +212 -212
  84. package/src/architecture/network/stats/README.md +84 -84
  85. package/src/architecture/network/topology/README.md +465 -465
  86. package/src/architecture/network/training/README.md +200 -200
  87. package/src/architecture/node/README.md +5 -5
  88. package/src/architecture/nodePool/README.md +14 -14
  89. package/src/methods/README.md +99 -99
  90. package/src/methods/activation/README.md +189 -189
  91. package/src/methods/cost/README.md +131 -131
  92. package/src/methods/rate/README.md +86 -86
  93. package/src/multithreading/README.md +77 -77
  94. package/src/multithreading/workers/browser/README.md +8 -8
  95. package/src/multithreading/workers/node/README.md +8 -8
  96. package/src/neat/README.md +148 -148
  97. package/src/neat/adaptive/README.md +120 -120
  98. package/src/neat/adaptive/acceptance/README.md +40 -40
  99. package/src/neat/adaptive/complexity/README.md +137 -137
  100. package/src/neat/adaptive/core/README.md +197 -197
  101. package/src/neat/adaptive/lineage/README.md +90 -90
  102. package/src/neat/adaptive/mutation/README.md +284 -284
  103. package/src/neat/compat/README.md +43 -43
  104. package/src/neat/compat/core/README.md +90 -90
  105. package/src/neat/diversity/README.md +35 -35
  106. package/src/neat/diversity/core/README.md +88 -88
  107. package/src/neat/evaluate/README.md +85 -85
  108. package/src/neat/evaluate/auto-distance/README.md +75 -75
  109. package/src/neat/evaluate/entropy-compat/README.md +37 -37
  110. package/src/neat/evaluate/entropy-sharing/README.md +43 -43
  111. package/src/neat/evaluate/fitness/README.md +23 -23
  112. package/src/neat/evaluate/novelty/README.md +120 -120
  113. package/src/neat/evaluate/objectives/README.md +17 -17
  114. package/src/neat/evaluate/shared/README.md +94 -94
  115. package/src/neat/evolve/README.md +96 -96
  116. package/src/neat/evolve/adaptive/README.md +60 -60
  117. package/src/neat/evolve/objectives/README.md +63 -63
  118. package/src/neat/evolve/offspring/README.md +56 -56
  119. package/src/neat/evolve/population/README.md +171 -171
  120. package/src/neat/evolve/runtime/README.md +79 -79
  121. package/src/neat/evolve/speciation/README.md +74 -74
  122. package/src/neat/evolve/warnings/README.md +10 -10
  123. package/src/neat/export/README.md +114 -114
  124. package/src/neat/helpers/README.md +50 -50
  125. package/src/neat/init/README.md +9 -9
  126. package/src/neat/lineage/core/README.md +101 -101
  127. package/src/neat/multiobjective/category/README.md +74 -74
  128. package/src/neat/multiobjective/crowding/README.md +272 -272
  129. package/src/neat/multiobjective/dominance/README.md +171 -171
  130. package/src/neat/multiobjective/fronts/README.md +68 -68
  131. package/src/neat/multiobjective/metrics/README.md +43 -43
  132. package/src/neat/multiobjective/objectives/README.md +31 -31
  133. package/src/neat/multiobjective/shared/README.md +27 -27
  134. package/src/neat/mutation/README.md +97 -97
  135. package/src/neat/mutation/add-conn/README.md +115 -115
  136. package/src/neat/mutation/add-node/README.md +126 -126
  137. package/src/neat/mutation/flow/README.md +149 -149
  138. package/src/neat/mutation/repair/README.md +185 -185
  139. package/src/neat/mutation/select/README.md +117 -117
  140. package/src/neat/mutation/shared/README.md +32 -32
  141. package/src/neat/objectives/README.md +25 -25
  142. package/src/neat/objectives/core/README.md +67 -67
  143. package/src/neat/pruning/README.md +40 -40
  144. package/src/neat/pruning/core/README.md +171 -171
  145. package/src/neat/pruning/facade/README.md +32 -32
  146. package/src/neat/rng/README.md +104 -104
  147. package/src/neat/rng/core/README.md +137 -137
  148. package/src/neat/rng/facade/README.md +50 -50
  149. package/src/neat/selection/README.md +111 -111
  150. package/src/neat/selection/core/README.md +227 -227
  151. package/src/neat/selection/facade/README.md +61 -61
  152. package/src/neat/shared/README.md +163 -163
  153. package/src/neat/speciation/README.md +31 -31
  154. package/src/neat/speciation/threshold/README.md +35 -35
  155. package/src/neat/species/README.md +25 -25
  156. package/src/neat/species/core/README.md +20 -20
  157. package/src/neat/species/core/shared/README.md +18 -18
  158. package/src/neat/species/history/context/README.md +22 -22
  159. package/src/neat/telemetry/accessors/README.md +58 -58
  160. package/src/neat/telemetry/exports/README.md +233 -233
  161. package/src/neat/telemetry/facade/README.md +252 -252
  162. package/src/neat/telemetry/facade/archive/README.md +57 -57
  163. package/src/neat/telemetry/facade/buffer/README.md +43 -43
  164. package/src/neat/telemetry/facade/lineage/README.md +12 -12
  165. package/src/neat/telemetry/facade/objectives/README.md +44 -44
  166. package/src/neat/telemetry/facade/runtime/README.md +26 -26
  167. package/src/neat/telemetry/facade/species/README.md +27 -27
  168. package/src/neat/telemetry/metrics/README.md +696 -696
  169. package/src/neat/telemetry/recorder/README.md +57 -57
  170. package/src/neat/telemetry/types/README.md +32 -32
  171. package/src/neat/topology-intent/README.md +75 -75
  172. package/src/utils/README.md +193 -193
  173. package/test/examples/asciiMaze/browser-entry/README.md +92 -92
  174. package/test/examples/asciiMaze/dashboardManager/README.md +109 -109
  175. package/test/examples/asciiMaze/dashboardManager/telemetry/README.md +28 -28
  176. package/test/examples/asciiMaze/evolutionEngine/README.md +1527 -1527
  177. package/test/examples/asciiMaze/mazeMovement/README.md +105 -105
  178. package/test/examples/asciiMaze/mazeMovement/finalization/README.md +16 -16
  179. package/test/examples/asciiMaze/mazeMovement/policy/README.md +57 -57
  180. package/test/examples/asciiMaze/mazeMovement/runtime/README.md +52 -52
  181. package/test/examples/asciiMaze/mazeMovement/shaping/README.md +46 -46
  182. package/test/examples/flappy_bird/browser-entry/README.md +508 -508
  183. package/test/examples/flappy_bird/browser-entry/host/README.md +101 -101
  184. package/test/examples/flappy_bird/browser-entry/host/resize/README.md +144 -144
  185. package/test/examples/flappy_bird/browser-entry/network-view/README.md +194 -194
  186. package/test/examples/flappy_bird/browser-entry/playback/README.md +278 -278
  187. package/test/examples/flappy_bird/browser-entry/playback/background/README.md +129 -129
  188. package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/README.md +502 -502
  189. package/test/examples/flappy_bird/browser-entry/playback/frame-render/README.md +139 -139
  190. package/test/examples/flappy_bird/browser-entry/playback/snapshot/README.md +10 -10
  191. package/test/examples/flappy_bird/browser-entry/playback/trail/README.md +43 -43
  192. package/test/examples/flappy_bird/browser-entry/playback/worker-channel/README.md +30 -30
  193. package/test/examples/flappy_bird/browser-entry/runtime/README.md +59 -59
  194. package/test/examples/flappy_bird/browser-entry/visualization/README.md +276 -276
  195. package/test/examples/flappy_bird/browser-entry/worker-channel/README.md +16 -16
  196. package/test/examples/flappy_bird/constants/README.md +1070 -1070
  197. package/test/examples/flappy_bird/environment/README.md +22 -22
  198. package/test/examples/flappy_bird/evaluation/README.md +32 -32
  199. package/test/examples/flappy_bird/evaluation/rollout/README.md +141 -141
  200. package/test/examples/flappy_bird/flappy-evolution-worker/README.md +425 -425
  201. package/test/examples/flappy_bird/simulation-shared/README.md +170 -170
  202. package/test/examples/flappy_bird/simulation-shared/observation/README.md +109 -109
  203. package/test/examples/flappy_bird/trainer/README.md +325 -325
  204. package/test/examples/flappy_bird/trainer/evaluation/README.md +74 -74
  205. package/scripts/analyze-trace.ts +0 -590
  206. package/scripts/copy-examples.mjs +0 -114
  207. package/scripts/export-onnx.mjs +0 -86
  208. package/scripts/generate-bench-tables.mjs +0 -182
  209. package/scripts/generate-docs.ts +0 -2900
  210. package/scripts/write-dist-docs-pkg.mjs +0 -16
@@ -33,19 +33,6 @@ Keep the contract loose when you add new genome-side fields elsewhere in the
33
33
  controller. If a selection helper can still do its job from score plus opaque
34
34
  metadata, the extra fields belong outside this boundary.
35
35
 
36
- ### SelectionOptions
37
-
38
- Selection strategy settings used by the NEAT controller.
39
-
40
- These options are intentionally small because the public selection story is
41
- already taught at the root selection chapter and exposed through the stable
42
- `Neat` wrappers. The core layer only needs the knobs that alter actual parent
43
- choice mechanics: which strategy runs, how strongly POWER biases toward the
44
- front, and how TOURNAMENT sizes and probabilistic winner walks behave.
45
-
46
- Keeping this contract narrow prevents the core chapter from turning into a
47
- second facade for broader controller policy.
48
-
49
36
  ### NeatLikeWithSelection
50
37
 
51
38
  NEAT-like instance extended with selection-specific state and helpers.
@@ -76,6 +63,19 @@ data off the host.
76
63
  Read this as the per-selection call frame: one host, one population view,
77
64
  one resolved selection-options object, and one RNG source.
78
65
 
66
+ ### SelectionOptions
67
+
68
+ Selection strategy settings used by the NEAT controller.
69
+
70
+ These options are intentionally small because the public selection story is
71
+ already taught at the root selection chapter and exposed through the stable
72
+ `Neat` wrappers. The core layer only needs the knobs that alter actual parent
73
+ choice mechanics: which strategy runs, how strongly POWER biases toward the
74
+ front, and how TOURNAMENT sizes and probabilistic winner walks behave.
75
+
76
+ Keeping this contract narrow prevents the core chapter from turning into a
77
+ second facade for broader controller policy.
78
+
79
79
  ## neat/selection/core/selection.core.ts
80
80
 
81
81
  Selection mechanics used by the NEAT controller.
@@ -128,77 +128,27 @@ flowchart TD
128
128
  Tournament --> Parent
129
129
  ```
130
130
 
131
- ### selectParentByStrategy
132
-
133
- ```ts
134
- selectParentByStrategy(
135
- internal: NeatLikeWithSelection,
136
- ): GenomeWithScore
137
- ```
138
-
139
- Select a parent genome according to the configured selection strategy.
140
-
141
- This is the single dispatch point shared by the controller-facing selection
142
- helpers. It resolves the active strategy once, builds a compact
143
- {@link SelectionContext}, and then hands off to the concrete algorithm.
144
-
145
- The fallback to the first population entry is deliberate. When callers have
146
- configured an unknown strategy name, selection still returns a deterministic
147
- candidate instead of failing unexpectedly deep inside crossover or mutation
148
- flow.
149
-
150
- Parameters:
151
- - `internal` - - NEAT host containing population, options, and RNG access.
152
-
153
- Returns: A genome chosen according to the active selection strategy.
154
-
155
- Example:
156
-
157
- ```ts
158
- const parent = selectParentByStrategy(neat);
159
- const strategyName = neat.options.selection?.name;
160
- ```
161
-
162
- ### ensurePopulationEvaluated
163
-
164
- ```ts
165
- ensurePopulationEvaluated(
166
- internal: NeatLikeWithSelection,
167
- ): void
168
- ```
169
-
170
- Ensure population scores exist by running evaluation if needed.
171
-
172
- Selection treats score production as an upstream responsibility, but the
173
- controller still needs a safe guard at the point where score-dependent reads
174
- actually happen. This helper preserves that assumption: callers can ask for
175
- fittest genomes, averages, or parents without manually remembering whether
176
- evaluation already ran this generation.
177
-
178
- Parameters:
179
- - `internal` - - NEAT host containing population and evaluation support.
180
-
181
- Returns: Nothing. Evaluation is triggered only when the population is unevaluated.
182
-
183
- ### ensurePopulationSortedDescending
131
+ ### calculateFitnessTotals
184
132
 
185
133
  ```ts
186
- ensurePopulationSortedDescending(
187
- internal: NeatLikeWithSelection,
188
- ): void
134
+ calculateFitnessTotals(
135
+ population: GenomeWithScore[],
136
+ ): { totalFitness: number; minFitnessShift: number; }
189
137
  ```
190
138
 
191
- Ensure the population is sorted descending by score when out of order.
139
+ Compute the total fitness and minimal shift used by roulette selection.
192
140
 
193
- Several selection reads assume best-first order but should not pay the cost
194
- of sorting when the population is already in the expected shape. This helper
195
- preserves that cheap guard by checking only the leading edge before calling
196
- the shared in-place sort hook.
141
+ Fitness-proportionate selection must work even when a population contains
142
+ negative scores. This helper records the most-negative value, converts that
143
+ into a uniform upward shift, and returns the adjusted total that the later
144
+ threshold scan uses.
145
+ In other words, it prepares the roulette space so every genome still gets a
146
+ measurable slice even when raw scores dip below zero.
197
147
 
198
148
  Parameters:
199
- - `internal` - - NEAT host containing the current population.
149
+ - `population` - - Genomes in the current population.
200
150
 
201
- Returns: Nothing. Sorting only runs when the first two scores are out of order.
151
+ Returns: Aggregate fitness totals with the negative-score shift.
202
152
 
203
153
  ### calculateTotalScore
204
154
 
@@ -232,26 +182,6 @@ That makes this the mildest built-in pressure setting: strong enough to
232
182
  prefer the front of the sorted population, but not so aggressive that the
233
183
  champion becomes nearly inevitable on every draw.
234
184
 
235
- ### DEFAULT_TOURNAMENT_SIZE
236
-
237
- Default tournament size when none is configured.
238
-
239
- The built-in bracket stays intentionally small so tournament selection keeps
240
- some competitive pressure without collapsing into near-deterministic champion
241
- picks. In practice this means the default strategy samples just enough local
242
- competition to reward strong genomes while still letting non-champion genomes
243
- remain reachable.
244
-
245
- ### DEFAULT_TOURNAMENT_PROBABILITY
246
-
247
- Default tournament win probability when none is configured.
248
-
249
- This keeps the top sampled participant favored while still allowing weaker
250
- entrants to remain reachable later in the tournament walk. Read it as the
251
- tournament counterpart to selection pressure: a balanced default that keeps
252
- the bracket competitive instead of turning every mini-tournament into a
253
- guaranteed top-seed march.
254
-
255
185
  ### DEFAULT_SCORE
256
186
 
257
187
  Default score when a genome has no explicit score.
@@ -262,175 +192,159 @@ chapter coherence as much as runtime behavior: every inspection helper and
262
192
  parent-selection guard speaks the same "missing score" language instead of
263
193
  inventing its own local default.
264
194
 
265
- ### FIRST_INDEX
266
-
267
- First element index used by guards, fallbacks, and best-first reads.
268
-
269
- Selection logic names this index explicitly because the front of the
270
- population has semantic meaning: it is where champion reads and sorted-bias
271
- strategies begin.
272
-
273
- ### SECOND_INDEX
274
-
275
- Second element index used by the cheap leading-edge ordering guard.
276
-
277
- Comparing the first two genomes is enough for the root helpers' fast
278
- "probably already sorted" check, so this constant marks the smallest useful
279
- comparison boundary.
280
-
281
- ### LAST_INDEX_OFFSET
195
+ ### DEFAULT_TOURNAMENT_PROBABILITY
282
196
 
283
- Offset for retrieving the last element via length arithmetic.
197
+ Default tournament win probability when none is configured.
284
198
 
285
- This keeps tail access readable in places where explicit length math is more
286
- portable than `at()` for the surrounding helper shape.
199
+ This keeps the top sampled participant favored while still allowing weaker
200
+ entrants to remain reachable later in the tournament walk. Read it as the
201
+ tournament counterpart to selection pressure: a balanced default that keeps
202
+ the bracket competitive instead of turning every mini-tournament into a
203
+ guaranteed top-seed march.
287
204
 
288
- ### LOOP_INDEX_INCREMENT
205
+ ### DEFAULT_TOURNAMENT_SIZE
289
206
 
290
- Loop step used by explicit tournament and threshold walks.
207
+ Default tournament size when none is configured.
291
208
 
292
- Naming the increment makes the small index-based scans read like deliberate
293
- traversal code instead of scattered magic numbers.
209
+ The built-in bracket stays intentionally small so tournament selection keeps
210
+ some competitive pressure without collapsing into near-deterministic champion
211
+ picks. In practice this means the default strategy samples just enough local
212
+ competition to reward strong genomes while still letting non-champion genomes
213
+ remain reachable.
294
214
 
295
- ### LAST_ELEMENT_INDEX
215
+ ### ensurePopulationEvaluated
296
216
 
297
- Index used with `at()` when checking the tail of the population.
217
+ ```ts
218
+ ensurePopulationEvaluated(
219
+ internal: NeatLikeWithSelection,
220
+ ): void
221
+ ```
298
222
 
299
- The evaluation guard only needs the final genome to answer one practical
300
- question: has this generation already been scored all the way through?
223
+ Ensure population scores exist by running evaluation if needed.
301
224
 
302
- ### INITIAL_TOTAL_FITNESS
225
+ Selection treats score production as an upstream responsibility, but the
226
+ controller still needs a safe guard at the point where score-dependent reads
227
+ actually happen. This helper preserves that assumption: callers can ask for
228
+ fittest genomes, averages, or parents without manually remembering whether
229
+ evaluation already ran this generation.
303
230
 
304
- Initial accumulator value for generation-wide score folds.
231
+ Parameters:
232
+ - `internal` - - NEAT host containing population and evaluation support.
305
233
 
306
- Summary helpers begin from this neutral total so whole-population averages
307
- and other folds remain explicit about their starting score semantics.
234
+ Returns: Nothing. Evaluation is triggered only when the population is unevaluated.
308
235
 
309
- ### INITIAL_MOST_NEGATIVE_SCORE
236
+ ### ensurePopulationSortedDescending
310
237
 
311
- Initial most-negative score sentinel for shifted-fitness scans.
238
+ ```ts
239
+ ensurePopulationSortedDescending(
240
+ internal: NeatLikeWithSelection,
241
+ ): void
242
+ ```
312
243
 
313
- FITNESS_PROPORTIONATE selection may need to lift negative scores into a
314
- usable roulette space, and this sentinel marks the baseline from which that
315
- most-negative search starts.
244
+ Ensure the population is sorted descending by score when out of order.
316
245
 
317
- ### INITIAL_CUMULATIVE_FITNESS
246
+ Several selection reads assume best-first order but should not pay the cost
247
+ of sorting when the population is already in the expected shape. This helper
248
+ preserves that cheap guard by checking only the leading edge before calling
249
+ the shared in-place sort hook.
318
250
 
319
- Initial cumulative fitness value for roulette threshold scans.
251
+ Parameters:
252
+ - `internal` - - NEAT host containing the current population.
320
253
 
321
- Roulette-style selection accumulates shifted fitness as it walks the
322
- population. This zero point keeps that running threshold explicit and aligned
323
- with the rest of the selection fallback semantics.
254
+ Returns: Nothing. Sorting only runs when the first two scores are out of order.
324
255
 
325
- ### selectParentByPower
256
+ ### ensurePopulationSortedDescendingForPower
326
257
 
327
258
  ```ts
328
- selectParentByPower(
259
+ ensurePopulationSortedDescendingForPower(
329
260
  selectionContext: SelectionContext,
330
- ): GenomeWithScore
261
+ ): void
331
262
  ```
332
263
 
333
- Select a parent by power-law distribution on the sorted population.
264
+ Ensure the population is sorted descending by score for POWER selection.
334
265
 
335
- POWER selection assumes best-first ordering and then biases random choice
336
- toward the front of that ranking. Lower random samples stay near the leading
337
- genomes, while the configured exponent controls how quickly the chance falls
338
- away from the champion.
339
- Read this as the lightest built-in strategy: it does not inspect absolute
340
- score gaps, only the current descending order.
266
+ POWER selection is the only built-in strategy that depends on the population
267
+ already being rank-ordered before index sampling. The narrower guard lives
268
+ here instead of in the root chapter so the strategy can preserve that rule
269
+ without forcing unrelated selection paths to sort first.
341
270
 
342
271
  Parameters:
343
272
  - `selectionContext` - - Shared selection state.
344
273
 
345
- Returns: The chosen parent genome.
274
+ Returns: Nothing. Sorting only runs when the first two entries are out of order.
346
275
 
347
- ### selectParentByFitnessProportionate
276
+ ### FIRST_INDEX
277
+
278
+ First element index used by guards, fallbacks, and best-first reads.
279
+
280
+ Selection logic names this index explicitly because the front of the
281
+ population has semantic meaning: it is where champion reads and sorted-bias
282
+ strategies begin.
283
+
284
+ ### getRandomPopulationMember
348
285
 
349
286
  ```ts
350
- selectParentByFitnessProportionate(
287
+ getRandomPopulationMember(
351
288
  selectionContext: SelectionContext,
352
289
  ): GenomeWithScore
353
290
  ```
354
291
 
355
- Select a parent using roulette-wheel fitness proportionate selection.
292
+ Select a random population member using the configured RNG.
356
293
 
357
- This path turns the current population into a weighted threshold scan. When
358
- some genomes have negative scores, the helper first shifts the whole fitness
359
- space upward so every participant still occupies a non-negative span on the
360
- roulette wheel.
361
- That makes this strategy the most score-sensitive branch in the chapter: it
362
- reacts to relative score magnitude rather than only rank or sampled bracket
363
- ordering.
294
+ This is the small shared fallback used by roulette misses and suppressed
295
+ tournament overflow. Centralizing it here keeps every selection path tied to
296
+ the same controller RNG stream.
297
+ It also makes the fallback semantics explicit instead of hiding ad hoc random
298
+ picks inside individual strategies.
364
299
 
365
300
  Parameters:
366
301
  - `selectionContext` - - Shared selection state.
367
302
 
368
- Returns: The chosen parent genome.
303
+ Returns: Randomly chosen genome from the current population.
369
304
 
370
- ### selectParentByTournament
305
+ ### INITIAL_CUMULATIVE_FITNESS
371
306
 
372
- ```ts
373
- selectParentByTournament(
374
- selectionContext: SelectionContext,
375
- ): GenomeWithScore
376
- ```
307
+ Initial cumulative fitness value for roulette threshold scans.
377
308
 
378
- Select a parent by tournament selection.
309
+ Roulette-style selection accumulates shifted fitness as it walks the
310
+ population. This zero point keeps that running threshold explicit and aligned
311
+ with the rest of the selection fallback semantics.
379
312
 
380
- Tournament selection samples a temporary bracket, orders it by descending
381
- score, then walks from strongest to weakest using the configured win
382
- probability. This gives the controller a middle ground between pure
383
- best-first bias and fully score-proportional roulette.
384
- The sampled bracket is intentionally local: the strategy asks "who wins this
385
- small contest?" rather than "how does the whole population distribute
386
- weight?"
313
+ ### INITIAL_MOST_NEGATIVE_SCORE
387
314
 
388
- Parameters:
389
- - `selectionContext` - - Shared selection state.
315
+ Initial most-negative score sentinel for shifted-fitness scans.
390
316
 
391
- Returns: The chosen parent genome.
317
+ FITNESS_PROPORTIONATE selection may need to lift negative scores into a
318
+ usable roulette space, and this sentinel marks the baseline from which that
319
+ most-negative search starts.
392
320
 
393
- ### ensurePopulationSortedDescendingForPower
321
+ ### INITIAL_TOTAL_FITNESS
394
322
 
395
- ```ts
396
- ensurePopulationSortedDescendingForPower(
397
- selectionContext: SelectionContext,
398
- ): void
399
- ```
323
+ Initial accumulator value for generation-wide score folds.
400
324
 
401
- Ensure the population is sorted descending by score for POWER selection.
325
+ Summary helpers begin from this neutral total so whole-population averages
326
+ and other folds remain explicit about their starting score semantics.
402
327
 
403
- POWER selection is the only built-in strategy that depends on the population
404
- already being rank-ordered before index sampling. The narrower guard lives
405
- here instead of in the root chapter so the strategy can preserve that rule
406
- without forcing unrelated selection paths to sort first.
328
+ ### LAST_ELEMENT_INDEX
407
329
 
408
- Parameters:
409
- - `selectionContext` - - Shared selection state.
330
+ Index used with `at()` when checking the tail of the population.
410
331
 
411
- Returns: Nothing. Sorting only runs when the first two entries are out of order.
332
+ The evaluation guard only needs the final genome to answer one practical
333
+ question: has this generation already been scored all the way through?
412
334
 
413
- ### calculateFitnessTotals
335
+ ### LAST_INDEX_OFFSET
414
336
 
415
- ```ts
416
- calculateFitnessTotals(
417
- population: GenomeWithScore[],
418
- ): { totalFitness: number; minFitnessShift: number; }
419
- ```
337
+ Offset for retrieving the last element via length arithmetic.
420
338
 
421
- Compute the total fitness and minimal shift used by roulette selection.
339
+ This keeps tail access readable in places where explicit length math is more
340
+ portable than `at()` for the surrounding helper shape.
422
341
 
423
- Fitness-proportionate selection must work even when a population contains
424
- negative scores. This helper records the most-negative value, converts that
425
- into a uniform upward shift, and returns the adjusted total that the later
426
- threshold scan uses.
427
- In other words, it prepares the roulette space so every genome still gets a
428
- measurable slice even when raw scores dip below zero.
342
+ ### LOOP_INDEX_INCREMENT
429
343
 
430
- Parameters:
431
- - `population` - - Genomes in the current population.
344
+ Loop step used by explicit tournament and threshold walks.
432
345
 
433
- Returns: Aggregate fitness totals with the negative-score shift.
346
+ Naming the increment makes the small index-based scans read like deliberate
347
+ traversal code instead of scattered magic numbers.
434
348
 
435
349
  ### pickByShiftedThreshold
436
350
 
@@ -456,6 +370,29 @@ Parameters:
456
370
 
457
371
  Returns: The chosen genome when a threshold crossing occurs.
458
372
 
373
+ ### pickTournamentWinner
374
+
375
+ ```ts
376
+ pickTournamentWinner(
377
+ selectionContext: SelectionContext,
378
+ sortedParticipants: GenomeWithScore[],
379
+ ): GenomeWithScore
380
+ ```
381
+
382
+ Select a winner from sorted tournament participants.
383
+
384
+ After participants are sorted best-first, this helper walks the list from the
385
+ front and gives each participant a chance to win immediately. The configured
386
+ probability therefore controls how often the top entrant wins outright versus
387
+ how often weaker entrants remain reachable later in the walk.
388
+ This is what makes tournament selection tunable instead of purely greedy.
389
+
390
+ Parameters:
391
+ - `selectionContext` - - Shared selection state.
392
+ - `sortedParticipants` - - Participants sorted by descending score.
393
+
394
+ Returns: The chosen tournament winner.
395
+
459
396
  ### resolveTournamentOverflow
460
397
 
461
398
  ```ts
@@ -501,46 +438,109 @@ Parameters:
501
438
 
502
439
  Returns: Sampled participants.
503
440
 
504
- ### pickTournamentWinner
441
+ ### SECOND_INDEX
442
+
443
+ Second element index used by the cheap leading-edge ordering guard.
444
+
445
+ Comparing the first two genomes is enough for the root helpers' fast
446
+ "probably already sorted" check, so this constant marks the smallest useful
447
+ comparison boundary.
448
+
449
+ ### selectParentByFitnessProportionate
505
450
 
506
451
  ```ts
507
- pickTournamentWinner(
452
+ selectParentByFitnessProportionate(
508
453
  selectionContext: SelectionContext,
509
- sortedParticipants: GenomeWithScore[],
510
454
  ): GenomeWithScore
511
455
  ```
512
456
 
513
- Select a winner from sorted tournament participants.
457
+ Select a parent using roulette-wheel fitness proportionate selection.
514
458
 
515
- After participants are sorted best-first, this helper walks the list from the
516
- front and gives each participant a chance to win immediately. The configured
517
- probability therefore controls how often the top entrant wins outright versus
518
- how often weaker entrants remain reachable later in the walk.
519
- This is what makes tournament selection tunable instead of purely greedy.
459
+ This path turns the current population into a weighted threshold scan. When
460
+ some genomes have negative scores, the helper first shifts the whole fitness
461
+ space upward so every participant still occupies a non-negative span on the
462
+ roulette wheel.
463
+ That makes this strategy the most score-sensitive branch in the chapter: it
464
+ reacts to relative score magnitude rather than only rank or sampled bracket
465
+ ordering.
520
466
 
521
467
  Parameters:
522
468
  - `selectionContext` - - Shared selection state.
523
- - `sortedParticipants` - - Participants sorted by descending score.
524
469
 
525
- Returns: The chosen tournament winner.
470
+ Returns: The chosen parent genome.
526
471
 
527
- ### getRandomPopulationMember
472
+ ### selectParentByPower
528
473
 
529
474
  ```ts
530
- getRandomPopulationMember(
475
+ selectParentByPower(
531
476
  selectionContext: SelectionContext,
532
477
  ): GenomeWithScore
533
478
  ```
534
479
 
535
- Select a random population member using the configured RNG.
480
+ Select a parent by power-law distribution on the sorted population.
536
481
 
537
- This is the small shared fallback used by roulette misses and suppressed
538
- tournament overflow. Centralizing it here keeps every selection path tied to
539
- the same controller RNG stream.
540
- It also makes the fallback semantics explicit instead of hiding ad hoc random
541
- picks inside individual strategies.
482
+ POWER selection assumes best-first ordering and then biases random choice
483
+ toward the front of that ranking. Lower random samples stay near the leading
484
+ genomes, while the configured exponent controls how quickly the chance falls
485
+ away from the champion.
486
+ Read this as the lightest built-in strategy: it does not inspect absolute
487
+ score gaps, only the current descending order.
542
488
 
543
489
  Parameters:
544
490
  - `selectionContext` - - Shared selection state.
545
491
 
546
- Returns: Randomly chosen genome from the current population.
492
+ Returns: The chosen parent genome.
493
+
494
+ ### selectParentByStrategy
495
+
496
+ ```ts
497
+ selectParentByStrategy(
498
+ internal: NeatLikeWithSelection,
499
+ ): GenomeWithScore
500
+ ```
501
+
502
+ Select a parent genome according to the configured selection strategy.
503
+
504
+ This is the single dispatch point shared by the controller-facing selection
505
+ helpers. It resolves the active strategy once, builds a compact
506
+ {@link SelectionContext}, and then hands off to the concrete algorithm.
507
+
508
+ The fallback to the first population entry is deliberate. When callers have
509
+ configured an unknown strategy name, selection still returns a deterministic
510
+ candidate instead of failing unexpectedly deep inside crossover or mutation
511
+ flow.
512
+
513
+ Parameters:
514
+ - `internal` - - NEAT host containing population, options, and RNG access.
515
+
516
+ Returns: A genome chosen according to the active selection strategy.
517
+
518
+ Example:
519
+
520
+ ```ts
521
+ const parent = selectParentByStrategy(neat);
522
+ const strategyName = neat.options.selection?.name;
523
+ ```
524
+
525
+ ### selectParentByTournament
526
+
527
+ ```ts
528
+ selectParentByTournament(
529
+ selectionContext: SelectionContext,
530
+ ): GenomeWithScore
531
+ ```
532
+
533
+ Select a parent by tournament selection.
534
+
535
+ Tournament selection samples a temporary bracket, orders it by descending
536
+ score, then walks from strongest to weakest using the configured win
537
+ probability. This gives the controller a middle ground between pure
538
+ best-first bias and fully score-proportional roulette.
539
+ The sampled bracket is intentionally local: the strategy asks "who wins this
540
+ small contest?" rather than "how does the whole population distribute
541
+ weight?"
542
+
543
+ Parameters:
544
+ - `selectionContext` - - Shared selection state.
545
+
546
+ Returns: The chosen parent genome.