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 by
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).
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.