iterative-solver 0.0
Matrix.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_SUBSPACE_MATRIX_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_SUBSPACE_MATRIX_H
3#include <algorithm>
4#include <cassert>
5#include <cstddef>
6#include <iomanip>
7#include <sstream>
8#include <stdexcept>
9#include <utility>
10#include <vector>
11
13
14// FIXME Since we are only supporting a few underlying data types Matrix should not be header only
15// FIXME Usage of Eigen for matrix would not be as catastrophic now that the headers are separated
27template <typename T>
28class Matrix {
29protected:
30 class Slice;
31 class CSlice;
32
33public:
34 using value_type = T;
35 using index_type = size_t;
36 using coord_type = std::pair<size_t, size_t>;
37
38public:
39 explicit Matrix(coord_type dims) : m_rows(dims.first), m_cols(dims.second), m_buffer(m_rows * m_cols) {}
41 explicit Matrix(std::vector<T>&& data, coord_type dims)
42 : m_rows(dims.first), m_cols(dims.second), m_buffer(std::move(data)) {
43 if (m_buffer.size() != size())
44 throw std::runtime_error("data buffer is of the wrong size");
45 }
46 explicit Matrix(const std::vector<T>& data, coord_type dims)
47 : m_rows(dims.first), m_cols(dims.second), m_buffer(data) {
48 if (m_buffer.size() != size())
49 throw std::runtime_error("data buffer is of the wrong size");
50 }
51 Matrix() = default;
52 ~Matrix() = default;
53 Matrix(const Matrix<T>&) = default;
54 Matrix(Matrix<T>&&) noexcept = default;
55 Matrix<T>& operator=(const Matrix<T>&) = default;
56 Matrix<T>& operator=(Matrix<T>&&) noexcept = default;
57
59 T& operator()(index_type i, index_type j) { return m_buffer[i * m_cols + j]; }
60
62 T operator()(index_type i, index_type j) const { return m_buffer[i * m_cols + j]; }
63
65 const std::vector<T>& data() const& { return m_buffer; }
67 std::vector<T>&& data() && {
68 m_rows = 0;
69 m_cols = 0;
70 return std::move(m_buffer);
71 }
72
74 bool empty() const { return size() == 0; }
75
77 void clear() { resize({0, 0}); }
78
80 coord_type to_coord(size_t ind) const {
81 if (ind >= size())
82 throw std::out_of_range("index is larger than size");
83 auto row = ind / m_cols;
84 auto col = ind - row * m_cols;
85 return {row, col};
86 }
87
89 void fill(T value) { std::fill(begin(m_buffer), end(m_buffer), value); }
90
97 Slice slice(coord_type upper_left, coord_type bottom_right) {
98 return Slice(*this, std::move(upper_left), std::move(bottom_right));
99 }
100
102 Slice slice() { return slice({0, 0}, dimensions()); }
103
110 CSlice slice(coord_type upper_left, coord_type bottom_right) const {
111 return CSlice(*this, std::move(upper_left), std::move(bottom_right));
112 }
113
115 CSlice slice() const { return slice({0, 0}, dimensions()); }
116
118 Slice row(size_t i) { return slice({i, 0}, {i + 1, m_cols}); }
119 CSlice row(size_t i) const { return slice({i, 0}, {i + 1, m_cols}); }
120
122 Slice col(size_t j) { return slice({0, j}, {m_rows, j + 1}); }
123 CSlice col(size_t j) const { return slice({0, j}, {m_rows, j + 1}); }
124
126 void resize(const coord_type& dims) {
127 if (dims == dimensions())
128 return;
129 if (dims.second == m_cols) {
130 m_rows = dims.first;
131 m_buffer.resize(size());
132 } else {
133 auto m = Matrix<T>(dims);
134 auto upper_left = coord_type{0, 0};
135 auto bottom_right = coord_type{std::min(rows(), m.rows()), std::min(cols(), m.cols())};
136 m.slice(upper_left, bottom_right) = slice(upper_left, bottom_right);
137 std::swap(*this, m);
138 }
139 }
140
143 if (row >= m_rows)
144 throw std::runtime_error("row is out of range");
145 slice({row, 0}, {m_rows - 1, m_cols}) = slice({row + 1, 0}, dimensions());
146 resize({m_rows - 1, m_cols});
147 }
148
151 if (col >= m_cols)
152 throw std::runtime_error("column is out of range");
153 auto m = Matrix<T>({m_rows, m_cols - 1});
154 m.slice({0, 0}, {m_rows, col}) = slice({0, 0}, {m_rows, col});
155 m.slice({0, col}, {m_rows, m.m_cols}) = slice({0, col + 1}, dimensions());
156 std::swap(*this, m);
157 }
158
163 }
164
165 index_type rows() const { return m_rows; }
166 index_type cols() const { return m_cols; }
168 size_t size() const { return m_rows * m_cols; }
169
170protected:
173 std::vector<T> m_buffer;
174
178 class Slice {
179 public:
180 Slice(Matrix<T>& matrix, coord_type upper_left, coord_type bottom_right)
181 : mat(matrix), upl(std::move(upper_left)), btr(std::move(bottom_right)) {
182 if (upl.first > btr.first || upl.second > btr.second)
183 throw std::runtime_error("specified incorrect corners");
184 if (upl.first < 0 || upl.second < 0)
185 throw std::runtime_error("slice is out of range");
186 if (btr.first > matrix.rows() || btr.second > matrix.cols())
187 throw std::runtime_error("slice is out of range");
188 }
189 Slice() = delete;
190 ~Slice() = default;
191 Slice(const Slice&) = delete;
192 Slice(Slice&&) noexcept = default;
193 Slice& operator=(Slice&&) noexcept = default;
194
195 Slice& operator=(const Slice& right) {
196 if (dimensions() != right.dimensions())
197 throw std::runtime_error("attempting to copy slices of different dimensions");
198 for (size_t i = 0; i < dimensions().first; ++i) {
199 for (size_t j = 0; j < dimensions().second; ++j) {
200 mat(upl.first + i, upl.second + j) = right.mat(right.upl.first + i, right.upl.second + j);
201 }
202 }
203 return *this;
204 }
205
206 T& operator()(size_t i, size_t j) { return mat(upl.first + i, upl.second + j); }
207 T operator()(size_t i, size_t j) const { return mat(upl.first + i, upl.second + j); }
208
209 Slice& axpy(T a, const Slice& x) {
210 if (dimensions() != x.dimensions())
211 throw std::runtime_error("attempting to copy slices of different dimensions");
212 for (size_t i = 0; i < dimensions().first; ++i) {
213 for (size_t j = 0; j < dimensions().second; ++j) {
214 mat(upl.first + i, upl.second + j) += a * x.mat(x.upl.first + i, x.upl.second + j);
215 }
216 }
217 return *this;
218 }
219
220 Slice& axpy(T a, const CSlice& x) {
221 axpy(a, x.m_slice);
222 return *this;
223 }
224
226 Slice& scal(T a) {
227 for (size_t i = 0; i < dimensions().first; ++i)
228 for (size_t j = 0; j < dimensions().second; ++j)
229 mat(upl.first + i, upl.second + j) *= a;
230 return *this;
231 }
232
234 Slice& fill(T a) {
235 for (size_t i = 0; i < dimensions().first; ++i)
236 for (size_t j = 0; j < dimensions().second; ++j)
237 mat(upl.first + i, upl.second + j) = a;
238 return *this;
239 }
240
241 Slice& operator=(const CSlice& right) {
242 *this = right.m_slice;
243 return *this;
244 }
245
246 Slice& operator=(const Matrix<T>& right) {
247 *this = right.slice({0, 0}, right.dimensions());
248 return *this;
249 }
250
251 coord_type dimensions() const { return {btr.first - upl.first, btr.second - upl.second}; }
252 size_t rows() const { return btr.first - upl.first; }
253 size_t cols() const { return btr.second - upl.second; }
254
255 protected:
259 };
260
262 class CSlice {
263 friend Slice;
264
265 public:
266 CSlice(const Matrix<T>& matrix, coord_type upper_left, coord_type bottom_right)
267 : m_slice(const_cast<Matrix<T>&>(matrix), std::move(upper_left), std::move(bottom_right)) {}
268 CSlice() = delete;
269 ~CSlice() = default;
270 CSlice(const CSlice&) = delete;
271 CSlice(CSlice&&) noexcept = default;
272 CSlice& operator=(CSlice&&) = default;
273 T operator()(size_t i, size_t j) const { return const_cast<Slice&>(m_slice)(i, j); }
274
275 protected:
277 };
278};
279
280template <class ML, class MR>
281void transpose_copy(ML&& ml, const MR& mr) {
282 assert(ml.rows() == mr.cols() && ml.cols() == mr.rows());
283 for (size_t i = 0; i < ml.rows(); ++i)
284 for (size_t j = 0; j < ml.cols(); ++j)
285 ml(i, j) = mr(j, i);
286}
287
288template <class Mat>
289std::string as_string(const Mat& m, int precision = 6) {
290 auto s = std::stringstream{};
291 s << std::setprecision(precision);
292 auto dims = m.dimensions();
293 if (dims.first * dims.second != 0) {
294 s << "\n[";
295 for (size_t i = 0; i < dims.first; ++i) {
296 s << "[";
297 for (size_t j = 0; j < dims.second; ++j) {
298 s << m(i, j);
299 if (j != dims.second - 1)
300 s << ", ";
301 }
302 s << "]";
303 if (i != dims.first - 1)
304 s << ",\n ";
305 }
306 s << "]";
307 } else {
308 s << "[[]]";
309 }
310 return s.str();
311}
312
313} // namespace molpro::linalg::itsolv::subspace
314
315#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_SUBSPACE_MATRIX_H
Constant slice that cannot be assigned to.
Definition: Matrix.h:262
CSlice(const Matrix< T > &matrix, coord_type upper_left, coord_type bottom_right)
Definition: Matrix.h:266
Proxy mapping to a rectangular slice of the matrix data. Implements simple assignment.
Definition: Matrix.h:178
coord_type upl
upper left corner
Definition: Matrix.h:257
Slice & operator=(const CSlice &right)
Definition: Matrix.h:241
coord_type dimensions() const
Definition: Matrix.h:251
Matrix< T > & mat
matrix being sliced
Definition: Matrix.h:256
Slice & fill(T a)
Fill all elements of the slice with new values.
Definition: Matrix.h:234
Slice(Matrix< T > &matrix, coord_type upper_left, coord_type bottom_right)
Definition: Matrix.h:180
size_t rows() const
Definition: Matrix.h:252
T operator()(size_t i, size_t j) const
Definition: Matrix.h:207
T & operator()(size_t i, size_t j)
Definition: Matrix.h:206
coord_type btr
bottom right corner
Definition: Matrix.h:258
Slice & operator=(const Matrix< T > &right)
Definition: Matrix.h:246
size_t cols() const
Definition: Matrix.h:253
Slice & axpy(T a, const CSlice &x)
Definition: Matrix.h:220
Slice & scal(T a)
Scale all elements of the slice.
Definition: Matrix.h:226
Slice & axpy(T a, const Slice &x)
Definition: Matrix.h:209
Matrix container that allows simple data access, slicing, copying and resizing without loosing data.
Definition: Matrix.h:28
Matrix(const std::vector< T > &data, coord_type dims)
Definition: Matrix.h:46
index_type m_rows
number of rows
Definition: Matrix.h:171
Slice slice()
Access the whole matrix as a slice.
Definition: Matrix.h:102
T operator()(index_type i, index_type j) const
Access element.
Definition: Matrix.h:62
Slice row(size_t i)
Access row slice.
Definition: Matrix.h:118
T value_type
Definition: Matrix.h:34
Slice col(size_t j)
Access column slice.
Definition: Matrix.h:122
std::pair< size_t, size_t > coord_type
Definition: Matrix.h:36
void remove_row(index_type row)
removes a row from the matrix
Definition: Matrix.h:142
Slice slice(coord_type upper_left, coord_type bottom_right)
Access a rectangular slice of the matrix.
Definition: Matrix.h:97
std::vector< T > m_buffer
data buffer
Definition: Matrix.h:173
void remove_row_col(index_type row, index_type col)
removes row and column
Definition: Matrix.h:160
CSlice row(size_t i) const
Definition: Matrix.h:119
Matrix(const Matrix< T > &)=default
CSlice col(size_t j) const
Definition: Matrix.h:123
CSlice slice(coord_type upper_left, coord_type bottom_right) const
Access a constant rectangular slice of the matrix.
Definition: Matrix.h:110
const std::vector< T > & data() const &
Access the underlying data buffer.
Definition: Matrix.h:65
void clear()
Clears all elements and sets dimensions to 0.
Definition: Matrix.h:77
void remove_col(index_type col)
removes a column from the matrix
Definition: Matrix.h:150
coord_type dimensions() const
Definition: Matrix.h:167
Matrix(coord_type dims)
Definition: Matrix.h:39
size_t size() const
Definition: Matrix.h:168
bool empty() const
Returns true if matrix is empty.
Definition: Matrix.h:74
Matrix(std::vector< T > &&data, coord_type dims)
Construct a matrix by taking ownership of an existing data buffer which must be of correct size.
Definition: Matrix.h:41
void fill(T value)
Sets all elements of matrix to value.
Definition: Matrix.h:89
Matrix(Matrix< T > &&) noexcept=default
void resize(const coord_type &dims)
Resize the matrix. The old data is preserved and any new rows/cols are zeroed.
Definition: Matrix.h:126
CSlice slice() const
Access the whole matrix as a slice.
Definition: Matrix.h:115
index_type rows() const
Definition: Matrix.h:165
coord_type to_coord(size_t ind) const
Converts index of 1D data to matrix coordinate.
Definition: Matrix.h:80
size_t index_type
Definition: Matrix.h:35
index_type cols() const
Definition: Matrix.h:166
std::vector< T > && data() &&
Access the raw data buffer of an r-value matrix. The matrix is left empty.
Definition: Matrix.h:67
index_type m_cols
number of columns
Definition: Matrix.h:172
Definition: PSpace.h:7
std::string as_string(const Mat &m, int precision=6)
Definition: Matrix.h:289
void transpose_copy(ML &&ml, const MR &mr)
Definition: Matrix.h:281