#include "Matrice.h"
#include <iostream.h>
#include <stdio.h>



//############
//# MATRICES #
//############
// Les matrices sont representes par des vecteurs stockant les elements par lignes.


//-----------------
//# CONSTRUCTEURS #

template <class T> Matrice<T>::Matrice()
{
    element=new T[0];
    lignes=0;
    colonnes=0;
};

template <class T> Matrice<T>::Matrice(int a, int b)
{
    element=new T[a*b];
    lignes=a;
    colonnes=b;
};

template <class T> Matrice<T>::Matrice(int a, int b, int disp, T* tab)
{
	element=new T[a*b];
    lignes=a;
    colonnes=b;
	if (disp==0)    // par ligne
		for (int i=0; i<a*b; i++)
				element[i]=tab[i];
	else            // par colonne
		for (int j=0; j<b; j++)
			for (int i=0; i<b; i++)
				element[a*i+j]=tab[b*j+i];
};

template <class T> Matrice<T>::Matrice(Matrice<T>& M)
{
    lignes=M.lignes;
    colonnes=M.colonnes;
    element=new T[lignes*colonnes];
    for (int i=0; i<lignes*colonnes; i++)
        element[i]=M.element[i];
};

//# CONSTRUCTEURS #
//-----------------


//---------------
//# DESTRUCTEUR #

template <class T> Matrice<T>:: ~Matrice()
{
    delete [] element;
};

//# DESTRUCTEUR #
//---------------


//--------------
//# OPERATEURS #
// Definitions des operateurs suivants: [] * + - =

template <class T> Vecteur<T> Matrice<T>::operator [] (int indice)
{
    Vecteur<T> V(colonnes);
    for (int i=0; i<colonnes; i++)
        V[i+1]=element[(indice-1)*colonnes+i];
    return V;
};

template <class T> Vecteur<T> Matrice<T>::operator () (int indice)
{
    Vecteur<T> V(colonnes);
    for (int i=0; i<colonnes; i++)
        V[i+1]=element[(indice-1)*colonnes+i];
    return V;
};

template <class T> T& Matrice<T>::operator () (int a, int b)
{
    return element[(a-1)*colonnes+b-1];
};

template <class T> Matrice<T> operator* (T x, Matrice<T>& M)
{
    Matrice<T> resultat(M);
    for (int i=1; i<=M.lignes; i++)
        for (int j=1; j<=M.colonnes; j++)
            resultat(i,j)=x*(resultat(i,j));
    return resultat;
};

template <class T> Vecteur<T> Matrice<T>::operator* (Vecteur<T> &V)
{
    Vecteur<T> resultat(lignes);
    T zero(0);
    T temp;
    for (int i=0; i<lignes; i++)
        {
            temp=zero;
            for (int j=0; j<colonnes; j++)
                temp=temp+element[colonnes*i+j]*V[j+1];
            resultat[i+1]=temp;
        };
    return resultat;
};

template <class T> Matrice<T> Matrice<T>::operator* (Matrice<T> &M)
{
    Matrice<T> resultat(lignes,M.colonnes);
    T zero(0);
    T temp;
    for (int h=0; h<lignes; h++)
    for (int i=0; i<M.colonnes; i++)
        {
            temp=zero;
            for (int j=0; j<colonnes; j++)
                temp=temp+element[h*colonnes+j]*M[j+1][i+1];
            resultat(h+1,i+1)=temp;
        };
    return resultat;
};

template <class T> Matrice<T> Matrice<T>::operator+ (Matrice<T>& A)
{
    Matrice<T> resultat(lignes, colonnes);
    for (int i=0; i<lignes*colonnes; i++)
        resultat.element[i]=this->element[i]+A.element[i];
    return resultat;
};

template <class T> Matrice<T> Matrice<T>::operator- (Matrice<T>& A)
{
    Matrice<T> resultat(lignes, colonnes);
    for (int i=0; i<lignes*colonnes; i++)
        resultat.element[i]=this->element[i]-A.element[i];
    return resultat;
};

template <class T> Matrice<T>& Matrice<T>::operator= (Matrice<T>& M)
{
    this->lignes=M.lignes;
    this->colonnes=M.colonnes;
	delete [] element;
    this->element=new T[this->lignes*this->colonnes];
    for (int i=0; i<this->lignes*this->colonnes; i++)
        {
            this->element[i]=M.element[i];
        };
    return *this;
};

template <class T> ostream& operator<<(ostream& f, Matrice<T>& M)
{
    for (int i=1; i<=M.lignes; i++)
        {
            for (int j=1; j<=M.colonnes; j++)
                f<<M[i][j]<<" ";
            f<<endl;
        };
    return f;
};
            
//# OPERATEURS #
//--------------


//-------------
//# FONCTIONS #

template <class T> Matrice<T> Matrice<T>::transposee()
{
	Matrice<T> resultat(colonnes, lignes);
    for (int i=0; i<lignes; i++)
        for (int j=0; j<colonnes; j++)
            resultat.element[lignes*j+i]=element[colonnes*i+j];
    return resultat;
};

template <class T> Matrice<T> Matrice<T>::sub(int a, int b, int c, int d)
{
    Matrice<T> resultat(c-a+1, d-b+1);
    for (int i=a-1; i<c; i++)
        for (int j=b-1; j<d; j++)
            resultat(i-a+2,j-b+2)=element[colonnes*i+j];
    return resultat;
};

template <class T> T Matrice<T>::trace()
{
    T resultat(0);
    for (int i=0; (i<lignes) && (i<colonnes); i++)
        resultat=resultat+element[i*(lignes+1)];
    return resultat;
};

template <class T> void Matrice<T>::afficher()
{
    for (int i=0; i<lignes; i++)
        {
            for (int j=0; j<colonnes; j++)
                cout<<element[i*colonnes+j]<<" ";
            cout<<endl;
        };
};

template <class T> int Matrice<T>::nb_lignes()
{
	return lignes;
};

template <class T> int Matrice<T>::nb_colonnes()
{
	return colonnes;
};

template <class T> Vecteur<int> Matrice<T>::taille()
{
	Vecteur<int> resultat(2);
	resultat(1)=lignes;
	resultat(2)=colonnes;
	return resultat;
};

//# FONCTIONS #
//-------------



//############
//# VECTEURS #
//############


//-----------------
//# CONSTRUCTEURS #

template <class T> Vecteur<T>::Vecteur()
{
    lignes=0;
    element=new T[0];
};

template <class T> Vecteur<T>::Vecteur(int longueur)
{
    lignes=longueur;
    element=new T[lignes];
};

template <class T> Vecteur<T>::Vecteur(int longueur, T* val)
{
    lignes=longueur;
    element=new T[lignes];
    for (int i=0; i<lignes; i++)
        element[i]=val[i];
};

template <class T> Vecteur<T>::Vecteur(Vecteur<T>& V)
{
    lignes=V.lignes;
    element=new T[lignes];
    for (int i=0; i<lignes; i++)
        element[i]=V[i+1];
};

//# CONSTRUCTEURS #
//-----------------


//---------------
//# DESTRUCTEUR #

template <class T> Vecteur<T>::~Vecteur()
{
    delete [] element;
};

//# DESTRUCTEUR #
//---------------


//--------------
//# OPERATEURS #
// Definition des operateurs suivants: [] * + - =

template <class T> T& Vecteur<T>::operator[] (int indice)
{
    return element[indice-1];
};

template <class T> T& Vecteur<T>::operator() (int indice)
{
    return element[indice-1];
};

template <class T> Vecteur<T> operator* (T x, Vecteur<T>& V)
{
    Vecteur<T> resultat(V);
    for (int i=1; i<=V.lignes; i++)
            resultat(i)=x*(resultat(i));
    return resultat;
};

template <class T> T Vecteur<T>::operator* (Vecteur<T> &V)
{
    T resultat(0);
    for (int i=0; i<lignes; i++)
        resultat=resultat+element[i]*V[i+1];
    return resultat;
};

template <class T> Vecteur<T> Vecteur<T>::operator+(Vecteur<T>& V)
{
    Vecteur<T> resultat(lignes);
    for (int i=0; i<lignes; i++)
        resultat.element[i]=this->element[i]+V.element[i];
    return resultat;
};

template <class T> Vecteur<T> Vecteur<T>::operator-(Vecteur<T>& V)
{
    Vecteur<T> resultat(lignes);
    for (int i=0; i<lignes; i++)
        resultat.element[i]=this->element[i]-V.element[i];
    return resultat;
};

template <class T> Vecteur<T>& Vecteur<T>::operator= (Vecteur<T> V)
{
    this->lignes=V.lignes;
	delete [] element;
    this->element=new T[this->lignes];
    for (int i=0; i<this->lignes; i++)
        {
            this->element[i]=V.element[i];
        };
    return *this;
};

template <class T> ostream& operator<< (ostream& f, Vecteur<T>& V)
{
    for (int i=0; i<V.lignes; i++)
        f<<V[i+1]<<" ";
    f<<endl;
    return f;
};

//# OPERATEURS #
//--------------


//-------------
//# FONCTIONS #

template <class T> void Vecteur<T>::afficher()
{
    for (int i=0; i<lignes; i++)
        cout<<element[i]<<" ";
    cout<<endl;
};

/*double Vecteur<double>::norme()
{
    double resultat=0;
    for (int i=0; i<lignes; i++)
        resultat=resultat+element[i]^2;
    return sqrt(resultat);
};*/

template <class T> int Vecteur<T>::longueur()
{
	return lignes;
};

template <class T> int Vecteur<T>::taille()
{
	return lignes;
};

//# FONCTIONS #
//-------------
