2024-11-13 19:30:41 +04:00
|
|
|
|
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()
|