-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathiterativemethods.py
More file actions
159 lines (125 loc) · 5.21 KB
/
iterativemethods.py
File metadata and controls
159 lines (125 loc) · 5.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
"""
Iterative Solvers for Modified Graph Laplacian Systems
This module provides Python functions to solve a system of linear equations
of the form Ax = b, where A is a modified graph Laplacian matrix given by
A = L + 0.001 * I (graph Laplacian matrix L plus 0.001 times the identity
matrix I),
and the matrix is represented in CSR format.
It includes implementations of the following stationary iterative methods using
a matrix (or function) M for each choice derived from A:
(i) Forward Gauss-Seidel
(ii) Backward Gauss-Seidel
(iii) Symmetric Gauss-Seidel
(iv) The (diagonal) ell_1 smoother matrix
Each function takes as input the following parameters:
A: A symmetric positive definite (s.p.d.) CSR matrix
b: The right-hand side of the equation
epsilon: The tolerance for convergence (default: 1.e-6)
max_iter: The maximal number of iterations (default: 1000)
The output of each function includes:
x: The approximate solution
iter: The number of iterations used
delta_0: The norm of the initial r
delta: The norm of the final r
Author: Micron Jenkins
Date: 2023-05-07
"""
import graphrelations as gr
import numpy as np
import numpy.linalg as npla
from numpy import zeros, sum, squeeze, asarray
import scipy.sparse.linalg as la
from scipy.sparse import triu, tril, csr_matrix, eye, diags
# wrapper function to call in main code
def stationary_it_method(Adj, b, M, x0=0, max_iter=1000, epsilon=1e-6):
"""
using a modified graph Laplacian matrix A of adjacency matrix Adj and a
smoothing matrix operator M,
iteratively solve for a close approximation of Ax=b for unknown x.
:param Adj: a scipy CSR(or COO) matrix representing a vertex_vertex
adjacency relation of a weighted or unweighted
undirected graph
:param b: known right hand side of equation Ax = b
:param M: smoother method to use as defined below
:param x0: initial guess. if none given, zero vector of correct size will
be made and used
:param max_iter: maximum number of iterations
:param epsilon: tolerance level for how small the residual norm needs to
be before stopping
:return: x (the approximate solution), iter (number of iterations used),
delta_0 (norm of initial residual),
and delta (norm of final residual)
"""
#uncomment to build the special laplacian from hw 2 first
# A = gr.Laplacian(Adj) + 0.001 * eye(Adj.shape[0])
if x0 == 0:
x0 = zeros(Adj.shape[1])
return M(Adj, b, x0, max_iter, epsilon)
# below are the iterative smoothers to pass as M to stationary_it_method:
# bgs: backward Gauss-Seidel, fgs: forward Gauss-Seidel, sgs: symmetric
# Gauss-Seidel, and L_1
def bgs(A, b, guess, max_iter=1000, epsilon=1e-6):
upper = triu(A, format='csr')
x = guess.copy()
r = b - A @ x # this is the error vector b-Ax
delta_0 = delta = npla.norm(r) # size of the error vector
curr_iter = 0
while curr_iter < max_iter:
if delta <= epsilon * delta_0: # if this is true, the error is
# sufficiently small, so we stop.
return x, curr_iter, delta_0, delta
x += la.spsolve_triangular(upper, r, lower=False)
r = b - A @ x
delta = npla.norm(r)
curr_iter += 1
return x, curr_iter-1, delta_0, delta
def fgs(A, b, guess, max_iter=1000, epsilon=1e-6):
lower = tril(A, format='csr')
x = guess.copy()
r = b - A @ x # this is the error vector b-Ax
delta_0 = delta = npla.norm(r) # size of the error vector
curr_iter = 0
while curr_iter < max_iter:
if delta <= epsilon * delta_0: # if this is true, the error is
# sufficiently small, so we stop.
return x, curr_iter, delta_0, delta
x += la.spsolve_triangular(lower, r)
r = b - A @ x
delta = npla.norm(r)
curr_iter += 1
return x, curr_iter-1, delta_0, delta
def sgs(A, b, guess, max_iter=1000, epsilon=1e-6):
lower = tril(A, format='csr')
diag = csr_matrix.diagonal(A)
upper = triu(A, format='csr')
x = guess.copy()
r = b - A @ x # this is the error vector b-Ax
delta_0 = delta = npla.norm(r) # size of the error vector
curr_iter = 0
while curr_iter < max_iter:
if delta <= epsilon * delta_0: # if this is true, the error is
# sufficiently small, so we stop.
return x, curr_iter, delta_0, delta
L_inv_r = la.spsolve_triangular(lower, r, lower=True)
d_inv_L = diag * L_inv_r
x += la.spsolve_triangular(upper, d_inv_L, lower=False)
r = b - A @ x
delta = npla.norm(r)
curr_iter += 1
return x, curr_iter-1, delta_0, delta
def L_1(A, b, guess, max_iter=1000, epsilon=1e-6):
l_1 = sum(abs(A), axis=1)
l_1 = diags(squeeze(asarray(l_1)))
x = guess.copy()
r = b - A @ x # this is the error vector b-Ax
delta_0 = delta = npla.norm(r) # size of the error vector
curr_iter = 0
while curr_iter < max_iter:
if delta <= epsilon * delta_0: # if this is true, the error is
# sufficiently small, so we stop.
return x, curr_iter, delta_0, delta
x += la.spsolve_triangular(l_1, r)
r = b - A @ x
delta = npla.norm(r)
curr_iter += 1
return x, curr_iter-1, delta_0, delta