Skip to main content

Root

Trait Root 

Source
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§

Source

fn root_rank(&self) -> Rank

The rank of the root process.

Provided Methods§

Source

fn broadcast_into<Buf: BufferMut + ?Sized>(&self, buffer: &mut Buf)

Broadcast the root’s buffer to every rank (MPI_Bcast).

Examples found in repository?
examples/cluster.rs (line 47)
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
Hide additional examples
examples/selftest.rs (line 62)
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}
Source

fn gather_into<S: Buffer + ?Sized>(&self, sendbuf: &S)

(non-root) Contribute to a gather (MPI_Gather).

Examples found in repository?
examples/selftest.rs (line 88)
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}
Source

fn gather_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
where S: Buffer + ?Sized, R: BufferMut + ?Sized,

(root) Collect contributions from all ranks (MPI_Gather).

Examples found in repository?
examples/selftest.rs (line 84)
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}
Source

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?
examples/selftest.rs (line 74)
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}
Source

fn scatter_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)
where S: Buffer + ?Sized, R: BufferMut + ?Sized,

(root) Distribute slices of the send buffer to all ranks (MPI_Scatter).

Examples found in repository?
examples/selftest.rs (line 72)
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}
Source

fn reduce_into<S, O>(&self, sendbuf: &S, op: O)
where S: Buffer + ?Sized, O: Operation,

(non-root) Contribute to a reduction whose result lands on the root (MPI_Reduce).

Examples found in repository?
examples/reduce.rs (line 22)
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
Hide additional examples
examples/selftest.rs (line 118)
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}
Source

fn reduce_into_root<S, R, O>(&self, sendbuf: &S, recvbuf: &mut R, op: O)
where S: Buffer + ?Sized, R: BufferMut + ?Sized, O: Operation,

(root) Reduce contributions from all ranks into recvbuf (MPI_Reduce).

Examples found in repository?
examples/reduce.rs (line 17)
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
Hide additional examples
examples/selftest.rs (line 115)
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}
Source

fn reduce_into_root_in_place<R, O>(&self, buf: &mut R, op: O)
where R: BufferMut + ?Sized, O: Operation,

(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.

Source

fn gather_into_root_in_place<R>(&self, buf: &mut R)
where R: BufferMut + ?Sized,

(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.

Source

fn gather_varcount_into<S: Buffer + ?Sized>(&self, sendbuf: &S)

(non-root) Contribute to a varying-count gather (MPI_Gatherv).

Source

fn gather_varcount_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)

(root) Collect varying-count contributions (MPI_Gatherv).

Source

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).

Source

fn scatter_varcount_into_root<S, R>(&self, sendbuf: &S, recvbuf: &mut R)

(root) Distribute varying-count slices to all ranks (MPI_Scatterv).

Source

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>,

Non-blocking broadcast (MPI_Ibcast).

Examples found in repository?
examples/selftest.rs (line 334)
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}
Source

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>,

(non-root) Non-blocking gather (MPI_Igather).

Source

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>,

(root) Non-blocking gather (MPI_Igather).

Source

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>,

(non-root) Non-blocking scatter (MPI_Iscatter).

Source

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>,

(root) Non-blocking scatter (MPI_Iscatter).

Source

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>,

(non-root) Non-blocking reduce (MPI_Ireduce).

Source

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>,

(root) Non-blocking reduce (MPI_Ireduce).

Source

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?
examples/spawn.rs (line 35)
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".

Implementors§

Source§

impl Root for Process<'_>