Date Редакция Категория edu Теги курсы

Светлячки (семейство жучков Lampyridae, насчитывающее более 2000 видов) знамениты своей способностью испускать в темноте мягкий фосфоресцирующий свет. Коэффициент полезного действия «фонариков» светлячков необыкновенно высок. Если в обычной электрической лампочке в видимый свет превращается около 5% энергии (а остальная рассеивается в виде тепла), то у светлячков в световые лучи переходит от 87 до 98% энергии. Причем многие виды способны по своему желанию уменьшать и увеличивать силу света, а также испускать прерывистый свет.

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

Час за часом, неделями и даже месяцами, жучки мигают на своих деревьях все в том же ритме. Ни ветер, ни сильный дождь не могут изменить интенсивности и частоты вспышек. Можно нарушить синхронность вспышек, если осветить дерево яркой лампой, но когда она погаснет, светлячки опять, словно по команде, начнут мигать. Сначала те, что в центре дерева, приспосабливаются к одному ритму, потом соседние жуки подключаются к ним и постепенно волны вспыхивающих в унисон огоньков распространяются по всем ветвям дерева.

Рассмотрим групповое поведение светлячков (синхронизацию их мерцаний) и попытаемся смоделировать его с помощью NetLogo. NetLogo — это свободное программное обеспечение для агентного моделирования, использующее JVM и работающее на большинстве платформ. Скачать NetLogo можно на %newwin%официальном сайте после бесплатной регистрации.

Начало работы: Command Center и создание проекта

Начнем с работы с Command Center — окном, расположенным в нижней части вкладки Interface. Command Center предназначен для ввода команд и просмотра результатов их выполнения. Создадим 100 черепашек (так называются агенты, способные перемещаться по игровому миру)

observer> crt 100

Но где они?

l1_0.png

Дело в том, что все созданные черепашки имеют одни и те же координаты и располагаются в центре мира (если хотите, можно представить себе «стопочку» черепашек, сидящих одна на другой). Каждая черепашка ориентируется в своем направлении (по умолчанию черепашки изображаются стрелкой, направление которой указывает на ориентацию черепашки). Вновь созданные черепашки ориентированы случайным образом. Цвет черепашек также выбирается случайно.

Чтобы показать, что черепашек действительно сотня, нужно сдвинуть их от центра. Т.к. эта команда относится только к черепашкам (turtles), изменим обращение observer> на turtles>, и введем следующее

turtles> fd 10

Вот что из этого получится:

l1_1.png

Черепашки переместились вперед на 10 шагов. Теперь прикажем им переместиться вперед на случайное число шагов (от 0 до 9):

turtles> fd (random 10)

l1_2.png

Наконец, перейдя опять к observer>, очистим игровой мир командой ca — все черепашки исчезнут.

Набирать одиночные команды в Command Center удобно, но вряд ли этот способ подойдет для создания сколько-нибудь сложной модели (особенно, если мы захотим ее потом использовать). NetLogo позволяет создавать собственные программы и процедуры. Начнем с создания кнопки setup, назначение которой — задать начальные установки модели.

Для этого кликнем по иконке Button на панели инструментов, а затем — на свободном месте во вкладке Interface, там где мы хотим создать кнопку. В появившемся окошке введем setup в поле Commands (команды, которые будут выполняться при нажатии кнопки) и в поле Display Name (надпись, отображаемая на кнопке). Жмем OK.

l1_3.png

Однако имя кнопки и имя вкладки Interface, на которой она расположена, подсвечено красным. Это означает, что мы где-то допустили ошибку.

l1_4.png

Нет ничего удивительного, ведь мы еще не создали процедуру, которая будет выполняться по нажатию этой кнопки (командами или примитивами чаще называют встроенные команды NetLogo, а созданные пользователем команды называют процедурами. Те и другие имеют одинаковый статус).

Итак, идем во вкладку Procedures, чтобы создать процедуру setup

l1_5.png

Разберем этот код подробнее:

  • ca (сокращение от clear-all: можно использовать как полное, так и сокращенное имя команды). Эта команда, как мы уже знаем, очищает игровой мир.
  • crt 100 — снова известная команда — создает 100 черепашек.
  • ask turtles [ ] указывает (буквально: просит) каждой черепашке независимо от других выполнять команды, расположенные в скобках. Это эквивалентно тому, как если бы мы выбирали turtles> в командной строке. Отметим, что crt не расположено в скобках, а значит не относится к черепашкам. Эта команда относится к другому виду агентов — наблюдателю (observer). Если в самой команде или в блоке ask не указан вид агентов, к которым относится команда, значит ее выполняет наблюдатель. В NetLogo существует единственный наблюдатель, которого можно представить себе как некое «верховное существо», рассматривающее игровой мир извне и видящее все, что происходит. Третий вид агентов — участки (patches) — неподвижные прямоугольные… участки, служащие для создания ландшафта игрового мира. Четвертый вид агентов — связи, соединяющие между собой две и более черепашки. Последние два видов агентов мы здесь рассматривать не будем.
  • set shape "circle" задает форму (shape), т.е. графическое представление черепашек. Данная команда изменяет форму черепашек c принятой по умолчанию на круговую (circle). Создавать новые графические представления можно с помощью Shapes Editor (в меню Tools. Свои редакторы есть для черепашек и связей).
  • строка setxy random-xcor random-ycor — представляет собой сразу несколько команд. Сначала черепашки выполняют команды random-xcor и random-ycor, каждая их которых возвращает случайное число в диапазоне от минимального до максимального значения координат по осям x и y соответственно. Затем эти два числа используются в качестве аргументов команды setxy.

Нажмем кнопку setup и получим ожидаемую картинку:

l1_6.png

Каждый раз, нажимая setup, мы будем получать новое распределение черепашек.

Перед тем, как перейти к созданию следующей процедуры имеет смысл сохранить проект (File/Save), чтобы потом, как говорится, «не было мучительно больно…».

Итак, приступим к созданию кнопки go-one-step. Пусть процедура, вызываемая по нажатию кнопки, называется go (вообще говоря, между надписью на кнопке и именем процедуры нет никакой связи).

Переключаемся во вкладку Procedures и запишем код процедуры

to go
    move
end

Но что такое move? Это следующая процедура, которую нам предстоит написать:

to move
    ask turtles
    [set heading random 360
    fd 1]
end

l1_7.png

Теперь рассмотрим код этой процедуры:

  • ask turtles [ ] — указывает, что делать черепашкам.
  • set heading random 360 — еще одна «двухшаговая» команда. Сначала, каждая черепашка выбирает случайное целое число в диапазоне от 0 до 359 (random не содержит числа, которое является его аргументом). Затем это число присваивается ориентации черепашки (heading, если хотите — направлению «головы» черепашки). Ориентация измеряется в градусах, которые отсчитываются по часовой стрелке.
  • fd 1: Теперь черепашки должны сделать по одному шагу вперед в новом направлении.

Разве нельзя было написать все это прямо внутри go? Конечно можно, но наш проект будет развиваться, в него будет добавляться новые возможности, процедуру go хотелось бы сохранить простой, насколько это возможно. Тогда по ней будет удобно разбираться как устроена модель. Постепенно в go будут добавляться расчетные процедуры, вывод графиков и пр. И каждое такое действие будет реализовано отдельно процедурой.

Каждый раз, когда мы нажимаем go-one-step, будет выполняться turn-step. Было бы хорошо, чтобы выполнение turn-step продолжалось столько шагов, сколько нам нужно. Добиться этого легко: создаем новую кнопку — go (она выполняет процедуру go), и в окне редактирования отмечаем галочкой Forever.

l1_8.png

В результате будет создана «постоянная кнопка» (forever-button) go, которая будет оставаться включенной до тех пор, пока ее не выключат повторным нажатием. Постоянные кнопки отличаются по оформлению от обычных («разовых»).

l1_9.png

Давайте пока поэкспериментируем с другими командами, относящимися к черепашкам. Например, наберите в Command Center set color red (не забыли указать адресата — turtles>?), или добавьте это в код процедур (в блок ask turtles [commands]). Заметьте, что turtles> set color red эквивалентно, например, следующему: observer> ask turtles [set color red].

Вы может набрать turtles> pendown (опустить перо, чтобы черепашка могла чертить траекторию своего движения) и увидите «следы», оставляемые черепашками, или изменить set heading (random 360) на lt (random 45). Можно сделать число создаваемых черепашек переменным. Вместо crt 100 в setup запишем crt number, а значение переменной number зададим при помощи ползунка, который можно создать так же, как и кнопку. Хорошо то, что очень быстро можно увидеть результаты сделанных изменений. Тем не менее, работа над проектом продолжается…

Разработка модели: от черепашек к светлячкам

У нас есть сотня черепашек бесцельно блуждающих по игровому миру. Хотелось бы, чтобы черепашки изображали светлячков и подражали, пусть и упрощенно, их поведению. Например, мерцали синхронно при встрече друг с другом. Для этого нужно снабдить наших черепашек-светлячков несколькими переменными: clock — «внутренние часы» светлячка (он будет светить при clock = 0, затем показания счетчика постепенно увеличиваются до 9, после чего опять сбрасываются в 0), threshold — значение clock при котором светлячок перестает светить, reset-level — показания счетчика, которые устанавливаются, когда светлячок видит другого светящего светлячка и window — период «безразличия» после вспышки, в течение которого светлячок не реагирует на вспышки других.

Начнем с того, что объявим эти переменные перед кодом процедур.

turtles-own
[ clock       ;; счетчик светлячка
  threshold   ;; значение счетчика при котором светлячок перестает светить
  reset-level  ;; показания счетчика, устанавливающиеся, когда светлячок видит вспышку
  window       ;; светлячок не реагирует на вспышки, если (clock <= window)
]

После «;» идет комментарий к коду.

Теперь мы можем записать процедуру setup, где присвоим объявленным переменным реалистичные значения. Светящие светлячки отображаются желтыми, а остальные — серыми.

to setup
  ca
  crt number
  ask turtles
    [ setxy random-xcor random-ycor
      set shape "circle"
      set clock random (round 10) ;; т.к. значения счетчика изменяются от 0 до 9
      set threshold 1
      set reset-level threshold
      set window -1
      ifelse (clock < threshold)
        [ set color yellow ]
        [ set color gray ]
     ]
end

Мы использовали новую команду: ifelse (test) [commands1] [commands2], которая выполняет команды commands1, если значение test истинно, и commands2 — в противном случае.

Вводим все это.

l1_10.png

Ну вот, опять ругань — значение-то number мы еще не задали! Исправляемся. Используем кнопку на панели инструментов вкладки Interface и выбираем в выпадающем меню «ползунок» (Slider). Наш ползунок регулирует значение переменной number, которая будет изменяться в диапазоне от 0 до 2000 с шагом 10.

l1_11.png

Теперь все в порядке. Впрочем, нет. Вряд ли светлячкам свойственно крутиться совершенно бесцельно, как это описано в move. Пусть наши светлячки совершают случайный поворот направо или налево, перед тем как продолжить движение вперед. Новый вариант move имеет вид

to move
  ask turtles [
    rt random-float 90 - random-float 90
    fd 1
  ]
end

В go мы должны добавить процедуру, которое увеличивает значение счетчика clock на каждом шаге и изменяет цвет светлячка в соответствии со значением clock.

to go
   move
   ask turtles [
      increment-clock
   ]
   ask turtles [
    ifelse (clock < threshold)
      [ set color yellow ]
      [ set color gray ]
  ]
end
to increment-clock
   set clock (clock + 1)
   if clock = 10
     [ set clock 0 ]
end

Мы использовали новую команду if (test) [commands], которая является упрощенным вариантом ifelse. Если вернуться к вкладке интерфейс и запустить модель, нажав go-one-step, мы увидим, что светлячки желтого цвета (т.е. мерцающие) на следующем шаге гаснут (становятся серыми).

l1_12.png

Добавляем правило синхронизации

Теперь наши светлячки движутся кругами и мерцают каждые 10 шагов. Однако в их мерцании нет никакой синхронности. Почему? Ну, хотя бы потому, что мы не реализовали простейшего правила такой синхронизации. Оно состоит в следующем: когда соседний светлячок вспыхивает, то clock устанавливается равным threshold. Следовательно, мы нуждаемся в процедуре look, чтобы следить за вспышками соседних светлячков.

to look
   if ( count turtles in-radius 1 with [color = yellow] >= 1 )
     [set clock reset-level ]
end

Что делает этот тест? Во-первых, он считает количество мерцающих светлячков по соседству с данным, а во-вторых — проверяет больше ли оно единицы (ведь и сам светлячок находится в собственной окрестности). Эта процедура вызывается после increment-clock, если светлячок не мерцает сам, и стал снова чувствителен к мерцанию окружающих его сородичей.

to go
   move
   ask turtles [
      increment-clock
      if ( (clock > window) and (clock >= threshold) )
        [ look ]
   ]
   ask turtles [
      ifelse (clock < threshold)
        [ set color yellow ]
        [ set color gray ]
   ]
end

Ну вот, правило синхронизирующее мерцания светлячков готово. Проверим, работает ли оно.

Улучшаем интерфейс

Наша модель работает. Теперь с ее помощью можно изучать, как различные внешние факторы влияют на синхронизацию. Сколько времени, например, займет синхронизация 80% светлячков? Как влияет на это время численность популяции? А как влияет значение window? Эксперименты с нашей моделью помогут выявить новые закономерности в групповом поведении светлячков, которые затем можно будет проверить в природных условиях.

Чтобы сделать работу с моделью более удобной, нам предстоит внести несколько улучшений в интерфейс. Чтобы вывести на экран количество шагов работы модели, создадим новый элемент интерфейса — датчик (monitor). Выбираем на панели инструментов в Interface пункт Monitor и указываем, что необходимо вывести значение ticks.

l1_13.png

Эта встроенная команда возвращает интересующее нас количество шагов. Поместим ее также в процедуру go, чтобы значение обновлялось на каждом шаге работы.

На экране появляется датчик «Число шагов», значение которого обращается в 0 после нажатия setup и увеличивается на единицу после каждого нажатия на go-one-step. Как видно, ничто не мешает использовать для именования элементов интерфейса русский язык.

l1_14.png

Хорошо бы знать также количество мерцающих в данный момент светлячков. Для этого создадим датчик Flashes, основанный на глобальной переменной — flashes. Глобальную переменную объявим, добавив строчку

globals [ flashes ]

после команды turtles-own [ ... ]. Код процедуры, подсчитывающей мерцающих светлячков выглядит так:

to count-flashes
   set flashes ( count turtles with [color = yellow] )
end

count-flashes может вызываться в конце процедуры go, а как создать датчик мы уже знаем. Теперь, выполняя программу шаг за шагом, мы сможем определить момент, когда синхронизация охватит более 80% популяции светлячков. Попробуйте сделать это самостоятельно.

Долго? Согласен. Гораздо удобнее было бы выводить на экран график, изображающий количество мерцающих светлячков (flashes) как функцию времени (steps). Естественно, NetLogo позволяет выводить графики. Для этого нужно создать процедуру, задающую параметры данного графика, а затем — процедуру, обновляющие данные на графике на каждом шаге выполнения модели. Итак, в процедуру setup добавим вызов процедуры create-plot

to create-plot
  set-current-plot "Flashing Fireflies"
  set-plot-y-range 0 number
end

и в go — вызов процедуры do-plot

to do-plot
  set-current-plot "Flashing Fireflies"
  plot flashes
end

Процедура create-plot устанавливает: * окно для рисования графика; * диапазон значений по оси y: от 0 до number (ясно, что численность мерцающих светлячков не может быть больше общей);

Процедура do-plot выбирает график "Flashing Fireflies", и добавляет в него очередное значение flashes.

Чтобы set-current-plot "Flashing Fireflies" сработало, необходимо создать соответствующий элемент интерфейса и изменить его имя на то, которое используется в коде (Flashing Fireflies). Кроме того, здесь мы можем задать автоматическое масштабирование координатных осей (Autoplot) и цвет кривой, выводимой на графике (в нашем случае: красный).

l1_15.png

Наведем теперь порядок в расположении элементов интерфейса. Для этого, щелкнем правой кнопкой мыши на интересующем нас элементе. Выбирая Select, можно изменять размеры или расположение элемента.

Теперь нажимаем setup, затем go, и получаем нечто вроде этого.

l1_16.png

Итак, в наших руках простейшая модель для исследования задачи синхронизации мерцания светлячков. Конечно, процедуры можно было бы написать и получше (в File/Models Library, в разделе Biology, есть более аккуратная реализация этой модели). Тем не менее, модель работает, а дальше вы сами можете ее развивать и изучать поведение светлячков (код данной модели находится в файле Fireflies.nlogo архива).

Информация о модели

Подробная информация о каждой модели находится во вкладке Information.

l1_17.png

Что делать дальше?

Изучите, как численность светлячков влияет на время синхронизации 80% их популяции (устанавливайте number равным 10, 20, 50, 100, 200, 500, 1000, и пробуйте). Убедитесь в том, что полученный результат устойчив, запуская модель несколько раз с одними и теми же параметрами.

Рассмотрите, как для фиксированной численности светлячков (например, 500), этот интервал зависит от значения переменной window (времени, в течение которого светлячок не обращает внимание на мерцание соседей). Добавьте ползунок или окно ввода для изменения значения window. Как можно трактовать этот эффект с точки зрения биологии?

Предложенный способ синхронизации мерцаний далеко не единственный. Можете ли вы улучшить существующий способ или предложить свой?



Комментарии

comments powered by Disqus