diff --git a/pupkov_alexey_lab_6/README.md b/pupkov_alexey_lab_6/README.md new file mode 100644 index 0000000..7d8d7fd --- /dev/null +++ b/pupkov_alexey_lab_6/README.md @@ -0,0 +1,67 @@ +# Пупков Алексей ИСЭбд-41 +# Отчет по вычислению детерминанта матрицы +## Описание +В данной лабораторной работе реализовано вычисление детерминанта квадратной матрицы двумя способами: последовательно и параллельно. Для параллельного вычисления используется библиотека concurrent.futures в Python. Программа позволяет задавать количество процессов, что позволяет наблюдать за изменением производительности при увеличении числа потоков. +## Как работает код: + +1. Импорт библиотек +- numpy используется для работы с матрицами и для вычислений +- concurrent.futures помогает запускать параллельные задачи с использованием потоков +- time используется для измерения времени выполнения алгоритмов +- argparse для обработки аргументов командной строки + +2. Функция determinant_sequential(matrix) +- Вычисляет детерминант матрицы, используя метод Гаусса (прямой ход преобразования матрицы в верхнетреугольную форму) + +3. Функция calculate_minor(matrix, i, j) +- Возвращает минор элемента матрицы, находящегося в позиции (i, j) + +4. Функция determinant_parallel(matrix, num_threads) +- Рассчитывает детерминант параллельно, распределяя вычисление миноров между потоками + +5. Функция benchmark(matrix_sizes, num_threads_list) +- Тестирует и сравнивает скорость последовательного и параллельного алгоритмов для матриц разных размеров + +## Результаты + +Размер матрицы: 100x100 +Последовательный алгоритм занял: 0.0150 секунд + +Параллельный алгоритм с 1 потоками занял: 0.0170 секунд + +Параллельный алгоритм с 2 потоками занял: 0.0200 секунд + +Параллельный алгоритм с 4 потоками занял: 0.0200 секунд + +Параллельный алгоритм с 8 потоками занял: 0.0200 секунд + + +Размер матрицы: 300x300 +Последовательный алгоритм занял: 0.1492 секунд + +Параллельный алгоритм с 1 потоками занял: 0.1510 секунд + +Параллельный алгоритм с 2 потоками занял: 3.1997 секунд + +Параллельный алгоритм с 4 потоками занял: 1.8139 секунд + +Параллельный алгоритм с 8 потоками занял: 1.6556 секунд + +Размер матрицы: 500x500 +Последовательный алгоритм занял: 0.4196 секунд + +Параллельный алгоритм с 1 потоками занял: 0.4201 секунд + +Параллельный алгоритм с 2 потоками занял: 6.0421 секунд + +Параллельный алгоритм с 4 потоками занял: 8.1776 секунд + +Параллельный алгоритм с 8 потоками занял: 5.3308 секунд + +## Выводы +Время параллельного алгоритма (с любым количеством потоков) оказывается немного выше, чем у последовательного. Это объясняется затратами на создание и управление потоками, которые не компенсируются выигрышем от параллельных вычислений для маленьких задач. В случае малых матриц лучше использовать последовательный алгоритм. С увеличением размеров матриц (300x300 и 500x500) время параллельного вычисления увеличивается, что указывает на неэффективность при использовании большого количества процессов. + +## Запуск +Python main.py – threads 1 2 4 8 + +[Ссылка на демонстрацию работы программы](https://vk.com/video547368103_456239606?list=ln-1NucWuxvOOBqHDCdvn) \ No newline at end of file diff --git a/pupkov_alexey_lab_6/main.py b/pupkov_alexey_lab_6/main.py new file mode 100644 index 0000000..048aa20 --- /dev/null +++ b/pupkov_alexey_lab_6/main.py @@ -0,0 +1,84 @@ +import numpy as np +from concurrent.futures import ThreadPoolExecutor +import time +import argparse + +# Вычисляет детерминант матрицы с использованием метода Гаусса +def determinant_sequential(matrix): + n = matrix.shape[0] + mat = matrix.copy().astype(float) + + for i in range(n): + if mat[i, i] == 0: + for j in range(i + 1, n): + if mat[j, i] != 0: + mat[[i, j]] = mat[[j, i]] # Меняем строки + break + + for j in range(i + 1, n): + factor = mat[j, i] / mat[i, i] + mat[j] -= factor * mat[i] + + det = np.prod(np.diag(mat)) + return det + +# Функция для вычисления минора +def calculate_minor(matrix, i, j): + minor = np.delete(matrix, i, axis=0) + minor = np.delete(minor, j, axis=1) + return np.linalg.det(minor) + +# Параллельное вычисление +def determinant_parallel(matrix, num_threads): + + if num_threads == 1: + return determinant_sequential(matrix) + + n = len(matrix) + results = [] + + with ThreadPoolExecutor(max_workers=num_threads) as executor: + futures = [ + executor.submit(lambda x: ((-1) ** x) * matrix[0, x] * calculate_minor(matrix, 0, x), i) + for i in range(n) + ] + for future in futures: + results.append(future.result()) + + return sum(results) + +def benchmark(matrix_sizes, num_threads_list): + for size in matrix_sizes: + matrix = np.random.rand(size, size) + print(f"\nРазмер матрицы: {size}x{size}") + + # Бенчмарк для последовательного алгоритма + start_time = time.time() + det_seq = determinant_sequential(matrix) + sequential_time = time.time() - start_time + print(f"Последовательный алгоритм занял: {sequential_time:.4f} секунд") + + # Бенчмарк для параллельного алгоритма + for num_threads in num_threads_list: + start_time = time.time() + det_par = determinant_parallel(matrix, num_threads) + parallel_time = time.time() - start_time + print(f"Параллельный алгоритм с {num_threads} потоками занял: {parallel_time:.4f} секунд") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Запуск бенчмарков для последовательного и параллельного вычисления детерминанта.") + parser.add_argument( + "--threads", + type=int, + nargs="+", + required=True, + help="Список количества потоков для параллельного алгоритма (например, --threads 1 2 4 8)" + ) + args = parser.parse_args() + + # Задание размеров матриц для тестов + matrix_sizes = [100, 300, 500] + num_threads_list = args.threads # Получаем список потоков из аргументов командной строки + + # Запуск бенчмарка + benchmark(matrix_sizes, num_threads_list)