#include <stdio.h> /* Include stdio lib */
#include <math.h>  /* Include math lib */
#include "../include/pvm3.h" /* Include pvm3 lib */

#define PROC 10 /* The number of slave processes */

float addup(float data[100], int part); /* Finds the sum of the elements
                                           of data[] */
/* Finds the sum of the squared differences between the elements of data[]
   and the mean */
float sq_diff(float data[100], float mean, int part);

main() {
    int mytid; /* Holds this process' tid */
    int me, i, msgtype; /* me holds this process' id number, i is a
                           counter, msgtype is used to verify messages
                           sent between this process and the master */
    int master; /* Holds the master process' tid */
    int part; /* Holds the size of the partition received from master */
    float data[100], mean; /* data[] holds the data received from the
                              master, while mean is the average of all
                              of the data in the program */
    float sum1 = 0, sum2 = 0; /* sum1 holds the sum of all the elements
                                 in data[], while sum2 holds the sum of
                                 the squared differences */
    int tids[PROC]; /* Holds the slave processes' tids */

    mytid = pvm_mytid(); /* Find this process' tid and enroll in PVM */
    master = pvm_parent(); /* Find the master's tid */

    /* Receive the data from the master */
    msgtype = 0;
    pvm_recv(-1, msgtype);
    pvm_upkint(tids, PROC, 1);
    pvm_upkint(&part, 1, 1);
    for(i = 0; i < part; i++) pvm_upkfloat(&data[i], 1, 1);

    /* Find this process' id */
    for(i = 0; i < PROC; i++)
        if(mytid == tids[i]) me = i;

    /* Find the sum of the elements of data[] and store it in sum1 */
    sum1 = addup(data, part);

    /* Send sum1 to the master */
    msgtype = 1;
    pvm_initsend(PvmDataDefault);
    pvm_pkint(&me, 1, 1);
    pvm_pkfloat(&sum1, 1, 1);
    pvm_send(master, msgtype);

    /* Receive the mean from the master */
    msgtype = 2;
    pvm_recv(-1, msgtype);
    pvm_upkfloat(&mean, 1, 1);

    /* Find the sum of the squared differences between the elements of
       data[] and the mean and store it in sum2 */ 
    sum2 = sq_diff(data, mean, part);

    /* Send sum2 to the master */
    msgtype = 3;
    pvm_initsend(PvmDataDefault);
    pvm_pkint(&me, 1, 1);
    pvm_pkfloat(&sum2, 1, 1);
    pvm_send(master, msgtype);

    /* Exit the program */
    pvm_exit();
    return;
}

float addup(float data[100], int part) {
    int i; /* Counter */
    float sum = 0; /* Holds the sum of the elements of data[] */

    for(i = 0; i < part; i++) sum += data[i]; /* Add the elements of the
                                                 partition to sum */

    return sum; /* Return the sum */
}

float sq_diff(float data[100], float mean, int part) {
    int i; /* Counter */
    float sum; /* Holds the sum of the squared differences */

    /* Add the squared differences between the elements of data[] and the
       mean to sum */
    for(i = 0; i < part; i++)
        sum += (data[i]-mean) * (data[i]-mean);

    return sum; /* Return the sum of the squared differences */
}

