首页 > 解决方案 > 基于代理的模型的实现

问题描述

我正在尝试在 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

标签: python

解决方案


问题是deepcopy您正在复制作为observer每个代理的引用的自身,并且这些observer副本self.prev_agents = None在您即将设置此属性时具有。详细来说,第 20 行self.prev_agents = deepcopy(self.agents)

  1. 为 中的每个代理self.agents创建一个副本。
  2. 每个代理都存储一个引用self.observer
  3. 因为我们正在做一个深拷贝,所以我们也需要复制那个观察者。
  4. 具有observer各种属性,其中有self.prev_agents
  5. 由于我们仍在计算 的右手边self.prev_agents = deepcopy(self.agents)self.prev_agents仍然是None(第 14 行)。
  6. 因此,每个代理副本现在都有一个引用self.observer,它是原始观察者的副本,并且该副本具有self.prev_agents is None.

这就是为什么在随后step对代理的调用中引用了错误的观察者,从而导致了错误。我不明白你为什么要复制观察者,所以使用copy.copy而不是copy.deepcopy应该解决问题。

旁注:深度复制每个代理也会遇到表单的引用循环,agent -> observer -> self.agents -> agentcopy.deepcopy通过保留已复制对象的备忘录字典来避免此问题。


推荐阅读