北航数值分析作业二

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了北航数值分析作业二相关的知识,希望对你有一定的参考价值。

import cmath
from math import *
sgn = lambda x: 1 if x > 0 else -1


# 坑爹的赋值问题!注意下标从1开始
def init():
   A = [[0 for i in range(10)] for i in range(10)]
   for i in range(10):
      for j in range(10):
         ii, jj = i + 1, j + 1
         A[i][j] = sin(0.5 * ii + 0.2 * jj) if ii != jj else 1.52 * cos(ii + 1.2 * jj)
   return A


# 矩阵转置
def transposition(A):
   ans = [[0 for i in range(len(A))] for j in range(len(A[0]))]
   for i in range(len(A)):
      for j in range(len(A[i])):
         ans[j][i] = A[i][j]
   return ans


# 矩阵与矩阵相乘
def matrix_mul_matrix(A, B):
   assert len(A[0]) == len(B)
   ans = [[0] * len(B[0]) for i in range(len(A))]
   for i in range(len(ans)):
      for j in range(len(ans[i])):
         ans[i][j] = sum([A[i][k] * B[k][j] for k in range(len(B))])
   return ans


# 矩阵与向量相乘
def matrix_mul_vector(A, b):
   assert len(A[0]) == len(b)
   return [sum([A[i][j] * b[j] for j in range(len(b))]) for i in range(len(A))]


# 向量与向量相乘
def vector_mul_vector(A, B):
   assert len(A) == len(B)
   return sum([A[i] * B[i] for i in range(len(A))])


# 向量除以常数k
def div(v, k):
   return [v[i] / k for i in range(len(v))]


# 矩阵的拟上三角化
def quasi_upper_triangular(A):
   for i in range(0, len(A) - 2):  # i表示列数
      if not any([A[j][i] for j in range(i + 2, len(A))]): continue
      d = sqrt(sum([A[j][i] ** 2 for j in range(i + 1, len(A))]))
      c = -sgn(A[i + 1][i]) * d
      h = c * (c - A[i + 1][i])
      u = [0] * (i + 1) + [A[i + 1][i] - c] + [A[j][i] for j in range(i + 2, len(A))]
      p = div(matrix_mul_vector(transposition(A), u), h)
      q = div(matrix_mul_vector(A, u), h)
      t = vector_mul_vector(p, u) / h
      w = [q[i] - t * u[i] for i in range(len(q))]

      for i in range(len(A)):
         for j in range(len(A[i])):
            A[i][j] = A[i][j] - w[i] * u[j] - u[i] * p[j]


# 打印矩阵
def printMatrix(A,s):
   print(s)
   for i in range(len(A)):
      for j in range(len(A[i])):
         print(%.3f % A[i][j],  , end=,)
      print()
   print("=========")


def qr(B, C):
   for i in range(len(B) - 1):
      if not any([B[j][i] for j in range(i + 1, len(B))]): continue
      d = sqrt(sum([B[j][i] ** 2 for j in range(i, len(B))]))
      c = -sgn(B[i][i]) * d
      h = c * (c - B[i][i])
      u = [0] * (i) + [B[i][i] - c] + [B[j][i] for j in range(i + 1, len(B))]
      v = div(matrix_mul_vector(transposition(B), u), h)
      for i in range(len(B)):
         for j in range(len(B[i])):
            B[i][j] -= u[i] * v[j]
      p = div(matrix_mul_vector(transposition(C), u), h)
      q = div(matrix_mul_vector(C, u), h)
      t = vector_mul_vector(p, u) / h
      w = [q[i] - t * u[i] for i in range(len(q))]
      for i in range(len(C)):
         for j in range(len(C[i])):
            C[i][j] = C[i][j] - w[i] * u[j] - u[i] * p[j]


# 带双步位移的QR分解求特征根
def qr_with_double_shift(A):
   root = [0] * len(A)
   i = len(A) - 1
   k = 0  # 步数
   while i >= 0:
      if i == 0:
         root[0] = A[0][0]
         break
      elif abs(A[i][i - 1]) < epsilon:
         root[i] = A[i][i]
         i -= 1
         continue
      d1, d2, d3, d4 = A[i - 1][i - 1], A[i - 1][i], A[i][i - 1], A[i][i]
      delta = cmath.sqrt((d1 + d4) ** 2 - 4 * (d1 * d4 - d2 * d3))
      if i == 1 or abs(A[i - 1][i - 2]) < epsilon:
         (root[i], root[i - 1]) = (((d1 + d4) + delta) / 2, ((d1 + d4) - delta) / 2)
         i -= 2
         continue
      if k == L:
         print("didn‘t get all of the root after {} steps".format(L))
         break
      s, t = d1 + d4, d1 * d4 - d2 * d3
      M = matrix_mul_matrix(A, A)
      for i in range(len(M)):
         for j in range(len(M[0])):
            M[i][j] -= s * A[i][j]
         M[i][i] += t
      qr(M, A)
      k += 1
   return root


"""
高斯消去法适用范围:各阶主子式大于0
列主元高斯消去法适用范围:行列式值大于0
全主元高斯消去法适用范围:求解任意方程,可以求出一个解空间来
在本问题中,根据特征值求特征向量有两种方法:
   1.零点平移反幂法迭代求最接近lamda的特征值,也能求出特征向量,但它只能求出一个特征向量
   2.全主元高斯消去法,这种方法最完善
"""


# 全主元高斯消去法求方阵A关于特征根root的特征向量
def solve(A, root):
   n = len(A)
   for i in range(n):
      A[i][i] -= root
   ind = [i for i in range(n)]
   rank = n
   for i in range(n):
      x, y = i, i
      for row in range(i, n):
         for col in range(i, n):
            if abs(A[x][y]) < abs(A[row][col]):
               x, y = row, col
      if abs(A[x][y]) < epsilon:  # 最大值也为0,开始回代
         rank = i
         break
      # 将最大行与当前行进行交换
      A[x], A[i] = A[i], A[x]
      # 换列,第y列和第i列
      for row in range(n):
         A[row][y], A[row][i] = A[row][i], A[row][y]
      ind[i], ind[y] = ind[y], ind[i]
      # 单位化一行
      t=A[i][i]
      for j in range(i, n):
         A[i][j] /= t
      for row in range(i + 1, n):  # 第j行-A[j][i]倍的第i行
         t = A[row][i]
         if t==0:continue
         for col in range(i,n):
            A[row][col]-=t*A[i][col]
   # 回代过程
   for row in range(rank - 1, -1, -1):
      for j in range(row + 1, n):  # 第i行-A[i][j]倍的第j行
         # 这里一定要注意必须用t把A[i][j]存起来,否则A[i][j]就变成0了
         t = A[row][j]
         for k in range(j, n):
            A[row][k] -= t * A[j][k]
   # 构造特征向量空间,一定要注意把各个列给换回去!
   ans = [[0] * len(A) for i in range(n - rank)]
   for i in range(rank, n):
      for j in range(n):
         ans[i - rank][ind[j]] = -A[j][i]
      ans[i - rank][ind[i]] = 1
   return ans


epsilon = 1e-12
L = 0xffffff

A = init()
printMatrix(A,最初的矩阵)
quasi_upper_triangular(A)
printMatrix(A,拟对角化之后的矩阵)
roots = qr_with_double_shift(A)
print(各个特征根,roots)
printMatrix(A,qr双步位移法结束之后的矩阵)
for i in roots:
   if type(i) == float:
      A = init()
      x = solve(A, i)
      print(特征根, i, 对应的特征向量为\n, x)

 

以上是关于北航数值分析作业二的主要内容,如果未能解决你的问题,请参考以下文章

染色体基因芯片分析和第二代测序应用的区别

北航算法作业二

个人作业-Week2 案例分析

软工第0次作业

大连理工大学软件学院2022年秋季学期《矩阵与数值分析》上机作业

20165332第十周课下作业