- Для реализации алгоритма и визуализации симуляции использовалась
библиотека
taichi- Позволяет компилировать python-подобный код в нативный
- Автоматически поддерживает
fork–joinпараллелизм (все внешние циклыforпараллелятся) - Предоставляет из коробки инструменты для визуализации
- Для управления зависимостями использовался пакетный менеджер rye
Библиотека
taichiнакладывает ряд ограничений, из-за которых было удобно воспринимать один модуль-файл, как один класс. Кроме того, для ускорения работы алгоритма, вся динамическая память выделяется заранее на этапе конфигурации и потом переиспользуется.
__main__.py-- это основной файл для запуска.- тут выделяется массив "котов", который используется потом в алгоритме и при отрисовке
cats = Cat.field(shape=(cfg.CATS_N,))
cat.py-- содержит в себе,dataclassCat. Он описывает передвижение, а также изменение состояния одного "кота".- перед использованием надо вызвать
init_cat_env(), для инициализации модуля
- перед использованием надо вызвать
grid.py-- здесь представлен сам алгоритм- перед использованием надо вызвать
setup_grid(), для инициализации модуля
- перед использованием надо вызвать
config.py-- это конфигурация запуска (из-за отсутствия интерактивного UI изменять параметры запуска можно только при перезагрузке всего приложения)
Сама архитектура довольно проста:
- В
__main__.pyпроисходит вся инициализация (алгоритма и "котов"), а также исполнение основного цикла:
move_cats(cats)-- передвижение котовupdate_statuses(cats)-- пересчет состояний (запуск алгоритма)GUI.circles(cats)-- отрисовка "котов" (в виде окружностей)GUI.show()-- отображение одного кадра
cats-- заранее выделенный массив "котов"
Алгоритм основывается на том, что все пространство разбивается на равные ячейки.
- На каждой итерации после перемещения "котов" на новые позиции происходит вызов функции
update_statuses, которая проходится по всем "котам" (окружностям) и обновляет их состояние. - Алгоритм смотрит в какую ячейку попадает рассматриваемый "кот". И проверяет расстояние до всех "котов" расположенных в соседних ячейках (т.е. рассматривается 9 ячеек).
- Этого достаточно, потому что высота и ширина ячейки равняется
2*RADIUS_1.
Важно заметить, что в худшем случае, когда
RADIUS_1будет достаточно большим, весь алгоритм будет работать заO(n^2), что обусловлено нахождением всех "котов" в одной ячейке (приходится рассматривать всех со всеми)
Алгоритм решения вдохновлен этой статьей.
- Тестирование алгоритма ячеек проводилось путем сравнения его результатов с "наивным" решением, основанным на методе полного перебора. "Наивное" решение подразумевает исчерпывающий поиск соседних узлов ("котов") для каждого элемента набора данных путем последовательного обхода всех имеющихся узлов ("котов").
primitive_update_states()наивное решение
-
В качестве тестовых данных использовались наборы, сгенерированные с применением различных конфигурационных параметров. Координаты узлов в рамках каждого тестового набора определялись посредством генератора псевдослучайных чисел, что обеспечивало репрезентативность и вариативность условий эксперимента.
-
Также проведено юнит-тестирование функций перемещения: протестировано, что функции не нарушают допустимый радиус перемещения.