#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <omp.h>

#define N 512  // Size of the matrix
#define NUM_THREADS 4

// Global matrices
int A[N][N], B[N][N], C[N][N];

// --- OpenMP Implementation ---
void matrix_multiply_openmp(int A[N][N], int B[N][N], int C[N][N]) {
    #pragma omp parallel for collapse(2)
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            C[i][j] = 0;
            for (int k = 0; k < N; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

// --- POSIX Threads Implementation ---
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

typedef struct {
    int start_row, end_row;
} ThreadData;

void *matrix_multiply_pthreads(void *arg) {
    ThreadData *data = (ThreadData *)arg;
    for (int i = data->start_row; i < data->end_row; i++) {
        for (int j = 0; j < N; j++) {
            C[i][j] = 0;
            for (int k = 0; k < N; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
    return NULL;
}

void matrix_multiply_pthreads_wrapper() {
    pthread_t threads[NUM_THREADS];
    ThreadData thread_data[NUM_THREADS];

    // Divide the matrix rows among threads
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_data[i].start_row = i * (N / NUM_THREADS);
        thread_data[i].end_row = (i + 1) * (N / NUM_THREADS);
        pthread_create(&threads[i], NULL, matrix_multiply_pthreads, &thread_data[i]);
    }

    // Join all threads
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }
}

// --- Main Function to Test All Implementations ---
int main() {
    // Initialize matrices A and B with some values (e.g., 1s)
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            A[i][j] = 1;
            B[i][j] = 1;
        }
    }

    // OpenMP Matrix Multiplication
    printf("Starting OpenMP Matrix Multiplication...\n");
    matrix_multiply_openmp(A, B, C);
    printf("OpenMP Matrix Multiplication Done!\n");

    // POSIX Threads Matrix Multiplication
    printf("Starting POSIX Threads Matrix Multiplication...\n");
    matrix_multiply_pthreads_wrapper();
    printf("POSIX Threads Matrix Multiplication Done!\n");

    return 0;
}
