Skip to content

Commit fe1b981

Browse files
Don't track loop_param (#15814)
* Don't track loop_param * Update releasenotes/notes/fix-for-loop-loop-param-in-outer-parameters-e0f2b653308aaadc.yaml Co-authored-by: Jake Lishman <jake@binhbar.com> --------- Co-authored-by: Jake Lishman <jake@binhbar.com>
1 parent 0b45bf0 commit fe1b981

3 files changed

Lines changed: 25 additions & 10 deletions

File tree

crates/circuit/src/circuit_data.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,22 +2001,16 @@ fn for_each_symbol_use_in_control_flow(
20012001
body,
20022002
collection: _,
20032003
} => {
2004-
// The loop param is technically a parameter in Python land at `params[1]`.
2005-
if let Some(symbol) = loop_param {
2006-
action(
2007-
symbol,
2008-
ParameterUse::Index {
2009-
instruction: instruction_index,
2010-
parameter: 1,
2011-
},
2012-
)?;
2013-
}
20142004
// The body is at `params[2]`.
20152005
let usage = ParameterUse::Index {
20162006
instruction: instruction_index,
20172007
parameter: 2,
20182008
};
20192009
for symbol in body.parameters() {
2010+
// Skip the loop variable itself — it is runtime-bound.
2011+
if loop_param.as_ref() == Some(&symbol) {
2012+
continue;
2013+
}
20202014
action(symbol, usage)?;
20212015
}
20222016
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fixes:
2+
- |
3+
Fixed a bug where the loop variable of a :class:`.ForLoopOp` was incorrectly
4+
tracked in the outer circuit's parameter table, causing it to appear in
5+
:attr:`.QuantumCircuit.parameters` and making :meth:`~.QuantumCircuit.assign_parameters` raise an internal
6+
:exc:`RuntimeError`.
7+
8+
See `#15657 <https://github.com/Qiskit/qiskit/issues/15657>`__ for details.

test/python/circuit/test_control_flow.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,19 @@ def test_quantumcircuit_for_loop_op(self):
813813
self.assertEqual(qc.data[0].qubits, tuple(qc.qubits[1:4]))
814814
self.assertEqual(qc.data[0].clbits, (qc.clbits[1],))
815815

816+
def test_for_loop_loop_parameter_not_in_outer_parameters(self):
817+
"""A ForLoopOp's loop_parameter must NOT appear in the outer circuit's parameters."""
818+
theta = Parameter("θ")
819+
body = QuantumCircuit(1)
820+
body.rx(theta, 0)
821+
822+
qc = QuantumCircuit(1)
823+
qc.append(ForLoopOp(range(3), theta, body), [0])
824+
825+
self.assertNotIn(theta, qc.parameters)
826+
with self.assertRaisesRegex(CircuitError, r"not present in the circuit"):
827+
qc.assign_parameters({theta: math.pi / 2}, inplace=False)
828+
816829
@idata(CONDITION_PARAMETRISATION)
817830
def test_appending_if_else_op(self, condition):
818831
"""Verify we can append a IfElseOp to a QuantumCircuit."""

0 commit comments

Comments
 (0)