jackygu's blog

发布于 2023-09-02到 Mirror 阅读

涌现的建模:NetLogo入门

这两天看关于”涌现“现象的内容,无意中发现了NetLogo这个软件,可以用它方便的为各种涌现(Emergence)现象建模,甚至还可以为进化博弈(Evolutionary Game)模型进行建模分析,因此迅速花了几小时学习了下,并把学习笔记整理如下。

另外,Logo语言是笔者在1984年学习的第一门计算机语言,所以当40年后,再一次用到“小图龟(Turtle)”时,顿感亲切!

NetLogo (官网:https://ccl.northwestern.edu/netlogo )是一个多主体可编程的建模环境(Multi Agent-based Programmable Modeling Environment),它基于Logo绘图语言,用于模拟自然和社会现象。它由Uri Wilensky于1999年发起,并由西北大学Center for Connected Learning and Computer-Based Modeling (CCL)中心持续开发,目前最新版是6.3.0,支持Windows,MacOS和Linux桌面系统。

NetLogo非常适合对随时间演化的复杂系统进行建模。可以模拟成百上千个独立运行的"主体"(agent),这使得我们能够探究个体行为与涌现出的宏观模式之间的微观与宏观联系。

本文参考张发翻译的《NetLogo 4.0.2 用户手册》,整理了一份简易教程,以便更好地使用NetLogo来理解仿真建模。

第一部分:体验

模型实例:聚会(Party)

这一部分让你了解什么是计算机建模以及如何使用它,也让你对 NetLogo 软件有所了解。

场景描述

你是否参加过聚会,注意过人们是怎样聚集成小组的吗?你也可能注意到人们并非一直呆在一个小组里,而是走来走去。当人们走来走去的时候,小组就发生变化。如果你长期观察这种变化,你应该注意到使用模型思维来研究这个聚会现象。

NetLogo 的“Party”模型从性别这个特殊角度考察这个问题:为什么有些小组多数是男性,或多数是女性?相同的思路可以扩展到拥有相同性格、观点、话题的人们往往更容易聚在一起。

初始化模型

  1. 启动 NetLogo

  2. 打开文件夹 "Social Science"下的"Party"模型

  3. 点击”Setup" 按钮

这些线表示聚会上男女混合的小组。男性用蓝色表示,女性用粉色。数字是每个小组的人数。假如你邀请了 150 人参加聚会,假设人们分成了 10 组,我们使用计算机仿真,来看看人们是怎样扎堆的。

启动模型

  1. 按下 "go" 按钮 (再次按下 "go" 会停止模型运行)

  2. 观察人们的移动直到模型停止

  3. 看图形输出了解发生了什么?每组有多少人?

开始时你可能认为将 150 人分成 10 组的结果是每组大约 10 人。从模型运行得知,人们并没有均等的分成 10 组,相反,有些组人数特别少,而有些组人数却特别多。更有意思的是,随着时间发展,所有小组男女都转变为均由同性组成。

如何解释这个现象?

对这个问题有很多可能的解释。本模型的设计者认为聚会上的小组不是完全按随机方式形成的。小组如何形成取决于个体的行为。模型设计者关注一个特殊变量“tolerance”(容忍度):

这里将容忍度定义为个体感到舒服的异性的比例。如果小组中异性比例超过容忍度,他们就觉得不舒服,因此离开这一组去寻找别的小组。

例如,如果容忍度水平设为 25%,那么一个男性只有在女性比例少于25%的小组里才会感到舒服。同样女性只有在男性少于 25%的小组里才会感到舒服。当个体变得不舒服时会选择离开,转移到别的小组,这可能又让这个组中的某些人不舒服。这种链式反应不断进行,直到聚会上的所有人都感到舒服。

重启模型

在这个模型中,容忍度可以用滑动条改变,重新运行模型,再看看结果会如何。

  1. 如果 "go" 按钮已按下 (黑色),说明模型还在运行。再次按下该按钮停止运行。

  2. 通过拖动滑块调整 "tolerance" 值

  3. 按下"setup"按钮重设模型

  4. 按下"go"按钮再次启动模型

挑战

  1. 作为聚会的主人,你希望看到各组里都是男女混合。调整容忍度滑动条,让每组都尽量能够男女混合。 为保证 10 个小组都是男女混合,容忍度水平要设成多少? 如何达到尽量让不同人混在一起的容忍度,也许是会议或社群组织者要考虑的重要问题。

  2. 你能想到可能影响每组中男女比例的其他因素吗? 当你检验假设的时候,你会从数据中发现模型所产生的涌现(Emergence)。

  3. 容忍度水平与混合组的比例有什么关系?

涌现

NetLogo对聚会这样的情景建模使你可以对系统进行快速、灵活的试验,而在现实情况下这是很困难的。建模也给了你少受偏见的影响去观察各种情景的机会,因为你可以检查系统内部的动态。你会发现随着你建模越来越多,对许多现象的原有的想法会被改变。例如 Party模型一个令人惊讶的结果是:即使容忍度水平相对较高,不同性别的人仍然会分开。

这是关于涌现现象的一个经典例子,这里小组模式是许多个体交互的结果。涌现思想可以应用在几乎任何领域,NetLogo是研究涌现现象的重要工具,NetLogo 模型库里有许多模型,演示了各种不同类型的涌现现象,如:蚂蚁寻食,鸟类迁徙等著名涌现现象

要更详细了解关于涌现的讨论以及NetLogo如何帮助学习者进行探索,参见《Modeling Nature's Emergent Patterns with Multi-agent Languages》 (Wilensky, 2001).

模型实例:狼吃羊( Wolf Sheep Predation)

我们来试一个生物模型:狼吃羊,这是一个掠食-食饵种群模型

  • 从文件菜单打开模型库

  • 从 Biology 部分选择"Wolf Sheep Predation" 按下"Open"

当你第一次打开模型时,你会看到视图是空的(全黑)。要让模型开始,你需要先设置它。

  • 按下"setup"按钮

  • 按下"go"按钮开始仿真

  • 按下"go"按钮停止运行

控制模型:按钮

按钮按下后模型就会通过执行一个动作做出响应。按钮分为“一次性”(once)和“永久性”(forever)两种。可以通过按钮上的一个符号区分二者。

  • 永久性按钮的右下角有两个箭头:

  • 一次性按钮没有箭头:

一次性按钮执行动作一次然后停止。当动作完成后,按钮弹起。

永久性按钮不断的执行一个动作。当你想让动作停止时,再次按下按钮。它会完成当前动作,然后弹起。

大多数模型,包括狼吃羊模型,有一个一次性按钮称为“setup”和一个永久性按钮称为“go”。许多模型还有一个一次性按钮称作“go once”或“step once”,它们很像go按钮,但区别在于它们只执行一步(时间步长)。使用这样的一次性按钮能让你更仔细的查 看模型的运行过程。

当模型因某种原因卡住时,可以使用Tools下的Halt强行停止模型运行。

控制速度:速度滑动条

滑块左移使模型速度变慢,右移使模型速度变快,变快可能会引起跳帧。

另外,所谓的加速,其实是视图更新更频繁。实际没有变慢,可以从时钟(tick)显示确认这一点。

调整设置:滑动条和开关

模型的配置给了你尝试不同场景或假设的机会。修改配置运行模型,观察这些改变所引起的反应,使你能更深入的了解所模拟的现象。

调整1:开关

我们看看如果改变下面的设置的话,羊群怎么变化。

  • 打开"grass?" 开关

  • 按下"setup" 和 "go" ,运行与上次差不多相同的时间

开关有与它相连的信息。这些信息采用开/关格式。开关发出特别的指令,这些指令对模型并非必要,但为模型增加了附加的维度。打开"grass?"影响模型结果。

通过设置和打开草的增长率,我们能够对三个因素建模:羊、狼和草。

调整2:滑动条。

滑动条是一个可调的数值范围。例如"initial-number-sheep"滑动条最小值为0,最大值为250。模型运行时可以有 0 只羊,也可以有 250只羊,或者中间的任何一个数值。

实验:

  • 关掉"grass?" 开关

  • 设置"initial-number-sheep" 滑动条为 100.

  • 设置"initial-number-wolves" 滑动条为 20.

  • 按下 "setup" 和 "go".

  • 模型运行约 100 时间步

实验:

  • 设置 "initial-number-sheep" 为 80 ,"initial-number-wolves" 为 50.

  • 设置"sheep-reproduce" 为 10.0%.

  • 按下"setup" 和 "go".

  • 模型运行约 100 时间步

绘图和监视器

建模的目的之一是对那些难以在实验室中进行研究的问题收集数据。NetLogo主要有两个显示数据的方式:绘图和监视器。

绘图(Plots)

这些线显示了随着时间推进,模型中发生了什么。要想知道每条线代表什么,在图形窗口的右上角单击”Pens”,打开画笔图例。一个关键字说明了每条线是什么。在本例中就是种群数量。 当图快被充满时,水平轴增加,以前的数据被压缩只占一部分空间,更多的空间用来绘制将来的图形。

如果你想保存图上数据以备查看或在另一个程序里进行分析,使用 File 菜单的"Export Plot"。这些数据就被保存,数据格式可以被电子表格,如 Excel,或数据库程序识别。

监视器(Monitors)

监视器"time-ticks"告诉我们仿真时间。其他的监视器告诉我们狼、羊、草的数量。(记 住,草的数量除以 4,为了别使图形太高)

当模型运行时监视器中的数值不断更新,而图形能显示模型整个运行过程中的数据。

模型库

模型库包括五部分:Sample Models, Perspective Demos, Curricular Models, Code Examples, HubNet Computer Activities.

模型样例(Sample Models)

Sample Models 部分是分科目组织的,目前有 210 多个模型。我们一直在增加模型,因此过段时间后能看到新加的模型。

有些文件夹下包含"(unverified)"子文件夹。这些模型是完整、可用的,但模型的内容、精度、代码质量等仍在评审之中。

透视演示(Perspective Demos)

这些模型在 Sample Models 中也有。但是略作修改,用来演示 NetLogo 的透视功能。

课程模型(Curricular Models)

这些模型是西北大学 CCL 开发的在学校使用的课程。有些模型在 Sample Models 中也有,有些没有。看看信息标签页,了解更多的信息。

代码例子(Code Examples )

这是 NetLogo 特别功能的一些简单演示。当你以后扩展现存模型或新建模型时很有用。例如,你想在模型中增加直方图,可以看看"Histogram Example",看看怎么做。

HubNet 计算机活动(HubNet Computer Activities)

这一部分包括教室中使用的参与式仿真。要了解HubNet的更多信息,参见 HubNet Guide.

第二部分:常用命令Commands

在这一部分,焦点从观察模型转换到改变模型。

模型实例: 基本交通模型(Traffic Basic)

  • 在"Social Science"部分,找到并打开 Traffic Basic 模型

在这个模型里,你会注意到一系列蓝车里有一辆红车,车流同向移动。这些车时不时的会挤成一堆,无法移动。这是关于幽灵式阻塞的模型,即有时交通流会出现阻塞,但却找不到任何明显的原因。通过改变模型的参数:加速与刹车,会发现堵塞是由驾驶习惯导致的。

这个模型的配置太简单,黑色背景、白色街道、一些蓝车和一辆红车。现在需要对模型做点改变:改变车的形状和颜色、加上房子或路灯、新建信号灯、或者再创建一条车道。这些建议有些是装饰性的,只是改善模型的观感,另外一些是行为性的。在本教程里我们主要关注较简单的、装饰性的改变。

命令中心(The Command Center)

命令中心位于界面最下方,在这里可以向模型发出指令。

例如:输入下面所示的文本

ask patches [set pcolor yellow]
ask turtles [set color brown]

可以看到背景色和图龟颜色都变了。

NetLogo是由海龟(turtles)、瓦片(patches)和观察者(observers)组成的二维世界。瓦片构成背景,海龟在背景上移动,观察者(observer)是观察着所有事情的一个生命体。

颜色名称

为得到一个没有名字的颜色,你需要使用一个数值,或者在颜色名上加上或减去一个数。

例如,输入set color red与输入set color 15效果完全一样。要得到一个更浅或更深的颜色,只需使用一个比该颜色更小或更大的一个数。如

  • set pcolor red - 2 ("-" 两侧的空格很重要)

  • set pcolor red + 2,通过在 red 上加上一个数, 得到更浅的颜色。

主体监视器(Agent Monitors)和主体命令器(Agent Commanders)

修改单个图龟属性

修改属性:

  • 方法一:在Agent Monitors最下方直接输入set color green

  • 方法二:直接在Turtle Monitor中改属性

  • 方法三:在命令菜单中改

修改单个patch属性

修改patch的属性方式同修改图龟属性。

第三部分:程序(Procedures)

NetLogo 中可以执行命令的主体类型有:

  • 瓦片(patch)

  • 海龟(turtle)

  • 链(link)

  • 观察者(observer) 瓦片是静止的,组成网格。海龟在网格上移动,链(link)接两个海龟。观察者俯视在进行的所有事情, 做那些海龟、瓦片和链自己不能做的事情。

所有这四种主体都能执行 NetLogo 命令。前三种主体还能运行程序(procedures)。

一个程序包括一系列 NetLogo 命令,你将它们定义为一个单一的新命令,让海龟移动、进食、繁殖和死亡。还将学习如何制作监视器、滑动 条和绘图。我们要建立一个简单的生态系统模型,与教学#1 的狼吃羊模型部分相似。

制作 setup 按钮

  • 新建一个模型。

  • 切换到代码code窗口,输入setup按钮的代码:

to setup 
 clear-all 
 create-turtles 100 
 ask turtles [ setxy random-xcor random-ycor ] 
end

制作 go 按钮

  • 同上,在桌面上创建go按钮,注意:需要选择forever,持续执行。

  • 在代码窗口添加代码:

to go 
 move-turtles 
end

to move-turtles
  ask turtles [
    right random 360  ;向右随机旋转一个角度
    forward 1
  ]
end

为海龟添加属性

turtles-own [energy]

添加一个叫energy的属性。

另外,在添加一个eat-grass的方法,并在go方法中调用eat-grass

to eat-grass
  ask turtles [
    if pcolor = green [
      set pcolor brown
      set energy energy + 10
    ]
  ]
end

move-turtles方法中,增加走一步需要消耗能量的代码:

to move-turtles
  ask turtles [
    right random 360 ;随机旋转角度
    forward 1
    set energy energy - 1
  ]
end

添加监视器

  • 添加海龟数量的监视器,在reporter中输入:count turtles

  • 添加绿地数量的监视器,在reporter中输入:count patches with [pcolor = green]

添加开关

  • 添加“开关”组件,注意变量名需要加问号?,然后重写eat-grass方法
to eat-grass
  ask turtles [
    if pcolor = green [
      set pcolor black
      set energy energy + 10
    ]
    ifelse show-energy? [
      set label energy
    ] [
      set label ""
    ]
  ]
end

添加养小海龟的方法

to reproduce 
  ask turtles [ 
    if energy > 50 [ ;如果能量值>50,则生小海龟
      set energy energy - 50 ;生完小海龟,能量值减50
      hatch 1 [ set energy 50 ] ;hatch为孵化一个新的turtle(属性同母体),后面[]中写初始化设置
    ] 
  ] 
end

添加海龟死亡的方法

to check-death
  ask turtles [
    if energy <= 0 [ die ] ;die为默认方法,销毁一个turtle
  ]
end

添加草场生长的方法

to regrow-grass
  ask patches [
    if random 100 < 3 [ set pcolor green ] ;3%概率会生长出草地
  ]
end

将上述方法添加到go方法中,供每一步都调用

to go 
  move-turtles 
  eat-grass
  reproduce 
  check-death 
  regrow-grass 
end

跟踪数据变化,并绘图

添加个一个绘图的方法:

to do-plots 
  set-current-plot "Totals" 
  set-current-plot-pen "turtles" 
  plot count turtles 
  set-current-plot-pen "grasses" 
  plot count patches with [pcolor = green] 
end

然后分别在setupgo方法中调用do-plots方法。

控制时间与步数 tick

setup方法中添加:reset-ticks;

修改go方法:

to go 
  if ticks >= 500 [ stop ]
  ...
  tick ;步进一次
end

添加草场生长速度的参数输入框

添加一个输入框,并命名为regrow-grass-speed,数量范围为0-100。

然后将regrow-grass方法改为如下:

to regrow-grass
  ask patches [
    if random 100 < regrow-grass-speed [ set pcolor green ]
  ]
end

添加初始化海龟数量的滑块

添加一个滑块,命名为initial-turtles,然后将set-turtles方法改为:

to set-turtles
  create-turtles initial-turtles
  ask turtles [
    setxy random-xcor random-ycor
  ]
end