diff --git a/docs/docs/noir/concepts/data_types/arrays.md b/docs/docs/noir/concepts/data_types/arrays.md index e5e9f5a1d3b..d0d8eb70aa6 100644 --- a/docs/docs/noir/concepts/data_types/arrays.md +++ b/docs/docs/noir/concepts/data_types/arrays.md @@ -128,7 +128,9 @@ fn main() { ### sort_via -Sorts the array with a custom comparison function +Sorts the array with a custom comparison function. The ordering function must return true if the first argument should be sorted to be before the second argument or is equal to the second argument. + +Using this method with an operator like `<` that does not return `true` for equal values will result in an assertion failure for arrays with equal elements. ```rust fn sort_via(self, ordering: fn(T, T) -> bool) -> [T; N] @@ -139,10 +141,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md b/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md index 1424ca2df14..3c84da3f8ad 100644 --- a/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md +++ b/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md @@ -130,10 +130,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md b/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md index 1424ca2df14..3c84da3f8ad 100644 --- a/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md +++ b/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md @@ -130,10 +130,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md b/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md index 1424ca2df14..3c84da3f8ad 100644 --- a/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md +++ b/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md @@ -130,10 +130,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md b/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md index 1424ca2df14..3c84da3f8ad 100644 --- a/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md +++ b/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md @@ -130,10 +130,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md b/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md index 1424ca2df14..3c84da3f8ad 100644 --- a/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md +++ b/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md @@ -130,10 +130,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md b/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md index 5b4a544cf37..36410468ec1 100644 --- a/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md +++ b/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md @@ -130,10 +130,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md b/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md index 4c80d50ed01..addda1da8bc 100644 --- a/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md @@ -131,10 +131,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md index d95346454a9..fb81dcc3970 100644 --- a/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md @@ -137,10 +137,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md index ca54d82b26b..9a4c485feb1 100644 --- a/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.25.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.25.0/noir/concepts/data_types/arrays.md index ca54d82b26b..9a4c485feb1 100644 --- a/docs/versioned_docs/version-v0.25.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.25.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.26.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.26.0/noir/concepts/data_types/arrays.md index 95d749053e2..9b02d52e8a8 100644 --- a/docs/versioned_docs/version-v0.26.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.26.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.27.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.27.0/noir/concepts/data_types/arrays.md index 95d749053e2..9b02d52e8a8 100644 --- a/docs/versioned_docs/version-v0.27.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.27.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/arrays.md index 95d749053e2..9b02d52e8a8 100644 --- a/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.28.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/arrays.md index 95d749053e2..9b02d52e8a8 100644 --- a/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.29.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.30.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.30.0/noir/concepts/data_types/arrays.md index 95d749053e2..9b02d52e8a8 100644 --- a/docs/versioned_docs/version-v0.30.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.30.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.31.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.31.0/noir/concepts/data_types/arrays.md index 95d749053e2..9b02d52e8a8 100644 --- a/docs/versioned_docs/version-v0.31.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.31.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.32.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.32.0/noir/concepts/data_types/arrays.md index 9a4ab5d3c1f..d26f6dff070 100644 --- a/docs/versioned_docs/version-v0.32.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.32.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/docs/versioned_docs/version-v0.33.0/noir/concepts/data_types/arrays.md b/docs/versioned_docs/version-v0.33.0/noir/concepts/data_types/arrays.md index 9a4ab5d3c1f..d26f6dff070 100644 --- a/docs/versioned_docs/version-v0.33.0/noir/concepts/data_types/arrays.md +++ b/docs/versioned_docs/version-v0.33.0/noir/concepts/data_types/arrays.md @@ -139,10 +139,10 @@ example ```rust fn main() { let arr = [42, 32] - let sorted_ascending = arr.sort_via(|a, b| a < b); + let sorted_ascending = arr.sort_via(|a, b| a <= b); assert(sorted_ascending == [32, 42]); // verifies - let sorted_descending = arr.sort_via(|a, b| a > b); + let sorted_descending = arr.sort_via(|a, b| a >= b); assert(sorted_descending == [32, 42]); // does not verify } ``` diff --git a/noir_stdlib/src/array/check_shuffle.nr b/noir_stdlib/src/array/check_shuffle.nr new file mode 100644 index 00000000000..26f5ced3467 --- /dev/null +++ b/noir_stdlib/src/array/check_shuffle.nr @@ -0,0 +1,116 @@ +use crate::cmp::Eq; + +unconstrained fn __get_shuffle_indices(lhs: [T; N], rhs: [T; N]) -> [Field; N] where T: Eq { + let mut shuffle_indices: [Field;N ] = [0; N]; + + let mut shuffle_mask: [bool; N] = [false; N]; + for i in 0..N { + let mut found = false; + for j in 0..N { + if ((shuffle_mask[j] == false) & (!found)) { + if (lhs[i] == rhs[j]) { + found = true; + shuffle_indices[i] = j as Field; + shuffle_mask[j] = true; + } + } + if (found) { + continue; + } + } + assert(found == true, "check_shuffle, lhs and rhs arrays do not contain equivalent values"); + } + + shuffle_indices +} + +unconstrained fn __get_index(indices: [Field; N], idx: Field) -> Field { + let mut result = 0; + for i in 0..N { + if (indices[i] == idx) { + result = i as Field; + break; + } + } + result +} + +pub(crate) fn check_shuffle(lhs: [T; N], rhs: [T; N]) where T: Eq { + unsafe { + let shuffle_indices = __get_shuffle_indices(lhs, rhs); + + for i in 0..N { + let idx = __get_index(shuffle_indices, i as Field); + assert_eq(shuffle_indices[idx], i as Field); + } + for i in 0..N { + let idx = shuffle_indices[i]; + let expected = rhs[idx]; + let result = lhs[i]; + assert_eq(expected, result); + } + } +} + +mod test { + use super::check_shuffle; + use crate::cmp::Eq; + + struct CompoundStruct { + a: bool, + b: Field, + c: u64 + } + impl Eq for CompoundStruct { + fn eq(self, other: Self) -> bool { + (self.a == other.a) & (self.b == other.b) & (self.c == other.c) + } + } + + #[test] + fn test_shuffle() { + let lhs: [Field; 5] = [0, 1, 2, 3, 4]; + let rhs: [Field; 5] = [2, 0, 3, 1, 4]; + check_shuffle(lhs, rhs); + } + + #[test] + fn test_shuffle_identity() { + let lhs: [Field; 5] = [0, 1, 2, 3, 4]; + let rhs: [Field; 5] = [0, 1, 2, 3, 4]; + check_shuffle(lhs, rhs); + } + + #[test(should_fail_with = "check_shuffle, lhs and rhs arrays do not contain equivalent values")] + fn test_shuffle_fail() { + let lhs: [Field; 5] = [0, 1, 2, 3, 4]; + let rhs: [Field; 5] = [0, 1, 2, 3, 5]; + check_shuffle(lhs, rhs); + } + + #[test(should_fail_with = "check_shuffle, lhs and rhs arrays do not contain equivalent values")] + fn test_shuffle_duplicates() { + let lhs: [Field; 5] = [0, 1, 2, 3, 4]; + let rhs: [Field; 5] = [0, 1, 2, 3, 3]; + check_shuffle(lhs, rhs); + } + + #[test] + fn test_shuffle_compound_struct() { + let lhs: [CompoundStruct; 5] = [ + CompoundStruct { a: false, b: 0, c: 12345 }, + CompoundStruct { a: false, b: -100, c: 54321 }, + CompoundStruct { a: true, b: 5, c: 0xffffffffffffffff }, + CompoundStruct { a: true, b: 9814, c: 0xeeffee0011001133 }, + CompoundStruct { a: false, b: 0x155, c: 0 } + ]; + let rhs: [CompoundStruct; 5] = [ + CompoundStruct { a: false, b: 0x155, c: 0 }, + CompoundStruct { a: false, b: 0, c: 12345 }, + CompoundStruct { a: false, b: -100, c: 54321 }, + CompoundStruct { a: true, b: 9814, c: 0xeeffee0011001133 }, + CompoundStruct { a: true, b: 5, c: 0xffffffffffffffff } + ]; + check_shuffle(lhs, rhs); + } +} diff --git a/noir_stdlib/src/array.nr b/noir_stdlib/src/array/mod.nr similarity index 57% rename from noir_stdlib/src/array.nr rename to noir_stdlib/src/array/mod.nr index 68e134b56fa..f3cf6b78081 100644 --- a/noir_stdlib/src/array.nr +++ b/noir_stdlib/src/array/mod.nr @@ -1,63 +1,15 @@ -use crate::cmp::Ord; +use crate::cmp::{Eq, Ord}; use crate::convert::From; +use crate::runtime::is_unconstrained; + +mod check_shuffle; +mod quicksort; impl [T; N] { /// Returns the length of the slice. #[builtin(array_len)] pub fn len(self) -> u32 {} - pub fn sort(self) -> Self where T: Ord { - self.sort_via(|a: T, b: T| a <= b) - } - - pub fn sort_via(self, ordering: fn[Env](T, T) -> bool) -> Self { - let sorted_index = unsafe { - // Safety: These indices are asserted to be the sorted element indices via `find_index` - let sorted_index: [u32; N] = self.get_sorting_index(ordering); - - for i in 0..N { - let pos = find_index(sorted_index, i); - assert(sorted_index[pos] == i); - } - - sorted_index - }; - - // Sort the array using the indexes - let mut result = self; - for i in 0..N { - result[i] = self[sorted_index[i]]; - } - // Ensure the array is sorted - for i in 0..N - 1 { - assert(ordering(result[i], result[i + 1])); - } - - result - } - - /// Returns the index of the elements in the array that would sort it, using the provided custom sorting function. - unconstrained fn get_sorting_index(self, ordering: fn[Env](T, T) -> bool) -> [u32; N] { - let mut result = [0; N]; - let mut a = self; - for i in 0..N { - result[i] = i; - } - for i in 1..N { - for j in 0..i { - if ordering(a[i], a[j]) { - let old_a_j = a[j]; - a[j] = a[i]; - a[i] = old_a_j; - let old_j = result[j]; - result[j] = result[i]; - result[i] = old_j; - } - } - } - result - } - #[builtin(as_slice)] pub fn as_slice(self) -> [T] {} @@ -114,6 +66,38 @@ impl [T; N] { } } +impl [T; N] where T: Ord + Eq { + pub fn sort(self) -> Self { + self.sort_via(|a: T, b: T| a <= b) + } +} + +impl [T; N] where T: Eq { + + /// Sorts the array using a custom predicate function `ordering`. + /// + /// The `ordering` function must be designed to return `true` for equal valued inputs + /// If this is not done, `sort_via` will fail to sort inputs with duplicated elements. + pub fn sort_via(self, ordering: fn[Env](T, T) -> bool) -> Self { + unsafe { + // Safety: `sorted` array is checked to be: + // a. a permutation of `input`'s elements + // b. satisfying the predicate `ordering` + let sorted = quicksort::quicksort(self, ordering); + + if !is_unconstrained() { + for i in 0..N - 1 { + assert( + ordering(sorted[i], sorted[i + 1]), "Array has not been sorted correctly according to `ordering`." + ); + } + check_shuffle::check_shuffle(self, sorted); + } + sorted + } + } +} + impl [u8; N] { /// Convert a sequence of bytes as-is into a string. /// This function performs no UTF-8 validation or similar. @@ -121,18 +105,6 @@ impl [u8; N] { pub fn as_str_unchecked(self) -> str {} } -// helper function used to look up the position of a value in an array of Field -// Note that function returns 0 if the value is not found -unconstrained fn find_index(a: [u32; N], find: u32) -> u32 { - let mut result = 0; - for i in 0..a.len() { - if a[i] == find { - result = i; - } - } - result -} - impl From> for [u8; N] { fn from(s: str) -> Self { s.as_bytes() diff --git a/noir_stdlib/src/array/quicksort.nr b/noir_stdlib/src/array/quicksort.nr new file mode 100644 index 00000000000..6a54ed246f5 --- /dev/null +++ b/noir_stdlib/src/array/quicksort.nr @@ -0,0 +1,39 @@ +unconstrained fn partition( + arr: &mut [T; N], + low: u32, + high: u32, + sortfn: fn[Env](T, T) -> bool +) -> u32 { + let pivot = high; + let mut i = low; + for j in low..high { + if (sortfn(arr[j], arr[pivot])) { + let temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + i += 1; + } + } + let temp = arr[i]; + arr[i] = arr[pivot]; + arr[pivot] = temp; + i +} + +unconstrained fn quicksort_recursive(arr: &mut [T; N], low: u32, high: u32, sortfn: fn[Env](T, T) -> bool) { + if low < high { + let pivot_index = partition(arr, low, high, sortfn); + if pivot_index > 0 { + quicksort_recursive(arr, low, pivot_index - 1, sortfn); + } + quicksort_recursive(arr, pivot_index + 1, high, sortfn); + } +} + +unconstrained pub(crate) fn quicksort(_arr: [T; N], sortfn: fn[Env](T, T) -> bool) -> [T; N] { + let mut arr: [T; N] = _arr; + if arr.len() <= 1 {} else { + quicksort_recursive(&mut arr, 0, arr.len() - 1, sortfn); + } + arr +} diff --git a/test_programs/execution_success/higher_order_functions/src/main.nr b/test_programs/execution_success/higher_order_functions/src/main.nr index 6583f961d58..0a498e74ad1 100644 --- a/test_programs/execution_success/higher_order_functions/src/main.nr +++ b/test_programs/execution_success/higher_order_functions/src/main.nr @@ -63,7 +63,7 @@ fn test_array_functions() { // // opened #2121 for it // https://github.com/noir-lang/noir/issues/2121 - // let descending = myarray.sort_via(|a, b| a > b); + // let descending = myarray.sort_via(|a, b| a >= b); // assert(descending == [3, 2, 1]); assert(evens.map(|n| n / 2) == myarray); assert(evens.map(|n| n / two) == myarray);