import numpy as np
import time
import multiprocessing


def matrix_multiply(A, B):
    n = A.shape[0]
    C = np.zeros((n, n))
    for i in range(n):
        for j in range(n):
            for k in range(n):
                C[i, j] += A[i, k] * B[k, j]
    return C

def worker(A, B, C, row_indices):
    for i in row_indices:
        for j in range(B.shape[1]):
            for k in range(A.shape[1]):
                C[i, j] += A[i, k] * B[k, j]

def parallel_matrix_multiply(A, B, num_processes):
    n = A.shape[0]
    C = np.zeros((n, n))

    rows_per_process = n // num_processes
    processes = []
    for i in range(num_processes):
        start_row = i * rows_per_process
        end_row = start_row + rows_per_process if i != num_processes - 1 else n
        p = multiprocessing.Process(target=worker, args=(A, B, C, range(start_row, end_row)))
        processes.append(p)
        p.start()

    for p in processes:
        p.join()

    return C

def benchmark(matrix_size, num_processes):
    A = np.random.rand(matrix_size, matrix_size)
    B = np.random.rand(matrix_size, matrix_size)

    start_time = time.time()
    C_par = parallel_matrix_multiply(A, B, num_processes)
    par_time = time.time() - start_time
    print(f"Размер матрицы: {matrix_size}x{matrix_size}, Потоки: {num_processes}, Время: {par_time:.4f} сек.")

if __name__ == "__main__":
    mat_sizes = [100, 300, 500]
    for size in mat_sizes:
        for num_processes in [1, 2, 4]:
            benchmark(size, num_processes)