I implemented matrix multiplication using functional approach.
struct Matrix {
vals: Vec<i32>,
rows: usize,
cols: usize,
}
fn mul(a: &Matrix, b: &Matrix) -> Matrix {
assert_eq!(a.cols, b.rows);
let vals = a
.vals
.par_chunks(a.cols)
.map(|row| {
(0..b.cols).map(|i| {
row
.iter()
.zip(b.vals.iter().skip(i).step_by(b.cols))
.map(|(a, b)| a * b)
.sum()
})
})
.flatten()
.collect();
Matrix {
vals,
rows: a.rows,
cols: b.cols,
}
}
I tried to parallelize this algorithm by using par_chunks from Rayon 1.8.1 instead of chunks, so each row is constructed in a separate thread. With chunks the algorithm works, but with par_chunks it results in two errors:
error[E0277]: the trait bound `std::iter::Map<std::ops::Range<usize>, {closure@src\main.rs:145:23: 145:26}>: rayon::iter::ParallelIterator` is not satisfied
--> src\main.rs:153:6
|
153 | .flatten()
| ^^^^^^^ the trait `rayon::iter::ParallelIterator` is not implemented for `std::iter::Map<std::ops::Range<usize>, {closure@src\main.rs:145:23: 145:26}>`
and
error[E0599]: the method `collect` exists for struct `Flatten<Map<Chunks<'_, i32>, {[email protected]:144:10}>>`, but its
trait bounds were not satisfied
--> src\main.rs:154:6
|
141 | let vals = a
| ______________-
142 | | .vals
143 | | .par_chunks(a.cols)
144 | | .map(|row| {
... |
153 | | .flatten()
154 | | .collect();
| | -^^^^^^^ method cannot be called due to unsatisfied trait bounds
| |_____|
|
|
::: C:\rust\.rustup\toolchains\stable-x86_64-pc-windows-gnu\lib/rustlib/src/rust\library\core\src\iter\adapters\map.rs:62:1
|
62 | pub struct Map<I, F> {
| -------------------- doesn't satisfy `_: IntoParallelIterator`
|
::: C:\rust\.cargo\registry\src\index.crates.io-6f17d22bba15001f\rayon-1.8.1\src\iter\flatten.rs:11:1
|
11 | pub struct Flatten<I: ParallelIterator> {
| ---------------------------------------
| |
| doesn't satisfy `_: Iterator`
| doesn't satisfy `_: ParallelIterator`
I have no idea what is going on. I suspect that it might be somehow related to sharing second matrix between threads but it is read-only and is guaranteed to stay in the scope until threads have finished their jobs. Error messages don't help at all. What am I doing wrong? How do I even read this error message?
UPD. Rayon's prelude is included.
The error messages are not great here (the content is mostly correct but the location is misleading), but luckily there's only a few things that can go wrong when Rayon's trait bounds are not satisfied.
Here,
flattenexpects to find items that implementParallelIterator. Instead, yourmapproduces items which are a regularIteratortype. You can fix this by inserting aninto_par_iter:Rayon also has the
flatten_itermethod that is similar toflattenbut works on regularIteratortypes. This works well if the outer iterator already has enough items to occupy all your cores.And finally, there's
flat_map_iter, which just combinesmapandflatten_iterinto one function.