use crate::numeric::mul14;
pub(crate) fn durbin(
correlation: &[i32],
coefficients: &mut [i32],
parcor: &mut [i32],
scratch: &mut [i32],
) -> bool {
let order = coefficients.len();
if order == 0 {
return false;
}
if correlation[0] <= 0_i32 {
return false;
}
let mut alpha = correlation[0];
let one = 16384;
for i in 0..order {
let mut sum = 0_i32;
for j in 0..i {
sum = sum.wrapping_add(coefficients[j].wrapping_mul(correlation[i - j]));
}
sum = sum.wrapping_shr(14);
if alpha == 0_i32 {
return false;
}
let k = correlation[i + 1]
.wrapping_sub(sum)
.wrapping_shl(14)
.wrapping_div(alpha);
parcor[i] = k;
if k.wrapping_abs() >= one {
return false;
}
scratch[i] = k;
for j in 0..i {
scratch[j] = coefficients[j]
.wrapping_shl(14)
.wrapping_sub(k.wrapping_mul(coefficients[i - j - 1]))
.wrapping_shr(14);
}
coefficients[..=i].copy_from_slice(&scratch[..=i]);
alpha = mul14(alpha, one.wrapping_sub(mul14(k, k)));
}
true
}
pub(crate) fn parcor_to_areas(parcor: &[i32], areas: &mut [i32]) -> Option<u32> {
let one = 16384;
let mut area = one;
let mut scale = 0;
for (i, &k) in parcor.iter().enumerate() {
let mut sum = k.wrapping_add(one);
let numerator = mul14(one.wrapping_sub(k), area);
while numerator.wrapping_abs() > sum.wrapping_abs() {
for a in &mut areas[..i] {
*a = a.wrapping_shr(1);
if *a == 0_i32 {
*a = 1;
}
}
sum = sum.wrapping_shl(1);
scale += 1;
if sum == 0_i32 || scale >= 32 {
return None;
}
}
if sum == 0_i32 {
return None;
}
area = numerator.wrapping_shl(14).wrapping_div(sum);
if area == 0_i32 {
area = 1;
}
areas[i] = area;
}
Some(scale)
}
pub(crate) fn areas_to_parcor(areas: &[i32], parcor: &mut [i32], scale: u32) -> bool {
let mut previous = 16384_i32.wrapping_shr(scale);
for (i, &area) in areas.iter().enumerate() {
let denominator = area.wrapping_add(previous);
if denominator == 0_i32 {
return false;
}
parcor[i] = previous
.wrapping_sub(area)
.wrapping_shl(14)
.wrapping_div(denominator);
previous = area;
}
true
}
pub(crate) fn parcor_to_pef(
parcor: &[i32],
coefficients: &mut [i32],
scratch: &mut [i32],
scale: u32,
) {
for (i, &k) in parcor.iter().enumerate() {
scratch[i] = k.wrapping_shl(scale);
for j in 0..i {
scratch[j] = coefficients[j]
.wrapping_sub(k.wrapping_mul(coefficients[i - j - 1].wrapping_shr(scale)));
}
coefficients[..=i].copy_from_slice(&scratch[..=i]);
}
for coefficient in &mut coefficients[..parcor.len()] {
*coefficient = coefficient.wrapping_shr(scale);
}
}