Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix behavior of n_local calling circuits for num_qubits=1 #13523

Merged
merged 17 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion qiskit/circuit/library/n_local/efficient_su2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
18 changes: 11 additions & 7 deletions qiskit/circuit/library/n_local/excitation_preserving.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions qiskit/circuit/library/n_local/pauli_two_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion qiskit/circuit/library/n_local/real_amplitudes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
29 changes: 29 additions & 0 deletions test/python/circuit/library/test_nlocal.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand All @@ -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):
Expand All @@ -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
Expand Down
Loading