def rem(g: nx.MultiGraph) -> None: node_attributes = nx.get_node_attributes(G, 'elderly') nodes = list(g.nodes) for node in nodes: neigh = list(g.neighbors(node)) if len(neigh) == 2 and (g.degree(node) % 2) == 0: try: set1 = { edge['label'] for edge in g.get_edge_data(node, neigh[0]).values() } except: print(g.get_edge_data(node, neigh[0])) set2 = { edge['label'] for edge in g.get_edge_data(node, neigh[1]).values() } if set1 == set2: #prec=node_attributes[neigh[0]]+0.001 succ = node_attributes[neigh[1]] + 0.001 node_attr = node_attributes[node] + 0.001 # if (abs((node_attr-prec))<1000) and (abs((node_attr-succ))<1000): if (abs((node_attr - succ)) < 1000): g.remove_node(node) for edge_label in set1: g.add_edge(neigh[0], neigh[1], label=edge_label)
def reduction2(g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): for v in h.nodes(): # Check if G[W ∪ {v}] contains a cycle. if not is_forest(g.subgraph(w.union({v}))): g.remove_node(v) h.remove_nodes_from([v]) return (k - 1, v, True) return (k, None, False)
def reduction1(g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): changed = False for v in g.nodes(): if g.degree(v) <= 1: g.remove_node(v) h.remove_nodes_from([v]) changed = True return (k, None, changed)
def reduction3(self, g: MultiGraph, k: int) -> (int, List[int], bool): """ If there is a vertex v of degree at most 1, delete v. """ changed = False for v in g.nodes(): if g.degree(v) <= 1: g.remove_node(v) changed = True return k, None, changed
def reduction1(self, g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): """ Delete all nodes of degree 0 or 1 as they can't be part of any cycles. """ changed = False for v in g.nodes(): if g.degree(v) <= 1: g.remove_node(v) h.remove_nodes_from([v]) changed = True return k, None, changed
def reduction1(self, g: MultiGraph, k: int) -> (int, List[int], bool): """ If there is a loop at a vertex v, delete v from the graph and decrease k by 1. """ changed = False vs = g.nodes_with_selfloops() for v in vs: g.remove_node(v) k -= 1 changed = True return k, vs, changed
def reduction3(g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): for v in h.nodes(): if g.degree(v) == 2: # If v has a neighbour in H, short-curcuit it. if len(h[v]) >= 1: # Delete v and make its neighbors adjacent. [n1, n2] = g.neighbors(v) g.remove_node(v) g.add_edge(n1, n2) # Update H accordingly. h.remove_nodes_from([v]) if n1 not in w and n2 not in w: h.add_edge(n1, n2) return (k, None, True) return (k, None, False)
def reduction2(self, g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): """ If there exists a node v in H such that G[W ∪ {v}] contains a cycle, then include v in the solution, delete v and decrease the parameter by 1. That is, the new instance is (G - {v}, W, k - 1). If v introduces a cycle, it must be part of X as none of the vertices in W will be available to neutralise this cycle. """ for v in h.nodes(): # Check if G[W ∪ {v}] contains a cycle. if not is_acyclic(g.subgraph(w.union({v}))): g.remove_node(v) h.remove_nodes_from([v]) return k - 1, v, True return k, None, False
def reduction3(self, g: MultiGraph, w: set, h: MultiGraph, k: int) -> (int, int, bool): """ If there is a node v ∈ V(H) of degree 2 in G such that at least one neighbor of v in G is from V (H), then delete this node and make its neighbors adjacent (even if they were adjacent before; the graph could become a multigraph now). """ for v in h.nodes(): if g.degree(v) == 2: # If v has a neighbour in H, short-curcuit it. if len(h[v]) >= 1: # Delete v and make its neighbors adjacent. [n1, n2] = g.neighbors(v) g.remove_node(v) g.add_edge(n1, n2) # Update H accordingly. h.remove_nodes_from([v]) if n1 not in w and n2 not in w: h.add_edge(n1, n2) return k, None, True return k, None, False
def reduction4(self, g: MultiGraph, k: int) -> (int, List[int], bool): """ If there is a vertex v of degree 2, delete v and connect its two neighbors by a new edge. """ for v in g.nodes(): if g.degree(v) == 2: # Delete v and make its neighbors adjacent. ne = g.neighbors(v) # We must check whether v has 2 neighbors, or just one but connected to v by multiple edges if len(ne) == 2: [n1, n2] = ne else: [n1] = ne n2 = n1 g.remove_node(v) # Only add the edge if there are currently less than 2 edges between these two nodes es = g[n1].get(n2, {}) if len(es) < 2: g.add_edge(n1, n2) return k, None, True return k, None, False
class ShuttlingGraph(list): def __init__(self, shuttlingEdges=list() ): super(ShuttlingGraph, self).__init__(shuttlingEdges) self.currentPosition = None self.currentPositionName = None self.nodeLookup = dict() self.currentPositionObservable = Observable() self.graphChangedObservable = Observable() self.initGraph() self._hasChanged = True def initGraph(self): self.shuttlingGraph = MultiGraph() for edge in self: self.shuttlingGraph.add_node(edge.startName) self.shuttlingGraph.add_node(edge.stopName) self.shuttlingGraph.add_edge(edge.startName, edge.stopName, key=hash(edge), edge=edge, weight=abs(edge.stopLine-edge.startLine)) self.nodeLookup[edge.startLine] = edge.startName self.nodeLookup[edge.stopLine] = edge.stopName def rgenerateNodeLookup(self): self.nodeLookup.clear() for edge in self: self.nodeLookup[edge.startLine] = edge.startName self.nodeLookup[edge.stopLine] = edge.stopName @property def hasChanged(self): return self._hasChanged @hasChanged.setter def hasChanged(self, value): self._hasChanged = value def position(self, line): return self.nodeLookup.get(line) def setPosition(self, line): if self.currentPosition!=line: self.currentPosition = line self.currentPositionName = self.position(line) self.currentPositionObservable.fire( line=line, text=firstNotNone(self.currentPositionName, "") ) def getMatchingPosition(self,graph): """Try to match node name/position to the current settings in the provided ShuttlingGraph.""" if not graph: return self.currentPosition # no change # Matching node name. Need to set the corresponding position for edge in self: if edge.startName == graph.currentPositionName: return edge.startLine if edge.stopName == graph.currentPositionName: return edge.stopLine #if graph.currentPosition: # return graph.currentPosition #just use the graph's position return self.currentPosition def addEdge(self, edge): self._hasChanged = True self.append(edge) self.shuttlingGraph.add_edge(edge.startName, edge.stopName, key=hash(edge), edge=edge, weight=abs(edge.stopLine-edge.startLine)) self.nodeLookup[edge.startLine] = edge.startName self.nodeLookup[edge.stopLine] = edge.stopName self.graphChangedObservable.firebare() self.setPosition(self.currentPosition) def isValidEdge(self, edge): return ((edge.startLine not in self.nodeLookup or self.nodeLookup[edge.startLine] == edge.startName) and (edge.stopLine not in self.nodeLookup or self.nodeLookup[edge.stopLine] == edge.stopName)) def getValidEdge(self): index = 0 while self.shuttlingGraph.has_node("Start_{0}".format(index)): index += 1 startName = "Start_{0}".format(index) index = 0 while self.shuttlingGraph.has_node("Stop_{0}".format(index)): index += 1 stopName = "Stop_{0}".format(index) index = 0 startLine = (max( self.nodeLookup.keys() )+1) if self.nodeLookup else 1 stopLine = startLine + 1 return ShuttleEdge(startName, stopName, startLine, stopLine, 0, 0, 0, 0) def removeEdge(self, edgeno): self._hasChanged = True edge = self.pop(edgeno) self.shuttlingGraph.remove_edge(edge.startName, edge.stopName, hash(edge)) if self.shuttlingGraph.degree(edge.startName) == 0: self.shuttlingGraph.remove_node(edge.startName) if self.shuttlingGraph.degree(edge.stopName) == 0: self.shuttlingGraph.remove_node(edge.stopName) self.graphChangedObservable.firebare() self.rgenerateNodeLookup() self.setPosition(self.currentPosition) def setStartName(self, edgeno, startName): self._hasChanged = True startName = str(startName) edge = self[edgeno] if edge.startName != startName: self.shuttlingGraph.remove_edge(edge.startName, edge.stopName, key=hash(edge)) if self.shuttlingGraph.degree(edge.startName) == 0: self.shuttlingGraph.remove_node(edge.startName) edge.startName = startName self.shuttlingGraph.add_edge(edge.startName, edge.stopName, key=hash(edge), edge=edge, weight=abs(edge.stopLine-edge.startLine) ) self.graphChangedObservable.firebare() self.setPosition(self.currentPosition) self.rgenerateNodeLookup() return True def setStopName(self, edgeno, stopName): self._hasChanged = True stopName = str(stopName) edge = self[edgeno] if edge.stopName != stopName: self.shuttlingGraph.remove_edge(edge.startName, edge.stopName, key=hash(edge)) if self.shuttlingGraph.degree(edge.stopName) == 0: self.shuttlingGraph.remove_node(edge.stopName) edge.stopName = stopName self.shuttlingGraph.add_edge(edge.startName, edge.stopName, key=hash(edge), edge=edge, weight=abs(edge.stopLine-edge.startLine) ) self.graphChangedObservable.firebare() self.rgenerateNodeLookup() self.setPosition(self.currentPosition) return True def setStartLine(self, edgeno, startLine): self._hasChanged = True edge = self[edgeno] if startLine != edge.startLine and (startLine not in self.nodeLookup or self.nodeLookup[startLine] == edge.startName): self.nodeLookup.pop(edge.startLine) edge.startLine = startLine self.shuttlingGraph.edge[edge.startName][edge.stopName][hash(edge)]['weight'] = abs(edge.stopLine-edge.startLine) self.rgenerateNodeLookup() self.graphChangedObservable.firebare() self.setPosition(self.currentPosition) return True return False def setStopLine(self, edgeno, stopLine): self._hasChanged = True edge = self[edgeno] if stopLine != edge.stopLine and (stopLine not in self.nodeLookup or self.nodeLookup[stopLine] == edge.stopName): self.nodeLookup.pop(edge.stopLine) edge.stopLine = stopLine self.shuttlingGraph.edge[edge.startName][edge.stopName][hash(edge)]['weight'] = abs(edge.stopLine-edge.startLine) self.rgenerateNodeLookup() self.graphChangedObservable.firebare() self.setPosition(self.currentPosition) return True return False def setIdleCount(self, edgeno, idleCount): self._hasChanged = True self[edgeno].idleCount = idleCount return True def setSteps(self, edgeno, steps): self._hasChanged = True self[edgeno].steps = steps return True def shuttlePath(self, fromName, toName ): fromName = firstNotNone(fromName, self.currentPositionName) fromName = fromName if fromName else self.position(float(self.currentPosition)) if fromName not in self.shuttlingGraph: raise ShuttlingGraphException("Shuttling failed, origin '{0}' is not a valid shuttling node".format(fromName)) if toName not in self.shuttlingGraph: raise ShuttlingGraphException("Shuttling failed, target '{0}' is not a valid shuttling node".format(toName)) sp = shortest_path(self.shuttlingGraph, fromName, toName) path = list() for a, b in pairs_iter(sp): edge = sorted(self.shuttlingGraph.edge[a][b].values(), key=itemgetter('weight'))[0]['edge'] path.append((a, b, edge, self.index(edge))) return path def nodes(self): return self.shuttlingGraph.nodes() def toXmlElement(self, root): mydict = dict( ( (key, str(getattr(self, key))) for key in ('currentPosition', 'currentPositionName') if getattr(self, key) is not None ) ) myElement = ElementTree.SubElement(root, "ShuttlingGraph", attrib=mydict ) for edge in self: edge.toXmlElement( myElement ) return myElement def setStartType(self, edgeno, Type): self._hasChanged = True self[edgeno].startType = str(Type) return True def setStopType(self, edgeno, Type): self._hasChanged = True self[edgeno].stopType = str(Type) return True def setStartLength(self, edgeno, length): edge = self[edgeno] if length!=edge.startLength: if length+edge.stopLength<edge.sampleCount: self._hasChanged = True edge.startLength = int(length) else: return False return True def setStopLength(self, edgeno, length): edge = self[edgeno] if length!=edge.stopLength: if edge.startLength+length<edge.sampleCount: self._hasChanged = True edge.stopLength = int(length) else: return False return True @staticmethod def fromXmlElement( element ): edgeElementList = element.findall("ShuttleEdge") edgeList = [ ShuttleEdge.fromXmlElement(e) for e in edgeElementList ] return ShuttlingGraph(edgeList)