SageMath 基本代数
archive time: 2024-09-05
这个算是 SageMath 的强项,不过还是不太方便
常见的环
我们在 SageMath 中进行代数运算的时候,例如微积分,或者后面会提到的向量和矩阵运算, 有时必须要指定一个环才能够计算出想要的结果,所以,了解 SageMath 中有哪些常见的环是非常有必要的
环简介
那么,什么是环呢?
环,英文是 Ring,是数学上的一个结构,这个结构满足如下性质:
- 是一个集合,并且在这个集合上定义有两种运算, 和
- 在集合中, 有么元,记为
- 在集合中,每个元素 都有对应的 逆元,记为 或
- 在集合中, 满足交换律,即对于集合元素 和 ,满足
- 在集合中, 满足结合律,即对于集合元素 , 和 ,满足
- 在集合中, 有么元,记为
- 在集合中, 满足结合律,即对于集合元素 , 和 ,满足
- 在集合中, 和 满足左分配律,即对于集合元素 , 和 ,满足
- 在集合中, 和 满足右分配律,即对于集合元素 , 和 ,满足
我们可以来验证一下,一个最常见的环就是整数环 ,在 SageMath 中表示为 ZZ
:
# 定义整数环,并且定义整数环上的三个元素,a,b 和 c
R = PolynomialRing(ZZ, "a, b, c")
(a, b, c) = (R.gen(0), R.gen(1), R.gen(2))
# 定义有加法和乘法
_ = a + b
_ = a * b
# 加法有么元
zero = R(0)
assert(a == zero + a == a + zero)
# 加法有逆元
assert(zero == a - a)
# 加法有交换律
assert(a + b == b + a)
# 加法有结合律
assert((a + b) + c == a + (b + c))
# 乘法有么元
one = R(1)
assert(a == a * one == one * a)
# 乘法有结合律
assert((a * b) * c == a * (b * c))
# 乘法有左分配律
assert(a * (b + c) == a * b + a * c)
# 乘法有右分配律
assert((a + b) * c == a * c + b * c)
此外还有例如有理数环 对应 QQ
,实数环 对应 RR
,以及复数环 对应 CC
但是对于这些常见的环,例如有理数环 ,我们有个更加熟悉的名称,那就是有理数域,这又是怎么回事呢?
域,对应英文 Field,也是数学上的一种结构,并且是 环 的一种特殊情况,域在满足环的所有特点的同时还满足:
- 在集合上,除了 么元,即 ,外的任一元素 都有对应 逆元,记作:
- 在集合上, 满足交换律,即对于集合元素 和 ,满足
# 定义实数域元素,其中 a 和 b 属于实数域
a, b = var("a, b", domain=RR)
# 除了 0 以外的元素 a 有逆元 1/a
one = RR(1)
assert(one == a / a)
# 乘法有交换律
assert(a * b == b * a)
所以并不存在整数域,因为整数没有除法,并且因为环的定义更加灵活,所以在 SageMath 中更加常用的是环
环的应用
下面的例子展现了在不同的环下运算结果的差异:
ratioRing.<t> = PolynomialRing(QQ)
realRing.<z> = PolynomialRing(RR)
tuple(map(lambda x: factor(x^2 - 2), (t, z)))
# => (t^2 - 2, (z - 1.41421356237310) * (z + 1.41421356237310))
可以发现,在有理数域上的变量 t
,因为不包含无理数 ,所以无法对 进行因式分解,而实数 z
就可以
对于某些预定义名称,如果不小心覆盖了其定义,可以使用
reset()
函数复原,例如reset("ZZ")
要判断某一个数或者变量是否属于某一个环或者域,我们可以通过 in
这个操作符来查看:
(t in ratioRing, z in ratioRing, 2 in ratioRing, sqrt(2) in ratioRing)
# => (True, False, True, False)
我们还可以通过 parent()
方法查看某一变量的归属,
并且在遇到冲突时,例如一个有理数和实数的运算,
那么 SageMath 会自动使用类型转换,尽可能的符合运算的定义,例如:
((2/3).parent(), (sqrt(2)).parent(), (2/3 + sqrt(2)).parent())
除了常见的这些环以外,SageMath 还支持很多数学结构,例如有限域以及矩阵环,下面是一些例子:
# 3 个元素的有限域
GF(3)
# 5 进数整数环
Zp(5)
# sqrt(3) 属于代数域
assert(sqrt(3) in QQbar)
线性代数
常见示例
SageMath 基于 Numpy 和 Scipy 等数学工具,自然是支持线性代数的, 包括矩阵,向量以及特征多项式等等,下面是一些示例:
A = Matrix([[1, 2, 3], [3, 2, 1], [1, 1, 1]])
w = vector([1, 1, -4])
(w * A, A * w, kernel(A))
# =>
# ((0, 0, 0),
# (-9, 1, -2),
# Free module of degree 3 and rank 1 over Integer Ring
# Echelon basis matrix:
# [ 1 1 -4])
其中 kernel()
函数返回对应矩阵的 左核,即
对于可以求解的矩阵,SageMath 会返回对应方程组的解,否则会返回一个错误:
A = Matrix([[1, 2, 3], [3, 2, 1], [1, 1, 1]])
Y = vector([0, -4, -1])
X = A.solve_right(Y) # A . X = Y
X
# => (-2, 1, 0)
# A.solve_right(w) 会返回错误
一般的特征值和特征向量可以通过 eigenvalues()
和 eigenvectors_right()
求得:
A = matrix([[0, 4], [-1, 0]])
(A.eigenvalues(), A.eigenvectors_right())
# => ([-2*I, 2*I],
# [(-2*I, [(1, -0.50000000000000000?*I)], 1),
# (2*I, [(1, 0.50000000000000000?*I)], 1)])
eigenvectors_left()
求解的是 ,
而 eigenvectors_right()
则是
矩阵定义
矩阵也可以在定义时指定所属的环或者域,例如:
AZ = matrix(ZZ, [[2, 0], [0, 1]])
AQ = matrix(QQ, [[2, 0], [0, 1]])
不同的定义计算结果也会有所不同,例如化为阶梯式:
(AZ.echelon_form(), AQ.echelon_form())
# =>
# (
# [2 0] [1 0]
# [0 1], [0 1]
# )
通常为了能够计算,并且计算结果,会将矩阵定义在 RDF
或者 CDF
上,即 实/复双精度域
矩阵空间
我们可以通过 MatrixSpace()
来定义矩阵空间,即所有满足某条件的矩阵构成的集合,例如
M = MatrixSpace(QQ, 3)
M
# => Full MatrixSpace of 3 by 3 dense matrices over Rational Field
如果想要定义非方阵,那么可以用 MatrixSpace(R, a, b)
来定义 R
上的 a
行 b
列的矩阵空间
我们还可以通过 basis()
函数查看矩阵空间的标准基:
B = M.basis()
(len(B), B[0, 1])
# =>
# (
# [0 1 0]
# [0 0 0]
# 9, [0 0 0]
# )
对于一个矩阵空间 M
,我们可以通过给定元素来构造一个矩阵:
A = M(range(2, 11))
A
# =>
# [ 2 3 4]
# [ 5 6 7]
# [ 8 9 10]
我们有很多种方式来展示矩阵,例如通过 rows()
或者 columns()
来获取矩阵所有的的行或者列
这非常有用,例如可以用矩阵的行来 张(span) 出一个向量空间:
V = VectorSpace(QQ, 3)
S = V.subspace(A.rows())
S
# =>
# Vector space of degree 3 and dimension 2 over Rational Field
# Basis matrix:
# [ 1 0 -1]
# [ 0 1 2]
稀疏线性代数
注意到上述矩阵空间都是 dense matrices
,也就是 稠密的,
但是现实中很多数据构成的矩阵并没有那么稠密,而是非常空的,或者称为 稀疏的
我们可以用相似的方式来运算稀疏线性代数, SageMath 的稀疏线性代数基于 PIDs,也就是主理想整数环
M = MatrixSpace(QQ, 8, sparse=True)
A = M.random_element(density=0.2)
(A, A.echelon_form())
# =>
# (
# [ 0 0 -6/23 0 -3 0 3 -1/7]
# [ 0 -1/3 0 0 0 0 0 0]
# [ 0 0 0 0 0 0 0 0]
# [ 0 -23/3 0 0 0 0 0 1]
# [ 0 -3 0 0 0 0 0 0]
# [ 0 0 0 0 0 0 0 0]
# [ 3 0 0 0 0 0 0 0]
# [ 0 0 0 15 1 1 0 0],
#
# [ 1 0 0 0 0 0 0 0]
# [ 0 1 0 0 0 0 0 0]
# [ 0 0 1 0 23/2 0 -23/2 0]
# [ 0 0 0 1 1/15 1/15 0 0]
# [ 0 0 0 0 0 0 0 1]
# [ 0 0 0 0 0 0 0 0]
# [ 0 0 0 0 0 0 0 0]
# [ 0 0 0 0 0 0 0 0]
# )
后记
SageMath 由于集成了很多代数方面的工具, 所以在一些数论和代数相关的方面, SageMath 比起一些付费的 CAS 还要全面, 但是由于一些命名和使用方式和主流的名称有所区别, 使用起来还需要多注意,特别是多个 CAS 混用的时候