目录

  • 前言
  • 复现步骤
  • 参考文献

前言

当初在上学的时候就被根系所震撼,恰好我们的《李代数和表示理论》课程也就上到根系那一章,前面几章的习题我还能动笔,后面的难以攀登,至今对根系知识充满敬畏之心,具体可以看作者写的习题解集。后来有缘在网上碰到一个用python绘制李代数E8的根系博客,甚是惊喜,便抽空复现了一下,效果如下。

复现用python绘制李代数E8的根系_李代数E8

复现步骤

第一步,安装依赖包cairocffi

pip install cairocffi

安装完这个包可能 还会报如下错误,解决方法就是下载 安装GTK应用程序,具体可以参考文献3,

import cairocffi as cairo
  File "C:\Users\bowen\AppData\Roaming\Python\Python39\site-packages\cairocffi\__init__.py", line 47, in <module>
    cairo = dlopen(
  File "C:\Users\bowen\AppData\Roaming\Python\Python39\site-packages\cairocffi\__init__.py", line 44, in dlopen
    raise OSError(error_message)  # pragma: no cover
OSError: no library called "cairo-2" was found
no library called "cairo" was found
no library called "libcairo-2" was found
cannot load library 'libcairo.so.2': error 0x7e
cannot load library 'libcairo.2.dylib': error 0x7e
cannot load library 'libcairo-2.dll': error 0x7e

第二步,复制如下代码到IDE直接运行

from itertools import product, combinations
import cairocffi as cairo
import numpy as np


COLORS = [(0.894, 0.102, 0.11),
          (0.216, 0.494, 0.72),
          (0.302, 0.686, 0.29),
          (0.596, 0.306, 0.639),
          (1.0, 0.5, 0),
          (1.0, 1.0, 0.2),
          (0.65, 0.337, 0.157),
          (0.97, 0.506, 0.75)]


# --- step one: compute all roots and edges ---

# There are 240 roots in the root system,
# mutiply them by a factor 2 to be handy for computations.
roots = []

# Roots of the form (+-1, +-1, 0, 0, 0, 0, 0, 0),
# signs can be chosen independently and the two non-zeros can be anywhere.
for i, j in combinations(range(8), 2):
    for x, y in product([-2, 2], repeat=2):
        v = np.zeros(8)
        v[i] = x
        v[j] = y
        roots.append(v)

# Roots of the form 1/2 * (+-1, +-1, ..., +-1), signs can be chosen
# indenpendently except that there must be an even numer of -1s.
for v in product([-1, 1], repeat=8):
    if sum(v) % 4 == 0:
        roots.append(v)
roots = np.array(roots).astype(np.int64)


# Connect a root to its nearest neighbors,
# two roots are connected if and only if they form an angle of pi/3.
edges = []
for i, r in enumerate(roots):
    for j, s in enumerate(roots[i+1:], i+1):
        if np.sum((r - s)**2) == 8:
            edges.append([i, j])

# --- Step two: compute a basis of the Coxeter plane ---

# A set of simple roots listed by rows of 'delta'
delta = np.array([[1, -1, 0, 0, 0, 0, 0, 0],
                  [0, 1, -1, 0, 0, 0, 0, 0],
                  [0, 0, 1, -1, 0, 0, 0, 0],
                  [0, 0, 0, 1, -1, 0, 0, 0],
                  [0, 0, 0, 0, 1, -1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 0],
                  [-.5, -.5, -.5, -.5, -.5, -.5, -.5, -.5],
                  [0, 0, 0, 0, 0, 1, -1, 0]])

# Dynkin diagram of E8:
# 1---2---3---4---5---6---7
#                 |
#                 8
# where vertex i is the i-th simple root.

# The cartan matrix:
cartan = np.dot(delta, delta.transpose())

# Now we split the simple roots into two disjoint sets I and J
# such that the simple roots in each set are pairwise orthogonal.
# It's obvious to see how to find such a partition given the
# Dynkin graph above: I = [1, 3, 5, 7] and J = [2, 4, 6, 8],
# since roots are not connected by an edge if and only if they are orthogonal.
# Then a basis of the Coxeter plane is given by
# u = sum (c[i] * delta[i]) for i in I,
# v = sum (c[j] * delta[j]) for j in J,
# where c is an eigenvector for the minimal
# eigenvalue of the Cartan matrix.
eigenvals, eigenvecs = np.linalg.eigh(cartan)

# The eigenvalues returned by eigh() are in ascending order
# and the eigenvectors are listed by columns.
c = eigenvecs[:, 0]
u = np.sum([c[i] * delta[i] for i in [0, 2, 4, 6]], axis=0)
v = np.sum([c[j] * delta[j] for j in [1, 3, 5, 7]], axis=0)

# Gram-Schimdt u, v and normalize them to unit vectors.
u /= np.linalg.norm(u)
v = v - np.dot(u, v) * u
v /= np.linalg.norm(v)


# --- step three: project to the Coxeter plane ---
roots_2d = [(np.dot(u, x), np.dot(v, x)) for x in roots]

# Sort these projected vertices by their modulus in the coxter plane,
# every successive 30 vertices form one ring in the resulting pattern,
# assign these 30 vertices a same color.
vertex_colors = np.zeros((len(roots), 3))
modulus = np.linalg.norm(roots_2d, axis=1)
ind_array = modulus.argsort()
for i in range(8):
    for j in ind_array[30*i: 30*(i+1)]:
        vertex_colors[j] = COLORS[i]


# --- step four: render to png image ---
image_size = 600
# The axis lie between [-extent, extent] x [-extent, extent]
extent = 2.4
linewidth = 0.0018
markersize = 0.05

surface = cairo.ImageSurface(cairo.FORMAT_RGB24, image_size, image_size)
ctx = cairo.Context(surface)
ctx.scale(image_size/(extent*2.0), -image_size/(extent*2.0))
ctx.translate(extent, -extent)
ctx.set_source_rgb(1, 1, 1)
ctx.paint()

for i, j in edges:
    x1, y1 = roots_2d[i]
    x2, y2 = roots_2d[j]
    ctx.set_source_rgb(0.2, 0.2, 0.2)
    ctx.set_line_width(linewidth)
    ctx.move_to(x1, y1)
    ctx.line_to(x2, y2)
    ctx.stroke()

for i in range(len(roots)):
    x, y = roots_2d[i]
    color = vertex_colors[i]
    grad = cairo.RadialGradient(x, y, 0.0001, x, y, markersize)
    grad.add_color_stop_rgb(0, *color)
    grad.add_color_stop_rgb(1, *color/2)
    ctx.set_source(grad)
    ctx.arc(x, y, markersize, 0, 2*np.pi)
    ctx.fill()

surface.write_to_png(r'D:\项目\E8\E8.png')

可能36行会报如下错误

roots = np.array(roots).astype(np.int)
  File "C:\Users\bowen\AppData\Roaming\Python\Python39\site-packages\numpy\__init__.py", line 305, in __getattr__
    raise AttributeError(__former_attrs__[attr])
AttributeError: module 'numpy' has no attribute 'int'.
`np.int` was a deprecated alias for the builtin `int`. To avoid this error in existing code, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
The aliases was originally deprecated in NumPy 1.20; for more details and guidance see the original release note at:
    https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations

这是因为numpy包版本升级的原因,按照提醒如下改正过来便是,再次运行,便可以在本地生成一张精美的E8根系图,祝大家好运。

roots = np.array(roots).astype(np.int64)

参考文献

2,李代数E8 的根系 python绘图

3,OSError: no library called “cairo” was found 怎么解决