Skip to content

Commit dc1a3b9

Browse files
authored
Merge pull request #120 from fverdugo/partition_from_colors
Partition from colors
2 parents 48c4410 + f751eb3 commit dc1a3b9

File tree

5 files changed

+114
-8
lines changed

5 files changed

+114
-8
lines changed

CHANGELOG.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## Unreleased
9+
10+
### Added
11+
12+
- Function `partition_from_color`.
13+
814
## [0.3.3] - 2023-08-09
915

1016
### Added
1117

12-
- Added an MPI ibarrier-based (supposedly scalable) algorithm to find rcv neighbours in a sparse all-to-all communication graph given the snd neighbors. We left the previous non-scalable algorithm as default (based on gather-scatter) until we have experimental evidence on the relative performance and scalability of the former with respect to the latter and for which core ranges.
13-
- Added a new kwarg `discover_cols=true` to the `psparse!` constructor, which allows the user to skip column index discovery.
18+
- MPI ibarrier-based (supposedly scalable) algorithm to find rcv neighbours in a sparse all-to-all communication graph given the snd neighbors. We left the previous non-scalable algorithm as default (based on gather-scatter) until we have experimental evidence on the relative performance and scalability of the former with respect to the latter and for which core ranges.
19+
- New kwarg `discover_cols=true` to the `psparse!` constructor, which allows the user to skip column index discovery.
1420

1521
### Fixed
1622

docs/src/reference/partition.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
```@docs
66
uniform_partition
77
variable_partition
8+
partition_from_color
89
```
910

1011
## AbstractLocalIndices

src/PartitionedArrays.jl

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ include("mpi_array.jl")
6161
export PRange
6262
export uniform_partition
6363
export variable_partition
64+
export partition_from_color
6465
export AbstractLocalIndices
6566
export OwnAndGhostIndices
6667
export LocalIndices

src/p_range.jl

+57-6
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,43 @@ function variable_partition(
696696
indices
697697
end
698698

699+
"""
700+
partition_from_color(ranks,global_to_color;multicast=false,source=MAIN)
701+
702+
Build an arbitrary 1d partition by defining the parts via the argument `global_to_color` (see below).
703+
The output is a vector of vectors containing the indices in each component of
704+
the partition. The `eltype` of the result implements the [`AbstractLocalIndices`](@ref)
705+
interface.
706+
707+
# Arguments
708+
709+
- `ranks`: Array containing the distribution of ranks.
710+
- `global_to_color`: If `multicast==false`, `global_to_color[gid]` contains the part id that owns the global id `gid`. If `multicast==true`, then `global_to_color[source][gid]` contains the part id that owns the global id `gid`.
711+
712+
# Key-word arguments
713+
- `multicast=false`
714+
- `source=MAIN`
715+
716+
This function is useful when generating a partition using a graph partitioner such as METIS.
717+
The argument `global_to_color` is the usual output of such tools.
718+
"""
719+
function partition_from_color(ranks,global_to_color;multicast=false,source=MAIN)
720+
if multicast == true
721+
global_to_owner = getany(emit(global_to_color;source))
722+
else
723+
global_to_owner = global_to_color
724+
end
725+
map(ranks) do rank
726+
nglobal = length(global_to_owner)
727+
own_to_global = findall(owner->owner==rank,global_to_owner)
728+
ghost_to_global = Int[]
729+
ghost_to_owner = Int32[]
730+
own = OwnIndices(nglobal,rank,own_to_global)
731+
ghost = GhostIndices(nglobal,ghost_to_global,ghost_to_owner)
732+
OwnAndGhostIndices(own,ghost,global_to_owner)
733+
end
734+
end
735+
699736
function local_range(p,np,n,ghost=false,periodic=false)
700737
l = n ÷ np
701738
offset = l * (p-1)
@@ -1119,23 +1156,28 @@ Local indices are defined by concatenating own and ghost ones.
11191156
11201157
- `own::OwnIndices`: Container for the own indices.
11211158
- `ghost::GhostIndices`: Container for the ghost indices.
1159+
- `global_to_owner`: [optional: it can be `nothing`] Vector containing the owner of each global id.
11221160
11231161
# Supertype hierarchy
11241162
1125-
OwnAndGhostIndices <: AbstractLocalIndices
1163+
OwnAndGhostIndices{A} <: AbstractLocalIndices
1164+
1165+
where `A=typeof(global_to_owner)`.
11261166
11271167
"""
1128-
struct OwnAndGhostIndices <: AbstractLocalIndices
1168+
struct OwnAndGhostIndices{A} <: AbstractLocalIndices
11291169
own::OwnIndices
11301170
ghost::GhostIndices
1171+
global_to_owner::A
11311172
assembly_cache::AssemblyCache
11321173
@doc """
1133-
OwnAndGhostIndices(own::OwnIndices,ghost::GhostIndices)
1174+
OwnAndGhostIndices(own::OwnIndices,ghost::GhostIndices,global_to_owner=nothing)
11341175
1135-
Build an instance of [`OwnAndGhostIndices`](@ref) from the underlying properties `own` and `ghost`.
1176+
Build an instance of [`OwnAndGhostIndices`](@ref) from the underlying properties `own`, `ghost`, and `global_to_owner`.
11361177
"""
1137-
function OwnAndGhostIndices(own::OwnIndices,ghost::GhostIndices)
1138-
new(own,ghost,AssemblyCache())
1178+
function OwnAndGhostIndices(own::OwnIndices,ghost::GhostIndices,global_to_owner=nothing)
1179+
A = typeof(global_to_owner)
1180+
new{A}(own,ghost,global_to_owner,AssemblyCache())
11391181
end
11401182
end
11411183
assembly_cache(a::OwnAndGhostIndices) = a.assembly_cache
@@ -1146,6 +1188,15 @@ function replace_ghost(a::OwnAndGhostIndices,ghost::GhostIndices)
11461188
OwnAndGhostIndices(a.own,ghost)
11471189
end
11481190

1191+
function find_owner(indices,global_ids,::Type{<:OwnAndGhostIndices{T}}) where T
1192+
if T == Nothing
1193+
error("Not enough data to perform this operation without communciation")
1194+
end
1195+
map(indices,global_ids) do indices,global_ids
1196+
indices.global_to_owner[global_ids]
1197+
end
1198+
end
1199+
11491200
part_id(a::OwnAndGhostIndices) = a.own.owner
11501201

11511202
function own_to_global(a::OwnAndGhostIndices)

test/p_range_tests.jl

+47
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,51 @@ function p_range_tests(distribute)
245245

246246
display(PRange(ids4))
247247

248+
n = 21
249+
np = 4
250+
rank = distribute(LinearIndices((4,)))
251+
global_to_color = zeros(Int,n)
252+
for p in 1:np
253+
global_to_color[local_range(p,np,n)] .= p
254+
end
255+
ids_color = partition_from_color(rank,global_to_color)
256+
ids_uniform = uniform_partition(rank,n)
257+
map(ids_color,ids_uniform) do ids1,ids2
258+
@test ids1 == ids2
259+
end
260+
261+
global_to_color = map(rank) do rank
262+
if rank == MAIN
263+
my_global_to_color = zeros(Int,n)
264+
for p in 1:np
265+
my_global_to_color[local_range(p,np,n)] .= p
266+
end
267+
else
268+
my_global_to_color = Int[]
269+
end
270+
my_global_to_color
271+
end
272+
ids_color = partition_from_color(rank,global_to_color;multicast=true)
273+
ids_color = partition_from_color(rank,global_to_color;multicast=true,source=MAIN)
274+
map(ids_color,ids_uniform) do ids1,ids2
275+
@test ids1 == ids2
276+
end
277+
278+
gids = map(rank) do part
279+
if part == 1
280+
[1,4,6]
281+
elseif part == 2
282+
[3,1,2,8]
283+
elseif part == 3
284+
[1,9,6]
285+
else
286+
[3,2,8,10]
287+
end
288+
end
289+
owners1 = find_owner(ids_color,gids)
290+
owners2 = find_owner(ids_uniform,gids)
291+
map(owners1,owners2) do ids1,ids2
292+
@test ids1 == ids2
293+
end
294+
248295
end

0 commit comments

Comments
 (0)