Skip to content

Direct access to Shape #592

@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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions