1

In order to read and store some results from a MATLAB program, I need to use up to 6 dimensional matrices. Instead of doing something like:

typedef std::vector<double>  Row;
typedef std::vector<Row>     Matrix2;
typedef std::vector<Matrix2> Matrix3;
typedef std::vector<Matrix3> Matrix4;
typedef std::vector<Matrix4> Matrix5;
typedef std::vector<Matrix5> Matrix6;

I decided to go with templates, and here's what I have so far:

template <class T, int N>
class Matrix {
public:
    typedef typename Matrix<T, N - 1>::type MatrixOneDimLower;
    typedef std::vector<MatrixOneDimLower> type;

    type _data;

    template <unsigned int dn, typename ...NT>
    Matrix(unsigned int dn, NT ...drest) : _data(dn, MatrixOneDimLower(drest)) {}

    MatrixOneDimLower& operator[](unsigned int index)
    {
        return _data[index];
    }
};

template <class T>
class Matrix<T, 1> {
public:
    typedef std::vector<T> type;

    type _data;

    Matrix(unsigned int d0) : _data(d0, T(0.0)) {}

    T& operator[](unsigned int index)
    {
        return _data[index];
    }
};

Unfortunately, I'm not very adept in variadic templates and recursive templates, and this doesn't work. For example, if I try to use this as:

Matrix<double, 4> temp(n,  dim[2], dim[1], dim[0]);

I get this compile time error (Visual Studio 2017):

error C2661: 'Matrix<double,4>::Matrix': no overloaded function takes 4 arguments

I would really appreciate if you can let me know what I'm doing wrong.

2
  • 4
    You really don't want a lot of nested vectors. See the bottom half of my answer here for why and a toy example of how to work around the issue. Commented Oct 25, 2018 at 19:16
  • 1
    I think the correct term is "sixth-order tensor". Commented Oct 25, 2018 at 19:18

1 Answer 1

2
template<class T, std::size_t I>
struct MatrixView {
  MatrixView<T, I-1> operator[](std::size_t i) {
    return {ptr + i* *strides, strides+1};
  }
  MatrixView( T* p, std::size_t const* stride ):ptr(p), strides(stride) {}
private:
  T* ptr = 0;
  std::size_t const* strides = 0;
};
template<class T>
struct MatrixView<T, 1> {
  T& operator[](std::size_t i) {
    return ptr[i];
  }
  MatrixView( T* p, std::size_t const* stride ):ptr(p) {}
private:
  T* ptr = 0;
};
template<class T, std::size_t N>
struct Matrix {
  Matrix( std::array<std::size_t, N> sizes ) {
    std::size_t accumulated = 1;
    for (std::size_t i = 1; i < sizes.size(); ++i) {
      accumulated *= sizes[N-i];
      strides[N-i] = accumulated;
    }
    storage.resize( strides[0] * sizes[0] );
  }
  MatrixView<T, N> get() { return {storage.data(), strides.data()}; }
  MatrixView<T const, N> get() const { return {storage.data(), strides.data()}; }
private:
  std::vector<T> storage;
  std::array<std::size_t, N-1> strides;
};

this requires doing Matrix<int, 6> m{ {5,4,2,1,3,5} }; to create a matrix with 6 dimensions.

To access it you need to do m.get()[3][0][0][0][0][0] = 4.

You get get rid of that .get() but it is a bit annoying so long as you want to support tensors of first order.

The data is stored contiguously.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a lot! This is very helpful. I have a question though, how can I change this to allow for strides not being compile time constants. Because I don't know the strides for each dimension until I load the files. So I want to be able to write Matrix<int, 2> a { {d0, d1} } where d0 and d1 are run time variables.
@triple_r The dimensions are just values in a std::array. The strides are the product of dimensions. There is 1 fewer stride than dimension, as the top-level dimension only matters to the size of the buffer, not the space between elements.
Oh, sorry, I meant the size of the dimensions. I needed to cast my variables to size_t, or else I was getting an error :-) Thanks again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.