import numpy as np
from time import time
import multiprocessing


def do_task(matrix, start_j, stop_j, queue):
    size = len(matrix[0] - 1)
    if size == 2:
        return matrix[0][0] * matrix[1][1] - matrix[1][0] * matrix[0][1]
    else:
        res = 0
        for j in range(start_j, stop_j):
            tmp = np.delete(matrix, 0, axis=0)
            tmp = np.delete(tmp, j, axis=1)
            a = matrix[0][j]
            b = do_task(tmp, 0, len(tmp[0]), None)

            if j % 2 == 0:
                res += a * b
            else:
                res += a * b * (-1)
        if queue:
            queue.put(res)
        return res


def do_threads(matrix, size, threads):
    offset = int(size / threads)
    offset_last = size % threads + offset

    processes = []
    queue = multiprocessing.Queue()
    start_test = time()
    for i in range(threads):
        start_ = i * offset
        stop_ = start_ + offset_last if i == threads - 1 else start_ + offset

        process = multiprocessing.Process(target=do_task, args=(matrix, start_, stop_, queue))
        processes.append(process)
        process.start()

    total_result = 0
    for p in processes:
        p.join()
        total_result += queue.get()

    # print(total_result)
    stop_test = time()
    print(f'{size}x{size}, time: {stop_test - start_test}')


if __name__ == '__main__':
    sizes = [8, 9, 10, 11]
    threads_counts = [1, 4, 6, 8, 10]

    for threads in threads_counts:
        print('-------------------------------------------------')
        print(f'Threads:{threads}')
        for n in sizes:
            m = np.random.randint(3, size=(n, n))
            do_threads(m, n, threads)

        print('-------------------------------------------------')