// **************************************************************************** // Calculates the inverse of N x N matrix A and stores it in matrix Ainv. // It is assumed that the memory required for this has already been allocated. // The data in matrix A is not destroyed, unless the same address is supplied for Ainv. // (This case should be successfully handled also.) // The function returns -1 if the matrix is not invertible. // **************************************************************************** int matrix_invert(double *A, double *Ainv, long int N) { double *backup = malloc_1d_array_double(N*N); double pivot, factor; long int pivot_row; if (A==NULL || Ainv==NULL || N<1) quit_error((char*)"Bad input data to matrix_invert"); // Backup the A matrix so that manipulations can be performed here // without damaging the original matrix. for (long int row=0; row<N; row++) for (long int col=0; col<N; col++) backup[row*N+col]=A[row*N+col]; // First, fill Ainv with the identity matrix for (long int row=0; row<N; row++) { for (long int col=0; col<N; col++) { if (row==col) Ainv[row*N+col]=1; else Ainv[row*N+col]=0; } } // Calculate the inverse using Gauss-Jordan elimination for (long int col=0; col<N; col++) { //display_augmented(backup, Ainv, N); pivot_row=-1; pivot=0.0; for (long int row=col; row<N; row++) { if (fabs(backup[row*N+col])>fabs(pivot)) { pivot_row=row; pivot=backup[row*N+col]; } } //printf("Pivot: %lf\n\n", pivot); if (pivot_row<0 || pivot_row>=N || fabs(pivot)<DBL_EPSILON) { free_1d_array_double(backup); return -1; } else { swap_row(col, pivot_row, backup, Ainv, N); multiply_row(col, 1.0/pivot, backup, Ainv, N); for (long int elim_row=0; elim_row<N; elim_row++) { if (elim_row!=col) { factor=-backup[elim_row*N+col]; add_multiple_row(factor, col, elim_row, backup, Ainv, N); } } } } free_1d_array_double(backup); return 0; }
int main(int argc, char *argv[]){ int i, j, k, rows_index, last_rows_index, sum = 0; int **first, **second; int **result; int *row_first, *row_result = NULL; int size; int rank, n_process, n_process_working; int rows_per_process, remaining_rows; MPI_Status status; int no_need = 0; srand(time(NULL)); /* Start up MPI */ MPI_Init(&argc, &argv); /* Get some info about MPI */ MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &n_process); if(argc!=NUM_ARG){ if(rank == RANK_MASTER) printf("USAGE:\n %s <n_size>\n", argv[0]); MPI_Finalize(); return -1; } if((size =atoi(argv[1]))<=0){ if(rank == RANK_MASTER) printf("(ERROR\t) Invalid size\n"); MPI_Finalize(); return -1; } if (rank == RANK_MASTER) { /* Allocation and setting of the matrices */ first = (int **)malloc(sizeof(int)*size); second = (int **)malloc(sizeof(int)*size); result = (int **)malloc(sizeof(int)*size); for(i=0;i<size;i++){ first[i]= (int *)malloc(sizeof(int)*size); second[i] = (int *)malloc(sizeof(int)*size); result[i] = (int *)malloc(sizeof(int)*size); } /* Setting the contents of the matrices and broadcast of the second matrix */ for(i=0;i<size;i++){ for(j=0;j<size;j++){ first[i][j]=aleat_num(0,size); second[i][j]=aleat_num(0,size); result[i][j]=aleat_num(0,size); } MPI_Bcast(&(second[i][0]), size, MPI_INT, RANK_MASTER, MPI_COMM_WORLD); } /* Send to each slave (rank-1)*(size/n_process)+1 to i*(size/n_process) * rows of the first column */ if (size < (n_process-1)) { rows_per_process = 1; remaining_rows = 0; n_process_working = size; } else { rows_per_process = size / (n_process-1); remaining_rows = size % (n_process-1); n_process_working = n_process-1; } printf(" %s ROWS PER PROCESS = %d\n",LABEL_MASTER, rows_per_process); printf(" %s REMAINING ROWS = %d\n",LABEL_MASTER, remaining_rows); printf(" %s PROCESSES WORKING = %d\n",LABEL_MASTER, n_process_working); for (i = 1; i <= n_process_working; i++) { for (rows_index = (i-1)*(rows_per_process); rows_index < i*rows_per_process ;rows_index++){ MPI_Send(&(first[rows_index][0]),size,MPI_INT,i,TAG_ROWS,MPI_COMM_WORLD); printf(" %s SENT ROW [%d] to processor %d\n",LABEL_MASTER, rows_index, i); } } /* If there are remaining rows (never more than N-1), master sends to each * processos like a Round Robin */ last_rows_index = rows_index; /* The first remaining row to send */ for (i = 1; i <= remaining_rows ; i++, last_rows_index++){ MPI_Send(&(first[last_rows_index][0]),size,MPI_INT,i,TAG_REMAINING_ROWS,MPI_COMM_WORLD); printf(" %s SENT REMAINING ROW [%d] to processor %d\n",LABEL_MASTER, last_rows_index, i); } /* Receives result */ for (i = 1; i <= n_process_working; i++) { for (rows_index = (i-1)*(rows_per_process); rows_index < i*rows_per_process ;rows_index++){ MPI_Recv(&(result[rows_index][0]),size,MPI_INT,i,TAG_RESULT,MPI_COMM_WORLD,&status); } } /* Receives remaining rows of the result */ last_rows_index = rows_index; /* The first remaining row to receive */ for (i = 1; i <= remaining_rows ; i++, last_rows_index++){ MPI_Recv(&(result[last_rows_index][0]),size,MPI_INT,i,TAG_RESULT,MPI_COMM_WORLD,&status); } printf(" %s RESULTS\n", LABEL_MASTER); /* PRINT */ for(i=0;i<size;i++){ printf("\t"); for(j=0;j<size;j++){ printf("%d ",first[i][j]); } printf("x "); for(j=0;j<size;j++){ printf("%d ",second[i][j]); } printf("= "); for(j=0;j<size;j++){ printf("%d ",result[i][j]); } printf("\n"); } free(first); free(second); free(result); MPI_Barrier(MPI_COMM_WORLD); } else { /* Cannot scatter the workload between a high number of processors with a matrix * size relative small */ if (rank-1 >= size) { printf(" # %s %d # NOT NECESSARY\n",LABEL_SLAVE, rank); no_need = 1; MPI_Barrier(MPI_COMM_WORLD); } if (no_need != 1){ /* Receives the second matrix */ second = (int **)malloc(sizeof(int)*size); for (i = 0; i < size; i++) { second[i] = (int *)malloc(sizeof(int)*size); MPI_Bcast(&(second[i][0]), size, MPI_INT, RANK_MASTER, MPI_COMM_WORLD); } /* Each slave receives (rank-1)*(size/n_process)+1 to i*(size/n_process) * rows of the first matrix to calculate that many rows of the product matrix */ row_first = (int *)malloc(sizeof(int)*size); result = (int **)malloc(sizeof(int)*size); rows_per_process = (size < (n_process-1)) ? 1 : (size / (n_process-1)); for (rows_index = 0; rows_index < rows_per_process ;rows_index++){ MPI_Recv(row_first,size,MPI_INT,RANK_MASTER,TAG_ROWS,MPI_COMM_WORLD,&status); /* Calculation of the result row */ result[rows_index] = (int *)malloc(sizeof(int)*size); multiply_row(result[rows_index], row_first, second, size); MPI_Send(&(result[rows_index][0]),size,MPI_INT,RANK_MASTER,TAG_RESULT,MPI_COMM_WORLD); } /* If there are remaining rows to finish (never more than N-1) each slave * calculates the remaining row according to their rank */ remaining_rows = (size < (n_process-1)) ? 0 : size % (n_process-1); last_rows_index = rows_index; /* This is the corresponding index of the remaining row */ /* Only the first processes ought to deal with the remaining rows */ if ((remaining_rows >= rank) && (remaining_rows != 0)) { MPI_Recv(row_first,size,MPI_INT,RANK_MASTER,TAG_REMAINING_ROWS,MPI_COMM_WORLD,&status); result[last_rows_index] = (int *)malloc(sizeof(int)*size); multiply_row(result[last_rows_index], row_first, second, size); MPI_Send(&(result[last_rows_index][0]),size,MPI_INT,RANK_MASTER,TAG_RESULT,MPI_COMM_WORLD); } free(second); free(row_first); free(result); MPI_Barrier(MPI_COMM_WORLD); } } /* All done */ MPI_Finalize(); return 0; }