Fix `StatevectorSampler` to raise an error if a circuit with c_if is passed (#12842)

* fix StatevectorSampler with c_if

* add comment
This commit is contained in:
Takashi Imamichi 2024-07-30 20:04:51 +09:00 committed by GitHub
parent b985b96b9d
commit 239a669ab7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 30 additions and 10 deletions

View File

@ -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
@ -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
)

View File

@ -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``.

View File

@ -280,6 +280,11 @@ class TestStatevectorSampler(QiskitTestCase):
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"):
@ -301,6 +306,9 @@ class TestStatevectorSampler(QiskitTestCase):
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()
@ -584,17 +592,21 @@ class TestStatevectorSampler(QiskitTestCase):
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},
@ -602,7 +614,7 @@ class TestStatevectorSampler(QiskitTestCase):
}
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)