FR算法(Fruchterman-Reingold)Python实现

简介Fruchterman Reingold (FR)

FR算法将所有的结点看做是电子,每个结点收到两个力的作用:
在这里插入图片描述

  1. 其他结点的库伦力(斥力)

f a ( d ) = d 2 k f_{a}(d)=\frac{d^{2}}{k} fa(d)=kd2

  1. 边对点的胡克力(引力)。

f r ( d ) = − k 2 d f_{r}(d)=\frac{-k^{2}}{d} fr(d)=dk2
该算法遵循两个简单的原则:有边连接的节点应该互相靠近;节点间不能离得太近。FR算法建立在粒子物理理论的基础上,将图中的节点模拟成原子,通过模拟原子间的力场来计算节点间的位置关系。算法通过考虑原子间引力和斥力的互相作用,计算得到节点的速度和加速度。依照类似原子或者行星的运动规律,系统最终进入一种动态平衡状态。

Python实现

输入的A是稀疏邻接矩阵,用scipy的coo_matrix生成,k是上述引斥力的系数,fiexed是固定不变的点的序号,返回结果是点的坐标。

import numpy as np
from scipy.sparse import coo_matrix


def sparse_fruchterman_reingold(A, k=None, pos=None, fixed=None, iterations=50, threshold=1e-5, dim=3):
    # np.random.seed(1)
    nodes_num = A.shape[0]
    A = A.tolil()
    A = A.astype('float')
    if pos is None:
        pos = np.asarray(np.random.rand(nodes_num, dim), dtype=A.dtype)
        print('Init pos', pos)
    else:
        pos = np.array(pos)
        pos = pos.astype(A.dtype)

    if fixed is None:
        fixed = []

    if k is None:
        k = np.sqrt(1.0 / nodes_num)
    t = max(max(pos.T[0]) - min(pos.T[0]), max(pos.T[1]) - min(pos.T[1])) * 0.1
    dt = t / float(iterations + 1)
    displacement = np.zeros((dim, nodes_num))
    for iteration in range(iterations):
        displacement *= 0
        for i in range(A.shape[0]):
            if i in fixed:
                continue
            delta = (pos[i] - pos).T
            distance = np.sqrt((delta ** 2).sum(axis=0))
            distance = np.where(distance < 0.01, 0.01, distance)
            Ai = np.asarray(A.getrowview(i).toarray())
            print('Ai', Ai)
            displacement[:, i] += \
                (delta * (k * k / distance ** 2 - Ai * distance / k)).sum(axis=1)
        # update positions
        length = np.sqrt((displacement ** 2).sum(axis=0))
        length = np.where(length < 0.01, 0.1, length)
        delta_pos = (displacement * t / length).T
        pos += delta_pos
        # cool temperature
        t -= dt
        err = np.linalg.norm(delta_pos) / nodes_num
        if err < threshold:
            break

    return pos


if __name__ == '__main__':

    row = np.array([0, 0, 1, 2, 3, 3])
    col = np.array([1, 3, 0, 3, 0, 2])
    data = np.array([1, 1, 1, 1, 1, 1])
    coo_matrix((data, (row, col)), shape=(4, 4)).toarray()
    print(coo_matrix((data, (row, col)), shape=(4, 4)))
    a = sparse_fruchterman_reingold(coo_matrix((data, (row, col)), shape=(4, 4)))
    print(a)

其他算法可见:

https://www.omegaxyz.com/

参考

https://zhuanlan.zhihu.com/p/59977713
https://www.cnblogs.com/Dyleaf/p/8491136.html

更多内容访问 omegaxyz.com
网站所有代码采用Apache 2.0授权
网站文章采用知识共享许可协议BY-NC-SA4.0授权
© 2020 • OmegaXYZ-版权所有 转载请注明出处

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值