Собственные индексы плотной матрицы, удовлетворяющие условию - PullRequest
0 голосов
/ 25 апреля 2018

Я хочу получить индексы строк / столбцов из плотной матрицы, которые удовлетворяют условию.В моем случае результат, скорее всего, будет очень скудным.Например, с матрицей

1 5 2
7 6 3
2 3 8

я бы хотел получить указание, где коэффициент больше 4, или

(0,1), (1,0), (1,1), (2,2)

Мои первоначальные мысли включают использование select или по коэффициенту операций для построения матрицы bool / int

0 1 0
1 1 0
0 0 1

, а затем преобразование ее в разреженную матрицу

(0,1,1), (1,0,1), (1,1,1), (2,2,1)

и удаление значений коэффициентов

(0,1), (1,0), (1,1), (2,2)

Однако для этого требуется два прохода по матрицам, размер которых может быть очень большим.

Альтернативно простой двойной цикл по исходной матрице, похожий на псевдокод

for (int i; i < mat.cols(); i++) {
    for (int j; j < mat.rows(); j++) {
        if(cond(mat(j, i))) {
            add_index(i, j, index_list)
        }
    }
}

, но это требует только оптимизации компиляторов и ни одной оптимизации / векторизации Eigen.

Есть ли более эффективный способ, которого мне не хватает?В моем случае это простые сравнения.

Спасибо за любую помощь

1 Ответ

0 голосов
/ 26 апреля 2018

Здесь не так много векторизации, но во избежание записи двух циклов (которые лучше поменять местами для хранилища с основными строками), лучшим инструментом будет посетитель:

mat.visit(some_visitor);

К сожалениюпосетитель не может быть простой лямбдой, так как visit вызывает метод init(val,0,0) для первого элемента.Это полезно для уменьшающих посетителей, но не всегда.Чтобы заставить visit принимать простую лямбду, вы можете использовать следующий помощник:

template<typename Func>
struct lambda_as_visitor_wrapper : Func {
    lambda_as_visitor_wrapper(const Func& f) : Func(f) {}
    template<typename S,typename I>
    void init(const S& v, I i, I j) { return Func::operator()(v,i,j); }
};

template<typename Mat, typename Func>
void visit_lambda(const Mat& m, const Func& f)
{
    lambda_as_visitor_wrapper<Func> visitor(f);
    m.visit(visitor);
}

В таком случае вы можете написать:

int main() {
    int n = 5;
    double th = 0.5;
    Eigen::MatrixXd M = Eigen::MatrixXd::Random(n,n);

    std::vector<std::pair<int,int>> indices;
    visit_lambda(M,
        [&indices,th](double v, int i, int j) {
            if(v>th)
                indices.push_back(std::make_pair(i,j));
        });


    std::cout << M << "\n\n";

    for(auto p:indices)
        std::cout << '(' << p.first << ',' << p.second << ") ";
    std::cout << '\n';

    return 0;
}
...