Как известно, гипотеза Пуанкаре на сегодня является единственной решённой задачей тысячелетия.

Её формулировка довольно проста:

Всякое односвязное компактное трёхмерное многообразие без края гомеоморфно трёхмерной сфере. Источник [1].

В 2002-2003 годах российский математик Григорий Яковлевич Перельман (Источник [10]) опубликовал 3 препринта на Arxiv.org со своим доказательством (Источник [11],[12], [13]). Его правильность проверили и подтвердили 3 независимые группы учёных (Источник [3], [6]) и в 2006 году Перельману присудили премию Филдса, а в 2010 году Премию тысячелетия в 1 млн долларов, но тот от обеих высоких наград отказался. Источник [1].

В этой статье мы сделаем компьютерную визуализацию основных пунктов доказательства.

Упрощённая схема доказательства приведена в Источник [1]:

Пусть есть произвольное односвязное компактное трёхмерное многообразие без края:

Трёхмерное многообразие
Трёхмерное многообразие

Начнём с потоков Риччи:

Поток Риччи — система дифференциальных уравнений в частных производных, описывающая деформацию римановой метрики на многообразии. Ключевая идея данных уравнений- где кривизна больше — там метрика меняется быстрее.Источник [2].

Уравнение Риччи записывается так:

\frac{\partial g_{ij}}{\partial t} = -2 R_{ij}

Где:

g_{ij}

 — метрический тензор (задаёт геометрию многообразия),

R_{ij}

— тензор Риччи (характеризует кривизну),

t — параметр «времени» потока (не физическое время, а параметр эволюции метрики).

Источник [2]

Для иллюстрации напишем код на Python, демонстрирующий одномерную кривизну и поток:

import numpy as np
import matplotlib.pyplot as plt

# Параметры
N = 100                 # число точек на отрезке
L = 1.0                 # длина отрезка
dx = L / (N - 1)
x = np.linspace(0, L, N)

# Начальное «поле кривизны» (аналог скалярной кривизны в 1D)
# Сделаем горбик в центре
R = np.zeros(N)
center = N // 2
width = N // 8
for i in range(N):
    R[i] = np.exp(-((i - center) / width)**2)

# Метрика (в 1D это просто локальный масштаб ds^2 = g dx^2)
g = np.ones(N)          # изначально везде 1

dt = 0.01               # шаг по «времени потока»
steps = 500             # сколько шагов сделать

history_g = []

for t in range(steps):
    # Аналог потока Риччи: dg/dt ~ -R (упрощённо)
    dg = -2* R * dt
    g += dg
    
    # Ограничиваем, чтобы метрика не стала отрицательной
    g = np.maximum(g, 0.1)
    
    if t % 50 == 0:
        history_g.append(g.copy())

# Визуализация
plt.figure(figsize=(8, 4))
for i, g_snap in enumerate(history_g):
    plt.plot(x, g_snap, label=f'step {i*50}')
plt.plot(x, R, 'k--', linewidth=1, label='curvature R')
plt.xlabel('x')
plt.ylabel('metric g')
plt.title('Simplified Ricci-like flow (1D toy model)')
plt.legend()
plt.grid(True)
plt.show()

Результат работы программы видно здесь:

Одномерный поток Риччи.
Одномерный поток Риччи.

В 2d код будет посложнее:

import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay
from matplotlib.animation import FuncAnimation

# --- Параметры ---
N = 120                 # число точек
dt = 0.002              # шаг по «времени»
steps = 400             # сколько шагов
target_curvature = 0.0 # целевая кривизна в каждой вершине (0 = плоская)

np.random.seed(42)
points = np.random.rand(N, 2) * 10.0  # [0,10] x [0,10]

def compute_angles_and_curvature(points, tri):
    """
    Для каждой вершины считаем сумму углов треугольников вокруг неё.
    Дискретная гауссова кривизна: K_i = 2π - Σ углов.
    """
    n = len(points)
    angles_sum = np.zeros(n)
    
    for s in tri.simplices:
        i, j, k = s
        a = points[j] - points[i]
        b = points[k] - points[i]
        c = points[k] - points[j]
        
        la = np.linalg.norm(a)
        lb = np.linalg.norm(b)
        lc = np.linalg.norm(c)
        
        # защита от вырожденных треугольников
        if la < 1e-8 or lb < 1e-8 or lc < 1e-8:
            continue
        
        cos_i = np.clip((la**2 + lb**2 - lc**2) / (2*la*lb), -1.0, 1.0)
        cos_j = np.clip((la**2 + lc**2 - lb**2) / (2*la*lc), -1.0, 1.0)
        cos_k = np.clip((lb**2 + lc**2 - la**2) / (2*lb*lc), -1.0, 1.0)
        
        angles_sum[i] += np.arccos(cos_i)
        angles_sum[j] += np.arccos(cos_j)
        angles_sum[k] += np.arccos(cos_k)
    
    K = 2*np.pi - angles_sum
    return K

# --- Подготовка для анимации ---
fig, ax = plt.subplots(figsize=(6, 6))
ax.set_aspect('equal')
ax.axis('off')

# Хранилище кадров
frames_K = []
frames_points = []

# Начальное состояние
tri = Delaunay(points)
K = compute_angles_and_curvature(points, tri)
frames_K.append(K.copy())
frames_points.append(points.copy())

# --- Эволюция (поток) ---
for t in range(steps):
    # Вычисляем кривизну
    tri = Delaunay(points)
    K = compute_angles_and_curvature(points, tri)
    
    # Правило обновления: двигаем точки так, чтобы кривизна стремилась к target_curvature
    diff = target_curvature - K
    
    # Локальное масштабирование: если K > target, «раздвигаем» точки вокруг вершины
    scale_factor = 1.0 + dt * diff
    scale_factor = np.clip(scale_factor, 0.8, 1.2)  # ограничение, чтобы не схлопнулось
    
    center = points.mean(axis=0)
    points = center + (points - center) * scale_factor[:, np.newaxis]
    
    # Сохраняем состояние
    if t % 10 == 0:
        frames_K.append(K.copy())
        frames_points.append(points.copy())

# --- Визуализация: последний кадр + распределение кривизны ---
tri_final = Delaunay(frames_points[-1])
K_final = frames_K[-1]

plt.figure(figsize=(10, 4))

plt.subplot(1, 2, 1)
plt.triplot(frames_points[-1][:, 0], frames_points[-1][:, 1], tri_final.simplices,
            color='gray', linewidth=0.4, alpha=0.7)
sc = plt.scatter(frames_points[-1][:, 0], frames_points[-1][:, 1],
                 c=K_final, cmap='coolwarm', s=25, edgecolors='k', linewidths=0.3)
plt.colorbar(sc, label='Gaussian curvature K')
plt.title('Final state after Ricci-like flow')
plt.axis('equal')

plt.subplot(1, 2, 2)
mean_K = [np.mean(K) for K in frames_K]
var_K = [np.var(K) for K in frames_K]
plt.plot(mean_K, label='Mean curvature', color='blue')
plt.plot(var_K, label='Variance of curvature', color='orange')
plt.axhline(target_curvature, color='green', linestyle='--', label='Target')
plt.xlabel('Step (every 10 iterations saved)')
plt.ylabel('Curvature stats')
plt.legend()
plt.grid(True, alpha=0.3)
plt.title('Evolution of curvature statistics')

plt.tight_layout()
plt.show()

В итоге мы получим следующую картинку:

Двумерный поток Риччи
Двумерный поток Риччи
Деформация на многообразиях
Деформация на многообразиях

Он позволяет деформировать риманову метрику на многообразии, но в процессе деформации возможно образование «сингулярностей» — точек, в которых кривизна стремится к бесконечности, и деформацию невозможно продолжить.Источник [1]

Сингулярность на многообразии
Сингулярность на многообразии

В таком случае производят хирургию: Вырезают "шею" и залепляют её шарами, а затем продолжают деформацию.Источник [1].

Напишем код для демонстрации:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# --- Параметры поверхности (гантель) ---
def radius_gantel(z, L=4.0, r_thick=1.0, neck_width=0.4, neck_height=0.5):
    """
    Радиус сечения гантели в зависимости от z.
    L - полная длина вдоль z, r_thick - радиус шаров,
    neck_width - ширина шеи, neck_height - насколько она тонкая.
    """
    # Нормализованная координата от -1 до 1
    t = z / (L / 2)
    # Функция, которая даёт «шею» в центре и «шары» по краям
    r = r_thick * (1.0 - neck_height * np.exp(-t**2 / (neck_width**2)))
    return r

def smooth_radius(z, L, r_thick, alpha=0.3):
    """
    Имитация сглаживания (упрощённый «поток Риччи»):
    делаем шею менее выраженной, поверхность более сферической.
    alpha - сила сглаживания: 0 = без сглаживания, 1 = почти сфера.
    """
    t = z / (L / 2)
    # Базовая гантель
    r_base = radius_gantel(z, L, r_thick, neck_width=0.6, neck_height=0.7)
    # Целевая сфера (радиус как среднее)
    r_sphere = r_thick
    # Линейная интерполяция между гантелью и сферой
    r_smooth = (1 - alpha) * r_base + alpha * r_sphere
    return r_smooth

# --- Генерация сетки ---
L = 4.0
z = np.linspace(-L/2, L/2, 80)
theta = np.linspace(0, 2*np.pi, 80)
Z, Theta = np.meshgrid(z, theta)

# Радиусы для «до» (гантель) и «после» (сглаженная)
R_before = radius_gantel(Z, L)
R_after = smooth_radius(Z, L, r_thick=1.0, alpha=0.85)  # сильное сглаживание

# Переход в декартовы координаты
X_before = R_before * np.cos(Theta)
Y_before = R_before * np.sin(Theta)

X_after = R_after * np.cos(Theta)
Y_after = R_after * np.sin(Theta)

# --- Визуализация ---
fig = plt.figure(figsize=(12, 5))

ax1 = fig.add_subplot(121, projection='3d')
surf1 = ax1.plot_surface(X_before, Y_before, Z, cmap='viridis', alpha=0.9, edgecolor='none')
ax1.set_title('До: гантелеподобное многообразие\n(возможная сингулярность в шее)')
ax1.set_xlabel('X'); ax1.set_ylabel('Y'); ax1.set_zlabel('Z')

ax2 = fig.add_subplot(122, projection='3d')
surf2 = ax2.plot_surface(X_after, Y_after, Z, cmap='plasma', alpha=0.9, edgecolor='none')
ax2.set_title('После: сглаженное многообразие\n(упрощённая имитация потока Риччи)')
ax2.set_xlabel('X'); ax2.set_ylabel('Y'); ax2.set_zlabel('Z')

plt.tight_layout()
plt.show()

В результате получаем следующую картинку:

Хирургия
Хирургия

Таким образом, исходное многообразие гомеоморфно (то есть переходит путём непрерывных деформаций) связной сумме трёхмерных сфер,

Связная сумма сфер
Связная сумма сфер

то есть трёхмерной сфере.

Сфера
Сфера

Таким образом, в данной статье сделана компьютерная визуализация основных идей доказательства Перельмана, получены несколько графических иллюстраций многообразия, потоков Риччи, сглаживания "шеи" и финального результата.

Статья носит чисто иллюстративный и демонстративный характер для наглядного представления доказательства гипотезы Пуанкаре.

Литература:

1.https://ru.wikipedia.org/wiki/Гипотеза_Пуанкаре

2.https://ru.wikipedia.org/wiki/Поток_Риччи

3.https://arxiv.org/abs/math/0612069

4.https://old.mccme.ru/free-books/matpros/articles/МП-24/mp-24-pages-8.pdf

5.https://arxiv.org/abs/0809.1483

6.https://arxiv.org/pdf/math/0211159

7.https://www.wikidata.org/wiki/Q99179783

8.https://www.wikidata.org/wiki/Q99178831

9.https://docs.yandex.ru/docs/view?tm=1784695492&tld=ru&lang=ru&name=mp-24-pages-8.pdf&text=гипотеза пуанкаре доказательство&url=https%3A%2F%2Fold.mccme.ru%2Ffree-books%2Fmatpros%2Farticles%2F%25D0%259C%25D0%259F-24%2Fmp-24-pages-8.pdf&lr=20683&mime=pdf&l10n=ru&sign=a33bbb82ab624fbc77c6d5f4d9a042d9&keyno=0&nosw=1&serpParams=tm%3D1784695492%26tld%3Dru%26lang%3Dru%26name%3Dmp-24-pages-8.pdf%26text%3D%25D0%25B3%25D0%25B8%25D0%25BF%25D0%25BE%25D1%2582%25D0%25B5%25D0%25B7%25D0%25B0%2B%25D0%25BF%25D1%2583%25D0%25B0%25D0%25BD%25D0%25BA%25D0%25B0%25D1%2580%25D0%25B5%2B%25D0%25B4%25D0%25BE%25D0%25BA%25D0%25B0%25D0%25B7%25D0%25B0%25D1%2582%25D0%25B5%25D0%25BB%25D1%258C%25D1%2581%25D1%2582%25D0%25B2%25D0%25BE%26url%3Dhttps%253A%2F%2Fold.mccme.ru%2Ffree-books%2Fmatpros%2Farticles%2F%2525D0%25259C%2525D0%25259F-24%2Fmp-24-pages-8.pdf%26lr%3D20683%26mime%3Dpdf%26l10n%3Dru%26sign%3Da33bbb82ab624fbc77c6d5f4d9a042d9%26keyno%3D0%26nosw%3D1

10.https://ru.wikipedia.org/wiki/Перельман,_Григорий_Яковлевич

11.https://arxiv.org/abs/math/0307245

12.https://arxiv.org/abs/math/0303109

13.https://arxiv.org/abs/math/0211159

Комментарии (0)