#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "mpi.h"

#include "mpi_bnc.h"

#define DIM 5

int main(int argc, char *argv[])
{
    DMatrix my_dmat_ans[10], my_dmat1[10], my_dmat2[10];
    DMatrix dmat_ans, dmat1, dmat2;

    long int d_ddim[MPI_GMP_MAXPROCS];
    long int i, j, local_dim;
    int myrank, num_procs;
    double start_wtime, end_wtime;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);

    local_dim = _mpi_divide_dim(d_ddim, DIM, num_procs);

    _mpi_init_dmatrix(my_dmat_ans, d_ddim, DIM, MPI_COMM_WORLD);
    _mpi_init_dmatrix(my_dmat1, d_ddim, DIM, MPI_COMM_WORLD);
    _mpi_init_dmatrix(my_dmat2, d_ddim, DIM, MPI_COMM_WORLD);

    if(myrank == 0)
    {
        dmat_ans = init_dmatrix(local_dim * num_procs, local_dim * num_procs);
        dmat1 = init_dmatrix(local_dim * num_procs, local_dim * num_procs);
        dmat2 = init_dmatrix(local_dim * num_procs, local_dim * num_procs);
        for(i = 0; i < DIM; i++)
            for(j = 0; j < DIM; j++)
            {
                set_dmatrix_ij(dmat1, i, j, (double)(i*DIM + j + 1));
                set_dmatrix_ij(dmat2, i, j, (double)(DIM * DIM - (i*DIM +j)));
            }
    }

    _mpi_divide_dmatrix(my_dmat1, d_ddim, dmat1, MPI_COMM_WORLD);
    _mpi_divide_dmatrix(my_dmat2, d_ddim, dmat2, MPI_COMM_WORLD);

    if(myrank == 0) start_wtime = MPI_Wtime();
    _mpi_mul_dmatrix(my_dmat_ans, my_dmat1, my_dmat2, MPI_COMM_WORLD);
    if(myrank == 0) end_wtime = MPI_Wtime();

    _mpi_collect_dmatrix(dmat_ans, d_ddim, my_dmat_ans, MPI_COMM_WORLD);

    /* free */
    _mpi_free_dmatrix(my_dmat_ans, MPI_COMM_WORLD);
    _mpi_free_dmatrix(my_dmat1, MPI_COMM_WORLD);
    _mpi_free_dmatrix(my_dmat2, MPI_COMM_WORLD);

    if(myrank == 0)
    {
        printf("MPIBNC:\n"); print_dmatrix(dmat_ans);
        printf("MPI_MUL_TIME: %f\n", end_wtime - start_wtime);

        start_wtime = get_secv();
        mul_dmatrix(dmat_ans, dmat1, dmat2);
        end_wtime = get_secv();

        printf("BNC:\n"); print_dmatrix(dmat_ans);
        printf("BNC_MUL_TIME: %f\n", end_wtime - start_wtime);

        free_dmatrix(dmat_ans);
        free_dmatrix(dmat1);
        free_dmatrix(dmat2);
    }
    MPI_Finalize();

	return EXIT_SUCCESS;
}

