From 71be8e9fe10e1443eaefa9c1d30167879908f566 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 16 Mar 2023 11:24:39 +0100 Subject: [PATCH 01/10] agg function headers --- src/FSharp.Core/array.fsi | 199 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index ca8e2013493..26b031840e5 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3190,6 +3190,205 @@ module Array = [] val tryPick: chooser:('T -> 'U option) -> array:'T[] -> 'U option + + + /// Applies a function to each element of the array in parallel, threading an accumulator argument + /// through the computation for each thread involved in the computation. After processing entire input, results from all threads are reduced together. + /// Raises ArgumentException if the array is empty. + + /// The order of processing is not guaranteed. For that reason, the 'reduce' function argument should be commutative. + /// (That is, changing the order of execution must not affect the result) + /// Also, compared the non-parallel version of Array.reduce, the 'reduce' function may be invoked more times due to the resulting reduction from participating threads. + /// + /// The function to reduce a pair of elements to a single element. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The final result of the reductions. + /// + /// + /// + /// let inputs = [| 1; 3; 4; 2 |] + /// + /// inputs |> Array.Parallel.reduce (fun a b -> a + b) + /// + /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. + /// + [] + val reduce: reduction:('T -> 'T -> 'T) -> array:'T[] -> 'T + + /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. + /// + /// Throws ArgumentException for empty arrays. + /// + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The maximum element. + /// + /// + /// + /// let inputs = [| 10; 12; 11 |] + /// + /// inputs |> Array.Parallel.max + /// + /// Evaluates to 12 + /// + /// + /// + /// + /// let inputs: int[]= [| |] + /// + /// inputs |> Array.Parallel.max + /// + /// Throws System.ArgumentException. + /// + [] + val inline max: array:'T[] -> 'T when 'T : comparison + + /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. + /// + /// Throws ArgumentException for empty arrays. + /// + /// The function to transform the elements into a type supporting comparison. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The maximum element. + /// + /// + /// + /// let inputs = [| "aaa"; "b"; "cccc" |] + /// + /// inputs |> Array.maxBy (fun s -> s.Length) + /// + /// Evaluates to "cccc" + /// + /// + /// + /// + /// let inputs: string[]= [| |] + /// + /// inputs |> Array.maxBy (fun s -> s.Length) + /// + /// Throws System.ArgumentException. + /// + [] + val inline maxBy : projection:('T -> 'U) -> array:'T[] -> 'T when 'U : comparison + + /// Returns the lowest of all elements of the array, compared via Operators.min. + /// + /// Throws ArgumentException for empty arrays + /// + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The minimum element. + /// + /// + /// + /// let inputs = [| 10; 12; 11 |] + /// + /// inputs |> Array.min + /// + /// Evaluates to 10 + /// + /// + /// + /// + /// let inputs: int[]= [| |] + /// + /// inputs |> Array.min + /// + /// Throws System.ArgumentException. + /// + [] + val inline min: array:'T[] -> 'T when 'T : comparison + + /// Returns the lowest of all elements of the array, compared via Operators.min on the function result. + /// + /// Throws ArgumentException for empty arrays. + /// + /// The function to transform the elements into a type supporting comparison. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The minimum element. + /// + /// + /// + /// let inputs = [| "aaa"; "b"; "cccc" |] + /// + /// inputs |> Array.minBy (fun s -> s.Length) + /// + /// Evaluates to "b" + /// + /// + /// + /// + /// let inputs: string[]= [| |] + /// + /// inputs |> Array.minBy (fun s -> s.Length) + /// + /// Throws System.ArgumentException. + /// + [] + val inline minBy : projection:('T -> 'U) -> array:'T[] -> 'T when 'U : comparison + + /// Returns the sum of the elements in the array. + /// + /// The input array. + /// + /// The resulting sum. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let input = [| 1; 5; 3; 2 |] + /// + /// input |> Array.sum + /// + /// Evaluates to 11. + /// + [] + val inline sum: array: ^T[] -> ^T + when ^T : (static member ( + ) : ^T * ^T -> ^T) + and ^T : (static member Zero : ^T) + + + /// Returns the sum of the results generated by applying the function to each element of the array. + /// + /// The function to transform the array elements into the type to be summed. + /// The input array. + /// + /// The resulting sum. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let input = [| "aa"; "bbb"; "cc" |] + /// + /// input |> Array.sumBy (fun s -> s.Length) + /// + /// Evaluates to 7. + /// + [] + val inline sumBy: projection:('T -> ^U) -> array:'T[] -> ^U + when ^U : (static member ( + ) : ^U * ^U -> ^U) + and ^U : (static member Zero : ^U) + /// Apply the given function to each element of the array. Return /// the array comprised of the results x for each element where /// the function returns Some(x). From 3a0cf2200eed562a96d32aa7c171b9fc8e9d5d24 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 17 Mar 2023 11:45:41 +0100 Subject: [PATCH 02/10] reduceBy added to public signature --- src/FSharp.Core/array.fs | 90 +++++++++++++++++++++++++- src/FSharp.Core/array.fsi | 133 ++++++++++++++++++++++++++++++++------ 2 files changed, 201 insertions(+), 22 deletions(-) diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index a4a80bc9789..31f70c69dc8 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -2061,7 +2061,7 @@ module Array = let private maxPartitions = Environment.ProcessorCount // The maximum number of partitions to use let private minChunkSize = 256 // The minimum size of a chunk to be sorted in parallel - let private createPartitionsUpTo maxIdxExclusive (array: 'T[]) = + let private createPartitionsUpToWithMinChunkSize maxIdxExclusive minChunkSize (array: 'T[]) = [| let chunkSize = match maxIdxExclusive with @@ -2078,6 +2078,94 @@ module Array = yield new ArraySegment<'T>(array, offset, maxIdxExclusive - offset) |] + let private createPartitionsUpTo maxIdxExclusive (array: 'T[]) = + createPartitionsUpToWithMinChunkSize maxIdxExclusive minChunkSize array + + let chunkNonEmptyArrayAndPrepareEmptyResults (array: 'T[]) = + checkNonNull "array" array + if array.Length = 0 then + invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString + + let chunks = createPartitionsUpToWithMinChunkSize array.Length 1 array + chunks,Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked chunks.Length + + + [] + let reduceBy (projection:'T -> 'U) (reduction:'U -> 'U ->'U) (array: 'T[]) = + (* This function is there also as a support vehicle for other aggregations. + It is a public in order to be called from inlined functions, the benefit of inlining call into it is significant *) + + let chunks,chunkResults = chunkNonEmptyArrayAndPrepareEmptyResults array + + Parallel.For( + 0, + chunks.Length, + fun chunkIdx -> + let chunk = chunks[chunkIdx] + let mutable res = projection array[chunk.Offset] + let lastIdx = chunk.Offset + chunk.Count - 1 + + for i = chunk.Offset + 1 to lastIdx do + let projected = projection array[i] + res <- reduction res projected + + chunkResults[chunkIdx] <- res + ) |> ignore + + let mutable finalResult = chunkResults[0] + + for i = 1 to chunkResults.Length - 1 do + finalResult <- reduction finalResult chunkResults[i] + + finalResult + + [] + let inline reduce ([] reduction) (array: _[]) = array |> reduceBy id reduction + + [] + let inline minBy ([] projection) (array: _[]) = + let inline vFst struct(a,_) = a + let inline vSnd struct(_,b) = b + array + |> reduceBy (fun x -> struct(projection x, x)) (fun a b -> if vFst a < vFst b then a else b) + |> vSnd + + [] + let inline min (array: _[]) = + array |> reduce (fun a b -> if a < b then a else b) + + [] + let inline sumBy ([] projection: 'T -> ^U) (array: 'T[]) : ^U = + if array.Length = 0 then + LanguagePrimitives.GenericZero + else + array |> reduceBy projection Operators.Checked.(+) + + [] + let inline sum (array: ^T[]) : ^T = + array |> sumBy id + + [] + let inline maxBy projection (array: _[]) = + let inline vFst struct(a,_) = a + let inline vSnd struct(_,b) = b + array + |> reduceBy (fun x -> struct(projection x, x)) (fun a b -> if vFst a > vFst b then a else b) + |> vSnd + + [] + let inline max (array: _[]) = + array |> reduce (fun a b -> if a > b then a else b) + + [] + let inline averageBy ([] projection: 'T -> ^U) (array: 'T[]) : ^U = + let sum = array |> sumBy projection + LanguagePrimitives.DivideByInt sum (array.Length) + + [] + let inline average (array: 'T[]) = + array |> averageBy id + let inline groupByImplParallel (comparer: IEqualityComparer<'SafeKey>) ([] keyf: 'T -> 'SafeKey) diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 26b031840e5..7bd7121e157 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3190,8 +3190,6 @@ module Array = [] val tryPick: chooser:('T -> 'U option) -> array:'T[] -> 'U option - - /// Applies a function to each element of the array in parallel, threading an accumulator argument /// through the computation for each thread involved in the computation. After processing entire input, results from all threads are reduced together. /// Raises ArgumentException if the array is empty. @@ -3214,10 +3212,37 @@ module Array = /// /// inputs |> Array.Parallel.reduce (fun a b -> a + b) /// - /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. + /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. /// [] - val reduce: reduction:('T -> 'T -> 'T) -> array:'T[] -> 'T + val inline reduce: reduction:('T -> 'T -> 'T) -> array:'T[] -> 'T + + /// Applies a projection function to each element of the array in parallel, reducing elements in each thread with a dedicated 'reduction' function. + /// After processing entire input, results from all threads are reduced together. + /// Raises ArgumentException if the array is empty. + + /// The order of processing is not guaranteed. For that reason, the 'reduction' function argument should be commutative. + /// (That is, changing the order of execution must not affect the result) + /// + /// The function to project from elements of the input array + /// The function to reduce a pair of projected elements to a single element. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// The final result of the reductions. + /// + /// + /// + /// let inputs = [| "1"; "3"; "4"; "2" |] + /// + /// inputs |> Array.Parallel.reduceBy (fun x -> int x) (+) + /// + /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. + /// + [] + val inline reduceBy: projection:('T -> 'U) -> reduction:('U -> 'U ->'U) -> array:'T[] -> 'U /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. /// @@ -3230,7 +3255,7 @@ module Array = /// /// The maximum element. /// - /// + /// /// /// let inputs = [| 10; 12; 11 |] /// @@ -3239,7 +3264,7 @@ module Array = /// Evaluates to 12 /// /// - /// + /// /// /// let inputs: int[]= [| |] /// @@ -3262,20 +3287,20 @@ module Array = /// /// The maximum element. /// - /// + /// /// /// let inputs = [| "aaa"; "b"; "cccc" |] /// - /// inputs |> Array.maxBy (fun s -> s.Length) + /// inputs |> Array.Parallel.maxBy (fun s -> s.Length) /// /// Evaluates to "cccc" /// /// - /// + /// /// /// let inputs: string[]= [| |] /// - /// inputs |> Array.maxBy (fun s -> s.Length) + /// inputs |> Array.Parallel.maxBy (fun s -> s.Length) /// /// Throws System.ArgumentException. /// @@ -3293,11 +3318,11 @@ module Array = /// /// The minimum element. /// - /// + /// /// /// let inputs = [| 10; 12; 11 |] /// - /// inputs |> Array.min + /// inputs |> Array.Parallel.min /// /// Evaluates to 10 /// @@ -3306,7 +3331,7 @@ module Array = /// /// let inputs: int[]= [| |] /// - /// inputs |> Array.min + /// inputs |> Array.Parallel.min /// /// Throws System.ArgumentException. /// @@ -3325,20 +3350,20 @@ module Array = /// /// The minimum element. /// - /// + /// /// /// let inputs = [| "aaa"; "b"; "cccc" |] /// - /// inputs |> Array.minBy (fun s -> s.Length) + /// inputs |> Array.Parallel.minBy (fun s -> s.Length) /// /// Evaluates to "b" /// /// - /// + /// /// /// let inputs: string[]= [| |] /// - /// inputs |> Array.minBy (fun s -> s.Length) + /// inputs |> Array.Parallel.minBy (fun s -> s.Length) /// /// Throws System.ArgumentException. /// @@ -3353,11 +3378,11 @@ module Array = /// /// Thrown when the input array is null. /// - /// + /// /// /// let input = [| 1; 5; 3; 2 |] /// - /// input |> Array.sum + /// input |> Array.Parallel.sum /// /// Evaluates to 11. /// @@ -3376,11 +3401,11 @@ module Array = /// /// Thrown when the input array is null. /// - /// + /// /// /// let input = [| "aa"; "bbb"; "cc" |] /// - /// input |> Array.sumBy (fun s -> s.Length) + /// input |> Array.Parallel.sumBy (fun s -> s.Length) /// /// Evaluates to 7. /// @@ -3389,6 +3414,72 @@ module Array = when ^U : (static member ( + ) : ^U * ^U -> ^U) and ^U : (static member Zero : ^U) + /// Returns the average of the elements in the array. + /// + /// The input array. + /// + /// Thrown when array is empty. + /// Thrown when the input array is null. + /// + /// The average of the elements in the array. + /// + /// + /// + /// [| 1.0; 2.0; 6.0 |] |> Array.Parallel.average + /// + /// Evaluates to 3.0 + /// + /// + /// + /// + /// [| |] |> Array.Parallel.average + /// + /// Throws ArgumentException + /// + [] + val inline average : array:^T[] -> ^T + when ^T : (static member ( + ) : ^T * ^T -> ^T) + and ^T : (static member DivideByInt : ^T*int -> ^T) + and ^T : (static member Zero : ^T) + + /// Returns the average of the elements generated by applying the function to each element of the array. + /// + /// The function to transform the array elements before averaging. + /// The input array. + /// + /// Thrown when array is empty. + /// + /// The computed average. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// type Foo = { Bar: float } + /// + /// let input = [| {Bar = 2.0}; {Bar = 4.0} |] + /// + /// input |> Array.Parallel.averageBy (fun foo -> foo.Bar) + /// + /// Evaluates to 3.0 + /// + /// + /// + /// + /// type Foo = { Bar: float } + /// + /// let input : Foo[] = [| |] + /// + /// input |> Array.Parallel.averageBy (fun foo -> foo.Bar) + /// + /// Throws ArgumentException + /// + [] + val inline averageBy : projection:('T -> ^U) -> array:'T[] -> ^U + when ^U : (static member ( + ) : ^U * ^U -> ^U) + and ^U : (static member DivideByInt : ^U*int -> ^U) + and ^U : (static member Zero : ^U) + /// Apply the given function to each element of the array. Return /// the array comprised of the results x for each element where /// the function returns Some(x). From 2041e51add489dec1dcd8ddc81a42c753758dc0b Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 17 Mar 2023 15:21:03 +0100 Subject: [PATCH 03/10] tests added --- src/FSharp.Core/array.fs | 52 +++++----- src/FSharp.Core/array.fsi | 10 +- ...p.Core.SurfaceArea.netstandard20.debug.bsl | 16 +++- ...p.Core.SurfaceArea.netstandard21.debug.bsl | 16 +++- .../ArrayModule2.fs | 95 ++++++++++++++++++- .../CollectionModulesConsistency.fs | 49 ++++++---- .../ListProperties.fs | 10 +- .../Microsoft.FSharp.Collections/Utils.fs | 11 +-- 8 files changed, 196 insertions(+), 63 deletions(-) diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index 31f70c69dc8..46ada1aadd9 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -2081,21 +2081,19 @@ module Array = let private createPartitionsUpTo maxIdxExclusive (array: 'T[]) = createPartitionsUpToWithMinChunkSize maxIdxExclusive minChunkSize array - let chunkNonEmptyArrayAndPrepareEmptyResults (array: 'T[]) = + (* This function is there also as a support vehicle for other aggregations. + It is a public in order to be called from inlined functions, the benefit of inlining call into it is significant *) + [] + let reduceBy (projection: 'T -> 'U) (reduction: 'U -> 'U -> 'U) (array: 'T[]) = checkNonNull "array" array + if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString - let chunks = createPartitionsUpToWithMinChunkSize array.Length 1 array - chunks,Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked chunks.Length - - - [] - let reduceBy (projection:'T -> 'U) (reduction:'U -> 'U ->'U) (array: 'T[]) = - (* This function is there also as a support vehicle for other aggregations. - It is a public in order to be called from inlined functions, the benefit of inlining call into it is significant *) + let chunks = createPartitionsUpToWithMinChunkSize array.Length 2 array // We need at least 2 elements/chunk for 'reduction' - let chunks,chunkResults = chunkNonEmptyArrayAndPrepareEmptyResults array + let chunkResults = + Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked chunks.Length Parallel.For( 0, @@ -2110,7 +2108,8 @@ module Array = res <- reduction res projected chunkResults[chunkIdx] <- res - ) |> ignore + ) + |> ignore let mutable finalResult = chunkResults[0] @@ -2120,14 +2119,19 @@ module Array = finalResult [] - let inline reduce ([] reduction) (array: _[]) = array |> reduceBy id reduction + let inline reduce ([] reduction) (array: _[]) = + array |> reduceBy id reduction [] let inline minBy ([] projection) (array: _[]) = - let inline vFst struct(a,_) = a - let inline vSnd struct(_,b) = b - array - |> reduceBy (fun x -> struct(projection x, x)) (fun a b -> if vFst a < vFst b then a else b) + let inline vFst struct (a, _) = + a + + let inline vSnd struct (_, b) = + b + + array + |> reduceBy (fun x -> struct (projection x, x)) (fun a b -> if vFst a < vFst b then a else b) |> vSnd [] @@ -2139,7 +2143,7 @@ module Array = if array.Length = 0 then LanguagePrimitives.GenericZero else - array |> reduceBy projection Operators.Checked.(+) + array |> reduceBy projection Operators.Checked.(+) [] let inline sum (array: ^T[]) : ^T = @@ -2147,10 +2151,14 @@ module Array = [] let inline maxBy projection (array: _[]) = - let inline vFst struct(a,_) = a - let inline vSnd struct(_,b) = b - array - |> reduceBy (fun x -> struct(projection x, x)) (fun a b -> if vFst a > vFst b then a else b) + let inline vFst struct (a, _) = + a + + let inline vSnd struct (_, b) = + b + + array + |> reduceBy (fun x -> struct (projection x, x)) (fun a b -> if vFst a > vFst b then a else b) |> vSnd [] @@ -2159,7 +2167,7 @@ module Array = [] let inline averageBy ([] projection: 'T -> ^U) (array: 'T[]) : ^U = - let sum = array |> sumBy projection + let sum = array |> reduceBy projection Operators.Checked.(+) LanguagePrimitives.DivideByInt sum (array.Length) [] diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 7bd7121e157..b259f5d88f7 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3222,7 +3222,7 @@ module Array = /// Raises ArgumentException if the array is empty. /// The order of processing is not guaranteed. For that reason, the 'reduction' function argument should be commutative. - /// (That is, changing the order of execution must not affect the result) + /// (That is, changing the order of execution must not affect the result) /// /// The function to project from elements of the input array /// The function to reduce a pair of projected elements to a single element. @@ -3242,7 +3242,7 @@ module Array = /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. /// [] - val inline reduceBy: projection:('T -> 'U) -> reduction:('U -> 'U ->'U) -> array:'T[] -> 'U + val reduceBy: projection:('T -> 'U) -> reduction:('U -> 'U ->'U) -> array:'T[] -> 'U /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. /// @@ -3439,8 +3439,7 @@ module Array = [] val inline average : array:^T[] -> ^T when ^T : (static member ( + ) : ^T * ^T -> ^T) - and ^T : (static member DivideByInt : ^T*int -> ^T) - and ^T : (static member Zero : ^T) + and ^T : (static member DivideByInt : ^T*int -> ^T) /// Returns the average of the elements generated by applying the function to each element of the array. /// @@ -3477,8 +3476,7 @@ module Array = [] val inline averageBy : projection:('T -> ^U) -> array:'T[] -> ^U when ^U : (static member ( + ) : ^U * ^U -> ^U) - and ^U : (static member DivideByInt : ^U*int -> ^U) - and ^U : (static member Zero : ^U) + and ^U : (static member DivideByInt : ^U*int -> ^U) /// Apply the given function to each element of the array. Return /// the array comprised of the results x for each element where diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl index cfa1d024b69..87a0b4b7d42 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl @@ -40,11 +40,25 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) -Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average$W[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MaxBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Max[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult ReduceBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] MapIndexed[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl index 99505e2972c..0f5466a59f9 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl @@ -40,11 +40,25 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) -Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average$W[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MaxBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Max[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult ReduceBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] MapIndexed[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs index b10ce17fb2e..c20ee0aff46 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs @@ -443,9 +443,30 @@ type ArrayModule2() = // null array let nullArr = null:string[] CheckThrowsArgumentNullException (fun () -> Array.reduce (fun (x:string) (y:string) -> x.Remove(0,y.Length)) nullArr |> ignore) - - () + [] + member this.ParallelReduce() = + let assertSameBehavior reduction arr = + Assert.AreEqual(Array.reduce reduction arr, Array.Parallel.reduce reduction arr) + + [|5*4*3*2; 4;3;2;1|] |> assertSameBehavior (fun x y -> x/y) + [|"A"; "B"; "C" ; "D" |] |> assertSameBehavior (fun x y -> if x < y then x else y) + + CheckThrowsArgumentException (fun () -> Array.Parallel.reduce (fun x y -> x/y) [||] |> ignore) + let nullArr = null:string[] + CheckThrowsArgumentNullException (fun () -> Array.Parallel.reduce (fun (x:string) (y:string) -> x.Remove(0,y.Length)) nullArr |> ignore) + + [] + member this.ParallelReduceBy() = + let assertSameBehavior projection reduction arr = + Assert.AreEqual(arr |> Array.map projection |> Array.reduce reduction, Array.Parallel.reduceBy projection reduction arr) + + [|5*4*3*2; 4;3;2;1|] |> assertSameBehavior (fun x -> x * 2)(fun x y -> x/y) + [|"ABCD"; "B"; "C" ; "D" |] |> assertSameBehavior (fun x -> x.Length) (Operators.Checked.(+)) + + CheckThrowsArgumentException (fun () -> Array.Parallel.reduceBy id (fun x y -> x/y) [||] |> ignore) + let nullArr = null:string[] + CheckThrowsArgumentNullException (fun () -> Array.Parallel.reduceBy id (fun (x:string) (y:string) -> x.Remove(0,y.Length)) nullArr |> ignore) [] member this.ReduceBack() = @@ -865,6 +886,76 @@ type ArrayModule2() = CheckThrowsArgumentNullException (fun () -> Array.sumBy float32 nullArr |> ignore) () + member private _.TestOperation opName (actual:'T) (expected:'T) = + Assert.AreEqual(expected, actual, sprintf "%s: should be %A but is %A" opName expected actual) + + [] + member this.ParallelSum() = + this.TestOperation "sum empty" (Array.Parallel.sum [||]) (0) + this.TestOperation "sum single" (Array.Parallel.sum [|42|]) (42) + this.TestOperation "sum two" (Array.Parallel.sum [|42;-21|]) (21) + this.TestOperation "sum many" (Array.Parallel.sum [|1..1000|]) ((1000*1001) / 2) + this.TestOperation "sum floats" (Array.Parallel.sum [|1.;2.;3.|]) (6.) + this.TestOperation "sum infinity" (Array.Parallel.sum [|1.;2.;infinity;3.|]) (infinity) + this.TestOperation "sum nan" (Array.Parallel.sum [|infinity;nan|] |> Double.IsNaN) (true) + + [] + member this.ParallelSumBy() = + this.TestOperation "sum_by empty" (Array.Parallel.sumBy int [||]) (0) + this.TestOperation "sum_by single" (Array.Parallel.sumBy int [|42|]) (42) + this.TestOperation "sum_by two" (Array.Parallel.sumBy int [|42;-21|]) (21) + this.TestOperation "sum_by many" (Array.Parallel.sumBy int [|1..1000|]) ((1000*1001) / 2) + this.TestOperation "sum_by floats" (Array.Parallel.sumBy float [|1.;2.;3.|]) (6.) + this.TestOperation "sum_by infinity" (Array.Parallel.sumBy float [|1.;2.;infinity;3.|]) (infinity) + this.TestOperation "sum_by abs" (Array.Parallel.sumBy abs [|1; -2; 3; -4|]) (10) + this.TestOperation "sum_by string.Length" (Array.Parallel.sumBy String.length [|"abcd";"efg";"hi";"j";""|]) (10) + + [] + member this.ParallelAverage() = + CheckThrowsArgumentException (fun () -> Array.Parallel.average [||] |> ignore) + this.TestOperation "average of 0" (Array.Parallel.average [|0.|]) (0.) + this.TestOperation "average of single" (Array.Parallel.average [|4.|]) (4.) + this.TestOperation "average of two" (Array.Parallel.average [|4.;6.|]) (5.) + + [] + member this.ParallelAverageBy() = + CheckThrowsArgumentException (fun () -> Array.Parallel.averageBy float [||] |> ignore) + this.TestOperation "average_by of 0" (Array.Parallel.averageBy id [|0.|]) (0.) + this.TestOperation "average_by of single" (Array.Parallel.averageBy id [|4.|]) (4.) + this.TestOperation "average_by of two" (Array.Parallel.averageBy id [|4.;6.|]) (5.) + this.TestOperation "average_by int>float" (Array.Parallel.averageBy float [|0..1000|]) (500.) + this.TestOperation "average_by string.Length" (Array.Parallel.averageBy (String.length >> float) [|"ab";"cdef"|]) (3.) + + [] + member this.ParallelMin() = + CheckThrowsArgumentException (fun () -> Array.Parallel.min [||] |> ignore) + this.TestOperation "min single" (Array.Parallel.min [|42|]) (42) + this.TestOperation "min many" (Array.Parallel.min [|1..100|]) (1) + this.TestOperation "min floats" (Array.Parallel.min [|1.0;-1.0;nan;infinity;-infinity|]) (-infinity) + + [] + member this.ParallelMax() = + CheckThrowsArgumentException (fun () -> Array.Parallel.max [||] |> ignore) + this.TestOperation "max single" (Array.Parallel.max [|42|]) (42) + this.TestOperation "max many" (Array.Parallel.max [|1..100|]) (100) + this.TestOperation "max floats" (Array.Parallel.max [|1.0;-1.0;nan;infinity;-infinity|]) (infinity) + + [] + member this.ParallelMinBy() = + CheckThrowsArgumentException (fun () -> Array.Parallel.minBy string [||] |> ignore) + this.TestOperation "minBy single" (Array.Parallel.minBy string [|42|]) (42) + this.TestOperation "minBy int->string" (Array.Parallel.minBy string [|5..25|]) (10) + this.TestOperation "minBy many" (Array.Parallel.minBy (fun x -> -x) [|1..100|]) (100) + this.TestOperation "minBy floats" (Array.Parallel.minBy (fun x -> 1./float x) [|1..100|]) (100) + + [] + member this.ParallelMaxBy() = + CheckThrowsArgumentException (fun () -> Array.Parallel.maxBy int [||] |> ignore) + this.TestOperation "maxBy single" (Array.Parallel.maxBy string [|42|]) (42) + this.TestOperation "maxBy many" (Array.Parallel.maxBy (fun x -> -x) [|1..100|]) (1) + this.TestOperation "maxBy floats" (Array.Parallel.maxBy (fun x -> 1./float x) [|1..100|]) (1) + + [] member this.Tl() = // integer array diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs index 0494f9682d4..049ab533f8f 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs @@ -43,12 +43,15 @@ let ``append is consistent`` () = smallerSizeCheck append smallerSizeCheck append +let inline roundResult res = res |> Result.map (fun (x:float) -> Math.Round(x,8)) + let averageFloat (xs : NormalFloat []) = let xs = xs |> Array.map float - let s = runAndCheckErrorType (fun () -> xs |> Seq.average) - let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.average) - let a = runAndCheckErrorType (fun () -> xs |> Array.average) - consistency "average" s l a + let s = runAndCheckErrorType (fun () -> xs |> Seq.average) |> roundResult + let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.average) |> roundResult + let a = runAndCheckErrorType (fun () -> xs |> Array.average) |> roundResult + let pa = runAndCheckErrorType (fun () -> xs |> Array.Parallel.average) |> roundResult + consistencyIncludingParallel "average" s l a pa [] let ``average is consistent`` () = @@ -57,10 +60,11 @@ let ``average is consistent`` () = let averageBy (xs : float []) f = let xs = xs |> Array.map float let f x = (f x : NormalFloat) |> float - let s = runAndCheckErrorType (fun () -> xs |> Seq.averageBy f) - let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.averageBy f) - let a = runAndCheckErrorType (fun () -> xs |> Array.averageBy f) - consistency "averageBy" s l a + let s = runAndCheckErrorType (fun () -> xs |> Seq.averageBy f) |> roundResult + let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.averageBy f) |> roundResult + let a = runAndCheckErrorType (fun () -> xs |> Array.averageBy f) |> roundResult + let pa = runAndCheckErrorType (fun () -> xs |> Array.Parallel.averageBy f) |> roundResult + consistencyIncludingParallel "averageBy" s l a pa [] @@ -84,7 +88,9 @@ let choose<'a when 'a : equality> (xs : 'a []) f = let s = xs |> Seq.choose f |> Seq.toArray let l = xs |> List.ofArray |> List.choose f |> List.toArray let a = xs |> Array.choose f - consistency "contains" s l a + let pa = xs |> Array.Parallel.choose f + + consistencyIncludingParallel "contains" s l a pa [] let ``choose is consistent`` () = @@ -115,7 +121,8 @@ let collect<'a> (xs : 'a []) f = let s = xs |> Seq.collect f |> Seq.toArray let l = xs |> List.ofArray |> List.collect (fun x -> f x |> List.ofArray) |> List.toArray let a = xs |> Array.collect f - consistency "collect" s l a + let pa = xs |> Array.Parallel.collect f + consistencyIncludingParallel "collect" s l a pa @@ -701,7 +708,8 @@ let max<'a when 'a : comparison> (xs : 'a []) = let s = runAndCheckIfAnyError (fun () -> xs |> Seq.max) let l = runAndCheckIfAnyError (fun () -> xs |> List.ofArray |> List.max) let a = runAndCheckIfAnyError (fun () -> xs |> Array.max) - consistency "max" s l a + let pa = runAndCheckIfAnyError (fun () -> xs |> Array.Parallel.max) + consistencyIncludingParallel "max" s l a pa [] let ``max is consistent`` () = @@ -713,7 +721,8 @@ let maxBy<'a when 'a : comparison> (xs : 'a []) f = let s = runAndCheckIfAnyError (fun () -> xs |> Seq.maxBy f) let l = runAndCheckIfAnyError (fun () -> xs |> List.ofArray |> List.maxBy f) let a = runAndCheckIfAnyError (fun () -> xs |> Array.maxBy f) - consistency "maxBy" s l a + let pa = runAndCheckIfAnyError (fun () -> xs |> Array.Parallel.maxBy f) + consistencyIncludingParallel "maxBy" s l a pa [] let ``maxBy is consistent`` () = @@ -725,7 +734,8 @@ let min<'a when 'a : comparison> (xs : 'a []) = let s = runAndCheckIfAnyError (fun () -> xs |> Seq.min) let l = runAndCheckIfAnyError (fun () -> xs |> List.ofArray |> List.min) let a = runAndCheckIfAnyError (fun () -> xs |> Array.min) - consistency "min" s l a + let pa = runAndCheckIfAnyError (fun () -> xs |> Array.Parallel.min) + consistencyIncludingParallel "min" s l a pa [] let ``min is consistent`` () = @@ -737,7 +747,8 @@ let minBy<'a when 'a : comparison> (xs : 'a []) f = let s = runAndCheckIfAnyError (fun () -> xs |> Seq.minBy f) let l = runAndCheckIfAnyError (fun () -> xs |> List.ofArray |> List.minBy f) let a = runAndCheckIfAnyError (fun () -> xs |> Array.minBy f) - consistency "minBy" s l a + let pa = runAndCheckIfAnyError (fun () -> xs |> Array.Parallel.minBy f) + consistencyIncludingParallel "minBy" s l a pa [] let ``minBy is consistent`` () = @@ -809,8 +820,8 @@ let ``pick is consistent`` () = let reduce<'a when 'a : equality> (xs : 'a []) f = let s = runAndCheckErrorType (fun () -> xs |> Seq.reduce f) let l = runAndCheckErrorType (fun () -> xs |> List.ofArray |> List.reduce f) - let a = runAndCheckErrorType (fun () -> xs |> Array.reduce f) - consistency "reduce" s l a + let a = runAndCheckErrorType (fun () -> xs |> Array.reduce f) + consistency "reduce" s l a [] let ``reduce is consistent`` () = @@ -999,7 +1010,8 @@ let sum (xs : int []) = let s = run (fun () -> xs |> Seq.sum) let l = run (fun () -> xs |> Array.toList |> List.sum) let a = run (fun () -> xs |> Array.sum) - consistency "sum" s l a + let pa = run (fun () -> xs |> Array.Parallel.sum) + consistencyIncludingParallel "sum" s l a pa [] let ``sum is consistent`` () = @@ -1009,7 +1021,8 @@ let sumBy<'a> (xs : 'a []) (f:'a -> int) = let s = run (fun () -> xs |> Seq.sumBy f) let l = run (fun () -> xs |> Array.toList |> List.sumBy f) let a = run (fun () -> xs |> Array.sumBy f) - consistency "sumBy" s l a + let pa = run (fun () -> xs |> Array.Parallel.sumBy f) + consistencyIncludingParallel "sumBy" s l a pa [] let ``sumBy is consistent`` () = diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListProperties.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListProperties.fs index 53623f11548..00ae357fac6 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListProperties.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListProperties.fs @@ -377,7 +377,7 @@ type ListProperties () = let b = List.tryItem pos xs match a with - | Success a -> b.Value = a + | Ok a -> b.Value = a | _ -> b = None [] @@ -391,7 +391,7 @@ type ListProperties () = let b = List.tryPick f xs match a with - | Success a -> b.Value = a + | Ok a -> b.Value = a | _ -> b = None [] @@ -405,7 +405,7 @@ type ListProperties () = let b = List.tryLast xs match a with - | Success a -> b.Value = a + | Ok a -> b.Value = a | _ -> b = None [] @@ -503,7 +503,7 @@ type ListProperties () = match run (fun () -> xs |> List.indexed |> List.permute permutation) with - | Success s -> + | Ok s -> let originals = s |> List.map fst let rs = s |> List.map snd for o in originals do @@ -718,7 +718,7 @@ type ListProperties () = let a = run (fun () -> xs |> List.findIndex predicate) let b = run (fun () -> xs |> List.rev |> List.findIndexBack predicate) match a,b with - | Success a, Success b -> a = (xs.Length - b - 1) + | Ok a, Ok b -> a = (xs.Length - b - 1) | _ -> a = b [] diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/Utils.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/Utils.fs index 7d55fdcb142..ce2a299a3f1 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/Utils.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/Utils.fs @@ -4,29 +4,24 @@ module FSharp.Core.UnitTests.Collections.Utils open Xunit -type Result<'a> = -| Success of 'a -| Error of string - let run f = try - Success(f()) + Ok(f()) with | exn -> Error(exn.Message) let runAndCheckErrorType f = try - Success(f()) + Ok(f()) with | exn -> Error(exn.GetType().ToString()) let runAndCheckIfAnyError f = try - Success(f()) + Ok(f()) with | exn -> Error("") - let isStable sorted = sorted |> Seq.pairwise |> Seq.forall (fun ((ia, a),(ib, b)) -> if a = b then ia < ib else true) let isSorted sorted = sorted |> Seq.pairwise |> Seq.forall (fun (a,b) -> a <= b) From 4b1ff3441198d17a331a32e8c17eadbd2cde39c9 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 17 Mar 2023 15:31:15 +0100 Subject: [PATCH 04/10] release surface area update --- ...rp.Core.SurfaceArea.netstandard20.release.bsl | 16 +++++++++++++++- ...rp.Core.SurfaceArea.netstandard21.release.bsl | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl index 0c4153eb824..0df906c4632 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -40,11 +40,25 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) -Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average$W[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MaxBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Max[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult ReduceBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] MapIndexed[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl index ee1efd4c674..28be34402c6 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -40,11 +40,25 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) -Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[TKey,T[]][] GroupBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average$W[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Average[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MaxBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Max[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: T Sum[T](T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult AverageBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult ReduceBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy$W[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,TResult], Microsoft.FSharp.Core.FSharpFunc`2[TResult,Microsoft.FSharp.Core.FSharpFunc`2[TResult,TResult]], Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult SumBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] MapIndexed[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]], T[]) From a0ac6acfc08067ffb10bc63f0f3e2d8e9b60c42d Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 20 Mar 2023 11:43:31 +0100 Subject: [PATCH 05/10] parallel reduce tests - changed to be associative --- .../FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs index c20ee0aff46..45052d497ac 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs @@ -449,7 +449,7 @@ type ArrayModule2() = let assertSameBehavior reduction arr = Assert.AreEqual(Array.reduce reduction arr, Array.Parallel.reduce reduction arr) - [|5*4*3*2; 4;3;2;1|] |> assertSameBehavior (fun x y -> x/y) + [|5;4;3;2;1|] |> assertSameBehavior (fun x y -> x+y) [|"A"; "B"; "C" ; "D" |] |> assertSameBehavior (fun x y -> if x < y then x else y) CheckThrowsArgumentException (fun () -> Array.Parallel.reduce (fun x y -> x/y) [||] |> ignore) @@ -461,7 +461,7 @@ type ArrayModule2() = let assertSameBehavior projection reduction arr = Assert.AreEqual(arr |> Array.map projection |> Array.reduce reduction, Array.Parallel.reduceBy projection reduction arr) - [|5*4*3*2; 4;3;2;1|] |> assertSameBehavior (fun x -> x * 2)(fun x y -> x/y) + [|5;4;3;2;1|] |> assertSameBehavior (fun x -> x * 2)(fun x y -> x+y) [|"ABCD"; "B"; "C" ; "D" |] |> assertSameBehavior (fun x -> x.Length) (Operators.Checked.(+)) CheckThrowsArgumentException (fun () -> Array.Parallel.reduceBy id (fun x y -> x/y) [||] |> ignore) From 926a0bbac3ed45a84eb5c166dbd5a99722a31d27 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 21 Mar 2023 18:09:14 +0100 Subject: [PATCH 06/10] [] added --- src/FSharp.Core/array.fsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index b259f5d88f7..02ffd03092b 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3215,6 +3215,7 @@ module Array = /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. /// [] + [] val inline reduce: reduction:('T -> 'T -> 'T) -> array:'T[] -> 'T /// Applies a projection function to each element of the array in parallel, reducing elements in each thread with a dedicated 'reduction' function. @@ -3242,6 +3243,7 @@ module Array = /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. /// [] + [] val reduceBy: projection:('T -> 'U) -> reduction:('U -> 'U ->'U) -> array:'T[] -> 'U /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. @@ -3273,6 +3275,7 @@ module Array = /// Throws System.ArgumentException. /// [] + [] val inline max: array:'T[] -> 'T when 'T : comparison /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. @@ -3305,6 +3308,7 @@ module Array = /// Throws System.ArgumentException. /// [] + [] val inline maxBy : projection:('T -> 'U) -> array:'T[] -> 'T when 'U : comparison /// Returns the lowest of all elements of the array, compared via Operators.min. @@ -3336,6 +3340,7 @@ module Array = /// Throws System.ArgumentException. /// [] + [] val inline min: array:'T[] -> 'T when 'T : comparison /// Returns the lowest of all elements of the array, compared via Operators.min on the function result. @@ -3368,6 +3373,7 @@ module Array = /// Throws System.ArgumentException. /// [] + [] val inline minBy : projection:('T -> 'U) -> array:'T[] -> 'T when 'U : comparison /// Returns the sum of the elements in the array. @@ -3387,6 +3393,7 @@ module Array = /// Evaluates to 11. /// [] + [] val inline sum: array: ^T[] -> ^T when ^T : (static member ( + ) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) @@ -3410,6 +3417,7 @@ module Array = /// Evaluates to 7. /// [] + [] val inline sumBy: projection:('T -> ^U) -> array:'T[] -> ^U when ^U : (static member ( + ) : ^U * ^U -> ^U) and ^U : (static member Zero : ^U) @@ -3437,6 +3445,7 @@ module Array = /// Throws ArgumentException /// [] + [] val inline average : array:^T[] -> ^T when ^T : (static member ( + ) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) @@ -3474,6 +3483,7 @@ module Array = /// Throws ArgumentException /// [] + [] val inline averageBy : projection:('T -> ^U) -> array:'T[] -> ^U when ^U : (static member ( + ) : ^U * ^U -> ^U) and ^U : (static member DivideByInt : ^U*int -> ^U) From 1775d3db1a5f8b0571c4e0a104dc906e43b0938a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 12:54:58 +0000 Subject: [PATCH 07/10] Automated command ran: fantomas Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com> --- src/FSharp.Core/array.fsi | 57 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 95cc7d57af8..d5df841eeac 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3255,8 +3255,7 @@ module Array = /// Applies a function to each element of the array in parallel, threading an accumulator argument /// through the computation for each thread involved in the computation. After processing entire input, results from all threads are reduced together. /// Raises ArgumentException if the array is empty. - - /// The order of processing is not guaranteed. For that reason, the 'reduce' function argument should be commutative. + /// The order of processing is not guaranteed. For that reason, the 'reduce' function argument should be commutative. /// (That is, changing the order of execution must not affect the result) /// Also, compared the non-parallel version of Array.reduce, the 'reduce' function may be invoked more times due to the resulting reduction from participating threads. /// @@ -3267,7 +3266,7 @@ module Array = /// Thrown when the input array is empty. /// /// The final result of the reductions. - /// + /// /// /// /// let inputs = [| 1; 3; 4; 2 |] @@ -3276,16 +3275,16 @@ module Array = /// /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. /// + [] [] - val inline reduce: reduction:('T -> 'T -> 'T) -> array:'T[] -> 'T + val inline reduce: reduction: ('T -> 'T -> 'T) -> array: 'T[] -> 'T /// Applies a projection function to each element of the array in parallel, reducing elements in each thread with a dedicated 'reduction' function. /// After processing entire input, results from all threads are reduced together. /// Raises ArgumentException if the array is empty. - - /// The order of processing is not guaranteed. For that reason, the 'reduction' function argument should be commutative. - /// (That is, changing the order of execution must not affect the result) + /// The order of processing is not guaranteed. For that reason, the 'reduction' function argument should be commutative. + /// (That is, changing the order of execution must not affect the result) /// /// The function to project from elements of the input array /// The function to reduce a pair of projected elements to a single element. @@ -3295,19 +3294,20 @@ module Array = /// Thrown when the input array is empty. /// /// The final result of the reductions. - /// + /// /// /// /// let inputs = [| "1"; "3"; "4"; "2" |] /// - /// inputs |> Array.Parallel.reduceBy (fun x -> int x) (+) + /// inputs |> Array.Parallel.reduceBy (fun x -> int x) (+) /// /// Evaluates to 1 + 3 + 4 + 2. However, the system could have decided to compute (1+3) and (4+2) first, and then put them together. /// + [] [] - val reduceBy: projection:('T -> 'U) -> reduction:('U -> 'U ->'U) -> array:'T[] -> 'U - + val reduceBy: projection: ('T -> 'U) -> reduction: ('U -> 'U -> 'U) -> array: 'T[] -> 'U + /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. /// /// Throws ArgumentException for empty arrays. @@ -3338,7 +3338,7 @@ module Array = /// [] [] - val inline max: array:'T[] -> 'T when 'T : comparison + val inline max: array: 'T[] -> 'T when 'T: comparison /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. /// @@ -3371,7 +3371,7 @@ module Array = /// [] [] - val inline maxBy : projection:('T -> 'U) -> array:'T[] -> 'T when 'U : comparison + val inline maxBy: projection: ('T -> 'U) -> array: 'T[] -> 'T when 'U: comparison /// Returns the lowest of all elements of the array, compared via Operators.min. /// @@ -3403,7 +3403,7 @@ module Array = /// [] [] - val inline min: array:'T[] -> 'T when 'T : comparison + val inline min: array: 'T[] -> 'T when 'T: comparison /// Returns the lowest of all elements of the array, compared via Operators.min on the function result. /// @@ -3436,7 +3436,7 @@ module Array = /// [] [] - val inline minBy : projection:('T -> 'U) -> array:'T[] -> 'T when 'U : comparison + val inline minBy: projection: ('T -> 'U) -> array: 'T[] -> 'T when 'U: comparison /// Returns the sum of the elements in the array. /// @@ -3445,7 +3445,7 @@ module Array = /// The resulting sum. /// /// Thrown when the input array is null. - /// + /// /// /// /// let input = [| 1; 5; 3; 2 |] @@ -3456,10 +3456,7 @@ module Array = /// [] [] - val inline sum: array: ^T[] -> ^T - when ^T : (static member ( + ) : ^T * ^T -> ^T) - and ^T : (static member Zero : ^T) - + val inline sum: array: ^T[] -> ^T when ^T: (static member (+): ^T * ^T -> ^T) and ^T: (static member Zero: ^T) /// Returns the sum of the results generated by applying the function to each element of the array. /// @@ -3469,7 +3466,7 @@ module Array = /// The resulting sum. /// /// Thrown when the input array is null. - /// + /// /// /// /// let input = [| "aa"; "bbb"; "cc" |] @@ -3480,9 +3477,9 @@ module Array = /// [] [] - val inline sumBy: projection:('T -> ^U) -> array:'T[] -> ^U - when ^U : (static member ( + ) : ^U * ^U -> ^U) - and ^U : (static member Zero : ^U) + val inline sumBy: + projection: ('T -> ^U) -> array: 'T[] -> ^U + when ^U: (static member (+): ^U * ^U -> ^U) and ^U: (static member Zero: ^U) /// Returns the average of the elements in the array. /// @@ -3508,9 +3505,9 @@ module Array = /// [] [] - val inline average : array:^T[] -> ^T - when ^T : (static member ( + ) : ^T * ^T -> ^T) - and ^T : (static member DivideByInt : ^T*int -> ^T) + val inline average: + array: ^T[] -> ^T + when ^T: (static member (+): ^T * ^T -> ^T) and ^T: (static member DivideByInt: ^T * int -> ^T) /// Returns the average of the elements generated by applying the function to each element of the array. /// @@ -3546,9 +3543,9 @@ module Array = /// [] [] - val inline averageBy : projection:('T -> ^U) -> array:'T[] -> ^U - when ^U : (static member ( + ) : ^U * ^U -> ^U) - and ^U : (static member DivideByInt : ^U*int -> ^U) + val inline averageBy: + projection: ('T -> ^U) -> array: 'T[] -> ^U + when ^U: (static member (+): ^U * ^U -> ^U) and ^U: (static member DivideByInt: ^U * int -> ^U) /// Apply the given function to each element of the array. Return /// the array comprised of the results x for each element where From 019fcf719c990090ebf9ad9083d05d7e67018538 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 13 Apr 2023 19:42:52 +0200 Subject: [PATCH 08/10] PR feedback --- src/FSharp.Core/array.fs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index 97cde421797..31b10b2690d 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -2142,13 +2142,14 @@ module Array = let inline reduce ([] reduction) (array: _[]) = array |> reduceBy id reduction + let inline vFst struct (a, _) = + a + + let inline vSnd struct (_, b) = + b + [] let inline minBy ([] projection) (array: _[]) = - let inline vFst struct (a, _) = - a - - let inline vSnd struct (_, b) = - b array |> reduceBy (fun x -> struct (projection x, x)) (fun a b -> if vFst a < vFst b then a else b) @@ -2171,11 +2172,6 @@ module Array = [] let inline maxBy projection (array: _[]) = - let inline vFst struct (a, _) = - a - - let inline vSnd struct (_, b) = - b array |> reduceBy (fun x -> struct (projection x, x)) (fun a b -> if vFst a > vFst b then a else b) From e8c3bf70a2bd54d3216170cf009e83d3523688ab Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 19 Apr 2023 20:58:46 +0200 Subject: [PATCH 09/10] Code review suggestions applied Co-authored-by: Petr --- src/FSharp.Core/array.fs | 2 +- src/FSharp.Core/array.fsi | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index 31b10b2690d..21fee099a9e 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -2102,7 +2102,7 @@ module Array = createPartitionsUpToWithMinChunkSize maxIdxExclusive minChunkSize array (* This function is there also as a support vehicle for other aggregations. - It is a public in order to be called from inlined functions, the benefit of inlining call into it is significant *) + It is public in order to be called from inlined functions, the benefit of inlining call into it is significant *) [] let reduceBy (projection: 'T -> 'U) (reduction: 'U -> 'U -> 'U) (array: 'T[]) = checkNonNull "array" array diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index d5df841eeac..694354fbf5a 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3257,7 +3257,7 @@ module Array = /// Raises ArgumentException if the array is empty. /// The order of processing is not guaranteed. For that reason, the 'reduce' function argument should be commutative. /// (That is, changing the order of execution must not affect the result) - /// Also, compared the non-parallel version of Array.reduce, the 'reduce' function may be invoked more times due to the resulting reduction from participating threads. + /// Also, compared to the non-parallel version of Array.reduce, the 'reduce' function may be invoked more times due to the resulting reduction from participating threads. /// /// The function to reduce a pair of elements to a single element. /// The input array. @@ -3265,7 +3265,7 @@ module Array = /// Thrown when the input array is null. /// Thrown when the input array is empty. /// - /// The final result of the reductions. + /// Result of the reductions. /// /// /// @@ -3373,7 +3373,7 @@ module Array = [] val inline maxBy: projection: ('T -> 'U) -> array: 'T[] -> 'T when 'U: comparison - /// Returns the lowest of all elements of the array, compared via Operators.min. + /// Returns the smallest of all elements of the array, compared via Operators.min. /// /// Throws ArgumentException for empty arrays /// From 99644168298e81c632280c5c42680d9d56ef7e26 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 19 Apr 2023 21:02:14 +0200 Subject: [PATCH 10/10] Apply suggestions from code review --- src/FSharp.Core/array.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 694354fbf5a..3cd6996b132 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3308,7 +3308,7 @@ module Array = [] val reduceBy: projection: ('T -> 'U) -> reduction: ('U -> 'U -> 'U) -> array: 'T[] -> 'U - /// Returns the greatest of all elements of the array, compared via Operators.max on the function result. + /// Returns the greatest of all elements of the array, compared via Operators.max. /// /// Throws ArgumentException for empty arrays. ///