ParallelUtilities.jl

ParallelUtilities.BroadcastFunctionType
BroadcastFunction(f)

Construct a binary function that evaluates f.(x, y) given the arguments x and y.

Note

The function BroadcastFunction(f) is equivalent to Base.BroadcastFunction(f) on Julia versions 1.6 and above.

Examples

julia> ParallelUtilities.BroadcastFunction(+)(ones(3), ones(3))
3-element Vector{Float64}:
 2.0
 2.0
 2.0
ParallelUtilities.BroadcastStackType
BroadcastStack(f, dims)(x::AbstractArray, y::AbstractArray)

Construct a binary function that stacks its arguments along dims, with overlapping indices I being replaced by f(x[I], y[I]). The arguments x and y must both be n-dimensional arrays that have identical axes along all dimensions aside from those specified by dims. The axes of the result along each dimensions d in dims would be union(axes(x, d), axes(y, d)). Along the other dimensions the result has the same axes as x and y.

Note

If the resulting axes along the concatenated dimensions are not 1-based, one might require an offset array package such as OffsetArrays.jl.

Examples

julia> A = ones(2)*2
2-element Vector{Float64}:
 2.0
 2.0

julia> B = ones(3)*3
3-element Vector{Float64}:
 3.0
 3.0
 3.0

julia> ParallelUtilities.BroadcastStack(min, 1)(A, B)
3-element Vector{Float64}:
 2.0
 2.0
 3.0

julia> A = ones(2,2)*2
2×2 Matrix{Float64}:
 2.0  2.0
 2.0  2.0

julia> B = ones(2,3)*3
2×3 Matrix{Float64}:
 3.0  3.0  3.0
 3.0  3.0  3.0

julia> ParallelUtilities.BroadcastStack(+, 2)(A, B)
2×3 Matrix{Float64}:
 5.0  5.0  3.0
 5.0  5.0  3.0
ParallelUtilities.CommutativeType
Commutative

Declare a reduction operator to be commutative in its arguments. No check is performed to ascertain if the operator is indeed commutative.

ParallelUtilities.FlipType
Flip(f)

Flip the arguments of a binary function f, so that Flip(f)(x, y) == f(y,x).

Examples

julia> flip1 = ParallelUtilities.Flip(vcat);

julia> flip1(2, 3)
2-element Vector{Int64}:
 3
 2

Two flips pop the original function back:

julia> flip2 = ParallelUtilities.Flip(flip1);

julia> flip2(2, 3)
2-element Vector{Int64}:
 2
 3
ParallelUtilities.ProductSectionType
ProductSection{T, N, Q<:NTuple{N,AbstractRange}}

Iterator that loops over a specified section of the outer product of ranges in. If the ranges are strictly increasing, the iteration will be in reverse - lexicographic order. Given N ranges, each element returned by the iterator will be a tuple of length N with one element from each range.

See also: ProductSplit

ParallelUtilities.ProductSectionMethod
ProductSection(iterators::Tuple{Vararg{AbstractRange}}, inds::AbstractUnitRange)

Construct a ProductSection iterator that represents a 1D view of the outer product of the ranges provided in iterators, with the range of indices in the view being specified by inds.

Examples

julia> p = ParallelUtilities.ProductSection((1:3, 4:6), 5:8);

julia> collect(p)
4-element Vector{Tuple{Int64, Int64}}:
 (2, 5)
 (3, 5)
 (1, 6)
 (2, 6)

julia> collect(p) == collect(Iterators.product(1:3, 4:6))[5:8]
true
ParallelUtilities.ProductSplitType
ProductSplit{T, N, Q<:NTuple{N,AbstractRange}}

Iterator that loops over a section of the outer product of ranges. If the ranges are strictly increasing, the iteration is in reverse - lexicographic order. Given N ranges, each element returned by the iterator will be a tuple of length N with one element from each range.

See also: ProductSection

ParallelUtilities.ProductSplitMethod
ProductSplit(iterators::Tuple{Vararg{AbstractRange}}, np::Integer, p::Integer)

Construct a ProductSplit iterator that represents the outer product of the iterators split over np workers, with this instance reprsenting the values on the p-th worker.

Note

p here refers to the rank of the worker, and is unrelated to the worker ID obtained by executing myid() on that worker.

Examples

julia> ParallelUtilities.ProductSplit((1:2, 4:5), 2, 1) |> collect
2-element Vector{Tuple{Int64, Int64}}:
 (1, 4)
 (2, 4)

julia> ParallelUtilities.ProductSplit((1:2, 4:5), 2, 2) |> collect
2-element Vector{Tuple{Int64, Int64}}:
 (1, 5)
 (2, 5)
ParallelUtilities.broadcastinplaceMethod
broadcastinplace(f, ::Val{N}) where {N}

Construct a binary operator that evaluates f.(x, y) and overwrites the Nth argument with the result. For N == 1 this evaluates x .= f.(x, y), whereas for N == 2 this evaluates y .= f.(x, y).

Examples

julia> op = ParallelUtilities.broadcastinplace(+, Val(1));

julia> x = ones(3); y = ones(3);

julia> op(x, y)
3-element Vector{Float64}:
 2.0
 2.0
 2.0

julia> x # overwritten
3-element Vector{Float64}:
 2.0
 2.0
 2.0
ParallelUtilities.childindexMethod
childindex(ps::AbstractConstrainedProduct, ind)

Return a tuple containing the indices of the individual AbstractRanges corresponding to the element that is present at index ind in the outer product of the ranges.

Note

The index ind corresponds to the outer product of the ranges, and not to ps.

Examples

julia> iters = (1:5, 2:4, 1:3);

julia> ps = ParallelUtilities.ProductSplit(iters, 7, 1);

julia> ind = 6;

julia> cinds = ParallelUtilities.childindex(ps, ind)
(1, 2, 1)

julia> v = collect(Iterators.product(iters...));

julia> getindex.(iters, cinds) == v[ind]
true

See also: childindexshifted

ParallelUtilities.childindexshiftedMethod
childindexshifted(ps::AbstractConstrainedProduct, ind)

Return a tuple containing the indices in the individual iterators given an index of ps.

If the iterators (r1, r2, ...) are used to generate ps, then return (i1, i2, ...) such that ps[ind] == (r1[i1], r2[i2], ...).

Examples

julia> iters = (1:5, 2:4, 1:3);

julia> ps = ParallelUtilities.ProductSplit(iters, 7, 3);

julia> psind = 4;

julia> cinds = ParallelUtilities.childindexshifted(ps, psind)
(3, 1, 2)

julia> getindex.(iters, cinds) == ps[psind]
true

See also: childindex

ParallelUtilities.dropleadingMethod
dropleading(ps::AbstractConstrainedProduct{T, N, NTuple{N,AbstractUnitRange}}) where {T,N}

Return a ProductSection leaving out the first iterator contained in ps. The range of values of the remaining iterators in the resulting ProductSection will be the same as in ps.

Examples

julia> ps = ParallelUtilities.ProductSplit((1:5, 2:4, 1:3), 7, 3);

julia> collect(ps)
7-element Vector{Tuple{Int64, Int64, Int64}}:
 (5, 4, 1)
 (1, 2, 2)
 (2, 2, 2)
 (3, 2, 2)
 (4, 2, 2)
 (5, 2, 2)
 (1, 3, 2)

julia> ParallelUtilities.dropleading(ps) |> collect
3-element Vector{Tuple{Int64, Int64}}:
 (4, 1)
 (2, 2)
 (3, 2)
ParallelUtilities.elementwisemax!Function
elementwisemax!(x, y)

Binary reduction operator that performs an elementwise max and stores the result inplace in x. The value of x is overwritten in the process.

Functionally elementwisemax!(x, y) is equivalent to x .= max.(x, y).

Note

The operator is assumed to be commutative.

ParallelUtilities.elementwisemin!Function
elementwisemin!(x, y)

Binary reduction operator that performs an elementwise min and stores the result inplace in x. The value of x is overwritten in the process.

Functionally elementwisemin!(x, y) is equivalent to x .= min.(x, y).

Note

The operator is assumed to be commutative.

ParallelUtilities.elementwiseproduct!Function
elementwiseproduct!(x, y)

Binary reduction operator that performs an elementwise product and stores the result inplace in x. The value of x is overwritten in the process.

Functionally elementwiseproduct!(x, y) is equivalent to x .= x .* y.

Note

The operator is assumed to be commutative.

ParallelUtilities.elementwisesum!Function
elementwisesum!(x, y)

Binary reduction operator that performs an elementwise product and stores the result inplace in x. The value of x is overwritten in the process.

Functionally elementwisesum!(x, y) is equivalent to x .= x .+ y.

Note

The operator is assumed to be commutative.

ParallelUtilities.extrema_commonlastdimMethod
extrema_commonlastdim(ps::AbstractConstrainedProduct{T, N, <:NTuple{N,AbstractUnitRange}}) where {T,N}

Return the reverse - lexicographic extrema of values taken from ranges contained in ps, where the pairs of ranges are constructed by concatenating the ranges along each dimension with the last one.

For two ranges this simply returns ([first(ps)], [last(ps)]).

Examples

julia> ps = ParallelUtilities.ProductSplit((1:3, 4:7, 2:7), 10, 2);

julia> collect(ps)
8-element Vector{Tuple{Int64, Int64, Int64}}:
 (3, 6, 2)
 (1, 7, 2)
 (2, 7, 2)
 (3, 7, 2)
 (1, 4, 3)
 (2, 4, 3)
 (3, 4, 3)
 (1, 5, 3)

julia> ParallelUtilities.extrema_commonlastdim(ps)
([(1, 2), (6, 2)], [(3, 3), (5, 3)])
ParallelUtilities.extremadimsMethod
extremadims(ps::AbstractConstrainedProduct)

Compute the extrema of the sections of all the ranges contained in ps. Functionally this is equivalent to

map(i -> extrema(ps, dims = i), 1:_niterators(ps))

but it is implemented more efficiently.

Returns a Tuple containing the (min, max) pairs along each dimension, such that the i-th index of the result contains the extrema along the section of the i-th range contained locally.

Examples

julia> ps = ParallelUtilities.ProductSplit((1:2, 4:5), 2, 1);

julia> collect(ps)
2-element Vector{Tuple{Int64, Int64}}:
 (1, 4)
 (2, 4)

julia> ParallelUtilities.extremadims(ps)
((1, 2), (4, 4))
ParallelUtilities.extremaelementMethod
extremaelement(ps::AbstractConstrainedProduct; dims::Integer)

Compute the extrema of the section of the range number dims contained in ps.

Examples

julia> ps = ParallelUtilities.ProductSplit((1:2, 4:5), 2, 1);

julia> collect(ps)
2-element Vector{Tuple{Int64, Int64}}:
 (1, 4)
 (2, 4)

julia> ParallelUtilities.extremaelement(ps, dims = 1)
(1, 2)

julia> ParallelUtilities.extremaelement(ps, dims = 2)
(4, 4)
ParallelUtilities.indexinproductMethod
indexinproduct(iterators::NTuple{N, AbstractRange}, val::NTuple{N, Any}) where {N}

Return the index of val in the outer product of iterators. Return nothing if val is not present.

Examples

julia> iterators = (1:4, 1:3, 3:5);

julia> val = (2, 2, 4);

julia> ind = ParallelUtilities.indexinproduct(iterators, val)
18

julia> collect(Iterators.product(iterators...))[ind] == val
true
ParallelUtilities.localindexMethod
localindex(ps::AbstractConstrainedProduct{T}, val::T) where {T}

Return the index of val in ps. Return nothing if the value is not found.

Examples

julia> ps = ParallelUtilities.ProductSplit((1:3, 4:5:20), 3, 2);

julia> collect(ps)
4-element Vector{Tuple{Int64, Int64}}:
 (2, 9)
 (3, 9)
 (1, 14)
 (2, 14)

julia> ParallelUtilities.localindex(ps, (3, 9))
2
ParallelUtilities.masternodeindexMethod
masternodeindex(tree::SegmentedOrderedBinaryTree, p)

Given the top worker p on one node, compute the serial order of the host that it corresponds to.

ParallelUtilities.maximumelementMethod
maximumelement(ps::AbstractConstrainedProduct; dims::Integer)

Compute the maximum value of the section of the range number dims contained in ps.

Examples

julia> ps = ParallelUtilities.ProductSplit((1:2, 4:5), 2, 1);

julia> collect(ps)
2-element Vector{Tuple{Int64, Int64}}:
 (1, 4)
 (2, 4)

julia> ParallelUtilities.maximumelement(ps, dims = 1)
2

julia> ParallelUtilities.maximumelement(ps, dims = 2)
4
ParallelUtilities.minimumelementMethod
minimumelement(ps::AbstractConstrainedProduct; dims::Integer)

Compute the minimum value of the section of the range number dims contained in ps.

Examples

julia> ps = ParallelUtilities.ProductSplit((1:2, 4:5), 2, 1);

julia> collect(ps)
2-element Vector{Tuple{Int64, Int64}}:
 (1, 4)
 (2, 4)

julia> ParallelUtilities.minimumelement(ps, dims = 1)
1

julia> ParallelUtilities.minimumelement(ps, dims = 2)
4
ParallelUtilities.nelementsMethod
nelements(ps::AbstractConstrainedProduct{T, N, <:NTuple{N,AbstractUnitRange}}; dims::Integer) where {T,N}

Compute the number of unique values in the section of the dims-th range contained in ps.

The function is defined currently only for iterator products of AbstractUnitRanges.

Examples

julia> ps = ParallelUtilities.ProductSplit((1:5, 2:4, 1:3), 7, 3);

julia> collect(ps)
7-element Vector{Tuple{Int64, Int64, Int64}}:
 (5, 4, 1)
 (1, 2, 2)
 (2, 2, 2)
 (3, 2, 2)
 (4, 2, 2)
 (5, 2, 2)
 (1, 3, 2)

julia> ParallelUtilities.nelements(ps, dims = 1)
5

julia> ParallelUtilities.nelements(ps, dims = 2)
3

julia> ParallelUtilities.nelements(ps, dims = 3)
2
ParallelUtilities.pmapbatchMethod
pmapbatch(f, [pool::AbstractWorkerPool], iterators...)

Carry out a pmap with the iterators divided evenly among the available workers.

See also: pmapreduce

ParallelUtilities.pmapreduceMethod
pmapreduce(f, op, [pool::AbstractWorkerPool], iterators...; reducekw...)

Evaluate a parallel mapreduce over the elements from iterators. For multiple iterators, apply f elementwise.

The keyword arguments reducekw are passed on to the reduction.

See also: pmapreduce_productsplit

ParallelUtilities.pmapreduce_productsplitMethod
pmapreduce_productsplit(f, op, [pool::AbstractWorkerPool], iterators...; reducekw...)

Evaluate a parallel mapreduce over the outer product of elements from iterators. The product of iterators is split over the workers available, and each worker is assigned a section of the product. The function f should accept a single argument that is a collection of Tuples.

The keyword arguments reducekw are passed on to the reduction.

See also: pmapreduce

ParallelUtilities.procrange_recastMethod
procrange_recast(ps::AbstractConstrainedProduct, np_new::Integer)

Return the range of processor ranks that would contain the values in ps if the iterators used to construct ps were split across np_new processes.

Examples

julia> iters = (1:10, 4:6, 1:4);

julia> ps = ParallelUtilities.ProductSplit(iters, 5, 2); # split across 5 processes initially

julia> ParallelUtilities.procrange_recast(ps, 10) # If `iters` were spread across 10 processes
3:4
ParallelUtilities.procrange_recastMethod
procrange_recast(iterators::Tuple{Vararg{AbstractRange}}, ps, np_new::Integer)

Return the range of processor ranks that would contain the values in ps if the outer produce of the ranges in iterators is split across np_new workers.

The values contained in ps should be a subsection of the outer product of the ranges in iterators.

Examples

julia> iters = (1:10, 4:6, 1:4);

julia> ps = ParallelUtilities.ProductSplit(iters, 5, 2);

julia> ParallelUtilities.procrange_recast(iters, ps, 10)
3:4
ParallelUtilities.whichprocMethod
whichproc(iterators::Tuple{Vararg{AbstractRange}}, val::Tuple, np::Integer)

Return the processor rank that will contain val if the outer product of the ranges contained in iterators is split evenly across np processors.

Examples

julia> iters = (1:4, 2:3);

julia> np = 2;

julia> ParallelUtilities.ProductSplit(iters, np, 2) |> collect
4-element Vector{Tuple{Int64, Int64}}:
 (1, 3)
 (2, 3)
 (3, 3)
 (4, 3)

julia> ParallelUtilities.whichproc(iters, (2, 3), np)
2
ParallelUtilities.whichproc_localindexMethod
whichproc_localindex(iterators::Tuple{Vararg{AbstractRange}}, val::Tuple, np::Integer)

Return (rank, ind), where rank is the rank of the worker that val will reside on if the outer product of the ranges in iterators is spread over np workers, and ind is the index of val in the local section on that worker.

Examples

julia> iters = (1:4, 2:8);

julia> np = 10;

julia> ParallelUtilities.whichproc_localindex(iters, (2, 4), np)
(4, 1)

julia> ParallelUtilities.ProductSplit(iters, np, 4) |> collect
3-element Vector{Tuple{Int64, Int64}}:
 (2, 4)
 (3, 4)
 (4, 4)