QuarksLab / Down /AntiDown /levo /levo_q_tabular.py
TwoQuarks's picture
Upload 100 files
ccba775 verified
Raw
History Blame Contribute Delete
2.07 kB
from typing import Optional
import numpy as np
from .policies import hf_levo_policy_tabular
class LevoQTabularAgent:
"""
Tabular Q-learning agent with an HF-Levo policy.
The Q-update is standard:
Q(s, a) <- Q(s, a) + alpha * (r + gamma max_a' Q(s', a') - Q(s, a))
The policy is:
score(a) = Q(s, a) + A cos(omega * t + phi_a + phase_offset)
pi(a|s) = softmax(score / tau)
"""
def __init__(
self,
n_states: int,
n_actions: int,
gamma: float = 0.99,
alpha: float = 0.1,
A: float = 0.5,
omega: float = 0.1,
phase_offset: float = 0.0,
ent_weight: float = 0.0,
prior: Optional[np.ndarray] = None,
tau: float = 1.0,
name: str = "LevoQ",
) -> None:
self.n_states = n_states
self.n_actions = n_actions
self.gamma = gamma
self.alpha = alpha
self.A = A
self.omega = omega
self.phase_offset = phase_offset
self.ent_weight = ent_weight
self.prior = prior
self.tau = tau
self.name = name
self.Q = np.zeros((n_states, n_actions), dtype=float)
self.t = 0 # global step counter for the HF modulation
def select_action(self, state: int, rng: np.random.Generator) -> int:
probs = hf_levo_policy_tabular(
self.Q,
state,
t=self.t,
A=self.A,
omega=self.omega,
phase_offset=self.phase_offset,
ent_weight=self.ent_weight,
prior=self.prior,
tau=self.tau,
)
self.t += 1
return int(rng.choice(self.n_actions, p=probs))
def update(self, s: int, a: int, r: float, s_next: int, done: bool) -> None:
q_sa = self.Q[s, a]
if done:
target = r
else:
target = r + self.gamma * float(self.Q[s_next].max())
td = target - q_sa
self.Q[s, a] = q_sa + self.alpha * td