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 get_channels(self, graph: nx.MultiGraph) -> List[Dict]: """ This function gets the graph as and return the channels the agent wants to create. :param graph: The graph where the agent operates in. :return: A list containing the channels the agent wishes to create. Each channel is a dictionary containing the relevant attributes. """ channels = list() funds = self.initial_funds # get more nodes to surround than possible with the given funds and costs: try to fully utilize initial funds # Also some nodes may not have self.n_channels_per_node neighbors number_of_nodes_to_surround = funds // ( self.n_channels_per_node * (self.channel_cost + self.new_channel_balance)) + 5 assert number_of_nodes_to_surround > 0, "Consider subtracting self.n_channels_per_node or the channel cost " nodes_to_surround = find_best_k_nodes(graph, k=number_of_nodes_to_surround, agent_public_key=self.pub_key, alpha=self.alpha, visualize=False, use_node_degree=self.use_node_degree, use_node_routeness=self.use_node_routeness, use_node_distance=self.use_nodes_distance, minimize=self.minimize) nodes_in_already_chosen_edges = set() for node in nodes_to_surround: agent_policy = get_agent_policy(graph, node, True, self.fee) if self.use_node_routeness: nodes_to_connect_with = nodes_to_surround else: node_neighbors = [n for n in graph.neighbors(node) if n not in nodes_in_already_chosen_edges] if len(node_neighbors) > self.n_channels_per_node: nodes_to_connect_with = random.sample(node_neighbors, k=self.n_channels_per_node) else: nodes_to_connect_with = node_neighbors for node_to_connect in nodes_to_connect_with: if funds < self.channel_cost: return channels channel_balance = min(self.new_channel_balance, funds - self.channel_cost) # Allows using all the funds funds -= channel_balance + self.channel_cost channel_details = {'node1_pub': self.pub_key, 'node2_pub': node_to_connect, 'node1_policy': agent_policy, 'node1_balance': channel_balance} channels.append(channel_details) nodes_in_already_chosen_edges = nodes_in_already_chosen_edges.union(nodes_to_connect_with) return channels
def generalized_degree(self, g: MultiGraph, f: set, active_node, node) -> (int, set): assert g.has_node(node), "Calculating gd for node which is not in g!" k = set(g.neighbors(node)) k.remove(active_node) k = k.intersection(f) gx = self.compress(g, k, node) neighbors = list(gx.neighbors(node)) neighbors.remove(active_node) return len(neighbors), neighbors
def generalized_degree(g: MultiGraph, f: set, active_node, node) -> (int, set): assert g.has_node(node), "Calculating gd for node which is not in g!" k = set(g.neighbors(node)) k.remove(active_node) k = k.intersection(f) gx = compress(g, k, node) neighbors = gx.neighbors(node) neighbors.remove(active_node) return (len(neighbors), neighbors)
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 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
def get_all_related_people(g: nx.MultiGraph, person): return g.neighbors(person)
def mif_main(self, g: MultiGraph, f: set, t) -> set: if f == g.nodes(): return f if not f: g_degree = g.degree() g_max_degree_node = max(g_degree, key=lambda n: n[1])[0] if g_degree[g_max_degree_node] <= 1: return set(g.nodes()) else: fx = f.copy() fx.add(g_max_degree_node) gx = g.copy() gx.remove_node(g_max_degree_node) mif_set1 = self.preprocess_1(g, fx, t) mif_set2 = self.preprocess_1(gx, f, t) if not mif_set1: return mif_set2 elif not mif_set2: return mif_set1 else: return max(mif_set1, mif_set2, key=len) # Set t as active vertex if t is None or t not in f: t = next(iter(f)) gd_over_3 = None gd_2 = None for v in g.neighbors(t): (gd_v, gn_v) = self.generalized_degree(g, f, t, v) if gd_v <= 1: f.add(v) return self.preprocess_1(g, f, t) elif gd_v >= 3: gd_over_3 = v else: gd_2 = (v, gn_v) if gd_over_3 is not None: # Cannot simply use "if gd_over_3" because v might be 0 fx = f.copy() fx.add(gd_over_3) gx = g.copy() gx.remove_node(gd_over_3) mif_set1 = self.preprocess_1(g, fx, t) mif_set2 = self.preprocess_1(gx, f, t) if not mif_set1: return mif_set2 elif not mif_set2: return mif_set1 else: return max(mif_set1, mif_set2, key=len) elif gd_2 is not None: (v, gn) = gd_2 fx1 = f.copy() fx2 = f.copy() fx1.add(v) for n in gn: fx2.add(n) gx = g.copy() gx.remove_node(v) try: find_cycle(gx.subgraph(fx2)) mif_set1 = None except: mif_set1 = self.preprocess_1(gx, fx2, t) mif_set2 = self.preprocess_1(g, fx1, t) if not mif_set1: return mif_set2 elif not mif_set2: return mif_set1 else: return max(mif_set1, mif_set2, key=len) return None