mptensor v0.5.1
Parallel Library for Tensor Network Methods
Loading...
Searching...
No Matches
tensor_impl.hpp
Go to the documentation of this file.
1/*
2 mptensor - Parallel Library for Tensor Network Methods
3
4 Copyright 2016 Satoshi Morita
5
6 mptensor is free software: you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation, either version 3 of the
9 License, or (at your option) any later version.
10
11 mptensor is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with mptensor. If not, see
18 <https://www.gnu.org/licenses/>.
19*/
20
29#ifndef _TENSOR_IMPL_HPP_
30#define _TENSOR_IMPL_HPP_
31
32#include <algorithm>
33#include <cassert>
34#include <cstdio>
35#include <cstdlib>
36#include <cstring>
37#include <fstream>
38#include <iostream>
39#include <type_traits>
40#include <vector>
41
42#include "mptensor/complex.hpp"
43#include "mptensor/index.hpp"
45#include "mptensor/tensor.hpp"
46
47namespace mptensor {
48
49/* Utilities */
50bool is_no_transpose(const Axes &axes, const Axes &axes_map, size_t rank);
51namespace debug {
52bool check_total_size(const Shape &s1, const Shape &s2);
53bool check_extend(const Shape &s_old, const Shape &s_new);
54bool check_transpose_axes(const Axes &axes, size_t rank);
55bool check_svd_axes(const Axes &axes_row, const Axes &axes_col, size_t rank);
56bool check_trace_axes(const Axes &axes_1, const Axes &axes_2, size_t rank);
57bool check_trace_axes(const Axes &axes_a, const Axes &axes_b,
58 const Shape &shape_a, const Shape &shape_b);
59bool check_contract_axes(const Axes &axes_1, const Axes &axes_2, size_t rank);
60bool check_square(const Shape &shape, size_t urank);
61} // namespace debug
62
63/* ---------- constructors ---------- */
64
70template <typename MatrixType>
71Tensor<MatrixType>::Tensor() : Mat(), upper_rank(0), axes_map(){};
72
79template <typename MatrixType>
80Tensor<MatrixType>::Tensor(const Shape &shape) : Mat() {
81 init(shape, shape.size() / 2);
82};
83
88template <typename MatrixType>
90 : Mat(comm), upper_rank(0), axes_map(){};
91
98template <typename MatrixType>
99Tensor<MatrixType>::Tensor(const comm_type &comm, const Shape &shape)
100 : Mat(comm) {
101 init(shape, shape.size() / 2);
102};
103
110template <typename MatrixType>
112 const size_t upper_rank)
113 : Mat(comm) {
114 init(shape, upper_rank);
116
118
123template <typename MatrixType>
125 const Tensor<lapack::Matrix<value_type>> &t)
126 : Mat(comm) {
127 init(t.shape(), t.get_upper_rank());
128 const size_t n = Mat.local_size();
129 size_t idx;
130 int dummy;
131 for (size_t i = 0; i < n; ++i) {
132 t.local_position(global_index(i), dummy, idx);
133 Mat[i] = t[idx];
138
143template <typename MatrixType>
144Tensor<MatrixType>::Tensor(const comm_type &comm, const std::vector<value_type> &v)
145 : Mat(comm) {
146 init(Shape(v.size()), 0);
147 const size_t n = Mat.local_size();
148 Index idx;
149 for (size_t i = 0; i < n; ++i) {
150 idx = global_index(i);
151 Mat[i] = v[idx[0]];
152 }
153};
154
155/* ---------- inline member functions ---------- */
156
158template <typename MatrixType>
159inline const Shape &Tensor<MatrixType>::shape() const {
160 return Dim;
161};
162
164template <typename MatrixType>
165inline size_t Tensor<MatrixType>::rank() const {
166 return Dim.size();
167};
168
170
173template <typename MatrixType>
174inline size_t Tensor<MatrixType>::ndim() const {
175 return Dim.size();
176};
177
179template <typename MatrixType>
180inline size_t Tensor<MatrixType>::local_size() const {
181 return Mat.local_size();
182};
183
185template <typename MatrixType>
187 return upper_rank;
188};
189
191
197template <typename MatrixType>
199 return axes_map;
200};
201
203template <typename MatrixType>
205 return Mat;
206};
207
209template <typename MatrixType>
211 return Mat;
212};
213
215template <typename MatrixType>
216inline const typename Tensor<MatrixType>::comm_type &
218 return Mat.get_comm();
219};
220
222template <typename MatrixType>
224 return Mat.get_comm_size();
225};
226
228template <typename MatrixType>
230 return Mat.get_comm_rank();
231};
232
234
237template <typename MatrixType>
238inline const typename MatrixType::value_type &Tensor<MatrixType>::operator[](size_t local_idx) const {
239 return Mat[local_idx];
240}
241
243
246template <typename MatrixType>
247inline typename MatrixType::value_type &Tensor<MatrixType>::operator[](size_t local_idx) {
248 return Mat[local_idx];
249}
250
252template <typename MatrixType>
254 Mat.prep_global_to_local();
255};
256
258template <typename MatrixType>
260 Mat.prep_local_to_global();
261};
262
264template <typename MatrixType>
266 const size_t rank = Dim.size();
267 const size_t rank0 = upper_rank;
268 const size_t rank1 = rank - rank0; // lower_rank
269 const size_t l_row = Mat.local_row_size();
270 const size_t l_col = Mat.local_col_size();
271 // When rank0 (== upper_rank) or rank1 (== lower_rank) is zero, the
272 // corresponding range is empty; taking the base address of an empty range
273 // (&axes_map[rank0] one past the end, or &l2g_map_row[0] on an empty vector)
274 // is undefined behavior and aborts under _GLIBCXX_ASSERTIONS. Guard with a
275 // null pointer that is never dereferenced (the matching loops are skipped).
276 const size_t *axes_map0 = rank0 > 0 ? &(axes_map[0]) : nullptr;
277 const size_t *axes_map1 = rank1 > 0 ? &(axes_map[rank0]) : nullptr;
278
279 l2g_map_row.resize(l_row * rank0);
280 l2g_map_col.resize(l_col * rank1);
281
282#pragma omp parallel default(shared)
283 {
284 // Type int instead of size_t is used because of std::div()
285 std::vector<int> dim0(rank0);
286 std::vector<int> dim1(rank1);
287 for (size_t i = 0; i < rank0; ++i) dim0[i] = int(Dim[axes_map0[i]]);
288 for (size_t i = 0; i < rank1; ++i) dim1[i] = int(Dim[axes_map1[i]]);
289
290 int g_row, g_col; // global matrix row- and column-index
291 std::div_t divresult;
292 size_t *map;
293 if (rank0 > 0) {
294#pragma omp for
295 for (size_t k = 0; k < l_row; ++k) {
296 map = &(l2g_map_row[k * rank0]);
297 g_row = int(Mat.global_row_index(k));
298 for (size_t i = 0; i < rank0; ++i) {
299 divresult = std::div(g_row, dim0[i]);
300 map[i] = divresult.rem;
301 g_row = divresult.quot;
302 }
303 }
304 }
305 if (rank1 > 0) {
306#pragma omp for
307 for (size_t k = 0; k < l_col; ++k) {
308 map = &(l2g_map_col[k * rank1]);
309 g_col = int(Mat.global_col_index(k));
310 for (size_t i = 0; i < rank1; ++i) {
311 divresult = std::div(g_col, dim1[i]);
312 map[i] = divresult.rem;
313 g_col = divresult.quot;
314 }
315 }
316 }
317 }
318
319 return;
320};
321
323
329template <typename MatrixType>
331 size_t gindex[]) const {
332 const size_t rank = Dim.size();
333 const size_t rank0 = upper_rank;
334 const size_t rank1 = rank - rank0; // lower_rank
335 const size_t lindex_row = Mat.local_row_index(lindex);
336 const size_t lindex_col = Mat.local_col_index(lindex);
337 // Guard against empty upper/lower ranges (see make_l2g_map): a null base
338 // pointer is safe because the matching loop below is then empty.
339 const size_t *map_row = rank0 > 0 ? &(l2g_map_row[lindex_row * rank0]) : nullptr;
340 const size_t *map_col = rank1 > 0 ? &(l2g_map_col[lindex_col * rank1]) : nullptr;
341 const size_t *axes_map0 = rank0 > 0 ? &(axes_map[0]) : nullptr;
342 const size_t *axes_map1 = rank1 > 0 ? &(axes_map[rank0]) : nullptr;
343 for (size_t i = 0; i < rank0; ++i) {
345 }
346 for (size_t i = 0; i < rank1; ++i) {
348 }
349 return;
350};
351
353
364template <typename MatrixType>
366 size_t lindex, const size_t axes_trans[], size_t index_new[]) const {
367 const size_t rank = Dim.size();
368 const size_t rank0 = upper_rank;
369 const size_t rank1 = rank - rank0; // lower_rank
370 const size_t lindex_row = Mat.local_row_index(lindex);
371 const size_t lindex_col = Mat.local_col_index(lindex);
372 // Guard against empty upper/lower ranges (see make_l2g_map): a null base
373 // pointer is safe because the matching loop below is then empty.
374 const size_t *map_row = rank0 > 0 ? &(l2g_map_row[lindex_row * rank0]) : nullptr;
375 const size_t *map_col = rank1 > 0 ? &(l2g_map_col[lindex_col * rank1]) : nullptr;
376 // const size_t* axes_map0 = &(axes_map[0]);
377 // const size_t* axes_map1 = &(axes_map[rank0]);
378 for (size_t i = 0; i < rank0; ++i) {
380 // index_new[axes_inv[axes_map0[i]]] = map_row[i];
381 }
382 for (size_t i = 0; i < rank1; ++i) {
384 // index_new[axes_inv[axes_map1[i]]] = map_col[i];
385 }
386 return;
387};
388
389template <typename MatrixType>
391 int &comm_rank,
392 size_t &local_idx) const {
393 Mat.local_position(g_row, g_col, comm_rank, local_idx);
394}
395
396/* ---------- member functions ---------- */
397
399
403template <typename MatrixType>
404inline void Tensor<MatrixType>::init(const Shape &shape, size_t urank) {
405 init(shape, urank, range(shape.size()));
406}
407
409
414template <typename MatrixType>
415void Tensor<MatrixType>::init(const Shape &shape, size_t urank,
416 const Axes &map) {
417 Dim = shape;
418 axes_map = map;
419 const size_t rank = Dim.size();
420 assert(urank <= rank);
421 upper_rank = urank;
422
423 size_t n_row = 1;
424 size_t n_col = 1;
425 for (size_t i = 0; i < upper_rank; ++i) n_row *= shape[map[i]];
426 for (size_t i = upper_rank; i < rank; ++i) n_col *= shape[map[i]];
427 Mat.init(n_row, n_col);
428}
429
431
437template <typename MatrixType>
439 const std::string &tag) const {
440 if (tag.size() > 0) {
441 out << tag << ":\t";
442 }
443 out << "Tensor: shape= " << Dim << " upper_rank= " << upper_rank
444 << " axes_map= " << axes_map << "\t";
445 Mat.print_info(out);
446};
447
449
455template <typename MatrixType>
457 const std::string &tag) const {
458 const int mpisize = get_comm_size();
459 const int mpirank = get_comm_rank();
460 const typename Tensor<MatrixType>::comm_type &comm = get_comm();
461 Mat.barrier();
462 for (int i = 0; i < mpisize; ++i) {
463 if (i == mpirank) {
464 if (tag.size() > 0) {
465 out << tag << ":\t";
466 }
467 out << "mpirank: " << mpirank << "\t";
468 print_info(out, "");
469 }
470 Mat.barrier();
471 }
472}
473
475
483template <typename MatrixType>
484bool Tensor<MatrixType>::local_index(const Index &gindex, size_t &lindex) const {
485 const size_t rank = gindex.size();
486 assert(rank == Dim.size());
487 assert(rank > 0);
488 size_t g_row(0), g_col(0);
489 size_t d_row(1), d_col(1);
490 for (size_t i = 0; i < upper_rank; ++i) {
491 size_t j = axes_map[i];
492 g_row += gindex[j] * d_row;
493 d_row *= Dim[j];
494 }
495 for (size_t i = upper_rank; i < rank; ++i) {
496 size_t j = axes_map[i];
497 g_col += gindex[j] * d_col;
498 d_col *= Dim[j];
499 }
500 return Mat.local_index(g_row, g_col, lindex);
501};
502
504
508template <typename MatrixType>
510 const size_t rank = Dim.size();
512 size_t g_row, g_col;
513 Mat.global_index(lindex, g_row, g_col);
514 gindex.resize(rank);
515 std::div_t divresult;
516 for (size_t i = 0; i < upper_rank; ++i) {
517 size_t j = axes_map[i];
518 divresult = std::div(int(g_row), int(Dim[j]));
519 gindex[j] = divresult.rem;
520 g_row = divresult.quot;
521 }
522 for (size_t i = upper_rank; i < rank; ++i) {
523 size_t j = axes_map[i];
524 divresult = std::div(int(g_col), int(Dim[j]));
525 gindex[j] = divresult.rem;
526 g_col = divresult.quot;
527 }
528 return gindex;
529};
530
532
538template <typename MatrixType>
540 const size_t rank = Dim.size();
541 size_t g_row, g_col;
542 Mat.global_index(lindex, g_row, g_col);
543 std::div_t divresult;
544 for (size_t i = 0; i < upper_rank; ++i) {
545 size_t j = axes_map[i];
546 divresult = std::div(int(g_row), int(Dim[j]));
547 gindex[j] = divresult.rem;
548 g_row = divresult.quot;
549 }
550 for (size_t i = upper_rank; i < rank; ++i) {
551 size_t j = axes_map[i];
552 divresult = std::div(int(g_col), int(Dim[j]));
553 gindex[j] = divresult.rem;
554 g_col = divresult.quot;
555 }
556 return;
557};
558
560
565template <typename MatrixType>
567 size_t li;
568 if (local_index(idx, li)) {
569 val = Mat[li];
570 return true;
571 } else {
572 return false;
573 }
574}
575
577
583template <typename MatrixType>
585 size_t li;
586 if (local_index(idx, li)) {
587 Mat[li] = val;
588 }
589}
590
592
597template <typename MatrixType>
599 size_t &local_idx) const {
600 const size_t rank = Dim.size();
601 size_t g_row(0), g_col(0);
602 size_t d_row(1), d_col(1);
603 for (size_t i = 0; i < upper_rank; ++i) {
604 size_t j = axes_map[i];
605 g_row += index[j] * d_row;
606 d_row *= Dim[j];
607 }
608 for (size_t i = upper_rank; i < rank; ++i) {
609 size_t j = axes_map[i];
610 g_col += index[j] * d_col;
611 d_col *= Dim[j];
612 }
613 Mat.local_position(g_row, g_col, comm_rank, local_idx);
614 return;
615}
616
618
624template <typename MatrixType>
626 const Axes &new_axes_map) {
627 if ((upper_rank == new_upper_rank) && (axes_map == new_axes_map)) return;
628
630
631 const size_t rank = this->rank();
632 Shape dim;
633 Axes axes;
634 dim.resize(rank);
635 axes.resize(rank);
636 for (size_t i = 0; i < rank; ++i) {
637 dim[i] = Dim[new_axes_map[i]];
638 axes[new_axes_map[i]] = i;
639 }
640 init(dim, new_upper_rank);
642
643 /* create lists of local position and destination rank */
644 const size_t local_size = T_old.local_size();
645 std::vector<int> dest_mpirank(local_size);
646 std::vector<size_t> local_position(local_size);
647
648 T_old.prep_local_to_global();
649 this->prep_global_to_local();
650
651#pragma omp parallel default(shared)
652 {
653 Index index;
654 index.resize(rank);
655
656#pragma omp for
657 for (size_t i = 0; i < local_size; ++i) {
658 T_old.global_index_fast(i, index);
659
660 int dest;
661 size_t pos;
662 this->local_position(index, dest, pos);
663
664 local_position[i] = pos;
666 }
667 }
668
669 /* exchange data */
670 replace_matrix_data(T_old.get_matrix(), dest_mpirank, local_position, Mat);
671
672 return;
673}
674
676
680template <typename MatrixType>
682 const size_t rank = Dim.size();
684
685 Shape dim_now = Dim;
686 Axes map_now = axes_map;
688 axes_inv.resize(rank);
689 for (size_t i = 0; i < rank; ++i) {
690 axes_inv[axes[i]] = i;
691 }
692
693 for (size_t i = 0; i < rank; ++i) {
694 Dim[i] = dim_now[axes[i]];
695 axes_map[i] = axes_inv[map_now[i]];
696 }
697
698 return (*this);
699}
700
702
712template <typename MatrixType>
713template <typename D>
715 size_t n_axes) {
716 assert(Dim[n_axes] <= vec.size());
717 const size_t local_size = this->local_size();
718 prep_local_to_global();
719#pragma omp parallel default(shared)
720 {
721 Index idx;
722 idx.resize(rank());
723#pragma omp for
724 for (size_t i = 0; i < local_size; ++i) {
725 global_index_fast(i, idx);
726 Mat[i] *= vec[idx[n_axes]];
727 }
728 }
729 return (*this);
730};
731
733
745template <typename MatrixType>
746template <typename D0, typename D1>
748 const std::vector<D0> &vec0, size_t n_axes0, const std::vector<D1> &vec1,
749 size_t n_axes1) {
750 assert(Dim[n_axes0] <= vec0.size());
751 assert(Dim[n_axes1] <= vec1.size());
752 const size_t local_size = this->local_size();
753 prep_local_to_global();
754#pragma omp parallel default(shared)
755 {
756 Index idx;
757 idx.resize(rank());
758#pragma omp for
759 for (size_t i = 0; i < local_size; ++i) {
760 global_index_fast(i, idx);
761 Mat[i] *= vec0[idx[n_axes0]] * vec1[idx[n_axes1]];
762 }
763 }
764 return (*this);
765};
766
768
782template <typename MatrixType>
783template <typename D0, typename D1, typename D2>
785 const std::vector<D0> &vec0, size_t n_axes0, const std::vector<D1> &vec1,
786 size_t n_axes1, const std::vector<D2> &vec2, size_t n_axes2) {
787 assert(Dim[n_axes0] <= vec0.size());
788 assert(Dim[n_axes1] <= vec1.size());
789 assert(Dim[n_axes2] <= vec2.size());
790 const size_t local_size = this->local_size();
791 prep_local_to_global();
792#pragma omp parallel default(shared)
793 {
794 Index idx;
795 idx.resize(rank());
796#pragma omp for
797 for (size_t i = 0; i < local_size; ++i) {
798 global_index_fast(i, idx);
799 Mat[i] *= vec0[idx[n_axes0]] * vec1[idx[n_axes1]] * vec2[idx[n_axes2]];
800 }
801 }
802 return (*this);
803};
804
806
822template <typename MatrixType>
823template <typename D0, typename D1, typename D2, typename D3>
825 const std::vector<D0> &vec0, size_t n_axes0, const std::vector<D1> &vec1,
826 size_t n_axes1, const std::vector<D2> &vec2, size_t n_axes2,
827 const std::vector<D3> &vec3, size_t n_axes3) {
828 assert(Dim[n_axes0] <= vec0.size());
829 assert(Dim[n_axes1] <= vec1.size());
830 assert(Dim[n_axes2] <= vec2.size());
831 assert(Dim[n_axes3] <= vec3.size());
832 const size_t local_size = this->local_size();
833 prep_local_to_global();
834#pragma omp parallel default(shared)
835 {
836 Index idx;
837 idx.resize(rank());
838#pragma omp for
839 for (size_t i = 0; i < local_size; ++i) {
840 global_index_fast(i, idx);
841 Mat[i] *= vec0[idx[n_axes0]] * vec1[idx[n_axes1]] * vec2[idx[n_axes2]] *
842 vec3[idx[n_axes3]];
843 }
844 }
845 return (*this);
846};
847
849
859template <typename MatrixType>
861 const size_t n_axes,
862 const size_t i_begin,
863 const size_t i_end) {
864 assert(rank() == a.rank());
865 assert(n_axes < rank());
867 assert(i_end <= shape()[n_axes]);
868 assert(i_end - i_begin == a.shape()[n_axes]);
869
870 /* create lists of local position and destination rank */
871 const size_t local_size = a.local_size();
872 std::vector<int> dest_mpirank(local_size);
873 std::vector<size_t> local_position(local_size);
874
876 prep_global_to_local();
877
878#pragma omp parallel default(shared)
879 {
880 Index index;
881 index.resize(rank());
882#pragma omp for
883 for (size_t i = 0; i < local_size; ++i) {
884 a.global_index_fast(i, index);
885 index[n_axes] += i_begin;
886
887 int dest;
888 size_t pos;
889 this->local_position(index, dest, pos);
890
891 local_position[i] = pos;
893 }
894 }
895
896 /* exchange data */
897 replace_matrix_data(a.get_matrix(), dest_mpirank, local_position,
898 get_matrix());
899
900 return (*this);
901}
902
904
914template <typename MatrixType>
916 const Index &index_begin,
917 const Index &index_end) {
918 const size_t nr = rank();
919 assert(nr == a.rank());
920 assert(index_begin.size() == nr);
921 assert(index_end.size() == nr);
922 for (size_t r = 0; r < nr; ++r) {
923 assert(index_end[r] <= shape()[r]);
925 }
926
927 /* create lists of local position and destination rank */
928 const size_t local_size = a.local_size();
929 std::vector<int> dest_mpirank(local_size);
930 std::vector<size_t> local_position(local_size);
931
933 prep_global_to_local();
934
935#pragma omp parallel default(shared)
936 {
937 Index index;
938 index.resize(nr);
939#pragma omp for
940 for (size_t i = 0; i < local_size; ++i) {
941 a.global_index_fast(i, index);
942 for (size_t r = 0; r < nr; ++r) {
943 if (index_begin[r] != index_end[r]) index[r] += index_begin[r];
944 }
945
946 int dest;
947 size_t pos;
948 this->local_position(index, dest, pos);
949
950 local_position[i] = pos;
952 }
953 }
954
955 /* exchange data */
956 replace_matrix_data(a.get_matrix(), dest_mpirank, local_position,
957 get_matrix());
958
959 return (*this);
960}
961
962
964
968template <typename MatrixType>
970 const size_t n = rank();
971 if (!(axes_map == range(n))) {
972 change_configuration(n / 2, range(n));
973 }
974 Tensor<lapack::Matrix<typename MatrixType::value_type>> T(get_comm(), get_matrix().flatten());
975 return reshape(T, Dim);
976}
977
978
980
984template <typename MatrixType>
985std::vector<typename MatrixType::value_type> Tensor<MatrixType>::flatten() {
986 const size_t n = rank();
987 if (!(axes_map == range(n))) {
988 change_configuration(n / 2, range(n));
989 }
990 return get_matrix().flatten();
991}
992
994template <typename MatrixType>
996 assert(Dim == rhs.shape());
997 change_configuration(rhs.get_upper_rank(), rhs.get_axes_map());
998 Mat += rhs.get_matrix();
999 return (*this);
1000}
1001
1003template <typename MatrixType>
1005 assert(Dim == rhs.shape());
1006 change_configuration(rhs.get_upper_rank(), rhs.get_axes_map());
1007 Mat -= rhs.get_matrix();
1008 return (*this);
1009}
1010
1012template <typename MatrixType>
1014 Mat *= rhs;
1015 return (*this);
1016}
1017
1019template <typename MatrixType>
1021 Mat /= rhs;
1022 return (*this);
1023}
1024
1026template <typename MatrixType>
1028 const size_t n = Mat.local_size();
1029 for (int i = 0; i < n; ++i) Mat[i] = rhs;
1030 return (*this);
1031}
1032
1034
1038template <typename MatrixType>
1039template <typename UnaryOperation>
1041 Mat.map(op);
1042 return (*this);
1043}
1044
1045/* ---------- non-member functions (Opeations) ---------- */
1046
1048
1054template <typename MatrixType>
1056 return T.transpose(axes);
1057}
1058
1060
1069template <typename MatrixType>
1071 size_t urank_new) {
1072 const size_t rank = T.rank();
1074 assert(urank_new <= rank);
1075
1076 if (urank_new == T.get_upper_rank()) {
1077 if (is_no_transpose(axes, T.get_axes_map(), rank)) return T;
1078 }
1079
1080 /* new index dimension */
1081 Shape dim_old = T.shape();
1082 Shape dim_new;
1083 dim_new.resize(rank);
1084 for (size_t r = 0; r < rank; ++r) {
1085 dim_new[r] = dim_old[axes[r]];
1086 }
1087
1088 /* new tensor */
1090
1091 /* create lists of local position and destination rank */
1092 const size_t local_size = T.local_size();
1093 std::vector<int> dest_mpirank(local_size);
1094 std::vector<size_t> local_position(local_size);
1095
1096 T.make_l2g_map();
1097 T_new.prep_global_to_local();
1098
1099#pragma omp parallel default(shared)
1100 {
1101 // Assuming axes_map of T_new is [0,1,2,...]
1102 std::vector<size_t> d_offset(rank);
1103 size_t d_row(1), d_col(1);
1104 for (size_t r = 0; r < urank_new; ++r) {
1105 d_offset[r] = d_row;
1106 d_row *= dim_new[r];
1107 }
1108 for (size_t r = urank_new; r < rank; ++r) {
1109 d_offset[r] = d_col;
1110 d_col *= dim_new[r];
1111 }
1112
1113 Axes axes_map = T.get_axes_map();
1114 std::vector<size_t> axes_inv(rank);
1115 std::vector<size_t> axes_trans(rank);
1116 for (size_t r = 0; r < rank; ++r) {
1117 axes_inv[axes[r]] = r;
1118 }
1119 for (size_t r = 0; r < rank; ++r) {
1120 axes_trans[r] = axes_inv[axes_map[r]];
1121 }
1122
1123 std::vector<size_t> index_new(rank);
1124
1125#pragma omp for
1126 for (size_t i = 0; i < local_size; ++i) {
1127 T.global_index_l2g_map_transpose(i, axes_trans.data(), index_new.data());
1128
1129 size_t g_row(0),
1130 g_col(0); // indices of global matrix for transposed tensor
1131 for (size_t r = 0; r < urank_new; ++r) {
1132 g_row += index_new[r] * d_offset[r];
1133 }
1134 for (size_t r = urank_new; r < rank; ++r) {
1135 g_col += index_new[r] * d_offset[r];
1136 }
1137
1138 T_new.local_position_fast(g_row, g_col, dest_mpirank[i],
1139 local_position[i]);
1140 }
1141 }
1142
1143 /* exchange data */
1144 replace_matrix_data(T.get_matrix(), dest_mpirank, local_position,
1145 T_new.get_matrix());
1146
1147 return T_new;
1148};
1149
1151
1162template <typename MatrixType>
1165
1166 const Shape &shape = T.shape();
1167 const size_t rank = shape.size();
1168 const size_t rank_new = shape_new.size();
1169
1170 /* initialize new tensor */
1171 Tensor<MatrixType> T_new(T.get_comm(), shape_new);
1172
1173 /* create lists of local position and destination rank */
1174 const size_t local_size = T.local_size();
1175 std::vector<int> dest_mpirank(local_size);
1176 std::vector<size_t> local_position(local_size);
1177
1178 T.prep_local_to_global();
1179 T_new.prep_global_to_local();
1180
1181#pragma omp parallel default(shared)
1182 {
1183 Index index, index_new;
1184 index.resize(rank);
1185 index_new.resize(rank_new);
1186#pragma omp for
1187 for (size_t i = 0; i < local_size; ++i) {
1188 T.global_index_fast(i, index);
1189 size_t global_position(0);
1190 size_t dim(1);
1191 for (size_t r = 0; r < rank; ++r) {
1192 global_position += index[r] * dim;
1193 dim *= shape[r];
1194 }
1195
1196 for (size_t r = 0; r < rank_new; ++r) {
1199 }
1200
1201 int dest;
1202 size_t pos;
1203 T_new.local_position(index_new, dest, pos);
1204
1205 local_position[i] = pos;
1206 dest_mpirank[i] = dest;
1207 }
1208 }
1209
1210 /* exchange data */
1211 replace_matrix_data(T.get_matrix(), dest_mpirank, local_position,
1212 T_new.get_matrix());
1213
1214 return T_new;
1215};
1216
1218
1228template <typename MatrixType>
1230 size_t i_begin, size_t i_end) {
1231 const int mpisize = T.get_comm_size();
1232 const Shape &shape = T.shape();
1233 assert(n_axes < T.rank());
1234 assert(i_begin < i_end);
1235 assert(i_end <= shape[n_axes]);
1236
1237 Shape shape_new = shape;
1239
1240 /* initialize new tensor */
1241 Tensor<MatrixType> T_new(T.get_comm(), shape_new);
1242
1243 /* create lists of local position and destination rank */
1244 const size_t local_size = T.local_size();
1245 std::vector<int> dest_mpirank(local_size);
1246 std::vector<size_t> local_position(local_size);
1247
1248 T.prep_local_to_global();
1249 T_new.prep_global_to_local();
1250
1251#pragma omp parallel default(shared)
1252 {
1253 Index index;
1254 index.resize(T.rank());
1255#pragma omp for
1256 for (size_t i = 0; i < local_size; ++i) {
1257 T.global_index_fast(i, index);
1258 if (index[n_axes] >= i_begin && index[n_axes] < i_end) {
1259 index[n_axes] -= i_begin;
1260
1261 int dest;
1262 size_t pos;
1263 T_new.local_position(index, dest, pos);
1264
1265 local_position[i] = pos;
1266 dest_mpirank[i] = dest;
1267 } else {
1268 // not send
1269 local_position[i] = 0;
1270 dest_mpirank[i] = mpisize;
1271 }
1272 }
1273 }
1274
1275 /* exchange data */
1276 replace_matrix_data(T.get_matrix(), dest_mpirank, local_position,
1277 T_new.get_matrix());
1278
1279 return T_new;
1280}
1281
1283
1296template <typename MatrixType>
1298 const Index &index_end) {
1299 const int mpisize = T.get_comm_size();
1300 const Shape &shape = T.shape();
1301 const size_t rank = T.rank();
1302 assert(index_begin.size() == rank);
1303 assert(index_end.size() == rank);
1304
1305 Shape shape_new = shape;
1306 for (size_t r = 0; r < rank; ++r) {
1307 assert(index_end[r] <= shape[r]);
1310 if (shape_new[r] == 0) shape_new[r] = shape[r];
1311 }
1312
1313 /* initialize new tensor */
1314 Tensor<MatrixType> T_new(T.get_comm(), shape_new);
1315
1316 /* create lists of local position and destination rank */
1317 const size_t local_size = T.local_size();
1318 std::vector<int> dest_mpirank(local_size);
1319 std::vector<size_t> local_position(local_size);
1320
1321 T.prep_local_to_global();
1322 T_new.prep_global_to_local();
1323
1324#pragma omp parallel default(shared)
1325 {
1326 Index index;
1327 index.resize(T.rank());
1328#pragma omp for
1329 for (size_t i = 0; i < local_size; ++i) {
1330 T.global_index_fast(i, index);
1331
1332 bool is_send = true;
1333 for (size_t r = 0; r < rank; ++r) {
1334 size_t idx = index[r];
1335 if (index_begin[r] == index_end[r]) {
1336 continue;
1337 } else if (idx >= index_begin[r] && idx < index_end[r]) {
1338 index[r] -= index_begin[r];
1339 } else {
1340 is_send = false;
1341 break;
1342 }
1343 }
1344
1345 if (is_send) {
1346 int dest;
1347 size_t pos;
1348 T_new.local_position(index, dest, pos);
1349
1350 local_position[i] = pos;
1351 dest_mpirank[i] = dest;
1352 } else {
1353 // not send
1354 local_position[i] = 0;
1355 dest_mpirank[i] = mpisize;
1356 }
1357 }
1358 }
1359
1360 /* exchange data */
1361 replace_matrix_data(T.get_matrix(), dest_mpirank, local_position,
1362 T_new.get_matrix());
1363
1364 return T_new;
1365};
1366
1368
1376template <typename MatrixType>
1378 assert(T.rank() == shape_new.size());
1380
1381 /* initialize new tensor */
1382 Tensor<MatrixType> T_new(T.get_comm(), shape_new);
1383
1384 /* create lists of local position and destination rank */
1385 const size_t local_size = T.local_size();
1386 std::vector<int> dest_mpirank(local_size);
1387 std::vector<size_t> local_position(local_size);
1388
1389 T.prep_local_to_global();
1390 T_new.prep_global_to_local();
1391
1392#pragma omp parallel default(shared)
1393 {
1394 Index index;
1395 index.resize(T.rank());
1396#pragma omp for
1397 for (size_t i = 0; i < local_size; ++i) {
1398 T.global_index_fast(i, index);
1399
1400 int dest;
1401 size_t pos;
1402 T_new.local_position(index, dest, pos);
1403
1404 local_position[i] = pos;
1405 dest_mpirank[i] = dest;
1406 }
1407 }
1408
1409 /* exchange data */
1410 replace_matrix_data(T.get_matrix(), dest_mpirank, local_position,
1411 T_new.get_matrix());
1412
1413 return T_new;
1414}
1415
1417
1422template <typename MatrixType>
1423typename MatrixType::value_type trace(const Tensor<MatrixType> &M) {
1424 assert(M.rank() == 2);
1425 return matrix_trace(M.get_matrix());
1426};
1427
1429
1442template <typename MatrixType>
1443typename MatrixType::value_type trace(const Tensor<MatrixType> &T, const Axes &axes_1, const Axes &axes_2) {
1444 assert(axes_1.size() == axes_2.size());
1445 assert(axes_1.size() + axes_2.size() == T.rank());
1447
1448 if (T.rank() == 2) return trace(T);
1449
1450 const size_t n = T.local_size();
1451 const size_t l = axes_1.size();
1452 Index index;
1453 bool check;
1454 typename MatrixType::value_type sum(0.0);
1455
1456 index.resize(T.rank());
1457 for (size_t i = 0; i < n; ++i) {
1458 T.global_index_fast(i, index);
1459 check = true;
1460 for (size_t k = 0; k < l; ++k) {
1461 if (index[axes_1[k]] != index[axes_2[k]]) {
1462 check = false;
1463 break;
1464 }
1465 }
1466 if (check) {
1467 sum += T[i];
1468 }
1469 }
1470
1471 return T.get_matrix().allreduce_sum(sum);
1472};
1473
1475
1488template <typename MatrixType>
1489typename MatrixType::value_type trace(const Tensor<MatrixType> &A, const Tensor<MatrixType> &B,
1490 const Axes &axes_a, const Axes &axes_b) {
1491 assert(A.rank() == B.rank());
1492 assert(A.rank() == axes_a.size());
1493 assert(B.rank() == axes_b.size());
1494 assert(debug::check_trace_axes(axes_a, axes_b, A.shape(), B.shape()));
1495
1496 const size_t rank = A.rank();
1497 Axes axes;
1499 Axes axes_map = A.get_axes_map();
1500 axes.resize(rank);
1501 axes_a_inv.resize(rank);
1502
1503 for (size_t i = 0; i < rank; ++i) {
1504 axes_a_inv[axes_a[i]] = i;
1505 }
1506 for (size_t i = 0; i < rank; ++i) {
1507 axes[i] = axes_b[axes_a_inv[axes_map[i]]];
1508 }
1509
1510 const size_t n = A.local_size();
1511 Tensor<MatrixType> B_t = transpose(B, axes, A.get_upper_rank());
1512 typename MatrixType::value_type sum(0.0);
1513
1514 for (size_t i = 0; i < n; ++i) {
1515 sum += A[i] * B_t[i];
1516 }
1517
1518 return A.get_matrix().allreduce_sum(sum);
1519}
1520
1522
1532template <typename MatrixType>
1534 const Axes &axes_2) {
1535 const int mpisize = T.get_comm_size();
1536 assert(axes_1.size() == axes_2.size());
1537 assert(axes_1.size() + axes_2.size() < T.rank());
1538 if (axes_1.size() == 0) return T;
1540
1541 Shape shape = T.shape();
1543 Axes axes_new;
1544 {
1545 Axes v = axes_1 + axes_2;
1546 v.sort();
1547 size_t k = 0;
1548 size_t n = v.size();
1549 for (size_t i = 0; i < T.rank(); ++i) {
1550 if (k < n && i == v[k]) {
1551 ++k;
1552 } else {
1553 shape_new.push(shape[i]);
1554 axes_new.push(i);
1555 }
1556 }
1557 }
1558
1559 /* initialize new tensor */
1560 Tensor<MatrixType> T_new(T.get_comm(), shape_new);
1561
1562 /* create lists of local position and destination rank */
1563 std::vector<int> dest_mpirank(T.local_size());
1564 std::vector<size_t> local_position(T.local_size());
1565
1566 Index index, index_new;
1567 index.resize(T.rank());
1568 index_new.resize(T_new.rank());
1569 bool check;
1570 const size_t n = axes_1.size();
1571
1572 for (size_t i = 0; i < T.local_size(); ++i) {
1573 T.global_index_fast(i, index);
1574 check = true;
1575 for (size_t k = 0; k < n; ++k) {
1576 if (index[axes_1[k]] != index[axes_2[k]]) {
1577 check = false;
1578 continue;
1579 }
1580 }
1581
1582 if (check) {
1583 for (size_t k = 0; k < index_new.size(); ++k) {
1584 index_new[k] = index[axes_new[k]];
1585 }
1586
1587 int dest;
1588 size_t pos;
1589 T_new.local_position(index_new, dest, pos);
1590
1591 local_position[i] = pos;
1592 dest_mpirank[i] = dest;
1593 } else {
1594 // not send
1595 local_position[i] = 0;
1596 dest_mpirank[i] = mpisize;
1597 }
1598 }
1599
1600 /* sum data */
1601 sum_matrix_data(T.get_matrix(), dest_mpirank, local_position,
1602 T_new.get_matrix());
1603
1604 return T_new;
1605}
1606
1608
1625template <typename MatrixType>
1627 assert(a.rank() == b.rank());
1628 assert(a.get_comm() == b.get_comm());
1629
1630 Shape shape_a = a.shape();
1631 Shape shape_b = b.shape();
1633 size_t n = shape_a.size();
1635 axes_trans.resize(2 * n);
1636 for (size_t i = 0; i < shape_b.size(); ++i) {
1637 shape_c[i] *= shape_b[i];
1638 axes_trans[2 * i] = i;
1639 axes_trans[2 * i + 1] = i + n;
1640 }
1641
1642 return reshape(
1644 reshape(b, Shape(1) + shape_b), Axes(n), Axes(0)),
1645 axes_trans),
1646 shape_c);
1647};
1648
1650
1661template <typename MatrixType>
1663 const Tensor<MatrixType> &b, const Axes &axes_a,
1664 const Axes &axes_b) {
1665 assert(axes_a.size() == axes_b.size());
1666 assert(a.get_comm() == b.get_comm());
1667 Shape shape_a = a.shape();
1668 Shape shape_b = b.shape();
1669 for (size_t i = 0; i < axes_a.size(); ++i) {
1671 }
1672
1673 const typename Tensor<MatrixType>::comm_type &comm = a.get_comm();
1674
1675 Shape shape_c;
1676 const size_t rank_row_c = a.rank() - axes_a.size();
1677 const size_t rank_col_c = b.rank() - axes_b.size();
1678 shape_c.resize(rank_row_c + rank_col_c);
1679
1682 size_t urank_a;
1683 size_t urank_b;
1684
1685 {
1686 const size_t rank = a.rank();
1687 const size_t rank_row = rank - axes_a.size();
1688 const size_t rank_col = axes_a.size();
1689 std::vector<size_t> v(rank);
1690 for (size_t i = 0; i < rank; ++i) v[i] = i;
1691 for (size_t i = 0; i < rank_col; ++i) v[axes_a[i]] = rank;
1692 std::sort(v.begin(), v.end());
1693 for (size_t i = 0; i < rank_col; ++i) v[rank_row + i] = axes_a[i];
1694
1695 trans_axes_a.assign(rank, v.data());
1696 urank_a = rank_row;
1697
1698 for (size_t i = 0; i < rank_row; ++i) shape_c[i] = shape_a[v[i]];
1699 }
1700
1701 {
1702 const size_t rank = b.rank();
1703 const size_t rank_row = axes_b.size();
1704 const size_t rank_col = rank - axes_b.size();
1705 std::vector<size_t> v(rank);
1706 for (size_t i = 0; i < rank; ++i) v[i] = i;
1707 for (size_t i = 0; i < rank_row; ++i) v[axes_b[i]] = 0;
1708 std::sort(v.begin(), v.end());
1709 for (size_t i = 0; i < rank_row; ++i) v[i] = axes_b[i];
1710
1711 trans_axes_b.assign(rank, v.data());
1712 urank_b = rank_row;
1713
1714 for (size_t i = 0; i < rank_col; ++i)
1716 }
1717
1719 matrix_product(transpose(a, trans_axes_a, urank_a).get_matrix(),
1720 transpose(b, trans_axes_b, urank_b).get_matrix(),
1721 c.get_matrix());
1722
1723 return c;
1724};
1725
1727
1735template <typename MatrixType>
1736int svd(const Tensor<MatrixType> &a, std::vector<double> &s) {
1737 assert(a.rank() == 2);
1738 int info;
1739 info = svd(a, Axes(0), Axes(1), s);
1740 return info;
1741}
1742
1744
1756template <typename MatrixType>
1758 std::vector<double> &s, Tensor<MatrixType> &vt) {
1759 assert(a.rank() == 2);
1760 int info;
1761 info = svd(a, Axes(0), Axes(1), u, s, vt);
1762 return info;
1763}
1764
1766
1776template <typename MatrixType>
1777int svd(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
1778 std::vector<double> &s) {
1779 assert(axes_row.size() > 0);
1780 assert(axes_col.size() > 0);
1782
1783 const size_t rank = a.rank();
1784 const size_t urank = axes_row.size();
1785
1787
1789 const Shape &shape = a_t.shape();
1790
1791 size_t d_row(1), d_col(1);
1792 for (size_t i = 0; i < urank; ++i) d_row *= shape[i];
1793 for (size_t i = urank; i < rank; ++i) d_col *= shape[i];
1794 size_t size = (d_row < d_col) ? d_row : d_col;
1795
1796 s.resize(size);
1797
1798 int info;
1799 info = matrix_svd(a_t.get_matrix(), s);
1800
1801 return info;
1802}
1803
1805
1824template <typename MatrixType>
1825int svd(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
1826 Tensor<MatrixType> &u, std::vector<double> &s, Tensor<MatrixType> &vt) {
1827 assert(axes_row.size() > 0);
1828 assert(axes_col.size() > 0);
1830
1831 const size_t rank = a.rank();
1832 const size_t urank = axes_row.size();
1833
1835
1837 const Shape &shape = a_t.shape();
1838
1839 size_t d_row(1), d_col(1);
1840 for (size_t i = 0; i < urank; ++i) d_row *= shape[i];
1841 for (size_t i = urank; i < rank; ++i) d_col *= shape[i];
1842 size_t size = (d_row < d_col) ? d_row : d_col;
1843
1844 Shape shape_u;
1845 shape_u.resize(urank + 1);
1846 for (size_t i = 0; i < urank; ++i) shape_u[i] = shape[i];
1847 shape_u[urank] = size;
1848
1850 shape_vt.resize(rank - urank + 1);
1851 shape_vt[0] = size;
1852 for (size_t i = urank; i < rank; ++i) shape_vt[i - urank + 1] = shape[i];
1853
1854 size_t urank_u = urank;
1855 size_t urank_vt = 1;
1856
1859 s.resize(size);
1860
1861 int info;
1862 info = matrix_svd(a_t.get_matrix(), u.get_matrix(), s, vt.get_matrix());
1863
1864 return info;
1865}
1866
1868
1879template <typename MatrixType>
1880int psvd(const Tensor<MatrixType> &a, std::vector<double> &s,
1881 const size_t target_rank) {
1882 int info = svd(a, s);
1883 if (s.size() > target_rank) s.resize(target_rank);
1884 return info;
1885}
1886
1888
1903template <typename MatrixType>
1905 std::vector<double> &s, Tensor<MatrixType> &vt,
1906 const size_t target_rank) {
1907 int info = svd(a, u, s, vt);
1908 if (s.size() > target_rank) {
1909 s.resize(target_rank);
1910 u = slice(u, 1, 0, target_rank);
1911 vt = slice(vt, 0, 0, target_rank);
1912 }
1913 return info;
1914}
1915
1917
1930template <typename MatrixType>
1931int psvd(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
1932 std::vector<double> &s, const size_t target_rank) {
1933 int info = svd(a, axes_row, axes_col, s);
1934 if (s.size() > target_rank) s.resize(target_rank);
1935 return info;
1936}
1937
1939
1961template <typename MatrixType>
1962int psvd(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
1963 Tensor<MatrixType> &u, std::vector<double> &s, Tensor<MatrixType> &vt,
1964 const size_t target_rank) {
1965 int info = svd(a, axes_row, axes_col, u, s, vt);
1966 if (s.size() > target_rank) {
1967 s.resize(target_rank);
1968 u = slice(u, axes_row.size(), 0, target_rank);
1969 vt = slice(vt, 0, 0, target_rank);
1970 }
1971 return info;
1972}
1973
1975
1987template <typename MatrixType>
1989 assert(a.rank() == 2);
1990 int info;
1991 info = qr(a, Axes(0), Axes(1), q, r);
1992 return info;
1993}
1994
1996
2019template <typename MatrixType>
2020int qr(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
2022 assert(axes_row.size() > 0);
2023 assert(axes_col.size() > 0);
2025
2026 const size_t rank = a.rank();
2027 const size_t urank = axes_row.size();
2028 const Shape shape_a = a.shape();
2029
2031 Shape shape;
2032 shape.resize(rank);
2033 for (size_t i = 0; i < rank; ++i) shape[i] = shape_a[axes[i]];
2034
2035 size_t d_row(1), d_col(1);
2036 for (size_t i = 0; i < urank; ++i) d_row *= shape[i];
2037 for (size_t i = urank; i < rank; ++i) d_col *= shape[i];
2038 size_t size = (d_row < d_col) ? d_row : d_col;
2039
2040 // rank-2 tensors (matrices)
2043 Tensor<MatrixType> mat_r(mat_q.get_comm(), mat_q.shape(), 1);
2044
2045 // QR decomposition. Elements of mat_q change from a to q.
2046 int info;
2047 info = matrix_qr(mat_q.get_matrix(), mat_r.get_matrix());
2048
2049 // Get shape of q and r.
2050 Shape shape_q;
2051 shape_q.resize(urank + 1);
2052 for (size_t i = 0; i < urank; ++i) shape_q[i] = shape[i];
2053 shape_q[urank] = size;
2054
2055 Shape shape_r;
2056 shape_r.resize(rank - urank + 1);
2057 shape_r[0] = size;
2058 for (size_t i = urank; i < rank; ++i) shape_r[i - urank + 1] = shape[i];
2059
2060 // Reshape q and r.
2061 if (d_row > d_col) {
2062 q = reshape(mat_q, shape_q);
2063 r = reshape(slice(mat_r, 0, 0, size), shape_r);
2064 } else if (d_row < d_col) {
2065 q = reshape(slice(mat_q, 1, 0, size), shape_q);
2066 r = reshape(mat_r, shape_r);
2067 } else { // d_row==d_col
2068 q = reshape(mat_q, shape_q);
2069 r = reshape(mat_r, shape_r);
2070 }
2071
2072 return info;
2073}
2074
2077
2084template <typename MatrixType>
2085int eigh(const Tensor<MatrixType> &a, std::vector<double> &w,
2087 assert(a.rank() == 2);
2088 Shape shape = a.shape();
2089 assert(shape[0] == shape[1]);
2090
2091 Tensor<MatrixType> a_t = transpose(a, Axes(0, 1), 1);
2092
2093 size_t n = shape[0];
2094 w.resize(n);
2095 z = Tensor<MatrixType>(a.get_comm(), Shape(n, n), 1);
2096
2097 int info;
2098 info = matrix_eigh(a_t.get_matrix(), w, z.get_matrix());
2099 return info;
2100};
2101
2104
2110template <typename MatrixType>
2111int eigh(const Tensor<MatrixType> &a, std::vector<double> &w) {
2112 assert(a.rank() == 2);
2113 Shape shape = a.shape();
2114 assert(shape[0] == shape[1]);
2115
2116 Tensor<MatrixType> a_t = transpose(a, Axes(0, 1), 1);
2117
2118 size_t n = shape[0];
2119 w.resize(n);
2120
2121 int info;
2122 info = matrix_eigh(a_t.get_matrix(), w);
2123 return info;
2124};
2125
2128
2148template <typename MatrixType>
2149int eigh(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
2150 std::vector<double> &w, Tensor<MatrixType> &z) {
2151 assert(axes_row.size() > 0);
2152 assert(axes_col.size() > 0);
2153
2154 const size_t rank = a.rank();
2155 const size_t urank = axes_row.size();
2156
2158
2160 const Shape &shape = a_t.shape();
2161
2162 size_t d_row(1), d_col(1);
2163 for (size_t i = 0; i < urank; ++i) d_row *= shape[i];
2164 for (size_t i = urank; i < rank; ++i) d_col *= shape[i];
2165 size_t size = (d_row < d_col) ? d_row : d_col;
2166
2167 assert(d_row == d_col);
2168
2169 Shape shape_z;
2170 shape_z.resize(urank + 1);
2171 for (size_t i = 0; i < urank; ++i) shape_z[i] = shape[i];
2172 shape_z[urank] = size;
2173
2175 w.resize(size);
2176
2177 int info;
2178 info = matrix_eigh(a_t.get_matrix(), w, z.get_matrix());
2179 return info;
2180};
2181
2183
2193template <typename MatrixType>
2194int eigh(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
2195 std::vector<double> &w) {
2196 assert(axes_row.size() > 0);
2197 assert(axes_col.size() > 0);
2198
2199 const size_t rank = a.rank();
2200 const size_t urank = axes_row.size();
2201
2203
2205 const Shape &shape = a_t.shape();
2206
2207 size_t d_row(1), d_col(1);
2208 for (size_t i = 0; i < urank; ++i) d_row *= shape[i];
2209 for (size_t i = urank; i < rank; ++i) d_col *= shape[i];
2210 size_t size = (d_row < d_col) ? d_row : d_col;
2211 w.resize(size);
2212
2213 assert(d_row == d_col);
2214
2215 int info;
2216 info = matrix_eigh(a_t.get_matrix(), w);
2217 return info;
2218};
2219
2222
2253template <typename MatrixType>
2255 const Axes &axes_col_a, const Tensor<MatrixType> &b,
2256 const Axes &axes_row_b, const Axes &axes_col_b, std::vector<double> &w,
2258 assert(axes_row_a.size() > 0);
2259 assert(axes_col_a.size() > 0);
2260 assert(axes_row_b.size() > 0);
2261 assert(axes_col_b.size() > 0);
2262
2263 const size_t rank_a = a.rank();
2264 const size_t rank_b = b.rank();
2265 const size_t urank_a = axes_row_a.size();
2266 const size_t urank_b = axes_row_b.size();
2271 const Shape &shape_a = a_t.shape();
2272 const Shape &shape_b = b_t.shape();
2273 size_t d_row_a(1), d_col_a(1);
2274 size_t d_row_b(1), d_col_b(1);
2275 for (size_t i = 0; i < urank_a; ++i) d_row_a *= shape_a[i];
2276 for (size_t i = 0; i < urank_b; ++i) d_row_b *= shape_b[i];
2277 for (size_t i = urank_a; i < rank_a; ++i) d_col_a *= shape_a[i];
2278 for (size_t i = urank_b; i < rank_b; ++i) d_col_b *= shape_b[i];
2279
2283 size_t size = d_row_a;
2284
2285 Shape shape_z;
2287 for (size_t i = urank_a; i < rank_a; ++i) shape_z[i - urank_a] = shape_a[i];
2288 shape_z[rank_a - urank_a] = size;
2289
2291 w.resize(size);
2292
2293 int info;
2294 info = matrix_eigh(a_t.get_matrix(), b_t.get_matrix(), w, z.get_matrix());
2295
2296 return info;
2297};
2298
2300
2308template <typename MatrixType>
2309int eig(const Tensor<MatrixType> &a, std::vector<complex> &w,
2311 assert(a.rank() == 2);
2312 Shape shape = a.shape();
2313 assert(shape[0] == shape[1]);
2314
2316
2317 size_t n = shape[0];
2318 w.resize(n);
2319
2321
2322 int info;
2323 info = matrix_eig(a_t.get_matrix(), w, z_t.get_matrix());
2324
2326
2327 return info;
2328};
2329
2331
2338template <typename MatrixType>
2339int eig(const Tensor<MatrixType> &a, std::vector<complex> &w) {
2340 assert(a.rank() == 2);
2341 Shape shape = a.shape();
2342 assert(shape[0] == shape[1]);
2343
2345
2346 size_t n = shape[0];
2347 w.resize(n);
2348
2349 int info;
2350 info = matrix_eig(a_t.get_matrix(), w);
2351 return info;
2352};
2353
2355
2375template <typename MatrixType>
2376int eig(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
2377 std::vector<complex> &w, typename Tensor<MatrixType>::template rebind<complex> &z) {
2378 assert(axes_row.size() > 0);
2379 assert(axes_col.size() > 0);
2380
2381 const size_t rank = a.rank();
2382 const size_t urank = axes_row.size();
2383
2385
2387 const Shape &shape = a_t.shape();
2388
2389 size_t d_row(1), d_col(1);
2390 for (size_t i = 0; i < urank; ++i) d_row *= shape[i];
2391 for (size_t i = urank; i < rank; ++i) d_col *= shape[i];
2392 size_t size = (d_row < d_col) ? d_row : d_col;
2393
2394 assert(d_row == d_col);
2395
2396 Shape shape_z;
2397 shape_z.resize(urank + 1);
2398 for (size_t i = 0; i < urank; ++i) shape_z[i] = shape[i];
2399 shape_z[urank] = size;
2400
2402
2403 w.resize(size);
2404
2405 int info;
2406 info = matrix_eig(a_t.get_matrix(), w, z_t.get_matrix());
2407
2409
2410 return info;
2411};
2412
2414
2424template <typename MatrixType>
2425int eig(const Tensor<MatrixType> &a, const Axes &axes_row, const Axes &axes_col,
2426 std::vector<complex> &w) {
2427 assert(axes_row.size() > 0);
2428 assert(axes_col.size() > 0);
2429
2430 const size_t rank = a.rank();
2431 const size_t urank = axes_row.size();
2432
2434
2436 const Shape &shape = a_t.shape();
2437
2438 size_t d_row(1), d_col(1);
2439 for (size_t i = 0; i < urank; ++i) d_row *= shape[i];
2440 for (size_t i = urank; i < rank; ++i) d_col *= shape[i];
2441 size_t size = (d_row < d_col) ? d_row : d_col;
2442 w.resize(size);
2443
2444 assert(d_row == d_col);
2445
2446 int info;
2447 info = matrix_eig(a_t.get_matrix(), w);
2448 return info;
2449};
2450
2451
2453
2460template <typename MatrixType>
2461int solve(const Tensor<MatrixType> &a, const std::vector<typename MatrixType::value_type> &b,
2462 std::vector<typename MatrixType::value_type> &x) {
2463 assert(a.rank() == 2);
2464 assert(a.shape()[0] == a.shape()[1]);
2465 assert(a.shape()[0] == b.size());
2466
2468 int info;
2469 info = solve(a, Tensor<MatrixType>(a.get_comm(), b), x_t, Axes(0), Axes(1),
2470 Axes(0), Axes());
2471 x = x_t.flatten();
2472
2473 return info;
2474};
2475
2477
2484template <typename MatrixType>
2487 assert(a.rank() == 2);
2488 assert(b.rank() == 2 || b.rank() == 1);
2489 assert(a.shape()[0] == a.shape()[1]);
2490 assert(a.shape()[0] == b.shape()[0]);
2491 int info;
2492
2493 if (b.rank() == 2) {
2494 info = solve(a, b, x, Axes(0), Axes(1), Axes(0), Axes(1));
2495 } else {
2496 info = solve(a, b, x, Axes(0), Axes(1), Axes(0), Axes());
2497 }
2498
2499 return info;
2500};
2501
2503
2530template <typename MatrixType>
2533 const Axes &axes_row_b, const Axes &axes_col_b) {
2534 assert(a.rank() == axes_row_a.size() + axes_col_a.size());
2535 assert(b.rank() == axes_row_b.size() + axes_col_b.size());
2536 assert(axes_row_a.size() > 0);
2537 assert(axes_col_a.size() > 0);
2538 assert(axes_row_b.size() > 0);
2539 assert(axes_col_b.size() >= 0);
2540
2541 // size_t rank_a = a.rank();
2542 // size_t rank_b = b.rank();
2543 size_t rank_row_a = axes_row_a.size();
2544 size_t rank_col_a = axes_col_a.size();
2545 size_t rank_row_b = axes_row_b.size();
2546 size_t rank_col_b = axes_col_b.size();
2549
2552 const Shape &shape_a = a_t.shape();
2553 const Shape &shape_b = b_t.shape();
2554
2556
2557 Shape shape_x;
2559 for (size_t i = 0; i < rank_col_a; ++i) shape_x[i] = shape_a[i + rank_row_a];
2560 for (size_t i = 0; i < rank_col_b; ++i)
2562
2563 int info;
2564 info = matrix_solve(a_t.get_matrix(), b_t.get_matrix());
2565 x = reshape(b_t, shape_x);
2566 return info;
2567};
2568
2570template <typename MatrixType>
2575template <typename MatrixType>
2577 return (rhs *= -1.0);
2578}
2580template <typename MatrixType>
2582 const Tensor<MatrixType> &rhs) {
2583 return (lhs += rhs);
2584}
2586template <typename MatrixType>
2588 const Tensor<MatrixType> &rhs) {
2589 return (lhs -= rhs);
2590}
2592template <typename MatrixType, typename D>
2594 return (lhs *= rhs);
2595}
2597template <typename MatrixType, typename D>
2599 return (lhs /= rhs);
2600}
2602template <typename MatrixType, typename D>
2604 return (rhs *= lhs);
2605}
2606
2608template <typename MatrixType>
2609inline double max(const Tensor<MatrixType> &t) {
2610 return max(t.get_matrix());
2611}
2613template <typename MatrixType>
2614inline double min(const Tensor<MatrixType> &t) {
2615 return min(t.get_matrix());
2616}
2618template <typename MatrixType>
2619inline double max_abs(const Tensor<MatrixType> &t) {
2620 return max_abs(t.get_matrix());
2621}
2623template <typename MatrixType>
2624inline double min_abs(const Tensor<MatrixType> &t) {
2625 return min_abs(t.get_matrix());
2626}
2627
2629template <typename MatrixType>
2631 using value_type = typename MatrixType::value_type;
2632 if constexpr (std::is_same_v<value_type, double>) {
2633 return t.map(static_cast<double (*)(double)>(&std::sqrt));
2634 } else {
2635 return t.map(static_cast<complex (*)(const complex &)>(&std::sqrt));
2636 }
2637}
2638template <typename MatrixType>
2640 using value_type = typename MatrixType::value_type;
2641 if constexpr (std::is_same_v<value_type, double>) {
2642 return t;
2643 } else {
2644 return t.map(static_cast<complex (*)(const complex &)>(&std::conj));
2645 }
2646}
2648
2650
2654template <typename MatrixType>
2655std::ostream &operator<<(std::ostream &out, const Tensor<MatrixType> &t) {
2656 std::size_t dim = t.ndim();
2657 if (t.get_comm_size() == 1) {
2658 std::size_t size = t.local_size();
2659 Shape shape = t.shape();
2660 std::vector<std::size_t> accum(dim + 1, 1);
2661 for (size_t d = dim; d != 0; --d) accum[d - 1] = accum[d] * shape[d - 1];
2662
2663 std::vector<std::size_t> idx(dim);
2664 for (size_t i = 0; i < size; ++i) {
2665 for (size_t d = 0; d < dim; ++d) idx[d] = (i % accum[d]) / accum[d + 1];
2666 if (idx[dim - 1] == 0) {
2667 size_t count = 0;
2668 for (size_t d = dim; d != 0 && idx[d - 1] == 0; --d) ++count;
2669 for (size_t i = 0; i < dim - count; ++i) out << ' ';
2670 for (size_t i = 0; i < count; ++i) out << '[';
2671 }
2672
2673 using value_type = typename MatrixType::value_type;
2674 value_type val;
2675 t.get_value(idx, val);
2676 out << ' ' << val << ' ';
2677
2678 if (idx[dim - 1] == shape[dim - 1] - 1) {
2679 size_t count = 0;
2680 for (size_t d = dim; d != 0 && idx[d - 1] == shape[d - 1] - 1; --d) ++count;
2681 for (size_t i = 0; i < count; ++i) out << ']';
2682 if (count < dim) {
2683 for (size_t i = 0; i < count; ++i) out << '\n';
2684 } else {
2685 out << '\n';
2686 }
2687 }
2688 }
2689 } else {
2690 if (t.get_comm_rank() == 0) {
2691 for (size_t d = 0; d < dim; ++d) out << '[';
2692 out << " distributed tensor ... ";
2693 for (size_t d = 0; d < dim; ++d) out << ']';
2694 out << '\n';
2695 }
2696 }
2697 return out;
2698}
2699
2700} // namespace mptensor
2701
2702#endif // _TENSOR_IMPL_HPP_
Definition index.hpp:39
void resize(size_t n)
Definition index.hpp:81
void sort()
Definition index.cc:42
size_t size() const
Definition index.hpp:79
Tensor class. The main object of mptensor.
Definition tensor.hpp:54
Tensor< MatrixType > & transpose(const Axes &axes)
Transposition of tensor with lazy evaluation.
Definition tensor_impl.hpp:681
typename MatrixType::value_type value_type
double or complex
Definition tensor.hpp:56
size_t rank() const
Rank of tensor.
Definition tensor_impl.hpp:165
const comm_type & get_comm() const
Communicator.
Definition tensor_impl.hpp:217
const Axes & get_axes_map() const
Map of axes for lazy evaluation of transpose.
Definition tensor_impl.hpp:198
size_t local_size() const
Size of local storage.
Definition tensor_impl.hpp:180
std::vector< value_type > flatten()
Return a copy of the flattened vector.
Definition tensor_impl.hpp:985
Tensor< MatrixType > & map(UnaryOperation op)
Apply a unary operation to each element.
Definition tensor_impl.hpp:1040
void make_l2g_map() const
Preprocess for fast conversion from local index to global one.
Definition tensor_impl.hpp:265
const value_type & operator[](size_t local_idx) const
Const array subscript operator.
Definition tensor_impl.hpp:238
void global_index_fast(size_t i, Index &idx) const
Convert local index to global index fast.
Definition tensor_impl.hpp:539
Tensor< MatrixType > & operator=(value_type rhs)
Initialize all elements by rhs.
Definition tensor_impl.hpp:1027
void global_index_l2g_map_transpose(size_t lindex, const size_t axes_trans[], size_t index_new[]) const
Convert local index to global index of transposed tensor using l2g_map.
Definition tensor_impl.hpp:365
void local_position(const Index &idx, int &comm_rank, size_t &local_idx) const
Calculate rank which has the given global index and its local index.
Definition tensor_impl.hpp:598
void global_index_l2g_map(size_t lindex, size_t gindex[]) const
Convert local index to global index using l2g_map.
Definition tensor_impl.hpp:330
Tensor< lapack::Matrix< value_type > > gather()
Gather all elements into a non-distributed tensor.
Definition tensor_impl.hpp:969
bool get_value(const Index &idx, value_type &val) const
Get an element.
Definition tensor_impl.hpp:566
Tensor< MatrixType > & operator-=(const Tensor &rhs)
Subtraction assignment.
Definition tensor_impl.hpp:1004
void prep_local_to_global() const
Preprocess for fast conversion from local index to global one.
Definition tensor_impl.hpp:259
void print_info_mpi(std::ostream &, const std::string &tag="") const
Output information of tensor.
Definition tensor_impl.hpp:456
void print_info(std::ostream &out, const std::string &tag="") const
Output information of tensor.
Definition tensor_impl.hpp:438
size_t ndim() const
Rank of tensor.
Definition tensor_impl.hpp:174
Tensor< MatrixType > & multiply_vector(const std::vector< D > &vec, size_t n_axes)
Element-wise vector multiplication.
Definition tensor_impl.hpp:714
void set_value(const Index &idx, value_type val)
Set an element.
Definition tensor_impl.hpp:584
Tensor< MatrixType > & operator/=(value_type rhs)
Scalar-division assignment.
Definition tensor_impl.hpp:1020
int get_comm_rank() const
Rank of process.
Definition tensor_impl.hpp:229
void local_position_fast(size_t g_row, size_t g_col, int &comm_rank, size_t &local_idx) const
Definition tensor_impl.hpp:390
Index global_index(size_t i) const
Convert local index to global index.
Definition tensor_impl.hpp:509
void prep_global_to_local() const
Preprocess for fast conversion from global index to local one.
Definition tensor_impl.hpp:253
Tensor< MatrixType > & operator*=(value_type rhs)
Scalar-multiplication assignment.
Definition tensor_impl.hpp:1013
Tensor< MatrixType > & set_slice(const Tensor &a, size_t n_axes, size_t i_begin, size_t i_end)
Inverse of slice().
Definition tensor_impl.hpp:860
const Shape & shape() const
Shape of tensor.
Definition tensor_impl.hpp:159
size_t get_upper_rank() const
Upper rank for matrix representation.
Definition tensor_impl.hpp:186
Tensor< MatrixType > & operator+=(const Tensor &rhs)
Addition assignment.
Definition tensor_impl.hpp:995
const MatrixType & get_matrix() const
distributed Matrix
Definition tensor_impl.hpp:204
int get_comm_size() const
Size of communicator.
Definition tensor_impl.hpp:223
typename MatrixType::comm_type comm_type
type of communicator. MPI_Comm or int.
Definition tensor.hpp:58
Define the type of a complex number.
Tensor< MatrixType > operator/(Tensor< MatrixType > lhs, D rhs)
Scalar division.
Definition tensor_impl.hpp:2598
Tensor< MatrixType > operator-(Tensor< MatrixType > rhs)
Unary minus.
Definition tensor_impl.hpp:2576
Tensor< MatrixType > operator*(Tensor< MatrixType > lhs, D rhs)
Tensor-scalar multiplication.
Definition tensor_impl.hpp:2593
std::complex< double > complex
Definition complex.hpp:38
int eig(const Tensor< MatrixType > &a, std::vector< complex > &eigval, typename Tensor< MatrixType >::template rebind< complex > &eigvec)
Compute the eigenvalues and eigenvectors of a general matrix (rank-2 tensor)
Definition tensor_impl.hpp:2309
int psvd(const Tensor< MatrixType > &a, std::vector< double > &s, const size_t target_rank)
Partial SVD for rank-2 tensor (matrix)
Definition tensor_impl.hpp:1880
int eigh(const Tensor< MatrixType > &a, std::vector< double > &eigval, Tensor< MatrixType > &eigvec)
Definition tensor_impl.hpp:2085
int qr(const Tensor< MatrixType > &a, Tensor< MatrixType > &q, Tensor< MatrixType > &r)
QR decomposition of matrix (rank-2 tensor)
Definition tensor_impl.hpp:1988
int svd(const Tensor< MatrixType > &a, std::vector< double > &s)
Singular value decomposition for rank-2 tensor (matrix)
Definition tensor_impl.hpp:1736
MatrixType::value_type trace(const Tensor< MatrixType > &a)
Trace of matrix (rank-2 tensor)
Definition tensor_impl.hpp:1423
Tensor< MatrixType > contract(const Tensor< MatrixType > &a, const Axes &axes_1, const Axes &axes_2)
Partial trace of tensor.
Definition tensor_impl.hpp:1533
Tensor< MatrixType > tensordot(const Tensor< MatrixType > &a, const Tensor< MatrixType > &b, const Axes &axes_a, const Axes &axes_b)
Compute tensor dot product.
Definition tensor_impl.hpp:1662
Tensor< MatrixType > kron(const Tensor< MatrixType > &a, const Tensor< MatrixType > &b)
Compute the Kronecker product.
Definition tensor_impl.hpp:1626
int solve(const Tensor< MatrixType > &a, const std::vector< typename MatrixType::value_type > &b, std::vector< typename MatrixType::value_type > &x)
Solve linear equation .
Definition tensor_impl.hpp:2461
Tensor< MatrixType > conj(Tensor< MatrixType > t)
Take conjugate of each element.
double min_abs(const Tensor< MatrixType > &t)
Return minimum of the absolute value of an element.
Definition tensor_impl.hpp:2624
Tensor< MatrixType > sqrt(Tensor< MatrixType > t)
Take square-root of each element.
double min(const Tensor< MatrixType > &t)
Return the minimum element. For complex, same as min_abs().
Definition tensor_impl.hpp:2614
double max_abs(const Tensor< MatrixType > &t)
Return maximum of the absolute value of an element.
Definition tensor_impl.hpp:2619
double max(const Tensor< MatrixType > &t)
Return the maximum element. For complex, same as max_abs().
Definition tensor_impl.hpp:2609
Tensor< MatrixType > extend(const Tensor< MatrixType > &a, const Shape &shape_new)
Extend the size of a tensor.
Definition tensor_impl.hpp:1377
Tensor< MatrixType > transpose(Tensor< MatrixType > a, const Axes &axes)
Transposition of tensor with lazy evaluation.
Definition tensor_impl.hpp:1055
Tensor< MatrixType > reshape(const Tensor< MatrixType > &a, const Shape &shape_new)
Change the shape of tensor.
Definition tensor_impl.hpp:1163
Tensor< MatrixType > slice(const Tensor< MatrixType > &a, size_t n_axes, size_t i_begin, size_t i_end)
Slice a tensor.
Definition tensor_impl.hpp:1229
Tensor()
Default constructor of tensor.
Definition tensor_impl.hpp:71
header file of Index class
Index(size_t j0)
Definition index_constructor.hpp:11
List of header files for matrix classes.
mptensor::complex complex
Definition matrix_lapack.cc:36
bool check_total_size(const Shape &s1, const Shape &s2)
Definition tensor.cc:49
bool check_trace_axes(const Axes &axes_1, const Axes &axes_2, size_t rank)
Definition tensor.cc:86
bool check_extend(const Shape &s_old, const Shape &s_new)
Definition tensor.cc:57
bool check_svd_axes(const Axes &axes_row, const Axes &axes_col, size_t rank)
Definition tensor.cc:76
bool check_contract_axes(const Axes &axes_1, const Axes &axes_2, size_t rank)
Definition tensor.cc:114
bool check_transpose_axes(const Axes &axes, size_t rank)
Definition tensor.cc:66
bool check_square(const Shape &shape, size_t urank)
Definition tensor.cc:125
void replace_matrix_data(const Matrix< C > &M, const std::vector< int > &dest_rank, const std::vector< size_t > &local_position, Matrix< C > &M_new)
Definition complex.hpp:34
Index Shape
Definition tensor.hpp:46
std::ostream & operator<<(std::ostream &os, const Index &idx)
Index range(const size_t start, const size_t stop)
Create an increasing sequence. it is similar to range() in python.
Definition index.cc:91
Index Axes
Definition tensor.hpp:45
bool is_no_transpose(const Axes &axes, const Axes &axes_map, size_t rank)
Definition tensor.cc:35
Index operator+(const Index &, const Index &)
Tensor class.