Files

171 lines
5.4 KiB
Python
Raw Permalink Normal View History

2026-09-15 13:35:35 +08:00
from __future__ import annotations
import unittest
import numpy as np
from evaluate_annotated_floor_events import AnnotatedOpportunity
from evaluate_egospeak_event_proxy import (
decision_source_rows,
evaluate_family,
horizon_indices,
score_activity_proxy,
)
from evaluate_floor_state_changes import NUM_CLASSES, NUM_HORIZONS
def opportunity(
uid: str,
*,
family: str = "entry",
positive: bool = True,
start: int = 20,
end: int = 21,
anchor: float = 4.0,
region_start: float = 4.0,
region_end: float = 4.0,
source: str = "WEARER_ONSET",
) -> AnnotatedOpportunity:
return AnnotatedOpportunity(
uid=uid,
session="Session_4",
family=family, # type: ignore[arg-type]
positive=positive,
subtype=("WEARER_ENTRY" if family == "entry" else "INT_YIELD")
if positive
else ("ENTRY_OTHER_TO_OTHER" if family == "entry" else "INT_OTHER_BACKCHANNEL"),
start_row=start,
end_row_exclusive=end,
anchor_seconds=anchor,
region_start_seconds=region_start,
region_end_seconds=region_end,
candidate_source=source,
)
def arrays(length: int = 50) -> tuple[np.ndarray, np.ndarray]:
return (
np.zeros((length, NUM_CLASSES, NUM_HORIZONS), dtype=np.float32),
np.ones((length, NUM_HORIZONS), dtype=bool),
)
class EgoSpeakEventProxyTests(unittest.TestCase):
def test_positive_uses_three_pre_anchor_source_rows(self) -> None:
item = opportunity("positive", anchor=4.0)
self.assertEqual(
decision_source_rows(item, window_rows=3),
(17, 20, "pre_behavior_anchor"),
)
def test_independent_hard_negative_uses_only_equal_width_region_prefix(self) -> None:
item = opportunity(
"negative",
positive=False,
start=10,
end=40,
anchor=2.0,
region_start=2.0,
region_end=8.0,
source="OTHER_TO_OTHER",
)
self.assertEqual(
decision_source_rows(item, window_rows=3),
(10, 13, "hard_negative_opportunity_onset"),
)
def test_short_hard_negative_is_not_silently_padded(self) -> None:
item = opportunity(
"short",
positive=False,
start=10,
end=12,
source="OTHER_TO_OTHER",
)
self.assertIsNone(decision_source_rows(item, window_rows=3))
def test_relabelled_raw_boundary_uses_pre_anchor_rows(self) -> None:
item = opportunity(
"backchannel",
positive=False,
start=5,
end=35,
anchor=4.0,
region_start=1.0,
region_end=7.0,
source="WEARER_ONSET",
)
self.assertEqual(
decision_source_rows(item, window_rows=3),
(17, 20, "pre_behavior_anchor"),
)
def test_trajectory_follows_target_aligned_diagonal(self) -> None:
item = opportunity("positive", anchor=4.0)
prediction, valid = arrays()
selected = horizon_indices([0.6, 0.8, 1.0])
# Best decision row is 18. Target rows are source+horizon_index+1.
prediction[21, 1, 2] = 0.6
prediction[22, 1, 3] = 0.9
prediction[23, 1, 4] = 0.3
scored = score_activity_proxy(
item,
{"Session_4": (prediction, valid)},
window_rows=3,
selected_horizons=selected,
)
self.assertIsNotNone(scored)
score, details = scored # type: ignore[misc]
self.assertAlmostEqual(score, 0.6)
self.assertEqual(details["best_source_row"], 18)
self.assertEqual(len(details["best_wearer_trajectory"]), 3)
def test_yield_inverts_sustained_wearer_activity(self) -> None:
item = opportunity("yield", family="int", anchor=4.0, source="WEARER_OFFSET")
prediction, valid = arrays()
selected = horizon_indices([0.6, 0.8])
for source_row in range(17, 20):
prediction[source_row + 3, 1, 2] = 0.2
prediction[source_row + 4, 1, 3] = 0.2
scored = score_activity_proxy(
item,
{"Session_4": (prediction, valid)},
window_rows=3,
selected_horizons=selected,
)
self.assertIsNotNone(scored)
self.assertAlmostEqual(scored[0], 0.8) # type: ignore[index]
def test_each_opportunity_contributes_one_metric_row(self) -> None:
positive = opportunity("p", anchor=4.0)
negative = opportunity(
"n",
positive=False,
start=25,
end=30,
anchor=5.0,
region_start=5.0,
region_end=6.0,
source="OTHER_TO_OTHER",
)
prediction, valid = arrays()
selected = horizon_indices([0.6])
for source_row in range(17, 20):
prediction[source_row + 3, 1, 2] = 0.9
metric, rows = evaluate_family(
[positive, negative],
{"Session_4": (prediction, valid)},
"entry",
[],
window_rows=3,
selected_horizons=selected,
)
self.assertEqual(len(rows), 2)
self.assertEqual(metric["num_positive"], 1)
self.assertEqual(metric["num_hard_negative"], 1)
self.assertAlmostEqual(metric["average_precision"], 1.0)
if __name__ == "__main__":
unittest.main()