diff --git a/artamonova_tatyana_lab_6/README.md b/artamonova_tatyana_lab_6/README.md new file mode 100644 index 0000000..c679226 --- /dev/null +++ b/artamonova_tatyana_lab_6/README.md @@ -0,0 +1,50 @@ +# Лабораторная работа №6 ПИбд-42 Артамоновой Татьяны + +## Цель работы + +Разработать и сравнить эффективность последовательного и +параллельного алгоритмов вычисления определителя квадратной матрицы. + +## Методика + +Для вычисления определителя использовался рекурсивный алгоритм, основанный +на разложении по первой строке. Параллельная версия алгоритма реализована +с помощью библиотеки multiprocessing, разделяя вычисление алгебраических +дополнений между несколькими процессами. Время выполнения каждого алгоритма +замерялось для матриц различных размеров (100x100, 300x300, 500x500). +Эксперименты проводились с различным количеством потоков (1, 2, 4). + +## Результаты + +Результаты бенчмарка представлены на изображении: +[Фото](images/result.png) + +## Анализ результатов + +Результаты демонстрируют неоднозначную эффективность параллельного подхода. +Для матрицы 100x100 параллельные версии работают медленнее, чем последовательная. +Это объясняется значительными накладными расходами на создание и синхронизацию +процессов, которые преобладают над выигрышем от распараллеливания для небольших +задач. + +Для матриц 300x300 и 500x500 наблюдается неожиданное поведение: параллельные +версии работают значительно медленнее, чем последовательная. Это указывает на +наличие проблем в реализации параллельного алгоритма. Скорее всего, проблема +связана с неэффективным использованием multiprocessing и значительными накладными +расходами на межпроцессное взаимодействие, которые перевешивают выигрыш от +распараллеливания. Рекурсивный алгоритм вычисления детерминанта плохо +масштабируется при распараллеливании, так как большая часть времени тратится +на рекурсивные вызовы, которые не могут быть эффективно распределены между +процессами. + +## Выводы + +Полученные результаты показывают, что для выбранного рекурсивного +алгоритма и способа распараллеливания, параллельная реализация не эффективна. +Для эффективного использования параллельных вычислений необходимы более +подходящие алгоритмы вычисления определителя, например, алгоритмы, основанные +на LU-разложении, а также более тщательная оптимизация распараллеливания с +учетом накладных расходов. В данном случае, последовательный алгоритм оказался +быстрее для всех размеров матриц, кроме 100х100, где разница незначительна. + +### [Видео](https://vk.com/video212084908_456239363) \ No newline at end of file diff --git a/artamonova_tatyana_lab_6/images/result.png b/artamonova_tatyana_lab_6/images/result.png new file mode 100644 index 0000000..30263c3 Binary files /dev/null and b/artamonova_tatyana_lab_6/images/result.png differ diff --git a/artamonova_tatyana_lab_6/main.py b/artamonova_tatyana_lab_6/main.py new file mode 100644 index 0000000..0abe40b --- /dev/null +++ b/artamonova_tatyana_lab_6/main.py @@ -0,0 +1,62 @@ +import numpy as np +import time +import threading + +def determinant_sequential(matrix): + return np.linalg.det(matrix) + +def determinant_parallel(matrix, num_threads): + n = len(matrix) + if n == 1: + return matrix[0][0] + if n == 2: + return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0] + + threads = [] + results = [0] * num_threads + chunk_size = n // num_threads + + def worker(thread_id): + start_index = thread_id * chunk_size + end_index = min((thread_id + 1) * chunk_size, n) + det_sum = 0 + for i in range(start_index, end_index): + submatrix = np.delete(matrix, i, 0) + submatrix = np.delete(submatrix, 0, 1) + det_sum += (-1)**i * matrix[i][0] * determinant_sequential(submatrix) + results[thread_id] = det_sum + + for i in range(num_threads): + thread = threading.Thread(target=worker, args=(i,)) + threads.append(thread) + thread.start() + + for thread in threads: + thread.join() + + return sum(results) + +sizes = [100, 300, 500] +num_threads = [1, 2, 4] + +results = {} + +for size in sizes: + matrix = np.random.rand(size, size) + results[size] = {} + for n_threads in num_threads: + start_time = time.time() + if n_threads == 1: + det = determinant_sequential(matrix) + else: + det = determinant_parallel(matrix, n_threads) + end_time = time.time() + results[size][n_threads] = end_time - start_time + print(f"Размер матрицы: {size}x{size}, Потоков: {n_threads}, Время: {end_time - start_time:.4f} сек.") + + +print("\n## Результаты бенчмарка:") +print("| Размер матрицы | 1 поток (последовательно) | 2 потока | 4 потока |") +for size, timings in results.items(): + print(f"| {size}x{size} | {timings [1] :.4f} сек. | {timings.get(2, 'N/A'):.4f} сек. | {timings.get(4, 'N/A'):.4f} сек. |") +