简体   繁体   中英

Divide Matrix by vector in armadillo

I have a sparse matrix and a vector, both constructed in armadillo. Now I want to divide the matrix by the vector, ie divide the first column of the matrix by the first element, and so on. Now I can do that in a loop:

int r_num = 5000;
arma::colvec r_vec = arma::linspace(0, 1, r_num);
double dh = abs(r_vec(1)-r_vec(0));
arma::sp_cx_mat r1_matrix = arma::sp_cx_mat(r_num, r_num);
r1_matrix.diag(0).fill(0);
r1_matrix.diag(1).fill(8);
r1_matrix.diag(-1).fill(-8);
r1_matrix.diag(2).fill(-1);
r1_matrix.diag(-2).fill(1);

arma::cx_colvec divider_vec = r_vec*std::complex<double>{1.0, 0.0};
divider_vec(0) = 1;

for (size_t i = 0; i < r_num; i++)
{
    if (i % 100 == 0)
        std::cout << i << " of " << r_num << '\n';
    r1_matrix.col(i) = r1_matrix.col(i) / divider_vec(i);
}

but that is extremely slow (especially after I will increase r_num afterwards). When using the usual approach

r1_matrix = r1_matrix/divider_vec;

I get the error of mismatched dimensions ((5000x5000) and (5000x1)). Is there another faster way?

Apart maybe for specifics due to sparse matrices or armadillo (which I do not know at all), the best way I think about to solve your problem is to compute the inverse of your vector, store it as the diagonal of a diagonal matrix (of the size of your matrix) and then multiply your matrix by this computed one.

Some examples using Eigen :

#include <Eigen/Core>
#include <iostream>

using namespace Eigen;

int main()
{
    Matrix<float, 3, 3> r1_matrix;
    r1_matrix <<
        2, 3, 5,
        4, 6, 10,
        6, 9, 15;

    Matrix<float, 3, 1> divider_vec;
    divider_vec << 2, 3, 5;
    divider_vec = divider_vec.cwiseInverse();

    Matrix<float, 3, 3> divider_mat = divider_vec.asDiagonal();

    r1_matrix = r1_matrix * divider_mat;

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

    Matrix<float, 5, 3> r2_matrix;
    r2_matrix <<
        2, 3, 5,
        4, 6, 10,
        6, 9, 15,
        8, 12, 20,
        10, 15, 25;

    Matrix<float, 3, 5> divider_mat2 = Matrix<float, 3, 5>::Zero();
    divider_mat2.block<3, 3>(0, 0) = divider_mat;

    r2_matrix = (r2_matrix * divider_mat2).block<5, 3>(0, 0);
    std::cout << std::endl << r2_matrix << std::endl;

    SparseMatrix<float> sp_matrix(5, 5);
    std::vector<Triplet<float>> data =
    {
        { 0, 0, 2.f }, { 2, 1, 6.f }, { 1, 2, 10.f }, { 3, 3, 14.f }, { 4, 3, 21.f }, { 1, 4, 11.f }
    };
    sp_matrix.setFromTriplets(data.begin(), data.end());

    Matrix<float, 5, 1> divider_vec2;
    divider_vec2 << 2, 3, 5, 7, 11;
    divider_vec2 = divider_vec2.cwiseInverse();
    SparseMatrix<float> divider_sp_mat(5, 5);
    data.clear();

    for (int i = 0; i < 5; ++i)
    {
        data.push_back(Triplet<float>{ i, i, divider_vec2[i]});
    }

    divider_sp_mat.setFromTriplets(data.begin(), data.end());

    sp_matrix = sp_matrix * divider_sp_mat;
    std::cout << std::endl << sp_matrix << std::endl;
    return 0;
}

I am not sure if there is another way than making a square matrix when the matrix has more rows than columns though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM