Представим школьный двор на перемене. Дети приносят карточки Pokemon, показывают друг другу коллекции и начинают меняться: одному нужна огненная карта, другой охотится за редкими, третий пытается собрать небольшую воображаемую колоду. Никого не заставляют обмениваться, и сделка происходит только если оба ребенка считают, что получили что-то полезное для себя. Но асимметрия видна с первой минуты: кто-то пришел с толстой пачкой карточек, у кого-то много дублей, а кому-то случайно досталась редкая карта, которая сразу привлекает внимание. Эта статья использует такой бытовой сценарий как маленькую рыночную симуляцию, чтобы точнее сформулировать главный тезис: в этой модели конечный успех не требует большего умения торговаться, манипуляции или обмана. Уже сами стартовые условия могут создавать больше будущих возможностей.
simpleVis - небольшой Jupyter/Manim-проект, который моделирует именно такой школьный рынок карточек Pokemon. Модель начинается с простого вопроса: что будет, если часть детей случайно получила более крупные или более ликвидные стартовые коллекции, каждая следующая сделка добровольна, и каждая совершенная сделка субъективно выгодна обеим сторонам? Ответ намеренно не в том, что дети с лучшим стартом лучше торгуются. Симуляция убирает это объяснение: все дети следуют одним и тем же правилам обмена. Механизм проще и структурнее: большая и разнообразная коллекция создает больше независимых возможностей, больше карточек, которые могут кому-то понадобиться, и больше способов собрать bundle-сделку.
Репозиторий ноутбука: eosfor/simpleVis. Запуск в Binder: pokemon_yard_simulation.ipynb.
В репозитории лежат сам notebook, воспроизводимая модель pokemon_yard_model.py и три Manim-сцены в manim_card_flow.py. Код лучше смотреть и запускать там: Binder открывает готовый notebook в браузере, а статья ниже оставляет только ход рассуждения, графики, анимации и пояснения к ним.
Идея модели
В ноутбуке отдельно считаются две величины, которые легко смешать в обычном разговоре: субъективная полезность и рыночная ценность. Ребенок может очень хотеть конкретную карточку, потому что она подходит к любимому типу, закрывает воображаемую колоду или просто кажется более интересной, чем то, что у него уже есть. Рыночная ценность - другое: это переносимая ценность карточки внутри модели, зависящая от редкости и типа.
Каждая сделка должна увеличивать субъективную полезность для обоих детей. При этом владелец ликвидной целевой карточки не обязан принимать рыночный минус. Если кому-то эта карточка очень нужна, владелец может попросить bundle из нескольких менее нужных ему карточек, суммарная рыночная стоимость которых не ниже стоимости целевой карточки. Покупатель может согласиться, потому что субъективно целевая карточка для него ценнее.
В этом и состоит главный смысл модели. Совокупная субъективная полезность может расти, а рыночная ценность при этом может концентрироваться.
1. Стартовые коллекции
Первая секция ноутбука генерирует физическое количество карточек у 100 детей. Распределение случайное, но обрезается снизу нулем: кто-то начинает почти без карточек, кто-то с заметно большей коллекцией. Затем симуляция создает сами карточки. У каждой карточки есть тип, редкость и рыночная ценность. Редкость смещена в сторону common cards, но небольшая доля rare cards получает намного большую стоимость.
Поэтому два ребенка с похожим физическим количеством карточек могут иметь очень разную стартовую рыночную ценность. У одного много обычных карточек, у другого меньше карточек, но есть редкая карта, которую многие хотят.
Прозрачные столбцы показывают начальное состояние, непрозрачные - финальное. В нижних 20% только 1 ребенок из 20 получил положительный прирост рыночной стоимости; 16 детей закончили ниже стартового значения, еще 3 остались без изменений. Суммарно группа снизилась со 166.6 до 129.6 условных единиц, то есть потеряла 36.9. В средней группе 24 ребенка из 60 выросли, а 36 просели; суммарная рыночная стоимость группы упала с 3030.7 до 2871.9, на 158.8. Верхние стартовые 20% выглядят иначе: 11 детей из 20 выросли, 9 просели, а общий итог группы поднялся с 2713.9 до 2909.6, то есть на 195.7.
2. Предпочтения и полезность
Модель также задает каждому ребенку личный вектор предпочтений. У ребенка есть общий профиль вкусов и один усиленный любимый тип. Поэтому субъективная полезность карточки - это не просто ее рыночная стоимость. В модели используется сглаженная стоимость, вес предпочтения ребенка к типу этой карточки и небольшой idiosyncratic fit.
Именно поэтому модель может совершать сделки, которые выгодны обоим детям субъективно, даже если рыночная стоимость перетекает в одну сторону. Каждый оценивает карточки через свой вектор предпочтений.
3. Добровольные bundle-сделки
В этой секции важно разделить два шага. Trade lead - это еще не сделка, а только возможность ее попробовать: кто-то заметил карточку, карточка попала в поле внимания, и модель выбирает потенциального контрагента. Только после этого начинается поиск bundle-сделки, которая пройдет проверку полезности для обеих сторон.
Первый шаг специально сделан механистичным. Каждая физическая карточка может независимо создать lead. Более дорогие карточки создают немного больше leads, потому что они более ликвидны и чаще привлекают внимание.
Поэтому первый график не показывает, кто лучше торгуется. Он показывает размер входа в воронку обмена. У ребенка с большим числом карточек больше попыток, потому что больше карточек видно во дворе. У ребенка с ценными карточками больше попыток, потому что эти карточки чаще кому-то интересны. Вероятность успеха одной конкретной сделки не становится скрыто выше для изначально удачливой группы; у нее просто больше поводов начать проверку сделки.
Для каждого lead симуляция выбирает контрагента: чаще локального соседа в круговой схеме двора, иногда случайного ребенка. Это превращает абстрактный интерес к карточке в конкретную пару детей, между которыми можно попробовать обмен.
Второй шаг - сама bundle-сделка. Модель ищет целевую карточку у владельца и набор карточек, который bidder может отдать взамен. Сделка разрешается только если оба ребенка получают достаточный прирост субъективной полезности. Владелец целевой карточки дополнительно требует неотрицательного изменения рыночной ценности.
Именно здесь появляется связь со вторым графиком. После принятия сделки меняется ownership, но общее количество карточек и общая рыночная стоимость во дворе сохраняются. Значит, график Финал минус старт не показывает создание новой рыночной стоимости. Он показывает, куда после всех принятых bundle-сделок перетекла уже существующая стоимость.
Если верхняя стартовая группа чаще оказывается владельцем ликвидной целевой карточки, она чаще может принять bundle только при рыночно неотрицательном обмене. Другая сторона может согласиться, потому что субъективно нужная карточка для нее ценнее. Так добровольная сделка может быть полезной для обоих детей и одновременно переносить рыночную стоимость в сторону владельца более ликвидной позиции.
4. Что измеряет ноутбук
После симуляции ноутбук смотрит не на одну итоговую цифру, а на несколько разных следов процесса. Это важно, потому что у модели два разных вопроса.
Первый вопрос: становятся ли дети субъективно довольнее? Для этого используется total subjective utility. Если эта линия растет, значит принятые сделки действительно делают коллекции более подходящими под личные предпочтения детей.
Второй вопрос: становится ли рыночная стоимость распределена равномернее или, наоборот, концентрируется? Для этого используются Gini по market value и Lorenz curve. Эти метрики смотрят не на субъективную радость от карточек, а на переносимую рыночную стоимость коллекций.
Третий ряд данных - сделки, нормировано - нужен как шкала прогресса симуляции. Он показывает, что изменения в utility и Gini происходят не мгновенно в конце, а накапливаются по мере принятых обменов.
На этом графике можно переключать метрику. Если выбрать суммарная subjective utility, видно, что добровольные обмены выполняют свое локальное обещание: совокупная субъективная полезность растет. Если выбрать Gini по market value, видно другое: индекс неравенства тоже растет, то есть рыночная стоимость распределяется менее равномерно. Это и есть главный конфликт модели - локально взаимовыгодные сделки не гарантируют равный рыночный результат.
Lorenz curve читается так: по оси X дети отсортированы от меньшей рыночной стоимости к большей, по оси Y показана накопленная доля всей рыночной стоимости. Пунктирная диагональ - идеальное равенство: например, нижние 50% детей владеют 50% стоимости. Чем ниже кривая уходит под диагональ, тем сильнее концентрация. Если финальная линия сильнее выгнута вниз, значит после симуляции большая часть стоимости оказалась у меньшей части детей.
5. Группы и перемещение рангов
До этого места мы смотрели на общее неравенство. Теперь нужен более прямой вопрос: что случилось с детьми, которые начали в разных стартовых позициях?
Ноутбук делит детей на три группы по стартовой рыночной ценности коллекции: нижние 20%, средние 60% и верхние 20%. Это не финальный рейтинг и не оценка заслуг. Это срез начальных условий. Дальше мы следим за тем, удерживают ли эти стартовые группы свою долю карточек и рыночной стоимости.
Первый график отвечает на групповой вопрос: какая часть общего “пирога” остается у каждой стартовой группы по мере симуляции? Переключатель меняет смысл пирога. В режиме market value это доля общей рыночной стоимости. В режиме physical cards это доля физического количества карточек.
В режиме market value общий тренд простой: красная и синяя группы беднеют, зеленая богатеет. Нижние 20% снижают свою долю с примерно 2.8% до 2.2%, средние 60% - с примерно 51.3% до 48.6%, а верхние 20% растут с примерно 45.9% до 49.2%. Переключение на physical cards показывает, что количество карточек тоже перераспределяется, но не полностью объясняет перераспределение рыночной стоимости.
Но групповая доля не говорит, пересекали ли отдельные дети границы между группами. Поэтому следующий график отвечает на другой вопрос: где ребенок начал и где оказался в финале? Это transition matrix из стартовой группы в финальную. Строка - стартовая группа, столбец - финальная группа, число в ячейке - сколько детей прошли такой путь.
Матрица переходов показывает, насколько трудно выйти из стартовой ниши. Из нижних 20% 17 детей остаются в нижней группе, 3 поднимаются в среднюю и никто не доходит до верхней. Из средней группы 54 ребенка остаются в середине, 3 падают вниз и 3 поднимаются наверх. Из верхних 20% 17 детей остаются наверху, 3 спускаются в середину и никто не падает сразу в нижнюю группу. Индивидуальные перемещения есть, но стартовая группа сильно ограничивает диапазон вероятных исходов.
Последний вид - поименная таблица крупнейших movers. Она нужна, чтобы не потерять индивидуальную динамику за агрегатами. В ней видно, какие дети сильнее всего изменили ранг, откуда они стартовали, куда попали и насколько изменилась их рыночная стоимость.
Это одна из самых интересных частей ноутбука. Модель не говорит, что все дети навсегда зафиксированы в стартовой группе: переходы есть, и отдельные дети могут заметно подняться или упасть. Но таблица и матрица вместе показывают ограничение диапазона. Подвижность существует внутри структуры, заданной стартовой коллекцией, а не вместо этой структуры.
6. Manim-сцены
В конце ноутбук рендерит три Manim-анимации.
CardFlowScene сортирует детей по стартовой рыночной ценности и рисует bar chart во времени. Красные столбцы - стартовые нижние 20%, синие - средние 60%, зеленые - стартовые верхние 20%. Желтые частицы показывают заметные transfer events от более низкого стартового ранга к более высокому.
CircleTradeScene размещает детей по кругу. Цвет вершины все еще означает стартовую группу, а радиус вершины соответствует текущей рыночной стоимости. Желтые точки анимируют transfers, созданные bundle-сделками. Подпись кадра показывает Gini, число детей с нулем карточек и максимальную рыночную стоимость.
Эта сцена хорошо показывает то, что сложнее увидеть на статических графиках: сделки идут между конкретными детьми, стоимость переносится отдельными событиями, а текущая рыночная сила ребенка меняется постепенно, не как одномоментный финальный пересчет.
GroupMigrationScene на каждом кадре пересчитывает текущие bottom/middle/top groups. Дети перемещаются между тремя зонами, а для самых важных переходов через границу ненадолго появляются подписи child_XX.
Эта анимация дополняет матрицу переходов из раздела 5: она показывает не только стартовую и финальную группу, а сам процесс пересечения границ. Видно, что часть детей действительно мигрирует между зонами, но движение происходит внутри общей структуры, заданной стартовыми условиями.
В ноутбуке эти сцены запускаются так, чтобы Binder мог тихо выполнить Manim и встроить готовый MP4 под ячейкой. Полные команды и параметры запуска оставлены в notebook и в manim_card_flow.py; в статье важнее результат и связь анимаций с графиками выше.
Как запустить
Самый быстрый путь - открыть готовый notebook в Binder. Там можно выполнить модель, пересобрать графики и запустить Manim-сцены без локальной установки.
Если нужен локальный запуск, все файлы лежат в репозитории eosfor/simpleVis: notebook, модель, зависимости и Manim-сцены. Команды установки и запуска лучше брать прямо из репозитория, чтобы они не расходились со статьей.