/*!
 * 
 *
 * \brief       -
 *
 * \author      O.Krause
 * \date        2011
 *
 *
 * \par Copyright 1995-2015 Shark Development Team
 * 
 * <BR><HR>
 * This file is part of Shark.
 * <http://image.diku.dk/shark/>
 * 
 * Shark is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published 
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Shark is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with Shark.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
#ifndef MODELS_IMPL_NEURONS_H
#define MODELS_IMPL_NEURONS_H

#include <shark/LinAlg/Base.h>

 
namespace shark{
namespace detail{
	///\brief Baseclass for all Neurons. it defines y=operator(x) for evaluation and derivative(y) for the derivative of the sigmoid.
	///
	///You need to provide a public static member function function() and functionDerivative() in the derived class.
	///Those functions calculate value and derivative for a single input.
	///Due to template magic, the neurons can either use vectors or matrices as input.
	///Additionally, they avoid temporary values completely using ublas magic.
	///Usage: 
	///struct Neuron:public NeuronBase<Neuron> { 
	///    static double function(double x){return ...}
        ///    static double functionDerivative(double y){return ...}
	///};
	template<class Derived>
	//again, one step ahead using templates!
	class NeuronBase{
	private:
		template<class T>
		struct Function{
			typedef T argument_type;
			typedef argument_type result_type;
			static const bool zero_identity = false;

			result_type operator()(argument_type x)const{
				return Derived::function(x);
			}
		};
		template<class T>
		struct FunctionDerivative{
			typedef T argument_type;
			typedef argument_type result_type;
			static const bool zero_identity = false;

			result_type operator()(argument_type x)const{
				return Derived::functionDerivative(x);
			}
		};
	public:
		
		///for a given input vector, calculates the elementwise application of the sigmoid function defined by Derived.
		template<class E>
		vector_unary<E, Function<typename E::value_type> > operator()(blas::vector_expression<E> const& x)const{
			typedef Function<typename E::value_type> functor_type;
			return vector_unary<E, functor_type >(x,functor_type());
		}
		///for a given batch of input vectors, calculates the elementwise application of the sigmoid function defined by Derived.
		template<class E>
		matrix_unary<E, Function<typename E::value_type> > operator()(blas::matrix_expression<E> const& x)const{
			typedef Function<typename E::value_type> functor_type;
			return matrix_unary<E, functor_type >(x,functor_type());
		}
		///Calculates the elementwise application of the sigmoid function derivative defined by Derived.
		///It's input is a matrix or vector of previously calculated neuron responses generated by operator()
		template<class E>
		vector_unary<E, FunctionDerivative<typename E::value_type> > derivative(blas::vector_expression<E> const& x)const{
			typedef FunctionDerivative<typename E::value_type> functor_type;
			return vector_unary<E, functor_type >(x,functor_type());
		}
		///Calculates the elementwise application of the sigmoid function derivative defined by Derived.
		///It's input is a matrix or vector of previously calculated neuron responses generated by operator()
		template<class E>
		matrix_unary<E, FunctionDerivative<typename E::value_type> > derivative(blas::matrix_expression<E> const& x)const{
			typedef FunctionDerivative<typename E::value_type> functor_type;
			return matrix_unary<E, functor_type >(x,functor_type());
		}
	};
}
	 
}
 
 #endif
