#JCourtin 08/2016

#class matrices réelles n-lignes x m-colonnes

class matrice():
    
    ##attributs de class
    n=None        #?
    m=None        #?
    
    ligne=()      
    colonne=()    
    
    
    ##Méthodes de class
    
    
    #constructeur qui mange une liste de liste
    def __init__(self, liste2Lignes):
        ERROR=False
        self.n=len(liste2Lignes);      self.m=len(liste2Lignes[0])
        self.ligne=();                 self.colonne=()
        
        #récupération des lignes
        for ligne in liste2Lignes:
            ERROR=(len(ligne)!=self.m) #si une ligne n'a pas même longueur
            line=()
            for val in ligne:
                line+=(val,)
                if (type(val+0.)!=type(1.)):#si pas int ou float
                    ERROR=True; break
            if (ERROR):
                raise Exception("Erreur dans les données")
            self.ligne+=(line,)
            
        #construction des colonnes

        #A chercher : permet de gagner du temps sur la transposition
    
    
    #AFFICHAGE------------------------------------------------------------
    def __str__(self):
        
        mystring="Proposer un affichage"
        return myString#-------------------------------------------------

    
########################### PARTIE 1 : A MODIFIER ############################    
    
     ## OPERATION INTERNE   
   
    #multiplication par un scalaire
    def __mul__(self, scala):
        
        # Acompléter
        
        return #la matrice en question
        
    __rmul__=__mul__   # gère la multiplication par la droite
    
    
    
    #negation
    def __neg__(self):
        return # A compléter
        
        
        
        
    #Opération de signe /
    def __truediv__(self, scalaire):
        # A compléter
        return # A compléter
    
    
    
    #sousMatrice(i,j) !!! (i,j) indices MATH commencent à 1 !!!
    def subMatrice(self, k, l):
        k=#?; l=?# expliquer
        matriceTMP=[]
        
        # A compléter
        
        return #A completer
    
    
    
    
    #calcul du déterminant : Approche récursive !----------------------
    def determinant(self):
        if (self.n!=self.m):
            print("Opération sur les matrice carrées svp !"); return
        if (self.n==1):
            return #A compléter 
        det=0.
        for k in range(self.n):   
            i,j=0,0 #A corriger    
            M=toto  #A corriger 
            det+=0. #A corriger
        return  det     
    
    #matrice transposée------------------------------------------------
    def transpose(self):
        
        #A compléter (il y a une astuce !).
        
        return #matrice transposée
    
    
    #calcul de la comatrice--------------------------------------------
    def comatrice(self):
        matriceTMP=[]
        #A compléter
        return #renvoyer la matrice correspondante.
    
    
    
    
    #calcul de la matrice inverse-------------------------------------
    def inverse(self):
        det=self.determinant()
        if (det==0.):
            raise Exception("Matrice non inversible !!!")
        #doit on ou non utiliser l'appel au constructeur ci-dessous ?
        return #Compléter : on veut une matrice
     
     
     
     
    #Arrondi à 10-15 près--------------------------------------------
    def round(self,n=15):
        matriceTMP=[]
        for i in range(self.n):         #essayer et commenter cette méthode
            ligneTMP=[]                 
            for j in range(self.m):
                val=round(self.ligne[i][j],n)
                if (abs(val-int(val))<10**(-n)):
                    val=int(val)
                ligneTMP+=[val]
            matriceTMP+=[ligneTMP]
        return matrice(matriceTMP)



    ## OPERATION EXTERNE   
 
    #opération de signe +   --------------------------------------------
    def __add__(self, other):
        if (self.n!= other.n or self.m!=other.m):
            raise Exception("Matrices non semblables")
        matriceTMP=[]
        
        #A compléter
        
        return matrice(matriceTMP)
    
    #soustraction signe -  --------------------------------------------
    def __sub__(self, other):
        return #A compléter (il y a toujours une astuce ici)
    
    
    #test égalité          --------------------------------------------
    def __eq__(self, other):
        test=True                         
        #Proposer un test
        return test
    
    
    
    #produit matriciel --> SELF.OTHER (sens de lecture)----------------
    def dot(self, other):
        if (self.m!= other.n):
            raise Exception("Produit impossible")
        matriceTMP=[]
        
        # A compléter
        
        return matrice(matriceTMP)
    ##FIN DE LA CLASS

########################### PARTIE 2 : A MODIFIER ############################    

"""
Cette pratie se propose de résoudre un système linéaire de type AX=B dans le cas le plus général
par la méthode du pivot de Gauss.
L'intérêt de cette méthode est d'être beaucoup plus rapide que de calculer la matrice inverse (dont le coût devient vite inacceptable) et de détecter automatiquement si le système n'est pas solvable.

En niveau Noir on demande de proposer une méthode de résolution d'un système
linéaire où A est une matrice carrée et B une matrice colonne.
Vous pouvez la tester sur la base des matrice 4x4 donnée en fin de programme.

Bon courage
"""
## Résolution de système linéaire type AX=B  


############# MAIN #############################################################
if (__name__=='__main__'):
    
    
    data22=[[1,2],\
            [3,4]]
    
    data42=[[2,2],\
            [3,4],\
            [5,6],\
            [7,8]]
    
    data33=[[1,2,3],\
            [4,5,6],\
            [7,8,9]]     #lignes liées : L1 + L3 - 2*L2 = 0
    
    matrice22=matrice(data22)
    matrice42=matrice(data42)
    matrice33=matrice(data33)
    
    print("matrice 2x2 :\n")
    print(matrice22.ligne)
    print(matrice22.colonne)
    print()
    print("matrice 4x2 :\n")
    print(matrice42.ligne)
    print(matrice42.colonne)
    print()
    print("matrice 3x3 :\n")
    print(matrice33.ligne)
    print(matrice33.colonne)
    
    ############################### TEST RESOLUTION ############################
    
    #Test de la résolution d'un système en 4x4
    mTest=matrice([[4,1,2,3], [5,2,0,3], [0,9,1,4], [2,1,3,4]])
    bTest=matrice([[1], [2], [3], [4]])
    
    X=resolSystem(mTest, bTest)
    #Proposer une formule utilisant la matrice inverse pour comparer les résultats.
    #AY=B soit:
    #Y=??????
    #on compare ensuite X (par Gauss) et Y :
    #print("X.round(14)==Y.round(14) : ",X.round(14)==Y.round(14))