!**********************************************************************
!     matmat.f - matrix - matrix multiply, simple self-scheduling version
!************************************************************************
      program main
      use mpi
!      include "mpif.h"

      integer MAX_AROWS, MAX_ACOLS, MAX_BCOLS 
      parameter (MAX_AROWS = 20, MAX_ACOLS = 1000, MAX_BCOLS = 20)
      double precision a(MAX_AROWS,MAX_ACOLS), b(MAX_ACOLS,MAX_BCOLS)
      double precision c(MAX_AROWS,MAX_BCOLS)
      double precision buffer(MAX_ACOLS), ans(MAX_ACOLS)

      integer myid, master, numprocs, ierr, status(MPI_STATUS_SIZE)
      integer i, j, numsent, sender
      integer anstype, row, arows, acols, brows, bcols, crows, ccols

      call MPI_INIT( ierr )
      call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr )
      call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr )
      print *, "Process ", myid, " of ", numprocs, " is alive"

      master = 0
      arows  = 10
      acols  = 100
      brows  = 100
      bcols  = 10
      crows  = arows
      ccols  = bcols

      if ( myid .eq. master ) then
!        master initializes and then dispatches
!        initialize a and b
         do 11 i = 1,acols
            do 10 j = 1,arows
               a(j,i) = i
 10         continue
 11      continue
         do 21 i = 1,bcols
            do 20 j = 1,brows
               b(j,i) = i
 20         continue
 21      continue

         numsent = 0
         
!        send b to each other process
         do 25 i = 1,bcols
         call MPI_BCAST(b(1,i), brows, MPI_DOUBLE_PRECISION, master, &
             MPI_COMM_WORLD, ierr)
 25      continue

!        send a row of a to each other process; tag with row number
         do 40 i = 1,numprocs-1
            do 30 j = 1,acols
               buffer(j) = a(i,j)
 30         continue
            call MPI_SEND(buffer, acols, MPI_DOUBLE_PRECISION, i, &
                i, MPI_COMM_WORLD, ierr)
            numsent = numsent+1
 40      continue
         
         do 70 i = 1,crows
            call MPI_RECV(ans, ccols, MPI_DOUBLE_PRECISION, &
                MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, status, &
                ierr)
            sender     = status(MPI_SOURCE)
            anstype    = status(MPI_TAG)
            do 45 j = 1,ccols
               c(anstype,j) = ans(j)
 45         continue

            if (numsent .lt. arows) then
               do 50 j = 1,acols
                  buffer(j) = a(numsent+1,j)
 50            continue
               call MPI_SEND(buffer, acols, MPI_DOUBLE_PRECISION, &
                   sender, numsent+1, MPI_COMM_WORLD, ierr)
               numsent = numsent+1
            else
               call MPI_SEND(1.0, 1, MPI_DOUBLE_PRECISION, sender, &
                   0, MPI_COMM_WORLD, ierr)
            endif
 70      continue
         
!        print out the answer
         do 80 i = 1,crows
            do 78 j = 1,ccols
               print *, "c(", i, ",", j, ") = ", c(i,j)
 78         continue
 80      continue

      else
!     slaves receive B, then compute rows of C until done message
      do 85 i = 1,bcols
         call MPI_BCAST(b(1,i), brows, MPI_DOUBLE_PRECISION, &
                        master, MPI_COMM_WORLD, ierr)
 85   continue
 90   call MPI_RECV(buffer, acols, MPI_DOUBLE_PRECISION, master, &
                    MPI_ANY_TAG, MPI_COMM_WORLD, status, ierr)
      if (status(MPI_TAG) .eq. 0) then
         go to 200
      else
         row = status(MPI_TAG)
         do 100 i = 1,bcols
            ans(i) = 0.0
            do 95 j = 1,acols
               ans(i) = ans(i) + buffer(j)*b(j,i)
 95         continue
 100     continue
         call MPI_SEND(ans, bcols, MPI_DOUBLE_PRECISION, master, &
                       row, MPI_COMM_WORLD, ierr)
         go to 90
      endif
 200  continue
      endif

      call MPI_FINALIZE(ierr)
      stop
      end




