Eigen: Сравните две разреженные матрицы с, вероятно, разной картиной разреженности - PullRequest
0 голосов
/ 11 июня 2019

Я хочу сравнить два Eigen::SparseMatrix

Существует метод res.isApprox(ans), но, к сожалению, он терпит неудачу с утверждением в случае разной картины разреженности, насколько я знаю

AffineInvariantDeformerTest01: Eigen/src/SparseCore/SparseMatrix.h:934: void Eigen::internal::set_from_triplets(const InputIterator&, const InputIterator&, SparseMatrixType&, DupFunctor) [with InputIterator = __gnu_cxx::__normal_iterator<Eigen::Triplet<double, int>*, std::vector<Eigen::Triplet<double, int>, std::allocator<Eigen::Triplet<double, int> > > >; SparseMatrixType = Eigen::SparseMatrix<double, 0, int>; DupFunctor = Eigen::internal::scalar_sum_op<double, double>]: Assertion `it->row()>=0 && it->row()<mat.rows() && it->col()>=0 && it->col()<mat.cols()' failed.

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

РЕДАКТИРОВАТЬ: Просто метод, который может сравнить шаблоны разреженности двух матриц, мне тоже подходит

1 Ответ

1 голос
/ 14 июня 2019

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

Если даны две матрицы с разными шаблонами разреженности, они будут считаться приблизительно равными, если различные записи (почти) равны нулю. Следующее должно вычислить true дважды (увеличьте 1e-19, чтобы увидеть разницу):

#include <Eigen/SparseCore>
#include <iostream>
#include <array>

int main() {
    Eigen::SparseMatrix<double> Mat1(2,2), Mat2(2,2);

    std::array<Eigen::Triplet<double,int>, 2> data1  {{{0,0,1.0}, {1,1, 1e-19}}};
    std::array<Eigen::Triplet<double,int>, 2> data2  {{{0,0,1.0}, {1,0, 1e-19}}};

    Mat1.setFromTriplets(data1.begin(), data1.end());
    Mat2.setFromTriplets(data2.begin(), data2.end());

    std::cout << "Mat1.isApprox(Mat1) == " << Mat1.isApprox(Mat1) << "\nMat1.isApprox(Mat2) == " << Mat1.isApprox(Mat2) << "\n";
}

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

template<class Derived>
bool hasSamePattern(Eigen::SparseCompressedBase<Derived> const& A, Eigen::SparseCompressedBase<Derived> const& B)
{
    assert(A.isCompressed() && B.isCompressed());
    if(A.rows() != B.rows() || A.cols() != B.cols() || A.nonZeros() != B.nonZeros())
        return false;
    typedef Eigen::Matrix<typename Derived::StorageIndex, Eigen::Dynamic, 1> IndexVector;
    Eigen::Index outerSize = A.outerSize(), nnz = A.nonZeros();
    if(IndexVector::Map(A.outerIndexPtr(), outerSize) != IndexVector::Map(B.outerIndexPtr(), outerSize))
        return false;
    if(IndexVector::Map(A.innerIndexPtr(), nnz) != IndexVector::Map(B.innerIndexPtr(), nnz))
        return false;

    return true;
}
...