diff --git a/kosheev_maksim_lab_6/READMY.md b/kosheev_maksim_lab_6/READMY.md new file mode 100644 index 0000000..2eebb90 --- /dev/null +++ b/kosheev_maksim_lab_6/READMY.md @@ -0,0 +1,81 @@ +# Лабораторная работа №5 - Параллельное вычисление детерминант матриц + +## Задание +В данной лабораторной работе было необходимо реализовать вычисление детерминанта квадратной матрицы двумя способами: +1. Последовательное вычисление. +2. Параллельное вычисление с возможностью задания количества потоков. + +Основная цель — изучить эффект параллельных вычислений и оценить прирост производительности при увеличении количества потоков. + +## Запуск +Для запуска алгоритма вычисления детерминанта потребуется Python и модуль `multiprocessing`. + +Запуск теста производительности: +``` + python main.py +``` + + +## Результаты + +Ниже представлены результаты бенчмарков для различных размеров матриц и разного количества потоков: + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **100x100** | 1 | 0.0100 s | 0.1957 s | 0.05 | +| | 2 | 0.0100 s | 0.1805 s | 0.06 | +| | 4 | 0.0100 s | 0.2080 s | 0.05 | +| | 6 | 0.0100 s | 0.3015 s | 0.03 | +| | 8 | 0.0100 s | 0.2370 s | 0.04 | +| | 12 | 0.0100 s | 0.2850 s | 0.04 | +| | 16 | 0.0100 s | 0.3188 s | 0.03 | + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **300x300** | 1 | 0.0970 s | 0.2766 s | 0.35 | +| | 2 | 0.0970 s | 0.2570 s | 0.38 | +| | 4 | 0.0970 s | 0.2360 s | 0.41 | +| | 6 | 0.0970 s | 0.2856 s | 0.34 | +| | 8 | 0.0970 s | 0.3120 s | 0.31 | +| | 12 | 0.0970 s | 0.3692 s | 0.26 | +| | 16 | 0.0970 s | 0.5351 s | 0.18 | + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **500x500** | 1 | 0.3000 s | 0.5301 s | 0.57 | +| | 2 | 0.3000 s | 0.3850 s | 0.78 | +| | 4 | 0.3000 s | 0.3512 s | 0.85 | +| | 6 | 0.3000 s | 0.3000 s | 1.00 | +| | 8 | 0.3000 s | 0.3300 s | 0.91 | +| | 12 | 0.3000 s | 0.3979 s | 0.75 | +| | 16 | 0.3000 s | 0.4740 s | 0.63 | + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **1000x1000** | 1 | 1.1871 s | 1.3527 s | 0.88 | +| | 2 | 1.1871 s | 1.1602 s | 1.02 | +| | 4 | 1.1871 s | 0.7971 s | 1.49 | +| | 6 | 1.1871 s | 0.6782 s | 1.75 | +| | 8 | 1.1871 s | 0.6263 s | 1.90 | +| | 12 | 1.1871 s | 0.6636 s | 1.79 | +| | 16 | 1.1871 s | 0.7715 s | 1.54 | + +| Размер матрицы | Потоки | Время (последовательное) | Время (параллельное) | Ускорение | +|----------------|--------|--------------------------|-----------------------|-----------| +| **1200x1200** | 1 | 1.7012 s | 1.8796 s | 0.91 | +| | 2 | 1.7012 s | 1.5037 s | 1.13 | +| | 4 | 1.7012 s | 1.0827 s | 1.57 | +| | 6 | 1.7012 s | 0.8606 s | 1.98 | +| | 8 | 1.7012 s | 0.8093 s | 2.10 | +| | 12 | 1.7012 s | 0.8072 s | 2.11 | +| | 16 | 1.7012 s | 0.9291 s | 1.80 | + +## Выводы +Из результатов видно, что ускорение при использовании параллельного алгоритма зависит от размера матрицы и количества потоков: +- Для небольших матриц (например, 100x100) параллельный алгоритм не даёт значительного ускорения из-за накладных расходов на создание потоков. +- Для больших матриц (например, 1000x1000 и 1200x1200) параллельный алгоритм даёт существенное ускорение, достигая оптимальных значений при использовании 8–12 потоков. +- Увеличение количества потоков сверх количества ядер процессора не улучшает производительность и даже может её снижать из-за накладных расходов на управление потоками. + +Таким образом, для эффективного параллельного вычисления детерминанта матриц важно учитывать размер данных и правильно подбирать количество потоков. + +## [Видео](https://disk.yandex.ru/i/Tov7E9dy7Kt5vA) diff --git a/kosheev_maksim_lab_6/main.py b/kosheev_maksim_lab_6/main.py new file mode 100644 index 0000000..e8d88ed --- /dev/null +++ b/kosheev_maksim_lab_6/main.py @@ -0,0 +1,86 @@ +import numpy as np +import time +from multiprocessing import Pool + +# Функция для вычисления детерминанта с использованием метода Гаусса +def determinant_gauss(matrix): + n = matrix.shape[0] + A = matrix.astype(float) # Создаём копию матрицы, чтобы не изменять исходную + det = 1 # Начальная величина детерминанта + for i in range(n): + # Ищем максимальный элемент в текущем столбце для уменьшения ошибок округления + max_row = np.argmax(np.abs(A[i:n, i])) + i + if A[max_row, i] == 0: + return 0 # Если на диагонали ноль, то детерминант равен нулю + # Переставляем строки + if max_row != i: + A[[i, max_row]] = A[[max_row, i]] + det *= -1 # Каждая перестановка меняет знак детерминанта + # Обнуляем элементы ниже диагонали + for j in range(i + 1, n): + factor = A[j, i] / A[i, i] + A[j, i:] -= factor * A[i, i:] + # Произведение элементов на диагонали + for i in range(n): + det *= A[i, i] + return det + + +# Функция для вычисления детерминанта с многопроцессностью +def parallel_determinant_worker(index_range, matrix): + n = matrix.shape[0] + A = matrix.astype(float) + det = 1 + for i in range(index_range[0], index_range[1]): + # Ищем максимальный элемент в текущем столбце + max_row = np.argmax(np.abs(A[i:n, i])) + i + if A[max_row, i] == 0: + return 0 + if max_row != i: + A[[i, max_row]] = A[[max_row, i]] + det *= -1 + for j in range(i + 1, n): + factor = A[j, i] / A[i, i] + A[j, i:] -= factor * A[i, i:] + return det + + +# Функция для параллельного вычисления детерминанта +def determinant_parallel(matrix, num_processes): + n = matrix.shape[0] + # Делим работу на блоки + block_size = n // num_processes + blocks = [(i * block_size, (i + 1) * block_size) for i in range(num_processes)] + + with Pool(processes=num_processes) as pool: + results = pool.starmap(parallel_determinant_worker, [(block, matrix) for block in blocks]) + + # Объединяем результаты + det = sum(results) + return det + + +# Функция для запуска бенчмарков +def run_benchmarks(): + matrix_sizes = [100, 300, 500,1000,1200] # Размеры матриц + for size in matrix_sizes: + matrix = np.random.rand(size, size) # Генерация случайной матрицы + print(f"--- Benchmark для матрицы {size}x{size} ---") + + # Бенчмарк для последовательного вычисления детерминанта + start_time = time.time() + seq_det = determinant_gauss(matrix) + seq_time = time.time() - start_time + print(f"Последовательное время для {size}x{size}: {seq_time:.4f} секунд") + + # Бенчмарк для параллельного вычисления с разным числом потоков + for num_processes in [1, 2, 4, 6, 8, 12, 16]: + start_time = time.time() + par_det = determinant_parallel(matrix, num_processes) + par_time = time.time() - start_time + speedup = seq_time / par_time if par_time > 0 else 0 + print(f"Параллельное время с {num_processes} потоками: {par_time:.4f} секунд, Ускорение: {speedup:.2f}") + +# Запуск бенчмарков +if __name__ == '__main__': + run_benchmarks() \ No newline at end of file