use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::ptr;
use {Element, Matrix, Position, Size};
#[derive(Clone, Debug, PartialEq)]
pub struct Conventional<T: Element> {
pub rows: usize,
pub columns: usize,
pub values: Vec<T>,
}
macro_rules! new(
($rows:expr, $columns:expr, $values:expr) => (
Conventional {
rows: $rows,
columns: $columns,
values: $values,
}
);
);
mod convert;
mod decomposition;
mod operation;
size!(Conventional);
impl<T: Element> Conventional<T> {
pub fn new<S: Size>(size: S) -> Self {
let (rows, columns) = size.dimensions();
new!(rows, columns, vec![T::zero(); rows * columns])
}
pub fn from_slice<S: Size>(size: S, values: &[T]) -> Self {
let (rows, columns) = size.dimensions();
debug_assert_eq!(values.len(), rows * columns);
new!(rows, columns, values.to_vec())
}
pub fn from_vec<S: Size>(size: S, values: Vec<T>) -> Self {
let (rows, columns) = size.dimensions();
debug_assert_eq!(values.len(), rows * columns);
new!(rows, columns, values)
}
pub unsafe fn with_uninitialized<S: Size>(size: S) -> Self {
let (rows, columns) = size.dimensions();
new!(rows, columns, buffer!(rows * columns))
}
#[inline]
pub unsafe fn erase(&mut self) {
ptr::write_bytes(self.values.as_mut_ptr(), 0, self.values.len())
}
pub fn resize<S: Size>(&mut self, size: S) {
let (rows, columns) = size.dimensions();
if self.rows == rows {
if self.columns > columns {
self.values.truncate(rows * columns);
} else {
self.values
.extend(vec![T::zero(); rows * (columns - self.columns)]);
}
self.columns = columns;
} else {
let mut matrix = Conventional::zero(size);
let rows = min!(self.rows, rows);
let columns = min!(self.columns, columns);
for j in 0..columns {
for i in 0..rows {
matrix[(i, j)] = self[(i, j)];
}
}
*self = matrix;
}
}
}
impl<T: Element> Matrix for Conventional<T> {
type Element = T;
fn nonzeros(&self) -> usize {
self.values
.iter()
.fold(0, |sum, &value| if value.is_zero() { sum } else { sum + 1 })
}
#[inline]
fn zero<S: Size>(size: S) -> Self {
Conventional::new(size)
}
}
impl<T: Element, P: Position> Index<P> for Conventional<T> {
type Output = T;
#[inline(always)]
fn index(&self, index: P) -> &Self::Output {
let (i, j) = index.coordinates();
&self.values[j * self.rows + i]
}
}
impl<T: Element, P: Position> IndexMut<P> for Conventional<T> {
#[inline(always)]
fn index_mut(&mut self, index: P) -> &mut Self::Output {
let (i, j) = index.coordinates();
&mut self.values[j * self.rows + i]
}
}
impl<T: Element> Deref for Conventional<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &Self::Target {
self.values.deref()
}
}
impl<T: Element> DerefMut for Conventional<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.values.deref_mut()
}
}
#[cfg(test)]
mod tests {
use prelude::*;
#[test]
fn erase() {
let mut matrix = Conventional::from_vec(10, vec![42.0; 10 * 10]);
unsafe { matrix.erase() };
assert!(matrix.iter().all(|&value| value == 0.0));
}
#[test]
fn resize_fewer_columns() {
let mut matrix = Conventional::from_vec((2, 3), vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
matrix.resize((2, 2));
assert_eq!(
matrix,
Conventional::from_vec(
(2, 2),
matrix![
1.0, 2.0;
4.0, 5.0;
],
)
);
}
#[test]
fn resize_fewer_rows() {
let mut matrix = Conventional::from_vec((2, 3), vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
matrix.resize((1, 3));
assert_eq!(
matrix,
Conventional::from_vec(
(1, 3),
matrix![
1.0, 2.0, 3.0;
],
)
);
}
#[test]
fn resize_more_columns() {
let mut matrix = Conventional::from_vec((2, 3), vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
matrix.resize((2, 4));
assert_eq!(
matrix,
Conventional::from_vec(
(2, 4),
matrix![
1.0, 2.0, 3.0, 0.0;
4.0, 5.0, 6.0, 0.0;
],
)
);
}
#[test]
fn resize_more_rows() {
let mut matrix = Conventional::from_vec((2, 3), vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
matrix.resize((3, 3));
assert_eq!(
matrix,
Conventional::from_vec(
(3, 3),
matrix![
1.0, 2.0, 3.0;
4.0, 5.0, 6.0;
0.0, 0.0, 0.0;
],
)
);
}
#[test]
fn resize_more_columns_rows() {
let mut matrix = Conventional::from_vec((2, 3), vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
matrix.resize((3, 4));
assert_eq!(
matrix,
Conventional::from_vec(
(3, 4),
matrix![
1.0, 2.0, 3.0, 0.0;
4.0, 5.0, 6.0, 0.0;
0.0, 0.0, 0.0, 0.0;
],
)
);
}
#[test]
fn nonzeros() {
let matrix = Conventional::from_vec(2, vec![1.0, 2.0, 3.0, 0.0]);
assert_eq!(matrix.nonzeros(), 3);
}
}