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,744 @@
|
|
|
1
|
+
"""Deterministic bounded-cost allocation over resolved action forecasts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
import math
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from agent_evolve.ports.action_allocation import (
|
|
11
|
+
ActionAllocationRequest,
|
|
12
|
+
ActionAllocationResult,
|
|
13
|
+
ActionPortfolioDecision,
|
|
14
|
+
AllocatedActionMember,
|
|
15
|
+
ForecastPortfolioUtilityInput,
|
|
16
|
+
ForecastQuantile,
|
|
17
|
+
PortfolioAllocationScore,
|
|
18
|
+
validate_action_portfolio_decision,
|
|
19
|
+
)
|
|
20
|
+
from agent_evolve.ports.action_forecast import ResolvedActionForecast
|
|
21
|
+
from agent_evolve.ports.portfolio_selection import (
|
|
22
|
+
pairwise_disjoint_parent_patch_pairs,
|
|
23
|
+
single_path_parent_patch_option_ids,
|
|
24
|
+
validate_pairwise_disjoint_parent_patch_selection,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
GREEDY_RISK_DIVERSITY_ALLOCATOR_ID = "greedy_risk_diversity"
|
|
28
|
+
GREEDY_RISK_DIVERSITY_ALLOCATOR_VERSION = 2
|
|
29
|
+
GREEDY_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256 = hashlib.sha256(
|
|
30
|
+
b"agent-evolve:greedy-risk-diversity:v2:"
|
|
31
|
+
b"at-each-step-score-every-eligible-extension-at-p10-p50-p90;"
|
|
32
|
+
b"downside=min(p10,p90);risk=max(0,p50-downside);"
|
|
33
|
+
b"attainable-diversity=min(portfolio-size,eligible-distinct-families);"
|
|
34
|
+
b"diversity=selected-distinct-families/attainable-diversity;"
|
|
35
|
+
b"maximize-marginal-total-with-smallest-option-identity-tie-break"
|
|
36
|
+
).hexdigest()
|
|
37
|
+
_CONFIGURATION_DOMAIN = b"agent-evolve:greedy-risk-diversity-config:v1\x00"
|
|
38
|
+
FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_ID = "feasible_beam_risk_diversity"
|
|
39
|
+
FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_VERSION = 3
|
|
40
|
+
FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256 = hashlib.sha256(
|
|
41
|
+
b"agent-evolve:feasible-beam-risk-diversity:v3:"
|
|
42
|
+
b"canonical-combination-beam;every-retained-prefix-has-a-hard-feasible-"
|
|
43
|
+
b"completion;pairwise-parent-patch-disjointness-and-minimum-distinct-"
|
|
44
|
+
b"families-and-exact-generic-arm-counts-and-minimum-single-path-actions-"
|
|
45
|
+
b"and-minimum-disjoint-parent-patch-pairs-are-trusted-code-constraints;"
|
|
46
|
+
b"score=p50-minus-quantile-downside-"
|
|
47
|
+
b"risk-plus-family-diversity;canonical-content-identity-tie-break"
|
|
48
|
+
).hexdigest()
|
|
49
|
+
_FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_V2_DEFINITION_SHA256 = hashlib.sha256(
|
|
50
|
+
b"agent-evolve:feasible-beam-risk-diversity:v2:"
|
|
51
|
+
b"canonical-combination-beam;every-retained-prefix-has-a-hard-feasible-"
|
|
52
|
+
b"completion;pairwise-parent-patch-disjointness-and-minimum-distinct-"
|
|
53
|
+
b"families-and-exact-generic-arm-counts-are-trusted-code-constraints;"
|
|
54
|
+
b"score=p50-minus-quantile-downside-"
|
|
55
|
+
b"risk-plus-family-diversity;canonical-content-identity-tie-break"
|
|
56
|
+
).hexdigest()
|
|
57
|
+
_FEASIBLE_BEAM_CONFIGURATION_DOMAIN = (
|
|
58
|
+
b"agent-evolve:feasible-beam-risk-diversity-config:v1\x00"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _configuration_sha256(risk_aversion: float, diversity_weight: float) -> str:
|
|
63
|
+
payload = json.dumps(
|
|
64
|
+
{
|
|
65
|
+
"risk_aversion_hex": risk_aversion.hex(),
|
|
66
|
+
"diversity_weight_hex": diversity_weight.hex(),
|
|
67
|
+
},
|
|
68
|
+
allow_nan=False,
|
|
69
|
+
ensure_ascii=True,
|
|
70
|
+
separators=(",", ":"),
|
|
71
|
+
sort_keys=True,
|
|
72
|
+
).encode("ascii")
|
|
73
|
+
return hashlib.sha256(_CONFIGURATION_DOMAIN + payload).hexdigest()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass(frozen=True, slots=True)
|
|
77
|
+
class GreedyRiskAdjustedDiversityAllocator:
|
|
78
|
+
"""Greedy marginal set allocator with O(k^2 n) elementary work.
|
|
79
|
+
|
|
80
|
+
The benchmark-owned, identified utility scores the complete forecast set,
|
|
81
|
+
so it can encode hypervolume, feasibility-first orderings, or any other
|
|
82
|
+
domain semantics. This generic policy adds only a quantile downside term
|
|
83
|
+
and a fixed family-diversity reward. It never enumerates k-combinations.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
risk_aversion: float = 0.5
|
|
87
|
+
diversity_weight: float = 0.0
|
|
88
|
+
|
|
89
|
+
def __post_init__(self) -> None:
|
|
90
|
+
for name in ("risk_aversion", "diversity_weight"):
|
|
91
|
+
value = getattr(self, name)
|
|
92
|
+
if type(value) is not float or not math.isfinite(value):
|
|
93
|
+
raise TypeError(f"{name} must be a finite canonical float")
|
|
94
|
+
if value < 0.0:
|
|
95
|
+
raise ValueError(f"{name} must be non-negative")
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def configuration_sha256(self) -> str:
|
|
99
|
+
self.__post_init__()
|
|
100
|
+
return _configuration_sha256(self.risk_aversion, self.diversity_weight)
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _utility(
|
|
104
|
+
request: ActionAllocationRequest,
|
|
105
|
+
members: tuple[ResolvedActionForecast, ...],
|
|
106
|
+
quantile: ForecastQuantile,
|
|
107
|
+
) -> float:
|
|
108
|
+
canonical_members = tuple(
|
|
109
|
+
sorted(
|
|
110
|
+
members,
|
|
111
|
+
key=lambda value: (value.option_identity_sha256, value.option_id),
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
value = request.utility.utility(
|
|
115
|
+
ForecastPortfolioUtilityInput(
|
|
116
|
+
optimization_semantics=(
|
|
117
|
+
request.forecast_request.optimization_semantics
|
|
118
|
+
),
|
|
119
|
+
parent_metric_values=(request.forecast_request.parent_metric_values),
|
|
120
|
+
metric_scales=request.forecast_request.metric_scales,
|
|
121
|
+
members=canonical_members,
|
|
122
|
+
quantile=quantile,
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
if type(value) is not float or not math.isfinite(value):
|
|
126
|
+
raise TypeError("bound portfolio utility must return a finite float")
|
|
127
|
+
return value
|
|
128
|
+
|
|
129
|
+
def _score(
|
|
130
|
+
self,
|
|
131
|
+
request: ActionAllocationRequest,
|
|
132
|
+
members: tuple[ResolvedActionForecast, ...],
|
|
133
|
+
*,
|
|
134
|
+
attainable_diversity: int,
|
|
135
|
+
) -> PortfolioAllocationScore:
|
|
136
|
+
if type(attainable_diversity) is not int or attainable_diversity <= 0:
|
|
137
|
+
raise ValueError("attainable_diversity must be a positive exact integer")
|
|
138
|
+
p10 = self._utility(request, members, ForecastQuantile.P10)
|
|
139
|
+
p50 = self._utility(request, members, ForecastQuantile.P50)
|
|
140
|
+
p90 = self._utility(request, members, ForecastQuantile.P90)
|
|
141
|
+
downside = min(p10, p90)
|
|
142
|
+
risk_penalty = self.risk_aversion * max(0.0, p50 - downside)
|
|
143
|
+
diversity_reward = self.diversity_weight * (
|
|
144
|
+
len({member.family for member in members}) / attainable_diversity
|
|
145
|
+
)
|
|
146
|
+
return PortfolioAllocationScore(
|
|
147
|
+
p10_utility=p10,
|
|
148
|
+
p50_utility=p50,
|
|
149
|
+
p90_utility=p90,
|
|
150
|
+
downside_utility=downside,
|
|
151
|
+
risk_penalty=risk_penalty,
|
|
152
|
+
diversity_reward=diversity_reward,
|
|
153
|
+
total_utility=p50 - risk_penalty + diversity_reward,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def allocate(self, request: ActionAllocationRequest) -> ActionAllocationResult:
|
|
157
|
+
if type(request) is not ActionAllocationRequest:
|
|
158
|
+
raise TypeError("request must be an exact ActionAllocationRequest")
|
|
159
|
+
request.__post_init__()
|
|
160
|
+
self.__post_init__()
|
|
161
|
+
if request.exact_arm_count_constraints:
|
|
162
|
+
raise ValueError(
|
|
163
|
+
"GreedyRiskAdjustedDiversityAllocator does not implement exact "
|
|
164
|
+
"arm-count constraints; use FeasibleBeamActionAllocator"
|
|
165
|
+
)
|
|
166
|
+
if (
|
|
167
|
+
request.minimum_single_path_interventions
|
|
168
|
+
or request.minimum_disjoint_parent_patch_pairs
|
|
169
|
+
):
|
|
170
|
+
raise ValueError(
|
|
171
|
+
"GreedyRiskAdjustedDiversityAllocator does not implement minimum "
|
|
172
|
+
"structural floors; use FeasibleBeamActionAllocator"
|
|
173
|
+
)
|
|
174
|
+
by_id = {value.option_id: value for value in request.forecasts.forecasts}
|
|
175
|
+
attainable_diversity = min(
|
|
176
|
+
request.portfolio_size,
|
|
177
|
+
len({by_id[option_id].family for option_id in request.eligible_option_ids}),
|
|
178
|
+
)
|
|
179
|
+
remaining = sorted(
|
|
180
|
+
(by_id[option_id] for option_id in request.eligible_option_ids),
|
|
181
|
+
key=lambda value: (value.option_identity_sha256, value.option_id),
|
|
182
|
+
)
|
|
183
|
+
required = tuple(
|
|
184
|
+
value
|
|
185
|
+
for value in remaining
|
|
186
|
+
if value.option_id in set(request.required_option_ids)
|
|
187
|
+
)
|
|
188
|
+
selected: list[ResolvedActionForecast] = []
|
|
189
|
+
members: list[AllocatedActionMember] = []
|
|
190
|
+
previous_total = 0.0
|
|
191
|
+
candidate_evaluations = 0
|
|
192
|
+
for rank in range(1, request.portfolio_size + 1):
|
|
193
|
+
if rank <= len(required):
|
|
194
|
+
best_forecast = required[rank - 1]
|
|
195
|
+
best_score = self._score(
|
|
196
|
+
request,
|
|
197
|
+
(*selected, best_forecast),
|
|
198
|
+
attainable_diversity=attainable_diversity,
|
|
199
|
+
)
|
|
200
|
+
best_marginal = best_score.total_utility - previous_total
|
|
201
|
+
candidate_evaluations += 1
|
|
202
|
+
else:
|
|
203
|
+
best_forecast = None
|
|
204
|
+
best_score = None
|
|
205
|
+
best_marginal = None
|
|
206
|
+
for candidate in remaining:
|
|
207
|
+
portfolio = (*selected, candidate)
|
|
208
|
+
score = self._score(
|
|
209
|
+
request,
|
|
210
|
+
portfolio,
|
|
211
|
+
attainable_diversity=attainable_diversity,
|
|
212
|
+
)
|
|
213
|
+
marginal = score.total_utility - previous_total
|
|
214
|
+
candidate_evaluations += 1
|
|
215
|
+
# ``remaining`` is canonical; strict comparison retains the
|
|
216
|
+
# smallest option identity on an exact numerical tie.
|
|
217
|
+
if best_marginal is None or marginal > best_marginal:
|
|
218
|
+
best_forecast = candidate
|
|
219
|
+
best_score = score
|
|
220
|
+
best_marginal = marginal
|
|
221
|
+
assert best_forecast is not None
|
|
222
|
+
assert best_score is not None
|
|
223
|
+
assert best_marginal is not None
|
|
224
|
+
selected.append(best_forecast)
|
|
225
|
+
remaining.remove(best_forecast)
|
|
226
|
+
members.append(
|
|
227
|
+
AllocatedActionMember(
|
|
228
|
+
rank=rank,
|
|
229
|
+
option_id=best_forecast.option_id,
|
|
230
|
+
option_identity_sha256=best_forecast.option_identity_sha256,
|
|
231
|
+
child_configuration_sha256=(
|
|
232
|
+
best_forecast.child_configuration_sha256
|
|
233
|
+
),
|
|
234
|
+
family=best_forecast.family,
|
|
235
|
+
greedy_step_score=best_score,
|
|
236
|
+
marginal_total_utility=best_marginal,
|
|
237
|
+
)
|
|
238
|
+
)
|
|
239
|
+
previous_total = best_score.total_utility
|
|
240
|
+
decision = ActionPortfolioDecision(
|
|
241
|
+
allocation_request_sha256=request.request_sha256,
|
|
242
|
+
forecast_receipt_sha256=request.forecasts.receipt_sha256,
|
|
243
|
+
finite_contract_identity_sha256=(
|
|
244
|
+
request.forecast_request.finite_variation_contract.identity_sha256
|
|
245
|
+
),
|
|
246
|
+
eligible_options_sha256=request.eligible_options_sha256,
|
|
247
|
+
members=tuple(members),
|
|
248
|
+
final_score=members[-1].greedy_step_score,
|
|
249
|
+
candidate_evaluations=candidate_evaluations,
|
|
250
|
+
utility_policy_id=request.utility.policy_id,
|
|
251
|
+
utility_policy_version=request.utility.policy_version,
|
|
252
|
+
utility_definition_sha256=request.utility.definition_sha256,
|
|
253
|
+
allocator_policy_id=GREEDY_RISK_DIVERSITY_ALLOCATOR_ID,
|
|
254
|
+
allocator_policy_version=GREEDY_RISK_DIVERSITY_ALLOCATOR_VERSION,
|
|
255
|
+
allocator_definition_sha256=(
|
|
256
|
+
GREEDY_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256
|
|
257
|
+
),
|
|
258
|
+
allocator_configuration_sha256=self.configuration_sha256,
|
|
259
|
+
)
|
|
260
|
+
validate_action_portfolio_decision(request, decision)
|
|
261
|
+
return ActionAllocationResult(decision=decision)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@dataclass(frozen=True, slots=True)
|
|
265
|
+
class FeasibleBeamRiskAdjustedDiversityAllocator:
|
|
266
|
+
"""Bounded beam allocation whose every published set is hard feasible.
|
|
267
|
+
|
|
268
|
+
The LLM forecasts consequences only. Trusted application code owns set
|
|
269
|
+
construction and cannot publish a portfolio that violates the generic
|
|
270
|
+
structural constraints sealed into :class:`ActionAllocationRequest`.
|
|
271
|
+
"""
|
|
272
|
+
|
|
273
|
+
risk_aversion: float = 0.5
|
|
274
|
+
diversity_weight: float = 0.05
|
|
275
|
+
beam_width: int = 256
|
|
276
|
+
|
|
277
|
+
def __post_init__(self) -> None:
|
|
278
|
+
for name in ("risk_aversion", "diversity_weight"):
|
|
279
|
+
value = getattr(self, name)
|
|
280
|
+
if type(value) is not float or not math.isfinite(value):
|
|
281
|
+
raise TypeError(f"{name} must be a finite canonical float")
|
|
282
|
+
if value < 0.0:
|
|
283
|
+
raise ValueError(f"{name} must be non-negative")
|
|
284
|
+
if type(self.beam_width) is not int or self.beam_width <= 0:
|
|
285
|
+
raise ValueError("beam_width must be a positive exact integer")
|
|
286
|
+
|
|
287
|
+
@property
|
|
288
|
+
def configuration_sha256(self) -> str:
|
|
289
|
+
self.__post_init__()
|
|
290
|
+
payload = json.dumps(
|
|
291
|
+
{
|
|
292
|
+
"risk_aversion_hex": self.risk_aversion.hex(),
|
|
293
|
+
"diversity_weight_hex": self.diversity_weight.hex(),
|
|
294
|
+
"beam_width": self.beam_width,
|
|
295
|
+
},
|
|
296
|
+
allow_nan=False,
|
|
297
|
+
ensure_ascii=True,
|
|
298
|
+
separators=(",", ":"),
|
|
299
|
+
sort_keys=True,
|
|
300
|
+
).encode("ascii")
|
|
301
|
+
return hashlib.sha256(_FEASIBLE_BEAM_CONFIGURATION_DOMAIN + payload).hexdigest()
|
|
302
|
+
|
|
303
|
+
@staticmethod
|
|
304
|
+
def _allowed_pairs(
|
|
305
|
+
request: ActionAllocationRequest,
|
|
306
|
+
) -> frozenset[frozenset[str]] | None:
|
|
307
|
+
if not request.require_pairwise_disjoint_parent_patches:
|
|
308
|
+
return None
|
|
309
|
+
return frozenset(
|
|
310
|
+
frozenset(value)
|
|
311
|
+
for value in pairwise_disjoint_parent_patch_pairs(
|
|
312
|
+
request.forecast_request.finite_variation_contract,
|
|
313
|
+
request.eligible_option_ids,
|
|
314
|
+
)
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
@staticmethod
|
|
318
|
+
def _disjoint_pairs(
|
|
319
|
+
request: ActionAllocationRequest,
|
|
320
|
+
) -> frozenset[frozenset[str]]:
|
|
321
|
+
if (
|
|
322
|
+
not request.require_pairwise_disjoint_parent_patches
|
|
323
|
+
and request.minimum_disjoint_parent_patch_pairs == 0
|
|
324
|
+
):
|
|
325
|
+
return frozenset()
|
|
326
|
+
return frozenset(
|
|
327
|
+
frozenset(value)
|
|
328
|
+
for value in pairwise_disjoint_parent_patch_pairs(
|
|
329
|
+
request.forecast_request.finite_variation_contract,
|
|
330
|
+
request.eligible_option_ids,
|
|
331
|
+
)
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
@staticmethod
|
|
335
|
+
def _pairs_allowed(
|
|
336
|
+
indices: tuple[int, ...],
|
|
337
|
+
options: tuple[ResolvedActionForecast, ...],
|
|
338
|
+
allowed_pairs: frozenset[frozenset[str]] | None,
|
|
339
|
+
) -> bool:
|
|
340
|
+
return allowed_pairs is None or all(
|
|
341
|
+
frozenset((options[left].option_id, options[right].option_id))
|
|
342
|
+
in allowed_pairs
|
|
343
|
+
for position, left in enumerate(indices)
|
|
344
|
+
for right in indices[position + 1 :]
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
@staticmethod
|
|
348
|
+
def _arm_constraints_have_completion(
|
|
349
|
+
*,
|
|
350
|
+
selected: tuple[int, ...],
|
|
351
|
+
remaining: tuple[int, ...],
|
|
352
|
+
needed: int,
|
|
353
|
+
arm_constraints: tuple[tuple[dict[str, int], tuple[str, ...]], ...],
|
|
354
|
+
) -> bool:
|
|
355
|
+
"""Cheap exact marginal-count bound for every generic arm axis."""
|
|
356
|
+
|
|
357
|
+
for target, arm_by_index in arm_constraints:
|
|
358
|
+
selected_counts = {arm_id: 0 for arm_id in target}
|
|
359
|
+
for index in selected:
|
|
360
|
+
selected_counts[arm_by_index[index]] += 1
|
|
361
|
+
deficits: dict[str, int] = {}
|
|
362
|
+
for arm_id, count in target.items():
|
|
363
|
+
deficit = count - selected_counts[arm_id]
|
|
364
|
+
if deficit < 0:
|
|
365
|
+
return False
|
|
366
|
+
deficits[arm_id] = deficit
|
|
367
|
+
if sum(deficits.values()) != needed:
|
|
368
|
+
return False
|
|
369
|
+
available_counts = {arm_id: 0 for arm_id in target}
|
|
370
|
+
for index in remaining:
|
|
371
|
+
available_counts[arm_by_index[index]] += 1
|
|
372
|
+
if any(
|
|
373
|
+
available_counts[arm_id] < deficit
|
|
374
|
+
for arm_id, deficit in deficits.items()
|
|
375
|
+
):
|
|
376
|
+
return False
|
|
377
|
+
return True
|
|
378
|
+
|
|
379
|
+
@staticmethod
|
|
380
|
+
def _structural_floors_have_completion(
|
|
381
|
+
*,
|
|
382
|
+
selected: tuple[int, ...],
|
|
383
|
+
remaining: tuple[int, ...],
|
|
384
|
+
needed: int,
|
|
385
|
+
options: tuple[ResolvedActionForecast, ...],
|
|
386
|
+
single_path_indices: frozenset[int],
|
|
387
|
+
minimum_single_path_interventions: int,
|
|
388
|
+
disjoint_pairs: frozenset[frozenset[str]],
|
|
389
|
+
minimum_disjoint_parent_patch_pairs: int,
|
|
390
|
+
) -> bool:
|
|
391
|
+
"""Return a safe upper-bound test, exact when no slots remain."""
|
|
392
|
+
|
|
393
|
+
selected_single = sum(value in single_path_indices for value in selected)
|
|
394
|
+
if selected_single + min(
|
|
395
|
+
needed,
|
|
396
|
+
sum(value in single_path_indices for value in remaining),
|
|
397
|
+
) < minimum_single_path_interventions:
|
|
398
|
+
return False
|
|
399
|
+
|
|
400
|
+
def pair(left: int, right: int) -> frozenset[str]:
|
|
401
|
+
return frozenset(
|
|
402
|
+
(options[left].option_id, options[right].option_id)
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
observed_pairs = sum(
|
|
406
|
+
pair(left, right) in disjoint_pairs
|
|
407
|
+
for position, left in enumerate(selected)
|
|
408
|
+
for right in selected[position + 1 :]
|
|
409
|
+
)
|
|
410
|
+
if needed == 0:
|
|
411
|
+
return observed_pairs >= minimum_disjoint_parent_patch_pairs
|
|
412
|
+
optimistic_pairs = (
|
|
413
|
+
observed_pairs
|
|
414
|
+
+ len(selected) * needed
|
|
415
|
+
+ needed * (needed - 1) // 2
|
|
416
|
+
)
|
|
417
|
+
return optimistic_pairs >= minimum_disjoint_parent_patch_pairs
|
|
418
|
+
|
|
419
|
+
@classmethod
|
|
420
|
+
def _has_completion(
|
|
421
|
+
cls,
|
|
422
|
+
*,
|
|
423
|
+
partial: tuple[int, ...],
|
|
424
|
+
options: tuple[ResolvedActionForecast, ...],
|
|
425
|
+
portfolio_size: int,
|
|
426
|
+
min_distinct_families: int | None,
|
|
427
|
+
allowed_pairs: frozenset[frozenset[str]] | None,
|
|
428
|
+
disjoint_pairs: frozenset[frozenset[str]],
|
|
429
|
+
single_path_indices: frozenset[int],
|
|
430
|
+
minimum_single_path_interventions: int,
|
|
431
|
+
minimum_disjoint_parent_patch_pairs: int,
|
|
432
|
+
required_indices: frozenset[int],
|
|
433
|
+
arm_constraints: tuple[tuple[dict[str, int], tuple[str, ...]], ...],
|
|
434
|
+
) -> bool:
|
|
435
|
+
"""Exact bounded-depth feasibility oracle for one canonical prefix."""
|
|
436
|
+
|
|
437
|
+
slots = portfolio_size - len(partial)
|
|
438
|
+
if slots < 0 or not cls._pairs_allowed(partial, options, allowed_pairs):
|
|
439
|
+
return False
|
|
440
|
+
missing_required = required_indices.difference(partial)
|
|
441
|
+
if len(missing_required) > slots:
|
|
442
|
+
return False
|
|
443
|
+
families = {options[index].family for index in partial}
|
|
444
|
+
all_remaining = tuple(range(partial[-1] + 1, len(options))) if partial else (
|
|
445
|
+
tuple(range(len(options)))
|
|
446
|
+
)
|
|
447
|
+
if not cls._structural_floors_have_completion(
|
|
448
|
+
selected=partial,
|
|
449
|
+
remaining=all_remaining,
|
|
450
|
+
needed=slots,
|
|
451
|
+
options=options,
|
|
452
|
+
single_path_indices=single_path_indices,
|
|
453
|
+
minimum_single_path_interventions=minimum_single_path_interventions,
|
|
454
|
+
disjoint_pairs=disjoint_pairs,
|
|
455
|
+
minimum_disjoint_parent_patch_pairs=(
|
|
456
|
+
minimum_disjoint_parent_patch_pairs
|
|
457
|
+
),
|
|
458
|
+
):
|
|
459
|
+
return False
|
|
460
|
+
if slots == 0:
|
|
461
|
+
return (
|
|
462
|
+
not missing_required
|
|
463
|
+
and (
|
|
464
|
+
min_distinct_families is None
|
|
465
|
+
or len(families) >= min_distinct_families
|
|
466
|
+
)
|
|
467
|
+
and cls._arm_constraints_have_completion(
|
|
468
|
+
selected=partial,
|
|
469
|
+
remaining=(),
|
|
470
|
+
needed=0,
|
|
471
|
+
arm_constraints=arm_constraints,
|
|
472
|
+
)
|
|
473
|
+
)
|
|
474
|
+
start = partial[-1] + 1 if partial else 0
|
|
475
|
+
if any(index < start for index in missing_required):
|
|
476
|
+
return False
|
|
477
|
+
compatible = tuple(
|
|
478
|
+
index
|
|
479
|
+
for index in range(start, len(options))
|
|
480
|
+
if all(
|
|
481
|
+
allowed_pairs is None
|
|
482
|
+
or frozenset((options[index].option_id, options[chosen].option_id))
|
|
483
|
+
in allowed_pairs
|
|
484
|
+
for chosen in partial
|
|
485
|
+
)
|
|
486
|
+
)
|
|
487
|
+
if len(compatible) < slots:
|
|
488
|
+
return False
|
|
489
|
+
if not missing_required.issubset(compatible):
|
|
490
|
+
return False
|
|
491
|
+
if not cls._arm_constraints_have_completion(
|
|
492
|
+
selected=partial,
|
|
493
|
+
remaining=compatible,
|
|
494
|
+
needed=slots,
|
|
495
|
+
arm_constraints=arm_constraints,
|
|
496
|
+
):
|
|
497
|
+
return False
|
|
498
|
+
if (
|
|
499
|
+
min_distinct_families is not None
|
|
500
|
+
and len(families | {options[index].family for index in compatible})
|
|
501
|
+
< min_distinct_families
|
|
502
|
+
):
|
|
503
|
+
return False
|
|
504
|
+
|
|
505
|
+
def visit(
|
|
506
|
+
chosen: tuple[int, ...],
|
|
507
|
+
remaining: tuple[int, ...],
|
|
508
|
+
) -> bool:
|
|
509
|
+
needed = slots - len(chosen)
|
|
510
|
+
still_required = missing_required.difference(chosen)
|
|
511
|
+
if len(still_required) > needed or not still_required.issubset(remaining):
|
|
512
|
+
return False
|
|
513
|
+
if not cls._arm_constraints_have_completion(
|
|
514
|
+
selected=(*partial, *chosen),
|
|
515
|
+
remaining=remaining,
|
|
516
|
+
needed=needed,
|
|
517
|
+
arm_constraints=arm_constraints,
|
|
518
|
+
):
|
|
519
|
+
return False
|
|
520
|
+
if not cls._structural_floors_have_completion(
|
|
521
|
+
selected=(*partial, *chosen),
|
|
522
|
+
remaining=remaining,
|
|
523
|
+
needed=needed,
|
|
524
|
+
options=options,
|
|
525
|
+
single_path_indices=single_path_indices,
|
|
526
|
+
minimum_single_path_interventions=(
|
|
527
|
+
minimum_single_path_interventions
|
|
528
|
+
),
|
|
529
|
+
disjoint_pairs=disjoint_pairs,
|
|
530
|
+
minimum_disjoint_parent_patch_pairs=(
|
|
531
|
+
minimum_disjoint_parent_patch_pairs
|
|
532
|
+
),
|
|
533
|
+
):
|
|
534
|
+
return False
|
|
535
|
+
chosen_families = families | {options[index].family for index in chosen}
|
|
536
|
+
if needed == 0:
|
|
537
|
+
return not still_required and (
|
|
538
|
+
min_distinct_families is None
|
|
539
|
+
or len(chosen_families) >= min_distinct_families
|
|
540
|
+
)
|
|
541
|
+
if len(remaining) < needed:
|
|
542
|
+
return False
|
|
543
|
+
if (
|
|
544
|
+
min_distinct_families is not None
|
|
545
|
+
and len(
|
|
546
|
+
chosen_families | {options[index].family for index in remaining}
|
|
547
|
+
)
|
|
548
|
+
< min_distinct_families
|
|
549
|
+
):
|
|
550
|
+
return False
|
|
551
|
+
for position, candidate in enumerate(remaining):
|
|
552
|
+
if all(
|
|
553
|
+
allowed_pairs is None
|
|
554
|
+
or frozenset(
|
|
555
|
+
(options[candidate].option_id, options[prior].option_id)
|
|
556
|
+
)
|
|
557
|
+
in allowed_pairs
|
|
558
|
+
for prior in chosen
|
|
559
|
+
) and visit(
|
|
560
|
+
(*chosen, candidate),
|
|
561
|
+
remaining[position + 1 :],
|
|
562
|
+
):
|
|
563
|
+
return True
|
|
564
|
+
return False
|
|
565
|
+
|
|
566
|
+
return visit((), compatible)
|
|
567
|
+
|
|
568
|
+
def allocate(self, request: ActionAllocationRequest) -> ActionAllocationResult:
|
|
569
|
+
if type(request) is not ActionAllocationRequest:
|
|
570
|
+
raise TypeError("request must be an exact ActionAllocationRequest")
|
|
571
|
+
request.__post_init__()
|
|
572
|
+
self.__post_init__()
|
|
573
|
+
by_id = {value.option_id: value for value in request.forecasts.forecasts}
|
|
574
|
+
options = tuple(
|
|
575
|
+
sorted(
|
|
576
|
+
(by_id[value] for value in request.eligible_option_ids),
|
|
577
|
+
key=lambda item: (item.option_identity_sha256, item.option_id),
|
|
578
|
+
)
|
|
579
|
+
)
|
|
580
|
+
allowed_pairs = self._allowed_pairs(request)
|
|
581
|
+
disjoint_pairs = self._disjoint_pairs(request)
|
|
582
|
+
single_path_option_ids = set(
|
|
583
|
+
single_path_parent_patch_option_ids(
|
|
584
|
+
request.forecast_request.finite_variation_contract,
|
|
585
|
+
request.eligible_option_ids,
|
|
586
|
+
)
|
|
587
|
+
)
|
|
588
|
+
single_path_indices = frozenset(
|
|
589
|
+
index
|
|
590
|
+
for index, option in enumerate(options)
|
|
591
|
+
if option.option_id in single_path_option_ids
|
|
592
|
+
)
|
|
593
|
+
required_option_ids = set(request.required_option_ids)
|
|
594
|
+
required_indices = frozenset(
|
|
595
|
+
index
|
|
596
|
+
for index, option in enumerate(options)
|
|
597
|
+
if option.option_id in required_option_ids
|
|
598
|
+
)
|
|
599
|
+
arm_constraints = tuple(
|
|
600
|
+
(
|
|
601
|
+
dict(constraint.target_counts),
|
|
602
|
+
tuple(
|
|
603
|
+
dict(constraint.option_arm_ids)[option.option_id]
|
|
604
|
+
for option in options
|
|
605
|
+
),
|
|
606
|
+
)
|
|
607
|
+
for constraint in request.exact_arm_count_constraints
|
|
608
|
+
)
|
|
609
|
+
scorer = GreedyRiskAdjustedDiversityAllocator(
|
|
610
|
+
risk_aversion=self.risk_aversion,
|
|
611
|
+
diversity_weight=self.diversity_weight,
|
|
612
|
+
)
|
|
613
|
+
attainable_diversity = min(
|
|
614
|
+
request.portfolio_size,
|
|
615
|
+
len({value.family for value in options}),
|
|
616
|
+
)
|
|
617
|
+
beam: list[tuple[tuple[int, ...], PortfolioAllocationScore]] = []
|
|
618
|
+
candidate_evaluations = 0
|
|
619
|
+
for depth in range(1, request.portfolio_size + 1):
|
|
620
|
+
candidates: list[tuple[tuple[int, ...], PortfolioAllocationScore]] = []
|
|
621
|
+
prefixes = (((), None),) if depth == 1 else tuple(beam)
|
|
622
|
+
for prefix, _ in prefixes:
|
|
623
|
+
start = prefix[-1] + 1 if prefix else 0
|
|
624
|
+
for index in range(start, len(options)):
|
|
625
|
+
extension = (*prefix, index)
|
|
626
|
+
if not self._has_completion(
|
|
627
|
+
partial=extension,
|
|
628
|
+
options=options,
|
|
629
|
+
portfolio_size=request.portfolio_size,
|
|
630
|
+
min_distinct_families=request.min_distinct_families,
|
|
631
|
+
allowed_pairs=allowed_pairs,
|
|
632
|
+
disjoint_pairs=disjoint_pairs,
|
|
633
|
+
single_path_indices=single_path_indices,
|
|
634
|
+
minimum_single_path_interventions=(
|
|
635
|
+
request.minimum_single_path_interventions
|
|
636
|
+
),
|
|
637
|
+
minimum_disjoint_parent_patch_pairs=(
|
|
638
|
+
request.minimum_disjoint_parent_patch_pairs
|
|
639
|
+
),
|
|
640
|
+
required_indices=required_indices,
|
|
641
|
+
arm_constraints=arm_constraints,
|
|
642
|
+
):
|
|
643
|
+
continue
|
|
644
|
+
score = scorer._score(
|
|
645
|
+
request,
|
|
646
|
+
tuple(options[value] for value in extension),
|
|
647
|
+
attainable_diversity=attainable_diversity,
|
|
648
|
+
)
|
|
649
|
+
candidate_evaluations += 1
|
|
650
|
+
candidates.append((extension, score))
|
|
651
|
+
if not candidates:
|
|
652
|
+
raise RuntimeError(
|
|
653
|
+
"feasibility oracle admitted no target-allocation prefix"
|
|
654
|
+
)
|
|
655
|
+
candidates.sort(
|
|
656
|
+
key=lambda value: (
|
|
657
|
+
-value[1].total_utility,
|
|
658
|
+
tuple(options[index].option_identity_sha256 for index in value[0]),
|
|
659
|
+
)
|
|
660
|
+
)
|
|
661
|
+
beam = candidates[: self.beam_width]
|
|
662
|
+
|
|
663
|
+
selected_indices, final_score = beam[0]
|
|
664
|
+
selected = tuple(options[index] for index in selected_indices)
|
|
665
|
+
if (
|
|
666
|
+
request.min_distinct_families is not None
|
|
667
|
+
and len({value.family for value in selected})
|
|
668
|
+
< request.min_distinct_families
|
|
669
|
+
):
|
|
670
|
+
raise RuntimeError("beam allocator violated minimum family coverage")
|
|
671
|
+
if request.require_pairwise_disjoint_parent_patches:
|
|
672
|
+
validate_pairwise_disjoint_parent_patch_selection(
|
|
673
|
+
request.forecast_request.finite_variation_contract,
|
|
674
|
+
tuple(value.option_id for value in selected),
|
|
675
|
+
)
|
|
676
|
+
if not required_option_ids.issubset(value.option_id for value in selected):
|
|
677
|
+
raise RuntimeError("beam allocator omitted a required option")
|
|
678
|
+
prefix_scores = tuple(
|
|
679
|
+
scorer._score(
|
|
680
|
+
request,
|
|
681
|
+
selected[:index],
|
|
682
|
+
attainable_diversity=attainable_diversity,
|
|
683
|
+
)
|
|
684
|
+
for index in range(1, len(selected) + 1)
|
|
685
|
+
)
|
|
686
|
+
members = tuple(
|
|
687
|
+
AllocatedActionMember(
|
|
688
|
+
rank=index,
|
|
689
|
+
option_id=value.option_id,
|
|
690
|
+
option_identity_sha256=value.option_identity_sha256,
|
|
691
|
+
child_configuration_sha256=value.child_configuration_sha256,
|
|
692
|
+
family=value.family,
|
|
693
|
+
greedy_step_score=prefix_scores[index - 1],
|
|
694
|
+
marginal_total_utility=(
|
|
695
|
+
prefix_scores[index - 1].total_utility
|
|
696
|
+
- (0.0 if index == 1 else prefix_scores[index - 2].total_utility)
|
|
697
|
+
),
|
|
698
|
+
)
|
|
699
|
+
for index, value in enumerate(selected, start=1)
|
|
700
|
+
)
|
|
701
|
+
if final_score != prefix_scores[-1]:
|
|
702
|
+
raise RuntimeError("beam final score differs from its selected prefix")
|
|
703
|
+
decision = ActionPortfolioDecision(
|
|
704
|
+
allocation_request_sha256=request.request_sha256,
|
|
705
|
+
forecast_receipt_sha256=request.forecasts.receipt_sha256,
|
|
706
|
+
finite_contract_identity_sha256=(
|
|
707
|
+
request.forecast_request.finite_variation_contract.identity_sha256
|
|
708
|
+
),
|
|
709
|
+
eligible_options_sha256=request.eligible_options_sha256,
|
|
710
|
+
members=members,
|
|
711
|
+
final_score=final_score,
|
|
712
|
+
candidate_evaluations=candidate_evaluations,
|
|
713
|
+
utility_policy_id=request.utility.policy_id,
|
|
714
|
+
utility_policy_version=request.utility.policy_version,
|
|
715
|
+
utility_definition_sha256=request.utility.definition_sha256,
|
|
716
|
+
allocator_policy_id=FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_ID,
|
|
717
|
+
allocator_policy_version=(
|
|
718
|
+
FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_VERSION
|
|
719
|
+
if request.minimum_single_path_interventions
|
|
720
|
+
or request.minimum_disjoint_parent_patch_pairs
|
|
721
|
+
else 2
|
|
722
|
+
),
|
|
723
|
+
allocator_definition_sha256=(
|
|
724
|
+
FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256
|
|
725
|
+
if request.minimum_single_path_interventions
|
|
726
|
+
or request.minimum_disjoint_parent_patch_pairs
|
|
727
|
+
else _FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_V2_DEFINITION_SHA256
|
|
728
|
+
),
|
|
729
|
+
allocator_configuration_sha256=self.configuration_sha256,
|
|
730
|
+
)
|
|
731
|
+
validate_action_portfolio_decision(request, decision)
|
|
732
|
+
return ActionAllocationResult(decision=decision)
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
__all__ = [
|
|
736
|
+
"FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256",
|
|
737
|
+
"FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_ID",
|
|
738
|
+
"FEASIBLE_BEAM_RISK_DIVERSITY_ALLOCATOR_VERSION",
|
|
739
|
+
"GREEDY_RISK_DIVERSITY_ALLOCATOR_DEFINITION_SHA256",
|
|
740
|
+
"GREEDY_RISK_DIVERSITY_ALLOCATOR_ID",
|
|
741
|
+
"GREEDY_RISK_DIVERSITY_ALLOCATOR_VERSION",
|
|
742
|
+
"FeasibleBeamRiskAdjustedDiversityAllocator",
|
|
743
|
+
"GreedyRiskAdjustedDiversityAllocator",
|
|
744
|
+
]
|