/*
 * =====================================================================================
 *
 *       Filename:  sample_multitasking.c
 *
 *    Description:  Sample use of pthread
 *
 *        Version:  1.0
 *        Created:  01/10/2011 07:12:20 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  MACHIZAUD Andréa (blackpanther), andrea.machizaud@gmail.com
 *        Company:  
 *
 * =====================================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <pthread.h>

#define PRECISION 0.001

int i;
#define printVector(vector,dimension) \
    printf("{");                                          \
    for (i= 0; i< dimension; i++) { \
        printf("%lf",vector[i]);                  \
        if( i!= ( dimension - 1 ) )              \
            printf(", ");                                 \
    }                                                   \
    printf("}\n");                                        \

typedef struct thread_parameter {
     double  outputValue;
     double *vector;
     int     ordre;
     int     dimension;
} ThreadParameter;

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  compute
 *  Description:  
 * =====================================================================================
 */
    double
compute (double * vector, int dimension)
{
    return pow(vector[0],2) + pow(vector[1],2); 
}		/* -----  end of function compute  ----- */


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  computeDerivative
 *  Description:  
 * =====================================================================================
 */
    double*
computeDerivative (double * vector, int dimension)
{
    double* gradient = (double *)calloc(dimension,sizeof(double));
    gradient[0]      = 2 * vector[0];
    gradient[1]      = 2 * vector[1];
    return gradient; 
}		/* -----  end of function computeDerivative  ----- */


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  approximateCompute
 *  Description:  
 * =====================================================================================
 */
  void * 
approximateCompute (void * parameters)
{
    double *neighbor;
    ThreadParameter *params = (ThreadParameter *)parameters;
    neighbor = (double *)malloc(params->dimension*sizeof(double));
    memcpy(neighbor,params->vector,params->dimension*sizeof(double));
    neighbor[params->ordre] += PRECISION;
    double intermediate = compute(neighbor,params->dimension) - compute(params->vector,params->dimension); 
    params->outputValue = intermediate / PRECISION;
    return NULL; 
}		/* -----  end of function approximateCompute  ----- */

int main(int argc, const char *argv[])
{
    double          vector[2]     = {5434.5464, -763454.534246};
    double *        solution;
    unsigned int    dimension     = 2;
    pthread_t       threads[dimension];
    int             counter       = 0;
    ThreadParameter parameters[dimension];

    for (counter = 0; counter < dimension; counter++) {
        printf("Creating thread num-%d\n",counter);
        parameters[counter].dimension  = dimension;
        parameters[counter].ordre      = counter;
        parameters[counter].vector     = (double *)malloc(dimension*sizeof(double));
        memcpy(parameters[counter].vector,vector,dimension*sizeof(double));
        pthread_create(&threads[counter], NULL, approximateCompute, &parameters[counter]);
    }

    for (counter = 0; counter < dimension; counter++) {
        printf("Waiting for thread num-%d\n",counter);
        pthread_join(threads[counter],NULL);
        puts("freeing vector buffer\n");
        free(parameters[counter].vector);
    }

    solution = computeDerivative(vector,dimension); 
    puts("Real value : ");
    printVector(solution,dimension);
    free(solution);
    
    puts("Computed value : ");
    printf("{");
    for (counter = 0; counter < dimension; counter++) {
        printf("%lf",parameters[counter].outputValue);
        if( counter != ( dimension - 1 ) )
            printf(", ");
    }
    printf("}\n");

    return 0;
}
