19#include <initializer_list>
21#include <unordered_set>
25#include <boost/archive/text_iarchive.hpp>
26#include <boost/archive/text_oarchive.hpp>
27#include <boost/serialization/valarray.hpp>
28#include <boost/serialization/vector.hpp>
30#include "QubitRegisterCalculator.h"
39template <
class T = std::complex<
double>,
class Storage = std::valarray<T>>
50 return QC::QubitRegisterCalculator<>::GetNumberOfThreads();
60 Tensor(
const std::vector<size_t> &
dims,
bool dummy =
false)
63 if constexpr (std::is_convertible<int, T>::value)
73 if constexpr (std::is_convertible<int, T>::value)
80 template <
class indT =
size_t>
81 Tensor(std::initializer_list<indT>
dims,
bool dummy =
false)
84 if constexpr (std::is_convertible<int, T>::value)
95 dims.swap(other.dims);
97 std::swap(
sz, other.sz);
102 template <
class Archive>
104 if (
typename Archive::is_loading())
112 *
this = std::move(temp);
118 if (
this != &other) {
119 dims.swap(other.dims);
120 values.swap(other.values);
121 std::swap(
sz, other.sz);
130 std::swap(
sz, other.
sz);
135 sz = std::accumulate(
dims.begin(),
dims.end(), 1,
136 std::multiplies<size_t>());
142 assert(index <
dims.size());
154 long long pos =
dims.size() - 1;
157 if (indices[pos] <
dims[pos] - 1) {
170 long long pos =
dims.size() - 1;
173 const bool notOnPos = pos != skip;
174 if (notOnPos && indices[pos] <
dims[pos] - 1) {
188 const std::vector<int> &skipv)
const {
189 long long int pos =
dims.size() - 1;
193 if (!skipv.empty()) {
195 skipPos =
static_cast<int>(skipv.size()) - 1;
199 const bool notOnPos = pos != skip;
200 if (notOnPos && indices[pos] <
dims[pos] - 1) {
211 skip = skipv[skipPos];
233 void Resize(
const std::vector<size_t> &newdims) {
241 template <
class indT =
size_t>
242 void Resize(std::initializer_list<indT> newdims) {
250 const T
at(
const std::vector<size_t> &indices)
const {
251 assert(indices.size() ==
dims.size());
257 assert(indices.size() ==
dims.size());
262 inline const T &
operator[](
const std::vector<size_t> &indices)
const {
267 assert(
values.size() > offset);
273 assert(
values.size() > offset);
280 template <
class indT =
size_t>
282 assert(args.size() ==
dims.size());
284 const std::vector<size_t> indices(args.begin(), args.end());
289 template <
class indT =
size_t>
290 const T &
operator[](std::initializer_list<indT> args)
const {
291 assert(args.size() ==
dims.size());
293 const std::vector<size_t> indices(args.begin(), args.end());
299 assert(indices.size() ==
dims.size());
304 inline const T &
operator()(
const std::vector<size_t> &indices)
const {
308 template <
class indT =
size_t>
310 assert(args.size() ==
dims.size());
312 const std::vector<size_t> indices(args.begin(), args.end());
317 template <
class indT =
size_t>
318 const T &
operator()(std::initializer_list<indT> args)
const {
319 assert(args.size() ==
dims.size());
321 const std::vector<size_t> indices(args.begin(), args.end());
335 for (
size_t i = 0; i <
GetSize(); ++i)
346 for (
size_t i = 0; i <
GetSize(); ++i)
357 for (
size_t i = 0; i <
GetSize(); ++i)
368 for (
size_t i = 0; i <
GetSize(); ++i)
377 for (
size_t i = 0; i <
GetSize(); ++i)
386 for (
size_t i = 0; i <
GetSize(); ++i)
395 for (
size_t i = 0; i <
GetSize(); ++i)
404 for (
size_t i = 0; i <
GetSize(); ++i)
413 for (
size_t i = 0; i <
GetSize(); ++i)
422 for (
size_t i = 0; i <
GetSize(); ++i)
431 for (
size_t i = 0; i <
GetSize(); ++i)
440 for (
size_t i = 0; i <
GetSize(); ++i)
447 for (
size_t i = 0; i <
GetSize(); ++i)
454 for (
size_t i = 0; i <
GetSize(); ++i)
461 for (
size_t i = 0; i <
GetSize(); ++i)
468 for (
size_t i = 0; i <
GetSize(); ++i)
477 for (
size_t i = 0; i <
GetSize(); ++i)
484 for (
size_t i = 0; i <
GetSize(); ++i)
491 for (
size_t i = 0; i <
GetSize(); ++i)
498 for (
size_t i = 0; i <
GetSize(); ++i)
507 for (
size_t i = 0; i <
GetSize(); ++i)
514 for (
size_t i = 0; i <
GetSize(); ++i)
519 std::vector<size_t> newdims(
dims.size() + other.
dims.size());
521 for (
size_t i = 0; i <
dims.size(); ++i)
522 newdims[i] =
dims[i];
524 for (
size_t i = 0; i < other.
dims.size(); ++i)
525 newdims[
dims.size() + i] = other.
dims[i];
530 for (
size_t i = 0; i <
GetSize(); ++i)
531 for (
size_t j = 0; j < other.
GetSize(); ++j)
539 bool allowMultithreading =
true)
const {
540 assert(
dims[ind1] == other.
dims[ind2]);
542 std::vector<size_t> newdims;
544 const size_t newsize =
dims.size() + other.
dims.size() - 2;
546 newdims.resize(1, 1);
548 newdims.reserve(newsize);
550 for (
size_t i = 0; i <
dims.size(); ++i)
552 newdims.push_back(
dims[i]);
554 for (
size_t i = 0; i < other.
dims.size(); ++i)
556 newdims.push_back(other.
dims[i]);
565 std::vector<size_t> indices1(
dims.size());
566 std::vector<size_t> indices2(other.
dims.size());
568 for (
size_t offset = 0; offset <
sz; ++offset) {
572 for (
size_t i = 0; i <
dims.size(); ++i)
574 indices1[i] = indicesres[pos];
578 for (
size_t i = 0; i < other.
dims.size(); ++i)
580 indices2[i] = indicesres[pos];
586 for (
size_t i = 0; i <
dims[ind1]; ++i) {
587 indices1[ind1] = indices2[ind2] = i;
596#pragma omp parallel for num_threads(processor_count) \
597 schedule(static, OmpLimit / divSchedule)
598 for (
long long int offset = 0; offset < static_cast<long long int>(
sz);
601 std::vector<size_t> indices1(
dims.size());
602 std::vector<size_t> indices2(other.
dims.size());
605 for (
size_t i = 0; i <
dims.size(); ++i)
607 indices1[i] = indicesres[pos];
611 for (
size_t i = 0; i < other.
dims.size(); ++i)
613 indices2[i] = indicesres[pos];
619 for (
size_t i = 0; i <
dims[ind1]; ++i) {
620 indices1[ind1] = indices2[ind2] = i;
634 const std::vector<std::pair<size_t, size_t>> &indices,
635 bool allowMultithreading =
true)
const {
636 std::vector<size_t> newdims;
637 std::vector<size_t> contractDims;
639 std::unordered_set<size_t> indicesSet1;
640 std::unordered_set<size_t> indicesSet2;
642 for (
const auto &index : indices) {
643 assert(
dims[index.first] == other.
dims[index.second]);
645 indicesSet1.insert(index.first);
646 indicesSet2.insert(index.second);
647 contractDims.push_back(
dims[index.first]);
650 const size_t newsize =
dims.size() + other.
dims.size() - 2 * indices.size();
652 newdims.resize(1, 1);
654 newdims.reserve(newsize);
656 for (
size_t i = 0; i <
dims.size(); ++i)
657 if (indicesSet1.find(i) == indicesSet1.end())
658 newdims.push_back(
dims[i]);
660 for (
size_t i = 0; i < other.
dims.size(); ++i)
661 if (indicesSet2.find(i) == indicesSet2.end())
662 newdims.push_back(other.
dims[i]);
673 std::vector<size_t> dummyIndices(
674 contractDims.size(), 0);
676 std::vector<size_t> indices1(
dims.size());
677 std::vector<size_t> indices2(other.
dims.size());
679 for (
size_t offset = 0; offset <
sz; ++offset) {
683 for (
size_t i = 0; i <
dims.size(); ++i)
684 if (indicesSet1.find(i) == indicesSet1.end()) {
685 indices1[i] = indicesres[pos];
689 for (
size_t i = 0; i < other.
dims.size(); ++i)
690 if (indicesSet2.find(i) == indicesSet2.end()) {
691 indices2[i] = indicesres[pos];
698 for (
size_t i = 0; i < dummyIndices.size(); ++i)
699 indices1[indices[i].first] = indices2[indices[i].second] =
704 const T &val2 = other[indices2];
705 auto mulRes = val1 * val2;
706 result[offset] = result[offset] + std::move(mulRes);
712#pragma omp parallel for num_threads(processor_count) \
713 schedule(static, OmpLimit / divSchedule)
714 for (
long long int offset = 0; offset < static_cast<long long int>(
sz);
717 std::vector<size_t> indices1(
dims.size());
718 std::vector<size_t> indices2(other.
dims.size());
721 for (
size_t i = 0; i <
dims.size(); ++i)
722 if (indicesSet1.find(i) == indicesSet1.end()) {
723 indices1[i] = indicesres[pos];
727 for (
size_t i = 0; i < other.
dims.size(); ++i)
728 if (indicesSet2.find(i) == indicesSet2.end()) {
729 indices2[i] = indicesres[pos];
735 std::vector<size_t> dummyIndices(
741 for (
size_t i = 0; i < dummyIndices.size(); ++i)
742 indices1[indices[i].first] = indices2[indices[i].second] =
747 const T &val2 = other[indices2];
749 auto mulRes = val1 * val2;
750 result[offset] = result[offset] + std::move(mulRes);
760 assert(
dims.size() > 0);
767 size_t dimMin =
dims[0];
768 for (
size_t i = 1; i <
dims.size(); ++i)
769 if (
dims[i] < dimMin)
772 for (
size_t i = 0; i < dimMin; ++i) {
773 const std::vector<size_t> indices(
dims.size(), i);
782 assert(ind1 <
dims.size() && ind2 <
dims.size());
784 std::vector<size_t> newdims;
786 size_t newsize =
dims.size() - 2;
790 newdims.push_back(1);
792 newdims.reserve(newsize);
794 for (
size_t i = 0; i <
dims.size(); ++i)
795 if (i != ind1 && i != ind2)
796 newdims.push_back(
dims[i]);
799 size_t dimMin =
dims[ind1];
800 if (
dims[ind2] < dimMin)
806 for (
size_t offset = 0; offset < result.
GetSize(); ++offset) {
807 std::vector<size_t> indices1(
dims.size());
811 for (
size_t i = 0; i <
dims.size(); ++i)
812 if (i != ind1 && i != ind2)
813 indices1[i] = indices[i - skip];
817 for (
size_t i = 0; i < dimMin; ++i) {
818 indices1[ind1] = indices1[ind2] = i;
829 std::vector<size_t> newdims;
831 size_t newsize =
dims.size() - tindices.size();
835 newdims.push_back(1);
837 newdims.reserve(newsize);
839 for (
size_t i = 0; i <
dims.size(); ++i) {
841 for (
size_t j = 0; j < tindices.size(); ++j)
842 if (i == tindices[j]) {
848 newdims.push_back(
dims[i]);
852 size_t dimMin =
dims[tindices[0]];
853 for (
size_t i = 1; i < tindices.size(); ++i)
854 if (
dims[tindices[i]] < dimMin)
855 dimMin =
dims[tindices[i]];
860 for (
size_t offset = 0; offset < result.
GetSize(); ++offset) {
861 std::vector<size_t> indices1(
dims.size());
865 for (
size_t i = 0; i <
dims.size(); ++i) {
867 for (
size_t j = 0; j < tindices.size(); ++j)
868 if (i == tindices[j]) {
874 indices1[i] = indices[i - skipv];
879 for (
size_t i = 0; i < dimMin; ++i) {
880 for (
size_t j = 0; j < tindices.size(); ++j)
881 indices1[tindices[j]] = i;
891 template <
class indT =
size_t>
893 const std::vector<size_t> indices(args.begin(), args.end());
895 return Trace(indices);
899 assert(indices.size() ==
dims.size());
901 std::vector<size_t> newdims(
dims.size());
902 for (
size_t i = 0; i <
dims.size(); ++i)
903 newdims[i] =
dims[indices[i]];
908 std::vector<size_t> indices2(
dims.size());
909 for (
size_t offset = 0; offset <
GetSize(); ++offset) {
912 for (
size_t i = 0; i <
dims.size(); ++i)
913 indices2[indices[i]] = indices1[i];
915 result[indices2] =
values[offset];
922 template <
class indT =
size_t>
924 const std::vector<size_t> indices(args.begin(), args.end());
935 for (
size_t offset = 0; offset <
GetSize(); ++offset)
936 result[offset] =
values[offset];
941 template <
class indT =
size_t>
943 const std::vector<size_t> newdims(args.begin(), args.end());
951 inline size_t GetOffset(
const std::vector<size_t> &indices)
const {
952 return GetFortranOffset(indices);
956 return IndexFromFortranOffset(offset);
962 inline size_t GetCPPOffset(
const std::vector<size_t> &indices)
const {
963 assert(indices.size() ==
dims.size());
967 for (
size_t i = 0; i <
dims.size(); ++i) {
968 assert(indices[i] <
dims[i]);
970 result = result *
dims[i] + indices[i];
976 inline std::vector<size_t> IndexFromCPPOffset(
size_t offset)
const {
977 std::vector<size_t> indices(
dims.size(), 0);
979 for (
int i =
static_cast<int>(
dims.size()) - 1; i >= 0; --i) {
980 indices[i] = offset %
dims[i];
994 inline size_t GetFortranOffset(
const std::vector<size_t> &indices)
const {
995 assert(indices.size() ==
dims.size());
999 for (
long long int i =
dims.size() - 1; i >= 0; --i) {
1000 assert(indices[i] <
dims[i]);
1002 result = result *
dims[i] + indices[i];
1008 inline std::vector<size_t> IndexFromFortranOffset(
size_t offset)
const {
1009 std::vector<size_t> indices(
dims.size(), 0);
1011 for (
size_t i = 0; i <
dims.size(); ++i) {
1012 indices[i] = offset %
dims[i];
Tensor< T, Storage > & operator+=(const Tensor< T, Storage > &other)
Tensor< T, Storage > operator+(const Tensor< T, Storage > &other) const
T & operator[](size_t offset)
Tensor(const std::vector< size_t > &dims, bool dummy=false)
T & operator[](std::initializer_list< indT > args)
T atOffset(size_t offset)
Tensor< T, Storage > & operator=(const Tensor< T, Storage > &other)
std::vector< size_t > dims
Tensor< T, Storage > & operator*=(const Tensor< T, Storage > &other)
bool IncrementIndexSkip(std::vector< size_t > &indices, const std::vector< int > &skipv) const
Tensor< T, Storage > operator/(const Tensor< T, Storage > &other) const
Tensor< T, Storage > operator/(const T &scalar) const
static int GetNumberOfThreads()
bool IncrementIndexSkip(std::vector< size_t > &indices, int skip) const
void Resize(const std::vector< size_t > &newdims)
Tensor< T, Storage > & operator-=(const Tensor< T, Storage > &other)
const Storage & GetValues() const
const T & operator[](const std::vector< size_t > &indices) const
bool IncrementIndex(std::vector< size_t > &indices) const
void serialize(Archive &ar, const unsigned int)
size_t GetDim(size_t index) const
static constexpr int divSchedule
Tensor(std::initializer_list< indT > dims, bool dummy=false)
Tensor< T, Storage > & operator/=(const double scalar)
Tensor< T, Storage > Trace(const std::vector< size_t > &tindices) const
static constexpr size_t OmpLimit
void Swap(Tensor< T, Storage > &other)
const T & operator[](std::initializer_list< indT > args) const
Tensor< T, Storage > & operator/=(const Tensor< T, Storage > &other)
Tensor(const std::vector< int > &dims, bool dummy=false)
Tensor< T, Storage > & operator-=(const double scalar)
Tensor< T, Storage > & operator+=(const T &scalar)
const T at(const std::vector< size_t > &indices) const
T & operator[](const std::vector< size_t > &indices)
const size_t GetRank() const
Tensor< T, Storage > & operator+=(const double scalar)
Tensor(const Tensor< T, Storage > &other)
Tensor< T, Storage > operator*(const Tensor< T, Storage > &other) const
virtual ~Tensor()=default
Tensor(Tensor< T, Storage > &&other) noexcept
const T & operator()(std::initializer_list< indT > args) const
const std::vector< size_t > & GetDims() const
T & operator()(std::initializer_list< indT > args)
Tensor< T, Storage > & operator*=(const T &scalar)
size_t GetOffset(const std::vector< size_t > &indices) const
Tensor< T, Storage > Reshape(const std::vector< size_t > &newdims) const
Tensor< T, Storage > & operator-=(const T &scalar)
Tensor< T, Storage > operator+(const T &scalar) const
const T & operator()(const std::vector< size_t > &indices) const
Tensor< T, Storage > & operator=(Tensor< T, Storage > &&other) noexcept
Tensor< T, Storage > operator*(const T &scalar) const
const T & operator[](size_t offset) const
Tensor< T, Storage > operator-(const T &scalar) const
Tensor< T, Storage > TensorProduct(const Tensor< T, Storage > &other) const
Tensor< T, Storage > operator-() const
Tensor< T, Storage > Reshape(std::initializer_list< indT > args) const
std::vector< size_t > IndexFromOffset(size_t offset) const
friend class boost::serialization::access
Tensor< T, Storage > & operator/=(const T &scalar)
Tensor< T, Storage > Shuffle(const std::vector< size_t > &indices) const
void Resize(std::initializer_list< indT > newdims)
Tensor< T, Storage > Trace(size_t ind1, size_t ind2) const
Tensor< T, Storage > Contract(const Tensor< T, Storage > &other, const std::vector< std::pair< size_t, size_t > > &indices, bool allowMultithreading=true) const
Tensor< T, Storage > Trace(std::initializer_list< indT > args) const
Tensor< T, Storage > Contract(const Tensor< T, Storage > &other, size_t ind1, size_t ind2, bool allowMultithreading=true) const
Tensor< T, Storage > & operator*=(const double scalar)
Tensor< T, Storage > Shuffle(std::initializer_list< indT > args) const
Tensor< T, Storage > operator-(const Tensor< T, Storage > &other) const
T & operator()(const std::vector< size_t > &indices)