#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::vec::Vec;
use num_traits::Float;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum BoundaryPolicy {
#[default]
Extend,
Reflect,
Zero,
NoBoundary,
}
pub fn apply_boundary_policy<T: Float>(
x: &[T],
y: &[T],
window_size: usize,
policy: BoundaryPolicy,
) -> (Vec<T>, Vec<T>) {
let n = x.len();
if policy == BoundaryPolicy::NoBoundary {
return (x.to_vec(), y.to_vec());
}
let pad_len = (window_size / 2).min(n - 1);
if pad_len == 0 {
return (x.to_vec(), y.to_vec());
}
let total_len = n + 2 * pad_len;
let mut px = Vec::with_capacity(total_len);
let mut py = Vec::with_capacity(total_len);
match policy {
BoundaryPolicy::Extend => {
let x0 = x[0];
let y0 = y[0];
let dx = x[1] - x[0];
for i in (1..=pad_len).rev() {
px.push(x0 - T::from(i).unwrap() * dx);
py.push(y0);
}
}
BoundaryPolicy::Reflect => {
let x0 = x[0];
for i in (1..=pad_len).rev() {
px.push(x0 - (x[i] - x0));
py.push(y[i]);
}
}
BoundaryPolicy::Zero => {
let x0 = x[0];
let dx = x[1] - x[0];
for i in (1..=pad_len).rev() {
px.push(x0 - T::from(i).unwrap() * dx);
py.push(T::zero());
}
}
BoundaryPolicy::NoBoundary => unreachable!(),
}
px.extend_from_slice(x);
py.extend_from_slice(y);
match policy {
BoundaryPolicy::Extend => {
let xn = x[n - 1];
let yn = y[n - 1];
let dx = x[n - 1] - x[n - 2];
for i in 1..=pad_len {
px.push(xn + T::from(i).unwrap() * dx);
py.push(yn);
}
}
BoundaryPolicy::Reflect => {
let xn = x[n - 1];
for i in 1..=pad_len {
px.push(xn + (xn - x[n - 1 - i]));
py.push(y[n - 1 - i]);
}
}
BoundaryPolicy::Zero => {
let xn = x[n - 1];
let dx = x[n - 1] - x[n - 2];
for i in 1..=pad_len {
px.push(xn + T::from(i).unwrap() * dx);
py.push(T::zero());
}
}
BoundaryPolicy::NoBoundary => unreachable!(),
}
(px, py)
}