├── Kronecker_Generator.py ├── StochasticKroneckerGenerator.py ├── StochasticKroneckerGeneratorTest.py └── graph_kernel.py /Kronecker_Generator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Nov 1 12:07:10 2015 4 | 5 | @author: Pankaj 6 | """ 7 | 8 | import numpy as np 9 | import networkx as nx 10 | from scipy.sparse import dia_matrix, kron 11 | import scipy 12 | from scipy import sparse 13 | from apgl.graph.VertexList import VertexList 14 | from apgl.graph.SparseGraph import SparseGraph 15 | from apgl.generator.KroneckerGenerator import KroneckerGenerator 16 | import unittest 17 | 18 | # Basic sparse kronecker product 19 | A = sparse.csr_matrix(np.array([[0, 2], [5, 0]])) 20 | B = sparse.csr_matrix(np.array([[1, 2], [3, 4]])) 21 | sparse.kron(A, B).toarray() 22 | sparse.kron(A, B).todense() 23 | 24 | # Construct a 1000x1000 lil_matrix 25 | from scipy.sparse import lil_matrix 26 | from numpy.random import rand 27 | A1 = lil_matrix((1000, 1000)) 28 | A1[0, :100] = rand(100) 29 | A1[1, 100:200] = A1[0, :100] 30 | A1.setdiag(rand(1000)) 31 | # converting in CSR format 32 | A1 = A1.tocsr() 33 | 34 | # Construct anther matrix 35 | B1 = lil_matrix((1000, 1000)) 36 | B1[0, :100] = rand(100) 37 | B1[1, 100:200] = B1[0, :100] 38 | B1.setdiag(rand(1000)) 39 | # converting in CSR forma 40 | B1 = B1.tocsr() 41 | 42 | # Sparse kronecker product 43 | C1 = sparse.kron(A1, B1).toarray() 44 | 45 | #sparse kronecker sum 46 | C2 = sparse.kronsum(A1,B1).toarray() 47 | 48 | # Sparse Kronecker product diagonal matrix 49 | def populatematrix1(dim): 50 | return dia_matrix( (np.array( [np.array([2]*5),np.array([1]*5), np.array([1]*5)] ),np.array([0,1,-1]) ),shape=(5,5)) 51 | def populatematrix2(dim): 52 | return dia_matrix( (np.array( [np.array([2]*5),np.array([1]*5), np.array([1]*5)] ),np.array([0,1,-1]) ),shape=(5,5)) 53 | 54 | dx = np.linspace(0,1,5) 55 | x = populatematrix1(len(dx)) 56 | print (x.shape, type(x)) 57 | y = populatematrix2(len(dx)) 58 | print (y.shape, type(y)) 59 | z = kron(x,y) 60 | print (z.shape) 61 | 62 | # Generating simple graph 63 | 64 | numVertices = 5000 65 | 66 | weightMatrix = scipy.sparse.lil_matrix((numVertices, numVertices)) 67 | graph = SparseGraph(numVertices, W=weightMatrix) 68 | graph[0, 1] = 1 69 | graph[0, 2] = 1 70 | 71 | #Output the number of vertices 72 | print(graph.size) 73 | 74 | # PLotting Graph 75 | a = np.reshape(np.random.random_integers(0,1,size=100),(10,10)) 76 | G= nx.DiGraph(a) 77 | nx.draw(G) 78 | 79 | # Computing Matrix Exponetaial 80 | 81 | Mat_Exp = scipy.linalg.expm(a, q=None) 82 | 83 | # Outputsum of all elements 84 | 85 | Sum = np.sum(Mat_Exp) 86 | Cul_Sum = np.cumsum(Mat_Exp) 87 | 88 | 89 | 90 | # Other Know method from different authors. 91 | # generating graph 92 | 93 | class KroneckerGenerator(object): 94 | ''' 95 | A class which generates graphs according to the Kronecker method. 96 | ''' 97 | def __init__(self, initialGraph, k): 98 | """ 99 | Initialise with a starting graph, and number of iterations k. Note that 100 | the starting graph must have self edges on every vertex. Only the 101 | adjacency matrix of the starting graph is used. 102 | 103 | :param initialGraph: The intial graph to use. 104 | :type initialGraph: :class:`apgl.graph.AbstractMatrixGraph` 105 | 106 | :param k: The number of iterations. 107 | :type k: :class:`int` 108 | """ 109 | Parameter.checkInt(k, 1, float('inf')) 110 | 111 | W = initialGraph.getWeightMatrix() 112 | if (np.diag(W)==np.zeros(W.shape[0])).any(): 113 | raise ValueError("Initial graph must have all self-edges") 114 | 115 | self.initialGraph = initialGraph 116 | self.k = k 117 | 118 | def setK(self, k): 119 | """ 120 | Set the number of iterations k. 121 | 122 | :param k: The number of iterations. 123 | :type k: :class:`int` 124 | """ 125 | Parameter.checkInt(k, 1, float('inf')) 126 | self.k = k 127 | 128 | def generate(self): 129 | """ 130 | Generate a Kronecker graph using the adjacency matrix of the input graph. 131 | 132 | :returns: The generate graph as a SparseGraph object. 133 | """ 134 | W = self.initialGraph.adjacencyMatrix() 135 | Wi = W 136 | 137 | for i in range(1, self.k): 138 | Wi = np.kron(Wi, W) 139 | 140 | vList = VertexList(Wi.shape[0], 0) 141 | graph = SparseGraph(vList, self.initialGraph.isUndirected()) 142 | graph.setWeightMatrix(Wi) 143 | 144 | return graph 145 | 146 | class KroneckerGeneratorTest(unittest.TestCase): 147 | def setUp(self): 148 | pass 149 | 150 | def testGenerate(self): 151 | k = 2 152 | numVertices = 1000 153 | numFeatures = 0 154 | 155 | vList = VertexList(numVertices, numFeatures) 156 | initialGraph = SparseGraph(vList) 157 | initialGraph.addEdge(0, 1) 158 | initialGraph.addEdge(1, 2) 159 | 160 | for i in range(numVertices): 161 | initialGraph.addEdge(i, i) 162 | 163 | generator = KroneckerGenerator(initialGraph, k) 164 | 165 | graph = generator.generate() 166 | print (graph.size) 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /StochasticKroneckerGenerator.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy 3 | from apgl.util.Parameter import Parameter 4 | from apgl.graph.VertexList import VertexList 5 | from apgl.graph.SparseGraph import SparseGraph 6 | 7 | class StochasticKroneckerGenerator(object): 8 | ''' 9 | A class which generates graphs according to the Stochastic Kronecker method. 10 | ''' 11 | def __init__(self, initialGraph, k): 12 | """ 13 | Initialise with a starting graph, and number of iterations k. The weights 14 | of the initial graph correspond to probabilities. 15 | 16 | :param initialGraph: The intial graph to use. 17 | :type initialGraph: :class:`apgl.graph.AbstractMatrixGraph` 18 | 19 | :param k: The number of iterations. 20 | :type k: :class:`int` 21 | """ 22 | Parameter.checkInt(k, 1, float('inf')) 23 | edgeVals = initialGraph.getEdgeValues(initialGraph.getAllEdges()) 24 | Parameter.checkList(edgeVals, Parameter.checkFloat, [0.0, 1.0]) 25 | 26 | W = initialGraph.getWeightMatrix() 27 | if (numpy.diag(W)==numpy.zeros(W.shape[0])).any(): 28 | raise ValueError("Initial graph must have all self-edges") 29 | 30 | self.initialGraph = initialGraph 31 | self.k = k 32 | 33 | def setK(self, k): 34 | """ 35 | Set the number of iterations k. 36 | 37 | :param initialGraph: The number of iterations. 38 | :type initialGraph: :class:`int` 39 | """ 40 | Parameter.checkInt(k, 1, float('inf')) 41 | self.k = k 42 | 43 | def generateGraph(self): 44 | """ 45 | Generate a Kronecker graph 46 | """ 47 | W = self.initialGraph.getWeightMatrix() 48 | Wi = W 49 | 50 | for i in range(1, self.k): 51 | Wi = numpy.kron(Wi, W) 52 | 53 | P = numpy.random.rand(Wi.shape[0], Wi.shape[0]) 54 | Wi = numpy.array(P < Wi, numpy.float64) 55 | 56 | vList = VertexList(Wi.shape[0], 0) 57 | graph = SparseGraph(vList, self.initialGraph.isUndirected()) 58 | graph.setWeightMatrix(Wi) 59 | 60 | return graph -------------------------------------------------------------------------------- /StochasticKroneckerGeneratorTest.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy 3 | from apgl.graph.VertexList import VertexList 4 | from apgl.graph.SparseGraph import SparseGraph 5 | from apgl.generator.StochasticKroneckerGenerator import StochasticKroneckerGenerator 6 | import unittest 7 | import logging 8 | 9 | class StochasticKroneckerGeneratorTest(unittest.TestCase): 10 | def setUp(self): 11 | pass 12 | 13 | def testGenerateGraph(self): 14 | k = 2 15 | numVertices = 3 16 | numFeatures = 0 17 | 18 | vList = VertexList(numVertices, numFeatures) 19 | initialGraph = SparseGraph(vList) 20 | initialGraph.addEdge(0, 1) 21 | initialGraph.addEdge(1, 2) 22 | 23 | for i in range(numVertices): 24 | initialGraph.addEdge(i, i) 25 | 26 | d = initialGraph.diameter() 27 | degreeSequence = initialGraph.outDegreeSequence() 28 | generator = StochasticKroneckerGenerator(initialGraph, k) 29 | 30 | graph = generator.generateGraph() 31 | d2 = graph.diameter() 32 | degreeSequence2 = graph.outDegreeSequence() 33 | 34 | self.assertTrue((numpy.kron(degreeSequence, degreeSequence) == degreeSequence2).all()) 35 | self.assertTrue(graph.getNumVertices() == numVertices**k) 36 | self.assertTrue(graph.getNumDirEdges() == initialGraph.getNumDirEdges()**k) 37 | self.assertEquals(d, d2) 38 | 39 | #Try different k 40 | k = 3 41 | generator.setK(k) 42 | graph = generator.generateGraph() 43 | d3 = graph.diameter() 44 | degreeSequence3 = graph.outDegreeSequence() 45 | 46 | self.assertTrue((numpy.kron(degreeSequence, degreeSequence2) == degreeSequence3).all()) 47 | self.assertTrue(graph.getNumVertices() == numVertices**k) 48 | self.assertTrue(graph.getNumDirEdges() == initialGraph.getNumDirEdges()**k) 49 | self.assertEquals(d, d3) 50 | 51 | #Test the multinomial degree distribution 52 | logging.debug(degreeSequence) 53 | logging.debug(degreeSequence2) 54 | logging.debug(degreeSequence3) 55 | 56 | def testDegreeDistribution(self): 57 | #We want to see how the degree distribution changes with kronecker powers 58 | 59 | 60 | numVertices = 3 61 | numFeatures = 0 62 | 63 | vList = VertexList(numVertices, numFeatures) 64 | initialGraph = SparseGraph(vList) 65 | initialGraph.addEdge(0, 1) 66 | initialGraph.addEdge(1, 2) 67 | 68 | for i in range(numVertices): 69 | initialGraph.addEdge(i, i) 70 | 71 | logging.debug((initialGraph.outDegreeSequence())) 72 | logging.debug((initialGraph.degreeDistribution())) 73 | 74 | k = 2 75 | generator = StochasticKroneckerGenerator(initialGraph, k) 76 | graph = generator.generateGraph() 77 | 78 | logging.debug((graph.outDegreeSequence())) 79 | logging.debug((graph.degreeDistribution())) 80 | 81 | k = 3 82 | generator = StochasticKroneckerGenerator(initialGraph, k) 83 | graph = generator.generateGraph() 84 | 85 | logging.debug((graph.degreeDistribution())) -------------------------------------------------------------------------------- /graph_kernel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu Oct 29 12:45:00 2015 4 | 5 | @author: Pankaj 6 | """ 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import scipy.sparse 10 | import scipy as sp 11 | from scipy import linalg 12 | from scipy import sparse as sps 13 | from scipy.sparse import linalg as spla 14 | from apgl.graph import * 15 | from apgl.generator.KroneckerGenerator import KroneckerGenerator 16 | 17 | initialGraph = SparseGraph(VertexList(5, 1)) 18 | initialGraph.addEdge(1, 2) 19 | initialGraph.addEdge(2, 3) 20 | for i in range(5): 21 | initialGraph.addEdge(i,i) 22 | k=2 23 | generator = KroneckerGenerator(initialGraph, k) 24 | graph = generator.generate() --------------------------------------------------------------------------------