/**
 * @file matriceTest.c
 * @brief Contients les matrices test sproposées et des fonctions de bases pour créer/afficher ces matrices.
 * @author Valentin PORTAIL et Jérémie VILLEPREUX
 * @version 1.0
 * @date 02/10/2022
 */


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


/** \def TAILLE_MATRICE
 * @brief Correspond à la taille de la matrice le plus souvent considérer.
 */
#define TAILLE_MATRICE 3



/** 
 * @brief Permet d'afficher les éléments d'une matrice.
 *
 * @param[in] tab      Matrice à afficher.
 * @param[in] nbrLig   Correspond au nombre de ligne de la matrice à afficher.
 * @param[in] nbrCol   Correspond au nombre de colonne de la matrice à afficher.

 * @return Renvoie 0 si la focntion se déroule normalement  jusqu'à la fin.
 */
int afficheMatrice(double **tab, unsigned int nbrLig, unsigned int nbrCol){

    if (tab != NULL){ //Cas où la matrice à un problème (e.g. Problème d'allocation dynamique) 
  
	for (unsigned int i=0; i<nbrLig; ++i){
	    for (unsigned int j=0; j<nbrCol; ++j){
	    	printf("%lf ", tab[i][j]);
	    }
	    printf("\n");
	}
	printf("\n");
    }

    else{
	printf("NULL\n");
    }
    
    return EXIT_SUCCESS;

}


/** 
 * @brief Permet de créer une matrice de manière dynamique.
 *
 * @param[in] nbrLig   Correspond au nombre de ligne que l'on veut donner à la matrice .
 * @param[in] nbrCol   Correspond au nombre de colonne que l'on veut donner à la matrice.
 *
 * @return Renvoie le pointeur sur la matrice, vaut **NULL** si l'allocation à échouer.
 */
double ** creationMatriceDynamique(unsigned int nbrLig, unsigned int nbrCol){
    
    double **matrice = (double **)calloc(nbrLig, sizeof(double *));

    if (matrice==NULL){ //En cas de problème lors de l'allocation, permet de tout stopper

	return NULL;
    }
    for (unsigned int i=0; i<nbrLig; i++){
	matrice[i]=(double *)calloc(nbrCol, sizeof(double));
	
	if (matrice[i]==NULL){ //Si l'allocation d'une 'ligne' échoue: libère la mémoire échoue et renvoie le pointeur NULL
	    for (unsigned int j=0; j<i; j++){
		free(matrice[j]);
		matrice[j]=NULL;
	    }
	    free(matrice);
	    matrice=NULL;
	    return NULL;
	}
    }    
    return matrice; //Ici, l'allocation à marcher avec succès
}


/** 
 * @brief Permet de libérer la mémoire d'une matrice, qui a été créer dynamiquement.
 *
 * @param[in] matrice  Correspond à la matrice à libérer.
 * @param[in] nbrLig   Correspond au nombre de ligne de cette matrice.
 *
 * @return Renvoie 0 si la focntion se déroule normalement  jusqu'à la fin.
 */
int liberationMemoireMatrice(double **matrice, unsigned int nbrLig){

    for (unsigned int i=0; i<nbrLig; i++){
	free(matrice[i]);
	matrice[i]=NULL;
    }
    free(matrice);
    matrice=NULL;

    return EXIT_SUCCESS;
}



/* ==================================================
    PARTIE DÉDIÉES À LA CRÉATION DES MATRICES TESTS
      *******************************************
    
    Les matrices A sont rentrée à la main pour A1 à A4
    et de manière itérative pour A5 et A6.
    
    Chaque coefficient de la matrices B est obtenu en 
    en sommant une ligne de la matrice A (car x doit 
    contenir seulement des 1, et on multiple donc 
    par le vecteur colonne constitué que de 1)...

    Un choix d'implémentation des matrices par fonction a
    été fait, afin de ne pas allouer "pour rien" des matrices,
    si on ne les utilise pas dans la suite.
    ================================================== */


/** 
 * @brief Permet de créer dynamiquement la matrice A1 de l'énoncé.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceA1Dynamique(void){

    
    double **A1=creationMatriceDynamique(TAILLE_MATRICE, TAILLE_MATRICE);
    if (A1!=NULL){
	A1[0][0]=3;
	A1[0][1]=0;
	A1[0][2]=4;
	
	A1[1][0]=7;
	A1[1][1]=4;
	A1[1][2]=2;

	A1[2][0]=-1;
	A1[2][1]=1;
	A1[2][2]=2;
    }
    
    return A1;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B1 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A1.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB1Dynamique(void){ 

    double **B1=creationMatriceDynamique(3, 1);
    if (B1!=NULL){
	B1[0][0]=7;
	B1[1][0]=13;
	B1[2][0]=2;
    }
    return B1;
}


/** 
 * @brief Permet de créer dynamiquement la matrice A2 de l'énoncé.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceA2Dynamique(void){

    double ** A2=creationMatriceDynamique(TAILLE_MATRICE, TAILLE_MATRICE);
    if (A2!=NULL){
	A2[0][0]=-3;
	A2[0][1]=3;
	A2[0][2]=-6;
       
	A2[1][0]=-4;
	A2[1][1]=7;
	A2[1][2]=8;

	A2[2][0]=5;
	A2[2][1]=7;
	A2[2][2]=-9;
    }
    return A2;
}

/** 
 * @brief Permet de créer dynamiquement la matrice B2 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A2.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB2Dynamique(void){

    double **B2=creationMatriceDynamique(3, 1);
    if (B2!=NULL){
	B2[0][0]=-6;
	B2[1][0]=11;
	B2[2][0]=3;
    }
    return B2;
}


/** 
 * @brief Permet de créer dynamiquement la matrice A3 de l'énoncé.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à
 *échouer.
 */
double ** matriceA3Dynamique(void){

    double **A3=creationMatriceDynamique(TAILLE_MATRICE, TAILLE_MATRICE);
    if (A3!=NULL){
	A3[0][0]=4;
	A3[0][1]=1;
	A3[0][2]=1;
	
	A3[1][0]=2;
	A3[1][1]=-9;
	A3[1][2]=0;

	A3[2][0]=0;
	A3[2][1]=-8;
	A3[2][2]=6;
    }
    return A3;
}

/** 
 * @brief Permet de créer dynamiquement la matrice B3 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A3.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à
 *échouer.
 */
double ** matriceB3Dynamique(void){

    double **B3=creationMatriceDynamique(3, 1);
    if (B3!=NULL){
	B3[0][0]=6;
	B3[1][0]=-7;
	B3[2][0]=-2;
    }
    return B3;
}


/** 
 * @brief Permet de créer dynamiquement la matrice A4 de l'énoncé.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à
 *échouer.
 */
double ** matriceA4Dynamique(void){

    double **A4=creationMatriceDynamique(TAILLE_MATRICE, TAILLE_MATRICE);
    if (A4!=NULL){
	A4[0][0]=7;
	A4[0][1]=6;
	A4[0][2]=9;
	
	A4[1][0]=4;
	A4[1][1]=5;
	A4[1][2]=-4;

	A4[2][0]=-7;
	A4[2][1]=-3;
	A4[2][2]=8;
    }
    return A4;
}

/** 
 * @brief Permet de créer dynamiquement la matrice B4 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A4.
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à
 *échouer.
 */
double ** matriceB4Dynamique(void){

    double **B4=creationMatriceDynamique(3, 1);
    if (B4!=NULL){
	B4[0][0]=22;
	B4[1][0]=5;
	B4[2][0]=-2;
    }
    return B4;
}


/** 
 * @brief Permet de créer dynamiquement la matrice A5 de l'énoncé.
 *
 * @param[in] taille   Correspond à la taille que l'on veut donner à la
 * matrice .
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à
 *échouer.
 */
double ** matriceA5Dynamique(unsigned int taille){

    double **A5=creationMatriceDynamique(taille, taille);

    if (A5 != NULL){
	
	int puissance=0;
	
	for (unsigned int i=0; i<taille; ++i){
	    for (unsigned int j=0; j<taille; ++j){
		if (i==j){
		    A5[i][j]=1;
		}
		else{
		    if (i==0){
			puissance=1-(j+1);
			A5[i][j]=pow(2, puissance);
			A5[j][i]=A5[i][j];
		    }
		}
	    }
	}	
    }
    return A5;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B5 en taille 3 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A5 en taille 3.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB5_3Dynamique(void){

    double **B5_3=creationMatriceDynamique(3, 1);
    if (B5_3!=NULL){
	B5_3[0][0]=7./4;
	B5_3[1][0]=3./2;
	B5_3[2][0]=5./4;
    }
    return B5_3;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B5 en taille 6 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A5 en taille 6.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB5_6Dynamique(void){

    double **B5_6=creationMatriceDynamique(6, 1);
    if (B5_6!=NULL){
	B5_6[0][0]=63./32;
	B5_6[1][0]=3./2;
	B5_6[2][0]=5./4;
	B5_6[3][0]=9./8;
	B5_6[4][0]=17./16;
	B5_6[5][0]=33./32;
    }
    return B5_6;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B5 en taille 8 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A5 en taille 8.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB5_8Dynamique(void){

    double **B5_8=creationMatriceDynamique(8, 1);
    if (B5_8!=NULL){
	B5_8[0][0]=255./128;
	B5_8[1][0]=3./2;
	B5_8[2][0]=5./4;
	B5_8[3][0]=9./8;
	B5_8[4][0]=17./16;
	B5_8[5][0]=33./32;
	B5_8[6][0]=65./64;
	B5_8[7][0]=129./128;
    }
    return B5_8;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B5 en taille 10 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A5 en taille 10.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB5_10Dynamique(void){

    double **B5_10=creationMatriceDynamique(10, 1);
    if (B5_10!=NULL){
	B5_10[0][0]=1023./512;
	B5_10[1][0]=3./2;
	B5_10[2][0]=5./4;
	B5_10[3][0]=9./8;
	B5_10[4][0]=17./16;
	B5_10[5][0]=33./32;
	B5_10[6][0]=65./64;
	B5_10[7][0]=129./128;
	B5_10[8][0]=257./256;
	B5_10[9][0]=513./512;
    }
    return B5_10;
}


/** 
 * @brief Permet de créer dynamiquement la matrice A6 de l'énoncé.
 *
 * @param[in] taille   Correspond à la taille que l'on veut donner à la
 * matrice .
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à
 *échouer.
 */
double ** matriceA6Dynamique(unsigned int taille){

    
    double **A6=creationMatriceDynamique(taille, taille);

    
    if (A6!=NULL){		  
	for (unsigned int i=0; i<taille; ++i){
	    for (unsigned int j=0; j<taille; ++j){
		if (i==j){
		    A6[i][j]=3;
		}
		else{
		    if (i<taille-1 && j==i+1){
			A6[i][j]=-1;
		    }
		    if (i>0 && j==i-1){
			A6[i][j]=-2 ;
		    }
		}
	    }
	}
    }
    return A6;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B6 en taille 3 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A6 en taille 3.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB6_3Dynamique(void){

    double **B6_3=creationMatriceDynamique(3, 1);
    if (B6_3!=NULL){
	B6_3[0][0]=2;
	B6_3[1][0]=0;
	B6_3[2][0]=1;
    }
    return B6_3;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B6 en taille 6 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A6 en taille 6.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB6_6Dynamique(void){

    double **B6_6=creationMatriceDynamique(6, 1);
    if (B6_6!=NULL){
	B6_6[0][0]=2;
	B6_6[1][0]=0;
	B6_6[2][0]=0;
	B6_6[3][0]=0;
	B6_6[4][0]=0;
	B6_6[5][0]=1;
    }
    return B6_6;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B6 en taille 8 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A6 en taille 8.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB6_8Dynamique(void){

    double **B6_8=creationMatriceDynamique(8, 1);
    if (B6_8!=NULL){
	B6_8[0][0]=2;
	B6_8[1][0]=0;
	B6_8[2][0]=0;
	B6_8[3][0]=0;
	B6_8[4][0]=0;
	B6_8[5][0]=0;
	B6_8[6][0]=0;
	B6_8[7][0]=1;
    }
    return B6_8;
}


/** 
 * @brief Permet de créer dynamiquement la matrice B6 en taille 10 de l'énoncé.
 * Obtenu en faisaint la somme des lignes de la matrice A6 en taille 10.
 *
 * @return Renvoie le pointeur sur cette matrice, **NULL** si l'allocation à échouer.
 */
double ** matriceB6_10Dynamique(void){

    double **B6_10=creationMatriceDynamique(10, 1);
    if (B6_10!=NULL){
	B6_10[0][0]=2;
	B6_10[1][0]=0;
	B6_10[2][0]=0;
	B6_10[3][0]=0;
	B6_10[4][0]=0;
	B6_10[5][0]=0;
	B6_10[6][0]=0;
	B6_10[7][0]=0;
	B6_10[8][0]=0;
	B6_10[9][0]=1;
    }
    return B6_10;
}
