Skip to content

Commit 740c492

Browse files
authored
Simplify Relabel logic (#2085)
This simplifies the relabeling logic to collapse the four match cases down into one for easier readibility. It avoids trying to optimize special cases for qubits that may not have been mapped and treats all labels as having an intial mapping to themselves. Based on feedback from @DmitryVasilevsky in #2082 (comment)
1 parent d7f8962 commit 740c492

File tree

1 file changed

+19
-45
lines changed

1 file changed

+19
-45
lines changed

compiler/qsc_eval/src/intrinsic.rs

Lines changed: 19 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -377,56 +377,30 @@ pub fn qubit_relabel(
377377
return Err(Error::RelabelingMismatch(arg_span));
378378
}
379379

380-
let mut map = FxHashMap::default();
381-
map.reserve(left.len());
380+
// Start with a mapping of each qubit to itself.
381+
let mut mappings: FxHashMap<usize, usize> =
382+
left.iter().copied().zip(left.iter().copied()).collect();
382383
for (l, r) in left.into_iter().zip(right.into_iter()) {
384+
// Trivial case where the qubit is already mapped to itself in the relabel, which can be short circuited.
383385
if l == r {
384386
continue;
385387
}
386-
match (map.contains_key(&l), map.contains_key(&r)) {
387-
(false, false) => {
388-
// Neither qubit has been relabeled yet.
389-
swap(l, r);
390-
map.insert(l, r);
391-
map.insert(r, l);
392-
}
393-
(false, true) => {
394-
// The right qubit has been relabeled, so we need to swap the left qubit with the
395-
// new label for the right qubit.
396-
let label = *map
397-
.keys()
398-
.find(|k| map[*k] == r)
399-
.expect("mapped qubit should be present as both key and value");
400-
swap(l, label);
401-
map.insert(l, r);
402-
map.insert(label, l);
403-
}
404-
(true, false) => {
405-
// The left qubit has been relabeled, so we swap the qubits as normal but
406-
// remember the new mapping of the right qubit.
407-
let mapped = *map.get(&l).expect("mapped qubit should be present");
408-
swap(l, r);
409-
map.insert(l, r);
410-
map.insert(r, mapped);
411-
}
412-
(true, true) => {
413-
// Both qubits have been relabeled, so we need to swap new label for the right qubit with
414-
// the left qubit and remember the new mapping of both qubits.
415-
// This is effectively a combination of the second and third cases above.
416-
let label_r = *map
417-
.keys()
418-
.find(|k| map[*k] == r)
419-
.expect("mapped qubit should be present as both key and value");
420-
let mapped_l = *map.get(&l).expect("mapped qubit should be present");
421-
let mapped_r = *map.get(&r).expect("mapped qubit should be present");
422388

423-
// This swap is only necessary if the labels don't already point to each other.
424-
if mapped_l != r && mapped_r != l {
425-
swap(label_r, l);
426-
map.insert(label_r, mapped_l);
427-
map.insert(l, mapped_r);
428-
}
429-
}
389+
// Check what each label currently maps to.
390+
let mapped_l = *mappings.get(&l).expect("mapped qubit should be present");
391+
let mapped_r = *mappings.get(&r).expect("mapped qubit should be present");
392+
393+
// We only need to swap if the label is not pointing to the correct qubit.
394+
if mapped_l != r && mapped_r != l {
395+
// Do a reverse lookup to find which label is currently mapped to the desired right qubit.
396+
// This tells us which label to use in the swap, which we will use in the update of the mappings too.
397+
let label_r = *mappings
398+
.keys()
399+
.find(|k| mappings[*k] == r)
400+
.expect("mapped qubit should be present as both key and value");
401+
swap(l, label_r);
402+
mappings.insert(label_r, mapped_l);
403+
mappings.insert(l, mapped_r);
430404
}
431405
}
432406

0 commit comments

Comments
 (0)