From c8afd6854e0bf2b8dabb80880c7266e6f1a9e624 Mon Sep 17 00:00:00 2001 From: "Stefan J. Wernli" Date: Fri, 12 May 2023 13:02:12 -0700 Subject: [PATCH] Fixes for simulator qubit management (#303) This change includes two bugfixes: - Evaluator now checks for qubit argument uniques on intrinsic gate invocation to avoid triggering a panic in the simulator (treated instead as a runtime error). - Updates to a simulator package with the bug fix for dumping state after a swap of two qubits where one has been released (see https://github.com/qir-alliance/qir-runner/pull/67) --- Cargo.lock | 4 +- compiler/qsc_eval/Cargo.toml | 4 +- compiler/qsc_eval/src/intrinsic.rs | 6 ++ compiler/qsc_eval/src/intrinsic/tests.rs | 98 ++++++++++++++++++++++++ compiler/qsc_eval/src/lib.rs | 3 + 5 files changed, 111 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a8c610052..3a0769e07a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -759,7 +759,7 @@ dependencies = [ [[package]] name = "qir-backend" version = "0.3.0" -source = "git+https://github.com/qir-alliance/qir-runner?rev=617fa33e0966579c3ef5cf55ce20c7d2d76c09a7#617fa33e0966579c3ef5cf55ce20c7d2d76c09a7" +source = "git+https://github.com/qir-alliance/qir-runner?rev=7141d6ebc0a573dfe2871a362b46d98dfe6f751c#7141d6ebc0a573dfe2871a362b46d98dfe6f751c" dependencies = [ "bitvec", "ndarray", @@ -774,7 +774,7 @@ dependencies = [ [[package]] name = "qir-stdlib" version = "0.3.0" -source = "git+https://github.com/qir-alliance/qir-runner?rev=617fa33e0966579c3ef5cf55ce20c7d2d76c09a7#617fa33e0966579c3ef5cf55ce20c7d2d76c09a7" +source = "git+https://github.com/qir-alliance/qir-runner?rev=7141d6ebc0a573dfe2871a362b46d98dfe6f751c#7141d6ebc0a573dfe2871a362b46d98dfe6f751c" dependencies = [ "num-bigint", "rand", diff --git a/compiler/qsc_eval/Cargo.toml b/compiler/qsc_eval/Cargo.toml index abacd4d552..f3c98f3df4 100644 --- a/compiler/qsc_eval/Cargo.toml +++ b/compiler/qsc_eval/Cargo.toml @@ -12,8 +12,8 @@ license.workspace = true miette = { workspace = true } num-bigint = { workspace = true } num-complex = { workspace = true } -qir-backend = { git = "https://github.com/qir-alliance/qir-runner", rev = "617fa33e0966579c3ef5cf55ce20c7d2d76c09a7" } -qir-stdlib = { git = "https://github.com/qir-alliance/qir-runner", rev = "617fa33e0966579c3ef5cf55ce20c7d2d76c09a7" } +qir-backend = { git = "https://github.com/qir-alliance/qir-runner", rev = "7141d6ebc0a573dfe2871a362b46d98dfe6f751c" } +qir-stdlib = { git = "https://github.com/qir-alliance/qir-runner", rev = "7141d6ebc0a573dfe2871a362b46d98dfe6f751c" } qsc_data_structures = { path = "../qsc_data_structures" } qsc_hir = { path = "../qsc_hir" } rand = { workspace = true } diff --git a/compiler/qsc_eval/src/intrinsic.rs b/compiler/qsc_eval/src/intrinsic.rs index 04599d54af..e1ee2566ab 100644 --- a/compiler/qsc_eval/src/intrinsic.rs +++ b/compiler/qsc_eval/src/intrinsic.rs @@ -166,6 +166,9 @@ fn invoke_quantum_intrinsic( $(stringify!($op2) => { match args.try_into_tuple().with_span(args_span)?.as_ref() { [x, y] => { + if x == y { + return Break(Reason::Error(Error::QubitUniqueness(args_span))); + } $op2( x.clone().try_into().with_span(args_span)?, y.clone().try_into().with_span(args_span)?, @@ -178,6 +181,9 @@ fn invoke_quantum_intrinsic( $(stringify!($op3) => { match args.try_into_tuple().with_span(args_span)?.as_ref() { [x, y, z] => { + if x == y || y == z || x == z { + return Break(Reason::Error(Error::QubitUniqueness(args_span))); + } $op3( x.clone().try_into().with_span(args_span)?, y.clone().try_into().with_span(args_span)?, diff --git a/compiler/qsc_eval/src/intrinsic/tests.rs b/compiler/qsc_eval/src/intrinsic/tests.rs index 33794e7c52..d20c470744 100644 --- a/compiler/qsc_eval/src/intrinsic/tests.rs +++ b/compiler/qsc_eval/src/intrinsic/tests.rs @@ -882,3 +882,101 @@ fn qubit_release_non_zero_failure() { "#]], ); } + +#[test] +fn qubit_not_unique_two_qubit_error() { + check_intrinsic_output( + "", + indoc! {"{ + use q = Qubit(); + CNOT(q , q); + }"}, + &expect![[r#" + QubitUniqueness( + Span { + lo: 32166, + hi: 32183, + }, + ) + "#]], + ); +} + +#[test] +fn qubit_not_unique_two_qubit_rotation_error() { + check_intrinsic_output( + "", + indoc! {"{ + use q = Qubit(); + Rxx(0.1, q, q); + }"}, + &expect![[r#" + QubitUniqueness( + Span { + lo: 45069, + hi: 45092, + }, + ) + "#]], + ); +} + +#[test] +fn qubit_not_unique_three_qubit_error_first_second() { + check_intrinsic_output( + "", + indoc! {"{ + use q = Qubit(); + use a = Qubit(); + CCNOT(q , q, a); + }"}, + &expect![[r#" + QubitUniqueness( + Span { + lo: 31122, + hi: 31150, + }, + ) + "#]], + ); +} + +#[test] +fn qubit_not_unique_three_qubit_error_first_third() { + check_intrinsic_output( + "", + indoc! {"{ + use q = Qubit(); + use a = Qubit(); + CCNOT(q , a, q); + }"}, + &expect![[r#" + QubitUniqueness( + Span { + lo: 31122, + hi: 31150, + }, + ) + "#]], + ); +} + +#[test] +fn qubit_not_unique_three_qubit_error_second_third() { + check_intrinsic_output( + "", + indoc! {"{ + use q = Qubit(); + use a = Qubit(); + CCNOT(a , q, q); + }"}, + &expect![[r#" + QubitUniqueness( + Span { + lo: 31122, + hi: 31150, + }, + ) + "#]], + ); +} diff --git a/compiler/qsc_eval/src/lib.rs b/compiler/qsc_eval/src/lib.rs index 14174a38d4..b0b2b28517 100644 --- a/compiler/qsc_eval/src/lib.rs +++ b/compiler/qsc_eval/src/lib.rs @@ -85,6 +85,9 @@ pub enum Error { #[error("output failure")] Output(#[label("failed to generate output")] Span), + #[error("qubits in gate invocation are not unique")] + QubitUniqueness(#[label] Span), + #[error("range with step size of zero")] RangeStepZero(#[label("invalid range")] Span),