Skip to content

Commit 1817f4e

Browse files
mtreinishraynelfss
authored andcommitted
Preserve bit locations through pickle (Qiskit#13980)
* Preserve bit locations through pickle Previously when we were pickling a DAGCircuit the bit locations fields were forgotten about. So when we loaded a DAGCircuit from a pickle the bit locations were empty. This would cause any call to find_bit() to raise an error because there was no entry for any of the bits in the dag. This commit fixes this by reconstructing the bit locations on __setstate__ by iterating over the dag's qubits and clbits. Fixes Qiskit#13976 * Fix clippy * Update docstrings * Fix name change after rebase
1 parent 866a09a commit 1817f4e

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

crates/circuit/src/dag_circuit.rs

+20
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,26 @@ impl DAGCircuit {
857857
}
858858
}
859859
self.dag.remove_node(tmp_node);
860+
self.qubit_locations = BitLocator::with_capacity(self.qubits.len());
861+
for (index, qubit) in self.qubits.objects().iter().enumerate() {
862+
let registers = self
863+
.qregs
864+
.registers()
865+
.iter()
866+
.filter_map(|x| x.index_of(qubit).map(|y| (x.clone(), y)));
867+
self.qubit_locations
868+
.insert(qubit.clone(), BitLocations::new(index as u32, registers));
869+
}
870+
self.clbit_locations = BitLocator::with_capacity(self.clbits.len());
871+
for (index, clbit) in self.clbits.objects().iter().enumerate() {
872+
let registers = self
873+
.cregs
874+
.registers()
875+
.iter()
876+
.filter_map(|x| x.index_of(clbit).map(|y| (x.clone(), y)));
877+
self.clbit_locations
878+
.insert(clbit.clone(), BitLocations::new(index as u32, registers));
879+
}
860880
Ok(())
861881
}
862882

test/python/dagcircuit/test_dagcircuit.py

+77
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
from __future__ import annotations
1616

1717
from collections import Counter
18+
import pickle
19+
import copy
20+
import io
1821
import unittest
1922

2023
from ddt import ddt, data
@@ -161,6 +164,80 @@ def test_dag_get_qubits(self):
161164
],
162165
)
163166

167+
def test_pickle_bit_locations_with_reg(self):
168+
"""Test bit locations preserved through pickle."""
169+
dag = DAGCircuit()
170+
qr = QuantumRegister(2, "qr")
171+
cr = ClassicalRegister(1, "cr")
172+
dag.add_qreg(qr)
173+
dag.add_creg(cr)
174+
self.assertEqual(dag.find_bit(dag.qubits[1]).index, 1)
175+
self.assertEqual(dag.find_bit(dag.qubits[1]).registers, [(qr, 1)])
176+
self.assertEqual(dag.find_bit(dag.clbits[0]).index, 0)
177+
self.assertEqual(dag.find_bit(dag.clbits[0]).registers, [(cr, 0)])
178+
with io.BytesIO() as buf:
179+
pickle.dump(dag, buf)
180+
buf.seek(0)
181+
output = pickle.load(buf)
182+
self.assertEqual(output.find_bit(output.qubits[1]).index, 1)
183+
self.assertEqual(output.find_bit(output.qubits[1]).registers, [(qr, 1)])
184+
self.assertEqual(output.find_bit(output.clbits[0]).index, 0)
185+
self.assertEqual(output.find_bit(output.clbits[0]).registers, [(cr, 0)])
186+
187+
def test_deepcopy_bit_locations_with_reg(self):
188+
"""Test bit locations preserved through deepcopy."""
189+
dag = DAGCircuit()
190+
qr = QuantumRegister(2, "qr")
191+
cr = ClassicalRegister(1, "cr")
192+
dag.add_qreg(qr)
193+
dag.add_creg(cr)
194+
self.assertEqual(dag.find_bit(dag.qubits[1]).index, 1)
195+
self.assertEqual(dag.find_bit(dag.qubits[1]).registers, [(qr, 1)])
196+
self.assertEqual(dag.find_bit(dag.clbits[0]).index, 0)
197+
self.assertEqual(dag.find_bit(dag.clbits[0]).registers, [(cr, 0)])
198+
output = copy.deepcopy(dag)
199+
self.assertEqual(output.find_bit(output.qubits[1]).index, 1)
200+
self.assertEqual(output.find_bit(output.qubits[1]).registers, [(qr, 1)])
201+
self.assertEqual(output.find_bit(output.clbits[0]).index, 0)
202+
self.assertEqual(output.find_bit(output.clbits[0]).registers, [(cr, 0)])
203+
204+
def test_pickle_bit_locations_with_no_reg(self):
205+
"""Test bit locations with no registers preserved through pickle."""
206+
dag = DAGCircuit()
207+
qubits = [Qubit(), Qubit()]
208+
clbits = [Clbit()]
209+
dag.add_qubits(qubits)
210+
dag.add_clbits(clbits)
211+
self.assertEqual(dag.find_bit(dag.qubits[1]).index, 1)
212+
self.assertEqual(dag.find_bit(dag.qubits[1]).registers, [])
213+
self.assertEqual(dag.find_bit(dag.clbits[0]).index, 0)
214+
self.assertEqual(dag.find_bit(dag.clbits[0]).registers, [])
215+
with io.BytesIO() as buf:
216+
pickle.dump(dag, buf)
217+
buf.seek(0)
218+
output = pickle.load(buf)
219+
self.assertEqual(output.find_bit(output.qubits[1]).index, 1)
220+
self.assertEqual(output.find_bit(output.qubits[1]).registers, [])
221+
self.assertEqual(output.find_bit(output.clbits[0]).index, 0)
222+
self.assertEqual(output.find_bit(output.clbits[0]).registers, [])
223+
224+
def test_deepcopy_bit_locations_with_no_reg(self):
225+
"""Test bit locations with no registers preserved through deepcopy."""
226+
dag = DAGCircuit()
227+
qubits = [Qubit(), Qubit()]
228+
clbits = [Clbit()]
229+
dag.add_qubits(qubits)
230+
dag.add_clbits(clbits)
231+
self.assertEqual(dag.find_bit(dag.qubits[1]).index, 1)
232+
self.assertEqual(dag.find_bit(dag.qubits[1]).registers, [])
233+
self.assertEqual(dag.find_bit(dag.clbits[0]).index, 0)
234+
self.assertEqual(dag.find_bit(dag.clbits[0]).registers, [])
235+
output = copy.deepcopy(dag)
236+
self.assertEqual(output.find_bit(output.qubits[1]).index, 1)
237+
self.assertEqual(output.find_bit(output.qubits[1]).registers, [])
238+
self.assertEqual(output.find_bit(output.clbits[0]).index, 0)
239+
self.assertEqual(output.find_bit(output.clbits[0]).registers, [])
240+
164241
def test_add_reg_duplicate(self):
165242
"""add_qreg with the same register twice is not allowed."""
166243
dag = DAGCircuit()

0 commit comments

Comments
 (0)