pyscf/lib/shciscf/libSHCITools.c
/*
  Multiplies the matrices m1[n^4] by m2[n^2] and allows the user to choose
  the index of m1 to sum over using the indx parameter, e.g. 0 sums over
  the last index of m1. n is the common dimension of m1 and m2. mout is the
  output array for the multiplication. When used with two-body integrals,
  m1 shold be the eri (or intermediate eri) array and m2 should be the unitary
  matrix. This function has a temporal cost of O(n^5).
  
  NOTE: Chemistry notation is used for the two-body matrix indices, e.g.
  (ab|cd) = \int \phi_{a^+} \phi_b O_2 \phi_{c^+} \phi_d dx
*/
Multiplies the matrices m1[n^4] by m2[n^2] and allows the user to choose
the index of m1 to sum over using the indx parameter, e.g. 0 sums over
the last index of m1. n is the common dimension of m1 and m2. mout is the
output array for the multiplication. When used with two-body integrals,
m1 shold be the eri (or intermediate eri) array and m2 should be the unitary
matrix. This function has a temporal cost of O(n^5).

Chemistry notation is used for the two-body matrix indices, e.g.
Multiplies the matrices m1 [ n^4 ] by m2 [ n^2 ] and allows the user to choose the index of m1 to sum over using the indx parameter e . g . 0 sums over the last index of m1 . n is the common dimension of m1 and m2 . mout is the output array for the multiplication . When used with two - body integrals m1 shold be the eri ( or intermediate eri ) array and m2 should be the unitary matrix . This function has a temporal cost of O ( n^5 ) . Chemistry notation is used for the two - body matrix indices e . g .
void multMat4D ( size_t n, double * m1, double * m2, double * mout,
		 size_t indx )
{
  size_t n2 = n*n, n3 = n2*n;
  switch ( indx )
    {
    case 0:
#pragma omp parallel
      {
	size_t a,b,c,d,i;
	for ( a = 0; a < n; ++a )
	  for ( b = 0; b < n; ++b )
	    for ( c = 0; c < n; ++c )
	      for ( d = 0; d < n; ++d )
		{
		  size_t abcd = d + c*n + b*n2 + a*n3;
		  mout[abcd] = 0;
		  for ( i = 0; i < n; ++i )
		    {
		      size_t ia = i*n + a;
		      size_t ibcd = d + c*n + b*n2 + i*n3;
		      mout[abcd] += m1[ibcd] * m2[ia];
		    }
		}
      }
      break;
    case 1:
#pragma omp parallel
      {
	size_t i,b,c,d,j;
	for ( i = 0; i < n; ++i )
	  for ( b = 0; b < n; ++b )
	    for ( c = 0; c < n; ++c )
	      for ( d = 0; d < n; ++d )
		{
		  size_t ibcd = d + c*n + b*n2 + i*n3;
		  mout[ibcd] = 0;
		  for ( j = 0; j < n; ++j )
		    {
		      size_t jb = j*n + b;
		      size_t ijcd = d + c*n + j*n2 + i*n3;
		      mout[ibcd] += m1[ijcd] * m2[jb];
		    }
		}
      }
      break;
    case 2:
#pragma omp parallel
      {
	size_t i,j,c,d,k;
	for ( i = 0; i < n; ++i )
	  for ( j = 0; j < n; ++j )
	    for ( c = 0; c < n; ++c )
	      for ( d = 0; d < n; ++d )
		{
		  size_t ijcd = d + c*n + j*n2 + i*n3;
		  mout[ijcd] = 0;
		  for ( k = 0; k < n; ++k )
		    {
		      size_t kc = k*n + c;
		      size_t ijkd = d + k*n + j*n2 + i*n3;
		      mout[ijcd] += m1[ijkd] * m2[kc];
		    }
		}
      }
      break;
    default:
#pragma omp parallel
      {
	size_t i,j,k,l,d;
	for ( i = 0; i < n; ++i )
	  for ( j = 0; j < n; ++j )
	    for ( k = 0; k < n; ++k )
	      for ( d = 0; d < n; ++d )
		{
		  size_t ijkd = d + k*n + j*n2 + i*n3;
		  mout[ijkd] = 0;
		  for ( l = 0; l < n; ++l )
		    {
		      size_t ld = l*n + d;
		      size_t ijkl = l + k*n + j*n2 + i*n3;
		      mout[ijkd] += m1[ijkl] * m2[ld];
		    }
		}
      }
      break;
    }
}
void multMat4D ( size_t n , double * m1 , double * m2 , double * mout , size_t indx ) { size_t n2 = n * n , n3 = n2 * n ; switch ( indx ) { case 0 : #pragma  omp parallel { size_t a , b , c , d , i ; for ( a = 0 ; a < n ; ++ a ) for ( b = 0 ; b < n ; ++ b ) for ( c = 0 ; c < n ; ++ c ) for ( d = 0 ; d < n ; ++ d ) { size_t abcd = d + c * n + b * n2 + a * n3 ; mout [ abcd ] = 0 ; for ( i = 0 ; i < n ; ++ i ) { size_t ia = i * n + a ; size_t ibcd = d + c * n + b * n2 + i * n3 ; mout [ abcd ] += m1 [ ibcd ] * m2 [ ia ] ; } } } break ; case 1 : #pragma  omp parallel { size_t i , b , c , d , j ; for ( i = 0 ; i < n ; ++ i ) for ( b = 0 ; b < n ; ++ b ) for ( c = 0 ; c < n ; ++ c ) for ( d = 0 ; d < n ; ++ d ) { size_t ibcd = d + c * n + b * n2 + i * n3 ; mout [ ibcd ] = 0 ; for ( j = 0 ; j < n ; ++ j ) { size_t jb = j * n + b ; size_t ijcd = d + c * n + j * n2 + i * n3 ; mout [ ibcd ] += m1 [ ijcd ] * m2 [ jb ] ; } } } break ; case 2 : #pragma  omp parallel { size_t i , j , c , d , k ; for ( i = 0 ; i < n ; ++ i ) for ( j = 0 ; j < n ; ++ j ) for ( c = 0 ; c < n ; ++ c ) for ( d = 0 ; d < n ; ++ d ) { size_t ijcd = d + c * n + j * n2 + i * n3 ; mout [ ijcd ] = 0 ; for ( k = 0 ; k < n ; ++ k ) { size_t kc = k * n + c ; size_t ijkd = d + k * n + j * n2 + i * n3 ; mout [ ijcd ] += m1 [ ijkd ] * m2 [ kc ] ; } } } break ; default : #pragma  omp parallel { size_t i , j , k , l , d ; for ( i = 0 ; i < n ; ++ i ) for ( j = 0 ; j < n ; ++ j ) for ( k = 0 ; k < n ; ++ k ) for ( d = 0 ; d < n ; ++ d ) { size_t ijkd = d + k * n + j * n2 + i * n3 ; mout [ ijkd ] = 0 ; for ( l = 0 ; l < n ; ++ l ) { size_t ld = l * n + d ; size_t ijkl = l + k * n + j * n2 + i * n3 ; mout [ ijkd ] += m1 [ ijkl ] * m2 [ ld ] ; } } } break ; } }
Multiplies the matrices m1[n^4] by m2[n^2] and allows the user to choose
the index of m1 to sum over using the indx parameter, e.g.
Multiplies the matrices m1 [ n^4 ] by m2 [ n^2 ] and allows the user to choose the index of m1 to sum over using the indx parameter e . g .
// Switch statement deals with the different indices to sum over.