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>
2006-04-03 00:54:40 +02:00
# include <sys/types.h>
2006-04-25 16:49:43 +02:00
# include <sys/vfs.h>
# include <sys/mman.h>
# include <sys/stat.h>
2006-04-03 00:54:40 +02:00
# include <unistd.h>
2006-04-25 16:49:43 +02:00
# include <sys/stat.h>
2006-04-03 03:43:02 +02:00
# include "la.h"
2006-04-06 00:06:24 +02:00
# include "laerror.h"
2004-03-17 04:07:21 +01:00
2006-04-25 16:49:43 +02:00
static unsigned int hcd0 ( unsigned int big , unsigned int small )
{
register unsigned int help ;
if ( big = = 0 )
{
if ( small = = 0 ) laerror ( " bad arguments in hcd " ) ;
return small ;
}
if ( small = = 0 ) return big ;
if ( small = = 1 | | big = = 1 ) return 1 ;
if ( small > big ) { help = big ; big = small ; small = help ; }
do {
help = small ;
small = big % small ;
big = help ;
}
while ( small ! = 0 ) ;
return big ;
}
2006-04-25 16:52:44 +02:00
static inline unsigned int lcm0 ( unsigned int i , unsigned int j )
2006-04-25 16:49:43 +02:00
{
return ( i / hcd0 ( i , j ) * j ) ;
}
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
2006-04-03 00:54:40 +02:00
//it is actually not needed for the algorithms here, but may be useful for the
//user of this class to keep this piece of information along with the data
2004-03-17 04:07:21 +01:00
2006-04-06 23:45:51 +02:00
//when patient enough, make const_casts for piterators to have pbegin() const
2006-04-02 22:07:29 +02:00
template < class I >
union packed_index {
I packed [ 4 ] ;
struct {
I i ;
I j ;
I k ;
I l ;
} indiv ;
} ;
2004-03-17 04:07:21 +01:00
template < class I , class T >
struct matel4
{
T elem ;
matel4 * next ;
2006-04-02 22:07:29 +02:00
union packed_index < I > index ;
2004-03-17 04:07:21 +01:00
} ;
2006-04-02 22:07:29 +02:00
template < class I , class T >
struct matel4stored
{
T elem ;
union packed_index < I > index ;
} ;
2006-04-03 21:56:20 +02:00
//later add symmetry of complex integrals
2006-09-09 21:51:04 +02:00
typedef enum { undefined_symmetry = - 1 , nosymmetry = 0 , twoelectronrealmullikan = 1 , twoelectronrealdirac = 2 , T2ijab_aces = 3 , antisymtwoelectronrealmullikan = 4 , antisymtwoelectronrealdirac = 5 , T2IjAb_aces = 6 } 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
2006-09-09 21:51:04 +02:00
static const int fourindex_n_symmetrytypes = 7 ;
2006-04-03 21:56:20 +02:00
static const int fourindex_permnumbers [ fourindex_n_symmetrytypes ] = { 1 , 8 , 8 , 4 , 16 , 16 } ;
static const int fourindex_permutations [ fourindex_n_symmetrytypes ] [ 16 ] [ 5 ] =
2005-12-08 11:35:50 +01:00
{
2006-04-03 21:56:20 +02:00
{ { 0 , 1 , 2 , 3 , 1 } } ,
2005-12-08 11:35:50 +01:00
{ { 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 } } ,
2006-04-03 21:56:20 +02:00
{ { 0 , 1 , 2 , 3 , 1 } , { 1 , 0 , 2 , 3 , - 1 } , { 0 , 1 , 3 , 2 , - 1 } , { 1 , 0 , 3 , 2 , 1 } } ,
{ { 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 , 3 , 2 , 1 , - 1 } , { 1 , 3 , 2 , 0 , - 1 } , { 0 , 2 , 3 , 1 , - 1 } , { 1 , 2 , 3 , 1 , - 1 } , { 2 , 1 , 0 , 3 , - 1 } , { 3 , 1 , 0 , 2 , - 1 } , { 2 , 0 , 1 , 3 , - 1 } , { 3 , 0 , 1 , 2 , - 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 , 3 , 2 , - 1 } , { 2 , 1 , 3 , 0 , - 1 } , { 0 , 3 , 1 , 2 , - 1 } , { 2 , 3 , 1 , 0 , - 1 } , { 1 , 0 , 2 , 3 , - 1 } , { 3 , 0 , 2 , 1 , - 1 } , { 1 , 2 , 0 , 3 , - 1 } , { 3 , 2 , 0 , 1 , - 1 } } ,
2006-09-09 21:51:04 +02:00
{ { 0 , 1 , 2 , 3 , 1 } } , //like nosymmetry but different index ranges
2005-12-08 11:35:50 +01:00
} ;
2004-03-17 04:07:21 +01:00
2006-04-03 21:56:20 +02:00
template < class I , class T >
void symmetry_faktor ( const fourindexsymtype symmetry , const union packed_index < I > & index , T & elem )
{
switch ( symmetry )
{
case antisymtwoelectronrealmullikan : //in case of antisymmetry it will vanish anyway, first two conditions apply the same
case twoelectronrealmullikan :
if ( index . indiv . i = = index . indiv . j ) elem * = .5 ;
if ( index . indiv . k = = index . indiv . l ) elem * = .5 ;
if ( index . indiv . i = = index . indiv . k & & index . indiv . j = = index . indiv . l
| | index . indiv . i = = index . indiv . l & & index . indiv . j = = index . indiv . k ) elem * = .5 ;
break ;
case antisymtwoelectronrealdirac : //in case of antisymmetry it will vanish anyway, first two conditions apply the same
case twoelectronrealdirac :
if ( index . indiv . i = = index . indiv . k ) elem * = .5 ;
if ( index . indiv . j = = index . indiv . l ) elem * = .5 ;
if ( index . indiv . i = = index . indiv . j & & index . indiv . k = = index . indiv . l
| | index . indiv . k = = index . indiv . j & & index . indiv . i = = index . indiv . l ) elem * = .5 ;
break ;
2006-09-09 21:51:04 +02:00
case T2ijab_aces : break ; //result will automatically vanish due to generated antisymmetry; i!=a from principle
case T2IjAb_aces : break ; //no actual symmetry
2006-04-03 21:56:20 +02:00
case nosymmetry : break ;
2006-04-06 05:45:50 +02:00
default : laerror ( " illegal symmetry " ) ;
2006-04-03 21:56:20 +02:00
}
}
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
{
2006-04-03 03:43:02 +02:00
if ( symmetry = = undefined_symmetry ) laerror ( " fourindex symmetry has not been set " ) ;
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 ] ;
2006-04-03 21:56:20 +02:00
//now treat the redundancy due to possibly equal indices by a scaling factor
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
2006-04-03 21:56:20 +02:00
symmetry_faktor ( symmetry , p - > index , my . elem ) ;
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 " ) ; }
2006-04-03 00:54:40 +02:00
bool operator ! = ( const piterator & rhs ) const { return p ! = rhs . p ; } //should only be used for comparison with pend()
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 ) ; }
2006-04-03 00:54:40 +02:00
piterator pend ( ) const { return piterator ( NULL ) ; } //inefficient, use end() or notend() instead
2004-03-17 04:07:21 +01:00
//constructors etc.
2006-04-03 03:43:02 +02:00
inline fourindex ( ) : symmetry ( undefined_symmetry ) , nn ( 0 ) , count ( NULL ) , list ( NULL ) { } ;
inline fourindex ( const I n ) : symmetry ( undefined_symmetry ) , nn ( n ) , count ( new int ( 1 ) ) , list ( NULL ) { } ;
2004-03-17 04:07:21 +01:00
fourindex ( const fourindex & rhs ) ; //copy constructor
inline int getcount ( ) const { return count ? * count : 0 ; }
fourindex & operator = ( const fourindex & rhs ) ;
fourindex & operator + = ( const fourindex & rhs ) ;
2006-04-06 05:45:50 +02:00
void setsymmetry ( fourindexsymtype s ) { symmetry = s ; }
fourindexsymtype getsymmetry ( ) const { return symmetry ; }
2004-03-17 04:07:21 +01:00
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 ( ) ;
2006-04-02 22:48:48 +02:00
unsigned long length ( ) const ;
2004-03-17 04:07:21 +01:00
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 ; }
2006-04-02 22:07:29 +02:00
inline void add ( const union packed_index < I > & index , const T elem )
2004-03-17 04:07:21 +01:00
{ 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 )
2006-04-02 22:07:29 +02:00
{ matel4 < I , T > * ltmp = new matel4 < I , T > ; ltmp - > next = list ; list = ltmp ; memcpy ( & list - > index . packed , & index , sizeof ( union packed_index < I > ) ) ; list - > elem = elem ; }
2006-09-09 21:51:04 +02:00
inline void add ( const matel4 < I , T > & rhs )
{ matel4 < I , T > * ltmp = new matel4 < I , T > ; ltmp - > next = list ; list = ltmp ; memcpy ( & list - > index . packed , & rhs . index , sizeof ( union packed_index < I > ) ) ; list - > elem = rhs . elem ; }
inline void add ( const matel4stored < I , T > & rhs )
{ matel4 < I , T > * ltmp = new matel4 < I , T > ; ltmp - > next = list ; list = ltmp ; memcpy ( & list - > index . packed , & rhs . index , sizeof ( union packed_index < I > ) ) ; list - > elem = rhs . elem ; }
2006-04-06 00:06:24 +02:00
unsigned long put ( int fd , bool withattr = true ) const ;
unsigned long get ( int fd , bool withattr = true ) ;
2006-04-02 22:48:48 +02:00
} ;
2004-03-17 04:07:21 +01:00
2006-04-03 00:54:40 +02:00
//and a class for accessing a disc-stored fourindex, taking care of permutational index symmetry
2006-04-25 16:49:43 +02:00
//O_DIRECT approach to avoid filling of the buffer cache when reading
//large file sequentially is implemented:
//the user of the class must open the file with O_DIRECT
//NOTE!!! it will not work on linux 2.4, where O_DIRECT requires filesize to be a multiple of the block; 2.6 kernel is necessary!!!
2006-04-03 00:54:40 +02:00
template < class I , class T >
class fourindex_ext {
private : //at the moment for simplicity forbid some operations, otherwise reference counting on the buffer has to be done
fourindex_ext ( ) ;
fourindex_ext ( const fourindex_ext & rhs ) ;
fourindex_ext & operator = ( const fourindex_ext & rhs ) ;
protected :
2006-04-25 16:49:43 +02:00
matel4stored < I , T > * buffer0 ;
2006-04-03 00:54:40 +02:00
matel4stored < I , T > * buffer ;
matel4stored < I , T > * current ;
2006-04-03 04:01:45 +02:00
int fd ;
unsigned int bufsize ;
2006-04-03 00:54:40 +02:00
unsigned int nread ;
2006-04-03 04:01:45 +02:00
fourindexsymtype symmetry ;
I nn ;
//methods
2006-04-06 05:45:50 +02:00
void tryread ( ) const
2006-04-03 00:54:40 +02:00
{
2006-04-06 05:45:50 +02:00
const_cast < fourindex_ext < I , T > * > ( this ) - > current = NULL ;
2006-04-03 00:54:40 +02:00
ssize_t r = read ( fd , buffer , bufsize * sizeof ( matel4stored < I , T > ) ) ;
if ( r < 0 ) { perror ( " read error " ) ; laerror ( " read error in fourindex_ext " ) ; }
if ( r % sizeof ( matel4stored < I , T > ) ) laerror ( " read inconsistency in fourindex_ext " ) ;
2006-04-06 05:45:50 +02:00
const_cast < fourindex_ext < I , T > * > ( this ) - > nread = r / sizeof ( matel4stored < I , T > ) ;
if ( nread ) const_cast < fourindex_ext < I , T > * > ( this ) - > current = buffer ;
2006-04-03 00:54:40 +02:00
}
2006-04-25 16:49:43 +02:00
void next ( ) const {
if ( current )
{
if ( ( unsigned int ) ( + + const_cast < fourindex_ext < I , T > * > ( this ) - > current - buffer ) > = nread ) tryread ( ) ;
}
}
2006-04-06 05:45:50 +02:00
bool eof ( ) const { return ! current ; } ;
2006-04-06 00:06:24 +02:00
2006-04-03 00:54:40 +02:00
public :
2006-04-25 16:49:43 +02:00
fourindex_ext ( const int file , const fourindexsymtype s = undefined_symmetry , const I n = 0 , const unsigned int b = 1024 ) : current ( NULL ) , fd ( file ) , nread ( 0 ) , symmetry ( s ) , nn ( n )
{
struct statfs sfs ;
2006-04-25 16:54:42 +02:00
struct stat64 sf ;
if ( fstat64 ( fd , & sf ) ) { perror ( " cannot fstat " ) ; laerror ( " I/O error " ) ; }
2006-04-25 16:49:43 +02:00
if ( fstatfs ( fd , & sfs ) ) { perror ( " cannot fstatfs " ) ; laerror ( " I/O error " ) ; }
const unsigned int pagesize = getpagesize ( ) ;
//make bufsize*sizeof(matel4stored<I,T>) a multiple of fs block size and page size
bufsize = b * sizeof ( matel4stored < I , T > ) ;
bufsize = lcm0 ( bufsize , pagesize ) ;
bufsize = lcm0 ( bufsize , sfs . f_bsize ) ;
bufsize = lcm0 ( bufsize , sf . st_blksize ) ;
buffer0 = new matel4stored < I , T > [ ( bufsize + pagesize ) / sizeof ( matel4stored < I , T > ) + 1 ] ; //ensure alignment at page boundary
unsigned char * buf = ( unsigned char * ) buffer0 ;
buf = buf + pagesize - ( ( unsigned long ) buf % pagesize ) ;
buffer = ( matel4stored < I , T > * ) buf ;
mlock ( buf , bufsize ) ; //ignore error when not root, hope we will not be paged out anyway
bufsize / = sizeof ( matel4stored < I , T > ) ;
}
~ fourindex_ext ( ) { if ( buffer0 ) delete [ ] buffer0 ; }
2006-04-03 00:54:40 +02:00
void setsymmetry ( fourindexsymtype s ) { symmetry = s ; } ;
2006-04-06 05:45:50 +02:00
fourindexsymtype getsymmetry ( ) const { return symmetry ; }
2006-04-25 16:49:43 +02:00
void rewind ( ) const { if ( 0 ! = lseek64 ( fd , 0L , SEEK_SET ) ) { perror ( " seek error " ) ; laerror ( " cannot seek in fourindex_ext " ) ; } } ;
2006-04-03 00:54:40 +02:00
inline I size ( ) const { return nn ; }
2006-04-19 16:04:52 +02:00
2006-04-03 00:54:40 +02:00
//iterator and permute-iterator are both implemented as poiters to the original class, using private functions of this class
//this is possible, since one instance of this class can have only one active iterator at a time
//iterator
typedef class iterator {
private :
2006-04-06 05:45:50 +02:00
const fourindex_ext * base ;
2006-04-03 00:54:40 +02:00
public :
iterator ( ) { } ;
2006-04-06 05:45:50 +02:00
iterator ( const fourindex_ext * p ) : base ( p ) { } ;
2006-04-03 00:54:40 +02:00
~ iterator ( ) { } ;
bool operator ! = ( const iterator & rhs ) const { return base ! = rhs . base ; } //should only be used for comparison with end()
2006-04-03 04:01:45 +02:00
iterator & operator + + ( ) { if ( base ) base - > next ( ) ; if ( base - > eof ( ) ) base = NULL ; return * this ; }
2006-04-03 00:54:40 +02:00
iterator operator + + ( int ) { laerror ( " postincrement not possible " ) ; }
const matel4stored < I , T > * operator - > ( ) const { return base - > current ; }
const matel4stored < I , T > & operator * ( ) const { return * base - > current ; }
2006-04-03 04:53:22 +02:00
bool notNULL ( ) const { return base ; }
2006-04-03 00:54:40 +02:00
} ;
2006-04-06 05:45:50 +02:00
iterator begin ( ) const { rewind ( ) ; tryread ( ) ; if ( ! eof ( ) ) return this ; else return NULL ; }
2006-04-03 04:01:45 +02:00
iterator end ( ) const { return iterator ( NULL ) ; }
2006-04-03 00:54:40 +02:00
2006-04-25 16:49:43 +02:00
2006-04-03 04:53:22 +02:00
//piterator ... iterate over all allowed permutations; conveniently expressed via the basic iterator which does the block-buffering
typedef class piterator {
private :
fourindex_ext * base ;
matel4stored < I , T > my ;
int permindex ;
2006-07-29 21:46:41 +02:00
typename fourindex_ext : : iterator it ;
2006-04-03 04:53:22 +02:00
//private methods
void setup ( void ) //make a copy of *it to my with scaled element and anti/permuted indices
{
if ( base - > symmetry = = undefined_symmetry ) laerror ( " fourindex symmetry has not been set " ) ;
if ( ! it . notNULL ( ) ) { permindex = 0 ; memset ( & my , 0 , sizeof ( my ) ) ; return ; } //we rely that end() is NULL
for ( int i = 0 ; i < 4 ; + + i )
my . index . packed [ i ] = it - > index . packed [ fourindex_permutations [ base - > symmetry ] [ permindex ] [ i ] ] ;
my . elem = it - > elem * fourindex_permutations [ base - > symmetry ] [ permindex ] [ 4 ] ;
2006-04-03 21:56:20 +02:00
//redundancy due to possibly equal indices
2006-04-03 04:53:22 +02:00
//if the processing of individual term becomes very costly, an alternative would be to screen permutations yielding identical result
2006-04-03 21:56:20 +02:00
symmetry_faktor ( base - > symmetry , it - > index , my . elem ) ;
2006-04-03 04:53:22 +02:00
} ;
public :
piterator ( ) { } ;
piterator ( fourindex_ext * p ) : base ( p ) , permindex ( 0 ) { if ( p ) { it = p - > begin ( ) ; setup ( ) ; } } ;
piterator ( fourindex_ext & x ) : base ( & x ) , permindex ( 0 ) { it = x . begin ( ) ; setup ( ) ; } ;
~ piterator ( ) { } ;
bool operator ! = ( const piterator & rhs ) const { return base ! = rhs . base ; } //should only be used for comparison with end()
piterator & operator + + ( ) { if ( + + permindex > = fourindex_permnumbers [ base - > symmetry ] ) { permindex = 0 ; + + it ; } if ( it . notNULL ( ) ) setup ( ) ; else base = NULL ; return * this ; }
piterator operator + + ( int ) { laerror ( " postincrement not possible " ) ; }
const matel4stored < I , T > * operator - > ( ) const { return & my ; }
const matel4stored < I , T > & operator * ( ) const { return my ; }
bool end ( void ) { return ! base ; }
bool notend ( void ) { return base ; }
} ;
piterator pbegin ( ) { return piterator ( * this ) ; }
piterator pend ( ) const { return piterator ( NULL ) ; } //inefficient, use end() or notend() instead
2006-04-03 00:54:40 +02:00
} ;
2006-04-02 22:48:48 +02:00
/////////////////////////////implementations///////////////////////////////////
template < class I , class T >
2006-04-06 00:06:24 +02:00
unsigned long fourindex < I , T > : : put ( int fd , bool withattr ) const
2006-04-02 22:48:48 +02:00
{
unsigned long n = 0 ;
matel4 < I , T > * l = list ;
matel4stored < I , T > buf ;
2006-04-06 00:06:24 +02:00
if ( withattr )
{
union { fourindexsymtype sym ; I n ; T padding ; } u ;
u . sym = symmetry ;
if ( sizeof ( u ) ! = write ( fd , & u , sizeof ( u ) ) ) laerror ( " write error in fourindex::put " ) ;
u . n = nn ;
if ( sizeof ( u ) ! = write ( fd , & u , sizeof ( u ) ) ) laerror ( " write error in fourindex::put " ) ;
}
2006-04-02 22:48:48 +02:00
while ( l )
{
+ + n ;
buf . elem = l - > elem ;
2006-04-03 03:43:02 +02:00
buf . index = l - > index ;
if ( sizeof ( buf ) ! = write ( fd , & buf , sizeof ( buf ) ) ) laerror ( " write error in fourindex::put " ) ;
2006-04-02 22:48:48 +02:00
l = l - > next ;
}
return n ;
}
template < class I , class T >
2006-04-06 00:06:24 +02:00
unsigned long fourindex < I , T > : : get ( int fd , bool withattr )
2006-04-02 22:48:48 +02:00
{
unsigned long n = 0 ;
matel4stored < I , T > buf ;
2006-04-06 00:06:24 +02:00
if ( withattr )
{
union { fourindexsymtype sym ; I n ; T padding ; } u ;
if ( sizeof ( u ) ! = read ( fd , & u , sizeof ( u ) ) ) laerror ( " read inconsistency in fourindex::put " ) ;
symmetry = u . sym ;
if ( sizeof ( u ) ! = read ( fd , & u , sizeof ( u ) ) ) laerror ( " read inconsistency in fourindex::put " ) ;
nn = u . n ;
}
2006-04-03 03:43:02 +02:00
while ( sizeof ( buf ) = = read ( fd , & buf , sizeof ( buf ) ) ) { + + n ; add ( buf . index , buf . elem ) ; }
2006-04-02 22:48:48 +02:00
return n ;
}
2004-03-17 04:07:21 +01:00
//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 >
2006-04-02 22:48:48 +02:00
unsigned long fourindex < I , T > : : length ( ) const
2004-03-17 04:07:21 +01:00
{
2006-04-02 22:48:48 +02:00
unsigned long n = 0 ;
2004-03-17 04:07:21 +01:00
matel4 < I , T > * l = list ;
while ( l )
{
+ + n ;
l = l - > next ;
}
return n ;
}
2006-04-03 00:54:40 +02:00
template < class I , class T >
ostream & operator < < ( ostream & s , const fourindex_ext < I , T > & x )
{
int n ;
n = x . size ( ) ;
s < < n < < ' \n ' ;
2006-05-28 16:53:36 +02:00
typename fourindex_ext < I , T > : : iterator it = x . begin ( ) ;
2006-04-03 00:54:40 +02:00
while ( it ! = x . end ( ) )
{
2006-04-03 03:43:02 +02:00
s < < ( typename LA_traits_io < I > : : IOtype ) it - > index . indiv . i < < ' ' < < ( typename LA_traits_io < I > : : IOtype ) it - > index . indiv . j < < ' ' < < ( typename LA_traits_io < I > : : IOtype ) it - > index . indiv . k < < ' ' < < ( typename LA_traits_io < I > : : IOtype ) it - > index . indiv . l < < ' ' < < ( typename LA_traits_io < T > : : IOtype ) it - > elem < < ' \n ' ;
2006-04-03 00:54:40 +02:00
+ + it ;
}
s < < " -1 -1 -1 -1 \n " ;
return s ;
}
2004-03-17 04:07:21 +01:00
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
{
2006-04-03 03:43:02 +02:00
s < < ( typename LA_traits_io < I > : : IOtype ) it - > index . indiv . i < < ' ' < < ( typename LA_traits_io < I > : : IOtype ) it - > index . indiv . j < < ' ' < < ( typename LA_traits_io < I > : : IOtype ) it - > index . indiv . k < < ' ' < < ( typename LA_traits_io < I > : : IOtype ) it - > index . indiv . l < < ' ' < < ( typename LA_traits_io < T > : : IOtype ) it - > elem < < ' \n ' ;
2004-03-17 04:07:21 +01:00
+ + it ;
}
s < < " -1 -1 -1 -1 \n " ;
return s ;
}
template < class I , class T >
istream & operator > > ( istream & s , fourindex < I , T > & x )
{
2006-04-03 03:43:02 +02:00
typename LA_traits_io < I > : : IOtype i , j , k , l ;
2006-04-02 22:07:29 +02:00
typename LA_traits_io < T > : : IOtype elem ;
2004-03-17 04:07:21 +01:00
int n ;
s > > n ;
x . resize ( n ) ;
s > > i > > j > > k > > l ;
2006-04-03 03:43:02 +02:00
while ( i ! = ( typename LA_traits_io < I > : : IOtype ) - 1 & & j ! = ( typename LA_traits_io < I > : : IOtype ) - 1 & & k ! = ( typename LA_traits_io < I > : : IOtype ) - 1 & & l ! = ( typename LA_traits_io < I > : : IOtype ) - 1 )
2004-03-17 04:07:21 +01:00
{
s > > elem ;
2006-04-03 03:43:02 +02:00
x . add ( ( I ) i , ( I ) j , ( I ) k , ( I ) l , ( T ) elem ) ;
2005-09-11 22:04:24 +02:00
s > > i > > j > > k > > l ;
2004-03-17 04:07:21 +01:00
}
return s ;
}
2006-09-09 21:51:04 +02:00
2006-04-06 04:12:19 +02:00
/////////////////////densely stored fourindex///////////////////////////////////
//not all symmetry cases implemented yet, but a general template declaration used
//we use a general template forward declaration, but then it has to be done differently for (almost) each case
//by means of partial template specialization
2006-04-07 07:00:44 +02:00
//note - loops for the twoelectronrealmullikan integral to be unique and in canonical order
// i=1..n, j=1..i, k=1..i, l=1..(i==k?j:k)
2006-04-06 04:12:19 +02:00
template < fourindexsymtype S , class T , class DUMMY > class fourindex_dense ;
//make it as a derived class in order to be able to use it in a base class context - "supermatrix" operations
template < class T , class I >
class fourindex_dense < twoelectronrealmullikan , T , I > : public NRSMat < T > {
public :
fourindex_dense ( ) : NRSMat < T > ( ) { } ;
explicit fourindex_dense ( const int n ) : NRSMat < T > ( n * ( n + 1 ) / 2 ) { } ;
fourindex_dense ( const NRSMat < T > & rhs ) : NRSMat < T > ( rhs ) { } ; //be able to convert the parent class transparently to this
fourindex_dense ( const T & a , const int n ) : NRSMat < T > ( a , n * ( n + 1 ) / 2 ) { } ;
fourindex_dense ( const T * a , const int n ) : NRSMat < T > ( a , n * ( n + 1 ) / 2 ) { } ;
//and also construct it from sparse and externally stored fourindex classes
//it seems not possible to nest template<class I> just for the two constructors
fourindex_dense ( const fourindex < I , T > & rhs ) ;
fourindex_dense ( const fourindex_ext < I , T > & rhs ) ;
T & operator ( ) ( unsigned int i , unsigned int j , unsigned int k , unsigned int l ) ;
const T & operator ( ) ( unsigned int i , unsigned int j , unsigned int k , unsigned int l ) const ;
} ;
template < class T , class I >
2006-09-10 22:06:44 +02:00
fourindex_dense < twoelectronrealmullikan , T , I > : : fourindex_dense ( const fourindex < I , T > & rhs ) : NRSMat < T > ( ( T ) 0 , rhs . size ( ) * ( rhs . size ( ) + 1 ) / 2 )
2006-04-06 04:12:19 +02:00
{
2006-04-06 05:45:50 +02:00
if ( rhs . getsymmetry ( ) ! = twoelectronrealmullikan ) laerror ( " fourindex_dense symmetry mismatch " ) ;
2006-04-06 04:12:19 +02:00
typename fourindex < I , T > : : iterator p ;
2006-08-16 23:43:45 +02:00
# ifdef DEBUG
2006-09-09 21:51:04 +02:00
unsigned int IJ = SMat_index_1 ( p - > index . indiv . i , p - > index . indiv . j ) ;
unsigned int KL = SMat_index_1 ( p - > index . indiv . k , p - > index . indiv . l ) ;
if ( IJ < 0 | | IJ > = ( unsigned int ) NRSMat < T > : : nn | | KL < 0 | | KL > = ( unsigned int ) NRSMat < T > : : nn ) laerror ( " fourindex_dense index out of range in constructor " ) ;
2006-08-16 23:43:45 +02:00
# endif
2006-04-06 04:12:19 +02:00
for ( p = rhs . begin ( ) ; p ! = rhs . end ( ) ; + + p ) ( * this ) ( p - > index . indiv . i , p - > index . indiv . j , p - > index . indiv . k , p - > index . indiv . l ) = p - > elem ;
}
template < class T , class I >
2006-09-10 22:06:44 +02:00
fourindex_dense < twoelectronrealmullikan , T , I > : : fourindex_dense ( const fourindex_ext < I , T > & rhs ) : NRSMat < T > ( ( T ) 0 , rhs . size ( ) * ( rhs . size ( ) + 1 ) / 2 )
2006-04-06 04:12:19 +02:00
{
2006-04-06 05:45:50 +02:00
if ( rhs . getsymmetry ( ) ! = twoelectronrealmullikan ) laerror ( " fourindex_dense symmetry mismatch " ) ;
2006-04-06 04:12:19 +02:00
typename fourindex_ext < I , T > : : iterator p ;
2006-09-11 18:00:39 +02:00
for ( p = rhs . begin ( ) ; p ! = rhs . end ( ) ; + + p )
{
2006-08-16 23:43:45 +02:00
# ifdef DEBUG
2006-09-09 21:51:04 +02:00
unsigned int IJ = SMat_index_1 ( p - > index . indiv . i , p - > index . indiv . j ) ;
unsigned int KL = SMat_index_1 ( p - > index . indiv . k , p - > index . indiv . l ) ;
if ( IJ < 0 | | IJ > = ( unsigned int ) NRSMat < T > : : nn | | KL < 0 | | KL > = ( unsigned int ) NRSMat < T > : : nn ) laerror ( " fourindex_dense index out of range in constructor " ) ;
2006-08-16 23:43:45 +02:00
# endif
2006-09-11 18:00:39 +02:00
( * this ) ( p - > index . indiv . i , p - > index . indiv . j , p - > index . indiv . k , p - > index . indiv . l ) = p - > elem ;
}
2006-04-06 04:12:19 +02:00
}
template < class T , class DUMMY >
T & fourindex_dense < twoelectronrealmullikan , T , DUMMY > : : operator ( ) ( unsigned int i , unsigned int j , unsigned int k , unsigned int l )
{
2006-09-09 21:51:04 +02:00
unsigned int I = SMat_index_1 ( i , j ) ;
unsigned int J = SMat_index_1 ( k , l ) ;
2006-04-06 04:12:19 +02:00
//I,J act as indices of a NRSmat
# ifdef DEBUG
2006-07-29 22:07:02 +02:00
if ( * NRSMat < T > : : count ! = 1 ) laerror ( " lval (i,j,k,l) with count > 1 in fourindex_dense " ) ;
2006-09-09 21:51:04 +02:00
if ( I < 0 | | I > = ( unsigned int ) NRSMat < T > : : nn | | J < 0 | | J > = ( unsigned int ) NRSMat < T > : : nn ) laerror ( " fourindex_dense index out of range " ) ;
2006-07-29 21:46:41 +02:00
if ( ! NRSMat < T > : : v ) laerror ( " access to unallocated fourindex_dense " ) ;
2006-04-06 04:12:19 +02:00
# endif
2006-07-29 21:46:41 +02:00
return NRSMat < T > : : v [ SMat_index ( I , J ) ] ;
2006-04-06 04:12:19 +02:00
}
2006-07-29 22:07:02 +02:00
2006-04-06 04:12:19 +02:00
template < class T , class DUMMY >
const T & fourindex_dense < twoelectronrealmullikan , T , DUMMY > : : operator ( ) ( unsigned int i , unsigned int j , unsigned int k , unsigned int l ) const
{
2006-09-09 21:51:04 +02:00
unsigned int I = SMat_index_1 ( i , j ) ;
unsigned int J = SMat_index_1 ( k , l ) ;
2006-04-06 04:12:19 +02:00
//I,J act as indices of a NRSmat
# ifdef DEBUG
2006-09-09 21:51:04 +02:00
if ( I < 0 | | I > = ( unsigned int ) NRSMat < T > : : nn | | J < 0 | | J > = ( unsigned int ) NRSMat < T > : : nn ) laerror ( " fourindex_dense index out of range " ) ;
2006-07-29 21:46:41 +02:00
if ( ! NRSMat < T > : : v ) laerror ( " access to unallocated fourindex_dense " ) ;
2006-04-06 04:12:19 +02:00
# endif
2006-07-29 21:46:41 +02:00
return NRSMat < T > : : v [ SMat_index ( I , J ) ] ;
2006-04-06 04:12:19 +02:00
}
2006-09-09 21:51:04 +02:00
//access to spin-blocks of T2 amplitudes in aces storage order
//both occupied and virtual indices start from 1
template < class T , class I >
class fourindex_dense < T2IjAb_aces , T , I > : public NRMat < T > {
private :
unsigned int noca , nocb , nvra , nvrb ;
public :
fourindex_dense ( ) : NRMat < T > ( ) { noca = nocb = nvra = nvrb = 0 ; } ;
explicit fourindex_dense ( const int nocca , const int noccb , const int nvrta , const int nvrtb ) : NRMat < T > ( nocca * noccb , nvrta * nvrtb ) { noca = nocca ; nocb = noccb ; nvra = nvrta ; nvrb = nvrtb ; } ;
//here i,a are alpha j,b beta
inline T & operator ( ) ( unsigned int i , unsigned int j , unsigned int a , unsigned int b )
{
# ifdef DEBUG
2006-09-11 17:56:49 +02:00
if ( i < 1 | | i > noca | | j < 1 | | j > nocb | | a < 1 | | a > nvra | | b < 1 | | b > nvrb ) laerror ( " T2IjAb_aces fourindex out of range " ) ;
2006-09-09 21:51:04 +02:00
if ( ! NRMat < T > : : v ) laerror ( " access to unallocated fourindex_dense " ) ;
# endif
return ( * this ) . NRMat < T > : : operator ( ) ( ( j - 1 ) * noca + i - 1 , ( b - 1 ) * nvra + a - 1 ) ;
}
inline const T & operator ( ) ( unsigned int i , unsigned int j , unsigned int a , unsigned int b ) const
{
# ifdef DEBUG
2006-09-11 17:56:49 +02:00
if ( i < 1 | | i > noca | | j < 1 | | j > nocb | | a < 1 | | a > nvra | | b < 1 | | b > nvrb ) laerror ( " T2IjAb_aces fourindex out of range " ) ;
2006-09-09 21:51:04 +02:00
if ( ! NRMat < T > : : v ) laerror ( " access to unallocated fourindex_dense " ) ;
# endif
return ( * this ) . NRMat < T > : : operator ( ) ( ( j - 1 ) * noca + i - 1 , ( b - 1 ) * nvra + a - 1 ) ;
}
} ;
template < class T , class I >
class fourindex_dense < T2ijab_aces , T , I > : public NRMat < T > {
private :
unsigned int nocc , nvrt , ntri ;
public :
fourindex_dense ( ) : NRMat < T > ( ) { nocc = nvrt = ntri = 0 ; } ;
explicit fourindex_dense ( const int noc , const int nvr ) : NRMat < T > ( noc * ( noc - 1 ) / 2 , nvr * ( nvr - 1 ) / 2 ) { nocc = noc ; nvrt = nvr ; ntri = nvr * ( nvr - 1 ) / 2 ; } ;
//we cannot return reference due to the possible sign change
//stored values are for i>j a>b
2006-09-11 17:49:34 +02:00
inline T operator ( ) ( unsigned int i , unsigned int j , unsigned int a , unsigned int b ) const
2006-09-09 21:51:04 +02:00
{
# ifdef DEBUG
2006-09-11 17:56:49 +02:00
if ( i < 1 | | i > nocc | | j < 1 | | j > nocc | | a < 1 | | a > nvrt | | b < 1 | | b > nvrt ) laerror ( " T2ijab_aces fourindex out of range " ) ;
2006-09-09 21:51:04 +02:00
if ( ! NRMat < T > : : v ) laerror ( " access to unallocated fourindex_dense " ) ;
# endif
int minus = 0 ;
if ( i < j ) { minus + + ; unsigned int t = i ; i = j ; j = t ; }
if ( a < b ) { minus + + ; unsigned int t = a ; a = b ; b = t ; }
T val = ( * this ) . NRMat < T > : : operator ( ) ( ( i - 2 ) * ( i - 1 ) / 2 + j - 1 , ( a - 2 ) * ( a - 1 ) / 2 + b - 1 ) ;
return ( minus & 1 ) ? - val : val ;
}
} ;
2006-04-06 04:12:19 +02:00
2004-03-17 04:07:21 +01:00
# endif /*_fourindex_included*/