Source code for tabench.core.factors
"""Typed hyperparameter ("factor") specifications, SimOpt-style (P4).
Every model declares its tunable factors with defaults so experiment
manifests can log the complete configuration.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
__all__ = ["FactorSpec", "resolve_factors"]
[docs]
@dataclass(frozen=True)
class FactorSpec:
"""Specification of one model hyperparameter."""
default: Any
kind: str = "float" # float | int | bool | str
bounds: tuple[float, float] | None = None
doc: str = ""
[docs]
def resolve_factors(
specs: dict[str, FactorSpec], overrides: dict[str, Any]
) -> dict[str, Any]:
"""Merge user overrides into declared factor defaults, validating names/bounds."""
unknown = set(overrides) - set(specs)
if unknown:
raise ValueError(f"Unknown factors {sorted(unknown)}; declared: {sorted(specs)}")
values: dict[str, Any] = {}
for name, spec in specs.items():
value = overrides.get(name, spec.default)
if spec.bounds is not None:
lo, hi = spec.bounds
if not (lo <= value <= hi):
raise ValueError(f"Factor {name}={value!r} outside bounds [{lo}, {hi}]")
values[name] = value
return values