def computeAdjacencyMatrix(self, step, agentPos, CommunicationRadius, graphConnected=False): len_TimeSteps = agentPos.shape[0] # length of timesteps nNodes = agentPos.shape[1] # Number of nodes # Create the space to hold the adjacency matrices W = np.zeros([len_TimeSteps, nNodes, nNodes]) # Initial matrix distances = squareform(pdist(agentPos[0])) # nNodes x nNodes # I will increase the communication radius by 10% each time, # but I have to do it consistently within the while loop, # so in order to not affect the first value set of communication radius, I will account for that initial 10% outside if step == 0: self.communicationRadius = self.communicationRadius / 1.1 while graphConnected is False: self.communicationRadius = self.communicationRadius * 1.1 W[0] = (distances < self.communicationRadius).astype( agentPos.dtype) W[0] = W[0] - np.diag(np.diag(W[0])) graphConnected = graph.isConnected(W[0]) # And once we have found a connected initial position, we normalize it deg = np.sum(W[0], axis=1) # nNodes (degree vector) zeroDeg = np.nonzero(np.abs(deg) < self.zeroTolerance)[0] deg[zeroDeg] = 1. invSqrtDeg = np.sqrt(1. / deg) invSqrtDeg[zeroDeg] = 0. Deg = np.diag(invSqrtDeg) W[0] = Deg @ W[0] @ Deg # And once we have found a communication radius that makes the initial graph connected, # just follow through with the rest of the times, with that communication radius else: distances = squareform(pdist(agentPos[0])) # nNodes x nNodes W[0] = (distances < self.communicationRadius).astype( agentPos.dtype) W[0] = W[0] - np.diag(np.diag(W[0])) graphConnected = graph.isConnected(W[0]) deg = np.sum(W[0], axis=1) # nNodes (degree vector) zeroDeg = np.nonzero(np.abs(deg) < self.zeroTolerance)[0] deg[zeroDeg] = 1. invSqrtDeg = np.sqrt(1. / deg) invSqrtDeg[zeroDeg] = 0. Deg = np.diag(invSqrtDeg) W[0] = Deg @ W[0] @ Deg return W, self.communicationRadius, graphConnected
def computeAdjacencyMatrix(self, pos, CommunicationRadius, connected=True): # First, transpose the axis of pos so that the rest of the code follows # through as legible as possible (i.e. convert the last two dimensions # from 2 x nNodes to nNodes x 2) # pos: TimeSteps x nAgents x 2 (X, Y) # Get the appropriate dimensions nSamples = pos.shape[0] len_TimeSteps = pos.shape[0] # length of timesteps nNodes = pos.shape[1] # Number of nodes # Create the space to hold the adjacency matrices W = np.zeros([len_TimeSteps, nNodes, nNodes]) threshold = CommunicationRadius # We compute a different # threshold for each sample, because otherwise one bad trajectory # will ruin all the adjacency matrices for t in range(len_TimeSteps): # Compute the distances distances = squareform(pdist(pos[t])) # nNodes x nNodes # Threshold them W[t] = (distances < threshold).astype(pos.dtype) # And get rid of the self-loops W[t] = W[t] - np.diag(np.diag(W[t])) # Now, check if it is connected, if not, let's make the # threshold bigger while (not graph.isConnected(W[t])) and (connected): # while (not graph.isConnected(W[t])) and (connected): # Increase threshold threshold = threshold * 1.1 # Increase 10% # Compute adjacency matrix W[t] = (distances < threshold).astype(pos.dtype) W[t] = W[t] - np.diag(np.diag(W[t])) # And since the threshold has probably changed, and we want the same # threshold for all nodes, we repeat: W = np.zeros([len_TimeSteps, nNodes, nNodes]) for t in range(len_TimeSteps): distances = squareform(pdist(pos[t])) W[t] = (distances < threshold).astype(pos.dtype) W[t] = W[t] - np.diag(np.diag(W[t])) # And, when we compute the adjacency matrix, we normalize it by # the degree deg = np.sum(W[t], axis=1) # nNodes (degree vector) # Build the degree matrix powered to the -1/2 Deg = np.diag(np.sqrt(1. / deg)) # And finally get the correct adjacency W[t] = Deg @ W[t] @ Deg return W, threshold