我在研究一种基于代理的流行病模型。其思想是,个体代理根据他们在网络中观察到的(基于距离的)来做出决策。我在每个代理中有几个功能,动态更新感染联系人的计数,显示特定行为的联系人等。
下面的代码用于计算代理网络中受感染的联系人。
int infectedConnections = 0;
if (getConnections() != null)
for (Agent a : this.getConnections())
{
Person p = (Person) a;
if (p.IsCurrentlyInfected())
infectedConnections++;
}
return infectedConnections ;至少还会有3个这样的函数来保持代理网络中表示其他功能的其他代理的数量。现在,当我有<500个代理时,它似乎运行得很好,但是当我将代理数量增加到大约1,000个左右时,模型变得非常慢。我希望至少模拟5000名代理,而此时,模型甚至还没有初始化。
是否有一种更有效的计算方法来跟踪更多人口的网络统计数据?
发布于 2017-11-15 00:55:21
在我看到的基于代理的模型中,您的结果在1000到5000之间非常普遍。这是一个基本的计算复杂性问题。对于N个代理,双向相互作用的数目为N。选择2,即O(N^2)。5000剂大约是1000剂的25倍。
你可以用本土化来做一些特技。基本上,根据特定区域的代理不能与其他区域的代理交互的事实,将沙箱划分为不同的游戏区域,因此您只需要检查交互的子集。如果可能的话,将N个代理划分为k个独立组,将在运行时产生O(k)-fold改进。
另一种选择可能是远离时间步长框架,为您的问题制定一个基于事件的设计。您可以在本论文中找到这种方法的示例。
发布于 2017-11-15 15:45:14
该模型不初始化,因为默认的内存量不足以容纳5000名代理。如果每个代理与所有其他代理连接(每个代理都有4999个连接),则需要大于1.300 Mb的RAM,而默认模拟实验只分配512 Mb的RAM。更改实验属性中的内存量。然后,所有5000名特工的代码大约需要1秒的时间。换句话说,如果我每秒钟收集统计数据,最大执行速度大约是每1秒钟一个模型秒。
如果用Java:return (int)getConnections().stream() .filter( a -> (Person)a).IsCurrentlyInfected()) .count();重写代码,可以增加
然后,在0.5秒内执行一个模型秒(x2增益)。如果统计数据收集是并行执行的(使用Java代码创建的多个线程),那么您可能会得到相应的增益,这取决于PC上的核数。无论如何,这是计算复杂性问题,所以您需要更改方法(见@pjs答复),否则性能非常差。
发布于 2017-11-15 22:33:42
正如其他答案所涵盖的,你的问题实际上是两个问题:
我很惊讶--没有人提到这一点,但后者的主要性能问题是,(似乎)无论何时需要重新计算统计数据(而且您没有指定需要计算的频率),而不仅仅是在状态发生变化时保持计数。
(这是一种通用的编程折衷方法:(a)尽量减少内存,避免在任何适当的时候不更新计数的潜在错误,就像在您的方法中那样;(b)保留计数,并且只在它们依赖的事件发生时才更新它们。)
因此,只要让每个代理更新其连接的代理中的计数,只要它从非感染更改为受感染,反之亦然。
作为一个例子,假设您有10个代理,因此每个代理有9个连接(总共90个连接)。假设一个代理每10分钟就会被感染一次(平均每10分钟),你就会跑60分钟。每分钟更新每个代理中的“受感染连接数”。(如果您正在提高效率,则此间隔将是可能的转换之间的最小周期,但很可能是因为您查询的频率比这高得多,或者最小的时间段非常小。)
使用您的方法,您将检查90个连接60次(所以5400次访问代理,以及为每个代理获取/循环连接的开销)。
用我的方法,将有6x10 =60个相关的转换,所以60x9 = 540个代理访问(增加/减少计数),加上只需要通过一个代理的连接60次,而不是60x10 = 600次。因此,a>10倍性能改进。
效率明显地提高了“更少见”的转换,与您需要使用统计数据的频率(反之亦然)相比,因此,在某些情况下,这两种方法的性能将是相似的。
https://stackoverflow.com/questions/47284377
复制相似问题