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 StatevectorSampler to raise an error if a circuit with c_if is passed (backport #12842) #12851

Merged
merged 1 commit into from
Jul 30, 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
7 changes: 5 additions & 2 deletions qiskit/primitives/statevector_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def _preprocess_circuit(circuit: QuantumCircuit):
qargs_index = {v: k for k, v in enumerate(qargs)}
circuit = circuit.remove_final_measurements(inplace=False)
if _has_control_flow(circuit):
raise QiskitError("StatevectorSampler cannot handle ControlFlowOp")
raise QiskitError("StatevectorSampler cannot handle ControlFlowOp and c_if")
if _has_measure(circuit):
raise QiskitError("StatevectorSampler cannot handle mid-circuit measurements")
# num_qubits is used as sentinel to fill 0 in _samples_to_packed_array
Expand Down Expand Up @@ -283,4 +283,7 @@ def _final_measurement_mapping(circuit: QuantumCircuit) -> dict[tuple[ClassicalR


def _has_control_flow(circuit: QuantumCircuit) -> bool:
return any(isinstance(instruction.operation, ControlFlowOp) for instruction in circuit)
return any(
isinstance((op := instruction.operation), ControlFlowOp) or op.condition
for instruction in circuit
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
fixes:
- |
Fixed a bug of :class:`.StatevectorSampler` that ignored gates with ``c_if``.
It will raise an error because :class:`.Statevector` cannot handle ``c_if``.
28 changes: 20 additions & 8 deletions test/python/primitives/test_statevector_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@ def test_run_errors(self):
qc3 = QuantumCircuit(1, 1)
with qc3.for_loop(range(5)):
qc3.h(0)
qc4 = QuantumCircuit(2, 2)
qc4.h(0)
qc4.measure(1, 1)
qc4.x(0).c_if(1, 1)
qc4.measure(0, 0)

sampler = StatevectorSampler()
with self.subTest("set parameter values to a non-parameterized circuit"):
Expand All @@ -301,6 +306,9 @@ def test_run_errors(self):
with self.subTest("with control flow"):
with self.assertRaises(QiskitError):
_ = sampler.run([qc3]).result()
with self.subTest("with c_if"):
with self.assertRaises(QiskitError):
_ = sampler.run([qc4]).result()
with self.subTest("negative shots, run arg"):
with self.assertRaises(ValueError):
_ = sampler.run([qc1], shots=-1).result()
Expand Down Expand Up @@ -584,25 +592,29 @@ def test_circuit_with_aliased_cregs(self):
c2 = ClassicalRegister(1, "c2")

qc = QuantumCircuit(q, c1, c2)
qc.ry(np.pi / 4, 2)
qc.cx(2, 1)
qc.cx(0, 1)
qc.h(0)
qc.measure(0, c1)
qc.measure(1, c2)
qc.z(2).c_if(c1, 1)
qc.x(2).c_if(c2, 1)
qc2 = QuantumCircuit(5, 5)
qc2.compose(qc, [0, 2, 3], [2, 4], inplace=True)
cregs = [creg.name for creg in qc2.cregs]
# Note: qc2 has aliased cregs, c0 -> c[2] and c1 -> c[4].
# copy_empty_like copies the aliased cregs of qc2 to qc3.
qc3 = QuantumCircuit.copy_empty_like(qc2)
qc3.ry(np.pi / 4, 2)
qc3.cx(2, 1)
qc3.cx(0, 1)
qc3.h(0)
qc3.measure(0, 2)
qc3.measure(1, 4)
self.assertEqual(len(qc3.cregs), 3)
cregs = [creg.name for creg in qc3.cregs]
target = {
cregs[0]: {0: 4255, 4: 4297, 16: 720, 20: 726},
cregs[1]: {0: 5000, 1: 5000},
cregs[2]: {0: 8500, 1: 1500},
}

sampler = StatevectorSampler(seed=self._seed)
result = sampler.run([qc2], shots=self._shots).result()
result = sampler.run([qc3], shots=self._shots).result()
self.assertEqual(len(result), 1)
data = result[0].data
self.assertEqual(len(data), 3)
Expand Down
Loading