目录
第一部分:矩阵和基本运算
第二部分:高级操作
第三部分:特征值与特征向量
- 线性代数导论
如果不了解复数,建议先阅读上一篇关于复数的博客,以便更好学习线性代数的相关知识。
后面练习用的是Python内置的复数模块(cmath),下面介绍一下cmath的一些特殊语法:
1、z代表复数,实部则为z.real,虚部为z.imag
2、将j放在实数之后来表示虚数,如3.14j
3、一个实数加一个虚数表示复数
4、abs可以计算虚数的模
在学习之前,导入必要的库和定义矩阵:
from typing import Listimport math
import cmathMatrix = List[List[complex]]
第一部分:矩阵和基本运算
- 矩阵和向量
文章图片
,是一个2*2的矩阵。
文章图片
表示矩阵A的第i行第j列的元素,如
文章图片
。
一个n * m的矩阵有n行和m列,形式如下图:
文章图片
量子计算使用复数矩阵:矩阵的元素可以是复数,比如
文章图片
是有效的复数矩阵。
一个向量是n * 1的矩阵,如
文章图片
就是一个3*1的向量。因为向量的宽度固定为1,所以可以只用一个索引来表示向量元素。如
文章图片
。
- 矩阵加法
文章图片
。
使用Python定义矩阵加法:
输入:
1.一个n * m的矩阵A,表现为一个二维列表
2.一个n * m的矩阵B,表现为一个二维列表
目标:
返回矩阵A与B的和,一个n * m的矩阵,表现为一个二维列表
# 创建全0矩阵
def create_empty_matrix(n: int, m:int) -> Matrix:
re = []
for i in range(n):
tmp = []
for j in range(m):
tmp.append(0)
re.append(tmp)
return re# 矩阵加法
def matrix_add(a: Matrix, b:Matrix) -> Matrix:
# 获取矩阵大小
n = len(a)
m = len(b)# 创建n * m的全0矩阵
ans = create_empty_matrix(n, m)# 计算矩阵元素值
for i in range(n):
for j in range(m):
x = a[i][j]
y = b[i][j]ans[i][j] = x + yreturn ans
- 标量乘法
文章图片
标量乘法有以下特性:
文章图片
文章图片
文章图片
使用Python定义标量乘法:
输入:
1.一个标量x
2.一个n * m的矩阵A
目标:
返回x * A,一个n * m的矩阵
# 标量乘法
def scalar_mult(x: complex, a: Matrix) -> Matrix:
n = len(a)
m = len(a[0])# 创建n * m的全0矩阵
ans = create_empty_matrix(n, m)# 计算矩阵元素值
for i in range(n):
for j in range(m):
ans[i][j] = x * a[i][j]return ans
- 矩阵乘法
文章图片
通过下面简例理解下上面公式:
文章图片
矩阵乘法有如下性质:
文章图片
文章图片
文章图片
,其中x为标量
注意:矩阵乘法是不可交换的,AB很少等于BA。
矩阵乘法的另一个重要性质是,一个矩阵乘以一个向量会得到另一个向量。
下图是一个特殊的单位矩阵
文章图片
,主对角线上是1,其他地方都是0。它的特殊之处在于,如果
文章图片
是一个m * n的矩阵,那么任意矩阵A(大小n * m),存在
文章图片
。所以
文章图片
又被称为单位矩阵,作为一个乘法单元,它与数字1是等价的。
文章图片
使用Python定义矩阵乘法:
输入:
1.一个n * m的矩阵A
2.一个m * k的矩阵B
目标:
返回矩阵AB,一个n * k的矩阵
# 矩阵乘法
def matrix_mult(a: Matrix, b: Matrix) -> Matrix:
# 获取输出矩阵大小
n = len(a)
m = len(b[0])
# 创建n * m全0矩阵
ans = create_empty_matrix(n, m)# 计算矩阵元素值
for i in range(n):
for j in range(len(b[0])):
tmp = 0
for k in range(len(b)):
tmp += a[i][k] * b[k][j]
ans[i][j] = tmpreturn ans
- 逆矩阵
文章图片
,那么A是可逆的,
文章图片
称为A的逆矩阵。
然后对于兼容大小的B和C,我们会发现一些有趣的事情:
文章图片
文章图片
一个方阵有一个叫做行列式的性质,矩阵A的行列式写成|A|,必须是方阵(n * n)才有行列式。
对于一个2 * 2的矩阵,行列式的定义是:
文章图片
对于一个n阶矩阵,只有当
文章图片
,才可逆。这里介绍一个二阶矩阵求逆公式:
文章图片
使用Python定义二阶矩阵求逆
输入:
1.一个2 * 2的矩阵A
目标:
返回A的可逆矩阵
文章图片
# 二阶矩阵求逆
def matrix_inverse(a: Matrix) -> Matrix:
# 获取矩阵元素
det_a = a[0][0] * a[1][1] - a[0][1] * a[1][0]
if det_a == 0:
print("A don't have inverse matrix")
return# 创建全0矩阵
n = len(a)
ans = create_empty_matrix(n, n)
# 获取元素
g = a[0][0]
h = a[0][1]
i = a[1][0]
j = a[1][1]
# 计算逆矩阵,根据公式
ans[0][0] = j / (g*j - h*i)
ans[0][1] = (-h) / (g*j - h*i)
ans[1][0] = (-i) / (g*j - h*i)
ans[1][1] = g / (g*j - h*i)return ans
- 转置运算
文章图片
,本质是矩阵在对角线上的反射,即
文章图片
。n * m的矩阵A,它的转置矩阵
文章图片
,大小为m * n,如下图:
文章图片
对称矩阵是一个方阵,它是自身的转置:
文章图片
。换句话说,它在主对角线上具有反射对称性(因此得名),例如,这个矩阵是对称的:
文章图片
矩阵乘积的转置等于矩阵转置后的乘积,按相反的顺序取:
文章图片
用Python定义矩阵的转置:
输入:
1.一个n * m的矩阵A
目标:
返回m * n的转置矩阵
文章图片
# 转置矩阵
def transpose(a: Matrix) -> Matrix:
n = len(a)
m = len(a[0])# 创建全0矩阵
ans = create_empty_matrix(m, n)
# 给转置矩阵赋值
for i in range(n):
for j in range(m):
ans[j][i] = a[i][j]return ans
- 共轭
文章图片
有个特性需要记住,矩阵的乘积的共轭,等于矩阵共轭的乘积:
文章图片
使用Python定义矩阵共轭:
输入:
1.一个n * m的矩阵A
目标:
返回A的共轭矩阵,n * m的
文章图片
# 矩阵共轭
def conjugate(a: Matrix) -> Matrix:
n = len(a)
m = len(a[0])# 创建全0矩阵
ans = create_empty_matrix(n, m)
for i in range(n):
for j in range(m):
ans[i][j] = complex(a[i][j].real, -a[i][j].imag)return ans
- 伴随矩阵
文章图片
如果一个矩阵等于它的伴随矩阵,我们称其为厄米矩阵:
文章图片
,例如
文章图片
矩阵乘积的伴随可以进行这样的转换:
文章图片
使用Python定义伴随矩阵
输入:
1.一个n * m的矩阵A
目标:
返回A的伴随矩阵
文章图片
,大小为m * n
# 矩阵伴随
def adjoint(a: Matrix) -> Matrix:
# 矩阵转置
tmp = transpose(a)
# 矩阵共轭
ans = conjugate(tmp)return ans
- 酉矩阵
文章图片
只有当一个n * n的方阵满足
文章图片
时,它是可酉的。例如:
文章图片
使用Python判断一个矩阵是否为酉矩阵
输入:
1.一个n * m的矩阵A
目标:
判断这个矩阵是否为酉矩阵,输出为True或False
tip:在计算机上使用float时会有误差(舍入误差),Python中又一个approx函数,可以用来检查2个数字是否足够接近。
# 判断矩阵是否酉矩阵
from pytest import approxdef is_matrix_unitary(a: Matrix) -> bool:
# 如果非方阵,则不是酉矩阵
if len(a) != len(a[0]):
return False
# a的伴随矩阵
tmp_adj = adjoint(a)
print(tmp_adj)# a乘以它的伴随矩阵
tmp_re = matrix_mult(a, tmp_adj)
print(tmp_re)
# 判断结果是否为单位矩阵,如果不是返回False
for i in range(len(tmp_re)):
for j in range(len(tmp_re[0])):
if i == j:
if approx(tmp_re[i][j]) != 1:
return False
elif approx(tmp_re[i][j]) != 0:
return Falsereturn True
- 小结
第二部分:高级操作
- 内积
文章图片
:
文章图片
我们把这个过程分解下便于理解,一个1 * n的矩阵(一个n * 1的向量的伴随矩阵)乘以一个n * 1的向量,结果是一个1 * 1的矩阵(它等价于一个标量),内积的结果就是这个标量。换句话说,计算两个向量的内积,取对应的元素
文章图片
和
文章图片
,然后将
文章图片
的共轭复数乘以
文章图片
,再将这些乘积相加:
文章图片
举个简单的例子:
文章图片
内积具有以下特性:
文章图片
文章图片
文章图片
文章图片
(一个向量乘以一个酉矩阵,与向量自己的内积相同)
使用Python定义内积
输入:
1.一个n * 1的向量V
2.一个n * 1的向量W
目标:
返回一个复数 - 内积
# 内积
def inner_prod(v: Matrix, w: Matrix) -> complex:
# 求v的伴随矩阵
v_adj = adjoint(v)
# 求内积
ans = matrix_mult(v_adj, w)
# 内积是非负实数,虚部为0,所以取结果的实部
ans = ans[0][0].realreturn ans
- 向量范数
文章图片
,这将向量压缩成一个非负的实数。如果向量表示空间中的坐标,则范数恰好是向量长度。如果一个向量的模等于1,那么它就被称为标准化向量。
使用Python定义向量归一化:
输入:
1.一个非0的n * 1的向量
目标:
返回V的向量归一化结果,一个n * 1的向量
文章图片
# 向量归一化
def normalize(v : Matrix) -> Matrix:
# 求内积
tmp_vvip = inner_prod(v, v)
# 求的开方
tmp_vvip_sqrt = math.sqrt(tmp_vvip.real)
# 求归一化向量
ans = scalar_mult((1 / tmp_vvip_sqrt), v)return ans
- 外积
文章图片
。也就是说,一个n * 1的向量和一个m * 1的向量的外积是一个n * m的矩阵。如果我们用X来代表V和W的外积,那么
文章图片
。下图是一个简单的例子:
文章图片
用Python定义外积
输入:
1.一个n * 1的向量V
2.一个m * 1的向量W
目标:
返回V和W的外积,一个n * m的矩阵X
# 外积
def outer_prod(v: Matrix, w:Matrix) -> Matrix:
# 求w的伴随
w_adj = adjoint(w)
# 求外积
ans = matrix_mult(v, w_adj)return ans
- 张量积
对于n * m的矩阵A和k * l的矩阵B,他们的张量积表示为
文章图片
,是一个
文章图片
的矩阵,如下图:
文章图片
举一个简答的实例便于理解:
文章图片
注意:两个向量的张量积还是一个向量,比如n * 1的向量V和m * 1的向量W,
文章图片
是一个
文章图片
的向量。
张量积有如下性质:
文章图片
文章图片
文章图片
用Python定义张量积:
输入:
1.n * m的矩阵A
2.k * l的矩阵B
目标:
返回A和B的张量积
文章图片
,一个
文章图片
的矩阵
# 张量积
def tensor_product(a: Matrix, b:Matrix) -> Matrix:
n = len(a)
m = len(a[0])
k = len(b)
l = len(b[0])
# 创建全0矩阵
ans = create_empty_matrix(n*k, m*l)# 计算张量积每个元素值
for a_i in range(n):
for a_j in range(m):
for b_i in range(k):
for b_j in range(l):
ans[a_i * k + b_i][a_j * l +b_j] = a[a_i][a_j] * b[b_i][b_j]return ans
- 小结
第三部分:特征值与特征向量 先看一个例子,下面是一个矩阵和向量的乘积:
文章图片
仔细观察下上面的示例,结果向量只是初始向量乘以一个标量,在上面的例子中是4。
一个非零的n * n的矩阵A,一个非零向量V,一个标量x,如果
文章图片
,那么x是A的一个特征值,V是A对于x的一个特征向量。
特征值和特征向量的性质在量子计算中有广泛的应用。
用Python定义寻找特征值
输入:
1.一个n * n的向量A
2.一个A的特征向量V
目标:
返回一个实数,A对于V的一个特征值
# 已知特征向量求特征值
def find_eigenvalue(a: Matrix, v: Matrix) -> float:
# 求av
tmp_vec = matrix_mult(a, v)
for i in range(len(tmp_vec)):
# 避免除0
if tmp_vec[i][0] != 0:
ev = tmp_vec[i][0] / v[i][0]
return evprint("There is no eigenvalue")
用Python定义已知二阶方阵特征值求特征变量
输入:
1.一个2*2的矩阵A
2.A的一个特征值x
目标:
返回任何与x相关的A的非零特征向量
推导过程:
文章图片
文章图片
文章图片
文章图片
文章图片
,
文章图片
TIP:一个矩阵和一个特征值将有多个特征向量(实际上是无穷多个),通过上面的推导可以得到特征向量的两个元素之间的对应关系,给定其中一个元素一个确定的值,就可以得到另一个元素,注意除0风险。
# 已知特征值求特征向量(二阶)
def find_eigenvector(a: Matrix, x: float) -> Matrix:
# 创建空白向量
ans = create_empty_matrix(2, 1)
# 给特征向量第一个元素赋值
ans[0][0] = 1
# 判断分母是否为0
if a[0][1] != 0:
ans[1][0] = (x - a[0][0]) / a[0][1]
return ans
elif (x - a[1][1]) != 0:
ans[1][0] = a[1][0] / (x - a[1][1])
return ans
else:
print("There is no eigenvector")
【量子计算基础02-线性代数】