Fork me on GitHub

一百行写小世界网络和无标度网络

  曾经觉得能写很长的代码就是厉害的表现,随着学习的深入,对于好的代码有了更加深刻的认识,一个好的代码应该:

  1、可读性。好的代码不仅能让机器读懂,更要让看代码的人读懂----合理布局,逻辑清晰。

  2、充分发挥语言的优势,比如接下来的matlab矩阵化编程。

  3、占用尽可能小的内存,运行尽量快,输出结果尽量容易处理。并在此之间找到平衡。

  。。。。。

  需要说明的是,如果没有对复杂网络有基本的了解,下面的东西没有看下去的必要。关于小世界网络和无标度网络,可以参考Watts DJ和Strogatz SH的Collective dynamics of 'small-world' networks(NATURE)以及Barabasi AL和Albert R的 Emergence of scaling in random networks(SCIENCE)。

  之前,国庆期间曾经用了四百行代码(C语言)实现了无标度网络,之后又用一到两百行代码写完了小世界网络。现在看这些代码,确实受制于C语言语法的限制,所以写出来十分冗杂,而且不易理解。由于最近在学习matlab编程,所以尝试了一下,两个代码加起来竟然不到一百行。而且没有使用matlabBGL之类的工具。而且算法上由于语言变的更加自由,所以算法上也优化了不少(由后面的度分度图就可以看出来)

  此外,虽然matlab基于JVM,但是只要算法设计的好,还是可以完爆之前的C语言,关于无标度网络的博客中提到计算1000个节点需要35min,经过测试,这个matlab程序处理10000个节点的时间是38min,1000个节点是21.9s!新的程序时间复杂度O(N^2),N是节点数量(由于数据结构没有时间系统学习,时间复杂度可能说错了!)。

  最后,matlab可以对矩阵进行稀疏化处理,而无标度网络正是一个极其稀疏的网络,所以,借助稀疏化操作,使得matlab也能操作较大的矩阵。

先贴上实现小世界网络的matlab代码:

 1 NodesNum = 1000;
 2 K = 10;
 3 p = 1;
 4 A = sparse(NodesNum, NodesNum);
 5 for i=1:K/2
 6     A = A + diag(ones(1, length(diag(A, i))), i);
 7 end
 8 A = sparse(A);
 9 for i=1:K/2
10     A(i, (NodesNum-K/2+i):NodesNum) = 1;
11 end
12 A = A + A';
13 for i=1:K/2
14     P = rand(1,NodesNum);
15     P = find(P <= p);
16     for j=1:length(P)
17         while true
18             x = fix(rand()*NodesNum)+1;
19             if A(x, P(j)) == 0
20                 A(x, P(j)) = 1;
21                 A(P(j), x) = 1;
22                 break;
23             end
24         end
25         
26         if P(j) <= NodesNum-i
27             A(NodesNum-i, P(j)) = 0;
28             A(P(j), NodesNum-i) = 0;
29         else
30             A(P(j)-NodesNum+i, P(j)) = 0;
31             A(P(j), P(j)-NodesNum+i) = 0;
32         end
33  
34     end
35 end
36 clear i j P x
37 B3 =A^3;
38 B33 = B3(1:NodesNum+1:end);
39 B2 = A^2;
40 B22 = B2(1:NodesNum+1:end);
41 c = B33./(B22.*(B22-1));
42 c(isnan(c)) = 0;
43 C = mean(c);
44 clear B33 B3 B2 B22
45 
46 Paths = graphallshortestpaths(tril(A), 'directed', false);
47 Paths = tril(Paths);
48 L = sum(sum(Paths)) / nchoosek(NodesNum, 2);

再贴上无标度网络实现的matlab代码

 1 tic
 2 m0 = 10;
 3 m = 5;
 4 NodesNum = 1000;
 5 A = sparse(NodesNum, NodesNum);
 6 A(1:m0,1:m0) = round(rand(m0));
 7 A = tril(A); 
 8 A = A+A';
 9 A = A - diag(diag(A));
10 for i=m0+1:NodesNum
11     Degree = sum(A(1:i-1,1:i-1));
12     for j=2:i-1
13         Degree(j) = Degree(j) + Degree(j-1);
14     end
15     LinksNum = 0;
16     while LinksNum<m
17         link = fix(rand()*Degree(i-1)+1);
18         for j=1:i-2
19             if link<=Degree(1) && A(i,1)==0
20                 A(i,1) = 1;     
21                 A(1,i) = 1;
22                 LinksNum = LinksNum+1;
23             elseif link>Degree(j) && link<=Degree(j+1) && A(i,j+1)==0
24                 A(i,j+1) = 1;       A(j+1,i) = 1;
25                 LinksNum = LinksNum+1;
26             end
27         end
28     end
29 end
30 Degree = sum(A);
31 list = unique(Degree);
32 num = zeros(1,length(list));
33 for i=1:length(list)
34     num(i) = length(find(list(i)==Degree));
35 end
36 toc
37 loglog(list,num ./ sum(num),'.','markersize',20)
38 xlabel('k'),ylabel('P(k)')

再贴一张小世界网络聚类系数和最短平均路径变化图(最短路径变化有点波动,看来算法还需优化)

最后贴一张10000节点生成的matlab度分布对数坐标图,确实比之前的明显多了(算法改进立竿见影):

 

2015-12-14

 

posted @ 2015-12-14 23:14  赵裕(vimerzhao)  阅读(7485)  评论(5编辑  收藏  举报