use crate::error::{LinalgError, LinalgResult};
#[derive(Debug, Clone)]
pub struct FlatToeplitz {
pub first_row: Vec<f64>,
pub first_col: Vec<f64>,
pub n: usize,
}
impl FlatToeplitz {
pub fn new(first_row: Vec<f64>, first_col: Vec<f64>) -> LinalgResult<Self> {
let n = first_row.len();
if first_col.len() != n {
return Err(LinalgError::ShapeError(format!(
"first_row length {} ≠ first_col length {}",
n,
first_col.len()
)));
}
if n == 0 {
return Err(LinalgError::DimensionError("n must be > 0".into()));
}
if (first_row[0] - first_col[0]).abs() > 1e-14 * first_row[0].abs().max(1.0) {
return Err(LinalgError::ValueError(
"first_row[0] and first_col[0] must be equal".into(),
));
}
Ok(Self {
first_row,
first_col,
n,
})
}
pub fn get(&self, i: usize, j: usize) -> LinalgResult<f64> {
if i >= self.n || j >= self.n {
return Err(LinalgError::IndexError(format!(
"({},{}) out of bounds for {}×{}",
i, j, self.n, self.n
)));
}
Ok(if i <= j {
self.first_row[j - i]
} else {
self.first_col[i - j]
})
}
pub fn to_dense(&self) -> Vec<f64> {
let n = self.n;
let mut a = vec![0.0_f64; n * n];
for i in 0..n {
for j in 0..n {
a[i * n + j] = if i <= j {
self.first_row[j - i]
} else {
self.first_col[i - j]
};
}
}
a
}
}
#[derive(Debug, Clone)]
pub struct FlatCirculant {
pub first_row: Vec<f64>,
pub n: usize,
}
impl FlatCirculant {
pub fn new(first_row: Vec<f64>) -> LinalgResult<Self> {
let n = first_row.len();
if n == 0 {
return Err(LinalgError::DimensionError("n must be > 0".into()));
}
Ok(Self { first_row, n })
}
pub fn get(&self, i: usize, j: usize) -> LinalgResult<f64> {
if i >= self.n || j >= self.n {
return Err(LinalgError::IndexError(format!(
"({},{}) out of bounds for {}×{}",
i, j, self.n, self.n
)));
}
let idx = (i + self.n - j) % self.n;
Ok(self.first_row[idx])
}
pub fn to_dense(&self) -> Vec<f64> {
let n = self.n;
let mut a = vec![0.0_f64; n * n];
for i in 0..n {
for j in 0..n {
let idx = (i + n - j) % n;
a[i * n + j] = self.first_row[idx];
}
}
a
}
}
#[derive(Debug, Clone)]
pub struct FlatHankel {
pub first_row: Vec<f64>,
pub last_col: Vec<f64>,
pub n: usize,
}
impl FlatHankel {
pub fn new(first_row: Vec<f64>, last_col: Vec<f64>) -> LinalgResult<Self> {
let n = first_row.len();
if last_col.len() != n {
return Err(LinalgError::ShapeError(format!(
"first_row length {} ≠ last_col length {}",
n,
last_col.len()
)));
}
if n == 0 {
return Err(LinalgError::DimensionError("n must be > 0".into()));
}
if (first_row[n - 1] - last_col[0]).abs() > 1e-14 * first_row[n - 1].abs().max(1.0) {
return Err(LinalgError::ValueError(
"first_row[n-1] and last_col[0] must be equal (corner element)".into(),
));
}
Ok(Self {
first_row,
last_col,
n,
})
}
pub fn get(&self, i: usize, j: usize) -> LinalgResult<f64> {
if i >= self.n || j >= self.n {
return Err(LinalgError::IndexError(format!(
"({},{}) out of bounds for {}×{}",
i, j, self.n, self.n
)));
}
let k = i + j;
Ok(if k < self.n {
self.first_row[k]
} else {
self.last_col[k - (self.n - 1)]
})
}
pub fn to_dense(&self) -> Vec<f64> {
let n = self.n;
let mut a = vec![0.0_f64; n * n];
for i in 0..n {
for j in 0..n {
let k = i + j;
a[i * n + j] = if k < n {
self.first_row[k]
} else {
self.last_col[k - (n - 1)]
};
}
}
a
}
}