agentevolve-optimizer 0.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.
Files changed (414) hide show
  1. agent_evolve/__init__.py +722 -0
  2. agent_evolve/agentic.py +2800 -0
  3. agent_evolve/api.py +767 -0
  4. agent_evolve/application/__init__.py +1580 -0
  5. agent_evolve/application/action_allocation.py +744 -0
  6. agent_evolve/application/action_allocation_frame.py +347 -0
  7. agent_evolve/application/action_allocation_frame_commit.py +185 -0
  8. agent_evolve/application/action_allocation_frame_commit_v3.py +184 -0
  9. agent_evolve/application/action_allocation_frame_v3.py +338 -0
  10. agent_evolve/application/action_archive_value.py +497 -0
  11. agent_evolve/application/action_evidence_consistency.py +455 -0
  12. agent_evolve/application/action_forecast_partitioning.py +1471 -0
  13. agent_evolve/application/action_metric_projection.py +211 -0
  14. agent_evolve/application/action_role_value.py +680 -0
  15. agent_evolve/application/action_score_authorities.py +363 -0
  16. agent_evolve/application/action_structural_signature.py +116 -0
  17. agent_evolve/application/action_target_realization.py +402 -0
  18. agent_evolve/application/agentic_evolution.py +7734 -0
  19. agent_evolve/application/agentic_portfolio_residual_expert.py +835 -0
  20. agent_evolve/application/anchor_residual_identification.py +463 -0
  21. agent_evolve/application/archive_conditioned_action_target.py +208 -0
  22. agent_evolve/application/artifact_journal.py +246 -0
  23. agent_evolve/application/artifact_replay.py +347 -0
  24. agent_evolve/application/budgeted_optimizer.py +1828 -0
  25. agent_evolve/application/calibrated_campaign.py +485 -0
  26. agent_evolve/application/calibrated_current_prefix_forecast_opportunity.py +322 -0
  27. agent_evolve/application/calibrated_positive_gain_opportunity.py +1581 -0
  28. agent_evolve/application/campaign_capacity_recourse.py +254 -0
  29. agent_evolve/application/campaign_contextual_outcomes.py +119 -0
  30. agent_evolve/application/campaign_diagnostic_blocks.py +930 -0
  31. agent_evolve/application/campaign_evidence_registry.py +262 -0
  32. agent_evolve/application/campaign_execution.py +2537 -0
  33. agent_evolve/application/campaign_generation_audit.py +942 -0
  34. agent_evolve/application/campaign_learning.py +1812 -0
  35. agent_evolve/application/campaign_learning_runtime.py +1977 -0
  36. agent_evolve/application/campaign_search_phase.py +227 -0
  37. agent_evolve/application/campaign_selector_context_extension.py +220 -0
  38. agent_evolve/application/campaign_variation_envelope.py +649 -0
  39. agent_evolve/application/campaign_variation_trace.py +451 -0
  40. agent_evolve/application/candidate_archive_consequence.py +128 -0
  41. agent_evolve/application/causal_opportunity_portfolio_gate.py +385 -0
  42. agent_evolve/application/composite_outcome_updater.py +145 -0
  43. agent_evolve/application/composition_portfolio_selection.py +363 -0
  44. agent_evolve/application/concurrent_stage.py +144 -0
  45. agent_evolve/application/contextual_action_allocation.py +181 -0
  46. agent_evolve/application/contextual_campaign_outcomes.py +267 -0
  47. agent_evolve/application/contextual_campaign_planning.py +1366 -0
  48. agent_evolve/application/contextual_delayed_credit.py +651 -0
  49. agent_evolve/application/contextual_search_controller.py +2374 -0
  50. agent_evolve/application/current_prefix_forecast_opportunity.py +714 -0
  51. agent_evolve/application/decision_metric_projection.py +112 -0
  52. agent_evolve/application/derived_action_semantics.py +129 -0
  53. agent_evolve/application/detailed_evaluation.py +449 -0
  54. agent_evolve/application/earned_lineage.py +1011 -0
  55. agent_evolve/application/effective_choice_audit.py +484 -0
  56. agent_evolve/application/empirical_consequence_calibration.py +908 -0
  57. agent_evolve/application/evaluation_accounting.py +325 -0
  58. agent_evolve/application/evaluation_cache.py +199 -0
  59. agent_evolve/application/evaluation_escrow.py +547 -0
  60. agent_evolve/application/evaluation_recourse.py +253 -0
  61. agent_evolve/application/event_recorder.py +151 -0
  62. agent_evolve/application/evolution_campaign.py +1840 -0
  63. agent_evolve/application/executable_hypothesis.py +323 -0
  64. agent_evolve/application/factorial_branch_pilot.py +772 -0
  65. agent_evolve/application/finite_acquisition_capacity_recourse.py +672 -0
  66. agent_evolve/application/finite_acquisition_residual_expert.py +373 -0
  67. agent_evolve/application/finite_acquisition_variation_envelope.py +802 -0
  68. agent_evolve/application/finite_action_hypothesis_semantics.py +446 -0
  69. agent_evolve/application/finite_action_selection.py +188 -0
  70. agent_evolve/application/finite_action_set.py +306 -0
  71. agent_evolve/application/finite_action_transition.py +537 -0
  72. agent_evolve/application/finite_variation_eligibility.py +296 -0
  73. agent_evolve/application/forecast_geometry_portfolio.py +799 -0
  74. agent_evolve/application/forecast_opportunity_shadow_calibration.py +316 -0
  75. agent_evolve/application/front_proximity_admission.py +311 -0
  76. agent_evolve/application/front_proximity_parent_basis.py +458 -0
  77. agent_evolve/application/frozen_hurdle_score.py +659 -0
  78. agent_evolve/application/g3_causal_screen.py +2257 -0
  79. agent_evolve/application/g3_causal_validation.py +1046 -0
  80. agent_evolve/application/g3_postseal_curation.py +818 -0
  81. agent_evolve/application/gated_agentic_generator.py +205 -0
  82. agent_evolve/application/generation_feedback.py +293 -0
  83. agent_evolve/application/generative_proposal_journal.py +185 -0
  84. agent_evolve/application/geometry_conditional_elasticity.py +453 -0
  85. agent_evolve/application/global_wave_action_allocation.py +1151 -0
  86. agent_evolve/application/head_mass_conditional_seat.py +268 -0
  87. agent_evolve/application/identifiable_reflection_evidence.py +1147 -0
  88. agent_evolve/application/identifiable_reflection_learning.py +395 -0
  89. agent_evolve/application/identifiable_reflection_request.py +364 -0
  90. agent_evolve/application/in_memory_residual_archive.py +341 -0
  91. agent_evolve/application/insight_memory.py +1804 -0
  92. agent_evolve/application/live_runtime_manifest.py +758 -0
  93. agent_evolve/application/llm_task_queue.py +769 -0
  94. agent_evolve/application/matched_finite_action_block.py +409 -0
  95. agent_evolve/application/materialized_action_broker.py +2328 -0
  96. agent_evolve/application/materialized_action_constraints.py +83 -0
  97. agent_evolve/application/materialized_variation.py +211 -0
  98. agent_evolve/application/multi_option_evolution.py +1536 -0
  99. agent_evolve/application/outcome_adaptive_action_racing.py +2827 -0
  100. agent_evolve/application/outcome_adaptive_residual_campaign_runtime.py +580 -0
  101. agent_evolve/application/outcome_adaptive_residual_portfolio_evolution.py +3671 -0
  102. agent_evolve/application/outcome_conditioned_portfolio_selection.py +1374 -0
  103. agent_evolve/application/outcome_relation.py +193 -0
  104. agent_evolve/application/paired_allocation_comparison.py +241 -0
  105. agent_evolve/application/paired_block_schedule.py +127 -0
  106. agent_evolve/application/parent_measurement.py +226 -0
  107. agent_evolve/application/pareto_archive.py +811 -0
  108. agent_evolve/application/portfolio_campaign_runtime.py +4739 -0
  109. agent_evolve/application/portfolio_evolution.py +2950 -0
  110. agent_evolve/application/portfolio_hypothesis_observations.py +814 -0
  111. agent_evolve/application/portfolio_memory_attribution.py +581 -0
  112. agent_evolve/application/portfolio_memory_dose.py +788 -0
  113. agent_evolve/application/portfolio_memory_matched_control.py +938 -0
  114. agent_evolve/application/portfolio_memory_transfer.py +297 -0
  115. agent_evolve/application/portfolio_optimization_memory.py +363 -0
  116. agent_evolve/application/portfolio_outcome_feedback.py +1613 -0
  117. agent_evolve/application/portfolio_projection.py +335 -0
  118. agent_evolve/application/portfolio_recombination.py +2032 -0
  119. agent_evolve/application/post_evolution_reflection.py +834 -0
  120. agent_evolve/application/postcommit_rank_authority.py +245 -0
  121. agent_evolve/application/precommitted_portfolio_racing.py +2762 -0
  122. agent_evolve/application/prequential_archive_opportunity_calibration.py +1154 -0
  123. agent_evolve/application/prequential_residual_exploration.py +343 -0
  124. agent_evolve/application/prequential_score_portfolio.py +954 -0
  125. agent_evolve/application/projections.py +292 -0
  126. agent_evolve/application/protected_action_committee.py +1027 -0
  127. agent_evolve/application/protected_branch_pilot.py +376 -0
  128. agent_evolve/application/protected_current_prefix_forecast_opportunity.py +552 -0
  129. agent_evolve/application/provider_replay.py +910 -0
  130. agent_evolve/application/rank_balanced_causal_pilot.py +1372 -0
  131. agent_evolve/application/recombination_residual_expert.py +403 -0
  132. agent_evolve/application/reflection_workflow.py +571 -0
  133. agent_evolve/application/region_conditional_credit.py +911 -0
  134. agent_evolve/application/residual_campaign_runtime.py +531 -0
  135. agent_evolve/application/residual_headroom_campaign_runtime.py +459 -0
  136. agent_evolve/application/residual_headroom_ledger.py +1544 -0
  137. agent_evolve/application/residual_learning_transaction.py +396 -0
  138. agent_evolve/application/residual_portfolio_evolution.py +1228 -0
  139. agent_evolve/application/residual_reachability.py +749 -0
  140. agent_evolve/application/residual_stage_credit.py +499 -0
  141. agent_evolve/application/same_prefix_paired_audit.py +1580 -0
  142. agent_evolve/application/semantic_coverage_score_portfolio.py +838 -0
  143. agent_evolve/application/sequential_lineage_allocation.py +1017 -0
  144. agent_evolve/application/sequential_market_replay.py +1395 -0
  145. agent_evolve/application/sequential_residual_campaign_runtime.py +305 -0
  146. agent_evolve/application/sequential_residual_portfolio_evolution.py +940 -0
  147. agent_evolve/application/single_score_action_allocation.py +299 -0
  148. agent_evolve/application/source_exposure_allocation.py +906 -0
  149. agent_evolve/application/staged_memory.py +210 -0
  150. agent_evolve/application/stratified_cold_start_allocation.py +732 -0
  151. agent_evolve/application/support_guarded_hurdle_score.py +549 -0
  152. agent_evolve/application/target_conditioned_action_forecast.py +595 -0
  153. agent_evolve/application/target_conditioned_campaign.py +566 -0
  154. agent_evolve/application/treatment_assignment.py +201 -0
  155. agent_evolve/application/trusted_objective_evidence.py +217 -0
  156. agent_evolve/application/two_stage_action_evolution.py +1131 -0
  157. agent_evolve/application/v8lite_allocation_policy.py +1083 -0
  158. agent_evolve/application/v9_candidate_policy.py +1303 -0
  159. agent_evolve/bootstrap.py +108 -0
  160. agent_evolve/campaign_presets.py +517 -0
  161. agent_evolve/campaign_profiles.py +452 -0
  162. agent_evolve/campaign_variation_topology.py +288 -0
  163. agent_evolve/campaign_workload.py +950 -0
  164. agent_evolve/cli.py +797 -0
  165. agent_evolve/contract.py +241 -0
  166. agent_evolve/core/__init__.py +91 -0
  167. agent_evolve/core/action_semantics.py +411 -0
  168. agent_evolve/core/authored.py +105 -0
  169. agent_evolve/core/formatting.py +286 -0
  170. agent_evolve/core/optimization_semantics.py +324 -0
  171. agent_evolve/core/problem.py +167 -0
  172. agent_evolve/core/results.py +323 -0
  173. agent_evolve/core/stats.py +70 -0
  174. agent_evolve/core/telemetry.py +100 -0
  175. agent_evolve/domain/__init__.py +89 -0
  176. agent_evolve/domain/artifact.py +162 -0
  177. agent_evolve/domain/durable_text.py +68 -0
  178. agent_evolve/domain/event.py +1454 -0
  179. agent_evolve/domain/finite_action_set.py +426 -0
  180. agent_evolve/domain/finite_variation.py +526 -0
  181. agent_evolve/domain/generative_emission.py +559 -0
  182. agent_evolve/domain/ids.py +163 -0
  183. agent_evolve/domain/inline_text.py +106 -0
  184. agent_evolve/domain/insight.py +27 -0
  185. agent_evolve/domain/lineage.py +737 -0
  186. agent_evolve/domain/llm_task_queue.py +960 -0
  187. agent_evolve/domain/outcome.py +96 -0
  188. agent_evolve/domain/patch.py +854 -0
  189. agent_evolve/domain/typed_json.py +542 -0
  190. agent_evolve/domain/variation_space.py +158 -0
  191. agent_evolve/driver.py +1014 -0
  192. agent_evolve/harness/__init__.py +29 -0
  193. agent_evolve/harness/base.py +242 -0
  194. agent_evolve/harness/directives.py +163 -0
  195. agent_evolve/harness/generative_seal.py +479 -0
  196. agent_evolve/harness/registry.py +41 -0
  197. agent_evolve/infrastructure/__init__.py +39 -0
  198. agent_evolve/infrastructure/artifacts/__init__.py +6 -0
  199. agent_evolve/infrastructure/artifacts/_verification.py +67 -0
  200. agent_evolve/infrastructure/artifacts/filesystem.py +343 -0
  201. agent_evolve/infrastructure/artifacts/in_memory.py +73 -0
  202. agent_evolve/infrastructure/asyncio_runtime.py +109 -0
  203. agent_evolve/infrastructure/authored_runtime.py +188 -0
  204. agent_evolve/infrastructure/authored_worker.py +171 -0
  205. agent_evolve/infrastructure/clock.py +53 -0
  206. agent_evolve/infrastructure/events/__init__.py +6 -0
  207. agent_evolve/infrastructure/events/_validation.py +89 -0
  208. agent_evolve/infrastructure/events/in_memory.py +56 -0
  209. agent_evolve/infrastructure/events/jsonl.py +193 -0
  210. agent_evolve/infrastructure/exception_provenance.py +215 -0
  211. agent_evolve/infrastructure/ids.py +118 -0
  212. agent_evolve/infrastructure/lineage_codec.py +1836 -0
  213. agent_evolve/infrastructure/outcome_adaptive_phase_journal.py +170 -0
  214. agent_evolve/infrastructure/residual_headroom_journal.py +221 -0
  215. agent_evolve/infrastructure/resource_lease.py +370 -0
  216. agent_evolve/infrastructure/sanitization/__init__.py +8 -0
  217. agent_evolve/infrastructure/sanitization/strict_json.py +484 -0
  218. agent_evolve/infrastructure/sequential_phase_journal.py +170 -0
  219. agent_evolve/infrastructure/stream_liveness.py +383 -0
  220. agent_evolve/infrastructure/subprocess_boundary.py +136 -0
  221. agent_evolve/integrations/__init__.py +1 -0
  222. agent_evolve/integrations/botorch/__init__.py +28 -0
  223. agent_evolve/integrations/botorch/finite_qlognehvi.py +190 -0
  224. agent_evolve/integrations/botorch/finite_qlognehvi_batch.py +155 -0
  225. agent_evolve/integrations/botorch/finite_qlognehvi_batch_identity.py +20 -0
  226. agent_evolve/integrations/botorch/finite_qlognehvi_batch_worker.py +55 -0
  227. agent_evolve/integrations/botorch/finite_qlognehvi_identity.py +22 -0
  228. agent_evolve/integrations/botorch/finite_qlognehvi_worker.py +55 -0
  229. agent_evolve/integrations/botorch/subprocess_qlognehvi.py +261 -0
  230. agent_evolve/integrations/botorch/subprocess_qlognehvi_batch.py +273 -0
  231. agent_evolve/integrations/completion.py +242 -0
  232. agent_evolve/integrations/pydantic_ai/__init__.py +441 -0
  233. agent_evolve/integrations/pydantic_ai/action_forecast.py +1068 -0
  234. agent_evolve/integrations/pydantic_ai/agentic_generator.py +2308 -0
  235. agent_evolve/integrations/pydantic_ai/async_generator.py +1604 -0
  236. agent_evolve/integrations/pydantic_ai/boundary_codec.py +1526 -0
  237. agent_evolve/integrations/pydantic_ai/calibrated_portfolio_campaign.py +756 -0
  238. agent_evolve/integrations/pydantic_ai/calibrated_portfolio_selection.py +7537 -0
  239. agent_evolve/integrations/pydantic_ai/campaign_acquisition.py +609 -0
  240. agent_evolve/integrations/pydantic_ai/execution_binding.py +138 -0
  241. agent_evolve/integrations/pydantic_ai/forecast_geometry_action_committee.py +217 -0
  242. agent_evolve/integrations/pydantic_ai/harness.py +159 -0
  243. agent_evolve/integrations/pydantic_ai/heterogeneous_model_execution.py +306 -0
  244. agent_evolve/integrations/pydantic_ai/hierarchical_residual_adaptive_semantic_view.py +179 -0
  245. agent_evolve/integrations/pydantic_ai/json_schema_dialect.py +108 -0
  246. agent_evolve/integrations/pydantic_ai/materialized_hierarchical_residual_expert.py +952 -0
  247. agent_evolve/integrations/pydantic_ai/materialized_portfolio_judge.py +520 -0
  248. agent_evolve/integrations/pydantic_ai/model_execution_profile.py +659 -0
  249. agent_evolve/integrations/pydantic_ai/outbound_request_manifest.py +1170 -0
  250. agent_evolve/integrations/pydantic_ai/portable_residual_consequence_features.py +575 -0
  251. agent_evolve/integrations/pydantic_ai/portfolio_selection.py +422 -0
  252. agent_evolve/integrations/pydantic_ai/progress_aware_openrouter.py +416 -0
  253. agent_evolve/integrations/pydantic_ai/provider_attempt_join.py +1523 -0
  254. agent_evolve/integrations/pydantic_ai/provider_free_calibrated_runner.py +607 -0
  255. agent_evolve/integrations/pydantic_ai/queued_runner.py +2634 -0
  256. agent_evolve/integrations/pydantic_ai/reconciled_residual_reachability.py +1417 -0
  257. agent_evolve/integrations/pydantic_ai/residual_forecast_geometry.py +445 -0
  258. agent_evolve/integrations/pydantic_ai/residual_reachability.py +674 -0
  259. agent_evolve/integrations/pydantic_ai/residual_semantic_cells.py +239 -0
  260. agent_evolve/integrations/pydantic_ai/sealed_output_replay.py +1068 -0
  261. agent_evolve/integrations/pydantic_ai/semantic_coverage_residual_portfolio.py +770 -0
  262. agent_evolve/integrations/pydantic_ai/semantic_decision_replay.py +383 -0
  263. agent_evolve/integrations/pydantic_ai/support_adaptive_residual_portfolio.py +135 -0
  264. agent_evolve/integrations/pydantic_ai/trusted_residual_prompt_context.py +143 -0
  265. agent_evolve/integrations/pydantic_ai/validated_openrouter_model.py +107 -0
  266. agent_evolve/integrations/pymoo_adapter.py +242 -0
  267. agent_evolve/policies/__init__.py +17 -0
  268. agent_evolve/policies/check.py +469 -0
  269. agent_evolve/policies/emit_scaffold.py +451 -0
  270. agent_evolve/policies/feedback/__init__.py +37 -0
  271. agent_evolve/policies/feedback/held_out_asn.py +1325 -0
  272. agent_evolve/policies/genetic.py +607 -0
  273. agent_evolve/policies/llm_backoff.py +183 -0
  274. agent_evolve/policies/llm_chooser.py +226 -0
  275. agent_evolve/policies/llm_generator.py +1760 -0
  276. agent_evolve/policies/llm_init.py +267 -0
  277. agent_evolve/policies/llm_operator.py +109 -0
  278. agent_evolve/policies/llm_prior.py +194 -0
  279. agent_evolve/policies/llm_surrogate.py +334 -0
  280. agent_evolve/policies/measurement_evidence.py +704 -0
  281. agent_evolve/policies/memory/__init__.py +223 -0
  282. agent_evolve/policies/memory/balanced_subset_blocks.py +707 -0
  283. agent_evolve/policies/memory/compatibility_matching.py +593 -0
  284. agent_evolve/policies/memory/global_falsification.py +1841 -0
  285. agent_evolve/policies/memory/prompt_shape.py +503 -0
  286. agent_evolve/policies/memory/randomized_subset.py +714 -0
  287. agent_evolve/policies/memory/staged_causal.py +1270 -0
  288. agent_evolve/policies/memory/treatment_compliance.py +759 -0
  289. agent_evolve/policies/objective_resolution/__init__.py +17 -0
  290. agent_evolve/policies/objective_resolution/fixed_grid.py +364 -0
  291. agent_evolve/policies/operator_portfolio.py +407 -0
  292. agent_evolve/policies/reguidance.py +1133 -0
  293. agent_evolve/policies/reward/__init__.py +83 -0
  294. agent_evolve/policies/reward/affine_candidate_consequence.py +156 -0
  295. agent_evolve/policies/reward/affine_candidate_consequence_3d.py +159 -0
  296. agent_evolve/policies/reward/affine_hypervolume.py +490 -0
  297. agent_evolve/policies/reward/affine_hypervolume_3d.py +567 -0
  298. agent_evolve/policies/reward/contextual_marginal_utility.py +318 -0
  299. agent_evolve/policies/reward/frozen_archive.py +360 -0
  300. agent_evolve/policies/reward/frozen_wave_archive.py +368 -0
  301. agent_evolve/policies/search_state.py +208 -0
  302. agent_evolve/policies/selection/__init__.py +345 -0
  303. agent_evolve/policies/selection/acquisition_certified_slate.py +684 -0
  304. agent_evolve/policies/selection/affine_frontier_context.py +330 -0
  305. agent_evolve/policies/selection/affine_frontier_target.py +473 -0
  306. agent_evolve/policies/selection/archive_elite.py +1346 -0
  307. agent_evolve/policies/selection/calibrated_portfolio_binding.py +640 -0
  308. agent_evolve/policies/selection/calibrated_slate.py +1394 -0
  309. agent_evolve/policies/selection/calibrated_slate_codec.py +579 -0
  310. agent_evolve/policies/selection/common_candidate_pool.py +685 -0
  311. agent_evolve/policies/selection/diagnostic_sampling.py +319 -0
  312. agent_evolve/policies/selection/disjoint_pairs.py +479 -0
  313. agent_evolve/policies/selection/elite_explorer.py +719 -0
  314. agent_evolve/policies/selection/finite_action.py +187 -0
  315. agent_evolve/policies/selection/finite_option_prompt_projection.py +377 -0
  316. agent_evolve/policies/selection/finite_palette_evidence.py +247 -0
  317. agent_evolve/policies/selection/forecast_calibration.py +922 -0
  318. agent_evolve/policies/selection/frontier_probe_slate.py +814 -0
  319. agent_evolve/policies/selection/frozen_archive_pairs.py +762 -0
  320. agent_evolve/policies/selection/full_support_slate.py +91 -0
  321. agent_evolve/policies/selection/meaningful_direction.py +240 -0
  322. agent_evolve/policies/selection/memory_dose_feasibility.py +259 -0
  323. agent_evolve/policies/selection/model_anchored_slate.py +826 -0
  324. agent_evolve/policies/selection/phenotype_recourse.py +979 -0
  325. agent_evolve/policies/selection/proposal_support.py +368 -0
  326. agent_evolve/policies/selection/random_portfolio.py +254 -0
  327. agent_evolve/policies/selection/regret_bounded_slate.py +1084 -0
  328. agent_evolve/policies/selection/residual_frontier.py +463 -0
  329. agent_evolve/policies/selection/residual_frontier_target.py +605 -0
  330. agent_evolve/policies/selection/structural_posterior_slate.py +1571 -0
  331. agent_evolve/policies/selection/target_conditioned_allocator.py +648 -0
  332. agent_evolve/policies/selection/target_conditioned_features.py +812 -0
  333. agent_evolve/policies/selection/target_conditioned_prequential.py +1527 -0
  334. agent_evolve/policies/selection/task_keyed_palette.py +906 -0
  335. agent_evolve/policies/semantics.py +147 -0
  336. agent_evolve/policies/structure.py +362 -0
  337. agent_evolve/policies/structured_output_budget.py +62 -0
  338. agent_evolve/policies/surrogate.py +696 -0
  339. agent_evolve/policies/variation/__init__.py +1 -0
  340. agent_evolve/policies/variation/compositional_finite_catalog.py +426 -0
  341. agent_evolve/policies/variation/crossover_inheritance.py +575 -0
  342. agent_evolve/policies/variation/disjoint_recombination.py +611 -0
  343. agent_evolve/policies/variation/exact_composition_capacity.py +214 -0
  344. agent_evolve/policies/variation/exact_parent_crossover.py +950 -0
  345. agent_evolve/policies/variation/multiscale_restart_catalog.py +372 -0
  346. agent_evolve/policies/variation/source_union_finite_catalog.py +403 -0
  347. agent_evolve/policies/variation/typed_patch.py +1981 -0
  348. agent_evolve/policies/weighted_prior.py +394 -0
  349. agent_evolve/ports/__init__.py +383 -0
  350. agent_evolve/ports/action_allocation.py +733 -0
  351. agent_evolve/ports/action_allocation_frame.py +1153 -0
  352. agent_evolve/ports/action_allocation_frame_commit.py +294 -0
  353. agent_evolve/ports/action_allocation_frame_commit_v3.py +432 -0
  354. agent_evolve/ports/action_allocation_frame_v3.py +995 -0
  355. agent_evolve/ports/action_forecast.py +1568 -0
  356. agent_evolve/ports/action_metric_projection.py +165 -0
  357. agent_evolve/ports/agentic_generator.py +1561 -0
  358. agent_evolve/ports/archive_context.py +136 -0
  359. agent_evolve/ports/artifact_sanitizer.py +44 -0
  360. agent_evolve/ports/artifact_store.py +225 -0
  361. agent_evolve/ports/clock.py +13 -0
  362. agent_evolve/ports/contextual_search_allocation.py +827 -0
  363. agent_evolve/ports/decision_metric_projection.py +258 -0
  364. agent_evolve/ports/event_store.py +55 -0
  365. agent_evolve/ports/executable_hypothesis.py +557 -0
  366. agent_evolve/ports/finite_acquisition.py +377 -0
  367. agent_evolve/ports/finite_acquisition_batch.py +296 -0
  368. agent_evolve/ports/finite_acquisition_batch_json.py +164 -0
  369. agent_evolve/ports/finite_acquisition_json.py +247 -0
  370. agent_evolve/ports/finite_acquisition_space.py +168 -0
  371. agent_evolve/ports/finite_action_selection.py +348 -0
  372. agent_evolve/ports/finite_action_set.py +256 -0
  373. agent_evolve/ports/frontier_target.py +396 -0
  374. agent_evolve/ports/generation_failure.py +43 -0
  375. agent_evolve/ports/hard_feasibility.py +233 -0
  376. agent_evolve/ports/id_factory.py +34 -0
  377. agent_evolve/ports/llm_task_queue.py +93 -0
  378. agent_evolve/ports/objective_resolution.py +419 -0
  379. agent_evolve/ports/paired_allocation_comparison.py +401 -0
  380. agent_evolve/ports/paired_block_schedule.py +475 -0
  381. agent_evolve/ports/parent_measurement.py +336 -0
  382. agent_evolve/ports/portfolio_memory_dose.py +643 -0
  383. agent_evolve/ports/portfolio_selection.py +3169 -0
  384. agent_evolve/ports/postcommit_rank_authority.py +467 -0
  385. agent_evolve/ports/presented_action_evidence.py +794 -0
  386. agent_evolve/ports/resource_lease.py +162 -0
  387. agent_evolve/ports/structured_generator.py +734 -0
  388. agent_evolve/ports/structured_output_budget.py +120 -0
  389. agent_evolve/ports/subprocess_boundary.py +138 -0
  390. agent_evolve/ports/treatment_assignment.py +466 -0
  391. agent_evolve/ports/variation_catalog.py +76 -0
  392. agent_evolve/ports/variation_source.py +226 -0
  393. agent_evolve/proposal_mode.py +157 -0
  394. agent_evolve/proposers/__init__.py +10 -0
  395. agent_evolve/proposers/random_proposer.py +188 -0
  396. agent_evolve/provider_accounting.py +163 -0
  397. agent_evolve/py.typed +0 -0
  398. agent_evolve/reference_method.py +1570 -0
  399. agent_evolve/session/__init__.py +11 -0
  400. agent_evolve/session/authorship.py +864 -0
  401. agent_evolve/session/evaluate.py +236 -0
  402. agent_evolve/session/fidelity.py +237 -0
  403. agent_evolve/session/genetic_loop.py +742 -0
  404. agent_evolve/session/loop.py +803 -0
  405. agent_evolve/session/screening.py +671 -0
  406. agent_evolve/settings.py +376 -0
  407. agent_evolve/workload_kit.py +368 -0
  408. agent_evolve/workload_prompt.py +398 -0
  409. agentevolve_optimizer-0.5.0.dist-info/METADATA +599 -0
  410. agentevolve_optimizer-0.5.0.dist-info/RECORD +414 -0
  411. agentevolve_optimizer-0.5.0.dist-info/WHEEL +5 -0
  412. agentevolve_optimizer-0.5.0.dist-info/entry_points.txt +2 -0
  413. agentevolve_optimizer-0.5.0.dist-info/licenses/LICENSE +21 -0
  414. agentevolve_optimizer-0.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,318 @@
1
+ """Dimension-agnostic fixed-reference utility attribution.
2
+
3
+ The legacy projector scores every candidate independently against the same
4
+ frozen archive. Those marginal gains are order invariant, but they are not
5
+ coalition efficient: redundant candidates can each receive credit for the
6
+ same archive region. The exact Shapley projector below uses only already
7
+ evaluated objective vectors and an injected joint-utility snapshot. It
8
+ therefore allocates the *realized joint stage gain* without another workload
9
+ evaluation, simulator call, or objective-specific branch in the framework.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import hashlib
15
+ import math
16
+ from itertools import combinations
17
+ from dataclasses import dataclass, field
18
+ from typing import Mapping, Protocol, runtime_checkable
19
+
20
+ from agent_evolve.application.evolution_campaign import ArchiveUtilitySnapshot
21
+ from agent_evolve.application.portfolio_evolution import (
22
+ PortfolioMemberDisposition,
23
+ PortfolioVariationWaveResult,
24
+ )
25
+
26
+
27
+ CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_ID = (
28
+ "fixed_reference_candidate_marginal_utility"
29
+ )
30
+ CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_VERSION = 1
31
+ CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_DEFINITION_SHA256 = hashlib.sha256(
32
+ b"agent-evolve:fixed-reference-candidate-marginal-utility:v1;"
33
+ b"snapshot=authenticated-pre-generation-archive-utility;"
34
+ b"candidate=ranked-itt-scored-outcome;infeasible=zero;"
35
+ b"dimension-and-objective-names=opaque;negative-clamp=zero"
36
+ ).hexdigest()
37
+
38
+ CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_ID = (
39
+ "fixed_reference_exact_coalition_shapley_utility"
40
+ )
41
+ CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_VERSION = 1
42
+ CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_DEFINITION_SHA256 = hashlib.sha256(
43
+ b"agent-evolve:fixed-reference-exact-coalition-shapley-utility:v1;"
44
+ b"snapshot=authenticated-pre-generation-archive-utility;"
45
+ b"players=ranked-itt-scored-outcomes;infeasible=zero;"
46
+ b"coalition-value=joint-normalized-archive-gain;"
47
+ b"credit=exact-shapley;efficiency=true;symmetry=true;dummy=true;"
48
+ b"simulator-calls=zero;dimension-and-objective-names=opaque;"
49
+ b"maximum-exact-players=16;floating-residual=canonical-largest-credit"
50
+ ).hexdigest()
51
+
52
+ MAXIMUM_EXACT_SHAPLEY_PLAYERS = 16
53
+
54
+
55
+ @runtime_checkable
56
+ class MarginalUtilitySnapshot(Protocol):
57
+ def marginal_gain(self, point: Mapping[str, float]) -> float: ...
58
+
59
+
60
+ @runtime_checkable
61
+ class JointUtilitySnapshot(Protocol):
62
+ """Replay normalized archive gain for an already evaluated coalition."""
63
+
64
+ def joint_gain(self, points: tuple[Mapping[str, float], ...]) -> float: ...
65
+
66
+
67
+ @runtime_checkable
68
+ class ReplayableArchiveUtility(Protocol):
69
+ def require_snapshot(
70
+ self,
71
+ value: ArchiveUtilitySnapshot,
72
+ ) -> MarginalUtilitySnapshot: ...
73
+
74
+
75
+ @dataclass(frozen=True, slots=True)
76
+ class FixedReferenceContextualMarginalUtilityProjector:
77
+ """Project ranked evaluated members through an injected utility snapshot."""
78
+
79
+ archive_utility: ReplayableArchiveUtility = field(repr=False, compare=False)
80
+ projector_id: str = field(
81
+ init=False,
82
+ default=CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_ID,
83
+ )
84
+ projector_version: int = field(
85
+ init=False,
86
+ default=CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_VERSION,
87
+ )
88
+ definition_sha256: str = field(
89
+ init=False,
90
+ default=CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_DEFINITION_SHA256,
91
+ )
92
+
93
+ def __post_init__(self) -> None:
94
+ if not isinstance(self.archive_utility, ReplayableArchiveUtility):
95
+ raise TypeError("archive_utility must replay marginal-gain snapshots")
96
+ if (
97
+ self.projector_id != CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_ID
98
+ or self.projector_version
99
+ != CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_VERSION
100
+ or self.definition_sha256
101
+ != CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_DEFINITION_SHA256
102
+ ):
103
+ raise ValueError("unsupported contextual marginal utility projector")
104
+
105
+ def project(
106
+ self,
107
+ *,
108
+ snapshot: ArchiveUtilitySnapshot,
109
+ results: tuple[PortfolioVariationWaveResult, ...],
110
+ ) -> tuple[tuple[float, ...], ...]:
111
+ self.__post_init__()
112
+ if type(snapshot) is not ArchiveUtilitySnapshot:
113
+ raise TypeError("snapshot must be exact ArchiveUtilitySnapshot")
114
+ snapshot.__post_init__()
115
+ if type(results) is not tuple or not results:
116
+ raise ValueError("results must be a non-empty exact tuple")
117
+ replayed = self.archive_utility.require_snapshot(snapshot)
118
+ if not isinstance(replayed, MarginalUtilitySnapshot):
119
+ raise TypeError("archive utility returned no marginal-gain snapshot")
120
+ projected: list[tuple[float, ...]] = []
121
+ for result in results:
122
+ if type(result) is not PortfolioVariationWaveResult:
123
+ raise TypeError("results must contain exact portfolio results")
124
+ result.__post_init__()
125
+ values: list[float] = []
126
+ for member, outcome in zip(
127
+ result.receipt.members,
128
+ result.outcomes,
129
+ strict=True,
130
+ ):
131
+ if member.disposition is PortfolioMemberDisposition.CANDIDATE_INFEASIBLE:
132
+ values.append(0.0)
133
+ continue
134
+ candidate = outcome.candidate
135
+ if candidate is None:
136
+ raise ValueError("scored outcome omitted its candidate")
137
+ utility = replayed.marginal_gain(candidate.objective_map)
138
+ if type(utility) is not float or not math.isfinite(utility):
139
+ raise TypeError("marginal utility must be a finite canonical float")
140
+ normalized = max(0.0, utility)
141
+ if normalized > 1.0:
142
+ raise ValueError(
143
+ "archive utility must expose normalized marginal gain in [0, 1]"
144
+ )
145
+ values.append(normalized)
146
+ projected.append(tuple(values))
147
+ return tuple(projected)
148
+
149
+
150
+ def exact_coalition_shapley_values(
151
+ snapshot: JointUtilitySnapshot,
152
+ points: tuple[Mapping[str, float], ...],
153
+ ) -> tuple[float, ...]:
154
+ """Allocate one monotone joint gain exactly over at most sixteen players.
155
+
156
+ This workload-neutral primitive is public because residual portfolio
157
+ stages no longer necessarily originate as legacy
158
+ ``PortfolioVariationWaveResult`` rows. Both the legacy projector and the
159
+ mixed-expert stage closer must nevertheless use the identical coalition
160
+ game and floating-residual rule.
161
+ """
162
+
163
+ player_count = len(points)
164
+ if player_count == 0:
165
+ return ()
166
+ if player_count > MAXIMUM_EXACT_SHAPLEY_PLAYERS:
167
+ raise ValueError(
168
+ "exact coalition attribution supports at most "
169
+ f"{MAXIMUM_EXACT_SHAPLEY_PLAYERS} scored candidates"
170
+ )
171
+
172
+ coalition_values: dict[int, float] = {0: 0.0}
173
+
174
+ def coalition_value(mask: int) -> float:
175
+ cached = coalition_values.get(mask)
176
+ if cached is not None:
177
+ return cached
178
+ value = snapshot.joint_gain(
179
+ tuple(points[index] for index in range(player_count) if mask >> index & 1)
180
+ )
181
+ if type(value) is not float or not math.isfinite(value):
182
+ raise TypeError("joint utility must be a finite canonical float")
183
+ if not 0.0 <= value <= 1.0:
184
+ raise ValueError("joint utility must lie in [0, 1]")
185
+ coalition_values[mask] = value
186
+ return value
187
+
188
+ full_mask = (1 << player_count) - 1
189
+ values: list[float] = []
190
+ for player in range(player_count):
191
+ others = tuple(index for index in range(player_count) if index != player)
192
+ terms: list[float] = []
193
+ player_bit = 1 << player
194
+ for size in range(player_count):
195
+ weight = 1.0 / (player_count * math.comb(player_count - 1, size))
196
+ for members in combinations(others, size):
197
+ mask = 0
198
+ for member in members:
199
+ mask |= 1 << member
200
+ marginal = coalition_value(mask | player_bit) - coalition_value(mask)
201
+ if marginal < -1e-12:
202
+ raise ValueError("joint archive utility is not monotone")
203
+ terms.append(weight * max(0.0, marginal))
204
+ values.append(math.fsum(terms))
205
+
206
+ # Shapley efficiency is exact algebraically. Floating sweeps can leave a
207
+ # few ulps; bind those deterministically to the largest-credit player so
208
+ # serialized credit closes exactly to the observed joint stage gain.
209
+ joint_gain = coalition_value(full_mask)
210
+ residual = joint_gain - math.fsum(values)
211
+ if abs(residual) > 1e-10:
212
+ raise RuntimeError("Shapley credit does not close to joint archive gain")
213
+ correction_index = min(
214
+ range(player_count),
215
+ key=lambda index: (-values[index], index),
216
+ )
217
+ values[correction_index] += residual
218
+ if any(value < 0.0 or value > 1.0 for value in values):
219
+ raise RuntimeError("corrected Shapley credit escapes [0, 1]")
220
+ return tuple(float(value) for value in values)
221
+
222
+
223
+ @dataclass(frozen=True, slots=True)
224
+ class ExactCoalitionShapleyContextualUtilityProjector:
225
+ """Conservatively attribute exact joint stage utility to evaluated actions."""
226
+
227
+ archive_utility: ReplayableArchiveUtility = field(repr=False, compare=False)
228
+ projector_id: str = field(
229
+ init=False,
230
+ default=CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_ID,
231
+ )
232
+ projector_version: int = field(
233
+ init=False,
234
+ default=CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_VERSION,
235
+ )
236
+ definition_sha256: str = field(
237
+ init=False,
238
+ default=CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_DEFINITION_SHA256,
239
+ )
240
+
241
+ def __post_init__(self) -> None:
242
+ if not isinstance(self.archive_utility, ReplayableArchiveUtility):
243
+ raise TypeError("archive_utility must replay utility snapshots")
244
+
245
+ def project(
246
+ self,
247
+ *,
248
+ snapshot: ArchiveUtilitySnapshot,
249
+ results: tuple[PortfolioVariationWaveResult, ...],
250
+ ) -> tuple[tuple[float, ...], ...]:
251
+ self.__post_init__()
252
+ if type(snapshot) is not ArchiveUtilitySnapshot:
253
+ raise TypeError("snapshot must be exact ArchiveUtilitySnapshot")
254
+ snapshot.__post_init__()
255
+ if type(results) is not tuple or not results:
256
+ raise ValueError("results must be a non-empty exact tuple")
257
+ replayed = self.archive_utility.require_snapshot(snapshot)
258
+ if not isinstance(replayed, JointUtilitySnapshot):
259
+ raise TypeError("archive utility returned no joint-gain snapshot")
260
+
261
+ # Canonical candidate identity makes attribution invariant to concurrent
262
+ # lane completion order. Infeasible members are retained as explicit
263
+ # zero rows but are not players in the scored coalition.
264
+ scored: list[tuple[str, int, int, Mapping[str, float]]] = []
265
+ rows: list[list[float]] = []
266
+ for result_index, result in enumerate(results):
267
+ if type(result) is not PortfolioVariationWaveResult:
268
+ raise TypeError("results must contain exact portfolio results")
269
+ result.__post_init__()
270
+ row = [0.0] * len(result.receipt.members)
271
+ rows.append(row)
272
+ for member_index, (member, outcome) in enumerate(
273
+ zip(result.receipt.members, result.outcomes, strict=True)
274
+ ):
275
+ if member.disposition is PortfolioMemberDisposition.CANDIDATE_INFEASIBLE:
276
+ continue
277
+ candidate = outcome.candidate
278
+ if candidate is None:
279
+ raise ValueError("scored outcome omitted its candidate")
280
+ scored.append(
281
+ (
282
+ candidate.candidate_id.value,
283
+ result_index,
284
+ member_index,
285
+ candidate.objective_map,
286
+ )
287
+ )
288
+ scored.sort(key=lambda value: value[0])
289
+ if len({value[0] for value in scored}) != len(scored):
290
+ raise ValueError("one stage cannot attribute a candidate more than once")
291
+ credits = exact_coalition_shapley_values(
292
+ replayed,
293
+ tuple(value[3] for value in scored),
294
+ )
295
+ for (_candidate_id, result_index, member_index, _point), credit in zip(
296
+ scored,
297
+ credits,
298
+ strict=True,
299
+ ):
300
+ rows[result_index][member_index] = credit
301
+ return tuple(tuple(row) for row in rows)
302
+
303
+
304
+ __all__ = [
305
+ "CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_DEFINITION_SHA256",
306
+ "CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_ID",
307
+ "CONTEXTUAL_MARGINAL_UTILITY_PROJECTOR_VERSION",
308
+ "CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_DEFINITION_SHA256",
309
+ "CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_ID",
310
+ "CONTEXTUAL_SHAPLEY_UTILITY_PROJECTOR_VERSION",
311
+ "ExactCoalitionShapleyContextualUtilityProjector",
312
+ "FixedReferenceContextualMarginalUtilityProjector",
313
+ "JointUtilitySnapshot",
314
+ "MAXIMUM_EXACT_SHAPLEY_PLAYERS",
315
+ "MarginalUtilitySnapshot",
316
+ "ReplayableArchiveUtility",
317
+ "exact_coalition_shapley_values",
318
+ ]
@@ -0,0 +1,360 @@
1
+ """Order-invariant marginal hypervolume credit against a frozen wave archive.
2
+
3
+ The policy deliberately freezes the archive before a concurrent proposal wave.
4
+ Every invocation is therefore scored against the same history cutoff, rather
5
+ than against an archive that changes with task completion or publication order.
6
+ It is an exact two-objective policy; higher-dimensional indicators belong behind
7
+ a separate policy with a distinct reward-definition hash.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import hashlib
13
+ import json
14
+ import math
15
+ from collections.abc import Mapping, Sequence
16
+ from dataclasses import dataclass, field
17
+ from numbers import Real
18
+ from typing import Protocol
19
+
20
+ from agent_evolve.core.problem import ObjectiveSpec, validate_objective_specs
21
+
22
+
23
+ ObjectivePoint = tuple[tuple[str, float], ...]
24
+ _DEFINITION_DOMAIN = b"agent-evolve:frozen-archive-marginal-hv-reward:v1\x00"
25
+ _SNAPSHOT_DOMAIN = b"agent-evolve:frozen-archive-snapshot-2d:v1\x00"
26
+
27
+
28
+ class _RewardCandidate(Protocol):
29
+ valid: bool
30
+ operator_compliant: bool
31
+
32
+ @property
33
+ def objective_map(self) -> dict[str, float]: ...
34
+
35
+
36
+ def _finite(value: Real, *, name: str) -> float:
37
+ if isinstance(value, bool) or not isinstance(value, Real):
38
+ raise TypeError(f"{name} must be a real number")
39
+ result = float(value)
40
+ if not math.isfinite(result):
41
+ raise ValueError(f"{name} must be finite")
42
+ return result
43
+
44
+
45
+ def _canonical_point(
46
+ value: Mapping[str, Real],
47
+ objectives: tuple[ObjectiveSpec, ObjectiveSpec],
48
+ *,
49
+ name: str,
50
+ ) -> ObjectivePoint:
51
+ if not isinstance(value, Mapping):
52
+ raise TypeError(f"{name} must be a mapping")
53
+ expected = {objective.name for objective in objectives}
54
+ supplied = set(value)
55
+ if supplied != expected:
56
+ missing = sorted(expected - supplied)
57
+ extra = sorted(supplied - expected)
58
+ raise ValueError(
59
+ f"{name} objective keys differ: missing={missing}, extra={extra}"
60
+ )
61
+ return tuple(
62
+ (
63
+ objective.name,
64
+ _finite(value[objective.name], name=f"{name}.{objective.name}"),
65
+ )
66
+ for objective in objectives
67
+ )
68
+
69
+
70
+ def _point_record(point: ObjectivePoint) -> list[list[str]]:
71
+ return [[name, value.hex()] for name, value in point]
72
+
73
+
74
+ def _transform(
75
+ point: ObjectivePoint,
76
+ objectives: tuple[ObjectiveSpec, ObjectiveSpec],
77
+ ) -> tuple[float, float]:
78
+ values = dict(point)
79
+ return tuple(
80
+ values[objective.name] if objective.goal == "min" else -values[objective.name]
81
+ for objective in objectives
82
+ ) # type: ignore[return-value]
83
+
84
+
85
+ def hypervolume_2d(
86
+ points: Sequence[tuple[Real, Real]],
87
+ reference_point: tuple[Real, Real],
88
+ ) -> float:
89
+ """Exact sweep for a two-objective minimization front.
90
+
91
+ Points that do not strictly improve both coordinates of the reference have
92
+ zero measure inside its rectangle. Dominated and duplicate points are
93
+ removed deterministically before the sweep.
94
+ """
95
+
96
+ if type(reference_point) is not tuple or len(reference_point) != 2:
97
+ raise TypeError("reference_point must be an exact two-item tuple")
98
+ if isinstance(points, (str, bytes)) or not isinstance(points, Sequence):
99
+ raise TypeError("points must be a sequence of exact two-item tuples")
100
+ canonical_points: list[tuple[float, float]] = []
101
+ for index, point in enumerate(points):
102
+ if type(point) is not tuple or len(point) != 2:
103
+ raise TypeError(f"points[{index}] must be an exact two-item tuple")
104
+ canonical_points.append(
105
+ (
106
+ _finite(point[0], name=f"points[{index}][0]"),
107
+ _finite(point[1], name=f"points[{index}][1]"),
108
+ )
109
+ )
110
+ reference = (
111
+ _finite(reference_point[0], name="reference_point[0]"),
112
+ _finite(reference_point[1], name="reference_point[1]"),
113
+ )
114
+ eligible = sorted(set(canonical_points))
115
+ eligible = [
116
+ point
117
+ for point in eligible
118
+ if point[0] < reference[0] and point[1] < reference[1]
119
+ ]
120
+ frontier: list[tuple[float, float]] = []
121
+ best_second = math.inf
122
+ for point in eligible:
123
+ if point[1] < best_second:
124
+ frontier.append(point)
125
+ best_second = point[1]
126
+ area = 0.0
127
+ for index, point in enumerate(frontier):
128
+ next_first = (
129
+ frontier[index + 1][0] if index + 1 < len(frontier) else reference[0]
130
+ )
131
+ area += (next_first - point[0]) * (reference[1] - point[1])
132
+ if area < 0 or not math.isfinite(area): # pragma: no cover - sweep guard.
133
+ raise RuntimeError("hypervolume sweep produced an invalid area")
134
+ return area
135
+
136
+
137
+ @dataclass(frozen=True, slots=True)
138
+ class FrozenArchiveSnapshot2D:
139
+ """Canonical pre-wave archive and fixed reference for one reward stratum."""
140
+
141
+ objectives: tuple[ObjectiveSpec, ObjectiveSpec]
142
+ reference_point: ObjectivePoint
143
+ archive_points: tuple[ObjectivePoint, ...]
144
+ base_hypervolume: float = field(init=False)
145
+ normalization: float = field(init=False)
146
+ definition_hash: str = field(init=False)
147
+ snapshot_hash: str = field(init=False)
148
+
149
+ def __post_init__(self) -> None:
150
+ if type(self.objectives) is not tuple or len(self.objectives) != 2:
151
+ raise ValueError(
152
+ "frozen hypervolume reward requires exactly two objectives"
153
+ )
154
+ validate_objective_specs(self.objectives)
155
+ if type(self.reference_point) is not tuple:
156
+ raise TypeError("reference_point must be an exact tuple")
157
+ if tuple(name for name, _ in self.reference_point) != tuple(
158
+ objective.name for objective in self.objectives
159
+ ):
160
+ raise ValueError("reference_point must follow objective order")
161
+ for _, value in self.reference_point:
162
+ _finite(value, name="reference point value")
163
+ if type(self.archive_points) is not tuple:
164
+ raise TypeError("archive_points must be an exact tuple")
165
+ expected_names = tuple(objective.name for objective in self.objectives)
166
+ for point in self.archive_points:
167
+ if (
168
+ type(point) is not tuple
169
+ or tuple(name for name, _ in point) != expected_names
170
+ ):
171
+ raise ValueError("archive points must follow objective order")
172
+ for _, value in point:
173
+ _finite(value, name="archive point value")
174
+ canonical = tuple(
175
+ sorted(
176
+ set(self.archive_points),
177
+ key=lambda point: tuple(value for _, value in point),
178
+ )
179
+ )
180
+ if canonical != self.archive_points:
181
+ raise ValueError("archive_points must be unique and canonically sorted")
182
+
183
+ reference = _transform(self.reference_point, self.objectives)
184
+ transformed = tuple(
185
+ _transform(point, self.objectives) for point in self.archive_points
186
+ )
187
+ base = hypervolume_2d(transformed, reference)
188
+ normalization = max(abs(base), 1.0)
189
+ definition_record = {
190
+ "schema_version": 1,
191
+ "indicator": "two_objective_fixed_reference_hypervolume",
192
+ "credit": "individual_candidate_marginal_gain_against_frozen_archive",
193
+ "normalization": "divide_by_max_abs_base_hypervolume_or_one",
194
+ "invalid_or_operator_noncompliant_reward": -1.0,
195
+ "zero_gain_reward": 0.0,
196
+ "objectives": [
197
+ {"name": objective.name, "goal": objective.goal}
198
+ for objective in self.objectives
199
+ ],
200
+ "reference_point": _point_record(self.reference_point),
201
+ }
202
+ snapshot_record = {
203
+ "definition": definition_record,
204
+ "archive_points": [_point_record(point) for point in self.archive_points],
205
+ "base_hypervolume": base.hex(),
206
+ "normalization": normalization.hex(),
207
+ }
208
+ definition_payload = json.dumps(
209
+ definition_record,
210
+ ensure_ascii=True,
211
+ allow_nan=False,
212
+ separators=(",", ":"),
213
+ sort_keys=True,
214
+ ).encode("ascii")
215
+ snapshot_payload = json.dumps(
216
+ snapshot_record,
217
+ ensure_ascii=True,
218
+ allow_nan=False,
219
+ separators=(",", ":"),
220
+ sort_keys=True,
221
+ ).encode("ascii")
222
+ object.__setattr__(self, "base_hypervolume", base)
223
+ object.__setattr__(self, "normalization", normalization)
224
+ object.__setattr__(
225
+ self,
226
+ "definition_hash",
227
+ hashlib.sha256(_DEFINITION_DOMAIN + definition_payload).hexdigest(),
228
+ )
229
+ object.__setattr__(
230
+ self,
231
+ "snapshot_hash",
232
+ hashlib.sha256(_SNAPSHOT_DOMAIN + snapshot_payload).hexdigest(),
233
+ )
234
+
235
+ @classmethod
236
+ def create(
237
+ cls,
238
+ *,
239
+ objectives: Sequence[ObjectiveSpec],
240
+ reference_point: Mapping[str, Real],
241
+ archive_points: Sequence[Mapping[str, Real]],
242
+ ) -> "FrozenArchiveSnapshot2D":
243
+ objective_tuple = tuple(objectives)
244
+ if len(objective_tuple) != 2:
245
+ raise ValueError(
246
+ "frozen hypervolume reward requires exactly two objectives"
247
+ )
248
+ validate_objective_specs(objective_tuple)
249
+ typed_objectives = (objective_tuple[0], objective_tuple[1])
250
+ reference = _canonical_point(
251
+ reference_point,
252
+ typed_objectives,
253
+ name="reference_point",
254
+ )
255
+ points = tuple(
256
+ sorted(
257
+ {
258
+ _canonical_point(
259
+ point,
260
+ typed_objectives,
261
+ name=f"archive_points[{index}]",
262
+ )
263
+ for index, point in enumerate(archive_points)
264
+ },
265
+ key=lambda point: tuple(value for _, value in point),
266
+ )
267
+ )
268
+ return cls(typed_objectives, reference, points)
269
+
270
+ def augmented_hypervolume(self, point: Mapping[str, Real]) -> float:
271
+ candidate = _canonical_point(point, self.objectives, name="candidate")
272
+ reference = _transform(self.reference_point, self.objectives)
273
+ transformed = tuple(
274
+ _transform(archive_point, self.objectives)
275
+ for archive_point in (*self.archive_points, candidate)
276
+ )
277
+ return hypervolume_2d(transformed, reference)
278
+
279
+
280
+ @dataclass(frozen=True, slots=True)
281
+ class FrozenArchiveRewardRecord:
282
+ status: str
283
+ reward: float
284
+ marginal_hypervolume_gain: float
285
+ base_hypervolume: float
286
+ augmented_hypervolume: float
287
+ normalization: float
288
+ reward_definition_hash: str
289
+ archive_snapshot_hash: str
290
+ candidate_point: ObjectivePoint | None
291
+
292
+
293
+ @dataclass(frozen=True, slots=True)
294
+ class FrozenArchiveMarginalHypervolumeReward:
295
+ """Callable engine policy plus an inspectable per-candidate reward record."""
296
+
297
+ snapshot: FrozenArchiveSnapshot2D
298
+
299
+ @property
300
+ def definition_hash(self) -> str:
301
+ return self.snapshot.definition_hash
302
+
303
+ def record(self, child: _RewardCandidate) -> FrozenArchiveRewardRecord:
304
+ if not child.valid:
305
+ return self._failure_record("invalid_candidate")
306
+ if not child.operator_compliant:
307
+ return self._failure_record("operator_noncompliant")
308
+ candidate = _canonical_point(
309
+ child.objective_map,
310
+ self.snapshot.objectives,
311
+ name="child.objectives",
312
+ )
313
+ augmented = self.snapshot.augmented_hypervolume(dict(candidate))
314
+ gain = max(0.0, augmented - self.snapshot.base_hypervolume)
315
+ reward = gain / self.snapshot.normalization
316
+ return FrozenArchiveRewardRecord(
317
+ status="credited",
318
+ reward=float(reward),
319
+ marginal_hypervolume_gain=float(gain),
320
+ base_hypervolume=self.snapshot.base_hypervolume,
321
+ augmented_hypervolume=augmented,
322
+ normalization=self.snapshot.normalization,
323
+ reward_definition_hash=self.definition_hash,
324
+ archive_snapshot_hash=self.snapshot.snapshot_hash,
325
+ candidate_point=candidate,
326
+ )
327
+
328
+ def _failure_record(self, status: str) -> FrozenArchiveRewardRecord:
329
+ return FrozenArchiveRewardRecord(
330
+ status=status,
331
+ reward=-1.0,
332
+ marginal_hypervolume_gain=0.0,
333
+ base_hypervolume=self.snapshot.base_hypervolume,
334
+ augmented_hypervolume=self.snapshot.base_hypervolume,
335
+ normalization=self.snapshot.normalization,
336
+ reward_definition_hash=self.definition_hash,
337
+ archive_snapshot_hash=self.snapshot.snapshot_hash,
338
+ candidate_point=None,
339
+ )
340
+
341
+ def __call__(
342
+ self,
343
+ child: _RewardCandidate,
344
+ parents: tuple[_RewardCandidate, ...],
345
+ objectives: Sequence[ObjectiveSpec],
346
+ ) -> float:
347
+ del parents
348
+ if tuple(objectives) != self.snapshot.objectives:
349
+ raise ValueError(
350
+ "reward objectives differ from the frozen archive snapshot"
351
+ )
352
+ return self.record(child).reward
353
+
354
+
355
+ __all__ = [
356
+ "FrozenArchiveMarginalHypervolumeReward",
357
+ "FrozenArchiveRewardRecord",
358
+ "FrozenArchiveSnapshot2D",
359
+ "hypervolume_2d",
360
+ ]