/**
* Lena Lopez
* CS 442, Homework 2, Exercise 1
*
* Idea:
* First, I impose a binary tree hierarchy containing all of the processes in rank order.  Thus,
* in the hierarchy, Process 0 is always the root node, Process 1 is always Process 0's left child,
* Process 2 is always Process 0's right child, Process 3 is always Process 1's left child, etc.
* Binary addition is performed on the leaves and propagate up the tree until the accumulating sum
* reaches Process 0.  Finally, Process 0 sends this sum to the specified root node to return.
*/

#include <mpi.h>
#include <stdio.h>

int gsum(int summand, int root, MPI_Comm comm)
{
   int my_rank, nproc;
   int tag, left, right, parent, sum;
   MPI_Status status;
   MPI_Request request;
   
   MPI_Comm_size(comm, &nproc);
   MPI_Comm_rank(comm, &my_rank);

   /* Check if the specified root exists */
   if((root < 0) || (root >= nproc))
   {
      printf("ERROR: Invalid root!");
      MPI_Abort(comm, -1);
   }

   /* Initialize some variables */
   tag = 0;
   left = (my_rank * 2) + 1;
   right = (my_rank * 2) + 2;
   parent = (my_rank-1) / 2;
   sum = summand;
   
   /* If left child exists, wait to receive from them */
   if(left < nproc)
   {
      MPI_Recv(&summand, 1, MPI_INT, left, tag, comm, &status);
      sum += summand;
      /* If right child exists, wait to receive from them */
      if(right < nproc)
      {
         MPI_Recv(&summand, 1, MPI_INT, right, tag, comm, &status);
         sum += summand;
      }
   }
   summand = sum;
   sum = 0;

   /* Reached the root of the tree, but need to send it to the real root of the system */
   if(my_rank == 0)
   {
      MPI_Isend(&summand, 1, MPI_INT, root, tag, comm, &request);
   }
   /* Send the sum so far to my parent */
   else
   {
      MPI_Send(&summand, 1, MPI_INT, parent, tag, comm);
   }
   /* Return the sum on the root */
   if(my_rank == root)
   {
      MPI_Recv(&summand, 1, MPI_INT, 0, tag, comm, &status);
      sum = summand;
   }

   return sum;
}
