/* 
 * File:   main.c
 * Author: Andréa
 *
 * Created on 13 octobre 2010, 10:28
 */

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

#include <math.h>

#include "penality.h"

#define DEBUG  0
#define DEBUG2 0
#define DELTA  0.00001

char* printVector(const double vector[],const size_t dimension)
{
    char* value;
    char buffer[20];
    unsigned int counter = 0;

    // {1.4, 3.6, 5.2}

    value =(char *)malloc(40*sizeof(char));
    memset(value,'\0',40);

    if(DEBUG)printf("\n\n<init>Value : '%s'\n",value);

    strcat(value,"{");
    if(DEBUG)printf("<1st delimiter>Value : '%s'\n",value);

    for(counter = 0; counter < dimension;counter++)
    {
        if(DEBUG)printf("<counter>Value : '%d'\n",counter);
        if(DEBUG)printf("<dimension>Value : '%d'\n",dimension);

        memset(buffer,'\0',20);

        if(DEBUG)printf("<clean buffer>Value : '%s'\n",buffer);

        sprintf(buffer,"%.3lf",vector[counter]);
        if( counter + 1 < dimension ) strcat(buffer,", ");

        if(DEBUG)printf("<fill buffer> Value : '%s'\n",buffer);

        strcat(value,buffer);

        if(DEBUG)printf("<concat value> Value : '%s'\n",value);
    }
    strcat(value,"}");
    if(DEBUG)printf("<completed> Value : '%s'\n",value);
    return value;
}

double* ES(const double x[], const size_t dimension)
{
    double* result;

    if( dimension != 3 ) return NULL; // Fonction de R^3 vers R

    result = (double *)malloc(sizeof(double));

    result[0] = x[0]*x[0] + x[1]*x[1] + x[2]*x[2];

    return result;
}

typedef struct _vr3
{
    double x[3];
} VR3;


VR3 gradientES(double x[])
{
    VR3 v;
    v.x[0] = 2 * x[0];
    v.x[1] = 2 * x[1];
    v.x[2] = 2 * x[2];

    return v;
}

double* approximateGradient(
    double* (*function)(const double vector[],const size_t dimension),
    double x[],
    size_t dimension,
    double delta)
{
    double buffer[dimension];
    double* result;
    int counter;

    result = (double *)malloc(dimension * sizeof(double));
    
    if(DEBUG2)printf("\n\n<init vector>    Value : '%s'\n",printVector(x,dimension));
    if(DEBUG2)printf("<init dimension> Value : '%d'\n",dimension);

    for(counter = 0; counter < dimension;counter++)
    {
        memcpy(buffer,x,dimension * sizeof(double)); //copie du vecteur
        if(DEBUG2)printf("<init buffer> Value : '%s'\n",printVector(buffer,dimension));
        buffer[counter] += delta;
        if(DEBUG2)printf("<delta buffer> Value : '%s'\n",printVector(buffer,dimension));

        result[counter] = ( ((*function)(buffer,dimension))[0] - ((*function)(x,dimension))[0] ) / delta;
    }

    if(DEBUG2)printf("<result> Value : '%s'\n",printVector(result,dimension));

    return result;
}

double* sinCustom(const double vector[],const size_t dimension)
{
    double* result;

    if( dimension != 1 ) return NULL; // Fonction de R^3 vers R

    result = (double *)malloc(sizeof(double));

    result[0] = sin(vector[0]);

    return result;
}

double* sinGradient(const double vector[],const size_t dimension)
{
    double* result;

    if( dimension != 1 ) return NULL; // Fonction de R^3 vers R

    result = (double *)malloc(sizeof(double));

    result[0] = cos(vector[0]);

    return result;
}

/*
 * 
 */
int main(int argc, char** argv) {

    double vector[] = {0.6879};
    int dim = 1;

    printf("Here is my vector                    : '%s'\n",printVector(vector,dim));
    printf("Here is function value               : '%.3lf'\n",sinCustom(vector,dim)[0]);
    printf("Here is gradient vector              : '%s'\n",printVector(sinGradient(vector,dim),dim));
    printf("Here is approximatte gradient vector : '%s'\n",printVector(approximateGradient(sinCustom,vector,dim,DELTA),dim));

/*
    resolveByPenality(1, vector, EPSILON, MAX_ITER);
*/

    return (EXIT_SUCCESS);
}

