
/* Josh Holtrop
 * 2008-11-05
 * CS 677
 * Grand Valley State University
 * Instrumented to get serial vs. parallel run times
 */

#include <omp.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <sys/time.h>   /* gettimeofday(), struct timeval */
using namespace std;

void usage(char * progname);
int readFile(char * fileName, vector<int> & v);
void convertToMatrix(const vector<int> & v, int num_verts, int * vals);

void usage(char * progname)
{
    cout << "Usage: " << progname << " <adjacency-file>" << endl;
    exit(42);
}

int main(int argc, char * argv[])
{
    struct timeval start_time, switch_time, end_time;

    gettimeofday(&start_time, NULL);        /* Start timing */

    if (argc < 1)
        usage(argv[0]);

    vector<int> v;

    int num_verts = readFile(argv[1], v);
    int D[2][num_verts][num_verts];
    convertToMatrix(v, num_verts, (int *) &D[0]);

    gettimeofday(&switch_time, NULL);        /* Start timing */

    /* Run Floyd's Algorithm on D */
    for (int k = 1; k <= num_verts; k++)
    {
        for (int i = 0; i < num_verts; i++)
        {
            for (int j = 0; j < num_verts; j++)
            {
                int distWithoutK = D[(k-1) & 1][i][j];
                int distItoK = D[(k-1) & 1][i][k-1];
                int distKtoJ = D[(k-1) & 1][k-1][j];
                int distWithK =
                    (distItoK == INT_MAX || distKtoJ == INT_MAX)
                        ? INT_MAX
                        : distItoK + distKtoJ;
                D[k & 1][i][j] = min(
                    distWithoutK,
                    distWithK
                );
            }
        }
    }

    gettimeofday(&end_time, NULL);         /* Stop timing */

#ifdef PRINT_RESULT
    cout << "Result:" << endl;
    /* Print out the final matrix */
    for (int i = 0; i < num_verts; i++)
    {
        for (int j = 0; j < num_verts; j++)
        {
            if (D[num_verts & 1][i][j] == INT_MAX)
                printf("-- ");
            else
                printf("%2d ", D[num_verts & 1][i][j]);
        }
        printf("\n");
    }
#endif

    double time_start = start_time.tv_sec + start_time.tv_usec / 1000000.0;
    double time_switch = switch_time.tv_sec + switch_time.tv_usec / 1000000.0;
    double time_end = end_time.tv_sec + end_time.tv_usec / 1000000.0;
    double serial = time_switch - time_start;
    double parallel = time_end - time_switch;
    cout << "Serial execution time: " << serial << " seconds" << endl;
    cout << "Parallel execution time: " << parallel << " seconds" << endl;

    return 0;
}

int readFile(char * fileName, vector<int> & v)
{
    ifstream in(fileName);
    if (!in.is_open())
    {
        cerr << "Error opening " << fileName << endl;
        return -1;
    }

    for (;;)
    {
        int weight;
        in >> weight;
        if (in.eof())
            break;
        v.push_back(weight);
    }

    return (int) sqrt(v.size());
}

void convertToMatrix(const vector<int> & v, int num_verts, int * vals)
{
    int vidx = 0;
    int (*V)[num_verts][num_verts] = (int (*)[num_verts][num_verts]) vals;
    for (int i = 0; i < num_verts; i++)
    {
        for (int j = 0; j < num_verts; j++)
        {
            (*V)[i][j] = v[vidx++];
            if ((*V)[i][j] == 0)
                (*V)[i][j] = INT_MAX;
        }
    }
}
