CS-PROJECTS / fuzzylloyd / main.c
main.c
Raw
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <unistd.h>
#include <time.h>

#include "fuzzykmeans.h"
#include "oracle.h"

/* Uncomment for Debugging Print Statments */
// #define DEBUG

static void find_min_and_max(double arr[], double min_and_max[], int len);

int main(int argc, char **argv)
{
    int rank, size, n, k, r;
    double min_max[4], g_max_x = 0, g_max_y = 0,
                       g_min_x = 0, g_min_y = 0;

    MPI_Init(&argc, &argv);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    // Total number of data points
    n = atoi(argv[1]);
    // Total number of clusters
    k = atoi(argv[2]);
    // Display runtime or data and clusters
    r = atoi(argv[3]);

    // Gets start time for runtime option
    double start = (r) ? -1 : MPI_Wtime();

    // Increases number of points until all ranks
    // possess an equal number of data points
    while (n % size != 0)
        n++;

    // Number of data points per rank
    int num_points = n / size;
    // Rank data and global cluster center arrays
    double data[2 * num_points], centers[2 * k];
    // Generates an equal number of data points for each rank
    oracle(data, rank * num_points, num_points);

    if (r) // Prints data points in ascending rank order
    {
        int rec[1], print[1];
        // Receives message from previous rank to print
        if (rank != 0)
            MPI_Recv(rec, 1, MPI_INT, rank - 1, 999, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        // Each rank prints its own data points
        for (int x = 0; x < 2 * num_points; x += 2)
            printf("Rank %d DP: %lf, %lf\n",
                   rank, data[x], data[x + 1]);
        // Sends message to next rank to print
        if (rank != (size - 1))
            MPI_Send(print, 1, MPI_INT, rank + 1, 999, MPI_COMM_WORLD);
    }

    // Finds the minimum and maximum x and y values
    find_min_and_max(data, min_max, num_points);
    // Sets global minimum and maximum x and y values for all ranks
    MPI_Allreduce(&min_max[0], &g_max_x, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
    MPI_Allreduce(&min_max[1], &g_max_y, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
    MPI_Allreduce(&min_max[2], &g_min_x, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
    MPI_Allreduce(&min_max[3], &g_min_y, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);

#ifdef DEBUG
    printf("X_MAX for Rank %d: %lf\n", rank, g_max_x);
    printf("Y_MAX for Rank %d: %lf\n", rank, g_max_y);
    printf("X_MIN for Rank %d: %lf\n", rank, g_min_x);
    printf("Y_MIN for Rank %d: %lf\n", rank, g_min_y);
#endif

    // Rank 0 creates the initial cluster centers
    // for all ranks to use in fuzzykmeans
    if (rank == 0)
    {
        struct drand48_data seed;
        srand48_r(time(NULL), &seed);

        // Sets ranges for x and y values 
        double x_range = g_max_x - g_min_x,
               y_range = g_max_y - g_min_y,
               rand_x, rand_y;

        // Randomly generates cluster centers within the
        // ranges defined above
        for (int i = 0; i < 2 * k; i += 2)
        {
            // Generates random double between 0 and 1
            drand48_r(&seed, &rand_x);
            drand48_r(&seed, &rand_y);

            centers[i] = rand_x * x_range;
            centers[i + 1] = rand_y * y_range;
        }
    }

    // Rank zero sends initial clusters centers to other ranks while
    // non-zero ranks receive cluster centers from rank zero
    MPI_Bcast(centers, 2 * k, MPI_DOUBLE, 0, MPI_COMM_WORLD);

#ifdef DEBUG
    for (int i = 0; i < 2 * k; i++)
        printf("Center %d for Rank %d : %lf\n", i, rank, centers[i]);
#endif

    // fuzzykmeans calculation
    fuzzykmeans(data, num_points, centers, k);

    // Rank 0 prints the final cluster centers
    if (r && rank == 0)
        for (int x = 0; x < 2 * k; x += 2)
            printf("Center: %lf, %lf\n",
                   centers[x], centers[x + 1]);

    // Hghest rank prints the runtime of the program
    // given the valid runtime option
    else if (!r && (rank == (size - 1)))
        printf("Runtime: %lf\n",
               MPI_Wtime() - start);

    MPI_Finalize();

    return 0;
}

/* Finds the minimum and maximum x and y values for an array of lenght 2 * len */
static void find_min_and_max(double arr[], double min_and_max[], int len)
{
    // Sets main and max x and y to first values in arr
    min_and_max[0] = arr[0]; // -- MAX X
    min_and_max[1] = arr[1]; // -- MAX Y
    min_and_max[2] = arr[0]; // -- MIN X
    min_and_max[3] = arr[1]; // -- MIN Y

    for (int i = 0; i < 2 * len; i += 2)
    {
        double x_coor = arr[i],
               y_coor = arr[i + 1];

        if (x_coor > min_and_max[0])
            min_and_max[0] = x_coor;
        else if (x_coor < min_and_max[2])
            min_and_max[2] = x_coor;

        if (y_coor > min_and_max[1])
            min_and_max[1] = y_coor;
        else if (y_coor < min_and_max[3])
            min_and_max[3] = y_coor;
    }
}