#ifndef _fourindex_included #define _fourindex_included #include //element of a linked list, indices in a portable way, no bit shifts and endianity problems any more! //note: nn is never compared with individual indices, so indexing from 1 as well as from 0 is possible template struct matel4 { T elem; matel4 *next; typedef union { I packed[4]; struct { I i; I j; I k; I l; } indiv; } packedindex; packedindex index; }; typedef enum {nosymmetry=0, twoelectronrealmullikan=1, twoelectronrealdirac=2, T2ijab_real=3} fourindexsymtype; //if twoelectron, only permutation-nonequivalent elements are stored // these should actually be static private members of the fourindex class, but leads to an ICE on gcc3.2 static const int fourindex_n_symmetrytypes=4; static const int fourindex_permnumbers[fourindex_n_symmetrytypes]={1,8,8,4}; static const int fourindex_permutations[fourindex_n_symmetrytypes][8][5]= { {{0,1,2,3,1},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, {{0,1,2,3,1}, {1,0,2,3,1}, {0,1,3,2,1}, {1,0,3,2,1}, {2,3,0,1,1}, {3,2,0,1,1}, {2,3,1,0,1}, {3,2,1,0,1}}, {{0,1,2,3,1},{2,1,0,3,1},{0,3,2,1,1},{2,3,0,1,1},{1,0,3,2,1},{3,0,1,2,1},{1,2,3,0,1},{3,2,1,0,1}}, {{0,1,2,3,1},{1,0,2,3,-1},{0,1,3,2,-1},{1,0,3,2,1},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}} }; template class fourindex { protected: fourindexsymtype symmetry; I nn; int *count; matel4 *list; private: void deletelist(); void copylist(const matel4 *l); public: //iterator typedef class iterator { private: matel4 *p; public: iterator() {}; ~iterator() {}; iterator(matel4 *list): p(list) {}; bool operator==(const iterator &rhs) const {return p==rhs.p;} bool operator!=(const iterator &rhs) const {return p!=rhs.p;} iterator &operator++() {p=p->next; return *this;} iterator operator++(int) {iterator q(p); p=p->next; return q;} matel4 & operator*() {return *p;} matel4 * operator->() {return p;} const matel4 * operator->() const {return p;} const matel4 & operator*() const {return *p;} }; iterator begin() const {return list;} iterator end() const {return NULL;} //permiterator ... iterates also over all permutations, with a possibly scaled matrix element or skips permutations yielding equivalent result //has to take into account the symmetry type of the fourindex typedef class piterator { private: fourindexsymtype symmetry; matel4 *p; matel4 my; int permindex; void setup(void) //make a copy of *p to my with scaled element and anti/permuted indices { if(!p) {permindex=0; memset(&my,0,sizeof(my)); return;} for(int i=0; i<4; ++i) my.index.packed[i] = p->index.packed[fourindex_permutations[symmetry][permindex][i]]; my.elem = p->elem * fourindex_permutations[symmetry][permindex][4]; //now treat the redundancy by possibly equal indices //if the processing of individual term becomes very costly, an alternative would be to screen permutations yielding identical result switch(symmetry) { case twoelectronrealmullikan: if(p->index.indiv.i==p->index.indiv.j) my.elem*=.5; if(p->index.indiv.k==p->index.indiv.l) my.elem*=.5; if(p->index.indiv.i==p->index.indiv.k && p->index.indiv.j==p->index.indiv.l) my.elem*=.5; break; case twoelectronrealdirac: if(p->index.indiv.i==p->index.indiv.k) my.elem*=.5; if(p->index.indiv.j==p->index.indiv.l) my.elem*=.5; if(p->index.indiv.i==p->index.indiv.j && p->index.indiv.k==p->index.indiv.l) my.elem*=.5; break; case T2ijab_real: break; //result will automatically vanish due to antisymmetry case nosymmetry: break; default: laerror("illegal symmetry in piterator"); } }; public: piterator() {}; piterator(matel4 *pp): symmetry(nosymmetry),p(pp),permindex(0){}; ~piterator() {}; piterator(const fourindex &x): symmetry(x.symmetry),p(x.list),permindex(0) {setup();}; piterator& operator++() {if(++permindex>=fourindex_permnumbers[symmetry]) {permindex=0; p=p->next;} setup(); return *this;} const matel4 & operator*() const {return my;} const matel4 * operator->() const {return &my;} piterator operator++(int) {laerror("postincrement not possible on permute-iterator");} bool operator==(const piterator &rhs) const {return p==rhs.p && (!p || permindex==rhs.permindex);} bool operator!=(const piterator &rhs) const {return p!=rhs.p || p && rhs.p && permindex!=rhs.permindex;} bool end(void) {return !p;} bool notend(void) {return p;} }; piterator pbegin() const {return piterator(*this);} piterator pend() const {return piterator(NULL);}//deprecated, inefficient //constructors etc. inline fourindex() :nn(0),count(NULL),list(NULL) {}; inline fourindex(const I n) :nn(n),count(new int(1)),list(NULL) {}; fourindex(const fourindex &rhs); //copy constructor inline int getcount() const {return count?*count:0;} fourindex & operator=(const fourindex &rhs); fourindex & operator+=(const fourindex &rhs); inline void setsymmetry(fourindexsymtype s) {symmetry=s;} fourindex & join(fourindex &rhs); //more efficient +=, rhs will be emptied inline ~fourindex(); inline matel4 *getlist() const {return list;} inline I size() const {return nn;} void resize(const I n); void copyonwrite(); int length() const; inline void add(const I i, const I j, const I k, const I l, const T elem) {matel4 *ltmp= new matel4; ltmp->next=list; list=ltmp; list->index.indiv.i=i;list->index.indiv.j=j;list->index.indiv.k=k;list->index.indiv.l=l; list->elem=elem;} inline void add(const typename matel4::packedindex &index , const T elem) {matel4 *ltmp= new matel4; ltmp->next=list; list=ltmp; list->index=index; list->elem=elem;} inline void add(const I (&index)[4], const T elem) {matel4 *ltmp= new matel4; ltmp->next=list; list=ltmp; memcpy(&list->index.packed, &index, sizeof(typename matel4::packedindex)); list->elem=elem;} }; //destructor template fourindex::~fourindex() { if(!count) return; if(--(*count)<=0) { deletelist(); delete count; } } //copy constructor (sort arrays are not going to be copied) template fourindex::fourindex(const fourindex &rhs) { #ifdef debug if(! &rhs) laerror("fourindex copy constructor with NULL argument"); #endif nn=rhs.nn; if(rhs.list&&!rhs.count) laerror("some inconsistency in fourindex contructors or assignments"); list=rhs.list; if(list) {count=rhs.count; (*count)++;} else count=new int(1); //make the matrix defined, but empty and not shared } //assignment operator template fourindex & fourindex::operator=(const fourindex &rhs) { if (this != &rhs) { if(count) if(--(*count) ==0) {deletelist(); delete count;} // old stuff obsolete list=rhs.list; nn=rhs.nn; if(list) count=rhs.count; else count= new int(0); //make the matrix defined, but empty and not shared, count will be incremented below if(count) (*count)++; } return *this; } template fourindex & fourindex::operator+=(const fourindex &rhs) { if(nn!=rhs.nn) laerror("incompatible dimensions for +="); if(!count) {count=new int; *count=1; list=NULL;} else copyonwrite(); register matel4 *l=rhs.list; while(l) { add( l->index,l->elem); l=l->next; } return *this; } template fourindex & fourindex::join(fourindex &rhs) { if(nn!=rhs.nn) laerror("incompatible dimensions for join"); if(*rhs.count!=1) laerror("shared rhs in join()"); if(!count) {count=new int; *count=1; list=NULL;} else copyonwrite(); matel4 **last=&list; while(*last) last= &((*last)->next); *last=rhs.list; rhs.list=NULL; return *this; } template void fourindex::resize(const I n) { if(n<=0 ) laerror("illegal fourindex dimension"); if(count) { if(*count > 1) {(*count)--; count=NULL; list=NULL;} //detach from previous else if(*count==1) deletelist(); } nn=n; count=new int(1); //empty but defined matrix list=NULL; } template void fourindex::deletelist() { if(*count >1) laerror("trying to delete shared list"); matel4 *l=list; while(l) { matel4 *ltmp=l; l=l->next; delete ltmp; } list=NULL; delete count; count=NULL; } template void fourindex::copylist(const matel4 *l) { list=NULL; while(l) { add(l->index,l->elem); l=l->next; } } template void fourindex::copyonwrite() { if(!count) laerror("probably an assignment to undefined fourindex"); if(*count > 1) { (*count)--; count = new int; *count=1; if(!list) laerror("empty list with count>1"); copylist(list); } } template int fourindex::length() const { int n=0; matel4 *l=list; while(l) { ++n; l=l->next; } return n; } template ostream& operator<<(ostream &s, const fourindex &x) { int n; n=x.size(); s << n << '\n'; typename fourindex::iterator it=x.begin(),end=x.end(); while(it!=end) { s << (int)it->index.indiv.i << ' ' << (int)it->index.indiv.j<< ' ' <<(int)it->index.indiv.k << ' ' << (int)it->index.indiv.l << ' ' << it->elem << '\n'; ++it; } s << "-1 -1 -1 -1\n"; return s; } template istream& operator>>(istream &s, fourindex &x) { int i,j,k,l; T elem; int n; s >> n ; x.resize(n); s >> i >> j >>k >>l; while(i>=0 && j>=0 &&k>=0 &&l>=0) { s>>elem; x.add(i,j,k,l,elem); s >> i >> j >>k >>l; } return s; } #endif /*_fourindex_included*/