diff --git a/mochalov_danila_lab_6/main.py b/mochalov_danila_lab_6/main.py new file mode 100644 index 0000000..998dba5 --- /dev/null +++ b/mochalov_danila_lab_6/main.py @@ -0,0 +1,85 @@ +import random as rnd +import time +from multiprocessing import Pool + +# Функция для генерации квадратной матрицы заданного размера со случайными значениями от 0 до 100 +def generateMatrixWithSize(size): + return [[rnd.randint(0, 100) for i in range(size)] for j in range(size)] + +# Функция для вывода матрицы на экран +def printMatrix(matrix): + for row in matrix: + print(*row, sep="\t") + + +# Функция для вычисления определителя матрицы (стандартный алгоритм, рекурсивный) +def determinantOGWay(matrix): + size = len(matrix) + if size == 1: + return matrix[0][0] + elif size == 2: + return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0] + else: + det = 0 + for c in range(size): + submatrix = [row[:c] + row[c+1:] for row in matrix[1:]] + det += ((-1)**c) * matrix[0][c] * determinantOGWay(submatrix) + return det + +# Функция для вычисления минора матрицы (для параллельного алгоритма) +def calculateMinor(matrix, row, col): + return [r[:col] + r[col+1:] for r in (matrix[:row]+matrix[row+1:])] + +# Функция для вычисления части определителя в отдельном процессе (worker для Pool) +def determinantPart(args): + matrix, col_range_start, col_range_end = args + size = len(matrix) + det_part = 0 + for c in range(col_range_start, col_range_end): + submatrix = calculateMinor(matrix, 0, c) + det_part += ((-1)**c) * matrix[0][c] * determinantOGWay(submatrix) + return det_part + + +# Функция для параллельного вычисления определителя матрицы с использованием процессов +def determinantWithProcesses(matrix, process_count): + size = len(matrix) + + chunk_size = size // process_count + remainder = size % process_count + + args = [] + start_c = 0 + for i in range(process_count): + end_c = start_c + chunk_size + (1 if i < remainder else 0) + args.append((matrix, start_c, end_c)) + start_c = end_c + + with Pool(processes=process_count) as pool: + results = pool.map(determinantPart, args) + + return sum(results) + + +if __name__ == "__main__": + + matrix_sizes = [9,10,11] # С большими размерами рекурсивный метод очень долгий, лучше использовать другие алгоритмы (например в numpy) + num_processes = [1, 2, 4] + + for size in matrix_sizes: + matrix = generateMatrixWithSize(size) + + # Замер времени для стандартного вычисления определителя + start_time = time.time() + det_og = determinantOGWay(matrix) + end_time = time.time() + print(f"Обычный режим. Размер матрицы: {size}x{size}. Время: {end_time - start_time} сек. Определитель: {det_og}") + + # Замер времени для параллельного вычисления определителя с разным количеством процессов + for processes in num_processes: + start_time = time.time() + det_parallel = determinantWithProcesses(matrix, processes) + end_time = time.time() + print(f"Параллельный режим. Размер матрицы: {size}x{size}. Количество процессов: {processes}. Время: {end_time - start_time} сек. Определитель: {det_parallel}") + + print("\n\n") diff --git a/mochalov_danila_lab_6/readme.md b/mochalov_danila_lab_6/readme.md new file mode 100644 index 0000000..b60cab1 --- /dev/null +++ b/mochalov_danila_lab_6/readme.md @@ -0,0 +1,35 @@ +# Лабораторная работа №6 +#### ПИбд-42. Мочалов Данила. + +#### Выполнение +Реализованы два алгоритма вычисления определителя квадратной матрицы: обычный (рекурсивный) и параллельный. Параллельный алгоритм использует multiprocessing.Pool для разделения вычислений миноров между несколькими процессами. + +#### Результаты бенчмарков: + +Тесты проведены для матриц размером 9x9, 10x10 и 11x11 с разным количеством процессов (1, 2, 4). Большие размеры не использовались из-за высокой вычислительной сложности рекурсивного алгоритма. Результаты представлены в таблице: + +| Размер матрицы | Алгоритм | Кол-во процессов | Время (сек.) | +|----------------|------------|------------------|-------------| +| 9x9 | Обычный | - | 0.24 | +| 9x9 | Параллельный | 1 | 0.39 | +| 9x9 | Параллельный | 2 | 0.25 | +| 9x9 | Параллельный | 4 | 0.20 | +| 10x10 | Обычный | - | 2.37 | +| 10x10 | Параллельный | 1 | 2.47 | +| 10x10 | Параллельный | 2 | 1.42 | +| 10x10 | Параллельный | 4 | 0.85 | +| 11x11 | Обычный | - | 26.02 | +| 11x11 | Параллельный | 1 | 25.90 | +| 11x11 | Параллельный | 2 | 14.15 | +| 11x11 | Параллельный | 4 | 7.21 | + + +#### Анализ +- Рекурсивный алгоритм имеет экспоненциальную сложность, что делает его очень медленным для матриц больших размеров. +- Параллельный алгоритм с одним процессом работает примерно с той же скоростью (или чуть медленнее), что и последовательный, из-за накладных расходов на создание и управление процессами. +- С увеличением размера матрицы и количества процессов эффективность параллельного алгоритма возрастает. Наиболее заметное ускорение достигается при использовании 4 процессов для матрицы 11x11. +- Для маленьких матриц параллелизм может быть неэффективен из-за накладных расходов. + + +#### Демонстрация +Доступна по [ссылке](https://drive.google.com/file/d/1XkkIvRzfLpiqzkJjBeTQHF-VMr9KhkeA/view?usp=sharing) diff --git a/mochalov_danila_lab_6/screenshot.png b/mochalov_danila_lab_6/screenshot.png new file mode 100644 index 0000000..bd96d37 Binary files /dev/null and b/mochalov_danila_lab_6/screenshot.png differ