Source code for graphix.graphsim.rxgraphstate

from __future__ import annotations

from .basegraphstate import RUSTWORKX_INSTALLED, BaseGraphState
from .rxgraphviews import EdgeList, NodeList

if RUSTWORKX_INSTALLED:
    import rustworkx as rx
else:
    rx = None


[docs]class RXGraphState(BaseGraphState): """Graph state simulator implemented with rustworkx. See :class:`~graphix.graphsim.basegraphstate.BaseGraphState` for more details. """
[docs] def __init__(self, nodes: list[int] = None, edges: list[tuple[int, int]] = None, vops: dict[int, int] = None): """ Parameters ---------- nodes : list[int] A container of nodes (list, dict, etc) edges : list[tuple[int, int]] list of tuples (i,j) for pairs to be entangled. vops : dict[int, int] dict of local Clifford gates with keys for node indices and values for Clifford index (see graphix.clifford.CLIFFORD) """ super().__init__() self._graph = rx.PyGraph() self._nodes = NodeList() self._edges = EdgeList() if nodes is not None: self.add_nodes_from(nodes) if edges is not None: self.add_edges_from(edges) if vops is not None: self.apply_vops(vops)
@property def nodes(self) -> NodeList: return self._nodes @property def edges(self) -> EdgeList: return self._edges @property def graph(self) -> rx.PyGraph: return self._graph
[docs] def degree(self) -> iter[tuple[int, int]]: ret = [] for n in self.nodes: nidx = self.nodes.get_node_index(n) degree = self._graph.degree(nidx) ret.append((n, degree)) return iter(ret)
[docs] def neighbors(self, node) -> iter: nidx = self.nodes.get_node_index(node) return iter(self._graph.neighbors(nidx))
[docs] def subgraph(self, nodes: list) -> rx.PyGraph: nidx = [self.nodes.get_node_index(n) for n in nodes] return self._graph.subgraph(nidx)
[docs] def number_of_edges(self, u: int | None = None, v: int | None = None) -> int: if u is None and v is None: return len(self.edges) elif u is None or v is None: raise ValueError("u and v must be specified together") uidx = self.nodes.get_node_index(u) vidx = self.nodes.get_node_index(v) return len(self._graph.get_all_edge_data(uidx, vidx))
[docs] def adjacency(self) -> iter: ret = [] for n in self.nodes: nidx = self.nodes.get_node_index(n) adjacency_dict = self._graph.adj(nidx) new_adjacency_dict = {} for nidx, _ in adjacency_dict.items(): new_adjacency_dict[self.nodes.get_node_index(nidx)] = {} # replace None with {} ret.append((n, new_adjacency_dict)) return iter(ret)
[docs] def remove_node(self, node: int) -> None: nidx = self.nodes.get_node_index(node) self._graph.remove_node(nidx) self.nodes.remove_node(node) self.edges.remove_edges_by_node(node)
[docs] def remove_nodes_from(self, nodes: list[int]) -> None: for n in nodes: self.remove_node(n)
[docs] def remove_edge(self, u: int, v: int) -> None: uidx = self.nodes.get_node_index(u) vidx = self.nodes.get_node_index(v) self._graph.remove_edge(uidx, vidx) self.edges.remove_edge((u, v))
[docs] def remove_edges_from(self, edges: list[tuple[int, int]]) -> None: for e in edges: self.remove_edge(e[0], e[1])
[docs] def add_nodes_from(self, nodes: list[int]): node_indices = self._graph.add_nodes_from([(n, {"loop": False, "sign": False, "hollow": False}) for n in nodes]) for nidx in node_indices: self.nodes.add_node(self._graph[nidx][0], self._graph[nidx][1], nidx)
[docs] def add_edges_from(self, edges): for u, v in edges: # adding edges may add new nodes if u not in self.nodes: nidx = self._graph.add_node((u, {"loop": False, "sign": False, "hollow": False})) self.nodes.add_node(self._graph[nidx][0], self._graph[nidx][1], nidx) if v not in self.nodes: nidx = self._graph.add_node((v, {"loop": False, "sign": False, "hollow": False})) self.nodes.add_node(self._graph[nidx][0], self._graph[nidx][1], nidx) uidx = self.nodes.get_node_index(u) vidx = self.nodes.get_node_index(v) eidx = self._graph.add_edge(uidx, vidx, None) self.edges.add_edge((self._graph[uidx][0], self._graph[vidx][0]), None, eidx)
[docs] def local_complement(self, node): g = self.subgraph(list(self.neighbors(node))) g_new = rx.complement(g) g_edge_list = [] for uidx, vidx in g.edge_list(): u = g.get_node_data(uidx)[0] v = g.get_node_data(vidx)[0] g_edge_list.append((u, v)) g_new_eidx_list = [] for uidx, vidx in g_new.edge_list(): u = g_new.get_node_data(uidx)[0] v = g_new.get_node_data(vidx)[0] g_new_eidx_list.append((u, v)) self.remove_edges_from(g_edge_list) self.add_edges_from(g_new_eidx_list)
[docs] def get_isolates(self) -> list[int]: # return list(rx.isolates(self.graph)) # will work with rustworkx>=0.14.0 return [nnum for nnum, deg in self.degree() if deg == 0]