//
// Created by fluffymoo on 11.6.18.
//


#include "NeuronLogistic.h"

NeuronLogistic_d2::NeuronLogistic_d2( ) {}

double NeuronLogistic_d2::activate( double x, double b ) {
    //(e^(b + x) (e^b - e^x))/(e^b + e^x)^3

    double ex = std::pow(E, x);
    double eb = std::pow(E, b);
    double denom = (eb + ex);

    return (eb*ex*(eb - ex))/(denom*denom*denom);
}

double NeuronLogistic_d2::activation_function_eval_derivative_bias( double x, double b ) {
    //-(e^(b + x) (-4 e^(b + x) + e^(2 b) + e^(2 x)))/(e^b + e^x)^4

    double eb = std::pow(E, b);
    double ex = std::pow(E, x);
    double ebex = eb * ex;
    double denom = (eb + ex);

    return  -(ebex*(-4*ebex + eb*eb +ex*ex))/(denom*denom*denom*denom);
}

double NeuronLogistic_d2::activation_function_eval_derivative( double x, double b ) {
    //(e^(b + x) (-4 e^(b + x) + e^(2 b) + e^(2 x)))/(e^b + e^x)^4
    return -this->activation_function_eval_derivative_bias( x, b );
}

NeuronLogistic* NeuronLogistic_d2::get_derivative() {
    //TODO maybe not the best way
    return nullptr;
}

NeuronLogistic_d1::NeuronLogistic_d1( ) {}


double NeuronLogistic_d1::activate( double x, double b ) {
    //e^(b - x)/(e^(b - x) + 1)^2

    double ex = std::pow(E, x);
    double eb = std::pow(E, b);
    double d = (eb/ex);
    double denom = (d + 1);

    return d/(denom*denom);
}

double NeuronLogistic_d1::activation_function_eval_derivative_bias( double x, double b ) {
    //(e^(b + x) (e^x - e^b))/(e^b + e^x)^3

    double ex = std::pow(E, x);
    double eb = std::pow(E, b);
    double denom = (eb + ex);

    return (eb*ex* (ex - eb))/(denom*denom*denom);
}

double NeuronLogistic_d1::activation_function_eval_derivative( double x, double b ) {
    //(e^(b + x) (e^b - e^x))/(e^b + e^x)^3
    return -this->activation_function_eval_derivative_bias( x, b );
}

NeuronLogistic* NeuronLogistic_d1::get_derivative( ) {
    //(e^(b + x) (e^b - e^x))/(e^b + e^x)^3
    NeuronLogistic_d2* output = nullptr;

    output = new NeuronLogistic_d2( );

    return output;
}

NeuronLogistic::NeuronLogistic( ) {}

double NeuronLogistic::activate( double x, double b ) {
    //(1 + e^(-x + b))^(-1)

    double ex = std::pow(E, b - x);
    return 1.0 / (1.0 + ex);
}

double NeuronLogistic::activation_function_eval_derivative_bias( double x, double b ) {
    //-e^(b - x)/(e^(b - x) + 1)^2
    double ex = std::pow(E, b - x);
    double denom = (ex + 1);

    return -ex/(denom*denom);
}


double NeuronLogistic::activation_function_eval_derivative( double x, double b ) {
    //e^(b - x)/(e^(b - x) + 1)^2
    return -this->activation_function_eval_derivative_bias( x, b );

}

NeuronLogistic* NeuronLogistic::get_derivative( ) {

    NeuronLogistic_d1 *output = nullptr;
    output = new NeuronLogistic_d1( );

    return output;

}