iterative-solver 0.0
 
Loading...
Searching...
No Matches
Matrix.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_SUBSPACE_MATRIX_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_SUBSPACE_MATRIX_H
3#include <molpro/linalg/scalar_traits.h>
4
5#include <algorithm>
6#include <cassert>
7#include <cstddef>
8#include <format>
9#include <iomanip>
10#include <sstream>
11#include <stdexcept>
12#include <string_view>
13#include <utility>
14#include <vector>
15
17
18// FIXME Since we are only supporting a few underlying data types Matrix should not be header only
19// FIXME Usage of Eigen for matrix would not be as catastrophic now that the headers are separated
31template <typename T>
32class Matrix {
33protected:
34 class Slice;
35 class CSlice;
36
37public:
38 using value_type = T;
40 using coord_type = std::pair<size_t, size_t>;
41
42public:
45 explicit Matrix(std::vector<T>&& data, coord_type dims)
47 if (m_buffer.size() != size())
48 throw std::runtime_error("data buffer is of the wrong size");
49 }
50 explicit Matrix(const std::vector<T>& data, coord_type dims)
52 if (m_buffer.size() != size())
53 throw std::runtime_error("data buffer is of the wrong size");
54 }
55 Matrix() = default;
56 ~Matrix() = default;
57 Matrix(const Matrix<T>&) = default;
61
64
66 T operator()(index_type i, index_type j) const { return m_buffer[i * m_cols + j]; }
67
69 const std::vector<T>& data() const& { return m_buffer; }
71 std::vector<T>&& data() && {
72 m_rows = 0;
73 m_cols = 0;
74 return std::move(m_buffer);
75 }
76
78 bool empty() const { return size() == 0; }
79
81 void clear() { resize({0, 0}); }
82
84 coord_type to_coord(size_t ind) const {
85 if (ind >= size())
86 throw std::out_of_range("index is larger than size");
87 auto row = ind / m_cols;
88 auto col = ind - row * m_cols;
89 return {row, col};
90 }
91
93 void fill(T value) { std::fill(begin(m_buffer), end(m_buffer), value); }
94
102 return Slice(*this, std::move(upper_left), std::move(bottom_right));
103 }
104
106 Slice slice() { return slice({0, 0}, dimensions()); }
107
115 return CSlice(*this, std::move(upper_left), std::move(bottom_right));
116 }
117
119 CSlice slice() const { return slice({0, 0}, dimensions()); }
120
122 Slice row(size_t i) { return slice({i, 0}, {i + 1, m_cols}); }
123 CSlice row(size_t i) const { return slice({i, 0}, {i + 1, m_cols}); }
124
126 Slice col(size_t j) { return slice({0, j}, {m_rows, j + 1}); }
127 CSlice col(size_t j) const { return slice({0, j}, {m_rows, j + 1}); }
128
130 void resize(const coord_type& dims) {
131 if (dims == dimensions())
132 return;
133 if (dims.second == m_cols) {
134 m_rows = dims.first;
135 m_buffer.resize(size());
136 } else {
137 auto m = Matrix<T>(dims);
138 auto upper_left = coord_type{0, 0};
139 auto bottom_right = coord_type{std::min(rows(), m.rows()), std::min(cols(), m.cols())};
141 std::swap(*this, m);
142 }
143 }
144
147 if (row >= m_rows)
148 throw std::runtime_error("row is out of range");
149 slice({row, 0}, {m_rows - 1, m_cols}) = slice({row + 1, 0}, dimensions());
150 resize({m_rows - 1, m_cols});
151 }
152
155 if (col >= m_cols)
156 throw std::runtime_error("column is out of range");
157 auto m = Matrix<T>({m_rows, m_cols - 1});
158 m.slice({0, 0}, {m_rows, col}) = slice({0, 0}, {m_rows, col});
159 m.slice({0, col}, {m_rows, m.m_cols}) = slice({0, col + 1}, dimensions());
160 std::swap(*this, m);
161 }
162
168
169 index_type rows() const { return m_rows; }
170 index_type cols() const { return m_cols; }
172 size_t size() const { return m_rows * m_cols; }
173
174protected:
177 std::vector<T> m_buffer;
178
182 class Slice {
183 public:
185 : mat(matrix), upl(std::move(upper_left)), btr(std::move(bottom_right)) {
186 if (upl.first > btr.first || upl.second > btr.second)
187 throw std::runtime_error("specified incorrect corners");
188 if (upl.first < 0 || upl.second < 0)
189 throw std::runtime_error("slice is out of range");
190 if (btr.first > matrix.rows() || btr.second > matrix.cols())
191 throw std::runtime_error("slice is out of range");
192 }
193 Slice() = delete;
194 ~Slice() = default;
195 Slice(const Slice&) = delete;
198
200 if (dimensions() != right.dimensions())
201 throw std::runtime_error("attempting to copy slices of different dimensions");
202 for (size_t i = 0; i < dimensions().first; ++i) {
203 for (size_t j = 0; j < dimensions().second; ++j) {
204 mat(upl.first + i, upl.second + j) = right.mat(right.upl.first + i, right.upl.second + j);
205 }
206 }
207 return *this;
208 }
209
210 T& operator()(size_t i, size_t j) { return mat(upl.first + i, upl.second + j); }
211 T operator()(size_t i, size_t j) const { return mat(upl.first + i, upl.second + j); }
212
213 Slice& axpy(T a, const Slice& x) {
214 if (dimensions() != x.dimensions())
215 throw std::runtime_error("attempting to copy slices of different dimensions");
216 for (size_t i = 0; i < dimensions().first; ++i) {
217 for (size_t j = 0; j < dimensions().second; ++j) {
218 mat(upl.first + i, upl.second + j) += a * x.mat(x.upl.first + i, x.upl.second + j);
219 }
220 }
221 return *this;
222 }
223
224 Slice& axpy(T a, const CSlice& x) {
225 axpy(a, x.m_slice);
226 return *this;
227 }
228
231 for (size_t i = 0; i < dimensions().first; ++i)
232 for (size_t j = 0; j < dimensions().second; ++j)
233 mat(upl.first + i, upl.second + j) *= a;
234 return *this;
235 }
236
239 for (size_t i = 0; i < dimensions().first; ++i)
240 for (size_t j = 0; j < dimensions().second; ++j)
241 mat(upl.first + i, upl.second + j) = a;
242 return *this;
243 }
244
246 *this = right.m_slice;
247 return *this;
248 }
249
251 *this = right.slice({0, 0}, right.dimensions());
252 return *this;
253 }
254
255 coord_type dimensions() const { return {btr.first - upl.first, btr.second - upl.second}; }
256 size_t rows() const { return btr.first - upl.first; }
257 size_t cols() const { return btr.second - upl.second; }
258
259 protected:
263 };
264
266 class CSlice {
267 friend Slice;
268
269 public:
272 CSlice() = delete;
273 ~CSlice() = default;
274 CSlice(const CSlice&) = delete;
277 T operator()(size_t i, size_t j) const { return const_cast<Slice&>(m_slice)(i, j); }
278
279 protected:
281 };
282};
283
284template <class ML, class MR>
285void transpose_copy(ML&& ml, const MR& mr) {
286 assert(ml.rows() == mr.cols() && ml.cols() == mr.rows());
287 for (size_t i = 0; i < ml.rows(); ++i)
288 for (size_t j = 0; j < ml.cols(); ++j)
289 ml(i, j) = mr(j, i);
290}
291
298template <class ML, class MR>
300 assert(ml.rows() == mr.cols() && ml.cols() == mr.rows());
301 for (size_t i = 0; i < ml.rows(); ++i)
302 for (size_t j = 0; j < ml.cols(); ++j)
304}
305
306template <class Mat>
307std::string as_string(const Mat& m, int precision = 6) {
308 auto s = std::stringstream{};
309 s << std::setprecision(precision);
310 auto dims = m.dimensions();
311 if (dims.first * dims.second != 0) {
312 s << "\n[";
313 for (size_t i = 0; i < dims.first; ++i) {
314 s << "[";
315 for (size_t j = 0; j < dims.second; ++j) {
316 s << m(i, j);
317 if (j != dims.second - 1)
318 s << ", ";
319 }
320 s << "]";
321 if (i != dims.first - 1)
322 s << ",\n ";
323 }
324 s << "]";
325 } else {
326 s << "[[]]";
327 }
328 return s.str();
329}
330
331} // namespace molpro::linalg::itsolv::subspace
332
333template<typename T>
334struct std::formatter<molpro::linalg::itsolv::subspace::Matrix<T>> : std::formatter<std::string_view> {
335 using Base = std::formatter<std::string_view>;
336
337 std::size_t precision = 6;
338
339 constexpr auto parse(std::format_parse_context &ctx) {
340 auto it = ctx.begin();
341
342 if (it == ctx.end()) {
343 return it;
344 }
345
346 if (*it != '.') {
347 return Base::parse(ctx);
348 }
349
350 ++it;
351
352 if (it == ctx.end() || ( *it < '0' && *it > '9' )) {
353 throw std::format_error("Format string uses precision quantifier '.' without giving a (numeric) precision");
354 }
355
356 // Parse specified precision
357 // Unfortunately, the stdlib doesn't have a constexpr function for this until C++23
358 precision = 0;
359 while (it != ctx.end() && ( *it >= '0' && *it <= '9' )) {
360 precision *= 10;
361 precision += *it - '0';
362 ++it;
363 }
364
365 // Interpret remaining format context as specification for std::string_view formatter
366 ctx.advance_to(it);
367 return Base::parse(ctx);
368 }
369
370 auto format(const molpro::linalg::itsolv::subspace::Matrix<T> &mat, std::format_context &ctx) const {
371 std::string tmp = molpro::linalg::itsolv::subspace::as_string(mat, precision);
372
373 return Base::format(tmp, ctx);
374 }
375};
376
377#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ITSOLV_SUBSPACE_MATRIX_H
Constant slice that cannot be assigned to.
Definition Matrix.h:266
CSlice(const Matrix< T > &matrix, coord_type upper_left, coord_type bottom_right)
Definition Matrix.h:270
Proxy mapping to a rectangular slice of the matrix data. Implements simple assignment.
Definition Matrix.h:182
coord_type upl
upper left corner
Definition Matrix.h:261
Slice & operator=(const CSlice &right)
Definition Matrix.h:245
coord_type dimensions() const
Definition Matrix.h:255
Matrix< T > & mat
matrix being sliced
Definition Matrix.h:260
Slice & fill(T a)
Fill all elements of the slice with new values.
Definition Matrix.h:238
Slice(Matrix< T > &matrix, coord_type upper_left, coord_type bottom_right)
Definition Matrix.h:184
size_t rows() const
Definition Matrix.h:256
T operator()(size_t i, size_t j) const
Definition Matrix.h:211
T & operator()(size_t i, size_t j)
Definition Matrix.h:210
coord_type btr
bottom right corner
Definition Matrix.h:262
Slice & operator=(const Matrix< T > &right)
Definition Matrix.h:250
size_t cols() const
Definition Matrix.h:257
Slice & axpy(T a, const CSlice &x)
Definition Matrix.h:224
Slice & scal(T a)
Scale all elements of the slice.
Definition Matrix.h:230
Slice & axpy(T a, const Slice &x)
Definition Matrix.h:213
Matrix container that allows simple data access, slicing, copying and resizing without loosing data.
Definition Matrix.h:32
Matrix(const std::vector< T > &data, coord_type dims)
Definition Matrix.h:50
index_type m_rows
number of rows
Definition Matrix.h:175
Slice slice()
Access the whole matrix as a slice.
Definition Matrix.h:106
T operator()(index_type i, index_type j) const
Access element.
Definition Matrix.h:66
Slice row(size_t i)
Access row slice.
Definition Matrix.h:122
Slice col(size_t j)
Access column slice.
Definition Matrix.h:126
std::pair< size_t, size_t > coord_type
Definition Matrix.h:40
void remove_row(index_type row)
removes a row from the matrix
Definition Matrix.h:146
Slice slice(coord_type upper_left, coord_type bottom_right)
Access a rectangular slice of the matrix.
Definition Matrix.h:101
std::vector< T > m_buffer
data buffer
Definition Matrix.h:177
void remove_row_col(index_type row, index_type col)
removes row and column
Definition Matrix.h:164
CSlice row(size_t i) const
Definition Matrix.h:123
Matrix(const Matrix< T > &)=default
CSlice col(size_t j) const
Definition Matrix.h:127
CSlice slice(coord_type upper_left, coord_type bottom_right) const
Access a constant rectangular slice of the matrix.
Definition Matrix.h:114
const std::vector< T > & data() const &
Access the underlying data buffer.
Definition Matrix.h:69
void clear()
Clears all elements and sets dimensions to 0.
Definition Matrix.h:81
void remove_col(index_type col)
removes a column from the matrix
Definition Matrix.h:154
coord_type dimensions() const
Definition Matrix.h:171
Matrix(coord_type dims)
Definition Matrix.h:43
size_t size() const
Definition Matrix.h:172
bool empty() const
Returns true if matrix is empty.
Definition Matrix.h:78
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:45
void fill(T value)
Sets all elements of matrix to value.
Definition Matrix.h:93
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:130
CSlice slice() const
Access the whole matrix as a slice.
Definition Matrix.h:119
index_type rows() const
Definition Matrix.h:169
coord_type to_coord(size_t ind) const
Converts index of 1D data to matrix coordinate.
Definition Matrix.h:84
size_t index_type
Definition Matrix.h:39
index_type cols() const
Definition Matrix.h:170
std::vector< T > && data() &&
Access the raw data buffer of an r-value matrix. The matrix is left empty.
Definition Matrix.h:71
index_type m_cols
number of columns
Definition Matrix.h:176
std::string as_string(const Mat &m, int precision=6)
Definition Matrix.h:307
void transpose_copy(ML &&ml, const MR &mr)
Definition Matrix.h:285
void conjugate_transpose_copy(ML &&ml, const MR &mr)
Copies the conjugate transpose of mr into ml.
Definition Matrix.h:299
std::unique_ptr< LinearEigensystem< R, Q, P > > create_LinearEigensystem(const LinearEigensystemOptions &options, const std::shared_ptr< ArrayHandlers< R, Q, P > > &handlers=std::make_shared< molpro::linalg::itsolv::ArrayHandlers< R, Q, P > >())
Definition SolverFactory.h:111
T conjugate(const T &x)
Complex conjugate, staying within the scalar type; the identity for a real type.
Definition scalar_traits.h:47
auto format(const molpro::linalg::itsolv::subspace::Matrix< T > &mat, std::format_context &ctx) const
Definition Matrix.h:370
std::formatter< std::string_view > Base
Definition Matrix.h:335
constexpr auto parse(std::format_parse_context &ctx)
Definition Matrix.h:339