Search code examples
c++matrixindexingeigen

How to traverse the matix rows for index not in a special index vector P by Eigen?


Today i met a trouble.I have a special index vector P,and a matrix A.for example:

    MatrixXd B = MatrixXd::Ones(10, 10);
    std::cout << B;
    std::vector<int> P = { 1, 6, 3, 7, 5 };

and I want to change values of rows of B.Which rows' indexs is not in P;In this case ,i want to do some implements to row 0,2,4,5,8,9.

But how to get that efficiently by eigen?


Solution

  • The use of Eigen is rather secondary to the question. The main issue is that you need to find all indices in the range [0, B.rows()) which are not in P. From the looks of things, P is not sorted, which is unfortunate. I assume it is at least unique as this saves us some memory.

    Here is a version that is optimized to be fast, rather than pretty.

    std::vector<int> indices_not_in(const std::vector<int>& P, int end)
    {
        assert(P.size() <= end);
        std::vector<bool> inP(end);
        for(int pi: P) {
            assert(inP[pi] == false && "Duplicate entry");
            inP[pi] = true;
        }
        std::vector<int> notP(inP.size() - P.size() + 1);
        auto cur = notP.begin();
        int i = 0;
        for(bool inPi: inP) {
            *cur = i++;
            cur += ! inPi;
        }
        notP.erase(cur, notP.end());
        return notP;
    }
    
    int main()
    {
        Eigen::MatrixXd B = Eigen::MatrixXd::Ones(10, 10);
        std::cout << B << "\n\n";
        std::vector<int> P = { 1, 6, 3, 7, 5 };
        std::vector<int> notP = indices_not_in(P, B.rows());
        B(notP, Eigen::all) *= 2.;
        std::cout << B << "\n";
    }
    

    If you cannot guarantee that the P vector contains unique entries, then here is a modified version that works with that:

    std::vector<int> indices_not_in(const std::vector<int>& P, int end)
    {
        std::vector<bool> inP(end);
        for(int pi: P)
            inP[pi] = true;
        std::vector<int> notP(end);
        auto cur = notP.begin();
        int i = 0;
        for(bool inPi: inP) {
            *cur = i++;
            cur += ! inPi;
        }
        notP.erase(cur, notP.end());
        return notP;
    }