next up previous
Next: Two-electron Integrals Up: Book of Knowledge Previous: Spin Orbitals vs.

One-electron Integrals and the ioff Array

Now consider the one-electron integrals. They are indexed by two orbitals, the bra and ket orbitals.

However, recall that the one-electron operator is Hermitian, so . Further, if and are real orbitals, then . In that case, we can save computer memory by storing only the lower (or upper) triangle of the matrix representation of .

Recall that we desire a rapid way to access the elements of this lower-trianglular array. First, note that a computer doesn't know how to store triangles of memory; everything (even a matrix) is is accessed linearly from memory at the machine-code level. Now, how do we compute the linear address of a matrix element ? First, recall that we have chosen (arbitrarily) to use the lower triangle, so . Now the composite index ij of indices i and j will give the linear address of the memory location holding (i.e. how far from the start of the array we must travel before finding the value for ). The composite index ij for is given bygif

 

if numbering for i, j, and ij starts at zero (as it should for a C programmer). The FORTRAN equivalent is

if i, j, and ij start from one.

It is very inconvenient to apply formula (2) often because it can become computationally expensive to do so. A preferable solution is to prepare, in advance, an array which contains the precomputed values of the first term for all possible values of i. This array is called ioff in the programs of the PSI package. With it, the above equations both become

 

Recall that the above equations assume that . If we do not know which index is larger during the course of a program, the most efficient way to find the larger one is by using an inline function or macro for a conditional assignment (conditional assignments are sometimes less computationally expensive than their if/then equivalents). Thus we might define two macros to determine the greater and smaller members of a pair:

         #define MAX0(a,b) (((a)>(b)) ? (a) : (b))
         #define MIN0(a,b) (((a)<(b)) ? (a) : (b))
using these macros, the previous equation for ij becomes

Of course, whenever we know that , it is more efficient to use the equation (4) directly.

Now, suppose we turn things around. What if we have a compound index ij and we want to compute the corresponding i and j, ? After a bit of thinking and luck, you will be able to determine the following formulae (or perhaps something better!)

 

where we have taken only the integer part of the expression in equation (6). The difficulty with this decomposition is that it involves a square root operation, which is very expensive (not to mention the division). An alternative would be to determine i by running through the ioff array, and then to get j as above. This method, while less elegant, might actually be cheaper as long as the number of elements to be traversed in ioff is small.

Throughout this section, we have been assuming that we are going to store the lower triangle of the matrix. This is the standard choice, even though it shouldn't matter (in general) from the perspective of computational efficiency whether we choose to keep the upper or lower triangle. Note the ``in general'' qualifier in the previous sentence. Sometimes we want to store the upper triangle! One instance where this is the case is in Yoshimine sorts using the Elbert loop structure during two-electron integral transformations (more on two-electron integrals in a moment). It should be obvious that the formula for the composite index ij is no longer given by equation (2).gif We can use a formula like that in equation (4) if we use a different ioff array. This is the ioff2 array found in the TRANSQT program and in the library libiwl.



next up previous
Next: Two-electron Integrals Up: Book of Knowledge Previous: Spin Orbitals vs.



© 1996 by C. David Sherrill  / sherrill@bastille.cchem.berkeley.edu
Last modified: Tue Sep 17 22:13:09 EDT 1996