Skip to content

Commit

Permalink
Support Adjoint of Relabel
Browse files Browse the repository at this point in the history
This change adds one layer of indirection in the library implementation of `Relabel` so that the operation can be adjointable. The adjoint is just a switch of the qubit arrays such that `Adjoint Relabel(current, updated)` is the same as `Relabel(updated, current)`.
  • Loading branch information
swernli committed Sep 16, 2024
1 parent 7b532fe commit 1b08403
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 5 deletions.
2 changes: 1 addition & 1 deletion compiler/qsc_eval/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub(crate) fn call(
Err(_) => Err(Error::OutputFail(name_span)),
}
}
"Relabel" => qubit_relabel(arg, arg_span, |q0, q1| sim.qubit_swap_id(q0, q1)),
"PermuteLabels" => qubit_relabel(arg, arg_span, |q0, q1| sim.qubit_swap_id(q0, q1)),
"Message" => match out.message(&arg.unwrap_string()) {
Ok(()) => Ok(Value::unit()),
Err(_) => Err(Error::OutputFail(name_span)),
Expand Down
4 changes: 2 additions & 2 deletions compiler/qsc_eval/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3724,7 +3724,7 @@ fn controlled_operation_with_duplicate_controls_fails() {
1,
),
item: LocalItemId(
131,
132,
),
},
caller: PackageId(
Expand Down Expand Up @@ -3774,7 +3774,7 @@ fn controlled_operation_with_target_in_controls_fails() {
1,
),
item: LocalItemId(
131,
132,
),
},
caller: PackageId(
Expand Down
2 changes: 1 addition & 1 deletion compiler/qsc_partial_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ impl<'a> PartialEvaluator<'a> {
// Qubit allocations and measurements have special handling.
"__quantum__rt__qubit_allocate" => Ok(self.allocate_qubit()),
"__quantum__rt__qubit_release" => Ok(self.release_qubit(args_value)),
"Relabel" => qubit_relabel(args_value, args_span, |q0, q1| {
"PermuteLabels" => qubit_relabel(args_value, args_span, |q0, q1| {
self.resource_manager.swap_qubit_ids(Qubit(q0), Qubit(q1));
})
.map_err(std::convert::Into::into),
Expand Down
21 changes: 21 additions & 0 deletions library/src/tests/canon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,27 @@ fn check_relabel_four_qubit_shuffle_permutation() {
);
}

#[test]
fn check_relabel_adjoint_undoes_permutation() {
test_expression(
"{
use qs = Qubit[3];
// Prepare |01+⟩
X(qs[1]);
H(qs[2]);
Relabel([qs[0], qs[1], qs[2]], [qs[1], qs[2], qs[0]]);
// Expected state is |1+0⟩, perform part of the adjoint to correct one of the qubits.
X(qs[0]);
Adjoint Relabel([qs[0], qs[1], qs[2]], [qs[1], qs[2], qs[0]]);
// Expected state is now |00+⟩, perform the rest of the adjoint to get back to ground state,
// using the original qubit ids.
H(qs[2]);
// Qubit release will fail if the state is not |000⟩
}",
&Value::unit(),
);
}

#[test]
fn check_apply_cnot_chain_2() {
test_expression(
Expand Down
13 changes: 12 additions & 1 deletion library/std/src/canon.qs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,18 @@ namespace Microsoft.Quantum.Canon {
/// use (q0, q1) = (Qubit(), Qubit());
/// Relabel([q0, q1], [q1, q0]);
/// ```
operation Relabel(current : Qubit[], updated : Qubit[]) : Unit {
/// Note that the adjoint of this operation effectively changes the order of arguments, such that
/// `Adjoint Relabel(qubits, newOrder)` is equivalent to `Relabel(newOrder, qubits)`.
operation Relabel(current : Qubit[], updated : Qubit[]) : Unit is Adj {
body ... {
PermuteLabels(current, updated);
}
adjoint ... {
PermuteLabels(updated, current);
}
}

operation PermuteLabels(current : Qubit[], updated : Qubit[]) : Unit {
body intrinsic;
}

Expand Down

0 comments on commit 1b08403

Please sign in to comment.