#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;
}
}