From 9af6f075fd8ae52e200c753f4aa5f8c6e27843ac Mon Sep 17 00:00:00 2001 From: sezna Date: Mon, 9 Sep 2024 13:59:42 -0700 Subject: [PATCH 01/29] convert arrays.qs to the new stdlib --- library/src/lib.rs | 8 +- library/src/tests/diagnostics.rs | 2 +- library/src/tests/resources/src/qft_le.qs | 2 +- library/src/tests/resources/src/select.qs | 2 +- .../tests/resources/src/state_preparation.qs | 2 +- library/std/qsharp.json | 8 +- library/std/src/Std/Arrays.qs | 1486 +++++++++++++++++ library/std/src/arrays.qs | 1444 ---------------- library/std/src/internal.qs | 2 +- .../std/src/{modern_api.qs => legacy_api.qs} | 5 +- library/std/src/unstable_arithmetic.qs | 2 +- .../std/src/unstable_arithmetic_internal.qs | 2 +- library/std/src/unstable_state_preparation.qs | 2 +- library/std/src/unstable_table_lookup.qs | 2 +- 14 files changed, 1507 insertions(+), 1462 deletions(-) create mode 100644 library/std/src/Std/Arrays.qs delete mode 100644 library/std/src/arrays.qs rename library/std/src/{modern_api.qs => legacy_api.qs} (91%) diff --git a/library/src/lib.rs b/library/src/lib.rs index bef834659a..d928236f78 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -22,8 +22,8 @@ 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", @@ -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/diagnostics.rs b/library/src/tests/diagnostics.rs index 4e3de801db..208e3c6c48 100644 --- a/library/src/tests/diagnostics.rs +++ b/library/src/tests/diagnostics.rs @@ -9,7 +9,7 @@ fn check_operations_are_equal() { test_expression( "{ open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; operation op1(xs: Qubit[]): Unit is Adj { CCNOT(xs[0], xs[1], xs[2]); } diff --git a/library/src/tests/resources/src/qft_le.qs b/library/src/tests/resources/src/qft_le.qs index 7a9f7b256f..dde380be58 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.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..29793efd9b 100644 --- a/library/src/tests/resources/src/select.qs +++ b/library/src/tests/resources/src/select.qs @@ -1,5 +1,5 @@ namespace Test { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Random; diff --git a/library/src/tests/resources/src/state_preparation.qs b/library/src/tests/resources/src/state_preparation.qs index a6f573b734..c5c249e0f5 100644 --- a/library/src/tests/resources/src/state_preparation.qs +++ b/library/src/tests/resources/src/state_preparation.qs @@ -2,7 +2,7 @@ namespace Test { open Microsoft.Quantum.Convert; open Microsoft.Quantum.Math; open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; open Microsoft.Quantum.Unstable.StatePreparation; diff --git a/library/std/qsharp.json b/library/std/qsharp.json index b6af02517b..0ea6309480 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/legacy_api.qs", "src/logical.qs", "src/math.qs", "src/measurement.qs", - "src/modern_api.qs", "src/qir.qs", "src/random.qs", "src/re.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/Std/Arrays.qs" ] -} +} \ No newline at end of file diff --git a/library/std/src/Std/Arrays.qs b/library/std/src/Std/Arrays.qs new file mode 100644 index 0000000000..3253f33a1d --- /dev/null +++ b/library/std/src/Std/Arrays.qs @@ -0,0 +1,1486 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +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/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/internal.qs b/library/std/src/internal.qs index 72afb101b7..0ccb52d5f4 100644 --- a/library/std/src/internal.qs +++ b/library/std/src/internal.qs @@ -2,7 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Intrinsic { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; open Microsoft.Quantum.Core; open Microsoft.Quantum.Math; open QIR.Intrinsic; diff --git a/library/std/src/modern_api.qs b/library/std/src/legacy_api.qs similarity index 91% rename from library/std/src/modern_api.qs rename to library/std/src/legacy_api.qs index 91b9aa43bb..d1f206193d 100644 --- a/library/std/src/modern_api.qs +++ b/library/std/src/legacy_api.qs @@ -4,9 +4,12 @@ // 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; +} + namespace Std { export - Microsoft.Quantum.Arrays, Microsoft.Quantum.Canon, Microsoft.Quantum.Convert, Microsoft.Quantum.Core, diff --git a/library/std/src/unstable_arithmetic.qs b/library/std/src/unstable_arithmetic.qs index 22ae84ae13..4b15873f02 100644 --- a/library/std/src/unstable_arithmetic.qs +++ b/library/std/src/unstable_arithmetic.qs @@ -2,7 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Unstable.Arithmetic { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert; diff --git a/library/std/src/unstable_arithmetic_internal.qs b/library/std/src/unstable_arithmetic_internal.qs index 5125859fa8..ac414f4a8b 100644 --- a/library/std/src/unstable_arithmetic_internal.qs +++ b/library/std/src/unstable_arithmetic_internal.qs @@ -3,7 +3,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert; diff --git a/library/std/src/unstable_state_preparation.qs b/library/std/src/unstable_state_preparation.qs index dfc3d5ebb7..66ecceb143 100644 --- a/library/std/src/unstable_state_preparation.qs +++ b/library/std/src/unstable_state_preparation.qs @@ -4,7 +4,7 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; open Microsoft.Quantum.Math; /// # Summary diff --git a/library/std/src/unstable_table_lookup.qs b/library/std/src/unstable_table_lookup.qs index 5ff35395b6..15b346c197 100644 --- a/library/std/src/unstable_table_lookup.qs +++ b/library/std/src/unstable_table_lookup.qs @@ -2,7 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Unstable.TableLookup { - open Microsoft.Quantum.Arrays; + import Std.Arrays.*; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Math; From dd55538f9002aa163ff659ab46e400824c2582b8 Mon Sep 17 00:00:00 2001 From: sezna Date: Mon, 9 Sep 2024 14:01:21 -0700 Subject: [PATCH 02/29] move Convert to modern stdlib --- library/std/qsharp.json | 3 +- library/std/src/Std/Convert.qs | 284 +++++++++++++++++++++++++++++++++ library/std/src/convert.qs | 284 +-------------------------------- library/std/src/legacy_api.qs | 2 +- 4 files changed, 288 insertions(+), 285 deletions(-) create mode 100644 library/std/src/Std/Convert.qs diff --git a/library/std/qsharp.json b/library/std/qsharp.json index 0ea6309480..ba7d0c2ae3 100644 --- a/library/std/qsharp.json +++ b/library/std/qsharp.json @@ -19,6 +19,7 @@ "src/unstable_arithmetic_internal.qs", "src/unstable_state_preparation.qs", "src/unstable_table_lookup.qs", - "src/Std/Arrays.qs" + "src/Std/Arrays.qs", + "src/Std/Convert.qs" ] } \ No newline at end of file diff --git a/library/std/src/Std/Convert.qs b/library/std/src/Std/Convert.qs new file mode 100644 index 0000000000..3aa1f18280 --- /dev/null +++ b/library/std/src/Std/Convert.qs @@ -0,0 +1,284 @@ + 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; \ No newline at end of file diff --git a/library/std/src/convert.qs b/library/std/src/convert.qs index 84bdfbf3e0..4d68f4e640 100644 --- a/library/std/src/convert.qs +++ b/library/std/src/convert.qs @@ -2,287 +2,5 @@ // 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/legacy_api.qs b/library/std/src/legacy_api.qs index d1f206193d..a10bb8f7ec 100644 --- a/library/std/src/legacy_api.qs +++ b/library/std/src/legacy_api.qs @@ -5,7 +5,7 @@ // 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; + export Std.Arrays, Std.Convert; } namespace Std { From d3905aeacfd8c14cf2be0a5d2ffc21313dda50d1 Mon Sep 17 00:00:00 2001 From: sezna Date: Mon, 9 Sep 2024 14:02:50 -0700 Subject: [PATCH 03/29] move diagnostics to new stdlib --- library/std/qsharp.json | 5 ++--- library/std/src/{diagnostics.qs => Std/Diagnostics.qs} | 9 ++------- library/std/src/convert.qs | 6 ------ library/std/src/legacy_api.qs | 2 +- 4 files changed, 5 insertions(+), 17 deletions(-) rename library/std/src/{diagnostics.qs => Std/Diagnostics.qs} (98%) delete mode 100644 library/std/src/convert.qs diff --git a/library/std/qsharp.json b/library/std/qsharp.json index ba7d0c2ae3..f1cea966dd 100644 --- a/library/std/qsharp.json +++ b/library/std/qsharp.json @@ -3,9 +3,7 @@ "license": "MIT", "files": [ "src/canon.qs", - "src/convert.qs", "src/core.qs", - "src/diagnostics.qs", "src/internal.qs", "src/intrinsic.qs", "src/legacy_api.qs", @@ -20,6 +18,7 @@ "src/unstable_state_preparation.qs", "src/unstable_table_lookup.qs", "src/Std/Arrays.qs", - "src/Std/Convert.qs" + "src/Std/Convert.qs", + "src/Std/Diagnostics.qs" ] } \ No newline at end of file diff --git a/library/std/src/diagnostics.qs b/library/std/src/Std/Diagnostics.qs similarity index 98% rename from library/std/src/diagnostics.qs rename to library/std/src/Std/Diagnostics.qs index 452a0bd7f0..40fc614405 100644 --- a/library/std/src/diagnostics.qs +++ b/library/std/src/Std/Diagnostics.qs @@ -1,8 +1,4 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Diagnostics { - open QIR.Intrinsic; +open QIR.Intrinsic; /// # Summary /// Dumps the current target machine's status. @@ -332,5 +328,4 @@ namespace Microsoft.Quantum.Diagnostics { body intrinsic; } - export DumpMachine, DumpRegister, CheckZero, CheckAllZero, Fact, CheckOperationsAreEqual, StartCountingOperation, StopCountingOperation, StartCountingFunction, StopCountingFunction, StartCountingQubits, StopCountingQubits; -} + 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/convert.qs b/library/std/src/convert.qs deleted file mode 100644 index 4d68f4e640..0000000000 --- a/library/std/src/convert.qs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Convert { - -} diff --git a/library/std/src/legacy_api.qs b/library/std/src/legacy_api.qs index a10bb8f7ec..bbefc4358b 100644 --- a/library/std/src/legacy_api.qs +++ b/library/std/src/legacy_api.qs @@ -5,7 +5,7 @@ // 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; + export Std.Arrays, Std.Convert, Std.Diagnostics; } namespace Std { From a86106c056fd88d5fd98211766ea49ed53f90a0e Mon Sep 17 00:00:00 2001 From: sezna Date: Mon, 9 Sep 2024 14:41:23 -0700 Subject: [PATCH 04/29] convert some more to the modern style --- library/std/qsharp.json | 10 +- library/std/src/QIR/Intrinsic.qs | 1183 +++++++++++++++++ .../std/src/{logical.qs => Std/Logical.qs} | 3 +- library/std/src/{math.qs => Std/Math.qs} | 6 +- .../{measurement.qs => Std/Measurement.qs} | 3 +- library/std/src/canon.qs | 2 +- library/std/src/intrinsic.qs | 1158 ---------------- library/std/src/legacy_api.qs | 6 +- library/std/src/unstable_arithmetic.qs | 1 + .../std/src/unstable_arithmetic_internal.qs | 2 + library/std/src/unstable_state_preparation.qs | 2 + library/std/src/unstable_table_lookup.qs | 2 + 12 files changed, 1202 insertions(+), 1176 deletions(-) create mode 100644 library/std/src/QIR/Intrinsic.qs rename library/std/src/{logical.qs => Std/Logical.qs} (95%) rename library/std/src/{math.qs => Std/Math.qs} (97%) rename library/std/src/{measurement.qs => Std/Measurement.qs} (99%) delete mode 100644 library/std/src/intrinsic.qs diff --git a/library/std/qsharp.json b/library/std/qsharp.json index f1cea966dd..6f9b9c0553 100644 --- a/library/std/qsharp.json +++ b/library/std/qsharp.json @@ -5,11 +5,7 @@ "src/canon.qs", "src/core.qs", "src/internal.qs", - "src/intrinsic.qs", "src/legacy_api.qs", - "src/logical.qs", - "src/math.qs", - "src/measurement.qs", "src/qir.qs", "src/random.qs", "src/re.qs", @@ -17,8 +13,12 @@ "src/unstable_arithmetic_internal.qs", "src/unstable_state_preparation.qs", "src/unstable_table_lookup.qs", + "src/QIR/Intrinsic.qs", "src/Std/Arrays.qs", "src/Std/Convert.qs", - "src/Std/Diagnostics.qs" + "src/Std/Diagnostics.qs", + "src/Std/Logical.qs", + "src/Std/Math.qs", + "src/Std/Measurement.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..7f501012db --- /dev/null +++ b/library/std/src/QIR/Intrinsic.qs @@ -0,0 +1,1183 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +open Std.Convert; +open Microsoft.Quantum.Core; +open Std.Diagnostics; +open Microsoft.Quantum.Math; + +/// # 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/logical.qs b/library/std/src/Std/Logical.qs similarity index 95% rename from library/std/src/logical.qs rename to library/std/src/Std/Logical.qs index be7417a339..329ff427f9 100644 --- a/library/std/src/logical.qs +++ b/library/std/src/Std/Logical.qs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.Quantum.Logical { /// # Summary /// Returns the boolean exclusive disjunction (eXclusive OR, XOR) @@ -29,4 +28,4 @@ namespace Microsoft.Quantum.Logical { first != second } export Xor; -} + diff --git a/library/std/src/math.qs b/library/std/src/Std/Math.qs similarity index 97% rename from library/std/src/math.qs rename to library/std/src/Std/Math.qs index dd9e7a0e64..c018e5d348 100644 --- a/library/std/src/math.qs +++ b/library/std/src/Std/Math.qs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.Quantum.Math { + open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; @@ -1451,5 +1451,5 @@ namespace Microsoft.Quantum.Math { 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; -} + 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/Std/Measurement.qs similarity index 99% rename from library/std/src/measurement.qs rename to library/std/src/Std/Measurement.qs index ea5c2dd608..3d0d7ba2a2 100644 --- a/library/std/src/measurement.qs +++ b/library/std/src/Std/Measurement.qs @@ -1,7 +1,7 @@ // 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; @@ -183,4 +183,3 @@ namespace Microsoft.Quantum.Measurement { } export MeasureAllZ, MeasureEachZ, MResetEachZ, MResetX, MResetY, MResetZ, MeasureInteger; -} diff --git a/library/std/src/canon.qs b/library/std/src/canon.qs index 6bccc1c1fa..a8dd54f66b 100644 --- a/library/std/src/canon.qs +++ b/library/std/src/canon.qs @@ -2,7 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Canon { - open QIR.Intrinsic; + import QIR.Intrinsic.*; open Microsoft.Quantum.Intrinsic; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Math; 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 index bbefc4358b..d1bebfd5ef 100644 --- a/library/std/src/legacy_api.qs +++ b/library/std/src/legacy_api.qs @@ -5,18 +5,14 @@ // 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; + export Std.Arrays, Std.Convert, Std.Diagnostics, Std.Logical, Std.Math, Std.Measurement; } namespace Std { export 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/unstable_arithmetic.qs b/library/std/src/unstable_arithmetic.qs index 4b15873f02..0dea7ce1bf 100644 --- a/library/std/src/unstable_arithmetic.qs +++ b/library/std/src/unstable_arithmetic.qs @@ -3,6 +3,7 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { import Std.Arrays.*; + import QIR.Intrinsic.*; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert; diff --git a/library/std/src/unstable_arithmetic_internal.qs b/library/std/src/unstable_arithmetic_internal.qs index ac414f4a8b..c491971bb2 100644 --- a/library/std/src/unstable_arithmetic_internal.qs +++ b/library/std/src/unstable_arithmetic_internal.qs @@ -6,6 +6,8 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { import Std.Arrays.*; open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert; + import QIR.Intrinsic.*; + /// # 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 66ecceb143..ed7a48252a 100644 --- a/library/std/src/unstable_state_preparation.qs +++ b/library/std/src/unstable_state_preparation.qs @@ -6,6 +6,8 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { open Microsoft.Quantum.Diagnostics; import Std.Arrays.*; open Microsoft.Quantum.Math; + import QIR.Intrinsic.*; + /// # 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 15b346c197..e003e2b54f 100644 --- a/library/std/src/unstable_table_lookup.qs +++ b/library/std/src/unstable_table_lookup.qs @@ -8,6 +8,8 @@ namespace Microsoft.Quantum.Unstable.TableLookup { open Microsoft.Quantum.Math; open Microsoft.Quantum.ResourceEstimation; open Microsoft.Quantum.Unstable.Arithmetic; + import QIR.Intrinsic.*; + /// # Summary /// Performs table lookup using a SELECT network From baf489a377cc185ef81ac1074a7bcf3beaebb098 Mon Sep 17 00:00:00 2001 From: sezna Date: Mon, 9 Sep 2024 14:41:33 -0700 Subject: [PATCH 05/29] forgotten adds --- library/src/lib.rs | 24 +++++++++---------- .../tests/resources/src/state_preparation.qs | 2 ++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/library/src/lib.rs b/library/src/lib.rs index d928236f78..aefecea64c 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -30,36 +30,36 @@ pub const STD_LIB: &[(&str, &str)] = &[ include_str!("../std/src/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:intrinsic.qs", - include_str!("../std/src/intrinsic.qs"), + "qsharp-library-source:QIR/Intrinsic.qs", + include_str!("../std/src/QIR/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", diff --git a/library/src/tests/resources/src/state_preparation.qs b/library/src/tests/resources/src/state_preparation.qs index c5c249e0f5..7be1024314 100644 --- a/library/src/tests/resources/src/state_preparation.qs +++ b/library/src/tests/resources/src/state_preparation.qs @@ -4,6 +4,8 @@ namespace Test { open Microsoft.Quantum.Diagnostics; import Std.Arrays.*; open Microsoft.Quantum.Unstable.StatePreparation; + import QIR.Intrinsic.*; + operation TestPlusState() : Unit { From 9bd448701f2610503a4bcad0064a2403f61d1a34 Mon Sep 17 00:00:00 2001 From: sezna Date: Mon, 9 Sep 2024 14:44:44 -0700 Subject: [PATCH 06/29] wip: refactor stdlib --- library/src/lib.rs | 4 +- library/std/src/QIR/Intrinsic.qs | 1177 ++---------------------------- library/std/src/qir.qs | 105 --- 3 files changed, 51 insertions(+), 1235 deletions(-) delete mode 100644 library/std/src/qir.qs diff --git a/library/src/lib.rs b/library/src/lib.rs index aefecea64c..19856df2d6 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -46,8 +46,8 @@ pub const STD_LIB: &[(&str, &str)] = &[ include_str!("../std/src/internal.qs"), ), ( - "qsharp-library-source:QIR/Intrinsic.qs", - include_str!("../std/src/QIR/Intrinsic.qs"), + "qsharp-library-source:Std/Intrinsic.qs", + include_str!("../std/src/Std/Intrinsic.qs"), ), ( "qsharp-library-source:Std/Logical.qs", diff --git a/library/std/src/QIR/Intrinsic.qs b/library/std/src/QIR/Intrinsic.qs index 7f501012db..d6304a39f2 100644 --- a/library/std/src/QIR/Intrinsic.qs +++ b/library/std/src/QIR/Intrinsic.qs @@ -2,1182 +2,103 @@ // Licensed under the MIT License. -open Std.Convert; -open Microsoft.Quantum.Core; -open Std.Diagnostics; -open Microsoft.Quantum.Math; -/// # 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; -} +// Controlled Gates - /// # 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); - } +operation __quantum__qis__ccx__body(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit { + body intrinsic; } - /// # 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; +operation __quantum__qis__cx__body(control : Qubit, target : Qubit) : Unit { + body intrinsic; } - /// # 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; +operation __quantum__qis__cy__body(control : Qubit, target : Qubit) : Unit { + body intrinsic; } - /// # 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) +operation __quantum__qis__cz__body(control : Qubit, target : Qubit) : Unit { + body intrinsic; } - /// # 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]) -} +// Rotation Gates - /// # 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) - } +operation __quantum__qis__rx__body(angle : Double, target : Qubit) : Unit { + body intrinsic; } - /// # 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) +operation __quantum__qis__rxx__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { + body intrinsic; } - /// # 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); - } +operation __quantum__qis__ry__body(angle : Double, target : Qubit) : Unit { + body intrinsic; } - /// # 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); +operation __quantum__qis__ryy__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { + body intrinsic; } - /// # 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); +operation __quantum__qis__rz__body(angle : Double, target : Qubit) : Unit { + body intrinsic; } - /// # 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); +operation __quantum__qis__rzz__body(angle : Double, target1 : Qubit, target2 : Qubit) : Unit { + body intrinsic; } - /// # 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); - } -} +// Single-Qubit Gates - /// # 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); +operation __quantum__qis__h__body(target : Qubit) : Unit { + body intrinsic; } - /// # 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); - } +operation __quantum__qis__s__body(target : Qubit) : Unit { + body intrinsic; } - /// # 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); - } +operation __quantum__qis__s__adj(target : Qubit) : Unit { + body intrinsic; } - /// # 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); - } +operation __quantum__qis__t__body(target : Qubit) : Unit { + body intrinsic; } - /// # 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); - } +operation __quantum__qis__t__adj(target : Qubit) : Unit { + body intrinsic; } - /// # 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); - } +operation __quantum__qis__x__body(target : Qubit) : Unit { + body intrinsic; } - /// # 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); - } +operation __quantum__qis__y__body(target : Qubit) : Unit { + body intrinsic; } - /// # 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)); - } - } - } - } +operation __quantum__qis__z__body(target : Qubit) : Unit { + body intrinsic; } - /// # 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)); - } - } - } -} +// Two-Qubit Gates - /// # 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); - } - } - } +operation __quantum__qis__swap__body(target1 : Qubit, target2 : Qubit) : Unit { + body intrinsic; } - /// # 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; -} +// Quantum Measurement - /// # 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; +operation __quantum__qis__m__body(target : Qubit) : Result { + body intrinsic; } - /// # 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; +operation __quantum__qis__reset__body(target : Qubit) : Unit { + body intrinsic; } - /// # 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 { +operation __quantum__qis__mresetz__body(target : Qubit) : Result { 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; +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/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; -} From 50e49a652f0359430e49849682029775bd8dc5db Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Tue, 10 Sep 2024 07:45:32 -0700 Subject: [PATCH 07/29] port intrinsic and internals to new project format --- library/src/lib.rs | 8 +- library/std/qsharp.json | 4 +- .../{internal.qs => Std/InternalHelpers.qs} | 6 +- library/std/src/Std/Intrinsic.qs | 1158 +++++++++++++++++ library/std/src/legacy_api.qs | 3 +- 5 files changed, 1168 insertions(+), 11 deletions(-) rename library/std/src/{internal.qs => Std/InternalHelpers.qs} (99%) create mode 100644 library/std/src/Std/Intrinsic.qs diff --git a/library/src/lib.rs b/library/src/lib.rs index 19856df2d6..1da68cc7a0 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -42,8 +42,8 @@ pub const STD_LIB: &[(&str, &str)] = &[ 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:Std/Intrinsic.qs", @@ -62,8 +62,8 @@ pub const STD_LIB: &[(&str, &str)] = &[ 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", diff --git a/library/std/qsharp.json b/library/std/qsharp.json index 6f9b9c0553..57acf94610 100644 --- a/library/std/qsharp.json +++ b/library/std/qsharp.json @@ -4,9 +4,7 @@ "files": [ "src/canon.qs", "src/core.qs", - "src/internal.qs", "src/legacy_api.qs", - "src/qir.qs", "src/random.qs", "src/re.qs", "src/unstable_arithmetic.qs", @@ -17,6 +15,8 @@ "src/Std/Arrays.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" diff --git a/library/std/src/internal.qs b/library/std/src/Std/InternalHelpers.qs similarity index 99% rename from library/std/src/internal.qs rename to library/std/src/Std/InternalHelpers.qs index 0ccb52d5f4..86887b4b20 100644 --- a/library/std/src/internal.qs +++ b/library/std/src/Std/InternalHelpers.qs @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.Quantum.Intrinsic { + import Std.Arrays.*; open Microsoft.Quantum.Core; open Microsoft.Quantum.Math; - open QIR.Intrinsic; + import Std.Intrinsic.*; + import QIR.Intrinsic.*; internal operation CH(control : Qubit, target : Qubit) : Unit is Adj { within { @@ -247,4 +248,3 @@ namespace Microsoft.Quantum.Intrinsic { targets } -} diff --git a/library/std/src/Std/Intrinsic.qs b/library/std/src/Std/Intrinsic.qs new file mode 100644 index 0000000000..05dfea9fc7 --- /dev/null +++ b/library/std/src/Std/Intrinsic.qs @@ -0,0 +1,1158 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Core; + open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.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); + } + } + } + + /// # 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 index d1bebfd5ef..3fde6d7cfa 100644 --- a/library/std/src/legacy_api.qs +++ b/library/std/src/legacy_api.qs @@ -5,14 +5,13 @@ // 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; + export Std.Arrays, Std.Convert, Std.Diagnostics, Std.Logical, Std.Math, Std.Measurement, Std.Intrinsic; } namespace Std { export Microsoft.Quantum.Canon, Microsoft.Quantum.Core, - Microsoft.Quantum.Intrinsic, Microsoft.Quantum.Measurement, Microsoft.Quantum.Random, Microsoft.Quantum.ResourceEstimation; From 84258abaf8899a331aac113f1e5670648a4f9ef5 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Tue, 10 Sep 2024 07:56:03 -0700 Subject: [PATCH 08/29] migrate half of unstable lib --- library/src/lib.rs | 16 ++++++++-------- library/std/qsharp.json | 10 +++++----- library/std/src/{random.qs => Std/Random.qs} | 3 +-- .../std/src/{re.qs => Std/ResourceEstimation.qs} | 3 +-- .../Unstable/Arithmetic.qs} | 4 ++-- .../Unstable/ArithmeticHelpers.qs} | 3 +-- library/std/src/legacy_api.qs | 11 ++++++----- library/std/src/unstable_state_preparation.qs | 4 ++-- library/std/src/unstable_table_lookup.qs | 2 ++ 9 files changed, 28 insertions(+), 28 deletions(-) rename library/std/src/{random.qs => Std/Random.qs} (98%) rename library/std/src/{re.qs => Std/ResourceEstimation.qs} (99%) rename library/std/src/{unstable_arithmetic.qs => Std/Unstable/Arithmetic.qs} (99%) rename library/std/src/{unstable_arithmetic_internal.qs => Std/Unstable/ArithmeticHelpers.qs} (99%) diff --git a/library/src/lib.rs b/library/src/lib.rs index 1da68cc7a0..2057a0af2b 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -66,20 +66,20 @@ pub const STD_LIB: &[(&str, &str)] = &[ 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:Std/ResourceEstimation.qs", + include_str!("../std/src/Std/ResourceEstimation.qs"), ), ( - "qsharp-library-source:unstable_arithmetic.qs", - include_str!("../std/src/unstable_arithmetic.qs"), + "qsharp-library-source:Std/Unstable/Arithmetic.qs", + include_str!("../std/src/Std/Unstable/Arithmetic.qs"), ), ( - "qsharp-library-source:unstable_arithmetic_internal.qs", - include_str!("../std/src/unstable_arithmetic_internal.qs"), + "qsharp-library-source:Std/Unstable/ArithmeticHelpers.qs", + include_str!("../std/src/Std/Unstable/ArithmeticHelpers.qs"), ), ( "qsharp-library-source:unstable_state_preparation.qs", diff --git a/library/std/qsharp.json b/library/std/qsharp.json index 57acf94610..6d983c1a95 100644 --- a/library/std/qsharp.json +++ b/library/std/qsharp.json @@ -5,10 +5,6 @@ "src/canon.qs", "src/core.qs", "src/legacy_api.qs", - "src/random.qs", - "src/re.qs", - "src/unstable_arithmetic.qs", - "src/unstable_arithmetic_internal.qs", "src/unstable_state_preparation.qs", "src/unstable_table_lookup.qs", "src/QIR/Intrinsic.qs", @@ -19,6 +15,10 @@ "src/Std/Intrinsic.qs", "src/Std/Logical.qs", "src/Std/Math.qs", - "src/Std/Measurement.qs" + "src/Std/Measurement.qs", + "src/Std/Random.qs", + "src/Std/ResourceEstimation.qs", + "src/Std/Unstable/Arithmetic.qs", + "src/Std/Unstable/ArithmeticHelpers.qs" ] } \ No newline at end of file diff --git a/library/std/src/random.qs b/library/std/src/Std/Random.qs similarity index 98% rename from library/std/src/random.qs rename to library/std/src/Std/Random.qs index c70cb51c4a..2a20346660 100644 --- a/library/std/src/random.qs +++ b/library/std/src/Std/Random.qs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.Quantum.Random { + /// # Summary /// Draws a random integer from a uniform distribution @@ -74,4 +74,3 @@ namespace Microsoft.Quantum.Random { } export DrawRandomInt, DrawRandomDouble, DrawRandomBool; -} diff --git a/library/std/src/re.qs b/library/std/src/Std/ResourceEstimation.qs similarity index 99% rename from library/std/src/re.qs rename to library/std/src/Std/ResourceEstimation.qs index 8fbfac943d..581e2a83df 100644 --- a/library/std/src/re.qs +++ b/library/std/src/Std/ResourceEstimation.qs @@ -1,7 +1,7 @@ // 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 @@ -179,4 +179,3 @@ namespace Microsoft.Quantum.ResourceEstimation { } } 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/Std/Unstable/Arithmetic.qs similarity index 99% rename from library/std/src/unstable_arithmetic.qs rename to library/std/src/Std/Unstable/Arithmetic.qs index 0dea7ce1bf..edded93320 100644 --- a/library/std/src/unstable_arithmetic.qs +++ b/library/std/src/Std/Unstable/Arithmetic.qs @@ -1,12 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.Quantum.Unstable.Arithmetic { + import Std.Arrays.*; import QIR.Intrinsic.*; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Math; open Microsoft.Quantum.Convert; + import Std.Unstable.ArithmeticHelpers.*; /// # Summary /// This applies the in-place majority operation to 3 qubits. @@ -699,4 +700,3 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { } export AddLE, ApplyIfEqualLE, ApplyIfEqualL, ApplyIfGreaterLE, ApplyIfGreaterL, ApplyIfGreaterOrEqualLE, ApplyIfGreaterOrEqualL, ApplyIfLessLE, ApplyIfLessL, ApplyIfLessOrEqualLE, ApplyIfLessOrEqualL, IncByI, IncByIUsingIncByLE, IncByL, IncByLUsingIncByLE, IncByLE, IncByLEUsingAddLE, LookAheadDKRSAddLE, MAJ, ReflectAboutInteger, RippleCarryCGAddLE, RippleCarryCGIncByLE, RippleCarryTTKIncByLE, FourierTDIncByLE; -} diff --git a/library/std/src/unstable_arithmetic_internal.qs b/library/std/src/Std/Unstable/ArithmeticHelpers.qs similarity index 99% rename from library/std/src/unstable_arithmetic_internal.qs rename to library/std/src/Std/Unstable/ArithmeticHelpers.qs index c491971bb2..5d72beba79 100644 --- a/library/std/src/unstable_arithmetic_internal.qs +++ b/library/std/src/Std/Unstable/ArithmeticHelpers.qs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.Quantum.Unstable.Arithmetic { + open Microsoft.Quantum.Diagnostics; import Std.Arrays.*; open Microsoft.Quantum.Math; @@ -584,4 +584,3 @@ namespace Microsoft.Quantum.Unstable.Arithmetic { ApplyAndAssuming0Target(Tail(tgtsLeft), Tail(tgtsRight), Tail(tgts)); } } -} diff --git a/library/std/src/legacy_api.qs b/library/std/src/legacy_api.qs index 3fde6d7cfa..038d2c224b 100644 --- a/library/std/src/legacy_api.qs +++ b/library/std/src/legacy_api.qs @@ -5,14 +5,15 @@ // 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; + export Std.Arrays, Std.Convert, Std.Diagnostics, Std.Logical, Std.Math, Std.Measurement, Std.Intrinsic, Std.Random, Std.ResourceEstimation; +} + +namespace Microsoft.Quantum.Unstable { + export Std.Unstable.Arithmetic; } namespace Std { export Microsoft.Quantum.Canon, - Microsoft.Quantum.Core, - Microsoft.Quantum.Measurement, - Microsoft.Quantum.Random, - Microsoft.Quantum.ResourceEstimation; + Microsoft.Quantum.Core; } diff --git a/library/std/src/unstable_state_preparation.qs b/library/std/src/unstable_state_preparation.qs index ed7a48252a..1fb1f4a377 100644 --- a/library/std/src/unstable_state_preparation.qs +++ b/library/std/src/unstable_state_preparation.qs @@ -1,12 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.Quantum.Unstable.StatePreparation { + open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; import Std.Arrays.*; open Microsoft.Quantum.Math; import QIR.Intrinsic.*; + import Std.Unstable.ArithmeticHelpers.*; /// # Summary @@ -387,4 +388,3 @@ namespace Microsoft.Quantum.Unstable.StatePreparation { } export PreparePureStateD, ApproximatelyPreparePureStateCP; -} diff --git a/library/std/src/unstable_table_lookup.qs b/library/std/src/unstable_table_lookup.qs index e003e2b54f..1142669c78 100644 --- a/library/std/src/unstable_table_lookup.qs +++ b/library/std/src/unstable_table_lookup.qs @@ -8,6 +8,8 @@ namespace Microsoft.Quantum.Unstable.TableLookup { open Microsoft.Quantum.Math; open Microsoft.Quantum.ResourceEstimation; open Microsoft.Quantum.Unstable.Arithmetic; + import Std.Unstable.ArithmeticHelpers.*; + import QIR.Intrinsic.*; From 06b372cb6d0387b9d78494112617d87a8fc94566 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Tue, 10 Sep 2024 08:01:06 -0700 Subject: [PATCH 09/29] everything migrated except canon and core --- library/src/lib.rs | 8 ++++---- library/std/qsharp.json | 6 +++--- .../Unstable/StatePreparation.qs} | 0 .../Unstable/TableLookup.qs} | 3 +-- library/std/src/legacy_api.qs | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) rename library/std/src/{unstable_state_preparation.qs => Std/Unstable/StatePreparation.qs} (100%) rename library/std/src/{unstable_table_lookup.qs => Std/Unstable/TableLookup.qs} (99%) diff --git a/library/src/lib.rs b/library/src/lib.rs index 2057a0af2b..f41b02b74e 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -82,12 +82,12 @@ pub const STD_LIB: &[(&str, &str)] = &[ include_str!("../std/src/Std/Unstable/ArithmeticHelpers.qs"), ), ( - "qsharp-library-source:unstable_state_preparation.qs", - include_str!("../std/src/unstable_state_preparation.qs"), + "qsharp-library-source:Std/Unstable/StatePreparation.qs", + include_str!("../std/src/Std/Unstable/StatePreparation.qs"), ), ( - "qsharp-library-source:unstable_table_lookup.qs", - include_str!("../std/src/unstable_table_lookup.qs"), + "qsharp-library-source:Std/Unstable/TableLookup.qs", + include_str!("../std/src/Std/Unstable/TableLookup.qs"), ), ( "qsharp-library-source:legacy_api.qs", diff --git a/library/std/qsharp.json b/library/std/qsharp.json index 6d983c1a95..4c27d0d140 100644 --- a/library/std/qsharp.json +++ b/library/std/qsharp.json @@ -5,8 +5,6 @@ "src/canon.qs", "src/core.qs", "src/legacy_api.qs", - "src/unstable_state_preparation.qs", - "src/unstable_table_lookup.qs", "src/QIR/Intrinsic.qs", "src/Std/Arrays.qs", "src/Std/Convert.qs", @@ -19,6 +17,8 @@ "src/Std/Random.qs", "src/Std/ResourceEstimation.qs", "src/Std/Unstable/Arithmetic.qs", - "src/Std/Unstable/ArithmeticHelpers.qs" + "src/Std/Unstable/ArithmeticHelpers.qs", + "src/Std/Unstable/StatePreparation.qs", + "src/Std/Unstable/TableLookup.qs" ] } \ No newline at end of file diff --git a/library/std/src/unstable_state_preparation.qs b/library/std/src/Std/Unstable/StatePreparation.qs similarity index 100% rename from library/std/src/unstable_state_preparation.qs rename to library/std/src/Std/Unstable/StatePreparation.qs diff --git a/library/std/src/unstable_table_lookup.qs b/library/std/src/Std/Unstable/TableLookup.qs similarity index 99% rename from library/std/src/unstable_table_lookup.qs rename to library/std/src/Std/Unstable/TableLookup.qs index 1142669c78..046b00d90b 100644 --- a/library/std/src/unstable_table_lookup.qs +++ b/library/std/src/Std/Unstable/TableLookup.qs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Microsoft.Quantum.Unstable.TableLookup { + import Std.Arrays.*; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; @@ -279,4 +279,3 @@ namespace Microsoft.Quantum.Unstable.TableLookup { } export Select; -} diff --git a/library/std/src/legacy_api.qs b/library/std/src/legacy_api.qs index 038d2c224b..b4de6e7ee1 100644 --- a/library/std/src/legacy_api.qs +++ b/library/std/src/legacy_api.qs @@ -9,7 +9,7 @@ namespace Microsoft.Quantum { } namespace Microsoft.Quantum.Unstable { - export Std.Unstable.Arithmetic; + export Std.Unstable.Arithmetic, Std.Unstable.TableLookup, Std.Unstable.StatePreparation; } namespace Std { From 6cd0124841ef6d40f1e56486ee32e373b31b49cf Mon Sep 17 00:00:00 2001 From: sezna Date: Tue, 10 Sep 2024 14:02:05 -0700 Subject: [PATCH 10/29] finalize new stdlib --- compiler/qsc/src/interpret/tests.rs | 2 +- compiler/qsc/src/location.rs | 2 +- .../qsc_data_structures/src/namespaces.rs | 12 +- .../src/namespaces/tests.rs | 115 +- .../qsc_frontend/src/incremental/tests.rs | 4 +- compiler/qsc_frontend/src/resolve.rs | 2 +- compiler/qsc_frontend/src/resolve/tests.rs | 648 ++-- compiler/qsc_frontend/src/typeck/tests.rs | 32 +- compiler/qsc_partial_eval/src/tests/misc.rs | 2 +- language_service/src/completion.rs | 2 +- library/std/src/Std/Convert.qs | 501 +-- library/std/src/Std/Diagnostics.qs | 598 ++-- library/std/src/Std/InternalHelpers.qs | 452 +-- library/std/src/Std/Intrinsic.qs | 2010 ++++++------ library/std/src/Std/Logical.qs | 52 +- library/std/src/Std/Math.qs | 2770 +++++++++-------- library/std/src/Std/Measurement.qs | 324 +- library/std/src/Std/Random.qs | 132 +- library/std/src/Std/ResourceEstimation.qs | 300 +- library/std/src/Std/Unstable/Arithmetic.qs | 1214 ++++---- .../std/src/Std/Unstable/ArithmeticHelpers.qs | 970 +++--- .../std/src/Std/Unstable/StatePreparation.qs | 684 ++-- library/std/src/Std/Unstable/TableLookup.qs | 480 +-- 23 files changed, 5707 insertions(+), 5601 deletions(-) diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs index b948b4bfb3..d1e0ae63d5 100644 --- a/compiler/qsc/src/interpret/tests.rs +++ b/compiler/qsc/src/interpret/tests.rs @@ -484,7 +484,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)] "#]], ); } 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_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_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..d5cccb7ef2 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(); @@ -513,21 +513,19 @@ fn ambiguous_prelude() { } "}, &expect![[r#" - namespace namespace3 { + namespace namespace8 { function item1() : Unit {} } - namespace namespace4 { + namespace namespace5 { function item3() : Unit {} } - namespace namespace7 { + namespace namespace9 { function item5() : Unit { - A(); + item3(); } } - - // AmbiguousPrelude { name: "A", candidate_a: "Microsoft.Quantum.Canon", candidate_b: "Microsoft.Quantum.Core", span: Span { lo: 181, hi: 182 } } "#]], ); } @@ -544,7 +542,7 @@ fn local_var() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { let local13 = 0; local13 @@ -570,7 +568,7 @@ fn shadow_local() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { let local13 = 0; let local17 = { @@ -595,7 +593,7 @@ fn callable_param() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local8 : Int) : Int { local8 } @@ -617,7 +615,7 @@ fn spec_param() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit) : (Qubit[], Qubit) { controlled (local23, ...) { (local23, local8) @@ -644,7 +642,7 @@ fn spec_param_shadow_disallowed() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit[]) : Qubit[] { controlled (local20, ...) { local20 @@ -675,7 +673,7 @@ fn local_shadows_global() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit {} function item2() : Int { @@ -701,7 +699,7 @@ fn shadow_same_block() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { let local13 = 0; let local17 = local13 + 1; @@ -731,12 +729,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 +767,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 +795,7 @@ fn shadowing_disallowed_within_parameters() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8: Int, local13: Double, local18: Bool) : Unit {} } @@ -817,7 +815,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 +837,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 +859,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 +893,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 +924,7 @@ fn ty_decl() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; function item2(local14 : item1) : Unit {} } @@ -944,7 +942,7 @@ fn struct_decl() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} function item2(local11 : item1) : Unit {} } @@ -962,7 +960,7 @@ fn ty_decl_duplicate_error() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; newtype item2 = Bool; } @@ -982,7 +980,7 @@ fn struct_decl_duplicate_error() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} struct item2 { first : Bool } } @@ -1001,7 +999,7 @@ fn ty_decl_duplicate_error_on_built_in_ty() { } "}, &expect![[r#" - namespace namespace4 { + namespace namespace5 { newtype item1 = Unit; } @@ -1019,7 +1017,7 @@ fn struct_decl_duplicate_error_on_built_in_ty() { } "}, &expect![[r#" - namespace namespace4 { + namespace namespace5 { struct item1 {} } @@ -1038,7 +1036,7 @@ fn ty_decl_in_ty_decl() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; newtype item2 = item1; } @@ -1056,7 +1054,7 @@ fn struct_decl_in_struct_decl() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} struct item2 { a : item1 } } @@ -1073,7 +1071,7 @@ fn ty_decl_recursive() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = item1; } "#]], @@ -1089,7 +1087,7 @@ fn struct_decl_recursive() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 { a : item1 } } "#]], @@ -1109,7 +1107,7 @@ fn ty_decl_cons() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = Unit; function item2() : item1 { @@ -1133,7 +1131,7 @@ fn struct_decl_call_cons() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} function item2() : item1 { @@ -1157,7 +1155,7 @@ fn struct_decl_cons() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { struct item1 {} function item2() : item1 { @@ -1183,7 +1181,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 +1210,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 +1240,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 +1265,7 @@ fn unknown_term() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { B(); } @@ -1287,7 +1285,7 @@ fn unknown_ty() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local8 : B) : Unit {} } @@ -1318,17 +1316,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 +1358,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 +1400,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 +1442,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 +1473,7 @@ fn lambda_param() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { let local13 = local16 -> local16 + 1; } @@ -1497,7 +1495,7 @@ fn lambda_shadows_local() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { let local13 = 1; let local17 = local20 -> local20 + 1; @@ -1521,7 +1519,7 @@ fn for_loop_range() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { for local14 in 0..9 { let _ = local14; @@ -1545,7 +1543,7 @@ fn for_loop_var() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local8 : Int[]) : Unit { for local20 in local8 { let _ = local20; @@ -1570,7 +1568,7 @@ fn repeat_until() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { mutable local13 = false; repeat { @@ -1599,7 +1597,7 @@ fn repeat_until_fixup() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { mutable local13 = false; repeat { @@ -1630,7 +1628,7 @@ fn repeat_until_fixup_scoping() { } }"}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { repeat { mutable local16 = false; @@ -1662,7 +1660,7 @@ fn use_qubit() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit) : Unit { body intrinsic; } @@ -1691,7 +1689,7 @@ fn use_qubit_block() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1(local8 : Qubit) : Unit { body intrinsic; } @@ -1722,7 +1720,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 +1749,7 @@ fn local_function() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Int { function item2() : Int { 2 } item2() + 1 @@ -1773,7 +1771,7 @@ fn local_function_use_before_declare() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { item2(); function item2() : () {} @@ -1797,7 +1795,7 @@ fn local_function_is_really_local() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { function item3() : () {} item3(); @@ -1823,7 +1821,7 @@ fn local_function_is_not_closure() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { let local11 = 2; function item2() : Int { x } @@ -1847,7 +1845,7 @@ fn local_type() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { newtype item2 = Int; let local18 = item2(5); @@ -1865,8 +1863,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 +1881,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 +1904,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 +1928,7 @@ fn update_array_index_var() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { let local11 = [2]; let local16 = 0; @@ -1954,7 +1952,7 @@ fn update_array_index_expr() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : () { let local11 = [2]; let local16 = 0; @@ -1979,7 +1977,7 @@ fn update_udt_known_field_name() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First : Int, Second : Int); function item2() : () { @@ -2005,7 +2003,7 @@ fn update_udt_known_field_name_expr() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First : Int, Second : Int); function item2() : () { @@ -2033,7 +2031,7 @@ fn update_udt_unknown_field_name() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First : Int, Second : Int); function item2() : () { @@ -2061,7 +2059,7 @@ fn update_udt_unknown_field_name_known_global() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { newtype item1 = (First : Int, Second : Int); function item2() : () {} @@ -2084,7 +2082,7 @@ fn unknown_namespace() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { open Microsoft.Quantum.Fake; } @@ -2104,11 +2102,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 +2129,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 +2161,7 @@ fn bind_items_in_repeat() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { repeat { function item2() : Unit {} @@ -2190,7 +2188,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 +2213,7 @@ fn use_bound_item_in_another_bound_item() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { function item2() : Unit { item3(); @@ -2238,7 +2236,7 @@ fn use_unbound_generic() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local9: 'U) : 'U { local9 } @@ -2261,7 +2259,7 @@ fn resolve_local_generic() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1(local9: param0) : param0 { local9 } @@ -2285,7 +2283,7 @@ fn dropped_base_callable_from_unrestricted() { "}, TargetCapabilityFlags::all(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Base) function Dropped() : Unit {} @@ -2314,7 +2312,7 @@ fn dropped_base_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Base) function Dropped() : Unit {} @@ -2343,7 +2341,7 @@ fn dropped_not_base_callable_from_base() { "}, TargetCapabilityFlags::empty(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Base) function Dropped() : Unit {} @@ -2372,7 +2370,7 @@ fn resolved_not_base_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Base) function item1() : Unit {} @@ -2400,7 +2398,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 +2428,7 @@ fn resolved_not_unrestricted_callable_from_base() { "}, TargetCapabilityFlags::empty(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Unrestricted) function item1() : Unit {} @@ -2457,7 +2455,7 @@ fn resolved_not_unrestricted_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Unrestricted) function item1() : Unit {} @@ -2484,7 +2482,7 @@ fn dropped_not_unrestricted_callable_from_unrestricted() { "}, TargetCapabilityFlags::all(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(not Unrestricted) function Dropped() : Unit {} @@ -2513,7 +2511,7 @@ fn resolved_adaptive_callable_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) function item1() : Unit {} @@ -2540,7 +2538,7 @@ fn resolved_adaptive_callable_from_unrestricted() { "}, TargetCapabilityFlags::all(), &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) function item1() : Unit {} @@ -2567,7 +2565,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 +2594,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 +2621,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 +2649,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 +2680,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 +2711,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 +2739,7 @@ fn dropped_floating_point_from_adaptive() { "}, TargetCapabilityFlags::Adaptive, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(FloatingPointComputations) function Dropped() : Double {} @@ -2771,7 +2769,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 +2809,7 @@ fn multiple_definition_dropped_is_not_found() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @Config(Adaptive) operation item1() : Unit {} @Config(Base) @@ -2821,13 +2819,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 +2853,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 +2888,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 +2923,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 +3258,7 @@ fn use_after_scope() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { { let local16 = 42; @@ -3289,7 +3287,7 @@ fn nested_function_definition() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { function item2() : Unit { function item3() : Unit {} @@ -3320,7 +3318,7 @@ fn variable_in_nested_blocks() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { { let local16 = 10; @@ -3353,11 +3351,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 +3379,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 +3410,7 @@ fn lambda_inside_lambda() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { function item1() : Unit { let local13 = () -> { let local20 = (local24) -> local24 + 1; @@ -3441,10 +3439,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 +3462,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 +3485,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 +3516,7 @@ namespace Foo.Bar.Baz { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { @EntryPoint() function item1(): Int { item2() @@ -3529,7 +3527,7 @@ namespace Foo.Bar.Baz { } } - namespace namespace9 { + namespace namespace10 { function item4() : Int { 6 } } "#]], @@ -3556,17 +3554,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 +3591,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 +3627,13 @@ namespace Foo { } }"#}, &expect![[r#" - namespace namespace8 { + namespace namespace9 { operation item1() : Unit { } } - namespace namespace7 { + namespace namespace8 { open Bar; @EntryPoint() operation item3() : Unit { @@ -3655,7 +3653,7 @@ fn test_export_statement() { } " }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { } export item1; @@ -3700,29 +3698,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 +3742,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 +3773,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 +3807,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 +3837,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 +3859,7 @@ fn export_non_existent_symbol() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { export NonExistent; } @@ -3888,14 +3886,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 +3914,7 @@ fn disallow_exporting_local_vars() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { let local13 = 5; } @@ -3941,8 +3939,8 @@ fn export_non_item() { } "}, &expect![[r#" - namespace namespace7 {} - namespace namespace8 { + namespace namespace8 {} + namespace namespace9 { operation item2() : Unit { } export Unit; @@ -3970,12 +3968,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 +3998,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 +4030,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 +4064,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 +4094,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 +4117,7 @@ fn disallow_repeated_exports() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} export item1; export item1; @@ -4140,7 +4138,7 @@ fn disallow_repeated_exports_inline() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} export item1, item1; } @@ -4165,12 +4163,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 +4192,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 +4220,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 +4248,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 +4275,9 @@ fn import_non_existent_item() { } "}, &expect![[r#" - namespace namespace7 { - } namespace namespace8 { + } + namespace namespace9 { import Foo.Bar; operation item2() : Unit { Bar(); @@ -4308,10 +4306,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 +4335,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 +4359,7 @@ fn import_non_item() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import Unit; operation item1() : Unit { } @@ -4387,11 +4385,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 +4414,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 +4444,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 +4469,7 @@ fn import_non_existent_namespace() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { import NonExistent; } @@ -4493,7 +4491,7 @@ fn import_self() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { import item1; } @@ -4515,10 +4513,10 @@ fn import_duplicate_symbol() { } "# }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import item2, item2; } - namespace namespace9 { + namespace namespace10 { operation item2() : Unit {} } "#]], @@ -4539,11 +4537,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 +4562,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 +4593,7 @@ fn import_takes_precedence_over_local_decl() { } "# }, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit { import item3; @@ -4604,7 +4602,7 @@ fn import_takes_precedence_over_local_decl() { } - namespace namespace9 { + namespace namespace10 { operation item3() : Unit {} } "#]], @@ -4624,10 +4622,10 @@ fn import_then_export() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { operation item1() : Unit {} } - namespace namespace8 { + namespace namespace9 { import item1; export item1; } @@ -4680,40 +4678,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 +4737,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 +4764,7 @@ fn invalid_import() { } "}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import A.B.C; operation item1() : Unit { } @@ -4797,15 +4795,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 +4831,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 +4864,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 +4893,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 +4924,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 +4958,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 +4990,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 +5018,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 +5053,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 +5095,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 +5133,7 @@ fn import_newtype() { }"#}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import item3; // no error operation item1() : Unit { @@ -5143,7 +5141,7 @@ fn import_newtype() { } } - namespace namespace8 { + namespace namespace9 { newtype item3 = String; export item3; @@ -5161,9 +5159,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 +5178,7 @@ fn glob_import_ns_not_found() { } "#}, &expect![[r#" - namespace namespace7 { + namespace namespace8 { import Bar.*; } @@ -5198,8 +5196,8 @@ fn allow_export_of_namespace_within_itself() { } "#}, &expect![[r#" - namespace namespace7 { - export namespace7; + namespace namespace8 { + export namespace8; } "#]], ); @@ -5215,7 +5213,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 +5231,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/misc.rs b/compiler/qsc_partial_eval/src/tests/misc.rs index d05ea68a2a..c5ea3bf262 100644 --- a/compiler/qsc_partial_eval/src/tests/misc.rs +++ b/compiler/qsc_partial_eval/src/tests/misc.rs @@ -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: 13926, hi: 13941 } })"]); } diff --git a/language_service/src/completion.rs b/language_service/src/completion.rs index e8af05f39f..89bc081016 100644 --- a/language_service/src/completion.rs +++ b/language_service/src/completion.rs @@ -123,7 +123,7 @@ pub(crate) fn get_completions( let mut prelude_ns_ids: Vec = PRELUDE .into_iter() .map(|ns| ImportItem { - path: ns.into_iter().map(Rc::from).collect(), + path: ns.into_iter().map(|x| Rc::from(*x)).collect(), alias: None, is_glob: true, }) diff --git a/library/std/src/Std/Convert.qs b/library/std/src/Std/Convert.qs index 3aa1f18280..19a0ed6c7a 100644 --- a/library/std/src/Std/Convert.qs +++ b/library/std/src/Std/Convert.qs @@ -1,284 +1,297 @@ - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; +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 +/// 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; - } +/// 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 - } +/// 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 } - } +/// 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}."); +/// 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; - } + 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`."); + number +} - result + /// # 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; - } +/// 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 +} - 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}."); +/// 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; - } + 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]; - } + number +} - output + /// # 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]; } - /// # 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 +} - 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)); - } +/// 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) - ); - } +/// 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; - } +/// 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 +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 index 40fc614405..c250b29b48 100644 --- a/library/std/src/Std/Diagnostics.qs +++ b/library/std/src/Std/Diagnostics.qs @@ -1,331 +1,331 @@ 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. +/// +/// # 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; - } +/// 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; - } +/// 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; - } +/// 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; } + 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; - } +/// 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 { +/// 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]; + // 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); + // Apply operations. + within { + for i in 0..nQubits - 1 { + H(reference[i]); + CNOT(reference[i], target[i]); } - - // Check and return result. - let areEqual = CheckAllZero(reference) and CheckAllZero(target); - ResetAll(target); - ResetAll(reference); - areEqual + } 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; - } +/// 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; - } +/// 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; - } +/// 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; - } +/// 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; - } +/// 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; - } +/// 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 +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 index 86887b4b20..62fc0acb30 100644 --- a/library/std/src/Std/InternalHelpers.qs +++ b/library/std/src/Std/InternalHelpers.qs @@ -2,249 +2,249 @@ // Licensed under the MIT License. - import Std.Arrays.*; - open Microsoft.Quantum.Core; - open Microsoft.Quantum.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); +import Std.Arrays.*; +open Microsoft.Quantum.Core; +open Microsoft.Quantum.Math; +import Std.Intrinsic.*; +import QIR.Intrinsic.*; + +internal operation CH(control : Qubit, target : Qubit) : Unit is Adj { + within { + S(target); + H(target); T(target); - CNOT(control, target); - Adjoint T(target); + } apply { 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 +internal operation CCH(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + within { + S(target); 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); + } apply { + CCNOT(control1, control2, target); } +} - internal operation CCZ(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - within { - H(target); - } apply { - CCNOT(control1, control2, target); - } +internal operation ApplyGlobalPhase(theta : Double) : Unit is Ctl + Adj { + body ... { + ControllableGlobalPhase(theta); } - - internal operation CCY(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - within { - MapPauli(target, PauliX, PauliY); - } apply { - CCNOT(control1, control2, target); - } + adjoint ... { + ControllableGlobalPhase(-theta); } +} - internal operation CRxx(control : Qubit, theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit { - within { - CNOT(qubit1, qubit0); - } apply { - Controlled Rx([control], (theta, qubit0)); - } +// 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); } - - 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]; + 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); } } - 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); } +} + +// 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); + } +} - internal operation SpreadZ(from : Qubit, to : Qubit[]) : Unit is Adj { - let targets = GetSpread(from, to); - for (ctl, tgt) in targets { - CNOT(ctl, tgt); - } - } + /// 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]); + } +} - 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; - } + /// 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 } + + targets +} diff --git a/library/std/src/Std/Intrinsic.qs b/library/std/src/Std/Intrinsic.qs index 05dfea9fc7..f7c8f01f7a 100644 --- a/library/std/src/Std/Intrinsic.qs +++ b/library/std/src/Std/Intrinsic.qs @@ -2,387 +2,342 @@ // Licensed under the MIT License. - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Core; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open QIR.Intrinsic; - import Std.InternalHelpers.*; +open Microsoft.Quantum.Convert; +open Microsoft.Quantum.Core; +open Microsoft.Quantum.Diagnostics; +open Microsoft.Quantum.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); - } +/// # 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); - } +/// 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; +/// 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; +/// 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); +/// 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]); - } + 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 + } + } else { + // len > 2 + within { + for i in 0..Length(paulis) - 1 { + MapPauli(qubits[i], PauliZ, paulis[i]); + } + } apply { within { - for i in 0..Length(paulis) - 1 { - MapPauli(qubits[i], PauliZ, paulis[i]); - } + SpreadZ(qubits[1], qubits[2..Length(qubits) - 1]); } apply { - within { - SpreadZ(qubits[1], qubits[2..Length(qubits) - 1]); - } apply { - Rzz(angle, qubits[0], qubits[1]); - } + Rzz(angle, qubits[0], qubits[1]); } } } - adjoint ... { - Exp(paulis, -theta, qubits); - } } + 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 ... { +/// 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); - } - 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); - } + } 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; } + 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; - } +/// 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) - } +/// 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]) - } +/// 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) - } +/// 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."; } - - /// # 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."; + if Length(bases) == 1 { + within { + MapPauli(qubits[0], PauliZ, bases[0]); + } apply { + __quantum__qis__m__body(qubits[0]) } - // 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. + } else { use aux = Qubit(); within { H(aux); @@ -393,766 +348,811 @@ } __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); +/// 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 |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 { +/// 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); - R(PauliI, -theta, qubit); + } else { + // PauliI + ApplyGlobalPhase(-theta / 2.0); } +} /// # 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); - } +/// 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 - /// 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); - } +/// 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 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); - } - } +/// 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 - /// 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); +/// 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 ... { +/// 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); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__rx__body(theta, qubit); - } else { - within { - MapPauli(qubit, PauliZ, PauliX); - } apply { - Controlled Rz(ctls, (theta, qubit)); - } + } else { + within { + MapPauli(qubit, PauliZ, PauliX); + } apply { + Controlled Rz(ctls, (theta, qubit)); } } - adjoint ... { - Rx(-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 ... { +/// 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); - } - 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); - } + } 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); - } } + 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 ... { +/// 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); - } - controlled (ctls, ...) { - if Length(ctls) == 0 { - __quantum__qis__ry__body(theta, qubit); - } else { - within { - MapPauli(qubit, PauliZ, PauliY); - } apply { - Controlled Rz(ctls, (theta, qubit)); - } + } else { + within { + MapPauli(qubit, PauliZ, PauliY); + } apply { + Controlled Rz(ctls, (theta, qubit)); } } - adjoint ... { - Ry(-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 ... { +/// 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); - } - 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); - } + } 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); - } } + 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 ... { +/// 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); - } - 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); - } + } 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); - } } + 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 ... { +/// 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); - } - 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); - } + } 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); - } } + 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 ... { +/// 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); - } - 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)); - } + } 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)); - } + } + 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 ... { +/// 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); - } - 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)); - } + } 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 ... { +/// 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); - } - 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); - } + } 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); - } + } + 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 ... { +/// 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); - } - 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); - } + } 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; } + 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 ... { +/// 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); - } - 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); - } + } 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; } + 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 ... { +/// 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); - } - 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); - } + } 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; } + 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; - } +/// 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; +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 index 329ff427f9..97050651cb 100644 --- a/library/std/src/Std/Logical.qs +++ b/library/std/src/Std/Logical.qs @@ -2,30 +2,30 @@ // 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; +/// # 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 index c018e5d348..52079e74fa 100644 --- a/library/std/src/Std/Math.qs +++ b/library/std/src/Std/Math.qs @@ -2,1454 +2,1546 @@ // Licensed under the MIT License. - 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) { +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 - } + } 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) { +/// 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 - } + } 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) { +/// 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 - } + } elif (a > 0L) { + + 1 + } else { + 0 } +} /// # Summary - /// Returns the absolute value of an integer. - function AbsI(a : Int) : Int { - a < 0 ? -a | a - } +/// 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 - } +/// 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 - } +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 - } +/// 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 - } +/// 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 - } +/// 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 - } +/// 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 - } +/// 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 - } +/// 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; - } +/// 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; - } + 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 - // + min +} - /// # Summary - /// Returns the angle whose cosine is the specified number. - function ArcCos(x : Double) : Double { - body intrinsic; - } +// +// Trigonometric functions +// - /// # Summary - /// Returns the angle whose sine is the specified number. - function ArcSin(y : Double) : Double { - body intrinsic; - } +/// # Summary +/// Returns the angle whose cosine is the specified number. +function ArcCos(x : Double) : Double { + body intrinsic; +} /// # Summary - /// Returns the angle whose tangent is the specified number. - function ArcTan(d : Double) : Double { - body intrinsic; - } +/// Returns the angle whose sine is the specified number. +function ArcSin(y : 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; - } +/// Returns the angle whose tangent is the specified number. +function ArcTan(d : Double) : Double { + body intrinsic; +} /// # Summary - /// Returns the cosine of the specified angle. - function Cos(theta : 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; +} /// # Summary - /// Returns the hyperbolic cosine of the specified angle. - function Cosh(d : Double) : Double { - body intrinsic; - } +/// Returns the cosine of the specified angle. +function Cos(theta : Double) : Double { + body intrinsic; +} /// # Summary - /// Returns the sine of the specified angle. - function Sin(theta : Double) : Double { - body intrinsic; - } +/// Returns the hyperbolic cosine of the specified angle. +function Cosh(d : Double) : Double { + body intrinsic; +} /// # Summary - /// Returns the hyperbolic sine of the specified angle. - function Sinh(d : Double) : Double { - body intrinsic; - } +/// Returns the sine of the specified angle. +function Sin(theta : Double) : Double { + body intrinsic; +} /// # Summary - /// Returns the tangent of the specified angle. - function Tan(d : Double) : Double { - body intrinsic; - } +/// Returns the hyperbolic sine of the specified angle. +function Sinh(d : Double) : Double { + body intrinsic; +} /// # Summary - /// Returns the hyperbolic tangent of the specified angle. - function Tanh(d : Double) : Double { - body intrinsic; - } +/// Returns the tangent of the specified angle. +function Tan(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)) - } +/// Returns the hyperbolic tangent of the specified angle. +function Tanh(d : Double) : Double { + body intrinsic; +} /// # Summary - /// Computes the inverse hyperbolic sine of a number. - function ArcSinh(x : Double) : Double { - Log(x + Sqrt(x * x + 1.0)) - } - +/// 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 tangent of a number. - function ArcTanh(x : Double) : Double { - Log((1.0 + x) / (1.0 - x)) * 0.5 - } +/// Computes the inverse hyperbolic sine of a number. +function ArcSinh(x : Double) : Double { + Log(x + Sqrt(x * x + 1.0)) +} - // - // Sqrt, Log, exp, etc. - // /// # Summary - /// Returns the square root of a specified number. - function Sqrt(d : Double) : Double { - body intrinsic; - } +/// Computes the inverse hyperbolic tangent of a number. +function ArcTanh(x : Double) : Double { + Log((1.0 + x) / (1.0 - x)) * 0.5 +} - /// # Summary - /// Returns the natural (base _e_) logarithm of a specified number. - function Log(input : Double) : Double { - body intrinsic; - } +// +// Sqrt, Log, exp, etc. +// - /// # Summary - /// Returns the base-10 logarithm of a specified number. - function Log10(input : Double) : Double { - Log(input) / Log(10.0) - } +/// # Summary +/// Returns the square root of a specified number. +function Sqrt(d : Double) : Double { + body intrinsic; +} /// # Summary - /// Computes the base-2 logarithm of a number. - function Lg(input : Double) : Double { - Log(input) / Log(2.0) - } - - // - // Truncation and Rounding - // +/// Returns the natural (base _e_) logarithm of a specified number. +function Log(input : Double) : Double { + body intrinsic; +} /// # 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 base-10 logarithm of a specified number. +function Log10(input : Double) : Double { + Log(input) / Log(10.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 - } - } +/// Computes the base-2 logarithm of a number. +function Lg(input : Double) : Double { + Log(input) / Log(2.0) +} - /// # 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 - } - } +// +// Truncation and Rounding +// - /// # 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; - } +/// # 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; +} - 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) - } +internal function ExtendedTruncation(value : Double) : (Int, Double, Bool) { + let truncated = Truncate(value); + (truncated, IntAsDouble(truncated) - value, value >= 0.0) +} /// # 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 +/// 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 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 +/// 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 - /// 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) - } +/// 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)) } +} - /// # 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); - } +// +// Modular arithmetic +// - if r2 == 0L and AbsL(s2) <= denominatorBound { - (-t2 * signB, s2 * signA) - } else { - (-t1 * signB, s1 * signA) - } - } +/// # 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 - /// 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. - // - +/// 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 - /// 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 - } +/// 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 - /// 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 - } +/// 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 - /// 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; +/// 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; } - count + // update value of expBase^(2^k) (mod `modulus`) + set expPow2mod = (expPow2mod * expPow2mod) % modulus; + set powerBits >>>= 1; } - /// # 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 - } + res +} /// # 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 - } +/// 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"); - // - // 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] + // shortcut when modulus is 1 + if modulus == 1L { + return 0L; } - /// # 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 - } + mutable res = 1L; + mutable expPow2mod = expBase % modulus; + mutable powerBits = power; - /// # 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)); + while powerBits > 0L { + if (powerBits &&& 1L) != 0L { + // if bit pₖ is 1, multiply res by expBase^(2ᵏ) (mod `modulus`) + set res = (res * expPow2mod) % modulus; } - 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, + // 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, + 14.1360979747417471, -0.491913816097620199, - 0.339946499848118887e-4, - 0.465236289270485756e-4, + 0.339946499848118887e-4, + 0.465236289270485756e-4, -0.983744753048795646e-4, - 0.158088703224912494e-3, + 0.158088703224912494e-3, -0.210264441724104883e-3, - 0.217439618115212643e-3, + 0.217439618115212643e-3, -0.164318106536763890e-3, - 0.844182239838527433e-4, + 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 + 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 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 { + ) +} + + /// # 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; +} + + /// # 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/Std/Measurement.qs b/library/std/src/Std/Measurement.qs index 3d0d7ba2a2..81009c68a6 100644 --- a/library/std/src/Std/Measurement.qs +++ b/library/std/src/Std/Measurement.qs @@ -2,184 +2,184 @@ // Licensed under the MIT License. - open Microsoft.Quantum.Core; - open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Diagnostics; - open QIR.Intrinsic; +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 +/// 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 +/// 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 +/// 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) - } +/// 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) - } +/// 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) - } +/// 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}."); +/// 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; - } + 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; + + 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 index 2a20346660..7709d6d2e1 100644 --- a/library/std/src/Std/Random.qs +++ b/library/std/src/Std/Random.qs @@ -3,74 +3,74 @@ - /// # 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 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; - } +/// 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; - } +/// 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; +export DrawRandomInt, DrawRandomDouble, DrawRandomBool; diff --git a/library/std/src/Std/ResourceEstimation.qs b/library/std/src/Std/ResourceEstimation.qs index 581e2a83df..a834565d66 100644 --- a/library/std/src/Std/ResourceEstimation.qs +++ b/library/std/src/Std/ResourceEstimation.qs @@ -3,179 +3,179 @@ - // 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. +// 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 - /// 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; +} /// # 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; - } +/// 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 - /// 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. +/// 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 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 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 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 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 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 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 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 Measurements is equal to the `amount`. +function MeasurementCount(amount : Int) : (Int, Int) { + return (5, 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); - } +/// 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 - /// 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); - } +/// 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 - /// 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; - } +/// 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 - /// 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; +/// Companion operation to `BeginRepeatEstimates`. +operation EndRepeatEstimates() : Unit { + body ... { + EndRepeatEstimatesInternal(); } + adjoint self; +} - internal operation AccountForEstimatesInternal(estimates : (Int, Int)[], layout : Int, arguments : Qubit[]) : Unit { - body intrinsic; - } +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 `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; +/// 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/Std/Unstable/Arithmetic.qs b/library/std/src/Std/Unstable/Arithmetic.qs index edded93320..8cd6f370b3 100644 --- a/library/std/src/Std/Unstable/Arithmetic.qs +++ b/library/std/src/Std/Unstable/Arithmetic.qs @@ -2,701 +2,701 @@ // Licensed under the MIT License. - import Std.Arrays.*; - import QIR.Intrinsic.*; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Convert; - import Std.Unstable.ArithmeticHelpers.*; +import Std.Arrays.*; +import QIR.Intrinsic.*; +open Microsoft.Quantum.Diagnostics; +open Microsoft.Quantum.Math; +open Microsoft.Quantum.Convert; +import Std.Unstable.ArithmeticHelpers.*; + +/// # Summary +/// This applies the in-place majority operation to 3 qubits. +/// +/// # Description +/// Assuming the state of the input qubits are |x⟩, |y⟩ and |z⟩, then +/// this operation performs the following transformation: +/// |x⟩|y⟩|z⟩ ↦ |x ⊕ z⟩|y ⊕ z⟩MAJ(x, y, z). +/// +/// # Input +/// ## x +/// The first input qubit. +/// ## y +/// The second input qubit. +/// ## z +/// A qubit onto which the majority function will be applied. +operation MAJ(x : Qubit, y : Qubit, z : Qubit) : Unit is Adj + Ctl { + CNOT(z, y); + CNOT(z, x); + CCNOT(y, x, z); +} /// # Summary - /// This applies the in-place majority operation to 3 qubits. - /// - /// # Description - /// Assuming the state of the input qubits are |x⟩, |y⟩ and |z⟩, then - /// this operation performs the following transformation: - /// |x⟩|y⟩|z⟩ ↦ |x ⊕ z⟩|y ⊕ z⟩MAJ(x, y, z). - /// - /// # Input - /// ## x - /// The first input qubit. - /// ## y - /// The second input qubit. - /// ## z - /// A qubit onto which the majority function will be applied. - operation MAJ(x : Qubit, y : Qubit, z : Qubit) : Unit is Adj + Ctl { - CNOT(z, y); - CNOT(z, x); - CCNOT(y, x, z); - } - - /// # Summary - /// Reflects a quantum register about a given classical integer. - /// - /// # Description - /// Given a quantum register initially in the state ∑ᵢ(αᵢ|i⟩), - /// where each |i⟩ is a basis state representing an integer i, - /// reflects the state of the register about the basis state |j⟩ - /// for a given integer j: ∑ᵢ(-1)^(δᵢⱼ)(αᵢ|i⟩) - /// This operation is implemented in-place, without explicit allocation of - /// additional auxiliary qubits. - /// - /// # Input - /// ## index - /// The classical integer j indexing the basis state about which to reflect. - /// ## reg - /// Little-endian quantum register to reflect. - operation ReflectAboutInteger(index : Int, reg : Qubit[]) : Unit is Adj + Ctl { - within { - // Evaluation optimization for case index == 0 - if index == 0 { - ApplyToEachA(X, reg); - } else { - // We want to reduce to the problem of reflecting about the all-ones - // state. To do that, we apply our reflection within an application - // of X instructions that flip all the zeros in our index. - ApplyPauliFromInt(PauliX, false, index, reg); - } - } apply { - Controlled ApplyAsSinglyControlled(Most(reg), (Z, Tail(reg))); +/// Reflects a quantum register about a given classical integer. +/// +/// # Description +/// Given a quantum register initially in the state ∑ᵢ(αᵢ|i⟩), +/// where each |i⟩ is a basis state representing an integer i, +/// reflects the state of the register about the basis state |j⟩ +/// for a given integer j: ∑ᵢ(-1)^(δᵢⱼ)(αᵢ|i⟩) +/// This operation is implemented in-place, without explicit allocation of +/// additional auxiliary qubits. +/// +/// # Input +/// ## index +/// The classical integer j indexing the basis state about which to reflect. +/// ## reg +/// Little-endian quantum register to reflect. +operation ReflectAboutInteger(index : Int, reg : Qubit[]) : Unit is Adj + Ctl { + within { + // Evaluation optimization for case index == 0 + if index == 0 { + ApplyToEachA(X, reg); + } else { + // We want to reduce to the problem of reflecting about the all-ones + // state. To do that, we apply our reflection within an application + // of X instructions that flip all the zeros in our index. + ApplyPauliFromInt(PauliX, false, index, reg); } + } apply { + Controlled ApplyAsSinglyControlled(Most(reg), (Z, Tail(reg))); } - - // - // Add, Increment | Operation | Description - // ____________________|________________|_______________________________________________________________ - // y += 5 | IncByI, IncByL | Increment LE register in-place by integer - // y += x | IncByLE | Increment LE register in-place by LE register - // z = x + 5 (z was 0) | | Add integer to LE register creating result out-of-place - // z = x + y (z was 0) | AddLE | Add two LE register creating result out-of-place - // z += x + 5 | | Increment LE register by the sum of integer and LE register - // z += x + y | | Increment LE register by the sum of two LE registers - // - // IncByLE implementations: - // RippleCarryTTKIncByLE (default) - // RippleCarryCGIncByLE - // FourierTDIncByLE - // via IncByLEUsingAddLE and any out-of-place addition - // IncByI implementations: - // via IncByIUsingIncByLE and any in-place LE adder - // IncByL implementations: - // via IncByLUsingIncByLE and any in-place LE adder - // AddLE implementations: - // RippleCarryCGAddLE (default) - // LookAheadDKRSAddLE - // +} + +// +// Add, Increment | Operation | Description +// ____________________|________________|_______________________________________________________________ +// y += 5 | IncByI, IncByL | Increment LE register in-place by integer +// y += x | IncByLE | Increment LE register in-place by LE register +// z = x + 5 (z was 0) | | Add integer to LE register creating result out-of-place +// z = x + y (z was 0) | AddLE | Add two LE register creating result out-of-place +// z += x + 5 | | Increment LE register by the sum of integer and LE register +// z += x + y | | Increment LE register by the sum of two LE registers +// +// IncByLE implementations: +// RippleCarryTTKIncByLE (default) +// RippleCarryCGIncByLE +// FourierTDIncByLE +// via IncByLEUsingAddLE and any out-of-place addition +// IncByI implementations: +// via IncByIUsingIncByLE and any in-place LE adder +// IncByL implementations: +// via IncByLUsingIncByLE and any in-place LE adder +// AddLE implementations: +// RippleCarryCGAddLE (default) +// LookAheadDKRSAddLE +// + +/// # Summary +/// Increments a little-endian register ys by an integer number c +/// +/// # Description +/// Computes ys += c modulo 2ⁿ, where ys is a little-endian register, +/// Length(ys) = n > 0, c is a Int number, 0 ≤ c < 2ⁿ. +/// NOTE: Use IncByIUsingIncByLE directly if the choice of implementation +/// is important. +operation IncByI(c : Int, ys : Qubit[]) : Unit is Adj + Ctl { + IncByIUsingIncByLE(RippleCarryTTKIncByLE, c, ys); +} /// # Summary - /// Increments a little-endian register ys by an integer number c - /// - /// # Description - /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register, - /// Length(ys) = n > 0, c is a Int number, 0 ≤ c < 2ⁿ. - /// NOTE: Use IncByIUsingIncByLE directly if the choice of implementation - /// is important. - operation IncByI(c : Int, ys : Qubit[]) : Unit is Adj + Ctl { - IncByIUsingIncByLE(RippleCarryTTKIncByLE, c, ys); - } +/// Increments a little-endian register ys by a BigInt number c +/// +/// # Description +/// Computes ys += c modulo 2ⁿ, where ys is a little-endian register, +/// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. +/// NOTE: Use IncByLUsingIncByLE directly if the choice of implementation +/// is important. +operation IncByL(c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { + IncByLUsingIncByLE(RippleCarryTTKIncByLE, c, ys); +} /// # Summary - /// Increments a little-endian register ys by a BigInt number c - /// - /// # Description - /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register, - /// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. - /// NOTE: Use IncByLUsingIncByLE directly if the choice of implementation - /// is important. - operation IncByL(c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { - IncByLUsingIncByLE(RippleCarryTTKIncByLE, c, ys); - } +/// Increments a little-endian register ys by a little-endian register xs +/// +/// # Description +/// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, +/// and Length(xs) ≤ Length(ys) = n. +/// NOTE: Use operations like RippleCarryCGIncByLE directly if +/// the choice of implementation is important. +operation IncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + RippleCarryTTKIncByLE(xs, ys); +} /// # Summary - /// Increments a little-endian register ys by a little-endian register xs - /// - /// # Description - /// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, - /// and Length(xs) ≤ Length(ys) = n. - /// NOTE: Use operations like RippleCarryCGIncByLE directly if - /// the choice of implementation is important. - operation IncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - RippleCarryTTKIncByLE(xs, ys); - } +/// Sets a zero-initialized little-endian register zs to the sum of +/// little-endian registers xs and ys +/// +/// # Description +/// Computes zs := xs + ys modulo 2ⁿ, where xs, ys, and zs are little-endian registers, +/// Length(xs) = Length(ys) ≤ Length(zs) = n, assuming zs is 0-initialized. +/// NOTE: Use operations like RippleCarryCGAddLE directly if +/// the choice of implementation is important. +operation AddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + RippleCarryCGAddLE(xs, ys, zs); +} /// # Summary - /// Sets a zero-initialized little-endian register zs to the sum of - /// little-endian registers xs and ys - /// - /// # Description - /// Computes zs := xs + ys modulo 2ⁿ, where xs, ys, and zs are little-endian registers, - /// Length(xs) = Length(ys) ≤ Length(zs) = n, assuming zs is 0-initialized. - /// NOTE: Use operations like RippleCarryCGAddLE directly if - /// the choice of implementation is important. - operation AddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { - RippleCarryCGAddLE(xs, ys, zs); +/// Reversible, in-place ripple-carry addition of two integers. +/// +/// # Description +/// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, +/// and Length(xs) ≤ Length(ys) = n. +/// This operation uses the ripple-carry algorithm. +/// Note that if Length(ys) >= Length(xs)+2, xs is padded with 0-initialized +/// qubits to match ys's length. The operation doesn't use any auxiliary +/// qubits otherwise. +/// +/// # References +/// - [arXiv:0910.2530](https://arxiv.org/abs/0910.2530) +/// "Quantum Addition Circuits and Unbounded Fan-Out", +/// Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro +operation RippleCarryTTKIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + let xsLen = Length(xs); + let ysLen = Length(ys); + + Fact(ysLen >= xsLen, "Register `ys` must be longer than register `xs`."); + Fact(xsLen >= 1, "Registers `xs` and `ys` must contain at least one qubit."); + + if xsLen == ysLen { + if xsLen > 1 { + within { + ApplyOuterTTKAdder(xs, ys); + } apply { + ApplyInnerTTKAdderNoCarry(xs, ys); + } + } + CNOT(xs[0], ys[0]); + } elif xsLen + 1 == ysLen { + if xsLen > 1 { + CNOT(xs[xsLen - 1], ys[ysLen - 1]); + within { + ApplyOuterTTKAdder(xs, ys); + } apply { + ApplyInnerTTKAdderWithCarry(xs, ys); + } + } else { + CCNOT(xs[0], ys[0], ys[1]); + } + CNOT(xs[0], ys[0]); + } elif xsLen + 2 <= ysLen { + // Pad xs so that its length is one qubit shorter than ys. + use padding = Qubit[ysLen - xsLen - 1]; + RippleCarryTTKIncByLE(xs + padding, ys); } +} /// # Summary - /// Reversible, in-place ripple-carry addition of two integers. - /// - /// # Description - /// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, - /// and Length(xs) ≤ Length(ys) = n. - /// This operation uses the ripple-carry algorithm. - /// Note that if Length(ys) >= Length(xs)+2, xs is padded with 0-initialized - /// qubits to match ys's length. The operation doesn't use any auxiliary - /// qubits otherwise. - /// - /// # References - /// - [arXiv:0910.2530](https://arxiv.org/abs/0910.2530) - /// "Quantum Addition Circuits and Unbounded Fan-Out", - /// Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro - operation RippleCarryTTKIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - let xsLen = Length(xs); - let ysLen = Length(ys); - - Fact(ysLen >= xsLen, "Register `ys` must be longer than register `xs`."); - Fact(xsLen >= 1, "Registers `xs` and `ys` must contain at least one qubit."); - - if xsLen == ysLen { - if xsLen > 1 { - within { - ApplyOuterTTKAdder(xs, ys); - } apply { - ApplyInnerTTKAdderNoCarry(xs, ys); - } - } +/// Increments a little-endian register ys by a little-endian register xs +/// using the ripple-carry algorithm. +/// +/// # Description +/// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, +/// and Length(xs) ≤ Length(ys) = n. +/// Note that if Length(xs) != Length(ys), xs is padded with 0-initialized +/// qubits to match ys's length. +/// This operation uses the ripple-carry algorithm. +/// +/// # Reference +/// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) +/// "Halving the cost of quantum addition", Craig Gidney. +operation RippleCarryCGIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + let xsLen = Length(xs); + let ysLen = Length(ys); + + Fact(ysLen >= xsLen, "Register `ys` must be longer than register `xs`."); + Fact(xsLen >= 1, "Registers `xs` and `ys` must contain at least one qubit."); + + if ysLen - xsLen >= 2 { + // Pad xs so that its length is one qubit shorter than ys. + use padding = Qubit[ysLen - xsLen - 1]; + RippleCarryCGIncByLE(xs + padding, ys); + } elif xsLen == 1 { + if ysLen == 1 { CNOT(xs[0], ys[0]); - } elif xsLen + 1 == ysLen { - if xsLen > 1 { - CNOT(xs[xsLen - 1], ys[ysLen - 1]); + } elif ysLen == 2 { + HalfAdderForInc(xs[0], ys[0], ys[1]); + } + } else { + use carries = Qubit[xsLen]; + within { + ApplyAndAssuming0Target(xs[0], ys[0], carries[0]); + } apply { + for i in 1..xsLen - 2 { + CarryForInc(carries[i - 1], xs[i], ys[i], carries[i]); + } + if xsLen == ysLen { within { - ApplyOuterTTKAdder(xs, ys); + CNOT(carries[xsLen - 2], xs[xsLen - 1]); } apply { - ApplyInnerTTKAdderWithCarry(xs, ys); + CNOT(xs[xsLen - 1], ys[xsLen - 1]); } } else { - CCNOT(xs[0], ys[0], ys[1]); + FullAdderForInc(carries[xsLen - 2], xs[xsLen - 1], ys[xsLen - 1], ys[xsLen]); } - CNOT(xs[0], ys[0]); - } elif xsLen + 2 <= ysLen { - // Pad xs so that its length is one qubit shorter than ys. - use padding = Qubit[ysLen - xsLen - 1]; - RippleCarryTTKIncByLE(xs + padding, ys); - } - } - - /// # Summary - /// Increments a little-endian register ys by a little-endian register xs - /// using the ripple-carry algorithm. - /// - /// # Description - /// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, - /// and Length(xs) ≤ Length(ys) = n. - /// Note that if Length(xs) != Length(ys), xs is padded with 0-initialized - /// qubits to match ys's length. - /// This operation uses the ripple-carry algorithm. - /// - /// # Reference - /// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) - /// "Halving the cost of quantum addition", Craig Gidney. - operation RippleCarryCGIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - let xsLen = Length(xs); - let ysLen = Length(ys); - - Fact(ysLen >= xsLen, "Register `ys` must be longer than register `xs`."); - Fact(xsLen >= 1, "Registers `xs` and `ys` must contain at least one qubit."); - - if ysLen - xsLen >= 2 { - // Pad xs so that its length is one qubit shorter than ys. - use padding = Qubit[ysLen - xsLen - 1]; - RippleCarryCGIncByLE(xs + padding, ys); - } elif xsLen == 1 { - if ysLen == 1 { - CNOT(xs[0], ys[0]); - } elif ysLen == 2 { - HalfAdderForInc(xs[0], ys[0], ys[1]); - } - } else { - use carries = Qubit[xsLen]; - within { - ApplyAndAssuming0Target(xs[0], ys[0], carries[0]); - } apply { - for i in 1..xsLen - 2 { - CarryForInc(carries[i - 1], xs[i], ys[i], carries[i]); - } - if xsLen == ysLen { - within { - CNOT(carries[xsLen - 2], xs[xsLen - 1]); - } apply { - CNOT(xs[xsLen - 1], ys[xsLen - 1]); - } - } else { - FullAdderForInc(carries[xsLen - 2], xs[xsLen - 1], ys[xsLen - 1], ys[xsLen]); - } - for i in xsLen - 2..-1..1 { - UncarryForInc(carries[i - 1], xs[i], ys[i], carries[i]); - } + for i in xsLen - 2..-1..1 { + UncarryForInc(carries[i - 1], xs[i], ys[i], carries[i]); } - CNOT(xs[0], ys[0]); } + CNOT(xs[0], ys[0]); } +} /// # Summary - /// Sets a zero-initialized little-endian register zs to the sum of - /// little-endian registers xs and ys using the ripple-carry algorithm. - /// - /// # Description - /// Computes zs := xs + ys + zs[0] modulo 2ⁿ, where xs, ys, and zs are - /// little-endian registers, Length(xs) = Length(ys) ≤ Length(zs) = n, - /// assuming zs is 0-initialized, except for maybe zs[0], which can be - // in |0> or |1> state and can be used as carry-in. - /// This operation uses the ripple-carry algorithm. - /// NOTE: `zs[Length(xs)]` can be used as carry-out, if `zs` is longer than `xs`. - /// - /// # Reference - /// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) - /// "Halving the cost of quantum addition", Craig Gidney. - operation RippleCarryCGAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { - let xsLen = Length(xs); - let zsLen = Length(zs); - Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); - Fact(zsLen >= xsLen, "Register `zs` must be no shorter than register `xs`."); - - // Since zs is zero-initialized, its bits at indexes higher than - // xsLen remain unused as there will be no carry into them. - let top = MinI(zsLen - 2, xsLen - 1); - for k in 0..top { - FullAdder(zs[k], xs[k], ys[k], zs[k + 1]); - } +/// Sets a zero-initialized little-endian register zs to the sum of +/// little-endian registers xs and ys using the ripple-carry algorithm. +/// +/// # Description +/// Computes zs := xs + ys + zs[0] modulo 2ⁿ, where xs, ys, and zs are +/// little-endian registers, Length(xs) = Length(ys) ≤ Length(zs) = n, +/// assuming zs is 0-initialized, except for maybe zs[0], which can be +// in |0> or |1> state and can be used as carry-in. +/// This operation uses the ripple-carry algorithm. +/// NOTE: `zs[Length(xs)]` can be used as carry-out, if `zs` is longer than `xs`. +/// +/// # Reference +/// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) +/// "Halving the cost of quantum addition", Craig Gidney. +operation RippleCarryCGAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + let xsLen = Length(xs); + let zsLen = Length(zs); + Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); + Fact(zsLen >= xsLen, "Register `zs` must be no shorter than register `xs`."); + + // Since zs is zero-initialized, its bits at indexes higher than + // xsLen remain unused as there will be no carry into them. + let top = MinI(zsLen - 2, xsLen - 1); + for k in 0..top { + FullAdder(zs[k], xs[k], ys[k], zs[k + 1]); + } - if xsLen > 0 and xsLen == zsLen { - CNOT(Tail(xs), Tail(zs)); - CNOT(Tail(ys), Tail(zs)); - } + if xsLen > 0 and xsLen == zsLen { + CNOT(Tail(xs), Tail(zs)); + CNOT(Tail(ys), Tail(zs)); } +} /// # Summary - /// Sets a zero-initialized little-endian register zs to the sum of - /// little-endian registers xs and ys using the carry-lookahead algorithm. - /// - /// # Description - /// Computes zs := xs + ys + zs[0] modulo 2ⁿ, where xs, ys, and zs are - /// little-endian registers, Length(xs) = Length(ys) ≤ Length(zs) = n, - /// assuming zs is 0-initialized, except for maybe zs[0], which can be - /// in |0> or |1> state and can be used as carry-in. - /// NOTE: `zs[Length(xs)]` can be used as carry-out, if `zs` is longer than `xs`. - /// This operation uses the carry-lookahead algorithm. - /// - /// # Reference - /// - [arXiv:quant-ph/0406142](https://arxiv.org/abs/quant-ph/0406142) - /// "A logarithmic-depth quantum carry-lookahead adder", - /// Thomas G. Draper, Samuel A. Kutin, Eric M. Rains, Krysta M. Svore - operation LookAheadDKRSAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { - let xsLen = Length(xs); - let zsLen = Length(zs); - Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); - Fact(zsLen >= xsLen, "Register `zs` must be no shorter than register `xs`."); - - if zsLen > xsLen { - // with carry-out - // compute initial generate values - for k in 0..xsLen - 1 { - ApplyAndAssuming0Target(xs[k], ys[k], zs[k + 1]); - } +/// Sets a zero-initialized little-endian register zs to the sum of +/// little-endian registers xs and ys using the carry-lookahead algorithm. +/// +/// # Description +/// Computes zs := xs + ys + zs[0] modulo 2ⁿ, where xs, ys, and zs are +/// little-endian registers, Length(xs) = Length(ys) ≤ Length(zs) = n, +/// assuming zs is 0-initialized, except for maybe zs[0], which can be +/// in |0> or |1> state and can be used as carry-in. +/// NOTE: `zs[Length(xs)]` can be used as carry-out, if `zs` is longer than `xs`. +/// This operation uses the carry-lookahead algorithm. +/// +/// # Reference +/// - [arXiv:quant-ph/0406142](https://arxiv.org/abs/quant-ph/0406142) +/// "A logarithmic-depth quantum carry-lookahead adder", +/// Thomas G. Draper, Samuel A. Kutin, Eric M. Rains, Krysta M. Svore +operation LookAheadDKRSAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + let xsLen = Length(xs); + let zsLen = Length(zs); + Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); + Fact(zsLen >= xsLen, "Register `zs` must be no shorter than register `xs`."); + + if zsLen > xsLen { + // with carry-out + // compute initial generate values + for k in 0..xsLen - 1 { + ApplyAndAssuming0Target(xs[k], ys[k], zs[k + 1]); + } - within { - // compute initial propagate values - for i in IndexRange(xs) { - CNOT(xs[i], ys[i]); - } - } apply { - if xsLen > 1 { - ComputeCarries(Rest(ys), zs[1..xsLen]); - } + within { + // compute initial propagate values + for i in IndexRange(xs) { + CNOT(xs[i], ys[i]); + } + } apply { + if xsLen > 1 { + ComputeCarries(Rest(ys), zs[1..xsLen]); + } - // compute sum into carries - for k in 0..xsLen - 1 { - CNOT(ys[k], zs[k]); - } + // compute sum into carries + for k in 0..xsLen - 1 { + CNOT(ys[k], zs[k]); } - } else { - // xsLen == zsLen, so without carry-out - LookAheadDKRSAddLE(Most(xs), Most(ys), zs); - CNOT(Tail(xs), Tail(zs)); - CNOT(Tail(ys), Tail(zs)); } + } else { + // xsLen == zsLen, so without carry-out + LookAheadDKRSAddLE(Most(xs), Most(ys), zs); + CNOT(Tail(xs), Tail(zs)); + CNOT(Tail(ys), Tail(zs)); } +} /// # Summary - /// Increments a little-endian register ys by a little-endian register xs - /// using Quantum Fourier Transform. - /// - /// # Description - /// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, - /// and Length(xs) = Length(ys) = n. - /// This operation uses Quantum Fourier Transform. - /// - /// # Reference - /// - [arXiv:quant-ph/0008033](https://arxiv.org/abs/quant-ph/0008033) - /// "Addition on a Quantum Computer", Thomas G. Draper - operation FourierTDIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - within { - ApplyQFT(ys); - } apply { - for i in IndexRange(xs) { - Controlled PhaseGradient([xs[i]], ys[i...]); - } +/// Increments a little-endian register ys by a little-endian register xs +/// using Quantum Fourier Transform. +/// +/// # Description +/// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, +/// and Length(xs) = Length(ys) = n. +/// This operation uses Quantum Fourier Transform. +/// +/// # Reference +/// - [arXiv:quant-ph/0008033](https://arxiv.org/abs/quant-ph/0008033) +/// "Addition on a Quantum Computer", Thomas G. Draper +operation FourierTDIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + within { + ApplyQFT(ys); + } apply { + for i in IndexRange(xs) { + Controlled PhaseGradient([xs[i]], ys[i...]); } } +} /// # Summary - /// Increments a little-endian register ys by a BigInt number c - /// using provided adder. - /// - /// # Description - /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register - /// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. - operation IncByLUsingIncByLE( - adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, - c : BigInt, - ys : Qubit[] - ) : Unit is Adj + Ctl { - - let ysLen = Length(ys); - Fact(ysLen > 0, "Length of `ys` must be at least 1."); - Fact(c >= 0L, "Constant `c` must be non-negative."); - Fact(c < 2L^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); - - if c != 0L { - // If c has j trailing zeros, then the j least significant - // bits of y won't be affected by the addition and can - // therefore be ignored by applying the addition only to - // the other qubits and shifting c accordingly. - let j = TrailingZeroCountL(c); - use x = Qubit[ysLen - j]; - within { - ApplyXorInPlaceL(c >>> j, x); - } apply { - adder(x, ys[j...]); - } +/// Increments a little-endian register ys by a BigInt number c +/// using provided adder. +/// +/// # Description +/// Computes ys += c modulo 2ⁿ, where ys is a little-endian register +/// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. +operation IncByLUsingIncByLE( + adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, + c : BigInt, + ys : Qubit[] +) : Unit is Adj + Ctl { + + let ysLen = Length(ys); + Fact(ysLen > 0, "Length of `ys` must be at least 1."); + Fact(c >= 0L, "Constant `c` must be non-negative."); + Fact(c < 2L^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); + + if c != 0L { + // If c has j trailing zeros, then the j least significant + // bits of y won't be affected by the addition and can + // therefore be ignored by applying the addition only to + // the other qubits and shifting c accordingly. + let j = TrailingZeroCountL(c); + use x = Qubit[ysLen - j]; + within { + ApplyXorInPlaceL(c >>> j, x); + } apply { + adder(x, ys[j...]); } } +} /// # Summary - /// Increments a little-endian register ys by an Int number c - /// using provided adder. - /// - /// # Description - /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register - /// Length(ys) = n > 0, c is an Int number, 0 ≤ c < 2ⁿ. - operation IncByIUsingIncByLE( - adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, - c : Int, - ys : Qubit[] - ) : Unit is Adj + Ctl { - - let ysLen = Length(ys); - Fact(ysLen > 0, "Length of `ys` must be at least 1."); - Fact(c >= 0, "Constant `c` must be non-negative."); - Fact(c < 2^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); - - if c != 0 { - // If c has j trailing zeros than the j least significant - // bits of y won't be affected by the addition and can - // therefore be ignored by applying the addition only to - // the other qubits and shifting c accordingly. - let j = TrailingZeroCountI(c); - use x = Qubit[ysLen - j]; - within { - ApplyXorInPlace(c >>> j, x); - } apply { - adder(x, ys[j...]); - } +/// Increments a little-endian register ys by an Int number c +/// using provided adder. +/// +/// # Description +/// Computes ys += c modulo 2ⁿ, where ys is a little-endian register +/// Length(ys) = n > 0, c is an Int number, 0 ≤ c < 2ⁿ. +operation IncByIUsingIncByLE( + adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, + c : Int, + ys : Qubit[] +) : Unit is Adj + Ctl { + + let ysLen = Length(ys); + Fact(ysLen > 0, "Length of `ys` must be at least 1."); + Fact(c >= 0, "Constant `c` must be non-negative."); + Fact(c < 2^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); + + if c != 0 { + // If c has j trailing zeros than the j least significant + // bits of y won't be affected by the addition and can + // therefore be ignored by applying the addition only to + // the other qubits and shifting c accordingly. + let j = TrailingZeroCountI(c); + use x = Qubit[ysLen - j]; + within { + ApplyXorInPlace(c >>> j, x); + } apply { + adder(x, ys[j...]); } } +} /// # Summary - /// Generic operation to turn two out-place adders into one in-place adder - /// - /// # Description - /// This implementation allows to specify two distinct adders for forward - /// and backward direction. The forward adder is always applied in its - /// body variant, whereas the backward adder is always applied in its adjoint - /// variant. Therefore, it's possible to, for example, use the ripple-carry - /// out-of-place adder in backwards direction to require no T gates. - /// - /// The controlled variant is also optimized in a way that everything but - /// the adders is controlled, - /// - /// # Reference - /// - [arXiv:2012.01624](https://arxiv.org/abs/2012.01624) - /// "Quantum block lookahead adders and the wait for magic states", - /// Craig Gidney. - operation IncByLEUsingAddLE( - forwardAdder : (Qubit[], Qubit[], Qubit[]) => Unit is Adj, - backwardAdder : (Qubit[], Qubit[], Qubit[]) => Unit is Adj, - xs : Qubit[], - ys : Qubit[] - ) : Unit is Adj + Ctl { - - body (...) { - let n = Length(xs); - - Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - - use qs = Qubit[n]; - - forwardAdder(xs, ys, qs); - for i in IndexRange(ys) { - SWAP(ys[i], qs[i]); - } - ApplyToEachA(X, qs); - within { - ApplyToEachA(X, ys); - } apply { - Adjoint backwardAdder(xs, ys, qs); - } +/// Generic operation to turn two out-place adders into one in-place adder +/// +/// # Description +/// This implementation allows to specify two distinct adders for forward +/// and backward direction. The forward adder is always applied in its +/// body variant, whereas the backward adder is always applied in its adjoint +/// variant. Therefore, it's possible to, for example, use the ripple-carry +/// out-of-place adder in backwards direction to require no T gates. +/// +/// The controlled variant is also optimized in a way that everything but +/// the adders is controlled, +/// +/// # Reference +/// - [arXiv:2012.01624](https://arxiv.org/abs/2012.01624) +/// "Quantum block lookahead adders and the wait for magic states", +/// Craig Gidney. +operation IncByLEUsingAddLE( + forwardAdder : (Qubit[], Qubit[], Qubit[]) => Unit is Adj, + backwardAdder : (Qubit[], Qubit[], Qubit[]) => Unit is Adj, + xs : Qubit[], + ys : Qubit[] +) : Unit is Adj + Ctl { + + body (...) { + let n = Length(xs); + + Fact(Length(ys) == n, "Registers xs and ys must be of same length"); + + use qs = Qubit[n]; + + forwardAdder(xs, ys, qs); + for i in IndexRange(ys) { + SWAP(ys[i], qs[i]); } - adjoint (...) { - let n = Length(xs); - - Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - - use qs = Qubit[n]; - - within { - ApplyToEachA(X, ys); - } apply { - forwardAdder(xs, ys, qs); - } - ApplyToEachA(X, qs); - for i in IndexRange(ys) { - SWAP(ys[i], qs[i]); - } + ApplyToEachA(X, qs); + within { + ApplyToEachA(X, ys); + } apply { Adjoint backwardAdder(xs, ys, qs); } - controlled (ctls, ...) { - // When we control everything except the adders, the adders will - // cancel themselves. - let n = Length(xs); + } + adjoint (...) { + let n = Length(xs); - Fact(Length(ys) == n, "Registers xs and ys must be of same length"); + Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - use qs = Qubit[n]; + use qs = Qubit[n]; + within { + ApplyToEachA(X, ys); + } apply { forwardAdder(xs, ys, qs); - for i in IndexRange(ys) { - Controlled SWAP(ctls, (ys[i], qs[i])) - } - ApplyToEachA(tgt => Controlled X(ctls, tgt), qs); - within { - ApplyToEachA(tgt => Controlled X(ctls, tgt), ys); - } apply { - Adjoint backwardAdder(xs, ys, qs); - } } - controlled adjoint (ctls, ...) { - // When we control everything except the adders, the adders will - // cancel themselves. - let n = Length(xs); + ApplyToEachA(X, qs); + for i in IndexRange(ys) { + SWAP(ys[i], qs[i]); + } + Adjoint backwardAdder(xs, ys, qs); + } + controlled (ctls, ...) { + // When we control everything except the adders, the adders will + // cancel themselves. + let n = Length(xs); - Fact(Length(ys) == n, "Registers xs and ys must be of same length"); + Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - use qs = Qubit[n]; + use qs = Qubit[n]; - within { - ApplyToEachA(tgt => Controlled X(ctls, tgt), ys); - } apply { - forwardAdder(xs, ys, qs); - } - ApplyToEachA(tgt => Controlled X(ctls, tgt), qs); - for i in IndexRange(ys) { - Controlled SWAP(ctls, (ys[i], qs[i])) - } + forwardAdder(xs, ys, qs); + for i in IndexRange(ys) { + Controlled SWAP(ctls, (ys[i], qs[i])) + } + ApplyToEachA(tgt => Controlled X(ctls, tgt), qs); + within { + ApplyToEachA(tgt => Controlled X(ctls, tgt), ys); + } apply { Adjoint backwardAdder(xs, ys, qs); } } + controlled adjoint (ctls, ...) { + // When we control everything except the adders, the adders will + // cancel themselves. + let n = Length(xs); - // - // Comparisons - // - // Compare BigInt and qubit register in a little-endian format and apply action - // if c < x { action(target) } | ApplyIfLessL - // if c <= x { action(target) } | ApplyIfLessOrEqualL - // if c == x { action(target) } | ApplyIfEqualL - // if c >= x { action(target) } | ApplyIfGreaterOrEqualL - // if c > x { action(target) } | ApplyIfGreaterL - // - // Compare two qubit registers in a little-endian format and apply action - // if x < y { action(target) } | ApplyIfLessLE - // if x <= y { action(target) } | ApplyIfLessOrEqualLE - // if x == y { action(target) } | ApplyIfEqualLE - // if x >= y { action(target) } | ApplyIfGreaterOrEqualLE - // if x > y { action(target) } | ApplyIfGreaterLE - // + Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - /// # Summary - /// Computes `if (c < x) { action(target) }`, that is, applies `action` to `target` - /// if a BigInt value `c` is less than the little-endian qubit register `x` - operation ApplyIfLessL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - ApplyActionIfGreaterThanOrEqualConstant(false, action, c + 1L, x, target); + use qs = Qubit[n]; + + within { + ApplyToEachA(tgt => Controlled X(ctls, tgt), ys); + } apply { + forwardAdder(xs, ys, qs); + } + ApplyToEachA(tgt => Controlled X(ctls, tgt), qs); + for i in IndexRange(ys) { + Controlled SWAP(ctls, (ys[i], qs[i])) + } + Adjoint backwardAdder(xs, ys, qs); } +} + +// +// Comparisons +// +// Compare BigInt and qubit register in a little-endian format and apply action +// if c < x { action(target) } | ApplyIfLessL +// if c <= x { action(target) } | ApplyIfLessOrEqualL +// if c == x { action(target) } | ApplyIfEqualL +// if c >= x { action(target) } | ApplyIfGreaterOrEqualL +// if c > x { action(target) } | ApplyIfGreaterL +// +// Compare two qubit registers in a little-endian format and apply action +// if x < y { action(target) } | ApplyIfLessLE +// if x <= y { action(target) } | ApplyIfLessOrEqualLE +// if x == y { action(target) } | ApplyIfEqualLE +// if x >= y { action(target) } | ApplyIfGreaterOrEqualLE +// if x > y { action(target) } | ApplyIfGreaterLE +// + +/// # Summary +/// Computes `if (c < x) { action(target) }`, that is, applies `action` to `target` +/// if a BigInt value `c` is less than the little-endian qubit register `x` +operation ApplyIfLessL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + ApplyActionIfGreaterThanOrEqualConstant(false, action, c + 1L, x, target); +} /// # Summary - /// Computes `if (c <= x) { action(target) }`, that is, applies `action` to `target` - /// if a BigInt value `c` is less or equal to the little-endian qubit register `x` - operation ApplyIfLessOrEqualL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - ApplyActionIfGreaterThanOrEqualConstant(false, action, c, x, target); - } +/// Computes `if (c <= x) { action(target) }`, that is, applies `action` to `target` +/// if a BigInt value `c` is less or equal to the little-endian qubit register `x` +operation ApplyIfLessOrEqualL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + ApplyActionIfGreaterThanOrEqualConstant(false, action, c, x, target); +} /// # Summary - /// Computes `if (c == x) { action(target) }`, that is, applies `action` to `target` - /// if a BigInt value `c` is equal to the little-endian qubit register `x` - operation ApplyIfEqualL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - xs : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - let cBitSize = BitSizeL(c); - let xLen = Length(xs); - if (cBitSize <= xLen) { - let bits = BigIntAsBoolArray(c, Length(xs)); - within { - ApplyPauliFromBitString(PauliX, false, bits, xs); - } apply { - Controlled ApplyAsSinglyControlled(xs, (a => action(a), target)); - } +/// Computes `if (c == x) { action(target) }`, that is, applies `action` to `target` +/// if a BigInt value `c` is equal to the little-endian qubit register `x` +operation ApplyIfEqualL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + xs : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + let cBitSize = BitSizeL(c); + let xLen = Length(xs); + if (cBitSize <= xLen) { + let bits = BigIntAsBoolArray(c, Length(xs)); + within { + ApplyPauliFromBitString(PauliX, false, bits, xs); + } apply { + Controlled ApplyAsSinglyControlled(xs, (a => action(a), target)); } } +} /// # Summary - /// Computes `if (c >= x) { action(target) }`, that is, applies `action` to `target` - /// if a BigInt value `c` is greater or equal to the little-endian qubit register `x` - operation ApplyIfGreaterOrEqualL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - ApplyActionIfGreaterThanOrEqualConstant(true, action, c + 1L, x, target); - } +/// Computes `if (c >= x) { action(target) }`, that is, applies `action` to `target` +/// if a BigInt value `c` is greater or equal to the little-endian qubit register `x` +operation ApplyIfGreaterOrEqualL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + ApplyActionIfGreaterThanOrEqualConstant(true, action, c + 1L, x, target); +} /// # Summary - /// Computes `if (c > x) { action(target) }`, that is, applies `action` to `target` - /// if a BigInt value `c` is greater than the little-endian qubit register `x` - operation ApplyIfGreaterL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - ApplyActionIfGreaterThanOrEqualConstant(true, action, c, x, target); - } +/// Computes `if (c > x) { action(target) }`, that is, applies `action` to `target` +/// if a BigInt value `c` is greater than the little-endian qubit register `x` +operation ApplyIfGreaterL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + ApplyActionIfGreaterThanOrEqualConstant(true, action, c, x, target); +} /// # Summary - /// Computes `if x < y { action(target) }`, that is, applies `action` to `target` - /// if register `x` is less than the register `y`. - /// Both qubit registers should be in a little-endian format. - operation ApplyIfLessLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - ApplyIfGreaterLE(action, y, x, target); - } +/// Computes `if x < y { action(target) }`, that is, applies `action` to `target` +/// if register `x` is less than the register `y`. +/// Both qubit registers should be in a little-endian format. +operation ApplyIfLessLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + ApplyIfGreaterLE(action, y, x, target); +} /// # Summary - /// Computes `if x <= y { action(target) }`, that is, applies `action` to `target` - /// if register `x` is less or equal to the register `y`. - /// Both qubit registers should be in a little-endian format. - operation ApplyIfLessOrEqualLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - Fact(Length(x) > 0, "Bitwidth must be at least 1"); - within { - ApplyToEachA(X, x); - } apply { - // control is not inverted - ApplyActionIfSumOverflows(action, x, y, false, target); - } +/// Computes `if x <= y { action(target) }`, that is, applies `action` to `target` +/// if register `x` is less or equal to the register `y`. +/// Both qubit registers should be in a little-endian format. +operation ApplyIfLessOrEqualLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + Fact(Length(x) > 0, "Bitwidth must be at least 1"); + within { + ApplyToEachA(X, x); + } apply { + // control is not inverted + ApplyActionIfSumOverflows(action, x, y, false, target); } +} /// # Summary - /// Computes `if x == y { action(target) }`, that is, applies `action` to `target` - /// if register `x` is equal to the register `y`. - /// Both qubit registers should be in a little-endian format. - operation ApplyIfEqualLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - Fact(Length(x) == Length(y), "x and y must be of same length"); - within { - for i in IndexRange(x) { - CNOT(x[i], y[i]); - X(y[i]); - } - } apply { - Controlled ApplyAsSinglyControlled(y, (a => action(a), target)) +/// Computes `if x == y { action(target) }`, that is, applies `action` to `target` +/// if register `x` is equal to the register `y`. +/// Both qubit registers should be in a little-endian format. +operation ApplyIfEqualLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + Fact(Length(x) == Length(y), "x and y must be of same length"); + within { + for i in IndexRange(x) { + CNOT(x[i], y[i]); + X(y[i]); } + } apply { + Controlled ApplyAsSinglyControlled(y, (a => action(a), target)) } +} /// # Summary - /// Computes `if x >= y { action(target) }`, that is, applies `action` to `target` - /// if register `x` is greater or equal to the register `y`. - /// Both qubit registers should be in a little-endian format. - operation ApplyIfGreaterOrEqualLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - ApplyIfLessOrEqualLE(action, y, x, target); - } +/// Computes `if x >= y { action(target) }`, that is, applies `action` to `target` +/// if register `x` is greater or equal to the register `y`. +/// Both qubit registers should be in a little-endian format. +operation ApplyIfGreaterOrEqualLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + ApplyIfLessOrEqualLE(action, y, x, target); +} /// # Summary - /// Computes `if x > y { action(target) }`, that is, applies `action` to `target` - /// if register `x` is greater than the register `y`. - /// Both qubit registers should be in a little-endian format. - operation ApplyIfGreaterLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - Fact(Length(x) > 0, "Bitwidth must be at least 1"); - within { - ApplyToEachA(X, x); - } apply { - // control is inverted - ApplyActionIfSumOverflows(action, x, y, true, target); - } +/// Computes `if x > y { action(target) }`, that is, applies `action` to `target` +/// if register `x` is greater than the register `y`. +/// Both qubit registers should be in a little-endian format. +operation ApplyIfGreaterLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + Fact(Length(x) > 0, "Bitwidth must be at least 1"); + within { + ApplyToEachA(X, x); + } apply { + // control is inverted + ApplyActionIfSumOverflows(action, x, y, true, target); } +} - export AddLE, ApplyIfEqualLE, ApplyIfEqualL, ApplyIfGreaterLE, ApplyIfGreaterL, ApplyIfGreaterOrEqualLE, ApplyIfGreaterOrEqualL, ApplyIfLessLE, ApplyIfLessL, ApplyIfLessOrEqualLE, ApplyIfLessOrEqualL, IncByI, IncByIUsingIncByLE, IncByL, IncByLUsingIncByLE, IncByLE, IncByLEUsingAddLE, LookAheadDKRSAddLE, MAJ, ReflectAboutInteger, RippleCarryCGAddLE, RippleCarryCGIncByLE, RippleCarryTTKIncByLE, FourierTDIncByLE; +export AddLE, ApplyIfEqualLE, ApplyIfEqualL, ApplyIfGreaterLE, ApplyIfGreaterL, ApplyIfGreaterOrEqualLE, ApplyIfGreaterOrEqualL, ApplyIfLessLE, ApplyIfLessL, ApplyIfLessOrEqualLE, ApplyIfLessOrEqualL, IncByI, IncByIUsingIncByLE, IncByL, IncByLUsingIncByLE, IncByLE, IncByLEUsingAddLE, LookAheadDKRSAddLE, MAJ, ReflectAboutInteger, RippleCarryCGAddLE, RippleCarryCGIncByLE, RippleCarryTTKIncByLE, FourierTDIncByLE; diff --git a/library/std/src/Std/Unstable/ArithmeticHelpers.qs b/library/std/src/Std/Unstable/ArithmeticHelpers.qs index 5d72beba79..bb28c85c4f 100644 --- a/library/std/src/Std/Unstable/ArithmeticHelpers.qs +++ b/library/std/src/Std/Unstable/ArithmeticHelpers.qs @@ -2,585 +2,585 @@ // Licensed under the MIT License. - open Microsoft.Quantum.Diagnostics; - import Std.Arrays.*; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Convert; - import QIR.Intrinsic.*; - +open Microsoft.Quantum.Diagnostics; +import Std.Arrays.*; +open Microsoft.Quantum.Math; +open Microsoft.Quantum.Convert; +import QIR.Intrinsic.*; + + +/// # Summary +/// Implements the outer operation for RippleCarryTTKIncByLE to conjugate +/// the inner operation to construct the full adder. Only Length(xs) +/// qubits are processed. +/// +/// # Input +/// ## xs +/// Qubit register in a little-endian format containing the first summand +/// input to RippleCarryTTKIncByLE. +/// ## ys +/// Qubit register in a little-endian format containing the second summand +/// input to RippleCarryTTKIncByLE. +/// +/// # References +/// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum +/// Addition Circuits and Unbounded Fan-Out", Quantum Information and +/// Computation, Vol. 10, 2010. +/// https://arxiv.org/abs/0910.2530 +internal operation ApplyOuterTTKAdder(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + Fact(Length(xs) <= Length(ys), "Input register ys must be at lease as long as xs."); + for i in 1..Length(xs) - 1 { + CNOT(xs[i], ys[i]); + } + for i in Length(xs) - 2..-1..1 { + CNOT(xs[i], xs[i + 1]); + } +} /// # Summary - /// Implements the outer operation for RippleCarryTTKIncByLE to conjugate - /// the inner operation to construct the full adder. Only Length(xs) - /// qubits are processed. - /// - /// # Input - /// ## xs - /// Qubit register in a little-endian format containing the first summand - /// input to RippleCarryTTKIncByLE. - /// ## ys - /// Qubit register in a little-endian format containing the second summand - /// input to RippleCarryTTKIncByLE. - /// - /// # References - /// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum - /// Addition Circuits and Unbounded Fan-Out", Quantum Information and - /// Computation, Vol. 10, 2010. - /// https://arxiv.org/abs/0910.2530 - internal operation ApplyOuterTTKAdder(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - Fact(Length(xs) <= Length(ys), "Input register ys must be at lease as long as xs."); - for i in 1..Length(xs) - 1 { - CNOT(xs[i], ys[i]); - } - for i in Length(xs) - 2..-1..1 { - CNOT(xs[i], xs[i + 1]); - } +/// Implements the inner addition function for the operation +/// RippleCarryTTKIncByLE. This is the inner operation that is conjugated +/// with the outer operation to construct the full adder. +/// +/// # Input +/// ## xs +/// Qubit register in a little-endian format containing the first summand +/// input to RippleCarryTTKIncByLE. +/// ## ys +/// Qubit register in a little-endian format containing the second summand +/// input to RippleCarryTTKIncByLE. +/// +/// # References +/// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum +/// Addition Circuits and Unbounded Fan-Out", Quantum Information and +/// Computation, Vol. 10, 2010. +/// https://arxiv.org/abs/0910.2530 +/// +/// # Remarks +/// The specified controlled operation makes use of symmetry and mutual +/// cancellation of operations to improve on the default implementation +/// that adds a control to every operation. +internal operation ApplyInnerTTKAdderNoCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + body (...) { + (Controlled ApplyInnerTTKAdderNoCarry)([], (xs, ys)); } + controlled (controls, ...) { + Fact(Length(xs) == Length(ys), "Input registers must have the same number of qubits."); - /// # Summary - /// Implements the inner addition function for the operation - /// RippleCarryTTKIncByLE. This is the inner operation that is conjugated - /// with the outer operation to construct the full adder. - /// - /// # Input - /// ## xs - /// Qubit register in a little-endian format containing the first summand - /// input to RippleCarryTTKIncByLE. - /// ## ys - /// Qubit register in a little-endian format containing the second summand - /// input to RippleCarryTTKIncByLE. - /// - /// # References - /// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum - /// Addition Circuits and Unbounded Fan-Out", Quantum Information and - /// Computation, Vol. 10, 2010. - /// https://arxiv.org/abs/0910.2530 - /// - /// # Remarks - /// The specified controlled operation makes use of symmetry and mutual - /// cancellation of operations to improve on the default implementation - /// that adds a control to every operation. - internal operation ApplyInnerTTKAdderNoCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - body (...) { - (Controlled ApplyInnerTTKAdderNoCarry)([], (xs, ys)); + for idx in 0..Length(xs) - 2 { + CCNOT(xs[idx], ys[idx], xs[idx + 1]); } - controlled (controls, ...) { - Fact(Length(xs) == Length(ys), "Input registers must have the same number of qubits."); - - for idx in 0..Length(xs) - 2 { - CCNOT(xs[idx], ys[idx], xs[idx + 1]); - } - for idx in Length(xs) - 1..-1..1 { - Controlled CNOT(controls, (xs[idx], ys[idx])); - CCNOT(xs[idx - 1], ys[idx - 1], xs[idx]); - } + for idx in Length(xs) - 1..-1..1 { + Controlled CNOT(controls, (xs[idx], ys[idx])); + CCNOT(xs[idx - 1], ys[idx - 1], xs[idx]); } } +} /// # Summary - /// Implements the inner addition function for the operation - /// RippleCarryTTKIncByLE. This is the inner operation that is conjugated - /// with the outer operation to construct the full adder. - /// - /// # Input - /// ## xs - /// Qubit register in a little-endian format containing the first summand - /// input to RippleCarryTTKIncByLE. - /// ## ys - /// Qubit register in a little-endian format containing the second summand - /// input to RippleCarryTTKIncByLE. - /// - /// # References - /// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum - /// Addition Circuits and Unbounded Fan-Out", Quantum Information and - /// Computation, Vol. 10, 2010. - /// https://arxiv.org/abs/0910.2530 - /// - /// # Remarks - /// The specified controlled operation makes use of symmetry and mutual - /// cancellation of operations to improve on the default implementation - /// that adds a control to every operation. - internal operation ApplyInnerTTKAdderWithCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - body (...) { - (Controlled ApplyInnerTTKAdderWithCarry)([], (xs, ys)); - } - controlled (controls, ...) { - Fact(Length(xs) + 1 == Length(ys), "ys must be one qubit longer then xs."); - Fact(Length(xs) > 0, "Array should not be empty."); +/// Implements the inner addition function for the operation +/// RippleCarryTTKIncByLE. This is the inner operation that is conjugated +/// with the outer operation to construct the full adder. +/// +/// # Input +/// ## xs +/// Qubit register in a little-endian format containing the first summand +/// input to RippleCarryTTKIncByLE. +/// ## ys +/// Qubit register in a little-endian format containing the second summand +/// input to RippleCarryTTKIncByLE. +/// +/// # References +/// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum +/// Addition Circuits and Unbounded Fan-Out", Quantum Information and +/// Computation, Vol. 10, 2010. +/// https://arxiv.org/abs/0910.2530 +/// +/// # Remarks +/// The specified controlled operation makes use of symmetry and mutual +/// cancellation of operations to improve on the default implementation +/// that adds a control to every operation. +internal operation ApplyInnerTTKAdderWithCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + body (...) { + (Controlled ApplyInnerTTKAdderWithCarry)([], (xs, ys)); + } + controlled (controls, ...) { + Fact(Length(xs) + 1 == Length(ys), "ys must be one qubit longer then xs."); + Fact(Length(xs) > 0, "Array should not be empty."); - let nQubits = Length(xs); - for idx in 0..nQubits - 2 { - CCNOT(xs[idx], ys[idx], xs[idx + 1]); - } - (Controlled CCNOT)(controls, (xs[nQubits - 1], ys[nQubits - 1], ys[nQubits])); - for idx in nQubits - 1..-1..1 { - Controlled CNOT(controls, (xs[idx], ys[idx])); - CCNOT(xs[idx - 1], ys[idx - 1], xs[idx]); - } + let nQubits = Length(xs); + for idx in 0..nQubits - 2 { + CCNOT(xs[idx], ys[idx], xs[idx + 1]); + } + (Controlled CCNOT)(controls, (xs[nQubits - 1], ys[nQubits - 1], ys[nQubits])); + for idx in nQubits - 1..-1..1 { + Controlled CNOT(controls, (xs[idx], ys[idx])); + CCNOT(xs[idx - 1], ys[idx - 1], xs[idx]); } } +} /// # Summary - /// Implements Half-adder. Adds qubit x to qubit y and sets carryOut appropriately - internal operation HalfAdderForInc(x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { - body (...) { - CCNOT(x, y, carryOut); - CNOT(x, y); - } - adjoint auto; +/// Implements Half-adder. Adds qubit x to qubit y and sets carryOut appropriately +internal operation HalfAdderForInc(x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { + body (...) { + CCNOT(x, y, carryOut); + CNOT(x, y); + } + adjoint auto; - controlled (ctls, ...) { - Fact(Length(ctls) == 1, "HalfAdderForInc should be controlled by exactly one control qubit."); + controlled (ctls, ...) { + Fact(Length(ctls) == 1, "HalfAdderForInc should be controlled by exactly one control qubit."); - let ctl = ctls[0]; - use helper = Qubit(); + let ctl = ctls[0]; + use helper = Qubit(); - within { - ApplyAndAssuming0Target(x, y, helper); - } apply { - ApplyAndAssuming0Target(ctl, helper, carryOut); - } - CCNOT(ctl, x, y); + within { + ApplyAndAssuming0Target(x, y, helper); + } apply { + ApplyAndAssuming0Target(ctl, helper, carryOut); } - controlled adjoint auto; + CCNOT(ctl, x, y); } + controlled adjoint auto; +} /// # Summary - /// Implements Full-adder. Adds qubit carryIn and x to qubit y and sets carryOut appropriately. - internal operation FullAdderForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { - body (...) { - // TODO: cannot use `Carry` operation here - CNOT(carryIn, x); - CNOT(carryIn, y); - CCNOT(x, y, carryOut); - CNOT(carryIn, carryOut); - CNOT(carryIn, x); - CNOT(x, y); - } - adjoint auto; - - controlled (ctls, ...) { - Fact(Length(ctls) == 1, "FullAdderForInc should be controlled by exactly one control qubit."); +/// Implements Full-adder. Adds qubit carryIn and x to qubit y and sets carryOut appropriately. +internal operation FullAdderForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { + body (...) { + // TODO: cannot use `Carry` operation here + CNOT(carryIn, x); + CNOT(carryIn, y); + CCNOT(x, y, carryOut); + CNOT(carryIn, carryOut); + CNOT(carryIn, x); + CNOT(x, y); + } + adjoint auto; - let ctl = ctls[0]; - use helper = Qubit(); + controlled (ctls, ...) { + Fact(Length(ctls) == 1, "FullAdderForInc should be controlled by exactly one control qubit."); - CarryForInc(carryIn, x, y, helper); - CCNOT(ctl, helper, carryOut); - Controlled UncarryForInc(ctls, (carryIn, x, y, helper)); - } - controlled adjoint auto; - } + let ctl = ctls[0]; + use helper = Qubit(); - // Computes carryOut := carryIn + x + y - internal operation FullAdder(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj { - CNOT(x, y); - CNOT(x, carryIn); - ApplyAndAssuming0Target(y, carryIn, carryOut); - CNOT(x, y); - CNOT(x, carryOut); - CNOT(y, carryIn); + CarryForInc(carryIn, x, y, helper); + CCNOT(ctl, helper, carryOut); + Controlled UncarryForInc(ctls, (carryIn, x, y, helper)); } + controlled adjoint auto; +} + +// Computes carryOut := carryIn + x + y +internal operation FullAdder(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj { + CNOT(x, y); + CNOT(x, carryIn); + ApplyAndAssuming0Target(y, carryIn, carryOut); + CNOT(x, y); + CNOT(x, carryOut); + CNOT(y, carryIn); +} /// # Summary - /// Computes carry bit for a full adder. - internal operation CarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { - body (...) { - CNOT(carryIn, x); - CNOT(carryIn, y); - ApplyAndAssuming0Target(x, y, carryOut); - CNOT(carryIn, carryOut); - } - adjoint auto; - controlled (ctls, ...) { - // This CarryForInc is intended to be used only in an in-place - // ripple-carry implementation. Only such particular use case allows - // for this simple implementation where controlled version - // is the same as uncontrolled body. - CarryForInc(carryIn, x, y, carryOut); - } - controlled adjoint auto; +/// Computes carry bit for a full adder. +internal operation CarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { + body (...) { + CNOT(carryIn, x); + CNOT(carryIn, y); + ApplyAndAssuming0Target(x, y, carryOut); + CNOT(carryIn, carryOut); + } + adjoint auto; + controlled (ctls, ...) { + // This CarryForInc is intended to be used only in an in-place + // ripple-carry implementation. Only such particular use case allows + // for this simple implementation where controlled version + // is the same as uncontrolled body. + CarryForInc(carryIn, x, y, carryOut); } + controlled adjoint auto; +} /// # Summary - /// Uncomputes carry bit for a full adder. - internal operation UncarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { - body (...) { - CNOT(carryIn, carryOut); - Adjoint ApplyAndAssuming0Target(x, y, carryOut); - CNOT(carryIn, x); - CNOT(x, y); - } - adjoint auto; - controlled (ctls, ...) { - Fact(Length(ctls) == 1, "UncarryForInc should be controlled by exactly one control qubit."); +/// Uncomputes carry bit for a full adder. +internal operation UncarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { + body (...) { + CNOT(carryIn, carryOut); + Adjoint ApplyAndAssuming0Target(x, y, carryOut); + CNOT(carryIn, x); + CNOT(x, y); + } + adjoint auto; + controlled (ctls, ...) { + Fact(Length(ctls) == 1, "UncarryForInc should be controlled by exactly one control qubit."); - let ctl = ctls[0]; + let ctl = ctls[0]; - CNOT(carryIn, carryOut); - Adjoint ApplyAndAssuming0Target(x, y, carryOut); - CCNOT(ctl, x, y); // Controlled X(ctls + [x], y); - CNOT(carryIn, x); - CNOT(carryIn, y); - } - controlled adjoint auto; + CNOT(carryIn, carryOut); + Adjoint ApplyAndAssuming0Target(x, y, carryOut); + CCNOT(ctl, x, y); // Controlled X(ctls + [x], y); + CNOT(carryIn, x); + CNOT(carryIn, y); } + controlled adjoint auto; +} /// # Summary - /// Applies AND gate between `control1` and `control2` and stores the result - /// in `target` assuming `target` is in |0> state. - /// - /// # Description - /// Inverts `target` if and only if both controls are 1, but assumes that - /// `target` is in state 0. The operation has T-count 4, T-depth 2 and - /// requires no helper qubit, and may therefore be preferable to a CCNOT - /// operation, if `target` is known to be 0. - /// The adjoint of this operation is measurement based and requires no T - /// gates (but requires target to support branching on measurements). - /// Although the Toffoli gate (CCNOT) will perform faster in simulations, - /// this version has lower T gate requirements. - /// # References - /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", - /// Phys. Rev. A 87, 022328, 2013 - /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) - /// doi:10.1103/PhysRevA.87.022328 - @Config(Adaptive) - internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - // NOTE: Eventually this operation will be public and intrinsic. - body (...) { - CCNOT(control1, control2, target); - } - adjoint (...) { - H(target); - if M(target) == One { - Reset(target); - CZ(control1, control2); - } - } +/// Applies AND gate between `control1` and `control2` and stores the result +/// in `target` assuming `target` is in |0> state. +/// +/// # Description +/// Inverts `target` if and only if both controls are 1, but assumes that +/// `target` is in state 0. The operation has T-count 4, T-depth 2 and +/// requires no helper qubit, and may therefore be preferable to a CCNOT +/// operation, if `target` is known to be 0. +/// The adjoint of this operation is measurement based and requires no T +/// gates (but requires target to support branching on measurements). +/// Although the Toffoli gate (CCNOT) will perform faster in simulations, +/// this version has lower T gate requirements. +/// # References +/// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", +/// Phys. Rev. A 87, 022328, 2013 +/// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) +/// doi:10.1103/PhysRevA.87.022328 +@Config(Adaptive) +internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + // NOTE: Eventually this operation will be public and intrinsic. + body (...) { + CCNOT(control1, control2, target); } - - internal operation ApplyOrAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - within { - X(control1); - X(control2); - } apply { - ApplyAndAssuming0Target(control1, control2, target); - X(target); + adjoint (...) { + H(target); + if M(target) == One { + Reset(target); + CZ(control1, control2); } } +} + +internal operation ApplyOrAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + within { + X(control1); + X(control2); + } apply { + ApplyAndAssuming0Target(control1, control2, target); + X(target); + } +} /// # Summary - /// Applies AND gate between `control1` and `control2` and stores the result - /// in `target` assuming `target` is in |0> state. - /// - /// # Description - /// Inverts `target` if and only if both controls are 1, but assumes that - /// `target` is in state 0. The operation has T-count 4, T-depth 2 and - /// requires no helper qubit, and may therefore be preferable to a CCNOT - /// operation, if `target` is known to be 0. - /// This version is suitable for Base profile. - /// Although the Toffoli gate (CCNOT) will perform faster in simulations, - /// this version has lower T gate requirements. - /// # References - /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", - /// Phys. Rev. A 87, 022328, 2013 - /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) - /// doi:10.1103/PhysRevA.87.022328 - @Config(not Adaptive) - internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - H(target); +/// Applies AND gate between `control1` and `control2` and stores the result +/// in `target` assuming `target` is in |0> state. +/// +/// # Description +/// Inverts `target` if and only if both controls are 1, but assumes that +/// `target` is in state 0. The operation has T-count 4, T-depth 2 and +/// requires no helper qubit, and may therefore be preferable to a CCNOT +/// operation, if `target` is known to be 0. +/// This version is suitable for Base profile. +/// Although the Toffoli gate (CCNOT) will perform faster in simulations, +/// this version has lower T gate requirements. +/// # References +/// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", +/// Phys. Rev. A 87, 022328, 2013 +/// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) +/// doi:10.1103/PhysRevA.87.022328 +@Config(not Adaptive) +internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + H(target); + T(target); + CNOT(control1, target); + CNOT(control2, target); + within { + CNOT(target, control1); + CNOT(target, control2); + } apply { + Adjoint T(control1); + Adjoint T(control2); T(target); - CNOT(control1, target); - CNOT(control2, target); - within { - CNOT(target, control1); - CNOT(target, control2); - } apply { - Adjoint T(control1); - Adjoint T(control2); - T(target); - } - H(target); - S(target); } + H(target); + S(target); +} /// # Summary - /// Computes carries for the look-ahead adder - internal operation ComputeCarries(ps : Qubit[], gs : Qubit[]) : Unit is Adj { - let n = Length(gs); - Fact(Length(ps) + 1 == n, "Register gs must be one qubit longer than register gs."); +/// Computes carries for the look-ahead adder +internal operation ComputeCarries(ps : Qubit[], gs : Qubit[]) : Unit is Adj { + let n = Length(gs); + Fact(Length(ps) + 1 == n, "Register gs must be one qubit longer than register gs."); - let T = Floor(Lg(IntAsDouble(n))); - use qs = Qubit[n - HammingWeightI(n) - T]; + let T = Floor(Lg(IntAsDouble(n))); + use qs = Qubit[n - HammingWeightI(n) - T]; - let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1, 1..T - 1); - let pWorkspace = [ps] + Partitioned(registerPartition, qs); + let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1, 1..T - 1); + let pWorkspace = [ps] + Partitioned(registerPartition, qs); - within { - PRounds(pWorkspace); - } apply { - // U_G - GRounds(pWorkspace, gs); + within { + PRounds(pWorkspace); + } apply { + // U_G + GRounds(pWorkspace, gs); - // U_C - CRounds(pWorkspace, gs); - } + // U_C + CRounds(pWorkspace, gs); } +} /// # Summary - /// Computes all p[i, j] values in workspace for the look-ahead adder. - /// - /// The register array `pWorkspace` has T entries, where T = ⌊log₂ n⌋. - /// - /// The first entry `pWorkspace[0]` is initialized with `P_0` which is - /// computed before `ComputeCarries` is called. The other registers are - /// 0-initialized and will be computed in successive rounds t = 1, ..., T - 1. - /// - /// In each round t we compute - /// - /// p[i, j] = p[2ᵗ × m, 2ᵗ × (m + 1)] = p[i, k] ∧ p[k, j] - /// - /// in `pWorkspace[t][m - 1]` and use that for k = 2ᵗ × m + 2ᵗ⁻¹, p[i, k] and p[k, j] - /// have already been computed in round t - 1 in `pWorkspace[t - 1][2 * m - 1]` and - /// `pWorkspace[t - 1][2 * m]`, respectively. - internal operation PRounds(pWorkspace : Qubit[][]) : Unit is Adj { - for ws in Windows(2, pWorkspace) { - // note that we are using Rest, since pWorkspace[t - 1][0] is never - // accessed in round t. - let (current, next) = (Rest(ws[0]), ws[1]); - - for m in IndexRange(next) { - ApplyAndAssuming0Target(current[2 * m], current[2 * m + 1], next[m]); - } +/// Computes all p[i, j] values in workspace for the look-ahead adder. +/// +/// The register array `pWorkspace` has T entries, where T = ⌊log₂ n⌋. +/// +/// The first entry `pWorkspace[0]` is initialized with `P_0` which is +/// computed before `ComputeCarries` is called. The other registers are +/// 0-initialized and will be computed in successive rounds t = 1, ..., T - 1. +/// +/// In each round t we compute +/// +/// p[i, j] = p[2ᵗ × m, 2ᵗ × (m + 1)] = p[i, k] ∧ p[k, j] +/// +/// in `pWorkspace[t][m - 1]` and use that for k = 2ᵗ × m + 2ᵗ⁻¹, p[i, k] and p[k, j] +/// have already been computed in round t - 1 in `pWorkspace[t - 1][2 * m - 1]` and +/// `pWorkspace[t - 1][2 * m]`, respectively. +internal operation PRounds(pWorkspace : Qubit[][]) : Unit is Adj { + for ws in Windows(2, pWorkspace) { + // note that we are using Rest, since pWorkspace[t - 1][0] is never + // accessed in round t. + let (current, next) = (Rest(ws[0]), ws[1]); + + for m in IndexRange(next) { + ApplyAndAssuming0Target(current[2 * m], current[2 * m + 1], next[m]); } } +} /// # Summary - /// Computes g[i ∧ (i + 1), i + 1] into gs[i] for the look-ahead adder. - /// - /// The register gs has n entries initialized to gs[i] = g[i, i + 1]. - /// - /// After successive rounds t = 1, ..., T, the register is updated to - /// gs[i] = g[i ∧ (i + 1), i + 1], from which we can compute the carries - /// in the C-rounds. - internal operation GRounds(pWorkspace : Qubit[][], gs : Qubit[]) : Unit is Adj { - let T = Length(pWorkspace); - let n = Length(gs); - - for t in 1..T { - let length = Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1; - let ps = pWorkspace[t - 1][0..2...]; - - for m in 0..length { - CCNOT(gs[2^t * m + 2^(t - 1) - 1], ps[m], gs[2^t * m + 2^t - 1]); - } +/// Computes g[i ∧ (i + 1), i + 1] into gs[i] for the look-ahead adder. +/// +/// The register gs has n entries initialized to gs[i] = g[i, i + 1]. +/// +/// After successive rounds t = 1, ..., T, the register is updated to +/// gs[i] = g[i ∧ (i + 1), i + 1], from which we can compute the carries +/// in the C-rounds. +internal operation GRounds(pWorkspace : Qubit[][], gs : Qubit[]) : Unit is Adj { + let T = Length(pWorkspace); + let n = Length(gs); + + for t in 1..T { + let length = Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1; + let ps = pWorkspace[t - 1][0..2...]; + + for m in 0..length { + CCNOT(gs[2^t * m + 2^(t - 1) - 1], ps[m], gs[2^t * m + 2^t - 1]); } } +} /// # Summary - /// Computes carries into gs for the look-ahead adder. - internal operation CRounds(pWorkspace : Qubit[][], gs : Qubit[]) : Unit is Adj { - let n = Length(gs); +/// Computes carries into gs for the look-ahead adder. +internal operation CRounds(pWorkspace : Qubit[][], gs : Qubit[]) : Unit is Adj { + let n = Length(gs); - let start = Floor(Lg(IntAsDouble(2 * n) / 3.0)); - for t in start..-1..1 { - let length = Floor(IntAsDouble(n - 2^(t - 1)) / IntAsDouble(2^t)); - let ps = pWorkspace[t - 1][1..2...]; + let start = Floor(Lg(IntAsDouble(2 * n) / 3.0)); + for t in start..-1..1 { + let length = Floor(IntAsDouble(n - 2^(t - 1)) / IntAsDouble(2^t)); + let ps = pWorkspace[t - 1][1..2...]; - for m in 1..length { - CCNOT(gs[2^t * m - 1], ps[m - 1], gs[2^t * m + 2^(t - 1) - 1]); - } + for m in 1..length { + CCNOT(gs[2^t * m - 1], ps[m - 1], gs[2^t * m + 2^(t - 1) - 1]); } } +} - internal operation PhaseGradient(qs : Qubit[]) : Unit is Adj + Ctl { - for i in IndexRange(qs) { - R1Frac(1, i, qs[i]); - } +internal operation PhaseGradient(qs : Qubit[]) : Unit is Adj + Ctl { + for i in IndexRange(qs) { + R1Frac(1, i, qs[i]); } +} + +// +// Internal operations for comparisons +// + +/// # Summary +/// Applies `action` to `target` if register `x` is greater or equal to BigInt `c` +/// (if `invertControl` is false). If `invertControl` is true, the `action` +/// is applied in the opposite situation. +internal operation ApplyActionIfGreaterThanOrEqualConstant<'T>( + invertControl : Bool, + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T +) : Unit is Adj + Ctl { + + let bitWidth = Length(x); + if c == 0L { + if not invertControl { + action(target); + } + } elif c >= (2L^bitWidth) { + if invertControl { + action(target); + } + } else { + // normalize constant + let l = TrailingZeroCountL(c); - // - // Internal operations for comparisons - // - - /// # Summary - /// Applies `action` to `target` if register `x` is greater or equal to BigInt `c` - /// (if `invertControl` is false). If `invertControl` is true, the `action` - /// is applied in the opposite situation. - internal operation ApplyActionIfGreaterThanOrEqualConstant<'T>( - invertControl : Bool, - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T - ) : Unit is Adj + Ctl { - - let bitWidth = Length(x); - if c == 0L { - if not invertControl { - action(target); - } - } elif c >= (2L^bitWidth) { - if invertControl { - action(target); - } - } else { - // normalize constant - let l = TrailingZeroCountL(c); - - let cNormalized = c >>> l; - let xNormalized = x[l...]; - let bitWidthNormalized = Length(xNormalized); + let cNormalized = c >>> l; + let xNormalized = x[l...]; + let bitWidthNormalized = Length(xNormalized); - // If c == 2L^(bitwidth - 1), then bitWidthNormalized will be 1, - // and qs will be empty. In that case, we do not need to compute - // any temporary values, and some optimizations are apply, which - // are considered in the remainder. - use qs = Qubit[bitWidthNormalized - 1]; - let cs1 = IsEmpty(qs) ? [] | [Head(xNormalized)] + Most(qs); + // If c == 2L^(bitwidth - 1), then bitWidthNormalized will be 1, + // and qs will be empty. In that case, we do not need to compute + // any temporary values, and some optimizations are apply, which + // are considered in the remainder. + use qs = Qubit[bitWidthNormalized - 1]; + let cs1 = IsEmpty(qs) ? [] | [Head(xNormalized)] + Most(qs); - Fact(Length(cs1) == Length(qs), "Arrays should be of the same length."); + Fact(Length(cs1) == Length(qs), "Arrays should be of the same length."); + within { + for i in 0..Length(cs1) - 1 { + let op = cNormalized &&& (1L <<< (i + 1)) != 0L ? ApplyAndAssuming0Target | ApplyOrAssuming0Target; + op(cs1[i], xNormalized[i + 1], qs[i]); + } + } apply { + let control = IsEmpty(qs) ? Tail(x) | Tail(qs); within { - for i in 0..Length(cs1) - 1 { - let op = cNormalized &&& (1L <<< (i + 1)) != 0L ? ApplyAndAssuming0Target | ApplyOrAssuming0Target; - op(cs1[i], xNormalized[i + 1], qs[i]); + if invertControl { + X(control); } } apply { - let control = IsEmpty(qs) ? Tail(x) | Tail(qs); - within { - if invertControl { - X(control); - } - } apply { - Controlled action([control], target); - } + Controlled action([control], target); } } } +} /// # Summary - /// Applies `action` to `target` if the sum of `x` and `y` registers - /// overflows, i.e. there's a carry out (if `invertControl` is false). - /// If `invertControl` is true, the `action` is applied when there's no carry out. - internal operation ApplyActionIfSumOverflows<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - invertControl : Bool, - target : 'T - ) : Unit is Adj + Ctl { - - let n = Length(x); - Fact(n >= 1, "Registers must contain at least one qubit."); - Fact(Length(y) == n, "Registers must be of the same length."); - - use carries = Qubit[n]; - +/// Applies `action` to `target` if the sum of `x` and `y` registers +/// overflows, i.e. there's a carry out (if `invertControl` is false). +/// If `invertControl` is true, the `action` is applied when there's no carry out. +internal operation ApplyActionIfSumOverflows<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + invertControl : Bool, + target : 'T +) : Unit is Adj + Ctl { + + let n = Length(x); + Fact(n >= 1, "Registers must contain at least one qubit."); + Fact(Length(y) == n, "Registers must be of the same length."); + + use carries = Qubit[n]; + + within { + CarryWith1CarryIn(x[0], y[0], carries[0]); + for i in 1..n - 1 { + CarryForInc(carries[i - 1], x[i], y[i], carries[i]); + } + } apply { within { - CarryWith1CarryIn(x[0], y[0], carries[0]); - for i in 1..n - 1 { - CarryForInc(carries[i - 1], x[i], y[i], carries[i]); + if invertControl { + X(carries[n - 1]); } } apply { - within { - if invertControl { - X(carries[n - 1]); - } - } apply { - Controlled action([carries[n - 1]], target); - } + Controlled action([carries[n - 1]], target); } } +} /// # Summary - /// Computes carry out assuming carry in is 1. - /// Simplified version that is only applicable for scenarios - /// where controlled version is the same as non-controlled. - internal operation CarryWith1CarryIn( - x : Qubit, - y : Qubit, - carryOut : Qubit - ) : Unit is Adj + Ctl { - - body (...) { - X(x); - X(y); - ApplyAndAssuming0Target(x, y, carryOut); - X(carryOut); - } - - adjoint auto; +/// Computes carry out assuming carry in is 1. +/// Simplified version that is only applicable for scenarios +/// where controlled version is the same as non-controlled. +internal operation CarryWith1CarryIn( + x : Qubit, + y : Qubit, + carryOut : Qubit +) : Unit is Adj + Ctl { + + body (...) { + X(x); + X(y); + ApplyAndAssuming0Target(x, y, carryOut); + X(carryOut); + } - controlled (ctls, ...) { - Fact(Length(ctls) <= 1, "Number of control lines must be at most 1"); - CarryWith1CarryIn(x, y, carryOut); - } + adjoint auto; - controlled adjoint auto; + controlled (ctls, ...) { + Fact(Length(ctls) <= 1, "Number of control lines must be at most 1"); + CarryWith1CarryIn(x, y, carryOut); } + controlled adjoint auto; +} + /// # Summary - /// This wrapper allows operations that support only one control - /// qubit to be used in a multi-controlled scenarios. It provides - /// controlled version that collects controls into one qubit - /// by applying AND chain using auxiliary qubit array. - internal operation ApplyAsSinglyControlled<'TIn>( - op : ('TIn => Unit is Adj + Ctl), - input : 'TIn - ) : Unit is Adj + Ctl { - - body (...) { - op(input); - } +/// This wrapper allows operations that support only one control +/// qubit to be used in a multi-controlled scenarios. It provides +/// controlled version that collects controls into one qubit +/// by applying AND chain using auxiliary qubit array. +internal operation ApplyAsSinglyControlled<'TIn>( + op : ('TIn => Unit is Adj + Ctl), + input : 'TIn +) : Unit is Adj + Ctl { + + body (...) { + op(input); + } - controlled (ctls, ...) { - let n = Length(ctls); - if n == 0 { - op(input); - } elif n == 1 { - Controlled op(ctls, input); - } else { - use aux = Qubit[n - 1]; - within { - LogDepthAndChain(ctls, aux); - } apply { - Controlled op([Tail(aux)], input); - } + controlled (ctls, ...) { + let n = Length(ctls); + if n == 0 { + op(input); + } elif n == 1 { + Controlled op(ctls, input); + } else { + use aux = Qubit[n - 1]; + within { + LogDepthAndChain(ctls, aux); + } apply { + Controlled op([Tail(aux)], input); } } } +} /// # Summary - /// This helper function computes the AND of all control bits in `ctls` into - /// the last qubit of `tgts`, using the other qubits in `tgts` as helper - /// qubits for the AND of subsets of control bits. The operation has a - /// logarithmic depth of AND gates by aligning them using a balanced binary - /// tree. - internal operation LogDepthAndChain(ctls : Qubit[], tgts : Qubit[]) : Unit is Adj { - let lc = Length(ctls); - let lt = Length(tgts); - - Fact(lc == lt + 1, $"There must be exactly one more control qubit than target qubits (got {lc}, {lt})"); - - if lt == 1 { - ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]); - } elif lt == 2 { - ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]); - ApplyAndAssuming0Target(ctls[2], tgts[0], tgts[1]); - } else { - let left = lc / 2; - let right = lc - left; - - let ctlsLeft = ctls[...left - 1]; - let tgtsLeft = tgts[...left - 2]; - - let ctlsRight = ctls[left..left + right - 1]; - let tgtsRight = tgts[left - 1..left + right - 3]; - - LogDepthAndChain(ctlsLeft, tgtsLeft); - LogDepthAndChain(ctlsRight, tgtsRight); - ApplyAndAssuming0Target(Tail(tgtsLeft), Tail(tgtsRight), Tail(tgts)); - } +/// This helper function computes the AND of all control bits in `ctls` into +/// the last qubit of `tgts`, using the other qubits in `tgts` as helper +/// qubits for the AND of subsets of control bits. The operation has a +/// logarithmic depth of AND gates by aligning them using a balanced binary +/// tree. +internal operation LogDepthAndChain(ctls : Qubit[], tgts : Qubit[]) : Unit is Adj { + let lc = Length(ctls); + let lt = Length(tgts); + + Fact(lc == lt + 1, $"There must be exactly one more control qubit than target qubits (got {lc}, {lt})"); + + if lt == 1 { + ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]); + } elif lt == 2 { + ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]); + ApplyAndAssuming0Target(ctls[2], tgts[0], tgts[1]); + } else { + let left = lc / 2; + let right = lc - left; + + let ctlsLeft = ctls[...left - 1]; + let tgtsLeft = tgts[...left - 2]; + + let ctlsRight = ctls[left..left + right - 1]; + let tgtsRight = tgts[left - 1..left + right - 3]; + + LogDepthAndChain(ctlsLeft, tgtsLeft); + LogDepthAndChain(ctlsRight, tgtsRight); + ApplyAndAssuming0Target(Tail(tgtsLeft), Tail(tgtsRight), Tail(tgts)); } +} diff --git a/library/std/src/Std/Unstable/StatePreparation.qs b/library/std/src/Std/Unstable/StatePreparation.qs index 1fb1f4a377..1d3cb742ef 100644 --- a/library/std/src/Std/Unstable/StatePreparation.qs +++ b/library/std/src/Std/Unstable/StatePreparation.qs @@ -2,389 +2,389 @@ // Licensed under the MIT License. - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - import Std.Arrays.*; - open Microsoft.Quantum.Math; - import QIR.Intrinsic.*; - import Std.Unstable.ArithmeticHelpers.*; +open Microsoft.Quantum.Convert; +open Microsoft.Quantum.Diagnostics; +import Std.Arrays.*; +open Microsoft.Quantum.Math; +import QIR.Intrinsic.*; +import Std.Unstable.ArithmeticHelpers.*; - /// # Summary - /// Given a set of coefficients and a big-endian quantum register, - /// prepares a state on that register described by the given coefficients. - /// - /// # Description - /// This operation prepares an arbitrary quantum - /// state |𝜓⟩ with coefficients 𝑎ⱼ from - /// the n-qubit computational basis state |0...0⟩. - /// - /// The action of U on the all-zeros state is given by - /// $$ - /// \begin{align} - /// U \ket{0\cdots 0} = \ket{\psi} = \frac{\sum_{j=0}^{2^n-1}\alpha_j \ket{j}}{\sqrt{\sum_{j=0}^{2^n-1}|\alpha_j|^2}}. - /// \end{align} - /// $$ - /// - /// # Input - /// ## coefficients - /// Array of up to 2ⁿ real coefficients. The j-th coefficient - /// indexes the number state |j⟩ encoded in big-endian format. - /// - /// ## qubits - /// Qubit register encoding number states in a big-endian format. This is - /// expected to be initialized in the computational basis state |0...0⟩. - /// - /// # Remarks - /// `coefficients` will be normalized and padded with - /// elements 𝑎ⱼ = 0.0 if fewer than 2ⁿ are specified. - /// - /// # Example - /// The following snippet prepares the quantum state |𝜓⟩=√(1/8)|0⟩+√(7/8)|2⟩=√(1/8)|00⟩+√(7/8)|10⟩ - /// in the qubit register `qubits`. - /// ```qsharp - /// let amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0]; - /// use qubits = Qubit[2]; - /// PreparePureStateD(amplitudes, qubits); - /// ``` - /// - /// # References - /// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) - /// "Synthesis of Quantum Logic Circuits", - /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov - /// - /// # See Also - /// - Microsoft.Quantum.Unstable.StatePreparation.ApproximatelyPreparePureStateCP - operation PreparePureStateD(coefficients : Double[], qubits : Qubit[]) : Unit is Adj + Ctl { - let coefficientsAsComplexPolar = Mapped(a -> ComplexAsComplexPolar(Complex(a, 0.0)), coefficients); - ApproximatelyPreparePureStateCP(0.0, coefficientsAsComplexPolar, qubits); - } +/// # Summary +/// Given a set of coefficients and a big-endian quantum register, +/// prepares a state on that register described by the given coefficients. +/// +/// # Description +/// This operation prepares an arbitrary quantum +/// state |𝜓⟩ with coefficients 𝑎ⱼ from +/// the n-qubit computational basis state |0...0⟩. +/// +/// The action of U on the all-zeros state is given by +/// $$ +/// \begin{align} +/// U \ket{0\cdots 0} = \ket{\psi} = \frac{\sum_{j=0}^{2^n-1}\alpha_j \ket{j}}{\sqrt{\sum_{j=0}^{2^n-1}|\alpha_j|^2}}. +/// \end{align} +/// $$ +/// +/// # Input +/// ## coefficients +/// Array of up to 2ⁿ real coefficients. The j-th coefficient +/// indexes the number state |j⟩ encoded in big-endian format. +/// +/// ## qubits +/// Qubit register encoding number states in a big-endian format. This is +/// expected to be initialized in the computational basis state |0...0⟩. +/// +/// # Remarks +/// `coefficients` will be normalized and padded with +/// elements 𝑎ⱼ = 0.0 if fewer than 2ⁿ are specified. +/// +/// # Example +/// The following snippet prepares the quantum state |𝜓⟩=√(1/8)|0⟩+√(7/8)|2⟩=√(1/8)|00⟩+√(7/8)|10⟩ +/// in the qubit register `qubits`. +/// ```qsharp +/// let amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0]; +/// use qubits = Qubit[2]; +/// PreparePureStateD(amplitudes, qubits); +/// ``` +/// +/// # References +/// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) +/// "Synthesis of Quantum Logic Circuits", +/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov +/// +/// # See Also +/// - Microsoft.Quantum.Unstable.StatePreparation.ApproximatelyPreparePureStateCP +operation PreparePureStateD(coefficients : Double[], qubits : Qubit[]) : Unit is Adj + Ctl { + let coefficientsAsComplexPolar = Mapped(a -> ComplexAsComplexPolar(Complex(a, 0.0)), coefficients); + ApproximatelyPreparePureStateCP(0.0, coefficientsAsComplexPolar, qubits); +} /// # Summary - /// Given a set of coefficients and a big-endian quantum register, - /// prepares a state on that register described by the given coefficients, - /// up to a given approximation tolerance. - /// - /// # Description - /// This operation prepares an arbitrary quantum - /// state |𝜓⟩ with complex coefficients rⱼ·𝒆^(𝒊·tⱼ) from - /// the n-qubit computational basis state |0...0⟩. - /// In particular, the action of this operation can be simulated by the - /// a unitary transformation U which acts on the all-zeros state as - /// - /// $$ - /// \begin{align} - /// U\ket{0...0} - /// & = \ket{\psi} \\\\ - /// & = \frac{ - /// \sum_{j=0}^{2^n-1} r_j e^{i t_j} \ket{j} - /// }{ - /// \sqrt{\sum_{j=0}^{2^n-1} |r_j|^2} - /// }. - /// \end{align} - /// $$ - /// - /// # Input - /// ## tolerance - /// The approximation tolerance to be used when preparing the given state. - /// - /// ## coefficients - /// Array of up to 2ⁿ complex coefficients represented by their - /// absolute value and phase (rⱼ, tⱼ). The j-th coefficient - /// indexes the number state |j⟩ encoded in a big-endian format. - /// - /// ## qubits - /// Qubit register encoding number states in a big-endian format. This is - /// expected to be initialized in the computational basis state - /// |0...0⟩. - /// - /// # Remarks - /// `coefficients` will be padded with - /// elements (rⱼ, tⱼ) = (0.0, 0.0) if fewer than 2ⁿ are - /// specified. - /// - /// # References - /// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) - /// "Synthesis of Quantum Logic Circuits", - /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov - operation ApproximatelyPreparePureStateCP( - tolerance : Double, - coefficients : ComplexPolar[], - qubits : Qubit[] - ) : Unit is Adj + Ctl { +/// Given a set of coefficients and a big-endian quantum register, +/// prepares a state on that register described by the given coefficients, +/// up to a given approximation tolerance. +/// +/// # Description +/// This operation prepares an arbitrary quantum +/// state |𝜓⟩ with complex coefficients rⱼ·𝒆^(𝒊·tⱼ) from +/// the n-qubit computational basis state |0...0⟩. +/// In particular, the action of this operation can be simulated by the +/// a unitary transformation U which acts on the all-zeros state as +/// +/// $$ +/// \begin{align} +/// U\ket{0...0} +/// & = \ket{\psi} \\\\ +/// & = \frac{ +/// \sum_{j=0}^{2^n-1} r_j e^{i t_j} \ket{j} +/// }{ +/// \sqrt{\sum_{j=0}^{2^n-1} |r_j|^2} +/// }. +/// \end{align} +/// $$ +/// +/// # Input +/// ## tolerance +/// The approximation tolerance to be used when preparing the given state. +/// +/// ## coefficients +/// Array of up to 2ⁿ complex coefficients represented by their +/// absolute value and phase (rⱼ, tⱼ). The j-th coefficient +/// indexes the number state |j⟩ encoded in a big-endian format. +/// +/// ## qubits +/// Qubit register encoding number states in a big-endian format. This is +/// expected to be initialized in the computational basis state +/// |0...0⟩. +/// +/// # Remarks +/// `coefficients` will be padded with +/// elements (rⱼ, tⱼ) = (0.0, 0.0) if fewer than 2ⁿ are +/// specified. +/// +/// # References +/// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) +/// "Synthesis of Quantum Logic Circuits", +/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov +operation ApproximatelyPreparePureStateCP( + tolerance : Double, + coefficients : ComplexPolar[], + qubits : Qubit[] +) : Unit is Adj + Ctl { - let nQubits = Length(qubits); - // pad coefficients at tail length to a power of 2. - let coefficientsPadded = Padded(-2^nQubits, ComplexPolar(0.0, 0.0), coefficients); - let idxTarget = 0; - // Determine what controls to apply - let rngControl = nQubits > 1 ? (1..(nQubits - 1)) | (1..0); - // Note we use the reversed qubits array to get the endianness ordering that we expect - // when corresponding qubit state to state vector index. - Adjoint ApproximatelyUnprepareArbitraryState( - tolerance, - coefficientsPadded, - rngControl, - idxTarget, - Reversed(qubits) - ); - } + let nQubits = Length(qubits); + // pad coefficients at tail length to a power of 2. + let coefficientsPadded = Padded(-2^nQubits, ComplexPolar(0.0, 0.0), coefficients); + let idxTarget = 0; + // Determine what controls to apply + let rngControl = nQubits > 1 ? (1..(nQubits - 1)) | (1..0); + // Note we use the reversed qubits array to get the endianness ordering that we expect + // when corresponding qubit state to state vector index. + Adjoint ApproximatelyUnprepareArbitraryState( + tolerance, + coefficientsPadded, + rngControl, + idxTarget, + Reversed(qubits) + ); +} /// # Summary - /// Implementation step of arbitrary state preparation procedure. - internal operation ApproximatelyUnprepareArbitraryState( - tolerance : Double, - coefficients : ComplexPolar[], - rngControl : Range, - idxTarget : Int, - register : Qubit[] - ) : Unit is Adj + Ctl { +/// Implementation step of arbitrary state preparation procedure. +internal operation ApproximatelyUnprepareArbitraryState( + tolerance : Double, + coefficients : ComplexPolar[], + rngControl : Range, + idxTarget : Int, + register : Qubit[] +) : Unit is Adj + Ctl { - // For each 2D block, compute disentangling single-qubit rotation parameters - let (disentanglingY, disentanglingZ, newCoefficients) = StatePreparationSBMComputeCoefficients(coefficients); - if (AnyOutsideToleranceD(tolerance, disentanglingZ)) { - ApproximatelyMultiplexPauli(tolerance, disentanglingZ, PauliZ, register[rngControl], register[idxTarget]); + // For each 2D block, compute disentangling single-qubit rotation parameters + let (disentanglingY, disentanglingZ, newCoefficients) = StatePreparationSBMComputeCoefficients(coefficients); + if (AnyOutsideToleranceD(tolerance, disentanglingZ)) { + ApproximatelyMultiplexPauli(tolerance, disentanglingZ, PauliZ, register[rngControl], register[idxTarget]); - } - if (AnyOutsideToleranceD(tolerance, disentanglingY)) { - ApproximatelyMultiplexPauli(tolerance, disentanglingY, PauliY, register[rngControl], register[idxTarget]); - } - // target is now in |0> state up to the phase given by arg of newCoefficients. + } + if (AnyOutsideToleranceD(tolerance, disentanglingY)) { + ApproximatelyMultiplexPauli(tolerance, disentanglingY, PauliY, register[rngControl], register[idxTarget]); + } + // target is now in |0> state up to the phase given by arg of newCoefficients. - // Continue recursion while there are control qubits. - if (IsRangeEmpty(rngControl)) { - let (abs, arg) = (newCoefficients[0].Magnitude, newCoefficients[0].Argument); - if (AbsD(arg) > tolerance) { - Exp([PauliI], -1.0 * arg, [register[idxTarget]]); - } - } elif (Any(c -> AbsComplexPolar(c) > tolerance, newCoefficients)) { - // Some coefficients are outside tolerance - let newControl = (RangeStart(rngControl) + 1)..RangeStep(rngControl)..RangeEnd(rngControl); - let newTarget = RangeStart(rngControl); - ApproximatelyUnprepareArbitraryState(tolerance, newCoefficients, newControl, newTarget, register); + // Continue recursion while there are control qubits. + if (IsRangeEmpty(rngControl)) { + let (abs, arg) = (newCoefficients[0].Magnitude, newCoefficients[0].Argument); + if (AbsD(arg) > tolerance) { + Exp([PauliI], -1.0 * arg, [register[idxTarget]]); } + } elif (Any(c -> AbsComplexPolar(c) > tolerance, newCoefficients)) { + // Some coefficients are outside tolerance + let newControl = (RangeStart(rngControl) + 1)..RangeStep(rngControl)..RangeEnd(rngControl); + let newTarget = RangeStart(rngControl); + ApproximatelyUnprepareArbitraryState(tolerance, newCoefficients, newControl, newTarget, register); } +} /// # Summary - /// Applies a Pauli rotation conditioned on an array of qubits, truncating - /// small rotation angles according to a given tolerance. - /// - /// # Description - /// This applies a multiply controlled unitary operation that performs - /// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ - /// when controlled by the $n$-qubit number state $\ket{j}$. - /// In particular, the action of this operation is represented by the - /// unitary - /// - /// $$ - /// \begin{align} - /// U = \sum^{2^n - 1}_{j=0} \ket{j}\bra{j} \otimes e^{i P \theta_j}. - /// \end{align} - /// ## - /// - /// # Input - /// ## tolerance - /// A tolerance below which small coefficients are truncated. - /// - /// ## coefficients - /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient - /// indexes the number state $\ket{j}$ encoded in little-endian format. - /// - /// ## pauli - /// Pauli operator $P$ that determines axis of rotation. - /// - /// ## control - /// $n$-qubit control register that encodes number states $\ket{j}$ in - /// little-endian format. - /// - /// ## target - /// Single qubit register that is rotated by $e^{i P \theta_j}$. - /// - /// # Remarks - /// `coefficients` will be padded with elements $\theta_j = 0.0$ if - /// fewer than $2^n$ are specified. - internal operation ApproximatelyMultiplexPauli( - tolerance : Double, - coefficients : Double[], - pauli : Pauli, - control : Qubit[], - target : Qubit - ) : Unit is Adj + Ctl { +/// Applies a Pauli rotation conditioned on an array of qubits, truncating +/// small rotation angles according to a given tolerance. +/// +/// # Description +/// This applies a multiply controlled unitary operation that performs +/// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ +/// when controlled by the $n$-qubit number state $\ket{j}$. +/// In particular, the action of this operation is represented by the +/// unitary +/// +/// $$ +/// \begin{align} +/// U = \sum^{2^n - 1}_{j=0} \ket{j}\bra{j} \otimes e^{i P \theta_j}. +/// \end{align} +/// ## +/// +/// # Input +/// ## tolerance +/// A tolerance below which small coefficients are truncated. +/// +/// ## coefficients +/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient +/// indexes the number state $\ket{j}$ encoded in little-endian format. +/// +/// ## pauli +/// Pauli operator $P$ that determines axis of rotation. +/// +/// ## control +/// $n$-qubit control register that encodes number states $\ket{j}$ in +/// little-endian format. +/// +/// ## target +/// Single qubit register that is rotated by $e^{i P \theta_j}$. +/// +/// # Remarks +/// `coefficients` will be padded with elements $\theta_j = 0.0$ if +/// fewer than $2^n$ are specified. +internal operation ApproximatelyMultiplexPauli( + tolerance : Double, + coefficients : Double[], + pauli : Pauli, + control : Qubit[], + target : Qubit +) : Unit is Adj + Ctl { - if pauli == PauliZ { - ApproximatelyMultiplexZ(tolerance, coefficients, control, target); - } elif pauli == PauliX { - within { - H(target); - } apply { - ApproximatelyMultiplexPauli(tolerance, coefficients, PauliZ, control, target); - } - } elif pauli == PauliY { - within { - Adjoint S(target); - } apply { - ApproximatelyMultiplexPauli(tolerance, coefficients, PauliX, control, target); - } - } else { - fail $"MultiplexPauli failed. Invalid pauli {pauli}."; + if pauli == PauliZ { + ApproximatelyMultiplexZ(tolerance, coefficients, control, target); + } elif pauli == PauliX { + within { + H(target); + } apply { + ApproximatelyMultiplexPauli(tolerance, coefficients, PauliZ, control, target); + } + } elif pauli == PauliY { + within { + Adjoint S(target); + } apply { + ApproximatelyMultiplexPauli(tolerance, coefficients, PauliX, control, target); } + } else { + fail $"MultiplexPauli failed. Invalid pauli {pauli}."; } +} /// # Summary - /// Implementation step of arbitrary state preparation procedure. - internal function StatePreparationSBMComputeCoefficients( - coefficients : ComplexPolar[] - ) : (Double[], Double[], ComplexPolar[]) { +/// Implementation step of arbitrary state preparation procedure. +internal function StatePreparationSBMComputeCoefficients( + coefficients : ComplexPolar[] +) : (Double[], Double[], ComplexPolar[]) { - mutable disentanglingZ = []; - mutable disentanglingY = []; - mutable newCoefficients = []; - - for idxCoeff in 0..2..Length(coefficients) - 1 { - let (rt, phi, theta) = BlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff + 1]); - set disentanglingZ += [0.5 * phi]; - set disentanglingY += [0.5 * theta]; - set newCoefficients += [rt]; - } + mutable disentanglingZ = []; + mutable disentanglingY = []; + mutable newCoefficients = []; - return (disentanglingY, disentanglingZ, newCoefficients); + for idxCoeff in 0..2..Length(coefficients) - 1 { + let (rt, phi, theta) = BlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff + 1]); + set disentanglingZ += [0.5 * phi]; + set disentanglingY += [0.5 * theta]; + set newCoefficients += [rt]; } + return (disentanglingY, disentanglingZ, newCoefficients); +} + /// # Summary - /// Computes the Bloch sphere coordinates for a single-qubit state. - /// - /// Given two complex numbers $a0, a1$ that represent the qubit state, computes coordinates - /// on the Bloch sphere such that - /// $a0 \ket{0} + a1 \ket{1} = r e^{it}(e^{-i \phi /2}\cos{(\theta/2)}\ket{0}+e^{i \phi /2}\sin{(\theta/2)}\ket{1})$. - /// - /// # Input - /// ## a0 - /// Complex coefficient of state $\ket{0}$. - /// ## a1 - /// Complex coefficient of state $\ket{1}$. - /// - /// # Output - /// A tuple containing `(ComplexPolar(r, t), phi, theta)`. - internal function BlochSphereCoordinates( - a0 : ComplexPolar, - a1 : ComplexPolar - ) : (ComplexPolar, Double, Double) { +/// Computes the Bloch sphere coordinates for a single-qubit state. +/// +/// Given two complex numbers $a0, a1$ that represent the qubit state, computes coordinates +/// on the Bloch sphere such that +/// $a0 \ket{0} + a1 \ket{1} = r e^{it}(e^{-i \phi /2}\cos{(\theta/2)}\ket{0}+e^{i \phi /2}\sin{(\theta/2)}\ket{1})$. +/// +/// # Input +/// ## a0 +/// Complex coefficient of state $\ket{0}$. +/// ## a1 +/// Complex coefficient of state $\ket{1}$. +/// +/// # Output +/// A tuple containing `(ComplexPolar(r, t), phi, theta)`. +internal function BlochSphereCoordinates( + a0 : ComplexPolar, + a1 : ComplexPolar +) : (ComplexPolar, Double, Double) { - let abs0 = AbsComplexPolar(a0); - let abs1 = AbsComplexPolar(a1); - let arg0 = ArgComplexPolar(a0); - let arg1 = ArgComplexPolar(a1); - let r = Sqrt(abs0 * abs0 + abs1 * abs1); - let t = 0.5 * (arg0 + arg1); - let phi = arg1 - arg0; - let theta = 2.0 * ArcTan2(abs1, abs0); - return (ComplexPolar(r, t), phi, theta); - } + let abs0 = AbsComplexPolar(a0); + let abs1 = AbsComplexPolar(a1); + let arg0 = ArgComplexPolar(a0); + let arg1 = ArgComplexPolar(a1); + let r = Sqrt(abs0 * abs0 + abs1 * abs1); + let t = 0.5 * (arg0 + arg1); + let phi = arg1 - arg0; + let theta = 2.0 * ArcTan2(abs1, abs0); + return (ComplexPolar(r, t), phi, theta); +} /// # Summary - /// Applies a Pauli Z rotation conditioned on an array of qubits, truncating - /// small rotation angles according to a given tolerance. - /// - /// # Description - /// This applies the multiply controlled unitary operation that performs - /// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ - /// when controlled by the $n$-qubit number state $\ket{j}$. - /// In particular, this operation can be represented by the unitary - /// - /// $$ - /// \begin{align} - /// U = \sum^{2^n-1}_{j=0} \ket{j}\bra{j} \otimes e^{i Z \theta_j}. - /// \end{align} - /// $$ - /// - /// # Input - /// ## tolerance - /// A tolerance below which small coefficients are truncated. - /// - /// ## coefficients - /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient - /// indexes the number state $\ket{j}$ encoded in little-endian format. - /// - /// ## control - /// $n$-qubit control register that encodes number states $\ket{j}$ in - /// little-endian format. - /// - /// ## target - /// Single qubit register that is rotated by $e^{i P \theta_j}$. - /// - /// # Remarks - /// `coefficients` will be padded with elements $\theta_j = 0.0$ if - /// fewer than $2^n$ are specified. - /// - /// # References - /// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) - /// "Synthesis of Quantum Logic Circuits", - /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov - internal operation ApproximatelyMultiplexZ( - tolerance : Double, - coefficients : Double[], - control : Qubit[], - target : Qubit - ) : Unit is Adj + Ctl { +/// Applies a Pauli Z rotation conditioned on an array of qubits, truncating +/// small rotation angles according to a given tolerance. +/// +/// # Description +/// This applies the multiply controlled unitary operation that performs +/// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ +/// when controlled by the $n$-qubit number state $\ket{j}$. +/// In particular, this operation can be represented by the unitary +/// +/// $$ +/// \begin{align} +/// U = \sum^{2^n-1}_{j=0} \ket{j}\bra{j} \otimes e^{i Z \theta_j}. +/// \end{align} +/// $$ +/// +/// # Input +/// ## tolerance +/// A tolerance below which small coefficients are truncated. +/// +/// ## coefficients +/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient +/// indexes the number state $\ket{j}$ encoded in little-endian format. +/// +/// ## control +/// $n$-qubit control register that encodes number states $\ket{j}$ in +/// little-endian format. +/// +/// ## target +/// Single qubit register that is rotated by $e^{i P \theta_j}$. +/// +/// # Remarks +/// `coefficients` will be padded with elements $\theta_j = 0.0$ if +/// fewer than $2^n$ are specified. +/// +/// # References +/// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) +/// "Synthesis of Quantum Logic Circuits", +/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov +internal operation ApproximatelyMultiplexZ( + tolerance : Double, + coefficients : Double[], + control : Qubit[], + target : Qubit +) : Unit is Adj + Ctl { - body (...) { - // pad coefficients length at tail to a power of 2. - let coefficientsPadded = Padded(-2^Length(control), 0.0, coefficients); + body (...) { + // pad coefficients length at tail to a power of 2. + let coefficientsPadded = Padded(-2^Length(control), 0.0, coefficients); - if Length(coefficientsPadded) == 1 { - // Termination case - if AbsD(coefficientsPadded[0]) > tolerance { - Exp([PauliZ], coefficientsPadded[0], [target]); - } - } else { - // Compute new coefficients. - let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance, coefficients0, Most(control), target); - if AnyOutsideToleranceD(tolerance, coefficients1) { - within { - CNOT(Tail(control), target); - } apply { - ApproximatelyMultiplexZ(tolerance, coefficients1, Most(control), target); - } - } + if Length(coefficientsPadded) == 1 { + // Termination case + if AbsD(coefficientsPadded[0]) > tolerance { + Exp([PauliZ], coefficientsPadded[0], [target]); } - } - - controlled (controlRegister, ...) { - // pad coefficients length to a power of 2. - let coefficientsPadded = Padded(2^(Length(control) + 1), 0.0, Padded(-2^Length(control), 0.0, coefficients)); + } else { + // Compute new coefficients. let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance, coefficients0, control, target); + ApproximatelyMultiplexZ(tolerance, coefficients0, Most(control), target); if AnyOutsideToleranceD(tolerance, coefficients1) { within { - Controlled X(controlRegister, target); + CNOT(Tail(control), target); } apply { - ApproximatelyMultiplexZ(tolerance, coefficients1, control, target); + ApproximatelyMultiplexZ(tolerance, coefficients1, Most(control), target); } } } } - /// # Summary - /// Implementation step of multiply-controlled Z rotations. - internal function MultiplexZCoefficients(coefficients : Double[]) : (Double[], Double[]) { - let newCoefficientsLength = Length(coefficients) / 2; - mutable coefficients0 = []; - mutable coefficients1 = []; - - for idxCoeff in 0..newCoefficientsLength - 1 { - set coefficients0 += [0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength])]; - set coefficients1 += [0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength])]; + controlled (controlRegister, ...) { + // pad coefficients length to a power of 2. + let coefficientsPadded = Padded(2^(Length(control) + 1), 0.0, Padded(-2^Length(control), 0.0, coefficients)); + let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); + ApproximatelyMultiplexZ(tolerance, coefficients0, control, target); + if AnyOutsideToleranceD(tolerance, coefficients1) { + within { + Controlled X(controlRegister, target); + } apply { + ApproximatelyMultiplexZ(tolerance, coefficients1, control, target); + } } - - return (coefficients0, coefficients1); } +} - internal function AnyOutsideToleranceD(tolerance : Double, coefficients : Double[]) : Bool { - // NOTE: This function is not used as the only recursion termination condition - // only to determine if the multiplex step needs to be applied. - // For tolerance 0.0 it is always applied due to >= comparison. - Any(coefficient -> AbsD(coefficient) >= tolerance, coefficients) + /// # Summary +/// Implementation step of multiply-controlled Z rotations. +internal function MultiplexZCoefficients(coefficients : Double[]) : (Double[], Double[]) { + let newCoefficientsLength = Length(coefficients) / 2; + mutable coefficients0 = []; + mutable coefficients1 = []; + + for idxCoeff in 0..newCoefficientsLength - 1 { + set coefficients0 += [0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength])]; + set coefficients1 += [0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength])]; } - export PreparePureStateD, ApproximatelyPreparePureStateCP; + return (coefficients0, coefficients1); +} + +internal function AnyOutsideToleranceD(tolerance : Double, coefficients : Double[]) : Bool { + // NOTE: This function is not used as the only recursion termination condition + // only to determine if the multiplex step needs to be applied. + // For tolerance 0.0 it is always applied due to >= comparison. + Any(coefficient -> AbsD(coefficient) >= tolerance, coefficients) +} + +export PreparePureStateD, ApproximatelyPreparePureStateCP; diff --git a/library/std/src/Std/Unstable/TableLookup.qs b/library/std/src/Std/Unstable/TableLookup.qs index 046b00d90b..89a2d45da0 100644 --- a/library/std/src/Std/Unstable/TableLookup.qs +++ b/library/std/src/Std/Unstable/TableLookup.qs @@ -2,280 +2,280 @@ // Licensed under the MIT License. - import Std.Arrays.*; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.ResourceEstimation; - open Microsoft.Quantum.Unstable.Arithmetic; - import Std.Unstable.ArithmeticHelpers.*; - - import QIR.Intrinsic.*; - - - /// # Summary - /// Performs table lookup using a SELECT network - /// - /// # Description - /// Assuming a zero-initialized `target` register, this operation will - /// initialize it with the bitstrings in `data` at indices according to the - /// computational values of the `address` register. - /// - /// # Input - /// ## data - /// The classical table lookup data which is prepared in `target` with - /// respect to the state in `address`. The length of data must be less than - /// 2ⁿ, where 𝑛 is the length of `address`. Each entry in data must have - /// the same length that must be equal to the length of `target`. - /// ## address - /// Address register - /// ## target - /// Zero-initialized target register - /// - /// # Remarks - /// The implementation of the SELECT network is based on unary encoding as - /// presented in [1]. The recursive implementation of that algorithm is - /// presented in [3]. The adjoint variant is optimized using a - /// measurement-based unlookup operation [3]. The controlled adjoint variant - /// is not optimized using this technique. - /// - /// # References - /// 1. [arXiv:1805.03662](https://arxiv.org/abs/1805.03662) - /// "Encoding Electronic Spectra in Quantum Circuits with Linear T - /// Complexity" - /// 2. [arXiv:1905.07682](https://arxiv.org/abs/1905.07682) - /// "Windowed arithmetic" - /// 3. [arXiv:2211.01133](https://arxiv.org/abs/2211.01133) - /// "Space-time optimized table lookup" - operation Select( - data : Bool[][], - address : Qubit[], - target : Qubit[] - ) : Unit is Adj + Ctl { - body (...) { - let (N, n) = DimensionsForSelect(data, address); - - if N == 1 { - // base case - WriteMemoryContents(Head(data), target); - } else { - let (most, tail) = MostAndTail(address[...n - 1]); - let parts = Partitioned([2^(n - 1)], data); - - within { - X(tail); - } apply { - SinglyControlledSelect(tail, parts[0], most, target); - } - - SinglyControlledSelect(tail, parts[1], most, target); - } - } - adjoint (...) { - Unlookup(Select, data, address, target); - } +import Std.Arrays.*; +open Microsoft.Quantum.Convert; +open Microsoft.Quantum.Diagnostics; +open Microsoft.Quantum.Math; +open Microsoft.Quantum.ResourceEstimation; +open Microsoft.Quantum.Unstable.Arithmetic; +import Std.Unstable.ArithmeticHelpers.*; + +import QIR.Intrinsic.*; + + +/// # Summary +/// Performs table lookup using a SELECT network +/// +/// # Description +/// Assuming a zero-initialized `target` register, this operation will +/// initialize it with the bitstrings in `data` at indices according to the +/// computational values of the `address` register. +/// +/// # Input +/// ## data +/// The classical table lookup data which is prepared in `target` with +/// respect to the state in `address`. The length of data must be less than +/// 2ⁿ, where 𝑛 is the length of `address`. Each entry in data must have +/// the same length that must be equal to the length of `target`. +/// ## address +/// Address register +/// ## target +/// Zero-initialized target register +/// +/// # Remarks +/// The implementation of the SELECT network is based on unary encoding as +/// presented in [1]. The recursive implementation of that algorithm is +/// presented in [3]. The adjoint variant is optimized using a +/// measurement-based unlookup operation [3]. The controlled adjoint variant +/// is not optimized using this technique. +/// +/// # References +/// 1. [arXiv:1805.03662](https://arxiv.org/abs/1805.03662) +/// "Encoding Electronic Spectra in Quantum Circuits with Linear T +/// Complexity" +/// 2. [arXiv:1905.07682](https://arxiv.org/abs/1905.07682) +/// "Windowed arithmetic" +/// 3. [arXiv:2211.01133](https://arxiv.org/abs/2211.01133) +/// "Space-time optimized table lookup" +operation Select( + data : Bool[][], + address : Qubit[], + target : Qubit[] +) : Unit is Adj + Ctl { + body (...) { + let (N, n) = DimensionsForSelect(data, address); - controlled (ctls, ...) { - let numCtls = Length(ctls); - - if numCtls == 0 { - Select(data, address, target); - } elif numCtls == 1 { - SinglyControlledSelect(ctls[0], data, address, target); - } else { - use andChainTarget = Qubit(); - let andChain = MakeAndChain(ctls, andChainTarget); - use helper = Qubit[andChain.NGarbageQubits]; - - within { - andChain.Apply(helper); - } apply { - SinglyControlledSelect(andChainTarget, data, address, target); - } + if N == 1 { + // base case + WriteMemoryContents(Head(data), target); + } else { + let (most, tail) = MostAndTail(address[...n - 1]); + let parts = Partitioned([2^(n - 1)], data); + + within { + X(tail); + } apply { + SinglyControlledSelect(tail, parts[0], most, target); } - } - controlled adjoint (ctls, ...) { - Controlled Select(ctls, (data, address, target)); + SinglyControlledSelect(tail, parts[1], most, target); } } + adjoint (...) { + Unlookup(Select, data, address, target); + } - internal operation SinglyControlledSelect( - ctl : Qubit, - data : Bool[][], - address : Qubit[], - target : Qubit[] - ) : Unit { - let (N, n) = DimensionsForSelect(data, address); + controlled (ctls, ...) { + let numCtls = Length(ctls); - if BeginEstimateCaching("Microsoft.Quantum.Unstable.TableLookup.SinglyControlledSelect", N) { - if N == 1 { - // base case - Controlled WriteMemoryContents([ctl], (Head(data), target)); - } else { - use helper = Qubit(); + if numCtls == 0 { + Select(data, address, target); + } elif numCtls == 1 { + SinglyControlledSelect(ctls[0], data, address, target); + } else { + use andChainTarget = Qubit(); + let andChain = MakeAndChain(ctls, andChainTarget); + use helper = Qubit[andChain.NGarbageQubits]; + + within { + andChain.Apply(helper); + } apply { + SinglyControlledSelect(andChainTarget, data, address, target); + } + } + } - let (most, tail) = MostAndTail(address[...n - 1]); - let parts = Partitioned([2^(n - 1)], data); + controlled adjoint (ctls, ...) { + Controlled Select(ctls, (data, address, target)); + } +} + +internal operation SinglyControlledSelect( + ctl : Qubit, + data : Bool[][], + address : Qubit[], + target : Qubit[] +) : Unit { + let (N, n) = DimensionsForSelect(data, address); + + if BeginEstimateCaching("Microsoft.Quantum.Unstable.TableLookup.SinglyControlledSelect", N) { + if N == 1 { + // base case + Controlled WriteMemoryContents([ctl], (Head(data), target)); + } else { + use helper = Qubit(); - within { - X(tail); - } apply { - ApplyAndAssuming0Target(ctl, tail, helper); - } + let (most, tail) = MostAndTail(address[...n - 1]); + let parts = Partitioned([2^(n - 1)], data); - SinglyControlledSelect(helper, parts[0], most, target); + within { + X(tail); + } apply { + ApplyAndAssuming0Target(ctl, tail, helper); + } - CNOT(ctl, helper); + SinglyControlledSelect(helper, parts[0], most, target); - SinglyControlledSelect(helper, parts[1], most, target); + CNOT(ctl, helper); - Adjoint ApplyAndAssuming0Target(ctl, tail, helper); - } + SinglyControlledSelect(helper, parts[1], most, target); - EndEstimateCaching(); + Adjoint ApplyAndAssuming0Target(ctl, tail, helper); } + + EndEstimateCaching(); } +} + +internal function DimensionsForSelect( + data : Bool[][], + address : Qubit[] +) : (Int, Int) { + let N = Length(data); + Fact(N > 0, "data cannot be empty"); + + let n = Ceiling(Lg(IntAsDouble(N))); + Fact( + Length(address) >= n, + $"address register is too small, requires at least {n} qubits" + ); - internal function DimensionsForSelect( - data : Bool[][], - address : Qubit[] - ) : (Int, Int) { - let N = Length(data); - Fact(N > 0, "data cannot be empty"); + return (N, n); +} - let n = Ceiling(Lg(IntAsDouble(N))); - Fact( - Length(address) >= n, - $"address register is too small, requires at least {n} qubits" - ); +internal operation WriteMemoryContents( + value : Bool[], + target : Qubit[] +) : Unit is Adj + Ctl { + Fact( + Length(value) == Length(target), + "number of data bits must equal number of target qubits" + ); - return (N, n); - } + ApplyPauliFromBitString(PauliX, true, value, target); +} - internal operation WriteMemoryContents( - value : Bool[], - target : Qubit[] - ) : Unit is Adj + Ctl { - Fact( - Length(value) == Length(target), - "number of data bits must equal number of target qubits" - ); + /// # References +/// - [arXiv:1905.07682](https://arxiv.org/abs/1905.07682) +/// "Windowed arithmetic" +internal operation Unlookup( + lookup : (Bool[][], Qubit[], Qubit[]) => Unit, + data : Bool[][], + select : Qubit[], + target : Qubit[] +) : Unit { + let numBits = Length(target); + let numAddressBits = Length(select); + + let l = MinI(Floor(Lg(IntAsDouble(numBits))), numAddressBits - 1); + Fact( + l < numAddressBits, + $"l = {l} must be smaller than {numAddressBits}" + ); - ApplyPauliFromBitString(PauliX, true, value, target); - } + let res = Mapped(r -> r == One, ForEach(MResetX, target)); - /// # References - /// - [arXiv:1905.07682](https://arxiv.org/abs/1905.07682) - /// "Windowed arithmetic" - internal operation Unlookup( - lookup : (Bool[][], Qubit[], Qubit[]) => Unit, - data : Bool[][], - select : Qubit[], - target : Qubit[] - ) : Unit { - let numBits = Length(target); - let numAddressBits = Length(select); - - let l = MinI(Floor(Lg(IntAsDouble(numBits))), numAddressBits - 1); - Fact( - l < numAddressBits, - $"l = {l} must be smaller than {numAddressBits}" - ); - - let res = Mapped(r -> r == One, ForEach(MResetX, target)); - - let dataFixup = Chunks(2^l, Padded(-2^numAddressBits, false, Mapped(MustBeFixed(res, _), data))); - - let numAddressBitsFixup = numAddressBits - l; - - let selectParts = Partitioned([l], select); - let targetFixup = target[...2^l - 1]; - - within { - EncodeUnary(selectParts[0], targetFixup); - ApplyToEachA(H, targetFixup); - } apply { - lookup(dataFixup, selectParts[1], targetFixup); - } - } + let dataFixup = Chunks(2^l, Padded(-2^numAddressBits, false, Mapped(MustBeFixed(res, _), data))); - // Checks whether specific bit string `data` must be fixed for a given - // measurement result `result`. - // - // Returns true if the number of indices for which both result and data are - // `true` is odd. - internal function MustBeFixed(result : Bool[], data : Bool[]) : Bool { - mutable state = false; - for i in IndexRange(result) { - set state = state != (result[i] and data[i]); - } - state + let numAddressBitsFixup = numAddressBits - l; + + let selectParts = Partitioned([l], select); + let targetFixup = target[...2^l - 1]; + + within { + EncodeUnary(selectParts[0], targetFixup); + ApplyToEachA(H, targetFixup); + } apply { + lookup(dataFixup, selectParts[1], targetFixup); } +} + +// Checks whether specific bit string `data` must be fixed for a given +// measurement result `result`. +// +// Returns true if the number of indices for which both result and data are +// `true` is odd. +internal function MustBeFixed(result : Bool[], data : Bool[]) : Bool { + mutable state = false; + for i in IndexRange(result) { + set state = state != (result[i] and data[i]); + } + state +} + +// Computes unary encoding of value in `input` into `target` +// +// Assumptions: +// - `target` is zero-initialized +// - length of `input` is n +// - length of `target` is 2^n +internal operation EncodeUnary( + input : Qubit[], + target : Qubit[] +) : Unit is Adj { + Fact( + Length(target) == 2^Length(input), + $"target register should be of length {2^Length(input)}, but is {Length(target)}" + ); + + X(Head(target)); - // Computes unary encoding of value in `input` into `target` - // - // Assumptions: - // - `target` is zero-initialized - // - length of `input` is n - // - length of `target` is 2^n - internal operation EncodeUnary( - input : Qubit[], - target : Qubit[] - ) : Unit is Adj { - Fact( - Length(target) == 2^Length(input), - $"target register should be of length {2^Length(input)}, but is {Length(target)}" - ); - - X(Head(target)); - - for i in IndexRange(input) { - if i == 0 { - CNOT(input[i], target[1]); - CNOT(target[1], target[0]); - } else { - // targets are the first and second 2^i qubits of the target register - let split = Partitioned([2^i, 2^i], target); - for j in IndexRange(split[0]) { - ApplyAndAssuming0Target(input[i], split[0][j], split[1][j]); - CNOT(split[1][j], split[0][j]); - } + for i in IndexRange(input) { + if i == 0 { + CNOT(input[i], target[1]); + CNOT(target[1], target[0]); + } else { + // targets are the first and second 2^i qubits of the target register + let split = Partitioned([2^i, 2^i], target); + for j in IndexRange(split[0]) { + ApplyAndAssuming0Target(input[i], split[0][j], split[1][j]); + CNOT(split[1][j], split[0][j]); } } - } - internal newtype AndChain = ( - NGarbageQubits : Int, - Apply : Qubit[] => Unit is Adj - ); +} - internal function MakeAndChain(ctls : Qubit[], target : Qubit) : AndChain { - AndChain( - MaxI(Length(ctls) - 2, 0), - helper => AndChainOperation(ctls, helper, target) - ) - } +internal newtype AndChain = ( + NGarbageQubits : Int, + Apply : Qubit[] => Unit is Adj +); - internal operation AndChainOperation(ctls : Qubit[], helper : Qubit[], target : Qubit) : Unit is Adj { - let n = Length(ctls); +internal function MakeAndChain(ctls : Qubit[], target : Qubit) : AndChain { + AndChain( + MaxI(Length(ctls) - 2, 0), + helper => AndChainOperation(ctls, helper, target) + ) +} - Fact(Length(helper) == MaxI(n - 2, 0), "Invalid number of helper qubits"); +internal operation AndChainOperation(ctls : Qubit[], helper : Qubit[], target : Qubit) : Unit is Adj { + let n = Length(ctls); - if n == 0 { - X(target); - } elif n == 1 { - CNOT(ctls[0], target); - } else { - let ctls1 = ctls[0..0] + helper; - let ctls2 = ctls[1...]; - let tgts = helper + [target]; + Fact(Length(helper) == MaxI(n - 2, 0), "Invalid number of helper qubits"); - for idx in IndexRange(tgts) { - ApplyAndAssuming0Target(ctls1[idx], ctls2[idx], tgts[idx]); - } + if n == 0 { + X(target); + } elif n == 1 { + CNOT(ctls[0], target); + } else { + let ctls1 = ctls[0..0] + helper; + let ctls2 = ctls[1...]; + let tgts = helper + [target]; + + for idx in IndexRange(tgts) { + ApplyAndAssuming0Target(ctls1[idx], ctls2[idx], tgts[idx]); } } +} - export Select; +export Select; From 920dd7160aa4d49aa39ee517ae4f504b4366f4e9 Mon Sep 17 00:00:00 2001 From: sezna Date: Tue, 10 Sep 2024 14:24:00 -0700 Subject: [PATCH 11/29] migrate canon and undo unstable migration --- library/src/lib.rs | 20 +- library/std/qsharp.json | 12 +- library/std/src/Std/Arrays.qs | 44 -- library/std/src/Std/Canon.qs | 588 +++++++++++++++ library/std/src/Std/Convert.qs | 13 - library/std/src/Std/Diagnostics.qs | 11 - library/std/src/Std/Intrinsic.qs | 29 - library/std/src/Std/Math.qs | 81 -- library/std/src/Std/Measurement.qs | 6 - library/std/src/Std/Random.qs | 2 - library/std/src/Std/ResourceEstimation.qs | 12 - library/std/src/Std/Unstable/Arithmetic.qs | 702 ------------------ .../std/src/Std/Unstable/ArithmeticHelpers.qs | 586 --------------- .../std/src/Std/Unstable/StatePreparation.qs | 390 ---------- library/std/src/Std/Unstable/TableLookup.qs | 281 ------- library/std/src/canon.qs | 589 --------------- library/std/src/legacy_api.qs | 6 +- library/std/src/unstable_arithmetic.qs | 701 +++++++++++++++++ .../std/src/unstable_arithmetic_internal.qs | 585 +++++++++++++++ library/std/src/unstable_state_preparation.qs | 388 ++++++++++ library/std/src/unstable_table_lookup.qs | 278 +++++++ 21 files changed, 2557 insertions(+), 2767 deletions(-) create mode 100644 library/std/src/Std/Canon.qs delete mode 100644 library/std/src/Std/Unstable/Arithmetic.qs delete mode 100644 library/std/src/Std/Unstable/ArithmeticHelpers.qs delete mode 100644 library/std/src/Std/Unstable/StatePreparation.qs delete mode 100644 library/std/src/Std/Unstable/TableLookup.qs delete mode 100644 library/std/src/canon.qs create mode 100644 library/std/src/unstable_arithmetic.qs create mode 100644 library/std/src/unstable_arithmetic_internal.qs create mode 100644 library/std/src/unstable_state_preparation.qs create mode 100644 library/std/src/unstable_table_lookup.qs diff --git a/library/src/lib.rs b/library/src/lib.rs index f41b02b74e..c0f28dfeda 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -26,8 +26,8 @@ pub const STD_LIB: &[(&str, &str)] = &[ 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:Std/Convert.qs", @@ -74,20 +74,20 @@ pub const STD_LIB: &[(&str, &str)] = &[ include_str!("../std/src/Std/ResourceEstimation.qs"), ), ( - "qsharp-library-source:Std/Unstable/Arithmetic.qs", - include_str!("../std/src/Std/Unstable/Arithmetic.qs"), + "qsharp-library-source:unstable_arithmetic_internal.qs", + include_str!("../std/src/unstable_arithmetic_internal.qs"), ), ( - "qsharp-library-source:Std/Unstable/ArithmeticHelpers.qs", - include_str!("../std/src/Std/Unstable/ArithmeticHelpers.qs"), + "qsharp-library-source:unstable_arithmetic.qs", + include_str!("../std/src/unstable_arithmetic.qs"), ), ( - "qsharp-library-source:Std/Unstable/StatePreparation.qs", - include_str!("../std/src/Std/Unstable/StatePreparation.qs"), + "qsharp-library-source:unstable_state_preparation.qs", + include_str!("../std/src/unstable_state_preparation.qs"), ), ( - "qsharp-library-source:Std/Unstable/TableLookup.qs", - include_str!("../std/src/Std/Unstable/TableLookup.qs"), + "qsharp-library-source:unstable_table_lookup.qs", + include_str!("../std/src/unstable_table_lookup.qs"), ), ( "qsharp-library-source:legacy_api.qs", diff --git a/library/std/qsharp.json b/library/std/qsharp.json index 4c27d0d140..e3a857383e 100644 --- a/library/std/qsharp.json +++ b/library/std/qsharp.json @@ -2,11 +2,15 @@ "author": "Microsoft", "license": "MIT", "files": [ - "src/canon.qs", "src/core.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/QIR/Intrinsic.qs", "src/Std/Arrays.qs", + "src/Std/Canon.qs", "src/Std/Convert.qs", "src/Std/Diagnostics.qs", "src/Std/InternalHelpers.qs", @@ -15,10 +19,6 @@ "src/Std/Math.qs", "src/Std/Measurement.qs", "src/Std/Random.qs", - "src/Std/ResourceEstimation.qs", - "src/Std/Unstable/Arithmetic.qs", - "src/Std/Unstable/ArithmeticHelpers.qs", - "src/Std/Unstable/StatePreparation.qs", - "src/Std/Unstable/TableLookup.qs" + "src/Std/ResourceEstimation.qs" ] } \ No newline at end of file diff --git a/library/std/src/Std/Arrays.qs b/library/std/src/Std/Arrays.qs index 3253f33a1d..f2a572b96b 100644 --- a/library/std/src/Std/Arrays.qs +++ b/library/std/src/Std/Arrays.qs @@ -37,7 +37,6 @@ function All<'T>(predicate : ('T -> Bool), array : 'T[]) : Bool { 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. @@ -69,7 +68,6 @@ function Any<'T>(predicate : ('T -> Bool), array : 'T[]) : Bool { false } - /// # Summary /// Splits an array into multiple parts of equal length. /// /// # Input @@ -97,7 +95,6 @@ function Chunks<'T>(chunkSize : Int, array : 'T[]) : 'T[][] { output } - /// # Summary /// Shift an array circularly left or right by a specific step size. /// /// # Type Parameters @@ -145,7 +142,6 @@ function CircularlyShifted<'T>(stepCount : Int, array : 'T[]) : 'T[] { rightPart + leftPart } - /// # Summary /// Extracts a column from a matrix. /// /// # Description @@ -182,7 +178,6 @@ function ColumnAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { 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. @@ -215,7 +210,6 @@ function Count<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { count } - /// # Summary /// Returns an array of diagonal elements of a 2-dimensional array /// /// # Description @@ -252,7 +246,6 @@ function Diagonal<'T>(matrix : 'T[][]) : 'T[] { diagonal } - /// # Summary /// Repeats an operation for a given number of samples, collecting its outputs /// in an array. /// @@ -284,7 +277,6 @@ operation DrawMany<'TInput, 'TOutput>(op : ('TInput => 'TOutput), nSamples : Int outputs } - /// # Summary /// Given an array, returns a new array containing elements of the original /// array along with the indices of each element. /// @@ -313,7 +305,6 @@ 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. /// @@ -355,7 +346,6 @@ function Excluding<'T>(remove : Int[], array : 'T[]) : 'T[] { 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. @@ -388,7 +378,6 @@ function Filtered<'T>(predicate : ('T -> Bool), array : 'T[]) : 'T[] { 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. /// @@ -422,7 +411,6 @@ function FlatMapped<'TInput, 'TOutput>(mapper : ('TInput -> 'TOutput[]), array : output } - /// # Summary /// Given an array of arrays, returns the concatenation of all arrays. /// /// # Type Parameters @@ -449,7 +437,6 @@ function Flattened<'T>(arrays : 'T[][]) : 'T[] { output } - /// # Summary /// Iterates a function `f` through an array `array`, returning /// `f(...f(f(initialState, array[0]), array[1]), ...)`. /// @@ -484,7 +471,6 @@ function Fold<'State, 'T>(folder : (('State, 'T) -> 'State), state : 'State, arr 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. @@ -514,7 +500,6 @@ operation ForEach<'T, 'U>(action : ('T => 'U), array : 'T[]) : 'U[] { output } - /// # Summary /// Returns the first element of the array. /// /// # Type Parameters @@ -532,7 +517,6 @@ function Head<'A>(array : 'A[]) : 'A { array[0] } - /// # Summary /// Returns a tuple of first and all remaining elements of the array. /// /// # Type Parameters @@ -549,7 +533,6 @@ 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. /// @@ -578,7 +561,6 @@ function IndexOf<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { -1 } - /// # Summary /// Given an array, returns a range over the indices of that array, suitable /// for use in a for loop. /// @@ -603,7 +585,6 @@ function IndexRange<'TElement>(array : 'TElement[]) : Range { 0..Length(array) - 1 } - /// # Summary /// Interleaves two arrays of (almost) same size. /// /// # Description @@ -651,7 +632,6 @@ function Interleaved<'T>(first : 'T[], second : 'T[]) : 'T[] { interleaved } - /// # Summary /// Returns true if and only if an array is empty. /// /// # Input @@ -664,7 +644,6 @@ function IsEmpty<'T>(array : 'T[]) : Bool { Length(array) == 0 } - /// # Summary /// Returns whether a 2-dimensional array has a rectangular shape /// /// # Type Parameters @@ -700,7 +679,6 @@ function IsRectangularArray<'T>(array : 'T[][]) : Bool { true } - /// # Summary /// Given an array, returns whether that array is sorted as defined by /// a given comparison function. /// @@ -732,7 +710,6 @@ function IsSorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : Bool { true } - /// # Summary /// Returns whether a 2-dimensional array has a square shape /// /// # Type Parameters @@ -768,7 +745,6 @@ function IsSquareArray<'T>(array : 'T[][]) : Bool { 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. @@ -798,7 +774,6 @@ function Mapped<'T, 'U>(mapper : ('T -> 'U), array : 'T[]) : 'U[] { 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. @@ -839,7 +814,6 @@ function MappedByIndex<'T, 'U>(mapper : ((Int, 'T) -> 'U), array : 'T[]) : 'U[] 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. @@ -874,7 +848,6 @@ function MappedOverRange<'T>(mapper : (Int -> 'T), range : Range) : 'T[] { output } - /// # Summary /// Creates an array that is equal to an input array except that the last array /// element is dropped. /// @@ -892,7 +865,6 @@ 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 @@ -909,7 +881,6 @@ 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. /// @@ -954,7 +925,6 @@ function Padded<'T>(paddedLength : Int, defaultElement : 'T, inputArray : 'T[]) } } - /// # Summary /// Splits an array into multiple parts. /// /// # Input @@ -994,7 +964,6 @@ function Partitioned<'T>(partitionSizes : Int[], array : 'T[]) : 'T[][] { output } - /// # Summary /// Creates an array that is equal to an input array except that the first array /// element is dropped. /// @@ -1012,7 +981,6 @@ 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. /// @@ -1030,7 +998,6 @@ function Reversed<'T>(array : 'T[]) : 'T[] { array[...-1...] } - /// # Summary /// Get an array of integers in a given interval. /// /// # Input @@ -1061,7 +1028,6 @@ function SequenceI(from : Int, to : Int) : Int[] { array } - /// # Summary /// Get an array of integers in a given interval. /// /// # Input @@ -1095,7 +1061,6 @@ function SequenceL(from : BigInt, to : BigInt) : BigInt[] { array } - /// # Summary /// Given an array, returns the elements of that array sorted by a given /// comparison function. /// @@ -1145,7 +1110,6 @@ function Sorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : 'T[] { ) } - /// # 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[] { @@ -1167,7 +1131,6 @@ internal function SortedMerged<'T>(comparison : (('T, 'T) -> Bool), left : 'T[], 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. @@ -1205,7 +1168,6 @@ function Subarray<'T>(locations : Int[], array : 'T[]) : 'T[] { subarray } - /// # Summary /// Applies a swap of two elements in an array. /// /// # Input @@ -1232,7 +1194,6 @@ function Swapped<'T>(firstIndex : Int, secondIndex : Int, array : 'T[]) : 'T[] { w/ secondIndex <- array[firstIndex] } - /// # Summary /// Returns the transpose of a matrix represented as an array /// of arrays. /// @@ -1276,7 +1237,6 @@ function Transposed<'T>(matrix : 'T[][]) : 'T[][] { transposed } - /// # Summary /// Returns the last element of the array. /// /// # Type Parameters @@ -1295,7 +1255,6 @@ function Tail<'A>(array : 'A[]) : 'A { 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. /// @@ -1332,7 +1291,6 @@ function Unzipped<'T, 'U>(array : ('T, 'U)[]) : ('T[], 'U[]) { return (first, second); } - /// # Summary /// Given a predicate and an array, returns the indices of that /// array where the predicate is true. /// @@ -1358,7 +1316,6 @@ function Where<'T>(predicate : ('T -> Bool), array : 'T[]) : Int[] { indexes } - /// # Summary /// Returns all consecutive subarrays of length `size`. /// /// # Description @@ -1400,7 +1357,6 @@ function Windows<'T>(size : Int, array : 'T[]) : 'T[][] { windows } - /// # Summary /// Given two arrays, returns a new array of pairs such that each pair /// contains an element from each original array. /// diff --git a/library/std/src/Std/Canon.qs b/library/std/src/Std/Canon.qs new file mode 100644 index 0000000000..be7def9b1b --- /dev/null +++ b/library/std/src/Std/Canon.qs @@ -0,0 +1,588 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + + +import QIR.Intrinsic.*; +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 +/// 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, ApplyCNOTChain, ApplyP, ApplyPauli, ApplyPauliFromBitString, ApplyPauliFromInt, ApplyControlledOnInt, ApplyControlledOnBitString, ApplyQFT, SwapReverseRegister, ApplyXorInPlace, ApplyXorInPlaceL; + diff --git a/library/std/src/Std/Convert.qs b/library/std/src/Std/Convert.qs index 19a0ed6c7a..46ab3a3715 100644 --- a/library/std/src/Std/Convert.qs +++ b/library/std/src/Std/Convert.qs @@ -21,13 +21,11 @@ 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`. /// @@ -41,7 +39,6 @@ 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`. /// @@ -55,7 +52,6 @@ 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. /// @@ -76,7 +72,6 @@ function BoolArrayAsInt(bits : Bool[]) : Int { number } - /// # Summary /// Produces a binary representation of a non-negative integer, using the /// little-endian representation for the returned array. /// @@ -106,7 +101,6 @@ function IntAsBoolArray(number : Int, bits : Int) : Bool[] { result } - /// # Summary /// Converts an array of Boolean values into a non-negative BigInt, interpreting the /// array as a binary representation in little-endian format. /// @@ -132,7 +126,6 @@ function BoolArrayAsBigInt(boolArray : Bool[]) : BigInt { result } - /// # Summary /// Produces a binary representation of a non-negative BigInt, using the /// little-endian representation for the returned array. /// @@ -162,7 +155,6 @@ function BigIntAsBoolArray(number : BigInt, bits : Int) : Bool[] { result } - /// # Summary /// Produces a non-negative integer from a string of Results in little-endian format. /// /// # Input @@ -191,7 +183,6 @@ function ResultArrayAsInt(results : Result[]) : Int { number } - /// # Summary /// Converts a `Result[]` type to a `Bool[]` type, where `One` /// is mapped to `true` and `Zero` is mapped to `false`. /// @@ -210,7 +201,6 @@ function ResultArrayAsBoolArray(input : Result[]) : Bool[] { output } - /// # Summary /// Converts a `Bool[]` type to a `Result[]` type, where `true` /// is mapped to `One` and `false` is mapped to `Zero`. /// @@ -229,7 +219,6 @@ function BoolArrayAsResultArray(input : Bool[]) : Result[] { output } - /// # Summary /// Converts a complex number of type `Complex` to a complex /// number of type `ComplexPolar`. /// @@ -243,7 +232,6 @@ 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`. /// @@ -260,7 +248,6 @@ function ComplexPolarAsComplex(input : ComplexPolar) : Complex { ); } - /// # Summary /// Converts a given double-precision floating-point number to a string representation with desired precision, rounding if required. /// /// # Input diff --git a/library/std/src/Std/Diagnostics.qs b/library/std/src/Std/Diagnostics.qs index c250b29b48..127d05b4f2 100644 --- a/library/std/src/Std/Diagnostics.qs +++ b/library/std/src/Std/Diagnostics.qs @@ -29,7 +29,6 @@ function DumpMachine() : Unit { body intrinsic; } - /// # Summary /// Dumps the current target machine's status associated with the given qubits. /// /// # Input @@ -65,7 +64,6 @@ function DumpRegister(register : Qubit[]) : Unit { body intrinsic; } - /// # Summary /// Checks whether a qubit is in the |0⟩ state, returning true if it is. /// /// # Description @@ -87,7 +85,6 @@ 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 @@ -115,7 +112,6 @@ operation CheckAllZero(qubits : Qubit[]) : Bool { return true; } - /// # Summary /// Checks whether a given condition is true, failing with a message if it is not. /// /// # Description @@ -133,7 +129,6 @@ function Fact(actual : Bool, message : String) : Unit { } } - /// # Summary /// Given two operations, checks that they act identically for all input states. /// /// # Description @@ -190,7 +185,6 @@ operation CheckOperationsAreEqual( areEqual } - /// # Summary /// Starts counting the number of times the given operation is called. Fails if the operation is already being counted. /// /// # Description @@ -227,7 +221,6 @@ 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. /// @@ -245,7 +238,6 @@ 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 @@ -273,7 +265,6 @@ 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. /// @@ -291,7 +282,6 @@ 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 @@ -314,7 +304,6 @@ 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 diff --git a/library/std/src/Std/Intrinsic.qs b/library/std/src/Std/Intrinsic.qs index f7c8f01f7a..2e177663c9 100644 --- a/library/std/src/Std/Intrinsic.qs +++ b/library/std/src/Std/Intrinsic.qs @@ -36,7 +36,6 @@ operation AND(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj } } - /// # 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. /// @@ -55,7 +54,6 @@ 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 @@ -81,7 +79,6 @@ operation CCNOT(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Ad adjoint self; } - /// # Summary /// Applies the controlled-NOT (CNOT) gate to a pair of qubits. /// /// # Input @@ -119,7 +116,6 @@ operation CNOT(control : Qubit, target : Qubit) : Unit is Adj + Ctl { adjoint self; } - /// # Summary /// Applies the exponential of a multi-qubit Pauli operator. /// /// # Input @@ -183,7 +179,6 @@ operation Exp(paulis : Pauli[], theta : Double, qubits : Qubit[]) : Unit is Adj } } - /// # Summary /// Applies the Hadamard transformation to a single qubit. /// /// # Input @@ -228,7 +223,6 @@ operation H(qubit : Qubit) : Unit is Adj + Ctl { adjoint self; } - /// # Summary /// Performs the identity operation (no-op) on a single qubit. /// /// # Remarks @@ -239,7 +233,6 @@ operation I(target : Qubit) : Unit is Adj + Ctl { adjoint self; } - /// # Summary /// Performs a measurement of a single qubit in the /// Pauli _Z_ basis. /// @@ -270,7 +263,6 @@ operation M(qubit : Qubit) : Result { __quantum__qis__m__body(qubit) } - /// # Summary /// Performs a measurement of a single qubit in the /// Pauli _Z_ basis. /// @@ -301,7 +293,6 @@ operation M(qubit : Qubit) : Result { Measure([PauliZ], [qubit]) } - /// # Summary /// Performs a joint measurement of one or more qubits in the /// specified Pauli bases. /// @@ -350,7 +341,6 @@ operation Measure(bases : Pauli[], qubits : Qubit[]) : Result { } } - /// # Summary /// Performs a joint measurement of one or more qubits in the /// specified Pauli bases. /// @@ -394,7 +384,6 @@ operation Measure(bases : Pauli[], qubits : Qubit[]) : Result { __quantum__qis__mresetz__body(aux) } - /// # Summary /// Applies a rotation about the given Pauli axis. /// /// # Input @@ -430,7 +419,6 @@ operation R(pauli : Pauli, theta : Double, qubit : Qubit) : Unit is Adj + Ctl { } } - /// # Summary /// Applies a rotation about the |1⟩ state by a given angle. /// /// # Input @@ -457,7 +445,6 @@ operation R1(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { R(PauliI, -theta, qubit); } - /// # Summary /// Applies a rotation about the |1⟩ state by an angle specified /// as a dyadic fraction. /// @@ -493,7 +480,6 @@ operation R1Frac(numerator : Int, power : Int, qubit : Qubit) : Unit is Adj + Ct 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. /// @@ -504,7 +490,6 @@ 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. /// @@ -517,7 +502,6 @@ operation ResetAll(qubits : Qubit[]) : Unit { } } - /// # Summary /// Applies a rotation about the given Pauli axis by an angle specified /// as a dyadic fraction. /// @@ -558,7 +542,6 @@ operation RFrac(pauli : Pauli, numerator : Int, power : Int, qubit : Qubit) : Un R(pauli, angle, qubit); } - /// # Summary /// Applies a rotation about the _x_-axis by a given angle. /// /// # Input @@ -603,7 +586,6 @@ operation Rx(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { } } - /// # Summary /// Applies the two qubit Ising _XX_ rotation gate. /// /// # Input @@ -650,7 +632,6 @@ operation Rxx(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ct } } - /// # Summary /// Applies a rotation about the _y_-axis by a given angle. /// /// # Input @@ -695,7 +676,6 @@ operation Ry(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { } } - /// # Summary /// Applies the two qubit Ising _YY_ rotation gate. /// /// # Input @@ -742,7 +722,6 @@ operation Ryy(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ct } } - /// # Summary /// Applies a rotation about the _z_-axis by a given angle. /// /// # Input @@ -791,7 +770,6 @@ operation Rz(theta : Double, qubit : Qubit) : Unit is Adj + Ctl { } } - /// # Summary /// Applies the two qubit Ising _ZZ_ rotation gate. /// /// # Input @@ -838,7 +816,6 @@ operation Rzz(theta : Double, qubit0 : Qubit, qubit1 : Qubit) : Unit is Adj + Ct } } - /// # Summary /// Applies the π/4 phase gate to a single qubit. /// /// # Input @@ -904,7 +881,6 @@ operation S(qubit : Qubit) : Unit is Adj + Ctl { } } - /// # Summary /// Applies the SWAP gate to a pair of qubits. /// /// # Input @@ -952,7 +928,6 @@ operation SWAP(qubit1 : Qubit, qubit2 : Qubit) : Unit is Adj + Ctl { } } - /// # Summary /// Applies the π/8 gate to a single qubit. /// /// # Input @@ -1008,7 +983,6 @@ operation T(qubit : Qubit) : Unit is Adj + Ctl { } } - /// # Summary /// Applies the Pauli _X_ gate. /// /// # Input @@ -1052,7 +1026,6 @@ operation X(qubit : Qubit) : Unit is Adj + Ctl { adjoint self; } - /// # Summary /// Applies the Pauli _Y_ gate. /// /// # Input @@ -1096,7 +1069,6 @@ operation Y(qubit : Qubit) : Unit is Adj + Ctl { adjoint self; } - /// # Summary /// Applies the Pauli _Z_ gate. /// /// # Input @@ -1140,7 +1112,6 @@ operation Z(qubit : Qubit) : Unit is Adj + Ctl { adjoint self; } - /// # Summary /// Logs a message. /// /// # Input diff --git a/library/std/src/Std/Math.qs b/library/std/src/Std/Math.qs index 52079e74fa..d046f91908 100644 --- a/library/std/src/Std/Math.qs +++ b/library/std/src/Std/Math.qs @@ -27,7 +27,6 @@ function PI() : Double { 3.14159265358979323846 } - /// # Summary /// Returns a double-precision approximation of the /// mathematical constant 𝒆 ≈ 2.7182818284590452354 /// @@ -44,7 +43,6 @@ function E() : Double { 2.7182818284590452354 } - /// # Summary /// Returns a double-precision approximation of the constant /// ㏑2 ≈ 0.6931471805599453 /// @@ -75,7 +73,6 @@ function IsNaN(d : Double) : Bool { return d != d; } - /// # Summary /// Returns whether a given floating-point value is either positive or /// negative infinity. /// @@ -124,7 +121,6 @@ function SignI(a : Int) : Int { } } - /// # Summary /// Returns -1, 0 or +1 that indicates the sign of a number. function SignD(a : Double) : Int { if (a < 0.0) { @@ -136,7 +132,6 @@ function SignD(a : Double) : Int { } } - /// # Summary /// Returns -1, 0 or +1 that indicates the sign of a number. function SignL(a : BigInt) : Int { if (a < 0L) { @@ -148,60 +143,50 @@ function SignL(a : BigInt) : Int { } } - /// # 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 @@ -222,7 +207,6 @@ function Max(values : Int[]) : Int { max } - /// # Summary /// Given an array of integers, returns the smallest element. /// /// # Input @@ -253,74 +237,62 @@ 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 @@ -336,19 +308,16 @@ 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) @@ -370,7 +339,6 @@ internal function ExtendedTruncation(value : Double) : (Int, Double, Bool) { (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 { @@ -382,7 +350,6 @@ function Ceiling(value : Double) : Int { } } - /// # 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 { @@ -394,7 +361,6 @@ function Floor(value : Double) : Int { } } - /// # Summary /// Returns the nearest integer to the specified number. /// For example: Round(3.7) = 4; Round(-3.7) = -4 function Round(value : Double) : Int { @@ -417,13 +383,11 @@ 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 { @@ -432,7 +396,6 @@ function ModulusI(value : Int, modulus : Int) : Int { (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 { @@ -441,7 +404,6 @@ function ModulusL(value : BigInt, modulus : BigInt) : BigInt { (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 { @@ -472,7 +434,6 @@ function ExpModI(expBase : Int, power : Int, modulus : Int) : Int { 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 { @@ -503,7 +464,6 @@ function ExpModL(expBase : BigInt, power : BigInt, modulus : BigInt) : BigInt { res } - /// # Summary /// Returns the multiplicative inverse of a modular integer. /// /// # Description @@ -516,7 +476,6 @@ function InverseModI(a : Int, modulus : Int) : Int { ModulusI(u, modulus) } - /// # Summary /// Returns the multiplicative inverse of a modular integer. /// /// # Description @@ -547,7 +506,6 @@ function GreatestCommonDivisorI(a : Int, b : Int) : Int { 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 { @@ -561,7 +519,6 @@ function GreatestCommonDivisorL(a : BigInt, b : BigInt) : BigInt { 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) { @@ -581,7 +538,6 @@ function ExtendedGreatestCommonDivisorI(a : Int, b : Int) : (Int, Int) { (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) { @@ -601,7 +557,6 @@ function ExtendedGreatestCommonDivisorL(a : BigInt, b : BigInt) : (BigInt, BigIn (s1 * signA, t1 * signB) } - /// # Summary /// Returns if two integers are co-prime. /// /// # Description @@ -620,7 +575,6 @@ function IsCoprimeI(a : Int, b : Int) : Bool { GreatestCommonDivisorI(a, b) == 1 } - /// # Summary /// Returns if two integers are co-prime. /// /// # Description @@ -639,7 +593,6 @@ 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 @@ -670,7 +623,6 @@ function ContinuedFractionConvergentI( } } - /// # 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 @@ -701,7 +653,6 @@ function ContinuedFractionConvergentL( } } - /// # Summary /// Computes the modulus between two real numbers. /// /// # Input @@ -745,7 +696,6 @@ function BitSizeI(a : Int) : Int { 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 { @@ -760,7 +710,6 @@ function BitSizeL(a : BigInt) : Int { 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 { @@ -776,7 +725,6 @@ function TrailingZeroCountI(a : Int) : Int { 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 { @@ -792,7 +740,6 @@ function TrailingZeroCountL(a : BigInt) : Int { 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); @@ -853,7 +800,6 @@ function FactorialI(n : Int) : Int { ][n] } - /// # Summary /// Returns the factorial of a given number. /// /// # Input @@ -876,7 +822,6 @@ function FactorialL(n : Int) : BigInt { result } - /// # Summary /// Returns an approximate factorial of a given number. /// /// # Description @@ -914,7 +859,6 @@ function ApproximateFactorial(n : Int) : Double { a * b * c } - /// # Summary /// Returns the natural logarithm of the gamma function (aka the log-gamma /// function). /// @@ -966,7 +910,6 @@ function LogGammaD(x : Double) : Double { Log(2.506628274631000 * acc / x) + ((x + 0.5) * Log(tmp) - tmp) } - /// # Summary /// Returns the approximate natural logarithm of the factorial of a given /// integer. /// @@ -985,7 +928,6 @@ function LogFactorialD(n : Int) : Double { LogGammaD(IntAsDouble(n) + 1.0) } - /// # Summary /// Returns the approximate binomial coefficient of two integers. /// /// # Description @@ -1035,7 +977,6 @@ function SquaredNorm(array : Double[]) : Double { 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 @@ -1060,7 +1001,6 @@ function PNorm(p : Double, array : Double[]) : Double { 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 @@ -1106,7 +1046,6 @@ function PNormalized(p : Double, array : Double[]) : Double[] { /// ``` 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𝑖). /// @@ -1117,7 +1056,6 @@ struct Complex { Real : Double, Imag : Double } /// The phase t ∈ ℝ of c. struct ComplexPolar { Magnitude : Double, Argument : Double } - /// # Summary /// Returns the squared absolute value of a complex number of type /// `Complex`. /// @@ -1131,7 +1069,6 @@ 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`. /// @@ -1145,7 +1082,6 @@ function AbsComplex(input : Complex) : Double { Sqrt(AbsSquaredComplex(input)) } - /// # Summary /// Returns the phase of a complex number of type /// `Complex`. /// @@ -1159,7 +1095,6 @@ function ArgComplex(input : Complex) : Double { ArcTan2(input.Imag, input.Real) } - /// # Summary /// Returns the squared absolute value of a complex number of type /// `ComplexPolar`. /// @@ -1173,7 +1108,6 @@ function AbsSquaredComplexPolar(input : ComplexPolar) : Double { input.Magnitude * input.Magnitude } - /// # Summary /// Returns the absolute value of a complex number of type /// `ComplexPolar`. /// @@ -1185,7 +1119,6 @@ function AbsSquaredComplexPolar(input : ComplexPolar) : Double { /// Absolute value |c| = r. function AbsComplexPolar(input : ComplexPolar) : Double { input.Magnitude } - /// # Summary /// Returns the phase of a complex number of type `ComplexPolar`. /// /// # Input @@ -1196,7 +1129,6 @@ function AbsComplexPolar(input : ComplexPolar) : Double { input.Magnitude } /// Phase Arg(c) = t. function ArgComplexPolar(input : ComplexPolar) : Double { input.Argument } - /// # Summary /// Returns the unary negation of an input of type `Complex`. /// /// # Input @@ -1209,7 +1141,6 @@ function NegationC(input : Complex) : Complex { Complex(-input.Real, -input.Imag) } - /// # Summary /// Returns the unary negation of an input of type `ComplexPolar` /// /// # Input @@ -1222,7 +1153,6 @@ function NegationCP(input : ComplexPolar) : ComplexPolar { ComplexPolar(input.Magnitude, input.Argument + PI()) } - /// # Summary /// Returns the sum of two inputs of type `Complex`. /// /// # Input @@ -1237,7 +1167,6 @@ 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 @@ -1257,7 +1186,6 @@ function PlusCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { ) } - /// # Summary /// Returns the difference between two inputs of type `Complex`. /// /// # Input @@ -1272,7 +1200,6 @@ 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 @@ -1287,7 +1214,6 @@ function MinusCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { PlusCP(a, NegationCP(b)) } - /// # Summary /// Returns the product of two inputs of type `Complex`. /// /// # Input @@ -1305,7 +1231,6 @@ function TimesC(a : Complex, b : Complex) : Complex { ) } - /// # Summary /// Returns the product of two inputs of type `ComplexPolar`. /// /// # Input @@ -1323,7 +1248,6 @@ function TimesCP(a : ComplexPolar, b : ComplexPolar) : ComplexPolar { ) } - /// # 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. @@ -1350,7 +1274,6 @@ internal function PowCAsCP(base : Complex, power : Complex) : ComplexPolar { 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. /// @@ -1366,7 +1289,6 @@ 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. /// @@ -1382,7 +1304,6 @@ function PowCP(a : ComplexPolar, power : ComplexPolar) : ComplexPolar { PowCAsCP(ComplexPolarAsComplex(a), ComplexPolarAsComplex(power)) } - /// # Summary /// Returns the quotient of two inputs of type `Complex`. /// /// # Input @@ -1401,7 +1322,6 @@ function DividedByC(a : Complex, b : Complex) : Complex { ) } - /// # Summary /// Returns the quotient of two inputs of type `ComplexPolar`. /// /// # Input @@ -1435,7 +1355,6 @@ function SmallestFixedPoint(integerBits : Int, fractionalBits : Int) : Double { -(2.0^IntAsDouble(integerBits - 1)) } - /// # Summary /// Returns the largest representable number for specific fixed point dimensions. /// /// # Input diff --git a/library/std/src/Std/Measurement.qs b/library/std/src/Std/Measurement.qs index 81009c68a6..a37580b552 100644 --- a/library/std/src/Std/Measurement.qs +++ b/library/std/src/Std/Measurement.qs @@ -29,7 +29,6 @@ operation MeasureAllZ(register : Qubit[]) : Result { Measure(Repeated(PauliZ, Length(register)), register) } - /// # Summary /// Measures each qubit in a given array in the standard basis. /// /// # Description @@ -64,7 +63,6 @@ operation MeasureEachZ(register : Qubit[]) : Result[] { results } - /// # Summary /// Measures each qubit in a given array in the Z basis /// and resets them to a fixed initial state. /// @@ -85,7 +83,6 @@ operation MResetEachZ(register : Qubit[]) : Result[] { results } - /// # Summary /// Measures a single qubit in the X basis, /// and resets it to a fixed initial state /// following the measurement. @@ -108,7 +105,6 @@ operation MResetX(target : Qubit) : Result { MResetZ(target) } - /// # Summary /// Measures a single qubit in the Y basis, /// and resets it to a fixed initial state /// following the measurement. @@ -133,7 +129,6 @@ operation MResetY(target : Qubit) : Result { MResetZ(target) } - /// # Summary /// Measures a single qubit in the Z basis, /// and resets it to a fixed initial state /// following the measurement. @@ -153,7 +148,6 @@ 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`. diff --git a/library/std/src/Std/Random.qs b/library/std/src/Std/Random.qs index 7709d6d2e1..e1007dbe5d 100644 --- a/library/std/src/Std/Random.qs +++ b/library/std/src/Std/Random.qs @@ -27,7 +27,6 @@ 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`. /// @@ -51,7 +50,6 @@ 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. /// diff --git a/library/std/src/Std/ResourceEstimation.qs b/library/std/src/Std/ResourceEstimation.qs index a834565d66..6dfd5540fd 100644 --- a/library/std/src/Std/ResourceEstimation.qs +++ b/library/std/src/Std/ResourceEstimation.qs @@ -15,7 +15,6 @@ 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. @@ -37,7 +36,6 @@ 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. @@ -58,42 +56,36 @@ 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. @@ -101,7 +93,6 @@ 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. @@ -126,7 +117,6 @@ internal operation AccountForEstimatesInternal(estimates : (Int, Int)[], layout 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 @@ -148,7 +138,6 @@ internal operation BeginRepeatEstimatesInternal(count : Int) : Unit { body intrinsic; } - /// # Summary /// Companion operation to `BeginRepeatEstimates`. operation EndRepeatEstimates() : Unit { body ... { @@ -161,7 +150,6 @@ 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 diff --git a/library/std/src/Std/Unstable/Arithmetic.qs b/library/std/src/Std/Unstable/Arithmetic.qs deleted file mode 100644 index 8cd6f370b3..0000000000 --- a/library/std/src/Std/Unstable/Arithmetic.qs +++ /dev/null @@ -1,702 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - - -import Std.Arrays.*; -import QIR.Intrinsic.*; -open Microsoft.Quantum.Diagnostics; -open Microsoft.Quantum.Math; -open Microsoft.Quantum.Convert; -import Std.Unstable.ArithmeticHelpers.*; - -/// # Summary -/// This applies the in-place majority operation to 3 qubits. -/// -/// # Description -/// Assuming the state of the input qubits are |x⟩, |y⟩ and |z⟩, then -/// this operation performs the following transformation: -/// |x⟩|y⟩|z⟩ ↦ |x ⊕ z⟩|y ⊕ z⟩MAJ(x, y, z). -/// -/// # Input -/// ## x -/// The first input qubit. -/// ## y -/// The second input qubit. -/// ## z -/// A qubit onto which the majority function will be applied. -operation MAJ(x : Qubit, y : Qubit, z : Qubit) : Unit is Adj + Ctl { - CNOT(z, y); - CNOT(z, x); - CCNOT(y, x, z); -} - - /// # Summary -/// Reflects a quantum register about a given classical integer. -/// -/// # Description -/// Given a quantum register initially in the state ∑ᵢ(αᵢ|i⟩), -/// where each |i⟩ is a basis state representing an integer i, -/// reflects the state of the register about the basis state |j⟩ -/// for a given integer j: ∑ᵢ(-1)^(δᵢⱼ)(αᵢ|i⟩) -/// This operation is implemented in-place, without explicit allocation of -/// additional auxiliary qubits. -/// -/// # Input -/// ## index -/// The classical integer j indexing the basis state about which to reflect. -/// ## reg -/// Little-endian quantum register to reflect. -operation ReflectAboutInteger(index : Int, reg : Qubit[]) : Unit is Adj + Ctl { - within { - // Evaluation optimization for case index == 0 - if index == 0 { - ApplyToEachA(X, reg); - } else { - // We want to reduce to the problem of reflecting about the all-ones - // state. To do that, we apply our reflection within an application - // of X instructions that flip all the zeros in our index. - ApplyPauliFromInt(PauliX, false, index, reg); - } - } apply { - Controlled ApplyAsSinglyControlled(Most(reg), (Z, Tail(reg))); - } -} - -// -// Add, Increment | Operation | Description -// ____________________|________________|_______________________________________________________________ -// y += 5 | IncByI, IncByL | Increment LE register in-place by integer -// y += x | IncByLE | Increment LE register in-place by LE register -// z = x + 5 (z was 0) | | Add integer to LE register creating result out-of-place -// z = x + y (z was 0) | AddLE | Add two LE register creating result out-of-place -// z += x + 5 | | Increment LE register by the sum of integer and LE register -// z += x + y | | Increment LE register by the sum of two LE registers -// -// IncByLE implementations: -// RippleCarryTTKIncByLE (default) -// RippleCarryCGIncByLE -// FourierTDIncByLE -// via IncByLEUsingAddLE and any out-of-place addition -// IncByI implementations: -// via IncByIUsingIncByLE and any in-place LE adder -// IncByL implementations: -// via IncByLUsingIncByLE and any in-place LE adder -// AddLE implementations: -// RippleCarryCGAddLE (default) -// LookAheadDKRSAddLE -// - -/// # Summary -/// Increments a little-endian register ys by an integer number c -/// -/// # Description -/// Computes ys += c modulo 2ⁿ, where ys is a little-endian register, -/// Length(ys) = n > 0, c is a Int number, 0 ≤ c < 2ⁿ. -/// NOTE: Use IncByIUsingIncByLE directly if the choice of implementation -/// is important. -operation IncByI(c : Int, ys : Qubit[]) : Unit is Adj + Ctl { - IncByIUsingIncByLE(RippleCarryTTKIncByLE, c, ys); -} - - /// # Summary -/// Increments a little-endian register ys by a BigInt number c -/// -/// # Description -/// Computes ys += c modulo 2ⁿ, where ys is a little-endian register, -/// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. -/// NOTE: Use IncByLUsingIncByLE directly if the choice of implementation -/// is important. -operation IncByL(c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { - IncByLUsingIncByLE(RippleCarryTTKIncByLE, c, ys); -} - - /// # Summary -/// Increments a little-endian register ys by a little-endian register xs -/// -/// # Description -/// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, -/// and Length(xs) ≤ Length(ys) = n. -/// NOTE: Use operations like RippleCarryCGIncByLE directly if -/// the choice of implementation is important. -operation IncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - RippleCarryTTKIncByLE(xs, ys); -} - - /// # Summary -/// Sets a zero-initialized little-endian register zs to the sum of -/// little-endian registers xs and ys -/// -/// # Description -/// Computes zs := xs + ys modulo 2ⁿ, where xs, ys, and zs are little-endian registers, -/// Length(xs) = Length(ys) ≤ Length(zs) = n, assuming zs is 0-initialized. -/// NOTE: Use operations like RippleCarryCGAddLE directly if -/// the choice of implementation is important. -operation AddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { - RippleCarryCGAddLE(xs, ys, zs); -} - - /// # Summary -/// Reversible, in-place ripple-carry addition of two integers. -/// -/// # Description -/// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, -/// and Length(xs) ≤ Length(ys) = n. -/// This operation uses the ripple-carry algorithm. -/// Note that if Length(ys) >= Length(xs)+2, xs is padded with 0-initialized -/// qubits to match ys's length. The operation doesn't use any auxiliary -/// qubits otherwise. -/// -/// # References -/// - [arXiv:0910.2530](https://arxiv.org/abs/0910.2530) -/// "Quantum Addition Circuits and Unbounded Fan-Out", -/// Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro -operation RippleCarryTTKIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - let xsLen = Length(xs); - let ysLen = Length(ys); - - Fact(ysLen >= xsLen, "Register `ys` must be longer than register `xs`."); - Fact(xsLen >= 1, "Registers `xs` and `ys` must contain at least one qubit."); - - if xsLen == ysLen { - if xsLen > 1 { - within { - ApplyOuterTTKAdder(xs, ys); - } apply { - ApplyInnerTTKAdderNoCarry(xs, ys); - } - } - CNOT(xs[0], ys[0]); - } elif xsLen + 1 == ysLen { - if xsLen > 1 { - CNOT(xs[xsLen - 1], ys[ysLen - 1]); - within { - ApplyOuterTTKAdder(xs, ys); - } apply { - ApplyInnerTTKAdderWithCarry(xs, ys); - } - } else { - CCNOT(xs[0], ys[0], ys[1]); - } - CNOT(xs[0], ys[0]); - } elif xsLen + 2 <= ysLen { - // Pad xs so that its length is one qubit shorter than ys. - use padding = Qubit[ysLen - xsLen - 1]; - RippleCarryTTKIncByLE(xs + padding, ys); - } -} - - /// # Summary -/// Increments a little-endian register ys by a little-endian register xs -/// using the ripple-carry algorithm. -/// -/// # Description -/// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, -/// and Length(xs) ≤ Length(ys) = n. -/// Note that if Length(xs) != Length(ys), xs is padded with 0-initialized -/// qubits to match ys's length. -/// This operation uses the ripple-carry algorithm. -/// -/// # Reference -/// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) -/// "Halving the cost of quantum addition", Craig Gidney. -operation RippleCarryCGIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - let xsLen = Length(xs); - let ysLen = Length(ys); - - Fact(ysLen >= xsLen, "Register `ys` must be longer than register `xs`."); - Fact(xsLen >= 1, "Registers `xs` and `ys` must contain at least one qubit."); - - if ysLen - xsLen >= 2 { - // Pad xs so that its length is one qubit shorter than ys. - use padding = Qubit[ysLen - xsLen - 1]; - RippleCarryCGIncByLE(xs + padding, ys); - } elif xsLen == 1 { - if ysLen == 1 { - CNOT(xs[0], ys[0]); - } elif ysLen == 2 { - HalfAdderForInc(xs[0], ys[0], ys[1]); - } - } else { - use carries = Qubit[xsLen]; - within { - ApplyAndAssuming0Target(xs[0], ys[0], carries[0]); - } apply { - for i in 1..xsLen - 2 { - CarryForInc(carries[i - 1], xs[i], ys[i], carries[i]); - } - if xsLen == ysLen { - within { - CNOT(carries[xsLen - 2], xs[xsLen - 1]); - } apply { - CNOT(xs[xsLen - 1], ys[xsLen - 1]); - } - } else { - FullAdderForInc(carries[xsLen - 2], xs[xsLen - 1], ys[xsLen - 1], ys[xsLen]); - } - for i in xsLen - 2..-1..1 { - UncarryForInc(carries[i - 1], xs[i], ys[i], carries[i]); - } - } - CNOT(xs[0], ys[0]); - } -} - - /// # Summary -/// Sets a zero-initialized little-endian register zs to the sum of -/// little-endian registers xs and ys using the ripple-carry algorithm. -/// -/// # Description -/// Computes zs := xs + ys + zs[0] modulo 2ⁿ, where xs, ys, and zs are -/// little-endian registers, Length(xs) = Length(ys) ≤ Length(zs) = n, -/// assuming zs is 0-initialized, except for maybe zs[0], which can be -// in |0> or |1> state and can be used as carry-in. -/// This operation uses the ripple-carry algorithm. -/// NOTE: `zs[Length(xs)]` can be used as carry-out, if `zs` is longer than `xs`. -/// -/// # Reference -/// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) -/// "Halving the cost of quantum addition", Craig Gidney. -operation RippleCarryCGAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { - let xsLen = Length(xs); - let zsLen = Length(zs); - Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); - Fact(zsLen >= xsLen, "Register `zs` must be no shorter than register `xs`."); - - // Since zs is zero-initialized, its bits at indexes higher than - // xsLen remain unused as there will be no carry into them. - let top = MinI(zsLen - 2, xsLen - 1); - for k in 0..top { - FullAdder(zs[k], xs[k], ys[k], zs[k + 1]); - } - - if xsLen > 0 and xsLen == zsLen { - CNOT(Tail(xs), Tail(zs)); - CNOT(Tail(ys), Tail(zs)); - } -} - - /// # Summary -/// Sets a zero-initialized little-endian register zs to the sum of -/// little-endian registers xs and ys using the carry-lookahead algorithm. -/// -/// # Description -/// Computes zs := xs + ys + zs[0] modulo 2ⁿ, where xs, ys, and zs are -/// little-endian registers, Length(xs) = Length(ys) ≤ Length(zs) = n, -/// assuming zs is 0-initialized, except for maybe zs[0], which can be -/// in |0> or |1> state and can be used as carry-in. -/// NOTE: `zs[Length(xs)]` can be used as carry-out, if `zs` is longer than `xs`. -/// This operation uses the carry-lookahead algorithm. -/// -/// # Reference -/// - [arXiv:quant-ph/0406142](https://arxiv.org/abs/quant-ph/0406142) -/// "A logarithmic-depth quantum carry-lookahead adder", -/// Thomas G. Draper, Samuel A. Kutin, Eric M. Rains, Krysta M. Svore -operation LookAheadDKRSAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { - let xsLen = Length(xs); - let zsLen = Length(zs); - Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); - Fact(zsLen >= xsLen, "Register `zs` must be no shorter than register `xs`."); - - if zsLen > xsLen { - // with carry-out - // compute initial generate values - for k in 0..xsLen - 1 { - ApplyAndAssuming0Target(xs[k], ys[k], zs[k + 1]); - } - - within { - // compute initial propagate values - for i in IndexRange(xs) { - CNOT(xs[i], ys[i]); - } - } apply { - if xsLen > 1 { - ComputeCarries(Rest(ys), zs[1..xsLen]); - } - - // compute sum into carries - for k in 0..xsLen - 1 { - CNOT(ys[k], zs[k]); - } - } - } else { - // xsLen == zsLen, so without carry-out - LookAheadDKRSAddLE(Most(xs), Most(ys), zs); - CNOT(Tail(xs), Tail(zs)); - CNOT(Tail(ys), Tail(zs)); - } -} - - /// # Summary -/// Increments a little-endian register ys by a little-endian register xs -/// using Quantum Fourier Transform. -/// -/// # Description -/// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, -/// and Length(xs) = Length(ys) = n. -/// This operation uses Quantum Fourier Transform. -/// -/// # Reference -/// - [arXiv:quant-ph/0008033](https://arxiv.org/abs/quant-ph/0008033) -/// "Addition on a Quantum Computer", Thomas G. Draper -operation FourierTDIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - within { - ApplyQFT(ys); - } apply { - for i in IndexRange(xs) { - Controlled PhaseGradient([xs[i]], ys[i...]); - } - } -} - - /// # Summary -/// Increments a little-endian register ys by a BigInt number c -/// using provided adder. -/// -/// # Description -/// Computes ys += c modulo 2ⁿ, where ys is a little-endian register -/// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. -operation IncByLUsingIncByLE( - adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, - c : BigInt, - ys : Qubit[] -) : Unit is Adj + Ctl { - - let ysLen = Length(ys); - Fact(ysLen > 0, "Length of `ys` must be at least 1."); - Fact(c >= 0L, "Constant `c` must be non-negative."); - Fact(c < 2L^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); - - if c != 0L { - // If c has j trailing zeros, then the j least significant - // bits of y won't be affected by the addition and can - // therefore be ignored by applying the addition only to - // the other qubits and shifting c accordingly. - let j = TrailingZeroCountL(c); - use x = Qubit[ysLen - j]; - within { - ApplyXorInPlaceL(c >>> j, x); - } apply { - adder(x, ys[j...]); - } - } -} - - /// # Summary -/// Increments a little-endian register ys by an Int number c -/// using provided adder. -/// -/// # Description -/// Computes ys += c modulo 2ⁿ, where ys is a little-endian register -/// Length(ys) = n > 0, c is an Int number, 0 ≤ c < 2ⁿ. -operation IncByIUsingIncByLE( - adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, - c : Int, - ys : Qubit[] -) : Unit is Adj + Ctl { - - let ysLen = Length(ys); - Fact(ysLen > 0, "Length of `ys` must be at least 1."); - Fact(c >= 0, "Constant `c` must be non-negative."); - Fact(c < 2^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); - - if c != 0 { - // If c has j trailing zeros than the j least significant - // bits of y won't be affected by the addition and can - // therefore be ignored by applying the addition only to - // the other qubits and shifting c accordingly. - let j = TrailingZeroCountI(c); - use x = Qubit[ysLen - j]; - within { - ApplyXorInPlace(c >>> j, x); - } apply { - adder(x, ys[j...]); - } - } -} - - /// # Summary -/// Generic operation to turn two out-place adders into one in-place adder -/// -/// # Description -/// This implementation allows to specify two distinct adders for forward -/// and backward direction. The forward adder is always applied in its -/// body variant, whereas the backward adder is always applied in its adjoint -/// variant. Therefore, it's possible to, for example, use the ripple-carry -/// out-of-place adder in backwards direction to require no T gates. -/// -/// The controlled variant is also optimized in a way that everything but -/// the adders is controlled, -/// -/// # Reference -/// - [arXiv:2012.01624](https://arxiv.org/abs/2012.01624) -/// "Quantum block lookahead adders and the wait for magic states", -/// Craig Gidney. -operation IncByLEUsingAddLE( - forwardAdder : (Qubit[], Qubit[], Qubit[]) => Unit is Adj, - backwardAdder : (Qubit[], Qubit[], Qubit[]) => Unit is Adj, - xs : Qubit[], - ys : Qubit[] -) : Unit is Adj + Ctl { - - body (...) { - let n = Length(xs); - - Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - - use qs = Qubit[n]; - - forwardAdder(xs, ys, qs); - for i in IndexRange(ys) { - SWAP(ys[i], qs[i]); - } - ApplyToEachA(X, qs); - within { - ApplyToEachA(X, ys); - } apply { - Adjoint backwardAdder(xs, ys, qs); - } - } - adjoint (...) { - let n = Length(xs); - - Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - - use qs = Qubit[n]; - - within { - ApplyToEachA(X, ys); - } apply { - forwardAdder(xs, ys, qs); - } - ApplyToEachA(X, qs); - for i in IndexRange(ys) { - SWAP(ys[i], qs[i]); - } - Adjoint backwardAdder(xs, ys, qs); - } - controlled (ctls, ...) { - // When we control everything except the adders, the adders will - // cancel themselves. - let n = Length(xs); - - Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - - use qs = Qubit[n]; - - forwardAdder(xs, ys, qs); - for i in IndexRange(ys) { - Controlled SWAP(ctls, (ys[i], qs[i])) - } - ApplyToEachA(tgt => Controlled X(ctls, tgt), qs); - within { - ApplyToEachA(tgt => Controlled X(ctls, tgt), ys); - } apply { - Adjoint backwardAdder(xs, ys, qs); - } - } - controlled adjoint (ctls, ...) { - // When we control everything except the adders, the adders will - // cancel themselves. - let n = Length(xs); - - Fact(Length(ys) == n, "Registers xs and ys must be of same length"); - - use qs = Qubit[n]; - - within { - ApplyToEachA(tgt => Controlled X(ctls, tgt), ys); - } apply { - forwardAdder(xs, ys, qs); - } - ApplyToEachA(tgt => Controlled X(ctls, tgt), qs); - for i in IndexRange(ys) { - Controlled SWAP(ctls, (ys[i], qs[i])) - } - Adjoint backwardAdder(xs, ys, qs); - } -} - -// -// Comparisons -// -// Compare BigInt and qubit register in a little-endian format and apply action -// if c < x { action(target) } | ApplyIfLessL -// if c <= x { action(target) } | ApplyIfLessOrEqualL -// if c == x { action(target) } | ApplyIfEqualL -// if c >= x { action(target) } | ApplyIfGreaterOrEqualL -// if c > x { action(target) } | ApplyIfGreaterL -// -// Compare two qubit registers in a little-endian format and apply action -// if x < y { action(target) } | ApplyIfLessLE -// if x <= y { action(target) } | ApplyIfLessOrEqualLE -// if x == y { action(target) } | ApplyIfEqualLE -// if x >= y { action(target) } | ApplyIfGreaterOrEqualLE -// if x > y { action(target) } | ApplyIfGreaterLE -// - -/// # Summary -/// Computes `if (c < x) { action(target) }`, that is, applies `action` to `target` -/// if a BigInt value `c` is less than the little-endian qubit register `x` -operation ApplyIfLessL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - ApplyActionIfGreaterThanOrEqualConstant(false, action, c + 1L, x, target); -} - - /// # Summary -/// Computes `if (c <= x) { action(target) }`, that is, applies `action` to `target` -/// if a BigInt value `c` is less or equal to the little-endian qubit register `x` -operation ApplyIfLessOrEqualL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - ApplyActionIfGreaterThanOrEqualConstant(false, action, c, x, target); -} - - /// # Summary -/// Computes `if (c == x) { action(target) }`, that is, applies `action` to `target` -/// if a BigInt value `c` is equal to the little-endian qubit register `x` -operation ApplyIfEqualL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - xs : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - let cBitSize = BitSizeL(c); - let xLen = Length(xs); - if (cBitSize <= xLen) { - let bits = BigIntAsBoolArray(c, Length(xs)); - within { - ApplyPauliFromBitString(PauliX, false, bits, xs); - } apply { - Controlled ApplyAsSinglyControlled(xs, (a => action(a), target)); - } - } -} - - /// # Summary -/// Computes `if (c >= x) { action(target) }`, that is, applies `action` to `target` -/// if a BigInt value `c` is greater or equal to the little-endian qubit register `x` -operation ApplyIfGreaterOrEqualL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - ApplyActionIfGreaterThanOrEqualConstant(true, action, c + 1L, x, target); -} - - /// # Summary -/// Computes `if (c > x) { action(target) }`, that is, applies `action` to `target` -/// if a BigInt value `c` is greater than the little-endian qubit register `x` -operation ApplyIfGreaterL<'T>( - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - ApplyActionIfGreaterThanOrEqualConstant(true, action, c, x, target); -} - - /// # Summary -/// Computes `if x < y { action(target) }`, that is, applies `action` to `target` -/// if register `x` is less than the register `y`. -/// Both qubit registers should be in a little-endian format. -operation ApplyIfLessLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - ApplyIfGreaterLE(action, y, x, target); -} - - /// # Summary -/// Computes `if x <= y { action(target) }`, that is, applies `action` to `target` -/// if register `x` is less or equal to the register `y`. -/// Both qubit registers should be in a little-endian format. -operation ApplyIfLessOrEqualLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - Fact(Length(x) > 0, "Bitwidth must be at least 1"); - within { - ApplyToEachA(X, x); - } apply { - // control is not inverted - ApplyActionIfSumOverflows(action, x, y, false, target); - } -} - - /// # Summary -/// Computes `if x == y { action(target) }`, that is, applies `action` to `target` -/// if register `x` is equal to the register `y`. -/// Both qubit registers should be in a little-endian format. -operation ApplyIfEqualLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - Fact(Length(x) == Length(y), "x and y must be of same length"); - within { - for i in IndexRange(x) { - CNOT(x[i], y[i]); - X(y[i]); - } - } apply { - Controlled ApplyAsSinglyControlled(y, (a => action(a), target)) - } -} - - /// # Summary -/// Computes `if x >= y { action(target) }`, that is, applies `action` to `target` -/// if register `x` is greater or equal to the register `y`. -/// Both qubit registers should be in a little-endian format. -operation ApplyIfGreaterOrEqualLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - ApplyIfLessOrEqualLE(action, y, x, target); -} - - /// # Summary -/// Computes `if x > y { action(target) }`, that is, applies `action` to `target` -/// if register `x` is greater than the register `y`. -/// Both qubit registers should be in a little-endian format. -operation ApplyIfGreaterLE<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - Fact(Length(x) > 0, "Bitwidth must be at least 1"); - within { - ApplyToEachA(X, x); - } apply { - // control is inverted - ApplyActionIfSumOverflows(action, x, y, true, target); - } -} - -export AddLE, ApplyIfEqualLE, ApplyIfEqualL, ApplyIfGreaterLE, ApplyIfGreaterL, ApplyIfGreaterOrEqualLE, ApplyIfGreaterOrEqualL, ApplyIfLessLE, ApplyIfLessL, ApplyIfLessOrEqualLE, ApplyIfLessOrEqualL, IncByI, IncByIUsingIncByLE, IncByL, IncByLUsingIncByLE, IncByLE, IncByLEUsingAddLE, LookAheadDKRSAddLE, MAJ, ReflectAboutInteger, RippleCarryCGAddLE, RippleCarryCGIncByLE, RippleCarryTTKIncByLE, FourierTDIncByLE; diff --git a/library/std/src/Std/Unstable/ArithmeticHelpers.qs b/library/std/src/Std/Unstable/ArithmeticHelpers.qs deleted file mode 100644 index bb28c85c4f..0000000000 --- a/library/std/src/Std/Unstable/ArithmeticHelpers.qs +++ /dev/null @@ -1,586 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - - -open Microsoft.Quantum.Diagnostics; -import Std.Arrays.*; -open Microsoft.Quantum.Math; -open Microsoft.Quantum.Convert; -import QIR.Intrinsic.*; - - -/// # Summary -/// Implements the outer operation for RippleCarryTTKIncByLE to conjugate -/// the inner operation to construct the full adder. Only Length(xs) -/// qubits are processed. -/// -/// # Input -/// ## xs -/// Qubit register in a little-endian format containing the first summand -/// input to RippleCarryTTKIncByLE. -/// ## ys -/// Qubit register in a little-endian format containing the second summand -/// input to RippleCarryTTKIncByLE. -/// -/// # References -/// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum -/// Addition Circuits and Unbounded Fan-Out", Quantum Information and -/// Computation, Vol. 10, 2010. -/// https://arxiv.org/abs/0910.2530 -internal operation ApplyOuterTTKAdder(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - Fact(Length(xs) <= Length(ys), "Input register ys must be at lease as long as xs."); - for i in 1..Length(xs) - 1 { - CNOT(xs[i], ys[i]); - } - for i in Length(xs) - 2..-1..1 { - CNOT(xs[i], xs[i + 1]); - } -} - - /// # Summary -/// Implements the inner addition function for the operation -/// RippleCarryTTKIncByLE. This is the inner operation that is conjugated -/// with the outer operation to construct the full adder. -/// -/// # Input -/// ## xs -/// Qubit register in a little-endian format containing the first summand -/// input to RippleCarryTTKIncByLE. -/// ## ys -/// Qubit register in a little-endian format containing the second summand -/// input to RippleCarryTTKIncByLE. -/// -/// # References -/// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum -/// Addition Circuits and Unbounded Fan-Out", Quantum Information and -/// Computation, Vol. 10, 2010. -/// https://arxiv.org/abs/0910.2530 -/// -/// # Remarks -/// The specified controlled operation makes use of symmetry and mutual -/// cancellation of operations to improve on the default implementation -/// that adds a control to every operation. -internal operation ApplyInnerTTKAdderNoCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - body (...) { - (Controlled ApplyInnerTTKAdderNoCarry)([], (xs, ys)); - } - controlled (controls, ...) { - Fact(Length(xs) == Length(ys), "Input registers must have the same number of qubits."); - - for idx in 0..Length(xs) - 2 { - CCNOT(xs[idx], ys[idx], xs[idx + 1]); - } - for idx in Length(xs) - 1..-1..1 { - Controlled CNOT(controls, (xs[idx], ys[idx])); - CCNOT(xs[idx - 1], ys[idx - 1], xs[idx]); - } - } -} - - /// # Summary -/// Implements the inner addition function for the operation -/// RippleCarryTTKIncByLE. This is the inner operation that is conjugated -/// with the outer operation to construct the full adder. -/// -/// # Input -/// ## xs -/// Qubit register in a little-endian format containing the first summand -/// input to RippleCarryTTKIncByLE. -/// ## ys -/// Qubit register in a little-endian format containing the second summand -/// input to RippleCarryTTKIncByLE. -/// -/// # References -/// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum -/// Addition Circuits and Unbounded Fan-Out", Quantum Information and -/// Computation, Vol. 10, 2010. -/// https://arxiv.org/abs/0910.2530 -/// -/// # Remarks -/// The specified controlled operation makes use of symmetry and mutual -/// cancellation of operations to improve on the default implementation -/// that adds a control to every operation. -internal operation ApplyInnerTTKAdderWithCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { - body (...) { - (Controlled ApplyInnerTTKAdderWithCarry)([], (xs, ys)); - } - controlled (controls, ...) { - Fact(Length(xs) + 1 == Length(ys), "ys must be one qubit longer then xs."); - Fact(Length(xs) > 0, "Array should not be empty."); - - - let nQubits = Length(xs); - for idx in 0..nQubits - 2 { - CCNOT(xs[idx], ys[idx], xs[idx + 1]); - } - (Controlled CCNOT)(controls, (xs[nQubits - 1], ys[nQubits - 1], ys[nQubits])); - for idx in nQubits - 1..-1..1 { - Controlled CNOT(controls, (xs[idx], ys[idx])); - CCNOT(xs[idx - 1], ys[idx - 1], xs[idx]); - } - } -} - - /// # Summary -/// Implements Half-adder. Adds qubit x to qubit y and sets carryOut appropriately -internal operation HalfAdderForInc(x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { - body (...) { - CCNOT(x, y, carryOut); - CNOT(x, y); - } - adjoint auto; - - controlled (ctls, ...) { - Fact(Length(ctls) == 1, "HalfAdderForInc should be controlled by exactly one control qubit."); - - let ctl = ctls[0]; - use helper = Qubit(); - - within { - ApplyAndAssuming0Target(x, y, helper); - } apply { - ApplyAndAssuming0Target(ctl, helper, carryOut); - } - CCNOT(ctl, x, y); - } - controlled adjoint auto; -} - - /// # Summary -/// Implements Full-adder. Adds qubit carryIn and x to qubit y and sets carryOut appropriately. -internal operation FullAdderForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { - body (...) { - // TODO: cannot use `Carry` operation here - CNOT(carryIn, x); - CNOT(carryIn, y); - CCNOT(x, y, carryOut); - CNOT(carryIn, carryOut); - CNOT(carryIn, x); - CNOT(x, y); - } - adjoint auto; - - controlled (ctls, ...) { - Fact(Length(ctls) == 1, "FullAdderForInc should be controlled by exactly one control qubit."); - - let ctl = ctls[0]; - use helper = Qubit(); - - CarryForInc(carryIn, x, y, helper); - CCNOT(ctl, helper, carryOut); - Controlled UncarryForInc(ctls, (carryIn, x, y, helper)); - } - controlled adjoint auto; -} - -// Computes carryOut := carryIn + x + y -internal operation FullAdder(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj { - CNOT(x, y); - CNOT(x, carryIn); - ApplyAndAssuming0Target(y, carryIn, carryOut); - CNOT(x, y); - CNOT(x, carryOut); - CNOT(y, carryIn); -} - - /// # Summary -/// Computes carry bit for a full adder. -internal operation CarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { - body (...) { - CNOT(carryIn, x); - CNOT(carryIn, y); - ApplyAndAssuming0Target(x, y, carryOut); - CNOT(carryIn, carryOut); - } - adjoint auto; - controlled (ctls, ...) { - // This CarryForInc is intended to be used only in an in-place - // ripple-carry implementation. Only such particular use case allows - // for this simple implementation where controlled version - // is the same as uncontrolled body. - CarryForInc(carryIn, x, y, carryOut); - } - controlled adjoint auto; -} - - /// # Summary -/// Uncomputes carry bit for a full adder. -internal operation UncarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { - body (...) { - CNOT(carryIn, carryOut); - Adjoint ApplyAndAssuming0Target(x, y, carryOut); - CNOT(carryIn, x); - CNOT(x, y); - } - adjoint auto; - controlled (ctls, ...) { - Fact(Length(ctls) == 1, "UncarryForInc should be controlled by exactly one control qubit."); - - let ctl = ctls[0]; - - CNOT(carryIn, carryOut); - Adjoint ApplyAndAssuming0Target(x, y, carryOut); - CCNOT(ctl, x, y); // Controlled X(ctls + [x], y); - CNOT(carryIn, x); - CNOT(carryIn, y); - } - controlled adjoint auto; -} - - /// # Summary -/// Applies AND gate between `control1` and `control2` and stores the result -/// in `target` assuming `target` is in |0> state. -/// -/// # Description -/// Inverts `target` if and only if both controls are 1, but assumes that -/// `target` is in state 0. The operation has T-count 4, T-depth 2 and -/// requires no helper qubit, and may therefore be preferable to a CCNOT -/// operation, if `target` is known to be 0. -/// The adjoint of this operation is measurement based and requires no T -/// gates (but requires target to support branching on measurements). -/// Although the Toffoli gate (CCNOT) will perform faster in simulations, -/// this version has lower T gate requirements. -/// # References -/// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", -/// Phys. Rev. A 87, 022328, 2013 -/// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) -/// doi:10.1103/PhysRevA.87.022328 -@Config(Adaptive) -internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - // NOTE: Eventually this operation will be public and intrinsic. - body (...) { - CCNOT(control1, control2, target); - } - adjoint (...) { - H(target); - if M(target) == One { - Reset(target); - CZ(control1, control2); - } - } -} - -internal operation ApplyOrAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - within { - X(control1); - X(control2); - } apply { - ApplyAndAssuming0Target(control1, control2, target); - X(target); - } -} - - /// # Summary -/// Applies AND gate between `control1` and `control2` and stores the result -/// in `target` assuming `target` is in |0> state. -/// -/// # Description -/// Inverts `target` if and only if both controls are 1, but assumes that -/// `target` is in state 0. The operation has T-count 4, T-depth 2 and -/// requires no helper qubit, and may therefore be preferable to a CCNOT -/// operation, if `target` is known to be 0. -/// This version is suitable for Base profile. -/// Although the Toffoli gate (CCNOT) will perform faster in simulations, -/// this version has lower T gate requirements. -/// # References -/// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", -/// Phys. Rev. A 87, 022328, 2013 -/// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) -/// doi:10.1103/PhysRevA.87.022328 -@Config(not Adaptive) -internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { - H(target); - T(target); - CNOT(control1, target); - CNOT(control2, target); - within { - CNOT(target, control1); - CNOT(target, control2); - } apply { - Adjoint T(control1); - Adjoint T(control2); - T(target); - } - H(target); - S(target); -} - - /// # Summary -/// Computes carries for the look-ahead adder -internal operation ComputeCarries(ps : Qubit[], gs : Qubit[]) : Unit is Adj { - let n = Length(gs); - Fact(Length(ps) + 1 == n, "Register gs must be one qubit longer than register gs."); - - let T = Floor(Lg(IntAsDouble(n))); - use qs = Qubit[n - HammingWeightI(n) - T]; - - let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1, 1..T - 1); - let pWorkspace = [ps] + Partitioned(registerPartition, qs); - - within { - PRounds(pWorkspace); - } apply { - // U_G - GRounds(pWorkspace, gs); - - // U_C - CRounds(pWorkspace, gs); - } -} - - /// # Summary -/// Computes all p[i, j] values in workspace for the look-ahead adder. -/// -/// The register array `pWorkspace` has T entries, where T = ⌊log₂ n⌋. -/// -/// The first entry `pWorkspace[0]` is initialized with `P_0` which is -/// computed before `ComputeCarries` is called. The other registers are -/// 0-initialized and will be computed in successive rounds t = 1, ..., T - 1. -/// -/// In each round t we compute -/// -/// p[i, j] = p[2ᵗ × m, 2ᵗ × (m + 1)] = p[i, k] ∧ p[k, j] -/// -/// in `pWorkspace[t][m - 1]` and use that for k = 2ᵗ × m + 2ᵗ⁻¹, p[i, k] and p[k, j] -/// have already been computed in round t - 1 in `pWorkspace[t - 1][2 * m - 1]` and -/// `pWorkspace[t - 1][2 * m]`, respectively. -internal operation PRounds(pWorkspace : Qubit[][]) : Unit is Adj { - for ws in Windows(2, pWorkspace) { - // note that we are using Rest, since pWorkspace[t - 1][0] is never - // accessed in round t. - let (current, next) = (Rest(ws[0]), ws[1]); - - for m in IndexRange(next) { - ApplyAndAssuming0Target(current[2 * m], current[2 * m + 1], next[m]); - } - } -} - - /// # Summary -/// Computes g[i ∧ (i + 1), i + 1] into gs[i] for the look-ahead adder. -/// -/// The register gs has n entries initialized to gs[i] = g[i, i + 1]. -/// -/// After successive rounds t = 1, ..., T, the register is updated to -/// gs[i] = g[i ∧ (i + 1), i + 1], from which we can compute the carries -/// in the C-rounds. -internal operation GRounds(pWorkspace : Qubit[][], gs : Qubit[]) : Unit is Adj { - let T = Length(pWorkspace); - let n = Length(gs); - - for t in 1..T { - let length = Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1; - let ps = pWorkspace[t - 1][0..2...]; - - for m in 0..length { - CCNOT(gs[2^t * m + 2^(t - 1) - 1], ps[m], gs[2^t * m + 2^t - 1]); - } - } -} - - /// # Summary -/// Computes carries into gs for the look-ahead adder. -internal operation CRounds(pWorkspace : Qubit[][], gs : Qubit[]) : Unit is Adj { - let n = Length(gs); - - let start = Floor(Lg(IntAsDouble(2 * n) / 3.0)); - for t in start..-1..1 { - let length = Floor(IntAsDouble(n - 2^(t - 1)) / IntAsDouble(2^t)); - let ps = pWorkspace[t - 1][1..2...]; - - for m in 1..length { - CCNOT(gs[2^t * m - 1], ps[m - 1], gs[2^t * m + 2^(t - 1) - 1]); - } - } -} - -internal operation PhaseGradient(qs : Qubit[]) : Unit is Adj + Ctl { - for i in IndexRange(qs) { - R1Frac(1, i, qs[i]); - } -} - -// -// Internal operations for comparisons -// - -/// # Summary -/// Applies `action` to `target` if register `x` is greater or equal to BigInt `c` -/// (if `invertControl` is false). If `invertControl` is true, the `action` -/// is applied in the opposite situation. -internal operation ApplyActionIfGreaterThanOrEqualConstant<'T>( - invertControl : Bool, - action : 'T => Unit is Adj + Ctl, - c : BigInt, - x : Qubit[], - target : 'T -) : Unit is Adj + Ctl { - - let bitWidth = Length(x); - if c == 0L { - if not invertControl { - action(target); - } - } elif c >= (2L^bitWidth) { - if invertControl { - action(target); - } - } else { - // normalize constant - let l = TrailingZeroCountL(c); - - let cNormalized = c >>> l; - let xNormalized = x[l...]; - let bitWidthNormalized = Length(xNormalized); - - // If c == 2L^(bitwidth - 1), then bitWidthNormalized will be 1, - // and qs will be empty. In that case, we do not need to compute - // any temporary values, and some optimizations are apply, which - // are considered in the remainder. - use qs = Qubit[bitWidthNormalized - 1]; - let cs1 = IsEmpty(qs) ? [] | [Head(xNormalized)] + Most(qs); - - Fact(Length(cs1) == Length(qs), "Arrays should be of the same length."); - - within { - for i in 0..Length(cs1) - 1 { - let op = cNormalized &&& (1L <<< (i + 1)) != 0L ? ApplyAndAssuming0Target | ApplyOrAssuming0Target; - op(cs1[i], xNormalized[i + 1], qs[i]); - } - } apply { - let control = IsEmpty(qs) ? Tail(x) | Tail(qs); - within { - if invertControl { - X(control); - } - } apply { - Controlled action([control], target); - } - } - } -} - - /// # Summary -/// Applies `action` to `target` if the sum of `x` and `y` registers -/// overflows, i.e. there's a carry out (if `invertControl` is false). -/// If `invertControl` is true, the `action` is applied when there's no carry out. -internal operation ApplyActionIfSumOverflows<'T>( - action : 'T => Unit is Adj + Ctl, - x : Qubit[], - y : Qubit[], - invertControl : Bool, - target : 'T -) : Unit is Adj + Ctl { - - let n = Length(x); - Fact(n >= 1, "Registers must contain at least one qubit."); - Fact(Length(y) == n, "Registers must be of the same length."); - - use carries = Qubit[n]; - - within { - CarryWith1CarryIn(x[0], y[0], carries[0]); - for i in 1..n - 1 { - CarryForInc(carries[i - 1], x[i], y[i], carries[i]); - } - } apply { - within { - if invertControl { - X(carries[n - 1]); - } - } apply { - Controlled action([carries[n - 1]], target); - } - } -} - - /// # Summary -/// Computes carry out assuming carry in is 1. -/// Simplified version that is only applicable for scenarios -/// where controlled version is the same as non-controlled. -internal operation CarryWith1CarryIn( - x : Qubit, - y : Qubit, - carryOut : Qubit -) : Unit is Adj + Ctl { - - body (...) { - X(x); - X(y); - ApplyAndAssuming0Target(x, y, carryOut); - X(carryOut); - } - - adjoint auto; - - controlled (ctls, ...) { - Fact(Length(ctls) <= 1, "Number of control lines must be at most 1"); - CarryWith1CarryIn(x, y, carryOut); - } - - controlled adjoint auto; -} - - /// # Summary -/// This wrapper allows operations that support only one control -/// qubit to be used in a multi-controlled scenarios. It provides -/// controlled version that collects controls into one qubit -/// by applying AND chain using auxiliary qubit array. -internal operation ApplyAsSinglyControlled<'TIn>( - op : ('TIn => Unit is Adj + Ctl), - input : 'TIn -) : Unit is Adj + Ctl { - - body (...) { - op(input); - } - - controlled (ctls, ...) { - let n = Length(ctls); - if n == 0 { - op(input); - } elif n == 1 { - Controlled op(ctls, input); - } else { - use aux = Qubit[n - 1]; - within { - LogDepthAndChain(ctls, aux); - } apply { - Controlled op([Tail(aux)], input); - } - } - } -} - - /// # Summary -/// This helper function computes the AND of all control bits in `ctls` into -/// the last qubit of `tgts`, using the other qubits in `tgts` as helper -/// qubits for the AND of subsets of control bits. The operation has a -/// logarithmic depth of AND gates by aligning them using a balanced binary -/// tree. -internal operation LogDepthAndChain(ctls : Qubit[], tgts : Qubit[]) : Unit is Adj { - let lc = Length(ctls); - let lt = Length(tgts); - - Fact(lc == lt + 1, $"There must be exactly one more control qubit than target qubits (got {lc}, {lt})"); - - if lt == 1 { - ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]); - } elif lt == 2 { - ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]); - ApplyAndAssuming0Target(ctls[2], tgts[0], tgts[1]); - } else { - let left = lc / 2; - let right = lc - left; - - let ctlsLeft = ctls[...left - 1]; - let tgtsLeft = tgts[...left - 2]; - - let ctlsRight = ctls[left..left + right - 1]; - let tgtsRight = tgts[left - 1..left + right - 3]; - - LogDepthAndChain(ctlsLeft, tgtsLeft); - LogDepthAndChain(ctlsRight, tgtsRight); - ApplyAndAssuming0Target(Tail(tgtsLeft), Tail(tgtsRight), Tail(tgts)); - } -} diff --git a/library/std/src/Std/Unstable/StatePreparation.qs b/library/std/src/Std/Unstable/StatePreparation.qs deleted file mode 100644 index 1d3cb742ef..0000000000 --- a/library/std/src/Std/Unstable/StatePreparation.qs +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - - -open Microsoft.Quantum.Convert; -open Microsoft.Quantum.Diagnostics; -import Std.Arrays.*; -open Microsoft.Quantum.Math; -import QIR.Intrinsic.*; -import Std.Unstable.ArithmeticHelpers.*; - - -/// # Summary -/// Given a set of coefficients and a big-endian quantum register, -/// prepares a state on that register described by the given coefficients. -/// -/// # Description -/// This operation prepares an arbitrary quantum -/// state |𝜓⟩ with coefficients 𝑎ⱼ from -/// the n-qubit computational basis state |0...0⟩. -/// -/// The action of U on the all-zeros state is given by -/// $$ -/// \begin{align} -/// U \ket{0\cdots 0} = \ket{\psi} = \frac{\sum_{j=0}^{2^n-1}\alpha_j \ket{j}}{\sqrt{\sum_{j=0}^{2^n-1}|\alpha_j|^2}}. -/// \end{align} -/// $$ -/// -/// # Input -/// ## coefficients -/// Array of up to 2ⁿ real coefficients. The j-th coefficient -/// indexes the number state |j⟩ encoded in big-endian format. -/// -/// ## qubits -/// Qubit register encoding number states in a big-endian format. This is -/// expected to be initialized in the computational basis state |0...0⟩. -/// -/// # Remarks -/// `coefficients` will be normalized and padded with -/// elements 𝑎ⱼ = 0.0 if fewer than 2ⁿ are specified. -/// -/// # Example -/// The following snippet prepares the quantum state |𝜓⟩=√(1/8)|0⟩+√(7/8)|2⟩=√(1/8)|00⟩+√(7/8)|10⟩ -/// in the qubit register `qubits`. -/// ```qsharp -/// let amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0]; -/// use qubits = Qubit[2]; -/// PreparePureStateD(amplitudes, qubits); -/// ``` -/// -/// # References -/// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) -/// "Synthesis of Quantum Logic Circuits", -/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov -/// -/// # See Also -/// - Microsoft.Quantum.Unstable.StatePreparation.ApproximatelyPreparePureStateCP -operation PreparePureStateD(coefficients : Double[], qubits : Qubit[]) : Unit is Adj + Ctl { - let coefficientsAsComplexPolar = Mapped(a -> ComplexAsComplexPolar(Complex(a, 0.0)), coefficients); - ApproximatelyPreparePureStateCP(0.0, coefficientsAsComplexPolar, qubits); -} - - /// # Summary -/// Given a set of coefficients and a big-endian quantum register, -/// prepares a state on that register described by the given coefficients, -/// up to a given approximation tolerance. -/// -/// # Description -/// This operation prepares an arbitrary quantum -/// state |𝜓⟩ with complex coefficients rⱼ·𝒆^(𝒊·tⱼ) from -/// the n-qubit computational basis state |0...0⟩. -/// In particular, the action of this operation can be simulated by the -/// a unitary transformation U which acts on the all-zeros state as -/// -/// $$ -/// \begin{align} -/// U\ket{0...0} -/// & = \ket{\psi} \\\\ -/// & = \frac{ -/// \sum_{j=0}^{2^n-1} r_j e^{i t_j} \ket{j} -/// }{ -/// \sqrt{\sum_{j=0}^{2^n-1} |r_j|^2} -/// }. -/// \end{align} -/// $$ -/// -/// # Input -/// ## tolerance -/// The approximation tolerance to be used when preparing the given state. -/// -/// ## coefficients -/// Array of up to 2ⁿ complex coefficients represented by their -/// absolute value and phase (rⱼ, tⱼ). The j-th coefficient -/// indexes the number state |j⟩ encoded in a big-endian format. -/// -/// ## qubits -/// Qubit register encoding number states in a big-endian format. This is -/// expected to be initialized in the computational basis state -/// |0...0⟩. -/// -/// # Remarks -/// `coefficients` will be padded with -/// elements (rⱼ, tⱼ) = (0.0, 0.0) if fewer than 2ⁿ are -/// specified. -/// -/// # References -/// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) -/// "Synthesis of Quantum Logic Circuits", -/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov -operation ApproximatelyPreparePureStateCP( - tolerance : Double, - coefficients : ComplexPolar[], - qubits : Qubit[] -) : Unit is Adj + Ctl { - - let nQubits = Length(qubits); - // pad coefficients at tail length to a power of 2. - let coefficientsPadded = Padded(-2^nQubits, ComplexPolar(0.0, 0.0), coefficients); - let idxTarget = 0; - // Determine what controls to apply - let rngControl = nQubits > 1 ? (1..(nQubits - 1)) | (1..0); - // Note we use the reversed qubits array to get the endianness ordering that we expect - // when corresponding qubit state to state vector index. - Adjoint ApproximatelyUnprepareArbitraryState( - tolerance, - coefficientsPadded, - rngControl, - idxTarget, - Reversed(qubits) - ); -} - - /// # Summary -/// Implementation step of arbitrary state preparation procedure. -internal operation ApproximatelyUnprepareArbitraryState( - tolerance : Double, - coefficients : ComplexPolar[], - rngControl : Range, - idxTarget : Int, - register : Qubit[] -) : Unit is Adj + Ctl { - - // For each 2D block, compute disentangling single-qubit rotation parameters - let (disentanglingY, disentanglingZ, newCoefficients) = StatePreparationSBMComputeCoefficients(coefficients); - if (AnyOutsideToleranceD(tolerance, disentanglingZ)) { - ApproximatelyMultiplexPauli(tolerance, disentanglingZ, PauliZ, register[rngControl], register[idxTarget]); - - } - if (AnyOutsideToleranceD(tolerance, disentanglingY)) { - ApproximatelyMultiplexPauli(tolerance, disentanglingY, PauliY, register[rngControl], register[idxTarget]); - } - // target is now in |0> state up to the phase given by arg of newCoefficients. - - // Continue recursion while there are control qubits. - if (IsRangeEmpty(rngControl)) { - let (abs, arg) = (newCoefficients[0].Magnitude, newCoefficients[0].Argument); - if (AbsD(arg) > tolerance) { - Exp([PauliI], -1.0 * arg, [register[idxTarget]]); - } - } elif (Any(c -> AbsComplexPolar(c) > tolerance, newCoefficients)) { - // Some coefficients are outside tolerance - let newControl = (RangeStart(rngControl) + 1)..RangeStep(rngControl)..RangeEnd(rngControl); - let newTarget = RangeStart(rngControl); - ApproximatelyUnprepareArbitraryState(tolerance, newCoefficients, newControl, newTarget, register); - } -} - - /// # Summary -/// Applies a Pauli rotation conditioned on an array of qubits, truncating -/// small rotation angles according to a given tolerance. -/// -/// # Description -/// This applies a multiply controlled unitary operation that performs -/// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ -/// when controlled by the $n$-qubit number state $\ket{j}$. -/// In particular, the action of this operation is represented by the -/// unitary -/// -/// $$ -/// \begin{align} -/// U = \sum^{2^n - 1}_{j=0} \ket{j}\bra{j} \otimes e^{i P \theta_j}. -/// \end{align} -/// ## -/// -/// # Input -/// ## tolerance -/// A tolerance below which small coefficients are truncated. -/// -/// ## coefficients -/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient -/// indexes the number state $\ket{j}$ encoded in little-endian format. -/// -/// ## pauli -/// Pauli operator $P$ that determines axis of rotation. -/// -/// ## control -/// $n$-qubit control register that encodes number states $\ket{j}$ in -/// little-endian format. -/// -/// ## target -/// Single qubit register that is rotated by $e^{i P \theta_j}$. -/// -/// # Remarks -/// `coefficients` will be padded with elements $\theta_j = 0.0$ if -/// fewer than $2^n$ are specified. -internal operation ApproximatelyMultiplexPauli( - tolerance : Double, - coefficients : Double[], - pauli : Pauli, - control : Qubit[], - target : Qubit -) : Unit is Adj + Ctl { - - if pauli == PauliZ { - ApproximatelyMultiplexZ(tolerance, coefficients, control, target); - } elif pauli == PauliX { - within { - H(target); - } apply { - ApproximatelyMultiplexPauli(tolerance, coefficients, PauliZ, control, target); - } - } elif pauli == PauliY { - within { - Adjoint S(target); - } apply { - ApproximatelyMultiplexPauli(tolerance, coefficients, PauliX, control, target); - } - } else { - fail $"MultiplexPauli failed. Invalid pauli {pauli}."; - } -} - - /// # Summary -/// Implementation step of arbitrary state preparation procedure. -internal function StatePreparationSBMComputeCoefficients( - coefficients : ComplexPolar[] -) : (Double[], Double[], ComplexPolar[]) { - - mutable disentanglingZ = []; - mutable disentanglingY = []; - mutable newCoefficients = []; - - for idxCoeff in 0..2..Length(coefficients) - 1 { - let (rt, phi, theta) = BlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff + 1]); - set disentanglingZ += [0.5 * phi]; - set disentanglingY += [0.5 * theta]; - set newCoefficients += [rt]; - } - - return (disentanglingY, disentanglingZ, newCoefficients); -} - - /// # Summary -/// Computes the Bloch sphere coordinates for a single-qubit state. -/// -/// Given two complex numbers $a0, a1$ that represent the qubit state, computes coordinates -/// on the Bloch sphere such that -/// $a0 \ket{0} + a1 \ket{1} = r e^{it}(e^{-i \phi /2}\cos{(\theta/2)}\ket{0}+e^{i \phi /2}\sin{(\theta/2)}\ket{1})$. -/// -/// # Input -/// ## a0 -/// Complex coefficient of state $\ket{0}$. -/// ## a1 -/// Complex coefficient of state $\ket{1}$. -/// -/// # Output -/// A tuple containing `(ComplexPolar(r, t), phi, theta)`. -internal function BlochSphereCoordinates( - a0 : ComplexPolar, - a1 : ComplexPolar -) : (ComplexPolar, Double, Double) { - - let abs0 = AbsComplexPolar(a0); - let abs1 = AbsComplexPolar(a1); - let arg0 = ArgComplexPolar(a0); - let arg1 = ArgComplexPolar(a1); - let r = Sqrt(abs0 * abs0 + abs1 * abs1); - let t = 0.5 * (arg0 + arg1); - let phi = arg1 - arg0; - let theta = 2.0 * ArcTan2(abs1, abs0); - return (ComplexPolar(r, t), phi, theta); -} - - /// # Summary -/// Applies a Pauli Z rotation conditioned on an array of qubits, truncating -/// small rotation angles according to a given tolerance. -/// -/// # Description -/// This applies the multiply controlled unitary operation that performs -/// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ -/// when controlled by the $n$-qubit number state $\ket{j}$. -/// In particular, this operation can be represented by the unitary -/// -/// $$ -/// \begin{align} -/// U = \sum^{2^n-1}_{j=0} \ket{j}\bra{j} \otimes e^{i Z \theta_j}. -/// \end{align} -/// $$ -/// -/// # Input -/// ## tolerance -/// A tolerance below which small coefficients are truncated. -/// -/// ## coefficients -/// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient -/// indexes the number state $\ket{j}$ encoded in little-endian format. -/// -/// ## control -/// $n$-qubit control register that encodes number states $\ket{j}$ in -/// little-endian format. -/// -/// ## target -/// Single qubit register that is rotated by $e^{i P \theta_j}$. -/// -/// # Remarks -/// `coefficients` will be padded with elements $\theta_j = 0.0$ if -/// fewer than $2^n$ are specified. -/// -/// # References -/// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) -/// "Synthesis of Quantum Logic Circuits", -/// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov -internal operation ApproximatelyMultiplexZ( - tolerance : Double, - coefficients : Double[], - control : Qubit[], - target : Qubit -) : Unit is Adj + Ctl { - - body (...) { - // pad coefficients length at tail to a power of 2. - let coefficientsPadded = Padded(-2^Length(control), 0.0, coefficients); - - if Length(coefficientsPadded) == 1 { - // Termination case - if AbsD(coefficientsPadded[0]) > tolerance { - Exp([PauliZ], coefficientsPadded[0], [target]); - } - } else { - // Compute new coefficients. - let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance, coefficients0, Most(control), target); - if AnyOutsideToleranceD(tolerance, coefficients1) { - within { - CNOT(Tail(control), target); - } apply { - ApproximatelyMultiplexZ(tolerance, coefficients1, Most(control), target); - } - } - } - } - - controlled (controlRegister, ...) { - // pad coefficients length to a power of 2. - let coefficientsPadded = Padded(2^(Length(control) + 1), 0.0, Padded(-2^Length(control), 0.0, coefficients)); - let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); - ApproximatelyMultiplexZ(tolerance, coefficients0, control, target); - if AnyOutsideToleranceD(tolerance, coefficients1) { - within { - Controlled X(controlRegister, target); - } apply { - ApproximatelyMultiplexZ(tolerance, coefficients1, control, target); - } - } - } -} - - /// # Summary -/// Implementation step of multiply-controlled Z rotations. -internal function MultiplexZCoefficients(coefficients : Double[]) : (Double[], Double[]) { - let newCoefficientsLength = Length(coefficients) / 2; - mutable coefficients0 = []; - mutable coefficients1 = []; - - for idxCoeff in 0..newCoefficientsLength - 1 { - set coefficients0 += [0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength])]; - set coefficients1 += [0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength])]; - } - - return (coefficients0, coefficients1); -} - -internal function AnyOutsideToleranceD(tolerance : Double, coefficients : Double[]) : Bool { - // NOTE: This function is not used as the only recursion termination condition - // only to determine if the multiplex step needs to be applied. - // For tolerance 0.0 it is always applied due to >= comparison. - Any(coefficient -> AbsD(coefficient) >= tolerance, coefficients) -} - -export PreparePureStateD, ApproximatelyPreparePureStateCP; diff --git a/library/std/src/Std/Unstable/TableLookup.qs b/library/std/src/Std/Unstable/TableLookup.qs deleted file mode 100644 index 89a2d45da0..0000000000 --- a/library/std/src/Std/Unstable/TableLookup.qs +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - - -import Std.Arrays.*; -open Microsoft.Quantum.Convert; -open Microsoft.Quantum.Diagnostics; -open Microsoft.Quantum.Math; -open Microsoft.Quantum.ResourceEstimation; -open Microsoft.Quantum.Unstable.Arithmetic; -import Std.Unstable.ArithmeticHelpers.*; - -import QIR.Intrinsic.*; - - -/// # Summary -/// Performs table lookup using a SELECT network -/// -/// # Description -/// Assuming a zero-initialized `target` register, this operation will -/// initialize it with the bitstrings in `data` at indices according to the -/// computational values of the `address` register. -/// -/// # Input -/// ## data -/// The classical table lookup data which is prepared in `target` with -/// respect to the state in `address`. The length of data must be less than -/// 2ⁿ, where 𝑛 is the length of `address`. Each entry in data must have -/// the same length that must be equal to the length of `target`. -/// ## address -/// Address register -/// ## target -/// Zero-initialized target register -/// -/// # Remarks -/// The implementation of the SELECT network is based on unary encoding as -/// presented in [1]. The recursive implementation of that algorithm is -/// presented in [3]. The adjoint variant is optimized using a -/// measurement-based unlookup operation [3]. The controlled adjoint variant -/// is not optimized using this technique. -/// -/// # References -/// 1. [arXiv:1805.03662](https://arxiv.org/abs/1805.03662) -/// "Encoding Electronic Spectra in Quantum Circuits with Linear T -/// Complexity" -/// 2. [arXiv:1905.07682](https://arxiv.org/abs/1905.07682) -/// "Windowed arithmetic" -/// 3. [arXiv:2211.01133](https://arxiv.org/abs/2211.01133) -/// "Space-time optimized table lookup" -operation Select( - data : Bool[][], - address : Qubit[], - target : Qubit[] -) : Unit is Adj + Ctl { - body (...) { - let (N, n) = DimensionsForSelect(data, address); - - if N == 1 { - // base case - WriteMemoryContents(Head(data), target); - } else { - let (most, tail) = MostAndTail(address[...n - 1]); - let parts = Partitioned([2^(n - 1)], data); - - within { - X(tail); - } apply { - SinglyControlledSelect(tail, parts[0], most, target); - } - - SinglyControlledSelect(tail, parts[1], most, target); - } - } - adjoint (...) { - Unlookup(Select, data, address, target); - } - - controlled (ctls, ...) { - let numCtls = Length(ctls); - - if numCtls == 0 { - Select(data, address, target); - } elif numCtls == 1 { - SinglyControlledSelect(ctls[0], data, address, target); - } else { - use andChainTarget = Qubit(); - let andChain = MakeAndChain(ctls, andChainTarget); - use helper = Qubit[andChain.NGarbageQubits]; - - within { - andChain.Apply(helper); - } apply { - SinglyControlledSelect(andChainTarget, data, address, target); - } - } - } - - controlled adjoint (ctls, ...) { - Controlled Select(ctls, (data, address, target)); - } -} - -internal operation SinglyControlledSelect( - ctl : Qubit, - data : Bool[][], - address : Qubit[], - target : Qubit[] -) : Unit { - let (N, n) = DimensionsForSelect(data, address); - - if BeginEstimateCaching("Microsoft.Quantum.Unstable.TableLookup.SinglyControlledSelect", N) { - if N == 1 { - // base case - Controlled WriteMemoryContents([ctl], (Head(data), target)); - } else { - use helper = Qubit(); - - let (most, tail) = MostAndTail(address[...n - 1]); - let parts = Partitioned([2^(n - 1)], data); - - within { - X(tail); - } apply { - ApplyAndAssuming0Target(ctl, tail, helper); - } - - SinglyControlledSelect(helper, parts[0], most, target); - - CNOT(ctl, helper); - - SinglyControlledSelect(helper, parts[1], most, target); - - Adjoint ApplyAndAssuming0Target(ctl, tail, helper); - } - - EndEstimateCaching(); - } -} - -internal function DimensionsForSelect( - data : Bool[][], - address : Qubit[] -) : (Int, Int) { - let N = Length(data); - Fact(N > 0, "data cannot be empty"); - - let n = Ceiling(Lg(IntAsDouble(N))); - Fact( - Length(address) >= n, - $"address register is too small, requires at least {n} qubits" - ); - - return (N, n); -} - -internal operation WriteMemoryContents( - value : Bool[], - target : Qubit[] -) : Unit is Adj + Ctl { - Fact( - Length(value) == Length(target), - "number of data bits must equal number of target qubits" - ); - - ApplyPauliFromBitString(PauliX, true, value, target); -} - - /// # References -/// - [arXiv:1905.07682](https://arxiv.org/abs/1905.07682) -/// "Windowed arithmetic" -internal operation Unlookup( - lookup : (Bool[][], Qubit[], Qubit[]) => Unit, - data : Bool[][], - select : Qubit[], - target : Qubit[] -) : Unit { - let numBits = Length(target); - let numAddressBits = Length(select); - - let l = MinI(Floor(Lg(IntAsDouble(numBits))), numAddressBits - 1); - Fact( - l < numAddressBits, - $"l = {l} must be smaller than {numAddressBits}" - ); - - let res = Mapped(r -> r == One, ForEach(MResetX, target)); - - let dataFixup = Chunks(2^l, Padded(-2^numAddressBits, false, Mapped(MustBeFixed(res, _), data))); - - let numAddressBitsFixup = numAddressBits - l; - - let selectParts = Partitioned([l], select); - let targetFixup = target[...2^l - 1]; - - within { - EncodeUnary(selectParts[0], targetFixup); - ApplyToEachA(H, targetFixup); - } apply { - lookup(dataFixup, selectParts[1], targetFixup); - } -} - -// Checks whether specific bit string `data` must be fixed for a given -// measurement result `result`. -// -// Returns true if the number of indices for which both result and data are -// `true` is odd. -internal function MustBeFixed(result : Bool[], data : Bool[]) : Bool { - mutable state = false; - for i in IndexRange(result) { - set state = state != (result[i] and data[i]); - } - state -} - -// Computes unary encoding of value in `input` into `target` -// -// Assumptions: -// - `target` is zero-initialized -// - length of `input` is n -// - length of `target` is 2^n -internal operation EncodeUnary( - input : Qubit[], - target : Qubit[] -) : Unit is Adj { - Fact( - Length(target) == 2^Length(input), - $"target register should be of length {2^Length(input)}, but is {Length(target)}" - ); - - X(Head(target)); - - for i in IndexRange(input) { - if i == 0 { - CNOT(input[i], target[1]); - CNOT(target[1], target[0]); - } else { - // targets are the first and second 2^i qubits of the target register - let split = Partitioned([2^i, 2^i], target); - for j in IndexRange(split[0]) { - ApplyAndAssuming0Target(input[i], split[0][j], split[1][j]); - CNOT(split[1][j], split[0][j]); - } - } - } - -} - -internal newtype AndChain = ( - NGarbageQubits : Int, - Apply : Qubit[] => Unit is Adj -); - -internal function MakeAndChain(ctls : Qubit[], target : Qubit) : AndChain { - AndChain( - MaxI(Length(ctls) - 2, 0), - helper => AndChainOperation(ctls, helper, target) - ) -} - -internal operation AndChainOperation(ctls : Qubit[], helper : Qubit[], target : Qubit) : Unit is Adj { - let n = Length(ctls); - - Fact(Length(helper) == MaxI(n - 2, 0), "Invalid number of helper qubits"); - - if n == 0 { - X(target); - } elif n == 1 { - CNOT(ctls[0], target); - } else { - let ctls1 = ctls[0..0] + helper; - let ctls2 = ctls[1...]; - let tgts = helper + [target]; - - for idx in IndexRange(tgts) { - ApplyAndAssuming0Target(ctls1[idx], ctls2[idx], tgts[idx]); - } - } -} - -export Select; diff --git a/library/std/src/canon.qs b/library/std/src/canon.qs deleted file mode 100644 index a8dd54f66b..0000000000 --- a/library/std/src/canon.qs +++ /dev/null @@ -1,589 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Microsoft.Quantum.Canon { - import QIR.Intrinsic.*; - 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 - /// 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, ApplyCNOTChain, ApplyP, ApplyPauli, ApplyPauliFromBitString, ApplyPauliFromInt, ApplyControlledOnInt, ApplyControlledOnBitString, ApplyQFT, SwapReverseRegister, ApplyXorInPlace, ApplyXorInPlaceL; - -} diff --git a/library/std/src/legacy_api.qs b/library/std/src/legacy_api.qs index b4de6e7ee1..d351c868de 100644 --- a/library/std/src/legacy_api.qs +++ b/library/std/src/legacy_api.qs @@ -5,11 +5,7 @@ // 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; -} - -namespace Microsoft.Quantum.Unstable { - export Std.Unstable.Arithmetic, Std.Unstable.TableLookup, Std.Unstable.StatePreparation; + export Std.Arrays, Std.Convert, Std.Diagnostics, Std.Logical, Std.Math, Std.Measurement, Std.Intrinsic, Std.Random, Std.ResourceEstimation, Std.Canon; } namespace Std { diff --git a/library/std/src/unstable_arithmetic.qs b/library/std/src/unstable_arithmetic.qs new file mode 100644 index 0000000000..22ae84ae13 --- /dev/null +++ b/library/std/src/unstable_arithmetic.qs @@ -0,0 +1,701 @@ +// Copyright (c) Microsoft Corporation. +// 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; + + /// # Summary + /// This applies the in-place majority operation to 3 qubits. + /// + /// # Description + /// Assuming the state of the input qubits are |x⟩, |y⟩ and |z⟩, then + /// this operation performs the following transformation: + /// |x⟩|y⟩|z⟩ ↦ |x ⊕ z⟩|y ⊕ z⟩MAJ(x, y, z). + /// + /// # Input + /// ## x + /// The first input qubit. + /// ## y + /// The second input qubit. + /// ## z + /// A qubit onto which the majority function will be applied. + operation MAJ(x : Qubit, y : Qubit, z : Qubit) : Unit is Adj + Ctl { + CNOT(z, y); + CNOT(z, x); + CCNOT(y, x, z); + } + + /// # Summary + /// Reflects a quantum register about a given classical integer. + /// + /// # Description + /// Given a quantum register initially in the state ∑ᵢ(αᵢ|i⟩), + /// where each |i⟩ is a basis state representing an integer i, + /// reflects the state of the register about the basis state |j⟩ + /// for a given integer j: ∑ᵢ(-1)^(δᵢⱼ)(αᵢ|i⟩) + /// This operation is implemented in-place, without explicit allocation of + /// additional auxiliary qubits. + /// + /// # Input + /// ## index + /// The classical integer j indexing the basis state about which to reflect. + /// ## reg + /// Little-endian quantum register to reflect. + operation ReflectAboutInteger(index : Int, reg : Qubit[]) : Unit is Adj + Ctl { + within { + // Evaluation optimization for case index == 0 + if index == 0 { + ApplyToEachA(X, reg); + } else { + // We want to reduce to the problem of reflecting about the all-ones + // state. To do that, we apply our reflection within an application + // of X instructions that flip all the zeros in our index. + ApplyPauliFromInt(PauliX, false, index, reg); + } + } apply { + Controlled ApplyAsSinglyControlled(Most(reg), (Z, Tail(reg))); + } + } + + // + // Add, Increment | Operation | Description + // ____________________|________________|_______________________________________________________________ + // y += 5 | IncByI, IncByL | Increment LE register in-place by integer + // y += x | IncByLE | Increment LE register in-place by LE register + // z = x + 5 (z was 0) | | Add integer to LE register creating result out-of-place + // z = x + y (z was 0) | AddLE | Add two LE register creating result out-of-place + // z += x + 5 | | Increment LE register by the sum of integer and LE register + // z += x + y | | Increment LE register by the sum of two LE registers + // + // IncByLE implementations: + // RippleCarryTTKIncByLE (default) + // RippleCarryCGIncByLE + // FourierTDIncByLE + // via IncByLEUsingAddLE and any out-of-place addition + // IncByI implementations: + // via IncByIUsingIncByLE and any in-place LE adder + // IncByL implementations: + // via IncByLUsingIncByLE and any in-place LE adder + // AddLE implementations: + // RippleCarryCGAddLE (default) + // LookAheadDKRSAddLE + // + + /// # Summary + /// Increments a little-endian register ys by an integer number c + /// + /// # Description + /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register, + /// Length(ys) = n > 0, c is a Int number, 0 ≤ c < 2ⁿ. + /// NOTE: Use IncByIUsingIncByLE directly if the choice of implementation + /// is important. + operation IncByI(c : Int, ys : Qubit[]) : Unit is Adj + Ctl { + IncByIUsingIncByLE(RippleCarryTTKIncByLE, c, ys); + } + + /// # Summary + /// Increments a little-endian register ys by a BigInt number c + /// + /// # Description + /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register, + /// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. + /// NOTE: Use IncByLUsingIncByLE directly if the choice of implementation + /// is important. + operation IncByL(c : BigInt, ys : Qubit[]) : Unit is Adj + Ctl { + IncByLUsingIncByLE(RippleCarryTTKIncByLE, c, ys); + } + + /// # Summary + /// Increments a little-endian register ys by a little-endian register xs + /// + /// # Description + /// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, + /// and Length(xs) ≤ Length(ys) = n. + /// NOTE: Use operations like RippleCarryCGIncByLE directly if + /// the choice of implementation is important. + operation IncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + RippleCarryTTKIncByLE(xs, ys); + } + + /// # Summary + /// Sets a zero-initialized little-endian register zs to the sum of + /// little-endian registers xs and ys + /// + /// # Description + /// Computes zs := xs + ys modulo 2ⁿ, where xs, ys, and zs are little-endian registers, + /// Length(xs) = Length(ys) ≤ Length(zs) = n, assuming zs is 0-initialized. + /// NOTE: Use operations like RippleCarryCGAddLE directly if + /// the choice of implementation is important. + operation AddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + RippleCarryCGAddLE(xs, ys, zs); + } + + /// # Summary + /// Reversible, in-place ripple-carry addition of two integers. + /// + /// # Description + /// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, + /// and Length(xs) ≤ Length(ys) = n. + /// This operation uses the ripple-carry algorithm. + /// Note that if Length(ys) >= Length(xs)+2, xs is padded with 0-initialized + /// qubits to match ys's length. The operation doesn't use any auxiliary + /// qubits otherwise. + /// + /// # References + /// - [arXiv:0910.2530](https://arxiv.org/abs/0910.2530) + /// "Quantum Addition Circuits and Unbounded Fan-Out", + /// Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro + operation RippleCarryTTKIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + let xsLen = Length(xs); + let ysLen = Length(ys); + + Fact(ysLen >= xsLen, "Register `ys` must be longer than register `xs`."); + Fact(xsLen >= 1, "Registers `xs` and `ys` must contain at least one qubit."); + + if xsLen == ysLen { + if xsLen > 1 { + within { + ApplyOuterTTKAdder(xs, ys); + } apply { + ApplyInnerTTKAdderNoCarry(xs, ys); + } + } + CNOT(xs[0], ys[0]); + } elif xsLen + 1 == ysLen { + if xsLen > 1 { + CNOT(xs[xsLen - 1], ys[ysLen - 1]); + within { + ApplyOuterTTKAdder(xs, ys); + } apply { + ApplyInnerTTKAdderWithCarry(xs, ys); + } + } else { + CCNOT(xs[0], ys[0], ys[1]); + } + CNOT(xs[0], ys[0]); + } elif xsLen + 2 <= ysLen { + // Pad xs so that its length is one qubit shorter than ys. + use padding = Qubit[ysLen - xsLen - 1]; + RippleCarryTTKIncByLE(xs + padding, ys); + } + } + + /// # Summary + /// Increments a little-endian register ys by a little-endian register xs + /// using the ripple-carry algorithm. + /// + /// # Description + /// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, + /// and Length(xs) ≤ Length(ys) = n. + /// Note that if Length(xs) != Length(ys), xs is padded with 0-initialized + /// qubits to match ys's length. + /// This operation uses the ripple-carry algorithm. + /// + /// # Reference + /// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) + /// "Halving the cost of quantum addition", Craig Gidney. + operation RippleCarryCGIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + let xsLen = Length(xs); + let ysLen = Length(ys); + + Fact(ysLen >= xsLen, "Register `ys` must be longer than register `xs`."); + Fact(xsLen >= 1, "Registers `xs` and `ys` must contain at least one qubit."); + + if ysLen - xsLen >= 2 { + // Pad xs so that its length is one qubit shorter than ys. + use padding = Qubit[ysLen - xsLen - 1]; + RippleCarryCGIncByLE(xs + padding, ys); + } elif xsLen == 1 { + if ysLen == 1 { + CNOT(xs[0], ys[0]); + } elif ysLen == 2 { + HalfAdderForInc(xs[0], ys[0], ys[1]); + } + } else { + use carries = Qubit[xsLen]; + within { + ApplyAndAssuming0Target(xs[0], ys[0], carries[0]); + } apply { + for i in 1..xsLen - 2 { + CarryForInc(carries[i - 1], xs[i], ys[i], carries[i]); + } + if xsLen == ysLen { + within { + CNOT(carries[xsLen - 2], xs[xsLen - 1]); + } apply { + CNOT(xs[xsLen - 1], ys[xsLen - 1]); + } + } else { + FullAdderForInc(carries[xsLen - 2], xs[xsLen - 1], ys[xsLen - 1], ys[xsLen]); + } + for i in xsLen - 2..-1..1 { + UncarryForInc(carries[i - 1], xs[i], ys[i], carries[i]); + } + } + CNOT(xs[0], ys[0]); + } + } + + /// # Summary + /// Sets a zero-initialized little-endian register zs to the sum of + /// little-endian registers xs and ys using the ripple-carry algorithm. + /// + /// # Description + /// Computes zs := xs + ys + zs[0] modulo 2ⁿ, where xs, ys, and zs are + /// little-endian registers, Length(xs) = Length(ys) ≤ Length(zs) = n, + /// assuming zs is 0-initialized, except for maybe zs[0], which can be + // in |0> or |1> state and can be used as carry-in. + /// This operation uses the ripple-carry algorithm. + /// NOTE: `zs[Length(xs)]` can be used as carry-out, if `zs` is longer than `xs`. + /// + /// # Reference + /// - [arXiv:1709.06648](https://arxiv.org/pdf/1709.06648.pdf) + /// "Halving the cost of quantum addition", Craig Gidney. + operation RippleCarryCGAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + let xsLen = Length(xs); + let zsLen = Length(zs); + Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); + Fact(zsLen >= xsLen, "Register `zs` must be no shorter than register `xs`."); + + // Since zs is zero-initialized, its bits at indexes higher than + // xsLen remain unused as there will be no carry into them. + let top = MinI(zsLen - 2, xsLen - 1); + for k in 0..top { + FullAdder(zs[k], xs[k], ys[k], zs[k + 1]); + } + + if xsLen > 0 and xsLen == zsLen { + CNOT(Tail(xs), Tail(zs)); + CNOT(Tail(ys), Tail(zs)); + } + } + + /// # Summary + /// Sets a zero-initialized little-endian register zs to the sum of + /// little-endian registers xs and ys using the carry-lookahead algorithm. + /// + /// # Description + /// Computes zs := xs + ys + zs[0] modulo 2ⁿ, where xs, ys, and zs are + /// little-endian registers, Length(xs) = Length(ys) ≤ Length(zs) = n, + /// assuming zs is 0-initialized, except for maybe zs[0], which can be + /// in |0> or |1> state and can be used as carry-in. + /// NOTE: `zs[Length(xs)]` can be used as carry-out, if `zs` is longer than `xs`. + /// This operation uses the carry-lookahead algorithm. + /// + /// # Reference + /// - [arXiv:quant-ph/0406142](https://arxiv.org/abs/quant-ph/0406142) + /// "A logarithmic-depth quantum carry-lookahead adder", + /// Thomas G. Draper, Samuel A. Kutin, Eric M. Rains, Krysta M. Svore + operation LookAheadDKRSAddLE(xs : Qubit[], ys : Qubit[], zs : Qubit[]) : Unit is Adj { + let xsLen = Length(xs); + let zsLen = Length(zs); + Fact(Length(ys) == xsLen, "Registers `xs` and `ys` must be of same length."); + Fact(zsLen >= xsLen, "Register `zs` must be no shorter than register `xs`."); + + if zsLen > xsLen { + // with carry-out + // compute initial generate values + for k in 0..xsLen - 1 { + ApplyAndAssuming0Target(xs[k], ys[k], zs[k + 1]); + } + + within { + // compute initial propagate values + for i in IndexRange(xs) { + CNOT(xs[i], ys[i]); + } + } apply { + if xsLen > 1 { + ComputeCarries(Rest(ys), zs[1..xsLen]); + } + + // compute sum into carries + for k in 0..xsLen - 1 { + CNOT(ys[k], zs[k]); + } + } + } else { + // xsLen == zsLen, so without carry-out + LookAheadDKRSAddLE(Most(xs), Most(ys), zs); + CNOT(Tail(xs), Tail(zs)); + CNOT(Tail(ys), Tail(zs)); + } + } + + /// # Summary + /// Increments a little-endian register ys by a little-endian register xs + /// using Quantum Fourier Transform. + /// + /// # Description + /// Computes ys += xs modulo 2ⁿ, where xs and ys are little-endian registers, + /// and Length(xs) = Length(ys) = n. + /// This operation uses Quantum Fourier Transform. + /// + /// # Reference + /// - [arXiv:quant-ph/0008033](https://arxiv.org/abs/quant-ph/0008033) + /// "Addition on a Quantum Computer", Thomas G. Draper + operation FourierTDIncByLE(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + within { + ApplyQFT(ys); + } apply { + for i in IndexRange(xs) { + Controlled PhaseGradient([xs[i]], ys[i...]); + } + } + } + + /// # Summary + /// Increments a little-endian register ys by a BigInt number c + /// using provided adder. + /// + /// # Description + /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register + /// Length(ys) = n > 0, c is a BigInt number, 0 ≤ c < 2ⁿ. + operation IncByLUsingIncByLE( + adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, + c : BigInt, + ys : Qubit[] + ) : Unit is Adj + Ctl { + + let ysLen = Length(ys); + Fact(ysLen > 0, "Length of `ys` must be at least 1."); + Fact(c >= 0L, "Constant `c` must be non-negative."); + Fact(c < 2L^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); + + if c != 0L { + // If c has j trailing zeros, then the j least significant + // bits of y won't be affected by the addition and can + // therefore be ignored by applying the addition only to + // the other qubits and shifting c accordingly. + let j = TrailingZeroCountL(c); + use x = Qubit[ysLen - j]; + within { + ApplyXorInPlaceL(c >>> j, x); + } apply { + adder(x, ys[j...]); + } + } + } + + /// # Summary + /// Increments a little-endian register ys by an Int number c + /// using provided adder. + /// + /// # Description + /// Computes ys += c modulo 2ⁿ, where ys is a little-endian register + /// Length(ys) = n > 0, c is an Int number, 0 ≤ c < 2ⁿ. + operation IncByIUsingIncByLE( + adder : (Qubit[], Qubit[]) => Unit is Adj + Ctl, + c : Int, + ys : Qubit[] + ) : Unit is Adj + Ctl { + + let ysLen = Length(ys); + Fact(ysLen > 0, "Length of `ys` must be at least 1."); + Fact(c >= 0, "Constant `c` must be non-negative."); + Fact(c < 2^ysLen, "Constant `c` must be smaller than 2^Length(ys)."); + + if c != 0 { + // If c has j trailing zeros than the j least significant + // bits of y won't be affected by the addition and can + // therefore be ignored by applying the addition only to + // the other qubits and shifting c accordingly. + let j = TrailingZeroCountI(c); + use x = Qubit[ysLen - j]; + within { + ApplyXorInPlace(c >>> j, x); + } apply { + adder(x, ys[j...]); + } + } + } + + /// # Summary + /// Generic operation to turn two out-place adders into one in-place adder + /// + /// # Description + /// This implementation allows to specify two distinct adders for forward + /// and backward direction. The forward adder is always applied in its + /// body variant, whereas the backward adder is always applied in its adjoint + /// variant. Therefore, it's possible to, for example, use the ripple-carry + /// out-of-place adder in backwards direction to require no T gates. + /// + /// The controlled variant is also optimized in a way that everything but + /// the adders is controlled, + /// + /// # Reference + /// - [arXiv:2012.01624](https://arxiv.org/abs/2012.01624) + /// "Quantum block lookahead adders and the wait for magic states", + /// Craig Gidney. + operation IncByLEUsingAddLE( + forwardAdder : (Qubit[], Qubit[], Qubit[]) => Unit is Adj, + backwardAdder : (Qubit[], Qubit[], Qubit[]) => Unit is Adj, + xs : Qubit[], + ys : Qubit[] + ) : Unit is Adj + Ctl { + + body (...) { + let n = Length(xs); + + Fact(Length(ys) == n, "Registers xs and ys must be of same length"); + + use qs = Qubit[n]; + + forwardAdder(xs, ys, qs); + for i in IndexRange(ys) { + SWAP(ys[i], qs[i]); + } + ApplyToEachA(X, qs); + within { + ApplyToEachA(X, ys); + } apply { + Adjoint backwardAdder(xs, ys, qs); + } + } + adjoint (...) { + let n = Length(xs); + + Fact(Length(ys) == n, "Registers xs and ys must be of same length"); + + use qs = Qubit[n]; + + within { + ApplyToEachA(X, ys); + } apply { + forwardAdder(xs, ys, qs); + } + ApplyToEachA(X, qs); + for i in IndexRange(ys) { + SWAP(ys[i], qs[i]); + } + Adjoint backwardAdder(xs, ys, qs); + } + controlled (ctls, ...) { + // When we control everything except the adders, the adders will + // cancel themselves. + let n = Length(xs); + + Fact(Length(ys) == n, "Registers xs and ys must be of same length"); + + use qs = Qubit[n]; + + forwardAdder(xs, ys, qs); + for i in IndexRange(ys) { + Controlled SWAP(ctls, (ys[i], qs[i])) + } + ApplyToEachA(tgt => Controlled X(ctls, tgt), qs); + within { + ApplyToEachA(tgt => Controlled X(ctls, tgt), ys); + } apply { + Adjoint backwardAdder(xs, ys, qs); + } + } + controlled adjoint (ctls, ...) { + // When we control everything except the adders, the adders will + // cancel themselves. + let n = Length(xs); + + Fact(Length(ys) == n, "Registers xs and ys must be of same length"); + + use qs = Qubit[n]; + + within { + ApplyToEachA(tgt => Controlled X(ctls, tgt), ys); + } apply { + forwardAdder(xs, ys, qs); + } + ApplyToEachA(tgt => Controlled X(ctls, tgt), qs); + for i in IndexRange(ys) { + Controlled SWAP(ctls, (ys[i], qs[i])) + } + Adjoint backwardAdder(xs, ys, qs); + } + } + + // + // Comparisons + // + // Compare BigInt and qubit register in a little-endian format and apply action + // if c < x { action(target) } | ApplyIfLessL + // if c <= x { action(target) } | ApplyIfLessOrEqualL + // if c == x { action(target) } | ApplyIfEqualL + // if c >= x { action(target) } | ApplyIfGreaterOrEqualL + // if c > x { action(target) } | ApplyIfGreaterL + // + // Compare two qubit registers in a little-endian format and apply action + // if x < y { action(target) } | ApplyIfLessLE + // if x <= y { action(target) } | ApplyIfLessOrEqualLE + // if x == y { action(target) } | ApplyIfEqualLE + // if x >= y { action(target) } | ApplyIfGreaterOrEqualLE + // if x > y { action(target) } | ApplyIfGreaterLE + // + + /// # Summary + /// Computes `if (c < x) { action(target) }`, that is, applies `action` to `target` + /// if a BigInt value `c` is less than the little-endian qubit register `x` + operation ApplyIfLessL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + ApplyActionIfGreaterThanOrEqualConstant(false, action, c + 1L, x, target); + } + + /// # Summary + /// Computes `if (c <= x) { action(target) }`, that is, applies `action` to `target` + /// if a BigInt value `c` is less or equal to the little-endian qubit register `x` + operation ApplyIfLessOrEqualL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + ApplyActionIfGreaterThanOrEqualConstant(false, action, c, x, target); + } + + /// # Summary + /// Computes `if (c == x) { action(target) }`, that is, applies `action` to `target` + /// if a BigInt value `c` is equal to the little-endian qubit register `x` + operation ApplyIfEqualL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + xs : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + let cBitSize = BitSizeL(c); + let xLen = Length(xs); + if (cBitSize <= xLen) { + let bits = BigIntAsBoolArray(c, Length(xs)); + within { + ApplyPauliFromBitString(PauliX, false, bits, xs); + } apply { + Controlled ApplyAsSinglyControlled(xs, (a => action(a), target)); + } + } + } + + /// # Summary + /// Computes `if (c >= x) { action(target) }`, that is, applies `action` to `target` + /// if a BigInt value `c` is greater or equal to the little-endian qubit register `x` + operation ApplyIfGreaterOrEqualL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + ApplyActionIfGreaterThanOrEqualConstant(true, action, c + 1L, x, target); + } + + /// # Summary + /// Computes `if (c > x) { action(target) }`, that is, applies `action` to `target` + /// if a BigInt value `c` is greater than the little-endian qubit register `x` + operation ApplyIfGreaterL<'T>( + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + ApplyActionIfGreaterThanOrEqualConstant(true, action, c, x, target); + } + + /// # Summary + /// Computes `if x < y { action(target) }`, that is, applies `action` to `target` + /// if register `x` is less than the register `y`. + /// Both qubit registers should be in a little-endian format. + operation ApplyIfLessLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + ApplyIfGreaterLE(action, y, x, target); + } + + /// # Summary + /// Computes `if x <= y { action(target) }`, that is, applies `action` to `target` + /// if register `x` is less or equal to the register `y`. + /// Both qubit registers should be in a little-endian format. + operation ApplyIfLessOrEqualLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + Fact(Length(x) > 0, "Bitwidth must be at least 1"); + within { + ApplyToEachA(X, x); + } apply { + // control is not inverted + ApplyActionIfSumOverflows(action, x, y, false, target); + } + } + + /// # Summary + /// Computes `if x == y { action(target) }`, that is, applies `action` to `target` + /// if register `x` is equal to the register `y`. + /// Both qubit registers should be in a little-endian format. + operation ApplyIfEqualLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + Fact(Length(x) == Length(y), "x and y must be of same length"); + within { + for i in IndexRange(x) { + CNOT(x[i], y[i]); + X(y[i]); + } + } apply { + Controlled ApplyAsSinglyControlled(y, (a => action(a), target)) + } + } + + /// # Summary + /// Computes `if x >= y { action(target) }`, that is, applies `action` to `target` + /// if register `x` is greater or equal to the register `y`. + /// Both qubit registers should be in a little-endian format. + operation ApplyIfGreaterOrEqualLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + ApplyIfLessOrEqualLE(action, y, x, target); + } + + /// # Summary + /// Computes `if x > y { action(target) }`, that is, applies `action` to `target` + /// if register `x` is greater than the register `y`. + /// Both qubit registers should be in a little-endian format. + operation ApplyIfGreaterLE<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + Fact(Length(x) > 0, "Bitwidth must be at least 1"); + within { + ApplyToEachA(X, x); + } apply { + // control is inverted + ApplyActionIfSumOverflows(action, x, y, true, target); + } + } + + export AddLE, ApplyIfEqualLE, ApplyIfEqualL, ApplyIfGreaterLE, ApplyIfGreaterL, ApplyIfGreaterOrEqualLE, ApplyIfGreaterOrEqualL, ApplyIfLessLE, ApplyIfLessL, ApplyIfLessOrEqualLE, ApplyIfLessOrEqualL, IncByI, IncByIUsingIncByLE, IncByL, IncByLUsingIncByLE, IncByLE, IncByLEUsingAddLE, LookAheadDKRSAddLE, MAJ, ReflectAboutInteger, RippleCarryCGAddLE, RippleCarryCGIncByLE, RippleCarryTTKIncByLE, FourierTDIncByLE; +} diff --git a/library/std/src/unstable_arithmetic_internal.qs b/library/std/src/unstable_arithmetic_internal.qs new file mode 100644 index 0000000000..5125859fa8 --- /dev/null +++ b/library/std/src/unstable_arithmetic_internal.qs @@ -0,0 +1,585 @@ +// Copyright (c) Microsoft Corporation. +// 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; + + /// # Summary + /// Implements the outer operation for RippleCarryTTKIncByLE to conjugate + /// the inner operation to construct the full adder. Only Length(xs) + /// qubits are processed. + /// + /// # Input + /// ## xs + /// Qubit register in a little-endian format containing the first summand + /// input to RippleCarryTTKIncByLE. + /// ## ys + /// Qubit register in a little-endian format containing the second summand + /// input to RippleCarryTTKIncByLE. + /// + /// # References + /// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum + /// Addition Circuits and Unbounded Fan-Out", Quantum Information and + /// Computation, Vol. 10, 2010. + /// https://arxiv.org/abs/0910.2530 + internal operation ApplyOuterTTKAdder(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + Fact(Length(xs) <= Length(ys), "Input register ys must be at lease as long as xs."); + for i in 1..Length(xs) - 1 { + CNOT(xs[i], ys[i]); + } + for i in Length(xs) - 2..-1..1 { + CNOT(xs[i], xs[i + 1]); + } + } + + /// # Summary + /// Implements the inner addition function for the operation + /// RippleCarryTTKIncByLE. This is the inner operation that is conjugated + /// with the outer operation to construct the full adder. + /// + /// # Input + /// ## xs + /// Qubit register in a little-endian format containing the first summand + /// input to RippleCarryTTKIncByLE. + /// ## ys + /// Qubit register in a little-endian format containing the second summand + /// input to RippleCarryTTKIncByLE. + /// + /// # References + /// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum + /// Addition Circuits and Unbounded Fan-Out", Quantum Information and + /// Computation, Vol. 10, 2010. + /// https://arxiv.org/abs/0910.2530 + /// + /// # Remarks + /// The specified controlled operation makes use of symmetry and mutual + /// cancellation of operations to improve on the default implementation + /// that adds a control to every operation. + internal operation ApplyInnerTTKAdderNoCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + body (...) { + (Controlled ApplyInnerTTKAdderNoCarry)([], (xs, ys)); + } + controlled (controls, ...) { + Fact(Length(xs) == Length(ys), "Input registers must have the same number of qubits."); + + for idx in 0..Length(xs) - 2 { + CCNOT(xs[idx], ys[idx], xs[idx + 1]); + } + for idx in Length(xs) - 1..-1..1 { + Controlled CNOT(controls, (xs[idx], ys[idx])); + CCNOT(xs[idx - 1], ys[idx - 1], xs[idx]); + } + } + } + + /// # Summary + /// Implements the inner addition function for the operation + /// RippleCarryTTKIncByLE. This is the inner operation that is conjugated + /// with the outer operation to construct the full adder. + /// + /// # Input + /// ## xs + /// Qubit register in a little-endian format containing the first summand + /// input to RippleCarryTTKIncByLE. + /// ## ys + /// Qubit register in a little-endian format containing the second summand + /// input to RippleCarryTTKIncByLE. + /// + /// # References + /// - Yasuhiro Takahashi, Seiichiro Tani, Noboru Kunihiro: "Quantum + /// Addition Circuits and Unbounded Fan-Out", Quantum Information and + /// Computation, Vol. 10, 2010. + /// https://arxiv.org/abs/0910.2530 + /// + /// # Remarks + /// The specified controlled operation makes use of symmetry and mutual + /// cancellation of operations to improve on the default implementation + /// that adds a control to every operation. + internal operation ApplyInnerTTKAdderWithCarry(xs : Qubit[], ys : Qubit[]) : Unit is Adj + Ctl { + body (...) { + (Controlled ApplyInnerTTKAdderWithCarry)([], (xs, ys)); + } + controlled (controls, ...) { + Fact(Length(xs) + 1 == Length(ys), "ys must be one qubit longer then xs."); + Fact(Length(xs) > 0, "Array should not be empty."); + + + let nQubits = Length(xs); + for idx in 0..nQubits - 2 { + CCNOT(xs[idx], ys[idx], xs[idx + 1]); + } + (Controlled CCNOT)(controls, (xs[nQubits - 1], ys[nQubits - 1], ys[nQubits])); + for idx in nQubits - 1..-1..1 { + Controlled CNOT(controls, (xs[idx], ys[idx])); + CCNOT(xs[idx - 1], ys[idx - 1], xs[idx]); + } + } + } + + /// # Summary + /// Implements Half-adder. Adds qubit x to qubit y and sets carryOut appropriately + internal operation HalfAdderForInc(x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { + body (...) { + CCNOT(x, y, carryOut); + CNOT(x, y); + } + adjoint auto; + + controlled (ctls, ...) { + Fact(Length(ctls) == 1, "HalfAdderForInc should be controlled by exactly one control qubit."); + + let ctl = ctls[0]; + use helper = Qubit(); + + within { + ApplyAndAssuming0Target(x, y, helper); + } apply { + ApplyAndAssuming0Target(ctl, helper, carryOut); + } + CCNOT(ctl, x, y); + } + controlled adjoint auto; + } + + /// # Summary + /// Implements Full-adder. Adds qubit carryIn and x to qubit y and sets carryOut appropriately. + internal operation FullAdderForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { + body (...) { + // TODO: cannot use `Carry` operation here + CNOT(carryIn, x); + CNOT(carryIn, y); + CCNOT(x, y, carryOut); + CNOT(carryIn, carryOut); + CNOT(carryIn, x); + CNOT(x, y); + } + adjoint auto; + + controlled (ctls, ...) { + Fact(Length(ctls) == 1, "FullAdderForInc should be controlled by exactly one control qubit."); + + let ctl = ctls[0]; + use helper = Qubit(); + + CarryForInc(carryIn, x, y, helper); + CCNOT(ctl, helper, carryOut); + Controlled UncarryForInc(ctls, (carryIn, x, y, helper)); + } + controlled adjoint auto; + } + + // Computes carryOut := carryIn + x + y + internal operation FullAdder(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj { + CNOT(x, y); + CNOT(x, carryIn); + ApplyAndAssuming0Target(y, carryIn, carryOut); + CNOT(x, y); + CNOT(x, carryOut); + CNOT(y, carryIn); + } + + /// # Summary + /// Computes carry bit for a full adder. + internal operation CarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { + body (...) { + CNOT(carryIn, x); + CNOT(carryIn, y); + ApplyAndAssuming0Target(x, y, carryOut); + CNOT(carryIn, carryOut); + } + adjoint auto; + controlled (ctls, ...) { + // This CarryForInc is intended to be used only in an in-place + // ripple-carry implementation. Only such particular use case allows + // for this simple implementation where controlled version + // is the same as uncontrolled body. + CarryForInc(carryIn, x, y, carryOut); + } + controlled adjoint auto; + } + + /// # Summary + /// Uncomputes carry bit for a full adder. + internal operation UncarryForInc(carryIn : Qubit, x : Qubit, y : Qubit, carryOut : Qubit) : Unit is Adj + Ctl { + body (...) { + CNOT(carryIn, carryOut); + Adjoint ApplyAndAssuming0Target(x, y, carryOut); + CNOT(carryIn, x); + CNOT(x, y); + } + adjoint auto; + controlled (ctls, ...) { + Fact(Length(ctls) == 1, "UncarryForInc should be controlled by exactly one control qubit."); + + let ctl = ctls[0]; + + CNOT(carryIn, carryOut); + Adjoint ApplyAndAssuming0Target(x, y, carryOut); + CCNOT(ctl, x, y); // Controlled X(ctls + [x], y); + CNOT(carryIn, x); + CNOT(carryIn, y); + } + controlled adjoint auto; + } + + /// # Summary + /// Applies AND gate between `control1` and `control2` and stores the result + /// in `target` assuming `target` is in |0> state. + /// + /// # Description + /// Inverts `target` if and only if both controls are 1, but assumes that + /// `target` is in state 0. The operation has T-count 4, T-depth 2 and + /// requires no helper qubit, and may therefore be preferable to a CCNOT + /// operation, if `target` is known to be 0. + /// The adjoint of this operation is measurement based and requires no T + /// gates (but requires target to support branching on measurements). + /// Although the Toffoli gate (CCNOT) will perform faster in simulations, + /// this version has lower T gate requirements. + /// # References + /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", + /// Phys. Rev. A 87, 022328, 2013 + /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) + /// doi:10.1103/PhysRevA.87.022328 + @Config(Adaptive) + internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + // NOTE: Eventually this operation will be public and intrinsic. + body (...) { + CCNOT(control1, control2, target); + } + adjoint (...) { + H(target); + if M(target) == One { + Reset(target); + CZ(control1, control2); + } + } + } + + internal operation ApplyOrAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + within { + X(control1); + X(control2); + } apply { + ApplyAndAssuming0Target(control1, control2, target); + X(target); + } + } + + /// # Summary + /// Applies AND gate between `control1` and `control2` and stores the result + /// in `target` assuming `target` is in |0> state. + /// + /// # Description + /// Inverts `target` if and only if both controls are 1, but assumes that + /// `target` is in state 0. The operation has T-count 4, T-depth 2 and + /// requires no helper qubit, and may therefore be preferable to a CCNOT + /// operation, if `target` is known to be 0. + /// This version is suitable for Base profile. + /// Although the Toffoli gate (CCNOT) will perform faster in simulations, + /// this version has lower T gate requirements. + /// # References + /// - Cody Jones: "Novel constructions for the fault-tolerant Toffoli gate", + /// Phys. Rev. A 87, 022328, 2013 + /// [arXiv:1212.5069](https://arxiv.org/abs/1212.5069) + /// doi:10.1103/PhysRevA.87.022328 + @Config(not Adaptive) + internal operation ApplyAndAssuming0Target(control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj { + H(target); + T(target); + CNOT(control1, target); + CNOT(control2, target); + within { + CNOT(target, control1); + CNOT(target, control2); + } apply { + Adjoint T(control1); + Adjoint T(control2); + T(target); + } + H(target); + S(target); + } + + /// # Summary + /// Computes carries for the look-ahead adder + internal operation ComputeCarries(ps : Qubit[], gs : Qubit[]) : Unit is Adj { + let n = Length(gs); + Fact(Length(ps) + 1 == n, "Register gs must be one qubit longer than register gs."); + + let T = Floor(Lg(IntAsDouble(n))); + use qs = Qubit[n - HammingWeightI(n) - T]; + + let registerPartition = MappedOverRange(t -> Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1, 1..T - 1); + let pWorkspace = [ps] + Partitioned(registerPartition, qs); + + within { + PRounds(pWorkspace); + } apply { + // U_G + GRounds(pWorkspace, gs); + + // U_C + CRounds(pWorkspace, gs); + } + } + + /// # Summary + /// Computes all p[i, j] values in workspace for the look-ahead adder. + /// + /// The register array `pWorkspace` has T entries, where T = ⌊log₂ n⌋. + /// + /// The first entry `pWorkspace[0]` is initialized with `P_0` which is + /// computed before `ComputeCarries` is called. The other registers are + /// 0-initialized and will be computed in successive rounds t = 1, ..., T - 1. + /// + /// In each round t we compute + /// + /// p[i, j] = p[2ᵗ × m, 2ᵗ × (m + 1)] = p[i, k] ∧ p[k, j] + /// + /// in `pWorkspace[t][m - 1]` and use that for k = 2ᵗ × m + 2ᵗ⁻¹, p[i, k] and p[k, j] + /// have already been computed in round t - 1 in `pWorkspace[t - 1][2 * m - 1]` and + /// `pWorkspace[t - 1][2 * m]`, respectively. + internal operation PRounds(pWorkspace : Qubit[][]) : Unit is Adj { + for ws in Windows(2, pWorkspace) { + // note that we are using Rest, since pWorkspace[t - 1][0] is never + // accessed in round t. + let (current, next) = (Rest(ws[0]), ws[1]); + + for m in IndexRange(next) { + ApplyAndAssuming0Target(current[2 * m], current[2 * m + 1], next[m]); + } + } + } + + /// # Summary + /// Computes g[i ∧ (i + 1), i + 1] into gs[i] for the look-ahead adder. + /// + /// The register gs has n entries initialized to gs[i] = g[i, i + 1]. + /// + /// After successive rounds t = 1, ..., T, the register is updated to + /// gs[i] = g[i ∧ (i + 1), i + 1], from which we can compute the carries + /// in the C-rounds. + internal operation GRounds(pWorkspace : Qubit[][], gs : Qubit[]) : Unit is Adj { + let T = Length(pWorkspace); + let n = Length(gs); + + for t in 1..T { + let length = Floor(IntAsDouble(n) / IntAsDouble(2^t)) - 1; + let ps = pWorkspace[t - 1][0..2...]; + + for m in 0..length { + CCNOT(gs[2^t * m + 2^(t - 1) - 1], ps[m], gs[2^t * m + 2^t - 1]); + } + } + } + + /// # Summary + /// Computes carries into gs for the look-ahead adder. + internal operation CRounds(pWorkspace : Qubit[][], gs : Qubit[]) : Unit is Adj { + let n = Length(gs); + + let start = Floor(Lg(IntAsDouble(2 * n) / 3.0)); + for t in start..-1..1 { + let length = Floor(IntAsDouble(n - 2^(t - 1)) / IntAsDouble(2^t)); + let ps = pWorkspace[t - 1][1..2...]; + + for m in 1..length { + CCNOT(gs[2^t * m - 1], ps[m - 1], gs[2^t * m + 2^(t - 1) - 1]); + } + } + } + + internal operation PhaseGradient(qs : Qubit[]) : Unit is Adj + Ctl { + for i in IndexRange(qs) { + R1Frac(1, i, qs[i]); + } + } + + // + // Internal operations for comparisons + // + + /// # Summary + /// Applies `action` to `target` if register `x` is greater or equal to BigInt `c` + /// (if `invertControl` is false). If `invertControl` is true, the `action` + /// is applied in the opposite situation. + internal operation ApplyActionIfGreaterThanOrEqualConstant<'T>( + invertControl : Bool, + action : 'T => Unit is Adj + Ctl, + c : BigInt, + x : Qubit[], + target : 'T + ) : Unit is Adj + Ctl { + + let bitWidth = Length(x); + if c == 0L { + if not invertControl { + action(target); + } + } elif c >= (2L^bitWidth) { + if invertControl { + action(target); + } + } else { + // normalize constant + let l = TrailingZeroCountL(c); + + let cNormalized = c >>> l; + let xNormalized = x[l...]; + let bitWidthNormalized = Length(xNormalized); + + // If c == 2L^(bitwidth - 1), then bitWidthNormalized will be 1, + // and qs will be empty. In that case, we do not need to compute + // any temporary values, and some optimizations are apply, which + // are considered in the remainder. + use qs = Qubit[bitWidthNormalized - 1]; + let cs1 = IsEmpty(qs) ? [] | [Head(xNormalized)] + Most(qs); + + Fact(Length(cs1) == Length(qs), "Arrays should be of the same length."); + + within { + for i in 0..Length(cs1) - 1 { + let op = cNormalized &&& (1L <<< (i + 1)) != 0L ? ApplyAndAssuming0Target | ApplyOrAssuming0Target; + op(cs1[i], xNormalized[i + 1], qs[i]); + } + } apply { + let control = IsEmpty(qs) ? Tail(x) | Tail(qs); + within { + if invertControl { + X(control); + } + } apply { + Controlled action([control], target); + } + } + } + } + + /// # Summary + /// Applies `action` to `target` if the sum of `x` and `y` registers + /// overflows, i.e. there's a carry out (if `invertControl` is false). + /// If `invertControl` is true, the `action` is applied when there's no carry out. + internal operation ApplyActionIfSumOverflows<'T>( + action : 'T => Unit is Adj + Ctl, + x : Qubit[], + y : Qubit[], + invertControl : Bool, + target : 'T + ) : Unit is Adj + Ctl { + + let n = Length(x); + Fact(n >= 1, "Registers must contain at least one qubit."); + Fact(Length(y) == n, "Registers must be of the same length."); + + use carries = Qubit[n]; + + within { + CarryWith1CarryIn(x[0], y[0], carries[0]); + for i in 1..n - 1 { + CarryForInc(carries[i - 1], x[i], y[i], carries[i]); + } + } apply { + within { + if invertControl { + X(carries[n - 1]); + } + } apply { + Controlled action([carries[n - 1]], target); + } + } + } + + /// # Summary + /// Computes carry out assuming carry in is 1. + /// Simplified version that is only applicable for scenarios + /// where controlled version is the same as non-controlled. + internal operation CarryWith1CarryIn( + x : Qubit, + y : Qubit, + carryOut : Qubit + ) : Unit is Adj + Ctl { + + body (...) { + X(x); + X(y); + ApplyAndAssuming0Target(x, y, carryOut); + X(carryOut); + } + + adjoint auto; + + controlled (ctls, ...) { + Fact(Length(ctls) <= 1, "Number of control lines must be at most 1"); + CarryWith1CarryIn(x, y, carryOut); + } + + controlled adjoint auto; + } + + /// # Summary + /// This wrapper allows operations that support only one control + /// qubit to be used in a multi-controlled scenarios. It provides + /// controlled version that collects controls into one qubit + /// by applying AND chain using auxiliary qubit array. + internal operation ApplyAsSinglyControlled<'TIn>( + op : ('TIn => Unit is Adj + Ctl), + input : 'TIn + ) : Unit is Adj + Ctl { + + body (...) { + op(input); + } + + controlled (ctls, ...) { + let n = Length(ctls); + if n == 0 { + op(input); + } elif n == 1 { + Controlled op(ctls, input); + } else { + use aux = Qubit[n - 1]; + within { + LogDepthAndChain(ctls, aux); + } apply { + Controlled op([Tail(aux)], input); + } + } + } + } + + /// # Summary + /// This helper function computes the AND of all control bits in `ctls` into + /// the last qubit of `tgts`, using the other qubits in `tgts` as helper + /// qubits for the AND of subsets of control bits. The operation has a + /// logarithmic depth of AND gates by aligning them using a balanced binary + /// tree. + internal operation LogDepthAndChain(ctls : Qubit[], tgts : Qubit[]) : Unit is Adj { + let lc = Length(ctls); + let lt = Length(tgts); + + Fact(lc == lt + 1, $"There must be exactly one more control qubit than target qubits (got {lc}, {lt})"); + + if lt == 1 { + ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]); + } elif lt == 2 { + ApplyAndAssuming0Target(ctls[0], ctls[1], tgts[0]); + ApplyAndAssuming0Target(ctls[2], tgts[0], tgts[1]); + } else { + let left = lc / 2; + let right = lc - left; + + let ctlsLeft = ctls[...left - 1]; + let tgtsLeft = tgts[...left - 2]; + + let ctlsRight = ctls[left..left + right - 1]; + let tgtsRight = tgts[left - 1..left + right - 3]; + + LogDepthAndChain(ctlsLeft, tgtsLeft); + LogDepthAndChain(ctlsRight, tgtsRight); + ApplyAndAssuming0Target(Tail(tgtsLeft), Tail(tgtsRight), Tail(tgts)); + } + } +} diff --git a/library/std/src/unstable_state_preparation.qs b/library/std/src/unstable_state_preparation.qs new file mode 100644 index 0000000000..dfc3d5ebb7 --- /dev/null +++ b/library/std/src/unstable_state_preparation.qs @@ -0,0 +1,388 @@ +// Copyright (c) Microsoft Corporation. +// 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; + + /// # Summary + /// Given a set of coefficients and a big-endian quantum register, + /// prepares a state on that register described by the given coefficients. + /// + /// # Description + /// This operation prepares an arbitrary quantum + /// state |𝜓⟩ with coefficients 𝑎ⱼ from + /// the n-qubit computational basis state |0...0⟩. + /// + /// The action of U on the all-zeros state is given by + /// $$ + /// \begin{align} + /// U \ket{0\cdots 0} = \ket{\psi} = \frac{\sum_{j=0}^{2^n-1}\alpha_j \ket{j}}{\sqrt{\sum_{j=0}^{2^n-1}|\alpha_j|^2}}. + /// \end{align} + /// $$ + /// + /// # Input + /// ## coefficients + /// Array of up to 2ⁿ real coefficients. The j-th coefficient + /// indexes the number state |j⟩ encoded in big-endian format. + /// + /// ## qubits + /// Qubit register encoding number states in a big-endian format. This is + /// expected to be initialized in the computational basis state |0...0⟩. + /// + /// # Remarks + /// `coefficients` will be normalized and padded with + /// elements 𝑎ⱼ = 0.0 if fewer than 2ⁿ are specified. + /// + /// # Example + /// The following snippet prepares the quantum state |𝜓⟩=√(1/8)|0⟩+√(7/8)|2⟩=√(1/8)|00⟩+√(7/8)|10⟩ + /// in the qubit register `qubits`. + /// ```qsharp + /// let amplitudes = [Sqrt(0.125), 0.0, Sqrt(0.875), 0.0]; + /// use qubits = Qubit[2]; + /// PreparePureStateD(amplitudes, qubits); + /// ``` + /// + /// # References + /// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) + /// "Synthesis of Quantum Logic Circuits", + /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov + /// + /// # See Also + /// - Microsoft.Quantum.Unstable.StatePreparation.ApproximatelyPreparePureStateCP + operation PreparePureStateD(coefficients : Double[], qubits : Qubit[]) : Unit is Adj + Ctl { + let coefficientsAsComplexPolar = Mapped(a -> ComplexAsComplexPolar(Complex(a, 0.0)), coefficients); + ApproximatelyPreparePureStateCP(0.0, coefficientsAsComplexPolar, qubits); + } + + /// # Summary + /// Given a set of coefficients and a big-endian quantum register, + /// prepares a state on that register described by the given coefficients, + /// up to a given approximation tolerance. + /// + /// # Description + /// This operation prepares an arbitrary quantum + /// state |𝜓⟩ with complex coefficients rⱼ·𝒆^(𝒊·tⱼ) from + /// the n-qubit computational basis state |0...0⟩. + /// In particular, the action of this operation can be simulated by the + /// a unitary transformation U which acts on the all-zeros state as + /// + /// $$ + /// \begin{align} + /// U\ket{0...0} + /// & = \ket{\psi} \\\\ + /// & = \frac{ + /// \sum_{j=0}^{2^n-1} r_j e^{i t_j} \ket{j} + /// }{ + /// \sqrt{\sum_{j=0}^{2^n-1} |r_j|^2} + /// }. + /// \end{align} + /// $$ + /// + /// # Input + /// ## tolerance + /// The approximation tolerance to be used when preparing the given state. + /// + /// ## coefficients + /// Array of up to 2ⁿ complex coefficients represented by their + /// absolute value and phase (rⱼ, tⱼ). The j-th coefficient + /// indexes the number state |j⟩ encoded in a big-endian format. + /// + /// ## qubits + /// Qubit register encoding number states in a big-endian format. This is + /// expected to be initialized in the computational basis state + /// |0...0⟩. + /// + /// # Remarks + /// `coefficients` will be padded with + /// elements (rⱼ, tⱼ) = (0.0, 0.0) if fewer than 2ⁿ are + /// specified. + /// + /// # References + /// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) + /// "Synthesis of Quantum Logic Circuits", + /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov + operation ApproximatelyPreparePureStateCP( + tolerance : Double, + coefficients : ComplexPolar[], + qubits : Qubit[] + ) : Unit is Adj + Ctl { + + let nQubits = Length(qubits); + // pad coefficients at tail length to a power of 2. + let coefficientsPadded = Padded(-2^nQubits, ComplexPolar(0.0, 0.0), coefficients); + let idxTarget = 0; + // Determine what controls to apply + let rngControl = nQubits > 1 ? (1..(nQubits - 1)) | (1..0); + // Note we use the reversed qubits array to get the endianness ordering that we expect + // when corresponding qubit state to state vector index. + Adjoint ApproximatelyUnprepareArbitraryState( + tolerance, + coefficientsPadded, + rngControl, + idxTarget, + Reversed(qubits) + ); + } + + /// # Summary + /// Implementation step of arbitrary state preparation procedure. + internal operation ApproximatelyUnprepareArbitraryState( + tolerance : Double, + coefficients : ComplexPolar[], + rngControl : Range, + idxTarget : Int, + register : Qubit[] + ) : Unit is Adj + Ctl { + + // For each 2D block, compute disentangling single-qubit rotation parameters + let (disentanglingY, disentanglingZ, newCoefficients) = StatePreparationSBMComputeCoefficients(coefficients); + if (AnyOutsideToleranceD(tolerance, disentanglingZ)) { + ApproximatelyMultiplexPauli(tolerance, disentanglingZ, PauliZ, register[rngControl], register[idxTarget]); + + } + if (AnyOutsideToleranceD(tolerance, disentanglingY)) { + ApproximatelyMultiplexPauli(tolerance, disentanglingY, PauliY, register[rngControl], register[idxTarget]); + } + // target is now in |0> state up to the phase given by arg of newCoefficients. + + // Continue recursion while there are control qubits. + if (IsRangeEmpty(rngControl)) { + let (abs, arg) = (newCoefficients[0].Magnitude, newCoefficients[0].Argument); + if (AbsD(arg) > tolerance) { + Exp([PauliI], -1.0 * arg, [register[idxTarget]]); + } + } elif (Any(c -> AbsComplexPolar(c) > tolerance, newCoefficients)) { + // Some coefficients are outside tolerance + let newControl = (RangeStart(rngControl) + 1)..RangeStep(rngControl)..RangeEnd(rngControl); + let newTarget = RangeStart(rngControl); + ApproximatelyUnprepareArbitraryState(tolerance, newCoefficients, newControl, newTarget, register); + } + } + + /// # Summary + /// Applies a Pauli rotation conditioned on an array of qubits, truncating + /// small rotation angles according to a given tolerance. + /// + /// # Description + /// This applies a multiply controlled unitary operation that performs + /// rotations by angle $\theta_j$ about single-qubit Pauli operator $P$ + /// when controlled by the $n$-qubit number state $\ket{j}$. + /// In particular, the action of this operation is represented by the + /// unitary + /// + /// $$ + /// \begin{align} + /// U = \sum^{2^n - 1}_{j=0} \ket{j}\bra{j} \otimes e^{i P \theta_j}. + /// \end{align} + /// ## + /// + /// # Input + /// ## tolerance + /// A tolerance below which small coefficients are truncated. + /// + /// ## coefficients + /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient + /// indexes the number state $\ket{j}$ encoded in little-endian format. + /// + /// ## pauli + /// Pauli operator $P$ that determines axis of rotation. + /// + /// ## control + /// $n$-qubit control register that encodes number states $\ket{j}$ in + /// little-endian format. + /// + /// ## target + /// Single qubit register that is rotated by $e^{i P \theta_j}$. + /// + /// # Remarks + /// `coefficients` will be padded with elements $\theta_j = 0.0$ if + /// fewer than $2^n$ are specified. + internal operation ApproximatelyMultiplexPauli( + tolerance : Double, + coefficients : Double[], + pauli : Pauli, + control : Qubit[], + target : Qubit + ) : Unit is Adj + Ctl { + + if pauli == PauliZ { + ApproximatelyMultiplexZ(tolerance, coefficients, control, target); + } elif pauli == PauliX { + within { + H(target); + } apply { + ApproximatelyMultiplexPauli(tolerance, coefficients, PauliZ, control, target); + } + } elif pauli == PauliY { + within { + Adjoint S(target); + } apply { + ApproximatelyMultiplexPauli(tolerance, coefficients, PauliX, control, target); + } + } else { + fail $"MultiplexPauli failed. Invalid pauli {pauli}."; + } + } + + /// # Summary + /// Implementation step of arbitrary state preparation procedure. + internal function StatePreparationSBMComputeCoefficients( + coefficients : ComplexPolar[] + ) : (Double[], Double[], ComplexPolar[]) { + + mutable disentanglingZ = []; + mutable disentanglingY = []; + mutable newCoefficients = []; + + for idxCoeff in 0..2..Length(coefficients) - 1 { + let (rt, phi, theta) = BlochSphereCoordinates(coefficients[idxCoeff], coefficients[idxCoeff + 1]); + set disentanglingZ += [0.5 * phi]; + set disentanglingY += [0.5 * theta]; + set newCoefficients += [rt]; + } + + return (disentanglingY, disentanglingZ, newCoefficients); + } + + /// # Summary + /// Computes the Bloch sphere coordinates for a single-qubit state. + /// + /// Given two complex numbers $a0, a1$ that represent the qubit state, computes coordinates + /// on the Bloch sphere such that + /// $a0 \ket{0} + a1 \ket{1} = r e^{it}(e^{-i \phi /2}\cos{(\theta/2)}\ket{0}+e^{i \phi /2}\sin{(\theta/2)}\ket{1})$. + /// + /// # Input + /// ## a0 + /// Complex coefficient of state $\ket{0}$. + /// ## a1 + /// Complex coefficient of state $\ket{1}$. + /// + /// # Output + /// A tuple containing `(ComplexPolar(r, t), phi, theta)`. + internal function BlochSphereCoordinates( + a0 : ComplexPolar, + a1 : ComplexPolar + ) : (ComplexPolar, Double, Double) { + + let abs0 = AbsComplexPolar(a0); + let abs1 = AbsComplexPolar(a1); + let arg0 = ArgComplexPolar(a0); + let arg1 = ArgComplexPolar(a1); + let r = Sqrt(abs0 * abs0 + abs1 * abs1); + let t = 0.5 * (arg0 + arg1); + let phi = arg1 - arg0; + let theta = 2.0 * ArcTan2(abs1, abs0); + return (ComplexPolar(r, t), phi, theta); + } + + /// # Summary + /// Applies a Pauli Z rotation conditioned on an array of qubits, truncating + /// small rotation angles according to a given tolerance. + /// + /// # Description + /// This applies the multiply controlled unitary operation that performs + /// rotations by angle $\theta_j$ about single-qubit Pauli operator $Z$ + /// when controlled by the $n$-qubit number state $\ket{j}$. + /// In particular, this operation can be represented by the unitary + /// + /// $$ + /// \begin{align} + /// U = \sum^{2^n-1}_{j=0} \ket{j}\bra{j} \otimes e^{i Z \theta_j}. + /// \end{align} + /// $$ + /// + /// # Input + /// ## tolerance + /// A tolerance below which small coefficients are truncated. + /// + /// ## coefficients + /// Array of up to $2^n$ coefficients $\theta_j$. The $j$th coefficient + /// indexes the number state $\ket{j}$ encoded in little-endian format. + /// + /// ## control + /// $n$-qubit control register that encodes number states $\ket{j}$ in + /// little-endian format. + /// + /// ## target + /// Single qubit register that is rotated by $e^{i P \theta_j}$. + /// + /// # Remarks + /// `coefficients` will be padded with elements $\theta_j = 0.0$ if + /// fewer than $2^n$ are specified. + /// + /// # References + /// - [arXiv:quant-ph/0406176](https://arxiv.org/abs/quant-ph/0406176) + /// "Synthesis of Quantum Logic Circuits", + /// Vivek V. Shende, Stephen S. Bullock, Igor L. Markov + internal operation ApproximatelyMultiplexZ( + tolerance : Double, + coefficients : Double[], + control : Qubit[], + target : Qubit + ) : Unit is Adj + Ctl { + + body (...) { + // pad coefficients length at tail to a power of 2. + let coefficientsPadded = Padded(-2^Length(control), 0.0, coefficients); + + if Length(coefficientsPadded) == 1 { + // Termination case + if AbsD(coefficientsPadded[0]) > tolerance { + Exp([PauliZ], coefficientsPadded[0], [target]); + } + } else { + // Compute new coefficients. + let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); + ApproximatelyMultiplexZ(tolerance, coefficients0, Most(control), target); + if AnyOutsideToleranceD(tolerance, coefficients1) { + within { + CNOT(Tail(control), target); + } apply { + ApproximatelyMultiplexZ(tolerance, coefficients1, Most(control), target); + } + } + } + } + + controlled (controlRegister, ...) { + // pad coefficients length to a power of 2. + let coefficientsPadded = Padded(2^(Length(control) + 1), 0.0, Padded(-2^Length(control), 0.0, coefficients)); + let (coefficients0, coefficients1) = MultiplexZCoefficients(coefficientsPadded); + ApproximatelyMultiplexZ(tolerance, coefficients0, control, target); + if AnyOutsideToleranceD(tolerance, coefficients1) { + within { + Controlled X(controlRegister, target); + } apply { + ApproximatelyMultiplexZ(tolerance, coefficients1, control, target); + } + } + } + } + + /// # Summary + /// Implementation step of multiply-controlled Z rotations. + internal function MultiplexZCoefficients(coefficients : Double[]) : (Double[], Double[]) { + let newCoefficientsLength = Length(coefficients) / 2; + mutable coefficients0 = []; + mutable coefficients1 = []; + + for idxCoeff in 0..newCoefficientsLength - 1 { + set coefficients0 += [0.5 * (coefficients[idxCoeff] + coefficients[idxCoeff + newCoefficientsLength])]; + set coefficients1 += [0.5 * (coefficients[idxCoeff] - coefficients[idxCoeff + newCoefficientsLength])]; + } + + return (coefficients0, coefficients1); + } + + internal function AnyOutsideToleranceD(tolerance : Double, coefficients : Double[]) : Bool { + // NOTE: This function is not used as the only recursion termination condition + // only to determine if the multiplex step needs to be applied. + // For tolerance 0.0 it is always applied due to >= comparison. + Any(coefficient -> AbsD(coefficient) >= tolerance, coefficients) + } + + export PreparePureStateD, ApproximatelyPreparePureStateCP; +} diff --git a/library/std/src/unstable_table_lookup.qs b/library/std/src/unstable_table_lookup.qs new file mode 100644 index 0000000000..5ff35395b6 --- /dev/null +++ b/library/std/src/unstable_table_lookup.qs @@ -0,0 +1,278 @@ +// Copyright (c) Microsoft Corporation. +// 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; + + /// # Summary + /// Performs table lookup using a SELECT network + /// + /// # Description + /// Assuming a zero-initialized `target` register, this operation will + /// initialize it with the bitstrings in `data` at indices according to the + /// computational values of the `address` register. + /// + /// # Input + /// ## data + /// The classical table lookup data which is prepared in `target` with + /// respect to the state in `address`. The length of data must be less than + /// 2ⁿ, where 𝑛 is the length of `address`. Each entry in data must have + /// the same length that must be equal to the length of `target`. + /// ## address + /// Address register + /// ## target + /// Zero-initialized target register + /// + /// # Remarks + /// The implementation of the SELECT network is based on unary encoding as + /// presented in [1]. The recursive implementation of that algorithm is + /// presented in [3]. The adjoint variant is optimized using a + /// measurement-based unlookup operation [3]. The controlled adjoint variant + /// is not optimized using this technique. + /// + /// # References + /// 1. [arXiv:1805.03662](https://arxiv.org/abs/1805.03662) + /// "Encoding Electronic Spectra in Quantum Circuits with Linear T + /// Complexity" + /// 2. [arXiv:1905.07682](https://arxiv.org/abs/1905.07682) + /// "Windowed arithmetic" + /// 3. [arXiv:2211.01133](https://arxiv.org/abs/2211.01133) + /// "Space-time optimized table lookup" + operation Select( + data : Bool[][], + address : Qubit[], + target : Qubit[] + ) : Unit is Adj + Ctl { + body (...) { + let (N, n) = DimensionsForSelect(data, address); + + if N == 1 { + // base case + WriteMemoryContents(Head(data), target); + } else { + let (most, tail) = MostAndTail(address[...n - 1]); + let parts = Partitioned([2^(n - 1)], data); + + within { + X(tail); + } apply { + SinglyControlledSelect(tail, parts[0], most, target); + } + + SinglyControlledSelect(tail, parts[1], most, target); + } + } + adjoint (...) { + Unlookup(Select, data, address, target); + } + + controlled (ctls, ...) { + let numCtls = Length(ctls); + + if numCtls == 0 { + Select(data, address, target); + } elif numCtls == 1 { + SinglyControlledSelect(ctls[0], data, address, target); + } else { + use andChainTarget = Qubit(); + let andChain = MakeAndChain(ctls, andChainTarget); + use helper = Qubit[andChain.NGarbageQubits]; + + within { + andChain.Apply(helper); + } apply { + SinglyControlledSelect(andChainTarget, data, address, target); + } + } + } + + controlled adjoint (ctls, ...) { + Controlled Select(ctls, (data, address, target)); + } + } + + internal operation SinglyControlledSelect( + ctl : Qubit, + data : Bool[][], + address : Qubit[], + target : Qubit[] + ) : Unit { + let (N, n) = DimensionsForSelect(data, address); + + if BeginEstimateCaching("Microsoft.Quantum.Unstable.TableLookup.SinglyControlledSelect", N) { + if N == 1 { + // base case + Controlled WriteMemoryContents([ctl], (Head(data), target)); + } else { + use helper = Qubit(); + + let (most, tail) = MostAndTail(address[...n - 1]); + let parts = Partitioned([2^(n - 1)], data); + + within { + X(tail); + } apply { + ApplyAndAssuming0Target(ctl, tail, helper); + } + + SinglyControlledSelect(helper, parts[0], most, target); + + CNOT(ctl, helper); + + SinglyControlledSelect(helper, parts[1], most, target); + + Adjoint ApplyAndAssuming0Target(ctl, tail, helper); + } + + EndEstimateCaching(); + } + } + + internal function DimensionsForSelect( + data : Bool[][], + address : Qubit[] + ) : (Int, Int) { + let N = Length(data); + Fact(N > 0, "data cannot be empty"); + + let n = Ceiling(Lg(IntAsDouble(N))); + Fact( + Length(address) >= n, + $"address register is too small, requires at least {n} qubits" + ); + + return (N, n); + } + + internal operation WriteMemoryContents( + value : Bool[], + target : Qubit[] + ) : Unit is Adj + Ctl { + Fact( + Length(value) == Length(target), + "number of data bits must equal number of target qubits" + ); + + ApplyPauliFromBitString(PauliX, true, value, target); + } + + /// # References + /// - [arXiv:1905.07682](https://arxiv.org/abs/1905.07682) + /// "Windowed arithmetic" + internal operation Unlookup( + lookup : (Bool[][], Qubit[], Qubit[]) => Unit, + data : Bool[][], + select : Qubit[], + target : Qubit[] + ) : Unit { + let numBits = Length(target); + let numAddressBits = Length(select); + + let l = MinI(Floor(Lg(IntAsDouble(numBits))), numAddressBits - 1); + Fact( + l < numAddressBits, + $"l = {l} must be smaller than {numAddressBits}" + ); + + let res = Mapped(r -> r == One, ForEach(MResetX, target)); + + let dataFixup = Chunks(2^l, Padded(-2^numAddressBits, false, Mapped(MustBeFixed(res, _), data))); + + let numAddressBitsFixup = numAddressBits - l; + + let selectParts = Partitioned([l], select); + let targetFixup = target[...2^l - 1]; + + within { + EncodeUnary(selectParts[0], targetFixup); + ApplyToEachA(H, targetFixup); + } apply { + lookup(dataFixup, selectParts[1], targetFixup); + } + } + + // Checks whether specific bit string `data` must be fixed for a given + // measurement result `result`. + // + // Returns true if the number of indices for which both result and data are + // `true` is odd. + internal function MustBeFixed(result : Bool[], data : Bool[]) : Bool { + mutable state = false; + for i in IndexRange(result) { + set state = state != (result[i] and data[i]); + } + state + } + + // Computes unary encoding of value in `input` into `target` + // + // Assumptions: + // - `target` is zero-initialized + // - length of `input` is n + // - length of `target` is 2^n + internal operation EncodeUnary( + input : Qubit[], + target : Qubit[] + ) : Unit is Adj { + Fact( + Length(target) == 2^Length(input), + $"target register should be of length {2^Length(input)}, but is {Length(target)}" + ); + + X(Head(target)); + + for i in IndexRange(input) { + if i == 0 { + CNOT(input[i], target[1]); + CNOT(target[1], target[0]); + } else { + // targets are the first and second 2^i qubits of the target register + let split = Partitioned([2^i, 2^i], target); + for j in IndexRange(split[0]) { + ApplyAndAssuming0Target(input[i], split[0][j], split[1][j]); + CNOT(split[1][j], split[0][j]); + } + } + } + + } + + internal newtype AndChain = ( + NGarbageQubits : Int, + Apply : Qubit[] => Unit is Adj + ); + + internal function MakeAndChain(ctls : Qubit[], target : Qubit) : AndChain { + AndChain( + MaxI(Length(ctls) - 2, 0), + helper => AndChainOperation(ctls, helper, target) + ) + } + + internal operation AndChainOperation(ctls : Qubit[], helper : Qubit[], target : Qubit) : Unit is Adj { + let n = Length(ctls); + + Fact(Length(helper) == MaxI(n - 2, 0), "Invalid number of helper qubits"); + + if n == 0 { + X(target); + } elif n == 1 { + CNOT(ctls[0], target); + } else { + let ctls1 = ctls[0..0] + helper; + let ctls2 = ctls[1...]; + let tgts = helper + [target]; + + for idx in IndexRange(tgts) { + ApplyAndAssuming0Target(ctls1[idx], ctls2[idx], tgts[idx]); + } + } + } + + export Select; +} From f878951fa883d9e613d05ae2e1df559dd8c466f2 Mon Sep 17 00:00:00 2001 From: sezna Date: Tue, 10 Sep 2024 14:28:28 -0700 Subject: [PATCH 12/29] remove opens --- library/std/src/Std/Arrays.qs | 4 ++-- library/std/src/Std/Canon.qs | 6 +++--- library/std/src/Std/Convert.qs | 4 ++-- library/std/src/Std/InternalHelpers.qs | 4 ++-- library/std/src/Std/Intrinsic.qs | 8 ++++---- library/std/src/Std/Math.qs | 4 ++-- library/std/src/Std/Measurement.qs | 6 +++--- library/std/src/unstable_arithmetic.qs | 8 ++++---- library/std/src/unstable_arithmetic_internal.qs | 8 ++++---- library/std/src/unstable_state_preparation.qs | 8 ++++---- library/std/src/unstable_table_lookup.qs | 12 ++++++------ 11 files changed, 36 insertions(+), 36 deletions(-) diff --git a/library/std/src/Std/Arrays.qs b/library/std/src/Std/Arrays.qs index f2a572b96b..bd099bda12 100644 --- a/library/std/src/Std/Arrays.qs +++ b/library/std/src/Std/Arrays.qs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -open Microsoft.Quantum.Diagnostics; -open Microsoft.Quantum.Math; +import Std.Diagnostics.*; +import Std.Math.*; /// # Summary /// Given an array and a predicate that is defined diff --git a/library/std/src/Std/Canon.qs b/library/std/src/Std/Canon.qs index be7def9b1b..944a36c255 100644 --- a/library/std/src/Std/Canon.qs +++ b/library/std/src/Std/Canon.qs @@ -3,9 +3,9 @@ import QIR.Intrinsic.*; -open Microsoft.Quantum.Intrinsic; -open Microsoft.Quantum.Diagnostics; -open Microsoft.Quantum.Math; +import Std.Intrinsic.*; +import Std.Diagnostics.*; +import Std.Math.*; /// # Summary /// Applies an operation to each element in a register. diff --git a/library/std/src/Std/Convert.qs b/library/std/src/Std/Convert.qs index 46ab3a3715..08d2a1568e 100644 --- a/library/std/src/Std/Convert.qs +++ b/library/std/src/Std/Convert.qs @@ -1,5 +1,5 @@ -open Microsoft.Quantum.Diagnostics; -open Microsoft.Quantum.Math; +import Std.Diagnostics.*; +import Std.Math.*; /// # Summary /// Converts a given integer `number` to an equivalent diff --git a/library/std/src/Std/InternalHelpers.qs b/library/std/src/Std/InternalHelpers.qs index 62fc0acb30..61da81a939 100644 --- a/library/std/src/Std/InternalHelpers.qs +++ b/library/std/src/Std/InternalHelpers.qs @@ -3,8 +3,8 @@ import Std.Arrays.*; -open Microsoft.Quantum.Core; -open Microsoft.Quantum.Math; +import Std.Core.*; +import Std.Math.*; import Std.Intrinsic.*; import QIR.Intrinsic.*; diff --git a/library/std/src/Std/Intrinsic.qs b/library/std/src/Std/Intrinsic.qs index 2e177663c9..03f5524ff9 100644 --- a/library/std/src/Std/Intrinsic.qs +++ b/library/std/src/Std/Intrinsic.qs @@ -2,10 +2,10 @@ // Licensed under the MIT License. -open Microsoft.Quantum.Convert; -open Microsoft.Quantum.Core; -open Microsoft.Quantum.Diagnostics; -open Microsoft.Quantum.Math; +import Std.Convert.*; +import Std.Core.*; +import Std.Diagnostics.*; +import Std.Math.*; open QIR.Intrinsic; import Std.InternalHelpers.*; diff --git a/library/std/src/Std/Math.qs b/library/std/src/Std/Math.qs index d046f91908..9022c04e6b 100644 --- a/library/std/src/Std/Math.qs +++ b/library/std/src/Std/Math.qs @@ -2,8 +2,8 @@ // Licensed under the MIT License. -open Microsoft.Quantum.Convert; -open Microsoft.Quantum.Diagnostics; +import Std.Convert.*; +import Std.Diagnostics.*; // // Constants PI, E, LogOf2. diff --git a/library/std/src/Std/Measurement.qs b/library/std/src/Std/Measurement.qs index a37580b552..2b538d8554 100644 --- a/library/std/src/Std/Measurement.qs +++ b/library/std/src/Std/Measurement.qs @@ -2,9 +2,9 @@ // Licensed under the MIT License. -open Microsoft.Quantum.Core; -open Microsoft.Quantum.Intrinsic; -open Microsoft.Quantum.Diagnostics; +import Std.Core.*; +import Std.Intrinsic.*; +import Std.Diagnostics.*; open QIR.Intrinsic; /// # Summary 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 From 59bff76f5c93bdb175bfe52be8e66545d409d751 Mon Sep 17 00:00:00 2001 From: sezna Date: Tue, 10 Sep 2024 14:33:59 -0700 Subject: [PATCH 13/29] update tests --- compiler/qsc_partial_eval/src/tests/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/qsc_partial_eval/src/tests/misc.rs b/compiler/qsc_partial_eval/src/tests/misc.rs index c5ea3bf262..0fed1f6c98 100644 --- a/compiler/qsc_partial_eval/src/tests/misc.rs +++ b/compiler/qsc_partial_eval/src/tests/misc.rs @@ -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: 13926, hi: 13941 } })"]); + assert_error(&error, &expect!["UnexpectedDynamicValue(PackageSpan { package: PackageId(1), span: Span { lo: 13654, hi: 13669 } })"]); } From 22b6ffcdb64e539f08a4e5291665d7946e071488 Mon Sep 17 00:00:00 2001 From: sezna Date: Tue, 10 Sep 2024 14:56:50 -0700 Subject: [PATCH 14/29] clippy --- language_service/src/completion.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/language_service/src/completion.rs b/language_service/src/completion.rs index 89bc081016..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(|x| Rc::from(*x)).collect(), + path: ns.iter().map(|x| Rc::from(*x)).collect(), alias: None, is_glob: true, }) From e6de5affe1dbbebdcad1052e42453d94e9fdc906 Mon Sep 17 00:00:00 2001 From: sezna Date: Tue, 10 Sep 2024 15:18:55 -0700 Subject: [PATCH 15/29] fix basics.js test --- npm/qsharp/test/basics.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index 4e5178e7f0..c9caca95ed 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++; } From 0e7f0f75140c35a0a139c8825a34622635c1f570 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Wed, 11 Sep 2024 14:11:00 -0700 Subject: [PATCH 16/29] update integration test --- vscode/test/suites/debugger/debugger.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode/test/suites/debugger/debugger.test.ts b/vscode/test/suites/debugger/debugger.test.ts index 084a0a36c1..9b32a57c85 100644 --- a/vscode/test/suites/debugger/debugger.test.ts +++ b/vscode/test/suites/debugger/debugger.test.ts @@ -371,7 +371,7 @@ suite("Q# Debugger Tests", function suite() { id: 1, source: { name: "intrinsic.qs", - path: "qsharp-library-source:intrinsic.qs", + path: "qsharp-library-source:Std/Intrinsic.qs", sourceReference: 0, adapterData: "qsharp-adapter-data", }, @@ -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"), ); }); From 2a8f221eef8c01cbb6d7ab1c1625ac86415f00df Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Wed, 11 Sep 2024 15:26:55 -0700 Subject: [PATCH 17/29] update integration tests --- vscode/test/suites/debugger/debugger.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vscode/test/suites/debugger/debugger.test.ts b/vscode/test/suites/debugger/debugger.test.ts index 9b32a57c85..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", + 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, From 343a3769810f2a621b1111ece17273006dd89860 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Fri, 13 Sep 2024 10:20:36 -0700 Subject: [PATCH 18/29] pr feedback --- compiler/qsc_frontend/src/resolve/tests.rs | 14 +++++++------ library/src/tests/resources/src/qft_le.qs | 2 +- library/std/src/QIR/Intrinsic.qs | 24 +++++++++++++++++++++- library/std/src/Std/Diagnostics.qs | 14 ++++++++++++- library/std/src/Std/ResourceEstimation.qs | 16 ++++++++++++++- 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/compiler/qsc_frontend/src/resolve/tests.rs b/compiler/qsc_frontend/src/resolve/tests.rs index d5cccb7ef2..e77c785121 100644 --- a/compiler/qsc_frontend/src/resolve/tests.rs +++ b/compiler/qsc_frontend/src/resolve/tests.rs @@ -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,19 +513,21 @@ fn ambiguous_prelude() { } "}, &expect![[r#" - namespace namespace8 { + namespace namespace2 { function item1() : Unit {} } - namespace namespace5 { + namespace namespace7 { function item3() : Unit {} } - namespace namespace9 { + namespace namespace8 { function item5() : Unit { - item3(); + A(); } } + + // AmbiguousPrelude { name: "A", candidate_a: "Std.Canon", candidate_b: "Std.Measurement", span: Span { lo: 160, hi: 161 } } "#]], ); } diff --git a/library/src/tests/resources/src/qft_le.qs b/library/src/tests/resources/src/qft_le.qs index dde380be58..038006ac1e 100644 --- a/library/src/tests/resources/src/qft_le.qs +++ b/library/src/tests/resources/src/qft_le.qs @@ -1,5 +1,5 @@ namespace Test { - open Microsoft.Quantum.Diagnostics; + import Std.Diagnostics.*; import Std.Arrays.*; operation PrepareEntangledState( diff --git a/library/std/src/QIR/Intrinsic.qs b/library/std/src/QIR/Intrinsic.qs index d6304a39f2..d2f0c74209 100644 --- a/library/std/src/QIR/Intrinsic.qs +++ b/library/std/src/QIR/Intrinsic.qs @@ -101,4 +101,26 @@ 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; +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/Diagnostics.qs b/library/std/src/Std/Diagnostics.qs index 127d05b4f2..2b9d40b5c0 100644 --- a/library/std/src/Std/Diagnostics.qs +++ b/library/std/src/Std/Diagnostics.qs @@ -317,4 +317,16 @@ operation StopCountingQubits() : Int { body intrinsic; } -export DumpMachine, DumpRegister, CheckZero, CheckAllZero, Fact, CheckOperationsAreEqual, StartCountingOperation, StopCountingOperation, StartCountingFunction, StopCountingFunction, StartCountingQubits, StopCountingQubits; \ No newline at end of file +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/ResourceEstimation.qs b/library/std/src/Std/ResourceEstimation.qs index 6dfd5540fd..f0da84c88e 100644 --- a/library/std/src/Std/ResourceEstimation.qs +++ b/library/std/src/Std/ResourceEstimation.qs @@ -166,4 +166,18 @@ operation RepeatEstimates(count : Int) : Unit is Adj { EndRepeatEstimates(); } } -export SingleVariant, BeginEstimateCaching, EndEstimateCaching, AuxQubitCount, TCount, RotationCount, RotationDepth, CczCount, MeasurementCount, PSSPCLayout, AccountForEstimates, BeginRepeatEstimates, EndRepeatEstimates, RepeatEstimates; +export + SingleVariant, + BeginEstimateCaching, + EndEstimateCaching, + AuxQubitCount, + TCount, + RotationCount, + RotationDepth, + CczCount, + MeasurementCount, + PSSPCLayout, + AccountForEstimates, + BeginRepeatEstimates, + EndRepeatEstimates, + RepeatEstimates; From 64906c4183abe7727938a77c34ef26ec5470c3c5 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Fri, 13 Sep 2024 10:54:07 -0700 Subject: [PATCH 19/29] update all non-katas code to use import instead of open --- 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 | 14 ++-- compiler/qsc_codegen/src/qsharp/tests.rs | 24 +++--- compiler/qsc_eval/src/intrinsic/tests.rs | 2 +- compiler/qsc_formatter/src/formatter/tests.rs | 6 +- compiler/qsc_frontend/src/compile/tests.rs | 8 +- compiler/qsc_frontend/src/resolve/tests.rs | 4 +- compiler/qsc_parse/src/item/tests.rs | 2 +- compiler/qsc_partial_eval/src/tests/calls.rs | 10 +-- .../qsc_partial_eval/src/tests/intrinsics.rs | 24 +++--- compiler/qsc_partial_eval/src/tests/misc.rs | 2 +- .../qsc_partial_eval/src/tests/returns.rs | 8 +- .../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/tests.rs | 2 +- library/src/tests.rs | 8 +- library/src/tests/arithmetic.rs | 46 +++++------ library/src/tests/convert.rs | 4 +- library/src/tests/diagnostics.rs | 2 +- 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/select.qs | 8 +- .../tests/resources/src/state_preparation.qs | 8 +- library/src/tests/state_preparation.rs | 2 +- npm/qsharp/test/basics.js | 4 +- 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 +- wasm/src/tests.rs | 8 +- 106 files changed, 420 insertions(+), 420 deletions(-) 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 82ef545884..68bf62ea81 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 { @@ -262,7 +262,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 { @@ -477,7 +477,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 bf037ed1fa..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()] "#]], @@ -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_codegen/src/qsharp/tests.rs b/compiler/qsc_codegen/src/qsharp/tests.rs index 4e27d41bcd..9fb9155a0f 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_eval/src/intrinsic/tests.rs b/compiler/qsc_eval/src/intrinsic/tests.rs index 1746c0578f..a43ba6c6f8 100644 --- a/compiler/qsc_eval/src/intrinsic/tests.rs +++ b/compiler/qsc_eval/src/intrinsic/tests.rs @@ -544,7 +544,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..89e3510197 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 @@ -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/resolve/tests.rs b/compiler/qsc_frontend/src/resolve/tests.rs index e77c785121..06cc4a8dec 100644 --- a/compiler/qsc_frontend/src/resolve/tests.rs +++ b/compiler/qsc_frontend/src/resolve/tests.rs @@ -2080,12 +2080,12 @@ fn unknown_namespace() { check( indoc! {" namespace A { - open Microsoft.Quantum.Fake; + import Std.Fake.*; } "}, &expect![[r#" namespace namespace8 { - open Microsoft.Quantum.Fake; + import Std.Fake.*; } // NotFound("Microsoft.Quantum.Fake", Span { lo: 23, hi: 45 }) diff --git a/compiler/qsc_parse/src/item/tests.rs b/compiler/qsc_parse/src/item/tests.rs index 782e68918c..8919b08b11 100644 --- a/compiler/qsc_parse/src/item/tests.rs +++ b/compiler/qsc_parse/src/item/tests.rs @@ -1751,7 +1751,7 @@ fn helpful_error_on_dotted_alias() { check_vec( parse_namespaces, "namespace A { - open Microsoft.Quantum.Math as Foo.Bar.Baz; + import Std.Math as Foo.Bar.Baz.*; operation Main() : Unit {} }", &expect![[r#" diff --git a/compiler/qsc_partial_eval/src/tests/calls.rs b/compiler/qsc_partial_eval/src/tests/calls.rs index 9dfa3c7c77..abb17c5203 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); } @@ -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 @@ -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) } @@ -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 0fed1f6c98..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]; diff --git a/compiler/qsc_partial_eval/src/tests/returns.rs b/compiler/qsc_partial_eval/src/tests/returns.rs index 8aeb6b3f6f..45f993c86d 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. @@ -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. @@ -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. @@ -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. 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/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/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 208e3c6c48..449cd25a1e 100644 --- a/library/src/tests/diagnostics.rs +++ b/library/src/tests/diagnostics.rs @@ -8,7 +8,7 @@ use qsc::interpret::Value; fn check_operations_are_equal() { test_expression( "{ - open Microsoft.Quantum.Diagnostics; + 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/select.qs b/library/src/tests/resources/src/select.qs index 29793efd9b..7d70a523ea 100644 --- a/library/src/tests/resources/src/select.qs +++ b/library/src/tests/resources/src/select.qs @@ -1,9 +1,9 @@ namespace Test { import Std.Arrays.*; - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Diagnostics; - open Microsoft.Quantum.Random; - open Microsoft.Quantum.Unstable.TableLookup; + 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 7be1024314..b9400f3b06 100644 --- a/library/src/tests/resources/src/state_preparation.qs +++ b/library/src/tests/resources/src/state_preparation.qs @@ -1,9 +1,9 @@ namespace Test { - open Microsoft.Quantum.Convert; - open Microsoft.Quantum.Math; - open Microsoft.Quantum.Diagnostics; + import Std.Convert.*; + import Std.Math.*; + import Std.Diagnostics.*; import Std.Arrays.*; - open Microsoft.Quantum.Unstable.StatePreparation; + import Microsoft.Quantum.Unstable.StatePreparation.*; import QIR.Intrinsic.*; 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/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index c9caca95ed..27fe6ac819 100644 --- a/npm/qsharp/test/basics.js +++ b/npm/qsharp/test/basics.js @@ -398,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[] { @@ -551,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 86838e1899..cefa028ae7 100644 --- a/pip/tests/test_interpreter.py +++ b/pip/tests/test_interpreter.py @@ -334,7 +334,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 { @@ -398,7 +398,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/wasm/src/tests.rs b/wasm/src/tests.rs index 0f22f22361..d79ba56723 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() From 98789153ff221de071977547ff8590cdf8b31a07 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Fri, 13 Sep 2024 11:17:21 -0700 Subject: [PATCH 20/29] update codegen tests --- compiler/qsc_codegen/src/qsharp/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/qsc_codegen/src/qsharp/tests.rs b/compiler/qsc_codegen/src/qsharp/tests.rs index 9fb9155a0f..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 { - import Std.Intrinsic as sics.*; + import Std.Intrinsic as sics; import Std.Diagnostics.*; - import Std.Intrinsic as intrin.*; + import Std.Intrinsic as intrin; @EntryPoint() operation Entry() : Unit { } @@ -51,9 +51,9 @@ fn open() { None, &expect![[r#" namespace Sample { - import Std.Intrinsic as sics.*; + import Std.Intrinsic as sics; import Std.Diagnostics.*; - import Std.Intrinsic as intrin.*; + import Std.Intrinsic as intrin; @EntryPoint() operation Entry() : Unit {} }"#]], From c11543632a5985a53b9e9f9624f94ec6504c9b1f Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Fri, 13 Sep 2024 12:31:34 -0700 Subject: [PATCH 21/29] fix codegen bug --- compiler/qsc_codegen/src/qsharp.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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(";"); } } From d661795057bd1cb2f85b03fe379ce9a5c5b22748 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Fri, 13 Sep 2024 14:23:18 -0700 Subject: [PATCH 22/29] update tests --- compiler/qsc_frontend/src/compile/tests.rs | 4 ++-- compiler/qsc_frontend/src/resolve/tests.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/qsc_frontend/src/compile/tests.rs b/compiler/qsc_frontend/src/compile/tests.rs index 89e3510197..77d7ea699f 100644 --- a/compiler/qsc_frontend/src/compile/tests.rs +++ b/compiler/qsc_frontend/src/compile/tests.rs @@ -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, }, ), ), diff --git a/compiler/qsc_frontend/src/resolve/tests.rs b/compiler/qsc_frontend/src/resolve/tests.rs index 06cc4a8dec..7024c6dd5f 100644 --- a/compiler/qsc_frontend/src/resolve/tests.rs +++ b/compiler/qsc_frontend/src/resolve/tests.rs @@ -2088,7 +2088,7 @@ fn unknown_namespace() { import Std.Fake.*; } - // NotFound("Microsoft.Quantum.Fake", Span { lo: 23, hi: 45 }) + // GlobImportNamespaceNotFound("Fake", Span { lo: 25, hi: 33 }) "#]], ); } From 83c25bc96ec6f627e2a8ef5673eba6eb540ab026 Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Fri, 13 Sep 2024 14:23:18 -0700 Subject: [PATCH 23/29] update tests --- compiler/qsc_frontend/src/compile/tests.rs | 4 ++-- compiler/qsc_frontend/src/resolve/tests.rs | 2 +- compiler/qsc_parse/src/item/tests.rs | 2 +- library/fixed_point/qsharp.json | 9 ++------- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/qsc_frontend/src/compile/tests.rs b/compiler/qsc_frontend/src/compile/tests.rs index 89e3510197..77d7ea699f 100644 --- a/compiler/qsc_frontend/src/compile/tests.rs +++ b/compiler/qsc_frontend/src/compile/tests.rs @@ -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, }, ), ), diff --git a/compiler/qsc_frontend/src/resolve/tests.rs b/compiler/qsc_frontend/src/resolve/tests.rs index 06cc4a8dec..7024c6dd5f 100644 --- a/compiler/qsc_frontend/src/resolve/tests.rs +++ b/compiler/qsc_frontend/src/resolve/tests.rs @@ -2088,7 +2088,7 @@ fn unknown_namespace() { import Std.Fake.*; } - // NotFound("Microsoft.Quantum.Fake", Span { lo: 23, hi: 45 }) + // GlobImportNamespaceNotFound("Fake", Span { lo: 25, hi: 33 }) "#]], ); } diff --git a/compiler/qsc_parse/src/item/tests.rs b/compiler/qsc_parse/src/item/tests.rs index 8919b08b11..782e68918c 100644 --- a/compiler/qsc_parse/src/item/tests.rs +++ b/compiler/qsc_parse/src/item/tests.rs @@ -1751,7 +1751,7 @@ fn helpful_error_on_dotted_alias() { check_vec( parse_namespaces, "namespace A { - import Std.Math as Foo.Bar.Baz.*; + open Microsoft.Quantum.Math as Foo.Bar.Baz; operation Main() : Unit {} }", &expect![[r#" 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 From f2787df609c5baca8a2cef7a89f3c4e51527470b Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Fri, 13 Sep 2024 14:56:28 -0700 Subject: [PATCH 24/29] update spans --- compiler/qsc_partial_eval/src/tests/calls.rs | 6 +- .../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 +++++++++--------- wasm/src/tests.rs | 2 +- 6 files changed, 132 insertions(+), 140 deletions(-) diff --git a/compiler/qsc_partial_eval/src/tests/calls.rs b/compiler/qsc_partial_eval/src/tests/calls.rs index abb17c5203..f614c7120c 100644 --- a/compiler/qsc_partial_eval/src/tests/calls.rs +++ b/compiler/qsc_partial_eval/src/tests/calls.rs @@ -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 }))"], ); } @@ -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 } })"], ); } @@ -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 }))"], ); } diff --git a/compiler/qsc_partial_eval/src/tests/returns.rs b/compiler/qsc_partial_eval/src/tests/returns.rs index 45f993c86d..fc3108f61c 100644 --- a/compiler/qsc_partial_eval/src/tests/returns.rs +++ b/compiler/qsc_partial_eval/src/tests/returns.rs @@ -898,9 +898,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 } })"# - ]], + &expect![[r#"Unexpected("updating a field of a dynamic user-defined type is invalid", PackageSpan { package: PackageId(2), span: Span { lo: 207, hi: 233 } })"#]], ); } @@ -981,9 +979,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 } })"# - ]], + &expect![[r#"Unexpected("embedded return in call arguments", PackageSpan { package: PackageId(2), span: Span { lo: 164, hi: 176 } })"#]], ); } @@ -1004,9 +1000,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 } })"# - ]], + &expect![[r#"Unexpected("embedded return in if condition", PackageSpan { package: PackageId(2), span: Span { lo: 165, hi: 177 } })"#]], ); } @@ -1087,9 +1081,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 } })"# - ]], + &expect![[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/wasm/src/tests.rs b/wasm/src/tests.rs index d79ba56723..b7d5bd27b0 100644 --- a/wasm/src/tests.rs +++ b/wasm/src/tests.rs @@ -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")); } From f16998a32ae09913e6b28c2165f289eb39f3f0ad Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Fri, 13 Sep 2024 17:54:17 -0700 Subject: [PATCH 25/29] update basics test --- npm/qsharp/test/basics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index 27fe6ac819..d39ee97820 100644 --- a/npm/qsharp/test/basics.js +++ b/npm/qsharp/test/basics.js @@ -492,7 +492,7 @@ test("diagnostics with related spans", async () => { { code: "Qsc.Resolve.Ambiguous", message: - "name error: `DumpMachine` could refer to the item in `Microsoft.Quantum.Diagnostics` or `Other`", + "name error: `DumpMachine` could refer to the item in `Std.Diagnostics` or `Other`", related: [ { message: "ambiguous name", From 0bca193975a381811fe9e700f373587c3a4b7f2f Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Mon, 16 Sep 2024 10:31:47 -0700 Subject: [PATCH 26/29] sanity check --- npm/qsharp/test/basics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index d39ee97820..5f84e59b0e 100644 --- a/npm/qsharp/test/basics.js +++ b/npm/qsharp/test/basics.js @@ -492,7 +492,7 @@ test("diagnostics with related spans", async () => { { code: "Qsc.Resolve.Ambiguous", message: - "name error: `DumpMachine` could refer to the item in `Std.Diagnostics` or `Other`", + "name error: `DumpMachine` could refer to the item in `FOO` or `Other`", related: [ { message: "ambiguous name", From 6ecc2be5c7eeb98d0af62985c72f6dd2cbb37b8e Mon Sep 17 00:00:00 2001 From: Alexander Hansen Date: Mon, 16 Sep 2024 11:10:33 -0700 Subject: [PATCH 27/29] Sanity check??? --- npm/qsharp/test/basics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index 5f84e59b0e..27fe6ac819 100644 --- a/npm/qsharp/test/basics.js +++ b/npm/qsharp/test/basics.js @@ -492,7 +492,7 @@ test("diagnostics with related spans", async () => { { code: "Qsc.Resolve.Ambiguous", message: - "name error: `DumpMachine` could refer to the item in `FOO` or `Other`", + "name error: `DumpMachine` could refer to the item in `Microsoft.Quantum.Diagnostics` or `Other`", related: [ { message: "ambiguous name", From 8973d25fe430ddeb13afa1323668c8d18a9f53fa Mon Sep 17 00:00:00 2001 From: sezna Date: Tue, 17 Sep 2024 10:23:57 -0700 Subject: [PATCH 28/29] fix tests --- npm/qsharp/test/basics.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm/qsharp/test/basics.js b/npm/qsharp/test/basics.js index 27fe6ac819..4edca62089 100644 --- a/npm/qsharp/test/basics.js +++ b/npm/qsharp/test/basics.js @@ -511,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, }, }, From 9647ce9299dd971a888f4841044abf703abc29ee Mon Sep 17 00:00:00 2001 From: sezna Date: Tue, 17 Sep 2024 11:02:41 -0700 Subject: [PATCH 29/29] Fmt --- library/std/src/Std/Canon.qs | 57 ++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/library/std/src/Std/Canon.qs b/library/std/src/Std/Canon.qs index 8a9c2f753d..49fde0c17e 100644 --- a/library/std/src/Std/Canon.qs +++ b/library/std/src/Std/Canon.qs @@ -32,7 +32,7 @@ operation ApplyToEach<'T>(singleElementOperation : ('T => Unit), register : 'T[] } } - /// # Summary +/// # Summary /// Applies an operation to each element in a register. /// The modifier `A` indicates that the single-element operation is adjointable. /// @@ -61,7 +61,7 @@ operation ApplyToEachA<'T>(singleElementOperation : ('T => Unit is Adj), registe } } - /// # Summary +/// # Summary /// Applies an operation to each element in a register. /// The modifier `C` indicates that the single-element operation is controllable. /// @@ -90,7 +90,7 @@ operation ApplyToEachC<'T>(singleElementOperation : ('T => Unit is Ctl), registe } } - /// # Summary +/// # Summary /// Applies an operation to each element in a register. /// The modifier `CA` indicates that the single-element operation is controllable and adjointable. /// @@ -119,7 +119,7 @@ operation ApplyToEachCA<'T>(singleElementOperation : ('T => Unit is Adj + Ctl), } } - /// # Summary +/// # Summary /// Applies the controlled-X (CX) gate to a pair of qubits. /// /// # Input @@ -160,7 +160,7 @@ operation CX(control : Qubit, target : Qubit) : Unit is Adj + Ctl { adjoint self; } - /// # Summary +/// # Summary /// Applies the controlled-Y (CY) gate to a pair of qubits. /// /// # Input @@ -197,7 +197,7 @@ operation CY(control : Qubit, target : Qubit) : Unit is Adj + Ctl { adjoint self; } - /// # Summary +/// # Summary /// Applies the controlled-Z (CZ) gate to a pair of qubits. /// /// # Input @@ -246,7 +246,7 @@ function Snd<'T, 'U>(pair : ('T, 'U)) : 'U { return snd; } - /// # Summary +/// # Summary /// Computes the parity of a register of qubits in-place. /// /// # Input @@ -268,7 +268,7 @@ operation ApplyCNOTChain(qubits : Qubit[]) : Unit is Adj + Ctl { } } - /// # Summary +/// # Summary /// Given a single-qubit Pauli operator, applies the corresponding operation /// to a single qubit. /// @@ -291,7 +291,7 @@ 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 +/// # Summary /// Given a multi-qubit Pauli operator, applies the corresponding operation /// to a quantum register. /// @@ -319,7 +319,7 @@ operation ApplyPauli(pauli : Pauli[], target : Qubit[]) : Unit is Adj + Ctl { } } - /// # Summary +/// # Summary /// Applies a Pauli operator on each qubit in an array if the corresponding /// bit of a Boolean array matches a given input. /// @@ -356,7 +356,7 @@ operation ApplyPauliFromBitString(pauli : Pauli, bitApply : Bool, bits : Bool[], } } - /// # Summary +/// # Summary /// Applies a Pauli operator on each qubit in an array if the corresponding /// bit of a Little-endian integer matches a given input. /// @@ -400,7 +400,7 @@ operation ApplyPauliFromInt( } } - /// # Summary +/// # Summary /// Applies a unitary operation on the target if the control /// register state corresponds to a specified nonnegative integer. /// @@ -435,7 +435,7 @@ operation ApplyControlledOnInt<'T>( } } - /// # Summary +/// # Summary /// Applies `oracle` on `target` when `controlRegister` /// is in the state specified by `bits`. /// @@ -488,7 +488,7 @@ operation ApplyControlledOnBitString<'T>( } } - /// # Summary +/// # Summary /// Applies the rotations of Quantum Fourier Transform (QFT) to a little-endian quantum register. /// /// # Description @@ -519,7 +519,7 @@ operation ApplyQFT(qs : Qubit[]) : Unit is Adj + Ctl { } } - /// # Summary +/// # Summary /// Uses SWAP gates to reverse the order of the qubits in a register. /// /// # Input @@ -532,7 +532,7 @@ operation SwapReverseRegister(register : Qubit[]) : Unit is Adj + Ctl { } } - /// # Summary +/// # Summary /// Applies a bitwise-XOR operation between a classical integer and an /// integer represented by a register of qubits. /// @@ -558,7 +558,7 @@ operation ApplyXorInPlace(value : Int, target : Qubit[]) : Unit is Adj + Ctl { adjoint self; } - /// # Summary +/// # Summary /// Applies a bitwise-XOR operation between a classical integer and an /// integer represented by a register of qubits. /// @@ -626,4 +626,25 @@ 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; +export + ApplyToEach, + ApplyToEachA, + ApplyToEachC, + ApplyToEachCA, + CX, + CY, + CZ, + Fst, + Snd, + ApplyCNOTChain, + ApplyP, + ApplyPauli, + ApplyPauliFromBitString, + ApplyPauliFromInt, + ApplyControlledOnInt, + ApplyControlledOnBitString, + ApplyQFT, + SwapReverseRegister, + ApplyXorInPlace, + ApplyXorInPlaceL, + Relabel;