Introduce shape() function

Issue #201 wontfix
Mikhail Katliar created an issue

Sometimes it is necessary to check/compare the dimensions of a given matrix or a vector in a uniform fashion. For this purpose,

  1. We can define shape of a matrix as a pair of numbers (M, N) where M is the number of rows and N is the number of columns.
  2. For a vector, the shape can be defined as a pair of a number and a bool (N, TF), where N is the size of a vector and TF is the transpose flag.
  3. Alternatively, the shape of a vector can be defined as a pair of numbers, too, such that for a column vector cv the the shape is (size(cv), 1), and for a row vector rv the shape is (1, size(rv)). In this case shape of a vector can be compared to a shape of a matrix. I am not sure which of the two options is better.

Possible implementation:

namespace blaze {

template <typename M, bool SO>
inline auto shape(Matrix<M, SO>& m)
{
    return std::pair<size_t, size_t>(rows(m), columns(m));
}

template <typename V, bool TF>
inline auto shape(Vector<V, rowVector>& v)
{
    return std::pair<size_t, bool>(size(v), TF);
}

}

Then, the following generic code can be written (which is a simplified example of what I needed to implement):

template <
    typename Value, // A type that can be either a vector of a matrix
    typename ExpectedShape // A functor that returns the correct shape of a matrix or a vector for a given key
>
class PropertyMap
{
public:
    PropertyMap(Value& val, ExpectedShape expected_shape)
    :    val_(val)
    ,    expectedShape_(expected_shape)
    {
    }

    template <typename V>
    friend void put(PropertyMap const& pm, int key, V const& val)
    {
        if (shape(val) != pm.expectedShape_(key))
            throw std::invalid_argument("Invalid argument shape");
        pm.val_ = val;
    }

private:
    Value& val_;
    ExpectedShapeFunc expectedShape_;
};

class Foo
{
public:
    using Matrix = blaze::DynamicMatrix<double>;
    using Vector = blaze::DynamicVector<double>;

    // Define many like those:
    auto propertyMap1()
    {
        return PropertyMap(m1, [] (int key) { return std::pair<size_t, size_t>(abs(key) + 42, 42); } );
    }

    auto propertyMap1()
    {
        return PropertyMap(m2, [] (int key) { return std::pair<size_t, size_t>(abs(key) + 43, 43); } );
    }

    auto propertyMap3()
    {
        return PropertyMap(v_, [] (int key) { return std::pair<size_t, bool>(abs(key + 11), true); } );
    }

private:
    Matrix m1_;
    Matrix m2_;
    Vector v_;
}

Comments (3)

  1. Klaus Iglberger

    Hi Mikhail!

    Thanks a lot for the proposal. We have given this idea some thought, but currently we feel that it would not fit well as a general feature. Since we plan to introduce n-dimensional data structures (see issue #53), we simply don't have a firm understanding of what the shape() function should return in general. Still, thanks for sharing the idea,

    Best regards,

    Klaus!

  2. Log in to comment