Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Array.Parallel.forall , Array.Parallel.exists #14910

Merged
merged 8 commits into from
Mar 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/FSharp.Core/array.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1936,6 +1936,26 @@ module Array =
open System.Threading.Tasks
open System.Collections.Concurrent

[<CompiledName("Exists")>]
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

[<CompiledName("ForAll")>]
let forall (predicate: 'T -> bool) (array: 'T[]) =
// Not exists $condition <==> (opposite of $condition is true forall)
exists (predicate >> not) array |> not

[<CompiledName("TryFindIndex")>]
let tryFindIndex predicate (array: _[]) =
checkNonNull "array" array
Expand Down
61 changes: 61 additions & 0 deletions src/FSharp.Core/array.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -3094,6 +3094,67 @@ module Array =
/// <summary>Provides parallel operations on arrays </summary>
module Parallel =


/// <summary>Tests if all elements of the array satisfy the given predicate.</summary>
///
/// <remarks>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.</remarks>
///
/// <param name="predicate">The function to test the input elements.</param>
/// <param name="array">The input array.</param>
///
/// <returns>True if all of the array elements satisfy the predicate.</returns>
///
/// <exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
///
/// <example id="para-forall-1">
/// <code lang="fsharp">
/// let isEven a = a % 2 = 0
///
/// [2; 42] |> Array.Parallel.forall isEven // evaluates to true
///
/// [1; 2] |> Array.Parallel.forall isEven // evaluates to false
/// </code>
/// </example>
[<CompiledName("ForAll")>]
[<Experimental("Experimental library feature, requires '--langversion:preview'")>]
val forall: predicate:('T -> bool) -> array:'T[] -> bool

/// <summary>Tests if any element of the array satisfies the given predicate.</summary>
///
/// <remarks>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, <c>false</c> is returned.</remarks>
///
/// <param name="predicate">The function to test the input elements.</param>
/// <param name="array">The input array.</param>
///
/// <returns>True if any result from <c>predicate</c> is true.</returns>
///
/// <exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
///
/// <example id="para-exists-1">
/// <code lang="fsharp">
/// let input = [| 1; 2; 3; 4; 5 |]
///
/// input |> Array.Parallel.exists (fun elm -> elm % 4 = 0)
/// </code>
/// Evaluates to <c>true</c>
/// </example>
///
/// <example id="para-exists-2">
/// <code lang="fsharp">
/// let input = [| 1; 2; 3; 4; 5 |]
///
/// input |> Array.Parallel.exists (fun elm -> elm % 6 = 0)
/// </code>
/// Evaluates to <c>false</c>
/// </example>
[<CompiledName("Exists")>]
[<Experimental("Experimental library feature, requires '--langversion:preview'")>]
val exists: predicate:('T -> bool) -> array:'T[] -> bool

/// <summary>Returns the first element for which the given function returns <c>True</c>.
/// Returns None if no such element exists.</summary>
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,41 @@ type ArrayModule() =
CheckThrowsArgumentNullException (fun () -> Array.forall (fun x -> true) nullArr |> ignore)

()

[<Fact>]
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)

()

[<Fact>]
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)

()

[<Fact>]
member this.ForAll2() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

[<Fact>]
let ``exists is consistent`` () =
Expand Down Expand Up @@ -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

[<Fact>]
let ``forall is consistent`` () =
Expand Down