Source code for qca.mlqca.schema
"""Input schema objects for machine-learning-enhanced QCA."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Literal
MLConditionDataType = Literal["continuous", "ordinal", "binary", "nominal"]
MLConditionDirection = Literal["high", "low", "infer"]
[docs]
@dataclass(frozen=True)
class MLConditionSpec:
"""Describe one uncalibrated candidate condition for mlQCA."""
name: str
data_type: MLConditionDataType = "continuous"
direction: MLConditionDirection = "infer"
required: bool = False
enabled: bool = True
theoretical_cutoffs: tuple[float, ...] = ()
def __post_init__(self) -> None:
name = str(self.name).strip()
data_type = str(self.data_type).strip().lower()
direction = str(self.direction).strip().lower()
if not name:
raise ValueError("MLConditionSpec.name must be a non-empty string.")
if data_type not in {"continuous", "ordinal", "binary", "nominal"}:
raise ValueError(
"MLConditionSpec.data_type must be continuous, ordinal, "
f"binary, or nominal. Got {self.data_type!r}."
)
if direction not in {"high", "low", "infer"}:
raise ValueError(
"MLConditionSpec.direction must be high, low, or infer. "
f"Got {self.direction!r}."
)
cutoffs = tuple(float(value) for value in self.theoretical_cutoffs)
if any(not _is_finite(value) for value in cutoffs):
raise ValueError("theoretical_cutoffs must contain finite values.")
if len(set(cutoffs)) != len(cutoffs):
raise ValueError("theoretical_cutoffs cannot contain duplicates.")
object.__setattr__(self, "name", name)
object.__setattr__(self, "data_type", data_type)
object.__setattr__(self, "direction", direction)
object.__setattr__(self, "theoretical_cutoffs", tuple(sorted(cutoffs)))
[docs]
def to_dict(self) -> dict[str, object]:
"""Return a serializable schema record."""
return {
"name": self.name,
"data_type": self.data_type,
"direction": self.direction,
"required": self.required,
"enabled": self.enabled,
"theoretical_cutoffs": list(self.theoretical_cutoffs),
}
def _is_finite(value: float) -> bool:
return value not in {float("inf"), float("-inf")} and value == value
__all__ = [
"MLConditionDataType",
"MLConditionDirection",
"MLConditionSpec",
]