diff --git a/compiler/qsc_eval/src/intrinsic.rs b/compiler/qsc_eval/src/intrinsic.rs index 711f34de19..4d2b2e5ebb 100644 --- a/compiler/qsc_eval/src/intrinsic.rs +++ b/compiler/qsc_eval/src/intrinsic.rs @@ -392,14 +392,14 @@ pub fn qubit_relabel( } (false, true) => { // The right qubit has been relabeled, so we need to swap the left qubit with the - // qubit that the right qubit was relabeled to. - let mapped = *map + // new label for the right qubit. + let label = *map .keys() .find(|k| map[*k] == r) .expect("mapped qubit should be present as both key and value"); - swap(l, mapped); + swap(l, label); map.insert(l, r); - map.insert(mapped, l); + map.insert(label, l); } (true, false) => { // The left qubit has been relabeled, so we swap the qubits as normal but @@ -410,14 +410,21 @@ pub fn qubit_relabel( map.insert(r, mapped); } (true, true) => { - // Both qubits have been relabeled, so we need to swap the mapped right qubit with + // Both qubits have been relabeled, so we need to swap new label for the right qubit with // the left qubit and remember the new mapping of both qubits. + // This is effectively a combination of the second and third cases above. + let label_r = *map + .keys() + .find(|k| map[*k] == r) + .expect("mapped qubit should be present as both key and value"); let mapped_l = *map.get(&l).expect("mapped qubit should be present"); let mapped_r = *map.get(&r).expect("mapped qubit should be present"); + + // This swap is only necessary if the labels don't already point to each other. if mapped_l != r && mapped_r != l { - swap(mapped_r, l); - map.insert(mapped_r, mapped_l); - map.insert(l, r); + swap(label_r, l); + map.insert(label_r, mapped_l); + map.insert(l, mapped_r); } } } diff --git a/library/src/tests/canon.rs b/library/src/tests/canon.rs index 18d06bacc4..7133ebf22e 100644 --- a/library/src/tests/canon.rs +++ b/library/src/tests/canon.rs @@ -154,6 +154,78 @@ fn check_relabel_rotational_permutation_alternate_expression() { ); } +#[test] +fn check_relabel_rotational_permutation_size_4() { + test_expression( + "{ + use qs = Qubit[4]; + // Prepare |01+0⟩ + X(qs[1]); + H(qs[2]); + Relabel(qs, qs[2...] + qs[0..1]); + // Expected state is |+001⟩, perform adjoint to get back to ground state. + H(qs[0]); + X(qs[Length(qs)-1]); + // Qubit release will fail if the state is not |000⟩ + }", + &Value::unit(), + ); +} + +#[test] +fn check_relabel_rotational_permutation_size_5() { + test_expression( + "{ + use qs = Qubit[5]; + // Prepare |01+00⟩ + X(qs[1]); + H(qs[2]); + Relabel(qs, qs[2...] + qs[0..1]); + // Expected state is |+0001⟩, perform adjoint to get back to ground state. + H(qs[0]); + X(qs[Length(qs)-1]); + // Qubit release will fail if the state is not |000⟩ + }", + &Value::unit(), + ); +} + +#[test] +fn check_relabel_rotational_permutation_size_6() { + test_expression( + "{ + use qs = Qubit[6]; + // Prepare |01+000⟩ + X(qs[1]); + H(qs[2]); + Relabel(qs, qs[2...] + qs[0..1]); + // Expected state is |+00001⟩, perform adjoint to get back to ground state. + H(qs[0]); + X(qs[Length(qs)-1]); + // Qubit release will fail if the state is not |000⟩ + }", + &Value::unit(), + ); +} + +#[test] +fn check_relabel_rotational_permutation_size_7() { + test_expression( + "{ + use qs = Qubit[7]; + // Prepare |01+0000⟩ + X(qs[1]); + H(qs[2]); + Relabel(qs, qs[2...] + qs[0..1]); + // Expected state is |+000001⟩, perform adjoint to get back to ground state. + H(qs[0]); + X(qs[Length(qs)-1]); + // Qubit release will fail if the state is not |000⟩ + }", + &Value::unit(), + ); +} + #[test] fn check_relabel_four_qubit_shuffle_permutation() { test_expression( @@ -162,12 +234,44 @@ fn check_relabel_four_qubit_shuffle_permutation() { // Prepare |01+i⟩ X(qs[1]); H(qs[2]); - Y(qs[3]); + H(qs[3]); + S(qs[3]); + H(qs[3]); Relabel([qs[0], qs[1], qs[2], qs[3]], [qs[1], qs[0], qs[3], qs[2]]); // Expected state is |10i+⟩, perform adjoint to get back to ground state. X(qs[0]); - Y(qs[2]); + H(qs[2]); + Adjoint S(qs[2]); + H(qs[2]); + H(qs[3]); + // Qubit release will fail if the state is not |0000⟩ + }", + &Value::unit(), + ); +} + +#[test] +fn check_relabel_five_qubit_shuffle_permutation() { + test_expression( + "{ + use qs = Qubit[5]; + // Prepare |01+i-⟩ + X(qs[1]); + H(qs[2]); + H(qs[3]); + S(qs[3]); + H(qs[3]); + H(qs[4]); + Z(qs[4]); + Relabel([qs[0], qs[1], qs[2], qs[3], qs[4]], [qs[1], qs[0], qs[3], qs[4], qs[2]]); + // Expected state is |10i-+⟩, perform adjoint to get back to ground state. + X(qs[0]); + H(qs[2]); + Adjoint S(qs[2]); + H(qs[2]); + Z(qs[3]); H(qs[3]); + H(qs[4]); // Qubit release will fail if the state is not |0000⟩ }", &Value::unit(),