├── LICENSE ├── README.md ├── Toolbox Readme.pdf ├── arrayToContactSeq.m ├── betweennessCentrality.m ├── broadcastRecieveCentrality.m ├── burstiness.m ├── closenessCentrality.m ├── forwardLatency.m ├── forwardLatencyComputations.m ├── informationLatency.m ├── informationView.m ├── isStronglyConnected.m ├── isWeaklyConnected.m ├── latency.m ├── latencyComputations.m ├── listAllMotifs.m ├── makeReachabilityArray.m ├── networksFromContacts.m ├── plotArcNetwork.m ├── plotDNarc.m ├── plotDNarc_dir.m ├── plotDNline.m ├── randomDN.m ├── randomPermutedTimes.m ├── randomizedEdges.m ├── reachabilityAtTimeT.m ├── reachabilityGraph.m ├── ringDN.m ├── setOfInfluence.m ├── shuffledTimeSteps.m ├── sourceSet.m ├── temporalCorrelation.m ├── temporalSmallWorldness.m ├── thresholdMatDensity.m └── timeAggregate_bin.m /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ann E. Sizemore and Danielle S. Bassett 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dynamic-Graph-Metrics 2 | 3 | Contains code associated with 4 | Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 5 | 6 | See Toolbox Readme for a list of functions and their descriptions. 7 | 8 | 9 | This repository is no longer maintained. 10 | -------------------------------------------------------------------------------- /Toolbox Readme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asizemore/Dynamic-Graph-Metrics/ab5a9ef630e3095724e0222cd0cbe595241cd07e/Toolbox Readme.pdf -------------------------------------------------------------------------------- /arrayToContactSeq.m: -------------------------------------------------------------------------------- 1 | function [ contactSequence ] = arrayToContactSeq(adjArray,isdirected) 2 | % arrayToContactSeq takes a sequence of matrices and converts this to a 3 | % long format contact sequence. 4 | % 5 | % Inputs: 6 | % adjArray = an nNodes x nNodes x time-points array encoding a 7 | % dynamic network 8 | % isdirected = boolean indicating if the network is directed 9 | % 10 | % Output: 11 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 12 | % contact between nodes i,j at time t. If adjArray is weighted, 13 | % this will be an nEdges x 4 array of (i,j,t,w) including the 14 | % edge weight w. 15 | % 16 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 17 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 18 | % 19 | % Main function 20 | 21 | %% making contact sequence from networks 22 | 23 | % networsk are adjArray 24 | 25 | nNodes = size(adjArray,1); 26 | contactSequence = []; 27 | 28 | for t = 1:size(adjArray,3) 29 | if ~isdirected 30 | for i =1:nNodes 31 | for j = i+1:nNodes 32 | if adjArray(i,j,t) ~= 0 33 | contactSequence = [contactSequence; i j t adjArray(i,j,t)]; 34 | end 35 | end 36 | end 37 | 38 | else 39 | for i = 1:nNodes 40 | for j = 1:nNodes 41 | if i~=j 42 | if adjArray(i,j,t) ~=0 43 | contactSequence = [contactSequence; i j t adjArray(i,j,t)]; 44 | end 45 | end 46 | end 47 | end 48 | end 49 | 50 | end 51 | 52 | 53 | 54 | % if it is unweighted, return only the first three columns 55 | if length(unique(contactSequence(:,4))) == 1 56 | contactSequence = contactSequence(:,1:3); 57 | end 58 | 59 | 60 | end 61 | 62 | -------------------------------------------------------------------------------- /betweennessCentrality.m: -------------------------------------------------------------------------------- 1 | function [ betweennessCent, durationShortestPaths, nFastestPaths ] = ... 2 | betweennessCentrality(contactSequence,directed) 3 | %% Calculate the betweenness centrality of all nodes in a dynamic network. 4 | % 5 | % Inputs: 6 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 7 | % contact between nodes i,j at time t. 8 | % directed = 1 if network is directed, 0 if undirected. 9 | % 10 | % Outputs: 11 | % betweennessCent = nNodes x 1 vector recording the betweenness 12 | % centrality at each node. 13 | % durationShortestPath = nNodes x nNodes matrix recording the 14 | % duration of the shortest path from node i to node j in entry 15 | % ij. 16 | % nFastestPaths = nNodes x nNodes matrix with entry ij the number of 17 | % fastest paths from node i to node j. 18 | % 19 | % 20 | % 21 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 22 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 23 | % 24 | % Main function: 25 | 26 | % betweenness centrality 27 | % First section based on betweenness_bin from the Brain connectivity 28 | % toolbox (Complex network measures of brain connectivity: Uses and 29 | % interpretations. Rubinov M, Sporns O (2010) NeuroImage 52:1059-69.) 30 | 31 | adjArray = networksFromContacts(contactSequence,directed); 32 | 33 | npoints = size(adjArray,3); 34 | nNodes = size(adjArray,1); 35 | durationShortestPaths = zeros(nNodes); 36 | 37 | 38 | nPathsDurationt = sum(adjArray,3); 39 | nFastestPathsDurationt = nPathsDurationt; 40 | nFastestPaths = nFastestPathsDurationt; 41 | nFastestPaths(logical(eye(nNodes))) = 1; 42 | durationShortestPaths(find(nPathsDurationt)) = 1; 43 | durationShortestPaths(logical(eye(nNodes))) = 1; 44 | 45 | startingInfo = zeros(nNodes,nNodes,npoints); 46 | 47 | 48 | % Note: we assume time steps are 1:nPoints 49 | 50 | for t = 2:npoints 51 | 52 | tArray = zeros(nNodes,nNodes,npoints-t+1); 53 | 54 | for p = 1:size(tArray,3) 55 | 56 | tArray(:,:,p) = adjArray(:,:,p); 57 | for j = p+1:p+t-1 58 | 59 | tArray(:,:,p) = tArray(:,:,p)*adjArray(:,:,j)+ (tArray(:,:,p)>0); 60 | end 61 | 62 | tArraySlice = tArray(:,:,p); 63 | startingInfoSlice = startingInfo(:,:,p); 64 | 65 | startingInfoSlice(nFastestPaths==0) = tArraySlice(nFastestPaths==0); 66 | startingInfo(:,:,p) = startingInfoSlice; 67 | 68 | end 69 | 70 | 71 | % need to update shortest path matrix 72 | nPathsDurationt = sum(tArray,3); 73 | nFastestPathsDurationt(nFastestPaths==0) = ... 74 | nPathsDurationt(nFastestPaths==0); 75 | newPathind = nFastestPathsDurationt; 76 | newPathind(newPathind>0) = 1; 77 | durationShortestPaths(nFastestPaths==0) = t*newPathind(nFastestPaths==0); 78 | 79 | % update fastest paths 80 | nFastestPaths(nFastestPaths==0) = ... 81 | nFastestPathsDurationt(nFastestPaths==0); 82 | 83 | 84 | 85 | 86 | end 87 | 88 | 89 | 90 | % Prepare to find path members 91 | 92 | durationShortestPaths(~durationShortestPaths) = inf; 93 | durationShortestPaths(logical(eye(nNodes))) = 0; 94 | nFastestPaths(~nFastestPaths) = 1; 95 | 96 | 97 | 98 | % Finding which nodes belong in each path 99 | 100 | betweennessCent = zeros(nNodes,1); 101 | for t = 1:npoints-1 102 | 103 | shortestPathsStartingAtTimet = startingInfo(:,:,t); 104 | 105 | % Records number of shortest paths 106 | lengthShortestPathsStartingAtTimet = zeros(nNodes); 107 | lengthShortestPathsStartingAtTimet(shortestPathsStartingAtTimet>0) = ... 108 | durationShortestPaths(shortestPathsStartingAtTimet>0); 109 | 110 | [startingNode,endingNode] = find(shortestPathsStartingAtTimet); 111 | 112 | for p = 1:length(startingNode) 113 | 114 | dur = lengthShortestPathsStartingAtTimet(startingNode(p),endingNode(p)); 115 | if ~isinf(dur) && dur>1 116 | if dur == 2 117 | betweenNode = intersect(find(adjArray(startingNode(p),:,t)),... 118 | find(adjArray(:,endingNode(p),t+1))); 119 | betweennessCent(betweenNode) = betweennessCent(betweenNode) + ... 120 | 1/nFastestPaths(startingNode(p),endingNode(p)); 121 | else 122 | 123 | 124 | 125 | node2 = find(adjArray(startingNode(p),:,t)>0); 126 | 127 | keeps = []; 128 | for n = 1:length(node2) 129 | yn = setOfInfluence(node2(n),contactSequence,directed,t,t+dur-1,[],nNodes); 130 | if ismember(endingNode(p),yn) 131 | keeps = [keeps n]; 132 | end 133 | end 134 | node2 = node2(keeps); 135 | paths = node2'; 136 | 137 | 138 | for t_i = t+1:t+dur-2 139 | 140 | allNewPaths = []; 141 | for n1 = 1:size(paths,1) 142 | 143 | nodet_i = paths(n1,end); 144 | 145 | [~,more] = find(adjArray(nodet_i,:,t_i)>0); 146 | nodet_i = union(nodet_i,more)'; 147 | 148 | keeps = []; 149 | for n = 1:length(nodet_i) 150 | yn = setOfInfluence(nodet_i(n),contactSequence,directed,t_i+1,... 151 | t+dur-1,[],nNodes); 152 | if ismember(endingNode(p),yn) 153 | keeps = [keeps; n]; 154 | end 155 | end 156 | 157 | nodet_i = nodet_i(keeps); 158 | 159 | %add new paths 160 | oldPaths = repmat(paths(n1,:),[length(nodet_i) 1]); 161 | newPaths = [oldPaths nodet_i]; 162 | allNewPaths = [allNewPaths; newPaths]; 163 | 164 | end 165 | 166 | paths = allNewPaths; 167 | 168 | end 169 | 170 | % Then we need to add this to betweenness centrality vector 171 | for n3 = 1:size(paths,1) 172 | betweennessCent(unique(paths(n3,:))) = ... 173 | betweennessCent(unique(paths(n3,:))) + ... 174 | 1/nFastestPaths(startingNode(p),endingNode(p)); 175 | 176 | end 177 | 178 | 179 | end 180 | end 181 | 182 | end 183 | 184 | end 185 | 186 | 187 | 188 | 189 | end 190 | 191 | -------------------------------------------------------------------------------- /broadcastRecieveCentrality.m: -------------------------------------------------------------------------------- 1 | function [ broadcastCentrality, receiveCentrality ] = ... 2 | broadcastRecieveCentrality( contactSequence,alpha, nNodes ) 3 | %% Calculate the broadcast and receive centrality as defined in Mantzaris 4 | % et al. 2013. 5 | % 6 | % Inputs: 7 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 8 | % contact between nodes i,j at time t. Assumes undirected. 9 | % alpha = scalar in (0,1) governing weight given to paths based on 10 | % the number of edges. 11 | % 12 | % Optional Inputs: 13 | % nNodes = number of nodes in the dynamic network. Default is all 14 | % nodes which appear in contactSequence (have at least one 15 | % contact). 16 | % 17 | % Outputs: 18 | % broadcastCentrality = nNodes x 1 vector recording the broadcast 19 | % centrality at each node. 20 | % receiveCentrality = nNodes x 1 vector recording the receive 21 | % centrality at each node. 22 | % 23 | % 24 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 25 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 26 | % 27 | % 28 | % 29 | % Main function: 30 | 31 | if ~exist('nNodes','var') || isempty(nNodes) 32 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 33 | end 34 | 35 | % convert contact sequence to array of networks 36 | directed = 0; 37 | [ adjArray ] = networksFromContacts(contactSequence,directed); 38 | badj = adjArray(:,:,1); 39 | badj(badj>0) = 1; 40 | P_sd = inv(eye(nNodes) - alpha*badj); 41 | nTimes = size(adjArray,3); 42 | 43 | for n = 2:nTimes 44 | badj = thresholdMatDensity(adjArray(:,:,n),0.1); 45 | badj(badj>0) = 1; 46 | P_sd = P_sd*inv(eye(nNodes) - alpha*badj); 47 | end 48 | 49 | Q_sd = P_sd/norm(P_sd); 50 | 51 | broadcastCentrality = sum(Q_sd,2); 52 | receiveCentrality = sum(Q_sd,1); 53 | 54 | end 55 | 56 | -------------------------------------------------------------------------------- /burstiness.m: -------------------------------------------------------------------------------- 1 | function [ B, cov, sigma, m ] = burstiness(sequence) 2 | % Calculate the burstiness of a given sequence. 3 | % 4 | % Input: 5 | % sequence = vector, often the vector of contact times 6 | % 7 | % Outputs: 8 | % B = burstiness of input sequence 9 | % cov = coefficient of variation 10 | % sigma = standard deviaiton 11 | % m = mean of input sequence 12 | % 13 | % 14 | % 15 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 16 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 17 | % 18 | % Main function: 19 | 20 | % first calculate sigma, the standard deviation 21 | 22 | sigma = std(sequence); 23 | 24 | % now calculate the mean 25 | 26 | m = mean(sequence); 27 | 28 | % coefficient of variation 29 | 30 | cov = sigma/m; 31 | 32 | % burstiness 33 | 34 | B = (sigma - m)/(sigma + m); 35 | 36 | 37 | end 38 | 39 | -------------------------------------------------------------------------------- /closenessCentrality.m: -------------------------------------------------------------------------------- 1 | function [ Cc, tau_vec ] = closenessCentrality(node_i,time,... 2 | contactSequence,directed,contactTimes,nNodes) 3 | % Calculate the closeness centrality of a given node beginning at a 4 | % particular time. 5 | % 6 | % Inputs: 7 | % node_i = starting node 8 | % time = earliest time a path can begin 9 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 10 | % contact between nodes i,j at time t. 11 | % directed = 1 if network is directed, 0 if undirected. 12 | % Optional Inputs: 13 | % contactTimes = ascending vector of all possible contact times. Ex. 14 | % 1:20. Default assumes all possible times exist in 15 | % contactSequence. 16 | % nNodes = number of nodes total in dynamic network. Default assumes 17 | % all nodes are present in contactSequence. 18 | % 19 | % Output: 20 | % Cc = closeness centrality of node i at time t. 21 | % tau_vec = vector recording values of tau_{i,t}(j) (forward 22 | % latency). Unreachable nodes and node i are given value inf. 23 | % 24 | % 25 | % Note: if input time is that of a contact originating at node i, the 26 | % forward latency will be 0 for that node, making the overall Cc = inf 27 | % (since we take the average of 1/tau). 28 | % 29 | % 30 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 31 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 32 | % 33 | % 34 | % Main function: 35 | 36 | if ~exist('contactTimes','var') || isempty(contactTimes); 37 | contactTimes = sort(unique(contactSequence(:,3)),'ascend'); 38 | end 39 | if ~exist('nNodes','var') || isempty(nNodes); 40 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 41 | end 42 | 43 | 44 | 45 | 46 | 47 | 48 | for node_j = 1:nNodes 49 | 50 | tau = inf; 51 | 52 | if node_j ~= node_i 53 | [tau] = forwardLatency(node_i,node_j,time,... 54 | contactSequence,directed,contactTimes,nNodes); 55 | 56 | end 57 | 58 | tau_vec(node_j) = tau; 59 | 60 | end 61 | 62 | Cc = (1/(nNodes-1)) * sum(1./tau_vec); 63 | 64 | 65 | end 66 | 67 | -------------------------------------------------------------------------------- /forwardLatency.m: -------------------------------------------------------------------------------- 1 | function [ tau ] = forwardLatency(node_i,node_j,time,... 2 | contactSequence,directed,contactTimes,nNodes) 3 | % Calculate the forward latency of a node at a given time. 4 | % 5 | % Inputs: 6 | % node_i = starting node 7 | % node_j = final node 8 | % time = earliest time a path can begin 9 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 10 | % contact between nodes i,j at time t. 11 | % directed = 1 if network is directed, 0 if undirected. 12 | % Optional Inputs: 13 | % contactTimes = ascending vector of all possible contact times. Ex. 14 | % 1:20. Default assumes all possible times exist in 15 | % contactSequence. 16 | % nNodes = number of nodes total in dynamic network. Default assumes 17 | % all nodes are present in contactSequence. 18 | % 19 | % Output: 20 | % forwardLatency = the time it takes to reach node j from node i via 21 | % a time-respecting path beginning no earlier than the input 22 | % time. 23 | % 24 | % 25 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 26 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 27 | % 28 | % 29 | % 30 | % Main function: 31 | 32 | 33 | interval = [time inf]; 34 | 35 | if ~exist('contactTimes','var') || isempty(contactTimes); 36 | contactTimes = sort(unique(contactSequence(:,3)),'ascend'); 37 | end 38 | if ~exist('nNodes','var') || isempty(nNodes); 39 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 40 | end 41 | 42 | 43 | % use only times wihtin the given interval 44 | contactTimes(contactTimes < interval(1)) = []; 45 | contactTimes(contactTimes > interval(2)) = []; 46 | 47 | % Preallocate 48 | reachabilityArray = zeros(nNodes,nNodes,length(contactTimes)); 49 | pathLengthArray = zeros(nNodes,nNodes,length(contactTimes)); 50 | latencyArray = zeros(nNodes,nNodes,length(contactTimes)); 51 | lastContactTimeArray = zeros(nNodes,nNodes,length(contactTimes)); 52 | 53 | t = 1; 54 | maxt = length(contactTimes); 55 | tau = 0; 56 | 57 | while tau == 0 && t<=maxt 58 | 59 | t1 = contactTimes(t); 60 | 61 | 62 | % make binary matrix at this time 63 | badj = reachabilityAtTimeT(contactSequence,t1,directed,nNodes); 64 | [a1,b1] = find(badj); 65 | 66 | if t == 1 67 | if ~isempty(a1) 68 | for i = 1:length(a1) 69 | reachabilityArray(:,:,t) = badj; 70 | pathLengthArray(a1(i),b1(i),t) = 1; 71 | latencyArray(a1(i),b1(i),t) = 0; 72 | lastContactTimeArray(a1(i),b1(i),t) = t1; 73 | end 74 | end 75 | else 76 | 77 | newSlice = reachabilityArray(:,:,(t-1))*badj; 78 | reachabilityArray(:,:,t) = newSlice + badj + ... 79 | reachabilityArray(:,:,(t-1)); 80 | 81 | reachabilityArray(reachabilityArray>0) = 1; 82 | 83 | % record/update latency 84 | % assume it takes no time to traverse a path, so latency between 85 | % directly connected nodes is 0 -- but we will subtract this out at the 86 | % end so for now it is 1. 87 | 88 | % Next, for all new paths of length >1 (recorded in newSlice), we need 89 | % to update latencies if necessary. 90 | 91 | [a,b] = find(newSlice); 92 | newPathPairs = [a b]; 93 | 94 | % Bring forward old information to later update. 95 | latencyArray(:,:,t) = latencyArray(:,:,t-1); 96 | pathLengthArray(:,:,t) = pathLengthArray(:,:,t-1); 97 | lastContactTimeArray(:,:,t) = lastContactTimeArray(:,:,t-1); 98 | 99 | 100 | % Update node pairs with direct contacts at this time t 101 | if ~isempty(a1) 102 | for i = 1:length(a1) 103 | 104 | pathLengthArray(a1(i),b1(i),t) = 1; 105 | latencyArray(a1(i),b1(i),t) = 0; 106 | lastContactTimeArray(a1(i),b1(i),t) = t1; 107 | 108 | end 109 | end 110 | 111 | % Update node pairs with a new time-respecting path connection 112 | if ~isempty(a) 113 | for i1 = 1:size(newPathPairs,1) 114 | % vector for node i 115 | v_i = reachabilityArray(newPathPairs(i1,1),:,(t-1)); 116 | 117 | % vector for node j 118 | v_j = badj(:,newPathPairs(i1,2)); 119 | 120 | % want only indices where both v_i and v_j are nonzero 121 | inds = find(v_i.*v_j'); 122 | 123 | % new latency will be the minimum of v_i plus the time step 124 | newPathLength = min(pathLengthArray(newPathPairs(i1,1),inds,t-1)) + 1; 125 | newLatency = t1-max(lastContactTimeArray(newPathPairs(i1,1),inds,t-1) - ... 126 | latencyArray(newPathPairs(i1,1),inds,t-1)); 127 | 128 | % update! 129 | latencyArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = ... 130 | newLatency; 131 | pathLengthArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = ... 132 | newPathLength; 133 | lastContactTimeArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = t1; 134 | 135 | end 136 | 137 | 138 | end 139 | 140 | end 141 | 142 | 143 | 144 | tau = lastContactTimeArray(node_i,node_j,t); 145 | 146 | t = t+1; 147 | 148 | 149 | 150 | 151 | 152 | end 153 | 154 | 155 | 156 | latencyArray(pathLengthArray == 0) = inf; 157 | lastContactTimeArray(pathLengthArray == 0) = -inf; 158 | pathLengthArray(pathLengthArray == 0) = inf; 159 | 160 | 161 | tau = tau - time; 162 | 163 | % more correct for forward latency to be inf for disconnected pairs. 164 | if tau == 0 && t1 ~= time 165 | tau = inf; 166 | end 167 | 168 | if tau < 0 169 | tau = inf; 170 | end 171 | 172 | end 173 | 174 | -------------------------------------------------------------------------------- /forwardLatencyComputations.m: -------------------------------------------------------------------------------- 1 | function [ forwardLatency, latencyArray, lastContactTimeArray, pathLengthArray ] = ... 2 | forwardLatencyComputations(node_i,node_j,time,contactSequence,directed,... 3 | contactTimes,nNodes) 4 | % Calculate and record statstics for time respecting paths and connectivity. 5 | % 6 | % Inputs: 7 | % node_i = 8 | % node_j = 9 | % time = 10 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 11 | % contact between nodes i,j at time t. 12 | % directed = 1 if network is directed, 0 if undirected. 13 | % Optional Inputs: 14 | % contactTimes = ascending vector of all possible contact times. Ex. 15 | % 1:20. Default assumes all possible times exist in 16 | % contactSequence. 17 | % nNodes = number of nodes total in dynamic network. Default assumes 18 | % all nodes are present in contactSequence. 19 | % 20 | % Output: 21 | % latencyArray = nNodes x nNodes x nContactTimes recording the 22 | % latency between node pairs at each contact time. 23 | % lastContactTimeArray = nNodes x nNodes x nContactTimes recording 24 | % the last time node a time-respecting path from node i reached 25 | % node j. 26 | % pathLengthArray = nNodes x nNodes x nContactTimes recording number 27 | % of edges in the most recent time-respecting path from node i to 28 | % node j. 29 | % 30 | % 31 | % Notes: this code updates the above arrays at each time point, so to find 32 | % the minimum latency, for example, simply take the minimum value across 33 | % time. 34 | % 35 | % 36 | % 37 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 38 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 39 | % 40 | % Main function: 41 | 42 | 43 | interval = [time inf]; 44 | 45 | if ~exist('contactTimes','var') || isempty(contactTimes); 46 | contactTimes = sort(unique(contactSequence(:,3)),'ascend'); 47 | end 48 | if ~exist('nNodes','var') || isempty(nNodes); 49 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 50 | end 51 | 52 | 53 | % use only times wihtin the given interval 54 | contactTimes(contactTimes < interval(1)) = []; 55 | contactTimes(contactTimes > interval(2)) = []; 56 | 57 | % Preallocate 58 | reachabilityArray = zeros(nNodes,nNodes,length(contactTimes)); 59 | pathLengthArray = zeros(nNodes,nNodes,length(contactTimes)); 60 | latencyArray = zeros(nNodes,nNodes,length(contactTimes)); 61 | lastContactTimeArray = zeros(nNodes,nNodes,length(contactTimes)); 62 | 63 | t = 1; 64 | maxt = length(contactTimes); 65 | forwardLatency = 0; 66 | 67 | while forwardLatency == 0 && t<=maxt 68 | 69 | t1 = contactTimes(t); 70 | 71 | 72 | % make binary matrix at this time 73 | badj = reachabilityAtTimeT(contactSequence,t1,directed,nNodes); 74 | [a1,b1] = find(badj); 75 | 76 | if t == 1 77 | if ~isempty(a1) 78 | for i = 1:length(a1) 79 | reachabilityArray(:,:,t) = badj; 80 | pathLengthArray(a1(i),b1(i),t) = 1; 81 | latencyArray(a1(i),b1(i),t) = 0; 82 | lastContactTimeArray(a1(i),b1(i),t) = t1; 83 | end 84 | end 85 | else 86 | 87 | newSlice = reachabilityArray(:,:,(t-1))*badj; 88 | reachabilityArray(:,:,t) = newSlice + badj + ... 89 | reachabilityArray(:,:,(t-1)); 90 | 91 | reachabilityArray(reachabilityArray>0) = 1; 92 | 93 | % record/update latency 94 | % assume it takes no time to traverse a path, so latency between 95 | % directly connected nodes is 0 -- but we will subtract this out at the 96 | % end so for now it is 1. 97 | 98 | % Next, for all new paths of length >1 (recorded in newSlice), we need 99 | % to update latencies if necessary. 100 | 101 | [a,b] = find(newSlice); 102 | newPathPairs = [a b]; 103 | 104 | % Bring forward old information to later update. 105 | latencyArray(:,:,t) = latencyArray(:,:,t-1); 106 | pathLengthArray(:,:,t) = pathLengthArray(:,:,t-1); 107 | lastContactTimeArray(:,:,t) = lastContactTimeArray(:,:,t-1); 108 | 109 | 110 | % Update node pairs with direct contacts at this time t 111 | if ~isempty(a1) 112 | for i = 1:length(a1) 113 | 114 | pathLengthArray(a1(i),b1(i),t) = 1; 115 | latencyArray(a1(i),b1(i),t) = 0; 116 | lastContactTimeArray(a1(i),b1(i),t) = t1; 117 | 118 | end 119 | end 120 | 121 | % Update node pairs with a new time-respecting path connection 122 | if ~isempty(a) 123 | for i1 = 1:size(newPathPairs,1) 124 | % vector for node i 125 | v_i = reachabilityArray(newPathPairs(i1,1),:,(t-1)); 126 | 127 | % vector for node j 128 | v_j = badj(:,newPathPairs(i1,2)); 129 | 130 | % want only indices where both v_i and v_j are nonzero 131 | inds = find(v_i.*v_j'); 132 | 133 | % new latency will be the minimum of v_i plus the time step 134 | newPathLength = min(pathLengthArray(newPathPairs(i1,1),inds,t-1)) + 1; 135 | newLatency = t1-max(lastContactTimeArray(newPathPairs(i1,1),inds,t-1) - ... 136 | latencyArray(newPathPairs(i1,1),inds,t-1)); 137 | 138 | % update! 139 | latencyArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = ... 140 | newLatency; 141 | pathLengthArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = ... 142 | newPathLength; 143 | lastContactTimeArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = t1; 144 | 145 | end 146 | 147 | 148 | end 149 | 150 | end 151 | 152 | 153 | 154 | forwardLatency = lastContactTimeArray(node_i,node_j,t); 155 | 156 | t = t+1; 157 | 158 | 159 | 160 | 161 | 162 | end 163 | 164 | 165 | 166 | latencyArray(pathLengthArray == 0) = inf; 167 | lastContactTimeArray(pathLengthArray == 0) = -inf; 168 | pathLengthArray(pathLengthArray == 0) = inf; 169 | 170 | 171 | end 172 | 173 | -------------------------------------------------------------------------------- /informationLatency.m: -------------------------------------------------------------------------------- 1 | function [ phi, lambda] = informationLatency(node_i,node_j,time,contactSequence,... 2 | directed,interval,contactTimes,nNodes) 3 | % Return node_i's view of node_j's information at a particular time. 4 | % 5 | % Inputs: 6 | % node_i = node receiving information 7 | % node_j = node sending information 8 | % time = time at which to measure node i's view of node j's 9 | % information. 10 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 11 | % contact between nodes i,j at time t. 12 | % directed = 1 if network is directed, 0 if undirected. 13 | % Optional Inputs: 14 | % interval = 1 x 2 vector containing desired start and end points for 15 | % the calculation. Default is [-inf inf]. 16 | % contactTimes = ascending vector of all possible contact times. Ex. 17 | % 1:20. Default assumes all possible times exist in 18 | % contactSequence. 19 | % nNodes = number of nodes total in dynamic network. Default assumes 20 | % all nodes are present in contactSequence. 21 | % 22 | % Output: 23 | % phi = the last point at which information from node j reached node 24 | % i. 25 | % lambda = time - phi 26 | % 27 | % 28 | % 29 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 30 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 31 | % 32 | % Main function: 33 | 34 | 35 | if ~exist('interval','var') || isempty(interval); 36 | interval = [-inf inf]; 37 | end 38 | if ~exist('contactTimes','var') || isempty(contactTimes); 39 | contactTimes = sort(unique(contactSequence(:,3)),'ascend'); 40 | end 41 | if ~exist('nNodes','var') || isempty(nNodes); 42 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 43 | end 44 | 45 | 46 | 47 | [~, lastContactTimeArray] = latencyComputations(contactSequence,directed,... 48 | interval,contactTimes,nNodes); 49 | 50 | 51 | point = find(contactTimes interval(2),:) = []; 45 | 46 | [latencyMatrix,lastContactTimes,pathLengthMatrix] = ... 47 | latencyComputations(contactSequence,directed,... 48 | interval,contactTimes,nNodes); 49 | 50 | l = min(latencyMatrix(node_i,node_j,:)); 51 | 52 | % find the first point at which the latency was minimal. 53 | time = find(latencyMatrix(node_i,node_j,:) == l,1,'first'); 54 | 55 | lastContact = lastContactTimes(node_i,node_j,time); 56 | pathLength = pathLengthMatrix(node_i,node_j,time); 57 | 58 | 59 | end 60 | 61 | -------------------------------------------------------------------------------- /latencyComputations.m: -------------------------------------------------------------------------------- 1 | function [ latencyArray, lastContactTimeArray, pathLengthArray ] = ... 2 | latencyComputations(contactSequence,directed,interval,... 3 | contactTimes,nNodes) 4 | % Calculate and record statstics for time respecting paths and connectivity. 5 | % 6 | % Inputs: 7 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 8 | % contact between nodes i,j at time t. 9 | % directed = 1 if network is directed, 0 if undirected. 10 | % Optional Inputs: 11 | % interval = 1 x 2 vector containing desired start and end points for 12 | % the calculation. Default is [-inf inf]. 13 | % contactTimes = ascending vector of all possible contact times. Ex. 14 | % 1:20. Default assumes all possible times exist in 15 | % contactSequence. 16 | % nNodes = number of nodes total in dynamic network. Default assumes 17 | % all nodes are present in contactSequence. 18 | % 19 | % Output: 20 | % latencyArray = nNodes x nNodes x nContactTimes recording the 21 | % latency between node pairs at each contact time. 22 | % lastContactTimeArray = nNodes x nNodes x nContactTimes recording 23 | % the last time node a time-respecting path from node i reached 24 | % node j. 25 | % pathLengthArray = nNodes x nNodes x nContactTimes recording number 26 | % of edges in the most recent time-respecting path from node i to 27 | % node j. 28 | % 29 | % 30 | % Notes: this code updates the above arrays at each time point, so to find 31 | % the minimum latency, for example, simply take the minimum value across 32 | % time. 33 | % 34 | % 35 | % 36 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 37 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 38 | % 39 | % Main function: 40 | 41 | if ~exist('interval','var') || isempty(interval); 42 | interval = [-inf inf]; 43 | end 44 | if ~exist('contactTimes','var') || isempty(contactTimes); 45 | contactTimes = sort(unique(contactSequence(:,3)),'ascend'); 46 | end 47 | if ~exist('nNodes','var') || isempty(nNodes); 48 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 49 | end 50 | 51 | 52 | % use only times wihtin the given interval 53 | contactTimes(contactTimes < interval(1)) = []; 54 | contactTimes(contactTimes > interval(2)) = []; 55 | 56 | % Preallocate 57 | reachabilityArray = zeros(nNodes,nNodes,length(contactTimes)); 58 | pathLengthArray = zeros(nNodes,nNodes,length(contactTimes)); 59 | latencyArray = zeros(nNodes,nNodes,length(contactTimes)); 60 | lastContactTimeArray = zeros(nNodes,nNodes,length(contactTimes)); 61 | 62 | for t = 1:length(contactTimes) 63 | 64 | t1 = contactTimes(t); 65 | 66 | 67 | % make binary matrix at this time 68 | badj = reachabilityAtTimeT(contactSequence,t1,directed,nNodes); 69 | [a1,b1] = find(badj); 70 | 71 | if t == 1 72 | if ~isempty(a1) 73 | for i = 1:length(a1) 74 | reachabilityArray(:,:,t) = badj; 75 | pathLengthArray(a1(i),b1(i),t) = 1; 76 | latencyArray(a1(i),b1(i),t) = 0; 77 | lastContactTimeArray(a1(i),b1(i),t) = t1; 78 | end 79 | end 80 | else 81 | 82 | newSlice = reachabilityArray(:,:,(t-1))*badj; 83 | reachabilityArray(:,:,t) = newSlice + badj + ... 84 | reachabilityArray(:,:,(t-1)); 85 | 86 | reachabilityArray(reachabilityArray>0) = 1; 87 | 88 | % record/update latency 89 | % assume it takes no time to traverse a path, so latency between 90 | % directly connected nodes is 0 -- but we will subtract this out at the 91 | % end so for now it is 1. 92 | 93 | % Next, for all new paths of length >1 (recorded in newSlice), we need 94 | % to update latencies if necessary. 95 | 96 | [a,b] = find(newSlice); 97 | newPathPairs = [a b]; 98 | 99 | % Bring forward old information to later update. 100 | latencyArray(:,:,t) = latencyArray(:,:,t-1); 101 | pathLengthArray(:,:,t) = pathLengthArray(:,:,t-1); 102 | lastContactTimeArray(:,:,t) = lastContactTimeArray(:,:,t-1); 103 | 104 | 105 | % Update node pairs with direct contacts at this time t 106 | if ~isempty(a1) 107 | for i = 1:length(a1) 108 | 109 | pathLengthArray(a1(i),b1(i),t) = 1; 110 | latencyArray(a1(i),b1(i),t) = 0; 111 | lastContactTimeArray(a1(i),b1(i),t) = t1; 112 | 113 | end 114 | end 115 | 116 | % Update node pairs with a new time-respecting path connection 117 | if ~isempty(a) 118 | for i1 = 1:size(newPathPairs,1) 119 | % vector for node i 120 | v_i = reachabilityArray(newPathPairs(i1,1),:,(t-1)); 121 | 122 | % vector for node j 123 | v_j = badj(:,newPathPairs(i1,2)); 124 | 125 | % want only indices where both v_i and v_j are nonzero 126 | inds = find(v_i.*v_j'); 127 | 128 | % new latency will be the minimum of v_i plus the time step 129 | newPathLength = min(pathLengthArray(newPathPairs(i1,1),inds,t-1)) + 1; 130 | newLatency = t1-max(lastContactTimeArray(newPathPairs(i1,1),inds,t-1) - ... 131 | latencyArray(newPathPairs(i1,1),inds,t-1)); 132 | 133 | % update! 134 | latencyArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = ... 135 | newLatency; 136 | pathLengthArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = ... 137 | newPathLength; 138 | lastContactTimeArray(newPathPairs(i1,1),newPathPairs(i1,2),t) = t1; 139 | 140 | end 141 | 142 | 143 | end 144 | 145 | end 146 | 147 | 148 | end 149 | 150 | 151 | latencyArray(pathLengthArray == 0) = inf; 152 | lastContactTimeArray(pathLengthArray == 0) = -inf; 153 | pathLengthArray(pathLengthArray == 0) = inf; 154 | 155 | end 156 | 157 | -------------------------------------------------------------------------------- /listAllMotifs.m: -------------------------------------------------------------------------------- 1 | function [ motifs ] = listAllMotifs( contactSequence, directed, T, nNodes ) 2 | % listAllMotifs returns all motifs (here defined as time-respecting paths 3 | % which visit a new node at each time point) of length >=2 in a dynamic 4 | % network. 5 | % 6 | % Inputs: 7 | % contactSequence = nEdges x 3 matrix encoding contacts between node 8 | % i,j at time t by (i,j,t). 9 | % directed = 1 for creating a directed network, 0 otherwise. 10 | % 11 | % Optional Inputs: 12 | % T = the last time at which to use for the calculation. Default is 13 | % last time within the contactSequence. 14 | % nNodes = number of nodes in the network. Default includes all nodes 15 | % with a connection in contactSequence. 16 | % 17 | % Outputs: 18 | % motifs = T+1 x nNodes x nPaths array recording at entry (t,n,p) the 19 | % node at which motif p is visiting at time t-1. 20 | % 21 | % Notes: This function requires a good deal of time/memory for most dynamic 22 | % networks. Not recommended for large or dense dynamic networks. 23 | % 24 | % Main function: 25 | 26 | disp('starting code') 27 | tic 28 | % first need to find all three-node adjacent paths 29 | largeNumber = 100; % for preallocation only 30 | adjArray = networksFromContacts(contactSequence,directed); 31 | motifs = zeros(T+1,nNodes,largeNumber); 32 | nmotifs = 1; 33 | for t = 1:T-1 34 | 35 | g1 = adjArray(:,:,t); 36 | g2 = adjArray(:,:,t+1); 37 | 38 | % first we want to see which paths will exist at t+1 39 | g_12 = g1*g2; 40 | 41 | [pathFrom,pathTo] = find(g_12); 42 | 43 | % Now we have nodes from which path began and where it ends 44 | % Iterate through these to find the middle node 45 | if ~isempty(pathFrom) 46 | for p = 1:length(pathFrom) 47 | 48 | middleNode = find(g1(pathFrom(p),:).*g2(:,pathTo(p))'); 49 | % This is the middle node in a connected path 50 | 51 | for m = 1:length(middleNode) 52 | % need to store all of this in an effective way 53 | motifs(t,pathFrom(p),nmotifs) = 1; 54 | motifs(t+1,middleNode(m),nmotifs) = 1; 55 | motifs(t+2,pathTo(p),nmotifs) = 1; 56 | 57 | nmotifs = nmotifs+1; 58 | 59 | end 60 | 61 | end 62 | end 63 | 64 | 65 | end 66 | 67 | keeps = find(squeeze(sum(sum(motifs)))); 68 | motifs = motifs(:,:,keeps); 69 | 70 | 71 | % Now we need to glue these motif parts together. 72 | 73 | motifsLenK = motifs; 74 | 75 | 76 | for len = 4:nNodes 77 | 78 | toGlue = (sum(motifsLenK,3)>=2); 79 | [glueTime,glueingNode] = find(toGlue); 80 | 81 | gluedMotifs = zeros(T+1,nNodes,largeNumber); 82 | ngluedmotifs = 1; 83 | 84 | for g = 1:length(glueTime) 85 | 86 | % make sure these both aren't at the start of paths 87 | ps = find(motifsLenK(glueTime(g),glueingNode(g),:)); 88 | 89 | 90 | for p1 = 1:length(ps)-1 91 | for p2 = p1+1:length(ps) 92 | 93 | % We need to know which path begins first 94 | t1 = find(sum(motifsLenK(:,:,ps(p1)),2),1); 95 | t2 = find(sum(motifsLenK(:,:,ps(p2)),2),1); 96 | % only want to add one contact at a time 97 | if abs(t1-t2)==1 98 | if t1 < t2 99 | % then we need to glue the first part of the p1 to the 100 | % second of p2 101 | 102 | newmot = [motifsLenK(1:glueTime(g),:,ps(p1)); ... 103 | motifsLenK(glueTime(g)+1:end,:,ps(p2))]; 104 | 105 | if nnz(newmot) == len 106 | gluedMotifs(:,:,ngluedmotifs) = newmot; 107 | ngluedmotifs = ngluedmotifs+1; 108 | 109 | end 110 | 111 | 112 | elseif t1 > t2 113 | % then glue the first part of p2 to second part of p1 114 | newmot = [motifsLenK(1:glueTime(g),:,ps(p2)); ... 115 | motifsLenK(glueTime(g)+1:end,:,ps(p1))]; 116 | 117 | if nnz(newmot)==len 118 | gluedMotifs(:,:,ngluedmotifs) = newmot; 119 | ngluedmotifs = ngluedmotifs+1; 120 | 121 | end 122 | 123 | 124 | end 125 | end 126 | 127 | 128 | end 129 | end 130 | 131 | end 132 | 133 | % remove unused preallocated paths 134 | keeps = find(squeeze(sum(sum(gluedMotifs)))); 135 | gluedMotifs = gluedMotifs(:,:,keeps); 136 | gluedMotifs = uniqueArray(gluedMotifs,len); 137 | motifs = cat(3,motifs,gluedMotifs); 138 | 139 | % update with newest motifs of length len 140 | motifsLenK = gluedMotifs; 141 | fprintf('Found %d new paths of length %d\n',ngluedmotifs-1,len) 142 | end 143 | 144 | 145 | toc 146 | 147 | end 148 | 149 | -------------------------------------------------------------------------------- /makeReachabilityArray.m: -------------------------------------------------------------------------------- 1 | function [ reachabilityArray ] = makeReachabilityArray(contactSequence,... 2 | directed,contactTimes,nNodes) 3 | % Create an array encoding time-respecting paths between nodes 4 | % 5 | % Inputs: 6 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 7 | % contact between nodes i,j at time t. 8 | % directed = 1 if network is directed, 0 if undirected. 9 | % Optional Inputs: 10 | % contactTimes = ascending vector of all possible contact times. Ex. 11 | % 1:20. Default assumes all possible times exist in 12 | % contactSequence. 13 | % nNodes = number of nodes total in dynamic network. Default assumes 14 | % all nodes are present in contactSequence. 15 | % 16 | % Output: 17 | % reachabilityArray = nNodes x nNodes x nContactTimes binary array 18 | % recording if node j can be reached from node i via a 19 | % time-respecting path up to that time index. 20 | % 21 | % 22 | % 23 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 24 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 25 | % 26 | % Main function: 27 | 28 | if ~exist('contactTimes','var') || isempty(contactTimes); 29 | contactTimes = sort(unique(contactSequence(:,3)),'ascend'); 30 | end 31 | if ~exist('nNodes','var') || isempty(nNodes); 32 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 33 | end 34 | 35 | % Preallocate 36 | reachabilityArray = zeros(nNodes,nNodes,length(contactTimes)); 37 | 38 | 39 | for t = 1:length(contactTimes) 40 | 41 | t1 = contactTimes(t); 42 | 43 | 44 | % make binary matrix at this time 45 | badj = reachabilityAtTimeT(contactSequence,t1,directed,nNodes); 46 | 47 | if t == 1 48 | reachabilityArray(:,:,t) = badj; 49 | else 50 | 51 | newSlice = reachabilityArray(:,:,(t-1))*badj; 52 | 53 | reachabilityArray(:,:,t) = newSlice + badj + ... 54 | reachabilityArray(:,:,(t-1)); 55 | 56 | reachabilityArray(reachabilityArray>0) = 1; 57 | 58 | end 59 | 60 | 61 | end 62 | 63 | 64 | 65 | end 66 | 67 | -------------------------------------------------------------------------------- /networksFromContacts.m: -------------------------------------------------------------------------------- 1 | function [ adjArray ] = networksFromContacts(contactSequence,directed) 2 | % networksFromContacts creates an array of networks (weighted or binary) 3 | % from a contact sequence. 4 | % 5 | % Input: 6 | % contactSequence = nEdges x 3 matrix encoding contacts between node 7 | % i,j at time t by (i,j,t). Optionally a fourth column denotes 8 | % edge weight. 9 | % directed = 1 for creating a directed network, 0 otherwise. 10 | % 11 | % 12 | % Output: 13 | % adjArray = nNodes x nNodes x nTimes array describing binary or 14 | % weighted network at each time point. 15 | % 16 | % 17 | % 18 | % 19 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 20 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 21 | % 22 | % 23 | % Main function: 24 | 25 | times = unique(contactSequence(:,3)); 26 | 27 | nNodes = length(unique([contactSequence(:,1) ; contactSequence(:,2)])); 28 | adjArray = zeros(nNodes,nNodes,length(times)); 29 | if size(contactSequence,2) == 3 30 | edgeWeights = ones(size(contactSequence,1),1); 31 | else 32 | edgeWeights = contactSequence(:,4); 33 | end 34 | 35 | 36 | for t = 1:length(times) 37 | 38 | edges = find(contactSequence(:,3) == times(t)); 39 | 40 | nodes = contactSequence(edges,1:2); 41 | 42 | for i = 1:size(nodes,1) 43 | 44 | if size(nodes,1) == 1 45 | adjArray(nodes(1),nodes(2),t) = edgeWeights(edges(i)); 46 | if ~directed 47 | adjArray(nodes(2),nodes(1),t) = edgeWeights(edges(i)); 48 | end 49 | 50 | else 51 | adjArray(nodes(i,1),nodes(i,2),t) = edgeWeights(edges(i)); 52 | if ~directed 53 | adjArray(nodes(i,2),nodes(i,1),t) = edgeWeights(edges(i)); 54 | end 55 | 56 | end 57 | 58 | end 59 | 60 | 61 | 62 | end 63 | 64 | 65 | 66 | end 67 | 68 | -------------------------------------------------------------------------------- /plotArcNetwork.m: -------------------------------------------------------------------------------- 1 | function plotArcNetwork(adj,nodeColor,edgeColor) 2 | %plotArcNetwork plots a weighted network in a circle with the edges shown 3 | %as colored arcs 4 | 5 | % Inputs 6 | % adj = weighted adjacency matrix. 7 | % nodeColor = 1 x 3 vector specifying node color 8 | % edgeColor = 1 x 3 vector specifying edge color for the maximally 9 | % weighted edge. Edge colors are determined by a gradient from gray to 10 | % edgeColor and colors edge by ranking. Will plot the line 11 | % thickness according to the actual edge weight. 12 | % 13 | % 14 | % 15 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 16 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 17 | % 18 | 19 | %% Circle plot 20 | 21 | t = linspace(-pi,pi,10001); 22 | 23 | npoints = size(adj,1); 24 | pos = linspace(-pi+0.3,pi+0.3,npoints+1); 25 | 26 | if ~isempty(find(adj~=adj', 1)) 27 | disp('network is not symmetric. Symmetrizing...') 28 | adj = adj+adj'; 29 | adj = 0.5*adj; 30 | end 31 | 32 | % add a tiny bit of noise to get unique edge weights 33 | Adj = adj; 34 | for i = 1:length(adj) 35 | for j = i+1:length(adj) 36 | 37 | if Adj(i,j)>0 38 | Adj(i,j) = Adj(i,j) + 0.000001*rand; 39 | Adj(j,i) = Adj(i,j); 40 | end 41 | 42 | end 43 | end 44 | 45 | Edges_1 = sort(unique(Adj(:)),'descend'); 46 | Edges = zeros(length(Edges_1),2); 47 | nedges = 0.5*nnz(Adj); 48 | for k = 1:length(Edges_1) 49 | find(Adj==Edges_1(k)); 50 | [j,h] = find(Adj==Edges_1(k)); 51 | Edges(k,1) = j(1); 52 | Edges(k,2) = h(1); 53 | end 54 | 55 | lw = linspace(3,0.3,nedges); 56 | gradient = [linspace(edgeColor(1),0.8,nedges)' linspace(edgeColor(2),0.8,nedges)' linspace(edgeColor(3),0.8,nedges)']; 57 | 58 | %figure('Color',[1 1 1]) 59 | for i = 1:size(Edges,1) 60 | 61 | edge = Edges(i,:); % 'edge' contains end nodes 62 | edge = sort(edge,'ascend'); 63 | 64 | if adj(edge(1),edge(2))>0 65 | 66 | % Get node positions (x1,y1) and (x2,y2) 67 | y1 = sin(pos(edge(1))); 68 | x1 = cos(pos(edge(1))); 69 | 70 | y2 = sin(pos(edge(2))); 71 | x2 = cos(pos(edge(2))); 72 | 73 | 74 | % Calculate the center of the circle which is perpendicular to the 75 | % large, outer circle at points (x1,y1) and (x2,y2). The center of 76 | % this smaller circle will be called 77 | % (xx,yy). 78 | 79 | m1 = -x1/y1; 80 | m2 = -x2/y2; 81 | 82 | xx = (m1*x1-y1-m2*x2+y2)/(m1-m2); 83 | yy = m1*(xx-x1)+y1; 84 | 85 | % Will have radius r = distance from (x1,y1) to (xx,yy) 86 | r = sqrt((x1-xx)^2 + (y1-yy)^2); 87 | 88 | % plot! 89 | plot(r*cos(t)+xx,r*sin(t)+yy,'Color',gradient(i,:),'LineWidth',lw(i)) 90 | hold on 91 | end % finished plotting one edge 92 | end % finished plotting all edges 93 | 94 | % Cover up edges outside our circle 95 | xout = 15*cos(t); 96 | yout = 15*sin(t); 97 | patch([xout,cos(t)],[yout,sin(t)],'w','facealpha',1,'EdgeColor','w') 98 | 99 | 100 | plot(cos(t),sin(t),'Color',[.67 .67 .67],'LineWidth',3) 101 | 102 | plot(cos(pos),sin(pos),'.','Color',nodeColor,'MarkerSize',20) 103 | axis([-1 1 -1 1]) 104 | axis square 105 | axis off 106 | grid off 107 | end 108 | 109 | -------------------------------------------------------------------------------- /plotDNarc.m: -------------------------------------------------------------------------------- 1 | function [ nodeColors ] = plotDNarc( contactSequence, nNodes, timeInterval) 2 | % Create a line plot showing contacts across time. Node colors assigned 3 | % randomly. 4 | % 5 | % Input: 6 | % contactSequence = nEdges x 3 array of contacts (i,j,t) 7 | % 8 | % Optional Input: 9 | % nNodes = number of nodes total in dynamic network. Default assumes 10 | % all nodes are present in contactSequence. 11 | % timeInterval = start and end time of network. Default assumes the 12 | % initial time is at the time of first contact and end time is at 13 | % the last contact. 14 | % 15 | % Output: 16 | % nodeColors = nNodes x 3 array of node colors. 17 | % 18 | % Inspiration from Holme and Saramaki, "Temporal Networks" 2011. 19 | % 20 | % 21 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 22 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 23 | % 24 | % Main function: 25 | 26 | if ~exist('nNodes','var') || isempty(nNodes); 27 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 28 | end 29 | if ~exist('timeInterval','var') || isempty(timeInterval) 30 | timeInterval = [min(contactSequence(:,3)) max(contactSequence(:,3))]; 31 | end 32 | 33 | 34 | nEdges = size(contactSequence,1); 35 | % draw gray lines for each of the nodes 36 | for n = 1:nNodes 37 | plot([min(timeInterval) max(timeInterval)],[n n],'-',... 38 | 'Color',[.75 .75 .75],'LineWidth',1.5) 39 | hold on 40 | end 41 | 42 | axis([min(timeInterval)-1 max(timeInterval)+1 0.5 nNodes]) 43 | a = axis; %// get axis size 44 | plot([a(1) a(2)],[a(3) a(3)],'w','LineWidth',1); %// plot white line over x axis 45 | plot([a(1) a(1)],[a(3) a(4)],'w','LineWidth',1); %// plot white line over y axis 46 | 47 | 48 | % draw contacts (black) 49 | for edges = 1:nEdges 50 | 51 | t = contactSequence(edges,3); 52 | a = 1; 53 | b = abs(contactSequence(edges,1) - contactSequence(edges,2)); 54 | theta = linspace(-pi/2,pi/2,100); 55 | ys = 0.5*(1+(sin(theta))); 56 | plot(t + 0.7*(cos(theta).^2), ... 57 | min(contactSequence(edges,1:2)) + b*ys,'k-') 58 | %plot([t t],[contactSequence(edges,1) contactSequence(edges,2)],... 59 | % 'k-') 60 | end 61 | 62 | %axis off 63 | 64 | % each node needs a color 65 | nodeColors = rand(nNodes,3); 66 | for n = 1:nNodes 67 | 68 | times1 = contactSequence(contactSequence(:,1) == n,3); 69 | times2 = contactSequence(contactSequence(:,2) == n,3); 70 | 71 | plot([times1' times2'], n*ones(1,length([times1' times2'])),'.',... 72 | 'Color',nodeColors(n,:),'MarkerSize',30); 73 | plot(min(timeInterval)-0.8,n,'.','Color',nodeColors(n,:),'MarkerSize',30) 74 | end 75 | 76 | box off 77 | ax = gca; 78 | ax.TickLength = [0 0]; 79 | xlabel('Time') 80 | ax.XTick = timeInterval(1):timeInterval(2); 81 | ax.YTick = 1:nNodes; 82 | set(gcf,'Position',[0 0 1100 400]) 83 | ylabel('Nodes') 84 | end 85 | 86 | -------------------------------------------------------------------------------- /plotDNarc_dir.m: -------------------------------------------------------------------------------- 1 | function [ nodeColors ] = plotDNarc_dir( contactSequence, nNodes, ... 2 | timeInterval) 3 | % create a line plot showing contacts across time. Node colors assigned 4 | % randomly. 5 | % 6 | % Input: 7 | % contactSequence = nEdges x 3 array of contacts (i,j,t) 8 | % 9 | % Optional Input: 10 | % nNodes = number of nodes total in dynamic network. Default assumes 11 | % all nodes are present in contactSequence. 12 | % timeInterval = start and end time of network. Default assumes the 13 | % initial time is at the time of first contact and end time is at 14 | % the last contact. 15 | % 16 | % Output: 17 | % nodeColors = nNodes x 3 array of node colors. 18 | % 19 | % Inspiration from Holme and Saramaki, "Temporal Networks" 2011. 20 | % 21 | % 22 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 23 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 24 | % 25 | % Main function: 26 | 27 | if ~exist('nNodes','var') || isempty(nNodes); 28 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 29 | end 30 | if ~exist('timeInterval','var') || isempty(timeInterval) 31 | timeInterval = [min(contactSequence(:,3)) max(contactSequence(:,3))]; 32 | end 33 | 34 | 35 | nEdges = size(contactSequence,1); 36 | % draw gray lines for each of the nodes 37 | for n = 1:nNodes 38 | plot([min(timeInterval) max(timeInterval)],[n n],'-',... 39 | 'Color',[.75 .75 .75]) 40 | hold on 41 | end 42 | 43 | axis([min(timeInterval)-1 max(timeInterval)+1 0.5 nNodes]) 44 | a = axis; %// get axis size 45 | plot([a(1) a(2)],[a(3) a(3)],'w','LineWidth',1); %// plot white line over x axis 46 | plot([a(1) a(1)],[a(3) a(4)],'w','LineWidth',1); %// plot white line over y axis 47 | 48 | 49 | % draw contacts (black) 50 | for edges = 1:nEdges 51 | 52 | t = contactSequence(edges,3); 53 | a = 1; 54 | b = abs(contactSequence(edges,1) - contactSequence(edges,2)); 55 | theta = linspace(-pi/2,pi/2,101); 56 | ys = 0.5*(1+(sin(theta))); 57 | plot(t + 0.7*(cos(theta).^2), ... 58 | min(contactSequence(edges,1:2)) + b*ys,'k-') 59 | %plot([t t],[contactSequence(edges,1) contactSequence(edges,2)],... 60 | % 'k-') 61 | 62 | if contactSequence(edges,1) < contactSequence(edges,2) 63 | % then the arrow should be pointing up 64 | plot(t + 0.7*(cos(theta(51).^2)),... 65 | min(contactSequence(edges,1:2)) + b*ys(51),'k^',... 66 | 'MarkerFaceColor','k','MarkerSize',4) 67 | else 68 | % node 1 > node two and arrow should be pointing down 69 | plot(t + 0.7*(cos(theta(51).^2)),... 70 | min(contactSequence(edges,1:2)) + b*ys(51),'kv',... 71 | 'MarkerFaceColor','k','MarkerSize',4) 72 | end 73 | 74 | end 75 | 76 | %axis off 77 | 78 | % each node needs a color 79 | nodeColors = rand(nNodes,3); 80 | for n = 1:nNodes 81 | 82 | times1 = contactSequence(contactSequence(:,1) == n,3); 83 | times2 = contactSequence(contactSequence(:,2) == n,3); 84 | 85 | plot([times1' times2'], n*ones(1,length([times1' times2'])),'.',... 86 | 'Color',nodeColors(n,:),'MarkerSize',20); 87 | plot(min(timeInterval)-1,n,'.','Color',nodeColors(n,:),'MarkerSize',20) 88 | end 89 | 90 | box off 91 | ax = gca; 92 | ax.TickLength = [0 0]; 93 | xlabel('Time') 94 | ax.XTick = timeInterval(1):timeInterval(2); 95 | ax.YTick = 1:nNodes; 96 | set(gcf,'Position',[0 0 1100 400]) 97 | ylabel('Nodes') 98 | end 99 | 100 | -------------------------------------------------------------------------------- /plotDNline.m: -------------------------------------------------------------------------------- 1 | function [ nodeColors ] = plotDNline( contactSequence, nNodes, timeInterval) 2 | % Create a line plot showing contacts across time. Node colors assigned 3 | % randomly. 4 | % 5 | % Input: 6 | % contactSequence = nEdges x 3 array of contacts (i,j,t) 7 | % 8 | % Optional Input: 9 | % nNodes = number of nodes total in dynamic network. Default assumes 10 | % all nodes are present in contactSequence. 11 | % timeInterval = start and end time of network. Default assumes the 12 | % initial time is at the time of first contact and end time is at 13 | % the last contact. 14 | % 15 | % Output: 16 | % nodeColors = nNodes x 3 array of node colors. 17 | % 18 | % 19 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 20 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 21 | % 22 | 23 | % Main function: 24 | 25 | if ~exist('nNodes','var') || isempty(nNodes); 26 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 27 | end 28 | 29 | if ~exist('timeInterval','var') || isempty(timeInterval); 30 | timeInterval = [min(contactSequence(:,3)) max(contactSequence(:,3))]; 31 | end 32 | 33 | nEdges = size(contactSequence,1); 34 | % draw gray lines for each of the nodes 35 | for n = 1:nNodes 36 | plot([min(timeInterval) max(timeInterval)],[n n],'-',... 37 | 'Color',[.75 .75 .75]) 38 | hold on 39 | end 40 | 41 | axis([min(timeInterval)-1 max(timeInterval) 0.5 nNodes]) 42 | a = axis; %// get axis size 43 | plot([a(1) a(2)],[a(3) a(3)],'w','LineWidth',1); %// plot white line over x axis 44 | plot([a(1) a(1)],[a(3) a(4)],'w','LineWidth',1); %// plot white line over y axis 45 | 46 | 47 | % draw contacts (black) 48 | for edges = 1:nEdges 49 | t = contactSequence(edges,3); 50 | plot([t t],[contactSequence(edges,1) contactSequence(edges,2)],... 51 | 'k-') 52 | end 53 | 54 | %axis off 55 | 56 | % each node needs a color 57 | nodeColors = rand(nNodes,3); 58 | for n = 1:nNodes 59 | 60 | times1 = contactSequence(contactSequence(:,1) == n,3); 61 | times2 = contactSequence(contactSequence(:,2) == n,3); 62 | 63 | plot([times1' times2'], n*ones(1,length([times1' times2'])),'.',... 64 | 'Color',nodeColors(n,:),'MarkerSize',20); 65 | plot(min(timeInterval)-1,n,'.','Color',nodeColors(n,:),'MarkerSize',20) 66 | end 67 | 68 | box off 69 | ax = gca; 70 | ax.TickLength = [0 0]; 71 | xlabel('Time') 72 | ax.XTick = timeInterval(1):timeInterval(2); 73 | ax.YTick = 1:nNodes; 74 | set(gcf,'Position',[0 0 1100 400]) 75 | ylabel('Nodes') 76 | end 77 | 78 | -------------------------------------------------------------------------------- /randomDN.m: -------------------------------------------------------------------------------- 1 | function [ contactSequence ] = randomDN(nNodes,nEdges,edgeTimes) 2 | % Create a dynamic network with randomly connected nodes and random times. 3 | % 4 | % Inputs: 5 | % nNodes = number of nodes 6 | % nEdges = total number of connections 7 | % edgeTimes = 1 x nEdges vector of times a connection could occur. 8 | % ex: 1:20 9 | % 10 | % Outputs: 11 | % contactSequence = nEdges x 3 with row (i,j,t) a contact from node i 12 | % to node j at time t. 13 | % 14 | % 15 | % 16 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 17 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 18 | % 19 | % Main function: 20 | 21 | contactSequence = zeros(nEdges,3); 22 | 23 | % choose first nodes 24 | contactSequence(:,1) = randi(nNodes,nEdges,1); 25 | 26 | % choose second node (self edges not allowed) 27 | for n = 1:nEdges 28 | 29 | secondNode = randperm(nNodes,1); 30 | firstNodes = contactSequence(n,1); 31 | 32 | while secondNode == firstNodes 33 | secondNode = randperm(nNodes,1); 34 | end 35 | 36 | contactSequence(n,2) = secondNode; 37 | 38 | end 39 | 40 | % randomly assign times 41 | contactSequence(:,3) = randi(max(edgeTimes),nEdges,1); 42 | 43 | % sort by ascending contact time 44 | [~,idx] = sort(contactSequence(:,3)); 45 | contactSequence = contactSequence(idx,:); 46 | 47 | 48 | end 49 | 50 | -------------------------------------------------------------------------------- /randomPermutedTimes.m: -------------------------------------------------------------------------------- 1 | function [ rand_contactSequence ] = randomPermutedTimes(contactSequence) 2 | % randomPermutedTimes returns a randomized dynamic network from the input 3 | % contact sequence by randomly permuting the times of each contact. 4 | % 5 | % Input: 6 | % contactSequence = nEdges x 3 matrix encoding contacts between node 7 | % i,j at time t by (i,j,t). 8 | % 9 | % Output: 10 | % rand_contactSequence = contact sequence of randomized input data. 11 | % 12 | % 13 | % 14 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 15 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 16 | % 17 | % Main function: 18 | 19 | 20 | newOrder = randsample(size(contactSequence,1),size(contactSequence,1)); 21 | 22 | rand_contactSequence = contactSequence; 23 | rand_contactSequence(:,3) = rand_contactSequence(newOrder,3); 24 | 25 | 26 | end 27 | 28 | -------------------------------------------------------------------------------- /randomizedEdges.m: -------------------------------------------------------------------------------- 1 | function [ rand_contactSequence ] = randomizedEdges( contactSequence,repeats) 2 | % randomEdges returns a randomized dynamic network from the initial contact 3 | % sequence by randomly rewiring each edge. 4 | % 5 | % Inputs: 6 | % contactSequence = nEdges x 3 matrix encoding contacts between node 7 | % i,j at time t by (i,j,t). 8 | % repeats = number of times each edge should be rewired. 9 | % 10 | % Output: 11 | % rand_contactSequence = contact sequence of randomized input data. 12 | % 13 | % 14 | % 15 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 16 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 17 | % 18 | % Main function: 19 | 20 | nEdges = size(contactSequence,1); 21 | rand_contactSequence = contactSequence; 22 | 23 | for reps = 1:repeats 24 | for ed = 1:nEdges 25 | % take each edge and swap end nodes with another 26 | 27 | edge1 = rand_contactSequence(ed,1:2); 28 | 29 | ed2 = randsample(nEdges,1); 30 | 31 | % new edge is at position ed2 32 | edge2 = rand_contactSequence(ed2,1:2); 33 | 34 | r = rand; 35 | if r < 0.5 36 | if edge1(1) ~= edge2(2) && edge2(1) ~= edge1(2) 37 | rand_contactSequence(ed,1:2) = [edge1(1) edge2(2)]; 38 | rand_contactSequence(ed2,1:2) = [edge2(1) edge1(2)]; 39 | end 40 | else 41 | if edge1(1) ~= edge2(1) && edge1(2) ~= edge2(2) 42 | rand_contactSequence(ed,1:2) = [edge1(1) edge2(1)]; 43 | rand_contactSequence(ed2,1:2) = [edge1(2) edge2(2)]; 44 | end 45 | end 46 | 47 | 48 | end 49 | end 50 | 51 | -------------------------------------------------------------------------------- /reachabilityAtTimeT.m: -------------------------------------------------------------------------------- 1 | function [ badj ] = reachabilityAtTimeT(contactSequence,t,directed,nNodes) 2 | % Create a binary network summarizing contacts which appear at time t. 3 | % 4 | % Inputs: 5 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 6 | % contact between nodes i,j at time t. 7 | % t = time at which to create graph 8 | % directed = 1 if network is directed, 0 if undirected. 9 | % 10 | % Optional Inputs: 11 | % nNodes = number of nodes total in dynamic network. Default assumes 12 | % all nodes are present in contactSequence. 13 | % 14 | % Output: 15 | % badj = nNodes x nNodes binary graph indicating which nodes are 16 | % connected at time t in dynamic network. 17 | % 18 | % 19 | % 20 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 21 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 22 | % 23 | % Main function: 24 | 25 | if ~exist('nNodes','var') || isempty(nNodes); 26 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 27 | end 28 | 29 | badj = zeros(nNodes); 30 | times = find(contactSequence(:,3) == t); 31 | 32 | if ~isempty(times) 33 | for t1 = 1:length(times) 34 | badj(contactSequence(times(t1),1),contactSequence(times(t1),2)) = 1; 35 | if directed == 0 36 | badj(contactSequence(times(t1),2),contactSequence(times(t1),1)) = 1; 37 | end 38 | 39 | end 40 | end 41 | 42 | 43 | 44 | end 45 | 46 | -------------------------------------------------------------------------------- /reachabilityGraph.m: -------------------------------------------------------------------------------- 1 | function [ reachGraph ] = reachabilityGraph(contactSequence,... 2 | directed,contactTimes,nNodes) 3 | % Construct a binary graph encoding existence of time-respecting paths 4 | % between nodes. 5 | % 6 | % Inputs: 7 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 8 | % contact between nodes i,j at time t. 9 | % directed = 1 if network is directed, 0 if undirected. 10 | % 11 | % Optional Inputs: 12 | % contactTimes = ascending vector of all possible contact times. Ex. 13 | % 1:20. Default assumes all possible times exist in 14 | % contactSequence. 15 | % nNodes = number of nodes total in dynamic network. Default assumes 16 | % all nodes are present in contactSequence. 17 | % 18 | % Output: 19 | % reachabilityGraph = nNodes x nNodes binary matrix recording if 20 | % recording if node j can be reached from node i via a 21 | % time-respecting path up to that time index. 22 | % 23 | % 24 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 25 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 26 | % 27 | % Main function: 28 | 29 | if ~exist('contactTimes','var') || isempty(contactTimes); 30 | contactTimes = sort(unique(contactSequence(:,3),'ascend')); 31 | end 32 | if ~exist('nNodes','var') || isempty(nNodes); 33 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 34 | end 35 | 36 | 37 | 38 | reachabilityArray = makeReachabilityArray(contactSequence,... 39 | directed,contactTimes,nNodes); 40 | reachGraph = reachabilityArray(:,:,end); 41 | 42 | end 43 | 44 | -------------------------------------------------------------------------------- /ringDN.m: -------------------------------------------------------------------------------- 1 | function [ contactSequence ] = ringDN(nNodes,timeInterval) 2 | % Create a ring network with each edge connecting adjacent nodes. 3 | % 4 | % Inputs: 5 | % nNodes = number of nodes 6 | % timeInterval = 1 x 2 vector of start and end time 7 | % 8 | % Output: 9 | % contactSequence = nNodes x 3 matrix with rows of form (i,j,t) 10 | % indicating a contact between nodes i,j at time t. 11 | % 12 | % 13 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 14 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 15 | % 16 | % Main function: 17 | 18 | contactSequence = zeros(nNodes,3); 19 | contactSequence(:,1) = 1:nNodes; 20 | contactSequence(:,2) = [2:nNodes 1]; 21 | contactSequence(:,3) = linspace(timeInterval(1),timeInterval(2),nNodes); 22 | 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /setOfInfluence.m: -------------------------------------------------------------------------------- 1 | function [ S ] = setOfInfluence( node_i, contactSequence, directed, ... 2 | t_i,t_end,contactTimes, nNodes) 3 | % Determine the set of influence of a node (the set of nodes which can be 4 | % reached from node i via a time-respecting paths beginning at time t 5 | % or later). 6 | % 7 | % Inputs: 8 | % node_i = node of interest 9 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 10 | % contact between nodes i,j at time t. 11 | % directed = 1 if network is directed, 0 if undirected. 12 | % 13 | % Optional Inputs: 14 | % t_i = time t at which to begin recording connectivity. Default is 15 | % the time of first contact or min(contactTimes). 16 | % t_end = tme at which to end calculation. Default is inf. 17 | % contactTimes = ascending vector of all possible contact times. Ex. 18 | % 1:20. Default assumes all possible times exist in 19 | % contactSequence. 20 | % nNodes = number of nodes total in dynamic network. Default assumes 21 | % all nodes are present in contactSequence. 22 | % 23 | % Output: 24 | % S = set of Influence vector for node i 25 | % 26 | % 27 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 28 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 29 | % 30 | % Main function: 31 | 32 | if ~exist('contactTimes','var') || isempty(contactTimes); 33 | contactTimes = sort(unique(contactSequence(:,3)),'ascend'); 34 | end 35 | if ~exist('nNodes','var') || isempty(nNodes); 36 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 37 | end 38 | if ~exist('t_i','var') || isempty(t_i); 39 | t_i = min(contactTimes); 40 | end 41 | if ~exist('t_end','var') || isempty(t_end); 42 | t_end = inf; 43 | end 44 | 45 | 46 | 47 | % find nodes which can be reached from nodei 48 | 49 | contactSequence(contactSequence(:,3) t_end,:) = []; 51 | 52 | reachabilityArray = makeReachabilityArray(contactSequence,directed,... 53 | contactTimes(contactTimes>=t_i),nNodes); 54 | 55 | 56 | S = find(reachabilityArray(node_i,:,end)); 57 | 58 | 59 | 60 | 61 | end 62 | 63 | -------------------------------------------------------------------------------- /shuffledTimeSteps.m: -------------------------------------------------------------------------------- 1 | function [ rand_contactSequence ] = shuffledTimeSteps(contactSequence,directed) 2 | % shuffledTimeSteps randomizes the input dynamic network by randomly 3 | % permuting the order of the graph sequence. 4 | % 5 | % Inputs: 6 | % contactSequence = nEdges x 3 matrix encoding contacts between node 7 | % i,j at time t by (i,j,t). 8 | % directed = 1 if directed network, 0 if undirected. 9 | % 10 | % Output: 11 | % rand_contactSequence = contact sequence of randomized input data. 12 | % 13 | % 14 | % 15 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 16 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 17 | % 18 | % Main function: 19 | 20 | adjArray = networksFromContacts(contactSequence,directed); 21 | 22 | nTimePoints = size(adjArray,3); 23 | 24 | newOrder = randsample(nTimePoints,nTimePoints); 25 | 26 | randAdjArray = adjArray(:,:,newOrder); 27 | 28 | rand_contactSequence = arrayToContactSeq(randAdjArray,directed); 29 | 30 | 31 | end 32 | 33 | -------------------------------------------------------------------------------- /sourceSet.m: -------------------------------------------------------------------------------- 1 | function [ S_o ] = sourceSet(node_i,contactSequence,directed,t_i,... 2 | contactTimes,nNodes) 3 | % Determine the source set of a node (the set of nodes from which node i 4 | % can be reached via time-respecting paths beginning at time t or later). 5 | % 6 | % Inputs: 7 | % node_i = node of interest 8 | % contactSequence = nEdges x 3 array of (i,j,t) tuples indicating 9 | % contact between nodes i,j at time t. 10 | % directed = 1 if network is directed, 0 if undirected. 11 | % 12 | % Optional Inputs: 13 | % t_i = time t at which to begin recording connectivity. Default is 14 | % the time of first contact or min(contactTimes). 15 | % contactTimes = ascending vector of all possible contact times. Ex. 16 | % 1:20. Default assumes all possible times exist in 17 | % contactSequence. 18 | % nNodes = number of nodes total in dynamic network. Default assumes 19 | % all nodes are present in contactSequence. 20 | % 21 | % Output: 22 | % S_o = source set vector for node i 23 | % 24 | % 25 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 26 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 27 | % 28 | % Main function: 29 | 30 | if ~exist('contactTimes','var') || isempty(contactTimes); 31 | contactTimes = sort(unique(contactSequence(:,3)),'ascend'); 32 | end 33 | if ~exist('nNodes','var') || isempty(nNodes); 34 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 35 | end 36 | if ~exist('t_i','var') || isempty(t_i); 37 | t_i = min(contactTimes); 38 | end 39 | 40 | 41 | % find nodes which can reach node_i at time t_i 42 | 43 | cS = contactSequence; 44 | cS(cS(:,3) > t_i,:) = []; 45 | reachabilityArray = makeReachabilityArray(cS,directed,... 46 | contactTimes(contactTimes<=t_i),nNodes); 47 | 48 | 49 | S_o = find(reachabilityArray(:,node_i,end)); 50 | 51 | 52 | end 53 | 54 | -------------------------------------------------------------------------------- /temporalCorrelation.m: -------------------------------------------------------------------------------- 1 | function [ C,C_vec ] = temporalCorrelation( contactSequence,directed ) 2 | % temporalCorrelation calculates the temporal correlation of a dynamic 3 | % network as defined in Tang et al. 2010. 4 | % 5 | % Inputs: 6 | % contactSequence = nEdges x 3 matrix encoding contacts between node 7 | % i,j at time t by (i,j,t). 8 | % directed = 1 if the dynamic network is directed, 0 otherwise. 9 | % 10 | % Output: 11 | % C = temporal correlation coefficient of the network 12 | % C_vec = temporal correlation of each node 13 | % 14 | % 15 | % 16 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 17 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 18 | % 19 | % Main function: 20 | 21 | 22 | 23 | adjArray = networksFromContacts(contactSequence,directed); 24 | 25 | T = size(adjArray,3); 26 | nNodes = size(adjArray,1); 27 | 28 | C_vec = zeros(nNodes,1); 29 | 30 | for node_i = 1:size(adjArray,1) 31 | 32 | 33 | 34 | gammaVec = zeros(1,T-1); 35 | 36 | for t = 1:T-1 37 | num = 0; 38 | 39 | for j = 1:nNodes 40 | if node_i~= j 41 | num = num + adjArray(node_i,j,t)*adjArray(node_i,j,t+1); 42 | end 43 | end 44 | 45 | den = sqrt(sum(adjArray(node_i,:,t))*sum(adjArray(node_i,:,t+1))); 46 | 47 | if den~=0 48 | gamma = num/den; 49 | gammaVec(t) = gamma; 50 | end 51 | 52 | end 53 | 54 | % sum over timepoints 55 | 56 | C_i = (1/(T-1))*sum(gammaVec); 57 | 58 | C_vec(node_i) = C_i; 59 | 60 | end 61 | 62 | C = sum(C_vec)/nNodes; 63 | 64 | end 65 | 66 | -------------------------------------------------------------------------------- /temporalSmallWorldness.m: -------------------------------------------------------------------------------- 1 | function [ C,L ] = temporalSmallWorldness(contactSequence,... 2 | directed,nNodes) 3 | % temporalSmallWorldness returns values needed to compute the temporal 4 | % small worldness of a dynamic network. 5 | % 6 | % Inputs: 7 | % contactSequence = nEdges x 3 matrix encoding contacts between node 8 | % i,j at time t by (i,j,t). 9 | % directed = 1 if the dynamic network is directed, 0 otherwise. 10 | % 11 | % Optional Inputs: 12 | % nNodes = number of nodes in the dynamic network. Default is all 13 | % nodes which appear in contactSequence (have at least one 14 | % contact). 15 | % 16 | % Outputs: 17 | % C = temporal correlation of input dynamic network 18 | % L = efficientcy of dynamic network 19 | % 20 | % 21 | % 22 | % Reference: Ann E. Sizemore and Danielle S. Bassett, "Dynamic Graph 23 | % Metrics: Tutorial, Toolbox, and Tale." Submitted. (2017) 24 | % 25 | % Main function: 26 | 27 | 28 | if ~exist('nNodes','var') || isempty(nNodes); 29 | nNodes = length(unique([contactSequence(:,1); contactSequence(:,2)])); 30 | end 31 | 32 | 33 | [C] = temporalCorrelation( contactSequence,directed); 34 | 35 | % compute efficiency 36 | [~,L_mat] = betweennessCentrality(contactSequence,directed); 37 | 38 | 39 | L = (1/(nNodes*(nNodes-1)))*sum(L_mat(:)); 40 | 41 | 42 | 43 | end 44 | 45 | -------------------------------------------------------------------------------- /thresholdMatDensity.m: -------------------------------------------------------------------------------- 1 | function [ tadj, threshold ] = thresholdMatDensity( adj, density ) 2 | % Threshold matrix at a given edge density. 3 | 4 | 5 | % Main function: 6 | 7 | % record and sort edges in decreasing order 8 | edges = adj(:); 9 | sortedEdges = sort(edges,'descend'); 10 | nEdges = length(edges); 11 | 12 | % Calculate threshold 13 | threshold = sortedEdges(ceil(nEdges*density)); 14 | 15 | % Threshold matrix 16 | tadj = adj; 17 | tadj(tadj