#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pvm3.h"

#define MAX_SLAVES 120
#define NR_OF_INPUTS 100
#define NR_OF_LOOPS 100

main()
{
    int mytid;             /* my task id */
    int tids[MAX_SLAVES];  /* task ids   */
    int n, me, i, j, nproc, master, winner, xpos, ypos, z, l, f;
    float input[NR_OF_INPUTS], weights[MAX_SLAVES][NR_OF_INPUTS];
    float result, min;
    float prop[10000];

    mytid = pvm_mytid();    /* enroll in pvm */

    /* initialise my weights to low random values */   
    srand(mytid);
    for(i=0; i<MAX_SLAVES; i++)
       for(j=0; j<NR_OF_INPUTS; j++) {
           weights[i][j] = (float) rand()/RAND_MAX;
       }

    /* Receive data from master */
    pvm_recv( -1, 1 );      /* messagetype = 1 */
    pvm_upkint(&nproc, 1, 1);
    pvm_upkint(tids, nproc, 1);
    pvm_upkint(&n, 1, 1);
    pvm_upkfloat(input, n, 1);
   
    /* Determine which slave I am (0 -- nproc-1) */
    for( i=0; i<nproc; i++ )
       if( mytid == tids[i] ){ me = i; break; }
    printf("slave %d of %d is present.\n",me, nproc);

    for (z=0; z<NR_OF_LOOPS; z++) {

      /* find the minimum distance */
      min = 1000000;
      for( i=0; i<nproc; i++) { 
        result = 0.0;    
        for( j=0; j<n; j++)   // calculate Eucl. distance
            result += ( (input[j]-weights[i][j]) * (input[j]-weights[i][j]));
        if ( result < min ) {
            min = result;
            winner = i;   /* the X position of the winner (the Y-pos is the slave-nr) */
        }
      }
      // printf("slave %d found %d for a winner with distance %f.\n", me, winner, min);

      /* Send result to master */
      pvm_initsend( PvmDataDefault );
      pvm_pkint( &me, 1, 1 );
      pvm_pkint( &winner, 1, 1 );
      pvm_pkfloat( &min, 1, 1 );
      pvm_pkfloat( prop, 10000,1);
      master = pvm_parent();
      pvm_send( master, 2 );

      /* Wait for final winner */
      pvm_recv( -1, 3 );   /* messagetype = 3 */
      pvm_upkint(&xpos, 1, 1);
      pvm_upkint(&ypos, 1, 1);
        
      /* Update my weights */
      for (i=0; i<nproc; i++) { 
        for (j=0; j<n; j++) {
            result = ( (xpos-me)*(xpos-me) ) + ( (ypos-i)*(ypos-i) );
            weights[i][j] += 0.1 * (weights[i][j]-input[j]) * (1/result);
        } 
      }

      /* Report to the master */
      pvm_initsend( PvmDataDefault );
      pvm_pkint( &me, 1, 1 ); 
      master = pvm_parent();
      pvm_send( master, 4 );  

    }

    /* Program finished. Exit PVM before stopping */
    pvm_exit();
}

