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,236 @@
|
|
|
1
|
+
"""Black-box candidate evaluation against a Problem.
|
|
2
|
+
|
|
3
|
+
Runs the three per-candidate obligations in order: ``validate`` rejects cheaply
|
|
4
|
+
and explains itself, ``materialize`` builds the artifact, ``evaluate`` measures
|
|
5
|
+
it. Expected infeasibility surfaces as a failed :class:`CandidateResult`
|
|
6
|
+
carrying a ``failure_phase`` and message; the message is forwarded to the LLM
|
|
7
|
+
as feedback.
|
|
8
|
+
|
|
9
|
+
Evaluation is cached on the identity of the *materialized artifact*, not the
|
|
10
|
+
configuration. Distinct configurations that build the same artifact are
|
|
11
|
+
therefore measured once. Keying on the configuration -- which is what this did
|
|
12
|
+
before -- paid twice for the redundancy the union-over-sum analysis measured as
|
|
13
|
+
the dominant loss.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any, Dict, List, MutableMapping, Optional, Sequence, Tuple
|
|
19
|
+
|
|
20
|
+
from agent_evolve.contract import artifact_key, as_evaluator
|
|
21
|
+
from agent_evolve.core.formatting import CandidateResult
|
|
22
|
+
from agent_evolve.core.problem import (
|
|
23
|
+
ObjectiveSpec,
|
|
24
|
+
ValidationOutcome,
|
|
25
|
+
normalize_objective_values,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
INVALID_PENALTY: float = 1e18
|
|
29
|
+
|
|
30
|
+
_VALIDATION_FALSE_HINT = (
|
|
31
|
+
"validate() returned False without a reason. Raise ValueError('...') from "
|
|
32
|
+
"validate() describing what is wrong and how to fix it (unknown keys, wrong "
|
|
33
|
+
"types, out-of-range values, invalid combinations)."
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def format_optimizer_error(exc: BaseException) -> str:
|
|
38
|
+
"""Format an exception for regeneration prompts with a concrete fix hint."""
|
|
39
|
+
name = type(exc).__name__
|
|
40
|
+
msg = str(exc).strip()
|
|
41
|
+
if msg:
|
|
42
|
+
return f"{name}: {msg}"
|
|
43
|
+
return (
|
|
44
|
+
f"{name} was raised with no message. Raise ValueError('clear explanation of "
|
|
45
|
+
"what failed and valid alternatives') instead."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _penalty_objectives(objectives: Sequence[ObjectiveSpec]) -> Dict[str, float]:
|
|
50
|
+
return {s.name: (0.0 if s.goal == "max" else INVALID_PENALTY) for s in objectives}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _failure(
|
|
54
|
+
config: Dict[str, Any],
|
|
55
|
+
objectives: Sequence[ObjectiveSpec],
|
|
56
|
+
message: str,
|
|
57
|
+
phase: str,
|
|
58
|
+
*,
|
|
59
|
+
evaluation_attempted: bool = False,
|
|
60
|
+
) -> CandidateResult:
|
|
61
|
+
return CandidateResult(
|
|
62
|
+
configuration=config,
|
|
63
|
+
objectives=_penalty_objectives(objectives),
|
|
64
|
+
is_valid=False,
|
|
65
|
+
error_message=message,
|
|
66
|
+
failure_phase=phase,
|
|
67
|
+
evaluation_attempted=evaluation_attempted,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class EvaluationCache(dict):
|
|
72
|
+
"""Artifact identity -> objective vector, plus what it saved.
|
|
73
|
+
|
|
74
|
+
``hits`` is the number of evaluations not paid for. It is reported rather
|
|
75
|
+
than inferred, so a problem whose ``materialize`` collapses nothing can see
|
|
76
|
+
that immediately instead of assuming a saving it never got.
|
|
77
|
+
|
|
78
|
+
``misses`` is what the budget actually counts: distinct artifacts measured.
|
|
79
|
+
|
|
80
|
+
A REFUSAL is a measurement too. An artifact whose ``evaluate`` raised was
|
|
81
|
+
charged -- it ran the evaluator, it took the wall-clock -- so its outcome
|
|
82
|
+
is recorded exactly like a successful one, and a re-proposed refusal is
|
|
83
|
+
served from memory instead of being charged again. On a venue that
|
|
84
|
+
refuses over half of what is proposed (the EDA case: 53%), forgetting
|
|
85
|
+
refusals meant a config could be billed every time the sampler re-drew
|
|
86
|
+
it. ``refusal_hits`` counts those replays, apart from ``hits``, because
|
|
87
|
+
"we did not pay for a success again" and "we did not pay for a failure
|
|
88
|
+
again" are different savings and a campaign should see both.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, *args, **kwargs) -> None:
|
|
92
|
+
super().__init__(*args, **kwargs)
|
|
93
|
+
self.hits = 0
|
|
94
|
+
self.misses = 0
|
|
95
|
+
self.refusal_hits = 0
|
|
96
|
+
#: artifact key -> (message, failure phase) of the charged refusal.
|
|
97
|
+
self._refusals: Dict[str, Tuple[str, str]] = {}
|
|
98
|
+
|
|
99
|
+
def record_refusal(self, key: str, message: str, phase: str) -> None:
|
|
100
|
+
self._refusals[key] = (str(message), str(phase))
|
|
101
|
+
|
|
102
|
+
def refusal(self, key: str) -> Optional[Tuple[str, str]]:
|
|
103
|
+
return self._refusals.get(key)
|
|
104
|
+
|
|
105
|
+
#: Hard ceiling on ``misses``. Once reached, no further artifact is
|
|
106
|
+
#: measured; a budget that is only checked between generations is not a
|
|
107
|
+
#: budget, and a caller who said 40 must not be billed for 48.
|
|
108
|
+
budget: Optional[int] = None
|
|
109
|
+
|
|
110
|
+
def exhausted(self) -> bool:
|
|
111
|
+
return self.budget is not None and self.misses >= self.budget
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def evaluate_batch(
|
|
115
|
+
problem: Any,
|
|
116
|
+
candidates: List[Dict[str, Any]],
|
|
117
|
+
objectives: Sequence[ObjectiveSpec],
|
|
118
|
+
cache: Optional[MutableMapping[str, Dict[str, float]]] = None,
|
|
119
|
+
) -> Tuple[List[CandidateResult], List[CandidateResult], List[CandidateResult]]:
|
|
120
|
+
"""Evaluate *candidates* against *problem*.
|
|
121
|
+
|
|
122
|
+
Returns ``(valid, failed, ordered)`` where *ordered* has one
|
|
123
|
+
:class:`CandidateResult` per input candidate in input order. When *cache*
|
|
124
|
+
is supplied, artifacts already measured are not measured again.
|
|
125
|
+
"""
|
|
126
|
+
bound = as_evaluator(problem)
|
|
127
|
+
valid: List[CandidateResult] = []
|
|
128
|
+
failed: List[CandidateResult] = []
|
|
129
|
+
ordered: List[CandidateResult] = []
|
|
130
|
+
|
|
131
|
+
def _record(cr: CandidateResult, bucket: List[CandidateResult]) -> None:
|
|
132
|
+
bucket.append(cr)
|
|
133
|
+
ordered.append(cr)
|
|
134
|
+
|
|
135
|
+
for config in candidates:
|
|
136
|
+
try:
|
|
137
|
+
outcome = bound.validate(config)
|
|
138
|
+
except ValueError as exc:
|
|
139
|
+
outcome = ValidationOutcome(False, "validation", format_optimizer_error(exc))
|
|
140
|
+
if not outcome.ok:
|
|
141
|
+
_record(
|
|
142
|
+
_failure(
|
|
143
|
+
config,
|
|
144
|
+
objectives,
|
|
145
|
+
outcome.message or "invalid configuration",
|
|
146
|
+
outcome.failure_phase or "validation",
|
|
147
|
+
),
|
|
148
|
+
failed,
|
|
149
|
+
)
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
artifact = bound.materialize(config)
|
|
154
|
+
except ValueError as exc:
|
|
155
|
+
_record(
|
|
156
|
+
_failure(config, objectives, format_optimizer_error(exc), "materialization"),
|
|
157
|
+
failed,
|
|
158
|
+
)
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
key = artifact_key(artifact) if cache is not None else None
|
|
162
|
+
if key is not None and isinstance(cache, EvaluationCache):
|
|
163
|
+
remembered = cache.refusal(key)
|
|
164
|
+
if remembered is not None:
|
|
165
|
+
# This artifact was already measured and REFUSED, and that
|
|
166
|
+
# refusal was charged once. Replay the recorded outcome --
|
|
167
|
+
# same message, same phase, so the feedback upstream is
|
|
168
|
+
# identical -- without running the evaluator or charging the
|
|
169
|
+
# budget again (evaluation_attempted stays False: no
|
|
170
|
+
# evaluation happened HERE).
|
|
171
|
+
message, phase = remembered
|
|
172
|
+
cache.refusal_hits += 1
|
|
173
|
+
_record(_failure(config, objectives, message, phase), failed)
|
|
174
|
+
continue
|
|
175
|
+
if key is not None and key in cache:
|
|
176
|
+
normalized = dict(cache[key])
|
|
177
|
+
if isinstance(cache, EvaluationCache):
|
|
178
|
+
cache.hits += 1
|
|
179
|
+
elif isinstance(cache, EvaluationCache) and cache.exhausted():
|
|
180
|
+
# The budget is spent. Report it as a refusal rather than quietly
|
|
181
|
+
# measuring one more, so the number the caller gave is the number
|
|
182
|
+
# they are billed for.
|
|
183
|
+
_record(
|
|
184
|
+
_failure(
|
|
185
|
+
config,
|
|
186
|
+
objectives,
|
|
187
|
+
f"evaluation budget of {cache.budget} exhausted",
|
|
188
|
+
"budget",
|
|
189
|
+
),
|
|
190
|
+
failed,
|
|
191
|
+
)
|
|
192
|
+
continue
|
|
193
|
+
else:
|
|
194
|
+
try:
|
|
195
|
+
obj = bound.evaluate(artifact)
|
|
196
|
+
except ValueError as exc:
|
|
197
|
+
# A measurement that failed was still a measurement. It ran the
|
|
198
|
+
# simulator, it took the wall-clock, and on a timeout it took
|
|
199
|
+
# the *most* wall-clock of anything in the batch. Not charging
|
|
200
|
+
# it let a run keep going until it had 40 successes, however
|
|
201
|
+
# many artifacts that took, and report the budget as honoured.
|
|
202
|
+
if isinstance(cache, EvaluationCache):
|
|
203
|
+
cache.misses += 1
|
|
204
|
+
if key is not None:
|
|
205
|
+
# Remember the refusal under the artifact's identity,
|
|
206
|
+
# so re-proposing it is a replay, never a second bill.
|
|
207
|
+
cache.record_refusal(
|
|
208
|
+
key, format_optimizer_error(exc), "evaluation")
|
|
209
|
+
_record(
|
|
210
|
+
_failure(
|
|
211
|
+
config,
|
|
212
|
+
objectives,
|
|
213
|
+
format_optimizer_error(exc),
|
|
214
|
+
"evaluation",
|
|
215
|
+
evaluation_attempted=True,
|
|
216
|
+
),
|
|
217
|
+
failed,
|
|
218
|
+
)
|
|
219
|
+
continue
|
|
220
|
+
normalized = normalize_objective_values(obj, objectives)
|
|
221
|
+
if key is not None:
|
|
222
|
+
cache[key] = dict(normalized)
|
|
223
|
+
if isinstance(cache, EvaluationCache):
|
|
224
|
+
cache.misses += 1
|
|
225
|
+
|
|
226
|
+
_record(
|
|
227
|
+
CandidateResult(
|
|
228
|
+
configuration=config,
|
|
229
|
+
objectives=normalized,
|
|
230
|
+
is_valid=True,
|
|
231
|
+
evaluation_attempted=True,
|
|
232
|
+
),
|
|
233
|
+
valid,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
return valid, failed, ordered
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""A problem's optional CHEAPER evaluation fidelity, and its separate ledger.
|
|
2
|
+
|
|
3
|
+
Some evaluators expose a knob that buys a correlated answer for a fraction of
|
|
4
|
+
the cost -- fewer mapper iterations, a coarser mesh, a shorter simulation, a
|
|
5
|
+
subsample of the workload. A campaign whose budget is denominated in REAL
|
|
6
|
+
evaluations can spend that cheaper mode on evidence the surrogate needs and
|
|
7
|
+
still be honest about what it paid, but only if the two are never added up.
|
|
8
|
+
|
|
9
|
+
This module is the seam, and its whole design is the separation:
|
|
10
|
+
|
|
11
|
+
* :class:`ProxySource` holds the problem's ``evaluate_proxy`` bound method and
|
|
12
|
+
a key function, **and nothing else**. It has no reference to the problem,
|
|
13
|
+
the evaluation cache, or the budget, so "a proxy evaluation cannot become a
|
|
14
|
+
charged evaluation" is a property of the object graph rather than a promise
|
|
15
|
+
in a docstring -- the same construction that makes the screen unable to
|
|
16
|
+
spend budget (see :mod:`agent_evolve.session.screening`).
|
|
17
|
+
* Every proxy call is counted in :class:`ProxyLedger`, reported beside the
|
|
18
|
+
charged count and never folded into it.
|
|
19
|
+
* A hard ``ceiling`` bounds what a run may spend at the cheap fidelity, so a
|
|
20
|
+
consumer that asks for a proxy value in a loop degrades to "no proxy" rather
|
|
21
|
+
than to an unbounded bill.
|
|
22
|
+
|
|
23
|
+
A problem opts in by defining::
|
|
24
|
+
|
|
25
|
+
def evaluate_proxy(self, config) -> Mapping[str, float]: ...
|
|
26
|
+
|
|
27
|
+
returning EXACTLY the declared objectives, at a cheaper and correlated
|
|
28
|
+
fidelity. Optionally it may describe that fidelity for the record::
|
|
29
|
+
|
|
30
|
+
proxy_fidelity_name: str # e.g. "timeloop@50-mappings"
|
|
31
|
+
proxy_cost_ratio: float # measured seconds(proxy)/seconds(real)
|
|
32
|
+
|
|
33
|
+
Nothing here decides whether a proxy is GOOD. That is the gate's job: a proxy
|
|
34
|
+
enters the screen as evidence or as a candidate ordering and is
|
|
35
|
+
cross-validated against the run's own REAL measurements like anything else.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from __future__ import annotations
|
|
39
|
+
|
|
40
|
+
import json
|
|
41
|
+
from dataclasses import dataclass, field
|
|
42
|
+
from typing import Any, Callable, Dict, Mapping, Optional, Sequence
|
|
43
|
+
|
|
44
|
+
from agent_evolve.core.problem import ObjectiveSpec, normalize_objective_values
|
|
45
|
+
|
|
46
|
+
__all__ = ["ProxyLedger", "ProxySource", "proxy_fidelity_builder"]
|
|
47
|
+
|
|
48
|
+
Config = Dict[str, Any]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _canonical_key(config: Mapping[str, Any]) -> str:
|
|
52
|
+
return json.dumps(config, sort_keys=True, default=str)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class ProxyLedger:
|
|
57
|
+
"""What the cheap fidelity was asked for, and what it cost. Never charged.
|
|
58
|
+
|
|
59
|
+
``evaluations`` counts calls that actually ran the cheap evaluator;
|
|
60
|
+
``cache_hits`` counts repeats served from memory, because a consumer that
|
|
61
|
+
re-asks for the same candidate must not be reported as having spent
|
|
62
|
+
anything twice. ``refused_ceiling`` is the count of requests declined
|
|
63
|
+
because the run had spent its proxy allowance.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
evaluations: int = 0
|
|
67
|
+
cache_hits: int = 0
|
|
68
|
+
failures: int = 0
|
|
69
|
+
refused_ceiling: int = 0
|
|
70
|
+
rows_offered: int = 0
|
|
71
|
+
rows_used: int = 0
|
|
72
|
+
|
|
73
|
+
def as_dict(self) -> Dict[str, int]:
|
|
74
|
+
return {
|
|
75
|
+
"proxy_evaluations": self.evaluations,
|
|
76
|
+
"proxy_cache_hits": self.cache_hits,
|
|
77
|
+
"proxy_failures": self.failures,
|
|
78
|
+
"proxy_refused_ceiling": self.refused_ceiling,
|
|
79
|
+
"proxy_rows_offered": self.rows_offered,
|
|
80
|
+
"proxy_rows_used": self.rows_used,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ProxySource:
|
|
85
|
+
"""The cheap fidelity, memoized, counted, and bounded.
|
|
86
|
+
|
|
87
|
+
Construct with :meth:`for_problem`, which returns ``None`` when the
|
|
88
|
+
problem exposes no cheaper fidelity -- so every consumer's "off" path is
|
|
89
|
+
the absence of an object rather than a flag it might forget to read.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
def __init__(
|
|
93
|
+
self,
|
|
94
|
+
evaluate: Callable[[Config], Mapping[str, float]],
|
|
95
|
+
objectives: Sequence[ObjectiveSpec],
|
|
96
|
+
*,
|
|
97
|
+
key: Callable[[Config], str] = _canonical_key,
|
|
98
|
+
name: str = "proxy",
|
|
99
|
+
cost_ratio: Optional[float] = None,
|
|
100
|
+
ceiling: Optional[int] = None,
|
|
101
|
+
) -> None:
|
|
102
|
+
if not callable(evaluate):
|
|
103
|
+
raise TypeError("evaluate must be callable")
|
|
104
|
+
if ceiling is not None and ceiling < 0:
|
|
105
|
+
raise ValueError(f"ceiling must not be negative, got {ceiling}")
|
|
106
|
+
# DELIBERATELY only these: a bound method, a key function, the
|
|
107
|
+
# objective specs, and counters. No problem, no cache, no budget.
|
|
108
|
+
self._evaluate = evaluate
|
|
109
|
+
self._key = key
|
|
110
|
+
self._specs = list(objectives)
|
|
111
|
+
self.name = str(name)
|
|
112
|
+
self.cost_ratio = None if cost_ratio is None else float(cost_ratio)
|
|
113
|
+
self.ceiling = ceiling
|
|
114
|
+
self.ledger = ProxyLedger()
|
|
115
|
+
self._memo: Dict[str, Optional[Dict[str, float]]] = {}
|
|
116
|
+
#: the harvest contract (`core.telemetry`), so the cheap fidelity's
|
|
117
|
+
#: ledger reaches the SearchResult like any other mechanism's counters
|
|
118
|
+
self.telemetry = self.ledger
|
|
119
|
+
self.mechanism = "proxy_fidelity"
|
|
120
|
+
self.authored_by = "none"
|
|
121
|
+
|
|
122
|
+
# -- construction ------------------------------------------------------
|
|
123
|
+
@classmethod
|
|
124
|
+
def for_problem(cls, problem: Any, *, ceiling: Optional[int] = None
|
|
125
|
+
) -> Optional["ProxySource"]:
|
|
126
|
+
"""The problem's cheap fidelity, or ``None`` if it does not have one."""
|
|
127
|
+
|
|
128
|
+
evaluate = getattr(problem, "evaluate_proxy", None)
|
|
129
|
+
if not callable(evaluate):
|
|
130
|
+
return None
|
|
131
|
+
key = getattr(problem, "candidate_key", None)
|
|
132
|
+
return cls(
|
|
133
|
+
evaluate,
|
|
134
|
+
list(problem.objectives),
|
|
135
|
+
key=key if callable(key) else _canonical_key,
|
|
136
|
+
name=str(getattr(problem, "proxy_fidelity_name", "proxy")),
|
|
137
|
+
cost_ratio=getattr(problem, "proxy_cost_ratio", None),
|
|
138
|
+
ceiling=ceiling,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# -- use ---------------------------------------------------------------
|
|
142
|
+
def key(self, config: Config) -> str:
|
|
143
|
+
return self._key(config)
|
|
144
|
+
|
|
145
|
+
def evaluate(self, config: Config) -> Optional[Dict[str, float]]:
|
|
146
|
+
"""The cheap objectives for *config*, or ``None``.
|
|
147
|
+
|
|
148
|
+
``None`` means "this run has no cheap answer for this candidate" --
|
|
149
|
+
the evaluator refused, returned something the objective contract does
|
|
150
|
+
not accept, or the proxy allowance is spent. Every consumer treats
|
|
151
|
+
that as "no proxy", never as a value.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
token = self._key(config)
|
|
155
|
+
if token in self._memo:
|
|
156
|
+
self.ledger.cache_hits += 1
|
|
157
|
+
return self._memo[token]
|
|
158
|
+
if self.ceiling is not None and self.ledger.evaluations >= self.ceiling:
|
|
159
|
+
self.ledger.refused_ceiling += 1
|
|
160
|
+
return None
|
|
161
|
+
self.ledger.evaluations += 1
|
|
162
|
+
try:
|
|
163
|
+
values = normalize_objective_values(self._evaluate(config), self._specs)
|
|
164
|
+
except Exception:
|
|
165
|
+
self.ledger.failures += 1
|
|
166
|
+
self._memo[token] = None
|
|
167
|
+
return None
|
|
168
|
+
self._memo[token] = values
|
|
169
|
+
return values
|
|
170
|
+
|
|
171
|
+
def rows(
|
|
172
|
+
self, candidates: Sequence[Config], *, exclude: Sequence[str] = ()
|
|
173
|
+
) -> list[tuple[Config, Dict[str, float]]]:
|
|
174
|
+
"""``(config, cheap objectives)`` for each candidate that yields one.
|
|
175
|
+
|
|
176
|
+
``exclude`` names candidate keys that already have a REAL measurement.
|
|
177
|
+
A real row always supersedes a cheap one: the point of the seam is to
|
|
178
|
+
add evidence where there is none, never to dilute evidence there is.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
skip = set(exclude)
|
|
182
|
+
out = []
|
|
183
|
+
for candidate in candidates:
|
|
184
|
+
if self._key(candidate) in skip:
|
|
185
|
+
continue
|
|
186
|
+
self.ledger.rows_offered += 1
|
|
187
|
+
values = self.evaluate(candidate)
|
|
188
|
+
if values is not None:
|
|
189
|
+
out.append((dict(candidate), values))
|
|
190
|
+
return out
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def proxy_fidelity_builder(source: ProxySource) -> Callable[..., Any]:
|
|
194
|
+
"""The cheap fidelity itself, as a :data:`SurrogateBuilder`.
|
|
195
|
+
|
|
196
|
+
A surrogate is anything that ORDERS candidates without charging the
|
|
197
|
+
budget, and a correlated cheap evaluation is exactly that. Presenting it
|
|
198
|
+
as a builder means it earns its place the same way an authored artifact
|
|
199
|
+
does: the screen's gate cross-validates it against the run's own REAL
|
|
200
|
+
measurements, per objective, and admits it only if it ranks them. Nothing
|
|
201
|
+
about this asserts that a cheap fidelity ranks well -- it makes the claim
|
|
202
|
+
checkable in the loop that would rely on it.
|
|
203
|
+
|
|
204
|
+
The builder ignores the training rows because there is nothing to fit.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
def build(rows: Any, specs: Any) -> Callable[[Sequence[Config]], Any]:
|
|
208
|
+
names = [spec.name for spec in specs]
|
|
209
|
+
goals = {spec.name: spec.goal for spec in specs}
|
|
210
|
+
|
|
211
|
+
def predict(configs: Sequence[Config]) -> Any:
|
|
212
|
+
out: list[Optional[Dict[str, float]]] = []
|
|
213
|
+
for config in configs:
|
|
214
|
+
out.append(source.evaluate(config))
|
|
215
|
+
got = [row for row in out if row is not None]
|
|
216
|
+
if not got:
|
|
217
|
+
return None # no cheap answer at all -> screen nothing
|
|
218
|
+
if len(got) == len(out):
|
|
219
|
+
return out
|
|
220
|
+
# A candidate the cheap fidelity REFUSES is ranked last, not
|
|
221
|
+
# dropped: refusing one member of a pool must not blind the screen
|
|
222
|
+
# to the other n-1. This mirrors what the expensive evaluator
|
|
223
|
+
# already does with an infeasible candidate -- it returns a
|
|
224
|
+
# penalty vector rather than nothing -- and it keeps the returned
|
|
225
|
+
# sequence aligned with the pool the caller passed in.
|
|
226
|
+
worst: Dict[str, float] = {}
|
|
227
|
+
for name in names:
|
|
228
|
+
values = [row[name] for row in got]
|
|
229
|
+
span = max(values) - min(values)
|
|
230
|
+
pad = abs(span) * 0.1 + (abs(max(values, key=abs)) * 1e-9) + 1e-12
|
|
231
|
+
worst[name] = (max(values) + pad if goals.get(name) == "min"
|
|
232
|
+
else min(values) - pad)
|
|
233
|
+
return [dict(worst) if row is None else row for row in out]
|
|
234
|
+
|
|
235
|
+
return predict
|
|
236
|
+
|
|
237
|
+
return build
|