Home > Net >  C EIGEN: How to create triangular matrix map from a vector?
C EIGEN: How to create triangular matrix map from a vector?

Time:09-01

I would like to use data stored into an Eigen (https://eigen.tuxfamily.org) vector

Eigen::Vector<double, 6> vec({1,2,3,4,5,6});

as if they were a triangular matrix

1 2 3
0 4 5
0 0 6

I know how to do it for a full matrix using Eigen's Map

Eigen::Vector<double, 9>  vec({1,2,3,4,5,6,7,8,9});
std::cout << Eigen::Map<Eigen::Matrix<double, 3, 3, RowMajor>>(vec.data());

which produces

1 2 3
4 5 6
7 8 9

However I do not know how to make a Map to a triangular matrix.

Is it possible? Thanks!

[Edited for clarity]

CodePudding user response:

This is not a direct solution to your problem but a way how to calculate the std::vector to fill in the 0 at the correct place. I think it is also possible to calculate it as a std::array if needed. I am not sure if that helps, but I guess you could use the calculated vector to fill the Eigen::Map

#include <array>
#include <cstddef>
#include <iostream>
#include <vector>

template<typename T, size_t N>
class EigenVector
{
    static constexpr int CalculateRowColSize(size_t n)
    {
        size_t i = 1;
        size_t inc = 1;
        do
        {
            if (inc == n)
            {
                return static_cast<int>(i);
            }
            i  ;
            inc  = i;
        } while (i < n);
        return -1;
    }

    static constexpr bool IsValid(size_t n)
    {
        if(CalculateRowColSize(n) == -1)
        {
            return false;
        }
        return true;
    }
    static_assert(IsValid(N));

public:
    EigenVector() = delete;

    static std::vector<T> Calculate(std::array<T, N> values)
    {
        constexpr size_t mRowColSize = CalculateRowColSize(N);
        std::vector<T> ret;
        auto count = 0;
        auto valueCounter = 0;
        for (size_t i = 0; i < mRowColSize; i  )
        {
            for (auto j = 0; j < count; j  )
            {
                ret.push_back(T());
            }
            for (size_t j = 0; j < mRowColSize - count; j  )
            {
                ret.push_back(values[valueCounter]);
                valueCounter  ;
            }
            count  ;
        }

        return ret;
    }
};

int main()
{
    {
        const std::array<int, 6> arr{ 1,2,3,4,5,6 };

        const auto values = EigenVector<int, 6>::Calculate(arr);

        for (auto& val : values)
        {
            std::cout << val << " ";
        }
    }

    std::cout << std::endl << std::endl;

    {
        const std::array<int, 10> arr{ 1,2,3,4,5,6,7,8,9,10 };

        const auto values = EigenVector<int, 10>::Calculate(arr);

        for (auto& val : values)
        {
            std::cout << val << " ";
        }
    }

    return 0;
}

Output:

1 2 3 0 4 5 0 0 6

1 2 3 4 0 5 6 7 0 0 8 9 0 0 0 10

Note that the algorithm is written that only possible matrix sizes are valid as input

CodePudding user response:

In my opinion this cannot be done using Map only: The implementation of Map as it is relies on stride sizes that remain constant no matter their index positions, see https://eigen.tuxfamily.org/dox/classEigen_1_1Stride.html. To implement a triangular matrix map you would have to have a Map that changes its inner stride depending on the actual column number. The interfaces in Eigen do not allow that at the moment, see https://eigen.tuxfamily.org/dox/Map_8h_source.html.


But if you are just concerned about the extra memory you can just use Eigen's sparse matrix representation:

https://eigen.tuxfamily.org/dox/group__TutorialSparse.html

(Refer to section "Filling a sparse matrix".)

  • Related