llm-adaptive-novelty-framework / tests /test_controller.py
finpy1789
Sync Space to verified v10 framework; pin gradio 6.16.0 everywhere
078ba7c
Raw
History Blame Contribute Delete
5.26 kB
from framework.controller import (
AdaptiveController,
DecodingParameters,
FrameworkState,
)
def _make_state(lam=0.30, novelty=0.20, bias=0.40, quality=0.60):
return FrameworkState(
lambda_model=lam,
lambda_human=0.15,
aggregate_novelty=novelty,
aggregate_bias=bias,
aggregate_quality=quality,
)
def test_reward_signal_eq_xxxiii():
controller = AdaptiveController()
# r_{t+1} = D(s_t) - D(s_{t+1})
assert abs(controller.compute_reward(0.8, 0.5) - 0.3) < 1e-12
assert controller.compute_reward(0.5, 0.8) < 0
def test_td_error_and_value_update_eq_xxxv_xxxvi():
controller = AdaptiveController(gamma=0.95, alpha=0.1)
s0 = _make_state(novelty=0.10)
s1 = _make_state(novelty=0.30)
# With an empty value table: δ = r + γ·0 - 0 = r
reward = 0.25
delta = controller.compute_td_error(reward, s0, s1)
assert abs(delta - reward) < 1e-12
# V(s0) ← V(s0) + α·δ (Eq xxxvi)
v_after = controller.update_value(s0, delta)
assert abs(v_after - 0.1 * reward) < 1e-12
# Second TD error now sees the updated V(s0)
delta2 = controller.compute_td_error(reward, s0, s1)
assert abs(delta2 - (reward - v_after)) < 1e-12
def test_theta_update_moves_along_direction_and_clips_eq_xxxvii():
controller = AdaptiveController(eta=0.5)
theta = DecodingParameters(temperature=0.7, top_p=0.9, top_k=50)
# Novelty deficit direction increases exploration
direction = controller.CONTROL_DIRECTIONS["novelty_deficit"]
updated = controller.apply_parameter_update(theta, td_error=0.4, direction=direction)
assert updated.temperature > theta.temperature
assert updated.top_p >= theta.top_p
assert updated.top_k >= theta.top_k
# Large positive TD error must clip at θ_max
updated_max = controller.apply_parameter_update(theta, td_error=100.0, direction=direction)
assert updated_max.temperature == controller.TEMP_MAX
assert updated_max.top_p == controller.TOP_P_MAX
assert updated_max.top_k == controller.TOP_K_MAX
# Negative TD error reverses along c and clips at θ_min
updated_min = controller.apply_parameter_update(theta, td_error=-100.0, direction=direction)
assert updated_min.temperature == controller.TEMP_MIN
assert updated_min.top_p == controller.TOP_P_MIN
assert updated_min.top_k == controller.TOP_K_MIN
def test_control_direction_follows_dominant_gap():
controller = AdaptiveController()
state = _make_state(lam=0.30)
dominant, direction = controller.select_control_direction(
{"decay_mismatch": 0.02, "novelty_deficit": 0.30,
"bias_excess": 0.01, "quality_deficit": 0.05},
state,
)
assert dominant == "novelty_deficit"
assert direction["temperature"] > 0
dominant, direction = controller.select_control_direction(
{"decay_mismatch": 0.02, "novelty_deficit": 0.01,
"bias_excess": 0.40, "quality_deficit": 0.05},
state,
)
assert dominant == "bias_excess"
assert direction["temperature"] < 0
def test_closed_loop_episode_bootstrap_and_transition():
controller = AdaptiveController(eta=0.2, gamma=0.95, alpha=0.1)
theta_0 = DecodingParameters(temperature=0.7, top_p=0.9, top_k=50)
s0 = _make_state(novelty=0.10)
d0 = {"total_distance": 0.6,
"gap_vector": {"decay_mismatch": 0.0, "novelty_deficit": 0.25,
"bias_excess": 0.0, "quality_deficit": 0.05}}
step1 = controller.initial_step(s0, d0, theta_0)
# Bootstrap: δ_0 = D(s_0) with an empty value table
assert abs(step1.td_error - 0.6) < 1e-12
assert step1.theta_after.temperature > theta_0.temperature
s1 = _make_state(novelty=0.30)
d1 = {"total_distance": 0.35,
"gap_vector": {"decay_mismatch": 0.0, "novelty_deficit": 0.05,
"bias_excess": 0.0, "quality_deficit": 0.05}}
step2 = controller.transition_step(s0, s1, d0, d1, step1.theta_after)
# r_1 = 0.6 - 0.35 (Eq xxxiii); V updated by α·δ (Eq xxxvi)
assert abs(step2.reward - 0.25) < 1e-12
assert step2.value_after != step2.value_before
assert step2.distance_after == 0.35
def test_controller_accepts_cli_metric_keys():
controller = AdaptiveController()
recommendation = controller.recommend_parameters(
{
"novelty": 0.2,
"self_bleu": 60.0,
"fallback_quality": 0.8,
"bias_proxy": 0.1,
"perplexity": 40.0,
},
current_temp=0.7,
current_top_p=0.9,
)
assert "temperature=0.85" in recommendation
assert "top_p=0.96" in recommendation
def test_controller_clamps_recommendations():
controller = AdaptiveController()
recommendation = controller.recommend_parameters(
{
"Novelty": 0.0,
"Self-BLEU": 100.0,
"Fallback Quality": 0.0,
"Bias Proxy": 1.0,
"Perplexity": 999.0,
},
current_temp=1.2,
current_top_p=0.98,
)
assert "temperature=1.20" in recommendation
assert "top_p=0.98" in recommendation
if __name__ == "__main__":
test_controller_accepts_cli_metric_keys()
test_controller_clamps_recommendations()