From 82bbcaa8281e020b30ad3bb6f8483141836378e5 Mon Sep 17 00:00:00 2001 From: trigpolynom Date: Tue, 17 Dec 2024 03:30:46 -0500 Subject: [PATCH] Fix behavior of n_local calling circuits for num_qubits=1 (#13523) * added fix for efficient_su2 * making fix for real_amplitudes and excitation_preserving * formatted * passing tests * added release notes * fixed pauli_two_design * fixed format * fixed pauli_two_design issue * fixed unused gate * Update qiskit/circuit/library/n_local/pauli_two_design.py Co-authored-by: Julien Gacon * addressing change --------- Co-authored-by: Julien Gacon --- .../circuit/library/n_local/efficient_su2.py | 5 +++- .../library/n_local/excitation_preserving.py | 18 +++++++----- .../library/n_local/pauli_two_design.py | 5 ++-- .../library/n_local/real_amplitudes.py | 4 ++- ...-su2-numqubits-issue-2b2c91c1186f82ac.yaml | 6 ++++ test/python/circuit/library/test_nlocal.py | 29 +++++++++++++++++++ 6 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 releasenotes/notes/fix-efficient-su2-numqubits-issue-2b2c91c1186f82ac.yaml diff --git a/qiskit/circuit/library/n_local/efficient_su2.py b/qiskit/circuit/library/n_local/efficient_su2.py index 53698a3e18a..c9589a22c9f 100644 --- a/qiskit/circuit/library/n_local/efficient_su2.py +++ b/qiskit/circuit/library/n_local/efficient_su2.py @@ -114,10 +114,13 @@ def efficient_su2( if su2_gates is None: su2_gates = ["ry", "rz"] + # Set entanglement_blocks to None when num_qubits == 1 + entanglement_blocks = ["cx"] if num_qubits > 1 else [] + return n_local( num_qubits, su2_gates, - ["cx"], + entanglement_blocks, entanglement, reps, insert_barriers, diff --git a/qiskit/circuit/library/n_local/excitation_preserving.py b/qiskit/circuit/library/n_local/excitation_preserving.py index 49bfdb07f01..b2fd3f0cdc4 100644 --- a/qiskit/circuit/library/n_local/excitation_preserving.py +++ b/qiskit/circuit/library/n_local/excitation_preserving.py @@ -112,17 +112,21 @@ def excitation_preserving( raise ValueError(f"Unsupported mode {mode}, choose one of {supported_modes}") theta = Parameter("θ") - swap = QuantumCircuit(2, name="Interaction") - swap.rxx(theta, 0, 1) - swap.ryy(theta, 0, 1) - if mode == "fsim": - phi = Parameter("φ") - swap.cp(phi, 0, 1) + if num_qubits > 1: + swap = QuantumCircuit(2, name="Interaction") + swap.rxx(theta, 0, 1) + swap.ryy(theta, 0, 1) + if mode == "fsim": + phi = Parameter("φ") + swap.cp(phi, 0, 1) + entanglement_blocks = [swap.to_gate()] + else: + entanglement_blocks = [] return n_local( num_qubits, ["rz"], - [swap.to_gate()], + entanglement_blocks, entanglement, reps, insert_barriers, diff --git a/qiskit/circuit/library/n_local/pauli_two_design.py b/qiskit/circuit/library/n_local/pauli_two_design.py index f0deeb68b28..fc286c8533b 100644 --- a/qiskit/circuit/library/n_local/pauli_two_design.py +++ b/qiskit/circuit/library/n_local/pauli_two_design.py @@ -88,19 +88,20 @@ def pauli_two_design( """ rng = np.random.default_rng(seed) random_block = Block.from_callable(1, 1, lambda params: _random_pauli_builder(params, rng)) - cz_block = Block.from_standard_gate(CZGate._standard_gate) + entanglement_block = [Block.from_standard_gate(CZGate._standard_gate)] if num_qubits > 1 else [] data = py_n_local( num_qubits=num_qubits, reps=reps, rotation_blocks=[random_block], - entanglement_blocks=[cz_block], + entanglement_blocks=entanglement_block, entanglement=["pairwise"], insert_barriers=insert_barriers, skip_final_rotation_layer=False, skip_unentangled_qubits=False, parameter_prefix=parameter_prefix, ) + two_design = QuantumCircuit._from_circuit_data(data) circuit = QuantumCircuit(num_qubits, name=name) diff --git a/qiskit/circuit/library/n_local/real_amplitudes.py b/qiskit/circuit/library/n_local/real_amplitudes.py index f1ba10604e9..572cc036ad7 100644 --- a/qiskit/circuit/library/n_local/real_amplitudes.py +++ b/qiskit/circuit/library/n_local/real_amplitudes.py @@ -114,11 +114,13 @@ def real_amplitudes( Returns: A real-amplitudes circuit. """ + # Set entanglement_blocks to None when num_qubits == 1 + entanglement_blocks = ["cx"] if num_qubits > 1 else [] return n_local( num_qubits, ["ry"], - ["cx"], + entanglement_blocks, entanglement, reps, insert_barriers, diff --git a/releasenotes/notes/fix-efficient-su2-numqubits-issue-2b2c91c1186f82ac.yaml b/releasenotes/notes/fix-efficient-su2-numqubits-issue-2b2c91c1186f82ac.yaml new file mode 100644 index 00000000000..530c4438de3 --- /dev/null +++ b/releasenotes/notes/fix-efficient-su2-numqubits-issue-2b2c91c1186f82ac.yaml @@ -0,0 +1,6 @@ +fixes: + - | + Fixed a bug that caused the circuit library functions :func:`.efficient_su2`, + :func:`.real_amplitudes`, :func:`.excitation_preserving` and :func:`.pauli_two_design` + to error out when constructed for ``num_qubits==1``. For a single qubit these + circuits will not contain any 2-qubit gates. \ No newline at end of file diff --git a/test/python/circuit/library/test_nlocal.py b/test/python/circuit/library/test_nlocal.py index 22bfa391612..b171a728d4c 100644 --- a/test/python/circuit/library/test_nlocal.py +++ b/test/python/circuit/library/test_nlocal.py @@ -784,12 +784,24 @@ def test_real_amplitudes(self): expected = n_local(4, "ry", "cx", "reverse_linear", reps=3) self.assertEqual(expected.assign_parameters(circuit.parameters), circuit) + def test_real_amplitudes_numqubits_equal1(self): + """Test the real amplitudes circuit for a single qubit.""" + circuit = real_amplitudes(1) + expected = n_local(1, "ry", []) + self.assertEqual(expected.assign_parameters(circuit.parameters), circuit) + def test_efficient_su2(self): """Test the efficient SU(2) circuit.""" circuit = efficient_su2(4) expected = n_local(4, ["ry", "rz"], "cx", "reverse_linear", reps=3) self.assertEqual(expected.assign_parameters(circuit.parameters), circuit) + def test_efficient_su2_numqubits_equal1(self): + """Test the efficient SU(2) circuit for a single qubit.""" + circuit = efficient_su2(1) + expected = n_local(1, ["ry", "rz"], []) + self.assertEqual(expected.assign_parameters(circuit.parameters), circuit) + @data("fsim", "iswap") def test_excitation_preserving(self, mode): """Test the excitation preserving circuit.""" @@ -808,6 +820,15 @@ def test_excitation_preserving(self, mode): expected.assign_parameters(circuit.parameters).decompose(), circuit.decompose() ) + @data("fsim", "iswap") + def test_excitation_preserving_numqubits_equal1(self, mode): + """Test the excitation preserving circuit for a single qubit.""" + circuit = excitation_preserving(1, mode=mode) + expected = n_local(1, "rz", []) + self.assertEqual( + expected.assign_parameters(circuit.parameters).decompose(), circuit.decompose() + ) + def test_excitation_preserving_invalid_mode(self): """Test an error is raised for an invalid mode.""" with self.assertRaises(ValueError): @@ -824,6 +845,14 @@ def test_two_design(self): self.assertTrue(circuit_ops.issubset(expected_ops)) + def test_two_design_numqubits_equal1(self): + """Test the Pauli 2-design circuit for a single qubit.""" + circuit = pauli_two_design(1) + expected_ops = {"rx", "ry", "rz", "id"} + circuit_ops = set(circuit.count_ops().keys()) + + self.assertTrue(circuit_ops.issubset(expected_ops)) + def test_two_design_seed(self): """Test the seed""" seed1 = 123