tnfr 3.0.3__py3-none-any.whl → 8.5.0__py3-none-any.whl

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.

Potentially problematic release.


This version of tnfr might be problematic. Click here for more details.

Files changed (360) hide show
  1. tnfr/__init__.py +375 -56
  2. tnfr/__init__.pyi +33 -0
  3. tnfr/_compat.py +10 -0
  4. tnfr/_generated_version.py +34 -0
  5. tnfr/_version.py +49 -0
  6. tnfr/_version.pyi +7 -0
  7. tnfr/alias.py +723 -0
  8. tnfr/alias.pyi +108 -0
  9. tnfr/backends/__init__.py +354 -0
  10. tnfr/backends/jax_backend.py +173 -0
  11. tnfr/backends/numpy_backend.py +238 -0
  12. tnfr/backends/optimized_numpy.py +420 -0
  13. tnfr/backends/torch_backend.py +408 -0
  14. tnfr/cache.py +171 -0
  15. tnfr/cache.pyi +13 -0
  16. tnfr/cli/__init__.py +110 -0
  17. tnfr/cli/__init__.pyi +26 -0
  18. tnfr/cli/arguments.py +489 -0
  19. tnfr/cli/arguments.pyi +29 -0
  20. tnfr/cli/execution.py +914 -0
  21. tnfr/cli/execution.pyi +70 -0
  22. tnfr/cli/interactive_validator.py +614 -0
  23. tnfr/cli/utils.py +51 -0
  24. tnfr/cli/utils.pyi +7 -0
  25. tnfr/cli/validate.py +236 -0
  26. tnfr/compat/__init__.py +85 -0
  27. tnfr/compat/dataclass.py +136 -0
  28. tnfr/compat/jsonschema_stub.py +61 -0
  29. tnfr/compat/matplotlib_stub.py +73 -0
  30. tnfr/compat/numpy_stub.py +155 -0
  31. tnfr/config/__init__.py +224 -0
  32. tnfr/config/__init__.pyi +10 -0
  33. tnfr/config/constants.py +104 -0
  34. tnfr/config/constants.pyi +12 -0
  35. tnfr/config/defaults.py +54 -0
  36. tnfr/config/defaults_core.py +212 -0
  37. tnfr/config/defaults_init.py +33 -0
  38. tnfr/config/defaults_metric.py +104 -0
  39. tnfr/config/feature_flags.py +81 -0
  40. tnfr/config/feature_flags.pyi +16 -0
  41. tnfr/config/glyph_constants.py +31 -0
  42. tnfr/config/init.py +77 -0
  43. tnfr/config/init.pyi +8 -0
  44. tnfr/config/operator_names.py +254 -0
  45. tnfr/config/operator_names.pyi +36 -0
  46. tnfr/config/physics_derivation.py +354 -0
  47. tnfr/config/presets.py +83 -0
  48. tnfr/config/presets.pyi +7 -0
  49. tnfr/config/security.py +927 -0
  50. tnfr/config/thresholds.py +114 -0
  51. tnfr/config/tnfr_config.py +498 -0
  52. tnfr/constants/__init__.py +92 -0
  53. tnfr/constants/__init__.pyi +92 -0
  54. tnfr/constants/aliases.py +33 -0
  55. tnfr/constants/aliases.pyi +27 -0
  56. tnfr/constants/init.py +33 -0
  57. tnfr/constants/init.pyi +12 -0
  58. tnfr/constants/metric.py +104 -0
  59. tnfr/constants/metric.pyi +19 -0
  60. tnfr/core/__init__.py +33 -0
  61. tnfr/core/container.py +226 -0
  62. tnfr/core/default_implementations.py +329 -0
  63. tnfr/core/interfaces.py +279 -0
  64. tnfr/dynamics/__init__.py +238 -0
  65. tnfr/dynamics/__init__.pyi +83 -0
  66. tnfr/dynamics/adaptation.py +267 -0
  67. tnfr/dynamics/adaptation.pyi +7 -0
  68. tnfr/dynamics/adaptive_sequences.py +189 -0
  69. tnfr/dynamics/adaptive_sequences.pyi +14 -0
  70. tnfr/dynamics/aliases.py +23 -0
  71. tnfr/dynamics/aliases.pyi +19 -0
  72. tnfr/dynamics/bifurcation.py +232 -0
  73. tnfr/dynamics/canonical.py +229 -0
  74. tnfr/dynamics/canonical.pyi +48 -0
  75. tnfr/dynamics/coordination.py +385 -0
  76. tnfr/dynamics/coordination.pyi +25 -0
  77. tnfr/dynamics/dnfr.py +3034 -0
  78. tnfr/dynamics/dnfr.pyi +26 -0
  79. tnfr/dynamics/dynamic_limits.py +225 -0
  80. tnfr/dynamics/feedback.py +252 -0
  81. tnfr/dynamics/feedback.pyi +24 -0
  82. tnfr/dynamics/fused_dnfr.py +454 -0
  83. tnfr/dynamics/homeostasis.py +157 -0
  84. tnfr/dynamics/homeostasis.pyi +14 -0
  85. tnfr/dynamics/integrators.py +661 -0
  86. tnfr/dynamics/integrators.pyi +36 -0
  87. tnfr/dynamics/learning.py +310 -0
  88. tnfr/dynamics/learning.pyi +33 -0
  89. tnfr/dynamics/metabolism.py +254 -0
  90. tnfr/dynamics/nbody.py +796 -0
  91. tnfr/dynamics/nbody_tnfr.py +783 -0
  92. tnfr/dynamics/propagation.py +326 -0
  93. tnfr/dynamics/runtime.py +908 -0
  94. tnfr/dynamics/runtime.pyi +77 -0
  95. tnfr/dynamics/sampling.py +36 -0
  96. tnfr/dynamics/sampling.pyi +7 -0
  97. tnfr/dynamics/selectors.py +711 -0
  98. tnfr/dynamics/selectors.pyi +85 -0
  99. tnfr/dynamics/structural_clip.py +207 -0
  100. tnfr/errors/__init__.py +37 -0
  101. tnfr/errors/contextual.py +492 -0
  102. tnfr/execution.py +223 -0
  103. tnfr/execution.pyi +45 -0
  104. tnfr/extensions/__init__.py +205 -0
  105. tnfr/extensions/__init__.pyi +18 -0
  106. tnfr/extensions/base.py +173 -0
  107. tnfr/extensions/base.pyi +35 -0
  108. tnfr/extensions/business/__init__.py +71 -0
  109. tnfr/extensions/business/__init__.pyi +11 -0
  110. tnfr/extensions/business/cookbook.py +88 -0
  111. tnfr/extensions/business/cookbook.pyi +8 -0
  112. tnfr/extensions/business/health_analyzers.py +202 -0
  113. tnfr/extensions/business/health_analyzers.pyi +9 -0
  114. tnfr/extensions/business/patterns.py +183 -0
  115. tnfr/extensions/business/patterns.pyi +8 -0
  116. tnfr/extensions/medical/__init__.py +73 -0
  117. tnfr/extensions/medical/__init__.pyi +11 -0
  118. tnfr/extensions/medical/cookbook.py +88 -0
  119. tnfr/extensions/medical/cookbook.pyi +8 -0
  120. tnfr/extensions/medical/health_analyzers.py +181 -0
  121. tnfr/extensions/medical/health_analyzers.pyi +9 -0
  122. tnfr/extensions/medical/patterns.py +163 -0
  123. tnfr/extensions/medical/patterns.pyi +8 -0
  124. tnfr/flatten.py +262 -0
  125. tnfr/flatten.pyi +21 -0
  126. tnfr/gamma.py +354 -0
  127. tnfr/gamma.pyi +36 -0
  128. tnfr/glyph_history.py +377 -0
  129. tnfr/glyph_history.pyi +35 -0
  130. tnfr/glyph_runtime.py +19 -0
  131. tnfr/glyph_runtime.pyi +8 -0
  132. tnfr/immutable.py +218 -0
  133. tnfr/immutable.pyi +36 -0
  134. tnfr/initialization.py +203 -0
  135. tnfr/initialization.pyi +65 -0
  136. tnfr/io.py +10 -0
  137. tnfr/io.pyi +13 -0
  138. tnfr/locking.py +37 -0
  139. tnfr/locking.pyi +7 -0
  140. tnfr/mathematics/__init__.py +79 -0
  141. tnfr/mathematics/backend.py +453 -0
  142. tnfr/mathematics/backend.pyi +99 -0
  143. tnfr/mathematics/dynamics.py +408 -0
  144. tnfr/mathematics/dynamics.pyi +90 -0
  145. tnfr/mathematics/epi.py +391 -0
  146. tnfr/mathematics/epi.pyi +65 -0
  147. tnfr/mathematics/generators.py +242 -0
  148. tnfr/mathematics/generators.pyi +29 -0
  149. tnfr/mathematics/metrics.py +119 -0
  150. tnfr/mathematics/metrics.pyi +16 -0
  151. tnfr/mathematics/operators.py +239 -0
  152. tnfr/mathematics/operators.pyi +59 -0
  153. tnfr/mathematics/operators_factory.py +124 -0
  154. tnfr/mathematics/operators_factory.pyi +11 -0
  155. tnfr/mathematics/projection.py +87 -0
  156. tnfr/mathematics/projection.pyi +33 -0
  157. tnfr/mathematics/runtime.py +182 -0
  158. tnfr/mathematics/runtime.pyi +64 -0
  159. tnfr/mathematics/spaces.py +256 -0
  160. tnfr/mathematics/spaces.pyi +83 -0
  161. tnfr/mathematics/transforms.py +305 -0
  162. tnfr/mathematics/transforms.pyi +62 -0
  163. tnfr/metrics/__init__.py +79 -0
  164. tnfr/metrics/__init__.pyi +20 -0
  165. tnfr/metrics/buffer_cache.py +163 -0
  166. tnfr/metrics/buffer_cache.pyi +24 -0
  167. tnfr/metrics/cache_utils.py +214 -0
  168. tnfr/metrics/coherence.py +2009 -0
  169. tnfr/metrics/coherence.pyi +129 -0
  170. tnfr/metrics/common.py +158 -0
  171. tnfr/metrics/common.pyi +35 -0
  172. tnfr/metrics/core.py +316 -0
  173. tnfr/metrics/core.pyi +13 -0
  174. tnfr/metrics/diagnosis.py +833 -0
  175. tnfr/metrics/diagnosis.pyi +86 -0
  176. tnfr/metrics/emergence.py +245 -0
  177. tnfr/metrics/export.py +179 -0
  178. tnfr/metrics/export.pyi +7 -0
  179. tnfr/metrics/glyph_timing.py +379 -0
  180. tnfr/metrics/glyph_timing.pyi +81 -0
  181. tnfr/metrics/learning_metrics.py +280 -0
  182. tnfr/metrics/learning_metrics.pyi +21 -0
  183. tnfr/metrics/phase_coherence.py +351 -0
  184. tnfr/metrics/phase_compatibility.py +349 -0
  185. tnfr/metrics/reporting.py +183 -0
  186. tnfr/metrics/reporting.pyi +25 -0
  187. tnfr/metrics/sense_index.py +1203 -0
  188. tnfr/metrics/sense_index.pyi +9 -0
  189. tnfr/metrics/trig.py +373 -0
  190. tnfr/metrics/trig.pyi +13 -0
  191. tnfr/metrics/trig_cache.py +233 -0
  192. tnfr/metrics/trig_cache.pyi +10 -0
  193. tnfr/multiscale/__init__.py +32 -0
  194. tnfr/multiscale/hierarchical.py +517 -0
  195. tnfr/node.py +763 -0
  196. tnfr/node.pyi +139 -0
  197. tnfr/observers.py +255 -130
  198. tnfr/observers.pyi +31 -0
  199. tnfr/ontosim.py +144 -137
  200. tnfr/ontosim.pyi +28 -0
  201. tnfr/operators/__init__.py +1672 -0
  202. tnfr/operators/__init__.pyi +31 -0
  203. tnfr/operators/algebra.py +277 -0
  204. tnfr/operators/canonical_patterns.py +420 -0
  205. tnfr/operators/cascade.py +267 -0
  206. tnfr/operators/cycle_detection.py +358 -0
  207. tnfr/operators/definitions.py +4108 -0
  208. tnfr/operators/definitions.pyi +78 -0
  209. tnfr/operators/grammar.py +1164 -0
  210. tnfr/operators/grammar.pyi +140 -0
  211. tnfr/operators/hamiltonian.py +710 -0
  212. tnfr/operators/health_analyzer.py +809 -0
  213. tnfr/operators/jitter.py +272 -0
  214. tnfr/operators/jitter.pyi +11 -0
  215. tnfr/operators/lifecycle.py +314 -0
  216. tnfr/operators/metabolism.py +618 -0
  217. tnfr/operators/metrics.py +2138 -0
  218. tnfr/operators/network_analysis/__init__.py +27 -0
  219. tnfr/operators/network_analysis/source_detection.py +186 -0
  220. tnfr/operators/nodal_equation.py +395 -0
  221. tnfr/operators/pattern_detection.py +660 -0
  222. tnfr/operators/patterns.py +669 -0
  223. tnfr/operators/postconditions/__init__.py +38 -0
  224. tnfr/operators/postconditions/mutation.py +236 -0
  225. tnfr/operators/preconditions/__init__.py +1226 -0
  226. tnfr/operators/preconditions/coherence.py +305 -0
  227. tnfr/operators/preconditions/dissonance.py +236 -0
  228. tnfr/operators/preconditions/emission.py +128 -0
  229. tnfr/operators/preconditions/mutation.py +580 -0
  230. tnfr/operators/preconditions/reception.py +125 -0
  231. tnfr/operators/preconditions/resonance.py +364 -0
  232. tnfr/operators/registry.py +74 -0
  233. tnfr/operators/registry.pyi +9 -0
  234. tnfr/operators/remesh.py +1809 -0
  235. tnfr/operators/remesh.pyi +26 -0
  236. tnfr/operators/structural_units.py +268 -0
  237. tnfr/operators/unified_grammar.py +105 -0
  238. tnfr/parallel/__init__.py +54 -0
  239. tnfr/parallel/auto_scaler.py +234 -0
  240. tnfr/parallel/distributed.py +384 -0
  241. tnfr/parallel/engine.py +238 -0
  242. tnfr/parallel/gpu_engine.py +420 -0
  243. tnfr/parallel/monitoring.py +248 -0
  244. tnfr/parallel/partitioner.py +459 -0
  245. tnfr/py.typed +0 -0
  246. tnfr/recipes/__init__.py +22 -0
  247. tnfr/recipes/cookbook.py +743 -0
  248. tnfr/rng.py +178 -0
  249. tnfr/rng.pyi +26 -0
  250. tnfr/schemas/__init__.py +8 -0
  251. tnfr/schemas/grammar.json +94 -0
  252. tnfr/sdk/__init__.py +107 -0
  253. tnfr/sdk/__init__.pyi +19 -0
  254. tnfr/sdk/adaptive_system.py +173 -0
  255. tnfr/sdk/adaptive_system.pyi +21 -0
  256. tnfr/sdk/builders.py +370 -0
  257. tnfr/sdk/builders.pyi +51 -0
  258. tnfr/sdk/fluent.py +1121 -0
  259. tnfr/sdk/fluent.pyi +74 -0
  260. tnfr/sdk/templates.py +342 -0
  261. tnfr/sdk/templates.pyi +41 -0
  262. tnfr/sdk/utils.py +341 -0
  263. tnfr/secure_config.py +46 -0
  264. tnfr/security/__init__.py +70 -0
  265. tnfr/security/database.py +514 -0
  266. tnfr/security/subprocess.py +503 -0
  267. tnfr/security/validation.py +290 -0
  268. tnfr/selector.py +247 -0
  269. tnfr/selector.pyi +19 -0
  270. tnfr/sense.py +378 -0
  271. tnfr/sense.pyi +23 -0
  272. tnfr/services/__init__.py +17 -0
  273. tnfr/services/orchestrator.py +325 -0
  274. tnfr/sparse/__init__.py +39 -0
  275. tnfr/sparse/representations.py +492 -0
  276. tnfr/structural.py +705 -0
  277. tnfr/structural.pyi +83 -0
  278. tnfr/telemetry/__init__.py +35 -0
  279. tnfr/telemetry/cache_metrics.py +226 -0
  280. tnfr/telemetry/cache_metrics.pyi +64 -0
  281. tnfr/telemetry/nu_f.py +422 -0
  282. tnfr/telemetry/nu_f.pyi +108 -0
  283. tnfr/telemetry/verbosity.py +36 -0
  284. tnfr/telemetry/verbosity.pyi +15 -0
  285. tnfr/tokens.py +58 -0
  286. tnfr/tokens.pyi +36 -0
  287. tnfr/tools/__init__.py +20 -0
  288. tnfr/tools/domain_templates.py +478 -0
  289. tnfr/tools/sequence_generator.py +846 -0
  290. tnfr/topology/__init__.py +13 -0
  291. tnfr/topology/asymmetry.py +151 -0
  292. tnfr/trace.py +543 -0
  293. tnfr/trace.pyi +42 -0
  294. tnfr/tutorials/__init__.py +38 -0
  295. tnfr/tutorials/autonomous_evolution.py +285 -0
  296. tnfr/tutorials/interactive.py +1576 -0
  297. tnfr/tutorials/structural_metabolism.py +238 -0
  298. tnfr/types.py +775 -0
  299. tnfr/types.pyi +357 -0
  300. tnfr/units.py +68 -0
  301. tnfr/units.pyi +13 -0
  302. tnfr/utils/__init__.py +282 -0
  303. tnfr/utils/__init__.pyi +215 -0
  304. tnfr/utils/cache.py +4223 -0
  305. tnfr/utils/cache.pyi +470 -0
  306. tnfr/utils/callbacks.py +375 -0
  307. tnfr/utils/callbacks.pyi +49 -0
  308. tnfr/utils/chunks.py +108 -0
  309. tnfr/utils/chunks.pyi +22 -0
  310. tnfr/utils/data.py +428 -0
  311. tnfr/utils/data.pyi +74 -0
  312. tnfr/utils/graph.py +85 -0
  313. tnfr/utils/graph.pyi +10 -0
  314. tnfr/utils/init.py +821 -0
  315. tnfr/utils/init.pyi +80 -0
  316. tnfr/utils/io.py +559 -0
  317. tnfr/utils/io.pyi +66 -0
  318. tnfr/utils/numeric.py +114 -0
  319. tnfr/utils/numeric.pyi +21 -0
  320. tnfr/validation/__init__.py +257 -0
  321. tnfr/validation/__init__.pyi +85 -0
  322. tnfr/validation/compatibility.py +460 -0
  323. tnfr/validation/compatibility.pyi +6 -0
  324. tnfr/validation/config.py +73 -0
  325. tnfr/validation/graph.py +139 -0
  326. tnfr/validation/graph.pyi +18 -0
  327. tnfr/validation/input_validation.py +755 -0
  328. tnfr/validation/invariants.py +712 -0
  329. tnfr/validation/rules.py +253 -0
  330. tnfr/validation/rules.pyi +44 -0
  331. tnfr/validation/runtime.py +279 -0
  332. tnfr/validation/runtime.pyi +28 -0
  333. tnfr/validation/sequence_validator.py +162 -0
  334. tnfr/validation/soft_filters.py +170 -0
  335. tnfr/validation/soft_filters.pyi +32 -0
  336. tnfr/validation/spectral.py +164 -0
  337. tnfr/validation/spectral.pyi +42 -0
  338. tnfr/validation/validator.py +1266 -0
  339. tnfr/validation/window.py +39 -0
  340. tnfr/validation/window.pyi +1 -0
  341. tnfr/visualization/__init__.py +98 -0
  342. tnfr/visualization/cascade_viz.py +256 -0
  343. tnfr/visualization/hierarchy.py +284 -0
  344. tnfr/visualization/sequence_plotter.py +784 -0
  345. tnfr/viz/__init__.py +60 -0
  346. tnfr/viz/matplotlib.py +278 -0
  347. tnfr/viz/matplotlib.pyi +35 -0
  348. tnfr-8.5.0.dist-info/METADATA +573 -0
  349. tnfr-8.5.0.dist-info/RECORD +353 -0
  350. tnfr-8.5.0.dist-info/entry_points.txt +3 -0
  351. tnfr-3.0.3.dist-info/licenses/LICENSE.txt → tnfr-8.5.0.dist-info/licenses/LICENSE.md +1 -1
  352. tnfr/constants.py +0 -183
  353. tnfr/dynamics.py +0 -543
  354. tnfr/helpers.py +0 -198
  355. tnfr/main.py +0 -37
  356. tnfr/operators.py +0 -296
  357. tnfr-3.0.3.dist-info/METADATA +0 -35
  358. tnfr-3.0.3.dist-info/RECORD +0 -13
  359. {tnfr-3.0.3.dist-info → tnfr-8.5.0.dist-info}/WHEEL +0 -0
  360. {tnfr-3.0.3.dist-info → tnfr-8.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,846 @@
1
+ """Context-guided sequence generator for TNFR operator sequences.
2
+
3
+ This module provides intelligent sequence generation capabilities that help
4
+ users construct optimal TNFR operator sequences based on context, objectives,
5
+ and structural constraints. The generator uses domain templates, pattern
6
+ detection, and health analysis to produce high-quality sequences.
7
+
8
+ Examples
9
+ --------
10
+ >>> from tnfr.tools.sequence_generator import ContextualSequenceGenerator
11
+ >>> generator = ContextualSequenceGenerator()
12
+ >>>
13
+ >>> # Generate for specific domain and objective
14
+ >>> seq = generator.generate_for_context(
15
+ ... domain="therapeutic",
16
+ ... objective="crisis_intervention",
17
+ ... min_health=0.75
18
+ ... )
19
+ >>> print(seq)
20
+ ['emission', 'reception', 'coherence', 'resonance', 'silence']
21
+ >>>
22
+ >>> # Generate to match a specific pattern
23
+ >>> seq = generator.generate_for_pattern(
24
+ ... target_pattern="BOOTSTRAP",
25
+ ... min_health=0.70
26
+ ... )
27
+ >>>
28
+ >>> # Improve an existing sequence
29
+ >>> current = ["emission", "coherence", "silence"]
30
+ >>> improved, recommendations = generator.improve_sequence(current, target_health=0.80)
31
+ """
32
+
33
+ from __future__ import annotations
34
+
35
+ import random
36
+ from typing import TYPE_CHECKING
37
+
38
+ if TYPE_CHECKING:
39
+ from ..operators.grammar import StructuralPattern
40
+
41
+ from ..compat.dataclass import dataclass
42
+ from ..config.operator_names import (
43
+ COHERENCE,
44
+ CONTRACTION,
45
+ COUPLING,
46
+ DISSONANCE,
47
+ EMISSION,
48
+ EXPANSION,
49
+ MUTATION,
50
+ RECEPTION,
51
+ RECURSIVITY,
52
+ RESONANCE,
53
+ SELF_ORGANIZATION,
54
+ SILENCE,
55
+ TRANSITION,
56
+ )
57
+ from ..operators.health_analyzer import SequenceHealthAnalyzer
58
+ from ..operators.patterns import AdvancedPatternDetector
59
+ from ..validation.compatibility import (
60
+ GRADUATED_COMPATIBILITY,
61
+ CompatibilityLevel,
62
+ get_compatibility_level,
63
+ )
64
+ from .domain_templates import DOMAIN_TEMPLATES, get_template
65
+
66
+ __all__ = [
67
+ "ContextualSequenceGenerator",
68
+ "GenerationResult",
69
+ ]
70
+
71
+
72
+ # Operator groups for intelligent variation
73
+ _STABILIZERS = [COHERENCE, SELF_ORGANIZATION, SILENCE, RESONANCE]
74
+ _DESTABILIZERS = [DISSONANCE, MUTATION, EXPANSION]
75
+ _ACTIVATORS = [EMISSION, RECEPTION]
76
+ _CONNECTORS = [COUPLING, RESONANCE]
77
+ _TRANSFORMERS = [TRANSITION, RECURSIVITY, MUTATION]
78
+
79
+
80
+ @dataclass
81
+ class GenerationResult:
82
+ """Result of a sequence generation operation.
83
+
84
+ Attributes
85
+ ----------
86
+ sequence : list[str]
87
+ Generated operator sequence (canonical names).
88
+ health_score : float
89
+ Overall structural health score (0.0-1.0).
90
+ detected_pattern : str
91
+ Primary structural pattern detected.
92
+ domain : str | None
93
+ Domain context used for generation (if applicable).
94
+ objective : str | None
95
+ Specific objective within domain (if applicable).
96
+ method : str
97
+ Generation method used ("template", "pattern", "improvement").
98
+ recommendations : list[str]
99
+ Suggestions for further improvement.
100
+ metadata : dict[str, object]
101
+ Additional generation metadata.
102
+ """
103
+
104
+ sequence: list[str]
105
+ health_score: float
106
+ detected_pattern: str
107
+ domain: str | None
108
+ objective: str | None
109
+ method: str
110
+ recommendations: list[str]
111
+ metadata: dict[str, object]
112
+
113
+
114
+ class ContextualSequenceGenerator:
115
+ """Generator for context-guided TNFR operator sequences.
116
+
117
+ This generator combines domain templates, pattern detection, and health
118
+ analysis to produce optimal operator sequences for specific contexts and
119
+ objectives. It supports:
120
+
121
+ - Domain/objective-based generation from curated templates
122
+ - Pattern-targeted generation to achieve specific structural patterns
123
+ - Sequence improvement with targeted recommendations
124
+ - Constraint-based filtering (health, length, pattern)
125
+
126
+ All generated sequences respect TNFR canonical principles:
127
+ - Operator closure (only canonical operators)
128
+ - Phase coherence (compatible transitions)
129
+ - Structural health (balanced forces)
130
+ - Operational fractality (composable patterns)
131
+
132
+ Examples
133
+ --------
134
+ >>> generator = ContextualSequenceGenerator()
135
+ >>> result = generator.generate_for_context(
136
+ ... domain="therapeutic",
137
+ ... objective="crisis_intervention"
138
+ ... )
139
+ >>> print(result.sequence)
140
+ ['emission', 'reception', 'coherence', 'resonance', 'silence']
141
+ >>> print(f"Health: {result.health_score:.2f}")
142
+ Health: 0.78
143
+ """
144
+
145
+ def __init__(self, seed: int | None = None) -> None:
146
+ """Initialize the contextual sequence generator.
147
+
148
+ Parameters
149
+ ----------
150
+ seed : int, optional
151
+ Random seed for deterministic generation. If None, generation
152
+ is non-deterministic.
153
+ """
154
+ self.health_analyzer = SequenceHealthAnalyzer()
155
+ self.pattern_detector = AdvancedPatternDetector()
156
+ self._rng = random.Random(seed)
157
+
158
+ def generate_for_context(
159
+ self,
160
+ domain: str,
161
+ objective: str | None = None,
162
+ max_length: int = 10,
163
+ min_health: float = 0.70,
164
+ required_pattern: str | None = None,
165
+ ) -> GenerationResult:
166
+ """Generate optimal sequence for specific domain and objective.
167
+
168
+ This method uses domain templates as a starting point and applies
169
+ intelligent variations to meet constraints while maintaining structural
170
+ coherence.
171
+
172
+ Parameters
173
+ ----------
174
+ domain : str
175
+ Application domain (therapeutic, educational, organizational, creative).
176
+ objective : str, optional
177
+ Specific objective within domain. If None, uses first template.
178
+ max_length : int, default=10
179
+ Maximum sequence length. Sequences longer than this will be trimmed.
180
+ min_health : float, default=0.70
181
+ Minimum required health score (0.0-1.0).
182
+ required_pattern : str, optional
183
+ If specified, generator will try to produce this pattern.
184
+
185
+ Returns
186
+ -------
187
+ GenerationResult
188
+ Complete generation result with sequence, health metrics, and metadata.
189
+
190
+ Raises
191
+ ------
192
+ KeyError
193
+ If domain or objective not found.
194
+ ValueError
195
+ If no valid sequence can be generated meeting constraints.
196
+
197
+ Examples
198
+ --------
199
+ >>> generator = ContextualSequenceGenerator()
200
+ >>> result = generator.generate_for_context(
201
+ ... domain="therapeutic",
202
+ ... objective="crisis_intervention",
203
+ ... min_health=0.75
204
+ ... )
205
+ >>> print(result.sequence)
206
+ ['emission', 'reception', 'coherence', 'resonance', 'silence']
207
+ """
208
+ # Determine objective if not specified
209
+ if objective is None:
210
+ from .domain_templates import list_objectives
211
+
212
+ objectives = list_objectives(domain)
213
+ objective = objectives[0] if objectives else None
214
+
215
+ # Get base template
216
+ base_sequence = get_template(domain, objective)
217
+
218
+ # Apply length constraint
219
+ if len(base_sequence) > max_length:
220
+ base_sequence = self._trim_sequence(base_sequence, max_length)
221
+
222
+ # Analyze base template
223
+ health = self.health_analyzer.analyze_health(base_sequence)
224
+
225
+ # If template already meets requirements, return it
226
+ if health.overall_health >= min_health:
227
+ if required_pattern is None or self._matches_pattern(
228
+ base_sequence, required_pattern
229
+ ):
230
+ return GenerationResult(
231
+ sequence=base_sequence,
232
+ health_score=health.overall_health,
233
+ detected_pattern=health.dominant_pattern,
234
+ domain=domain,
235
+ objective=objective,
236
+ method="template",
237
+ recommendations=health.recommendations,
238
+ metadata={
239
+ "template_used": True,
240
+ "variations_tried": 0,
241
+ },
242
+ )
243
+
244
+ # Generate variations to meet constraints
245
+ candidates = self._generate_variations(base_sequence, max_length, count=20)
246
+
247
+ # Filter candidates by constraints
248
+ valid_candidates = []
249
+ for candidate in candidates:
250
+ candidate_health = self.health_analyzer.analyze_health(candidate)
251
+ if candidate_health.overall_health >= min_health:
252
+ if required_pattern is None or self._matches_pattern(
253
+ candidate, required_pattern
254
+ ):
255
+ valid_candidates.append((candidate, candidate_health))
256
+
257
+ if not valid_candidates:
258
+ # Fallback: return best candidate even if below threshold
259
+ all_with_health = [
260
+ (seq, self.health_analyzer.analyze_health(seq)) for seq in candidates
261
+ ]
262
+ best_seq, best_health = max(
263
+ all_with_health, key=lambda x: x[1].overall_health
264
+ )
265
+
266
+ return GenerationResult(
267
+ sequence=best_seq,
268
+ health_score=best_health.overall_health,
269
+ detected_pattern=best_health.dominant_pattern,
270
+ domain=domain,
271
+ objective=objective,
272
+ method="template_variant",
273
+ recommendations=[
274
+ f"Warning: Could not meet min_health={min_health:.2f}",
275
+ f"Best achievable health: {best_health.overall_health:.2f}",
276
+ ]
277
+ + best_health.recommendations,
278
+ metadata={
279
+ "template_used": True,
280
+ "variations_tried": len(candidates),
281
+ "constraint_met": False,
282
+ },
283
+ )
284
+
285
+ # Select best valid candidate
286
+ best_seq, best_health = max(valid_candidates, key=lambda x: x[1].overall_health)
287
+
288
+ return GenerationResult(
289
+ sequence=best_seq,
290
+ health_score=best_health.overall_health,
291
+ detected_pattern=best_health.dominant_pattern,
292
+ domain=domain,
293
+ objective=objective,
294
+ method="template_optimized",
295
+ recommendations=best_health.recommendations,
296
+ metadata={
297
+ "template_used": True,
298
+ "variations_tried": len(candidates),
299
+ "valid_candidates": len(valid_candidates),
300
+ },
301
+ )
302
+
303
+ def generate_for_pattern(
304
+ self,
305
+ target_pattern: str,
306
+ max_length: int = 10,
307
+ min_health: float = 0.70,
308
+ ) -> GenerationResult:
309
+ """Generate sequence targeting a specific structural pattern.
310
+
311
+ Uses pattern signatures and characteristic operator combinations to
312
+ construct sequences that maximize the probability of matching the
313
+ target pattern while maintaining structural health.
314
+
315
+ Parameters
316
+ ----------
317
+ target_pattern : str
318
+ Target structural pattern (e.g., "BOOTSTRAP", "THERAPEUTIC",
319
+ "STABILIZE").
320
+ max_length : int, default=10
321
+ Maximum sequence length.
322
+ min_health : float, default=0.70
323
+ Minimum required health score (0.0-1.0).
324
+
325
+ Returns
326
+ -------
327
+ GenerationResult
328
+ Complete generation result with sequence and metrics.
329
+
330
+ Raises
331
+ ------
332
+ ValueError
333
+ If pattern name is not recognized or no valid sequence can be generated.
334
+
335
+ Examples
336
+ --------
337
+ >>> generator = ContextualSequenceGenerator()
338
+ >>> result = generator.generate_for_pattern("BOOTSTRAP", min_health=0.70)
339
+ >>> print(result.sequence)
340
+ ['emission', 'coupling', 'coherence']
341
+ """
342
+ # Get pattern signature
343
+ signature = self._get_pattern_signature(target_pattern)
344
+
345
+ # Build base sequence from signature
346
+ base_sequence = self._build_from_signature(signature, max_length)
347
+
348
+ # Analyze and optimize
349
+ health = self.health_analyzer.analyze_health(base_sequence)
350
+
351
+ if health.overall_health >= min_health:
352
+ return GenerationResult(
353
+ sequence=base_sequence,
354
+ health_score=health.overall_health,
355
+ detected_pattern=health.dominant_pattern,
356
+ domain=None,
357
+ objective=None,
358
+ method="pattern_direct",
359
+ recommendations=health.recommendations,
360
+ metadata={
361
+ "target_pattern": target_pattern,
362
+ "pattern_matched": self._matches_pattern(
363
+ base_sequence, target_pattern
364
+ ),
365
+ },
366
+ )
367
+
368
+ # Generate variations to improve health
369
+ candidates = self._generate_variations(base_sequence, max_length, count=15)
370
+
371
+ # Filter by constraints and pattern match
372
+ valid_candidates = []
373
+ for candidate in candidates:
374
+ if self._matches_pattern(candidate, target_pattern):
375
+ candidate_health = self.health_analyzer.analyze_health(candidate)
376
+ if candidate_health.overall_health >= min_health:
377
+ valid_candidates.append((candidate, candidate_health))
378
+
379
+ if not valid_candidates:
380
+ # Return base even if below threshold
381
+ return GenerationResult(
382
+ sequence=base_sequence,
383
+ health_score=health.overall_health,
384
+ detected_pattern=health.dominant_pattern,
385
+ domain=None,
386
+ objective=None,
387
+ method="pattern_suboptimal",
388
+ recommendations=[
389
+ f"Warning: Could not meet min_health={min_health:.2f}",
390
+ f"Best achievable health: {health.overall_health:.2f}",
391
+ ]
392
+ + health.recommendations,
393
+ metadata={
394
+ "target_pattern": target_pattern,
395
+ "pattern_matched": self._matches_pattern(
396
+ base_sequence, target_pattern
397
+ ),
398
+ "constraint_met": False,
399
+ },
400
+ )
401
+
402
+ # Select best valid candidate
403
+ best_seq, best_health = max(valid_candidates, key=lambda x: x[1].overall_health)
404
+
405
+ return GenerationResult(
406
+ sequence=best_seq,
407
+ health_score=best_health.overall_health,
408
+ detected_pattern=best_health.dominant_pattern,
409
+ domain=None,
410
+ objective=None,
411
+ method="pattern_optimized",
412
+ recommendations=best_health.recommendations,
413
+ metadata={
414
+ "target_pattern": target_pattern,
415
+ "pattern_matched": True,
416
+ "variations_tried": len(candidates),
417
+ },
418
+ )
419
+
420
+ def improve_sequence(
421
+ self,
422
+ current: list[str],
423
+ target_health: float | None = None,
424
+ max_length: int | None = None,
425
+ ) -> tuple[list[str], list[str]]:
426
+ """Improve existing sequence with targeted recommendations.
427
+
428
+ Analyzes the current sequence, identifies weaknesses, and generates
429
+ an improved version along with specific recommendations explaining
430
+ the improvements made.
431
+
432
+ Parameters
433
+ ----------
434
+ current : list[str]
435
+ Current operator sequence to improve.
436
+ target_health : float, optional
437
+ Target health score. If None, aims for current + 0.15.
438
+ max_length : int, optional
439
+ Maximum allowed length for improved sequence. If None, allows
440
+ length to increase by up to 3 operators.
441
+
442
+ Returns
443
+ -------
444
+ tuple[list[str], list[str]]
445
+ A tuple containing:
446
+ - Improved operator sequence
447
+ - List of recommendations explaining improvements
448
+
449
+ Examples
450
+ --------
451
+ >>> generator = ContextualSequenceGenerator()
452
+ >>> current = ["emission", "coherence", "silence"]
453
+ >>> improved, recommendations = generator.improve_sequence(current)
454
+ >>> print(improved)
455
+ ['emission', 'reception', 'coherence', 'resonance', 'silence']
456
+ >>> print(recommendations[0])
457
+ 'Added reception after emission: improves completeness (+0.25)'
458
+ """
459
+ # Analyze current sequence
460
+ current_health = self.health_analyzer.analyze_health(current)
461
+
462
+ # Set target health
463
+ if target_health is None:
464
+ target_health = min(1.0, current_health.overall_health + 0.15)
465
+
466
+ # Set max length
467
+ if max_length is None:
468
+ max_length = len(current) + 3
469
+
470
+ # Generate improvement candidates
471
+ improvements = self._generate_improvements(
472
+ current, current_health, target_health, max_length
473
+ )
474
+
475
+ # Select best improvement
476
+ best_improvement = max(
477
+ improvements,
478
+ key=lambda seq: self.health_analyzer.analyze_health(seq).overall_health,
479
+ )
480
+
481
+ # Generate explanatory recommendations
482
+ recommendations = self._explain_improvements(current, best_improvement)
483
+
484
+ return best_improvement, recommendations
485
+
486
+ # =========================================================================
487
+ # INTERNAL HELPER METHODS
488
+ # =========================================================================
489
+
490
+ def _trim_sequence(self, sequence: list[str], max_length: int) -> list[str]:
491
+ """Trim sequence to max_length while preserving structure."""
492
+ if len(sequence) <= max_length:
493
+ return sequence
494
+
495
+ # Try to preserve ending if it's a stabilizer
496
+ if sequence[-1] in _STABILIZERS:
497
+ # Keep ending, trim from middle
498
+ keep_start = max_length // 2
499
+ keep_end = max_length - keep_start
500
+ return sequence[:keep_start] + sequence[-keep_end:]
501
+ else:
502
+ # Simple truncation
503
+ return sequence[:max_length]
504
+
505
+ def _generate_variations(
506
+ self, base: list[str], max_length: int, count: int = 20
507
+ ) -> list[list[str]]:
508
+ """Generate variations of a base sequence."""
509
+ variations = [base]
510
+
511
+ for _ in range(count):
512
+ variation = base.copy()
513
+
514
+ # Random modification
515
+ modification = self._rng.choice(["insert", "remove", "replace", "extend"])
516
+
517
+ if modification == "insert" and len(variation) < max_length:
518
+ pos = self._rng.randint(0, len(variation))
519
+ new_op = self._select_compatible_operator(
520
+ variation[pos - 1] if pos > 0 else None,
521
+ variation[pos] if pos < len(variation) else None,
522
+ )
523
+ if new_op:
524
+ variation.insert(pos, new_op)
525
+
526
+ elif modification == "remove" and len(variation) > 3:
527
+ pos = self._rng.randint(0, len(variation) - 1)
528
+ # Don't remove if it breaks compatibility
529
+ if self._can_remove(variation, pos):
530
+ variation.pop(pos)
531
+
532
+ elif modification == "replace":
533
+ pos = self._rng.randint(0, len(variation) - 1)
534
+ new_op = self._select_compatible_operator(
535
+ variation[pos - 1] if pos > 0 else None,
536
+ variation[pos + 1] if pos < len(variation) - 1 else None,
537
+ )
538
+ if new_op:
539
+ variation[pos] = new_op
540
+
541
+ elif modification == "extend" and len(variation) < max_length:
542
+ new_op = self._select_compatible_operator(variation[-1], None)
543
+ if new_op:
544
+ variation.append(new_op)
545
+
546
+ variations.append(variation)
547
+
548
+ return variations
549
+
550
+ def _select_compatible_operator(
551
+ self, prev: str | None, next_op: str | None
552
+ ) -> str | None:
553
+ """Select an operator compatible with neighbors."""
554
+ all_operators = [
555
+ EMISSION,
556
+ RECEPTION,
557
+ COHERENCE,
558
+ DISSONANCE,
559
+ COUPLING,
560
+ RESONANCE,
561
+ SILENCE,
562
+ EXPANSION,
563
+ CONTRACTION,
564
+ SELF_ORGANIZATION,
565
+ MUTATION,
566
+ TRANSITION,
567
+ RECURSIVITY,
568
+ ]
569
+
570
+ if prev is None and next_op is None:
571
+ return self._rng.choice(all_operators)
572
+
573
+ compatible = []
574
+
575
+ if prev is not None and next_op is None:
576
+ # Find operators compatible after prev
577
+ if prev in GRADUATED_COMPATIBILITY:
578
+ levels = GRADUATED_COMPATIBILITY[prev]
579
+ compatible.extend(levels.get("excellent", []))
580
+ compatible.extend(levels.get("good", []))
581
+
582
+ elif prev is None and next_op is not None:
583
+ # Find operators that can precede next_op
584
+ for op in all_operators:
585
+ level = get_compatibility_level(op, next_op)
586
+ if level in (CompatibilityLevel.EXCELLENT, CompatibilityLevel.GOOD):
587
+ compatible.append(op)
588
+
589
+ else:
590
+ # Must be compatible with both
591
+ for op in all_operators:
592
+ if prev and next_op:
593
+ level_after = get_compatibility_level(prev, op)
594
+ level_before = get_compatibility_level(op, next_op)
595
+ if level_after in (
596
+ CompatibilityLevel.EXCELLENT,
597
+ CompatibilityLevel.GOOD,
598
+ ) and level_before in (
599
+ CompatibilityLevel.EXCELLENT,
600
+ CompatibilityLevel.GOOD,
601
+ ):
602
+ compatible.append(op)
603
+
604
+ return self._rng.choice(compatible) if compatible else None
605
+
606
+ def _can_remove(self, sequence: list[str], pos: int) -> bool:
607
+ """Check if operator at pos can be safely removed."""
608
+ if pos == 0 or pos == len(sequence) - 1:
609
+ return True # Can always remove endpoints
610
+
611
+ prev = sequence[pos - 1]
612
+ next_op = sequence[pos + 1]
613
+
614
+ level = get_compatibility_level(prev, next_op)
615
+ return level in (CompatibilityLevel.EXCELLENT, CompatibilityLevel.GOOD)
616
+
617
+ def _matches_pattern(self, sequence: list[str], pattern_name: str) -> bool:
618
+ """Check if sequence matches the specified pattern."""
619
+ detected = self.pattern_detector.detect_pattern(sequence)
620
+ return detected.value == pattern_name
621
+
622
+ def _get_pattern_signature(self, pattern_name: str) -> dict[str, list[str]]:
623
+ """Get characteristic signature for a structural pattern."""
624
+ # Pattern signatures mapping pattern names to operator combinations
625
+ signatures: dict[str, dict[str, list[str]]] = {
626
+ "BOOTSTRAP": {
627
+ "core": [EMISSION, COUPLING, COHERENCE],
628
+ "optional": [RECEPTION, SILENCE],
629
+ "avoid": [DISSONANCE, MUTATION],
630
+ },
631
+ "THERAPEUTIC": {
632
+ "core": [
633
+ EMISSION,
634
+ RECEPTION,
635
+ COHERENCE,
636
+ DISSONANCE,
637
+ SELF_ORGANIZATION,
638
+ COHERENCE,
639
+ ],
640
+ "optional": [SILENCE, TRANSITION],
641
+ "avoid": [],
642
+ },
643
+ "EDUCATIONAL": {
644
+ "core": [RECEPTION, COHERENCE, EXPANSION, DISSONANCE, MUTATION],
645
+ "optional": [EMISSION, COHERENCE, SILENCE],
646
+ "avoid": [],
647
+ },
648
+ "ORGANIZATIONAL": {
649
+ "core": [
650
+ TRANSITION,
651
+ EMISSION,
652
+ RECEPTION,
653
+ COUPLING,
654
+ DISSONANCE,
655
+ SELF_ORGANIZATION,
656
+ ],
657
+ "optional": [COHERENCE, RESONANCE],
658
+ "avoid": [],
659
+ },
660
+ "CREATIVE": {
661
+ "core": [
662
+ SILENCE,
663
+ EMISSION,
664
+ EXPANSION,
665
+ DISSONANCE,
666
+ MUTATION,
667
+ SELF_ORGANIZATION,
668
+ ],
669
+ "optional": [COHERENCE, RECURSIVITY],
670
+ "avoid": [],
671
+ },
672
+ "STABILIZE": {
673
+ "core": [COHERENCE, SILENCE],
674
+ "optional": [RESONANCE, COHERENCE],
675
+ "avoid": [DISSONANCE, MUTATION, EXPANSION],
676
+ },
677
+ "EXPLORE": {
678
+ "core": [DISSONANCE, MUTATION, COHERENCE],
679
+ "optional": [EMISSION, RECEPTION],
680
+ "avoid": [SILENCE],
681
+ },
682
+ "RESONATE": {
683
+ "core": [RESONANCE, COUPLING, RESONANCE],
684
+ "optional": [COHERENCE, EMISSION],
685
+ "avoid": [DISSONANCE, MUTATION],
686
+ },
687
+ }
688
+
689
+ if pattern_name not in signatures:
690
+ # Default signature for unknown patterns
691
+ return {
692
+ "core": [EMISSION, COHERENCE, SILENCE],
693
+ "optional": [RECEPTION, RESONANCE],
694
+ "avoid": [],
695
+ }
696
+
697
+ return signatures[pattern_name]
698
+
699
+ def _build_from_signature(
700
+ self, signature: dict[str, list[str]], max_length: int
701
+ ) -> list[str]:
702
+ """Build sequence from pattern signature."""
703
+ core = signature["core"]
704
+ optional = signature.get("optional", [])
705
+
706
+ # Start with core
707
+ sequence = list(core)
708
+
709
+ # Add optional operators if room and improves health
710
+ remaining = max_length - len(sequence)
711
+ if remaining > 0 and optional:
712
+ for op in optional:
713
+ if len(sequence) < max_length:
714
+ # Try to insert at compatible position
715
+ for i in range(len(sequence) + 1):
716
+ prev = sequence[i - 1] if i > 0 else None
717
+ next_op = sequence[i] if i < len(sequence) else None
718
+
719
+ if prev is None or get_compatibility_level(prev, op) in (
720
+ CompatibilityLevel.EXCELLENT,
721
+ CompatibilityLevel.GOOD,
722
+ ):
723
+ if next_op is None or get_compatibility_level(
724
+ op, next_op
725
+ ) in (
726
+ CompatibilityLevel.EXCELLENT,
727
+ CompatibilityLevel.GOOD,
728
+ ):
729
+ sequence.insert(i, op)
730
+ break
731
+
732
+ return sequence[:max_length]
733
+
734
+ def _generate_improvements(
735
+ self,
736
+ current: list[str],
737
+ current_health: object,
738
+ target_health: float,
739
+ max_length: int,
740
+ ) -> list[list[str]]:
741
+ """Generate candidate improvements for a sequence."""
742
+ improvements = [current]
743
+
744
+ # Strategy 1: Add missing phases
745
+ if hasattr(current_health, "pattern_completeness"):
746
+ if current_health.pattern_completeness < 0.75: # type: ignore[attr-defined]
747
+ # Try adding activation
748
+ if not any(op in [EMISSION, RECEPTION] for op in current):
749
+ for pos in range(min(2, len(current))):
750
+ candidate = current.copy()
751
+ candidate.insert(pos, RECEPTION)
752
+ if len(candidate) <= max_length:
753
+ improvements.append(candidate)
754
+
755
+ # Strategy 2: Add stabilizers if unbalanced
756
+ if hasattr(current_health, "balance_score"):
757
+ if current_health.balance_score < 0.6: # type: ignore[attr-defined]
758
+ for stabilizer in _STABILIZERS:
759
+ candidate = current.copy()
760
+ if len(candidate) < max_length:
761
+ candidate.append(stabilizer)
762
+ improvements.append(candidate)
763
+
764
+ # Strategy 3: Improve ending
765
+ if hasattr(current_health, "sustainability_index"):
766
+ if (
767
+ current_health.sustainability_index < 0.7 # type: ignore[attr-defined]
768
+ and current[-1] not in _STABILIZERS
769
+ ):
770
+ for stabilizer in _STABILIZERS:
771
+ candidate = current.copy()
772
+ candidate.append(stabilizer)
773
+ if len(candidate) <= max_length:
774
+ improvements.append(candidate)
775
+
776
+ # Strategy 4: Add resonance for amplification
777
+ if RESONANCE not in current and len(current) < max_length:
778
+ for i in range(1, len(current)):
779
+ if current[i - 1] in [COUPLING, COHERENCE, EXPANSION]:
780
+ candidate = current.copy()
781
+ candidate.insert(i, RESONANCE)
782
+ if len(candidate) <= max_length:
783
+ improvements.append(candidate)
784
+
785
+ return improvements
786
+
787
+ def _explain_improvements(
788
+ self, original: list[str], improved: list[str]
789
+ ) -> list[str]:
790
+ """Generate explanations for improvements made."""
791
+ recommendations = []
792
+
793
+ # Analyze differences
794
+ original_health = self.health_analyzer.analyze_health(original)
795
+ improved_health = self.health_analyzer.analyze_health(improved)
796
+
797
+ # Overall improvement
798
+ health_delta = improved_health.overall_health - original_health.overall_health
799
+ if health_delta > 0.01:
800
+ recommendations.append(
801
+ f"Overall health improved by {health_delta:.2f} "
802
+ f"(from {original_health.overall_health:.2f} to {improved_health.overall_health:.2f})"
803
+ )
804
+
805
+ # Specific metric improvements
806
+ if improved_health.coherence_index > original_health.coherence_index + 0.05:
807
+ recommendations.append(
808
+ f"Coherence improved by {improved_health.coherence_index - original_health.coherence_index:.2f}"
809
+ )
810
+
811
+ if improved_health.balance_score > original_health.balance_score + 0.05:
812
+ recommendations.append(
813
+ f"Balance improved by {improved_health.balance_score - original_health.balance_score:.2f}"
814
+ )
815
+
816
+ if (
817
+ improved_health.sustainability_index
818
+ > original_health.sustainability_index + 0.05
819
+ ):
820
+ recommendations.append(
821
+ f"Sustainability improved by {improved_health.sustainability_index - original_health.sustainability_index:.2f}"
822
+ )
823
+
824
+ # Identify added operators
825
+ from collections import Counter
826
+
827
+ original_counts = Counter(original)
828
+ improved_counts = Counter(improved)
829
+ added = [
830
+ op
831
+ for op in improved_counts
832
+ if improved_counts[op] > original_counts.get(op, 0)
833
+ ]
834
+ if added:
835
+ recommendations.append(f"Added operators: {', '.join(set(added))}")
836
+
837
+ # Pattern change
838
+ if improved_health.dominant_pattern != original_health.dominant_pattern:
839
+ recommendations.append(
840
+ f"Pattern evolved from {original_health.dominant_pattern} to {improved_health.dominant_pattern}"
841
+ )
842
+
843
+ if not recommendations:
844
+ recommendations.append("Sequence maintained with minor refinements")
845
+
846
+ return recommendations