def testNativeAdjacencyMatrix(self): numVertices = 10 graph = SparseGraph(GeneralVertexList(numVertices)) graph.addEdge(1, 1, 0.1) graph.addEdge(1, 3, 0.5) graph.addEdge(2, 5, 1) graph.addEdge(7, 0, 2) A = graph.nativeAdjacencyMatrix() self.assertEquals(A[0, 7], 1) self.assertEquals(A[7, 0], 1) self.assertEquals(A[1, 3], 1) self.assertEquals(A[3, 1], 1) self.assertEquals(A[1, 1], 1) self.assertEquals(A[2, 5], 1) self.assertEquals(A[5, 2], 1) self.assertEquals(A.getnnz(), 7) graph = SparseGraph(GeneralVertexList(numVertices), False) graph.addEdge(1, 1, 0.1) graph.addEdge(1, 3, 0.5) graph.addEdge(2, 5, 1) A = graph.nativeAdjacencyMatrix() self.assertEquals(A[1, 3], 1) self.assertEquals(A[1, 1], 1) self.assertEquals(A[2, 5], 1) self.assertEquals(A.getnnz(), 3)
def testGenerate2(self): """ Make sure that the generated degree is less than or equal to the given degree """ numVertices = 10 for i in range(10): degSequence = numpy.random.randint(0, 3, numVertices) generator = ConfigModelGenerator(degSequence) graph = SparseGraph(GeneralVertexList(numVertices)) graph = generator.generate(graph) self.assertTrue((graph.outDegreeSequence() <= degSequence).all()) #We try to match an evolving degree sequence degSequence1 = numpy.array([0, 0, 1, 1, 1, 2, 2, 2, 3, 4]) degSequence2 = numpy.array([2, 0, 3, 1, 2, 2, 2, 2, 3, 4]) degSequence3 = numpy.array([2, 1, 4, 1, 2, 2, 2, 2, 3, 6]) generator = ConfigModelGenerator(degSequence1) graph = SparseGraph(GeneralVertexList(numVertices)) graph = generator.generate(graph) self.assertTrue((degSequence1 >= graph.outDegreeSequence()).all()) deltaSequence = degSequence2 - graph.outDegreeSequence() generator = ConfigModelGenerator(deltaSequence) graph = generator.generate(graph, False) self.assertTrue((degSequence2 >= graph.outDegreeSequence()).all()) deltaSequence = degSequence3 - graph.outDegreeSequence() generator = ConfigModelGenerator(deltaSequence) graph = generator.generate(graph, False) self.assertTrue((degSequence3 >= graph.outDegreeSequence()).all())
def testConcat(self): numVertices = 5 graph = SparseGraph(GeneralVertexList(numVertices)) graph.addEdge(1, 1, 0.1) graph.addEdge(1, 3, 0.5) graph.addEdge(2, 4, 1) graph.addEdge(2, 3, 2) graph.setVertex(0, "abc") graph2 = SparseGraph(GeneralVertexList(numVertices)) graph2.addEdge(1, 1) graph2.addEdge(1, 4) graph2.setVertex(1, "def") graph3 = graph.concat(graph2) self.assertTrue(graph3.getNumVertices, 10) self.assertEquals(graph3.getVertex(0), "abc") self.assertEquals(graph3.getVertex(6), "def") self.assertEquals(graph3.getEdge(1, 1), 0.1) self.assertEquals(graph3.getEdge(1, 3), 0.5) self.assertEquals(graph3.getEdge(2, 4), 1) self.assertEquals(graph3.getEdge(2, 3), 2) self.assertEquals(graph3.getEdge(6, 6), 1) self.assertEquals(graph3.getEdge(6, 9), 1)
def concat(self, graph): """ Take a new graph and concatenate it to the current one. Returns a new graph of the concatenated graphs with this graphs vertices first in the new list of vertices. :param graph: the input graph. :type graph: :class:`apgl.graph.SparseGraph` """ Parameter.checkClass(graph, SparseGraph) if type(graph.getVertexList()) != type(self.getVertexList()): raise ValueError("Vertex lists must be of same type") if graph.isUndirected() != self.isUndirected(): raise ValueError("Graphs must be of the same directed type") numVertices = self.getNumVertices() + graph.getNumVertices() vList = GeneralVertexList(numVertices) vList.setVertices(self.getVertexList().getVertices(), list(range(self.getNumVertices()))) vList.setVertices(graph.getVertexList().getVertices(), list(range(self.getNumVertices(), numVertices))) newGraph = SparseGraph(vList) W = scipy.sparse.bmat([[self.W, None], [None, graph.W]], format="csr") newGraph.setWeightMatrixSparse(W) return newGraph
def testAddVertices(self): vList = GeneralVertexList(10) vList.setVertex(1, 2) self.assertEquals(vList.getNumVertices(), 10) self.assertEquals(vList[1], 2) vList.addVertices(5) self.assertEquals(vList.getNumVertices(), 15) vList.setVertex(11, 2) self.assertEquals(vList[1], 2) self.assertEquals(vList[1], 2)
def fromNetworkXGraph(cls, networkXGraph): """ Take a networkx Graph or DiGraph object, and return a subclass of AbstractMatrixGraph. Notice that networkx must be installed to use this function. The networkXGraph graph dict must have an attribute VListType which is the type of the VertexList used to construct the SparseGraph. Furthermore, only node attributes index by "label" are stored in the VertexList, and edge values are currently ignored. :returns: A networkx Graph or DiGraph object. """ try: import networkx except ImportError: raise ImportError("toNetworkXGraph() requires networkx") if type(networkXGraph) == networkx.classes.graph.Graph: undirected = True elif type(networkXGraph) == networkx.classes.digraph.DiGraph: undirected = False else: raise ValueError("Unsupported NetworkX graph type") numVertices = networkXGraph.number_of_nodes() if "VListType" in networkXGraph.graph and networkXGraph.graph["VListType"] == VertexList: vList = networkXGraph.graph["VListType"](numVertices, networkXGraph.graph["numFeatures"]) else: vList = GeneralVertexList(numVertices) graph = cls(vList, undirected) #Map from networkx nodes to an index nodeDict = {} #Set the vertices - note that vertex names are ignored for i in range(len(networkXGraph.nodes())): if "label" in networkXGraph.node[networkXGraph.nodes()[i]]: graph.setVertex(i, networkXGraph.node[networkXGraph.nodes()[i]]["label"]) else: graph.setVertex(i, None) nodeDict[networkXGraph.nodes()[i]] = i #Set edges for i in range(len(networkXGraph.edges())): vertexIndex1 = nodeDict[networkXGraph.edges()[i][0]] vertexIndex2 = nodeDict[networkXGraph.edges()[i][1]] graph.addEdge(vertexIndex1, vertexIndex2) return graph
def __init__(self): numVertices = 1000 graph = SparseGraph(GeneralVertexList(numVertices)) p = 0.1 generator = ErdosRenyiGenerator(p) graph = generator.generate(graph) subgraphIndicesList = [] for i in range(100, numVertices, 10): subgraphIndicesList.append(range(i)) k1 = 5 k2 = 100 self.graph = graph self.subgraphIndicesList = subgraphIndicesList self.clusterer = IterativeSpectralClustering(k1, k2, T=10, alg="IASC")
def testKwayNormalisedCut(self): numVertices = 6 graph = SparseGraph(GeneralVertexList(numVertices)) graph.addEdge(0, 1) graph.addEdge(0, 2) graph.addEdge(2, 1) graph.addEdge(3, 4) graph.addEdge(3, 5) graph.addEdge(5, 4) W = graph.getWeightMatrix() clustering = numpy.array([0, 0, 0, 1, 1, 1]) self.assertEquals(GraphUtils.kwayNormalisedCut(W, clustering), 0.0) #Try sparse W Ws = scipy.sparse.csr_matrix(W) self.assertEquals(GraphUtils.kwayNormalisedCut(Ws, clustering), 0.0) graph.addEdge(2, 3) W = graph.getWeightMatrix() self.assertEquals(GraphUtils.kwayNormalisedCut(W, clustering), 1.0 / 7) Ws = scipy.sparse.csr_matrix(W) self.assertEquals(GraphUtils.kwayNormalisedCut(Ws, clustering), 1.0 / 7) clustering = numpy.array([0, 0, 0, 1, 1, 2]) self.assertEquals(GraphUtils.kwayNormalisedCut(W, clustering), 61.0 / 105) self.assertEquals(GraphUtils.kwayNormalisedCut(Ws, clustering), 61.0 / 105) #Test two vertices without any edges W = numpy.zeros((2, 2)) clustering = numpy.array([0, 1]) self.assertEquals(GraphUtils.kwayNormalisedCut(W, clustering), 0.0) Ws = scipy.sparse.csr_matrix(W) self.assertEquals(GraphUtils.kwayNormalisedCut(Ws, clustering), 0.0)
def testSaveLoad(self): try: vList = GeneralVertexList(self.numVertices) vList.setVertex(0, "abc") vList.setVertex(1, 12) vList.setVertex(2, "num") tempDir = PathDefaults.getTempDir() fileName = tempDir + "vList" vList.save(fileName) vList2 = GeneralVertexList.load(fileName) for i in range(self.numVertices): self.assertEquals(vList.getVertex(i), vList2.getVertex(i)) except IOError as e: logging.warn(e) pass
def clusterFromIterator(self, graphListIterator, timeIter=False): """ Find a set of clusters for the graphs given by the iterator. """ clustersList = [] timeList = [] for subW in graphListIterator: logging.debug("Clustering graph of size " + str(subW.shape)) #Create a SparseGraph startTime = time.time() graph = SparseGraph(GeneralVertexList(subW.shape[0])) graph.setWeightMatrixSparse(subW) iGraph = graph.toIGraph() vertexCluster = iGraph.community_leading_eigenvector(self.k) clustersList.append(vertexCluster.membership) timeList.append(time.time()-startTime) if timeIter: return clustersList, timeList else: return clustersList
def testModularity(self): numVertices = 6 graph = SparseGraph(GeneralVertexList(numVertices)) graph.addEdge(0, 0) graph.addEdge(1, 1) graph.addEdge(2, 2) graph.addEdge(0, 1) graph.addEdge(0, 2) graph.addEdge(2, 1) graph.addEdge(3, 4, 2) graph.addEdge(3, 5, 2) graph.addEdge(4, 5, 2) graph.addEdge(3, 3, 2) graph.addEdge(4, 4, 2) graph.addEdge(5, 5, 2) W = graph.getWeightMatrix() clustering = numpy.array([0, 0, 0, 1, 1, 1]) #This is the same as the igraph result Q = GraphUtils.modularity(W, clustering) self.assertEquals(Q, 4.0 / 9.0) Ws = scipy.sparse.csr_matrix(W) Q = GraphUtils.modularity(Ws, clustering) self.assertEquals(Q, 4.0 / 9.0) W = numpy.ones((numVertices, numVertices)) Q = GraphUtils.modularity(W, clustering) self.assertEquals(Q, 0.0) Ws = scipy.sparse.csr_matrix(W) Q = GraphUtils.modularity(Ws, clustering) self.assertEquals(Q, 0.0)
""" Name: Generate Graph: Author: Jia_qiu Wang(王佳秋) Data: December, 2016 function: """ from apgl.graph.GeneralVertexList import GeneralVertexList from apgl.graph.SparseGraph import SparseGraph numVertices = 10 graph = SparseGraph(GeneralVertexList(numVertices)) graph[0, 1] = 1 graph[0, 2] = 1 P = graph.floydWarshall() print("geodesicDistance:", graph.geodesicDistance(P=P)) print("harmonicGeodesicDistance:", graph.harmonicGeodesicDistance(P=P))
def testGenerate(self): degSequence = numpy.array([2, 1, 3, 0, 0, 0, 0, 0, 0, 1]) generator = ConfigModelGenerator(degSequence) numVertices = 10 graph = SparseGraph(GeneralVertexList(numVertices)) graph = generator.generate(graph) tol = 3 self.assertTrue( numpy.linalg.norm(degSequence - graph.degreeSequence()) < tol) degSequence = numpy.array([2, 1, 3, 0, 2, 1, 4, 0, 0, 1]) generator.setOutDegSequence(degSequence) graph.removeAllEdges() graph = generator.generate(graph) self.assertTrue( numpy.linalg.norm(degSequence - graph.degreeSequence()) < tol) #Test using a non-empty graph degSequence = numpy.array([0, 0, 0, 2, 0, 0, 0, 1, 1, 0]) generator.setOutDegSequence(degSequence) oldDegSequence = graph.degreeSequence() self.assertRaises(ValueError, generator.generate, graph, True) graph = generator.generate(graph, False) diffSequence = graph.degreeSequence() - oldDegSequence self.assertTrue(numpy.linalg.norm(degSequence - diffSequence) < tol) #Test the case where we also have an in-degree sequence degSequence = numpy.array([2, 1, 3, 0, 0, 0, 0, 0, 0, 1]) inDegSequence = numpy.array([1, 1, 1, 1, 1, 1, 1, 0, 0, 0]) generator = ConfigModelGenerator(degSequence, inDegSequence) graph = SparseGraph(GeneralVertexList(numVertices)) self.assertRaises(ValueError, generator.generate, graph) graph = SparseGraph(GeneralVertexList(numVertices), False) graph = generator.generate(graph) self.assertTrue( numpy.linalg.norm(degSequence - graph.outDegreeSequence()) < tol) self.assertTrue( numpy.linalg.norm(inDegSequence - graph.inDegreeSequence()) < tol) outDegSequence = numpy.array([2, 1, 3, 0, 2, 1, 4, 0, 0, 1]) inDegSequence = numpy.array([1, 2, 1, 1, 2, 1, 2, 1, 2, 1]) generator.setOutDegSequence(outDegSequence) generator.setInDegSequence(inDegSequence) graph.removeAllEdges() graph = generator.generate(graph) self.assertTrue( numpy.linalg.norm(outDegSequence - graph.outDegreeSequence()) < tol) self.assertTrue( numpy.linalg.norm(inDegSequence - graph.inDegreeSequence()) < tol) #In the case that the in-degree sequence sum larger than that of the out-degree it is #not satisfied, but the out-degree should be. inDegSequence = numpy.array([1, 2, 1, 1, 2, 1, 2, 1, 5, 6]) generator.setInDegSequence(inDegSequence) graph.removeAllEdges() graph = generator.generate(graph) self.assertTrue( numpy.linalg.norm(outDegSequence - graph.outDegreeSequence()) < tol) #Now try the other way around generator.setOutDegSequence(inDegSequence) generator.setInDegSequence(outDegSequence) graph.removeAllEdges() graph = generator.generate(graph) self.assertTrue( numpy.linalg.norm(outDegSequence - graph.inDegreeSequence()) < tol) #Test growing graph outDegSequence = numpy.array([2, 1, 3, 0, 2, 1, 4, 0, 0, 1]) inDegSequence = numpy.array([1, 2, 1, 1, 2, 1, 2, 1, 2, 1]) generator.setOutDegSequence(outDegSequence) generator.setInDegSequence(inDegSequence) graph.removeAllEdges() graph = generator.generate(graph) newOutDegreeSequence = numpy.array([2, 1, 3, 5, 2, 1, 4, 0, 0, 1]) newInDegreeSequence = numpy.array([2, 3, 2, 2, 3, 1, 2, 1, 2, 1]) diffOutSequence = newOutDegreeSequence - graph.outDegreeSequence() diffInSequence = newInDegreeSequence - graph.inDegreeSequence() generator.setOutDegSequence(diffOutSequence) generator.setInDegSequence(diffInSequence) graph = generator.generate(graph, False) self.assertTrue( numpy.linalg.norm(newOutDegreeSequence - graph.outDegreeSequence()) < tol) self.assertTrue( numpy.linalg.norm(newInDegreeSequence - graph.inDegreeSequence()) < tol)
def setUp(self): self.VListType = GeneralVertexList self.numVertices = 10 self.vList = GeneralVertexList(self.numVertices) self.emptyVertex = None self.initialise()
""" Name: Generate Graph: Author: Jia_qiu Wang(王佳秋) Data: December, 2016 function: """ import numpy import scipy.sparse as sps from apgl.graph.GeneralVertexList import GeneralVertexList from apgl.graph.SparseGraph import SparseGraph numVertices = 10 vList = GeneralVertexList(numVertices) wght = sps.csc_matrix(numVertices, numVertices) graph = SparseGraph(vList, W=wght, undirected=False) graph[0, 1] = 1 graph[0, 2] = 1 graph.setVertex(0, "abc") graph.setVertex(1, 123) print(graph)
""" Name: Generate Graph: Author: Jia_qiu Wang(王佳秋) Data: December, 2016 function: """ from apgl.graph.DictGraph import DictGraph from apgl.graph.SparseGraph import SparseGraph from apgl.graph.GeneralVertexList import GeneralVertexList graph = DictGraph() graph.addEdge("a", "b") graph.addEdge("a", "c") graph.addEdge("a", "d") edgeIndices = graph.getAllEdgeIndices() graph2 = SparseGraph(GeneralVertexList(graph.getNumVertices())) graph2.addEdges(edgeIndices)
""" Name: Generate Graph: Author: Jia_qiu Wang(王佳秋) Data: December, 2016 function: """ from apgl.graph.DenseGraph import DenseGraph from apgl.graph.GeneralVertexList import GeneralVertexList from apgl.generator.ErdosRenyiGenerator import * numVertices = 20 graph = DenseGraph(GeneralVertexList(numVertices)) p = 0.2 generator = ErdosRenyiGenerator(p) graph = generator.generate(graph)
def __init__(self, vertices, undirected=True, W=None, dtype=numpy.float, frmt="csr"): """ Create a SparseGraph with a given AbstractVertexList or number of vertices, and specify whether it is directed. One can optionally pass in a sparse matrix W which is used as the weight matrix of the graph. Different kinds of sparse matrix can impact the speed of various operations. The currently supported sparse matrix types are: lil_matrix, csr_matrix, csc_matrix and dok_matrix. The default sparse matrix is csr_matrix. :param vertices: the initial set of vertices as a AbstractVertexList object, or an int to specify the number of vertices in which case vertices are stored in a GeneralVertexList. :param undirected: a boolean variable to indicate if the graph is undirected. :type undirected: :class:`boolean` :param W: a square sparse matrix of the same size as the number of vertices, or None to create the default one. :param dtype: the data type of the sparse matrix if W is not specified. :param frmt: the format of the sparse matrix: lil, csr or csc if W is not specified """ Parameter.checkBoolean(undirected) if isinstance(vertices, AbstractVertexList): self.vList = vertices elif isinstance(vertices, int): self.vList = GeneralVertexList(vertices) else: raise ValueError("Invalid vList parameter: " + str(vertices)) if W != None and not (sparse.issparse(W) and W.shape == ( self.vList.getNumVertices(), self.vList.getNumVertices())): raise ValueError( "Input argument W must be None or sparse matrix of size " + str(self.vList.getNumVertices())) self.undirected = undirected if frmt == "lil": matrix = sparse.lil_matrix elif frmt == "csr": matrix = sparse.csr_matrix elif frmt == "csc": matrix = sparse.csc_matrix else: raise ValueError("Invalid sparse matrix format: " + frmt) #Terrible hack alert: can't create a zero size sparse matrix, so we settle #for one of size 1. Better is to create a new class. if self.vList.getNumVertices() == 0 and W == None: self.W = matrix((1, 1), dtype=dtype) elif W == None: self.W = matrix( (self.vList.getNumVertices(), self.vList.getNumVertices()), dtype=dtype) else: self.W = W #The next line is for error checking mainly self.setWeightMatrix(W)