def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the UnitarySynthesis pass on `dag`. Args: dag: input dag. Returns: Output dag with UnitaryGates synthesized to target basis. Raises: TranspilerError: 1. pulse_optimize is True but pulse optimal decomposition is not known for requested basis. 2. pulse_optimize is True and natural_direction is True but a preferred gate direction can't be determined from the coupling map or the relative gate lengths. """ euler_basis = _choose_euler_basis(self._basis_gates) kak_gate = _choose_kak_gate(self._basis_gates) decomposer1q, decomposer2q = None, None if euler_basis is not None: decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer( euler_basis) if kak_gate is not None: decomposer2q = TwoQubitBasisDecomposer( kak_gate, euler_basis=euler_basis, pulse_optimize=self._pulse_optimize) for node in dag.named_nodes(*self._synth_gates): if self._basis_gates and node.name in self._basis_gates: continue synth_dag = None wires = None if len(node.qargs) == 1: if decomposer1q is None: continue synth_dag = circuit_to_dag( decomposer1q._decompose(node.op.to_matrix())) elif len(node.qargs) == 2: if decomposer2q is None: continue synth_dag, wires = self._synth_natural_direction( node, dag, decomposer2q) else: synth_dag = circuit_to_dag( isometry.Isometry(node.op.to_matrix(), 0, 0).definition) dag.substitute_node_with_dag(node, synth_dag, wires=wires) return dag
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the HighLevelSynthesis pass on `dag`. Args: dag: input dag. Returns: Output dag with high level objects synthesized. """ for node in dag.named_nodes("clifford"): decomposition = circuit_to_dag(decompose_clifford(node.op)) dag.substitute_node_with_dag(node, decomposition) return dag
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the LinearFunctionsSynthesis pass on `dag`. Args: dag: input dag. Returns: Output dag with LinearFunctions synthesized. """ for node in dag.named_nodes("linear_function"): decomposition = circuit_to_dag(node.op.definition) dag.substitute_node_with_dag(node, decomposition) return dag
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the LinearFunctionsToPermutations pass on `dag`. Args: dag: input dag. Returns: Output dag with LinearFunctions synthesized. """ for node in dag.named_nodes("linear_function"): try: pattern = node.op.permutation_pattern() except CircuitError: continue permutation = Permutation(len(pattern), pattern) dag.substitute_node(node, permutation.to_instruction()) return dag
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the UnitarySynthesis pass on `dag`. Args: dag: input dag. Returns: Output dag with UnitaryGates synthesized to target basis. """ euler_basis = _choose_euler_basis(self._basis_gates) kak_gate = _choose_kak_gate(self._basis_gates) decomposer1q, decomposer2q = None, None if euler_basis is not None: decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer( euler_basis) if kak_gate is not None: decomposer2q = TwoQubitBasisDecomposer(kak_gate, euler_basis=euler_basis) for node in dag.named_nodes("unitary"): synth_dag = None if len(node.qargs) == 1: if decomposer1q is None: continue synth_dag = circuit_to_dag( decomposer1q._decompose(node.op.to_matrix())) elif len(node.qargs) == 2: if decomposer2q is None: continue synth_dag = circuit_to_dag( decomposer2q(node.op.to_matrix(), basis_fidelity=self._approximation_degree)) else: synth_dag = circuit_to_dag( isometry.Isometry(node.op.to_matrix(), 0, 0).definition) dag.substitute_node_with_dag(node, synth_dag) return dag
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the UnitarySynthesis pass on `dag`. Args: dag: input dag. Returns: Output dag with UnitaryGates synthesized to target basis. Raises: TranspilerError: if a 'method' was specified for the class and is not found in the installed plugins list. The list of installed plugins can be queried with :func:`~qiskit.transpiler.passes.synthesis.plugin.unitary_synthesis_plugin_names` """ if self.method not in self.plugins.ext_plugins: raise TranspilerError( "Specified method: %s not found in plugin list" % self.method) default_method = self.plugins.ext_plugins["default"].obj plugin_method = self.plugins.ext_plugins[self.method].obj if plugin_method.supports_coupling_map: dag_bit_indices = {bit: idx for idx, bit in enumerate(dag.qubits)} kwargs = {} if plugin_method.supports_basis_gates: kwargs["basis_gates"] = self._basis_gates if plugin_method.supports_natural_direction: kwargs["natural_direction"] = self._natural_direction if plugin_method.supports_pulse_optimize: kwargs["pulse_optimize"] = self._pulse_optimize if plugin_method.supports_gate_lengths: kwargs["gate_lengths"] = _build_gate_lengths(self._backend_props) if plugin_method.supports_gate_errors: kwargs["gate_errors"] = _build_gate_errors(self._backend_props) supported_bases = plugin_method.supported_bases if supported_bases is not None: kwargs["matched_basis"] = _choose_bases(self._basis_gates, supported_bases) # Handle approximation degree as a special case for backwards compatibility, it's # not part of the plugin interface and only something needed for the default # pass. default_method._approximation_degree = self._approximation_degree if self.method == "default": plugin_method._approximation_degree = self._approximation_degree for node in dag.named_nodes(*self._synth_gates): if self._min_qubits is not None and len( node.qargs) < self._min_qubits: continue if plugin_method.supports_coupling_map: kwargs["coupling_map"] = ( self._coupling_map, [dag_bit_indices[x] for x in node.qargs], ) synth_dag = None unitary = node.op.to_matrix() n_qubits = len(node.qargs) if (plugin_method.max_qubits is not None and n_qubits > plugin_method.max_qubits) or ( plugin_method.min_qubits is not None and n_qubits < plugin_method.min_qubits): synth_dag = default_method.run(unitary, **kwargs) else: synth_dag = plugin_method.run(unitary, **kwargs) if synth_dag is not None: if isinstance(synth_dag, tuple): dag.substitute_node_with_dag(node, synth_dag[0], wires=synth_dag[1]) else: dag.substitute_node_with_dag(node, synth_dag) return dag
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the UnitarySynthesis pass on `dag`. Args: dag: input dag. Returns: Output dag with UnitaryGates synthesized to target basis. Raises: TranspilerError: if a 'method' was specified for the class and is not found in the installed plugins list. The list of installed plugins can be queried with :func:`~qiskit.transpiler.passes.synthesis.plugin.unitary_synthesis_plugin_names` """ if self.method not in self.plugins.ext_plugins: raise TranspilerError( "Specified method: %s not found in plugin list" % self.method) # Return fast if we have no synth gates (ie user specified an empty # list or the synth gates are all in the basis if not self._synth_gates: return dag plugin_method = self.plugins.ext_plugins[self.method].obj plugin_kwargs = {"config": self._plugin_config} _gate_lengths = _gate_errors = None dag_bit_indices = {} if self.method == "default": # If the method is the default, we only need to evaluate one set of keyword arguments. # To simplify later logic, and avoid cases where static analysis might complain that we # haven't initialised the "default" handler, we rebind the names so they point to the # same object as the chosen method. default_method = plugin_method default_kwargs = plugin_kwargs method_list = [(plugin_method, plugin_kwargs)] else: # If the method is not the default, we still need to initialise the default plugin's # keyword arguments in case we have to fall back on it during the actual run. default_method = self.plugins.ext_plugins["default"].obj default_kwargs = {} method_list = [(plugin_method, plugin_kwargs), (default_method, default_kwargs)] for method, kwargs in method_list: if method.supports_basis_gates: kwargs["basis_gates"] = self._basis_gates if method.supports_coupling_map: dag_bit_indices = dag_bit_indices or { bit: i for i, bit in enumerate(dag.qubits) } if method.supports_natural_direction: kwargs["natural_direction"] = self._natural_direction if method.supports_pulse_optimize: kwargs["pulse_optimize"] = self._pulse_optimize if method.supports_gate_lengths: _gate_lengths = _gate_lengths or _build_gate_lengths( self._backend_props, self._target) kwargs["gate_lengths"] = _gate_lengths if method.supports_gate_errors: _gate_errors = _gate_errors or _build_gate_errors( self._backend_props, self._target) kwargs["gate_errors"] = _gate_errors supported_bases = method.supported_bases if supported_bases is not None: kwargs["matched_basis"] = _choose_bases( self._basis_gates, supported_bases) if method.supports_target: kwargs["target"] = self._target # Handle approximation degree as a special case for backwards compatibility, it's # not part of the plugin interface and only something needed for the default # pass. default_method._approximation_degree = self._approximation_degree if self.method == "default": plugin_method._approximation_degree = self._approximation_degree for node in dag.named_nodes(*self._synth_gates): if self._min_qubits is not None and len( node.qargs) < self._min_qubits: continue synth_dag = None unitary = node.op.to_matrix() n_qubits = len(node.qargs) if (plugin_method.max_qubits is not None and n_qubits > plugin_method.max_qubits) or ( plugin_method.min_qubits is not None and n_qubits < plugin_method.min_qubits): method, kwargs = default_method, default_kwargs else: method, kwargs = plugin_method, plugin_kwargs if method.supports_coupling_map: kwargs["coupling_map"] = ( self._coupling_map, [dag_bit_indices[x] for x in node.qargs], ) synth_dag = method.run(unitary, **kwargs) if synth_dag is not None: if isinstance(synth_dag, tuple): dag.substitute_node_with_dag(node, synth_dag[0], wires=synth_dag[1]) else: dag.substitute_node_with_dag(node, synth_dag) return dag