Description
I have this code, which takes a matrix and tries to create a matrix with similar specifications, i.e. a matrix with the same Shape
. Unfortunately, this turns out to be more complicated then I hoped, because I don't have an easy way to check the memory layout of my matrix.
The reasons are:
- I don't have direct access to
Shape
, but only toDim::Pattern
(viaArrayBase::dim
) orDim
(viaArrayBase::raw_dim
). If I could get theShape
from an array, I could pass it to the various methods that accept aT: ShapeBuilder
. - There is no way to check if a matrix is in column major or row major form. Similarly, there is no way to check if a
Shape
is for column or row major form.
The only workaround that I see and am using, is to call as_slice
and as_slice_memory_order
on my array. If the first call returns an Option
, I know I am in row major form. If it returns None
but as_slice_memory_order
returns an Option
, I know I am in column major form. Both of these methods of course depend on the current specific implementation in ndarray.
It would be nice to have a more direct check for the memory layout. This is important when writing methods that call blas
or lapack
functions.
See the code below for reference.
fn from_matrix<S>(a: &ArrayBase<S, Ix2>) -> Result<Self>
where S: Data<Elem = f64>
{
use cblas::Layout::*;
let dim = a.dim();
let shape = match utils::get_layout(a) {
Some(ColumnMajor) => dim.f(),
Some(RowMajor) => dim.into_shape(),
None => Err(Error::NonContiguous)?,
};
Self::from_shape(shape)
}
fn from_shape<T>(shape: T) -> Result<Self>
where T: ShapeBuilder<Dim = Ix2>,
{
// Unfortunately we cannot check the shape itself to see if it's
// in ColumnMajor or RowMajor layout. So we need to first construct
// an array and then check that.
let shape = shape.into_shape();
let q = Array2::zeros(shape);
let memory_layout = match get_layout(&q) {
Some(layout) => layout,
None => Err(Error::NonContiguous)?,
};
let r = q.clone();
Ok(ClassicalGramSchmidt {
q,
r,
memory_layout,
})
}
fn get_layout<S, T, D>(a: &ArrayBase<S, D>) -> Option<cblas::Layout>
where S: Data<Elem=T>,
D: Dimension
{
if let Some(_) = a.as_slice() {
Some(cblas::Layout::RowMajor)
} else if let Some(_) = a.as_slice_memory_order() {
Some(cblas::Layout::ColumnMajor)
} else {
None
}
}