From 7f6e30275b17b0575438b8af9c51be07eaa49d9f Mon Sep 17 00:00:00 2001 From: Alex Hansen Date: Tue, 17 Sep 2024 13:10:06 -0700 Subject: [PATCH] Migrate the standard library to the project system (#1912) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR migrates the standard library into a Q# project structure. Previously, we provided the modern standard library API via re-export, while the "true" stdlib was defined in the old explicit-namespace style. Now, that is inverted: the stdlib's code is housed in a project with implicit namespaces, and the legacy (`Microsoft.Quantum.____`) API is provided via re-exports. Why do this? Well, for one, the standard library should look like a regular library and use the latest features we have. Secondarily, auto-imports and other language dev tools now refer to these items by their `Std.__` name, not their `Microsoft.Quantum.__` name. See the video below for an example of this in completions: https://github.com/user-attachments/assets/fa96e5b7-0cca-4a44-9224-7742d50f8370 Go-to def rendering the new paths: https://github.com/user-attachments/assets/5fea33ec-9478-4c16-9e78-b8f8b1420ed0 Note that `Unstable.*` has not been migrated to the modern API, as we want to explore stabilizing state preparation (#1910) Core is also not included, but for different reasons: #1911. Coming in a Follow Up PR™️ (`alex/1911` if you want to preview the work there) --- compiler/qsc/benches/eval.rs | 2 +- compiler/qsc/benches/large.qs | 4 +- compiler/qsc/src/codegen/tests.rs | 6 +- compiler/qsc/src/interpret/circuit_tests.rs | 20 +- compiler/qsc/src/interpret/tests.rs | 16 +- compiler/qsc/src/location.rs | 2 +- compiler/qsc_codegen/src/qsharp.rs | 9 +- compiler/qsc_codegen/src/qsharp/tests.rs | 24 +- .../qsc_data_structures/src/namespaces.rs | 12 +- .../src/namespaces/tests.rs | 115 +- compiler/qsc_eval/src/intrinsic/tests.rs | 2 +- compiler/qsc_formatter/src/formatter/tests.rs | 6 +- compiler/qsc_frontend/src/compile/tests.rs | 12 +- .../qsc_frontend/src/incremental/tests.rs | 4 +- compiler/qsc_frontend/src/resolve.rs | 2 +- compiler/qsc_frontend/src/resolve/tests.rs | 656 ++++---- compiler/qsc_frontend/src/typeck/tests.rs | 32 +- compiler/qsc_partial_eval/src/tests/calls.rs | 16 +- .../qsc_partial_eval/src/tests/intrinsics.rs | 24 +- compiler/qsc_partial_eval/src/tests/misc.rs | 4 +- .../qsc_partial_eval/src/tests/returns.rs | 16 +- .../src/capabilitiesck/tests_adaptive.rs | 80 +- .../tests_adaptive_plus_integers.rs | 56 +- .../src/capabilitiesck/tests_base.rs | 112 +- .../src/capabilitiesck/tests_common.rs | 34 +- compiler/qsc_rca/src/tests/arrays.rs | 6 +- compiler/qsc_rca/src/tests/assigns.rs | 26 +- compiler/qsc_rca/src/tests/bindings.rs | 10 +- compiler/qsc_rca/src/tests/binops.rs | 2 +- compiler/qsc_rca/src/tests/callables.rs | 8 +- compiler/qsc_rca/src/tests/calls.rs | 8 +- compiler/qsc_rca/src/tests/cycles.rs | 2 +- compiler/qsc_rca/src/tests/ifs.rs | 4 +- compiler/qsc_rca/src/tests/measurements.rs | 6 +- compiler/qsc_rca/src/tests/structs.rs | 10 +- compiler/qsc_rca/src/tests/types.rs | 10 +- compiler/qsc_rca/src/tests/udts.rs | 8 +- compiler/qsc_rca/src/tests/vars.rs | 2 +- fuzz/seed_inputs/compile/input.qs | 32 +- language_service/src/completion.rs | 4 +- language_service/src/completion/tests.rs | 2 +- library/fixed_point/qsharp.json | 9 +- library/src/lib.rs | 60 +- library/src/tests.rs | 8 +- library/src/tests/arithmetic.rs | 46 +- library/src/tests/convert.rs | 4 +- library/src/tests/diagnostics.rs | 4 +- library/src/tests/math.rs | 76 +- library/src/tests/resources/src/add_le.qs | 6 +- library/src/tests/resources/src/compare.qs | 6 +- library/src/tests/resources/src/inc_by_le.qs | 6 +- library/src/tests/resources/src/qft_le.qs | 4 +- library/src/tests/resources/src/select.qs | 10 +- .../tests/resources/src/state_preparation.qs | 12 +- library/src/tests/state_preparation.rs | 2 +- library/std/qsharp.json | 30 +- library/std/src/QIR/Intrinsic.qs | 126 ++ library/std/src/Std/Arrays.qs | 1442 ++++++++++++++++ library/std/src/Std/Canon.qs | 650 ++++++++ library/std/src/Std/Convert.qs | 284 ++++ library/std/src/Std/Diagnostics.qs | 332 ++++ library/std/src/Std/InternalHelpers.qs | 250 +++ library/std/src/Std/Intrinsic.qs | 1129 +++++++++++++ library/std/src/Std/Logical.qs | 31 + library/std/src/Std/Math.qs | 1466 +++++++++++++++++ library/std/src/Std/Measurement.qs | 179 ++ library/std/src/Std/Random.qs | 74 + library/std/src/Std/ResourceEstimation.qs | 183 ++ library/std/src/arrays.qs | 1444 ---------------- library/std/src/canon.qs | 633 ------- library/std/src/convert.qs | 288 ---- library/std/src/diagnostics.qs | 336 ---- library/std/src/internal.qs | 250 --- library/std/src/intrinsic.qs | 1158 ------------- library/std/src/legacy_api.qs | 15 + library/std/src/logical.qs | 32 - library/std/src/math.qs | 1455 ---------------- library/std/src/measurement.qs | 186 --- library/std/src/modern_api.qs | 20 - library/std/src/qir.qs | 105 -- library/std/src/random.qs | 77 - library/std/src/re.qs | 182 -- library/std/src/unstable_arithmetic.qs | 8 +- .../std/src/unstable_arithmetic_internal.qs | 8 +- library/std/src/unstable_state_preparation.qs | 8 +- library/std/src/unstable_table_lookup.qs | 12 +- npm/qsharp/test/basics.js | 13 +- pip/README.md | 2 +- .../resources/ArithmeticOps.qs | 4 +- .../resources/BernsteinVaziraniNISQ.qs | 12 +- .../resources/ConstantFolding.qs | 6 +- .../resources/CopyAndUpdateExpressions.qs | 4 +- .../resources/DeutschJozsaNISQ.qs | 4 +- .../resources/ExpandedTests.qs | 12 +- pip/tests-integration/resources/Functors.qs | 4 +- .../resources/HiddenShiftNISQ.qs | 10 +- .../resources/IntegerComparison.qs | 2 +- .../resources/IntrinsicCCNOT.qs | 4 +- .../resources/IntrinsicCNOT.qs | 4 +- .../resources/IntrinsicHIXYZ.qs | 4 +- pip/tests-integration/resources/IntrinsicM.qs | 4 +- .../IntrinsicMeasureWithBitFlipCode.qs | 4 +- .../IntrinsicMeasureWithPhaseFlipCode.qs | 4 +- .../resources/IntrinsicRotationsWithPeriod.qs | 6 +- .../resources/IntrinsicSTSWAP.qs | 4 +- .../resources/MeasureAndReuse.qs | 4 +- .../resources/MeasurementComparison.qs | 4 +- .../resources/NestedBranching.qs | 6 +- pip/tests-integration/resources/RandomBit.qs | 2 +- .../resources/SampleTeleport.qs | 6 +- .../resources/ShortcuttingMeasurement.qs | 2 +- pip/tests-integration/resources/Slicing.qs | 6 +- .../resources/SwitchHandling.qs | 6 +- .../resources/ThreeQubitRepetitionCode.qs | 4 +- .../resources/WithinApply.qs | 4 +- pip/tests/test_interpreter.py | 4 +- pip/tests/test_re.py | 2 +- resource_estimator/src/counts/tests.rs | 6 +- samples/algorithms/BellState.qs | 4 +- samples/algorithms/BernsteinVazirani.qs | 10 +- samples/algorithms/BernsteinVaziraniNISQ.qs | 10 +- samples/algorithms/BitFlipCode.qs | 10 +- samples/algorithms/CatState.qs | 2 +- samples/algorithms/DeutschJozsa.qs | 6 +- samples/algorithms/DeutschJozsaNISQ.qs | 2 +- .../DotProductViaPhaseEstimation.qs | 4 +- samples/algorithms/Entanglement.qs | 2 +- samples/algorithms/GHZ.qs | 2 +- samples/algorithms/Grover.qs | 10 +- samples/algorithms/HiddenShift.qs | 8 +- samples/algorithms/HiddenShiftNISQ.qs | 8 +- samples/algorithms/JointMeasurement.qs | 2 +- samples/algorithms/Measurement.qs | 2 +- samples/algorithms/PhaseFlipCode.qs | 10 +- samples/algorithms/QRNG.qs | 6 +- samples/algorithms/QRNGNISQ.qs | 4 +- samples/algorithms/Shor.qs | 12 +- samples/algorithms/Teleportation.qs | 6 +- .../algorithms/ThreeQubitRepetitionCode.qs | 4 +- samples/estimation/Dynamics.qs | 4 +- samples/estimation/EkeraHastadFactoring.qs | 12 +- samples/estimation/Precalculated.qs | 2 +- samples/estimation/ShorRE.qs | 18 +- .../df-chemistry/src/df_chemistry.qs | 16 +- .../estimation/df-chemistry/src/prepare.qs | 14 +- .../src/GenerateRandomNumbers.qs | 4 +- samples/testing/operations/src/BellState.qs | 2 +- .../operations/src/OperationEquivalence.qs | 2 +- vscode/src/notebookTemplate.ts | 2 +- vscode/test/suites/debugger/debugger.test.ts | 14 +- wasm/src/tests.rs | 10 +- 151 files changed, 7221 insertions(+), 7218 deletions(-) create mode 100644 library/std/src/QIR/Intrinsic.qs create mode 100644 library/std/src/Std/Arrays.qs create mode 100644 library/std/src/Std/Canon.qs create mode 100644 library/std/src/Std/Convert.qs create mode 100644 library/std/src/Std/Diagnostics.qs create mode 100644 library/std/src/Std/InternalHelpers.qs create mode 100644 library/std/src/Std/Intrinsic.qs create mode 100644 library/std/src/Std/Logical.qs create mode 100644 library/std/src/Std/Math.qs create mode 100644 library/std/src/Std/Measurement.qs create mode 100644 library/std/src/Std/Random.qs create mode 100644 library/std/src/Std/ResourceEstimation.qs delete mode 100644 library/std/src/arrays.qs delete mode 100644 library/std/src/canon.qs delete mode 100644 library/std/src/convert.qs delete mode 100644 library/std/src/diagnostics.qs delete mode 100644 library/std/src/internal.qs delete mode 100644 library/std/src/intrinsic.qs create mode 100644 library/std/src/legacy_api.qs delete mode 100644 library/std/src/logical.qs delete mode 100644 library/std/src/math.qs delete mode 100644 library/std/src/measurement.qs delete mode 100644 library/std/src/modern_api.qs delete mode 100644 library/std/src/qir.qs delete mode 100644 library/std/src/random.qs delete mode 100644 library/std/src/re.qs diff --git a/compiler/qsc/benches/eval.rs b/compiler/qsc/benches/eval.rs index 033a8a9b3f..884c2d856b 100644 --- a/compiler/qsc/benches/eval.rs +++ b/compiler/qsc/benches/eval.rs @@ -175,7 +175,7 @@ pub fn large_nested_iteration(c: &mut Criterion) { [("none".into(), "".into())], Some( indoc! {"{ - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; mutable arr = [[0, size = 100], size = 1000]; for i in IndexRange(arr) { mutable inner = arr[i]; diff --git a/compiler/qsc/benches/large.qs b/compiler/qsc/benches/large.qs index bbf65c63bf..1f0d999dc2 100644 --- a/compiler/qsc/benches/large.qs +++ b/compiler/qsc/benches/large.qs @@ -2,8 +2,8 @@ // Licensed under the MIT License. namespace Large { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; operation ThousandQubitsParityX(qs : Qubit[]) : Result { mutable res = Zero; diff --git a/compiler/qsc/src/codegen/tests.rs b/compiler/qsc/src/codegen/tests.rs index c313d838e5..c17b5547c1 100644 --- a/compiler/qsc/src/codegen/tests.rs +++ b/compiler/qsc/src/codegen/tests.rs @@ -69,7 +69,7 @@ mod base_profile { #[test] fn simple() { let source = "namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; open QIR.Intrinsic; @EntryPoint() operation Main() : Result { @@ -393,7 +393,7 @@ mod adaptive_profile { #[test] fn simple() { let source = "namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; open QIR.Intrinsic; @EntryPoint() operation Main() : Result { @@ -608,7 +608,7 @@ mod adaptive_ri_profile { #[test] fn simple() { let source = "namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; open QIR.Intrinsic; @EntryPoint() operation Main() : Result { diff --git a/compiler/qsc/src/interpret/circuit_tests.rs b/compiler/qsc/src/interpret/circuit_tests.rs index 6a55f4dd60..9de00e3d7b 100644 --- a/compiler/qsc/src/interpret/circuit_tests.rs +++ b/compiler/qsc/src/interpret/circuit_tests.rs @@ -158,7 +158,7 @@ fn m_base_profile() { let mut interpreter = interpreter( r" namespace Test { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { use q = Qubit(); @@ -187,7 +187,7 @@ fn m_unrestricted_profile() { let mut interpreter = interpreter( r" namespace Test { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { use q = Qubit(); @@ -215,7 +215,7 @@ fn mresetz_unrestricted_profile() { let mut interpreter = interpreter( r" namespace Test { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { use q = Qubit(); @@ -243,7 +243,7 @@ fn mresetz_base_profile() { let mut interpreter = interpreter( r" namespace Test { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { use q = Qubit(); @@ -271,7 +271,7 @@ fn unrestricted_profile_result_comparison() { let mut interpreter = interpreter( r" namespace Test { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { use q1 = Qubit(); @@ -439,7 +439,7 @@ fn custom_intrinsic_mixed_args() { let mut interpreter = interpreter( r" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; @EntryPoint() operation Main() : Unit { @@ -555,7 +555,7 @@ fn operation_with_qubit_arrays() { @EntryPoint() operation Main() : Result[] { [] } - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; operation Test(q1: Qubit[], q2: Qubit[][], q3: Qubit[][][], q: Qubit) : Result[] { for q in q1 { H(q); @@ -925,7 +925,7 @@ mod debugger_stepping { let circs = generate_circuit_steps( r" namespace Test { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { use q = Qubit(); @@ -974,7 +974,7 @@ mod debugger_stepping { let circs = generate_circuit_steps( r" namespace Test { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { use q = Qubit(); @@ -1012,7 +1012,7 @@ mod debugger_stepping { let circs = generate_circuit_steps( r" namespace Test { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { use q = Qubit(); diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs index 64eb45b3bb..5f5421568c 100644 --- a/compiler/qsc/src/interpret/tests.rs +++ b/compiler/qsc/src/interpret/tests.rs @@ -263,7 +263,7 @@ mod given_interpreter { #[test] fn open_namespace() { let mut interpreter = get_interpreter(); - let (result, output) = line(&mut interpreter, "open Microsoft.Quantum.Diagnostics;"); + let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;"); is_only_value(&result, &output, &Value::unit()); let (result, output) = line(&mut interpreter, "DumpMachine()"); is_unit_with_output(&result, &output, "STATE:\n|0⟩: 1+0i"); @@ -328,7 +328,7 @@ mod given_interpreter { #[test] fn global_qubits() { let mut interpreter = get_interpreter(); - let (result, output) = line(&mut interpreter, "open Microsoft.Quantum.Diagnostics;"); + let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;"); is_only_value(&result, &output, &Value::unit()); let (result, output) = line(&mut interpreter, "DumpMachine()"); is_unit_with_output(&result, &output, "STATE:\n|0⟩: 1+0i"); @@ -453,7 +453,7 @@ mod given_interpreter { is_only_value(&result, &output, &Value::unit()); let (result, output) = line(&mut interpreter, "open Other;"); is_only_value(&result, &output, &Value::unit()); - let (result, output) = line(&mut interpreter, "open Microsoft.Quantum.Diagnostics;"); + let (result, output) = line(&mut interpreter, "import Std.Diagnostics.*;"); is_only_value(&result, &output, &Value::unit()); let (result, output) = line(&mut interpreter, "DumpMachine();"); is_only_error( @@ -463,7 +463,7 @@ mod given_interpreter { name error: `DumpMachine` could refer to the item in `Other` or `Microsoft.Quantum.Diagnostics` ambiguous name [line_3] [DumpMachine] found in this namespace [line_1] [Other] - and also in this namespace [line_2] [Microsoft.Quantum.Diagnostics] + and also in this namespace [line_2] [Std.Diagnostics] type error: insufficient type information to infer type [line_3] [DumpMachine()] "#]], @@ -479,7 +479,7 @@ mod given_interpreter { &output, &expect![[r#" runtime error: qubits in invocation are not unique - [qsharp-library-source:intrinsic.qs] [(control, target)] + [qsharp-library-source:Std/Intrinsic.qs] [(control, target)] "#]], ); } @@ -749,7 +749,7 @@ mod given_interpreter { &mut interpreter, indoc! {r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; open QIR.Intrinsic; @EntryPoint() operation Main() : Result { @@ -1552,7 +1552,7 @@ mod given_interpreter { fn debugger_execution_with_call_to_library_succeeds() { let source = indoc! { r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; @EntryPoint() operation Main() : Int { Binom(31, 7) @@ -1579,7 +1579,7 @@ mod given_interpreter { fn debugger_execution_with_early_return_succeeds() { let source = indoc! { r#" namespace Test { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; operation Max20(i : Int) : Int { if (i > 20) { diff --git a/compiler/qsc/src/location.rs b/compiler/qsc/src/location.rs index d9cda716ec..ee1cf261ab 100644 --- a/compiler/qsc/src/location.rs +++ b/compiler/qsc/src/location.rs @@ -72,7 +72,7 @@ mod tests { expect![[r#" Location { - source: "qsharp-library-source:arrays.qs", + source: "qsharp-library-source:Std/Arrays.qs", range: Range { start: Position { line: 0, diff --git a/compiler/qsc_codegen/src/qsharp.rs b/compiler/qsc_codegen/src/qsharp.rs index 0c507bb3b9..3a07e96ef7 100644 --- a/compiler/qsc_codegen/src/qsharp.rs +++ b/compiler/qsc_codegen/src/qsharp.rs @@ -162,19 +162,26 @@ impl Visitor<'_> for QSharpGen { ImportOrExportItem { ref path, ref is_glob, - .. + ref alias, }, ) in decl.items.iter().enumerate() { let is_last = ix == decl.items.len() - 1; self.visit_path(path); + if *is_glob { self.write(".*"); } + + if let Some(ref alias) = alias { + self.write(&format!(" as {}", alias.name)); + } + if !is_last { self.write(", "); }; } + self.write(";"); } } diff --git a/compiler/qsc_codegen/src/qsharp/tests.rs b/compiler/qsc_codegen/src/qsharp/tests.rs index 4e27d41bcd..15f457907e 100644 --- a/compiler/qsc_codegen/src/qsharp/tests.rs +++ b/compiler/qsc_codegen/src/qsharp/tests.rs @@ -40,10 +40,10 @@ fn open() { check( indoc! {r#" namespace Sample { - open Microsoft.Quantum.Intrinsic as sics; + import Std.Intrinsic as sics; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Intrinsic as intrin; + import Std.Diagnostics.*; + import Std.Intrinsic as intrin; @EntryPoint() operation Entry() : Unit { } @@ -51,9 +51,9 @@ fn open() { None, &expect![[r#" namespace Sample { - open Microsoft.Quantum.Intrinsic as sics; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Intrinsic as intrin; + import Std.Intrinsic as sics; + import Std.Diagnostics.*; + import Std.Intrinsic as intrin; @EntryPoint() operation Entry() : Unit {} }"#]], @@ -472,7 +472,7 @@ fn lambda_fns() { check( indoc! {r#" namespace A { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; operation B() : Unit { let add = (x, y) -> x + y; let intArray = [1, 2, 3, 4, 5]; @@ -501,7 +501,7 @@ fn lambda_fns() { None, &expect![[r#" namespace A { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; operation B() : Unit { let add = (x, y) -> x + y; let intArray = [1, 2, 3, 4, 5]; @@ -534,7 +534,7 @@ fn ranges() { check( indoc! {r#" namespace A { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; operation B() : Unit { let range = 1..3; let range = 2..2..5; @@ -558,7 +558,7 @@ fn ranges() { None, &expect![[r#" namespace A { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; operation B() : Unit { let range = 1..3; let range = 2..2..5; @@ -620,7 +620,7 @@ fn field_access_and_string_interning() { check( indoc! {r#" namespace A { - open Microsoft.Quantum.Math; + import Std.Math.*; function ComplexAsString(x : Complex) : String { if x.Imag < 0.0 { $"{x.Real} - {AbsD(x.Imag)}i" @@ -632,7 +632,7 @@ fn field_access_and_string_interning() { None, &expect![[r#" namespace A { - open Microsoft.Quantum.Math; + import Std.Math.*; function ComplexAsString(x : Complex) : String { if x.Imag < 0. { $"{x.Real} - {AbsD(x.Imag)}i" diff --git a/compiler/qsc_data_structures/src/namespaces.rs b/compiler/qsc_data_structures/src/namespaces.rs index 2f3fc8bc79..8eb30f8ab8 100644 --- a/compiler/qsc_data_structures/src/namespaces.rs +++ b/compiler/qsc_data_structures/src/namespaces.rs @@ -7,11 +7,11 @@ mod tests; use rustc_hash::{FxHashMap, FxHashSet}; use std::{cell::RefCell, collections::BTreeMap, fmt::Display, iter::Peekable, ops::Deref, rc::Rc}; -pub const PRELUDE: [[&str; 3]; 4] = [ - ["Microsoft", "Quantum", "Canon"], - ["Microsoft", "Quantum", "Core"], - ["Microsoft", "Quantum", "Intrinsic"], - ["Microsoft", "Quantum", "Measurement"], +pub const PRELUDE: &[&[&str]; 4] = &[ + &["Std", "Canon"], + &["Microsoft", "Quantum", "Core"], + &["Std", "Intrinsic"], + &["Std", "Measurement"], ]; /// An ID that corresponds to a namespace in the global scope. @@ -279,7 +279,7 @@ impl Default for NamespaceTreeRoot { memo: RefCell::new(FxHashMap::default()), }; // insert the prelude namespaces using the `NamespaceTreeRoot` API - for ns in &PRELUDE { + for ns in PRELUDE { let iter = ns.iter().map(|s| Rc::from(*s)).peekable(); let _ = tree.insert_or_find_namespace(iter); } diff --git a/compiler/qsc_data_structures/src/namespaces/tests.rs b/compiler/qsc_data_structures/src/namespaces/tests.rs index 8ecad1562b..eea07f9c61 100644 --- a/compiler/qsc_data_structures/src/namespaces/tests.rs +++ b/compiler/qsc_data_structures/src/namespaces/tests.rs @@ -25,37 +25,41 @@ fn test_tree_construction() { NamespaceTreeRoot children: [ - ns1(id 11) { + Std(id 1) { children: [ - nsc(id 14) {empty node}, - nsb(id 13) {empty node}, - nsa(id 12) {empty node}, + Measurement(id 7) {empty node}, + Canon(id 2) {empty node}, + Intrinsic(id 6) {empty node}, ] }, - ns0(id 7) { + ns1(id 12) { children: [ - nsc(id 10) {empty node}, - nsb(id 9) {empty node}, - nsa(id 8) {empty node}, + nsc(id 15) {empty node}, + nsb(id 14) {empty node}, + nsa(id 13) {empty node}, ] }, - Microsoft(id 1) { + ns0(id 8) { children: [ - Quantum(id 2) { + nsc(id 11) {empty node}, + nsb(id 10) {empty node}, + nsa(id 9) {empty node}, + ] + }, + Microsoft(id 3) { + children: [ + Quantum(id 4) { children: [ - Canon(id 3) {empty node}, - Measurement(id 6) {empty node}, - Core(id 4) {empty node}, - Intrinsic(id 5) {empty node}, + Core(id 5) {empty node}, ] }, ] }, - ns2(id 15) { + ns2(id 16) { children: [ - nsc(id 18) {empty node}, - nsb(id 17) {empty node}, - nsa(id 16) {empty node}, + nsc(id 19) {empty node}, + nsb(id 18) {empty node}, + nsa(id 17) {empty node}, ] }, ] @@ -117,9 +121,9 @@ fn test_find_id() { RefCell { value: children: [ - nsc(id 10) {empty node}, - nsb(id 9) {empty node}, - nsa(id 8) {empty node}, + nsc(id 11) {empty node}, + nsb(id 10) {empty node}, + nsa(id 9) {empty node}, ] }, }, @@ -158,9 +162,9 @@ fn test_find_id() { RefCell { value: children: [ - nsc(id 14) {empty node}, - nsb(id 13) {empty node}, - nsa(id 12) {empty node}, + nsc(id 15) {empty node}, + nsb(id 14) {empty node}, + nsa(id 13) {empty node}, ] }, }, @@ -199,9 +203,9 @@ fn test_find_id() { RefCell { value: children: [ - nsc(id 18) {empty node}, - nsb(id 17) {empty node}, - nsa(id 16) {empty node}, + nsc(id 19) {empty node}, + nsb(id 18) {empty node}, + nsa(id 17) {empty node}, ] }, }, @@ -228,19 +232,19 @@ fn test_insert_or_find_namespace() { ids_sorted.dedup(); // there should be no duplicate or out-of-order ids assert_eq!(ids_sorted, ids); - expect![[r" + expect![[r#" [ - 8, 9, 10, - 12, + 11, 13, 14, - 16, + 15, 17, 18, + 19, ] - "]] + "#]] .assert_debug_eq(&ids); } @@ -265,11 +269,6 @@ fn test_get_namespace_id() { } expect![[r#" [ - Some( - NamespaceId( - 8, - ), - ), Some( NamespaceId( 9, @@ -282,12 +281,12 @@ fn test_get_namespace_id() { ), Some( NamespaceId( - 7, + 11, ), ), Some( NamespaceId( - 12, + 8, ), ), Some( @@ -302,12 +301,12 @@ fn test_get_namespace_id() { ), Some( NamespaceId( - 11, + 15, ), ), Some( NamespaceId( - 16, + 12, ), ), Some( @@ -322,7 +321,12 @@ fn test_get_namespace_id() { ), Some( NamespaceId( - 15, + 19, + ), + ), + Some( + NamespaceId( + 16, ), ), ] @@ -350,25 +354,28 @@ fn test_tree_iter() { ], [ [ - "Microsoft", + "Std", ], ], [ [ - "Microsoft", - "Quantum", + "Std", + "Canon", + ], + [ + "Std", + "Canon", ], ], [ [ "Microsoft", - "Quantum", - "Canon", ], + ], + [ [ "Microsoft", "Quantum", - "Canon", ], ], [ @@ -385,25 +392,21 @@ fn test_tree_iter() { ], [ [ - "Microsoft", - "Quantum", + "Std", "Intrinsic", ], [ - "Microsoft", - "Quantum", + "Std", "Intrinsic", ], ], [ [ - "Microsoft", - "Quantum", + "Std", "Measurement", ], [ - "Microsoft", - "Quantum", + "Std", "Measurement", ], ], diff --git a/compiler/qsc_eval/src/intrinsic/tests.rs b/compiler/qsc_eval/src/intrinsic/tests.rs index dd707a76fe..d06d35e8b4 100644 --- a/compiler/qsc_eval/src/intrinsic/tests.rs +++ b/compiler/qsc_eval/src/intrinsic/tests.rs @@ -548,7 +548,7 @@ fn dump_register_all_qubits_normalized_is_same_as_dump_machine() { "", indoc! { "{ - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; use qs = Qubit[2]; let alpha = -4.20025; diff --git a/compiler/qsc_formatter/src/formatter/tests.rs b/compiler/qsc_formatter/src/formatter/tests.rs index 94b99d828f..28a9955783 100644 --- a/compiler/qsc_formatter/src/formatter/tests.rs +++ b/compiler/qsc_formatter/src/formatter/tests.rs @@ -656,7 +656,7 @@ fn formatting_corrects_indentation() { /// Second /// Third namespace MyQuantumProgram { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Int { @@ -673,7 +673,7 @@ fn formatting_corrects_indentation() { /// Second /// Third namespace MyQuantumProgram { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Int { @@ -1186,7 +1186,7 @@ fn sample_has_no_formatting_changes() { /// Joint measurements, also known as Pauli measurements, are a generalization /// of 2-outcome measurements to multiple qubits and other bases. namespace Sample { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : (Result, Result[]) { diff --git a/compiler/qsc_frontend/src/compile/tests.rs b/compiler/qsc_frontend/src/compile/tests.rs index 9c5d4743e3..77d7ea699f 100644 --- a/compiler/qsc_frontend/src/compile/tests.rs +++ b/compiler/qsc_frontend/src/compile/tests.rs @@ -772,7 +772,7 @@ fn std_dependency() { "test".into(), indoc! {" namespace Foo { - open Microsoft.Quantum.Intrinsic; + import Std.Intrinsic.*; operation Main() : Unit { use q = Qubit(); @@ -804,7 +804,7 @@ fn std_dependency_base_profile() { "test".into(), indoc! {" namespace Foo { - open Microsoft.Quantum.Intrinsic; + import Std.Intrinsic.*; operation Main() : Unit { use q = Qubit(); @@ -1191,7 +1191,7 @@ fn reject_use_qubit_block_syntax_if_preview_feature_is_on() { "test".into(), indoc! {" namespace Foo { - open Microsoft.Quantum.Intrinsic; + import Std.Intrinsic.*; operation Main() : Unit { use q = Qubit() { // some qubit operation here @@ -1226,8 +1226,8 @@ fn reject_use_qubit_block_syntax_if_preview_feature_is_on() { Brace, ), Span { - lo: 119, - hi: 120, + lo: 109, + hi: 110, }, ), ), @@ -1247,7 +1247,7 @@ fn accept_use_qubit_block_syntax_if_preview_feature_is_off() { "test".into(), indoc! {" namespace Foo { - open Microsoft.Quantum.Intrinsic; + import Std.Intrinsic.*; operation Main() : Unit { use q = Qubit() { // some qubit operation here diff --git a/compiler/qsc_frontend/src/incremental/tests.rs b/compiler/qsc_frontend/src/incremental/tests.rs index fe2fe642d3..31b5f8f103 100644 --- a/compiler/qsc_frontend/src/incremental/tests.rs +++ b/compiler/qsc_frontend/src/incremental/tests.rs @@ -68,14 +68,14 @@ fn one_callable() { }, kind: Namespace( NamespaceId( - 9, + 10, ), ), opens: { []: [ Open { namespace: NamespaceId( - 9, + 10, ), span: Span { lo: 10, diff --git a/compiler/qsc_frontend/src/resolve.rs b/compiler/qsc_frontend/src/resolve.rs index 62a8f4c951..9f5bc0193c 100644 --- a/compiler/qsc_frontend/src/resolve.rs +++ b/compiler/qsc_frontend/src/resolve.rs @@ -2195,7 +2195,7 @@ pub fn prelude_namespaces(globals: &GlobalScope) -> Vec<(NamespaceId, String)> { prelude.push(( globals .namespaces - .get_namespace_id(prelude_namespace) + .get_namespace_id(prelude_namespace.to_vec()) .expect("prelude should always exist in the namespace map"), prelude_namespace.join("."), )); diff --git a/compiler/qsc_frontend/src/resolve/tests.rs b/compiler/qsc_frontend/src/resolve/tests.rs index e1771d2636..7024c6dd5f 100644 --- a/compiler/qsc_frontend/src/resolve/tests.rs +++ b/compiler/qsc_frontend/src/resolve/tests.rs @@ -227,7 +227,7 @@ fn global_callable() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} function item2() : Unit { @@ -249,7 +249,7 @@ fn global_callable_recursive() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { item1(); } @@ -271,7 +271,7 @@ fn global_callable_internal() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { internal function item1() : Unit {} function item2() : Unit { @@ -292,7 +292,7 @@ fn global_callable_duplicate_error() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} operation item2() : Unit {} } @@ -317,11 +317,11 @@ fn global_path() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { function item3() : Unit { item1(); } @@ -347,12 +347,12 @@ fn open_namespace() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; function item3() : Unit { item1(); @@ -379,12 +379,12 @@ fn open_alias() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { - open namespace7 as F; + namespace namespace9 { + open namespace8 as F; function item3() : Unit { item1(); @@ -409,11 +409,11 @@ fn prelude_callable() { } "}, &expect![[r#" - namespace namespace4 { + namespace namespace5 { function item1() : Unit {} } - namespace namespace7 { + namespace namespace8 { function item3() : Unit { item1(); } @@ -439,11 +439,11 @@ fn parent_namespace_shadows_prelude() { } "}, &expect![[r#" - namespace namespace4 { + namespace namespace5 { function item1() : Unit {} } - namespace namespace7 { + namespace namespace8 { function item3() : Unit {} function item4() : Unit { @@ -475,16 +475,16 @@ fn open_shadows_prelude() { } "}, &expect![[r#" - namespace namespace4 { + namespace namespace5 { function item1() : Unit {} } - namespace namespace7 { + namespace namespace8 { function item3() : Unit {} } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; function item5() : Unit { item3(); @@ -498,11 +498,11 @@ fn open_shadows_prelude() { fn ambiguous_prelude() { check( indoc! {" - namespace Microsoft.Quantum.Canon { + namespace Std.Canon { function A() : Unit {} } - namespace Microsoft.Quantum.Core { + namespace Std.Measurement { function A() : Unit {} } @@ -513,21 +513,21 @@ fn ambiguous_prelude() { } "}, &expect![[r#" - namespace namespace3 { + namespace namespace2 { function item1() : Unit {} } - namespace namespace4 { + namespace namespace7 { function item3() : Unit {} } - namespace namespace7 { + namespace namespace8 { function item5() : Unit { A(); } } - // AmbiguousPrelude { name: "A", candidate_a: "Microsoft.Quantum.Canon", candidate_b: "Microsoft.Quantum.Core", span: Span { lo: 181, hi: 182 } } + // AmbiguousPrelude { name: "A", candidate_a: "Std.Canon", candidate_b: "Std.Measurement", span: Span { lo: 160, hi: 161 } } "#]], ); } @@ -544,7 +544,7 @@ fn local_var() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { let local13 = 0; local13 @@ -570,7 +570,7 @@ fn shadow_local() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { let local13 = 0; let local17 = { @@ -595,7 +595,7 @@ fn callable_param() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local8 : Int) : Int { local8 } @@ -617,7 +617,7 @@ fn spec_param() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit) : (Qubit[], Qubit) { controlled (local23, ...) { (local23, local8) @@ -644,7 +644,7 @@ fn spec_param_shadow_disallowed() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit[]) : Qubit[] { controlled (local20, ...) { local20 @@ -675,7 +675,7 @@ fn local_shadows_global() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} function item2() : Int { @@ -701,7 +701,7 @@ fn shadow_same_block() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { let local13 = 0; let local17 = local13 + 1; @@ -731,12 +731,12 @@ fn parent_namespace_shadows_open() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; function item3() : Unit {} @@ -769,16 +769,16 @@ fn open_alias_shadows_global() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { function item3() : Unit {} } - namespace namespace9 { - open namespace7 as Bar; + namespace namespace10 { + open namespace8 as Bar; function item5() : Unit { item1(); @@ -797,7 +797,7 @@ fn shadowing_disallowed_within_parameters() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8: Int, local13: Double, local18: Bool) : Unit {} } @@ -817,7 +817,7 @@ fn shadowing_disallowed_within_local_binding() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { let (local14, local16, local18) = (1, 2, 3); } @@ -839,7 +839,7 @@ fn shadowing_disallowed_within_for_loop() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { for (local15, local17, local19) in [(1, 1, 1)] {} } @@ -861,7 +861,7 @@ fn shadowing_disallowed_within_lambda_param() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { let local13 = (local17, local19, local21) -> local21 + local19 + 1; } @@ -895,17 +895,17 @@ fn merged_aliases() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { function item3() : Unit {} } - namespace namespace9 { - open namespace7 as Alias; + namespace namespace10 { open namespace8 as Alias; + open namespace9 as Alias; function item5() : Unit { item1(); @@ -926,7 +926,7 @@ fn ty_decl() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; function item2(local14 : item1) : Unit {} } @@ -944,7 +944,7 @@ fn struct_decl() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} function item2(local11 : item1) : Unit {} } @@ -962,7 +962,7 @@ fn ty_decl_duplicate_error() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; newtype item2 = Bool; } @@ -982,7 +982,7 @@ fn struct_decl_duplicate_error() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} struct item2 { first : Bool } } @@ -1001,7 +1001,7 @@ fn ty_decl_duplicate_error_on_built_in_ty() { } "}, &expect![[r#" - namespace namespace4 { + namespace namespace5 { newtype item1 = Unit; } @@ -1019,7 +1019,7 @@ fn struct_decl_duplicate_error_on_built_in_ty() { } "}, &expect![[r#" - namespace namespace4 { + namespace namespace5 { struct item1 {} } @@ -1038,7 +1038,7 @@ fn ty_decl_in_ty_decl() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; newtype item2 = item1; } @@ -1056,7 +1056,7 @@ fn struct_decl_in_struct_decl() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} struct item2 { a : item1 } } @@ -1073,7 +1073,7 @@ fn ty_decl_recursive() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = item1; } "#]], @@ -1089,7 +1089,7 @@ fn struct_decl_recursive() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 { a : item1 } } "#]], @@ -1109,7 +1109,7 @@ fn ty_decl_cons() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; function item2() : item1 { @@ -1133,7 +1133,7 @@ fn struct_decl_call_cons() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} function item2() : item1 { @@ -1157,7 +1157,7 @@ fn struct_decl_cons() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} function item2() : item1 { @@ -1183,7 +1183,7 @@ fn struct_decl_cons_with_fields() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} struct item2 {} struct item3 { a : item1, b : item2 } @@ -1212,7 +1212,7 @@ fn struct_field_accessor() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 { b : item2 } struct item2 { c : item3} struct item3 { i : Int } @@ -1242,7 +1242,7 @@ fn struct_field_accessor_with_expr() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 { b : item2 } struct item2 { c : item3} struct item3 { i : Int } @@ -1267,7 +1267,7 @@ fn unknown_term() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { B(); } @@ -1287,7 +1287,7 @@ fn unknown_ty() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local8 : B) : Unit {} } @@ -1318,17 +1318,17 @@ fn open_ambiguous_terms() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { function item3() : Unit {} } - namespace namespace9 { - open namespace7; + namespace namespace10 { open namespace8; + open namespace9; function item5() : Unit { A(); @@ -1360,17 +1360,17 @@ fn open_ambiguous_tys() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; } - namespace namespace8 { + namespace namespace9 { newtype item3 = Unit; } - namespace namespace9 { - open namespace7; + namespace namespace10 { open namespace8; + open namespace9; function item5(local28 : A) : Unit {} } @@ -1402,20 +1402,20 @@ fn merged_aliases_ambiguous_terms() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { function item3() : Unit {} } - namespace namespace9 { - open namespace7 as Alias; + namespace namespace10 { open namespace8 as Alias; + open namespace9 as Alias; function item5() : Unit { - namespace8.A(); + namespace9.A(); } } @@ -1444,19 +1444,19 @@ fn merged_aliases_ambiguous_tys() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; } - namespace namespace8 { + namespace namespace9 { newtype item3 = Unit; } - namespace namespace9 { - open namespace7 as Alias; + namespace namespace10 { open namespace8 as Alias; + open namespace9 as Alias; - function item5(local30 : namespace8.A) : Unit {} + function item5(local30 : namespace9.A) : Unit {} } // Ambiguous { name: "A", first_open: "Foo", second_open: "Bar", name_span: Span { lo: 170, hi: 171 }, first_open_span: Span { lo: 107, hi: 110 }, second_open_span: Span { lo: 130, hi: 133 } } @@ -1475,7 +1475,7 @@ fn lambda_param() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { let local13 = local16 -> local16 + 1; } @@ -1497,7 +1497,7 @@ fn lambda_shadows_local() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { let local13 = 1; let local17 = local20 -> local20 + 1; @@ -1521,7 +1521,7 @@ fn for_loop_range() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { for local14 in 0..9 { let _ = local14; @@ -1545,7 +1545,7 @@ fn for_loop_var() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local8 : Int[]) : Unit { for local20 in local8 { let _ = local20; @@ -1570,7 +1570,7 @@ fn repeat_until() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { mutable local13 = false; repeat { @@ -1599,7 +1599,7 @@ fn repeat_until_fixup() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { mutable local13 = false; repeat { @@ -1630,7 +1630,7 @@ fn repeat_until_fixup_scoping() { } }"}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { repeat { mutable local16 = false; @@ -1662,7 +1662,7 @@ fn use_qubit() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit) : Unit { body intrinsic; } @@ -1691,7 +1691,7 @@ fn use_qubit_block() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit) : Unit { body intrinsic; } @@ -1722,7 +1722,7 @@ fn use_qubit_block_qubit_restricted_to_block_scope() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit) : Unit { body intrinsic; } @@ -1751,7 +1751,7 @@ fn local_function() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { function item2() : Int { 2 } item2() + 1 @@ -1773,7 +1773,7 @@ fn local_function_use_before_declare() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { item2(); function item2() : () {} @@ -1797,7 +1797,7 @@ fn local_function_is_really_local() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { function item3() : () {} item3(); @@ -1823,7 +1823,7 @@ fn local_function_is_not_closure() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { let local11 = 2; function item2() : Int { x } @@ -1847,7 +1847,7 @@ fn local_type() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { newtype item2 = Int; let local18 = item2(5); @@ -1865,8 +1865,8 @@ fn local_open() { namespace B { function Bar() : () {} } "}, &expect![[r#" - namespace namespace7 { function item1() : () { open namespace8; item3(); } } - namespace namespace8 { function item3() : () {} } + namespace namespace8 { function item1() : () { open namespace9; item3(); } } + namespace namespace9 { function item3() : () {} } "#]], ); } @@ -1883,12 +1883,12 @@ fn local_open_shadows_parent_item() { namespace B { function Bar() : () {} } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () {} - function item2() : () { open namespace8; item4(); } + function item2() : () { open namespace9; item4(); } } - namespace namespace8 { function item4() : () {} } + namespace namespace9 { function item4() : () {} } "#]], ); } @@ -1906,13 +1906,13 @@ fn local_open_shadows_parent_open() { namespace C { function Bar() : () {} } "}, &expect![[r#" - namespace namespace7 { - open namespace8; - function item1() : () { open namespace9; item5(); } + namespace namespace8 { + open namespace9; + function item1() : () { open namespace10; item5(); } } - namespace namespace8 { function item3() : () {} } - namespace namespace9 { function item5() : () {} } + namespace namespace9 { function item3() : () {} } + namespace namespace10 { function item5() : () {} } "#]], ); } @@ -1930,7 +1930,7 @@ fn update_array_index_var() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { let local11 = [2]; let local16 = 0; @@ -1954,7 +1954,7 @@ fn update_array_index_expr() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { let local11 = [2]; let local16 = 0; @@ -1979,7 +1979,7 @@ fn update_udt_known_field_name() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First : Int, Second : Int); function item2() : () { @@ -2005,7 +2005,7 @@ fn update_udt_known_field_name_expr() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First : Int, Second : Int); function item2() : () { @@ -2033,7 +2033,7 @@ fn update_udt_unknown_field_name() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First : Int, Second : Int); function item2() : () { @@ -2061,7 +2061,7 @@ fn update_udt_unknown_field_name_known_global() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First : Int, Second : Int); function item2() : () {} @@ -2080,15 +2080,15 @@ fn unknown_namespace() { check( indoc! {" namespace A { - open Microsoft.Quantum.Fake; + import Std.Fake.*; } "}, &expect![[r#" - namespace namespace7 { - open Microsoft.Quantum.Fake; + namespace namespace8 { + import Std.Fake.*; } - // NotFound("Microsoft.Quantum.Fake", Span { lo: 23, hi: 45 }) + // GlobImportNamespaceNotFound("Fake", Span { lo: 25, hi: 33 }) "#]], ); } @@ -2104,11 +2104,11 @@ fn empty_namespace_works() { namespace B {} "}, &expect![[r#" - namespace namespace7 { - open namespace8; + namespace namespace8 { + open namespace9; function item1(): Unit{} } - namespace namespace8 {} + namespace namespace9 {} "#]], ); } @@ -2131,14 +2131,14 @@ fn cyclic_namespace_dependency_supported() { } "}, &expect![[r#" - namespace namespace7 { - open namespace8; + namespace namespace8 { + open namespace9; operation item1() : Unit { item3(); } } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; operation item3() : Unit { item1(); } @@ -2163,7 +2163,7 @@ fn bind_items_in_repeat() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { repeat { function item2() : Unit {} @@ -2190,7 +2190,7 @@ fn bind_items_in_qubit_use_block() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { use local13 = Qubit() { function item2() : Unit {} @@ -2215,7 +2215,7 @@ fn use_bound_item_in_another_bound_item() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { function item2() : Unit { item3(); @@ -2238,7 +2238,7 @@ fn use_unbound_generic() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local9: 'U) : 'U { local9 } @@ -2261,7 +2261,7 @@ fn resolve_local_generic() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local9: param0) : param0 { local9 } @@ -2285,7 +2285,7 @@ fn dropped_base_callable_from_unrestricted() { "}, TargetCapabilityFlags::all(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Base) function Dropped() : Unit {} @@ -2314,7 +2314,7 @@ fn dropped_base_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Base) function Dropped() : Unit {} @@ -2343,7 +2343,7 @@ fn dropped_not_base_callable_from_base() { "}, TargetCapabilityFlags::empty(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Base) function Dropped() : Unit {} @@ -2372,7 +2372,7 @@ fn resolved_not_base_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Base) function item1() : Unit {} @@ -2400,7 +2400,7 @@ fn dropped_base_and_not_base_callable_from_base() { "}, TargetCapabilityFlags::empty(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Base) @Config(not Base) function Dropped() : Unit {} @@ -2430,7 +2430,7 @@ fn resolved_not_unrestricted_callable_from_base() { "}, TargetCapabilityFlags::empty(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Unrestricted) function item1() : Unit {} @@ -2457,7 +2457,7 @@ fn resolved_not_unrestricted_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Unrestricted) function item1() : Unit {} @@ -2484,7 +2484,7 @@ fn dropped_not_unrestricted_callable_from_unrestricted() { "}, TargetCapabilityFlags::all(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Unrestricted) function Dropped() : Unit {} @@ -2513,7 +2513,7 @@ fn resolved_adaptive_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) function item1() : Unit {} @@ -2540,7 +2540,7 @@ fn resolved_adaptive_callable_from_unrestricted() { "}, TargetCapabilityFlags::all(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) function item1() : Unit {} @@ -2567,7 +2567,7 @@ fn dropped_not_higher_level_callable_from_unrestricted() { "}, TargetCapabilityFlags::all(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not HigherLevelConstructs) function Dropped() : Unit {} @@ -2596,7 +2596,7 @@ fn resolved_not_higher_level_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not HigherLevelConstructs) function item1() : Unit {} @@ -2623,7 +2623,7 @@ fn resolved_not_higher_level_callable_from_base() { "}, TargetCapabilityFlags::empty(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not HigherLevelConstructs) function item1() : Unit {} @@ -2651,7 +2651,7 @@ fn dropped_not_higher_level_and_adaptive_callable_from_base() { "}, TargetCapabilityFlags::empty(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) @Config(not HigherLevelConstructs) function Dropped() : Unit {} @@ -2682,7 +2682,7 @@ fn dropped_not_higher_level_and_adaptive_callable_from_unrestricted() { "}, TargetCapabilityFlags::all(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) @Config(not HigherLevelConstructs) function Dropped() : Unit {} @@ -2713,7 +2713,7 @@ fn resolved_not_higher_level_and_adaptive_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) @Config(not HigherLevelConstructs) function item1() : Unit {} @@ -2741,7 +2741,7 @@ fn dropped_floating_point_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(FloatingPointComputations) function Dropped() : Double {} @@ -2771,7 +2771,7 @@ fn resolved_adaptive_and_integer_from_adaptive_and_integer() { "}, TargetCapabilityFlags::Adaptive | TargetCapabilityFlags::IntegerComputations, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) @Config(IntegerComputations) function item1() : Double {} @@ -2811,7 +2811,7 @@ fn multiple_definition_dropped_is_not_found() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) operation item1() : Unit {} @Config(Base) @@ -2821,13 +2821,13 @@ fn multiple_definition_dropped_is_not_found() { @Config(Adaptive) operation item2() : Unit {} } - namespace namespace8 { + namespace namespace9 { operation item4() : Unit { B(); C(); } operation item5() : Unit { - open namespace7; + open namespace8; item1(); item2(); } @@ -2855,12 +2855,12 @@ fn disallow_duplicate_intrinsic() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { body intrinsic; } } - namespace namespace8 { + namespace namespace9 { operation item3() : Unit { body intrinsic; } @@ -2890,15 +2890,15 @@ fn disallow_duplicate_intrinsic_and_non_intrinsic_collision() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { internal operation item1() : Unit { body intrinsic; } } - namespace namespace8 { + namespace namespace9 { operation item3() : Unit {} } - namespace namespace8 { + namespace namespace9 { operation item5() : Unit { body intrinsic; } @@ -2925,12 +2925,12 @@ fn disallow_duplicate_intrinsic_and_simulatableintrinsic() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { body intrinsic; } } - namespace namespace8 { + namespace namespace9 { @SimulatableIntrinsic() operation item3() : Unit {} } @@ -3260,7 +3260,7 @@ fn use_after_scope() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { { let local16 = 42; @@ -3289,7 +3289,7 @@ fn nested_function_definition() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { function item2() : Unit { function item3() : Unit {} @@ -3320,7 +3320,7 @@ fn variable_in_nested_blocks() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { { let local16 = 10; @@ -3353,11 +3353,11 @@ fn function_call_with_namespace_alias() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { - open namespace7 as F; + namespace namespace9 { + open namespace8 as F; function item3() : Unit { item1(); } @@ -3381,7 +3381,7 @@ fn type_alias_in_function_scope() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { newtype item3 = Int; let local20 : item3 = item3(5); @@ -3412,7 +3412,7 @@ fn lambda_inside_lambda() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { let local13 = () -> { let local20 = (local24) -> local24 + 1; @@ -3441,10 +3441,10 @@ fn nested_namespaces_with_same_function_name() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { function item3() : Unit {} function item4() : Unit { item1(); @@ -3464,7 +3464,7 @@ fn newtype_with_invalid_field_type() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (Re: Real, Im: Imaginary); // Imaginary is not a valid type } @@ -3487,7 +3487,7 @@ fn newtype_with_tuple_destructuring() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First: Int, Second: Int); function item2(local21: item1) : Int { let (local32, local34) = local21; @@ -3518,7 +3518,7 @@ namespace Foo.Bar.Baz { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @EntryPoint() function item1(): Int { item2() @@ -3529,7 +3529,7 @@ namespace Foo.Bar.Baz { } } - namespace namespace9 { + namespace namespace10 { function item4() : Int { 6 } } "#]], @@ -3556,17 +3556,17 @@ fn basic_hierarchical_namespace() { } }"}, &expect![[r#" - namespace namespace9 { + namespace namespace10 { operation item1() : Unit {} } - namespace namespace10 { - open namespace7; + namespace namespace11 { + open namespace8; operation item3() : Unit { item1(); } } - namespace namespace11 { - open namespace8; + namespace namespace12 { + open namespace9; operation item5() : Unit { item1(); } @@ -3593,13 +3593,13 @@ namespace Kata.Verification { } " }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { // Do nothing. } } - namespace namespace8 { + namespace namespace9 { operation item3() : Bool { let _ = item1(); let _ = item4(); @@ -3629,13 +3629,13 @@ namespace Foo { } }"#}, &expect![[r#" - namespace namespace8 { + namespace namespace9 { operation item1() : Unit { } } - namespace namespace7 { + namespace namespace8 { open Bar; @EntryPoint() operation item3() : Unit { @@ -3655,7 +3655,7 @@ fn test_export_statement() { } " }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { } export item1; @@ -3700,29 +3700,29 @@ namespace Foo.Bar.Graule { }" }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { export item2; } - namespace namespace10 { + namespace namespace11 { function item2() : Unit {} } - namespace namespace8 { + namespace namespace9 { export item2; } - namespace namespace9 { + namespace namespace10 { export item2; } - namespace namespace11 { + namespace namespace12 { // HelloWorld should be available from all namespaces operation item6() : Unit { item2(); item2(); item2(); item2(); - open namespace7; + open namespace8; item2(); } // and we should be able to re-export it @@ -3744,11 +3744,11 @@ fn exports_aware_of_opens() { } "# }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; export item1; } "#]], @@ -3775,15 +3775,15 @@ namespace Main { } }" }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { export item2; } - namespace namespace10 { + namespace namespace11 { function item2() : Unit {} } - namespace namespace11 { - open namespace7; + namespace namespace12 { + open namespace8; operation item4() : Unit { item2(); item2(); @@ -3809,11 +3809,11 @@ fn multiple_exports() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} operation item2() : Unit {} } - namespace namespace8 { + namespace namespace9 { import item1, item2; operation item4() : Unit { item1(); @@ -3839,11 +3839,11 @@ fn no_exports() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; operation item3() : Unit { item1(); } @@ -3861,7 +3861,7 @@ fn export_non_existent_symbol() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { export NonExistent; } @@ -3888,14 +3888,14 @@ fn export_symbol_from_nested_namespace() { } "}, &expect![[r#" - namespace namespace8 { + namespace namespace9 { operation item1() : Unit {} } - namespace namespace7 { + namespace namespace8 { export item1; } - namespace namespace9 { - open namespace7; + namespace namespace10 { + open namespace8; operation item4() : Unit { item1(); } @@ -3916,7 +3916,7 @@ fn disallow_exporting_local_vars() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { let local13 = 5; } @@ -3941,8 +3941,8 @@ fn export_non_item() { } "}, &expect![[r#" - namespace namespace7 {} - namespace namespace8 { + namespace namespace8 {} + namespace namespace9 { operation item2() : Unit { } export Unit; @@ -3970,12 +3970,12 @@ fn export_udt() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First: Int, Second: Int); export item1; } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; operation item3() : Unit { item1(1, 2); } @@ -4000,12 +4000,12 @@ fn export_with_alias() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} export item1; } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; operation item3() : Unit { item1(); } @@ -4032,13 +4032,13 @@ fn multiple_exports_with_aliases() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} operation item2() : Unit {} export item1, item2; } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; operation item4() : Unit { item1(); item2(); @@ -4066,13 +4066,13 @@ fn aliased_exports_call_with_qualified_paths() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} operation item2() : Unit {} export item1, item2; } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; operation item4() : Unit { item1(); item2(); @@ -4096,12 +4096,12 @@ fn reexport_from_full_path_with_alias() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} export item1; } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; export item1; } "#]], @@ -4119,7 +4119,7 @@ fn disallow_repeated_exports() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} export item1; export item1; @@ -4140,7 +4140,7 @@ fn disallow_repeated_exports_inline() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} export item1, item1; } @@ -4165,12 +4165,12 @@ fn order_of_exports_does_not_matter() { "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { export item3; export item1; operation item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { operation item3() : Unit {} } @@ -4194,12 +4194,12 @@ fn export_udt_and_construct_it() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First: Int, Second: Int); export item1; } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; operation item3() : Unit { let local33: item1 = item1(1, 2); } @@ -4222,10 +4222,10 @@ fn import_single_item() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { import item1; operation item3() : Unit { item1(); @@ -4250,11 +4250,11 @@ fn import_namespace() { } "}, &expect![[r#" - namespace namespace8 { + namespace namespace9 { function item1() : Unit {} } - namespace namespace9 { - import namespace8; + namespace namespace10 { + import namespace9; operation item3() : Unit { item1(); } @@ -4277,9 +4277,9 @@ fn import_non_existent_item() { } "}, &expect![[r#" - namespace namespace7 { - } namespace namespace8 { + } + namespace namespace9 { import Foo.Bar; operation item2() : Unit { Bar(); @@ -4308,10 +4308,10 @@ fn import_shadowing() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { function item3() : Unit {} import item1; operation item4() : Unit { @@ -4337,10 +4337,10 @@ fn import_with_alias() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { import item1; operation item3() : Unit { item1(); @@ -4361,7 +4361,7 @@ fn import_non_item() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import Unit; operation item1() : Unit { } @@ -4387,11 +4387,11 @@ fn import_namespace_nested() { } "}, &expect![[r#" - namespace namespace9 { + namespace namespace10 { operation item1() : Unit {} } - namespace namespace10 { - import namespace8; + namespace namespace11 { + import namespace9; operation item3() : Unit { item1(); } @@ -4416,11 +4416,11 @@ fn import_single_namespace() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} } - namespace namespace8 { - import namespace7; + namespace namespace9 { + import namespace8; operation item3() : Unit { item1(); @@ -4446,10 +4446,10 @@ fn import_shadowing_function() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { operation item3() : Unit {} operation item4() : Unit { import item1; @@ -4471,7 +4471,7 @@ fn import_non_existent_namespace() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { import NonExistent; } @@ -4493,7 +4493,7 @@ fn import_self() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { import item1; } @@ -4515,10 +4515,10 @@ fn import_duplicate_symbol() { } "# }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import item2, item2; } - namespace namespace9 { + namespace namespace10 { operation item2() : Unit {} } "#]], @@ -4539,11 +4539,11 @@ fn import_duplicate_symbol_different_name() { } "# }, &expect![[r#" - namespace namespace7 { - import item2, namespace9; + namespace namespace8 { + import item2, namespace10; import item2; } - namespace namespace9 { + namespace namespace10 { operation item2() : Unit {} } "#]], @@ -4564,10 +4564,10 @@ fn disallow_importing_different_items_with_same_name() { } "# }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import item2, item3; } - namespace namespace9 { + namespace namespace10 { operation item2() : Unit {} operation item3() : Unit {} } @@ -4595,7 +4595,7 @@ fn import_takes_precedence_over_local_decl() { } "# }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { import item3; @@ -4604,7 +4604,7 @@ fn import_takes_precedence_over_local_decl() { } - namespace namespace9 { + namespace namespace10 { operation item3() : Unit {} } "#]], @@ -4624,10 +4624,10 @@ fn import_then_export() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { import item1; export item1; } @@ -4680,40 +4680,40 @@ fn import_namespace_advanced() { } "}, &expect![[r#" - namespace namespace11 { - operation item1() : Unit {} - } namespace namespace12 { - import namespace7; - operation item3() : Unit { - item1(); - } + operation item1() : Unit {} } namespace namespace13 { import namespace8; - operation item5() : Unit { + operation item3() : Unit { item1(); } } namespace namespace14 { import namespace9; - operation item7() : Unit { + operation item5() : Unit { item1(); } } namespace namespace15 { import namespace10; - operation item9() : Unit { + operation item7() : Unit { item1(); } } namespace namespace16 { import namespace11; - operation item11() : Unit { + operation item9() : Unit { item1(); } } namespace namespace17 { + import namespace12; + operation item11() : Unit { + item1(); + } + } + namespace namespace18 { import item1; operation item13() : Unit { item1(); @@ -4739,11 +4739,11 @@ fn import_namespace_does_not_open_it() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} } - namespace namespace8 { - import namespace7; + namespace namespace9 { + import namespace8; operation item3() : Unit { item1(); DumpMachine(); @@ -4766,7 +4766,7 @@ fn invalid_import() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import A.B.C; operation item1() : Unit { } @@ -4797,15 +4797,15 @@ fn export_namespace() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} operation item2() : Unit {} } - namespace namespace8 { + namespace namespace9 { export item4; } - namespace namespace9 { - open namespace7; + namespace namespace10 { + open namespace8; operation item6() : Unit { item1(); item2(); @@ -4833,14 +4833,14 @@ fn export_namespace_contains_children() { } "}, &expect![[r#" - namespace namespace8 { + namespace namespace9 { operation item1() : Unit {} } - namespace namespace9 { + namespace namespace10 { export item3; } - namespace namespace10 { - open namespace8; + namespace namespace11 { + open namespace9; operation item5() : Unit { item1(); } @@ -4866,15 +4866,15 @@ fn export_namespace_cyclic() { } "}, &expect![[r#" - namespace namespace7 { - export namespace8; - } namespace namespace8 { + export namespace9; + } + namespace namespace9 { export item2; operation item3() : Unit {} } - namespace namespace9 { - open namespace8; + namespace namespace10 { + open namespace9; operation item5() : Unit { item3(); } } "#]], @@ -4895,12 +4895,12 @@ fn export_direct_cycle() { } "}, &expect![[r#" - namespace namespace7 { - export namespace7; + namespace namespace8 { + export namespace8; } - namespace namespace8 { - open namespace7; + namespace namespace9 { + open namespace8; operation item2() : Unit { } } "#]], @@ -4926,14 +4926,14 @@ fn export_namespace_with_alias() { } "}, &expect![[r#" - namespace namespace8 { - operation item1() : Unit {} - } namespace namespace9 { - export namespace8; + operation item1() : Unit {} } namespace namespace10 { - open namespace8; + export namespace9; + } + namespace namespace11 { + open namespace9; operation item5() : Unit { item1(); item1(); @@ -4960,12 +4960,12 @@ fn import_glob() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} operation item2() : Unit {} } - namespace namespace8 { - import namespace7.*; + namespace namespace9 { + import namespace8.*; operation item4() : Unit { item1(); item2(); @@ -4992,12 +4992,12 @@ fn import_aliased_glob() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} operation item2() : Unit {} } - namespace namespace8 { - import namespace7; + namespace namespace9 { + import namespace8; operation item4() : Unit { item1(); item2(); @@ -5020,12 +5020,12 @@ fn disallow_glob_export() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} operation item2() : Unit {} } - namespace namespace8 { - export namespace7.*; + namespace namespace9 { + export namespace8.*; } // GlobExportNotSupported(Span { lo: 111, hi: 114 }) @@ -5055,15 +5055,15 @@ fn import_glob_in_list() { } "}, &expect![[r#" - namespace namespace8 { + namespace namespace9 { operation item1() : Unit {} operation item2() : Unit {} } - namespace namespace9 { + namespace namespace10 { operation item4() : Unit {} } - namespace namespace10 { - import namespace8.*, item4; + namespace namespace11 { + import namespace9.*, item4; operation item6() : Unit { item1(); item2(); @@ -5097,15 +5097,15 @@ fn import_glob_in_list_with_alias() { } "}, &expect![[r#" - namespace namespace8 { + namespace namespace9 { operation item1() : Unit {} operation item2() : Unit {} } - namespace namespace9 { + namespace namespace10 { operation item4() : Unit {} } - namespace namespace10 { - import namespace8, item4; + namespace namespace11 { + import namespace9, item4; operation item6() : Unit { item1(); item2(); @@ -5135,7 +5135,7 @@ fn import_newtype() { }"#}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import item3; // no error operation item1() : Unit { @@ -5143,7 +5143,7 @@ fn import_newtype() { } } - namespace namespace8 { + namespace namespace9 { newtype item3 = String; export item3; @@ -5161,9 +5161,9 @@ fn disallow_glob_alias_import() { } "#}, &expect![[r#" - namespace namespace7 {} - namespace namespace8 { - import namespace7; + namespace namespace8 {} + namespace namespace9 { + import namespace8; } // GlobImportAliasNotSupported { namespace_name: "Bar", alias: "B", span: Span { lo: 45, hi: 55 } } @@ -5180,7 +5180,7 @@ fn glob_import_ns_not_found() { } "#}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import Bar.*; } @@ -5198,8 +5198,8 @@ fn allow_export_of_namespace_within_itself() { } "#}, &expect![[r#" - namespace namespace7 { - export namespace7; + namespace namespace8 { + export namespace8; } "#]], ); @@ -5215,7 +5215,7 @@ fn export_of_item_with_same_name_as_namespace_resolves_to_item() { } "#}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} export item1; } @@ -5233,7 +5233,7 @@ fn export_of_item_with_same_name_as_namespace_resolves_to_item_even_when_before_ } "#}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { export item1; operation item1() : Unit {} } diff --git a/compiler/qsc_frontend/src/typeck/tests.rs b/compiler/qsc_frontend/src/typeck/tests.rs index 9b3515e2ac..fb79c0ca1c 100644 --- a/compiler/qsc_frontend/src/typeck/tests.rs +++ b/compiler/qsc_frontend/src/typeck/tests.rs @@ -444,7 +444,7 @@ fn length_type_error() { fn single_arg_for_tuple() { check( indoc! {" - namespace Microsoft.Quantum.Intrinsic { + namespace Std.Intrinsic { operation Ry(theta : Double, qubit : Qubit) : () is Adj + Ctl {} } "}, @@ -452,21 +452,21 @@ fn single_arg_for_tuple() { use q = Qubit(); Ry(q); }"}, - &expect![[r#" - #8 56-87 "(theta : Double, qubit : Qubit)" : (Double, Qubit) - #9 57-71 "theta : Double" : Double - #14 73-86 "qubit : Qubit" : Qubit - #23 106-108 "{}" : Unit - #24 111-146 "{\n use q = Qubit();\n Ry(q);\n}" : Unit - #25 111-146 "{\n use q = Qubit();\n Ry(q);\n}" : Unit - #27 121-122 "q" : Qubit - #29 125-132 "Qubit()" : Qubit - #31 138-143 "Ry(q)" : Unit - #32 138-140 "Ry" : ((Double, Qubit) => Unit is Adj + Ctl) - #35 140-143 "(q)" : Qubit - #36 141-142 "q" : Qubit - Error(Type(Error(TyMismatch("(Double, Qubit)", "Qubit", Span { lo: 138, hi: 143 })))) - "#]], + &expect![[r##" + #7 42-73 "(theta : Double, qubit : Qubit)" : (Double, Qubit) + #8 43-57 "theta : Double" : Double + #13 59-72 "qubit : Qubit" : Qubit + #22 92-94 "{}" : Unit + #23 97-132 "{\n use q = Qubit();\n Ry(q);\n}" : Unit + #24 97-132 "{\n use q = Qubit();\n Ry(q);\n}" : Unit + #26 107-108 "q" : Qubit + #28 111-118 "Qubit()" : Qubit + #30 124-129 "Ry(q)" : Unit + #31 124-126 "Ry" : ((Double, Qubit) => Unit is Adj + Ctl) + #34 126-129 "(q)" : Qubit + #35 127-128 "q" : Qubit + Error(Type(Error(TyMismatch("(Double, Qubit)", "Qubit", Span { lo: 124, hi: 129 })))) + "##]], ); } diff --git a/compiler/qsc_partial_eval/src/tests/calls.rs b/compiler/qsc_partial_eval/src/tests/calls.rs index 9dfa3c7c77..f614c7120c 100644 --- a/compiler/qsc_partial_eval/src/tests/calls.rs +++ b/compiler/qsc_partial_eval/src/tests/calls.rs @@ -1209,7 +1209,7 @@ fn call_to_unresolved_callee_with_classical_arg_allowed() { let program = get_rir_program_with_capabilities( indoc! {" namespace Test { - open Microsoft.Quantum.Convert; + import Std.Convert.*; operation Op(i : Int, q : Qubit) : Unit { Rx(IntAsDouble(i), q); } @@ -1239,7 +1239,7 @@ fn call_to_unresolved_callee_with_dynamic_arg_fails() { let error = get_partial_evaluation_error_with_capabilities( indoc! {" namespace Test { - open Microsoft.Quantum.Convert; + import Std.Convert.*; operation Op(i : Int, q : Qubit) : Unit { Rx(IntAsDouble(i), q); } @@ -1256,7 +1256,7 @@ fn call_to_unresolved_callee_with_dynamic_arg_fails() { assert_error( &error, - &expect!["CapabilityError(UseOfDynamicDouble(Span { lo: 298, hi: 305 }))"], + &expect!["CapabilityError(UseOfDynamicDouble(Span { lo: 288, hi: 295 }))"], ); } @@ -1265,7 +1265,7 @@ fn call_to_unresolved_callee_producing_dynamic_value_fails() { let error = get_partial_evaluation_error_with_capabilities( indoc! {" namespace Test { - open Microsoft.Quantum.Convert; + import Std.Convert.*; operation Op(i : Int, q : Qubit) : Int { X(q); i @@ -1283,7 +1283,7 @@ fn call_to_unresolved_callee_producing_dynamic_value_fails() { assert_error( &error, - &expect!["UnexpectedDynamicValue(PackageSpan { package: PackageId(2), span: Span { lo: 298, hi: 305 } })"], + &expect!["UnexpectedDynamicValue(PackageSpan { package: PackageId(2), span: Span { lo: 288, hi: 295 } })"], ); } @@ -1292,7 +1292,7 @@ fn call_to_unresolved_callee_via_closure_with_dynamic_arg_fails() { let error = get_partial_evaluation_error_with_capabilities( indoc! {" namespace Test { - open Microsoft.Quantum.Convert; + import Std.Convert.*; operation Op() : (Int, Qubit) => Unit { (i, q) => Rx(IntAsDouble(i), q) } @@ -1309,7 +1309,7 @@ fn call_to_unresolved_callee_via_closure_with_dynamic_arg_fails() { assert_error( &error, - &expect!["CapabilityError(UseOfDynamicDouble(Span { lo: 302, hi: 309 }))"], + &expect!["CapabilityError(UseOfDynamicDouble(Span { lo: 292, hi: 299 }))"], ); } @@ -1318,7 +1318,7 @@ fn call_to_unresolved_callee_with_static_arg_and_entry_return_value_succeeds() { let program = get_rir_program_with_capabilities( indoc! {" namespace Test { - open Microsoft.Quantum.Convert; + import Std.Convert.*; operation Op(i : Int, q : Qubit) : Unit { Rx(IntAsDouble(i), q); } diff --git a/compiler/qsc_partial_eval/src/tests/intrinsics.rs b/compiler/qsc_partial_eval/src/tests/intrinsics.rs index 8cff8f37f3..26ca88ba52 100644 --- a/compiler/qsc_partial_eval/src/tests/intrinsics.rs +++ b/compiler/qsc_partial_eval/src/tests/intrinsics.rs @@ -646,7 +646,7 @@ fn calls_to_intrinsic_begin_estimate_caching_with_classical_values_always_yield_ let program = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; operation Op(q : Qubit) : Unit { body intrinsic; } @EntryPoint() operation Main() : Unit { @@ -691,7 +691,7 @@ fn call_to_intrinsic_begin_estimate_caching_with_dynamic_values_yields_true() { let program = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; open QIR.Intrinsic; operation Op(q : Qubit) : Unit { body intrinsic; } @EntryPoint() @@ -786,7 +786,7 @@ fn call_to_intrinsic_end_estimate_caching_does_not_generate_instructions() { let program = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; @EntryPoint() operation Main() : Unit { EndEstimateCaching(); @@ -809,7 +809,7 @@ fn call_to_account_for_estimates_does_not_generate_instructions() { let program = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; @EntryPoint() operation Main() : Unit { // Calls to internal operation `AccountForEstimatesInternal`, which is intrinsic. @@ -833,7 +833,7 @@ fn call_to_begin_repeat_estimates_does_not_generate_instructions() { let program = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; @EntryPoint() operation Main() : Unit { // Calls to internal operation `BeginRepeatEstimatesInternal`, which is intrinsic. @@ -857,7 +857,7 @@ fn call_to_end_repeat_estimates_does_not_generate_instructions() { let program = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; @EntryPoint() operation Main() : Unit { // Calls to internal operation `EndRepeatEstimatesInternal`, which is intrinsic. @@ -881,7 +881,7 @@ fn call_to_dump_machine_does_not_generate_instructions() { let program = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Unit { DumpMachine(); @@ -904,7 +904,7 @@ fn call_to_dump_register_does_not_generate_instructions() { let program = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Unit { use q = Qubit(); @@ -929,7 +929,7 @@ fn call_to_check_zero_panics() { _ = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Unit { use q = Qubit(); @@ -946,7 +946,7 @@ fn call_to_draw_random_int_panics() { _ = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.Random; + import Std.Random.*; @EntryPoint() operation Main() : Unit { let _ = DrawRandomInt(0, 1); @@ -962,7 +962,7 @@ fn call_to_draw_random_double_panics() { _ = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.Random; + import Std.Random.*; @EntryPoint() operation Main() : Unit { let _ = DrawRandomDouble(0.0, 1.0); @@ -978,7 +978,7 @@ fn call_to_draw_random_bool_panics() { _ = get_rir_program(indoc! { r#" namespace Test { - open Microsoft.Quantum.Random; + import Std.Random.*; @EntryPoint() operation Main() : Unit { let _ = DrawRandomBool(0.0); diff --git a/compiler/qsc_partial_eval/src/tests/misc.rs b/compiler/qsc_partial_eval/src/tests/misc.rs index d05ea68a2a..3fdb33df0a 100644 --- a/compiler/qsc_partial_eval/src/tests/misc.rs +++ b/compiler/qsc_partial_eval/src/tests/misc.rs @@ -592,7 +592,7 @@ fn evaluation_error_within_stdlib_yield_correct_package_span() { let error = get_partial_evaluation_error(indoc! { r#" namespace Test { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; @EntryPoint() operation Main() : Result[] { use qs = Qubit[1]; @@ -602,5 +602,5 @@ fn evaluation_error_within_stdlib_yield_correct_package_span() { } "#, }); - assert_error(&error, &expect!["UnexpectedDynamicValue(PackageSpan { package: PackageId(1), span: Span { lo: 15851, hi: 15866 } })"]); + assert_error(&error, &expect!["UnexpectedDynamicValue(PackageSpan { package: PackageId(1), span: Span { lo: 13654, hi: 13669 } })"]); } diff --git a/compiler/qsc_partial_eval/src/tests/returns.rs b/compiler/qsc_partial_eval/src/tests/returns.rs index 8aeb6b3f6f..e296099fd3 100644 --- a/compiler/qsc_partial_eval/src/tests/returns.rs +++ b/compiler/qsc_partial_eval/src/tests/returns.rs @@ -886,7 +886,7 @@ fn explicit_return_embedded_in_assign_expr_yields_error() { fn explicit_return_embedded_in_assign_field_expr_yields_error() { let error = get_partial_evaluation_error(indoc! {r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; @EntryPoint() operation Main() : Bool { use q = Qubit(); // Needed to make `Main` non-classical. @@ -899,7 +899,7 @@ fn explicit_return_embedded_in_assign_field_expr_yields_error() { assert_error( &error, &expect![[ - r#"Unexpected("updating a field of a dynamic user-defined type is invalid", PackageSpan { package: PackageId(2), span: Span { lo: 217, hi: 243 } })"# + r#"Unexpected("updating a field of a dynamic user-defined type is invalid", PackageSpan { package: PackageId(2), span: Span { lo: 207, hi: 233 } })"# ]], ); } @@ -970,7 +970,7 @@ fn explicit_return_embedded_in_bin_op_expr_yields_error() { fn explicit_return_embedded_in_call_expr_yields_error() { let error = get_partial_evaluation_error(indoc! {r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; @EntryPoint() operation Main() : Bool { use q = Qubit(); // Needed to make `Main` non-classical. @@ -982,7 +982,7 @@ fn explicit_return_embedded_in_call_expr_yields_error() { assert_error( &error, &expect![[ - r#"Unexpected("embedded return in call arguments", PackageSpan { package: PackageId(2), span: Span { lo: 174, hi: 186 } })"# + r#"Unexpected("embedded return in call arguments", PackageSpan { package: PackageId(2), span: Span { lo: 164, hi: 176 } })"# ]], ); } @@ -991,7 +991,7 @@ fn explicit_return_embedded_in_call_expr_yields_error() { fn explicit_return_embedded_in_if_expr_yields_error() { let error = get_partial_evaluation_error(indoc! {r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; @EntryPoint() operation Main() : Bool { use q = Qubit(); // Needed to make `Main` non-classical. @@ -1005,7 +1005,7 @@ fn explicit_return_embedded_in_if_expr_yields_error() { assert_error( &error, &expect![[ - r#"Unexpected("embedded return in if condition", PackageSpan { package: PackageId(2), span: Span { lo: 175, hi: 187 } })"# + r#"Unexpected("embedded return in if condition", PackageSpan { package: PackageId(2), span: Span { lo: 165, hi: 177 } })"# ]], ); } @@ -1075,7 +1075,7 @@ fn explicit_return_embedded_in_unary_expr_yields_error() { fn explicit_return_embedded_in_update_field_expr_yields_error() { let error = get_partial_evaluation_error(indoc! {r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; @EntryPoint() operation Main() : Bool { use q = Qubit(); // Needed to make `Main` non-classical. @@ -1088,7 +1088,7 @@ fn explicit_return_embedded_in_update_field_expr_yields_error() { assert_error( &error, &expect![[ - r#"Unexpected("assigning a dynamic value to a field of a user-defined type is invalid", PackageSpan { package: PackageId(2), span: Span { lo: 211, hi: 241 } })"# + r#"Unexpected("assigning a dynamic value to a field of a user-defined type is invalid", PackageSpan { package: PackageId(2), span: Span { lo: 201, hi: 231 } })"# ]], ); } diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive.rs b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive.rs index 25f94904a9..57d468b5b1 100644 --- a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive.rs +++ b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive.rs @@ -57,8 +57,8 @@ fn use_of_dynamic_int_yields_error() { [ UseOfDynamicInt( Span { - lo: 246, - hi: 271, + lo: 226, + hi: 251, }, ), ] @@ -114,14 +114,14 @@ fn use_of_dynamic_double_yields_errors() { [ UseOfDynamicInt( Span { - lo: 246, - hi: 284, + lo: 226, + hi: 264, }, ), UseOfDynamicDouble( Span { - lo: 246, - hi: 284, + lo: 226, + hi: 264, }, ), ] @@ -154,14 +154,14 @@ fn use_of_dynamic_big_int_yields_errors() { [ UseOfDynamicInt( Span { - lo: 247, - hi: 285, + lo: 227, + hi: 265, }, ), UseOfDynamicBigInt( Span { - lo: 247, - hi: 285, + lo: 227, + hi: 265, }, ), ] @@ -217,20 +217,20 @@ fn use_of_dynamic_udt_yields_errors() { [ UseOfDynamicInt( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), UseOfDynamicDouble( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), UseOfDynamicUdt( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), ] @@ -246,8 +246,8 @@ fn use_of_dynamic_function_yields_errors() { [ UseOfDynamicArrowFunction( Span { - lo: 142, - hi: 166, + lo: 132, + hi: 156, }, ), ] @@ -263,8 +263,8 @@ fn use_of_dynamic_operation_yields_errors() { [ UseOfDynamicArrowOperation( Span { - lo: 142, - hi: 162, + lo: 132, + hi: 152, }, ), ] @@ -371,26 +371,26 @@ fn call_to_dynamic_function_yields_errors() { [ UseOfDynamicArrowFunction( Span { - lo: 142, - hi: 166, + lo: 132, + hi: 156, }, ), UseOfDynamicDouble( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), UseOfDynamicArrowFunction( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), CallToDynamicCallee( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), ] @@ -406,20 +406,20 @@ fn call_to_dynamic_operation_yields_errors() { [ UseOfDynamicArrowOperation( Span { - lo: 142, - hi: 162, + lo: 132, + hi: 152, }, ), UseOfDynamicArrowOperation( Span { - lo: 176, - hi: 181, + lo: 166, + hi: 171, }, ), CallToDynamicCallee( Span { - lo: 176, - hi: 181, + lo: 166, + hi: 171, }, ), ] @@ -455,20 +455,20 @@ fn use_of_dynamic_index_yields_errors() { [ UseOfDynamicInt( Span { - lo: 246, - hi: 271, + lo: 226, + hi: 251, }, ), UseOfDynamicInt( Span { - lo: 319, - hi: 323, + lo: 299, + hi: 303, }, ), UseOfDynamicIndex( Span { - lo: 319, - hi: 323, + lo: 299, + hi: 303, }, ), ] diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers.rs b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers.rs index d687b998d9..88a3640dd5 100644 --- a/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers.rs +++ b/compiler/qsc_passes/src/capabilitiesck/tests_adaptive_plus_integers.rs @@ -111,8 +111,8 @@ fn use_of_dynamic_double_yields_error() { [ UseOfDynamicDouble( Span { - lo: 246, - hi: 284, + lo: 226, + hi: 264, }, ), ] @@ -145,8 +145,8 @@ fn use_of_dynamic_big_int_yields_errors() { [ UseOfDynamicBigInt( Span { - lo: 247, - hi: 285, + lo: 227, + hi: 265, }, ), ] @@ -196,14 +196,14 @@ fn use_of_dynamic_udt_yields_errors() { [ UseOfDynamicDouble( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), UseOfDynamicUdt( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), ] @@ -219,8 +219,8 @@ fn use_of_dynamic_function_yields_errors() { [ UseOfDynamicArrowFunction( Span { - lo: 142, - hi: 166, + lo: 132, + hi: 156, }, ), ] @@ -236,8 +236,8 @@ fn use_of_dynamic_operation_yields_errors() { [ UseOfDynamicArrowOperation( Span { - lo: 142, - hi: 162, + lo: 132, + hi: 152, }, ), ] @@ -326,26 +326,26 @@ fn call_to_dynamic_function_yields_errors() { [ UseOfDynamicArrowFunction( Span { - lo: 142, - hi: 166, + lo: 132, + hi: 156, }, ), UseOfDynamicDouble( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), UseOfDynamicArrowFunction( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), CallToDynamicCallee( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), ] @@ -361,20 +361,20 @@ fn call_to_dynamic_operation_yields_errors() { [ UseOfDynamicArrowOperation( Span { - lo: 142, - hi: 162, + lo: 132, + hi: 152, }, ), UseOfDynamicArrowOperation( Span { - lo: 176, - hi: 181, + lo: 166, + hi: 171, }, ), CallToDynamicCallee( Span { - lo: 176, - hi: 181, + lo: 166, + hi: 171, }, ), ] @@ -410,8 +410,8 @@ fn use_of_dynamic_index_yields_errors() { [ UseOfDynamicIndex( Span { - lo: 319, - hi: 323, + lo: 299, + hi: 303, }, ), ] diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_base.rs b/compiler/qsc_passes/src/capabilitiesck/tests_base.rs index a721452013..c2622c6a36 100644 --- a/compiler/qsc_passes/src/capabilitiesck/tests_base.rs +++ b/compiler/qsc_passes/src/capabilitiesck/tests_base.rs @@ -64,14 +64,14 @@ fn use_of_dynamic_int_yields_errors() { [ UseOfDynamicBool( Span { - lo: 246, - hi: 271, + lo: 226, + hi: 251, }, ), UseOfDynamicInt( Span { - lo: 246, - hi: 271, + lo: 226, + hi: 251, }, ), ] @@ -136,20 +136,20 @@ fn use_of_dynamic_double_yields_errors() { [ UseOfDynamicBool( Span { - lo: 246, - hi: 284, + lo: 226, + hi: 264, }, ), UseOfDynamicInt( Span { - lo: 246, - hi: 284, + lo: 226, + hi: 264, }, ), UseOfDynamicDouble( Span { - lo: 246, - hi: 284, + lo: 226, + hi: 264, }, ), ] @@ -188,20 +188,20 @@ fn use_of_dynamic_big_int_yields_errors() { [ UseOfDynamicBool( Span { - lo: 247, - hi: 285, + lo: 227, + hi: 265, }, ), UseOfDynamicInt( Span { - lo: 247, - hi: 285, + lo: 227, + hi: 265, }, ), UseOfDynamicBigInt( Span { - lo: 247, - hi: 285, + lo: 227, + hi: 265, }, ), ] @@ -269,26 +269,26 @@ fn use_of_dynamic_udt_yields_errors() { [ UseOfDynamicBool( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), UseOfDynamicInt( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), UseOfDynamicDouble( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), UseOfDynamicUdt( Span { - lo: 283, - hi: 335, + lo: 253, + hi: 305, }, ), ] @@ -307,8 +307,8 @@ fn use_of_dynamic_function_yields_errors() { [ UseOfDynamicBool( Span { - lo: 142, - hi: 154, + lo: 132, + hi: 144, }, ), ] @@ -327,8 +327,8 @@ fn use_of_dynamic_operation_yields_errors() { [ UseOfDynamicBool( Span { - lo: 142, - hi: 154, + lo: 132, + hi: 144, }, ), ] @@ -447,32 +447,32 @@ fn call_to_dynamic_function_yields_errors() { [ UseOfDynamicBool( Span { - lo: 142, - hi: 154, + lo: 132, + hi: 144, }, ), UseOfDynamicBool( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), UseOfDynamicDouble( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), UseOfDynamicArrowFunction( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), CallToDynamicCallee( Span { - lo: 180, - hi: 188, + lo: 170, + hi: 178, }, ), ] @@ -488,26 +488,26 @@ fn call_to_dynamic_operation_yields_errors() { [ UseOfDynamicBool( Span { - lo: 142, - hi: 154, + lo: 132, + hi: 144, }, ), UseOfDynamicBool( Span { - lo: 176, - hi: 181, + lo: 166, + hi: 171, }, ), UseOfDynamicArrowOperation( Span { - lo: 176, - hi: 181, + lo: 166, + hi: 171, }, ), CallToDynamicCallee( Span { - lo: 176, - hi: 181, + lo: 166, + hi: 171, }, ), ] @@ -556,32 +556,32 @@ fn use_of_dynamic_index_yields_errors() { [ UseOfDynamicBool( Span { - lo: 246, - hi: 271, + lo: 226, + hi: 251, }, ), UseOfDynamicInt( Span { - lo: 246, - hi: 271, + lo: 226, + hi: 251, }, ), UseOfDynamicBool( Span { - lo: 319, - hi: 323, + lo: 299, + hi: 303, }, ), UseOfDynamicInt( Span { - lo: 319, - hi: 323, + lo: 299, + hi: 303, }, ), UseOfDynamicIndex( Span { - lo: 319, - hi: 323, + lo: 299, + hi: 303, }, ), ] diff --git a/compiler/qsc_passes/src/capabilitiesck/tests_common.rs b/compiler/qsc_passes/src/capabilitiesck/tests_common.rs index 93a5580af4..85185122a5 100644 --- a/compiler/qsc_passes/src/capabilitiesck/tests_common.rs +++ b/compiler/qsc_passes/src/capabilitiesck/tests_common.rs @@ -133,8 +133,8 @@ pub const USE_DYNAMIC_BOOLEAN: &str = r#" pub const USE_DYNAMIC_INT: &str = r#" namespace Test { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; operation Foo() : Unit { use register = Qubit[4]; let results = MeasureEachZ(register); @@ -160,8 +160,8 @@ pub const USE_DYNAMIC_RANGE: &str = r#" pub const USE_DYNAMIC_DOUBLE: &str = r#" namespace Test { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; operation Foo() : Unit { use register = Qubit[4]; let results = MeasureEachZ(register); @@ -181,8 +181,8 @@ pub const USE_DYNAMIC_QUBIT: &str = r#" pub const USE_DYNAMIC_BIG_INT: &str = r#" namespace Test { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; operation Foo() : Unit { use register = Qubit[4]; let results = MeasureEachZ(register); @@ -209,9 +209,9 @@ pub const USE_DYNAMICALLY_SIZED_ARRAY: &str = r#" pub const USE_DYNAMIC_UDT: &str = r#" namespace Test { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Math.*; + import Std.Measurement.*; operation Foo() : Unit { use register = Qubit[4]; let results = MeasureEachZ(register); @@ -221,7 +221,7 @@ pub const USE_DYNAMIC_UDT: &str = r#" pub const USE_DYNAMIC_FUNCTION: &str = r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; operation Foo() : Unit { use q = Qubit(); let fn = M(q) == Zero ? Cos | Sin; @@ -230,7 +230,7 @@ pub const USE_DYNAMIC_FUNCTION: &str = r#" pub const USE_DYNAMIC_OPERATION: &str = r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; operation Foo() : Unit { use q = Qubit(); let op = M(q) == Zero ? X | Y; @@ -289,7 +289,7 @@ pub const CALL_TO_CYCLIC_OPERATION_WITH_DYNAMIC_ARGUMENT: &str = r#" pub const CALL_DYNAMIC_FUNCTION: &str = r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; operation Foo() : Unit { use q = Qubit(); let fn = M(q) == Zero ? Cos | Sin; @@ -299,7 +299,7 @@ pub const CALL_DYNAMIC_FUNCTION: &str = r#" pub const CALL_DYNAMIC_OPERATION: &str = r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; operation Foo() : Unit { use q = Qubit(); let op = M(q) == Zero ? X | Y; @@ -309,7 +309,7 @@ pub const CALL_DYNAMIC_OPERATION: &str = r#" pub const CALL_UNRESOLVED_FUNCTION: &str = r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; operation Foo() : Unit { use q = Qubit(); let fn = true ? Cos | Sin; @@ -329,8 +329,8 @@ pub const MEASUREMENT_WITHIN_DYNAMIC_SCOPE: &str = r#" pub const USE_DYNAMIC_INDEX: &str = r#" namespace Test { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; operation Foo() : Unit { use register = Qubit[2]; let results = MeasureEachZ(register); @@ -380,7 +380,7 @@ pub const LOOP_WITH_DYNAMIC_CONDITION: &str = r#" pub const USE_CLOSURE_FUNCTION: &str = r#" namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; operation Foo() : Unit { let theta = PI(); let lambdaFn = theta -> Sin(theta); diff --git a/compiler/qsc_rca/src/tests/arrays.rs b/compiler/qsc_rca/src/tests/arrays.rs index f7ada8b4ef..a06c919d48 100644 --- a/compiler/qsc_rca/src/tests/arrays.rs +++ b/compiler/qsc_rca/src/tests/arrays.rs @@ -50,7 +50,7 @@ fn check_rca_for_array_with_dynamic_bools() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; + import Std.Convert.*; use (a, b, c) = (Qubit(), Qubit(), Qubit()); [ResultAsBool(M(a)), ResultAsBool(M(b)), ResultAsBool(M(c))]"#, ); @@ -111,7 +111,7 @@ fn check_rca_for_array_repeat_with_dynamic_bool_value_and_classical_size() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; + import Std.Convert.*; use q = Qubit(); [ResultAsBool(M(q)), size = 11]"#, ); @@ -157,7 +157,7 @@ fn check_rca_for_array_repeat_with_dynamic_double_value_and_dynamic_size() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; + import Std.Convert.*; use q = Qubit(); let r = M(q); let s = r == Zero ? 5 | 10; diff --git a/compiler/qsc_rca/src/tests/assigns.rs b/compiler/qsc_rca/src/tests/assigns.rs index ae086e26e6..69d47b486c 100644 --- a/compiler/qsc_rca/src/tests/assigns.rs +++ b/compiler/qsc_rca/src/tests/assigns.rs @@ -56,7 +56,7 @@ fn check_rca_for_dynamic_bool_assign_to_local() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; + import Std.Convert.*; use q = Qubit(); mutable b = false; set b = ResultAsBool(M(q)); @@ -81,8 +81,8 @@ fn check_rca_for_dynamic_int_assign_to_local() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); mutable i = 0; @@ -108,8 +108,8 @@ fn check_rca_for_dynamic_double_assign_to_local() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); let i = ResultArrayAsInt(results); @@ -319,8 +319,8 @@ fn check_rca_for_mutable_classical_integer_assigned_updated_with_classical_integ let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); mutable i = 0; @@ -342,8 +342,8 @@ fn check_rca_for_mutable_classical_integer_assigned_updated_with_dynamic_integer let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); mutable i = 0; @@ -367,8 +367,8 @@ fn check_rca_for_mutable_dynamic_integer_assigned_updated_with_classical_integer let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); mutable i = ResultArrayAsInt(results); @@ -392,8 +392,8 @@ fn check_rca_for_mutable_dynamic_integer_assigned_updated_with_dynamic_integer() let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); mutable i = ResultArrayAsInt(results); diff --git a/compiler/qsc_rca/src/tests/bindings.rs b/compiler/qsc_rca/src/tests/bindings.rs index 18e5b0400d..c188c431c7 100644 --- a/compiler/qsc_rca/src/tests/bindings.rs +++ b/compiler/qsc_rca/src/tests/bindings.rs @@ -76,7 +76,7 @@ fn check_rca_for_mutable_dynamic_bool_binding() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; + import Std.Convert.*; use q = Qubit(); mutable b = ResultAsBool(M(q)); b"#, @@ -120,8 +120,8 @@ fn check_rca_for_immutable_dynamic_int_binding() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); let i = ResultArrayAsInt(results); @@ -166,8 +166,8 @@ fn check_rca_for_mutable_dynamic_double_binding() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); let i = ResultArrayAsInt(results); diff --git a/compiler/qsc_rca/src/tests/binops.rs b/compiler/qsc_rca/src/tests/binops.rs index aa285a70a8..e02771db4d 100644 --- a/compiler/qsc_rca/src/tests/binops.rs +++ b/compiler/qsc_rca/src/tests/binops.rs @@ -94,7 +94,7 @@ fn check_rca_for_nested_bin_ops_with_classic_operands() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; Sin(PI() / 2.0) ^ 2.0 + Cos(PI() / 2.0) ^ 2.0"#, ); let package_store_compute_properties = compilation_context.get_compute_properties(); diff --git a/compiler/qsc_rca/src/tests/callables.rs b/compiler/qsc_rca/src/tests/callables.rs index ea778bf4c0..958e01cb04 100644 --- a/compiler/qsc_rca/src/tests/callables.rs +++ b/compiler/qsc_rca/src/tests/callables.rs @@ -14,7 +14,7 @@ fn check_rca_for_closure_function_with_classical_captured_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; let f = i -> IsCoprimeI(11, i); f"#, ); @@ -34,7 +34,7 @@ fn check_rca_for_closure_function_with_dynamic_captured_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; use q = Qubit(); let dynamicInt = M(q) == Zero ? 11 | 13; let f = i -> IsCoprimeI(dynamicInt, i); @@ -56,7 +56,7 @@ fn check_rca_for_closure_operation_with_classical_captured_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; let theta = PI(); let f = q => Rx(theta, q); f"#, @@ -77,7 +77,7 @@ fn check_rca_for_closure_operation_with_dynamic_captured_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; use qubit = Qubit(); let theta = M(qubit) == Zero ? PI() | PI() / 2.0; let f = q => Rx(theta, q); diff --git a/compiler/qsc_rca/src/tests/calls.rs b/compiler/qsc_rca/src/tests/calls.rs index dfbded07a9..d5c76bd899 100644 --- a/compiler/qsc_rca/src/tests/calls.rs +++ b/compiler/qsc_rca/src/tests/calls.rs @@ -115,7 +115,7 @@ fn check_rca_for_call_to_static_closure_function() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; let f = i -> IsCoprimeI(11, i); f(13)"#, ); @@ -135,7 +135,7 @@ fn check_rca_for_call_to_dynamic_closure_function() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; use q = Qubit(); let dynamicInt = M(q) == Zero ? 11 | 13; let f = i -> IsCoprimeI(dynamicInt, i); @@ -159,7 +159,7 @@ fn check_rca_for_call_to_static_closure_operation() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; use qubit = Qubit(); let theta = PI(); let f = q => Rx(theta, q); @@ -183,7 +183,7 @@ fn check_rca_for_call_to_dynamic_closure_operation() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; use qubit = Qubit(); let theta = M(qubit) == Zero ? PI() | PI() / 2.0; let f = q => Rx(theta, q); diff --git a/compiler/qsc_rca/src/tests/cycles.rs b/compiler/qsc_rca/src/tests/cycles.rs index e8cf28694b..64d2c0d2d8 100644 --- a/compiler/qsc_rca/src/tests/cycles.rs +++ b/compiler/qsc_rca/src/tests/cycles.rs @@ -376,7 +376,7 @@ fn check_rca_for_function_cycle_within_call_input() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; function MySorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : 'T[] { if Length(array) <= 1 { return array; diff --git a/compiler/qsc_rca/src/tests/ifs.rs b/compiler/qsc_rca/src/tests/ifs.rs index 0b671f67c8..da99dac810 100644 --- a/compiler/qsc_rca/src/tests/ifs.rs +++ b/compiler/qsc_rca/src/tests/ifs.rs @@ -13,7 +13,7 @@ fn check_rca_for_if_stmt_with_classic_condition_and_classic_if_true_block() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; operation Foo() : Unit { if true { let s = Sqrt(4.0); @@ -42,7 +42,7 @@ fn check_rca_for_if_stmt_with_dynamic_condition_and_classic_if_true_block() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; operation Foo() : Unit { use q = Qubit(); if M(q) == Zero { diff --git a/compiler/qsc_rca/src/tests/measurements.rs b/compiler/qsc_rca/src/tests/measurements.rs index 2e4622881f..f45cb37d73 100644 --- a/compiler/qsc_rca/src/tests/measurements.rs +++ b/compiler/qsc_rca/src/tests/measurements.rs @@ -57,7 +57,7 @@ fn check_rca_for_static_single_measurement_and_reset() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; use q = Qubit(); MResetZ(q)"#, ); @@ -80,7 +80,7 @@ fn check_rca_for_dynamic_single_measurement_and_reset() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; use (condition, target) = (Qubit(), Qubit()); mutable r = Zero; if MResetZ(condition) == Zero { @@ -105,7 +105,7 @@ fn check_rca_for_static_multi_qubit_measurement() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; use register = Qubit[2]; MeasureEachZ(register)"#, ); diff --git a/compiler/qsc_rca/src/tests/structs.rs b/compiler/qsc_rca/src/tests/structs.rs index 0b7d04e757..99170918f0 100644 --- a/compiler/qsc_rca/src/tests/structs.rs +++ b/compiler/qsc_rca/src/tests/structs.rs @@ -11,7 +11,7 @@ fn check_rca_for_struct_constructor_with_classical_values() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; new Complex { Real = 0.0, Imag = 0.0 }"#, ); let package_store_compute_properties = compilation_context.get_compute_properties(); @@ -31,7 +31,7 @@ fn check_rca_for_struct_constructor_with_a_dynamic_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; use q = Qubit(); let r = M(q) == Zero ? 0.0 | 1.0; new Complex { Real = r, Imag = 0.0 }"#, @@ -55,7 +55,7 @@ fn check_rca_for_struct_copy_constructor_with_classical_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; let c = new Complex { Real = 0.0, Imag = 0.0 }; new Complex { ...c, Real = 1.0 }"#, ); @@ -76,7 +76,7 @@ fn check_rca_for_struct_copy_constructor_with_dynamic_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; let c = new Complex { Real = 0.0, Imag = 0.0 }; use q = Qubit(); let i = M(q) == Zero ? 0.0 | 1.0; @@ -101,7 +101,7 @@ fn check_rca_for_struct_dynamic_constructor_overwritten_with_classic_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; use q = Qubit(); let i = M(q) == Zero ? 0.0 | 1.0; let c = new Complex { Real = 0.0, Imag = i }; diff --git a/compiler/qsc_rca/src/tests/types.rs b/compiler/qsc_rca/src/tests/types.rs index 1bd2714cf3..9c5d5ad339 100644 --- a/compiler/qsc_rca/src/tests/types.rs +++ b/compiler/qsc_rca/src/tests/types.rs @@ -65,7 +65,7 @@ fn check_rca_for_dynamic_bool() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; + import Std.Convert.*; use q = Qubit(); ResultAsBool(M(q))"#, ); @@ -104,8 +104,8 @@ fn check_rca_for_dynamic_int() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); ResultArrayAsInt(results)"#, @@ -222,8 +222,8 @@ fn check_rca_for_dynamic_double() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Measurement; + import Std.Convert.*; + import Std.Measurement.*; use register = Qubit[8]; let results = MeasureEachZ(register); let i = ResultArrayAsInt(results); diff --git a/compiler/qsc_rca/src/tests/udts.rs b/compiler/qsc_rca/src/tests/udts.rs index 8b00582ab4..715aa33afe 100644 --- a/compiler/qsc_rca/src/tests/udts.rs +++ b/compiler/qsc_rca/src/tests/udts.rs @@ -11,7 +11,7 @@ fn check_rca_for_udt_constructor_with_classical_values() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; Complex(0.0, 0.0)"#, ); let package_store_compute_properties = compilation_context.get_compute_properties(); @@ -31,7 +31,7 @@ fn check_rca_for_udt_constructor_with_a_dynamic_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; use q = Qubit(); let r = M(q) == Zero ? 0.0 | 1.0; Complex(r, 0.0)"#, @@ -55,7 +55,7 @@ fn check_rca_for_udt_field_update_with_classical_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; mutable c = Complex(0.0, 0.0); set c w/= Real <- 1.0; c"#, @@ -77,7 +77,7 @@ fn check_rca_for_udt_field_update_with_dynamic_value() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; mutable c = Complex(0.0, 0.0); use q = Qubit(); let i = M(q) == Zero ? 0.0 | 1.0; diff --git a/compiler/qsc_rca/src/tests/vars.rs b/compiler/qsc_rca/src/tests/vars.rs index 7816e63659..b4bf2890e5 100644 --- a/compiler/qsc_rca/src/tests/vars.rs +++ b/compiler/qsc_rca/src/tests/vars.rs @@ -27,7 +27,7 @@ fn check_rca_for_udt_var() { let mut compilation_context = CompilationContext::default(); compilation_context.update( r#" - open Microsoft.Quantum.Math; + import Std.Math.*; Complex"#, ); let package_store_compute_properties = compilation_context.get_compute_properties(); diff --git a/fuzz/seed_inputs/compile/input.qs b/fuzz/seed_inputs/compile/input.qs index db249c897b..0f5656a824 100644 --- a/fuzz/seed_inputs/compile/input.qs +++ b/fuzz/seed_inputs/compile/input.qs @@ -1,21 +1,21 @@ // namespace Fuzz.Testing { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Characterization; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Logical; - open Microsoft.Quantum.MachineLearning; - open Microsoft.Quantum.MachineLearning.Datasets as Datasets; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Preparation; - open Microsoft.Quantum.Random; - open Microsoft.Quantum.Simulation; - open Microsoft.Quantum.Synthesis; - open Microsoft.Quantum.Targeting; + import Std.Arrays.*; + import Std.Canon.*; + import Std.Characterization.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Intrinsic.*; + import Std.Logical.*; + import Std.MachineLearning.*; + import Std.MachineLearning.Datasets as Datasets.*; + import Std.Math.*; + import Std.Measurement.*; + import Std.Preparation.*; + import Std.Random.*; + import Std.Simulation.*; + import Std.Synthesis.*; + import Std.Targeting.*; function IfRetExpr(cond : Bool, a : Int, b : Int) : Int { let x = if cond { a } else { b }; diff --git a/language_service/src/completion.rs b/language_service/src/completion.rs index e8af05f39f..f2ebdb23b0 100644 --- a/language_service/src/completion.rs +++ b/language_service/src/completion.rs @@ -121,9 +121,9 @@ pub(crate) fn get_completions( }; let mut prelude_ns_ids: Vec = PRELUDE - .into_iter() + .iter() .map(|ns| ImportItem { - path: ns.into_iter().map(Rc::from).collect(), + path: ns.iter().map(|x| Rc::from(*x)).collect(), alias: None, is_glob: true, }) diff --git a/language_service/src/completion/tests.rs b/language_service/src/completion/tests.rs index c22a8e5535..8cce3183c5 100644 --- a/language_service/src/completion/tests.rs +++ b/language_service/src/completion/tests.rs @@ -146,7 +146,7 @@ fn ignore_unstable_callable() { check( r#" namespace Test { - open Microsoft.Quantum.Unstable; + import Microsoft.Quantum.Unstable.*; operation Foo() : Unit { ↘ } diff --git a/library/fixed_point/qsharp.json b/library/fixed_point/qsharp.json index 78cdd82d68..a966a4309b 100644 --- a/library/fixed_point/qsharp.json +++ b/library/fixed_point/qsharp.json @@ -3,12 +3,7 @@ "license": "MIT", "dependencies": { "Signed": { - "github": { - "owner": "microsoft", - "repo": "qsharp", - "ref": "adcefe8", - "path": "library/signed" - } + "path": "/Users/alexanderhansen/code/qsharp/library/signed" }, "Unstable": { "github": { @@ -32,4 +27,4 @@ "src/Tests.qs", "src/Types.qs" ] -} +} \ No newline at end of file diff --git a/library/src/lib.rs b/library/src/lib.rs index bef834659a..c0f28dfeda 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -22,65 +22,65 @@ pub const CORE_LIB: &[(&str, &str)] = &[ pub const STD_LIB: &[(&str, &str)] = &[ ( - "qsharp-library-source:arrays.qs", - include_str!("../std/src/arrays.qs"), + "qsharp-library-source:Std/Arrays.qs", + include_str!("../std/src/Std/Arrays.qs"), ), ( - "qsharp-library-source:canon.qs", - include_str!("../std/src/canon.qs"), + "qsharp-library-source:Std/Canon.qs", + include_str!("../std/src/Std/Canon.qs"), ), ( - "qsharp-library-source:convert.qs", - include_str!("../std/src/convert.qs"), + "qsharp-library-source:Std/Convert.qs", + include_str!("../std/src/Std/Convert.qs"), ), ( "qsharp-library-source:core.qs", include_str!("../std/src/core.qs"), ), ( - "qsharp-library-source:diagnostics.qs", - include_str!("../std/src/diagnostics.qs"), + "qsharp-library-source:Std/Diagnostics.qs", + include_str!("../std/src/Std/Diagnostics.qs"), ), ( - "qsharp-library-source:internal.qs", - include_str!("../std/src/internal.qs"), + "qsharp-library-source:Std/InternalHelpers.qs", + include_str!("../std/src/Std/InternalHelpers.qs"), ), ( - "qsharp-library-source:intrinsic.qs", - include_str!("../std/src/intrinsic.qs"), + "qsharp-library-source:Std/Intrinsic.qs", + include_str!("../std/src/Std/Intrinsic.qs"), ), ( - "qsharp-library-source:logical.qs", - include_str!("../std/src/logical.qs"), + "qsharp-library-source:Std/Logical.qs", + include_str!("../std/src/Std/Logical.qs"), ), ( - "qsharp-library-source:math.qs", - include_str!("../std/src/math.qs"), + "qsharp-library-source:Std/Math.qs", + include_str!("../std/src/Std/Math.qs"), ), ( - "qsharp-library-source:measurement.qs", - include_str!("../std/src/measurement.qs"), + "qsharp-library-source:Std/Measurement.qs", + include_str!("../std/src/Std/Measurement.qs"), ), ( - "qsharp-library-source:qir.qs", - include_str!("../std/src/qir.qs"), + "qsharp-library-source:QIR/Intrinsic.qs", + include_str!("../std/src/QIR/Intrinsic.qs"), ), ( - "qsharp-library-source:random.qs", - include_str!("../std/src/random.qs"), + "qsharp-library-source:Std/Random.qs", + include_str!("../std/src/Std/Random.qs"), ), ( - "qsharp-library-source:re.qs", - include_str!("../std/src/re.qs"), - ), - ( - "qsharp-library-source:unstable_arithmetic.qs", - include_str!("../std/src/unstable_arithmetic.qs"), + "qsharp-library-source:Std/ResourceEstimation.qs", + include_str!("../std/src/Std/ResourceEstimation.qs"), ), ( "qsharp-library-source:unstable_arithmetic_internal.qs", include_str!("../std/src/unstable_arithmetic_internal.qs"), ), + ( + "qsharp-library-source:unstable_arithmetic.qs", + include_str!("../std/src/unstable_arithmetic.qs"), + ), ( "qsharp-library-source:unstable_state_preparation.qs", include_str!("../std/src/unstable_state_preparation.qs"), @@ -90,7 +90,7 @@ pub const STD_LIB: &[(&str, &str)] = &[ include_str!("../std/src/unstable_table_lookup.qs"), ), ( - "qsharp-library-source:modern_api.qs", - include_str!("../std/src/modern_api.qs"), + "qsharp-library-source:legacy_api.qs", + include_str!("../std/src/legacy_api.qs"), ), ]; diff --git a/library/src/tests.rs b/library/src/tests.rs index 0d2ab8b81b..246d0ad57f 100644 --- a/library/src/tests.rs +++ b/library/src/tests.rs @@ -137,8 +137,8 @@ fn check_exp_with_cnot() { // sign convention between Rx, Rz, and Exp is consistent. test_expression( indoc! {r#"{ - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; + import Std.Diagnostics.*; + import Std.Math.*; use (aux, control, target) = (Qubit(), Qubit(), Qubit()); within { @@ -166,8 +166,8 @@ fn check_exp_with_swap() { // This decomposition only holds if the magnitude of the angle used in Exp is correct. test_expression( indoc! {r#"{ - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; + import Std.Diagnostics.*; + import Std.Math.*; use (aux, qs) = (Qubit(), Qubit[2]); within { diff --git a/library/src/tests/arithmetic.rs b/library/src/tests/arithmetic.rs index 6254d2f692..274e2eec18 100644 --- a/library/src/tests/arithmetic.rs +++ b/library/src/tests/arithmetic.rs @@ -11,7 +11,7 @@ fn check_maj() { test_expression( { "{ - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use q = Qubit[3]; mutable r = []; for i in 0..7 { @@ -44,8 +44,8 @@ fn check_reflect_about_integer() { test_expression( { "{ - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.Diagnostics; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Std.Diagnostics.*; operation ManuallyReflectAboutFive(register : Qubit[]) : Unit is Adj + Ctl { within { X(register[1]); @@ -106,7 +106,7 @@ fn check_inc_by_le_general() { test_expression( { "{ // General cases for IncByLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use x1 = Qubit[10]; use y1 = Qubit[10]; ApplyXorInPlace(279, x1); @@ -171,7 +171,7 @@ fn check_ripple_carry_ttk_inc_by_le_general() { test_expression( { "{ // General cases for RippleCarryTTKIncByLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use x1 = Qubit[10]; use y1 = Qubit[10]; @@ -276,7 +276,7 @@ fn check_ripple_carry_cg_inc_by_le_general() { test_expression( { "{ // General cases for RippleCarryCGIncByLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use x1 = Qubit[10]; use y1 = Qubit[10]; @@ -334,7 +334,7 @@ fn check_fourier_td_inc_by_le_exhaustive_bitwidth_3() { #[test] fn check_inc_by_le_using_add_le_exhaustive_bitwidth_1() { test_expression_with_lib( - "{open Microsoft.Quantum.Unstable.Arithmetic; + "{import Microsoft.Quantum.Unstable.Arithmetic.*; Test.TestIncByLE2(\"Check IncByLEUsingAddLE\", IncByLEUsingAddLE(LookAheadDKRSAddLE,RippleCarryCGAddLE,_,_), 1, 1)}", @@ -346,7 +346,7 @@ fn check_inc_by_le_using_add_le_exhaustive_bitwidth_1() { #[test] fn check_inc_by_le_using_add_le_exhaustive_bitwidth_2() { test_expression_with_lib( - "{open Microsoft.Quantum.Unstable.Arithmetic; + "{import Microsoft.Quantum.Unstable.Arithmetic.*; Test.TestIncByLE2(\"Check IncByLEUsingAddLE\", IncByLEUsingAddLE(LookAheadDKRSAddLE,RippleCarryCGAddLE,_,_), 2, 2)}", @@ -358,7 +358,7 @@ fn check_inc_by_le_using_add_le_exhaustive_bitwidth_2() { #[test] fn check_inc_by_le_using_add_le_exhaustive_bitwidth_3() { test_expression_with_lib( - "{open Microsoft.Quantum.Unstable.Arithmetic; + "{import Microsoft.Quantum.Unstable.Arithmetic.*; Test.TestIncByLE2(\"Check IncByLEUsingAddLE\", IncByLEUsingAddLE(LookAheadDKRSAddLE,RippleCarryCGAddLE,_,_), 3, 3)}", @@ -370,7 +370,7 @@ fn check_inc_by_le_using_add_le_exhaustive_bitwidth_3() { #[test] fn check_inc_by_le_using_add_le_exhaustive_bitwidth_4() { test_expression_with_lib( - "{open Microsoft.Quantum.Unstable.Arithmetic; + "{import Microsoft.Quantum.Unstable.Arithmetic.*; Test.TestIncByLE2(\"Check IncByLEUsingAddLE\", IncByLEUsingAddLE(LookAheadDKRSAddLE,RippleCarryCGAddLE,_,_), 4, 4)}", @@ -382,7 +382,7 @@ fn check_inc_by_le_using_add_le_exhaustive_bitwidth_4() { #[test] fn check_inc_by_le_using_add_le_ctl_exhaustive_bitwidth_1() { test_expression_with_lib( - "{open Microsoft.Quantum.Unstable.Arithmetic; + "{import Microsoft.Quantum.Unstable.Arithmetic.*; Test.TestIncByLECtl2(\"Check IncByLEUsingAddLE(Ctl)\", IncByLEUsingAddLE(LookAheadDKRSAddLE,RippleCarryCGAddLE,_,_), 1, 1)}", @@ -394,7 +394,7 @@ fn check_inc_by_le_using_add_le_ctl_exhaustive_bitwidth_1() { #[test] fn check_inc_by_le_using_add_le_ctl_exhaustive_bitwidth_2() { test_expression_with_lib( - "{open Microsoft.Quantum.Unstable.Arithmetic; + "{import Microsoft.Quantum.Unstable.Arithmetic.*; Test.TestIncByLECtl2(\"Check IncByLEUsingAddLE(Ctl)\", IncByLEUsingAddLE(LookAheadDKRSAddLE,RippleCarryCGAddLE,_,_), 2, 2)}", @@ -406,7 +406,7 @@ fn check_inc_by_le_using_add_le_ctl_exhaustive_bitwidth_2() { #[test] fn check_inc_by_le_using_add_le_ctl_exhaustive_bitwidth_3() { test_expression_with_lib( - "{open Microsoft.Quantum.Unstable.Arithmetic; + "{import Microsoft.Quantum.Unstable.Arithmetic.*; Test.TestIncByLECtl2(\"Check IncByLEUsingAddLE(Ctl)\", IncByLEUsingAddLE(LookAheadDKRSAddLE,RippleCarryCGAddLE,_,_), 3, 3)}", @@ -418,7 +418,7 @@ fn check_inc_by_le_using_add_le_ctl_exhaustive_bitwidth_3() { #[test] fn check_inc_by_le_using_add_le_ctl_exhaustive_bitwidth_4() { test_expression_with_lib( - "{open Microsoft.Quantum.Unstable.Arithmetic; + "{import Microsoft.Quantum.Unstable.Arithmetic.*; Test.TestIncByLECtl2(\"Check IncByLEUsingAddLE(Ctl)\", IncByLEUsingAddLE(LookAheadDKRSAddLE,RippleCarryCGAddLE,_,_), 4, 4)}", @@ -432,7 +432,7 @@ fn check_inc_by_le_using_add_le_general() { test_expression( { "{ // General cases for IncByLEUsingAddLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use x1 = Qubit[10]; use y1 = Qubit[10]; @@ -458,7 +458,7 @@ fn check_inc_by_i_general() { test_expression( { "{ // General cases for IncByI - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use y0 = Qubit[1]; IncByI(0,y0); // 0 += 0 @@ -513,7 +513,7 @@ fn check_ripple_carry_cg_inc_by_i_general() { test_expression( { "{ // General cases for IncByIUsingIncByLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use y0 = Qubit[10]; ApplyXorInPlace(172, y0); @@ -549,7 +549,7 @@ fn check_inc_by_l_general() { test_expression( { "{ // General cases for IncByL - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use y0 = Qubit[1]; IncByL(0L,y0); // 0 += 0 @@ -604,7 +604,7 @@ fn check_ripple_carry_cg_inc_by_l_general() { test_expression( { "{ // Branching cases for IncByLUsingIncByLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use y0 = Qubit[10]; ApplyXorInPlace(172, y0); @@ -682,7 +682,7 @@ fn check_add_le_general() { test_expression( { "{ // General cases for AddLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use x1 = Qubit[10]; use y1 = Qubit[10]; @@ -751,7 +751,7 @@ fn check_ripple_carry_cg_add_le_general() { test_expression( { "{ // General cases for RippleCarryAddLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use x1 = Qubit[10]; use y1 = Qubit[10]; @@ -818,7 +818,7 @@ fn check_lookahead_dkrs_add_le_general() { test_expression( { "{ // General cases for LookAheadDKRSAddLE - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use x1 = Qubit[10]; use y1 = Qubit[10]; @@ -952,7 +952,7 @@ fn check_apply_if_greater_le_exhaustive() { fn check_apply_if_less_l_non_x_action() { test_expression( "{ - open Microsoft.Quantum.Unstable.Arithmetic; + import Microsoft.Quantum.Unstable.Arithmetic.*; use input = Qubit[10]; use output1 = Qubit[10]; use output2 = Qubit[10]; diff --git a/library/src/tests/convert.rs b/library/src/tests/convert.rs index c526e9ab96..415dbe0a0b 100644 --- a/library/src/tests/convert.rs +++ b/library/src/tests/convert.rs @@ -255,7 +255,7 @@ fn test_complex_as_complex_polar() { test_expression( { "{ - open Microsoft.Quantum.Math; + import Std.Math.*; let a = Complex(2.0*Cos(1.0), 2.0*Sin(1.0)); Microsoft.Quantum.Convert.ComplexAsComplexPolar(a) }" @@ -269,7 +269,7 @@ fn test_complex_polar_as_complex() { test_expression( { "{ - open Microsoft.Quantum.Math; + import Std.Math.*; let a = ComplexPolar(Sqrt(5.0), ArcTan2(1.0, 2.0)); Microsoft.Quantum.Convert.ComplexPolarAsComplex(a) }" diff --git a/library/src/tests/diagnostics.rs b/library/src/tests/diagnostics.rs index 4e3de801db..449cd25a1e 100644 --- a/library/src/tests/diagnostics.rs +++ b/library/src/tests/diagnostics.rs @@ -8,8 +8,8 @@ use qsc::interpret::Value; fn check_operations_are_equal() { test_expression( "{ - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; + import Std.Diagnostics.*; + import Std.Arrays.*; operation op1(xs: Qubit[]): Unit is Adj { CCNOT(xs[0], xs[1], xs[2]); } diff --git a/library/src/tests/math.rs b/library/src/tests/math.rs index 61becf4271..b1d8c85eab 100644 --- a/library/src/tests/math.rs +++ b/library/src/tests/math.rs @@ -615,12 +615,12 @@ fn check_cfc_l() { #[test] fn check_real_mod() { test_expression( - "{ open Microsoft.Quantum.Math; + "{ import Std.Math.*; RealMod(5.5 * PI(), 2.0 * PI(), 0.0) }", &Value::Double(1.5 * PI), ); test_expression( - "{ open Microsoft.Quantum.Math; + "{ import Std.Math.*; RealMod(0.5 * PI(), 2.0 * PI(), -PI()/2.0) }", &Value::Double(0.5 * PI), ); @@ -866,13 +866,13 @@ fn check_p_normalized() { fn check_abs_squared_complex() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; AbsSquaredComplex(Complex(1.0,1.0))}", &Value::Double(2.0), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; AbsSquaredComplex(Complex(-3.0,4.0))}", &Value::Double(25.0), ); @@ -882,13 +882,13 @@ fn check_abs_squared_complex() { fn check_abs_complex() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; AbsComplex(Complex(1.0,1.0))}", &Value::Double(2.0_f64.sqrt()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; AbsComplex(Complex(-3.0,4.0))}", &Value::Double(5.0), ); @@ -898,13 +898,13 @@ fn check_abs_complex() { fn check_arg_complex() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; ArgComplex(Complex(100.0,0.0))}", &Value::Double(0.0), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; ArgComplex(Complex(1.0,1.0))}", &Value::Double(PI / 4.0), ); @@ -914,13 +914,13 @@ fn check_arg_complex() { fn check_abs_squared_complex_polar() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; AbsSquaredComplexPolar(ComplexPolar(1.0,2.0))}", &Value::Double(1.0), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; AbsSquaredComplexPolar(ComplexPolar(5.0,-1.0))}", &Value::Double(25.0), ); @@ -930,13 +930,13 @@ fn check_abs_squared_complex_polar() { fn check_abs_complex_polar() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; AbsComplexPolar(ComplexPolar(1.0,2.0))}", &Value::Double(1.0), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; AbsComplexPolar(ComplexPolar(5.0,-1.0))}", &Value::Double(5.0), ); @@ -946,13 +946,13 @@ fn check_abs_complex_polar() { fn check_arg_complex_polar() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; ArgComplexPolar(ComplexPolar(1.0,2.0))}", &Value::Double(2.0), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; ArgComplexPolar(ComplexPolar(5.0,-1.0))}", &Value::Double(-1.0), ); @@ -962,13 +962,13 @@ fn check_arg_complex_polar() { fn check_negation_c() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; NegationC(Complex(1.0,2.0))}", &Value::Tuple(vec![Value::Double(-1.0), Value::Double(-2.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; NegationC(Complex(5.0,-1.0))}", &Value::Tuple(vec![Value::Double(-5.0), Value::Double(1.0)].into()), ); @@ -978,13 +978,13 @@ fn check_negation_c() { fn check_negation_cp() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; NegationCP(ComplexPolar(1.0,0.0))}", &Value::Tuple(vec![Value::Double(1.0), Value::Double(PI)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; NegationCP(ComplexPolar(5.0,-PI()/2.0))}", &Value::Tuple(vec![Value::Double(5.0), Value::Double(PI / 2.0)].into()), ); @@ -994,13 +994,13 @@ fn check_negation_cp() { fn check_plus_c() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; PlusC(Complex(1.0,0.0), Complex(0.0,1.0))}", &Value::Tuple(vec![Value::Double(1.0), Value::Double(1.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; PlusC(Complex(10.0,10.0), Complex(-10.0,10.0))}", &Value::Tuple(vec![Value::Double(0.0), Value::Double(20.0)].into()), ); @@ -1010,13 +1010,13 @@ fn check_plus_c() { fn check_plus_cp() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; PlusCP(ComplexPolar(1.0,0.0), ComplexPolar(1.0,PI()/2.0))}", &Value::Tuple(vec![Value::Double(2.0_f64.sqrt()), Value::Double(PI / 4.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; PlusCP(ComplexPolar(10.0,PI()/4.0), ComplexPolar(10.0,3.0*PI()/4.0))}", &Value::Tuple(vec![Value::Double(200.0_f64.sqrt()), Value::Double(PI / 2.0)].into()), ); @@ -1026,13 +1026,13 @@ fn check_plus_cp() { fn check_minus_c() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; MinusC(Complex(1.0,0.0), Complex(0.0,1.0))}", &Value::Tuple(vec![Value::Double(1.0), Value::Double(-1.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; MinusC(Complex(10.0,10.0), Complex(-10.0,10.0))}", &Value::Tuple(vec![Value::Double(20.0), Value::Double(0.0)].into()), ); @@ -1042,7 +1042,7 @@ fn check_minus_c() { fn check_minus_cp() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; MinusCP(ComplexPolar(4.0,0.0), ComplexPolar(1.0,-PI()))}", &Value::Tuple(vec![Value::Double(5.0), Value::Double(0.0)].into()), ); @@ -1052,19 +1052,19 @@ fn check_minus_cp() { fn check_times_c() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; TimesC(Complex(2.0,0.0), Complex(3.0,0.0))}", &Value::Tuple(vec![Value::Double(6.0), Value::Double(0.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; TimesC(Complex(3.0,0.0), Complex(0.0,1.0))}", &Value::Tuple(vec![Value::Double(0.0), Value::Double(3.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; TimesC(Complex(1.0,2.0), Complex(3.0,4.0))}", &Value::Tuple(vec![Value::Double(-5.0), Value::Double(10.0)].into()), ); @@ -1074,13 +1074,13 @@ fn check_times_c() { fn check_times_cp() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; TimesCP(ComplexPolar(1.0,0.0), ComplexPolar(1.0,PI()/2.0))}", &Value::Tuple(vec![Value::Double(1.0), Value::Double(PI / 2.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; TimesCP(ComplexPolar(1.0,PI()/4.0), ComplexPolar(2.0,3.0*PI()/4.0))}", &Value::Tuple(vec![Value::Double(2.0), Value::Double(PI)].into()), ); @@ -1090,13 +1090,13 @@ fn check_times_cp() { fn check_pow_c() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; PowC(Complex(2.0,0.0), Complex(3.0,0.0))}", &Value::Tuple(vec![Value::Double(8.0), Value::Double(0.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; PowC(Complex(0.0,1.0), Complex(0.0,1.0))}", &Value::Tuple(vec![Value::Double(E.powf(-PI / 2.0)), Value::Double(0.0)].into()), ); @@ -1106,7 +1106,7 @@ fn check_pow_c() { fn check_pow_cp() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; PowCP(ComplexPolar(2.0,0.0), ComplexPolar(3.0,0.0))}", &Value::Tuple(vec![Value::Double(8.0), Value::Double(0.0)].into()), ); @@ -1116,19 +1116,19 @@ fn check_pow_cp() { fn check_divide_by_c() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; DividedByC(Complex(1.0,0.0), Complex(2.0,0.0))}", &Value::Tuple(vec![Value::Double(0.5), Value::Double(0.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; DividedByC(Complex(3.0,0.0), Complex(0.0,1.0))}", &Value::Tuple(vec![Value::Double(0.0), Value::Double(-3.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; DividedByC(Complex(1.0,2.0), Complex(3.0,4.0))}", &Value::Tuple(vec![Value::Double(0.44), Value::Double(0.08)].into()), ); @@ -1138,13 +1138,13 @@ fn check_divide_by_c() { fn check_devide_by_cp() { test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; DividedByCP(ComplexPolar(1.0,0.0), ComplexPolar(1.0,PI()/2.0))}", &Value::Tuple(vec![Value::Double(1.0), Value::Double(-PI / 2.0)].into()), ); test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; DividedByCP(ComplexPolar(1.0,PI()/4.0), ComplexPolar(2.0,3.0*PI()/4.0))}", &Value::Tuple(vec![Value::Double(0.5), Value::Double(-PI / 2.0)].into()), ); diff --git a/library/src/tests/resources/src/add_le.qs b/library/src/tests/resources/src/add_le.qs index 86dc032365..766ebfb785 100644 --- a/library/src/tests/resources/src/add_le.qs +++ b/library/src/tests/resources/src/add_le.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Std.Convert.*; + import Std.Diagnostics.*; internal operation TestAddLE3( name : String, diff --git a/library/src/tests/resources/src/compare.qs b/library/src/tests/resources/src/compare.qs index 1330691592..09bc3a205e 100644 --- a/library/src/tests/resources/src/compare.qs +++ b/library/src/tests/resources/src/compare.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Std.Convert.*; + import Std.Diagnostics.*; internal operation CompareWithBigInt( name : String, diff --git a/library/src/tests/resources/src/inc_by_le.qs b/library/src/tests/resources/src/inc_by_le.qs index 5f12d11b0f..0a0ddf453f 100644 --- a/library/src/tests/resources/src/inc_by_le.qs +++ b/library/src/tests/resources/src/inc_by_le.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Std.Convert.*; + import Std.Diagnostics.*; internal operation TestIncByLE2( name : String, diff --git a/library/src/tests/resources/src/qft_le.qs b/library/src/tests/resources/src/qft_le.qs index 7a9f7b256f..038006ac1e 100644 --- a/library/src/tests/resources/src/qft_le.qs +++ b/library/src/tests/resources/src/qft_le.qs @@ -1,6 +1,6 @@ namespace Test { - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; + import Std.Diagnostics.*; + import Std.Arrays.*; operation PrepareEntangledState( left : Qubit[], diff --git a/library/src/tests/resources/src/select.qs b/library/src/tests/resources/src/select.qs index 08087539ad..7d70a523ea 100644 --- a/library/src/tests/resources/src/select.qs +++ b/library/src/tests/resources/src/select.qs @@ -1,9 +1,9 @@ namespace Test { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Random; - open Microsoft.Quantum.Unstable.TableLookup; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Random.*; + import Microsoft.Quantum.Unstable.TableLookup.*; internal operation TestSelect(addressBits : Int, dataBits : Int) : Unit { use addressRegister = Qubit[addressBits]; diff --git a/library/src/tests/resources/src/state_preparation.qs b/library/src/tests/resources/src/state_preparation.qs index a6f573b734..b9400f3b06 100644 --- a/library/src/tests/resources/src/state_preparation.qs +++ b/library/src/tests/resources/src/state_preparation.qs @@ -1,9 +1,11 @@ namespace Test { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Unstable.StatePreparation; + import Std.Convert.*; + import Std.Math.*; + import Std.Diagnostics.*; + import Std.Arrays.*; + import Microsoft.Quantum.Unstable.StatePreparation.*; + import QIR.Intrinsic.*; + operation TestPlusState() : Unit { diff --git a/library/src/tests/state_preparation.rs b/library/src/tests/state_preparation.rs index 37723446c7..c6575eca59 100644 --- a/library/src/tests/state_preparation.rs +++ b/library/src/tests/state_preparation.rs @@ -238,7 +238,7 @@ fn check_preparation_endianness() { fn check_preparation_doc_sample() { let out = test_expression( "{ - open Microsoft.Quantum.Math; + import Std.Math.*; let amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0]; use qubits = Qubit[2]; Microsoft.Quantum.Unstable.StatePreparation.PreparePureStateD(amplitudes, qubits); diff --git a/library/std/qsharp.json b/library/std/qsharp.json index b6af02517b..e3a857383e 100644 --- a/library/std/qsharp.json +++ b/library/std/qsharp.json @@ -2,23 +2,23 @@ "author": "Microsoft", "license": "MIT", "files": [ - "src/arrays.qs", - "src/canon.qs", - "src/convert.qs", "src/core.qs", - "src/diagnostics.qs", - "src/internal.qs", - "src/intrinsic.qs", - "src/logical.qs", - "src/math.qs", - "src/measurement.qs", - "src/modern_api.qs", - "src/qir.qs", - "src/random.qs", - "src/re.qs", + "src/legacy_api.qs", "src/unstable_arithmetic.qs", "src/unstable_arithmetic_internal.qs", "src/unstable_state_preparation.qs", - "src/unstable_table_lookup.qs" + "src/unstable_table_lookup.qs", + "src/QIR/Intrinsic.qs", + "src/Std/Arrays.qs", + "src/Std/Canon.qs", + "src/Std/Convert.qs", + "src/Std/Diagnostics.qs", + "src/Std/InternalHelpers.qs", + "src/Std/Intrinsic.qs", + "src/Std/Logical.qs", + "src/Std/Math.qs", + "src/Std/Measurement.qs", + "src/Std/Random.qs", + "src/Std/ResourceEstimation.qs" ] -} +} \ No newline at end of file diff --git a/library/std/src/QIR/Intrinsic.qs b/library/std/src/QIR/Intrinsic.qs new file mode 100644 index 0000000000..d2f0c74209 --- /dev/null +++ b/library/std/src/QIR/Intrinsic.qs @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + + +// Controlled Gates + +operation __quantum__qis__ccx__body(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__cx__body(control : Qubit, target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__cy__body(control : Qubit, target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__cz__body(control : Qubit, target : Qubit) : Unit { + body intrinsic; +} + +// Rotation Gates + +operation __quantum__qis__rx__body(angle : Double, target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__rxx__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__ry__body(angle : Double, target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__ryy__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__rz__body(angle : Double, target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__rzz__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { + body intrinsic; +} + +// Single-Qubit Gates + +operation __quantum__qis__h__body(target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__s__body(target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__s__adj(target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__t__body(target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__t__adj(target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__x__body(target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__y__body(target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__z__body(target : Qubit) : Unit { + body intrinsic; +} + +// Two-Qubit Gates + +operation __quantum__qis__swap__body(target1 : Qubit, target2 : Qubit) : Unit { + body intrinsic; +} + +// Quantum Measurement + +operation __quantum__qis__m__body(target : Qubit) : Result { + body intrinsic; +} + +operation __quantum__qis__reset__body(target : Qubit) : Unit { + body intrinsic; +} + +operation __quantum__qis__mresetz__body(target : Qubit) : Result { + body intrinsic; +} + +export + __quantum__qis__ccx__body, + __quantum__qis__cx__body, + __quantum__qis__cy__body, + __quantum__qis__cz__body, + __quantum__qis__rx__body, + __quantum__qis__rxx__body, + __quantum__qis__ry__body, + __quantum__qis__ryy__body, + __quantum__qis__rz__body, + __quantum__qis__rzz__body, + __quantum__qis__h__body, + __quantum__qis__s__body, + __quantum__qis__s__adj, + __quantum__qis__t__body, + __quantum__qis__t__adj, + __quantum__qis__x__body, + __quantum__qis__y__body, + __quantum__qis__z__body, + __quantum__qis__swap__body, + __quantum__qis__m__body, + __quantum__qis__reset__body, + __quantum__qis__mresetz__body; diff --git a/library/std/src/Std/Arrays.qs b/library/std/src/Std/Arrays.qs new file mode 100644 index 0000000000..bd099bda12 --- /dev/null +++ b/library/std/src/Std/Arrays.qs @@ -0,0 +1,1442 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import Std.Diagnostics.*; +import Std.Math.*; + +/// # Summary +/// Given an array and a predicate that is defined +/// for the elements of the array, and checks if all elements of the +/// array satisfy the predicate. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## predicate +/// A function from `'T` to `Bool` that is used to check elements. +/// ## array +/// An array of elements over `'T`. +/// +/// # Output +/// A `Bool` value of the AND function of the predicate applied to all elements. +/// +/// # Example +/// The following code checks whether all elements of the array are non-zero: +/// ```qsharp +/// let allNonZero = All(x -> x != 0, [1, 2, 3, 4, 5]); +/// ``` +function All<'T>(predicate : ('T -> Bool), array : 'T[]) : Bool { + for element in array { + if not predicate(element) { + return false; + } + } + + true +} + +/// Given an array and a predicate that is defined +/// for the elements of the array, checks if at least one element of +/// the array satisfies the predicate. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## predicate +/// A function from `'T` to `Bool` that is used to check elements. +/// ## array +/// An array of elements over `'T`. +/// +/// # Output +/// A `Bool` value of the OR function of the predicate applied to all elements. +/// +/// # Example +/// ```qsharp +/// let anyEven = Any(x -> x % 2 == 0, [1, 3, 6, 7, 9]); +/// ``` +function Any<'T>(predicate : ('T -> Bool), array : 'T[]) : Bool { + for element in array { + if predicate(element) { + return true; + } + } + + false +} + +/// Splits an array into multiple parts of equal length. +/// +/// # Input +/// ## chunkSize +/// The length of each chunk. Must be positive. +/// ## array +/// The array to be split in chunks. +/// +/// # Output +/// A array containing each chunk of the original array. +/// +/// # Remarks +/// Note that the last element of the output may be shorter +/// than `chunkSize` if `Length(array)` is not divisible by `chunkSize`. +function Chunks<'T>(chunkSize : Int, array : 'T[]) : 'T[][] { + Fact(chunkSize > 0, "`chunkSize` must be positive"); + mutable output = []; + mutable remaining = array; + while (not IsEmpty(remaining)) { + let chunkSizeToTake = MinI(Length(remaining), chunkSize); + set output += [remaining[...chunkSizeToTake - 1]]; + set remaining = remaining[chunkSizeToTake...]; + } + + output +} + +/// Shift an array circularly left or right by a specific step size. +/// +/// # Type Parameters +/// ## 'T +/// The type of the array elements. +/// +/// # Input +/// ## stepCount +/// The amount of positions by which the array elements will be shifted. +/// If this is positive, `array` is circularly shifted to the right. +/// If this is negative, `array` is circularly shifted to the left. +/// ## array +/// Array to be circularly shifted. +/// +/// # Output +/// An array `output` that is the `array` circularly shifted to the right or left +/// by the specified step size. +/// +/// # Example +/// ```qsharp +/// let array = [10, 11, 12]; +/// // The following line returns [11, 12, 10]. +/// let output = CircularlyShifted(2, array); +/// // The following line returns [12, 10, 11]. +/// let output = CircularlyShifted(-2, array); +/// ``` +function CircularlyShifted<'T>(stepCount : Int, array : 'T[]) : 'T[] { + let arrayLength = Length(array); + if arrayLength <= 1 { + return array; + } + + // normalize circular shift count to be within the bounds of the array length + let normalizedShift = stepCount % arrayLength; + let effectiveShift = normalizedShift >= 0 ? arrayLength - normalizedShift | -normalizedShift; + + // no shift needed + if effectiveShift == 0 { + return array; + } + + let leftPart = array[...effectiveShift - 1]; + let rightPart = array[effectiveShift..arrayLength - 1]; + + rightPart + leftPart +} + +/// Extracts a column from a matrix. +/// +/// # Description +/// This function extracts a column in a matrix in row-wise order. +/// Extracting a row corresponds to element access of the first index +/// and therefore requires no further treatment. +/// +/// # Type Parameters +/// ## 'T +/// The type of each element of `matrix`. +/// +/// # Input +/// ## column +/// Column of the matrix +/// ## matrix +/// 2-dimensional matrix in row-wise order +/// +/// # Example +/// ```qsharp +/// let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; +/// let column = ColumnAt(0, matrix); +/// // same as: column = [1, 4, 7] +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.Transposed +/// - Microsoft.Quantum.Arrays.Diagonal +function ColumnAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { + Fact(IsRectangularArray(matrix), "`matrix` is not a rectangular array"); + mutable columnValues = []; + for row in matrix { + set columnValues += [row[column]]; + } + columnValues +} + +/// Given an array and a predicate that is defined +/// for the elements of the array, returns the number of elements +/// an array that consists of those elements that satisfy the predicate. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## predicate +/// A function from `'T` to Boolean that is used to filter elements. +/// ## array +/// An array of elements over `'T`. +/// +/// # Output +/// The number of elements in `array` that satisfy the predicate. +/// +/// # Example +/// ```qsharp +/// let evensCount = Count(x -> x % 2 == 0, [1, 3, 6, 7, 9]); +/// // evensCount is 1. +/// ``` +function Count<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { + mutable count = 0; + for element in array { + if predicate(element) { + set count += 1; + } + } + count +} + +/// Returns an array of diagonal elements of a 2-dimensional array +/// +/// # Description +/// If the 2-dimensional array has not a square shape, the diagonal over +/// the minimum over the number of rows and columns will be returned. +/// +/// # Type Parameters +/// ## 'T +/// The type of each element of `matrix`. +/// +/// # Input +/// ## matrix +/// 2-dimensional matrix in row-wise order. +/// +/// # Example +/// ```qsharp +/// let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; +/// let diagonal = Diagonal(matrix); +/// // same as: column = [1, 5, 9] +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.Transposed +function Diagonal<'T>(matrix : 'T[][]) : 'T[] { + Fact(IsRectangularArray(matrix), "`matrix` is not a rectangular array"); + let rows = Length(matrix); + let columns = rows == 0 ? 0 | Length(Head(matrix)); + let rangeLimit = MinI(rows, columns) - 1; + mutable diagonal = []; + for index in 0..rangeLimit { + set diagonal += [matrix[index][index]]; + } + + diagonal +} + +/// Repeats an operation for a given number of samples, collecting its outputs +/// in an array. +/// +/// # Input +/// ## op +/// The operation to be called repeatedly. +/// ## nSamples +/// The number of samples of calling `op` to collect. +/// ## input +/// The input to be passed to `op`. +/// +/// # Type Parameters +/// ## TInput +/// The type of input expected by `op`. +/// ## TOutput +/// The type of output returned by `op`. +/// +/// # Example +/// The following samples an alternating array of results. +/// ```qsharp +/// use qubit = Qubit(); +/// let results = Microsoft.Quantum.Arrays.DrawMany(q => {X(q); M(q)}, 3, qubit); +/// ``` +operation DrawMany<'TInput, 'TOutput>(op : ('TInput => 'TOutput), nSamples : Int, input : 'TInput) : 'TOutput[] { + mutable outputs = []; + for _ in 1..nSamples { + set outputs += [op(input)]; + } + outputs +} + +/// Given an array, returns a new array containing elements of the original +/// array along with the indices of each element. +/// +/// # Type Parameters +/// ## 'TElement +/// The type of elements of the array. +/// +/// # Input +/// ## array +/// An array whose elements are to be enumerated. +/// +/// # Output +/// A new array containing elements of the original array along with their +/// indices. +/// +/// # Example +/// The following `for` loops are equivalent: +/// ```qsharp +/// for (idx in IndexRange(array)) { +/// let element = array[idx]; +/// ... +/// } +/// for ((idx, element) in Enumerated(array)) { ... } +/// ``` +function Enumerated<'TElement>(array : 'TElement[]) : (Int, 'TElement)[] { + MappedByIndex((index, element) -> (index, element), array) +} + +/// Returns an array containing the elements of another array, +/// excluding elements at a given list of indices. +/// +/// # Type Parameters +/// ## 'T +/// The type of the array elements. +/// +/// # Input +/// ## remove +/// An array of indices denoting which elements should be excluded. +/// from the output. +/// ## array +/// Array of which the values in the output array are taken. +/// +/// # Output +/// An array `output` such that `output[0]` is the first element +/// of `array` whose index does not appear in `remove`, +/// such that `output[1]` is the second such element, and so +/// forth. +/// +/// # Example +/// ```qsharp +/// let array = [10, 11, 12, 13, 14, 15]; +/// // The following line returns [10, 12, 15]. +/// let subarray = Excluding([1, 3, 4], array); +/// ``` +function Excluding<'T>(remove : Int[], array : 'T[]) : 'T[] { + let arrayLength = Length(array); + mutable toKeep = Repeated(true, arrayLength); + for indexToRemove in remove { + set toKeep w/= indexToRemove <- false; + } + mutable output = []; + for index in 0..arrayLength - 1 { + if toKeep[index] { + set output += [array[index]]; + } + } + output +} + +/// Given an array and a predicate that is defined +/// for the elements of the array, returns an array that consists of +/// those elements that satisfy the predicate. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## predicate +/// A function from `'T` to Boolean that is used to filter elements. +/// ## array +/// An array of elements over `'T`. +/// +/// # Output +/// An array `'T[]` of elements that satisfy the predicate. +/// +/// # Example +/// The following code creates an array that contains only even numbers. +/// ```qsharp +/// Filtered(x -> x % 2 == 0, [0, 1, 2, 3, 4]) +/// ``` +function Filtered<'T>(predicate : ('T -> Bool), array : 'T[]) : 'T[] { + mutable filtered = []; + for element in array { + if predicate(element) { + set filtered += [element]; + } + } + filtered +} + +/// Given an array and a function that maps an array element to some output +/// array, returns the concatenated output arrays for each array element. +/// +/// # Type Parameters +/// ## 'TInput +/// The type of `array` elements. +/// ## 'TOutput +/// The `mapper` function returns arrays of this type. +/// +/// # Input +/// ## mapper +/// A function from `'TInput` to `'TOutput[]` that is used to map array elements. +/// ## array +/// An array of elements. +/// +/// # Output +/// An array of `'TOutput[]` which is the concatenation of all arrays generated by +/// the mapping function. +/// +/// # Example +/// The following code creates an array with each element of the input array repeated twice. +/// ```qsharp +/// let repeatedPairs = FlatMapped(x -> Repeated(x, 2), [1, 2, 3]); +/// // repeatedPairs is [1, 1, 2, 2, 3, 3]. +/// ``` +function FlatMapped<'TInput, 'TOutput>(mapper : ('TInput -> 'TOutput[]), array : 'TInput[]) : 'TOutput[] { + mutable output = []; + for element in array { + set output += mapper(element); + } + output +} + +/// Given an array of arrays, returns the concatenation of all arrays. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## arrays +/// Array of arrays. +/// +/// # Output +/// Concatenation of all arrays. +/// +/// # Example +/// ```qsharp +/// let flattened = Flattened([[1, 2], [3], [4, 5, 6]]); +/// // flattened = [1, 2, 3, 4, 5, 6] +/// ``` +function Flattened<'T>(arrays : 'T[][]) : 'T[] { + mutable output = []; + for array in arrays { + set output += array; + } + output +} + +/// Iterates a function `f` through an array `array`, returning +/// `f(...f(f(initialState, array[0]), array[1]), ...)`. +/// +/// # Type Parameters +/// ## 'State +/// The type of states the `folder` function operates on, i.e., accepts as its first +/// argument and returns. +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## folder +/// A function to be folded over the array. +/// ## state +/// The initial state of the folder. +/// ## array +/// An array of values to be folded over. +/// +/// # Output +/// The final state returned by the folder after iterating over +/// all elements of `array`. +/// +/// # Example +/// ```qsharp +/// let sum = Fold((x, y) -> x + y, 0, [1, 2, 3, 4, 5]); // `sum` is 15. +/// ``` +function Fold<'State, 'T>(folder : (('State, 'T) -> 'State), state : 'State, array : 'T[]) : 'State { + mutable current = state; + for element in array { + set current = folder(current, element); + } + current +} + +/// Given an array and an operation that is defined +/// for the elements of the array, returns a new array that consists +/// of the images of the original array under the operation. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// ## 'U +/// The result type of the `action` operation. +/// +/// # Input +/// ## action +/// An operation from `'T` to `'U` that is applied to each element. +/// ## array +/// An array of elements over `'T`. +/// +/// # Output +/// An array `'U[]` of elements that are mapped by the `action` operation. +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.Mapped +operation ForEach<'T, 'U>(action : ('T => 'U), array : 'T[]) : 'U[] { + mutable output = []; + for element in array { + set output += [action(element)]; + } + output +} + +/// Returns the first element of the array. +/// +/// # Type Parameters +/// ## 'A +/// The type of the array elements. +/// +/// # Input +/// ## array +/// Array of which the first element is taken. Array must have at least 1 element. +/// +/// # Output +/// The first element of the array. +function Head<'A>(array : 'A[]) : 'A { + Fact(Length(array) > 0, "Array must have at least 1 element"); + array[0] +} + +/// Returns a tuple of first and all remaining elements of the array. +/// +/// # Type Parameters +/// ## 'A +/// The type of the array elements. +/// +/// # Input +/// ## array +/// An array with at least one element. +/// +/// # Output +/// A tuple of first and all remaining elements of the array. +function HeadAndRest<'A>(array : 'A[]) : ('A, 'A[]) { + (Head(array), Rest(array)) +} + +/// Returns the first index of the first element in an array that satisfies +/// a given predicate. If no such element exists, returns -1. +/// +/// # Input +/// ## predicate +/// A predicate function acting on elements of the array. +/// ## array +/// An array to be searched using the given predicate. +/// +/// # Output +/// Either the smallest index of an element for which `predicate(array[index])` is true, +/// or -1 if no such element exists. +/// +/// # Example +/// The following code gets the index of the first even number in the input array. +/// ```qsharp +/// let indexOfFirstEven = IndexOf(x -> x % 2 == 0, [1, 3, 17, 2, 21]); +/// // `indexOfFirstEven` is 3. +/// ``` +function IndexOf<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { + for index in 0..Length(array) - 1 { + if predicate(array[index]) { + return index; + } + } + -1 +} + +/// Given an array, returns a range over the indices of that array, suitable +/// for use in a for loop. +/// +/// # Type Parameters +/// ## 'TElement +/// The type of elements of the array. +/// +/// # Input +/// ## array +/// An array for which a range of indices should be returned. +/// +/// # Output +/// A range over all indices of the array. +/// +/// # Example +/// The following `for` loops are equivalent: +/// ```qsharp +/// for idx in IndexRange(array) { ... } +/// for idx in 0 .. Length(array) - 1 { ... } +/// ``` +function IndexRange<'TElement>(array : 'TElement[]) : Range { + 0..Length(array) - 1 +} + +/// Interleaves two arrays of (almost) same size. +/// +/// # Description +/// This function returns the interleaving of two arrays, starting +/// with the first element from the first array, then the first +/// element from the second array, and so on. +/// +/// The first array must either be +/// of the same length as the second one, or can have one more element. +/// +/// # Type Parameters +/// ## 'T +/// The type of each element of `first` and `second`. +/// +/// # Input +/// ## first +/// The first array to be interleaved. +/// +/// ## second +/// The second array to be interleaved. +/// +/// # Output +/// Interleaved array +/// +/// # Example +/// ```qsharp +/// // same as interleaved = [1, -1, 2, -2, 3, -3] +/// let interleaved = Interleaved([1, 2, 3], [-1, -2, -3]) +/// ``` +function Interleaved<'T>(first : 'T[], second : 'T[]) : 'T[] { + let firstLength = Length(first); + let secondLength = Length(second); + Fact( + firstLength == secondLength or firstLength == secondLength + 1, + "Array `first` must either be of same size as `second` or have one more element" + ); + + let interleavedLength = firstLength + secondLength; + mutable interleaved = []; + for index in 0..interleavedLength - 1 { + let originalIndex = index / 2; + let value = if index % 2 == 0 { first[originalIndex] } else { second[originalIndex] }; + set interleaved += [value]; + } + interleaved +} + +/// Returns true if and only if an array is empty. +/// +/// # Input +/// ## array +/// The array to be checked. +/// +/// # Output +/// `true` if and only if the array is empty (has length 0). +function IsEmpty<'T>(array : 'T[]) : Bool { + Length(array) == 0 +} + +/// Returns whether a 2-dimensional array has a rectangular shape +/// +/// # Type Parameters +/// ## 'T +/// The type of each element of `array`. +/// +/// # Input +/// ## array +/// A 2-dimensional array of elements. +/// +/// # Output +/// `true` if the array is rectangular, `false` otherwise. +/// +/// # Example +/// ```qsharp +/// IsRectangularArray([[1, 2], [3, 4]]); // true +/// IsRectangularArray([[1, 2, 3], [4, 5, 6]]); // true +/// IsRectangularArray([[1, 2], [3, 4, 5]]); // false +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.IsSquareArray +function IsRectangularArray<'T>(array : 'T[][]) : Bool { + if (Length(array) > 0) { + let columnCount = Length(Head(array)); + for index in 1..Length(array) - 1 { + if Length(array[index]) != columnCount { + return false; + } + } + } + + true +} + +/// Given an array, returns whether that array is sorted as defined by +/// a given comparison function. +/// +/// # Type Parameters +/// ## 'T +/// The type of each element of `array`. +/// +/// # Input +/// ## comparison +/// A function that compares two elements such that `a` is considered to +/// be less than or equal to `b` if `comparison(a, b)` is `true`. +/// ## array +/// The array to be checked. +/// +/// # Output +/// `true` if and only if for each pair of elements `a` and `b` of +/// `array` occurring in that order, `comparison(a, b)` is `true`. +/// +/// # Remarks +/// The function `comparison` is assumed to be transitive, such that +/// if `comparison(a, b)` and `comparison(b, c)`, then `comparison(a, c)` +/// is assumed. +function IsSorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : Bool { + for index in 1..Length(array) - 1 { + if not comparison(array[index - 1], array[index]) { + return false; + } + } + true +} + +/// Returns whether a 2-dimensional array has a square shape +/// +/// # Type Parameters +/// ## 'T +/// The type of each element of `array`. +/// +/// # Input +/// ## array +/// A 2-dimensional array of elements. +/// +/// # Example +/// ```qsharp +/// IsSquareArray([[1, 2], [3, 4]]); // true +/// IsSquareArray([[1, 2, 3], [4, 5, 6]]); // false +/// IsSquareArray([[1, 2], [3, 4], [5, 6]]); // false +/// ``` +/// +/// # Output +/// `true` if the array is square, `false` otherwise. +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.IsRectangularArray +function IsSquareArray<'T>(array : 'T[][]) : Bool { + if (Length(array) > 0) { + let columnCount = Length(array); + for column in array { + if Length(column) != columnCount { + return false; + } + } + } + + true +} + +/// Given an array and a function that is defined +/// for the elements of the array, returns a new array that consists +/// of the images of the original array under the function. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// ## 'U +/// The result type of the `mapper` function. +/// +/// # Input +/// ## mapper +/// A function from `'T` to `'U` that is used to map elements. +/// ## array +/// An array of elements over `'T`. +/// +/// # Output +/// An array `'U[]` of elements that are mapped by the `mapper` function. +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.ForEach +function Mapped<'T, 'U>(mapper : ('T -> 'U), array : 'T[]) : 'U[] { + mutable mapped = []; + for element in array { + set mapped += [mapper(element)]; + } + mapped +} + +/// Given an array and a function that is defined +/// for the indexed elements of the array, returns a new array that consists +/// of the images of the original array under the function. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// ## 'U +/// The result type of the `mapper` function. +/// +/// # Input +/// ## mapper +/// A function from `(Int, 'T)` to `'U` that is used to map elements +/// and their indices. +/// ## array +/// An array of elements over `'T`. +/// +/// # Output +/// An array `'U[]` of elements that are mapped by the `mapper` function. +/// +/// # Example +/// The following two lines are equivalent: +/// ```qsharp +/// let array = MappedByIndex(f, [x0, x1, x2]); +/// ``` +/// and +/// ```qsharp +/// let array = [f(0, x0), f(1, x1), f(2, x2)]; +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.Mapped +function MappedByIndex<'T, 'U>(mapper : ((Int, 'T) -> 'U), array : 'T[]) : 'U[] { + mutable mapped = []; + for index in 0..Length(array) - 1 { + set mapped += [mapper(index, array[index])]; + } + mapped +} + +/// Given a range and a function that takes an integer as input, +/// returns a new array that consists +/// of the images of the range values under the function. +/// +/// # Type Parameters +/// ## 'T +/// The result type of the `mapper` function. +/// +/// # Input +/// ## mapper +/// A function from `Int` to `'T` that is used to map range values. +/// ## range +/// A range of integers. +/// +/// # Output +/// An array `'T[]` of elements that are mapped by the `mapper` function. +/// +/// # Example +/// This example adds 1 to a range of even numbers: +/// ```qsharp +/// let numbers = MappedOverRange(x -> x + 1, 0..2..10); +/// // numbers = [1, 3, 5, 7, 9, 11] +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.Mapped +function MappedOverRange<'T>(mapper : (Int -> 'T), range : Range) : 'T[] { + mutable output = []; + for element in range { + set output += [mapper(element)]; + } + output +} + +/// Creates an array that is equal to an input array except that the last array +/// element is dropped. +/// +/// # Type Parameters +/// ## 'T +/// The type of the array elements. +/// +/// # Input +/// ## array +/// An array whose first to second-to-last elements are to form the output array. +/// +/// # Output +/// An array containing the elements `array[0..Length(array) - 2]`. +function Most<'T>(array : 'T[]) : 'T[] { + array[...Length(array) - 2] +} + +/// Returns a tuple of all but one and the last element of the array. +/// +/// # Type Parameters +/// ## 'A +/// The type of the array elements. +/// +/// # Input +/// ## array +/// An array with at least one element. +/// +/// # Output +/// A tuple of all but one and the last element of the array. +function MostAndTail<'A>(array : 'A[]) : ('A[], 'A) { + (Most(array), Tail(array)) +} + +/// Returns an array padded at with specified values up to a +/// specified length. +/// +/// # Type Parameters +/// ## 'T +/// The type of the array elements. +/// +/// # Input +/// ## paddedLength +/// The length of the padded array. If this is positive, `array` +/// is padded at the head. If this is negative, `array` is padded +/// at the tail. +/// ## defaultElement +/// Default value to use for padding elements. +/// ## array +/// Array to be padded. +/// +/// # Output +/// An array `output` that is the `array` padded at the head or the tail +/// with `defaultElement`s until `output` has length `paddedLength` +/// +/// # Example +/// ```qsharp +/// let array = [10, 11, 12]; +/// // The following line returns [10, 12, 15, 2, 2]. +/// let output = Padded(-5, 2, array); +/// // The following line returns [2, 2, 10, 12, 15]. +/// let output = Padded(5, 2, array); +/// ``` +function Padded<'T>(paddedLength : Int, defaultElement : 'T, inputArray : 'T[]) : 'T[] { + let nElementsInitial = Length(inputArray); + let nAbsElementsTotal = AbsI(paddedLength); + if nAbsElementsTotal < nElementsInitial { + fail "Specified output array length must be at least as long as `inputArray` length."; + } + let nElementsPad = nAbsElementsTotal - nElementsInitial; + let padArray = Repeated(defaultElement, nElementsPad); + if (paddedLength >= 0) { + padArray + inputArray // Padded at head. + } else { + inputArray + padArray // Padded at tail. + } +} + +/// Splits an array into multiple parts. +/// +/// # Input +/// ## partitionSizes +/// Number of elements in each split part of array. +/// ## array +/// Input array to be split. +/// +/// # Output +/// Multiple arrays where the first array is the first `partitionSizes[0]` of `array` +/// and the second array are the next `partitionSizes[1]` of `array` etc. The last array +/// will contain all remaining elements. If the array is split exactly, the +/// last array will be the empty array, indicating there are no remaining elements. +/// In other words, `Tail(Partitioned(...))` will always return the remaining +/// elements, while `Most(Partitioned(...))` will always return the complete +/// partitions of the array. +/// +/// # Example +/// ```qsharp +/// // The following returns [[2, 3], [5], [7]]; +/// let split = Partitioned([2, 1], [2, 3, 5, 7]); +/// // The following returns [[2, 3], [5, 7], []]; +/// let split = Partitioned([2, 2], [2, 3, 5, 7]); +/// ``` +function Partitioned<'T>(partitionSizes : Int[], array : 'T[]) : 'T[][] { + mutable output = Repeated([], Length(partitionSizes) + 1); + mutable partitionStartIndex = 0; + for index in IndexRange(partitionSizes) { + let partitionEndIndex = partitionStartIndex + partitionSizes[index] - 1; + if partitionEndIndex >= Length(array) { + fail "Partitioned argument out of bounds."; + } + set output w/= index <- array[partitionStartIndex..partitionEndIndex]; + set partitionStartIndex = partitionEndIndex + 1; + } + set output w/= Length(partitionSizes) <- array[partitionStartIndex..Length(array) - 1]; + output +} + +/// Creates an array that is equal to an input array except that the first array +/// element is dropped. +/// +/// # Type Parameters +/// ## 'T +/// The type of the array elements. +/// +/// # Input +/// ## array +/// An array whose second to last elements are to form the output array. +/// +/// # Output +/// An array containing the elements `array[1..Length(array) - 1]`. +function Rest<'T>(array : 'T[]) : 'T[] { + array[1...] +} + +/// Create an array that contains the same elements as an input array but in reversed +/// order. +/// +/// # Type Parameters +/// ## 'T +/// The type of the array elements. +/// +/// # Input +/// ## array +/// An array whose elements are to be copied in reversed order. +/// +/// # Output +/// An array containing the elements `array[Length(array) - 1]` .. `array[0]`. +function Reversed<'T>(array : 'T[]) : 'T[] { + array[...-1...] +} + +/// Get an array of integers in a given interval. +/// +/// # Input +/// ## from +/// An inclusive start index of the interval. +/// ## to +/// An inclusive end index of the interval that is not smaller than `from`. +/// +/// # Output +/// An array containing the sequence of numbers `from`, `from + 1`, ..., +/// `to`. +/// +/// # Example +/// ```qsharp +/// let arr1 = SequenceI(0, 3); // [0, 1, 2, 3] +/// let arr2 = SequenceI(23, 29); // [23, 24, 25, 26, 27, 28, 29] +/// let arr3 = SequenceI(-5, -2); // [-5, -4, -3, -2] +/// +/// let numbers = SequenceI(0, _); // function to create sequence from 0 to `to` +/// let naturals = SequenceI(1, _); // function to create sequence from 1 to `to` +/// ``` +function SequenceI(from : Int, to : Int) : Int[] { + Fact(to >= from, "`to` must be larger than `from`."); + mutable array = []; + for index in from..to { + set array += [index]; + } + array +} + +/// Get an array of integers in a given interval. +/// +/// # Input +/// ## from +/// An inclusive start index of the interval. +/// ## to +/// An inclusive end index of the interval that is not smaller than `from`. +/// +/// # Output +/// An array containing the sequence of numbers `from`, `from + 1`, ..., +/// `to`. +/// +/// # Remarks +/// The difference between `from` and `to` must fit into an `Int` value. +/// +/// # Example +/// ```qsharp +/// let arr1 = SequenceL(0L, 3L); // [0L, 1L, 2L, 3L] +/// let arr2 = SequenceL(23L, 29L); // [23L, 24L, 25L, 26L, 27L, 28L, 29L] +/// let arr3 = SequenceL(-5L, -2L); // [-5L, -4L, -3L, -2L] +/// ``` +function SequenceL(from : BigInt, to : BigInt) : BigInt[] { + Fact(to >= from, "`to` must be larger than `from`"); + mutable array = []; + mutable current = from; + while current <= to { + set array += [current]; + set current += 1L; + } + + array +} + +/// Given an array, returns the elements of that array sorted by a given +/// comparison function. +/// +/// # Type Parameters +/// ## 'T +/// The type of each element of `array`. +/// +/// # Input +/// ## comparison +/// A function that compares two elements such that `a` is considered to +/// be less than or equal to `b` if `comparison(a, b)` is `true`. +/// ## array +/// The array to be sorted. +/// +/// # Output +/// An array containing the same elements as `array`, such that for all +/// elements `a` occurring earlier than elements `b`, `comparison(a, b)` +/// is `true`. +/// +/// # Example +/// The following snippet sorts an array of integers to occur in ascending +/// order: +/// ```qsharp +/// let sortedArray = Sorted(LessThanOrEqualI, [3, 17, 11, -201, -11]); +/// ``` +/// +/// # Remarks +/// The function `comparison` is assumed to be transitive, such that +/// if `comparison(a, b)` and `comparison(b, c)`, then `comparison(a, c)` +/// is assumed. If this property does not hold, then the output of this +/// function may be incorrect. +function Sorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : 'T[] { + if Length(array) <= 1 { + return array; + } + + let pivotIndex = Length(array) / 2; + let left = array[...pivotIndex - 1]; + let right = array[pivotIndex...]; + + // Sort each sublist, then merge them back into a single combined + // list and return. + SortedMerged( + comparison, + Sorted(comparison, left), + Sorted(comparison, right) + ) +} + +/// Given two sorted arrays, returns a single array containing the +/// elements of both in sorted order. Used internally by `Sorted`. +internal function SortedMerged<'T>(comparison : (('T, 'T) -> Bool), left : 'T[], right : 'T[]) : 'T[] { + mutable output = []; + mutable remainingLeft = left; + mutable remainingRight = right; + while (not IsEmpty(remainingLeft)) and (not IsEmpty(remainingRight)) { + if comparison(Head(remainingLeft), Head(remainingRight)) { + set output += [Head(remainingLeft)]; + set remainingLeft = Rest(remainingLeft); + } else { + set output += [Head(remainingRight)]; + set remainingRight = Rest(remainingRight); + } + } + + // Note that at this point, either or both of `remainingLeft` and `remainingRight` are empty, + // such that we can simply append both to our output to get the whole merged array. + output + remainingLeft + remainingRight +} + +/// Takes an array and a list of locations and +/// produces a new array formed from the elements of the original +/// array that match the given locations. +/// +/// # Remarks +/// If `locations` contains repeated elements, the corresponding elements +/// of `array` will likewise be repeated. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## locations +/// A list of locations in the input array that is used to define the subarray. +/// ## array +/// An array from which a subarray will be generated. +/// +/// # Output +/// An array `out` of elements whose locations correspond to the subarray, +/// such that `out[index] == array[locations[index]]`. +/// +/// # Example +/// +/// ```qsharp +/// let array = [1, 2, 3, 4]; +/// let permutation = Subarray([3, 0, 2, 1], array); // [4, 1, 3, 2] +/// let duplicates = Subarray([1, 2, 2], array); // [2, 3, 3] +/// ``` +function Subarray<'T>(locations : Int[], array : 'T[]) : 'T[] { + mutable subarray = []; + for location in locations { + set subarray += [array[location]]; + } + subarray +} + +/// Applies a swap of two elements in an array. +/// +/// # Input +/// ## firstIndex +/// Index of the first element to be swapped. +/// +/// ## secondIndex +/// Index of the second element to be swapped. +/// +/// ## array +/// Array with elements to be swapped. +/// +/// # Output +/// The array with the in place swap applied. +/// +/// # Example +/// ```qsharp +/// // The following returns [0, 3, 2, 1, 4] +/// Swapped(1, 3, [0, 1, 2, 3, 4]); +/// ``` +function Swapped<'T>(firstIndex : Int, secondIndex : Int, array : 'T[]) : 'T[] { + array + w/ firstIndex <- array[secondIndex] + w/ secondIndex <- array[firstIndex] +} + +/// Returns the transpose of a matrix represented as an array +/// of arrays. +/// +/// # Description +/// Input as an r x c matrix with r rows and c columns. The matrix +/// is row-based, i.e., `matrix[i][j]` accesses the element at row `i` and column `j`. +/// +/// This function returns the c x r matrix that is the transpose of the +/// input matrix. +/// +/// # Type Parameters +/// ## 'T +/// The type of each element of `matrix`. +/// +/// # Input +/// ## matrix +/// Row-based r x c matrix. +/// +/// # Output +/// Transposed c x r matrix. +/// +/// # Example +/// ```qsharp +/// // same as [[1, 4], [2, 5], [3, 6]] +/// let transposed = Transposed([[1, 2, 3], [4, 5, 6]]); +/// ``` +function Transposed<'T>(matrix : 'T[][]) : 'T[][] { + let rowCount = Length(matrix); + Fact(rowCount > 0, "Matrix must have at least 1 row"); + let columnCount = Length(Head(matrix)); + Fact(columnCount > 0, "Matrix must have at least 1 column"); + Fact(IsRectangularArray(matrix), "Matrix is not a rectangular array"); + mutable transposed = []; + for columnIndex in 0..columnCount - 1 { + mutable newRow = []; + for rowIndex in 0..rowCount - 1 { + set newRow += [matrix[rowIndex][columnIndex]]; + } + set transposed += [newRow]; + } + transposed +} + +/// Returns the last element of the array. +/// +/// # Type Parameters +/// ## 'A +/// The type of the array elements. +/// +/// # Input +/// ## array +/// Array of which the last element is taken. Array must have at least 1 element. +/// +/// # Output +/// The last element of the array. +function Tail<'A>(array : 'A[]) : 'A { + let size = Length(array); + Fact(size > 0, "Array must have at least 1 element"); + array[size - 1] +} + +/// Given an array of 2-tuples, returns a tuple of two arrays, each containing +/// the elements of the tuples of the input array. +/// +/// # Type Parameters +/// ## 'T +/// The type of the first element in each tuple. +/// ## 'U +/// The type of the second element in each tuple. +/// +/// # Input +/// ## array +/// An array containing 2-tuples. +/// +/// # Output +/// Two arrays, the first one containing all first elements of the input +/// tuples, the second one containing all second elements of the input tuples. +/// +/// # Example +/// ```qsharp +/// // split is same as ([5, 4, 3, 2, 1], [true, false, true, true, false]) +/// let split = Unzipped([(5, true), (4, false), (3, true), (2, true), (1, false)]); +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.Zipped +function Unzipped<'T, 'U>(array : ('T, 'U)[]) : ('T[], 'U[]) { + mutable first = []; + mutable second = []; + for index in 0..Length(array) - 1 { + let (left, right) = array[index]; + set first += [left]; + set second += [right]; + } + return (first, second); +} + +/// Given a predicate and an array, returns the indices of that +/// array where the predicate is true. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## predicate +/// A function from `'T` to Boolean that is used to filter elements. +/// ## array +/// An array of elements over `'T`. +/// +/// # Output +/// An array of indices where `predicate` is true. +function Where<'T>(predicate : ('T -> Bool), array : 'T[]) : Int[] { + mutable indexes = []; + for index in 0..Length(array) - 1 { + if predicate(array[index]) { + set indexes += [index]; + } + } + indexes +} + +/// Returns all consecutive subarrays of length `size`. +/// +/// # Description +/// This function returns all `n - size + 1` subarrays of +/// length `size` in order, where `n` is the length of `array`. +/// The first subarrays are `array[0..size - 1], array[1..size], array[2..size + 1]` +/// until the last subarray `array[n - size..n - 1]`. +/// +/// # Type Parameters +/// ## 'T +/// The type of `array` elements. +/// +/// # Input +/// ## size +/// Length of the subarrays. +/// +/// ## array +/// An array of elements. +/// +/// # Example +/// ```qsharp +/// // same as [[1, 2, 3], [2, 3, 4], [3, 4, 5]] +/// let windows = Windows(3, [1, 2, 3, 4, 5]); +/// ``` +/// +/// # Remarks +/// The size of the window must be a positive integer no greater than the size of the array +function Windows<'T>(size : Int, array : 'T[]) : 'T[][] { + let arrayLength = Length(array); + Fact( + size > 0 or size <= arrayLength, + "The size of the window must be a positive integer no greater than the size of the array" + ); + + mutable windows = []; + for index in 0..arrayLength - size { + set windows += [array[index..index + size - 1]]; + } + windows +} + +/// Given two arrays, returns a new array of pairs such that each pair +/// contains an element from each original array. +/// +/// # Type Parameters +/// ## 'T +/// The type of the left array elements. +/// ## 'U +/// The type of the right array elements. +/// +/// # Input +/// ## left +/// An array containing values for the first element of each tuple. +/// ## right +/// An array containing values for the second element of each tuple. +/// +/// # Output +/// An array containing pairs of the form `(left[index], right[index])` for +/// each `index`. If the two arrays are not of equal length, the output will +/// be as long as the shorter of the inputs. +/// +/// # Example +/// ```qsharp +/// let left = [1, 3, 71]; +/// let right = [false, true]; +/// let pairs = Zipped(left, right); // [(1, false), (3, true)] +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Arrays.Unzipped +function Zipped<'T, 'U>(left : 'T[], right : 'U[]) : ('T, 'U)[] { + let arrayLength = MinI(Length(left), Length(right)); + mutable zipped = []; + for index in 0..arrayLength - 1 { + set zipped += [(left[index], right[index])]; + } + zipped +} + +export + All, + Any, + Chunks, + CircularlyShifted, + ColumnAt, + Count, + Diagonal, + DrawMany, + Enumerated, + Excluding, + Filtered, + FlatMapped, + Flattened, + Fold, + ForEach, + Head, + HeadAndRest, + IndexOf, + IndexRange, + Interleaved, + IsEmpty, + IsRectangularArray, + IsSorted, + IsSquareArray, + Mapped, + MappedByIndex, + MappedOverRange, + Most, + MostAndTail, + Padded, + Partitioned, + Rest, + Reversed, + SequenceI, + SequenceL, + Sorted, + Subarray, + Swapped, + Transposed, + Tail, + Unzipped, + Where, + Windows, + Zipped; diff --git a/library/std/src/Std/Canon.qs b/library/std/src/Std/Canon.qs new file mode 100644 index 0000000000..49fde0c17e --- /dev/null +++ b/library/std/src/Std/Canon.qs @@ -0,0 +1,650 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +import QIR.Intrinsic.*; +import Std.Intrinsic.*; +import Std.Diagnostics.*; +import Std.Math.*; + +/// # Summary +/// Applies an operation to each element in a register. +/// +/// # Input +/// ## singleElementOperation +/// Operation to apply to each element. +/// ## register +/// Array of elements on which to apply the given operation. +/// +/// # Type Parameters +/// ## 'T +/// The target on which the operation acts. +/// +/// # Example +/// Prepare a three-qubit |+⟩ state: +/// ```qsharp +/// use register = Qubit[3]; +/// ApplyToEach(H, register); +/// ``` +operation ApplyToEach<'T>(singleElementOperation : ('T => Unit), register : 'T[]) : Unit { + for item in register { + singleElementOperation(item); + } +} + +/// # Summary +/// Applies an operation to each element in a register. +/// The modifier `A` indicates that the single-element operation is adjointable. +/// +/// # Input +/// ## singleElementOperation +/// Operation to apply to each element. +/// ## register +/// Array of elements on which to apply the given operation. +/// +/// # Type Parameters +/// ## 'T +/// The target on which the operation acts. +/// +/// # Example +/// Prepare a three-qubit |+⟩ state: +/// ```qsharp +/// use register = Qubit[3]; +/// ApplyToEach(H, register); +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Canon.ApplyToEach +operation ApplyToEachA<'T>(singleElementOperation : ('T => Unit is Adj), register : 'T[]) : Unit is Adj { + for item in register { + singleElementOperation(item); + } +} + +/// # Summary +/// Applies an operation to each element in a register. +/// The modifier `C` indicates that the single-element operation is controllable. +/// +/// # Input +/// ## singleElementOperation +/// Operation to apply to each element. +/// ## register +/// Array of elements on which to apply the given operation. +/// +/// # Type Parameters +/// ## 'T +/// The target on which the operation acts. +/// +/// # Example +/// Prepare a three-qubit |+⟩ state: +/// ```qsharp +/// use register = Qubit[3]; +/// ApplyToEach(H, register); +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Canon.ApplyToEach +operation ApplyToEachC<'T>(singleElementOperation : ('T => Unit is Ctl), register : 'T[]) : Unit is Ctl { + for item in register { + singleElementOperation(item); + } +} + +/// # Summary +/// Applies an operation to each element in a register. +/// The modifier `CA` indicates that the single-element operation is controllable and adjointable. +/// +/// # Input +/// ## singleElementOperation +/// Operation to apply to each element. +/// ## register +/// Array of elements on which to apply the given operation. +/// +/// # Type Parameters +/// ## 'T +/// The target on which the operation acts. +/// +/// # Example +/// Prepare a three-qubit |+⟩ state: +/// ```qsharp +/// use register = Qubit[3]; +/// ApplyToEach(H, register); +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Canon.ApplyToEach +operation ApplyToEachCA<'T>(singleElementOperation : ('T => Unit is Adj + Ctl), register : 'T[]) : Unit is Adj + Ctl { + for item in register { + singleElementOperation(item); + } +} + +/// # Summary +/// Applies the controlled-X (CX) gate to a pair of qubits. +/// +/// # Input +/// ## control +/// Control qubit for the CX gate. +/// ## target +/// Target qubit for the CX gate. +/// +/// # Remarks +/// This operation can be simulated by the unitary matrix +/// $$ +/// \begin{align} +/// \left(\begin{matrix} +/// 1 & 0 & 0 & 0 \\\\ +/// 0 & 1 & 0 & 0 \\\\ +/// 0 & 0 & 0 & 1 \\\\ +/// 0 & 0 & 1 & 0 +/// \end{matrix}\right) +/// \end{align}, +/// $$ +/// where rows and columns are organized as in the quantum concepts guide. +/// +/// Equivalent to: +/// ```qsharp +/// Controlled X([control], target); +/// ``` +/// and to: +/// ```qsharp +/// CNOT(control, target); +/// ``` +operation CX(control : Qubit, target : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__cx__body(control, target); + } + controlled (ctls, ...) { + Controlled X(ctls + [control], target); + } + adjoint self; +} + +/// # Summary +/// Applies the controlled-Y (CY) gate to a pair of qubits. +/// +/// # Input +/// ## control +/// Control qubit for the CY gate. +/// ## target +/// Target qubit for the CY gate. +/// +/// # Remarks +/// This operation can be simulated by the unitary matrix +/// $$ +/// \begin{align} +/// \left(\begin{matrix} +/// 1 & 0 & 0 & 0 \\\\ +/// 0 & 1 & 0 & 0 \\\\ +/// 0 & 0 & 0 & -i \\\\ +/// 0 & 0 & i & 0 +/// \end{matrix}\right) +/// \end{align}, +/// $$ +/// where rows and columns are organized as in the quantum concepts guide. +/// +/// Equivalent to: +/// ```qsharp +/// Controlled Y([control], target); +/// ``` +operation CY(control : Qubit, target : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__cy__body(control, target); + } + controlled (ctls, ...) { + Controlled Y(ctls + [control], target); + } + adjoint self; +} + +/// # Summary +/// Applies the controlled-Z (CZ) gate to a pair of qubits. +/// +/// # Input +/// ## control +/// Control qubit for the CZ gate. +/// ## target +/// Target qubit for the CZ gate. +/// +/// # Remarks +/// This operation can be simulated by the unitary matrix +/// $$ +/// \begin{align} +/// \left(\begin{matrix} +/// 1 & 0 & 0 & 0 \\\\ +/// 0 & 1 & 0 & 0 \\\\ +/// 0 & 0 & 1 & 0 \\\\ +/// 0 & 0 & 0 & -1 +/// \end{matrix}\right) +/// \end{align}, +/// $$ +/// where rows and columns are organized as in the quantum concepts guide. +/// +/// Equivalent to: +/// ```qsharp +/// Controlled Z([control], target); +/// ``` +operation CZ(control : Qubit, target : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__cz__body(control, target); + } + controlled (ctls, ...) { + Controlled Z(ctls + [control], target); + } + adjoint self; +} + + /// Given a pair, returns its first element. +function Fst<'T, 'U>(pair : ('T, 'U)) : 'T { + let (fst, _) = pair; + return fst; +} + + /// Given a pair, returns its second element. +function Snd<'T, 'U>(pair : ('T, 'U)) : 'U { + let (_, snd) = pair; + return snd; +} + +/// # Summary +/// Computes the parity of a register of qubits in-place. +/// +/// # Input +/// ## qubits +/// Array of qubits whose parity is to be computed and stored. +/// +/// # Remarks +/// This operation transforms the state of its input as +/// $$ +/// \begin{align} +/// \ket{q_0} \ket{q_1} \cdots \ket{q_{n - 1}} & \mapsto +/// \ket{q_0} \ket{q_0 \oplus q_1} \ket{q_0 \oplus q_1 \oplus q_2} \cdots +/// \ket{q_0 \oplus \cdots \oplus q_{n - 1}}. +/// \end{align} +/// $$ +operation ApplyCNOTChain(qubits : Qubit[]) : Unit is Adj + Ctl { + for i in 0..Length(qubits) - 2 { + CNOT(qubits[i], qubits[i + 1]); + } +} + +/// # Summary +/// Given a single-qubit Pauli operator, applies the corresponding operation +/// to a single qubit. +/// +/// # Input +/// ## pauli +/// The Pauli operator to be applied. +/// ## target +/// The qubit to which `pauli` is to be applied as an operation. +/// +/// # Example +/// The following are equivalent: +/// ```qsharp +/// ApplyP(PauliX, q); +/// ``` +/// and +/// ```qsharp +/// X(q); +/// ``` +operation ApplyP(pauli : Pauli, target : Qubit) : Unit is Adj + Ctl { + if pauli == PauliX { X(target); } elif pauli == PauliY { Y(target); } elif pauli == PauliZ { Z(target); } +} + +/// # Summary +/// Given a multi-qubit Pauli operator, applies the corresponding operation +/// to a quantum register. +/// +/// # Input +/// ## pauli +/// A multi-qubit Pauli operator represented as an array of single-qubit Pauli operators. +/// ## target +/// Register to apply the given Pauli operation on. +/// +/// # Example +/// The following are equivalent: +/// ```qsharp +/// ApplyPauli([PauliY, PauliZ, PauliX], target); +/// ``` +/// and +/// ```qsharp +/// Y(target[0]); +/// Z(target[1]); +/// X(target[2]); +/// ``` +operation ApplyPauli(pauli : Pauli[], target : Qubit[]) : Unit is Adj + Ctl { + Fact(Length(pauli) == Length(target), "`pauli` and `target` must be of the same length."); + for i in 0..Length(pauli) - 1 { + ApplyP(pauli[i], target[i]); + } +} + +/// # Summary +/// Applies a Pauli operator on each qubit in an array if the corresponding +/// bit of a Boolean array matches a given input. +/// +/// # Input +/// ## pauli +/// Pauli operator to apply to `qubits[idx]` where `bitApply == bits[idx]` +/// ## bitApply +/// apply Pauli if bit is this value +/// ## bits +/// Boolean register specifying which corresponding qubit in `qubits` should be operated on +/// ## qubits +/// Quantum register on which to selectively apply the specified Pauli operator +/// +/// # Remarks +/// The Boolean array and the quantum register must be of equal length. +/// +/// # Example +/// The following applies an X operation on qubits 0 and 2, and a Z operation on qubits 1 and 3. +/// ```qsharp +/// use qubits = Qubit[4]; +/// let bits = [true, false, true, false]; +/// // Apply when index in `bits` is `true`. +/// ApplyPauliFromBitString(PauliX, true, bits, qubits); +/// // Apply when index in `bits` is `false`. +/// ApplyPauliFromBitString(PauliZ, false, bits, qubits); +/// ``` +operation ApplyPauliFromBitString(pauli : Pauli, bitApply : Bool, bits : Bool[], qubits : Qubit[]) : Unit is Adj + Ctl { + let nBits = Length(bits); + Fact(nBits == Length(qubits), "Number of bits must be equal to number of qubits."); + for i in 0..nBits - 1 { + if bits[i] == bitApply { + ApplyP(pauli, qubits[i]); + } + } +} + +/// # Summary +/// Applies a Pauli operator on each qubit in an array if the corresponding +/// bit of a Little-endian integer matches a given input. +/// +/// # Input +/// ## pauli +/// Pauli operator to apply to `qubits[idx]` when bit of numberState +/// in idx position is the same as bitApply. +/// ## bitApply +/// apply Pauli if bit is this value +/// ## numberState +/// Little-endian integer specifying which corresponding qubit in `qubits` should be operated on +/// ## qubits +/// Quantum register on which to selectively apply the specified Pauli operator +/// +/// # Example +/// The following applies an X operation on qubits 0 and 2, and a Z operation on qubits 1 and 3. +/// ```qsharp +/// use qubits = Qubit[4]; +/// let n = 5; +/// // Apply when index in `bits` is `true`. +/// ApplyPauliFromBitString(PauliX, true, n, qubits); +/// // Apply when index in `bits` is `false`. +/// ApplyPauliFromBitString(PauliZ, false, n, qubits); +/// ``` +operation ApplyPauliFromInt( + pauli : Pauli, + bitApply : Bool, + numberState : Int, + qubits : Qubit[] +) : Unit is Adj + Ctl { + + let length = Length(qubits); + Fact(numberState >= 0, "number must be non-negative"); + Fact(BitSizeI(numberState) <= length, "Bit size of numberState must not exceed qubits length"); + + for i in 0..length - 1 { + // If we assume loop unrolling, 2^i will be optimized to a constant. + if ((numberState &&& (1 <<< i)) != 0) == bitApply { + ApplyP(pauli, qubits[i]); + } + } +} + +/// # Summary +/// Applies a unitary operation on the target if the control +/// register state corresponds to a specified nonnegative integer. +/// +/// # Input +/// ## numberState +/// A nonnegative integer on which the operation `oracle` should be +/// controlled. +/// ## oracle +/// A unitary operation to be controlled. +/// ## target +/// A target on which to apply `oracle`. +/// ## controlRegister +/// A quantum register that controls application of `oracle`. +/// +/// # Remarks +/// The value of `numberState` is interpreted using a little-endian encoding. +/// +/// `numberState` must be at most $2^\texttt{Length(controlRegister)} - 1$. +/// For example, `numberState = 537` means that `oracle` +/// is applied if and only if `controlRegister` is in the state $\ket{537}$. +operation ApplyControlledOnInt<'T>( + numberState : Int, + oracle : ('T => Unit is Adj + Ctl), + controlRegister : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + within { + ApplyPauliFromInt(PauliX, false, numberState, controlRegister); + } apply { + Controlled oracle(controlRegister, target); + } +} + +/// # Summary +/// Applies `oracle` on `target` when `controlRegister` +/// is in the state specified by `bits`. +/// +/// # Description +/// Applies a unitary operation `oracle` on the `target`, controlled +/// on a state specified by a given bit mask `bits`. +/// The bit at `bits[i]` corresponds to qubit at `controlRegister[i]`. +/// The pattern given by `bits` may be shorter than `controlRegister`, +/// in which case additional control qubits are ignored (that is, neither +/// controlled on |0⟩ nor |1⟩). +/// If `bits` is longer than `controlRegister`, an error is raised. +/// +/// # Input +/// ## bits +/// The bit string to control the given unitary operation on. +/// ## oracle +/// The unitary operation to be applied on the target. +/// ## target +/// The target to be passed to `oracle` as an input. +/// ## controlRegister +/// A quantum register that controls application of `oracle`. +/// +/// # Example +/// ```qsharp +/// // When bits = [1,0,0] oracle is applied if and only if controlRegister +/// // is in the state |100⟩. +/// use t = Qubit(); +/// use c = Qubit[3]; +/// X(c[0]); +/// ApplyControlledOnBitString([true, false, false], X, c, t); +/// Message($"{M(t)}"); // Prints `One` since oracle `X` was applied. +/// ``` +operation ApplyControlledOnBitString<'T>( + bits : Bool[], + oracle : ('T => Unit is Adj + Ctl), + controlRegister : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + // The control register must have enough bits to implement the requested control. + Fact(Length(bits) <= Length(controlRegister), "Control register shorter than control pattern."); + + // Use a subregister of the controlled register when + // bits is shorter than controlRegister. + let controlSubregister = controlRegister[...Length(bits) - 1]; + within { + ApplyPauliFromBitString(PauliX, false, bits, controlSubregister); + } apply { + Controlled oracle(controlSubregister, target); + } +} + +/// # Summary +/// Applies the rotations of Quantum Fourier Transform (QFT) to a little-endian quantum register. +/// +/// # Description +/// Applies the rotations of QFT to a little-endian register `qs` of length n +/// containing |x₁⟩⊗|x₂⟩⊗…⊗|xₙ⟩. The qs[0] initially contains the +/// least significant bit xₙ. The state of qs[0] becomes +/// (|0⟩+𝑒^(2π𝑖[0.xₙ])|1⟩)/sqrt(2) after the operation. +/// +/// # Input +/// ## qs +/// Quantum register in a little-endian format to which the rotations are applied. +/// +/// # Remarks +/// Note that this operation applies only the rotations part of the QFT. +/// To complete the transform, you need to reverse the order of qubits after this operation, +/// for example, using the operation `SwapReverseRegister`. +/// +/// # Reference +/// - [Quantum Fourier transform](https://en.wikipedia.org/wiki/Quantum_Fourier_transform) +operation ApplyQFT(qs : Qubit[]) : Unit is Adj + Ctl { + let length = Length(qs); + Fact(length >= 1, "ApplyQFT: Length(qs) must be at least 1."); + for i in length - 1..-1..0 { + H(qs[i]); + for j in 0..i - 1 { + Controlled R1Frac([qs[i]], (1, j + 1, qs[i - j - 1])); + } + } +} + +/// # Summary +/// Uses SWAP gates to reverse the order of the qubits in a register. +/// +/// # Input +/// ## register +/// The qubits order of which should be reversed using SWAP gates +operation SwapReverseRegister(register : Qubit[]) : Unit is Adj + Ctl { + let length = Length(register); + for i in 0..length / 2 - 1 { + SWAP(register[i], register[(length - i) - 1]); + } +} + +/// # Summary +/// Applies a bitwise-XOR operation between a classical integer and an +/// integer represented by a register of qubits. +/// +/// # Description +/// Applies `X` operations to qubits in a little-endian register based on +/// 1 bits in an integer. +/// +/// Let us denote `value` by a and let y be an unsigned integer encoded in `target`, +/// then `ApplyXorInPlace` performs an operation given by the following map: +/// |y⟩ ↦ |y ⊕ a⟩, where ⊕ is the bitwise exclusive OR operator. +operation ApplyXorInPlace(value : Int, target : Qubit[]) : Unit is Adj + Ctl { + body (...) { + Fact(value >= 0, "`value` must be non-negative."); + mutable runningValue = value; + for q in target { + if (runningValue &&& 1) != 0 { + X(q); + } + set runningValue >>>= 1; + } + Fact(runningValue == 0, "value is too large"); + } + adjoint self; +} + +/// # Summary +/// Applies a bitwise-XOR operation between a classical integer and an +/// integer represented by a register of qubits. +/// +/// # Description +/// Applies `X` operations to qubits in a little-endian register based on +/// 1 bits in an integer. +/// +/// Let us denote `value` by a and let y be an unsigned integer encoded in `target`, +/// then `ApplyXorInPlace` performs an operation given by the following map: +/// |y⟩ ↦ |y ⊕ a⟩, where ⊕ is the bitwise exclusive OR operator. +operation ApplyXorInPlaceL(value : BigInt, target : Qubit[]) : Unit is Adj + Ctl { + body (...) { + Fact(value >= 0L, "`value` must be non-negative."); + mutable runningValue = value; + for q in target { + if (runningValue &&& 1L) != 0L { + X(q); + } + set runningValue >>>= 1; + } + Fact(runningValue == 0L, "`value` is too large."); + } + adjoint self; +} + /// # Summary +/// Relabels the qubits in the `current` array with the qubits in the `updated` array. The `updated` array +/// must be a valid permutation of the `current` array. +/// +/// # Input +/// ## current +/// Array of qubits to be relabeled. +/// ## updated +/// Array of qubits with which to relabel the `current` array. +/// +/// # Remarks +/// This operation is useful when you need to relabel qubits in a way that does not incur any quantum operations. +/// Note that when compiling for execution on hardware with limited qubit connectivity, this operation +/// may not result in any changes to qubit adjacency and one or more `SWAP` gates may still be required. +/// +/// # Example +/// The following example demonstrates how to relabel qubits in a register: +/// ```qsharp +/// use qubits = Qubit[3]; +/// let newOrder = [qubits[2], qubits[0], qubits[1]]; +/// Relabel(qubits, newOrder); +/// ``` +/// After this operation, any use of `qubits[0]` will refer to the qubit that was originally `qubits[2]`, and so on. +/// To exchange the labels on two qubits, the virtual equivalent of a `SWAP` gate, you can use the following code: +/// ```qsharp +/// use (q0, q1) = (Qubit(), Qubit()); +/// Relabel([q0, q1], [q1, q0]); +/// ``` +/// 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; +} + +export + ApplyToEach, + ApplyToEachA, + ApplyToEachC, + ApplyToEachCA, + CX, + CY, + CZ, + Fst, + Snd, + ApplyCNOTChain, + ApplyP, + ApplyPauli, + ApplyPauliFromBitString, + ApplyPauliFromInt, + ApplyControlledOnInt, + ApplyControlledOnBitString, + ApplyQFT, + SwapReverseRegister, + ApplyXorInPlace, + ApplyXorInPlaceL, + Relabel; diff --git a/library/std/src/Std/Convert.qs b/library/std/src/Std/Convert.qs new file mode 100644 index 0000000000..08d2a1568e --- /dev/null +++ b/library/std/src/Std/Convert.qs @@ -0,0 +1,284 @@ +import Std.Diagnostics.*; +import Std.Math.*; + +/// # Summary +/// Converts a given integer `number` to an equivalent +/// double-precision floating-point number. +/// +/// # Description +/// Converts a given integer to a double-precision floating point number. +/// Please note that the double-precision representation may have fewer +/// bits allocated to represent [significant digits](https://en.wikipedia.org/wiki/Significand) +/// so the conversion may be approximate for large numbers. For example, +/// the current simulator converts 4,611,686,018,427,387,919 = 2^64+15 +/// to 4,611,686,018,427,387,904.0 = 2^64. +/// +/// # Example +/// ```qsharp +/// Message($"{IntAsDouble(1)}"); // Prints 1.0 rather than 1 +/// ``` +function IntAsDouble(number : Int) : Double { + body intrinsic; +} + +/// Converts a given integer `number` to an equivalent big integer. +function IntAsBigInt(number : Int) : BigInt { + body intrinsic; +} + +/// Converts a `Result` type to a `Bool` type, where `One` is mapped to +/// `true` and `Zero` is mapped to `false`. +/// +/// # Input +/// ## input +/// `Result` to be converted. +/// +/// # Output +/// A `Bool` representing the `input`. +function ResultAsBool(input : Result) : Bool { + input == One +} + +/// Converts a `Bool` type to a `Result` type, where `true` is mapped to +/// `One` and `false` is mapped to `Zero`. +/// +/// # Input +/// ## input +/// `Bool` to be converted. +/// +/// # Output +/// A `Result` representing the `input`. +function BoolAsResult(input : Bool) : Result { + if input { One } else { Zero } +} + +/// Produces a non-negative integer from a string of bits in little-endian format. +/// `bits[0]` represents the least significant bit. +/// +/// # Input +/// ## bits +/// Bits in binary representation of number. +function BoolArrayAsInt(bits : Bool[]) : Int { + let nBits = Length(bits); + Fact(nBits < 64, $"`Length(bits)` must be less than 64, but was {nBits}."); + + mutable number = 0; + for i in 0..nBits - 1 { + if (bits[i]) { + set number |||= 1 <<< i; + } + } + + number +} + +/// Produces a binary representation of a non-negative integer, using the +/// little-endian representation for the returned array. +/// +/// # Input +/// ## number +/// A non-negative integer to be converted to an array of Boolean values. +/// ## bits +/// The number of bits in the binary representation of `number`. +/// +/// # Output +/// An array of Boolean values representing `number`. +/// +/// # Remarks +/// The input `bits` must be non-negative. +/// The input `number` must be between 0 and 2^bits - 1. +function IntAsBoolArray(number : Int, bits : Int) : Bool[] { + Fact(bits >= 0, "Requested number of bits must be non-negative."); + Fact(number >= 0, "Number must be non-negative."); + mutable runningValue = number; + mutable result = []; + for _ in 1..bits { + set result += [(runningValue &&& 1) != 0]; + set runningValue >>>= 1; + } + Fact(runningValue == 0, "`number` is too large to fit into array of length `bits`."); + + result +} + +/// Converts an array of Boolean values into a non-negative BigInt, interpreting the +/// array as a binary representation in little-endian format. +/// +/// # Input +/// ## boolArray +/// An array of Boolean values representing the binary digits of a BigInt. +/// +/// # Output +/// A BigInt represented by `boolArray`. +/// +/// # Remarks +/// The function interprets the array in little-endian format, where the first +/// element of the array represents the least significant bit. +/// The input `boolArray` should not be empty. +function BoolArrayAsBigInt(boolArray : Bool[]) : BigInt { + mutable result = 0L; + for i in 0..Length(boolArray) - 1 { + if boolArray[i] { + set result += 1L <<< i; + } + } + + result +} + +/// Produces a binary representation of a non-negative BigInt, using the +/// little-endian representation for the returned array. +/// +/// # Input +/// ## number +/// A non-negative BigInt to be converted to an array of Boolean values. +/// ## bits +/// The number of bits in the binary representation of `number`. +/// +/// # Output +/// An array of Boolean values representing `number`. +/// +/// # Remarks +/// The input `bits` must be non-negative. +/// The input `number` must be between 0 and 2^bits - 1. +function BigIntAsBoolArray(number : BigInt, bits : Int) : Bool[] { + Fact(bits >= 0, "Requested number of bits must be non-negative."); + Fact(number >= 0L, "Number must be non-negative."); + mutable runningValue = number; + mutable result = []; + for _ in 1..bits { + set result += [(runningValue &&& 1L) != 0L]; + set runningValue >>>= 1; + } + Fact(runningValue == 0L, $"`number`={number} is too large to fit into {bits} bits."); + + result +} + +/// Produces a non-negative integer from a string of Results in little-endian format. +/// +/// # Input +/// ## results +/// Results in binary representation of number. +/// +/// # Output +/// A non-negative integer +/// +/// # Example +/// ```qsharp +/// // The following returns 1 +/// let int1 = ResultArrayAsInt([One,Zero]) +/// ``` +function ResultArrayAsInt(results : Result[]) : Int { + let nBits = Length(results); + Fact(nBits < 64, $"`Length(bits)` must be less than 64, but was {nBits}."); + + mutable number = 0; + for idxBit in 0..nBits - 1 { + if (results[idxBit] == One) { + set number |||= 1 <<< idxBit; + } + } + + number +} + +/// Converts a `Result[]` type to a `Bool[]` type, where `One` +/// is mapped to `true` and `Zero` is mapped to `false`. +/// +/// # Input +/// ## input +/// `Result[]` to be converted. +/// +/// # Output +/// A `Bool[]` representing the `input`. +function ResultArrayAsBoolArray(input : Result[]) : Bool[] { + mutable output = []; + for r in input { + set output += [r == One]; + } + + output +} + +/// Converts a `Bool[]` type to a `Result[]` type, where `true` +/// is mapped to `One` and `false` is mapped to `Zero`. +/// +/// # Input +/// ## input +/// `Bool[]` to be converted. +/// +/// # Output +/// A `Result[]` representing the `input`. +function BoolArrayAsResultArray(input : Bool[]) : Result[] { + mutable output = []; + for b in input { + set output += [if b { One } else { Zero }]; + } + + output +} + +/// Converts a complex number of type `Complex` to a complex +/// number of type `ComplexPolar`. +/// +/// # Input +/// ## input +/// Complex number c = x + y𝑖. +/// +/// # Output +/// Complex number c = r⋅e^(t𝑖). +function ComplexAsComplexPolar(input : Complex) : ComplexPolar { + return ComplexPolar(AbsComplex(input), ArgComplex(input)); +} + +/// Converts a complex number of type `ComplexPolar` to a complex +/// number of type `Complex`. +/// +/// # Input +/// ## input +/// Complex number c = r⋅e^(t𝑖). +/// +/// # Output +/// Complex number c = x + y𝑖. +function ComplexPolarAsComplex(input : ComplexPolar) : Complex { + return Complex( + input.Magnitude * Cos(input.Argument), + input.Magnitude * Sin(input.Argument) + ); +} + +/// Converts a given double-precision floating-point number to a string representation with desired precision, rounding if required. +/// +/// # Input +/// ## input +/// Double to be converted. +/// ## precision +/// Non-negative number of digits after the decimal point. +/// +/// # Example +/// ```qsharp +/// Message($"{DoubleAsStringWithPrecision(0.354, 2)}"); // Prints 0.35 +/// Message($"{DoubleAsStringWithPrecision(0.485, 1)}"); // Prints 0.5 +/// Message($"{DoubleAsStringWithPrecision(5.6, 4)}"); // Prints 5.6000 +/// Message($"{DoubleAsStringWithPrecision(2.268, 0)}"); // Prints 2 +/// ``` +function DoubleAsStringWithPrecision(input : Double, precision : Int) : String { + body intrinsic; +} + +export + IntAsDouble, + IntAsBigInt, + ResultAsBool, + BoolAsResult, + BoolArrayAsInt, + IntAsBoolArray, + BoolArrayAsBigInt, + BigIntAsBoolArray, + ResultArrayAsInt, + ResultArrayAsBoolArray, + BoolArrayAsResultArray, + ComplexAsComplexPolar, + ComplexPolarAsComplex, + DoubleAsStringWithPrecision; \ No newline at end of file diff --git a/library/std/src/Std/Diagnostics.qs b/library/std/src/Std/Diagnostics.qs new file mode 100644 index 0000000000..2b9d40b5c0 --- /dev/null +++ b/library/std/src/Std/Diagnostics.qs @@ -0,0 +1,332 @@ +open QIR.Intrinsic; + +/// # Summary +/// Dumps the current target machine's status. +/// +/// # Description +/// This method allows you to dump information about the current quantum state. +/// The actual information generated and the semantics are specific to each target machine. +/// +/// For the local sparse-state simulator distributed as part of the +/// Quantum Development Kit, this method will write the wave function as a +/// one-dimensional array of pairs of state indices and complex numbers, in which each element represents +/// the amplitudes of the probability of measuring the corresponding state. +/// +/// # Example +/// When run on the sparse-state simulator, the following snippet dumps +/// the Bell state (|00⟩ + |11⟩ ) / √2 to the console: +/// ```qsharp +/// use left = Qubit(); +/// use right = Qubit(); +/// within { +/// H(left); +/// CNOT(left, right); +/// } apply { +/// DumpMachine(); +/// } +/// ``` +function DumpMachine() : Unit { + body intrinsic; +} + +/// Dumps the current target machine's status associated with the given qubits. +/// +/// # Input +/// ## qubits +/// The list of qubits to report. +/// +/// # Remarks +/// This method allows you to dump the information associated with the state of the +/// given qubits. +/// +/// For the local sparse-state simulator distributed as part of the +/// Quantum Development Kit, this method will write the +/// state of the given qubits (i.e. the wave function of the corresponding subsystem) as a +/// one-dimensional array of pairs of state indices and complex numbers, in which each element represents +/// the amplitudes of the probability of measuring the corresponding state. +/// If the given qubits are entangled with some other qubit and their +/// state can't be separated, it fails with a runtime error indicating that the qubits are entangled. +/// +/// # Example +/// When run on the sparse-state simulator, the following snippet dumps +/// the Bell state (|00⟩ + |11⟩ ) / √2 to the console: +/// ```qsharp +/// use left = Qubit(); +/// use right = Qubit(); +/// within { +/// H(left); +/// CNOT(left, right); +/// } apply { +/// DumpRegister([left, right]); +/// } +/// ``` +function DumpRegister(register : Qubit[]) : Unit { + body intrinsic; +} + +/// Checks whether a qubit is in the |0⟩ state, returning true if it is. +/// +/// # Description +/// This operation checks whether a qubit is in the |0⟩ state. It will return true only +/// if the qubit is deterministically in the |0⟩ state, and will return false otherwise. This operation +/// does not change the state of the qubit. +/// +/// # Input +/// ## qubit +/// The qubit to check. +/// # Output +/// True if the qubit is in the |0⟩ state, false otherwise. +/// +/// # Remarks +/// This operation is useful for checking whether a qubit is in the |0⟩ state during simulation. It is not possible to check +/// this on hardware without measuring the qubit, which could change the state. +@Config(Unrestricted) +operation CheckZero(qubit : Qubit) : Bool { + body intrinsic; +} + +/// Checks whether all qubits in the provided array are in the |0⟩ state. Returns true if they are. +/// +/// # Description +/// This operation checks whether all qubits in the provided array are in the |0⟩ state. It will return true only +/// if all qubits are deterministically in the |0⟩ state, and will return false otherwise. This operation +/// does not change the state of the qubits. +/// +/// # Input +/// ## qubits +/// The qubits to check. +/// # Output +/// True if all qubits are in the |0⟩ state, false otherwise. +/// +/// # Remarks +/// This operation is useful for checking whether a qubit is in the |0⟩ state during simulation. It is not possible to check +/// this on hardware without measuring the qubit, which could change the state. +@Config(Unrestricted) +operation CheckAllZero(qubits : Qubit[]) : Bool { + for q in qubits { + if not CheckZero(q) { + return false; + } + } + + return true; +} + +/// Checks whether a given condition is true, failing with a message if it is not. +/// +/// # Description +/// This function checks whether a given condition is true. If the condition is false, the operation fails with the given message, +/// terminating the program. +/// +/// # Input +/// ## actual +/// The condition to check. +/// ## message +/// The message to use in the failure if the condition is false. +function Fact(actual : Bool, message : String) : Unit { + if (not actual) { + fail message; + } +} + +/// Given two operations, checks that they act identically for all input states. +/// +/// # Description +/// This check is implemented by using the Choi–Jamiołkowski isomorphism to reduce +/// this check to a check on two entangled registers. +/// Thus, this operation needs only a single call to each operation being tested, +/// but requires twice as many qubits to be allocated. +/// This check can be used to ensure, for instance, that an optimized version of an +/// operation acts identically to its naïve implementation, or that an operation +/// which acts on a range of non-quantum inputs agrees with known cases. +/// +/// # Remarks +/// This operation requires that the operation modeling the expected behavior is +/// adjointable, so that the inverse can be performed on the target register alone. +/// Formally, one can specify a transpose operation, which relaxes this requirement, +/// but the transpose operation is not in general physically realizable for arbitrary +/// quantum operations and thus is not included here as an option. +/// +/// # Input +/// ## nQubits +/// Number of qubits to pass to each operation. +/// ## actual +/// Operation to be tested. +/// ## expected +/// Operation defining the expected behavior for the operation under test. +/// # Output +/// True if operations are equal, false otherwise. +@Config(Unrestricted) +operation CheckOperationsAreEqual( + nQubits : Int, + actual : (Qubit[] => Unit), + expected : (Qubit[] => Unit is Adj) +) : Bool { + + // Prepare a reference register entangled with the target register. + use reference = Qubit[nQubits]; + use target = Qubit[nQubits]; + + // Apply operations. + within { + for i in 0..nQubits - 1 { + H(reference[i]); + CNOT(reference[i], target[i]); + } + } apply { + actual(target); + Adjoint expected(target); + } + + // Check and return result. + let areEqual = CheckAllZero(reference) and CheckAllZero(target); + ResetAll(target); + ResetAll(reference); + areEqual +} + +/// Starts counting the number of times the given operation is called. Fails if the operation is already being counted. +/// +/// # Description +/// This operation allows you to count the number of times a given operation is called. If the given operation is already +/// being counted, calling `StartCountingOperation` again will trigger a runtime failure. Counting is based on the specific +/// specialization of the operation invoked, so `X` and `Adjoint X` are counted separately. +/// Likewise `Controlled X`, `CNOT`, and `CX` are independent operations that are counted separately, as are `Controlled X` +/// and `Controlled Adjoint X`. +/// +/// # Input +/// ## callable +/// The operation to be counted. +/// +/// # Remarks +/// Counting operation calls requires specific care in what operation is passed as input. For example, `StartCountingOperation(H)` will +/// count only the number of times `H` is called, while `StartCountingOperation(Adjoint H)` will count only the number of times `Adjoint H` is called, even +/// though `H` is self-adjoint. This is due to how the execution treats the invocation of these operations as distinct by their specialization. +/// In the same way, `StartCountingOperation(Controlled X)` will count only the number of times `Controlled X` is called, while +/// `StartCountingOperation(CNOT)` will count only the number of times `CNOT` is called. +/// +/// When counting lambdas, the symbol the lambda is bound to is used to identify the operation and it is counted as a separate operation. For example, +/// ```qsharp +/// let myOp = q => H(q); +/// StartCountingOperation(myOp); +/// ``` +/// Will count specifically calls to `myOp` and not `H`. By contrast, the following code will count calls to `H` itself: +/// ```qsharp +/// let myOp = H; +/// StartCountingOperation(myOp); +/// ``` +/// This is because this code does not define a lambda and instead just creates a binding to `H` directly. +@Config(Unrestricted) +operation StartCountingOperation<'In, 'Out>(callable : 'In => 'Out) : Unit { + body intrinsic; +} + +/// Stops counting the number of times the given operation is called and returns the count. Fails +/// if the operation was not being counted. +/// +/// # Description +/// This operation allows you to stop counting the number of times a given operation is called and returns the count. +/// If the operation was not being counted, it triggers a runtime failure. +/// +/// # Input +/// ## callable +/// The operation whose count will be returned. +/// # Output +/// The number of times the operation was called since the last call to `StartCountingOperation`. +@Config(Unrestricted) +operation StopCountingOperation<'In, 'Out>(callable : 'In => 'Out) : Int { + body intrinsic; +} + +/// Starts counting the number of times the given function is called. Fails if the function is already being counted. +/// +/// # Description +/// This operation allows you to count the number of times a given function is called. If the given function is already +/// being counted, calling `StartCountingFunction` again will trigger a runtime failure. +/// +/// # Input +/// ## callable +/// The function to be counted. +/// +/// # Remarks +/// When counting lambdas, the symbol the lambda is bound to is used to identify the function and it is counted as a separate function. For example, +/// ```qsharp +/// let myFunc = i -> AbsI(i); +/// StartCountingFunction(myFunc); +/// ``` +/// Will count specifically calls to `myFunc` and not `AbsI`. By contrast, the following code will count calls to `AbsI` itself: +/// ```qsharp +/// let myFunc = AbsI; +/// StartCountingFunction(myFunc); +/// ``` +/// This is because this code does not define a lambda and instead just creates a binding to `AbsI` directly. +@Config(Unrestricted) +operation StartCountingFunction<'In, 'Out>(callable : 'In -> 'Out) : Unit { + body intrinsic; +} + +/// Stops counting the number of times the given function is called and returns the count. Fails +/// if the function was not being counted. +/// +/// # Description +/// This operation allows you to stop counting the number of times a given function is called and returns the count. +/// If the function was not being counted, it triggers a runtime failure. +/// +/// # Input +/// ## callable +/// The function whose count will be returned. +/// # Output +/// The number of times the function was called since the last call to `StartCountingFunction`. +@Config(Unrestricted) +operation StopCountingFunction<'In, 'Out>(callable : 'In -> 'Out) : Int { + body intrinsic; +} + +/// Starts counting the number of qubits allocated. Fails if qubits are already being counted. +/// +/// # Description +/// This operation allows you to count the number of qubits allocated until `StopCountingQubits` is called. +/// The counter is incremented only when a new unique qubit is allocated, so reusing the same qubit multiple times +/// across separate allocations does not increment the counter. +/// +/// # Remarks +/// This operation is useful for tracking the number of unique qubits allocated in a given scope. Along with +/// `StopCountingQubits`, it can be used to verify that a given operation does not allocate more qubits than +/// expected. For example, +/// ```qsharp +/// StartCountingQubits(); +/// testOperation(); +/// let qubitsAllocated = StopCountingQubits(); +/// Fact(qubitsAllocated <= 4, "Operation should not allocate more than 4 qubits."); +/// ``` +@Config(Unrestricted) +operation StartCountingQubits() : Unit { + body intrinsic; +} + +/// Stops counting the number of qubits allocated and returns the count. Fails if the qubits were not being counted. +/// +/// # Description +/// This operation allows you to stop counting the number of qubits allocated and returns the count since the +/// last call to `StartCountingQubits`. If the qubits were not being counted, it triggers a runtime failure. +/// +/// # Output +/// The number of unique qubits allocated since the last call to `StartCountingQubits`. +@Config(Unrestricted) +operation StopCountingQubits() : Int { + body intrinsic; +} + +export + DumpMachine, + DumpRegister, + CheckZero, + CheckAllZero, + Fact, + CheckOperationsAreEqual, + StartCountingOperation, + StopCountingOperation, + StartCountingFunction, + StopCountingFunction, + StartCountingQubits, + StopCountingQubits; \ No newline at end of file diff --git a/library/std/src/Std/InternalHelpers.qs b/library/std/src/Std/InternalHelpers.qs new file mode 100644 index 0000000000..61da81a939 --- /dev/null +++ b/library/std/src/Std/InternalHelpers.qs @@ -0,0 +1,250 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +import Std.Arrays.*; +import Std.Core.*; +import Std.Math.*; +import Std.Intrinsic.*; +import QIR.Intrinsic.*; + +internal operation CH(control : Qubit, target : Qubit) : Unit is Adj { + within { + S(target); + H(target); + T(target); + } apply { + CNOT(control, target); + } +} + +internal operation CCH(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + within { + S(target); + H(target); + T(target); + } apply { + CCNOT(control1, control2, target); + } +} + +internal operation ApplyGlobalPhase(theta : Double) : Unit is Ctl + Adj { + body ... { + ControllableGlobalPhase(theta); + } + adjoint ... { + ControllableGlobalPhase(-theta); + } +} + +// Global phase is not relevant for physical systems, but controlled global phase is physical. We use +// the Rz gate to implement controlled global phase physically, and then correct for the extra global phase it +// introduces in simulation using additional calls to the simulation-only global phase intrinsic. +// We use a separate operation for this controlled case to avoid recursive calls to the same operation +// that can interfere with runtime capabilities analysis. +internal operation ControllableGlobalPhase(theta : Double) : Unit is Ctl { + body ... { + GlobalPhase([], theta); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + GlobalPhase([], theta); + } else { + Controlled Rz(ctls[1...], (theta, ctls[0])); + GlobalPhase(ctls[1...], theta / 2.0); + // With a single control qubit, the call to Rz uses no controls and global phase is corrected + // by just the call above. + // Multi-controlled Rz gates use a decomposition that introduces an additional global + // phase, so we need to correct for that here. + if Length(ctls) > 1 { + GlobalPhase([], -theta / 4.0); + } + } + } +} + +// Global phase intrinsic, which only has affect in simulation and is a no-op otherwise. +internal operation GlobalPhase(ctls : Qubit[], theta : Double) : Unit { + body intrinsic; +} + +internal operation CRz(control : Qubit, theta : Double, target : Qubit) : Unit is Adj { + Rz(theta / 2.0, target); + CNOT(control, target); + Rz(-theta / 2.0, target); + CNOT(control, target); +} + +internal operation CS(control : Qubit, target : Qubit) : Unit is Adj + Ctl { + T(control); + T(target); + CNOT(control, target); + Adjoint T(target); + CNOT(control, target); +} + +internal operation CT(control : Qubit, target : Qubit) : Unit is Adj { + let angle = PI() / 8.0; + Rz(angle, control); + Rz(angle, target); + CNOT(control, target); + Adjoint Rz(angle, target); + CNOT(control, target); +} + +internal operation MapPauli(qubit : Qubit, from : Pauli, to : Pauli) : Unit is Adj { + if from == to {} elif (from == PauliZ and to == PauliX) or (from == PauliX and to == PauliZ) { + H(qubit); + } elif from == PauliZ and to == PauliY { + H(qubit); + S(qubit); + H(qubit); + } elif from == PauliY and to == PauliZ { + H(qubit); + Adjoint S(qubit); + H(qubit); + } elif from == PauliY and to == PauliX { + S(qubit); + } elif from == PauliX and to == PauliY { + Adjoint S(qubit); + } else { + fail "Unsupported input"; + } +} + +internal operation EntangleForJointMeasure(basis : Pauli, aux : Qubit, qubit : Qubit) : Unit { + if basis == PauliX { + __quantum__qis__cx__body(aux, qubit); + } elif basis == PauliZ { + __quantum__qis__cz__body(aux, qubit); + } elif basis == PauliY { + __quantum__qis__cy__body(aux, qubit); + } +} + + /// Collects the given list of control qubits into one or two of the given auxiliary qubits, using +/// all but the last qubits in the auxiliary list as scratch qubits. The auxiliary list must be +/// big enough to accommodate the data, so it is usually smaller than controls list by number of +/// qubits needed for the eventual controlled unitary application. The passed adjustment value is +/// used to ensure the right number of auxiliary qubits are processed. +/// +/// For example, if the controls list is 6 qubits, the auxiliary list must be 5 qubits, and the +/// state from the 6 control qubits will be collected into the last qubit of the auxiliary array. +internal operation CollectControls(ctls : Qubit[], aux : Qubit[], adjustment : Int) : Unit is Adj { + // First collect the controls into the first part of the auxiliary list. + for i in 0..2..(Length(ctls) - 2) { + AND(ctls[i], ctls[i + 1], aux[i / 2]); + } + // Then collect the auxiliary qubits in the first part of the list forward into the last + // qubit of the auxiliary list. The adjustment is used to allow the caller to reduce or increase + // the number of times this is run based on the eventual number of control qubits needed. + for i in 0..((Length(ctls) / 2) - 2 - adjustment) { + AND(aux[i * 2], aux[(i * 2) + 1], aux[i + Length(ctls) / 2]); + } +} + + /// When collecting controls, if there is an uneven number of original control qubits then the +/// last control and the second to last auxiliary will be collected into the last auxiliary. +internal operation AdjustForSingleControl(ctls : Qubit[], aux : Qubit[]) : Unit is Adj { + if Length(ctls) % 2 != 0 { + AND(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], aux[Length(ctls) - 2]); + } +} + +internal operation PhaseCCX(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + // https://arxiv.org/pdf/1210.0974.pdf#page=2 + H(target); + CNOT(target, control1); + CNOT(control1, control2); + T(control2); + Adjoint T(control1); + T(target); + CNOT(target, control1); + CNOT(control1, control2); + Adjoint T(control2); + CNOT(target, control2); + H(target); +} + +internal operation CCZ(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + within { + H(target); + } apply { + CCNOT(control1, control2, target); + } +} + +internal operation CCY(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + within { + MapPauli(target, PauliX, PauliY); + } apply { + CCNOT(control1, control2, target); + } +} + +internal operation CRxx(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { + within { + CNOT(qubit1, qubit0); + } apply { + Controlled Rx([control], (theta, qubit0)); + } +} + +internal operation CRyy(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { + within { + CNOT(qubit1, qubit0); + } apply { + Controlled Ry([control], (theta, qubit0)); + } +} + +internal operation CRzz(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { + within { + CNOT(qubit1, qubit0); + } apply { + Controlled Rz([control], (theta, qubit0)); + } +} + +internal function IndicesOfNonIdentity(paulies : Pauli[]) : Int[] { + mutable indices = []; + for i in 0..Length(paulies) - 1 { + if (paulies[i] != PauliI) { + set indices += [i]; + } + } + indices +} + +internal function RemovePauliI(paulis : Pauli[], qubits : Qubit[]) : (Pauli[], Qubit[]) { + let indices = IndicesOfNonIdentity(paulis); + let newPaulis = Subarray(indices, paulis); + let newQubits = Subarray(indices, qubits); + return (newPaulis, newQubits); +} + +internal operation SpreadZ(from : Qubit, to : Qubit[]) : Unit is Adj { + let targets = GetSpread(from, to); + for (ctl, tgt) in targets { + CNOT(ctl, tgt); + } +} + +internal function GetSpread(from : Qubit, to : Qubit[]) : (Qubit, Qubit)[] { + mutable queue = [(from, to)]; + mutable targets = []; + while Length(queue) > 0 { + mutable (next, rest) = (queue[0], queue[1...]); + set queue = rest; + let (next_from, next_to) = next; + if Length(next_to) > 0 { + set targets = [(next_to[0], next_from)] + targets; + if Length(next_to) > 1 { + let half = Length(next_to) / 2; + set queue = [(next_from, next_to[1..half]), (next_to[0], next_to[(half + 1)...])] + rest; + } + } + } + + targets +} diff --git a/library/std/src/Std/Intrinsic.qs b/library/std/src/Std/Intrinsic.qs new file mode 100644 index 0000000000..03f5524ff9 --- /dev/null +++ b/library/std/src/Std/Intrinsic.qs @@ -0,0 +1,1129 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +import Std.Convert.*; +import Std.Core.*; +import Std.Diagnostics.*; +import Std.Math.*; +open QIR.Intrinsic; +import Std.InternalHelpers.*; + +/// # Summary +/// Applies the AND gate that is more efficient for use with decomposition of multi-controlled operations. +/// Note that target qubit must be in |0⟩ state. +/// +/// # Input +/// ## control1 +/// First control qubit for the AND gate. +/// ## control2 +/// Second control qubit for the AND gate. +/// ## target +/// Target qubit for the AND gate. +/// +/// # Remarks +/// Use the Adjoint only for uncomputation purposes. +@Config(Adaptive) +operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + body ... { + __quantum__qis__ccx__body(control1, control2, target); + } + adjoint ... { + __quantum__qis__h__body(target); + if MResetZ(target) == One { + __quantum__qis__cz__body(control1, control2); + } + } +} + +/// Applies the AND gate that is more efficient for use with decomposition of multi-controlled operations. +/// Note that target qubit must be in |0⟩ state. +/// +/// # Input +/// ## control1 +/// First control qubit for the AND gate. +/// ## control2 +/// Second control qubit for the AND gate. +/// ## target +/// Target qubit for the AND gate. +/// +/// # Remarks +/// Use the Adjoint only for uncomputation purposes. +@Config(not Adaptive) +operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + PhaseCCX(control1, control2, target); +} + +/// Applies the doubly controlled–NOT (CCNOT) gate to three qubits. +/// +/// # Input +/// ## control1 +/// First control qubit for the CCNOT gate. +/// ## control2 +/// Second control qubit for the CCNOT gate. +/// ## target +/// Target qubit for the CCNOT gate. +/// +/// # Remarks +/// Equivalent to: +/// ```qsharp +/// Controlled X([control1, control2], target); +/// ``` +operation CCNOT(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__ccx__body(control1, control2, target); + } + controlled (ctls, ...) { + Controlled X(ctls + [control1, control2], target); + } + adjoint self; +} + +/// Applies the controlled-NOT (CNOT) gate to a pair of qubits. +/// +/// # Input +/// ## control +/// Control qubit for the CNOT gate. +/// ## target +/// Target qubit for the CNOT gate. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// \operatorname{CNOT} \mathrel{:=} +/// \begin{bmatrix} +/// 1 & 0 & 0 & 0 \\\\ +/// 0 & 1 & 0 & 0 \\\\ +/// 0 & 0 & 0 & 1 \\\\ +/// 0 & 0 & 1 & 0 +/// \end{bmatrix}, +/// \end{align} +/// $$ +/// +/// where rows and columns are ordered as in the quantum concepts guide. +/// +/// Equivalent to: +/// ```qsharp +/// Controlled X([control], target); +/// ``` +operation CNOT(control : Qubit, target : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__cx__body(control, target); + } + controlled (ctls, ...) { + Controlled X(ctls + [control], target); + } + adjoint self; +} + +/// Applies the exponential of a multi-qubit Pauli operator. +/// +/// # Input +/// ## paulis +/// Array of single-qubit Pauli values indicating the tensor product +/// factors on each qubit. +/// ## theta +/// Angle about the given multi-qubit Pauli operator by which the +/// target register is to be rotated. +/// ## qubits +/// Register to apply the given rotation to. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// e^{i \theta [P_0 \otimes P_1 \cdots P_{N-1}]}, +/// \end{align} +/// $$ +/// where $P_i$ is the $i$-th element of `paulis`, and where +/// $N = $`Length(paulis)`. +operation Exp(paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl { + body ... { + Fact(Length(paulis) == Length(qubits), "Arrays 'pauli' and 'qubits' must have the same length"); + let (newPaulis, newQubits) = RemovePauliI(paulis, qubits); + let angle = -2.0 * theta; + let len = Length(newPaulis); + + if len == 0 { + ApplyGlobalPhase(theta); + } elif len == 1 { + R(newPaulis[0], angle, qubits[0]); + } elif len == 2 { + within { + MapPauli(qubits[1], paulis[0], paulis[1]); + } apply { + if (paulis[0] == PauliX) { + Rxx(angle, qubits[0], qubits[1]); + } elif (paulis[0] == PauliY) { + Ryy(angle, qubits[0], qubits[1]); + } elif (paulis[0] == PauliZ) { + Rzz(angle, qubits[0], qubits[1]); + } + } + } else { + // len > 2 + within { + for i in 0..Length(paulis) - 1 { + MapPauli(qubits[i], PauliZ, paulis[i]); + } + } apply { + within { + SpreadZ(qubits[1], qubits[2..Length(qubits) - 1]); + } apply { + Rzz(angle, qubits[0], qubits[1]); + } + } + } + } + adjoint ... { + Exp(paulis, -theta, qubits); + } +} + +/// Applies the Hadamard transformation to a single qubit. +/// +/// # Input +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// H \mathrel{:=} +/// \frac{1}{\sqrt{2}} +/// \begin{bmatrix} +/// 1 & 1 \\\\ +/// 1 & -1 +/// \end{bmatrix} +/// \end{align} +/// $$ +operation H(qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__h__body(qubit); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__h__body(qubit); + } elif Length(ctls) == 1 { + CH(ctls[0], qubit); + } elif Length(ctls) == 2 { + CCH(ctls[0], ctls[1], qubit); + } else { + use aux = Qubit[Length(ctls) - 1 - (Length(ctls) % 2)]; + within { + CollectControls(ctls, aux, 0); + } apply { + if Length(ctls) % 2 != 0 { + CCH(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); + } else { + CCH(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); + } + } + } + } + adjoint self; +} + +/// Performs the identity operation (no-op) on a single qubit. +/// +/// # Remarks +/// This is a no-op. It is provided for completeness and because +/// sometimes it is useful to call the identity in an algorithm or to pass it as a parameter. +operation I(target : Qubit) : Unit is Adj + Ctl { + body ... {} + adjoint self; +} + +/// Performs a measurement of a single qubit in the +/// Pauli _Z_ basis. +/// +/// # Input +/// ## qubit +/// Qubit to be measured. +/// +/// # Output +/// `Zero` if the +1 eigenvalue is observed, and `One` if +/// the -1 eigenvalue is observed. +/// +/// # Remarks +/// The output result is given by +/// the distribution +/// $$ +/// \begin{align} +/// \Pr(\texttt{Zero} | \ket{\psi}) = +/// \braket{\psi | 0} \braket{0 | \psi}. +/// \end{align} +/// $$ +/// +/// Equivalent to: +/// ```qsharp +/// Measure([PauliZ], [qubit]); +/// ``` +@Config(QubitReset) +operation M(qubit : Qubit) : Result { + __quantum__qis__m__body(qubit) +} + +/// Performs a measurement of a single qubit in the +/// Pauli _Z_ basis. +/// +/// # Input +/// ## qubit +/// Qubit to be measured. +/// +/// # Output +/// `Zero` if the +1 eigenvalue is observed, and `One` if +/// the -1 eigenvalue is observed. +/// +/// # Remarks +/// The output result is given by +/// the distribution +/// $$ +/// \begin{align} +/// \Pr(\texttt{Zero} | \ket{\psi}) = +/// \braket{\psi | 0} \braket{0 | \psi}. +/// \end{align} +/// $$ +/// +/// Equivalent to: +/// ```qsharp +/// Measure([PauliZ], [qubit]); +/// ``` +@Config(not QubitReset) +operation M(qubit : Qubit) : Result { + Measure([PauliZ], [qubit]) +} + +/// Performs a joint measurement of one or more qubits in the +/// specified Pauli bases. +/// +/// If the basis array and qubit array are different lengths, then the +/// operation will fail. +/// +/// # Input +/// ## bases +/// Array of single-qubit Pauli values indicating the tensor product +/// factors on each qubit. +/// ## qubits +/// Register of qubits to be measured. +/// +/// # Output +/// `Zero` if the +1 eigenvalue is observed, and `One` if +/// the -1 eigenvalue is observed. +/// +/// # Remarks +/// The probability of getting `Zero` is +/// $\bra{\psi} \frac{I + P_0 \otimes \ldots \otimes P_{N-1}}{2} \ket{\psi}$ +/// where $P_i$ is the $i$-th element of `bases`, and where +/// $N$ is the `Length(bases)`. +/// That is, measurement returns a `Result` $d$ such that the eigenvalue of the +/// observed measurement effect is $(-1)^d$. +@Config(QubitReset) +operation Measure(bases : Pauli[], qubits : Qubit[]) : Result { + if Length(bases) != Length(qubits) { + fail "Arrays 'bases' and 'qubits' must be of the same length."; + } + if Length(bases) == 1 { + within { + MapPauli(qubits[0], PauliZ, bases[0]); + } apply { + __quantum__qis__m__body(qubits[0]) + } + } else { + use aux = Qubit(); + within { + H(aux); + } apply { + for i in 0..Length(bases) - 1 { + EntangleForJointMeasure(bases[i], aux, qubits[i]); + } + } + __quantum__qis__mresetz__body(aux) + } +} + +/// Performs a joint measurement of one or more qubits in the +/// specified Pauli bases. +/// +/// If the basis array and qubit array are different lengths, then the +/// operation will fail. +/// +/// # Input +/// ## bases +/// Array of single-qubit Pauli values indicating the tensor product +/// factors on each qubit. +/// ## qubits +/// Register of qubits to be measured. +/// +/// # Output +/// `Zero` if the +1 eigenvalue is observed, and `One` if +/// the -1 eigenvalue is observed. +/// +/// # Remarks +/// The probability of getting `Zero` is +/// $\bra{\psi} \frac{I + P_0 \otimes \ldots \otimes P_{N-1}}{2} \ket{\psi}$ +/// where $P_i$ is the $i$-th element of `bases`, and where +/// $N$ is the `Length(bases)`. +/// That is, measurement returns a `Result` $d$ such that the eigenvalue of the +/// observed measurement effect is $(-1)^d$. +@Config(not QubitReset) +operation Measure(bases : Pauli[], qubits : Qubit[]) : Result { + if Length(bases) != Length(qubits) { + fail "Arrays 'bases' and 'qubits' must be of the same length."; + } + // Because Base Profile does not allow qubit reuse, we always allocate a new qubit + // and use entanglement to measure the state while collapsing the original target(s) and + // leaving it available for later operations. + use aux = Qubit(); + within { + H(aux); + } apply { + for i in 0..Length(bases) - 1 { + EntangleForJointMeasure(bases[i], aux, qubits[i]); + } + } + __quantum__qis__mresetz__body(aux) +} + +/// Applies a rotation about the given Pauli axis. +/// +/// # Input +/// ## pauli +/// Pauli operator (μ) to be exponentiated to form the rotation. +/// ## theta +/// Angle in radians about which the qubit is to be rotated. +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_{\mu}(\theta) \mathrel{:=} +/// e^{-i \theta \sigma_{\mu} / 2}, +/// \end{align} +/// $$ +/// where $\mu \in \{I, X, Y, Z\}$. +/// +/// When called with `pauli = PauliI`, this operation applies +/// a *global phase*. This phase can be significant +/// when used with the `Controlled` functor. +operation R(pauli : Pauli, theta : Double, qubit : Qubit) : Unit is Adj + Ctl { + if (pauli == PauliX) { + Rx(theta, qubit); + } elif (pauli == PauliY) { + Ry(theta, qubit); + } elif (pauli == PauliZ) { + Rz(theta, qubit); + } else { + // PauliI + ApplyGlobalPhase(-theta / 2.0); + } +} + +/// Applies a rotation about the |1⟩ state by a given angle. +/// +/// # Input +/// ## theta +/// Angle about which the qubit is to be rotated. +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_1(\theta) \mathrel{:=} +/// \operatorname{diag}(1, e^{i\theta}). +/// \end{align} +/// $$ +/// +/// Equivalent to: +/// ```qsharp +/// R(PauliZ, theta, qubit); +/// R(PauliI, -theta, qubit); +/// ``` +operation R1(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { + Rz(theta, qubit); + R(PauliI, -theta, qubit); +} + +/// Applies a rotation about the |1⟩ state by an angle specified +/// as a dyadic fraction. +/// +/// WARNING: +/// This operation uses the **opposite** sign convention from +/// Microsoft.Quantum.Intrinsic.R. +/// +/// # Input +/// ## numerator +/// Numerator in the dyadic fraction representation of the angle +/// by which the qubit is to be rotated. This angle is expressed in radians. +/// ## power +/// Power of two specifying the denominator of the angle by which +/// the qubit is to be rotated. This angle is expressed in radians. +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_1(n, k) \mathrel{:=} +/// \operatorname{diag}(1, e^{i \pi n / 2^k}). +/// \end{align} +/// $$ +/// +/// Equivalent to: +/// ```qsharp +/// RFrac(PauliZ, -numerator, denominator + 1, qubit); +/// RFrac(PauliI, numerator, denominator + 1, qubit); +/// ``` +operation R1Frac(numerator : Int, power : Int, qubit : Qubit) : Unit is Adj + Ctl { + RFrac(PauliZ, -numerator, power + 1, qubit); + RFrac(PauliI, numerator, power + 1, qubit); +} + +/// Given a single qubit, measures it and ensures it is in the |0⟩ state +/// such that it can be safely released. +/// +/// # Input +/// ## qubit +/// The qubit whose state is to be reset to |0⟩. +operation Reset(qubit : Qubit) : Unit { + __quantum__qis__reset__body(qubit); +} + +/// Given an array of qubits, measure them and ensure they are in the |0⟩ state +/// such that they can be safely released. +/// +/// # Input +/// ## qubits +/// An array of qubits whose states are to be reset to |0⟩. +operation ResetAll(qubits : Qubit[]) : Unit { + for q in qubits { + Reset(q); + } +} + +/// Applies a rotation about the given Pauli axis by an angle specified +/// as a dyadic fraction. +/// +/// WARNING: +/// This operation uses the **opposite** sign convention from +/// Microsoft.Quantum.Intrinsic.R. +/// +/// # Input +/// ## pauli +/// Pauli operator to be exponentiated to form the rotation. +/// ## numerator +/// Numerator in the dyadic fraction representation of the angle +/// by which the qubit is to be rotated. This angle is expressed in radians. +/// ## power +/// Power of two specifying the denominator of the angle by which +/// the qubit is to be rotated. This angle is expressed in radians. +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_{\mu}(n, k) \mathrel{:=} +/// e^{i \pi n \sigma_{\mu} / 2^k}, +/// \end{align} +/// $$ +/// where $\mu \in \{I, X, Y, Z\}$. +/// +/// Equivalent to: +/// ```qsharp +/// // PI() is a Q# function that returns an approximation of π. +/// R(pauli, -2.0 * PI() * IntAsDouble(numerator) / IntAsDouble(2 ^ (power - 1)), qubit); +/// ``` +operation RFrac(pauli : Pauli, numerator : Int, power : Int, qubit : Qubit) : Unit is Adj + Ctl { + // Note that power must be converted to a double and used with 2.0 instead of 2 to allow for + // negative exponents that result in a fractional denominator. + let angle = ((-2.0 * PI()) * IntAsDouble(numerator)) / (2.0^IntAsDouble(power)); + R(pauli, angle, qubit); +} + +/// Applies a rotation about the _x_-axis by a given angle. +/// +/// # Input +/// ## theta +/// Angle about which the qubit is to be rotated. +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_x(\theta) \mathrel{:=} +/// e^{-i \theta \sigma_x / 2} = +/// \begin{bmatrix} +/// \cos \frac{\theta}{2} & -i\sin \frac{\theta}{2} \\\\ +/// -i\sin \frac{\theta}{2} & \cos \frac{\theta}{2} +/// \end{bmatrix}. +/// \end{align} +/// $$ +/// +/// Equivalent to: +/// ```qsharp +/// R(PauliX, theta, qubit); +/// ``` +operation Rx(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__rx__body(theta, qubit); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__rx__body(theta, qubit); + } else { + within { + MapPauli(qubit, PauliZ, PauliX); + } apply { + Controlled Rz(ctls, (theta, qubit)); + } + } + } + adjoint ... { + Rx(-theta, qubit); + } +} + +/// Applies the two qubit Ising _XX_ rotation gate. +/// +/// # Input +/// ## theta +/// The angle about which the qubits are rotated. +/// ## qubit0 +/// The first qubit input to the gate. +/// ## qubit1 +/// The second qubit input to the gate. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_{xx}(\theta) \mathrel{:=} +/// \begin{bmatrix} +/// \cos \theta & 0 & 0 & -i\sin \theta \\\\ +/// 0 & \cos \theta & -i\sin \theta & 0 \\\\ +/// 0 & -i\sin \theta & \cos \theta & 0 \\\\ +/// -i\sin \theta & 0 & 0 & \cos \theta +/// \end{bmatrix}. +/// \end{align} +/// $$ +operation Rxx(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__rxx__body(theta, qubit0, qubit1); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__rxx__body(theta, qubit0, qubit1); + } elif Length(ctls) == 1 { + CRxx(ctls[0], theta, qubit0, qubit1); + } else { + use aux = Qubit[Length(ctls) - 1]; + within { + CollectControls(ctls, aux, 0); + AdjustForSingleControl(ctls, aux); + } apply { + CRxx(aux[Length(ctls) - 2], theta, qubit0, qubit1); + } + } + } + adjoint ... { + Rxx(-theta, qubit0, qubit1); + } +} + +/// Applies a rotation about the _y_-axis by a given angle. +/// +/// # Input +/// ## theta +/// Angle about which the qubit is to be rotated. +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_y(\theta) \mathrel{:=} +/// e^{-i \theta \sigma_y / 2} = +/// \begin{bmatrix} +/// \cos \frac{\theta}{2} & -\sin \frac{\theta}{2} \\\\ +/// \sin \frac{\theta}{2} & \cos \frac{\theta}{2} +/// \end{bmatrix}. +/// \end{align} +/// $$ +/// +/// Equivalent to: +/// ```qsharp +/// R(PauliY, theta, qubit); +/// ``` +operation Ry(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__ry__body(theta, qubit); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__ry__body(theta, qubit); + } else { + within { + MapPauli(qubit, PauliZ, PauliY); + } apply { + Controlled Rz(ctls, (theta, qubit)); + } + } + } + adjoint ... { + Ry(-theta, qubit); + } +} + +/// Applies the two qubit Ising _YY_ rotation gate. +/// +/// # Input +/// ## theta +/// The angle about which the qubits are rotated. +/// ## qubit0 +/// The first qubit input to the gate. +/// ## qubit1 +/// The second qubit input to the gate. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_{yy}(\theta) \mathrel{:=} +/// \begin{bmatrix} +/// \cos \theta & 0 & 0 & i\sin \theta \\\\ +/// 0 & \cos \theta & -i\sin \theta & 0 \\\\ +/// 0 & -i\sin \theta & \cos \theta & 0 \\\\ +/// i\sin \theta & 0 & 0 & \cos \theta +/// \end{bmatrix}. +/// \end{align} +/// $$ +operation Ryy(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__ryy__body(theta, qubit0, qubit1); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__ryy__body(theta, qubit0, qubit1); + } elif Length(ctls) == 1 { + CRyy(ctls[0], theta, qubit0, qubit1); + } else { + use aux = Qubit[Length(ctls) - 1]; + within { + CollectControls(ctls, aux, 0); + AdjustForSingleControl(ctls, aux); + } apply { + CRyy(aux[Length(ctls) - 2], theta, qubit0, qubit1); + } + } + } + adjoint ... { + Ryy(-theta, qubit0, qubit1); + } +} + +/// Applies a rotation about the _z_-axis by a given angle. +/// +/// # Input +/// ## theta +/// Angle about which the qubit is to be rotated. +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_z(\theta) \mathrel{:=} +/// e^{-i \theta \sigma_z / 2} = +/// \begin{bmatrix} +/// e^{-i \theta / 2} & 0 \\\\ +/// 0 & e^{i \theta / 2} +/// \end{bmatrix}. +/// \end{align} +/// $$ +/// +/// Equivalent to: +/// ```qsharp +/// R(PauliZ, theta, qubit); +/// ``` +operation Rz(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__rz__body(theta, qubit); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__rz__body(theta, qubit); + } elif Length(ctls) == 1 { + CRz(ctls[0], theta, qubit); + } else { + use aux = Qubit[Length(ctls) - 1]; + within { + CollectControls(ctls, aux, 0); + AdjustForSingleControl(ctls, aux); + } apply { + CRz(aux[Length(ctls) - 2], theta, qubit); + } + } + } + adjoint ... { + Rz(-theta, qubit); + } +} + +/// Applies the two qubit Ising _ZZ_ rotation gate. +/// +/// # Input +/// ## theta +/// The angle about which the qubits are rotated. +/// ## qubit0 +/// The first qubit input to the gate. +/// ## qubit1 +/// The second qubit input to the gate. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// R_{zz}(\theta) \mathrel{:=} +/// \begin{bmatrix} +/// e^{-i \theta / 2} & 0 & 0 & 0 \\\\ +/// 0 & e^{i \theta / 2} & 0 & 0 \\\\ +/// 0 & 0 & e^{i \theta / 2} & 0 \\\\ +/// 0 & 0 & 0 & e^{-i \theta / 2} +/// \end{bmatrix}. +/// \end{align} +/// $$ +operation Rzz(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__rzz__body(theta, qubit0, qubit1); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__rzz__body(theta, qubit0, qubit1); + } elif Length(ctls) == 1 { + CRzz(ctls[0], theta, qubit0, qubit1); + } else { + use aux = Qubit[Length(ctls) - 1]; + within { + CollectControls(ctls, aux, 0); + AdjustForSingleControl(ctls, aux); + } apply { + CRzz(aux[Length(ctls) - 2], theta, qubit0, qubit1); + } + } + } + adjoint ... { + Rzz(-theta, qubit0, qubit1); + } +} + +/// Applies the π/4 phase gate to a single qubit. +/// +/// # Input +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// S \mathrel{:=} +/// \begin{bmatrix} +/// 1 & 0 \\\\ +/// 0 & i +/// \end{bmatrix}. +/// \end{align} +/// $$ +operation S(qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__s__body(qubit); + } + adjoint ... { + __quantum__qis__s__adj(qubit); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__s__body(qubit); + } elif Length(ctls) == 1 { + CS(ctls[0], qubit); + } elif Length(ctls) == 2 { + Controlled CS([ctls[0]], (ctls[1], qubit)); + } else { + use aux = Qubit[Length(ctls) - 2]; + within { + CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); + } apply { + if Length(ctls) % 2 != 0 { + Controlled CS([ctls[Length(ctls) - 1]], (aux[Length(ctls) - 3], qubit)); + } else { + Controlled CS([aux[Length(ctls) - 3]], (aux[Length(ctls) - 4], qubit)); + } + } + } + } + controlled adjoint (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__s__adj(qubit); + } elif Length(ctls) == 1 { + Adjoint CS(ctls[0], qubit); + } elif Length(ctls) == 2 { + Controlled Adjoint CS([ctls[0]], (ctls[1], qubit)); + } else { + use aux = Qubit[Length(ctls) - 2]; + within { + CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); + } apply { + if Length(ctls) % 2 != 0 { + Controlled Adjoint CS([ctls[Length(ctls) - 1]], (aux[Length(ctls) - 3], qubit)); + } else { + Controlled Adjoint CS([aux[Length(ctls) - 3]], (aux[Length(ctls) - 4], qubit)); + } + } + } + } +} + +/// Applies the SWAP gate to a pair of qubits. +/// +/// # Input +/// ## qubit1 +/// First qubit to be swapped. +/// ## qubit2 +/// Second qubit to be swapped. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// \operatorname{SWAP} \mathrel{:=} +/// \begin{bmatrix} +/// 1 & 0 & 0 & 0 \\\\ +/// 0 & 0 & 1 & 0 \\\\ +/// 0 & 1 & 0 & 0 \\\\ +/// 0 & 0 & 0 & 1 +/// \end{bmatrix}, +/// \end{align} +/// $$ +/// +/// where rows and columns are ordered as in the quantum concepts guide. +/// +/// Equivalent to: +/// ```qsharp +/// CNOT(qubit1, qubit2); +/// CNOT(qubit2, qubit1); +/// CNOT(qubit1, qubit2); +/// ``` +operation SWAP(qubit1 : Qubit, qubit2 : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__swap__body(qubit1, qubit2); + } + adjoint self; + controlled (ctls, ...) { + if (Length(ctls) == 0) { + __quantum__qis__swap__body(qubit1, qubit2); + } else { + within { + CNOT(qubit1, qubit2); + } apply { + Controlled CNOT(ctls, (qubit2, qubit1)); + } + } + } +} + +/// Applies the π/8 gate to a single qubit. +/// +/// # Input +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// T \mathrel{:=} +/// \begin{bmatrix} +/// 1 & 0 \\\\ +/// 0 & e^{i \pi / 4} +/// \end{bmatrix}. +/// \end{align} +/// $$ +operation T(qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__t__body(qubit); + } + adjoint ... { + __quantum__qis__t__adj(qubit); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__t__body(qubit); + } elif Length(ctls) == 1 { + CT(ctls[0], qubit); + } else { + use aux = Qubit[Length(ctls) - 1]; + within { + CollectControls(ctls, aux, 0); + AdjustForSingleControl(ctls, aux); + } apply { + CT(aux[Length(ctls) - 2], qubit); + } + } + } + controlled adjoint (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__t__adj(qubit); + } elif Length(ctls) == 1 { + Adjoint CT(ctls[0], qubit); + } else { + use aux = Qubit[Length(ctls) - 1]; + within { + CollectControls(ctls, aux, 0); + AdjustForSingleControl(ctls, aux); + } apply { + Adjoint CT(aux[Length(ctls) - 2], qubit); + } + } + } +} + +/// Applies the Pauli _X_ gate. +/// +/// # Input +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// \sigma_x \mathrel{:=} +/// \begin{bmatrix} +/// 0 & 1 \\\\ +/// 1 & 0 +/// \end{bmatrix}. +/// \end{align} +/// $$ +operation X(qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__x__body(qubit); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__x__body(qubit); + } elif Length(ctls) == 1 { + __quantum__qis__cx__body(ctls[0], qubit); + } elif Length(ctls) == 2 { + __quantum__qis__ccx__body(ctls[0], ctls[1], qubit); + } else { + use aux = Qubit[Length(ctls) - 2]; + within { + CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); + } apply { + if Length(ctls) % 2 != 0 { + __quantum__qis__ccx__body(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); + } else { + __quantum__qis__ccx__body(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); + } + } + } + } + adjoint self; +} + +/// Applies the Pauli _Y_ gate. +/// +/// # Input +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// \sigma_y \mathrel{:=} +/// \begin{bmatrix} +/// 0 & -i \\\\ +/// i & 0 +/// \end{bmatrix}. +/// \end{align} +/// $$ +operation Y(qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__y__body(qubit); + } + controlled (ctls, ...) { + if (Length(ctls) == 0) { + __quantum__qis__y__body(qubit); + } elif (Length(ctls) == 1) { + __quantum__qis__cy__body(ctls[0], qubit); + } elif (Length(ctls) == 2) { + CCY(ctls[0], ctls[1], qubit); + } else { + use aux = Qubit[Length(ctls) - 2]; + within { + CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); + } apply { + if Length(ctls) % 2 != 0 { + CCY(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); + } else { + CCY(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); + } + } + } + } + adjoint self; +} + +/// Applies the Pauli _Z_ gate. +/// +/// # Input +/// ## qubit +/// Qubit to which the gate should be applied. +/// +/// # Remarks +/// $$ +/// \begin{align} +/// \sigma_z \mathrel{:=} +/// \begin{bmatrix} +/// 1 & 0 \\\\ +/// 0 & -1 +/// \end{bmatrix}. +/// \end{align} +/// $$ +operation Z(qubit : Qubit) : Unit is Adj + Ctl { + body ... { + __quantum__qis__z__body(qubit); + } + controlled (ctls, ...) { + if Length(ctls) == 0 { + __quantum__qis__z__body(qubit); + } elif Length(ctls) == 1 { + __quantum__qis__cz__body(ctls[0], qubit); + } elif Length(ctls) == 2 { + CCZ(ctls[0], ctls[1], qubit); + } else { + use aux = Qubit[Length(ctls) - 2]; + within { + CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); + } apply { + if Length(ctls) % 2 != 0 { + CCZ(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); + } else { + CCZ(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); + } + } + } + } + adjoint self; +} + +/// Logs a message. +/// +/// # Input +/// ## msg +/// The message to be reported. +/// +/// # Remarks +/// The specific behavior of this function is simulator-dependent, +/// but in most cases the given message will be written to the console. +/// ``` +function Message(msg : String) : Unit { + body intrinsic; +} + +export AND, CCNOT, CNOT, Exp, H, I, M, Measure, R, R1, R1Frac, Reset, ResetAll, RFrac, Rx, Rxx, Ry, Ryy, Rz, Rzz, S, SWAP, T, X, Y, Z, Message; diff --git a/library/std/src/Std/Logical.qs b/library/std/src/Std/Logical.qs new file mode 100644 index 0000000000..97050651cb --- /dev/null +++ b/library/std/src/Std/Logical.qs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +/// # Summary +/// Returns the boolean exclusive disjunction (eXclusive OR, XOR) +/// of two input boolean values. +/// +/// # Input +/// ## first +/// The first boolean value to be considered. +/// +/// ## second +/// The second boolean value to be considered. +/// +/// # Output +/// A `Bool` which is `true` if and only if exactly one of `first` and `second` is `true`. +/// +/// # Remarks +/// In Q#, `Xor(a, b)` is equivalent to `a != b`. +/// +/// # Example +/// ```qsharp +/// let result = Xor(true, false); +/// // result is true +/// ``` +function Xor(first : Bool, second : Bool) : Bool { + first != second +} +export Xor; + diff --git a/library/std/src/Std/Math.qs b/library/std/src/Std/Math.qs new file mode 100644 index 0000000000..9022c04e6b --- /dev/null +++ b/library/std/src/Std/Math.qs @@ -0,0 +1,1466 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +import Std.Convert.*; +import Std.Diagnostics.*; + +// +// Constants PI, E, LogOf2. +// + +/// # Summary +/// Returns a double-precision approximation of the +/// matematical constant 𝝅 ≈ 3.14159265358979323846 +/// +/// # Remarks +/// Mathematical constant 𝝅 represents the ratio of the circumference +/// of a circle to its diameter. It is useful in many applications +/// such as rotations and complex arithmetic. +/// +/// # References +/// [Wikipedia article - Pi](https://en.wikipedia.org/wiki/Pi) +/// +/// # See Also +/// - Microsoft.Quantum.Math.E +function PI() : Double { + 3.14159265358979323846 +} + +/// Returns a double-precision approximation of the +/// mathematical constant 𝒆 ≈ 2.7182818284590452354 +/// +/// # Remarks +/// Mathematical constant 𝒆 is the base of the natural logarithm +/// also known as the Euler's number +/// +/// # References +/// [Wikipedia article - e](https://en.wikipedia.org/wiki/E_(mathematical_constant)) +/// +/// # See Also +/// - Microsoft.Quantum.Math.PI +function E() : Double { + 2.7182818284590452354 +} + +/// Returns a double-precision approximation of the constant +/// ㏑2 ≈ 0.6931471805599453 +/// +/// # Remarks +/// ㏑2 is the natural logarithm of 2, or the logarithm of 2 base 𝒆. +/// +/// # References +/// [Wikipedia article - Natural logarithm](https://en.wikipedia.org/wiki/Natural_logarithm) +function LogOf2() : Double { + 0.6931471805599453 +} + +// +// Special numbers in IEEE floating-point representation +// + +/// # Summary +/// Returns whether a given floating-point value is not a number (i.e. is +/// NaN). +/// +/// # Input +/// ## d +/// A floating-point value to be checked. +/// +/// # Output +/// `true` if and only if `d` is not a number. +function IsNaN(d : Double) : Bool { + return d != d; +} + +/// Returns whether a given floating-point value is either positive or +/// negative infinity. +/// +/// # Input +/// ## d +/// The floating-point value to be checked. +/// +/// # Output +/// `true` if and only if `d` is either positive or negative infinity. +/// +/// # Remarks +/// `NaN` is not a number, and is thus neither a finite number nor +/// is it infinite. As such, `IsInfinite(0.0 / 0.0)` returns `false`. +/// To check if a value is `NaN`, use `IsNaN(d)`. +/// +/// Note that even though this function returns `true` for both +/// positive and negative infinities, these values can still be +/// discriminated by checking `d > 0.0` and `d < 0.0`. +/// +/// # Example +/// ```qsharp +/// Message($"{IsInfinite(42.0)}"); // false +/// Message($"{IsInfinite(0.0 / 0.0)}"); // false +/// Message($"{IsInfinite(-1.0 / 0.0}"); // true +/// ``` +/// +/// # See Also +/// - Microsoft.Quantum.Math.IsNaN +function IsInfinite(d : Double) : Bool { + return d == 1.0 / 0.0 or d == -1.0 / 0.0; +} + +// +// Sign, Abs, Min, Max, etc. +// + +/// # Summary +/// Returns -1, 0 or +1 that indicates the sign of a number. +function SignI(a : Int) : Int { + if (a < 0) { + -1 + } elif (a > 0) { + + 1 + } else { + 0 + } +} + +/// Returns -1, 0 or +1 that indicates the sign of a number. +function SignD(a : Double) : Int { + if (a < 0.0) { + -1 + } elif (a > 0.0) { + + 1 + } else { + 0 + } +} + +/// Returns -1, 0 or +1 that indicates the sign of a number. +function SignL(a : BigInt) : Int { + if (a < 0L) { + -1 + } elif (a > 0L) { + + 1 + } else { + 0 + } +} + +/// Returns the absolute value of an integer. +function AbsI(a : Int) : Int { + a < 0 ? -a | a +} + +/// Returns the absolute value of a double-precision floating-point number. +function AbsD(a : Double) : Double { + a < 0.0 ? -a | a +} + +function AbsL(a : BigInt) : BigInt { + a < 0L ? -a | a +} + +/// Returns the larger of two specified numbers. +function MaxI(a : Int, b : Int) : Int { + a > b ? a | b +} + +/// Returns the larger of two specified numbers. +function MaxD(a : Double, b : Double) : Double { + a > b ? a | b +} + +/// Returns the larger of two specified numbers. +function MaxL(a : BigInt, b : BigInt) : BigInt { + a > b ? a | b +} + +/// Returns the smaller of two specified numbers. +function MinI(a : Int, b : Int) : Int { + a < b ? a | b +} + +/// Returns the smaller of two specified numbers. +function MinD(a : Double, b : Double) : Double { + a < b ? a | b +} + +/// Returns the smaller of two specified numbers. +function MinL(a : BigInt, b : BigInt) : BigInt { + a < b ? a | b +} + +/// Given an array of integers, returns the largest element. +/// +/// # Input +/// ## values +/// An array to take the maximum of. +/// +/// # Output +/// The largest element of `values`. +function Max(values : Int[]) : Int { + Fact(Length(values) > 0, "Array must contain at least one element."); + mutable max = values[0]; + for element in values[1...] { + if element > max { + set max = element; + } + } + + max +} + +/// Given an array of integers, returns the smallest element. +/// +/// # Input +/// ## values +/// An array to take the minimum of. +/// +/// # Output +/// The smallest element of `values`. +function Min(values : Int[]) : Int { + Fact(Length(values) > 0, "Array must contain at least one element."); + mutable min = values[0]; + for element in values[1...] { + if element < min { + set min = element; + } + } + + min +} + +// +// Trigonometric functions +// + +/// # Summary +/// Returns the angle whose cosine is the specified number. +function ArcCos(x : Double) : Double { + body intrinsic; +} + +/// Returns the angle whose sine is the specified number. +function ArcSin(y : Double) : Double { + body intrinsic; +} + +/// Returns the angle whose tangent is the specified number. +function ArcTan(d : Double) : Double { + body intrinsic; +} + +/// Returns the angle whose tangent is the quotient of two specified numbers. +function ArcTan2(y : Double, x : Double) : Double { + body intrinsic; +} + +/// Returns the cosine of the specified angle. +function Cos(theta : Double) : Double { + body intrinsic; +} + +/// Returns the hyperbolic cosine of the specified angle. +function Cosh(d : Double) : Double { + body intrinsic; +} + +/// Returns the sine of the specified angle. +function Sin(theta : Double) : Double { + body intrinsic; +} + +/// Returns the hyperbolic sine of the specified angle. +function Sinh(d : Double) : Double { + body intrinsic; +} + +/// Returns the tangent of the specified angle. +function Tan(d : Double) : Double { + body intrinsic; +} + +/// Returns the hyperbolic tangent of the specified angle. +function Tanh(d : Double) : Double { + body intrinsic; +} + +/// Computes the inverse hyperbolic cosine of a number. +function ArcCosh(x : Double) : Double { + Log(x + Sqrt(x * x - 1.0)) +} + +/// Computes the inverse hyperbolic sine of a number. +function ArcSinh(x : Double) : Double { + Log(x + Sqrt(x * x + 1.0)) +} + + +/// Computes the inverse hyperbolic tangent of a number. +function ArcTanh(x : Double) : Double { + Log((1.0 + x) / (1.0 - x)) * 0.5 +} + +// +// Sqrt, Log, exp, etc. +// + +/// # Summary +/// Returns the square root of a specified number. +function Sqrt(d : Double) : Double { + body intrinsic; +} + +/// Returns the natural (base _e_) logarithm of a specified number. +function Log(input : Double) : Double { + body intrinsic; +} + +/// Returns the base-10 logarithm of a specified number. +function Log10(input : Double) : Double { + Log(input) / Log(10.0) +} + +/// Computes the base-2 logarithm of a number. +function Lg(input : Double) : Double { + Log(input) / Log(2.0) +} + +// +// Truncation and Rounding +// + +/// # Summary +/// Returns the integral part of a number. +/// For example: Truncate(3.7) = 3; Truncate(-3.7) = -3 +function Truncate(value : Double) : Int { + body intrinsic; +} + +internal function ExtendedTruncation(value : Double) : (Int, Double, Bool) { + let truncated = Truncate(value); + (truncated, IntAsDouble(truncated) - value, value >= 0.0) +} + +/// Returns the smallest integer greater than or equal to the specified number. +/// For example: Ceiling(3.1) = 4; Ceiling(-3.7) = -3 +function Ceiling(value : Double) : Int { + let (truncated, remainder, isPositive) = ExtendedTruncation(value); + if AbsD(remainder) <= 1e-15 { + truncated + } else { + isPositive ? truncated + 1 | truncated + } +} + +/// Returns the largest integer less than or equal to the specified number. +/// For example: Floor(3.7) = 3; Floor(-3.1) = -4 +function Floor(value : Double) : Int { + let (truncated, remainder, isPositive) = ExtendedTruncation(value); + if AbsD(remainder) <= 1e-15 { + truncated + } else { + isPositive ? truncated | truncated - 1 + } +} + +/// Returns the nearest integer to the specified number. +/// For example: Round(3.7) = 4; Round(-3.7) = -4 +function Round(value : Double) : Int { + let (truncated, remainder, isPositive) = ExtendedTruncation(value); + if AbsD(remainder) <= 1e-15 { + truncated + } else { + let abs = AbsD(remainder); + truncated + (abs <= 0.5 ? 0 | (isPositive ? 1 | -1)) + } +} + +// +// Modular arithmetic +// + +/// # Summary +/// Divides one Integer value by another, returns the result and the remainder as a tuple. +function DivRemI(dividend : Int, divisor : Int) : (Int, Int) { + (dividend / divisor, dividend % divisor) +} + +/// Divides one BigInteger value by another, returns the result and the remainder as a tuple. +function DivRemL(dividend : BigInt, divisor : BigInt) : (BigInt, BigInt) { + (dividend / divisor, dividend % divisor) +} + +/// Computes the canonical residue of `value` modulo `modulus`. +/// The result is always in the range 0..modulus-1 even for negative numbers. +function ModulusI(value : Int, modulus : Int) : Int { + Fact(modulus > 0, "`modulus` must be positive"); + let r = value % modulus; + (r < 0) ? (r + modulus) | r +} + +/// Computes the canonical residue of `value` modulo `modulus`. +/// The result is always in the range 0..modulus-1 even for negative numbers. +function ModulusL(value : BigInt, modulus : BigInt) : BigInt { + Fact(modulus > 0L, "`modulus` must be positive"); + let r = value % modulus; + (r < 0L) ? (r + modulus) | r +} + +/// Returns an integer raised to a given power, with respect to a given +/// modulus. I.e. (expBase^power) % modulus. +function ExpModI(expBase : Int, power : Int, modulus : Int) : Int { + Fact(power >= 0, "`power` must be non-negative"); + Fact(modulus > 0, "`modulus` must be positive"); + Fact(expBase > 0, "`expBase` must be positive"); + + // shortcut when modulus is 1 + if modulus == 1 { + return 0; + } + + mutable res = 1; + mutable expPow2mod = expBase % modulus; + mutable powerBits = power; + + while powerBits > 0 { + if (powerBits &&& 1) != 0 { + // if bit pₖ is 1, multiply res by expBase^(2^k) (mod `modulus`) + set res = (res * expPow2mod) % modulus; + } + + // update value of expBase^(2^k) (mod `modulus`) + set expPow2mod = (expPow2mod * expPow2mod) % modulus; + set powerBits >>>= 1; + } + + res +} + +/// Returns an integer raised to a given power, with respect to a given +/// modulus. I.e. (expBase^power) % modulus. +function ExpModL(expBase : BigInt, power : BigInt, modulus : BigInt) : BigInt { + Fact(power >= 0L, "`power` must be non-negative"); + Fact(modulus > 0L, "`modulus` must be positive"); + Fact(expBase > 0L, "`expBase` must be positive"); + + // shortcut when modulus is 1 + if modulus == 1L { + return 0L; + } + + mutable res = 1L; + mutable expPow2mod = expBase % modulus; + mutable powerBits = power; + + while powerBits > 0L { + if (powerBits &&& 1L) != 0L { + // if bit pₖ is 1, multiply res by expBase^(2ᵏ) (mod `modulus`) + set res = (res * expPow2mod) % modulus; + } + + // update value of expBase^(2ᵏ) (mod `modulus`) + set expPow2mod = (expPow2mod * expPow2mod) % modulus; + set powerBits >>>= 1; + } + + res +} + +/// Returns the multiplicative inverse of a modular integer. +/// +/// # Description +/// This will calculate the multiplicative inverse of a +/// modular integer `b` such that `a • b = 1 (mod modulus)`. +function InverseModI(a : Int, modulus : Int) : Int { + let (u, v) = ExtendedGreatestCommonDivisorI(a, modulus); + let gcd = u * a + v * modulus; + Fact(gcd == 1, "`a` and `modulus` must be co-prime"); + ModulusI(u, modulus) +} + +/// Returns the multiplicative inverse of a modular integer. +/// +/// # Description +/// This will calculate the multiplicative inverse of a +/// modular integer `b` such that `a • b = 1 (mod modulus)`. +function InverseModL(a : BigInt, modulus : BigInt) : BigInt { + let (u, v) = ExtendedGreatestCommonDivisorL(a, modulus); + let gcd = u * a + v * modulus; + Fact(gcd == 1L, "`a` and `modulus` must be co-prime"); + ModulusL(u, modulus) +} + +// +// GCD, etc. +// + +/// # Summary +/// Computes the greatest common divisor of two integers. +/// Note: GCD is always positive except that GCD(0,0)=0. +function GreatestCommonDivisorI(a : Int, b : Int) : Int { + mutable aa = AbsI(a); + mutable bb = AbsI(b); + while bb != 0 { + let cc = aa % bb; + set aa = bb; + set bb = cc; + } + aa +} + +/// Computes the greatest common divisor of two integers. +/// Note: GCD is always positive except that GCD(0,0)=0. +function GreatestCommonDivisorL(a : BigInt, b : BigInt) : BigInt { + mutable aa = AbsL(a); + mutable bb = AbsL(b); + while bb != 0L { + let cc = aa % bb; + set aa = bb; + set bb = cc; + } + aa +} + +/// Returns a tuple (u,v) such that u*a+v*b=GCD(a,b) +/// Note: GCD is always positive except that GCD(0,0)=0. +function ExtendedGreatestCommonDivisorI(a : Int, b : Int) : (Int, Int) { + let signA = SignI(a); + let signB = SignI(b); + mutable (s1, s2) = (1, 0); + mutable (t1, t2) = (0, 1); + mutable (r1, r2) = (a * signA, b * signB); + + while r2 != 0 { + let quotient = r1 / r2; + set (r1, r2) = (r2, r1 - quotient * r2); + set (s1, s2) = (s2, s1 - quotient * s2); + set (t1, t2) = (t2, t1 - quotient * t2); + } + + (s1 * signA, t1 * signB) +} + +/// Returns a tuple (u,v) such that u*a+v*b=GCD(a,b) +/// Note: GCD is always positive except that GCD(0,0)=0. +function ExtendedGreatestCommonDivisorL(a : BigInt, b : BigInt) : (BigInt, BigInt) { + let signA = IntAsBigInt(SignL(a)); + let signB = IntAsBigInt(SignL(b)); + mutable (s1, s2) = (1L, 0L); + mutable (t1, t2) = (0L, 1L); + mutable (r1, r2) = (a * signA, b * signB); + + while r2 != 0L { + let quotient = r1 / r2; + set (r1, r2) = (r2, r1 - quotient * r2); + set (s1, s2) = (s2, s1 - quotient * s2); + set (t1, t2) = (t2, t1 - quotient * t2); + } + + (s1 * signA, t1 * signB) +} + +/// Returns if two integers are co-prime. +/// +/// # Description +/// Returns true if a and b are co-prime and false otherwise. +/// +/// # Input +/// ## a +/// the first number of which co-primality is being tested +/// ## b +/// the second number of which co-primality is being tested +/// +/// # Output +/// True, if a and b are co-prime (e.g. their greatest common divisor is 1), +/// and false otherwise +function IsCoprimeI(a : Int, b : Int) : Bool { + GreatestCommonDivisorI(a, b) == 1 +} + +/// Returns if two integers are co-prime. +/// +/// # Description +/// Returns true if a and b are co-prime and false otherwise. +/// +/// # Input +/// ## a +/// the first number of which co-primality is being tested +/// ## b +/// the second number of which co-primality is being tested +/// +/// # Output +/// True, if a and b are co-prime (e.g. their greatest common divisor is 1), +/// and false otherwise +function IsCoprimeL(a : BigInt, b : BigInt) : Bool { + GreatestCommonDivisorL(a, b) == 1L +} + +/// Finds the continued fraction convergent closest to `fraction` +/// with the denominator less or equal to `denominatorBound` +/// Using process similar to this: https://nrich.maths.org/1397 +function ContinuedFractionConvergentI( + fraction : (Int, Int), + denominatorBound : Int +) : (Int, Int) { + Fact(denominatorBound > 0, "Denominator bound must be positive"); + + let (a, b) = fraction; + let signA = SignI(a); + let signB = SignI(b); + mutable (s1, s2) = (1, 0); + mutable (t1, t2) = (0, 1); + mutable (r1, r2) = (a * signA, b * signB); + + while r2 != 0 and AbsI(s2) <= denominatorBound { + let quotient = r1 / r2; + set (r1, r2) = (r2, r1 - quotient * r2); + set (s1, s2) = (s2, s1 - quotient * s2); + set (t1, t2) = (t2, t1 - quotient * t2); + } + + if r2 == 0 and AbsI(s2) <= denominatorBound { + (-t2 * signB, s2 * signA) + } else { + (-t1 * signB, s1 * signA) + } +} + +/// Finds the continued fraction convergent closest to `fraction` +/// with the denominator less or equal to `denominatorBound` +/// Using process similar to this: https://nrich.maths.org/1397 +function ContinuedFractionConvergentL( + fraction : (BigInt, BigInt), + denominatorBound : BigInt +) : (BigInt, BigInt) { + Fact(denominatorBound > 0L, "Denominator bound must be positive"); + + let (a, b) = fraction; + let signA = IntAsBigInt(SignL(a)); + let signB = IntAsBigInt(SignL(b)); + mutable (s1, s2) = (1L, 0L); + mutable (t1, t2) = (0L, 1L); + mutable (r1, r2) = (a * signA, b * signB); + + while r2 != 0L and AbsL(s2) <= denominatorBound { + let quotient = r1 / r2; + set (r1, r2) = (r2, r1 - quotient * r2); + set (s1, s2) = (s2, s1 - quotient * s2); + set (t1, t2) = (t2, t1 - quotient * t2); + } + + if r2 == 0L and AbsL(s2) <= denominatorBound { + (-t2 * signB, s2 * signA) + } else { + (-t1 * signB, s1 * signA) + } +} + +/// Computes the modulus between two real numbers. +/// +/// # Input +/// ## value +/// A real number x to take the modulus of. +/// ## modulo +/// A real number to take the modulus of x with respect to. +/// ## minValue +/// The smallest value to be returned by this function. +/// +/// # Example +/// ```qsharp +/// // Returns 3 π / 2. +/// let y = RealMod(5.5 * PI(), 2.0 * PI(), 0.0); +/// // Returns -1.2, since +3.6 and -1.2 are 4.8 apart on the real line, +/// // which is a multiple of 2.4. +/// let z = RealMod(3.6, 2.4, -1.2); +/// ``` +function RealMod(value : Double, modulo : Double, minValue : Double) : Double { + let timesModuloInSegment = (value - minValue) / modulo; + let fractionalPart = timesModuloInSegment - IntAsDouble(Truncate(timesModuloInSegment)); + modulo * fractionalPart + minValue +} + +// +// Binary, bits, etc. +// + +/// # Summary +/// For a non-negative integer `a`, returns the number of bits required to represent `a`. +/// NOTE: This function returns the smallest n such that a < 2^n. +function BitSizeI(a : Int) : Int { + Fact(a >= 0, "`a` must be non-negative."); + mutable number = a; + mutable size = 0; + while (number != 0) { + set size = size + 1; + set number = number >>> 1; + } + + size +} + +/// For a non-negative integer `a`, returns the number of bits required to represent `a`. +/// NOTE: This function returns the smallest n such that a < 2^n. +function BitSizeL(a : BigInt) : Int { + Fact(a >= 0L, "`a` must be non-negative."); + mutable number = a; + mutable size = 0; + while (number != 0L) { + set size = size + 1; + set number = number >>> 1; + } + + size +} + +/// For a non-zero integer `a`, returns the number of trailing zero bits +/// in the binary representation of `a`. +function TrailingZeroCountI(a : Int) : Int { + Fact(a != 0, "TrailingZeroCountI: `a` cannot be 0."); + + mutable count = 0; + mutable n = a; + while n &&& 1 == 0 { + set count += 1; + set n >>>= 1; + } + + count +} + +/// For a non-zero integer `a`, returns the number of trailing zero bits +/// in the binary representation of `a`. +function TrailingZeroCountL(a : BigInt) : Int { + Fact(a != 0L, "TrailingZeroCountL: `a` cannot be 0."); + + mutable count = 0; + mutable n = a; + while n &&& 1L == 0L { + set count += 1; + set n >>>= 1; + } + + count +} + +/// Returns the number of 1 bits in the binary representation of integer `n`. +function HammingWeightI(n : Int) : Int { + let i1 = n - ((n >>> 1) &&& 0x5555555555555555); + let i2 = (i1 &&& 0x3333333333333333) + ((i1 >>> 2) &&& 0x3333333333333333); + // Multiplication may overflow. See https://github.com/microsoft/qsharp/issues/828 + (((i2 + (i2 >>> 4)) &&& 0xF0F0F0F0F0F0F0F) * 0x101010101010101) >>> 56 +} + +// +// Combinatorics +// + +/// # Summary +/// Returns the factorial of a given number. +/// +/// # Description +/// Returns the factorial of a given nonnegative integer n, where 0 ≤ n ≤ 20. +/// +/// # Input +/// ## n +/// The number to take the factorial of. +/// +/// # Output +/// The factorial of `n`. +/// +/// # Remarks +/// For inputs greater than 20, please use `Microsoft.Quantum.Math.FactorialL`. +/// +/// # See Also +/// - Microsoft.Quantum.Math.FactorialL +/// - Microsoft.Quantum.Math.ApproximateFactorial +function FactorialI(n : Int) : Int { + Fact(n >= 0, "The factorial is not defined for negative inputs."); + Fact(n <= 20, "The largest factorial that can be stored as an Int is 20!. Use FactorialL or ApproximateFactorial."); + + [ + 1, + 1, + 2, + 6, + 24, + 120, + 720, + 5040, + 40320, + 362880, + 3628800, + 39916800, + 479001600, + 6227020800, + 87178291200, + 1307674368000, + 20922789888000, + 355687428096000, + 6402373705728000, + 121645100408832000, + 2432902008176640000 + ][n] +} + +/// Returns the factorial of a given number. +/// +/// # Input +/// ## n +/// The number to take the factorial of. +/// +/// # Output +/// The factorial of `n`. +/// +/// # See Also +/// - Microsoft.Quantum.Math.FactorialI +/// - Microsoft.Quantum.Math.ApproximateFactorial +function FactorialL(n : Int) : BigInt { + Fact(n >= 0, "The factorial is not defined for negative inputs."); + + mutable result = 1L; + for i in 1..n { + set result *= IntAsBigInt(i); + } + result +} + +/// Returns an approximate factorial of a given number. +/// +/// # Description +/// Returns the factorial as `Double`, given an input `n`. +/// The domain of inputs for this function is `n <= 169`. +/// +/// # Remarks +/// For n > 10, this function uses the Ramanujan approximation with a +/// relative error of the order of 1 / n⁵. +/// +/// # Input +/// ## n +/// The number to take the approximate factorial of. Must not be negative. +/// +/// # Output +/// The approximate factorial of `n`. +/// +/// # See Also +/// - Microsoft.Quantum.Math.FactorialI +/// - Microsoft.Quantum.Math.FactorialL +function ApproximateFactorial(n : Int) : Double { + Fact(n >= 0, "The factorial is not defined for negative inputs."); + Fact(n <= 169, "The largest approximate factorial that can be stored as a Double is 169!. Use FactorialL."); + + // For small enough n, use the exact factorial instead. + if n <= 20 { + return IntAsDouble(FactorialI(n)); + } + + let absN = IntAsDouble(n); + let a = Sqrt(2.0 * PI() * absN); + let b = (absN / E())^absN; + let c = E()^(1.0 / (12.0 * absN) - (1.0 / (360.0 * (absN^3.0)))); + + a * b * c +} + +/// Returns the natural logarithm of the gamma function (aka the log-gamma +/// function). +/// +/// # Description +/// The gamma function Γ(x) generalizes the factorial function +/// to the positive real numbers and is defined as +/// integral from 0 to ∞ of t¹⁻ˣ⋅e⁻ᵗ𝑑t +/// +/// The gamma function has the property that for all positive real numbers +/// x, Γ(x + 1) = x⋅Γ(x), such that the factorial function +/// is a special case of Γ, n! = Γ(n + 1) for all natural numbers n. +/// +/// # Input +/// ## x +/// The point x at which the log-gamma function is to be evaluated. +/// +/// # Output +/// The value ㏑(Γ(x)). +function LogGammaD(x : Double) : Double { + // Here, we use the approximation described in Numerical Recipes in C. + let coefficients = [ + 57.1562356658629235, + -59.5979603554754912, + 14.1360979747417471, + -0.491913816097620199, + 0.339946499848118887e-4, + 0.465236289270485756e-4, + -0.983744753048795646e-4, + 0.158088703224912494e-3, + -0.210264441724104883e-3, + 0.217439618115212643e-3, + -0.164318106536763890e-3, + 0.844182239838527433e-4, + -0.261908384015814087e-4, + 0.368991826595316234e-5 + ]; + + Fact(x > 0.0, "Γ(x) not defined for x <= 0."); + + mutable y = x; + let tmp = x + 5.2421875000000000; + + mutable acc = 0.99999999999999709; + for coeff in coefficients { + set y += 1.0; + set acc += coeff / y; + } + + Log(2.506628274631000 * acc / x) + ((x + 0.5) * Log(tmp) - tmp) +} + +/// Returns the approximate natural logarithm of the factorial of a given +/// integer. +/// +/// # Input +/// ## n +/// The number to take the log-factorial of. +/// +/// # Output +/// The natural logarithm of the factorial of the provided input. +/// +/// # See Also +/// - Microsoft.Quantum.Math.ApproximateFactorial +/// - Microsoft.Quantum.Math.FactorialI +/// - Microsoft.Quantum.Math.FactorialL +function LogFactorialD(n : Int) : Double { + LogGammaD(IntAsDouble(n) + 1.0) +} + +/// Returns the approximate binomial coefficient of two integers. +/// +/// # Description +/// Given two integers n and k, returns the binomial coefficient +/// binom(n, k), also known as n-choose-k. Computed approximately. +/// +/// # Input +/// ## n +/// The first of the two integers to compute the binomial coefficient of. +/// ## k +/// The second of the two integers to compute the binomial coefficient of. +/// +/// # Output +/// The binomial coefficient n-choose-k. +function Binom(n : Int, k : Int) : Int { + // Here, we use the approximation described in Numerical Recipes in C. + if n < 171 { + Floor(0.5 + ApproximateFactorial(n) / (ApproximateFactorial(k) * ApproximateFactorial(n - k))) + } else { + Floor(0.5 + E()^(LogFactorialD(n) - LogFactorialD(k) - LogFactorialD(n - k))) + } +} + +// +// Norms +// + +/// # Summary +/// Returns the squared 2-norm of a vector. +/// +/// # Description +/// Returns the squared 2-norm of a vector; that is, given an input +/// x̄, returns ∑xᵢ. +/// +/// # Input +/// ## array +/// The vector whose squared 2-norm is to be returned. +/// +/// # Output +/// The squared 2-norm of `array`. +function SquaredNorm(array : Double[]) : Double { + mutable sum = 0.0; + for element in array { + set sum += element * element; + } + + sum +} + +/// Returns the `L(p)` norm of a vector of `Double`s. +/// +/// That is, given an array x of type `Double[]`, this returns the p-norm +/// |x̄|ₚ= (∑(xᵢ)ᵖ)¹ᐟᵖ. +/// +/// # Input +/// ## p +/// The exponent p in the p-norm. +/// +/// # Output +/// The p-norm |x̄|ₚ. +function PNorm(p : Double, array : Double[]) : Double { + if p < 1.0 { + fail "p must be >= 1.0"; + } + + mutable sum = 0.0; + for element in array { + set sum += AbsD(element)^p; + } + + sum^(1.0 / p) +} + +/// Normalizes a vector of `Double`s in the `L(p)` norm. +/// +/// That is, given an array x of type `Double[]`, this returns an array where +/// all elements are divided by the p-norm |x̄|ₚ. +/// Function leaves array with norm 0 unchanged. +/// +/// # Input +/// ## p +/// The exponent p in the p-norm. +/// +/// # Output +/// The array x normalized by the p-norm |x̄|ₚ. +/// +/// # See Also +/// - PNorm +function PNormalized(p : Double, array : Double[]) : Double[] { + let norm = PNorm(p, array); + if (norm == 0.0) { + return array; + } + + mutable result = []; + for element in array { + set result += [element / norm]; + } + + result +} + +// +// Complex numbers +// + +/// # Summary +/// Represents a complex number by its real and imaginary components. +/// The first element of the tuple is the real component, +/// the second one - the imaginary component. +/// +/// # Example +/// The following snippet defines the imaginary unit 𝑖 = 0 + 1𝑖: +/// ```qsharp +/// let imagUnit = Complex(0.0, 1.0); +/// ``` +struct Complex { Real : Double, Imag : Double } + +/// Represents a complex number in polar form. +/// The polar representation of a complex number is c = r⋅𝑒^(t𝑖). +/// +/// # Named Items +/// ## Magnitude +/// The absolute value r>0 of c. +/// ## Argument +/// The phase t ∈ ℝ of c. +struct ComplexPolar { Magnitude : Double, Argument : Double } + +/// Returns the squared absolute value of a complex number of type +/// `Complex`. +/// +/// # Input +/// ## input +/// Complex number c = x + y𝑖. +/// +/// # Output +/// Squared absolute value |c|² = x² + y². +function AbsSquaredComplex(input : Complex) : Double { + input.Real * input.Real + input.Imag * input.Imag +} + +/// Returns the absolute value of a complex number of type +/// `Complex`. +/// +/// # Input +/// ## input +/// Complex number c = x + y𝑖. +/// +/// # Output +/// Absolute value |c| = √(x² + y²). +function AbsComplex(input : Complex) : Double { + Sqrt(AbsSquaredComplex(input)) +} + +/// Returns the phase of a complex number of type +/// `Complex`. +/// +/// # Input +/// ## input +/// Complex number c = x + y𝑖. +/// +/// # Output +/// Phase Arg(c) = ArcTan(y,x) ∈ (-𝜋,𝜋]. +function ArgComplex(input : Complex) : Double { + ArcTan2(input.Imag, input.Real) +} + +/// Returns the squared absolute value of a complex number of type +/// `ComplexPolar`. +/// +/// # Input +/// ## input +/// Complex number c = r⋅𝑒^(t𝑖). +/// +/// # Output +/// Squared absolute value |c|² = r². +function AbsSquaredComplexPolar(input : ComplexPolar) : Double { + input.Magnitude * input.Magnitude +} + +/// Returns the absolute value of a complex number of type +/// `ComplexPolar`. +/// +/// # Input +/// ## input +/// Complex number c = r⋅𝑒^(t𝑖). +/// +/// # Output +/// Absolute value |c| = r. +function AbsComplexPolar(input : ComplexPolar) : Double { input.Magnitude } + +/// Returns the phase of a complex number of type `ComplexPolar`. +/// +/// # Input +/// ## input +/// Complex number c = r⋅𝑒^(t𝑖). +/// +/// # Output +/// Phase Arg(c) = t. +function ArgComplexPolar(input : ComplexPolar) : Double { input.Argument } + +/// Returns the unary negation of an input of type `Complex`. +/// +/// # Input +/// ## input +/// A value whose negation is to be returned. +/// +/// # Output +/// The unary negation of `input`. +function NegationC(input : Complex) : Complex { + Complex(-input.Real, -input.Imag) +} + +/// Returns the unary negation of an input of type `ComplexPolar` +/// +/// # Input +/// ## input +/// A value whose negation is to be returned. +/// +/// # Output +/// The unary negation of `input`. +function NegationCP(input : ComplexPolar) : ComplexPolar { + ComplexPolar(input.Magnitude, input.Argument + PI()) +} + +/// Returns the sum of two inputs of type `Complex`. +/// +/// # Input +/// ## a +/// The first input a to be summed. +/// ## b +/// The second input b to be summed. +/// +/// # Output +/// The sum a + b. +function PlusC(a : Complex, b : Complex) : Complex { + Complex(a.Real + b.Real, a.Imag + b.Imag) +} + +/// Returns the sum of two inputs of type `ComplexPolar`. +/// +/// # Input +/// ## a +/// The first input a to be summed. +/// ## b +/// The second input b to be summed. +/// +/// # Output +/// The sum a + b. +function PlusCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { + ComplexAsComplexPolar( + PlusC( + ComplexPolarAsComplex(a), + ComplexPolarAsComplex(b) + ) + ) +} + +/// Returns the difference between two inputs of type `Complex`. +/// +/// # Input +/// ## a +/// The first input a to be subtracted. +/// ## b +/// The second input b to be subtracted. +/// +/// # Output +/// The difference a - b. +function MinusC(a : Complex, b : Complex) : Complex { + Complex(a.Real - b.Real, a.Imag - b.Imag) +} + +/// Returns the difference between two inputs of type `ComplexPolar`. +/// +/// # Input +/// ## a +/// The first input a to be subtracted. +/// ## b +/// The second input b to be subtracted. +/// +/// # Output +/// The difference a - b. +function MinusCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { + PlusCP(a, NegationCP(b)) +} + +/// Returns the product of two inputs of type `Complex`. +/// +/// # Input +/// ## a +/// The first input a to be multiplied. +/// ## b +/// The second input b to be multiplied. +/// +/// # Output +/// The product a⋅b. +function TimesC(a : Complex, b : Complex) : Complex { + Complex( + a.Real * b.Real - a.Imag * b.Imag, + a.Real * b.Imag + a.Imag * b.Real + ) +} + +/// Returns the product of two inputs of type `ComplexPolar`. +/// +/// # Input +/// ## a +/// The first input a to be multiplied. +/// ## b +/// The second input b to be multiplied. +/// +/// # Output +/// The product a⋅b. +function TimesCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { + ComplexPolar( + a.Magnitude * b.Magnitude, + a.Argument + b.Argument + ) +} + +/// Internal. Since it is easiest to define the power of two complex numbers +/// in Cartesian form as returning in polar form, we define that here, then +/// convert as needed. +/// Note that this is a multi-valued function, but only one value is returned. +internal function PowCAsCP(base : Complex, power : Complex) : ComplexPolar { + let (a, b) = (base.Real, base.Imag); + let (c, d) = (power.Real, power.Imag); + let baseSqNorm = a * a + b * b; + let baseNorm = Sqrt(baseSqNorm); + let baseArg = ArgComplex(base); + + // We pick the principal value of the multi-valued complex function ㏑ as + // ㏑(a+b𝑖) = ln(|a+b𝑖|) + 𝑖⋅arg(a+b𝑖) = ln(baseNorm) + 𝑖⋅baseArg + // Therefore + // base^power = (a+b𝑖)^(c+d𝑖) = 𝑒^( (c+d𝑖)⋅㏑(a+b𝑖) ) = + // = 𝑒^( (c+d𝑖)⋅(ln(baseNorm)+𝑖⋅baseArg) ) = + // = 𝑒^( (c⋅ln(baseNorm) - d⋅baseArg) + 𝑖⋅(c⋅baseArg + d⋅ln(baseNorm)) ) + // magnitude = 𝑒^((c⋅ln(baseNorm) - d⋅baseArg)) = baseNorm^c / 𝑒^(d⋅baseArg) + // angle = d⋅ln(baseNorm) + c⋅baseArg + + let magnitude = baseNorm^c / E()^(d * baseArg); + let angle = d * Log(baseNorm) + c * baseArg; + + ComplexPolar(magnitude, angle) +} + +/// Returns a number raised to a given power of type `Complex`. +/// Note that this is a multi-valued function, but only one value is returned. +/// +/// # Input +/// ## a +/// The number a that is to be raised. +/// ## power +/// The power b to which a should be raised. +/// +/// # Output +/// The power a^b +function PowC(a : Complex, power : Complex) : Complex { + ComplexPolarAsComplex(PowCAsCP(a, power)) +} + +/// Returns a number raised to a given power of type `ComplexPolar`. +/// Note that this is a multi-valued function, but only one value is returned. +/// +/// # Input +/// ## a +/// The number a that is to be raised. +/// ## power +/// The power b to which a should be raised. +/// +/// # Output +/// The power a^b +function PowCP(a : ComplexPolar, power : ComplexPolar) : ComplexPolar { + PowCAsCP(ComplexPolarAsComplex(a), ComplexPolarAsComplex(power)) +} + +/// Returns the quotient of two inputs of type `Complex`. +/// +/// # Input +/// ## a +/// The first input a to be divided. +/// ## b +/// The second input b to be divided. +/// +/// # Output +/// The quotient a / b. +function DividedByC(a : Complex, b : Complex) : Complex { + let sqNorm = b.Real * b.Real + b.Imag * b.Imag; + Complex( + (a.Real * b.Real + a.Imag * b.Imag) / sqNorm, + (a.Imag * b.Real - a.Real * b.Imag) / sqNorm + ) +} + +/// Returns the quotient of two inputs of type `ComplexPolar`. +/// +/// # Input +/// ## a +/// The first input a to be divided. +/// ## b +/// The second input b to be divided. +/// +/// # Output +/// The quotient a / b. +function DividedByCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { + ComplexPolar(a.Magnitude / b.Magnitude, a.Argument - b.Argument) +} + +// +// Fixed point +// + +/// # Summary +/// Returns the smallest representable number for specific fixed point dimensions. +/// +/// # Input +/// ## integerBits +/// Number of integer bits (including the sign bit). +/// ## fractionalBits +/// Number of fractional bits. +/// +/// # Remark +/// The value can be computed as -2^(p-1), where p is the number of integer bits. +function SmallestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { + -(2.0^IntAsDouble(integerBits - 1)) +} + +/// Returns the largest representable number for specific fixed point dimensions. +/// +/// # Input +/// ## integerBits +/// Number of integer bits (including the sign bit). +/// ## fractionalBits +/// Number of fractional bits. +/// +/// # Remark +/// The value can be computed as 2^(p-1) - 2^(-q), where p +/// is the number of integer bits and q is the number of fractional bits. +function LargestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { + 2.0^IntAsDouble(integerBits - 1) - 2.0^(-IntAsDouble(fractionalBits)) +} + +export + PI, + E, + LogOf2, + IsNaN, + IsInfinite, + SignI, + SignD, + SignL, + AbsI, + AbsD, + AbsL, + MaxI, + MaxD, + MaxL, + MinI, + MinD, + MinL, + Max, + Min, + ArcCos, + ArcSin, + ArcTan, + ArcTan2, + Cos, + Cosh, + Sin, + Sinh, + Tan, + Tanh, + ArcCosh, + ArcSinh, + ArcTanh, + Sqrt, + Log, + Log10, + Lg, + Truncate, + Ceiling, + Floor, + Round, + DivRemI, + DivRemL, + ModulusI, + ModulusL, + ExpModI, + ExpModL, + InverseModI, + InverseModL, + GreatestCommonDivisorI, + GreatestCommonDivisorL, + ExtendedGreatestCommonDivisorI, + ExtendedGreatestCommonDivisorL, + IsCoprimeI, + IsCoprimeL, + ContinuedFractionConvergentI, + ContinuedFractionConvergentL, + RealMod, + BitSizeI, + BitSizeL, + TrailingZeroCountI, + TrailingZeroCountL, + HammingWeightI, + FactorialI, + FactorialL, + ApproximateFactorial, + LogGammaD, + LogFactorialD, + Binom, + SquaredNorm, + PNorm, + PNormalized, + Complex, + ComplexPolar, + AbsSquaredComplex, + AbsComplex, + ArgComplex, + AbsSquaredComplexPolar, + AbsComplexPolar, + ArgComplexPolar, + NegationC, + NegationCP, + PlusC, + PlusCP, + MinusC, + MinusCP, + TimesC, + TimesCP, + PowC, + PowCP, + DividedByC, + DividedByCP, + SmallestFixedPoint, + LargestFixedPoint; diff --git a/library/std/src/Std/Measurement.qs b/library/std/src/Std/Measurement.qs new file mode 100644 index 0000000000..2b538d8554 --- /dev/null +++ b/library/std/src/Std/Measurement.qs @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +import Std.Core.*; +import Std.Intrinsic.*; +import Std.Diagnostics.*; +open QIR.Intrinsic; + +/// # Summary +/// Jointly measures a register of qubits in the Pauli Z basis. +/// +/// # Description +/// Measures a register of qubits in the `Z ⊗ Z ⊗ ••• ⊗ Z` +/// basis, representing the parity of the entire register. +/// This operation does not reset the measured qubits to the |0⟩ state, +/// leaving them in the state that corresponds to the measurement result. +/// +/// # Input +/// ## register +/// The register to be jointly measured. +/// +/// # Output +/// The result of measuring in the `Z ⊗ Z ⊗ ••• ⊗ Z` basis. +/// +/// # See also +/// - Microsoft.Quantum.Measurement.MeasureEachZ +operation MeasureAllZ(register : Qubit[]) : Result { + Measure(Repeated(PauliZ, Length(register)), register) +} + +/// Measures each qubit in a given array in the standard basis. +/// +/// # Description +/// Measures each qubit in a register in the `Z` basis +/// and retuns the result of each measurement. +/// This operation does not reset the measured qubits to the |0⟩ state, +/// leaving them in the state that corresponds to the measurement results. +/// +/// # Input +/// ## targets +/// An array of qubits to be measured. +/// # Output +/// An array of measurement results. +/// +/// # Remarks +/// Please note the following differences: +/// - Operation `MeasureEachZ` performs one measurement for each qubit and retuns +/// an array of results. The operation does not reset the qubits. +/// - Operation `MResetEachZ` performs one measurement for each qubit and retuns +/// an array of results. The operation resets all qubits to |0⟩ state. +/// - Operation `MeasureAllZ` performs a joint measurement on all qubits +/// and returns one result. The operation does not reset the qubits. +/// +/// # See also +/// - Microsoft.Quantum.Measurement.MeasureAllZ +/// - Microsoft.Quantum.Measurement.MResetEachZ +operation MeasureEachZ(register : Qubit[]) : Result[] { + mutable results = []; + for qubit in register { + set results += [M(qubit)]; + } + results +} + +/// Measures each qubit in a given array in the Z basis +/// and resets them to a fixed initial state. +/// +/// # Input +/// ## targets +/// An array of qubits to be measured. +/// +/// # Output +/// An array of measurement results. +/// +/// # See also +/// - Microsoft.Quantum.Measurement.MeasureEachZ +operation MResetEachZ(register : Qubit[]) : Result[] { + mutable results = []; + for qubit in register { + set results += [MResetZ(qubit)]; + } + results +} + +/// Measures a single qubit in the X basis, +/// and resets it to a fixed initial state +/// following the measurement. +/// +/// # Description +/// Performs a single-qubit measurement in the X-basis, +/// and ensures that the qubit is returned to |0⟩ +/// following the measurement. +/// +/// # Input +/// ## target +/// A single qubit to be measured. +/// +/// # Output +/// The result of measuring `target` in the Pauli X basis. +operation MResetX(target : Qubit) : Result { + // Map the qubit's state from the Z-basis to the X-basis. + // Then measure and reset the qubit. + H(target); + MResetZ(target) +} + +/// Measures a single qubit in the Y basis, +/// and resets it to a fixed initial state +/// following the measurement. +/// +/// # Description +/// Performs a single-qubit measurement in the Y-basis, +/// and ensures that the qubit is returned to |0⟩ +/// following the measurement. +/// +/// # Input +/// ## target +/// A single qubit to be measured. +/// +/// # Output +/// The result of measuring `target` in the Pauli Y basis. +operation MResetY(target : Qubit) : Result { + // Map the qubit's state from the Z-basis to the Y-basis. + // Then measure and reset the qubit. + // Note: this use HSadj instead of HSH since that is sufficient for measurement. + Adjoint S(target); + H(target); + MResetZ(target) +} + +/// Measures a single qubit in the Z basis, +/// and resets it to a fixed initial state +/// following the measurement. +/// +/// # Description +/// Performs a single-qubit measurement in the Z-basis, +/// and ensures that the qubit is returned to |0⟩ +/// following the measurement. +/// +/// # Input +/// ## target +/// A single qubit to be measured. +/// +/// # Output +/// The result of measuring `target` in the Pauli Z basis. +operation MResetZ(target : Qubit) : Result { + __quantum__qis__mresetz__body(target) +} + +/// Measures the content of a quantum register and converts +/// it to an integer. The measurement is performed with respect +/// to the standard computational basis, i.e., the eigenbasis of `PauliZ`. +/// +/// # Input +/// ## target +/// A quantum register in the little-endian encoding. +/// +/// # Output +/// An unsigned integer that contains the measured value of `target`. +/// +/// # Remarks +/// This operation resets its input register to the |00...0> state, +/// suitable for releasing back to a target machine. +operation MeasureInteger(target : Qubit[]) : Int { + let nBits = Length(target); + Fact(nBits < 64, $"`Length(target)` must be less than 64, but was {nBits}."); + + mutable number = 0; + for i in 0..nBits - 1 { + if (MResetZ(target[i]) == One) { + set number |||= 1 <<< i; + } + } + + number +} +export MeasureAllZ, MeasureEachZ, MResetEachZ, MResetX, MResetY, MResetZ, MeasureInteger; + diff --git a/library/std/src/Std/Random.qs b/library/std/src/Std/Random.qs new file mode 100644 index 0000000000..e1007dbe5d --- /dev/null +++ b/library/std/src/Std/Random.qs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + + +/// # Summary +/// Draws a random integer from a uniform distribution +/// in a given inclusive range. Fails if `max < min`. +/// +/// # Input +/// ## min +/// The smallest integer to be drawn. +/// ## max +/// The largest integer to be drawn. +/// +/// # Output +/// An integer in the inclusive range from `min` to `max` with uniform +/// probability. +/// +/// # Example +/// The following Q# snippet randomly rolls a six-sided die: +/// ```qsharp +/// let roll = DrawRandomInt(1, 6); +/// ``` +@Config(Unrestricted) +operation DrawRandomInt(min : Int, max : Int) : Int { + body intrinsic; +} + +/// Draws a random real number from a uniform distribution +/// in a given inclusive interval. Fails if `max < min`. +/// +/// # Input +/// ## min +/// The smallest real number to be drawn. +/// ## max +/// The largest real number to be drawn. +/// +/// # Output +/// A random real number in the inclusive interval from `min` to `max` with +/// uniform probability. +/// +/// # Example +/// The following Q# snippet randomly draws an angle between 0 and 2π: +/// ```qsharp +/// let angle = DrawRandomDouble(0.0, 2.0 * PI()); +/// ``` +@Config(Unrestricted) +operation DrawRandomDouble(min : Double, max : Double) : Double { + body intrinsic; +} + +/// Given a success probability, returns a single Bernoulli trial +/// that is true with the given probability. +/// +/// # Input +/// ## successProbability +/// The probability with which true should be returned. +/// +/// # Output +/// `true` with probability `successProbability` +/// and `false` with probability `1.0 - successProbability`. +/// +/// # Example +/// The following Q# snippet samples flips from a biased coin: +/// ```qsharp +/// let flips = DrawMany(DrawRandomBool, 10, 0.6); +/// ``` +@Config(Unrestricted) +operation DrawRandomBool(successProbability : Double) : Bool { + body intrinsic; +} + +export DrawRandomInt, DrawRandomDouble, DrawRandomBool; diff --git a/library/std/src/Std/ResourceEstimation.qs b/library/std/src/Std/ResourceEstimation.qs new file mode 100644 index 0000000000..f0da84c88e --- /dev/null +++ b/library/std/src/Std/ResourceEstimation.qs @@ -0,0 +1,183 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + + +// Functionality needed to instruct the resource estimator to cache estimates of a code fragment +// and reuse these estimates without executing the code fragment repeatedly. This functionality +// is only available when using resource estimator execution target. `BeginCostCaching` +// and `EndCostCaching` are not defined for other execution targets. + +/// # Summary +/// Used to specify that there's only one execution variant in `BeginEstimateCaching` +/// function +function SingleVariant() : Int { + return 0; +} + +/// Informs the resource estimator of the start of the code fragment +/// for which estimates caching can be done. This function +/// is only available when using resource estimator execution target. +/// +/// # Input +/// ## name +/// The name of the code fragment. Used to distinguish it from other code fragments. +/// Typically this is the name of the operation for which estimates can be cached. +/// ## variant +/// Specific variant of the execution. Cached estimates can only be reused if the +/// variant for which they were collected and the current variant is the same. +/// +/// # Output +/// `true` indicated that the cached estimates are not yet available and the code fragment +/// needs to be executed in order to collect and cache estimates. +/// `false` indicates if cached estimates have been incorporated into the overall costs +/// and the code fragment should be skipped. +function BeginEstimateCaching(name : String, variant : Int) : Bool { + body intrinsic; +} + +/// Instructs the resource estimator to stop estimates caching +/// because the code fragment in consideration is over. This function +/// is only available when using resource estimator execution target. +function EndEstimateCaching() : Unit { + body intrinsic; +} + +// Functionality needed to account for the resource estimates of an operation +// that is not implemented. Estimates that are obtained separately and passed to the +// `AccountForEstimates` become incorporated into the overall program estimates. +// This functionality is only available when using resource estimator execution target. +// `AccountForEstimates' is not defined for other execution targets. + +/// # Summary +/// Returns a tuple that can be passed to the `AccountForEstimates` operation +/// to specify that the number of auxiliary qubits is equal to the `amount`. +function AuxQubitCount(amount : Int) : (Int, Int) { + return (0, amount); +} + +/// Returns a tuple that can be passed to the `AccountForEstimates` operation +/// to specify that the number of the T gates is equal to the `amount`. +function TCount(amount : Int) : (Int, Int) { + return (1, amount); +} + +/// Returns a tuple that can be passed to the `AccountForEstimates` operation +/// to specify that the number of rotations is equal to the `amount`. +function RotationCount(amount : Int) : (Int, Int) { + return (2, amount); +} + +/// Returns a tuple that can be passed to the `AccountForEstimates` operation +/// to specify that the rotation depth is equal to the `amount`. +function RotationDepth(amount : Int) : (Int, Int) { + return (3, amount); +} + +/// Returns a tuple that can be passed to the `AccountForEstimates` operation +/// to specify that the number of the CCZ gates is equal to the `amount`. +function CczCount(amount : Int) : (Int, Int) { + return (4, amount); +} + +/// Returns a tuple that can be passed to the `AccountForEstimates` operation +/// to specify that the number Measurements is equal to the `amount`. +function MeasurementCount(amount : Int) : (Int, Int) { + return (5, amount); +} + +/// Pass the value returned by the function to the `AccountForEstimates` operation +/// to indicate Parallel Synthesis Sequential Pauli Computation (PSSPC) layout. +/// See https://arxiv.org/pdf/2211.07629.pdf for details. +function PSSPCLayout() : Int { + return 1; +} + +/// Account for the resource estimates of an unimplemented operation, +/// which were obtained separately. This operation is only available +/// when using resource estimator execution target. +/// # Input +/// ## cost +/// Array of tuples containing resource estimates of the operation. For example, +/// if the operation uses three T gates, pass the tuple returned by TCount(3) +/// as one of the array elements. +/// ## layout +/// Provides the layout scheme that is used to convert logical resource estimates +/// to physical resource estimates. Only PSSPCLayout() is supported at this time. +/// ## arguments +/// Operation takes these qubits as its arguments. +operation AccountForEstimates(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit is Adj { + body ... { + AccountForEstimatesInternal(estimates, layout, arguments); + } + adjoint self; +} + +internal operation AccountForEstimatesInternal(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit { + body intrinsic; +} + +/// Instructs the resource estimator to assume that the resources from the +/// call of this operation until a call to `EndRepeatEstimates` are +/// accounted for `count` times, without the need to execute the code that many +/// times. Calls to `BeginRepeatEstimates` and `EndRepeatEstimates` can be nested. +/// A helper operation `RepeatEstimates` allows to call the two functions in a +/// `within` block. +/// +/// # Input +/// ## count +/// Assumed number of repetitions, factor to multiply the cost with +operation BeginRepeatEstimates(count : Int) : Unit { + body ... { + BeginRepeatEstimatesInternal(count); + } + adjoint self; +} + +internal operation BeginRepeatEstimatesInternal(count : Int) : Unit { + body intrinsic; +} + +/// Companion operation to `BeginRepeatEstimates`. +operation EndRepeatEstimates() : Unit { + body ... { + EndRepeatEstimatesInternal(); + } + adjoint self; +} + +internal operation EndRepeatEstimatesInternal() : Unit { + body intrinsic; +} + +/// Instructs the resource estimator to assume that the resources from the +/// call of this operation until a call to `Adjoint RepeatEstimates` are +/// accounted for `count` times, without the need to execute the code that many +/// times. +/// +/// # Input +/// ## count +/// Assumed number of repetitions, factor to multiply the cost with +operation RepeatEstimates(count : Int) : Unit is Adj { + body ... { + BeginRepeatEstimates(count); + } + adjoint ... { + EndRepeatEstimates(); + } +} +export + SingleVariant, + BeginEstimateCaching, + EndEstimateCaching, + AuxQubitCount, + TCount, + RotationCount, + RotationDepth, + CczCount, + MeasurementCount, + PSSPCLayout, + AccountForEstimates, + BeginRepeatEstimates, + EndRepeatEstimates, + RepeatEstimates; diff --git a/library/std/src/arrays.qs b/library/std/src/arrays.qs deleted file mode 100644 index 2cde64b90d..0000000000 --- a/library/std/src/arrays.qs +++ /dev/null @@ -1,1444 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Arrays { - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - - /// # Summary - /// Given an array and a predicate that is defined - /// for the elements of the array, and checks if all elements of the - /// array satisfy the predicate. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## predicate - /// A function from `'T` to `Bool` that is used to check elements. - /// ## array - /// An array of elements over `'T`. - /// - /// # Output - /// A `Bool` value of the AND function of the predicate applied to all elements. - /// - /// # Example - /// The following code checks whether all elements of the array are non-zero: - /// ```qsharp - /// let allNonZero = All(x -> x != 0, [1, 2, 3, 4, 5]); - /// ``` - function All<'T>(predicate : ('T -> Bool), array : 'T[]) : Bool { - for element in array { - if not predicate(element) { - return false; - } - } - - true - } - - /// # Summary - /// Given an array and a predicate that is defined - /// for the elements of the array, checks if at least one element of - /// the array satisfies the predicate. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## predicate - /// A function from `'T` to `Bool` that is used to check elements. - /// ## array - /// An array of elements over `'T`. - /// - /// # Output - /// A `Bool` value of the OR function of the predicate applied to all elements. - /// - /// # Example - /// ```qsharp - /// let anyEven = Any(x -> x % 2 == 0, [1, 3, 6, 7, 9]); - /// ``` - function Any<'T>(predicate : ('T -> Bool), array : 'T[]) : Bool { - for element in array { - if predicate(element) { - return true; - } - } - - false - } - - /// # Summary - /// Splits an array into multiple parts of equal length. - /// - /// # Input - /// ## chunkSize - /// The length of each chunk. Must be positive. - /// ## array - /// The array to be split in chunks. - /// - /// # Output - /// A array containing each chunk of the original array. - /// - /// # Remarks - /// Note that the last element of the output may be shorter - /// than `chunkSize` if `Length(array)` is not divisible by `chunkSize`. - function Chunks<'T>(chunkSize : Int, array : 'T[]) : 'T[][] { - Fact(chunkSize > 0, "`chunkSize` must be positive"); - mutable output = []; - mutable remaining = array; - while (not IsEmpty(remaining)) { - let chunkSizeToTake = MinI(Length(remaining), chunkSize); - set output += [remaining[...chunkSizeToTake - 1]]; - set remaining = remaining[chunkSizeToTake...]; - } - - output - } - - /// # Summary - /// Shift an array circularly left or right by a specific step size. - /// - /// # Type Parameters - /// ## 'T - /// The type of the array elements. - /// - /// # Input - /// ## stepCount - /// The amount of positions by which the array elements will be shifted. - /// If this is positive, `array` is circularly shifted to the right. - /// If this is negative, `array` is circularly shifted to the left. - /// ## array - /// Array to be circularly shifted. - /// - /// # Output - /// An array `output` that is the `array` circularly shifted to the right or left - /// by the specified step size. - /// - /// # Example - /// ```qsharp - /// let array = [10, 11, 12]; - /// // The following line returns [11, 12, 10]. - /// let output = CircularlyShifted(2, array); - /// // The following line returns [12, 10, 11]. - /// let output = CircularlyShifted(-2, array); - /// ``` - function CircularlyShifted<'T>(stepCount : Int, array : 'T[]) : 'T[] { - let arrayLength = Length(array); - if arrayLength <= 1 { - return array; - } - - // normalize circular shift count to be within the bounds of the array length - let normalizedShift = stepCount % arrayLength; - let effectiveShift = normalizedShift >= 0 ? arrayLength - normalizedShift | -normalizedShift; - - // no shift needed - if effectiveShift == 0 { - return array; - } - - let leftPart = array[...effectiveShift - 1]; - let rightPart = array[effectiveShift..arrayLength - 1]; - - rightPart + leftPart - } - - /// # Summary - /// Extracts a column from a matrix. - /// - /// # Description - /// This function extracts a column in a matrix in row-wise order. - /// Extracting a row corresponds to element access of the first index - /// and therefore requires no further treatment. - /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `matrix`. - /// - /// # Input - /// ## column - /// Column of the matrix - /// ## matrix - /// 2-dimensional matrix in row-wise order - /// - /// # Example - /// ```qsharp - /// let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; - /// let column = ColumnAt(0, matrix); - /// // same as: column = [1, 4, 7] - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.Transposed - /// - Microsoft.Quantum.Arrays.Diagonal - function ColumnAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { - Fact(IsRectangularArray(matrix), "`matrix` is not a rectangular array"); - mutable columnValues = []; - for row in matrix { - set columnValues += [row[column]]; - } - columnValues - } - - /// # Summary - /// Given an array and a predicate that is defined - /// for the elements of the array, returns the number of elements - /// an array that consists of those elements that satisfy the predicate. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## predicate - /// A function from `'T` to Boolean that is used to filter elements. - /// ## array - /// An array of elements over `'T`. - /// - /// # Output - /// The number of elements in `array` that satisfy the predicate. - /// - /// # Example - /// ```qsharp - /// let evensCount = Count(x -> x % 2 == 0, [1, 3, 6, 7, 9]); - /// // evensCount is 1. - /// ``` - function Count<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { - mutable count = 0; - for element in array { - if predicate(element) { - set count += 1; - } - } - count - } - - /// # Summary - /// Returns an array of diagonal elements of a 2-dimensional array - /// - /// # Description - /// If the 2-dimensional array has not a square shape, the diagonal over - /// the minimum over the number of rows and columns will be returned. - /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `matrix`. - /// - /// # Input - /// ## matrix - /// 2-dimensional matrix in row-wise order. - /// - /// # Example - /// ```qsharp - /// let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; - /// let diagonal = Diagonal(matrix); - /// // same as: column = [1, 5, 9] - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.Transposed - function Diagonal<'T>(matrix : 'T[][]) : 'T[] { - Fact(IsRectangularArray(matrix), "`matrix` is not a rectangular array"); - let rows = Length(matrix); - let columns = rows == 0 ? 0 | Length(Head(matrix)); - let rangeLimit = MinI(rows, columns) - 1; - mutable diagonal = []; - for index in 0..rangeLimit { - set diagonal += [matrix[index][index]]; - } - - diagonal - } - - /// # Summary - /// Repeats an operation for a given number of samples, collecting its outputs - /// in an array. - /// - /// # Input - /// ## op - /// The operation to be called repeatedly. - /// ## nSamples - /// The number of samples of calling `op` to collect. - /// ## input - /// The input to be passed to `op`. - /// - /// # Type Parameters - /// ## TInput - /// The type of input expected by `op`. - /// ## TOutput - /// The type of output returned by `op`. - /// - /// # Example - /// The following samples an alternating array of results. - /// ```qsharp - /// use qubit = Qubit(); - /// let results = Microsoft.Quantum.Arrays.DrawMany(q => {X(q); M(q)}, 3, qubit); - /// ``` - operation DrawMany<'TInput, 'TOutput>(op : ('TInput => 'TOutput), nSamples : Int, input : 'TInput) : 'TOutput[] { - mutable outputs = []; - for _ in 1..nSamples { - set outputs += [op(input)]; - } - outputs - } - - /// # Summary - /// Given an array, returns a new array containing elements of the original - /// array along with the indices of each element. - /// - /// # Type Parameters - /// ## 'TElement - /// The type of elements of the array. - /// - /// # Input - /// ## array - /// An array whose elements are to be enumerated. - /// - /// # Output - /// A new array containing elements of the original array along with their - /// indices. - /// - /// # Example - /// The following `for` loops are equivalent: - /// ```qsharp - /// for (idx in IndexRange(array)) { - /// let element = array[idx]; - /// ... - /// } - /// for ((idx, element) in Enumerated(array)) { ... } - /// ``` - function Enumerated<'TElement>(array : 'TElement[]) : (Int, 'TElement)[] { - MappedByIndex((index, element) -> (index, element), array) - } - - /// # Summary - /// Returns an array containing the elements of another array, - /// excluding elements at a given list of indices. - /// - /// # Type Parameters - /// ## 'T - /// The type of the array elements. - /// - /// # Input - /// ## remove - /// An array of indices denoting which elements should be excluded. - /// from the output. - /// ## array - /// Array of which the values in the output array are taken. - /// - /// # Output - /// An array `output` such that `output[0]` is the first element - /// of `array` whose index does not appear in `remove`, - /// such that `output[1]` is the second such element, and so - /// forth. - /// - /// # Example - /// ```qsharp - /// let array = [10, 11, 12, 13, 14, 15]; - /// // The following line returns [10, 12, 15]. - /// let subarray = Excluding([1, 3, 4], array); - /// ``` - function Excluding<'T>(remove : Int[], array : 'T[]) : 'T[] { - let arrayLength = Length(array); - mutable toKeep = Repeated(true, arrayLength); - for indexToRemove in remove { - set toKeep w/= indexToRemove <- false; - } - mutable output = []; - for index in 0..arrayLength - 1 { - if toKeep[index] { - set output += [array[index]]; - } - } - output - } - - /// # Summary - /// Given an array and a predicate that is defined - /// for the elements of the array, returns an array that consists of - /// those elements that satisfy the predicate. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## predicate - /// A function from `'T` to Boolean that is used to filter elements. - /// ## array - /// An array of elements over `'T`. - /// - /// # Output - /// An array `'T[]` of elements that satisfy the predicate. - /// - /// # Example - /// The following code creates an array that contains only even numbers. - /// ```qsharp - /// Filtered(x -> x % 2 == 0, [0, 1, 2, 3, 4]) - /// ``` - function Filtered<'T>(predicate : ('T -> Bool), array : 'T[]) : 'T[] { - mutable filtered = []; - for element in array { - if predicate(element) { - set filtered += [element]; - } - } - filtered - } - - /// # Summary - /// Given an array and a function that maps an array element to some output - /// array, returns the concatenated output arrays for each array element. - /// - /// # Type Parameters - /// ## 'TInput - /// The type of `array` elements. - /// ## 'TOutput - /// The `mapper` function returns arrays of this type. - /// - /// # Input - /// ## mapper - /// A function from `'TInput` to `'TOutput[]` that is used to map array elements. - /// ## array - /// An array of elements. - /// - /// # Output - /// An array of `'TOutput[]` which is the concatenation of all arrays generated by - /// the mapping function. - /// - /// # Example - /// The following code creates an array with each element of the input array repeated twice. - /// ```qsharp - /// let repeatedPairs = FlatMapped(x -> Repeated(x, 2), [1, 2, 3]); - /// // repeatedPairs is [1, 1, 2, 2, 3, 3]. - /// ``` - function FlatMapped<'TInput, 'TOutput>(mapper : ('TInput -> 'TOutput[]), array : 'TInput[]) : 'TOutput[] { - mutable output = []; - for element in array { - set output += mapper(element); - } - output - } - - /// # Summary - /// Given an array of arrays, returns the concatenation of all arrays. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## arrays - /// Array of arrays. - /// - /// # Output - /// Concatenation of all arrays. - /// - /// # Example - /// ```qsharp - /// let flattened = Flattened([[1, 2], [3], [4, 5, 6]]); - /// // flattened = [1, 2, 3, 4, 5, 6] - /// ``` - function Flattened<'T>(arrays : 'T[][]) : 'T[] { - mutable output = []; - for array in arrays { - set output += array; - } - output - } - - /// # Summary - /// Iterates a function `f` through an array `array`, returning - /// `f(...f(f(initialState, array[0]), array[1]), ...)`. - /// - /// # Type Parameters - /// ## 'State - /// The type of states the `folder` function operates on, i.e., accepts as its first - /// argument and returns. - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## folder - /// A function to be folded over the array. - /// ## state - /// The initial state of the folder. - /// ## array - /// An array of values to be folded over. - /// - /// # Output - /// The final state returned by the folder after iterating over - /// all elements of `array`. - /// - /// # Example - /// ```qsharp - /// let sum = Fold((x, y) -> x + y, 0, [1, 2, 3, 4, 5]); // `sum` is 15. - /// ``` - function Fold<'State, 'T>(folder : (('State, 'T) -> 'State), state : 'State, array : 'T[]) : 'State { - mutable current = state; - for element in array { - set current = folder(current, element); - } - current - } - - /// # Summary - /// Given an array and an operation that is defined - /// for the elements of the array, returns a new array that consists - /// of the images of the original array under the operation. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// ## 'U - /// The result type of the `action` operation. - /// - /// # Input - /// ## action - /// An operation from `'T` to `'U` that is applied to each element. - /// ## array - /// An array of elements over `'T`. - /// - /// # Output - /// An array `'U[]` of elements that are mapped by the `action` operation. - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.Mapped - operation ForEach<'T, 'U>(action : ('T => 'U), array : 'T[]) : 'U[] { - mutable output = []; - for element in array { - set output += [action(element)]; - } - output - } - - /// # Summary - /// Returns the first element of the array. - /// - /// # Type Parameters - /// ## 'A - /// The type of the array elements. - /// - /// # Input - /// ## array - /// Array of which the first element is taken. Array must have at least 1 element. - /// - /// # Output - /// The first element of the array. - function Head<'A>(array : 'A[]) : 'A { - Fact(Length(array) > 0, "Array must have at least 1 element"); - array[0] - } - - /// # Summary - /// Returns a tuple of first and all remaining elements of the array. - /// - /// # Type Parameters - /// ## 'A - /// The type of the array elements. - /// - /// # Input - /// ## array - /// An array with at least one element. - /// - /// # Output - /// A tuple of first and all remaining elements of the array. - function HeadAndRest<'A>(array : 'A[]) : ('A, 'A[]) { - (Head(array), Rest(array)) - } - - /// # Summary - /// Returns the first index of the first element in an array that satisfies - /// a given predicate. If no such element exists, returns -1. - /// - /// # Input - /// ## predicate - /// A predicate function acting on elements of the array. - /// ## array - /// An array to be searched using the given predicate. - /// - /// # Output - /// Either the smallest index of an element for which `predicate(array[index])` is true, - /// or -1 if no such element exists. - /// - /// # Example - /// The following code gets the index of the first even number in the input array. - /// ```qsharp - /// let indexOfFirstEven = IndexOf(x -> x % 2 == 0, [1, 3, 17, 2, 21]); - /// // `indexOfFirstEven` is 3. - /// ``` - function IndexOf<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { - for index in 0..Length(array) - 1 { - if predicate(array[index]) { - return index; - } - } - -1 - } - - /// # Summary - /// Given an array, returns a range over the indices of that array, suitable - /// for use in a for loop. - /// - /// # Type Parameters - /// ## 'TElement - /// The type of elements of the array. - /// - /// # Input - /// ## array - /// An array for which a range of indices should be returned. - /// - /// # Output - /// A range over all indices of the array. - /// - /// # Example - /// The following `for` loops are equivalent: - /// ```qsharp - /// for idx in IndexRange(array) { ... } - /// for idx in 0 .. Length(array) - 1 { ... } - /// ``` - function IndexRange<'TElement>(array : 'TElement[]) : Range { - 0..Length(array) - 1 - } - - /// # Summary - /// Interleaves two arrays of (almost) same size. - /// - /// # Description - /// This function returns the interleaving of two arrays, starting - /// with the first element from the first array, then the first - /// element from the second array, and so on. - /// - /// The first array must either be - /// of the same length as the second one, or can have one more element. - /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `first` and `second`. - /// - /// # Input - /// ## first - /// The first array to be interleaved. - /// - /// ## second - /// The second array to be interleaved. - /// - /// # Output - /// Interleaved array - /// - /// # Example - /// ```qsharp - /// // same as interleaved = [1, -1, 2, -2, 3, -3] - /// let interleaved = Interleaved([1, 2, 3], [-1, -2, -3]) - /// ``` - function Interleaved<'T>(first : 'T[], second : 'T[]) : 'T[] { - let firstLength = Length(first); - let secondLength = Length(second); - Fact( - firstLength == secondLength or firstLength == secondLength + 1, - "Array `first` must either be of same size as `second` or have one more element" - ); - - let interleavedLength = firstLength + secondLength; - mutable interleaved = []; - for index in 0..interleavedLength - 1 { - let originalIndex = index / 2; - let value = if index % 2 == 0 { first[originalIndex] } else { second[originalIndex] }; - set interleaved += [value]; - } - interleaved - } - - /// # Summary - /// Returns true if and only if an array is empty. - /// - /// # Input - /// ## array - /// The array to be checked. - /// - /// # Output - /// `true` if and only if the array is empty (has length 0). - function IsEmpty<'T>(array : 'T[]) : Bool { - Length(array) == 0 - } - - /// # Summary - /// Returns whether a 2-dimensional array has a rectangular shape - /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `array`. - /// - /// # Input - /// ## array - /// A 2-dimensional array of elements. - /// - /// # Output - /// `true` if the array is rectangular, `false` otherwise. - /// - /// # Example - /// ```qsharp - /// IsRectangularArray([[1, 2], [3, 4]]); // true - /// IsRectangularArray([[1, 2, 3], [4, 5, 6]]); // true - /// IsRectangularArray([[1, 2], [3, 4, 5]]); // false - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.IsSquareArray - function IsRectangularArray<'T>(array : 'T[][]) : Bool { - if (Length(array) > 0) { - let columnCount = Length(Head(array)); - for index in 1..Length(array) - 1 { - if Length(array[index]) != columnCount { - return false; - } - } - } - - true - } - - /// # Summary - /// Given an array, returns whether that array is sorted as defined by - /// a given comparison function. - /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `array`. - /// - /// # Input - /// ## comparison - /// A function that compares two elements such that `a` is considered to - /// be less than or equal to `b` if `comparison(a, b)` is `true`. - /// ## array - /// The array to be checked. - /// - /// # Output - /// `true` if and only if for each pair of elements `a` and `b` of - /// `array` occurring in that order, `comparison(a, b)` is `true`. - /// - /// # Remarks - /// The function `comparison` is assumed to be transitive, such that - /// if `comparison(a, b)` and `comparison(b, c)`, then `comparison(a, c)` - /// is assumed. - function IsSorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : Bool { - for index in 1..Length(array) - 1 { - if not comparison(array[index - 1], array[index]) { - return false; - } - } - true - } - - /// # Summary - /// Returns whether a 2-dimensional array has a square shape - /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `array`. - /// - /// # Input - /// ## array - /// A 2-dimensional array of elements. - /// - /// # Example - /// ```qsharp - /// IsSquareArray([[1, 2], [3, 4]]); // true - /// IsSquareArray([[1, 2, 3], [4, 5, 6]]); // false - /// IsSquareArray([[1, 2], [3, 4], [5, 6]]); // false - /// ``` - /// - /// # Output - /// `true` if the array is square, `false` otherwise. - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.IsRectangularArray - function IsSquareArray<'T>(array : 'T[][]) : Bool { - if (Length(array) > 0) { - let columnCount = Length(array); - for column in array { - if Length(column) != columnCount { - return false; - } - } - } - - true - } - - /// # Summary - /// Given an array and a function that is defined - /// for the elements of the array, returns a new array that consists - /// of the images of the original array under the function. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// ## 'U - /// The result type of the `mapper` function. - /// - /// # Input - /// ## mapper - /// A function from `'T` to `'U` that is used to map elements. - /// ## array - /// An array of elements over `'T`. - /// - /// # Output - /// An array `'U[]` of elements that are mapped by the `mapper` function. - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.ForEach - function Mapped<'T, 'U>(mapper : ('T -> 'U), array : 'T[]) : 'U[] { - mutable mapped = []; - for element in array { - set mapped += [mapper(element)]; - } - mapped - } - - /// # Summary - /// Given an array and a function that is defined - /// for the indexed elements of the array, returns a new array that consists - /// of the images of the original array under the function. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// ## 'U - /// The result type of the `mapper` function. - /// - /// # Input - /// ## mapper - /// A function from `(Int, 'T)` to `'U` that is used to map elements - /// and their indices. - /// ## array - /// An array of elements over `'T`. - /// - /// # Output - /// An array `'U[]` of elements that are mapped by the `mapper` function. - /// - /// # Example - /// The following two lines are equivalent: - /// ```qsharp - /// let array = MappedByIndex(f, [x0, x1, x2]); - /// ``` - /// and - /// ```qsharp - /// let array = [f(0, x0), f(1, x1), f(2, x2)]; - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.Mapped - function MappedByIndex<'T, 'U>(mapper : ((Int, 'T) -> 'U), array : 'T[]) : 'U[] { - mutable mapped = []; - for index in 0..Length(array) - 1 { - set mapped += [mapper(index, array[index])]; - } - mapped - } - - /// # Summary - /// Given a range and a function that takes an integer as input, - /// returns a new array that consists - /// of the images of the range values under the function. - /// - /// # Type Parameters - /// ## 'T - /// The result type of the `mapper` function. - /// - /// # Input - /// ## mapper - /// A function from `Int` to `'T` that is used to map range values. - /// ## range - /// A range of integers. - /// - /// # Output - /// An array `'T[]` of elements that are mapped by the `mapper` function. - /// - /// # Example - /// This example adds 1 to a range of even numbers: - /// ```qsharp - /// let numbers = MappedOverRange(x -> x + 1, 0..2..10); - /// // numbers = [1, 3, 5, 7, 9, 11] - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.Mapped - function MappedOverRange<'T>(mapper : (Int -> 'T), range : Range) : 'T[] { - mutable output = []; - for element in range { - set output += [mapper(element)]; - } - output - } - - /// # Summary - /// Creates an array that is equal to an input array except that the last array - /// element is dropped. - /// - /// # Type Parameters - /// ## 'T - /// The type of the array elements. - /// - /// # Input - /// ## array - /// An array whose first to second-to-last elements are to form the output array. - /// - /// # Output - /// An array containing the elements `array[0..Length(array) - 2]`. - function Most<'T>(array : 'T[]) : 'T[] { - array[...Length(array) - 2] - } - - /// # Summary - /// Returns a tuple of all but one and the last element of the array. - /// - /// # Type Parameters - /// ## 'A - /// The type of the array elements. - /// - /// # Input - /// ## array - /// An array with at least one element. - /// - /// # Output - /// A tuple of all but one and the last element of the array. - function MostAndTail<'A>(array : 'A[]) : ('A[], 'A) { - (Most(array), Tail(array)) - } - - /// # Summary - /// Returns an array padded at with specified values up to a - /// specified length. - /// - /// # Type Parameters - /// ## 'T - /// The type of the array elements. - /// - /// # Input - /// ## paddedLength - /// The length of the padded array. If this is positive, `array` - /// is padded at the head. If this is negative, `array` is padded - /// at the tail. - /// ## defaultElement - /// Default value to use for padding elements. - /// ## array - /// Array to be padded. - /// - /// # Output - /// An array `output` that is the `array` padded at the head or the tail - /// with `defaultElement`s until `output` has length `paddedLength` - /// - /// # Example - /// ```qsharp - /// let array = [10, 11, 12]; - /// // The following line returns [10, 12, 15, 2, 2]. - /// let output = Padded(-5, 2, array); - /// // The following line returns [2, 2, 10, 12, 15]. - /// let output = Padded(5, 2, array); - /// ``` - function Padded<'T>(paddedLength : Int, defaultElement : 'T, inputArray : 'T[]) : 'T[] { - let nElementsInitial = Length(inputArray); - let nAbsElementsTotal = AbsI(paddedLength); - if nAbsElementsTotal < nElementsInitial { - fail "Specified output array length must be at least as long as `inputArray` length."; - } - let nElementsPad = nAbsElementsTotal - nElementsInitial; - let padArray = Repeated(defaultElement, nElementsPad); - if (paddedLength >= 0) { - padArray + inputArray // Padded at head. - } else { - inputArray + padArray // Padded at tail. - } - } - - /// # Summary - /// Splits an array into multiple parts. - /// - /// # Input - /// ## partitionSizes - /// Number of elements in each split part of array. - /// ## array - /// Input array to be split. - /// - /// # Output - /// Multiple arrays where the first array is the first `partitionSizes[0]` of `array` - /// and the second array are the next `partitionSizes[1]` of `array` etc. The last array - /// will contain all remaining elements. If the array is split exactly, the - /// last array will be the empty array, indicating there are no remaining elements. - /// In other words, `Tail(Partitioned(...))` will always return the remaining - /// elements, while `Most(Partitioned(...))` will always return the complete - /// partitions of the array. - /// - /// # Example - /// ```qsharp - /// // The following returns [[2, 3], [5], [7]]; - /// let split = Partitioned([2, 1], [2, 3, 5, 7]); - /// // The following returns [[2, 3], [5, 7], []]; - /// let split = Partitioned([2, 2], [2, 3, 5, 7]); - /// ``` - function Partitioned<'T>(partitionSizes : Int[], array : 'T[]) : 'T[][] { - mutable output = Repeated([], Length(partitionSizes) + 1); - mutable partitionStartIndex = 0; - for index in IndexRange(partitionSizes) { - let partitionEndIndex = partitionStartIndex + partitionSizes[index] - 1; - if partitionEndIndex >= Length(array) { - fail "Partitioned argument out of bounds."; - } - set output w/= index <- array[partitionStartIndex..partitionEndIndex]; - set partitionStartIndex = partitionEndIndex + 1; - } - set output w/= Length(partitionSizes) <- array[partitionStartIndex..Length(array) - 1]; - output - } - - /// # Summary - /// Creates an array that is equal to an input array except that the first array - /// element is dropped. - /// - /// # Type Parameters - /// ## 'T - /// The type of the array elements. - /// - /// # Input - /// ## array - /// An array whose second to last elements are to form the output array. - /// - /// # Output - /// An array containing the elements `array[1..Length(array) - 1]`. - function Rest<'T>(array : 'T[]) : 'T[] { - array[1...] - } - - /// # Summary - /// Create an array that contains the same elements as an input array but in reversed - /// order. - /// - /// # Type Parameters - /// ## 'T - /// The type of the array elements. - /// - /// # Input - /// ## array - /// An array whose elements are to be copied in reversed order. - /// - /// # Output - /// An array containing the elements `array[Length(array) - 1]` .. `array[0]`. - function Reversed<'T>(array : 'T[]) : 'T[] { - array[...-1...] - } - - /// # Summary - /// Get an array of integers in a given interval. - /// - /// # Input - /// ## from - /// An inclusive start index of the interval. - /// ## to - /// An inclusive end index of the interval that is not smaller than `from`. - /// - /// # Output - /// An array containing the sequence of numbers `from`, `from + 1`, ..., - /// `to`. - /// - /// # Example - /// ```qsharp - /// let arr1 = SequenceI(0, 3); // [0, 1, 2, 3] - /// let arr2 = SequenceI(23, 29); // [23, 24, 25, 26, 27, 28, 29] - /// let arr3 = SequenceI(-5, -2); // [-5, -4, -3, -2] - /// - /// let numbers = SequenceI(0, _); // function to create sequence from 0 to `to` - /// let naturals = SequenceI(1, _); // function to create sequence from 1 to `to` - /// ``` - function SequenceI(from : Int, to : Int) : Int[] { - Fact(to >= from, "`to` must be larger than `from`."); - mutable array = []; - for index in from..to { - set array += [index]; - } - array - } - - /// # Summary - /// Get an array of integers in a given interval. - /// - /// # Input - /// ## from - /// An inclusive start index of the interval. - /// ## to - /// An inclusive end index of the interval that is not smaller than `from`. - /// - /// # Output - /// An array containing the sequence of numbers `from`, `from + 1`, ..., - /// `to`. - /// - /// # Remarks - /// The difference between `from` and `to` must fit into an `Int` value. - /// - /// # Example - /// ```qsharp - /// let arr1 = SequenceL(0L, 3L); // [0L, 1L, 2L, 3L] - /// let arr2 = SequenceL(23L, 29L); // [23L, 24L, 25L, 26L, 27L, 28L, 29L] - /// let arr3 = SequenceL(-5L, -2L); // [-5L, -4L, -3L, -2L] - /// ``` - function SequenceL(from : BigInt, to : BigInt) : BigInt[] { - Fact(to >= from, "`to` must be larger than `from`"); - mutable array = []; - mutable current = from; - while current <= to { - set array += [current]; - set current += 1L; - } - - array - } - - /// # Summary - /// Given an array, returns the elements of that array sorted by a given - /// comparison function. - /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `array`. - /// - /// # Input - /// ## comparison - /// A function that compares two elements such that `a` is considered to - /// be less than or equal to `b` if `comparison(a, b)` is `true`. - /// ## array - /// The array to be sorted. - /// - /// # Output - /// An array containing the same elements as `array`, such that for all - /// elements `a` occurring earlier than elements `b`, `comparison(a, b)` - /// is `true`. - /// - /// # Example - /// The following snippet sorts an array of integers to occur in ascending - /// order: - /// ```qsharp - /// let sortedArray = Sorted(LessThanOrEqualI, [3, 17, 11, -201, -11]); - /// ``` - /// - /// # Remarks - /// The function `comparison` is assumed to be transitive, such that - /// if `comparison(a, b)` and `comparison(b, c)`, then `comparison(a, c)` - /// is assumed. If this property does not hold, then the output of this - /// function may be incorrect. - function Sorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : 'T[] { - if Length(array) <= 1 { - return array; - } - - let pivotIndex = Length(array) / 2; - let left = array[...pivotIndex - 1]; - let right = array[pivotIndex...]; - - // Sort each sublist, then merge them back into a single combined - // list and return. - SortedMerged( - comparison, - Sorted(comparison, left), - Sorted(comparison, right) - ) - } - - /// # Summary - /// Given two sorted arrays, returns a single array containing the - /// elements of both in sorted order. Used internally by `Sorted`. - internal function SortedMerged<'T>(comparison : (('T, 'T) -> Bool), left : 'T[], right : 'T[]) : 'T[] { - mutable output = []; - mutable remainingLeft = left; - mutable remainingRight = right; - while (not IsEmpty(remainingLeft)) and (not IsEmpty(remainingRight)) { - if comparison(Head(remainingLeft), Head(remainingRight)) { - set output += [Head(remainingLeft)]; - set remainingLeft = Rest(remainingLeft); - } else { - set output += [Head(remainingRight)]; - set remainingRight = Rest(remainingRight); - } - } - - // Note that at this point, either or both of `remainingLeft` and `remainingRight` are empty, - // such that we can simply append both to our output to get the whole merged array. - output + remainingLeft + remainingRight - } - - /// # Summary - /// Takes an array and a list of locations and - /// produces a new array formed from the elements of the original - /// array that match the given locations. - /// - /// # Remarks - /// If `locations` contains repeated elements, the corresponding elements - /// of `array` will likewise be repeated. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## locations - /// A list of locations in the input array that is used to define the subarray. - /// ## array - /// An array from which a subarray will be generated. - /// - /// # Output - /// An array `out` of elements whose locations correspond to the subarray, - /// such that `out[index] == array[locations[index]]`. - /// - /// # Example - /// - /// ```qsharp - /// let array = [1, 2, 3, 4]; - /// let permutation = Subarray([3, 0, 2, 1], array); // [4, 1, 3, 2] - /// let duplicates = Subarray([1, 2, 2], array); // [2, 3, 3] - /// ``` - function Subarray<'T>(locations : Int[], array : 'T[]) : 'T[] { - mutable subarray = []; - for location in locations { - set subarray += [array[location]]; - } - subarray - } - - /// # Summary - /// Applies a swap of two elements in an array. - /// - /// # Input - /// ## firstIndex - /// Index of the first element to be swapped. - /// - /// ## secondIndex - /// Index of the second element to be swapped. - /// - /// ## array - /// Array with elements to be swapped. - /// - /// # Output - /// The array with the in place swap applied. - /// - /// # Example - /// ```qsharp - /// // The following returns [0, 3, 2, 1, 4] - /// Swapped(1, 3, [0, 1, 2, 3, 4]); - /// ``` - function Swapped<'T>(firstIndex : Int, secondIndex : Int, array : 'T[]) : 'T[] { - array - w/ firstIndex <- array[secondIndex] - w/ secondIndex <- array[firstIndex] - } - - /// # Summary - /// Returns the transpose of a matrix represented as an array - /// of arrays. - /// - /// # Description - /// Input as an r x c matrix with r rows and c columns. The matrix - /// is row-based, i.e., `matrix[i][j]` accesses the element at row `i` and column `j`. - /// - /// This function returns the c x r matrix that is the transpose of the - /// input matrix. - /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `matrix`. - /// - /// # Input - /// ## matrix - /// Row-based r x c matrix. - /// - /// # Output - /// Transposed c x r matrix. - /// - /// # Example - /// ```qsharp - /// // same as [[1, 4], [2, 5], [3, 6]] - /// let transposed = Transposed([[1, 2, 3], [4, 5, 6]]); - /// ``` - function Transposed<'T>(matrix : 'T[][]) : 'T[][] { - let rowCount = Length(matrix); - Fact(rowCount > 0, "Matrix must have at least 1 row"); - let columnCount = Length(Head(matrix)); - Fact(columnCount > 0, "Matrix must have at least 1 column"); - Fact(IsRectangularArray(matrix), "Matrix is not a rectangular array"); - mutable transposed = []; - for columnIndex in 0..columnCount - 1 { - mutable newRow = []; - for rowIndex in 0..rowCount - 1 { - set newRow += [matrix[rowIndex][columnIndex]]; - } - set transposed += [newRow]; - } - transposed - } - - /// # Summary - /// Returns the last element of the array. - /// - /// # Type Parameters - /// ## 'A - /// The type of the array elements. - /// - /// # Input - /// ## array - /// Array of which the last element is taken. Array must have at least 1 element. - /// - /// # Output - /// The last element of the array. - function Tail<'A>(array : 'A[]) : 'A { - let size = Length(array); - Fact(size > 0, "Array must have at least 1 element"); - array[size - 1] - } - - /// # Summary - /// Given an array of 2-tuples, returns a tuple of two arrays, each containing - /// the elements of the tuples of the input array. - /// - /// # Type Parameters - /// ## 'T - /// The type of the first element in each tuple. - /// ## 'U - /// The type of the second element in each tuple. - /// - /// # Input - /// ## array - /// An array containing 2-tuples. - /// - /// # Output - /// Two arrays, the first one containing all first elements of the input - /// tuples, the second one containing all second elements of the input tuples. - /// - /// # Example - /// ```qsharp - /// // split is same as ([5, 4, 3, 2, 1], [true, false, true, true, false]) - /// let split = Unzipped([(5, true), (4, false), (3, true), (2, true), (1, false)]); - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.Zipped - function Unzipped<'T, 'U>(array : ('T, 'U)[]) : ('T[], 'U[]) { - mutable first = []; - mutable second = []; - for index in 0..Length(array) - 1 { - let (left, right) = array[index]; - set first += [left]; - set second += [right]; - } - return (first, second); - } - - /// # Summary - /// Given a predicate and an array, returns the indices of that - /// array where the predicate is true. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## predicate - /// A function from `'T` to Boolean that is used to filter elements. - /// ## array - /// An array of elements over `'T`. - /// - /// # Output - /// An array of indices where `predicate` is true. - function Where<'T>(predicate : ('T -> Bool), array : 'T[]) : Int[] { - mutable indexes = []; - for index in 0..Length(array) - 1 { - if predicate(array[index]) { - set indexes += [index]; - } - } - indexes - } - - /// # Summary - /// Returns all consecutive subarrays of length `size`. - /// - /// # Description - /// This function returns all `n - size + 1` subarrays of - /// length `size` in order, where `n` is the length of `array`. - /// The first subarrays are `array[0..size - 1], array[1..size], array[2..size + 1]` - /// until the last subarray `array[n - size..n - 1]`. - /// - /// # Type Parameters - /// ## 'T - /// The type of `array` elements. - /// - /// # Input - /// ## size - /// Length of the subarrays. - /// - /// ## array - /// An array of elements. - /// - /// # Example - /// ```qsharp - /// // same as [[1, 2, 3], [2, 3, 4], [3, 4, 5]] - /// let windows = Windows(3, [1, 2, 3, 4, 5]); - /// ``` - /// - /// # Remarks - /// The size of the window must be a positive integer no greater than the size of the array - function Windows<'T>(size : Int, array : 'T[]) : 'T[][] { - let arrayLength = Length(array); - Fact( - size > 0 or size <= arrayLength, - "The size of the window must be a positive integer no greater than the size of the array" - ); - - mutable windows = []; - for index in 0..arrayLength - size { - set windows += [array[index..index + size - 1]]; - } - windows - } - - /// # Summary - /// Given two arrays, returns a new array of pairs such that each pair - /// contains an element from each original array. - /// - /// # Type Parameters - /// ## 'T - /// The type of the left array elements. - /// ## 'U - /// The type of the right array elements. - /// - /// # Input - /// ## left - /// An array containing values for the first element of each tuple. - /// ## right - /// An array containing values for the second element of each tuple. - /// - /// # Output - /// An array containing pairs of the form `(left[index], right[index])` for - /// each `index`. If the two arrays are not of equal length, the output will - /// be as long as the shorter of the inputs. - /// - /// # Example - /// ```qsharp - /// let left = [1, 3, 71]; - /// let right = [false, true]; - /// let pairs = Zipped(left, right); // [(1, false), (3, true)] - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Arrays.Unzipped - function Zipped<'T, 'U>(left : 'T[], right : 'U[]) : ('T, 'U)[] { - let arrayLength = MinI(Length(left), Length(right)); - mutable zipped = []; - for index in 0..arrayLength - 1 { - set zipped += [(left[index], right[index])]; - } - zipped - } - - export All, Any, Chunks, CircularlyShifted, ColumnAt, Count, Diagonal, DrawMany, Enumerated, Excluding, Filtered, FlatMapped, Flattened, Fold, ForEach, Head, HeadAndRest, IndexOf, IndexRange, Interleaved, IsEmpty, IsRectangularArray, IsSorted, IsSquareArray, Mapped, MappedByIndex, MappedOverRange, Most, MostAndTail, Padded, Partitioned, Rest, Reversed, SequenceI, SequenceL, Sorted, Subarray, Swapped, Transposed, Tail, Unzipped, Where, Windows, Zipped; -} diff --git a/library/std/src/canon.qs b/library/std/src/canon.qs deleted file mode 100644 index 3f8ed05f24..0000000000 --- a/library/std/src/canon.qs +++ /dev/null @@ -1,633 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Canon { - open QIR.Intrinsic; - open QIR.Runtime; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - - /// # Summary - /// Applies an operation to each element in a register. - /// - /// # Input - /// ## singleElementOperation - /// Operation to apply to each element. - /// ## register - /// Array of elements on which to apply the given operation. - /// - /// # Type Parameters - /// ## 'T - /// The target on which the operation acts. - /// - /// # Example - /// Prepare a three-qubit |+⟩ state: - /// ```qsharp - /// use register = Qubit[3]; - /// ApplyToEach(H, register); - /// ``` - operation ApplyToEach<'T>(singleElementOperation : ('T => Unit), register : 'T[]) : Unit { - for item in register { - singleElementOperation(item); - } - } - - /// # Summary - /// Applies an operation to each element in a register. - /// The modifier `A` indicates that the single-element operation is adjointable. - /// - /// # Input - /// ## singleElementOperation - /// Operation to apply to each element. - /// ## register - /// Array of elements on which to apply the given operation. - /// - /// # Type Parameters - /// ## 'T - /// The target on which the operation acts. - /// - /// # Example - /// Prepare a three-qubit |+⟩ state: - /// ```qsharp - /// use register = Qubit[3]; - /// ApplyToEach(H, register); - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Canon.ApplyToEach - operation ApplyToEachA<'T>(singleElementOperation : ('T => Unit is Adj), register : 'T[]) : Unit is Adj { - for item in register { - singleElementOperation(item); - } - } - - /// # Summary - /// Applies an operation to each element in a register. - /// The modifier `C` indicates that the single-element operation is controllable. - /// - /// # Input - /// ## singleElementOperation - /// Operation to apply to each element. - /// ## register - /// Array of elements on which to apply the given operation. - /// - /// # Type Parameters - /// ## 'T - /// The target on which the operation acts. - /// - /// # Example - /// Prepare a three-qubit |+⟩ state: - /// ```qsharp - /// use register = Qubit[3]; - /// ApplyToEach(H, register); - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Canon.ApplyToEach - operation ApplyToEachC<'T>(singleElementOperation : ('T => Unit is Ctl), register : 'T[]) : Unit is Ctl { - for item in register { - singleElementOperation(item); - } - } - - /// # Summary - /// Applies an operation to each element in a register. - /// The modifier `CA` indicates that the single-element operation is controllable and adjointable. - /// - /// # Input - /// ## singleElementOperation - /// Operation to apply to each element. - /// ## register - /// Array of elements on which to apply the given operation. - /// - /// # Type Parameters - /// ## 'T - /// The target on which the operation acts. - /// - /// # Example - /// Prepare a three-qubit |+⟩ state: - /// ```qsharp - /// use register = Qubit[3]; - /// ApplyToEach(H, register); - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Canon.ApplyToEach - operation ApplyToEachCA<'T>(singleElementOperation : ('T => Unit is Adj + Ctl), register : 'T[]) : Unit is Adj + Ctl { - for item in register { - singleElementOperation(item); - } - } - - /// # Summary - /// Applies the controlled-X (CX) gate to a pair of qubits. - /// - /// # Input - /// ## control - /// Control qubit for the CX gate. - /// ## target - /// Target qubit for the CX gate. - /// - /// # Remarks - /// This operation can be simulated by the unitary matrix - /// $$ - /// \begin{align} - /// \left(\begin{matrix} - /// 1 & 0 & 0 & 0 \\\\ - /// 0 & 1 & 0 & 0 \\\\ - /// 0 & 0 & 0 & 1 \\\\ - /// 0 & 0 & 1 & 0 - /// \end{matrix}\right) - /// \end{align}, - /// $$ - /// where rows and columns are organized as in the quantum concepts guide. - /// - /// Equivalent to: - /// ```qsharp - /// Controlled X([control], target); - /// ``` - /// and to: - /// ```qsharp - /// CNOT(control, target); - /// ``` - operation CX(control : Qubit, target : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__cx__body(control, target); - } - controlled (ctls, ...) { - Controlled X(ctls + [control], target); - } - adjoint self; - } - - /// # Summary - /// Applies the controlled-Y (CY) gate to a pair of qubits. - /// - /// # Input - /// ## control - /// Control qubit for the CY gate. - /// ## target - /// Target qubit for the CY gate. - /// - /// # Remarks - /// This operation can be simulated by the unitary matrix - /// $$ - /// \begin{align} - /// \left(\begin{matrix} - /// 1 & 0 & 0 & 0 \\\\ - /// 0 & 1 & 0 & 0 \\\\ - /// 0 & 0 & 0 & -i \\\\ - /// 0 & 0 & i & 0 - /// \end{matrix}\right) - /// \end{align}, - /// $$ - /// where rows and columns are organized as in the quantum concepts guide. - /// - /// Equivalent to: - /// ```qsharp - /// Controlled Y([control], target); - /// ``` - operation CY(control : Qubit, target : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__cy__body(control, target); - } - controlled (ctls, ...) { - Controlled Y(ctls + [control], target); - } - adjoint self; - } - - /// # Summary - /// Applies the controlled-Z (CZ) gate to a pair of qubits. - /// - /// # Input - /// ## control - /// Control qubit for the CZ gate. - /// ## target - /// Target qubit for the CZ gate. - /// - /// # Remarks - /// This operation can be simulated by the unitary matrix - /// $$ - /// \begin{align} - /// \left(\begin{matrix} - /// 1 & 0 & 0 & 0 \\\\ - /// 0 & 1 & 0 & 0 \\\\ - /// 0 & 0 & 1 & 0 \\\\ - /// 0 & 0 & 0 & -1 - /// \end{matrix}\right) - /// \end{align}, - /// $$ - /// where rows and columns are organized as in the quantum concepts guide. - /// - /// Equivalent to: - /// ```qsharp - /// Controlled Z([control], target); - /// ``` - operation CZ(control : Qubit, target : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__cz__body(control, target); - } - controlled (ctls, ...) { - Controlled Z(ctls + [control], target); - } - adjoint self; - } - - /// Given a pair, returns its first element. - function Fst<'T, 'U>(pair : ('T, 'U)) : 'T { - let (fst, _) = pair; - return fst; - } - - /// Given a pair, returns its second element. - function Snd<'T, 'U>(pair : ('T, 'U)) : 'U { - let (_, snd) = pair; - return snd; - } - - /// # Summary - /// Relabels the qubits in the `current` array with the qubits in the `updated` array. The `updated` array - /// must be a valid permutation of the `current` array. - /// - /// # Input - /// ## current - /// Array of qubits to be relabeled. - /// ## updated - /// Array of qubits with which to relabel the `current` array. - /// - /// # Remarks - /// This operation is useful when you need to relabel qubits in a way that does not incur any quantum operations. - /// Note that when compiling for execution on hardware with limited qubit connectivity, this operation - /// may not result in any changes to qubit adjacency and one or more `SWAP` gates may still be required. - /// - /// # Example - /// The following example demonstrates how to relabel qubits in a register: - /// ```qsharp - /// use qubits = Qubit[3]; - /// let newOrder = [qubits[2], qubits[0], qubits[1]]; - /// Relabel(qubits, newOrder); - /// ``` - /// After this operation, any use of `qubits[0]` will refer to the qubit that was originally `qubits[2]`, and so on. - /// To exchange the labels on two qubits, the virtual equivalent of a `SWAP` gate, you can use the following code: - /// ```qsharp - /// use (q0, q1) = (Qubit(), Qubit()); - /// Relabel([q0, q1], [q1, q0]); - /// ``` - /// 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; - } - - /// # Summary - /// Computes the parity of a register of qubits in-place. - /// - /// # Input - /// ## qubits - /// Array of qubits whose parity is to be computed and stored. - /// - /// # Remarks - /// This operation transforms the state of its input as - /// $$ - /// \begin{align} - /// \ket{q_0} \ket{q_1} \cdots \ket{q_{n - 1}} & \mapsto - /// \ket{q_0} \ket{q_0 \oplus q_1} \ket{q_0 \oplus q_1 \oplus q_2} \cdots - /// \ket{q_0 \oplus \cdots \oplus q_{n - 1}}. - /// \end{align} - /// $$ - operation ApplyCNOTChain(qubits : Qubit[]) : Unit is Adj + Ctl { - for i in 0..Length(qubits) - 2 { - CNOT(qubits[i], qubits[i + 1]); - } - } - - /// # Summary - /// Given a single-qubit Pauli operator, applies the corresponding operation - /// to a single qubit. - /// - /// # Input - /// ## pauli - /// The Pauli operator to be applied. - /// ## target - /// The qubit to which `pauli` is to be applied as an operation. - /// - /// # Example - /// The following are equivalent: - /// ```qsharp - /// ApplyP(PauliX, q); - /// ``` - /// and - /// ```qsharp - /// X(q); - /// ``` - operation ApplyP(pauli : Pauli, target : Qubit) : Unit is Adj + Ctl { - if pauli == PauliX { X(target); } elif pauli == PauliY { Y(target); } elif pauli == PauliZ { Z(target); } - } - - /// # Summary - /// Given a multi-qubit Pauli operator, applies the corresponding operation - /// to a quantum register. - /// - /// # Input - /// ## pauli - /// A multi-qubit Pauli operator represented as an array of single-qubit Pauli operators. - /// ## target - /// Register to apply the given Pauli operation on. - /// - /// # Example - /// The following are equivalent: - /// ```qsharp - /// ApplyPauli([PauliY, PauliZ, PauliX], target); - /// ``` - /// and - /// ```qsharp - /// Y(target[0]); - /// Z(target[1]); - /// X(target[2]); - /// ``` - operation ApplyPauli(pauli : Pauli[], target : Qubit[]) : Unit is Adj + Ctl { - Fact(Length(pauli) == Length(target), "`pauli` and `target` must be of the same length."); - for i in 0..Length(pauli) - 1 { - ApplyP(pauli[i], target[i]); - } - } - - /// # Summary - /// Applies a Pauli operator on each qubit in an array if the corresponding - /// bit of a Boolean array matches a given input. - /// - /// # Input - /// ## pauli - /// Pauli operator to apply to `qubits[idx]` where `bitApply == bits[idx]` - /// ## bitApply - /// apply Pauli if bit is this value - /// ## bits - /// Boolean register specifying which corresponding qubit in `qubits` should be operated on - /// ## qubits - /// Quantum register on which to selectively apply the specified Pauli operator - /// - /// # Remarks - /// The Boolean array and the quantum register must be of equal length. - /// - /// # Example - /// The following applies an X operation on qubits 0 and 2, and a Z operation on qubits 1 and 3. - /// ```qsharp - /// use qubits = Qubit[4]; - /// let bits = [true, false, true, false]; - /// // Apply when index in `bits` is `true`. - /// ApplyPauliFromBitString(PauliX, true, bits, qubits); - /// // Apply when index in `bits` is `false`. - /// ApplyPauliFromBitString(PauliZ, false, bits, qubits); - /// ``` - operation ApplyPauliFromBitString(pauli : Pauli, bitApply : Bool, bits : Bool[], qubits : Qubit[]) : Unit is Adj + Ctl { - let nBits = Length(bits); - Fact(nBits == Length(qubits), "Number of bits must be equal to number of qubits."); - for i in 0..nBits - 1 { - if bits[i] == bitApply { - ApplyP(pauli, qubits[i]); - } - } - } - - /// # Summary - /// Applies a Pauli operator on each qubit in an array if the corresponding - /// bit of a Little-endian integer matches a given input. - /// - /// # Input - /// ## pauli - /// Pauli operator to apply to `qubits[idx]` when bit of numberState - /// in idx position is the same as bitApply. - /// ## bitApply - /// apply Pauli if bit is this value - /// ## numberState - /// Little-endian integer specifying which corresponding qubit in `qubits` should be operated on - /// ## qubits - /// Quantum register on which to selectively apply the specified Pauli operator - /// - /// # Example - /// The following applies an X operation on qubits 0 and 2, and a Z operation on qubits 1 and 3. - /// ```qsharp - /// use qubits = Qubit[4]; - /// let n = 5; - /// // Apply when index in `bits` is `true`. - /// ApplyPauliFromBitString(PauliX, true, n, qubits); - /// // Apply when index in `bits` is `false`. - /// ApplyPauliFromBitString(PauliZ, false, n, qubits); - /// ``` - operation ApplyPauliFromInt( - pauli : Pauli, - bitApply : Bool, - numberState : Int, - qubits : Qubit[] - ) : Unit is Adj + Ctl { - - let length = Length(qubits); - Fact(numberState >= 0, "number must be non-negative"); - Fact(BitSizeI(numberState) <= length, "Bit size of numberState must not exceed qubits length"); - - for i in 0..length - 1 { - // If we assume loop unrolling, 2^i will be optimized to a constant. - if ((numberState &&& (1 <<< i)) != 0) == bitApply { - ApplyP(pauli, qubits[i]); - } - } - } - - /// # Summary - /// Applies a unitary operation on the target if the control - /// register state corresponds to a specified nonnegative integer. - /// - /// # Input - /// ## numberState - /// A nonnegative integer on which the operation `oracle` should be - /// controlled. - /// ## oracle - /// A unitary operation to be controlled. - /// ## target - /// A target on which to apply `oracle`. - /// ## controlRegister - /// A quantum register that controls application of `oracle`. - /// - /// # Remarks - /// The value of `numberState` is interpreted using a little-endian encoding. - /// - /// `numberState` must be at most $2^\texttt{Length(controlRegister)} - 1$. - /// For example, `numberState = 537` means that `oracle` - /// is applied if and only if `controlRegister` is in the state $\ket{537}$. - operation ApplyControlledOnInt<'T>( - numberState : Int, - oracle : ('T => Unit is Adj + Ctl), - controlRegister : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - within { - ApplyPauliFromInt(PauliX, false, numberState, controlRegister); - } apply { - Controlled oracle(controlRegister, target); - } - } - - /// # Summary - /// Applies `oracle` on `target` when `controlRegister` - /// is in the state specified by `bits`. - /// - /// # Description - /// Applies a unitary operation `oracle` on the `target`, controlled - /// on a state specified by a given bit mask `bits`. - /// The bit at `bits[i]` corresponds to qubit at `controlRegister[i]`. - /// The pattern given by `bits` may be shorter than `controlRegister`, - /// in which case additional control qubits are ignored (that is, neither - /// controlled on |0⟩ nor |1⟩). - /// If `bits` is longer than `controlRegister`, an error is raised. - /// - /// # Input - /// ## bits - /// The bit string to control the given unitary operation on. - /// ## oracle - /// The unitary operation to be applied on the target. - /// ## target - /// The target to be passed to `oracle` as an input. - /// ## controlRegister - /// A quantum register that controls application of `oracle`. - /// - /// # Example - /// ```qsharp - /// // When bits = [1,0,0] oracle is applied if and only if controlRegister - /// // is in the state |100⟩. - /// use t = Qubit(); - /// use c = Qubit[3]; - /// X(c[0]); - /// ApplyControlledOnBitString([true, false, false], X, c, t); - /// Message($"{M(t)}"); // Prints `One` since oracle `X` was applied. - /// ``` - operation ApplyControlledOnBitString<'T>( - bits : Bool[], - oracle : ('T => Unit is Adj + Ctl), - controlRegister : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - // The control register must have enough bits to implement the requested control. - Fact(Length(bits) <= Length(controlRegister), "Control register shorter than control pattern."); - - // Use a subregister of the controlled register when - // bits is shorter than controlRegister. - let controlSubregister = controlRegister[...Length(bits) - 1]; - within { - ApplyPauliFromBitString(PauliX, false, bits, controlSubregister); - } apply { - Controlled oracle(controlSubregister, target); - } - } - - /// # Summary - /// Applies the rotations of Quantum Fourier Transform (QFT) to a little-endian quantum register. - /// - /// # Description - /// Applies the rotations of QFT to a little-endian register `qs` of length n - /// containing |x₁⟩⊗|x₂⟩⊗…⊗|xₙ⟩. The qs[0] initially contains the - /// least significant bit xₙ. The state of qs[0] becomes - /// (|0⟩+𝑒^(2π𝑖[0.xₙ])|1⟩)/sqrt(2) after the operation. - /// - /// # Input - /// ## qs - /// Quantum register in a little-endian format to which the rotations are applied. - /// - /// # Remarks - /// Note that this operation applies only the rotations part of the QFT. - /// To complete the transform, you need to reverse the order of qubits after this operation, - /// for example, using the operation `SwapReverseRegister`. - /// - /// # Reference - /// - [Quantum Fourier transform](https://en.wikipedia.org/wiki/Quantum_Fourier_transform) - operation ApplyQFT(qs : Qubit[]) : Unit is Adj + Ctl { - let length = Length(qs); - Fact(length >= 1, "ApplyQFT: Length(qs) must be at least 1."); - for i in length - 1..-1..0 { - H(qs[i]); - for j in 0..i - 1 { - Controlled R1Frac([qs[i]], (1, j + 1, qs[i - j - 1])); - } - } - } - - /// # Summary - /// Uses SWAP gates to reverse the order of the qubits in a register. - /// - /// # Input - /// ## register - /// The qubits order of which should be reversed using SWAP gates - operation SwapReverseRegister(register : Qubit[]) : Unit is Adj + Ctl { - let length = Length(register); - for i in 0..length / 2 - 1 { - SWAP(register[i], register[(length - i) - 1]); - } - } - - /// # Summary - /// Applies a bitwise-XOR operation between a classical integer and an - /// integer represented by a register of qubits. - /// - /// # Description - /// Applies `X` operations to qubits in a little-endian register based on - /// 1 bits in an integer. - /// - /// Let us denote `value` by a and let y be an unsigned integer encoded in `target`, - /// then `ApplyXorInPlace` performs an operation given by the following map: - /// |y⟩ ↦ |y ⊕ a⟩, where ⊕ is the bitwise exclusive OR operator. - operation ApplyXorInPlace(value : Int, target : Qubit[]) : Unit is Adj + Ctl { - body (...) { - Fact(value >= 0, "`value` must be non-negative."); - mutable runningValue = value; - for q in target { - if (runningValue &&& 1) != 0 { - X(q); - } - set runningValue >>>= 1; - } - Fact(runningValue == 0, "value is too large"); - } - adjoint self; - } - - /// # Summary - /// Applies a bitwise-XOR operation between a classical integer and an - /// integer represented by a register of qubits. - /// - /// # Description - /// Applies `X` operations to qubits in a little-endian register based on - /// 1 bits in an integer. - /// - /// Let us denote `value` by a and let y be an unsigned integer encoded in `target`, - /// then `ApplyXorInPlace` performs an operation given by the following map: - /// |y⟩ ↦ |y ⊕ a⟩, where ⊕ is the bitwise exclusive OR operator. - operation ApplyXorInPlaceL(value : BigInt, target : Qubit[]) : Unit is Adj + Ctl { - body (...) { - Fact(value >= 0L, "`value` must be non-negative."); - mutable runningValue = value; - for q in target { - if (runningValue &&& 1L) != 0L { - X(q); - } - set runningValue >>>= 1; - } - Fact(runningValue == 0L, "`value` is too large."); - } - adjoint self; - } - - export ApplyToEach, ApplyToEachA, ApplyToEachC, ApplyToEachCA, CX, CY, CZ, Fst, Snd, Relabel, ApplyCNOTChain, ApplyP, ApplyPauli, ApplyPauliFromBitString, ApplyPauliFromInt, ApplyControlledOnInt, ApplyControlledOnBitString, ApplyQFT, SwapReverseRegister, ApplyXorInPlace, ApplyXorInPlaceL; - -} diff --git a/library/std/src/convert.qs b/library/std/src/convert.qs deleted file mode 100644 index 84bdfbf3e0..0000000000 --- a/library/std/src/convert.qs +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Convert { - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - - /// # Summary - /// Converts a given integer `number` to an equivalent - /// double-precision floating-point number. - /// - /// # Description - /// Converts a given integer to a double-precision floating point number. - /// Please note that the double-precision representation may have fewer - /// bits allocated to represent [significant digits](https://en.wikipedia.org/wiki/Significand) - /// so the conversion may be approximate for large numbers. For example, - /// the current simulator converts 4,611,686,018,427,387,919 = 2^64+15 - /// to 4,611,686,018,427,387,904.0 = 2^64. - /// - /// # Example - /// ```qsharp - /// Message($"{IntAsDouble(1)}"); // Prints 1.0 rather than 1 - /// ``` - function IntAsDouble(number : Int) : Double { - body intrinsic; - } - - /// # Summary - /// Converts a given integer `number` to an equivalent big integer. - function IntAsBigInt(number : Int) : BigInt { - body intrinsic; - } - - /// # Summary - /// Converts a `Result` type to a `Bool` type, where `One` is mapped to - /// `true` and `Zero` is mapped to `false`. - /// - /// # Input - /// ## input - /// `Result` to be converted. - /// - /// # Output - /// A `Bool` representing the `input`. - function ResultAsBool(input : Result) : Bool { - input == One - } - - /// # Summary - /// Converts a `Bool` type to a `Result` type, where `true` is mapped to - /// `One` and `false` is mapped to `Zero`. - /// - /// # Input - /// ## input - /// `Bool` to be converted. - /// - /// # Output - /// A `Result` representing the `input`. - function BoolAsResult(input : Bool) : Result { - if input { One } else { Zero } - } - - /// # Summary - /// Produces a non-negative integer from a string of bits in little-endian format. - /// `bits[0]` represents the least significant bit. - /// - /// # Input - /// ## bits - /// Bits in binary representation of number. - function BoolArrayAsInt(bits : Bool[]) : Int { - let nBits = Length(bits); - Fact(nBits < 64, $"`Length(bits)` must be less than 64, but was {nBits}."); - - mutable number = 0; - for i in 0..nBits - 1 { - if (bits[i]) { - set number |||= 1 <<< i; - } - } - - number - } - - /// # Summary - /// Produces a binary representation of a non-negative integer, using the - /// little-endian representation for the returned array. - /// - /// # Input - /// ## number - /// A non-negative integer to be converted to an array of Boolean values. - /// ## bits - /// The number of bits in the binary representation of `number`. - /// - /// # Output - /// An array of Boolean values representing `number`. - /// - /// # Remarks - /// The input `bits` must be non-negative. - /// The input `number` must be between 0 and 2^bits - 1. - function IntAsBoolArray(number : Int, bits : Int) : Bool[] { - Fact(bits >= 0, "Requested number of bits must be non-negative."); - Fact(number >= 0, "Number must be non-negative."); - mutable runningValue = number; - mutable result = []; - for _ in 1..bits { - set result += [(runningValue &&& 1) != 0]; - set runningValue >>>= 1; - } - Fact(runningValue == 0, "`number` is too large to fit into array of length `bits`."); - - result - } - - /// # Summary - /// Converts an array of Boolean values into a non-negative BigInt, interpreting the - /// array as a binary representation in little-endian format. - /// - /// # Input - /// ## boolArray - /// An array of Boolean values representing the binary digits of a BigInt. - /// - /// # Output - /// A BigInt represented by `boolArray`. - /// - /// # Remarks - /// The function interprets the array in little-endian format, where the first - /// element of the array represents the least significant bit. - /// The input `boolArray` should not be empty. - function BoolArrayAsBigInt(boolArray : Bool[]) : BigInt { - mutable result = 0L; - for i in 0..Length(boolArray) - 1 { - if boolArray[i] { - set result += 1L <<< i; - } - } - - result - } - - /// # Summary - /// Produces a binary representation of a non-negative BigInt, using the - /// little-endian representation for the returned array. - /// - /// # Input - /// ## number - /// A non-negative BigInt to be converted to an array of Boolean values. - /// ## bits - /// The number of bits in the binary representation of `number`. - /// - /// # Output - /// An array of Boolean values representing `number`. - /// - /// # Remarks - /// The input `bits` must be non-negative. - /// The input `number` must be between 0 and 2^bits - 1. - function BigIntAsBoolArray(number : BigInt, bits : Int) : Bool[] { - Fact(bits >= 0, "Requested number of bits must be non-negative."); - Fact(number >= 0L, "Number must be non-negative."); - mutable runningValue = number; - mutable result = []; - for _ in 1..bits { - set result += [(runningValue &&& 1L) != 0L]; - set runningValue >>>= 1; - } - Fact(runningValue == 0L, $"`number`={number} is too large to fit into {bits} bits."); - - result - } - - /// # Summary - /// Produces a non-negative integer from a string of Results in little-endian format. - /// - /// # Input - /// ## results - /// Results in binary representation of number. - /// - /// # Output - /// A non-negative integer - /// - /// # Example - /// ```qsharp - /// // The following returns 1 - /// let int1 = ResultArrayAsInt([One,Zero]) - /// ``` - function ResultArrayAsInt(results : Result[]) : Int { - let nBits = Length(results); - Fact(nBits < 64, $"`Length(bits)` must be less than 64, but was {nBits}."); - - mutable number = 0; - for idxBit in 0..nBits - 1 { - if (results[idxBit] == One) { - set number |||= 1 <<< idxBit; - } - } - - number - } - - /// # Summary - /// Converts a `Result[]` type to a `Bool[]` type, where `One` - /// is mapped to `true` and `Zero` is mapped to `false`. - /// - /// # Input - /// ## input - /// `Result[]` to be converted. - /// - /// # Output - /// A `Bool[]` representing the `input`. - function ResultArrayAsBoolArray(input : Result[]) : Bool[] { - mutable output = []; - for r in input { - set output += [r == One]; - } - - output - } - - /// # Summary - /// Converts a `Bool[]` type to a `Result[]` type, where `true` - /// is mapped to `One` and `false` is mapped to `Zero`. - /// - /// # Input - /// ## input - /// `Bool[]` to be converted. - /// - /// # Output - /// A `Result[]` representing the `input`. - function BoolArrayAsResultArray(input : Bool[]) : Result[] { - mutable output = []; - for b in input { - set output += [if b { One } else { Zero }]; - } - - output - } - - /// # Summary - /// Converts a complex number of type `Complex` to a complex - /// number of type `ComplexPolar`. - /// - /// # Input - /// ## input - /// Complex number c = x + y𝑖. - /// - /// # Output - /// Complex number c = r⋅e^(t𝑖). - function ComplexAsComplexPolar(input : Complex) : ComplexPolar { - return ComplexPolar(AbsComplex(input), ArgComplex(input)); - } - - /// # Summary - /// Converts a complex number of type `ComplexPolar` to a complex - /// number of type `Complex`. - /// - /// # Input - /// ## input - /// Complex number c = r⋅e^(t𝑖). - /// - /// # Output - /// Complex number c = x + y𝑖. - function ComplexPolarAsComplex(input : ComplexPolar) : Complex { - return Complex( - input.Magnitude * Cos(input.Argument), - input.Magnitude * Sin(input.Argument) - ); - } - - /// # Summary - /// Converts a given double-precision floating-point number to a string representation with desired precision, rounding if required. - /// - /// # Input - /// ## input - /// Double to be converted. - /// ## precision - /// Non-negative number of digits after the decimal point. - /// - /// # Example - /// ```qsharp - /// Message($"{DoubleAsStringWithPrecision(0.354, 2)}"); // Prints 0.35 - /// Message($"{DoubleAsStringWithPrecision(0.485, 1)}"); // Prints 0.5 - /// Message($"{DoubleAsStringWithPrecision(5.6, 4)}"); // Prints 5.6000 - /// Message($"{DoubleAsStringWithPrecision(2.268, 0)}"); // Prints 2 - /// ``` - function DoubleAsStringWithPrecision(input : Double, precision : Int) : String { - body intrinsic; - } - - export IntAsDouble, IntAsBigInt, ResultAsBool, BoolAsResult, BoolArrayAsInt, IntAsBoolArray, BoolArrayAsBigInt, BigIntAsBoolArray, ResultArrayAsInt, ResultArrayAsBoolArray, BoolArrayAsResultArray, ComplexAsComplexPolar, ComplexPolarAsComplex, DoubleAsStringWithPrecision; -} diff --git a/library/std/src/diagnostics.qs b/library/std/src/diagnostics.qs deleted file mode 100644 index 452a0bd7f0..0000000000 --- a/library/std/src/diagnostics.qs +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Diagnostics { - open QIR.Intrinsic; - - /// # Summary - /// Dumps the current target machine's status. - /// - /// # Description - /// This method allows you to dump information about the current quantum state. - /// The actual information generated and the semantics are specific to each target machine. - /// - /// For the local sparse-state simulator distributed as part of the - /// Quantum Development Kit, this method will write the wave function as a - /// one-dimensional array of pairs of state indices and complex numbers, in which each element represents - /// the amplitudes of the probability of measuring the corresponding state. - /// - /// # Example - /// When run on the sparse-state simulator, the following snippet dumps - /// the Bell state (|00⟩ + |11⟩ ) / √2 to the console: - /// ```qsharp - /// use left = Qubit(); - /// use right = Qubit(); - /// within { - /// H(left); - /// CNOT(left, right); - /// } apply { - /// DumpMachine(); - /// } - /// ``` - function DumpMachine() : Unit { - body intrinsic; - } - - /// # Summary - /// Dumps the current target machine's status associated with the given qubits. - /// - /// # Input - /// ## qubits - /// The list of qubits to report. - /// - /// # Remarks - /// This method allows you to dump the information associated with the state of the - /// given qubits. - /// - /// For the local sparse-state simulator distributed as part of the - /// Quantum Development Kit, this method will write the - /// state of the given qubits (i.e. the wave function of the corresponding subsystem) as a - /// one-dimensional array of pairs of state indices and complex numbers, in which each element represents - /// the amplitudes of the probability of measuring the corresponding state. - /// If the given qubits are entangled with some other qubit and their - /// state can't be separated, it fails with a runtime error indicating that the qubits are entangled. - /// - /// # Example - /// When run on the sparse-state simulator, the following snippet dumps - /// the Bell state (|00⟩ + |11⟩ ) / √2 to the console: - /// ```qsharp - /// use left = Qubit(); - /// use right = Qubit(); - /// within { - /// H(left); - /// CNOT(left, right); - /// } apply { - /// DumpRegister([left, right]); - /// } - /// ``` - function DumpRegister(register : Qubit[]) : Unit { - body intrinsic; - } - - /// # Summary - /// Checks whether a qubit is in the |0⟩ state, returning true if it is. - /// - /// # Description - /// This operation checks whether a qubit is in the |0⟩ state. It will return true only - /// if the qubit is deterministically in the |0⟩ state, and will return false otherwise. This operation - /// does not change the state of the qubit. - /// - /// # Input - /// ## qubit - /// The qubit to check. - /// # Output - /// True if the qubit is in the |0⟩ state, false otherwise. - /// - /// # Remarks - /// This operation is useful for checking whether a qubit is in the |0⟩ state during simulation. It is not possible to check - /// this on hardware without measuring the qubit, which could change the state. - @Config(Unrestricted) - operation CheckZero(qubit : Qubit) : Bool { - body intrinsic; - } - - /// # Summary - /// Checks whether all qubits in the provided array are in the |0⟩ state. Returns true if they are. - /// - /// # Description - /// This operation checks whether all qubits in the provided array are in the |0⟩ state. It will return true only - /// if all qubits are deterministically in the |0⟩ state, and will return false otherwise. This operation - /// does not change the state of the qubits. - /// - /// # Input - /// ## qubits - /// The qubits to check. - /// # Output - /// True if all qubits are in the |0⟩ state, false otherwise. - /// - /// # Remarks - /// This operation is useful for checking whether a qubit is in the |0⟩ state during simulation. It is not possible to check - /// this on hardware without measuring the qubit, which could change the state. - @Config(Unrestricted) - operation CheckAllZero(qubits : Qubit[]) : Bool { - for q in qubits { - if not CheckZero(q) { - return false; - } - } - - return true; - } - - /// # Summary - /// Checks whether a given condition is true, failing with a message if it is not. - /// - /// # Description - /// This function checks whether a given condition is true. If the condition is false, the operation fails with the given message, - /// terminating the program. - /// - /// # Input - /// ## actual - /// The condition to check. - /// ## message - /// The message to use in the failure if the condition is false. - function Fact(actual : Bool, message : String) : Unit { - if (not actual) { - fail message; - } - } - - /// # Summary - /// Given two operations, checks that they act identically for all input states. - /// - /// # Description - /// This check is implemented by using the Choi–Jamiołkowski isomorphism to reduce - /// this check to a check on two entangled registers. - /// Thus, this operation needs only a single call to each operation being tested, - /// but requires twice as many qubits to be allocated. - /// This check can be used to ensure, for instance, that an optimized version of an - /// operation acts identically to its naïve implementation, or that an operation - /// which acts on a range of non-quantum inputs agrees with known cases. - /// - /// # Remarks - /// This operation requires that the operation modeling the expected behavior is - /// adjointable, so that the inverse can be performed on the target register alone. - /// Formally, one can specify a transpose operation, which relaxes this requirement, - /// but the transpose operation is not in general physically realizable for arbitrary - /// quantum operations and thus is not included here as an option. - /// - /// # Input - /// ## nQubits - /// Number of qubits to pass to each operation. - /// ## actual - /// Operation to be tested. - /// ## expected - /// Operation defining the expected behavior for the operation under test. - /// # Output - /// True if operations are equal, false otherwise. - @Config(Unrestricted) - operation CheckOperationsAreEqual( - nQubits : Int, - actual : (Qubit[] => Unit), - expected : (Qubit[] => Unit is Adj) - ) : Bool { - - // Prepare a reference register entangled with the target register. - use reference = Qubit[nQubits]; - use target = Qubit[nQubits]; - - // Apply operations. - within { - for i in 0..nQubits - 1 { - H(reference[i]); - CNOT(reference[i], target[i]); - } - } apply { - actual(target); - Adjoint expected(target); - } - - // Check and return result. - let areEqual = CheckAllZero(reference) and CheckAllZero(target); - ResetAll(target); - ResetAll(reference); - areEqual - } - - /// # Summary - /// Starts counting the number of times the given operation is called. Fails if the operation is already being counted. - /// - /// # Description - /// This operation allows you to count the number of times a given operation is called. If the given operation is already - /// being counted, calling `StartCountingOperation` again will trigger a runtime failure. Counting is based on the specific - /// specialization of the operation invoked, so `X` and `Adjoint X` are counted separately. - /// Likewise `Controlled X`, `CNOT`, and `CX` are independent operations that are counted separately, as are `Controlled X` - /// and `Controlled Adjoint X`. - /// - /// # Input - /// ## callable - /// The operation to be counted. - /// - /// # Remarks - /// Counting operation calls requires specific care in what operation is passed as input. For example, `StartCountingOperation(H)` will - /// count only the number of times `H` is called, while `StartCountingOperation(Adjoint H)` will count only the number of times `Adjoint H` is called, even - /// though `H` is self-adjoint. This is due to how the execution treats the invocation of these operations as distinct by their specialization. - /// In the same way, `StartCountingOperation(Controlled X)` will count only the number of times `Controlled X` is called, while - /// `StartCountingOperation(CNOT)` will count only the number of times `CNOT` is called. - /// - /// When counting lambdas, the symbol the lambda is bound to is used to identify the operation and it is counted as a separate operation. For example, - /// ```qsharp - /// let myOp = q => H(q); - /// StartCountingOperation(myOp); - /// ``` - /// Will count specifically calls to `myOp` and not `H`. By contrast, the following code will count calls to `H` itself: - /// ```qsharp - /// let myOp = H; - /// StartCountingOperation(myOp); - /// ``` - /// This is because this code does not define a lambda and instead just creates a binding to `H` directly. - @Config(Unrestricted) - operation StartCountingOperation<'In, 'Out>(callable : 'In => 'Out) : Unit { - body intrinsic; - } - - /// # Summary - /// Stops counting the number of times the given operation is called and returns the count. Fails - /// if the operation was not being counted. - /// - /// # Description - /// This operation allows you to stop counting the number of times a given operation is called and returns the count. - /// If the operation was not being counted, it triggers a runtime failure. - /// - /// # Input - /// ## callable - /// The operation whose count will be returned. - /// # Output - /// The number of times the operation was called since the last call to `StartCountingOperation`. - @Config(Unrestricted) - operation StopCountingOperation<'In, 'Out>(callable : 'In => 'Out) : Int { - body intrinsic; - } - - /// # Summary - /// Starts counting the number of times the given function is called. Fails if the function is already being counted. - /// - /// # Description - /// This operation allows you to count the number of times a given function is called. If the given function is already - /// being counted, calling `StartCountingFunction` again will trigger a runtime failure. - /// - /// # Input - /// ## callable - /// The function to be counted. - /// - /// # Remarks - /// When counting lambdas, the symbol the lambda is bound to is used to identify the function and it is counted as a separate function. For example, - /// ```qsharp - /// let myFunc = i -> AbsI(i); - /// StartCountingFunction(myFunc); - /// ``` - /// Will count specifically calls to `myFunc` and not `AbsI`. By contrast, the following code will count calls to `AbsI` itself: - /// ```qsharp - /// let myFunc = AbsI; - /// StartCountingFunction(myFunc); - /// ``` - /// This is because this code does not define a lambda and instead just creates a binding to `AbsI` directly. - @Config(Unrestricted) - operation StartCountingFunction<'In, 'Out>(callable : 'In -> 'Out) : Unit { - body intrinsic; - } - - /// # Summary - /// Stops counting the number of times the given function is called and returns the count. Fails - /// if the function was not being counted. - /// - /// # Description - /// This operation allows you to stop counting the number of times a given function is called and returns the count. - /// If the function was not being counted, it triggers a runtime failure. - /// - /// # Input - /// ## callable - /// The function whose count will be returned. - /// # Output - /// The number of times the function was called since the last call to `StartCountingFunction`. - @Config(Unrestricted) - operation StopCountingFunction<'In, 'Out>(callable : 'In -> 'Out) : Int { - body intrinsic; - } - - /// # Summary - /// Starts counting the number of qubits allocated. Fails if qubits are already being counted. - /// - /// # Description - /// This operation allows you to count the number of qubits allocated until `StopCountingQubits` is called. - /// The counter is incremented only when a new unique qubit is allocated, so reusing the same qubit multiple times - /// across separate allocations does not increment the counter. - /// - /// # Remarks - /// This operation is useful for tracking the number of unique qubits allocated in a given scope. Along with - /// `StopCountingQubits`, it can be used to verify that a given operation does not allocate more qubits than - /// expected. For example, - /// ```qsharp - /// StartCountingQubits(); - /// testOperation(); - /// let qubitsAllocated = StopCountingQubits(); - /// Fact(qubitsAllocated <= 4, "Operation should not allocate more than 4 qubits."); - /// ``` - @Config(Unrestricted) - operation StartCountingQubits() : Unit { - body intrinsic; - } - - /// # Summary - /// Stops counting the number of qubits allocated and returns the count. Fails if the qubits were not being counted. - /// - /// # Description - /// This operation allows you to stop counting the number of qubits allocated and returns the count since the - /// last call to `StartCountingQubits`. If the qubits were not being counted, it triggers a runtime failure. - /// - /// # Output - /// The number of unique qubits allocated since the last call to `StartCountingQubits`. - @Config(Unrestricted) - operation StopCountingQubits() : Int { - body intrinsic; - } - - export DumpMachine, DumpRegister, CheckZero, CheckAllZero, Fact, CheckOperationsAreEqual, StartCountingOperation, StopCountingOperation, StartCountingFunction, StopCountingFunction, StartCountingQubits, StopCountingQubits; -} diff --git a/library/std/src/internal.qs b/library/std/src/internal.qs deleted file mode 100644 index 72afb101b7..0000000000 --- a/library/std/src/internal.qs +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Intrinsic { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Core; - open Microsoft.Quantum.Math; - open QIR.Intrinsic; - - internal operation CH(control : Qubit, target : Qubit) : Unit is Adj { - within { - S(target); - H(target); - T(target); - } apply { - CNOT(control, target); - } - } - - internal operation CCH(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - within { - S(target); - H(target); - T(target); - } apply { - CCNOT(control1, control2, target); - } - } - - internal operation ApplyGlobalPhase(theta : Double) : Unit is Ctl + Adj { - body ... { - ControllableGlobalPhase(theta); - } - adjoint ... { - ControllableGlobalPhase(-theta); - } - } - - // Global phase is not relevant for physical systems, but controlled global phase is physical. We use - // the Rz gate to implement controlled global phase physically, and then correct for the extra global phase it - // introduces in simulation using additional calls to the simulation-only global phase intrinsic. - // We use a separate operation for this controlled case to avoid recursive calls to the same operation - // that can interfere with runtime capabilities analysis. - internal operation ControllableGlobalPhase(theta : Double) : Unit is Ctl { - body ... { - GlobalPhase([], theta); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - GlobalPhase([], theta); - } else { - Controlled Rz(ctls[1...], (theta, ctls[0])); - GlobalPhase(ctls[1...], theta / 2.0); - // With a single control qubit, the call to Rz uses no controls and global phase is corrected - // by just the call above. - // Multi-controlled Rz gates use a decomposition that introduces an additional global - // phase, so we need to correct for that here. - if Length(ctls) > 1 { - GlobalPhase([], -theta / 4.0); - } - } - } - } - - // Global phase intrinsic, which only has affect in simulation and is a no-op otherwise. - internal operation GlobalPhase(ctls : Qubit[], theta : Double) : Unit { - body intrinsic; - } - - internal operation CRz(control : Qubit, theta : Double, target : Qubit) : Unit is Adj { - Rz(theta / 2.0, target); - CNOT(control, target); - Rz(-theta / 2.0, target); - CNOT(control, target); - } - - internal operation CS(control : Qubit, target : Qubit) : Unit is Adj + Ctl { - T(control); - T(target); - CNOT(control, target); - Adjoint T(target); - CNOT(control, target); - } - - internal operation CT(control : Qubit, target : Qubit) : Unit is Adj { - let angle = PI() / 8.0; - Rz(angle, control); - Rz(angle, target); - CNOT(control, target); - Adjoint Rz(angle, target); - CNOT(control, target); - } - - internal operation MapPauli(qubit : Qubit, from : Pauli, to : Pauli) : Unit is Adj { - if from == to {} elif (from == PauliZ and to == PauliX) or (from == PauliX and to == PauliZ) { - H(qubit); - } elif from == PauliZ and to == PauliY { - H(qubit); - S(qubit); - H(qubit); - } elif from == PauliY and to == PauliZ { - H(qubit); - Adjoint S(qubit); - H(qubit); - } elif from == PauliY and to == PauliX { - S(qubit); - } elif from == PauliX and to == PauliY { - Adjoint S(qubit); - } else { - fail "Unsupported input"; - } - } - - internal operation EntangleForJointMeasure(basis : Pauli, aux : Qubit, qubit : Qubit) : Unit { - if basis == PauliX { - __quantum__qis__cx__body(aux, qubit); - } elif basis == PauliZ { - __quantum__qis__cz__body(aux, qubit); - } elif basis == PauliY { - __quantum__qis__cy__body(aux, qubit); - } - } - - /// Collects the given list of control qubits into one or two of the given auxiliary qubits, using - /// all but the last qubits in the auxiliary list as scratch qubits. The auxiliary list must be - /// big enough to accommodate the data, so it is usually smaller than controls list by number of - /// qubits needed for the eventual controlled unitary application. The passed adjustment value is - /// used to ensure the right number of auxiliary qubits are processed. - /// - /// For example, if the controls list is 6 qubits, the auxiliary list must be 5 qubits, and the - /// state from the 6 control qubits will be collected into the last qubit of the auxiliary array. - internal operation CollectControls(ctls : Qubit[], aux : Qubit[], adjustment : Int) : Unit is Adj { - // First collect the controls into the first part of the auxiliary list. - for i in 0..2..(Length(ctls) - 2) { - AND(ctls[i], ctls[i + 1], aux[i / 2]); - } - // Then collect the auxiliary qubits in the first part of the list forward into the last - // qubit of the auxiliary list. The adjustment is used to allow the caller to reduce or increase - // the number of times this is run based on the eventual number of control qubits needed. - for i in 0..((Length(ctls) / 2) - 2 - adjustment) { - AND(aux[i * 2], aux[(i * 2) + 1], aux[i + Length(ctls) / 2]); - } - } - - /// When collecting controls, if there is an uneven number of original control qubits then the - /// last control and the second to last auxiliary will be collected into the last auxiliary. - internal operation AdjustForSingleControl(ctls : Qubit[], aux : Qubit[]) : Unit is Adj { - if Length(ctls) % 2 != 0 { - AND(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], aux[Length(ctls) - 2]); - } - } - - internal operation PhaseCCX(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - // https://arxiv.org/pdf/1210.0974.pdf#page=2 - H(target); - CNOT(target, control1); - CNOT(control1, control2); - T(control2); - Adjoint T(control1); - T(target); - CNOT(target, control1); - CNOT(control1, control2); - Adjoint T(control2); - CNOT(target, control2); - H(target); - } - - internal operation CCZ(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - within { - H(target); - } apply { - CCNOT(control1, control2, target); - } - } - - internal operation CCY(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - within { - MapPauli(target, PauliX, PauliY); - } apply { - CCNOT(control1, control2, target); - } - } - - internal operation CRxx(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { - within { - CNOT(qubit1, qubit0); - } apply { - Controlled Rx([control], (theta, qubit0)); - } - } - - internal operation CRyy(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { - within { - CNOT(qubit1, qubit0); - } apply { - Controlled Ry([control], (theta, qubit0)); - } - } - - internal operation CRzz(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { - within { - CNOT(qubit1, qubit0); - } apply { - Controlled Rz([control], (theta, qubit0)); - } - } - - internal function IndicesOfNonIdentity(paulies : Pauli[]) : Int[] { - mutable indices = []; - for i in 0..Length(paulies) - 1 { - if (paulies[i] != PauliI) { - set indices += [i]; - } - } - indices - } - - internal function RemovePauliI(paulis : Pauli[], qubits : Qubit[]) : (Pauli[], Qubit[]) { - let indices = IndicesOfNonIdentity(paulis); - let newPaulis = Subarray(indices, paulis); - let newQubits = Subarray(indices, qubits); - return (newPaulis, newQubits); - } - - internal operation SpreadZ(from : Qubit, to : Qubit[]) : Unit is Adj { - let targets = GetSpread(from, to); - for (ctl, tgt) in targets { - CNOT(ctl, tgt); - } - } - - internal function GetSpread(from : Qubit, to : Qubit[]) : (Qubit, Qubit)[] { - mutable queue = [(from, to)]; - mutable targets = []; - while Length(queue) > 0 { - mutable (next, rest) = (queue[0], queue[1...]); - set queue = rest; - let (next_from, next_to) = next; - if Length(next_to) > 0 { - set targets = [(next_to[0], next_from)] + targets; - if Length(next_to) > 1 { - let half = Length(next_to) / 2; - set queue = [(next_from, next_to[1..half]), (next_to[0], next_to[(half + 1)...])] + rest; - } - } - } - - targets - } -} diff --git a/library/std/src/intrinsic.qs b/library/std/src/intrinsic.qs deleted file mode 100644 index b4a8e0f4d7..0000000000 --- a/library/std/src/intrinsic.qs +++ /dev/null @@ -1,1158 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Intrinsic { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Core; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open QIR.Intrinsic; - - /// # Summary - /// Applies the AND gate that is more efficient for use with decomposition of multi-controlled operations. - /// Note that target qubit must be in |0⟩ state. - /// - /// # Input - /// ## control1 - /// First control qubit for the AND gate. - /// ## control2 - /// Second control qubit for the AND gate. - /// ## target - /// Target qubit for the AND gate. - /// - /// # Remarks - /// Use the Adjoint only for uncomputation purposes. - @Config(Adaptive) - operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - body ... { - __quantum__qis__ccx__body(control1, control2, target); - } - adjoint ... { - __quantum__qis__h__body(target); - if MResetZ(target) == One { - __quantum__qis__cz__body(control1, control2); - } - } - } - - /// # Summary - /// Applies the AND gate that is more efficient for use with decomposition of multi-controlled operations. - /// Note that target qubit must be in |0⟩ state. - /// - /// # Input - /// ## control1 - /// First control qubit for the AND gate. - /// ## control2 - /// Second control qubit for the AND gate. - /// ## target - /// Target qubit for the AND gate. - /// - /// # Remarks - /// Use the Adjoint only for uncomputation purposes. - @Config(not Adaptive) - operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - PhaseCCX(control1, control2, target); - } - - /// # Summary - /// Applies the doubly controlled–NOT (CCNOT) gate to three qubits. - /// - /// # Input - /// ## control1 - /// First control qubit for the CCNOT gate. - /// ## control2 - /// Second control qubit for the CCNOT gate. - /// ## target - /// Target qubit for the CCNOT gate. - /// - /// # Remarks - /// Equivalent to: - /// ```qsharp - /// Controlled X([control1, control2], target); - /// ``` - operation CCNOT(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__ccx__body(control1, control2, target); - } - controlled (ctls, ...) { - Controlled X(ctls + [control1, control2], target); - } - adjoint self; - } - - /// # Summary - /// Applies the controlled-NOT (CNOT) gate to a pair of qubits. - /// - /// # Input - /// ## control - /// Control qubit for the CNOT gate. - /// ## target - /// Target qubit for the CNOT gate. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// \operatorname{CNOT} \mathrel{:=} - /// \begin{bmatrix} - /// 1 & 0 & 0 & 0 \\\\ - /// 0 & 1 & 0 & 0 \\\\ - /// 0 & 0 & 0 & 1 \\\\ - /// 0 & 0 & 1 & 0 - /// \end{bmatrix}, - /// \end{align} - /// $$ - /// - /// where rows and columns are ordered as in the quantum concepts guide. - /// - /// Equivalent to: - /// ```qsharp - /// Controlled X([control], target); - /// ``` - operation CNOT(control : Qubit, target : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__cx__body(control, target); - } - controlled (ctls, ...) { - Controlled X(ctls + [control], target); - } - adjoint self; - } - - /// # Summary - /// Applies the exponential of a multi-qubit Pauli operator. - /// - /// # Input - /// ## paulis - /// Array of single-qubit Pauli values indicating the tensor product - /// factors on each qubit. - /// ## theta - /// Angle about the given multi-qubit Pauli operator by which the - /// target register is to be rotated. - /// ## qubits - /// Register to apply the given rotation to. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// e^{i \theta [P_0 \otimes P_1 \cdots P_{N-1}]}, - /// \end{align} - /// $$ - /// where $P_i$ is the $i$-th element of `paulis`, and where - /// $N = $`Length(paulis)`. - operation Exp(paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj + Ctl { - body ... { - Fact(Length(paulis) == Length(qubits), "Arrays 'pauli' and 'qubits' must have the same length"); - let (newPaulis, newQubits) = RemovePauliI(paulis, qubits); - let angle = -2.0 * theta; - let len = Length(newPaulis); - - if len == 0 { - ApplyGlobalPhase(theta); - } elif len == 1 { - R(newPaulis[0], angle, qubits[0]); - } elif len == 2 { - within { - MapPauli(qubits[1], paulis[0], paulis[1]); - } apply { - if (paulis[0] == PauliX) { - Rxx(angle, qubits[0], qubits[1]); - } elif (paulis[0] == PauliY) { - Ryy(angle, qubits[0], qubits[1]); - } elif (paulis[0] == PauliZ) { - Rzz(angle, qubits[0], qubits[1]); - } - } - } else { - // len > 2 - within { - for i in 0..Length(paulis) - 1 { - MapPauli(qubits[i], PauliZ, paulis[i]); - } - } apply { - within { - SpreadZ(qubits[1], qubits[2..Length(qubits) - 1]); - } apply { - Rzz(angle, qubits[0], qubits[1]); - } - } - } - } - adjoint ... { - Exp(paulis, -theta, qubits); - } - } - - /// # Summary - /// Applies the Hadamard transformation to a single qubit. - /// - /// # Input - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// H \mathrel{:=} - /// \frac{1}{\sqrt{2}} - /// \begin{bmatrix} - /// 1 & 1 \\\\ - /// 1 & -1 - /// \end{bmatrix} - /// \end{align} - /// $$ - operation H(qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__h__body(qubit); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__h__body(qubit); - } elif Length(ctls) == 1 { - CH(ctls[0], qubit); - } elif Length(ctls) == 2 { - CCH(ctls[0], ctls[1], qubit); - } else { - use aux = Qubit[Length(ctls) - 1 - (Length(ctls) % 2)]; - within { - CollectControls(ctls, aux, 0); - } apply { - if Length(ctls) % 2 != 0 { - CCH(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } else { - CCH(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); - } - } - } - } - adjoint self; - } - - /// # Summary - /// Performs the identity operation (no-op) on a single qubit. - /// - /// # Remarks - /// This is a no-op. It is provided for completeness and because - /// sometimes it is useful to call the identity in an algorithm or to pass it as a parameter. - operation I(target : Qubit) : Unit is Adj + Ctl { - body ... {} - adjoint self; - } - - /// # Summary - /// Performs a measurement of a single qubit in the - /// Pauli _Z_ basis. - /// - /// # Input - /// ## qubit - /// Qubit to be measured. - /// - /// # Output - /// `Zero` if the +1 eigenvalue is observed, and `One` if - /// the -1 eigenvalue is observed. - /// - /// # Remarks - /// The output result is given by - /// the distribution - /// $$ - /// \begin{align} - /// \Pr(\texttt{Zero} | \ket{\psi}) = - /// \braket{\psi | 0} \braket{0 | \psi}. - /// \end{align} - /// $$ - /// - /// Equivalent to: - /// ```qsharp - /// Measure([PauliZ], [qubit]); - /// ``` - @Config(QubitReset) - operation M(qubit : Qubit) : Result { - __quantum__qis__m__body(qubit) - } - - /// # Summary - /// Performs a measurement of a single qubit in the - /// Pauli _Z_ basis. - /// - /// # Input - /// ## qubit - /// Qubit to be measured. - /// - /// # Output - /// `Zero` if the +1 eigenvalue is observed, and `One` if - /// the -1 eigenvalue is observed. - /// - /// # Remarks - /// The output result is given by - /// the distribution - /// $$ - /// \begin{align} - /// \Pr(\texttt{Zero} | \ket{\psi}) = - /// \braket{\psi | 0} \braket{0 | \psi}. - /// \end{align} - /// $$ - /// - /// Equivalent to: - /// ```qsharp - /// Measure([PauliZ], [qubit]); - /// ``` - @Config(not QubitReset) - operation M(qubit : Qubit) : Result { - Measure([PauliZ], [qubit]) - } - - /// # Summary - /// Performs a joint measurement of one or more qubits in the - /// specified Pauli bases. - /// - /// If the basis array and qubit array are different lengths, then the - /// operation will fail. - /// - /// # Input - /// ## bases - /// Array of single-qubit Pauli values indicating the tensor product - /// factors on each qubit. - /// ## qubits - /// Register of qubits to be measured. - /// - /// # Output - /// `Zero` if the +1 eigenvalue is observed, and `One` if - /// the -1 eigenvalue is observed. - /// - /// # Remarks - /// The probability of getting `Zero` is - /// $\bra{\psi} \frac{I + P_0 \otimes \ldots \otimes P_{N-1}}{2} \ket{\psi}$ - /// where $P_i$ is the $i$-th element of `bases`, and where - /// $N$ is the `Length(bases)`. - /// That is, measurement returns a `Result` $d$ such that the eigenvalue of the - /// observed measurement effect is $(-1)^d$. - @Config(QubitReset) - operation Measure(bases : Pauli[], qubits : Qubit[]) : Result { - if Length(bases) != Length(qubits) { - fail "Arrays 'bases' and 'qubits' must be of the same length."; - } - if Length(bases) == 1 { - within { - MapPauli(qubits[0], PauliZ, bases[0]); - } apply { - __quantum__qis__m__body(qubits[0]) - } - } else { - use aux = Qubit(); - within { - H(aux); - } apply { - for i in 0..Length(bases) - 1 { - EntangleForJointMeasure(bases[i], aux, qubits[i]); - } - } - __quantum__qis__mresetz__body(aux) - } - } - - /// # Summary - /// Performs a joint measurement of one or more qubits in the - /// specified Pauli bases. - /// - /// If the basis array and qubit array are different lengths, then the - /// operation will fail. - /// - /// # Input - /// ## bases - /// Array of single-qubit Pauli values indicating the tensor product - /// factors on each qubit. - /// ## qubits - /// Register of qubits to be measured. - /// - /// # Output - /// `Zero` if the +1 eigenvalue is observed, and `One` if - /// the -1 eigenvalue is observed. - /// - /// # Remarks - /// The probability of getting `Zero` is - /// $\bra{\psi} \frac{I + P_0 \otimes \ldots \otimes P_{N-1}}{2} \ket{\psi}$ - /// where $P_i$ is the $i$-th element of `bases`, and where - /// $N$ is the `Length(bases)`. - /// That is, measurement returns a `Result` $d$ such that the eigenvalue of the - /// observed measurement effect is $(-1)^d$. - @Config(not QubitReset) - operation Measure(bases : Pauli[], qubits : Qubit[]) : Result { - if Length(bases) != Length(qubits) { - fail "Arrays 'bases' and 'qubits' must be of the same length."; - } - // Because Base Profile does not allow qubit reuse, we always allocate a new qubit - // and use entanglement to measure the state while collapsing the original target(s) and - // leaving it available for later operations. - use aux = Qubit(); - within { - H(aux); - } apply { - for i in 0..Length(bases) - 1 { - EntangleForJointMeasure(bases[i], aux, qubits[i]); - } - } - __quantum__qis__mresetz__body(aux) - } - - /// # Summary - /// Applies a rotation about the given Pauli axis. - /// - /// # Input - /// ## pauli - /// Pauli operator (μ) to be exponentiated to form the rotation. - /// ## theta - /// Angle in radians about which the qubit is to be rotated. - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_{\mu}(\theta) \mathrel{:=} - /// e^{-i \theta \sigma_{\mu} / 2}, - /// \end{align} - /// $$ - /// where $\mu \in \{I, X, Y, Z\}$. - /// - /// When called with `pauli = PauliI`, this operation applies - /// a *global phase*. This phase can be significant - /// when used with the `Controlled` functor. - operation R(pauli : Pauli, theta : Double, qubit : Qubit) : Unit is Adj + Ctl { - if (pauli == PauliX) { - Rx(theta, qubit); - } elif (pauli == PauliY) { - Ry(theta, qubit); - } elif (pauli == PauliZ) { - Rz(theta, qubit); - } else { - // PauliI - ApplyGlobalPhase(-theta / 2.0); - } - } - - /// # Summary - /// Applies a rotation about the |1⟩ state by a given angle. - /// - /// # Input - /// ## theta - /// Angle about which the qubit is to be rotated. - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_1(\theta) \mathrel{:=} - /// \operatorname{diag}(1, e^{i\theta}). - /// \end{align} - /// $$ - /// - /// Equivalent to: - /// ```qsharp - /// R(PauliZ, theta, qubit); - /// R(PauliI, -theta, qubit); - /// ``` - operation R1(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { - Rz(theta, qubit); - R(PauliI, -theta, qubit); - } - - /// # Summary - /// Applies a rotation about the |1⟩ state by an angle specified - /// as a dyadic fraction. - /// - /// WARNING: - /// This operation uses the **opposite** sign convention from - /// Microsoft.Quantum.Intrinsic.R. - /// - /// # Input - /// ## numerator - /// Numerator in the dyadic fraction representation of the angle - /// by which the qubit is to be rotated. This angle is expressed in radians. - /// ## power - /// Power of two specifying the denominator of the angle by which - /// the qubit is to be rotated. This angle is expressed in radians. - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_1(n, k) \mathrel{:=} - /// \operatorname{diag}(1, e^{i \pi n / 2^k}). - /// \end{align} - /// $$ - /// - /// Equivalent to: - /// ```qsharp - /// RFrac(PauliZ, -numerator, denominator + 1, qubit); - /// RFrac(PauliI, numerator, denominator + 1, qubit); - /// ``` - operation R1Frac(numerator : Int, power : Int, qubit : Qubit) : Unit is Adj + Ctl { - RFrac(PauliZ, -numerator, power + 1, qubit); - RFrac(PauliI, numerator, power + 1, qubit); - } - - /// # Summary - /// Given a single qubit, measures it and ensures it is in the |0⟩ state - /// such that it can be safely released. - /// - /// # Input - /// ## qubit - /// The qubit whose state is to be reset to |0⟩. - operation Reset(qubit : Qubit) : Unit { - __quantum__qis__reset__body(qubit); - } - - /// # Summary - /// Given an array of qubits, measure them and ensure they are in the |0⟩ state - /// such that they can be safely released. - /// - /// # Input - /// ## qubits - /// An array of qubits whose states are to be reset to |0⟩. - operation ResetAll(qubits : Qubit[]) : Unit { - for q in qubits { - Reset(q); - } - } - - /// # Summary - /// Applies a rotation about the given Pauli axis by an angle specified - /// as a dyadic fraction. - /// - /// WARNING: - /// This operation uses the **opposite** sign convention from - /// Microsoft.Quantum.Intrinsic.R. - /// - /// # Input - /// ## pauli - /// Pauli operator to be exponentiated to form the rotation. - /// ## numerator - /// Numerator in the dyadic fraction representation of the angle - /// by which the qubit is to be rotated. This angle is expressed in radians. - /// ## power - /// Power of two specifying the denominator of the angle by which - /// the qubit is to be rotated. This angle is expressed in radians. - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_{\mu}(n, k) \mathrel{:=} - /// e^{i \pi n \sigma_{\mu} / 2^k}, - /// \end{align} - /// $$ - /// where $\mu \in \{I, X, Y, Z\}$. - /// - /// Equivalent to: - /// ```qsharp - /// // PI() is a Q# function that returns an approximation of π. - /// R(pauli, -2.0 * PI() * IntAsDouble(numerator) / IntAsDouble(2 ^ (power - 1)), qubit); - /// ``` - operation RFrac(pauli : Pauli, numerator : Int, power : Int, qubit : Qubit) : Unit is Adj + Ctl { - // Note that power must be converted to a double and used with 2.0 instead of 2 to allow for - // negative exponents that result in a fractional denominator. - let angle = ((-2.0 * PI()) * IntAsDouble(numerator)) / (2.0^IntAsDouble(power)); - R(pauli, angle, qubit); - } - - /// # Summary - /// Applies a rotation about the _x_-axis by a given angle. - /// - /// # Input - /// ## theta - /// Angle about which the qubit is to be rotated. - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_x(\theta) \mathrel{:=} - /// e^{-i \theta \sigma_x / 2} = - /// \begin{bmatrix} - /// \cos \frac{\theta}{2} & -i\sin \frac{\theta}{2} \\\\ - /// -i\sin \frac{\theta}{2} & \cos \frac{\theta}{2} - /// \end{bmatrix}. - /// \end{align} - /// $$ - /// - /// Equivalent to: - /// ```qsharp - /// R(PauliX, theta, qubit); - /// ``` - operation Rx(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__rx__body(theta, qubit); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__rx__body(theta, qubit); - } else { - within { - MapPauli(qubit, PauliZ, PauliX); - } apply { - Controlled Rz(ctls, (theta, qubit)); - } - } - } - adjoint ... { - Rx(-theta, qubit); - } - } - - /// # Summary - /// Applies the two qubit Ising _XX_ rotation gate. - /// - /// # Input - /// ## theta - /// The angle about which the qubits are rotated. - /// ## qubit0 - /// The first qubit input to the gate. - /// ## qubit1 - /// The second qubit input to the gate. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_{xx}(\theta) \mathrel{:=} - /// \begin{bmatrix} - /// \cos \theta & 0 & 0 & -i\sin \theta \\\\ - /// 0 & \cos \theta & -i\sin \theta & 0 \\\\ - /// 0 & -i\sin \theta & \cos \theta & 0 \\\\ - /// -i\sin \theta & 0 & 0 & \cos \theta - /// \end{bmatrix}. - /// \end{align} - /// $$ - operation Rxx(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__rxx__body(theta, qubit0, qubit1); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__rxx__body(theta, qubit0, qubit1); - } elif Length(ctls) == 1 { - CRxx(ctls[0], theta, qubit0, qubit1); - } else { - use aux = Qubit[Length(ctls) - 1]; - within { - CollectControls(ctls, aux, 0); - AdjustForSingleControl(ctls, aux); - } apply { - CRxx(aux[Length(ctls) - 2], theta, qubit0, qubit1); - } - } - } - adjoint ... { - Rxx(-theta, qubit0, qubit1); - } - } - - /// # Summary - /// Applies a rotation about the _y_-axis by a given angle. - /// - /// # Input - /// ## theta - /// Angle about which the qubit is to be rotated. - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_y(\theta) \mathrel{:=} - /// e^{-i \theta \sigma_y / 2} = - /// \begin{bmatrix} - /// \cos \frac{\theta}{2} & -\sin \frac{\theta}{2} \\\\ - /// \sin \frac{\theta}{2} & \cos \frac{\theta}{2} - /// \end{bmatrix}. - /// \end{align} - /// $$ - /// - /// Equivalent to: - /// ```qsharp - /// R(PauliY, theta, qubit); - /// ``` - operation Ry(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__ry__body(theta, qubit); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__ry__body(theta, qubit); - } else { - within { - MapPauli(qubit, PauliZ, PauliY); - } apply { - Controlled Rz(ctls, (theta, qubit)); - } - } - } - adjoint ... { - Ry(-theta, qubit); - } - } - - /// # Summary - /// Applies the two qubit Ising _YY_ rotation gate. - /// - /// # Input - /// ## theta - /// The angle about which the qubits are rotated. - /// ## qubit0 - /// The first qubit input to the gate. - /// ## qubit1 - /// The second qubit input to the gate. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_{yy}(\theta) \mathrel{:=} - /// \begin{bmatrix} - /// \cos \theta & 0 & 0 & i\sin \theta \\\\ - /// 0 & \cos \theta & -i\sin \theta & 0 \\\\ - /// 0 & -i\sin \theta & \cos \theta & 0 \\\\ - /// i\sin \theta & 0 & 0 & \cos \theta - /// \end{bmatrix}. - /// \end{align} - /// $$ - operation Ryy(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__ryy__body(theta, qubit0, qubit1); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__ryy__body(theta, qubit0, qubit1); - } elif Length(ctls) == 1 { - CRyy(ctls[0], theta, qubit0, qubit1); - } else { - use aux = Qubit[Length(ctls) - 1]; - within { - CollectControls(ctls, aux, 0); - AdjustForSingleControl(ctls, aux); - } apply { - CRyy(aux[Length(ctls) - 2], theta, qubit0, qubit1); - } - } - } - adjoint ... { - Ryy(-theta, qubit0, qubit1); - } - } - - /// # Summary - /// Applies a rotation about the _z_-axis by a given angle. - /// - /// # Input - /// ## theta - /// Angle about which the qubit is to be rotated. - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_z(\theta) \mathrel{:=} - /// e^{-i \theta \sigma_z / 2} = - /// \begin{bmatrix} - /// e^{-i \theta / 2} & 0 \\\\ - /// 0 & e^{i \theta / 2} - /// \end{bmatrix}. - /// \end{align} - /// $$ - /// - /// Equivalent to: - /// ```qsharp - /// R(PauliZ, theta, qubit); - /// ``` - operation Rz(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__rz__body(theta, qubit); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__rz__body(theta, qubit); - } elif Length(ctls) == 1 { - CRz(ctls[0], theta, qubit); - } else { - use aux = Qubit[Length(ctls) - 1]; - within { - CollectControls(ctls, aux, 0); - AdjustForSingleControl(ctls, aux); - } apply { - CRz(aux[Length(ctls) - 2], theta, qubit); - } - } - } - adjoint ... { - Rz(-theta, qubit); - } - } - - /// # Summary - /// Applies the two qubit Ising _ZZ_ rotation gate. - /// - /// # Input - /// ## theta - /// The angle about which the qubits are rotated. - /// ## qubit0 - /// The first qubit input to the gate. - /// ## qubit1 - /// The second qubit input to the gate. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// R_{zz}(\theta) \mathrel{:=} - /// \begin{bmatrix} - /// e^{-i \theta / 2} & 0 & 0 & 0 \\\\ - /// 0 & e^{i \theta / 2} & 0 & 0 \\\\ - /// 0 & 0 & e^{i \theta / 2} & 0 \\\\ - /// 0 & 0 & 0 & e^{-i \theta / 2} - /// \end{bmatrix}. - /// \end{align} - /// $$ - operation Rzz(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__rzz__body(theta, qubit0, qubit1); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__rzz__body(theta, qubit0, qubit1); - } elif Length(ctls) == 1 { - CRzz(ctls[0], theta, qubit0, qubit1); - } else { - use aux = Qubit[Length(ctls) - 1]; - within { - CollectControls(ctls, aux, 0); - AdjustForSingleControl(ctls, aux); - } apply { - CRzz(aux[Length(ctls) - 2], theta, qubit0, qubit1); - } - } - } - adjoint ... { - Rzz(-theta, qubit0, qubit1); - } - } - - /// # Summary - /// Applies the π/4 phase gate to a single qubit. - /// - /// # Input - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// S \mathrel{:=} - /// \begin{bmatrix} - /// 1 & 0 \\\\ - /// 0 & i - /// \end{bmatrix}. - /// \end{align} - /// $$ - operation S(qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__s__body(qubit); - } - adjoint ... { - __quantum__qis__s__adj(qubit); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__s__body(qubit); - } elif Length(ctls) == 1 { - CS(ctls[0], qubit); - } elif Length(ctls) == 2 { - Controlled CS([ctls[0]], (ctls[1], qubit)); - } else { - use aux = Qubit[Length(ctls) - 2]; - within { - CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { - if Length(ctls) % 2 != 0 { - Controlled CS([ctls[Length(ctls) - 1]], (aux[Length(ctls) - 3], qubit)); - } else { - Controlled CS([aux[Length(ctls) - 3]], (aux[Length(ctls) - 4], qubit)); - } - } - } - } - controlled adjoint (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__s__adj(qubit); - } elif Length(ctls) == 1 { - Adjoint CS(ctls[0], qubit); - } elif Length(ctls) == 2 { - Controlled Adjoint CS([ctls[0]], (ctls[1], qubit)); - } else { - use aux = Qubit[Length(ctls) - 2]; - within { - CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { - if Length(ctls) % 2 != 0 { - Controlled Adjoint CS([ctls[Length(ctls) - 1]], (aux[Length(ctls) - 3], qubit)); - } else { - Controlled Adjoint CS([aux[Length(ctls) - 3]], (aux[Length(ctls) - 4], qubit)); - } - } - } - } - } - - /// # Summary - /// Applies the SWAP gate to a pair of qubits. - /// - /// # Input - /// ## qubit1 - /// First qubit to be swapped. - /// ## qubit2 - /// Second qubit to be swapped. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// \operatorname{SWAP} \mathrel{:=} - /// \begin{bmatrix} - /// 1 & 0 & 0 & 0 \\\\ - /// 0 & 0 & 1 & 0 \\\\ - /// 0 & 1 & 0 & 0 \\\\ - /// 0 & 0 & 0 & 1 - /// \end{bmatrix}, - /// \end{align} - /// $$ - /// - /// where rows and columns are ordered as in the quantum concepts guide. - /// - /// Equivalent to: - /// ```qsharp - /// CNOT(qubit1, qubit2); - /// CNOT(qubit2, qubit1); - /// CNOT(qubit1, qubit2); - /// ``` - operation SWAP(qubit1 : Qubit, qubit2 : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__swap__body(qubit1, qubit2); - } - adjoint self; - controlled (ctls, ...) { - if (Length(ctls) == 0) { - __quantum__qis__swap__body(qubit1, qubit2); - } else { - within { - CNOT(qubit1, qubit2); - } apply { - Controlled CNOT(ctls, (qubit2, qubit1)); - } - } - } - } - - /// # Summary - /// Applies the π/8 gate to a single qubit. - /// - /// # Input - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// T \mathrel{:=} - /// \begin{bmatrix} - /// 1 & 0 \\\\ - /// 0 & e^{i \pi / 4} - /// \end{bmatrix}. - /// \end{align} - /// $$ - operation T(qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__t__body(qubit); - } - adjoint ... { - __quantum__qis__t__adj(qubit); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__t__body(qubit); - } elif Length(ctls) == 1 { - CT(ctls[0], qubit); - } else { - use aux = Qubit[Length(ctls) - 1]; - within { - CollectControls(ctls, aux, 0); - AdjustForSingleControl(ctls, aux); - } apply { - CT(aux[Length(ctls) - 2], qubit); - } - } - } - controlled adjoint (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__t__adj(qubit); - } elif Length(ctls) == 1 { - Adjoint CT(ctls[0], qubit); - } else { - use aux = Qubit[Length(ctls) - 1]; - within { - CollectControls(ctls, aux, 0); - AdjustForSingleControl(ctls, aux); - } apply { - Adjoint CT(aux[Length(ctls) - 2], qubit); - } - } - } - } - - /// # Summary - /// Applies the Pauli _X_ gate. - /// - /// # Input - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// \sigma_x \mathrel{:=} - /// \begin{bmatrix} - /// 0 & 1 \\\\ - /// 1 & 0 - /// \end{bmatrix}. - /// \end{align} - /// $$ - operation X(qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__x__body(qubit); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__x__body(qubit); - } elif Length(ctls) == 1 { - __quantum__qis__cx__body(ctls[0], qubit); - } elif Length(ctls) == 2 { - __quantum__qis__ccx__body(ctls[0], ctls[1], qubit); - } else { - use aux = Qubit[Length(ctls) - 2]; - within { - CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { - if Length(ctls) % 2 != 0 { - __quantum__qis__ccx__body(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } else { - __quantum__qis__ccx__body(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); - } - } - } - } - adjoint self; - } - - /// # Summary - /// Applies the Pauli _Y_ gate. - /// - /// # Input - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// \sigma_y \mathrel{:=} - /// \begin{bmatrix} - /// 0 & -i \\\\ - /// i & 0 - /// \end{bmatrix}. - /// \end{align} - /// $$ - operation Y(qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__y__body(qubit); - } - controlled (ctls, ...) { - if (Length(ctls) == 0) { - __quantum__qis__y__body(qubit); - } elif (Length(ctls) == 1) { - __quantum__qis__cy__body(ctls[0], qubit); - } elif (Length(ctls) == 2) { - CCY(ctls[0], ctls[1], qubit); - } else { - use aux = Qubit[Length(ctls) - 2]; - within { - CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { - if Length(ctls) % 2 != 0 { - CCY(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } else { - CCY(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); - } - } - } - } - adjoint self; - } - - /// # Summary - /// Applies the Pauli _Z_ gate. - /// - /// # Input - /// ## qubit - /// Qubit to which the gate should be applied. - /// - /// # Remarks - /// $$ - /// \begin{align} - /// \sigma_z \mathrel{:=} - /// \begin{bmatrix} - /// 1 & 0 \\\\ - /// 0 & -1 - /// \end{bmatrix}. - /// \end{align} - /// $$ - operation Z(qubit : Qubit) : Unit is Adj + Ctl { - body ... { - __quantum__qis__z__body(qubit); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__z__body(qubit); - } elif Length(ctls) == 1 { - __quantum__qis__cz__body(ctls[0], qubit); - } elif Length(ctls) == 2 { - CCZ(ctls[0], ctls[1], qubit); - } else { - use aux = Qubit[Length(ctls) - 2]; - within { - CollectControls(ctls, aux, 1 - (Length(ctls) % 2)); - } apply { - if Length(ctls) % 2 != 0 { - CCZ(ctls[Length(ctls) - 1], aux[Length(ctls) - 3], qubit); - } else { - CCZ(aux[Length(ctls) - 3], aux[Length(ctls) - 4], qubit); - } - } - } - } - adjoint self; - } - - /// # Summary - /// Logs a message. - /// - /// # Input - /// ## msg - /// The message to be reported. - /// - /// # Remarks - /// The specific behavior of this function is simulator-dependent, - /// but in most cases the given message will be written to the console. - /// ``` - function Message(msg : String) : Unit { - body intrinsic; - } - - export AND, CCNOT, CNOT, Exp, H, I, M, Measure, R, R1, R1Frac, Reset, ResetAll, RFrac, Rx, Rxx, Ry, Ryy, Rz, Rzz, S, SWAP, T, X, Y, Z, Message; -} diff --git a/library/std/src/legacy_api.qs b/library/std/src/legacy_api.qs new file mode 100644 index 0000000000..d351c868de --- /dev/null +++ b/library/std/src/legacy_api.qs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +// This file re-exports the standard library under the name `Std`, which will be the preferred standard library API going forward. + +namespace Microsoft.Quantum { + export Std.Arrays, Std.Convert, Std.Diagnostics, Std.Logical, Std.Math, Std.Measurement, Std.Intrinsic, Std.Random, Std.ResourceEstimation, Std.Canon; +} + +namespace Std { + export + Microsoft.Quantum.Canon, + Microsoft.Quantum.Core; +} diff --git a/library/std/src/logical.qs b/library/std/src/logical.qs deleted file mode 100644 index be7417a339..0000000000 --- a/library/std/src/logical.qs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Logical { - - /// # Summary - /// Returns the boolean exclusive disjunction (eXclusive OR, XOR) - /// of two input boolean values. - /// - /// # Input - /// ## first - /// The first boolean value to be considered. - /// - /// ## second - /// The second boolean value to be considered. - /// - /// # Output - /// A `Bool` which is `true` if and only if exactly one of `first` and `second` is `true`. - /// - /// # Remarks - /// In Q#, `Xor(a, b)` is equivalent to `a != b`. - /// - /// # Example - /// ```qsharp - /// let result = Xor(true, false); - /// // result is true - /// ``` - function Xor(first : Bool, second : Bool) : Bool { - first != second - } - export Xor; -} diff --git a/library/std/src/math.qs b/library/std/src/math.qs deleted file mode 100644 index dd9e7a0e64..0000000000 --- a/library/std/src/math.qs +++ /dev/null @@ -1,1455 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Math { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - - // - // Constants PI, E, LogOf2. - // - - /// # Summary - /// Returns a double-precision approximation of the - /// matematical constant 𝝅 ≈ 3.14159265358979323846 - /// - /// # Remarks - /// Mathematical constant 𝝅 represents the ratio of the circumference - /// of a circle to its diameter. It is useful in many applications - /// such as rotations and complex arithmetic. - /// - /// # References - /// [Wikipedia article - Pi](https://en.wikipedia.org/wiki/Pi) - /// - /// # See Also - /// - Microsoft.Quantum.Math.E - function PI() : Double { - 3.14159265358979323846 - } - - /// # Summary - /// Returns a double-precision approximation of the - /// mathematical constant 𝒆 ≈ 2.7182818284590452354 - /// - /// # Remarks - /// Mathematical constant 𝒆 is the base of the natural logarithm - /// also known as the Euler's number - /// - /// # References - /// [Wikipedia article - e](https://en.wikipedia.org/wiki/E_(mathematical_constant)) - /// - /// # See Also - /// - Microsoft.Quantum.Math.PI - function E() : Double { - 2.7182818284590452354 - } - - /// # Summary - /// Returns a double-precision approximation of the constant - /// ㏑2 ≈ 0.6931471805599453 - /// - /// # Remarks - /// ㏑2 is the natural logarithm of 2, or the logarithm of 2 base 𝒆. - /// - /// # References - /// [Wikipedia article - Natural logarithm](https://en.wikipedia.org/wiki/Natural_logarithm) - function LogOf2() : Double { - 0.6931471805599453 - } - - // - // Special numbers in IEEE floating-point representation - // - - /// # Summary - /// Returns whether a given floating-point value is not a number (i.e. is - /// NaN). - /// - /// # Input - /// ## d - /// A floating-point value to be checked. - /// - /// # Output - /// `true` if and only if `d` is not a number. - function IsNaN(d : Double) : Bool { - return d != d; - } - - /// # Summary - /// Returns whether a given floating-point value is either positive or - /// negative infinity. - /// - /// # Input - /// ## d - /// The floating-point value to be checked. - /// - /// # Output - /// `true` if and only if `d` is either positive or negative infinity. - /// - /// # Remarks - /// `NaN` is not a number, and is thus neither a finite number nor - /// is it infinite. As such, `IsInfinite(0.0 / 0.0)` returns `false`. - /// To check if a value is `NaN`, use `IsNaN(d)`. - /// - /// Note that even though this function returns `true` for both - /// positive and negative infinities, these values can still be - /// discriminated by checking `d > 0.0` and `d < 0.0`. - /// - /// # Example - /// ```qsharp - /// Message($"{IsInfinite(42.0)}"); // false - /// Message($"{IsInfinite(0.0 / 0.0)}"); // false - /// Message($"{IsInfinite(-1.0 / 0.0}"); // true - /// ``` - /// - /// # See Also - /// - Microsoft.Quantum.Math.IsNaN - function IsInfinite(d : Double) : Bool { - return d == 1.0 / 0.0 or d == -1.0 / 0.0; - } - - // - // Sign, Abs, Min, Max, etc. - // - - /// # Summary - /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignI(a : Int) : Int { - if (a < 0) { - -1 - } elif (a > 0) { - + 1 - } else { - 0 - } - } - - /// # Summary - /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignD(a : Double) : Int { - if (a < 0.0) { - -1 - } elif (a > 0.0) { - + 1 - } else { - 0 - } - } - - /// # Summary - /// Returns -1, 0 or +1 that indicates the sign of a number. - function SignL(a : BigInt) : Int { - if (a < 0L) { - -1 - } elif (a > 0L) { - + 1 - } else { - 0 - } - } - - /// # Summary - /// Returns the absolute value of an integer. - function AbsI(a : Int) : Int { - a < 0 ? -a | a - } - - /// # Summary - /// Returns the absolute value of a double-precision floating-point number. - function AbsD(a : Double) : Double { - a < 0.0 ? -a | a - } - - /// # Summary - function AbsL(a : BigInt) : BigInt { - a < 0L ? -a | a - } - - /// # Summary - /// Returns the larger of two specified numbers. - function MaxI(a : Int, b : Int) : Int { - a > b ? a | b - } - - /// # Summary - /// Returns the larger of two specified numbers. - function MaxD(a : Double, b : Double) : Double { - a > b ? a | b - } - - /// # Summary - /// Returns the larger of two specified numbers. - function MaxL(a : BigInt, b : BigInt) : BigInt { - a > b ? a | b - } - - /// # Summary - /// Returns the smaller of two specified numbers. - function MinI(a : Int, b : Int) : Int { - a < b ? a | b - } - - /// # Summary - /// Returns the smaller of two specified numbers. - function MinD(a : Double, b : Double) : Double { - a < b ? a | b - } - - /// # Summary - /// Returns the smaller of two specified numbers. - function MinL(a : BigInt, b : BigInt) : BigInt { - a < b ? a | b - } - - /// # Summary - /// Given an array of integers, returns the largest element. - /// - /// # Input - /// ## values - /// An array to take the maximum of. - /// - /// # Output - /// The largest element of `values`. - function Max(values : Int[]) : Int { - Fact(Length(values) > 0, "Array must contain at least one element."); - mutable max = values[0]; - for element in values[1...] { - if element > max { - set max = element; - } - } - - max - } - - /// # Summary - /// Given an array of integers, returns the smallest element. - /// - /// # Input - /// ## values - /// An array to take the minimum of. - /// - /// # Output - /// The smallest element of `values`. - function Min(values : Int[]) : Int { - Fact(Length(values) > 0, "Array must contain at least one element."); - mutable min = values[0]; - for element in values[1...] { - if element < min { - set min = element; - } - } - - min - } - - // - // Trigonometric functions - // - - /// # Summary - /// Returns the angle whose cosine is the specified number. - function ArcCos(x : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the angle whose sine is the specified number. - function ArcSin(y : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the angle whose tangent is the specified number. - function ArcTan(d : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the angle whose tangent is the quotient of two specified numbers. - function ArcTan2(y : Double, x : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the cosine of the specified angle. - function Cos(theta : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the hyperbolic cosine of the specified angle. - function Cosh(d : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the sine of the specified angle. - function Sin(theta : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the hyperbolic sine of the specified angle. - function Sinh(d : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the tangent of the specified angle. - function Tan(d : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the hyperbolic tangent of the specified angle. - function Tanh(d : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Computes the inverse hyperbolic cosine of a number. - function ArcCosh(x : Double) : Double { - Log(x + Sqrt(x * x - 1.0)) - } - - /// # Summary - /// Computes the inverse hyperbolic sine of a number. - function ArcSinh(x : Double) : Double { - Log(x + Sqrt(x * x + 1.0)) - } - - - /// # Summary - /// Computes the inverse hyperbolic tangent of a number. - function ArcTanh(x : Double) : Double { - Log((1.0 + x) / (1.0 - x)) * 0.5 - } - - // - // Sqrt, Log, exp, etc. - // - - /// # Summary - /// Returns the square root of a specified number. - function Sqrt(d : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the natural (base _e_) logarithm of a specified number. - function Log(input : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Returns the base-10 logarithm of a specified number. - function Log10(input : Double) : Double { - Log(input) / Log(10.0) - } - - /// # Summary - /// Computes the base-2 logarithm of a number. - function Lg(input : Double) : Double { - Log(input) / Log(2.0) - } - - // - // Truncation and Rounding - // - - /// # Summary - /// Returns the integral part of a number. - /// For example: Truncate(3.7) = 3; Truncate(-3.7) = -3 - function Truncate(value : Double) : Int { - body intrinsic; - } - - internal function ExtendedTruncation(value : Double) : (Int, Double, Bool) { - let truncated = Truncate(value); - (truncated, IntAsDouble(truncated) - value, value >= 0.0) - } - - /// # Summary - /// Returns the smallest integer greater than or equal to the specified number. - /// For example: Ceiling(3.1) = 4; Ceiling(-3.7) = -3 - function Ceiling(value : Double) : Int { - let (truncated, remainder, isPositive) = ExtendedTruncation(value); - if AbsD(remainder) <= 1e-15 { - truncated - } else { - isPositive ? truncated + 1 | truncated - } - } - - /// # Summary - /// Returns the largest integer less than or equal to the specified number. - /// For example: Floor(3.7) = 3; Floor(-3.1) = -4 - function Floor(value : Double) : Int { - let (truncated, remainder, isPositive) = ExtendedTruncation(value); - if AbsD(remainder) <= 1e-15 { - truncated - } else { - isPositive ? truncated | truncated - 1 - } - } - - /// # Summary - /// Returns the nearest integer to the specified number. - /// For example: Round(3.7) = 4; Round(-3.7) = -4 - function Round(value : Double) : Int { - let (truncated, remainder, isPositive) = ExtendedTruncation(value); - if AbsD(remainder) <= 1e-15 { - truncated - } else { - let abs = AbsD(remainder); - truncated + (abs <= 0.5 ? 0 | (isPositive ? 1 | -1)) - } - } - - // - // Modular arithmetic - // - - /// # Summary - /// Divides one Integer value by another, returns the result and the remainder as a tuple. - function DivRemI(dividend : Int, divisor : Int) : (Int, Int) { - (dividend / divisor, dividend % divisor) - } - - /// # Summary - /// Divides one BigInteger value by another, returns the result and the remainder as a tuple. - function DivRemL(dividend : BigInt, divisor : BigInt) : (BigInt, BigInt) { - (dividend / divisor, dividend % divisor) - } - - /// # Summary - /// Computes the canonical residue of `value` modulo `modulus`. - /// The result is always in the range 0..modulus-1 even for negative numbers. - function ModulusI(value : Int, modulus : Int) : Int { - Fact(modulus > 0, "`modulus` must be positive"); - let r = value % modulus; - (r < 0) ? (r + modulus) | r - } - - /// # Summary - /// Computes the canonical residue of `value` modulo `modulus`. - /// The result is always in the range 0..modulus-1 even for negative numbers. - function ModulusL(value : BigInt, modulus : BigInt) : BigInt { - Fact(modulus > 0L, "`modulus` must be positive"); - let r = value % modulus; - (r < 0L) ? (r + modulus) | r - } - - /// # Summary - /// Returns an integer raised to a given power, with respect to a given - /// modulus. I.e. (expBase^power) % modulus. - function ExpModI(expBase : Int, power : Int, modulus : Int) : Int { - Fact(power >= 0, "`power` must be non-negative"); - Fact(modulus > 0, "`modulus` must be positive"); - Fact(expBase > 0, "`expBase` must be positive"); - - // shortcut when modulus is 1 - if modulus == 1 { - return 0; - } - - mutable res = 1; - mutable expPow2mod = expBase % modulus; - mutable powerBits = power; - - while powerBits > 0 { - if (powerBits &&& 1) != 0 { - // if bit pₖ is 1, multiply res by expBase^(2^k) (mod `modulus`) - set res = (res * expPow2mod) % modulus; - } - - // update value of expBase^(2^k) (mod `modulus`) - set expPow2mod = (expPow2mod * expPow2mod) % modulus; - set powerBits >>>= 1; - } - - res - } - - /// # Summary - /// Returns an integer raised to a given power, with respect to a given - /// modulus. I.e. (expBase^power) % modulus. - function ExpModL(expBase : BigInt, power : BigInt, modulus : BigInt) : BigInt { - Fact(power >= 0L, "`power` must be non-negative"); - Fact(modulus > 0L, "`modulus` must be positive"); - Fact(expBase > 0L, "`expBase` must be positive"); - - // shortcut when modulus is 1 - if modulus == 1L { - return 0L; - } - - mutable res = 1L; - mutable expPow2mod = expBase % modulus; - mutable powerBits = power; - - while powerBits > 0L { - if (powerBits &&& 1L) != 0L { - // if bit pₖ is 1, multiply res by expBase^(2ᵏ) (mod `modulus`) - set res = (res * expPow2mod) % modulus; - } - - // update value of expBase^(2ᵏ) (mod `modulus`) - set expPow2mod = (expPow2mod * expPow2mod) % modulus; - set powerBits >>>= 1; - } - - res - } - - /// # Summary - /// Returns the multiplicative inverse of a modular integer. - /// - /// # Description - /// This will calculate the multiplicative inverse of a - /// modular integer `b` such that `a • b = 1 (mod modulus)`. - function InverseModI(a : Int, modulus : Int) : Int { - let (u, v) = ExtendedGreatestCommonDivisorI(a, modulus); - let gcd = u * a + v * modulus; - Fact(gcd == 1, "`a` and `modulus` must be co-prime"); - ModulusI(u, modulus) - } - - /// # Summary - /// Returns the multiplicative inverse of a modular integer. - /// - /// # Description - /// This will calculate the multiplicative inverse of a - /// modular integer `b` such that `a • b = 1 (mod modulus)`. - function InverseModL(a : BigInt, modulus : BigInt) : BigInt { - let (u, v) = ExtendedGreatestCommonDivisorL(a, modulus); - let gcd = u * a + v * modulus; - Fact(gcd == 1L, "`a` and `modulus` must be co-prime"); - ModulusL(u, modulus) - } - - // - // GCD, etc. - // - - /// # Summary - /// Computes the greatest common divisor of two integers. - /// Note: GCD is always positive except that GCD(0,0)=0. - function GreatestCommonDivisorI(a : Int, b : Int) : Int { - mutable aa = AbsI(a); - mutable bb = AbsI(b); - while bb != 0 { - let cc = aa % bb; - set aa = bb; - set bb = cc; - } - aa - } - - /// # Summary - /// Computes the greatest common divisor of two integers. - /// Note: GCD is always positive except that GCD(0,0)=0. - function GreatestCommonDivisorL(a : BigInt, b : BigInt) : BigInt { - mutable aa = AbsL(a); - mutable bb = AbsL(b); - while bb != 0L { - let cc = aa % bb; - set aa = bb; - set bb = cc; - } - aa - } - - /// # Summary - /// Returns a tuple (u,v) such that u*a+v*b=GCD(a,b) - /// Note: GCD is always positive except that GCD(0,0)=0. - function ExtendedGreatestCommonDivisorI(a : Int, b : Int) : (Int, Int) { - let signA = SignI(a); - let signB = SignI(b); - mutable (s1, s2) = (1, 0); - mutable (t1, t2) = (0, 1); - mutable (r1, r2) = (a * signA, b * signB); - - while r2 != 0 { - let quotient = r1 / r2; - set (r1, r2) = (r2, r1 - quotient * r2); - set (s1, s2) = (s2, s1 - quotient * s2); - set (t1, t2) = (t2, t1 - quotient * t2); - } - - (s1 * signA, t1 * signB) - } - - /// # Summary - /// Returns a tuple (u,v) such that u*a+v*b=GCD(a,b) - /// Note: GCD is always positive except that GCD(0,0)=0. - function ExtendedGreatestCommonDivisorL(a : BigInt, b : BigInt) : (BigInt, BigInt) { - let signA = IntAsBigInt(SignL(a)); - let signB = IntAsBigInt(SignL(b)); - mutable (s1, s2) = (1L, 0L); - mutable (t1, t2) = (0L, 1L); - mutable (r1, r2) = (a * signA, b * signB); - - while r2 != 0L { - let quotient = r1 / r2; - set (r1, r2) = (r2, r1 - quotient * r2); - set (s1, s2) = (s2, s1 - quotient * s2); - set (t1, t2) = (t2, t1 - quotient * t2); - } - - (s1 * signA, t1 * signB) - } - - /// # Summary - /// Returns if two integers are co-prime. - /// - /// # Description - /// Returns true if a and b are co-prime and false otherwise. - /// - /// # Input - /// ## a - /// the first number of which co-primality is being tested - /// ## b - /// the second number of which co-primality is being tested - /// - /// # Output - /// True, if a and b are co-prime (e.g. their greatest common divisor is 1), - /// and false otherwise - function IsCoprimeI(a : Int, b : Int) : Bool { - GreatestCommonDivisorI(a, b) == 1 - } - - /// # Summary - /// Returns if two integers are co-prime. - /// - /// # Description - /// Returns true if a and b are co-prime and false otherwise. - /// - /// # Input - /// ## a - /// the first number of which co-primality is being tested - /// ## b - /// the second number of which co-primality is being tested - /// - /// # Output - /// True, if a and b are co-prime (e.g. their greatest common divisor is 1), - /// and false otherwise - function IsCoprimeL(a : BigInt, b : BigInt) : Bool { - GreatestCommonDivisorL(a, b) == 1L - } - - /// # Summary - /// Finds the continued fraction convergent closest to `fraction` - /// with the denominator less or equal to `denominatorBound` - /// Using process similar to this: https://nrich.maths.org/1397 - function ContinuedFractionConvergentI( - fraction : (Int, Int), - denominatorBound : Int - ) : (Int, Int) { - Fact(denominatorBound > 0, "Denominator bound must be positive"); - - let (a, b) = fraction; - let signA = SignI(a); - let signB = SignI(b); - mutable (s1, s2) = (1, 0); - mutable (t1, t2) = (0, 1); - mutable (r1, r2) = (a * signA, b * signB); - - while r2 != 0 and AbsI(s2) <= denominatorBound { - let quotient = r1 / r2; - set (r1, r2) = (r2, r1 - quotient * r2); - set (s1, s2) = (s2, s1 - quotient * s2); - set (t1, t2) = (t2, t1 - quotient * t2); - } - - if r2 == 0 and AbsI(s2) <= denominatorBound { - (-t2 * signB, s2 * signA) - } else { - (-t1 * signB, s1 * signA) - } - } - - /// # Summary - /// Finds the continued fraction convergent closest to `fraction` - /// with the denominator less or equal to `denominatorBound` - /// Using process similar to this: https://nrich.maths.org/1397 - function ContinuedFractionConvergentL( - fraction : (BigInt, BigInt), - denominatorBound : BigInt - ) : (BigInt, BigInt) { - Fact(denominatorBound > 0L, "Denominator bound must be positive"); - - let (a, b) = fraction; - let signA = IntAsBigInt(SignL(a)); - let signB = IntAsBigInt(SignL(b)); - mutable (s1, s2) = (1L, 0L); - mutable (t1, t2) = (0L, 1L); - mutable (r1, r2) = (a * signA, b * signB); - - while r2 != 0L and AbsL(s2) <= denominatorBound { - let quotient = r1 / r2; - set (r1, r2) = (r2, r1 - quotient * r2); - set (s1, s2) = (s2, s1 - quotient * s2); - set (t1, t2) = (t2, t1 - quotient * t2); - } - - if r2 == 0L and AbsL(s2) <= denominatorBound { - (-t2 * signB, s2 * signA) - } else { - (-t1 * signB, s1 * signA) - } - } - - /// # Summary - /// Computes the modulus between two real numbers. - /// - /// # Input - /// ## value - /// A real number x to take the modulus of. - /// ## modulo - /// A real number to take the modulus of x with respect to. - /// ## minValue - /// The smallest value to be returned by this function. - /// - /// # Example - /// ```qsharp - /// // Returns 3 π / 2. - /// let y = RealMod(5.5 * PI(), 2.0 * PI(), 0.0); - /// // Returns -1.2, since +3.6 and -1.2 are 4.8 apart on the real line, - /// // which is a multiple of 2.4. - /// let z = RealMod(3.6, 2.4, -1.2); - /// ``` - function RealMod(value : Double, modulo : Double, minValue : Double) : Double { - let timesModuloInSegment = (value - minValue) / modulo; - let fractionalPart = timesModuloInSegment - IntAsDouble(Truncate(timesModuloInSegment)); - modulo * fractionalPart + minValue - } - - // - // Binary, bits, etc. - // - - /// # Summary - /// For a non-negative integer `a`, returns the number of bits required to represent `a`. - /// NOTE: This function returns the smallest n such that a < 2^n. - function BitSizeI(a : Int) : Int { - Fact(a >= 0, "`a` must be non-negative."); - mutable number = a; - mutable size = 0; - while (number != 0) { - set size = size + 1; - set number = number >>> 1; - } - - size - } - - /// # Summary - /// For a non-negative integer `a`, returns the number of bits required to represent `a`. - /// NOTE: This function returns the smallest n such that a < 2^n. - function BitSizeL(a : BigInt) : Int { - Fact(a >= 0L, "`a` must be non-negative."); - mutable number = a; - mutable size = 0; - while (number != 0L) { - set size = size + 1; - set number = number >>> 1; - } - - size - } - - /// # Summary - /// For a non-zero integer `a`, returns the number of trailing zero bits - /// in the binary representation of `a`. - function TrailingZeroCountI(a : Int) : Int { - Fact(a != 0, "TrailingZeroCountI: `a` cannot be 0."); - - mutable count = 0; - mutable n = a; - while n &&& 1 == 0 { - set count += 1; - set n >>>= 1; - } - - count - } - - /// # Summary - /// For a non-zero integer `a`, returns the number of trailing zero bits - /// in the binary representation of `a`. - function TrailingZeroCountL(a : BigInt) : Int { - Fact(a != 0L, "TrailingZeroCountL: `a` cannot be 0."); - - mutable count = 0; - mutable n = a; - while n &&& 1L == 0L { - set count += 1; - set n >>>= 1; - } - - count - } - - /// # Summary - /// Returns the number of 1 bits in the binary representation of integer `n`. - function HammingWeightI(n : Int) : Int { - let i1 = n - ((n >>> 1) &&& 0x5555555555555555); - let i2 = (i1 &&& 0x3333333333333333) + ((i1 >>> 2) &&& 0x3333333333333333); - // Multiplication may overflow. See https://github.com/microsoft/qsharp/issues/828 - (((i2 + (i2 >>> 4)) &&& 0xF0F0F0F0F0F0F0F) * 0x101010101010101) >>> 56 - } - - // - // Combinatorics - // - - /// # Summary - /// Returns the factorial of a given number. - /// - /// # Description - /// Returns the factorial of a given nonnegative integer n, where 0 ≤ n ≤ 20. - /// - /// # Input - /// ## n - /// The number to take the factorial of. - /// - /// # Output - /// The factorial of `n`. - /// - /// # Remarks - /// For inputs greater than 20, please use `Microsoft.Quantum.Math.FactorialL`. - /// - /// # See Also - /// - Microsoft.Quantum.Math.FactorialL - /// - Microsoft.Quantum.Math.ApproximateFactorial - function FactorialI(n : Int) : Int { - Fact(n >= 0, "The factorial is not defined for negative inputs."); - Fact(n <= 20, "The largest factorial that can be stored as an Int is 20!. Use FactorialL or ApproximateFactorial."); - - [ - 1, - 1, - 2, - 6, - 24, - 120, - 720, - 5040, - 40320, - 362880, - 3628800, - 39916800, - 479001600, - 6227020800, - 87178291200, - 1307674368000, - 20922789888000, - 355687428096000, - 6402373705728000, - 121645100408832000, - 2432902008176640000 - ][n] - } - - /// # Summary - /// Returns the factorial of a given number. - /// - /// # Input - /// ## n - /// The number to take the factorial of. - /// - /// # Output - /// The factorial of `n`. - /// - /// # See Also - /// - Microsoft.Quantum.Math.FactorialI - /// - Microsoft.Quantum.Math.ApproximateFactorial - function FactorialL(n : Int) : BigInt { - Fact(n >= 0, "The factorial is not defined for negative inputs."); - - mutable result = 1L; - for i in 1..n { - set result *= IntAsBigInt(i); - } - result - } - - /// # Summary - /// Returns an approximate factorial of a given number. - /// - /// # Description - /// Returns the factorial as `Double`, given an input `n`. - /// The domain of inputs for this function is `n <= 169`. - /// - /// # Remarks - /// For n > 10, this function uses the Ramanujan approximation with a - /// relative error of the order of 1 / n⁵. - /// - /// # Input - /// ## n - /// The number to take the approximate factorial of. Must not be negative. - /// - /// # Output - /// The approximate factorial of `n`. - /// - /// # See Also - /// - Microsoft.Quantum.Math.FactorialI - /// - Microsoft.Quantum.Math.FactorialL - function ApproximateFactorial(n : Int) : Double { - Fact(n >= 0, "The factorial is not defined for negative inputs."); - Fact(n <= 169, "The largest approximate factorial that can be stored as a Double is 169!. Use FactorialL."); - - // For small enough n, use the exact factorial instead. - if n <= 20 { - return IntAsDouble(FactorialI(n)); - } - - let absN = IntAsDouble(n); - let a = Sqrt(2.0 * PI() * absN); - let b = (absN / E())^absN; - let c = E()^(1.0 / (12.0 * absN) - (1.0 / (360.0 * (absN^3.0)))); - - a * b * c - } - - /// # Summary - /// Returns the natural logarithm of the gamma function (aka the log-gamma - /// function). - /// - /// # Description - /// The gamma function Γ(x) generalizes the factorial function - /// to the positive real numbers and is defined as - /// integral from 0 to ∞ of t¹⁻ˣ⋅e⁻ᵗ𝑑t - /// - /// The gamma function has the property that for all positive real numbers - /// x, Γ(x + 1) = x⋅Γ(x), such that the factorial function - /// is a special case of Γ, n! = Γ(n + 1) for all natural numbers n. - /// - /// # Input - /// ## x - /// The point x at which the log-gamma function is to be evaluated. - /// - /// # Output - /// The value ㏑(Γ(x)). - function LogGammaD(x : Double) : Double { - // Here, we use the approximation described in Numerical Recipes in C. - let coefficients = [ - 57.1562356658629235, - -59.5979603554754912, - 14.1360979747417471, - -0.491913816097620199, - 0.339946499848118887e-4, - 0.465236289270485756e-4, - -0.983744753048795646e-4, - 0.158088703224912494e-3, - -0.210264441724104883e-3, - 0.217439618115212643e-3, - -0.164318106536763890e-3, - 0.844182239838527433e-4, - -0.261908384015814087e-4, - 0.368991826595316234e-5 - ]; - - Fact(x > 0.0, "Γ(x) not defined for x <= 0."); - - mutable y = x; - let tmp = x + 5.2421875000000000; - - mutable acc = 0.99999999999999709; - for coeff in coefficients { - set y += 1.0; - set acc += coeff / y; - } - - Log(2.506628274631000 * acc / x) + ((x + 0.5) * Log(tmp) - tmp) - } - - /// # Summary - /// Returns the approximate natural logarithm of the factorial of a given - /// integer. - /// - /// # Input - /// ## n - /// The number to take the log-factorial of. - /// - /// # Output - /// The natural logarithm of the factorial of the provided input. - /// - /// # See Also - /// - Microsoft.Quantum.Math.ApproximateFactorial - /// - Microsoft.Quantum.Math.FactorialI - /// - Microsoft.Quantum.Math.FactorialL - function LogFactorialD(n : Int) : Double { - LogGammaD(IntAsDouble(n) + 1.0) - } - - /// # Summary - /// Returns the approximate binomial coefficient of two integers. - /// - /// # Description - /// Given two integers n and k, returns the binomial coefficient - /// binom(n, k), also known as n-choose-k. Computed approximately. - /// - /// # Input - /// ## n - /// The first of the two integers to compute the binomial coefficient of. - /// ## k - /// The second of the two integers to compute the binomial coefficient of. - /// - /// # Output - /// The binomial coefficient n-choose-k. - function Binom(n : Int, k : Int) : Int { - // Here, we use the approximation described in Numerical Recipes in C. - if n < 171 { - Floor(0.5 + ApproximateFactorial(n) / (ApproximateFactorial(k) * ApproximateFactorial(n - k))) - } else { - Floor(0.5 + E()^(LogFactorialD(n) - LogFactorialD(k) - LogFactorialD(n - k))) - } - } - - // - // Norms - // - - /// # Summary - /// Returns the squared 2-norm of a vector. - /// - /// # Description - /// Returns the squared 2-norm of a vector; that is, given an input - /// x̄, returns ∑xᵢ. - /// - /// # Input - /// ## array - /// The vector whose squared 2-norm is to be returned. - /// - /// # Output - /// The squared 2-norm of `array`. - function SquaredNorm(array : Double[]) : Double { - mutable sum = 0.0; - for element in array { - set sum += element * element; - } - - sum - } - - /// # Summary - /// Returns the `L(p)` norm of a vector of `Double`s. - /// - /// That is, given an array x of type `Double[]`, this returns the p-norm - /// |x̄|ₚ= (∑(xᵢ)ᵖ)¹ᐟᵖ. - /// - /// # Input - /// ## p - /// The exponent p in the p-norm. - /// - /// # Output - /// The p-norm |x̄|ₚ. - function PNorm(p : Double, array : Double[]) : Double { - if p < 1.0 { - fail "p must be >= 1.0"; - } - - mutable sum = 0.0; - for element in array { - set sum += AbsD(element)^p; - } - - sum^(1.0 / p) - } - - /// # Summary - /// Normalizes a vector of `Double`s in the `L(p)` norm. - /// - /// That is, given an array x of type `Double[]`, this returns an array where - /// all elements are divided by the p-norm |x̄|ₚ. - /// Function leaves array with norm 0 unchanged. - /// - /// # Input - /// ## p - /// The exponent p in the p-norm. - /// - /// # Output - /// The array x normalized by the p-norm |x̄|ₚ. - /// - /// # See Also - /// - PNorm - function PNormalized(p : Double, array : Double[]) : Double[] { - let norm = PNorm(p, array); - if (norm == 0.0) { - return array; - } - - mutable result = []; - for element in array { - set result += [element / norm]; - } - - result - } - - // - // Complex numbers - // - - /// # Summary - /// Represents a complex number by its real and imaginary components. - /// The first element of the tuple is the real component, - /// the second one - the imaginary component. - /// - /// # Example - /// The following snippet defines the imaginary unit 𝑖 = 0 + 1𝑖: - /// ```qsharp - /// let imagUnit = Complex(0.0, 1.0); - /// ``` - struct Complex { Real : Double, Imag : Double } - - /// # Summary - /// Represents a complex number in polar form. - /// The polar representation of a complex number is c = r⋅𝑒^(t𝑖). - /// - /// # Named Items - /// ## Magnitude - /// The absolute value r>0 of c. - /// ## Argument - /// The phase t ∈ ℝ of c. - struct ComplexPolar { Magnitude : Double, Argument : Double } - - /// # Summary - /// Returns the squared absolute value of a complex number of type - /// `Complex`. - /// - /// # Input - /// ## input - /// Complex number c = x + y𝑖. - /// - /// # Output - /// Squared absolute value |c|² = x² + y². - function AbsSquaredComplex(input : Complex) : Double { - input.Real * input.Real + input.Imag * input.Imag - } - - /// # Summary - /// Returns the absolute value of a complex number of type - /// `Complex`. - /// - /// # Input - /// ## input - /// Complex number c = x + y𝑖. - /// - /// # Output - /// Absolute value |c| = √(x² + y²). - function AbsComplex(input : Complex) : Double { - Sqrt(AbsSquaredComplex(input)) - } - - /// # Summary - /// Returns the phase of a complex number of type - /// `Complex`. - /// - /// # Input - /// ## input - /// Complex number c = x + y𝑖. - /// - /// # Output - /// Phase Arg(c) = ArcTan(y,x) ∈ (-𝜋,𝜋]. - function ArgComplex(input : Complex) : Double { - ArcTan2(input.Imag, input.Real) - } - - /// # Summary - /// Returns the squared absolute value of a complex number of type - /// `ComplexPolar`. - /// - /// # Input - /// ## input - /// Complex number c = r⋅𝑒^(t𝑖). - /// - /// # Output - /// Squared absolute value |c|² = r². - function AbsSquaredComplexPolar(input : ComplexPolar) : Double { - input.Magnitude * input.Magnitude - } - - /// # Summary - /// Returns the absolute value of a complex number of type - /// `ComplexPolar`. - /// - /// # Input - /// ## input - /// Complex number c = r⋅𝑒^(t𝑖). - /// - /// # Output - /// Absolute value |c| = r. - function AbsComplexPolar(input : ComplexPolar) : Double { input.Magnitude } - - /// # Summary - /// Returns the phase of a complex number of type `ComplexPolar`. - /// - /// # Input - /// ## input - /// Complex number c = r⋅𝑒^(t𝑖). - /// - /// # Output - /// Phase Arg(c) = t. - function ArgComplexPolar(input : ComplexPolar) : Double { input.Argument } - - /// # Summary - /// Returns the unary negation of an input of type `Complex`. - /// - /// # Input - /// ## input - /// A value whose negation is to be returned. - /// - /// # Output - /// The unary negation of `input`. - function NegationC(input : Complex) : Complex { - Complex(-input.Real, -input.Imag) - } - - /// # Summary - /// Returns the unary negation of an input of type `ComplexPolar` - /// - /// # Input - /// ## input - /// A value whose negation is to be returned. - /// - /// # Output - /// The unary negation of `input`. - function NegationCP(input : ComplexPolar) : ComplexPolar { - ComplexPolar(input.Magnitude, input.Argument + PI()) - } - - /// # Summary - /// Returns the sum of two inputs of type `Complex`. - /// - /// # Input - /// ## a - /// The first input a to be summed. - /// ## b - /// The second input b to be summed. - /// - /// # Output - /// The sum a + b. - function PlusC(a : Complex, b : Complex) : Complex { - Complex(a.Real + b.Real, a.Imag + b.Imag) - } - - /// # Summary - /// Returns the sum of two inputs of type `ComplexPolar`. - /// - /// # Input - /// ## a - /// The first input a to be summed. - /// ## b - /// The second input b to be summed. - /// - /// # Output - /// The sum a + b. - function PlusCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { - ComplexAsComplexPolar( - PlusC( - ComplexPolarAsComplex(a), - ComplexPolarAsComplex(b) - ) - ) - } - - /// # Summary - /// Returns the difference between two inputs of type `Complex`. - /// - /// # Input - /// ## a - /// The first input a to be subtracted. - /// ## b - /// The second input b to be subtracted. - /// - /// # Output - /// The difference a - b. - function MinusC(a : Complex, b : Complex) : Complex { - Complex(a.Real - b.Real, a.Imag - b.Imag) - } - - /// # Summary - /// Returns the difference between two inputs of type `ComplexPolar`. - /// - /// # Input - /// ## a - /// The first input a to be subtracted. - /// ## b - /// The second input b to be subtracted. - /// - /// # Output - /// The difference a - b. - function MinusCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { - PlusCP(a, NegationCP(b)) - } - - /// # Summary - /// Returns the product of two inputs of type `Complex`. - /// - /// # Input - /// ## a - /// The first input a to be multiplied. - /// ## b - /// The second input b to be multiplied. - /// - /// # Output - /// The product a⋅b. - function TimesC(a : Complex, b : Complex) : Complex { - Complex( - a.Real * b.Real - a.Imag * b.Imag, - a.Real * b.Imag + a.Imag * b.Real - ) - } - - /// # Summary - /// Returns the product of two inputs of type `ComplexPolar`. - /// - /// # Input - /// ## a - /// The first input a to be multiplied. - /// ## b - /// The second input b to be multiplied. - /// - /// # Output - /// The product a⋅b. - function TimesCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { - ComplexPolar( - a.Magnitude * b.Magnitude, - a.Argument + b.Argument - ) - } - - /// # Summary - /// Internal. Since it is easiest to define the power of two complex numbers - /// in Cartesian form as returning in polar form, we define that here, then - /// convert as needed. - /// Note that this is a multi-valued function, but only one value is returned. - internal function PowCAsCP(base : Complex, power : Complex) : ComplexPolar { - let (a, b) = (base.Real, base.Imag); - let (c, d) = (power.Real, power.Imag); - let baseSqNorm = a * a + b * b; - let baseNorm = Sqrt(baseSqNorm); - let baseArg = ArgComplex(base); - - // We pick the principal value of the multi-valued complex function ㏑ as - // ㏑(a+b𝑖) = ln(|a+b𝑖|) + 𝑖⋅arg(a+b𝑖) = ln(baseNorm) + 𝑖⋅baseArg - // Therefore - // base^power = (a+b𝑖)^(c+d𝑖) = 𝑒^( (c+d𝑖)⋅㏑(a+b𝑖) ) = - // = 𝑒^( (c+d𝑖)⋅(ln(baseNorm)+𝑖⋅baseArg) ) = - // = 𝑒^( (c⋅ln(baseNorm) - d⋅baseArg) + 𝑖⋅(c⋅baseArg + d⋅ln(baseNorm)) ) - // magnitude = 𝑒^((c⋅ln(baseNorm) - d⋅baseArg)) = baseNorm^c / 𝑒^(d⋅baseArg) - // angle = d⋅ln(baseNorm) + c⋅baseArg - - let magnitude = baseNorm^c / E()^(d * baseArg); - let angle = d * Log(baseNorm) + c * baseArg; - - ComplexPolar(magnitude, angle) - } - - /// # Summary - /// Returns a number raised to a given power of type `Complex`. - /// Note that this is a multi-valued function, but only one value is returned. - /// - /// # Input - /// ## a - /// The number a that is to be raised. - /// ## power - /// The power b to which a should be raised. - /// - /// # Output - /// The power a^b - function PowC(a : Complex, power : Complex) : Complex { - ComplexPolarAsComplex(PowCAsCP(a, power)) - } - - /// # Summary - /// Returns a number raised to a given power of type `ComplexPolar`. - /// Note that this is a multi-valued function, but only one value is returned. - /// - /// # Input - /// ## a - /// The number a that is to be raised. - /// ## power - /// The power b to which a should be raised. - /// - /// # Output - /// The power a^b - function PowCP(a : ComplexPolar, power : ComplexPolar) : ComplexPolar { - PowCAsCP(ComplexPolarAsComplex(a), ComplexPolarAsComplex(power)) - } - - /// # Summary - /// Returns the quotient of two inputs of type `Complex`. - /// - /// # Input - /// ## a - /// The first input a to be divided. - /// ## b - /// The second input b to be divided. - /// - /// # Output - /// The quotient a / b. - function DividedByC(a : Complex, b : Complex) : Complex { - let sqNorm = b.Real * b.Real + b.Imag * b.Imag; - Complex( - (a.Real * b.Real + a.Imag * b.Imag) / sqNorm, - (a.Imag * b.Real - a.Real * b.Imag) / sqNorm - ) - } - - /// # Summary - /// Returns the quotient of two inputs of type `ComplexPolar`. - /// - /// # Input - /// ## a - /// The first input a to be divided. - /// ## b - /// The second input b to be divided. - /// - /// # Output - /// The quotient a / b. - function DividedByCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { - ComplexPolar(a.Magnitude / b.Magnitude, a.Argument - b.Argument) - } - - // - // Fixed point - // - - /// # Summary - /// Returns the smallest representable number for specific fixed point dimensions. - /// - /// # Input - /// ## integerBits - /// Number of integer bits (including the sign bit). - /// ## fractionalBits - /// Number of fractional bits. - /// - /// # Remark - /// The value can be computed as -2^(p-1), where p is the number of integer bits. - function SmallestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { - -(2.0^IntAsDouble(integerBits - 1)) - } - - /// # Summary - /// Returns the largest representable number for specific fixed point dimensions. - /// - /// # Input - /// ## integerBits - /// Number of integer bits (including the sign bit). - /// ## fractionalBits - /// Number of fractional bits. - /// - /// # Remark - /// The value can be computed as 2^(p-1) - 2^(-q), where p - /// is the number of integer bits and q is the number of fractional bits. - function LargestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { - 2.0^IntAsDouble(integerBits - 1) - 2.0^(-IntAsDouble(fractionalBits)) - } - - export PI, E, LogOf2, IsNaN, IsInfinite, SignI, SignD, SignL, AbsI, AbsD, AbsL, MaxI, MaxD, MaxL, MinI, MinD, MinL, Max, Min, ArcCos, ArcSin, ArcTan, ArcTan2, Cos, Cosh, Sin, Sinh, Tan, Tanh, ArcCosh, ArcSinh, ArcTanh, Sqrt, Log, Log10, Lg, Truncate, Ceiling, Floor, Round, DivRemI, DivRemL, ModulusI, ModulusL, ExpModI, ExpModL, InverseModI, InverseModL, GreatestCommonDivisorI, GreatestCommonDivisorL, ExtendedGreatestCommonDivisorI, ExtendedGreatestCommonDivisorL, IsCoprimeI, IsCoprimeL, ContinuedFractionConvergentI, ContinuedFractionConvergentL, RealMod, BitSizeI, BitSizeL, TrailingZeroCountI, TrailingZeroCountL, HammingWeightI, FactorialI, FactorialL, ApproximateFactorial, LogGammaD, LogFactorialD, Binom, SquaredNorm, PNorm, PNormalized, Complex, ComplexPolar, AbsSquaredComplex, AbsComplex, ArgComplex, AbsSquaredComplexPolar, AbsComplexPolar, ArgComplexPolar, NegationC, NegationCP, PlusC, PlusCP, MinusC, MinusCP, TimesC, TimesCP, PowC, PowCP, DividedByC, DividedByCP, SmallestFixedPoint, LargestFixedPoint; -} diff --git a/library/std/src/measurement.qs b/library/std/src/measurement.qs deleted file mode 100644 index ea5c2dd608..0000000000 --- a/library/std/src/measurement.qs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Measurement { - open Microsoft.Quantum.Core; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Diagnostics; - open QIR.Intrinsic; - - /// # Summary - /// Jointly measures a register of qubits in the Pauli Z basis. - /// - /// # Description - /// Measures a register of qubits in the `Z ⊗ Z ⊗ ••• ⊗ Z` - /// basis, representing the parity of the entire register. - /// This operation does not reset the measured qubits to the |0⟩ state, - /// leaving them in the state that corresponds to the measurement result. - /// - /// # Input - /// ## register - /// The register to be jointly measured. - /// - /// # Output - /// The result of measuring in the `Z ⊗ Z ⊗ ••• ⊗ Z` basis. - /// - /// # See also - /// - Microsoft.Quantum.Measurement.MeasureEachZ - operation MeasureAllZ(register : Qubit[]) : Result { - Measure(Repeated(PauliZ, Length(register)), register) - } - - /// # Summary - /// Measures each qubit in a given array in the standard basis. - /// - /// # Description - /// Measures each qubit in a register in the `Z` basis - /// and retuns the result of each measurement. - /// This operation does not reset the measured qubits to the |0⟩ state, - /// leaving them in the state that corresponds to the measurement results. - /// - /// # Input - /// ## targets - /// An array of qubits to be measured. - /// # Output - /// An array of measurement results. - /// - /// # Remarks - /// Please note the following differences: - /// - Operation `MeasureEachZ` performs one measurement for each qubit and retuns - /// an array of results. The operation does not reset the qubits. - /// - Operation `MResetEachZ` performs one measurement for each qubit and retuns - /// an array of results. The operation resets all qubits to |0⟩ state. - /// - Operation `MeasureAllZ` performs a joint measurement on all qubits - /// and returns one result. The operation does not reset the qubits. - /// - /// # See also - /// - Microsoft.Quantum.Measurement.MeasureAllZ - /// - Microsoft.Quantum.Measurement.MResetEachZ - operation MeasureEachZ(register : Qubit[]) : Result[] { - mutable results = []; - for qubit in register { - set results += [M(qubit)]; - } - results - } - - /// # Summary - /// Measures each qubit in a given array in the Z basis - /// and resets them to a fixed initial state. - /// - /// # Input - /// ## targets - /// An array of qubits to be measured. - /// - /// # Output - /// An array of measurement results. - /// - /// # See also - /// - Microsoft.Quantum.Measurement.MeasureEachZ - operation MResetEachZ(register : Qubit[]) : Result[] { - mutable results = []; - for qubit in register { - set results += [MResetZ(qubit)]; - } - results - } - - /// # Summary - /// Measures a single qubit in the X basis, - /// and resets it to a fixed initial state - /// following the measurement. - /// - /// # Description - /// Performs a single-qubit measurement in the X-basis, - /// and ensures that the qubit is returned to |0⟩ - /// following the measurement. - /// - /// # Input - /// ## target - /// A single qubit to be measured. - /// - /// # Output - /// The result of measuring `target` in the Pauli X basis. - operation MResetX(target : Qubit) : Result { - // Map the qubit's state from the Z-basis to the X-basis. - // Then measure and reset the qubit. - H(target); - MResetZ(target) - } - - /// # Summary - /// Measures a single qubit in the Y basis, - /// and resets it to a fixed initial state - /// following the measurement. - /// - /// # Description - /// Performs a single-qubit measurement in the Y-basis, - /// and ensures that the qubit is returned to |0⟩ - /// following the measurement. - /// - /// # Input - /// ## target - /// A single qubit to be measured. - /// - /// # Output - /// The result of measuring `target` in the Pauli Y basis. - operation MResetY(target : Qubit) : Result { - // Map the qubit's state from the Z-basis to the Y-basis. - // Then measure and reset the qubit. - // Note: this use HSadj instead of HSH since that is sufficient for measurement. - Adjoint S(target); - H(target); - MResetZ(target) - } - - /// # Summary - /// Measures a single qubit in the Z basis, - /// and resets it to a fixed initial state - /// following the measurement. - /// - /// # Description - /// Performs a single-qubit measurement in the Z-basis, - /// and ensures that the qubit is returned to |0⟩ - /// following the measurement. - /// - /// # Input - /// ## target - /// A single qubit to be measured. - /// - /// # Output - /// The result of measuring `target` in the Pauli Z basis. - operation MResetZ(target : Qubit) : Result { - __quantum__qis__mresetz__body(target) - } - - /// # Summary - /// Measures the content of a quantum register and converts - /// it to an integer. The measurement is performed with respect - /// to the standard computational basis, i.e., the eigenbasis of `PauliZ`. - /// - /// # Input - /// ## target - /// A quantum register in the little-endian encoding. - /// - /// # Output - /// An unsigned integer that contains the measured value of `target`. - /// - /// # Remarks - /// This operation resets its input register to the |00...0> state, - /// suitable for releasing back to a target machine. - operation MeasureInteger(target : Qubit[]) : Int { - let nBits = Length(target); - Fact(nBits < 64, $"`Length(target)` must be less than 64, but was {nBits}."); - - mutable number = 0; - for i in 0..nBits - 1 { - if (MResetZ(target[i]) == One) { - set number |||= 1 <<< i; - } - } - - number - } - export MeasureAllZ, MeasureEachZ, MResetEachZ, MResetX, MResetY, MResetZ, MeasureInteger; - -} diff --git a/library/std/src/modern_api.qs b/library/std/src/modern_api.qs deleted file mode 100644 index 91b9aa43bb..0000000000 --- a/library/std/src/modern_api.qs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - - -// This file re-exports the standard library under the name `Std`, which will be the preferred standard library API going forward. - -namespace Std { - export - Microsoft.Quantum.Arrays, - Microsoft.Quantum.Canon, - Microsoft.Quantum.Convert, - Microsoft.Quantum.Core, - Microsoft.Quantum.Diagnostics, - Microsoft.Quantum.Logical, - Microsoft.Quantum.Intrinsic, - Microsoft.Quantum.Math, - Microsoft.Quantum.Measurement, - Microsoft.Quantum.Random, - Microsoft.Quantum.ResourceEstimation; -} diff --git a/library/std/src/qir.qs b/library/std/src/qir.qs deleted file mode 100644 index f123ffe861..0000000000 --- a/library/std/src/qir.qs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace QIR.Intrinsic { - - // Controlled Gates - - operation __quantum__qis__ccx__body(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__cx__body(control : Qubit, target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__cy__body(control : Qubit, target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__cz__body(control : Qubit, target : Qubit) : Unit { - body intrinsic; - } - - // Rotation Gates - - operation __quantum__qis__rx__body(angle : Double, target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__rxx__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__ry__body(angle : Double, target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__ryy__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__rz__body(angle : Double, target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__rzz__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { - body intrinsic; - } - - // Single-Qubit Gates - - operation __quantum__qis__h__body(target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__s__body(target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__s__adj(target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__t__body(target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__t__adj(target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__x__body(target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__y__body(target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__z__body(target : Qubit) : Unit { - body intrinsic; - } - - // Two-Qubit Gates - - operation __quantum__qis__swap__body(target1 : Qubit, target2 : Qubit) : Unit { - body intrinsic; - } - - // Quantum Measurement - - operation __quantum__qis__m__body(target : Qubit) : Result { - body intrinsic; - } - - operation __quantum__qis__reset__body(target : Qubit) : Unit { - body intrinsic; - } - - operation __quantum__qis__mresetz__body(target : Qubit) : Result { - body intrinsic; - } - - export __quantum__qis__ccx__body, __quantum__qis__cx__body, __quantum__qis__cy__body, __quantum__qis__cz__body, __quantum__qis__rx__body, __quantum__qis__rxx__body, __quantum__qis__ry__body, __quantum__qis__ryy__body, __quantum__qis__rz__body, __quantum__qis__rzz__body, __quantum__qis__h__body, __quantum__qis__s__body, __quantum__qis__s__adj, __quantum__qis__t__body, __quantum__qis__t__adj, __quantum__qis__x__body, __quantum__qis__y__body, __quantum__qis__z__body, __quantum__qis__swap__body, __quantum__qis__m__body, __quantum__qis__reset__body, __quantum__qis__mresetz__body; -} diff --git a/library/std/src/random.qs b/library/std/src/random.qs deleted file mode 100644 index c70cb51c4a..0000000000 --- a/library/std/src/random.qs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Random { - - /// # Summary - /// Draws a random integer from a uniform distribution - /// in a given inclusive range. Fails if `max < min`. - /// - /// # Input - /// ## min - /// The smallest integer to be drawn. - /// ## max - /// The largest integer to be drawn. - /// - /// # Output - /// An integer in the inclusive range from `min` to `max` with uniform - /// probability. - /// - /// # Example - /// The following Q# snippet randomly rolls a six-sided die: - /// ```qsharp - /// let roll = DrawRandomInt(1, 6); - /// ``` - @Config(Unrestricted) - operation DrawRandomInt(min : Int, max : Int) : Int { - body intrinsic; - } - - /// # Summary - /// Draws a random real number from a uniform distribution - /// in a given inclusive interval. Fails if `max < min`. - /// - /// # Input - /// ## min - /// The smallest real number to be drawn. - /// ## max - /// The largest real number to be drawn. - /// - /// # Output - /// A random real number in the inclusive interval from `min` to `max` with - /// uniform probability. - /// - /// # Example - /// The following Q# snippet randomly draws an angle between 0 and 2π: - /// ```qsharp - /// let angle = DrawRandomDouble(0.0, 2.0 * PI()); - /// ``` - @Config(Unrestricted) - operation DrawRandomDouble(min : Double, max : Double) : Double { - body intrinsic; - } - - /// # Summary - /// Given a success probability, returns a single Bernoulli trial - /// that is true with the given probability. - /// - /// # Input - /// ## successProbability - /// The probability with which true should be returned. - /// - /// # Output - /// `true` with probability `successProbability` - /// and `false` with probability `1.0 - successProbability`. - /// - /// # Example - /// The following Q# snippet samples flips from a biased coin: - /// ```qsharp - /// let flips = DrawMany(DrawRandomBool, 10, 0.6); - /// ``` - @Config(Unrestricted) - operation DrawRandomBool(successProbability : Double) : Bool { - body intrinsic; - } - - export DrawRandomInt, DrawRandomDouble, DrawRandomBool; -} diff --git a/library/std/src/re.qs b/library/std/src/re.qs deleted file mode 100644 index 8fbfac943d..0000000000 --- a/library/std/src/re.qs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.ResourceEstimation { - - // Functionality needed to instruct the resource estimator to cache estimates of a code fragment - // and reuse these estimates without executing the code fragment repeatedly. This functionality - // is only available when using resource estimator execution target. `BeginCostCaching` - // and `EndCostCaching` are not defined for other execution targets. - - /// # Summary - /// Used to specify that there's only one execution variant in `BeginEstimateCaching` - /// function - function SingleVariant() : Int { - return 0; - } - - /// # Summary - /// Informs the resource estimator of the start of the code fragment - /// for which estimates caching can be done. This function - /// is only available when using resource estimator execution target. - /// - /// # Input - /// ## name - /// The name of the code fragment. Used to distinguish it from other code fragments. - /// Typically this is the name of the operation for which estimates can be cached. - /// ## variant - /// Specific variant of the execution. Cached estimates can only be reused if the - /// variant for which they were collected and the current variant is the same. - /// - /// # Output - /// `true` indicated that the cached estimates are not yet available and the code fragment - /// needs to be executed in order to collect and cache estimates. - /// `false` indicates if cached estimates have been incorporated into the overall costs - /// and the code fragment should be skipped. - function BeginEstimateCaching(name : String, variant : Int) : Bool { - body intrinsic; - } - - /// # Summary - /// Instructs the resource estimator to stop estimates caching - /// because the code fragment in consideration is over. This function - /// is only available when using resource estimator execution target. - function EndEstimateCaching() : Unit { - body intrinsic; - } - - // Functionality needed to account for the resource estimates of an operation - // that is not implemented. Estimates that are obtained separately and passed to the - // `AccountForEstimates` become incorporated into the overall program estimates. - // This functionality is only available when using resource estimator execution target. - // `AccountForEstimates' is not defined for other execution targets. - - /// # Summary - /// Returns a tuple that can be passed to the `AccountForEstimates` operation - /// to specify that the number of auxiliary qubits is equal to the `amount`. - function AuxQubitCount(amount : Int) : (Int, Int) { - return (0, amount); - } - - /// # Summary - /// Returns a tuple that can be passed to the `AccountForEstimates` operation - /// to specify that the number of the T gates is equal to the `amount`. - function TCount(amount : Int) : (Int, Int) { - return (1, amount); - } - - /// # Summary - /// Returns a tuple that can be passed to the `AccountForEstimates` operation - /// to specify that the number of rotations is equal to the `amount`. - function RotationCount(amount : Int) : (Int, Int) { - return (2, amount); - } - - /// # Summary - /// Returns a tuple that can be passed to the `AccountForEstimates` operation - /// to specify that the rotation depth is equal to the `amount`. - function RotationDepth(amount : Int) : (Int, Int) { - return (3, amount); - } - - /// # Summary - /// Returns a tuple that can be passed to the `AccountForEstimates` operation - /// to specify that the number of the CCZ gates is equal to the `amount`. - function CczCount(amount : Int) : (Int, Int) { - return (4, amount); - } - - /// # Summary - /// Returns a tuple that can be passed to the `AccountForEstimates` operation - /// to specify that the number Measurements is equal to the `amount`. - function MeasurementCount(amount : Int) : (Int, Int) { - return (5, amount); - } - - /// # Summary - /// Pass the value returned by the function to the `AccountForEstimates` operation - /// to indicate Parallel Synthesis Sequential Pauli Computation (PSSPC) layout. - /// See https://arxiv.org/pdf/2211.07629.pdf for details. - function PSSPCLayout() : Int { - return 1; - } - - /// # Summary - /// Account for the resource estimates of an unimplemented operation, - /// which were obtained separately. This operation is only available - /// when using resource estimator execution target. - /// # Input - /// ## cost - /// Array of tuples containing resource estimates of the operation. For example, - /// if the operation uses three T gates, pass the tuple returned by TCount(3) - /// as one of the array elements. - /// ## layout - /// Provides the layout scheme that is used to convert logical resource estimates - /// to physical resource estimates. Only PSSPCLayout() is supported at this time. - /// ## arguments - /// Operation takes these qubits as its arguments. - operation AccountForEstimates(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit is Adj { - body ... { - AccountForEstimatesInternal(estimates, layout, arguments); - } - adjoint self; - } - - internal operation AccountForEstimatesInternal(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit { - body intrinsic; - } - - /// # Summary - /// Instructs the resource estimator to assume that the resources from the - /// call of this operation until a call to `EndRepeatEstimates` are - /// accounted for `count` times, without the need to execute the code that many - /// times. Calls to `BeginRepeatEstimates` and `EndRepeatEstimates` can be nested. - /// A helper operation `RepeatEstimates` allows to call the two functions in a - /// `within` block. - /// - /// # Input - /// ## count - /// Assumed number of repetitions, factor to multiply the cost with - operation BeginRepeatEstimates(count : Int) : Unit { - body ... { - BeginRepeatEstimatesInternal(count); - } - adjoint self; - } - - internal operation BeginRepeatEstimatesInternal(count : Int) : Unit { - body intrinsic; - } - - /// # Summary - /// Companion operation to `BeginRepeatEstimates`. - operation EndRepeatEstimates() : Unit { - body ... { - EndRepeatEstimatesInternal(); - } - adjoint self; - } - - internal operation EndRepeatEstimatesInternal() : Unit { - body intrinsic; - } - - /// # Summary - /// Instructs the resource estimator to assume that the resources from the - /// call of this operation until a call to `Adjoint RepeatEstimates` are - /// accounted for `count` times, without the need to execute the code that many - /// times. - /// - /// # Input - /// ## count - /// Assumed number of repetitions, factor to multiply the cost with - operation RepeatEstimates(count : Int) : Unit is Adj { - body ... { - BeginRepeatEstimates(count); - } - adjoint ... { - EndRepeatEstimates(); - } - } - export SingleVariant, BeginEstimateCaching, EndEstimateCaching, AuxQubitCount, TCount, RotationCount, RotationDepth, CczCount, MeasurementCount, PSSPCLayout, AccountForEstimates, BeginRepeatEstimates, EndRepeatEstimates, RepeatEstimates; -} diff --git a/library/std/src/unstable_arithmetic.qs b/library/std/src/unstable_arithmetic.qs index 22ae84ae13..718ef56ca4 100644 --- a/library/std/src/unstable_arithmetic.qs +++ b/library/std/src/unstable_arithmetic.qs @@ -2,10 +2,10 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Unstable.Arithmetic { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Convert; + import Std.Arrays.*; + import Std.Diagnostics.*; + import Std.Math.*; + import Std.Convert.*; /// # Summary /// This applies the in-place majority operation to 3 qubits. diff --git a/library/std/src/unstable_arithmetic_internal.qs b/library/std/src/unstable_arithmetic_internal.qs index 5125859fa8..5638c38ce6 100644 --- a/library/std/src/unstable_arithmetic_internal.qs +++ b/library/std/src/unstable_arithmetic_internal.qs @@ -2,10 +2,10 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Unstable.Arithmetic { - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Convert; + import Std.Diagnostics.*; + import Std.Arrays.*; + import Std.Math.*; + import Std.Convert.*; /// # Summary /// Implements the outer operation for RippleCarryTTKIncByLE to conjugate diff --git a/library/std/src/unstable_state_preparation.qs b/library/std/src/unstable_state_preparation.qs index dfc3d5ebb7..1bca7fcf0a 100644 --- a/library/std/src/unstable_state_preparation.qs +++ b/library/std/src/unstable_state_preparation.qs @@ -2,10 +2,10 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Unstable.StatePreparation { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Math; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Arrays.*; + import Std.Math.*; /// # Summary /// Given a set of coefficients and a big-endian quantum register, diff --git a/library/std/src/unstable_table_lookup.qs b/library/std/src/unstable_table_lookup.qs index 5ff35395b6..dba2a50e1f 100644 --- a/library/std/src/unstable_table_lookup.qs +++ b/library/std/src/unstable_table_lookup.qs @@ -2,12 +2,12 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Unstable.TableLookup { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.ResourceEstimation; - open Microsoft.Quantum.Unstable.Arithmetic; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Math.*; + import Std.ResourceEstimation.*; + import Microsoft.Quantum.Unstable.Arithmetic.*; /// # Summary /// Performs table lookup using a SELECT network diff --git a/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index 4e5178e7f0..4edca62089 100644 --- a/npm/qsharp/test/basics.js +++ b/npm/qsharp/test/basics.js @@ -61,8 +61,9 @@ test("autogenerated documentation", async () => { } const namespace = match[1]; assert( - namespace.startsWith("Microsoft.Quantum."), - "Namespaces in the standard library should start with Microsoft.Quantum.", + namespace.startsWith("Std.") || namespace.startsWith("Microsoft.Quantum"), + // old libraries like Unstable are still in M.Q, but newer ones are in Std. + "Namespaces in the standard library should start with Std. or Microsoft.Quantum", ); numberOfGoodFiles++; } @@ -397,7 +398,7 @@ test("state change", async () => { test("cancel worker", () => { return new Promise((resolve) => { const code = `namespace MyQuantumApp { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Result[] { @@ -510,11 +511,11 @@ test("diagnostics with related spans", async () => { message: "found in this namespace", range: { start: { - character: 11, + character: 13, line: 2, }, end: { - character: 40, + character: 28, line: 2, }, }, @@ -550,7 +551,7 @@ test("diagnostics with related spans", async () => { 1, `namespace Other { operation DumpMachine() : Unit { } } namespace Test { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; open Other; @EntryPoint() operation Main() : Unit { diff --git a/pip/README.md b/pip/README.md index 22b065d371..29fe1adc35 100644 --- a/pip/README.md +++ b/pip/README.md @@ -25,7 +25,7 @@ Then, use the `%%qsharp` cell magic to run Q# directly in Jupyter notebook cells ```qsharp %%qsharp -open Microsoft.Quantum.Diagnostics; +import Std.Diagnostics.*; @EntryPoint() operation BellState() : Unit { diff --git a/pip/tests-integration/resources/ArithmeticOps.qs b/pip/tests-integration/resources/ArithmeticOps.qs index 874c1c6dcc..4dff49b1c0 100644 --- a/pip/tests-integration/resources/ArithmeticOps.qs +++ b/pip/tests-integration/resources/ArithmeticOps.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Demonstrates use of arithmetic operations on integers at runtime. // Expected output: (5, 25, 0, 243) diff --git a/pip/tests-integration/resources/BernsteinVaziraniNISQ.qs b/pip/tests-integration/resources/BernsteinVaziraniNISQ.qs index 466cc6927f..361635f5e0 100644 --- a/pip/tests-integration/resources/BernsteinVaziraniNISQ.qs +++ b/pip/tests-integration/resources/BernsteinVaziraniNISQ.qs @@ -7,12 +7,12 @@ /// /// This Q# program implements the Bernstein-Vazirani algorithm. namespace Test { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Intrinsic.*; + import Std.Math.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { diff --git a/pip/tests-integration/resources/ConstantFolding.qs b/pip/tests-integration/resources/ConstantFolding.qs index e152d6ed70..1f02c93a2f 100644 --- a/pip/tests-integration/resources/ConstantFolding.qs +++ b/pip/tests-integration/resources/ConstantFolding.qs @@ -1,8 +1,8 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Canon.*; + import Std.Measurement.*; // Verifies constant folding, unrolling, optimizing out of invalid array access, array concatenation. // Expected output: [1, 1, 1, 1] diff --git a/pip/tests-integration/resources/CopyAndUpdateExpressions.qs b/pip/tests-integration/resources/CopyAndUpdateExpressions.qs index 70f01ea37b..73f79df03f 100644 --- a/pip/tests-integration/resources/CopyAndUpdateExpressions.qs +++ b/pip/tests-integration/resources/CopyAndUpdateExpressions.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Demonstrates copy and update expressions. // Expected output: ([1], [0], [1, 1, 1]) diff --git a/pip/tests-integration/resources/DeutschJozsaNISQ.qs b/pip/tests-integration/resources/DeutschJozsaNISQ.qs index da1fa047f3..715ac8b1a7 100644 --- a/pip/tests-integration/resources/DeutschJozsaNISQ.qs +++ b/pip/tests-integration/resources/DeutschJozsaNISQ.qs @@ -9,8 +9,8 @@ /// This Q# program implements the Deutsch–Jozsa algorithm. namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; @EntryPoint() operation Main() : (Result[], Result[]) { diff --git a/pip/tests-integration/resources/ExpandedTests.qs b/pip/tests-integration/resources/ExpandedTests.qs index 04dc716f39..c993b60513 100644 --- a/pip/tests-integration/resources/ExpandedTests.qs +++ b/pip/tests-integration/resources/ExpandedTests.qs @@ -2,12 +2,12 @@ // Licensed under the MIT License. namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Canon; + import Std.Intrinsic.*; + import Std.Convert.*; + import Std.Math.*; + import Std.Arrays.*; + import Std.Measurement.*; + import Std.Canon.*; @EntryPoint() operation Main() : (Result[], Result) { diff --git a/pip/tests-integration/resources/Functors.qs b/pip/tests-integration/resources/Functors.qs index d0568ee52e..eb787841c0 100644 --- a/pip/tests-integration/resources/Functors.qs +++ b/pip/tests-integration/resources/Functors.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies use of Q# functors. // Expected simulation output: diff --git a/pip/tests-integration/resources/HiddenShiftNISQ.qs b/pip/tests-integration/resources/HiddenShiftNISQ.qs index 974a18d30c..ad0477ef68 100644 --- a/pip/tests-integration/resources/HiddenShiftNISQ.qs +++ b/pip/tests-integration/resources/HiddenShiftNISQ.qs @@ -9,11 +9,11 @@ /// /// This Q# program implements an algorithm to solve the hidden shift problem. namespace Test { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Intrinsic.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { diff --git a/pip/tests-integration/resources/IntegerComparison.qs b/pip/tests-integration/resources/IntegerComparison.qs index 7b12436310..1218558b29 100644 --- a/pip/tests-integration/resources/IntegerComparison.qs +++ b/pip/tests-integration/resources/IntegerComparison.qs @@ -1,6 +1,6 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; + import Std.Intrinsic.*; // Demonstrates use of integer comparisons. // Expected output: (true, false, true) diff --git a/pip/tests-integration/resources/IntrinsicCCNOT.qs b/pip/tests-integration/resources/IntrinsicCCNOT.qs index ed0abb1338..d6aeafb644 100644 --- a/pip/tests-integration/resources/IntrinsicCCNOT.qs +++ b/pip/tests-integration/resources/IntrinsicCCNOT.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies the use of the CCNOT quantum gate from Q#'s Microsoft.Quantum.Intrinsic namespace. // Expected simulation output: ([0, 0, 0], [1, 0, 0], [1, 1, 1]). diff --git a/pip/tests-integration/resources/IntrinsicCNOT.qs b/pip/tests-integration/resources/IntrinsicCNOT.qs index f6ac3834ea..a5b783e1e1 100644 --- a/pip/tests-integration/resources/IntrinsicCNOT.qs +++ b/pip/tests-integration/resources/IntrinsicCNOT.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies the use of the CNOT quantum gate from Q#'s Microsoft.Quantum.Intrinsic namespace. // Expected simulation output: ([0, 0], [1, 1]). diff --git a/pip/tests-integration/resources/IntrinsicHIXYZ.qs b/pip/tests-integration/resources/IntrinsicHIXYZ.qs index 4058500b36..467b53f822 100644 --- a/pip/tests-integration/resources/IntrinsicHIXYZ.qs +++ b/pip/tests-integration/resources/IntrinsicHIXYZ.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies the I, H, X, Y, and Z quantum gates from Q#'s Microsoft.Quantum.Intrinsic namespace. // Expected simulation output: (1, 1, 1, 1, 1, 1). diff --git a/pip/tests-integration/resources/IntrinsicM.qs b/pip/tests-integration/resources/IntrinsicM.qs index 6296a67d56..cf46449e1f 100644 --- a/pip/tests-integration/resources/IntrinsicM.qs +++ b/pip/tests-integration/resources/IntrinsicM.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies the use of the M gate from Q#'s Microsoft.Quantum.Intrinsic namespace. // Expected simulation output: (0, 1). diff --git a/pip/tests-integration/resources/IntrinsicMeasureWithBitFlipCode.qs b/pip/tests-integration/resources/IntrinsicMeasureWithBitFlipCode.qs index 026b3c3605..2a5779b8b5 100644 --- a/pip/tests-integration/resources/IntrinsicMeasureWithBitFlipCode.qs +++ b/pip/tests-integration/resources/IntrinsicMeasureWithBitFlipCode.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies the use of the Measure operation from Q#'s Microsoft.Quantum.Intrinsic namespace. // Expected simulation output: ([0, 0], [0, 1], [0, 0, 1]). diff --git a/pip/tests-integration/resources/IntrinsicMeasureWithPhaseFlipCode.qs b/pip/tests-integration/resources/IntrinsicMeasureWithPhaseFlipCode.qs index cbcc95f8bf..81e69a1632 100644 --- a/pip/tests-integration/resources/IntrinsicMeasureWithPhaseFlipCode.qs +++ b/pip/tests-integration/resources/IntrinsicMeasureWithPhaseFlipCode.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies the use of the Measure operation from Q#'s Microsoft.Quantum.Intrinsic namespace. // Expected simulation output: ([0, 0], [1, 1], [0, 1, 0]). diff --git a/pip/tests-integration/resources/IntrinsicRotationsWithPeriod.qs b/pip/tests-integration/resources/IntrinsicRotationsWithPeriod.qs index 3eee901ed8..eca68a1ee5 100644 --- a/pip/tests-integration/resources/IntrinsicRotationsWithPeriod.qs +++ b/pip/tests-integration/resources/IntrinsicRotationsWithPeriod.qs @@ -1,8 +1,8 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Math.*; + import Std.Measurement.*; // Verifies the use of the rotation quantum operations from Q#'s Microsoft.Quantum.Intrinsic namespace. // Expected simulation output: ([1, 1], [1, 1], [1, 1]). diff --git a/pip/tests-integration/resources/IntrinsicSTSWAP.qs b/pip/tests-integration/resources/IntrinsicSTSWAP.qs index ffd5eef59b..181633c50b 100644 --- a/pip/tests-integration/resources/IntrinsicSTSWAP.qs +++ b/pip/tests-integration/resources/IntrinsicSTSWAP.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies the use of the S, SWAP and T operations from Q#'s Microsoft.Quantum.Intrinsic namespace. // Expected simulation output: (1, 1, [1, 0]). diff --git a/pip/tests-integration/resources/MeasureAndReuse.qs b/pip/tests-integration/resources/MeasureAndReuse.qs index 7e4d73f221..7870d64e7b 100644 --- a/pip/tests-integration/resources/MeasureAndReuse.qs +++ b/pip/tests-integration/resources/MeasureAndReuse.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Reusing a qubit after `M` should work on supported platforms, be replaced by entanglement with auxiliary on others. // Reusing a qubit after `Reset` should work on supported platforms, be replaced by newly allocated qubit on others. diff --git a/pip/tests-integration/resources/MeasurementComparison.qs b/pip/tests-integration/resources/MeasurementComparison.qs index a243f28477..aecc5b7a4b 100644 --- a/pip/tests-integration/resources/MeasurementComparison.qs +++ b/pip/tests-integration/resources/MeasurementComparison.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Intrinsic; + import Std.Arrays.*; + import Std.Intrinsic.*; // Demonstrates use of measurement comparisons, including ternary. // Expected output: (true, false, true, true) diff --git a/pip/tests-integration/resources/NestedBranching.qs b/pip/tests-integration/resources/NestedBranching.qs index d3ce24a0c7..52108d70ee 100644 --- a/pip/tests-integration/resources/NestedBranching.qs +++ b/pip/tests-integration/resources/NestedBranching.qs @@ -1,8 +1,8 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Math.*; + import Std.Measurement.*; // Demonstrates nested branching. // Expected output: (([1, 1, 0], 6), ([1, 1, 1, 0], true)) diff --git a/pip/tests-integration/resources/RandomBit.qs b/pip/tests-integration/resources/RandomBit.qs index 76e818951d..b2ebaca677 100644 --- a/pip/tests-integration/resources/RandomBit.qs +++ b/pip/tests-integration/resources/RandomBit.qs @@ -1,6 +1,6 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; + import Std.Intrinsic.*; @EntryPoint() operation Main() : Result { diff --git a/pip/tests-integration/resources/SampleTeleport.qs b/pip/tests-integration/resources/SampleTeleport.qs index 977546a99c..59d639a46b 100644 --- a/pip/tests-integration/resources/SampleTeleport.qs +++ b/pip/tests-integration/resources/SampleTeleport.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Arrays.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Result { diff --git a/pip/tests-integration/resources/ShortcuttingMeasurement.qs b/pip/tests-integration/resources/ShortcuttingMeasurement.qs index 2c3778637b..d54c7f0e2f 100644 --- a/pip/tests-integration/resources/ShortcuttingMeasurement.qs +++ b/pip/tests-integration/resources/ShortcuttingMeasurement.qs @@ -1,6 +1,6 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; + import Std.Intrinsic.*; // Demonstrates shortcutting of measurement ops in conditionals. // Expected output: (0, 0) diff --git a/pip/tests-integration/resources/Slicing.qs b/pip/tests-integration/resources/Slicing.qs index 17e316f61f..d8d40f92da 100644 --- a/pip/tests-integration/resources/Slicing.qs +++ b/pip/tests-integration/resources/Slicing.qs @@ -1,8 +1,8 @@ namespace Test { - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Canon.*; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies loop over subset of index range, constant folding division of array length, array slicing, qubit reindexing, reverse iteration. // Expected output: [1, 1, 1, 1, 1]. diff --git a/pip/tests-integration/resources/SwitchHandling.qs b/pip/tests-integration/resources/SwitchHandling.qs index 7294684609..135dd93dfe 100644 --- a/pip/tests-integration/resources/SwitchHandling.qs +++ b/pip/tests-integration/resources/SwitchHandling.qs @@ -1,8 +1,8 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Math; + import Std.Intrinsic.*; + import Std.Measurement.*; + import Std.Math.*; // Demonstrates using a computed integer to do a branch that gets turned into a switch instruction // (should get transformed back into nested branches). diff --git a/pip/tests-integration/resources/ThreeQubitRepetitionCode.qs b/pip/tests-integration/resources/ThreeQubitRepetitionCode.qs index b563caf4e7..d1352322b7 100644 --- a/pip/tests-integration/resources/ThreeQubitRepetitionCode.qs +++ b/pip/tests-integration/resources/ThreeQubitRepetitionCode.qs @@ -1,6 +1,6 @@ namespace Test { - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Diagnostics; + import Std.Math.*; + import Std.Diagnostics.*; @EntryPoint() operation Main() : (Bool, Int) { diff --git a/pip/tests-integration/resources/WithinApply.qs b/pip/tests-integration/resources/WithinApply.qs index 7496168f12..fa5a41c0bd 100644 --- a/pip/tests-integration/resources/WithinApply.qs +++ b/pip/tests-integration/resources/WithinApply.qs @@ -1,7 +1,7 @@ namespace Test { - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Intrinsic.*; + import Std.Measurement.*; // Verifies use of Q# within apply construct. // Expected simulation output: [0, 0, 1] diff --git a/pip/tests/test_interpreter.py b/pip/tests/test_interpreter.py index 67a7fc352d..f2b90a97c8 100644 --- a/pip/tests/test_interpreter.py +++ b/pip/tests/test_interpreter.py @@ -348,7 +348,7 @@ def test_adaptive_errors_are_raised_from_entry_expr() -> None: def test_adaptive_ri_qir_can_be_generated() -> None: adaptive_input = """ namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; open QIR.Intrinsic; @EntryPoint() operation Main() : Result { @@ -412,7 +412,7 @@ def test_adaptive_ri_qir_can_be_generated() -> None: def test_base_qir_can_be_generated() -> None: base_input = """ namespace Test { - open Microsoft.Quantum.Math; + import Std.Math.*; open QIR.Intrinsic; @EntryPoint() operation Main() : Result { diff --git a/pip/tests/test_re.py b/pip/tests/test_re.py index ace1e685ad..a0c205a166 100644 --- a/pip/tests/test_re.py +++ b/pip/tests/test_re.py @@ -34,7 +34,7 @@ def test_qsharp_estimation_from_precalculated_counts() -> None: qsharp.init(target_profile=qsharp.TargetProfile.Unrestricted) res = qsharp.estimate( """{{ - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; use qubits = Qubit[12581]; AccountForEstimates( [TCount(12), RotationCount(12), RotationDepth(12), diff --git a/resource_estimator/src/counts/tests.rs b/resource_estimator/src/counts/tests.rs index c7bd34b8fe..2ee1408c9a 100644 --- a/resource_estimator/src/counts/tests.rs +++ b/resource_estimator/src/counts/tests.rs @@ -83,7 +83,7 @@ fn estimate_caching_works() { verify_logical_counts( indoc! {r#" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; operation Rotate(qs: Qubit[]) : Unit { for q in qs { @@ -130,7 +130,7 @@ fn estimate_repeat_works() { verify_logical_counts( indoc! {r#" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; operation Rotate(qs: Qubit[]) : Unit { for q in qs { @@ -177,7 +177,7 @@ fn account_for_estimates_works() { verify_logical_counts( indoc! {" namespace Test { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; @EntryPoint() operation Main() : Unit { diff --git a/samples/algorithms/BellState.qs b/samples/algorithms/BellState.qs index f9b57810bb..dcc37c85d8 100644 --- a/samples/algorithms/BellState.qs +++ b/samples/algorithms/BellState.qs @@ -7,8 +7,8 @@ /// /// This Q# program implements the four different Bell states. namespace Sample { - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Measurement; + import Std.Diagnostics.*; + import Std.Measurement.*; @EntryPoint() operation BellStates() : (Result, Result)[] { diff --git a/samples/algorithms/BernsteinVazirani.qs b/samples/algorithms/BernsteinVazirani.qs index 5b28f0d242..79e3283da1 100644 --- a/samples/algorithms/BernsteinVazirani.qs +++ b/samples/algorithms/BernsteinVazirani.qs @@ -7,11 +7,11 @@ /// /// This Q# program implements the Bernstein-Vazirani algorithm. namespace Sample { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Math.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Int[] { diff --git a/samples/algorithms/BernsteinVaziraniNISQ.qs b/samples/algorithms/BernsteinVaziraniNISQ.qs index d8d83eba4d..628575c34d 100644 --- a/samples/algorithms/BernsteinVaziraniNISQ.qs +++ b/samples/algorithms/BernsteinVaziraniNISQ.qs @@ -7,11 +7,11 @@ /// /// This Q# program implements the Bernstein-Vazirani algorithm. namespace Sample { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Math.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { diff --git a/samples/algorithms/BitFlipCode.qs b/samples/algorithms/BitFlipCode.qs index 4b7910866f..d1d9004485 100644 --- a/samples/algorithms/BitFlipCode.qs +++ b/samples/algorithms/BitFlipCode.qs @@ -19,11 +19,11 @@ /// with one of the qubits being bit-flipped. It then identifies and corrects /// the flipped qubit. namespace Sample { - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Random; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Measurement; + import Std.Math.*; + import Std.Random.*; + import Std.Arrays.*; + import Std.Diagnostics.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Result { diff --git a/samples/algorithms/CatState.qs b/samples/algorithms/CatState.qs index 4eb3e2f077..fc6a1f7e6f 100644 --- a/samples/algorithms/CatState.qs +++ b/samples/algorithms/CatState.qs @@ -7,7 +7,7 @@ /// /// This Q# program implements a cat state of 5 qubits. namespace Sample { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Result[] { diff --git a/samples/algorithms/DeutschJozsa.qs b/samples/algorithms/DeutschJozsa.qs index 3ec9f1864d..3c988610b3 100644 --- a/samples/algorithms/DeutschJozsa.qs +++ b/samples/algorithms/DeutschJozsa.qs @@ -8,9 +8,9 @@ /// /// This Q# program implements the Deutsch–Jozsa algorithm. namespace Sample { - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; + import Std.Diagnostics.*; + import Std.Math.*; + import Std.Measurement.*; @EntryPoint() operation Main() : (String, Bool)[] { diff --git a/samples/algorithms/DeutschJozsaNISQ.qs b/samples/algorithms/DeutschJozsaNISQ.qs index 992d8fd5c8..bec6469b4a 100644 --- a/samples/algorithms/DeutschJozsaNISQ.qs +++ b/samples/algorithms/DeutschJozsaNISQ.qs @@ -8,7 +8,7 @@ /// /// This Q# program implements the Deutsch–Jozsa algorithm. namespace Sample { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : (Result[], Result[]) { diff --git a/samples/algorithms/DotProductViaPhaseEstimation.qs b/samples/algorithms/DotProductViaPhaseEstimation.qs index 63e9e04e7a..73fddad397 100644 --- a/samples/algorithms/DotProductViaPhaseEstimation.qs +++ b/samples/algorithms/DotProductViaPhaseEstimation.qs @@ -21,8 +21,8 @@ // SOFTWARE. namespace IterativePhaseEstimation { - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Convert; + import Std.Math.*; + import Std.Convert.*; @EntryPoint() operation Main() : (Int, Int) { diff --git a/samples/algorithms/Entanglement.qs b/samples/algorithms/Entanglement.qs index dca96c80f7..d9907aca71 100644 --- a/samples/algorithms/Entanglement.qs +++ b/samples/algorithms/Entanglement.qs @@ -7,7 +7,7 @@ /// /// This Q# program entangles two qubits. namespace Sample { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation EntangleQubits() : (Result, Result) { diff --git a/samples/algorithms/GHZ.qs b/samples/algorithms/GHZ.qs index 413d28aa3f..5bf6820d24 100644 --- a/samples/algorithms/GHZ.qs +++ b/samples/algorithms/GHZ.qs @@ -16,7 +16,7 @@ /// This Q# program prepares the GHZ state in a register of 3 qubits, then /// returns the result of measuring those qubits. namespace Sample { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Result[] { diff --git a/samples/algorithms/Grover.qs b/samples/algorithms/Grover.qs index 6159a99bc0..6c735bb417 100644 --- a/samples/algorithms/Grover.qs +++ b/samples/algorithms/Grover.qs @@ -8,11 +8,11 @@ /// /// This Q# program implements the Grover's search algorithm. namespace Sample { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Diagnostics; + import Std.Convert.*; + import Std.Math.*; + import Std.Arrays.*; + import Std.Measurement.*; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Result[] { diff --git a/samples/algorithms/HiddenShift.qs b/samples/algorithms/HiddenShift.qs index 9eff933c67..5b6f7d1d6d 100644 --- a/samples/algorithms/HiddenShift.qs +++ b/samples/algorithms/HiddenShift.qs @@ -9,10 +9,10 @@ /// /// This Q# program implements an algorithm to solve the hidden shift problem. namespace Sample { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Measurement; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Int[] { diff --git a/samples/algorithms/HiddenShiftNISQ.qs b/samples/algorithms/HiddenShiftNISQ.qs index f2955a91ba..d492d26397 100644 --- a/samples/algorithms/HiddenShiftNISQ.qs +++ b/samples/algorithms/HiddenShiftNISQ.qs @@ -9,10 +9,10 @@ /// /// This Q# program implements an algorithm to solve the hidden shift problem. namespace Sample { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Measurement; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { diff --git a/samples/algorithms/JointMeasurement.qs b/samples/algorithms/JointMeasurement.qs index 86ed63d9a6..92ae0775b8 100644 --- a/samples/algorithms/JointMeasurement.qs +++ b/samples/algorithms/JointMeasurement.qs @@ -5,7 +5,7 @@ /// Joint measurements, also known as Pauli measurements, are a generalization /// of 2-outcome measurements to multiple qubits and other bases. namespace Sample { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : (Result, Result[]) { diff --git a/samples/algorithms/Measurement.qs b/samples/algorithms/Measurement.qs index 4f0d9ad15e..b3626c1cc1 100644 --- a/samples/algorithms/Measurement.qs +++ b/samples/algorithms/Measurement.qs @@ -11,7 +11,7 @@ /// /// This Q# program exemplifies different types of measurements. namespace Sample { - open Microsoft.Quantum.Measurement; + import Std.Measurement.*; @EntryPoint() operation Main() : (Result, Result[]) { diff --git a/samples/algorithms/PhaseFlipCode.qs b/samples/algorithms/PhaseFlipCode.qs index 0a052731fd..a7337f418a 100644 --- a/samples/algorithms/PhaseFlipCode.qs +++ b/samples/algorithms/PhaseFlipCode.qs @@ -19,11 +19,11 @@ /// with one of the qubits being phase-flipped. It then identifies and corrects /// the flipped qubit. namespace Sample { - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Random; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Measurement; + import Std.Math.*; + import Std.Random.*; + import Std.Arrays.*; + import Std.Diagnostics.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Result { diff --git a/samples/algorithms/QRNG.qs b/samples/algorithms/QRNG.qs index 64e031f896..5f88d07fd7 100644 --- a/samples/algorithms/QRNG.qs +++ b/samples/algorithms/QRNG.qs @@ -5,9 +5,9 @@ /// This program implements a quantum random number generator by setting qubits /// in superposition and then using the measurement results as random bits. namespace Sample { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Math; + import Std.Convert.*; + import Std.Intrinsic.*; + import Std.Math.*; @EntryPoint() operation Main() : Int { diff --git a/samples/algorithms/QRNGNISQ.qs b/samples/algorithms/QRNGNISQ.qs index c4354b2bf1..e608bb650a 100644 --- a/samples/algorithms/QRNGNISQ.qs +++ b/samples/algorithms/QRNGNISQ.qs @@ -5,8 +5,8 @@ /// This program implements a quantum random number generator by setting qubits /// in superposition and then using the measurement results as random bits. namespace Sample { - open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Intrinsic; + import Std.Measurement.*; + import Std.Intrinsic.*; @EntryPoint() operation Main() : Result[] { diff --git a/samples/algorithms/Shor.qs b/samples/algorithms/Shor.qs index d4fae62b3b..4b08f19654 100644 --- a/samples/algorithms/Shor.qs +++ b/samples/algorithms/Shor.qs @@ -7,12 +7,12 @@ /// /// This Q# program implements Shor's algorithm. namespace Sample { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Random; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.Arrays; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Random.*; + import Std.Math.*; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Std.Arrays.*; @EntryPoint() operation Main() : (Int, Int) { diff --git a/samples/algorithms/Teleportation.qs b/samples/algorithms/Teleportation.qs index aa5cc79127..7e0dd87dba 100644 --- a/samples/algorithms/Teleportation.qs +++ b/samples/algorithms/Teleportation.qs @@ -10,9 +10,9 @@ /// /// This Q# program implements quantum teleportation. namespace Sample { - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Measurement; + import Std.Diagnostics.*; + import Std.Intrinsic.*; + import Std.Measurement.*; @EntryPoint() operation Main() : Result[] { diff --git a/samples/algorithms/ThreeQubitRepetitionCode.qs b/samples/algorithms/ThreeQubitRepetitionCode.qs index 30a7ce3dfc..7c900a7d89 100644 --- a/samples/algorithms/ThreeQubitRepetitionCode.qs +++ b/samples/algorithms/ThreeQubitRepetitionCode.qs @@ -2,8 +2,8 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Samples { - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Diagnostics; + import Std.Math.*; + import Std.Diagnostics.*; @EntryPoint() operation ThreeQubitRepetitionCode() : (Bool, Int) { diff --git a/samples/estimation/Dynamics.qs b/samples/estimation/Dynamics.qs index a985c2edf7..3fca18c31f 100644 --- a/samples/estimation/Dynamics.qs +++ b/samples/estimation/Dynamics.qs @@ -12,8 +12,8 @@ /// what size of quantum system would be needed to solve the problem. namespace QuantumDynamics { - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Arrays; + import Std.Math.*; + import Std.Arrays.*; @EntryPoint() diff --git a/samples/estimation/EkeraHastadFactoring.qs b/samples/estimation/EkeraHastadFactoring.qs index 248c7529f8..b2ea0d809e 100644 --- a/samples/estimation/EkeraHastadFactoring.qs +++ b/samples/estimation/EkeraHastadFactoring.qs @@ -9,12 +9,12 @@ /// [arXiv:1905.09749](https://arxiv.org/abs/1905.09749). This makes it ideal /// for use with the Azure Quantum Resource Estimator. namespace Microsoft.Quantum.Applications.Cryptography { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.ResourceEstimation; - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.Unstable.TableLookup; + import Std.Convert.*; + import Std.Math.*; + import Std.ResourceEstimation.*; + import Std.Arrays.*; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Microsoft.Quantum.Unstable.TableLookup.*; // !!! IMPORTANT !!! // When computing resource estimtes from the VS Code plugin directly on this diff --git a/samples/estimation/Precalculated.qs b/samples/estimation/Precalculated.qs index 801e524ee7..f5a81e676e 100644 --- a/samples/estimation/Precalculated.qs +++ b/samples/estimation/Precalculated.qs @@ -10,7 +10,7 @@ /// Our implementation incorporates all techniques described in the paper, except for /// carry runways. namespace PrecalculatedEstimates { - open Microsoft.Quantum.ResourceEstimation; + import Std.ResourceEstimation.*; @EntryPoint() operation FactoringFromLogicalCounts() : Unit { diff --git a/samples/estimation/ShorRE.qs b/samples/estimation/ShorRE.qs index 3bb148a160..7e5b65474b 100644 --- a/samples/estimation/ShorRE.qs +++ b/samples/estimation/ShorRE.qs @@ -7,15 +7,15 @@ /// we omit the classical pre- and post-processing. This makes it ideal for /// use with the Azure Quantum Resource Estimator. namespace Shors { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Measurement; - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.ResourceEstimation; + import Std.Arrays.*; + import Std.Canon.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Intrinsic.*; + import Std.Math.*; + import Std.Measurement.*; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Std.ResourceEstimation.*; @EntryPoint() operation RunProgram() : Unit { diff --git a/samples/estimation/df-chemistry/src/df_chemistry.qs b/samples/estimation/df-chemistry/src/df_chemistry.qs index 49af9c564a..25382cd96a 100644 --- a/samples/estimation/df-chemistry/src/df_chemistry.qs +++ b/samples/estimation/df-chemistry/src/df_chemistry.qs @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. namespace Microsoft.Quantum.Applications.Chemistry { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Canon; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.ResourceEstimation; - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.Unstable.TableLookup; + import Std.Arrays.*; + import Std.Canon.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Math.*; + import Std.ResourceEstimation.*; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Microsoft.Quantum.Unstable.TableLookup.*; // ------------------------------------------ // // DF chemistry (public operations and types) // diff --git a/samples/estimation/df-chemistry/src/prepare.qs b/samples/estimation/df-chemistry/src/prepare.qs index 00dda312e1..363d0252b3 100644 --- a/samples/estimation/df-chemistry/src/prepare.qs +++ b/samples/estimation/df-chemistry/src/prepare.qs @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. namespace Microsoft.Quantum.Applications.Chemistry { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Unstable.Arithmetic; - open Microsoft.Quantum.Unstable.TableLookup; + import Std.Arrays.*; + import Std.Convert.*; + import Std.Diagnostics.*; + import Std.Intrinsic.*; + import Std.Math.*; + import Microsoft.Quantum.Unstable.Arithmetic.*; + import Microsoft.Quantum.Unstable.TableLookup.*; // ------------------------------------- // // State preparation (public operations) // diff --git a/samples/python_interop/generating_n_random_bits/src/GenerateRandomNumbers.qs b/samples/python_interop/generating_n_random_bits/src/GenerateRandomNumbers.qs index e238e51f12..4756ed8e48 100644 --- a/samples/python_interop/generating_n_random_bits/src/GenerateRandomNumbers.qs +++ b/samples/python_interop/generating_n_random_bits/src/GenerateRandomNumbers.qs @@ -1,6 +1,6 @@ namespace GenerateRandom { - open Microsoft.Quantum.Arrays; - open Microsoft.Quantum.Convert; + import Std.Arrays.*; + import Std.Convert.*; operation GenerateRandomNumbers(nQubits : Int) : (Result[], Int) { use qubits = Qubit[nQubits]; diff --git a/samples/testing/operations/src/BellState.qs b/samples/testing/operations/src/BellState.qs index 4fe9753739..435acc3126 100644 --- a/samples/testing/operations/src/BellState.qs +++ b/samples/testing/operations/src/BellState.qs @@ -17,7 +17,7 @@ namespace BellState { /// 3: |Ψ-〉(PsiMinus) operation AllBellStates(qs : Qubit[], choice : Int) : Unit is Ctl + Adj { - open Microsoft.Quantum.Convert; + import Std.Convert.*; H(qs[0]); CNOT(qs[0], qs[1]); diff --git a/samples/testing/operations/src/OperationEquivalence.qs b/samples/testing/operations/src/OperationEquivalence.qs index beec07871c..56bfb861d6 100644 --- a/samples/testing/operations/src/OperationEquivalence.qs +++ b/samples/testing/operations/src/OperationEquivalence.qs @@ -2,7 +2,7 @@ // Licensed under the MIT License. namespace OperationEquivalence { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; open CustomOperation; /// # Summary /// Verifies the equivalence of quantum operations up to a global phase using `Fact` function diff --git a/vscode/src/notebookTemplate.ts b/vscode/src/notebookTemplate.ts index 78cc8f5dc3..bf3f6c45a3 100644 --- a/vscode/src/notebookTemplate.ts +++ b/vscode/src/notebookTemplate.ts @@ -44,7 +44,7 @@ import qsharp value: `%%qsharp // This makes the DumpMachine() function available. -open Microsoft.Quantum.Diagnostics; +import Std.Diagnostics.*; operation RandomBit() : Result { // Qubits are only accesible for the duration of the scope where they diff --git a/vscode/test/suites/debugger/debugger.test.ts b/vscode/test/suites/debugger/debugger.test.ts index 084a0a36c1..f88bb0b87a 100644 --- a/vscode/test/suites/debugger/debugger.test.ts +++ b/vscode/test/suites/debugger/debugger.test.ts @@ -370,16 +370,16 @@ suite("Q# Debugger Tests", function suite() { { id: 1, source: { - name: "intrinsic.qs", - path: "qsharp-library-source:intrinsic.qs", + name: "Intrinsic.qs", + path: "qsharp-library-source:Std/Intrinsic.qs", sourceReference: 0, adapterData: "qsharp-adapter-data", }, - line: 205, - column: 13, + line: 201, + column: 9, name: "H ", - endLine: 205, - endColumn: 44, + endLine: 201, + endColumn: 40, }, { id: 0, @@ -400,7 +400,7 @@ suite("Q# Debugger Tests", function suite() { // text editor should now be open on intrinsic.qs await waitForTextEditorOn( - vscode.Uri.parse("qsharp-library-source:intrinsic.qs"), + vscode.Uri.parse("qsharp-library-source:Std/Intrinsic.qs"), ); }); diff --git a/wasm/src/tests.rs b/wasm/src/tests.rs index 0f22f22361..b7d5bd27b0 100644 --- a/wasm/src/tests.rs +++ b/wasm/src/tests.rs @@ -112,7 +112,7 @@ fn fail_ry() { #[test] fn test_message() { let code = r#"namespace Sample { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; operation main() : Unit { Message("hi"); @@ -132,7 +132,7 @@ fn test_message() { #[test] fn message_with_escape_sequences() { let code = r#"namespace Sample { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; operation main() : Unit { Message("\ta\n\t"); @@ -153,7 +153,7 @@ fn message_with_escape_sequences() { #[test] fn message_with_backslashes() { let code = r#"namespace Sample { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; operation main() : Unit { Message("hi \\World"); @@ -397,7 +397,7 @@ fn test_compile_error_related_spans() { namespace Other { operation DumpMachine() : Unit { } } namespace Test { open Other; - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; @EntryPoint() operation Main() : Unit { DumpMachine() @@ -411,7 +411,7 @@ fn test_compile_error_related_spans() { 1, ) .expect_err("code should fail to compile"); - expect![[r#"{"result":{"code":"Qsc.Resolve.Ambiguous","message":"name error: `DumpMachine` could refer to the item in `Other` or `Microsoft.Quantum.Diagnostics`","range":{"end":{"character":19,"line":6},"start":{"character":8,"line":6}},"related":[{"location":{"source":"test.qs","span":{"end":{"character":19,"line":6},"start":{"character":8,"line":6}}},"message":"ambiguous name"},{"location":{"source":"test.qs","span":{"end":{"character":14,"line":2},"start":{"character":9,"line":2}}},"message":"found in this namespace"},{"location":{"source":"test.qs","span":{"end":{"character":38,"line":3},"start":{"character":9,"line":3}}},"message":"and also in this namespace"}],"severity":"error"},"success":false,"type":"Result"}"#]] + expect![[r#"{"result":{"code":"Qsc.Resolve.Ambiguous","message":"name error: `DumpMachine` could refer to the item in `Other` or `Microsoft.Quantum.Diagnostics`","range":{"end":{"character":19,"line":6},"start":{"character":8,"line":6}},"related":[{"location":{"source":"test.qs","span":{"end":{"character":19,"line":6},"start":{"character":8,"line":6}}},"message":"ambiguous name"},{"location":{"source":"test.qs","span":{"end":{"character":14,"line":2},"start":{"character":9,"line":2}}},"message":"found in this namespace"},{"location":{"source":"test.qs","span":{"end":{"character":26,"line":3},"start":{"character":11,"line":3}}},"message":"and also in this namespace"}],"severity":"error"},"success":false,"type":"Result"}"#]] .assert_eq(&output.join("\n")); }