def addEdge(self, vertexIndex1, vertexIndex2, edge=1): """ Add a non-zero edge between two vertices. :param vertexIndex1: The index of the first vertex. :type vertexIndex1: :class:`int` :param vertexIndex2: The index of the second vertex. :type vertexIndex2: :class:`int` :param edge: The value of the edge. :type edge: :class:`float` """ Parameter.checkIndex(vertexIndex1, 0, self.vList.getNumVertices()) Parameter.checkIndex(vertexIndex2, 0, self.vList.getNumVertices()) vertexIndex1 = int(vertexIndex1) vertexIndex2 = int(vertexIndex2) if edge == 0 or edge == float('inf'): raise ValueError("Cannot add a zero or infinite edge") if self.undirected: self.W[vertexIndex1, vertexIndex2] = edge self.W[vertexIndex2, vertexIndex1] = edge else: self.W[vertexIndex1, vertexIndex2] = edge
def breadthFirstSearch(self, root): """ Breadth first search starting from a particular vertex. Returns a list of connected vertices in the order they were found. :param root: The index of the root vertex. :type root: :class:`int` :returns: A list of vertices connected to the input one via a path in the graph. """ Parameter.checkIndex(root, 0, self.size) toVisit = [root] visited = set() searchPath = [] #adjacencyList, weights = self.adjacencyList() while len(toVisit) != 0: currentVertex = toVisit.pop(0) if currentVertex not in visited: visited.add(currentVertex) searchPath.append(currentVertex) neighbours = self.neighbours(currentVertex) unvisited = sorted(set(neighbours).difference(visited)) toVisit.extend(list(unvisited)) return searchPath
def depthFirstSearch(self, root): """ Depth first search starting from a particular vertex. Returns a list of connected vertices in the order they were found. :param root: The index of the root vertex. :type root: :class:`int` :returns: A list of vertices connected to the input one via a path in the graph. """ Parameter.checkIndex(root, 0, self.size) currentPath = [root] visited = set() searchPath = [] while len(currentPath) != 0: currentVertex = currentPath[-1] if currentVertex not in visited: visited.add(currentVertex) searchPath.append(currentVertex) neighbours = self.neighbours(currentVertex) unvisited = (set(neighbours).difference(visited)) if len(unvisited) != 0: currentPath.append(unvisited.pop()) else: currentPath.pop() return searchPath
def getAlters(self, i): Parameter.checkIndex(i, 0, self.iteration) alters = [] for j in range(0, len(self.allTransmissionEdges[i])): alters.append(self.allTransmissionEdges[i][j, 1]) return numpy.unique(numpy.array(alters))
def removeEdge(self, vertexIndex1, vertexIndex2, edgeTypeIndex): """ Remove an edge between two vertices. @param vertexIndex1: The index of the first vertex. @param vertexIndex1: The index of the second vertex. """ Parameter.checkIndex(edgeTypeIndex, 0, self.maxEdgeTypes) self.sparseGraphs[edgeTypeIndex].removeEdge(vertexIndex1, vertexIndex2)
def clearVertex(self, index): """ Sets a vertex to the all-zeros array. :param index: the index of the vertex to assign a value. :type index: :class:`int` """ Parameter.checkIndex(index, 0, self.V.shape[0]) self.V[index, :] = numpy.zeros((1, self.V.shape[1]))
def getVertex(self, index): """ Returns the value of a vertex. :param index: the index of the vertex. :type index: :class:`int` """ Parameter.checkIndex(index, 0, len(self.V)) return self.V[index]
def addEdge(self, vertexIndex1, vertexIndex2, edgeTypeIndex, edge=1): """ Add an edge to the graph between two vertices. @param vertexIndex1: The index of the first vertex. @param vertexIndex1: The index of the second vertex. @param edge: The value to assign to the edge. """ Parameter.checkIndex(edgeTypeIndex, 0, self.maxEdgeTypes) self.sparseGraphs[edgeTypeIndex].addEdge(vertexIndex1, vertexIndex2, edge)
def setK(self, k): """ The number of neighbours of each vertex. :param k: the number of neighbours in the regular lattice. :type k: :class:`int` """ Parameter.checkIndex(k, 0, float('inf')) self.k = k
def clearVertex(self, index): """ Sets a vertex to None :param index: the index of the vertex to assign a value. :type index: :class:`int` """ Parameter.checkIndex(index, 0, len(self.V)) self.V[index] = None
def setInfected(self, vertexInd, time): Parameter.checkIndex(vertexInd, 0, self.getNumVertices()) Parameter.checkFloat(time, 0.0, float('inf')) if self.V[vertexInd, HIVVertices.stateIndex] == HIVVertices.infected: raise ValueError("Person is already infected") self.V[vertexInd, HIVVertices.stateIndex] = HIVVertices.infected self.V[vertexInd, HIVVertices.infectionTimeIndex] = time
def neighbours(self, vertexIndex): """ Return an array of the indices of the neighbours of the given vertex. :param vertexIndex: the index of a vertex. :type vertexIndex: :class:`int` """ Parameter.checkIndex(vertexIndex, 0, self.vList.getNumVertices()) neighbourIndices = self.W.rowInds(vertexIndex) return neighbourIndices
def getVertex(self, index): """ Returns the value of a vertex. :param index: the index of the vertex. :type index: :class:`int` :returns: the value of the vertex. """ Parameter.checkIndex(index, 0, self.V.shape[0]) return self.V[index, :]
def setVertex(self, vertexIndex, vertex): """ Set the vertex with given index to a particular value. :param vertexIndex: the index of the vertex. :type vertexIndex: :class:`int` :param vertex: the value of the vertex. """ Parameter.checkIndex(vertexIndex, 0, self.vList.getNumVertices()) self.vList.setVertex(vertexIndex, vertex)
def neighbours(self, vertexIndex): """ Return an array of the indices of the neighbours of the given vertex. :param vertexIndex: the index of a vertex. :type vertexIndex: :class:`int` """ Parameter.checkIndex(vertexIndex, 0, self.vList.getNumVertices()) nonZeroIndices = numpy.nonzero(self.W[vertexIndex, :]) neighbourIndices = nonZeroIndices[0] return neighbourIndices
def setVertex(self, index, value): """ Set a vertex to the corresponding value. :param index: the index of the vertex to assign a value. :type index: :class:`int` :param value: the value to assign to the vertex. """ Parameter.checkIndex(index, 0, len(self.V)) self.V[index] = value
def neighbourOf(self, vertexIndex): """ Return an array of the indices of vertices than have an edge going to the input vertex. :param vertexIndex: the index of a vertex. :type vertexIndex: :class:`int` """ Parameter.checkIndex(vertexIndex, 0, self.vList.getNumVertices()) nonZeroIndices = numpy.nonzero(self.W[:, vertexIndex]) neighbourIndices = nonZeroIndices[0] return neighbourIndices
def getFeatureDistribution(self, fIndex, vIndices=None): """ Returns a tuple (frequencies, items) about a particular feature given by fIndex. This method is depricated. """ Parameter.checkIndex(fIndex, 0, self.getNumFeatures()) if vIndices == None: (freqs, items) = Util.histogram(self.V[:, fIndex]) else: (freqs, items) = Util.histogram(self.V[vIndices, fIndex]) return (freqs, items)
def setDetected(self, vertexInd, time, detectionType): Parameter.checkIndex(vertexInd, 0, self.getNumVertices()) Parameter.checkFloat(time, 0.0, float('inf')) if detectionType not in [HIVVertices.randomDetect, HIVVertices.contactTrace]: raise ValueError("Invalid detection type : " + str(detectionType)) if self.V[vertexInd, HIVVertices.stateIndex] != HIVVertices.infected: raise ValueError("Person must be infected to be detected") self.V[vertexInd, HIVVertices.stateIndex] = HIVVertices.removed self.V[vertexInd, HIVVertices.detectionTimeIndex] = time self.V[vertexInd, HIVVertices.detectionTypeIndex] = detectionType
def neighbourOf(self, vertexIndex): """ Return an array of the indices of vertices than have an edge going to the input vertex. :param vertexIndex: the index of a vertex. :type vertexIndex: :class:`int` :returns: An array of the indices of all vertices with an edge towards the input vertex. """ Parameter.checkIndex(vertexIndex, 0, self.vList.getNumVertices()) neighbours = PySparseUtils.nonzero(self.W[:, vertexIndex])[0] return numpy.array(neighbours)
def neighbours(self, vertexIndex): """ Return an array of the indices of neighbours. In the case of a directed graph it is an array of those vertices connected by an edge from the current one. :param vertexIndex: the index of a vertex. :type vertexIndex: :class:`int` :returns: An array of the indices of all neigbours of the input vertex. """ Parameter.checkIndex(vertexIndex, 0, self.vList.getNumVertices()) neighbours = PySparseUtils.nonzero(self.W[int(vertexIndex), :])[1] return numpy.array(neighbours)
def removeEdge(self, vertexIndex1, vertexIndex2): """ Remove an edge between two vertices. :param vertexIndex1: The index of the first vertex. :type vertexIndex1: :class:`int` :param vertexIndex2: The index of the second vertex. :type vertexIndex2: :class:`int` """ Parameter.checkIndex(vertexIndex1, 0, self.vList.getNumVertices()) Parameter.checkIndex(vertexIndex2, 0, self.vList.getNumVertices()) self.W[vertexIndex1, vertexIndex2] = 0 if self.undirected: self.W[vertexIndex2, vertexIndex1] = 0
def getNumEdges(self, edgeTypeIndex=-1): """ Returns the total number of edges in the graph of a given type. If the edgeType is -1 then returns the total number of indices of all types. """ Parameter.checkIndex(edgeTypeIndex, -1, self.maxEdgeTypes) if edgeTypeIndex == -1: numEdges = 0 for i in range(0, self.maxEdgeTypes): numEdges = numEdges + self.sparseGraphs[i].getNumEdges() else: numEdges = self.sparseGraphs[edgeTypeIndex].getNumEdges() return numEdges
def egoGraph(self, vertexIndex): """ Returns the subgraph composed of the given vertex and its immediate neighbours. In the new graph, the ego is index 0 and neighbours are indexed in order after 0. :param vertexIndex: the index of the source vertex. :type vertexIndex: :class:`int` :returns: A subgraph of the current one consisting of only immediate neighbours. """ Parameter.checkIndex(vertexIndex, 0, self.vList.getNumVertices()) neighbours = self.neighbours(vertexIndex) egoGraphIndices = numpy.r_[numpy.array([vertexIndex]), neighbours] return self.subgraph(egoGraphIndices)
def setVertex(self, index, value): """ Set a vertex to the corresponding value. :param index: the index of the vertex to assign a value. :type index: :class:`int` :param value: the value to assign to the vertex. :type value: :class:`numpy.ndarray` """ Parameter.checkIndex(index, 0, self.V.shape[0]) Parameter.checkClass(value, numpy.ndarray) #Parameter.checkFloat(value, -float('inf'), float('inf')) if value.shape[0] != self.V.shape[1]: raise ValueError("All vertices must be arrays of length " + str(self.V.shape[1])) self.V[index, :] = value
def neighbours(self, vertexIndex): """ Return an array of the indices of neighbours. In the case of a directed graph it is an array of those vertices connected by an edge from the current one. :param vertexIndex: the index of a vertex. :type vertexIndex: :class:`int` :returns: An array of the indices of all neigbours of the input vertex. """ Parameter.checkIndex(vertexIndex, 0, self.vList.getNumVertices()) #neighbours = self.W[vertexIndex, :].nonzero()[1] neighbours = self.W.getrow(vertexIndex).nonzero()[1] #neighbours = numpy.nonzero(self.W.getrow(vertexIndex).toarray())[1] return neighbours
def getEdge(self, vertexIndex1, vertexIndex2): """ Get the value of an edge, or None if no edge exists. :param vertexIndex1: The index of the first vertex. :type vertexIndex1: :class:`int` :param vertexIndex2: The index of the second vertex. :type vertexIndex2: :class:`int` :returns: The value of the edge between the given vertex indices. """ Parameter.checkIndex(vertexIndex1, 0, self.vList.getNumVertices()) Parameter.checkIndex(vertexIndex2, 0, self.vList.getNumVertices()) if self.W[vertexIndex1, vertexIndex2]==0: return None else: return self.W[vertexIndex1, vertexIndex2]
def dijkstrasAlgorithm(self, vertexIndex, neighbourLists=None): """ Run Dijkstras Algorithm on the graph for a given source vertex. The parameter neighbourLists is a tuple containing two lists. The first of this lists contains at the ith position all the neighbours of vertex i. The second list contains the corresponding weight on the edge. If neighbourLists=None, then it is computed automatically and all edge weights are set to 1. Returns an array with the distance to all vertices (including itself). :param vertexIndex: the index of the source vertex. :type vertexIndex: :class:`int` :param neighbourLists: A tuple of two lists containing vertex adjacencies and edge weights respectively. :type neighbourLists: :class:`list` :returns: An array whose ith element is the distance to vertex i. """ Parameter.checkIndex(vertexIndex, 0, self.getNumVertices()) if neighbourLists!=None: neighbourIndices, neighbourWeights = neighbourLists if len(neighbourIndices) != self.getNumVertices() or len(neighbourWeights) != self.getNumVertices(): raise ValueError("Adjacency lists must be of same size as graph") else: neighbourIndices, neighbourWeights = self.adjacencyList(False) previous = numpy.zeros(self.getNumVertices()) distance = numpy.ones((self.getNumVertices(), 2))*numpy.inf distance[vertexIndex, 0] = 0 distance[:, 1] = numpy.arange(self.getNumVertices()) distance = distance.tolist() heapq.heapify(distance) #Dictionary of the tuples indexed by the vertex index distanceDict = {} for i in distance: distanceDict[i[1]] = i INVALID = -1 distanceArray = numpy.ones(self.getNumVertices())*numpy.inf notVisited = numpy.ones(self.getNumVertices(), numpy.bool) while len(distanceDict) != 0: minVertexIndex = INVALID while minVertexIndex == INVALID: (minVertexDistance, minVertexIndex) = heapq.heappop(distance) distanceArray[minVertexIndex] = minVertexDistance del(distanceDict[minVertexIndex]) notVisited[minVertexIndex] = False if minVertexDistance == numpy.inf: break minVertexIndex = int(minVertexIndex) cols = neighbourIndices[minVertexIndex] weights = neighbourWeights[minVertexIndex] #updateDistances(cols, weights, minVertexDistance, distanceDict, previous, distanceArray) newDistances = weights + minVertexDistance isBetter = numpy.logical_and(newDistances < distanceArray[cols], notVisited[cols]) for i in range(cols[isBetter].shape[0]): j = cols[isBetter][i] distanceDict[j][1] = INVALID distanceDict[j] = [newDistances[isBetter][i], j] heapq.heappush(distance, distanceDict[j]) distanceArray[j] = newDistances[isBetter][i] return distanceArray
def getTransmissions(self, i=None): if i != None: Parameter.checkIndex(i, 0, self.iteration) return self.allTransmissionEdges[i] else: return self.allTransmissionEdges