Skip to content
Snippets Groups Projects
opti.c 10.9 KiB
Newer Older
philippe.montando's avatar
philippe.montando committed
#include "opti.h"
philippe.montando's avatar
philippe.montando committed
int LINE_POINTS = 1000000;
philippe.montando's avatar
philippe.montando committed
double X_VALUE = 0.000001;
// Learning rate
double ER = 0.0000000001;
philippe.montando's avatar
philippe.montando committed


philippe.montando's avatar
philippe.montando committed
// y(x)=ax+b
// crée plein de points sur une même ligne
philippe.montando's avatar
philippe.montando committed
Point* line(double a, double b){
    Point * points = (Point*)malloc(sizeof(Point)*LINE_POINTS);
    double x = 0.0;
    for(int i=0;i<LINE_POINTS;i++){
philippe.montando's avatar
philippe.montando committed
        Point d;
        d.x = x;
        d.y = (a*x)+b;
        points[i]=d;
        //printf("%lf, %lf", d.x, d.y);
        x+=X_VALUE;
    }
    return points;
}
philippe.montando's avatar
philippe.montando committed

// La fonction pow() de math.h avait un problème aavec mon Makefile donc je l'ai refaite
// et puis après avoir résolu le problème (emplacement du -lm) afin de pouvoir utiliser
// sqrt() j'ai décidé de la laisser car le nom est mignon
double popow(double v, double w){
    double u=v;
    for(int i=1;i<w;i++){
        v*=u;
    }
    return v;
}

// Génère un double random...
philippe.montando's avatar
philippe.montando committed
double double_random(double min, double max) 
{
    double my_random;
    my_random = (double)rand()/RAND_MAX*(max-min)+min;
    //printf ( "%f\n", my_random);
    return my_random;
}
philippe.montando's avatar
philippe.montando committed

// Version 1 du nuage, se doit d'appeler line indirectement
Point* cloud1(Point* a_line){
    Point * my_cloud = malloc(sizeof(Point)*CLOUD_POINTS);
    for(int i=0;i<CLOUD_POINTS;i++){
philippe.montando's avatar
philippe.montando committed
        Point chosen_point = a_line[rand()%LINE_POINTS-1];
        double new_y = double_random(chosen_point.y-RANDOMNESS, chosen_point.y+RANDOMNESS);
        my_cloud[i].x=chosen_point.x;
        my_cloud[i].y=new_y;
        printf("\nx = %f | y = %f\n", my_cloud[i].x,my_cloud[i].y);
    }
    return my_cloud;
}
philippe.montando's avatar
philippe.montando committed

// Version 2 du nuage, peut être généré grâce aux a et b d'une droite
// Génère aléatoirement des points sur l'axe des x (qui ne sont donc pas espacés uniformément)
// le while ne sert pas à grand chose. cloud2_5() est censé rectifier ça. 
Point* cloud2(double *a, double *b){
    Point * my_cloud = (Point*)malloc(sizeof(Point)*CLOUD_POINTS);
    for(int i=0;i<CLOUD_POINTS;i++){
        Point chosen_point;
        chosen_point.x = double_random(0,1);
        for(int j=0;j<CLOUD_POINTS-1;j++){
            while(chosen_point.x==my_cloud[j].x){
                chosen_point.x = double_random(0,1);
            }
        }
        double rj = double_random(-RANDOMNESS, RANDOMNESS);
        chosen_point.y = (*a*chosen_point.x)+*b+rj;
        my_cloud[i].x=chosen_point.x;
        my_cloud[i].y=chosen_point.y;
        //printf("\nx = %f | y = %f\n", my_cloud[i].x,my_cloud[i].y);
    }
    return my_cloud;
}

double random_point_in_cloud2_5(Point* my_cloud){
    double v = double_random(0,1);
    for(int i=0;i<CLOUD_POINTS;i++){
        if(v==my_cloud[i].x){
            v =random_point_in_cloud2_5(my_cloud);
        }
    }
    return v;
}

Point* cloud2_5(double *a, double *b){
    Point * my_cloud = (Point*)malloc(sizeof(Point)*CLOUD_POINTS);
    for(int i=0;i<CLOUD_POINTS;i++){
        Point chosen_point;
        chosen_point.x=random_point_in_cloud2_5(my_cloud);
        double rj = double_random(-RANDOMNESS, RANDOMNESS);
        chosen_point.y = (*a*chosen_point.x)+*b+rj;
        my_cloud[i].x=chosen_point.x;
        my_cloud[i].y=chosen_point.y;
        //printf("\nx = %f | y = %f\n", my_cloud[i].x,my_cloud[i].y);
    }
    return my_cloud;
}


// version 3 du nuage, plus simple, x espacés uniformément
Point* cloud3(double *a, double *b){
    Point * my_cloud = (Point*)malloc(sizeof(Point)*CLOUD_POINTS);
    for(int i=0;i<CLOUD_POINTS;i++){
        my_cloud[i].x=((double)i/(double)CLOUD_POINTS);
        double rj = double_random(-RANDOMNESS, RANDOMNESS);
        my_cloud[i].y = ((*a)*my_cloud[i].x)+(*b)+rj;
    }
    return my_cloud;
}

Point* cloud_test(){
    Point * my_cloud = (Point*)malloc(sizeof(Point)*3);
    my_cloud[0].x = 0.51;
    my_cloud[0].y = 0.24;
    my_cloud[1].x = 0.98;
    my_cloud[1].y = 0.867;
    my_cloud[2].x = 0.1;
    my_cloud[2].y = 0.0042;
    return my_cloud;
}

// Méthode des moindres carrés
philippe.montando's avatar
philippe.montando committed
double* averages(Point* my_cloud, int cloud_size){
    //double* avg = (double*)malloc(sizeof(double)*4);
    double* avg = malloc(sizeof(double)*4);
    double x_avg, y_avg, x2_avg, xy_avg;
    for(int i=0; i<cloud_size-1;i++){
        x_avg+=my_cloud[i].x;
        y_avg+=my_cloud[i].y;
        x2_avg+=popow(my_cloud[i].x,2);
        xy_avg+=(my_cloud[i].x*my_cloud[i].y);
    x_avg/=cloud_size;y_avg/=cloud_size;x2_avg/=cloud_size;xy_avg/=cloud_size;
    avg[0]=x_avg;avg[1]=y_avg;avg[2]=x2_avg;avg[3]=xy_avg;
    printf("x=%f - y=%f - x2=%f - xy=%f", avg[0],avg[1],avg[2],avg[3]);
    return avg;
}

// Méthode des moindres carrés
philippe.montando's avatar
philippe.montando committed
double* a_and_b(double* my_averages){
    double* a_n_b = (double*)malloc(sizeof(double)*2);
philippe.montando's avatar
philippe.montando committed
    double x_avg = my_averages[0];
    double y_avg = my_averages[1];
    double x2_avg = my_averages[2];
    double xy_avg = my_averages[3];
    double a = (xy_avg-(x_avg*y_avg))/(x2_avg-popow(x_avg,2));
    double b = y_avg-(a*x_avg);
    a_n_b[0]=a;
    a_n_b[1]=b;
    return a_n_b;
}

philippe.montando's avatar
philippe.montando committed
// Sommes (similaire à averages() mais ne divise pas par le nb de points)
double* sums(Point* my_cloud, int cloud_size){
    //double* avg = (double*)malloc(sizeof(double)*4);
    double* my_sums = (double*)malloc(sizeof(double)*4);
philippe.montando's avatar
philippe.montando committed
    double x, y, x2, xy;
    for(int i=0; i<cloud_size-1;i++){
        x+=my_cloud[i].x;
        y+=my_cloud[i].y;
        x2+=popow(my_cloud[i].x,2);
        xy+=(my_cloud[i].x*my_cloud[i].y);
    }
    my_sums[0]=x;my_sums[1]=y;my_sums[2]=x2;my_sums[3]=xy;
    printf("x=%f - y=%f - x2=%f - xy=%f", my_sums[0],my_sums[1],my_sums[2],my_sums[3]);
    return my_sums;
}

// La nouvelle fonction gradient 2 en 1, uniquement chez Lidl
double gradient(double *a, double *b, Point* my_cloud, int cloud_size, bool is_a){
    double my_gradient;
    for(int i = 0;i<cloud_size;i++){
        //Somme des Xi(aXi+b-Yi)
        if(is_a){
            my_gradient+=(my_cloud[i].x)*((*a*(my_cloud[i].x)+*b-(my_cloud[i].y)));
            my_gradient+=(*a*(my_cloud[i].x))+*b-(my_cloud[i].y);
/*void gradient_one(double* a, double* b, Point* my_cloud, double* current_cost){
    double gr_A,gr_B;
    double* my_new_a,my_new_b;
    gr_A = gradient(a, b, my_cloud, CLOUD_POINTS, true);
    gr_B = gradient(a, b, my_cloud, CLOUD_POINTS, false);
    // Les 2 lignes ci-dessous pourraient être condensées, mais c'est pour rendre le code
    // plus explicite que je sépare volontairement les étapes.
    my_new_a = (*a) - (LR * gr_A);
    //printf("\nNew A : %f\n", my_new_a);
    my_new_b = (*b) - (LR * gr_B);
    //printf("New B : %f\n", my_new_b);
    *current_cost = cost2(a,b,my_new_a,my_new_b);
    //printf("\nCost : %f\n", current_cost);
    *a = my_new_a; *b = my_new_b;
}

void gradient_descent_v3(double* a, double* b, Point* my_cloud){
    //double current_cost = 10.0;
    printf("\navant\n");
    gradient_one(a, b,my_cloud, &current_cost);
    printf("\naprès\n");
    int nb_it = 1;
    //double* a_n_b = (double*)malloc(sizeof(double)*2);
    while(current_cost>=ER){
        gradient_one(a, b,my_cloud, &current_cost);
        nb_it++;
    }
    printf("\nCost : %f || Nombre d'itérations : %d\n ", current_cost, nb_it);
    //a_n_b[0]=a; a_n_b[1]=b;
    //return a_n_b;
}*/

void gradient_descent_v4(double *a, double *b, Point* my_cloud){
    double gr_A,gr_B,my_new_a,my_new_b,current_cost;
    double *zero;
    double z = 0.0;
    zero = &z;
    current_cost = cost2(zero,zero,a,b);
    //double* a_n_b = (double*)malloc(sizeof(double)*2);
        gr_A = gradient(a, b, my_cloud, CLOUD_POINTS, true);
        gr_B = gradient(a, b, my_cloud, CLOUD_POINTS, false);
        // Les 2 lignes ci-dessous pourraient être condensées, mais c'est pour rendre le code
        // plus explicite que je sépare volontairement les étapes.
        //printf("\nNew A : %f\n", my_new_a);
        //printf("New B : %f\n", my_new_b);
        current_cost = cost2(a,b,&my_new_a,&my_new_b);
        //printf("\nCost : %f\n", current_cost);
        //current_cost = cost(a, b, my_cloud, CLOUD_POINTS);
        nb_it++;
    printf("\nCost : %f || Nombre d'itérations : %d\n ", current_cost, nb_it);
    //a_n_b[0]=a; a_n_b[1]=b;
    //return a_n_b;
// La nouvelle fonction gradient_descent 2 en 1, uniquement chez Lidl
// Formule fausse et pas fait la norme donc bug. A refaire demain.
void gradient_descent_v2(double *a, double *b, Point* my_cloud, double current_cost){
    double gr_A,gr_B,my_new_a,my_new_b;
    int nb_it = 0;
    //double* a_n_b = (double*)malloc(sizeof(double)*2);
    while(current_cost>=ER){
        gr_A = gradient(a, b, my_cloud, CLOUD_POINTS, true);
        gr_B = gradient(a, b, my_cloud, CLOUD_POINTS, false);
        // Les 2 lignes ci-dessous pourraient être condensées, mais c'est pour rendre le code
        // plus explicite que je sépare volontairement les étapes.
        my_new_a = (*a) - (LR * gr_A);
        //printf("\nNew A : %f\n", my_new_a);
        my_new_b = (*b) - (LR * gr_B);
        //printf("New B : %f\n", my_new_b);
        current_cost = cost2(a,b,&my_new_a,&my_new_b);
        //printf("\nCost : %f\n", current_cost);
        *a = my_new_a; *b = my_new_b;
        //current_cost = cost(a, b, my_cloud, CLOUD_POINTS);
        nb_it++;
    printf("\nCost : %f || Nombre d'itérations : %d\n ", current_cost, nb_it);
    //a_n_b[0]=a; a_n_b[1]=b;
    //return a_n_b;
double cost2(double *a, double *b, double *new_a, double *new_b){
    return sqrt(popow((*new_a - *a),2)+popow((*new_b - *b), 2));
philippe.montando's avatar
philippe.montando committed
int main (void){
    srand(time(NULL));
    /*// Create a vector X = [0,1,2...99]
    double_vector_t *X = iota(100);
    // Create a vector Y = my_function(x)
    double_vector_t *Y = apply_function(X, my_function);

    // Export our vectors into files
    export_vector("./X.vec", X);
    export_vector("./Y.vec", Y);

    // Free our vectors
    destroy_vector(&Y);
    destroy_vector(&X);
    */
    //Point* first_line = line(7.0, 5.5);
    double a_init = 0.98902527076;
    double b_init = -0.1537833935;
    //Point* fluffy = cloud2_5(&a_init, &b_init);
    Point* fluffy = cloud_test();
    printf("\na initial = %f || b initial = %f\n", a_init, b_init);
    double a = double_random(-100,100);
    double b = double_random(-100,100);
    //double initial_cost = cost2(&a, &b,0,0);
    //gradient_descent_v2(&a, &b, fluffy, initial_cost);
    double initial_costs = 0;
    gradient_descent_v4(&a, &b, fluffy);
    printf("\na trouvé = %f || b trouvé = %f\n", a, b);
philippe.montando's avatar
philippe.montando committed
    printf("\ndone\n");
philippe.montando's avatar
philippe.montando committed
    return 0;
}