0
$\begingroup$

I've just implemented the GMRES algorithm based on chapter 4 of Fundamentals of Numerical Mathematics for Physicists and Engineers using the problems in Numerical Analysis by Timothy Sauer for validation. Implementation converges for all of the worked examples in the Prof Sauer's text but does not for the singular non-textbook problem.

#!/usr/bin/python3

import math
import copy
import numpy as np

TEXTBOOK_PROBLEM = True

if TEXTBOOK_PROBLEM:
    # From Numerical Analysis by Timothy Sauer
    # https://media.pearsoncmg.com/aw/aw_sauer_num_analysis_3/solutions/sol_4_4.html
    A = np.array([
                    [ 1, 1, 0],
                    [-1, 1, 2],
                    [ 0, 0, 1]
                    ])

    b = np.array(
        [[1],
         [0],
         [0]])
else:
    A = np.array(
    [[  53,   83,  101,  119,  133,  161,    0,    0,    0],
     [  83,  130,  158,  187,  209,  253,    0,    0,    0],
     [ 101,  158,  194,  221,  247,  299,    0,    0,    0],
     [ 119,  187,  221, 1130, 1222, 1464, 1189, 1247, 1363],
     [ 133,  209,  247, 1222, 1322, 1584, 1271, 1333, 1457],
     [ 161,  253,  299, 1464, 1584, 1898, 1517, 1591, 1739],
     [   0,    0,    0, 1189, 1271, 1517, 1681, 1763, 1927],
     [   0,    0,    0, 1247, 1333, 1591, 1763, 1849, 2021],
     [   0,    0,    0, 1363, 1457, 1739, 1927, 2021, 2209]])

    b = np.array(
    [[  650],
     [ 1020],
     [ 1220],
     [ 8142],
     [ 8778],
     [10506],
     [ 9348],
     [ 9804],
     [10716]])

################################################################################
# Uses Given's rotation to convert an upper Hessenberg matrix H to an upper
# triangular matrix which is trivial to solve.
def solve(H):
    numRows, numCols = H.shape
    b = np.hstack(([1], np.zeros(numRows - 1)))
    x = np.zeros(numCols)

    # Given's rotation (converts upper Hessenberg matrix to upper triangular matrix)
    for i in range(numCols):
        d = math.sqrt(H[i][i]**2 + H[i + 1][i]**2)
        s = H[i + 1][i]/d
        c = H[i][i]/d
        e1 = b[i]
        e2 = b[i + 1]
        b[i] = c*e1 + s*e2
        b[i + 1] = c*e2 - s*e1
        for j in range(i, numCols):
            r1 = H[i][j]
            r2 = H[i + 1][j]
            H[i][j]     = c*r1 + s*r2
            H[i + 1][j] = c*r2 - s*r1

    # Solve upper triangular matrix
    for i in range(numCols - 1, -1, -1):
        accum = 0
        for j in range(numCols - 1, i, -1):
            accum = x[j]*H[i][j]
        x[i] = (b[i] - accum)/H[i][i]

    return x

################################################################################

index = 1
terminate = False

q = b/np.linalg.norm(b)
h = np.array([[0.0]])

while True:
    h = np.vstack((h, [0]*h.shape[-1])) # adds a row of zeros
    Aq = A.dot(q[:,-1])
    Q = copy.deepcopy(Aq)

    for i in range(index):
        value = q[:,-index + i]
        h[i][-1] = np.dot(value, Aq)
        Q -= h[i][-1]*value

    h[index][-1] = np.linalg.norm(Q)
    c = solve(copy.deepcopy(h))

    if h[index][-1] == 0:
        x = q.dot(c) # solution
        print(x)
        break
    else:
        q = np.column_stack((q, Q/h[index][-1]))

    h = np.column_stack((h, np.zeros(len(h))))
    index += 1

The singular (non-textbook) problem is solvable by numpy as follows:

from scipy.sparse.linalg import gmres
x, exitCode = gmres(A, b, atol=1e-5)
print(exitCode)
$\endgroup$
6
  • $\begingroup$ Can you check if things dramatically improve if you add at least the diagonal preconditioning? (see this answer of mine on a different question for some context). $\endgroup$
    – Anton Menshov
    Commented Jul 4 at 17:42
  • $\begingroup$ Is the non-textbook problem singular? GMRES is guaranteed to converge in at most $n$ iterations if a solution exists. ($n$ is the size of the matrix). It may be that the scipy implementation has some heuristics in place for singular problems that are not present in the textbook algorithm. $\endgroup$
    – whpowell96
    Commented Jul 4 at 19:50
  • $\begingroup$ @whpowell96 The problem I am trying to solve is singular. Do you know any strategies for solving singular problems. $\endgroup$
    – Olumide
    Commented Jul 4 at 20:27
  • $\begingroup$ I recommend you update your post to reflect the fact that the matrix is singular. I will write a short answer $\endgroup$
    – whpowell96
    Commented Jul 4 at 20:36
  • $\begingroup$ @AntonMenshov The diagonal preconditioner does not help. $\endgroup$
    – Olumide
    Commented Jul 4 at 20:57

1 Answer 1

0
$\begingroup$

MINRES-QLP appears to be the only algorithm capable of solving singular symmetric and Hermitian Linear systems.

$\endgroup$
1
  • $\begingroup$ I believe conjugate gradients also can do so as long as the system is consistent. MINRES and the conjugate residual (CR) method on the other hand work also when the system is inconsistent. $\endgroup$
    – lightxbulb
    Commented Jul 4 at 23:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.