# ksvm
# SVM utility codes generated by James are collected. 

import numpy as np
import pandas as pd
from sklearn import model_selection, svm

class GridSVRPrecomp():
    @staticmethod
    def get_r2_mean_std(r2_df):
        r2_df_g = r2_df.groupby(["C"])
        r2_mean = r2_df_g.mean()
        r2_std = r2_df_g.std()
        return r2_mean, r2_std 

    def __init__(self, Aall, yall, C_a=np.logspace(0,3,4), epsilon=0.1, n_splits=5, disp=False):
        self.Aall = Aall
        self.yall = yall
        self.C_a = C_a
        self.n_splits = n_splits
        self.epsilon = epsilon
        self.disp = disp

    def calc(self):
        """
        Aall <- kernel matrix of X
        yall <- equivalent to y
        """
        Aall = self.Aall
        yall = self.yall
        C_a = self.C_a
        n_splits = self.n_splits  
        epsilon = self.epsilon      
        disp = self.disp

        df_l = list()
        KF = model_selection.KFold(n_splits=n_splits, shuffle=True)
        for C in C_a:
            for it, (tr, te) in enumerate(KF.split(Aall)):
                r, e = np.array(tr).reshape(-1,1), np.array(te).reshape(-1,1)
                Atr = Aall[r,r.T]
                ytr = yall[tr]
                Atetr = Aall[e,r.T]
                yte = yall[te]

                ms = svm.SVR(kernel='precomputed', C=C, epsilon=epsilon)
                ms.fit(Atr, ytr)
                r2_tr = ms.score(Atr, ytr)
                r2_te = ms.score(Atetr, yte)
                if(disp): print( C, r2_tr, r2_te)
                df_i = pd.DataFrame()
                df_i["C"] = [C]
                df_i["unit"] = [it]
                df_i["r2_tr"] = [r2_tr]
                df_i["r2_te"] = [r2_te]
                df_l.append( df_i)
            if(disp):
                print('--------------')
            self.r2_df = pd.concat(df_l, ignore_index=True)
        return self

    def get_r2(self):
        """
        Return
        ------
        r2_mean, mean of r2_df
        r2_std, std of r2_df
        """
        r2_df = self.r2_df
        return GridSVRPrecomp.get_r2_mean_std(r2_df)
