This repository was archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 180
Add new Sorted fn for merge sort. #327
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
a09ae2b
Add new Sorted fn for merge sort.
cgranade 4405238
Fix ⓒ header.
cgranade 358eacd
Update Standard/src/Arrays/Sorted.qs
c7eaf1b
Added lexographic comparison, new tests.
cgranade 9d4b439
Merge branch 'cgranade/sorted' of https://github.com/microsoft/Quantu…
cgranade 79d7d6a
Merge branch 'feature/arrays' into cgranade/sorted
547a930
Merge feature/arrays into cgranade/sorted
github-actions[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| namespace Microsoft.Quantum.Arrays { | ||
| open Microsoft.Quantum.Intrinsic; | ||
| open Microsoft.Quantum.Canon; | ||
|
|
||
| /// # Summary | ||
| /// Given two sorted arrays, returns a single array containing the | ||
| /// elements of both in sorted order. Used internally by merge sort. | ||
| internal function Merged<'T>(comparison : (('T, 'T) -> Bool), left : 'T[], right : 'T[]) : 'T[] { | ||
| mutable result = new 'T[0]; | ||
| mutable l = left; | ||
| mutable r = right; | ||
| while ((not IsEmpty(l)) and (not IsEmpty(r))) { | ||
| if (comparison(Head(l), Head(r))) { | ||
| set result += [Head(l)]; | ||
| set l = Rest(l); | ||
| } else { | ||
| set result += [Head(r)]; | ||
| set r = Rest(r); | ||
| } | ||
| } | ||
|
|
||
| // Note that at this point, either or both of l and r are empty, | ||
| // such that we can simply append both to our result to get the | ||
| // whole merged array. | ||
| return result + l + r; | ||
| } | ||
|
|
||
| /// # 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` occuring 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. If this property does not hold, then the output of this | ||
| /// function may be incorrect. | ||
| function IsSorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : Bool { | ||
| return All( | ||
| comparison, | ||
| Zip(Most(array), Rest(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. | ||
| /// | ||
| /// # Ouput | ||
| /// An array containing the same elements as `array`, such that for all | ||
| /// elements `a` occuring earlier than elements `b`, `comparison(a, b)` | ||
| /// is `true`. | ||
| /// | ||
| /// # Example | ||
| /// The following snippet sorts an array of integers to occur in ascending | ||
| /// order: | ||
| /// ```Q# | ||
| /// 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. | ||
| /// | ||
| /// As this is a function, the results are completely determinstic, even | ||
| /// when two elements are considered equal under `comparison`; | ||
| /// that is, when `comparison(a, b)` and `comparison(b, a)` are both `true`. | ||
| /// In particular, the sort performed by this function is guaranteed to be | ||
| /// stable, so that if two elements `a` and `b` occur in that order within | ||
| /// `array` and are considered equal under `comparison`, then `a` will also | ||
| /// appear before `b` in the output. | ||
| /// | ||
| /// For example: | ||
| /// ```Q# | ||
| /// function LastDigitLessThanOrEqual(left : Int, right : Int) : Bool { | ||
| /// return LessThanOrEqualI( | ||
| /// left % 10, right % 10 | ||
| /// ); | ||
| /// } | ||
| /// | ||
| /// function SortedByLastDigit() : Int[] { | ||
| /// return Sorted(LastDigitLessThanOrEqual, [3, 37, 11, 17]); | ||
| /// } | ||
| /// // returns [11, 3, 37, 17]. | ||
| /// ``` | ||
cgranade marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| function Sorted<'T>(comparison : (('T, 'T) -> Bool), array : 'T[]) : 'T[] { | ||
| if (Length(array) <= 1) { | ||
| return array; | ||
| } else { | ||
| let idxPivot = Length(array) / 2; | ||
| let left = array[...idxPivot - 1]; | ||
| let right = array[idxPivot...]; | ||
|
|
||
| // Sort each sublist, then merge them back into a single combined | ||
| // list and return. | ||
| return Merged<'T>( | ||
| comparison, | ||
| Sorted(comparison, left), | ||
| Sorted(comparison, right) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| namespace Microsoft.Quantum.Logical { | ||
| open Microsoft.Quantum.Arrays; | ||
| open Microsoft.Quantum.Intrinsic; | ||
| open Microsoft.Quantum.Canon; | ||
|
|
||
| /// # Summary | ||
| /// Given a comparison function, returns a new function that | ||
| /// lexographically compares two arrays. | ||
| /// | ||
| /// # Type Parameters | ||
| /// ## 'T | ||
| /// The type of the elements of the arrays being compared. | ||
| /// | ||
| /// # Input | ||
| /// ## elementComparison | ||
| /// A function that compares two elements `x` and `y` and returns if | ||
| /// `x` is less than or equal to `y`. | ||
| /// | ||
| /// # Output | ||
| /// A function that compares two arrays `xs` and `ys` and returns if | ||
| /// `xs` occurs before or equal to `ys` in lexographical ordering. | ||
| /// | ||
| /// # Remarks | ||
| /// The lexographic comparison between two arrays `xs` and `ys` is defined | ||
| /// by the following procedure. We say that two elements `x` and `y` | ||
| /// are equivalent if `elementComparison(x, y)` and `elementComparison(y, x)` | ||
| /// are both true. | ||
| /// | ||
| /// - Both arrays are compared element-by-element until the first pair of | ||
| /// elements that are not equivalent. The array containing the element | ||
| /// that occurs first according to `elementComparison` is said to occur | ||
| /// first in lexographical ordering. | ||
| /// - If no inequivalent elements are found, and one array is longer than | ||
| /// the other, the shorter array is said to occur first. | ||
| /// | ||
| /// # Examples | ||
| /// ```Q# | ||
| /// let arrayComparison = LexographicComparison(LessThanOrEqualD); | ||
| /// let data = [ | ||
| /// [1.1, 2.2, 3.3], | ||
| /// [1.1, 2.2], | ||
| /// [0.2, 2.2], | ||
| /// [1.1, 2.7] | ||
| /// ]; | ||
| /// let sorted = Sorted(arrayComparison, data); | ||
| /// // sorted: | ||
| /// // [ | ||
| /// // [0.2, 2.2], | ||
| /// // [1.1, 2.2], | ||
| /// // [1.1, 2.2, 3.3], | ||
| /// // [1.1, 2.7] | ||
| /// // ]; | ||
| /// ``` | ||
| /// | ||
| /// # See Also | ||
| /// - Microsoft.Quantum.Arrays.Sorted | ||
| function LexographicComparison<'T>(elementComparison : (('T, 'T) -> Bool)) : (('T[], 'T[]) -> Bool) { | ||
| return LessThanLexographic(elementComparison, _, _); | ||
| } | ||
|
|
||
| /// # Summary | ||
| /// Used to implement `LexographicComparison`. | ||
| internal function LessThanLexographic<'T>(comparison : (('T, 'T) -> Bool), left : 'T[], right : 'T[]) : Bool { | ||
| for ((l, r) in Zip(left, right)) { | ||
| let lessThanOrEqual = comparison(l, r); | ||
| let greaterThanOrEqual = comparison(r, l); | ||
| let equal = lessThanOrEqual and greaterThanOrEqual; | ||
| if (lessThanOrEqual and not equal) { | ||
| return true; | ||
| } elif (greaterThanOrEqual and not equal) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| // At this point, all items in the common prefix of both arrays | ||
| // are equal to each other under comparison (l ≤ r and r ≤ l). | ||
| // Thus, if left is shorter than or equal to right, then left occurs | ||
| // at or before right in lexographical ordering. | ||
| return Length(left) <= Length(right); | ||
| } | ||
|
|
||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| namespace Microsoft.Quantum.Arrays { | ||
| open Microsoft.Quantum.Random; | ||
| open Microsoft.Quantum.Diagnostics; | ||
| open Microsoft.Quantum.Logical; | ||
|
|
||
| @Test("QuantumSimulator") | ||
| function IntsAreSorted() : Unit { | ||
| Fact(IsSorted(LessThanOrEqualI, [1, 10, 100]), "[1, 10, 100] was marked as unsorted."); | ||
| } | ||
|
|
||
| @Test("QuantumSimulator") | ||
| function DoublesAreSorted() : Unit { | ||
| Fact(IsSorted(LessThanOrEqualD, [1.0, 10.1, 100.2]), "[1.0, 10.1, 100.2] was marked as unsorted."); | ||
| } | ||
|
|
||
| @Test("QuantumSimulator") | ||
| function IntsAreNotSorted() : Unit { | ||
| Contradiction(IsSorted(LessThanOrEqualI, [100, 10, 3]), "[100, 10, 3] was marked as sorted."); | ||
| } | ||
|
|
||
| @Test("QuantumSimulator") | ||
| function SortedIntsAreSorted() : Unit { | ||
cgranade marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Fact(IsSorted(LessThanOrEqualI, | ||
| Sorted(LessThanOrEqualI, [100, 10, 3])), | ||
| "Sorted(<=, [100, 10, 3]) was marked as unsorted." | ||
| ); | ||
| } | ||
|
|
||
| @Test("QuantumSimulator") | ||
| function SortedDoublesAreSorted() : Unit { | ||
| Fact(IsSorted(LessThanOrEqualD, | ||
| Sorted(LessThanOrEqualD, [100.0, 10.1, 3.14])), | ||
| "Sorted(<=, [100.0, 10.1, 3.14]) was marked as unsorted." | ||
| ); | ||
| } | ||
|
|
||
| @Test("QuantumSimulator") | ||
| operation CheckRandomArraysAreSortedWhenSorted() : Unit { | ||
| let nItems = 100; | ||
| let nTrials = 10; | ||
| let maxItem = 1000; | ||
| for (_ in 0..nTrials - 1) { | ||
| let data = DrawMany((DiscreteUniformDistribution(0, maxItem))::Sample, nItems, ()); | ||
| Fact(IsSorted(LessThanOrEqualI, Sorted(LessThanOrEqualI, data)), $"{data} was not sorted after running Sorted."); | ||
| } | ||
| } | ||
|
|
||
| @Test("QuantumSimulator") | ||
| function LexographicSortIsCorrect() : Unit { | ||
| let arrayComparison = LexographicComparison(LessThanOrEqualI); | ||
| let data = [ | ||
| [1, 2, 3], | ||
| [1, 2], | ||
| [0, 2], | ||
| [1, 3] | ||
| ]; | ||
| let sorted = Sorted(arrayComparison, data); | ||
|
|
||
| AllEqualityFactI( | ||
| sorted[0], [0, 2], "0th item was not correct." | ||
| ); | ||
| AllEqualityFactI( | ||
| sorted[1], [1, 2], "1st item was not correct." | ||
| ); | ||
| AllEqualityFactI( | ||
| sorted[2], [1, 2, 3], "2nd item was not correct." | ||
| ); | ||
| AllEqualityFactI( | ||
| sorted[3], [1, 3], "3rd item was not correct." | ||
| ); | ||
| } | ||
|
|
||
| } | ||
cgranade marked this conversation as resolved.
Show resolved
Hide resolved
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| namespace Microsoft.Quantum.Tests { | ||
| open Microsoft.Quantum.Logical; | ||
| open Microsoft.Quantum.Diagnostics; | ||
| open Microsoft.Quantum.Math; | ||
| open Microsoft.Quantum.Arrays; | ||
|
|
||
| function LexographicComparisonIsCorrect() : Unit { | ||
| let lexographicComparison = LexographicComparison(LessThanOrEqualD); | ||
| Fact( | ||
| lexographicComparison( | ||
| [1.1, 2.2], [1.1, 2.2, 3.3] | ||
| ), | ||
| "Shorter array should have occured first." | ||
| ); | ||
| Fact( | ||
| lexographicComparison( | ||
| [0.7, 2.2], [1.1, 2.2] | ||
| ), | ||
| "Array with smaller first element should have occured first." | ||
| ); | ||
| Fact( | ||
| lexographicComparison( | ||
| [1.1, 2.2], [1.1, 2.2] | ||
| ), | ||
| "Identical arrays should be marked as less than or equal." | ||
| ); | ||
| Contradiction( | ||
| lexographicComparison( | ||
| [1.1, 2.7], [1.1, 2.2, 3.3] | ||
| ), | ||
| "Array with larger second element should have occured second." | ||
| ); | ||
| } | ||
|
|
||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.