import numpy as np
from concurrent.futures import ProcessPoolExecutor
import time

# Функция последовательного поиска детерминанта
def det_sequential(matrix):
    n = len(matrix)
    det = 1
    
    for i in range(n):
        if matrix[i][i] == 0:
            for j in range(i + 1, n):
                if matrix[j][i] != 0:
                    matrix[i], matrix[j] = matrix[j], matrix[i]
                    det *= -1  
                    break
            else:
                return 0

        for j in range(i + 1, n):
            factor = matrix[j][i] / matrix[i][i]
            for k in range(i, n):
                matrix[j][k] -= factor * matrix[i][k]

        det *= matrix[i][i]

    return det

# Функция поиска детерминанта с numpy
def det_numpy(A):
    return np.linalg.det(A)

# Функция параллельного поиска детерминанта
def det_parallel(A, num_threads):
    n = len(A)
    C = []
    step = n // num_threads
    
    with ProcessPoolExecutor(max_workers=num_threads) as executor:
        futures = []
        for i in range(num_threads):
            start_row = i * step
            end_row = (i + 1) * step if i != num_threads - 1 else n
            a_slice = A[start_row:end_row, start_row:end_row]

            futures.append(executor.submit(det_sequential, a_slice))
        for future in futures:
            C.append(future.result())
    
    return np.prod(C)

# Пример использования
if __name__ == "__main__":
    matrix_sizes = [100, 300, 500] 
    num_threads = [2, 4, 5, 10]
    for n in matrix_sizes:
        A = np.random.rand(n, n)
        
        # Поиск с numpy
        start_np = time.time() 
        nump = det_numpy(A)
        end_np = time.time() 
        print(f'Детерминант матрицы {n}x{n} с numpy: {(end_np - start_np):.3f} с.')

        # Последовательное умножение
        start_seq = time.time() 
        sequential = det_sequential(A)
        end_seq = time.time() 
        print(f'Детерминант матрицы {n}x{n} последовательно: {(end_seq - start_seq):.3f} с.')

        # Параллельное умножение
        for thread in num_threads:
            start_par = time.time() 
            parallel = det_parallel(A, thread)
            end_par = time.time() 
            print(f'Детерминант матрицы {n}x{n} параллельно для {thread} потоков: {(end_par - start_par):.3f} с.')
        print('')