Example #1
0
    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