20#include <initializer_list>
22#include <unordered_set>
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>
31#include "QubitRegisterCalculator.h"
42template <
class T = std::complex<
double>,
class Storage = std::valarray<T>>
class Tensor
47 mutable size_t sz = 0;
62 if constexpr (std::is_convertible<int, T>::value)
73 if constexpr (std::is_convertible<int, T>::value)
80 template <
class indT =
size_t>
Tensor(std::initializer_list<indT>
dims,
bool dummy =
false) :
dims(
dims.begin(),
dims.end()),
sz(0)
84 if constexpr (std::is_convertible<int, T>::value)
97 dims.swap(other.dims);
99 std::swap(
sz, other.sz);
104 template <
class Archive>
void serialize(Archive &ar,
const unsigned int )
106 if (
typename Archive::is_loading())
115 *
this = std::move(temp);
124 dims.swap(other.dims);
125 values.swap(other.values);
126 std::swap(
sz, other.sz);
136 std::swap(
sz, other.
sz);
144 for (
auto dimension :
dims)
154 assert(index <
dims.size());
171 return values.size() == 0;
176 long long pos =
dims.size() - 1;
180 if (indices[pos] <
dims[pos] - 1)
197 long long pos =
dims.size() - 1;
201 const bool notOnPos = pos != skip;
202 if (notOnPos && indices[pos] <
dims[pos] - 1)
220 long long int pos =
dims.size() - 1;
227 skipPos =
static_cast<int>(skipv.size()) - 1;
232 const bool notOnPos = pos != skip;
233 if (notOnPos && indices[pos] <
dims[pos] - 1)
248 skip = skipv[skipPos];
275 void Resize(
const std::vector<size_t> &newdims)
284 template <
class indT =
size_t>
void Resize(std::initializer_list<indT> newdims)
293 const T
at(
const std::vector<size_t> &indices)
const
295 assert(indices.size() ==
dims.size());
302 assert(indices.size() ==
dims.size());
307 inline const T &
operator[](
const std::vector<size_t> &indices)
const
314 assert(
values.size() > offset);
321 assert(
values.size() > offset);
331 template <
class indT =
size_t> T &
operator[](std::initializer_list<indT> args)
333 assert(args.size() ==
dims.size());
335 const std::vector<size_t> indices(args.begin(), args.end());
340 template <
class indT =
size_t>
const T &
operator[](std::initializer_list<indT> args)
const
342 assert(args.size() ==
dims.size());
344 const std::vector<size_t> indices(args.begin(), args.end());
351 assert(indices.size() ==
dims.size());
356 inline const T &
operator()(
const std::vector<size_t> &indices)
const
361 template <
class indT =
size_t> T &
operator()(std::initializer_list<indT> args)
363 assert(args.size() ==
dims.size());
365 const std::vector<size_t> indices(args.begin(), args.end());
370 template <
class indT =
size_t>
const T &
operator()(std::initializer_list<indT> args)
const
372 assert(args.size() ==
dims.size());
374 const std::vector<size_t> indices(args.begin(), args.end());
395 for (
size_t i = 0; i <
GetSize(); ++i)
407 for (
size_t i = 0; i <
GetSize(); ++i)
419 for (
size_t i = 0; i <
GetSize(); ++i)
431 for (
size_t i = 0; i <
GetSize(); ++i)
441 for (
size_t i = 0; i <
GetSize(); ++i)
451 for (
size_t i = 0; i <
GetSize(); ++i)
461 for (
size_t i = 0; i <
GetSize(); ++i)
471 for (
size_t i = 0; i <
GetSize(); ++i)
481 for (
size_t i = 0; i <
GetSize(); ++i)
491 for (
size_t i = 0; i <
GetSize(); ++i)
501 for (
size_t i = 0; i <
GetSize(); ++i)
511 for (
size_t i = 0; i <
GetSize(); ++i)
519 for (
size_t i = 0; i <
GetSize(); ++i)
527 for (
size_t i = 0; i <
GetSize(); ++i)
535 for (
size_t i = 0; i <
GetSize(); ++i)
543 for (
size_t i = 0; i <
GetSize(); ++i)
553 for (
size_t i = 0; i <
GetSize(); ++i)
561 for (
size_t i = 0; i <
GetSize(); ++i)
569 for (
size_t i = 0; i <
GetSize(); ++i)
577 for (
size_t i = 0; i <
GetSize(); ++i)
587 for (
size_t i = 0; i <
GetSize(); ++i)
595 for (
size_t i = 0; i <
GetSize(); ++i)
601 std::vector<size_t> newdims(
dims.size() + other.
dims.size());
603 for (
size_t i = 0; i <
dims.size(); ++i)
604 newdims[i] =
dims[i];
606 for (
size_t i = 0; i < other.
dims.size(); ++i)
607 newdims[
dims.size() + i] = other.
dims[i];
612 for (
size_t i = 0; i <
GetSize(); ++i)
613 for (
size_t j = 0; j < other.
GetSize(); ++j)
621 const std::array<std::pair<size_t, size_t>, 1> indices{{{ind1, ind2}}};
622 return ContractImpl(other, indices, allowMultithreading);
627 return ContractImpl(other, indices, allowMultithreading);
637 if (result.IsDummy())
644 detail::TensorDenseContraction<T>(
values, other.
values, result.values, fa, fb, ka, kb, allow,
detail::TensorGateSize(
dims, other.
dims, indices.size()));
651 assert(
dims.size() > 0);
658 size_t dimMin =
dims[0];
659 for (
size_t i = 1; i <
dims.size(); ++i)
660 if (
dims[i] < dimMin)
663 for (
size_t i = 0; i < dimMin; ++i)
665 const std::vector<size_t> indices(
dims.size(), i);
675 assert(ind1 <
dims.size() && ind2 <
dims.size());
677 std::vector<size_t> newdims;
679 size_t newsize =
dims.size() - 2;
684 newdims.push_back(1);
688 newdims.reserve(newsize);
690 for (
size_t i = 0; i <
dims.size(); ++i)
691 if (i != ind1 && i != ind2)
692 newdims.push_back(
dims[i]);
695 size_t dimMin =
dims[ind1];
696 if (
dims[ind2] < dimMin)
703 for (
size_t offset = 0; offset < result.
GetSize(); ++offset)
705 std::vector<size_t> indices1(
dims.size());
709 for (
size_t i = 0; i <
dims.size(); ++i)
710 if (i != ind1 && i != ind2)
711 indices1[i] = indices[i - skip];
715 for (
size_t i = 0; i < dimMin; ++i)
717 indices1[ind1] = indices1[ind2] = i;
729 std::vector<size_t> newdims;
731 size_t newsize =
dims.size() - tindices.size();
736 newdims.push_back(1);
740 newdims.reserve(newsize);
742 for (
size_t i = 0; i <
dims.size(); ++i)
745 for (
size_t j = 0; j < tindices.size(); ++j)
746 if (i == tindices[j])
753 newdims.push_back(
dims[i]);
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]];
766 for (
size_t offset = 0; offset < result.
GetSize(); ++offset)
768 std::vector<size_t> indices1(
dims.size());
772 for (
size_t i = 0; i <
dims.size(); ++i)
775 for (
size_t j = 0; j < tindices.size(); ++j)
776 if (i == tindices[j])
783 indices1[i] = indices[i - skipv];
788 for (
size_t i = 0; i < dimMin; ++i)
790 for (
size_t j = 0; j < tindices.size(); ++j)
791 indices1[tindices[j]] = i;
803 const std::vector<size_t> indices(args.begin(), args.end());
805 return Trace(indices);
810 assert(indices.size() ==
dims.size());
812 std::vector<size_t> newdims(
dims.size());
813 for (
size_t i = 0; i <
dims.size(); ++i)
814 newdims[i] =
dims[indices[i]];
820 std::vector<size_t> indices2(
dims.size());
821 for (
size_t offset = 0; offset <
GetSize(); ++offset)
825 for (
size_t i = 0; i <
dims.size(); ++i)
826 indices2[indices[i]] = indices1[i];
828 result[indices2] =
values[offset];
837 const std::vector<size_t> indices(args.begin(), args.end());
849 for (
size_t offset = 0; offset <
GetSize(); ++offset)
850 result[offset] =
values[offset];
857 const std::vector<size_t> newdims(args.begin(), args.end());
865 inline size_t GetOffset(
const std::vector<size_t> &indices)
const
867 return GetFortranOffset(indices);
872 return IndexFromFortranOffset(offset);
878 inline size_t GetCPPOffset(
const std::vector<size_t> &indices)
const
880 assert(indices.size() ==
dims.size());
884 for (
size_t i = 0; i <
dims.size(); ++i)
886 assert(indices[i] <
dims[i]);
888 result = result *
dims[i] + indices[i];
894 inline std::vector<size_t> IndexFromCPPOffset(
size_t offset)
const
896 std::vector<size_t> indices(
dims.size(), 0);
898 for (
int i =
static_cast<int>(
dims.size()) - 1; i >= 0; --i)
900 indices[i] = offset %
dims[i];
914 inline size_t GetFortranOffset(
const std::vector<size_t> &indices)
const
916 assert(indices.size() ==
dims.size());
920 for (
long long int i =
dims.size() - 1; i >= 0; --i)
922 assert(indices[i] <
dims[i]);
924 result = result *
dims[i] + indices[i];
930 inline std::vector<size_t> IndexFromFortranOffset(
size_t offset)
const
932 std::vector<size_t> indices(
dims.size(), 0);
934 for (
size_t i = 0; i <
dims.size(); ++i)
936 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
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
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
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)
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.