| // This file is part of Eigen, a lightweight C++ template library | |
| // for linear algebra. | |
| // | |
| // Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr> | |
| // | |
| // This Source Code Form is subject to the terms of the Mozilla | |
| // Public License v. 2.0. If a copy of the MPL was not distributed | |
| // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
| // SPDX-License-Identifier: MPL-2.0 | |
| #ifndef EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H | |
| #define EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H | |
| // IWYU pragma: private | |
| #include "./InternalHeaderCheck.h" | |
| namespace Eigen { | |
| namespace internal { | |
| // perform a pseudo in-place sparse * sparse product assuming all matrices are col major | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| static void sparse_sparse_product_with_pruning_impl(const Lhs& lhs, const Rhs& rhs, ResultType& res, | |
| const typename ResultType::RealScalar& tolerance) { | |
| using RhsScalar = typename remove_all_t<Rhs>::Scalar; | |
| using ResScalar = typename remove_all_t<ResultType>::Scalar; | |
| using StorageIndex = typename remove_all_t<Lhs>::StorageIndex; | |
| // make sure to call innerSize/outerSize since we fake the storage order. | |
| Index rows = lhs.innerSize(); | |
| Index cols = rhs.outerSize(); | |
| eigen_assert(lhs.outerSize() == rhs.innerSize()); | |
| // allocate a temporary buffer | |
| AmbiVector<ResScalar, StorageIndex> tempVector(rows); | |
| // mimics a resizeByInnerOuter: | |
| EIGEN_IF_CONSTEXPR (ResultType::IsRowMajor) { | |
| res.resize(cols, rows); | |
| } else { | |
| res.resize(rows, cols); | |
| } | |
| evaluator<Lhs> lhsEval(lhs); | |
| evaluator<Rhs> rhsEval(rhs); | |
| // estimate the number of non zero entries | |
| // given a rhs column containing Y non zeros, we assume that the respective Y columns | |
| // of the lhs differs in average of one non zeros, thus the number of non zeros for | |
| // the product of a rhs column with the lhs is X+Y where X is the average number of non zero | |
| // per column of the lhs. | |
| // Therefore, we have nnz(lhs*rhs) = nnz(lhs) + nnz(rhs) | |
| Index estimated_nnz_prod = lhsEval.nonZerosEstimate() + rhsEval.nonZerosEstimate(); | |
| res.reserve(estimated_nnz_prod); | |
| double ratioColRes = double(estimated_nnz_prod) / (double(lhs.rows()) * double(rhs.cols())); | |
| for (Index j = 0; j < cols; ++j) { | |
| // FIXME: compute a more accurate per-column nnz ratio for res. | |
| tempVector.init(ratioColRes); | |
| tempVector.setZero(); | |
| for (typename evaluator<Rhs>::InnerIterator rhsIt(rhsEval, j); rhsIt; ++rhsIt) { | |
| // FIXME: rewrite as tmp += rhsIt.value() * lhs.col(rhsIt.index()). | |
| tempVector.restart(); | |
| RhsScalar x = rhsIt.value(); | |
| for (typename evaluator<Lhs>::InnerIterator lhsIt(lhsEval, rhsIt.index()); lhsIt; ++lhsIt) { | |
| tempVector.coeffRef(lhsIt.index()) += lhsIt.value() * x; | |
| } | |
| } | |
| res.startVec(j); | |
| for (typename AmbiVector<ResScalar, StorageIndex>::Iterator it(tempVector, tolerance); it; ++it) | |
| res.insertBackByOuterInner(j, it.index()) = it.value(); | |
| } | |
| res.finalize(); | |
| } | |
| template <typename Lhs, typename Rhs, typename ResultType, int LhsStorageOrder = traits<Lhs>::Flags & RowMajorBit, | |
| int RhsStorageOrder = traits<Rhs>::Flags & RowMajorBit, | |
| int ResStorageOrder = traits<ResultType>::Flags & RowMajorBit> | |
| struct sparse_sparse_product_with_pruning_selector; | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| struct sparse_sparse_product_with_pruning_selector<Lhs, Rhs, ResultType, ColMajor, ColMajor, ColMajor> { | |
| using RealScalar = typename ResultType::RealScalar; | |
| static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) { | |
| remove_all_t<ResultType> res_{res.rows(), res.cols()}; | |
| internal::sparse_sparse_product_with_pruning_impl<Lhs, Rhs, ResultType>(lhs, rhs, res_, tolerance); | |
| res.swap(res_); | |
| } | |
| }; | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| struct sparse_sparse_product_with_pruning_selector<Lhs, Rhs, ResultType, ColMajor, ColMajor, RowMajor> { | |
| using RealScalar = typename ResultType::RealScalar; | |
| static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) { | |
| // we need a col-major matrix to hold the result | |
| using SparseTemporaryType = SparseMatrix<typename ResultType::Scalar, ColMajor, typename ResultType::StorageIndex>; | |
| SparseTemporaryType res_{res.rows(), res.cols()}; | |
| internal::sparse_sparse_product_with_pruning_impl<Lhs, Rhs, SparseTemporaryType>(lhs, rhs, res_, tolerance); | |
| res = res_; | |
| } | |
| }; | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| struct sparse_sparse_product_with_pruning_selector<Lhs, Rhs, ResultType, RowMajor, RowMajor, RowMajor> { | |
| using RealScalar = typename ResultType::RealScalar; | |
| static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) { | |
| // let's transpose the product to get a column x column product | |
| remove_all_t<ResultType> res_{res.rows(), res.cols()}; | |
| internal::sparse_sparse_product_with_pruning_impl<Rhs, Lhs, ResultType>(rhs, lhs, res_, tolerance); | |
| res.swap(res_); | |
| } | |
| }; | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| struct sparse_sparse_product_with_pruning_selector<Lhs, Rhs, ResultType, RowMajor, RowMajor, ColMajor> { | |
| using RealScalar = typename ResultType::RealScalar; | |
| static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) { | |
| using ColMajorMatrixLhs = SparseMatrix<typename Lhs::Scalar, ColMajor, typename Lhs::StorageIndex>; | |
| using ColMajorMatrixRhs = SparseMatrix<typename Rhs::Scalar, ColMajor, typename Lhs::StorageIndex>; | |
| ColMajorMatrixLhs colLhs(lhs); | |
| ColMajorMatrixRhs colRhs(rhs); | |
| internal::sparse_sparse_product_with_pruning_impl<ColMajorMatrixLhs, ColMajorMatrixRhs, ResultType>(colLhs, colRhs, | |
| res, tolerance); | |
| } | |
| }; | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| struct sparse_sparse_product_with_pruning_selector<Lhs, Rhs, ResultType, ColMajor, RowMajor, RowMajor> { | |
| using RealScalar = typename ResultType::RealScalar; | |
| static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) { | |
| using RowMajorMatrixLhs = SparseMatrix<typename Lhs::Scalar, RowMajor, typename Lhs::StorageIndex>; | |
| RowMajorMatrixLhs rowLhs(lhs); | |
| sparse_sparse_product_with_pruning_selector<RowMajorMatrixLhs, Rhs, ResultType, RowMajor, RowMajor>::run( | |
| rowLhs, rhs, res, tolerance); | |
| } | |
| }; | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| struct sparse_sparse_product_with_pruning_selector<Lhs, Rhs, ResultType, RowMajor, ColMajor, RowMajor> { | |
| using RealScalar = typename ResultType::RealScalar; | |
| static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) { | |
| using RowMajorMatrixRhs = SparseMatrix<typename Rhs::Scalar, RowMajor, typename Lhs::StorageIndex>; | |
| RowMajorMatrixRhs rowRhs(rhs); | |
| sparse_sparse_product_with_pruning_selector<Lhs, RowMajorMatrixRhs, ResultType, RowMajor, RowMajor, RowMajor>::run( | |
| lhs, rowRhs, res, tolerance); | |
| } | |
| }; | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| struct sparse_sparse_product_with_pruning_selector<Lhs, Rhs, ResultType, ColMajor, RowMajor, ColMajor> { | |
| using RealScalar = typename ResultType::RealScalar; | |
| static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) { | |
| using ColMajorMatrixRhs = SparseMatrix<typename Rhs::Scalar, ColMajor, typename Lhs::StorageIndex>; | |
| ColMajorMatrixRhs colRhs(rhs); | |
| internal::sparse_sparse_product_with_pruning_impl<Lhs, ColMajorMatrixRhs, ResultType>(lhs, colRhs, res, tolerance); | |
| } | |
| }; | |
| template <typename Lhs, typename Rhs, typename ResultType> | |
| struct sparse_sparse_product_with_pruning_selector<Lhs, Rhs, ResultType, RowMajor, ColMajor, ColMajor> { | |
| using RealScalar = typename ResultType::RealScalar; | |
| static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res, const RealScalar& tolerance) { | |
| using ColMajorMatrixLhs = SparseMatrix<typename Lhs::Scalar, ColMajor, typename Lhs::StorageIndex>; | |
| ColMajorMatrixLhs colLhs(lhs); | |
| internal::sparse_sparse_product_with_pruning_impl<ColMajorMatrixLhs, Rhs, ResultType>(colLhs, rhs, res, tolerance); | |
| } | |
| }; | |
| } // end namespace internal | |
| } // end namespace Eigen | |
| #endif // EIGEN_SPARSESPARSEPRODUCTWITHPRUNING_H |