// ****************************************************************************
// 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;
}
Example #2
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;  
}