1. 引言
当希望使用纯 Python 代码对整数 q 模矩阵进行操作,以演示使用学习误差 (Learning-With-Errors,LWE) 的基于格的加密方案的一些原理时,找到了 Thom Ives 编写的优秀代码“纯 Python 中无需 Numpy 或 Scipy 的 BASIC 线性代数工具”:
- https://github.com/ThomIves/BasicLinearAlgebraToolsPurePy(Python)
受该代码启发,编写了:
- https://github.com/davidi67/matrixzq(Python)
- 相关说明文档见:https://di-mgt.com.au/matrixzqdoc/html/index.html
matrixzq库提供了基本的 Python 函数而不是更复杂的类,以便可以轻松提取和使用底层列表的列表。
matrixzq
python库中:
- 包含对矩阵进行基于 Z q ( Z / q Z ) ℤ_q (ℤ/qℤ) Zq(Z/qZ) 运算的函数
- 不使用 Numpy 或 Scipy,而是使用纯 Python。
其中 q q q 是大于 1 的正整数。所有矩阵元素都应为 [ 0 , q − 1 ] [0, q-1] [0,q−1] 范围内的非负整数。所有计算均以 q q q 为模进行。
- 对于大多数矩阵算术运算(加、乘)来说,模数 q q q 不必是素数,
- 但 对于涉及除法的运算(求逆、求解), 模数 q q q必须是素数。
相关示例为:
import matrixzq as mzq
mzq.set_modulus(11)
print(f"q={mzq.get_modulus()}") # 11
# Invert a matrix
M = mzq.new_matrix([[2,3,7],[4,5,10],[9,0,7]])
print("M ="); mzq.print_matrix(M)
IM = mzq.invert(M)
print("IM=invert(M)=");mzq.print_matrix(IM)
# Multiply inverse by itself: should get identity
IMM = mzq.multiply(IM, M)
print(f"IM*M=\n{mzq.sprint_matrix(IMM)}")
I = mzq.identity_matrix(len(M))
print("IM*M==I:", mzq.equality(I, IMM))
assert(mzq.equality(I, IMM))
# Solve the matrix equation Ax = b
A = mzq.new_matrix([[1,1,1,1],[2,4,6,7],[4,5,3,5],[8,9,7,2]])
b = mzq.new_vector([6,0,4,5])
print("A=");mzq.print_matrix(A)
print("b=",end='');mzq.print_vector(b)
x = mzq.solve(A, b)
print("Solve Ax=b => x =", mzq.sprint_vector(x))
# Check result
ax = mzq.multiply(A, x)
print("Check Ax =", mzq.sprint_vector(ax))
print("Ax==b:", mzq.equality(ax, b))
assert(mzq.equality(ax, b))
# Show the transpose of a matrix
print("Transpose A^T=");mzq.print_matrix(mzq.transpose(A))
对应执行输出为:
q=11
M =
[2, 3, 7]
[4, 5, 10]
[9, 0, 7]
IM=invert(M)=
[5, 8, 4]
[1, 4, 9]
[3, 7, 6]
IM*M=
[1, 0, 0]
[0, 1, 0]
[0, 0, 1]
IM*M==I: True
A=
[1, 1, 1, 1]
[2, 4, 6, 7]
[4, 5, 3, 5]
[8, 9, 7, 2]
b=[6, 0, 4, 5]
Solve Ax=b => x = [10, 2, 8, 8]
Check Ax = [6, 0, 4, 5]
Ax==b: True
Transpose A^T=
[1, 2, 4, 8]
[1, 4, 5, 9]
[1, 6, 3, 7]
[1, 7, 5, 2]
参考资料
[1] Python matrix tools over ℤq