1463 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1463 lines
		
	
	
		
			57 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
    LA: linear algebra C++ interface library
 | 
						|
    Copyright (C) 2008-2019 Jiri Pittner <jiri.pittner@jh-inst.cas.cz> or <jiri@pittnerovi.com>
 | 
						|
 | 
						|
    This program is free software: you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU General Public License as published by
 | 
						|
    the Free Software Foundation, either version 3 of the License, or
 | 
						|
    (at your option) any later version.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU General Public License
 | 
						|
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
*/
 | 
						|
 | 
						|
#ifndef _fourindex_included
 | 
						|
#define _fourindex_included
 | 
						|
#include <iostream>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/vfs.h>
 | 
						|
#include <sys/mman.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include "laerror.h"
 | 
						|
#include "vec.h"
 | 
						|
#include "smat.h"
 | 
						|
#include "mat.h"
 | 
						|
#include "nonclass.h"
 | 
						|
 | 
						|
namespace LA {
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static inline unsigned int lcm0(unsigned int i,unsigned int j)
 | 
						|
{
 | 
						|
return (i/hcd0(i,j)*j);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//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
 | 
						|
//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
 | 
						|
 | 
						|
//when patient enough, make const_casts for piterators to have pbegin() const
 | 
						|
 | 
						|
template<class I>
 | 
						|
  struct indiv_index {
 | 
						|
                        I i;
 | 
						|
                        I j;
 | 
						|
                        I k;
 | 
						|
                        I l;
 | 
						|
                        }
 | 
						|
#ifdef __GNUC__
 | 
						|
__attribute__((packed))
 | 
						|
#endif
 | 
						|
;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
template<class I>
 | 
						|
union packed_index {
 | 
						|
                I packed[4];
 | 
						|
                struct  indiv_index<I> indiv;
 | 
						|
                }
 | 
						|
#ifdef __GNUC__
 | 
						|
__attribute__((packed))
 | 
						|
#endif
 | 
						|
;
 | 
						|
 | 
						|
template<class I, class T>
 | 
						|
struct matel4
 | 
						|
        {
 | 
						|
        T elem;
 | 
						|
        matel4 *next;
 | 
						|
	union packed_index<I> index;
 | 
						|
        };
 | 
						|
//should not be packed
 | 
						|
 | 
						|
 | 
						|
template<class I, class T>
 | 
						|
struct matel4stored 
 | 
						|
        {
 | 
						|
        T elem;
 | 
						|
        union packed_index<I> index;
 | 
						|
        }
 | 
						|
#ifdef __GNUC__
 | 
						|
__attribute__((packed))
 | 
						|
#endif
 | 
						|
;
 | 
						|
 | 
						|
 | 
						|
//later add symmetry of complex integrals
 | 
						|
typedef enum {
 | 
						|
	undefined_symmetry=-1,
 | 
						|
	nosymmetry=0, 
 | 
						|
	twoelectronrealmullikan=1, twoelectronrealmullikanAA=1,
 | 
						|
	twoelectronrealdirac=2, 
 | 
						|
	T2ijab_aces=3, 
 | 
						|
	trdm2AA=3, 
 | 
						|
	antisymtwoelectronrealdirac=4, rdm2AA=4, 
 | 
						|
	T2IjAb_aces=5, trdm2AB=5, 
 | 
						|
	twoelectronrealmullikanAB=6, 
 | 
						|
	T2ijab_unitary=7, 
 | 
						|
	T2IjAb_unitary=8, 
 | 
						|
	antisymtwoelectronrealdiracAB=9,rdm2AB=9,twoelectroncomplexmullikan_without_conjugation=9,
 | 
						|
	twoelectronrealmullikanreducedsymAA=10,
 | 
						|
	twoelectronrealmullikanreducedsymAB=11,
 | 
						|
	twoelectroncomplexmullikan=12,
 | 
						|
} 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=13;
 | 
						|
static const int fourindex_permnumbers[fourindex_n_symmetrytypes]={1,8,8,4,8,1,4,8,2,2,4,2,4};
 | 
						|
static const int max_fourindex_permnumbers=8;
 | 
						|
static const int fourindex_permutations[fourindex_n_symmetrytypes][max_fourindex_permnumbers+1][5]=
 | 
						|
		{
 | 
						|
		{{0,1,2,3,1}}, //nosymmetry
 | 
						|
		{{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}}, //twoelectronrealmullikan
 | 
						|
		{{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}}, //twoelectronrealdirac
 | 
						|
		{{0,1,2,3,1},{1,0,2,3,-1},{0,1,3,2,-1},{1,0,3,2,1}}, //T2ijab_aces
 | 
						|
		{{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}}, //antisymtwoelectronrealdirac
 | 
						|
		{{0,1,2,3,1}}, //T2IjAb_aces is like nosymmetry but different index ranges
 | 
						|
		{{0,1,2,3,1},{1,0,2,3,1},{0,1,3,2,1},{1,0,3,2,1}}, //twoelectronrealmullikanAB
 | 
						|
		{{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}}, //T2ijab_unitary (antiherm exponent)
 | 
						|
		{{0,1,2,3,1},{2,3,0,1,-1}}, //T2IjAb_unitary (antihermitian exponent)
 | 
						|
		{{0,1,2,3,1},{2,3,0,1,1}}, //antisymtwoelectronrealdiracAB
 | 
						|
		{{0,1,2,3,1},{2,3,0,1,1},{1,0,3,2,1},{3,2,1,0,1}}, //twoelectronrealmullikanreducedsymAA (e.g. unitary downfolded CC eff. integrals)
 | 
						|
		{{0,1,2,3,1},{1,0,3,2,1}}, //twoelectronrealmullikanreducedsymAB (e.g. unitary downfolded CC eff. integrals)
 | 
						|
		{{0,1,2,3,1},{2,3,0,1,1},{1,0,3,2,2},{3,2,1,0,2}}, //twoelectroncomplexmullikan ... 2 means complex conjugation
 | 
						|
		};
 | 
						|
 | 
						|
 | 
						|
template <class I, class T>
 | 
						|
void symmetry_faktor(const fourindexsymtype symmetry,const union packed_index<I> &index, T &elem)
 | 
						|
{
 | 
						|
switch(symmetry)
 | 
						|
	{
 | 
						|
	case twoelectronrealmullikanreducedsymAA:
 | 
						|
		if(index.indiv.i==index.indiv.j && index.indiv.k==index.indiv.l) elem*=.5;
 | 
						|
		if(index.indiv.i==index.indiv.k && index.indiv.j==index.indiv.l) elem*=.5;
 | 
						|
		break;
 | 
						|
	case twoelectronrealmullikanreducedsymAB:
 | 
						|
		if(index.indiv.i==index.indiv.j && index.indiv.k==index.indiv.l) elem*=.5;
 | 
						|
		break;
 | 
						|
	case antisymtwoelectronrealdirac: 
 | 
						|
	case antisymtwoelectronrealdiracAB: 
 | 
						|
		laerror("not implemented");
 | 
						|
	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 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;
 | 
						|
	case T2ijab_aces: break; //result will automatically vanish due to generated antisymmetry; i!=a from principle
 | 
						|
	case T2IjAb_aces: break; //no actual symmetry
 | 
						|
	case nosymmetry: break;
 | 
						|
	default: laerror("illegal symmetry or symmetry-redundant scaling factor not implemented");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template <class I, class T>
 | 
						|
class fourindex {
 | 
						|
protected:
 | 
						|
	fourindexsymtype symmetry;
 | 
						|
	I nn;
 | 
						|
        int *count;
 | 
						|
	matel4<I,T> *list;
 | 
						|
	I terminator;
 | 
						|
	bool doscaling;
 | 
						|
private:
 | 
						|
	void deletelist();
 | 
						|
	void copylist(const matel4<I,T> *l);
 | 
						|
public:
 | 
						|
	//iterator
 | 
						|
	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;}
 | 
						|
	};
 | 
						|
	void setterminator(const I terminator0) {terminator=terminator0;}
 | 
						|
	I getterminator() const {return terminator;}
 | 
						|
	void setscaling(const bool doscaling0) {doscaling=doscaling0;}
 | 
						|
	iterator begin() const {return list;}
 | 
						|
	iterator end() const {return NULL;}
 | 
						|
        
 | 
						|
        //permiterator ... iterates also over all permutations, with a possibly scaled matrix element for redundant results of the permutations
 | 
						|
        //it is assumed the original fourindex is the symmetry-reduced petite list, then the results of piterator contributions can be accumulated
 | 
						|
        //has to take into account the symmetry type of the fourindex
 | 
						|
        class piterator {
 | 
						|
	private:
 | 
						|
		fourindexsymtype symmetry;
 | 
						|
		matel4<I,T> *p;
 | 
						|
		matel4<I,T> my;
 | 
						|
		int permindex;
 | 
						|
		bool doscaling;
 | 
						|
		void setup(void) //make a copy of *p to my with scaled element and anti/permuted indices
 | 
						|
			{
 | 
						|
			if(symmetry==undefined_symmetry) laerror("fourindex symmetry has not been set");
 | 
						|
			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 due to possibly equal indices by a scaling factor
 | 
						|
			//if the processing of individual term becomes very costly, an alternative would be to screen permutations yielding identical result
 | 
						|
			if(doscaling) symmetry_faktor(symmetry, p->index, my.elem);
 | 
						|
			};
 | 
						|
        public:
 | 
						|
                piterator() {};
 | 
						|
		piterator(matel4<I,T> *pp): symmetry(nosymmetry),p(pp),permindex(0),doscaling(true){};
 | 
						|
                ~piterator() {};
 | 
						|
		piterator(const fourindex &x): symmetry(x.symmetry),p(x.list),permindex(0),doscaling(x.doscaling) {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"); return *this;}
 | 
						|
                bool operator!=(const piterator &rhs) const {return p!=rhs.p;} //should only be used for comparison with pend()
 | 
						|
		bool end(void) {return !p;}
 | 
						|
		bool notend(void) {return p;}
 | 
						|
        };
 | 
						|
        piterator pbegin() const {return piterator(*this);}
 | 
						|
        piterator pend() const {return piterator(NULL);}//inefficient, use end() or notend() instead
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//qiterator ... iterate over all allowed permutations, discared repeated indices (do not scale); conveniently expressed via the basic iterator 
 | 
						|
//		could be simplified using the pointer directly as piterator above if more efficiency is ever needed
 | 
						|
        class qiterator {
 | 
						|
        private:
 | 
						|
                fourindex *base;
 | 
						|
		matel4<I,T> my;
 | 
						|
		int permindex;
 | 
						|
		int uniqueindex;
 | 
						|
		typename fourindex::iterator it;
 | 
						|
		union packed_index<I> indices[max_fourindex_permnumbers];
 | 
						|
 | 
						|
		//private methods
 | 
						|
                bool setup(void) //make a copy of *it to my with anti/permuted indices; returns if element is valid (nonequivalent to previous) 
 | 
						|
                        {
 | 
						|
                        if(base->symmetry==undefined_symmetry) laerror("fourindex symmetry has not been set");
 | 
						|
                        if(it==NULL) {uniqueindex=permindex=0; memset(&my,0,sizeof(my)); return false;} //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]; //antisymmetry
 | 
						|
 | 
						|
			//store in a table of generated  and check redundancy
 | 
						|
			if(permindex==0) 
 | 
						|
				{
 | 
						|
				uniqueindex=0;
 | 
						|
				memcpy(&indices[0],&my.index,sizeof(union packed_index<I>));
 | 
						|
				return true;
 | 
						|
				}
 | 
						|
			//check redundancy
 | 
						|
			for(int i=0; i<=uniqueindex; ++i) if(!memcmp(&indices[i],&my.index,sizeof(union packed_index<I>))) return false;
 | 
						|
			//store unique
 | 
						|
			memcpy(&indices[++uniqueindex],&my.index,sizeof(union packed_index<I>));
 | 
						|
			return true;
 | 
						|
                        };
 | 
						|
        public:
 | 
						|
		qiterator() {};
 | 
						|
                qiterator(fourindex *p): base(p),permindex(0),uniqueindex(0) {if(p) {it=p->begin(); setup();}};
 | 
						|
		qiterator(fourindex &x): base(&x),permindex(0),uniqueindex(0) {it= x.begin(); setup();};
 | 
						|
                ~qiterator() {};
 | 
						|
                bool operator!=(const qiterator &rhs) const {return base!=rhs.base;} //should only be used for comparison with end()
 | 
						|
                qiterator &operator++() 
 | 
						|
			{
 | 
						|
			bool valid;
 | 
						|
			do 
 | 
						|
				{
 | 
						|
				valid=true;
 | 
						|
				++permindex;
 | 
						|
				if(permindex>=fourindex_permnumbers[base->symmetry]) {uniqueindex=permindex=0; ++it;} 
 | 
						|
				if(it!=NULL) 
 | 
						|
					valid=setup(); 
 | 
						|
				else 
 | 
						|
					{
 | 
						|
					base=NULL; 
 | 
						|
					break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			while(!valid);
 | 
						|
			return *this;
 | 
						|
			} 
 | 
						|
		qiterator operator++(int) {laerror("postincrement not possible"); return *this;}
 | 
						|
                const matel4<I,T> * operator->() const {return &my;}
 | 
						|
                const matel4<I,T> & operator*() const {return my;}
 | 
						|
		bool end(void) {return !base;}
 | 
						|
                bool notend(void) {return base;}
 | 
						|
	};
 | 
						|
	qiterator qbegin() {return qiterator(*this);}
 | 
						|
	qiterator qend() const {return qiterator(NULL);} //inefficient, use end() or notend() instead
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
	//constructors etc.
 | 
						|
	inline fourindex() :symmetry(undefined_symmetry),nn(0),count(NULL),list(NULL),terminator(-1),doscaling(true) {};
 | 
						|
	inline fourindex(const I n, const fourindexsymtype symmetry0=undefined_symmetry, const I terminator0= -1, const bool doscaling0=true) :nn(n),count(new int(1)),list(NULL),symmetry(symmetry0),terminator(terminator0),doscaling(doscaling0) {};
 | 
						|
	fourindex(const fourindex &rhs); //copy constructor
 | 
						|
	inline int getcount() const {return count?*count:0;}
 | 
						|
	fourindex & operator=(const fourindex &rhs);
 | 
						|
        fourindex & operator+=(const fourindex &rhs);
 | 
						|
	void setsymmetry(fourindexsymtype s) {symmetry=s;}
 | 
						|
	fourindexsymtype getsymmetry() const {return symmetry;}
 | 
						|
        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 dealloc(void) {resize(0);}
 | 
						|
	void copyonwrite();
 | 
						|
	unsigned long 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 union packed_index<I> &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(union packed_index<I>)); list->elem=elem;}
 | 
						|
	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;}
 | 
						|
	unsigned long put(int fd,bool withattr=true) const;
 | 
						|
	unsigned long get(int fd,bool withattr=true);
 | 
						|
	void fscanf(FILE *f); //C-style formatted IO
 | 
						|
	void fprintf(FILE *f, char *format) const;
 | 
						|
	void permuteme(const NRPerm<int> &p, const bool inverse=false)// index permutation
 | 
						|
		{
 | 
						|
		if(p.size()!=nn)  laerror("inconsistent dimension in fourindex::permuteme");
 | 
						|
		copyonwrite();
 | 
						|
		matel4<I,T> *l=list;
 | 
						|
		NRPerm<int> pp; if(inverse) pp=p.inverse(); else pp=p;
 | 
						|
		while(l)
 | 
						|
        		{
 | 
						|
        		l->index.indiv.i = (I) pp[(int)l->index.indiv.i];
 | 
						|
        		l->index.indiv.j = (I) pp[(int)l->index.indiv.j];
 | 
						|
        		l->index.indiv.k = (I) pp[(int)l->index.indiv.k];
 | 
						|
        		l->index.indiv.l = (I) pp[(int)l->index.indiv.l];
 | 
						|
        		l=l->next;
 | 
						|
        		}
 | 
						|
		}
 | 
						|
	void swap(fourindex &rhs) //more efficient swap than via tmp and constructors and operator=
 | 
						|
		{
 | 
						|
		I tmpnn=nn; nn=rhs.nn; rhs.nn=tmpnn;
 | 
						|
		I tmpterminator=terminator; terminator=rhs.terminator; rhs.terminator=tmpterminator;
 | 
						|
		int *tmpcount=count; count=rhs.count; rhs.count=tmpcount;
 | 
						|
		matel4<I,T> *tmplist=list; list=rhs.list; rhs.list=tmplist;
 | 
						|
		bool tmpdoscaling=doscaling; doscaling=rhs.doscaling; rhs.doscaling=tmpdoscaling;
 | 
						|
		fourindexsymtype tmpsymmetry=symmetry; symmetry=rhs.symmetry; rhs.symmetry=tmpsymmetry;
 | 
						|
		}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
//and a class for accessing a disc-stored fourindex, taking care of permutational index symmetry
 | 
						|
//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!!!
 | 
						|
//it used to work on older 2.6 kernels, but now does not work again since there is restriction to 512-byte alignment
 | 
						|
 | 
						|
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:
 | 
						|
	matel4stored<I,T> *buffer0;
 | 
						|
	matel4stored<I,T> *buffer;
 | 
						|
	matel4stored<I,T> *current;
 | 
						|
	int fd;
 | 
						|
	unsigned int bufsize;
 | 
						|
	unsigned int nread;
 | 
						|
        fourindexsymtype symmetry;
 | 
						|
	I nn;
 | 
						|
	bool doscaling;
 | 
						|
	I terminator;
 | 
						|
 | 
						|
	//methods
 | 
						|
	void tryread() const
 | 
						|
		{
 | 
						|
		const_cast<fourindex_ext<I,T> *>(this)->current=NULL;
 | 
						|
		errno=0;
 | 
						|
		//printf("read %d %llx %d\n",fd,buffer,bufsize*sizeof(matel4stored<I,T>));
 | 
						|
		ssize_t r=read(fd,buffer,bufsize*sizeof(matel4stored<I,T>));
 | 
						|
		if(r<0) {perror("read error"); laerror("read error in fourindex_ext (might be bug of O_DIRECT)");}
 | 
						|
		if(r%sizeof(matel4stored<I,T>)) laerror("read inconsistency in fourindex_ext");
 | 
						|
		const_cast<fourindex_ext<I,T> *>(this)->nread = r/sizeof(matel4stored<I,T>);
 | 
						|
		if(nread) const_cast<fourindex_ext<I,T> *>(this)->current=buffer;
 | 
						|
		}
 | 
						|
	void next() const { 
 | 
						|
			   if(current)
 | 
						|
				{
 | 
						|
			 	if( (unsigned int) (++ const_cast<fourindex_ext<I,T> *>(this)->current - buffer) >=nread) tryread(); 
 | 
						|
				}
 | 
						|
			  }
 | 
						|
	bool eof() const {return !current;};
 | 
						|
 | 
						|
 | 
						|
public:
 | 
						|
        void setterminator(const I terminator0) {terminator=terminator0;}
 | 
						|
	I getterminator() const {return terminator;}
 | 
						|
       	void setscaling(const bool doscaling0) {doscaling=doscaling0;}
 | 
						|
	void resize(I n) {nn=n;}
 | 
						|
        fourindex_ext(const int file, const fourindexsymtype s=undefined_symmetry, const I n=0, const unsigned int b=1024, const I terminator0= -1, const bool doscaling0= true) :current(NULL),fd(file),nread(0),symmetry(s),nn(n) 
 | 
						|
		{
 | 
						|
		struct statfs sfs;
 | 
						|
		struct stat64 sf;
 | 
						|
		if(fstat64(fd,&sf)) {perror("cannot fstat");laerror("I/O error");}
 | 
						|
		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 - ((uint64_t)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>);
 | 
						|
		terminator=terminator0;
 | 
						|
		doscaling=doscaling0;
 | 
						|
		}
 | 
						|
	~fourindex_ext() {if(buffer0) delete[] buffer0;}
 | 
						|
	void setsymmetry(fourindexsymtype s) {symmetry=s;};
 | 
						|
	fourindexsymtype getsymmetry() const {return symmetry;}
 | 
						|
	void rewind() const {if(0!=lseek64(fd,0L,SEEK_SET)) {perror("seek error"); laerror("cannot seek in fourindex_ext");} };
 | 
						|
 | 
						|
	//file output
 | 
						|
	void put(const matel4stored<I,T> x)
 | 
						|
		{
 | 
						|
		if(!current) current=buffer;
 | 
						|
		*current++ = x;
 | 
						|
		if(current-buffer >= bufsize ) flush();
 | 
						|
		}
 | 
						|
	void put(I i, I j, I k, I l, const T &elem)
 | 
						|
		{
 | 
						|
		if(!current) current=buffer;
 | 
						|
		current->index.indiv.i=i;
 | 
						|
		current->index.indiv.j=j;
 | 
						|
		current->index.indiv.k=k;
 | 
						|
		current->index.indiv.l=l;
 | 
						|
		current->elem = elem;
 | 
						|
		++current;
 | 
						|
		if(current-buffer >= bufsize ) flush();
 | 
						|
		}
 | 
						|
	void flush()
 | 
						|
		{
 | 
						|
		if(current)
 | 
						|
			{
 | 
						|
			ssize_t r=write(fd,buffer,(current-buffer)*sizeof(matel4stored<I,T>));
 | 
						|
			if(r!=(current-buffer)*sizeof(matel4stored<I,T>)) laerror("write error in fourindex_ext");
 | 
						|
			}
 | 
						|
		current=NULL;
 | 
						|
		}
 | 
						|
 | 
						|
	inline I size() const {return nn;}
 | 
						|
	
 | 
						|
 | 
						|
//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
 | 
						|
        class iterator {
 | 
						|
        private:
 | 
						|
                const fourindex_ext *base; 
 | 
						|
        public:
 | 
						|
		iterator() {};
 | 
						|
                iterator(const fourindex_ext *p): base(p) {};
 | 
						|
                ~iterator() {};
 | 
						|
                bool operator!=(const iterator &rhs) const {return base!=rhs.base;} //should only be used for comparison with end()
 | 
						|
                iterator &operator++() {if(base) base->next(); if(base->eof()) base=NULL; return *this;} 
 | 
						|
		iterator operator++(int) {laerror("postincrement not possible"); return *this;}
 | 
						|
                const matel4stored<I,T> * operator->() const {return base->current;}
 | 
						|
                const matel4stored<I,T> & operator*() const {return *base->current;}
 | 
						|
		bool notNULL() const {return base;}
 | 
						|
        };
 | 
						|
        iterator begin() const {rewind(); tryread(); if(!eof()) return this; else return NULL;}
 | 
						|
        iterator end() const {return iterator(NULL);}
 | 
						|
 | 
						|
 | 
						|
//piterator ... iterate over all allowed permutations, scale in case of repeated indices; conveniently expressed via the basic iterator which does the block-buffering
 | 
						|
        class piterator {
 | 
						|
        private:
 | 
						|
                fourindex_ext *base;
 | 
						|
		matel4<I,T> my;
 | 
						|
		int permindex;
 | 
						|
		typename fourindex_ext::iterator it;
 | 
						|
 | 
						|
		//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];
 | 
						|
                        //redundancy due to possibly equal indices
 | 
						|
                        //if the processing of individual term becomes very costly, an alternative would be to screen permutations yielding identical result
 | 
						|
			if(base->doscaling) symmetry_faktor(base->symmetry, it->index, my.elem);
 | 
						|
                        };
 | 
						|
        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"); return *this;}
 | 
						|
                const matel4<I,T> * operator->() const {return &my;}
 | 
						|
                const matel4<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
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//qiterator ... iterate over all allowed permutations, discared repeated indices (do not scale); conveniently expressed via the basic iterator which does the block-buffering
 | 
						|
        class qiterator {
 | 
						|
        private:
 | 
						|
                fourindex_ext *base;
 | 
						|
		matel4<I,T> my;
 | 
						|
		int permindex;
 | 
						|
		int uniqueindex;
 | 
						|
		typename fourindex_ext::iterator it;
 | 
						|
		union packed_index<I> indices[max_fourindex_permnumbers];
 | 
						|
 | 
						|
		//private methods
 | 
						|
                bool setup(void) //make a copy of *it to my with anti/permuted indices; returns if element is valid (nonequivalent to previous) 
 | 
						|
                        {
 | 
						|
                        if(base->symmetry==undefined_symmetry) laerror("fourindex symmetry has not been set");
 | 
						|
                        if(!it.notNULL()) {uniqueindex=permindex=0; memset(&my,0,sizeof(my)); return false;} //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]; //antisymmetry
 | 
						|
 | 
						|
			//store in a table of generated  and check redundancy
 | 
						|
			if(permindex==0) 
 | 
						|
				{
 | 
						|
				uniqueindex=0;
 | 
						|
				memcpy(&indices[0],&my.index,sizeof(union packed_index<I>));
 | 
						|
				return true;
 | 
						|
				}
 | 
						|
			//check redundancy
 | 
						|
			for(int i=0; i<=uniqueindex; ++i) if(!memcmp(&indices[i],&my.index,sizeof(union packed_index<I>))) return false;
 | 
						|
			//store unique
 | 
						|
			memcpy(&indices[++uniqueindex],&my.index,sizeof(union packed_index<I>));
 | 
						|
			return true;
 | 
						|
                        };
 | 
						|
        public:
 | 
						|
		qiterator() {};
 | 
						|
                qiterator(fourindex_ext *p): base(p),permindex(0),uniqueindex(0) {if(p) {it=p->begin(); setup();}};
 | 
						|
		qiterator(fourindex_ext &x): base(&x),permindex(0),uniqueindex(0) {it= x.begin(); setup();};
 | 
						|
                ~qiterator() {};
 | 
						|
                bool operator!=(const qiterator &rhs) const {return base!=rhs.base;} //should only be used for comparison with end()
 | 
						|
                qiterator &operator++() 
 | 
						|
			{
 | 
						|
			bool valid;
 | 
						|
			do 
 | 
						|
				{
 | 
						|
				valid=true;
 | 
						|
				++permindex;
 | 
						|
				if(permindex>=fourindex_permnumbers[base->symmetry]) {uniqueindex=permindex=0; ++it;} 
 | 
						|
				if(it.notNULL()) 
 | 
						|
					valid=setup(); 
 | 
						|
				else 
 | 
						|
					{
 | 
						|
					base=NULL; 
 | 
						|
					break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			while(!valid);
 | 
						|
			return *this;
 | 
						|
			} 
 | 
						|
		qiterator operator++(int) {laerror("postincrement not possible"); return *this;}
 | 
						|
                const matel4<I,T> * operator->() const {return &my;}
 | 
						|
                const matel4<I,T> & operator*() const {return my;}
 | 
						|
		bool end(void) {return !base;}
 | 
						|
                bool notend(void) {return base;}
 | 
						|
	};
 | 
						|
	qiterator qbegin() {return qiterator(*this);}
 | 
						|
	qiterator qend() const {return qiterator(NULL);} //inefficient, use end() or notend() instead
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
}; //end of fourindex_ext
 | 
						|
 | 
						|
/////////////////////////////implementations///////////////////////////////////
 | 
						|
 | 
						|
template <class I,class T>
 | 
						|
unsigned long fourindex<I,T>::put(int fd, bool withattr) const
 | 
						|
{
 | 
						|
unsigned long n=0;
 | 
						|
matel4<I,T> *l=list;
 | 
						|
matel4stored<I,T> buf;
 | 
						|
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");
 | 
						|
        }
 | 
						|
while(l)
 | 
						|
	{
 | 
						|
	++n;
 | 
						|
	buf.elem= l->elem;
 | 
						|
	buf.index= l->index;
 | 
						|
	if(sizeof(buf)!=write(fd,&buf,sizeof(buf))) laerror("write error in fourindex::put");
 | 
						|
	l=l->next;
 | 
						|
	}
 | 
						|
return n;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template <class I,class T>
 | 
						|
unsigned long fourindex<I,T>::get(int fd,bool withattr)
 | 
						|
{
 | 
						|
unsigned long n=0;
 | 
						|
matel4stored<I,T> buf;
 | 
						|
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;
 | 
						|
 | 
						|
	}
 | 
						|
while(sizeof(buf)==read(fd,&buf,sizeof(buf))) {++n; add(buf.index,buf.elem);}
 | 
						|
return n;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//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
 | 
						|
	terminator=rhs.terminator;
 | 
						|
	doscaling=rhs.doscaling;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//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; 
 | 
						|
		terminator=rhs.terminator;
 | 
						|
        	doscaling=rhs.doscaling;
 | 
						|
                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>
 | 
						|
unsigned long fourindex<I,T>::length() const
 | 
						|
{
 | 
						|
unsigned long n=0;
 | 
						|
matel4<I,T> *l=list;
 | 
						|
while(l)
 | 
						|
	{
 | 
						|
	++n;
 | 
						|
	l=l->next;
 | 
						|
	}
 | 
						|
return n;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template <class I, class T>
 | 
						|
std::ostream& operator<<(std::ostream &s, const fourindex_ext<I,T> &x)
 | 
						|
                {
 | 
						|
                int n;
 | 
						|
                n=x.size();
 | 
						|
                s << n << '\n';
 | 
						|
                typename fourindex_ext<I,T>::iterator it=x.begin();
 | 
						|
                while(it!=x.end())
 | 
						|
                        {
 | 
						|
                        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';
 | 
						|
                        ++it;
 | 
						|
                        }
 | 
						|
		s << (typename LA_traits_io<I>::IOtype) x.getterminator() << ' ' << (typename LA_traits_io<I>::IOtype)x.getterminator() <<  ' ' <<(typename LA_traits_io<I>::IOtype)x.getterminator() << ' ' << (typename LA_traits_io<I>::IOtype)x.getterminator()  << ' ' << (typename LA_traits_io<T>::IOtype) 0 << '\n';
 | 
						|
                return s;
 | 
						|
                }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
template <class I, class T>
 | 
						|
std::ostream& operator<<(std::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 << (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';
 | 
						|
			++it;
 | 
						|
                        }
 | 
						|
		s << (typename LA_traits_io<I>::IOtype)x.getterminator() << ' ' << (typename LA_traits_io<I>::IOtype)x.getterminator() <<  ' ' <<(typename LA_traits_io<I>::IOtype)x.getterminator() << ' ' << (typename LA_traits_io<I>::IOtype)x.getterminator()  << ' ' << (typename LA_traits_io<T>::IOtype) 0 << '\n';
 | 
						|
                return s;
 | 
						|
                }
 | 
						|
 | 
						|
template <class I, class T>
 | 
						|
std::istream& operator>>(std::istream  &s, fourindex<I,T> &x)
 | 
						|
                {
 | 
						|
                typename LA_traits_io<I>::IOtype i,j,k,l;
 | 
						|
		typename LA_traits_io<T>::IOtype elem;
 | 
						|
		int n;
 | 
						|
                s >> n ;
 | 
						|
                x.resize(n);
 | 
						|
                s >> i >> j >>k >>l;
 | 
						|
                while(i!= (typename LA_traits_io<I>::IOtype)x.getterminator() && j!= (typename LA_traits_io<I>::IOtype)x.getterminator() &&  k != (typename LA_traits_io<I>::IOtype)x.getterminator() && l!= (typename LA_traits_io<I>::IOtype)x.getterminator())
 | 
						|
                        {
 | 
						|
			s>>elem;
 | 
						|
			x.add((I)i,(I)j,(I)k,(I)l,(T)elem);
 | 
						|
			s >> i >> j >>k >>l;
 | 
						|
                        }
 | 
						|
                return s;
 | 
						|
                }
 | 
						|
 | 
						|
template <class I, class T>
 | 
						|
std::istream& operator>>(std::istream &s, fourindex_ext<I,T> &x)
 | 
						|
                {
 | 
						|
                int n;
 | 
						|
                s >> n;
 | 
						|
                x.resize(n);
 | 
						|
		typename LA_traits_io<I>::IOtype i,j,k,l;
 | 
						|
                typename LA_traits_io<T>::IOtype elem;
 | 
						|
		
 | 
						|
		s >> i >> j >>k >>l;
 | 
						|
                while(i!= (typename LA_traits_io<I>::IOtype)x.getterminator() && j!= (typename LA_traits_io<I>::IOtype)x.getterminator() &&  k != (typename LA_traits_io<I>::IOtype)x.getterminator() && l!= (typename LA_traits_io<I>::IOtype)x.getterminator())
 | 
						|
                        {
 | 
						|
                        s>>elem;
 | 
						|
                        x.put((I)i,(I)j,(I)k,(I)l,(T)elem);
 | 
						|
                        s >> i >> j >>k >>l;
 | 
						|
                        }
 | 
						|
	
 | 
						|
		x.flush();
 | 
						|
                return s;
 | 
						|
                }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/////////////////////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
 | 
						|
 | 
						|
//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)
 | 
						|
 | 
						|
//general template declaration
 | 
						|
template<fourindexsymtype S, class T, class DUMMY> class fourindex_dense;
 | 
						|
 | 
						|
//traits class
 | 
						|
template<fourindexsymtype S, class T, class DUMMY>
 | 
						|
struct LA_traits<fourindex_dense<S,T,DUMMY> > {
 | 
						|
typedef T elementtype;
 | 
						|
typedef typename LA_traits<T>::normtype normtype;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
//make it as a derived class in order to be able to use it in a base class context - "supermatrix" operations
 | 
						|
//note - loops for the twoelectronrealmullikanAB integral to be unique and in canonical order
 | 
						|
// i=1..n, j=1..i, k=1..n, l=1..k
 | 
						|
 | 
						|
template<class T, class I> 
 | 
						|
class fourindex_dense<twoelectronrealmullikanAB,T,I> : public NRMat<T> {
 | 
						|
public:
 | 
						|
	fourindex_dense(): NRMat<T>() {};
 | 
						|
	explicit fourindex_dense(const int n): NRMat<T>(n*(n+1)/2,n*(n+1)/2) {};
 | 
						|
	fourindex_dense(const NRMat<T> &rhs): NRMat<T>(rhs) {}; //be able to convert the parent class  transparently to this
 | 
						|
	fourindex_dense(const T &a, const int n): NRMat<T>(a,n*(n+1)/2,n*(n+1)/2) {};
 | 
						|
	fourindex_dense(const T *a, const int n): NRMat<T>(a,n*(n+1)/2,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;
 | 
						|
	void resize(const int n) {(*this).NRMat<T>::resize(n*(n+1)/2,n*(n+1)/2);};
 | 
						|
	void putext(int f, T thr=1e-15);
 | 
						|
	int nbas() const {return (int)std::sqrt(2*(*this).nrows());};
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
template<class T, class I>
 | 
						|
void fourindex_dense<twoelectronrealmullikanAB,T,I>::putext(int f, T thr)
 | 
						|
{
 | 
						|
T y;
 | 
						|
for(int i=1; i<=nbas(); ++i) for(int j=1; j<=i; ++j)
 | 
						|
        for(int k=1; k<=nbas(); ++k) for(int l=1; l<=k; ++l)
 | 
						|
		{
 | 
						|
		y=(*this)(i,j,k,l);
 | 
						|
		if(abs(y)>thr)
 | 
						|
			{
 | 
						|
			matel4stored<I,T> x;
 | 
						|
			x.elem= y;
 | 
						|
			x.index.indiv.i=i;
 | 
						|
			x.index.indiv.j=j;
 | 
						|
			x.index.indiv.k=k;
 | 
						|
			x.index.indiv.l=l;
 | 
						|
			if(sizeof(matel4stored<I,T>) != write(f,&x,sizeof(matel4stored<I,T>)) )
 | 
						|
				laerror("write error in putext");
 | 
						|
			}
 | 
						|
		}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template<class T, class I> 
 | 
						|
fourindex_dense<twoelectronrealmullikanAB,T,I>::fourindex_dense(const fourindex<I,T> &rhs) : NRMat<T>((T)0,rhs.size()*(rhs.size()+1)/2,rhs.size()*(rhs.size()+1)/2)
 | 
						|
{
 | 
						|
if(rhs.getsymmetry() != twoelectronrealmullikanAB ) laerror("fourindex_dense symmetry mismatch");
 | 
						|
typename fourindex<I,T>::iterator p;
 | 
						|
#ifdef DEBUG
 | 
						|
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)NRMat<T>::nn || KL<0 || KL>=(unsigned int)NRMat<T>::mm) laerror("fourindex_dense index out of range in constructor");
 | 
						|
#endif
 | 
						|
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>
 | 
						|
fourindex_dense<twoelectronrealmullikanAB,T,I>::fourindex_dense(const fourindex_ext<I,T> &rhs) : NRMat<T>((T)0,rhs.size()*(rhs.size()+1)/2,rhs.size()*(rhs.size()+1)/2)
 | 
						|
{
 | 
						|
if(rhs.getsymmetry() != twoelectronrealmullikanAB ) laerror("fourindex_dense symmetry mismatch");
 | 
						|
typename fourindex_ext<I,T>::iterator p;
 | 
						|
for(p=rhs.begin(); p!= rhs.end(); ++p) 
 | 
						|
	{
 | 
						|
#ifdef DEBUG
 | 
						|
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)NRMat<T>::nn || KL<0 || KL>=(unsigned int)NRMat<T>::mm) laerror("fourindex_dense index out of range in constructor");
 | 
						|
#endif
 | 
						|
	(*this)(p->index.indiv.i,p->index.indiv.j ,p->index.indiv.k,p->index.indiv.l) = p->elem;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
template<class T, class DUMMY>
 | 
						|
T& fourindex_dense<twoelectronrealmullikanAB,T,DUMMY>::operator() (unsigned int i, unsigned int j, unsigned int k, unsigned int l)
 | 
						|
{
 | 
						|
int I = SMat_index_1(i,j);
 | 
						|
int J = SMat_index_1(k,l);
 | 
						|
//I,J act as indices of a NRmat
 | 
						|
#ifdef DEBUG
 | 
						|
     	if (*NRMat<T>::count != 1) laerror("lval (i,j,k,l) with count > 1 in fourindex_dense");
 | 
						|
       	if (I<0 || I>=NRMat<T>::nn || J<0 || J>=NRMat<T>::mm) laerror("fourindex_dense index out of range");
 | 
						|
       	if (!NRMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return NRMat<T>::operator()(I,J);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template<class T, class DUMMY>
 | 
						|
const T& fourindex_dense<twoelectronrealmullikanAB,T,DUMMY>::operator() (unsigned int i, unsigned int j, unsigned int k, unsigned int l) const
 | 
						|
{
 | 
						|
int I = SMat_index_1(i,j);
 | 
						|
int J = SMat_index_1(k,l);
 | 
						|
//I,J act as indices of a NRSmat
 | 
						|
#ifdef DEBUG
 | 
						|
       	if (I<0 || I>=NRMat<T>::nn || J<0 || J>=NRMat<T>::mm) laerror("fourindex_dense index out of range");
 | 
						|
       	if (!NRMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return NRMat<T>::operator()(I,J);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
////////////////////
 | 
						|
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;
 | 
						|
	void resize(const int n) {(*this).NRSMat<T>::resize(n*(n+1)/2);};
 | 
						|
	void putext(int f, T thr=1e-15);
 | 
						|
	int nbas() const {return (int)std::sqrt(2*(*this).nrows());};
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
template<class T, class I>
 | 
						|
void fourindex_dense<twoelectronrealmullikan,T,I>::putext(int f, T thr)
 | 
						|
{
 | 
						|
T y;
 | 
						|
for(int i=1; i<=nbas(); ++i) for(int j=1; j<=i; ++j)
 | 
						|
        for(int k=1; k<=i; ++k) for(int l=1; l<=(i==k?j:k); ++l)
 | 
						|
		{
 | 
						|
		y=(*this)(i,j,k,l);
 | 
						|
		if(abs(y) > thr)
 | 
						|
			{
 | 
						|
			matel4stored<I,T> x;
 | 
						|
			x.elem= y;
 | 
						|
			x.index.indiv.i=i;
 | 
						|
			x.index.indiv.j=j;
 | 
						|
			x.index.indiv.k=k;
 | 
						|
			x.index.indiv.l=l;
 | 
						|
			if(sizeof(matel4stored<I,T>) != write(f,&x,sizeof(matel4stored<I,T>)) )
 | 
						|
				laerror("write error in putext");
 | 
						|
			}
 | 
						|
		}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template<class T, class I> 
 | 
						|
fourindex_dense<twoelectronrealmullikan,T,I>::fourindex_dense(const fourindex<I,T> &rhs) : NRSMat<T>((T)0,rhs.size()*(rhs.size()+1)/2)
 | 
						|
{
 | 
						|
if(rhs.getsymmetry() != twoelectronrealmullikan ) laerror("fourindex_dense symmetry mismatch");
 | 
						|
typename fourindex<I,T>::iterator p;
 | 
						|
#ifdef DEBUG
 | 
						|
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");
 | 
						|
#endif
 | 
						|
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>
 | 
						|
fourindex_dense<twoelectronrealmullikan,T,I>::fourindex_dense(const fourindex_ext<I,T> &rhs) : NRSMat<T>((T)0,rhs.size()*(rhs.size()+1)/2)
 | 
						|
{
 | 
						|
if(rhs.getsymmetry() != twoelectronrealmullikan ) laerror("fourindex_dense symmetry mismatch");
 | 
						|
typename fourindex_ext<I,T>::iterator p;
 | 
						|
for(p=rhs.begin(); p!= rhs.end(); ++p) 
 | 
						|
	{
 | 
						|
#ifdef DEBUG
 | 
						|
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");
 | 
						|
#endif
 | 
						|
	(*this)(p->index.indiv.i,p->index.indiv.j ,p->index.indiv.k,p->index.indiv.l) = p->elem;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
template<class T, class DUMMY>
 | 
						|
T& fourindex_dense<twoelectronrealmullikan,T,DUMMY>::operator() (unsigned int i, unsigned int j, unsigned int k, unsigned int l)
 | 
						|
{
 | 
						|
int I = SMat_index_1(i,j);
 | 
						|
int J = SMat_index_1(k,l);
 | 
						|
//I,J act as indices of a NRSmat
 | 
						|
#ifdef DEBUG
 | 
						|
     	if (*NRSMat<T>::count != 1) laerror("lval (i,j,k,l) with count > 1 in fourindex_dense");
 | 
						|
       	if (I<0 || I>=NRSMat<T>::nn || J<0 || J>=NRSMat<T>::nn) laerror("fourindex_dense index out of range");
 | 
						|
       	if (!NRSMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return NRSMat<T>::v[SMat_index(I,J)];
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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
 | 
						|
{
 | 
						|
int I = SMat_index_1(i,j);
 | 
						|
int J = SMat_index_1(k,l);
 | 
						|
//I,J act as indices of a NRSmat
 | 
						|
#ifdef DEBUG
 | 
						|
       	if (I<0 || I>=NRSMat<T>::nn || J<0 || J>=NRSMat<T>::nn) laerror("fourindex_dense index out of range");
 | 
						|
       	if (!NRSMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return NRSMat<T>::v[SMat_index(I,J)];
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class I>
 | 
						|
class fourindex_dense<nosymmetry,T,I> : public NRMat<T> {
 | 
						|
protected:
 | 
						|
	unsigned int nnbas;
 | 
						|
friend class explicit_t2;
 | 
						|
public:
 | 
						|
	unsigned int nbas() const {return nnbas;};	
 | 
						|
        fourindex_dense(): NRMat<T>() {nnbas=0;};
 | 
						|
	void resize(const int nnn) {nnbas=nnn; (*this).NRMat<T>::resize(nnbas*nnbas,nnbas*nnbas);};
 | 
						|
        explicit fourindex_dense(const int nnn): NRMat<T>(nnn*nnn,nnn*nnn) {nnbas=nnn;};
 | 
						|
        explicit fourindex_dense(const int nnn, const NRMat<T> &mat): NRMat<T>(mat) {nnbas=nnn;};
 | 
						|
 | 
						|
        inline T& operator() (unsigned int i, unsigned int j, unsigned int a, unsigned int b)
 | 
						|
{
 | 
						|
#ifdef DEBUG
 | 
						|
if(i<1||i>nnbas ||j<1||j>nnbas|| a<1||a>nnbas||b<1||b>nnbas) laerror("nosymmetry fourindex out of range");
 | 
						|
if (!NRMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return (*this).NRMat<T>::operator() ((j-1)*nnbas+i-1,(b-1)*nnbas+a-1);
 | 
						|
}
 | 
						|
        inline const T& operator() (unsigned int i, unsigned int j, unsigned int a, unsigned int b) const
 | 
						|
{
 | 
						|
#ifdef DEBUG
 | 
						|
if(i<1||i>nnbas ||j<1||j>nnbas|| a<1||a>nnbas||b<1||b>nnbas) laerror("nosymmetry fourindex out of range");
 | 
						|
if (!NRMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return (*this).NRMat<T>::operator() ((j-1)*nnbas+i-1,(b-1)*nnbas+a-1);
 | 
						|
}
 | 
						|
 | 
						|
void print(std::ostream &out) const
 | 
						|
		{
 | 
						|
		unsigned int i,j,a,b;
 | 
						|
		for(i=1; i<=nnbas; ++i) for(j=1; j<=nnbas; ++j) for(a=1; a<=nnbas; ++a) for(b=1; b<=nnbas; ++b) out << i<<" "<<j<<" "<<a<<" "<<b<<" "<<(*this)(i,j,a,b)<<std::endl;
 | 
						|
		}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
//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> {
 | 
						|
protected:
 | 
						|
friend class explicit_t2;
 | 
						|
public:
 | 
						|
	unsigned int noca,nocb,nvra,nvrb;
 | 
						|
        fourindex_dense(): NRMat<T>() {noca=nocb=nvra=nvrb=0;};
 | 
						|
	void resize(const int nocca, const int noccb, const int nvrta, const int nvrtb) {noca=nocca; nocb=noccb; nvra=nvrta; nvrb=nvrtb; (*this).NRMat<T>::resize(nocca*noccb,nvrta*nvrtb);};
 | 
						|
        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;};
 | 
						|
        explicit fourindex_dense(const int nocca, const int noccb, const int nvrta, const int nvrtb, const NRMat<T> &data): NRMat<T>(data) {noca=nocca; nocb=noccb; nvra=nvrta; nvrb=nvrtb; if(data.nrows()!=nocca*noccb||data.ncols()!=nvrta*nvrtb) laerror("data size mismatch in fourindex_dense T2IjAb_aces constructor");};
 | 
						|
 | 
						|
//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
 | 
						|
if(i<1||i>noca ||j<1||j>nocb|| a<1||a>nvra||b<1||b>nvrb) laerror("T2IjAb_aces fourindex out of range");
 | 
						|
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
 | 
						|
if(i<1||i>noca ||j<1||j>nocb|| a<1||a>nvra||b<1||b>nvrb) laerror("T2IjAb_aces fourindex out of range");
 | 
						|
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);
 | 
						|
}
 | 
						|
 | 
						|
	void print(std::ostream &out) const
 | 
						|
		{
 | 
						|
		unsigned int i,j,a,b;
 | 
						|
		for(i=1; i<=noca; ++i) for(j=1; j<=nocb; ++j) for(a=1; a<=nvra; ++a) for(b=1; b<=nvrb; ++b) out << i<<" "<<j<<" "<<a<<" "<<b<<" "<<(*this)(i,j,a,b)<<std::endl;
 | 
						|
		}
 | 
						|
};
 | 
						|
 | 
						|
template<class T, class I>
 | 
						|
class fourindex_dense<antisymtwoelectronrealdiracAB,T,I> : public NRSMat<T> {
 | 
						|
protected:
 | 
						|
	unsigned int nnbas;
 | 
						|
friend class explicit_t2;
 | 
						|
public:
 | 
						|
	unsigned int nbas() const {return nnbas;};
 | 
						|
        fourindex_dense(): NRSMat<T>() {nnbas=0;};
 | 
						|
	void resize(const int n) {nnbas=n; (*this).NRSMat<T>::resize(nnbas*nnbas);};
 | 
						|
        explicit fourindex_dense(const int n): NRSMat<T>(n*n) {nnbas=n;};
 | 
						|
        explicit fourindex_dense(const int n, const NRSMat<T>&data): NRSMat<T>(data) {nnbas=n; if(data.nrows()!=n*n) laerror("data size mismatch in fourindex_dense antisymtwoelectronrealdiracAB constructor");};
 | 
						|
 | 
						|
//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
 | 
						|
if(i<1||i>nnbas ||j<1||j>nnbas|| a<1||a>nnbas||b<1||b>nnbas) laerror("antisymtwoelectronrealdiracAB fourindex out of range");
 | 
						|
if (!NRSMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return (*this).NRSMat<T>::operator() ((j-1)*nnbas+i-1,(b-1)*nnbas+a-1);
 | 
						|
}
 | 
						|
        inline const T& operator() (unsigned int i, unsigned int j, unsigned int a, unsigned int b) const
 | 
						|
{
 | 
						|
#ifdef DEBUG
 | 
						|
if(i<1||i>nnbas ||j<1||j>nnbas|| a<1||a>nnbas||b<1||b>nnbas) laerror("antisymtwoelectronrealdiracAB fourindex out of range");
 | 
						|
if (!NRSMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return (*this).NRSMat<T>::operator() ((j-1)*nnbas+i-1,(b-1)*nnbas+a-1);
 | 
						|
}
 | 
						|
 | 
						|
	void print(std::ostream &out) const
 | 
						|
		{
 | 
						|
		unsigned int i,j,a,b;
 | 
						|
		for(i=1; i<=nnbas; ++i) for(j=1; j<=nnbas; ++j)
 | 
						|
			 for(a=1; a<=i; ++a) for(b=1; b<= (a<i?nnbas:j); ++b) 
 | 
						|
			out << i<<" "<<j<<" "<<a<<" "<<b<<" "<<(*this)(i,j,a,b)<<std::endl;
 | 
						|
		}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
template<class T, class I>
 | 
						|
class fourindex_dense<T2ijab_aces,T,I> : public NRMat<T> {
 | 
						|
protected:
 | 
						|
	unsigned int ntri;
 | 
						|
friend class explicit_t2;
 | 
						|
public:
 | 
						|
	 unsigned int nocc,nvrt;
 | 
						|
        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;};
 | 
						|
        explicit fourindex_dense(const int noc, const int nvr, const NRMat<T> &data): NRMat<T>(data) {nocc=noc; nvrt=nvr; ntri=nvr*(nvr-1)/2; if(data.nrows()!=noc*(noc-1)/2 || data.ncols()!=nvr*(nvr-1)/2) laerror("data size mismatch in T2ijab_aces constructor"); };
 | 
						|
	void resize(const int noc, const int nvr) {(*this).NRMat<T>::resize(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
 | 
						|
        inline T operator() (unsigned int i, unsigned int j, unsigned int a, unsigned int b) const
 | 
						|
{
 | 
						|
#ifdef DEBUG
 | 
						|
if(i<1||i>nocc ||j<1||j>nocc|| a<1||a>nvrt||b<1||b>nvrt) laerror("T2ijab_aces fourindex out of range");
 | 
						|
if (!NRMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
int minus=0;
 | 
						|
if(i==j||a==b) return (T)0; //important, needed
 | 
						|
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;
 | 
						|
}
 | 
						|
	inline void set(unsigned int i, unsigned int j, unsigned int a, unsigned int b, T elem)
 | 
						|
{
 | 
						|
#ifdef DEBUG
 | 
						|
if(i<1||i>nocc ||j<1||j>nocc|| a<1||a>nvrt||b<1||b>nvrt) laerror("T2ijab_aces fourindex out of range");
 | 
						|
if (!NRMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
if(i==j||a==b && elem) laerror("antisymmetry violation in fourindex_dense<T2ijab_aces>");
 | 
						|
#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;}
 | 
						|
(*this).NRMat<T>::operator() ((i-2)*(i-1)/2+j-1, (a-2)*(a-1)/2+b-1) = minus? -elem : elem;
 | 
						|
}
 | 
						|
        inline void add(unsigned int i, unsigned int j, unsigned int a, unsigned int b, T elem)
 | 
						|
{
 | 
						|
#ifdef DEBUG
 | 
						|
if(i<1||i>nocc ||j<1||j>nocc|| a<1||a>nvrt||b<1||b>nvrt) laerror("T2ijab_aces fourindex out of range");
 | 
						|
if (!NRMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
if(i==j||a==b && elem) laerror("antisymmetry violation in fourindex_dense<T2ijab_aces>");
 | 
						|
#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;}
 | 
						|
(*this).NRMat<T>::operator() ((i-2)*(i-1)/2+j-1, (a-2)*(a-1)/2+b-1) += minus? -elem : elem;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
        void print(std::ostream &out) const
 | 
						|
                {
 | 
						|
                unsigned int i,j,a,b;
 | 
						|
                for(i=1; i<=nocc; ++i) for(j=1; j<i; ++j) for(a=1; a<=nvrt; ++a) for(b=1; b<a; ++b) out << i<<" "<<j<<" "<<a<<" "<<b<<" "<<(*this)(i,j,a,b)<<std::endl;
 | 
						|
                }
 | 
						|
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//compact in-core storage of antisymmetrized two-electron integrals
 | 
						|
 | 
						|
template<class T, class I> 
 | 
						|
class fourindex_dense<antisymtwoelectronrealdirac,T,I> : public NRSMat<T> {
 | 
						|
private: 
 | 
						|
	int nnbas;
 | 
						|
public:
 | 
						|
	int nbas() const {return nnbas;};
 | 
						|
	fourindex_dense(): NRSMat<T>() {};
 | 
						|
	explicit fourindex_dense(const int n): nnbas(n), NRSMat<T>(n*(n-1)/2) {};
 | 
						|
	explicit fourindex_dense(const int n, const  NRSMat<T> &data): nnbas(n), NRSMat<T>(data) {if(data.nrows()!=n*(n-1)/2) laerror("data size mismatch in fourindex_dense antisymtwoelectronrealdirac constructor");};
 | 
						|
	fourindex_dense(const T &a, const int n): nnbas(n), NRSMat<T>(a,n*(n-1)/2) {};
 | 
						|
	fourindex_dense(const T *a, const int n): nnbas(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);
 | 
						|
 | 
						|
	void set(unsigned int i, unsigned int j, unsigned int k, unsigned int l, T elem);
 | 
						|
	void add(unsigned int i, unsigned int j, unsigned int k, unsigned int l, T elem);
 | 
						|
	void add_unique(unsigned int i, unsigned int j, unsigned int k, unsigned int l, T elem);
 | 
						|
	const T operator() (unsigned int i, unsigned int j, unsigned int k, unsigned int l) const;
 | 
						|
	void resize(const int n) {nnbas=n; (*this).NRSMat<T>::resize(n*(n-1)/2);};
 | 
						|
        void print(std::ostream &out) const
 | 
						|
                {
 | 
						|
                unsigned int i,j,k,l;
 | 
						|
		for(i=1; i<=nnbas; ++i)
 | 
						|
       			 for(k=1;k<i; ++k)
 | 
						|
                		for(j=1; j<=i; ++j)
 | 
						|
                        		for(l=1; l<j && (j==i ? l<=k : 1); ++l)
 | 
						|
                				std::cout << i<<" "<<k<<" "<<j<<" "<<l<<" "<<(*this)(i,k,j,l)<<std::endl;
 | 
						|
                }
 | 
						|
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//WARNING: assignment by regular pointer not possible due to the sign tracking - returns const value to prevent it, use set() for assignment
 | 
						|
//therefore also operator() cannot be T& but T only  - no legal lvalue
 | 
						|
template<class T, class DUMMY>
 | 
						|
const T fourindex_dense<antisymtwoelectronrealdirac,T,DUMMY>::operator() (unsigned int i, unsigned int j, unsigned int k, unsigned int l) const
 | 
						|
{
 | 
						|
int I = ASMat_index_1(i,j);
 | 
						|
int J = ASMat_index_1(k,l);
 | 
						|
if (I<0 || J<0) return 0.; 
 | 
						|
int sign=1;
 | 
						|
if(i<j) sign = -sign;
 | 
						|
if(k<l) sign = -sign;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
if (I>=(unsigned int)NRSMat<T>::nn || J>=(unsigned int)NRSMat<T>::nn) laerror("index out of range");
 | 
						|
if (!NRSMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
return sign==1? NRSMat<T>::v[SMat_index(I,J)] : -NRSMat<T>::v[SMat_index(I,J)];
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template<class T, class DUMMY>
 | 
						|
void fourindex_dense<antisymtwoelectronrealdirac,T,DUMMY>::set(unsigned int i, unsigned int j, unsigned int k, unsigned int l, T elem)
 | 
						|
{
 | 
						|
if(i<j) elem = -elem;
 | 
						|
if(k<l) elem = -elem;
 | 
						|
int I = ASMat_index_1(i,j);
 | 
						|
int J = ASMat_index_1(k,l);
 | 
						|
if (I<0 || J<0) laerror("assignment to nonexisting element");
 | 
						|
#ifdef DEBUG
 | 
						|
if (I>=NRSMat<T>::nn || J>=NRSMat<T>::nn) laerror("index out of range");
 | 
						|
if (!NRSMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
NRSMat<T>::v[SMat_index(I,J)] = elem;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template<class T, class DUMMY>
 | 
						|
void fourindex_dense<antisymtwoelectronrealdirac,T,DUMMY>::add(unsigned int i, unsigned int j, unsigned int k, unsigned int l, T elem)
 | 
						|
{
 | 
						|
if(i<j) elem = -elem;
 | 
						|
if(k<l) elem = -elem;
 | 
						|
int I = ASMat_index_1(i,j);
 | 
						|
int J = ASMat_index_1(k,l);
 | 
						|
if (I<0 || J<0) laerror("assignment to nonexisting element");
 | 
						|
#ifdef DEBUG
 | 
						|
if (I>=NRSMat<T>::nn || J>=NRSMat<T>::nn) laerror("index out of range");
 | 
						|
if (!NRSMat<T>::v) laerror("access to unallocated fourindex_dense");
 | 
						|
#endif
 | 
						|
NRSMat<T>::v[SMat_index(I,J)] += elem;
 | 
						|
}
 | 
						|
 | 
						|
template<class T, class DUMMY>
 | 
						|
void fourindex_dense<antisymtwoelectronrealdirac,T,DUMMY>::add_unique(unsigned int i, unsigned int j, unsigned int k, unsigned int l, T elem)
 | 
						|
{
 | 
						|
if(i<=j || k<=l) return;
 | 
						|
int I = ASMat_index_1(i,j);
 | 
						|
int J = ASMat_index_1(k,l);
 | 
						|
if (I<0 || J<0 || I<J) return;
 | 
						|
NRSMat<T>::v[SMat_index(I,J)] += elem;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template<class T, class I> 
 | 
						|
fourindex_dense<antisymtwoelectronrealdirac,T,I>::fourindex_dense(const fourindex<I,T> &rhs) : nnbas(rhs.size()), NRSMat<T>((T)0,rhs.size()*(rhs.size()-1)/2)
 | 
						|
{
 | 
						|
if(rhs.getsymmetry() != twoelectronrealmullikan ) laerror("fourindex_dense symmetry mismatch");
 | 
						|
typename fourindex_ext<I,T>::piterator p; //we have to run over equivalents in non-canonical order to build the antisymmetrization properly; it could be done less elegantly but more efficiently moving the if's to outer parts of the piterator loop, if needed
 | 
						|
for(p= const_cast<fourindex_ext<I,T> *>(&rhs)->pbegin(); p.notend(); ++p)
 | 
						|
        {
 | 
						|
        I i=p->index.indiv.i;
 | 
						|
        I j=p->index.indiv.j;
 | 
						|
        I k=p->index.indiv.k;
 | 
						|
        I l=p->index.indiv.l;
 | 
						|
        add_unique(i,k,j,l,p->elem);
 | 
						|
        add_unique(i,k,l,j,-p->elem);
 | 
						|
        }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template<class T, class I>
 | 
						|
fourindex_dense<antisymtwoelectronrealdirac,T,I>::fourindex_dense(const fourindex_ext<I,T> &rhs) : nnbas(rhs.size()), NRSMat<T>((T)0,rhs.size()*(rhs.size()-1)/2)
 | 
						|
{
 | 
						|
if(rhs.getsymmetry() != twoelectronrealmullikan ) laerror("fourindex_dense symmetry mismatch");
 | 
						|
typename fourindex_ext<I,T>::piterator p; //we have to run over equivalents in non-canonical order to build the antisymmetrization properly; it could be done less elegantly but more efficiently moving the if's to outer parts of the piterator loop, if needed
 | 
						|
for(p= const_cast<fourindex_ext<I,T> *>(&rhs)->pbegin(); p.notend(); ++p) 
 | 
						|
        {
 | 
						|
	I i=p->index.indiv.i;
 | 
						|
	I j=p->index.indiv.j;
 | 
						|
	I k=p->index.indiv.k;
 | 
						|
	I l=p->index.indiv.l;
 | 
						|
        add_unique(i,k,j,l,p->elem);
 | 
						|
        add_unique(i,k,l,j,-p->elem);
 | 
						|
        }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
}//namespace
 | 
						|
 | 
						|
//TODO:
 | 
						|
//implement fourindex_dense for unitary t2 symmetry types
 | 
						|
 | 
						|
#endif /*_fourindex_included*/
 |