Barnes-Hut算法是一种用于实现N体问题(n-body)模拟的近似算法,该算法由Josh Barnes 和 Piet Hut在1986年提出(可以参加文献【3】)。N体问题是指找出已知初始位置、速度和质量的多个物体在经典力学情况下的后续运动。庞加莱(Henri Poincaré)在研究N体问题时,发现了混沌现象。
欢迎关注白马负金羁的博客 http://blog.csdn.net/baimafujinji,为保证公式、图表得以正确显示,强烈建议你从该地址上查看原版博文。本博客主要关注方向包括:数字图像处理、算法设计与分析、数据结构、机器学习、数据挖掘、统计分析方法、自然语言处理。
因为N体问题是一种混沌现象,物体未来的运动状态是没有规律可言的,所以N体模拟只能采用Brute Force的策略。一种提升N体问题模拟算法的速度,一种非常重要的思想就是把相互接近的一组物体近似看成单独的一个物体。对于一组距离足够远的物体,我们可以将它的万有引力作用近似看成是其质心的作用。一组物体的质心是这种物体经过质量加权后的平均位置。更正式地说,如果两个物体的位置分别是( x1,y1 )和( x2,y2 ),质量分别为 m1 和 m2 ,那么它们的总质量和总质心( x,y )分别为:
如果非叶子节点离某个物体并不足够远,那么就递归地遍历其所有子树。为了确定一个节点是否离得足够远,我们需要计算商 s/d , 其中 s 是非叶子节点所代表的区域的宽度, d 是物体到节点所代表的那一组物体的质心的距离。然后将这个比值同一个阈值 θ 来作比较. 如果 s/d<θ ,那么非叶子节点就足够远。通过调整参数 θ ,我们就可以来改变模拟的精度和速度。通常在实际中 θ = 0.5 是一个常常被使用的值。注意到如果 θ = 0,那么算法就退化到了使用Brute Force时的情况。
为了构建一棵Barnes-Hut树,我们将一个一个地向树中插入节点。具体来说,当向一个由(根)节点 x 所表示的树中插入一个物体 b 时,我们就递归地执行如下步骤(注意这里我们给“根”字加了一个括号的意思是即使在整棵树中某个节点不是根节点,它也可能是其中某个子树的根节点):
下面这个例子演示了构建一棵包含5个节点的Barnes-Hut的过程,我们按A,B,C,D,E的顺序插入节点。
为了计算某个物体 b 所受到的合力,我们需要从四叉树的根节点开始,递归地执行如下步骤:
我们还是来看一个例子。我们计算在物体 a 上的合力,我们从根节点开始,它是一个内部节点,包含了 A,B,C,D,E,F 六个物体的质心,这六个物体的质量分别为 1,2,3,4,5,6 千克。
我们首先检测根节点,将区域宽度 s 和物体A到当前节点(根节点)的质心(图中白点)的距离 d 做除法,得到商 s/d=100/43.1>θ=0.5 ,因此我们需要执行算法步骤(3)。
【1】 http://arborjs.org/docs/barnes-hut
【2】 http://www.cs.princeton.edu/courses/archive/fall03/cs126/assignments/barnes-hut.html
【3】 Barnes, J. and Hut, P., 1986. A hierarchical O (N log N) force-calculation algorithm. nature, 324(6096), pp.446-449. (百度网盘下载链接)
【4】 牟磊,基于Barnes Hut算法的N-body问题模拟,福建电脑,2010 年第 8 期.(百度网盘下载链接)