pub trait Root {
Show 22 methods
// Required method
fn root_rank(&self) -> Rank;
// Provided methods
fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf) { ... }
fn gather_into<S: Buffer + ?Sized>(&self, sendbuf: &S) { ... }
fn gather_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
where S: Buffer + ?Sized,
R: BufferMut + ?Sized { ... }
fn scatter_into<R: BufferMut + ?Sized>(&self, recvbuf: &mut R) { ... }
fn scatter_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
where S: Buffer + ?Sized,
R: BufferMut + ?Sized { ... }
fn reduce_into<S, O>(&self, sendbuf: &S, op: O)
where S: Buffer + ?Sized,
O: Operation { ... }
fn reduce_into_root<S, R, O>(&self, sendbuf: &S, recvbuf: &mut R, op: O)
where S: Buffer + ?Sized,
R: BufferMut + ?Sized,
O: Operation { ... }
fn reduce_into_root_in_place<R, O>(&self, buf: &mut R, op: O)
where R: BufferMut + ?Sized,
O: Operation { ... }
fn gather_into_root_in_place<R>(&self, buf: &mut R)
where R: BufferMut + ?Sized { ... }
fn gather_varcount_into<S: Buffer + ?Sized>(&self, sendbuf: &S) { ... }
fn gather_varcount_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
where S: Buffer + ?Sized,
R: PartitionedBufferMut + ?Sized { ... }
fn scatter_varcount_into<R: BufferMut + ?Sized>(&self, recvbuf: &mut R) { ... }
fn scatter_varcount_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
where S: PartitionedBuffer + ?Sized,
R: BufferMut + ?Sized { ... }
fn immediate_broadcast_into<'a, Buf, Sc>(
&self,
scope: Sc,
buffer: &'a mut Buf,
) -> Request<'a, Buf, Sc>
where Buf: 'a + BufferMut + ?Sized,
Sc: Scope<'a> { ... }
fn immediate_gather_into<'a, S, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
) -> Request<'a, S, Sc>
where S: 'a + Buffer + ?Sized,
Sc: Scope<'a> { ... }
fn immediate_gather_into_root<'a, S, R, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
recvbuf: &'a mut R,
) -> Request<'a, R, Sc>
where S: 'a + Buffer + ?Sized,
R: 'a + BufferMut + ?Sized,
Sc: Scope<'a> { ... }
fn immediate_scatter_into<'a, R, Sc>(
&self,
scope: Sc,
recvbuf: &'a mut R,
) -> Request<'a, R, Sc>
where R: 'a + BufferMut + ?Sized,
Sc: Scope<'a> { ... }
fn immediate_scatter_into_root<'a, S, R, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
recvbuf: &'a mut R,
) -> Request<'a, R, Sc>
where S: 'a + Buffer + ?Sized,
R: 'a + BufferMut + ?Sized,
Sc: Scope<'a> { ... }
fn immediate_reduce_into<'a, S, O, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
op: O,
) -> Request<'a, S, Sc>
where S: 'a + Buffer + ?Sized,
O: Operation,
Sc: Scope<'a> { ... }
fn immediate_reduce_into_root<'a, S, R, O, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
recvbuf: &'a mut R,
op: O,
) -> Request<'a, R, Sc>
where S: 'a + Buffer + ?Sized,
R: 'a + BufferMut + ?Sized,
O: Operation,
Sc: Scope<'a> { ... }
fn spawn(
&self,
program: &str,
args: &[String],
maxprocs: Rank,
) -> Result<InterCommunicator, MpiError> { ... }
}Expand description
Rooted collective operations, called on the Process that is the root
(and, by non-root ranks, on the same root process handle). Mirrors rsmpi’s
Root.
Required Methods§
Provided Methods§
Sourcefn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf)
fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf)
Broadcast the root’s buffer to every rank (MPI_Bcast).
Examples found in repository?
12fn main() {
13 let universe = mpi::initialize().unwrap();
14 let world = universe.world();
15 let rank = world.rank();
16 let size = world.size();
17
18 println!(
19 "rank {rank}/{size}: os={} arch={}",
20 std::env::consts::OS,
21 std::env::consts::ARCH
22 );
23
24 // Ring send/receive across nodes.
25 let next = (rank + 1) % size;
26 let prev = (rank - 1 + size) % size;
27 let msg = rank * 1000;
28 let (got, status): (i32, _) = mpi::point_to_point::send_receive(
29 &msg,
30 &world.process_at_rank(next),
31 &world.process_at_rank(prev),
32 );
33 assert_eq!(got, prev * 1000, "ring mismatch");
34 assert_eq!(status.source_rank(), prev);
35
36 // All-reduce sum of ranks.
37 let mut sum = 0i32;
38 world.all_reduce_into(&rank, &mut sum, SystemOperation::sum());
39 assert_eq!(sum, (0..size).sum::<i32>(), "allreduce mismatch");
40
41 // Broadcast from rank 0.
42 let mut buf = if rank == 0 {
43 vec![42i32; 3]
44 } else {
45 vec![0; 3]
46 };
47 world.process_at_rank(0).broadcast_into(&mut buf[..]);
48 assert_eq!(buf, vec![42, 42, 42], "broadcast mismatch");
49
50 world.barrier();
51 println!("rank {rank}: cross-node comm OK (sum of ranks = {sum})");
52 if rank == 0 {
53 println!("CLUSTER PASS: {size} ranks communicated across hosts.");
54 }
55}More examples
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcefn gather_into<S: Buffer + ?Sized>(&self, sendbuf: &S)
fn gather_into<S: Buffer + ?Sized>(&self, sendbuf: &S)
(non-root) Contribute to a gather (MPI_Gather).
Examples found in repository?
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcefn gather_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
fn gather_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
(root) Collect contributions from all ranks (MPI_Gather).
Examples found in repository?
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcefn scatter_into<R: BufferMut + ?Sized>(&self, recvbuf: &mut R)
fn scatter_into<R: BufferMut + ?Sized>(&self, recvbuf: &mut R)
(non-root) Receive this rank’s slice of a scatter (MPI_Scatter).
Examples found in repository?
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcefn scatter_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
fn scatter_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
(root) Distribute slices of the send buffer to all ranks
(MPI_Scatter).
Examples found in repository?
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcefn reduce_into<S, O>(&self, sendbuf: &S, op: O)
fn reduce_into<S, O>(&self, sendbuf: &S, op: O)
(non-root) Contribute to a reduction whose result lands on the root
(MPI_Reduce).
Examples found in repository?
6fn main() {
7 let universe = mpi::initialize().unwrap();
8 let world = universe.world();
9 let rank = world.rank();
10 let size = world.size();
11 let root_rank = 0;
12 let root = world.process_at_rank(root_rank);
13
14 // Sum of all ranks lands on the root.
15 if rank == root_rank {
16 let mut sum = 0i32;
17 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
18 let expected = (0..size).sum::<i32>();
19 println!("Sum of ranks = {sum} (expected {expected})");
20 assert_eq!(sum, expected);
21 } else {
22 root.reduce_into(&rank, SystemOperation::sum());
23 }
24
25 // Every rank learns the maximum rank via all-reduce.
26 let mut max = 0i32;
27 world.all_reduce_into(&rank, &mut max, SystemOperation::max());
28 assert_eq!(max, size - 1);
29
30 // Element-wise all-reduce over a vector.
31 let local = [rank as f64, (rank * rank) as f64];
32 let mut total = vec![0.0f64; 2];
33 world.all_reduce_into(&local[..], &mut total[..], SystemOperation::sum());
34 let expected0: f64 = (0..size).map(|r| r as f64).sum();
35 let expected1: f64 = (0..size).map(|r| (r * r) as f64).sum();
36 assert!((total[0] - expected0).abs() < 1e-9);
37 assert!((total[1] - expected1).abs() < 1e-9);
38
39 world.barrier();
40 if rank == root_rank {
41 println!("Reductions verified. vector all-reduce = {total:?}");
42 }
43}More examples
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcefn reduce_into_root<S, R, O>(&self, sendbuf: &S, recvbuf: &mut R, op: O)
fn reduce_into_root<S, R, O>(&self, sendbuf: &S, recvbuf: &mut R, op: O)
(root) Reduce contributions from all ranks into recvbuf
(MPI_Reduce).
Examples found in repository?
6fn main() {
7 let universe = mpi::initialize().unwrap();
8 let world = universe.world();
9 let rank = world.rank();
10 let size = world.size();
11 let root_rank = 0;
12 let root = world.process_at_rank(root_rank);
13
14 // Sum of all ranks lands on the root.
15 if rank == root_rank {
16 let mut sum = 0i32;
17 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
18 let expected = (0..size).sum::<i32>();
19 println!("Sum of ranks = {sum} (expected {expected})");
20 assert_eq!(sum, expected);
21 } else {
22 root.reduce_into(&rank, SystemOperation::sum());
23 }
24
25 // Every rank learns the maximum rank via all-reduce.
26 let mut max = 0i32;
27 world.all_reduce_into(&rank, &mut max, SystemOperation::max());
28 assert_eq!(max, size - 1);
29
30 // Element-wise all-reduce over a vector.
31 let local = [rank as f64, (rank * rank) as f64];
32 let mut total = vec![0.0f64; 2];
33 world.all_reduce_into(&local[..], &mut total[..], SystemOperation::sum());
34 let expected0: f64 = (0..size).map(|r| r as f64).sum();
35 let expected1: f64 = (0..size).map(|r| (r * r) as f64).sum();
36 assert!((total[0] - expected0).abs() < 1e-9);
37 assert!((total[1] - expected1).abs() < 1e-9);
38
39 world.barrier();
40 if rank == root_rank {
41 println!("Reductions verified. vector all-reduce = {total:?}");
42 }
43}More examples
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcefn reduce_into_root_in_place<R, O>(&self, buf: &mut R, op: O)
fn reduce_into_root_in_place<R, O>(&self, buf: &mut R, op: O)
(root) In-place reduce: the root’s buf supplies its contribution and
receives the result (MPI_Reduce with MPI_IN_PLACE). Non-root ranks
call Root::reduce_into as usual.
Sourcefn gather_into_root_in_place<R>(&self, buf: &mut R)
fn gather_into_root_in_place<R>(&self, buf: &mut R)
(root) In-place gather: the root’s buf holds its own block at slot
root on entry and every rank’s block on return (MPI_Gather with
MPI_IN_PLACE). Non-root ranks call Root::gather_into.
Sourcefn gather_varcount_into<S: Buffer + ?Sized>(&self, sendbuf: &S)
fn gather_varcount_into<S: Buffer + ?Sized>(&self, sendbuf: &S)
(non-root) Contribute to a varying-count gather (MPI_Gatherv).
Sourcefn gather_varcount_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
fn gather_varcount_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
(root) Collect varying-count contributions (MPI_Gatherv).
Sourcefn scatter_varcount_into<R: BufferMut + ?Sized>(&self, recvbuf: &mut R)
fn scatter_varcount_into<R: BufferMut + ?Sized>(&self, recvbuf: &mut R)
(non-root) Receive this rank’s slice of a varying-count scatter
(MPI_Scatterv).
Sourcefn scatter_varcount_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
fn scatter_varcount_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
(root) Distribute varying-count slices to all ranks (MPI_Scatterv).
Sourcefn immediate_broadcast_into<'a, Buf, Sc>(
&self,
scope: Sc,
buffer: &'a mut Buf,
) -> Request<'a, Buf, Sc>
fn immediate_broadcast_into<'a, Buf, Sc>( &self, scope: Sc, buffer: &'a mut Buf, ) -> Request<'a, Buf, Sc>
Non-blocking broadcast (MPI_Ibcast).
Examples found in repository?
11fn main() {
12 let universe = mpi::initialize().unwrap();
13 let world = universe.world();
14 let rank = world.rank();
15 let size = world.size();
16
17 // ---- point-to-point: typed scalar ----
18 if size >= 2 {
19 if rank == 0 {
20 world.process_at_rank(1).send(&42u64);
21 } else if rank == 1 {
22 let (v, status) = world.process_at_rank(0).receive::<u64>();
23 assert_eq!(v, 42);
24 assert_eq!(status.source_rank(), 0);
25 }
26 }
27
28 // ---- point-to-point: vector + probe ----
29 if size >= 2 {
30 if rank == 0 {
31 let data: Vec<i32> = vec![10, 20, 30, 40, 50];
32 world.process_at_rank(1).send(&data[..]);
33 } else if rank == 1 {
34 let status = world.process_at_rank(0).probe();
35 let count = status.count(i32::equivalent_datatype());
36 assert_eq!(count, 5, "probe reported wrong count");
37 let (data, _s) = world.process_at_rank(0).receive_vec::<i32>();
38 assert_eq!(data, vec![10, 20, 30, 40, 50]);
39 }
40 }
41
42 // ---- send_receive ring ----
43 {
44 let next = (rank + 1) % size;
45 let prev = (rank - 1 + size) % size;
46 let (got, _status): (i32, _) = mpi::point_to_point::send_receive(
47 &rank,
48 &world.process_at_rank(next),
49 &world.process_at_rank(prev),
50 );
51 assert_eq!(got, prev, "send_receive ring mismatch");
52 }
53
54 // ---- broadcast ----
55 {
56 let root = world.process_at_rank(0);
57 let mut buf = if rank == 0 {
58 vec![2, 4, 8, 16]
59 } else {
60 vec![0; 4]
61 };
62 root.broadcast_into(&mut buf[..]);
63 assert_eq!(buf, vec![2, 4, 8, 16], "broadcast mismatch");
64 }
65
66 // ---- scatter ----
67 {
68 let root = world.process_at_rank(0);
69 let mut mine = 0i32;
70 if rank == 0 {
71 let send: Vec<i32> = (0..size).collect();
72 root.scatter_into_root(&send[..], &mut mine);
73 } else {
74 root.scatter_into(&mut mine);
75 }
76 assert_eq!(mine, rank, "scatter mismatch");
77 }
78
79 // ---- gather ----
80 {
81 let root = world.process_at_rank(0);
82 if rank == 0 {
83 let mut buf = vec![-1i32; size as usize];
84 root.gather_into_root(&rank, &mut buf[..]);
85 let expected: Vec<i32> = (0..size).collect();
86 assert_eq!(buf, expected, "gather mismatch");
87 } else {
88 root.gather_into(&rank);
89 }
90 }
91
92 // ---- all_gather ----
93 {
94 let mut buf = vec![-1i32; size as usize];
95 world.all_gather_into(&rank, &mut buf[..]);
96 let expected: Vec<i32> = (0..size).collect();
97 assert_eq!(buf, expected, "all_gather mismatch");
98 }
99
100 // ---- all_to_all ----
101 {
102 let send: Vec<i32> = (0..size).map(|j| rank * 100 + j).collect();
103 let mut recv = vec![-1i32; size as usize];
104 world.all_to_all_into(&send[..], &mut recv[..]);
105 for i in 0..size {
106 assert_eq!(recv[i as usize], i * 100 + rank, "all_to_all mismatch");
107 }
108 }
109
110 // ---- reduce to root (sum) ----
111 {
112 let root = world.process_at_rank(0);
113 if rank == 0 {
114 let mut sum = 0i32;
115 root.reduce_into_root(&rank, &mut sum, SystemOperation::sum());
116 assert_eq!(sum, (0..size).sum::<i32>(), "reduce sum mismatch");
117 } else {
118 root.reduce_into(&rank, SystemOperation::sum());
119 }
120 }
121
122 // ---- all_reduce (max) ----
123 {
124 let mut m = 0i32;
125 world.all_reduce_into(&rank, &mut m, SystemOperation::max());
126 assert_eq!(m, size - 1, "all_reduce max mismatch");
127 }
128
129 // ---- inclusive scan ----
130 {
131 let mut acc = 0i32;
132 world.scan_into(&rank, &mut acc, SystemOperation::sum());
133 let expected: i32 = (0..=rank).sum();
134 assert_eq!(acc, expected, "scan mismatch");
135 }
136
137 // ---- exclusive scan ----
138 {
139 let mut acc = -1i32;
140 world.exclusive_scan_into(&rank, &mut acc, SystemOperation::sum());
141 if rank > 0 {
142 let expected: i32 = (0..rank).sum();
143 assert_eq!(acc, expected, "exclusive_scan mismatch");
144 }
145 }
146
147 // ---- reduce_scatter_block ----
148 {
149 let send: Vec<i32> = vec![rank + 1; size as usize];
150 let mut recv = [0i32; 1];
151 world.reduce_scatter_block_into(&send[..], &mut recv[..], SystemOperation::sum());
152 let expected: i32 = (0..size).map(|k| k + 1).sum();
153 assert_eq!(recv[0], expected, "reduce_scatter_block mismatch");
154 }
155
156 // ---- user-defined operation (sum) matches built-in ----
157 {
158 let op = UserOperation::commutative(|inv: &[i32], inout: &mut [i32]| {
159 for (i, o) in inv.iter().zip(inout.iter_mut()) {
160 *o += *i;
161 }
162 });
163 let mut u = 0i32;
164 world.all_reduce_into(&rank, &mut u, op);
165 assert_eq!(u, (0..size).sum::<i32>(), "user op mismatch");
166 }
167
168 // ---- communicator split by parity ----
169 {
170 let color = mpi::topology::Color::with_value(rank % 2);
171 let sub = world.split_by_color(color).expect("split produced None");
172 let expected_size = (0..size).filter(|r| r % 2 == rank % 2).count() as i32;
173 assert_eq!(sub.size(), expected_size, "split size mismatch");
174 // Ranks in the sub-communicator sum to a known value.
175 let mut s = 0i32;
176 sub.all_reduce_into(&sub.rank(), &mut s, SystemOperation::sum());
177 let expected_sum: i32 = (0..sub.size()).sum();
178 assert_eq!(s, expected_sum, "split all_reduce mismatch");
179 }
180
181 // ---- communicator duplicate ----
182 {
183 let dup = world.duplicate();
184 assert_eq!(dup.size(), size);
185 assert_eq!(dup.rank(), rank);
186 dup.barrier();
187 }
188
189 // ---- group ----
190 {
191 let g = world.group();
192 assert_eq!(g.size(), size, "group size mismatch");
193 assert_eq!(g.rank(), Some(rank), "group rank mismatch");
194 }
195
196 // ---- group set algebra ----
197 {
198 let g = world.group();
199 let evens: Vec<i32> = (0..size).filter(|r| r % 2 == 0).collect();
200 let odds: Vec<i32> = (0..size).filter(|r| r % 2 == 1).collect();
201 let ge = g.include(&evens);
202 let go = g.include(&odds);
203 assert_eq!(ge.size() + go.size(), size, "group split size mismatch");
204 assert_eq!(ge.union(&go).size(), size, "group union mismatch");
205 assert_eq!(
206 ge.intersection(&go).size(),
207 0,
208 "group intersection mismatch"
209 );
210 }
211
212 // ---- varying-count all-gather (allgatherv) ----
213 {
214 let counts: Vec<i32> = (0..size).map(|i| i + 1).collect();
215 let mut displs = vec![0i32; size as usize];
216 for i in 1..size as usize {
217 displs[i] = displs[i - 1] + counts[i - 1];
218 }
219 let total: i32 = counts.iter().sum();
220 let send = vec![rank; (rank + 1) as usize];
221 let mut recvbuf = vec![-1i32; total as usize];
222 {
223 let mut part = PartitionMut::new(&mut recvbuf[..], counts.clone(), displs.clone());
224 world.all_gather_varcount_into(&send[..], &mut part);
225 }
226 for i in 0..size as usize {
227 let start = displs[i] as usize;
228 for k in 0..counts[i] as usize {
229 assert_eq!(recvbuf[start + k], i as i32, "allgatherv mismatch");
230 }
231 }
232 }
233
234 // ---- varying-count all-to-all (alltoallv) ----
235 {
236 let counts: Vec<i32> = vec![1; size as usize];
237 let displs: Vec<i32> = (0..size).collect();
238 let send: Vec<i32> = (0..size).map(|j| rank * 10 + j).collect();
239 let mut recv = vec![-1i32; size as usize];
240 {
241 let sp = Partition::new(&send[..], counts.clone(), displs.clone());
242 let mut rp = PartitionMut::new(&mut recv[..], counts.clone(), displs.clone());
243 world.all_to_all_varcount_into(&sp, &mut rp);
244 }
245 for i in 0..size {
246 assert_eq!(recv[i as usize], i * 10 + rank, "alltoallv mismatch");
247 }
248 }
249
250 // ---- Cartesian topology (1-D periodic ring) ----
251 {
252 let cart = world
253 .create_cartesian_communicator(&[size], &[true], false)
254 .expect("cartesian create returned None");
255 assert_eq!(cart.my_coordinates(), vec![rank], "cart coords mismatch");
256 let (src, dst) = cart.shift(0, 1);
257 assert_eq!(dst, Some((rank + 1) % size), "cart shift dest mismatch");
258 assert_eq!(
259 src,
260 Some((rank - 1 + size) % size),
261 "cart shift source mismatch"
262 );
263 assert_eq!(cart.rank_from_coordinates(&[0]), Some(0));
264 cart.barrier();
265 }
266
267 // ---- error handlers ----
268 {
269 use mpi::error::{class, error_string, ErrorHandler};
270 world.set_error_handler(ErrorHandler::Return);
271 assert_eq!(
272 world.error_handler(),
273 ErrorHandler::Return,
274 "errhandler mismatch"
275 );
276 world.set_error_handler(ErrorHandler::Fatal);
277 assert_eq!(world.error_handler(), ErrorHandler::Fatal);
278 assert!(!error_string(class::TRUNCATE).is_empty());
279 }
280
281 // ---- generalized request (completed from another thread) ----
282 {
283 use mpi::request::GeneralizedRequest;
284 let (req, completer) = GeneralizedRequest::start();
285 let handle = std::thread::spawn(move || completer.complete());
286 let _status = req.wait();
287 handle.join().unwrap();
288 }
289
290 // ---- pack / unpack ----
291 {
292 let val = vec![rank, rank * 2, rank * 3];
293 let packed = world.pack(&val[..]);
294 let mut out = vec![0i32; 3];
295 let pos = unsafe { world.unpack_into(&packed, &mut out[..], 0) };
296 assert_eq!(out, val, "pack/unpack mismatch");
297 assert_eq!(pos as usize, packed.len(), "unpack position mismatch");
298 }
299
300 // ---- communicator naming ----
301 {
302 assert_eq!(world.get_name(), "MPI_COMM_WORLD", "comm name mismatch");
303 let d = world.duplicate();
304 d.set_name("dup");
305 assert_eq!(d.get_name(), "dup", "set/get name mismatch");
306 }
307
308 // ---- non-blocking all-reduce + barrier ----
309 {
310 let send = rank;
311 let mut recv = 0i32;
312 mpi::request::scope(|s| {
313 world
314 .immediate_all_reduce_into(s, &send, &mut recv, SystemOperation::sum())
315 .wait();
316 });
317 assert_eq!(
318 recv,
319 (0..size).sum::<i32>(),
320 "immediate all_reduce mismatch"
321 );
322 world.immediate_barrier().wait();
323 }
324
325 // ---- non-blocking broadcast (Root) ----
326 {
327 let root = world.process_at_rank(0);
328 let mut buf = if rank == 0 {
329 vec![7, 7, 7]
330 } else {
331 vec![0, 0, 0]
332 };
333 mpi::request::scope(|s| {
334 root.immediate_broadcast_into(s, &mut buf[..]).wait();
335 });
336 assert_eq!(buf, vec![7, 7, 7], "immediate broadcast mismatch");
337 }
338
339 // ---- in-place all-reduce (MPI_IN_PLACE) ----
340 {
341 let mut b = vec![rank, rank + 1];
342 world.all_reduce_into_in_place(&mut b[..], SystemOperation::sum());
343 let s: i32 = (0..size).sum();
344 assert_eq!(b, vec![s, s + size], "in-place all_reduce mismatch");
345 }
346
347 // ---- persistent send/receive, reused across iterations ----
348 {
349 let next = (rank + 1) % size;
350 let prev = (rank - 1 + size) % size;
351 let sendbuf = [rank, rank * 2];
352 let mut recvbuf = vec![-1i32; 2];
353 {
354 let mut sreq = world.process_at_rank(next).send_init(&sendbuf[..]);
355 let mut rreq = world.process_at_rank(prev).receive_init(&mut recvbuf[..]);
356 for _ in 0..3 {
357 rreq.start();
358 sreq.start();
359 sreq.wait();
360 rreq.wait();
361 }
362 } // requests dropped -> buffer borrows released
363 assert_eq!(recvbuf, vec![prev, prev * 2], "persistent request mismatch");
364 }
365
366 world.barrier();
367 if rank == 0 {
368 println!("SELFTEST PASS: all checks passed on {size} ranks.");
369 }
370}Sourcefn immediate_gather_into<'a, S, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
) -> Request<'a, S, Sc>
fn immediate_gather_into<'a, S, Sc>( &self, scope: Sc, sendbuf: &'a S, ) -> Request<'a, S, Sc>
(non-root) Non-blocking gather (MPI_Igather).
Sourcefn immediate_gather_into_root<'a, S, R, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
recvbuf: &'a mut R,
) -> Request<'a, R, Sc>
fn immediate_gather_into_root<'a, S, R, Sc>( &self, scope: Sc, sendbuf: &'a S, recvbuf: &'a mut R, ) -> Request<'a, R, Sc>
(root) Non-blocking gather (MPI_Igather).
Sourcefn immediate_scatter_into<'a, R, Sc>(
&self,
scope: Sc,
recvbuf: &'a mut R,
) -> Request<'a, R, Sc>
fn immediate_scatter_into<'a, R, Sc>( &self, scope: Sc, recvbuf: &'a mut R, ) -> Request<'a, R, Sc>
(non-root) Non-blocking scatter (MPI_Iscatter).
Sourcefn immediate_scatter_into_root<'a, S, R, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
recvbuf: &'a mut R,
) -> Request<'a, R, Sc>
fn immediate_scatter_into_root<'a, S, R, Sc>( &self, scope: Sc, sendbuf: &'a S, recvbuf: &'a mut R, ) -> Request<'a, R, Sc>
(root) Non-blocking scatter (MPI_Iscatter).
Sourcefn immediate_reduce_into<'a, S, O, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
op: O,
) -> Request<'a, S, Sc>
fn immediate_reduce_into<'a, S, O, Sc>( &self, scope: Sc, sendbuf: &'a S, op: O, ) -> Request<'a, S, Sc>
(non-root) Non-blocking reduce (MPI_Ireduce).
Sourcefn immediate_reduce_into_root<'a, S, R, O, Sc>(
&self,
scope: Sc,
sendbuf: &'a S,
recvbuf: &'a mut R,
op: O,
) -> Request<'a, R, Sc>
fn immediate_reduce_into_root<'a, S, R, O, Sc>( &self, scope: Sc, sendbuf: &'a S, recvbuf: &'a mut R, op: O, ) -> Request<'a, R, Sc>
(root) Non-blocking reduce (MPI_Ireduce).
Sourcefn spawn(
&self,
program: &str,
args: &[String],
maxprocs: Rank,
) -> Result<InterCommunicator, MpiError>
fn spawn( &self, program: &str, args: &[String], maxprocs: Rank, ) -> Result<InterCommunicator, MpiError>
Spawn maxprocs copies of program (with args) as a new MPI world and
return an inter-communicator to them (MPI_Comm_spawn). Collective over
the root’s communicator; the spawned children obtain the matching parent
inter-communicator via crate::topology::Communicator::parent.
Examples found in repository?
14fn main() {
15 let universe = mpi::initialize().unwrap();
16 let world = universe.world();
17
18 if let Some(parent) = world.parent() {
19 // ---- child side ----
20 let rank = world.rank();
21 // Receive a value from parent rank 0, send it back incremented.
22 let (val, status) = parent.process_at_rank(0).receive::<i32>();
23 assert_eq!(status.source_rank(), 0);
24 parent.process_at_rank(0).send(&(val + 1));
25 println!(
26 "child {rank}/{} (parent group size {}) got {val}",
27 world.size(),
28 parent.remote_size()
29 );
30 } else {
31 // ---- parent side ----
32 let exe = std::env::current_exe().unwrap();
33 let inter = world
34 .process_at_rank(0)
35 .spawn(exe.to_str().unwrap(), &[], N_CHILDREN)
36 .expect("spawn failed");
37
38 assert_eq!(inter.remote_size(), N_CHILDREN, "wrong child count");
39
40 if world.rank() == 0 {
41 for c in 0..inter.remote_size() {
42 inter.process_at_rank(c).send(&(100 + c));
43 let (reply, _) = inter.process_at_rank(c).receive::<i32>();
44 assert_eq!(reply, 100 + c + 1, "child reply mismatch");
45 }
46 println!(
47 "SPAWN PASS: parent (size {}) round-tripped with {} spawned children.",
48 world.size(),
49 inter.remote_size()
50 );
51 }
52 world.barrier();
53 }
54}Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".