use std::ops::Range;
#[derive(Clone, Copy, Debug)]
pub enum Transpose {
NoTranspose,
Transpose,
}
#[derive(Clone, Copy, Debug)]
pub enum Triangular {
Upper,
Lower,
}
#[derive(Clone, Copy, Debug)]
pub struct VecRef<'a, T> {
buffer: &'a [T],
}
#[derive(Debug)]
pub struct VecMut<'a, T> {
buffer: &'a mut [T],
}
#[derive(Clone, Copy, Debug)]
pub struct MatRef<'a, T> {
buffer: &'a [T],
dimension: (usize, usize),
}
#[derive(Debug)]
pub struct MatMut<'a, T> {
buffer: &'a mut [T],
dimension: (usize, usize),
}
impl<'a, T> VecRef<'a, T> {
pub fn new(buffer: &'a [T]) -> Self {
Self { buffer }
}
pub fn length(&self) -> usize {
self.buffer.len()
}
pub fn as_slice(&self) -> &[T] {
self.buffer
}
pub fn slice(&self, range: Range<usize>) -> &[T] {
&self.buffer[range.start..range.end]
}
pub fn has_equal_length(&self, length: usize) -> bool {
self.buffer.len() == length
}
}
impl<'a, T> VecMut<'a, T> {
pub fn new(buffer: &'a mut [T]) -> Self {
Self { buffer }
}
pub fn length(&self) -> usize {
self.buffer.len()
}
pub fn as_slice(&self) -> &[T] {
self.buffer
}
pub fn slice(&self, range: Range<usize>) -> &[T] {
&self.buffer[range.start..range.end]
}
pub fn slice_mut(&mut self, range: Range<usize>) -> &mut [T] {
&mut self.buffer[range.start..range.end]
}
pub fn as_slice_mut(&mut self) -> &mut [T] {
self.buffer
}
pub fn has_equal_length(&self, length: usize) -> bool {
self.buffer.len() == length
}
pub fn reborrow(&mut self) -> VecMut<'_, T> {
VecMut::new(self.as_slice_mut())
}
}
impl<'a, T> MatRef<'a, T> {
pub fn new(buffer: &'a [T], dimension: (usize, usize)) -> Self {
let i = dimension.0;
let j = dimension.1;
let buffer_length = buffer.len();
let matrix_length = i * j;
assert_eq!(
matrix_length,
buffer_length,
"matrix has invalid dimensions: buffer length is {buffer_length}, \
but dimensions are {i} x {j} = {matrix_length}",
);
Self { buffer, dimension }
}
pub fn as_slice(&self) -> &[T] {
self.buffer
}
pub fn dimension(&self) -> (usize, usize) {
self.dimension
}
pub fn n_rows(&self) -> usize {
self.dimension.0
}
pub fn n_cols(&self) -> usize {
self.dimension.1
}
pub fn col(&self, j: usize) -> VecRef<'_, T> {
let n_rows = self.n_rows();
let beg_idx = n_rows * j;
let end_idx = n_rows * (j + 1);
let slice = &self.buffer[beg_idx..end_idx];
VecRef::new(slice)
}
pub fn col_panel(&self, cols: Range<usize>) -> MatRef<'_, T> {
debug_assert!(
cols.start < cols.end,
"start of col range must be < end of col range"
);
debug_assert!(
cols.end <= self.dimension.1,
"end of col range must be <= number cols in Self"
);
let n_rows = self.n_rows();
let n_cols = cols.end - cols.start;
let beg_idx = n_rows * cols.start;
let end_idx = n_rows * cols.end;
MatRef::new(
&self.buffer[beg_idx..end_idx],
(n_rows, n_cols)
)
}
pub fn col_panels(&self, nc: usize) -> impl DoubleEndedIterator<Item = (Range<usize>, MatRef<'_, T>)> {
debug_assert!(nc > 0, "nc must be > 0");
let n_cols = self.n_cols();
(0..n_cols).step_by(nc).map(move |j0| {
let j1 = usize::min(j0 + nc, n_cols);
(Range {start: j0, end: j1}, self.col_panel(j0..j1))
})
}
pub fn has_len_equal_to_n_cols(&self, length: usize) -> bool {
self.dimension.1 == length
}
pub fn has_len_equal_to_n_rows(&self, length: usize) -> bool {
self.dimension.0 == length
}
}
impl<'a, T> MatMut<'a, T> {
pub fn new(buffer: &'a mut [T], dimension: (usize, usize)) -> Self {
let i = dimension.0;
let j = dimension.1;
let buffer_length = buffer.len();
let matrix_length = i * j;
assert_eq!(
matrix_length,
buffer_length,
"matrix has invalid dimensions: buffer length is {buffer_length}, \
but dimensions are {i} x {j} = {matrix_length}"
);
Self { buffer, dimension }
}
pub fn as_slice(&self) -> &[T] {
self.buffer
}
pub fn as_slice_mut(&mut self) -> &mut [T] {
self.buffer
}
pub fn dimension(&self) -> (usize, usize) {
self.dimension
}
pub fn n_rows(&self) -> usize {
self.dimension.0
}
pub fn n_cols(&self) -> usize {
self.dimension.1
}
pub fn col(&self, j: usize) -> VecRef<'_, T> {
let n_rows = self.n_rows();
let beg_idx = n_rows * j;
let end_idx = n_rows * (j + 1);
let slice = &self.buffer[beg_idx..end_idx];
VecRef::new(slice)
}
pub fn col_mut(&mut self, j: usize) -> VecMut<'_, T> {
let n_rows = self.n_rows();
let beg_idx = n_rows * j;
let end_idx = n_rows * (j + 1);
let slice = &mut self.buffer[beg_idx..end_idx];
VecMut::new(slice)
}
pub fn col_panel(&self, cols: Range<usize>) -> MatRef<'_, T> {
debug_assert!(
cols.start < cols.end,
"start of col range must be < end of col range"
);
debug_assert!(
cols.end <= self.dimension.1,
"end of col range must be <= number cols in Self"
);
let n_rows = self.n_rows();
let n_cols = cols.end - cols.start;
let beg_idx = n_rows * cols.start;
let end_idx = n_rows * cols.end;
MatRef::new(
&self.buffer[beg_idx..end_idx],
(n_rows, n_cols)
)
}
pub fn col_panel_mut(&mut self, cols: Range<usize>) -> MatMut<'_, T> {
debug_assert!(
cols.start < cols.end,
"start of col range must be < end of col range"
);
debug_assert!(
cols.end <= self.dimension.1,
"end of col range must be <= number cols in Self"
);
let n_rows = self.n_rows();
let n_cols = cols.end - cols.start;
let beg_idx = n_rows * cols.start;
let end_idx = n_rows * cols.end;
MatMut::new(
&mut self.buffer[beg_idx..end_idx],
(n_rows, n_cols)
)
}
pub fn col_panels(&self, nc: usize) -> impl DoubleEndedIterator<Item = (Range<usize>, MatRef<'_, T>)> {
debug_assert!(nc > 0, "nc must be > 0");
let n_cols = self.n_cols();
(0..n_cols).step_by(nc).map(move |j0| {
let j1 = usize::min(j0 + nc, n_cols);
(Range {start: j0, end: j1}, self.col_panel(j0..j1))
})
}
pub fn has_len_equal_to_n_cols(&self, length: usize) -> bool {
self.dimension.1 == length
}
pub fn has_len_equal_to_n_rows(&self, length: usize) -> bool {
self.dimension.0 == length
}
pub fn reborrow(&mut self) -> MatMut<'_, T> {
let (n_rows, n_cols) = self.dimension();
MatMut::new(self.as_slice_mut(), (n_rows, n_cols))
}
}
#[macro_export]
macro_rules! assert_length_eq {
($x:expr, $y:expr) => {
assert!(
$x.has_equal_length($y.length()),
"number of elements must be equal"
);
};
}
#[macro_export]
macro_rules! assert_length_eq_n_cols {
($a:expr, $x:expr) => {
assert!(
$a.has_len_equal_to_n_cols($x.length()),
"number of cols in a does not match length of x"
);
};
}
#[macro_export]
macro_rules! assert_length_eq_n_rows {
($a:expr, $x:expr) => {
assert!(
$a.has_len_equal_to_n_rows($x.length()),
"number of rows in a does not match length of x"
);
};
}