From 39b2c90b813da63d006755580cabd80b718b74bb Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 26 Jun 2024 09:48:25 -0400 Subject: [PATCH 1/2] Add test case to validate the rust->Python gate conversion (#12623) This commit adds a test to the test_rust_equivalence module to assert that the Python gate objects returned from the Rust CircuitData is the correct type. --- test/python/circuit/test_rust_equivalence.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/python/circuit/test_rust_equivalence.py b/test/python/circuit/test_rust_equivalence.py index 8d6d159c0b64..b20db4c79f94 100644 --- a/test/python/circuit/test_rust_equivalence.py +++ b/test/python/circuit/test_rust_equivalence.py @@ -18,7 +18,7 @@ import numpy as np -from qiskit.circuit import QuantumCircuit +from qiskit.circuit import QuantumCircuit, CircuitInstruction from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping SKIP_LIST = {"rx", "ry", "ecr"} @@ -39,6 +39,21 @@ def setUp(self): gate = gate.base_class(*[pi] * len(gate.params)) qc.append(gate, list(range(gate.num_qubits))) + def test_gate_cross_domain_conversion(self): + """Test the rust -> python conversion returns the right class.""" + for name, gate_class in self.standard_gates.items(): + standard_gate = getattr(gate_class, "_standard_gate", None) + if standard_gate is None: + # Gate not in rust yet or no constructor method + continue + with self.subTest(name=name): + qc = QuantumCircuit(standard_gate.num_qubits) + qc._append( + CircuitInstruction(standard_gate, qubits=qc.qubits, params=gate_class.params) + ) + self.assertEqual(qc.data[0].operation.base_class, gate_class.base_class) + self.assertEqual(qc.data[0].operation, gate_class) + def test_definitions(self): """Test definitions are the same in rust space.""" for name, gate_class in self.standard_gates.items(): From 2fab2007e3d7384e9e55a10340952c4974ece03c Mon Sep 17 00:00:00 2001 From: Eli Arbel <46826214+eliarbel@users.noreply.github.com> Date: Wed, 26 Jun 2024 18:15:10 +0300 Subject: [PATCH 2/2] Add Rust representation for DCXGate (#12644) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Updating tables * Adding remaining code * Appending the Rust representation directly * Fix fmt --------- Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> --- crates/circuit/src/gate_matrix.rs | 7 ++++++ crates/circuit/src/imports.rs | 2 +- crates/circuit/src/operations.rs | 25 ++++++++++++++++---- qiskit/circuit/library/standard_gates/dcx.py | 3 +++ qiskit/circuit/quantumcircuit.py | 4 +--- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/crates/circuit/src/gate_matrix.rs b/crates/circuit/src/gate_matrix.rs index 2e5f55d6ddcb..80fecfb597c6 100644 --- a/crates/circuit/src/gate_matrix.rs +++ b/crates/circuit/src/gate_matrix.rs @@ -226,6 +226,13 @@ pub static TDG_GATE: [[Complex64; 2]; 2] = [ [c64(0., 0.), c64(FRAC_1_SQRT_2, -FRAC_1_SQRT_2)], ]; +pub static DCX_GATE: [[Complex64; 4]; 4] = [ + [c64(1., 0.), c64(0., 0.), c64(0., 0.), c64(0., 0.)], + [c64(0., 0.), c64(0., 0.), c64(0., 0.), c64(1., 0.)], + [c64(0., 0.), c64(1., 0.), c64(0., 0.), c64(0., 0.)], + [c64(0., 0.), c64(0., 0.), c64(1., 0.), c64(0., 0.)], +]; + #[inline] pub fn global_phase_gate(theta: f64) -> [[Complex64; 1]; 1] { [[c64(0., theta).exp()]] diff --git a/crates/circuit/src/imports.rs b/crates/circuit/src/imports.rs index 92700f3274e7..632f5b0f5737 100644 --- a/crates/circuit/src/imports.rs +++ b/crates/circuit/src/imports.rs @@ -183,7 +183,7 @@ static STDGATE_IMPORT_PATHS: [[&str; 2]; STANDARD_GATE_SIZE] = [ // C4XGate = 44 ["placeholder", "placeholder"], // DCXGate = 45 - ["placeholder", "placeholder"], + ["qiskit.circuit.library.standard_gates.dcx", "DCXGate"], // CCZGate = 46 ["placeholder", "placeholder"], // RCCXGate = 47 diff --git a/crates/circuit/src/operations.rs b/crates/circuit/src/operations.rs index af7dabc86216..d9626b5c7371 100644 --- a/crates/circuit/src/operations.rs +++ b/crates/circuit/src/operations.rs @@ -240,7 +240,7 @@ static STANDARD_GATE_NUM_QUBITS: [u32; STANDARD_GATE_SIZE] = [ 2, 2, 1, 0, 1, 1, 1, 1, 1, 1, // 10-19 1, 1, 1, 2, 2, 2, 1, 1, 1, 34, // 20-29 34, 34, 34, 2, 2, 2, 2, 2, 3, 2, // 30-39 - 2, 2, 34, 34, 34, 34, 34, 34, 34, 34, // 40-49 + 2, 2, 34, 34, 34, 2, 34, 34, 34, 34, // 40-49 34, 34, 34, // 50-52 ]; @@ -250,7 +250,7 @@ static STANDARD_GATE_NUM_PARAMS: [u32; STANDARD_GATE_SIZE] = [ 0, 0, 0, 1, 0, 0, 1, 3, 0, 0, // 10-19 0, 0, 0, 0, 2, 2, 1, 2, 3, 34, // 20-29 34, 34, 34, 0, 1, 0, 0, 0, 0, 3, // 30-39 - 1, 3, 34, 34, 34, 34, 34, 34, 34, 34, // 40-49 + 1, 3, 34, 34, 34, 0, 34, 34, 34, 34, // 40-49 34, 34, 34, // 50-52 ]; @@ -523,7 +523,10 @@ impl Operation for StandardGate { Self::CSwapGate => todo!(), Self::CUGate | Self::CU1Gate | Self::CU3Gate => todo!(), Self::C3XGate | Self::C3SXGate | Self::C4XGate => todo!(), - Self::DCXGate => todo!(), + Self::DCXGate => match params { + [] => Some(aview2(&gate_matrix::DCX_GATE).to_owned()), + _ => None, + }, Self::CCZGate => todo!(), Self::RCCXGate | Self::RC3XGate => todo!(), Self::RXXGate | Self::RYYGate | Self::RZZGate => todo!(), @@ -965,7 +968,21 @@ impl Operation for StandardGate { Self::CU1Gate => todo!(), Self::CU3Gate => todo!(), Self::C3XGate | Self::C3SXGate | Self::C4XGate => todo!(), - Self::DCXGate => todo!(), + Self::DCXGate => Python::with_gil(|py| -> Option { + Some( + CircuitData::from_standard_gates( + py, + 2, + [ + (Self::CXGate, smallvec![], smallvec![Qubit(0), Qubit(1)]), + (Self::CXGate, smallvec![], smallvec![Qubit(1), Qubit(0)]), + ], + FLOAT_ZERO, + ) + .expect("Unexpected Qiskit python bug"), + ) + }), + Self::CCZGate => todo!(), Self::RCCXGate | Self::RC3XGate => todo!(), Self::RXXGate | Self::RYYGate | Self::RZZGate => todo!(), diff --git a/qiskit/circuit/library/standard_gates/dcx.py b/qiskit/circuit/library/standard_gates/dcx.py index 6455bea2779e..d83f2e2f9c7f 100644 --- a/qiskit/circuit/library/standard_gates/dcx.py +++ b/qiskit/circuit/library/standard_gates/dcx.py @@ -15,6 +15,7 @@ from qiskit.circuit.singleton import SingletonGate, stdlib_singleton_key from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit._utils import with_gate_array +from qiskit._accelerate.circuit import StandardGate @with_gate_array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0]]) @@ -48,6 +49,8 @@ class DCXGate(SingletonGate): \end{pmatrix} """ + _standard_gate = StandardGate.DCXGate + def __init__(self, label=None, *, duration=None, unit="dt"): """Create new DCX gate.""" super().__init__("dcx", 2, [], label=label, duration=duration, unit=unit) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 8b3ff7bf1979..08bac04c9e6f 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -5328,9 +5328,7 @@ def dcx(self, qubit1: QubitSpecifier, qubit2: QubitSpecifier) -> InstructionSet: Returns: A handle to the instructions created. """ - from .library.standard_gates.dcx import DCXGate - - return self.append(DCXGate(), [qubit1, qubit2], [], copy=False) + return self._append_standard_gate(op=StandardGate.DCXGate, qargs=[qubit1, qubit2]) def ccx( self,