问题描述
我正在构建一个包含社交扩散组件的Netlogo模型,并使用Table扩展遇到了令人惊讶的性能问题。
对于某些情况:在模型中,每个业务代表都有一个态度表,该态度表带有字符串键(例如“ Environment”),浮点值为-1到1。每个刻度,业务代表会根据其态度更新其态度。接触和每个接触的权重。为了制作原型,我对每个联系人使用简单的更新规则:
a(t) = a(t-1) + w * [b(t-1) - a(t-1)]
其中a是坐席的态度,b是接触态度,w是重量。每个座席都有5-10个联系人。
我已经通过两种方式实现了这一点。第一个使用效果不错的链接。但是,随着我的扩展,用于此目的的内存占用量似乎会变得很大。由于网络不是动态的,因此我正在尝试将其实现为一个表,其中键是联系人乌龟ID,值是权重(严格来说,我创建了一个称为“ contacts”的乌龟ID列表以及一个对应权重的表,以避免重新创建每次迭代时列出该列表)。这似乎使许多代理使用的 更少,但出乎意料地慢了一个数量级。
以下是基于网络的更新的摘要:
ask my-in-links [
let neighborAttitude table:get [attitudes] of other-end "Environment"
let myAttitude table:get [attitudes] of myself "Environment"
let influence weight * (neighborAttitude - myAttitude)
set myAttitude myAttitude + influence
table:put [attitudes] of myself "Environment" myAttitude
]
以及基于表的版本:
foreach (contacts) [ i ->
let myAttitude table:get attitudes "Environment"
let neighborAttitude table:get [attitudes] of homeowner i "Environment"
let w table:get contactWeights i
let influence w * (neighborAttitude - myAttitude)
set myAttitude myAttitude + influence
table:put attitudes "Environment" myAttitude
]
从一些测试看来,获得NeighborAttitude会大大降低速度。如果我注释掉那条线,那么从座席的态度表中获取和放下似乎和基于网络的障碍一样快。因此,似乎正在寻找另一只乌龟(“房主”)。
在Netlogo中,是否确实存在某些通过ID查找乌龟/代理的速度真的很慢的问题?看来它应该基本上是免费的,但我不知道它的数据结构是什么。
解决方法
此代码与NetLogo不太相似,因此我在解析它时遇到了一些麻烦,而我的评论/答案可能已经完全忘记了重点。
我完全不理解在这些行中使用table
:
ask my-in-links [
let neighborAttitude table:get [attitudes] of other-end "Environment"
您从ask my-in-links
开始。大概是在ask turtles
或类似的块中。因此,运行代码首先选择一个乌龟,比方说,乌龟与其他乌龟有5个链接。它命中此代码并遍历这5个链接中的每一个,并创建一个包含这5个值的表,这些5个值以某种方式存储在键[attitudes] of other-end "Environment"
中。
假设您具有链接(必须能够使用ask my-in-links
),然后采用类似于NetLogo的方式进行操作,如下所示。请注意,这是一个完整的模型,您可以将其放入一个空的NetLogo模型中以运行它。
turtles-own
[ myAttitude
myUpdatedAttitude
]
links-own
[ wgt
]
to setup
clear-all
create-turtles 20
[ setxy random-xcor random-ycor
set myAttitude -1 + random-float 2
]
; create a network
repeat 50
[ ask one-of turtles
[ create-link-to one-of other turtles
[ set wgt random-float 1 ]
]
]
reset-ticks
end
to go
type "average attitude: " print mean [myAttitude] of turtles
let w 0.4
; calculate next value and store until all calculated
ask turtles with [any? in-link-neighbors]
[ let wtd-diffs [([myAttitude] of other-end - [myAttitude] of myself) * wgt] of my-in-links
set myUpdatedAttitude (1 - w) * myAttitude + w * sum wtd-diffs
]
; make the change
ask turtles [ set myAttitude myUpdatedAttitude ]
tick
end
对于每个海龟,此代码依次构造海龟和受其影响的海龟之间的姿态值的加权差异的列表。因此,如果它有5个in-link-neighbors
,则wtd-diffs列表将具有5个值。下一行计算总影响力,并将其存储在其他值中,以便所有计算均基于当前值。请注意,我不确定您使用方程式的确切方式,因为我不确定您如何防止方程式简单地不受控制地增长。
我意识到这不能回答您有关表性能的问题,但是我希望这种方法可以解决您所有的性能问题。
,提交此文件后,我立即尝试了一项实验,证实了我的怀疑,我认为得出了可以接受的解决方案。事实证明,仅要求海龟查找“ turtle i”是缓慢的,并且随着代理数量的增加而变得缓慢。
我猜测,使用of turtle i
的Netlogo相当于of turtles with [who = i]
,并且必须遍历所有海龟列表,直到找到匹配的ID。因此,作为测试,再次使用表扩展名,我手动创建了所有海龟的表:
globals [turtleTable]
...
to initialize-turtleTable
set turtleTabletable:make
ask turtles [
table:put turtleTable who self
]
end
然后可以说of turtle i
而不是of table:get turtleTable i
。这是稍微麻烦的语法,但是可以由报告程序清除。与完全退出并重新启动NetLogo相比,这最终达到了预期的效果,与使用链接差不多,但是大约25,000个代理使用了近一半的内存( 5GB)。