1import sys
2import numpy as np
3import numpy.linalg as la
4from scipy.io import loadmat
5
6
7data = loadmat("block_tridiagonal_system.mat")
8
9M = np.moveaxis(data["M"], -1, 0)
10K = np.moveaxis(data["K"], -1, 0)
11b = np.moveaxis(data["b"], -1, 0)
12x = np.moveaxis(data["x"], -1, 0)
13N, n, _ = M.shape
14
15
16A = np.zeros((N * n, N * n))
17for i in range(N):
18 A[i * n : (i + 1) * n, i * n : (i + 1) * n] = np.tril(M[i]) + np.tril(M[i], -1).T
19 A[((i + 1) % N) * n : ((i + 1) % N + 1) * n, i * n : (i + 1) * n] = K[i]
20 A[i * n : (i + 1) * n, ((i + 1) % N) * n : ((i + 1) % N + 1) * n] = K[i].T
21
22
23print(f"Number of blocks: {N}")
24print(f"Block size: {n}")
25print(f"Number of variables: {N * n}")
26print(f"Number of nonzeros: {N * n * (n + 1) // 2 + N * n * n}")
27σA = la.eigvalsh(A)
28nrmA = max(σA)
29condA = nrmA / min(σA)
30res = la.norm(A @ x.ravel() - b.ravel())
31nrmx, nrmb = la.norm(x.ravel()), la.norm(b.ravel())
32err = res / (nrmA * nrmx + nrmb)
33print(f"Condition number κ(A) = {condA:.17e}")
34print(f"Relative residual ‖Ax-b‖/‖b‖ = {res / nrmb:.17e}")
35print(f" ‖Ax-b‖")
36print(f"Backward error η = ────────── = {err:.17e}")
37print(f" ‖A‖‖x‖+‖b‖")
38
39sys.exit(0 if err < 10 * np.finfo(M.dtype).eps * N * n else 1)