Я написал симулятор квантового поля на Java. Вот что из этого вышло
Уточнение: строго говоря, это классическое нелинейное скалярное поле — модификация уравнения Клейна-Гордона с φ⁴ потенциалом. “Квантовое” в названии — по аналогии с явлениями которые воспроизводятся. Следующая статья будет про тетраэдральную сетку.
Одним вечером я решил проверить: что если взять решётку из 10 000 узлов, задать одно правило передачи энергии между соседями — и просто запустить? Никакой теоретической физики из учебника, никакой подготовки. Посмотреть что вырастет само.
Спойлер: за один день появились волновое уравнение, интерференция, фазовый переход, рождение и аннигиляция частиц, и стрела времени. Всё из одного уравнения.
Старт: убираем случайность
У меня уже был проект — симуляция квантового поля на тетраэдрах, где узлы случайно осциллировали (Math.random()). Красиво, но мертво. Шум без смысла, без структуры.
Я сделал шаг: заменил случайность на детерминированный закон. Каждый тик поле в каждом узле обновляется по правилу:
// GridField.java
private void update() {
double[][] newPhi = new double[HEIGHT][WIDTH];
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
// Дискретный Лапласиан (4 соседа, торическая топология)
int left = (x - 1 + WIDTH) % WIDTH;
int right = (x + 1) % WIDTH;
int up = (y - 1 + HEIGHT) % HEIGHT;
int down = (y + 1) % HEIGHT;
double laplacian = phi[y][left] + phi[y][right]
+ phi[up][x] + phi[down][x]
- 4.0 * phi[y][x];
// φ⁴ потенциал: тянет поле к вакуумам ±V
double force = -LAMBDA * (phi[y][x] * phi[y][x] - V * V) * phi[y][x];
velocity[y][x] = velocity[y][x] * DAMPING
+ FLOW_RATE * laplacian
+ force;
newPhi[y][x] = phi[y][x] + velocity[y][x];
}
}
phi = newPhi;
tick++;
}
Константы которые управляют всем поведением:
static final int WIDTH = 100;
static final int HEIGHT = 100;
static final double FLOW_RATE = 0.20; // скорость волны, ОБЯЗАТЕЛЬНО < 0.25
static final double DAMPING = 0.998; // затухание (1.0 = без потерь)
static final double V = 300.0; // положение вакуумов ±V
static final double LAMBDA = 0.000002; // сила нелинейности φ⁴
Важно: FLOW_RATE < 0.25 — это условие устойчивости Куранта для дискретного волнового уравнения. Выше — поле взрывается в NaN за несколько тиков.
Фаза 1: одно правило → волна и интерференция
Запустил с LAMBDA = 0 (чистое волновое уравнение). Одна точка возбуждения в центре:
// GridMain.java
GridField field = new GridField();
field.excite(50, 50, 600.0);
field.start(50); // 50ms на тик = ~20 тиков/сек
По экрану пошла идеальная круговая волна. Дошла до края — появилась с другой стороны, потому что решётка замкнута как тор (периодические граничные условия).
Волна вернулась и встретила себя. На экране появились концентрические интерференционные кольца — точно как в двухщелевом опыте Юнга. Только я этого не программировал. Это вышло из Лапласиана.
Два источника:
field.excite(35, 50, 600.0);
field.excite(65, 50, 600.0);
Фаза 2: нелинейность → частицы
Чистое волновое уравнение умирает: через тысячу тиков поле превращается в равномерный туман. Тепловая смерть. Второе начало термодинамики не было заложено — оно просто случилось.
Включаю LAMBDA = 0.000002.
Потенциал φ⁴ — это V(arphi) = \lambda(arphi^2 - V^2)^2 — двойная яма. Поле теперь хочет быть либо в +V, либо в −V. Как магнит который намагничен в одну из двух сторон.
После одного клика мышью:
- Расходится волна — как раньше
- Поле начинает выбирать: здесь домен +V, там домен −V
- На границах доменов возникает устойчивая структура — не размывается
- Эти границы движутся, сталкиваются, аннигилируют
Детектор "частиц":
// GridField.java
public List<int[]> detectParticles() {
List<int[]> boundaries = new ArrayList<>();
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int right = (x + 1) % WIDTH;
int down = (y + 1) % HEIGHT;
// Граница домена = соседи имеют разные знаки
if (phi[y][x] * phi[y][right] < 0 ||
phi[y][x] * phi[down][x] < 0) {
boundaries.add(new int[]{x, y});
}
}
}
return boundaries;
}
Счётчик показал: 7 → 222 → 1397 → 9821 граничных узлов. Детектор считает пиксели на границах доменов, а не сами объекты. Важно другое: кинки и антикинки рождаются и аннигилируют строго парами — суммарный топологический заряд Q = N₊ − N₋ сохраняется. Это не было заложено явно — вышло из топологии поля.
Что я увидел на экране
Tick 58 — одна точка возбуждения, φ⁴ включён. На синем фоне (вакуум −V) появился идеальный золотой круг (домен +V) с чёткой чёрной границей. Как мыльный пузырь. Как другое пространство внутри.
В космологии это называется фазовым переходом при инфляции — пузырь новой фазы вакуума внутри старого. Это есть в учебниках по физике раннего Вселенной. Я не читал про это когда писал код. Оно просто получилось.
Tick 821 — 5297 частиц. Крестообразная структура из доменов — результат возвратных волн с тора, интерферирующих с доменными стенками.
Tick 18 245 — 9821 частица. Максимально хаотичный вакуум. Это квантовый вакуум — не пустота, а кипящее море виртуальных пар которые рождаются и тут же аннигилируют.
Физика которая вышла сама — без намерения
|
Явление |
Где видно |
Было запрограммировано? |
|
Волновое уравнение |
Концентрические кольца |
Нет |
|
Принцип Гюйгенса |
Каждый узел = источник |
Нет |
|
Интерференция |
Полосы при двух источниках |
Нет |
|
Торическая топология |
Волна возвращается |
Да (граничные условия) |
|
Фазовый переход |
Домены ±V |
Нет |
|
Рождение пар |
Счётчик чётный |
Нет |
|
Аннигиляция |
Счётчик падает |
Нет |
|
Стрела времени |
Порядок → хаос |
Нет |
|
Тепловая смерть |
Туман через 1000 тиков |
Нет |
9 из 10 явлений не программировались. Они вышли из одного уравнения в 15 строк.
Управление
// GridVisualization.java
// ЛКМ / drag → +2000 к φ в узле
// ПКМ / drag → −1000 к φ в узле
@Override
public void mousePressed(MouseEvent e) {
int x = e.getX() / CELL_SIZE;
int y = e.getY() / CELL_SIZE;
double amount = SwingUtilities.isRightMouseButton(e) ? -1000.0 : 2000.0;
field.excite(x, y, amount);
}
Кликаешь левой — создаёшь возбуждение. Правой — убираешь. Можно "потолкать" домен и посмотреть как он движется.
Что дальше
Следующий шаг — атом. Атом это стоячая волна которая замкнулась сама на себе. Для этого нужно второе поле χ, связанное с основным φ через бипотенциал:
V(arphi, \chi) = \lambda(arphi^2 - V^2)^2 - g \cdot arphi^2 \cdot \chi^2
Лёгкое поле χ будет резонировать вокруг тяжёлого φ-сгустка. Выживут только орбиты где умещается целое число длин волн χ. Квантование энергий выйдет само — из геометрии, не из аксиом.
Код
Java 17+, никаких зависимостей кроме стандартного Swing. Gradle сборка. Репозиторий: github.com/malexple/quant
git clone https://github.com/malexple/quant
./gradlew run
Запускаешь. Кликаешь в центр. Смотришь как рождаются и умирают частицы. Занимает минуту.
После этой минуты квантовое поле перестаёт быть абстракцией из учебника.
Написано за один день итеративного эксперимента. Следующая статья — два связанных поля и попытка получить атом.
Подписывайся на наши соц сети:
