from aux_sys_err_prediction_module.additive.R_runmed_spline.my_R_runmed_spline_fit import R_runmed_smooth_spline
from numpy import random, array, median, zeros, arange, hstack

from win32com.client import Dispatch
import math

myName = 'R_runmed_spline'
useMAD = True  # use median absolute deviations instead of sum of squared residues


# -----------------------------------------------------------------------
def R_runmed_spline_MAIN(ARG3, Controller):
    pars = Controller.updatedSettings['refiningPars']['regressionSettings'][myName]

    # ARG3
    x = ARG3[0][0]
    y = ARG3[0][1]

    sc = Dispatch("StatConnectorSrv.StatConnector")
    sc.Init("R")

    # get the best smoothing parameter
    bestSpar = R_runmed_spline_KCV_OPTIMIZATION(x, y, sc=sc, **pars)

    # get the prediction error for this smoothing parameter
    bestPredErr = R_runmed_spline_KCV_predErr(x, y, spar=bestSpar, sc=sc, **pars)

    # compare with original SSE
    # is fit successful?
    # return isSuccessfulFit, yFit, yEval, runMedData
    SSE = sum(y ** 2)
    MAD = 1.4826 * median(abs(y))
    if useMAD:
        SSE = MAD
    if bestPredErr < SSE:
        isSuccessfulFit = True
        #
        ppmArrs = [[] for i in range(len(ARG3))]
        for ind in range(len(ARG3)):
            x = ARG3[ind][0]
            y = ARG3[ind][1]
            xEval = ARG3[ind][2]
            #
            yFit, runMedData = R_runmed_smooth_spline(x, y, x, spar=bestSpar, sc=sc, **pars)
            yEval, runMedData = R_runmed_smooth_spline(x, y, xEval, spar=bestSpar, sc=sc, **pars)
            #
            ppmArrs[ind] = [yFit, yEval]
    else:
        isSuccessfulFit = False
        #
        ppmArrs = [[] for i in range(len(ARG3))]
        for ind in range(len(ARG3)):
            x = ARG3[ind][0]
            y = ARG3[ind][1]
            xEval = ARG3[ind][2]
            #
            yFit = zeros(len(x), 'd')
            yEval = zeros(len(xEval), 'd')
            #
            ppmArrs[ind] = [yFit, yEval]

    sc.Close()

    return isSuccessfulFit, bestPredErr, ppmArrs


# -----------------------------------------------------------------------


# -----------------------------------------------------------------------
def R_runmed_spline_KCV_OPTIMIZATION(x, y, sc, **pars):
    sparRange = array([float(i) for i in pars['spar range'].split(',')])
    sparStepsNum = int(pars['spar steps number'])
    sparStep = round((sparRange[1] - sparRange[0]) / sparStepsNum, 5)
    sparSet = arange(sparRange[0], sparRange[1], sparStep)

    predErrSet = zeros(len(sparSet), 'd')
    for i in range(len(sparSet)):
        predErr = R_runmed_spline_KCV_predErr(x, y, spar=sparSet[i], sc=sc, **pars)
        predErrSet[i] = predErr

    ##    p(zip(sparSet, predErrSet))
    spar = sparSet[predErrSet == min(predErrSet)][-1]  # take the last one (smoothest) if there are few
    ##    print('spar ', spar)

    return spar


# -----------------------------------------------------------------------


# -----------------------------------------------------------------------
def R_runmed_spline_KCV_predErr(x, y, **kwargs):
    """
    just returns the prediction error
    """
    K = int(kwargs['K'])
    # --Related to K-fold CV---------------------------
    L = len(x)
    N = L / K  ##min length of pieces
    W = list(range(L))
    Z = list(range(1, K + 1))
    Z = [N for j in Z]
    R = L % K
    Z[0:R] = [j + 1 for j in Z[0:R]]  # length of the pieces
    random.shuffle(W)
    ind = 0
    predErr = 0
    allResiduals = array([])
    SSE = sum(y ** 2)  # VLAD. Why do I need this???
    # ---running through K training/testings-------------
    for val in Z:
        j = math.floor(val)

        # ---making training/testing subsets-------------
        test = W[ind:ind + j]
        test.sort()
        train = W[0:ind] + W[ind + j:]
        train.sort()
        ind += j
        # -----------------------------------------------

        # ---fit runmed_spline here----------------------
        yFit, runMed = R_runmed_smooth_spline(x[train], y[train], x[test], **kwargs)
        residualsTest = y[test] - yFit
        predErr += sum(residualsTest ** 2)
        allResiduals = hstack((allResiduals, residualsTest))
        # -----------------------------------------------

    if useMAD:
        predErr = 1.4826 * median(abs(allResiduals))

    return predErr


# -----------------------------------------------------------------------


if __name__ == '__main__':
    from numpy import linspace, cos, lexsort, zeros, sin
    from pylab import plot, show, subplot, savefig, clf, ylim
    from pprint import pprint as p
    from time import clock as c

    x1 = linspace(0, 30, 300)
    ##    y1 = cos(x1)
    ##    y1 = zeros(len(x1),'d') #nice test
    y1 = x1 * 0.03

    y1 += random.normal(scale=0.2, size=y1.shape)
    ind = lexsort(keys=(y1, x1))
    x1 = x1[ind]
    y1 = y1[ind]

    t1 = c()
    isSuccessfulFit, yFit, yEval, runMedData, predErr = \
        R_runmed_spline_MAIN(x1, y1, x1, runMedSpan=0.01, K=10, sparRange=[0.6, 1.1, 0.1])
    t2 = c()
    print('done in %s seconds' % (t2 - t1))

    subplot(211)
    plot(x1, y1, 'bo')
    plot(runMedData[0], runMedData[1], 'y^')
    plot(x1, yEval, 'r+-')
    ylim([-1.5, +1.5])
    subplot(212)
    plot(x1, y1 - yEval, 'go')
    ylim([-1.5, +1.5])
    show()

[((19, 9, 19, 51), 'win32com.client.Dispatch', 'Dispatch', ({(19, 18, 19, 50): '"""StatConnectorSrv.StatConnector"""'}, {}), "('StatConnectorSrv.StatConnector')", False, 'from win32com.client import Dispatch\n'), ((75, 14, 75, 58), 'numpy.arange', 'arange', ({(75, 21, 75, 33): 'sparRange[0]', (75, 35, 75, 47): 'sparRange[1]', (75, 49, 75, 57): 'sparStep'}, {}), '(sparRange[0], sparRange[1], sparStep)', False, 'from numpy import random, array, median, zeros, arange, hstack\n'), ((106, 4, 106, 21), 'numpy.random.shuffle', 'random.shuffle', ({(106, 19, 106, 20): 'W'}, {}), '(W)', False, 'from numpy import random, array, median, zeros, arange, hstack\n'), ((109, 19, 109, 28), 'numpy.array', 'array', ({(109, 25, 109, 27): '[]'}, {}), '([])', False, 'from numpy import random, array, median, zeros, arange, hstack\n'), ((145, 9, 145, 29), 'numpy.linspace', 'linspace', ({(145, 18, 145, 19): '0', (145, 21, 145, 23): '30', (145, 25, 145, 28): '300'}, {}), '(0, 30, 300)', False, 'from numpy import linspace, cos, lexsort, zeros, sin\n'), ((150, 10, 150, 49), 'numpy.random.normal', 'random.normal', (), '', False, 'from numpy import random, array, median, zeros, arange, hstack\n'), ((151, 10, 151, 32), 'numpy.lexsort', 'lexsort', (), '', False, 'from numpy import linspace, cos, lexsort, zeros, sin\n'), ((155, 9, 155, 12), 'time.clock', 'c', ({}, {}), '()', True, 'from time import clock as c\n'), ((158, 9, 158, 12), 'time.clock', 'c', ({}, {}), '()', True, 'from time import clock as c\n'), ((161, 4, 161, 16), 'pylab.subplot', 'subplot', ({(161, 12, 161, 15): '(211)'}, {}), '(211)', False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((162, 4, 162, 22), 'pylab.plot', 'plot', ({(162, 9, 162, 11): 'x1', (162, 13, 162, 15): 'y1', (162, 17, 162, 21): '"""bo"""'}, {}), "(x1, y1, 'bo')", False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((163, 4, 163, 44), 'pylab.plot', 'plot', ({(163, 9, 163, 22): 'runMedData[0]', (163, 24, 163, 37): 'runMedData[1]', (163, 39, 163, 43): '"""y^"""'}, {}), "(runMedData[0], runMedData[1], 'y^')", False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((164, 4, 164, 26), 'pylab.plot', 'plot', ({(164, 9, 164, 11): 'x1', (164, 13, 164, 18): 'yEval', (164, 20, 164, 25): '"""r+-"""'}, {}), "(x1, yEval, 'r+-')", False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((165, 4, 165, 22), 'pylab.ylim', 'ylim', ({(165, 9, 165, 21): '[-1.5, +1.5]'}, {}), '([-1.5, +1.5])', False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((166, 4, 166, 16), 'pylab.subplot', 'subplot', ({(166, 12, 166, 15): '(212)'}, {}), '(212)', False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((167, 4, 167, 30), 'pylab.plot', 'plot', ({(167, 9, 167, 11): 'x1', (167, 13, 167, 23): '(y1 - yEval)', (167, 25, 167, 29): '"""go"""'}, {}), "(x1, y1 - yEval, 'go')", False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((168, 4, 168, 22), 'pylab.ylim', 'ylim', ({(168, 9, 168, 21): '[-1.5, +1.5]'}, {}), '([-1.5, +1.5])', False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((169, 4, 169, 10), 'pylab.show', 'show', ({}, {}), '()', False, 'from pylab import plot, show, subplot, savefig, clf, ylim\n'), ((113, 12, 113, 27), 'math.floor', 'math.floor', ({(113, 23, 113, 26): 'val'}, {}), '(val)', False, 'import math\n'), ((124, 23, 124, 84), 'aux_sys_err_prediction_module.additive.R_runmed_spline.my_R_runmed_spline_fit.R_runmed_smooth_spline', 'R_runmed_smooth_spline', ({(124, 46, 124, 54): 'x[train]', (124, 56, 124, 64): 'y[train]', (124, 66, 124, 73): 'x[test]'}, {}), '(x[train], y[train], x[test], **kwargs)', False, 'from aux_sys_err_prediction_module.additive.R_runmed_spline.my_R_runmed_spline_fit import R_runmed_smooth_spline\n'), ((127, 23, 127, 60), 'numpy.hstack', 'hstack', ({(127, 30, 127, 59): '(allResiduals, residualsTest)'}, {}), '((allResiduals, residualsTest))', False, 'from numpy import random, array, median, zeros, arange, hstack\n'), ((44, 31, 44, 92), 'aux_sys_err_prediction_module.additive.R_runmed_spline.my_R_runmed_spline_fit.R_runmed_smooth_spline', 'R_runmed_smooth_spline', (), '', False, 'from aux_sys_err_prediction_module.additive.R_runmed_spline.my_R_runmed_spline_fit import R_runmed_smooth_spline\n'), ((45, 32, 45, 97), 'aux_sys_err_prediction_module.additive.R_runmed_spline.my_R_runmed_spline_fit.R_runmed_smooth_spline', 'R_runmed_smooth_spline', (), '', False, 'from aux_sys_err_prediction_module.additive.R_runmed_spline.my_R_runmed_spline_fit import R_runmed_smooth_spline\n')]