Files
digital-drosophila/models/male-cns-lif/frozen-interface-v1/frozen_interface.py
T

36 lines
1.2 KiB
Python

#!/usr/bin/env python3
"""Game-agnostic abstract action-logit API for Phase 4G learned adapters."""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
@dataclass(frozen=True)
class AbstractActionOutput:
action_logits: np.ndarray
def __post_init__(self) -> None:
value = np.asarray(self.action_logits, dtype=np.float32)
if value.shape != (4,) or not np.isfinite(value).all():
raise ValueError("action_logits must be finite float32[4]")
object.__setattr__(self, "action_logits", value)
def deterministic_argmax(self) -> int:
return int(np.argmax(self.action_logits))
def sample(self, seed: int, temperature: float = 1.0, epsilon: float = 0.0) -> int:
if temperature <= 0 or not 0 <= epsilon <= 1:
raise ValueError("temperature must be positive and epsilon in [0,1]")
rng = np.random.default_rng(seed)
if rng.random() < epsilon:
return int(rng.integers(0, 4))
z = self.action_logits.astype(np.float64) / temperature
z -= z.max(); p = np.exp(z); p /= p.sum()
return int(rng.choice(4, p=p))
ACTION_NAMES = ("ACTION_0", "ACTION_1", "ACTION_2", "ACTION_3")