diff --git a/src/solver/sparse_matrix.hh b/src/solver/sparse_matrix.hh index 8ec8c0fd4..6eef8f166 100644 --- a/src/solver/sparse_matrix.hh +++ b/src/solver/sparse_matrix.hh @@ -1,162 +1,167 @@ /** * @file sparse_matrix.hh * * @author Nicolas Richart * * @date creation: Mon Dec 13 2010 * @date last modification: Tue Feb 20 2018 * * @brief sparse matrix storage class (distributed assembled matrix) * This is a COO format (Coordinate List) * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SPARSE_MATRIX_HH__ #define __AKANTU_SPARSE_MATRIX_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class DOFManager; class TermsToAssemble; class SolverVector; } // namespace akantu namespace akantu { class SparseMatrix { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseMatrix(DOFManager & dof_manager, const MatrixType & matrix_type, const ID & id = "sparse_matrix"); SparseMatrix(const SparseMatrix & matrix, const ID & id = "sparse_matrix"); virtual ~SparseMatrix(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// remove the existing profile virtual void clearProfile(); /// set the matrix to 0 virtual void clear() = 0; /// add a non-zero element to the profile virtual UInt add(UInt i, UInt j) = 0; /// assemble a local matrix in the sparse one virtual void add(UInt i, UInt j, Real value) = 0; /// save the profil in a file using the MatrixMarket file format virtual void saveProfile(const std::string & /* filename */) const { AKANTU_TO_IMPLEMENT(); } /// save the matrix in a file using the MatrixMarket file format virtual void saveMatrix(const std::string & /* filename */) const { AKANTU_TO_IMPLEMENT(); }; /// multiply the matrix by a coefficient virtual void mul(Real alpha) = 0; /// add matrices virtual void add(const SparseMatrix & matrix, Real alpha = 1.); /// Equivalent of *gemv in blas virtual void matVecMul(const SolverVector & x, SolverVector & y, Real alpha = 1., Real beta = 0.) const = 0; /// modify the matrix to "remove" the blocked dof virtual void applyBoundary(Real block_val = 1.) = 0; /// copy the profile of another matrix virtual void copyProfile(const SparseMatrix & other) = 0; /// operator *= SparseMatrix & operator*=(Real alpha) { this->mul(alpha); return *this; } protected: /// This is the revert of add B += \alpha * *this; virtual void addMeTo(SparseMatrix & B, Real alpha) const = 0; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the values at potition i, j virtual inline Real operator()(UInt /*i*/, UInt /*j*/) const { AKANTU_TO_IMPLEMENT(); } /// return the values at potition i, j virtual inline Real & operator()(UInt /*i*/, UInt /*j*/) { AKANTU_TO_IMPLEMENT(); } + /// return the minimum value + virtual inline Real min() { + AKANTU_TO_IMPLEMENT(); + } + AKANTU_GET_MACRO(NbNonZero, nb_non_zero, UInt); UInt size() const { return size_; } AKANTU_GET_MACRO(MatrixType, matrix_type, const MatrixType &); virtual UInt getRelease() const = 0; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: ID id; /// Underlying dof manager DOFManager & _dof_manager; /// sparce matrix type MatrixType matrix_type; /// Size of the matrix UInt size_; /// number of processors UInt nb_proc; /// number of non zero element UInt nb_non_zero; }; // Array & operator*=(Array & vect, const SparseMatrix & mat); } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "sparse_matrix_inline_impl.cc" #endif /* __AKANTU_SPARSE_MATRIX_HH__ */ diff --git a/src/solver/sparse_matrix_aij.hh b/src/solver/sparse_matrix_aij.hh index 3aca4c3e3..801657809 100644 --- a/src/solver/sparse_matrix_aij.hh +++ b/src/solver/sparse_matrix_aij.hh @@ -1,202 +1,206 @@ /** * @file sparse_matrix_aij.hh * * @author Nicolas Richart * * @date creation: Mon Dec 13 2010 * @date last modification: Wed Nov 08 2017 * * @brief AIJ implementation of the SparseMatrix (this the format used by * Mumps) * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_common.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SPARSE_MATRIX_AIJ_HH__ #define __AKANTU_SPARSE_MATRIX_AIJ_HH__ namespace akantu { class DOFManagerDefault; class TermsToAssemble; } // namespace akantu namespace akantu { class SparseMatrixAIJ : public SparseMatrix { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: SparseMatrixAIJ(DOFManagerDefault & dof_manager, const MatrixType & matrix_type, const ID & id = "sparse_matrix_aij"); SparseMatrixAIJ(const SparseMatrixAIJ & matrix, const ID & id = "sparse_matrix_aij"); ~SparseMatrixAIJ() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// remove the existing profile inline void clearProfile() override; /// add a non-zero element inline UInt add(UInt i, UInt j) override; /// set the matrix to 0 void clear() override; /// assemble a local matrix in the sparse one inline void add(UInt i, UInt j, Real value) override; /// add a block of values inline void addValues(const Vector & is, const Vector & js, const Matrix & values, MatrixType values_type); /// set the size of the matrix void resize(UInt size) { this->size_ = size; } /// modify the matrix to "remove" the blocked dof void applyBoundary(Real block_val = 1.) override; /// save the profil in a file using the MatrixMarket file format void saveProfile(const std::string & filename) const override; /// save the matrix in a file using the MatrixMarket file format void saveMatrix(const std::string & filename) const override; /// copy assuming the profile are the same virtual void copyContent(const SparseMatrix & matrix); /// multiply the matrix by a scalar void mul(Real alpha) override; /// add matrix *this += B // virtual void add(const SparseMatrix & matrix, Real alpha); /// Equivalent of *gemv in blas void matVecMul(const SolverVector & x, SolverVector & y, Real alpha = 1., Real beta = 0.) const override; void matVecMul(const Array & x, Array & y, Real alpha = 1., Real beta = 0.) const; /// copy the profile of another matrix void copyProfile(const SparseMatrix & other) override; /* ------------------------------------------------------------------------ */ /// accessor to A_{ij} - if (i, j) not present it returns 0 inline Real operator()(UInt i, UInt j) const override; /// accessor to A_{ij} - if (i, j) not present it fails, (i, j) should be /// first added to the profile inline Real & operator()(UInt i, UInt j) override; + /// accessor to get the minimum value of A_{ij} + inline Real min() override; + + protected: /// This is the revert of add B += \alpha * *this; void addMeTo(SparseMatrix & B, Real alpha) const override; inline void addSymmetricValuesToSymmetric(const Vector & is, const Vector & js, const Matrix & values); inline void addUnsymmetricValuesToSymmetric(const Vector & is, const Vector & js, const Matrix & values); inline void addValuesToUnsymmetric(const Vector & is, const Vector & js, const Matrix & values); private: /// This is just to inline the addToMatrix function template void addMeToTemplated(MatrixType & B, Real alpha) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(IRN, irn, const Array &); AKANTU_GET_MACRO(JCN, jcn, const Array &); AKANTU_GET_MACRO(A, a, const Array &); /// The release changes at each call of a function that changes the profile, /// it in increasing but could overflow so it should be checked as /// (my_release != release) and not as (my_release < release) AKANTU_GET_MACRO(ProfileRelease, profile_release, UInt); AKANTU_GET_MACRO(ValueRelease, value_release, UInt); UInt getRelease() const override { return value_release; } - + protected: using KeyCOO = std::pair; using coordinate_list_map = std::unordered_map; /// get the pair corresponding to (i, j) inline KeyCOO key(UInt i, UInt j) const { if (this->matrix_type == _symmetric && (i > j)) return std::make_pair(j, i); return std::make_pair(i, j); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: DOFManagerDefault & dof_manager; /// row indexes Array irn; /// column indexes Array jcn; /// values : A[k] = Matrix[irn[k]][jcn[k]] Array a; /// Profile release UInt profile_release{1}; /// Value release UInt value_release{1}; /// map for (i, j) -> k correspondence coordinate_list_map irn_jcn_k; }; } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "sparse_matrix_aij_inline_impl.cc" #endif /* __AKANTU_SPARSE_MATRIX_AIJ_HH__ */ diff --git a/src/solver/sparse_matrix_aij_inline_impl.cc b/src/solver/sparse_matrix_aij_inline_impl.cc index f48042e16..5a25abdd0 100644 --- a/src/solver/sparse_matrix_aij_inline_impl.cc +++ b/src/solver/sparse_matrix_aij_inline_impl.cc @@ -1,189 +1,196 @@ /** * @file sparse_matrix_aij_inline_impl.cc * * @author Nicolas Richart * * @date creation: Fri Aug 21 2015 * @date last modification: Wed Nov 08 2017 * * @brief Implementation of inline functions of SparseMatrixAIJ * * @section LICENSE * * Copyright (©) 2015-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "sparse_matrix_aij.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SPARSE_MATRIX_AIJ_INLINE_IMPL_CC__ #define __AKANTU_SPARSE_MATRIX_AIJ_INLINE_IMPL_CC__ namespace akantu { inline UInt SparseMatrixAIJ::add(UInt i, UInt j) { KeyCOO jcn_irn = this->key(i, j); auto it = this->irn_jcn_k.find(jcn_irn); if (!(it == this->irn_jcn_k.end())) return it->second; if (i + 1 > this->size_) this->size_ = i + 1; if (j + 1 > this->size_) this->size_ = j + 1; this->irn.push_back(i + 1); this->jcn.push_back(j + 1); this->a.push_back(0.); this->irn_jcn_k[jcn_irn] = this->nb_non_zero; (this->nb_non_zero)++; this->profile_release++; this->value_release++; return (this->nb_non_zero - 1); } /* -------------------------------------------------------------------------- */ inline void SparseMatrixAIJ::clearProfile() { SparseMatrix::clearProfile(); this->irn_jcn_k.clear(); this->irn.resize(0); this->jcn.resize(0); this->a.resize(0); this->size_ = 0; this->nb_non_zero = 0; this->profile_release++; this->value_release++; } /* -------------------------------------------------------------------------- */ inline void SparseMatrixAIJ::add(UInt i, UInt j, Real value) { UInt idx = this->add(i, j); this->a(idx) += value; this->value_release++; } /* -------------------------------------------------------------------------- */ inline Real SparseMatrixAIJ::operator()(UInt i, UInt j) const { KeyCOO jcn_irn = this->key(i, j); auto irn_jcn_k_it = this->irn_jcn_k.find(jcn_irn); if (irn_jcn_k_it == this->irn_jcn_k.end()) return 0.; return this->a(irn_jcn_k_it->second); } /* -------------------------------------------------------------------------- */ inline Real & SparseMatrixAIJ::operator()(UInt i, UInt j) { KeyCOO jcn_irn = this->key(i, j); auto irn_jcn_k_it = this->irn_jcn_k.find(jcn_irn); AKANTU_DEBUG_ASSERT(irn_jcn_k_it != this->irn_jcn_k.end(), "Couple (i,j) = (" << i << "," << j << ") does not exist in the profile"); // it may change the profile so it is considered as a change this->value_release++; return this->a(irn_jcn_k_it->second); } /* -------------------------------------------------------------------------- */ inline void SparseMatrixAIJ::addSymmetricValuesToSymmetric(const Vector & is, const Vector & js, const Matrix & values) { for (UInt i = 0; i < values.rows(); ++i) { UInt c_irn = is(i); if (c_irn < size_) { for (UInt j = i; j < values.cols(); ++j) { UInt c_jcn = js(j); if (c_jcn < size_) { operator()(c_irn, c_jcn) += values(i, j); } } } } } /* -------------------------------------------------------------------------- */ inline void SparseMatrixAIJ::addUnsymmetricValuesToSymmetric(const Vector & is, const Vector & js, const Matrix & values) { for (UInt i = 0; i < values.rows(); ++i) { UInt c_irn = is(i); if (c_irn < size_) { for (UInt j = 0; j < values.cols(); ++j) { UInt c_jcn = js(j); if (c_jcn < size_) { if (c_jcn >= c_irn) { operator()(c_irn, c_jcn) += values(i, j); } } } } } } /* -------------------------------------------------------------------------- */ inline void SparseMatrixAIJ::addValuesToUnsymmetric(const Vector & is, const Vector & js, const Matrix & values) { for (UInt i = 0; i < values.rows(); ++i) { UInt c_irn = is(i); if (c_irn < size_) { for (UInt j = 0; j < values.cols(); ++j) { UInt c_jcn = js(j); if (c_jcn < size_) { operator()(c_irn, c_jcn) += values(i, j); } } } } } /* -------------------------------------------------------------------------- */ inline void SparseMatrixAIJ::addValues(const Vector & is, const Vector & js, const Matrix & values, MatrixType values_type) { if (getMatrixType() == _symmetric) if (values_type == _symmetric) this->addSymmetricValuesToSymmetric(is, js, values); else this->addUnsymmetricValuesToSymmetric(is, js, values); else this->addValuesToUnsymmetric(is, js, values); } + +/* -------------------------------------------------------------------------- */ +inline Real SparseMatrixAIJ::min() { + return *std::min(this->a.begin(), this->a.end()); +} + + } // namespace akantu #endif /* __AKANTU_SPARSE_MATRIX_AIJ_INLINE_IMPL_CC__ */