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.
- agent_evolve/__init__.py +722 -0
- agent_evolve/agentic.py +2800 -0
- agent_evolve/api.py +767 -0
- agent_evolve/application/__init__.py +1580 -0
- agent_evolve/application/action_allocation.py +744 -0
- agent_evolve/application/action_allocation_frame.py +347 -0
- agent_evolve/application/action_allocation_frame_commit.py +185 -0
- agent_evolve/application/action_allocation_frame_commit_v3.py +184 -0
- agent_evolve/application/action_allocation_frame_v3.py +338 -0
- agent_evolve/application/action_archive_value.py +497 -0
- agent_evolve/application/action_evidence_consistency.py +455 -0
- agent_evolve/application/action_forecast_partitioning.py +1471 -0
- agent_evolve/application/action_metric_projection.py +211 -0
- agent_evolve/application/action_role_value.py +680 -0
- agent_evolve/application/action_score_authorities.py +363 -0
- agent_evolve/application/action_structural_signature.py +116 -0
- agent_evolve/application/action_target_realization.py +402 -0
- agent_evolve/application/agentic_evolution.py +7734 -0
- agent_evolve/application/agentic_portfolio_residual_expert.py +835 -0
- agent_evolve/application/anchor_residual_identification.py +463 -0
- agent_evolve/application/archive_conditioned_action_target.py +208 -0
- agent_evolve/application/artifact_journal.py +246 -0
- agent_evolve/application/artifact_replay.py +347 -0
- agent_evolve/application/budgeted_optimizer.py +1828 -0
- agent_evolve/application/calibrated_campaign.py +485 -0
- agent_evolve/application/calibrated_current_prefix_forecast_opportunity.py +322 -0
- agent_evolve/application/calibrated_positive_gain_opportunity.py +1581 -0
- agent_evolve/application/campaign_capacity_recourse.py +254 -0
- agent_evolve/application/campaign_contextual_outcomes.py +119 -0
- agent_evolve/application/campaign_diagnostic_blocks.py +930 -0
- agent_evolve/application/campaign_evidence_registry.py +262 -0
- agent_evolve/application/campaign_execution.py +2537 -0
- agent_evolve/application/campaign_generation_audit.py +942 -0
- agent_evolve/application/campaign_learning.py +1812 -0
- agent_evolve/application/campaign_learning_runtime.py +1977 -0
- agent_evolve/application/campaign_search_phase.py +227 -0
- agent_evolve/application/campaign_selector_context_extension.py +220 -0
- agent_evolve/application/campaign_variation_envelope.py +649 -0
- agent_evolve/application/campaign_variation_trace.py +451 -0
- agent_evolve/application/candidate_archive_consequence.py +128 -0
- agent_evolve/application/causal_opportunity_portfolio_gate.py +385 -0
- agent_evolve/application/composite_outcome_updater.py +145 -0
- agent_evolve/application/composition_portfolio_selection.py +363 -0
- agent_evolve/application/concurrent_stage.py +144 -0
- agent_evolve/application/contextual_action_allocation.py +181 -0
- agent_evolve/application/contextual_campaign_outcomes.py +267 -0
- agent_evolve/application/contextual_campaign_planning.py +1366 -0
- agent_evolve/application/contextual_delayed_credit.py +651 -0
- agent_evolve/application/contextual_search_controller.py +2374 -0
- agent_evolve/application/current_prefix_forecast_opportunity.py +714 -0
- agent_evolve/application/decision_metric_projection.py +112 -0
- agent_evolve/application/derived_action_semantics.py +129 -0
- agent_evolve/application/detailed_evaluation.py +449 -0
- agent_evolve/application/earned_lineage.py +1011 -0
- agent_evolve/application/effective_choice_audit.py +484 -0
- agent_evolve/application/empirical_consequence_calibration.py +908 -0
- agent_evolve/application/evaluation_accounting.py +325 -0
- agent_evolve/application/evaluation_cache.py +199 -0
- agent_evolve/application/evaluation_escrow.py +547 -0
- agent_evolve/application/evaluation_recourse.py +253 -0
- agent_evolve/application/event_recorder.py +151 -0
- agent_evolve/application/evolution_campaign.py +1840 -0
- agent_evolve/application/executable_hypothesis.py +323 -0
- agent_evolve/application/factorial_branch_pilot.py +772 -0
- agent_evolve/application/finite_acquisition_capacity_recourse.py +672 -0
- agent_evolve/application/finite_acquisition_residual_expert.py +373 -0
- agent_evolve/application/finite_acquisition_variation_envelope.py +802 -0
- agent_evolve/application/finite_action_hypothesis_semantics.py +446 -0
- agent_evolve/application/finite_action_selection.py +188 -0
- agent_evolve/application/finite_action_set.py +306 -0
- agent_evolve/application/finite_action_transition.py +537 -0
- agent_evolve/application/finite_variation_eligibility.py +296 -0
- agent_evolve/application/forecast_geometry_portfolio.py +799 -0
- agent_evolve/application/forecast_opportunity_shadow_calibration.py +316 -0
- agent_evolve/application/front_proximity_admission.py +311 -0
- agent_evolve/application/front_proximity_parent_basis.py +458 -0
- agent_evolve/application/frozen_hurdle_score.py +659 -0
- agent_evolve/application/g3_causal_screen.py +2257 -0
- agent_evolve/application/g3_causal_validation.py +1046 -0
- agent_evolve/application/g3_postseal_curation.py +818 -0
- agent_evolve/application/gated_agentic_generator.py +205 -0
- agent_evolve/application/generation_feedback.py +293 -0
- agent_evolve/application/generative_proposal_journal.py +185 -0
- agent_evolve/application/geometry_conditional_elasticity.py +453 -0
- agent_evolve/application/global_wave_action_allocation.py +1151 -0
- agent_evolve/application/head_mass_conditional_seat.py +268 -0
- agent_evolve/application/identifiable_reflection_evidence.py +1147 -0
- agent_evolve/application/identifiable_reflection_learning.py +395 -0
- agent_evolve/application/identifiable_reflection_request.py +364 -0
- agent_evolve/application/in_memory_residual_archive.py +341 -0
- agent_evolve/application/insight_memory.py +1804 -0
- agent_evolve/application/live_runtime_manifest.py +758 -0
- agent_evolve/application/llm_task_queue.py +769 -0
- agent_evolve/application/matched_finite_action_block.py +409 -0
- agent_evolve/application/materialized_action_broker.py +2328 -0
- agent_evolve/application/materialized_action_constraints.py +83 -0
- agent_evolve/application/materialized_variation.py +211 -0
- agent_evolve/application/multi_option_evolution.py +1536 -0
- agent_evolve/application/outcome_adaptive_action_racing.py +2827 -0
- agent_evolve/application/outcome_adaptive_residual_campaign_runtime.py +580 -0
- agent_evolve/application/outcome_adaptive_residual_portfolio_evolution.py +3671 -0
- agent_evolve/application/outcome_conditioned_portfolio_selection.py +1374 -0
- agent_evolve/application/outcome_relation.py +193 -0
- agent_evolve/application/paired_allocation_comparison.py +241 -0
- agent_evolve/application/paired_block_schedule.py +127 -0
- agent_evolve/application/parent_measurement.py +226 -0
- agent_evolve/application/pareto_archive.py +811 -0
- agent_evolve/application/portfolio_campaign_runtime.py +4739 -0
- agent_evolve/application/portfolio_evolution.py +2950 -0
- agent_evolve/application/portfolio_hypothesis_observations.py +814 -0
- agent_evolve/application/portfolio_memory_attribution.py +581 -0
- agent_evolve/application/portfolio_memory_dose.py +788 -0
- agent_evolve/application/portfolio_memory_matched_control.py +938 -0
- agent_evolve/application/portfolio_memory_transfer.py +297 -0
- agent_evolve/application/portfolio_optimization_memory.py +363 -0
- agent_evolve/application/portfolio_outcome_feedback.py +1613 -0
- agent_evolve/application/portfolio_projection.py +335 -0
- agent_evolve/application/portfolio_recombination.py +2032 -0
- agent_evolve/application/post_evolution_reflection.py +834 -0
- agent_evolve/application/postcommit_rank_authority.py +245 -0
- agent_evolve/application/precommitted_portfolio_racing.py +2762 -0
- agent_evolve/application/prequential_archive_opportunity_calibration.py +1154 -0
- agent_evolve/application/prequential_residual_exploration.py +343 -0
- agent_evolve/application/prequential_score_portfolio.py +954 -0
- agent_evolve/application/projections.py +292 -0
- agent_evolve/application/protected_action_committee.py +1027 -0
- agent_evolve/application/protected_branch_pilot.py +376 -0
- agent_evolve/application/protected_current_prefix_forecast_opportunity.py +552 -0
- agent_evolve/application/provider_replay.py +910 -0
- agent_evolve/application/rank_balanced_causal_pilot.py +1372 -0
- agent_evolve/application/recombination_residual_expert.py +403 -0
- agent_evolve/application/reflection_workflow.py +571 -0
- agent_evolve/application/region_conditional_credit.py +911 -0
- agent_evolve/application/residual_campaign_runtime.py +531 -0
- agent_evolve/application/residual_headroom_campaign_runtime.py +459 -0
- agent_evolve/application/residual_headroom_ledger.py +1544 -0
- agent_evolve/application/residual_learning_transaction.py +396 -0
- agent_evolve/application/residual_portfolio_evolution.py +1228 -0
- agent_evolve/application/residual_reachability.py +749 -0
- agent_evolve/application/residual_stage_credit.py +499 -0
- agent_evolve/application/same_prefix_paired_audit.py +1580 -0
- agent_evolve/application/semantic_coverage_score_portfolio.py +838 -0
- agent_evolve/application/sequential_lineage_allocation.py +1017 -0
- agent_evolve/application/sequential_market_replay.py +1395 -0
- agent_evolve/application/sequential_residual_campaign_runtime.py +305 -0
- agent_evolve/application/sequential_residual_portfolio_evolution.py +940 -0
- agent_evolve/application/single_score_action_allocation.py +299 -0
- agent_evolve/application/source_exposure_allocation.py +906 -0
- agent_evolve/application/staged_memory.py +210 -0
- agent_evolve/application/stratified_cold_start_allocation.py +732 -0
- agent_evolve/application/support_guarded_hurdle_score.py +549 -0
- agent_evolve/application/target_conditioned_action_forecast.py +595 -0
- agent_evolve/application/target_conditioned_campaign.py +566 -0
- agent_evolve/application/treatment_assignment.py +201 -0
- agent_evolve/application/trusted_objective_evidence.py +217 -0
- agent_evolve/application/two_stage_action_evolution.py +1131 -0
- agent_evolve/application/v8lite_allocation_policy.py +1083 -0
- agent_evolve/application/v9_candidate_policy.py +1303 -0
- agent_evolve/bootstrap.py +108 -0
- agent_evolve/campaign_presets.py +517 -0
- agent_evolve/campaign_profiles.py +452 -0
- agent_evolve/campaign_variation_topology.py +288 -0
- agent_evolve/campaign_workload.py +950 -0
- agent_evolve/cli.py +797 -0
- agent_evolve/contract.py +241 -0
- agent_evolve/core/__init__.py +91 -0
- agent_evolve/core/action_semantics.py +411 -0
- agent_evolve/core/authored.py +105 -0
- agent_evolve/core/formatting.py +286 -0
- agent_evolve/core/optimization_semantics.py +324 -0
- agent_evolve/core/problem.py +167 -0
- agent_evolve/core/results.py +323 -0
- agent_evolve/core/stats.py +70 -0
- agent_evolve/core/telemetry.py +100 -0
- agent_evolve/domain/__init__.py +89 -0
- agent_evolve/domain/artifact.py +162 -0
- agent_evolve/domain/durable_text.py +68 -0
- agent_evolve/domain/event.py +1454 -0
- agent_evolve/domain/finite_action_set.py +426 -0
- agent_evolve/domain/finite_variation.py +526 -0
- agent_evolve/domain/generative_emission.py +559 -0
- agent_evolve/domain/ids.py +163 -0
- agent_evolve/domain/inline_text.py +106 -0
- agent_evolve/domain/insight.py +27 -0
- agent_evolve/domain/lineage.py +737 -0
- agent_evolve/domain/llm_task_queue.py +960 -0
- agent_evolve/domain/outcome.py +96 -0
- agent_evolve/domain/patch.py +854 -0
- agent_evolve/domain/typed_json.py +542 -0
- agent_evolve/domain/variation_space.py +158 -0
- agent_evolve/driver.py +1014 -0
- agent_evolve/harness/__init__.py +29 -0
- agent_evolve/harness/base.py +242 -0
- agent_evolve/harness/directives.py +163 -0
- agent_evolve/harness/generative_seal.py +479 -0
- agent_evolve/harness/registry.py +41 -0
- agent_evolve/infrastructure/__init__.py +39 -0
- agent_evolve/infrastructure/artifacts/__init__.py +6 -0
- agent_evolve/infrastructure/artifacts/_verification.py +67 -0
- agent_evolve/infrastructure/artifacts/filesystem.py +343 -0
- agent_evolve/infrastructure/artifacts/in_memory.py +73 -0
- agent_evolve/infrastructure/asyncio_runtime.py +109 -0
- agent_evolve/infrastructure/authored_runtime.py +188 -0
- agent_evolve/infrastructure/authored_worker.py +171 -0
- agent_evolve/infrastructure/clock.py +53 -0
- agent_evolve/infrastructure/events/__init__.py +6 -0
- agent_evolve/infrastructure/events/_validation.py +89 -0
- agent_evolve/infrastructure/events/in_memory.py +56 -0
- agent_evolve/infrastructure/events/jsonl.py +193 -0
- agent_evolve/infrastructure/exception_provenance.py +215 -0
- agent_evolve/infrastructure/ids.py +118 -0
- agent_evolve/infrastructure/lineage_codec.py +1836 -0
- agent_evolve/infrastructure/outcome_adaptive_phase_journal.py +170 -0
- agent_evolve/infrastructure/residual_headroom_journal.py +221 -0
- agent_evolve/infrastructure/resource_lease.py +370 -0
- agent_evolve/infrastructure/sanitization/__init__.py +8 -0
- agent_evolve/infrastructure/sanitization/strict_json.py +484 -0
- agent_evolve/infrastructure/sequential_phase_journal.py +170 -0
- agent_evolve/infrastructure/stream_liveness.py +383 -0
- agent_evolve/infrastructure/subprocess_boundary.py +136 -0
- agent_evolve/integrations/__init__.py +1 -0
- agent_evolve/integrations/botorch/__init__.py +28 -0
- agent_evolve/integrations/botorch/finite_qlognehvi.py +190 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch.py +155 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch_identity.py +20 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch_worker.py +55 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_identity.py +22 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_worker.py +55 -0
- agent_evolve/integrations/botorch/subprocess_qlognehvi.py +261 -0
- agent_evolve/integrations/botorch/subprocess_qlognehvi_batch.py +273 -0
- agent_evolve/integrations/completion.py +242 -0
- agent_evolve/integrations/pydantic_ai/__init__.py +441 -0
- agent_evolve/integrations/pydantic_ai/action_forecast.py +1068 -0
- agent_evolve/integrations/pydantic_ai/agentic_generator.py +2308 -0
- agent_evolve/integrations/pydantic_ai/async_generator.py +1604 -0
- agent_evolve/integrations/pydantic_ai/boundary_codec.py +1526 -0
- agent_evolve/integrations/pydantic_ai/calibrated_portfolio_campaign.py +756 -0
- agent_evolve/integrations/pydantic_ai/calibrated_portfolio_selection.py +7537 -0
- agent_evolve/integrations/pydantic_ai/campaign_acquisition.py +609 -0
- agent_evolve/integrations/pydantic_ai/execution_binding.py +138 -0
- agent_evolve/integrations/pydantic_ai/forecast_geometry_action_committee.py +217 -0
- agent_evolve/integrations/pydantic_ai/harness.py +159 -0
- agent_evolve/integrations/pydantic_ai/heterogeneous_model_execution.py +306 -0
- agent_evolve/integrations/pydantic_ai/hierarchical_residual_adaptive_semantic_view.py +179 -0
- agent_evolve/integrations/pydantic_ai/json_schema_dialect.py +108 -0
- agent_evolve/integrations/pydantic_ai/materialized_hierarchical_residual_expert.py +952 -0
- agent_evolve/integrations/pydantic_ai/materialized_portfolio_judge.py +520 -0
- agent_evolve/integrations/pydantic_ai/model_execution_profile.py +659 -0
- agent_evolve/integrations/pydantic_ai/outbound_request_manifest.py +1170 -0
- agent_evolve/integrations/pydantic_ai/portable_residual_consequence_features.py +575 -0
- agent_evolve/integrations/pydantic_ai/portfolio_selection.py +422 -0
- agent_evolve/integrations/pydantic_ai/progress_aware_openrouter.py +416 -0
- agent_evolve/integrations/pydantic_ai/provider_attempt_join.py +1523 -0
- agent_evolve/integrations/pydantic_ai/provider_free_calibrated_runner.py +607 -0
- agent_evolve/integrations/pydantic_ai/queued_runner.py +2634 -0
- agent_evolve/integrations/pydantic_ai/reconciled_residual_reachability.py +1417 -0
- agent_evolve/integrations/pydantic_ai/residual_forecast_geometry.py +445 -0
- agent_evolve/integrations/pydantic_ai/residual_reachability.py +674 -0
- agent_evolve/integrations/pydantic_ai/residual_semantic_cells.py +239 -0
- agent_evolve/integrations/pydantic_ai/sealed_output_replay.py +1068 -0
- agent_evolve/integrations/pydantic_ai/semantic_coverage_residual_portfolio.py +770 -0
- agent_evolve/integrations/pydantic_ai/semantic_decision_replay.py +383 -0
- agent_evolve/integrations/pydantic_ai/support_adaptive_residual_portfolio.py +135 -0
- agent_evolve/integrations/pydantic_ai/trusted_residual_prompt_context.py +143 -0
- agent_evolve/integrations/pydantic_ai/validated_openrouter_model.py +107 -0
- agent_evolve/integrations/pymoo_adapter.py +242 -0
- agent_evolve/policies/__init__.py +17 -0
- agent_evolve/policies/check.py +469 -0
- agent_evolve/policies/emit_scaffold.py +451 -0
- agent_evolve/policies/feedback/__init__.py +37 -0
- agent_evolve/policies/feedback/held_out_asn.py +1325 -0
- agent_evolve/policies/genetic.py +607 -0
- agent_evolve/policies/llm_backoff.py +183 -0
- agent_evolve/policies/llm_chooser.py +226 -0
- agent_evolve/policies/llm_generator.py +1760 -0
- agent_evolve/policies/llm_init.py +267 -0
- agent_evolve/policies/llm_operator.py +109 -0
- agent_evolve/policies/llm_prior.py +194 -0
- agent_evolve/policies/llm_surrogate.py +334 -0
- agent_evolve/policies/measurement_evidence.py +704 -0
- agent_evolve/policies/memory/__init__.py +223 -0
- agent_evolve/policies/memory/balanced_subset_blocks.py +707 -0
- agent_evolve/policies/memory/compatibility_matching.py +593 -0
- agent_evolve/policies/memory/global_falsification.py +1841 -0
- agent_evolve/policies/memory/prompt_shape.py +503 -0
- agent_evolve/policies/memory/randomized_subset.py +714 -0
- agent_evolve/policies/memory/staged_causal.py +1270 -0
- agent_evolve/policies/memory/treatment_compliance.py +759 -0
- agent_evolve/policies/objective_resolution/__init__.py +17 -0
- agent_evolve/policies/objective_resolution/fixed_grid.py +364 -0
- agent_evolve/policies/operator_portfolio.py +407 -0
- agent_evolve/policies/reguidance.py +1133 -0
- agent_evolve/policies/reward/__init__.py +83 -0
- agent_evolve/policies/reward/affine_candidate_consequence.py +156 -0
- agent_evolve/policies/reward/affine_candidate_consequence_3d.py +159 -0
- agent_evolve/policies/reward/affine_hypervolume.py +490 -0
- agent_evolve/policies/reward/affine_hypervolume_3d.py +567 -0
- agent_evolve/policies/reward/contextual_marginal_utility.py +318 -0
- agent_evolve/policies/reward/frozen_archive.py +360 -0
- agent_evolve/policies/reward/frozen_wave_archive.py +368 -0
- agent_evolve/policies/search_state.py +208 -0
- agent_evolve/policies/selection/__init__.py +345 -0
- agent_evolve/policies/selection/acquisition_certified_slate.py +684 -0
- agent_evolve/policies/selection/affine_frontier_context.py +330 -0
- agent_evolve/policies/selection/affine_frontier_target.py +473 -0
- agent_evolve/policies/selection/archive_elite.py +1346 -0
- agent_evolve/policies/selection/calibrated_portfolio_binding.py +640 -0
- agent_evolve/policies/selection/calibrated_slate.py +1394 -0
- agent_evolve/policies/selection/calibrated_slate_codec.py +579 -0
- agent_evolve/policies/selection/common_candidate_pool.py +685 -0
- agent_evolve/policies/selection/diagnostic_sampling.py +319 -0
- agent_evolve/policies/selection/disjoint_pairs.py +479 -0
- agent_evolve/policies/selection/elite_explorer.py +719 -0
- agent_evolve/policies/selection/finite_action.py +187 -0
- agent_evolve/policies/selection/finite_option_prompt_projection.py +377 -0
- agent_evolve/policies/selection/finite_palette_evidence.py +247 -0
- agent_evolve/policies/selection/forecast_calibration.py +922 -0
- agent_evolve/policies/selection/frontier_probe_slate.py +814 -0
- agent_evolve/policies/selection/frozen_archive_pairs.py +762 -0
- agent_evolve/policies/selection/full_support_slate.py +91 -0
- agent_evolve/policies/selection/meaningful_direction.py +240 -0
- agent_evolve/policies/selection/memory_dose_feasibility.py +259 -0
- agent_evolve/policies/selection/model_anchored_slate.py +826 -0
- agent_evolve/policies/selection/phenotype_recourse.py +979 -0
- agent_evolve/policies/selection/proposal_support.py +368 -0
- agent_evolve/policies/selection/random_portfolio.py +254 -0
- agent_evolve/policies/selection/regret_bounded_slate.py +1084 -0
- agent_evolve/policies/selection/residual_frontier.py +463 -0
- agent_evolve/policies/selection/residual_frontier_target.py +605 -0
- agent_evolve/policies/selection/structural_posterior_slate.py +1571 -0
- agent_evolve/policies/selection/target_conditioned_allocator.py +648 -0
- agent_evolve/policies/selection/target_conditioned_features.py +812 -0
- agent_evolve/policies/selection/target_conditioned_prequential.py +1527 -0
- agent_evolve/policies/selection/task_keyed_palette.py +906 -0
- agent_evolve/policies/semantics.py +147 -0
- agent_evolve/policies/structure.py +362 -0
- agent_evolve/policies/structured_output_budget.py +62 -0
- agent_evolve/policies/surrogate.py +696 -0
- agent_evolve/policies/variation/__init__.py +1 -0
- agent_evolve/policies/variation/compositional_finite_catalog.py +426 -0
- agent_evolve/policies/variation/crossover_inheritance.py +575 -0
- agent_evolve/policies/variation/disjoint_recombination.py +611 -0
- agent_evolve/policies/variation/exact_composition_capacity.py +214 -0
- agent_evolve/policies/variation/exact_parent_crossover.py +950 -0
- agent_evolve/policies/variation/multiscale_restart_catalog.py +372 -0
- agent_evolve/policies/variation/source_union_finite_catalog.py +403 -0
- agent_evolve/policies/variation/typed_patch.py +1981 -0
- agent_evolve/policies/weighted_prior.py +394 -0
- agent_evolve/ports/__init__.py +383 -0
- agent_evolve/ports/action_allocation.py +733 -0
- agent_evolve/ports/action_allocation_frame.py +1153 -0
- agent_evolve/ports/action_allocation_frame_commit.py +294 -0
- agent_evolve/ports/action_allocation_frame_commit_v3.py +432 -0
- agent_evolve/ports/action_allocation_frame_v3.py +995 -0
- agent_evolve/ports/action_forecast.py +1568 -0
- agent_evolve/ports/action_metric_projection.py +165 -0
- agent_evolve/ports/agentic_generator.py +1561 -0
- agent_evolve/ports/archive_context.py +136 -0
- agent_evolve/ports/artifact_sanitizer.py +44 -0
- agent_evolve/ports/artifact_store.py +225 -0
- agent_evolve/ports/clock.py +13 -0
- agent_evolve/ports/contextual_search_allocation.py +827 -0
- agent_evolve/ports/decision_metric_projection.py +258 -0
- agent_evolve/ports/event_store.py +55 -0
- agent_evolve/ports/executable_hypothesis.py +557 -0
- agent_evolve/ports/finite_acquisition.py +377 -0
- agent_evolve/ports/finite_acquisition_batch.py +296 -0
- agent_evolve/ports/finite_acquisition_batch_json.py +164 -0
- agent_evolve/ports/finite_acquisition_json.py +247 -0
- agent_evolve/ports/finite_acquisition_space.py +168 -0
- agent_evolve/ports/finite_action_selection.py +348 -0
- agent_evolve/ports/finite_action_set.py +256 -0
- agent_evolve/ports/frontier_target.py +396 -0
- agent_evolve/ports/generation_failure.py +43 -0
- agent_evolve/ports/hard_feasibility.py +233 -0
- agent_evolve/ports/id_factory.py +34 -0
- agent_evolve/ports/llm_task_queue.py +93 -0
- agent_evolve/ports/objective_resolution.py +419 -0
- agent_evolve/ports/paired_allocation_comparison.py +401 -0
- agent_evolve/ports/paired_block_schedule.py +475 -0
- agent_evolve/ports/parent_measurement.py +336 -0
- agent_evolve/ports/portfolio_memory_dose.py +643 -0
- agent_evolve/ports/portfolio_selection.py +3169 -0
- agent_evolve/ports/postcommit_rank_authority.py +467 -0
- agent_evolve/ports/presented_action_evidence.py +794 -0
- agent_evolve/ports/resource_lease.py +162 -0
- agent_evolve/ports/structured_generator.py +734 -0
- agent_evolve/ports/structured_output_budget.py +120 -0
- agent_evolve/ports/subprocess_boundary.py +138 -0
- agent_evolve/ports/treatment_assignment.py +466 -0
- agent_evolve/ports/variation_catalog.py +76 -0
- agent_evolve/ports/variation_source.py +226 -0
- agent_evolve/proposal_mode.py +157 -0
- agent_evolve/proposers/__init__.py +10 -0
- agent_evolve/proposers/random_proposer.py +188 -0
- agent_evolve/provider_accounting.py +163 -0
- agent_evolve/py.typed +0 -0
- agent_evolve/reference_method.py +1570 -0
- agent_evolve/session/__init__.py +11 -0
- agent_evolve/session/authorship.py +864 -0
- agent_evolve/session/evaluate.py +236 -0
- agent_evolve/session/fidelity.py +237 -0
- agent_evolve/session/genetic_loop.py +742 -0
- agent_evolve/session/loop.py +803 -0
- agent_evolve/session/screening.py +671 -0
- agent_evolve/settings.py +376 -0
- agent_evolve/workload_kit.py +368 -0
- agent_evolve/workload_prompt.py +398 -0
- agentevolve_optimizer-0.5.0.dist-info/METADATA +599 -0
- agentevolve_optimizer-0.5.0.dist-info/RECORD +414 -0
- agentevolve_optimizer-0.5.0.dist-info/WHEEL +5 -0
- agentevolve_optimizer-0.5.0.dist-info/entry_points.txt +2 -0
- agentevolve_optimizer-0.5.0.dist-info/licenses/LICENSE +21 -0
- 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
|
+
]
|