2004-03-17 04:07:21 +01:00
# ifndef _fourindex_included
# define _fourindex_included
2006-04-01 06:48:01 +02:00
# include <iostream>
2005-12-08 12:44:36 +01:00
# include <string.h>
2004-03-17 04:07:21 +01:00
//element of a linked list, indices in a portable way, no bit shifts and endianity problems any more!
2005-09-11 22:04:24 +02:00
//note: nn is never compared with individual indices, so indexing from 1 as well as from 0 is possible
2004-03-17 04:07:21 +01:00
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 ;
} ;
2006-04-01 06:48:01 +02:00
typedef enum { nosymmetry = 0 , twoelectronrealmullikan = 1 , twoelectronrealdirac = 2 , T2ijab_real = 3 } fourindexsymtype ; //only permutation-nonequivalent elements are stored
2005-12-08 11:35:50 +01:00
// 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 ;
2005-12-08 12:44:36 +01:00
static const int fourindex_permnumbers [ fourindex_n_symmetrytypes ] = { 1 , 8 , 8 , 4 } ;
2005-12-08 11:35:50 +01:00
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 } }
} ;
2004-03-17 04:07:21 +01:00
template < class I , class T >
class fourindex {
protected :
fourindexsymtype symmetry ;
2005-12-08 12:44:36 +01:00
I nn ;
2004-03-17 04:07:21 +01:00
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 ) { } ;
2005-12-08 11:35:50 +01:00
bool operator = = ( const iterator & rhs ) const { return p = = rhs . p ; }
bool operator ! = ( const iterator & rhs ) const { return p ! = rhs . p ; }
2005-12-08 12:44:36 +01:00
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 ; }
2004-03-17 04:07:21 +01:00
} ;
iterator begin ( ) const { return list ; }
iterator end ( ) const { return NULL ; }
2005-12-08 11:35:50 +01:00
//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 :
2005-12-08 12:44:36 +01:00
fourindexsymtype symmetry ;
2005-12-08 11:35:50 +01:00
matel4 < I , T > * p ;
matel4 < I , T > my ;
int permindex ;
2005-12-08 12:44:36 +01:00
void setup ( void ) //make a copy of *p to my with scaled element and anti/permuted indices
2005-12-08 11:35:50 +01:00
{
2005-12-08 12:44:36 +01:00
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
2005-12-08 14:03:07 +01:00
//if the processing of individual term becomes very costly, an alternative would be to screen permutations yielding identical result
2005-12-08 12:44:36 +01:00
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 ;
2005-12-08 11:35:50 +01:00
break ;
2005-12-08 12:44:36 +01:00
case T2ijab_real : break ; //result will automatically vanish due to antisymmetry
case nosymmetry : break ;
default : laerror ( " illegal symmetry in piterator " ) ;
2005-12-08 11:35:50 +01:00
}
} ;
public :
piterator ( ) { } ;
2005-12-08 12:44:36 +01:00
piterator ( matel4 < I , T > * pp ) : symmetry ( nosymmetry ) , p ( pp ) , permindex ( 0 ) { } ;
2005-12-08 11:35:50 +01:00
~ piterator ( ) { } ;
2005-12-08 12:44:36 +01:00
piterator ( const fourindex & x ) : symmetry ( x . symmetry ) , p ( x . list ) , permindex ( 0 ) { setup ( ) ; } ;
2005-12-08 13:06:23 +01:00
piterator & operator + + ( ) { if ( + + permindex > = fourindex_permnumbers [ symmetry ] ) { permindex = 0 ; p = p - > next ; } setup ( ) ; return * this ; }
2005-12-08 12:44:36 +01:00
const matel4 < I , T > & operator * ( ) const { return my ; }
const matel4 < I , T > * operator - > ( ) const { return & my ; }
2005-12-08 11:35:50 +01:00
piterator operator + + ( int ) { laerror ( " postincrement not possible on permute-iterator " ) ; }
2005-12-08 13:06:23 +01:00
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 ; }
2005-12-08 14:03:07 +01:00
bool end ( void ) { return ! p ; }
bool notend ( void ) { return p ; }
2005-12-08 11:35:50 +01:00
} ;
2005-12-08 13:06:23 +01:00
piterator pbegin ( ) const { return piterator ( * this ) ; }
2005-12-08 14:03:07 +01:00
piterator pend ( ) const { return piterator ( NULL ) ; } //deprecated, inefficient
2004-03-17 04:07:21 +01:00
//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 ' ;
2004-03-25 16:27:19 +01:00
typename fourindex < I , T > : : iterator it = x . begin ( ) , end = x . end ( ) ;
while ( it ! = end )
2004-03-17 04:07:21 +01:00
{
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 ) ;
2005-09-11 22:04:24 +02:00
s > > i > > j > > k > > l ;
2004-03-17 04:07:21 +01:00
}
return s ;
}
# endif /*_fourindex_included*/