GQCP
Loading...
Searching...
No Matches
Matrix.hpp
Go to the documentation of this file.
1// This file is part of GQCG-GQCP.
2//
3// Copyright (C) 2017-2020 the GQCG developers
4//
5// GQCG-GQCP is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// GQCG-GQCP is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with GQCG-GQCP. If not, see <http://www.gnu.org/licenses/>.
17
18#pragma once
19
20
22#include "Utilities/Eigen.hpp"
23#include "Utilities/aliases.hpp"
25
26#include <boost/algorithm/string.hpp>
27
28#include <fstream>
29#include <iostream>
30#include <vector>
31
32
33namespace GQCP {
34
35
45template <typename _Scalar = double, int _Rows = Dynamic, int _Cols = Dynamic>
46class Matrix:
47 public Eigen::Matrix<_Scalar, _Rows, _Cols> {
48
49public:
50 using Scalar = _Scalar;
51 static constexpr auto Rows = _Rows;
52 static constexpr auto Cols = _Cols;
53
55 using Base = Eigen::Matrix<Scalar, Rows, Cols>;
56
57
58private:
59 static constexpr bool is_vector = (Cols == 1);
60 static constexpr bool is_matrix = (Cols >= 2) || (Cols == Dynamic);
61
62
63public:
64 /*
65 * CONSTRUCTORS
66 */
67
68 using Eigen::Matrix<Scalar, Rows, Cols>::Matrix; // inherit base constructors
69
70
71 /*
72 * NAMED CONSTRUCTORS
73 */
74
82 template <typename Z = Self>
83 static enable_if_t<(Cols == Dynamic) && (Rows == Dynamic), Z> FromColumnMajorVector(const Matrix<Scalar, Dynamic, 1>& v, const size_t rows, const size_t cols) {
84
85 return Self(Eigen::Map<const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>(v.data(), rows, cols));
86 }
87
88
95 template <typename Z = Self> // enable_if must have Z inside
96 static enable_if_t<Self::is_vector, Z> FromFile(const std::string& filename, size_t rows) {
97
98 // Initialize a zero vector
99 Self result = Self::Zero(rows);
100
101 std::ifstream file {filename};
102 size_t index = 0;
103 if (file.is_open()) {
104 std::string line;
105
106 while (std::getline(file, line)) {
107 std::vector<std::string> splitted_line; // create a container for the line to be split in
108
109 // Split the line on any whitespace or tabs.
110 boost::split(splitted_line, line, boost::is_any_of(" \t"), boost::token_compress_on);
111
112 if (splitted_line.size() != 1) {
113 throw std::runtime_error("Matrix::FromFile(std::string, size_t): Found a line that doesn't contain exactly 1 field delimited by whitespace.");
114 }
115
116 auto value = std::stod(splitted_line[0]);
117 result(index) = value;
118
119 ++index;
120 }
121
122 file.close();
123 } else {
124 throw std::runtime_error("Matrix::FromFile(std::string, size_t): Cannot open the given file. Maybe you specified a wrong path?");
125 }
126
127 return result;
128 }
129
130
138 template <typename Z = Self> // enable_if must have Z inside
139 static enable_if_t<Self::is_matrix, Z> FromFile(const std::string& filename, size_t rows, size_t cols) {
140
141 Self result = Self::Zero(rows, cols);
142
143 std::ifstream file {filename};
144 if (file.is_open()) {
145 std::string line;
146
147 while (std::getline(file, line)) {
148 std::vector<std::string> splitted_line; // create a container for the line to be split in
149
150 // Split the line on any whitespace or tabs.
151 boost::split(splitted_line, line, boost::is_any_of(" \t"), boost::token_compress_on);
152
153 if (splitted_line.size() != 3) {
154 throw std::runtime_error("Matrix::FromFile(std::string, size_t, size_t): Found a line that doesn't contain exactly 3 fields delimited by whitespace.");
155 }
156
157 auto i = std::stoi(splitted_line[0]);
158 auto j = std::stoi(splitted_line[1]);
159 auto value = std::stod(splitted_line[2]);
160
161 result(i, j) = value;
162 }
163
164 file.close();
165 } else {
166 throw std::runtime_error("Matrix::FromFile(std::string, size_t, size_t): Cannot open the given file. Maybe you specified a wrong path?");
167 }
168
169 return result;
170 }
171
172
182 template <typename Z = bool> // enable_if must have Z inside
184 return Self::isApprox(other, tolerance);
185 }
186
187
197 template <typename Z = bool> // enable_if must have Z inside
199
200 // Eigenvectors are equal if they are equal up to their sign.
201 return (Self::isApprox(other, tolerance) || Self::isApprox(-other, tolerance));
202 }
203
204
214 template <typename Z = bool> // enable_if must have Z inside
216
217 // Check if the dimensions of the eigenvectors are equal.
218 if (Self::cols() != other.cols()) {
219 throw std::invalid_argument("hasEqualSetsOfEigenvectorsAs(MatrixX<double>, MatrixX<double>, double): Cannot compare the two sets of eigenvectors as they have different dimensions.");
220 }
221
222 if (Self::rows() != other.rows()) {
223 throw std::invalid_argument("hasEqualSetsOfEigenvectorsAs(MatrixX<double>, MatrixX<double>, double): Cannot compare the two sets of eigenvectors as they have different dimensions.");
224 }
225
226
227 for (size_t i = 0; i < Self::cols(); i++) {
228 const Matrix<Scalar, Dynamic, 1> eigenvector1 = Self::col(i);
229 const Matrix<Scalar, Dynamic, 1> eigenvector2 = other.col(i);
230
231 if (!eigenvector1.isEqualEigenvectorAs(eigenvector2, tolerance)) {
232 return false;
233 }
234 }
235
236 return true;
237 }
238
239
247 template <typename Z = Self>
248 static enable_if_t<(Cols == Dynamic) && (Rows == Dynamic), Z> FromRowMajorVector(const Matrix<Scalar, Dynamic, 1>& v, const size_t rows, const size_t cols) {
249
250 // Change the given vector's elements to a column-major representation
252 for (size_t i = 0; i < rows; i++) {
253 for (size_t j = 0; j < cols; j++) {
254 size_t row_major_index = i * cols + j;
255 size_t column_major_index = j * rows + i;
256
257 v_column_major(column_major_index) = v(row_major_index);
258 }
259 }
260
261 return Self::FromColumnMajorVector(v_column_major, rows, cols);
262 }
263
264
265 /*
266 * OPERATORS
267 */
268
274 template <typename Z = Scalar>
275 enable_if_t<Self::is_vector && (Rows == 3), Z> operator()(const CartesianDirection direction) const {
276
277 const auto index = static_cast<size_t>(direction); // 0, 1, or 2
278 return this->operator()(index);
279 }
280
286 template <typename Z = Scalar&>
287 enable_if_t<Self::is_vector && (Rows == 3), Z> operator()(const CartesianDirection direction) {
288
289 const auto index = static_cast<size_t>(direction); // 0, 1, or 2
290 return this->operator()(index);
291 }
292
293 using Base::operator(); // bring over the other operator() overloads
294
295
296 /*
297 * PUBLIC METHODS
298 */
299
300
307 template <typename Z = Self>
309
310 Self this_copy = *this;
311
312 this_copy.removeRow(i);
313 this_copy.removeColumn(j);
314
315 return this_copy;
316 }
317
321 const Base& Eigen() const { return static_cast<const Base&>(*this); }
322
326 Base& Eigen() { return static_cast<Base&>(*this); }
327
333 const bool isPositiveSemiDefinite(const double threshold = -1.0e-5) const {
334
335 const auto matrix = *this;
336
337 // Create an eigensolver to diagonalize the matrix.
338 using MatrixType = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
339 Eigen::SelfAdjointEigenSolver<MatrixType> eigensolver {matrix};
340
341 // Calculate the eigenvalues and check whether they are strictly positive or not.
342 const auto& eigenvalues = eigensolver.eigenvalues().transpose();
343
344 if (eigenvalues[0] < threshold) {
345 return false;
346 } else {
347 return true;
348 }
349 }
350
351
362 template <typename Z = Matrix<Scalar, Rows, 1>>
363 enable_if_t<Self::is_matrix, Z> pairWiseReduced(const size_t start_i = 0, size_t start_j = 0) const {
364
365 // Initialize the resulting vector
366 Matrix<Scalar, Rows, 1> v((this->rows() - start_i) * (this->cols() - start_j));
367
368 // Calculate the compound indices and bring the elements from the matrix over into the vector
369 size_t vector_index = 0;
370 for (size_t j = start_j; j < this->cols(); j++) { // "column major" ordering for row_index<-i,j so we do j first, then i
371 for (size_t i = start_i; i < this->rows(); i++) { // in column major indices, columns are contiguous, so the first of two indices changes more rapidly
372
373 v(vector_index) = this->operator()(i, j);
374 vector_index++;
375 }
376 }
377
378 return v;
379 }
380
381
387 template <typename Z = void> // enable_if must have Z inside
388 enable_if_t<Self::is_matrix, Z> print(std::ostream& output_stream = std::cout) const {
389
390 for (size_t i = 0; i < this->rows(); i++) {
391 for (size_t j = 0; j < this->cols(); j++) {
392 output_stream << i << ' ' << j << " " << this->operator()(i, j) << std::endl;
393 }
394 }
395 }
396
397
405 void removeColumn(const size_t i) {
406
407 const size_t rows = this->rows(); // the number of rows of the resulting matrix
408 const size_t columns = this->cols() - 1; // the number of columns of the resulting matrix
409
410 // Shift the columns to the left.
411 if (i < columns) {
412 this->block(0, i, rows, columns - i) = this->rightCols(columns - i);
413 }
414
415 this->conservativeResize(rows, columns);
416 }
417
418
424 void removeColumns(const std::vector<size_t>& column_indices) {
425
426 size_t removed_counter = 0;
427 for (const auto& i : column_indices) {
428 this->removeColumn(i - removed_counter); // take into account that the given indices are with respect to the old dimensions of the matrix
429 removed_counter++;
430 }
431 }
432
433
441 void removeRow(const size_t i) {
442
443 const size_t rows = this->rows() - 1; // the number of rows of the resulting matrix
444 const size_t columns = this->cols(); // the number of columns of the resulting matrix
445
446 // Shift the rows up.
447 if (i < rows) {
448 this->block(i, 0, rows - i, columns) = this->bottomRows(rows - i);
449 }
450
451 this->conservativeResize(rows, columns);
452 }
453
454
460 void removeRows(const std::vector<size_t>& row_indices) {
461
462 size_t removed_counter = 0;
463 for (const auto& i : row_indices) {
464 this->removeRow(i - removed_counter); // take into account that the given indices are with respect to the old dimensions of the matrix
465 removed_counter++;
466 }
467 }
468};
469
470
471/*
472 * Convenience typedefs related to Matrix. These have to be in order.
473 */
474
475template <typename Scalar, int Rows>
477
478template <typename Scalar>
480
481template <typename Scalar>
483
484template <typename Scalar>
485using VectorFunction = std::function<VectorX<Scalar>(const VectorX<Scalar>&)>;
486
487template <typename Scalar>
488using MatrixFunction = std::function<MatrixX<Scalar>(const VectorX<Scalar>&)>;
489
490
491} // namespace GQCP
Definition: Matrix.hpp:47
enable_if_t< Self::is_matrix, Z > pairWiseReduced(const size_t start_i=0, size_t start_j=0) const
Definition: Matrix.hpp:363
enable_if_t< Self::is_vector &&(Rows==3), Z > operator()(const CartesianDirection direction) const
Definition: Matrix.hpp:275
void removeColumns(const std::vector< size_t > &column_indices)
Definition: Matrix.hpp:424
enable_if_t< Self::is_vector, Z > areEqualEigenvaluesAs(const Matrix< Scalar, Dynamic, 1 > &other, double tolerance=1.0e-12) const
Definition: Matrix.hpp:183
Base & Eigen()
Definition: Matrix.hpp:326
enable_if_t< Self::is_vector, Z > isEqualEigenvectorAs(const Matrix< Scalar, Dynamic, 1 > &other, double tolerance=1.0e-12) const
Definition: Matrix.hpp:198
void removeRows(const std::vector< size_t > &row_indices)
Definition: Matrix.hpp:460
const bool isPositiveSemiDefinite(const double threshold=-1.0e-5) const
Definition: Matrix.hpp:333
Matrix< Scalar, Rows, Cols > Self
Definition: Matrix.hpp:54
static constexpr auto Rows
Definition: Matrix.hpp:51
enable_if_t< Self::is_matrix, Z > hasEqualSetsOfEigenvectorsAs(const Matrix< Scalar, Dynamic, Dynamic > &other, double tolerance=1.0e-12) const
Definition: Matrix.hpp:215
enable_if_t< Self::is_matrix, Z > print(std::ostream &output_stream=std::cout) const
Definition: Matrix.hpp:388
void removeRow(const size_t i)
Definition: Matrix.hpp:441
const Base & Eigen() const
Definition: Matrix.hpp:321
_Scalar Scalar
Definition: Matrix.hpp:50
static enable_if_t<(Cols==Dynamic) &&(Rows==Dynamic), Z > FromColumnMajorVector(const Matrix< Scalar, Dynamic, 1 > &v, const size_t rows, const size_t cols)
Definition: Matrix.hpp:83
enable_if_t< Self::is_matrix, Z > calculateMinor(size_t i, size_t j) const
Definition: Matrix.hpp:308
static constexpr auto Cols
Definition: Matrix.hpp:52
void removeColumn(const size_t i)
Definition: Matrix.hpp:405
static enable_if_t<(Cols==Dynamic) &&(Rows==Dynamic), Z > FromRowMajorVector(const Matrix< Scalar, Dynamic, 1 > &v, const size_t rows, const size_t cols)
Definition: Matrix.hpp:248
Eigen::Matrix< Scalar, Rows, Cols > Base
Definition: Matrix.hpp:55
static enable_if_t< Self::is_matrix, Z > FromFile(const std::string &filename, size_t rows, size_t cols)
Definition: Matrix.hpp:139
static enable_if_t< Self::is_vector, Z > FromFile(const std::string &filename, size_t rows)
Definition: Matrix.hpp:96
Definition: BaseOneElectronIntegralBuffer.hpp:25
typename std::enable_if< B, T >::type enable_if_t
Definition: type_traits.hpp:37
constexpr auto Dynamic
Definition: Eigen.hpp:27
CartesianDirection
Definition: CartesianDirection.hpp:27
std::function< VectorX< Scalar >(const VectorX< Scalar > &)> VectorFunction
Definition: Matrix.hpp:485
std::function< MatrixX< Scalar >(const VectorX< Scalar > &)> MatrixFunction
Definition: Matrix.hpp:488