#include "Bdef.h"

/*
 *  Tree_bs/br is a algorithm that does a broadcast send/recv such that the
 *  communication pattern is a tree with an arbitrary number of branches.
 *  The following two pairs of graphs give different ways of viewing the same
 *  algorithm.  The first pair shows the trees as they should be visualized
 *  when examining the algorithm.  The second pair are isomorphic graphs of
 *  of the first, which show the actual pattern of data movement.

 *  Note that a tree broadcast with NBRANCHES = 2 is isomorphic with a
 *  hypercube broadcast (however, it does not require the nodes be a
 *  power of two to work).
 *
 *    TREE BROADCAST, NBRANCHES = 2     *    TREE BROADCAST, NBRANCHES = 3
 *                                      *
 * i=4   &______________                *
 *       |              \               *
 * i=2   &______         &______        * i=3     &______________________
 *       |      \        |      \       *         |          \           \
 * i=1   &__     &__     &__     &__    * i=1     &______     &______     &__
 *       |  \    |  \    |  \    |  \   *         |  \   \    |  \   \    |  \
 *       0   1   2   3   4   5   6   7  *         0   1   2   3   4   5   6   7
 *
 *
 *          ISOMORPHIC GRAPHS OF ABOVE, SHOWN IN MORE FAMILIAR TERMS:
 *
 *                0                                           0
 *       _________|_________                       ___________|____________
 *      /         |         \                     /           |      |     \
 *     4          2          1                   6            3      2      1
 *    / \         |                              |           / \
 *   6   5        3                              7          4   5
 *   |
 *   7
 */
int Stree_bs(ctxt, scope, nbranches)
BLACSCONTEXT  *ctxt;
char  scope;
int  nbranches;
{
   void Ssend2d00();

   int i, j;
   int destdist;	/* the distance of the destination node */
   int rdest, cdest;
   int Ng, nprow, npcol, myrow, mycol;
   int msgid;

   Mgridinfo(ctxt, Ng, nprow, npcol, myrow, mycol);
   scope = Mlowcase(scope);
   switch(scope)
   {
   case 'r':
      if (npcol < 2) return(NORV);
      msgid = Mrid(ctxt);
      for (i=nbranches; i<npcol; i*=nbranches);
      for (i /= nbranches; i > 0; i /= nbranches)
      {
         j = 1;
         do
	 {
	    destdist = i*j;
	    if (destdist < npcol)
               Ssend2d00(ctxt, myrow, (destdist+mycol)%npcol,
                         msgid);
         }
         while(++j < nbranches);
      }
      break;
   case 'c':
      if (nprow < 2) return(NORV);
      msgid = Mcid(ctxt);
      for (i=nbranches; i<nprow; i*=nbranches);
      for (i /= nbranches; i > 0; i /= nbranches)
      {
         j = 1;
         do
         {
            destdist = i*j;
            if (destdist < nprow)
               Ssend2d00(ctxt, (destdist+myrow)%nprow, mycol,
                         msgid);
         }
         while(++j < nbranches);
      }
      break;
   case 'a':
      if (Ng < 2) return(NORV);
      msgid = Maid(ctxt);
      for (i=nbranches; i<Ng; i*=nbranches);
      for (i /= nbranches; i > 0; i /= nbranches)
      {
         j = 1;
         do
         {
            destdist = i*j;
            if (destdist < Ng)
            {
               destdist = (destdist + ctxt->vIam) % Ng;
               Mvpcoord(ctxt, destdist, rdest, cdest);
               Ssend2d00(ctxt, rdest, cdest, msgid);
            }
         }
         while (++j < nbranches);
      }
      break;
   default:
      return(BADSCP);
   }
   return(0);
} /* end Stree_bs */
