#include #include #include void local_quicksort(int *arr, int lo, int hi); char *string_of_list(int *arr, int len); int main(int argc, char **argv) { int rank, p; MPI_Init(&argc, &argv); int n = atoi(argv[1]); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &p); // Generate integers int n_over_p = n / p; int integers[n_over_p]; // Important implementation detail: srand(0) is specially handled by glibc to // behave as if it was called with srand(1). To get around this, I'm seeding // with rank + 1 // // See more: https://stackoverflow.com/a/27386563 srand(rank + 1); for (int i = 0; i < n_over_p; ++i) { // TODO: For readability during debugging, I'm capping this integers[i] = rand() % 101; // printf(" - %d\n", integers[i]); } int group_root = 0; // Locally sort printf("[%d] Numbers before: %s\n", rank, string_of_list(integers, n_over_p)); local_quicksort(integers, 0, n_over_p); printf("[%d] Numbers after first sort: %s\n", rank, string_of_list(integers, n_over_p)); // Select a pivot. // This pivot is broadcasted to all nodes int pivot; // The pivot is selected as the median (see chp. 9.4.4) // Not the real median though, need an existing element of the array pivot = integers[n_over_p / 2]; MPI_Bcast(&pivot, 1, MPI_INT, 0, MPI_COMM_WORLD); printf("Median: %d\n", pivot); // Determine where the boundary between S (lower) and L (higher) lies int boundary; for (int i = 0; i < n_over_p; ++i) { if (integers[i] >= pivot) { boundary = i; break; } } int S_lo = 0, S_hi = boundary - 1; int L_lo = boundary, L_hi = n_over_p - 1; int S_size = S_hi - S_lo + 1, L_size = L_hi - L_lo + 1; // printf("[%d] S: [%d - %d] (%d), L: [%d - %d] (%d)\n", rank, S_lo, S_hi, // S_size, L_lo, L_hi, L_size); // Perform global arrangement int S_global_end, L_global_end; MPI_Scan(&S_size, &S_global_end, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); MPI_Scan(&L_size, &L_global_end, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); int S_global_start = S_global_end - S_size, L_global_start = L_global_end - L_size; printf("[%d] S: [%d - %d], L: [%d - %d]\n", rank, S_global_start, S_global_end - 1, L_global_start, L_global_end - 1); // Send it to the correct target // The first node is responsible for collecting all the data and then printing // it out to the file // MPI_Gather(const void *sendbuf, int sendcount, MPI_INT, void *recvbuf, // int recvcount, MPI_INT, 0, MPI_COMM_WORLD); if (rank == 0) { FILE *f = fopen(argv[2], "w"); fclose(f); } MPI_Finalize(); return 0; } // hi not inclusive void local_quicksort(int *arr, int lo, int hi) { int temp; if (lo >= hi || lo < 0) return; int pivot = arr[hi - 1]; int pivot_idx = lo - 1; for (int j = lo; j < hi; ++j) { if (arr[j] < pivot) { pivot_idx += 1; temp = arr[j]; arr[j] = arr[pivot_idx]; arr[pivot_idx] = temp; } } pivot_idx += 1; temp = arr[hi - 1]; arr[hi - 1] = arr[pivot_idx]; arr[pivot_idx] = temp; // Recursive call local_quicksort(arr, lo, pivot_idx); local_quicksort(arr, pivot_idx + 1, hi); } char *string_of_list(int *arr, int len) { char *buffer = malloc(1000); int offset = 0; // Keep track of the current position in the buffer for (int i = 0; i < len; i++) { offset += sprintf(buffer + offset, "%d", arr[i]); if (i < len - 1) { // Add a separator (e.g., comma or space) if it's not the last element offset += sprintf(buffer + offset, " "); } } return buffer; }