def startElement(self, name, attrs): """ Parses all currently relevant XML tags and retrieves data.""" if name == "graph": # determine, if graph is directed: if attrs.getValue("edgedefault") == "directed": print("identified graph as directed") self.directed = True if "id" in attrs.getNames() and not attrs.getValue("id") == '': self.graphName = attrs.getValue("id") self.g = Graph(0, self.weighted, self.directed) self.g.setName(self.graphName) if name == "node": u = self.g.addNode() val = attrs.getValue("id") self.mapping[val] = u elif name == "edge": u = attrs.getValue("source") v = attrs.getValue("target") self.edgestack.append((u, v)) elif name == "key": #print("found element with tag KEY") if (attrs.getValue("for") == 'edge' and attrs.getValue("attr.name") == 'weight' and attrs.getValue("attr.type") == 'double'): self.weighted = True self.weightedID = attrs.getValue("id") print("identified graph as weighted") elif name == "data" and attrs.getValue("key") == self.weightedID: self.keepData = True
def setUp(self): from _NetworKit import Graph self.g = Graph(5) self.g.addEdge(0, 1) self.g.addEdge(0, 2) self.g.addEdge(0, 3) self.g.addEdge(0, 4)
def get_value(self, graph: Graph): self.logger.debug('calculate number of triangles') graph.indexEdges() triangles = TriangleEdgeScore(graph).run().scores() res = [] for item in self.process_centrality(triangles): res.append(float(item)) return res
def generate(self): G = Graph(self.n) for u in G.nodes(): if u is 0: pass else: G.addEdge(u, 0) return G
def __init__(self): """ Initializes the GEXFReader class """ self.mapping = dict() self.g = Graph(0) self.weighted = False self.directed = False self.dynamic = False self.hasDynamicWeights = False self.q = queue.Queue() self.eventStream = [] self.nInitialNodes = 0 self.timeFormat = ""
def __init__(self): """ Initializes several important variables """ xml.sax.ContentHandler.__init__(self) self.charBuffer = [] self.mapping = dict() self.g = Graph(0) self.graphName = 'unnamed' self.weightedID = '' self.weighted = False self.directed = False self.edgestack = [] self.edgeweight = 0.0 self.keepData = False
def startElement(self, name, attrs): """ Parses all currently relevant XML tags and retrieves data.""" if name == "graph": # determine, if graph is directed: if attrs.getValue("edgedefault") == "directed": print("identified graph as directed") self.directed = True if "id" in attrs.getNames() and not attrs.getValue("id") == '': self.graphName = attrs.getValue("id") self.g = Graph(0,self.weighted, self.directed) self.g.setName(self.graphName) if name == "node": u = self.g.addNode() val = attrs.getValue("id") self.mapping[val] = u elif name == "edge": u = attrs.getValue("source") v = attrs.getValue("target") self.edgestack.append((u,v)) elif name == "key": #print("found element with tag KEY") if (attrs.getValue("for") == 'edge' and attrs.getValue("attr.name") == 'weight' and attrs.getValue("attr.type") == 'double'): self.weighted = True self.weightedID = attrs.getValue("id") print("identified graph as weighted") elif name == "data" and attrs.getValue("key") == self.weightedID: self.keepData = True
def setUp(self): from _NetworKit import Graph self.g = Graph(5) self.g.addEdge(0,1) self.g.addEdge(0,2) self.g.addEdge(0,3) self.g.addEdge(0,4)
def graphFromStream(stream, weighted, directed): """ Convenience function for creating a new graph from a stream of graph events Parameters ---------- stream : list of GraphEvent event stream weighted : produce a weighted or unweighted graph boolean directed : produce a directed or undirected graph boolean """ G = Graph(0, weighted, directed) gu = GraphUpdater(G) gu.update(stream) return G
class TestExtMETISGraphReader(unittest.TestCase): def setUp(self): from _NetworKit import Graph self.g = Graph(5) self.g.addEdge(0, 1) self.g.addEdge(0, 2) self.g.addEdge(0, 3) self.g.addEdge(0, 4) def test_readAndWrite(self): # from networkit.graphio import METISGraphReader from _NetworKit import METISGraphReader from _NetworKit import METISGraphWriter w = METISGraphWriter() w.write(self.g, "output/metis_test.graph") self.assertTrue(os.path.isfile("output/metis_test.graph")) r = METISGraphReader() testg = r.read("output/metis_test.graph") self.assertEqual(self.g.numberOfNodes(), testg.numberOfNodes()) self.assertEqual(self.g.numberOfEdges(), testg.numberOfEdges())
class TestExtMETISGraphReader(unittest.TestCase): def setUp(self): from _NetworKit import Graph self.g = Graph(5) self.g.addEdge(0,1) self.g.addEdge(0,2) self.g.addEdge(0,3) self.g.addEdge(0,4) def test_readAndWrite(self): # from networkit.graphio import METISGraphReader from _NetworKit import METISGraphReader from _NetworKit import METISGraphWriter w = METISGraphWriter() w.write(self.g, "output/metis_test.graph") self.assertTrue(os.path.isfile("output/metis_test.graph")) r = METISGraphReader() testg = r.read("output/metis_test.graph") self.assertEqual(self.g.numberOfNodes(), testg.numberOfNodes()) self.assertEqual(self.g.numberOfEdges(), testg.numberOfEdges())
def get_value(self, graph: Graph): self.logger.debug('Calculate node count') return [graph.numberOfNodes()]
class GEXFReader: def __init__(self): """ Initializes the GEXFReader class """ self.mapping = dict() self.g = Graph(0) self.weighted = False self.directed = False self.dynamic = False self.hasDynamicWeights = False self.q = queue.Queue() self.eventStream = [] self.nInitialNodes = 0 self.ctr = 0 self.timeFormat = "" def read(self, fpath): """ Reads and returns the graph object defined in fpath """ #0. Reset internal vars and parse the xml self.__init__() doc = minidom.parse(fpath) #1. Determine if graph is dynamic, directed and has dynamically changing weights graph = doc.getElementsByTagName("graph")[0] if (graph.getAttribute("defaultedgetype") == "directed"): self.directed = True if (graph.getAttribute("mode") == "dynamic"): self.dynamic = True if self.dynamic: self.timeFormat = graph.getAttribute("timeformat") attributes = graph.getElementsByTagName("attribute") for att in attributes: if att.getAttribute("id") == "weight": self.hasDynamicWeights = True self.weighted = True #2. Read nodes and map them to IDs defined in GEXF file nodes = doc.getElementsByTagName("node") for n in nodes: u = n.getAttribute("id") if self.dynamic: # 2-way mapping to refer nodes back in mapDynamicNodes() method self.mapping[u] = self.ctr self.mapping[self.ctr] = u controlList = {'elementAdded': False, 'elementDeleted': False} spells = n.getElementsByTagName("spell") if len(spells) > 0: for s in spells: self.parseDynamics(s, "n", controlList, u) else: self.parseDynamics(n, "n", controlList, u) self.ctr += 1 else: self.mapping[u] = self.nInitialNodes self.nInitialNodes +=1 if self.dynamic: self.mapDynamicNodes() #3. Read edges and determine if graph is weighted edges = doc.getElementsByTagName("edge") for e in edges: u = e.getAttribute("source") v = e.getAttribute("target") w = "1.0" if e.hasAttribute("weight"): self.weighted = True w = e.getAttribute("weight") if self.dynamic: controlList = {'elementAdded': False, 'elementDeleted': False} spells = e.getElementsByTagName("spell") if len(spells) > 0: for s in spells: self.parseDynamics(s, "e", controlList, u, v, w) else: self.parseDynamics(e, "e", controlList, u, v, w) else: self.q.put((u, v, w)) #4. Create graph object self.g = Graph(self.nInitialNodes, self.weighted, self.directed) #5. Add initial edges to the graph and sort the eventStream by time #5.1 Adding initial edges while not self.q.empty(): edge = self.q.get() (u, v, w) = (edge[0], edge[1], float(edge[2])) self.g.addEdge(self.mapping[u], self.mapping[v], w) #5.2 Sorting the eventStream by time and adding timeStep between events that happen in different times self.eventStream.sort(key=lambda x:x[1]) for i in range(1, len(self.eventStream)): if self.eventStream[i][1] != self.eventStream[i-1][1]: self.eventStream.append((GraphEvent(GraphEvent.TIME_STEP, 0, 0, 0), self.eventStream[i-1][1])) self.eventStream.sort(key=lambda x:x[1]) self.eventStream = [event[0] for event in self.eventStream] return (self.g, self.eventStream) def parseDynamics(self, element, elementType, controlList, u, v = "0", w = "0"): """ Determine the operations as follows: 1.Element has start and not deleted before: Create add event 2.Element has start and deleted before: Create restore event 3.Element has end:Create del event 4.If an element has end before start(or no start at all), add it to the initial graph 5.For dynamic edges, simply go over the attvalues and create weight update events * A dynamic element must be defined either using only spells or inline attributes. These 2 shouldn't be mixed. (For example, Gephi will treat them differently. It'll ignore the inline declaration if the same element also contains spells) """ startTime = element.getAttribute("start") if startTime == "": startTime = element.getAttribute("startopen") endTime = element.getAttribute("end") if endTime == "": endTime = element.getAttribute("endopen") if self.timeFormat != "date": try: startTime = float(startTime) except: pass try: endTime = float(endTime) except: pass if startTime != "" and endTime != "": if startTime < endTime and not controlList['elementDeleted']: self.createEvent(startTime, "a"+elementType, u, v, w) controlList['elementAdded'] = True else: self.createEvent(startTime, "r"+elementType, u, v, w) self.createEvent(endTime, "d"+elementType, u, v, w) controlList['elementDeleted'] = True if startTime != "" and endTime == "": if controlList['elementDeleted']: self.createEvent(startTime, "r"+elementType, u, v, w) else: self.createEvent(startTime, "a"+elementType, u, v, w) controlList['elementAdded'] = True # Handle dynamic edge weights here if elementType == "e" and self.hasDynamicWeights: attvalues = element.getElementsByTagName("attvalue") # If a spell is traversed, attvalues are siblings if len(attvalues) == 0: attvalues = element.parentNode.parentNode.getElementsByTagName("attvalue") for att in attvalues: if att.getAttribute("for") == "weight": w = att.getAttribute("value") startTime = att.getAttribute("start") if startTime == "": startTime = att.getAttribute("startopen") if self.timeFormat != "date": startTime = float(startTime) # If this edge is not added, first weight update indicates edge addition if not controlList['elementAdded']: self.createEvent(startTime, "a"+elementType, u, v, w) controlList['elementAdded'] = True else: self.createEvent(startTime, "c"+elementType, u, v, w) if startTime == "": if not controlList['elementAdded']: if elementType == "n": self.mapping[u] = self.ctr self.nInitialNodes += 1 else: self.q.put((u,v,w)) controlList['elementAdded'] = True if endTime != "": self.createEvent(endTime, "d"+elementType, u, v, w) controlList['elementDeleted'] = True def createEvent(self, eventTime, eventType, u, v, w): """ Creates a NetworKit::GraphEvent from the supplied parameters and passes it to eventStream """ event, u = None, self.mapping[u] if eventType[1] == "e": v, w = self.mapping[v], float(w) if eventType == "an": event = GraphEvent(GraphEvent.NODE_ADDITION, u, 0, 0) elif eventType == "dn": event = GraphEvent(GraphEvent.NODE_REMOVAL, u, 0, 0) elif eventType == "rn": event = GraphEvent(GraphEvent.NODE_RESTORATION, u, 0, 0) elif eventType == "ae" or eventType == "re": event = GraphEvent(GraphEvent.EDGE_ADDITION, u, v, w) elif eventType == "de": event = GraphEvent(GraphEvent.EDGE_REMOVAL, u, v, w) elif eventType == "ce": event = GraphEvent(GraphEvent.EDGE_WEIGHT_UPDATE, u, v, w) self.eventStream.append((event, eventTime)) def mapDynamicNodes(self): """ Node ID of a dynamic node must be determined before it's mapped to its GEXF ID. This requires processing the sorted eventStream and figuring out the addition order of the nodes. After that, node addition/deletion/restoration operations of this node must be readded to eventStream with correct mapping. !Note: New mapping of a node can be equal to old mapping of a node. In order to prevent collisions, isMapped array must be maintained and controlled. """ nNodes = self.nInitialNodes nEvent = len(self.eventStream) isMapped = [False] * nEvent self.eventStream.sort(key=lambda x:x[1]) for i in range(0, nEvent): event = self.eventStream[i] # Only the nodes with addition event will get remapped. if not isMapped[i] and event[0].type == GraphEvent.NODE_ADDITION: u = event[0].u self.mapping[self.mapping[u]] = nNodes # All the other events of that node comes after it's addition event for j in range(i, len(self.eventStream)): event = self.eventStream[j] if not isMapped[j] and event[0].u == u: mappedEvent = GraphEvent(event[0].type, self.mapping[self.mapping[u]], 0, 0) self.eventStream[j] = (mappedEvent, event[1]) isMapped[j] = True nNodes +=1 isMapped[i] = True
def read(self, fpath): """ Reads and returns the graph object defined in fpath """ #0. Reset internal vars and parse the xml self.__init__() doc = minidom.parse(fpath) #1. Determine if graph is dynamic, directed and has dynamically changing weights graph = doc.getElementsByTagName("graph")[0] if (graph.getAttribute("defaultedgetype") == "directed"): self.directed = True if (graph.getAttribute("mode") == "dynamic"): self.dynamic = True if self.dynamic: self.timeFormat = graph.getAttribute("timeformat") attributes = graph.getElementsByTagName("attribute") for att in attributes: if att.getAttribute("id") == "weight": self.hasDynamicWeights = True self.weighted = True #2. Read nodes and map them to IDs defined in GEXF file nodes = doc.getElementsByTagName("node") for n in nodes: u = n.getAttribute("id") if self.dynamic: # 2-way mapping to refer nodes back in mapDynamicNodes() method self.mapping[u] = self.ctr self.mapping[self.ctr] = u controlList = {'elementAdded': False, 'elementDeleted': False} spells = n.getElementsByTagName("spell") if len(spells) > 0: for s in spells: self.parseDynamics(s, "n", controlList, u) else: self.parseDynamics(n, "n", controlList, u) self.ctr += 1 else: self.mapping[u] = self.nInitialNodes self.nInitialNodes +=1 if self.dynamic: self.mapDynamicNodes() #3. Read edges and determine if graph is weighted edges = doc.getElementsByTagName("edge") for e in edges: u = e.getAttribute("source") v = e.getAttribute("target") w = "1.0" if e.hasAttribute("weight"): self.weighted = True w = e.getAttribute("weight") if self.dynamic: controlList = {'elementAdded': False, 'elementDeleted': False} spells = e.getElementsByTagName("spell") if len(spells) > 0: for s in spells: self.parseDynamics(s, "e", controlList, u, v, w) else: self.parseDynamics(e, "e", controlList, u, v, w) else: self.q.put((u, v, w)) #4. Create graph object self.g = Graph(self.nInitialNodes, self.weighted, self.directed) #5. Add initial edges to the graph and sort the eventStream by time #5.1 Adding initial edges while not self.q.empty(): edge = self.q.get() (u, v, w) = (edge[0], edge[1], float(edge[2])) self.g.addEdge(self.mapping[u], self.mapping[v], w) #5.2 Sorting the eventStream by time and adding timeStep between events that happen in different times self.eventStream.sort(key=lambda x:x[1]) for i in range(1, len(self.eventStream)): if self.eventStream[i][1] != self.eventStream[i-1][1]: self.eventStream.append((GraphEvent(GraphEvent.TIME_STEP, 0, 0, 0), self.eventStream[i-1][1])) self.eventStream.sort(key=lambda x:x[1]) self.eventStream = [event[0] for event in self.eventStream] return (self.g, self.eventStream)
class GraphMLSAX(xml.sax.ContentHandler): """ Parser for GraphML XML files, based on Pythons XML.SAX implementation. """ def __init__(self): """ Initializes several important variables """ xml.sax.ContentHandler.__init__(self) self.charBuffer = [] self.mapping = dict() self.g = Graph(0) self.graphName = 'unnamed' self.weightedID = '' self.weighted = False self.directed = False self.edgestack = [] self.edgeweight = 0.0 self.keepData = False def startElement(self, name, attrs): """ Parses all currently relevant XML tags and retrieves data.""" if name == "graph": # determine, if graph is directed: if attrs.getValue("edgedefault") == "directed": print("identified graph as directed") self.directed = True if "id" in attrs.getNames() and not attrs.getValue("id") == '': self.graphName = attrs.getValue("id") self.g = Graph(0, self.weighted, self.directed) self.g.setName(self.graphName) if name == "node": u = self.g.addNode() val = attrs.getValue("id") self.mapping[val] = u elif name == "edge": u = attrs.getValue("source") v = attrs.getValue("target") self.edgestack.append((u, v)) elif name == "key": #print("found element with tag KEY") if (attrs.getValue("for") == 'edge' and attrs.getValue("attr.name") == 'weight' and attrs.getValue("attr.type") == 'double'): self.weighted = True self.weightedID = attrs.getValue("id") print("identified graph as weighted") elif name == "data" and attrs.getValue("key") == self.weightedID: self.keepData = True def endElement(self, name): """ Finalizes parsing of the started Element and processes retrieved data.""" data = self.getCharacterData() if name == "edge": u = self.edgestack[len(self.edgestack) - 1][0] v = self.edgestack[len(self.edgestack) - 1][1] self.edgestack.pop() if self.weighted: #print ("identified edge as weighted with weight: {0}".format(edgeweight)) self.g.addEdge(self.mapping[u], self.mapping[v], self.edgeweight) self.edgeweight = 0.0 else: self.g.addEdge(self.mapping[u], self.mapping[v]) elif name == "data" and self.keepData: self.keepData = False self.edgeweight = float(data) def characters(self, content): self.charBuffer.append(content) def getCharacterData(self): data = ''.join(self.charBuffer).strip() self.charBuffer = [] return data def getGraph(self): return self.g
def read(self, fpath): """ Reads and returns the graph object defined in fpath """ #0. Reset internal vars and parse the xml self.__init__() doc = minidom.parse(fpath) #1. Determine if graph is dynamic, directed and has dynamically changing weights graph = doc.getElementsByTagName("graph")[0] if (graph.getAttribute("defaultedgetype") == "directed"): self.directed = True if (graph.getAttribute("mode") == "dynamic"): self.dynamic = True if self.dynamic: self.timeFormat = graph.getAttribute("timeformat") attributes = graph.getElementsByTagName("attribute") for att in attributes: if att.getAttribute("id") == "weight": self.hasDynamicWeights = True self.weighted = True #2. Read nodes and map them to IDs defined in GEXF file nodes = doc.getElementsByTagName("node") for n in nodes: u = n.getAttribute("id") if self.dynamic: """ A GEXF ID can be a string. However, this version of parser accepts ids in only 2 formats: 1. id = "0,1,2," etc. 2. id = "n0, n1, n2" etc. So either an integer or an integer that has n prefix. Gephi generates its random graphs in 2nd format for example. """ _id = "" try: _id = int(u) except: _id = int(u[1:]) # 2-way mapping to refer nodes back in mapDynamicNodes() method self.mapping[u] = _id self.mapping[_id] = u controlList = {'elementAdded': False, 'elementDeleted': False} spells = n.getElementsByTagName("spell") if len(spells) > 0: for s in spells: self.parseDynamics(s, "n", controlList, u) else: self.parseDynamics(n, "n", controlList, u) else: self.mapping[u] = self.nInitialNodes self.nInitialNodes +=1 if self.dynamic: self.mapDynamicNodes() #3. Read edges and determine if graph is weighted edges = doc.getElementsByTagName("edge") for e in edges: u = e.getAttribute("source") v = e.getAttribute("target") w = "1.0" if e.hasAttribute("weight"): self.weighted = True w = e.getAttribute("weight") if self.dynamic: controlList = {'elementAdded': False, 'elementDeleted': False} spells = e.getElementsByTagName("spell") if len(spells) > 0: for s in spells: self.parseDynamics(s, "e", controlList, u, v, w) else: self.parseDynamics(e, "e", controlList, u, v, w) else: self.q.put((u, v, w)) #4. Create graph object self.g = Graph(self.nInitialNodes, self.weighted, self.directed) #5. Add initial edges to the graph and sort the eventStream by time #5.1 Adding initial edges while not self.q.empty(): edge = self.q.get() (u, v, w) = (edge[0], edge[1], float(edge[2])) self.g.addEdge(self.mapping[u], self.mapping[v], w) #5.2 Sorting the eventStream by time and adding timeStep between events that happen in different times self.eventStream.sort(key=lambda x:x[1]) for i in range(1, len(self.eventStream)): if self.eventStream[i][1] != self.eventStream[i-1][1]: self.eventStream.append((GraphEvent(GraphEvent.TIME_STEP, 0, 0, 0), self.eventStream[i-1][1])) self.eventStream.sort(key=lambda x:x[1]) self.eventStream = [event[0] for event in self.eventStream] return (self.g, self.eventStream)
class GEXFReader: def __init__(self): """ Initializes the GEXFReader class """ self.mapping = dict() self.g = Graph(0) self.weighted = False self.directed = False self.dynamic = False self.hasDynamicWeights = False self.q = queue.Queue() self.eventStream = [] self.nInitialNodes = 0 self.timeFormat = "" def read(self, fpath): """ Reads and returns the graph object defined in fpath """ #0. Reset internal vars and parse the xml self.__init__() doc = minidom.parse(fpath) #1. Determine if graph is dynamic, directed and has dynamically changing weights graph = doc.getElementsByTagName("graph")[0] if (graph.getAttribute("defaultedgetype") == "directed"): self.directed = True if (graph.getAttribute("mode") == "dynamic"): self.dynamic = True if self.dynamic: self.timeFormat = graph.getAttribute("timeformat") attributes = graph.getElementsByTagName("attribute") for att in attributes: if att.getAttribute("id") == "weight": self.hasDynamicWeights = True self.weighted = True #2. Read nodes and map them to IDs defined in GEXF file nodes = doc.getElementsByTagName("node") for n in nodes: u = n.getAttribute("id") if self.dynamic: """ A GEXF ID can be a string. However, this version of parser accepts ids in only 2 formats: 1. id = "0,1,2," etc. 2. id = "n0, n1, n2" etc. So either an integer or an integer that has n prefix. Gephi generates its random graphs in 2nd format for example. """ _id = "" try: _id = int(u) except: _id = int(u[1:]) # 2-way mapping to refer nodes back in mapDynamicNodes() method self.mapping[u] = _id self.mapping[_id] = u controlList = {'elementAdded': False, 'elementDeleted': False} spells = n.getElementsByTagName("spell") if len(spells) > 0: for s in spells: self.parseDynamics(s, "n", controlList, u) else: self.parseDynamics(n, "n", controlList, u) else: self.mapping[u] = self.nInitialNodes self.nInitialNodes +=1 if self.dynamic: self.mapDynamicNodes() #3. Read edges and determine if graph is weighted edges = doc.getElementsByTagName("edge") for e in edges: u = e.getAttribute("source") v = e.getAttribute("target") w = "1.0" if e.hasAttribute("weight"): self.weighted = True w = e.getAttribute("weight") if self.dynamic: controlList = {'elementAdded': False, 'elementDeleted': False} spells = e.getElementsByTagName("spell") if len(spells) > 0: for s in spells: self.parseDynamics(s, "e", controlList, u, v, w) else: self.parseDynamics(e, "e", controlList, u, v, w) else: self.q.put((u, v, w)) #4. Create graph object self.g = Graph(self.nInitialNodes, self.weighted, self.directed) #5. Add initial edges to the graph and sort the eventStream by time #5.1 Adding initial edges while not self.q.empty(): edge = self.q.get() (u, v, w) = (edge[0], edge[1], float(edge[2])) self.g.addEdge(self.mapping[u], self.mapping[v], w) #5.2 Sorting the eventStream by time and adding timeStep between events that happen in different times self.eventStream.sort(key=lambda x:x[1]) for i in range(1, len(self.eventStream)): if self.eventStream[i][1] != self.eventStream[i-1][1]: self.eventStream.append((GraphEvent(GraphEvent.TIME_STEP, 0, 0, 0), self.eventStream[i-1][1])) self.eventStream.sort(key=lambda x:x[1]) self.eventStream = [event[0] for event in self.eventStream] return (self.g, self.eventStream) def parseDynamics(self, element, elementType, controlList, u, v = "0", w = "0"): """ Determine the operations as follows: 1.Element has start and not deleted before: Create add event 2.Element has start and deleted before: Create restore event 3.Element has end:Create del event 4.If an element has end before start(or no start at all), add it to the initial graph 5.For dynamic edges, simply go over the attvalues and create weight update events * A dynamic element must be defined either using only spells or inline attributes. These 2 shouldn't be mixed. (For example, Gephi will treat them differently. It'll ignore the inline declaration if the same element also contains spells) """ startTime = element.getAttribute("start") if startTime == "": startTime = element.getAttribute("startopen") endTime = element.getAttribute("end") if endTime == "": endTime = element.getAttribute("endopen") if self.timeFormat != "date": try: startTime = float(startTime) except: pass try: endTime = float(endTime) except: pass if startTime != "" and endTime != "": if startTime < endTime and not controlList['elementDeleted']: self.createEvent(startTime, "a"+elementType, u, v, w) controlList['elementAdded'] = True else: self.createEvent(startTime, "r"+elementType, u, v, w) self.createEvent(endTime, "d"+elementType, u, v, w) controlList['elementDeleted'] = True if startTime != "" and endTime == "": if controlList['elementDeleted']: self.createEvent(startTime, "r"+elementType, u, v, w) else: self.createEvent(startTime, "a"+elementType, u, v, w) controlList['elementAdded'] = True # Handle dynamic edge weights here if elementType == "e" and self.hasDynamicWeights: attvalues = element.getElementsByTagName("attvalue") # If a spell is traversed, attvalues are siblings if len(attvalues) == 0: attvalues = element.parentNode.parentNode.getElementsByTagName("attvalue") for att in attvalues: if att.getAttribute("for") == "weight": w = att.getAttribute("value") startTime = att.getAttribute("start") if startTime == "": startTime = att.getAttribute("startopen") if self.timeFormat != "date": startTime = float(startTime) # If this edge is not added, first weight update indicates edge addition if not controlList['elementAdded']: self.createEvent(startTime, "a"+elementType, u, v, w) controlList['elementAdded'] = True else: self.createEvent(startTime, "c"+elementType, u, v, w) if startTime == "": if not controlList['elementAdded']: if elementType == "n": self.mapping[u] = self.nInitialNodes self.nInitialNodes += 1 else: self.q.put((u,v,w)) controlList['elementAdded'] = True if endTime != "": self.createEvent(endTime, "d"+elementType, u, v, w) controlList['elementDeleted'] = True def createEvent(self, eventTime, eventType, u, v, w): """ Creates a NetworKit::GraphEvent from the supplied parameters and passes it to eventStream """ event, u = None, self.mapping[u] if eventType[1] == "e": v, w = self.mapping[v], float(w) if eventType == "an": event = GraphEvent(GraphEvent.NODE_ADDITION, u, 0, 0) elif eventType == "dn": event = GraphEvent(GraphEvent.NODE_REMOVAL, u, 0, 0) elif eventType == "rn": event = GraphEvent(GraphEvent.NODE_RESTORATION, u, 0, 0) elif eventType == "ae" or eventType == "re": event = GraphEvent(GraphEvent.EDGE_ADDITION, u, v, w) elif eventType == "de": event = GraphEvent(GraphEvent.EDGE_REMOVAL, u, v, w) elif eventType == "ce": event = GraphEvent(GraphEvent.EDGE_WEIGHT_UPDATE, u, v, w) self.eventStream.append((event, eventTime)) def mapDynamicNodes(self): """ Node ID of a dynamic node must be determined before it's mapped to its GEXF ID. This requires processing the sorted eventStream and figuring out the addition order of the nodes. After that, node addition/deletion/restoration operations of this node must be readded to eventStream with correct mapping. !Note: New mapping of a node can be equal to old mapping of a node. In order to prevent collisions, isMapped array must be maintained and controlled. """ nNodes = self.nInitialNodes nEvent = len(self.eventStream) isMapped = [False] * nEvent self.eventStream.sort(key=lambda x:x[1]) for i in range(0, nEvent): event = self.eventStream[i] # Only the nodes with addition event will get remapped. if not isMapped[i] and event[0].type == GraphEvent.NODE_ADDITION: u = event[0].u self.mapping[self.mapping[u]] = nNodes # All the other events of that node comes after it's addition event for j in range(i, len(self.eventStream)): event = self.eventStream[j] if not isMapped[j] and event[0].u == u: mappedEvent = GraphEvent(event[0].type, self.mapping[self.mapping[u]], 0, 0) self.eventStream[j] = (mappedEvent, event[1]) isMapped[j] = True nNodes +=1 isMapped[i] = True def getNodeMap(self): """ Returns GEXF ID -> NetworKit::Graph node ID mapping. """ forwardMap = dict() for key in self.mapping: if type(key) == str: forwardMap[key] = self.mapping[key] return forwardMap
class GraphMLSAX(xml.sax.ContentHandler): """ Parser for GraphML XML files, based on Pythons XML.SAX implementation. """ def __init__(self): """ Initializes several important variables """ xml.sax.ContentHandler.__init__(self) self.charBuffer = [] self.mapping = dict() self.g = Graph(0) self.graphName = 'unnamed' self.weightedID = '' self.weighted = False self.directed = False self.edgestack = [] self.edgeweight = 0.0 self.keepData = False def startElement(self, name, attrs): """ Parses all currently relevant XML tags and retrieves data.""" if name == "graph": # determine, if graph is directed: if attrs.getValue("edgedefault") == "directed": print("identified graph as directed") self.directed = True if "id" in attrs.getNames() and not attrs.getValue("id") == '': self.graphName = attrs.getValue("id") self.g = Graph(0,self.weighted, self.directed) self.g.setName(self.graphName) if name == "node": u = self.g.addNode() val = attrs.getValue("id") self.mapping[val] = u elif name == "edge": u = attrs.getValue("source") v = attrs.getValue("target") self.edgestack.append((u,v)) elif name == "key": #print("found element with tag KEY") if (attrs.getValue("for") == 'edge' and attrs.getValue("attr.name") == 'weight' and attrs.getValue("attr.type") == 'double'): self.weighted = True self.weightedID = attrs.getValue("id") print("identified graph as weighted") elif name == "data" and attrs.getValue("key") == self.weightedID: self.keepData = True def endElement(self, name): """ Finalizes parsing of the started Element and processes retrieved data.""" data = self.getCharacterData() if name == "edge": u = self.edgestack[len(self.edgestack)-1][0] v = self.edgestack[len(self.edgestack)-1][1] self.edgestack.pop() if self.weighted: #print ("identified edge as weighted with weight: {0}".format(edgeweight)) self.g.addEdge(self.mapping[u], self.mapping[v], self.edgeweight) self.edgeweight = 0.0 else: self.g.addEdge(self.mapping[u], self.mapping[v]) elif name == "data" and self.keepData: self.keepData = False self.edgeweight = float(data) def characters(self, content): self.charBuffer.append(content) def getCharacterData(self): data = ''.join(self.charBuffer).strip() self.charBuffer = [] return data def getGraph(self): return self.g
def get_value(self, graph: Graph): self.logger.debug('Calculate vertex count') return [graph.numberOfEdges()]