PTL logo

From: Hanissalwan Mobidin (hanis9136.10_at_[hidden])
Date: 2014-06-04 04:07:45


Hello,
I am student from Malaysia that currently studying Parallel Computing
subject. I got problem to code for the collective MPI. My program
requirement is as follows:

   1. Generate a random array of numbers on the root process (process 0).
   2. Scatter the numbers to all processes, giving each process an equal
   amount of numbers.
   3. Each process computes the average of their subset of the numbers.
   4. Gather all averages to the root process. The root process then
   computes the average of these numbers to get the final average.

I manage to found the code for the program but it run using c/c++ as below:

// Author: Wes Kendall
// Copyright 2012 www.mpitutorial.com
// This code is provided freely with the tutorials on mpitutorial.com. Feel
// free to modify it for your own use. Any distribution of the code must
// either provide a link to www.mpitutorial.com or keep this header in tact.
//
// Program that computes the average of an array of elements in parallel
using
// MPI_Scatter and MPI_Gather
//
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <assert.h>

// Creates an array of random numbers. Each number has a value from 0 - 1
float *create_rand_nums(int num_elements) {
  float *rand_nums = (float *)malloc(sizeof(float) * num_elements);
  assert(rand_nums != NULL);
  int i;
  for (i = 0; i < num_elements; i++) {
    rand_nums[i] = (rand() / (float)RAND_MAX);
  }
  return rand_nums;
}

// Computes the average of an array of numbers
float compute_avg(float *array, int num_elements) {
  float sum = 0.f;
  int i;
  for (i = 0; i < num_elements; i++) {
    sum += array[i];
  }
  return sum / num_elements;
}

int main(int argc, char** argv) {
  if (argc != 2) {
    fprintf(stderr, "Usage: avg num_elements_per_proc\n");
    exit(1);
  }

  int num_elements_per_proc = atoi(argv[1]);
  // Seed the random number generator to get different results each time
  srand(time(NULL));

  MPI_Init(NULL, NULL);

  int world_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
  int world_size;
  MPI_Comm_size(MPI_COMM_WORLD, &world_size);

  // Create a random array of elements on the root process. Its total
  // size will be the number of elements per process times the number
  // of processes
  float *rand_nums = NULL;
  if (world_rank == 0) {
    rand_nums = create_rand_nums(num_elements_per_proc * world_size);
  }

  // For each process, create a buffer that will hold a subset of the entire
  // array
  float *sub_rand_nums = (float *)malloc(sizeof(float) *
num_elements_per_proc);
  assert(sub_rand_nums != NULL);

  // Scatter the random numbers from the root process to all processes in
  // the MPI world
  MPI_Scatter(rand_nums, num_elements_per_proc, MPI_FLOAT, sub_rand_nums,
              num_elements_per_proc, MPI_FLOAT, 0, MPI_COMM_WORLD);

  // Compute the average of your subset
  float sub_avg = compute_avg(sub_rand_nums, num_elements_per_proc);

  // Gather all partial averages down to the root process
  float *sub_avgs = NULL;
  if (world_rank == 0) {
    sub_avgs = (float *)malloc(sizeof(float) * world_size);
    assert(sub_avgs != NULL);
  }
  MPI_Gather(&sub_avg, 1, MPI_FLOAT, sub_avgs, 1, MPI_FLOAT, 0,
MPI_COMM_WORLD);

  // Now that we have all of the partial averages on the root, compute the
  // total average of all numbers. Since we are assuming each process
computed
  // an average across an equal amount of elements, this computation will
  // produce the correct answer.
  if (world_rank == 0) {
    float avg = compute_avg(sub_avgs, world_size);
    printf("Avg of all elements is %f\n", avg);
    // Compute the average across the original data for comparison
    float original_data_avg =
      compute_avg(rand_nums, num_elements_per_proc * world_size);
    printf("Avg computed across original data is %f\n", original_data_avg);
  }

  // Clean up
  if (world_rank == 0) {
    free(rand_nums);
    free(sub_avgs);
  }
  free(sub_rand_nums);

  MPI_Barrier(MPI_COMM_WORLD);
  MPI_Finalize();
}

I want to code the program sing c#. But i don't really understand to use
the method in c#. I manage to code in point-to-point communication, but it
does not fit with the requirement to code using collective communication.
My code for the point-to-point is as follows:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MPI;

    class Program
    {
        static void Main(string[] args)
        {

            using (new MPI.Environment(ref args))
            {
                Intracommunicator comm = MPI.Communicator.world;
                if (comm.Size < 4)
                {
                    Console.WriteLine("At least 4 processes needed");
                    return;
                }
                ArrayList tempArray = new ArrayList();

                int num = 0;
                //Distribute Array
                Random rnd = new Random();
                if (comm.Rank == 0)//Master or root process
                {
                    //initiliaze array
                    System.Console.WriteLine("INITIAL LIST: ");

                    for (int i = 0; i < 30; i++)
                    {
                        num = rnd.Next(1, 200);
                        tempArray.Add(num);
                        System.Console.Write(tempArray[i] + " ");
                    }
                    System.Console.WriteLine();

                    int split_size = tempArray.Count / 3;
                    System.Console.WriteLine("Splitsize: " + split_size);

                    int[] array1 = new int[split_size];
                    int[] array2 = new int[split_size];
                    int[] array3 = new int[split_size];

                    //copy tempArray to array1 (startIndex tempArray,
array1, startIndex array1, how many element from tempArray to be copied)
                    tempArray.CopyTo(0, array1, 0, split_size);
                    PrintValues(array1, ' ');

                    //copy tempArray to array2 (startIndex tempArray,
array3, startIndex array2, how many element from tempArray to be copied)
                    tempArray.CopyTo(split_size, array2, 0, split_size);
                    PrintValues(array2, ' ');

                    //copy tempArray to array3 (startIndex tempArray,
array3, startIndex array3, how many element from tempArray to be copied)
                    tempArray.CopyTo(split_size * 2, array3, 0, split_size);
                    PrintValues(array3, ' ');

                    comm.Send(array1, 1, 99);
                    comm.Send(array2, 2, 98);
                    comm.Send(array3, 3, 97);

                    int[] result = new int[3];
                    int finalAve = 0;
                    int sumTotal = 0;
                    comm.Receive(1, 96, out result[0]);
                    comm.Receive(2, 95, out result[1]);
                    comm.Receive(3, 94, out result[2]);
                    System.Console.WriteLine("Receive Ave1 : " + result[0]);
                    System.Console.WriteLine("Receive Ave2 : " + result[1]);
                    System.Console.WriteLine("Receive Ave3 : " + result[2]);

                    for (int i = 0; i < result.Length; i++)
                    {
                        //if (finalAve < result[i])
                           // finalAve = result[i];
                        sumTotal += result[i];
                        finalAve = sumTotal /result.Length;
                    }
                    System.Console.WriteLine("The total sum of average is:
" + sumTotal);
                    System.Console.WriteLine("The average value is : " +
finalAve);
                }

                else
                    if (comm.Rank == 1)
                    {
                        int sum = 0;
                        int ave = 0;
                        int[] a = new int[30];
                        comm.Receive(0, 99, ref a);
                        for (int i = 0; i < a.Length; i++)
                        {

                            //if (max < a[i])
                                //max = a[i];
                            sum += a[i];
                            ave = sum / a.Length;

                        }
                        //System.Console.WriteLine("Sum for Process 1 : " +
sum);
                        System.Console.WriteLine("Ave for Process 1 : " +
ave);
                        comm.Send(ave, 0, 96);
                    }

                    else
                        if (comm.Rank == 2)
                        {
                            int sum = 0;
                            int ave = 0;
                            int[] b = new int[30];
                            comm.Receive(0, 98, ref b);
                            for (int i = 0; i < b.Length; i++)
                            {
                                //if (max < b[i])
                                    //max = b[i];
                                sum += b[i];
                                ave = sum / b.Length;

                            }
                           // System.Console.WriteLine("Sum for Process 2:
" + sum);
                            System.Console.WriteLine("Ave for Process 2 : "
+ ave);
                            comm.Send(ave, 0, 95);
                        }
                        else
                            if (comm.Rank == 3)
                            {
                                int sum = 0;
                                int ave = 0;
                                int[] c = new int[30];
                                comm.Receive(0, 97, ref c);
                                for (int i = 0; i < c.Length; i++)
                                {
                                    //if (max < c[i])
                                        //max = c[i];
                                    sum += c[i];
                                    ave = sum / c.Length;
                                }
                                //System.Console.WriteLine("Sum for Process
3: " + sum);
                                System.Console.WriteLine("Ave for Process
3: " + ave);
                                comm.Send(ave, 0, 94);
                            }

            }

        }
        public static void PrintValues(int[] myArr, char mySeparator)
        {
            for (int i = 0; i < myArr.Length; i++)
                Console.Write("{0}{1}", mySeparator, myArr[i]);
            Console.WriteLine();
        }

    }

I hope that someone can help me to code in collective communication. I run
my program using Microsoft Visual Studio 2010 Professional.

Thank you and Regards,
 Hanis Salwan Binti Mobidin