DAS_2024_1/polevoy_sergey_lab_6/src/main.rs

126 lines
4.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::sync;
use std::thread;
use std::time;
// Квадратная матрица хранится в куче как последовательность всех её элементов, при этом на этапе компиляции всегда известен её размер
struct Matrix<const N: usize> {
inner: Vec<[i16; N]>,
}
impl<const N: usize> Matrix<N> {
fn new() -> Matrix<N> {
Matrix {
inner: vec![[0; N]; N],
}
}
// Псевдослучайная генерация данных для матрицы
fn random(seed: i16) -> Matrix<N> {
let mut matrix = Matrix::new();
for i in 0..N {
for j in 0..N {
matrix.inner[i][j] = i as i16 + j as i16 - seed;
}
}
matrix
}
}
// Рекурсивное получение определителя по первой строке, также включает необязательные аргументы, необходимые для случая с параллельностью
fn recursive(matrix: &[&[i16]], from: Option<usize>, to: Option<usize>) -> i16 {
let size = matrix.len();
match size {
0 => unreachable!(),
1 => matrix[0][0],
2 => matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0],
3.. => (from.unwrap_or(0)..to.unwrap_or(size))
.map(|c| {
((-1i16).pow(c as u32))
* matrix[0][c]
* recursive(
&matrix
.iter()
.skip(1)
.map(|row| {
row.iter()
.zip(0..)
.filter(|(_, i)| *i != c)
.map(|(n, _)| *n)
.collect::<Vec<i16>>()
})
.collect::<Vec<Vec<i16>>>()
.iter()
.map(|r| r.as_slice())
.collect::<Vec<&[i16]>>(),
None,
None,
)
})
.sum(),
}
}
fn parallel<const N: usize, const M: usize>(matrix: &Matrix<N>) -> i16 {
let (result_sender, result_receiver) = sync::mpsc::channel::<i16>();
let matrix: &[&[i16]] = &matrix
.inner
.iter()
.map(|r| r.as_slice())
.collect::<Vec<&[i16]>>();
thread::scope(move |scope| {
let chunk_size = N / M;
let remainder = N % M;
let mut chunks = Vec::new();
let mut start_col = 0;
for i in 0..M {
let end_col = start_col + chunk_size + if i < remainder { 1 } else { 0 };
chunks.push((start_col, end_col));
start_col = end_col;
}
chunks.into_iter().for_each(|(start_col, end_col)| {
let sender = result_sender.clone();
scope.spawn(move || sender.send(recursive(matrix, Some(start_col), Some(end_col))).unwrap());
});
});
result_receiver.into_iter().sum()
}
// Замер времени выполнения, при этом размеры матриц и количество потоков известны на этапе компиляции
fn benchmark<const N: usize, const M: usize>() {
let matrix = Matrix::<N>::random(0);
let start_time = time::Instant::now();
parallel::<N, M>(&matrix);
println!("Определитель для матрицы {0:>4}x{0:<4}: {1} сек ({2} потоков)", N, (time::Instant::now() - start_time).as_secs_f64(), M)
}
fn main() {
benchmark::<8, 1>();
benchmark::<8, 2>();
benchmark::<8, 4>();
benchmark::<8, 8>();
benchmark::<10, 1>();
benchmark::<10, 2>();
benchmark::<10, 4>();
benchmark::<10, 8>();
benchmark::<11, 1>();
benchmark::<11, 2>();
benchmark::<11, 4>();
benchmark::<11, 8>();
benchmark::<12, 1>();
benchmark::<12, 2>();
benchmark::<12, 4>();
benchmark::<12, 8>();
}