def add_physical_qubit(self, physical_qubit): """Add a physical qubit to the coupling graph as a node. physical_qubit (int): An integer representing a physical qubit. Raises: CouplingError: if trying to add duplicate qubit """ if not isinstance(physical_qubit, int): raise CouplingError("Physical qubits should be integers.") if physical_qubit in self.physical_qubits: raise CouplingError( "The physical qubit %s is already in the coupling graph" % physical_qubit) self.graph.add_node(physical_qubit) self._dist_matrix = None # invalidate self._qubit_list = None # invalidate
def _compute_distance_matrix(self): """Compute the full distance matrix on pairs of nodes. The distance map self._dist_matrix is computed from the graph using all_pairs_shortest_path_length. """ if not self.is_connected(): raise CouplingError("coupling graph not connected") self._dist_matrix = rx.digraph_distance_matrix(self.graph, as_undirected=True)
def distance(self, physical_qubit1, physical_qubit2): """Returns the undirected distance between physical_qubit1 and physical_qubit2. Args: physical_qubit1 (int): A physical qubit physical_qubit2 (int): Another physical qubit Returns: int: The undirected distance Raises: CouplingError: if the qubits do not exist in the CouplingMap """ if physical_qubit1 >= self.size(): raise CouplingError("%s not in coupling graph" % physical_qubit1) if physical_qubit2 >= self.size(): raise CouplingError("%s not in coupling graph" % physical_qubit2) self.compute_distance_matrix() return int(self._dist_matrix[physical_qubit1, physical_qubit2])
def distance(self, physical_qubit1, physical_qubit2): """Returns the undirected distance between physical_qubit1 and physical_qubit2. Args: physical_qubit1 (int): A physical qubit physical_qubit2 (int): Another physical qubit Returns: int: The undirected distance Raises: CouplingError: if the qubits do not exist in the CouplingMap """ if physical_qubit1 not in self.physical_qubits: raise CouplingError("%s not in coupling graph" % (physical_qubit1,)) if physical_qubit2 not in self.physical_qubits: raise CouplingError("%s not in coupling graph" % (physical_qubit2,)) if self._dist_matrix is None: self._compute_distance_matrix() return self._dist_matrix[physical_qubit1, physical_qubit2]
def compute_distance_matrix(self): """Compute the full distance matrix on pairs of nodes. The distance map self._dist_matrix is computed from the graph using all_pairs_shortest_path_length. This is normally handled internally by the :attr:`~qiskit.transpiler.CouplingMap.distance_matrix` attribute or the :meth:`~qiskit.transpiler.CouplingMap.distance` method but can be called if you're accessing the distance matrix outside of those or want to pre-generate it. """ if self._dist_matrix is None: if not self.is_connected(): raise CouplingError("coupling graph not connected") self._dist_matrix = rx.digraph_distance_matrix(self.graph, as_undirected=True)
def _compute_distance_matrix(self): """Compute the full distance matrix on pairs of nodes. The distance map self._dist_matrix is computed from the graph using all_pairs_shortest_path_length. """ if not self.is_connected(): raise CouplingError("coupling graph not connected") lengths = nx.all_pairs_shortest_path_length(self.graph.to_undirected(as_view=True)) lengths = dict(lengths) size = len(lengths) cmap = np.zeros((size, size)) for idx in range(size): cmap[idx, np.fromiter(lengths[idx].keys(), dtype=int)] = np.fromiter( lengths[idx].values(), dtype=int) self._dist_matrix = cmap
def shortest_undirected_path(self, physical_qubit1, physical_qubit2): """Returns the shortest undirected path between physical_qubit1 and physical_qubit2. Args: physical_qubit1 (int): A physical qubit physical_qubit2 (int): Another physical qubit Returns: List: The shortest undirected path Raises: CouplingError: When there is no path between physical_qubit1, physical_qubit2. """ try: return nx.shortest_path(self.graph.to_undirected(as_view=True), source=physical_qubit1, target=physical_qubit2) except nx.exception.NetworkXNoPath: raise CouplingError( "Nodes %s and %s are not connected" % (str(physical_qubit1), str(physical_qubit2)))
def shortest_undirected_path(self, physical_qubit1, physical_qubit2): """Returns the shortest undirected path between physical_qubit1 and physical_qubit2. Args: physical_qubit1 (int): A physical qubit physical_qubit2 (int): Another physical qubit Returns: List: The shortest undirected path Raises: CouplingError: When there is no path between physical_qubit1, physical_qubit2. """ paths = rx.digraph_dijkstra_shortest_paths(self.graph, source=physical_qubit1, target=physical_qubit2, as_undirected=True) if not paths: raise CouplingError("Nodes %s and %s are not connected" % (str(physical_qubit1), str(physical_qubit2))) return paths[physical_qubit2]
def reduce(self, mapping): """Returns a reduced coupling map that corresponds to the subgraph of qubits selected in the mapping. Args: mapping (list): A mapping of reduced qubits to device qubits. Returns: CouplingMap: A reduced coupling_map for the selected qubits. Raises: CouplingError: Reduced coupling map must be connected. """ from scipy.sparse import coo_matrix, csgraph reduced_qubits = len(mapping) inv_map = [None] * (max(mapping) + 1) for idx, val in enumerate(mapping): inv_map[val] = idx reduced_cmap = [] for edge in self.get_edges(): if edge[0] in mapping and edge[1] in mapping: reduced_cmap.append([inv_map[edge[0]], inv_map[edge[1]]]) # Verify coupling_map is connected rows = np.array([edge[0] for edge in reduced_cmap], dtype=int) cols = np.array([edge[1] for edge in reduced_cmap], dtype=int) data = np.ones_like(rows) mat = coo_matrix((data, (rows, cols)), shape=(reduced_qubits, reduced_qubits)).tocsr() if csgraph.connected_components(mat)[0] != 1: raise CouplingError("coupling_map must be connected.") return CouplingMap(reduced_cmap)