Mantid
Loading...
Searching...
No Matches
EigenMatrix.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
11#include <iostream>
12
13namespace Mantid::CurveFitting {
14
18EigenMatrix::EigenMatrix(const size_t nx, const size_t ny)
19 : m_data(nx * ny), m_view(EigenMatrix_View(m_data.data(), nx, ny)) {}
20
27EigenMatrix::EigenMatrix(std::initializer_list<std::initializer_list<double>> ilist)
28 : EigenMatrix(ilist.size(), ilist.begin()->size()) {
29 for (auto row = ilist.begin(); row != ilist.end(); ++row) { // loop through row by row
30 if (row->size() != size2()) { // check number of cells in row equals number of cols
31 throw std::runtime_error("All rows in initializer list must have the same size.");
32 }
33 auto i = static_cast<size_t>(std::distance(ilist.begin(), row));
34 for (auto cell = row->begin(); cell != row->end(); ++cell) {
35 auto j = static_cast<size_t>(std::distance(row->begin(), cell));
36 set(i, j, *cell);
37 }
38 }
39}
40
44 : m_data(M.m_data), m_view(EigenMatrix_View(m_data.data(), M.size1(), M.size2())) {}
45
52EigenMatrix::EigenMatrix(EigenMatrix &M, size_t row, size_t col, size_t nRows, size_t nCols) {
53 if (row + nRows > M.size1() || col + nCols > M.size2()) {
54 throw std::runtime_error("Submatrix exceeds matrix size.");
55 }
56 size_t newSize = nRows * nCols;
57 m_data.resize(newSize);
58 m_view = EigenMatrix_View(M.mutator(), nRows, nCols, row, col);
59 std::copy(M.mutator().data(), M.mutator().data() + newSize, m_data.data());
60}
61
65 : m_data(M.numRows() * M.numCols()), m_view(EigenMatrix_View(m_data.data(), M.numRows(), M.numCols())) {
66
67 // Mantid::Kernel::Matrix stores row by row, so have to transpose initial matrix.
68 // To do this we copy into an eign matrix, then tranpose.
69 auto tempVec = M.getVector();
70 Eigen::MatrixXd tempMatrTr = EigenMatrix_View(tempVec.data(), M.numCols(), M.numRows()).matrix_mutator();
71 Eigen::MatrixXd tempMatr = tempMatrTr.transpose();
72 std::copy(tempMatr.data(), tempMatr.data() + tempMatr.size(), m_data.data());
73}
74
81EigenMatrix::EigenMatrix(const Kernel::Matrix<double> &M, size_t row, size_t col, size_t nRows, size_t nCols) {
82 if (row + nRows > M.numRows() || col + nCols > M.numCols()) {
83 throw std::runtime_error("Submatrix exceeds matrix size.");
84 }
85 resize(nRows, nCols);
86
87 // Mantid::Kernel::Matrix stores row by row, so have to transpose initial matrix before taking view.
88 // To do this we copy into an eign matrix, tranpose, then take a sub matrix.
89 auto tempVec = M.getVector();
90 Eigen::MatrixXd tempMatrTr = EigenMatrix_View(tempVec.data(), M.numCols(), M.numRows()).matrix_mutator();
91 Eigen::MatrixXd tempMatr = tempMatrTr.transpose();
92 auto tempMatrSubView = EigenMatrix_View(tempMatr.data(), tempMatr.rows(), tempMatr.cols(), nRows, nCols, row, col);
93 Eigen::MatrixXd tempMatrSub = tempMatrSubView.matrix_inspector();
94 std::copy(tempMatrSub.data(), tempMatrSub.data() + tempMatrSub.size(), m_data.data());
95}
96
98EigenMatrix::EigenMatrix(std::vector<double> &&data, size_t nx, size_t ny)
99 : m_data(std::move(data)), m_view(EigenMatrix_View(m_data.data(), nx, ny)) {}
100
103 m_data = M.m_data;
104 m_view = EigenMatrix_View(m_data.data(), M.size1(), M.size2());
105 return *this;
106}
107
109EigenMatrix &EigenMatrix::operator=(const Eigen::MatrixXd m) {
110 m_data.resize(m.rows() * m.cols());
111 for (size_t i = 0; i < (size_t)m.size(); i++) {
112 m_data[i] = *(m.data() + i);
113 }
114 m_view = EigenMatrix_View(m_data.data(), m.rows(), m.cols());
115 return *this;
116}
117
119bool EigenMatrix::isEmpty() const { return m_data.empty(); }
120
124void EigenMatrix::resize(const size_t nx, const size_t ny) {
125 if (nx == 0 && ny == 0) {
126 // Matrix as minimum is 1x1, retained from gsl for consistency.
127 m_data.resize(2);
128 m_view = EigenMatrix_View(m_data.data(), 1, 1);
129
130 } else {
131 m_data.resize(nx * ny);
132 m_view = EigenMatrix_View(m_data.data(), nx, ny);
133 }
134}
135
137size_t EigenMatrix::size1() const { return m_view.rows(); }
138
140size_t EigenMatrix::size2() const { return m_view.cols(); }
141
146void EigenMatrix::set(size_t i, size_t j, double value) {
147 if (isEmpty()) {
148 throw std::out_of_range("Matrix is empty.");
149 }
150 if (i < m_view.rows() && j < m_view.cols())
151 m_view.matrix_mutator()(i, j) = value;
152 else {
153 throw std::out_of_range("EigenMatrix indices are out of range.");
154 }
155}
156
160double EigenMatrix::get(size_t i, size_t j) const {
161 if (isEmpty()) {
162 throw std::out_of_range("Matrix is empty.");
163 }
164 if (i < m_view.rows() && j < m_view.cols())
165 return m_view.matrix_inspector()(i, j);
166 else {
167 throw std::out_of_range("EigenMatrix indices are out of range.");
168 }
169}
170
172void EigenMatrix::identity() { m_view.matrix_mutator().setIdentity(); }
173
176
180 const auto n = d.size();
181 resize(n, n);
182 zero();
183 for (size_t i = 0; i < n; ++i) {
184 set(i, i, d.get(i));
185 }
186}
187
192 return *this;
193}
197 m_view.matrix_mutator().array() += d;
198 return *this;
199}
204 return *this;
205}
209 m_view.matrix_mutator().array() -= d;
210 return *this;
211}
216 return *this;
217}
218
225 if (v.size() != size2()) {
226 throw std::invalid_argument("Matrix by vector multiplication: wrong size of vector.");
227 }
228
229 EigenVector res;
230 res = inspector() * v.inspector();
231 return res;
232}
233
240 if (m.size1() != size2()) {
241 throw std::invalid_argument("Matrix by matrix multiplication: matricies are of incompatible sizes.");
242 }
243
244 EigenMatrix res;
245 res = inspector() * m.inspector();
246 return res;
247}
248
255 if (size1() != size2()) {
256 throw std::invalid_argument("System of linear equations: the matrix must be square.");
257 }
258 size_t n = size1();
259 if (rhs.size() != n) {
260 throw std::invalid_argument("System of linear equations: right-hand side vector has wrong size.");
261 }
262 if (det() == 0) {
263 throw std::invalid_argument("Matrix A is singular.");
264 }
265
266 Eigen::MatrixXd b = rhs.inspector();
267 Eigen::ColPivHouseholderQR<Eigen::MatrixXd> dec(inspector());
268 auto res = dec.solve(b);
269 x = res;
270
271 // Commented out soltution error, as gsl implementation didn't provide this.
272 // if (!rhs.inspector().isApprox(inspector() * x.inspector())) {
273 // //throw std::runtime_error("Matrix Solution Error: solution does not exist.");
274 //}
275}
276
279 if (size1() != size2()) {
280 throw std::runtime_error("Matrix inverse: the matrix must be square.");
281 }
282 mutator() = inspector().inverse();
283}
284
286double EigenMatrix::det() const {
287 if (size1() != size2()) {
288 throw std::runtime_error("Matrix inverse: the matrix must be square.");
289 }
290
291 return inspector().determinant();
292}
293
299void EigenMatrix::eigenSystem(EigenVector &eigenValues, EigenMatrix &eigenVectors) {
300 size_t n = size1();
301 if (n != size2()) {
302 throw std::runtime_error("Matrix eigenSystem: the matrix must be square.");
303 }
304
305 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> solver;
306 solver.compute(inspector());
307
308 // previously gsl used "gsl_eigen_symmv" to calculate the eigenSystem. This function only returned
309 // real eigenvalues/vectors. The eigen function used can handle and return complex eigen vectors.
310 // this causes errors when returning to a non-complex EigenVector and EigenMatrix classes.
311 // this check is here to alert to this error.
312 if (!solver.eigenvectors().imag().isZero()) {
313 throw std::invalid_argument("eigensystem has complex eigenvalues or eigenvectors");
314 } else {
315 eigenValues = solver.eigenvalues().real();
316 eigenVectors = solver.eigenvectors().real();
317 }
318}
319
323 if (i >= size1()) {
324 throw std::out_of_range("EigenMatrix row index is out of range.");
325 }
326
327 EigenMatrix_View rowView = EigenMatrix_View(copy_view().data(), size1(), size2(), 1, size1(), i, 0);
328 Eigen::VectorXd rowVec = Eigen::Map<Eigen::VectorXd, 0, Eigen::InnerStride<>>(
329 rowView.matrix_mutator().data(), rowView.cols(), Eigen::InnerStride<>(rowView.outerStride()));
330 return EigenVector(&rowVec);
331}
332
336 if (i >= size2()) {
337 throw std::out_of_range("EigenMatrix column index is out of range.");
338 }
339
340 EigenMatrix_View colView = EigenMatrix_View(copy_view().data(), size1(), size2(), size1(), 1, 0, i);
341 Eigen::VectorXd colVec = Eigen::Map<Eigen::VectorXd, 0, Eigen::InnerStride<>>(
342 colView.matrix_mutator().data(), colView.rows(), Eigen::InnerStride<>(colView.innerStride()));
343 return EigenVector(&colVec);
344}
345
348
350 if (v.size() != size2()) {
351 throw std::invalid_argument("Matrix by vector multiplication: wrong size of vector.");
352 }
353
354 EigenVector res;
355 res = inspector() * v.inspector();
356 return res;
357}
358
361 EigenMatrix res;
362 res = inspector().transpose();
363 return res;
364}
365
366} // namespace Mantid::CurveFitting
const std::vector< double > & rhs
double value
The value of the point.
Definition: FitMW.cpp:51
const std::vector< Type > & m_data
Definition: TableColumn.h:417
const map_type matrix_inspector() const
A wrapper around Eigen::Matrix.
Definition: EigenMatrix.h:33
EigenMatrix & operator-=(const EigenMatrix &M)
Subtract a matrix from this.
bool isEmpty() const
Is matrix empty.
EigenMatrix_View m_view
The pointer to the vector.
Definition: EigenMatrix.h:130
void set(size_t i, size_t j, double value)
Set an element.
EigenMatrix()=default
Constructor.
EigenVector copyColumn(size_t i) const
Copy a column into an EigenVector.
EigenVector copyRow(size_t i) const
Copy a row into an EigenVector.
double get(size_t i, size_t j) const
Get an element.
size_t size1() const
First size of the matrix.
void eigenSystem(EigenVector &eigenValues, EigenMatrix &eigenVectors)
Calculate the eigensystem of a symmetric matrix.
double det() const
Calculate the determinant.
EigenMatrix tr() const
Calculate the eigensystem of a symmetric matrix.
EigenVector multiplyByVector(const EigenVector &v) const
map_type copy_view() const
Get a copy of the Eigen matrix.
Definition: EigenMatrix.h:60
EigenMatrix & operator*=(const double &d)
Multiply this matrix by a number.
void diag(const EigenVector &d)
Set the matrix to be diagonal.
void invert()
Invert this matrix.
EigenMatrix move()
Create a new matrix and move the data to it.
std::vector< double > m_data
Default element storage.
Definition: EigenMatrix.h:128
map_type & mutator()
Get the map to Eigen matrix.
Definition: EigenMatrix.h:56
EigenMatrix & operator+=(const EigenMatrix &M)
Add a matrix to this.
EigenVector operator*(const EigenVector &v) const
Matrix by vector multiplication.
EigenMatrix & operator=(const EigenMatrix &M)
Copy assignment operator.
void zero()
Set all elements to zero.
size_t size2() const
Second size of the matrix.
void identity()
Set this matrix to identity matrix.
void solve(const EigenVector &rhs, EigenVector &x)
Solve system of linear equations M*x == rhs, M is this matrix This matrix is destroyed.
const map_type inspector() const
Get a const copy of the Eigen matrix.
Definition: EigenMatrix.h:58
void resize(const size_t nx, const size_t ny)
Resize the matrix.
A wrapper around Eigen::Vector.
Definition: EigenVector.h:27
const vec_map_type inspector() const
Get the const map of the eigen vector.
Definition: EigenVector.h:53
size_t size() const
Size of the vector.
Numerical Matrix class.
Definition: Matrix.h:42
std::vector< T > getVector() const
Definition: Matrix.cpp:77
size_t numRows() const
Return the number of rows in the matrix.
Definition: Matrix.h:144
size_t numCols() const
Return the number of columns in the matrix.
Definition: Matrix.h:147
STL namespace.