diff --git a/crates/accelerate/src/convert_2q_block_matrix.rs b/crates/accelerate/src/convert_2q_block_matrix.rs index dd61137c54f4..12146dd9d080 100644 --- a/crates/accelerate/src/convert_2q_block_matrix.rs +++ b/crates/accelerate/src/convert_2q_block_matrix.rs @@ -126,7 +126,9 @@ pub fn change_basis(matrix: ArrayView2) -> Array2 { #[pyfunction] pub fn collect_2q_blocks_filter(node: &Bound) -> Option { - let Ok(node) = node.downcast::() else { return None }; + let Ok(node) = node.downcast::() else { + return None; + }; let node = node.borrow(); match node.instruction.op() { gate @ (OperationRef::Standard(_) | OperationRef::Gate(_)) => Some( diff --git a/crates/accelerate/src/euler_one_qubit_decomposer.rs b/crates/accelerate/src/euler_one_qubit_decomposer.rs index f42cb7f705ee..7bbb6871db0a 100644 --- a/crates/accelerate/src/euler_one_qubit_decomposer.rs +++ b/crates/accelerate/src/euler_one_qubit_decomposer.rs @@ -1045,7 +1045,9 @@ fn matmul_1q(operator: &mut [[Complex64; 2]; 2], other: Array2) { #[pyfunction] pub fn collect_1q_runs_filter(node: &Bound) -> bool { - let Ok(node) = node.downcast::() else { return false }; + let Ok(node) = node.downcast::() else { + return false; + }; let node = node.borrow(); let op = node.instruction.op(); op.num_qubits() == 1 diff --git a/crates/accelerate/src/two_qubit_decompose.rs b/crates/accelerate/src/two_qubit_decompose.rs index ac2cc1d2e50e..ed4d32bd3b85 100644 --- a/crates/accelerate/src/two_qubit_decompose.rs +++ b/crates/accelerate/src/two_qubit_decompose.rs @@ -51,10 +51,13 @@ use rand::prelude::*; use rand_distr::StandardNormal; use rand_pcg::Pcg64Mcg; +use qiskit_circuit::circuit_data::CircuitData; +use qiskit_circuit::circuit_instruction::OperationFromPython; use qiskit_circuit::gate_matrix::{CX_GATE, H_GATE, ONE_QUBIT_IDENTITY, SX_GATE, X_GATE}; -use qiskit_circuit::operations::Operation; +use qiskit_circuit::operations::{Param, StandardGate}; use qiskit_circuit::slice::{PySequenceIndex, SequenceIndex}; use qiskit_circuit::util::{c64, GateArray1Q, GateArray2Q, C_M_ONE, C_ONE, C_ZERO, IM, M_IM}; +use qiskit_circuit::Qubit; const PI2: f64 = PI / 2.; const PI4: f64 = PI / 4.; @@ -309,10 +312,10 @@ fn compute_unitary(sequence: &TwoQubitSequenceVec, global_phase: f64) -> Array2< // sequence. If we get a different gate this is getting called // by something else and is invalid. let gate_matrix = match inst.0.as_ref() { - "sx" => aview2(&SX_GATE).to_owned(), - "rz" => rz_matrix(inst.1[0]), - "cx" => aview2(&CX_GATE).to_owned(), - "x" => aview2(&X_GATE).to_owned(), + Some(StandardGate::SXGate) => aview2(&SX_GATE).to_owned(), + Some(StandardGate::RZGate) => rz_matrix(inst.1[0]), + Some(StandardGate::CXGate) => aview2(&CX_GATE).to_owned(), + Some(StandardGate::XGate) => aview2(&X_GATE).to_owned(), _ => unreachable!("Undefined gate"), }; (gate_matrix, &inst.2) @@ -395,6 +398,8 @@ impl Specialization { } } +type WeylCircuitSequence = Vec<(StandardGate, SmallVec<[Param; 3]>, SmallVec<[Qubit; 2]>)>; + #[derive(Clone, Debug)] #[allow(non_snake_case)] #[pyclass(module = "qiskit._accelerate.two_qubit_decompose", subclass)] @@ -425,33 +430,53 @@ impl TwoQubitWeylDecomposition { fn weyl_gate( &self, simplify: bool, - sequence: &mut TwoQubitSequenceVec, + sequence: &mut WeylCircuitSequence, atol: f64, global_phase: &mut f64, ) { match self.specialization { Specialization::MirrorControlledEquiv => { - sequence.push(("swap".to_string(), SmallVec::new(), smallvec![0, 1])); sequence.push(( - "rzz".to_string(), - smallvec![(PI4 - self.c) * 2.], - smallvec![0, 1], + StandardGate::SwapGate, + SmallVec::new(), + smallvec![Qubit(0), Qubit(1)], + )); + sequence.push(( + StandardGate::RZZGate, + smallvec![Param::Float((PI4 - self.c) * 2.)], + smallvec![Qubit(0), Qubit(1)], )); *global_phase += PI4 } Specialization::SWAPEquiv => { - sequence.push(("swap".to_string(), SmallVec::new(), smallvec![0, 1])); + sequence.push(( + StandardGate::SwapGate, + SmallVec::new(), + smallvec![Qubit(0), Qubit(1)], + )); *global_phase -= 3. * PI / 4. } _ => { if !simplify || self.a.abs() > atol { - sequence.push(("rxx".to_string(), smallvec![-self.a * 2.], smallvec![0, 1])); + sequence.push(( + StandardGate::RXXGate, + smallvec![Param::Float(-self.a * 2.)], + smallvec![Qubit(0), Qubit(1)], + )); } if !simplify || self.b.abs() > atol { - sequence.push(("ryy".to_string(), smallvec![-self.b * 2.], smallvec![0, 1])); + sequence.push(( + StandardGate::RYYGate, + smallvec![Param::Float(-self.b * 2.)], + smallvec![Qubit(0), Qubit(1)], + )); } if !simplify || self.c.abs() > atol { - sequence.push(("rzz".to_string(), smallvec![-self.c * 2.], smallvec![0, 1])); + sequence.push(( + StandardGate::RZZGate, + smallvec![Param::Float(-self.c * 2.)], + smallvec![Qubit(0), Qubit(1)], + )); } } } @@ -1023,17 +1048,18 @@ impl TwoQubitWeylDecomposition { #[pyo3(signature = (euler_basis=None, simplify=false, atol=None))] fn circuit( &self, + py: Python, euler_basis: Option, simplify: bool, atol: Option, - ) -> PyResult { + ) -> PyResult { let euler_basis: EulerBasis = match euler_basis { Some(basis) => EulerBasis::__new__(basis.deref())?, None => self.default_euler_basis, }; let target_1q_basis_list: Vec = vec![euler_basis]; - let mut gate_sequence = Vec::new(); + let mut gate_sequence: WeylCircuitSequence = Vec::with_capacity(21); let mut global_phase: f64 = self.global_phase; let c2r = unitary_to_gate_sequence_inner( @@ -1046,7 +1072,11 @@ impl TwoQubitWeylDecomposition { ) .unwrap(); for gate in c2r.gates { - gate_sequence.push((gate.0.name().to_string(), gate.1, smallvec![0])) + gate_sequence.push(( + gate.0, + gate.1.into_iter().map(Param::Float).collect(), + smallvec![Qubit(0)], + )) } global_phase += c2r.global_phase; let c2l = unitary_to_gate_sequence_inner( @@ -1059,7 +1089,11 @@ impl TwoQubitWeylDecomposition { ) .unwrap(); for gate in c2l.gates { - gate_sequence.push((gate.0.name().to_string(), gate.1, smallvec![1])) + gate_sequence.push(( + gate.0, + gate.1.into_iter().map(Param::Float).collect(), + smallvec![Qubit(1)], + )) } global_phase += c2l.global_phase; self.weyl_gate( @@ -1078,7 +1112,11 @@ impl TwoQubitWeylDecomposition { ) .unwrap(); for gate in c1r.gates { - gate_sequence.push((gate.0.name().to_string(), gate.1, smallvec![0])) + gate_sequence.push(( + gate.0, + gate.1.into_iter().map(Param::Float).collect(), + smallvec![Qubit(0)], + )) } global_phase += c2r.global_phase; let c1l = unitary_to_gate_sequence_inner( @@ -1091,16 +1129,17 @@ impl TwoQubitWeylDecomposition { ) .unwrap(); for gate in c1l.gates { - gate_sequence.push((gate.0.name().to_string(), gate.1, smallvec![1])) + gate_sequence.push(( + gate.0, + gate.1.into_iter().map(Param::Float).collect(), + smallvec![Qubit(1)], + )) } - Ok(TwoQubitGateSequence { - gates: gate_sequence, - global_phase, - }) + CircuitData::from_standard_gates(py, 2, gate_sequence, Param::Float(global_phase)) } } -type TwoQubitSequenceVec = Vec<(String, SmallVec<[f64; 3]>, SmallVec<[u8; 2]>)>; +type TwoQubitSequenceVec = Vec<(Option, SmallVec<[f64; 3]>, SmallVec<[u8; 2]>)>; #[pyclass(sequence)] pub struct TwoQubitGateSequence { @@ -1263,17 +1302,21 @@ impl TwoQubitBasisDecomposer { let mut euler_matrix_q1 = rz_matrix(euler_q1[0][1]).dot(&rx_matrix(euler_q1[0][0])); euler_matrix_q1 = rx_matrix(euler_q1[0][2] + euler_q1[1][0]).dot(&euler_matrix_q1); self.append_1q_sequence(&mut gates, &mut global_phase, euler_matrix_q1.view(), 1); - gates.push(("cx".to_string(), smallvec![], smallvec![0, 1])); - gates.push(("sx".to_string(), smallvec![], smallvec![0])); + gates.push((Some(StandardGate::CXGate), smallvec![], smallvec![0, 1])); + gates.push((Some(StandardGate::SXGate), smallvec![], smallvec![0])); gates.push(( - "rz".to_string(), + Some(StandardGate::RZGate), smallvec![euler_q0[1][1] - PI], smallvec![0], )); - gates.push(("sx".to_string(), smallvec![], smallvec![0])); - gates.push(("rz".to_string(), smallvec![euler_q1[1][1]], smallvec![1])); + gates.push((Some(StandardGate::SXGate), smallvec![], smallvec![0])); + gates.push(( + Some(StandardGate::RZGate), + smallvec![euler_q1[1][1]], + smallvec![1], + )); global_phase += PI2; - gates.push(("cx".to_string(), smallvec![], smallvec![0, 1])); + gates.push((Some(StandardGate::CXGate), smallvec![], smallvec![0, 1])); let mut euler_matrix_q0 = rx_matrix(euler_q0[2][1]).dot(&rz_matrix(euler_q0[1][2] + euler_q0[2][0] + PI2)); euler_matrix_q0 = rz_matrix(euler_q0[2][2]).dot(&euler_matrix_q0); @@ -1358,7 +1401,7 @@ impl TwoQubitBasisDecomposer { euler_matrix_q1 = aview2(&H_GATE).dot(&euler_matrix_q1); self.append_1q_sequence(&mut gates, &mut global_phase, euler_matrix_q1.view(), 1); - gates.push(("cx".to_string(), smallvec![], smallvec![1, 0])); + gates.push((Some(StandardGate::CXGate), smallvec![], smallvec![1, 0])); if x12_is_pi_mult { // even or odd multiple @@ -1366,14 +1409,22 @@ impl TwoQubitBasisDecomposer { global_phase += x12_phase; } if x12_is_non_zero && x12_is_old_mult.unwrap() { - gates.push(("rz".to_string(), smallvec![-euler_q0[1][1]], smallvec![0])); + gates.push(( + Some(StandardGate::RZGate), + smallvec![-euler_q0[1][1]], + smallvec![0], + )); } else { - gates.push(("rz".to_string(), smallvec![euler_q0[1][1]], smallvec![0])); + gates.push(( + Some(StandardGate::RZGate), + smallvec![euler_q0[1][1]], + smallvec![0], + )); global_phase += PI; } } if x12_is_half_pi { - gates.push(("sx".to_string(), smallvec![], smallvec![0])); + gates.push((Some(StandardGate::SXGate), smallvec![], smallvec![0])); global_phase -= PI4; } else if x12_is_non_zero && !x12_is_pi_mult { if self.pulse_optimize.is_none() { @@ -1383,7 +1434,7 @@ impl TwoQubitBasisDecomposer { } } if abs_diff_eq!(euler_q1[1][1], PI2, epsilon = atol) { - gates.push(("sx".to_string(), smallvec![], smallvec![1])); + gates.push((Some(StandardGate::SXGate), smallvec![], smallvec![1])); global_phase -= PI4 } else if self.pulse_optimize.is_none() { self.append_1q_sequence( @@ -1396,14 +1447,18 @@ impl TwoQubitBasisDecomposer { return None; } gates.push(( - "rz".to_string(), + Some(StandardGate::RZGate), smallvec![euler_q1[1][2] + euler_q1[2][0]], smallvec![1], )); - gates.push(("cx".to_string(), smallvec![], smallvec![1, 0])); - gates.push(("rz".to_string(), smallvec![euler_q0[2][1]], smallvec![0])); + gates.push((Some(StandardGate::CXGate), smallvec![], smallvec![1, 0])); + gates.push(( + Some(StandardGate::RZGate), + smallvec![euler_q0[2][1]], + smallvec![0], + )); if abs_diff_eq!(euler_q1[2][1], PI2, epsilon = atol) { - gates.push(("sx".to_string(), smallvec![], smallvec![1])); + gates.push((Some(StandardGate::SXGate), smallvec![], smallvec![1])); global_phase -= PI4; } else if self.pulse_optimize.is_none() { self.append_1q_sequence( @@ -1415,7 +1470,7 @@ impl TwoQubitBasisDecomposer { } else { return None; } - gates.push(("cx".to_string(), smallvec![], smallvec![1, 0])); + gates.push((Some(StandardGate::CXGate), smallvec![], smallvec![1, 0])); let mut euler_matrix = rz_matrix(euler_q0[2][2] + euler_q0[3][0]).dot(&aview2(&H_GATE)); euler_matrix = rx_matrix(euler_q0[3][1]).dot(&euler_matrix); euler_matrix = rz_matrix(euler_q0[3][2]).dot(&euler_matrix); @@ -1460,7 +1515,7 @@ impl TwoQubitBasisDecomposer { if let Some(sequence) = sequence { *global_phase += sequence.global_phase; for gate in sequence.gates { - gates.push((gate.0.name().to_string(), gate.1, smallvec![qubit])); + gates.push((Some(gate.0), gate.1, smallvec![qubit])); } } } @@ -1848,27 +1903,27 @@ impl TwoQubitBasisDecomposer { for i in 0..best_nbasis as usize { if let Some(euler_decomp) = &euler_decompositions[2 * i] { for gate in &euler_decomp.gates { - gates.push((gate.0.name().to_string(), gate.1.clone(), smallvec![0])); + gates.push((Some(gate.0), gate.1.clone(), smallvec![0])); } global_phase += euler_decomp.global_phase } if let Some(euler_decomp) = &euler_decompositions[2 * i + 1] { for gate in &euler_decomp.gates { - gates.push((gate.0.name().to_string(), gate.1.clone(), smallvec![1])); + gates.push((Some(gate.0), gate.1.clone(), smallvec![1])); } global_phase += euler_decomp.global_phase } - gates.push((self.gate.clone(), smallvec![], smallvec![0, 1])); + gates.push((None, smallvec![], smallvec![0, 1])); } if let Some(euler_decomp) = &euler_decompositions[2 * best_nbasis as usize] { for gate in &euler_decomp.gates { - gates.push((gate.0.name().to_string(), gate.1.clone(), smallvec![0])); + gates.push((Some(gate.0), gate.1.clone(), smallvec![0])); } global_phase += euler_decomp.global_phase } if let Some(euler_decomp) = &euler_decompositions[2 * best_nbasis as usize + 1] { for gate in &euler_decomp.gates { - gates.push((gate.0.name().to_string(), gate.1.clone(), smallvec![1])); + gates.push((Some(gate.0), gate.1.clone(), smallvec![1])); } global_phase += euler_decomp.global_phase } @@ -1878,6 +1933,40 @@ impl TwoQubitBasisDecomposer { }) } + #[pyo3(signature = (unitary, kak_gate, basis_fidelity=None, approximate=true, _num_basis_uses=None))] + fn to_circuit( + &self, + py: Python, + unitary: PyReadonlyArray2, + kak_gate: PyObject, + basis_fidelity: Option, + approximate: bool, + _num_basis_uses: Option, + ) -> PyResult { + let kak_gate = kak_gate.extract::(py)?; + let sequence = self.__call__(unitary, basis_fidelity, approximate, _num_basis_uses)?; + CircuitData::from_standard_gates( + py, + 2, + sequence + .gates + .into_iter() + .map(|(gate, params, qubits)| match gate { + Some(gate) => ( + gate, + params.into_iter().map(Param::Float).collect(), + qubits.into_iter().map(|x| Qubit(x.into())).collect(), + ), + None => ( + kak_gate.operation.standard_gate(), + kak_gate.params.clone(), + qubits.into_iter().map(|x| Qubit(x.into())).collect(), + ), + }), + Param::Float(sequence.global_phase), + ) + } + fn num_basis_gates(&self, unitary: PyReadonlyArray2) -> usize { _num_basis_gates(self.basis_decomposer.b, self.basis_fidelity, unitary) } diff --git a/crates/circuit/src/circuit_instruction.rs b/crates/circuit/src/circuit_instruction.rs index 7fc35269d1f0..3ab0fe6279f7 100644 --- a/crates/circuit/src/circuit_instruction.rs +++ b/crates/circuit/src/circuit_instruction.rs @@ -429,7 +429,9 @@ impl CircuitInstruction { if other.is_instance_of::() { return Ok(Some(self_._legacy_format(py)?.eq(other)?)); } - let Ok(other) = other.downcast::() else { return Ok(None) }; + let Ok(other) = other.downcast::() else { + return Ok(None); + }; let other = other.try_borrow()?; Ok(Some( @@ -471,7 +473,7 @@ impl CircuitInstruction { /// though you can also accept `ob: OperationFromPython` directly, if you don't also need a handle /// to the Python object that it came from. The handle is useful for the Python-operation caching. #[derive(Debug)] -pub(crate) struct OperationFromPython { +pub struct OperationFromPython { pub operation: PackedOperation, pub params: SmallVec<[Param; 3]>, pub extra_attrs: Option>, @@ -508,7 +510,10 @@ impl<'py> FromPyObject<'py> for OperationFromPython { let Some(standard) = ob_type .getattr(intern!(py, "_standard_gate")) .and_then(|standard| standard.extract::()) - .ok() else { break 'standard }; + .ok() + else { + break 'standard; + }; // If the instruction is a controlled gate with a not-all-ones control state, it doesn't // fit our definition of standard. We abuse the fact that we know our standard-gate @@ -581,7 +586,9 @@ impl<'py> FromPyObject<'py> for OperationFromPython { /// Convert a sequence-like Python object to a tuple. fn as_tuple<'py>(py: Python<'py>, seq: Option>) -> PyResult> { - let Some(seq) = seq else { return Ok(PyTuple::empty_bound(py)) }; + let Some(seq) = seq else { + return Ok(PyTuple::empty_bound(py)); + }; if seq.is_instance_of::() { Ok(seq.downcast_into_exact::()?) } else if seq.is_instance_of::() { diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index 7a20001ffdf3..8d3cfdf7f007 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -412,7 +412,9 @@ impl StandardGate { pub fn __eq__(&self, other: &Bound) -> Py { let py = other.py(); - let Ok(other) = other.extract::() else { return py.NotImplemented() }; + let Ok(other) = other.extract::() else { + return py.NotImplemented(); + }; (*self == other).into_py(py) } diff --git a/crates/circuit/src/packed_instruction.rs b/crates/circuit/src/packed_instruction.rs index 9f7cf9c0135d..c909ca3d1b56 100644 --- a/crates/circuit/src/packed_instruction.rs +++ b/crates/circuit/src/packed_instruction.rs @@ -378,7 +378,9 @@ impl Drop for PackedOperation { fn drop_pointer_as(slf: &mut PackedOperation) { // This should only ever be called when the pointer is valid, but this is defensive just // to 100% ensure that our `Drop` implementation doesn't panic. - let Some(pointer) = slf.try_pointer() else { return }; + let Some(pointer) = slf.try_pointer() else { + return; + }; // SAFETY: `PackedOperation` asserts ownership over its contents, and the contained // pointer can only be null if we were already dropped. We set our discriminant to mark // ourselves as plain old data immediately just as a defensive measure. diff --git a/qiskit/synthesis/two_qubit/two_qubit_decompose.py b/qiskit/synthesis/two_qubit/two_qubit_decompose.py index 3269797827e2..80a454cc6bd4 100644 --- a/qiskit/synthesis/two_qubit/two_qubit_decompose.py +++ b/qiskit/synthesis/two_qubit/two_qubit_decompose.py @@ -35,7 +35,7 @@ import numpy as np -from qiskit.circuit import QuantumRegister, QuantumCircuit, Gate +from qiskit.circuit import QuantumRegister, QuantumCircuit, Gate, CircuitInstruction from qiskit.circuit.library.standard_gates import ( CXGate, U3Gate, @@ -60,7 +60,7 @@ from qiskit._accelerate import two_qubit_decompose if TYPE_CHECKING: - from qiskit.dagcircuit.dagcircuit import DAGCircuit + from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode logger = logging.getLogger(__name__) @@ -230,13 +230,10 @@ def circuit( self, *, euler_basis: str | None = None, simplify: bool = False, atol: float = DEFAULT_ATOL ) -> QuantumCircuit: """Returns Weyl decomposition in circuit form.""" - circuit_sequence = self._inner_decomposition.circuit( + circuit_data = self._inner_decomposition.circuit( euler_basis=euler_basis, simplify=simplify, atol=atol ) - circ = QuantumCircuit(2, global_phase=circuit_sequence.global_phase) - for name, params, qubits in circuit_sequence: - getattr(circ, name)(*params, *qubits) - return circ + return QuantumCircuit._from_circuit_data(circuit_data) def actual_fidelity(self, **kwargs) -> float: """Calculates the actual fidelity of the decomposed circuit to the input unitary.""" @@ -641,47 +638,58 @@ def __call__( QiskitError: if ``pulse_optimize`` is True but we don't know how to do it. """ - sequence = self._inner_decomposer( - np.asarray(unitary, dtype=complex), - basis_fidelity, - approximate, - _num_basis_uses=_num_basis_uses, - ) - q = QuantumRegister(2) if use_dag: - from qiskit.dagcircuit.dagcircuit import DAGCircuit + from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode + + sequence = self._inner_decomposer( + np.asarray(unitary, dtype=complex), + basis_fidelity, + approximate, + _num_basis_uses=_num_basis_uses, + ) + q = QuantumRegister(2) dag = DAGCircuit() dag.global_phase = sequence.global_phase dag.add_qreg(q) - for name, params, qubits in sequence: - if name == "USER_GATE": + for gate, params, qubits in sequence: + if gate is None: dag.apply_operation_back(self.gate, tuple(q[x] for x in qubits), check=False) else: - gate = GATE_NAME_MAP[name](*params) - dag.apply_operation_back(gate, tuple(q[x] for x in qubits), check=False) + op = CircuitInstruction.from_standard( + gate, qubits=tuple(q[x] for x in qubits), params=params + ) + node = DAGOpNode.from_instruction(op, dag=dag) + dag._apply_op_node_back(node) return dag else: - circ = QuantumCircuit(q, global_phase=sequence.global_phase) - for name, params, qubits in sequence: - try: - getattr(circ, name)(*params, *qubits) - except AttributeError as exc: - if name == "USER_GATE": - circ.append(self.gate, qubits) - elif name == "u3": - gate = U3Gate(*params) - circ.append(gate, qubits) - elif name == "u2": - gate = U2Gate(*params) - circ.append(gate, qubits) - elif name == "u1": - gate = U1Gate(*params) - circ.append(gate, qubits) + if getattr(self.gate, "_standard_gate", None): + circ_data = self._inner_decomposer.to_circuit( + np.asarray(unitary, dtype=complex), + self.gate, + basis_fidelity, + approximate, + _num_basis_uses=_num_basis_uses, + ) + return QuantumCircuit._from_circuit_data(circ_data) + else: + sequence = self._inner_decomposer( + np.asarray(unitary, dtype=complex), + basis_fidelity, + approximate, + _num_basis_uses=_num_basis_uses, + ) + q = QuantumRegister(2) + circ = QuantumCircuit(q, global_phase=sequence.global_phase) + for gate, params, qubits in sequence: + if gate is None: + circ._append(self.gate, qargs=tuple(q[x] for x in qubits)) else: - raise QiskitError(f"Unknown gate {name}") from exc - - return circ + inst = CircuitInstruction.from_standard( + gate, qubits=tuple(q[x] for x in qubits), params=params + ) + circ._append(inst) + return circ def traces(self, target): r""" diff --git a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py index 08b6a15fd03d..3b39228723dd 100644 --- a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py @@ -561,11 +561,11 @@ def _run_main_loop( qubits = node.qargs user_gate_node = DAGOpNode(gate) for ( - op_name, + gate, params, qargs, ) in node_list: - if op_name == "USER_GATE": + if gate is None: node = DAGOpNode.from_instruction( user_gate_node._to_circuit_instruction().replace( params=user_gate_node.params, @@ -576,7 +576,7 @@ def _run_main_loop( else: node = DAGOpNode.from_instruction( CircuitInstruction.from_standard( - GATE_NAME_MAP[op_name], tuple(qubits[x] for x in qargs), params + gate, tuple(qubits[x] for x in qargs), params ), dag=out_dag, ) @@ -1008,8 +1008,8 @@ def _synth_su4_no_dag(self, unitary, decomposer2q, preferred_direction, approxim # if the gates in synthesis are in the opposite direction of the preferred direction # resynthesize a new operator which is the original conjugated by swaps. # this new operator is doubly mirrored from the original and is locally equivalent. - for op_name, _params, qubits in synth_circ: - if op_name in {"USER_GATE", "cx"}: + for gate, _params, qubits in synth_circ: + if gate is None or gate == CXGate._standard_gate: synth_direction = qubits if synth_direction is not None and synth_direction != preferred_direction: # TODO: Avoid using a dag to correct the synthesis direction