diff --git a/t.cc b/t.cc index 54110cb..2408964 100644 --- a/t.cc +++ b/t.cc @@ -3974,7 +3974,7 @@ cout <>r>>n>>sym; +INDEXGROUP shape; + { + shape.number=r; + shape.symmetry= sym; + shape.range=n; + shape.offset=0; + } +Tensor x(shape); x.randomize(1.); +//cout < xf=x.flatten(); + +INDEXLIST il(r); +for(int i=0; i xx = xf.merge_indices(il,sym); +//cout <=shape[il[i].group].number) laerror("wrong index number in unwind_indices"); + for(int j=0; j u = conjugate1? (rhs1.unwind_indices(il1)).conjugateme() : rhs1.unwind_indices(il1); @@ -1650,6 +1652,130 @@ return ind; } +template +Tensor Tensor::merge_indices(const INDEXLIST &il, int sym) const +{ +if(il.size()==0) laerror("empty index list for merge_indices"); +if(il.size()==1) return unwind_index(il[0]); //result should be index group of size 1 + +bool samegroup=true; +bool isordered=true; +for(int i=0; i=shape.size()) laerror("wrong group number in merge_indices"); + if(il[i].index<0||il[i].index>=shape[il[i].group].number) laerror("wrong index number in merge_indices"); + for(int j=0; j workshape(shape); +workshape.copyonwrite(); +NRPerm basicperm(rank()); + +bitvector was_in_list(rank()); +was_in_list.clear(); +for(int i=0; i0) ++newshapesize; //this group survived index removal + +NRVec newshape(newshapesize); +newshape[0].number=il.size(); +newshape[0].symmetry=sym; +newshape[0].offset=shape[il[0].group].offset; +newshape[0].range=shape[il[0].group].range; +#ifdef LA_TENSOR_INDEXPOSITION +newshape[0].upperindex=shape[il[0].group].upperindex; +#endif +int ii=1; +for(int i=0; i0) + newshape[ii++] = workshape[i]; +int jj=1+il.size(); +for(int i=0; i>(std::istream &s, INDEX &x) +{ +s>>x.group>>x.index; +return s; +} + + + template class Tensor; template class Tensor >; diff --git a/tensor.h b/tensor.h index 53cda74..a23c498 100644 --- a/tensor.h +++ b/tensor.h @@ -41,15 +41,11 @@ //TODO: //@@@contraction inside one tensor - compute resulting shape, loopover the shape, create index into the original tensor + loop over the contr. index, do the summation, store result -//@@@ will need to store vector of INDEX to the original tensor for the result's flatindex -//@@@ will not be particularly efficient -// -//maybe optional negative range for beta spin handling in some cases of fourindex-tensor conversions -// +//@@@ will need to store vector of INDEX to the original tensor for the result's flatindex, will not be particularly efficient +//@@@?maybe optional negative range for beta spin handling in some cases of fourindex-tensor conversions //@@@?general permutation of individual indices - check the indices in sym groups remain adjacent, calculate result's shape, loopover the result and permute using unwind_callback -//@@@? apply_permutation_algebra if result should be symmetric/antisymmetric in such a way to compute only the nonredundant part -//@@@symetrizace a antisymetrizace skupiny indexu - jak efektivneji nez pres permutationalgebra? -// +//@@@ is that needed? we can flatten the relevant groups and permute index groups alternatively - maybe implement on high level this way for convenience + //do not distinguish covariant/contravariant indices @@ -160,9 +156,14 @@ struct INDEX { int group; int index; +bool operator==(const INDEX &rhs) const {return group==rhs.group && index==rhs.index;}; }; typedef NRVec INDEXLIST; //collection of several indices +std::ostream & operator<<(std::ostream &s, const INDEX &x); +std::istream & operator>>(std::istream &s, INDEX &x); + + int flatposition(int group, int index, const NRVec &shape); int flatposition(const INDEX &i, const NRVec &shape); //position of that index in FLATINDEX INDEX indexposition(int flatindex, const NRVec &shape); //inverse to flatposition @@ -188,12 +189,12 @@ public: //constructors Tensor() : myrank(-1) {}; explicit Tensor(const T &x) : myrank(0), data(1) {data[0]=x;}; //scalar - Tensor(const NRVec &s) : shape(s) { data.resize(calcsize()); calcrank();}; //general tensor - Tensor(const NRVec &s, const NRVec &newnames) : shape(s), names(newnames) { data.resize(calcsize()); calcrank(); if(names.size()!=myrank && names.size()!=0) laerror("bad number of index names");}; //general tensor - Tensor(const NRVec &s, const NRVec &mydata) : shape(s) { LA_largeindex dsize=calcsize(); calcrank(); if(mydata.size()!=dsize) laerror("inconsistent data size with shape"); data=mydata;} - Tensor(const NRVec &s, const NRVec &mydata, const NRVec &newnames) : shape(s), names(newnames) { LA_largeindex dsize=calcsize(); calcrank(); if(mydata.size()!=dsize) laerror("inconsistent data size with shape"); data=mydata; if(names.size()!=myrank && names.size()!=0) laerror("bad number of index names");} - Tensor(const indexgroup &g) {shape.resize(1); shape[0]=g; data.resize(calcsize()); calcrank();}; //tensor with a single index group - Tensor(const indexgroup &g, const NRVec &newnames) : names(newnames) {shape.resize(1); shape[0]=g; data.resize(calcsize()); calcrank(); if(names.size()!=myrank && names.size()!=0) laerror("bad number of index names");}; //tensor with a single index group + Tensor(const NRVec &s) : shape(s) { data.resize(calcsize()); calcrank(); canonicalize_shape();}; //general tensor + Tensor(const NRVec &s, const NRVec &newnames) : shape(s), names(newnames) { data.resize(calcsize()); calcrank(); canonicalize_shape(); if(names.size()!=myrank && names.size()!=0) laerror("bad number of index names");}; //general tensor + Tensor(const NRVec &s, const NRVec &mydata) : shape(s) { LA_largeindex dsize=calcsize(); calcrank(); canonicalize_shape(); if(mydata.size()!=dsize) laerror("inconsistent data size with shape"); data=mydata;} + Tensor(const NRVec &s, const NRVec &mydata, const NRVec &newnames) : shape(s), names(newnames) { LA_largeindex dsize=calcsize(); calcrank(); canonicalize_shape(); if(mydata.size()!=dsize) laerror("inconsistent data size with shape"); data=mydata; if(names.size()!=myrank && names.size()!=0) laerror("bad number of index names");} + Tensor(const indexgroup &g) {shape.resize(1); shape[0]=g; data.resize(calcsize()); calcrank(); canonicalize_shape();}; //tensor with a single index group + Tensor(const indexgroup &g, const NRVec &newnames) : names(newnames) {shape.resize(1); shape[0]=g; data.resize(calcsize()); calcrank(); canonicalize_shape(); if(names.size()!=myrank && names.size()!=0) laerror("bad number of index names");}; //tensor with a single index group Tensor(const Tensor &rhs): myrank(rhs.myrank), shape(rhs.shape), groupsizes(rhs.groupsizes), cumsizes(rhs.cumsizes), data(rhs.data), names(rhs.names) {}; Tensor(int xrank, const NRVec &xshape, const NRVec &xgroupsizes, const NRVec xcumsizes, const NRVec &xdata) : myrank(xrank), shape(xshape), groupsizes(xgroupsizes), cumsizes(xcumsizes), data(xdata) {}; Tensor(int xrank, const NRVec &xshape, const NRVec &xgroupsizes, const NRVec xcumsizes, const NRVec &xdata, const NRVec &xnames) : myrank(xrank), shape(xshape), groupsizes(xgroupsizes), cumsizes(xcumsizes), data(xdata), names(xnames) {}; @@ -212,6 +213,7 @@ public: void defaultnames() {names.resize(rank()); for(int i=0; i &groups) const; Tensor flatten(int group= -1) const; //split and uncompress a given group or all of them, leaving flat index order the same + Tensor merge_indices(const INDEXLIST &il, int symmetry=0) const; //opposite to flatten (merging with optional symmetrization/antisymmetrization and compression) NRVec > Tucker(typename LA_traits::normtype thr=1e-12, bool inverseorder=true); //HOSVD-Tucker decomposition, return core tensor in *this, flattened Tensor inverseTucker(const NRVec > &x, bool inverseorder=true) const; //rebuild the original tensor from Tucker