├── src ├── Stat.mat ├── image.mat ├── cardi.m ├── init_graph.m ├── add_varnode.m ├── belief_diff.m ├── ave_scatter.m ├── get_beliefs.m ├── add_facnode.m ├── initialize.m ├── marg_brute_force.m ├── run_loopy_bp_parallel.m ├── testvis.m ├── testdim.m ├── adjG2facG.m └── test.m ├── Final Report.pdf ├── topology analysis ├── selfloops.m ├── multiedges.m ├── graph_radius.m ├── numnodes.m ├── graph_spectrum.m ├── algebraic_connectivity.m ├── loops3.m ├── graph_complement.m ├── fiedler_vector.m ├── isdirected.m ├── issymmetric.m ├── adjL2edgeL.m ├── average_degree.m ├── symmetrize.m ├── edgeL2adjL.m ├── vertex_eccentricity.m ├── isweighted.m ├── kneighbors.m ├── subgraph.m ├── pajek2adj.m ├── eigencentrality.m ├── istree.m ├── purge.m ├── diameter.m ├── graph_energy.m ├── adjL2adj.m ├── issimple.m ├── isregular.m ├── link_density.m ├── adj2edgeL.m ├── adj2simple.m ├── adj2adjL.m ├── exponential_growth_model.m ├── num_conn_comp.m ├── edgelist2dl.m ├── giant_component.m ├── adj2dl.m ├── edgeL2adj.m ├── leaf_nodes.m ├── iscomplete.m ├── symmetrize_edgeL.m ├── ave_path_length.m ├── num_star_motifs.m ├── edgeL2simple.m ├── degrees.m ├── num_loops.m ├── BFS.m ├── kmin_neighbors.m ├── num_conn_triples.m ├── closeness.m ├── random_directed_graph.m ├── rich_club_metric.m ├── adj2str.m ├── ave_neighbor_deg.m ├── laplacian_matrix.m ├── add_edge_weights.m ├── graph_from_degree_sequence.m ├── edgeL2cyto.m ├── numedges.m ├── sort_nodes_by_max_neighbor_degree.m ├── graph_similarity.m ├── inc2edgeL.m ├── isgraphic.m ├── simple_dijkstra.m ├── leaf_edges.m ├── pajek2xyz.m ├── distance_distribution.m ├── getNodes.m ├── draw_circ_graph.m ├── iseulerian.m ├── getEdges.m ├── pajek2edgeL.m ├── s_metric.m ├── smooth_diameter.m ├── sort_nodes_by_sum_neighbor_degrees.m ├── inc2adj.m ├── str2adj.m ├── PriceModel.m ├── node_betweenness_faster.m ├── loops4.m ├── clust_coeff.m ├── pdf_cdf_rank.m ├── master_equation_growth_model.m ├── min_span_tree.m ├── isbipartite.m ├── shortest_pathDP.m ├── graph_dual.m ├── simple_spectral_partitioning.m ├── rewire_disassort.m ├── weighted_clust_coeff.m ├── random_modular_graph.m ├── node_betweenness_slow.m ├── rewire_assort.m ├── adj2inc.m ├── edgeL2pajek.m ├── license.txt ├── preferential_attachment.m ├── dijkstra.m ├── find_conn_comp.m ├── kregular.m ├── el2geom.m ├── pearson.m ├── fabrikant_model.m ├── modularity_metric.m ├── rewire.m ├── newmangastner.m ├── tarjan.m ├── isconnected.m ├── forestFireModel.m ├── DoddsWattsSabel.m ├── dot_matrix_plot.m ├── adj2pajek.m ├── newmangirvan.m ├── nested_hierarchies_model.m ├── newman_eigenvector_method.m ├── louvain_community_finding.m ├── random_graph.m ├── radial_plot.m ├── newman_comm_fast.m ├── edge_betweenness.m ├── build_smax_graph.m └── canonical_nets.m ├── LICENSE └── README.md /src/Stat.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diaoenmao/Belief-Propagation/HEAD/src/Stat.mat -------------------------------------------------------------------------------- /src/image.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diaoenmao/Belief-Propagation/HEAD/src/image.mat -------------------------------------------------------------------------------- /Final Report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diaoenmao/Belief-Propagation/HEAD/Final Report.pdf -------------------------------------------------------------------------------- /src/cardi.m: -------------------------------------------------------------------------------- 1 | function out = cardi(facG) 2 | facN = length(facG.fac); 3 | out = zeros(1,facN); 4 | for i=1:facN 5 | out(i) = length(size(facG.fac(i).p)); 6 | end 7 | end -------------------------------------------------------------------------------- /src/init_graph.m: -------------------------------------------------------------------------------- 1 | function G = init_graph() 2 | % INIT_GRAPH - Initialize factor graph data structure. 3 | % 4 | % Brown CS242 5 | 6 | G.var = []; % Variable nodes 7 | G.fac = []; % Factor nodes 8 | end 9 | -------------------------------------------------------------------------------- /topology analysis/selfloops.m: -------------------------------------------------------------------------------- 1 | % counts the number of self-loops in the graph 2 | % INPUT: adjacency matrix 3 | % OUTPUT: interger, number of self-loops 4 | % Last Updated: GB, October 1, 2009 5 | 6 | function sl=selfloops(adj) 7 | 8 | sl=sum(diag(adj)); -------------------------------------------------------------------------------- /topology analysis/multiedges.m: -------------------------------------------------------------------------------- 1 | % counts the number of multiple edges in the graph 2 | % INPUT: adjacency matrix 3 | % OUTPUT: interger, number of multiple edges 4 | % Last Updated: GB, October 1, 2009 5 | 6 | function mE=multiedges(adj) 7 | 8 | mE=length(find(adj>1)); -------------------------------------------------------------------------------- /topology analysis/graph_radius.m: -------------------------------------------------------------------------------- 1 | % The minimum vertex eccentricity is the graph radius 2 | % Inputs: adjacency matrix (nxn) 3 | % Outputs: graph radius 4 | % Other routines used: vertex_eccentricity.m 5 | 6 | function Rg=graph_radius(adj) 7 | 8 | Rg=min( vertex_eccentricity(adj) ); -------------------------------------------------------------------------------- /topology analysis/numnodes.m: -------------------------------------------------------------------------------- 1 | % Returns the number of nodes, given an adjacency list 2 | % also works for an adjacency matrix 3 | % INPUTs: adjacency list: {i:j_1,j_2 ..} 4 | % OUTPUTs: number of nodes 5 | % GB, February 19, 2006 6 | 7 | function n = numnodes(L) 8 | 9 | n = length(L); -------------------------------------------------------------------------------- /topology analysis/graph_spectrum.m: -------------------------------------------------------------------------------- 1 | % The eigenvalues of the Laplacian of the graph 2 | % INPUTs: adjacency matrix 3 | % OUTPUTs: laplacian eigenvalues, sorted 4 | 5 | function s=graph_spectrum(adj) 6 | 7 | [v,D]=eig(laplacian_matrix(adj)); 8 | s=-sort(-diag(D)); % sort in decreasing order -------------------------------------------------------------------------------- /topology analysis/algebraic_connectivity.m: -------------------------------------------------------------------------------- 1 | % The algebraic connectivity of a graph: the second smallest eigenvalue of the Laplacian 2 | % INPUTs: adjacency matrix 3 | % OUTPUTs: algebraic connectivity 4 | 5 | function a=algebraic_connectivity(adj) 6 | 7 | s=graph_spectrum(adj); 8 | a=s(length(s)-1); -------------------------------------------------------------------------------- /topology analysis/loops3.m: -------------------------------------------------------------------------------- 1 | % Calculates number of loops of length 3 2 | % INPUTs: adj - adjacency matrix 3 | % OUTPUTs: L3 - number of triangles (loops of length 3) 4 | % Valid for an undirected network 5 | % GB, April 6, 2006 6 | 7 | function L3 = loops3(adj) 8 | 9 | L3 = trace(adj^3)/6; % trace(adj^3)/3! -------------------------------------------------------------------------------- /topology analysis/graph_complement.m: -------------------------------------------------------------------------------- 1 | % Returns the complement of a graph 2 | % INPUTs: adj - original graph adjacency matrix 3 | % OUTPUTs: complement graph adjacency matrix 4 | % Note: Assumes no multiedges 5 | % GB, February 2, 2006 6 | 7 | function adj_c = graph_complement(adj) 8 | 9 | adj_c=ones(size(adj))-adj; -------------------------------------------------------------------------------- /topology analysis/fiedler_vector.m: -------------------------------------------------------------------------------- 1 | % The vector corresponding to the second smallest eigenvalue of the Laplacian matrix 2 | % INPUTs: adjacency matrix (nxn) 3 | % OUTPUTs: fiedler vector (nx1) 4 | 5 | function fv=fiedler_vector(adj) 6 | 7 | [V,D]=eig(laplacian_matrix(adj)); 8 | [ds,Y]=sort(diag(D)); 9 | fv=V(:,Y(2)); -------------------------------------------------------------------------------- /topology analysis/isdirected.m: -------------------------------------------------------------------------------- 1 | % Using the matrix transpose function 2 | % INPUTS: adjacency matrix 3 | % OUTPUTS: boolean variable 4 | % GB, Last updated: October 1, 2009 5 | 6 | function S=isdirected(adj) 7 | 8 | S = true; 9 | if adj==transpose(adj); S = false; end 10 | 11 | % one-liner alternative: S=not(issymmetric(adj)); -------------------------------------------------------------------------------- /topology analysis/issymmetric.m: -------------------------------------------------------------------------------- 1 | % Checks whether a matrix is symmetric (has to be square) 2 | % Check whether mat=mat^T 3 | % INPUTS: adjacency matrix 4 | % OUTPUTS: boolean variable, {0,1} 5 | % GB, October 1, 2009 6 | 7 | function S = issymmetric(mat) 8 | 9 | S = false; % default 10 | if mat == transpose(mat); S = true; end -------------------------------------------------------------------------------- /topology analysis/adjL2edgeL.m: -------------------------------------------------------------------------------- 1 | % Converts adjacency list to an edge list 2 | % INPUTS: adjacency list 3 | % OUTPUTS: edge list 4 | % GB, Last Updated: October 6, 2009 5 | 6 | function el = adjL2edgeL(adjL) 7 | 8 | el = []; % initialize edgelist 9 | for i=1:length(adjL) 10 | for j=1:length(adjL{i}); el=[el; i, adjL{i}(j), 1]; end 11 | end -------------------------------------------------------------------------------- /topology analysis/average_degree.m: -------------------------------------------------------------------------------- 1 | % Computes the average degree of a node in a graph, defined as 2*num_edges 2 | % divided by the num_nodes (every edge is counted in degrees twice). 3 | % Other routines used: numnodes.m, numedges.m 4 | % GB, Last Update: October 1, 2009 5 | 6 | function k=average_degree(adj) 7 | 8 | k=2*numedges(adj)/numnodes(adj); -------------------------------------------------------------------------------- /topology analysis/symmetrize.m: -------------------------------------------------------------------------------- 1 | % Symmetrize a non-symmetric matrix 2 | % For matrices in which mat(i,j)~=mat(j,i), the larger (nonzero) value is chosen 3 | % INPUTS: a matrix - nxn 4 | % OUTPUT: corresponding symmetric matrix - nxn 5 | % Last Updated: October 1, 2009 6 | 7 | function adj_sym = symmetrize(adj) 8 | 9 | adj_sym = max(adj,transpose(adj)); -------------------------------------------------------------------------------- /topology analysis/edgeL2adjL.m: -------------------------------------------------------------------------------- 1 | % Converts an edgelist to an adjacency list 2 | % INPUTS: edgelist, (mx3) 3 | % OUTPUTS: adjacency list 4 | % GB, Last updated: October 13, 2006 5 | 6 | function adjL = edgeL2adjL(el) 7 | 8 | nodes = unique([el(:,1)' el(:,2)']); 9 | adjL=cell(numel(nodes),1); 10 | 11 | for e=1:size(el,1); adjL{el(e,1)}=[adjL{el(e,1)},el(e,2)]; end -------------------------------------------------------------------------------- /topology analysis/vertex_eccentricity.m: -------------------------------------------------------------------------------- 1 | % Vertex eccentricity - the maximum distance to any other vertex 2 | % Input: adjacency matrix 3 | % Output: vector of eccentricities 4 | % Other routines used: simple_dijkstra.m 5 | 6 | function ec=vertex_eccentricity(adj) 7 | 8 | n=size(adj,1); 9 | ec=zeros(1,n); 10 | 11 | for s=1:n; ec(s)=max( simple_dijkstra(adj,s) ); end -------------------------------------------------------------------------------- /topology analysis/isweighted.m: -------------------------------------------------------------------------------- 1 | % Check whether a graph is weighted, i.e not all edges are 0,1. 2 | % INPUTS: edge list, m x 3, m: number of edges, [node 1, node 2, edge weight] 3 | % OUTPUTS: Boolean variable, yes/no 4 | % GB, Last updated: October 1, 2009 5 | 6 | function S=isweighted(el) 7 | 8 | S=true; 9 | 10 | if numel( find(el(:,3)==1) ) == size(el,1); S=false; end -------------------------------------------------------------------------------- /topology analysis/kneighbors.m: -------------------------------------------------------------------------------- 1 | % Finds the number of k-neighbors (k links away) for every node 2 | % INPUTS: adjacency matrix, node index, k - number of links 3 | % OUTPUTS: vector of k-neighbors indices 4 | % GB, May 3, 2006 5 | 6 | function kneigh = kneighbors(adj,ind,k) 7 | 8 | adjk = adj; 9 | for i=1:k-1; adjk = adjk*adj; end; 10 | 11 | kneigh = find(adjk(ind,:)>0); -------------------------------------------------------------------------------- /src/add_varnode.m: -------------------------------------------------------------------------------- 1 | function [G, id] = add_varnode( G, name, dim ) 2 | % ADD_VARNODE - Add variable node to factor graph 'G'. 3 | % 4 | % Brown CS242 5 | 6 | id = numel(G.var) + 1; 7 | 8 | v.name = name; 9 | % v.dim = numel(vals); 10 | % v.vals = vals; 11 | v.dim = dim; 12 | v.id = id; 13 | v.nbrs_fac = []; 14 | v.observed = 0; 15 | G.var = cat( 1, G.var, v ); 16 | end 17 | -------------------------------------------------------------------------------- /topology analysis/subgraph.m: -------------------------------------------------------------------------------- 1 | % This function outputs the adjacency matrix of a subgraph given the 2 | % supergraph and the node set of the subgraph 3 | % INPUTs: adj - supergraph adjacency matrix, S - vector of subgraph node indices 4 | % OUTPUTs: adj_sub - adjacency matrix of the subgraph 5 | % GB, January 5, 2006 6 | 7 | function adj_sub = subgraph(adj,S) 8 | 9 | adj_sub = adj(S,S); 10 | -------------------------------------------------------------------------------- /topology analysis/pajek2adj.m: -------------------------------------------------------------------------------- 1 | % This program extracts an adjacency matrix from a pajek text (.net) file 2 | % INPUT .net text filename, n - number of nodes in the graph 3 | % OUTPUT: adjacency matrix, nxn, n - # nodes 4 | % Other routines used: pajek2edgeL.m, edgeL2adj.m 5 | % GB, October 7, 2009 6 | 7 | function adj = pajek2adj(filename,n) 8 | 9 | el=pajek2edgeL(filename,n); 10 | adj=edgeL2adj(el); -------------------------------------------------------------------------------- /topology analysis/eigencentrality.m: -------------------------------------------------------------------------------- 1 | % The ith component of the eigenvector corresponding to the greatest 2 | % eigenvalue gives the centrality score of the ith node in the network. 3 | % INPUTs: adjacency matrix 4 | % OUTPUTs: eigen(-centrality) vector 5 | % GB, Last Updated: October 14, 2009 6 | 7 | function x=eigencentrality(adj) 8 | 9 | [V,D]=eig(adj); 10 | [max_eig,ind]=max(diag(D)); 11 | x=V(:,ind); -------------------------------------------------------------------------------- /topology analysis/istree.m: -------------------------------------------------------------------------------- 1 | % Check whether a graph is a tree 2 | % Source: "Intro to Graph Theory" by Bela Bollobas 3 | % INPUTS: adjacency matrix 4 | % OUTPUTS: Boolean variable 5 | % Other routines used: isconnected.m, numedges.m, numnodes.m 6 | % GB, Last Updated: June 19, 2007 7 | 8 | function S=istree(adj) 9 | 10 | S=false; 11 | 12 | if isconnected(adj) & numedges(adj)==numnodes(adj)-1; S=true; end -------------------------------------------------------------------------------- /topology analysis/purge.m: -------------------------------------------------------------------------------- 1 | % Removes a subset from a set, but preserves order of elements 2 | % Similar to setdiff - which sorts the elements 3 | % INPUTs: original set A, subset to remove B 4 | % OUTPUTs: set Anew = A-B 5 | % GB, Last updated: October 12, 2009 6 | 7 | function Anew = purge(A,B) 8 | 9 | Anew = []; 10 | for a=1:numel(A); 11 | if isempty(find(B==A(a))); Anew=[Anew, A(a)]; end 12 | end -------------------------------------------------------------------------------- /topology analysis/diameter.m: -------------------------------------------------------------------------------- 1 | % The longest shortest path between any two nodes nodes in the network 2 | % INPUTS: adjacency matrix, adj 3 | % OUTPUTS: network diameter, diam 4 | % Other routines used: simple_dijkstra.m 5 | % GB, Last updated: June 8, 2010 6 | 7 | function diam = diameter(adj) 8 | 9 | diam=0; 10 | for i=1:size(adj,1) 11 | d=simple_dijkstra(adj,i); 12 | diam = max([max(d),diam]); 13 | end -------------------------------------------------------------------------------- /topology analysis/graph_energy.m: -------------------------------------------------------------------------------- 1 | % Graph energy defined as: the sum of the absolute values of the real components of the eigenvalues 2 | % Source: Gutman, The energy of a graph, Ber. Math. Statist. Sekt. Forsch-ungszentram Graz. 103 (1978) 1?22. 3 | % INPUTs: adjacency matrix (nxn) 4 | % OUTPUTs: graph energy 5 | 6 | function G=graph_energy(adj) 7 | 8 | [~,e]=eig(adj); % e are the eigenvalues 9 | G=sum(abs(real(diag(e)))); -------------------------------------------------------------------------------- /topology analysis/adjL2adj.m: -------------------------------------------------------------------------------- 1 | % Convert an adjacency list to an adjacency matrix 2 | % INPUTS: adjacency list: {n} 3 | % OUTPUTS: adjacency matrix nxn 4 | % Note: Assume that if node i has no neighbours, L{i}=[]; 5 | % GB, Last updated: October 6, 2009 6 | 7 | function adj=adjL2adj(adjL) 8 | 9 | adj = zeros(length(adjL)); 10 | 11 | for i=1:length(adjL) 12 | for j=1:length(adjL{i}); adj(i,adjL{i}(j))=1; end 13 | end -------------------------------------------------------------------------------- /topology analysis/issimple.m: -------------------------------------------------------------------------------- 1 | % Checks whether a graph is simple (no self-loops, no multiple edges) 2 | % INPUTs: adj - adjacency matrix 3 | % OUTPUTs: S - a Boolean variable 4 | % Other routines used: selfloops.m, multiedges.m 5 | % GB, Last updated: October 1, 2009 6 | 7 | function S = issimple(adj) 8 | 9 | S=true; 10 | 11 | % check for self-loops or double edges 12 | if selfloops(adj)>0 | multiedges(adj)>0; S=false; end -------------------------------------------------------------------------------- /topology analysis/isregular.m: -------------------------------------------------------------------------------- 1 | % Checks whether a graph is regular, i.e. every node has the same degree. 2 | % Note: Defined for unweighted graphs only. 3 | % INPUTS: adjacency matrix nxn 4 | % OUTPUTS: Boolean, yes/no 5 | % GB, Last updated: October 1, 2009 6 | 7 | function S=isregular(adj) 8 | 9 | S=false; 10 | 11 | degs=sum(adj>0); % remove weights and sum columns 12 | 13 | if degs == degs(1)*ones(size(degs)); S = true; end -------------------------------------------------------------------------------- /topology analysis/link_density.m: -------------------------------------------------------------------------------- 1 | % Computes the link density of a graph, defined as num_edges divided by 2 | % num_nodes(num_nodes-1)/2 where the latter is the max possible num edges. 3 | % The graph needs to be non-trivial (more than 1 node). 4 | % Other routines used: numnodes.m, numedges.m 5 | % GB, Last Update: October 1, 2009 6 | 7 | function d=link_density(adj) 8 | 9 | n = numnodes(adj); 10 | d = 2*numedges(adj)/(n*(n-1)); -------------------------------------------------------------------------------- /topology analysis/adj2edgeL.m: -------------------------------------------------------------------------------- 1 | % Converts adjacency matrix (nxn) to edge list (mx3) 2 | % INPUTS: adjacency matrix: nxn 3 | % OUTPUTS: edge list: mx3 4 | % GB, Last updated: October 2, 2009 5 | 6 | function el=adj2edgeL(adj) 7 | 8 | n=length(adj); % number of nodes 9 | edges=find(adj>0); % indices of all edges 10 | 11 | el=[]; 12 | for e=1:length(edges) 13 | [i,j]=ind2sub([n,n],edges(e)); % node indices of edge e 14 | el=[el; i j adj(i,j)]; 15 | end -------------------------------------------------------------------------------- /topology analysis/adj2simple.m: -------------------------------------------------------------------------------- 1 | % Convert an adjacency matrix of a general graph to the adjacency matrix of 2 | % a simple graph (no loops, no double edges) - great for quick data clean up 3 | % INPUTS: adjacency matrix 4 | % OUTPUTs: adjacency matrix of the corresponding simple graph 5 | % GB, Last updated: October 4, 2009 6 | 7 | function adj=adj2simple(adj) 8 | 9 | adj=adj>0; % make all edges weight 1 10 | adj = adj - diag(diag(adj)); % clear the diagonal (selfloops) -------------------------------------------------------------------------------- /topology analysis/adj2adjL.m: -------------------------------------------------------------------------------- 1 | % Converts an adjacency graph representation to an adjacency list 2 | % Valid for a general (directed, not simple) network model, but edge 3 | % weights get lost in the conversion. 4 | % INPUT: an adjacency matrix, NxN, N - # of nodes 5 | % OUTPUT: cell structure for adjacency list: x{i_1}=[j_1,j_2 ...] 6 | % GB, October 1, 2009 7 | 8 | function L = adj2adjL(adj) 9 | 10 | L=cell(length(adj),1); 11 | 12 | for i=1:length(adj); L{i}=find(adj(i,:)>0); end -------------------------------------------------------------------------------- /topology analysis/exponential_growth_model.m: -------------------------------------------------------------------------------- 1 | % Grow a network exponentially 2 | % Probability of node s having k links at time t: p(k,s,t)=1/t*p(k-1,s,t-1)+(1-1/t)*p(k,s,t-1) 3 | % INPUTS: number of time-steps, t 4 | % OUTPUTs: edgelist, mx3 5 | % GB, Last Updated: May 7, 2007 6 | 7 | function el=exponential_growth_model(t) 8 | 9 | el=[1 2 1; 2 1 1]; % initialize with two connected nodes 10 | 11 | % for all remaining time t 12 | for i=3:t; r = randi(i-1); el=[el; i r 1; r i 1]; end 13 | -------------------------------------------------------------------------------- /topology analysis/num_conn_comp.m: -------------------------------------------------------------------------------- 1 | % Calculate the number of connected components using the Laplacian 2 | % eigenvalues - counting the number of zeros 3 | % INPUTS: adjacency matrix 4 | % OUTPUTs: positive integer - number of connected components 5 | % Other routines used: graph_spectrum.m 6 | % GB, Last updated: October 22, 2009 7 | 8 | function nc=num_conn_comp(adj) 9 | 10 | s=graph_spectrum(adj); 11 | nc=numel(find(s<10^(-5))); % zero eigenvalues are sometimes close to zeros numerically in matlab -------------------------------------------------------------------------------- /topology analysis/edgelist2dl.m: -------------------------------------------------------------------------------- 1 | function []=edgelist2dl(edgelistt,filename) 2 | 3 | % function to convert two-way edgelist to UCINET dl format 4 | % D Whitney Nov 29, 2010 5 | % example filename is 'filename.txt' 6 | 7 | numnodes=max(max(edgelistt)) 8 | n=numnodes; 9 | fid=fopen(filename,'w'); 10 | fprintf(fid,'dl n %1u format=el1 \n',n); 11 | fprintf(fid,'labels: \n'); 12 | labels=[1:n]; 13 | fprintf(fid,'%u \n',labels); 14 | fprintf(fid,'data: \n'); 15 | fprintf(fid,'%3u %3u \n', edgelistt); 16 | fclose(fid); -------------------------------------------------------------------------------- /topology analysis/giant_component.m: -------------------------------------------------------------------------------- 1 | % extract giant component from a network 2 | % INPUTS: adjacency matrix 3 | % OUTPUTS: giant comp matrix and node indeces 4 | % Other routines used: find_conn_comp.m, subgraph.m 5 | % GB, Last Updated: October 2, 2009 6 | 7 | 8 | function [GC,gc_nodes]=giant_component(adj) 9 | 10 | comps=find_conn_comp(adj); 11 | 12 | L=[]; 13 | for k=1:length(comps); L=[L, length(comps{k})]; end 14 | [maxL,ind_max]=max(L); 15 | 16 | gc_nodes=comps{ind_max}; 17 | GC=subgraph(adj,gc_nodes); -------------------------------------------------------------------------------- /topology analysis/adj2dl.m: -------------------------------------------------------------------------------- 1 | function []=adj2dl(adj,filename) 2 | 3 | % function to convert adjacency matrix to UCINET dl format 4 | % D Whitney Nov 29, 2010 5 | 6 | adj=full(adj'); 7 | n=size(adj,1); 8 | fid=fopen(filename,'w'); 9 | fprintf(fid,'dl n %1u format=fm diagonal=present \n',n'); 10 | fprintf(fid,'labels: \n'); 11 | labels=[1:n]; 12 | fprintf(fid,'%u \n',labels); 13 | fprintf(fid,'data: \n'); 14 | b=[]; 15 | for i = 1:n 16 | b=strcat(b,'%4u'); 17 | end 18 | fprintf(fid,strcat(b,'\n'),adj'); 19 | fclose(fid); -------------------------------------------------------------------------------- /topology analysis/edgeL2adj.m: -------------------------------------------------------------------------------- 1 | % Converts edge list to adjacency matrix 2 | % INPUTS: edgelist: mx3 3 | % OUTPUTS: adjacency matrix nxn 4 | % Note: information about nodes is lost: indices only (i1,...in) remain 5 | % GB, Last updated: October 6, 2009 6 | 7 | function adj=edgeL2adj(el) 8 | 9 | nodes=sort(unique([el(:,1) el(:,2)])); % get all nodes, sorted 10 | adj=zeros(numel(nodes)); % initialize adjacency matrix 11 | 12 | % across all edges 13 | for i=1:size(el,1); adj(find(nodes==el(i,1)),find(nodes==el(i,2)))=el(i,3); end -------------------------------------------------------------------------------- /topology analysis/leaf_nodes.m: -------------------------------------------------------------------------------- 1 | % Return the leaf nodes of the graph - degree 1 nodes 2 | % Note: For a directed graph, leaf nodes are those with a single incoming edge 3 | % Note 2: There could be other definitions of leaves ex: farthest away from a given root node 4 | % Note 3: Nodes with self-loops are not considered leaf nodes. 5 | % Input: adjacency matrix 6 | % Output: indexes of leaf nodes 7 | % Last updated: Mar 25, 2011, by GB 8 | 9 | function leaves=leaf_nodes(adj) 10 | 11 | adj=int8(adj>0); 12 | 13 | leaves=find(sum(adj)==1); -------------------------------------------------------------------------------- /topology analysis/iscomplete.m: -------------------------------------------------------------------------------- 1 | % Checks whether a (sub)graph is complete, i.e. whether every node is 2 | % linked to every other node. Only defined for unweighted graphs. 3 | % INPUTS: adjacency matrix, adj, nxn 4 | % OUTPUTS: Boolean variable, true/false 5 | % GB, Last Updated: October 1, 2009 6 | 7 | function S=iscomplete(adj) 8 | 9 | S=false; % default 10 | 11 | adj=adj>0; % remove weights 12 | n=length(adj); 13 | 14 | % all degrees "n-1" or "n" or w/ n selfloops 15 | if sum(adj)==ones(1,n)*(n-1) | sum(adj)==ones(1,n)*n; S=true; end -------------------------------------------------------------------------------- /topology analysis/symmetrize_edgeL.m: -------------------------------------------------------------------------------- 1 | % Making an edgelist (representation of a graph) symmetric 2 | % INPUTs: edge list, mx3 3 | % OUTPUTs: symmetrized edge list, mx3 4 | % GB, Last updated: October 8, 2009 5 | 6 | function el=symmetrize_edgeL(el) 7 | 8 | el2=[el(:,1), el(:,2)]; 9 | 10 | for e=1:size(el,1) 11 | ind=ismember(el2,[el2(e,2),el2(e,1)],'rows'); 12 | if sum(ind)==0; el=[el; el(e,2), el(e,1), el(e,3)]; end 13 | end 14 | 15 | % Alternative: Using the adjacency matrix 16 | % adj=edgeL2adj(el); 17 | % adj=symmetrize(adj); 18 | % el=adj2edgeL(adj); -------------------------------------------------------------------------------- /topology analysis/ave_path_length.m: -------------------------------------------------------------------------------- 1 | % Compute average path length for a network - the average shortest path 2 | % INPUTS: adjL - matrix of weights/distances between nodes 3 | % OUTPUTS: average path length: the average of the shortest paths between every two edges 4 | % Note: works for directed/undirected networks 5 | % GB, December 8, 2005 6 | 7 | function l = ave_path_length(adj) 8 | 9 | n=size(adj,1); 10 | 11 | dij = []; 12 | 13 | for i=1:n; dij=[dij; simple_dijkstra(adj,i) ]; end 14 | 15 | l = sum(sum(dij))/(n^2-n); % sum and average across everything but the diagonal -------------------------------------------------------------------------------- /src/belief_diff.m: -------------------------------------------------------------------------------- 1 | function D = belief_diff( b1, b2 ) 2 | % BELIEF_DIFF - Computes the symmetric L1 distance between belief's 'b1' 3 | % and 'b2'. Inputs are N-dim cell arrays, where each cell is a probability 4 | % vector. L1 distances are returned in an Nx1 vector. 5 | % 6 | % Brown CS242 7 | 8 | num_b = numel(b1); 9 | if num_b ~= numel(b2), error('belief_diff: Belief dimensions are not equal.\n'); end; 10 | 11 | D = zeros(num_b,1); 12 | for i=1:num_b 13 | D(i) = 1/length(b1{i}) * sum( abs( b1{i} - b2{i} ) ); 14 | end 15 | D = mean(D); 16 | end 17 | 18 | -------------------------------------------------------------------------------- /topology analysis/num_star_motifs.m: -------------------------------------------------------------------------------- 1 | % Calculates the number of star motifs of given (subgraph) size 2 | % Easily extendible to return the actual stars as k-tuples of nodes 3 | % INPUTs: adjacency matrix of original graph, k - size of the star motif 4 | % OUTPUTs: number of stars with k nodes (k-1 spokes) 5 | % Other routines used: degrees.m 6 | % Note: star of size 1 is the trivial case of a single node 7 | 8 | function num = num_star_motifs(adj,k) 9 | 10 | [deg,~,~]=degrees(adj); 11 | 12 | num=0; 13 | 14 | for i=1:length(deg) 15 | if deg(i)>=(k-1); num=num+nchoosek(deg(i),k-1); end 16 | end -------------------------------------------------------------------------------- /topology analysis/edgeL2simple.m: -------------------------------------------------------------------------------- 1 | % Convert an edge list of a general graph to the edge list of a simple 2 | % graph (no loops, no double edges) - great for quick data clean up 3 | % INPUTS: edgelist (mx3), m - number of edges 4 | % OUTPUTs: edge list of the corresponding simple graph 5 | % Note: Assumes all node pairs [n1,n2,x] occur once; if else see add_edge_weights.m 6 | % GB, Last updated: October 4, 2009 7 | 8 | function el=edgeL2simple(el) 9 | 10 | el(:,3)=ones(size(el,1),1); % make all edge weights 1 11 | 12 | ind=find(not(el(:,1)-el(:,2)==0)); % indices of the "non-self-loops" 13 | el=el(ind,:); -------------------------------------------------------------------------------- /topology analysis/degrees.m: -------------------------------------------------------------------------------- 1 | % Compute the total degree, in-degree and out-degree of a graph based on 2 | % the adjacency matrix; should produce weighted degrees, if the input matrix is weighted 3 | % INPUTS: adjacency matrix 4 | % OUTPUTS: degree, indegree and outdegree sequences 5 | % GB, Last Updated: October 2, 2009 6 | 7 | function [deg,indeg,outdeg]=degrees(adj) 8 | 9 | indeg = sum(adj); 10 | outdeg = sum(adj'); 11 | 12 | if isdirected(adj) 13 | deg = indeg + outdeg; % total degree 14 | 15 | else % undirected graph: indeg=outdeg 16 | deg = indeg + diag(adj)'; % add self-loops twice, if any 17 | 18 | end -------------------------------------------------------------------------------- /topology analysis/num_loops.m: -------------------------------------------------------------------------------- 1 | % Calculate the number of independent loops (use G=m-n+c) 2 | % where G = num loops, m - num edges, n - num nodes, c - num_connected_components 3 | % This is also known as the "cyclomatic number" or the number of edges that need to be removed so that the graph cannot have cycles. 4 | % INPUTS: adjacency matrix 5 | % OUTPUTs: number of independent loops (or cyclomatic number) 6 | % Other routines used: numnodes.m, numedges.m, find_conn_comp.m 7 | 8 | function G = num_loops(adj) 9 | 10 | n=numnodes(adj); 11 | m=numedges(adj); 12 | comp_mat = find_conn_comp(adj); 13 | 14 | G=m-n+length(comp_mat); -------------------------------------------------------------------------------- /topology analysis/BFS.m: -------------------------------------------------------------------------------- 1 | % Implementation of breadth-first-search of a graph 2 | % INPUTs: adjacency list, starting node index 3 | % OUTPUTs: BFS tree, in adjacency list format (directed) 4 | 5 | function T=BFS(adjL,i0) 6 | 7 | discovered=[i0]; 8 | q=[i0]; 9 | T=cell(length(adjL),1); 10 | 11 | while not(isempty(q)) 12 | j=q(1); q=q(2:length(q)); % pop the front 13 | neigh=adjL{j}; 14 | for nn=1:length(neigh) 15 | if isempty(find(discovered==neigh(nn))) 16 | T{j}=[T{j}, neigh(nn)]; 17 | discovered=[discovered, neigh(nn)]; 18 | q=[q, neigh(nn)]; 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /topology analysis/kmin_neighbors.m: -------------------------------------------------------------------------------- 1 | % Finds the number of "kmin"-neighbors (k links away at a minimum) for every node 2 | % If nodes are k-links away due to loops (so they appear as m-neighbours, m0)]; 14 | adjk = adjk*adj; 15 | end 16 | 17 | kneigh = setdiff(find(adjk(ind,:)>0),[close_neighbors ind]); -------------------------------------------------------------------------------- /topology analysis/num_conn_triples.m: -------------------------------------------------------------------------------- 1 | % Counts the number of connected triples in a graph 2 | % INPUTs: adjacency matrix 3 | % OUTPUTs: integer - num conn triples 4 | % Other routines used: kneighbors.m, loops3.m 5 | % Note: works for undirected graphs only 6 | % GB, Last updated: October 9, 2009 7 | 8 | function c=num_conn_triples(adj) 9 | 10 | c=0; % initialize 11 | 12 | for i=1:length(adj) 13 | neigh=kneighbors(adj,i,1); 14 | if length(neigh)<2; continue; end % handle leaves, no triple here 15 | c=c+nchoosek(length(neigh),2); 16 | end 17 | 18 | c=c-2*loops3(adj); % due to the symmetry triangles repeat 3 times in the nchoosek count -------------------------------------------------------------------------------- /topology analysis/closeness.m: -------------------------------------------------------------------------------- 1 | % Computes the closeness centrality for every vertex: 1/sum(dist to all other nodes) 2 | % For disconnected graphs can use: sum_over_t(2^-d(i,t)), idea Dangalchev (2006) 3 | % C(i)=sum(2.^(-d)) if graph is disconnected, but sum w/o d(i) 4 | % INPUTs: graph representation (adjacency matrix nxn) 5 | % OUTPUTs: vector of centralities, nx1 6 | % Source: social networks literature 7 | % Other routines used: simple_dijkstra.m 8 | % GB, Last updated: October 9, 2009 9 | 10 | function C=closeness(adj) 11 | 12 | C=zeros(length(adj),1); % initialize closeness vector 13 | 14 | for i=1:length(adj); C(i)=1/sum( simple_dijkstra(adj,i) ); end -------------------------------------------------------------------------------- /topology analysis/random_directed_graph.m: -------------------------------------------------------------------------------- 1 | % Random directed graph construction 2 | % INPUTS: N - number of nodes 3 | % p - probability, 0<=p<=1 4 | % Output: adjacency matrix 5 | % Note 1: if p is omitted, p=0.5 is default 6 | % Note 2: no self-loops, no double edges 7 | 8 | function adj = random_directed_graph(n,p) 9 | 10 | adj=zeros(n); % initialize adjacency matrix 11 | 12 | if nargin==1; p=0.5; end; 13 | 14 | % splitting j = 1:i-1,i+1,n avoids the if statement i==j 15 | 16 | for i=1:n 17 | 18 | for j=1:i-1 19 | if rand<=p; adj(i,j)=1; end; 20 | end 21 | 22 | 23 | for j=i+1:n 24 | if rand<=p; adj(i,j)=1; end; 25 | end 26 | 27 | end 28 | 29 | -------------------------------------------------------------------------------- /topology analysis/rich_club_metric.m: -------------------------------------------------------------------------------- 1 | % Compute the rich club metric for a graph 2 | % INPUTs: adjacency matrix, nxn, k - threshold number of links 3 | % OUTPUTs: rich club metric 4 | % Source: Colizza, Flammini, Serrano, Vespignani, "Detecting rich-club ordering in complex networks", Nature Physics, vol 2, Feb 2006 5 | % Other routines used: degrees.m, subgraph.m, numedges.m 6 | % GB, Last updated: October 16, 2009 7 | 8 | function phi=rich_club_metric(adj,k) 9 | 10 | [deg,~,~]=degrees(adj); 11 | 12 | Nk=find(deg>=k); % find the nodes with degree > k 13 | if isempty(Nk); phi = 0; return; end 14 | 15 | adjk=subgraph(adj,Nk); 16 | phi=2*numedges(adjk)/(length(Nk)*(length(Nk)-1)); -------------------------------------------------------------------------------- /topology analysis/adj2str.m: -------------------------------------------------------------------------------- 1 | % Converts an adjacency matrix to a one-line string representation 2 | % INPUTS: adjacency matrix, nxn 3 | % OUTPUTS: string 4 | % The nomenclature used to construct the string is arbitrary. Here we use 5 | % .i1.j1.k1,.i2.j2.k2,.... 6 | % Other routines used: kneighbors.m 7 | % GB, Last updated: October 6, 2009 8 | 9 | function str=adj2str(adj) 10 | 11 | % in '.i1.j1.k1,.i2.j2.k2,....', dot: signifies new neighbor, comma: next node 12 | str=''; 13 | n=length(adj); 14 | 15 | for i=1:n 16 | neigh=kneighbors(adj,i,1); 17 | for k=1:length(neigh); str=strcat(str,'.',num2str(neigh(k))); end 18 | str=strcat(str,','); % close this node's neighbors list 19 | end -------------------------------------------------------------------------------- /topology analysis/ave_neighbor_deg.m: -------------------------------------------------------------------------------- 1 | % Computes the average degree of neighboring nodes for every vertex 2 | % Note: Works for weighted degrees also 3 | % INPUTs: adjacency matrix 4 | % OUTPUTs: average neighbor degree vector nx1 5 | % Other routines used: degrees.m, kneighbors.m 6 | % GB, Last updated: May 21, 2010 7 | 8 | function ave_n_deg=ave_neighbor_deg(adj) 9 | 10 | ave_n_deg=zeros(1,length(adj)); % initialize output vector 11 | [deg,~,~]=degrees(adj); 12 | 13 | for i=1:length(adj) % across all nodes 14 | 15 | neigh=kneighbors(adj,i,1); % neighbors of i, one link away 16 | if isempty(neigh); ave_n_deg(i)=0; continue; end 17 | ave_n_deg(i)=sum(deg(neigh))/deg(i); 18 | 19 | end -------------------------------------------------------------------------------- /topology analysis/laplacian_matrix.m: -------------------------------------------------------------------------------- 1 | % The Laplacian matrix defined for a *simple* graph 2 | % (the difference b/w the diagonal degree and the adjacency matrices) 3 | % Note: This is not the normalized Laplacian 4 | % INPUTS: adjacency matrix 5 | % OUTPUTs: Laplacian matrix 6 | 7 | function L=laplacian_matrix(adj) 8 | 9 | L=diag(sum(adj))-adj; 10 | 11 | 12 | % NORMALIZED Laplacian ============= 13 | 14 | % n=length(adj); 15 | % deg = sum(adj); % for other than simple graphs, use [deg,~,~]=degrees(adj); 16 | 17 | % L=zeros(n); 18 | % edges=find(adj>0); 19 | % 20 | % for e=1:length(edges) 21 | % [ii,jj]=ind2sub([n,n],edges(e)) 22 | % if ii==jj; L(ii,ii)=1; continue; end 23 | % L(ii,jj)=-1/sqrt(deg(ii)*deg(jj)); 24 | % end -------------------------------------------------------------------------------- /topology analysis/add_edge_weights.m: -------------------------------------------------------------------------------- 1 | % Add multiple edges in an edgelist 2 | % INPUTS: original (non-compact) edgelist 3 | % OUTPUTS: final compact edgelist (no row repetitions) 4 | % GB, Last updated: October 7, 2009 5 | 6 | function elc=add_edge_weights(el) 7 | 8 | el2=[el(:,1), el(:,2)]; % make the edge list searchable w/o the weights 9 | visited=[]; % mark visited edges 10 | 11 | elc=[]; 12 | for e=1:size(el,1) 13 | if sum(ismember(visited,el2(e,:),'rows'))==0 % if not visited yet 14 | ind=ismember(el2,el2(e,:),'rows'); 15 | ind=find(ind==1); % these are all the ocurrences of el(e,:) 16 | elc=[elc; el(e,1), el(e,2), sum(el(ind,3))]; 17 | visited=[visited; el2(e,:)]; 18 | end 19 | end -------------------------------------------------------------------------------- /topology analysis/graph_from_degree_sequence.m: -------------------------------------------------------------------------------- 1 | % Constructing a graph from a given degree sequence: deterministic 2 | % This is the Havel-Hakimi algorithm 3 | % Inputs: a graphic degree sequence, [d1,d2, ... dn], where di is the degree of the ith node 4 | % Outputs: adjacency matrix, nxn 5 | 6 | function adj = graph_from_degree_sequence(seq) 7 | 8 | adj = zeros(length(seq)); 9 | 10 | while sum(seq)>0 % while there are still stubs to connect 11 | 12 | % order stubs by decreasing number of degrees left 13 | [sorted,I] = sort(-seq); 14 | n1 = I(1); 15 | for x=1:-sorted(1) 16 | n2 = I(x+1); 17 | adj(n1,n2)= adj(n1,n2)+1; 18 | adj(n2,n1)= adj(n2,n1)+1; 19 | seq(n1) = seq(n1)-1; 20 | seq(n2) = seq(n2)-1; 21 | end 22 | 23 | end -------------------------------------------------------------------------------- /topology analysis/edgeL2cyto.m: -------------------------------------------------------------------------------- 1 | % Write an edgelist structure m x [node 1, node 2, link] to Cytoscape input format (.txt or any text extension works) 2 | % In Cytoscape the column separator option is semi-colon ";". If desired, this is easy to change below in line 15. 3 | % INPUTs: edgelist - mx3 matrix, m = number of edges, file name string 4 | % OUTPUTs: text file in Cytoscape format with a semicolon column separator 5 | 6 | function []=edgeL2cyto(el,filename) 7 | 8 | nodes=unique([el(:,1)', el(:,2)']); 9 | n=length(nodes); % number of nodes 10 | m = size(el,1); % number of edges 11 | 12 | fid = fopen(filename,'wt','native'); 13 | 14 | for i=1:m 15 | fprintf(fid,' %4i ; %4i ; %3.6f\n',el(i,1),el(i,2),el(i,3)); 16 | end 17 | 18 | fclose(fid); 19 | 20 | -------------------------------------------------------------------------------- /src/ave_scatter.m: -------------------------------------------------------------------------------- 1 | function [x,y]= ave_scatter(org_x,org_y) 2 | u_x = unique(org_x); 3 | if(length(u_x)==1) 4 | x=u_x; 5 | y=mean(org_y(~isnan(org_y))); 6 | return; 7 | end 8 | dup_idx = u_x(hist(org_x,u_x)>1); 9 | x=[]; 10 | y=[]; 11 | removed_idx=[]; 12 | for i=1:length(org_x) 13 | if(any(removed_idx==i)) 14 | continue; 15 | end 16 | if(any(dup_idx==org_x(i))) 17 | all_dup_idx = find(org_x==org_x(i)); 18 | other_dup_idx = all_dup_idx(all_dup_idx~=i); 19 | removed_idx = [removed_idx other_dup_idx]; 20 | tmp = org_y(all_dup_idx); 21 | ave_dup_y = mean(tmp(~isnan(tmp))); 22 | x=[x org_x(i)]; 23 | y=[y ave_dup_y]; 24 | else 25 | x=[x org_x(i)]; 26 | y=[y org_y(i)]; 27 | end 28 | end 29 | end -------------------------------------------------------------------------------- /topology analysis/numedges.m: -------------------------------------------------------------------------------- 1 | % Returns the total number of edges given the adjacency matrix 2 | % Valid for both directed and undirected, simple or general graph 3 | % INPUTs: adjacency matrix 4 | % OUTPUTs: m - total number of edges/links 5 | % Other routines used: selfloops.m, issymmetric.m 6 | % GB, Last Updated: October 1, 2009 7 | 8 | function m = numedges(adj) 9 | 10 | sl=selfloops(adj); % counting the number of self-loops 11 | 12 | if issymmetric(adj) & sl==0 % undirected simple graph 13 | m=sum(sum(adj))/2; 14 | return 15 | elseif issymmetric(adj) & sl>0 16 | sl=selfloops(adj); 17 | m=(sum(sum(adj))-sl)/2+sl; % counting the self-loops only once 18 | return 19 | elseif not(issymmetric(adj)) % directed graph (not necessarily simple) 20 | m=sum(sum(adj)); 21 | return 22 | end -------------------------------------------------------------------------------- /src/get_beliefs.m: -------------------------------------------------------------------------------- 1 | function [node_marg] = get_beliefs(G) 2 | % GET_BELIEFS - Returns cell arrays containing beliefs for each node. 3 | % 4 | % Inputs: 5 | % G: Factor graph to perform loopy BP over 6 | % 7 | % Outputs: 8 | % node_marg: cell array containing the marginals of each variable node, 9 | % computed by multiplying and normalizing the current messages. 10 | % Same format as nodeMarg = marg_brute_force(G); 11 | % 12 | % Brown CS242 13 | 14 | num_var = numel(G.var); 15 | node_marg = cell(num_var,1); 16 | % FILL ME IN! 17 | for i=1:length(G.var) 18 | varmag = 1; 19 | for j=1:length(G.var(i).incoming) 20 | varmag = varmag .* G.var(i).incoming{j}; 21 | end 22 | node_marg{i} = varmag/sum(varmag); 23 | end 24 | 25 | 26 | 27 | 28 | end 29 | -------------------------------------------------------------------------------- /topology analysis/sort_nodes_by_max_neighbor_degree.m: -------------------------------------------------------------------------------- 1 | % Sort nodes by degree, and where there's equality, by maximum neighbor degree 2 | % Ideas from Guo, Chen, Zhou, "Fingerprint for Network Topologies" 3 | % INPUTS: adjacency matrix, 0s and 1s 4 | % OUTPUTS: sorted sequence from 1 to n, where n is the number of rows/cols of the adjacency 5 | % Other routines used: degrees.m, kneighbors.m 6 | 7 | function I=sort_nodes_by_max_neighbor_degree(adj) 8 | 9 | [deg,~,~]=degrees(adj); % compute all degrees, use "deg" assuming symmetry 10 | 11 | degmat=zeros(size(adj,1),2); % a nx2 matrix 12 | 13 | for x=1:size(adj,1) % across all nodes 14 | degmat(x,1)=deg(x); 15 | if deg(x)==0; degmat(x,2)=0; continue; end 16 | nei_inds=kneighbors(adj,x,1); 17 | degmat(x,2)=max(deg(nei_inds)); 18 | 19 | end 20 | 21 | [sortmat,I]=sortrows(degmat); -------------------------------------------------------------------------------- /topology analysis/graph_similarity.m: -------------------------------------------------------------------------------- 1 | % Computes the similarity matrix between two graphs 2 | % Ref: "A measure of similarity between graph vertices: 3 | % applications to synomym extraction and web searching" 4 | % Blondel, SIAM Review, Vol. 46, No. 4, pp. 647-666 5 | % Inputs: A, B - two graphs adjacency matrices, mxm and nxn 6 | % Outputs: S - similarity matrix, mxn 7 | % Last updated: December 11, 2006 8 | 9 | function S=graph_similarity(A,B) 10 | 11 | m=size(A,1); n=size(B,1); 12 | S=zeros(n,m); S_new=ones(n,m); % initialize S: 13 | 14 | while norm(S_new-S,'fro')>0.001 15 | S=S_new; 16 | % do an iteration twice 17 | S_new=(B*S*transpose(A)+transpose(B)*S*A)/norm(B*S*transpose(A)+transpose(B)*S*A,'fro'); 18 | S_new=(B*S_new*transpose(A)+transpose(B)*S_new*A)/norm(B*S_new*transpose(A)+transpose(B)*S_new*A,'fro'); 19 | end 20 | 21 | S=S_new; -------------------------------------------------------------------------------- /topology analysis/inc2edgeL.m: -------------------------------------------------------------------------------- 1 | % Converts an incidence matrix to an edgelist 2 | % inputs: inc - incidence matrix nxm 3 | % outputs: edgelist - mx3 4 | % GB, Last Updated: June 9, 2006 5 | 6 | function el = inc2edgeL(inc) 7 | 8 | m = size(inc,2); % number of edges 9 | el = zeros(m,3); % initialize edgelist [n1, n2, weight] 10 | 11 | for e=1:m 12 | ind_m1 = find(inc(:,e)==-1); 13 | ind_p1 = find(inc(:,e)==1); 14 | 15 | if numel(ind_m1)==0 & numel(ind_p1)==1 % undirected, self-loop 16 | el(e,:) = [ind_p1 ind_p1 1]; 17 | 18 | elseif numel(ind_m1)==0 & numel(ind_p1)==2 % undirected 19 | el(e,:) = [ind_p1(1) ind_p1(2) 1]; 20 | el=[el; ind_p1(2) ind_p1(1) 1]; 21 | 22 | elseif numel(ind_m1)==1 & numel(ind_p1)==1 % directed 23 | el(e,:) = [ind_m1 ind_p1 1]; 24 | 25 | end 26 | end -------------------------------------------------------------------------------- /topology analysis/isgraphic.m: -------------------------------------------------------------------------------- 1 | % Check whether a sequence of number is graphical, i.e. a graph with this degree sequence exists 2 | % INPUTs: a sequence (vector) of numbers 3 | % OUTPUTs: boolean, true or false 4 | % Note: not generalized to directed graph degree sequences 5 | % Source: Erdős, P. and Gallai, T. "Graphs with Prescribed Degrees of Vertices" [Hungarian]. Mat. Lapok. 11, 264-274, 1960. 6 | 7 | function B = isgraphic(seq) 8 | 9 | if not(isempty(find(seq<=0))) | mod(sum(seq),2)==1 10 | % there are non-positive degrees or their sum is odd 11 | B = false; return; 12 | end 13 | 14 | n=length(seq); 15 | seq=-sort(-seq); % sort in decreasing order 16 | 17 | for k=1:n-1 18 | sum_dk = sum(seq(1:k)); 19 | sum_dk1 = sum(min([k*ones(1,n-k);seq(k+1:n)])); 20 | 21 | if sum_dk > k*(k-1) + sum_dk1; B = false; return; end 22 | 23 | end 24 | 25 | B = true; -------------------------------------------------------------------------------- /topology analysis/simple_dijkstra.m: -------------------------------------------------------------------------------- 1 | % Implements a simple version of the Dijkstra shortest path algorithm 2 | % Returns the distance from a single vertex to all others, doesn't save the path 3 | % INPUTS: adjacency matrix (adj), start node (s) 4 | % OUTPUTS: shortest path length from start node to all other nodes 5 | % Note: works with a weighted/directed matrix 6 | % GB, Last Updated: December 13, 2004 7 | 8 | function d = simple_dijkstra(adj,s) 9 | 10 | n=length(adj); 11 | d = inf*ones(1,n); % distance s-all nodes 12 | d(s) = 0; % s-s distance 13 | T = 1:n; % node set with shortest paths not found 14 | 15 | while not(isempty(T)) 16 | [dmin,ind] = min(d(T)); 17 | for j=1:length(T) 18 | if adj(T(ind),T(j))>0 & d(T(j))>d(T(ind))+adj(T(ind),T(j)) 19 | d(T(j))=d(T(ind))+adj(T(ind),T(j)); 20 | end 21 | end 22 | T = setdiff(T,T(ind)); 23 | end -------------------------------------------------------------------------------- /topology analysis/leaf_edges.m: -------------------------------------------------------------------------------- 1 | % Return the leaf edges of the graph: edges with one adjacent edge only 2 | % Leaf edges have only one associated leaf node, otherwise they are single floating disconnected edges. 3 | % Assumptions: 4 | % Note 1: For a directed graph, leaf edges are those that "flow into" the leaf node 5 | % Note 2: There could be other definitions of leaves ex: farthest away from a given root node 6 | % Note 3: Edges that are self-loops are not considered leaf edges. 7 | % Input: adjacency matrix 8 | % Output: set of leaf edges: a (num edges x 2) matrix where every row containts the leaf edge nodal indices 9 | % Last updated: June 27, 2011, by GB 10 | 11 | 12 | function edges=leaf_edges(adj) 13 | 14 | adj=int8(adj>0); 15 | 16 | lves=find(sum(adj)==1); % same as leaf_nodes.m 17 | 18 | edges=[]; 19 | 20 | for i=1:length(lves); edges=[edges; find(adj(:,lves(i))==1),lves(i)]; end -------------------------------------------------------------------------------- /topology analysis/pajek2xyz.m: -------------------------------------------------------------------------------- 1 | % Read x,y,z node coordinates from a pajek .net file - useful for plotting in Matlab 2 | % INPUTS: filename, string format 3 | % OUTPUTS: x,y,z coordinate vectors 4 | % GB, Last updated: October 7, 2009 5 | 6 | function [x,y,z]=pajek2xyz(filename) 7 | 8 | f=fopen(filename,'r'); 9 | C = textscan(f, '%s'); 10 | c=C{1}; 11 | 12 | ind_edges=find(ismember(c, '*Edges')==1); 13 | if isempty(ind_edges); ind_edges=find(ismember(c, '*Arcs')==1); end 14 | 15 | % c{1}='*Vertices', n=str2num(c{2}); % number of nodes 16 | % c{3},c{8},c{13},...c{5k+3} are node indices 17 | % c{4},c{9},c{14},...c{5k+4} are 'vi', between them are coordinates 18 | 19 | x=[]; y=[]; z=[]; % initialize coordinates 20 | 21 | for cc=3:ind_edges-1 22 | if mod(cc,5)==4 23 | x=[x, str2num(c{cc+1})]; 24 | y=[y, str2num(c{cc+2})]; 25 | z=[z, str2num(c{cc+3})]; 26 | end 27 | end -------------------------------------------------------------------------------- /topology analysis/distance_distribution.m: -------------------------------------------------------------------------------- 1 | % The number of pairs of nodes at a distance x, divided by the total number of pairs n(n-1) 2 | % Source: Mahadevan et al, "Systematic Topology Analysis and Generation Using Degree Correlations" 3 | % Note: The cumulative distance distribution (hop-plot) can be obtained by using ddist(i)=length(find(dij<=i)); in line 18 instead. 4 | % INPUTS: adjacency matrix, (nxn) 5 | % OUTPUTS: distribution vector ((n-1)x1): {k_i} where k_i is the # of pairs at a distance i, normalized 6 | % Other routines used: simple_dijkstra.m 7 | 8 | function ddist=distance_distribution(adj) 9 | 10 | n=size(adj,1); 11 | 12 | dij=[]; 13 | for i=1:n; dij=[dij; simple_dijkstra(adj,i) ]; end 14 | 15 | dij(find(dij==0))=inf; % not considering (i-i) node pairs/loops, 16 | % otherwise divide ddist by n^2 17 | 18 | for i=1:n-1; ddist(i)=length(find(dij==i)) / (n*(n-1)); end -------------------------------------------------------------------------------- /topology analysis/getNodes.m: -------------------------------------------------------------------------------- 1 | % return the list of nodes for varying representation types 2 | % inputs: graph structure (matrix or cell or struct) and type of structure 3 | % (string) 4 | % 'type' can be: 'adj','edgelist','adjlist' (neighbor list),'inc' (incidence matrix) 5 | % Note 1: only the edge list allows/returns non-consecutive node indexing 6 | % Note 2: no build-in error check for graph structure - type matching 7 | 8 | function nodes = getNodes(graph,type) 9 | 10 | if strcmp(type,'adj') | strcmp(type,'adjlist') 11 | nodes=[1:max([size(graph,1) size(graph,2)])]; 12 | 13 | elseif strcmp(type,'edgelist') 14 | nodes=unique([graph(:,1)' graph(:,2)']); 15 | 16 | elseif strcmp(type,'inc') 17 | nodes=[1:size(graph,1)]; 18 | else 19 | fprintf('"type" input can only be "adj" (adjacency, nxn matrix), "edgelist" (mx3 matrix)\n, "adjlist" (neighbor list, nx1 cell) and "inc" incidence (nxm matrix)\n') 20 | end -------------------------------------------------------------------------------- /src/add_facnode.m: -------------------------------------------------------------------------------- 1 | function G = add_facnode(G, p, varargin) 2 | % ADD_FACNODE - Add factor node to factor graph 'G'. 3 | % 4 | % INPUTS: 5 | % G - Factor graph 6 | % 7 | % p - Potential matrix with p(i,j,...) the potential for 8 | % x_a=i, x_b=j, ... 9 | % 10 | % varargin - Variable nodes involved in factor. Order matches dimensions 11 | % potential, e.g. varargin = { a, b, ... } => p(x_a,x_b,...). 12 | % 13 | % Brown CS242 14 | 15 | f.p = p; 16 | f.nbrs_var = [ varargin{:} ]; 17 | f.id = numel(G.fac) + 1; 18 | 19 | % check dimensions 20 | if ( ( numel(f.nbrs_var) > 1 ) && ( numel(f.nbrs_var) ~= ndims(p)) ) || ... 21 | ( ( numel(f.nbrs_var) == 1 ) && ( ndims(p) ~= 2 ) ) 22 | error('add_facnode: Factor dimensions does not match size of domain.'); 23 | end 24 | 25 | G.fac = cat( 1, G.fac, f ); 26 | for I=f.nbrs_var 27 | G.var(I).nbrs_fac = [ G.var(I).nbrs_fac; f.id ]; 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /topology analysis/draw_circ_graph.m: -------------------------------------------------------------------------------- 1 | % Draw a circular graph with links and nodes in order of degree 2 | % Strategy: position vertices in a regular n-polygon 3 | % INPUTs: adj - adjacency matrix 4 | % OUTPUTs: a figure 5 | % Other routines used: degrees.m 6 | % GB, February 21, 2006 7 | 8 | function [] = draw_circ_graph(adj) 9 | 10 | n = size(adj,1); % number of nodes 11 | [degs,~,~]=degrees(adj); 12 | [~, Y] = sort(degs); % Y - sorted nodal indices 13 | angl = 2*pi/n; % rotation angle 14 | 15 | for k=1:n 16 | x(Y(k)) = real(exp(angl*(k-1)*i)); 17 | y(Y(k)) = imag(exp(angl*(k-1)*i)); 18 | end 19 | 20 | for k=1:n 21 | plot(x(k),y(k),'ko') 22 | text(1.1*x(k),1.1*y(k),strcat('v',num2str(k))); 23 | hold off; hold on; 24 | end 25 | 26 | edges=find(adj>0); 27 | set(gcf,'Color',[1,1,1]) 28 | 29 | for e=1:length(edges) 30 | [ii,jj]=ind2sub([n,n],edges(e)); 31 | line([x(ii) x(jj)],[y(ii) y(jj)],'Color','k'); 32 | hold off; hold on; 33 | end 34 | axis off; -------------------------------------------------------------------------------- /topology analysis/iseulerian.m: -------------------------------------------------------------------------------- 1 | % Check if a graph is Eulerian, i.e. it has an Eulerian circuit 2 | % "A connected undirected graph is Eulerian if and only if every graph vertex has an even degree." 3 | % "A connected directed graph is Eulerian if and only if every graph vertex has equal in- and out- degree." 4 | % Note: Assume that the graph is connected. 5 | % INPUTS: adjacency matrix 6 | % OUTPUTS: Boolean variable 7 | % Other routines used: degrees.m, isdirected.m 8 | % GB, Last Updated: October 2, 2009 9 | 10 | 11 | function S=iseulerian(adj) 12 | 13 | S=false; 14 | 15 | [degs,indeg,outdeg]=degrees(adj); 16 | odd=find(mod(degs,2)==1); 17 | 18 | if not(isdirected(adj)) & isempty(odd) % if undirected and all degrees are even 19 | S=true; 20 | 21 | elseif isdirected(adj) & indeg==outdeg % directed and in-degrees equal out-degrees 22 | S=true; 23 | 24 | elseif numel(odd)==2 25 | fprintf('there is an Eulerian trail from node %2i to node %2i\n',odd(1),odd(2)); 26 | 27 | end -------------------------------------------------------------------------------- /topology analysis/getEdges.m: -------------------------------------------------------------------------------- 1 | % Return the list of edges for varying representation types 2 | % Inputs: graph structure (matrix or cell or struct) and type of structure (string) 3 | % Outputs: edge list 4 | % 'type' can be: 'adj','edgelist','adjlist' (neighbor list),'inc' (incidence matrix) 5 | % Note: symmetric edges will both twice, also in undirected graphs, (i.e. [n1,n2] and [n2,n1]) 6 | % Other routines used: adj2edgeL.m, adjL2edgeL.m, inc2edgeL.m 7 | 8 | function edges = getEdges(graph,type) 9 | 10 | if strcmp(type,'adj') 11 | edges=adj2edgeL(graph); 12 | 13 | elseif strcmp(type,'edgelist') 14 | edges=graph; % the graph structure is the edge list 15 | 16 | elseif strcmp(type,'adjlist') 17 | edges=adjL2edgeL(graph); 18 | 19 | elseif strcmp(type,'inc') 20 | edges=inc2edgeL(graph); 21 | else 22 | fprintf('"type" input can only be "adj" (adjacency, nxn matrix), "edgelist" (mx3 matrix)\n, "adjlist" (neighbor list, nx1 cell) and "inc" incidence (nxm matrix)\n') 23 | end -------------------------------------------------------------------------------- /topology analysis/pajek2edgeL.m: -------------------------------------------------------------------------------- 1 | % This program extracts an edge list from a pajek text (.net) file 2 | % INPUT: .net (or .txt) filename, n - number of nodes in the graph 3 | % OUTPUT: edge list, mx3, m - # edges 4 | % GB, October 7, 2009 5 | 6 | function el=pajek2edgeL(filename,n) 7 | 8 | [e1,e2,e3] = textread(filename,'%6d%6d%6d','headerlines',n+2); 9 | el=[e1,e2,e3]; 10 | 11 | % ALTERNATIVE: Not using the number of nodes as an input: 12 | % f=fopen(filename,'r'); 13 | % C = textscan(f, '%s'); 14 | % c=C{1}; 15 | % ind_edges=find(ismember(c, '*Edges')==1); 16 | % 17 | % e1=[]; e2=[]; e3=[]; 18 | % for cc=ind_edges:length(c) 19 | % % two indices are edges, one is weight and again 20 | % if mod(ind_edges,3)==mod(cc,3) % this is edge weight 21 | % e3=[e3, str2num(c{cc})]; 22 | % elseif mod(ind_edges,3)==mod(cc-1,3) % this is node 1 23 | % e1=[e1, str2num(c{cc})]; 24 | % elseif mod(ind_edges,3)==mod(cc-2,3) % this is node 2 25 | % e2=[e2, str2num(c{cc})]; 26 | % end 27 | % end 28 | % 29 | % el=[e1',e2',e3']; -------------------------------------------------------------------------------- /topology analysis/s_metric.m: -------------------------------------------------------------------------------- 1 | % The sum of products of degrees across all edges 2 | % Source: "Towards a Theory of Scale-Free Graphs: Definition, Properties, and Implications", by Li, Alderson, Doyle, Willinger 3 | % Note: The total degree is used regardless of whether the graph is directed or not. 4 | % INPUTs: adjacency matrix 5 | % OUTPUTs: s-metric 6 | % Other routines used: degrees.m 7 | 8 | function s=s_metric(adj) 9 | 10 | [deg,~,~]=degrees(adj); 11 | edges=find(adj>0); 12 | 13 | s=0; 14 | for e=1:length(edges) 15 | [i,j]=ind2sub([length(adj),length(adj)],edges(e)); 16 | s=s+deg(i)*deg(j); 17 | end 18 | 19 | 20 | % ALTERNATIVE ================ 21 | % $$$ [deg,~,~]=degrees(adj); 22 | % $$$ el=adj2edgeL(adj); 23 | % $$$ 24 | % $$$ s=0; 25 | % $$$ for e=1:size(el,1) 26 | % $$$ if el(e,1)==el(e,2) 27 | % $$$ s=s+deg(el(e,1))*deg(el(e,2))*el(e,3)*2; % count selfloops twice 28 | % $$$ else 29 | % $$$ s=s+deg(el(e,1))*deg(el(e,2))*el(e,3); % multiply by the weight for multiedges 30 | % $$$ end 31 | % $$$ end 32 | -------------------------------------------------------------------------------- /src/initialize.m: -------------------------------------------------------------------------------- 1 | function G = initialize(G,prior) 2 | for i=1:length(G.fac) 3 | G.fac(i).outgoing = cell(1,length(G.fac(i).nbrs_var)); 4 | G.fac(i).incoming = cell(1,length(G.fac(i).nbrs_var)); 5 | G.fac(i).oldoutgoing = cell(1,length(G.fac(i).nbrs_var)); 6 | for j = 1:length(G.fac(i).nbrs_var) 7 | G.fac(i).outgoing{j} = prior*ones(G.var(G.fac(i).nbrs_var(j)).dim,1); 8 | G.fac(i).incoming{j} = prior*ones(G.var(G.fac(i).nbrs_var(j)).dim,1); 9 | G.fac(i).oldoutgoing{j} = prior*ones(G.var(G.fac(i).nbrs_var(j)).dim,1); 10 | end 11 | end 12 | for i=1:length(G.var) 13 | G.var(i).outgoing = cell(1,length(G.var(i).nbrs_fac)); 14 | G.var(i).incoming = cell(1,length(G.var(i).nbrs_fac)); 15 | G.var(i).oldoutgoing = cell(1,length(G.var(i).nbrs_fac)); 16 | for j = 1:length(G.var(i).nbrs_fac) 17 | G.var(i).outgoing{j} = prior*ones(G.var(i).dim,1); 18 | G.var(i).incoming{j} = prior*ones(G.var(i).dim,1); 19 | G.var(i).oldoutgoing{j} = prior*ones(G.var(i).dim,1); 20 | end 21 | end 22 | end -------------------------------------------------------------------------------- /topology analysis/smooth_diameter.m: -------------------------------------------------------------------------------- 1 | % A relaxed/smoothed definition of diameter: the number "d" at which 2 | % a threshold fraction "p" of pairs of nodes are at distance at most 3 | % "d". Can be non-integer using interpolation. 4 | % Idea: Leskovec et al, "Graphs over Time: Densification Laws, Shrinking Diameters and Possible Explanations" 5 | % Input: adjacency matrix of graph and diameter threshold, p in [0,1] 6 | % Output: relaxed or "effective" diameter 7 | % Other routines used: simple_dijkstra.m 8 | 9 | function diam = smooth_diameter(adj,p) 10 | 11 | n=size(adj,1); 12 | 13 | dij=[]; 14 | for i=1:n; dij=[dij; simple_dijkstra(adj,i)]; end 15 | 16 | dij(find(dij==0))=inf; 17 | for i=1:n-1; ddist(i)=length(find(dij<=i)); end 18 | ddist=ddist/(n*(n-1)); 19 | 20 | lb = max(find(ddist<=p)); % lower bound 21 | ub = min(find(ddist>=p)); % upper bound 22 | 23 | if p==1; diam = ub; 24 | elseif ub==lb; diam = lb; 25 | elseif p1 16 | % Extract the neighbors of the first node only 17 | neigh=str(1:commas(1)-1); 18 | dots=find(neigh=='.'); 19 | for d=1:length(dots)-1; adj(1,str2num(neigh(dots(d)+1:dots(d+1)-1)))=1; end 20 | adj(1,str2num(neigh(dots(length(dots))+1:length(neigh))))=1; 21 | end 22 | 23 | % Extract the neighbors of the remaining 2:n nodes 24 | for i=2:n 25 | neigh=str(commas(i-1)+1:commas(i)-1); 26 | if isempty(neigh); continue; end 27 | 28 | dots=find(neigh=='.'); 29 | for d=1:length(dots)-1; adj(i,str2num(neigh(dots(d)+1:dots(d+1)-1)))=1; end 30 | 31 | adj(i,str2num(neigh(dots(length(dots))+1:length(neigh))))=1; 32 | 33 | end -------------------------------------------------------------------------------- /topology analysis/PriceModel.m: -------------------------------------------------------------------------------- 1 | % Routine implementing the Price model for network growth 2 | % Notes: 3 | % p_k - fraction of vertices with degree k 4 | % probability a new vertex attaches to any of the degree-k vertices is 5 | % (k+1)p_k/(m+1), where m - mean number of new citations per vertex 6 | % Source: "The Structure and Function of Complex Networks", M.E.J. Newman 7 | % INPUTs: n - final number of vertices 8 | % OUTPUTs: adjacency matrix, directed 9 | % GB, Last modified: March 18, 2006 10 | 11 | function adj = PriceModel(n) 12 | 13 | adj = zeros(n); 14 | adj(1,1) = 1; 15 | vertices = 1; 16 | 17 | while vertices < n 18 | % attach new vertex 19 | vertices = vertices + 1; 20 | adj(vertices,vertices) = 1; 21 | 22 | indeg = sum(adj); % get indegree values 23 | m = 0; % mean in-degree (per vertex) 24 | for k=1:vertices 25 | pk(k) = numel(find(indeg==k))/vertices; 26 | m = m + pk(k)*k; 27 | end 28 | 29 | % attach new edges with probability (k+1)pk/(m+1) 30 | for k=1:vertices 31 | if rand < (k+1)*pk(k)/(m+1); adj(vertices,k)=adj(vertices,k)+1; end 32 | end 33 | 34 | end 35 | 36 | adj=adj-diag(diag(adj)); % remove self-loops -------------------------------------------------------------------------------- /topology analysis/node_betweenness_faster.m: -------------------------------------------------------------------------------- 1 | % Betweenness centrality measure: number of shortest paths running though a vertex 2 | % Compute for all vertices, using Dijkstra's algorithm, using 'number of shortest paths through a node' definition 3 | % Note: Valid for a general (connected) graph. 4 | % INPUTS: adjacency (distances) matrix (nxn) 5 | % OUTPUTS: betweeness vector for all vertices (nx1) 6 | % Other routines used: dijkstra.m 7 | % GB, December 22, 2009 8 | 9 | function betw = node_betweenness_faster(adj) 10 | 11 | n = length(adj); 12 | spaths=inf(n,n); 13 | adjk = adj; 14 | 15 | % calculate number of shortest paths 16 | for k=1:n-1 17 | 18 | for i=1:n 19 | for j=1:n 20 | 21 | if adjk(i,j)>0; spaths(i,j)=min([spaths(i,j) adjk(i,j)]); end 22 | 23 | end 24 | end 25 | 26 | adjk=adjk*adj; 27 | 28 | end 29 | 30 | 31 | betw = zeros(1,n); 32 | for i=1:n 33 | [dist,P]=dijkstra(adj,i,[]); 34 | for j=1:n 35 | 36 | if dist(j)<=1; continue; end % either i=j or i,j are 1 edge apart 37 | betw(P{j}(2:dist(j))) = betw(P{j}(2:dist(j))) + 1/spaths(i,j); 38 | 39 | end 40 | end 41 | 42 | betw=betw/nchoosek(n,2); % further normalize by the number of all node pairs -------------------------------------------------------------------------------- /topology analysis/loops4.m: -------------------------------------------------------------------------------- 1 | % Finds loops of length 4 in a graph; Note: Quite basic and slow, but works 2 | % INPUTs: adj - adjacency matrix of graph 3 | % OUTPUTs: number of loops of size 4 4 | % Note: assumes undirected graph 5 | % Other functions used: adj2adjL.m 6 | % Last Updated: May 25, 2010, originally April 2006 7 | 8 | function l4 = loops4(adj) 9 | 10 | n = size(adj,1); % number of nodes 11 | L = adj2adjL(adj); % adjacency list or list of neighbors 12 | 13 | l4 = {}; % initialize loops of size 4 14 | 15 | for i=1:n-1 16 | for j=i+1:n 17 | 18 | int=intersect(L{i},L{j}); 19 | int=setdiff(int,[i j]); 20 | 21 | if length(int)>=2 22 | % enumerate pairs in the intersection 23 | for ii=1:length(int)-1 24 | for jj=ii+1:length(int) 25 | loop4=sort([i,j,int(ii),int(jj)]); 26 | loop4=strcat(num2str(loop4(1)),'-',num2str(loop4(2)),'-',num2str(loop4(3)),'-',num2str(loop4(4))); 27 | 28 | if sum(ismember(l4,loop4))>0; continue; end 29 | l4{length(l4)+1}=loop4; 30 | 31 | end 32 | end 33 | end 34 | 35 | 36 | end 37 | end -------------------------------------------------------------------------------- /topology analysis/clust_coeff.m: -------------------------------------------------------------------------------- 1 | % Computes clustering coefficient, based on triangle motifs count and local clustering 2 | % C1 = num triangle loops / num connected triples 3 | % C2 = the average local clustering, where Ci = (num triangles connected to i) / (num triples centered on i) 4 | % Ref: M. E. J. Newman, "The structure and function of complex networks" 5 | % Valid for directed and undirected graphs 6 | % INPUT: adjacency matrix representation of a graph 7 | % OUTPUT: graph average clustering coefficient and clustering coefficient 8 | % Other routines used: degrees.m, isdirected.m, kneighbors.m, numedges.m, subgraph.m, loops3.m, num_conn_triples.m 9 | % GB, October 9, 2009 10 | 11 | function [C1,C2,C] = clust_coeff(adj) 12 | 13 | n = length(adj); 14 | adj = adj>0; % no multiple edges 15 | [deg,~,~] = degrees(adj); 16 | C=zeros(n,1); % initialize clustering coefficient 17 | 18 | % multiplication change in the clust coeff formula 19 | coeff = 2; 20 | if isdirected(adj); coeff=1; end 21 | 22 | for i=1:n 23 | 24 | if deg(i)==1 | deg(i)==0; C(i)=0; continue; end 25 | 26 | neigh=kneighbors(adj,i,1); 27 | edges_s=numedges(subgraph(adj,neigh)); 28 | 29 | C(i)=coeff*edges_s/deg(i)/(deg(i)-1); 30 | 31 | end 32 | 33 | C1=loops3(adj)/num_conn_triples(adj); 34 | C2=sum(C)/n; -------------------------------------------------------------------------------- /topology analysis/pdf_cdf_rank.m: -------------------------------------------------------------------------------- 1 | % Compute the pdf, cdf and rank distributions for a sequence of values 2 | % INPUTS: sequence of values: x, size 1xn, 'plot' - 'on' or 'off' 3 | % OUTPUTS: pdf, cdf and rank distribution values 4 | % Note: pdf = frequency, cdf = cumulative frequency, rank = log-log scale of the sorted sequence 5 | % GB, Last Updated: June 27, 2007 6 | 7 | function [xpdf,ypdf,xcdf,ycdf,logk,logx]=pdf_cdf_rank(x,plt) 8 | 9 | xx=unique(x); 10 | 11 | bin = 100; % arbitrary, change if xx has few values 12 | if length(xx)<100; bin = 10; end; 13 | 14 | 15 | for ii=1:numel(xx) 16 | xcdf(ii) = xx(ii); ycdf(ii) = length(find(x<=xx(ii)))/numel(x); 17 | 18 | % how many x's fall in the interval [xx(ii)-0.5*numel(xx)/bin,xx(ii)+0.5*numel(xx)/bin] 19 | xpdf(ii) = xx(ii); ypdf(ii) = length(find(abs(xx(ii)-x)<=0.5*numel(xx)/bin))/numel(x); 20 | end 21 | 22 | x=-sort(-x); 23 | logk=log(1:length(x)); 24 | logx=log(x); 25 | 26 | if strcmp(plt,'on') 27 | set(gcf,'color',[1,1,1]) 28 | subplot(1,3,1) 29 | plot(xpdf,ypdf,'k.') 30 | title('pdf') 31 | axis('tight') 32 | subplot(1,3,2) 33 | plot(xcdf,ycdf,'k.') 34 | title('cdf') 35 | axis('tight') 36 | subplot(1,3,3) 37 | plot(logk,logx,'k.') 38 | title('rank') 39 | axis('tight') 40 | end -------------------------------------------------------------------------------- /topology analysis/master_equation_growth_model.m: -------------------------------------------------------------------------------- 1 | % "Master equation" growth model, as in "Evolution of Networks" by Dorogovtsev, Mendez 2 | % Note: probability of attachment: (q(i)+ma)/((1+a)mt), q(i)-indegree of i, a=const, t - time step (# nodes) 3 | % INPUTS: number of nodes n, m - # links to add at each step, a=constant 4 | % OUTPUTS: adjacency matrix, nxn 5 | % Last updated by GB: May 18, 2007 6 | 7 | function adj=master_equation_growth_model(n,m,a) 8 | 9 | adj=zeros(n); adj(1,2)=2; adj(2,1)=2; % initial condition 10 | vertices = 2; 11 | if nargin==2 | a==[]; a = 2; end % pick a constant 12 | 13 | while vertices < n 14 | 15 | t = vertices; 16 | q=sum(adj); % indegrees 17 | 18 | % compute the probability of attachment 19 | pk = zeros(1,t); 20 | for k=1:t; pk(k)=(q(k)+m*a)/((1+a)*m*t); end 21 | 22 | r = randsample([1:t],m,true,pk); 23 | if length(unique(r))~=length(r) 24 | r = randsample([1:t],m,true,pk); 25 | end 26 | 27 | vertices=vertices+1; % add vertex 28 | 29 | % add m links 30 | for node=1:length(r) 31 | adj(vertices,r(node))=1; 32 | adj(r(node),vertices)=1; 33 | end 34 | 35 | adj(vertices,vertices)=1; % for the purposes of non-zero probability of attachment 36 | 37 | end 38 | 39 | adj = adj>0; 40 | adj=adj-diag(diag(adj)); % remove self-loops -------------------------------------------------------------------------------- /topology analysis/min_span_tree.m: -------------------------------------------------------------------------------- 1 | % Prim's minimal spanning tree algorithm 2 | % Prim's alg idea: 3 | % start at any node, find closest neighbor and mark edges 4 | % for all remaining nodes, find closest to previous cluster, mark edge 5 | % continue until no nodes remain 6 | % INPUTS: graph defined by adjacency matrix 7 | % OUTPUTS: matrix specifying minimum spanning tree (subgraph) 8 | % Other routines used: isconnected.m 9 | % GB, March 14, 2005 10 | 11 | function tr = min_span_tree(adj) 12 | 13 | % check if graph is connected: 14 | if not(isconnected(adj)); fprintf('the graph is not connected, no spanning tree exists\n'); return; end 15 | 16 | n = length(adj); % number of nodes 17 | tr = zeros(n); % initialize tree 18 | 19 | adj(find(adj==0))=inf; % set all zeros in the matrix to inf 20 | 21 | conn_nodes = 1; % nodes part of the min-span-tree 22 | rem_nodes = [2:n]; % remaining nodes 23 | 24 | while length(rem_nodes)>0 25 | [minlink]=min(min(adj(conn_nodes,rem_nodes))); 26 | ind=find(adj(conn_nodes,rem_nodes)==minlink); 27 | 28 | [ind_i,ind_j] = ind2sub([length(conn_nodes),length(rem_nodes)],ind(1)); 29 | 30 | i=conn_nodes(ind_i); j=rem_nodes(ind_j); % gets back to adj indices 31 | tr(i,j)=1; tr(j,i)=1; 32 | conn_nodes = [conn_nodes j]; 33 | rem_nodes = setdiff(rem_nodes,j); 34 | 35 | end -------------------------------------------------------------------------------- /topology analysis/isbipartite.m: -------------------------------------------------------------------------------- 1 | % Test whether a graph is bipartite, if yes, return the two vertex sets 2 | % Inputs: graph in the form of adjancency list (neighbor list, see adj2adjL.m) 3 | % Outputs: True/False (boolean), empty set (if False) or two sets of vertices 4 | % Note: This only works for undirected graphs 5 | % Last updated: April 28, 2011 6 | 7 | function [isit,A,B]=isbipartite(L) 8 | 9 | isit=true; % default 10 | A=[]; B=[]; 11 | 12 | queue=[1]; % initialize to first vertex arbitrarily 13 | visited=[]; % initilize to empty 14 | A=[1]; % put the first node on the queue in A, arbitrarily 15 | 16 | while not(isempty(queue)) 17 | 18 | i=queue(1); 19 | visited=[visited, i]; 20 | 21 | if length(find(A==i))>0 22 | for j=1:length(L{i}) 23 | B=[B,L{i}(j)]; 24 | if length(find(visited==L{i}(j)))==0; queue=[queue, L{i}(j)]; end 25 | end 26 | 27 | elseif length(find(B==i))>0 28 | 29 | for j=1:length(L{i}) 30 | A=[A,L{i}(j)]; 31 | if length(find(visited==L{i}(j)))==0; queue=[queue, L{i}(j)]; end 32 | end 33 | 34 | end 35 | 36 | queue=queue(2:length(queue)); % remove the visited node 37 | 38 | % if A and B overlap, return false, [],[] ==== 39 | A=unique(A); B=unique(B); 40 | if not(isempty(intersect(A,B))); isit=false; A=[]; B=[]; return; end 41 | % ============================================ 42 | 43 | end -------------------------------------------------------------------------------- /topology analysis/shortest_pathDP.m: -------------------------------------------------------------------------------- 1 | % Shortest path algorithm using Dynamic Programming 2 | % Valid for directed/undirected network 3 | % Disclaimer: if links have weights, they are treated as distances 4 | % INPUTs: L - (cost/path lengths matrix), s - (start/source node), t - (end/destination node) 5 | % OUTPUTS: 6 | % route - sequence of nodes on optimal path, at current stage 7 | % ex: route(i,j) - best route from j to destination in (i) steps 8 | % Jo - optimal cost function (path length) 9 | % Source: D. P. Bertsekas, Dynamic Programming and Optimal Control, Athena Scientific, 2005 (3rd edition) 10 | % GB, Last Updated: March 9, 2006 11 | 12 | function [J_st,route_st,J,route]=shortest_pathDP(L,s,t,steps) 13 | 14 | n = size(L,2); 15 | 16 | L(find(L==0))=Inf; % make all zero distances equal to infinity 17 | 18 | for i=1:n 19 | J(steps,i) = L(i,t); 20 | route(steps,i).path = [t]; 21 | end 22 | 23 | % find min for every i: Jk(i)=min_j(L(i,j)+Jk+1(j)) 24 | for p=1:steps-1 25 | k=steps-p; % recurse backwards 26 | 27 | for i=1:n 28 | %fprintf('stage %2i, node %2i \n',k,i) 29 | [J(k,i),ind_j] = min(L(i,:)+J(k+1,:)); 30 | route(k,i).path = [ind_j, route(k+1,ind_j).path]; 31 | end 32 | 33 | end 34 | 35 | [J_st,step_ind] = min(J(:,s)); 36 | route_st = [s, route(step_ind,s).path]; 37 | J=J(sort(1:n,'descend'),:); 38 | route=route(sort(1:n,'descend'),:); -------------------------------------------------------------------------------- /topology analysis/graph_dual.m: -------------------------------------------------------------------------------- 1 | % Finds the dual of a graph; a dual is the inverted nodes-edges graph 2 | % This is also called the line graph, adjoint graph or the edges adjacency 3 | % INPUTs: adjacency (neighbor) list representation of the graph (see adj2adjL.m) 4 | % OUTPUTs: adj (neighbor) list of the corresponding dual graph and cell array of edges 5 | % Note: this routine only works for undirected, simple graphs 6 | % GB, March 26, 2011 7 | 8 | function [dL,edge_array] = graph_dual(L) 9 | 10 | dL={}; % initialize 11 | for i=1:length(L) 12 | for j=1:length(L{i}) 13 | 14 | if i<=L{i}(j); dL{length(dL)+1}=[]; end 15 | 16 | end 17 | end 18 | 19 | edge_array={}; 20 | 21 | for i=1:length(L) 22 | 23 | for j=1:length(L{i}) % add i,L{i}j to list of nodes 24 | if i<=L{i}(j); edge_array{length(edge_array)+1}= strcat(num2str(i),'-',num2str(L{i}(j))); end 25 | end 26 | 27 | for j=1:length(L{i}) % add i - L{i}j to list of edges 28 | for k=j+1:length(L{i}) 29 | edge1=strcat(num2str(min([i,L{i}(j)])),'-',num2str(max([i,L{i}(j)]))); 30 | edge2=strcat(num2str(min([i,L{i}(k)])),'-',num2str(max([i,L{i}(k)]))); 31 | 32 | ind_edge1=find(ismember(edge_array, edge1)==1); 33 | ind_edge2=find(ismember(edge_array, edge2)==1); 34 | 35 | dL{ind_edge1}=unique([dL{ind_edge1},ind_edge2]); 36 | dL{ind_edge2}=unique([dL{ind_edge2},ind_edge1]); 37 | end 38 | end 39 | end -------------------------------------------------------------------------------- /topology analysis/simple_spectral_partitioning.m: -------------------------------------------------------------------------------- 1 | % Uses the fiedler vector to assign nodes to groups 2 | % INPUTS: adj - adjancency matrix, k - desired number of nodes in groups [n1, n2, ..], [optional] 3 | % OUTPUTs: modules - [k] partitioned groups of nodes 4 | % Other functions used: fiedler_vector.m 5 | 6 | function modules = simple_spectral_partitioning(adj,k) 7 | 8 | % find the Fiedler vector: eigenvector corresponding to the second smallest eigenvalue of the Laplacian matrix 9 | fv = fiedler_vector(adj); 10 | [~,I]=sort(fv); 11 | 12 | % depending on k, partition the nodes 13 | if nargin==1 14 | 15 | modules{1}=[]; modules{2}=[]; 16 | % choose 2 groups based on signs of fv components 17 | for v=1:length(fv) 18 | if fv(v)>0; modules{2} = [modules{2}, v]; end 19 | if fv(v)<=0; modules{1} = [modules{1}, v]; end 20 | end 21 | end 22 | 23 | if nargin==2 24 | 25 | k = [0 k]; 26 | 27 | for kk=1:length(k) 28 | 29 | modules{kk}=[]; 30 | for x=1:k(kk); modules{kk} = [modules{kk} I(x+k(kk-1))]; end 31 | 32 | end 33 | 34 | modules = modules(2:length(modules)); 35 | end 36 | 37 | 38 | set(gcf,'Color',[1 1 1]) 39 | subplot(1,2,1) 40 | plot(fv(I),'k.'); 41 | xlabel('index i') 42 | ylabel('fv(i)') 43 | title('sorted fiedler vector') 44 | axis('tight') 45 | axis('square') 46 | 47 | subplot(1,2,2) 48 | spy(adj(I,I),'k') 49 | title('sorted adjacency matrix') -------------------------------------------------------------------------------- /topology analysis/rewire_disassort.m: -------------------------------------------------------------------------------- 1 | % Degree-preserving random rewiring 2 | % Every rewiring decreases the assortativity (pearson coefficient) 3 | % Note 1: There are rare cases of neutral rewiring (coeff stays the same within numerical error) 4 | % Note 2: Assume unweighted undirected graph 5 | % INPUTS: edgelist, el and number of rewirings, k 6 | % OUTPUTS: rewired edgelist 7 | 8 | function el = rewire_disassort(el,k) 9 | 10 | [deg,~,~]=degrees(edgeL2adj(el)); 11 | 12 | rew=0; 13 | 14 | while rew0; continue; end % the two edges cannot overlap 21 | 22 | nodes=[edge1(1) edge1(2) edge2(1) edge2(2)]; 23 | [~,Y]=sort(deg(nodes)); 24 | 25 | % connect nodes(Y(1))-nodes(Y(4)) and nodes(Y(2))-nodes(Y(3)) 26 | if ismember([nodes(Y(1)),nodes(Y(4)),1],el,'rows') | ismember([nodes(Y(2)),nodes(Y(3)),1],el,'rows'); continue; end 27 | 28 | el(ind(1),:)=[nodes(Y(1)),nodes(Y(4)),1]; 29 | el(ind(2),:)=[nodes(Y(2)),nodes(Y(3)),1]; 30 | 31 | [~,inds1] = ismember([edge1(2),edge1(1),1],el,'rows'); 32 | el(inds1,:)=[nodes(Y(4)),nodes(Y(1)),1]; 33 | 34 | [~,inds2] = ismember([edge2(2),edge2(1),1],el,'rows'); 35 | el(inds2,:)=[nodes(Y(3)),nodes(Y(2)),1]; 36 | 37 | rew=rew+1; 38 | 39 | end -------------------------------------------------------------------------------- /topology analysis/weighted_clust_coeff.m: -------------------------------------------------------------------------------- 1 | % Weighted clustering coefficient 2 | % Source: Barrat, The architecture of complex weighted networks 3 | % INPUTS: weighted adjacency matrix 4 | % OUTPUTs: vector of node weighted clustering coefficients 5 | % Other routines used: degrees.m, kneighbors.m 6 | 7 | function wC=weighted_clust_coeff(adj) 8 | 9 | [deg,~,~]=degrees(adj); 10 | n=size(adj,1); % number of nodes 11 | wC=zeros(n,1); % initialize weighted clust coeff 12 | 13 | for i=1:n % across all nodes 14 | neigh=kneighbors(adj,i,1); 15 | if length(neigh)<2; continue; end 16 | 17 | s=0; 18 | for ii=1:length(neigh) 19 | for jj=1:length(neigh) 20 | 21 | if adj(neigh(ii),neigh(jj))>0; s=s+(adj(i,neigh(ii))+adj(i,neigh(jj)))/2; end 22 | 23 | end 24 | end 25 | 26 | wC(i)=s/(deg(i)*(length(neigh)-1)); 27 | end 28 | 29 | 30 | % % ALTERNATIVE ========================================================= 31 | % wadj=adj; 32 | % adj=adj>0; 33 | % 34 | % [wdeg,~,~]=degrees(wadj); 35 | % [deg,~,~]=degrees(adj); 36 | % n=size(adj,1); % number of nodes 37 | % wC=zeros(n,1); 38 | % 39 | % for i=1:n 40 | % if deg(i)<2; continue; end 41 | % 42 | % s=0; 43 | % for ii=1:n 44 | % for jj=1:n 45 | % s=s+adj(i,ii)*adj(i,jj)*adj(ii,jj)*(wadj(i,ii)+wadj(i,jj))/2; 46 | % end 47 | % end 48 | % 49 | % wC(i)=s/(wdeg(i)*(deg(i)-1)); 50 | % end -------------------------------------------------------------------------------- /topology analysis/random_modular_graph.m: -------------------------------------------------------------------------------- 1 | % Build a random modular graph, given number of modules, and link density 2 | % INPUTs: number of nodes, number of modules, total link density, 3 | % and proportion of links within modules compared to links across 4 | % OUTPUTs: adjacency matrix, modules to which the nodes are assigned 5 | % GB, Last updated: October 19, 2009 6 | 7 | function [adj, modules] = random_modular_graph(n,c,p,r) 8 | 9 | % n - number of nodes 10 | % c - number of clusters/modules 11 | % p - overall probability of attachment 12 | % r - proportion of links within modules 13 | 14 | z=round(p*(n-1)); % z=p(n-1) - Erdos-Renyi average degree 15 | 16 | % assign nodes to modules: 1 -> n/c, n/c+1 -> 2n/c, ... , (c-1)n/c -> c(n/c); 17 | modules=cell(c,1); 18 | for k=1:c; modules{k}=round((k-1)*n/c+1):round(k*n/c); end 19 | 20 | adj=zeros(n); % initialize adjacency matrix 21 | 22 | for i=1:n 23 | for j=i+1:n 24 | 25 | module_i=ceil(c*i/n); % the module to which i belongs to 26 | module_j=ceil(c*j/n); % the module to which j belongs to 27 | 28 | if module_i==module_j 29 | 30 | % prob of attachment within module 31 | if rand<=r*z/(n/c-1); adj(i,j)=1; adj(j,i)=1; end 32 | 33 | else 34 | 35 | % prob of attachment across modules 36 | if rand<=z*(1-r)/(n-n/c); adj(i,j)=1; adj(j,i)=1; end 37 | 38 | end 39 | end 40 | end -------------------------------------------------------------------------------- /topology analysis/node_betweenness_slow.m: -------------------------------------------------------------------------------- 1 | % Betweenness centrality measure: number of shortest paths running though a 2 | 3 | % vertex. Compute for all vertices. 4 | 5 | % Note: Valid for a general graph. Using 'number of shortest paths through a node' definition 6 | 7 | % INPUTS: adjacency (distances) matrix (nxn) 8 | 9 | % OUTPUTS: betweeness vector for all vertices (nx1) 10 | 11 | % 12 | 13 | % GB, October 13, 2009 14 | 15 | 16 | 17 | function betw = node_betweenness_slow(adj) 18 | 19 | 20 | 21 | n = numnodes(adj); 22 | 23 | spaths=inf(n,n); 24 | 25 | 26 | 27 | % calculate number of shortest paths 28 | 29 | for k=1:n-1 30 | 31 | adjk=adj^k; 32 | 33 | for i=1:n 34 | 35 | for j=1:n 36 | 37 | if adjk(i,j)>0 38 | 39 | spaths(i,j)=min([spaths(i,j) adjk(i,j)]); 40 | 41 | end 42 | 43 | end 44 | 45 | end 46 | 47 | end 48 | 49 | 50 | 51 | betw = zeros(1,n); 52 | 53 | for i=1:n 54 | 55 | [J_st,route_st,J,route]=shortest_pathDP(adj,i,i,n); 56 | 57 | for j=1:n 58 | 59 | if i==j 60 | 61 | continue 62 | 63 | end 64 | 65 | %[J_st,route_st]=shortest_pathDP(adj,i,j,n); 66 | 67 | [J_ji,step_ind] = min(J(:,j)); 68 | 69 | route_ji = [j, route(step_ind,j).path]; 70 | 71 | betw(route_ji(2:length(route_ji)-1)) = betw(route_ji(2:length(route_ji)-1)) + 1/spaths(j,i); 72 | 73 | end 74 | 75 | end 76 | 77 | 78 | 79 | betw=betw/nchoosek(n,2); -------------------------------------------------------------------------------- /topology analysis/rewire_assort.m: -------------------------------------------------------------------------------- 1 | % Degree-preserving random rewiring 2 | % Every rewiring increases the assortativity (pearson coefficient) 3 | % Note 1: There are rare cases of neutral rewiring (coeff stays the same within numerical error) 4 | % Note 2: Assume unweighted undirected graph 5 | % INPUTS: edgelist, el and number of rewirings, k 6 | % OUTPUTS: rewired edgelist 7 | % Other routines used: degrees.m 8 | 9 | function el = rewire_assort(el,k) 10 | 11 | [deg,~,~]=degrees(edgeL2adj(el)); 12 | 13 | rew=0; 14 | 15 | while rew0; continue; end % the two edges cannot overlap 22 | 23 | nodes=[edge1(1) edge1(2) edge2(1) edge2(2)]; 24 | [~,Y]=sort(deg(nodes)); 25 | 26 | % connect nodes(Y(1))-nodes(Y(2)) and nodes(Y(3))-nodes(Y(4)) 27 | if ismember([nodes(Y(1)),nodes(Y(2)),1],el,'rows') | ismember([nodes(Y(3)),nodes(Y(4)),1],el,'rows'); continue; end 28 | 29 | el(ind(1),:)=[nodes(Y(3)),nodes(Y(4)),1]; 30 | el(ind(2),:)=[nodes(Y(1)),nodes(Y(2)),1]; 31 | 32 | [~,inds1] = ismember([edge1(2),edge1(1),1],el,'rows'); 33 | el(inds1,:)=[nodes(Y(4)),nodes(Y(3)),1]; 34 | 35 | [~,inds2] = ismember([edge2(2),edge2(1),1],el,'rows'); 36 | el(inds2,:)=[nodes(Y(2)),nodes(Y(1)),1]; 37 | 38 | rew=rew+1; 39 | 40 | end -------------------------------------------------------------------------------- /topology analysis/adj2inc.m: -------------------------------------------------------------------------------- 1 | % Convert adjacency matrix to an incidence matrix 2 | % Valid for directed/undirected, simple/not simple graph 3 | % INPUTs: adjacency matrix, NxN, N - number of nodes 4 | % OUTPUTs: incidence matrix: N x number of edges 5 | % Other routines used: isdirected.m 6 | % GB, Last Updated: July 10, 2011 7 | 8 | function inc = adj2inc(adj) 9 | 10 | n=length(adj); % number of nodes 11 | 12 | inc=[]; % initialize incidence matrix 13 | 14 | if isdirected(adj) 15 | 16 | for i=1:n 17 | for j=1:n 18 | 19 | % handle selfloops 20 | if i==j; for x=1:adj(i,j); inc=[inc; zeros(1,length(1:i-1)), 1,zeros(1,length(i+1:n))]; end; continue; end 21 | 22 | for x=1:adj(i,j) % add multiple edges if any 23 | if i=vertices 21 | for node=1:vertices-1 22 | el = [el; node vertices 1]; 23 | el = [el; vertices node 1]; 24 | end 25 | continue 26 | end 27 | 28 | deg=[]; % compute nodal degrees for this iteration 29 | for v=1:vertices; deg=[deg; v numel(find(el(:,1)==v))]; end 30 | deg=sortrows(deg); 31 | 32 | % add m edges 33 | r = randsample(deg(:,1),m,'true',deg(:,2)/max(deg(:,2))); 34 | while not(length(unique(r))==length(r)) 35 | r = randsample(deg(:,1),m,'true',deg(:,2)/max(deg(:,2))); 36 | end 37 | 38 | for node=1:length(r) 39 | el = [el; r(node) vertices 1]; 40 | el = [el; vertices r(node) 1]; 41 | end 42 | 43 | end -------------------------------------------------------------------------------- /topology analysis/dijkstra.m: -------------------------------------------------------------------------------- 1 | % INPUTS: adj - adjacency matrix, s - source node, target - target node 2 | % OUTPUTS: distance, d and path, P (from s to target) 3 | % Note: if target==[], then dist and P include all distances and paths from s 4 | % Other routines used: adj2adjL.m, purge.m 5 | % GB, Last Updated: Dec 22, 2009 6 | 7 | function [dist,P]=dijkstra(adj,s,target) 8 | 9 | % initialize distances ========================== 10 | n=length(adj); % number of nodes 11 | adjL=adj2adjL(adj); % list of neighbors 12 | 13 | dist=inf(1,n); 14 | dist(s)=0; 15 | 16 | previous=[1:n; inf(1,n)]'; % {i: inf}, i=1:n, inf -> not assigned 17 | S=cell(1,n); % shortest path sequence 18 | 19 | 20 | Q=[1:n]; % all unvisited vertices, entire graph 21 | while length(Q)>0 % while not empty 22 | % get min dist member among unvisited vertices 23 | [mindist,min_ind]=min(dist(Q)); 24 | u=Q(min_ind); 25 | 26 | % termination condition - save source-u path 27 | S{u}=[]; 28 | t=u; 29 | while not(isempty(find(previous(:,1)==t))) % t in previous.keys(): 30 | % insert u at the beginning of S 31 | S{u}=[t S{u}]; 32 | t=previous(t,2); 33 | end 34 | if length(target)>0 & u==target 35 | dist=dist(u); P=S{u}; 36 | return 37 | end 38 | 39 | % ========================================= 40 | Q=purge(Q,u); % remove u from Q 41 | for v=1:length(adjL{u}) % across all neighbors of u 42 | v=adjL{u}(v); 43 | alt=dist(u)+adj(u,v); 44 | if alt < dist(v) 45 | dist(v)=alt; 46 | previous(v,2)=u; 47 | end 48 | end 49 | end 50 | 51 | P=S; -------------------------------------------------------------------------------- /topology analysis/find_conn_comp.m: -------------------------------------------------------------------------------- 1 | % Algorithm for finding connected components in a graph 2 | % Valid for undirected graphs only 3 | % INPUTS: adj - adjacency matrix 4 | % OUTPUTS: a list of the components comp{i}=[j1,j2,...jk} 5 | % Other routines used: find_conn_compI.m (embedded), degrees.m, kneighbors.m 6 | % GB, Last updated: October 2, 2009 7 | 8 | 9 | function comp_mat = find_conn_comp(adj) 10 | 11 | [deg,~,~]=degrees(adj); % degrees 12 | comp_mat={}; % initialize components matrix 13 | 14 | for i=1:length(deg) 15 | if deg(i)>0 16 | done=0; 17 | for x=1:length(comp_mat) 18 | if length(find(comp_mat{x}==i))>0 % i in comp_mat(x).mat 19 | done=1; 20 | break 21 | end 22 | end 23 | if not(done) 24 | comp=find_conn_compI(adj,i); 25 | comp_mat{length(comp_mat)+1}=comp; 26 | end 27 | 28 | elseif deg(i)==0 29 | comp_mat{length(comp_mat)+1}=[i]; 30 | end 31 | end 32 | 33 | 34 | function comp=find_conn_compI(adj,i) 35 | % heuristic for finding the conn component to which "i" belongs to 36 | % works well in practice for large datasets 37 | % INPUTS: adjacency matrix and index of the key node 38 | % OUTPUTS: all node indices of the nodes to which "i" belongs to 39 | 40 | neigh1=kneighbors(adj,i,1); 41 | neigh1=unique([neigh1 i]); % add i to its own component 42 | 43 | while 1 44 | len0=length(neigh1); 45 | for j=1:len0 46 | neigh2=kneighbors(adj,neigh1(j),1); 47 | neigh1=unique([neigh1, neigh2]); 48 | end 49 | if len0==length(neigh1) 50 | comp=neigh1; 51 | return 52 | end 53 | end -------------------------------------------------------------------------------- /topology analysis/kregular.m: -------------------------------------------------------------------------------- 1 | % Create a k-regular graph 2 | % INPUTs: n - # nodes, k - degree of each vertex 3 | % OUTPUTs: el - edge list of the k-regular undirected graph 4 | % GB, Last updated: January 12, 2011 5 | 6 | function eln = kregular(n,k) 7 | 8 | el={}; 9 | 10 | if k>n-1; fprintf('a simple graph with n nodes and k>n-1 does not exist\n'); return; end 11 | if mod(k,2)==1 & mod(n,2)==1; fprintf('no solution for this case\n'); return; end 12 | 13 | 14 | half_degree=floor(k/2); % k/2 if k even, else (k-1)/2 15 | 16 | 17 | for node=1:n 18 | for kk=1:half_degree 19 | 20 | node_f=mod(node+kk,n); 21 | if node_f==0; node_f=n; end 22 | edge_f=strcat(num2str(node),'+',num2str(node_f)); 23 | 24 | node_b=mod(node-kk,n); 25 | if node_b==0; node_b=n; end 26 | edge_b=strcat(num2str(node),'+',num2str(node_b)); 27 | 28 | if sum(ismember(el,edge_f))==0 29 | el{length(el)+1}=edge_f; 30 | end 31 | if sum(ismember(el,edge_b))==0 32 | el{length(el)+1}=edge_b; 33 | end 34 | 35 | end 36 | end 37 | 38 | if mod(k,2)==1 & mod(n,2)==0 39 | % connect mirror nodes 40 | for node=1:n/2 41 | 42 | node_m=mod(node+n/2,n); 43 | if node_m==0; node_m=n; end 44 | edge_m=strcat(num2str(node),'+',num2str(node_m)); 45 | 46 | if sum(ismember(el,edge_m))==0 47 | el{length(el)+1}=edge_m; 48 | end 49 | 50 | end 51 | end 52 | 53 | 54 | eln=[]; 55 | for edge=1:length(el) 56 | edge=el{edge}; 57 | plus=find(edge=='+'); 58 | eln=[eln; str2num(edge(1:plus-1)), str2num(edge(plus+1:length(edge))), 1]; 59 | end 60 | eln=symmetrize_edgeL(eln); -------------------------------------------------------------------------------- /topology analysis/el2geom.m: -------------------------------------------------------------------------------- 1 | % Plot geometry based on extended edgelist 2 | % INPUTS: extended edgelist el[i,:]=[n1 n2 m x1 y1 x2 y2] 3 | % OUTPUTS: geometry plot, higher-weight links are thicker and lighter 4 | % Note 1: m - edge weight; (x1,y1) are the Euclidean coordinates of n1, (x2,y2) - n2 resp. 5 | % Note 2: Easy to change colors and corresponding edge weight coloring 6 | % Example input: 7 | % [el,p] = newmangastner(1000,0.5); 8 | % elnew = []; 9 | % for e=1:size(el,1) 10 | % elnew = [elnew; el(e,1), el(e,2), randi(8), p(el(e,1),1), p(el(e,1),2), p(el(e,2),1), p(el(e,2),2)]; 11 | % end 12 | % el2geom(elnew) 13 | % GB, last updated: april 24, 2007 14 | 15 | function []=el2geom(el) 16 | 17 | set(gcf,'Color',[1 1 1]) 18 | map=colormap('hot'); 19 | 20 | for i=1:size(el,1) 21 | 22 | % plot line between two nodes 23 | x1=el(i,4); y1=el(i,5); 24 | x2=el(i,6); y2=el(i,7); 25 | 26 | % edge weights ============== 27 | if el(i,3)<2 28 | color=map(8,:); 29 | linew=1; 30 | elseif el(i,3)>=2 & el(i,3)<3 31 | color=map(2*8,:); 32 | linew=2; 33 | elseif el(i,3)>=3 & el(i,3)<4 34 | color=map(3*8,:); 35 | linew=3; 36 | elseif el(i,3)>=4 & el(i,3)<5 37 | color=map(4*8,:); 38 | linew=4; 39 | elseif el(i,3)>=5 & el(i,3)<6 40 | color=map(5*8,:); 41 | linew=5; 42 | elseif el(i,3)>=6 & el(i,3)<7 43 | color=map(6*8,:); 44 | linew=6; 45 | elseif el(i,3)>=7 & el(i,3)<8 46 | color=map(7*8,:); 47 | linew=7; 48 | elseif el(i,3)>=8 49 | color=map(8*8,:); 50 | linew=8; 51 | end 52 | line([x1 x2],[y1 y2],'LineWidth',linew,'Color',color) 53 | 54 | hold off; hold on; 55 | 56 | end 57 | axis equal -------------------------------------------------------------------------------- /topology analysis/pearson.m: -------------------------------------------------------------------------------- 1 | % Calculating the Pearson coefficient for a degree sequence 2 | % INPUTs: M - matrix, square 3 | % OUTPUTs: r - Pearson coefficient 4 | % Courtesy: Dr. Daniel Whitney, circa 2006 5 | 6 | function prs = pearson(M) 7 | 8 | %calculates pearson degree correlation of M 9 | [rows,colms]=size(M); 10 | won=ones(rows,1); 11 | k=won'*M; 12 | ksum=won'*k'; 13 | ksqsum=k*k'; 14 | xbar=ksqsum/ksum; 15 | num=(won'*M-won'*xbar)*M*(M*won-xbar*won); 16 | M*(M*won-xbar*won); 17 | kkk=(k'-xbar*won).*(k'.^.5); 18 | denom=kkk'*kkk; 19 | 20 | prs=num/denom; 21 | 22 | 23 | % ALTERNATIVE ===== BETTER-DOCUMENTED ==================================== 24 | 25 | % Calculating the Pearson coefficient for a degree sequence 26 | % INPUTs: M - matrix, square 27 | % OUTPUTs: r - Pearson coefficient 28 | % source: "Assortative Mixing in Network", M.E.J. Newman, PhysRevLet 2002 29 | % GB, March 15, 2006 30 | 31 | % function r = pearson(M) 32 | % 33 | % [degs,~,~] = degrees(M); % get the total degree sequence 34 | % m = numedges(M); % number of edges in M 35 | % inc = adj2inc(M); % get incidence matrix for convience 36 | % 37 | % % j,k - remaining degrees of adjacent nodes for a given edge 38 | % % sumjk - sum of all products jk 39 | % % sumjplusk - sum of all sums j+k 40 | % % sumj2plusk2 - sum of all sums of squares j^2+k^2 41 | % 42 | % % compute sumjk, sumjplusk, sumj2plusk2 43 | % sumjk = 0; sumjplusk = 0; sumj2plusk2 = 0; 44 | % for i=1:m 45 | % [v] = find(inc(:,i)==1); 46 | % j = degs(v(1))-1; k = degs(v(2))-1; % remaining degrees of 2 end-nodes 47 | % sumjk = sumjk + j*k; 48 | % sumjplusk = sumjplusk + 0.5*(j+k); 49 | % sumj2plusk2 = sumj2plusk2 + 0.5*(j^2+k^2); 50 | % end 51 | % 52 | % % Pearson coefficient formula 53 | % r = (sumjk - sumjplusk^2/m)/(sumj2plusk2-sumjplusk^2/m); -------------------------------------------------------------------------------- /topology analysis/fabrikant_model.m: -------------------------------------------------------------------------------- 1 | % Implements the Fabrikant model of internet growth 2 | % Source: Fabrikant et al, "Heuristically Optimized Trade-offs: A New Paradigm for Power Laws in the Internet" 3 | % Note: Assume the first point to be the center - easy to change by setting p(1,:) = [x0,y0] 4 | % INPUTS: n - number of points, parameter alpha, [0,inf), plt='on'/'off', if [], then 'off' is default 5 | % OUTPUTS: generated network (adjacency matrix) and plot [optional] 6 | % Other functions used: simple_dijkstra.m 7 | % GB, Last Updated: November 26, 2006 8 | 9 | 10 | function [adj,p]=fabrikant_model(n,alpha,plt) 11 | 12 | 13 | % create random point (polar) coordinates 14 | p = zeros(n-1,2); 15 | rad = rand(1,n-1); 16 | theta = 2*pi*rand(1,n-1); 17 | for i=1:n-1; p(i,:) = rad(i)*[cos(theta(i)),sin(theta(i))]; end 18 | p=[[0 0]; p]; % add zero 19 | 20 | h=zeros(n,1); % initialize centrality function 21 | adj=zeros(n); % initialize adjacency matrix 22 | 23 | 24 | for i=2:n % a new point arrives at each iteration 25 | 26 | % compute min weight across all existing points 27 | d=[]; 28 | for j=1:i-1; d=[d; alpha*norm(p(i,:)-p(j,:)) + h(j)]; end 29 | [~,indmin]=min(d); 30 | adj(i,indmin)=1; adj(indmin,i)=1; 31 | 32 | % compute centrality function for new point 33 | adjL = pdist2(p,p,'euclidean'); 34 | h = simple_dijkstra(adjL,1); 35 | 36 | end 37 | 38 | if nargin<=2 | not(strcmp(plt,'on')); return; end 39 | 40 | set(gcf,'color',[1,1,1]) 41 | for i=1:n 42 | axis off 43 | drawnow 44 | %plot(p(i,1),p(i,2),'.','Color',[0.5,0.5,0.5]); hold off; hold on; % plot the new point 45 | for j=i+1:n 46 | if adj(i,j)>0 47 | line([p(i,1) p(j,1)],[p(i,2) p(j,2)],'Color',[0.5,0.5,0.5]) 48 | hold off; hold on; 49 | end 50 | end 51 | end 52 | 53 | -------------------------------------------------------------------------------- /topology analysis/modularity_metric.m: -------------------------------------------------------------------------------- 1 | % Computing the modularity for a given module/commnunity break-down 2 | % Defined as: Q=sum_over_modules_i (eii-ai^2) (eq 5) in Newman and Girvan. 3 | % eij = fraction of edges that connect community i to community j, ai=sum_j (eij) 4 | % Source: Newman, M.E.J., Girvan, M., "Finding and evaluating community structure in networks" 5 | % Also: "Fast algorithm for detecting community structure in networks", Mark Newman 6 | % Inputs: adjacency matrix and set modules as cell array of vectors, ex: {[1,2,3],[4,5,6]} 7 | % Outputs: modularity metric, in [-1,1] 8 | % Other functions used: numedges.m 9 | % Last updated: June 13, 2011 10 | 11 | function Q=modularity_metric(modules,adj) 12 | 13 | nedges=numedges(adj); % total number of edges 14 | 15 | Q = 0; 16 | for m=1:length(modules) 17 | 18 | e_mm=numedges(adj(modules{m},modules{m}))/nedges; 19 | a_m=sum(sum(adj(modules{m},:)))/(2*nedges); 20 | Q = Q + (e_mm - a_m^2); 21 | 22 | end 23 | 24 | 25 | % $$$ % alternative: Q = sum_ij { 1/2m [Aij-kikj/2m]delta(ci,cj) } = 26 | % $$$ % = sum_ij Aij/2m delta(ci,cj) - sum_ij kikj/4m^2 delta(ci,cj) = 27 | % $$$ % = sum_modules e_mm - sum_modules (kikj/4m^2) = 28 | % $$$ % = sum_modules (e_mm - ((sum_i ki)/2m)^2) 29 | % $$$ 30 | % $$$ n = numnodes(adj); 31 | % $$$ m = numedges(adj); 32 | % $$$ 33 | % $$$ mod={}; 34 | % $$$ for mm=1:length(modules) 35 | % $$$ for ii=1:length(modules{mm}) 36 | % $$$ mod{modules{mm}(ii)}=modules{mm}; 37 | % $$$ end 38 | % $$$ end 39 | % $$$ 40 | % $$$ Q = 0; 41 | % $$$ 42 | % $$$ for i=1:n 43 | % $$$ for j=1:n 44 | % $$$ 45 | % $$$ if not(isequal(mod(i),mod(j))) 46 | % $$$ continue 47 | % $$$ end 48 | % $$$ 49 | % $$$ Q = Q + (adj(i,j) - sum(adj(i,:))*sum(adj(j,:))/(2*m))/(2*m); 50 | % $$$ 51 | % $$$ end 52 | % $$$ end -------------------------------------------------------------------------------- /topology analysis/rewire.m: -------------------------------------------------------------------------------- 1 | % Degree-preserving random rewiring 2 | % Note 1: Assume unweighted undirected graph 3 | % INPUTS: edgelist, el (mx3) and number of rewirings, k 4 | % OUTPUTS: rewired edgelist 5 | 6 | function el = rewire(el,k) 7 | 8 | rew=0; 9 | 10 | while rew0; continue; end % the two edges cannot overlap 17 | 18 | % else: rewire 19 | if not(ismember([edge1(1),edge2(2),1],el,'rows')) & not(ismember([edge1(2),edge2(1),1],el,'rows')) 20 | 21 | % first possibility: (e11,e22) & (e12,e21) 22 | el(ind(1),:)=[edge1(1),edge2(2),1]; 23 | el(ind(2),:)=[edge1(2),edge2(1),1]; 24 | 25 | % add the symmetric equivalents 26 | [~,inds1] = ismember([edge1(2),edge1(1),1],el,'rows'); 27 | el(inds1,:)=[edge2(2),edge1(1),1]; 28 | 29 | [~,inds2] = ismember([edge2(2),edge2(1),1],el,'rows'); 30 | el(inds2,:)=[edge2(1),edge1(2),1]; 31 | 32 | rew = rew + 1; 33 | 34 | elseif not(ismember([edge1(1),edge2(1),1],el,'rows')) & not(ismember([edge1(2),edge2(2),1],el,'rows')) 35 | 36 | % second possibility: (e11,e21) & (e12,e22) 37 | el(ind(1),:)=[edge1(1),edge2(1),1]; 38 | el(ind(2),:)=[edge1(2),edge2(2),1]; 39 | 40 | % add the symmetric equivalents 41 | [~,inds1] = ismember([edge1(2),edge1(1),1],el,'rows'); 42 | el(inds1,:)=[edge2(1),edge1(1),1]; 43 | 44 | [~,inds2] = ismember([edge2(2),edge2(1),1],el,'rows'); 45 | el(inds2,:)=[edge2(2),edge1(2),1]; 46 | 47 | rew = rew + 1; 48 | 49 | else 50 | 'creates a double edge'; 51 | continue 52 | end 53 | 54 | end -------------------------------------------------------------------------------- /topology analysis/newmangastner.m: -------------------------------------------------------------------------------- 1 | % Implements the Newman-Gastner model for spatially distributed networks 2 | % Source: Newman, Gastner, "Shape and efficiency in spatial distribution networks" 3 | % Note 1: minimize: wij = dij + beta x (dj0) 4 | % Note 2: easy to change to input point coordinates, instead of generate randomly 5 | % Inputs: n - number of points/nodes, beta - parameter [0,1], plt - 'on'/'off' 6 | % Outputs: graph (edgelist), point coordinates and plot [optional] 7 | % GB, Last Updated: May 23, 2007 8 | 9 | function [el,points]=newmangastner(n,beta,plt) 10 | 11 | % create random point coordinates 12 | points = zeros(n-1,2); 13 | rad = rand(1,n-1); 14 | theta = 2*pi*rand(1,n-1); 15 | for i=1:n-1; points(i,:) = rad(i)*[cos(theta(i)),sin(theta(i))]; end 16 | points=[[0 0]; points]; % add zero 17 | 18 | % order points in closeness to 0 19 | for i=1:n; normp(i)=norm(points(i,:)); end 20 | [normps,ind]=sort(normp); 21 | points=points(ind,:); 22 | 23 | % calculate distances between all points (can also use pdist) 24 | L=zeros(n); 25 | for i=1:n 26 | for j=i+1:n 27 | L(i,j)=norm(points(i,:)-points(j,:)); 28 | L(j,i)=L(i,j); 29 | end 30 | L(i,i)=Inf; 31 | end 32 | 33 | if nargin>2 & strcmp(plt,'on') % if plot is 'on' 34 | set(gcf,'Color',[1 1 1]) 35 | plot(points(:,1),points(:,2),'.','Color',[1,1,1]) 36 | hold off; hold on; 37 | axis off 38 | end 39 | 40 | % connect points consequtively 41 | el=[]; 42 | for i=2:n 43 | % current node is "i" 44 | w=L(i,1:i-1)+beta*normps(1:i-1); 45 | [minv,minj]=min(w); 46 | el=[el; i minj 1]; 47 | 48 | if nargin>2 & strcmp(plt,'on') % if plot is 'on' 49 | line([points(i,1) points(minj,1)],[points(i,2) points(minj,2)],'Color',[0.5,0.5,0.5]) 50 | hold off; hold on; 51 | drawnow 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /topology analysis/tarjan.m: -------------------------------------------------------------------------------- 1 | % Find the giant stronly connected component in a directed graph 2 | % Source: Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160 3 | % Input: graph, set of nodes and edges, in adjacency list format, ex: L{1}=[2], L{2]=[1] is the 1-2 edge 4 | % Outputs: set of strongly connected components, in cell array format 5 | % Other routines used: strongConnComp (embedded) 6 | % Last updated: July 6, 2011, GB 7 | 8 | function [GSCC,v] = tarjan(L) 9 | 10 | 11 | GSCC = {}; 12 | ind = 1; % node number counter 13 | S = []; % An empty stack of nodes 14 | for ll=1:length(L); v(ll).index = []; v(ll).lowlink = []; end % initialize indices 15 | 16 | for vi=1:length(L) 17 | if isempty(v(vi).index) 18 | [GSCC,S,ind,v]=strongConnComp(vi,S,ind,v,L,GSCC); % visit new nodes only 19 | end 20 | end 21 | 22 | 23 | function [GSCC,S,ind,v]=strongConnComp(vi,S,ind,v,L,GSCC) 24 | 25 | v(vi).index = ind; % Set the depth index for vi 26 | v(vi).lowlink = ind; 27 | ind = ind + 1; 28 | 29 | S = [vi S]; % Push vi on the stack 30 | 31 | for ll=1:length(L{vi}) 32 | vj = L{vi}(ll); % Consider successors of vi 33 | 34 | if isempty(v(vj).index) % Was successor vj visited? 35 | 36 | [GSCC,S,ind,v]=strongConnComp(vj,S,ind,v,L,GSCC); % Recursion 37 | v(vi).lowlink = min([v(vi).lowlink, v(vj).lowlink]); 38 | 39 | elseif not(isempty(find(S==vj))) % Is vj on the stack? 40 | v(vi).lowlink = min([v(vi).lowlink, v(vj).index]); 41 | 42 | end 43 | end 44 | 45 | 46 | if v(vi).lowlink == v(vi).index % Is v the root of an SCC? 47 | 48 | SCC = [vi]; 49 | while 1 50 | vj = S(1); S = S(2:length(S)); 51 | SCC = [SCC vj]; 52 | 53 | if vj==vi; SCC = unique(SCC); break; end 54 | end 55 | 56 | GSCC{length(GSCC)+1} = SCC; 57 | 58 | end -------------------------------------------------------------------------------- /topology analysis/isconnected.m: -------------------------------------------------------------------------------- 1 | % Determine if a graph is connected 2 | % INPUTS: adjacency matrix 3 | % OUTPUTS: Boolean variable {0,1} 4 | % Note: this only works for undirected graphs 5 | % Idea by Ed Scheinerman, circa 2006, source: http://www.ams.jhu.edu/~ers/matgraph/ 6 | % routine: matgraph/@graph/isconnected.m 7 | 8 | function S = isconnected(adj) 9 | 10 | if not(isempty(find(sum(adj)==0))); S = false; return; end 11 | 12 | n = length(adj); 13 | x = [1; zeros(n-1,1)]; % [1,0,...0] nx1 vector 14 | 15 | while 1 16 | y = x; 17 | x = adj*x + x; 18 | x = x>0; 19 | 20 | if x==y; break; end 21 | 22 | end 23 | 24 | S = true; 25 | if sum(x) 0 then the graph is connected 30 | % a=algebraic_connectivity(adj); 31 | % S = false; if a>0; S = true; end 32 | 33 | % Alternative 1 ========================================================== 34 | % Uses the fact that multiplying the adj matrix to itself k times give the 35 | % number of ways to get from i to j in k steps. If the end of the 36 | % multiplication in the sum of all matrices there are 0 entries then the 37 | % graph is disconnected. Computationally intensive, but can be sped up by 38 | % the fact that in practice the diameter is very short compared to n, so it 39 | % will terminate in order of 5 steps. 40 | % function S=isconnected(el): 41 | % 42 | % S=false; 43 | % 44 | % adj=edgeL2adj(el); 45 | % n=numnodes(adj); % number of nodes 46 | % adjn=zeros(n); 47 | % 48 | % adji=adj; 49 | % for i=1:n 50 | % adjn=adjn+adji; 51 | % adji=adji*adj; 52 | % 53 | % if length(find(adjn==0))==0 54 | % S=true; 55 | % return 56 | % end 57 | % end 58 | 59 | % Alternative 2 ========================================================== 60 | % Find all connected components, if their number is 1, the graph is 61 | % connected. Use find_conn_comp(adj). -------------------------------------------------------------------------------- /topology analysis/forestFireModel.m: -------------------------------------------------------------------------------- 1 | % Implementation of the forest fire model by Leskovec et al 2 | % Source: Graphs over Time: Densification Laws, Shrinking Diameters and Possible Explanations 3 | % Inputs: forward burning probability p in [0,1], 4 | % backward burning ratio r, in [1,inf), 5 | % T - number of nodes 6 | % Outputs: adjacency list of the constructed (directed) graph 7 | % Note 1: mean = 1/(1-p) => 1/(N*(1-p))<=1 <=> 1/(1-p)<=N <=> 1-p>=1/N <=> p<=1-1/N 8 | % Note 2: r is the ratio between outlinks and inlinks selected at every "back burn" step 9 | % Last updated: May 10, 2011 10 | 11 | 12 | function L = forestFireModel(T,p,r) 13 | 14 | if T==1 15 | L{1} = []; % a single node, no edges 16 | return 17 | elseif T>=2 18 | L{1} = [2]; L{2} = [1]; % two nodes, a single edge 19 | end 20 | 21 | 22 | for t=3:T 23 | 24 | L{t} = []; % new node arrives 25 | w = randi(t-1); % pick a node from 1->t-1 uniformly at random 26 | queue=[w]; visited = []; 27 | 28 | while not(isempty(queue)) 29 | 30 | w = queue(1); visited = [visited w]; 31 | 32 | outlinks = L{w}; inlinks = []; 33 | for ll=1:length(L) 34 | if sum(find(L{ll}==w))>0; inlinks = [inlinks ll]; end 35 | end 36 | 37 | L{t} = [L{t} w]; % connect t to w 38 | 39 | % generate a number from a binomial distribution with mean (1-p)^(-1) => binornd(N,1/(N(1-p))) 40 | N = length(unique([outlinks inlinks])); 41 | if 1/(N*(1-p))>1; x=N; end; 42 | if 1/(N*(1-p))<=1; x = binornd(N,1/(N*(1-p)),1,1); end 43 | 44 | NN = [inlinks outlinks]; 45 | w = [ones(size(inlinks)) ones(size(outlinks))*r]; 46 | w = w/sum(w); 47 | 48 | inds = randsample(length(NN),x,true,w); 49 | ws = unique(NN(inds)); 50 | 51 | L{t} = unique([L{t} ws]); % add as outlinks to new node 52 | 53 | for ii=1:length(ws) 54 | if sum(find(visited==ws(ii)))==0; queue = [queue ws(ii)]; end 55 | end 56 | queue = queue(2:length(queue)); % remove w from queue 57 | end 58 | 59 | end 60 | 61 | 62 | for ll=1:length(L); L{ll} = setdiff(L{ll},ll); end % remove self-loops -------------------------------------------------------------------------------- /topology analysis/DoddsWattsSabel.m: -------------------------------------------------------------------------------- 1 | % Add random cross-links on top of a perfect hierarchy 2 | % Non-backbone edges are added with probability P(i,j)=e^(-Dij/lambda)*e^(-xij/ksi), 3 | % where Dij is the level of the lowest common ancestor and xij is the "organizational" distance 4 | % Source: Dodds, Watts, Sabel, "Information exchange and the robustness of organizational networks", PNAS 100 (21): 12516-12521 5 | % INPUTs: number of nodes (N), tree branch factor (b), m - number of additional edges to add, parameters lambda (lam) and ksi in [0,inf) 6 | % OUTPUTs: adjacency matrix of randomized hierarchy, NxN 7 | % Other routines used: edgeL2adj.m, canonical_nets.m, dijkstra.m 8 | 9 | function adj = DoddsWattsSabel(N,b,m,lam,ksi) 10 | 11 | % construct a tree with N nodes and branch factor b 12 | adj0=edgeL2adj( canonical_nets(N,'tree',b) ); % backbone adjacency matrix 13 | 14 | adj=adj0; 15 | edges=0; 16 | 17 | while edges0 | adj(ind2,ind1)>0; continue; end 23 | 24 | % find di,dj and Dij 25 | [d1,path1]=dijkstra(adj0,ind1,1); % adjacency, source, target 26 | [d2,path2]=dijkstra(adj0,ind2,1); 27 | 28 | for p=1:length(path1) 29 | p1=path1(p); 30 | p2=find(path2==p1); 31 | if length(p2)>0 % if p1 in path2 32 | 33 | di=p-1; dj=p2-1; % di+dj is the the distance from ind1 34 | % to ind2 along the backbone hierarchy 35 | Dij=length(path1(p:length(path1)))-1; % the level of the 36 | % highest common 37 | % node on the path 38 | % to the root 39 | break 40 | end 41 | end 42 | xij=sqrt(di^2+dj^2-2); 43 | 44 | % connect ind1 and ind2 with prob. e^(-Dij/lam)e^(-xij/ksi)) 45 | if rand2 & nargin < 5 % 2D only, z is unspecified, put everything in one plane. 33 | for i=1:n 34 | fprintf(fid,' %3i %s %1.4f %1.4f %1.4f\n',i,strcat('"v',num2str(i),'"'),x(i),y(i),0); 35 | end 36 | else % 3D coords 37 | for i=1:n 38 | fprintf(fid,' %3i %s %1.4f %1.4f %1.4f\n',i,strcat('"v',num2str(i),'"'),x(i),y(i),z(i)); 39 | end 40 | end 41 | 42 | if issymmetric(adj); fprintf(fid,'*Edges\n'); end % undirected graph version 43 | if not(issymmetric(adj)); fprintf(fid,'*Arcs\n'); end % directed graph version 44 | 45 | edges=find(adj>0); 46 | for e=1:length(edges) 47 | [i,j]=ind2sub([n,n],edges(e)); 48 | fprintf(fid,' %4i %4i %2i\n',i,j,adj(i,j)); 49 | end 50 | 51 | fclose(fid); -------------------------------------------------------------------------------- /topology analysis/newmangirvan.m: -------------------------------------------------------------------------------- 1 | % Newman-Girvan community finding algorithm 2 | % source: Newman, M.E.J., Girvan, M., "Finding and evaluating community structure in networks" 3 | % Algorithm idea: 4 | % 1. Calculate betweenness scores for all edges in the network. 5 | % 2. Find the edge with the highest score and remove it from the network. 6 | % 3. Recalculate betweenness for all remaining edges. 7 | % 4. Repeat from step 2. 8 | % INPUTs: adjacency matrix (adj), number of modules (k) 9 | % OUTPUTs: modules (components) and modules history - each "current" module, Q - modularity metric 10 | % Other routines used: edge_betweenness.m, subgraph.m, numedges.m 11 | % GB, April 17, 2006, computing modularity, added April 28, 2011 12 | 13 | function [modules,module_hist,Q] = newmangirvan(adj,k) 14 | 15 | n=size(adj,1); 16 | module_hist{1} = [1:n]; % current component 17 | modules{1}=[1:n]; 18 | 19 | curr_mod=1; 20 | 21 | adj_temp=adj; 22 | 23 | 24 | while length(modules)1) 37 | G.var(i).oldoutgoing=G.var(i).outgoing; 38 | for j=1:length(G.var(i).incoming) 39 | curr = G.var(i).incoming; 40 | curr(j)=[]; 41 | newmessage=1; 42 | for m = 1:length(curr) 43 | newmessage = newmessage .* curr{m}; 44 | end 45 | G.var(i).outgoing{j}=newmessage/sum(newmessage); 46 | end 47 | end 48 | end 49 | for i=1:length(G.var) 50 | for j=1:length(G.var(i).outgoing) 51 | facidx=G.var(i).nbrs_fac(j); 52 | G.fac(facidx).incoming{G.fac(facidx).nbrs_var==i}=G.var(i).outgoing{j}; 53 | end 54 | end 55 | delta=[]; 56 | for i=1:length(G.var) 57 | for j=1:length(G.var(i).oldoutgoing) 58 | delta=[delta sum(abs(G.var(i).oldoutgoing{j}-G.var(i).outgoing{j}))]; 59 | end 60 | end 61 | for i=1:length(G.fac) 62 | for j=1:length(G.fac(i).oldoutgoing) 63 | delta=[delta sum(abs(G.fac(i).oldoutgoing{j}-G.fac(i).outgoing{j}))]; 64 | end 65 | end 66 | if(ifvis) 67 | node_marg = [node_marg get_beliefs(G)]; 68 | end 69 | if(all(delta0 % while there is always a divisible subgraph 27 | 28 | % compute modularity matrix- Bg 29 | G=queue{1}; % nodes in current (sub)graph to partition 30 | adjG=subgraph(adj,G); % first adjG same as original adj 31 | 32 | [degG,~,~]=degrees(adjG); 33 | Bg=zeros(length(G)); 34 | 35 | for i=1:length(G) % nodes are G(i) 36 | for j=i:length(G) % nodes are G(j) 37 | 38 | % Bij = adj(G(i),G(j))-deg(G(i))*deg(G(j))/(2*m) 39 | % delta_ij = (i==j) 40 | % k_i^g - k_i (d_g)/2m = degG(i)-deg(G(i))*sum(degG)/(2*m) 41 | Bg(i,j)=( adj(G(i),G(j))-deg(G(i))*deg(G(j))/(2*m) )-(i==j)*(degG(i)-deg(G(i))*sum(degG)/(2*m)); 42 | Bg(j,i)=Bg(i,j); 43 | 44 | end 45 | end 46 | 47 | [V,E]=eig(Bg); % eigenvalues 48 | 49 | if abs(max(diag(E)))<=10^(-5) % terminate - indivisible 50 | queue=queue(2:length(queue)); 51 | modules=[modules G]; 52 | continue 53 | end 54 | 55 | [~,indmax]=max(diag(E)); 56 | u1=V(:,indmax); 57 | comm1=find(u1>0); comm2=find(u1<0); % indices in G 58 | 59 | if not(isconnected(adj(G(comm1),G(comm1)))) | not(isconnected(adj(G(comm2),G(comm2)))) 60 | 61 | queue=queue(2:length(queue)); % remove(G) 62 | modules=[modules G]; % keep original G as indivisible 63 | %'found disconnected subgraphs - do not explore this option' 64 | 65 | continue 66 | 67 | end 68 | 69 | queue=[queue G(comm1) G(comm2)]; 70 | queue=queue(2:length(queue)); 71 | 72 | end -------------------------------------------------------------------------------- /topology analysis/louvain_community_finding.m: -------------------------------------------------------------------------------- 1 | % Implementation of a community finding algorithm by Blondel et al 2 | % Source: "Fast unfolding of communities in large networks", July 2008 3 | % https://sites.google.com/site/findcommunities/ 4 | % Note: This is just the first step of the Louvain community 5 | % finding algorithm, to extract fewer communities, need to repeat with the resulting modules themselves 6 | % INPUTs: adjancency matrix, nxn 7 | % OUTPUTs: modules, and node community labels 8 | % Other routines used: numedges.m, kneighbors.m, purge.m 9 | 10 | function [modules,inmodule] = louvain_community_finding(adj) 11 | 12 | m = numedges(adj); 13 | 14 | inmodule = {}; % inmodule{node} = module 15 | for mm=1:length(adj); inmodule{mm} = mm; end; 16 | 17 | modules = inmodule; % equal only for this step; modules{ind} = [nodes in module] 18 | 19 | % for all nodes, visit and assess joining to their neighbors 20 | % revisit until no improvement in dQ is available 21 | 22 | converged = false; 23 | 24 | while not(converged) 25 | 26 | converged = true; 27 | 28 | for i=1:length(adj) 29 | 30 | neigh = kneighbors(adj,i,1); 31 | dQ = zeros(1,length(neigh)); 32 | 33 | for nei=1:length(neigh) 34 | % attempt to join i and neigh(nei) 35 | % that is: move i from modules{i} to modules{neigh(nei)} 36 | % 2 dQs: modules{i} minus i & modules{neigh(nei)} plus i 37 | % if dQs balance is positive, do move; else: move on 38 | 39 | % sum_in = sum of weights of links inside C 40 | % sum_tot = sum of weights of links incident to nodes in C 41 | % ki = sum of weights of links incident to node i 42 | % ki_in = sum of weights of links from i to nodes in C 43 | % m = sum of weights of all links in the network 44 | 45 | if inmodule{i}==inmodule{neigh(nei)}; dQ(nei)=0; continue; end 46 | 47 | % removing i from modules{i}, expect dQ1 to be smaller than dQ2 48 | C = inmodule{neigh(nei)}; 49 | sum_in = sum(sum(adj(modules{C},modules{C})))/2; 50 | sum_tot = sum(sum(adj(modules{C},:))); % /2 ???? -sum_in 51 | ki = sum(adj(i,:)); 52 | ki_in = sum(sum(adj(i,modules{C}))); 53 | 54 | dQ1 = ((sum_in+ki_in)/(2*m)-(sum_tot+ki)^2/(4*m^2)) - (sum_in/(2*m)-sum_tot^2/(4*m^2)-ki^2/(4*m^2)); 55 | 56 | % adding i to modules{neigh(nei)}, this is hopefully a modularity gain 57 | C = inmodule{i}; 58 | sum_in = sum(sum(adj(modules{C},modules{C})))/2; 59 | sum_tot = sum(sum(adj(modules{C},:))); % /2 ???? -sum_in 60 | ki = sum(adj(i,:)); 61 | ki_in = sum(sum(adj(i,modules{C}))); 62 | 63 | dQ2 = ((sum_in+ki_in)/(2*m)-(sum_tot+ki)^2/(4*m^2)) - (sum_in/(2*m)-sum_tot^2/(4*m^2)-ki^2/(4*m^2)); 64 | dQ2 = - dQ2; 65 | 66 | dQ(nei) = dQ1+dQ2; 67 | end 68 | 69 | [maxv,maxnei]=min(dQ); % maximizing dQ2-dQ1 70 | 71 | if maxv>0 72 | 73 | modules{inmodule{i}} = purge(modules{inmodule{i}},i); 74 | inmodule{i}=inmodule{neigh(maxnei)}; 75 | modules{inmodule{neigh(maxnei)}} = [modules{inmodule{neigh(maxnei)}} i]; 76 | 77 | converged = false; 78 | end 79 | 80 | end 81 | 82 | end 83 | 84 | % remove empty modules 85 | new_modules={}; 86 | for mm=1:length(modules) 87 | if length(modules{mm})>0; new_modules{length(new_modules)+1}=modules{mm}; end 88 | end 89 | 90 | modules=new_modules; 91 | 92 | fprintf('found %3i modules\n',length(modules)) -------------------------------------------------------------------------------- /src/testvis.m: -------------------------------------------------------------------------------- 1 | clear; 2 | max_iters = 500; conv_tol = 1e-6; total_iters = 500; 3 | min_dim = 2; max_dim = 5; 4 | range_dim = max_dim-min_dim; 5 | n = 10; 6 | nodeMarg_undirected = {}; 7 | nodeMarg_directed = {}; 8 | G_undirected_obj = {}; 9 | G_directed_obj ={}; 10 | for i=1:length(n) 11 | facG_root_undirected.var=[]; 12 | facG_root_undirected.fac=[]; 13 | facG_root_directed.var=[]; 14 | facG_root_directed.fac=[]; 15 | while(length(facG_root_undirected.var)~=n) 16 | p = rand(1,1); 17 | G_undirected=random_graph(n,p); 18 | facG_root_undirected = adjG2facG(G_undirected,min_dim,max_dim); 19 | end 20 | while(length(facG_root_directed.var)~=n) 21 | p = rand(1,1); 22 | G_directed=random_directed_graph(n,p); 23 | facG_root_directed = adjG2facG(G_directed,min_dim,max_dim); 24 | end 25 | G_undirected_obj = [G_undirected_obj G_undirected]; 26 | G_directed_obj = [G_directed_obj G_directed]; 27 | facG_undirected=initialize(facG_root_undirected,1); 28 | facG_directed=initialize(facG_root_directed,1); 29 | [facG_undirected, iters_undirected, nodeMarg_par_undirected] = run_loopy_bp_parallel(facG_undirected, max_iters, conv_tol, true); 30 | [facG_directed, iters_directed, nodeMarg_par_directed] = run_loopy_bp_parallel(facG_directed, max_iters, conv_tol, true); 31 | if(~(iters_undirected0; continue; end % do not allow self-loops or double edges 39 | adj(i,j)=adj(i,j)+1; adj(j,i)=adj(i,j); 40 | end 41 | 42 | otherwise % pick from a distribution; generate *n* random numbers from a distribution 43 | Nseq=1; % ensure the while loops start 44 | switch distribution 45 | case 'uniform' 46 | while not(isgraphic(Nseq)) % make sure Nseq is a graphic sequence 47 | Nseq = randi(n-1,1,n); 48 | end 49 | case 'normal' 50 | while not(isgraphic(Nseq)) % make sure Nseq is a graphic sequence 51 | Nseq = ceil((n-1)/10*randn(1,n)+(n-1)/2); 52 | end 53 | case 'binomial' 54 | p=0.5; % default parameter for binomial distribution 55 | while not(isgraphic(Nseq)) % make sure Nseq is a graphic sequence 56 | Nseq = ceil(binornd(n-1,p,1,n)); 57 | end 58 | case 'exponential' 59 | while not(isgraphic(Nseq)) % make sure Nseq is a graphic sequence 60 | Nseq = ceil(exprnd((n-1)/4,1,n)); 61 | end 62 | 63 | case 'sequence' 64 | if nargin<5; fprintf('for distribution="sequence", need to specify a custom degree sequence\n'); return; end 65 | if not(isgraphic(degrees)); fprintf('degrees is not a graphic sequence - select a different sequence\n'); return; end 66 | Nseq = degrees; 67 | end 68 | 69 | % connect stubs at random 70 | stubs=Nseq; 71 | 72 | old_sum = 0; 73 | cnt=0; 74 | 75 | while sum(stubs)>0 % while no more stubs are left to connect 76 | 77 | new_sum = sum(stubs); 78 | if old_sum==new_sum; cnt = cnt+1; end 79 | if old_sum~=new_sum; cnt=0; end 80 | if cnt>100; stubs = Nseq; adj=zeros(length(Nseq)); cnt=0; end 81 | old_sum = sum(stubs); 82 | 83 | [~,n1] = max(stubs); 84 | 85 | ind = find(stubs>0); 86 | n2 = ind(randi(length(ind))); 87 | 88 | if n1==n2; continue; end 89 | 90 | if adj(n1,n2)>0; continue; end 91 | adj(n1,n2)=1; adj(n2,n1)=1; 92 | stubs(n1) = stubs(n1) - 1; 93 | stubs(n2) = stubs(n2) - 1; 94 | 95 | end 96 | 97 | end % end nargin options -------------------------------------------------------------------------------- /topology analysis/radial_plot.m: -------------------------------------------------------------------------------- 1 | % Plots nodes radially out from a given center. Equidistant nodes 2 | % have the same radius, but different angles. Works best as a quick 3 | % visualization for trees, or very sparse graphs. 4 | % Note 1: No spring-energy method implemented. 5 | % Note 2: If a center node is not specified, the nodes are ordered by 6 | % sum of neighbor degrees, and the node with highest sum is plotted 7 | % in the center. 8 | % Note 3: The graph has to be connected. 9 | % Note 4: To change the color scheme, modify lines: 84, 90, 96 and 110 10 | % Inputs: adjacency matrix, and center node (optional) 11 | % Outputs: plot 12 | % Other routines used: sort_nodes_by_sum_neighbor_degrees.m, 13 | % adj2adjL.m, diameter.m, kmin_neighbors.m 14 | % Last updated: May 19, 2011, GB 15 | 16 | function [] = radial_plot(adj,i0) 17 | 18 | d=diameter(adj); 19 | if d==Inf; fprintf('this graph is not connected, choose a connected graph\n'); return; end 20 | 21 | if nargin==1; I=sort_nodes_by_sum_neighbor_degrees(adj); i0=I(1); end; 22 | 23 | L=adj2adjL(adj); 24 | 25 | circles={}; % per circle 26 | circle{i0}=0; % per node 27 | 28 | for k=1:d 29 | kneigh = kmin_neighbors(adj,i0,k); 30 | if not(isempty(kneigh)); 31 | circles{k}=kneigh; 32 | for nei=1:length(kneigh); circle{kneigh(nei)}=k; end 33 | end; 34 | end 35 | 36 | for i=1:size(adj,1); descendants{i} = 0; end; 37 | 38 | for k=length(circles)-1:-1:1 39 | 40 | for i=1:length(circles{k}) 41 | node = circles{k}(i); 42 | neighs=L{node}; 43 | 44 | for nei=1:length(L{node}) 45 | nei = L{node}(nei); 46 | if sum(find(circles{k+1}==nei))>0; descendants{node}=descendants{node}+descendants{nei}+1; end 47 | end 48 | end 49 | 50 | end 51 | 52 | descendants{i0}=descendants{i0} + length(L{i0}); 53 | for i=1:length(L{i0}); descendants{i0}=descendants{i0} + descendants{L{i0}(i)}; end; 54 | 55 | start_angle{i0}=0; 56 | range{i0}=2*pi; 57 | 58 | queue=[i0]; visited=[]; 59 | 60 | while not(isempty(queue)) 61 | 62 | node=queue(1); queue=queue(2:length(queue)); visited=[visited node]; 63 | 64 | % select neighbours that have not been visited 65 | neigh=[]; 66 | for ll=1:length(L{node}) 67 | if sum(find(visited==L{node}(ll)))==0 & sum(find(queue==L{node}(ll)))==0; neigh=[neigh L{node}(ll)]; end; 68 | end 69 | 70 | if isempty(neigh); continue; end; 71 | 72 | range{neigh(1)} = range{node}*(descendants{neigh(1)}+1)/descendants{node}; 73 | start_angle{neigh(1)}=start_angle{node}; 74 | if sum(find(queue==neigh(1)))==0; queue=[queue neigh(1)]; end; 75 | 76 | for j=2:length(neigh) 77 | range{neigh(j)} = range{node}*(descendants{neigh(j)}+1)/descendants{node}; 78 | start_angle{neigh(j)} = start_angle{neigh(j-1)} + range{neigh(j-1)}; 79 | if sum(find(queue==neigh(j)))==0; queue=[queue neigh(j)]; end; 80 | end 81 | 82 | end 83 | 84 | set(gcf,'Color',[1 1 1],'Colormap',hot); 85 | map=colormap('hot'); 86 | 87 | % plot with the angle and radius (circle) information 88 | for i=1:size(adj,1) 89 | x = circle{i}*cos(start_angle{i}+range{i}/2); 90 | y = circle{i}*sin(start_angle{i}+range{i}/2); 91 | plot(x,y,'.','Color',map(mod(5*circle{i},length(map))+1,:)); hold off; hold on; 92 | end 93 | 94 | xs = cos([0:1:30]*2*pi/30); 95 | ys = sin([0:1:30]*2*pi/30); 96 | for c=1:length(circles) 97 | plot(c*xs,c*ys,':','Color',[244/255,244/255,244/255]); 98 | hold off; hold on; 99 | end 100 | 101 | % add the links between nodes 102 | for i=1:size(adj,1) 103 | for j=i+1:size(adj,1) 104 | if adj(i,j)>0 105 | xi=circle{i}*cos(start_angle{i}+range{i}/2); 106 | yi=circle{i}*sin(start_angle{i}+range{i}/2); 107 | 108 | xj=circle{j}*cos(start_angle{j}+range{j}/2); 109 | yj=circle{j}*sin(start_angle{j}+range{j}/2); 110 | 111 | line([xi xj],[yi yj],'Color',map(mod(5*circle{i},length(map))+1,:)) 112 | end 113 | end 114 | end 115 | 116 | axis tight 117 | axis off 118 | -------------------------------------------------------------------------------- /topology analysis/newman_comm_fast.m: -------------------------------------------------------------------------------- 1 | % Newman fast community finding algorithm 2 | % Source: "Fast algorithm for detecting community structure in networks", Mark Newman 3 | % Input: adjacency matrix 4 | % Output: group (cluster) formation over time, modularity metric for each cluster breakdown 5 | % Other functions used: numedges.m 6 | % Originally: June 6, 2007, GB, last modified May 4, 2011 7 | 8 | 9 | function [groups_hist,Q]=newman_comm_fast(adj) 10 | 11 | 12 | groups={}; 13 | groups_hist={}; 14 | Q=[]; 15 | n=size(adj,1); % number of vertices 16 | groups_hist{1}={}; 17 | 18 | for i=1:n 19 | groups{i}=i; % each node starts out as one community 20 | groups_hist{1}{i}=i; 21 | end 22 | 23 | Q(1) = Qfn(groups,adj); 24 | 25 | for s=1:n-1 % all possible iterations 26 | 27 | % print all groups 28 | %fprintf('modules at iteration: %4i\n',s); 29 | %for ss=1:length(groups) 30 | % fprintf('%3i',groups{ss}) 31 | % fprintf('\n') 32 | %end 33 | 34 | dQ=zeros(length(groups)); 35 | 36 | for i=1:length(groups) 37 | for j=i+1:length(groups) 38 | group_i=groups{i}; 39 | group_j=groups{j}; 40 | 41 | dQ(i,j)=0; % default 42 | 43 | % check if connected 44 | connected=0; 45 | if sum(sum(adj([group_i group_j],[group_i group_j])))>sum(sum(adj(group_i,group_i)))+sum(sum(adj(group_j,group_j))) 46 | connected=1; 47 | end 48 | 49 | if connected & not(isempty(group_i)) & not(isempty(group_j)) 50 | % join groups i and j? 51 | dQ(i,j)=deltaQ(groups,adj,i,j); 52 | end 53 | 54 | end 55 | end 56 | 57 | 58 | % pick max nonzero dQ 59 | dQ(find(dQ==0))=-Inf; 60 | [minv,minij]=max(dQ(:)); 61 | 62 | [mini,minj]=ind2sub([size(dQ,1),size(dQ,1)],minij); % i and j corresponding to min dQ 63 | groups{mini}=sort([groups{mini} groups{minj}]); 64 | groups{minj}=groups{length(groups)}; % swap minj with last group 65 | groups=groups(1:length(groups)-1); 66 | 67 | groups_hist{length(groups_hist)+1}=groups; % save current snapshot 68 | Q(length(Q)+1) = Qfn(groups,adj); 69 | 70 | end % end of all iterations 71 | 72 | num_modules=[]; 73 | for g=1:length(groups_hist) 74 | num_modules=[num_modules length(groups_hist{g})]; 75 | end 76 | 77 | set(gcf,'Color',[1 1 1],'Colormap',jet); 78 | plot(num_modules,Q,'ko-') 79 | xlabel('number of modules / communities') 80 | ylabel('modularity metric, Q') 81 | 82 | 83 | function dQ=deltaQ(groups,adj,i,j) 84 | 85 | % computing the delta Q between two community configurations 86 | % dQ = 2(e_ij - ai*aj) or (Q_groups_(i,j)_merged - Q_original) 87 | % inputs: current community assignments: groups, adjacency matrix, i,j to be joined 88 | % outputs: delta Q value (real number) 89 | 90 | % $$$ Q1=Qfn(groups,adj); 91 | % $$$ groups{i}=[groups{i} groups{j}]; 92 | % $$$ groups{j}=groups{length(groups)}; 93 | % $$$ groups=groups(1:length(groups)-1); 94 | % $$$ Q2=Qfn(groups,adj); 95 | % $$$ dQ = Q2-Q1; 96 | 97 | % alternative dQ = 2(e_ij - ai*aj) from paper; 98 | nedges=numedges(adj); % compute the total number of edges 99 | e_ii = numedges( adj(groups{i},groups{i}) ) / nedges; 100 | e_jj = numedges( adj(groups{j},groups{j}) ) / nedges; 101 | e_ij = numedges( adj([groups{i} groups{j}],[groups{i} groups{j}]) ) / nedges - e_ii - e_jj; 102 | 103 | a_i=sum(sum(adj(groups{i},:)))/nedges-e_ii; 104 | a_j=sum(sum(adj(groups{j},:)))/nedges-e_jj; 105 | 106 | dQ = 2*(e_ij-a_i*a_j); 107 | 108 | 109 | 110 | function Q=Qfn(modules,adj) % ======== same as modularity_metric.m ====== 111 | 112 | % computing the modularity for the final module break-down 113 | % Defined as: Q=sum_over_modules_i (eii-ai^2) (eq 5) in Newman and Girvan. 114 | % eij = fraction of edges that connect community i to community j 115 | % ai=sum_j (eij) 116 | 117 | nedges=numedges(adj); % compute the total number of edges 118 | 119 | Q = 0; 120 | for m=1:length(modules) 121 | 122 | e_mm=numedges(adj(modules{m},modules{m}))/nedges; 123 | a_m=sum(sum(adj(modules{m},:)))/nedges - e_mm; % counting e_mm only once 124 | 125 | Q = Q + (e_mm - a_m^2); 126 | end -------------------------------------------------------------------------------- /topology analysis/edge_betweenness.m: -------------------------------------------------------------------------------- 1 | % Edge betweenness routine, based on shortest paths 2 | % INPUTs: edgelist, mx3, m - number of edges 3 | % OUTPUTs: w - betweenness per edge 4 | % Note: Valid for undirected graphs only 5 | % Source: Newman, Girvan, "Finding and evaluating community structure in networks" 6 | % Other routines used: adj2edgeL.m, numnodes.m, numedges.m, kneighbors.m 7 | % Last modified: November 14, 2009 8 | 9 | function ew = edge_betweenness(adj) 10 | 11 | el=adj2edgeL(adj); % the corresponding edgelist 12 | n = numnodes(adj); % number of nodes 13 | m = numedges(adj); % number of edges 14 | 15 | ew = zeros(size(el,1),3); % edge betweenness - output 16 | 17 | 18 | for s=1:n % across all (source) nodes 19 | 20 | % compute the distances and weights starting at source node i 21 | d=inf(n,1); w=inf(n,1); 22 | d(s)=0; w(s)=1; % source node distance and weight 23 | queue=[s]; % add to queue 24 | visited=[]; 25 | 26 | while not(isempty(queue)) 27 | j=queue(1); % pop first member 28 | visited=[visited j]; 29 | neigh=kneighbors(adj,j,1); % find all adjacent nodes, 1 step away 30 | 31 | for x=1:length(neigh) % add to queue if unvisited 32 | nei=neigh(x); 33 | 34 | if isempty(find(visited==nei)) & isempty(find(queue==nei)); queue=[queue nei]; end 35 | 36 | end 37 | for x=1:length(neigh) 38 | 39 | nei=neigh(x); 40 | if d(nei)==inf % not assigned yet 41 | d(nei)=1+d(j); 42 | w(nei)=w(j); 43 | elseif d(nei)d(leaf) 87 | down_neigh=[down_neigh neigh(x)]; 88 | end 89 | end 90 | sum_down_edges=0; 91 | for x=1:length(down_neigh) 92 | indi=find(el(:,1)==leaf); 93 | indj=find(el(:,2)==down_neigh(x)); 94 | indij=intersect(indi,indj); 95 | sum_down_edges=sum_down_edges+eww(indij,3); 96 | end 97 | for x=1:length(up_neigh) 98 | indi=find(el(:,1)==up_neigh(x)); 99 | indj=find(el(:,2)==leaf); 100 | indij=intersect(indi,indj); 101 | eww(indij,3)=w(up_neigh(x))/w(leaf)*(1+sum_down_edges); 102 | end 103 | end 104 | end 105 | 106 | for e=1:size(ew,1); ew(e,3)=ew(e,3)+eww(e,3); end 107 | 108 | end 109 | 110 | for e=1:size(ew,1) 111 | ew(e,1)=el(e,1); 112 | ew(e,2)=el(e,2); 113 | ew(e,3)=ew(e,3)/n/(n-1); % normalize by the total number of paths 114 | end -------------------------------------------------------------------------------- /src/testdim.m: -------------------------------------------------------------------------------- 1 | clear; 2 | max_iters = 500; conv_tol = 1e-6; total_iters = 100; 3 | min_dim = 2; max_dim = 5; 4 | dims = 2:5; 5 | range_dim = max_dim-min_dim; 6 | n = 10; 7 | prior = [-1 1 10]; 8 | valid_undirected = []; 9 | I_undirected = []; 10 | ifconverged_undirected = []; 11 | valid_directed = []; 12 | I_directed = []; 13 | ifconverged_directed = []; 14 | DIM_undirected =[]; 15 | DIM_directed =[]; 16 | II_undirected =[]; 17 | II_directed =[]; 18 | for q = 1:length(dims) 19 | for i=1:total_iters 20 | fprintf('%d iteration\n', i); 21 | facG_root_undirected.var=[]; 22 | facG_root_undirected.fac=[]; 23 | facG_root_directed.var=[]; 24 | facG_root_directed.fac=[]; 25 | while(length(facG_root_undirected.var)~=n) 26 | p = rand(1,1); 27 | G_undirected=random_graph(n,p); 28 | facG_root_undirected = adjG2facG(G_undirected,min_dim,max_dim); 29 | end 30 | while(length(facG_root_directed.var)~=n) 31 | p = rand(1,1); 32 | G_directed=random_directed_graph(n,p); 33 | facG_root_directed = adjG2facG(G_directed,min_dim,max_dim); 34 | end 35 | 36 | 37 | B_PR_undirected = []; 38 | I_PR_undirected = []; 39 | ifconverged_PR_undirected = []; 40 | B_PR_directed = []; 41 | I_PR_directed = []; 42 | ifconverged_PR_directed = []; 43 | for prior_i=1:length(prior) 44 | facG_undirected=initialize(facG_root_undirected,prior(prior_i)); 45 | [facG_undirected, iters_undirected,~] = run_loopy_bp_parallel(facG_undirected, max_iters, conv_tol,false); 46 | [nodeMarg_par_undirected] = get_beliefs(facG_undirected); 47 | B_PR_undirected = [B_PR_undirected nodeMarg_par_undirected]; 48 | I_PR_undirected = [I_PR_undirected iters_undirected]; 49 | ifconverged_PR_undirected = [ifconverged_PR_undirected iters_undirectedconv_tol) 60 | flag_undirected = 1; 61 | end 62 | end 63 | if(flag_undirected ==0) 64 | I_undirected = [I_undirected sum(I_PR_undirected(ifconverged_PR_undirected==1))/length(I_PR_undirected(ifconverged_PR_undirected==1))]; 65 | ifconverged_undirected = [ifconverged_undirected;ifconverged_PR_undirected]; 66 | end 67 | valid_undirected = [valid_undirected flag_undirected==0]; 68 | 69 | 70 | flag_directed = 0; 71 | for j=1:size(B_PR_directed,2)-1 72 | if(belief_diff(B_PR_directed(:,j),B_PR_directed(:,j+1))>conv_tol) 73 | flag_directed = 1; 74 | end 75 | end 76 | if(flag_directed ==0) 77 | I_directed = [I_directed sum(I_PR_directed(ifconverged_PR_directed==1))/length(I_PR_directed(ifconverged_PR_directed==1))]; 78 | ifconverged_directed = [ifconverged_directed;ifconverged_PR_directed]; 79 | end 80 | valid_directed = [valid_directed flag_directed==0]; 81 | end 82 | DIM_undirected = [DIM_undirected dims(q)*ones(1,length(I_undirected(valid_undirected==1)))]; 83 | DIM_directed = [DIM_directed dims(q)*ones(1,length(I_directed(valid_directed==1)))]; 84 | II_undirected = [II_undirected I_undirected(valid_undirected==1)]; 85 | II_directed = [II_directed I_directed(valid_directed==1)]; 86 | end 87 | 88 | %% Averaged Version Plot 89 | [stat_undirected_x, I_undirected_y]=ave_scatter(DIM_undirected,II_undirected); 90 | [stat_directed_x, I_directed_y]=ave_scatter(DIM_directed,II_directed); 91 | figure 92 | scatter(stat_undirected_x,I_undirected_y,15,'b','filled'); 93 | hold on 94 | scatter(stat_directed_x,I_directed_y,15,'r','filled'); 95 | hold off 96 | grid on 97 | legend('undirected','directed') 98 | xlabel('Dimensions') 99 | ylabel('# of iterations') 100 | title(sprintf('Convergence rate analysis n=%d',n)) 101 | lsline 102 | %% Original Version Plot 103 | figure 104 | scatter(DIM_undirected,II_undirected,15,'b','filled'); 105 | hold on 106 | scatter(DIM_directed,II_directed,15,'r','filled'); 107 | hold off 108 | grid on 109 | legend('undirected','directed') 110 | xlabel('Dimensions') 111 | ylabel('# of iterations') 112 | title(sprintf('Convergence rate analysis n=%d',n)) 113 | lsline 114 | 115 | converge_rate_wrt_prior_undirected = sum(ifconverged_undirected,1)/size(ifconverged_undirected,1); 116 | converge_rate_wrt_prior_directed = sum(ifconverged_directed,1)/size(ifconverged_directed,1); 117 | -------------------------------------------------------------------------------- /src/adjG2facG.m: -------------------------------------------------------------------------------- 1 | function facG = adjG2facG(G,mindim,maxdim) 2 | if(issymmetric(G)) 3 | %Undirected Graph to MRF(pairwise factor graph) 4 | G = triu(G,1); 5 | facG = init_graph(); 6 | varN = []; 7 | for i=1:size(G,1) 8 | for k=i:size(G,2) 9 | if(G(i,k)==1) 10 | if(mindim~=maxdim) 11 | dims = randi(maxdim-(mindim-1),1,2)+(mindim-1); 12 | else 13 | dims = [mindim mindim]; 14 | end 15 | ids=zeros(1,2); 16 | if(i~=k) 17 | if(any(varN==i)) 18 | varid = varN==i; 19 | ids(1) = facG.var(varid).id; 20 | dims(1) = facG.var(varid).dim; 21 | else 22 | varN = [varN i]; 23 | [facG,ids(1)]=add_varnode(facG,strcat('v',int2str(i)),dims(1)); 24 | end 25 | if(any(varN==k)) 26 | varid = varN==k; 27 | ids(2) = facG.var(varid).id; 28 | dims(2) = facG.var(varid).dim; 29 | else 30 | varN = [varN k]; 31 | [facG,ids(2)]=add_varnode(facG,strcat('v',int2str(k)),dims(2)); 32 | end 33 | p=rand(dims(2),dims(1)); 34 | facG=add_facnode(facG,p,ids(2),ids(1)); 35 | else 36 | if(any(varN==i)) 37 | varid = varN==i; 38 | ids(1) = facG.var(varid).id; 39 | dims(1) = facG.var(varid).dim; 40 | else 41 | varN = [varN i]; 42 | [facG,ids(1)]=add_varnode(facG,strcat('v',int2str(i)),dims(1)); 43 | end 44 | p=rand(dims(1),dims(1)); 45 | facG=add_facnode(facG,p,ids(1),ids(1)); 46 | end 47 | end 48 | end 49 | end 50 | else 51 | %Directed Graph to hiorder potential(general factor graph) 52 | facG = init_graph(); 53 | varN = []; 54 | pointed = []; 55 | for i=1:size(G,1) 56 | for k=1:size(G,2) 57 | if(G(i,k)==1) 58 | if(mindim~=maxdim) 59 | dims = randi(maxdim-(mindim-1),1,2)+(mindim-1); 60 | else 61 | dims = [mindim mindim]; 62 | end 63 | ids=zeros(1,2); 64 | if(any(pointed==k)) 65 | facid = find(pointed==k); 66 | if(any(varN==i)) 67 | varid = varN==i; 68 | ids(1) = facG.var(varid).id; 69 | facG.var(ids(1)).nbrs_fac = [facG.var(ids(1)).nbrs_fac;facid]; 70 | else 71 | varN = [varN i]; 72 | if(i~=k) 73 | [facG,ids(1)]=add_varnode(facG,strcat('v',int2str(i)),dims(1)); 74 | end 75 | facG.var(ids(1)).nbrs_fac = facid; 76 | end 77 | facG.fac(facid).nbrs_var = [facG.fac(facid).nbrs_var ids(1)]; 78 | varids = facG.fac(facid).nbrs_var; 79 | dims = []; 80 | for j=1:length(varids) 81 | dims=[dims facG.var(varids(j)).dim]; 82 | end 83 | facG.fac(facid).p = rand(dims); 84 | else 85 | pointed=[pointed k]; 86 | if(i~=k) 87 | if(any(varN==i)) 88 | varid = varN==i; 89 | ids(1) = facG.var(varid).id; 90 | dims(1) = facG.var(varid).dim; 91 | else 92 | varN = [varN i]; 93 | [facG,ids(1)]=add_varnode(facG,strcat('v',int2str(i)),dims(1)); 94 | end 95 | if(any(varN==k)) 96 | varid = varN==k; 97 | ids(2) = facG.var(varid).id; 98 | dims(2) = facG.var(varid).dim; 99 | else 100 | varN = [varN k]; 101 | [facG,ids(2)]=add_varnode(facG,strcat('v',int2str(k)),dims(2)); 102 | end 103 | p=rand(dims(2),dims(1)); 104 | facG=add_facnode(facG,p,ids(2),ids(1)); 105 | else 106 | if(any(varN==i)) 107 | varid = varN==i; 108 | ids(1) = facG.var(varid).id; 109 | dims(1) = facG.var(varid).dim; 110 | else 111 | varN = [varN i]; 112 | [facG,ids(1)]=add_varnode(facG,strcat('v',int2str(i)),dims(1)); 113 | end 114 | p=rand(dims(1),dims(1)); 115 | facG=add_facnode(facG,p,ids(1),ids(1)); 116 | end 117 | end 118 | end 119 | end 120 | end 121 | non_pointed = varN(~ismember(varN,pointed)); 122 | for i=1:length(non_pointed) 123 | varid = varN==non_pointed(i); 124 | p=rand(facG.var(varid).dim,1); 125 | facG = add_facnode(facG,p,facG.var(varid).id); 126 | end 127 | end 128 | end -------------------------------------------------------------------------------- /topology analysis/build_smax_graph.m: -------------------------------------------------------------------------------- 1 | % Construct the graph with the maximum possible s-metric, given the degree 2 | % sequence; the s-metric is the sum of products of degrees across all edges 3 | % Source: Li et al "Towards a Theory of Scale-Free Graphs" 4 | % INPUTs: degree sequence: 1xn vector of positive integers 5 | % OUTPUTs: edgelist of the s-max graph, mx3 6 | % Other routines used: purge.m 7 | 8 | function gA=build_smax_graph(deg) 9 | 10 | didj=[]; 11 | for ii=1:length(deg)-1 12 | for jj=ii+1:length(deg) 13 | % [deg_i*deg_j, 'B', deg_i, deg_j, 'B', i, j] - 'B' for sorting purposes 14 | didj=[didj; deg(ii)*deg(jj), 2, deg(ii), deg(jj), 2, ii,jj]; 15 | end 16 | end 17 | 18 | didj=sortrows(didj); 19 | didj=didj(end:-1:1,:); % reverse to decreasing order 20 | 21 | w=deg; % number of remaining stubs - originally equals the degrees 22 | [dummy,maxdegind]=max(deg); % the index of the maximum degree 23 | A=[maxdegind]; 24 | B=purge([1:length(deg)],maxdegind); 25 | wA=deg(maxdegind); % remaining stubs in A 26 | dB=sum(deg(B)); % total degree of unattached vertices in B 27 | 28 | gA=[]; % initialize empty edgelist 29 | 30 | while sum(w)>0 % while there are still stubs to connect 31 | 32 | % STEP 1 (LINK SELECTION) 33 | if size(didj,1)==0 34 | if sum(w)>0 % connect all stubs left 35 | wstubs=[]; 36 | cnt=1; 37 | for ww=1:length(w) 38 | while w(ww)>0 39 | wstubs=[wstubs; cnt, ww]; 40 | w(ww)=w(ww)-1; 41 | cnt=cnt+1; 42 | end 43 | end 44 | for xx=1:size(wstubs,1)/2 45 | n1=wstubs(xx,2); 46 | n2=wstubs(xx+size(wstubs,1)/2,2); 47 | 48 | ind1=find(gA(:,1)==n1); 49 | if length(ind1)==0 50 | first_case=false; 51 | else 52 | ind2=find(gA(ind1,2)==n2); 53 | if length(ind2)==0 54 | first_case=false; 55 | else 56 | first_case=true; 57 | end 58 | end 59 | ind2=find(gA(:,1)==n2); 60 | if length(ind2)==0 61 | second_case=false; 62 | else 63 | ind1=find(gA(ind2,2)==n1); 64 | if length(ind1)==0 65 | second_case=false; 66 | else 67 | second_case=true; 68 | end 69 | end 70 | if first_case %if [n1,n2,1] in gA and not(n1==n2): 71 | gA=[gA; n1,n2,1]; 72 | elseif second_case % if [n2,n1,1] in gA and not(n1==n2): 73 | gA=[gA; n2,n1,1]; 74 | elseif n1==n2 75 | gA=[gA; n1,n2,1]; 76 | end 77 | 78 | 79 | end 80 | end 81 | return % gA 82 | end 83 | 84 | % eliminate zero stubs in didj 85 | didj_new=[]; 86 | for ii=1:size(didj,1) 87 | if w(didj(ii,6))>0 & w(didj(ii,7))>0 88 | didj_new=[didj_new; didj(ii,:)]; 89 | end 90 | end 91 | didj=didj_new; 92 | 93 | if size(didj,1)==0; continue; end 94 | 95 | for ii=1:size(didj,1) 96 | 97 | edge=[didj(ii,6), didj(ii,7)]; 98 | 99 | if length(find(A==edge(1)))>0 & length(find(A==edge(2)))>0 100 | didj(ii,:)=[didj(ii,1),100,w(edge(1)),w(edge(2)),100,edge(1),edge(2)]; 101 | elseif length(find(A==edge(1)))>0 & length(find(B==edge(2)))>0 102 | didj(ii,:)=[didj(ii,1),100,w(edge(1)),w(edge(2)),2,edge(1),edge(2)]; 103 | elseif length(find(B==edge(1)))>0 & length(find(A==edge(2)))>0 104 | didj(ii,:)=[didj(ii,1),2,w(edge(1)),w(edge(2)),1,edge(1),edge(2)]; 105 | didj(ii,:)=[didj(ii,1),100,w(edge(2)),w(edge(1)),2,edge(2),edge(1)]; 106 | else 107 | didj(ii,:)=[didj(ii,1),2,w(edge(1)),w(edge(2)),2,edge(1),edge(2)]; 108 | end 109 | 110 | end 111 | 112 | didj=sortrows(didj); 113 | didj=didj(end:-1:1,:); 114 | link_select=[didj(1,6),didj(1,7)]; % select the first link that starts in A 115 | 116 | % STEP 2 (LINK ADDITION) 117 | n1=link_select(1); 118 | n2=link_select(2); 119 | 120 | % if (n1 in A and n2 in B) or (n1 in B and n2 in A) 121 | if (length(find(A==n1))>0 & length(find(B==n2))>0) | (length(find(B==n1))>0 & length(find(A==n2))>0) 122 | gA=[gA; n1, n2, 1]; 123 | if length(find(A==n1))>0 & length(find(B==n2))>0 124 | B=purge(B,n2); 125 | A=[A; n2]; 126 | end 127 | if length(find(B==n1))>0 & length(find(A==n2))>0 128 | B=purge(B,n1); 129 | A=[A; n1]; 130 | end 131 | 132 | w(n1)=w(n1)-1; 133 | w(n2)=w(n2)-1; 134 | wA=sum(w(A)); 135 | dB=sum(deg(B)); 136 | 137 | didj=didj(2:size(didj,1),:); % remove link from top 138 | 139 | elseif length(find(A==n1))>0 & length(find(A==n2))>0 140 | % check the tree condition 141 | if dB==2*length(B)-wA 142 | didj=didj(2:size(didj,1),:); 143 | 144 | elseif wA==2 & length(B)>0 % results in a disconnected graph 145 | didj=didj(2:size(didj,1),:); 146 | 147 | else % add it! 148 | gA=[gA; n1,n2,1]; 149 | 150 | w(n1)=w(n1)-1; 151 | w(n2)=w(n2)-1; 152 | 153 | wA=sum(w(A)); 154 | dB=sum(deg(B)); 155 | 156 | didj=didj(2:size(didj,1),:); 157 | end 158 | end 159 | end 160 | -------------------------------------------------------------------------------- /src/test.m: -------------------------------------------------------------------------------- 1 | max_iters = 500; conv_tol = 1e-6; total_iters = 100; 2 | min_dim = 2; max_dim = 5; 3 | range_dim = max_dim-min_dim; 4 | n = 10; 5 | prior = [-1 1 10]; 6 | valid_undirected = []; 7 | I_undirected = []; 8 | ifconverged_undirected = []; 9 | valid_directed = []; 10 | I_directed = []; 11 | ifconverged_directed = []; 12 | Stats_name = {'# of edges','# of connected components',... 13 | 'diameter(the longest shortest path)','the average shortest path','radius(minimum vertex eccentricity)',... 14 | '# of size 3 loop','# of size 4 loop','# of independent loop','average factor node dimension(average cardinality)',... 15 | 'maximum factor node dimension(average cardinality)',}; 16 | Stats_undirected = zeros(length(Stats_name),total_iters); 17 | Stats_directed = zeros(length(Stats_name),total_iters); 18 | for i=1:total_iters 19 | fprintf('%d iteration\n', i); 20 | facG_root_undirected.var=[]; 21 | facG_root_undirected.fac=[]; 22 | facG_root_directed.var=[]; 23 | facG_root_directed.fac=[]; 24 | while(length(facG_root_undirected.var)~=n) 25 | p = rand(1,1); 26 | G_undirected=random_graph(n,p); 27 | facG_root_undirected = adjG2facG(G_undirected,min_dim,max_dim); 28 | end 29 | while(length(facG_root_directed.var)~=n) 30 | p = rand(1,1); 31 | G_directed=random_directed_graph(n,p); 32 | facG_root_directed = adjG2facG(G_directed,min_dim,max_dim); 33 | end 34 | Stats_undirected(1,i)=numedges(G_undirected); 35 | Stats_undirected(2,i)=num_conn_comp(G_undirected); 36 | Stats_undirected(3,i)=diameter(G_undirected); 37 | Stats_undirected(4,i)=ave_path_length(G_undirected); 38 | Stats_undirected(5,i)=graph_radius(G_undirected); 39 | Stats_undirected(6,i)=loops3(G_undirected); 40 | Stats_undirected(7,i)=length(loops4(G_undirected)); 41 | Stats_undirected(8,i)=num_loops(G_undirected); 42 | Stats_undirected(9,i)=mean(cardi(facG_root_undirected)); 43 | Stats_undirected(10,i)=max(cardi(facG_root_undirected)); 44 | 45 | Stats_directed(1,i)=numedges(G_directed); 46 | Stats_directed(2,i)=num_conn_comp(G_directed); 47 | Stats_directed(3,i)=diameter(G_directed); 48 | Stats_directed(4,i)=ave_path_length(G_directed); 49 | Stats_directed(5,i)=graph_radius(G_directed); 50 | Stats_directed(6,i)=loops3(G_directed); 51 | Stats_directed(7,i)=length(loops4(G_directed)); 52 | Stats_directed(8,i)=num_loops(G_directed); 53 | Stats_directed(9,i)=mean(cardi(facG_root_directed)); 54 | Stats_directed(10,i)=max(cardi(facG_root_directed)); 55 | 56 | 57 | B_PR_undirected = []; 58 | I_PR_undirected = []; 59 | ifconverged_PR_undirected = []; 60 | B_PR_directed = []; 61 | I_PR_directed = []; 62 | ifconverged_PR_directed = []; 63 | for prior_i=1:length(prior) 64 | facG_undirected=initialize(facG_root_undirected,prior(prior_i)); 65 | [facG_undirected, iters_undirected,~] = run_loopy_bp_parallel(facG_undirected, max_iters, conv_tol, false); 66 | [nodeMarg_par_undirected] = get_beliefs(facG_undirected); 67 | B_PR_undirected = [B_PR_undirected nodeMarg_par_undirected]; 68 | I_PR_undirected = [I_PR_undirected iters_undirected]; 69 | ifconverged_PR_undirected = [ifconverged_PR_undirected iters_undirectedconv_tol) 80 | flag_undirected = 1; 81 | end 82 | end 83 | if(flag_undirected ==0) 84 | I_undirected = [I_undirected sum(I_PR_undirected(ifconverged_PR_undirected==1))/length(I_PR_undirected(ifconverged_PR_undirected==1))]; 85 | ifconverged_undirected = [ifconverged_undirected;ifconverged_PR_undirected]; 86 | end 87 | valid_undirected = [valid_undirected flag_undirected==0]; 88 | 89 | 90 | flag_directed = 0; 91 | for j=1:size(B_PR_directed,2)-1 92 | if(belief_diff(B_PR_directed(:,j),B_PR_directed(:,j+1))>conv_tol) 93 | flag_directed = 1; 94 | end 95 | end 96 | if(flag_directed ==0) 97 | I_directed = [I_directed sum(I_PR_directed(ifconverged_PR_directed==1))/length(I_PR_directed(ifconverged_PR_directed==1))]; 98 | ifconverged_directed = [ifconverged_directed;ifconverged_PR_directed]; 99 | end 100 | valid_directed = [valid_directed flag_directed==0]; 101 | end 102 | Stats_undirected(Stats_undirected==inf)=0; 103 | Stats_directed(Stats_directed==inf)=0; 104 | 105 | for i=1:length(Stats_name) 106 | stat_undirected = Stats_undirected(i,:); 107 | stat_directed = Stats_directed(i,:); 108 | [stat_undirected_x, I_undirected_y]=ave_scatter(stat_undirected(valid_undirected==1),I_undirected(valid_undirected==1)); 109 | [stat_directed_x, I_directed_y]=ave_scatter(stat_directed(valid_directed==1),I_directed(valid_directed==1)); 110 | figure 111 | scatter(stat_undirected_x,I_undirected_y,15,'b','filled'); 112 | hold on 113 | scatter(stat_directed_x,I_directed_y,15,'r','filled'); 114 | hold off 115 | grid on 116 | legend('undirected','directed') 117 | xlabel(Stats_name{i}) 118 | ylabel('# of iterations') 119 | title(sprintf('Convergence rate analysis n=%d',n)) 120 | lsline 121 | end 122 | 123 | for i=1:length(Stats_name) 124 | stat_undirected = Stats_undirected(i,:); 125 | stat_directed = Stats_directed(i,:); 126 | %% Averaged Version Plot 127 | [stat_undirected_x, I_undirected_y]=ave_scatter(stat_undirected(valid_undirected==1),I_undirected(valid_undirected==1)); 128 | [stat_directed_x, I_directed_y]=ave_scatter(stat_directed(valid_directed==1),I_directed(valid_directed==1)); 129 | figure 130 | scatter(stat_undirected_x,I_undirected_y,15,'b','filled'); 131 | hold on 132 | scatter(stat_directed_x,I_directed_y,15,'r','filled'); 133 | hold off 134 | grid on 135 | legend('undirected','directed') 136 | xlabel(Stats_name{i}) 137 | ylabel('# of iterations') 138 | title(sprintf('Convergence rate analysis n=%d',n)) 139 | lsline 140 | %% Original Version Plot 141 | figure 142 | scatter(stat_undirected(valid_undirected==1),I_undirected(valid_undirected==1),15,'b','filled'); 143 | hold on 144 | scatter(stat_directed(valid_directed==1),I_directed(valid_directed==1),15,'r','filled'); 145 | hold off 146 | grid on 147 | legend('undirected','directed') 148 | xlabel(Stats_name{i}) 149 | ylabel('# of iterations') 150 | title(sprintf('Convergence rate analysis n=%d',n)) 151 | end 152 | 153 | save('Stat.mat','Stats_name','Stats_undirected','Stats_directed','I_undirected','I_directed','valid_undirected','valid_directed','n') 154 | converge_rate_wrt_prior_undirected = sum(ifconverged_undirected,1)/size(ifconverged_undirected,1); 155 | converge_rate_wrt_prior_directed = sum(ifconverged_directed,1)/size(ifconverged_directed,1); 156 | -------------------------------------------------------------------------------- /topology analysis/canonical_nets.m: -------------------------------------------------------------------------------- 1 | % Build edge lists for simple canonical graphs, ex: trees and lattices 2 | % INPUTS: number of nodes, net type, branch factor (for trees only) 3 | % Types can be 'line','circle','star','btree','tree','htree','trilattice','sqlattice','hexlattice', 'clique' 4 | % OUTPUTS: edgelist (mx3); additional outputs possible, see specific graph construction routine 5 | % Other functions used: symmetrize_edgeL.m, adj2edgeL.m 6 | % GB, Last Updated: November 18, 2009 7 | 8 | function el=canonical_nets(n,type,b) 9 | 10 | if strcmp(type,'line') 11 | el=build_line(n); 12 | elseif strcmp(type,'circle') 13 | el=build_circle(n); 14 | elseif strcmp(type,'star') 15 | el=build_star(n); 16 | elseif strcmp(type,'btree') 17 | el=build_binary_tree(n); 18 | elseif strcmp(type,'tree') 19 | el=build_tree(n,b); 20 | elseif strcmp(type,'htree') 21 | el=build_hierarchical_tree(n,b); 22 | elseif strcmp(type,'trilattice') 23 | el=build_triangular_lattice(n); 24 | elseif strcmp(type,'sqlattice') 25 | el=build_square_lattice(n); 26 | elseif strcmp(type,'hexlattice') 27 | el=build_hexagonal_lattice(n); 28 | elseif strcmp(type,'clique') 29 | el=build_clique(n); 30 | end 31 | 32 | %XXX canonical nets functions XXXXXXXXXXXXXXXX 33 | 34 | function el_line=build_line(n) % line ====================================== 35 | 36 | el_line = [[1:n-1]' [2:n]' ones(n-1,1)]; 37 | el_line = symmetrize_edgeL(el_line); 38 | 39 | 40 | function el_cir=build_circle(n) % circle =================================== 41 | 42 | el_cir = [[1:n-1]' [2:n]' ones(n-1,1)]; 43 | el_cir = [el_cir; 1 n 1]; 44 | el_cir = symmetrize_edgeL(el_cir); 45 | 46 | 47 | function el_star=build_star(n) % star ====================================== 48 | 49 | el_star = [ones(n-1,1) [2:n]' ones(n-1,1)]; 50 | el_star = symmetrize_edgeL(el_star); 51 | 52 | 53 | function el_clique = build_clique(n) 54 | 55 | el_clique = adj2edgeL(ones(n)-eye(n)); 56 | 57 | 58 | function el_bt=build_binary_tree(n) % binary tree ========================== 59 | 60 | el_bt=[]; 61 | 62 | for i=2:n 63 | if mod(i,2)==0 64 | el_bt=[el_bt; i i/2 1]; 65 | else 66 | el_bt=[el_bt; i (i-1)/2 1]; 67 | end 68 | end 69 | el_bt=symmetrize_edgeL(el_bt); 70 | 71 | 72 | function el=build_tree(n,b) 73 | % tree with n nodes and arbitrary branching factor b 74 | 75 | nodes=1; 76 | queue=1; 77 | el=[]; 78 | 79 | while nodes < n 80 | if nodes+b > n 81 | % add (n-nodes) to first stack member 82 | for i=1:n-nodes 83 | el=[el; queue(1) i+nodes 1]; 84 | end 85 | nodes=n; 86 | else 87 | % add b new edges: 88 | for bb=1:b 89 | el=[el; queue(1) nodes+bb 1]; 90 | queue=[queue nodes+bb]; 91 | end 92 | queue=queue(2:length(queue)); % remove first member 93 | nodes=nodes+b; % update node number 94 | end 95 | end 96 | el=symmetrize_edgeL(el); 97 | 98 | 99 | function el=build_hierarchical_tree(n,b) 100 | 101 | % build a tree with n nodes and b as a branch factor, where nodes on one level are connected 102 | % INPUTs: number of nodes - n, branch factor - b 103 | % OUTPUTs: edgelist 104 | 105 | 106 | L=ceil(log(1+n*(b-1))/log(b)); % L=log(1+n(b-1))/log(b) 107 | el=build_tree(n,b); % build the base 108 | 109 | % add the cross-level links 110 | for k=1:L 111 | 112 | start_node=1+round((b^(k-1)-1)/(b-1)); 113 | 114 | for bb=1:b^(k-1)-1 115 | if start_node+bb-1>n | start_node+bb>n 116 | el=symmetrize_edgeL(el); 117 | return 118 | end 119 | el=[el; start_node+bb-1, start_node+bb,1]; 120 | end 121 | 122 | end 123 | el=symmetrize_edgeL(el); 124 | 125 | 126 | 127 | function [el_tr,adj_tr,f1,f2]=build_triangular_lattice(n) 128 | 129 | % triangular lattice ============================ 130 | % build triangular lattice with n nodes 131 | % as close to a "square" shape as possible 132 | el_tr=[]; 133 | x=factor(n); 134 | if numel(x)==1 135 | el_tr=[el_tr; n 1 1]; 136 | n=n-1; 137 | x=factor(n); 138 | end 139 | 140 | if mod(numel(x),2)==0 % if there's an even number of factors, split in two 141 | f1=prod(x(1:numel(x)/2)); 142 | f2=prod(x(numel(x)/2+1:numel(x))); 143 | elseif mod(numel(x),2)==1 144 | f1=prod(x(1:(numel(x)+1)/2)); 145 | f2=prod(x((numel(x)+1)/2+1:numel(x))); 146 | end 147 | 148 | % the lattice will be f1xf2 149 | % inner mesh 150 | for i=2:f1-1 151 | for j=2:f2-1 152 | % (i,j)->f2*(i-1)+j 153 | el_tr=[el_tr; f2*(i-1)+j f2*(i-2)+j 1]; 154 | el_tr=[el_tr; f2*(i-1)+j f2*(i)+j 1]; 155 | el_tr=[el_tr; f2*(i-1)+j f2*(i-1)+j-1 1]; 156 | el_tr=[el_tr; f2*(i-1)+j f2*(i-1)+j+1 1]; 157 | el_tr=[el_tr; f2*(i-1)+j f2*i+j+1 1]; % added for tri lattice 158 | end 159 | end 160 | % four corners 161 | el_tr=[el_tr; 1 2 1]; 162 | el_tr=[el_tr; 1 f2+1 1]; 163 | el_tr=[el_tr; 1 f2+2 1]; % added for tri lattice 164 | el_tr=[el_tr; f2 f2-1 1]; 165 | el_tr=[el_tr; f2 2*f2 1]; 166 | el_tr=[el_tr; f2*(f1-1)+1 f2*(f1-2)+1 1]; 167 | el_tr=[el_tr; f2*(f1-1)+1 f2*(f1-1)+2 1]; 168 | el_tr=[el_tr; f1*f2 f2*(f1-1) 1]; 169 | el_tr=[el_tr; f1*f2 f2*f1-1 1]; 170 | 171 | % four walls 172 | for j=2:f2-1 173 | el_tr=[el_tr; j j-1 1]; 174 | el_tr=[el_tr; j j+1 1]; 175 | el_tr=[el_tr; j f2+j 1]; 176 | el_tr=[el_tr; j f2+j+1 1]; % added for tri lattice 177 | 178 | el_tr=[el_tr; f2*(f1-1)+j f2*(f1-1)+j-1 1]; 179 | el_tr=[el_tr; f2*(f1-1)+j f2*(f1-1)+j+1 1]; 180 | el_tr=[el_tr; f2*(f1-1)+j f2*(f1-2)+j 1]; 181 | end 182 | for i=2:f1-1 183 | el_tr=[el_tr; f2*(i-1)+1 f2*(i-2)+1 1]; 184 | el_tr=[el_tr; f2*(i-1)+1 f2*i+1 1]; 185 | el_tr=[el_tr; f2*(i-1)+1 f2*(i-1)+2 1]; 186 | el_tr=[el_tr; f2*(i-1)+1 f2*i+2 1]; % added for tri lattice 187 | 188 | el_tr=[el_tr; f2*i f2*(i-1) 1]; 189 | el_tr=[el_tr; f2*i f2*(i+1) 1]; 190 | el_tr=[el_tr; f2*i f2*i-1 1]; 191 | end 192 | 193 | el_tr=symmetrize_edgeL(el_tr); 194 | 195 | 196 | function [el_sq,adj_sq]=build_square_lattice(n) 197 | 198 | % square latice ==================================== 199 | el_sq=[]; 200 | x=factor(n); 201 | if numel(x)==1 202 | el_sq=[el_sq; n 1 1]; 203 | n=n-1; 204 | x=factor(n); 205 | end 206 | 207 | if mod(numel(x),2)==0 208 | f1=prod(x(1:numel(x)/2)); f2=prod(x(numel(x)/2+1:numel(x))); 209 | elseif mod(numel(x),2)==1 210 | f1=prod(x(1:(numel(x)+1)/2)); f2=prod(x((numel(x)+1)/2+1:numel(x))); 211 | end 212 | 213 | % the lattice will be f1xf2 214 | % inner mesh 215 | for i=2:f1-1 216 | for j=2:f2-1 217 | % (i,j)->f2*(i-1)+j 218 | el_sq=[el_sq; f2*(i-1)+j f2*(i-2)+j 1]; 219 | el_sq=[el_sq; f2*(i-1)+j f2*(i)+j 1]; 220 | el_sq=[el_sq; f2*(i-1)+j f2*(i-1)+j-1 1]; 221 | el_sq=[el_sq; f2*(i-1)+j f2*(i-1)+j+1 1]; 222 | end 223 | end 224 | % four corners 225 | el_sq=[el_sq; 1 2 1]; 226 | el_sq=[el_sq; 1 f2+1 1]; 227 | el_sq=[el_sq; f2 f2-1 1]; 228 | el_sq=[el_sq; f2 2*f2 1]; 229 | el_sq=[el_sq; f2*(f1-1)+1 f2*(f1-2)+1 1]; 230 | el_sq=[el_sq; f2*(f1-1)+1 f2*(f1-1)+2 1]; 231 | el_sq=[el_sq; f1*f2 f2*(f1-1) 1]; 232 | el_sq=[el_sq; f1*f2 f2*f1-1 1]; 233 | % four walls 234 | for j=2:f2-1 235 | el_sq=[el_sq; j j-1 1]; 236 | el_sq=[el_sq; j j+1 1]; 237 | el_sq=[el_sq; j f2+j 1]; 238 | 239 | el_sq=[el_sq; f2*(f1-1)+j f2*(f1-1)+j-1 1]; 240 | el_sq=[el_sq; f2*(f1-1)+j f2*(f1-1)+j+1 1]; 241 | el_sq=[el_sq; f2*(f1-1)+j f2*(f1-2)+j 1]; 242 | end 243 | for i=2:f1-1 244 | el_sq=[el_sq; f2*(i-1)+1 f2*(i-2)+1 1]; 245 | el_sq=[el_sq; f2*(i-1)+1 f2*i+1 1]; 246 | el_sq=[el_sq; f2*(i-1)+1 f2*(i-1)+2 1]; 247 | 248 | el_sq=[el_sq; f2*i f2*(i-1) 1]; 249 | el_sq=[el_sq; f2*i f2*(i+1) 1]; 250 | el_sq=[el_sq; f2*i f2*i-1 1]; 251 | end 252 | 253 | el_sq=symmetrize_edgeL(el_sq); 254 | 255 | 256 | function el_hex=build_hexagonal_lattice(n) 257 | 258 | % hexagonal lattice ========================================== 259 | % construct subgraph of the triangular lattice, f1xf2 260 | el_hex=[]; 261 | x=factor(n); 262 | 263 | if numel(x)==1 264 | el_hex=[el_hex; n 1 1]; 265 | n=n-1; 266 | x=factor(n); 267 | end 268 | 269 | if mod(numel(x),2)==0 270 | f1=prod(x(1:numel(x)/2)); f2=prod(x(numel(x)/2+1:numel(x))); 271 | elseif mod(numel(x),2)==1 272 | f1=prod(x(1:(numel(x)+1)/2)); f2=prod(x((numel(x)+1)/2+1:numel(x))); 273 | end 274 | 275 | % the lattice will be f1xf2 276 | % inner mesh 277 | fmax=max(f1,f2); 278 | fmin=min(f1,f2); 279 | 280 | for ff=1:fmin % from 1 to fmin 281 | % rows are from ff*fmax+1 to (ff+1)*fmax - 1 282 | % (ff+1)*fmax+1 to (ff+2)*fmax - 2 283 | for gg=1:fmax % in range(fmax): 284 | if gg