def split(self, graph): ''' Split nodes into d.cv alias nodes with identical edges ''' self.a_graph = self.alias_graph(graph) new_disks = [] new_edges = [] originals = [] for d in self.a_graph.nodes(): if d.org.cv > 1: edges = self.a_graph.edges(d) originals += self.a_graph.edges(d) # Create d.cv number of clones clones = [Alias(d.org) for i in range(1, d.org.cv)] # Distribute edges round-robin for i, e in enumerate(edges): new_edges.append((clones[i % len(clones)], e[1])) # Append cv clones self.a_graph.add_nodes_from(new_disks) self.a_graph.add_edges_from(new_edges) # Remove original edges for disks w/ cv > 1 self.a_graph.remove_edges_from(originals) return self.a_graph
def alias_graph(self, graph): a = nx.MultiGraph() for d in graph.nodes(): # Create alias disk disk_alias = Alias(d) # Copy edges from original edges = graph.edges(d) alias_edges = [(disk_alias, Alias(e[1])) for e in edges] # Add to alias graph a.add_node(disk_alias) a.add_edges_from(alias_edges) return a
def mg_split(self, graph): # Count occurence of edges occ = Counter(graph.edges()) for e in occ: n = occ[e] while n > 1: # Create new edge using Alias of e[0] graph.add_edge(Alias(e[0]), e[1]) # Remove old edge graph.remove_edge(e[0],e[1]) n -= 1
def split(self, graph): ''' Split nodes into d.cv alias nodes with identical edges ''' self.a_graph = self.alias_graph(graph) new_disks = [] new_edges = [] for d in self.a_graph.nodes(): if d.org.cv > 1: edges = self.a_graph.edges(d) # Create d.cv number of clones with a cv of 1 for i in range(1,d.org.cv-1): new_d = Alias(d.org) new_edges = [(new_d, e[1]) for e in edges] # Append cv clones self.a_graph.add_nodes_from(new_disks) self.a_graph.add_edges_from(new_edges) return self.a_graph
def gen_edges(self, graph): ''' Build bipartite graph ''' # Normalize if not self.normalized: # Relax CV for d in graph: if d.cv % 2: d.cv -= 1 d.avail -= 1 #self.mg_split(graph) self.normalize(graph) self.normalized = True # Euler cycle ec = nx.eulerian_circuit(graph) # Remove self-loops on graph loops = [] for e in graph.edges(): if e[0].org is e[1].org: loops.append(e) graph.remove_edges_from(loops) # Bipartite graph for flow problem, NOTE: cannot express MG characteristics self.b = nx.DiGraph() # v-in aliases and edge mapping v_out = [d for d in graph.nodes()] v_in = {d: Alias(d) for d in graph.nodes()} # Added edges in euler cycle with capacity of 1 c = 0 for e in ec: self.b.add_edge(e[0], v_in[e[1]], capacity=1) if e[0].org is not e[1].org: c += 1 # Create s-node self.b.add_node('t') for d in v_in.items(): self.b.add_edge(d[1], 't', capacity=ceil(d[1].org.cv / 2)) # Create t-node self.b.add_node('s') for d in v_out: self.b.add_edge('s', d, capacity=ceil(d.cv / 2)) # Ford-Fulkerson flow Returns: (flow_val, flow_dict) _, flow_dict = nx.maximum_flow(self.b, 's', 't') # Extract active edges and cull self loops and s/t nodes flow = [(d[0], d2[0]) for d in flow_dict.items() for d2 in d[1].items() \ if d2[1] > 0 and d[0] not in ['s','t'] and d2[0] not in ['s','t']] self.b.remove_edges_from(flow) # Reassociate aliases and return queue return [(e[0].org, e[1].org) for e in flow if e[0].org is not e[1].org]