diff --git a/t.cc b/t.cc index 2a069b5..318a52a 100644 --- a/t.cc +++ b/t.cc @@ -4424,7 +4424,7 @@ cout < y = x.inverseTucker(dec,inv); cout <<"invTucker\n"< names_saved = names; Tensor tmp(*this); Tensor r; if(!is_flat()) laerror("inverseTucker only for flat tensors as produced by Tucker"); @@ -1818,14 +1817,60 @@ for(int i=rank()-1; i>=0; --i) if(inverseorder) { NRPerm p(rank()); p.identity(); - r.names=names_saved.permuted(p.reverse()); + r.names=names.permuted(p.reverse()); } else - r.names=names_saved; + r.names=names; return r; } +template +Tensor Tensor::linear_transform(const NRVec > &x) const +{ +if(x.size()!=shape.size()) laerror("wrong number of transformation matrices in linear_transform"); +for(int i=0; i tmp(*this); +Tensor r; + +//do the groups in reverse order to preserve index ordering +for(int g=shape.size()-1; g>=0; --g) + { + Tensor mat(x[g],true); //flat tensor from a matrix + for(int i=shape[g].number-1; i>=0; --i) //indices in the group in reverse order + { + r= tmp.contraction(indexposition(rank()-1,tmp.shape),mat,INDEX(0,0),(T)1,false,false); //always the last index + if(i>0) + { + tmp=r; + r.deallocate(); + } + } + //the group's indices are now individual ones leftmost in tensor r, restore group size and symmetry + if(shape[g].number>1) + { + INDEXLIST il(shape[g].number); + for(int i=0; i0) + { + tmp=r; + r.deallocate(); + } + } + +r.names=names; +return r; +} + + + template int Tensor::findflatindex(const INDEXNAME nam) const { diff --git a/tensor.h b/tensor.h index e7152f6..29ab57c 100644 --- a/tensor.h +++ b/tensor.h @@ -83,6 +83,15 @@ if(LA_traits::is_complex()) //condition known at compile time } + +static inline bool ptr_ok(void *ptr) +{ +#ifdef DEBUG +if(ptr==NULL) std::cout<<"Warning: write to nonexistent tensor element ignored\n"; +#endif +return (bool)ptr; +} + template class Signedpointer { @@ -91,11 +100,11 @@ int sgn; public: Signedpointer(T *p, int s) : ptr(p),sgn(s) {}; //dereferencing *ptr should be ignored for sgn==0 - const T operator=(const T rhs) {*ptr = signeddata(sgn,rhs); return rhs;} - void operator*=(const T rhs) {*ptr *= rhs;} - void operator/=(const T rhs) {*ptr /= rhs;} - void operator+=(T rhs) {*ptr += signeddata(sgn,rhs);} - void operator-=(T rhs) {*ptr -= signeddata(sgn,rhs);} + const T operator=(const T rhs) {if(ptr_ok(ptr)) *ptr = signeddata(sgn,rhs); return rhs;} + void operator*=(const T rhs) {if(ptr_ok(ptr)) *ptr *= rhs;} + void operator/=(const T rhs) {if(ptr_ok(ptr)) *ptr /= rhs;} + void operator+=(T rhs) {if(ptr_ok(ptr)) *ptr += signeddata(sgn,rhs);} + void operator-=(T rhs) {if(ptr_ok(ptr)) *ptr -= signeddata(sgn,rhs);} }; @@ -182,6 +191,8 @@ struct INDEX int group; int index; bool operator==(const INDEX &rhs) const {return group==rhs.group && index==rhs.index;}; + INDEX() {}; + INDEX(int g, int i): group(g), index(i) {}; }; typedef NRVec INDEXLIST; //collection of several indices @@ -223,13 +234,16 @@ public: int myrank; NRVec groupsizes; //group sizes of symmetry index groups (a function of shape but precomputed for efficiency) NRVec cumsizes; //cumulative sizes of symmetry index groups (a function of shape but precomputed for efficiency); always cumsizes[0]=1, index group 0 is the innermost-loop one - -public: NRVec names; + + //indexing LA_largeindex index(int *sign, const SUPERINDEX &I) const; //map the tensor indices to the position in data LA_largeindex index(int *sign, const FLATINDEX &I) const; //map the tensor indices to the position in data LA_largeindex vindex(int *sign, LA_index i1, va_list args) const; //map list of indices to the position in data SUPERINDEX inverse_index(LA_largeindex s) const; //inefficient, but possible if needed + int myflatposition(int group, int index) const {return flatposition(group,index,shape);}; + int myflatposition(const INDEX &i) const {return flatposition(i,shape);}; + INDEX myindexposition(int flatindex) const {return indexposition(flatindex,shape);}; //constructors Tensor() : myrank(-1) {}; @@ -273,22 +287,16 @@ public: 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); -#ifdef DEBUG - if(sign==0) laerror("l-value pointer to nonexistent tensor element"); -#endif - return Signedpointer(&data[i],sign);}; + if(sign==0) return Signedpointer(NULL,sign); + else 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);}; + if(sign==0) return Signedpointer(NULL,sign); + else 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); }; + if(sign==0) return Signedpointer(NULL,sign); + else 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;}; @@ -406,6 +414,7 @@ public: NRVec > Tucker(typename LA_traits::normtype thr=1e-12, bool inverseorder=false); //HOSVD-Tucker decomposition, return core tensor in *this, flattened Tensor inverseTucker(const NRVec > &x, bool inverseorder=false) const; //rebuild the original tensor from Tucker + Tensor linear_transform(const NRVec > &x) const; //linear transform by a different matrix per each index group, preserving group symmetries };