#![cfg(feature = "nalgebra")]
use crate::array::Array;
use crate::error::{NumRs2Error, Result};
use nalgebra::{DMatrix, DVector, Dim, Matrix, Scalar};
use num_traits::NumCast;
use std::fmt::Debug;
pub fn from_dmatrix<T>(matrix: &DMatrix<T>) -> Result<Array<T>>
where
T: Clone + Debug + NumCast + Scalar,
{
let nrows = matrix.nrows();
let ncols = matrix.ncols();
let mut data = Vec::with_capacity(nrows * ncols);
for i in 0..nrows {
for j in 0..ncols {
data.push(matrix[(i, j)].clone());
}
}
let arr = Array::from_vec(data);
Ok(arr.reshape(&[nrows, ncols]))
}
pub fn to_dmatrix<T>(arr: &Array<T>) -> Result<DMatrix<T>>
where
T: Clone + Debug + Scalar,
{
if arr.ndim() != 2 {
return Err(NumRs2Error::DimensionMismatch(format!(
"Cannot convert Array with shape {:?} to DMatrix, expected 2D array",
arr.shape()
)));
}
let nrows = arr.shape()[0];
let ncols = arr.shape()[1];
let data = arr.to_vec();
let matrix = DMatrix::from_row_slice(nrows, ncols, &data);
Ok(matrix)
}
pub fn from_dvector<T>(vector: &DVector<T>) -> Result<Array<T>>
where
T: Clone + Debug + NumCast + Scalar,
{
let data: Vec<T> = vector.iter().cloned().collect();
Ok(Array::from_vec(data))
}
pub fn to_dvector<T>(arr: &Array<T>) -> Result<DVector<T>>
where
T: Clone + Debug + Scalar,
{
let is_vector =
arr.ndim() == 1 || (arr.ndim() == 2 && (arr.shape()[0] == 1 || arr.shape()[1] == 1));
if !is_vector {
return Err(NumRs2Error::DimensionMismatch(
format!("Cannot convert Array with shape {:?} to DVector, expected 1D array or column/row vector", arr.shape())
));
}
let data = arr.to_vec();
let vector = DVector::from_vec(data);
Ok(vector)
}
pub fn from_matrix<T, R, C, S>(matrix: &Matrix<T, R, C, S>) -> Result<Array<T>>
where
T: Clone + Debug + NumCast + Scalar,
R: Dim,
C: Dim,
S: nalgebra::storage::Storage<T, R, C>,
{
let nrows = matrix.nrows();
let ncols = matrix.ncols();
let mut data = Vec::with_capacity(nrows * ncols);
for i in 0..nrows {
for j in 0..ncols {
data.push(matrix[(i, j)].clone());
}
}
let arr = Array::from_vec(data);
Ok(arr.reshape(&[nrows, ncols]))
}
pub fn from_dynamic<T, R, C, S>(matrix: &Matrix<T, R, C, S>) -> Result<Array<T>>
where
T: Clone + Debug + NumCast + Scalar,
R: Dim,
C: Dim,
S: nalgebra::storage::Storage<T, R, C>,
{
from_matrix(matrix)
}
#[cfg(test)]
mod tests {
use super::*;
use nalgebra::{Matrix3, Vector3};
#[test]
fn test_from_dmatrix() {
let na_mat = DMatrix::from_row_slice(2, 3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let num_arr = from_dmatrix(&na_mat).expect("Failed to convert from DMatrix");
assert_eq!(num_arr.shape(), vec![2, 3]);
assert_eq!(num_arr.to_vec(), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
}
#[test]
fn test_to_dmatrix() {
let num_arr = Array::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).reshape(&[2, 3]);
let na_mat = to_dmatrix(&num_arr).expect("Failed to convert to DMatrix");
assert_eq!(na_mat.nrows(), 2);
assert_eq!(na_mat.ncols(), 3);
assert_eq!(na_mat[(0, 0)], 1.0);
assert_eq!(na_mat[(1, 2)], 6.0);
}
#[test]
fn test_from_dvector() {
let na_vec = DVector::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
let num_arr = from_dvector(&na_vec).expect("Failed to convert from DVector");
assert_eq!(num_arr.shape(), vec![4]);
assert_eq!(num_arr.to_vec(), vec![1.0, 2.0, 3.0, 4.0]);
}
#[test]
fn test_to_dvector() {
let num_arr = Array::from_vec(vec![1.0, 2.0, 3.0, 4.0]);
let na_vec = to_dvector(&num_arr).expect("Failed to convert to DVector");
assert_eq!(na_vec.len(), 4);
assert_eq!(na_vec[0], 1.0);
assert_eq!(na_vec[3], 4.0);
}
#[test]
fn test_fixed_size_matrix() {
let mat3 = Matrix3::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
let arr = from_matrix(&mat3).expect("Failed to convert from Matrix3");
assert_eq!(arr.shape(), vec![3, 3]);
assert_eq!(
arr.get(&[0, 0]).expect("Failed to get element at [0,0]"),
1.0
);
assert_eq!(
arr.get(&[2, 2]).expect("Failed to get element at [2,2]"),
9.0
);
}
#[test]
fn test_fixed_size_vector() {
let vec3 = Vector3::new(1.0, 2.0, 3.0);
let arr = from_matrix(&vec3).expect("Failed to convert from Vector3");
assert_eq!(arr.shape(), vec![3, 1]);
assert_eq!(arr.to_vec(), vec![1.0, 2.0, 3.0]);
}
}