Research

Hungry Cells: Fractals That Grow in Your Browser, and an Optimiser That Loses to Random Search

Голодные клетки: фракталы, которые растут у вас в браузере, и оптимизатор, проигравший случайному перебору

One rule — a cell divides once it has eaten enough — grows a fractal. Point the same rule at a mathematical function instead of agar and you get a famous optimisation algorithm, which we then benchmarked until it broke. Both simulations run live on this page, on your machine, with nobody else's state in them.

Одно правило — клетка делится, когда наелась — выращивает фрактал. Направьте то же правило не на агар, а на математическую функцию, и получится известный алгоритм оптимизации, который мы честно замерили, и он сломался. Обе симуляции работают прямо здесь, у вас в браузере, без чужого состояния внутри.

Bnome September 18, 2026 11 min read 11 минут
A branching, fractal bacterial colony in crimson and violet on a near-black field, grown by the simulation described in this article

Start with a single cell in the middle of a dish. Nutrient is spread evenly across the dish and diffuses. The cell eats what is under it. When it has accumulated enough to double, it divides into a free neighbouring square. If it cannot cover its maintenance cost, it starves and stops.

That is the entire model. Four lines of rules, no biology beyond arithmetic. Yet it reproduces — quantitatively — the branching morphologies that Fujikawa and Matsushita photographed in Bacillus subtilis colonies on real agar in 1989, including their fractal dimension.

The simulation below is the actual model, compiled to nothing: plain JavaScript on a 170×170 lattice. Press Grow.

Кладём одну клетку в центр чашки. Еда распределена равномерно и диффундирует. Клетка ест то, что под ней. Накопив достаточно, чтобы удвоиться, она делится в свободную соседнюю клетку решётки. Если ей не хватает даже на поддержание жизни — она голодает и останавливается.

Это вся модель. Четыре строки правил, никакой биологии сверх арифметики. И тем не менее она количественно воспроизводит ветвящиеся морфологии, которые Фудзикава и Мацусита сфотографировали у колоний Bacillus subtilis на настоящем агаре в 1989 году — включая фрактальную размерность.

Симуляция ниже — это та самая модель: обычный JavaScript на решётке 170×170. Нажмите Растить.

Lab 01 — the colony
Лаборатория 01 — колония
runs in this tab only · nothing is sent anywhere
работает только в этой вкладке · ничего никуда не отправляется
growingрастёт full, about to divideнаелась, вот-вот поделится starvedумерла от голода nutrient leftостатки еды
cells
клеток
1
starved
погибло
0
step
шаг
0
Df
—

Df is the box-counting fractal dimension, measured on the colony as it stands. A filled disc gives 2.00. Real B. subtilis colonies in the branching regime come out near 1.7–1.8.

Df — фрактальная размерность по методу подсчёта клеток, считается по текущей колонии. У сплошного диска она равна 2.00. У настоящих колоний B. subtilis в ветвящемся режиме получается около 1.7–1.8.

Why it branches at all

Почему вообще получается ветвление

A colony branches when the cells eat faster than the food can flow back in. A tip that happens to stick out reaches untouched nutrient first and casts a shadow over the gap behind it, so any accidental bump amplifies itself. That is a diffusion-limited instability, the same one behind snowflake dendrites and DLA clusters — Mullins and Sekerka wrote it down for solidifying crystals in 1963, long before anyone pointed it at bacteria.

Turn the food up, or let it diffuse quickly, and the shadowing disappears: every gap gets refilled before it matters, and the colony fills in as a boring compact disc. Drag the two top sliders above and you can walk the whole phase diagram yourself.

Here is that diagram, computed offline on a 301×301 lattice — nine regimes, nutrient falling left to right, diffusion slowing top to bottom.

Колония ветвится, когда клетки едят быстрее, чем еда успевает притечь обратно. Кончик, случайно вылезший вперёд, первым дотягивается до нетронутой еды и затеняет впадину позади себя — так любая случайная выпуклость сама себя усиливает. Это диффузионная неустойчивость, та же самая, что даёт дендриты снежинок и кластеры DLA: Малинс и Секерка описали её для растущих кристаллов ещё в 1963-м, задолго до бактерий.

Прибавьте еды или ускорьте диффузию — затенение исчезает: каждая впадина заполняется раньше, чем это успеет сыграть роль, и колония вырастает скучным плотным диском. Потяните два верхних слайдера — и вы пройдёте всю фазовую диаграмму руками.

Вот эта диаграмма, посчитанная офлайн на решётке 301×301: девять режимов, еды меньше слева направо, диффузия медленнее сверху вниз.

A three by three grid of simulated colonies: rich fast-diffusing nutrient gives compact discs, poor slow-diffusing nutrient gives sparse DLA-like branches
Nine colonies, one model. Nutrient concentration falls left to right, diffusion slows top to bottom. Measured fractal dimension runs from 1.83 in the compact corner to 1.40 in the starved, slow corner. This is the Matsushita–Fujikawa morphology diagram, reproduced from the four rules above and nothing else.
Девять колоний, одна модель. Еды становится меньше слева направо, диффузия замедляется сверху вниз. Измеренная фрактальная размерность идёт от 1.83 в плотном углу до 1.40 в голодном и медленном. Это диаграмма морфологий Мацуситы–Фудзикавы, воспроизведённая из тех же четырёх правил и ничего больше.

Load any of these four regimes into the lab above:

Загрузите любой из четырёх режимов в лабораторию выше:

The shape is not in the rules. Nothing in the model says “branch”. The branching is what a greedy local rule does to a field that cannot refill fast enough.

Формы нет в правилах. Ни одна строчка модели не говорит «ветвись». Ветвление — это то, что жадное локальное правило делает с полем, которое не успевает восполняться.

The same colony, given a function to eat

Та же колония, которой дали есть функцию

Now replace the agar with a mathematical landscape. Let the food at a point be −f(x): the lower the function, the tastier the spot. Bacteria that swim downhill are minimising f. That substitution is the whole idea of Bacterial Foraging Optimization, published by Kevin Passino in IEEE Control Systems Magazine in 2002, and cited several thousand times since.

It has four nested loops:

  1. Chemotaxis — tumble in a random direction, then swim in it as long as the objective keeps improving. This is the Monte Carlo part.
  2. Swarming — bacteria attract and repel each other through a chemical signal.
  3. Reproduction — health is the sum of everything a bacterium has tasted along the way; the best half is duplicated, the worst half dies.
  4. Elimination-dispersal — with some probability a bacterium is teleported somewhere random.

The race below runs that algorithm against two baselines that are much less charming: Metropolis (a single walker doing simulated annealing) and uniform random search. All three get exactly the same number of function evaluations. Pick a landscape and press Run.

Теперь заменим агар математическим ландшафтом. Пусть еда в точке равна −f(x): чем ниже функция, тем вкуснее место. Бактерии, плывущие вниз, минимизируют f. Эта подстановка — вся идея Bacterial Foraging Optimization, опубликованного Кевином Пассино в IEEE Control Systems Magazine в 2002 году и процитированного с тех пор несколько тысяч раз.

В нём четыре вложенных цикла:

  1. Хемотаксис — кувырок в случайном направлении, затем заплыв в ту же сторону, пока функция улучшается. Это и есть часть Монте-Карло.
  2. Роение — бактерии притягивают и отталкивают друг друга через химический сигнал.
  3. Репродукция — «здоровье» есть сумма всего, что бактерия попробовала по пути; лучшая половина удваивается, худшая умирает.
  4. Элиминация-дисперсия — с некоторой вероятностью бактерию телепортирует в случайную точку.

Гонка ниже стравливает этот алгоритм с двумя куда менее обаятельными базовыми методами: Метрополисом (один ходок, имитация отжига) и равномерным случайным перебором. Бюджет вычислений функции у всех троих одинаковый. Выберите ландшафт и нажмите «Запустить».

Lab 02 — the race
Лаборатория 02 — гонка
equal budget · your own random seed
равный бюджет · ваш собственный случайный сид
BFO (2002)
—
Metropolis
—
random searchслучайный перебор
—
evaluations
вычислений
0

Pink dots are the bacterial colony, gold is the Metropolis walker, blue is random search. The cross marks the true global minimum. One run is noise — the table below is a median of 20 runs at equal budget.

Розовые точки — колония бактерий, золотая — ходок Метрополиса, синяя — случайный перебор. Крестик — истинный глобальный минимум. Один запуск — это шум; таблица ниже даёт медиану 20 запусков при равном бюджете.

The honest number

Честная цифра

A single run proves nothing, so we ran the real thing offline: NumPy, 20 seeds, every method given the same 111,500 function evaluations — the exact budget BFO spends with Passino's own parameters. Lower is better; the global minimum of Rastrigin is 0.

Один запуск ничего не доказывает, поэтому мы посчитали всё офлайн: NumPy, 20 сидов, каждому методу один и тот же бюджет в 111 500 вычислений функции — ровно столько тратит BFO с авторскими параметрами Пассино. Меньше — лучше; глобальный минимум Растригина равен 0.

MethodМетод Rastrigin 2DРастригин 2D Rastrigin 10DРастригин 10D
BFO (Passino 2002)1.8637.3
BFO + decaying stepBFO + затухающий шаг1.0032.7
Metropolis (annealing)Метрополис (отжиг)0.00720.4
Uniform random searchСлучайный перебор0.01658.3

Median over 20 seeds at equal budget. Full parameters in the method note at the bottom.

Медиана по 20 сидам при равном бюджете. Все параметры — в методической заметке внизу.

In two dimensions, the elegant biological metaphor is beaten by a plain Metropolis walker by two orders of magnitude — and it also loses to guessing uniformly at random. In ten dimensions it finally beats random guessing, but it is still roughly twice as bad as annealing.

В двух измерениях изящная биологическая метафора проигрывает обычному ходоку Метрополиса на два порядка — и вдобавок проигрывает равномерному угадыванию наугад. В десяти измерениях она наконец обгоняет угадывание, но всё ещё примерно вдвое хуже отжига.

Why it loses, mechanically

Почему он проигрывает — механика

Two specific defects, both visible in the picture below.

The step size never decays. Chemotaxis moves a fixed distance C on every swim, for the entire run. An optimiser that cannot shrink its stride cannot polish an answer: it arrives in the neighbourhood of a minimum and then rattles around it forever. Annealing gets this for free — its temperature schedule is a decaying step. Just adding decay to C cut BFO's error from 1.86 to 1.00, and it is still nowhere near.

Reproduction destroys diversity. Duplicating the healthiest half each generation sounds Darwinian, but on a rugged landscape it is a ratchet with no return spring. We counted it: after the last reproduction step, all 50 bacteria occupy one distinct position — and it is a local minimum, not the global one. The population has converged in the worst sense of the word.

Swarming, the third loop, turns out to change nothing. With Passino's published coefficients the attract-repel term is orders of magnitude smaller than the variation in the objective on Rastrigin, so it never flips a single accept/reject decision. Running with swarming on and off gave byte-identical results.

Два конкретных дефекта, и оба видны на картинке ниже.

Шаг никогда не затухает. Хемотаксис двигает бактерию на фиксированное расстояние C при каждом заплыве — и так весь прогон. Оптимизатор, который не умеет укорачивать шаг, не умеет и доводить ответ: он приходит в окрестность минимума и вечно болтается вокруг. У отжига это бесплатно — его температурное расписание и есть затухающий шаг. Одно добавление затухания к C снизило ошибку BFO с 1.86 до 1.00 — и всё равно это не близко.

Репродукция убивает разнообразие. Удваивать самую здоровую половину каждое поколение звучит по-дарвиновски, но на изрезанном ландшафте это храповик без возвратной пружины. Мы посчитали: после последнего шага репродукции все 50 бактерий стоят в одной точке — и это локальный минимум, а не глобальный. Популяция сошлась в худшем смысле слова.

Роение, третий цикл, не меняет вообще ничего. С опубликованными коэффициентами Пассино слагаемое притяжения-отталкивания на порядки меньше, чем разброс самой функции на Растригине, поэтому оно ни разу не переворачивает решение «принять/отвергнуть». Прогоны с роением и без него дали побайтово одинаковый результат.

Four panels: where the colony spent its time, the final swarm collapsed onto a single wrong point, median convergence curves, and a boxplot of final values across seeds
The diagnosis in four panels. Top left: log density of every position the colony ever sampled. Top right: the final population — all 50 bacteria on one spot, marked against the true global minimum they never reached. Bottom: median convergence over 20 seeds, and the spread of final values. Metropolis (gold) drops through the floor; the two BFO variants flatten out early.
Диагноз в четырёх панелях. Слева вверху: логарифмическая плотность всех точек, которые колония вообще пробовала. Справа вверху: финальная популяция — все 50 бактерий в одном месте, рядом отмечен истинный глобальный минимум, до которого они не дошли. Снизу: медианная сходимость по 20 сидам и разброс финальных значений. Метрополис (золотой) проваливается вниз; обе версии BFO выходят на полку рано.

What to take from this

Что отсюда забрать

  1. Shape comes from constraint, not from instruction. Nothing in the colony model mentions branches. Starve a greedy local rule and the branches appear on their own.
  2. A model earns its keep by being falsifiable. Fractal dimension is a number you can measure on a real agar plate and on a simulation, and compare. That is the difference between a demo and a result.
  3. A metaphor is not a mechanism. Kenneth Sörensen's 2015 paper “Metaheuristics — the metaphor exposed” showed that a whole zoo of nature-inspired algorithms — grey wolf, moth-flame, whale, firefly, bat — are renamed particle-swarm variants. Biology explains where an idea came from; it does not explain why it works.
  4. Always benchmark a new idea against uniform random search at equal budget. It is the cheapest possible baseline, and it is far more often the winner than the literature admits. If your method cannot beat guessing, you do not have a method yet.
  5. Diversity is the thing you have to protect. Every selection step is a bet against exploration. Track how many distinct solutions your population actually holds — the number usually collapses long before the run ends.
  1. Форма берётся из ограничения, а не из инструкции. Модель колонии нигде не упоминает ветви. Посадите жадное локальное правило на голодный паёк — ветви появятся сами.
  2. Модель оправдывает себя только фальсифицируемостью. Фрактальная размерность — это число, которое можно измерить и на живой чашке с агаром, и в симуляции, и сравнить. В этом и разница между демкой и результатом.
  3. Метафора — это не механизм. Кеннет Сёренсен в статье 2015 года «Metaheuristics — the metaphor exposed» показал, что целый зоопарк природных алгоритмов — серый волк, мотылёк-и-пламя, кит, светлячок, летучая мышь — это переименованные варианты роя частиц. Биология объясняет, откуда взялась идея, но не объясняет, почему она работает.
  4. Всегда сравнивайте новую идею со случайным перебором при равном бюджете. Это самый дешёвый возможный бейзлайн — и он побеждает куда чаще, чем признаёт литература. Если метод не обыгрывает угадывание, метода пока нет.
  5. Разнообразие — это то, что нужно защищать. Любой шаг отбора — это ставка против исследования пространства. Считайте, сколько различных решений реально держит ваша популяция: обычно это число схлопывается задолго до конца прогона.

Method

Методика

Colony. Square lattice, no-flux boundary (a closed dish, so the food is finite). Nutrient diffuses by an explicit five-point Laplacian, eight substeps per Monte Carlo step, D ≤ 0.25 for stability. A cell takes σ·n from its own square only while it is not yet full, pays a fixed upkeep every step, dies below zero, and divides into a random free square of its eight-neighbourhood, splitting its biomass in half. Collisions between simultaneous divisions are resolved by keeping one claimant per target. Fractal dimension by box counting over box sizes 2–32.

Optimisers. BFO with Passino's parameters: S = 50, Nc = 60, Ns = 4, Nre = 6, Ned = 3, Ped = 0.25, C = 0.06·range, swarming coefficients 0.1 / 0.2 / 0.1 / 10. Metropolis: single walker, geometric cooling, Gaussian proposals scaled by temperature. Random search: uniform samples. Budget fixed at BFO's own evaluation count (111,500), 20 seeds, median reported. Code: colony.py, bfo.py, optimize.py, ~400 lines of NumPy.

The two labs on this page are the same algorithms rewritten in plain JavaScript, on smaller lattices and shorter budgets so they run at 60 fps. They keep no state outside this tab: no cookies, no local storage, no server. Your random seed is drawn when the page loads, so your colony is yours.

Колония. Квадратная решётка, граница без потока (закрытая чашка, поэтому еда конечна). Еда диффундирует явным пятиточечным лапласианом, восемь подшагов на один шаг Монте-Карло, D ≤ 0.25 для устойчивости. Клетка забирает σ·n только со своей ячейки и только пока не наелась, каждый шаг платит фиксированный расход, умирает при уходе в минус и делится в случайную свободную ячейку из своих восьми соседей, деля биомассу пополам. Столкновения одновременных делений разрешаются одним претендентом на ячейку. Фрактальная размерность — подсчётом клеток размеров 2–32.

Оптимизаторы. BFO с параметрами Пассино: S = 50, Nc = 60, Ns = 4, Nre = 6, Ned = 3, Ped = 0.25, C = 0.06·диапазон, коэффициенты роения 0.1 / 0.2 / 0.1 / 10. Метрополис: один ходок, геометрическое охлаждение, гауссовы предложения с масштабом по температуре. Случайный перебор: равномерные точки. Бюджет зафиксирован по собственному расходу BFO (111 500), 20 сидов, приводится медиана. Код: colony.py, bfo.py, optimize.py, около 400 строк NumPy.

Две лаборатории на этой странице — те же алгоритмы, переписанные на чистом JavaScript, на решётках поменьше и с коротким бюджетом, чтобы шло 60 кадров в секунду. Они не хранят состояние за пределами этой вкладки: ни кук, ни локального хранилища, ни сервера. Случайный сид берётся при загрузке страницы, так что ваша колония — только ваша.

Sources

Источники

  1. Passino, K. M. (2002). Biomimicry of bacterial foraging for distributed optimization and control. IEEE Control Systems Magazine, 22(3), 52–67.
  2. Fujikawa, H., & Matsushita, M. (1989). Fractal growth of Bacillus subtilis on agar plates. Journal of the Physical Society of Japan, 58(11), 3875–3878.
  3. Matsushita, M., et al. (1998). Interface growth and pattern formation in bacterial colonies. Physica A, 249(1–4), 517–524.
  4. Witten, T. A., & Sander, L. M. (1981). Diffusion-limited aggregation, a kinetic critical phenomenon. Physical Review Letters, 47(19), 1400–1403.
  5. Mullins, W. W., & Sekerka, R. F. (1963). Morphological stability of a particle growing by diffusion or heat flow. Journal of Applied Physics, 34(2), 323–329.
  6. Kreft, J.-U., Booth, G., & Wimpenny, J. W. T. (1998). BacSim, a simulator for individual-based modelling of bacterial colony growth. Microbiology, 144(12), 3275–3287.
  7. Sörensen, K. (2015). Metaheuristics — the metaphor exposed. International Transactions in Operational Research, 22(1), 3–18.

Describe a simulation — get one that runs

Опишите симуляцию — получите работающую

Everything interactive on this page is a few hundred lines of generated code on a live URL. Bnome builds that from a sentence, and gives it a domain.

Всё интерактивное на этой странице — пара сотен строк сгенерированного кода на живом адресе. Bnome собирает такое из одной фразы и выдаёт домен.

Try BnomeПопробовать Bnome