python - 基于代理的模型的实现
问题描述
我正在尝试在 python 中实现一个基于代理的模型(不使用 Mesa 包)作为实践。我编写了描述观察者(包含所有代理)的代码,它可以帮助邻居代理并告诉每个代理执行一个步骤。在将步骤复制到包含先前情况的列表之前,该步骤会保存在一个新列表中。
代理(本质上是域模型)是以下类型之一:“T”(树)、“S”(土壤)、“B”(燃烧树)和“Bd”(燃烧树)。
这个概念很简单:我们从一些树开始,一些燃烧的树,剩下的就是土壤。- 土壤不会燃烧。- 被烧毁的树木仍然是被烧毁的树木 - 燃烧的树木会点燃它旁边的树木(左、右、上或下),并在下一步中变成被烧毁的树木 - 除非被相邻的燃烧树木点燃,否则树木仍然是树木。
在此代码下方。我有几个版本,但似乎没有一个工作。当我运行以下版本时,出现错误。
import os
import sys
from copy import deepcopy
import random
# observer class
class Obs:
def __init__(self, max_iters=10):
self.agents = []
self.max_iters = max_iters
def run(self):
self.history = []
self.prev_agents = None
self.iters = 0
while self.iters < self.max_iters:
print(self.iters)
self.history.append(deepcopy(self.agents))
self.prev_agents = deepcopy(self.agents)
for agent in self.prev_agents:
agent.step()
self.iters += 1
def add_agent(self, x, y, agent_type, num_agent):
self.agents.append(
Agent(
agent_type=agent_type,
x=x,
y=y,
observer=self,
agent_id=num_agent
))
def get_neighbours(self, x, y):
# items do not move so use current_situation
nbs = []
for agent in self.agents:
if (abs(agent.x-x) == 1) & (abs(agent.y-y) == 1) & (abs(agent.x-x) == abs(agent.y-y)):
nbs.append(agent)
return nbs
def set_agent(self, index, agent):
self.agents[index] = agent
def changed(self, agent_id):
if self.prev_agents[agent_id].agent_type != self.agents[agent_id].agent_type:
# been changed, can't change it back so skip it
return True
return False
class Agent:
def __init__(self, agent_type, x, y, observer, agent_id):
self.agent_type = agent_type
self.x = x
self.y = y
self.observer = observer
self.agent_id = agent_id
def step(self):
# perform action
if self.agent_type == 'B':
# burning
nbs = self.observer.get_neighbours(self.x, self.y)
for nb in nbs:
if nb.agent_type == 'T':
self.observer.set_agent(
nb.agent_id,
Agent('B',
nb.x,
nb.y,
nb.observer,
nb.agent_id))
# set to burned
self.agent_type = 'Bd'
self.observer.set_agent(
self.agent_id,
self)
elif self.agent_type == 'T':
if not self.observer.changed(self.agent_id):
self.observer.set_agent(
self.agent_id,
self)
else:
# nothing happens to soil or burned trees
self.observer.set_agent(
self.agent_id,
self)
xsize, ysize = 10, 10
num_trees = 40
num_burning = 10
num_soil = (xsize * ysize) - num_trees - num_burning
items = ['T'] * num_trees + ['B'] * num_burning + ['S'] * num_soil
random.shuffle(items)
observer = Obs(10)
for i, item in enumerate(items):
x = i % xsize
y = i // xsize
observer.add_agent(x=x, y=y, agent_type=item, num_agent=i)
observer.run()
我得到的错误:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-26-74779de210e4> in <module>
104 observer.add_agent(x=x, y=y, agent_type=item, num_agent=i)
105
--> 106 observer.run()
<ipython-input-26-74779de210e4> in run(self)
20 self.prev_agents = deepcopy(self.agents)
21 for agent in self.prev_agents:
---> 22 agent.step()
23 self.iters += 1
24
<ipython-input-26-74779de210e4> in step(self)
79 self)
80 elif self.agent_type == 'T':
---> 81 if not self.observer.changed(self.agent_id):
82 self.observer.set_agent(
83 self.agent_id,
<ipython-input-26-74779de210e4> in changed(self, agent_id)
45
46 def changed(self, agent_id):
---> 47 if self.prev_agents[agent_id].agent_type != self.agents[agent_id].agent_type:
48 # been changed, can't change it back so skip it
49 return True
TypeError: 'NoneType' object is not subscriptable
解决方案
问题是deepcopy
您正在复制作为observer
每个代理的引用的自身,并且这些observer
副本self.prev_agents = None
在您即将设置此属性时具有。详细来说,第 20 行self.prev_agents = deepcopy(self.agents)
:
- 为 中的每个代理
self.agents
创建一个副本。 - 每个代理都存储一个引用
self.observer
。 - 因为我们正在做一个深拷贝,所以我们也需要复制那个观察者。
- 具有
observer
各种属性,其中有self.prev_agents
。 - 由于我们仍在计算 的右手边
self.prev_agents = deepcopy(self.agents)
,self.prev_agents
仍然是None
(第 14 行)。 - 因此,每个代理副本现在都有一个引用
self.observer
,它是原始观察者的副本,并且该副本具有self.prev_agents is None
.
这就是为什么在随后step
对代理的调用中引用了错误的观察者,从而导致了错误。我不明白你为什么要复制观察者,所以使用copy.copy
而不是copy.deepcopy
应该解决问题。
旁注:深度复制每个代理也会遇到表单的引用循环,agent -> observer -> self.agents -> agent
但copy.deepcopy
通过保留已复制对象的备忘录字典来避免此问题。
推荐阅读
- python - 在 sklearn 中训练神经网络时如何保存学习进度?
- python-3.x - scrapy:嵌套的 ItemLoader 生成包含 n(n-1) 个字段的输出
- javascript - 需要解释javascript中的递归反向单链表代码
- vb.net - 通过 VB 脚本编写 SharePoint 中的内容类型
- php - Ajax不发送数据php
- amazon-web-services - 如何通过选择时间间隔从 DynamoDB 表中导出数据
- pandas - 如何处理过滤数据框中不存在的列
- c# - 在for循环中修改类字段而不创建新实例
- javascript - Deno -> 如何运行代码以无错误地运行?
- javascript - 从函数返回 AJAX 调用的结果