28 #include <util/misc/scexception.h>
29 #include <chemistry/qc/wfn/orbitalspace.h>
30 #include <math/mmisc/pairiter.h>
32 #ifndef _chemistry_qc_lcao_utilsimpl_h
33 #define _chemistry_qc_lcao_utilsimpl_h
37 template <PureSpinCase2 spin>
43 const unsigned int brablock_size_ab = ij_iter.
nij_ab();
44 const unsigned int ketblock_size_ab = kl_iter.nij_ab();
45 if (A.rowdim().n()%brablock_size_ab)
46 throw ProgrammingError(
"sc::spinadapt() -- row dimension is not integer multiple of bra-space rank",__FILE__,__LINE__);
47 if (A.coldim().n()%ketblock_size_ab)
48 throw ProgrammingError(
"sc::spinadapt() -- col dimension is not integer multiple of ket-space rank",__FILE__,__LINE__);
49 const unsigned int nbra_blocks = A.rowdim().n() / brablock_size_ab;
50 const unsigned int nket_blocks = A.coldim().n() / ketblock_size_ab;
51 const unsigned int brablock_size_aa = ij_iter.nij_aa();
52 const unsigned int ketblock_size_aa = kl_iter.nij_aa();
53 RefSCMatrix Aspinadapted(A.rowdim(),A.coldim(),A->kit());
54 const double one_divby_sqrt_two=1.0/sqrt(2.0);
55 unsigned int bra_offset_ab = 0;
56 unsigned int bra_offset_aa = 0;
57 for(
int brablock=0; brablock<nbra_blocks; brablock++, bra_offset_ab += brablock_size_ab, bra_offset_aa += brablock_size_aa) {
58 for(ij_iter.start();int(ij_iter);ij_iter.next()) {
60 const int ij_ab = ij_iter.ij_ab();
62 unsigned int ket_offset_ab = 0;
63 unsigned int ket_offset_aa = 0;
64 for(
int ketblock=0; ketblock<nket_blocks; ketblock++, ket_offset_ab += ketblock_size_ab, ket_offset_aa += ketblock_size_aa) {
65 for(kl_iter.start();int(kl_iter);kl_iter.next()) {
67 const int kl_ab = kl_iter.ij_ab();
68 const int lk_ab = kl_iter.ij_ba();
69 double Aspinadapted_element;
73 if(ij_iter.i()==ij_iter.j()) {
74 prefactor*=one_divby_sqrt_two;
76 if(kl_iter.i()==kl_iter.j()) {
77 prefactor*=one_divby_sqrt_two;
80 Aspinadapted_element=prefactor*(A.get_element(ij_ab+bra_offset_ab,kl_ab+ket_offset_ab)+A.get_element(ij_ab+bra_offset_ab,lk_ab+ket_offset_ab));
82 else if(spin==Triplet){
83 Aspinadapted_element=A.get_element(ij_ab+bra_offset_ab,kl_ab+ket_offset_ab)-A.get_element(ij_ab+bra_offset_ab,lk_ab+ket_offset_ab);
86 throw ProgrammingError(
"sc::spinadapt() -- PureSpinCase2 spin is not adeqate",__FILE__,__LINE__);
89 Aspinadapted.set_element(ij_ab+bra_offset_ab,kl_ab+ket_offset_ab,Aspinadapted_element);
98 template <
bool accumulate>
106 const bool bra1_eq_bra2 = (bra1 == bra2);
107 const bool ket1_eq_ket2 = (ket1 == ket2);
108 if (!bra1_eq_bra2 && !ket1_eq_ket2)
109 throw ProgrammingError(
"sc::antisymmetrize() -- the operation does not make sense: bra1!=bra2, ket1!=ket2",__FILE__,__LINE__);
122 const unsigned int brablock_size_ab = ij_iter->
nij_ab();
123 const unsigned int ketblock_size_ab = kl_iter->
nij_ab();
124 const unsigned int brablock_size_aa = ij_iter->
nij_aa();
125 const unsigned int ketblock_size_aa = kl_iter->
nij_aa();
126 if (brablock_size_ab==0 || ketblock_size_ab==0)
128 if (A.rowdim().n()%brablock_size_ab)
129 throw ProgrammingError(
"sc::antisymmetrize() -- row dimension of Source is not integer multiple of bra-space rank",__FILE__,__LINE__);
130 if (A.coldim().n()%ketblock_size_ab)
131 throw ProgrammingError(
"sc::antisymmetrize() -- col dimension of Source is not integer multiple of ket-space rank",__FILE__,__LINE__);
132 if (Aanti.rowdim().n()%brablock_size_aa)
133 throw ProgrammingError(
"sc::antisymmetrize() -- row dimension of Result is not integer multiple of bra-space rank",__FILE__,__LINE__);
134 if (Aanti.coldim().n()%ketblock_size_aa)
135 throw ProgrammingError(
"sc::antisymmetrize() -- col dimension of Result is not integer multiple of ket-space rank",__FILE__,__LINE__);
136 const unsigned int nbra_blocks = A.rowdim().n() / brablock_size_ab;
137 const unsigned int nket_blocks = A.coldim().n() / ketblock_size_ab;
138 if (Aanti.rowdim().n() / brablock_size_aa != nbra_blocks)
139 throw ProgrammingError(
"sc::antisymmetrize() -- bra dimensions of Source and Result do not match",__FILE__,__LINE__);
140 if (Aanti.coldim().n() / ketblock_size_aa != nket_blocks)
141 throw ProgrammingError(
"sc::antisymmetrize() -- ket dimensions of Source and Result do not match",__FILE__,__LINE__);
143 unsigned int bra_offset_ab = 0;
144 unsigned int bra_offset_aa = 0;
145 for(
int brablock=0; brablock<nbra_blocks; brablock++, bra_offset_ab += brablock_size_ab, bra_offset_aa += brablock_size_aa) {
146 for(ij_iter->
start();int(*ij_iter);ij_iter->
next()) {
148 const int ij_aa = ij_iter->
ij_aa();
151 const int ij_ab = ij_iter->
ij_ab();
152 const int ji_ab = ij_iter->
ij_ba();
154 unsigned int ket_offset_ab = 0;
155 unsigned int ket_offset_aa = 0;
156 for(
int ketblock=0; ketblock<nket_blocks; ketblock++, ket_offset_ab += ketblock_size_ab, ket_offset_aa += ketblock_size_aa) {
157 for(kl_iter->
start();int(*kl_iter);kl_iter->
next()) {
159 const int kl_aa = kl_iter->
ij_aa();
162 const int kl_ab = kl_iter->
ij_ab();
163 const int lk_ab = kl_iter->
ij_ba();
165 double Aanti_ijkl = (ket1_eq_ket2) ?
166 A.get_element(ij_ab+bra_offset_ab,kl_ab+ket_offset_ab) -
167 A.get_element(ij_ab+bra_offset_ab,lk_ab+ket_offset_ab)
169 A.get_element(ij_ab+bra_offset_ab,kl_ab+ket_offset_ab) -
170 A.get_element(ji_ab+bra_offset_ab,kl_ab+ket_offset_ab);
172 Aanti.accumulate_element(ij_aa+bra_offset_aa,kl_aa+ket_offset_aa,Aanti_ijkl);
174 Aanti.set_element(ij_aa+bra_offset_aa,kl_aa+ket_offset_aa,Aanti_ijkl);
184 template <
bool accumulate>
192 const unsigned int block_size_ab = ij_iter->
nij_ab();
193 const unsigned int block_size_aa = ij_iter->
nij_aa();
194 if (block_size_ab==0)
196 if (A.dim().n()%block_size_ab)
197 throw ProgrammingError(
"sc::antisymmetrize() -- dimension of Source is not integer multiple of (bra1->rank)^2",__FILE__,__LINE__);
198 if (Aanti.dim().n()%block_size_aa)
199 throw ProgrammingError(
"sc::antisymmetrize() -- dimension of Result is not integer multiple of (bra1->rank * (bra1->rank-1)/2)",__FILE__,__LINE__);
200 const unsigned int nblocks = A.dim().n() / block_size_ab;
201 if (Aanti.dim().n() / block_size_aa != nblocks)
202 throw ProgrammingError(
"sc::antisymmetrize() -- dimensions of Source and Result do not match",__FILE__,__LINE__);
204 unsigned int bra_offset_ab = 0;
205 unsigned int bra_offset_aa = 0;
206 for(
unsigned int brablock=0; brablock<nblocks; brablock++, bra_offset_ab += block_size_ab, bra_offset_aa += block_size_aa) {
207 for(ij_iter->
start();int(*ij_iter);ij_iter->
next()) {
209 const int ij_aa = ij_iter->
ij_aa();
212 const int ij_ab = ij_iter->
ij_ab();
213 const int ji_ab = ij_iter->
ij_ba();
215 unsigned int ket_offset_ab = 0;
216 unsigned int ket_offset_aa = 0;
217 for(
unsigned int ketblock=0; ketblock<nblocks; ketblock++, ket_offset_ab += block_size_ab, ket_offset_aa += block_size_aa) {
218 for(kl_iter->start();int(*kl_iter);kl_iter->next()) {
220 const int kl_aa = kl_iter->ij_aa();
223 const int kl_ab = kl_iter->ij_ab();
224 const int lk_ab = kl_iter->ij_ba();
226 double Aanti_ijkl = A.get_element(ij_ab+bra_offset_ab,kl_ab+ket_offset_ab) -
227 A.get_element(ij_ab+bra_offset_ab,lk_ab+ket_offset_ab);
229 Aanti.accumulate_element(ij_aa+bra_offset_aa,kl_aa+ket_offset_aa,Aanti_ijkl);
231 Aanti.set_element(ij_aa+bra_offset_aa,kl_aa+ket_offset_aa,Aanti_ijkl);
241 template <
bool accumulate>
244 double * result_ptr = Aanti;
245 for(
int r=0; r<n; ++r) {
248 for(
int c=0; c<r; ++c, ++result_ptr, CR+=n) {
249 const double v = A[RC_offset + c] - A[CR];
259 template <
bool Accumulate>
264 if (A.rowdim().n() != Asymm.rowdim().n())
265 throw ProgrammingError(
"sc::symmetrize() -- source and target matrices have different row dimensions",__FILE__,__LINE__);
266 if (A.coldim().n() != Asymm.coldim().n())
267 throw ProgrammingError(
"sc::symmetrize() -- source and target matrices have different column dimensions",__FILE__,__LINE__);
270 const unsigned int brablock_size_ab = ij_iter.
nij_ab();
271 const unsigned int ketblock_size_ab = kl_iter.nij_ab();
272 if (A.rowdim().n()%brablock_size_ab)
273 throw ProgrammingError(
"sc::symmetrize() -- row dimension is not integer multiple of bra-space rank",__FILE__,__LINE__);
274 if (A.coldim().n()%ketblock_size_ab)
275 throw ProgrammingError(
"sc::symmetrize() -- col dimension is not integer multiple of ket-space rank",__FILE__,__LINE__);
276 const unsigned int nbra_blocks = A.rowdim().n() / brablock_size_ab;
277 const unsigned int nket_blocks = A.coldim().n() / ketblock_size_ab;
279 unsigned int bra_offset_ab = 0;
280 for(
int brablock=0; brablock<nbra_blocks; brablock++, bra_offset_ab += brablock_size_ab) {
281 for(ij_iter.start();int(ij_iter);ij_iter.next()) {
283 const unsigned int IJ_ab = ij_iter.ij_ab() + bra_offset_ab;
284 const unsigned int JI_ab = ij_iter.ij_ba() + bra_offset_ab;
286 unsigned int ket_offset_ab = 0;
287 for(
int ketblock=0; ketblock<nket_blocks; ketblock++, ket_offset_ab += ketblock_size_ab) {
288 for(kl_iter.start();int(kl_iter);kl_iter.next()) {
290 const unsigned int KL_ab = kl_iter.ij_ab() + ket_offset_ab;
291 const unsigned int LK_ab = kl_iter.ij_ba() + ket_offset_ab;
293 const double A_ijkl = A.get_element(IJ_ab,KL_ab);
294 const double A_ijlk = A.get_element(IJ_ab,LK_ab);
295 const double A_jikl = A.get_element(JI_ab,KL_ab);
296 const double A_jilk = A.get_element(JI_ab,LK_ab);
299 const double Asymm_ijkl = 0.5 * (A_ijkl + A_jilk);
301 Asymm.accumulate_element(IJ_ab,KL_ab,Asymm_ijkl);
302 Asymm.accumulate_element(JI_ab,LK_ab,Asymm_ijkl);
305 Asymm.set_element(IJ_ab,KL_ab,Asymm_ijkl);
306 Asymm.set_element(JI_ab,LK_ab,Asymm_ijkl);
310 const double Asymm_ijlk = 0.5 * (A_ijlk + A_jikl);
312 Asymm.accumulate_element(IJ_ab,LK_ab,Asymm_ijlk);
313 Asymm.accumulate_element(JI_ab,KL_ab,Asymm_ijlk);
316 Asymm.set_element(IJ_ab,LK_ab,Asymm_ijlk);
317 Asymm.set_element(JI_ab,KL_ab,Asymm_ijlk);
328 template <
bool Accumulate, sc::fastpairiter::PairSymm BraSymm, sc::fastpairiter::PairSymm KetSymm>
336 MPQC_ASSERT(&Asymm != &A);
337 using namespace sc::fastpairiter;
341 if ( (BraSymm == AntiSymm && KetSymm == AntiSymm) ||
342 (BraSymm == Symm && KetSymm == Symm) )
343 throw ProgrammingError(
"sc::symmetrize12() -- the matrix is already symmetric",__FILE__,__LINE__);
344 if ( (BraSymm == AntiSymm || BraSymm == Symm) && bra1 != bra2)
345 throw ProgrammingError(
"sc::symmetrize12() -- bra dimension is anti/symmetrized, but bra1!=bra2",__FILE__,__LINE__);
346 if ( (KetSymm == AntiSymm || KetSymm == Symm) && ket1 != ket2)
347 throw ProgrammingError(
"sc::symmetrize12() -- ket dimension is anti/symmetrized, but ket1!=ket2",__FILE__,__LINE__);
349 if (A.rowdim().n() != Asymm.rowdim().n())
350 throw ProgrammingError(
"sc::symmetrize() -- source and target matrices have different row dimensions",__FILE__,__LINE__);
351 if (A.coldim().n() != Asymm.coldim().n())
352 throw ProgrammingError(
"sc::symmetrize() -- source and target matrices have different column dimensions",__FILE__,__LINE__);
355 const unsigned int brablock_size = ij_iter.
nij();
356 const unsigned int ketblock_size = kl_iter.nij();
357 if (A.rowdim().n()%brablock_size)
358 throw ProgrammingError(
"sc::symmetrize() -- row dimension is not integer multiple of bra-space rank",__FILE__,__LINE__);
359 if (A.coldim().n()%ketblock_size)
360 throw ProgrammingError(
"sc::symmetrize() -- col dimension is not integer multiple of ket-space rank",__FILE__,__LINE__);
361 const unsigned int nbra_blocks = A.rowdim().n() / brablock_size;
362 const unsigned int nket_blocks = A.coldim().n() / ketblock_size;
364 unsigned int bra_offset = 0;
365 for(
int brablock=0; brablock<nbra_blocks; brablock++, bra_offset += brablock_size) {
366 for(ij_iter.start();int(ij_iter);ij_iter.next()) {
368 const unsigned int IJ = ij_iter.ij() + bra_offset;
369 const unsigned int JI = (BraSymm == ASymm) ? ij_iter.ij(ij_iter.j(),ij_iter.i()) + bra_offset
371 const double ij_permfac = (BraSymm == AntiSymm) ? -1.0 : 1.0;
373 unsigned int ket_offset = 0;
374 for(
int ketblock=0; ketblock<nket_blocks; ketblock++, ket_offset += ketblock_size) {
375 for(kl_iter.start();int(kl_iter);kl_iter.next()) {
377 const unsigned int KL = kl_iter.ij() + ket_offset;
378 const unsigned int LK = (KetSymm == ASymm) ? kl_iter.ij(kl_iter.j(),kl_iter.i()) + ket_offset
380 const double kl_permfac = (KetSymm == AntiSymm) ? -1.0 : 1.0;
382 const double A_ijkl = A.get_element(IJ,KL);
383 const double A_jilk = A.get_element(JI,LK);
384 const double Asymm_ijkl = 0.5 * (A_ijkl + ij_permfac*kl_permfac*A_jilk);
387 Asymm.accumulate_element(IJ,KL,Asymm_ijkl);
389 Asymm.set_element(IJ,KL,Asymm_ijkl);
400 template <
bool Accumulate,
401 sc::fastpairiter::PairSymm SrcBraSymm, sc::fastpairiter::PairSymm SrcKetSymm,
402 sc::fastpairiter::PairSymm DstBraSymm, sc::fastpairiter::PairSymm DstKetSymm
410 using namespace sc::fastpairiter;
414 if (SrcBraSymm == DstBraSymm && SrcKetSymm == DstKetSymm)
415 throw ProgrammingError(
"sc::symmetrize() -- nothing to be done",__FILE__,__LINE__);
416 if ( (SrcBraSymm != ASymm && SrcKetSymm != ASymm) )
417 throw ProgrammingError(
"sc::symmetrize() -- either bra of ket must be asymmetric",__FILE__,__LINE__);
418 if ( (SrcBraSymm != ASymm && SrcBraSymm != DstBraSymm) )
419 throw ProgrammingError(
"sc::symmetrize() -- can only change bra that is asymmetric",__FILE__,__LINE__);
420 if ( (SrcKetSymm != ASymm && SrcKetSymm != DstKetSymm) )
421 throw ProgrammingError(
"sc::symmetrize() -- can only change ket that is asymmetric",__FILE__,__LINE__);
422 if (DstBraSymm!=ASymm && bra1 != bra2)
423 throw ProgrammingError(
"sc::symmetrize12() -- bra is to be anti/symmetrized, but bra1!=bra2",__FILE__,__LINE__);
424 if (DstKetSymm!=ASymm && ket1 != ket2)
425 throw ProgrammingError(
"sc::symmetrize12() -- ket is to be anti/symmetrized, but ket1!=ket2",__FILE__,__LINE__);
426 const bool transform_bra = DstBraSymm != ASymm && DstBraSymm != SrcBraSymm;
427 const bool transform_ket = DstKetSymm != ASymm && DstKetSymm != SrcKetSymm;
433 const unsigned int brablock_size_src = ij_srciter.
nij();
434 const unsigned int ketblock_size_src = kl_srciter.nij();
435 const unsigned int brablock_size_dst = ij_dstiter.nij();
436 const unsigned int ketblock_size_dst = kl_dstiter.nij();
437 if (A.rowdim().n()%brablock_size_src)
438 throw ProgrammingError(
"sc::symmetrize() -- row dimension of Source is not integer multiple of bra-space rank",__FILE__,__LINE__);
439 if (A.coldim().n()%ketblock_size_src)
440 throw ProgrammingError(
"sc::symmetrize() -- col dimension of Source is not integer multiple of ket-space rank",__FILE__,__LINE__);
441 if (Asymm.rowdim().n()%brablock_size_dst)
442 throw ProgrammingError(
"sc::symmetrize() -- row dimension of Result is not integer multiple of bra-space rank",__FILE__,__LINE__);
443 if (Asymm.coldim().n()%ketblock_size_dst)
444 throw ProgrammingError(
"sc::symmetrize() -- col dimension of Result is not integer multiple of ket-space rank",__FILE__,__LINE__);
445 const unsigned int nbra_blocks = A.rowdim().n() / brablock_size_src;
446 const unsigned int nket_blocks = A.coldim().n() / ketblock_size_src;
447 if (nbra_blocks != Asymm.rowdim().n() / brablock_size_dst)
448 throw ProgrammingError(
"sc::symmetrize() -- # of bra blocks in Source and Result do not match",__FILE__,__LINE__);
449 if (nket_blocks != Asymm.coldim().n() / ketblock_size_dst)
450 throw ProgrammingError(
"sc::symmetrize() -- # of bra blocks in Source and Result do not match",__FILE__,__LINE__);
452 unsigned int bra_offset_src = 0;
453 unsigned int bra_offset_dst = 0;
454 for(
int brablock=0; brablock<nbra_blocks;
455 brablock++, bra_offset_src += brablock_size_src, bra_offset_dst += brablock_size_dst) {
456 for(ij_dstiter.start();int(ij_dstiter);ij_dstiter.next()) {
458 const unsigned int IJ_dst = ij_dstiter.ij() + bra_offset_dst;
460 const unsigned int I = ij_srciter.i();
461 const unsigned int J = ij_srciter.j();
462 const unsigned IJ = ij_srciter.ij(I,J) + bra_offset_src;
466 JI = ij_srciter.ij(J,I) + bra_offset_src;
467 ij_permfac = (DstBraSymm == AntiSymm) ? -1.0 : 1.0;
470 unsigned int ket_offset_src = 0;
471 unsigned int ket_offset_dst = 0;
472 for(
int ketblock=0; ketblock<nket_blocks;
473 ketblock++, ket_offset_src += ketblock_size_src, ket_offset_dst += ketblock_size_dst) {
474 for(kl_dstiter.start();int(kl_dstiter);kl_dstiter.next()) {
476 const unsigned int KL_dst = kl_dstiter.ij() + ket_offset_dst;
478 const unsigned int K = kl_srciter.i();
479 const unsigned int L = kl_srciter.j();
480 const unsigned int KL = kl_srciter.ij(K,L) + ket_offset_src;
484 LK = kl_srciter.ij(L,K) + ket_offset_src;
485 kl_permfac = (DstKetSymm == AntiSymm) ? -1.0 : 1.0;
490 const double A_ijkl = A.get_element(IJ,KL);
491 const double A_jikl = A.get_element(JI,KL);
492 Asymm_ijkl = A_ijkl + ij_permfac*A_jikl;
495 const double A_ijkl = A.get_element(IJ,KL);
496 const double A_ijlk = A.get_element(IJ,LK);
497 Asymm_ijkl = A_ijkl + kl_permfac*A_ijlk;
499 if (transform_bra && transform_ket) {
500 const double A_ijkl = A.get_element(IJ,KL);
501 const double A_jikl = A.get_element(JI,KL);
502 const double A_ijlk = A.get_element(IJ,LK);
503 const double A_jilk = A.get_element(JI,LK);
504 Asymm_ijkl = A_ijkl + ij_permfac*A_jikl + kl_permfac*A_ijlk + ij_permfac*kl_permfac*A_jilk;
508 Asymm.accumulate_element(IJ_dst,KL_dst,Asymm_ijkl);
510 Asymm.set_element(IJ_dst,KL_dst,Asymm_ijkl);