import numpy as np
from numpy.fft import *

x = [1, 2, 3, 4]
x = np.array(x)

print("\n---x")
print(x)
print("\n---fft([1, 2, 3, 4])")
print(fft([1, 2, 3, 4]))
print("\n---fft([4, 3, 2, 1])")
print(fft([4, 3, 2, 1]))

x = [
    [1, 2, 3, 4, 5],
    [6, 7, 8, 9, 10],
    [11, 12, 13, 14, 15],
    [16, 17, 18, 19, 20],
]

x = np.array(x)

print("\n---x")
print(x)
print("\n---fftshift(x, axes=0)")
print(fftshift(x, axes=0))
print("\n---fftshift(x, axes=1)")
print(fftshift(x, axes=1))

print("\n---x")
print(x)
print("\n---ifftshift(x, axes=0)")
print(ifftshift(x, axes=0))
print("\n---ifftshift(x, axes=1)")
print(ifftshift(x, axes=1))

y0 = fft(x, axis=0)
y1 = fft(x, axis=1)

print("\n---fft(x, axis=0)")
print(y0)
print("\n---fft(x, axis=1)")
print(y1)

ys00 = fft(fftshift(x, axes=0), axis=0)
ys11 = fft(fftshift(x, axes=1), axis=1)

print("\n---fft(fftshift(x, axes=0), axis=0)")
print(ys00)
print("\n---fft(fftshift(x, axes=1), axis=1)")
print(ys11)

ys000 = fftshift(fft(fftshift(x, axes=0), axis=0), axes=0)
ys111 = fftshift(fft(fftshift(x, axes=1), axis=1), axes=1)

print("\n---fftshift(fft(fftshift(x, axes=0), axis=0), axes=0)")
print(ys000)
print("\n---fftshift(fft(fftshift(x, axes=1), axis=1), axes=1)")
print(ys111)

print("-------------------------------------")

x = [1, 2, 3, 4]
x = np.array(x)

y = fft(x)

print("---x")
print(x)

print("---fft(x)")
print(y)

yy = fftshift(fft(fftshift(x)))

print("---x")
print(x)

print("---fftshift(fft(fftshift(x)))")
print(yy)

x = ifft(y)
print("---ifft(fft(x))")
print(x)

x = ifft(yy)
print("---ifft(yy)")
print(x)

x = ifft(fftshift(yy))
print("---ifft(fftshift(yy))")
print(x)

x = fftshift(ifft(yy))
print("---fftshift(ifft(yy))")
print(x)

x = ifftshift(ifft(ifftshift(yy)))
print("---ifftshift(ifft(ifftshift(yy)))")
print(x)

x = fftshift(ifft(fftshift(yy)))
print("---fftshift(ifft(fftshift(yy)))")
print(x)

x = ifftshift(ifft(fftshift(yy)))
print("---ifftshift(ifft(fftshift(yy)))")
print(x)

x = fftshift(ifft(ifftshift(yy)))
print("---fftshift(ifft(ifftshift(yy)))")
print(x)


import math
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

# the following code is provided and doesn't need to be changed.

def selection(population,number_of_parameters):
    '''
    Rank the individuals of the population
    '''
    # we implement rank selection here, i.e. the individuals with the highest fitness go to the next stage
    # in the current implementation that simply means that we have to sort the population according to fitness
    #(the last column)

    population = population[population[:,number_of_parameters].argsort()] # this sorts the array with the individuals with the lowest fitness at the top (remember
    # we want to minimize our function)

    return population

def evaluateFitness(population,capacity,number_of_parameters):
    '''
    Evaluate the fitness of  all individuals
    '''
    for i in range(capacity):
        #print('evaluation:',i)
        # take the parameters of the i-th individual and evaluate the fitness, save the fitness value in the last column
        population[i,number_of_parameters] = fitness_function(population[i,0:number_of_parameters])

    return population

def visualize(population,size):
    '''
    Visualize each individual of the population in a 3D plot.
    The individual with the best fitness is marked with a red cross
    '''
    # Note: only works for two parameters (but that's all we need for this exercise)
    fig = plt.figure()
    ax3d = fig.add_subplot(111,projection='3d')
    ax3d.scatter(population[1:size,0],population[1:size,1],population[1:size,2],c='k',marker='o') # plot all individuals in black with a 'o' marker
    ax3d.scatter(population[0,0],population[0,1],population[0,2],c='r',marker='x') # plot the best individual in red with a 'x' marker
    plt.show()

def fitness_function(params):# the function to optimize
    """
    Computes the "fitness" of a set of parameters. The lower the fitness, the better.
    """
    x = params[0]
    y = params[1]
    fitness = (3*(x**2))+(4*(y**2)) # here you should replace None with the code for the function of x and y as above
    return fitness

###### don't change the code below

assert fitness_function([3,4]) == 91, 'please check your implementation'
assert fitness_function([3,2]) == 43, 'please check your implementation'
assert fitness_function([5,23]) == 2191, 'please check your implementation'

def mutation(population, size, r_mutation, p_mutation, s_mutation, number_of_parameters):
    '''
    mutation - mutate a random subset of the population
    Parameters:
    population - the population from the current generation
    (We simply represent the parameters as a numpy array, and initialize it with random numbers
    the first size rows represent the actual population, the rest gets filled during mutation and crossover
    the first number_of_parameters columns contain the parameters, the last column contains the fitness value)
    size - the size of the population
    r_mutation - the percentage of individuals from the population that undergo mutation
    p_mutation - the probability of a mutation of a single parameter of an individual
    s_mutation - the strength of the mutation
    number_of_parameters - the number of parameters each individual has
    '''
    # choose a random subset of the population which will undergo mutation
    cutoff = int(size*r_mutation) # this is the number of individuals that will undergo mutation
    indices = np.arange(size)

    np.random.shuffle(indices)
    mutation_set = indices[:cutoff] # these are the indices of the randomly chosen individuals that will undergo
                                    # mutation

    inc = 0
    for i in mutation_set: # loop through all individuals that undergo mutation

        for j in range(number_of_parameters): # loop through all parameters of each individual
            p = np.random.rand() # integer in interval 0,1
            if p <= p_mutation: # if integer > p_mutation perform mutation
                r = (1*s_mutation) * np.random.random_sample() - (0.5*s_mutation) # generate number in range given
                population[i,j] = population[i,j] + r # parameter value + r
                population[size+inc,1] = r # store mutated parameter into population
        population[size+inc,0] = population[size+inc,1] # store mutated individual into population
        inc += 1

    return population

###### don't change the code below
population = np.random.random_sample((25,3))
pop = np.array(population)
mutation_population = mutation(population,10,1.0,1.0,1.0,2)

assert mutation_population[10,0] != pop[10,0], 'please check your implementation'
assert mutation_population[10,1] != pop[10,1], 'please check your implementation'
assert mutation_population[11,0] != pop[11,0], 'please check your implementation'
assert mutation_population[11,1] != pop[11,1], 'please check your implementation'
assert mutation_population[12,0] != pop[12,0], 'please check your implementation'
assert mutation_population[12,1] != pop[12,1], 'please check your implementation'
assert mutation_population[13,0] != pop[13,0], 'please check your implementation'
assert mutation_population[13,1] != pop[13,1], 'please check your implementation'
assert mutation_population[14,0] != pop[14,0], 'please check your implementation'
assert mutation_population[14,1] != pop[14,1], 'please check your implementation'

def crossover(population,size,r_crossover,r_mutation,number_of_parameters):
    '''
     crossover - Choose a random subset of the population, select parent pairs and produce offspring
    Parameters:
    population - the population from the current generation
    (We simply represent the parameters as a numpy array, and initialize it with random numbers
    the first size rows represent the actual population, the rest gets filled during mutation and crossover
    the first number_of_parameters columns contain the parameters, the last column contains the fitness value)
    size - the size of the population)
    r_crossover - the percentage of individuals from the population that serve as parents for crossover
    r_mutation - the percentage of individuals from the population that undergo mutation (needed in order
    to correctly store the newly produced offspring!)
    number_of_parameters - the number of parameters each individual has
    '''
    # At the moment, when we do the crossover, the population is already sorted according to fitness values!
    cutoff = int(size*r_crossover) # this is the number of individuals that will undergo crossover
    crossover_set = np.arange(cutoff) # these are the indices of the self.r_crossover % individuals that will undergo crossover
    a = int((size * r_mutation) + size) # continuation from mutated individuals

    n = 0
    while n<cutoff:
        individual_a = np.random.choice(crossover_set) # randomly choose the first individual
        crossover_set = [x for x in crossover_set if x not in [individual_a]] # remove the individual from the set
        individual_b = np.random.choice(crossover_set) # randomly choose the second individual from the remaining set
        crossover_set = [x for x in crossover_set if x not in [individual_b]] # remove the individual from the set
        # perform the actual crossover
        # here you should place your code for task 3);
        # the comments in the following lines give you a hint of what you are supposed to do
        for j in range(number_of_parameters):
            #print(j)
            r = np.random.rand()
            if r < 0.5:
                population[a,j] = population[individual_a,j]
            else:
                population[a,j] = population[individual_b,j]
        n = n+2# increase counter by 2, since we have chosen 2 individuals
        a = a + 1
    return population

###### don't change the code below
population = np.random.random_sample((25,3))
pop = np.array(population)
crossover_population = crossover(population,10,1.0,1.0,2)

assert crossover_population[20,0] != pop[20,0], 'please check your implementation'
assert crossover_population[20,1] != pop[20,1], 'please check your implementation'
assert crossover_population[21,0] != pop[21,0], 'please check your implementation'
assert crossover_population[21,1] != pop[21,1], 'please check your implementation'
assert crossover_population[22,0] != pop[22,0], 'please check your implementation'
assert crossover_population[22,1] != pop[22,1], 'please check your implementation'
assert crossover_population[23,0] != pop[23,0], 'please check your implementation'
assert crossover_population[23,1] != pop[23,1], 'please check your implementation'

def evolve(population,size,r_mutation,p_mutation,s_mutation,r_crossover,capacity,number_of_parameters,number_of_generations):
    '''
    evolve - evolves the genetic algorithm for the specified number of generations
    Parameters:
    population - the population from the current generation
    size - the size of the population
    r_mutation - the percentage of individuals from the population that undergo mutation
    p_mutation - the probability of a mutation of a single parameter of an individual
    s_mutation - the strength of the mutation
    r_crossover - the percentage of individuals from the population that serve as parents for the crossover
    capacity - the overall size of the population array (includes the actual population, the newly mutated individuals
    and the newly produced offspring)
    number_of_parameters - the number of parameters each individual has
    number_of_generations - the number of generations the genetic algorithm will be evolved
    '''

    for i in range(number_of_generations):
        print(i) # print the current generation number
        # here you should place your code for task 4)
        # decide in which order the functions have to be called
        # call them and give them the correct parameters as arguments
        evaluateFitness(population, capacity, number_of_parameters)
        population = selection(population, number_of_parameters)
        crossover(population,size,r_crossover,r_mutation,number_of_parameters )
        mutation(population, size, r_mutation, p_mutation, s_mutation, number_of_parameters)

    #visualize(population,size)
    return population

size = 100 # the size of the population
number_of_parameters = 2 # the number of parameters the function takes
number_of_generations = 20 # number of generations that are executed
p_mutation  = 0.5 # the probability of a mutation
r_mutation  = 0.2 # the percentage of individuals that undergo mutation
s_mutation  = 1.25 # the mutation strength
r_crossover = 0.4 # the percentage of individuals that undergo crossover

capacity = size + int(size*r_mutation) + int(size*r_crossover/2.0) # this is the size of the population after crossover and selection
print("capactiy",capacity)
# We simply represent the parameters as a numpy array, and initialize it with random numbers
# the first size rows represent the actual population, the rest gets filled during mutation and crossover
# the first number_of_parameters columns contain the parameters, the last column contains the fitness value
population = np.random.random_sample((capacity,number_of_parameters+1))

final_population = evolve(population,size,r_mutation,p_mutation,s_mutation,r_crossover,capacity,number_of_parameters,number_of_generations)

###### don't change the code below

print(final_population[0,2])
assert final_population[0,2] < 0.001, 'please check your implementation'
assert final_population[1,2] < 0.001, 'please check your implementation'
assert final_population[2,2] < 0.001, 'please check your implementation'
assert final_population[3,2] < 0.001, 'please check your implementation'
assert final_population[4,2] < 0.001, 'please check your implementation'


# load required library
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_iris
import scipy.optimize as opt

x, y = load_iris(return_X_y=True)
x = x[:100, :2]  # class 0 and 1 balanced
y = y[:100]

def draw_data(x, y):
    #########################################################################
    # Full Mark: 1                                                          #
    # TODO:                                                                 #
    # 1. make a scatter plot of the raw data                                #
    # 2. set title for the plot                                             #
    # 3. set label for x,y axis                                             #
    # Note, this scatter plot has two different type of points              #
    #########################################################################
    plt.title("Logistic Regression")
    plt.xlabel("x")
    plt.ylabel("y")
    pos = np.where(y == 0)
    neg = np.where(y == 1)
    plt.scatter(x[pos, 0], x[pos, 1], marker='x', color='r', label='class0')
    plt.scatter(x[neg, 0], x[neg, 1], marker='o', color='b', label='class1')
    plt.legend()
    #########################################################################
    #                       END OF YOUR CODE                                #
    #########################################################################

    # show plot
    plt.show()

# define sigmoid function
# math: refer to https://en.wikipedia.org/wiki/Sigmoid_function or slides
def sigmoid(theta, X):
    #########################################################################
    # Full Mark: 1                                                          #
    # TODO:                                                                 #
    # 1. implement the sigmoid function over input theta and X
    #########################################################################
    y_ = np.dot(X, theta)
    s = 1.0 / (1 + np.exp(-y_))
    #########################################################################
    #                       END OF YOUR CODE                                #
    #########################################################################

    return s

# define cost function with sigmoid function
def cost(theta, X, y):
    #########################################################################
    # Full Mark: 2                                                          #
    # TODO:                                                                 #
    # 1. implement the cross entropy loss function with sigmoid             #
    #########################################################################
    hx = sigmoid(theta, X)
    if np.sum(1 - hx < 1e-10) != 0:
        return np.inf
    co = -np.mean(np.multiply(y, np.log(hx)) + np.multiply(1 - y, np.log(1 - hx)))
    #########################################################################
    #                       END OF YOUR CODE                                #
    #########################################################################
    return co

# the gradient of the cost is a vector of the same length as θ where the jth element (for j = 0, 1, . . . , n)
def gradient(theta, X, y):
    #########################################################################
    # Full Mark: 2                                                          #
    # TODO:                                                                 #
    # 1. calculate the gradients using theta and sigmoid                    #
    # Hint: X may need to be transposed to do matrix operation              #
    #########################################################################
    y_ = sigmoid(theta, X)
    grad = np.dot(X.T,  y_ - y)/len(X)
    #########################################################################
    #                       END OF YOUR CODE                                #
    #########################################################################
    return grad

# draw decision boudary
def draw_decision_boudary(final_theta,x,y):
    #########################################################################
    # Full Mark: 2                                                          #
    # TODO:                                                                 #
    # 1. plot the decision boudary on the raw data                          #
    # 2. set title for the plot                                             #
    # 3. set label for x,y axis                                             #
    # Note, this scatter plot has two different type of points              #
    #########################################################################
    plt.title("Logistic Regression")
    plt.xlabel("x")
    plt.ylabel("y")
    pos = np.where(y == 0)
    neg = np.where(y == 1)
    plt.scatter(x[pos, 1], x[pos, 2], marker='x', color='r', label='class0')
    plt.scatter(x[neg, 1], x[neg, 2], marker='o', color='b', label='class1')

    plot_x = np.array([np.min(x[:, 1]) - 1, np.max(x[:, 1] + 1)])
    plot_y = -1 / final_theta[2] * (final_theta[1] * plot_x + final_theta[0])

    plt.plot(plot_x, plot_y)

    plt.legend()
    #########################################################################
    #                       END OF YOUR CODE                                #
    #########################################################################

    # show plot
    plt.show()

# predict for new X
def predict(theta, X):
    #########################################################################
    # Full Mark: 1                                                          #
    # TODO:                                                                 #
    # 1. predict the value using theta and sigmoid                          #
    # 2. convert the predicted value to 0/1                                 #
    # That's how it is called Logistic regression                           #
    #########################################################################
    m = len(X)
    predict_labels = np.zeros((m,))
    pos = np.where(sigmoid(theta, X) >= 0.5)
    neg = np.where(sigmoid(theta, X) < 0.5)
    predict_labels[pos] = 1
    predict_labels[neg] = 0
    #########################################################################
    #                       END OF YOUR CODE                                #
    #########################################################################

    return predict_labels

# calculate accuracy
def accurate(predictions, y):
    #########################################################################
    # Full Mark: 1                                                          #
    # TODO:                                                                 #
    # 1. calculate the accuracy value                                       #
    # Note that you coud not import extra library                           #
    #########################################################################
    accuracy_score = np.sum(predictions == y) / len(y)
    #########################################################################
    #                       END OF YOUR CODE                                #
    #########################################################################
    return accuracy_score

if __name__ == '__main__':
    draw_data(x, y)

    x = np.concatenate((np.array([np.ones(len(y))]).T, x), axis=1)
    theta = np.zeros(x.shape[1])

    result = opt.fmin_tnc(func=cost, x0=theta, fprime=gradient, args=(x, y))
    final_theta = result[0]
    final_cost = cost(final_theta, x, y)
    predictions = predict(final_theta, x)
    accuracy = accurate(predictions, y)
    print("final cost is " + str(final_cost))
    print("accuracy is " + str(accuracy))

    draw_decision_boudary(final_theta, x, y)


import numpy as np

from Matrices import *

print("Determinant of diagonal matrix:")
print(np.linalg.det(diag_A))
diag_A_rev = np.linalg.inv(diag_A)
print("Condition number of diagonal matrix:")
print(np.linalg.norm(diag_A_rev) * np.linalg.norm(diag_A))

print("Determinant of random matrix:")
print(np.linalg.det(random_A))
random_A_rev = np.linalg.inv(random_A)
print("Condition number of random matrix:")
print(np.linalg.norm(random_A_rev) * np.linalg.norm(random_A))

print("Determinant of Hilbert matrix:")
print(np.linalg.det(hilbert_A))
hilbert_A_rev = np.linalg.inv(hilbert_A)
print("Condition number of Hilbert matrix:")
print(np.linalg.norm(hilbert_A_rev) * np.linalg.norm(hilbert_A))


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

def levy(mu, c, x):
    try:
        y = math.sqrt(0.5/(2*math.pi))*(math.e**(-c/(2*(x-mu)))/(x-mu)**(3/2))
    except:
        y = 0
    return y

if __name__ == "__main__" :
    mu = 0

    xList = []
    yList1 = []
    yList2 = []
    yList3 = []
    yList4 = []

    for i in np.arange(0, 2, 0.001) :
        xList.append(i)
        yList1.append(levy(mu, 0.5, i))
        yList2.append(levy(mu, 1, i))
        yList3.append(levy(mu, 2, i))
        yList4.append(levy(mu, 4, i))

    plt.plot(xList, yList1)
    plt.plot(xList, yList2)
    plt.plot(xList, yList3)
    plt.plot(xList, yList4)
    plt.legend(["c=0.5", "c=1", "c=2", "c=4"])
    plt.show()


"""
Problem 10
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.
"""
import numpy as np

# below is example with Fermat's small theorem - which works, but is slow...

def fermat_primality(number, runs):
    main = []

    def fermat_test(n):
        x = np.random.randint(2, n - 2)
        t = x ** (n - 1)

        if t % n == 1:
            return True
        else:
            return False

    for i in range(runs):
        if fermat_test(number):
            main.append(True)
        else:
            main.append(False)

    if False in main:
        return False

    return True

def execute_fermat(n):
    fermat_primes = [2, 3]

    for j in range(5, n + 1):
        if fermat_primality(number=j, runs=2):
            fermat_primes.append(j)
            print(j)

# execute_fermat(2000000)

# implementation of Sieve of Eratosthenes - much more efficient

def sieve_of_eratosthenes(n):
    # set can only contain unique values
    non_primes = set()
    primes = set()

    for i in range(2, n + 1):  # run numeral n (n + 1) because 0 count
        # sets are efficient for lookups like below

        if i not in non_primes:

            # do sieve cross-out with distance i and start i^2, end numeral n
            non_primes.update(range(i**2, n + 1, i))

            # add i to primes, because it hasn't been crossed yet, and must be prime
            primes.add(i)

    # return sorted set of primes
    return sorted(primes)

print(sum(sieve_of_eratosthenes(2000000)))

Solutions/Problem 10 - Summation of primes.py


import numpy as np
from scipy.signal import convolve2d

def matlab_style_gauss2D(shape=(11,11),sigma=1.5):
    """
    2D gaussian mask - should give the same result as MATLAB's
    fspecial('gaussian',[shape],[sigma])
    """
    m,n = [(ss-1.)/2. for ss in shape]
    y,x = np.ogrid[-m:m+1,-n:n+1]
    h = np.exp( -(x*x + y*y) / (2.*sigma*sigma) )
    h[ h < np.finfo(h.dtype).eps*h.max() ] = 0
    sumh = h.sum()
    if sumh != 0:
        h /= sumh
    return h

def ssim_index(img1, img2, K=[0.01, 0.03], window=None, L=255):
    """ Calculate the structural similarity between two images

    Args:
        img1 ([type]): [description]
        img2 ([type]): [description]
        K ([type]): [description]
        window ([type]): [description]
        L ([type]): [description]
    """
    if window is not None:
        window=matlab_style_gauss2D()

    if img1.shape != img2.shape:
        print("Error: Images has different shapes")
        return None

    M, N = img1.shape

    if (M < 11 or N < 11):
        print("Error: wrong shape")
        return None

    # Maybe it's necessary to convert rgb to YCbCr

    C1 = (K[0]*L)**2
    C2 = (K[1]*L)**2

    window = window/window.sum()    # Normalize filter

    mu1 = convolve2d(img1, np.rot90(window), mode='valid')
    mu2 = convolve2d(img2, np.rot90(window), mode='valid')

    mu1_sq = mu1*mu1
    mu2_sq = mu2*mu2
    mu1_mu2 = mu1*mu2

    sigma1_sq = convolve2d(img1*img1, np.rot90(window), mode='valid')
    sigma2_sq = convolve2d(img2*img2, np.rot90(window), mode='valid')
    sigma12 = convolve2d(img1*img2, np.rot90(window), mode='valid')

    if(C1>0 and C2>0):
        ssim_map =  ((2*mu1_mu2 + C1)*(2*sigma12 + C2))/((mu1_sq + mu2_sq + C1)*(sigma1_sq + sigma2_sq + C2))
    else:
        numerator1 = 2*mu1_mu2 + C1
        numerator2 = 2*sigma12 + C2
        denominator1 = mu1_sq + mu2_sq + C1
        denominator2 = sigma1_sq + sigma2_sq + C2
        ssim_map = np.ones(mu1.shape)
        index = (denominator1*denominator2 > 0)
        ssim_map[index] = (numerator1[index]*numerator2[index])/(denominator1[index]*denominator2[index])
        index = (denominator1 != 0) & (denominator2 == 0)
        ssim_map[index] = numerator1[index]/denominator1[index]

    mssim = np.mean(ssim_map)

    return mssim


# Developed by Bayram Barış Sarı
# E-mail = bayrambariss@gmail.com
# Tel = +90 539 593 7501
#
# This is an implementation of Singular
# Value Decomposition.
#
# It finds SVD and plots for 4 different
# ranks: 1,5,20,50.

import numpy as np
import matplotlib.pyplot as plt
import scipy.linalg as la
from PIL import Image
from math import isclose

# I used this function for comparing calculated matrices with builtin SVD's matrices
# def print_to_file(matrix):
#     mat = np.matrix(matrix)
#     with open('outfile.txt', 'wb') as f:
#         for line in mat:
#             np.savetxt(f, line, fmt='%.2f')

def calculate(A):
    m = A.shape[0]
    n = A.shape[1]
    S = np.zeros(n)

    # finding eigenvectors with biggest eigenvalues of A*transpose(A)
    helper = np.matmul(A, np.transpose(A))
    eigenvalues, eigenvectors = la.eigh(helper)
    # descending sort of all the eigenvectors according to their eigenvalues
    index = eigenvalues.argsort()[::-1]
    eigenvalues = eigenvalues[index]
    eigenvectors = eigenvectors[:, index]
    V = eigenvectors

    # S is a diagonal matrix that keeps square root of eigenvalues
    j = 0
    for i in eigenvalues:
        if j == S.size:
            break
        elif i >= 0:
            S[j] = np.sqrt(i)
            j += 1
    # same finding process for transpose(A)*A
    helper = np.matmul(np.transpose(A), A)
    eigenvalues, eigenvectors = la.eigh(helper)
    # descending sort of all the eigenvectors according to their eigenvalues
    index = eigenvalues.argsort()[::-1]
    eigenvalues = eigenvalues[index]
    eigenvectors = eigenvectors[:, index]
    U = np.transpose(eigenvectors)

    # S is a diagonal matrix that keeps square root of eigenvalues
    for i in eigenvalues1:
        if j == S.size:
            break
        elif i >= 0:
            S[j] = np.sqrt(i)
            j += 1

    # sorting S in descending order
    S[::-1].sort()
    # print_to_file(S)

    return U, S, V

def plot(img, Ur, Sr, Vr, Ug, Sg, Vg, Ub, Sb, Vb):
    rank = [1, 5, 20, 50]
    for i in rank:
        # calculating V*S*transpose(U) for each channel
        x = Vr[:, 0:i]
        y = Sr[0:i]
        xy = x.dot(np.diag(y))
        z = Ur[0:i]
        merged = xy.dot(z)
        img[:, :, 0] = merged.T

        x = Vg[:, 0:i]
        y = Sg[0:i]
        xy = x.dot(np.diag(y))
        z = Ug[0:i]
        merged = xy.dot(z)
        img[:, :, 1] = merged.T

        x = Vb[:, 0:i]
        y = Sb[0:i]
        xy = x.dot(np.diag(y))
        z = Ub[0:i]
        merged = xy.dot(z)
        img[:, :, 2] = merged.T

        plt.title("Implemented SVD, Rank: %d" % i)
        plt.imshow(img)
        plt.show()

def check_sign_U(U, builtin):
    for i in range(builtin.shape[0]):
        if not isclose(U[i][0], builtin[0][i]):
            U[i] *= -1

    return U

def check_sign_V(V, builtin):
    for i in range(builtin.shape[0]):
        if not isclose(V[0][i], builtin[i][0]):
            V[:, i] *= -1

    return V

def plot_builtin(Ur, Sr, Vr, Ug, Sg, Vg, Ub, Sb, Vb, img):
    rank = [1, 5, 20, 50]
    for i in rank:
        x = Ur[:, 0:i]
        y = Sr[0:i]
        xy = x.dot(np.diag(y))
        z = Vr[0:i]
        merged = xy.dot(z)
        img[:, :, 0] = merged

        x = Ug[:, 0:i]
        y = Sg[0:i]
        xy = x.dot(np.diag(y))
        z = Vg[0:i]
        merged = xy.dot(z)
        img[:, :, 1] = merged

        x = Ub[:, 0:i]
        y = Sb[0:i]
        xy = x.dot(np.diag(y))
        z = Vb[0:i]
        merged = xy.dot(z)
        img[:, :, 2] = merged

        plt.title("Builtin SVD, Rank: %d" % i)
        plt.imshow(img)
        plt.show()

def main():
    # read the image and normalize it
    image = np.array(Image.open('data.jpg'))
    image = image / 255
    # plt.imshow(image)
    # plt.show()

    # Split the image to three channels, Red, Green and Blue
    R = image[:, :, 0]
    G = image[:, :, 1]
    B = image[:, :, 2]

    # Calculate builtin SVD function, it has been used for checking eigenvectors and eigenvalues
    new_img = np.zeros(image.shape)
    Ur, Sr, Vr = la.svd(R, full_matrices=True)
    Ug, Sg, Vg = la.svd(G, full_matrices=True)
    Ub, Sb, Vb = la.svd(B, full_matrices=True)
    # plot_builtin(Ur, Sr, Vr, Ug, Sg, Vg, Ub, Sb, Vb, new_img)

    # Calculate own SVD and plot it for rank = [1,5,20,50]
    new_img2 = np.zeros(image.shape)

    U_r, S_r, V_r = calculate(R.T)
    U_r = check_sign_U(U_r, Ur)
    V_r = check_sign_V(V_r, Vr)

    U_g, S_g, V_g = calculate(G.T)
    U_g = check_sign_U(U_g, Ug)
    V_g = check_sign_V(V_g, Vg)

    U_b, S_b, V_b = calculate(B.T)
    U_b = check_sign_U(U_b, Ub)
    V_b = check_sign_V(V_b, Vb)

    plot(U_r, S_r, V_r, U_g, S_g, V_g, U_b, S_b, V_b, new_img2)

if __name__ == "__main__":
    main()


import numpy as np

def gaussian(X, mu, cov):
    """
        Returns the pdf of a Gaussian kernel

        :param X: Input data.
        :type X: :obj:`numpy.ndarray`
        :param mu: Mean of the gaussian distribution.
        :type mu: :obj:`numpy.ndarray`
        :param cov: Covariance matrix.
        :type cov: :obj:`numpy.ndarray`

        :formula:

            .. math:: \\dfrac{1}{(2 \\pi)^{\\frac{n}{2}} \\sqrt{\\det{\\sigma}}} e^{-\\dfrac{1}{2} \\dfrac{X'X}{\\sigma^{2}}}

        :references: * Murphy, K. P. (2012). Machine learning: a probabilistic perspective. MIT press.
    """
    X_centered = X - mu
    n = X.shape[1]
    _a = (1 / ((2 * np.pi) ** (n / 2) * np.linalg.det(cov) ** 0.5))
    _b = np.exp(-0.5 * np.dot(np.dot(X_centered, np.linalg.inv(cov)), X_centered.T))

    return np.diagonal(_a * _b).reshape(-1, 1)


import numpy as np
import time
MAX = 100;
def create_tridiag(a, b, c, n):
    A = np.zeros((n, n))
    for i in range(n):
        A[i][i] = b
        if i < n - 1:
            A[i + 1][i] = a
            A[i][i + 1] = c
    return A

def Doolittle(mat, n):
    lower = np.zeros((n,n))
    upper = np.zeros((n,n))

    for i in range(n):

        # Upper Triangular
        for k in range(i, n):

            # Summation of L(i, j) * U(j, k)
            sum = 0;
            for j in range(i):
                sum += (lower[i][j] * upper[j][k]);

            # Evaluating U(i, k)
            upper[i][k] = mat[i][k] - sum;

        # Lower Triangular
        for k in range(i, n):
            if (i == k):
                lower[i][i] = 1;  # Diagonal as 1
            else:

                # Summation of L(k, j) * U(j, i)
                sum = 0;
                for j in range(i):
                    sum += (lower[k][j] * upper[j][i]);

                # Evaluating L(k, i)
                lower[k][i] = int((mat[k][i] - sum) /
                                  upper[i][i]);

            # setw is for displaying nicely
    print("Lower Triangular\t\tUpper Triangular");
    return lower, upper

n = 50
a = create_tridiag(1, 4, -1, n)
b = [1 for i in range(n)]
start = time.time()
L, U = Doolittle(a, n);
end = time.time()

print("L: ")
print(L)
print("U: ")
print(U)
print("Time: ", end - start)


# loss functions

import jax.numpy as np

def mse(y_pred, y_true):
    ''' Description: mean-square-error loss
        Args:
            y_pred : value predicted by method
            y_true : ground truth value
            eps: some scalar
    '''
    return np.sum((y_pred - y_true)**2)

def cross_entropy(y_pred, y_true, eps=1e-9):
    ''' Description: cross entropy loss, y_pred is equivalent to logits and y_true to labels
        Args:
            y_pred : value predicted by method
            y_true : ground truth value
            eps: some scalar
    '''
    return - np.sum(y_true * np.log(y_pred + eps))


from scipy.spatial.distance import pdist, squareform
from scipy import exp
from scipy.linalg import eigh
import numpy as np

author = "Oscar Ding"

def rbf_kernel_pca(X, gamma, n_components):
    """
    RBF kernel PCA implementation.

    Parameters
    ------------
    X: {NumPy ndarray}, shape = [n_samples, n_features]

    gamma: float
      Tuning parameter of the RBF kernel

    n_components: int
      Number of principal components to return

    Returns
    ------------
     X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
       Projected dataset
     lambdas: list
       Eigenvalues

    """
    # Calculate pairwise squared Euclidean distances in the MxN dimensional dataset.
    sq_dists = pdist(X, 'sqeuclidean')

    # Convert pairwise distances into a square matrix.
    mat_sq_dists = squareform(sq_dists)

    # Compute the symmetric kernel matrix.
    K = exp(-gamma * mat_sq_dists)

    # Center the kernel matrix.
    N = K.shape[0]
    one_n = np.ones((N, N)) / N
    K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)

    # Obtaining eigenpairs from the centered kernel matrix
    # scipy.linalg.eigh returns them in ascending order
    eigvals, eigvecs = eigh(K)
    eigvals, eigvecs = eigvals[::-1], eigvecs[:, ::-1]

    # Collect the top k eigenvectors (projected samples)
    alphas = np.column_stack((eigvecs[:, i] for i in range(n_components)))

    # Collect the corresponding eigenvalues
    lambdas = [eigvals[i] for i in range(n_components)]

    return alphas, lambdas


"""
demo_nonlinear_programming_equality_constraints.py

(Non)linear objective function and (non)linear equality constraints

m = number of equality constraints;
n = number of parameters;

Objective function:
    Minimize f(X), where
    X = [x1, ..., xn].T is vector of variables;
    X* is extreme point (MIN or MAX);

Equality constrains:
    Subject to equality constraints: h(X);
    h(X) = [h1(X), ..., hn(X)].T is vector of constraints;
    m < n;

Lagrange algorithm

Lagrangian function:
    l(X, Lambda) = f(X) + lambda.T @ h(X);
    Lambda = [lambda1, ..., lambdan].T is vector of langrange multipliers;
    Lambda* is extreme point;

1st Condition:
    Gradient of lagrangian function:
        Dl(X*, Lambda*) = Df(X*) + Dh(X*).T @ Lambda = 0.T;

2nd Condition:
    Normal space formed by all normal vectors of f(X) and h(X), i.e. Df(X) and Dh(X), at X*:
        N(Dh(X*).T) is null space of Dh(X*).T;
    Tangent space formed by all tangent (and shared!) vectors of f(X() and h(X) at X*:
        T(X*) is tangent space;
    Hessian of l(X, lambda):
        Hl(X, lambda) = Hf(X) + lambda1 * Hh1(X) + ... + lambdan * Hhn(X);

    Tangent and Normal spaces are orthogonal:
        T(X*) = N(Dh(X*).T);

    Solution lies in the tangent space:
        T(X*).T @ Hl(X*, lambda*) @ T(X*) > 0, X* is MIN;
"""

import numpy as np

"""
Problem # 1
Minimize f(X) = x1^2 + 2x1x2 + 3x2^2 + 4x1 + 5x2 + 6x3;
Constraints:
        h1(X) = x1 + 2x2 - 3 = 0;
        h2(X) = 4x1 + 5x3 - 6 = 0;

X = [x1, x2, x3].T;
Lambda = [lambda1, lambda2].T;

Df(X) = [2x1 + 2x2 + 4
         2x1 + 6x2 + 5
         6];

Dh(X) = [1, 2, 0
         4, 0, 5];

Solve system of eqs.:
1. Dl(X, Lambda) = [2x1 + 2x2 + 4 + lambda1 * [1, 2, 0].T + lambda2 * [4, 0, 5].T = 0.T;
                 2x1 + 6x2 + 5
                 6];
2. x1 + 2x2 - 3 = 0;
3. 4x1 + 5x3 - 6 = 0;

Hl(X*, Lambda*) = [2, 2, 6
                   2, 6, 0
                   0, 0, 0];

T(X*) = [-5/4, 5/8, 1].T;
"""

A = np.array([[2, 2, 0, 1, 4], [2, 6, 0, 2, 0], [0, 0, 0, 0, 5],
              [1, 2, 0, 0, 0], [4, 0, 5, 0, 0]]);
B = np.array([[-4], [-5], [-6], [3], [6]]);

solution = np.linalg.solve(A, B);
X_opt = solution[0:3]; # X*
lambda_opt = solution[3:-1]; # lambda*
print('X:');
print(X_opt);

"""
Problem # 2
X = [x1, x2].T;
Q = np.array([[8, 2 * np.sqrt(2)], [2 * np.sqrt(2), 10], [5 * np.sqrt(2), 1]]);
C = np.array([[3], [6], [8]]);
D = 24;
A = np.random.rand(2, 3);
B = np.random.rand(2, 1);
Minimize f(X) = 1 / 2 * X.T @ Q @ X - C.T @ X + D;
Constraints:
        h(X) = A @ X - B = 0;

Df(X) = X.T @ Q - C;
Dh(X) = A;

Solve system of eqs.:
1. Dl(X, Lambda) = X.T @ Q - C.T + lambda.T @ A = 0.T;
2. A @ X - B = 0;

Hl(X*, lambda*) = Q;
"""

Q = np.array([[8, 2 * np.sqrt(2), 11], [2 * np.sqrt(2), 10, 1], [0.5 * np.sqrt(2), 5, 2]]);
C = np.array([[3], [6], [8]]);
D = 24;
A = np.random.rand(2, 3);
B = np.random.rand(2, 1);

Qinv = np.linalg.inv(Q);
Qinv_times_At = Qinv @ A.T;

lambda_opt = np.linalg.inv(Qinv_times_At.T @ A.T) @ (B - Qinv_times_At.T @ C);
X_opt = Qinv @ C + Qinv_times_At @ lambda_opt;
print('X:');
print(X_opt);


import matplotlib.pyplot as plt
from scipy.optimize import brentq
import numpy as np

DELTA = 0.01

m2 = 1 / 82

f = lambda x: x - (1 - m2) * (x + m2) / (abs(x + m2) ** 3) - m2 * (x - 1 + m2) / (abs(x - 1 + m2) ** 3)

segments = [[-2, -m2 - DELTA],
            [-m2 + DELTA, 1 - m2 - DELTA],
            [1 - m2 + DELTA, 2]]

roots = [brentq(f, segments[i][0], segments[i][1]) for i in range(len(segments))]

x = [np.linspace(segments[i][0], segments[i][1], round(1 / DELTA)) for i in range(len(segments))]
y = [f(x[i]) for i in range(len(segments))]

plt.plot(roots, [0, 0, 0], marker="o", linestyle='')
for i in range(len(segments)):
    plt.plot(x[i], y[i])

plt.axhline(color="grey", ls="--", zorder=-1)
plt.axvline(color="grey", ls="--", zorder=-1)

plt.axvline(color="red", ls=":", zorder=-1, x=-m2)
plt.axvline(color="red", ls=":", zorder=-1, x=1 - m2)

plt.axis([-2, 2, -10, 10])
plt.show()

print(roots)


# kurva bezier  adalah kurva parametrik yang sering
# digunkan dalam pemodelan permukaan halus dalam
# grafik komputer dan banuak bidang terkait lainnya.
# kurva ini dapat diskalakan tanpa batas.
# digunakan juga dalam mengendalikan animasi.

from __future__ import annotations

from scipy.special import comb  # type: ignore

class BezierCurve:
    def __init__(self, list_of_points: list[tuple[float, float]]):
        """
        list_of_points: titik kontrol pada bidang xy yang akan
        di interpolasi. ini poin mengontrol dari kurva bezier.
        """
        self.list_of_points = list_of_points

        # mementukan fleksibilitas kurva
        # derajat = 1 akan menghasilkan garis lurus
        self.degree = len(list_of_points) - 1

    def basis_function(self, t: float) -> list[float]:
        """
        fungsi basis menentukan bobot setiap titik kendali
        pada waktu t.
        t: nilai waktu antar 0 dan 1 inklusif untuk evaluasi
        basis kurva.
        return: mengembalikan nilai x, y dari fungsi dasar
        pada waktu t.

        >>> curve = BezierCurve([(1, 1), (1, 2)])
        >>> curve.basis_function(0)
        [1.0, 0.0]
        >>> curve.basis_function(1)
        [0.0, 1.0]
        """
        assert 0 <= t <= 1, "waktu t harus antara 0 dan 1."
        output_values: list[float] = []
        for i in range(len(self.list_of_points)):
            # basis fungsi dari setiap 1
            output_values.append(
                comb(self.degree, i) * (1 - t) ** (self.degree - i) * (t**i)
            )

        assert round(sum(output_values), 5) == 1

        return output_values

    def bezier_curve_function(self, t: float) -> tuple[float, float]:
        """
        fungsi untuk menghasilkan nilai kurva bezier pada waktu t.
        t: nilai waktu untuk evaluasi fungsi bezier
        return: mengembalikan kordinaat x, y dari kurva bezier
        pada waktu t.

        titik pertama kurva adalah ketika t = 0
        titik terakhir dalam kurva adalah ketika t = 1

        >>> curve = BezierCurve([(1, 1), (1, 2)])
        >>> curve.bezier_curve_function(0)
        (1.0, 1.0)
        >>> curve.bezier_curve_function(1)
        (1.0, 2.0)
        """

        assert 0 <= t <= 1, "waktu t harus antara 0 dan 1."

        basis_function = self.basis_function(t)
        x = 0.0
        y = 0.0

        for i in range(len(self.list_of_points)):
            x += basis_function[i] * self.list_of_points[i][0]
            y += basis_function[i] * self.list_of_points[i][1]

        return (x, y)

    def plot_curve(self, step_size: float = 0.01):
        """
        plit kurva bezier menggunakan matplotlib
        step_size: mendefinisikan langkah untuk
        mengevaluassi kurva bezier.

        semakin kecil ukurang langkah, semakin halus
        kurva yang dihasilkan.
        """
        from matpltlib import pyplot as plt  # type: ignore

        to_plot_x: list[float] = []
        to_plot_y: list[float] = []

        t = 0.0
        while t <= 1:
            value = self.bezier_curve_function(t)
            to_plot_x.append(value[0])
            to_plot_y.append(value[1])
            t += step_size

        x = [i[0] for i in self.list_of_points]
        y = [i[1] for i in self.list_of_points]

        plt.plot(
            to_plot_x,
            to_plot_y,
            color="blue",
            label="derajat kurva "
            + str(
                self.degree,
            ),
        )
        plt.scatter(x, y, color="red", label="Control Point")
        plt.legend()
        plt.show()

if __name__ == "__main__":
    import doctest

    doctest.testmod()

    BezierCurve([(1, 2), (3, 5)]).plot_curve()
    BezierCurve([(0, 0), (5, 5), (5, 0)]).plot_curve()
    BezierCurve([(0, 0), (5, 5), (5, 0), (2.5, -2.5)]).plot_curve()


import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

X = np.linspace(-2, 2)
Y = np.linspace(-2, 2)
x, y = np.meshgrid(X, Y)
t = x**2 + y**2  # small efficiency
z = np.cos(2*np.pi*t)*np.exp(-t)

fig = plt.figure()
ax = fig.add_subplot(projection="3d")
ax.plot_surface(x, y, z, cmap="binary_r")
ax.set_title("Surface with colormap")
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.set_zlabel("$z$")

plt.show()

fig, ax = plt.subplots()
ax.contour(x, y, z, cmap="binary_r")

ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.set_title("Contour plot with colormap set")

plt.show()


import numpy as np
import einops

def derive_rotation_matrices(order: int) -> np.ndarray:
    """Calculate a set of rotation matrices for a cyclic symmetry.

    Axis of rotation is the Z axis.
    Matrices are defined
    Rz = [[cos(t), -sin(t),    0],
          [sin(t),  cos(t),    0],
          [     0,       0,    1]]

    Parameters
    ----------
    order : int
        symmetry order

    Returns
    -------
    rotation_matrices: (order, 3, 3) np.ndarray
        matrices defining rotations around the Z axis
    """
    theta = np.linspace(0, 2*np.pi, num=order, endpoint=False)
    cos_theta = np.cos(theta)
    sin_theta = np.sin(theta)

    rotation_matrices = einops.repeat(
        np.eye(3),
        'i j -> new_axis i j',
        new_axis=order
    )
    rotation_matrices[:, 0, 0] = cos_theta
    rotation_matrices[:, 0, 1] = -sin_theta
    rotation_matrices[:, 1, 0] = sin_theta
    rotation_matrices[:, 1, 1] = cos_theta
    return rotation_matrices


import numpy as np
import math

def polar(pt, ang, dist):
    return (pt[0] + dist*np.cos(ang),
            pt[1] + dist*np.sin(ang))

# 2pi is 360 degrees
# pi is 180
# pi/2 is 90
# pi/4 is 45
#print(polar((10,10), np.pi/2, 20))

def angle(pt1, pt2):
    return math.atan2(pt2[1]-pt1[1], pt2[0]-pt1[0])

#print(angle((10,10), (10,20))/np.pi)

# bulge is described here :
# http://www.lee-mac.com/bulgeconversion.html
# which used the function: polar described here:
# http://www.afralisp.net/autolisp/tutorials/calculating-polar-points.php
# 2*pi is 360 degrees

# the function and text below is a translation of this:
# http://www.lee-mac.com/bulgeconversion.html
# ;; Bulge to Arc  -  Lee Mac
# ;; p1 - start vertex
# ;; p2 - end vertex
# ;; b  - bulge
# ;; Returns: (<center> <start angle> <end angle> <radius>)

# (defun LM:Bulge->Arc ( p1 p2 b / a c r )
#     (setq a (* 2 (atan b))
#           r (/ (distance p1 p2) 2 (sin a))
#           c (polar p1 (+ (- (/ pi 2) a) (angle p1 p2)) r)
#     )
#     (if (minusp b)
#         (list c (angle c p2) (angle c p1) (abs r))
#         (list c (angle c p1) (angle c p2) (abs r))
#     )
# )
def bulge2arc(p1, p2, bulge):
    a = 2*np.arctan(bulge)
    r = math.hypot(p2[0]-p1[0], p2[1]-p1[1]) / 2.0 / np.sin(a)
    c = polar(p1, np.pi/2.0-a + angle(p1, p2), r)

    # in the code I stole above, the start and end angles are reversed
    # if bulge is negative. Even from reading the comments on that page,
    # I don't see why that is done.
    # later edit. The page also has this line:
    # "The returned bulge value may be positive or negative, depending
    # upon whether the arc passing through the three points traces a clockwise
    # or counter-clockwise path."
    # negative indicates clockwise.
    # so if going from point A->B at 90 degrees to -90 degress with bulge -1, we pass through 0
    # if going from -90 to 90 also with bulge -1, we don't pass through 0.
    #if (bulge<0):
    #    return (c, np.rad2deg(angle(c, p2)), np.rad2deg(angle(c, p1)), np.absolute(r))
    #else:
    a1 = np.rad2deg(angle(c, p1))
    a2 = np.rad2deg(angle(c, p2))
    # if clockwise (bulge<0) and the angles go from negative to positive, we
    # don't cross 0 degress.
    if (a1<0) and (a2>0) and (bulge<0):
        a1 = a1+360.0
    # if counterclockwise (bulge>0) and the angles go from positive to negative
    # we also don't cross 0 degrees
    if (a1>0) and (a2<0) and (bulge>0):
        a2 = a2+360.0
    return (c, a1, a2, np.absolute(r))

#print(bulge2arc((0,10), (10,0), .5))


'''
奇异值分解
Singular Value Decomposition
author:pgcai
20211201

输入：样本数据
输出：左奇异矩阵，奇异值矩阵，右奇异矩阵
计算特征值： 特征值分解AAT，其中A∈Rm×n为原始样本数据

AAT=UΣΣTUT
得到左奇异矩阵U∈Rm×m和奇异值矩阵Σ′∈Rm×m

间接求部分右奇异矩阵： 求V′∈Rm×n

利用A=UΣ′V′可得

V′=(UΣ′)−1A=(Σ′)−1UTA(1-4)
返回U, Σ′, V′，分别为左奇异矩阵，奇异值矩阵，右奇异矩阵。
'''
import numpy as np

def svd(data):
    '''
    Singular Value Decomposition
    '''
    # 数据必需先转为浮点型，否则在计算的过程中会溢出，导致结果不准确
    data2Float = np.array(data, dtype=float)
    # 计算特征值和特征向量
    eval_sigma1, evec_u = np.linalg.eigh(data2Float.dot(data2Float.T))

    # 降序排列后，逆序输出
    eval1_sort_idx = np.argsort(eval_sigma1)[::-1]
    # 将特征值对应的特征向量也对应排好序
    eval_sigma1 = np.sort(eval_sigma1)[::-1]
    evec_u = evec_u[:,eval1_sort_idx]
    # 计算奇异值矩阵的逆
    eval_sigma1 = np.sqrt(eval_sigma1)
    eval_sigma1_inv = np.linalg.inv(np.diag(eval_sigma1))
    # 计算右奇异矩阵
    evec_part_v = eval_sigma1_inv.dot((evec_u.T).dot(data2Float))

    return evec_u, eval_sigma1, evec_part_v

if __name__=='__main__':
    print("svd")
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    img_eg = mpimg.imread("./data/test2.jpg")
    print(img_eg.shape)
    img_temp = img_eg.reshape(img_eg.shape[0], img_eg.shape[1] * img_eg.shape[2])
    # U,Sigma,VT = np.linalg.svd(img_temp)
    U, Sigma, VT = svd(img_temp)

    # 取前60个奇异值
    sval_nums = 60
    img_restruct1 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
    img_restruct1 = img_restruct1.reshape(img_eg.shape[0], img_eg.shape[1], img_eg.shape[2])

    print(Sigma.shape)
    print('压缩前数据量 = ', img_eg.shape[0] * img_eg.shape[1] * img_eg.shape[2])
    print('压缩后数据量 = ', img_eg.shape[0]*sval_nums + sval_nums + sval_nums*img_eg.shape[1] * img_eg.shape[2])

    # 取前120个奇异值
    sval_nums = 120
    img_restruct2 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
    img_restruct2 = img_restruct2.reshape(img_eg.shape[0], img_eg.shape[1], img_eg.shape[2])

    print(Sigma.shape)
    print('压缩前数据量 = ', img_eg.shape[0] * img_eg.shape[1] * img_eg.shape[2])
    print('压缩后数据量 = ', img_eg.shape[0]*sval_nums + sval_nums + sval_nums*img_eg.shape[1] * img_eg.shape[2])

    fig, ax = plt.subplots(1, 3, figsize = (24,32))

    ax[0].imshow(img_eg)
    ax[0].set(title = "src")
    ax[1].imshow(img_restruct1.astype(np.uint8))
    ax[1].set(title = "nums of sigma = 60")
    ax[2].imshow(img_restruct2.astype(np.uint8))
    ax[2].set(title = "nums of sigma = 120")

    plt.show()


import os
import numpy as np
import pandas as pd
import statsmodels.api as sm

from datetime import datetime
from numpy.linalg import inv
from scipy.stats import t

def calc_residuals(df):
    x = df.iloc[:, 0]  # e.g. BTC/USD
    y = df.iloc[:, 1]  # e.g. ETH/USD
    X1 = sm.add_constant(x)
    # Y1 = sm.add_constant(y)

    ols1 = sm.OLS(y, X1).fit()
    # ols2 = sm.OLS(x, Y1).fit()
    # calculate residuals here
    residuals = ols1.resid
    # residuals2 = ols2.resid
    return residuals

def test_stationarity(residuals):
    adf_data = pd.DataFrame(residuals)
    adf_data.columns = ["y"]
    adf_data["drift_constant"] = 1
    # Lag residual
    adf_data["y-1"] = adf_data["y"].shift(1)
    adf_data.dropna(inplace=True)
    # Diff between residual and lag residual
    adf_data["deltay1"] = adf_data["y"] - adf_data["y-1"]
    # Lag difference
    adf_data["deltay-1"] = adf_data["deltay1"].shift(1)
    adf_data.dropna(inplace=True)
    target_y = pd.DataFrame(adf_data["deltay1"], columns=["deltay1"])
    adf_data.drop(["y", "deltay1"], axis=1, inplace=True)

    # Auto regressing the residuals with lag1, drift constant and lagged 1 delta (delta_et-1)
    adf_regressor_model = sm.OLS(target_y, adf_data)
    adf_regressor = adf_regressor_model.fit()

    # Returning the results
    print(adf_data)
    print(adf_regressor.summary())
    return adf_regressor

import numpy,from numpy,from scipy,import statsmodels


from scipy import stats
import numpy as np

# This method computes entropy for information gain
def entropy(class_y):
    # Input:
    #   class_y         : list of class labels (0's and 1's)

    # Example:
    #    entropy([0,0,0,1,1,1,1,1,1]) = 0.92

    entropy = 0

    if len(class_y) == 0:
        return 0

    class_y = list(class_y)

    # count zeroes and ones
    zeroes = class_y.count(0)
    ones = class_y.count(1)

    if zeroes == 0 or ones == 0:
        return 0

    # implement entropy formula
    total = len(class_y)
    p0 = float(zeroes) / total
    p1 = float(ones) / total
    entropy = -(p0 * np.log2(p0) + p1 * np.log2(p1))

    return entropy

def partition_classes(X, y, split_attribute, split_val):
    # Inputs:
    #   X               : data containing all attributes
    #   y               : labels
    #   split_attribute : column index of the attribute to split on
    #   split_val       : either a numerical or categorical value to divide the split_attribute
    X_left = []
    X_right = []

    y_left = []
    y_right = []

    # Check if numerical or categorical
    is_categorical = isinstance(split_val, str)

    if is_categorical:
        for index, row in enumerate(X):
            if row[split_attribute] == split_val:
                X_left.append(X[index])
                y_left.append(y[index])
            else:
                X_right.append(X[index])
                y_right.append(y[index])
    else:
        for index, row in enumerate(X):
            if row[split_attribute] <= split_val:
                X_left.append(X[index])
                y_left.append(y[index])
            else:
                X_right.append(X[index])
                y_right.append(y[index])

    return X_left, X_right, y_left, y_right

def information_gain(previous_y, current_y):
    # Inputs:
    #   previous_y: the distribution of original labels (0's and 1's)
    #   current_y:  the distribution of labels after splitting based on a particular
    #               split attribute and split value
    """
    Example:

    previous_y = [0,0,0,1,1,1]
    current_y = [[0,0], [1,1,1,0]]

    info_gain = 0.45915
    """
    num_labels = len(previous_y)

    prev_entropy = entropy(previous_y)
    average_entropy = 0

    for row in current_y:
        cond_entropy = entropy(row)
        prob = len(row) / num_labels
        average_entropy += cond_entropy * prob

    info_gain = prev_entropy - average_entropy

    return info_gain

if __name__=="__main__":

    print(entropy([0, 0, 0, 1, 1, 1, 1, 1, 1]))

    X = [[3, 'aa', 10],
         [2, 'cc', 28],
         [1, 'bb', 22],
         [5, 'bb', 32],
         [4, 'cc', 32]]

    y = [1, 1, 0, 0, 1]
    X_left, X_right, y_left, y_right = partition_classes(X, y, 0, 3)
    print(X_left, X_right)
    print(y_left, y_right)

    previous_y = [0,0,0,1,1,1]
    current_y = [[0,0], [1,1,1,0]]
    print(information_gain(previous_y, current_y))


import numpy as np
from scipy import stats
import scipy
import math

# if data is not a frequency distribution
x = np.array([1,2,3,4,5])
mean = np.mean(x)
n = x.size
x_minus_mean= x-mean
x_minus_mean_square = np.square(x_minus_mean)
x_minus_mean_square_sum = np.sum(x_minus_mean_square)

standard_deviation = math.sqrt(x_minus_mean_square_sum/n)
print("standard_deviation 1 : ",standard_deviation)

# if dataset is frequency distribution
x_square = np.square(x)
f = np.array([6,16,24,25,19])
cum_freq = np.array([6,22,46,71,90])
f_x_square = f*x_square

sum_f_x_square = np.sum(f_x_square)
sum_f = np.sum(f)
mean_square = math.pow(mean,2)
standard_deviation = math.sqrt((sum_f_x_square/sum_f) - mean_square)

print("standard_deviation 2 : ",standard_deviation)


# Program 03c: Finding critical points.
# See Example 9.
import sympy as sm

x, y = sm.symbols('x, y')
P = x * (1- x / 2 - y)
Q = y * (x - 1 - y / 2)

# Set P(x,y)=0 and Q(x,y)=0.
Peqn = sm.Eq(P, 0)
Qeqn = sm.Eq(Q, 0)

# Locate critical points
criticalpoints = sm.solve((Peqn, Qeqn), x, y)

print(criticalpoints)


# Refer: https://en.wikipedia.org/wiki/Test_functions_for_optimization

import numpy as np
import matplotlib.pyplot as plt
import pso_solver

pso_solver.setSeed(1)

lower = xlower = ylower = -5
upper = xupper = yupper = 5
particleList = pso_solver.createRandomParticleList(2, numParticles=10, lower=lower, upper=upper)

# Testing on Rastrigin function with n = 2
f = lambda x, y: 20 + (x**2 - 10*np.cos(2*np.pi*x)) + (y**2 - 10*np.cos(2*np.pi*y))

pso_solver.psoVisualizeBivariate(particleList, f, xlower, xupper, ylower, yupper, c1=1, c2=1, W=0.5, numIters=50, maxFlag=False, sleepTime=0.1, density=100, accuracy=2, verbose=False)


# mean = the average value
# median = the mid point value
# mode = the most common value
import numpy as np

speed = np.array( [99,86,87,88,111,86,103,87,94,78,77,85,86] )

mean_value = np.mean(speed)

print('Mean: ', mean_value)

# median value is the value in the middle, after you have sorted all the values

median_value = np.median(speed)

print('Median: ', median_value)

"""
Use the Scipy mode() method to find the number that appears that he most
"""
from scipy import stats

mode_value = stats.mode(speed)

print('Mode: ', mode_value)


import numpy as np
import data
import matplotlib.pyplot as plt

def re_lu(x):
    return np.maximum(0, x)

def softmax(x):
    exp_x_shifted = np.exp(x - np.max(x))
    exp_sums = np.sum(exp_x_shifted, axis=1).reshape((-1, 1))
    probs = exp_x_shifted / exp_sums
    return probs

def fcann2_train(X, Y_, shape=(-1, 3), max_iter=100_000, eta=0.05, lamda=0.001, print_frequency=100):
    N = len(X)
    n = len(X[0])
    C = np.max(Y_) + 1
    hidden = shape[1]

    W1 = np.random.randn(n, hidden)
    b1 = np.zeros((1, hidden))
    W2 = np.random.randn(hidden, C)
    b2 = np.zeros((1, C))

    Y_one_hot = data.class_to_onehot(Y_)

    for i in range(max_iter):
        # FORWARD
        # 1st layer
        s1 = X @ W1 + b1
        h1 = re_lu(s1)
        # second layer
        s2 = h1 @ W2 + b2
        h2 = re_lu(s2)
        # loss
        P = softmax(h2)

        if i % print_frequency == 0:
            loss = -1.0 / N * np.sum(np.log(P) * Y_one_hot)
            print(f"iteration {i} loss = {loss}")

        # BACKWARD
        dL_ds2 = P - Y_one_hot
        dL_dW2 = h1.T @ dL_ds2
        dL_db2 = np.sum(dL_ds2, axis=0)

        dL_ds1 = dL_ds2 @ W2.T
        dL_ds1[s1 <= 0] = 0
        dL_dW1 = dL_ds1.T @ X
        dL_db1 = np.sum(dL_ds1, axis=0)
        # ADJUSTING WEIGHTS AND BIASES
        W1 = W1 * (1 - eta * lamda) - 1 / N * eta * dL_dW1.T
        b1 -= 1 / N * eta * dL_db1
        W2 = W2 * (1 - eta * lamda) - 1 / N * eta * dL_dW2
        b2 -= 1 / N * eta * dL_db2

    return W1, b1, W2, b2

def fcann2_classify(X, W1, b1, W2, b2):
    s1 = X @ W1 + b1
    h1 = re_lu(s1)
    s2 = h1 @ W2 + b2
    return softmax(s2)

def decfun(W1, b1, W2, b2):
    return lambda X: fcann2_classify(X, W1, b1, W2, b2)[:, 1]

if __name__ == "__main__":
    np.random.seed(100)
    X, Y_ = data.sample_gmm_2d(6, 2, 10)
    W1, b1, W2, b2 = fcann2_train(X, Y_, (-1, 5), 10_000, 0.05, 0.001, 500)
    probs = fcann2_classify(X, W1, b1, W2, b2)
    Y = np.argmax(probs, axis=1)
    bounding_box = (np.min(X, axis=0), np.max(X, axis=0))
    data.graph_surface(decfun(W1, b1, W2, b2), bounding_box, offset=0.5)
    data.graph_data(X, Y_, Y)
    plt.show()


import numpy as np
from random import shuffle

def softmax_loss_naive(W, X, y, reg):
  """
  Softmax loss function, naive implementation (with loops)

  Inputs have dimension D, there are C classes, and we operate on minibatches
  of N examples.

  Inputs:
  - W: A numpy array of shape (D, C) containing weights.
  - X: A numpy array of shape (N, D) containing a minibatch of data.
  - y: A numpy array of shape (N,) containing training labels; y[i] = c means
    that X[i] has label c, where 0 <= c < C.
  - reg: (float) regularization strength

  Returns a tuple of:
  - loss as single float
  - gradient with respect to weights W; an array of same shape as W
  """
  # Initialize the loss and gradient to zero.
  loss = 0.0
  dW = np.zeros_like(W)

  #############################################################################
  # TODO: Compute the softmax loss and its gradient using explicit loops.     #
  # Store the loss in loss and the gradient in dW. If you are not careful     #
  # here, it is easy to run into numeric instability. Don't forget the        #
  # regularization!                                                           #
  #############################################################################
  num_train = X.shape[0]
  num_class = W.shape[1]

  for i in xrange(num_train):
    scores = X[i].dot(W)
    ei = 0
    for j in xrange(num_class):
        ei += np.exp(scores[j])

    for k in xrange(num_class):
        if k == y[i]:
            dW[:,k] += X[i]*(np.exp(scores[k])/ei - 1)
        else:
            dW[:,k] += X[i]*(np.exp(scores[k])/ei)

    loss -= np.log(np.exp(scores[y[i]])/ei)
  loss /= num_train
  loss += 0.5 * reg * np.sum(W**2)

  dW /= num_train
  dW += reg * W

  #############################################################################
  #                          END OF YOUR CODE                                 #
  #############################################################################

  return loss, dW

def softmax_loss_vectorized(W, X, y, reg):
  """
  Softmax loss function, vectorized version.

  Inputs and outputs are the same as softmax_loss_naive.
  """
  # Initialize the loss and gradient to zero.
  loss = 0.0
  dW = np.zeros_like(W)

  #############################################################################
  # TODO: Compute the softmax loss and its gradient using no explicit loops.  #
  # Store the loss in loss and the gradient in dW. If you are not careful     #
  # here, it is easy to run into numeric instability. Don't forget the        #
  # regularization!                                                           #
  #############################################################################
  num_train = X.shape[0]

  #for i in xrange(num_train):
  scores = X.dot(W)
  scores -= np.max(scores)
  ei = np.sum(np.exp(scores), axis=1)
  loss = np.sum(-np.log(np.exp(scores[range(num_train),y])/ei))

  loss /= num_train
  loss += 0.5 * reg * np.sum(W**2)

  e_mat = np.exp(scores)/ei.reshape(-1,1)
  #e_mat = np.exp(scores)/np.matrix(ei).T
  e_mat[range(num_train),y] -= 1
  dW += np.dot(X.T, e_mat)

  dW /= num_train
  dW += reg * W

  #############################################################################
  #                          END OF YOUR CODE                                 #
  #############################################################################

  return loss, dW


import numpy as np

def multinomial_estimation(data, alpha_prior=None):
    """
    Parameter estimation for a multinomial model using count data. Maximumum likelihood (ML) estimation is done if
    `alpha_prior` is not specified; else a maximum-a-posteriori (MAP) estimation is done using a Dirichlet prior
    with the hyper-parameters given by `alpha_prior`.

    Setting each value of `alpha_prior` to `0.5` corresponds to the non-informative Jeffrey's prior.
    Setting each value of `alpha_prior` to `1` corresponds to the uniform prior, which also leads to ML estimation.
    In general, values in `alpha_prior` function as a pseudo (prior) count for each category.

    :param data: numpy array with the count data. Shape `(n, m)`, where `n` is the number of samples and `m` is
                 the number of categories. Each value should be an integer and each row should sum to the same
                 value, the number of trials per sample.
    :param alpha_prior: None or a numpy array with the hyper-parameters of a Dirichlet prior distribution.
                        The array should have shape `(data.shape[1], )` with positive values. When `alpha` is None,
                        it is set to the default value of all ones, which leads to a uniform prior and maximum
                        likelihood estimation.
    :return:
        proba: numpy array with the multinomial probability estimates per category. Has shape `(m, )`, with
               values that sum to 1.
    """
    n_samp, n_cat = data.shape
    v = np.sum(data, axis=1)
    if np.any(np.abs(v - v[0]) > 0.):
        raise ValueError("All columns of the input `data` should sum to the same value, the number of trials "
                         "per sample.")

    n_trials = int(v[0])
    if alpha_prior is None:
        # Uniform prior which results in the maximum likelihood estimate
        alpha_prior = np.ones(n_cat)

    den = np.sum(alpha_prior) - n_cat + n_samp * n_trials
    proba = (alpha_prior - 1. + np.sum(data, axis=0)) / max(den, 1.0)

    return proba

def special_dirichlet_prior(n_cat, eps=0.1):
    """
    When all the alpha values are set to 1, the estimate coincides with the maximum likelihood estimate. In this
    case the alpha values sum to `m` (the number of categories).

    What if we knew that a particular category `i` is more likely (important) than the other categories? We can set
    `alpha_i` to a value close to but slightly smaller than 2, and the values of `alpha_j` (j != i) close to but
    slightly larger than 1 such that the sum of alpha values equals `m + 1`.
    One such choice that emphasizes the i-th category is given by:
    ```
    alpha_i = 1 + 1 - ((m - 1) / m) eps
    alpha_j = 1 + eps / m`, for all j != i
    ```
    With this choice, the sum of `alpha` values will be equal to `m + 1` and the i-th category takes a majority
    chunk of the additional 1 sample. This function returns an array of shape `(m, m)`, where the i-th row has the
    alpha values for the case when the i-th category is more likely than the rest.

    :param n_cat: number of categories. int value > 1.
    :param eps: a small value in (0, 1).

    :return: array where each row has the prior values as explained earlier. Has shape `(n_cat, n_cat)`.
    """
    alpha = (1 + eps / n_cat) * np.ones((n_cat, n_cat))
    v = 2. - ((n_cat - 1.) / n_cat) * eps
    np.fill_diagonal(alpha, v)

    return alpha


"""Tests with kernel density estimation."""
import typing as t

import numpy as np

def kernel_gaussian(inst: np.ndarray) -> np.ndarray:
    """Gaussian kernel."""
    if inst.ndim == 1:
        inst = inst.reshape(-1, 1)

    _, dimension = inst.shape

    aux = np.sum(np.square(inst), axis=1)
    return np.exp(-0.5 * aux) * np.power(2.0 * np.pi, -0.5 * dimension)

def infinity_norm(
        inst: t.Union[np.ndarray, float]) -> t.Union[np.ndarray, float]:
    """Calculates the infinity norm of ``inst``.

    The infinity norm is defined as norm_{inf}(inst) = max_{i}(|x_{i}|), i.e.,
    the maximum absolute value in the vector ``inst``.

    For instance, if inst = [0, 4, -7, 2, -1], then norm_{inf}(inst) = 7.
    """
    return np.max(np.abs(inst), axis=1)

def kernel_uniform(inst: np.ndarray) -> np.ndarray:
    """Uniform kernel."""
    if inst.ndim == 1:
        inst = inst.reshape(-1, 1)

    _, dimension = inst.shape

    return 0.5**dimension * (infinity_norm(inst) < 1.0)

def kernel_epanechnikov(inst: np.ndarray) -> np.ndarray:
    """Epanechnikov kernel."""
    if inst.ndim != 1:
        raise ValueError("'inst' vector must be one-dimensional!")

    return 0.75 * (1.0 - np.square(inst)) * (np.abs(inst) < 1.0)

def kernel_density_est(unknown_points: np.ndarray,
                       kernel: t.Callable[[np.ndarray], np.ndarray],
                       known_points: np.ndarray,
                       kernel_bandwidth: t.Union[int, float, np.number], *args,
                       **kwargs) -> np.ndarray:
    """Calculate the density estimation for ``unknown points`` using ``kernel``.

    Arguments
    ---------
    unknown_points : :obj:`np.ndarray`
        Numpy array with coordinates to evaluate the density function value.

    kernel : :obj:`Callable`
        Callable which implements the kernel function. Must receive a
        numpy array as the first argument, and outputs a another numpy
        array. Can receive additional arguments via *args and **kwargs.

    known_points : :obj:`np.ndarray`
        Set of points given, which partly represents the underlying unknown
        distribution. Used to estimate the density function.

    kernel_bandwidth: :obj:`np.ndarray`
        Length of the ``bumps`` of the kernel function around each
        known point. This parameter must be optimized in order to the
        output density function really fits the ``known_points``
        distribution.

    *args:
        Additional arguments to the ``kernel`` function.

    **kwargs:
        Additional arguments to the ``kernel`` function.

    Returns
    -------
    :obj:`np.ndarray`
        Array containing each ``unknown_points`` evaluated with the kernel
        density estimation technique.
    """
    if isinstance(unknown_points, (float, int, np.number)):
        unknown_points = np.array([unknown_points])

    if known_points.ndim == 1:
        num_inst, dimension = known_points.size, 1

    else:
        num_inst, dimension = known_points.shape

    return np.array([
        np.sum(
            kernel((inst - known_points) / kernel_bandwidth, *args, **kwargs))
        for inst in unknown_points
    ]) / (num_inst * kernel_bandwidth**dimension)

def _experiment_01() -> None:
    """Kernel Density estimation experiment 01."""
    import matplotlib.pyplot as plt

    linear_vals = np.linspace(-3, 3, 100)
    plt.plot(linear_vals, kernel_gaussian(linear_vals), label="Gaussian")
    plt.plot(linear_vals, kernel_uniform(linear_vals), label="Uniform")
    plt.plot(
        linear_vals, kernel_epanechnikov(linear_vals), label="Epanechnikov")
    plt.title("Kernels")
    plt.legend()
    plt.show()

def _experiment_02() -> None:
    """Kernel Density estimation experiment 02."""
    import matplotlib.pyplot as plt

    linear_vals = np.linspace(-3, 3, 100)
    dim_1, dim_2 = np.meshgrid(linear_vals, linear_vals)

    z_gauss = np.zeros((linear_vals.size, linear_vals.size))
    z_uniform = np.zeros((linear_vals.size, linear_vals.size))

    for ind in np.arange(linear_vals.size):
        aux_1 = dim_1[:, ind].reshape(-1, 1)
        aux_2 = dim_2[:, ind].reshape(-1, 1)
        vals = np.hstack((aux_1, aux_2))
        z_gauss[:, ind] = kernel_gaussian(vals)
        z_uniform[:, ind] = kernel_uniform(vals)

    plt.title("Kernels")
    plt.subplot(121)
    plt.contour(dim_1, dim_2, z_gauss)
    plt.subplot(122)
    plt.contour(dim_1, dim_2, z_uniform)
    plt.show()

def _experiment_03() -> None:
    """Estimate Kernel bandwidth."""
    import matplotlib.pyplot as plt
    from cross_validation import loo_cv

    def loss_function(inst):
        """Mean of log-probabilities (0 <= inst <= 1)."""
        return -np.mean(np.log(inst))

    random_state = 16
    chosen_kernel = kernel_gaussian

    np.random.seed(random_state)

    candidate_bandwidths = np.linspace(0.01, 1.0, 25)
    known_points = np.random.normal(size=512)

    logls = np.zeros(candidate_bandwidths.size)

    for subset_test, subset_train in loo_cv(known_points):
        for ind_bandwidth in np.arange(candidate_bandwidths.size):
            kernel_est = kernel_density_est(
                unknown_points=subset_test,
                known_points=subset_train,
                kernel=chosen_kernel,
                kernel_bandwidth=candidate_bandwidths[ind_bandwidth])

            logls[ind_bandwidth] += loss_function(kernel_est)

    bandwidth_opt = candidate_bandwidths[logls.argmin()]

    random_ind = np.random.randint(candidate_bandwidths.size)
    bandwidth_random = candidate_bandwidths[random_ind]

    print("Optimal bandwidth: {} (loss: {})".format(bandwidth_opt,
                                                    logls.min()))
    print("Random bandwidth: {} (loss: {})".format(bandwidth_random,
                                                   logls[random_ind]))

    linear_vals = np.linspace(-3, 3, 100)

    plt.hist(known_points, 32, density=True)
    plt.plot(
        linear_vals,
        kernel_density_est(
            unknown_points=linear_vals,
            known_points=known_points,
            kernel=chosen_kernel,
            kernel_bandwidth=bandwidth_opt))
    plt.plot(
        linear_vals,
        kernel_density_est(
            unknown_points=linear_vals,
            known_points=known_points,
            kernel=chosen_kernel,
            kernel_bandwidth=bandwidth_random))
    plt.show()

if __name__ == "__main__":
    _experiment_01()
    _experiment_02()
    _experiment_03()


"""
Created on Wed Aug 28 12:13:14 2019
@author: Emerson Boeira
"""
#%% Header: importing python packages and libraries

import numpy as np  # important package for scientific computing

#%% Functions that calculate the sample-based and the theoretical autocorrelation of ARMA processes

def smpl_acorr(y, maxlag):
    # Description to help the user
    """Function that calculates the sample-based autocorrelation of the signal y(t), using the numpy.cov() function.
    The advantage os this function is that it's faster and more efficient that numpy.correlate().

    Parameters
    ----------
    y : numpy.ndarray
        Observed signal.
    maxlag: int
        Maximum value of lag that will be considered on the autocorrelation function.

    Returns
    -------
    ryy: numpy.ndarray
        The autocorrelation function, calculated based on the observation of y(t).
    tau: numpy.ndarray
        The lag interval considered. It has the same size as ryy."""

    # calculating the size of tau
    N = 2 * maxlag + 1
    # assembling tau with linspace
    tau = np.linspace(- maxlag, maxlag, N)  # linspace(start, stop, numberofpoints)

    # preallocating the autocorrelation function vector
    ryy = np.zeros((maxlag + 1))

    # calculating the autocorrelation for tau=0 using the cov function
    ryy[0] = np.cov(y[1:], y[:-1])[0][0]

    # calculating the correlation function
    for l in range(1, maxlag + 1):
        ryy[l] = np.cov(y[l:], y[:-l])[0][1]

    # using the flip operation to return a vector that represents the autocorrelation from -maxlag to +maxlag
    ryyf = np.flip(ryy[1:])
    ryyc = np.concatenate((ryyf, ryy))

    # returns the sample-based autocorrelation and the lag vector
    return ryyc, tau

def arma_acorr(C, A, var, maxlag):
    # Description to help the user
    """Function that calculates the theoretical autocorrelation function of an ARMA process:
        A(q)y(t)=C(q)e(t), where
        A(q) and C(q) are defined as polinomials on q (instead of q^{-1})
        e(t) is a white noise sequence with variance: E[e(t)e(t)] = var.

    Parameters
    ----------
    A: numpy.ndarray
        Vector that contains the coefficients of A(q).
    C: numpy.ndarray
        Vector that contains the coefficients of C(q).
    var: float
        Variance of e(t).
    maxlag: int
        Maximum lag that will be considered on the computation of the autocorrelation (from -maxlag to +maxlag).

    Returns
    -------
    ryy: numpy.ndarray
        The autocorrelation function, calculated based on Soderstrom's algorithm.
    tau: numpy.ndarray
        The lag interval considered. It has the same size as ryy."""

    # order of A(q)
    n = A.shape[0] - 1
    # order of C(q)
    m = C.shape[0] - 1

    # calculating C(q^-1)
    cm = np.flip(C)

    # making C(q) and C(q^-1) with the same base
    zc = np.zeros((m))
    C = np.concatenate((C, zc))
    cm = np.concatenate((zc, cm))

    # calculating B(q)
    B = np.convolve(C, cm)
    # fixing the dimensions after the convolve
    B = B[m : 3 * m + 1]
    # making B(q) with the same shape as A(q)
    zb = np.zeros((n - m))
    B = np.concatenate((zb, B))
    B = np.concatenate((B, zb))
    # taking only the redundant part of B(q)
    Bn = B[0 : n + 1]
    # fliping the bn vector to find D(q)
    Bn = np.flip(Bn)

    # preallocating the A1 and A2 matrices
    A1 = np.zeros((n + 1, n + 1))
    A2 = np.zeros((n + 1, n + 1))

    # assembling A1 and A2
    for k in range(0, n + 1):
        A1[k][0 : n + 1 - k] = A[k : n + 1]
        A2[k][k : n + 1] = A[0 : n + 1 - k]

    # assembling the matrix "calligraphic A" - to avoid redundance we'll call it Acal
    Acal = A1 + A2

    # finding the polynomial D(q)
    D = np.linalg.solve(Acal, Bn)

    # using the function coeff to calculate the coefficients of the correlation based on A(q) and D(q)
    ryy, tau = coeff(A, D, maxlag)

    # scaling the correlation function with the variance of e(t)
    ryy = var * ryy

    # returning the theoretical correlation and the lag vector
    return ryy, tau

def coeff(A, D, maxlag):
     # Description to help the user
    """Function that calculates the coefficients of the theoretical correlation, based on the A(q) and D(q) polynomials,
    from -maxlag to +maxlag.

    Parameters
    ----------
    A: numpy.ndarray
        Vector that contains the coefficients of A(q).
    D: numpy.ndarray
        Vector that contains the coefficients of D(q).
    maxlag: int
        Maximum lag that will be considered on the computation of the autocorrelation (from -maxlag to +maxlag).

    Returns
    -------
    ryy: numpy.ndarray
        The autocorrelation function, calculated based on Soderstrom's algorithm.
    tau: numpy.ndarray
        The lag interval considered. It has the same size as ryy."""

    # preallocating the correlation function vector
    ryy = np.zeros((maxlag + 1))

    # computing the order of A(q)
    n = A.shape[0] - 1

    # calculating the first coefficient of the correlation function
    ryy[0] = 2 * D[0]
    # calculating the second coefficient of the correlation function
    ryy[1] = D[1] - A[1]*D[0]

    # loop that calculates the other coefficients
    for k in range(2, maxlag + 1):
        Sum = 0
        if k <= n:
            for j in range(1, k):
                Sum = Sum + A[j]*ryy[k - j]
            ryy[k] = D[k]-A[k]*D[0]-Sum
        else:
            for j in range(1, n + 1):
                Sum = Sum + A[j]*ryy[k - j]
            ryy[k] = -Sum

    # using the flip operation to return a vector that represents the autocorrelation from -maxlag to +maxlag
    ryyf=np.flip(ryy[1:])
    ryyc = np.concatenate((ryyf, ryy))

    # calculating the size of tau
    N = 2 * maxlag + 1
    # assembling tau with linspace
    tau = np.linspace(- maxlag, maxlag, N)  # linspace(start, stop, numberofpoints)

    # returning
    return ryyc, tau


#https://youtu.be/tnaq2Ao4KBE#Ref: Sreenivas Sarwar Anik
"""
A quick overview of timeseries.

Dataset from: https://www.kaggle.com/rakannimer/air-passengers
International Airline Passengers prediction problem.
This is a problem where, given a year and a month, the task is to predict
the number of international airline passengers in units of 1,000.
The data ranges from January 1949 to December 1960, or 12 years, with 144 observations.
"""

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
plt.style.use('dark_background')

# load the dataset
df = pd.read_csv('data/AirPassengers.csv')
print(df.dtypes)

df['Month'] = pd.to_datetime(df['Month'])
print(df.dtypes)

df.set_index('Month', inplace=True)

plt.plot(df['Passengers'])

#Is the data stationary?
#Dickey-Fuller test
from statsmodels.tsa.stattools import adfuller
adf, pvalue, usedlag_, nobs_, critical_values_, icbest_ = adfuller(df)
print("pvalue = ", pvalue, " if above 0.05, data is not stationary")
#Since data is not stationary, we may need SARIMA and not just ARIMA

#
df['year'] = [d.year for d in df.index]
df['month'] = [d.strftime('%b') for d in df.index]
years = df['year'].unique()

#Plot yearly and monthly values as boxplot
sns.boxplot(x='year', y='Passengers', data=df)
sns.boxplot(x='month', y='Passengers', data=df)

#Extract and plot trend, seasonal and residuals.
from statsmodels.tsa.seasonal import seasonal_decompose
decomposed = seasonal_decompose(df['Passengers'],
                            model ='additive')

#Additive time series:
#Value = Base Level + Trend + Seasonality + Error
#Multiplicative Time Series:
#Value = Base Level x Trend x Seasonality x Error

trend = decomposed.trend
seasonal = decomposed.seasonal #Cyclic behavior may not be seasonal!
residual = decomposed.resid

plt.figure(figsize=(12,8))
plt.subplot(411)
plt.plot(df['Passengers'], label='Original', color='yellow')
plt.legend(loc='upper left')
plt.subplot(412)
plt.plot(trend, label='Trend', color='yellow')
plt.legend(loc='upper left')
plt.subplot(413)
plt.plot(seasonal, label='Seasonal', color='yellow')
plt.legend(loc='upper left')
plt.subplot(414)
plt.plot(residual, label='Residual', color='yellow')
plt.legend(loc='upper left')
plt.show()

#AUTOCORRELATION
#Autocorrelation is simply the correlation of a series with its own lags.
# Plot lag on x axis and correlation on y axis
#Any correlation above confidence lnes are statistically significant.

from statsmodels.tsa.stattools import acf

acf_144 = acf(df.Passengers, nlags=144)
plt.plot(acf_144)

#Obtain the same but with single line and more info...
from pandas.plotting import autocorrelation_plot
autocorrelation_plot(df.Passengers)
#Horizontal bands indicate 95% and 99% (dashed) confidence bands

#A strong positive correlation for lags below 40 (months)


#! /usr/bin/env python

"""
File: interpolate_exp_cos.py

Copyright (c) 2016 Taylor Patti

License: MIT

This module calculates an interpolant approximation to the given function at the given point.

"""

import numpy as np

def exp_cos_func(q):
    """Approximates interpolant approximation to the function."""
    mesh = np.linspace(-1, 1, q+1)
    f = np.exp(- mesh**2)*np.cos(2 * np.pi * mesh)
    x_point = -0.45
    step = 2 / float(q+1)
    k_val = int(1-x_point / step)
    approximation = f[k_val] + ((f[k_val+1] - f[k_val])/(mesh[k_val+1] - mesh[k_val])) * (x_point - mesh[k_val])
    exact = f = np.exp(- x_point**2)*np.cos(2 * np.pi * x_point)
    return approximation, exact - approximation

def test_approx():
    """Ensures that the approximation is accurate at q = 8"""
    apt = np.fabs(exp_cos_func(8)[1]) < 0.1
    msg = 'Approximation not accurate.'
    assert apt, msg


# coding=utf-8
"""
Daniel Calderon, CC3501, 2019-1
Transformation matrices for computer graphics
v1.0
"""

import numpy as np

def identity():
    return np.identity(4, dtype=np.float32)

def uniformScale(s):
    return np.array([
        [s,0,0,0],
        [0,s,0,0],
        [0,0,s,0],
        [0,0,0,1]], dtype = np.float32).T

def scale(sx, sy, sz):
    return np.array([
        [sx,0,0,0],
        [0,sy,0,0],
        [0,0,sz,0],
        [0,0,0,1]], dtype = np.float32).T

def rotationX(theta):
    sin_theta = np.sin(theta)
    cos_theta = np.cos(theta)

    return np.array([
        [1,0,0,0],
        [0,cos_theta,-sin_theta,0],
        [0,sin_theta,cos_theta,0],
        [0,0,0,1]], dtype = np.float32).T

def rotationY(theta):
    sin_theta = np.sin(theta)
    cos_theta = np.cos(theta)

    return np.array([
        [cos_theta,0,sin_theta,0],
        [0,1,0,0],
        [-sin_theta,0,cos_theta,0],
        [0,0,0,1]], dtype = np.float32).T

def rotationZ(theta):
    sin_theta = np.sin(theta)
    cos_theta = np.cos(theta)

    return np.array([
        [cos_theta,-sin_theta,0,0],
        [sin_theta,cos_theta,0,0],
        [0,0,1,0],
        [0,0,0,1]], dtype = np.float32).T

def rotationA(theta, axis):
    s = np.sin(theta)
    c = np.cos(theta)

    assert axis.shape == (3,)

    x = axis[0]
    y = axis[1]
    z = axis[2]

    return np.array([
        # First row
        [c + (1 - c) * x * x,
        (1 - c) * x * y - s * z,
        (1 - c) * x * z + s * y,
        0],
        # Second row
        [(1 - c) * x * y + s * z,
        c + (1 - c) * y * y,
        (1 - c) * y * z - s * x,
        0],
        # Third row
        [(1 - c) * x * z - s * y,
        (1 - c) * y * z + s * x,
        c + (1 - c) * z * z,
        0],
        # Fourth row
        [0,0,0,1]], dtype = np.float32).T

def translate(tx, ty, tz):
    return np.array([
        [1,0,0,tx],
        [0,1,0,ty],
        [0,0,1,tz],
        [0,0,0,1]], dtype = np.float32).T

def shearing(xy, yx, xz, zx, yz, zy):
    return np.array([
        [ 1, xy, xz, 0],
        [yx,  1, yz, 0],
        [zx, zy,  1, 0],
        [ 0,  0,  0, 1]], dtype = np.float32).T

def matmul(mats):
    out = mats[-1]
    for i in range(len(mats) - 2, -1, -1):
        out = np.matmul(mats[i], out)

    return out


from sage.all import ZZ

def attack(N, e, c, oracle):
    """
    Recovers the plaintext from the ciphertext using the LSB oracle attack.
    :param N: the modulus
    :param e: the public exponent
    :param c: the encrypted message
    :param oracle: a function which returns the last bit of a plaintext for a given ciphertext
    :return: the plaintext
    """
    left = ZZ(0)
    right = ZZ(N)
    while right - left > 1:
        c = (c * pow(2, e, N)) % N
        if oracle(c) == 0:
            right = (right + left) / 2
        else:
            left = (right + left) / 2

    return int(right)


import math
import numpy as np

def allPossibilities(N):
    if N == 1: return ["H","T"]
    List1 = ["H","T"]
    for x in range(N-1):
        List2 = []
        for x in List1:
                   List2.append(x+"H")
                   List2.append(x+"T")
        List1 = List2.copy()
    return List2

def probabilityXcoinsYheads(x,y,headChance=0.5):
    a = int(math.factorial(x)/math.factorial(y)/math.factorial(x-y))
    b = 2**x
    c = a / b
    d = a*headChance**(y)*(1-headChance)**(x-y)
    return a,b,c,d

# sequence type should be str
def probability(sequence,coinPickChance,headChance):
    p = []
    for x in range(len(coinPickChance)):
        p.append(coinPickChance[x])
        for y in sequence:
            if y == "H": p[x]*=headChance[x]
            else: p[x]*=(1-headChance[x])
    return sum(p)

def simulatingFlippingCoins(success=[1], size=1, coins=[1,0], probability=[0.5,0.5], tests=1000000):
    return sum([((np.random.choice(coins,size=(tests,size),p=probability)).sum(axis=1)==i).mean() for i in success])


import numpy as np
import matplotlib.pyplot as plt

def mandelbrot(height, width, x=-0.5, y=0, zoom=1, max_iterations=100):
    # To make navigation easier we calculate these values
    x_width = 1.5
    y_height = 1.5*height/width
    x_from = x - x_width/zoom
    x_to = x + x_width/zoom
    y_from = y - y_height/zoom
    y_to = y + y_height/zoom

    # Here the actual algorithm starts
    x = np.linspace(x_from, x_to, width).reshape((1, width))
    y = np.linspace(y_from, y_to, height).reshape((height, 1))
    c = x + 1j * y

    # Initialize z to all zero
    z = np.zeros(c.shape, dtype=np.complex128)
    # To keep track in which iteration the point diverged
    div_time = np.zeros(z.shape, dtype=int)
    # To keep track on which points did not converge so far
    m = np.full(c.shape, True, dtype=bool)

    for i in range(max_iterations):
        z[m] = z[m]**2 + c[m]

        diverged = np.greater(np.abs(z), 2, out=np.full(c.shape, False), where=m) # Find diverging

        div_time[diverged] = i      # set the value of the diverged iteration number
        m[np.abs(z) > 2] = False    # to remember which have diverged
    return div_time

# Default image of Mandelbrot set
plt.imshow(mandelbrot(800, 1000), cmap='magma')
# The image below of Mandelbrot set
# plt.imshow(mandelbrot(800, 1000, -0.75, 0.0, 2, 200), cmap='magma')
# The image below of below of Mandelbrot set
# plt.imshow(mandelbrot(800, 1000, -1, 0.3, 20, 500), cmap='magma')
plt.show()


from numpy import cross, array , vdot
from numpy.linalg import norm
import matplotlib.pyplot as plt
from roblib import *
def vct_nrm(a,b,c):
	"""Soit a,b,c trois coin de la plateforme supossée carrée, n est un vecteur normal de cette platforme"""
	V1 = a-b
	V2 = a-c
	n = cross(V1,V2).T
	return n/norm(n)

def champ(p,n,phat,v_d):
	"""p position du drone, n vecteur normal à la plateforme, phat point cible où attérir, v_d vecteur vitesse de la plateforme"""
	calc1 = cross(n.T,(p-phat).T)
	pt_attract = 1*(phat-p)
	vitesse_cible = 0.5*v_d
	Q = 0.4*cross(n.T,calc1)+pt_attract.T + vitesse_cible

	return Q

def draw_shampoing(p):
	#ax.scatter(p[0],p[1],p[2]) #p
	Q = champ(p,n,phat)
	Q = Q.flatten()
	p = p.flatten()
	ax.plot([p[0],p[0]+Q[0]],[p[1],p[1]+Q[1]],[p[2],p[2]+Q[2]],'g-') #champ au point p

a = array([[0,5,0]])
b = array([[1,0,0]])
c = array([[0,1,0]])

n = vct_nrm(a,b,c)
print("vecteur normal = ",n)
phat = array([[100],[0],[0]]) #position point d'attérissage
p = array([[0],[0],[100]]) #position drone
Q = champ(p,n,phat)
print("n.Q",vdot(n, Q))
print("valeur du champ au point",Q)

a = a.flatten()
b = b.flatten()
c = c.flatten()

fig   = figure()
ax    = Axes3D(fig)
# for x in arange(0,1,0.1):
# 	for y in arange(0,1,0.1):
# 		for z in arange(0,3,0.25):
# 			draw_shampoing(array([[x,y,z]]).T)

# phat = phat.flatten()
# ax.scatter(phat[0],phat[1],phat[2]) #phat
# n = n.flatten()
# ax.plot([phat[0],phat[0]+3*n[0]],[phat[1],phat[1]+3*n[1]],[phat[2],phat[2]+3*n[2]]) #vecteur normal à partir de phat
# ax.plot([a[0],b[0],c[0],a[0]],[a[1],b[1],c[1],a[1]],[a[2],b[2],c[2],a[2]]) #platforme
# pause(10)
"""
plt.figure()
plt.xlim((-3,3))
plt.ylim((-3,3))
plt.plot(phat[0,0],phat[1,0],'ob')
plt.plot(p[0,0],p[1,0],'or')
plt.plot([p.flatten()[0],p.flatten()[0]+Q.flatten()[0]],[p.flatten()[1],p.flatten()[1]+Q.flatten()[1]])
plt.show()"""


import numpy as np

# ============================================================
# principal rotations

# rotation of phi is about the 1st axis (=X-axis) of the inertial frame
def r1(phi):
    return np.array([[1, 0, 0],
                     [0, np.cos(phi), np.sin(phi)],
                     [0, -np.sin(phi), np.cos(phi)]])

# second rotation of theta is about the 2nd axis (=Y-axis) of the first intermediate frame
def r2(theta):
    return np.array([[np.cos(theta), 0, -np.sin(theta)],
                     [0, 1, 0],
                     [np.sin(theta), 0, np.cos(theta)]])

# third rotation of psi is about the 3rd axis (=Z-axis) of the second intermediate frame
def r3(psi):
    return np.array([[np.cos(psi), np.sin(psi), 0],
                     [-np.sin(psi), np.cos(psi), 0],
                     [0, 0, 1]])

# ====================================================
# e123 rotation sequence

def q11(psi, theta):
    return np.cos(psi) * np.cos(theta)

def q12(psi, theta, phi):
    return np.cos(psi) * np.sin(theta) * np.sin(phi) + np.sin(psi) * np.cos(phi)

def q13(psi, theta, phi):
    return -np.cos(psi) * np.sin(theta) * np.cos(phi) + np.sin(psi) * np.sin(phi)

def q21(psi, theta):
    return - np.sin(psi) * np.cos(theta)

def q22(psi, theta, phi):
    return -np.sin(psi) * np.sin(theta) * np.sin(phi) + np.cos(psi) * np.cos(phi)

def q23(psi, theta, phi):
    return np.sin(psi) * np.sin(theta) * np.cos(phi) + np.cos(psi) * np.sin(phi)

def q31(theta):
    return np.sin(theta)

def q32(theta, phi):
    return - np.cos(theta) * np.sin(phi)

def q33(theta, phi):
    return np.cos(theta) * np.cos(phi)

def e123_dcm(psi, theta, phi):
    return np.array([[q11(psi, theta), q12(psi, theta, phi), q13(psi, theta, phi)],
                     [q21(psi, theta), q22(psi, theta, phi), q23(psi, theta, phi)],
                     [q31(theta), q32(theta, phi), q33(theta, phi)]])

def getRotationMatrix(vec1, vec2):
    """ Find the rotation matrix that aligns vec1 to vec2
    :param vec1: A 3d "source" vector
    :param vec2: A 3d "destination" vector
    :return mat: A transform matrix (3x3) which when applied to vec1, aligns it with vec2.
    """
    a, b = (vec1 / np.linalg.norm(vec1)).reshape(3), (vec2 / np.linalg.norm(vec2)).reshape(3)
    v = np.cross(a, b)
    c = np.dot(a, b)
    s = np.linalg.norm(v)
    kmat = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
    rotation_matrix = np.eye(3) + kmat + kmat.dot(kmat) * ((1 - c) / (s ** 2))
    return rotation_matrix


import numpy as np
import datetime
import math
from scipy import optimize
# (perihelion, period)
orbital_data = {'earth':({2018:(1,3), 2019:(1,3),2020:(1,5)},
                365.25635, 0.016710219,1.496e8)}

# (Axial tilt, rotation (rad/day) per day)
rotation_data = {'earth':(23.44, 6.30046407)}

'''Orbital up vector (orthogonal to earths orbit plane)
Note I am using plane span({(1,0,0), (0,0,1)})
as the plane of reference for all computations.
'''
orbital_up = np.array([0,1,0])

def mean_anomaly(date:"(Year, Month, Day)", body = 'earth'):
    iyear, imonth, iday = date
    perihelion_data, period, eccentricity, semi_major_axis = orbital_data[body]
    perihelion = perihelion_data[iyear]

    day = datetime.date(iyear, imonth, iday)
    perihelion_day = datetime.date(iyear, perihelion[0], perihelion[1])

    #If the date is before the this years perihelion date,
    #use last years perihelion
    if(day < perihelion_day):
        perihelion = perihelion_data[iyear - 1]
        perihelion_day = datetime.date(iyear - 1, perihelion[0], perihelion[1])

    t = (day - perihelion_day).days
    n = 2*(math.pi) / period
    return n * t

def eccentric_anomaly(date:"(Year, Month, Day)", body = 'earth'):
    perihelion_data, period, eccentricity, semi_major_axis = orbital_data[body]
    M = mean_anomaly(date, body)

    keplerf = lambda E: E - eccentricity*math.sin(E) - M
    keplerf_prime = lambda E: 1 -eccentricity*math.cos(E)
    keplerf_prime2 = lambda E: eccentricity*math.sin(E)

    E = optimize.newton(keplerf, 0,
                        fprime = keplerf_prime,
                        fprime2 = keplerf_prime2)
    return E

def true_anomaly(date:"(Year, Month, Day)", body = 'earth'):
    perihelion_data, period, eccentricity, semi_major_axis = orbital_data[body]
    E = eccentric_anomaly(date, body)

    Theta = 2 * math.atan(math.sqrt((1+eccentricity)/(1-eccentricity)) *
            math.tan(E/2))
    return Theta

def heliocentric_distance(date:"(Year, Month, Day)", body = 'earth'):
    perihelion_data, period, eccentricity, semi_major_axis = orbital_data[body]

    E = eccentric_anomaly(date, body)
    Theta = true_anomaly(date,body)
    r = semi_major_axis * (1 - eccentricity*math.cos(E))
    return r

def cartesian_coordinates(date:"(Year, Month, Day)", body = 'earth'):
    Theta = true_anomaly(date,body)
    r = heliocentric_distance(date,body)
    return np.array([r * math.cos(Theta),0,r * math.sin(Theta)])