From ce2acf6c73d817e3b5ffaa78f7ff8afcfcd8b2b6 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 1 Sep 2020 10:21:16 +0200 Subject: [PATCH 01/17] Unzipped function. --- Standard/src/Arrays/Zip.qs | 34 ++++++++++++++++++++++++++++++++++ Standard/tests/ArrayTests.qs | 10 ++++++++++ 2 files changed, 44 insertions(+) diff --git a/Standard/src/Arrays/Zip.qs b/Standard/src/Arrays/Zip.qs index caa785a2ba5..9578ac2bdf0 100644 --- a/Standard/src/Arrays/Zip.qs +++ b/Standard/src/Arrays/Zip.qs @@ -131,6 +131,40 @@ namespace Microsoft.Quantum.Arrays { return output; } + /// # 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 + /// ## arr + /// 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 + /// ```Q# + /// // split is same as ([6, 5, 5, 3, 2, 1], [true, false, false, false, true, false]) + /// let split = Unzipped([(6, true), (5, false), (5, false), (3, false), (2, true), (1, false)]); + /// ``` + function Unzipped<'T, 'U>(arr : ('T, 'U)[]) : ('T[], 'U[]) { + let nElements = Length(arr); + mutable first = new 'T[nElements]; + mutable second = new 'U[nElements]; + for (idxElement in 0 .. nElements - 1) { + let (left, right) = arr[idxElement]; + set first w/= idxElement <- left; + set second w/= idxElement <- right; + } + return (first, second); + } } diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 5dbadf4d724..44a2f00965b 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -26,6 +26,16 @@ namespace Microsoft.Quantum.Tests { } } + @Test("QuantumSimulator") + function UnzippedTest() : Unit { + let first = [6, 5, 5, 3, 2, 1]; + let second = [true, false, false, false, true, false]; + + let (first2, second2) = Unzipped(Zip(first, second)); + AllEqualityFactI(first2, first, "Unexpected array of integers"); + AllEqualityFactB(second2, second, "Unexpected array of Booleans"); + } + @Test("QuantumSimulator") function LookupTest () : Unit { From 3e25f94f500ffdac331841eeed17616eed49a82c Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Wed, 2 Sep 2020 12:52:01 +0200 Subject: [PATCH 02/17] Incorporating Chris' feedback. --- Standard/src/Arrays/Zip.qs | 4 ++++ Standard/tests/ArrayTests.qs | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Standard/src/Arrays/Zip.qs b/Standard/src/Arrays/Zip.qs index 9578ac2bdf0..1d2585a518e 100644 --- a/Standard/src/Arrays/Zip.qs +++ b/Standard/src/Arrays/Zip.qs @@ -36,6 +36,7 @@ namespace Microsoft.Quantum.Arrays { /// # See Also /// - Zip3 /// - Zip4 + /// - Unzipped function Zip<'T, 'U> (left : 'T[], right : 'U[]) : ('T, 'U)[] { let nElements = Length(left) < Length(right) ? Length(left) @@ -154,6 +155,9 @@ namespace Microsoft.Quantum.Arrays { /// // split is same as ([6, 5, 5, 3, 2, 1], [true, false, false, false, true, false]) /// let split = Unzipped([(6, true), (5, false), (5, false), (3, false), (2, true), (1, false)]); /// ``` + /// + /// # See Also + /// - Zip function Unzipped<'T, 'U>(arr : ('T, 'U)[]) : ('T[], 'U[]) { let nElements = Length(arr); mutable first = new 'T[nElements]; diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 44a2f00965b..a3b13900d9f 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Logical; @@ -8,7 +8,7 @@ namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Arrays; @Test("QuantumSimulator") - function ZipTest() : Unit { + function TestZip() : Unit { let left = [1, 2, 101]; let right = [PauliY, PauliI]; @@ -27,7 +27,7 @@ namespace Microsoft.Quantum.Tests { } @Test("QuantumSimulator") - function UnzippedTest() : Unit { + function TestUnzipped() : Unit { let first = [6, 5, 5, 3, 2, 1]; let second = [true, false, false, false, true, false]; @@ -38,7 +38,7 @@ namespace Microsoft.Quantum.Tests { @Test("QuantumSimulator") - function LookupTest () : Unit { + function TestLookup() : Unit { let array = [1, 12, 71, 103]; let fn = LookupFunction(array); @@ -55,7 +55,7 @@ namespace Microsoft.Quantum.Tests { } @Test("QuantumSimulator") - function ChunksTest() : Unit { + function TestChunks() : Unit { let data = [10, 11, 12, 13, 14, 15]; // 2 × 3 case. From 9aad99d58e36c36f1486ae858e4a841db9b23c22 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Thu, 3 Sep 2020 11:51:50 +0200 Subject: [PATCH 03/17] More array functions. --- Standard/src/Arrays/Interleaved.qs | 44 ++++++++ Standard/src/Arrays/Multidimensional.qs | 133 ++++++++++++++++++++++++ Standard/src/Arrays/Reductions.qs | 55 ++++++++++ Standard/tests/ArrayTests.qs | 55 +++++++++- 4 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 Standard/src/Arrays/Interleaved.qs create mode 100644 Standard/src/Arrays/Multidimensional.qs create mode 100644 Standard/src/Arrays/Reductions.qs diff --git a/Standard/src/Arrays/Interleaved.qs b/Standard/src/Arrays/Interleaved.qs new file mode 100644 index 00000000000..040b3006d5c --- /dev/null +++ b/Standard/src/Arrays/Interleaved.qs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Diagnostics; + + /// # Summary + /// Interleaves two arrays of (almost) same size + /// + /// # Description + /// This function returns the interleaving from two arrays, starting + /// to pick the first element from the first array, then the first + /// element from the second array, and so on. The first array is either + /// of the same length as the second one, or can have one more element. + /// + /// # Input + /// ## first + /// First array + /// + /// ## second + /// Second array + /// + /// # Output + /// Interleaved array + /// + /// # Example + /// ```Q# + /// // same as int1 = [1, -1, 2, -2, 3, -3] + /// let int1 = Interleaved([1, 2, 3], [-1, -2, -3]) + /// + /// // same as int2 = [false, true, false, true, false] + /// let int2 = Interleaved(ConstantArray(3, false), ConstantArray(2, true)); + /// ``` + function Interleaved<'T>(first : 'T[], second : 'T[]) : 'T[] { + let lFirst = Length(first); + let lSecond = Length(second); + + Fact(lFirst >= lSecond and lFirst - lSecond <= 1, "Array `first` is either of same size as `second`, or has one more element"); + + return new 'T[lFirst + lSecond] + w/ 0..2..(lFirst + lSecond - 1) <- first + w/ 1..2..(lFirst + lSecond - 1) <- second; + } +} diff --git a/Standard/src/Arrays/Multidimensional.qs b/Standard/src/Arrays/Multidimensional.qs new file mode 100644 index 00000000000..a00096329fe --- /dev/null +++ b/Standard/src/Arrays/Multidimensional.qs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Convert; + open Microsoft.Quantum.Diagnostics; + + /// # Summary + /// Returns the transpose of a matrix + /// + /// # Description + /// Input as an $r \times c$ matrix with $r$ rows and $$ columns. The matrix + /// is row-based, i.e., `matrix[i][j]` access the element at row $i$ and column $j$. + /// + /// This function returns the $c \times r$ matrix that is the transpose of the + /// input matrix. + /// + /// # Input + /// ## matrix + /// Row-based $r \times c$ matrix + /// + /// # Output + /// Transposed $c \times r$ matrix + /// + /// # Example + /// ```Q# + /// // same as [[1, 4], [2, 5], [3, 6]] + /// let transposed = Transposed([[1, 2, 3], [4, 5, 6]]); + /// ``` + function Transposed<'T>(matrix : 'T[][]) : 'T[][] { + let numRows = Length(matrix); + Fact(numRows > 0, "Matrix must have at least 1 row"); + let numColumns = Length(Head(matrix)); + Fact(numColumns > 0, "Matrix must have at least 1 column"); + + return Mapped(ColumnVectorAt(_, matrix), SequenceI(0, numColumns - 1)); + } + + /// # Summary + /// Returns the array's element at given index + /// + /// # Input + /// ## index + /// Index of element + /// ## array + /// Array + /// + /// # Remark + /// This function is more general than `LookupFunction`, since + /// it can also be used for partial application on a fixed index. + /// Note that the type parameter must explicitly be provided in + /// this case as it cannot be deduced automatically. + /// + /// # Example + /// Get the third number in four famous integer sequences. (note + /// that the 0 index corresponds to the _first_ value of the sequence.) + /// ```Q# + /// let lucas = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]; + /// let prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]; + /// let fibonacci = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + /// let catalan = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]; + /// let famous2 = Mapped(ElementAt(2, _), [lucas, prime, fibonacci, catalan]); + /// // same as: famous2 = [3, 5, 1, 2] + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.LookupFunction + /// - Microsoft.Quantum.Arrays.ElementsAt + function ElementAt<'T>(index : Int, array : 'T[]) : 'T { + Fact(index < Length(array), "Index is out of bound"); + return array[index]; + } + + /// # Summary + /// Returns the array's elements at a given range + /// + /// # Input + /// ## range + /// Range of array indexes + /// ## array + /// Array + /// + /// # Example + /// Get the odd indexes in famous integer sequences. (note + /// that the 0 index corresponds to the _first_ value of the sequence.) + /// ```Q# + /// let lucas = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]; + /// let prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]; + /// let fibonacci = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + /// let catalan = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]; + /// let famousOdd = Mapped(ElementsAt(0..2..9, _), [lucas, prime, fibonacci, catalan]); + /// // same as: famousOdd = [[2, 3, 7, 18, 47], [2, 5, 11, 17, 23], [0, 1, 3, 8, 21], [1, 2, 14, 132, 1430]] + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.ElementAt + /// - Microsoft.Quantum.Arrays.LookupFunction + function ElementsAt<'T>(range : Range, array : 'T[]) : 'T[] { + return array[range]; + } + + /// # Summary + /// Extracts a column in a matrix + /// + /// # Dimension + /// This function extracts a column in a matrix in row-wise order. + /// Extracting a row corrsponds to element access of the first index + /// and therefore requires no further treatment. + /// + /// # Input + /// ## column + /// Column of the matrix + /// ## matrix + /// 2-dimensional matrix in row-wise order + /// + /// # Example + /// ```Q# + /// let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + /// let column = ColumnVectorAt(0, matrix); + /// // same as: column = [1, 4, 7] + /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.Transposed + function ColumnVectorAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { + return Mapped( + Compose( + ElementAt<'T>(column, _), + LookupFunction(matrix) + ), RangeAsIntArray(IndexRange(matrix))); + } +} diff --git a/Standard/src/Arrays/Reductions.qs b/Standard/src/Arrays/Reductions.qs new file mode 100644 index 00000000000..0d96ce71d00 --- /dev/null +++ b/Standard/src/Arrays/Reductions.qs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + + /// # Summary + /// Combines Mapped and Fold into a single function + /// + /// # Description + /// This function iterates the `folder` function through the array, starting from + /// an initial state `state` and returns all intermediate values, not including + /// the inital state. + /// + /// # 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 + /// All intermediate states, including the final state, but not the initial state. + /// The length of the output array is of the same length as `array`. + /// + /// # Remark + /// This function generalizes `Fold` since + /// `Tail(CumulativeFolded(folder, state, array)) == Fold(folder, state, array)`. + /// + /// # Example + /// ```Q# + /// // same as sums = [1, 3, 6, 10, 15] + /// let sums = CumulativeFolded(PlusI, 0, SequenceI(1, 5)); + /// ``` + function CumulativeFolded<'State, 'T>(folder : (('State, 'T) -> 'State), state : 'State, array : 'T[]) : 'State[] { + mutable current = state; + mutable result = new 'State[Length(array)]; + + for ((i, elem) in Enumerated(array)) { + set current = folder(current, elem); + set result w/= i <- current; + } + + return result; + } +} diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index a3b13900d9f..0ee3b6392b6 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { - open Microsoft.Quantum.Logical; - open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Arrays; open Microsoft.Quantum.Canon; + open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Intrinsic; - open Microsoft.Quantum.Arrays; + open Microsoft.Quantum.Logical; + open Microsoft.Quantum.Math; @Test("QuantumSimulator") function TestZip() : Unit { @@ -247,6 +248,54 @@ namespace Microsoft.Quantum.Tests { let differentElements = EqualA(EqualR, [One, Zero], [One, One]); Fact(not differentElements, "Arrays with different elements were reported as equal"); } + + @Test("QuantumSimulator") + operation TestInterleaved() : Unit { + AllEqualityFactI(Interleaved([1, 2, 3], [-1, -2, -3]), [1, -1, 2, -2, 3, -3], "Interleaving failed"); + AllEqualityFactB(Interleaved(ConstantArray(3, false), ConstantArray(2, true)), [false, true, false, true, false], "Interleaving failed"); + } + + @Test("QuantumSimulator") + operation TestCumulativeFolded() : Unit { + AllEqualityFactI(CumulativeFolded(PlusI, 0, SequenceI(1, 5)), [1, 3, 6, 10, 15], "CumulativeFolded failed"); + } + + @Test("QuantumSimulator") + operation TestTransposed() : Unit { + for ((actual, expected) in Zip(Transposed([[1, 2, 3], [4, 5, 6]]), [[1, 4], [2, 5], [3, 6]])) { + AllEqualityFactI(actual, expected, "Transposed failed"); + } + } + + @Test("QuantumSimulator") + operation TestColumnVectorAt() : Unit { + let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + AllEqualityFactI(ColumnVectorAt(0, matrix), [1, 4, 7], "ColumnVectorAt failed"); + AllEqualityFactI(ColumnVectorAt(1, matrix), [2, 5, 8], "ColumnVectorAt failed"); + AllEqualityFactI(ColumnVectorAt(2, matrix), [3, 6, 9], "ColumnVectorAt failed"); + } + + @Test("QuantumSimulator") + operation TestElementAt() : Unit { + let lucas = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]; + let prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]; + let fibonacci = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + let catalan = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]; + let famous2 = Mapped(ElementAt(2, _), [lucas, prime, fibonacci, catalan]); + AllEqualityFactI(famous2, [3, 5, 1, 2], "ElementAt failed"); + } + + @Test("QuantumSimulator") + operation TestElementsAt() : Unit { + let lucas = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]; + let prime = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]; + let fibonacci = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]; + let catalan = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862]; + let famousOdd = Mapped(ElementsAt(0..2..9, _), [lucas, prime, fibonacci, catalan]); + for ((actual, expected) in Zip(famousOdd, [[2, 3, 7, 18, 47], [2, 5, 11, 17, 23], [0, 1, 3, 8, 21], [1, 2, 14, 132, 1430]])) { + AllEqualityFactI(actual, expected, "ElementsAt failed"); + } + } } From 0d6abd2cdf382cef4236bd2bbc517a8b5f0aac70 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 7 Sep 2020 21:38:24 +0200 Subject: [PATCH 04/17] Rename ColumnVectorAt to ColumnVector. --- Standard/src/Arrays/Multidimensional.qs | 6 +++--- Standard/tests/ArrayTests.qs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Standard/src/Arrays/Multidimensional.qs b/Standard/src/Arrays/Multidimensional.qs index a00096329fe..b470bfcba03 100644 --- a/Standard/src/Arrays/Multidimensional.qs +++ b/Standard/src/Arrays/Multidimensional.qs @@ -34,7 +34,7 @@ namespace Microsoft.Quantum.Arrays { let numColumns = Length(Head(matrix)); Fact(numColumns > 0, "Matrix must have at least 1 column"); - return Mapped(ColumnVectorAt(_, matrix), SequenceI(0, numColumns - 1)); + return Mapped(ColumnAt(_, matrix), SequenceI(0, numColumns - 1)); } /// # Summary @@ -117,13 +117,13 @@ namespace Microsoft.Quantum.Arrays { /// # Example /// ```Q# /// let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; - /// let column = ColumnVectorAt(0, matrix); + /// let column = ColumnAt(0, matrix); /// // same as: column = [1, 4, 7] /// ``` /// /// # See Also /// - Microsoft.Quantum.Arrays.Transposed - function ColumnVectorAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { + function ColumnAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { return Mapped( Compose( ElementAt<'T>(column, _), diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 0ee3b6392b6..37384eab8bc 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -268,11 +268,11 @@ namespace Microsoft.Quantum.Tests { } @Test("QuantumSimulator") - operation TestColumnVectorAt() : Unit { + operation TestColumnAt() : Unit { let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; - AllEqualityFactI(ColumnVectorAt(0, matrix), [1, 4, 7], "ColumnVectorAt failed"); - AllEqualityFactI(ColumnVectorAt(1, matrix), [2, 5, 8], "ColumnVectorAt failed"); - AllEqualityFactI(ColumnVectorAt(2, matrix), [3, 6, 9], "ColumnVectorAt failed"); + AllEqualityFactI(ColumnAt(0, matrix), [1, 4, 7], "ColumnAt failed"); + AllEqualityFactI(ColumnAt(1, matrix), [2, 5, 8], "ColumnAt failed"); + AllEqualityFactI(ColumnAt(2, matrix), [3, 6, 9], "ColumnAt failed"); } @Test("QuantumSimulator") From c5c01ca31fda2c64151fad1cd4e2a4e968fa39f9 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 7 Sep 2020 21:41:49 +0200 Subject: [PATCH 05/17] Windows function. --- Standard/src/Arrays/Windows.qs | 43 ++++++++++++++++++++++++++++++++++ Standard/tests/ArrayTests.qs | 13 ++++++++++ 2 files changed, 56 insertions(+) create mode 100644 Standard/src/Arrays/Windows.qs diff --git a/Standard/src/Arrays/Windows.qs b/Standard/src/Arrays/Windows.qs new file mode 100644 index 00000000000..7e28a8385c7 --- /dev/null +++ b/Standard/src/Arrays/Windows.qs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Microsoft.Quantum.Arrays { + /// # 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 `arr`. + /// The first subarrays are `arr[0..size - 1], arr[1..size], arr[2..size + 1]` + /// until the last subarray `arr[n - size..n - 1]`. + /// + /// If `size <= 0` or `size > n`, an empty array is returned. + /// + /// # Input + /// ## size + /// Length of the subarrays + /// + /// ## arr + /// Array + /// + /// # Example + /// ```Q# + /// // same as [[1, 2, 3], [2, 3, 4], [3, 4, 5]] + /// let windows = Windows(3, [1, 2, 3, 4, 5]); + /// ``` + function Windows<'T>(size : Int, arr : 'T[]) : 'T[][] { + let n = Length(arr); + + if (size <= 0 or size > n) { + return new 'T[][0]; + } + + mutable result = new 'T[][n + 1 - size]; + + for (i in 0..n - size) { + set result w/= i <- arr[i..i + size - 1]; + } + + return result; + } +} diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 37384eab8bc..a2b1f63183b 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -296,6 +296,19 @@ namespace Microsoft.Quantum.Tests { AllEqualityFactI(actual, expected, "ElementsAt failed"); } } + + @Test("QuantumSimulator") + operation TestWindows() : Unit { + let EqualIntA = EqualA(EqualI, _, _); + let EqualIntAA = EqualA(EqualIntA, _, _); + + Fact(EqualIntAA(Windows(-1, [1, 2, 3]), new Int[][0]), "unexpected windows"); + Fact(EqualIntAA(Windows(0, [1, 2, 3]), new Int[][0]), "unexpected windows"); + Fact(EqualIntAA(Windows(1, [1, 2, 3]), [[1], [2], [3]]), "unexpected windows"); + Fact(EqualIntAA(Windows(2, [1, 2, 3]), [[1, 2], [2, 3]]), "unexpected windows"); + Fact(EqualIntAA(Windows(3, [1, 2, 3]), [[1, 2, 3]]), "unexpected windows"); + Fact(EqualIntAA(Windows(4, [1, 2, 3]), new Int[][0]), "unexpected windows"); + } } From 200e23abf93c0754fc301c5f1e5e136295e359bd Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Fri, 18 Sep 2020 07:28:37 +0200 Subject: [PATCH 06/17] Apply suggestions from code review Co-authored-by: Chris Granade --- Standard/src/Arrays/Interleaved.qs | 14 ++++++++------ Standard/src/Arrays/Multidimensional.qs | 14 ++++++++------ Standard/src/Arrays/Reductions.qs | 4 ++-- Standard/src/Arrays/Windows.qs | 1 + 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/Standard/src/Arrays/Interleaved.qs b/Standard/src/Arrays/Interleaved.qs index 040b3006d5c..dfbec990099 100644 --- a/Standard/src/Arrays/Interleaved.qs +++ b/Standard/src/Arrays/Interleaved.qs @@ -5,20 +5,22 @@ namespace Microsoft.Quantum.Arrays { open Microsoft.Quantum.Diagnostics; /// # Summary - /// Interleaves two arrays of (almost) same size + /// Interleaves two arrays of (almost) same size. /// /// # Description - /// This function returns the interleaving from two arrays, starting - /// to pick the first element from the first array, then the first - /// element from the second array, and so on. The first array is either + /// 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. /// /// # Input /// ## first - /// First array + /// The first array to be interleaved. /// /// ## second - /// Second array + /// The second array to be interleaved. /// /// # Output /// Interleaved array diff --git a/Standard/src/Arrays/Multidimensional.qs b/Standard/src/Arrays/Multidimensional.qs index b470bfcba03..23393eaffa6 100644 --- a/Standard/src/Arrays/Multidimensional.qs +++ b/Standard/src/Arrays/Multidimensional.qs @@ -7,11 +7,12 @@ namespace Microsoft.Quantum.Arrays { open Microsoft.Quantum.Diagnostics; /// # Summary - /// Returns the transpose of a matrix + /// Returns the transpose of a matrix represented as an array + /// of arrays. /// /// # Description - /// Input as an $r \times c$ matrix with $r$ rows and $$ columns. The matrix - /// is row-based, i.e., `matrix[i][j]` access the element at row $i$ and column $j$. + /// Input as an $r \times 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 \times r$ matrix that is the transpose of the /// input matrix. @@ -38,13 +39,13 @@ namespace Microsoft.Quantum.Arrays { } /// # Summary - /// Returns the array's element at given index + /// Returns the at the given index of an array. /// /// # Input /// ## index /// Index of element /// ## array - /// Array + /// The array being indexed. /// /// # Remark /// This function is more general than `LookupFunction`, since @@ -74,6 +75,7 @@ namespace Microsoft.Quantum.Arrays { /// # Summary /// Returns the array's elements at a given range + /// of indices. /// /// # Input /// ## range @@ -101,7 +103,7 @@ namespace Microsoft.Quantum.Arrays { } /// # Summary - /// Extracts a column in a matrix + /// Extracts a column from a matrix. /// /// # Dimension /// This function extracts a column in a matrix in row-wise order. diff --git a/Standard/src/Arrays/Reductions.qs b/Standard/src/Arrays/Reductions.qs index 0d96ce71d00..0b9b140fc06 100644 --- a/Standard/src/Arrays/Reductions.qs +++ b/Standard/src/Arrays/Reductions.qs @@ -13,8 +13,8 @@ namespace Microsoft.Quantum.Arrays { /// /// # Type Parameters /// ## 'State - /// The type of states the `folder` function operates on, i.e., accepts as its first - /// argument and returns. + /// The type of states that the `folder` function operates on, i.e., accepts as its first + /// input and returns. /// ## 'T /// The type of `array` elements. /// diff --git a/Standard/src/Arrays/Windows.qs b/Standard/src/Arrays/Windows.qs index 7e28a8385c7..fab7195d53b 100644 --- a/Standard/src/Arrays/Windows.qs +++ b/Standard/src/Arrays/Windows.qs @@ -2,6 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Arrays { + /// # Summary /// Returns all consecutive subarrays of length `size`. /// From e66855fbca3b620a72a252395cbef5adc2304ad3 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Fri, 18 Sep 2020 07:44:27 +0200 Subject: [PATCH 07/17] Comments from Chris. --- Standard/src/Arrays/Multidimensional.qs | 4 ++-- Standard/src/Arrays/Reductions.qs | 10 +++++----- Standard/src/Arrays/Zip.qs | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Standard/src/Arrays/Multidimensional.qs b/Standard/src/Arrays/Multidimensional.qs index 23393eaffa6..5179ff1424a 100644 --- a/Standard/src/Arrays/Multidimensional.qs +++ b/Standard/src/Arrays/Multidimensional.qs @@ -69,7 +69,7 @@ namespace Microsoft.Quantum.Arrays { /// - Microsoft.Quantum.Arrays.LookupFunction /// - Microsoft.Quantum.Arrays.ElementsAt function ElementAt<'T>(index : Int, array : 'T[]) : 'T { - Fact(index < Length(array), "Index is out of bound"); + Fact(index >= 0 and index < Length(array), "Index is out of bound"); return array[index]; } @@ -105,7 +105,7 @@ namespace Microsoft.Quantum.Arrays { /// # Summary /// Extracts a column from a matrix. /// - /// # Dimension + /// # Description /// This function extracts a column in a matrix in row-wise order. /// Extracting a row corrsponds to element access of the first index /// and therefore requires no further treatment. diff --git a/Standard/src/Arrays/Reductions.qs b/Standard/src/Arrays/Reductions.qs index 0b9b140fc06..2095c13a455 100644 --- a/Standard/src/Arrays/Reductions.qs +++ b/Standard/src/Arrays/Reductions.qs @@ -19,11 +19,11 @@ namespace Microsoft.Quantum.Arrays { /// The type of `array` elements. /// /// # Input - /// ## folder + /// ## fn /// A function to be folded over the array /// /// ## state - /// The initial state of the folder + /// The initial state to be folded /// /// ## array /// An array of values to be folded over @@ -34,19 +34,19 @@ namespace Microsoft.Quantum.Arrays { /// /// # Remark /// This function generalizes `Fold` since - /// `Tail(CumulativeFolded(folder, state, array)) == Fold(folder, state, array)`. + /// `Tail(CumulativeFolded(fn, state, array)) == Fold(fn, state, array)`. /// /// # Example /// ```Q# /// // same as sums = [1, 3, 6, 10, 15] /// let sums = CumulativeFolded(PlusI, 0, SequenceI(1, 5)); /// ``` - function CumulativeFolded<'State, 'T>(folder : (('State, 'T) -> 'State), state : 'State, array : 'T[]) : 'State[] { + function CumulativeFolded<'State, 'T>(fn : (('State, 'T) -> 'State), state : 'State, array : 'T[]) : 'State[] { mutable current = state; mutable result = new 'State[Length(array)]; for ((i, elem) in Enumerated(array)) { - set current = folder(current, elem); + set current = fn(current, elem); set result w/= i <- current; } diff --git a/Standard/src/Arrays/Zip.qs b/Standard/src/Arrays/Zip.qs index 1d2585a518e..f698d9ffea9 100644 --- a/Standard/src/Arrays/Zip.qs +++ b/Standard/src/Arrays/Zip.qs @@ -156,6 +156,9 @@ namespace Microsoft.Quantum.Arrays { /// let split = Unzipped([(6, true), (5, false), (5, false), (3, false), (2, true), (1, false)]); /// ``` /// + /// # Remark + /// This function is equivalent to `(Mapped(Fst<'T, 'U>, arr), Mapped(Snd<'T, 'U>, arr))`. + /// /// # See Also /// - Zip function Unzipped<'T, 'U>(arr : ('T, 'U)[]) : ('T[], 'U[]) { From abe4fef3c7458d6897e059c8aafdfc629e47b83c Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Sat, 19 Sep 2020 16:01:11 +0200 Subject: [PATCH 08/17] Docs. --- Standard/src/Arrays/Interleaved.qs | 4 + Standard/src/Arrays/Multidimensional.qs | 98 ++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/Standard/src/Arrays/Interleaved.qs b/Standard/src/Arrays/Interleaved.qs index dfbec990099..05cbc93b6e4 100644 --- a/Standard/src/Arrays/Interleaved.qs +++ b/Standard/src/Arrays/Interleaved.qs @@ -15,6 +15,10 @@ namespace Microsoft.Quantum.Arrays { /// 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. diff --git a/Standard/src/Arrays/Multidimensional.qs b/Standard/src/Arrays/Multidimensional.qs index 5179ff1424a..9abfc0ec731 100644 --- a/Standard/src/Arrays/Multidimensional.qs +++ b/Standard/src/Arrays/Multidimensional.qs @@ -5,6 +5,7 @@ namespace Microsoft.Quantum.Arrays { open Microsoft.Quantum.Canon; open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; + open Microsoft.Quantum.Logical; /// # Summary /// Returns the transpose of a matrix represented as an array @@ -17,6 +18,10 @@ namespace Microsoft.Quantum.Arrays { /// This function returns the $c \times 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 \times c$ matrix @@ -34,13 +39,18 @@ namespace Microsoft.Quantum.Arrays { Fact(numRows > 0, "Matrix must have at least 1 row"); let numColumns = Length(Head(matrix)); Fact(numColumns > 0, "Matrix must have at least 1 column"); + RectangularArrayFact(matrix, "Matrix is not a rectangular array"); - return Mapped(ColumnAt(_, matrix), SequenceI(0, numColumns - 1)); + return Mapped(ColumnAtUnchecked(_, matrix), SequenceI(0, numColumns - 1)); } /// # Summary /// Returns the at the given index of an array. /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// /// # Input /// ## index /// Index of element @@ -77,6 +87,10 @@ namespace Microsoft.Quantum.Arrays { /// Returns the array's elements at a given range /// of indices. /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// /// # Input /// ## range /// Range of array indexes @@ -105,6 +119,10 @@ namespace Microsoft.Quantum.Arrays { /// # Summary /// Extracts a column from a matrix. /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `matrix`. + /// /// # Description /// This function extracts a column in a matrix in row-wise order. /// Extracting a row corrsponds to element access of the first index @@ -126,10 +144,88 @@ namespace Microsoft.Quantum.Arrays { /// # See Also /// - Microsoft.Quantum.Arrays.Transposed function ColumnAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { + RectangularArrayFact(matrix, "Matrix is not a rectangular array"); + return ColumnAtUnchecked(column, matrix); + } + + /// # Summary + /// This function does not check for matrix shape + /// + /// # Description + /// This function can be used in other multidimensional functions, + /// which already check the input matrix for a valid rectangular shape. + internal function ColumnAtUnchecked<'T>(column : Int, matrix : 'T[][]) : 'T[] { return Mapped( Compose( ElementAt<'T>(column, _), LookupFunction(matrix) ), RangeAsIntArray(IndexRange(matrix))); } + + /// # Summary + /// Asserts that a 2-dimensional array has a rectangular shape + /// + /// # Description + /// This function asserts that each row in an array has the same length. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## array + /// A 2-dimensional array of elements + /// ## message + /// A message to be printed if the array is not a rectangular array + /// + /// # Example + /// ```Q# + /// RectangularArrayFact([[1, 2], [3, 4]], "Array is not rectangular"); // okay + /// RectangularArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not rectangular"); // okay + /// RectangularArrayFact([[1, 2], [3, 4, 5]], "Array is not rectangular"); // will fail + /// ``` + function RectangularArrayFact<'T>(array : 'T[][], message : String) : Unit { + if (Length(array) == 0) { + return (); + } else { + let numColumns = Length(Head(array)); + if (Any(Compose(NotEqualI(numColumns, _), Length<'T>), Rest(array))) { + fail message; + } + } + } + + /// # Summary + /// Asserts that a 2-dimensional array has a square shape + /// + /// # Description + /// This function asserts that each row in an array has + /// as many elements as there are rows (elements) in the array. + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `array`. + /// + /// # Input + /// ## array + /// A 2-dimensional array of elements + /// ## message + /// A message to be printed if the array is not a square array + /// + /// # Example + /// ```Q# + /// SquareArrayFact([[1, 2], [3, 4]], "Array is not a square"); // okay + /// SquareArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not a square"); // will fail + /// SquareArrayFact([[1, 2], [3, 4, 5]], "Array is not a square"); // will fail + /// ``` + function SquareArrayFact<'T>(array : 'T[][], message : String) : Unit { + if (Length(array) == 0) { + return (); + } else { + let numColumns = Length(array); + if (Any(Compose(NotEqualI(numColumns, _), Length<'T>), array)) { + fail message; + } + } + } } From ba26cadb33d712a0caa3b800bcc57eded5276963 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Sat, 19 Sep 2020 16:14:17 +0200 Subject: [PATCH 09/17] Use `ElementAt` for `LookupFunction`. --- Standard/src/Arrays/Arrays.qs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 32e5ef991ab..a40520bb5d4 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -63,10 +63,6 @@ namespace Microsoft.Quantum.Arrays { return array[0 .. Length(array) - 2]; } - internal function Lookup<'T> (array : 'T[], index : Int) : 'T { - return array[index]; - } - /// # Summary /// Given an array, returns a function which returns elements of that /// array. @@ -90,7 +86,7 @@ namespace Microsoft.Quantum.Arrays { /// where functions are used to avoid the need to record an entire array /// in memory. function LookupFunction<'T> (array : 'T[]) : (Int -> 'T) { - return Lookup(array, _); + return ElementAt(_, array); } /// # Summary From 80076fcf4eee781392a9f10b84995325e85e8335 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Sat, 19 Sep 2020 16:30:04 +0200 Subject: [PATCH 10/17] Function `Diagonal`. --- Standard/src/Arrays/Multidimensional.qs | 45 ++++++++++++++++++++++--- Standard/tests/ArrayTests.qs | 5 +++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Standard/src/Arrays/Multidimensional.qs b/Standard/src/Arrays/Multidimensional.qs index 9abfc0ec731..399796a76e1 100644 --- a/Standard/src/Arrays/Multidimensional.qs +++ b/Standard/src/Arrays/Multidimensional.qs @@ -119,15 +119,15 @@ namespace Microsoft.Quantum.Arrays { /// # Summary /// Extracts a column from a matrix. /// - /// # Type Parameters - /// ## 'T - /// The type of each element of `matrix`. - /// /// # Description /// This function extracts a column in a matrix in row-wise order. /// Extracting a row corrsponds 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 @@ -143,6 +143,7 @@ namespace Microsoft.Quantum.Arrays { /// /// # See Also /// - Microsoft.Quantum.Arrays.Transposed + /// - Microsoft.Quantum.Arrays.Diagonal function ColumnAt<'T>(column : Int, matrix : 'T[][]) : 'T[] { RectangularArrayFact(matrix, "Matrix is not a rectangular array"); return ColumnAtUnchecked(column, matrix); @@ -162,6 +163,36 @@ namespace Microsoft.Quantum.Arrays { ), RangeAsIntArray(IndexRange(matrix))); } + /// # Summary + /// Returns an array of diagonal elements of an array in square shape + /// + /// # Type Parameters + /// ## 'T + /// The type of each element of `matrix`. + /// + /// # Input + /// ## matrix + /// 2-dimensional matrix in row-wise order + /// + /// # Example + /// ```Q# + /// 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[] { + SquareArrayFact(matrix, "Matrix is not a rectangular array"); + + return Mapped(ElementAtDiagonal(_, matrix), SequenceI(0, Length(matrix) - 1)); + } + + internal function ElementAtDiagonal<'T>(index : Int, matrix : 'T[][]) : 'T { + return matrix[index][index]; + } + /// # Summary /// Asserts that a 2-dimensional array has a rectangular shape /// @@ -184,6 +215,9 @@ namespace Microsoft.Quantum.Arrays { /// RectangularArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not rectangular"); // okay /// RectangularArrayFact([[1, 2], [3, 4, 5]], "Array is not rectangular"); // will fail /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.SquareArrayFact function RectangularArrayFact<'T>(array : 'T[][], message : String) : Unit { if (Length(array) == 0) { return (); @@ -218,6 +252,9 @@ namespace Microsoft.Quantum.Arrays { /// SquareArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not a square"); // will fail /// SquareArrayFact([[1, 2], [3, 4, 5]], "Array is not a square"); // will fail /// ``` + /// + /// # See Also + /// - Microsoft.Quantum.Arrays.RectangularArrayFact function SquareArrayFact<'T>(array : 'T[][], message : String) : Unit { if (Length(array) == 0) { return (); diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index a2b1f63183b..a563995c514 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -297,6 +297,11 @@ namespace Microsoft.Quantum.Tests { } } + @Test("QuantumSimulator") + operation TestDiagonal() : Unit { + AllEqualityFactI(Diagonal([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [1, 5, 9], "Diagonal failed"); + } + @Test("QuantumSimulator") operation TestWindows() : Unit { let EqualIntA = EqualA(EqualI, _, _); From 773e371031c4b8ea07c51e03ca077a8fdf0d0530 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Sun, 20 Sep 2020 10:39:56 +0200 Subject: [PATCH 11/17] Array function `Count`. --- Standard/src/Arrays/Filter.qs | 45 +++++++++++++++++++++++++++++++++-- Standard/tests/ArrayTests.qs | 8 +++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Standard/src/Arrays/Filter.qs b/Standard/src/Arrays/Filter.qs index f03605ef773..0d501d54102 100644 --- a/Standard/src/Arrays/Filter.qs +++ b/Standard/src/Arrays/Filter.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Arrays { @@ -40,7 +40,7 @@ namespace Microsoft.Quantum.Arrays { /// } /// ``` /// The outcome one should expect from this example will be an array of numbers greater than 5. - function Filtered<'T> (predicate : ('T -> Bool), array : 'T[]) : 'T[] { + function Filtered<'T>(predicate : ('T -> Bool), array : 'T[]) : 'T[] { mutable totalFound = 0; mutable idxArray = new Int[Length(array)]; @@ -80,4 +80,45 @@ namespace Microsoft.Quantum.Arrays { ); } + /// # 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. + /// + /// # Remarks + /// The function is defined for generic types, i.e., whenever we have + /// an array `'T[]` and a predicate `'T -> Bool` we can filter elements. + /// + /// # 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 + /// The following code demonstrates the "Count" function. + /// A predicate is defined using the @"microsoft.quantum.logical.greaterthani" function: + /// ```Q# + /// let predicate = GreaterThanI(_, 5); + /// let count = Count(predicate, [2, 5, 9, 1, 8]); + /// // count = 2 + /// ``` + function Count<'T>(predicate : ('T -> Bool), array : 'T[]) : Int { + mutable totalFound = 0; + + for (element in array) { + if (predicate(element)) { + set totalFound = totalFound + 1; + } + } + + return totalFound; + } } diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index a563995c514..e1617b97dfd 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -109,6 +109,14 @@ namespace Microsoft.Quantum.Tests { EqualityFactB(All(IsEven, evenArray), true, $"the even elements of [1..10] were not correctly filtered."); } + @Test("QuantumSimulator") + function TestCount() : Unit { + + let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let countEvens = Count(IsEven, array); + EqualityFactI(countEvens, 5, $"the even elements of [1..10] were not correctly counted."); + } + function ReverseTest () : Unit { From 8b00cddbb9ad617dc6bdfa8697ce3b2ccfd69166 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Sun, 20 Sep 2020 10:49:00 +0200 Subject: [PATCH 12/17] Array function `MappedOverRange`. --- Standard/src/Arrays/Map.qs | 40 ++++++++++++++++++++++++++++++ Standard/tests/EnumerationTests.qs | 17 ++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/Standard/src/Arrays/Map.qs b/Standard/src/Arrays/Map.qs index e6e28337d0e..9245cc0b6b8 100644 --- a/Standard/src/Arrays/Map.qs +++ b/Standard/src/Arrays/Map.qs @@ -86,6 +86,46 @@ namespace Microsoft.Quantum.Arrays { return resultArray; } + /// # 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. + /// + /// # Remarks + /// The function is defined for generic types, i.e., whenever we have + /// a function `mapper: Int -> 'T` we can map the values + /// of the range and produce an array of type `'T[]`. + /// + /// # 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. + function MappedOverRange<'T> (mapper : (Int -> 'T), range : Range) : 'T[] { + let start = RangeStart(range); + let step = RangeStep(range); + let end = RangeEnd(range); + if ((end - start) / step >= 0) { + let nTerms = (end - start) / step + 1; + mutable resultArray = new 'T[nTerms]; + mutable idxElement = 0; + for (elem in range) { + set resultArray w/= idxElement <- mapper(elem); + set idxElement += 1; + } + return resultArray; + } else { + return new 'T[0]; + } + } + /// # Summary /// Given an array and an operation that is defined /// for the elements of the array, returns a new array that consists diff --git a/Standard/tests/EnumerationTests.qs b/Standard/tests/EnumerationTests.qs index 48e23694f9d..cc9be56c631 100644 --- a/Standard/tests/EnumerationTests.qs +++ b/Standard/tests/EnumerationTests.qs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Quantum.Tests { open Microsoft.Quantum.Math; @@ -59,6 +59,21 @@ namespace Microsoft.Quantum.Tests { EqualityFactI(Fold(Add, 0, squaredArray), 30, $"the sum of the squares of [1, 2, 3, 4] was not found to be 30."); } + @Test("QuantumSimulator") + function TestMappedOverNonEmptyRange() : Unit { + AllEqualityFactI(MappedOverRange(PlusI(_, 2), 1..5), [3, 4, 5, 6, 7], "MappedOverRange failed."); + } + + @Test("QuantumSimulator") + function TestMappedOverReversedRange() : Unit { + AllEqualityFactI(MappedOverRange(TimesI(_, 2), 4..-2..-4), [8, 4, 0, -4, -8], "MappedOverRange failed."); + } + + @Test("QuantumSimulator") + function TestMappedOverEmpty() : Unit { + AllEqualityFactI(MappedOverRange(TimesI(_, 2), 1..-1..2), new Int[0], "MappedOverRange failed."); + } + function ExtremaTest () : Unit { let array = [-10, 10, 7, 0]; EqualityFactI(-10, Min(array), $"Min failed."); From 9feb23d2cc2bf5c4eb580ed0ad02018fa2f72393 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Sun, 20 Sep 2020 10:56:43 +0200 Subject: [PATCH 13/17] Functions `HeadAndRest` and `MostAndTail`. --- Standard/src/Arrays/Arrays.qs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index a40520bb5d4..4d9719596a0 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -125,6 +125,40 @@ namespace Microsoft.Quantum.Arrays { return array[0]; } + /// # Summary + /// Returns 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[]) { + return (Head(array), Rest(array)); + } + + /// # Summary + /// Returns 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) { + return (Most(array), Tail(array)); + } + /// # Summary /// Creates an array of given length with all elements equal to given value. /// From dfabf8f79ba59506c1017c4dd09a33ed70557a80 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Sun, 20 Sep 2020 11:22:32 +0200 Subject: [PATCH 14/17] Array functions `Flattened` and `FlatMapped`. --- Standard/src/Arrays/Map.qs | 54 ++++++++++++++++++++++++++++++ Standard/tests/EnumerationTests.qs | 12 +++++++ 2 files changed, 66 insertions(+) diff --git a/Standard/src/Arrays/Map.qs b/Standard/src/Arrays/Map.qs index 9245cc0b6b8..ac650650a80 100644 --- a/Standard/src/Arrays/Map.qs +++ b/Standard/src/Arrays/Map.qs @@ -2,6 +2,7 @@ // Licensed under the MIT License. namespace Microsoft.Quantum.Arrays { + open Microsoft.Quantum.Math; /// # Summary /// Given an array and a function that is defined @@ -126,6 +127,59 @@ namespace Microsoft.Quantum.Arrays { } } + /// # 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. + /// ## range + /// An array of elements. + /// + /// # Output + /// An array of `'TOutput[]` which is the concatenation of all arrays generated by + /// the mapping function. + /// + /// # Example + /// ```Q# + /// let Numbers = SequenceI(1, _); // generates numbers starting from 1 + /// let values = FlatMapped(Numbers, [1, 2, 3]); + /// // values = [1, 1, 2, 1, 2, 3] + /// ``` + function FlatMapped<'TInput, 'TOutput>(mapper : ('TInput -> 'TOutput[]), array : 'TInput[]) : 'TOutput[] { + return Fold(PlusA<'TOutput>, new 'TOutput[0], Mapped(mapper, array)); + } + + /// # 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 + /// ```Q# + /// let flattened = Flattened([[1, 2], [3], [4, 5, 6]]); + /// // flattened = [1, 2, 3, 4, 5, 6] + /// ``` + function Flattened<'T>(arrays : 'T[][]): 'T[] { + return Fold(PlusA<'T>, new 'T[0], arrays); + } + /// # Summary /// Given an array and an operation that is defined /// for the elements of the array, returns a new array that consists diff --git a/Standard/tests/EnumerationTests.qs b/Standard/tests/EnumerationTests.qs index cc9be56c631..5e9db499f26 100644 --- a/Standard/tests/EnumerationTests.qs +++ b/Standard/tests/EnumerationTests.qs @@ -74,6 +74,18 @@ namespace Microsoft.Quantum.Tests { AllEqualityFactI(MappedOverRange(TimesI(_, 2), 1..-1..2), new Int[0], "MappedOverRange failed."); } + @Test("QuantumSimulator") + function TestFlatMapped() : Unit { + let numbers = FlatMapped(SequenceI(1, _), SequenceI(1, 5)); + AllEqualityFactI(numbers, [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5], "FlatMapped failed"); + } + + @Test("QuantumSimulator") + function TestFlattened() : Unit { + let numbers = Flattened(ConstantArray(3, SequenceI(1, 3))); + AllEqualityFactI(numbers, [1, 2, 3, 1, 2, 3, 1, 2, 3], "Flattened failed"); + } + function ExtremaTest () : Unit { let array = [-10, 10, 7, 0]; EqualityFactI(-10, Min(array), $"Min failed."); From 87cb1d33f10315f181a1d2983deeda897da0e793 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Sun, 20 Sep 2020 15:51:45 +0200 Subject: [PATCH 15/17] Array function `Prefixes`. --- Standard/src/Arrays/Map.qs | 2 +- Standard/src/Arrays/Windows.qs | 44 +++++++++++++++++++++++++++++----- Standard/tests/ArrayTests.qs | 14 +++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/Standard/src/Arrays/Map.qs b/Standard/src/Arrays/Map.qs index ac650650a80..68a225acda5 100644 --- a/Standard/src/Arrays/Map.qs +++ b/Standard/src/Arrays/Map.qs @@ -140,7 +140,7 @@ namespace Microsoft.Quantum.Arrays { /// # Input /// ## mapper /// A function from `'TInput` to `'TOutput[]` that is used to map array elements. - /// ## range + /// ## array /// An array of elements. /// /// # Output diff --git a/Standard/src/Arrays/Windows.qs b/Standard/src/Arrays/Windows.qs index fab7195d53b..dca5f7365ae 100644 --- a/Standard/src/Arrays/Windows.qs +++ b/Standard/src/Arrays/Windows.qs @@ -14,20 +14,24 @@ namespace Microsoft.Quantum.Arrays { /// /// If `size <= 0` or `size > n`, an empty array is returned. /// + /// # Type Parameters + /// ## 'T + /// The type of `array` elements. + /// /// # Input /// ## size - /// Length of the subarrays + /// Length of the subarrays. /// - /// ## arr - /// Array + /// ## array + /// An array of elements. /// /// # Example /// ```Q# /// // same as [[1, 2, 3], [2, 3, 4], [3, 4, 5]] /// let windows = Windows(3, [1, 2, 3, 4, 5]); /// ``` - function Windows<'T>(size : Int, arr : 'T[]) : 'T[][] { - let n = Length(arr); + function Windows<'T>(size : Int, array : 'T[]) : 'T[][] { + let n = Length(array); if (size <= 0 or size > n) { return new 'T[][0]; @@ -36,9 +40,37 @@ namespace Microsoft.Quantum.Arrays { mutable result = new 'T[][n + 1 - size]; for (i in 0..n - size) { - set result w/= i <- arr[i..i + size - 1]; + set result w/= i <- array[i..i + size - 1]; } return result; } + + /// # Summary + /// Given an array, returns all its prefixes. + /// + /// # Description + /// Returns an array of all prefixes, starting with the empty + /// array until the complete array. + /// + /// # Type Parameters + /// ## 'T + /// The type of `array` elements. + /// + /// # Input + /// ## array + /// An array of elements. + /// + /// # Example + /// ```Q# + /// let prefixes = Prefixes([23, 42, 144]); + /// // prefixes = [EmptyArray(), [23], [23, 42], [23, 42, 144]] + /// ``` + function Prefixes<'T>(array : 'T[]) : 'T[][] { + return MappedOverRange(Prefix(_, array), -1..Length(array) - 1); + } + + internal function Prefix<'T>(to : Int, array : 'T[]) : 'T[] { + return array[0..to]; + } } diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index e1617b97dfd..8ae51de7ad5 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -322,6 +322,20 @@ namespace Microsoft.Quantum.Tests { Fact(EqualIntAA(Windows(3, [1, 2, 3]), [[1, 2, 3]]), "unexpected windows"); Fact(EqualIntAA(Windows(4, [1, 2, 3]), new Int[][0]), "unexpected windows"); } + + @Test("QuantumSimulator") + operation TestPrefixes() : Unit { + let prefixes = Prefixes([0, 1, 1, 2, 3, 5]); + + EqualityFactI(Length(prefixes), 7, "unexpected length for prefixes"); + EqualityFactI(Length(prefixes[0]), 0, "unexpected prefix"); + AllEqualityFactI(prefixes[1], [0], "unexpected prefix"); + AllEqualityFactI(prefixes[2], [0, 1], "unexpected prefix"); + AllEqualityFactI(prefixes[3], [0, 1, 1], "unexpected prefix"); + AllEqualityFactI(prefixes[4], [0, 1, 1, 2], "unexpected prefix"); + AllEqualityFactI(prefixes[5], [0, 1, 1, 2, 3], "unexpected prefix"); + AllEqualityFactI(prefixes[6], [0, 1, 1, 2, 3, 5], "unexpected prefix"); + } } From 4c825005dd8d76e0da8241bb2b901e9b36114fa3 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 21 Sep 2020 08:55:46 +0200 Subject: [PATCH 16/17] Apply suggestions from code review Co-authored-by: Chris Granade --- Standard/src/Arrays/Arrays.qs | 4 ++-- Standard/src/Arrays/Filter.qs | 2 +- Standard/src/Arrays/Reductions.qs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Standard/src/Arrays/Arrays.qs b/Standard/src/Arrays/Arrays.qs index 4d9719596a0..0baf6abc184 100644 --- a/Standard/src/Arrays/Arrays.qs +++ b/Standard/src/Arrays/Arrays.qs @@ -126,7 +126,7 @@ namespace Microsoft.Quantum.Arrays { } /// # Summary - /// Returns tuple of first and all remaining elements of the array. + /// Returns a tuple of first and all remaining elements of the array. /// /// # Type Parameters /// ## 'A @@ -143,7 +143,7 @@ namespace Microsoft.Quantum.Arrays { } /// # Summary - /// Returns tuple of all but one and the last element of the array. + /// Returns a tuple of all but one and the last element of the array. /// /// # Type Parameters /// ## 'A diff --git a/Standard/src/Arrays/Filter.qs b/Standard/src/Arrays/Filter.qs index 0d501d54102..38a7c463637 100644 --- a/Standard/src/Arrays/Filter.qs +++ b/Standard/src/Arrays/Filter.qs @@ -115,7 +115,7 @@ namespace Microsoft.Quantum.Arrays { for (element in array) { if (predicate(element)) { - set totalFound = totalFound + 1; + set totalFound += 1; } } diff --git a/Standard/src/Arrays/Reductions.qs b/Standard/src/Arrays/Reductions.qs index 2095c13a455..78a03c70737 100644 --- a/Standard/src/Arrays/Reductions.qs +++ b/Standard/src/Arrays/Reductions.qs @@ -34,7 +34,7 @@ namespace Microsoft.Quantum.Arrays { /// /// # Remark /// This function generalizes `Fold` since - /// `Tail(CumulativeFolded(fn, state, array)) == Fold(fn, state, array)`. + /// `Tail(CumulativeFolded(fn, state, array))` is the same as `Fold(fn, state, array)`. /// /// # Example /// ```Q# From 2c63f682e32e71e60e731c0601dd50de60d16788 Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Mon, 21 Sep 2020 09:20:55 +0200 Subject: [PATCH 17/17] Addressing Chris' comments. --- Standard/src/Arrays/Map.qs | 10 ++++++ Standard/src/Arrays/Multidimensional.qs | 18 +++++++--- Standard/src/Arrays/Reductions.qs | 4 +-- Standard/src/Arrays/Windows.qs | 8 ++--- Standard/tests/ArrayTests.qs | 45 +++++++++++++++++++------ 5 files changed, 64 insertions(+), 21 deletions(-) diff --git a/Standard/src/Arrays/Map.qs b/Standard/src/Arrays/Map.qs index 68a225acda5..b541190a738 100644 --- a/Standard/src/Arrays/Map.qs +++ b/Standard/src/Arrays/Map.qs @@ -109,6 +109,16 @@ namespace Microsoft.Quantum.Arrays { /// /// # Output /// An array `'T[]` of elements that are mapped by the `mapper` function. + /// + /// # Example + /// This example adds 1 to a range of even numbers: + /// ```Q# + /// let numbers = MappedOverRange(PlusI(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[] { let start = RangeStart(range); let step = RangeStep(range); diff --git a/Standard/src/Arrays/Multidimensional.qs b/Standard/src/Arrays/Multidimensional.qs index 399796a76e1..7e2102585ab 100644 --- a/Standard/src/Arrays/Multidimensional.qs +++ b/Standard/src/Arrays/Multidimensional.qs @@ -6,6 +6,7 @@ namespace Microsoft.Quantum.Arrays { open Microsoft.Quantum.Convert; open Microsoft.Quantum.Diagnostics; open Microsoft.Quantum.Logical; + open Microsoft.Quantum.Math; /// # Summary /// Returns the transpose of a matrix represented as an array @@ -164,7 +165,11 @@ namespace Microsoft.Quantum.Arrays { } /// # Summary - /// Returns an array of diagonal elements of an array in square shape + /// 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 @@ -184,9 +189,12 @@ namespace Microsoft.Quantum.Arrays { /// # See Also /// - Microsoft.Quantum.Arrays.Transposed function Diagonal<'T>(matrix : 'T[][]) : 'T[] { - SquareArrayFact(matrix, "Matrix is not a rectangular array"); + RectangularArrayFact(matrix, "Matrix is not a rectangular array"); + + let numRows = Length(matrix); + let numColumns = numRows == 0 ? 0 | Length(Head(matrix)); - return Mapped(ElementAtDiagonal(_, matrix), SequenceI(0, Length(matrix) - 1)); + return MappedOverRange(ElementAtDiagonal(_, matrix), 0..(MinI(numRows, numColumns) - 1)); } internal function ElementAtDiagonal<'T>(index : Int, matrix : 'T[][]) : 'T { @@ -194,7 +202,7 @@ namespace Microsoft.Quantum.Arrays { } /// # Summary - /// Asserts that a 2-dimensional array has a rectangular shape + /// Represents a condition that a 2-dimensional array has a rectangular shape /// /// # Description /// This function asserts that each row in an array has the same length. @@ -230,7 +238,7 @@ namespace Microsoft.Quantum.Arrays { } /// # Summary - /// Asserts that a 2-dimensional array has a square shape + /// Represents a condition that a 2-dimensional array has a square shape /// /// # Description /// This function asserts that each row in an array has diff --git a/Standard/src/Arrays/Reductions.qs b/Standard/src/Arrays/Reductions.qs index 78a03c70737..201c45b4fd7 100644 --- a/Standard/src/Arrays/Reductions.qs +++ b/Standard/src/Arrays/Reductions.qs @@ -7,13 +7,13 @@ namespace Microsoft.Quantum.Arrays { /// Combines Mapped and Fold into a single function /// /// # Description - /// This function iterates the `folder` function through the array, starting from + /// This function iterates the `fn` function through the array, starting from /// an initial state `state` and returns all intermediate values, not including /// the inital state. /// /// # Type Parameters /// ## 'State - /// The type of states that the `folder` function operates on, i.e., accepts as its first + /// The type of states that the `fn` function operates on, i.e., accepts as its first /// input and returns. /// ## 'T /// The type of `array` elements. diff --git a/Standard/src/Arrays/Windows.qs b/Standard/src/Arrays/Windows.qs index dca5f7365ae..bcad5c35111 100644 --- a/Standard/src/Arrays/Windows.qs +++ b/Standard/src/Arrays/Windows.qs @@ -50,8 +50,8 @@ namespace Microsoft.Quantum.Arrays { /// Given an array, returns all its prefixes. /// /// # Description - /// Returns an array of all prefixes, starting with the empty - /// array until the complete array. + /// Returns an array of all prefixes, starting with an array that only + /// has the first element until the complete array. /// /// # Type Parameters /// ## 'T @@ -64,10 +64,10 @@ namespace Microsoft.Quantum.Arrays { /// # Example /// ```Q# /// let prefixes = Prefixes([23, 42, 144]); - /// // prefixes = [EmptyArray(), [23], [23, 42], [23, 42, 144]] + /// // prefixes = [[23], [23, 42], [23, 42, 144]] /// ``` function Prefixes<'T>(array : 'T[]) : 'T[][] { - return MappedOverRange(Prefix(_, array), -1..Length(array) - 1); + return MappedOverRange(Prefix(_, array), IndexRange(array)); } internal function Prefix<'T>(to : Int, array : 'T[]) : 'T[] { diff --git a/Standard/tests/ArrayTests.qs b/Standard/tests/ArrayTests.qs index 8ae51de7ad5..bd674b65b50 100644 --- a/Standard/tests/ArrayTests.qs +++ b/Standard/tests/ArrayTests.qs @@ -308,6 +308,8 @@ namespace Microsoft.Quantum.Tests { @Test("QuantumSimulator") operation TestDiagonal() : Unit { AllEqualityFactI(Diagonal([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [1, 5, 9], "Diagonal failed"); + AllEqualityFactI(Diagonal([[1, 2, 3], [4, 5, 6]]), [1, 5], "Diagonal failed"); + AllEqualityFactI(Diagonal([[1, 2], [4, 5], [7, 8]]), [1, 5], "Diagonal failed"); } @Test("QuantumSimulator") @@ -325,16 +327,39 @@ namespace Microsoft.Quantum.Tests { @Test("QuantumSimulator") operation TestPrefixes() : Unit { - let prefixes = Prefixes([0, 1, 1, 2, 3, 5]); - - EqualityFactI(Length(prefixes), 7, "unexpected length for prefixes"); - EqualityFactI(Length(prefixes[0]), 0, "unexpected prefix"); - AllEqualityFactI(prefixes[1], [0], "unexpected prefix"); - AllEqualityFactI(prefixes[2], [0, 1], "unexpected prefix"); - AllEqualityFactI(prefixes[3], [0, 1, 1], "unexpected prefix"); - AllEqualityFactI(prefixes[4], [0, 1, 1, 2], "unexpected prefix"); - AllEqualityFactI(prefixes[5], [0, 1, 1, 2, 3], "unexpected prefix"); - AllEqualityFactI(prefixes[6], [0, 1, 1, 2, 3, 5], "unexpected prefix"); + let array = [0, 1, 1, 2, 3, 5]; + let prefixes = Prefixes(array); + + EqualityFactI(Length(prefixes), Length(array), "unexpected length for prefixes"); + AllEqualityFactI(prefixes[0], [0], "unexpected prefix"); + AllEqualityFactI(prefixes[1], [0, 1], "unexpected prefix"); + AllEqualityFactI(prefixes[2], [0, 1, 1], "unexpected prefix"); + AllEqualityFactI(prefixes[3], [0, 1, 1, 2], "unexpected prefix"); + AllEqualityFactI(prefixes[4], [0, 1, 1, 2, 3], "unexpected prefix"); + AllEqualityFactI(prefixes[5], [0, 1, 1, 2, 3, 5], "unexpected prefix"); + } + + @Test("QuantumSimulator") + operation TestSuccessfulRectangularFact() : Unit { + RectangularArrayFact([[1, 2], [3, 4]], "Array is not rectangular"); + RectangularArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not rectangular"); + } + + operation RectangularFactTestShouldFail() : Unit { + RectangularArrayFact([[1, 2], [3, 4, 5]], "Array is not rectangular"); + } + + @Test("QuantumSimulator") + operation TestSuccessfulSquareFact() : Unit { + SquareArrayFact([[1, 2], [3, 4]], "Array is not a square"); + } + + operation SquareFact1TestShouldFail() : Unit { + SquareArrayFact([[1, 2, 3], [4, 5, 6]], "Array is not a square"); + } + + operation SquareFact2TestShouldFail() : Unit { + SquareArrayFact([[1, 2], [3, 4, 5]], "Array is not a square"); } }