复数与矩阵

矩阵

1
2
n = 3
a = np.array([[1 + 2j, 3 - 4j], [5 + 6j, 7 - 8j]])

每个标题可以点,维基百科有图、甚至动图,详细介绍

转置

行变列,列变行,一般在右上角标注 \(^T\) 表示

1
a_zz = np.transpose(s)

共轭

这个是对复数的,就是把复数的复数部分,变成相反数

1
a_ge = np.conj(s)

余子式

除去这个元素所在行、所在列 剩下的矩阵行列式

行列式

对于二维,交叉相乘相减,对于三维,选一行或者一列,这一行 “每个元素” 分别乘以 它的余子式,然后求和,以此类推

1
det_A = np.linalg.det(A)

单位矩阵

对角线为1,其他全部0,对于n维单位矩阵一般表示为 \(I_n\)

求逆

对于矩阵 \(AB=BA=I_n\) (单位矩阵),一般在右上角标注 \(^{-1}\) 表示

1
inv_A = np.linalg.inv(A)  # 计算逆矩阵

伴随矩阵

每个元素的余子式的行列式值,组成的矩阵,再求转置

如果这个矩阵可逆,也可以用下面的求

1
2
3
4
det_A = np.linalg.det(A)  # 计算行列式
inv_A = np.linalg.inv(A) # 计算逆矩阵
# 下面这个不是矩阵乘法,仅仅是向量内积(点乘),也就是对应位置相乘
adj_A = det_A * inv_A # 计算伴随矩阵

矩阵乘法

注意,不要和向量的点乘、叉乘混淆,矩阵乘法没有方向,平时说的向量乘法相当于矩阵的叉乘

记作\(C=AB或C=A\cdot B\) 新矩阵每个元素=左行乘右列再求和,所以两个矩阵行列必须是\(A(m, n),B(n, k)\),前面的列数等于后面的行数,最后 \(C\)的形状是 \(C(m,k)\)

1
2
3
4
5
6
A = [[1, 2]]
B = [[2], [1]]
# 虽然叫 dot 但是这不是向量点乘!
C = np.dot(A, B)
# C = [[4]]
# 不能 C = A*B,因为它相当于 np.multiply 只是对应位置相乘,A和B的形状必须完全相同

向量


下面的是对向量来说的,但是和矩阵相似,而且容易混淆


向量点乘(内积)

是标量!可以理解为投影。这个不是针对矩阵的,这个是向量计算的,得到的是一个数,,实际操作中,两个向量对应位置上的值 相乘相加 的操作

\(\vec{a} = [x_1,y_1,z_1]\)\(\vec{b} = [x_2,y_2,z_2]\), 夹角 \(\theta\)

\[ \vec{a} \cdot \vec{b} = x_1x_2+y_1y_2+z_1z_2 \] 方向,\(x_1x_2\)平行四边形对角线

这个其实类似于矩阵的乘法,只不过实际操作中,如果ab是二维的,需要转置一下b(这里b是一维的,不转置也行)

1
2
3
4
5
6
7
8
9
10
11
12
13
a = [1, 2, 3]
b = [4, 5, 6]
# 一维的不存在行、列,转置没有意义,如下,二维的必须要转置,按照矩阵乘法来,结果也不是32而是[[32]]
# a = [[1, 2, 3]]
# b = [[4, 5, 6]]
bt = np.transpose(b)
print(bt)
# [4 5 6]

print(np.dot(a, bt))
# 32
print(np.dot(a, b))
# 32

但是numpy.dot中转置不转置,结果一样。。。。实际矩阵计算应该是 [3] 而不是 3

应用,刚才说了,其实就是投影,也就是 \(\cos\theta\) \[ \cos\theta = \frac{\vec{a}\vec{b}}{|\vec{a}||\vec{b}|} \]

1
2
3
4
5
6
7
8
a = [1, 0, 0]
b = [1, 3**0.5, 0]
# 求模
a_ = np.linalg.norm(a)
b_ = np.linalg.norm(b)
print(a_, b_)
print(np.dot(a, b) / (a_ * b_))
# 输出的是45°夹角余弦值

叉乘

外积(cross product)又称叉积、叉乘、向量积(vector product)

向量叉乘几何意义是面积,方向与二者垂直,结果是标量!

!注意,不是 外积:Outer product,是 np.cross 而不是 np.outer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a = [1, 0, 0]
b = [1, 3**0.5, 0]
# 求模
a_ = np.linalg.norm(a)
b_ = np.linalg.norm(b)
print(a_, b_)
print(np.cross(a, b) / (a_ * b_))
# 输出的是
# [0. 0. 1.73205081]

# 如果a b是二维
# a = [1, 0]
# b = [1, 3**0.5]
# 垂直方向没有,输出的是一个数
# 1.73205081

numpy函数说明

首先注意,一维向量 不等于 一维矩阵

  • 一维向量 [1, 2, 3]
  • 一维矩阵 [[1, 2, 3]]

尤其是在使用 dot 时,结果完全不一样

一维向量

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
a = [1, 2, 3]
b = [4, 5, 6]
# 转置不变,因为不存在行列,转置无意义
bt = np.transpose(b)
print(bt)

# 以下几个结果完全一样
print("dot_t", np.dot(a, bt))
# 32
print("dot", np.dot(a, b))
# 32
print("inner_t", np.inner(a, bt))
# 32
print("inner", np.inner(a, b))
# 32
print("matmul_t", np.matmul(a, bt))
# 32
print("matmul", np.matmul(a, b))
# 32

# 相当于把ab看做二维的,然后把a转置,在矩阵相乘
# np.outer不是叉乘(np.cross)
print("outer\n", np.outer(a, b))
# [[ 4 5 6]
# [ 8 10 12]
# [12 15 18]]

一维向量,dotinnermatmul 没任何区别

一维矩阵

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
# 本来形状是 (1, 3)
a = [[1, 2, 3]]
b = [[4, 5, 6]]
# 转置变成 (3, 1)
bt = np.transpose(b)
print(bt)

# 矩阵乘法,前后两个矩阵形状必须是 (m,n)(n,k)=(m,k)
# 前面列,等于后面行,相乘结果(m,k)
# 不满足 np.dot 直接报错
print("dot_t", np.dot(a, bt))
# [[32]]
# print("dot", np.dot(a, b))
# error

print("matmul_t", np.matmul(a, bt))
# [[32]]
# print("matmul", np.matmul(a, b))
# error

# np.inner 要求正好相反,对于 bt 反而报错。。。。
# print("inner_t", np.inner(a, bt))
# error
print("inner", np.inner(a, b))
# [[32]]


# 相当于把ab看做二维的,然后把a转置,在矩阵相乘
# np.outer不是叉乘(np.cross)
print("outer\n", np.outer(a, b))
# 结果和前面的一维向量没区别
# [[ 4 5 6]
# [ 8 10 12]
# [12 15 18]]

一维矩阵,dotinnermatmul 结果没有区别,但是对于矩阵乘法定义上有区别, 要求 np.inner不一样

但是推荐使用 np.dot 或者 np.matmul,使用时按照线性代数里的定义矩阵乘法即可

高维矩阵

与一维矩阵没有区别

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
a = [[1, 2, 3], [2, 3, 4]]
b = [[4, 5], [6, 7], [8, 9]]
bt = np.transpose(b)
print(bt)
print(np.shape(a))
# (2, 3)
print(np.shape(b))
# (3, 2)
print(np.shape(bt))
# (2, 3)

# print("dot,t", np.dot(a, bt))
# error
print("dot\n", np.dot(a, b))
# [[40 46]
# [58 67]]

# print("matmul,t\n", np.matmul(a, bt))
# error
print("matmul\n", np.matmul(a, b))
# [[40 46]
# [58 67]]

# print("inner", np.inner(a, b))
# error
print("inner,t\n", np.inner(a, bt))
# [[40 46]
# [58 67]]

np.dot 或者 np.matmul 一样,速度方面懒得测试了

复数

复数在python的表示

1
a = (1 + 1j)

数学运算定义

加法: \[(a+b)+(c+d)=(a+c)+(b+d)i\]

减法:

\[(a+bi)-(c+di)=(a-c)+(b-d)i\]

乘法:

\[ \begin{align} (a+bi)(c+di)&=ac+bci+adi+bdi^2\\&=(ac-bd)+(bc+adi) \end{align} \]

除法

\[ \begin{align} \frac{(a+bi)}{(c+di)} &=\frac{(a+bi)(c-di)}{(c+di)(c-di)}\\ &=\frac{ac+bci-adi-bdi^2}{c^2-(di)^2}\\ &=\frac{(ac+bd)+(bc-ad)i}{c^2+d^2}\\ &=(\frac{ac+bd}{c^2+d^2})+(\frac{bc-ad}{c^2+d^2})i \end{align} \]

矩阵乘积

不管 np.inner 了,测试 np.dot 或者 np.matmul

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
a = [[1+1j, 2+2j, 3+3j], [2+2j, 3+3j, 4+4j]]
b = [[4+4j, 5+5j], [6+6j, 7+7j], [8+8j, 9+9j]]
bt = np.transpose(b)
print(a)
print(bt)

print((1+1j)*(4+4j))
# 8j
print((1+1j)*(4+4j) + (2+2j)*(6+6j) + (3+3j)*(8+8j))
# 80j
print(1*4 + 2*6 + 3*8)
# 40

print("dot\n", np.dot(a, b))
# [[0. +80.j 0. +92.j]
# [0.+116.j 0.+134.j]]
print("matmul\n", np.matmul(a, b))
# [[0. +80.j 0. +92.j]
# [0.+116.j 0.+134.j]]

两个没区别

其他

正交归一

验证是否正交归一?

  • 对于实数矩阵,矩阵 乘以 矩阵的转置
  • 对于实数矩阵,矩阵 乘以 矩阵的共轭转置
1
2
t1 = np.dot(A, np.conj(np.transpose(A)))
t2 = np.dot(np.real(A), np.transpose(np.real(A)))

得到的结果,应该是单位矩阵

特征值

注意有两个函数 np.linalg.eigh()np.linalg.eig()

  • np.linalg.eig() 用于计算任意矩阵的特征值和特征向量,
  • np.linalg.eigh() 用于计算厄密矩阵或实对称矩阵的特征值和特征向量,即特征值一定为实数,因为矩阵是实数,所以特征值是排序的

另外,模式能量计算中,频率是特征值的 根号

QR分解

找到正交基

1
2
3
4
5
6
from scipy.linalg import qr
import numpy as np

n = 3
H = np.random.randn(n, n)
Q, R = qr(H)

本文作者:yuhldr
本文地址https://yuhldr.github.io/posts/af3ac84b.html
版权声明:转载请注明出处!