package AlgLin;

public class Thomas extends SysLin {

	public Thomas(Mat3Diag matrice, Vecteur secondMembre) throws IrregularSysLinException {
        super(matrice, secondMembre);
        // Vérification que la matrice est bien tridiagonale
        if (!(matrice instanceof Mat3Diag)) {
            throw new IrregularSysLinException("la matrice du système doit être de type Mat3Diag");
        }
    }

	@Override
    public Vecteur resolution() {
		
        int n = this.getMatriceSystem().nbColonne(); 
        Vecteur p = new Vecteur(n); // pk
        Vecteur q = new Vecteur(n); // qk
        Vecteur x = new Vecteur(n); // la solution
        Mat3Diag matrice =  (Mat3Diag) this.getMatriceSystem();
        Vecteur d = this.getSecondMembre();

        // initialisation des premiers coefficients p1 et q1 : 
        p.remplacerCoefficient(0, -matrice.getCoef(2, 0) / matrice.getCoef(1, 0)); 
        q.remplacerCoefficient(0, d.getCoef(0, 0) / matrice.getCoef(1, 0)); 

        // Calcul des pk et qk
        for (int k = 1; k < n - 1; k++) {
            double beta = matrice.getCoef(0, k) * p.getCoef(k - 1, 0) + matrice.getCoef(1, k);
            p.remplacerCoefficient(k, -matrice.getCoef(2, k) / beta); 
            q.remplacerCoefficient(k, (d.getCoef(k, 0) - matrice.getCoef(0, k) * q.getCoef(k - 1, 0)) / beta); 
        }

        // Calcul de xn, dernier element du vecteur solution
        x.remplacerCoefficient(n - 1, (d.getCoef(n - 1, 0) - matrice.getCoef(0, n - 1) * q.getCoef(n - 2, 0)) / (matrice.getCoef(0, n - 1) * p.getCoef(n - 2, 0) + matrice.getCoef(1, n - 1))); 

        // remontée pour calculer xk
        for (int k = n - 2; k >= 0; k--) {
            x.remplacerCoefficient(k, p.getCoef(k, 0) * x.getCoef(k + 1, 0) + q.getCoef(k, 0)); 
        }
        return x;
    }
    
    public static void main(String[] args) {
        try {
        	
        	// Test 1:
        	// Définition de la matrice tridiagonale
        	double[][] matrice = {{0, 2, 1}, {1, 3, 5}, {7, 4, 0}};
            Mat3Diag matrice1 = new Mat3Diag(matrice);
            System.out.println("matrice1: \n" + matrice1);

            // Définition du second membre
            double[] secondMembre = {7, 15, 8};
            Vecteur secondMembre1 = new Vecteur(secondMembre);
            System.out.println("vecteur 1: \n" + secondMembre1);

            // Résolution du système
            Thomas system1 = new Thomas(matrice1, secondMembre1);
            Vecteur solution1 = system1.resolution();
            System.out.println("La solution du systeme trouvée : \n" + solution1);
            
            // Calcul du produit de la matrice tridiagonale d'origine par la solution trouvée
            Vecteur produit1 = Mat3Diag.produit(matrice1, solution1);
            System.out.println("Produit de la matrice * solution : \n" + produit1);
            System.out.println("Sachant que le second membre était : \n" + secondMembre1);

            
            // Calcul de la différence entre le produit et le second membre
            Vecteur difference1 = Vecteur.soustraction(produit1, secondMembre1);
            System.out.println("Différence (produit - second membre) : \n" + difference1);

            double norme1 = difference1.normeL1(); // Norme L1 de la différence
            System.out.println("norme L1 de la différence : " + norme1);

            double norme2 = difference1.normeL2(); // Norme L2 de la différence
            System.out.println("norme L2 de la différence : " + norme2);

            double norme3 = difference1.normeLinfini(); // Norme Linfini de la différence
            System.out.println("norme LInfini de la différence : " + norme3 + "\n\n");


            System.out.println("\n test 2\n");
            
            // Test 2:
            // Définition de la seconde matrice tridiagonale
            double[][] matrices = {{0, 1, 2, 3}, {1, 2, 3, 4}, {6, 4, 1, 0}};
            Mat3Diag matrice2 = new Mat3Diag(matrices);
            System.out.println("matrice 2 : \n" + matrice2);

            // Définition du second membre pour le test 2
            double[] secondMembre4 = {5, 14, 23, 14};
            Vecteur secondMembre2 = new Vecteur(secondMembre4);
            System.out.println("vecteur 2: \n" + secondMembre2);
            
            // Résolution du système
            Thomas system2 = new Thomas(matrice2, secondMembre2);
            Vecteur solution2 = system2.resolution();
            System.out.println("solution du systeme trouvée : \n" + solution2);
            
            // Calcul du produit de la seconde matrice tridiagonale d'origine par la solution trouvée
            Vecteur produit2 = Mat3Diag.produit(matrice2, solution2);
            System.out.println("produit matrice * solution : \n" + produit2);
            System.out.println("Sachant que le second membre était \n" + secondMembre2);

            // Calcul de la différence entre le produit et le second membre
            Vecteur difference2 = Vecteur.soustraction(produit2, secondMembre2);
            System.out.println("différence (produit - second membre) : \n" + difference2);

            double norme4 = difference2.normeL1(); // Norme L1 de la différence
            System.out.println("Norme de la différence : " + norme4);

            double norme5 = difference2.normeL2(); // Norme L2 de la différence
            System.out.println("norme de la différence : " + norme5);

            double norme6 = difference2.normeLinfini(); // Norme Linfini de la différence
            System.out.println("Norme de la différence : " + norme6);

        } catch (IrregularSysLinException e) {
            System.err.println(e.getMessage());
        }
    }
}
