24#include <boost/algorithm/string.hpp>
26#include <unsupported/Eigen/CXX11/Tensor>
44template <
typename _Scalar,
int _Rank>
46 public Eigen::Tensor<_Scalar, _Rank> {
53 static constexpr auto Rank = _Rank;
59 using Base = Eigen::Tensor<Scalar, Rank>;
68 using Eigen::Tensor<
Scalar, _Rank>::Tensor;
86 template <
int Z = Rank>
90 static_cast<long>(T.dimension(1) - j - cutoff),
91 static_cast<long>(T.dimension(2) - k - cutoff),
92 static_cast<long>(T.dimension(3) - l - cutoff)};
95 for (
size_t p = 0; p < T_result.dimension(0); p++) {
96 for (
size_t q = 0; q < T_result.dimension(1); q++) {
97 for (
size_t r = 0; r < T_result.dimension(2); r++) {
98 for (
size_t s = 0; s < T_result.dimension(3); s++) {
99 T_result(p, q, r, s) = T(i + p, j + q, k + r, l + s);
152 template <
size_t r,
size_t s,
int Z = Rank>
156 size_t ia[4] = {1, 0, 0, 0};
157 size_t ja[4] = {0, 1, 0, 0};
158 size_t ka[4] = {0, 0, 1, 0};
159 size_t la[4] = {0, 0, 0, 1};
161 for (
size_t x = 0;
x < M.rows();
x++) {
162 for (
size_t y = 0;
y < M.cols();
y++) {
164 size_t i_effective = i +
x * ia[r] +
y * ia[s];
165 size_t j_effective = j +
x * ja[r] +
y * ja[s];
166 size_t k_effective = k +
x * ka[r] +
y * ka[s];
167 size_t l_effective = l +
x * la[r] +
y * la[s];
169 this->operator()(i_effective, j_effective, k_effective, l_effective) += M(
x,
y);
188 template <
int Z = Rank>
191 for (
size_t p = 0; p < T.dimension(0); p++) {
192 for (
size_t q = 0; q < T.dimension(1); q++) {
193 for (
size_t r = 0; r < T.dimension(2); r++) {
194 for (
size_t s = 0; s < T.dimension(3); s++) {
195 this->operator()(i + p, j + q, k + r, l + s) += T(p, q, r, s);
218 template <
int Z = Rank>
222 const auto dims = this->dimensions();
224 (dims[2] - start_k) * (dims[3] - start_l)};
227 size_t row_index = 0;
228 for (
size_t j = start_j; j < dims[1]; j++) {
229 for (
size_t i = start_i; i < dims[0]; i++) {
231 size_t column_index = 0;
232 for (
size_t l = start_l; l < dims[3]; l++) {
233 for (
size_t k = start_k; k < dims[2]; k++) {
235 M(row_index, column_index) = this->operator()(i, j, k, l);
263 template <
int N,
int LHSRank = Rank,
int RHSRank>
267 constexpr auto ResultRank = LHSRank + RHSRank - 2 * N;
269 if (lhs_labels.size() != LHSRank) {
270 throw std::invalid_argument(
"Tensor.einsum(const Tensor<Scalar, RHSRank>&, const std::string&, const std::string&, const std::string&): The number of indices for the left-hand side of the contraction does not match the rank of the left-hand side tensor.");
273 if (rhs_labels.size() != RHSRank) {
274 throw std::invalid_argument(
"Tensor.einsum(const Tensor<Scalar, RHSRank>&, const std::string&, const std::string&, const std::string&): The number of indices for the right-hand side of the contraction does not match the rank of the right-hand side tensor.");
277 if (output_labels.size() != ResultRank) {
278 throw std::invalid_argument(
"Tensor.einsum(const Tensor<Scalar, RHSRank>&, const std::string&, const std::string&, const std::string&): The number of output indices does not match the number of axes that should be contracted over.");
283 Eigen::array<Eigen::IndexPair<int>, N> contraction_pairs {};
284 size_t array_position = 0;
285 for (
size_t i = 0; i < LHSRank; i++) {
286 const auto current_label = lhs_labels[i];
287 const auto match = rhs_labels.find(current_label);
288 if (match != std::string::npos) {
289 contraction_pairs[array_position] = Eigen::IndexPair<int>(i, match);
299 auto intermediate_indices = lhs_labels + rhs_labels;
301 for (
size_t i = 1; i < LHSRank + RHSRank; i++) {
304 const auto current_label = intermediate_indices[i];
305 const auto match = intermediate_indices.substr(0, i).find(current_label);
307 if (match != std::string::npos) {
308 intermediate_indices.erase(match, 1);
309 intermediate_indices.erase(i - 1, 1);
322 if (output_labels !=
"") {
323 Eigen::array<int, 4> shuffle_indices {};
325 for (
size_t i = 0; i < 4; i++) {
326 const auto current_label = intermediate_indices[i];
327 shuffle_indices[i] = output_labels.find(current_label);
330 return T_intermediate.shuffle(shuffle_indices);
333 return T_intermediate;
349 template <
int N,
int LHSRank = Rank,
int RHSRank>
352 boost::erase_all(contraction_string,
" ");
353 boost::erase_all(contraction_string,
">");
354 boost::replace_all(contraction_string,
"-",
" ");
355 boost::replace_all(contraction_string,
",",
" ");
358 std::vector<std::string> segment_list;
359 boost::split(segment_list, contraction_string, boost::is_any_of(
" "));
362 if (segment_list.size() == 2) {
363 segment_list.push_back(
"");
378 return this->einsum<N>(rhs, segment_list[0], segment_list[1], segment_list[2]);
394 template <
int N,
int LHSRank = Rank>
397 const auto tensor_from_matrix =
Tensor<Scalar, 2>(Eigen::TensorMap<Eigen::Tensor<const Scalar, 2>>(rhs.data(), rhs.rows(), rhs.cols()));
398 return this->einsum<N>(contraction_string, tensor_from_matrix);
405 template <
int Z = Rank>
408 const auto rows = this->dimension(0);
409 const auto cols = this->dimension(1);
411 return GQCP::Matrix<Scalar>(Eigen::Map<
const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>>(this->data(), rows, cols));
426 throw std::invalid_argument(
"Tensor.reshape(const size_t rows, const size_t cols): The tensor cannot be reshaped into a matrix with the specified dimensions.");
433 std::vector<Scalar> vectorized;
436 vectorized.reserve(rows * cols);
439 for (
int i = 0; i < this->dimension(0); i++) {
440 for (
int j = 0; j < this->dimension(1); j++) {
441 for (
int k = 0; k < this->dimension(2); k++) {
442 for (
int l = 0; l < this->dimension(3); l++) {
443 vectorized.push_back(this->
operator()(i, j, k, l));
450 for (
int r = 0; r < rows; r++) {
451 for (
int c = 0; c < cols; c++) {
455 M(r, c) = vectorized[r * cols + c];
474 for (
size_t i = 0; i <
Rank; i++) {
475 if (this->dimension(i) != other.dimension(i)) {
490 template <
int Z = Rank>
494 throw std::invalid_argument(
"RankFourTensor<Scalar>::isApprox(Self, double): the tensors have different dimensions");
498 for (
size_t i = 0; i < this->dimension(0); i++) {
499 for (
size_t j = 0; j < this->dimension(1); j++) {
500 for (
size_t k = 0; k < this->dimension(2); k++) {
501 for (
size_t l = 0; l < this->dimension(3); l++) {
502 if (std::abs(this->
operator()(i, j, k, l) - other(i, j, k, l)) > tolerance) {
518 return this->dimension(0) * this->dimension(1) * this->dimension(2) * this->dimension(3);
527 template <
int Z = Rank>
530 for (
size_t i = 0; i < this->dimension(0); i++) {
531 for (
size_t j = 0; j < this->dimension(1); j++) {
532 for (
size_t k = 0; k < this->dimension(2); k++) {
533 for (
size_t l = 0; l < this->dimension(3); l++) {
534 output_stream << i <<
' ' << j <<
' ' << k <<
' ' << l <<
" " << this->operator()(i, j, k, l) << std::endl;
Definition: Matrix.hpp:47
Definition: Tensor.hpp:46
enable_if_t< Z==4 > print(std::ostream &output_stream=std::cout) const
Definition: Tensor.hpp:528
GQCP::Matrix< Scalar > reshape(const size_t rows, const size_t cols) const
Definition: Tensor.hpp:422
bool hasEqualDimensionsAs(const Self &other) const
Definition: Tensor.hpp:472
const Base & Eigen() const
Definition: Tensor.hpp:116
Tensor< Scalar, LHSRank+RHSRank - 2 *N > einsum(std::string contraction_string, const Tensor< Scalar, RHSRank > &rhs) const
Definition: Tensor.hpp:350
Tensor< Scalar, LHSRank+RHSRank - 2 *N > einsum(const Tensor< Scalar, RHSRank > &rhs, const std::string &lhs_labels, const std::string &rhs_labels, const std::string &output_labels) const
Definition: Tensor.hpp:264
enable_if_t< Z==4, Self & > addBlock(const MatrixX< Scalar > &M, const size_t i, const size_t j, const size_t k, const size_t l)
Definition: Tensor.hpp:153
Eigen::Tensor< Scalar, Rank > Base
Definition: Tensor.hpp:59
enable_if_t< Z==4, bool > isApprox(const Self &other, const double tolerance=1.0e-12) const
Definition: Tensor.hpp:491
enable_if_t< Z==4, Matrix< Scalar > > pairWiseReduced(const size_t start_i=0, const size_t start_j=0, const size_t start_k=0, const size_t start_l=0) const
Definition: Tensor.hpp:219
static constexpr auto Rank
Definition: Tensor.hpp:53
static enable_if_t< Z==4, Self > FromBlock(const Self &T, const size_t i, const size_t j, const size_t k, const size_t l, const size_t cutoff=0)
Definition: Tensor.hpp:87
Tensor< Scalar, LHSRank+2 - 2 *N > einsum(std::string contraction_string, const Matrix< Scalar > rhs) const
Definition: Tensor.hpp:395
size_t numberOfElements() const
Definition: Tensor.hpp:517
const enable_if_t< Z==2, GQCP::Matrix< Scalar > > asMatrix() const
Definition: Tensor.hpp:406
Base & Eigen()
Definition: Tensor.hpp:121
enable_if_t< Z==4, Self & > addBlock(const Self &T, const size_t i, const size_t j, const size_t k, const size_t l)
Definition: Tensor.hpp:189
_Scalar Scalar
Definition: Tensor.hpp:50
Definition: BaseOneElectronIntegralBuffer.hpp:25
typename std::enable_if< B, T >::type enable_if_t
Definition: type_traits.hpp:37
@ x
Definition: CartesianDirection.hpp:28
@ y
Definition: CartesianDirection.hpp:29