Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
Tensor.h
Go to the documentation of this file.
1
13
14#pragma once
15
16#ifndef _TENSOR_H_
17#define _TENSOR_H_ 1
18
19#include <complex>
20#include <initializer_list>
21#include <numeric>
22#include <unordered_set>
23#include <valarray>
24#include <vector>
25
26#include <boost/archive/text_iarchive.hpp>
27#include <boost/archive/text_oarchive.hpp>
28#include <boost/serialization/valarray.hpp>
29#include <boost/serialization/vector.hpp>
30
31#include "QubitRegisterCalculator.h"
32#include "TensorContraction.h"
33
34namespace Utils
35{
36
37// WARNING: Not all functions are tested, some of them are tested only
38// superficially, use with caution! Some were tested before switching to fortran
39// layout, so they might not work properly anymore! Accessing values and
40// contractions are working since they are used in circuit cutting and in the
41// tensor networks simulator.
42template <class T = std::complex<double>, class Storage = std::valarray<T>> class Tensor
43{
44 protected:
45 Storage values;
46 std::vector<size_t> dims;
47 mutable size_t sz = 0;
48
49 public:
51
52 Tensor() : sz(0)
53 {
54 }
55
56 // a dummy tensor should be used only for incrementing indices, not for
57 // storing values!
58 Tensor(const std::vector<size_t> &dims, bool dummy = false) : dims(dims), sz(0)
59 {
60 if (!dummy)
61 {
62 if constexpr (std::is_convertible<int, T>::value)
63 values.resize(GetSize(), static_cast<T>(0));
64 else
65 values.resize(GetSize());
66 }
67 }
68
69 Tensor(const std::vector<int> &dims, bool dummy = false) : dims(dims.cbegin(), dims.cend()), sz(0)
70 {
71 if (!dummy)
72 {
73 if constexpr (std::is_convertible<int, T>::value)
74 values.resize(GetSize(), static_cast<T>(0));
75 else
76 values.resize(GetSize());
77 }
78 }
79
80 template <class indT = size_t> Tensor(std::initializer_list<indT> dims, bool dummy = false) : dims(dims.begin(), dims.end()), sz(0)
81 {
82 if (!dummy)
83 {
84 if constexpr (std::is_convertible<int, T>::value)
85 values.resize(GetSize(), static_cast<T>(0));
86 else
87 values.resize(GetSize());
88 }
89 }
90
91 Tensor(const Tensor<T, Storage> &other) : values(other.values), dims(other.dims), sz(other.sz)
92 {
93 }
94
95 Tensor(Tensor<T, Storage> &&other) noexcept
96 {
97 dims.swap(other.dims);
98 values.swap(other.values);
99 std::swap(sz, other.sz);
100 }
101
102 virtual ~Tensor() = default;
103
104 template <class Archive> void serialize(Archive &ar, const unsigned int /*version*/)
105 {
106 if (typename Archive::is_loading())
107 values.clear();
108
109 ar &dims &sz;
110 }
111
113 {
114 Tensor temp(other);
115 *this = std::move(temp);
116
117 return *this;
118 }
119
121 {
122 if (this != &other)
123 {
124 dims.swap(other.dims);
125 values.swap(other.values);
126 std::swap(sz, other.sz);
127 }
128
129 return *this;
130 }
131
133 {
134 dims.swap(other.dims);
135 values.swap(other.values);
136 std::swap(sz, other.sz);
137 }
138
139 size_t GetSize() const
140 {
141 if (!sz)
142 {
143 size_t count = 1;
144 for (auto dimension : dims)
145 count = detail::TensorSizeProduct(count, dimension);
146 sz = count;
147 }
148
149 return sz;
150 }
151
152 size_t GetDim(size_t index) const
153 {
154 assert(index < dims.size());
155
156 return dims[index];
157 }
158
159 const std::vector<size_t> &GetDims() const
160 {
161 return dims;
162 }
163
164 const size_t GetRank() const
165 {
166 return dims.size();
167 }
168
169 inline bool IsDummy() const
170 {
171 return values.size() == 0;
172 }
173
174 inline bool IncrementIndex(std::vector<size_t> &indices) const
175 {
176 long long pos = dims.size() - 1;
177
178 while (pos >= 0)
179 {
180 if (indices[pos] < dims[pos] - 1)
181 {
182 ++indices[pos];
183 break;
184 }
185 else
186 {
187 indices[pos] = 0;
188 --pos;
189 }
190 }
191
192 return pos >= 0;
193 }
194
195 inline bool IncrementIndexSkip(std::vector<size_t> &indices, int skip) const
196 {
197 long long pos = dims.size() - 1;
198
199 while (pos >= 0)
200 {
201 const bool notOnPos = pos != skip;
202 if (notOnPos && indices[pos] < dims[pos] - 1)
203 {
204 ++indices[pos];
205 break;
206 }
207 else
208 {
209 if (notOnPos)
210 indices[pos] = 0;
211 --pos;
212 }
213 }
214
215 return pos >= 0;
216 }
217
218 inline bool IncrementIndexSkip(std::vector<size_t> &indices, const std::vector<int> &skipv) const
219 {
220 long long int pos = dims.size() - 1;
221
222 int skip = -1;
223 int skipPos = -1;
224 if (!skipv.empty())
225 {
226 skip = skipv.back();
227 skipPos = static_cast<int>(skipv.size()) - 1;
228 }
229
230 while (pos >= 0)
231 {
232 const bool notOnPos = pos != skip;
233 if (notOnPos && indices[pos] < dims[pos] - 1)
234 {
235 ++indices[pos];
236 break;
237 }
238 else
239 {
240 if (notOnPos)
241 indices[pos] = 0;
242 --pos;
243
244 if (pos < skip)
245 {
246 --skipPos;
247 if (skipPos >= 0)
248 skip = skipv[skipPos];
249 else
250 skip = -1;
251 }
252 }
253 }
254
255 return pos >= 0;
256 }
257
258 void Clear()
259 {
260 dims.clear();
261 ClearValues();
262 }
263
265 {
266 sz = 0;
267 values.resize(0);
268 }
269
270 bool Empty() const
271 {
272 return dims.empty();
273 }
274
275 void Resize(const std::vector<size_t> &newdims)
276 {
277 Clear();
278
279 dims = newdims;
280 sz = 0;
281 values.resize(GetSize());
282 }
283
284 template <class indT = size_t> void Resize(std::initializer_list<indT> newdims)
285 {
286 Clear();
287
288 dims = newdims;
289 sz = 0;
290 values.resize(GetSize());
291 }
292
293 const T at(const std::vector<size_t> &indices) const
294 {
295 assert(indices.size() == dims.size());
296
297 return values[GetOffset(indices)];
298 }
299
300 inline T &operator[](const std::vector<size_t> &indices)
301 {
302 assert(indices.size() == dims.size());
303
304 return values[GetOffset(indices)];
305 }
306
307 inline const T &operator[](const std::vector<size_t> &indices) const
308 {
309 return values[GetOffset(indices)];
310 }
311
312 T atOffset(size_t offset)
313 {
314 assert(values.size() > offset);
315
316 return values[offset];
317 }
318
319 inline T &operator[](size_t offset)
320 {
321 assert(values.size() > offset);
322
323 return values[offset];
324 }
325
326 inline const T &operator[](size_t offset) const
327 {
328 return values[offset];
329 }
330
331 template <class indT = size_t> T &operator[](std::initializer_list<indT> args)
332 {
333 assert(args.size() == dims.size());
334
335 const std::vector<size_t> indices(args.begin(), args.end());
336
337 return values[GetOffset(indices)];
338 }
339
340 template <class indT = size_t> const T &operator[](std::initializer_list<indT> args) const
341 {
342 assert(args.size() == dims.size());
343
344 const std::vector<size_t> indices(args.begin(), args.end());
345
346 return values[GetOffset(indices)];
347 }
348
349 inline T &operator()(const std::vector<size_t> &indices)
350 {
351 assert(indices.size() == dims.size());
352
353 return values[GetOffset(indices)];
354 }
355
356 inline const T &operator()(const std::vector<size_t> &indices) const
357 {
358 return values[GetOffset(indices)];
359 }
360
361 template <class indT = size_t> T &operator()(std::initializer_list<indT> args)
362 {
363 assert(args.size() == dims.size());
364
365 const std::vector<size_t> indices(args.begin(), args.end());
366
367 return values[GetOffset(indices)];
368 }
369
370 template <class indT = size_t> const T &operator()(std::initializer_list<indT> args) const
371 {
372 assert(args.size() == dims.size());
373
374 const std::vector<size_t> indices(args.begin(), args.end());
375
376 return values[GetOffset(indices)];
377 }
378
379 inline const Storage &GetValues() const
380 {
381 return values;
382 }
383
384 inline Storage &GetValues()
385 {
386 return values;
387 }
388
390 {
391 assert(dims == other.dims);
392
393 Tensor<T, Storage> result(dims);
394
395 for (size_t i = 0; i < GetSize(); ++i)
396 result.values[i] = values[i] + other.values[i];
397
398 return result;
399 }
400
402 {
403 assert(dims == other.dims);
404
405 Tensor<T, Storage> result(dims);
406
407 for (size_t i = 0; i < GetSize(); ++i)
408 result.values[i] = values[i] - other.values[i];
409
410 return result;
411 }
412
414 {
415 assert(dims == other.dims);
416
417 Tensor<T, Storage> result(dims);
418
419 for (size_t i = 0; i < GetSize(); ++i)
420 result.values[i] = values[i] * other.values[i];
421
422 return result;
423 }
424
426 {
427 assert(dims == other.dims);
428
429 Tensor<T, Storage> result(dims);
430
431 for (size_t i = 0; i < GetSize(); ++i)
432 result.values[i] = values[i] / other.values[i];
433
434 return result;
435 }
436
437 Tensor<T, Storage> operator+(const T &scalar) const
438 {
439 Tensor<T, Storage> result(dims);
440
441 for (size_t i = 0; i < GetSize(); ++i)
442 result.values[i] = values[i] + scalar;
443
444 return result;
445 }
446
447 Tensor<T, Storage> operator-(const T &scalar) const
448 {
449 Tensor<T, Storage> result(dims);
450
451 for (size_t i = 0; i < GetSize(); ++i)
452 result.values[i] = values[i] - scalar;
453
454 return result;
455 }
456
457 Tensor<T, Storage> operator*(const T &scalar) const
458 {
459 Tensor<T, Storage> result(dims);
460
461 for (size_t i = 0; i < GetSize(); ++i)
462 result.values[i] = values[i] * scalar;
463
464 return result;
465 }
466
467 Tensor<T, Storage> operator/(const T &scalar) const
468 {
469 Tensor<T, Storage> result(dims);
470
471 for (size_t i = 0; i < GetSize(); ++i)
472 result.values[i] = values[i] / scalar;
473
474 return result;
475 }
476
478 {
479 assert(dims == other.dims);
480
481 for (size_t i = 0; i < GetSize(); ++i)
482 values[i] += other.values[i];
483
484 return *this;
485 }
486
488 {
489 assert(dims == other.dims);
490
491 for (size_t i = 0; i < GetSize(); ++i)
492 values[i] -= other.values[i];
493
494 return *this;
495 }
496
498 {
499 assert(dims == other.dims);
500
501 for (size_t i = 0; i < GetSize(); ++i)
502 values[i] *= other.values[i];
503
504 return *this;
505 }
506
508 {
509 assert(dims == other.dims);
510
511 for (size_t i = 0; i < GetSize(); ++i)
512 values[i] /= other.values[i];
513
514 return *this;
515 }
516
518 {
519 for (size_t i = 0; i < GetSize(); ++i)
520 values[i] += scalar;
521
522 return *this;
523 }
524
526 {
527 for (size_t i = 0; i < GetSize(); ++i)
528 values[i] -= scalar;
529
530 return *this;
531 }
532
534 {
535 for (size_t i = 0; i < GetSize(); ++i)
536 values[i] *= scalar;
537
538 return *this;
539 }
540
542 {
543 for (size_t i = 0; i < GetSize(); ++i)
544 values[i] /= scalar;
545
546 return *this;
547 }
548
549 // the following four are for the special case then each value is a map of
550 // results (for cutting)
551 Tensor<T, Storage> &operator+=(const double scalar)
552 {
553 for (size_t i = 0; i < GetSize(); ++i)
554 values[i] = values[i] + scalar;
555
556 return *this;
557 }
558
559 Tensor<T, Storage> &operator-=(const double scalar)
560 {
561 for (size_t i = 0; i < GetSize(); ++i)
562 values[i] = values[i] - scalar;
563
564 return *this;
565 }
566
567 Tensor<T, Storage> &operator*=(const double scalar)
568 {
569 for (size_t i = 0; i < GetSize(); ++i)
570 values[i] = scalar * values[i];
571
572 return *this;
573 }
574
575 Tensor<T, Storage> &operator/=(const double scalar)
576 {
577 for (size_t i = 0; i < GetSize(); ++i)
578 values[i] = values[i] / scalar;
579
580 return *this;
581 }
582
584 {
585 Tensor<T, Storage> result(dims);
586
587 for (size_t i = 0; i < GetSize(); ++i)
588 result.values[i] = -values[i];
589
590 return result;
591 }
592
593 void Conj()
594 {
595 for (size_t i = 0; i < GetSize(); ++i)
596 values[i] = std::conj(values[i]);
597 }
598
600 {
601 std::vector<size_t> newdims(dims.size() + other.dims.size());
602
603 for (size_t i = 0; i < dims.size(); ++i)
604 newdims[i] = dims[i];
605
606 for (size_t i = 0; i < other.dims.size(); ++i)
607 newdims[dims.size() + i] = other.dims[i];
608
609 Tensor<T, Storage> result(newdims, values.size() == 0);
610
611 if (!IsDummy())
612 for (size_t i = 0; i < GetSize(); ++i)
613 for (size_t j = 0; j < other.GetSize(); ++j)
614 result.values[i * other.GetSize() + j] = values[i] * other.values[j];
615
616 return result;
617 }
618
619 Tensor<T, Storage> Contract(const Tensor<T, Storage> &other, size_t ind1, size_t ind2, bool allowMultithreading = true) const
620 {
621 const std::array<std::pair<size_t, size_t>, 1> indices{{{ind1, ind2}}};
622 return ContractImpl(other, indices, allowMultithreading);
623 }
624
625 Tensor<T, Storage> Contract(const Tensor<T, Storage> &other, const std::vector<std::pair<size_t, size_t>> &indices, bool allowMultithreading = true) const
626 {
627 return ContractImpl(other, indices, allowMultithreading);
628 }
629
630 private:
631 template <class Pairs> Tensor<T, Storage> ContractImpl(const Tensor<T, Storage> &other, const Pairs &indices, bool allow) const
632 {
633 detail::TensorAxisMask usedA(dims.size()), usedB(other.dims.size());
634 const auto newdims = detail::TensorContractionDimensions(dims, other.dims, indices, usedA, usedB);
635
636 Tensor<T, Storage> result(newdims, IsDummy() || other.IsDummy());
637 if (result.IsDummy())
638 return result;
639 if (detail::TensorSmallContraction<T>(values, other.values, result.values, dims, other.dims, usedA, usedB, indices))
640 return result;
641
642 detail::TensorAxisPattern fa, fb, ka, kb;
643 detail::TensorContractionPatterns(dims, other.dims, usedA, usedB, indices, fa, fb, ka, kb);
644 detail::TensorDenseContraction<T>(values, other.values, result.values, fa, fb, ka, kb, allow, detail::TensorGateSize(dims, other.dims, indices.size()));
645 return result;
646 }
647
648 public:
649 T Trace() const
650 {
651 assert(dims.size() > 0);
652
653 T result = 0;
654
655 if (values.size() == 0)
656 return result;
657
658 size_t dimMin = dims[0];
659 for (size_t i = 1; i < dims.size(); ++i)
660 if (dims[i] < dimMin)
661 dimMin = dims[i];
662
663 for (size_t i = 0; i < dimMin; ++i)
664 {
665 const std::vector<size_t> indices(dims.size(), i);
666
667 result += values[GetOffset(indices)];
668 }
669
670 return result;
671 }
672
673 Tensor<T, Storage> Trace(size_t ind1, size_t ind2) const
674 {
675 assert(ind1 < dims.size() && ind2 < dims.size());
676
677 std::vector<size_t> newdims;
678
679 size_t newsize = dims.size() - 2;
680
681 if (newsize == 0)
682 {
683 newsize = 1;
684 newdims.push_back(1);
685 }
686 else
687 {
688 newdims.reserve(newsize);
689
690 for (size_t i = 0; i < dims.size(); ++i)
691 if (i != ind1 && i != ind2)
692 newdims.push_back(dims[i]);
693 }
694
695 size_t dimMin = dims[ind1];
696 if (dims[ind2] < dimMin)
697 dimMin = dims[ind2];
698
699 Tensor<T, Storage> result(newdims, values.size() == 0);
700
701 if (values.size() != 0)
702 {
703 for (size_t offset = 0; offset < result.GetSize(); ++offset)
704 {
705 std::vector<size_t> indices1(dims.size());
706 const std::vector<size_t> indices = result.IndexFromOffset(offset);
707
708 size_t skip = 0;
709 for (size_t i = 0; i < dims.size(); ++i)
710 if (i != ind1 && i != ind2)
711 indices1[i] = indices[i - skip];
712 else
713 ++skip;
714
715 for (size_t i = 0; i < dimMin; ++i)
716 {
717 indices1[ind1] = indices1[ind2] = i;
718
719 result[offset] += values[GetOffset(indices1)];
720 }
721 }
722 }
723
724 return result;
725 }
726
727 Tensor<T, Storage> Trace(const std::vector<size_t> &tindices) const
728 {
729 std::vector<size_t> newdims;
730
731 size_t newsize = dims.size() - tindices.size();
732
733 if (newsize == 0)
734 {
735 newsize = 1;
736 newdims.push_back(1);
737 }
738 else
739 {
740 newdims.reserve(newsize);
741
742 for (size_t i = 0; i < dims.size(); ++i)
743 {
744 bool skip = false;
745 for (size_t j = 0; j < tindices.size(); ++j)
746 if (i == tindices[j])
747 {
748 skip = true;
749 break;
750 }
751
752 if (!skip)
753 newdims.push_back(dims[i]);
754 }
755 }
756
757 size_t dimMin = dims[tindices[0]];
758 for (size_t i = 1; i < tindices.size(); ++i)
759 if (dims[tindices[i]] < dimMin)
760 dimMin = dims[tindices[i]];
761
762 Tensor<T, Storage> result(newdims, values.size() == 0);
763
764 if (values.size() != 0)
765 {
766 for (size_t offset = 0; offset < result.GetSize(); ++offset)
767 {
768 std::vector<size_t> indices1(dims.size());
769 const std::vector<size_t> indices = result.IndexFromOffset(offset);
770
771 size_t skipv = 0;
772 for (size_t i = 0; i < dims.size(); ++i)
773 {
774 bool skip = false;
775 for (size_t j = 0; j < tindices.size(); ++j)
776 if (i == tindices[j])
777 {
778 skip = true;
779 break;
780 }
781
782 if (!skip)
783 indices1[i] = indices[i - skipv];
784 else
785 ++skipv;
786 }
787
788 for (size_t i = 0; i < dimMin; ++i)
789 {
790 for (size_t j = 0; j < tindices.size(); ++j)
791 indices1[tindices[j]] = i;
792
793 result[offset] += values[GetOffset(indices1)];
794 }
795 }
796 }
797
798 return result;
799 }
800
801 template <class indT = size_t> Tensor<T, Storage> Trace(std::initializer_list<indT> args) const
802 {
803 const std::vector<size_t> indices(args.begin(), args.end());
804
805 return Trace(indices);
806 }
807
808 Tensor<T, Storage> Shuffle(const std::vector<size_t> &indices) const
809 {
810 assert(indices.size() == dims.size());
811
812 std::vector<size_t> newdims(dims.size());
813 for (size_t i = 0; i < dims.size(); ++i)
814 newdims[i] = dims[indices[i]];
815
816 Tensor<T, Storage> result(newdims, values.size() == 0);
817
818 if (values.size() != 0)
819 {
820 std::vector<size_t> indices2(dims.size());
821 for (size_t offset = 0; offset < GetSize(); ++offset)
822 {
823 const std::vector<size_t> indices1 = IndexFromOffset(offset);
824
825 for (size_t i = 0; i < dims.size(); ++i)
826 indices2[indices[i]] = indices1[i];
827
828 result[indices2] = values[offset];
829 }
830 }
831
832 return result;
833 }
834
835 template <class indT = size_t> Tensor<T, Storage> Shuffle(std::initializer_list<indT> args) const
836 {
837 const std::vector<size_t> indices(args.begin(), args.end());
838
839 return Shuffle(indices);
840 }
841
842 Tensor<T, Storage> Reshape(const std::vector<size_t> &newdims) const
843 {
844 Tensor<T, Storage> result(newdims, values.size() == 0);
845
846 assert(result.GetSize() == GetSize());
847
848 if (values.size() != 0)
849 for (size_t offset = 0; offset < GetSize(); ++offset)
850 result[offset] = values[offset];
851
852 return result;
853 }
854
855 template <class indT = size_t> Tensor<T, Storage> Reshape(std::initializer_list<indT> args) const
856 {
857 const std::vector<size_t> newdims(args.begin(), args.end());
858
859 return Reshape(newdims);
860 }
861
862 // changing the layout format is as easy as changing what's called in the
863 // following two functions
864
865 inline size_t GetOffset(const std::vector<size_t> &indices) const
866 {
867 return GetFortranOffset(indices);
868 }
869
870 inline std::vector<size_t> IndexFromOffset(size_t offset) const
871 {
872 return IndexFromFortranOffset(offset);
873 }
874
875 private:
876 // C/C++ layout (row-major order)
877
878 inline size_t GetCPPOffset(const std::vector<size_t> &indices) const
879 {
880 assert(indices.size() == dims.size());
881
882 size_t result = 0;
883
884 for (size_t i = 0; i < dims.size(); ++i)
885 {
886 assert(indices[i] < dims[i]);
887
888 result = result * dims[i] + indices[i];
889 }
890
891 return result;
892 }
893
894 inline std::vector<size_t> IndexFromCPPOffset(size_t offset) const
895 {
896 std::vector<size_t> indices(dims.size(), 0);
897
898 for (int i = static_cast<int>(dims.size()) - 1; i >= 0; --i)
899 {
900 indices[i] = offset % dims[i];
901 offset /= dims[i];
902 if (0 == offset)
903 break;
904 }
905
906 return indices;
907 }
908
909 // the following two are for fortran layout (column-major order)
910 // for passing to cuda we need probably to convert anyway (as in from
911 // complex<double> to complex<float>) the tensors will be small so converting
912 // them should not be computationally expensive
913
914 inline size_t GetFortranOffset(const std::vector<size_t> &indices) const
915 {
916 assert(indices.size() == dims.size());
917
918 size_t result = 0;
919
920 for (long long int i = dims.size() - 1; i >= 0; --i)
921 {
922 assert(indices[i] < dims[i]);
923
924 result = result * dims[i] + indices[i];
925 }
926
927 return result;
928 }
929
930 inline std::vector<size_t> IndexFromFortranOffset(size_t offset) const
931 {
932 std::vector<size_t> indices(dims.size(), 0);
933
934 for (size_t i = 0; i < dims.size(); ++i)
935 {
936 indices[i] = offset % dims[i];
937 offset /= dims[i];
938 if (0 == offset)
939 break;
940 }
941
942 return indices;
943 }
944};
945
946} // namespace Utils
947
948#endif
void ClearValues()
Definition Tensor.h:264
Tensor< T, Storage > & operator+=(const Tensor< T, Storage > &other)
Definition Tensor.h:477
Tensor< T, Storage > operator+(const Tensor< T, Storage > &other) const
Definition Tensor.h:389
T & operator[](size_t offset)
Definition Tensor.h:319
Tensor(const std::vector< size_t > &dims, bool dummy=false)
Definition Tensor.h:58
T & operator[](std::initializer_list< indT > args)
Definition Tensor.h:331
T atOffset(size_t offset)
Definition Tensor.h:312
Tensor< T, Storage > & operator=(const Tensor< T, Storage > &other)
Definition Tensor.h:112
std::vector< size_t > dims
Definition Tensor.h:46
Tensor< T, Storage > & operator*=(const Tensor< T, Storage > &other)
Definition Tensor.h:497
T Trace() const
Definition Tensor.h:649
bool IncrementIndexSkip(std::vector< size_t > &indices, const std::vector< int > &skipv) const
Definition Tensor.h:218
Tensor< T, Storage > operator/(const Tensor< T, Storage > &other) const
Definition Tensor.h:425
Tensor< T, Storage > operator/(const T &scalar) const
Definition Tensor.h:467
bool IncrementIndexSkip(std::vector< size_t > &indices, int skip) const
Definition Tensor.h:195
void Resize(const std::vector< size_t > &newdims)
Definition Tensor.h:275
size_t GetSize() const
Definition Tensor.h:139
Tensor< T, Storage > & operator-=(const Tensor< T, Storage > &other)
Definition Tensor.h:487
const Storage & GetValues() const
Definition Tensor.h:379
const T & operator[](const std::vector< size_t > &indices) const
Definition Tensor.h:307
bool IncrementIndex(std::vector< size_t > &indices) const
Definition Tensor.h:174
void serialize(Archive &ar, const unsigned int)
Definition Tensor.h:104
size_t GetDim(size_t index) const
Definition Tensor.h:152
Tensor(std::initializer_list< indT > dims, bool dummy=false)
Definition Tensor.h:80
Storage values
Definition Tensor.h:45
Storage & GetValues()
Definition Tensor.h:384
Tensor< T, Storage > & operator/=(const double scalar)
Definition Tensor.h:575
Tensor< T, Storage > Trace(const std::vector< size_t > &tindices) const
Definition Tensor.h:727
void Swap(Tensor< T, Storage > &other)
Definition Tensor.h:132
const T & operator[](std::initializer_list< indT > args) const
Definition Tensor.h:340
Tensor< T, Storage > & operator/=(const Tensor< T, Storage > &other)
Definition Tensor.h:507
Tensor(const std::vector< int > &dims, bool dummy=false)
Definition Tensor.h:69
Tensor< T, Storage > & operator-=(const double scalar)
Definition Tensor.h:559
Tensor< T, Storage > & operator+=(const T &scalar)
Definition Tensor.h:517
const T at(const std::vector< size_t > &indices) const
Definition Tensor.h:293
T & operator[](const std::vector< size_t > &indices)
Definition Tensor.h:300
const size_t GetRank() const
Definition Tensor.h:164
void Conj()
Definition Tensor.h:593
Tensor< T, Storage > & operator+=(const double scalar)
Definition Tensor.h:551
bool Empty() const
Definition Tensor.h:270
Tensor(const Tensor< T, Storage > &other)
Definition Tensor.h:91
Tensor< T, Storage > operator*(const Tensor< T, Storage > &other) const
Definition Tensor.h:413
virtual ~Tensor()=default
Tensor(Tensor< T, Storage > &&other) noexcept
Definition Tensor.h:95
const T & operator()(std::initializer_list< indT > args) const
Definition Tensor.h:370
const std::vector< size_t > & GetDims() const
Definition Tensor.h:159
T & operator()(std::initializer_list< indT > args)
Definition Tensor.h:361
Tensor< T, Storage > & operator*=(const T &scalar)
Definition Tensor.h:533
size_t GetOffset(const std::vector< size_t > &indices) const
Definition Tensor.h:865
Tensor< T, Storage > Reshape(const std::vector< size_t > &newdims) const
Definition Tensor.h:842
Tensor< T, Storage > & operator-=(const T &scalar)
Definition Tensor.h:525
Tensor< T, Storage > operator+(const T &scalar) const
Definition Tensor.h:437
bool IsDummy() const
Definition Tensor.h:169
const T & operator()(const std::vector< size_t > &indices) const
Definition Tensor.h:356
Tensor< T, Storage > & operator=(Tensor< T, Storage > &&other) noexcept
Definition Tensor.h:120
Tensor< T, Storage > operator*(const T &scalar) const
Definition Tensor.h:457
const T & operator[](size_t offset) const
Definition Tensor.h:326
Tensor< T, Storage > operator-(const T &scalar) const
Definition Tensor.h:447
void Clear()
Definition Tensor.h:258
Tensor< T, Storage > TensorProduct(const Tensor< T, Storage > &other) const
Definition Tensor.h:599
Tensor< T, Storage > operator-() const
Definition Tensor.h:583
Tensor< T, Storage > Reshape(std::initializer_list< indT > args) const
Definition Tensor.h:855
std::vector< size_t > IndexFromOffset(size_t offset) const
Definition Tensor.h:870
friend class boost::serialization::access
Definition Tensor.h:50
size_t sz
Definition Tensor.h:47
Tensor< T, Storage > & operator/=(const T &scalar)
Definition Tensor.h:541
Tensor< T, Storage > Shuffle(const std::vector< size_t > &indices) const
Definition Tensor.h:808
void Resize(std::initializer_list< indT > newdims)
Definition Tensor.h:284
Tensor< T, Storage > Trace(size_t ind1, size_t ind2) const
Definition Tensor.h:673
Tensor< T, Storage > Contract(const Tensor< T, Storage > &other, const std::vector< std::pair< size_t, size_t > > &indices, bool allowMultithreading=true) const
Definition Tensor.h:625
Tensor< T, Storage > Trace(std::initializer_list< indT > args) const
Definition Tensor.h:801
Tensor< T, Storage > Contract(const Tensor< T, Storage > &other, size_t ind1, size_t ind2, bool allowMultithreading=true) const
Definition Tensor.h:619
Tensor< T, Storage > & operator*=(const double scalar)
Definition Tensor.h:567
Tensor< T, Storage > Shuffle(std::initializer_list< indT > args) const
Definition Tensor.h:835
Tensor< T, Storage > operator-(const Tensor< T, Storage > &other) const
Definition Tensor.h:401
T & operator()(const std::vector< size_t > &indices)
Definition Tensor.h:349
void TensorContractionPatterns(const std::vector< size_t > &da, const std::vector< size_t > &db, const TensorAxisMask &usedA, const TensorAxisMask &usedB, const Pairs &pairs, TensorAxisPattern &fa, TensorAxisPattern &fb, TensorAxisPattern &ka, TensorAxisPattern &kb)
int TensorGateSize(const std::vector< size_t > &da, const std::vector< size_t > &db, size_t pairs)
bool TensorSmallContraction(const Storage &a, const Storage &b, Storage &out, const std::vector< size_t > &da, const std::vector< size_t > &db, const TensorAxisMask &usedA, const TensorAxisMask &usedB, const Pairs &pairs)
std::vector< size_t > TensorContractionDimensions(const std::vector< size_t > &da, const std::vector< size_t > &db, const Pairs &pairs, TensorAxisMask &usedA, TensorAxisMask &usedB)
size_t TensorSizeProduct(size_t a, size_t b)
void TensorDenseContraction(const Storage &a, const Storage &b, Storage &out, const TensorAxisPattern &fa, const TensorAxisPattern &fb, const TensorAxisPattern &ka, const TensorAxisPattern &kb, bool allow, int gateSize=0)
Portable dense contraction kernels.