数学中的群论常被视为抽象代数的"高山",但今天我们要用Python和可视化工具,把它变成一场互动游戏。想象一下,当你敲几行代码就能让抽象的数学概念在屏幕上跳舞,群论还会那么可怕吗?我们将从整数加法群开始,一步步构建非阿贝尔群,用动态图形揭示封闭性、逆元等概念的本质差异。
在开始编程前,先确保你的Python环境安装了这些关键库:
bash复制pip install sympy matplotlib networkx
群的定义可以简化为四个公理:
让我们用整数加法群验证这些特性。在Python中,我们可以这样表示:
python复制class IntegerAdditiveGroup:
def __init__(self, elements):
self.elements = set(elements)
def operation(self, a, b):
return a + b # 加法作为二元运算
def is_closed(self):
for a in self.elements:
for b in self.elements:
if self.operation(a, b) not in self.elements:
return False
return True
def has_identity(self):
return 0 in self.elements # 加法单位元是0
def has_inverses(self):
for a in self.elements:
if -a not in self.elements:
return False
return True
测试一个简单的整数群:
python复制Z3 = IntegerAdditiveGroup([-1, 0, 1])
print(f"封闭性: {Z3.is_closed()}") # 输出: True
print(f"单位元: {Z3.has_identity()}") # 输出: True
print(f"逆元: {Z3.has_inverses()}") # 输出: True
理解群结构的最佳方式是通过可视化。我们将用networkx生成凯莱图,展示元素间的运算关系。
首先创建一个模3加法群的凯莱图:
python复制import networkx as nx
import matplotlib.pyplot as plt
def draw_cayley_graph(elements, operation):
G = nx.DiGraph()
G.add_nodes_from(elements)
for a in elements:
for b in elements:
result = operation(a, b)
G.add_edge(a, result, label=f"+{b%3}")
pos = nx.circular_layout(G)
plt.figure(figsize=(8,6))
nx.draw(G, pos, with_labels=True, node_size=1000, node_color='lightblue')
edge_labels = nx.get_edge_attributes(G, 'label')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)
plt.title("模3加法群的凯莱图")
plt.show()
draw_cayley_graph([0,1,2], lambda a,b: (a+b)%3)
生成的图形会清晰显示三个节点(0,1,2)及其通过加法模3的转换关系。这种可视化能直观展示:
群表是另一种有效的可视化工具。下面生成一个对称群S3的群表:
python复制from sympy.combinatorics import Permutation, PermutationGroup
def generate_group_table():
S3 = PermutationGroup([
Permutation([0,1,2]), # 恒等
Permutation([1,0,2]), # 交换前两个
Permutation([0,2,1]), # 交换后两个
Permutation([2,0,1]), # 轮换
Permutation([1,2,0]), # 逆轮换
Permutation([2,1,0]) # 完全逆序
])
elements = list(S3.elements)
table = []
for a in elements:
row = []
for b in elements:
row.append(a*b)
table.append(row)
print("S3群表:")
for row in table:
print([p.cyclic_form for p in row])
运行后会输出6×6的群表,展示这个非阿贝尔群中元素如何相互作用。注意观察表格不对称的地方,这正是群非交换性的体现。
阿贝尔群(交换群)的核心特征是运算可交换:a·b = b·a。让我们通过代码比较两种典型群:
整数加法群(阿贝尔群)示例:
python复制Z5 = IntegerAdditiveGroup([0,1,2,3,4])
print("验证交换律:")
for a in Z5.elements:
for b in Z5.elements:
if Z5.operation(a,b) != Z5.operation(b,a):
print("非交换群!")
break
else:
continue
break
else:
print("是阿贝尔群") # 会输出这个
对称群S3(非阿贝尔群)示例:
python复制p1 = Permutation([1,0,2]) # 交换前两个元素
p2 = Permutation([0,2,1]) # 交换后两个元素
print(f"p1*p2 = {p1*p2}") # [2,0,1]
print(f"p2*p1 = {p2*p1}") # [1,2,0]
通过这个对比可以清晰看到,在S3群中改变运算顺序会得到不同结果,这是非阿贝尔群的典型特征。我们可以进一步可视化这种差异:
python复制def visualize_non_abelian():
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5))
# 阿贝尔群示例(旋转对称)
angles = [0, 120, 240]
colors = ['red', 'green', 'blue']
for angle, color in zip(angles, colors):
ax1.plot([0, np.cos(np.radians(angle))],
[0, np.sin(np.radians(angle))],
color=color)
ax1.set_title("阿贝尔群(交换操作)")
# 非阿贝尔群示例(旋转+反射)
triangle = np.array([[0,0], [1,0], [0.5,0.866]])
transformed1 = np.dot(triangle, [[0,1],[1,0]]) # 反射
transformed2 = np.roll(transformed1, 1, axis=0) # 旋转
ax2.plot(triangle[:,0], triangle[:,1], 'r-')
ax2.plot(transformed1[:,0], transformed1[:,1], 'g--')
ax2.plot(transformed2[:,0], transformed2[:,1], 'b:')
ax2.set_title("非阿贝尔群(操作顺序影响结果)")
plt.show()
这个对比图生动展示了为什么在非阿贝尔群中操作顺序至关重要——先旋转后反射与先反射后旋转会产生完全不同的结果。
理解了基本原理后,我们可以尝试构建更复杂的群。下面实现一个二面体群D4(正方形的对称群):
python复制class DihedralGroup:
def __init__(self, n):
self.n = n # 边数
self.elements = []
# 生成所有旋转和反射
for r in range(n): # 旋转
for s in [0,1]: # 是否反射
self.elements.append((r,s))
def operation(self, a, b):
r1, s1 = a
r2, s2 = b
new_r = (r1 + (-1)**s1 * r2) % self.n
new_s = (s1 + s2) % 2
return (new_r, new_s)
def is_abelian(self):
for a in self.elements:
for b in self.elements:
if self.operation(a,b) != self.operation(b,a):
return False
return True
D4 = DihedralGroup(4)
print(f"D4是阿贝尔群吗? {D4.is_abelian()}") # 输出: False
我们可以进一步可视化D4群的对称操作:
python复制def visualize_d4():
square = np.array([[0,0], [1,0], [1,1], [0,1], [0,0]])
fig, axes = plt.subplots(2, 4, figsize=(16,8))
for i, (r, s) in enumerate(D4.elements):
ax = axes[i//4][i%4]
transformed = square.copy()
# 应用旋转
theta = r * 90
rot = np.array([[np.cos(np.radians(theta)), -np.sin(np.radians(theta))],
[np.sin(np.radians(theta)), np.cos(np.radians(theta))]])
transformed = np.dot(transformed, rot.T)
# 应用反射
if s == 1:
transformed[:,0] *= -1
ax.plot(transformed[:,0], transformed[:,1], 'b-')
ax.set_title(f"旋转{r*90}° + {'反射' if s else ''}")
ax.axis('equal')
plt.tight_layout()
plt.show()
运行这段代码会生成8个子图,展示正方形所有可能的对称变换。通过观察这些变换的组合,可以深入理解非阿贝尔群的操作不可交换特性。
群论不仅是抽象数学,在现代密码学中有直接应用。让我们实现一个简单的基于椭圆曲线群的加密演示:
python复制from sympy import symbols, Eq, solve
class EllipticCurveGroup:
def __init__(self, a, b, p):
self.a = a
self.b = b
self.p = p # 素数模
def add(self, P, Q):
if P == "O": return Q
if Q == "O": return P
x1, y1 = P
x2, y2 = Q
if x1 == x2 and (y1 + y2) % self.p == 0:
return "O" # 无穷远点
if P == Q:
m = (3*x1**2 + self.a) * pow(2*y1, -1, self.p) % self.p
else:
m = (y2 - y1) * pow(x2 - x1, -1, self.p) % self.p
x3 = (m**2 - x1 - x2) % self.p
y3 = (m*(x1 - x3) - y1) % self.p
return (x3, y3)
def multiply(self, P, n):
result = "O"
current = P
while n > 0:
if n % 2 == 1:
result = self.add(result, current)
current = self.add(current, current)
n = n // 2
return result
# 选择曲线 y² = x³ + 2x + 3 mod 97
ecg = EllipticCurveGroup(2, 3, 97)
G = (3, 6) # 生成元
# Alice的私钥
a_private = 36
A_public = ecg.multiply(G, a_private)
# Bob的私钥
b_private = 58
B_public = ecg.multiply(G, b_private)
# 共享密钥
shared_a = ecg.multiply(B_public, a_private)
shared_b = ecg.multiply(A_public, b_private)
print(f"Alice计算得到的共享点: {shared_a}")
print(f"Bob计算得到的共享点: {shared_b}") # 两者相同
这个实现展示了如何利用椭圆曲线群的离散对数难题构建密钥交换协议。注意观察:
理解了基本群结构后,我们可以探索更高级的概念。群同态是保持群结构的映射,下面检查两个群之间是否存在同态:
python复制def is_homomorphism(G, H, f):
"""检查f: G → H是否是群同态"""
for a in G.elements:
for b in G.elements:
if H.operation(f(a), f(b)) != f(G.operation(a, b)):
return False
return True
# 示例:检查从Z4到Z2的自然投影
class Z4:
elements = [0,1,2,3]
operation = lambda a,b: (a+b)%4
class Z2:
elements = [0,1]
operation = lambda a,b: (a+b)%2
f = lambda x: x % 2
print(f"f是群同态吗? {is_homomorphism(Z4, Z2, f)}") # 输出: True
群作用是另一个重要概念,描述群如何"作用"在其他数学对象上。下面实现一个群作用于集合的例子:
python复制def group_action(group, X, action_func):
"""验证群作用是否有效"""
# 验证单位元作用不变
e = next(x for x in group.elements if all(
group.operation(x,y)==y and group.operation(y,x)==y
for y in group.elements))
for x in X:
if action_func(e, x) != x:
return False
# 验证兼容性
for g in group.elements:
for h in group.elements:
for x in X:
if action_func(group.operation(g,h), x) != action_func(g, action_func(h, x)):
return False
return True
# 示例:D4群作用于正方形的顶点
D4 = DihedralGroup(4)
square_vertices = [(1,1), (-1,1), (-1,-1), (1,-1)]
def square_action(group_element, vertex):
r, s = group_element
x, y = vertex
# 旋转
theta = r * 90
rot = np.array([[np.cos(np.radians(theta)), -np.sin(np.radians(theta))],
[np.sin(np.radians(theta)), np.cos(np.radians(theta))]])
new_x, new_y = np.dot(rot, [x,y])
# 反射
if s == 1:
new_x *= -1
return (round(new_x), round(new_y))
print(f"D4在正方形上的作用是有效的吗? {group_action(D4, square_vertices, square_action)}")