Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/detectmatelibrary/detectors/value_range_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,28 @@ def __init__(
self.config: ValueRangeDetectorConfig # type narrowing for IDE

def add_value(self, tracker: SingleStabilityTracker, value: Any) -> None:
"""Add a new value to the tracker (range semantics)."""
"""Add a new value to the tracker (range semantics).

Only the extremes are stored: ``unique_set`` holds at most two elements
({min, max}), so storage is O(1) per variable instead of O(distinct
values). ``change_series`` and the min/max are byte-identical to storing
every value. The classifier's RANDOM branch can no longer fire for range
variables (size <= 2 never equals the change_series length); monotonic
counters stay excluded as UNSTABLE via their all-True series.
"""
try:
value = float(value)
value = int(value) if value.is_integer() else value
except ValueError:
return
if len(tracker.unique_set) > 0:
if tracker.unique_set:
min_ = min(tracker.unique_set)
max_ = max(tracker.unique_set)
tracker.change_series.append(value < min_ or value > max_)
tracker.unique_set = {min(min_, value), max(max_, value)}
else:
tracker.change_series.append(True)
tracker.unique_set.add(value)
tracker.unique_set = {value}

def _event_data_kwargs(self) -> Optional[Dict[str, Any]]:
return self._stability_kwargs()
Expand Down
15 changes: 15 additions & 0 deletions tests/test_detectors/test_value_range_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@ def test_add_value_updates_tracker(self):
assert tracker.unique_set == {5, 7}
assert list(tracker.change_series) == [True, True]

def test_add_value_stores_only_min_max(self):
"""unique_set stays bounded to {min, max} regardless of how many
distinct values are seen; change detection still tracks the true
range."""
detector = ValueRangeDetector()
tracker = SingleStabilityTracker()

for v in [50, 10, 30, 90, 20, 70]: # min=10, max=90
detector.add_value(tracker, v)

assert tracker.unique_set == {10, 90}
# 50 (first, True), 10 (new min, True), 90 (new max, True) extend range;
# 30, 20, 70 fall inside -> False
assert list(tracker.change_series) == [True, True, False, True, False, False]


class TestValueRangeDetectorTraining:
"""Test ValueRangeDetector training functionality."""
Expand Down
Loading