Parallel Merge Sort using MPI - c

I implemented Parallel Merge sort in this code using the tree Structural scheme; but it doesn't sort the Array!
Could you take look at it and tell me what is wrong?
For communication among the processor I used the normal MPI_send() and MPI_recv().
However I used numbers 0 and 1 and 2 as tags for the fifth argument of MPI_recv().
For 8 processors the tree structural scheme gives the Array to the processor with rank 0 then it splits the array in half an gives the right half to processor 4 and keeps the left half.
Then the processor 4 splits its array in half an gives the right half to processor 6 and keeps the left half.
At the end with this scheme all the processors work an the program and none of them will idle.
Since at the leaves of the tree all the processors have a piece of Array to do sequential Merge_sort_inc on it.
text
#include<stdio.h>
#include<mpi.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
/* print_array() takes the elements of Array to the output */
void print_array(int arr[], int size)
{
for (int i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
/*copyarray() takes as first argument an Array a[] which its elements
between indexes start_a and end_a are to be copied to the dynamic Array *b with size of (size_b) */
void copyarray(int a[] ,int start_a , int end_a, int* b, int size_b)
{
int i = 0;
for (i = 0; i < size_b;i++)
{
b[i] = a[start_a];
start_a++;
if (start_a == end_a)
break;
}
}
/* merge () function is just the sequential implementation of merge Sort Algorithm */
void merge(int Arr[], int left, int mid, int right)
{
int n_l = (mid - left + 1);
int n_r = (right - mid);
int* Arr_l = (int*)calloc(n_l, sizeof(int));
int* Arr_r = (int*)calloc(n_r, sizeof(int));
if (Arr_l == NULL)
return;
if (Arr_r == NULL)
return;
for (int i = 0;i < n_l;i++)
Arr_l[i] = Arr[left + i];
for (int j = 0;j < n_r;j++)
Arr_r[j] = Arr[mid + 1 + j];
int i = 0, j = 0, k = left;
while (i < n_l && j < n_r)
{
if (Arr_l[i] <= Arr_r[j])
{
Arr[k] = Arr_l[i];
i++;
k++;
}
else
{
Arr[k] = Arr_r[j];
j++;
k++;
}
}
while (i < n_l)
{
Arr[k] = Arr_l[i];
i++;
k++;
}
while (j < n_r)
{
Arr[k] = Arr_r[j];
j++;
k++;
}
free(Arr_l);
free(Arr_r);
}
/*merge_sort_inc() is the sequential algorithm of sorting in increasing order*/
void merge_sort_inc(int Arr[], int left, int right)
{
int mid = (int)(left + (right - left) / 2);
if (left < right)
{
merge_sort_inc(Arr, left, mid);
merge_sort_inc(Arr, mid + 1, right - 1);
merge(Arr, left, mid, right);
}
}
/*parallelMerge() builds first the tree-structural communication between the processors. at the leafs of the tree,
where there is no more divide and concurrent progress the Function gives the the processor the sequential Merge sort algorithm*/
void parallelMerge(int* array, int size, int height)
{
int parent;
int rank;
int numberOfproc;
int next;
int rightChild;
//MPI_Init(NULL, NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numberOfproc);
parent = rank & ~(1 << height);
next = height - 1;
rightChild = rank | (1 << (height - 1));
if (height > 0)
if (rightChild >= numberOfproc)
parallelMerge(array, size, next);
else
{
int left_size = (int)(size / 2);
int right_size = size - left_size;
int* leftArray = (int*)calloc(left_size, sizeof(int));
int * rightArray = (int*)calloc(right_size,sizeof(int));
if (leftArray == NULL)
return;
if (rightArray == NULL)
return;
int massage[2];
int i, j , k;
MPI_Status status;
copyarray(array, 0, left_size, leftArray, left_size);
copyarray(array, size - left_size, size, rightArray,right_size);
massage[0] = next;
massage[1] = right_size;
MPI_Send(massage, 2, MPI_INT, rightChild,0, MPI_COMM_WORLD);
MPI_Send(rightArray, right_size, MPI_INT, rightChild, 1, MPI_COMM_WORLD);
parallelMerge(leftArray, left_size, next);
MPI_Recv(rightArray, right_size, MPI_INT, rightChild, 2, MPI_COMM_WORLD, &status);
i = j = k = 0;
while (i < left_size && j < right_size)
{
if (leftArray[i] < rightArray[j])
{
array[k] = leftArray[i]; i++, k++;
}
else
{
array[k] = rightArray[j]; j++, k++;
}
}
while (i<left_size)
{
array[k] = leftArray[i];
k++;
i++;
}
while (j<right_size)
{
array[k] = rightArray[j];
k++;
j++;
}
}
else
{
merge_sort_inc(array, 0 ,size);
if (parent != rank)
MPI_Send(array, size, MPI_INT, parent, 2, MPI_COMM_WORLD);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
/*building an array with the help of Random function*/
time_t t;
srand((unsigned)time(&t));
int Arr[100];
int arrSize = sizeof(Arr) / sizeof(int);
for (int i = 0; i < arrSize; i++)
Arr[i] = rand() / 100;
printf("the unsorted array is : \n ");
print_array(Arr, arrSize);
/*starting the parallel sorting*/
int rank;
int comm_size;
MPI_Init(NULL,NULL);
MPI_Comm_rank(MPI_COMM_WORLD , &rank);
MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
double start = MPI_Wtime();//capture time
if (rank == 0)
{
int roothight = 0;
int nodeCount = 1;
while (nodeCount < comm_size)
nodeCount++;
roothight = (int)log(nodeCount);
int* newarray = (int*)calloc(arrSize, sizeof(int));
if (newarray == NULL)
return 1;
copyarray(Arr, 0, arrSize - 1, newarray, arrSize );
parallelMerge(newarray, arrSize, roothight);
double midle = MPI_Wtime();
}
else
{
int massage[2];
int height;
int size_array;
MPI_Status status;
MPI_Recv(massage, 2, MPI_INT, MPI_ANY_SOURCE,0, MPI_COMM_WORLD, &status);
height = massage[0];
size_array = massage[1];
int* newarray = (int*)calloc(size_array, sizeof(int));
if (newarray == NULL)
return 1;
MPI_Recv(newarray, size_array, MPI_INT, MPI_ANY_SOURCE,1, MPI_COMM_WORLD, &status);
parallelMerge(newarray, size_array, height);
}
double end = MPI_Wtime();
MPI_Finalize();
printf("\n the sorted array is : \n");
print_array(Arr, arrSize);
printf("\n the sorting takes %lf time ", (end - start));
return 0;
}

Related

stuck on implementation of merge sort

I am implementing mergesort referencing the geeks for geeks implementation as a guide but my implementation is not working.
I have my mergesort function that divides my given array in 2 and calls mergesort on half of the list.
Within mergesort, I use a helper function that merges the sub arrays together.
I have included my 2 functions. Could someone be my second set of eyes, I am have staring at this too long to tell the difference between 1's and l's
It is running but not sorting correctly.
void merge(int arr[], int temp[], int l, int m, int r) {
//TODO: implement merge.
// check arr
if (arr == NULL) {
return;
}
int left = m - l + 1;
int right = r - m;
// copy array into temp array
// first half
int i = 0;
for (i = 0; i < left; i++) {
temp[i] = arr[l + i];
}
// second half
int j = 0;
for (j = m + 1; i < right; j++) {
temp[j] = arr[m + l + i];
}
// compare from each end inserting the lower into the next location of the real array
// beginning index of front sub list
int front = 0;
// beginning of back sub list
int back = left;
// index within array to insert back in
int index = l;
while ((front < left) && (back < right)) {
if (temp[front] <= temp[back]) {
// temp front goes in the next array spot
arr[index] = temp[front];
// increase temp
front++;
} else {
// back is smaller and is put back in the list first
arr[index] = temp[back];
// increase back
back++;
}
// increase array index
index++;
}
while (front < left) {
arr[index] = temp[front];
front++;
index++;
}
while (back < right) {
arr[index] = temp[back];
back++;
index++;
}
}
void mergeSort(int array[], int temp[], int l, int r) {
if (r > l) {
// find middle point
int middle = l + (r - l) / 2;
// call merge on first half
mergeSort(array, temp, l, middle);
// call merge on second half
mergeSort(array, temp, middle + 1, r);
// merge the halves
merge(array, temp, l, middle, r);
}
}
There is a problem here:
// second half
int j = 0;
for (j = m + 1; i < right; j++) {
temp[j] = arr[m + l + i];
}
You should write:
// second half
for (i = 0; i < right; i++) {
temp[left + i] = arr[m + 1 + i];
}
Could someone be my second set of eyes, I am have staring at this too long to tell the difference between 1's and l's?
This is an excellent point! The solution is to never use l as a variable name, and to simplify the mergesort implementation to remove the confusing and error prone +1 / -1 adjustments. For this you just need to use the convention where r is the index of the element after the end of the slice.
Here is a modified version:
void merge(int arr[], int temp[], int lo, int mid, int hi) {
// check arr
if (arr == NULL) {
return;
}
int left = mid - lo;
int right = hi - mid;
// copy array into temp array
// first half
for (int i = 0; i < left; i++) {
temp[i] = arr[lo + i];
}
// second half
for (int i = 0; i < right; i++) {
temp[left + i] = arr[mid + i];
}
// compare from each end inserting the lower into the next location of the real array
// beginning index of front sub list
int front = 0;
// beginning of back sub list
int back = left;
// index within array to insert back in
int index = lo;
while ((front < left) && (back < right)) {
if (temp[front] <= temp[back]) {
// temp front goes in the next array spot
arr[index++] = temp[front++];
} else {
// back is smaller and is put back in the list first
arr[index++] = temp[back++];
}
}
while (front < left) {
arr[index++] = temp[front++];
}
while (back < right) {
arr[index++] = temp[back++];
}
}
void mergeSort(int array[], int temp[], int lo, int hi) {
if (hi - lo >= 2) {
// find middle point
int mid = lo + (hi - lo) / 2;
// call merge on first half
mergeSort(array, temp, lo, mid);
// call merge on second half
mergeSort(array, temp, mid, hi);
// merge the halves
merge(array, temp, lo, mid, hi);
}
}
The initial call should give 0 and the length of the array as index arguments.
I had some trouble understanding your merge logic.
Too many indexes/limits of the form (e.g): m - l + 1
So, I simplified things by having two temp pointers: tmp_l and tmp_r and added some length/count variables.
This allowed some of the indexes to start with 0.
Also, your middle calculation was unusual.
And, I changed the arg in the call to merge from middle to middle + 1
I've refactored the code and added a test suite. I've used cpp conditionals to denote old vs new code:
#if 0
// old code
#else
// new code
#endif
Anyway, here's my [working] version:
#include <stdio.h>
#include <stdlib.h>
#ifdef DEBUG
#define dbgprt(_fmt...) \
do { \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#endif
void
merge(int arr[], int temp[], int l, int m, int r)
{
if (arr == NULL) {
return;
}
// get number of left elements
int lcnt = (m - l);
// get number of right elements
int rcnt = (r - m) + 1;
dbgprt("merge: BEGIN l=%d m=%d r=%d lcnt=%d rcnt=%d\n",
l,m,r,lcnt,rcnt);
int i = 0;
int *tmp_l = &temp[0];
for (i = 0; i < lcnt; i++)
tmp_l[i] = arr[l + i];
int *tmp_r = &temp[lcnt];
for (i = 0; i < rcnt; i++)
tmp_r[i] = arr[m + i];
int front = 0;
int back = 0;
int index = l;
while ((front < lcnt) && (back < rcnt)) {
// temp front goes in the next array spot
if (tmp_l[front] <= tmp_r[back]) {
arr[index] = tmp_l[front];
// increase temp
front++;
}
// back is smaller and is put back in the list first
else {
arr[index] = tmp_r[back];
// increase back
back++;
}
// increase array index
index++;
}
while (front < lcnt) {
arr[index] = tmp_l[front];
index++;
front++;
}
while (back < rcnt) {
arr[index] = tmp_r[back];
index++;
back++;
}
}
void
mergeSort(int array[], int temp[], int l, int r)
{
int middle;
if (r > l) {
// find middle point
#if 0
middle = l + (r - 1) / 2;
#else
middle = (l + r) / 2;
#endif
dbgprt("msort: ENTER l=%d m=%d r=%d\n",l,middle,r);
// call merge on first half
mergeSort(array, temp, l, middle);
// call merge on second half
mergeSort(array, temp, middle + 1, r);
// merge the halves
#if 0
merge(array, temp, l, middle, r);
#else
merge(array, temp, l, middle + 1, r);
#endif
dbgprt("msort: EXIT l=%d m=%d r=%d\n",l,middle,r);
}
}
void
dotest(int tstno)
{
int count = (rand() % 30) + 1;
printf("dotest: %d %d\n",tstno,count);
int *arr = malloc(sizeof(*arr) * count);
int *tmp = malloc(sizeof(*tmp) * count);
for (int idx = 0; idx < count; ++idx) {
arr[idx] = count - idx;
dbgprt(" %d",arr[idx]);
}
dbgprt("\n");
mergeSort(arr,tmp,0,count - 1);
int err = 0;
for (int idx = 0; idx < count; ++idx) {
printf(" %d",arr[idx]);
if (arr[idx] != (idx + 1)) {
printf("?");
err = 1;
}
}
printf("\n");
if (err)
exit(1);
free(arr);
free(tmp);
}
int
main(void)
{
for (int tstno = 1; tstno <= 4; ++tstno)
dotest(tstno);
return 0;
}
void
merge_ORIG(int arr[], int temp[], int l, int m, int r)
{
if (arr == NULL) {
return;
}
int i = 0;
for (i = 0; i < m - l + 1; i++) {
temp[i] = arr[l + i];
}
for (i = 0; i < r + 1; i++) {
temp[i] = arr[m + l + i];
}
int front = l;
int back = m + 1;
int index = l;
while ((front < m - l + 1) && (back < r - m)) {
if (temp[front] <= temp[back]) {
// temp front goes in the next array spot
arr[index] = temp[front];
// increase temp
front++;
}
else {
// back is smaller and is put back in the list first
arr[index] = temp[back];
// increase back
back++;
}
// increase array index
index++;
}
while (front < m - l + 1) {
arr[index] = temp[front];
index++;
front++;
}
while (back < r - m) {
arr[index] = temp[back];
index++;
back++;
}
}

Why is an extra element being added to my void** array when I use merge-sort?

When I use mergeSort to sort my void** array (this array contains void* pointers that point to integers), an extra 1 (a new element) appears to be added to the array. I am nearly certain the issue is in mergeSort or merge, as when print my void** array before calling mergeSort, the data is correct (just unsorted). Here is the code.
#define SIZE 10
void mergeSort(void**, int, int);
void merge(void**, int, int, int);
int compare(void*, void*);
int main(void) {
int array[SIZE] = { 5, 6, 3, 2, 5, 6, 7, 4, 9, 3 };
void *voidArray[SIZE];
int query = 1;
void *queryPointer = &query;
for (int j = 0; j < SIZE; j++) {
voidArray[j] = &array[j];
}
printArray(voidArray);
mergeSort(voidArray, 0, SIZE);
printArray(voidArray);
result = binarySearch(voidArray, 0, SIZE, queryPointer);
if (result == -1) {
puts("Query not found.");
return(0);
}
printf("Query found at index %d.\n", result);
return(0);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void mergeSort(void **array, int head, int tail) {
if (head < tail) {
int middle = (head + ((tail - head) / 2));
mergeSort(array, head, middle);
mergeSort(array, (middle + 1), tail);
merge(array, head, middle, tail);
}
}
void merge(void **array, int head, int middle, int tail) {
int headLength = (middle - head + 1);
int tailLength = (tail - middle);
void *headSide[headLength];
void *tailSide[tailLength];
for (int i = 0; i < headLength; i++) {
headSide[i] = array[head + i];
}
for (int j = 0; j < tailLength; j++) {
tailSide[j] = array[middle + 1 + j];
}
int k = head;
int l = 0;
int m = 0;
while (l < headLength && m < tailLength) {
if (compare(headSide[l], tailSide[m]) == -1) {
array[k] = headSide[l];
l++;
} else {
array[k] = tailSide[m];
m++;
}
k++;
}
while (l < headLength) {
array[k] = headSide[l];
l++;
k++;
}
while (m < tailLength) {
array[k] = tailSide[m];
m++;
k++;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int compare(void *index, void *query) {
if (*((int *)index) == *((int *)query)) {
return (0);
}
if (*((int*)index) > *((int*)query)) {
return (1);
}
return (-1);
}
The output should have the unsorted array, the sorted array, and whether the query was found. There is no 1 in the unsorted array, but then there is a 1 in the sorted array; also, the number 9 is missing from the sorted results (interestingly, if I perform a binary search for 9, it will tell me that 9 is found at index 10).
Example output (for a query of 1):
5 6 3 2 5 6 7 4 9 3
1 2 3 3 4 5 5 6 6 7
Query found at index 0.
Check your array subscript.
int tailLength = (tail - middle)
tail is the size of array,I think tailLength is incorrect.
headSide[i] = array[head + i];
headSide[i] is void and array[head + i] is void*
There is some confusion in the arguments to margeSort and merge. Passing the index of the last element in the range is not idiomatic in C. It is much simpler to pass the index of the element after the end of the range, which is consistent with passing 0 and SIZE int main(): mergeSort(voidArray, 0, SIZE); and result = binarySearch(voidArray, 0, SIZE, queryPointer);
Here is a modified version with this API:
void mergeSort(void **array, int head, int tail) {
if (tail - head > 1) {
int middle = head + (tail - head) / 2);
mergeSort(array, head, middle);
mergeSort(array, middle, tail);
merge(array, head, middle, tail);
}
}
void merge(void **array, int head, int middle, int tail) {
int headLength = middle - head;
int tailLength = tail - middle;
void *headSide[headLength];
void *tailSide[tailLength];
for (int i = 0; i < headLength; i++) {
headSide[i] = array[head + i];
}
for (int j = 0; j < tailLength; j++) {
tailSide[j] = array[middle + j];
}
int k = head;
int l = 0;
int m = 0;
while (l < headLength && m < tailLength) {
if (compare(headSide[l], tailSide[m]) <= 0) {
array[k++] = headSide[l++];
} else {
array[k++] = tailSide[m++];
}
}
while (l < headLength) {
array[k++] = headSide[l++];
}
while (m < tailLength) {
array[k++] = tailSide[m++];
}
}
Note however that allocating the temporary arrays headSide and tailSide with automatic storage (aka on the stack) is risky for large arrays. Furthermore, it is not necessary to save the elements from the right half into tailSide as they will not be overwritten before they are copied to the final position. Here is a simpler version of merge:
void merge(void **array, int head, int middle, int tail) {
int headLength = middle - head;
void *headSide[headLength];
for (int i = 0; i < headLength; i++) {
headSide[i] = array[head + i];
}
int k = head;
int l = 0;
while (l < headLength && middle < tail) {
if (compare(headSide[l], array[middle]) <= 0) {
array[k++] = headSide[l++];
} else {
array[k++] = array[middle++];
}
}
while (l < headLength) {
array[k++] = headSide[l++];
}
}

Read Access Violation in C, trying to find the source

guys. I've got a project where I'm given a number of chairs, a number of parasols, and the locations of the chairs. I think have to find the optimal width of all parasols (all equal to each other) to cover each chair. I crafted this bit of code that works for the sample cases in the assignment file (it's messy, but it works):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void search();
int* constructParasols();
int check();
void draw();
int main(void)
{
int n, k, totalSize;
scanf("%d", &n);
printf("\n");
scanf("%d", &k);
printf("\n");
int* chairs = (int*)calloc(n + 1, sizeof(int));
for (int i = 0; i < n; i++)
{
scanf("%d", &chairs[i]);
}
printf("\n");
totalSize = chairs[n - 1];
search(n, k, chairs, totalSize, 0, totalSize/k);
free(chairs);
chairs = NULL;
system("pause");
}
void search(int n, int k, int* chairs, int totalSize, int low, int hi)
{
int mid = (low + hi)/2;
int tempPos = 0;
if (low >= hi - 1)
{
if (check(n, k, low, chairs, constructParasols(k,totalSize,low), k - 2, totalSize - (low * 2), totalSize) == 1)
{
printf("width %d is optimal\n", low);
}
else if (check(n, k, hi, chairs, constructParasols(k, totalSize, hi), k - 2, totalSize - (low * 2), totalSize) == 1)
{
printf("width%d is optimal\n", hi);
}
else
{
printf("no solution found\n");
}
}
else if (check(n, k, mid, chairs, constructParasols(k, totalSize, mid), k - 2, totalSize - (mid * 2), totalSize) == 1)
{
search(n, k, chairs, totalSize, low, mid-1);
}
else
{
search(n, k, chairs, totalSize, mid+1, hi);
}
}
int* constructParasols(int k, int totalSize, int width)
{
int* parasols = (int*)calloc(k + 1, sizeof(int));
int tempPos = 0;
for (int i = 0; i < k - 1; i++)
{
parasols[i] = tempPos;
tempPos += width;
}
parasols[k - 1] = totalSize - width;
return parasols;
}
int check(int n, int k, int width, int* chairs, int* parasols, int pNum, int maxPos, int totalSize)
{
int* cover = (int*)calloc(totalSize + 1, sizeof(int));
int failed = 0;
for (int i = 0; i < totalSize; i++)
{
cover[i] = 0;
}
if (k<=2)
{
draw(n, k, width, chairs, parasols, totalSize);
for (int i = 0; i < width; i++)
{
cover[i] = 1;
if(k==2) cover[parasols[1] + i] = 1;
}
for (int i = 0; i < n; i++)
{
if (cover[chairs[i] - 1] == 0)
{
failed = 1;
}
}
if (failed == 0)
{
free(cover);
cover = NULL;
free(parasols);
parasols = NULL;
return 1;
}
else
{
free(cover);
cover = NULL;
free(parasols);
parasols = NULL;
return 0;
}
}
draw(n, k, width, chairs, parasols, totalSize);
for (int i = 0; i < k; i++)
{
for (int j = 0; j < width; j++)
{
cover[parasols[i] + j] = 1;
}
}
for (int i = 0; i < n; i++)
{
if (cover[chairs[i]-1] == 0)
{
failed = 1;
}
}
if (failed == 0)
{
free(cover);
cover = NULL;
free(parasols);
parasols = NULL;
return 1;
}
if (pNum <= 1 && parasols[pNum] == maxPos)
{
free(cover);
cover = NULL;
free(parasols);
parasols = NULL;
return 0;
}
else if (parasols[pNum] == maxPos)
{
free(cover);
cover = NULL;
return check(n, k, width, chairs, parasols, pNum - 1, maxPos - width, totalSize);
}
else
{
free(cover);
cover = NULL;
parasols[pNum]++;
return check(n, k, width, chairs, parasols, pNum, maxPos, totalSize);
}
}
void draw(int n, int k, int width, int* chairs, int* parasols, int totalSize)
{
int* dCover = (int*)calloc(totalSize, sizeof(int));
int* chairPos = (int*)calloc(totalSize, sizeof(int));
for (int i = 0; i < totalSize; i++)
{
dCover[i] = 0;
chairPos[i] = 0;
}
for (int i = 0; i < k; i++)
{
for (int j = 0; j < width; j++)
{
if (dCover[parasols[i] + j] >= 1) dCover[parasols[i] + j] = 2;
else dCover[parasols[i] + j] = 1;
}
}
for (int i = 0; i < n; i++)
{
chairPos[chairs[i]-1] = 1;
}
for (int i = 0; i <= totalSize; i++)
{
if (dCover[i] == 2)
{
printf("=");
}
else if (dCover[i] == 1)
{
printf("-");
}
else
{
printf(" ");
}
}
printf("\n");
for (int i = 0; i <= totalSize; i++)
{
if (chairPos[i] == 1)
{
printf("|");
}
else
{
printf(" ");
}
}
printf("\n");
free(dCover);
dCover = NULL;
free(chairPos);
chairPos = NULL;
return;
}
(removed some comments and debug prints for clarity and reduced size)
However, these were only two samples shown out of the ten he will attempt. I want to get them all correct because I'm a perfectionist about programming, and I noticed a blind spot in the way I check if the cover works. Right now, it'll take the second parasol from the right and drag it space by space and check each time. Once it touches the parasol to the right of it, it'll start on the next parasol to the left, and do this until just the leftmost is remaining and conclude that this configuration won't succeed.
This means that if I give a sample input, such as 8 4 1 3 6 9 12 15 17 20,
it'll fail to check the situation in which the parasols are a width of 4 and evenly spaced out. I set out to rectify this, by changing this:
else
{
free(cover);
cover = NULL;
parasols[pNum]++;
return check(n, k, width, chairs, parasols, pNum, maxPos, totalSize);
}
(which is where it tries to push the parasol to the left and try again) to this:
else
{
printf("freeing cover\n");
free(cover);
cover = NULL;
printf("iteration failed\n");
//parasols[pNum]++;
//return check(n, k, width, chairs, parasols, pNum, maxPos, totalSize);
if (parasols[pNum] != parasols[pNum - 1] + width && check(n, k, width, chairs, parasols, pNum - 1, parasols[pNum]-width, totalSize) == 1)
{
return 1;
}
else
{
parasols[pNum]++;
return check(n, k, width, chairs, parasols, pNum, maxPos, totalSize);
}
}
Seemed to make sense. Only when I run it now, I get a read access violation. Right here:
else dCover[parasols[i] + j] = 1;
dCover. Under the draw command.
It'll grab the parasol and move it to the right, check it, then grab the parasol to the left of that and move it to the right. Just as I expected. It's only after
that in which it throws the exception.
If I revert the code, everything works perfectly. I have no idea how that relates to this - they're two different pointers entirely. I'm using Visual Studio 2017 to build this, if that makes a difference. Can someone help me out?
When you free already freed pointer you get this kind of crush.
You free parasols in check and continue to use it without reconstruct it.
in this part of your code:
if (parasols[pNum] != parasols[pNum - 1] + width && check(n, k, width, chairs, parasols, pNum - 1, parasols[pNum]-width, totalSize) == 1)
{
return 1;
}
else
{
parasols[pNum]++;
return check(n, k, width, chairs, parasols, pNum, maxPos, totalSize);
}
check was failed you free(parasols) and returned 0, so you get into the else and used it again in parasols[pNum]++ and also in the return check(... without reconstruct the parasols.
The program crash in the second free but may crush also when accesing the freed pointer.

Can't figure out why Heap Sort isn't working with a max heap

I've been scratching my head for the past couple of hours because I can't get my heapSort algorithm to work. My build Max-Heap and max-heapify outputs the correct code, and then I follow the HeapSort algorithm in Cormen's Intro to Algorithms, where you start from
for(i = A.length and go down to 2)
then exchange A[1] with A[i]
decrease heap size
call Max-Heapify(A,1)
I start with the array elements[3,4,1,2,7] and build the max heap to be [7, 4, 1, 2, 3], but when I do the sort I get: [1,1,1,2,3].
#include <stdio.h>
#include <math.h>
struct heap {
int size;
int *heaparr;
};
int *heap, size; //*heap makes a pointer to the struct
static void build_max_heap(struct heap *p)
{
int arr[5] = {0};
arr[0] = 3;
arr[1] = 4;
arr[2] = 1;
arr[3] = 2;
arr[4] = 7;
int count = 0;
p->heaparr = (int *) malloc(sizeof(int) * 5);
for (int i = 0; i < 5; i++)
{
p->heaparr[i] = arr[i];
//printf("number of each element: %d ", arr[i]);
count++; //count is equal to 10 elements
}
p->size = count-1; //size of heap is 9
printf("size is : %d", p->size);
for (int b = floor(p->size/2-1); b >= 0; b--)
{
max_heapify(p->heaparr, b, p->size);
printf("pass");
}
//printf("%d", p->size/2); //prints 10;
}
void max_heapify(int *data, int loc, int count) {
int left, right, largest, temp;
left = 2*(loc)+1; //2 (i which is 0) + 1
printf("your location: %d, your count: %d \n", loc, count);
right = left + 1; //right child
largest = loc;
printf("parent is: %d, left is: %d, right is: %d \n", data[loc],
data[left], data[right]);
// if given array of 10 so count = 10, left is 2*5 since we get floor
of
(p->size/2).
if (left <= count && data[left] > data[largest]) { //count is how many
elements in heap
largest = left; //update largest for location
printf("here left child %d is greater than parent %d \n",
data[left], data[loc]);
}
if (right <= count && data[right] > data[largest]) {
printf("here right child (%d) is greater than parent (%d): \n",
data[right], data[largest]);
largest = right; //update largest for recursion
}
if(largest != loc) { //original location
temp = data[loc]; // holds the value of the original location
data[loc] = data[largest]; //array location now equals
data[largest]
data[largest] = temp; //data[largest] (left or right child) = value
of original location
max_heapify(data, largest, count); //perculate through.
}
}
void heap_display(struct heap *h) {
int i;
int count = h->size+ 1;
for(i=0; i<h->size+1; ++i) {
printf("|%d|", h->heaparr[i]);
}
printf("\n");
printf("intial display is done");
for (int b = h->size ; b >= 1; b--)
{
h->heaparr[0]= h->heaparr[b];
h->size--;
max_heapify(h->heaparr, 0, h->size);
}
printf("\n");
h->size = 5;
for(i=0; i<h->size; ++i) {
printf("|%d|", h->heaparr[i]);
}
//printf("\n"); */
}
void heap_sort(struct heap *p)
{
build_max_heap(&p);
//printf("size: %d ", p->size);
/* for (int i = p->size + 1; i >= 2; i--)
{
printf("fault");
p->heaparr[0] = p->heaparr[i];
count--;
max_heapify(p->heaparr, 0, count);
} */
heap_display(&p);
}
void main()
{
int count, i, no;
struct heap h;
heap_sort(&h);
//int arr[10] = {4, 1,3, 2, 16, 9, 10, 14, 8, 7};
//heap_sort(&h, arr);
//heap_display(&h);
//build_max_heap(arr);
}
I think the problem is with this loop in your display_heap function:
for (int b = h->size ; b >= 1; b--)
{
h->heaparr[0]= h->heaparr[b];
h->size--;
max_heapify(h->heaparr, 0, h->size);
}
What you want is this:
while size > 1
swap the root item (0) with the last item in the heap
max_heapify(0)
decrease size
It looks like you're missing the swap step. Instead, you're just replacing the root item.
The fix is easy enough:
for (int b = h->size ; b >= 1; b--)
{
int temp = h->heaparr[0];
h->heaparr[0]= h->heaparr[b];
h->heaparr[b]= temp;
h->size--;
max_heapify(h->heaparr, 0, h->size);
}

Use MPI_Sendrecv for Conway Game of Life but the program can't exchange data in the borders

I'm trying to write a code of Conway's Game of Life, the pattern is Rabbit. And I used the Cartesian 2D method to build a processes group, the communication between them is MPI_Sendrecv. But this code didn't work, it just hanging there without any respond when I ran it. It has taken me a long time to find the problem but I got no progress. Could you please help me to figure it out? I'll be so glad for that!
#include <stdio.h>
#include "mpi.h"
#include <math.h>
#include <stdlib.h>
#define array 20
#define arrayhalf (array/2)
main(int argc, char *argv[])
{
int ndims = 2, ierr;
int p, my_rank, my_cart_rank;
MPI_Comm comm2d;
MPI_Datatype newtype;
int dims[ndims], coord[ndims];
int wrap_around[ndims];
int reorder, nrows, ncols;
int x[arrayhalf+2][arrayhalf+2], x2[arrayhalf+2][arrayhalf+2], x_rev[array+4][array+4];
int left, right, down, top;
MPI_Status status;
int tag_up = 20, tag_down =21, tag_left = 22, tag_right = 23;
long start, stop;
/*** start up initial MPI environment ***/
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
/* hardcore 2 processes in each dimension */
nrows = ncols = (int) sqrt(p);
dims[0] = dims[1] = 2;
/* create cartesian topology for processes */
MPI_Dims_create(p, ndims, dims);
/*if (my_rank == 0)
printf("PW[%d]/[%d%]: PEdims = [%d x %d] \n", my_rank, p, dims[0], dims[1]);*/
/* create cartesian mapping, and check it is created either correct or wrong */
wrap_around[0] = wrap_around[1] = 1; /*set periodicity to be true */
reorder = 0;
ierr = 0;
ierr = MPI_Cart_create(MPI_COMM_WORLD, ndims, dims, wrap_around, reorder, &comm2d);
if (ierr != 0)
printf("ERROR[%d] creating CART\n", ierr);
MPI_Type_vector( arrayhalf, 1, arrayhalf+2, MPI_INT, &newtype);
MPI_Type_commit( &newtype );
/* get the neighbour process, which is useful for hola exchange */
int SHIFT_ROW = 0;
int SHIFT_COL = 1;
int DISP = 1;
/*** load pattern ***/
/* initialize the data array */
int i, j ;
for (i = 0; i < arrayhalf + 2 ; i++)
for (j = 0; j < arrayhalf + 2; j++)
{
x[i][j] = 0;
x2[i][j] = 0;
}
if (my_rank == 0)
{
int r,c;
r = arrayhalf / 2;
c = arrayhalf / 2;
/* rabbits pattern
1 1 1 1
1 1 1 1
1
*/
x[r][c] = 1;
x[r][c+4] = 1;
x[r][c+5] = 1;
x[r][c+6] = 1;
x[r+1][c] = 1;
x[r+1][c+1] = 1;
x[r+1][c+2] = 1;
x[r+1][c+5] = 1;
x[r+2][c+1] = 1;
}
/*** calculate the next generation ***/
int row, col;
int steps;
steps = atoi(argv[1]); /* get the generation number from command line */
start = MPI_Wtime();
int soc;
int destination;
for (i = 1; i <= steps; i++)
{
/*** use hola exchange in boundary elements ***/
int * send_buffer = (int*) malloc((arrayhalf)*sizeof(int));
int * recv_buffer = (int*) malloc((arrayhalf)*sizeof(int));
/*int * send_buffer = (int *) calloc(arrayhalf,sizeof(int));
int * recv_buffer = (int *) calloc(arrayhalf,sizeof(int));
*/
/* to up */
MPI_Cart_shift(comm2d, 1, 1, &soc,&destination);
MPI_Sendrecv( &x[1][1], arrayhalf, MPI_INT, destination, tag_up,& x[arrayhalf + 1][1], arrayhalf, MPI_INT, soc, tag_up, comm2d, &status );
/* to down */
MPI_Cart_shift(comm2d, 1, 1, &destination,&soc);
MPI_Sendrecv( &x[arrayhalf][1], arrayhalf, MPI_INT, destination, tag_down,& x[0][1], arrayhalf, MPI_INT, soc, tag_down, comm2d, &status);
/* to left */
MPI_Cart_shift(comm2d, 0, 1, &destination,&soc);
MPI_Sendrecv( &x[1][1], 1,newtype, destination, tag_left,& x[1][arrayhalf+1], 1, newtype, soc, tag_left, comm2d, &status );
/*for (j=0;j<arrayhalf;j++) {
send_buffer[j]=x[j+1][1];
}
MPI_Sendrecv( send_buffer, arrayhalf,MPI_INT, destination, tag_left,recv_buffer, arrayhalf, MPI_INT, soc, tag_left, comm2d, &status );
for (j=0;j<arrayhalf;j++) {
x[j+1][arrayhalf+1]=recv_buffer[j];
}
*/
/* to right */
MPI_Cart_shift(comm2d, 0, 1, &soc,&destination);
MPI_Sendrecv( &x[1][arrayhalf], 1, newtype, destination, tag_right, &x[1][0], 1, newtype, soc, tag_right, comm2d, &status );
/*for (j=0;j<arrayhalf;j++) {
send_buffer[j]=x[j+1][arrayhalf];
}
MPI_Sendrecv( send_buffer, arrayhalf,MPI_INT, destination, tag_right,recv_buffer, arrayhalf, MPI_INT, soc, tag_right, comm2d, &status );
for (j=0;j<arrayhalf;j++) {
x[j+1][1]=recv_buffer[j];
}
*/
/*** sum the neighbour values and get the next generation ***/
for (row = 1; row < arrayhalf; row++)
{
for (col = 1; col < arrayhalf; col++)
{
int neighbor;
neighbor = x[row - 1][col - 1] + x[row - 1][col] + x[row - 1][col + 1] + x[row][col - 1] +
x[row][col + 1] +
x[row + 1][col - 1] + x[row + 1][col] + x[row + 1][col + 1];
if (neighbor == 3)
{
x2[row][col] = 1;
}
else if (x[row][col] == 1 && neighbor == 2)
{
x2[row][col] = 1;
}
else
{
x2[row][col] = 0;
}
}
}
/* used to be swap */
for (row = 1; row < arrayhalf; row++)
{
for (col = 1; col < arrayhalf; col++)
{
x[row][col] = x2[row][col];
}
}
free(send_buffer);
free(recv_buffer);
}
/*** print the final generation ***/
int population = 0;
int* A;
int process_num = dims[0]*dims[1];
int row_indx;
int col_indx;
int k;
if(my_rank == 0)
{
A = (int*) malloc((arrayhalf+2)*(arrayhalf+2)*sizeof(int));
for (k= 1; k< process_num; k++)
{
MPI_Recv(A,(arrayhalf+2)*(arrayhalf+2), MPI_INT,k, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
for (i = 0; i<arrayhalf+2; i++)
{
for (j = 0; j<arrayhalf+2; j++)
{
row_indx = (k%dims[1])*(arrayhalf+2)+i;
col_indx = (k/dims[0]*(arrayhalf+2))+j;
x_rev[row_indx][col_indx] = A[i*(arrayhalf+2)+j];
}
}
}
for (i = 0; i<arrayhalf+2; i++)
{
for (j = 0; j<arrayhalf+2; j++)
{
x_rev[i][j] = x[i][j];
}
}
for (row = 0; row < array+4; row++) {
for (col = 0; col < array+4; col++)
{
printf("%2d",x_rev[row][col]);
if(x_rev[row][col]==1)
{
population = population + 1;
}
}
printf("\n");
}
stop = MPI_Wtime();
printf("Running Time: %f\n ",stop-start);
printf("Population: %d\n",population);
printf("Generation: %d\n",steps);
}
else{
A = (int*) malloc((array+4)*(array+4)*sizeof(int));
for (i=0; i< arrayhalf +2; i++)
{
for(j = 0; j<arrayhalf+2; j++)
{
A[i*(arrayhalf+2)+j] = x[i][j];
}
}
MPI_Send(A,(arrayhalf+2)*(arrayhalf+2),MPI_INT,0,0,MPI_COMM_WORLD);
}
MPI_Comm_free( &comm2d );
MPI_Type_free( &newtype );
free(A);
MPI_Finalize();
}
I think I found the error.
It is in line 176.
Rank 0 is trying to listen to a msg from rank 0, but rank 0 is not sending a msg to itself. You should start the loop from 1 and not 0.

Resources