327 lines
11 KiB
C++
327 lines
11 KiB
C++
#ifndef _fourindex_included
|
|
#define _fourindex_included
|
|
#include <iostream>
|
|
#include <string.h>
|
|
|
|
//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<class I, class T>
|
|
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; //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 I, class T>
|
|
class fourindex {
|
|
protected:
|
|
fourindexsymtype symmetry;
|
|
I nn;
|
|
int *count;
|
|
matel4<I,T> *list;
|
|
private:
|
|
void deletelist();
|
|
void copylist(const matel4<I,T> *l);
|
|
public:
|
|
//iterator
|
|
typedef class iterator {
|
|
private:
|
|
matel4<I,T> *p;
|
|
public:
|
|
iterator() {};
|
|
~iterator() {};
|
|
iterator(matel4<I,T> *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<I,T> & operator*() {return *p;}
|
|
matel4<I,T> * operator->() {return p;}
|
|
const matel4<I,T> * operator->() const {return p;}
|
|
const matel4<I,T> & 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<I,T> *p;
|
|
matel4<I,T> 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<I,T> *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<I,T> & operator*() const {return my;}
|
|
const matel4<I,T> * 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<I,T> *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<I,T> *ltmp= new matel4<I,T>; 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<I,T>::packedindex &index , const T elem)
|
|
{matel4<I,T> *ltmp= new matel4<I,T>; ltmp->next=list; list=ltmp; list->index=index; list->elem=elem;}
|
|
|
|
inline void add(const I (&index)[4], const T elem)
|
|
{matel4<I,T> *ltmp= new matel4<I,T>; ltmp->next=list; list=ltmp; memcpy(&list->index.packed, &index, sizeof(typename matel4<I,T>::packedindex)); list->elem=elem;}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
//destructor
|
|
template <class I,class T>
|
|
fourindex<I,T>::~fourindex()
|
|
{
|
|
if(!count) return;
|
|
if(--(*count)<=0)
|
|
{
|
|
deletelist();
|
|
delete count;
|
|
}
|
|
}
|
|
|
|
//copy constructor (sort arrays are not going to be copied)
|
|
template <class I, class T>
|
|
fourindex<I,T>::fourindex(const fourindex<I,T> &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 <class I, class T>
|
|
fourindex<I,T> & fourindex<I,T>::operator=(const fourindex<I,T> &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 <class I, class T>
|
|
fourindex<I,T> & fourindex<I,T>::operator+=(const fourindex<I,T> &rhs)
|
|
{
|
|
if(nn!=rhs.nn) laerror("incompatible dimensions for +=");
|
|
if(!count) {count=new int; *count=1; list=NULL;}
|
|
else copyonwrite();
|
|
register matel4<I,T> *l=rhs.list;
|
|
while(l)
|
|
{
|
|
add( l->index,l->elem);
|
|
l=l->next;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <class I, class T>
|
|
fourindex<I,T> & fourindex<I,T>::join(fourindex<I,T> &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<I,T> **last=&list;
|
|
while(*last) last= &((*last)->next);
|
|
*last=rhs.list;
|
|
rhs.list=NULL;
|
|
return *this;
|
|
}
|
|
|
|
template <class I, class T>
|
|
void fourindex<I,T>::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 <class I, class T>
|
|
void fourindex<I,T>::deletelist()
|
|
{
|
|
if(*count >1) laerror("trying to delete shared list");
|
|
matel4<I,T> *l=list;
|
|
while(l)
|
|
{
|
|
matel4<I,T> *ltmp=l;
|
|
l=l->next;
|
|
delete ltmp;
|
|
}
|
|
list=NULL;
|
|
delete count;
|
|
count=NULL;
|
|
}
|
|
|
|
template <class I, class T>
|
|
void fourindex<I,T>::copylist(const matel4<I,T> *l)
|
|
{
|
|
list=NULL;
|
|
while(l)
|
|
{
|
|
add(l->index,l->elem);
|
|
l=l->next;
|
|
}
|
|
}
|
|
|
|
template <class I, class T>
|
|
void fourindex<I,T>::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 <class I, class T>
|
|
int fourindex<I,T>::length() const
|
|
{
|
|
int n=0;
|
|
matel4<I,T> *l=list;
|
|
while(l)
|
|
{
|
|
++n;
|
|
l=l->next;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
template <class I, class T>
|
|
ostream& operator<<(ostream &s, const fourindex<I,T> &x)
|
|
{
|
|
int n;
|
|
n=x.size();
|
|
s << n << '\n';
|
|
typename fourindex<I,T>::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 <class I, class T>
|
|
istream& operator>>(istream &s, fourindex<I,T> &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*/
|