#include "activ_function.h"
#include <stdio.h>
#include <math.h>


void activ_function::apply(gsl_matrix *m){
	for(unsigned int i = 0; i < m->size1; i++){
		for(unsigned int j = 0; j < m->size2; j++){
			gsl_matrix_set(m, i, j, actFunction(gsl_matrix_get(m, i, j)));
		}
	}
}

void activ_function::apply(gsl_vector *v){
	for(unsigned int i = 0; i < v->size; i++){
		gsl_vector_set(v, i, actFunction(gsl_vector_get(v, i)));
	}
}

void activ_function::applySoftmax(gsl_matrix *m){
	// softmaxova aktivacia, sumuje aktivacie na vrstve do jednotky (pravdepodobnost aktivacie vystupu)
	
	// spocitame menovatel, suma e^net
	for(unsigned int j = 0; j < m->size2; j++){
		double denominator = 0;
		
		for(unsigned int i = 0; i < m->size1; i++){
			denominator += exp(gsl_matrix_get(m, i, j));
		}
		// preskalujeme aktivacie
		for(unsigned int i = 0; i < m->size1; i++){
			gsl_matrix_set(m, i, j, exp(gsl_matrix_get(m, i, j)) / denominator);
		}
	}

}

void activ_function::applySoftmax(gsl_vector *v){
	// softmaxova aktivacia, sumuje aktivacie na vrstve do jednotky (pravdepodobnost aktivacie vystupu)
	double denominator = 0;

	// spocitame menovatel, suma e^net
	for(unsigned int i = 0; i < v->size; i++){
		denominator += exp(gsl_vector_get(v, i));
	}

	// preskalujeme aktivacie
	for(unsigned int i = 0; i < v->size; i++){
		gsl_vector_set(v, i, exp(gsl_vector_get(v, i)) / denominator);
	}
}


double activ_function::actFunction(double x){
	printf("WARNING: EMPTY activation function");
	return 0;
}
double activ_function::actFunction_inv(double x){
	printf("WARNING: EMPTY activation function");
	return 0;
}

double activ_function::actFunction_deriv(double y){
	printf("WARNING: EMPTY activation function");
	return 0;
}

double activ_function_linear::actFunction(double x){
	return x;
}
double activ_function_linear::actFunction_inv(double x){
	return x;
}
double activ_function_linear::actFunction_deriv(double y){
	return 1;
}


double activ_function_tanh::actFunction(double x){
	return tanh(x);
}

double activ_function_tanh::actFunction_inv(double x){
	if(abs(x) < 1)
		return 0.5 * log((1 + x) / (1 - x));
	else{
		printf("WARNING: Invalid input value in activation function");
		return 0;
	}
}

double activ_function_tanh::actFunction_deriv(double y){
	return 1 - y * y;
}

double activ_function_logistic::actFunction(double x){
	return 1 / (1 + pow(exp(1.0), -x));
}

double activ_function_logistic::actFunction_inv(double x){
	return log(x) - log(1 - x);
}

double activ_function_logistic::actFunction_deriv(double y){
	return (1 - y) * y;
}
