Java AnyLogic:提高网络模型的计算性能

Java AnyLogic:提高网络模型的计算性能,java,performance,simulation,anylogic,agent-based-modeling,Java,Performance,Simulation,Anylogic,Agent Based Modeling,我正在研究一种基于代理的流行病模型。其思想是,个体代理根据他们在网络中观察到的情况(基于距离)做出决策。我在每个代理中都有几个功能,可以动态更新感染联系人的数量、显示特定行为的联系人等 下面的代码用于计算代理网络中受感染的联系人 int infectedConnections = 0; if (getConnections() != null) for (Agent a : this.getConnections()) { Person p = (Per

我正在研究一种基于代理的流行病模型。其思想是,个体代理根据他们在网络中观察到的情况(基于距离)做出决策。我在每个代理中都有几个功能,可以动态更新感染联系人的数量、显示特定行为的联系人等

下面的代码用于计算代理网络中受感染的联系人

int infectedConnections = 0;

if (getConnections() != null)
    for (Agent a : this.getConnections())
        {
        Person p = (Person) a;

        if (p.IsCurrentlyInfected()) 
            infectedConnections++;
            }

return infectedConnections ;

至少还有3个这样的函数,用于保存表示代理网络中其他功能的其他代理的计数。现在,当我有了你的结果,事情停滞在1000到5000之间时,这似乎运行正常,这在我见过的基于代理的模型中非常常见。这是一个基本的计算复杂性问题。对于N个代理,双向交互的数量为N.choose.2,即O(N^2)。5000名特工的工作量大约是1000名特工的25倍

你可以用本地化来做一些特技。基本上,根据特定区域中的代理无法与其他区域中的代理交互的事实,将您的沙盒划分为不同的游戏区域,因此您只需要检查交互的子集。如果可能的话,将N个代理划分为k个独立的分组将在运行时产生O(k)倍的改进


另一种选择可能是远离时间步框架,为您的问题制定基于事件的设计。您可以在中找到这种方法的一个示例。

您的结果是,在1000到5000之间的某个位置出现问题,这在我所看到的基于代理的模型中非常常见。这是一个基本的计算复杂性问题。对于N个代理,双向交互的数量为N.choose.2,即O(N^2)。5000名特工的工作量大约是1000名特工的25倍

你可以用本地化来做一些特技。基本上,根据特定区域中的代理无法与其他区域中的代理交互的事实,将您的沙盒划分为不同的游戏区域,因此您只需要检查交互的子集。如果可能的话,将N个代理划分为k个独立的分组将在运行时产生O(k)倍的改进


另一种选择可能是远离时间步框架,为您的问题制定基于事件的设计。您可以在中找到此方法的示例。

由于默认内存量不足以容纳5000个代理,因此模型未初始化。如果每个代理与所有其他代理连接(每个代理4999个连接),则需要大于1.300 Mb的RAM,而默认模拟实验仅分配512 Mb的RAM。更改“实验属性”中的内存量。然后,所有5000个代理的代码大约需要1秒的时间。换句话说,如果我每秒收集一次统计数据,最大执行速度大约是每1实秒1个模型秒

如果使用Java Stream API重写代码,则可以增加:
return(int)getConnections().stream()
.filter(a->(Person)a).IsCurrentlyInfected())
.count()

然后,以0.5实秒(x2增益)执行1个模型秒。如果统计数据收集是并行执行的(使用多个线程,由Java代码创建),那么您可能会获得相应的增益,具体取决于PC上的内核数量。
无论如何,这是计算复杂性问题,因此您需要更改方法(),否则性能会非常差。

由于默认内存量不足以容纳5000个代理,因此模型不会初始化。如果每个代理与所有其他代理连接(每个代理4999个连接),则需要大于1.300 Mb的RAM,而默认模拟实验仅分配512 Mb的RAM。更改“实验属性”中的内存量。然后,所有5000个代理的代码大约需要1秒的时间。换句话说,如果我每秒收集一次统计数据,最大执行速度大约是每1实秒1个模型秒

如果使用Java Stream API重写代码,则可以增加:
return(int)getConnections().stream()
.filter(a->(Person)a).IsCurrentlyInfected())
.count()

然后,以0.5实秒(x2增益)执行1个模型秒。如果统计数据收集是并行执行的(使用多个线程,由Java代码创建),那么您可能会获得相应的增益,具体取决于PC上的内核数量。
无论如何,这是计算复杂性的问题,因此您需要更改方法(),否则性能会非常差。

其他答案涵盖了这两个问题:

  • 由于总网络连接数随着代理数量的增加而非线性增加(因为每个代理都连接到其他每个代理),导致内存使用和“基础”模型速度

  • 你的数据收集效率

我很惊讶没有人提到这一点,但后者的主要性能问题是因为(似乎)您在需要统计数据的时候重新计算统计数据(并且您没有指定需要计算的频率),而不仅仅是在影响统计数据的状态更改时维护统计数据

(这是(a)最小化内存并避免在所有适当时间不更新计数的潜在错误(如在您的方法中)与(b)保留计数并仅在事件发生时更新计数的速度之间的一般编程权衡。)

因此,只要让每个代理在其连接的代理从未感染更改为已感染时更新计数,反之亦然

例如,假设您有10个代理,每个代理有9个连接(总共90个连接)。假设一个代理每10分钟(平均)更换一次受感染的代理,然后运行60分钟。并且每分钟更新每个代理中的“受感染连接数”。(如果你是有效率的,这个时间间隔将是可能的转换之间的最短时间,但很可能你是q