-
Notifications
You must be signed in to change notification settings - Fork 9
Comparing changes
Open a pull request
base repository: LoopKit/LoopAlgorithm
base: 84a099f
head repository: LoopKit/LoopAlgorithm
compare: 7d016fb
- 19 commits
- 49 files changed
- 8 contributors
Commits on Aug 21, 2025
-
Fix decoding of old AutomaticDoseRecommendation structures without ba…
…salAdjustment (#20)
Configuration menu - View commit details
-
Copy full SHA for 7ba61e1 - Browse repository at this point
Copy the full SHA 7ba61e1View commit details
Commits on Aug 28, 2025
-
Carb absorption model selection updates. (#21)
* Add ability to specify carbAbsorptionModel in LoopPredictionInput and in encoded files * Make codable rep for CarbAbsorptionModel a string
Configuration menu - View commit details
-
Copy full SHA for 29c7b52 - Browse repository at this point
Copy the full SHA 29c7b52View commit details
Commits on Oct 31, 2025
-
LOOP-5502 Allow setting of max active insulin multiplier (#22)
* Allow setting of max active insulin multiplier * Fix formatting for older xcode * Fix formatting for older xcode
Configuration menu - View commit details
-
Copy full SHA for 89dd58a - Browse repository at this point
Copy the full SHA 89dd58aView commit details
Commits on Nov 13, 2025
-
Mjc/has gradual transitions (#23)
* Adds gradual transition validation for retrospective correction as a mitigation for spurious iCGM values * Add gradualTransitionsThreshold to AlgorithmInput and related structures Set RC transition check to only use the last 7 samples * Refactor conditions in momentum to include gradual transitions check * Changed default for gradualTransitionThreshold from 20 -> 40 * fixed naming for gradualTransitionThreshold * Missed a name change on cleanup * Add tests * fix comma for older xcode * Update xcode * Update xcode version * Change resource class * Update simulator --------- Co-authored-by: Pete Schwamb <pete@schwamb.net>
Configuration menu - View commit details
-
Copy full SHA for 8093b57 - Browse repository at this point
Copy the full SHA 8093b57View commit details
Commits on Nov 18, 2025
-
Configuration menu - View commit details
-
Copy full SHA for 13cb4b4 - Browse repository at this point
Copy the full SHA 13cb4b4View commit details
Commits on Mar 11, 2026
-
Configuration menu - View commit details
-
Copy full SHA for 9e1ff9b - Browse repository at this point
Copy the full SHA 9e1ff9bView commit details -
Configuration menu - View commit details
-
Copy full SHA for 07afc01 - Browse repository at this point
Copy the full SHA 07afc01View commit details
Commits on Mar 25, 2026
-
Configuration menu - View commit details
-
Copy full SHA for 1816673 - Browse repository at this point
Copy the full SHA 1816673View commit details -
Merge pull request #27 from tidepool-org/pd/NEMO-254/meal_bolus_no_is…
…f_test Pd/nemo 254/meal bolus no isf test
Configuration menu - View commit details
-
Copy full SHA for bd1a879 - Browse repository at this point
Copy the full SHA bd1a879View commit details
Commits on May 21, 2026
-
Make decayEffect a continuous function of sample timestamp (#33)
* Make decayEffect a continuous function of sample timestamp Reformulates decayEffect using a closed-form quadratic in time-since-sample rather than accumulating step-by-step from the floored simulation boundary. This makes the effect value at any future absolute timestamp independent of which delta-sized simulation bucket the sample's startDate falls into. For samples aligned to delta boundaries the two formulations are mathematically identical. For unaligned samples (the common case with real CGM streams) the new formulation removes a small discontinuity that the old code exhibited at bucket boundaries. Adds LoopMathTests covering continuity across a delta boundary. Existing fixture-calibrated tests are re-pinned to the new values; per-prediction drift is on the order of 0.1 mg/dL. Ports the LoopMath change from LoopKit/LoopKit#556 by Moti Nisenson-Ken to the LoopAlgorithm package, where decayEffect now lives. * Space to kick off tests --------- Co-authored-by: Pete Schwamb <pete@pete-mbp-eth.maplect.net>
Configuration menu - View commit details
-
Copy full SHA for b05f72b - Browse repository at this point
Copy the full SHA b05f72bView commit details -
Add unit tests for StandardRetrospectiveCorrection (#32)
StandardRetrospectiveCorrection (the P-only retrospective correction controller) had no dedicated unit tests — its behavior was only covered transitively via the higher-level LoopAlgorithm tests. Adds 9 tests covering: - Recency gating: stale / nil / empty discrepancy lists clear the correction and return empty. - Total correction effect equals the latest (most-recent) discrepancy magnitude (Standard is P-only on .last). - Positive / negative discrepancies project glucose forward in the expected direction, with the last sample ≈ starting + discrepancy. - The first effect sample equals the starting glucose value at the starting date (correction hasn't yet had time to apply). - Only the latest discrepancy contributes — older entries are ignored (the key behavioral difference vs IntegralRC, which integrates them). - Short discrepancies are clamped to retrospectiveCorrectionGroupingInterval to prevent over-amplified velocity from very short windows. These tests will serve as a backstop while the active-insulin / EGP decomposition work modifies the glucose-effect computation upstream of the RC discrepancy calculation. Co-authored-by: LoopKit Developer <dev@loopkit.org>
Configuration menu - View commit details
-
Copy full SHA for a1d0e57 - Browse repository at this point
Copy the full SHA a1d0e57View commit details -
Faster filterDateRange via binary search (#31)
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.
Configuration menu - View commit details
-
Copy full SHA for 729e508 - Browse repository at this point
Copy the full SHA 729e508View commit details -
Add PrecomputedInsulinInput for efficient multi-step prediction sweep…
…s + parallelize glucose-effects (#29) * Add PrecomputedInsulinInput for efficient multi-step prediction sweeps Introduces PrecomputedInsulinInput and a new generatePrediction overload that accepts pre-annotated dose data, enabling significant speedups for historical back-testing / evaluation sweeps. The key bottleneck in a dense prediction sweep is doses.annotated(with: basal), which is O(doses × basalSegments) and was called from scratch at every step. Between adjacent 5-min steps the dose list changes only at its edges; the annotation of every dose in the middle is identical. Changes: - Sources/LoopAlgorithm/Insulin/PrecomputedInsulinInput.swift (new) PrecomputedInsulinInput struct holding pre-annotated doses and an optional pre-built insulinEffects timeline. Includes a convenience .build() factory. - Sources/LoopAlgorithm/LoopAlgorithm.swift New generatePrediction(start:glucoseHistory:precomputedInsulin:carbEntries: sensitivity:carbRatio:...) overload. Skips annotated(with:) entirely; optionally skips glucoseEffects() when insulinEffects is pre-supplied. - Sources/LoopAlgorithm/Glucose/GlucoseEffect.swift Add Sendable conformance (struct with value-type fields, safe). - Tests/LoopAlgorithmTests/PrecomputedInsulinInputTests.swift (new) 3 tests verifying the new overload produces output matching the standard path (bit-identical for annotation-only, count-identical + clinically equivalent for pre-built effects). Expected speedup for a 7-day sweep at 5-min step (~2016 calls): annotation bypass alone: ~40-60% wall-clock reduction + effects cache (fixed ISF): additional ~20-30% * Refactor PrecomputedInsulinInput for explicit ISF-sweep pattern Split the API into two explicit steps so ISF sweeps pay annotation cost exactly once across all multipliers: annotate(doses:basal:) → ISF-independent, build once .withEffects(sensitivity:from:to:) → ISF-dependent, once per multiplier Correct ISF sweep pattern: let base = PrecomputedInsulinInput.annotate(doses: doses, basal: basal) for multiplier in isfMultipliers { let input = base.withEffects(sensitivity: scale(sensitivity, by: multiplier)) // run ~2016 steps with input — no annotation, no per-step glucoseEffects } Cost breakdown for 10-multiplier × 7-day sweep (n≈2016 steps each): Before: annotated(with:) + glucoseEffects() called 20160× each After: annotated(with:) called 1×, glucoseEffects() called 10× Also adds testISFSweepPattern verifying bit-identical output across multipliers [0.7, 0.8, ..., 1.3] vs the standard generatePrediction path. * Add sliced(from:to:) for per-step dose window slicing Enables EvalCore to slice pre-annotated doses to the per-step lookback window without re-annotating. Uses binary search on startDate + linear filter on endDate (arrays are ~100-200 entries, linear endDate scan is negligible). Also cleans up the unused private partition helper (now only used by sliced). * Expose dose-recommendation internals as public API Downstream callers (LoopEval bench engine) need to compute dose recommendations from a forecast without going through the full run() API, which re-computes insulin effects. Making insulinCorrection, recommendTempBasal, and recommendAutomaticDose public lets them do that efficiently using already-computed predictions. Enables delivery-based ODR/UDR metrics in LoopEval that compare the actual insulin Loop would deliver across two configurations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Parallelize glucose-effects accumulation in InsulinMath Replace the sequential reduce loop with DispatchQueue.concurrentPerform over per-step increments, then a final cumsum. Per-step contributions are independent until the final summation, so this scales with available cores. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: carry forward momentumVelocityMaximum param from eval/precomputed-insulin-effects --------- Co-authored-by: Bot <bot@macmini.maplect.net> Co-authored-by: LoopKit Developer <dev@loopkit.org> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Configuration menu - View commit details
-
Copy full SHA for 6e4e315 - Browse repository at this point
Copy the full SHA 6e4e315View commit details -
Merge pull request #6 from tidepool-org/main
Bring in Tidepool LoopAlgorithm updates
Configuration menu - View commit details
-
Copy full SHA for 1ca8566 - Browse repository at this point
Copy the full SHA 1ca8566View commit details
Commits on May 24, 2026
-
Assert filterDateRange input is sorted ascending
The binary-search filterDateRange overload assumes its collection is sorted ascending by startDate, but returns silently-wrong results otherwise. Add a debug-only assert enforcing that contract (compiled out of release builds, so no runtime cost). This immediately surfaced an existing violation: testGlucoseEffectFromHistory built a `basal` schedule with segments out of order (and one with endDate before startDate, plus overlaps). Replace it with a well-formed sorted, contiguous, non-overlapping schedule, and regenerate the expected-effect fixture to match the corrected schedule.
Configuration menu - View commit details
-
Copy full SHA for 8faf496 - Browse repository at this point
Copy the full SHA 8faf496View commit details
Commits on May 25, 2026
-
Merge pull request #7 from LoopKit/harden/filterdaterange-sorted-assert
Assert filterDateRange input is sorted ascending
Configuration menu - View commit details
-
Copy full SHA for 2f5c630 - Browse repository at this point
Copy the full SHA 2f5c630View commit details
Commits on Jul 15, 2026
-
Fix delta-scale IOB ripple for basal segments longer than delta (#35)
continuousDeliveryInsulinOnBoard quantized its integration bound to the delta grid (floor((time + delay) / delta) * delta), so a whole chunk was added discontinuously each time `time` crossed a delta boundary. This produced a delta-scale ripple in insulinOnBoard for any basal segment longer than one delta -- i.e. essentially every real temp basal / suspend (median ~10 min in real dose histories). Integrate the delivered fraction up to `time`, weighting a partial final chunk, and sample each chunk's remaining-effect at its midpoint. IOB is now continuous and matches a finely-subdivided equivalent delivery. Scoped to the insulinOnBoard path; glucoseEffect (and therefore dosing) is unchanged. Adds a regression test. All package tests pass.
Configuration menu - View commit details
-
Copy full SHA for aeffea8 - Browse repository at this point
Copy the full SHA aeffea8View commit details
Commits on Jul 27, 2026
-
Bound IntegralRC correction rate to a settings-free physiological cei…
…ling (#37) The port from LoopKit to LoopAlgorithm dropped IntegralRetrospectiveCorrection's integral clamp — a safety bound on the wound-up integral term. Rather than restore the original clamp (which scaled the bound by ISF x basal and the target range), this bounds the RC correction RATE to a physiological ceiling (mg/dL/min), independent of user settings. Rationale: RC forecasts unmodeled physiology, whose plausible velocity does not depend on a person's insulin needs or target range. The original clamp's implied "plausible unmodeled velocity" varied ~11x across settings (0.55-4.9 mg/dL/min for ISF x basal of 18-160) - trusting the same real carb rise for a high-need user while clamping it for a low-need one. The integral is already self-limiting (leaky integrator; converges to ~1.087 x discrepancy), so the clamp is a rare-event backstop for large or spurious discrepancies, and a fixed physiological rate ceiling is the right shape for that. Default 4 mg/dL/min (top of plausible sustained unmodeled velocity). On real IRC data (two datasets) this reproduces the deployed clamp's behavior - both near-inert in normal operation - without the settings coupling. Configurable via IntegralRetrospectiveCorrection(effectDuration:maxCorrectionVelocity:); nil disables. Tests: correction rate clamped to +/- the ceiling on a large windup, symmetric for negative discrepancies, and inert when the rate is below the ceiling. Co-authored-by: LoopKit Developer <dev@loopkit.org>
Configuration menu - View commit details
-
Copy full SHA for 925e672 - Browse repository at this point
Copy the full SHA 925e672View commit details -
Configuration menu - View commit details
-
Copy full SHA for 7d016fb - Browse repository at this point
Copy the full SHA 7d016fbView commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff 84a099f...7d016fb