import numpy as np
import math


c_map = [
    [+1, -1, -1, -1, -1, +1, +1, -1, -1, -1, -1, +1, +1, -1, +1, +1, -1, -1, +1, +1, -1, -1, +1, +1, -1, +1, -1, -1, +1, +1],
    [-1, +1, +1, +1, +1, -1, +1, +1, -1, -1, +1, +1, -1, +1, +1, +1, -1, +1, -1, -1, +1, +1, -1, +1, +1, +1, -1, +1, -1, +1],
    [-1, -1, +1, +1, +1, +1, -1, -1, +1, -1, -1, -1, -1, -1, +1, -1, -1, +1, -1, -1, +1, +1, -1, -1, +1, -1, +1, -1, -1, -1],
    [-1, +1, +1, +1, -1, -1, +1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1, +1, +1, -1, -1, -1, -1, +1, +1, +1, -1, +1, -1, +1],
    [+1, -1, -1, -1, -1, -1, +1, -1, +1, +1, -1, -1, +1, -1, +1, +1, +1, -1, +1, -1, -1, +1, +1, +1, +1, -1, +1, +1, -1, +1],
    [+1, +1, +1, -1, -1, -1, +1, +1, -1, +1, -1, -1, +1, +1, +1, -1, +1, -1, -1, +1, +1, +1, -1, -1, +1, +1, -1, +1, -1, +1],
    [-1, -1, -1, -1, +1, +1, -1, +1, +1, +1, +1, -1, -1, +1, -1, +1, +1, -1, -1, +1, +1, -1, +1, -1, +1, +1, -1, -1, +1, -1],
    [-1, +1, +1, -1, -1, +1, +1, +1, +1, -1, -1, -1, +1, -1, -1, +1, -1, +1, +1, -1, +1, +1, +1, -1, +1, -1, +1, -1, -1, -1],
    [-1, +1, +1, +1, -1, -1, -1, -1, -1, -1, +1, +1, -1, -1, -1, -1, +1, +1, -1, +1, -1, +1, +1, +1, +1, -1, +1, +1, -1, -1],
    [+1, +1, +1, +1, -1, +1, -1, +1, +1, -1, -1, -1, +1, -1, +1, +1, -1, -1, -1, +1, -1, +1, -1, +1, -1, +1, +1, +1, -1, +1],
    [-1, -1, +1, -1, +1, +1, -1, +1, +1, +1, -1, -1, +1, -1, -1, -1, -1, +1, -1, -1, -1, +1, -1, -1, +1, +1, -1, -1, -1, -1],
    [+1, -1, -1, +1, +1, -1, -1, -1, -1, -1, +1, -1, -1, -1, -1, -1, -1, +1, +1, +1, +1, +1, +1, -1, +1, -1, -1, +1, +1, -1],
    [-1, +1, +1, +1, -1, -1, -1, -1, -1, -1, -1, +1, +1, -1, +1, -1, -1, -1, +1, -1, +1, +1, -1, -1, -1, +1, +1, +1, -1, +1],
    [-1, +1, +1, -1, +1, -1, -1, +1, -1, +1, +1, -1, +1, +1, -1, +1, +1, -1, -1, +1, +1, +1, -1, -1, -1, +1, +1, +1, -1, -1],
    [-1, -1, +1, +1, +1, +1, -1, +1, -1, +1, +1, +1, +1, -1, +1, -1, +1, +1, -1, -1, +1, -1, -1, +1, -1, +1, -1, +1, -1, +1],
    [-1, -1, -1, -1, +1, +1, -1, +1, +1, -1, +1, +1, +1, -1, +1, -1, +1, +1, +1, -1, -1, +1, +1, +1, -1, +1, -1, +1, -1, +1],
    [-1, -1, +1, -1, -1, -1, +1, -1, -1, +1, -1, +1, -1, +1, -1, +1, +1, -1, +1, +1, +1, +1, -1, -1, -1, +1, -1, +1, -1, -1],
    [-1, +1, +1, +1, +1, -1, -1, -1, +1, +1, +1, +1, +1, -1, +1, -1, +1, +1, -1, +1, -1, -1, +1, +1, +1, -1, -1, -1, -1, -1],
    [+1, +1, +1, +1, -1, -1, +1, +1, -1, +1, +1, -1, -1, +1, +1, +1, -1, -1, -1, -1, -1, -1, -1, -1, +1, -1, +1, +1, -1, +1],
    [+1, -1, -1, +1, -1, +1, +1, -1, +1, -1, -1, -1, -1, +1, +1, -1, -1, +1, +1, -1, -1, +1, +1, +1, +1, +1, +1, +1, -1, +1],
    [-1, +1, -1, -1, -1, -1, -1, +1, +1, -1, -1, +1, -1, +1, -1, -1, +1, +1, -1, +1, -1, +1, -1, -1, +1, +1, +1, -1, +1, +1],
    [+1, -1, -1, +1, +1, +1, -1, -1, +1, +1, -1, +1, +1, -1, +1, -1, +1, -1, +1, +1, +1, +1, -1, -1, -1, +1, +1, -1, +1, +1],
    [+1, +1, -1, +1, -1, +1, +1, +1, -1, -1, +1, -1, -1, -1, -1, -1, -1, +1, -1, -1, -1, +1, -1, +1, -1, -1, -1, +1, -1, +1],
    [+1, -1, +1, -1, -1, +1, -1, +1, -1, +1, +1, +1, +1, +1, +1, +1, +1, -1, -1, -1, +1, +1, +1, +1, +1, +1, +1, -1, +1, -1],
    [+1, -1, -1, -1, +1, -1, -1, -1, -1, -1, +1, -1, +1, -1, +1, +1, -1, +1, -1, -1, +1, -1, -1, -1, +1, -1, -1, +1, -1, -1],
]

labels = [-1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1, +1, -1]
c_map = np.transpose(c_map)


classifiers_map = np.zeros((31, 25))
u = [0] * len(classifiers_map)
for m in range(1, len(classifiers_map)):
    w = [math.exp(-labels[i] * classifiers_map[m - 1][i]) for i in range(len(labels))]
    W = np.sum(w)
    W2 = np.inf
    t = 0
    for j in range(len(c_map)):
        if u[j] == 0:
            Y = 0
            for i in range(len(labels)):
                if not labels[i] == c_map[j][i]:
                    Y += w[i]
            if Y < W2:
                W2 = Y
                t = j
    u[t] = 1
    r = W2 / W
    alpha = 0.5 * math.log((1 - r) / r)
    classifiers_map[m] = [classifiers_map[m - 1][i] + alpha * c_map[t][i] for i in range(len(labels))]
    # Take the sign of each value, subtract that from labels, return the count of zeros in resulting vector
    # (number of values equal to their respective label)
    correct = dict(zip(*np.unique(np.sign(classifiers_map[m]) - np.array(labels), return_counts=True)))[0]
    print("Iter:", m)
    print(np.round(classifiers_map[m], decimals=4))
    print("Score:", correct, "/", len(labels))
    print("t:", t)
    print("W:", W)
    print("W2:", W2)
    print("r:", r)
    print("alpha:", alpha)
    print()


