Skip to content

Faster filterDateRange via binary search#31

Open
ps2 wants to merge 1 commit into
tidepool-org:mainfrom
ps2:pr-c-perf-and-transitions
Open

Faster filterDateRange via binary search#31
ps2 wants to merge 1 commit into
tidepool-org:mainfrom
ps2:pr-c-perf-and-transitions

Conversation

@ps2
Copy link
Copy Markdown
Collaborator

@ps2 ps2 commented May 19, 2026

Summary

Adds a binary-search filterDateRange overload on RandomAccessCollection where Element: TimelineValue, Index == Int. Returns the same result as the existing Sequence-based linear-filter implementation but uses two binary searches instead of a linear scan. Picks up automatically for Array-backed callers (which is every caller in this codebase) via Swift protocol dispatch.

Why

In LoopEval workloads that call filterDateRange repeatedly on long schedules — e.g., InsulinMath.glucoseEffectsMidAbsorptionISF and DoseMath.insulinCorrection when the sensitivity schedule has many segments — the linear filter was the dominant cost. A 60-day per-step prediction sweep with a per-step ISF schedule went from ~30 min to ~1 min (≈30× faster) with bit-identical output to the linear-filter path.

Test plan

  • All existing tests pass (xcrun swift test)
  • FilterDateRangeTests.swift (11 tests):
    • Equivalence with the linear-filter reference for all boundary shapes:
      empty input, both bounds nil, only-start, only-end, both-in-middle,
      start-before-all, end-after-all, fully-outside, before-all, exact-match-one-segment
    • Single-sample collection edge cases (size-1 arrays, queries before/inside/after)
    • 100-iteration randomized fuzz over a 200-element contiguous schedule

SampleValue.swift: add a filterDateRange overload for
RandomAccessCollection where Element: TimelineValue, Index == Int.
Returns the same result as the existing Sequence-based linear-filter
implementation but uses two binary searches instead of a linear scan.
Picks up automatically for Array-backed callers (which is every caller
in this codebase via Swift protocol dispatch).

Significant speedup for hot paths that call filterDateRange repeatedly
on long schedules — for example, InsulinMath.glucoseEffectsMidAbsorptionISF
and DoseMath.insulinCorrection when the sensitivity schedule has many
segments. In a LoopEval 60-day per-step prediction sweep with a per-step
ISF schedule, total sim wall-clock went from ~30 min to ~1 min (≈30×
faster) with bit-identical output to the linear-filter path.

Tests: FilterDateRangeTests.swift with 11 cases covering equivalence
with the linear-filter reference: boundary cases (empty, both bounds
nil, only start, only end), start-before-all, end-after-all, fully-
outside, single-sample collections, exact-match-one-segment, and a
100-iteration randomized fuzz over a 200-element contiguous schedule.
@ps2 ps2 force-pushed the pr-c-perf-and-transitions branch from dad0b81 to 31c533a Compare May 19, 2026 16:23
@ps2 ps2 changed the title Faster filterDateRange (binary search) + relax momentum gradual-transitions guard Faster filterDateRange via binary search May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant