#include "outputCouche.h"

OutputCouche::OutputCouche() : Couche(){
    //cout << "    Create empty PrevChange Matrix [in OutputCouche()]\n";
    prevChange = SynapseMatrix();
    //cout << "    Done\n";
}

OutputCouche::OutputCouche(const unsigned int nbr,const HiddenCouche *prev) : Couche(nbr,NULL){
    prevCouche = prev;
    if(prev)
        prevChange = SynapseMatrix(prev->getNumber(),getNumber());
    else
        prevChange = SynapseMatrix();
}

void OutputCouche::setPrevCouche(const HiddenCouche *prev){
    prevCouche = prev;
    //cout << "    Create Synapse PrevChange [in OutputCouche.setPrevCouche(const HiddenCouche *prev)]\n";
    prevChange = SynapseMatrix(prev->getNumber(),getNumber());
    //cout << prevChange;
    //cout << "    Done\n";
}

void OutputCouche::activate(){
    unsigned int prevSize = prevCouche->getNumber();
    unsigned int thisSize = getNumber();
 
    double sum;
    for(unsigned int i=0; i < thisSize ; ++i){
        sum = 0.0;
        for(unsigned int j=0; j < prevSize ; ++j){
            sum += (*prevCouche)[j].getWeight() * (*prevCouche).getSynapse(j,i).getWeight();
        }
        (*this)[i] = util.sigmoid(sum);
    }
 
}

void OutputCouche::backPropagate(const std::vector<double> deltaOutput){
    unsigned int prevSize = prevCouche->getNumber();
    unsigned int thisSize = getNumber();
    double change;
    for(unsigned int i=0; i < prevSize ; ++i){
        for(unsigned int j=0; j < thisSize ; ++j){
            change = (deltaOutput[j] * (*prevCouche)[i].getWeight());
            (*prevCouche).getSynapse(i,j) = (*prevCouche).getSynapse(i,j).getWeight() + LEARNING_RATE*change + MOMENTUM*getChange(i,j);
            prevChange(i,j) = change;
        }
    }
}

double OutputCouche::getChange(const unsigned int neurPrevCouche,const unsigned int neurThisCouche) const throw(const unsigned int, std::string){
    return prevChange(neurPrevCouche,neurThisCouche).getWeight();
}
void OutputCouche::printMatrix(){
    cout << prevChange;
}

OutputCouche& OutputCouche::operator=(const OutputCouche& c){
    if(this!=&c){
        Couche::operator=(c);
        prevChange = c.prevChange;
    }
    return (*this);
};
