def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the Decompose pass on `dag`. Args: dag: input dag. Returns: output dag where ``gate`` was expanded. """ # Walk through the DAG and expand each non-basis node for node in dag.op_nodes(): if self._should_decompose(node): if getattr(node.op, "definition", None) is None: continue # TODO: allow choosing among multiple decomposition rules rule = node.op.definition.data if len(rule) == 1 and len(node.qargs) == len( rule[0].qubits) == 1: if node.op.definition.global_phase: dag.global_phase += node.op.definition.global_phase dag.substitute_node(node, rule[0].operation, inplace=True) else: decomposition = circuit_to_dag(node.op.definition) dag.substitute_node_with_dag(node, decomposition) 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. """ for node in dag.nodes(): if node.type != 'op': continue # skip all nodes that do not represent operations if not node.op.num_qubits == 1: continue # ignore all non-single qubit gates, possible raise error here? matrix = node.op.to_matrix() # call solovay kitaev approximation = self._sk.run(matrix, self._recursion_degree) # convert to a dag and replace the gate by the approximation substitute = circuit_to_dag(approximation) dag.substitute_node_with_dag(node, substitute) return dag
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the Decompose pass on `dag`. Args: dag: input dag. Returns: output dag where ``gate`` was expanded. """ # Walk through the DAG and expand each non-basis node for node in dag.op_nodes(self.gate): # opaque or built-in gates are not decomposable if not node.op.definition: continue if node.op.definition.global_phase: dag.global_phase += node.op.definition.global_phase # TODO: allow choosing among multiple decomposition rules rule = node.op.definition.data if len(rule) == 1 and len(node.qargs) == len(rule[0][1]) == 1: dag.substitute_node(node, rule[0][0], inplace=True) else: decomposition = circuit_to_dag(node.op.definition) dag.substitute_node_with_dag(node, decomposition) return dag
def circuit_stripping(circuit,gates_to_strip): dag = circuit_to_dag(circuit) stripped_dag = DAGCircuit() [stripped_dag.add_qreg(x) for x in circuit.qregs] for vertex in dag.topological_op_nodes(): if vertex.op.name not in gates_to_strip: stripped_dag.apply_operation_back(op=vertex.op, qargs=vertex.qargs) return dag_to_circuit(stripped_dag)
def circuit_stripping(circuit): # Remove all single qubit gates and barriers in the circuit dag = circuit_to_dag(circuit) stripped_dag = DAGCircuit() [stripped_dag.add_qreg(x) for x in circuit.qregs] for vertex in dag.topological_op_nodes(): if len(vertex.qargs) == 2 and vertex.op.name!='barrier': stripped_dag.apply_operation_back(op=vertex.op, qargs=vertex.qargs) return dag_to_circuit(stripped_dag)
def dagdependency_to_dag(dagdependency): """Build a ``DAGCircuit`` object from a ``DAGDependency``. Args: dag dependency (DAGDependency): the input dag. Return: DAGCircuit: the DAG representing the input circuit. """ dagcircuit = DAGCircuit() dagcircuit.name = dagdependency.name qregs = list(dagdependency.qregs.values()) cregs = list(dagdependency.cregs.values()) for register in qregs: dagcircuit.add_qreg(register) for register in cregs: dagcircuit.add_creg(register) for node in dagdependency.get_nodes(): # Get arguments for classical control (if any) inst = node.op.copy() inst.condition = node.condition dagcircuit.apply_operation_back(inst, node.qargs, node.cargs, inst.condition) return dagcircuit
def circuit_to_dag(circuit): """Build a ``DAGCircuit`` object from a ``QuantumCircuit``. Args: circuit (QuantumCircuit): the input circuit. Return: DAGCircuit: the DAG representing the input circuit. """ dagcircuit = DAGCircuit() dagcircuit.name = circuit.name for register in circuit.qregs: dagcircuit.add_qreg(register) for register in circuit.cregs: dagcircuit.add_creg(register) for instruction, qargs, cargs in circuit.data: # Get arguments for classical control (if any) if instruction.control is None: control = None else: control = (instruction.control[0], instruction.control[1]) instruction = copy.deepcopy(instruction) dagcircuit.apply_operation_back(instruction, qargs, cargs, control) return dagcircuit
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 circuit_to_dag(circuit): """Build a ``DAGCircuit`` object from a ``QuantumCircuit``. Args: circuit (QuantumCircuit): the input circuit. Return: DAGCircuit: the DAG representing the input circuit. """ dagcircuit = DAGCircuit() dagcircuit.name = circuit.name for register in circuit.qregs: dagcircuit.add_qreg(register) for register in circuit.cregs: dagcircuit.add_creg(register) for instruction, qargs, cargs in circuit.data: # Get arguments for classical control (if any) if instruction.control is None: control = None else: control = (instruction.control[0], instruction.control[1]) def duplicate_instruction(inst): """Create a fresh instruction from an input instruction.""" if issubclass(inst.__class__, inst_mod.Instruction) and inst.__class__ not in [ inst_mod.Instruction, gate.Gate]: if inst.name == 'barrier': new_inst = inst.__class__(inst.num_qubits) elif inst.name == 'initialize': params = getattr(inst, 'params', []) new_inst = inst.__class__(params) elif inst.name == 'snapshot': label = inst.params[0] snap_type = inst.params[1] new_inst = inst.__class__(inst.num_qubits, inst.num_clbits, label, snap_type) else: params = getattr(inst, 'params', []) new_inst = inst.__class__(*params) else: if isinstance(inst, gate.Gate): new_inst = gate.Gate(inst.name, inst.num_qubits, inst.params) else: new_inst = inst_mod.Instruction(name=inst.name, num_qubits=inst.num_qubits, num_clbits=inst.num_clbits, params=inst.params) new_inst.definition = inst.definition return new_inst dagcircuit.apply_operation_back(duplicate_instruction(instruction), qargs, cargs, control) return dagcircuit
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 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 dag_stripping(dag, max_gates): ''' Remove all single qubit gates and barriers in the DAG Only leaves the first max_gates gates If max_gates is None, do all gates ''' stripped_dag = DAGCircuit() [stripped_dag.add_qreg(dag.qregs[qreg_name]) for qreg_name in dag.qregs] vertex_added = 0 for vertex in dag.topological_op_nodes(): within_gate_count = max_gates is None or vertex_added<max_gates if vertex.op.name!='barrier' and len(vertex.qargs)==2 and within_gate_count: stripped_dag.apply_operation_back(op=vertex.op, qargs=vertex.qargs) vertex_added += 1 return stripped_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 circuit_to_dag(circuit): """Build a ``DAGCircuit`` object from a ``QuantumCircuit``. Args: circuit (QuantumCircuit): the input circuit. Return: DAGCircuit: the DAG representing the input circuit. """ dagcircuit = DAGCircuit() dagcircuit.name = circuit.name for register in circuit.qregs: dagcircuit.add_qreg(register) for register in circuit.cregs: dagcircuit.add_creg(register) for main_instruction in circuit.data: # TODO: generate nodes for CompositeGates; # for now simply drop their instructions into the DAG instruction_list = [] is_composite = isinstance(main_instruction, CompositeGate) if is_composite: instruction_list = main_instruction.instruction_list() else: instruction_list.append(main_instruction) for instruction in instruction_list: # Get arguments for classical control (if any) if instruction.control is None: control = None else: control = (instruction.control[0], instruction.control[1]) def duplicate_instruction(inst): """Create a fresh instruction from an input instruction.""" if inst.name == 'barrier': params = [inst.qargs] elif inst.name == 'snapshot': params = inst.params + [inst.qargs] else: params = inst.params + inst.qargs + inst.cargs new_inst = inst.__class__(*params) return new_inst inst = duplicate_instruction(instruction) dagcircuit.apply_operation_back(inst, inst.qargs, inst.cargs, control) return dagcircuit
def apply_back_to_dag_circuit( self, dag_circuit: DAGCircuit, initial_mapping: ty.Dict[Qubit, int], trans_mapping: ty.Dict[Qubit, int], ): reversed_trans_mapping = { val: key for key, val in trans_mapping.items() } for op in self._operations: logical_qubits = [initial_mapping[qubit] for qubit in op.qargs] new_physical_qubits = [ reversed_trans_mapping[qubit_index] for qubit_index in logical_qubits ] #print(new_physical_qubits) dag_circuit.apply_operation_back(op.op, new_physical_qubits, op.cargs, op.condition)
def _to_dag(circuit): qiskit_dag = DAGCircuit() qreg = QuantumRegister(circuit.num_qubits()) qiskit_dag.add_qreg(qreg) if circuit.num_cbits(): creg = ClassicalRegister(circuit.num_cbits()) qiskit_dag.add_creg(creg) for instruction in circuit: gate = _convert_tweedledum_op(instruction) qubits = [qreg[qubit.uid()] for qubit in instruction.qubits()] cbits = [creg[cbit.uid()] for cbit in instruction.cbits()] qiskit_dag.apply_operation_back(gate, qubits, cbits) return qiskit_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 _create_empty_dagcircuit_from_existing(dagcircuit: DAGCircuit) -> DAGCircuit: result = DAGCircuit() for creg in dagcircuit.cregs.values(): result.add_creg(creg) for qreg in dagcircuit.qregs.values(): result.add_qreg(qreg) return result
def circuit_to_dag(circuit): """Build a ``DAGCircuit`` object from a ``QuantumCircuit``. Args: circuit (QuantumCircuit): the input circuit. Return: DAGCircuit: the DAG representing the input circuit. Example: .. jupyter-execute:: from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.dagcircuit import DAGCircuit from qiskit.converters import circuit_to_dag from qiskit.visualization import dag_drawer %matplotlib inline q = QuantumRegister(3, 'q') c = ClassicalRegister(3, 'c') circ = QuantumCircuit(q, c) circ.h(q[0]) circ.cx(q[0], q[1]) circ.measure(q[0], c[0]) circ.rz(0.5, q[1]).c_if(c, 2) dag = circuit_to_dag(circ) dag_drawer(dag) """ dagcircuit = DAGCircuit() dagcircuit.name = circuit.name dagcircuit.global_phase = circuit.global_phase for register in circuit.qregs: dagcircuit.add_qreg(register) for register in circuit.cregs: dagcircuit.add_creg(register) for instruction, qargs, cargs in circuit.data: dagcircuit.apply_operation_back(instruction.copy(), qargs, cargs) return dagcircuit
def tweedledum_to_qiskit_dag(circuit): qiskit_dag = DAGCircuit() qiskit_dag.add_qreg(circuit.num_qubits(), circuit.num_cbits()) for instruction in circuit: gate = _convert_tweedledum_op(instruction) qubits = [qubit.uid() for qubit in instruction.qubits()] cbits = [cbit.uid() for cbit in instruction.cbits()] qiskit_dag.apply_operation_back(gate, qubits, cbits) return qiskit_dag
def circuit_to_dag(circuit): """Build a ``DAGCircuit`` object from a ``QuantumCircuit``. Args: circuit (QuantumCircuit): the input circuit. Return: DAGCircuit: the DAG representing the input circuit. """ dagcircuit = DAGCircuit() dagcircuit.name = circuit.name for register in circuit.qregs: dagcircuit.add_qreg(register) for register in circuit.cregs: dagcircuit.add_creg(register) for instruction, qargs, cargs in circuit.data: dagcircuit.apply_operation_back(instruction.copy(), qargs, cargs, instruction.condition) return dagcircuit
def __init__(self, max_matches, circuit_dag_dep, template_dag_dep): """ Initialize TemplateSubstitution with necessary arguments. Args: max_matches (list): list of maximal matches obtained from the running the template matching algorithm. circuit_dag_dep (DAGDependency): circuit in the dag dependency form. template_dag_dep (DAGDependency): template in the dag dependency form. """ self.match_stack = max_matches self.circuit_dag_dep = circuit_dag_dep self.template_dag_dep = template_dag_dep self.substitution_list = [] self.unmatched_list = [] self.dag_dep_optimized = DAGDependency() self.dag_optimized = DAGCircuit()
def apply(self, dag_circuit: DAGCircuit, front_layer: QuantumLayer, initial_mapping: ty.Dict[Qubit, int], trans_mapping: ty.Dict[Qubit, int]): dag_circuit.apply_operation_back(CXGate(), [self.left, self.middle]) dag_circuit.apply_operation_back(CXGate(), [self.middle, self.right]) dag_circuit.apply_operation_back(CXGate(), [self.left, self.middle]) dag_circuit.apply_operation_back(CXGate(), [self.middle, self.right]) # dag_circuit.apply_operation_back( # _BridgeGate(), [self.left, self.middle, self.right] # ) # Do not forget to remove the CNOT gate from self.left to self.right from the # front layer. op_to_remove: ty.Optional[DAGNode] = None for op in front_layer.ops: q1, q2 = initial_mapping[op.qargs[0]], initial_mapping[op.qargs[1]] if (len(op.qargs) == 2 and q1 == trans_mapping[self.left] and q2 == trans_mapping[self.right]): op_to_remove = op if op_to_remove is None: logger.warning( "Could not find a corresponding CNOT gate to remove with " "Bridge usage. Resulting circuit will likely be wrong.") else: front_layer.remove_operation(op_to_remove)
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the Decompose pass on `dag`. Args: dag: input dag. Returns: output dag where ``gate`` was expanded. """ # Walk through the DAG and expand each non-basis node for node in dag.op_nodes(self.gate): # opaque or built-in gates are not decomposable if not node.op.definition: continue # TODO: allow choosing among multiple decomposition rules rule = node.op.definition if len(rule) == 1 and len(node.qargs) == len(rule[0][1]): dag.substitute_node(node, rule[0][0], inplace=True) else: # hacky way to build a dag on the same register as the rule is defined # TODO: need anonymous rules to address wires by index decomposition = DAGCircuit() qregs = {qb.register for inst in rule for qb in inst[1]} cregs = {cb.register for inst in rule for cb in inst[2]} for qreg in qregs: decomposition.add_qreg(qreg) for creg in cregs: decomposition.add_creg(creg) for inst in rule: decomposition.apply_operation_back(*inst) dag.substitute_node_with_dag(node, decomposition) return dag
def __init__(self, max_matches, circuit_dag_dep, template_dag_dep, user_cost_dict=None): """ Initialize TemplateSubstitution with necessary arguments. Args: max_matches (list): list of maximal matches obtained from the running the template matching algorithm. circuit_dag_dep (DAGDependency): circuit in the dag dependency form. template_dag_dep (DAGDependency): template in the dag dependency form. user_cost_dict (Optional[dict]): user provided cost dictionary that will override the default cost dictionary. """ self.match_stack = max_matches self.circuit_dag_dep = circuit_dag_dep self.template_dag_dep = template_dag_dep self.substitution_list = [] self.unmatched_list = [] self.dag_dep_optimized = DAGDependency() self.dag_optimized = DAGCircuit() if user_cost_dict is not None: self.cost_dict = dict(user_cost_dict) else: self.cost_dict = { "id": 0, "x": 1, "y": 1, "z": 1, "h": 1, "t": 1, "tdg": 1, "s": 1, "sdg": 1, "u1": 1, "u2": 2, "u3": 2, "rx": 1, "ry": 1, "rz": 1, "r": 2, "cx": 2, "cy": 4, "cz": 4, "ch": 8, "swap": 6, "iswap": 8, "rxx": 9, "ryy": 9, "rzz": 5, "rzx": 7, "ms": 9, "cu3": 10, "crx": 10, "cry": 10, "crz": 10, "ccx": 21, "rccx": 12, "c3x": 96, "rc3x": 24, "c4x": 312, "p": 1, }
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 dagdependency_to_dag(dagdependency): """Build a ``DAGCircuit`` object from a ``DAGDependency``. Args: dag dependency (DAGDependency): the input dag. Return: DAGCircuit: the DAG representing the input circuit. """ dagcircuit = DAGCircuit() dagcircuit.name = dagdependency.name dagcircuit.metadata = dagdependency.metadata dagcircuit.add_qubits(dagdependency.qubits) dagcircuit.add_clbits(dagdependency.clbits) for register in dagdependency.qregs.values(): dagcircuit.add_qreg(register) for register in dagdependency.cregs.values(): dagcircuit.add_creg(register) for node in dagdependency.get_nodes(): # Get arguments for classical control (if any) inst = node.op.copy() dagcircuit.apply_operation_back(inst, node.qargs, node.cargs) # copy metadata dagcircuit.global_phase = dagdependency.global_phase dagcircuit.calibrations = dagdependency.calibrations return dagcircuit
def apply(self, dag_circuit: DAGCircuit, front_layer: QuantumLayer, initial_mapping: ty.Dict[Qubit, int], trans_mapping: ty.Dict[Qubit, int]): dag_circuit.apply_operation_back(SwapGate(), [self.left, self.right])
def __init__(self, max_matches, circuit_dag_dep, template_dag_dep, user_cost_dict=None): """ Initialize TemplateSubstitution with necessary arguments. Args: max_matches (list): list of maximal matches obtained from the running the template matching algorithm. circuit_dag_dep (DAGDependency): circuit in the dag dependency form. template_dag_dep (DAGDependency): template in the dag dependency form. user_cost_dict (Optional[dict]): user provided cost dictionary that will override the default cost dictionary. """ self.match_stack = max_matches self.circuit_dag_dep = circuit_dag_dep self.template_dag_dep = template_dag_dep self.substitution_list = [] self.unmatched_list = [] self.dag_dep_optimized = DAGDependency() self.dag_optimized = DAGCircuit() if user_cost_dict is not None: self.cost_dict = dict(user_cost_dict) else: self.cost_dict = { 'id': 0, 'x': 1, 'y': 1, 'z': 1, 'h': 1, 't': 1, 'tdg': 1, 's': 1, 'sdg': 1, 'u1': 1, 'u2': 2, 'u3': 2, 'rx': 1, 'ry': 1, 'rz': 1, 'r': 2, 'cx': 2, 'cy': 4, 'cz': 4, 'ch': 8, 'swap': 6, 'iswap': 8, 'rxx': 9, 'ryy': 9, 'rzz': 5, 'rzx': 7, 'ms': 9, 'cu3': 10, 'crx': 10, 'cry': 10, 'crz': 10, 'ccx': 21, 'rccx': 12, 'c3x': 96, 'rc3x': 24, 'c4x': 312, 'p': 1 }
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