MatrixBackend.hpp 4.3 KB
Newer Older
1
2
#pragma once

3
#include <list>
4
#include <memory>
5
6
#include <string>
#include <vector>
7
8
9
10
11

#include <boost/numeric/mtl/matrix/inserter.hpp>
#include <boost/numeric/mtl/utility/property_map.hpp>
#include <boost/numeric/mtl/utility/range_wrapper.hpp>

12
#include <amdis/Output.hpp>
13
#include <amdis/linearalgebra/SymmetryStructure.hpp>
14
15
16

namespace AMDiS
{
17
  /// \brief The basic container that stores a base matrix
18
19
  template <class TraitsType>
  class MatrixBackend
20
  {
Praetorius, Simon's avatar
Praetorius, Simon committed
21
  public:
22
23
    using Traits = TraitsType;

24
    /// The matrix type of the underlying base matrix
25
    using BaseMatrix = typename Traits::Mat;
26

27
    /// The type of the elements of the DOFMatrix
28
    using value_type = typename BaseMatrix::value_type;
29

30
31
32
    /// The index/size - type
    using size_type = typename BaseMatrix::size_type;

33
    /// The type of the inserter used when filling the matrix. NOTE: need not be public
34
    using Inserter = mtl::mat::inserter<BaseMatrix, mtl::operations::update_plus<value_type>>;
35

36
37
  public:
    /// Constructor. Constructs new BaseMatrix.
38
    MatrixBackend(std::shared_ptr<typename Traits::Comm> const&) {}
39

40
    /// Return a reference to the data-matrix \ref matrix
41
    BaseMatrix& matrix()
42
    {
43
      assert( !inserter_ );
44
      return matrix_;
45
    }
46

47
    /// Return a reference to the data-matrix \ref matrix
48
    BaseMatrix const& matrix() const
49
    {
50
      assert( !inserter_ );
51
      return matrix_;
52
    }
53

54
    /// Create inserter. Assumes that no inserter is currently active on this matrix.
55
    template <class RowBasis, class ColBasis>
56
    void init(RowBasis const& rowBasis, ColBasis const& colBasis, SymmetryStructure symmetry)
57
    {
58
      test_exit(!inserter_, "Matrix already in insertion mode!");
59

60
      calculateSlotSize();
61
      matrix_.change_dim(rowBasis.dimension(), colBasis.dimension());
62
63
64
65
      set_to_zero(matrix_);

      inserter_ = new Inserter(matrix_, slotSize_);
      symmetry_ = symmetry;
66
67
    }

68
    /// Delete inserter -> finish insertion. Must be called in order to fill the
69
    /// final construction of the matrix.
70
71
    void finish()
    {
72
      delete inserter_;
73
      inserter_ = nullptr;
74
    }
75

76

Praetorius, Simon's avatar
Praetorius, Simon committed
77
    /// \brief Returns an update-proxy of the inserter, to insert/update a value at
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    /// position (\p r, \p c) in the matrix. Need an insertionMode inserter, that can
    /// be created by \ref init and must be closed by \ref finish after insertion.
    void insert(size_type r, size_type c, value_type const& value)
    {
      test_exit_dbg(inserter_, "Inserter not initilized!");
      test_exit_dbg(r < num_rows(matrix_) && c < num_cols(matrix_),
          "Indices out of range [0,{})x[0,{})", num_rows(matrix_), num_cols(matrix_));
      if (value != value_type(0) || r == c)
        (*inserter_)[r][c] += value;
    }

    template <class Ind, class LocalMat>
    void scatter(Ind const& idx, LocalMat const& mat)
    {
      scatter(idx, idx, mat);
    }

    template <class RowInd, class ColInd, class LocalMat>
    void scatter(RowInd const& rows, ColInd const& cols, LocalMat const& mat)
    {
      test_exit_dbg(inserter_, "Inserter not initilized!");
      for (size_type i = 0; i < size_type(rows.size()); ++i)
        for (size_type j = 0; j < size_type(cols.size()); ++j)
          if (mat[i][j] != value_type(0) || i == j)
            (*inserter_)[rows[i]][cols[j]] += mat[i][j];
    }

105
    /// Return the number of nonzeros in the matrix
106
    std::size_t nnz() const
107
    {
108
      return matrix_.nnz();
109
    }
110

111
112
113
114
115
    SymmetryStructure symmetry() const
    {
      return symmetry_;
    }

116
117
118
  protected:
    // Estimates the slot-size used in the inserter to reserve enough space per row.
    void calculateSlotSize()
119
    {
120
      slotSize_ = 0;
121

122
123
      if (num_rows(matrix_) != 0)
        slotSize_ = int(double(matrix_.nnz()) / num_rows(matrix_) * 1.2);
124
125
      if (slotSize_ < MIN_NNZ_PER_ROW)
        slotSize_ = MIN_NNZ_PER_ROW;
126
    }
127

128
  private:
129
    /// The minimal number of nonzeros per row
130
    static constexpr int MIN_NNZ_PER_ROW = 50;
131

132
    /// The data-matrix (can hold a new BaseMatrix or a pointer to external data
133
    BaseMatrix matrix_;
134

135
    /// A pointer to the inserter. Created in \ref init and destroyed in \ref finish
136
    Inserter* inserter_ = nullptr;
137

138
    /// The size of the slots used to insert values per row
139
    int slotSize_ = MIN_NNZ_PER_ROW;
140

141
142
    SymmetryStructure symmetry_ = SymmetryStructure::unknown;
  };
143

144
} // end namespace AMDiS