artamonova_tatyana_lab_6 is ready #205

Open
ttartt wants to merge 1 commits from artamonova_tatyana_lab_6 into main
3 changed files with 112 additions and 0 deletions

View File

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -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} сек. |")