【问题标题】:How to implement a rule-based decision maker for an agent-based model?如何为基于代理的模型实施基于规则的决策者?
【发布时间】:2021-09-24 22:58:54
【问题描述】:

我很难理解如何将基于规则的决策制定方法结合到我尝试开发的基于代理的模型中。

agent的界面很简单。

public interface IAgent
{
   public string ID { get; }

   public Action Percept(IPercept percept);
}

为了这个例子,我们假设代理代表车辆,它们在大型仓库内穿越道路,以装卸货物。他们的路线(道路序列,从起点到代理的目的地)由另一个代理,主管分配。车辆代理的目标是遍历其指定的路线,卸载货物,装载新的,接收主管指定的另一条路线并重复该过程。

车辆还必须意识到潜在的碰撞,例如在交叉点,并根据某些规则给予优先权(例如,载有最重货物的车辆具有优先权)。

据我了解,这是我要构建的代理的内部结构:

所以车辆代理可以是这样的:

public class Vehicle : IAgent
{
  public VehicleStateUpdater { get; set; }

  public RuleSet RuleSet { get; set; }

  public VehicleState State { get; set; }

  public Action Percept(IPercept percept)
  {
    VehicleStateUpdater.UpdateState(VehicleState, percept);
    Rule validRule = RuleSet.Match(VehicleState);
    VehicleStateUpdater.UpdateState(VehicleState, validRule);
    Action nextAction = validRule.GetAction();
    return nextAction;
  }
}

对于 Vehicle 代理的内部状态,我正在考虑类似:

public class VehicleState
{
  public Route Route { get; set; }

  public Cargo Cargo { get; set; }

  public Location CurrentLocation { get; set; }
}

对于此示例,必须为车辆代理实施 3 条规则。

  1. 如果代理附近有另一辆车(例如小于 50 米),则货物最重的车辆优先,其他代理必须保持原位。
  2. 当代理到达目的地时,他们卸下货物,装载新货物并等待主管分配新路线。
  3. 在任何给定时刻,无论出于何种原因,主管都可能发送命令,接收车辆必须遵守该命令(保持位置或继续)。

VehicleStateUpdater 必须考虑代理的当前状态、接收到的感知类型并相应地更改状态。因此,为了让国家反映这一点,例如Supervisor 收到一条命令,可以修改如下:

public class VehicleState
{
  public Route Route { get; set; }

  public Cargo Cargo { get; set; }

  public Location CurrentLocation { get; set; }

  // Additional Property
  public RadioCommand ActiveCommand { get; set; }
}

其中 RadioCommand 可以是值为 None、Hold、Continue 的枚举。

但是现在我还必须在代理状态下注册,如果另一辆车正在靠近。所以我必须向 VehicleState 添加另一个属性。

public class VehicleState
{
  public Route Route { get; set; }

  public Cargo Cargo { get; set; }

  public Location CurrentLocation { get; set; }

  public RadioCommand ActiveCommand { get; set; }

  // Additional properties
  public bool IsAnotherVehicleApproaching { get; set; }

  public Location ApproachingVehicleLocation { get; set; }
}

这是我很难理解如何进行的地方,我觉得我并没有真正遵循正确的方法。首先,我不确定如何使 VehicleState 类更加模块化和可扩展。其次,我不确定如何实现定义决策过程的基于规则的部分。我应该创建互斥规则(这意味着每个可能的状态必须对应不超过一个规则)?是否有一种设计方法可以让我添加额外的规则,而不必来回切换 VehicleState 类并添加/修改属性,以确保代理的内部状态可以处理每种可能的 Percept 类型?

我已经看过《人工智能:现代方法》课程手册和其他资源中演示的示例,但是当必须设计更复杂的模型时,可用示例太简单了,我无法“掌握”相关概念。

如果有人能指出关于基于规则部分的实施的正确方向,我将不胜感激。

我正在用 C# 编写,但据我所知,它与我试图解决的更广泛的问题并不真正相关。

更新:

我尝试合并的规则示例:

public class HoldPositionCommandRule : IAgentRule<VehicleState>
{
    public int Priority { get; } = 0;

    public bool ConcludesTurn { get; } = false;


    public void Fire(IAgent agent, VehicleState state, IActionScheduler actionScheduler)
    {
        state.Navigator.IsMoving = false;
        //Use action scheduler to schedule subsequent actions...
    }

    public bool IsValid(VehicleState state)
    {
        bool isValid = state.RadioCommandHandler.HasBeenOrderedToHoldPosition;
        return isValid;
    }
}

我也尝试实施的代理决策者示例。

public void Execute(IAgentMessage message,
                    IActionScheduler actionScheduler)
{
    _agentStateUpdater.Update(_state, message);
    Option<IAgentRule<TState>> validRule = _ruleMatcher.Match(_state);
    validRule.MatchSome(rule => rule.Fire(this, _state, actionScheduler));
}

【问题讨论】:

  • 这几天我一直在思考这个问题。我不喜欢 VehicleState 包含有关其他车辆及其位置的信息。因为车辆在规则中可能使用的每一点信息(可能是大量信息)都是其状态的一部分。也许 VehicleStateUpdater 应该封装世界状态?然后车辆不需要知道一天中的时间、其他车辆在哪里、它们载有多少货物等 - 它只需要知道它自己的位置和货物。
  • 然后问题从“车辆如何知道所有其他车辆的位置?”转至“VehicleStateUpdater 如何与实时世界状态信息保持同步?”
  • @JerryJeremiah 感谢您的意见。让 StateUpdater 封装世界状态(环境类,因为它是从基于代理的角度调用的)是一个好主意。也许这样一个规则可以同时考虑代理的内部状态和世界状态(环境)。

标签: simulation rules rule-engine agent-based-modeling traffic-simulation


【解决方案1】:

我认为您的问题包含两个主要子问题:

  • 建模灵活性,尤其是关于如何更轻松地向系统添加属性和规则。
  • 如何提出正确的规则集以及如何组织它们以使代理正常工作。

所以让我们去看看他们每个人。

建模灵活性

我认为你现在拥有的东西其实还不错。让我解释一下原因。

您表达了对“一种设计方法允许我添加其他规则而无需来回切换 VehicleState 类和添加/修改属性”的担忧。

我认为答案是“不”,除非您遵循完全不同的路径让代理自主学习规则和属性(如Deep Reinforcement Learning),这会带来一系列困难。

如果您要按照问题中的描述手动编码代理知识,那么您将如何避免在添加新规则时引入新属性的需要?您当然可以尝试预测您将需要的所有属性,并且不允许自己编写需要新属性的规则,但新规则的本质是带来问题的新方面,这通常需要新属性。这与需要多次迭代和更改的软件工程不同。

基于规则的建模

有两种编写规则的方式:命令式和声明式。

  • 在命令式风格中,您编写采取行动所需的条件。当两者都适用时,您还必须注意选择一个操作而不是另一个操作(可能使用优先系统)。因此,您可以制定一条沿路线行驶的规则,并制定一条在优先级较高的车辆接近时停下来的规则。这似乎是您目前正在采用的方法。

  • 在声明式风格中,您声明环境的规则是什么、操作如何影响环境以及您关心什么(将实用程序分配给特定状态或子状态),并让系统会处理所有这些来为您计算最佳操作。所以在这里你声明决定移动如何影响你的位置,你声明碰撞是如何发生的,你声明到达你路线的尽头是好的,碰撞是坏的。请注意,在这里您没有做出决定的规则;系统使用规则来确定在特定情况下具有最大价值的动作。

理解命令式和声明式风格之间区别的一种直观方法是考虑编写一个下棋的代理。在命令式风格中,程序员对国际象棋的规则进行编码,还对如何下棋、如何打开游戏、如何选择最佳走法等进行编码。也就是说,系统会体现出程序员的棋艺。在声明式风格中,程序员只需对国际象棋规则进行编码,以及系统如何自动探索这些规则并确定最佳棋步。在这种情况下,程序员不需要知道如何下好国际象棋,程序就可以真正玩一盘像样的国际象棋。

命令式风格更容易实现,但灵活性较差,并且随着系统复杂性的增加会变得非常混乱。您必须开始考虑各种场景,例如当三辆车相遇时该怎么办。在国际象棋的例子中,想象一下如果我们稍微改变一个国际象棋规则;整个系统需要审查!在某种程度上,命令式系统中几乎没有“人工智能”和“推理”,因为是程序员提前进行所有推理,提出所有解决方案并对其进行编码。它只是一个常规程序,而不是人工智能程序。这似乎是你所说的那种困难。

声明式风格更加优雅和可扩展。您无需弄清楚如何确定最佳操作;系统会为您完成。在国际象棋示例中,您可以轻松地更改代码中的一条国际象棋规则,系统将使用新规则在更改后的游戏中找到最佳着法。但是,它需要一个推理引擎,该软件知道如何接受大量规则和实用程序并决定哪个是最佳操作。这样的推理引擎就是系统中的“人工智能”。它会自动考虑所有可能的场景(不一定一个一个,因为它通常会采用更智能的技术来考虑场景的)并确定每个场景中的最佳操作。但是,推理引擎实现起来很复杂,或者,如果您使用现有的推理引擎,它可能非常有限,因为这些通常是研究包。我相信,当涉及到使用声明式方法的实际实际应用时,人们几乎会为他们的特定需求编写一个定制的系统。

我发现了一些类似的研究开源项目(见下文);这将使您了解可用的内容。如您所见,这些都是研究项目,范围相对有限。

毕竟,如何进行?我不知道你的具体目标是什么。如果您正在开发一个玩具问题来练习,那么您当前的命令式样式系统可能就足够了。如果您想了解声明式风格,深入阅读 AIMA 教科书会很好。作者也维护了open source repository with implementations for some of the algorithms in the book

https://www.jmlr.org/papers/v18/17-156.html

https://github.com/douthwja01/OpenMAS

https://smartgrid.ieee.org/newsletters/may-2021/multi-agent-opendss-an-open-source-and-scalable-distribution-grid-platform

【讨论】:

  • 属性通常用于记录代理的状态、意图和一般环境。无论您选择哪种风格,这些属性都会以或多或少相同的速度变化。如果您在模型定义中获得正确的抽象级别,您可能根本看不到太多变化。它有助于定义大多数伪规则,并从中识别评估这些规则所需的环境和状态属性。您对规则的逻辑可能会随着时间而改变,但环境不太可能这样做,这样的改变无论如何都需要改变新的模型。
  • @user118967 非常感谢您的意见。就基于规则的实现而言,我不知道存在解决同一问题的这两种不同方法。你是对的,由于我的知识有限,命令式风格是我首先想到的最直接的东西。我可以理解这种风格的局限性,但我仍然无法理解如何从声明的角度解决问题。我已经研究了 AI Modern Approach 的一些相关材料,但还没有运气:-( 可以指出这些来源中的特定章节/示例吗?
  • 从某种意义上说,整本书都是关于声明式的,因为这就是人工智能:对环境和代理可能的行为进行建模,但让它弄清楚如何行动。然后不同的章节讨论同一件事的不同方法:逻辑、概率推理等。我建议第 1.1、1.3 节、第 2、7 章,特别是第 7.7 节、第 11、16 和 17 章(我正在看第 4 版TOC,你可以在aima.cs.berkeley.edu/contents.html找到,但旧版本有相应的章节)。
  • 为了让您了解声明式风格,我认为国际象棋示例是最好的。我们可以编写规则来确定每个棋子如何移动、玩家轮流以及游戏如何结束,而无需编写任何关于如何选择好的移动的内容。这就是声明式风格的全部意义所在。
  • 更清楚一点:当然我们需要编写代码来选择一个好的棋步,但是代码是在一个更抽象的层次上完成的,它对国际象棋一无所知,只知道阅读定义域的规则并使用它们做出决策。如果明天我用其他定义跳棋的规则替换定义国际象棋的规则,那么相同的决策代码应该仍然可以工作并且能够下跳棋。现在这是理想的情况,但在实践中情况可能会变得更加模糊。
猜你喜欢
  • 2018-07-17
  • 2015-05-15
  • 1970-01-01
  • 2015-02-10
  • 2012-06-18
  • 2014-04-29
  • 2011-09-14
  • 2019-05-02
  • 1970-01-01
相关资源
最近更新 更多