Skip to content

Commit

Permalink
Relabel in adaptive conditional block should be disallowed
Browse files Browse the repository at this point in the history
This adds a check at codegen time if a qubit relabel is occurring in an adaptive conditional. This will ensure we don't generate QIR with incorrect qubit IDs. The change ties the error to the dynamic qubit capability because if/when we support dynamic qubits we'll need to update relabel to become an intrinsic that is supported by backends to do a runtime relabel of qubit identifiers.

Fixes #2152
  • Loading branch information
swernli committed Feb 4, 2025
1 parent acd1890 commit 235b8d7
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 3 deletions.
7 changes: 7 additions & 0 deletions compiler/qsc_partial_eval/src/evaluation_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ impl EvaluationContext {
pub fn push_scope(&mut self, s: Scope) {
self.scopes.push(s);
}

/// Determines whether we are currently in a dynamic branch context for any scope.
pub fn is_currently_evaluating_any_branch(&self) -> bool {
self.scopes
.iter()
.any(Scope::is_currently_evaluating_branch)
}
}

/// Struct that represents a block node when we intepret an RIR program as a graph.
Expand Down
15 changes: 12 additions & 3 deletions compiler/qsc_partial_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1583,9 +1583,18 @@ 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)),
"PermuteLabels" => qubit_relabel(args_value, args_span, |q0, q1| {
self.resource_manager.swap_qubit_ids(q0, q1);
})
"PermuteLabels" => {
if self.eval_context.is_currently_evaluating_any_branch() {
// If we are in a dynamic branch anywhere up the call stack, we cannot support relabel,
// as later qubit usage would need to be dynamic on whether the branch was taken.
return Err(Error::CapabilityError(CapabilityError::UseOfDynamicQubit(
callee_expr_span.span,
)));
}
qubit_relabel(args_value, args_span, |q0, q1| {
self.resource_manager.swap_qubit_ids(q0, q1);
})
}
.map_err(std::convert::Into::into),
"__quantum__qis__m__body" => Ok(self.measure_qubit(builder::m_decl(), args_value)),
"__quantum__qis__mresetz__body" => {
Expand Down
20 changes: 20 additions & 0 deletions compiler/qsc_partial_eval/src/tests/qubits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,23 @@ fn qubit_double_release_triggers_runtime_error() {
]],
);
}

#[test]
fn qubit_relabel_in_dynamic_block_triggers_capability_error() {
let error = get_partial_evaluation_error(indoc! {
r#"
operation Main() : Result {
use qs = Qubit[2];
if M(qs[0]) == One {
Relabel(qs, Std.Arrays.Reversed(qs));
}
MResetZ(qs[1])
}
"#,
});

assert_error(
&error,
&expect!["CapabilityError(UseOfDynamicQubit(Span { lo: 59760, hi: 59773 }))"],
);
}

0 comments on commit 235b8d7

Please sign in to comment.