Skip to content

Commit

Permalink
Fix StatevectorSampler to raise an error if a circuit with c_if is …
Browse files Browse the repository at this point in the history
…passed (#12842) (#12851)

* fix StatevectorSampler with c_if

* add comment

(cherry picked from commit 239a669)

Co-authored-by: Takashi Imamichi <[email protected]>
  • Loading branch information
mergify[bot] and t-imamichi authored Jul 30, 2024
1 parent 0c6acb7 commit e3cd5b3
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 10 deletions.
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

0 comments on commit e3cd5b3

Please sign in to comment.