Многие сложные системы удается исследовать только моделированием. Для систем, состоящих из большого количества независимых объектов, такие как поведение толпы, развитие многоклеточных организмов или военные операции, наиболее адекватным оказывается агентное моделирование. Есть много предназначенных для этого систем, например российская проприетарная AnyLogic.
Я же хочу рассказать об языке NetLogo, хорошо зарекомендовавшим себя в образовании, но годный и для взрослых задач.
Синтаксис
Синтаксис Logo минималистичен — разделенная пробелами последовательность имен и констант с редкой группировкой с помощью [] или (). [] служат для создания списков и группировки команд в блок в большинстве конструкций, () — обычные скобки для подвыражений. Имена ссылаются на встроенные или определенные программистом сущности — функции, переменные
Команды (процедуры) объявляются
to имя [список имен аргументов]
тело
end
Функции в NetLogo называются «репортеры» и объявляются немного по другому:
to-reporter имя [список имен аргументов]
тело
report возвращаемая величина
end
Про каждую процедуру или функцию компилятор знает «арность» («валентность») и не требует лишний раз использовать группировку. Правда с функциями высших порядков может ошибаться — тогда ему нужна подсказка в виде круглых скобок.
Пусть у нас определены функции:
to-report inc [x]
report x + 1
end
to-report add [x y]
report x + y
end
Тогда можно написать
add add inc 1 inc 2 inc 3
и получить заслуженную девятку.
Правильно работает так же
map inc [1 2 3]
который возвращает список [2 3 4]. А для add уже придется написать скобки
(map add [1 2 3] [4 5 6])
Агенты
Агенты бывают трех видов — черепашки (turtle — как же без них), связи (link) и пятна (patch — они же места в пространстве). Для черепашек и связей можно задать определяемую пользователем породу (breed). Агенты одного типа объединены в набор соответствующий (agentset) — turtles, links и pathes. Представители одной породы так же объединены в набор. Новая порода создается командой
breed [ninjas ninja]
где ninja — название породы, а ninjas — название набора, объединяющего всех агентов этой породы.
Есть так же особый агент — наблюдатель.
Черепашки создаются командой create-turtles (с аргументом — количество создаваемых черепах), и далее находятся по индексу функцией turtle. Агент — «first class value», при желании его можно сохранить в переменной, но требуется это редко.
Агент или набор агентов могут быть контекстом для команды. Выполнение команд в контексте агентов — основной механизм работы с ними.
ask turtles [fd 1]
Этот код попросит всех черепашек сделать шаг вперед.
ask patch 17 13 [set pcolor pink]
А этот покрасит поле с координатами (17,13) в нежно розовый цвет.
Породу можно установить динамически
ask turtle 1 [set bread ninjas]
ask ninja 1 [set pcolor black]
Переменные
В исходном Logo была реализована динамическая область видимости, что создает неудобства и противоречит современным тенденциями в области языков программирования. Разработчики NetLogo поступили сурово — запретили создание одноименных переменных, область видимости которых могут пересечься. Разработчикам библиотек это удобства не прибавляет, но в обучении школьников скорее полезно. Да и социологам и военспецам в разработке моделей позволит делать меньше ошибок :-).
Область видимости статическая, что упрощает использование функций высших порядков.
Переменные могут быть глобальные, собственные для типа агентов или породы, формальными аргументами и локальные в блоке кода. Одно и то же имя переменной не может ссылаться на разные классы переменных, но локальные переменные в разных блоках, в том числе и в одной функции, могут называться одинаково. Имя локальной переменной не может совпадать с именем аргумента функции, где она определена или с именем глобальной или агентной переменной.
Глобальные переменные описываются
global [имя1 имя2 ...]
собственные
turtles-own [имя3 имя4 ...]
ninjas-own [имя5 имя6 ...]
Локальные переменные создаются командой
let имя7 начальное_значение
Функции высших порядков
Некоторые стандартные функции, такие как map, в качестве одного из аргументов получают другую функцию. Им можно просто указать имя передаваемой функции или написать замыкание. Замыкание представляет из себя код, заключенные в []. То, что это замыкание, а не список, компилятор угадывает по контексту. В качестве формальных параметров используются переменные '?', '?1', '?2' и тд.
Использование своих функций высших порядков сложнее. Присвоить переменной или передать другой функции функцию-значение можно с помощью специальной функции task, а вызвать функцию из переменной — с помощью runresult (или run для команд).
to test1 [f]
show (runresult f 1)
show (map f [2 3 4])
end
test1 (task [? + 2])
Лично я такой подход с разделением функций и переменных, ссылающихся на функции, считаю не удачным, но он реализован, например, в Common Lisp, и имеет своих сторонников.
Интерфейс и графика
В программе присутствуют три вкладки (таба): «интерфейс», документация, и редактор кода. В табе «интерфейс» присутствуют поле графических объектов (в том числе и изображение мира), поле текстового вывода и REPL. В REPL можно переключать режимы, задающие в каком контексте выполняются водимые команды — «наблюдатель», «черепахи», «пятна» и «связи». REPL ограниченный — описывать переменные, породы, процедуры и функции в нем нельзя (они создаются вне контекста), придется переходить в редактор кода.
В зоне, где нарисовано поле с миром, можно «мышкой» (нажав правую кнопку на свободном месте) создавать другие графические объекты и элементы интерфейса. При создании им надо задать имена, по которым к ним можно обращаться из программы. Способа порождать графические объекты программно я не нашел. В файле эти объекты сохраняются в текстовом виде после кода, но в малопригодной для ручного редактирования форме.
Например, если мы создадим «график» с именем «plot1», то команда
set-current-plot "Class Histogram"
histogram map [position ? [red green blue]] ([color] of turtles)
нарисует график распределения черепах по красному, зеленому и синему цветам (предполагая, что другие не встречаются).
Библиотека моделей
К NetLogo прилагается обширная библиотека моделей, от учебных и развлекательных, до исследовательских. Некоторые модели умеют общаться со специализированным железом, таким как GoGo board.
Доступ к модели к модели осуществляется через меню File. Как правило, в интерфейсе моделей есть кнопки Setup и Go и для запуска их надо нажать в этом порядке. Setup инициализирует модель, после чего ее настройки можно изменить через интерфейс.
Автор: potan