Skip to content
Snippets Groups Projects
Select Git revision
  • 344591351adf4b47decc426f7c32c2727298be7c
  • develop default protected
  • feature/gmsh-reader
  • origin/stage/bouguettaia
  • feature/kinetic-schemes
  • feature/reconstruction
  • feature/local-dt-fsi
  • feature/composite-scheme-sources
  • feature/composite-scheme-other-fluxes
  • feature/serraille
  • feature/variational-hydro
  • feature/composite-scheme
  • hyperplastic
  • feature/polynomials
  • feature/gks
  • feature/implicit-solver-o2
  • feature/coupling_module
  • feature/implicit-solver
  • feature/merge-local-dt-fsi
  • master protected
  • feature/escobar-smoother
  • v0.5.0 protected
  • v0.4.1 protected
  • v0.4.0 protected
  • v0.3.0 protected
  • v0.2.0 protected
  • v0.1.0 protected
  • Kidder
  • v0.0.4 protected
  • v0.0.3 protected
  • v0.0.2 protected
  • v0 protected
  • v0.0.1 protected
33 results

CRSMatrixDescriptor.hpp

Blame
    • Stéphane Del Pino's avatar
      34459135
      Replace SparseMatrixDescriptor by CRSMatrixDescriptor · 34459135
      Stéphane Del Pino authored
      The new class is meant to be much faster
      - it requires an estimation of the number values per row
      - if the number of stored values per line exceeds the reserved one, an
      a special storage zone (per row) is used.
      
      It is important to give a precise estimation of the number of values
      per rows:
      - if the provided expected number of values is too small with regard
      to the real number of values stored for a given row, then building
      performances can be noticeably affected
      - if the provided expected number of values per row corresponds
      exactly to the effective number of stored values, then the
      construction of the CRSMatrix costs nothing.
      
      In the later case, one benefits from a significant CPU and memory
      costs reduction.
      34459135
      History
      Replace SparseMatrixDescriptor by CRSMatrixDescriptor
      Stéphane Del Pino authored
      The new class is meant to be much faster
      - it requires an estimation of the number values per row
      - if the number of stored values per line exceeds the reserved one, an
      a special storage zone (per row) is used.
      
      It is important to give a precise estimation of the number of values
      per rows:
      - if the provided expected number of values is too small with regard
      to the real number of values stored for a given row, then building
      performances can be noticeably affected
      - if the provided expected number of values per row corresponds
      exactly to the effective number of stored values, then the
      construction of the CRSMatrix costs nothing.
      
      In the later case, one benefits from a significant CPU and memory
      costs reduction.
    CRSMatrixDescriptor.hpp 7.67 KiB
    #ifndef CRS_MATRIX_DESCRIPTOR_HPP
    #define CRS_MATRIX_DESCRIPTOR_HPP
    
    #include <algebra/CRSMatrix.hpp>
    #include <utils/Array.hpp>
    #include <utils/Exceptions.hpp>
    
    #include <map>
    
    template <typename DataType = double, typename IndexType = int>
    class CRSMatrixDescriptor
    {
     public:
      using index_type = IndexType;
      using data_type  = DataType;
    
      static_assert(std::is_integral_v<IndexType>);
    
     private:
      const IndexType m_nb_rows;
      const IndexType m_nb_columns;
    
      Array<const IndexType> m_row_map;
      Array<data_type> m_values;
      Array<IndexType> m_column_indices;
    
      Array<IndexType> m_nb_values_per_row;
      Array<std::map<IndexType, DataType>> m_overflow_per_row;
    
      Array<const IndexType>
      _computeRowMap(const Array<IndexType>& non_zeros) const
      {
        Assert(non_zeros.size() - m_nb_rows == 0);
    
        Array<IndexType> row_map(m_nb_rows + 1);
        row_map[0] = 0;
        for (IndexType i = 0; i < m_nb_rows; ++i) {
          row_map[i + 1] = row_map[i] + non_zeros[i];
        }
    
        return row_map;
      }
    
     public:
      IndexType
      numberOfRows() const
      {
        return m_nb_rows;
      }
    
      IndexType
      numberOfColumns() const
      {
        return m_nb_columns;
      }
    
      bool PUGS_INLINE
      hasOverflow() const
      {
        for (IndexType i = 0; i < m_nb_rows; ++i) {
          if (m_overflow_per_row[i].size() > 0) {
            return true;
          }
        }
        return false;
      }
    
      bool PUGS_INLINE
      isFilled() const
      {
        for (IndexType i = 0; i < m_nb_rows; ++i) {
          if (m_nb_values_per_row[i] < m_row_map[i + 1] - m_row_map[i]) {
            return false;
          }
        }
        return true;
      }
    
      friend PUGS_INLINE std::ostream&
      operator<<(std::ostream& os, const CRSMatrixDescriptor& A)
      {
        for (IndexType i = 0; i < A.m_nb_rows; ++i) {
          const auto& overflow_row = A.m_overflow_per_row[i];
          os << i << "|";
    
          if (A.m_nb_values_per_row[i] > 0) {
            IndexType j     = 0;
            auto i_overflow = overflow_row.begin();
            while (j < A.m_nb_values_per_row[i] or i_overflow != overflow_row.end()) {
              const IndexType j_index = [&] {
                if (j < A.m_nb_values_per_row[i]) {
                  return A.m_column_indices[A.m_row_map[i] + j];
                } else {
                  return std::numeric_limits<IndexType>::max();
                }
              }();
    
              const IndexType overflow_index = [&] {
                if (i_overflow != overflow_row.end()) {
                  return i_overflow->first;
                } else {
                  return std::numeric_limits<IndexType>::max();
                }
              }();
    
              if (j_index < overflow_index) {
                os << ' ' << A.m_column_indices[A.m_row_map[i] + j] << ':' << A.m_values[A.m_row_map[i] + j];
                ++j;
              } else {
                os << ' ' << i_overflow->first << ':' << i_overflow->second;
                ++i_overflow;
              }
            }
          }
    
          os << '\n';
        }
        return os;
      }
    
      [[nodiscard]] PUGS_INLINE DataType&
      operator()(const IndexType i, const IndexType j)
      {
        Assert(i < m_nb_rows, "invalid row index");
        Assert(j < m_nb_columns, "invalid column index");
    
        const IndexType row_start = m_row_map[i];
        const IndexType row_end   = m_row_map[i + 1];
    
        IndexType position_candidate = 0;
        bool found                   = false;
        for (IndexType i_row = 0; i_row < m_nb_values_per_row[i]; ++i_row) {
          if (m_column_indices[row_start + i_row] > j) {
            position_candidate = i_row;
            break;
          } else {
            if (m_column_indices[row_start + i_row] == j) {
              position_candidate = i_row;
              found              = true;
              break;
            } else {
              ++position_candidate;
            }
          }
        }
    
        if (not found) {
          if (m_nb_values_per_row[i] < row_end - row_start) {
            for (IndexType i_shift = 0; i_shift < m_nb_values_per_row[i] - position_candidate; ++i_shift) {
              Assert(std::make_signed_t<IndexType>(row_start + m_nb_values_per_row[i]) -
                       std::make_signed_t<IndexType>(i_shift + 1) >=
                     0);
              const IndexType i_destination = row_start + m_nb_values_per_row[i] - i_shift;
              const IndexType i_source      = i_destination - 1;
    
              m_column_indices[i_destination] = m_column_indices[i_source];
              m_values[i_destination]         = m_values[i_source];
            }
    
            m_column_indices[row_start + position_candidate] = j;
            m_values[row_start + position_candidate]         = 0;
            ++m_nb_values_per_row[i];
    
            return m_values[row_start + position_candidate];
          } else {
            auto& overflow_row = m_overflow_per_row[i];
    
            auto iterator = overflow_row.insert(std::make_pair(j, DataType{0})).first;
    
            return iterator->second;
          }
        } else {
          return m_values[row_start + position_candidate];
        }
      }
    
      CRSMatrix<DataType, IndexType>
      getCRSMatrix() const
      {
        const bool is_filled    = this->isFilled();
        const bool has_overflow = this->hasOverflow();
        if (is_filled and not has_overflow) {
          return CRSMatrix<DataType, IndexType>{m_nb_rows, m_nb_columns, m_row_map, m_values, m_column_indices};
        } else {
          std::cout << rang::fgB::yellow << "warning:" << rang::style::reset
                    << " CRSMatrix profile was not properly set:\n";
          if (not is_filled) {
            std::cout << "- some rows are " << rang::style::bold << "too long" << rang::style::reset << '\n';
          }
          if (has_overflow) {
            std::cout << "- some rows are " << rang::style::bold << "too short" << rang::style::reset << '\n';
          }
    
          Array<IndexType> row_map(m_nb_rows + 1);
    
          row_map[0] = 0;
          for (IndexType i = 0; i < m_nb_rows; ++i) {
            row_map[i + 1] = row_map[i] + m_nb_values_per_row[i] + m_overflow_per_row[i].size();
          }
    
          IndexType nb_values = row_map[row_map.size() - 1];
    
          Array<data_type> values(nb_values);
          Array<IndexType> column_indices(nb_values);
    
          IndexType l = 0;
          for (IndexType i = 0; i < m_nb_rows; ++i) {
            const auto& overflow_row = m_overflow_per_row[i];
    
            if (m_nb_values_per_row[i] > 0) {
              IndexType j     = 0;
              auto i_overflow = overflow_row.begin();
              while (j < m_nb_values_per_row[i] or i_overflow != overflow_row.end()) {
                const IndexType j_index = [&] {
                  if (j < m_nb_values_per_row[i]) {
                    return m_column_indices[m_row_map[i] + j];
                  } else {
                    return std::numeric_limits<IndexType>::max();
                  }
                }();
    
                const IndexType overflow_index = [&] {
                  if (i_overflow != overflow_row.end()) {
                    return i_overflow->first;
                  } else {
                    return std::numeric_limits<IndexType>::max();
                  }
                }();
    
                if (j_index < overflow_index) {
                  column_indices[l] = m_column_indices[m_row_map[i] + j];
                  values[l]         = m_values[m_row_map[i] + j];
                  ++j;
    
                } else {
                  column_indices[l] = i_overflow->first;
                  values[l]         = i_overflow->second;
                  ++i_overflow;
                }
                ++l;
              }
            }
          }
    
          return CRSMatrix<DataType, IndexType>{m_nb_rows, m_nb_columns, row_map, values, column_indices};
        }
      }
    
      CRSMatrixDescriptor(const IndexType nb_rows, const IndexType nb_columns, const Array<IndexType>& non_zeros)
        : m_nb_rows{nb_rows},
          m_nb_columns{nb_columns},
          m_row_map{this->_computeRowMap(non_zeros)},
          m_values(m_row_map[m_row_map.size() - 1]),
          m_column_indices(m_row_map[m_row_map.size() - 1]),
          m_nb_values_per_row(m_nb_rows),
          m_overflow_per_row(m_nb_rows)
      {
        m_nb_values_per_row.fill(0);
        m_values.fill(0);
      }
    
      ~CRSMatrixDescriptor() = default;
    };
    
    #endif   // CRS_MATRIX_DESCRIPTOR_HPP