16. Linear Calculations of Sparse Matrices
Note – This document was created using AI translation.
16.1 Overview
Matrices in which many of the elements are 0 are referred to as sparse matrices. Such matrices often appear as coefficients in systems of linear equations for numerical solutions to partial differential equations.
Representing sparse matrices as regular two-dimensional arrays consumes significant memory to store the zeros and requires considerable CPU time for operations involving zeros during computation. To address this, special storage formats for sparse matrices are used.
Linear calculations with sparse matrices not only involve different storage formats, but also require different algorithms due to the large scale of the problems applied (e.g., involving tens of thousands or more). As a result, conventional linear calculation programs cannot be directly used. Specifically, iterative methods (such as Krylov subspace methods) are often employed for systems of linear equations, while methods such as the Lanczos method or the Arnoldi method are frequently used for eigenvalues and eigenvectors.
The following sections will explain example problems in sparse matrix calculations, the storage formats for sparse matrices used in XLPack, basic calculation programs, sparse matrix checks, solutions for systems of linear equations, file input/output, and more.
16.2 Example Problem in Sparse Matrix Calculations
This section explains an example of solving Laplace’s equation numerically using the five-point finite difference approximation.
Consider solving the following partial differential equation in a square domain where x = 0 to x = 1, and y = 0 to y = 1:
-d2u/dx2 - d2u/dy2 = 0 with Dirichlet boundary conditions: u(x, 0) = 0, u(0, y) = 0, u(x, 1) = x, u(1, y) = y
Such partial differential equations are applied, for example, to describe the temperature distribution of a plate in thermal equilibrium.
To perform finite difference approximation, the region in both the x and y directions is divided into N equal parts. Setting the division width as h = 1/N, the value of u at the grid point x = ih, y = jh (i = 0 to N, j = 0 to N) is represented as u[i,j]. The derivatives are approximated using differences as follows:
d2u/dx2 = (u[i-1,j] - 2u[i,j] + u[i+1,j])/h2 d2u/dy2 = (u[i,j-1] - 2u[i,j] + u[i,j+1])/h2
From this, Laplace’s equation is approximated by the following formula:
-u[i,j-1] - u[i-1,j] + 4u[i,j] - u[i+1,j] - u[i,j+1] = 0
The boundary conditions (Dirichlet conditions) directly assign values to the grid points along the boundary as follows:
u[i,0] = 0 (i = 0 to N) u[0,j] = 0 (j = 0 to N) u[i,N] = ih (i = 0 to N) u[N,j] = jh (j = 0 to N)
Thus, for the square region, the values on the edges are known, leaving only the interior part to be computed. Here, let m = N – 1, and reassign symbols as u1 = u[1,1], u2 = u[2,1], …, um = u[m,1], um+1 = u[1,2], …, um*m = u[m,m].
For N = 7 (m = 6), the arrangement is illustrated as follows.
In this case, out of the 64 grid points, 28 points are known from the boundary conditions, while the values of u at the remaining 36 points are unknown. This leads to the following system of linear equations:
Au = b
where, A is a 36 x 36 square matrix, u is a vector consisting of u1, u2, …, u36, and b is the right-hand side vector.
Using the approximate formula of Laplace’s equation above for i = 1 to 6, j = 1 to 6, the matrix A and vector b can be determined from the 36 equations.
( 4 -1 -1 ) (-1 4 -1 -1 ) ( -1 4 -1 -1 ) ( -1 4 -1 -1 ) ( -1 4 -1 -1 ) ( -1 4 -1 ) (-1 4 -1 -1 ) ( -1 -1 4 -1 -1 ) ( -1 -1 4 -1 -1 ) ( -1 -1 4 -1 -1 ) ( -1 -1 4 -1 -1 ) ( -1 -1 4 -1 ) A = ( . . . ) ( -1 4 -1 ) ( -1 -1 4 -1 ) ( -1 -1 4 -1 ) ( -1 -1 4 -1 ) ( -1 -1 4 -1 ) ( -1 -1 4 ) ( u[1,0] + u[0,1] = 0 ) ( u[2,0] = 0 ) ( u[3,0] = 0 ) ( u[4,0] = 0 ) ( u[5,0] = 0 ) ( u[6,0] + u[6,1] = h ) ( u[0,2] = 0 ) b = ( . . . ) ( u[5,7] = 5h ) ( u[6,7] + u[7,6] = 12h )
In this way, A becomes a symmetric sparse matrix with at most 5 non-zero elements in each row.
While the example with N = 7 was explained, achieving a more precise solution requires increasing N. For instance, if N = 100, the system of equations will have approximately 10,000 unknowns. Furthermore, for three-dimensional problems, it would involve approximately 1,000,000 unknowns. In such cases, conventional linear calculation programs can no longer be used, and programs specifically designed for large-scale sparse matrices become necessary.
16.3 Storage Formats for Sparse Matrices
XLPack uses the following three storage formats:
(1) Compressed Sparse Row (CSR) format
(2) Compressed Sparse Column (CSC) format
(3) Coordinate (COO) format
Formats (1) and (2) are used for computation, while format (3) is used for input and output. The basic functions of XLPack utilize only formats (1) and (3).
As an example, consider the following 3 × 4 matrix.
( 1 0 -2 4 ) ( -1 2 0 -9 ) ( 0 5 0 -8 )
(1) Compressed Sparse Row (CSR) Format
In CSR format, only the nonzero elements are stored using one floating-point array, val, and two integer arrays, rowptr and colind. The val array contains the values of nonzero elements arranged in row-wise order. The rowptr array represents the position of the first element of each row within the val array. The colind array stores the column indices corresponding to the elements in val. The last element of rowptr is set to the final position in val plus one.
Row and column indices generally start from 1 in Fortran programs and 0 in C programs, so compatibility should be considered.
C language format: val { 1, -2, 4, -1, 2, -9, 5, -8 } rowptr { 0, 3, 6, 8 } colind { 0, 2, 3, 0, 1, 3, 1, 3 } Fortran format: val { 1, -2, 4, -1, 2, -9, 5, -8 } rowptr { 1, 4, 7, 9 } colind { 1, 3, 4, 1, 2, 4, 2, 4 }
For symmetric matrices, only the diagonal elements and either the left or right part of the matrix may be stored to reduce memory usage. Here, such matrices are referred to as SSR format (not a commonly used term).
In the example above, column indices within each row are arranged in ascending order. While some programs may allow arbitrary ordering within rows, XLPack requires that the column indices be sorted in ascending order for computational efficiency.
(2) Compressed Sparse Column (CSC) Format
Since CSC format is not used in XLPack’s basic functions, its explanation is omitted. However, it stores nonzero elements in a column-wise order.
(3) Coordinate (COO) Format
In COO format, only the nonzero elements are stored using one floating-point array, val, and two integer arrays, rowind and colind. The val array holds the values of nonzero elements, while rowind and colind store the corresponding row and column indices.
Row and column indices generally start from 1 in Fortran programs and 0 in C programs, so compatibility should be considered.
C language format: val { 1, -2, 4, -1, 2, -9, 5, -8 } rowind { 0, 0, 0, 1, 1, 1, 2, 2 } colind { 0, 2, 3, 0, 1, 3, 1, 3 } Fortran format: val { 1, -2, 4, -1, 2, -9, 5, -8 } rowind { 1, 1, 1, 2, 2, 2, 3, 3 } colind { 1, 3, 4, 1, 2, 4, 2, 4 }
In the example above, row and column indices are arranged in ascending order. However, some programs may allow arbitrary ordering, depending on implementation.
16.4 Basic Computational Programs
In XLPack (basic functions), the following fundamental computational programs are available for matrices in CSR format:
CsrDusmv y <- αAx + βy or y <- αA^Tx + βy CsrDussv Solves Ax = b or A^Tx = b (triangular matrix) CsrDusmm C <- αAB + βC or C <- αA^TB + βC CsrDussm Solves AX = B or A^TX = B (triangular matrix) SsrDusmv y <- αAx + βy (symmetric matrix) CsrTrans Transpose of a sparse matrix
Additionally, the following conversion programs are available:
CooCsr COO -> CSR CsrCoo CSR -> COO SsrCsr SSR (CSR symmetric matrix format) -> CSR (full symmetric matrix) CsrSsr CSR (full symmetric matrix) -> SSR (CSR symmetric matrix format) CsrDense CSR -> Dense matrix DenseCsr Dense matrix -> CSR
16.5 Sparse Matrix Checking
When using matrices in CSR format, special care must be taken to avoid errors related to pointers and indices. These values correspond to variable addresses, meaning that incorrect handling can lead to unintended memory reads or writes, causing access errors.
In VBA, pointers are generally not used, and array bounds are always checked, preventing crashes. However, errors in CSR matrix pointers or indices can still cause Excel to crash, so extra caution is required during program development.
To help reduce such errors, the sparse matrix checking program CsrCheck is provided. While it does not completely eliminate errors, it can be a useful tool. An example of its usage is shown below.
Sub Start_2()
Const M = 3, N = 4
Dim Val(M * N) As Double, Ptr(M) As Long, Ind(M * N) As Long
Dim Result(9) As Long, Info As Long
'-- Check (1)
Debug.Print "** Check 1 **"
Val(0) = 1: Val(1) = -2: Val(2) = 4: Val(3) = -1: Val(4) = 2
Val(5) = -9: Val(6) = 5: Val(7) = -8
Ptr(0) = 0: Ptr(1) = 3: Ptr(2) = 6: Ptr(3) = 8
Ind(0) = 0: Ind(1) = 2: Ind(2) = 3: Ind(3) = 0: Ind(4) = 1
Ind(5) = 3: Ind(6) = 1: Ind(7) = 3
Call CsrCheck(M, N, Val(), Ptr(), Ind(), Result(), Info)
Call PrintResult(Info, Result())
'-- Check (2)
Debug.Print "** Check 2 **"
Val(0) = 0: Val(1) = 4: Val(2) = -2: Val(3) = -1: Val(4) = 2
Val(5) = -9: Val(6) = 5: Val(7) = -8
Ptr(0) = 0: Ptr(1) = 3: Ptr(2) = 6: Ptr(3) = 8
Ind(0) = 0: Ind(1) = 3: Ind(2) = 2: Ind(3) = 0: Ind(4) = 1
Ind(5) = 3: Ind(6) = 1: Ind(7) = 5
Call CsrCheck(M, N, Val(), Ptr(), Ind(), Result(), Info)
Call PrintResult(Info, Result())
End Sub
Sub PrintResult(Info As Long, Result() As Long)
Debug.Print "Info =" + Str(Info)
Debug.Print " Sym =" + Str(Result(0))
Debug.Print " Nnz =" + Str(Result(1));
Debug.Print " Nnz(L) =" + Str(Result(2));
Debug.Print " Nnz(U) =" + Str(Result(3));
Debug.Print " Nnz(D) =" + Str(Result(4))
Debug.Print " Zero =" + Str(Result(5));
Debug.Print " Zero(D) =" + Str(Result(6))
Debug.Print " Empty rows =" + Str(Result(7));
Debug.Print " Unsorted rows =" + Str(Result(8))
Debug.Print " Invalid inds =" + Str(Result(9))
End Sub
The output is as folows:
** Check 1 ** Info = 0 Sym = 0 Nnz = 8 Nnz(L) = 2 Nnz(U) = 4 Nnz(D) = 2 Zero = 0 Zero(D) = 0 Empty rows = 0 Unsorted rows = 0 Invalid inds = 0 ** Check 2 ** Info = 14 Sym = 0 Nnz = 8 Nnz(L) = 2 Nnz(U) = 4 Nnz(D) = 2 Zero = 1 Zero(D) = 1 Empty rows = 0 Unsorted rows = 1 Invalid inds = 1
Check 2 found one occurrence of an element with value 0 (harmless), one occurrence of rows not in ascending order (causing malfunctions in basic arithmetic programs and many other applications), and one occurrence of an invalid index (causing an access error).
16.6 Systems of Linear Equations
16.6.1 Solving Systems of Linear Equations
In sparse matrix linear calculations, iterative methods (such as Krylov subspace methods) are primarily used for solving systems of linear equations.
LU decomposition and Cholesky decomposition, commonly used for solving general systems of linear equations, allow coefficient matrices to have zero elements, but these elements may become nonzero as calculations progress. In contrast, iterative methods maintain zero elements in the coefficient matrix throughout the computation, making them well-suited for sparse matrix storage formats.
16.6.1.1 Conjugate Gradient (CG) Method
The conjugate gradient (CG) method is commonly used when the coefficient matrix A is symmetric and positive definite.
The solution to the equation Ax = b minimizes the following function:
f(x) = (1/2)(x, Ax) - (x, b)
In other words, solving this equation is equivalent to solving a nonlinear optimization problem with this as the objective function. The gradient descent method is applied (see Chapter 10).
Let pk be the direction vector and αk be the step size. The gradient descent method follows the following iterative formula:
xk+1 = xk + αkpk
To minimize f(xk+1), the step size and direction vector are determined as follows:
αk = (pk, rk)/(pk, Apk) rk+1 = rk - αkApk βk = -(rk+1, Apk)/(pk, Apk) pk+1 = rk+1 + βkpk
Here, rk represents the residual b – Axk.
Starting with an initial approximation x0, the iteration begins with p0 = r0 = b – Ax0.
In theory, this iterative process converges in at most n iterations. However, due to computational errors, it may not always do so in practice.
There is another interpretation of the CG method. Without going into detail, the Krylov subspace method generates a specialized space to approximate the solution of systems of linear equations. The CG method can be considered a variation of this approach.
16.6.1.2 Bi-Conjugate Gradient (BICG) Method
The conjugate gradient (CG) method cannot be used when the coefficient matrix A is a general (asymmetric) matrix. Therefore, various alternative methods have been proposed, with the bi-conjugate gradient (BICG) method being one of the most promising solutions.
Consider the equation Ax = b along with its dual equation ATx* = b*.
Using these, we define the following symmetric matrix and vectors:
A~ = ( A 0 ) ( 0 AT ) x~ = ( x ) ( x* ) b~ = ( b ) ( b* ) H~ = ( 0 I ) ( I 0 )
Next, we define the H~ inner product as follows:
<x~, y~> = (x~, H~y~) = (H~x~, y~)
Considering the equation A~x~ = b~, its solution minimizes the following function:
f(x~) = (1/2)<x~, A~x~> - <x~, b~>
By applying the computational procedures of the CG method to this problem, we derive the BICG method.
The BICG method can also be considered a variation of the Krylov subspace method.
16.6.2 Solving Systems of Linear Equations Using XLPack
In XLPack (basic functions), systems of linear equations can be solved using the conjugate gradient (CG) method for symmetric matrices (subroutine Cg1) and the bi-conjugate gradient (BICG) method for general (asymmetric) matrices (subroutine Bicg1).
The following example demonstrates solving the previously discussed Laplace equation using a five-point finite difference approximation. Since the coefficient matrix is symmetric, the CG method is used.
16.6.2.1 Generating the Coefficient Matrix and Right-Hand Side Vector
Following the problem setup, the coefficient matrix A and the right-hand side vector b are prepared accordingly.
Sub Mat5DF(M As Long, Val() As Double, Ptr() As Long, Ind() As Long)
Dim MM As Long, II As Long, I As Long, J As Long, K As Long
MM = M * M
K = 0
For II = 0 To MM - 1
I = Int(II / M)
J = II - I * M
Ptr(II) = K
If I > 0 Then
Ind(K) = II - M
Val(K) = -1
K = K + 1
End If
If J > 0 Then
Ind(K) = II - 1
Val(K) = -1
K = K + 1
End If
Ind(K) = II
Val(K) = 4
K = K + 1
If J < M - 1 Then
Ind(K) = II + 1
Val(K) = -1
K = K + 1
End If
If I < M - 1 Then
Ind(K) = II + M
Val(K) = -1
K = K + 1
End If
Next
Ptr(MM) = K
End Sub
Sub Rhs5DF(M As Long, B() As Double)
Dim H As Double, MM As Long, I As Long
H = 1# / (M + 1)
MM = M * M
For I = 0 To MM - 1
B(I) = 0
Next
For I = M - 1 To MM - 1 Step M
B(I) = H * (Int(I / M) + 1)
Next
For I = M * (M - 1) To MM - 1
B(I) = B(I) + H * (I - M * (M - 1) + 1)
Next
End Sub
16.6.2.2 Computing the Solution Using the CG Method
Once A and b are prepared, the subroutine Cg1 is called to obtain the solution. The initial values are all set to zero. After computing the solution, it is output in an appropriate format.
Sub Start()
Const N = 7, M = N - 1, MM = M * M
Dim Val(5 * MM) As Double, Ptr(MM) As Long, Ind(5 * MM) As Long
Dim B(MM - 1) As Double, X(MM - 1) As Double
Dim Resid As Double, Iter As Long, Info As Long
Dim I As Long, J As Long
'-- Set coefficients
Call Mat5DF(M, Val(), Ptr(), Ind())
Call Rhs5DF(M, B())
'-- Set initial approximation
For I = 0 To MM - 1
X(I) = 0
Next
'-- Solve equations
Call Cg1(MM, Val(), Ptr(), Ind(), B(), X(), Info, Iter, Resid)
'-- Output result
If Info = 0 Then
Call Output(N, X())
Else
MsgBox ("Error in Cg1: Info =" + Str(Info))
End If
End Sub
When this program is executed, the following results are obtained. Here, the values of all lattice points, including boundary points, are displayed.
16.7 File Input and Output
One of the commonly used formats for storing sparse matrices as text files is the MM format (Matrix Market Exchange Format). This format is often used for distributing test matrices.
In XLPack (basic functionality), the following input and output programs are provided for MM format files:
MMRead Reads a Matrix Market format file MMReadInfo Reads matrix information from a Matrix Market format file MMWrite Writes to a Matrix Market format file
Appendix: Computational Example Using the Finite Element Method
XLPack includes programs related to partial differential equations as part of its sparse matrix computation features (currently in an experimental version and subject to change in the future). Here, we will use the finite element method program to solve the above example problem of the Laplace equation.
This example uses a simple mesh with triangular elements. By inputting the information of lattice points, finite elements, and boundary elements into Fem2p, it outputs a finite element matrix in CSR format along with a right-hand side vector. Since this is a symmetric matrix, solving it using the CG method yields a numerical solution to the partial differential equation.
Sub Start()
Const Nx = 7, Ny = 7, N = (Nx + 1) * (Ny + 1), Ne = 2 * Nx * Ny
Const Nb = 2 * (Nx + Ny), Nb2 = 0, LdKnc = 4, LdKs = 3
Dim X(N - 1) As Double, Y(N - 1) As Double
Dim P(N - 1) As Double, Q(N - 1) As Double, F(N - 1) As Double
Dim Knc(LdKnc - 1, Ne - 1) As Long, Ks(LdKs - 1, Nb - 1) As Long
Dim Lb(Nb - 1) As Long, Ib(Nb - 1) As Long, Bv(Nb - 1) As Double
Dim Ks2() As Long, Alpha() As Double, Beta() As Double
Dim Val(20 * N) As Double, Ptr(N) As Long, Ind(20 * N) As Long
Dim B(N - 1) As Double, U(N - 1) As Double
Dim Ux As Double, Err As Double
Dim Info As Long
Dim I As Long, J As Long
'-- Set mesh data
Call SetData(Nx, Ny, N, Ne, Nb, X(), Y(), Knc(), Ks(), Lb(), P(), Q(), F(), Ib(), Bv())
'-- Assemble FEM matrix
Call Fem2p(N, Ne, X(), Y(), Knc(), P(), Q(), F(), Nb, Ib(), Bv(), Nb2, Ks2(), Alpha(), Beta(), Val(), Ptr(), Ind(), B(), Info)
'-- Solve equation
Dim Iter As Long, Res As Double
Call Cg1(N, Val(), Ptr(), Ind(), B(), U(), Info, Iter, Res)
Debug.Print "Info =" + Str(Info) + ", Iter =" + Str(Iter) + ", Res =" + Str(Res)
'-- Display solution
For I = 0 To Nx
For J = 0 To Ny
Cells(4 + Nx - J, 1 + I) = U((Ny + 1) * J + I)
Next
Next
End Sub
Sub SetData(Nx As Long, Ny As Long, N As Long, Ne As Long, Nb As Long, X() As Double, Y() As Double, Knc() As Long, Ks() As Long, Lb() As Long, P() As Double, Q() As Double, F() As Double, Ib() As Long, Bv() As Double)
Dim Id() As Long
Dim I As Long, J As Long, K As Long
Call Mesh23(Nx, Ny, X(), Y(), Knc(), Ks(), Lb())
For I = 0 To N - 1
P(I) = 1
Q(I) = 0
F(I) = 0
Next
'-- Set boundary condition 1
ReDim Id(N - 1)
For I = 0 To Nb - 1
For J = 1 To 2
Id(Ks(J, I) - 1) = Lb(I)
Next
Next
K = 0
For I = 0 To N - 1
If Id(I) = 1 Or Id(I) = 4 Then
Bv(K) = 0
ElseIf Id(I) = 2 Then
Bv(K) = Y(I)
ElseIf Id(I) = 3 Then
Bv(K) = X(I)
Else
GoTo Continue
End If
Ib(K) = I + 1
K = K + 1
Continue:
Next
End Sub
By executing this program, you can obtain the same results as those obtained using the difference method (within the margin of error).
As a function related to partial differential equations, the output program for VTK files, WriteVtkug, is provided. The final part of the above program is modified using this as below.
Sub Start2()
Const Nx = 7, Ny = 7, N = (Nx + 1) * (Ny + 1), Ne = 2 * Nx * Ny
Const Nb = 2 * (Nx + Ny), Nb2 = 0, LdKnc = 4, LdKs = 3
Dim X(N - 1) As Double, Y(N - 1) As Double
Dim P(N - 1) As Double, Q(N - 1) As Double, F(N - 1) As Double
Dim Knc(LdKnc - 1, Ne - 1) As Long, Ks(LdKs - 1, Nb - 1) As Long
Dim Lb(Nb - 1) As Long, Ib(Nb - 1) As Long, Bv(Nb - 1) As Double
Dim Ks2() As Long, Alpha() As Double, Beta() As Double
Dim Val(20 * N) As Double, Ptr(N) As Long, Ind(20 * N) As Long
Dim B(N - 1) As Double, U(N - 1) As Double
Dim Ux As Double, Err As Double
Dim Info As Long
Dim I As Long, J As Long
'-- Set mesh data
Call SetData(Nx, Ny, N, Ne, Nb, X(), Y(), Knc(), Ks(), Lb(), P(), Q(), F(), Ib(), Bv())
'-- Assemble FEM matrix
Call Fem2p(N, Ne, X(), Y(), Knc(), P(), Q(), F(), Nb, Ib(), Bv(), Nb2, Ks2(), Alpha(), Beta(), Val(), Ptr(), Ind(), B(), Info)
'-- Solve equation
Dim Iter As Long, Res As Double
Call Cg1(N, Val(), Ptr(), Ind(), B(), U(), Info, Iter, Res)
Debug.Print "Info =" + Str(Info) + ", Iter =" + Str(Iter) + ", Res =" + Str(Res)
'-- Output solution
Dim Z(N - 1) As Double
Call WriteVtkug("Test.vtk", N, X(), Y(), Z(), Ne, Knc(), U(), Info)
Debug.Print "Info =" + Str(Info)
End Sub
By executing this program, you can obtain the Test.vtk file. You can input the vtk file into external programs to display the results. For example, when viewed in the ParaView program, it appears as follows:
In XLPack (basic functions), other input/output programs for files generated by the mesh creation software gmsh (ReadGmsh22, WriteGmsh22) are provided. Using these allows calculations in various shaped regions created with gmsh. Below is a simple example of calculation results.