From d1316d35b7a6132226920e93ffb5e0106bb6d487 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 21 Mar 2023 18:09:41 +0100 Subject: [PATCH] Array.Parallel.forall , Array.Parallel.exists (#14910) * Array.Parallel.forall , Array.Parallel.exists --- src/FSharp.Core/array.fs | 20 ++++++ src/FSharp.Core/array.fsi | 61 +++++++++++++++++++ ...p.Core.SurfaceArea.netstandard20.debug.bsl | 2 + ...Core.SurfaceArea.netstandard20.release.bsl | 3 + ...p.Core.SurfaceArea.netstandard21.debug.bsl | 2 + ...Core.SurfaceArea.netstandard21.release.bsl | 2 + .../ArrayModule.fs | 35 +++++++++++ .../CollectionModulesConsistency.fs | 6 +- 8 files changed, 129 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index a4a80bc9789..e2e49de2f87 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -1936,6 +1936,26 @@ module Array = open System.Threading.Tasks open System.Collections.Concurrent + [] + let exists (predicate: 'T -> bool) (array: 'T[]) = + checkNonNull "array" array + + Parallel + .For( + 0, + array.Length, + (fun i pState -> + if predicate array[i] then + pState.Stop()) + ) + .IsCompleted + |> not + + [] + let forall (predicate: 'T -> bool) (array: 'T[]) = + // Not exists $condition <==> (opposite of $condition is true forall) + exists (predicate >> not) array |> not + [] let tryFindIndex predicate (array: _[]) = checkNonNull "array" array diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index ca8e2013493..caa39887ba1 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3094,6 +3094,67 @@ module Array = /// Provides parallel operations on arrays module Parallel = + + /// Tests if all elements of the array satisfy the given predicate. + /// + /// The predicate is applied to the elements of the input collection in parallel. If any application + /// returns false then the overall result is false and testing of other elements in all threads is stopped at system's earliest convenience. + /// Otherwise, true is returned. + /// + /// The function to test the input elements. + /// The input array. + /// + /// True if all of the array elements satisfy the predicate. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let isEven a = a % 2 = 0 + /// + /// [2; 42] |> Array.Parallel.forall isEven // evaluates to true + /// + /// [1; 2] |> Array.Parallel.forall isEven // evaluates to false + /// + /// + [] + [] + val forall: predicate:('T -> bool) -> array:'T[] -> bool + + /// Tests if any element of the array satisfies the given predicate. + /// + /// The predicate is applied to the elements of the input array in parallel. If any application + /// returns true then the overall result is true and testing of other elements in all threads is stopped at system's earliest convenience. + /// Otherwise, false is returned. + /// + /// The function to test the input elements. + /// The input array. + /// + /// True if any result from predicate is true. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let input = [| 1; 2; 3; 4; 5 |] + /// + /// input |> Array.Parallel.exists (fun elm -> elm % 4 = 0) + /// + /// Evaluates to true + /// + /// + /// + /// + /// let input = [| 1; 2; 3; 4; 5 |] + /// + /// input |> Array.Parallel.exists (fun elm -> elm % 6 = 0) + /// + /// Evaluates to false + /// + [] + [] + val exists: predicate:('T -> bool) -> array:'T[] -> bool + /// Returns the first element for which the given function returns True. /// Returns None if no such element exists. /// 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..d1d0d56baaa 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl @@ -40,6 +40,8 @@ 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: Boolean Exists[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Boolean ForAll[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: 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[]) 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 67632f25510..062ebfc1846 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -40,6 +40,9 @@ 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: Boolean Exists[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Boolean ForAll[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: 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[]) 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..5372b6fad1d 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl @@ -40,6 +40,8 @@ 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: Boolean Exists[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Boolean ForAll[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: 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[]) 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 2c5e5686f5e..f602fd1a98e 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -40,6 +40,8 @@ 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: Boolean Exists[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Boolean ForAll[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: 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[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs index e36ad305c88..8883731bc63 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs @@ -1120,6 +1120,41 @@ type ArrayModule() = CheckThrowsArgumentNullException (fun () -> Array.forall (fun x -> true) nullArr |> ignore) () + + [] + member this.ParallelForAll() = + let inline assertSame predicate array = + let seq = Array.forall predicate array + let para = Array.Parallel.forall predicate array + Assert.AreEqual(seq, para, sprintf "%A" array) + + [| 3..2..10 |] |> assertSame (fun x -> x > 15) + [| 3..2..10 |] |> assertSame (fun x -> x < 15) + [|"Lists"; "are"; "commonly" ; "list" |] |> assertSame (fun (x:string) -> x.Contains("a")) + [||] |> assertSame (fun (x:string) -> x.Contains("a")) + [||] |> assertSame (fun (x:string) -> x.Contains("a") |> not) + + let nullArr = null:string[] + CheckThrowsArgumentNullException (fun () -> Array.Parallel.forall (fun x -> true) nullArr |> ignore) + + () + + [] + member this.ParallelExists() = + let inline assertSame predicate array = + let seq = Array.exists predicate array + let para = Array.Parallel.exists predicate array + Assert.AreEqual(seq, para, sprintf "%A" array) + + [| 3..2..10 |] |> assertSame (fun x -> x > 2) + [|"Lists"; "are"; "commonly" ; "list" |] |> assertSame (fun (x:string) -> x.Contains("a")) + [||] |> assertSame (fun (x:string) -> x.Contains("a")) + [||] |> assertSame (fun (x:string) -> x.Contains("a") |> not) + + let nullArr = null:string[] + CheckThrowsArgumentNullException (fun () -> Array.Parallel.exists (fun x -> true) nullArr |> ignore) + + () [] member this.ForAll2() = 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..bfbf65e98ff 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 @@ -227,7 +227,8 @@ let exists<'a when 'a : equality> (xs : 'a []) f = let s = xs |> Seq.exists f let l = xs |> List.ofArray |> List.exists f let a = xs |> Array.exists f - consistency "exists" s l a + let pa = xs |> Array.Parallel.exists f + consistencyIncludingParallel "exists" s l a pa [] let ``exists is consistent`` () = @@ -373,7 +374,8 @@ let forall<'a when 'a : equality> (xs : 'a []) f = let s = xs |> Seq.forall f let l = xs |> List.ofArray |> List.forall f let a = xs |> Array.forall f - consistency "forall" s l a + let pa = xs |> Array.Parallel.forall f + consistencyIncludingParallel "forall" s l a pa [] let ``forall is consistent`` () =