import matplotlib.pyplot as plt
import numpy as np

# Define a main() function that prints a data statistics.
def main():
    data = np.loadtxt('data/populations.txt')
    year, hares, lynxes, carrots = data.T  # trick: columns to variables

    plt.axes([0.1, 0.1, 0.5, 0.8])
    plt.plot(year, hares, year, lynxes, year, carrots)
    plt.legend(('Hare', 'Lynx', 'Carrot'), loc=(1.05, 0.5))
    plt.show()

    # calculate mean and std population for each species (column) separately is slower.
    # calculating separately takes ~3.06 µs for each mean operation and on array
    # that contains all the data by axis=0 takes ~4.68 µs
    populations = data[:, 1:]
    print("Means by species: {}".format(populations.mean(axis=0)))
    print("Standard deviation by species: {}".format(populations.std(axis=0)))

    # calculate year when each species had the larges population
    max_populations = np.argmax(populations, axis=0)
    print("Max populations in years: {}".format(year[max_populations]))

    # calculate species that has larges population for each year
    max_species_idx = np.argmax(populations, axis=1)
    max_species = np.array(['H', 'L', 'C'])[max_species_idx]
    print("Max species: {}".format(tuple(zip(year, max_species))))

    # calculate years when any of the populations is above 50000
    above_mask = np.any(np.greater(populations, 50000), axis=1)
    print("Years any population above 50000: {}".format(year[above_mask]))

    # find the top 2 years for each species when they had the lowest populations
    sorted_indices = populations.argsort(axis=0)
    years_sorted = year[sorted_indices]
    print("Two smallest years: {}".format(years_sorted[:2, :]))

    # compare (plot) the change in hare population and the number of lynxes
    hare_gradients = np.gradient(hares)
    plt.axes([0.1, 0.1, 0.7, 0.8])
    plt.plot(year, hare_gradients, year, lynxes)
    plt.legend(('Hare', 'Lynx'), loc=(1.05, 0.5))
    plt.show()

    # calculate correlation
    print("Hares and lynxes correlation: {}".format(np.corrcoef(hare_gradients, lynxes)[0, 1]))

# This is the standard boilerplate that calls the main() function.
if __name__ == '__main__':
    main()


import numpy as np

from numba import jit, njit, prange

def is_symmetric(A, rtol=1e-05, atol=1e-08):
    # https://stackoverflow.com/questions/42908334/checking-if-a-matrix-is-symmetric-in-numpy
    return np.allclose(A, A.T, rtol=rtol, atol=atol)

def is_square(A):
    return A.shape[0] == A.shape[1]

@njit
def vec(A):
    # https://stackoverflow.com/questions/25248290/most-elegant-implementation-of-matlabs-vec-function-in-numpy
    return A.T.ravel().reshape(-1, 1)

def vech(A):
    if not is_square(A):
        raise Exception("It must be a square matrix.")
    return A.T[np.triu_indices_from(A)].reshape(-1, 1)

@njit(fastmath=True)
def kron(A, B=None):
    if B is not None:
        return np.kron(np.ascontiguousarray(A), np.ascontiguousarray(B))
    else:
        return np.kron(np.ascontiguousarray(A), np.ascontiguousarray(A))

@njit(fastmath=True,parallel=False)
def kron_preallocated(A, B, out):
#     #https://stackoverflow.com/questions/56067643/speeding-up-kronecker-products-numpy
    m, n = A.shape
    p, q = B.shape
    for i in prange(m):
        for j in range(p):
            for k in range(n):
                for l in range(q):
                    out[i, j, k, l] = A[i, k] * B[j, l]
    return out

# @njit(fastmath=True)
# def kron_vector(a, b):
#     return np.outer(a, b).reshape(-1, 1)

@njit
def unit_vector(n, i, j, p=None):
    if p is None:
        p = int(0.5 * n * (n + 1))
    u = np.zeros(p)
    i += 1
    j += 1
    u_idx = int((j - 1) * n + i - 0.5 * j * (j - 1)) - 1
    u[u_idx] = 1
    return u.reshape(p, 1)

@njit
def tij_matrix(n, i, j):
    T = np.zeros(shape=(n, n))
    T[i, j] = 1
    T[j, i] = 1
    return T

@njit(parallel=True)
def dup_matrix(n):
    # TODO: Deprecated
    p = int(n * (n + 1) / 2)
    nsq = n ** 2
    DT = np.zeros(shape=(p, nsq))
    for i in prange(n):
        for j in range(i + 1):
            u = unit_vector(n, i, j, p)
            T = tij_matrix(n, i, j)
            DT += u @ vec(T).T
    return DT.T

@njit
def diag_dup_prod(A, premul=True):
    n2, m2 = A.shape
    if premul:
        n = int(np.sqrt(n2))
        return A[::n+1, :]
    else:
        m = int(np.sqrt(m2))
        return A[:, ::m+1]

@njit(parallel=True)
def dupl_cols(n):
    k = 0
    col = np.empty(n ** 2, dtype=np.int32)
    for i in prange(n):
        for j in range(i, n):
            col[i + j * n] = col[j + i * n] = k
            k += 1
    return col

@njit
def duplication(n):
    # TODO: Validar que está funcionando bien!
    col = dupl_cols(n)
    dn = np.zeros((n ** 2, int(n * (n + 1) / 2)), dtype=np.int32)
    for i in range(n ** 2):
        dn[i, col[i]] = 1
    return dn

@njit(fastmath=True, parallel=True)
def kron_diag_dup(A, B):
    assert A.shape[1] == B.shape[1]
    q, n = A.shape
    m, _ = B.shape
    C = np.empty(shape=(m * q, n))
    for i in prange(n):
        C[:, i] = np.outer(A[:, i], B[:, i]).flatten()
    return C

def matrix_properties(a, rtol=1e-05, atol=1e-08):
    assert a.ndim == 2
    print(f"Any NaN? {np.isnan(a).any()}")
    print(f"Any Inf? {np.isinf(a).any()}")
    print(f"Is Square? {is_square(a)}")
    print(f"Is Symmetric? {is_symmetric(a, rtol=rtol, atol=atol)}")


import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
from numpy.linalg import norm
import os
from random import normalvariate
from math import sqrt
FOLDER = "./Dataset/"
FILES = os.listdir(FOLDER)
TEST_DIR = "./Testset/"

def load_images_train_and_test(TEST):
    test=np.asarray(Image.open(TEST)).flatten()
    train=[]
    for name in FILES:
        train.append(np.asarray(Image.open(FOLDER + name)).flatten())
    train= np.array(train)
    return test,train

def normalize(test,train):
    """
    TODO : Normalize test and train and return them properly
    Hint : To calculate mean properly use two arguments version of mean numpy method (https://www.javatpoint.com/numpy-mean)
    Hint : normalize test with train mean
    """
    arr = np.mean(train, axis=0)

    normalized_test = test - arr

    normalized_train = np.empty((0,train.shape[1]))
    for i in range(train.shape[0]):
        normalized_train = np.vstack([normalized_train, (np.array(train[i, :]) - arr)])

    return normalized_test,normalized_train
def svd_function(images):
    """
    TODO : implement SVD (use np.linalg.svd) and return u,s,v
    Additional(Emtiazi) todo : implement svd without using np.linalg.svd
    """
    if iteration == 0:
        return svd(images)
    else:
        return u,s,v
#   return np.linalg.svd(images, full_matrices=False)

def project_and_calculate_weights(img,u):
    """
    TODO : calculate element wise multiplication of img and u . (you can use numpy methods)
    """
    return np.multiply(img, u)

def predict(test,train):
    """
    TODO : Find the most similar face to test among train set by calculating errors and finding the face that has minimum error
    return : index of the data that has minimum error in train dataset
    Hint : error(i) = norm(train[:,i] - test)       (you can use np.linalg.norm)

    """
    min_error = 1_000_000_000
    min_index = 0
    for i in range(train.shape[1]):
        error = np.linalg.norm(train[:,i] - test)
        if error < min_error:
            min_index = i
            min_error = error

    return min_index
def plot_face(tested,predicted):
    """
    TODO : Plot tested image and predicted image . It would be great if you show them next to each other
    with subplot and figures that you learned in matplotlib video in the channel.
    But you are allowed to show them one by one
    """

    f, plt_arr = plt.subplots(1, 2 ,figsize=(7, 3))
    f.suptitle('Result Plots')

    plt_arr[0].imshow(tested, cmap = "gray")
    plt_arr[0].set_title('tested')

    plt_arr[1].imshow(predicted, cmap = "gray")
    plt_arr[1].set_title('predicted')

###################################### SVD part ######################################

def randomUnitVector(n):
    unnormalized = [normalvariate(0, 1) for _ in range(n)]
    theNorm = sqrt(sum(x * x for x in unnormalized))
    return [x / theNorm for x in unnormalized]

def svd_1d(A):
    ''' The one-dimensional SVD
        we use  Power iteration method to calculate svd :
        In fact this algorithm will produce the greatest (in absolute value) eigenvalue of A,
        so with help of this algo we can find eigen values and eigen vectors
        (eigen vectors will be orthogonal) one by one and then construct svd from them.

        In Power iteration method we start with v_0 which might be a random vector.
        At every iteration this vector is updated using following rule:
                v_k+1 = Bv_k / ||Bv_k||
        We’ll continue until result has converged.
        Power method has few assumptions:
         - v_0 has a nonzero component in the direction of an eigenvector associated with the dominant eigenvalue.
           (it means v_0 is NOT orthogonal to the eigenvector)
           Initializing v_0 randomly minimizes possibility that this assumption is not fulfilled.
         - matrix A has dominant eigenvalue which has strictly greater magnitude than other eigenvalues.
        These assumptions guarantee that algorithm converges to a reasonable result.

        So at the end when v_i converges enough this method found dominant singular value/eigenvector and return the eigen vector.
    '''

    n, m = A.shape

    # v_0 = x = random unit vector
    x = randomUnitVector(min(n,m))
    currentV = x

    #v_1 = ?
    lastV = None

    # calculate B according to shape of A so that we smaller size computation
    if n > m:
        B = np.dot(A.T, A)
    else:
        B = np.dot(A, A.T)

    # v_k+1 = Bv_k / ||Bv_k||
    iterations = 0
    epsilon=1e-10
    while True:
        iterations += 1
        lastV = currentV
        currentV = np.dot(B, lastV)
        currentV = currentV / norm(currentV)

        # continue until result has converged (updates are less than threshold).
        # if two normal vector become same then inner product of them will be 1
        if abs(np.dot(currentV, lastV)) > 1 - epsilon:
            return currentV

def svd(A):
    '''
        Compute the singular value decomposition of a matrix A
        using the power method. A is the input matrix, and k
        is the number of singular values you wish to compute.
        If k is None, this computes the full-rank decomposition.
    '''
    A = np.array(A, dtype=float)
    n, m = A.shape
    # save (singular value, u, v) as each element
    svdSoFar = []
    k = min(n, m)

    for i in range(k):
        matrixFor1D = A.copy()

        # remove all previous eigen values and vectors (dominant one) from matrix
        # so the next dominant eigen value and vector won't be repetitive
        # A_next = A-(singular_value)(u)(v.T)
        for singularValue, u, v in svdSoFar[:i]:
            matrixFor1D -= singularValue * np.outer(u, v)

        # 1. find v_i which is the next eigen vector for B = A.T @ A
        # 2. find sigma_i = ||Av_i|| (reason is in the next line)
        # ||Av_i||^2 = (Av_i).T A (Av_i) = (v_i).T @ A.T @ A @ v_i = (v_i).T @ (landa_i * v_i) ==v_i is orthonormal== landa_i = sigma_i ^ 2
        # 3. find u_i = 1/sigma_i * Av_i
        if n > m:
            # 1
            v = svd_1d(matrixFor1D)
            u_unnormalized = np.dot(A, v)
            # 2
            sigma = norm(u_unnormalized)  # next singular value
            # 3
            u = u_unnormalized / sigma
        else:
            u = svd_1d(matrixFor1D)  # next singular vector
            v_unnormalized = np.dot(A.T, u)
            sigma = norm(v_unnormalized)  # next singular value
            v = v_unnormalized / sigma

        # add new (sigma, u, v) we have found
        svdSoFar.append((sigma, u, v))

    singularValues, us, vs = [np.array(x) for x in zip(*svdSoFar)]
    return us.T, singularValues, vs
###################################################################################

true_predicts=0
all_predicts=0
iteration = 0
for TEST_FILE in os.listdir(TEST_DIR):
    # Loading train and test
    test,train=load_images_train_and_test(TEST_DIR+TEST_FILE)
    test,train=normalize(test,train)

    test=test.T
    train=train.T
    test = np.reshape(test, (test.size, 1))

    # Singular value decomposition
    u,s,v=svd_function(train)

    # Weigth for test
    w_test=project_and_calculate_weights(test,u)
    w_test=np.array(w_test, dtype='int8').flatten()

    # Weights for train set
    w_train=[]
    for i in range(train.shape[1]):
        w_i=project_and_calculate_weights(np.reshape(train[:, i], (train[:, i].size, 1)),u)
        w_i=np.array(w_i, dtype='int8').flatten()
        w_train.append(w_i)
    w_train=np.array(w_train).T

    # Predict
    index_of_most_similar_face=predict(w_test,w_train)
    # Showing results
    print("Test : "+TEST_FILE)
    print(f"The predicted face is: {FILES[index_of_most_similar_face]}")
    print("\n***************************\n")

    # Calculating Accuracy
    all_predicts+=1
    if FILES[index_of_most_similar_face].split("-")[0]==TEST_FILE.split("-")[0]:
        true_predicts+=1
        # Plotting correct predictions
        plot_face(Image.open(TEST_DIR+TEST_FILE),Image.open(FOLDER+FILES[index_of_most_similar_face]))
    else:
        # Plotting wrong predictions
        plot_face(Image.open(TEST_DIR+TEST_FILE),Image.open(FOLDER+FILES[index_of_most_similar_face]))
    iteration += 1
# Showing Accuracy
accuracy=true_predicts/all_predicts
print(f'Accuracy : {"{:.2f}".format(accuracy*100)} %')


import csv
import argparse
import numpy as np
import scipy.stats as stats

class data_group:
    def __init__(self, group_name, data_array):
        self.group_name = group_name
        self.data_array = data_array
        self.mean       = np.mean(np.array(data_array))
        self.sem        = stats.sem(np.array(data_array))
        self.sd         = np.std(np.array(data_array))

def data_reader(filename):
    group_list = []
    with open(filename, 'r') as r:
        data_reader = csv.reader(r)
        for row in data_reader:
            group_name = row[0]
            data_array = []
            for data in row[1:]:
                data_array.append(float(data))

            group_list.append(data_group(group_name,data_array))

    return group_list

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--input', type=str, default='testData.csv', help='path to the input csv file (default: testData.csv)')
    parser.add_argument('--confidence', type=float, default=0.95, help='level of significance (default: 0.95)')
    args       = parser.parse_args()
    filename   = args.input
    confidence = args.confidence

    group_list = data_reader(filename)

    for group_xi in group_list:
        print(group_xi.group_name)
        ci = stats.t.interval(confidence, len(group_xi.data_array)-1, loc=group_xi.mean, scale=group_xi.sem)
        print('mean: {}, SD: {}'.format(group_xi.mean, group_xi.sd))
        print('{}% confidence interval: {}'.format(int(confidence*100),ci))
        print(" ")

if __name__ == '__main__':
    main()


import cmath
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import scipy.signal as signal
from ..utils.Autocorrelation import Autocorrelation

sns.set()

class AutocorrelationMethod():

    def __init__(self):
        self.f = None
        self.default_f = np.linspace(0, 0.5, 500)
        self.x = None
        self.p = None
        self.a = None
        self.var_u = None
        self.P = None

        self.r_xx = Autocorrelation()

    def estimate(self, x, f=None, p=2):
        '''
            Estimates P_xx for given signal sequence x.

            Args:
                x (numpy array of doubles): Signal
                f (numpy array of doubles): Frequence
                p (integer): Polinomial order in A(f)
        '''
        # Init values
        self.x = x
        if f is None:
            self.f = self.default_f
        else:
            self.f = f
        self.p = p
        self.P = np.zeros(len(self.f))

        # Estimate autoccorelation
        self.r_xx.estimate(x)

        # Compose matrix Rxx
        Rxx = np.zeros([p, p])
        for i in range(p):
            for j in range(p):
                Rxx[i][j] = self.r_xx[i - j]

        # Compose vector rxx
        rxx_vec = np.zeros([p, 1])
        for i in range(p):
            rxx_vec[i] = self.r_xx[i + 1]

        # Calculate a and append [1] for a[0]
        self.a = np.matmul(-np.linalg.inv(Rxx),
                           rxx_vec)
        self.a = np.append([[1]], self.a, axis=0)

        # Calculate var_u
        self.var_u = 0
        for i in range(p + 1):
            self.var_u += self.a[i] * self.r_xx[-i]

        # Calculate P
        for fi in range(len(self.f)):
            A = 0
            for i in range(p + 1):
                A += self.a[i] * cmath.exp(-1j * 2*cmath.pi * self.f[fi] * i)
            self.P[fi] = self.var_u / pow(abs(A), 2)

    def plot(self):
        '''
            Plots estimated P.
        '''
        # Check if anything is estimated.
        if self.f is None or self.P is None:
            return

        plt.figure()
        plt.semilogy(self.f, self.P)
        plt.title('Autocorrelation method estimation')
        plt.xlabel('f [Hz]')
        plt.ylabel('P')
        plt.show()

    def __getitem__(self, key):
        if key == 'f':
            return self.f
        if key == 'P':
            return self.P
        if key == 'x':
            return self.x
        if key == 'a':
            return self.a
        if key == 'var_u':
            return self.var_u
        if key == 'p':
            return self.p
        return None


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 28 15:41:38 2019

@author: alankar
"""

import numpy as np

def NR_sec(func,x0,tol,verbose,*args): #Newton Raphson
    x_new = 0.
    x_old = x0
    counter = 0
    while(np.abs(x_new-x_old[0])>=tol):
        counter += 1
        #x_new = x_old[1]-func(x_old[1],*args)*((x_old[1]-x_old[0])/(func(x_old[1],*args)-func(x_old[1],*args)))
        x_new = (x_old[0]*func(x_old[1],*args)-x_old[1]*func(x_old[0],*args))/(func(x_old[1],*args)-func(x_old[0],*args))
        x_old[0] = x_old[1]
        x_old[1] = x_new
    if (verbose==True): print("Converged in %d steps"%counter)
    return x_new

omega = 2.662e-6
R = 3.844e8
Mm = 7.348e22
Me = 5.974e24
G = 6.674e-11

def lagr1(r):
    r *= 1e8 #in units of 10^8 m
    return -(omega**2*r)-((G*Me)/r**2)+((G*Mm)/(R-r)**2)

print('Distance of Earth-Moon L1 from earth')
print("r = %.2e AU"%(NR_sec(lagr1,np.array([3.4,3.6]),1e-6,False)*1e8/1.496e+11)) # agrees with the value of L1 for Earth-Moon system available on literature

"""
Output

Distance of Earth-Moon L1 from earth
r = 2.37e-03 AU
"""


import numpy as np

def dct(f, axis=-1):
    """
    Compute the Discrete Cosine Transform over the specified axis.

    :param     f: The input array.
    :param  axis: Axis along which the DCT is computed. The default is over the last axis.
    :return    c: The computed DCT.
    """

    # Size of the input along the specified axis.
    n = f.shape[axis]

    # Create two vectors containing the integers from 0 to n-1.
    i = k = np.arange(n)

    # Compute the x-axis coordinate of the f function.
    x = (2 * i + 1) / (2 * n)

    # Compute the outer product of x and kπ, obtaining the nxn matrix that will
    # form the argument of the cosine.
    arg = np.multiply.outer(x, k * np.pi)

    # Normalization factors.
    alpha = np.where(k == 0, 1 / np.sqrt(n), np.sqrt(2 / n))

    # The orthonormal DCT basis.
    w = alpha * np.cos(arg)

    # Compute the convolution between the input array and the DCT basis.
    # The output contains the amplitude coefficient for every frequency.
    c = np.tensordot(f, w, axes=(axis, 0))

    # `axis` becomes the last dimension in the output of `np.tensordot`.
    # Move it back to its original position so that the output shape matches
    # the input shape.
    c = np.moveaxis(c, -1, axis)

    return c

def dctn(array, axes=None):
    """
    Compute the multidimensional Discrete Cosine Transform over the specified axes.

    :param array: The input array
    :param axes: Axes along which the DCT is computed. The default is over all axes.
    :return: The computed DCT
    """

    # Axes along which the DCT is computed. The default is over all axes.
    if axes is None:
        axes = range(array.ndim)

    # Apply the 1D DCT to each axis in sequence.
    for axis in axes:
        array = dct(array, axis=axis)

    return array


#!/usr/bin/python
# -*- coding:utf-8 -*-

"""
最小二乘法线性回归
numpy
"""

import numpy as np
import matplotlib.pyplot as plt

def lstsq(X,Y):
    """
    最小二乘法线性回归
    """
    A = np.vstack([X, np.ones(len(X))]).T
    return np.linalg.lstsq(A, Y)[0]

if __name__ == '__main__':
    # 数据准备
    X = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    Y = [10, 11.5, 12, 13, 14.5, 15.5, 16.8, 17.3, 18, 18.7]

    #进行拟合
    a, b = lstsq(X,Y)
    print("y = %10.5fx + %10.5f" % (a, b))

    #展示拟合结果
    X1 = np.array(X)
    Y1 = np.array(Y)
    plt.plot(X1,Y1,'o',label='data',markersize=10)
    plt.plot(X1,a*X1+b,'b',label='line')
    plt.show()


import numpy as np

def LU_factor(A):
	"""Factor in place A in L*U=A. The lower triangular parts of A
	are the L matrix.  The L has implied ones on the diagonal.
	Args:
		A: N by N array
	Side Effects:
		A is factored in place.
	"""
	[Nrow, Ncol] = A.shape
	assert Nrow == Ncol
	N = Nrow
	for column in range(0,N):
		for row in range(column+1,N):
			mod_row = A[row]
			factor = mod_row[column]/A[column,column]
			mod_row = mod_row - factor*A[column,:]
			#put the factor in the correct place in the modified row
			mod_row[column] = factor
			#only take the part of the modified row we need
			mod_row = mod_row[column:N]
			A[row,column:N] = mod_row
	return

def LU_solve(A,b):
	"""Take a LU factorized matrix and solve it for RHS b Args:
	A: N by N array that has been LU factored with
	assumed 1's on the diagonal of the L matrix
	b: N by 1 array of righthand side
	Returns:
	x: N by 1 array of solutions
	"""
	[Nrow, Ncol] = A.shape
	assert Nrow == Ncol
	N = Nrow

	x = np.zeros(N)
	#temporary vector for L^-1 b
	y = np.zeros(N)

	#forward solve
	for row in range(N):
		RHS = b[row]
		for column in range(0,row):
			RHS -= y[column]*A[row,column]
		y[row] = RHS

	#back solve
	for row in range(N-1,-1,-1):
		RHS = y[row]
		for column in range(row+1,N):
			RHS -= x[column]*A[row,column]
		x[row] = RHS/A[row,row]

	return x


import numpy as np

def mean_square_error(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate MSE loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    MSE of given predictions
    """
    mse = 0
    for i in range(len(y_true)):
        mse += ((y_true[i] - y_pred[i]) ** 2)
    return mse / len(y_true)

def misclassification_error(y_true: np.ndarray, y_pred: np.ndarray,
                            normalize: bool = True) -> float:
    """
    Calculate misclassification loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values
    normalize: bool, default = True
        Normalize by number of samples or not

    Returns
    -------
    Misclassification of given predictions
    """
    misclassification = 0
    for i in range(y_true.size):
        if y_true[i] != y_pred[i]:misclassification +=1
    return misclassification/y_true.size if normalize else misclassification

def accuracy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate accuracy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Accuracy of given predictions
    """
    accuracy = 0
    for i in range(y_true.size):
        if y_true[i] == y_pred[i]:accuracy +=1
    return accuracy/y_true.size

def cross_entropy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate the cross entropy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Cross entropy of given predictions
    """
    raise NotImplementedError()


### Multivariate batch (standard) gradient descent algorithm

### author: Dr. Marko Mitic
### year 2015
### contact: miticm@gmail.com

import numpy as np
import matplotlib.pyplot as plt

class MultivariateBatchGD: #Main class for Batch Multivariate Gradient Descent

    def __init__(self, data):
        ### data is given in several-column format, last column is output
         self.m=len(data)
         self.size=data.shape
         self.x=data
         self.y=self.x[:,-1]

    def featurescaling(self):
        ### feature scaling using mean normalization and std instead of range
        self.xscaled=0.*self.x[:,0:self.x.shape[1]-1]

        for i in range (0, self.x.shape[1]-1): # last column is the output
            self.xscaled[:,i]=(self.x[:,i]-np.mean(self.x[:,i]))/np.std(self.x[:,i])

        #self.yscaled=(self.y-np.mean(self.y))/np.std(self.y) ##this is if you want to scale the output!
        self.yscaled=self.y
        return self.xscaled, self.yscaled

    def thetas(self):
        #self.thetas=np.random.rand(np.shape(self.xscaled)[1]) #randomly set values for theta
        self.thetas=np.zeros(3)
        return self.thetas

    def addones(self):
        self.xscaled=np.append(np.ones([self.m,1]),self.xscaled,1)
        return self.xscaled

    def hypothesis(self):
        #self.hy=self.thetas*self.xscaled
        self.hy=np.dot(self.xscaled, self.thetas)
        return self.hy

    def cost_function(self):
        "Return Cost function for hypothesis hy(of input x) and output y"
        #self.xtransp=self.xscaled.transpose()

        priv=np.dot(self.xscaled,(self.thetas.transpose()))
        self.J=(1./(2.*self.m))*sum((priv-self.y)**2)

        #priv=np.dot(self.xscaled,(self.thetas.transpose()))
        #self.J=(1./(2.*self.m))*sum((priv-self.yscaled)**2)
        return self.J

    def gradientdescent(self,alpha):
        "Perform gradient descent algorithm"
        self.a=alpha #leaarning rate
        temptheta=0.*np.arange(0.,np.shape(self.xscaled)[1])

        for i in range (0, self.x.shape[1]):
            #temptheta[i]=self.thetas[i]-self.a*(1./self.m)*sum(((self.hy[:,i]-self.yscaled)*self.xscaled[:,i]))
            temptheta[i]=self.thetas[i]-self.a*(1./self.m)*sum(((self.hy-self.yscaled)*self.xscaled[:,i]))

        self.thetas=temptheta

        return self.thetas

    def plotcost(self,col):
        plt.figure()
        iters=np.arange(0,len(self.Jhistory))
        plt.plot(iters, self.Jhistory, col)
        plt.xlabel('Number of iterations')
        plt.ylabel('Cost J')
        plt.show()

## END CLASS

################################################################################

#import data
data = np.loadtxt("data_MultiGD.txt", comments="#", delimiter=",", unpack=False)

gd=MultivariateBatchGD(data)

##initialize input and theta values
[gd.xscaled, gd.yscaled]=gd.featurescaling() ##dont scale output y! check Muktivariate BatchGD_class to see yscaled!
gd.xscaled=gd.addones()
gd.thetas=gd.thetas()

## starting hypothesis
gd.hy=gd.hypothesis()

#calculate initial gradient
gd.J=gd.cost_function()

max_iter=50
gd.Jhistory=np.zeros(max_iter)

for i in range (0,max_iter):

    gd.hy=gd.hypothesis()
    gd.J=gd.cost_function()
    gd.Jhistory[i]=gd.J
    gd.thetas=gd.gradientdescent(0.08) ##learning rate==0.008

    print "Current cost is", gd.J
    print 'Theta parameters are', gd.thetas

print 'Final Theta parameters', gd.thetas

gd.plotcost('b')

##END


""" Example showing how to create an annular NURBS surface as a Coons patch """

# -------------------------------------------------------------------------------------------------------------------- #
# Importing packages
# -------------------------------------------------------------------------------------------------------------------- #
import numpy as np
import nurbspy as nrb
import matplotlib.pyplot as plt

# -------------------------------------------------------------------------------------------------------------------- #
# Coons surface example: Annulus NURBS surface
# -------------------------------------------------------------------------------------------------------------------- #

# Define the outer circle
O = np.asarray([0.00, 0.00, 0.00])      # Circle center
X = np.asarray([1.00, 0.00, 0.00])      # Abscissa direction
Y = np.asarray([0.00, 1.00, 0.00])      # Ordinate direction
R = 1.00                                # Circle radius
theta_start = 0.00                      # Start angle (set any arbitrary value)
theta_end = 2*np.pi                     # End angle (set any arbitrary value)
nurbsOuter = nrb.CircularArc(O, X, Y , R, theta_start, theta_end).NurbsCurve

# Define the inner circle
O = np.asarray([0.00, 0.00, 0.00])      # Circle center
X = np.asarray([1.00, 0.00, 0.00])      # Abscissa direction
Y = np.asarray([0.00, 1.00, 0.00])      # Ordinate direction
R = 0.50                                # Circle radius
nurbsInner = nrb.CircularArc(O, X, Y , R, theta_start, theta_end).NurbsCurve

# Define start closing boundary
P = np.zeros((3, 2))
P[:, 0] = nurbsOuter.P[:, 0]
P[:, 1] = nurbsInner.P[:, 0]
W = np.asarray([nurbsOuter.W[0], nurbsInner.W[0]])
nurbsWest = nrb.NurbsCurve(control_points=P, weights=W)

# Define the west boundary (rational Bézier curve)
P = np.zeros((3, 2))
P[:, 0] = nurbsOuter.P[:, -1]
P[:, 1] = nurbsInner.P[:, -1]
W = np.asarray([nurbsOuter.W[-1], nurbsInner.W[-1]])
nurbsEast = nrb.NurbsCurve(control_points=P, weights=W)

# Create and plot the Coons NURBS surface to represent the annulus
coonsNurbsSurface = nrb.NurbsSurfaceCoons(nurbsOuter, nurbsInner, nurbsWest, nurbsEast).NurbsSurface
# coonsNurbsSurface = nrb.NurbsSurfaceRuled(nurbsOuter, nurbsInner).NurbsSurface

# Plot the annulus surface and some isoparametric curve
fig, ax = coonsNurbsSurface.plot(surface=True, surface_color='blue', control_points=False)
coonsNurbsSurface.plot_isocurve_u(fig, ax, np.linspace(0, 1, 20))
coonsNurbsSurface.plot_isocurve_v(fig, ax, np.linspace(0, 1, 5))
plt.show()


import random
import pylab
import numpy as np
def Markov_pi(N, delta):
        N_hits=0
        x, y=1, 1
        for i in range(1, N+1):
                Delta_x=random.uniform(-delta, delta)
                Delta_y=random.uniform(-delta, delta)
                if abs(x+Delta_x)<1 and abs(y+Delta_y)<1:
                        x+=Delta_x
                        y+=Delta_y
                if x**2+y**2<1: N_hits+=1
        return N_hits*4.0/N

def plot_Markov_pi_1(delta):
    X=[]
    Y=[]
    for i in range(1, 10000):
        X+=[i, ]
        Y+=[Markov_pi(i, delta), ]
    pylab.plot(X, Y, '-')
    pylab.show()

def plot_Markov_pi_2(N):
    X=[]
    Y=[]
    for delta in np.arange(-2, 2.05, 0.01):
        X+=[delta, ]
        Y+=[Markov_pi(N, delta), ]
    pylab.plot(X, Y, 'r-')
    pylab.xlabel('$\delta$')
    pylab.ylabel('Estimated value of pi')
    pylab.title('N=%s'%(N))
    pylab.show()


"""Numerical methods for mathematical functions neede for the program"""

import numpy as np
#This method finds the factorial of a given number(num).
#The method calls for an integer input num
#The method returns the factorial(represented as fact in the method)
def factorial(num):
    """Finds the factorial of the input integer.

    Args:
        num (int): The integer to find the factorial of.

    Returns:
        fact (int): The factorial of num.
    """
    #If the number provided is zero then the factorial is 1
    if num == 0:
        fact = 1
    #Otherwise set fact to 1 and begin finding the factorial r is
    #used to find each num-n for n=0 to n=num each value in r is
    #then used to compute the factorial
    else:
        fact = 1
        r = list(range(1,num+1))
        for i in r:
            fact *= i
    return fact

def binomial_coefficient(n, k):
    """Finds the binomial coefficient n choose k. See
    https://en.wikipedia.org/wiki/Binomial_coefficient for details.

    Args:
        n (int): An integer.
        k (int): An integer.

    Returns:
       t (int): The binomial coefficient, n choose k.

    """
    if not (-1 < k < n+1):
        return 0
    if k==0 and n == 0:
        return 1
    t = 1
    if k < n-k:
        for i in range(n, n-k, -1):
            t = t*i//(n-i+1)
    else:
        for i in range(n, k, -1):
            t = t*i//(n-i+1)

    return t

def multinomial(n):
    """Finds the multinomial coefficient for a given array of numbers.

    Args:
        n (list): the interegs to be used.
    """
    binomials = [[np.sum(n),n[0]]]
    for i in range(1,len(n)):
        new_sum = binomials[i-1][0]-binomials[i-1][1]
        binomials.append([new_sum,n[i]])

    bins = []
    for b in binomials:
        bins.append(binomial_coefficient(b[0],b[1]))

    return np.prod(bins)


# 1 DOF SYSTEM
import numpy as np
import matplotlib.pyplot as plt
import libraryTugas as lib

# 1. SYSTEMS PARAMETERS
#================
# a. Initial condition
x_init1, xDot_init1 =  0.1, 0   # [m], [m/s]

# b. System parameters
mass1, damp1, spring1 = 1, 1, 10 # [kg], [Ns/m], [N/m]
omega, forceMagnit = 2, 0.5 # [rad/s], [Newton]--> SYSTEM INPUT

# c. Time parameters
timeStart, timeStop, stepTime = 0, 30, 0.001 # [S]

# d. Define System MODEL!
def systemFunction (y, t):
    xDotDot = np.zeros((1,1), dtype = float)
    xDotDot[0] = (forceMagnit*np.sin(omega*t)-damp1*float(y[1])-spring1*float(y[0]))/mass1
    return xDotDot #*np.sin(omega*t)

# 2. INITIALIZE SIMULATION
# a. Simulation time
time = np.arange(timeStart, timeStop, stepTime, dtype = float)

# b. Initial Condition of THE state
y = np.array([[x_init1], [xDot_init1]], dtype = float)

# 3. SOLVING EQUATION OF MOTION USING RUNGE KUTTA 4th ORDER!!
position, velocity, acceleration = lib.rungeKutta4(y, time,
                                                systemFunction, stepTime)

# 4. PLOTING RESULTS!!
plt.figure(1)
plt.plot(time, position)
title = "position plot [step time = %1.6f s]" % stepTime
plt.title(title)
plt.ylabel('displacement [m]')
plt.xlabel('time [s]')
plt.grid(True)

plt.figure(2)
plt.plot(time, velocity)
title = "velocity plot [step time = %1.6f s]" % stepTime
plt.title(title)
plt.ylabel('velocity [m/s]')
plt.xlabel('time [s]')
plt.grid(True)

plt.figure(3)
plt.plot(time, acceleration)
title = "acceleration plot [step time = %1.6f s]" % stepTime
plt.title(title)
plt.ylabel('acceleration [m/s/s]')
plt.xlabel('time [s]')
plt.grid(True)
plt.show()


# routines for multiplying matrices
import numpy

def mult_Ax(A, x):
    """ return the product of matrix A and vector x: Ax = b """

    # x is a vector
    if not x.ndim == 1:
        print "ERROR: x should be a vector"
        return None

    N = len(x)

    # A is square, with each dimension of length N
    if not (A.shape[0] == N and A.shape[1] == N):
        print "ERROR: A should be square with each dim of same length as x"
        return None

    # allocation the product array
    b = numpy.zeros((N), dtype=A.dtype)

    # each row of b is the product of the like row of A dotted with
    # the vector x
    for i in range(N):
        b[i] = numpy.dot(A[i,:], x)

    print b

    return b


import numpy as np
import scipy.io
import seaborn as sns
import matplotlib.pyplot as plt

from gaussianDistribution import estimate_gaussian_para
from gaussianDistribution import multivariate_gaussian
from fitMGDToVisualization import fit_MGD_visualization
from selectThreshold import select_threshold

####################### (1) Anomaly detection ##########################
# Loading data
data1 = scipy.io.loadmat("data/ex8data1.mat")
# print(data1.keys())  # data1 contains X, Xval, yval (Xval: X validate dataset)

# Visualize data set data1
print("Visualizing X data")
ax = sns.scatterplot(data1["X"][:, 0], data1["X"][:, 1], marker="x", color="b", s=25)
ax.set(xlabel="Latency (ms)", ylabel="Throughput (mb/s)", title="1st data set")
plt.show()
input("Program pause, Press enter to continue")

# Compute Gaussian para & Multivariate Gaussian value
print("\nCompute Multivariate Gaussian (Normal) Distribution (MGD) for each data example")
mu, var = estimate_gaussian_para(data1["X"])
p = multivariate_gaussian(data1["X"], mu, var)
print(f"Shape of X and p (MGD result) simultaneously:\n {data1['X'].shape}\t{p.shape}")

# Apply result of MGD to visualization of data
print("\nVisualize the fit Multivariate Gaussian (Normal) Distribution to the dataset X")
fit_MGD_visualization(data1["X"], mu, var)
plt.show()
input("Program pause, Press enter to continue")

# Select the threshold for the validation dataset
# Compute the Gaussian (normal) distribution value for validation dataset
print("\nCompute the most suited threshold (epsilon) and their appropriate f1 score")
pval = multivariate_gaussian(data1["Xval"], mu, var)

# Compute the most suited threshold (epsilon) & their related F1 score
epsilon, f1 = select_threshold(data1["yval"].ravel(), pval)

print(f"Best epsilon found using cross-validation: {epsilon}")
print(f"Best F1 on Cross Validation Set: {f1}")
print("(you should see a value epsilon of about 8.99e-05)")
print("(you should see a Best F1 value of  0.875000)")
input("Program pause, Press enter to continue")

# Finding the outliers in dataset based on epsilon
print("\nVisualize the outliers inside the dataset")
outliers = np.argwhere(p < epsilon)
outliers = outliers.T[0]

# Visualize the outliers in dataset
ax = fit_MGD_visualization(data1["X"], mu, var)
# "facecolors": only plot the border of data value circle
ax.scatter(data1["X"][outliers, 0], data1["X"][outliers, 1], facecolors="none", color="r", s=200)
ax.set(title="Classify anomaly data sample")
plt.show()
input("Program pause, Press enter to continue")

########################## () High dimensional dataset detection #################
# Input "ex8data2.mat"
print("\nDetect anomaly data point in high dimensional dataset")
data2 = scipy.io.loadmat("data/ex8data2.mat")
# data2 contains X, Xval, yval (validation dataset) (with n number of features)

# Compute Gaussian (normal distribution) value for each data example in both training and validate dataset
mu, var = estimate_gaussian_para(data2["X"])
p = multivariate_gaussian(data2["X"], mu, var)
pval = multivariate_gaussian(data2["Xval"], mu, var)

# Finding the best value of epsilon
epsilon, f1 = select_threshold(data2["yval"].ravel(), pval)

print(f"Best epsilon found using cross-validation: {epsilon}")
print(f"Best F1 on Cross Validation Set: {f1}")
print(f"   (you should see a value epsilon of about 1.38e-18)")
print(f"   (you should see a Best F1 value of 0.615385)")
print(f" Outliers found: {sum(p < epsilon)}")


from typing import Callable
import numpy as np

def trapezoidalRule(f: Callable, N: float, start: float=-1e6,
                    stop: float=1e6) -> float:
    """Function to approximate the numeric integral of a function, f, using
    the Trapezoidal rule.

    Arguments:
        f {Callable} -- Function who's integral is to be estimated.
        N {int} -- Number of nodes to consider.

    Keyword Arguments:
        start {float} -- Starting point (default: {-1e6}).
        stop {float} -- Stopping point (default: {1e6}).

    Returns:
        float -- Approximation of the area under the function.
    """

    # Building values for approximation, and getting step size
    x, h = np.linspace(start=start, stop=stop, num=N, retstep=True)

    # Estimating area using trapezoidal rule, return
    return np.sum((h * f(x))) - ((h / 2) * (f(start) + f(stop)))


import math
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats

# Parameters
np.random.seed(421)
# generating data
# class_means = np.array([-3.0,-1.0,+3.0])
#
# class_deviations = np.array([1.2, 1.0, 1.3])
# #number of data points for each class.
# class_sizes = np.array([40, 30, 50])
#
# points1 = np.random.normal(class_means[0],class_deviations[0],class_sizes[0])
# points2 = np.random.normal(class_means[1],class_deviations[1],class_sizes[1])
# points3 = np.random.normal(class_means[2],class_deviations[2],class_sizes[2])
# points = np.concatenate((points1,points2,points3))
# # generating the labels.
# y = np.concatenate((np.repeat(1, class_sizes[0]), np.repeat(2, class_sizes[1]), np.repeat(3, class_sizes[2])))
#
# # print(points)
# # print(y)
#
# # Exporting data
# # First column is xi, second column is yi column.
# np.savetxt("lab01_data_set.csv", np.stack((points, y), axis=1), delimiter=",")
#
# # Plotting Data
# # Used for drawing purposes.
# data_interval = np.linspace(-7, +7, 1401)
# print(data_interval)
# # Probability density function for the normal distribution
# density1 = stats.norm.pdf(data_interval, loc= class_means[0], scale= class_deviations[0])
# density2 = stats.norm.pdf(data_interval, loc= class_means[1], scale= class_deviations[1])
# density3 = stats.norm.pdf(data_interval, loc= class_means[2], scale= class_deviations[2])
#
# plt.figure(figsize= (10,6))
# plt.plot(data_interval, density1, "r")
# plt.plot(data_interval, density2, "g")
# plt.plot(data_interval, density3, "b")
# plt.plot(points1, np.repeat(-0.01, class_sizes[0]),"r.", markersize= 12)
# plt.plot(points2, np.repeat(-0.02, class_sizes[1]),"g.", markersize= 12)
# plt.plot(points3, np.repeat(-0.03, class_sizes[2]),"b.", markersize= 12)
# plt.xlabel("x")
# plt.ylabel("density")
# plt.show()

#Starting the machine learning
# Importing data
data_set = np.genfromtxt("lab01_data_set.csv", delimiter= ",")
x = data_set[:,0]
y = data_set[:,1].astype(int)

# number of classes
K = np.max(y)
# number of data points
N = data_set.shape[0]

# Parameter Estimation
sample_means = [np.mean(x[y == (c + 1)]) for c in range(K)]
# y == c + 1 to get the x1s for example.
# x[y == ...] thing is where you slice x array into three pieces.
# with mean you get the mean of the data in x1 for example,
# or first 40 items in this case.

print(sample_means)
# parameters that we gave was, -3, -1, 3 so it is close but not perfect.

sample_deviations = [np.sqrt(np.mean((x[y == (c + 1)] - sample_means[c])**2)) for c in range(K)]
print(sample_deviations)
# Correct values were, 1.2, 1.0, 1.3
# Still close but not much.

class_priors = [np.mean(y == (c + 1)) for c in range(K)]
print(class_priors)
# 40 / 120, 30 /120 , 50 /120

# Parametric Classification
# We are giving 1401 data points to test the classification, between the intervals -7 to 7.

data_interval = np.linspace(-7, +7, 1401)

#gc(x) = log(x | y = c) + log P(y=c) = - 1/2 * log(2pi sigmac^2 )
# - (x - mu)^2 / 2 sigmac^2 + log P(y=c)
score_values = np.stack([-0.5 * np.log(2 * math.pi * sample_deviations[c]**2)
                         - 0.5 * (data_interval - sample_means[c])**2 / sample_deviations[c]**2
                         + np.log(class_priors[c])
                         for c in range(K)])
print("score_values:")
print(score_values)

# Score Functions
plt.figure(figsize=(10,6))
plt.plot(data_interval, score_values[0,:], "r")
plt.plot(data_interval, score_values[1,:], "g")
plt.plot(data_interval, score_values[2,:], "b")
plt.xlabel("x")
plt.ylabel("score")
plt.show()
# Based on the graph, you should pick what is on the top.
# So, from -7 to -2 you should pick red since it is on top.
# From -2 to 0.5, green, rest is blue.

# Posterior Probabilities
# calculate log posteriors:
log_posteriors = score_values - [np.max(score_values[:, r]) +
                                 np.log(np.sum(np.exp(score_values[:, r] - np.max(score_values[:, r]))))
                                 for r in range(score_values.shape[1])
                                 ]
print("log_posteriors")
print(log_posteriors)

# Posteriors

plt.figure(figsize = (10, 6))
# plot posterior probability of the first class
plt.plot(data_interval, np.exp(log_posteriors[0,:]), "r")
# plot posterior probability of the second class
plt.plot(data_interval, np.exp(log_posteriors[1,:]), "g")
# plot posterior probability of the third class
plt.plot(data_interval, np.exp(log_posteriors[2,:]), "b")

class_assignments = np.argmax(score_values, axis = 0)

#plot region where the first class has the highest probability
plt.plot(data_interval[class_assignments == 0],
         np.repeat(-0.05, np.sum(class_assignments == 0)), "r.", markersize = 10)
#plot region where the second class has the highest probability
plt.plot(data_interval[class_assignments == 1],
         np.repeat(-0.10, np.sum(class_assignments == 1)), "g.", markersize = 10)
#plot region where the third class has the highest probability
plt.plot(data_interval[class_assignments == 2],
         np.repeat(-0.15, np.sum(class_assignments == 2)), "b.", markersize = 10)

plt.xlabel("x")
plt.ylabel("probability")

plt.show()


import numpy as np
from scipy.special import gamma

from prml.rv.rv import RandomVariable

class Dirichlet(RandomVariable):
    """
    Dirichlet distribution
    p(mu|alpha)
    = gamma(sum(alpha))
      * prod_k mu_k ^ (alpha_k - 1)
      / gamma(alpha_1) / ... / gamma(alpha_K)
    """

    def __init__(self, alpha):
        """
        construct dirichlet distribution

        Parameters
        ----------
        alpha : (size,) np.ndarray
            pseudo count of each outcome, aka concentration parameter
        """
        super().__init__()
        self.alpha = alpha

    @property
    def alpha(self):
        return self.parameter["alpha"]

    @alpha.setter
    def alpha(self, alpha):
        assert isinstance(alpha, np.ndarray)
        assert alpha.ndim == 1
        assert (alpha >= 0).all()
        self.parameter["alpha"] = alpha

    @property
    def ndim(self):
        return self.alpha.ndim

    @property
    def size(self):
        return self.alpha.size

    @property
    def shape(self):
        return self.alpha.shape

    def _pdf(self, mu):
        return (
            gamma(self.alpha.sum())
            * np.prod(mu ** (self.alpha - 1), axis=-1)
            / np.prod(gamma(self.alpha), axis=-1)
        )

    def _draw(self, sample_size=1):
        return np.random.dirichlet(self.alpha, sample_size)


import numpy as np
from scipy.spatial.transform import Rotation as R
import logging
from scipy.optimize import least_squares

"""
    Find the camera pose given 3D to 2D correspondences using a least-squares formulation.
"""

def pose(R: np.array, t: np.array):
    T = np.eye(4, 4)
    T[:3, 3] = t
    T[:3, :3] = R
    return T

def euler_zyx(alpha, gamma, beta):
    return R.from_euler('z', alpha, degrees=True) * R.from_euler('y', beta, degrees=True) * R.from_euler('x', gamma, degrees=True)

def residuals(x, c_q__h, w_X__h):
    c_R_w = euler_zyx(*x[:3]).as_matrix()
    c_t_w = x[3:]
    T = pose(c_R_w, c_t_w)
    p_c = np.eye(3, 4) @ T @ w_X__h
    p = p_c[:2, ...] / p_c[2, :]
    return (c_q__h - p).reshape(-1)

if __name__ == '__main__':

    logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)

    zyx_angles = [45, 20,50]
    c_R_w = euler_zyx(*zyx_angles).as_matrix()
    c_t_w = np.r_[0, 1, 2]
    logging.info("Created camera translation...")

    # generate random 4D configurations
    w_X = np.random.rand(3, 20)
    w_X__h = np.vstack((w_X, np.ones((1, 20))))
    logging.info("Created random configurations...")

    # reproject the 4D configurations into 2D coords
    c_T_w = pose(c_R_w, c_t_w)
    logging.info("Created pose...")

    # reproject the image coordinates
    c_q__h = np.eye(3, 4) @ c_T_w @ w_X__h # (3, 4) @ (4, 4) @ (4, 20)
    logging.info("Reprojected the 3D points...")

    # homogenize the coordinates
    c_q__h = c_q__h[:2, ...] / c_q__h[2, ...] #(2, 20)
    logging.info("Homogenize the image-pts...")

    # change the zyx_angles (disturabance)
    zyx_angles += np.random.rand(3,) * 10 # (3, )
    c_t_w = np.r_[0, 1, 2] # (3, )
    x = np.hstack((c_t_w, zyx_angles)) # (6, )
    logging.info("Stack the pose vector")

    # make a least_squares object in scipy
    lms = least_squares(fun=residuals, x0=x, args=(c_q__h, w_X__h))
    res = residuals(lms.x, c_q__h, w_X__h)

    print("The resulting pose: ", np.array2string(lms.x, precision=2, suppress_small=True))
    print("The residual-squared: ", np.array2string(np.dot(res, res), precision=16, suppress_small=True))

    # https://www.coursera.org/lecture/robotics-perception/bundle-adjustment-i-oDj0o


import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fft, ifft, fftfreq

def diff(x, f, n):
    k = fftfreq(x.size, x[1] - x[0]) * 2 * np.pi
    return np.real(ifft((1j * k)**n * fft(f)))

def solve_heat_eq_pseudo_spectral(x, psi0, Delta_T, D):
    """
    D_t psi = D nabla^2 psi
    """
    k = fftfreq(x.size, x[1] - x[0]) * 2 * np.pi
    return np.real(ifft(np.exp(- D * Delta_T * k**2) * fft(psi0)))
    # D_t psi = D nabla^2 psi + V * psi
    # V = calc_pot(x)
    # return np.real(np.exp(- V / 2 * Delta_T) * ifft(np.exp(- D * Delta_T * k**2) * fft(np.exp(- V / 2 * Delta_T) * psi0)))

if __name__ == "__main__":
    x = np.linspace(0, 2*np.pi, 400)[:-1]
    f = np.sin(x)
    df = diff(x, f, 1)
    ddf = diff(x, f, 2)
    plt.subplot(2, 1, 1)
    plt.plot(x, f, label="f(x) = sin(x)")
    plt.plot(x, df, label="f'")
    plt.plot(x, ddf, label="f''")
    plt.ylim((-1.5, 1.5))
    plt.xlabel("x")
    plt.legend()

    psi0 = np.exp(- (x - np.pi)**2)
    Ts = [0, 1, 2, 3, 4]
    D = 0.5
    plt.subplot(2, 1, 2)
    for T in Ts:
        plt.plot(x, solve_heat_eq_pseudo_spectral(x, psi0, T, D), label="T = %.2f" % T)
    plt.legend()
    plt.xlabel("x")
    plt.ylabel(r"$\psi$")
    plt.title("Diffusion eq. using Spectral Method, D = %.2f" % D)
    plt.show()


# basic_stats.py: Basic stats functions (not available in Numpy alone) that are repeatedly used in the other fancier
# modules in this package.

import numpy as np

# =========================
# Basic statistics functions
# =========================
# Function for fisher transformation; used for one correlation coefficent averaging method
def fisher_transform(x, output_type='z', method='short'):
    """
    Calculates regular Fisher z-transformation of Pearson correlation
    coefficients (aka r values) into z-scores, or inverse fisher
    z-transformation of z-scores into Pearson correlation coefficients.

    Parameters
    ----------
    x : array-like
        The data array to be transformed.

    output_type : str
        The output statistic that is desired. 'z' implies regular
        Fisher z-transformation, while 'r' implies the inverse.

        (Default is 'z')

    method : str
        (Primarily exists for function test purposes)
        Chooses the method of calculation. 'short' uses numpy.arctanh and
        numpy.tanh to produce regular and inverse transformations,
        respectively. 'Long' instead calculates it step by step, but still
        uses numpy.log and numpy.exp for regular and inverse transforms.

        (Default is 'short')

    Returns
    -------
    output : array-like
        Will have the same shape/dimensions as x

    Warning:
    Using Fisher-transformation in within-between ISC (for calculating)
    average z then inverse transforming back to r) currently produces
    sporadic missing data, so the averaging method should use the
    median instead until this the effect of this function on results
    is better tested and validated.

    """
    # Currently, both output types assume the correct input (i.e., r or z) is provided
    # Transform Pearson r correlation coefficients into z by default or r when defined
    def arctanh_tanh(x, output): # fisher z transformation calculated with arctanh and tanh
        if output == 'z':
            z = np.arctanh(x)
            return z
        elif output == 'r':
            r = np.tanh(x)
            return r

    def long_fisher(x, output): # fisher z transformation calculated the long way
        if output == 'z':
            z = np.log((1+x)/(1-x)) / 2
            return z
        # Transform z scores back into r-values (presumably after z is averaged)
        elif output == 'r':
            r = (np.exp(2*x)-1) / (np.exp(2*x)+1)
            return r

    if method == 'short':
        transformed_output = arctanh_tanh(x, output_type)
    elif method == 'long':
        transformed_output = long_fisher(x, output_type)

    return transformed_output

# Retrieves upper triangle of a matrix
# TODO: I should make this upper or lower option
# NOTE: This function is not currently incorporated in any other function--should it be?
def unique_tri(array):
    """
    Retrieves the upper-triangle of a square m x m matrix; used in the
    context of getting unique x and y pairs. This currently excludes
    diagonal values since numpy.triu() already includes it.

    Parameters
    ----------
    array : array-like
        The matrix that the triangle is obtained from

    Returns
    -------
    output : the triangle (excluding the diagonal values)

    """

    m = array.shape[0]
    r, c = np.triu_indices(m,1)
    return array[r,c]

# Computes pairwise voxel correlations between two matrices
def pairwise_r(x_input, y_input):
    # Compute Pearsons' R for every x,y combination
    # Note:
    # - allows for (i,j) and (j,i)
    # - symmetry depends on whether x == y
    # - final matrix shape can be non-square

    # Save data and their number of rows
    r_matrix = np.array([])

    x = x_input
    y = y_input
    x_len, y_len = len(x), len(y) # default lengths of inputs

    # Reshape 1d data to matrix with 1 row
    if x.ndim == 1:
        x = x.reshape((1, x_len))
        x_len = 1

    if y.ndim == 1:
        y = y.reshape((1, y_len))
        y_len = 1

    # Correlate every combination of (x,y) pairs of rows
    for i in range(x_len):
        for j in range(y_len):
            r_i = np.corrcoef(x[i], y[j])[0,1]
            r_matrix = np.append(r_matrix, r_i)

    # Reshape into matrix and tranpose to correct x and y axes positions
    r_matrix = r_matrix.reshape((x_len, y_len)).T
    return r_matrix

# Function to easily choose the averaging method for a matrix of correlation coefficients
def r_mean(x, method='median', axis=None, fisher_method='short'):
    """
    Method can be
    - median (default)
    - fisher (fisher z -> mean -> fisher z inverse)
    - mean (not recommended, but included for comparison purposes)
    """
    if method=='median':
        r_mean = np.median(x, axis=axis)

    elif method=='fisher':
        if fisher_method=='short': # uses arctanh / tanh (inverse transform)
            r_mean = np.mean(fisher_transform(x), axis=axis) # get mean z values
            r_mean = fisher_transform(r_mean, output_type='r') # turn mean z-values back into r

        elif fisher_method=='long': # calculates transformation the long way
            r_mean = np.mean(fisher_transform(x, method='long'), axis=axis)
            r_mean = fisher_transform(r_mean, output_type='r', method='long')

    elif method=='mean':
        r_mean = np.mean(x, axis=axis)

    return r_mean


import numpy as np
# Load matlab's file
import scipy.io
# Build-in K-means clustering model of sklearn lib
from sklearn.cluster import KMeans
from findClosestCentroids import find_closest_centroid
from computeCentroidMean import compute_centroid_mean
from KmeansAlgo import kmeans_algo

############### (1) Find the closest centroids ####################
print(f"Find the closest centroids")

# Loading the example dataset
data2 = scipy.io.loadmat("data/ex7data2.mat")

# Find the closest centroid with with initial K=3
K = 3
initial_centroids = np.array([[3, 3], [6, 2], [8, 5]])
idx = find_closest_centroid(data2["X"], initial_centroids)
print(f"Closest centroids of the 1st 3 examples: {idx[:3].T}")
print(f"The closet centroids should be 1, 3, 2 respectively")
input("Pause program, Press enter to continue")

############## (2) Compute the centroids means ################
print(f"\nCompute means of data point closed to each associated centroid")
centroids = compute_centroid_mean(data2["X"], idx, K)
print(f"Centroids computed after initial finding of closest centroid:\n {centroids}\n")
print(f"(the centroids should be\n [ 2.428301 3.157924 ]\n[ 5.813503 2.633656 ]\n[ 7.119387 3.616684 ]")
input("Pause program, Press enter to continue")

################ (3) K-means clustering ######################
print(f"\nRunning K-means clustering on example dataset")

# Initial setting
K = 3
max_iter = 10
initial_centroids = np.array([[3, 3], [6, 2], [8, 5]])

# Run K-means clustering algorithm. "true" values at last parameter indicate plotting the progress of K-means
centroids, idx = kmeans_algo(data2["X"], initial_centroids, max_iter, True)
input("Pause program, Press enter to continue")

############# (4) K-means clustering using sklearn lib ###############
# from sklearn.cluster import KMeans
initial_centroids = np.array([[3, 3], [6, 2], [8, 5]])
# Create KMeans model
kmeans_model = KMeans(n_clusters=K, max_iter=max_iter, init=initial_centroids)
# Fit data to the model
kmeans_model.fit(data2["X"])

# Return trained centroids
kmeans_model_centroids = kmeans_model.cluster_centers_
# Comparing centroids of 2 ways
print(f"Trained cluster centroid of sklearn model:\n"
      f"{kmeans_model_centroids[0]}\n"
      f"{kmeans_model_centroids[1]}\n"
      f"{kmeans_model_centroids[2]}\n")

print(f"Trained cluster centroid of manual generation:\n"
      f"{centroids[0]}\n"
      f"{centroids[1]}\n"
      f"{centroids[2]}\n")

input("Pause program, Press enter to continue")


import numpy as np

# Cleaning data from -999 values
def clean_data(x):
	## Convert -999 to NaN as we believe these are misidentified data
    ## Recording as NaN prevents them from influencing nanmean calculations
    x[x == -999] = np.nan
    mean_x = np.nanmean(x, axis=0)
    return np.where(np.isnan(x), mean_x, x)

# Standardizing by subtracting the mean and dividing by standard deviation
def standardize(x):
    """Standardize the original data set."""
    means = np.mean(x, axis=0)
    x = x-means
    stds = np.std(x, axis=0)
    # this prevents division by zero
    stds[stds == 0] = 1
    x = x/stds
    return x, means, stds

# Adding 1-column at the data matrix
def add_constants(x, y):
    return np.c_[np.ones((y.shape[0], 1)), x]

# Preprocessing data function
def process_data(tx_tr, tx_te, y_tr, y_te):

    # Cleaning data from -999 values
    tx_tr = clean_data(tx_tr)
    tx_te = clean_data(tx_te)

    # Standardizing data
    tx_tr, mean, std = standardize(tx_tr)
    tx_te = (tx_te-mean)/std

    # Adding constants vector as a first column
    tx_tr = add_constants(tx_tr, y_tr)
    tx_te = add_constants(tx_te, y_te)

    return tx_tr, tx_te

## Because expansion and standardization are transformations of our initial feature set
## We must apply identical transformations to all feature sets we wish to make predictions upon
def expand_data(degree, tx_tr, tx_te, tx_pred = None):
    ## Extract jet numbers as three indicator variables
    ## Remove them so they will not be standardized or expanded
    jets_tr = jet_nums(tx_tr)
    jets_te= jet_nums(tx_te)
    ## Remove redundant columns
    res_tr = extract_col(tx_tr)
    res_te = extract_col(tx_te)
    ## Expand features to include polynomial terms
    res_tr = build_poly(tx_tr, degree)
    res_te = build_poly(tx_te, degree)
    ## Standardize
    res_tr, mean, std = standardize(res_tr)
    res_te = (res_te-mean)/std
    ## Fix NaNs resulting from division by 0
    res_tr[np.isnan(res_tr)]=1
    res_te[np.isnan(res_te)]=1
    ## Reconcatenate jet indicator columns
    res_tr = np.c_[res_tr, jets_tr]
    res_te = np.c_[res_te, jets_te]
    return res_tr, res_te #, res_pred

## Jet number seems to be categorical, taking on three discrete values
## Relative values do not seem to have meaning, so coefficients are not a good way to treat this
## Solution: Split this into three indicator vectors. Each indicator takes a different coefficient
def jet_nums(tx):
    jets = tx[:,22]
    new_tx = np.delete(tx, 22, axis=1)
    jet0 = np.zeros((jets.shape[0],1))
    jet0[jets==0] = 1
    jet1 = np.zeros((jets.shape[0],1))
    jet1[jets==1] = 1
    jet2 = np.zeros((jets.shape[0],1))
    jet2[jets==2] = 1
    jet3 = np.zeros((jets.shape[0],1))
    jet3[jets==3] = 1
    result = np.c_[jet0, jet1, jet2, jet3]
    return result

# Extract 22th column from the data
def extract_col(tx):
    result = np.delete(tx, 22, axis=1)
    return result

# Adding polynomial features up to the selected degree
def build_poly(x, degree):
    poly_x = np.ones((len(x), 1))
    for d in range(1, degree+1):
        poly_x = np.c_[poly_x, np.power(x, d)]
    return poly_x


import numpy as np
import numpy.linalg as la

class Kernel(object):
    """Implements list of kernels from
    http://en.wikipedia.org/wiki/Support_vector_machine
    """
    @staticmethod
    def linear():
        return lambda x, y: np.inner(x, y)

    @staticmethod
    def gaussian(sigma):
        return lambda x, y: \
            np.exp(-np.sqrt(la.norm(x-y) ** 2 / (2 * sigma ** 2)))

    @staticmethod
    def _polykernel(dimension, offset):
        return lambda x, y: (offset + np.inner(x, y)) ** dimension

    @classmethod
    def inhomogenous_polynomial(cls, dimension):
        return cls._polykernel(dimension=dimension, offset=1.0)

    @classmethod
    def homogenous_polynomial(cls, dimension):
        return cls._polykernel(dimension=dimension, offset=0.0)

    @staticmethod
    def hyperbolic_tangent(kappa, c):
        return lambda x, y: np.tanh(kappa * np.dot(x, y) + c)


import scipy.fftpack as fft
import matplotlib.pyplot as plt
import numpy
import imageio
import math
from pylab import *
from numpy.fft import fft2, ifft2, fftshift, ifftshift

#Reference: https://lab4sys.com/en/fourier-transform-of-an-image/?cn-reloaded=1

#N =256
#t = np.arange(N)

#m=4
#nu = float(m)/N
#f= np.sin(2*np.pi*nu*t)
#ft=np.fft.fft(f)
#freq=np.fft.fftfreq(N)
#plt.plot(freq,ft.real**2+ft.imag**2)
#plt.show()

def matriceImage(matrice,gamma,rgb):
    s= matrice.shape
    a=1.0/gamma;
    norm=matrice.max()
    m=numpy.power(matrice/norm,a) #normalization, gamma correction
    im=numpy.zeros((s[0],s[1],3),dtype=float64) #declare image matrix
    im[:,:,0] = rgb[0]*m
    im[:,:,1] = rgb[1]*m
    im[:,:,2] = rgb[2]*m
    return im

def matriceImageLog(matrice,rgb):
    s= matrice.shape
    m = numpy.log10(1+matrice)
    min = m.min()
    max = m.max()
    m = (m-min)/(max-min)
    im=numpy.zeros((s[0],s[1],3),dtype=float64) #declare image matrix
    im[:,:,0] = rgb[0]*m
    im[:,:,1] = rgb[1]*m
    im[:,:,2] = rgb[2]*m
    return im

def plotSpectre(image,Lx,Ly):
    (Ny,Nx,p) = image.shape
    fxm = Nx*1.0/(2*Lx)
    fym = Ny*1.0/(2*Ly)
    imshow(image,extent=[-fxm,fxm,-fym,fym])
    xlabel("fx")
    ylabel("fy")

def low_pass_transfert(fx,fy,p): #low pass filtering
    fc=p[0]
    return 1.0/numpy.power(1+(fx*fx+fy*fy)/(fc*fc),2)

def high_pass_transfert(fx,fy,p): #high pass filtering
    fc=p[0]
    return 1.0-1.0/numpy.power(1+(fx*fx+fy*fy)/(fc*fc),2)

def Gaussian_notch_transfert(fx,fy,p): #Gaussian notch filter
    f0 = p[0]
    sigma = p[1]
    ux = numpy.absolute(fx)-f0
    return 1.0-numpy.exp(-(ux*ux)/(sigma*sigma))

def matriceFiltre(matrice,transfert,p):
    s = matrice.shape
    Nx = s[1]
    Ny = s[0]
    nx = Nx/2
    ny = Ny/2
    Mat = zeros((Ny,Nx),dtype=numpy.complex)
    for n in range(Nx):
        for l in range(Ny):
            fx = float(n-nx-1)/Nx
            fy = float(l-ny-1)/Ny
            Mat[l,n] = matrice[l,n]*transfert(fx,fy,p)
    return Mat

print('Hi')
imA = imageio.imread("imageA.png")
U=numpy.array(imA[:,:,0],dtype=numpy.float64) #remove red layer
V=fft2(U)
VC = fftshift(V)
P = numpy.power(numpy.absolute(VC),2)
img = matriceImage(P,2.0,[1.0,0.0,0.0])
#plotSpectre(img,200.0,100.0)
img = matriceImageLog(P,[1.0,0.0,0.0])
#plotSpectre(img,200.0,100.0)
H = numpy.ones(VC.shape,dtype=numpy.complex)
H = matriceFiltre(H,low_pass_transfert,[0.1])
VCF = VC*H
PF = numpy.power(numpy.absolute(VCF),2)
imPF = matriceImageLog(PF,[1.0,0,0])
plotSpectre(imPF,200,100)
VF = ifftshift(VCF)
UF=ifft2(VF)
imageF = matriceImage(UF,1.0,[1.0,1.0,1.0])
figure()
imshow(imageF)


import numpy as np

def normalize_vec(vec):
    return vec / np.linalg.norm(vec)

def normalize_a_to_b(a, b):
    vec = b - a
    return vec / np.linalg.norm(vec)

def calc_angle_360(v1, v2, n):

    x = np.cross(v1, v2)
    c = np.sign(np.dot(x, n)) * np.linalg.norm(x)
    a = np.arctan2(c, np.dot(v1, v2))

    return np.degrees(a)


from math import cos, radians, sin
from typing import Optional, Tuple

import numpy as np

from squad.constants import AngleType

def _get_sin_cos_theta(theta: float) -> Tuple[float, float]:
    """Gets the :obj:`sin` and :obj:`cos` of the given `theta` (in
    radians).
    """
    return sin(theta), cos(theta)

def _x_rotation_mat(theta: float) -> np.ndarray:
    """Gets the X-axis rotation matrix for the given `theta` (in
    radians).
    """
    t_sin, t_cos = _get_sin_cos_theta(theta)

    r_x = np.identity(3)
    r_x[1, 1] = t_cos
    r_x[1, 2] = -t_sin
    r_x[2, 1] = t_sin
    r_x[2, 2] = t_cos

    return r_x

def _y_rotation_mat(theta: float) -> np.ndarray:
    """Gets the Y-axis rotation matrix for the given `theta` (in
    radians).
    """
    t_sin, t_cos = _get_sin_cos_theta(theta)

    r_y = np.identity(3)
    r_y[0, 0] = t_cos
    r_y[0, 2] = t_sin
    r_y[2, 0] = -t_sin
    r_y[2, 2] = t_cos

    return r_y

def _z_rotation_mat(theta: float) -> np.ndarray:
    """Gets the Z-axis rotation matrix for the given `theta` (in
    radians).
    """
    t_sin, t_cos = _get_sin_cos_theta(theta)

    r_z = np.identity(3)
    r_z[0, 0] = t_cos
    r_z[0, 1] = -t_sin
    r_z[1, 0] = t_sin
    r_z[1, 1] = t_cos

    return r_z

def rotation_matrix(x: float, y: float, z: float) -> np.ndarray:
    """Gets the rotation transformation matrix for the given angles (in
    radians).
    """
    if x:
        r_x = _x_rotation_mat(x)
    else:
        r_x = np.identity(3)

    if y:
        r_y = _y_rotation_mat(y)
    else:
        r_y = np.identity(3)

    if z:
        r_z = _z_rotation_mat(z)
    else:
        r_z = np.identity(3)

    r_xyz = r_z @ r_y @ r_x
    return r_xyz

def coord_rotate_xyz(
    x: float,
    y: float,
    z: float,
    x_rotation: Optional[float] = None,
    y_rotation: Optional[float] = None,
    z_rotation: Optional[float] = None,
    *,
    angle_type: AngleType = AngleType.DEGREES,
) -> Tuple[float, float, float]:
    """Apply a rotation transformation for the given position.

    Parameters
    ----------
    x : float
        The X-coordinate to apply the rotation(s) to.
    y : float
        The Y-coordinate to apply the rotation(s) to.
    z : float
        The Z-coordinate to apply the rotation(s) to.
    x_rotation : float, optional
        The rotation about the X-axis to apply (in radians, if any).
    y_rotation : float, optional
        The rotation about the Y-axis to apply (in radians, if any).
    z_rotation : float, optional
        The rotation about the Z-axis to apply (in radians, if any).
    angle_type : AngleType, default=AngleType.DEGREES
        The format of the given rotation angle inputs
        (:obj:`AngleType.DEGREES`, default) or
        (:obj:`AngleType.RADIANS`).

    Returns
    -------
    Tuple[float, float, float]
        The new coordinates, as a 3-element :obj:`tuple` of (x, y, z).

    """
    v0 = np.array((x, y, z))
    v1 = coord_rotate(
        v0,
        x_rotation=x_rotation,
        y_rotation=y_rotation,
        z_rotation=z_rotation,
        angle_type=angle_type,
    )
    return tuple(x for x in v1)

def coord_rotate(
    v: np.ndarray,
    x_rotation: Optional[float] = None,
    y_rotation: Optional[float] = None,
    z_rotation: Optional[float] = None,
    *,
    angle_type: AngleType = AngleType.DEGREES,
) -> np.ndarray:
    """Apply a rotation transformation for the given vector.

    Parameters
    ----------
    v : np.ndarray
        A 3D vector to rotate based on the given rotation angles.
    x_rotation : float, optional
        The rotation about the X-axis to apply (in radians, if any).
    y_rotation : float, optional
        The rotation about the Y-axis to apply (in radians, if any).
    z_rotation : float, optional
        The rotation about the Z-axis to apply (in radians, if any).
    angle_type : AngleType, default=AngleType.DEGREES
        The format of the given rotation angle inputs
        (:obj:`AngleType.DEGREES`, default) or
        (:obj:`AngleType.RADIANS`).

    Returns
    -------
    np.ndarray
        The new coordinates, as a 3-element vector, of (x, y, z).

    """
    if angle_type == AngleType.DEGREES:
        r_xyz = rotation_matrix(
            radians(x_rotation or 0.0),
            radians(y_rotation or 0.0),
            radians(z_rotation or 0.0),
        )
    else:
        r_xyz = rotation_matrix(
            x_rotation or 0.0,
            y_rotation or 0.0,
            z_rotation or 0.0,
        )
    return r_xyz @ v


import numpy as np

def mean_absolute_error(predictions, ground_truth):

    return np.mean(np.abs(predictions-ground_truth))

def root_mean_squared_error(predictions,ground_truth):

    return np.sqrt(np.mean(np.power(predictions-ground_truth,2)))


import numpy as np
import math

def rosenbrock(x,alpha=100):
    '''
        Rosenbrock function

        Single objective multiple input function
    '''
    f = 0
    for indx in range(len(x)-1):
        temp = alpha* math.pow(x[indx+1]-x[indx]*x[indx],2) + math.pow(1.0-x[indx],2)
        f+=temp
    return f

def KUR(x1,x2,x3):
    '''
        Kursawe Function
        mutiple output
    '''
    f1 = (-10*math.exp(-0.2*math.sqrt(x1*x1+x2*x2))) + (-10*math.exp(-0.2*math.sqrt(x2*x2+x3*x3)))

    f2 = (abs(x1)^0.8+5*math.sin(x1*x1*x1))+(math.pow(abs(x2),0.8)+5*math.sin(x2*x2*x2))+(math.pow(abs(x3),0.8)+5*math.sin(x3*x3*x3))

    return f1,f2


import numpy as np
import matplotlib.pyplot as plt

def rk2heun(x0, v0, tf, dt, a0, w0, w):
    fv = lambda x, t: -(w0**2)*np.sin(x) + a0*np.sin(w*t)
    pos = [x0]
    vel = [v0]
    for t in np.arange(0, tf, dt):
        k1x = v0
        k1v = fv(x0, t)
        xaux = x0 + k1x * dt
        vaux = v0 + k1v * dt
        k2x = vaux
        k2v = fv(xaux, t+dt)
        x0 += (k1x + k2x)*(dt/2)
        v0 += (k1v + k2v)*(dt/2)
        pos.append(x0)
        vel.append(v0)
    return pos, vel

x0 = 0.1
v0 = 0
tf = 25
dt = 0.1
a0 = 0.1
w0 = 1
w = 0.1

la = [0.1, 0.1, 1]
lw = [0.1, 0.5, 0.5]

t = np.arange(0, tf+dt, dt)

figura = plt.figure(figsize=(13, 5))
plt.subplot(121)
plt.plot(t, rk2heun(x0, v0, tf, dt, a0, w0, w)[0], label=r'$A_{0}=$'+f'{a0}'+r' | $\omega=$'+f'{w}')
#for a, w1 in zip(la, lw):
#    plt.plot(t, rk2heun(x0, v0, tf, dt, a, w0, w1)[0], label=r'$A_{0}=$'+f'{a}'+r' | $\omega=$'+f'{w1}')
plt.xlabel('t')
plt.ylabel('x')
plt.legend()
plt.title(r'Posição $\times$ Tempo')
plt.grid()

plt.subplot(122)
plt.plot(rk2heun(x0, v0, tf, dt, a0, w0, w)[0], rk2heun(x0, v0, tf, dt, a0, w0, w)[1], label=r'$A_{0}=$'+f'{a0}'+r' | $\omega=$'+f'{w}')
#for a, w1 in zip(la, lw):
#    plt.plot(rk2heun(x0, v0, tf, dt, a, w0, w1)[0], rk2heun(x0, v0, tf, dt, a, w0, w1)[1], label=r'$A_{0}=$'+f'{a}'+r' | $\omega=$'+f'{w1}')
plt.xlabel('x')
plt.ylabel('v')
plt.legend()
plt.title(r'Posição $\times$ Velocidade')
plt.grid()

plt.savefig('rk2heunpendulo1.png')


import unittest
import numpy as np
from numpy.testing import assert_array_equal

class TestArrayOperation(unittest.TestCase):

    def test_plus(self):
        vector = np.array([0, 0, 0, 0, 0])
        vector = vector + 1
        assert_array_equal(vector, np.array([1, 1, 1, 1, 1]))

    def test_minus(self):
        vector = np.array([1, 1, 1, 1, 1])
        vector = vector - 1
        assert_array_equal(vector, np.array([0, 0, 0, 0, 0]))

    def test_multi(self):
        vector = np.array([3, 3, 3, 3, 3])
        vector = vector * 3
        assert_array_equal(vector, np.array([9, 9, 9, 9, 9]))
# donot know
    def test_dot(self):
        vector = np.array([[1, 2], [3, 4]])
        vector = np.dot(vector, vector)
        assert_array_equal(vector, np.array([[7, 10], [15, 22]]))

    def test_expo(self):
        vector = np.array([3, 3, 3, 3, 3])
        vector = vector ** 2
        assert_array_equal(vector, np.array([9, 9, 9, 9, 9]))

    def test_bool(self):
        vector = np.array([0, 1, 2, 3, 4])
        vector = vector < 3
        assert_array_equal(vector, np.array([True, True, True, False, False]))

    def test_sum(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        self.assertEqual(metrix.sum(), 45)

    def test_max(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        self.assertEqual(metrix.max(), 9)

    def test_min(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        self.assertEqual(metrix.min(), 0)

    def test_sum_axis0(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        assert_array_equal(metrix.sum(axis=0), np.array([5, 7, 9, 11, 13]))

    def test_sum_axis1(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        assert_array_equal(metrix.sum(axis=1), np.array([10, 35]))

    def test_max_axis0(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        assert_array_equal(metrix.max(axis=0), np.array([5, 6, 7, 8, 9]))

    def test_max_axis1(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        assert_array_equal(metrix.max(axis=1), np.array([4, 9]))

    def test_min_axis0(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        assert_array_equal(metrix.min(axis=0), np.array([0, 1, 2, 3, 4]))

    def test_min_axis1(self):
        metrix = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
        assert_array_equal(metrix.min(axis=1), np.array([0, 5]))
#TODO
    def test_transpose(self):
        metrix = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
        assert_array_equal(metrix.transpose(), np.array([[0, 3, 6], [1, 4, 7], [2, 5, 8]]))

    def test_T(self):
        metrix = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
        assert_array_equal(metrix.T, np.array([[0, 3, 6], [1, 4, 7], [2, 5, 8]]))

    def test_flatten(self):
        metrix = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
        assert_array_equal(metrix.flatten(), np.array([0, 1, 2, 3, 4, 5, 6, 7, 8]))

if __name__ == '__main__':
    unittest.main()


# This program and its computation instruction was written by Andre Christoga Pramaditya (drepram.com) with the student ID (2006570006).
# Program dan instruksi komputasi ini ditulis oleh Andre Christoga Pramaditya (drepram.com) dengan Nomor Pokok Mahasiswa (2006570006).

import numpy as np
import matplotlib.pyplot as plt

import warnings
warnings.filterwarnings("ignore") # insert programmer laziness joke here

# number of trials, probability of each trial
number_of_trials = 100
probability_5 = 0.5
probability_1 = 0.1
probability_9 = 0.9

sample_5 = np.random.binomial(number_of_trials, probability_5, 10000)
sample_1 = np.random.binomial(number_of_trials, probability_1, 10000)
sample_9 = np.random.binomial(number_of_trials, probability_9, 10000)

# disclaimer_text = "Orange bars (n=0.1), Blue bars (n=0.5), Green bars (n=0.9)."

combined_histogram = plt.figure(1, figsize=(7,7))

plt.hist(sample_5, 15, density=True)
plt.hist(sample_1, 15, density=True)
plt.hist(sample_9, 15, density=True)

combined_histogram.suptitle('Binomial Distribution Combined Histogram', fontsize=14, fontweight='bold')
combined_axes_title = combined_histogram.add_subplot(111)
combined_histogram.subplots_adjust(top=0.85)
combined_axes_title.set_title('Orange bars (n=0.1), Blue bars (n=0.5), Green bars (n=0.9)')
combined_histogram.show()

histogram_each, (case1, case2, case3) = plt.subplots(1,3, figsize=(15,9))
histogram_each.suptitle('Binomial Distribution for Each Case \n(with more specific range for the x axis)', fontweight='bold')
case1.hist(sample_1, 15, density=True, color="orange")
case1.set_title('retrieved 10.000 random number\nfrom n=100,p=0.1')
case2.hist(sample_5, 15, density=True, color="blue")
case2.set_title('retrieved 10.000 random number\nfrom n=100,p=0.5')
case3.hist(sample_9, 15, density=True, color="green")
case3.set_title('retrieved 10.000 random number\nfrom n=100,p=0.9')

# Standardization of the y axis if of any need, it is unnecessary for now
# case1.set_ylim([0, 0.2])
# case2.set_ylim([0, 0.2])
# case3.set_ylim([0, 0.2])

histogram_each.show()

### OLD METHOD OF SHOWING EACH FIGURES
# histogram_5 = plt.figure(2)
# plt.hist(sample_5, 15, density=True, color="blue")
# histogram_5.show()

# histogram_1 = plt.figure(3)
# plt.hist(sample_1, 15, density=True, color="orange")
# histogram_1.show()

# histogram_9 = plt.figure(4)
# plt.hist(sample_9, 15, density=True, color="green")
# histogram_9.show()

plt.show()


"""
Q1: Resolver as questões do lab 10:
"""
from Metodos_numericos.metodos import EDO
from math import exp
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from pprint import pprint

# Declarando constantes:
R = 33000
C = 90*10**(-6)
ti = 0
vi = 1
vo_linha = lambda t, v: -(1/(R*C))*v

#Resultado analitico:
vo = lambda t: exp(-t/(R*C))
x = np.arange(0, 15.01, 0.01)
v_analitico = np.array([vo(i) for i in x])

#Pelo metodo de Euler:
edo = EDO(vo_linha, ti, vi, 0.5)
euler = np.array([])
for i in x:
    edo.Euler(i)
    euler = np.append(euler, edo.y_novo)

#Pelo metodo de Heun:
edo = EDO(vo_linha, ti, vi)
heun = np.array([])
for i in x:
    edo.Heun(i)
    heun = np.append(heun, edo.y_novo)

#Pelo metodo de Runge Kutta 4° ordem:
edo = EDO(vo_linha, ti, vi)
rk = np.array([])
for i in x:
    edo.Runge_Kutta_4(i)
    rk = np.append(rk, edo.y_novo)

#plotando graficos comparativos:
plt.grid()
plt.tight_layout()
plt.style.use('ggplot')
plt.plot(x, v_analitico, 'r-', label='Valor analitico')
plt.plot(x, euler, 'y-', label='Metodo de Euler')
plt.title('Analise de EDO pelo metodo de Euler')
plt.xlabel('x')
plt.ylabel('y')
plt.legend(loc='best')
plt.show()

plt.plot(x, v_analitico, 'r-', label='Valor analitico')
plt.plot(x, heun, 'g-', label='Metodo de Heun')
plt.title('Analise de EDOs pelo metodo de Heun')
plt.xlabel('x')
plt.ylabel('y')
plt.legend(loc='best')
plt.show()

plt.plot(x, v_analitico, 'r-', label='Valor analitico')
plt.plot(x, rk, 'b-', label='Metodo de Runge Kutta de 4º ordem')
plt.title('Analise de EDOs pelo metodo de Runge Kutta')
plt.xlabel('x')
plt.ylabel('y')
plt.legend(loc='best')
plt.show()

#Calculo dos erros:
erro_euler = max(abs(euler - v_analitico))
erro_heun = max(abs(heun - v_analitico))
erro_runge = max(abs(rk - v_analitico))

erros = {
    "Euler": round(erro_euler, 5),
    "Heun": round(erro_heun, 5),
    "Runge Kutta": round(erro_runge, 5)
}
db = pd.DataFrame(erros, index=['Erro absoluto'], columns=['Euler', 'Heun', 'Runge Kutta'])
pprint(db)


# day 6 Numpy Array Function

import numpy as np
import time
from timeit import timeit
np.random.seed(0)

def compute_reciprocals(values):
    output = np.empty(len(values))
    for i in range(len(values)):
        output[i] = 1.0 / values[i]
    return output

# time loop
# value1 = np.random.randint(1, 10, size=5)
# t1 = timeit('compute_reciprocals(value1)', 'from __main__ import compute_reciprocals, value1', number=1)
# print('timeit', t1)
#
# value2 = np.random.randint(1, 100, size=1000000)
# t2 = timeit('compute_reciprocals(value2)', 'from __main__ import compute_reciprocals, value2', number=1)
# print('timeit', t2)
#
# t3 = timeit('1.0 / value2', 'from __main__ import value2', number=1)
# print('timeit', t3)

def array_arithmetic():
    x = np.arange(4)
    print("x     =", x)
    print("x + 5 =", x + 5)
    print("x - 5 =", x - 5)
    print("x * 2 =", x * 2)
    print("x / 2 =", x / 2)
    print("x // 2 =", x // 2)
    print("-x     = ", -x)
    print("x ** 2 = ", x ** 2)
    print("x % 2  = ", x % 2)
    print('-(0.5*x + 1) ** 2', -(0.5*x + 1) ** 2)
    print('add', np.add(x, 2))

    x = np.array([-2, -1, 0, 1, 2])
    print('x=', x)
    print('abs(x)=', abs(x))
    print('np.absolute(x) = ', np.absolute(x))
    print('np.abs(x) = ', np.abs(x))
    x = np.array([3 - 4j, 4 - 3j, 2 + 0j, 0 + 1j])
    print('x=', x)
    print('np.abs(x) = ', np.abs(x))

def trigonometric():
    theta = np.linspace(0, np.pi, 3)
    print("theta      = ", theta)
    print("sin(theta) = ", np.sin(theta))
    print("cos(theta) = ", np.cos(theta))
    print("tan(theta) = ", np.tan(theta))
    x = [-1, 0, 1]
    print("x         = ", x)
    print("arcsin(x) = ", np.arcsin(x))
    print("arccos(x) = ", np.arccos(x))
    print("arctan(x) = ", np.arctan(x))

def logarithms():
    x = [1, 2, 3]
    print("x     =", x)
    print("e^x   =", np.exp(x))
    print("2^x   =", np.exp2(x))
    print("3^x   =", np.power(3, x))

    x = [1, 2, 4, 10]
    print("x        =", x)
    print("ln(x)    =", np.log(x))
    print("log2(x)  =", np.log2(x))
    print("log10(x) =", np.log10(x))

    x = [0, 0.001, 0.01, 0.1]
    print("exp(x) - 1 =", np.expm1(x))
    print("log(1 + x) =", np.log1p(x))

def advanced_feature():
    # write computation results directly to the memory location
    x = np.arange(5)
    y = np.empty(5)
    np.multiply(x, 10, out=y)
    print(y)

    y = np.zeros(10)
    np.power(2, x, out=y[::2])
    print(y)

    x = np.arange(1, 6)
    print('x=', x)
    sum = np.add.reduce(x)
    print('sum=', sum)
    mul = np.multiply.reduce(x)
    print('multiply reduce=', mul)
    sum2 = np.add.accumulate(x)
    mul2 = np.multiply.accumulate(x)
    out = np.multiply.outer(x, x)
    print('add.accumulate=', sum2)
    print('multiply.accumulate=', mul2)
    print('multiply.outer=', out)

from scipy import special

def scipy_special():
    # Gamma functions
    x = [1, 5, 10]
    print("gamma(x)     =", special.gamma(x))
    print("ln|gamma(x)| =", special.gammaln(x))
    print("beta(x, 2)   =", special.beta(x, 2))
    # Error function (integral of Gaussian)
    x = np.array([0, 0.3, 0.7, 1.0])
    print("erf(x)  =", special.erf(x))
    print("erfc(x) =", special.erfc(x))
    print("erfinv(x) =", special.erfinv(x))

if __name__ == '__main__':
    print('Numpy Version', np.__version__)
    array_arithmetic()
    trigonometric()
    logarithms()
    advanced_feature()
    scipy_special()


import numpy as np

def euclidean_distance(p1,p2):
	"""
	returns euclidean distance between matrices
	@params:
		p1, p2: np.ndarray
			matrices to perform operation to.
	"""
	return np.sqrt(np.sum((p1-p2)**2, axis=1))

def entropy(p):
		"""
		Will be our measurement for uncertainty in our construction
		of descision tree
		@params:
			p: float

		"""
		if p == 0:
			return 0
		elif p == 1:
			return 0
		else:
			return -(p * np.log2(p) + (1 - p) * np.log2(1 - p))

def information_gain(left_child, right_child):
		"""
		measurement of how much info we gained when splitting a node
		using our entropy method.
		@def:
			takes in a list of classes from left and right child to return
			the information gain of our curr split
		@params:
			left_child: np.ndarray
				curr left child arr
			right_child: np.ndarray
				curr left child arr
		"""
		parent = left_child + right_child
		p_par = parent.count(1) / len(parent) if len(parent) > 0 else 0
		p_left = left_child.count(1) / len(left_child) if len(left_child) \
		> 0 else 0
		p_right = right_child.count(1) / len(right_child) if len(right_child) \
		> 0 else 0

		infogain_p = self.entropy(p_par)
		infogain_l = self.entropy(p_left)
		infogain_r = self.entropy(p_right)

		return infogain_p - len(left_child) / len(parent) * infogain_l - \
		len(right_child) / len(parent) * infogain_r