from svmutil import *
import re


class SVMInterpolant:
    def __init__(self, sample_file, degree, mid_output, output, C=10, gamma=1, coef0=1):
        self.X = []
        self.y = []
        self.degree = degree
        self.output = output
        self.mid_output = mid_output
        self.C = C
        self.gamma = gamma
        self.coef0 = coef0
        self.clf = None
        with open(sample_file) as phi:
            while True:
                line = phi.readline()
                line = line.strip()
                if not line:
                    break
                lines = re.split(pattern=',| +|\t', string=line)
                self.X.append([float(eval(item.strip().replace('^','**'))) for item in lines[:-1]])
                self.y.append(int(lines[-1]))

    def train(self):
        C = self.C
        gamma = self.gamma
        coef0 = self.coef0
        degree = self.degree
        positive_negative = self.y.count(1)/self.y.count(-1)
        self.clf = svm_train(self.y, self.X,
                        '-c {C} -t 1 -d {degree} -r {coef0} -g {gamma} -w1 {w1} -w-1 {w_1} -e 0.0000001'.format(C=C, degree=degree, coef0=coef0,
                                                                               gamma=gamma, w1=1, w_1=positive_negative))
        svm_save_model(self.mid_output, self.clf)

    def test(self):
        p_label, p_acc, p_val = svm_predict(self.y, self.X, self.clf)
        if p_acc[0] != 100.0:
            with open('.exitcode', mode='w') as exitcode:
                exitcode.write('1')
            return 1
        return 0

    @staticmethod
    def post_number(number_str):
        if 'e' in number_str:
            return number_str.replace('e', '*10^(') + ')'
        else:
            return number_str

    def post_process(self):
        with open(self.mid_output) as model_file:
            with open(self.output, mode='w+') as out:
                parameters = {}
                for i in range(0, 10):
                    line = model_file.readline()[:-1]
                    lines = re.split(pattern=',| +|\t', string=line)
                    parameters[lines[0]] = lines[1]
                kernel = 'kernel[x_,y_]:=({gamma}*Sum[x[[i]]*y[[i]],{{i,1,Length[x]}}]+{coef0})^{degree};'.format(
                    gamma=self.post_number(parameters['gamma']),
                    coef0=self.post_number(parameters['coef0']),
                    degree=self.post_number(parameters['degree']))
                b = 'bias=-1*(' + self.post_number(parameters['rho']) + ');'
                total_sv = int(parameters['total_sv'])
                # read a line only contain SV
                model_file.readline()
                alphay = []
                xlist = []
                for i in range(0, total_sv):
                    line = model_file.readline().strip()
                    lines = line.split(' ')
                    alphay.append(self.post_number(lines[0]))
                    vec = []
                    for j in range(1, len(lines)):
                        var = lines[j]
                        var = var.split(':')[1]
                        vec.append(self.post_number(var))
                    xlist.append(vec)

                out.write(kernel + '\n')
                out.write(b + '\n')
                out.write(('alphay=' + str(alphay) + ';\n').replace('[', '{').replace(']', '}').replace('\'', ''))
                out.write(('xlist=' + str(xlist) + ';').replace('[', '{').replace(']', '}').replace('\'', ''))


if __name__ == '__main__':
    print(SVMInterpolant.post_number('7'))
