-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Issue 6633: Update _parameter_table after circuit assignment #7434
Changes from 16 commits
ace8f24
471f1aa
da1a64f
68b157b
a540ec1
4551c3d
b50f8a8
f5be2ad
5c9ff04
05a13a5
ed4395e
d318a18
1db7729
b2837b1
e16f51c
e8e54a9
b5969ad
3c352cc
86dc448
9592520
2832122
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
|
||
from qiskit.circuit.exceptions import CircuitError | ||
from qiskit.circuit.instruction import Instruction | ||
from .parameter import Parameter | ||
|
||
|
||
class QuantumCircuitData(MutableSequence): | ||
|
@@ -54,10 +55,46 @@ def __setitem__(self, key, value): | |
self._circuit._check_qargs(qargs) | ||
self._circuit._check_cargs(cargs) | ||
|
||
circ_data = {} | ||
param = {"old": 0, "new": 0} | ||
circ_data["old"] = self._circuit._data | ||
self._circuit._data[key] = (instruction, qargs, cargs) | ||
circ_data["new"] = self._circuit._data | ||
|
||
self._circuit._update_parameter_table(instruction) | ||
|
||
if len(circ_data["old"][key][0].params) > 0: | ||
if isinstance(circ_data["old"][key][0].params[0], Parameter): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't handle |
||
param["old"] = circ_data["old"][key][0].params[0] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This only checks the first parameter of an instruction, not all of the parameters. |
||
|
||
if len(circ_data["new"][key][0].params) > 0: | ||
if isinstance(circ_data["new"][key][0].params[0], Parameter): | ||
param["new"] = circ_data["new"][key][0].params[0] | ||
|
||
param_count = -1 | ||
if isinstance(param["old"], Parameter): | ||
for idx, data in enumerate(circ_data["old"]): | ||
if idx <= key: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be better done by only enumerating the items you are interested in, rather than looping through everything and skipping the last set. |
||
if len(data[0].params) > 0: | ||
if data[0].params[0] == param["old"]: | ||
param_count = param_count + 1 | ||
else: | ||
pass | ||
self._circuit._parameter_table[param["old"]].pop(param_count) | ||
|
||
param_count = -1 | ||
if isinstance(param["new"], Parameter): | ||
for idx, data in enumerate(circ_data["new"]): | ||
if idx <= key: | ||
if len(data[0].params) > 0: | ||
if data[0].params[0] == param["new"]: | ||
param_count = param_count + 1 | ||
else: | ||
pass | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This whole section is difficult to read, to the point that I'm not confident that I can review it for correctness. I suggested a few simplifications above, but really I think a lot of this should be in quite a different form within |
||
added_element = self._circuit._parameter_table[param["new"]][-1] | ||
self._circuit._parameter_table[param["new"]].insert(param_count, added_element) | ||
self._circuit._parameter_table[param["new"]].pop() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why update the parameter table earlier if we need to remove what it did and re-arrange it? More importantly, though, all of this modification of the internal data structures of |
||
|
||
def insert(self, index, value): | ||
self._circuit._data.insert(index, None) | ||
self[index] = value | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,6 +62,7 @@ class BaseTestCase(testtools.TestCase): | |
assertRaises = unittest.TestCase.assertRaises | ||
assertEqual = unittest.TestCase.assertEqual | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The version of |
||
else: | ||
|
||
class BaseTestCase(unittest.TestCase): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
fixes: | ||
- | | ||
Fixed a bug when ``QuantumCircuit._parameter_table`` is inconsistent with | ||
``QuantumCircuit.data`` after a circuit assignment. | ||
In __setitem__ of QuantumCiruitData, for each new entry, the old element | ||
is removed and the new element is added properly. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -425,3 +425,19 @@ def test_param_gate_instance(self): | |
qc0_instance = qc0._parameter_table[b][0][0] | ||
qc1_instance = qc1._parameter_table[a][0][0] | ||
self.assertNotEqual(qc0_instance, qc1_instance) | ||
|
||
def test_parameter_table_is_updated(self): | ||
"""Verify that circuit._parameter_table is consistent with circuit.data.""" | ||
qr = QuantumRegister(1, "q") | ||
qc = QuantumCircuit(qr) | ||
|
||
a = Parameter("a") | ||
qc.h(0) | ||
qc.ry(a, 0) | ||
qc.rz(a, 0) | ||
|
||
qc.data[0] = (RXGate(a), [qr[0]], []) | ||
qc.data[1] = (RXGate(a), [qr[0]], []) | ||
qc.data[2] = (HGate(), [qr[0]], []) | ||
|
||
qc.copy() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test has no assertions - it is only testing that nothing crashes. Tests also need to have positive assertions, that the output is correct. In every case, we should also test that:
There are also quite a few special cases, that we should be sure to test as well:
That list might not be complete, so other ideas are good too. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need to use dictionaries for this. It's much clearer to use two separate variables. This also does not do what you think - you're saving the same reference to the list into both
old
andnew
, and so there are no circumstances in whichcirc_data["old"]
will ever be different fromcirc_data["new"]
, because they're the exact same object.