diff --git a/la_traits.h b/la_traits.h index 6fe3abf..22e76c2 100644 --- a/la_traits.h +++ b/la_traits.h @@ -306,6 +306,8 @@ static void deallocate(std::complex &x) {}; static inline std::complex conjugate(const std::complex &x) {return std::complex(x.real(),-x.imag());}; static inline C realpart(const std::complex &x) {return x.real();} static inline C imagpart(const std::complex &x) {return x.imag();} +static inline void setrealpart(std::complex &x, const C &y) {reinterpret_cast(x)[0]=y;} +static inline void setimagpart(std::complex &x, const C &y) {reinterpret_cast(x)[1]=y;} }; @@ -364,6 +366,8 @@ static void deallocate(C &x) {}; static inline C conjugate(const C &x) {return x;}; static inline C realpart(const C &x) {return x;} static inline C imagpart(const C &x) {return 0;} +static inline void setrealpart(C &x, const C &y) {x=y;} +static inline void setimagpart(C &x, const C &y) {} }; diff --git a/t.cc b/t.cc index 5c3109c..fedf1ae 100644 --- a/t.cc +++ b/t.cc @@ -4263,7 +4263,7 @@ for(int k=0; k > xf=x.flatten(1); +cout <<"xf= "< > xxx=x.unwind_index_group(1); +cout <<"xxx= "< > xx = xf.merge_indices(il,sym); +cout <<"xx = "<(xlist); +Tensor > y(s); y.randomize(1.); +INDEXNAME ylist[] = {"n","m","j","i"}; +y.names=NRVec(ylist); + +Tensor >z(s); z.clear(); +INDEXNAME zlist[] = {"k","l","m","n"}; +z.names=NRVec(zlist); +Tensor >zz(z); + + +z.add_permuted_contractions("k/l,m",x,y,1,0,false,false); + +zz.copyonwrite(); +for(int k=0; k s=0; + for(int i=0; i > zzz(s); +for(int k=0; k +#include namespace LA { @@ -899,7 +900,7 @@ template static void flatten_callback(const SUPERINDEX &I, T *v) { FLATINDEX J = superindex2flat(I); -//std::cout <<"TEST flatten_callback: from "<)(J); //rhs operator() generates the redundant elements for the unwinded lhs tensor } // @@ -1432,6 +1433,7 @@ template static const PermutationAlgebra *help_pa; static bool help_inverse; +static bool help_conjugate; template static T help_alpha; @@ -1443,7 +1445,10 @@ FLATINDEX J = superindex2flat(I); for(int p=0; p->size(); ++p) { FLATINDEX Jp = J.permuted((*help_pa)[p].perm,help_inverse); - *v += help_alpha * (*help_pa)[p].weight * (*help_tt)(Jp); + bool conj=false; + if(help_conjugate) conj= ((*help_pa)[p].perm).parity()<0; + T tmp= (*help_tt)(Jp); + *v += help_alpha * (*help_pa)[p].weight * (conj ? LA_traits::conjugate(tmp) : tmp); } } @@ -1476,7 +1481,7 @@ for(int p=0; p->size(); ++p) template -void Tensor::apply_permutation_algebra(const Tensor &rhs, const PermutationAlgebra &pa, bool inverse, T alpha, T beta) +void Tensor::apply_permutation_algebra(const Tensor &rhs, const PermutationAlgebra &pa, bool inverse, T alpha, T beta, bool conjugate) { if(beta!=(T)0) {if(beta!=(T)1) *this *= beta;} else clear(); if(alpha==(T)0) return; @@ -1500,6 +1505,7 @@ if(rhs.is_named()) help_tt = &rhs; help_pa = &pa; help_inverse = inverse; +help_conjugate= LA_traits::is_complex() ? conjugate : false; help_alpha = alpha; loopover(permutationalgebra_callback); } @@ -1882,6 +1888,7 @@ if(!basicperm.is_valid()) laerror("internal error in merge_indices"); //prepare permutation algebra PermutationAlgebra pa; +bool doconjugate=false; if(sym==0) { pa.resize(1); @@ -1890,6 +1897,7 @@ if(sym==0) } else { + doconjugate = sym>=2||sym<= -2; PermutationAlgebra sa = sym>0 ? symmetrizer(il.size()) : antisymmetrizer(il.size()); //std::cout <<"SA = "< +static void hermiticity_callback(const SUPERINDEX &I, T *v) +{ +bool zeroimag; +bool zeroreal; +checkindex(help_t->shape,I,zeroreal,zeroimag); +if(zeroreal) LA_traits::setrealpart(*v,0); +if(zeroimag) LA_traits::setimagpart(*v,0); +} + + +template +static void hermiticity_callback2(const SUPERINDEX &I, const T *v) +{ +bool zeroimag; +bool zeroreal; +checkindex(help_tt->shape,I,zeroreal,zeroimag); +if(zeroreal && LA_traits::realpart(*v)!=(T)0 || zeroimag && LA_traits::imagpart(*v)!=(T)0) throw true; +} + + + +template +void Tensor::enforce_hermiticity() +{ +if(!has_hermiticity()) return; +help_t = this; +loopover(hermiticity_callback); +} + + +template +bool Tensor::fulfills_hermiticity() const +{ +if(!has_hermiticity()) return true; +help_tt = this; +try { + constloopover(hermiticity_callback2); + } +catch(bool failed) {return false;} +return true; +} + + template class Tensor; template class Tensor >; diff --git a/tensor.h b/tensor.h index 5fb4184..9c22569 100644 --- a/tensor.h +++ b/tensor.h @@ -50,7 +50,7 @@ namespace LA { template -inline T signeddata(const int sgn, const T data, const bool lhs=false) +static inline T signeddata(const int sgn, const T &data) { if(LA_traits::is_complex()) //condition known at compile time { @@ -69,9 +69,6 @@ if(LA_traits::is_complex()) //condition known at compile time return -LA_traits::conjugate(data); break; case 0: -#ifdef DEBUG - if(lhs) laerror("dereferencing lhs Signedpointer to nonexistent tensor element"); -#endif return 0; break; } @@ -81,9 +78,6 @@ if(LA_traits::is_complex()) //condition known at compile time { if(sgn>0) return data; if(sgn<0) return -data; -#ifdef DEBUG - if(sgn==0 && lhs) laerror("dereferencing lhs Signedpointer to nonexistent tensor element"); -#endif return 0; } @@ -273,12 +267,24 @@ public: void resize(const NRVec &s) {shape=s; data.resize(calcsize()); calcrank(); names.clear();}; void deallocate() {data.resize(0); shape.resize(0); groupsizes.resize(0); cumsizes.resize(0); names.resize(0);}; - inline Signedpointer lhs(const SUPERINDEX &I) {int sign; LA_largeindex i=index(&sign,I); return Signedpointer(&data[i],sign);}; - inline T operator()(const SUPERINDEX &I) const {int sign; LA_largeindex i=index(&sign,I); return signeddata(sign,data[i]);}; - inline Signedpointer lhs(const FLATINDEX &I) {int sign; LA_largeindex i=index(&sign,I); return Signedpointer(&data[i],sign);}; - inline T operator()(const FLATINDEX &I) const {int sign; LA_largeindex i=index(&sign,I); return signeddata(sign,data[i]);}; - inline Signedpointer lhs(LA_index i1...) {va_list args; int sign; LA_largeindex i; va_start(args,i1); i= vindex(&sign, i1,args); return Signedpointer(&data[i],sign); }; - inline T operator()(LA_index i1...) const {va_list args; ; int sign; LA_largeindex i; va_start(args,i1); i= vindex(&sign, i1,args); return signeddata(sign,data[i]);}; + inline Signedpointer lhs(const SUPERINDEX &I) {int sign; LA_largeindex i=index(&sign,I); +#ifdef DEBUG + if(sign==0) laerror("l-value pointer to nonexistent tensor element"); +#endif + return Signedpointer(&data[i],sign);}; + inline T operator()(const SUPERINDEX &I) const {int sign; LA_largeindex i=index(&sign,I); if(sign==0) return 0; else return signeddata(sign,data[i]);}; + inline Signedpointer lhs(const FLATINDEX &I) {int sign; LA_largeindex i=index(&sign,I); +#ifdef DEBUG + if(sign==0) laerror("l-value pointer to nonexistent tensor element"); +#endif + return Signedpointer(&data[i],sign);}; + inline T operator()(const FLATINDEX &I) const {int sign; LA_largeindex i=index(&sign,I); if(sign==0) return 0; else return signeddata(sign,data[i]);}; + inline Signedpointer lhs(LA_index i1...) {va_list args; int sign; LA_largeindex i; va_start(args,i1); i= vindex(&sign, i1,args); +#ifdef DEBUG + if(sign==0) laerror("l-value pointer to nonexistent tensor element"); +#endif + return Signedpointer(&data[i],sign); }; + inline T operator()(LA_index i1...) const {va_list args; ; int sign; LA_largeindex i; va_start(args,i1); i= vindex(&sign, i1,args); if(sign==0) return 0; else return signeddata(sign,data[i]);}; inline Tensor& operator=(const Tensor &rhs) {myrank=rhs.myrank; shape=rhs.shape; groupsizes=rhs.groupsizes; cumsizes=rhs.cumsizes; data=rhs.data; names=rhs.names; return *this;}; @@ -332,7 +338,9 @@ public: void put(int fd, bool with_names=false) const; void get(int fd, bool with_names=false); - inline void randomize(const typename LA_traits::normtype &x) {if(has_hermiticity()) laerror("randomization does not support correct treatment of hermitean/antihermitean index groups"); data.randomize(x);}; + void enforce_hermiticity(); //zero out real/imag parts for repeated indices appropriately + bool fulfills_hermiticity() const; //check it is so + inline void randomize(const typename LA_traits::normtype &x) {data.randomize(x); enforce_hermiticity();}; void loopover(void (*callback)(const SUPERINDEX &, T *)); //loop over all elements void constloopover(void (*callback)(const SUPERINDEX &, const T *)) const; //loop over all elements @@ -373,7 +381,7 @@ public: Tensor innercontraction(const NRVec &nl1, const NRVec &nl2) const {return innercontraction(findindexlist(nl1),findindexlist(nl2));}; Tensor innercontraction(const INDEXNAME &n1, const INDEXNAME &n2) const {return innercontraction(findindex(n1),findindex(n2));}; - void apply_permutation_algebra(const Tensor &rhs, const PermutationAlgebra &pa, bool inverse=false, T alpha=1, T beta=0); //general (not optimally efficient) symmetrizers, antisymmetrizers etc. acting on the flattened index list: + void apply_permutation_algebra(const Tensor &rhs, const PermutationAlgebra &pa, bool inverse=false, T alpha=1, T beta=0, bool conjugate_by_parity=false); //general (not optimally efficient) symmetrizers, antisymmetrizers etc. acting on the flattened index list: void apply_permutation_algebra(const NRVec &rhsvec, const PermutationAlgebra &pa, bool inverse=false, T alpha=1, T beta=0); //avoids explicit outer product but not vectorized, rather inefficient // this *=beta; for I over this: this(I) += alpha * sum_P c_P rhs(P(I)) // PermutationAlgebra can represent e.g. general_antisymmetrizer in Kucharski-Bartlett notation, or Grassmann products building RDM from cumulants