Skip to content

Direct access to Shape #592

Open
Open
@SuperFluffy

Description

@SuperFluffy

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:

  1. I don't have direct access to Shape, but only to Dim::Pattern (via ArrayBase::dim) or Dim (via ArrayBase::raw_dim). If I could get the Shape from an array, I could pass it to the various methods that accept a T: ShapeBuilder.
  2. 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
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions