polevoy_sergey_lab_6 #218
11
polevoy_sergey_lab_6/cargo.toml
Normal file
11
polevoy_sergey_lab_6/cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "matrix"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
strip = true
|
||||||
|
opt-level = 3
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
|
[dependencies]
|
BIN
polevoy_sergey_lab_6/image.png
Normal file
BIN
polevoy_sergey_lab_6/image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
13
polevoy_sergey_lab_6/readme.md
Normal file
13
polevoy_sergey_lab_6/readme.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Лабораторная работа №6
|
||||||
|
## Полевой Сергей ПИбд-42
|
||||||
|
### Реализация
|
||||||
|
|
||||||
|
Было решено распределять работу по потокам в виде диапазонов столбцов матрицы, по которым каждый поток по отдельности найдёт определитель минора, далее результаты работ каждого потока передаются по mpsc каналу и суммируется для окончательного результата.
|
||||||
|
|
||||||
|
#### Скриншот результата работы
|
||||||
|
![alt text](image.png)
|
||||||
|
|
||||||
|
#### Выводы
|
||||||
|
Подобно результату прошлой лабораторной работы, очевидного выигрыша программа достигает при должно большом размере матрицы, так как при малых значениях размера больше времени тратится на создание и управление потоками.
|
||||||
|
|
||||||
|
#### Демонстрация работы доступна по [ссылке](https://disk.yandex.ru/i/lv-Szz2Xzpvx7w)
|
125
polevoy_sergey_lab_6/src/main.rs
Normal file
125
polevoy_sergey_lab_6/src/main.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
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>();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user