Conversation
Replace seq-expression + ref-cell implementation of movingWindowFn with a direct imperative loop that builds into a ResizeArray<float> and returns float[]. Likewise convert expandingWindowFn from the Seq.scan |> Seq.skip 1 |> Seq.map chain to an equivalent imperative loop. Benefits: - movingWindowFn: eliminates the IEnumerator seq-expression state machine, 4 heap-allocated ref cells (r, i, isInit, state), and the Array.ofSeq materialisation call at each use site. - expandingWindowFn: eliminates 3 chained lazy-sequence state machines (Scan, Skip 1, Map) and the Array.ofSeq call at each use site. - Remove unused internal function expandingMinMaxHelper (dead code; actual expanding-min/max implementations are inline in Stats directly). All 685 existing tests pass without modification. Co-authored-by: Copilot <[email protected]>
9 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 This PR was created by Repo Assist, an automated AI assistant.
Summary
Two internal helpers in
StatsInternal(movingWindowFnandexpandingWindowFn) had unnecessary overhead from F# sequence expressions andrefcells. This PR replaces them with direct imperative loops that build into aResizeArray(float)and returnfloat[]directly.Changes
movingWindowFn(moving-window statistics:movingMean,movingStdDev,movingVar, etc.)Before: Used
seq { ... yield ... }with four heap-allocatedrefcells (r,i,isInit,state). Each caller also called>> Array.ofSeqto materialise the lazy sequence.After: Uses a plain
whileloop withmutablestack-level locals, accumulating directly into aResizeArray(float)and returning.ToArray(). Norefallocations; noseqstate machine; noArray.ofSeqat the call site.expandingWindowFn(expanding-window statistics:expandingMean,expandingStdDev, etc.)Before:
Seq.scan fupdate initState |> Seq.skip 1 |> Seq.map ftransf— three chained lazy-sequence state machines, plus>> Array.ofSeqat the caller.After: A single
for x in source doloop with amutable state, accumulating intoResizeArray(float). No lazy sequences.Dead code removal
expandingMinMaxHelperwas defined internally but never called anywhere — the actualexpandingMin/expandingMaximplementations are self-contained. It has been removed.Why this matters
These helpers are in the hot path of every
Stats.moving*andStats.expanding*call. For a series with N elements and window size W:movingWindowFncreated ≥ 4 heap objects per call plus oneseqstate machine and oneIEnumeratorwrapper; the new version has zero extra heap objects (theResizeArrayis the only allocation, as before withArray.ofSeq).expandingWindowFncreated 3 chained lazy-sequence state machines; the new version has none.The change is particularly valuable for long series or when multiple moving statistics are composed in a pipeline.
Test status
All existing tests pass without modification. The semantics are unchanged — the output arrays are identical to the previous implementation.