Merge pull request 'bondarenko_max_lab_6' () from bondarenko_max_lab_6 into main

Reviewed-on: 
This commit is contained in:
Alexey 2024-12-15 14:39:12 +04:00
commit 9485011484
5 changed files with 139 additions and 0 deletions

View File

@ -0,0 +1,34 @@
# Лабораторная работа 6 - Определение детерминанта матрицы с помощью параллельных вычислений
### ПИбд-42 || Бондаренко Максим
# Описание работы
## Задание
> [!NOTE]
> Кратко: реализовать нахождение детерминанта квадратной матрицы.
>
> Подробно: в лабораторной работе требуется сделать два алгоритма: обычный и параллельный (задание со * - реализовать это в рамках одного алгоритма). В параллельном алгоритме предусмотреть ручное задание количества потоков (число потоков = 1 как раз и реализует задание со *), каждый из которых будет выполнять нахождение отдельной группы множителей.
## Краткое описание модулей и их работа
1. matrix.operations.js
- getMinor(matrix, row, col): Получает минор матрицы для заданной строки и столбца.
- determinant(matrix): Вычисляет детерминант матрицы рекурсивно (последовательный алгоритм).
- determinantParallel(matrix, numThreads): Вычисляет детерминант матрицы параллельно, распределяя задачи по заданному количеству потоков.
2. det.worker.js
- Получает данные о своей части работы (миноры и знаки) и вычисляет частичный детерминант, который затем отправляет обратно главному потоку.
3. benchmark.js
- generateMatrix(size): Генерирует случайную квадратную матрицу заданного размера.
- benchmark(): Выполняет бенчмарки для матриц различных размеров, сравнивая время выполнения последовательного и параллельного алгоритмов с различным количеством потоков.
## Запуск
```
node benchmark.js
```
## Результат работы
> [!IMPORTANT]
> ![benchmark.png](./benchmark.png)
Ссылка на видео: https://cloud.mail.ru/public/9Bky/mjwK7bqBL

View File

@ -0,0 +1,37 @@
const { determinant, determinantParallel } = require('./matrix.operations');
function generateMatrix(size) {
const matrix = new Array(size);
for (let i = 0; i < size; i++) {
matrix[i] = new Array(size);
for (let j = 0; j < size; j++) {
matrix[i][j] = Math.floor(Math.random() * 20) - 10;
}
}
return matrix;
}
async function benchmark() {
const sizes = [5, 7, 10];
const numThreads = [2, 4, 8];
for (const size of sizes) {
const matrix = generateMatrix(size);
console.log(`\nМатрица (${size}x${size}):`);
console.time('Последовательно');
const detSeq = determinant(matrix);
console.timeEnd('Последовательно');
console.log(`Детерминант: ${detSeq}`);
for (const threads of numThreads) {
console.time(`Параллельно (${threads} потоков)`);
const detPar = await determinantParallel(matrix, threads);
console.timeEnd(`Параллельно (${threads} потоков)`);
console.log(`Детерминант: ${detPar}`);
}
}
}
benchmark();

Binary file not shown.

After

(image error) Size: 62 KiB

View File

@ -0,0 +1,8 @@
const { parentPort, workerData } = require('worker_threads');
const { determinant } = require('./matrix.operations');
const partialDet = workerData.reduce((acc, job) => {
return acc + job.value * determinant(job.minor) * job.sign;
}, 0);
parentPort.postMessage(partialDet);

View File

@ -0,0 +1,60 @@
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
function getMinor(matrix, row, col) {
return matrix
.filter((_, i) => i !== row)
.map(row => row.filter((_, j) => j !== col));
}
function determinant(matrix) {
const n = matrix.length;
if (n === 1) return matrix[0][0];
if (n === 2) return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
let det = 0;
for (let j = 0; j < n; j++) {
det += matrix[0][j] * determinant(getMinor(matrix, 0, j)) * (j % 2 === 0 ? 1 : -1);
}
return det;
}
function determinantParallel(matrix, numThreads) {
return new Promise((resolve, reject) => {
const n = matrix.length;
if (n === 1) return resolve(matrix[0][0]);
if (n === 2) return resolve(matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]);
let det = 0;
let completed = 0;
const jobs = [];
for (let j = 0; j < n; j++) {
const sign = j % 2 === 0 ? 1 : -1;
const minor = getMinor(matrix, 0, j);
jobs.push({ minor, sign, value: matrix[0][j] });
}
const chunkSize = Math.ceil(jobs.length / numThreads);
const results = Array(numThreads).fill(0);
for (let i = 0; i < numThreads; i++) {
const chunk = jobs.slice(i * chunkSize, (i + 1) * chunkSize);
const worker = new Worker('./det.worker.js', { workerData: chunk });
worker.on('message', (partialDet) => {
results[i] = partialDet;
completed++;
if (completed === numThreads) {
resolve(results.reduce((acc, val) => acc + val, 0));
}
});
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`));
});
}
});
}
module.exports = { determinant, determinantParallel };