作为练习,我正在尝试用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发布于 2019-09-17 04:26:38
问题是,使用deepcopy时,您正在复制observer本身,它是每个代理上的引用,并且在您将要设置此属性时,这些observer副本具有self.prev_agents = None。具体来说,第20行self.prev_agents = deepcopy(self.agents)
对于
observer有各种属性,其中有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通过保留已复制对象的备注字典来避免此问题。
https://stackoverflow.com/questions/57963581
复制相似问题