1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! Communicator split example - split world into even/odd rank sub-communicators.
//!
//! Demonstrates `MPI_Comm_split` by partitioning `MPI_COMM_WORLD` into two
//! groups based on rank parity: even ranks (color 0) and odd ranks (color 1).
//! Each sub-communicator then performs an independent allreduce to verify
//! the split is correct.
//!
//! Run with: mpiexec -n 4 cargo run --example comm_split
use ferrompi::{Mpi, ReduceOp, Result};
fn main() -> Result<()> {
let mpi = Mpi::init()?;
let world = mpi.world();
let rank = world.rank();
let size = world.size();
if size < 2 {
if rank == 0 {
eprintln!("This example requires at least 2 processes");
}
return Ok(());
}
// Split world into even (color=0) and odd (color=1) sub-communicators.
// The key parameter controls rank ordering within the new communicator;
// using the world rank preserves the original relative ordering.
let color = rank % 2;
let sub = world
.split(color, rank)?
.expect("split with valid color should return a communicator");
let sub_rank = sub.rank();
let sub_size = sub.size();
let group_name = if color == 0 { "even" } else { "odd" };
println!(
"World rank {}/{}: {} group — sub-communicator rank {}/{}",
rank, size, group_name, sub_rank, sub_size,
);
// Verify the sub-communicator works by performing an allreduce within it.
// Each process contributes its world rank; the sum should equal the sum of
// all world ranks that share the same parity.
let local_sum = world.allreduce_scalar(rank as f64, ReduceOp::Sum)?;
let sub_sum = sub.allreduce_scalar(rank as f64, ReduceOp::Sum)?;
// Compute expected sub-communicator sum based on parity
let expected_sub_sum: f64 = (0..size).filter(|r| r % 2 == color).map(|r| r as f64).sum();
assert!(
(sub_sum - expected_sub_sum).abs() < f64::EPSILON,
"Rank {}: sub-communicator allreduce mismatch: got {}, expected {}",
rank,
sub_sum,
expected_sub_sum,
);
world.barrier()?;
if rank == 0 {
println!(
"\nComm split test passed! World sum={}, even sum={}, odd sum={}",
local_sum,
expected_sub_sum,
(0..size)
.filter(|r| r % 2 == 1)
.map(|r| r as f64)
.sum::<f64>(),
);
}
// sub-communicator is freed on drop; MPI is finalized when `mpi` is dropped
Ok(())
}