# -*- coding: utf-8 -*-
""" Train error functions with derivatives
    
    :Example:
        >>> msef = MSE()
        >>> x = np.array([[1.0, 0.0], [2.0, 0.0]])
        >>> msef(x)
        1.25
        >>> # calc derivative:
        >>> msef.deriv(x[0])
        array([ 1.,  0.])
    
"""

import numpy as np


class MSE():
    """ 
    Mean squared error function 
    
    :Parameters:
        e: ndarray
            current errors: target - output
    :Returns:
        v: float
            Error value
    :Example:
        >>> f = MSE()
        >>> x = np.array([[1.0, 0.0], [2.0, 0.0]])
        >>> f(x)
        1.25
        
    """
    
    def __call__(self, e):
        N = e.size
        v =  np.sum(np.square(e)) / N
        return v
        
    def deriv(self, e):
        """
        Derivative of MSE error function
        
        :Parameters:
            e: ndarray
                current errors: target - output
        :Returns:
            d: ndarray
                Derivative: dE/d_out
        :Example:
            >>> f = MSE()
            >>> x = np.array([1.0, 0.0])
            >>> # calc derivative:
            >>> f.deriv(x)
            array([ 1.,  0.])
        
        """
        
        N = len(e)
        d = e * (2 / N)
        return d


class SSE:
    """ 
    Sum squared error function
    
    :Parameters:
        e: ndarray
            current errors: target - output
    :Returns:
        v: float
            Error value
            
    """
    
    def __call__(self, e):
        v = 0.5 * np.sum(np.square(e))
        return v
    
    def deriv(self, e):
        """
        Derivative of SSE error function
        
        :Parameters:
            e: ndarray
                current errors: target - output
        :Returns:
            d: ndarray
                Derivative: dE/d_out

        """
        return e
        

class SAE:
    """ 
    Sum absolute error function
    
    :Parameters:
        e: ndarray
            current errors: target - output
    :Returns:
        v: float
            Error value
    """
    
    def __call__(self, e):
        v = np.sum(np.abs(e))
        return v
    
    def deriv(self, e):
        """
        Derivative of SAE error function
        
        :Parameters:
            e: ndarray
                current errors: target - output
        :Returns:
            d: ndarray
                Derivative: dE/d_out

        """
        d = np.sign(e)
        return d


class MAE:
    """ 
    Mean absolute error function
    
    :Parameters:
        e: ndarray
            current errors: target - output
    :Returns:
        v: float
            Error value
    """
    
    def __call__(self, e):
        v = np.sum(np.abs(e)) / e.size
        return v
    
    def deriv(self, e):
        """
        Derivative of SAE error function
        
        :Parameters:
            e: ndarray
                current errors: target - output
        :Returns:
            d: ndarray
                Derivative: dE/d_out

        """
        d = np.sign(e) / e.size
        return d