import numpy as np
from multiprocessing import Pool
import time
import argparse


def determinant_block(matrix_block):
    """Вычисляет детерминант блока матрицы."""
    return np.linalg.det(matrix_block)


def determinant_parallel(matrix, num_processes):
    """Вычисляет детерминант матрицы параллельно."""
    size = matrix.shape[0]
    step = size // num_processes

    # Обработка случаев, когда размер матрицы не делится на число процессов
    blocks = []
    for i in range(num_processes):
        start_row = i * step
        end_row = start_row + step if i < num_processes - 1 else size
        blocks.append(matrix[start_row:end_row, start_row:end_row])

    pool = Pool(processes=num_processes)
    dets = pool.map(determinant_block, blocks)
    pool.close()
    pool.join()

    # Объединение детерминантов блоков
    return np.prod(dets)


def benchmark(size, num_processes):
    """Запускает бенчмарк для матрицы заданного размера и числа процессов."""
    matrix = np.random.rand(size, size)

    # Параллельное вычисление детерминанта
    start = time.time()
    det_parallel = determinant_parallel(matrix, num_processes)
    end = time.time()
    print(f"Матрица {size}x{size} с {num_processes} процессами заняла {end - start:.5f} сек (Параллельно)")

    # Последовательное вычисление детерминанта
    start = time.time()
    det_seq = determinant_block(matrix)
    end = time.time()
    print(f"Матрица {size}x{size} последовательный вычисление заняло {end - start:.5f} сек (Последовательно)")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Вычисление детерминанта с параллельной обработкой")
    parser.add_argument("--processes", type=int, default=4)
    args = parser.parse_args()

    sizes = [100, 300, 500]
    for size in sizes:
        benchmark(size, args.processes)