def mat_from_graph( G: nx.Graph, kernel: Callable[[float], float] = (lambda x: x)) -> np.ndarray: """ Given a weighted graph create a matrix based on a kernel function of the shortest weighted path distance. Parameters ---------- G : networkx.Graph A weighted graph kernel : function A function of the shortest weighted path distance, default= f(x)=x Returns ------- matrix : numpy.ndarray Note ---- This will only be a distance matrix if the kernel function keeps things as distances. """ Vdict = {v: i for i, v in enumerate(G.nodes)} matrix = np.full((G.order(), G.order()), np.inf) np.fill_diagonal(matrix, 0) for pair in nx.shortest_path_length(G, weight="weight"): i = Vdict[pair[0]] for v2 in pair[1]: matrix[i, Vdict[v2]] = kernel(pair[1][v2]) return matrix
def diameter_and_avg_path_length(graph: nx.Graph) -> Tuple[float, float]: max_path_length = 0 total = 0.0 for n in graph: path_length = nx.single_source_shortest_path_length(graph, n) total += sum(path_length.values()) if max(path_length.values()) > max_path_length: max_path_length = max(path_length.values()) try: avg_path_length = total / (graph.order() * (graph.order() - 1)) except ZeroDivisionError: avg_path_length = 0.0 return max_path_length, avg_path_length
def _propagate(self, graph: Graph, embedded_sub_graph: Graph, embeddings: np.array, node2id, id2node, max_itr: int = 20): reachable_nodes = self._get_reachable_subgraph(graph, embedded_sub_graph) Z1 = embeddings sparse_adj = nx.to_scipy_sparse_matrix(graph) while reachable_nodes.order() > 0: print("Propagating : current embedding size : {}, reachable nodes : {}, total graph size : {}".format( len(embedded_sub_graph), len(reachable_nodes), len(graph))) Z1 = embeddings reachable_indexes = [i for i, node in enumerate(graph) if node in reachable_nodes] embedded_indexes = [i for i, node in enumerate(graph) if node in embedded_sub_graph] A1, A2 = sparse_adj[embedded_indexes, :][:, reachable_indexes], sparse_adj[reachable_indexes, :][:, reachable_indexes] norm = sparse.hstack([A1.T, A2]).sum(axis=1) A1_norm, A2_norm = sparse.csc_matrix(A1/norm.T), sparse.csc_matrix(A2/norm.T) Z2 = sparse.csr_matrix(np.random.uniform(-1, 1, size=(reachable_nodes.order(), self.out_dim_))) for itr in range(max_itr): Z2 = A1_norm.T@Z1 + A2_norm.T@Z2 n1 = embedded_sub_graph.order() for node in reachable_nodes: node2id[node] = n1 id2node.append(node) n1 = n1 + 1 embeddings = np.concatenate([embeddings, Z2], axis=0) embedded_sub_graph = graph.subgraph(list(node2id.keys())) reachable_nodes = self._get_reachable_subgraph(graph, embedded_sub_graph) unreachable_nodes = graph.subgraph([node for node in graph if node not in embedded_sub_graph]) if unreachable_nodes: unreachable_nodes_embeddings = sparse.csr_matrix(np.zeros((unreachable_nodes.order(), self.out_dim_))) embeddings = np.concatenate([embeddings, unreachable_nodes_embeddings.todense()], axis=0) n1 = embedded_sub_graph.order() for node in unreachable_nodes: node2id[node] = n1 id2node.append(node) n1 = n1 + 1 return { "embeddings": np.array(embeddings), "node2id": node2id, "id2node": id2node, "unreachable_nodes": unreachable_nodes }
def prob_event_mc( graph: nx.Graph, photon_number: int, max_count_per_mode: int, n_mean: float = 5, samples: int = 1000, loss: float = 0.0, ) -> float: r"""Gives a Monte Carlo estimate of the probability of a given event for the input graph. To make this estimate, several samples from the event are drawn uniformly at random using :func:`event_to_sample`. The GBS probabilities of these samples are then calculated and the sum is used to create an estimate of the event probability. **Example usage:** >>> graph = nx.complete_graph(8) >>> prob_event_mc(graph, 4, 2) 0.11368151661229377 Args: graph (nx.Graph): input graph encoded in the GBS device photon_number (int): number of photons in the event max_count_per_mode (int): maximum number of photons per mode in the event n_mean (float): total mean photon number of the GBS device samples (int): number of samples used in the Monte Carlo estimation loss (float): fraction of photons lost in GBS Returns: float: Monte Carlo estimated event probability """ if samples < 1: raise ValueError("Number of samples must be at least one") if n_mean < 0: raise ValueError("Mean photon number must be non-negative") if not 0 <= loss <= 1: raise ValueError( "Loss parameter must take a value between zero and one") if photon_number < 0: raise ValueError("Photon number must not be below zero") if max_count_per_mode < 0: raise ValueError( "Maximum number of photons per mode must be non-negative") modes = graph.order() state = _get_state(graph, n_mean, loss) prob = 0 for _ in range(samples): sample = event_to_sample(photon_number, max_count_per_mode, modes) prob += state.fock_prob(sample, cutoff=photon_number + 1) prob = prob * event_cardinality(photon_number, max_count_per_mode, modes) / samples return prob
def prob_event_mc( graph: nx.Graph, photon_number: int, max_count_per_mode: int, n_mean: float = 5, samples: int = 1000, ) -> float: """Gives a Monte Carlo estimate of the probability of a given event for a GBS device encoded according to the input graph. To make this estimate, several samples from the event are drawn uniformly at random. For each sample, we calculate the probability of observing that sample from a GBS programmed according to the input graph and mean photon number. These probabilities are then rescaled according to the cardinality of the event. The estimate is the sample mean of the rescaled probabilities. To make this estimate, several samples from the event are drawn uniformly at random using :func:event_to_sample. **Example usage**: >>> graph = nx.complete_graph(8) >>> p_event_mc(graph, 4, 2) 0.1395 Args: graph (nx.Graph): input graph encoded in the GBS device photon_number (int): number of photons in the event max_count_per_mode (int): maximum number of photons per mode in the event n_mean (float): total mean photon number of the GBS device samples (int): number of samples used in the Monte Carlo estimation Returns: float: the estimated probability """ modes = graph.order() A = nx.to_numpy_array(graph) mean_photon_per_mode = n_mean / float(modes) p = sf.Program(modes) # pylint: disable=expression-not-assigned with p.context as q: sf.ops.GraphEmbed(A, mean_photon_per_mode=mean_photon_per_mode) | q eng = sf.LocalEngine(backend="gaussian") result = eng.run(p) prob = 0 for _ in range(samples): sample = event_to_sample(photon_number, max_count_per_mode, modes) prob += result.state.fock_prob(sample, cutoff=photon_number + 1) prob = prob * event_cardinality(photon_number, max_count_per_mode, modes) / samples return prob
def prob_orbit_mc(graph: nx.Graph, orbit: list, n_mean: float = 5, samples: int = 1000) -> float: """Gives a Monte Carlo estimate of the probability of a given orbit for a GBS device encoded according to the input graph. To make this estimate, several samples from the orbit are drawn uniformly at random using :func:`orbit_to_sample`. For each sample, this function calculates the probability of observing that sample from a GBS device programmed according to the input graph and mean photon number. The sum of the probabilities is then rescaled according to the cardinality of the orbit and the total number of samples. The estimate is the sample mean of the rescaled probabilities. To make this estimate, several samples from the orbit are drawn uniformly at random using :func:orbit_to_sample. **Example usage**: >>> graph = nx.complete_graph(8) >>> prob_orbit_mc(graph, [2, 1, 1]) 0.03744 Args: graph (nx.Graph): input graph encoded in the GBS device orbit (list[int]): orbit for which to estimate the probability n_mean (float): total mean photon number of the GBS device samples (int): number of samples used in the Monte Carlo estimation Returns: float: estimated orbit probability """ modes = graph.order() photons = sum(orbit) A = nx.to_numpy_array(graph) mean_photon_per_mode = n_mean / float(modes) p = sf.Program(modes) # pylint: disable=expression-not-assigned with p.context as q: sf.ops.GraphEmbed(A, mean_photon_per_mode=mean_photon_per_mode) | q eng = sf.LocalEngine(backend="gaussian") result = eng.run(p) prob = 0 for _ in range(samples): sample = orbit_to_sample(orbit, modes) prob += result.state.fock_prob(sample, cutoff=photons + 1) prob = prob * orbit_cardinality(orbit, modes) / samples return prob
def _coefficientsFromNetwork(self, g: Graph) -> List[float]: '''Compute the degree histogram. :param g: the network :returns: the fractional occurrence of each degree''' N = g.order() seq = sorted([d for (_, d) in g.degree()]) hist = Counter(seq) maxk = max(seq) cs = [hist[i] / N for i in range(maxk + 1)] return cs
def __init__(self, graph: nx.Graph, dataset: str, model: str, iteration: int, trial: int): self.graph: nx.Graph = graph self.trial = trial self.dataset = dataset self.model = model self.iteration = iteration self.stats: Dict[str, Any] = { 'dataset': dataset, 'model': model, 'iteration': iteration, 'trial': trial, 'n': graph.order(), 'm': graph.size() }
def prob_orbit_mc(graph: nx.Graph, orbit: list, n_mean: float = 5, samples: int = 1000, loss: float = 0.0) -> float: r"""Gives a Monte Carlo estimate of the probability of a given orbit for the input graph. To make this estimate, several samples from the orbit are drawn uniformly at random using :func:`orbit_to_sample`. The GBS probabilities of these samples are then calculated and the sum is used to create an estimate of the orbit probability. **Example usage:** >>> graph = nx.complete_graph(8) >>> prob_orbit_mc(graph, [2, 1, 1]) 0.03744399092424391 Args: graph (nx.Graph): input graph encoded in the GBS device orbit (list[int]): orbit for which to estimate the probability n_mean (float): total mean photon number of the GBS device samples (int): number of samples used in the Monte Carlo estimation loss (float): fraction of photons lost in GBS Returns: float: Monte Carlo estimated orbit probability """ if samples < 1: raise ValueError("Number of samples must be at least one") if n_mean < 0: raise ValueError("Mean photon number must be non-negative") if not 0 <= loss <= 1: raise ValueError( "Loss parameter must take a value between zero and one") modes = graph.order() photons = sum(orbit) state = _get_state(graph, n_mean, loss) prob = 0 for _ in range(samples): sample = orbit_to_sample(orbit, modes) prob += state.fock_prob(sample, cutoff=photons + 1) prob *= orbit_cardinality(orbit, modes) / samples return prob
def prob_orbit_exact(graph: nx.Graph, orbit: list, n_mean: float = 5, loss: float = 0.0) -> float: r"""Gives the exact probability of a given orbit for the input graph. The exact probability of an orbit is the sum of probabilities of all possible GBS output patterns that belong to it: .. math:: p(O) = \sum_{S \in O} p(S) where :math:`S` are samples belonging to :math:`O`. **Example usage:** >>> graph = nx.complete_graph(8) >>> prob_orbit_exact(graph, [2, 1, 1]) 0.03744399092424445 Args: graph (nx.Graph): input graph encoded in the GBS device orbit (list[int]): orbit for which to calculate the probability n_mean (float): total mean photon number of the GBS device loss (float): fraction of photons lost in GBS Returns: float: exact orbit probability """ if n_mean < 0: raise ValueError("Mean photon number must be non-negative") if not 0 <= loss <= 1: raise ValueError( "Loss parameter must take a value between zero and one") modes = graph.order() photons = sum(orbit) state = _get_state(graph, n_mean, loss) click = orbit + [0] * (modes - len(orbit)) prob = 0 for pattern in multiset_permutations(click): prob += state.fock_prob(pattern, cutoff=photons + 1) return prob
def preprocess(graph: nx.Graph, reindex_nodes: bool, first_label: int = 0, take_lcc: bool = True) -> nx.Graph: """ Preprocess the graph - taking the largest connected components, re-index nodes if needed :return: """ #CP.print_none('Pre-processing graph....') #CP.print_none(f'Original graph "{self.gname}" n:{self.graph.order():,} ' # f'm:{self.graph.size():,} #components: {nx.number_connected_components(self.graph)}') if take_lcc and nx.number_connected_components(graph) > 1: ## Take the LCC component_sizes = [ len(c) for c in sorted( nx.connected_components(graph), key=len, reverse=True) ] #CP.print_none(f'Taking the largest component out of {len(component_sizes)} components: {component_sizes}') graph_lcc = nx.Graph( graph.subgraph(max(nx.connected_components(graph), key=len))) perc_nodes = graph_lcc.order() / graph.order() * 100 perc_edges = graph_lcc.size() / graph.size() * 100 #CP.print_orange(f'LCC has {print_float(perc_nodes)}% of nodes and {print_float(perc_edges)}% edges in the original graph') graph = graph_lcc selfloop_edges = list(nx.selfloop_edges(graph)) if len(selfloop_edges) > 0: #CP.print_none(f'Removing {len(selfloop_edges)} self-loops') graph.remove_edges_from(selfloop_edges) # remove self-loops if reindex_nodes: # re-index nodes, stores the old label in old_label graph = nx.convert_node_labels_to_integers(graph, first_label=first_label, label_attribute='old_label') #CP.print_none( # f'Re-indexing nodes to start from {first_label}, old labels are stored in node attr "old_label"') #CP.print_none(f'Pre-processed graph "{self.gname}" n:{self.graph.order():,} m:{self.graph.size():,}') return graph
def louvain(g: nx.Graph, randomize=False): if g.order() < 2: return [[n] for n in g.nodes()] tree = [] partition = cmt.best_partition(g) clusters = defaultdict(list) for node, cluster_id in partition.items(): clusters[cluster_id].append(node) if len(clusters) == 1: return [[n] for n in clusters[0]] for cluster in clusters.values(): sg = g.subgraph(cluster).copy() # assert nx.is_connected(sg), "subgraph not connected" # TODO: replace this with a return None tree.append(louvain(sg)) return tree
def from_graph(cls, g: nx.Graph, json_path: Path = None, *, label: str = "") -> "Network": g = nx.convert_node_labels_to_integers(g) if g.size() == 0: edges = np.zeros((0, 2), dtype=np.int32) else: edges = np.array(g.edges(), dtype=np.int32) net = cls.from_edges( n=g.order(), edges=edges, directed=isinstance(g, nx.DiGraph), json_path=json_path, label=label, ) net._network = g return net
def _get_state(graph: nx.Graph, n_mean: float = 5, loss: float = 0.0) -> BaseGaussianState: r"""Embeds the input graph into a GBS device and returns the corresponding Gaussian state.""" modes = graph.order() A = nx.to_numpy_array(graph) mean_photon_per_mode = n_mean / float(modes) p = sf.Program(modes) # pylint: disable=expression-not-assigned with p.context as q: sf.ops.GraphEmbed(A, mean_photon_per_mode=mean_photon_per_mode) | q if loss: for _q in q: sf.ops.LossChannel(1 - loss) | _q eng = sf.LocalEngine(backend="gaussian") return eng.run(p).state
def is_clique(graph: nx.Graph) -> bool: """Determines if the input graph is a clique. A clique of :math:`n` nodes has exactly :math:`n( n-1)/2` edges. **Example usage:** >>> graph = nx.complete_graph(10) >>> is_clique(graph) True Args: graph (nx.Graph): the input graph Returns: bool: ``True`` if input graph is a clique and ``False`` otherwise """ edges = graph.edges nodes = graph.order() return len(edges) == nodes * (nodes - 1) / 2
def compare_two_graphs(g_true: nx.Graph, g_test: Union[nx.Graph, LightMultiGraph], true_deg=None, true_page=None): """ Compares two graphs :param g_true: actual graph :param g_test: generated graph :return: """ if true_deg is None: true_deg = nx.degree_histogram(g_true) if true_page is None: true_page = list(nx.pagerank_scipy(g_true).values()) start = time() g_test_deg = nx.degree_histogram(g_test) deg_time = time() - start start = time() g_test_pr = list(nx.pagerank_scipy(g_test).values()) page_time = time() - start start = time() gcd = GCD(g_true, g_test, 'orca') gcd_time = time() - start start = time() cvm_deg = cvm_distance(true_deg, g_test_deg) cvm_page = cvm_distance(true_page, g_test_pr) cvm_time = time() - start ld = lambda_dist(g_true, g_test, k=min(g_true.order(), g_test.order(), 10)) dc0 = deltacon0(g_true, g_test) logging.debug( f'times: deg {round(deg_time, 3)}s, page {round(page_time, 3)}s, gcd {round(gcd_time, 3)}s, cvm {round(cvm_time, 3)}s' ) return gcd, cvm_deg, cvm_page, ld, dc0
def get_compatibility_matrix(g: nx.Graph, attr_name: str): """ From Danai's heterophily paper :param g: :param attr_name: :return: """ if max(g.nodes) != g.order() - 1: g = nx.convert_node_labels_to_integers(g, first_label=0) values = set(nx.get_node_attributes(g, attr_name).values()) mapping = {val: i for i, val in enumerate(values)} # print(mapping) C = nx.attribute_mixing_matrix(g, attribute=attr_name, mapping=mapping, normalized=False) np.fill_diagonal(C, C.diagonal() / 2) D = np.diag(np.diag(C)) e = np.ones(shape=(len(mapping), 1)) h = float((e.T @ D @ e) / (e.T @ C @ e)) H = np.nan # Y = np.zeros(shape=(g.order(), len(mapping))) # for n, d in g.nodes(data=True): # attr = d[attr_name] # Y[n, mapping[attr]] = 1 # A = nx.adjacency_matrix(g) # E = np.ones(shape=(A.shape[0], len(mapping))) # # H = (Y.T @ A @ Y) / (Y.T @ A @ E) return_d = dict(homophily_ratio=h, compatibility_mat=H, attr_name=attr_name, mapping=mapping) return return_d
def plot_infection(susceptible: List[int], infected: List[int], removed: List[int], graph: nx.Graph) -> None: """ :param susceptible: time-ordered list from simulation output indicating how susceptible count changes over time :param infected: time-ordered list from simulation output indicating how infected count changes over time :param removed: time-ordered list from simulation output indicating how removed count changes over time :param graph: Graph/Network of statistic to plot Creates a plot of the S,I,R output of a spread simulation. """ peak_incidence = max(infected) peak_time = infected.index(max(infected)) total_infected = susceptible[0] - susceptible[-1] fig_size = [18, 13] plt.rcParams.update({'font.size': 14, 'figure.figsize': fig_size}) xvalues = range(len(susceptible)) plt.plot(xvalues, susceptible, color='g', linestyle='-', label='S') plt.plot(xvalues, infected, color='b', linestyle='-', label='I') plt.plot(xvalues, removed, color='r', linestyle='-', label='R') plt.axhline(peak_incidence, color='b', linestyle='--', label='Peak Incidence') plt.annotate(str(peak_incidence), xy=(1, peak_incidence + 10), color='b') plt.axvline(peak_time, color='b', linestyle=':', label='Peak Time') plt.annotate(str(peak_time), xy=(peak_time + 1, 8), color='b') plt.axhline(total_infected, color='r', linestyle='--', label='Total Infected') plt.annotate(str(total_infected), xy=(1, total_infected + 10), color='r') plt.legend() plt.xlabel('time step') plt.ylabel('Count') plt.title('SIR for network size ' + str(graph.order())) plt.show()
def get_clustering(g: nx.Graph, outdir: str, clustering: str, use_pickle: bool, filename='', write_pickle: bool = True) -> Any: """ wrapper method for getting dendrogram. uses an existing pickle if it can. :param g: graph :param outdir: output directory where picles are stored :param clustering: name of clustering method :param use_pickle: flag to whether or not to use the pickle :return: root node of the dendrogram """ if g.name == 'sample': list_of_list_clusters = [ [ [[0], [1]], [[2], [[3], [4]]] ], [ [[5], [6]], [[7], [8]] ] ] return list_of_list_clusters if filename == '': list_of_list_filename = os.path.join(outdir, 'output', 'trees', g.name, f'{clustering}_list.pkl') else: list_of_list_filename = filename if check_file_exists(list_of_list_filename) and use_pickle: logging.error(f'Using existing pickle for {clustering!r} clustering\n') list_of_list_clusters = load_pickle(list_of_list_filename) else: tqdm.write(f'Running {clustering!r} clustering on {g.name!r}...') if clustering == 'random': list_of_list_clusters = partitions.get_random_partition(g) elif clustering == 'consensus': # delete the matlab tree and sc files matlab_files_path = './src/matlab_clustering/HierarchicalConsensus/data' tree_path = os.path.join(matlab_files_path, f'{g.name}_tree.mat') sc_path = os.path.join(matlab_files_path, f'{g.name}_sc.vec') if check_file_exists(tree_path): os.remove(tree_path) if check_file_exists(sc_path): os.remove(sc_path) list_of_list_clusters = get_consensus_root(g=g, gname=g.name) elif clustering in ('leiden', 'louvain', 'infomap', 'labelprop', 'leadingeig'): try: list_of_list_clusters = partitions.louvain_leiden_infomap_label_prop(g, method=clustering) except Exception as e: list_of_list_clusters = [] elif clustering == 'cond': list_of_list_clusters = partitions.approx_min_conductance_partitioning(g) elif clustering == 'spectral': list_of_list_clusters = partitions.spectral_kmeans(g, K=int(math.sqrt(g.order() // 2))) else: raise NotImplementedError(f'Invalid clustering algorithm {clustering!r}') if len(list_of_list_clusters) != 0 and write_pickle: dump_pickle(list_of_list_clusters, list_of_list_filename) return list_of_list_clusters
class NetworkXGraphBackend(GenericGraphBackend): """ A wrapper for NetworkX as the backend of a graph. TESTS:: sage: import sage.graphs.base.graph_backends """ _nxg = None def __init__(self, N=None): """ Initialize the backend with NetworkX graph N. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_edges([],True) <generator object iterator_edges at ...> """ if N is None: import networkx N = networkx.MultiGraph() self._nxg = N try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() def add_edge(self, u, v, l, directed): """ Add an edge (u,v) to self, with label l. If directed is True, this is interpreted as an arc from u to v. INPUT: - ``u,v`` -- vertices - ``l`` -- edge label - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_edge(1,2,'a',True) """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() if u is None: u = self.add_vertex(None) if v is None: v = self.add_vertex(None) if l: self._nxg.add_edge(u, v, weight=l) else: self._nxg.add_edge(u, v) def add_edges(self, edges, directed): """ Add a sequence of edges to self. If directed is True, these are interpreted as arcs. INPUT: - ``edges`` -- list/iterator of edges to be added. - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_edges([],True) """ for e in edges: try: u, v, l = e except ValueError: u, v = e l = None self.add_edge(u, v, l, directed) def add_vertex(self, name): """ Add a labelled vertex to self. INPUT: - ``name``: vertex label OUTPUT: If ``name=None``, the new vertex name is returned. ``None`` otherwise. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_vertex(0) """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() retval = None if name is None: # then find an integer to use as a key i = 0 while self.has_vertex(i): i = i + 1 name = i retval = name self._nxg.add_node(name) return retval def add_vertices(self, vertices): """ Add labelled vertices to self. INPUT: - ``vertices``: iterator of vertex labels. A new label is created, used and returned in the output list for all ``None`` values in ``vertices``. OUTPUT: Generated names of new vertices if there is at least one ``None`` value present in ``vertices``. ``None`` otherwise. EXAMPLES:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_vertices([1,2,3]) sage: G.add_vertices([4,None,None,5]) [0, 6] """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() vertices = list(vertices) nones = vertices.count(None) vertices = [v for v in vertices if v is not None] self._nxg.add_nodes_from(vertices) new_names = [] i = 0 while nones > 0: while self.has_vertex(i): i += 1 self._nxg.add_node(i) new_names.append(i) nones -= 1 i += 1 return new_names if new_names != [] else None def degree(self, v, directed): """ Returns the total number of vertices incident to v. INPUT: - ``v`` -- a vertex label - ``directed`` -- boolean OUTPUT: degree of v TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_vertices(range(3)) sage: G.degree(1, False) 0 """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() return self._nxg.degree(v) def del_edge(self, u, v, l, directed): """ Deletes the edge (u,v) with label l. INPUT: - ``u,v`` -- vertices - ``l`` -- edge label - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.del_edge(1,2,'a',True) """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() import networkx try: if self._nxg.is_multigraph(): for k, d in self._nxg.edge[u][v].iteritems(): if d.get('weight', None) == l: self._nxg.remove_edge(u, v, k) break else: if l is None or self._nxg.edge[u][v].get('weight', None) == l: self._nxg.remove_edge(u, v) except (KeyError, networkx.NetworkXError): pass def del_vertex(self, v): """ Delete a labelled vertex in self. INPUT: - ``v`` -- vertex label TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.del_vertex(0) Traceback (most recent call last): ... NetworkXError: The node 0 is not in the graph. """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() self._nxg.remove_node(v) def del_vertices(self, vertices): """ Delete labelled vertices in self. INPUT: - ``vertices`` -- iterator of vertex labels TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.del_vertices([1,2,3]) Traceback (most recent call last): ... NetworkXError: The node 1 is not in the graph. """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() for v in vertices: self._nxg.remove_node(v) def get_edge_label(self, u, v): """ Returns the edge label of (u,v). INPUT: - ``u,v`` -- vertex labels OUTPUT: label of (u,v) TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.get_edge_label(1,2) Traceback (most recent call last): ... NetworkXError: Edge (1,2) requested via get_edge_label does not exist. """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() try: E = self._nxg.edge[u][v] except KeyError: from networkx import NetworkXError raise NetworkXError( "Edge (%s,%s) requested via get_edge_label does not exist." % (u, v)) if self._nxg.is_multigraph(): return [e.get('weight', None) for e in E.itervalues()] else: return E.get('weight', None) def has_edge(self, u, v, l): """ True if self has an edge (u,v) with label l. INPUT: - ``u,v`` -- vertex labels - ``l`` -- label OUTPUT: boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.has_edge(1,2,'a') False """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() if not self._nxg.has_edge(u, v): return False if l is None: return True if self._nxg.is_multigraph(): return any( e.get('weight', None) == l for e in self._nxg.adj[u][v].itervalues()) else: return any(e == l for e in self._nxg.adj[u][v].itervalues()) def has_vertex(self, v): """ True if self has a vertex with label v. INPUT: - ``v`` -- vertex label OUTPUT: boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.has_vertex(0) False """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() return self._nxg.has_node(v) def iterator_edges(self, vertices, labels): """ Iterate over the edges incident to a sequence of vertices. Edges are assumed to be undirected. INPUT: - ``vertices`` -- a list of vertex labels - ``labels`` -- boolean OUTPUT: a generator which yields edges, with or without labels depending on the labels parameter. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_edges([],True) <generator object iterator_edges at ...> """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() if labels: for u, v, d in self._nxg.edges_iter(data=True): if u in vertices or v in vertices: yield (u, v, d.get('weight', None)) else: for u, v in self._nxg.edges_iter(): if u in vertices or v in vertices: yield (u, v) def _iterator_in_edges_with_labels(self, vertices): """ Iterate over the incoming edges incident to a sequence of vertices. Special case, only for internal use. EXAMPLE:: sage: g = DiGraph(graphs.PetersenGraph(), implementation="networkx")._backend sage: sorted(list(g.iterator_in_edges([0,1], True))) [(0, 1, None), (1, 0, None), (2, 1, None), (4, 0, None), (5, 0, None), (6, 1, None)] """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() for u, v, d in self._nxg.in_edges_iter(vertices, data=True): yield (u, v, d.get('weight', None)) def iterator_in_edges(self, vertices, labels): """ Iterate over the incoming edges incident to a sequence of vertices. INPUT: - ``vertices`` -- a list of vertex labels - ``labels`` -- boolean OUTPUT: a generator which yields edges, with or without labels depending on the labels parameter. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: i = G.iterator_in_edges([],True) """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() if self._nxg.is_directed(): if labels: return self._iterator_in_edges_with_labels(vertices) else: return self._nxg.in_edges_iter(vertices) else: return self.iterator_edges(vertices, labels) def _iterator_out_edges_with_labels(self, vertices): """ Iterate over the outbound edges incident to a sequence of vertices. Special case, only for internal use. EXAMPLE:: sage: g = DiGraph(graphs.PetersenGraph(), implementation="networkx")._backend sage: sorted(list(g.iterator_out_edges([0,1], True))) [(0, 1, None), (0, 4, None), (0, 5, None), (1, 0, None), (1, 2, None), (1, 6, None)] """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() for u, v, d in self._nxg.out_edges_iter(vertices, data=True): yield (u, v, d.get('weight', None)) def iterator_out_edges(self, vertices, labels): """ Iterate over the outbound edges incident to a sequence of vertices. INPUT: - ``vertices`` -- a list of vertex labels - ``labels`` -- boolean OUTPUT: a generator which yields edges, with or without labels depending on the labels parameter. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: i = G.iterator_out_edges([],True) """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() if self._nxg.is_directed(): if labels: return self._iterator_out_edges_with_labels(vertices) else: return self._nxg.out_edges_iter(vertices) else: return self.iterator_edges(vertices, labels) def iterator_nbrs(self, v): """ Iterate over the vertices adjacent to v. INPUT: - ``v`` -- vertex label OUTPUT: a generator which yields vertex labels TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_vertex(0) sage: G.iterator_nbrs(0) <dictionary-keyiterator object at ...> """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() return self._nxg.neighbors_iter(v) def iterator_in_nbrs(self, v): """ Iterate over the vertices u such that the edge (u,v) is in self (that is, predecessors of v). INPUT: - ``v`` -- vertex label OUTPUT: a generator which yields vertex labels TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_in_nbrs(0) Traceback (most recent call last): ... AttributeError: 'MultiGraph' object has no attribute 'predecessors_iter' """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() return self._nxg.predecessors_iter(v) def iterator_out_nbrs(self, v): """ Iterate over the vertices u such that the edge (v,u) is in self (that is, successors of v). INPUT: - ``v`` -- vertex label OUTPUT: a generator which yields vertex labels TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_out_nbrs(0) Traceback (most recent call last): ... AttributeError: 'MultiGraph' object has no attribute 'successors_iter' """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() return self._nxg.successors_iter(v) def iterator_verts(self, verts): """ Iterate over the vertices v with labels in verts. INPUT: - ``vertex`` -- vertex labels OUTPUT: a generator which yields vertices TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_verts(0) <generator object bunch_iter at ...> """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() return self._nxg.nbunch_iter(verts) def loops(self, new=None): """ Get/set whether or not self allows loops. INPUT: - ``new`` -- can be a boolean (in which case it sets the value) or ``None``, in which case the current value is returned. It is set to ``None`` by default. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.loops(True) sage: G.loops(None) True """ if new is None: return self._loops if new: self._loops = True else: self._loops = False def multiple_edges(self, new=None): """ Get/set whether or not self allows multiple edges. INPUT: - ``new`` -- can be a boolean (in which case it sets the value) or ``None``, in which case the current value is returned. It is set to ``None`` by default. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.multiple_edges(True) sage: G.multiple_edges(None) True """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() from networkx import Graph, MultiGraph, DiGraph, MultiDiGraph if new is None: return self._nxg.is_multigraph() if new == self._nxg.is_multigraph(): return if new: if self._nxg.is_directed(): self._nxg = MultiDiGraph(self._nxg) else: self._nxg = MultiGraph(self._nxg) else: if self._nxg.is_directed(): self._nxg = DiGraph(self._nxg) else: self._nxg = Graph(self._nxg) def name(self, new=None): """ Get/set name of self. INPUT: - ``new`` -- can be a string (in which case it sets the value) or ``None``, in which case the current value is returned. It is set to ``None`` by default. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.name("A NetworkX Graph") sage: G.name(None) 'A NetworkX Graph' """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() if new is None: return self._nxg.name self._nxg.name = new def num_edges(self, directed): """ The number of edges in self INPUT: - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.num_edges(True) 0 sage: G.num_edges(False) 0 """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() return self._nxg.size() def num_verts(self): """ The number of vertices in self TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.num_verts() 0 """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() return self._nxg.order() def relabel(self, perm, directed): """ Relabel the vertices of self by a permutation. INPUT: - ``perm`` -- permutation - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.relabel([],False) """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() from networkx import relabel_nodes name = self._nxg.name self._nxg = relabel_nodes(self._nxg, perm) self._nxg.name = name def set_edge_label(self, u, v, l, directed): """ Label the edge (u,v) by l. INPUT: - ``u,v`` -- vertices - ``l`` -- edge label - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.set_edge_label(1,2,'a',True) """ try: assert (not isinstance( self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated))) except AssertionError: self._nxg = self._nxg.mutate() if not self.has_edge(u, v, None): return if self.multiple_edges(None): self._nxg[u][v].clear() self._nxg[u][v][0] = dict(weight=l) if directed is False: self._nxg[v][u].clear() self._nxg[v][u][0] = dict(weight=l) else: self._nxg[u][v]['weight'] = l if directed is False: self._nxg[v][u]['weight'] = l
class NetworkXGraphBackend(GenericGraphBackend): """ A wrapper for NetworkX as the backend of a graph. TESTS:: sage: import sage.graphs.base.graph_backends """ _nxg = None def __init__(self, N=None): """ Initialize the backend with NetworkX graph N. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_edges([],True) <generator object iterator_edges at ...> """ if N is None: import networkx N = networkx.MultiGraph() self._nxg = N if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() def add_edge(self, u, v, l, directed): """ Add an edge (u,v) to self, with label l. If directed is True, this is interpreted as an arc from u to v. INPUT: - ``u,v`` -- vertices - ``l`` -- edge label - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_edge(1,2,'a',True) """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() if u is None: u = self.add_vertex(None) if v is None: v = self.add_vertex(None) if l: self._nxg.add_edge(u, v, weight=l) else: self._nxg.add_edge(u, v) def add_edges(self, edges, directed): """ Add a sequence of edges to self. If directed is True, these are interpreted as arcs. INPUT: - ``edges`` -- list/iterator of edges to be added. - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_edges([],True) """ for e in edges: try: u,v,l = e except ValueError: u,v = e l = None self.add_edge(u,v,l,directed) def add_vertex(self, name): """ Add a labelled vertex to self. INPUT: - ``name``: vertex label OUTPUT: If ``name=None``, the new vertex name is returned. ``None`` otherwise. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_vertex(0) """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() retval = None if name is None: # then find an integer to use as a key i = 0 while self.has_vertex(i): i=i+1 name = i retval = name self._nxg.add_node(name) return retval def add_vertices(self, vertices): """ Add labelled vertices to self. INPUT: - ``vertices``: iterator of vertex labels. A new label is created, used and returned in the output list for all ``None`` values in ``vertices``. OUTPUT: Generated names of new vertices if there is at least one ``None`` value present in ``vertices``. ``None`` otherwise. EXAMPLES:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_vertices([1,2,3]) sage: G.add_vertices([4,None,None,5]) [0, 6] """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() vertices = list(vertices) nones = vertices.count(None) vertices = [v for v in vertices if v is not None] self._nxg.add_nodes_from(vertices) new_names = [] i = 0 while nones > 0: while self.has_vertex(i): i += 1 self._nxg.add_node(i) new_names.append(i) nones -= 1 i += 1 return new_names if new_names != [] else None def degree(self, v, directed): """ Returns the total number of vertices incident to v. INPUT: - ``v`` -- a vertex label - ``directed`` -- boolean OUTPUT: degree of v TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_vertices(range(3)) sage: G.degree(1, False) 0 """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.degree(v) def in_degree(self, v): """ Returns the in-degree of v. INPUT: - ``v`` -- a vertex label OUTPUT: degree of v TESTS:: sage: G = DiGraph(digraphs.Path(5),implementation="networkx") sage: G = G._backend sage: G.in_degree(0) 0 sage: G.in_degree(4) 1 """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.in_degree(v) def out_degree(self, v): """ Returns the out-degree of v. INPUT: - ``v`` -- a vertex label OUTPUT: degree of v TESTS:: sage: G = DiGraph(digraphs.Path(5),implementation="networkx") sage: G = G._backend sage: G.out_degree(0) 1 sage: G.out_degree(4) 0 """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.out_degree(v) def del_edge(self, u, v, l, directed): """ Deletes the edge (u,v) with label l. INPUT: - ``u,v`` -- vertices - ``l`` -- edge label - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.del_edge(1,2,'a',True) """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() import networkx try: if self._nxg.is_multigraph(): for k,d in self._nxg.edge[u][v].iteritems(): if d.get('weight',None) == l: self._nxg.remove_edge(u,v,k) break else: if l is None or self._nxg.edge[u][v].get('weight',None) == l: self._nxg.remove_edge(u,v) except (KeyError, networkx.NetworkXError): pass def del_vertex(self, v): """ Delete a labelled vertex in self. INPUT: - ``v`` -- vertex label TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.del_vertex(0) Traceback (most recent call last): ... NetworkXError: The node 0 is not in the graph. """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() self._nxg.remove_node(v) def del_vertices(self, vertices): """ Delete labelled vertices in self. INPUT: - ``vertices`` -- iterator of vertex labels TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.del_vertices([1,2,3]) Traceback (most recent call last): ... NetworkXError: The node 1 is not in the graph. """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() for v in vertices: self._nxg.remove_node(v) def get_edge_label(self, u, v): """ Returns the edge label of (u,v). INPUT: - ``u,v`` -- vertex labels OUTPUT: label of (u,v) TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.get_edge_label(1,2) Traceback (most recent call last): ... NetworkXError: Edge (1,2) requested via get_edge_label does not exist. """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() try: E = self._nxg.edge[u][v] except KeyError: from networkx import NetworkXError raise NetworkXError("Edge (%s,%s) requested via get_edge_label does not exist."%(u,v)) if self._nxg.is_multigraph(): return [ e.get('weight',None) for e in E.itervalues() ] else: return E.get('weight',None) def has_edge(self, u, v, l): """ True if self has an edge (u,v) with label l. INPUT: - ``u,v`` -- vertex labels - ``l`` -- label OUTPUT: boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.has_edge(1,2,'a') False """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() if not self._nxg.has_edge(u, v): return False if l is None: return True if self._nxg.is_multigraph(): return any( e.get('weight',None) == l for e in self._nxg.adj[u][v].itervalues() ) else: return any( e == l for e in self._nxg.adj[u][v].itervalues() ) def has_vertex(self, v): """ True if self has a vertex with label v. INPUT: - ``v`` -- vertex label OUTPUT: boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.has_vertex(0) False """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.has_node(v) def iterator_edges(self, vertices, labels): """ Iterate over the edges incident to a sequence of vertices. Edges are assumed to be undirected. INPUT: - ``vertices`` -- a list of vertex labels - ``labels`` -- boolean OUTPUT: a generator which yields edges, with or without labels depending on the labels parameter. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_edges([],True) <generator object iterator_edges at ...> """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() if labels: for u,v,d in self._nxg.edges_iter(data=True): if u in vertices or v in vertices: yield (u,v,d.get('weight',None)) else: for u,v in self._nxg.edges_iter(): if u in vertices or v in vertices: yield (u,v) def _iterator_in_edges_with_labels(self, vertices): """ Iterate over the incoming edges incident to a sequence of vertices. Special case, only for internal use. EXAMPLE:: sage: g = DiGraph(graphs.PetersenGraph(), implementation="networkx")._backend sage: sorted(list(g.iterator_in_edges([0,1], True))) [(0, 1, None), (1, 0, None), (2, 1, None), (4, 0, None), (5, 0, None), (6, 1, None)] """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() for u,v,d in self._nxg.in_edges_iter(vertices,data=True): yield (u,v,d.get('weight',None)) def iterator_in_edges(self, vertices, labels): """ Iterate over the incoming edges incident to a sequence of vertices. INPUT: - ``vertices`` -- a list of vertex labels - ``labels`` -- boolean OUTPUT: a generator which yields edges, with or without labels depending on the labels parameter. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: i = G.iterator_in_edges([],True) """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() if self._nxg.is_directed(): if labels: return self._iterator_in_edges_with_labels(vertices) else: return self._nxg.in_edges_iter(vertices) else: return self.iterator_edges(vertices,labels) def _iterator_out_edges_with_labels(self, vertices): """ Iterate over the outbound edges incident to a sequence of vertices. Special case, only for internal use. EXAMPLE:: sage: g = DiGraph(graphs.PetersenGraph(), implementation="networkx")._backend sage: sorted(list(g.iterator_out_edges([0,1], True))) [(0, 1, None), (0, 4, None), (0, 5, None), (1, 0, None), (1, 2, None), (1, 6, None)] """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() for u,v,d in self._nxg.out_edges_iter(vertices,data=True): yield (u,v,d.get('weight',None)) def iterator_out_edges(self, vertices, labels): """ Iterate over the outbound edges incident to a sequence of vertices. INPUT: - ``vertices`` -- a list of vertex labels - ``labels`` -- boolean OUTPUT: a generator which yields edges, with or without labels depending on the labels parameter. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: i = G.iterator_out_edges([],True) """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() if self._nxg.is_directed(): if labels: return self._iterator_out_edges_with_labels(vertices) else: return self._nxg.out_edges_iter(vertices) else: return self.iterator_edges(vertices,labels) def iterator_nbrs(self, v): """ Iterate over the vertices adjacent to v. INPUT: - ``v`` -- vertex label OUTPUT: a generator which yields vertex labels TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.add_vertex(0) sage: G.iterator_nbrs(0) <dictionary-keyiterator object at ...> """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.neighbors_iter(v) def iterator_in_nbrs(self, v): """ Iterate over the vertices u such that the edge (u,v) is in self (that is, predecessors of v). INPUT: - ``v`` -- vertex label OUTPUT: a generator which yields vertex labels TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_in_nbrs(0) Traceback (most recent call last): ... AttributeError: 'MultiGraph' object has no attribute 'predecessors_iter' """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.predecessors_iter(v) def iterator_out_nbrs(self, v): """ Iterate over the vertices u such that the edge (v,u) is in self (that is, successors of v). INPUT: - ``v`` -- vertex label OUTPUT: a generator which yields vertex labels TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_out_nbrs(0) Traceback (most recent call last): ... AttributeError: 'MultiGraph' object has no attribute 'successors_iter' """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.successors_iter(v) def iterator_verts(self, verts): """ Iterate over the vertices v with labels in verts. INPUT: - ``vertex`` -- vertex labels OUTPUT: a generator which yields vertices TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.iterator_verts(0) <generator object bunch_iter at ...> """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.nbunch_iter(verts) def loops(self, new=None): """ Get/set whether or not self allows loops. INPUT: - ``new`` -- can be a boolean (in which case it sets the value) or ``None``, in which case the current value is returned. It is set to ``None`` by default. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.loops(True) sage: G.loops(None) True """ if new is None: return self._loops if new: self._loops = True else: self._loops = False def multiple_edges(self, new=None): """ Get/set whether or not self allows multiple edges. INPUT: - ``new`` -- can be a boolean (in which case it sets the value) or ``None``, in which case the current value is returned. It is set to ``None`` by default. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.multiple_edges(True) sage: G.multiple_edges(None) True """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() from networkx import Graph,MultiGraph,DiGraph,MultiDiGraph if new is None: return self._nxg.is_multigraph() if new == self._nxg.is_multigraph(): return if new: if self._nxg.is_directed(): self._nxg = MultiDiGraph(self._nxg) else: self._nxg = MultiGraph(self._nxg) else: if self._nxg.is_directed(): self._nxg = DiGraph(self._nxg) else: self._nxg = Graph(self._nxg) def name(self, new=None): """ Get/set name of self. INPUT: - ``new`` -- can be a string (in which case it sets the value) or ``None``, in which case the current value is returned. It is set to ``None`` by default. TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.name("A NetworkX Graph") sage: G.name(None) 'A NetworkX Graph' """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() if new is None: return self._nxg.name self._nxg.name = new def num_edges(self, directed): """ The number of edges in self INPUT: - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.num_edges(True) 0 sage: G.num_edges(False) 0 """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.size() def num_verts(self): """ The number of vertices in self TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.num_verts() 0 """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() return self._nxg.order() def relabel(self, perm, directed): """ Relabel the vertices of self by a permutation. INPUT: - ``perm`` -- permutation - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.relabel([],False) """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() from networkx import relabel_nodes name = self._nxg.name self._nxg = relabel_nodes(self._nxg,perm) self._nxg.name = name def set_edge_label(self, u, v, l, directed): """ Label the edge (u,v) by l. INPUT: - ``u,v`` -- vertices - ``l`` -- edge label - ``directed`` -- boolean TESTS:: sage: G = sage.graphs.base.graph_backends.NetworkXGraphBackend() sage: G.set_edge_label(1,2,'a',True) """ if isinstance(self._nxg, (NetworkXGraphDeprecated, NetworkXDiGraphDeprecated)): self._nxg = self._nxg.mutate() if not self.has_edge(u, v, None): return if self.multiple_edges(None): self._nxg[u][v].clear() self._nxg[u][v][0] = dict(weight=l) if directed is False: self._nxg[v][u].clear() self._nxg[v][u][0] = dict(weight=l) else: self._nxg[u][v]['weight'] = l if directed is False: self._nxg[v][u]['weight'] = l
def do_visit( G: nx.Graph, agent: Agent.Agent, is_node_visited_only_once: bool = False, start_node: int = None, is_animated: bool = True, path_to_save_yandex_animation: str = "output/animated_map/frames/", path_to_save_matplotlib_animation: str = "output/matplotlib_animated_map/frames/", is_using_strict_order: bool = False) -> None: iteration = 0 path_to_matplotlib_frames = os.path.join(path_to_save_matplotlib_animation, "frames/") path_to_yandex_frames = os.path.join(path_to_save_yandex_animation, "frames/") is_first_visit = True if start_node is None: # node_to_visit = random.randint(0, G.__len__() - 1) node_to_visit = random.randint(0, G.order() - 1) if is_using_strict_order: node_to_visit = 0 # Using first node. Node 0 must always be present and connected with at least one other else: node_to_visit = start_node while not GU.is_all_nodes_visited(G): if is_node_visited_only_once: while True: if is_using_strict_order: break if G.nodes[node_to_visit][ 'data'].state == PSE.possible_state.not_visited: break else: node_to_visit = random.randint(0, G.order() - 1) elif not is_node_visited_only_once: node_to_visit = random.randint(0, G.order() - 1) if is_using_strict_order: # Causes an agent to visit places clearly in ascending order of node numbers. if not is_first_visit: node_to_visit += 1 if node_to_visit not in G.nodes: break # node with max index already visited print("Now in node #{0} : {1}".format(node_to_visit, G.nodes[node_to_visit])) agent.visited_nodes.append(node_to_visit) for target_person in G.nodes[node_to_visit]['data'].persons: # calculating probability that agent will infect persons for disease_of_agent, disease_of_agent_permissibility in agent.infected_with.items( ): # iterating over # dict's items # https://stackoverflow.com/questions/5466618/too-many-values-to-unpack-iterating-over-a-dict-key-string-value-list probability = GU.calc_infection_probability( Infection.infection( name=disease_of_agent, permissibility=disease_of_agent_permissibility), target_person, G.nodes[node_to_visit] ['data'].persons) # TODO : TEST THIS LINE # print("For agent {0} and target {1} in place {2}, probability of {3} = {4}".format(agent, target_person, # G.nodes[ ## node_to_visit][ # 'data'].name, # disease_of_agent, # probability)) if probability >= 0.5: target_person.infected_with[ disease_of_agent] = agent.infected_with[ disease_of_agent] G.nodes[node_to_visit][ 'data'].state = PSE.possible_state.infected else: if G.nodes[node_to_visit][ 'data'].state != PSE.possible_state.infected: G.nodes[node_to_visit][ 'data'].state = PSE.possible_state.not_infected for disease_of_person, disease_of_person_permissibility in target_person.infected_with.items( ): # calculating probability that person will infect agent with something new if disease_of_person in agent.infected_with: break probability = GU.calc_infection_probability( Infection.infection(disease_of_person, disease_of_person_permissibility), agent, G.nodes[node_to_visit]['data'].persons) if probability >= 0.5: agent.infected_with[ disease_of_person] = disease_of_person_permissibility GU.graph_show_and_save( G, name_to_save="frame" + str(len(next(os.walk(path_to_matplotlib_frames))[2])), path_to_save=path_to_matplotlib_frames, to_save=True, text="Graph after agent interference in node {0}, agent : {1}". format( G.nodes[node_to_visit]['data'].name + str(G.nodes[node_to_visit]['data'].number + 1), agent)) GU.get_map(G, agent, name_to_save="frame" + str(len(next(os.walk(path_to_yandex_frames))[2])) + ".png", path_to_save=path_to_yandex_frames) infection_tick(G) GU.graph_show_and_save( G, name_to_save="frame" + str(len(next(os.walk(path_to_matplotlib_frames))[2])), path_to_save=path_to_matplotlib_frames, to_save=True, text="Graph after in-node interference") GU.get_map(G, agent, name_to_save="frame" + str(len(next(os.walk(path_to_yandex_frames))[2])) + ".png", path_to_save=path_to_yandex_frames) prev_node = node_to_visit iteration += 1 if is_first_visit: is_first_visit = False
def prob_event_mc( graph: nx.Graph, photon_number: int, max_count_per_mode: int, n_mean: float = 5, samples: int = 1000, loss: float = 0.0, ) -> float: r"""Gives a Monte Carlo estimate of the GBS probability of a given event according to the input graph. To make this estimate, several samples from the event are drawn uniformly at random using :func:`event_to_sample`. The GBS probabilities of these samples are then calculated and the sum is used to create an estimate of the event probability. **Example usage:** >>> graph = nx.complete_graph(8) >>> prob_event_mc(graph, 4, 2) 0.1395 Args: graph (nx.Graph): input graph encoded in the GBS device photon_number (int): number of photons in the event max_count_per_mode (int): maximum number of photons per mode in the event n_mean (float): total mean photon number of the GBS device samples (int): number of samples used in the Monte Carlo estimation loss (float): fraction of photons lost in GBS Returns: float: estimated orbit probability """ if samples < 1: raise ValueError("Number of samples must be at least one") if n_mean < 0: raise ValueError("Mean photon number must be non-negative") if not 0 <= loss <= 1: raise ValueError( "Loss parameter must take a value between zero and one") if photon_number < 0: raise ValueError("Photon number must not be below zero") if max_count_per_mode < 0: raise ValueError( "Maximum number of photons per mode must be non-negative") modes = graph.order() A = nx.to_numpy_array(graph) mean_photon_per_mode = n_mean / float(modes) p = sf.Program(modes) # pylint: disable=expression-not-assigned with p.context as q: sf.ops.GraphEmbed(A, mean_photon_per_mode=mean_photon_per_mode) | q if loss: for _q in q: sf.ops.LossChannel(1 - loss) | _q eng = sf.LocalEngine(backend="gaussian") result = eng.run(p) prob = 0 for _ in range(samples): sample = event_to_sample(photon_number, max_count_per_mode, modes) prob += result.state.fock_prob(sample, cutoff=photon_number + 1) prob = prob * event_cardinality(photon_number, max_count_per_mode, modes) / samples return prob
def sample_subgraphs( graph: nx.Graph, nodes: int, samples: int = 1, sample_options: Optional[dict] = None, backend_options: Optional[dict] = None, ) -> list: """Functionality for sampling subgraphs. The optional ``sample_options`` argument can be used to specify the type of sampling. It should be a dict that contains any of the following: .. glossary:: key: ``"distribution"``, value: *str* Subgraphs can be sampled according to the following distributions: - ``"gbs"``: for generating subgraphs according to the Gaussian boson sampling distribution. In this distribution, subgraphs are sampled with a variable size ( default). - ``"uniform"``: for generating subgraphs uniformly at random. When using this distribution, subgraphs are of a fixed size. Note that ``backend_options`` are not used and that remote sampling is unavailable due to the simplicity of the distribution. key: ``"postselect_ratio"``, value: *float* Ratio of ``nodes`` used to determine the minimum size of subgraph sampled; defaults to 0.75. Args: graph (nx.Graph): the input graph nodes (int): the mean size of subgraph samples samples (int): number of samples; defaults to 1 sample_options (dict[str, Any]): dictionary specifying options used by ``sample_subgraphs``; defaults to :const:`SAMPLE_DEFAULTS` backend_options (dict[str, Any]): dictionary specifying options used by backends during sampling; defaults to ``None`` Returns: list[list[int]]: a list of length ``samples`` whose elements are subgraphs given by a list of nodes """ sample_options = {**SAMPLE_DEFAULTS, **(sample_options or {})} distribution = sample_options["distribution"] if distribution == "uniform": s = sample.uniform_sampler(modes=graph.order(), sampled_modes=nodes, samples=samples) elif distribution == "gbs": postselect = int(sample_options["postselect_ratio"] * nodes) backend_options = {**(backend_options or {}), "postselect": postselect} s = sample.quantum_sampler( A=nx.to_numpy_array(graph), n_mean=nodes, samples=samples, backend_options=backend_options, ) else: raise ValueError("Invalid distribution selected") return to_subgraphs(graph, s)
content = [x.split('\t') for x in content] # content = [x.split(' ') for x in content] graph_dict = {} for l in content: # print(l) try: g.add_edge(l[0], l[1]) except Exception as e: print(e) print(l[1]) sys.exit() vsg = max(nx.connected_components(g), key=len) print(vsg) print([ len(c) for c in sorted(nx.connected_components(g), key=len, reverse=True) ]) g = g.subgraph(max(nx.connected_components(g), key=len)) # g = generators.random_graphs.random_powerlaw_tree(n=5000, gamma=3, tries=500000) # print(lp1) nx.drawing.nx_pylab.draw_networkx(g) # # print('running tests') lp2 = lp(seepage_problem) lp2(g, range(0, g.order()), 1, 'new_vertex_selector', 'new_vertex_selector') lp.print_stats()