# Libraries.
import sys
import numpy as np

# Test function phi.
def test_phi(phi):
    """This function tests the implementation of the function phi to transform
    the data from 2D to 3D. """

    # Test 1.
    sys.stdout.write("Checking implementation\n")
    sys.stdout.write(">> Running test 1 ... ")
    X = np.array([[1,2,3,1],[4,5,6,1]]).T
    Z = phi(X)
    val = np.sum(Z)
    assert np.isclose(val, 116), 'The sum of element in Z should return %s, but returned %s \n' % (str(116), str(val))
    sys.stdout.write(" ok\n")

    # Test 2.
    sys.stdout.write(">> Running test 2 ... ")
    X = np.array([[11,0,3],[-4,1,0]]).T
    Z = phi(X)
    val = np.sum(Z)
    assert np.isclose(val, 158), 'The sum of element in Z should return %s, but returned %s \n' % (str(158), str(val))
    sys.stdout.write(" ok\n")

    sys.stdout.write("The exercise is correct. Well done !!!\n")

# Test kernel.
def test_kernel(kernel):
    """This function tests the implementation of kernel function. """

    # Function phi.
    def phi(x):
        x1 = x[0,0]
        x2 = x[0,1]
        return np.array([[x1, x2, x1**2 + x2**2]])

    # Test 1.
    sys.stdout.write("Checking implementation \n")
    sys.stdout.write("Run test 1 ... ")
    xa = np.array([[10, 2]])
    xb = np.array([[1, 3]])
    k = kernel(xa, xb, phi)
    assert np.isclose(k, 1056), 'The kernel value should return %s, but returned %s \n' % (str(1056), str(k))
    sys.stdout.write(" ok\n")

    # Test 2.
    sys.stdout.write("Run test 2 ... ")
    xa = np.array([[-2, 0]])
    xb = np.array([[3, 5]])
    k = kernel(xa, xb, phi)
    assert np.isclose(k, 130), 'The kernel value should return %s, but returned %s \n' % (str(130), str(k))
    sys.stdout.write(" ok\n")

    sys.stdout.write("The exercise is correct. Well done !!!\n")

# Test phi poly
def test_phi_poly(phi):
    """This function tests the implementation of the function phi-poly. """

    # Test 1.
    sys.stdout.write("Checking implementation\n")
    sys.stdout.write("Run test 1 ...")
    xa = np.array([[10, 2]])
    z = phi(xa)
    assert np.isclose(z[0,0], 100), 'The output z1 should be %s, but returned %s \n' % (str(100), str(z[0,0]))
    assert np.isclose(z[0,1], 28.284), 'The output z2 should be %s, but returned %s \n' % (str(28.284), str(z[0,1]))
    assert np.isclose(z[0,2], 4), 'The output z3 should be %s, but returned %s \n' % (str(4), str(z[0,2]))
    sys.stdout.write(" ok\n")

    # Test 2.
    sys.stdout.write("Run test 2 ...")
    xa = np.array([[3, -5]])
    z = phi(xa)
    assert np.isclose(z[0,0], 9), 'The output z1 should be %s, but returned %s \n' % (str(9), str(z[0,0]))
    assert np.isclose(z[0,1], -21.213), 'The output z2 should be %s, but returned %s \n' % (str(-21.213), str(z[0,1]))
    assert np.isclose(z[0,2], 25), 'The output z3 should be %s, but returned %s \n' % (str(25), str(z[0,2]))
    sys.stdout.write(" ok\n")

    sys.stdout.write("The exercise is correct. Well done !!!\n")

# Test polynomial kernel.
def test_kernel_poly(kernel_poly):
    """This function tests the implementation of the polynomial kernel. """

    # Test 1.
    sys.stdout.write("Checking implementation\n")
    sys.stdout.write("Run test 1 ...")
    xa = np.array([[10, 2]])
    xb = np.array([[2, 9]])
    k = kernel_poly(xa, xb, p=3, c=0)
    assert np.isclose(k, 54872), 'The kernel output should be %s, but returned %s \n' % (str(54872), str(k))
    sys.stdout.write(" ok\n")

    # Test 2.
    sys.stdout.write("Run test 2 ...")
    xa = np.array([[0.1, -2.0]])
    xb = np.array([[3.5, 0.3]])
    k = kernel_poly(xa, xb, p=2, c=2)
    assert np.isclose(k, 3.0625), 'The kernel output should be %s, but returned %s \n' % (str(3.0625), str(k))
    sys.stdout.write(" ok\n")

    sys.stdout.write("The exercise is correct. Well done !!!\n")

# Test RBF kernel.
def test_kernel_rbf(kernel_rbf):
    """This function tests the implementation of the RBF kernel. """

    # Test 1.
    sys.stdout.write("Checking implementation\n")
    sys.stdout.write("Run test 1 ...")
    xa = np.array([[0.2, 0.5]])
    xb = np.array([[0.25, 0.4]])
    k = kernel_rbf(xa, xb, gamma=1)
    assert np.isclose(k, 0.987577), 'The kernel output should be %s, but returned %s \n' % (str(0.987577), str(k))
    sys.stdout.write(" ok\n")

    # Test 2.
    sys.stdout.write("Run test 2 ...")
    xa = np.array([[2.1, 2.0]])
    xb = np.array([[3.5, 1.3]])
    k = kernel_rbf(xa, xb, gamma=2.5)
    assert np.isclose(k, 0.00218749), 'The kernel output should be %s, but returned %s \n' % (str(0.00218749), str(k))
    sys.stdout.write(" ok\n")

    sys.stdout.write("The exercise is correct. Well done !!!\n")

# Test transform data.
def test_transf_kernel(Z):
    """This function tests the implementation of transform function. """

    sys.stdout.write("Checking implementation ... ")
    k = np.sum(Z)
    assert np.isclose(k, 216.432, atol=0.1), 'The sum of the elements of Z should be %s, but returned %s \n' % (str(216.432), str(k))
    sys.stdout.write(" ok\n")

    sys.stdout.write("The exercise is correct. Well done !!!\n")


