1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
use Float;
/// Sequential (recurrent) scan — the correctness baseline that every
/// other scan in the crate is tested against.
///
/// Evaluates the first-order linear recurrence
/// `h_t = a_t * h_{t-1} + b_t`, with `h_{-1} = h0`
/// left-to-right, returning the full state sequence `[h_0, ..., h_{n-1}]`.
///
/// - `a`: per-step decay / transition coefficients
/// - `b`: per-step inputs (must be the same length as `a`)
/// - `h0`: the initial state fed in before the first step
///
/// Setting `a_t = 1` everywhere collapses this into a plain prefix sum
/// (running total) of `b` — the easiest case to eyeball, which is exactly
/// what the test below checks.
///
/// Cost: O(n), one multiply-add per element. Inherently sequential: each
/// step needs the previous `h`, so it can't be parallelized as-is.
/// `chunked_scan` exists to break that dependency for large inputs; this
/// function is the reference it must match. Generic over the float type
/// `T` (f32 for speed, f64 for numerical testing).
///
/// # Example
///
/// ```
/// use zilla_muf::scan::sequential_scan;
/// // a = 1 everywhere → plain prefix sum of b
/// let h = sequential_scan(&[1.0, 1.0, 1.0], &[1.0, 2.0, 3.0], 0.0);
/// assert_eq!(h, vec![1.0, 3.0, 6.0]);
/// ```