Source code for veupath_chatbot.services.parameter_optimization.config

"""Configuration types for parameter optimization.

Defines the parameter specification, optimization config, trial result,
and optimization result dataclasses, as well as type aliases for callbacks.
"""

from collections.abc import Callable
from dataclasses import dataclass
from typing import Literal

from veupath_chatbot.platform.types import JSONValue
from veupath_chatbot.services.experiment.helpers import ProgressCallback
from veupath_chatbot.services.experiment.types import (
    OptimizationObjective,
    ParameterType,
)

__all__ = ["ProgressCallback"]  # re-exported for parameter_optimization consumers


CancelCheck = Callable[[], bool]
"""Returns True when the optimisation should stop early."""

OptimizationMethod = Literal["bayesian", "grid", "random"]


[docs] @dataclass(frozen=True, slots=True) class ParameterSpec: """Describes a single parameter to optimise.""" name: str param_type: ParameterType # numeric / integer min_value: float | None = None max_value: float | None = None log_scale: bool = False step: float | None = None # categorical choices: list[str] | None = None
[docs] @dataclass(slots=True) class OptimizationConfig: budget: int = 30 objective: OptimizationObjective = "f1" beta: float = 1.0 # only for f_beta recall_weight: float = 1.0 # only for custom precision_weight: float = 1.0 # only for custom method: OptimizationMethod = "bayesian" result_count_penalty: float = 0.0 """Weight for penalising large result sets. The penalty is ``result_count_penalty * (result_count / total_genes)`` where *total_genes* is the denominator (defaults to 20 000 if unknown). A small value (e.g. 0.1) acts as a tiebreaker; higher values make the optimiser strongly prefer tighter results."""
[docs] @dataclass(frozen=True, slots=True) class TrialResult: trial_number: int parameters: dict[str, JSONValue] score: float recall: float | None false_positive_rate: float | None result_count: int | None positive_hits: int | None = None negative_hits: int | None = None total_positives: int | None = None total_negatives: int | None = None
[docs] @dataclass(slots=True) class OptimizationResult: optimization_id: str best_trial: TrialResult | None all_trials: list[TrialResult] pareto_frontier: list[TrialResult] sensitivity: dict[str, float] total_time_seconds: float status: str # completed | cancelled | error error_message: str | None = None