use std::convert::From;
use libnum::{Zero, ToPrimitive, NumCast};
use error::{Error, ErrorKind};
use super::matrix::{DiagOffset, Matrix, MatrixSlice, MatrixSliceMut, BaseMatrix,
Row, RowMut, Column, ColumnMut};
use super::vector::Vector;
impl<T> From<Vec<T>> for Vector<T> {
fn from(vec: Vec<T>) -> Self {
Vector::new(vec)
}
}
impl<'a, T> From<&'a [T]> for Vector<T>
where T: Clone
{
fn from(slice: &'a [T]) -> Self {
Vector::new(slice.to_owned())
}
}
impl<T> From<Vector<T>> for Matrix<T> {
fn from(vector: Vector<T>) -> Self {
Matrix::new(vector.size(), 1, vector.into_vec())
}
}
macro_rules! impl_matrix_from {
($slice_type:ident) => {
impl<'a, T: Copy> From<$slice_type<'a, T>> for Matrix<T> {
fn from(slice: $slice_type<'a, T>) -> Self {
slice.row_iter().collect::<Matrix<T>>()
}
}
}
}
impl_matrix_from!(MatrixSlice);
impl_matrix_from!(MatrixSliceMut);
macro_rules! impl_diag_offset_from {
($signed_type:ty) => {
impl From<$signed_type> for DiagOffset {
fn from(int: $signed_type) -> Self {
if int.is_zero() {
DiagOffset::Main
} else if int.is_positive() {
DiagOffset::Above(int as usize)
} else {
DiagOffset::Below((-int) as usize)
}
}
}
}
}
impl_diag_offset_from!(i8);
impl_diag_offset_from!(i16);
impl_diag_offset_from!(i32);
impl_diag_offset_from!(i64);
impl_diag_offset_from!(isize);
impl<T: ToPrimitive> Matrix<T> {
pub fn try_into<U: NumCast>(self) -> Result<Matrix<U>, Error> {
let (m, n) = (self.rows(), self.cols());
let ref make_error = || {
Error::new(ErrorKind::ScalarConversionFailure,
"Failed to convert between scalar types.")
};
let converted_data = self.into_vec()
.into_iter()
.map(|x| U::from(x).ok_or_else(make_error))
.collect::<Result<Vec<_>, Error>>();
Ok(Matrix::<U>::new(m, n, try!(converted_data)))
}
}
macro_rules! impl_row_to_vector (
($t:ident) => (
impl<'a, T: Clone> From<$t<'a, T>> for Vector<T> {
fn from(row: $t<'a, T>) -> Self {
Vector::new(row.raw_slice())
}
}
);
);
impl_row_to_vector!(Row);
impl_row_to_vector!(RowMut);
macro_rules! impl_column_to_vector (
($t:ident) => (
impl<'a, T: Clone> From<$t<'a, T>> for Vector<T> {
fn from(column: $t<'a, T>) -> Self {
column.iter().cloned().collect::<Self>()
}
}
);
);
impl_column_to_vector!(Column);
impl_column_to_vector!(ColumnMut);
#[cfg(test)]
mod tests {
use matrix::{DiagOffset, Matrix, MatrixSlice, MatrixSliceMut,
BaseMatrix, BaseMatrixMut};
use vector::Vector;
#[test]
fn inner_product_as_matrix_multiplication() {
let u: Vector<f32> = vector![1., 2., 3.];
let v: Vector<f32> = vector![3., 4., 5.];
let dot_product = u.dot(&v);
let um: Matrix<f32> = u.into();
let vm: Matrix<f32> = v.into();
let matrix_product = um.transpose() * vm;
assert_eq!(dot_product, matrix_product.data()[0]);
}
#[test]
fn matrix_from_slice() {
let mut a = Matrix::new(3, 3, vec![2.0; 9]);
{
let b = MatrixSlice::from_matrix(&a, [1, 1], 2, 2);
let c = Matrix::from(b);
assert_eq!(c.rows(), 2);
assert_eq!(c.cols(), 2);
}
let d = MatrixSliceMut::from_matrix(&mut a, [1, 1], 2, 2);
let e = Matrix::from(d);
assert_eq!(e.rows(), 2);
assert_eq!(e.cols(), 2);
}
#[test]
fn diag_offset_from_int() {
let a: DiagOffset = 3.into();
assert_eq!(a, DiagOffset::Above(3));
let a: DiagOffset = (-3).into();
assert_eq!(a, DiagOffset::Below(3));
let a: DiagOffset = 0.into();
assert_eq!(a, DiagOffset::Main);
}
#[test]
fn try_into_empty_matrix() {
{
let x: Matrix<f64> = matrix![];
let y: Matrix<f32> = x.try_into().unwrap();
assert_matrix_eq!(y, matrix![]);
}
{
let x: Matrix<u64> = matrix![];
let y: Matrix<u32> = x.try_into().unwrap();
assert_matrix_eq!(y, matrix![]);
}
{
let x: Matrix<f64> = matrix![];
let y: Matrix<u64> = x.try_into().unwrap();
assert_matrix_eq!(y, matrix![]);
}
{
let x: Matrix<u8> = matrix![];
let y: Matrix<u64> = x.try_into().unwrap();
assert_matrix_eq!(y, matrix![]);
}
}
#[test]
fn try_into_f64_to_i64() {
let x: Matrix<f64> = matrix![ 1.0, 2.0;
-3.0, 4.0];
let y: Matrix<i64> = x.try_into().unwrap();
let expected = matrix![ 1, 2;
-3, 4];
assert_matrix_eq!(y, expected);
}
#[test]
fn try_into_f64_to_u64() {
let x: Matrix<f64> = matrix![ 1.0, 2.0;
3.0, 4.0];
let y: Matrix<u64> = x.try_into().unwrap();
let expected = matrix![ 1, 2;
3, 4];
assert_matrix_eq!(y, expected);
}
#[test]
fn try_into_i64_to_f64() {
{
let x: Matrix<i64> = matrix![ 1, 2;
-3, 4];
let y: Matrix<f64> = x.try_into().unwrap();
let expected = matrix![ 1.0, 2.0;
-3.0, 4.0];
assert_matrix_eq!(y, expected);
}
{
{
let x: Matrix<i64> = matrix![1, 2, i64::max_value()];
let y_result = x.try_into::<f64>();
assert!(y_result.is_ok());
}
{
let x: Matrix<i64> = matrix![1, 2, i64::min_value()];
let y_result = x.try_into::<f64>();
assert!(y_result.is_ok());
}
}
}
#[test]
fn try_into_u64_to_f64() {
{
let x: Matrix<u64> = matrix![ 1, 2;
3, 4];
let y: Matrix<f64> = x.try_into().unwrap();
let expected = matrix![ 1.0, 2.0;
3.0, 4.0];
assert_matrix_eq!(y, expected);
}
{
{
let x: Matrix<u64> = matrix![1, 2, u64::max_value()];
let y_result = x.try_into::<f64>();
assert!(y_result.is_ok());
}
}
}
#[test]
fn try_into_signed_unsigned() {
{
let x: Matrix<u64> = matrix![ 1, 2;
3, 4];
let y: Matrix<i64> = x.try_into().unwrap();
let expected = matrix![ 1, 2;
3, 4];
assert_matrix_eq!(y, expected);
}
{
let x: Matrix<i64> = matrix![ 1, 2;
3, 4];
let y: Matrix<u64> = x.try_into().unwrap();
let expected = matrix![ 1, 2;
3, 4];
assert_matrix_eq!(y, expected);
}
{
let x = matrix![ 1, -2;
3, 4];
let y_result = x.try_into::<u64>();
assert!(y_result.is_err());
}
}
#[test]
fn test_row_convert() {
let a: Matrix<i64> = matrix![1, 2, 3, 4;
5, 6, 7, 8;
9, 10, 11, 12];
let row = a.row(1);
let v: Vector<i64> = row.into();
assert_eq!(v, vector![5, 6, 7, 8]);
let row = a.row(2);
let v = Vector::from(row);
assert_eq!(v, vector![9, 10, 11, 12]);
}
#[test]
fn test_row_convert_mut() {
let mut a: Matrix<i64> = matrix![1, 2, 3, 4;
5, 6, 7, 8;
9, 10, 11, 12];
let row = a.row_mut(1);
let v: Vector<i64> = row.into();
assert_eq!(v, vector![5, 6, 7, 8]);
let mut a: Matrix<i64> = matrix![1, 2, 3, 4;
5, 6, 7, 8;
9, 10, 11, 12];
let row = a.row_mut(2);
let v = Vector::from(row);
assert_eq!(v, vector![9, 10, 11, 12]);
}
#[test]
fn test_column_convert() {
let a: Matrix<i64> = matrix![1, 2, 3, 4;
5, 6, 7, 8;
9, 10, 11, 12];
let row = a.col(1);
let v: Vector<i64> = row.into();
assert_eq!(v, vector![2, 6, 10]);
let row = a.col(2);
let v = Vector::from(row);
assert_eq!(v, vector![3, 7, 11]);
}
#[test]
fn test_column_convert_mut() {
let mut a: Matrix<i64> = matrix![1, 2, 3, 4;
5, 6, 7, 8;
9, 10, 11, 12];
let row = a.col_mut(1);
let v: Vector<i64> = row.into();
assert_eq!(v, vector![2, 6, 10]);
let mut a: Matrix<i64> = matrix![1, 2, 3, 4;
5, 6, 7, 8;
9, 10, 11, 12];
let row = a.col_mut(2);
let v = Vector::from(row);
assert_eq!(v, vector![3, 7, 11]);
}
}