#include "reseau.h"

Reseau::Reseau()
	{
	}

Reseau::Reseau(int In, int Hid, int Out)
	{
	In++;	// pour le noeud de bias
	Ocouche=OutputCouche(Out);
	Hcouche=HiddenCouche(Hid,&Ocouche);
	Icouche=InputCouche(In,&Hcouche);
	Ocouche.setPrevCouche(&Hcouche);
	//Icouche.printSynapseMatrix();
	//Hcouche.printSynapseMatrix();
	}
void Reseau::rebuild(int In, int Hid, int Out) // METHODE BOURRAIN SPOTTED 
	{
	In++;
	Ocouche=OutputCouche(Out);
	Hcouche=HiddenCouche(Hid,&Ocouche);
	Icouche=InputCouche(In,&Hcouche);
	Ocouche.setPrevCouche(&Hcouche);
	Icouche.printSynapseMatrix();
	Hcouche.printSynapseMatrix();
	}

Reseau::~Reseau(){
}

void Reseau::saveState(const char* filename) throw(std::string){
    unsigned sizeinput  = Icouche.getNumber();
    unsigned sizehidden = Hcouche.getNumber();
    unsigned sizeoutput = Ocouche.getNumber();
    std::ofstream outFile(filename);
    if(outFile.fail()){
        throw(std::string("Couldn't open output file"));
    }
    outFile << sizeinput << " " << sizehidden << " " << sizeoutput << endl;
    for( unsigned int i=0 ; i < sizeinput ; ++i )
        for( unsigned int j=0 ; j < sizehidden ; ++j )
            outFile << Icouche.getSynapse(i,j).getWeight() << " " << endl;
    for( unsigned int i=0 ; i < sizehidden ; ++i )
        for( unsigned int j=0 ; j < sizeoutput ; ++j )
            outFile << Hcouche.getSynapse(i,j).getWeight() << " " << endl;
    outFile.close();
}

void Reseau::loadState(const char* filename) throw(std::string){
    std::ifstream inpFile(filename);
    unsigned int sizeinput,sizehidden,sizeoutput;
    if(inpFile.fail()){
        cout << "Can't open input file" << endl;
        throw(std::string("Couldn't open output file"));
    }
    if(!(inpFile >> sizeinput >> sizehidden >> sizeoutput))
        cout<<"Super error!!!" << endl;
    if(sizeinput!=Icouche.getNumber() || sizehidden!=Hcouche.getNumber() || sizeoutput != Ocouche.getNumber()){
        throw(std::string("Wrong size of Couche in file"));
    }
    double tmpDouble;
    //for( unsigned int i=0 ; i < sizeinput ; ++i )
    for( unsigned int i=0 ; i < sizeinput ; ++i ){
        for( unsigned int j=0 ; j < sizehidden ; ++j ){
            if(!(inpFile >> tmpDouble)){
                cout << "Input ERROR" << endl;
            }
            Icouche.getSynapse(i,j).setWeight(tmpDouble);
        }
    }

    for( unsigned int i=0 ; i < sizehidden ; ++i ){
        for( unsigned int j=0 ; j < sizeoutput ; ++j ){
           if(!(inpFile >> tmpDouble)){
             cout << "Input ERROR" << endl;
           }
           Hcouche.getSynapse(i,j).setWeight(tmpDouble);
        }
    }
    //cout << "==========After=========" << endl;
    Icouche.printSynapseMatrix();
    inpFile.close();
    //cout << sizeinput << " " << sizehidden << " " << sizeoutput << endl;
}

std::vector<double> Reseau::forward(bool input[])
	{
	std::vector<bool> tmp;
	/* on active les couches */
	for(unsigned i=0;i<(Icouche.getNumber()-1);i++) /* faut passer n-1 brol dans le vecteur d'activation car il y a le neurone de bias ... */
    		{ 
        	tmp.push_back(input[i]);
    		}
	Icouche.activate(tmp);
	Hcouche.activate(Icouche);
	Ocouche.activate();
	/* on place le resultat dans la shm */
	//for(unsigned i=0;i<Ocouche.getNumber();i++) target[i]=util.accept(Ocouche[i].getWeight());
	std::vector<double> resultat;
	for(unsigned i=0;i<Ocouche.getNumber();i++) resultat.push_back(Ocouche[i].getWeight());
	return resultat;
	}
	
void Reseau::backward(bool input[], bool target[])
	{
	std::vector<double> hidDelta;
	std::vector<double> outDelta;
    double error;
    hidDelta.clear();
    outDelta.clear();
	/* Calcul des delta pour la couche OUPUT */
	for(unsigned i=0;i<Ocouche.getNumber();i++)
		{
        error = (double)target[i] - Ocouche[i].getWeight();
		outDelta.push_back(util.dsigmoid(Ocouche[i].getWeight()) * error);
		}
	/* Calcul des delta pour la couche HIDDEN */
	for(unsigned i=0;i<Hcouche.getNumber();i++){
        error = 0.0;
        for(unsigned j=0;j<Ocouche.getNumber();++j){
            error += outDelta[j] * Hcouche.getSynapse(i,j).getWeight();
		}
        hidDelta.push_back(util.dsigmoid(Hcouche[i].getWeight()) * error);
    }
	Ocouche.backPropagate(outDelta);
	Icouche.backPropagate(hidDelta);
	}

void Reseau::initshm()
	{
	if ((shmid = shmget(SHMKEY, sizeof(struct shmdata), 0666)) < 0) 
		{
		perror("Unable to get shm id \n");
		exit(1);
		}
	if ((SData = (struct shmdata *)shmat(shmid, NULL, 0)) == (struct shmdata *) -1) 
		{
		perror("Unable to attach shm segment\n");
		exit(1);
		}
	}

double Reseau::getError(bool target[])
	{
	double error=0.0;
	for(unsigned i=0;i<Ocouche.getNumber();i++)
		{
		error += pow(((double)target[i] - Ocouche[i].getWeight()),2);
		}
	return sqrt(error);
	}
	
double Reseau::learnOne(bool input[], bool target[])
	{
	double error=0;
	forward(input);
	backward(input,target);
	error=getError(target);
	return error;
	}
	
double Reseau::learnAll(std::vector<bool *> inputs, std::vector<bool *> targets)
	{
	double error=0.0;
	unsigned i;
	for(i=0;i<inputs.size();i++)
		{
		error+=learnOne(inputs[i],targets[i]);
		}
	return (double)(error/i);
	}

Reseau& Reseau::operator=(const Reseau& c){
    if(this!=&c){
        Icouche=c.Icouche;
	Hcouche=c.Hcouche;
	Ocouche=c.Ocouche;
	SData=c.SData;
	shmid=c.shmid;
    }
    return *this;
}

/* END */
