1use crate::{check_input, Error, Result};
9
10#[derive(Debug, Clone)]
12pub struct Levinson {
13 pub pacf: Vec<f64>,
15 pub sigma2: Vec<f64>,
17 pub phi_last: Vec<f64>,
19}
20
21pub fn levinson(r: &[f64]) -> Result<Levinson> {
23 if r.len() < 2 {
24 return Err(Error::TooShort {
25 n: r.len(),
26 needed: 2,
27 });
28 }
29 let k_max = r.len() - 1;
30 let mut phi: Vec<f64> = Vec::with_capacity(k_max);
31 let mut pacf = Vec::with_capacity(k_max);
32 let mut sigma2 = Vec::with_capacity(k_max + 1);
33 let mut sig = r[0];
34 if sig <= 0.0 {
35 return Err(Error::Singular);
36 }
37 sigma2.push(sig);
38 for k in 1..=k_max {
39 let mut num = r[k];
40 for j in 1..k {
41 num -= phi[j - 1] * r[k - j];
42 }
43 let kk = num / sig;
44 if !kk.is_finite() {
45 return Err(Error::Singular);
46 }
47 let prev = phi.clone();
48 for j in 1..k {
49 phi[j - 1] = prev[j - 1] - kk * prev[k - j - 1];
50 }
51 phi.push(kk);
52 sig *= 1.0 - kk * kk;
53 if sig <= 0.0 {
54 sig = f64::EPSILON * r[0];
56 }
57 pacf.push(kk);
58 sigma2.push(sig);
59 }
60 Ok(Levinson {
61 pacf,
62 sigma2,
63 phi_last: phi,
64 })
65}
66
67pub fn levinson_from_series(x: &[f64], k_max: usize) -> Result<Levinson> {
69 check_input(x, k_max + 2)?;
70 let r = crate::acov::autocovariance(x, k_max)?;
71 levinson(&r)
72}
73
74pub fn burg_from_series(x: &[f64], k_max: usize) -> Result<Levinson> {
80 check_input(x, k_max + 2)?;
81 let n = x.len();
82 let mean = x.iter().sum::<f64>() / n as f64;
83 let xc: Vec<f64> = x.iter().map(|v| v - mean).collect();
84 let mut sig = xc.iter().map(|v| v * v).sum::<f64>() / n as f64;
85 if sig <= 0.0 {
86 return Err(Error::Singular);
87 }
88 let r0 = sig;
89 let mut f = xc.clone();
90 let mut b = xc;
91 let mut phi: Vec<f64> = Vec::with_capacity(k_max);
92 let mut pacf = Vec::with_capacity(k_max);
93 let mut sigma2 = Vec::with_capacity(k_max + 1);
94 sigma2.push(sig);
95 for k in 1..=k_max {
96 let mut num = 0.0;
97 let mut den = 0.0;
98 for t in k..n {
99 num += f[t] * b[t - 1];
100 den += f[t] * f[t] + b[t - 1] * b[t - 1];
101 }
102 if den <= 0.0 || !den.is_finite() {
103 return Err(Error::Singular);
104 }
105 let kk = 2.0 * num / den;
106 for t in (k..n).rev() {
109 let fo = f[t];
110 let bo = b[t - 1];
111 f[t] = fo - kk * bo;
112 b[t] = bo - kk * fo;
113 }
114 let prev = phi.clone();
115 for j in 1..k {
116 phi[j - 1] = prev[j - 1] - kk * prev[k - j - 1];
117 }
118 phi.push(kk);
119 sig *= 1.0 - kk * kk;
120 if sig <= 0.0 {
121 sig = f64::EPSILON * r0;
123 }
124 pacf.push(kk);
125 sigma2.push(sig);
126 }
127 Ok(Levinson {
128 pacf,
129 sigma2,
130 phi_last: phi,
131 })
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn ar1_exact_autocovariance_recovers_phi() {
140 let phi: f64 = 0.6;
142 let r: Vec<f64> = (0..6).map(|k| phi.powi(k) / (1.0 - phi * phi)).collect();
143 let l = levinson(&r).unwrap();
144 assert!((l.pacf[0] - phi).abs() < 1e-12);
145 for k in 1..5 {
146 assert!(l.pacf[k].abs() < 1e-10, "pacf[{k}] = {}", l.pacf[k]);
147 }
148 assert!((l.sigma2[1] - 1.0).abs() < 1e-10);
149 }
150}