import time
import random
from multiprocessing import Pool

# Генерация квадратной матрицы со случайными элементами
def generate_matrix(size):
    return [[random.randint(0, 10) for _ in range(size)] for _ in range(size)]

# Рекурсивное вычисление по определителю (по первой строке)
def determinant_recursive(matrix):
    n = len(matrix)
    if n == 1:
        return matrix[0][0]
    elif n == 2:
        return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]
    else:
        det = 0
        for c in range(n):
            if n > 1:
                minor = [row[:c] + row[c+1:] for row in matrix[1:]]
            else: 
                minor = []
            det += ((-1)**c) * matrix[0][c] * determinant_recursive(minor)
        return det

# Вычисление части определителя, выполняется каждым процессом
def worker(chunk):
    start, end, matrix = chunk
    local_det = 0

    if len(matrix) == 1:
        local_det = matrix[0][0]
    else:
        for c in range(start, end):
            minor = [row[:c] + row[c + 1:] for row in matrix[1:]]
            local_det += ((-1)**c) * matrix[0][c] * determinant_recursive(minor)

    return local_det

# Параллельное вычисление определителя матрицы
def parallel_determinant(matrix, num_processes):
    n = len(matrix)

    with Pool(processes=num_processes) as pool:
        num_chunks = min(n, num_processes)  
        chunk_size = n // num_chunks
        remainder = n % num_chunks

        chunks = []
        start_col = 0
        for i in range(num_chunks):
            end_col = start_col + chunk_size + (1 if i < remainder else 0)
            chunks.append((start_col, end_col, matrix))
            start_col = end_col

        results = pool.map(worker, chunks)

    return sum(results)

if __name__ == "__main__":
    sizes = [2, 4, 6, 8, 10]
    process_counts = [2, 4, 8]

    print("| Размер | Метод | Кол-во процессов | Время (мс) | Детерминант |")

    for size in sizes:
        matrix = generate_matrix(size)

        # Последовательное
        start_time = time.time()
        det_recursive = determinant_recursive(matrix)
        end_time = time.time()
        recursive_time_ms = (end_time - start_time) * 1000
        print(f"| {size}x{size} | Последовательный | - | {recursive_time_ms} | {det_recursive} |")

        # Параллельное
        for num_processes in process_counts:
            start_time = time.time()
            det_parallel = parallel_determinant(matrix, num_processes)
            end_time = time.time()
            parallel_time_ms = (end_time - start_time) * 1000
            print(f"| {size}x{size} | Параллельный | {num_processes} | {parallel_time_ms} | {det_parallel} |")