import numpy as np
import matplotlib.pyplot as plt

def load(filename):
    f = open(filename, 'rb')
    return np.loadtxt(f, delimiter=',')

data = load('ex1data2.txt')
X = data[:,0:2]
y = data[:,2:3]
m = len(y)

for i in range(10):
    print('x = [%.0f %.0f], y = %.0f \n' % (X[i,0], X[i,1], y[i, :]))

def featureNormalize(X):
    X_norm = X
    if (len(X) <= 1):
        return np.zeros(X.shape), np.zeros((1, X.shape[1])), np.zeros((1, X.shape[1]))

    mu = np.mean(X, axis=0, keepdims=True)
    # https://stackoverflow.com/questions/27600207/why-does-numpy-std-give-a-different-result-to-matlab-std
    sigma = np.std(X, axis=0, keepdims=True, ddof=1)
    X_norm = (X - mu) / sigma
    return X_norm, mu, sigma

# print('featureNormalize() test')
# def magic(n):
#   n = int(n)
#   if n < 3:
#     raise ValueError("Size must be at least 3")
#   if n % 2 == 1:
#     p = np.arange(1, n+1)
#     return n*np.mod(p[:, None] + p - (n+3)//2, n) + np.mod(p[:, None] + 2*p-2, n) + 1
#   elif n % 4 == 0:
#     J = np.mod(np.arange(1, n+1), 4) // 2
#     K = J[:, None] == J
#     M = np.arange(1, n*n+1, n)[:, None] + np.arange(n)
#     M[K] = n*n + 1 - M[K]
#   else:
#     p = n//2
#     M = magic(p)
#     M = np.block([[M, M+2*p*p], [M+3*p*p, M+p*p]])
#     i = np.arange(p)
#     k = (n-2)//4
#     j = np.concatenate((np.arange(k), np.arange(n-k+1, n)))
#     M[np.ix_(np.concatenate((i, i+p)), j)] = M[np.ix_(np.concatenate((i+p, i)), j)]
#     M[np.ix_([k, k+p], [0, k])] = M[np.ix_([k+p, k], [0, k])]
#   return M

# X_test, mu_test, sigma_test = featureNormalize(np.array([[1], [2], [3]]))
# print(X_test, mu_test, sigma_test)

# X_test, mu_test, sigma_test = featureNormalize(magic(3))
# print(X_test, mu_test, sigma_test)

# X_test, mu_test, sigma_test = featureNormalize(np.concatenate((-np.ones((1, 3)), magic(3))))
# print(X_test, mu_test, sigma_test)
# print('test over')

X, mu, sigma = featureNormalize(X)

print(X)
print(mu)
print(sigma)

X = np.concatenate((np.ones((m, 1)), X), 1)
alpha = 0.1
num_iters = 400

def computeCostMulti(X, y, theta):
    m = len(y)
    error = X @ theta - y;
    return error.T @ error / (2 * m)

# print('computeCostMulti() test')
# X_test = np.array([[2, 1, 3], [7, 1, 9], [1, 8, 1], [3, 7, 4]])
# y_test = np.array([[2], [5], [5], [6]])
# theta_test = np.array([[0.4], [0.6], [0.8]])
# print(computeCostMulti(X_test, y_test, theta_test))
# print('test over')

def gradientDescentMulti(X, y, theta, alpha, num_iters):
    m = len(y)
    J_history = np.zeros((num_iters, 1))
    for iters in range(num_iters):
        theta = theta - alpha * (X.T @ (X @ theta - y)) / m
        J_history[iters] = computeCostMulti(X, y, theta)
    return theta, J_history

# print('gradientDescentMulti() test')
# X_test = np.array([[2, 1, 3], [7, 1, 9], [1, 8, 1], [3, 7, 4]])
# y_test = np.array([[2], [5], [5], [6]])
# print(gradientDescentMulti(X_test, y_test, np.array([[0.1], [-0.2], [0.3]]), 0.01, 10))
# print('test over')

theta = np.zeros((3, 1))
theta, _ =  gradientDescentMulti(X, y, theta, alpha, num_iters)

print('Theta computed from gradient descent: [%f, %f %f]' % (theta[0], theta[1], theta[2]))

x = (np.array([1650, 3]) - mu) / sigma
price = np.concatenate(([[1]], x), 1) @ theta
print('Predicted price of a 1650 sq-ft, 3 br house (using gradient descent): $%f' % price)

alpha = [1, 0.3, 0.1, 0.03, 0.01]
num_iters = range(50, 201)
theta = np.zeros((3, 1))
_, J_history = gradientDescentMulti(X, y, theta, alpha[2], num_iters[0])
plt.plot(range(1, num_iters[0]+1), J_history, '-b', linewidth = 2)
plt.xlabel('Number of iterations')
plt.ylabel('Cost J')
plt.show()

# replace the value of alhpa below best alhpa value you found above
alpha = 0.1
num_iters = 50

theta = np.zeros((3, 1))
theta, _ = gradientDescentMulti(X, y, theta, alpha, num_iters)

print('Theta computed from gradent descent: [%f, %f, %f]' % (theta[0], theta[1], theta[2]))
x = (np.array([1650, 3]) - mu) / sigma
price = np.concatenate(([[1]], x), 1) @ theta
print('Predicted price of a 1650 sq-ft, 3 br house (using gradient descent): %f\n' % price)

data = load('ex1data2.txt')
X = data[:, 0:2]
y = data[:, 2:3]
m = len(y)

ax = plt.axes(projection = '3d')
x0 = X[:, 0:1]
x1 = X[:, 1:2]
x0 = np.linspace(np.min(x0), np.max(x0), 10)
x1 = np.linspace(np.min(x1), np.max(x1), 10)
x0, x1 = np.meshgrid(x0, x1)
X_norm = (np.array([x0,x1]).T - mu) / sigma
X_norm = np.concatenate((np.ones((X_norm.shape[0], X_norm.shape[1], 1)), X_norm), 2)
# z = x0 * theta[1] + x1 * theta[2] + theta[0]
z = (X_norm @ theta).T
ax.plot_surface(x0, x1, z.reshape(x0.shape), color='w', alpha=0.5)
ax.scatter3D(X[:,0:1], X[:,1:2], y, c='b', marker='^')
ax.scatter3D(1650, 3, price, c='r', marker='o')
ax.invert_xaxis()

plt.xlabel('sq-ft')
plt.ylabel('br')
plt.show()

data = load('ex1data2.txt')
X = data[:, 0:2]
y = data[:, 2:3]
m = len(y)

X = np.concatenate((np.ones((m, 1)), X), 1)

def normalEqn(X, y):
    return np.linalg.pinv((X.T @ X)) @ X.T @ y

# print('normalEqn() test')
# X_test = np.array([[2, 1, 3], [7, 1, 9], [1, 8, 1], [3, 7, 4]])
# y_test = np.array([[2], [5], [5], [6]])
# print(normalEqn(X_test, y_test))
# print('test over')

theta = normalEqn(X, y)
print('Theta computed from the normal equations: [%f, %f, %f]' % (theta[0], theta[1], theta[2]))

price = np.array([[1, 1650, 3]]) @ theta
print('Predicted price of a 1650 sq-ft, 3 br house (using norma equations): $%f' % price)

# plot normalEqn
ax = plt.axes(projection = '3d')
x0 = X[:, 1:2]
x1 = X[:, 2:3]
x0 = np.linspace(np.min(x0), np.max(x0), 10)
x1 = np.linspace(np.min(x1), np.max(x1), 10)
x0, x1 = np.meshgrid(x0, x1)
z = x0 * theta[1] + x1 * theta[2] + theta[0]
ax.plot_surface(x0, x1, z, color='w', alpha=0.5)
ax.scatter3D(X[:,1:2], X[:,2:3], y, c='b', marker='^')
ax.scatter3D(1650, 3, price, c='r', marker='o')
ax.invert_xaxis()

plt.xlabel('sq-ft')
plt.ylabel('br')
plt.show()


#!/usr/bin/env python

from scipy.optimize import linprog

"""
Solve a basic linear programming problem using SciPy
https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.linprog.html
"""

def main():
    """
    Minimize:  c^T * x
    Subject to:
        A_ub * x <= b_ub
        A_eq * x == b_eq
    """

    print('\n')
    print('**************************************************')
    print('Example from scipy.optimize.linprog documentation:')
    print('**************************************************')
    print('Minimize: [-1; 4] * x')
    print('Subject to:  [[-3, 1]; [1, 2]] * x < [6; 4]')
    c = [-1, 4]
    A = [[-3, 1], [1, 2]]
    b = [6, 4]
    x0_bounds = (None, None)
    x1_bounds = (-3, None)
    print('Solving...')
    result = linprog(c, A_ub=A, b_ub=b, bounds=(x0_bounds, x1_bounds),
                  options={"disp": True})
    print('Result:')
    print(result)

    print('\n')
    print('*********************************')
    print('Infeasible Example:')
    print('  http://math.stackexchange.com/questions/2011787/linear-programming-excercise/')
    print('*********************************')
    print('Minimize: [1;2;3] * x')
    print('Subject to:')
    print(    'x1 + 3*x3 >= 3')
    print(    '-x1 + x2 + 3*x3 <= 4')
    print(    'x1 + 2*x2 - 3*x3 <= -6')
    print(    'x1 >= 0')
    print(    'x2 >= 0')
    print(    'x3 >= 0')
    c = [1, 2, 3]  # objective function
    # Inequality constraint matrix. Note that first inequality is negated.
    A = [[-1,0,-3], [-1, 1, 3], [1,2,-3]]
    b = [-3, 4, -6]
    x0_bnd = (0, None)
    x1_bnd = (0, None)
    x2_bnd = (0, None)
    print('Solving...')
    result = linprog(c, A_ub=A, b_ub=b, bounds=(x0_bnd, x1_bnd, x2_bnd),
                  options={"disp": True})
    print('Result:')
    print(result)

if __name__ == "__main__":
    main()


#The Hacker Within: Python Boot Camp 2010 - Session 07 - Using SciPy.
#Presented by Anthony Scopatz.
#
#SciPy Integration, run before you glide.

#Tools used to calculate numerical, definite integrals may be found in the 'integrate' module.
import scipy.integrate
#For kicks, let's also grab
import scipy.special
import numpy

#There are two basic ways you can integrate in SciPy:
#     1. Integrate a function, or
#     2. Integrate piecewise data.

#First Let's deal with integration of functions.
#Recall that in Python, functions are also objects.
#Therefore you can pass functions as arguments to other functions!
#Just make sure that the function that you want to integrate returns a float,
#or, at the very least, an object that has a __float__() method.

#The simplest way to compute a functions definite integral is via the quad(...) function.
def CrazyFunc(x):
	return (scipy.special.i1(x) - 1)**3

print("Try integrating CrazyFunc on the range [-5, 10]...")

val, err = scipy.integrate.quad(CrazyFunc, -5, 10)

print("A Crazy Function integrates to %.8E"%val)
print("And with insanely low error of %.8E"%err)
print("")

#You can also use scipy.integrate.Inf for infinity in the limits of integration
print("Now try integrating e^x on [-inf, 0]")
print("(val, err) = " + str( scipy.integrate.quad(scipy.exp, -scipy.integrate.Inf, 0.0) ))
print("")

#2D integrations follows similarly,
def dA_Sphere(phi, theta):
	return  scipy.sin(phi)

print("Integrate the surface area of the unit sphere...")
val, err = scipy.integrate.dblquad(dA_Sphere, 0.0, 2.0*scipy.pi, lambda theta: 0.0,  lambda theta: scipy.pi )
print("val = %.8F"%val)
print("err = %.8E"%err)
print("")

def dV_Sphere(phi, theta, r):
	return r * r * dA_Sphere(phi, theta)

print("Integrate the volume of a sphere with r=3.5...")
val, err = scipy.integrate.tplquad(dV_Sphere, 0.0, 3.5, lambda r: 0.0, lambda r: 2.0*scipy.pi, lambda x, y: 0.0, lambda x, y: scipy.pi)
print("val = %.8F"%val)
print("err = %.8E"%err)
print("")

#Now, only very rarely will scientists (and even more rarely engineers) will truely 'know'
#the function that they wish to integrate.  Much more often we'll have piecewise data
#that we wish numerically integrate (ie sum an array y(x), biased by array x).
#This can be done in SciPy through the trapz function.

y = range(0, 11)
print("Trapazoidally integrate y = x on [0,10]...")
val = scipy.integrate.trapz(y)
print("val = %F"%val)
print("")

#You can also define a domain to integrate over.
x = numpy.arange(0.0, 20.5, 0.5)
y = x * x
print("Trapazoidally integrate y = x^2 on [0,20] with half steps...")
val = scipy.integrate.trapz(y, x)
print("val = %F"%val)
print("")

print("Trapazoidally integrate y = x^2 with dx=0.5...")
val = scipy.integrate.trapz(y, dx=0.5)
print("val = %F"%val)
print("")

def dDecay(y, t, lam):
	return -lam*y

#Of course, sometimes we have simple ODEs that we want to integrate over time for...
#These are generally of the form:
#     dy / dt = f(y, t)
#For example take the decay equation...
#     f(y, t) = - lambda * y
#We can integrate this using SciPy's 'odeint'  This is of the form:
#     odeint( f, y0, [t0, t1, ...])
#Let's try it...
vals = scipy.integrate.odeint( lambda y, t: dDecay(y, t, 0.2), 1.0, [0.0, 10.0] )
print("If you start with a mass of y(0) = %F"%vals[0][0])
print("you'll only have y(t=10) = %F left."%vals[1][0])

#Check out http://docs.scipy.org/doc/scipy/reference/integrate.html for a complete listing.


"""
simplex_algorithm.py

Returns the minimizer of the function
"""

import numpy as np
np.set_printoptions(formatter={'float': lambda x: "{0:0.3f}".format(x)});

def pivoting(tabl, p, q):
    # pivoting about (p,q)-th element
    tabl_new = tabl - tabl[p] * (tabl[:, [q]] / tabl[p, [q]]);
    tabl_new[p] = tabl[p] / tabl[p, [q]];

    return tabl_new;

def simplex_algorithm(A, b, C, indx_cols, options):

    b_print = options['b_print'];
    b_blands_rule = options['b_blands_rule'];
    epsilon = -10e-6; # workaround for -0 issues in while loop

    if (b_print):
        # Forming initial tableau
        tabl_top = np.concatenate((A, b), axis = 1);
        tabl_bottom = np.concatenate((C.T, np.array([[0]])), axis = 1);
        tabl = np.concatenate((tabl_top, tabl_bottom), axis = 0);
        print(' ');
        print('Initial Tableau [A b; C.T 0]');
        print(tabl);

    m, n = A.shape;
    Binv = np.linalg.inv(A[:, indx_cols]); # inverse matrix of basic columns of A
    A = Binv @ A;
    b = Binv @ b;
    cB = C[indx_cols]; # vector of cost coefficients for basic cols of A
    r = C - A.T @ cB; # vector of relative cost coefficients
    cost = -cB.T @ b; # cost function

    # Forming canonical tableau
    tabl_top = np.concatenate((A, b), axis = 1);
    tabl_bottom = np.concatenate((r.T, cost), axis = 1);
    tabl = np.concatenate((tabl_top, tabl_bottom), axis = 0);

    if (b_print):
        print(' ');
        print('Canonical Tableau [A b; r.T cost]');
        print(tabl);

    while (np.sum(r >= epsilon * np.ones((n, 1))) != n):

        if (b_blands_rule):
            q = 0;
            while(r[q] >= 0):
                q += 1;
        else:
            q = np.argmin(r); # col #q comes into basis

        if (np.sum((tabl[0:m, [q]]) > 0) == 0):
            print('Problem unbounded, exit..');
            break;

        a = tabl[0:m, [q]] / tabl[0:m, [n]];
        p = np.argmax(a); # col #p leaves basis

        # pivoting about (p,q)-th element
        tabl = pivoting(tabl, p, q);

        if (b_print):
            print(' ');
            print('Pivoting about (%d, %d)-th element' % (p, q));
            print(' ');
            print('Updated canonical Tableau [A b; r.T cost]');
            print(tabl);

        indx_cols[p] = q;
        r = (tabl[[m], 0:n]).T;

    X = np.zeros((n, 1));
    X[indx_cols] = tabl[0:m, [n]];
    cost = C.T @ X; # cost function

    if (b_print):
        print(' ');
        print('f(X) = %0.3f' % (cost));
        print('Solution:');
        print(X);

    return (X, cost);


"""Visuals for KLD divergence between a normal and Gaussian distribution"""
import matplotlib.pyplot as plt
import numpy as np

from autoencoders.divergence.kld import KLD

##############################################################################
stds = np.array([0.25, 0.5, 1, 4, 9, 16]).reshape(2, 3)

fig, axs = plt.subplots(
    nrows=2,
    ncols=3,
    figsize=(15, 8),
    sharex=True,
    sharey=True,
    tight_layout=True,
)

kld = KLD()

for idx_row, ax_row in enumerate(axs):

    for idx_col, ax in enumerate(ax_row):

        ax.plot(kld.x, kld.prior, color="black", label="N(0,1)")

        std = stds[idx_row, idx_col]

        divergence, g = kld.to_gaussian(mu=0, std=std)

        ax.plot(kld.x, g, label=f"N(0,{std})\nKLD={divergence:.2f}")
        ax.tick_params(labelleft=False, labelbottom=False)
        ax.legend()
##############################################################################
mus = np.arange(-2, 4, 1).reshape(2, 3)

fig, axs = plt.subplots(
    nrows=2,
    ncols=3,
    figsize=(15, 8),
    sharex=True,
    sharey=True,
    tight_layout=True,
)

for idx_row, ax_row in enumerate(axs):
    for idx_col, ax in enumerate(ax_row):

        ax.plot(kld.x, kld.prior, color="black", label="N(0,1)")

        mu = mus[idx_row, idx_col]

        divergence, g = kld.to_gaussian(mu=mu, std=1)

        ax.plot(kld.x, g, label=f"N({mu}, 1)\nKLD={divergence:.2f}")
        ax.tick_params(labelleft=False, labelbottom=True)
        ax.legend()


from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fminbound as fmin

#imports for auxiliar classes
import Spline as spl
import Interpolation as inter

'''functions, f, f(2),f(4) f(9)'''
f = lambda x: (4*np.power(x,2)+np.sin(9*x))
f2 = lambda x: (8-8*np.cos(9*x))
f4 = lambda x: 6561*np.cos(9*x)
f9 = lambda x: -386239509*np.sin(9*x)

def graphicTable(x,y,func=False):
    #Spline and Interpolating polinomial calculation
    #initiates classes
    data = spl.Spline(x,y)
    data2 = inter.Interpolation(x,y)

    spline = data.buildNormalSpline()   #calculates the spline for the dataset
    data2_x,data2_y= data2.interpolateData() #calculates the interpolating pol
    xs = np.arange(x[0],x[-1]+0.0001,0.0001)

    plt.plot(x,y,"o",label="Data")
    if func:
        #displays the actual function f
        plt.plot(xs,f(xs),label='True Value')
    plt.plot(xs,spline(xs),label="Spline Trace")
    plt.plot(data2_x,data2_y,label="Interpolation")
    plt.legend(loc='lower left',ncol=2)
    plt.grid()
    plt.show()

    return data,spline,data2

def pointSet(lower,upper,n):
    #Creates the liniar spaced values in [lower,upper]
    values = np.linspace(lower,upper,num=n,endpoint=True)
    a = []
    for val in values:
        a.append(f(val))
    return values,np.array(a)

def maxH(x):
    #Calculates the max h value in the data_set
    max_h = None
    for i in range(len(x)-1):
        h = x[i+1]-x[i]
        if not max_h:
            max_h = h
        max_h = max(max_h,h)
    return max_h

def M(lower,upper,interpolation=False):
    #Calculates the maximizer  of f4 or f9 in [lower,upper]
    if interpolation:
        return fmin(lambda x : -f9(x),lower,upper)
    return fmin(lambda x : -f4(x),lower,upper)

def interpolationError(x,value,lower,upper):
    #Calculates the major error in interpolating polinomial
    m = M(lower,upper,interpolation=True)
    m = abs(f9(m))
    print("     Max|f9(x)|="+str(m)+" ,"+str(lower)+"<=x<="+str(upper))
    n1 = len(x)+1
    b = np.arange(1,n1)
    fac = b.prod()
    mult = 1
    for i in x:
        mult *= (value-i)
    return (m/fac)*abs(mult)
def splineError(x,lower,upper):
    #Calculates the major error in the spline
    m = M(lower,upper,interpolation=False)
    m = abs(f4(m))
    h = maxH(x)
    print("     Max|f4(x)|="+str(m)+" ,"+str(lower)+"<=x<="+str(upper))
    print("     Max(h)="+str(h))
    return (5/384)*m*np.power(h,4)

def ex1():
    #exercise 1
    x = np.array([0,1,2,2.5,3,4])
    y = np.array([1.4,0.6,1.0,0.6,0.6,1.0])
    spline,natural,interpolator = graphicTable(x,y,func=False)
    print("Spline equations:")
    spline.showEquations(natural)

def ex2():
    #exercise 2
    x,y = pointSet(-1,1,9)
    spline,natural, interpolator = graphicTable(x,y,func=True)

    print("Data Table:") #Show points and images in table
    for i in range(len(x)):
        print("("+str(x[i])+","+str(y[i])+")")

    print("\n\nSpline equations:") #Show Spline equations
    spline.showEquations(natural)
    print("\n\nx=0.3: ")
    print("     S(0.3)="+str(spline.calc(0.3,spline=natural)))
    print("     |f(0.3)-S(0.3)|<="+str(splineError(x,-1,1)))

    print("\n     p(0.3)="+str(interpolator.calc(0.3)))
    print("     |f(0.3)-p(0.3)|<="+str(interpolationError(x,0.3,-1,1)))

    print("\n\nx=0.83:")
    print("     S(0.83)="+str(spline.calc(0.83,spline=natural)))
    print("     |f(0.83)-S(0.83)|<="+str(splineError(x,-1,1)))

    print("\n     p(0.83)="+str(interpolator.calc(0.83)))
    print("     |f(0.83)-p(0.83)|<="+str(interpolationError(x,0.83,-1,1)))

# Starter-----------------------------------------------------------------------
print("Exercise 1:")
ex1()
print("\nExercise2:")
ex2()


import numpy as np

from utils import load_data, plot_data, computer_cost, normalize

def gradient_descent(X, Y, alpha, iteration):
    m = Y.size
    theta = np.zeros((X.shape[1], 1))
    j_list = []
    for i in range(iteration):
        v = computer_cost.computer(X, Y, theta)
        j_list.append(v)
        values = (X.dot(theta) - Y).T.dot(X).T * (alpha / m)
        theta = theta - values
    return theta, np.array(j_list)

def main():
    X_normalize, Y_normalize, Origin_X_normalize, Y_mean, Y_std, Origin_X_mean, Origin_X_std = load_data.load_and_normalize('data2.txt')

    alpha = 0.024
    iterations = 800
    theta, j_list = gradient_descent(X_normalize, Y_normalize, alpha, iterations)
    print('The linear regression formula is {0} + {1} * x1 + {2} * x2'.format(theta[0, 0], theta[1, 0], theta[2,0]))

    iteration_array = range(iterations)
    plot_data.plot(iteration_array, j_list, 'iteration', "lost",
                   {
                       'fmt': 'b-',
                       'title': 'Lost',
                       'show': True
                   })

    house_size = 1650
    br_num = 3

    house_size_normal = (house_size - Origin_X_mean[0]) / Origin_X_std[0]
    br_num = (br_num - Origin_X_mean[1]) / Origin_X_std[1]

    X_new_normalize = np.array([1, house_size_normal, br_num])
    price_normalize = X_new_normalize.dot(theta).sum()
    price = price_normalize * Y_std[0] + Y_mean[0]
    print('price is {0}'.format(price))

if __name__ == '__main__':
    main()


import time
import numpy as np
from utils.features.pca import *

def pca_preprocess(X, K):
    """Data transformation step"""
    N, D = X.shape;
    X = X - np.tile(np.mean(X, 0), (N, 1))
    P, _ = pca_naive(X, K)
    return np.dot(X, P.T).real

def p_entropy(X2, sigma):
    """Calculating perplexity entropy"""
    epsilon = 1e-15
    P = np.exp(-X2*sigma)
    P = P / np.sum(P)
    H = -np.dot(np.log(P+epsilon), P)

    return P,H

def binary_search(X, perplexity):
    """Binary search for perplexity"""
    tol = 1e-5
    goal = np.log(perplexity)
    N, D = X.shape
    sigma = np.ones((N,)).astype('float')
    P = np.zeros((N,N))

    # X2: norm2 distance matrix - NxN
    X2 = (-2*np.dot(X, X.T) + np.sum(X**2, axis=1)).T + np.sum(X**2, axis=1)

    # loop over all points
    for i in range(N):

        sigma_max = np.inf
        sigma_min = 0
        maxiter = 50

        sigma_i = sigma[i]

        for t in range(maxiter):
            X2_i = X2[i, np.concatenate((np.r_[0:i], np.r_[i+1:N]))]
            Pi, Hi = p_entropy(X2_i, sigma_i)
            # binary search for a correct sigma_i
            if abs(Hi-goal) < tol:
                break
            else:
                if Hi > goal:
                    sigma_min = sigma_i
                    if sigma_max == np.inf:
                        sigma_i *= 2
                    else:
                        sigma_i = (sigma_i + sigma_max)/2
                else:
                    sigma_max = sigma_i
                    sigma_i = (sigma_i + sigma_min)/2

        # Set Pi
        sigma[i] = sigma_i
        P[i, np.concatenate((np.r_[0:i], np.r_[i+1:N]))] = Pi

    #Return P
    print(np.mean(np.sqrt(1/sigma)))
    return P

def tsne(X, low_dim=2, perplexity=30.0):
    """
    tSNE - t-Stochastic Neighbor Embedding
    Inputs:
    - X: (float) an array of shape(N,D)
    - low_dim: (int) dimenional of output data
    - pca_dim: (int) rather than using the raw data, we can apply
                pca preprocessing to reduce the dimension to pca_dim
    - perplexity:

    Returns;
    - Y: (float) an array of shape (N,low_dim)
    """

    # X = pca_preprocess(X, low_dim)

    N,D = X.shape

    P = binary_search(X, perplexity)
    P = (P + P.T) / (2*N)
    P = np.maximum(P, 1e-12)
    P *= 4
    Y = np.random.normal(0, 1e-4, (N,low_dim))

    T = 1000
    # training parameters
    momentum = 0.5 # initial momentum
    V = np.zeros_like(Y)
    lr = 100 # initial learning rate
    beta = 0.8
    kappa = 0.2
    gamma = 0.2
    mu = np.ones_like(V)

    tic = time.time()
    for t in range(T):

        Y2 = (-2*np.dot(Y, Y.T) + np.sum(Y**2, axis=1)).T + np.sum(Y**2, axis=1)
        Q_numerator = 1/(1 + Y2)
        Q = Q_numerator
        np.fill_diagonal(Q, 0)
        Q = Q / np.sum(Q)
        Q = np.maximum(Q,1e-12)

        dY = np.zeros_like(Y)
        for i in range(N):
            dY[i,:] = 4*np.dot((P[i,:]-Q[i,:])*Q_numerator[i,:], Y-Y[i,:])

        # calculate learning rate
        dY_hat = (1-beta)*dY + beta*V
        mu[np.where(dY*dY_hat>0)] = mu[np.where(dY*dY_hat>0)] + kappa
        mu[np.where(dY*dY_hat<0)] = (1-gamma)*mu[np.where(dY*dY_hat<0)]
        # update
        if t > 250:
            momentum = 0.8
        V = momentum*V + lr*mu*dY
        Y += V

        # stop early exaggeration
        if t == 100:
            P /= 4

        # verbose: report intermediate result
        if (t+1) % 100 == 0:
            cost = np.sum(P * np.log(P / Q));
            print('The {} th loop cost: {}, computation time: {}'.format(t+1, cost, time.time()-tic))

    return Y


# -*- coding: utf-8 -*-
"""
Created on Mon Sep 21 08:33:44 2020

@author: Ashlee
"""

import numpy as np

from scipy.integrate import odeint
import matplotlib.pyplot as plt

def system_of_ODEs(numerators=[6.25,0],denominator=0, parameters=[0.15,0.6,0.1,0.2]):
    # numerators are the dependent variables
    # denominator is the independent variable
    CA = numerators[0]
    CB = numerators[1]
    t = denominator
    k1 = parameters[0]
    k2 = parameters[1]
    k3 = parameters[2]
    k4 = parameters[3]

    dCAdt = -k1*CA-k2*CA
    dCBdt = k1*CA-k3-k4*CB

#    return np.array([[dCAdt],[dCBdt]]) # column vector
    return [dCAdt,dCBdt]

tspan = np.linspace(0,10,101)
CA0 = 6.25
CB0 = 0
C0 = CA0,CB0

k1 = 0.15
k2 = 0.6
k3 = 0.1
k4 = 0.2
parameters = (k1,k2,k3,k4)

output = odeint(system_of_ODEs, C0,tspan, args = (parameters,))
print(output)
plt.plot(output)

CHEclassFa20/In Class Problem Solutions/Python/solve_system_of_ODEs.py


import numpy as np
from numpy.random import choice, rand, randint
from numba import jit, njit

######## Main Code ###########

@njit
def mcmc(spins, N, J, B, T, n_steps = 10000, out_freq = 1000):

    '''mcmc takes spin configuration and samples with given N,J,B,T
    for n_steps outputing results every out_freq'''

    confs = []

    for step in range(n_steps):

        #Pick random spin
        i, j = randint(N), randint(N)

        #Compute energy change
        z  = spins[(i+1)%N, j] + spins[(i-1)%N, j] + spins[i, (j+1)%N] + spins[i, (j-1)%N]
        dE = 2*spins[i,j]*(J*z + B)

        #Metropolis condition
        if dE <= 0 or np.exp(-dE/T) > rand():

            spins[i,j] *= -1

        #Store the spin configuration
        if step % out_freq == 0:

            confs.append(spins.copy())

    return confs

@njit
def getM(spins):

    return np.mean(spins)

@njit
def getE(spins,N,J,B):

    E = 0

    for i in range(N):
        for j in range(N):

            z = spins[(i+1)%N, j] + spins[(i-1)%N, j] +spins[i,(j+1)%N] +  spins[i,(j-1)%N]

            E += -J*z*spins[i,j]/4 # Since we overcounted interactions 4 times divide by 4.

    return E - B*np.sum(spins) #Field contribution added

@jit
def temper(configs):

    '''Randomly pick two adjacent replicas and attempt an exchange'''

    i       = np.random.randint(N_repl-1)
    j       = i+1

    deltaBeta      = 1/T[i] - 1/T[j]

    deltaEnergy    = getE(configs[i][-1],N,J,B) - getE(configs[j][-1],N,J,B)

    if deltaBeta*deltaEnergy < 0 or np.exp(-deltaBeta*deltaEnergy) > rand():

        configs[i][-1], configs[j][-1] = configs[j][-1], configs[i][-1]

    return configs

@jit
def pt_mcmc(N, J, B, T=[1, 0.1], n_exch=1000, n_steps=10000, out_freq=1000):

    N_repl     = len(T)
    configs    = [[choice([-1,1], (N,N))] for i in range(N_repl)]

    for exch_attempt in range(n_exch): #Exchange attemps

        configs = temper(configs)

        for i in range(N_repl): #mcmc in between exchange attemps

            configs_new = mcmc(configs[i][-1],N, J, B, T[i])

            configs[i].extend(configs_new)

    return configs


import pandas as pd
import random
import numpy as np

N = 10000

TotalTime=[]

T =  np.empty(shape=(N,6))

TaskTimes=[[3,5,8],
          [2,4,7],
           [3,5,9],
           [4,6,10],
           [3,5,9],
           [2,6,8]]

Lh=[]
for i in range(6):
    Lh.append((TaskTimes[i][1]-TaskTimes[i][0])/(TaskTimes[i][2]-TaskTimes[i][0]))

for p in range(N):
    for i in range(6):
        trand=random.random()
        if (trand < Lh[i]):
            T[p][i] = TaskTimes[i][0] + np.sqrt(trand*(TaskTimes[i][1]-TaskTimes[i][0])*(TaskTimes[i][2]-TaskTimes[i][0]))
        else:
            T[p][i] = TaskTimes[i][2] - np.sqrt((1-trand)*(TaskTimes[i][2]-TaskTimes[i][1])*(TaskTimes[i][2]-TaskTimes[i][0]))
    TotalTime.append( T[p][0]+ np.maximum(T[p][1],T[p][2]) + np.maximum(T[p][3],T[p][4]) + T[p][5])

Data = pd.DataFrame(T,columns=['Task1', 'Task2', 'Task3', 'Task4', 'Task5', 'Task6'])

pd.set_option('display.max_columns', None)
print(Data.describe())

hist = Data.hist(bins=10)

print("Minimum project completion time = ",np.amin(TotalTime))

print("Mean project completion time = ",np.mean(TotalTime))

print("Maximum project completion time = ",np.amax(TotalTime))


"""Mixture model using EM"""
from typing import Tuple
import numpy as np
from utils import GaussianMixture

def estep(X: np.ndarray, mixture: GaussianMixture) -> Tuple[np.ndarray, float]:
    """E-step: Softly assigns each datapoint to a gaussian component

    Args:
        X: (n, d) array holding the data
        mixture: the current gaussian mixture

    Returns:
        np.ndarray: (n, K) array holding the soft counts
            for all components for all examples
        float: log-likelihood of the assignment
    """

    n, d = X.shape
    K, _ = mixture.mu.shape
    post = np.zeros((n, K))
    dr = np.sqrt((2*np.pi*mixture.var)**d)
    exponent_nr = -0.5*(np.linalg.norm(X[:,:,None] - mixture.mu.T,axis=1)**2)
    normal_ = np.exp(exponent_nr/mixture.var)/dr
    log_likelihood = np.sum(np.log(np.sum(mixture.p*normal_,axis=1)))
    post = (mixture.p*normal_)/(np.sum(mixture.p*normal_,axis=1,keepdims=True))

    return post, log_likelihood

def mstep(X: np.ndarray, post: np.ndarray) -> GaussianMixture:
    """M-step: Updates the gaussian mixture by maximizing the log-likelihood
    of the weighted dataset

    Args:
        X: (n, d) array holding the data
        post: (n, K) array holding the soft counts
            for all components for all examples

    Returns:
        GaussianMixture: the new gaussian mixture
    """

    n, d = X.shape
    _, K = post.shape
    n_hat = post.sum(axis=0, keepdims=True)
    p = n_hat / n
    mu = np.zeros((K, d))
    var = np.zeros(K)
    mu = post.T @ X / n_hat.T
    var = np.sum(post * (np.linalg.norm(X[:,:,None] - mu.T,axis=1)**2),axis=0)/(d*n_hat)

    return GaussianMixture(mu, var[0], p[0])

def run(X: np.ndarray, mixture: GaussianMixture,
        post: np.ndarray) -> Tuple[GaussianMixture, np.ndarray, float]:
    """Runs the mixture model

    Args:
        X: (n, d) array holding the data
        post: (n, K) array holding the soft counts
            for all components for all examples

    Returns:
        GaussianMixture: the new gaussian mixture
        np.ndarray: (n, K) array holding the soft counts
            for all components for all examples
        float: log-likelihood of the current assignment
    """
    prev_cost = None
    cost = None
    while True:
        prev_cost = cost
        post, cost = estep(X, mixture)
        mixture = mstep(X, post)
        try:
            if (abs(prev_cost - cost) < (1e-6*np.abs(cost))):
                break
            else:
                continue
        except:
            pass
    return mixture, post, cost


import numpy as np

def get_divisors(x):
	rez = [1]
	top_bar = x/2+1
	for i in xrange(2, x/2+1):
		if i >= top_bar:
			break
		div_whole = x / i
		if x % i == 0:
			rez.append(i)
			rez.append(div_whole)
			if div_whole < top_bar:
				top_bar = div_whole
	rez.sort()
	return rez

# print(np.array(get_divisors(220)).sum())
# print(np.array(get_divisors(284)).sum())
# exit()

total_sum = 0
found_pairs = []
for n in xrange(1, 10000):
	if n in found_pairs:
		continue
	divs1_sum = np.array(get_divisors(n)).sum()
	divs2_sum = np.array(get_divisors(divs1_sum)).sum()
	if divs2_sum == n and divs1_sum != n:
		total_sum += n
		total_sum += divs1_sum
		found_pairs.append(n)
		found_pairs.append(divs1_sum)

print(total_sum)


import numpy as np
import matplotlib.pylab  as plt
def Kendall_change_point_detection(inputdata):
    inputdata1 = np.array(inputdata)
    n=inputdata1.shape[0]
    Sk             = [0]
    UFk            = [0]
    s              =  0
    Exp_value      = [0]
    Var_value      = [0]
    for i in range(1,n):
        for j in range(i):
            if inputdata1[i] > inputdata1[j]:
                s = s+1
            else:
                s = s+0
        Sk.append(s)
        Exp_value.append((i+1)*(i+2)/4 )                     # Sk[i] mean
        Var_value.append((i+1)*i*(2*(i+1)+5)/72 )            # Sk[i] std
        UFk.append((Sk[i]-Exp_value[i])/np.sqrt(Var_value[i]))
    #Inverse sequence computing generation
    Sk2             = [0]
    # Define the reverse order statistics UBk, the length is consistent with inputdata, initial value = 0
    UBk             = [0]
    UBk2            = [0]
    # s=0
    s2              =  0
    Exp_value2      = [0]
    Var_value2      = [0]
    #
    inputdataT = list(reversed(inputdata1))
    for i in range(1,n):
        for j in range(i):
            if inputdataT[i] > inputdataT[j]:
                s2 = s2+1
            else:
                s2 = s2+0
        Sk2.append(s2)
        Exp_value2.append((i+1)*(i+2)/4 )                     # Sk[i] mean
        Var_value2.append((i+1)*i*(2*(i+1)+5)/72 )            # Sk[i] std
        UBk.append((Sk2[i]-Exp_value2[i])/np.sqrt(Var_value2[i]))
        UBk2.append(-UBk[i])
    UBkT = list(reversed(UBk2))
    diff = np.array(UFk) - np.array(UBkT)
    K    = list()
    # Find the intersection
    for k in range(1,n):
        if diff[k-1]*diff[k]<0:
            K.append(k)

 #   plt.figure(figsize=(10,5))
 #   plt.plot(range(1,n+1) ,UFk  ,label='UFk') # UFk
 #   plt.plot(range(1,n+1) ,UBkT ,label='UBk') # UBk
#    plt.ylabel('UFk-UBk')
 #   x_lim = plt.xlim()
#    plt.plot(x_lim,[-1.96,-1.96],'m--',color='r')
#    plt.plot(x_lim,[  0  ,  0  ],'m--')
#    plt.plot(x_lim,[+1.96,+1.96],'m--',color='r')
#    plt.legend(loc=2) # 图例
#     plt.savefig("./Dectection/{}_Mann-Kendall.png".format(name))
#    plt.show()
#   b=[]
#    for i in K:
#        tmp=inputdata.index[i]
#        b.append(tmp.strftime("%Y-%m-%d"))
    return K


# -*- coding: utf-8 -*-
# !/usr/bin/env python3

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

def pdf(x):
    return exp_lambda * np.exp(-exp_lambda * x)

def cdf(x):
    return 1 - np.exp(-exp_lambda * x)

def correlate(x, y):
    n = len(x)
    sx = sum(x)
    sy = sum(y)
    sx2 = sum(i ** 2 for i in x)
    sy2 = sum(i ** 2 for i in y)
    sxy = sum(x[i] * y[i] for i in range(n))
    return (n * sxy - sx * sy) / ((n * sx2 - sx * sx) * (n * sy2 - sy * sy)) ** 0.5

# Question 1(A)
exp_lambda = 57  # average confirmed cases per hour
x = np.arange(0, 0.1, 10 ** -6)
y = pdf(x)
plt.xlabel('Wait time in hours')
plt.ylabel('Probability density')
plt.plot(x, y)
plt.show()

# Question 1(B)
print("P(X < 1/60) = {:.6f}".format(cdf(1 / 60)))

# Question 1(C)
print("P(1/60 < X < 2/60) = {:.6f}".format(cdf(1 / 30) - cdf(1 / 60)))

# Question 1(D)
print("P(X > 2/60) = {:.6f}".format(1 - cdf(1 / 30)))

# Question 1(E)
exp_lambda = 114  # average confirmed cases per hour doubles
print("P(1/60 < X < 2/60) = {:.6f}".format(cdf(1 / 30) - cdf(1 / 60)))

# Question 2(A)
df = pd.read_csv('IC252_Lab8.csv')
df['Status'] = df['Status'].replace({"Hospitalized": 1, "Recovered": 2, "Dead": 3})

# Question 2(B)
r = [['Status,Population', correlate(df['Status'], df['Population'])],
     ['Status,SexRatio', correlate(df['Status'], df['SexRatio'])],
     ['Status,Literacy', correlate(df['Status'], df['Literacy'])],
     ['Status,Age', correlate(df['Status'], df['Age'])],
     ['Status,SmellTrend', correlate(df['Status'], df['SmellTrend'])],
     ['Status,Gender', correlate(df['Status'], df['Gender'])]]
print('\n'.join('r({}) = {:.6f}'.format(k[0], k[1]) for k in r))

# Question 2(C)
print(' > '.join(['r({})'.format(k[0]) for k in sorted(r, key=lambda x: x[1], reverse=True)]))


import numpy as np
import stats
import seaborn as sns
import matplotlib.pyplot as plt

# ----------- #
# Utils:
#   * scree_plot
#   * Hinton diagram
#
#
# ----------- #

def scree_plot(arr : np.ndarray, figsize=(18, 8)):
    """Generates a scree plot for a given data array.

    Parameters
    ----------
    arr : np.ndarray
        matrix in (samples x features) form
    figsize : tuple, optional
        by default (18, 8)
    """
    eigvals = np.linalg.eigs(stats.cov(arr))
    plt.figure(figsize=figsize)
    plt.title('Eigenvalue versus magnitude (Scree plot)')
    sns.barplot(x=np.arange(len(eigvals)), y=eigvals, color='blue', saturation=.3)
    plt.ylabel('Magnitude')
    plt.xlabel('Eigenvalue index')
    plt.show()

def hinton(matrix, max_weight=None, ax=None):
    """Draw Hinton diagram for visualizing a weight matrix."""
    ax = ax if ax is not None else plt.gca()

    if not max_weight:
        max_weight = 2 ** np.ceil(np.log(np.abs(matrix).max()) / np.log(2))

    ax.patch.set_facecolor('gray')
    ax.set_aspect('equal', 'box')
    ax.xaxis.set_major_locator(plt.NullLocator())
    ax.yaxis.set_major_locator(plt.NullLocator())

    for (x, y), w in np.ndenumerate(matrix):
        color = 'white' if w > 0 else 'black'
        size = np.sqrt(np.abs(w) / max_weight)
        rect = plt.Rectangle([x - size / 2, y - size / 2], size, size,
                             facecolor=color, edgecolor=color)
        ax.add_patch(rect)

    ax.autoscale_view()
    ax.invert_yaxis()

# ----------- #
# Linear Methods:
#   * pca
#
#
#
# ----------- #

def pca(data : np.ndarray, dim : int = 2, verbose : bool = False, class_identity=None, return_reconstruction=False) -> np.ndarray:
    """Principal components analysis to form a (dim) dimensional approximation
    of a given dataset.

    Parameters
    ----------
    data : np.ndarray
        matrix in (samples x features) form
    dim : int, optional
        approximating dimension, must be less than the data dimension, by default 2
    verbose : bool, optional
        whether to display reconstruction diagnostics and a scree plot
    Returns
    -------
    np.ndarray
        dim-dimensional representation of the input data
    """
    if np.sum(np.isnan(data).astype(int)) > 0:
        print("missing data detected. consider using pca_missing_data")
        raise(NotImplemented)

    reconstruction=None
    n, p = data.shape
    assert 0 < dim < p, "projection dimension must be a positive integer less than the number of data dimensions {}".format(p)

    # center the data
    de_meaned = stats.center(data)

    # optimize for high dimensionality data
    if p > n:
        print('High dimensional data detected, optimizing...')

        # X@X.T is (n x n) which we're assuming is actually smaller than (p x p) in this case
        X = de_meaned
        eigvals, X_eigvecs = np.linalg.eig(X @ X.T)

        # plop the eigenvalues into a diagonal matrix lambda
        lam = np.diag(np.real(eigvals))

        # compute the eigenvecs
        # transformed_E = X @ X_eigvecs
        lam_inv = np.linalg.inv(lam)
        eigvecs = (X.T @ X_eigvecs @ lam_inv)

    else:
        # generate the data covariance matrix
        sample_covariance = stats.cov(de_meaned)

        # extract spectrum of the covariance matrix (its set of eigenvalues and eigenvectors)
        eigvals, eigvecs = np.linalg.eig(sample_covariance)

    # arrange the eigenvectors so that they are ordered according to the magnitude (large->small) of their corresponding eigenvalue
    idx = eigvals.argsort()[::-1]
    eigvals = np.real(np.array(eigvals[idx]))
    eigvecs = np.real(np.array(eigvecs[:, idx]))
    E = eigvecs[:, :dim]

    # compute low dimensional representation.
    Y = np.array(data @ E)

    if verbose is True:
        # scree plot
        plt.figure(1, figsize=(18, 8))
        plt.title('Eigenvalue versus magnitude (Scree plot)')
        sns.barplot(x=np.arange(len(eigvals)), y=eigvals, color='blue', saturation=.3)
        plt.ylabel('Magnitude')
        plt.xlabel('Eigenvalue index')
        plt.show()

        # reconstruction
        reconstruction = Y @ E.T
        assert reconstruction.shape == data.shape
        reconstruction_params = [data, reconstruction]
        labels = ['Original data', 'Reconstruction']

        fig, axes = plt.subplots(ncols=2, nrows=1, figsize=(18, 8))
        for i, ax in zip(range(2), axes.flat):
            # extract given params
            given_params = reconstruction_params[i]
            ax.set_title(labels[i])
            sns.heatmap(given_params, cmap='Blues_r', alpha=0.65, annot=False, cbar=False, xticklabels=False, yticklabels=False, ax=ax)

        fig.tight_layout()
        plt.show()

        # print("Reconstruction error: {}".format(round(np.sum(np.linalg.norm(data - reconstruction, axis=1)), 2)))

        # plot 2D projection
        if labels:
            to_plot = Y
            if dim != 2:
                to_plot = pca(data, dim= 2, verbose=False)
            plt.figure(figsize=(10, 8))
            plt.title("2D Data Representation")
            sns.scatterplot(x=to_plot[:, 0], y=to_plot[:, 1], hue=class_identity, legend='full', \
                                palette=sns.color_palette('bright', n_colors=len(np.unique(class_identity))))
            plt.show()
        else:
            to_plot = Y
            if dim != 2:
                to_plot = pca(data, dim= 2, verbose=False)
            plt.figure(figsize=(10, 8))
            plt.title("2D Data Representation")
            sns.scatterplot(x=to_plot[:, 0], y=to_plot[:, 1])
            plt.show()

        # Hinton diagram for eigenvalue matrix (slow af though, only use for small matrices)
        if lam.shape[0] < 20:
            hinton(lam)
            plt.show()

    if return_reconstruction is True and reconstruction is not None:
        return Y, reconstruction

    elif return_reconstruction is True:
        reconstruction = Y @ E.T
        return Y, reconstruction

    else:
        return Y

def pca_missing_data(X : np.ndarray, projection_dim: int=2, max_iters: int=100, tol : float=.01, verbose : bool=False):
    assert np.sum(np.isnan(X).astype(int)) > 0, "pca_missing_data should only be called on data with missing values"

    def _fill_nan(X : np.ndarray):
        col_mean = np.nanmean(X, axis=0)

        #Find indicies that you need to replace
        inds = np.where(np.isnan(X))

        #Place column means in the indices. Align the arrays using take
        X[inds] = np.take(col_mean, inds[1])

        return X

    d, n = X.shape
    m = projection_dim
    G = np.isnan(X).astype(int)
    Y = np.zeros((m, n))

    # initialize B as the imputed basis
    X_imputed = _fill_nan(X)
    B_full, _, _ = np.linalg.svd(X_imputed)

    B = B_full[:, :m]

    old_msqerror=np.nan
    errs = []

    for iter in range(max_iters):
        for i in range(n):
            comprow= np.nonzero((G[:, i]==0).astype(int))[0] # complete rows
            Mn = B[comprow,:].T@B[comprow,:]
            cn=B[comprow,:].T@X[comprow][:, i]
            Y[:, i]=np.linalg.pinv(Mn)@cn
        for j in range(d): # update B (basis)
            goodn=np.nonzero((G[j, :]==0).astype(int))[0] #  complete columns
            Yg = Y[:, goodn]
            Fd = Yg@Yg.T
            md=Y[:,goodn]@(X[j][goodn]).T
            B[j,:]=(np.linalg.pinv(Fd)@md).T

        reconstruction = _fill_nan((X-(B@Y)))
        msqerror = np.linalg.norm(reconstruction)
        errs.append(msqerror)

        # convergence testing
        if abs(old_msqerror-msqerror) < tol:
            if verbose is True:
                print("converged after {} iterations".format(iter))
            break

        else:
            old_msqerror = msqerror

    if verbose is True:
        plt.figure(figsize=(18, 8))
        plt.title('reconstruction error versus iteration')
        plt.scatter(np.arange(len(errs)), errs)
        plt.xlabel('iteration')
        plt.ylabel('reconstruction error')
        plt.show()

    return B, Y


import numpy as np
from convexity_check import is_not_concave, is_not_convex

def convex_f(x):
    return x[:,0]**2+x[:,1]**2

def concave_f(x):
    return -x[:,0]**2-x[:,1]**2

def bohachevsky1(x):
    return x[:,0]**2+2*x[:,1]**2-0.3*np.cos(3*np.pi*x[:,0])-0.4*np.cos(4*np.pi*x[:,1])+0.7
def bohachevsky2(x):
    return x[:,0]**2+2*x[:,1]**2-0.3*np.cos(3*np.pi*x[:,0])*np.cos(4*np.pi*x[:,1])+0.3

bounds = np.array([[0,0],[1,1]])
assert is_not_concave(bohachevsky1,2,bounds)
assert is_not_convex(bohachevsky1,2,bounds)
assert is_not_concave(bohachevsky2,2,bounds)
assert is_not_convex(bohachevsky2,2,bounds)
try:
    assert not is_not_convex(convex_f,2,bounds)
except:
    pass
try:
    assert not is_not_concave(concave_f,2,bounds)
except:
    pass


from cmath import sqrt
import numpy as np
np.set_printoptions(suppress=True, linewidth=np.inf, precision=6)
def cholesky():
    S=[[0]*n for i in range(n)]
    for i in range(n):
        for j in range(i + 1):
            tổng = sum(S[k][i] * S[k][j] for k in range(j))
            if abs(tổng - A1[i][i]) == 0: break
            if i == j: S[j][i] = sqrt(A1[i][i] - tổng)
            else: S[j][i] = (A1[j][i] - tổng)/S[j][j]
        if S[i][i] == 0: break
    return S
def cholesky3(): #Hàm giải phương trình BY = E
    Y = np.zeros([n, n],dtype="complex_")
    for i in range(n-1, -1, -1):
        for j in range(i,n):
            if j == i: Y[i,j] = 1/S[i,j]
            if j>i:
                Y[i, j] = (B1[i,j]-sum(S[i][k]*Y[k,j] for k in range(i+1,n)))/S[i][i]
    return Y

#Nhập ma trận
A = np.loadtxt("test2.txt",dtype='complex', delimiter=' ') #Input

k=0
print('The input matrix is:')
print(A)
n = len(A)
B = np.zeros([n,n])
for i in range(n):
    B[i,i] = 1.0
m = 1
for i in range(n):
    for j in range(n):
        if A[i][j] == A[j][i]: continue
        else: m *= 0
if m == 1:
        A1=A
        B1=B
else:
        A1 = A.dot(np.transpose(A))
        B1 = B
        k = 1
S = np.array(cholesky())
if S[n-1][n-1] == 0:
    print('Ma trận A1 có định thức bằng 0 nên không thể khai triển Cholesky')
    quit()
Y = cholesky3()
Y = Y.dot(np.transpose(Y))
print()
print("=============================================================")
print('The inverse matrix is:')
if k == 0:
    print(Y)
if k == 1:
    Y = np.transpose(A).dot(Y)
    print(Y)
print('===============================================================')

Topic 2.5 - Matrix Inversion/Cholevsky/Cholevsky.py


#  ___________________________________________________________________________
#
# introducing the furniture factory problem
# https://www.youtube.com/watch?v=pSm1jONu2G8

# model in pygurobi
# https://www.youtube.com/watch?v=Copxhl2FShg
#  ___________________________________________________________________________

#
# Imports
#
import pyomo.environ as pyo

model = pyo.ConcreteModel()

# decision variables:
# number of chairs
# number of tables
model.c = pyo.Var(domain=pyo.NonNegativeIntegers)
model.t = pyo.Var(domain=pyo.NonNegativeIntegers)
#model.c = pyo.Var(domain=pyo.NonNegativeReals)
#model.t = pyo.Var(domain=pyo.NonNegativeReals)

# maximize the profit
model.OBJ = pyo.Objective(expr = 45*model.c + 80*model.t, sense=pyo.maximize)

# weekly material/wood constraint
model.wood = pyo.Constraint(expr = 5*model.c + 20*model.t <= 400)
# weekly labor constraint
model.labor = pyo.Constraint(expr = 10*model.c + 15*model.t <= 450)

pyo.SolverFactory('glpk').solve(model)

# model.pprint()
print("Profit = ", model.OBJ(), " per week")
print("c = ", model.c(), " chairs per week")
print("t = ", model.t(), " tables per week")


from typing import Optional
import numpy as np
import torch

def generate_origin_position(length:int, d_model:int) -> torch.Tensor:
    """
    Generate positional encoding as original paper
    """
    PE = torch.zeros((length, d_model))

    pos = torch.arange(length).unsqueeze(1)
    PE[:, 0::2] = torch.sin(
        pos / torch.pow(1000, torch.arange(0, d_model, 2, dtype=torch.float32)/d_model))
    PE[:, 1::2] = torch.cos(
        pos / torch.pow(1000, torch.arange(1, d_model, 2, dtype=torch.float32)/d_model))

    return PE

def generate_regular_position(length:int, d_model:int, period: Optional[int] = 24) -> torch.Tensor:
    PE = torch.zeros((length, d_model))

    pos = torch.arange(length, dtype=torch.float32).unsqueeze(1)
    PE = torch.sin(pos * 2 * np.pi / period)
    PE = PE.repeat((1, d_model))

    return PE


#setup: import numpy as np; r = np.arange(1000000, dtype=float)
#run: rosen(r)
import numpy as np

#pythran export rosen(float[])

def rosen(x):
    t0 = 100 * (x[1:] - x[:-1] ** 2) ** 2
    t1 = (1 - x[:-1]) ** 2
    return np.sum(t0 + t1)


import numpy as np
import time

t1 = time.time()
x = np.array([6, 9, 16, 21, 24, 29, 34, 41, 45, 50, 55])
y = np.array([18, 27, 50, 63, 72, 85, 100, 120, 135, 150, 165])

def cost(y_prediction, y):
    return (1 / (2 * y.__len__())) * np.sum((y_prediction - y) ** 2)

result = [100]
minimumCostResult = 0
w_best_param = 0
b_best_param = 0
y_prediction = 0
w_param = [i / 1000 for i in range(2900, 3000)]
b_param = [i / 1000 for i in range(0, 1000)]
for w in w_param:
    for b in b_param:
        y_pred = w * x.T + b
        costResult = cost(y_pred, y)
        if costResult < min(result):
            minimumCostResult = costResult
            w_best_param = w
            b_best_param = b
            y_prediction = y_pred
        result.append(costResult)

print(f"minimum cost result: {minimumCostResult}")
print(f"best w param: {w_best_param}")
print(f"best b param: {b_best_param}")
print(f"Y best prediction values:\n {y_prediction}")
print(f"Y real values:\n {y}")

t2 = time.time()
print(f"Execution time: {t2-t1}")


#minimizing scalar func of vector argument

import numpy as np
import scipy as sp
from copy import deepcopy

def func(x):
    y = 0
    for i in range(x.shape[0]):
        for j in range(x.shape[0]):
            if i == j:
                y += x[i] ** 2
            else:
                y += 2 * x[i] * x[j]
    return y

def fGrad(x, f, step=0.001):
    grad = np.zeros(x.shape)
    for i in range(x.shape[0]):
        partDx = deepcopy(x)
        partDx[i] = x[i] + step
        grad[i] = f(partDx) - f(x)
        grad[i] = grad[i] / step
    return grad

def gradStep(x,f, lr=0.001):
    grad = fGrad(x, f)
    nextX = x - lr * x * (grad / np.linalg.norm(grad))
    return nextX

eps = 0.00000001
x = np.random.random(5)
prevX = np.random.rand(x.shape[0])
while abs(func(x) - func(prevX)) > eps:
    print("x = {} | y = {}".format(x, func(x)))
    prevX = x
    x = gradStep(x, func)


# Lanchester War Model Solutions
# The following program plots the size of two armies following the Lanchester Model of warfare.
# It takes input parameters g, r, and y0, which are the "force multipliers" of the two armies,
# and the initial size of the second army. Then it calculates the minimum size needed for the
# first army to win. Further, it displays the time at which the second army will die out if the
# initial condition for the first army is met.

from numpy import *
from scipy import integrate
from matplotlib.pyplot import *

g = 0.45
r = 0.46
y0 = 100.
x0 = np.ceil(np.sqrt(g/r)* y0)

ic = array([x0, y0])
c1 = (0.5)*(ic[0] - (g*ic[1] / np.sqrt(g*r)))
c2 = (0.5)*(ic[0] + (g*ic[1] / np.sqrt(g*r)))
t_int = log(c2/c1)/(2*sqrt(g*r))
t = linspace(0, t_int*1.3, 365)

def f(X, t):
    return array([ -g*X[1], -r*X[0] ])

x = integrate.odeint(f, ic, t)

plot(t, x[:,0], 'b-', linewidth=2, label = 'Army A')
plot(t, x[:,1], 'r-', linewidth=2, label = 'Army B')
xlabel('Time', fontsize = 'large')
ylabel('Army Size', fontsize = 'large')
ylim(0,max(ic[0], ic[1]))
xlim(0, t_int*1.3)
title('Lanchester War Model')
legend(loc = 'best')
savefig('War.png')
show()

print("Army B dies out at time: ", t_int)


"""
demo03_normalization.py  归一化（正则化）
"""
import numpy as np
import sklearn.preprocessing as sp

samples = np.array([[17., 100., 4000.],
					[20., 80., 5000.],
					[23., 60., 5500.]])

r_samples = sp.normalize(samples, norm='l1')
print(r_samples)


import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)
mu = [0, 0]
sigma = [[5, 4], [4, 5]]
n = 1000
x = np.random.multivariate_normal(mu, sigma, size=n).T

set1 = np.argsort(np.linalg.norm(x, axis=0))[-20:]
set2 = list(set(range(n)) - set(set1))

fig, ax = plt.subplots()
ax.scatter(x[0, set1], x[1, set1], s=20, c="red", alpha=0.2)
ax.scatter(x[0, set2], x[1, set2], s=20, alpha=0.2)
ax.set_aspect("equal")
ax.set_xlim(-8, 8)
ax.set_ylim(-8, 8)
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.set_title("Original")
# plt.show()
print(np.corrcoef(x)[0, 1])
# 0.8020186259500502

sigma = np.cov(x)
# [4.07635286 5.19821674]]
evals, evecs = np.linalg.eigh(sigma)
# [1.00594615 9.16185704]
# [[-0.71694925  0.69712536]
#  [ 0.69712536  0.71694925]]

# PCA
z = np.diag(evals ** (-1 / 2)) @ evecs.T @ x
fig, ax = plt.subplots()
ax.scatter(z[0, set1], z[1, set1], s=20, c="red", alpha=0.2)
ax.scatter(z[0, set2], z[1, set2], s=20, alpha=0.2)
ax.set_aspect("equal")
ax.set_xlim(-8, 8)
ax.set_ylim(-8, 8)
ax.set_xlabel("$z_1$")
ax.set_ylabel("$z_2$")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.set_title("PCA")

# ZCA
z = evecs @ np.diag(evals**(-1/2)) @ evecs.T @ x
fig, ax = plt.subplots()
ax.scatter(z[0, set1], z[1, set1], s=20, c="red", alpha=0.2)
ax.scatter(z[0, set2], z[1, set2], s=20, alpha=0.2)
ax.set_aspect("equal")
ax.set_xlim(-8, 8)
ax.set_ylim(-8, 8)
ax.set_xlabel("$z_1$")
ax.set_ylabel("$z_2$")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.set_title("ZCA")
plt.show()


import numpy as np
import numba

n = 12

x, _ = np.polynomial.chebyshev.chebgauss(n)
V = np.polynomial.chebyshev.chebvander(x, n-1)
a = np.exp(np.sin(x))
b = np.cos(x)*a
c = np.linalg.solve(V, a)

def chebeval1(x, c):
    x2 = 2*x
    c0 = c[-2]
    c1 = c[-1]
    for i in range(3, len(c) + 1):
        tmp = c0
        c0 = c[-i] - c1
        c1 = tmp + c1*x2
    return c0 + c1*x

# get derivative by differentiating series and evaluating sum
cp = np.polynomial.chebyshev.chebder(c)
d = np.zeros(n)
for i in range(n):
    d[i] = chebeval1(x[i], cp)
print('Standard way error:  {:0.2e}'.format(np.abs(b-d).max()))

def chebeval_d1(x, c):
    x2 = 2*x
    c0 = c[-2] + x2*c[-1]
    c1 = c[-1]
    d0 = 2*c[-1]
    d1 = 0.0
    for i in range(3, len(c)):
        # recursion for d
        dm = 2*c0 + x2*d0 - d1
        d1 = d0
        d0 = dm
        # recursion for c
        cm = c[-i] + x2*c0 - c1
        c1 = c0
        c0 = cm
    return c0 + x*d0 - d1

# get derivative by using direct summation
d = np.zeros(n)
for i in range(n):
    d[i] = chebeval_d1(x[i], c)
print('New way error grad:  {:0.2e}'.format(np.abs(b-d).max()))


import numpy as np
from abc import ABC, abstractmethod

class AbstractCost(ABC):
  @abstractmethod
  def loss(self, predict: np.array, target: np.array) -> float:
    raise NotImplementedError

  @abstractmethod
  def gradient(self, predict: np.array, target: np.array) -> np.array:
    raise NotImplementedError

class MeanSquareError(AbstractCost):
  def loss(self, predict: np.array, target: np.array) -> np.array:
    return (1/2) * np.sum((target - predict) ** 2) / len(target)

  def gradient(self, predict: np.array, target: np.array) -> np.array:
    return -1 * (target - predict)

class CrossEntropyCost(AbstractCost):
  def __init__(self, limit=1e-15):
    self.limit = limit

  def loss(self, predict: np.array, target: np.array) -> np.array:
    clipped_predict = np.clip(predict, limit, 1 - limit)
    return -1 * np.sum(target * np.log(clipped_predict)) / len(target)

  def gradient(self, predict: np.array, target: np.array) -> np.array:
    clipped_predict = np.clip(predict, limit, 1 - limit)
    return -1 * (target / clipped_predict)

class BinaryCrossEntropyCost(AbstractCost):
  def __init__(self, limit=1e-15):
    self.limit = limit

  def loss(self, predict: np.array, target: np.array) -> np.array:
    clipped_predict = np.clip(predict, self.limit, 1 - self.limit)
    return -1 * np.sum(target * np.log(clipped_predict) + (1 - target) * np.log(1 - clipped_predict)) / len(target)

  def gradient(self, predict: np.array, target: np.array) -> np.array:
    clipped_predict = np.clip(predict, self.limit, 1 - self.limit)
    return -1 * ((target / clipped_predict) - ((1 - target) / (1 - clipped_predict)))


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

def init_domain():
	#Solution domain
	global nx,ny,dx,dy,dt,alpha,ft
	nx = 512
	ny = 512

	#Cell sizes
	dx = 2.0*np.pi/float(nx)
	dy = 2.0*np.pi/float(ny)

	#Indices
	index_range = np.arange(0,nx+2)
	x, y = np.meshgrid(dx*index_range-dx,dy*index_range-dy)

	#diffusion parameter
	alpha = 0.8
	#Stable timestep
	dt = 0.8*dx*dx/(4.0*alpha)

	#Initialize
	u = np.sin(x+y)

	#length of solution
	ft = 1.0

	return u,x,y

def plot_field(x,y,u,title):
	#levels = np.linspace(-1, 1, 20)
	fig, ax = plt.subplots(nrows=1,ncols=1)
	ax.set_title(title)
	p1 = ax.contourf(x,y,u)
	plt.colorbar(p1,ax=ax)#,format="%.2f"
	plt.show()

def vectorize_ftcs_1(u):

	global dx,dy,dt,alpha,ft
	nt = int(ft/dt)
	const_mult = alpha*dt/(dx*dx)

	#Finite difference coefficients
	i,j = np.meshgrid(np.arange(1,nx+1),np.arange(1,ny+1))
	ip1,jp1 = np.meshgrid(np.arange(2,nx+2),np.arange(2,ny+2))
	im1,jm1 = np.meshgrid(np.arange(0,nx),np.arange(0,ny))

	#Indices for BC update - x direction
	i1,j1 = np.meshgrid(np.arange(0,1),np.arange(1,ny+1))
	i2,j2 = np.meshgrid(np.arange(nx,nx+1),np.arange(1,ny+1))

	i3,j3 = np.meshgrid(np.arange(1,2),np.arange(1,ny+1))
	i4,j4 = np.meshgrid(np.arange(nx+1,nx+2),np.arange(1,ny+1))

	i5,j5 = np.meshgrid(np.arange(0,nx+2),np.arange(0,1))
	i6,j6 = np.meshgrid(np.arange(0,nx+2),np.arange(ny,ny+1))

	i7,j7 = np.meshgrid(np.arange(0,nx+2),np.arange(1,2))
	i8,j8 = np.meshgrid(np.arange(0,nx+2),np.arange(ny+1,ny+2))

	t = 0
	while t<nt:
		t = t+1
		utemp = np.copy(u)
		u[i,j] = utemp[i,j] + const_mult*(-4.0*utemp[i,j]+(utemp[im1,j]+utemp[ip1,j]+utemp[i,jm1]+utemp[i,jp1]))

		#Update BCS
		#Need to update BCs - x direction
		u[i1,j1] = u[i2,j2]
		u[i4,j4] = u[i3,j3]

		#Need to update BCs - y direction
		u[i5,j5] = u[i6,j6]
		u[i8,j8] = u[i7,j7]

		del(utemp)

	return u

def vectorize_ftcs_2(u):

	global dx,dy,dt,alpha,ft
	nt = int(ft/dt)
	const_mult = alpha*dt/(dx*dx)

	t = 0
	while t<nt:
		t = t+1
		utemp = np.copy(u)
		u[1:nx+1,1:ny+1] = utemp[1:nx+1,1:ny+1] + const_mult*(-4.0*utemp[1:nx+1,1:ny+1]+(utemp[0:nx,1:ny+1]+
							utemp[2:nx+2,1:ny+1]+utemp[1:nx+1,0:ny]+utemp[1:nx+1,2:ny+2]))

		#Update BCS
		#Need to update BCs - x direction
		u[0:1,1:ny+1] = u[nx:nx+1,1:ny+1]
		u[nx+1:nx+2,1:ny+1] = u[1:2,1:ny+1]

		#Need to update BCs - y direction
		u[0:nx+2,0:1] = u[0:nx+2,ny:ny+1]
		u[0:nx+2,ny+1:ny+2] = u[0:nx+2,1:2]

		del(utemp)

	return u

def loop_ftcs(u):

	global dx,dy,dt,alpha,ft
	nt = int(ft/dt)
	const_mult = alpha*dt/(dx*dx)

	t = 0
	while t<nt:
		t = t+1
		utemp = np.copy(u)

		#FTCS timestep
		for i in range(1,nx+1):
			for j in range(1,ny+1):
				u[i,j] = utemp[i,j] + const_mult*(-4.0*utemp[i,j]+(utemp[i-1,j]+utemp[i+1,j]+utemp[i,j-1]+utemp[i,j+1]))

		#Periodic boundary condition update
		for j in range(1,ny+1):
			u[0,j] = u[nx,j]
			u[nx+1,j] = u[1,j]

		for i in range(0,nx+2):
			u[i,0] = u[i,ny]
			u[i,ny+1] = u[i,1]

		del(utemp)

	return u

if __name__ == '__main__':

	global nx,ny,dx,dy,dt,alpha,ft
	uv, x, y = init_domain()
	plot_field(x,y,uv,'Initial Condition')

	t1 = time.time()
	uv = vectorize_ftcs_2(uv)
	print('CPU time taken for vectorized FTCS: ',time.time()-t1)
	plot_field(x,y,uv,'Final solution - vectorized FTCS')

	ul, x, y = init_domain()
	plot_field(x,y,ul,'Initial Condition')
	t1 = time.time()
	ul = loop_ftcs(ul)
	print('CPU time taken for for loop based FTCS: ',time.time()-t1)
	plot_field(x,y,ul,'Final solution - for loop based FTCS')

	plot_field(x,y,np.abs(ul-uv),'L1-norm difference (for loop and vectorized)')


# Question 2 Lab Assignment 03
# @AB Satyaprakash, 180123062

# imports
from math import exp, sqrt
import numpy as np
import time

# Initialising a dictionary -- C++ equivalent to map<>
Map = {}
# functions ---------------------------------------------------------------------------

def recursion(n, Smax, S, T, r, sig, M, u, d, p, q, dt):
    if (Smax, S) in Map:
        return Map[(Smax, S)]

    if n == M:
        Map[(Smax, S)] = Smax - S
        return Smax - S

    up = recursion(n + 1, max(Smax, S * u), S * u, T, r, sig, M, u, d, p, q, dt)
    dn = recursion(n + 1, max(Smax, S * d), S * d, T, r, sig, M, u, d, p, q, dt)
    pc = (exp(-r * dt)) * (p * up + q * dn)
    Map[(Smax, S)] = pc
    return pc

# -------------------------------------------------------------------------------------
# Given Initial Values
S0, T, r, sig = 100, 1, 0.08, 0.2
# M takes values [5, 10, 25, 50] -- we'll consider all of them here
Mlist = [5, 10, 25, 50]

for M in Mlist:
    dt = T/M

    u = exp(sig*sqrt(dt)+(r-sig*sig/2)*dt)
    d = exp(-sig*sqrt(dt)+(r-sig*sig/2)*dt)
    p = (exp(r*dt)-d)/(u-d)
    q = 1-p
    Map.clear()
    loopbackOptionPrice = recursion(0, S0, S0, T, r, sig, M, u, d, p, q, dt)
    print('The initial loopback option price for M = {} is {}'.format(M, loopbackOptionPrice))

# Test computation time for M = 15: ------------------------------------------------
dt = T/M

u = exp(sig*sqrt(dt)+(r-sig*sig/2)*dt)
d = exp(-sig*sqrt(dt)+(r-sig*sig/2)*dt)
p = (exp(r*dt)-d)/(u-d)
q = 1-p
Map.clear()
start = time.time()
timeTempPrice = recursion(0, S0, S0, T, r, sig, 15, u, d, p, q, dt)
end = time.time()

print('Computational time for M = 15 is {}s'.format(end-start))

# Question 2 ends ---------------------------------------------------------------------

Semester 6/MA 374 (Financial Engg. Lab)/Lab 3/180123062_AB_q2.py


import numpy

def partition(list, p):
    l =0
    r = len(list)

    #list = list.copy()
    list[p], list[l] = list[l], list[p]
    i = l + 1
    for j in range(l + 1, r):
        #c[0] += 1

        if list[j] < list[l]:
            list[i], list[j] = list[j], list[i]
            i += 1
    list[i - 1], list[l] = list[l], list[i - 1]
    #return the new position of pivot
    return i - 1, list[l: i - 1], list[i: r]

def choose_pivot(list):
    #choose the pivot randomly
    l = 0
    r = len(list)
    #p = randint(l, r)
    #print(p)

    p1 = l
    p3 = r - 1
    p2 = (l + r - 1)//2

    #print(p1, p2, p3)

    med = int(numpy.median([list[p1], list[p2], list[p3]]))
    for i in [p1, p2, p3]:
        if list[i] == med:
            break
    return i

def rand_select(list, i):

    if len(list) == 1:
        return list[0]

    p = choose_pivot(list)
    p, list_l, list_r = partition(list, p)
    #print(p, list_l, list_r)

    if p == i:
        return list[p]
    elif p < i:
        return rand_select(list_r, i - p - 1)
    else:
        return rand_select(list_l, i)

if __name__ == "__main__":
    list = [7,6,5,4,3,2,1,0]
    i = rand_select(list.copy(), 5)
    print(i)
    print(list)


import numpy as np
import matplotlib.pyplot as plt

def softmax_overflow(a):
    ''' Thissoftmax will cause overflow
    '''
    #輸入訊號的指數
    exp = np.exp(a)

    #輸入訊號的指數函數和
    sum_exp = np.sum(exp)

    y = exp/sum_exp
    return y

def softmax(a):

    #1. Set a constantant, which is the max value from input values
    #2. Set the new inut as a-c to avoid overflow
    c = np.max(a)
    a_new = a - c

    #輸入訊號的指數
    exp = np.exp(a_new)

    #輸入訊號的指數函數和
    sum_exp = np.sum(exp)

    y = exp/sum_exp
    return y

if __name__ == '__main__':
    a = np.array([.3,2.9,4.0])
    # a = np.array([1000,2000,3000])

    y =softmax(a)
    print(y)
    print(np.sum(y))


from __future__ import print_function
import numpy as np

# Python version of the IDL script
# Bryan Miller

def randomp(pow,n,range_x=[5.,100.]):
# NAME:
#       RANDOMP
# PURPOSE:
#       Generates an array of random numbers distributed as a power law.
# CALLING SEQUENCE:
#       RANDOMP(Pow, N, [ RANGE_X = [low,high]])'
# INPUTS:
#       Pow:  Exponent of power law.
#               The pdf of X is f_X(x) = A*x^pow, low <= x <= high
#               ASTRONOMERS PLEASE NOTE:
#               pow is little gamma  = big gamma - 1 for stellar IMFs.
#       N:    Number of elements in generated vector.
#
# OPTIONAL INPUT KEYWORD PARAMETER:
#       RANGE_X:  2-element vector [low,high] specifying the range of
#               output X values# the default is [5, 100].
#
# OUTPUTS:
#       X:    Vector of random numbers, distributed as a power law between
#               specified range
# PROCEDURE:
#       "Transformation Method" for random variables is described in Bevington
#       & Robinson, "Data Reduction & Error Analysis for Physical Sciences", 2nd
#       Edition (McGraw-Hill, 1992). p. 83.
#       Output of RANDOMU function is transformed to power-law
#       random variable.
#
# EXAMPLE:
#       Create a stellar initial mass function (IMF) with 10000 stars
#       ranging from 0.5 to 100 solar masses and a Salpeter slope.  Enter:
#
#       MASS = RANDOMP(-2.35,10000,RANGE_X=[0.5,100])
#
# NOTES:
#       Versions 5.1.1 and V5.2 of IDL have a bug in RANDOMU such that the SEED
#       value is initialized to the same value at the start of each session,
#       rather than being initialized by the system clock.    RANDOMP will be
#       affected in a similar manner.
# MODIFICATION HISTORY:
#       Written by R. S. Hill, Hughes STX, July 13, 1995
#       July 14, 1995   SEED keyword added at Landsman's suggestion.
#                    Documentation converted to standard format.  RSH
#       Converted to IDL V5.0   W. Landsman   September 1997
#       Converted to python     B. Miller     October 2014
#-

    if len(range_x) != 2:
        print ('Error - RANGE_X keyword must be a 2 element vector')
        return

    pow1 = pow + 1.0

    lo = range_x[0]
    hi = range_x[1]
    if lo > hi:
        temp=lo
        lo=hi
        hi=tmp

    r = np.random.random( n )
    if pow != -1.0:
        norm = 1.0/(hi**pow1 - lo**pow1)
        expo = np.log10(r/norm + lo**pow1)/pow1
        x = 10.0**expo
    else:
        norm = 1.0/(np.log(hi) - np.log(lo))
        x = np.exp(r/norm + np.log(lo))

    return x


import numpy as np
from scipy.spatial.distance import cdist

class KMeans:
    def __init__(
            self,
            k: int,
            metric: str = "euclidean",
            tol: float = 1e-6,
            max_iter: int = 100):
        """
        inputs:
            k: int
                the number of centroids to use in cluster fitting
            metric: str
                the name of the distance metric to use
            tol: float
                the minimum error tolerance from previous error during optimization to quit the model fit
            max_iter: int
                the maximum number of iterations before quitting model fit
        """
        self._k = k
        self._metric = metric
        self._tol = tol
        self._max_iter = max_iter

    def fit(self, mat: np.ndarray):
        """
        fits the kmeans algorithm onto a provided 2D matrix

        inputs:
            mat: np.ndarray
                A 2D matrix where the rows are observations and columns are features
        """
        obs = mat.shape[0]
        feats = mat.shape[1]

        if self._k > obs:
            raise ValueError(f"There must be more data points than clusters. You passed {obs} data points and {self._k}"
                             f"clusters.")

        if self._k < 1:
            raise ValueError("You must pass at least 1 cluster.")

        labels = np.zeros(obs)
        mat_min, mat_max = np.min(mat), np.max(mat)
        self.centers = np.random.uniform(mat_min, mat_max, size=(self._k, feats))
        prev = np.inf*np.ones((self._k, feats))
        self.mse = np.inf

        num_iter = 1
        while not self.mse < self._tol:
            if num_iter > self._max_iter:
                print("Max iter exceeded before convergence")
                break

            else:

                # update data assignments to closest centroid
                labels = self._assign_points_to_labels(mat)

                # update centeroid to be average of assigned data
                prev = self.centers.copy()
                for c in range(self._k):
                    closest_data = mat[labels == c]
                    if closest_data.shape[0] == 0: # no data points assigned to this centroid
                        self.centers[c] = np.random.uniform(mat_min, mat_max, size=(1, feats)) # try moving to new spot
                    else: # take the average value for each component assigned to this centroid
                        self.centers[c] = np.mean(closest_data, axis=0)

                num_iter += 1

            self.mse = self._calculate_mse(self.centers, prev)

    def predict(self, mat: np.ndarray) -> np.ndarray:
        """
        predicts the cluster labels for a provided 2D matrix

        inputs:
            mat: np.ndarray
                A 2D matrix where the rows are observations and columns are features

        outputs:
            np.ndarray
                a 1D array with the cluster label for each of the observations in `mat`
        """
        return self._assign_points_to_labels(mat)

    def get_error(self) -> float:
        """
        returns the final squared-mean error of the fit model

        outputs:
            float
                the squared-mean error of the fit model
        """
        return self.mse

    def get_centroids(self) -> np.ndarray:
        """
        returns the centroid locations of the fit model

        outputs:
            np.ndarray
                a `k x m` 2D matrix representing the cluster centroids of the fit model
        """
        return self.centers

    def _calculate_mse(self, data: np.array, centroids: np.array) -> float:
        """
        Calculate mean-squared error on fit model given training data.

        inputs:
            data: np.ndarray
                A 2D data matrix where the rows are observations and columns are features
            centroids: np.ndarray
                A 2D centroid location matrix where the rows are observations and columns are features

        returns:
            np.ndarray
                MSE between data and centroids
        """
        # get the distance between each point and its centroid, square it, take average across all point-centroid pairs
        return np.average(np.square(np.diag(cdist(data, centroids, metric=self._metric))))

    def _assign_points_to_labels(self, mat: np.array) -> np.array:
        """
        Given data stored in mat (and centers from `self.centers`), assign each point in `mat` to a center.

        inputs:
            mat: np.ndarray
                A 2D matrix where the rows are observations and columns are features

        returns:
            np.array
                array assigning each data point in `mat` to a center, it is of shape (mat.shape[0], self._k)
        """
        data_centers_dist = cdist(mat, self.centers, metric=self._metric)
        return np.argmin(data_centers_dist, axis=1)


from PIL import Image
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
from pylab import *
import matplotlib.pyplot as plt
from matplotlib import animation
import numpy as np
from numpy import interp
from math import pi
from scipy.integrate import quad

def create_close_loop(image_name, level=[200]):
    fig, ax = plt.subplots(1, 2, figsize=(10, 5))
    ax[0].set_aspect('equal', 'datalim')
    ax[1].set_aspect('equal', 'datalim')
    ax[0].set_title('Before Centered')
    ax[1].set_title('After Centered')
    a = image_name.split(".")[0]

    if image_name.lower().endswith(('.svg')):
        drawing = svg2rlg(image_name)

        renderPM.drawToFile(drawing, "%s.png"%(a), fmt="PNG")
        im = array(Image.open("%s.png"%(a)).convert('L'))
    else:
        im = array(Image.open(image_name).convert('L'))
    contour_plot = ax[0].contour(im, levels=level, colors='black', origin='image')

    contour_path = contour_plot.collections[0].get_paths()[0]
    x_table, y_table = contour_path.vertices[:, 0], contour_path.vertices[:, 1]
    time_table = np.linspace(0, 2*pi, len(x_table))

    x_table = x_table - min(x_table)
    y_table = y_table - min(y_table)
    x_table = x_table - max(x_table) / 2
    y_table = y_table - max(y_table) / 2

    ax[1].plot(x_table, y_table, c='blue')

    return time_table, x_table, y_table

def f(t, time_table, x_table, y_table):
    return interp(t, time_table, x_table) + 1j*interp(t, time_table, y_table)

def DFT(t, coef_list):
    order=200
    kernel = np.array([np.exp(-n*1j*t) for n in range(-order, order+1)])
    series = np.sum( (coef_list[:,0]+1j*coef_list[:,1]) * kernel[:])
    return np.real(series), np.imag(series)

def coef_list(time_table, x_table, y_table):
    order=200;coef_list = []
    for n in range(-order, order+1):
        real_coef = quad(lambda t: np.real(f(t, time_table, x_table, y_table) * np.exp(-n*1j*t)), 0, 2*pi, limit=100, full_output=1)[0]/(2*pi)
        imag_coef = quad(lambda t: np.imag(f(t, time_table, x_table, y_table) * np.exp(-n*1j*t)), 0, 2*pi, limit=100, full_output=1)[0]/(2*pi)
        coef_list.append([real_coef, imag_coef])
    return np.array(coef_list)

def visualize(x_DFT, y_DFT, coef, space, fig_lim,title):
    order=200
    fig, ax = plt.subplots()
    lim = max(fig_lim)
    ax.set_xlim([-lim, lim])
    ax.set_ylim([-lim, lim])
    plt.title(r'%s($_{Rousan}$)'%(title))
    ax.set_aspect('equal')

    line = plt.plot([], [], c='blue', linewidth=1.5)[0]

    radius = [plt.plot([], [],c='green', linewidth=0.5, marker='o', markersize=1)[0] for _ in range(2 * order + 1)]
    circles = [plt.plot([], [], 'r-', linewidth=0.5)[0] for _ in range(2 * order + 1)]

    def update_c(c, t):
        new_c = []
        for i, j in enumerate(range(-order, order + 1)):
            dtheta = -j * t
            ct, st = np.cos(dtheta), np.sin(dtheta)
            v = [ct * c[i][0] - st * c[i][1], st * c[i][0] + ct * c[i][1]]
            new_c.append(v)
        return np.array(new_c)

    def sort_velocity(order):
        idx = []
        for i in range(1,order+1):
            idx.extend([order+i, order-i])
        return idx

    def animate(i):
        line.set_data(x_DFT[:i], y_DFT[:i])
        r = [np.linalg.norm(coef[j]) for j in range(len(coef))]
        pos = coef[order]
        c = update_c(coef, i / len(space) * 2*pi)
        idx = sort_velocity(order)
        for j, rad, circle in zip(idx,radius,circles):
            new_pos = pos + c[j]
            rad.set_data([pos[0], new_pos[0]], [pos[1], new_pos[1]])
            theta = np.linspace(0, 2*pi, 50)
            x, y = r[j] * np.cos(theta) + pos[0], r[j] * np.sin(theta) + pos[1]
            circle.set_data(x, y)
            pos = new_pos

    ani = animation.FuncAnimation(fig, animate, frames=len(space), interval=7)
    return ani


import math
def calculate(x,y):
    n = len(x)
    #计算 x的平均数
    x_sum = 0
    for x_j in x:
        x_sum = x_sum + x_j
    x_arrange = x_sum / n
    #计算 y的平均数
    y_sum = 0
    for y_j in y:
        y_sum = y_sum + y_j
    y_arrange = y_sum / n
    #
    i = 0
    xiyi_sum = 0
    xi_square_sum = 0
    yi_square_sum = 0
    while i < n:
        xiyi_sum = xiyi_sum + x[i]*y[i]
        xi_square_sum = xi_square_sum + x[i]**2
        yi_square_sum = yi_square_sum + y[i]**2
        i = i + 1
    #计算分子与分母，以及 b,a,r
    numerator = xiyi_sum - n*x_arrange*y_arrange
    denominator_1 = xi_square_sum - n*pow(x_arrange,2)
    denominator_2 = math.sqrt(denominator_1 * (yi_square_sum - n*pow(y_arrange,2)))
    b = numerator / denominator_1
    a = y_arrange - b*x_arrange
    r = numerator / denominator_2
    #
    return [x_arrange,y_arrange,xiyi_sum,xi_square_sum,numerator,denominator_1,denominator_2,b,a,r]

def predict():
    print("预测(多个数用空格隔开)：")
    x_input = input("x = ")
    x_input = [float(n) for n in x_input.split()]
    y_output = []
    for x_in in x_input:
        y_out = b*x_in + a
        y_output.append(y_out)
    print("y = "+str(y_output))
    print("\n===========================\n")
    return [x_input,y_output]

def draw():
    import matplotlib.pyplot as plt
    import numpy as np
    #画散点图
    plt.scatter(x,y,s=25,color="blue",label="Raw")
    plt.scatter(results_predict[0],results_predict[1],s=35,color="red",marker="^",label="Predict")
    #画直线
    #合并原始数据，预测数据两个数组作为 x轴（变量名 x_s）
    x_s = x +results_predict[0]
    #用 np.arange 生成自变量范围：x轴中最小值-3 到 x轴中最大值+3，步长：1
    xdata = np.arange(min(x_s)-3,max(x_s)+3,1)
    ydata = b*xdata + a #回归方程
    plt.plot(xdata,ydata,color="green")
    # 设置图表标题， 并给坐标轴加上标签
    plt.title("Title", fontsize=24)
    plt.xlabel("x-value", fontsize=14)
    plt.ylabel("y-value", fontsize=14)
    plt.legend(loc="best") # 设置图例位置
    plt.savefig("./result.png")
    plt.show()

#定义原始数据
x = [1,2,3,4,5,6,8]
y = [-5,-7,-6,-9,-12,-11,-15]
#调用 “计算”，接受返回参数
results = calculate(x,y)
b = results[7]
a = results[8]
r = results[9]
#输出信息
print("===========================\n")
print("x = "+str(x))
print("y = "+str(y))
print("x_arrange= "+str(results[0]))
print("y_arrange= "+str(results[1]))
'''
print("xiyi_sum= "+str(results[2]))
print("xi_square_sum= "+str(results[3]))
print("numerator= "+str(results[4]))
print("denominator_1 = "+str(results[5]))
print("denominator_2 = "+str(results[6]))
'''
if a >= 0:
    print("\ny = "+str(b)+"x + "+str(a))
else:
    print("\ny = "+str(b)+"x "+str(a))
print("r = "+str(r))
print("\n===========================\n")
#调用 “预测”
results_predict = predict()
#交互 是否作图
c = input("是否作图？(y/n)：")
if c == "y" or c == "Y":
    print("\n开始作图……")
    draw()
else:
    print("\n跳过作图\n")
#
print("\n===========================\n")
print("运行完毕")


from sympy import isprime

def __gcd(x,y):
    if x == 0:
        return y
    if x > y:
        return __gcd(y,x)
    return __gcd(y%x, x)

def is_coprime(x, y):
    return __gcd(x,y) == 1

def get_f(n):
    f = []
    i = 2
    while i*i <= n:
        if n % i == 0 and isprime(i):
            f.append(i)
            while n % i == 0:
                n = n / i
        if i == 2 :
            i += 1
        else:
            i += 2
    if n != 1:
        f.append(n)
    return f

max_num = 1000000
found = False
maxim = 0

for i in range(2, max_num + 1):
    factors = get_f(i)
    s = set(range(1, i+1))
    for num in s.copy():
        for f in factors:
            if num % f == 0:
                s.discard(num)
                break
    n_cp = len(s)
    if not found or maxim < i / n_cp:
        maxim = i/n_cp
        found = True

print(maxim)


import numpy as np
import matplotlib.pyplot as plt

def cart2pol(x, y):
    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)
    return(rho, phi)

def pol2cart(rho, phi):
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    return(x, y)

def sum2(x, y):
	return tuple(map(sum, zip(x,y)))

def sum3(x, y, z):
	return tuple(map(sum, zip(x,y, z)))

def mag(x, y):
	return(np.sqrt(x**2+y**2))

def acc(x, y):
	return(-x/mag(x,y)**3, -y/mag(x,y)**3)

def int_q(q1,q2,v1,v2,t):
	q3 = q1 + t*v1
	q4 = q2 + t*v2
	return(q3,q4)

def int_v(q1,q2,v1,v2,t):
	v3 = v1 + t*acc(q1,q2)[0]
	v4 = v2 + t*acc(q1,q2)[1]
	return(v3,v4)

################################
#initial conditions

x_0 = 10
y_0 = 0
v_int = 1/10

r_0 = [(x_0, y_0)]
v_0 = [(0, v_int)]

r = r_0
v = v_0

h = x_0*v_int
p = h**2
E_0 = .5*v_int**2-1/x_0
a = -1/(2*E_0)
e = (1-p/a)**.5
P = 2*np.pi*a**(3/2)
t = P/1000
s = 2**(1/3)
H = t/(2-s)

##############################################
#Fourth-Order Forest Ruth
x_0 = 10
y_0 = -50
v_int = 1/10

r_0 = [(x_0, 0)]
v_0 = [(0, v_int)]

r = r_0
v = v_0
A_x = []
A_y = []

for i in range(0,int(P*100)):
	v_n = np.asarray(v[len(v)-1])
	r_n = np.asarray(r[len(r)-1])

	r_n = int_q(r_n[0],r_n[1], v_n[0], v_n[1], H/2)
	v_n = int_v(r_n[0],r_n[1], v_n[0], v_n[1], H)
	r_n = int_q(r_n[0],r_n[1], v_n[0], v_n[1], H/2*(1-s))
	v_n = int_v(r_n[0],r_n[1], v_n[0], v_n[1], -s*H)

	r_n = int_q(r_n[0],r_n[1], v_n[0], v_n[1], H/2*(1-s))
	v_n = int_v(r_n[0],r_n[1], v_n[0], v_n[1], H)
	r_n = int_q(r_n[0],r_n[1], v_n[0], v_n[1], H/2)

	A_x_add = v_n[1]*(r_n[0]*v_n[1]-v_n[0]*r_n[1])-r_n[0]/mag(r_n[0],r_n[1])
	A_y_add = v_n[0]*(r_n[1]*v_n[0]-v_n[1]*r_n[0])-r_n[1]/mag(r_n[0],r_n[1])

	# print(A_x_add, A_y_add)
	# print(A_x, A_y)

	r.append(r_n)
	v.append(v_n)
	A_x.append(A_x_add)
	A_y.append(A_y_add)

r = np.asarray(r)
l = []

# for i in r:
	# l.append(cart2pol(i[0],i[1]))

x_val = [x[0] for x in r]
y_val = [x[1] for x in r]

###################################################
#Graphing

fig1, ax3 = plt.subplots()
# ax3=fig1.add_subplot(111, projection='polar')
# ax3=fig1.add_subplot(111)
ax3.plot(y_val,x_val)
# ax3.plot(theta_comp, r_comp, 'o', markerfacecolor='none', markeredgecolor='r')
# ax3.set_rmax(.5)
# ax3.set_rticks([3, 6, 9, 12])  # less radial ticks
# ax3.set_rlabel_position(-22.5)  # get radial labels away from plotted line
# ax3.grid(True)
ax3.set_title("Forest Ruth", va='bottom')
# plt.show()

###################################################
#Forest Ruth Energy

r_mag = []
v_mag = []
E_t = []
time = []
timePeriod = []
E_rat = []

for i in r:
	r_mag.append((i[0]**2+i[1]**2)**.5)
for i in v:
	v_mag.append((i[0]**2+i[1]**2)**.5)
for i in range(len(r_mag)):
	E_t.append(.5*v_mag[i]**2-1/r_mag[i])
for i in range(0,int(P*100)+1):
	x = i*t
	time.append(x)
for i in time:
	x = i/P
	timePeriod.append(x)
for i in range(len(E_t)):
	E_rat.append((E_t[i]/E_0-1)/t**4)

E_rat = E_rat[450:550]
timePeriod = timePeriod[450:550]

fig2, ax5 = plt.subplots()
ax5.set_ylabel('(E(t)/E_0-1)/t^4')
ax5.set_xlabel('Time/Period')
ax5.set_title("Energy Ratio - Forest Ruth")
ax5.plot(timePeriod,E_rat)
plt.show()

#Computing A

m = []

cat = 0

for i in A_x:

	# print(A_y[cat], A_x[cat], np.arctan(A_y[cat]/A_x[cat]))
	m.append(np.arctan(A_y[cat]/A_x[cat])/t**4)

	cat+=1
	# print (m)
	# if cat > 5:
		# exit()

timing = []
for i in range(len(m)):
	timing.append(i*t)
	# print(timing)
	# if i >5:
		# exit()

fig3, ax6 = plt.subplots()
ax6.set_ylabel('theta/t^4')
ax6.set_xlabel('time')
ax6.set_title("theta/t^4 Plot Comparison")
ax6.plot(timing,m)
plt.show()


import numpy as np

sqrt = np.sqrt
kron = np.kron

PI = np.pi

I = np.matrix([[1, 0],
               [0, 1]])

X = np.matrix([[0, 1],
               [1, 0]])

Y = np.matrix([[0, -1j],
               [1j, 0]])

Z = np.matrix([[1, 0],
               [0, -1]])

def rx(theta):
    return np.cos(theta/2) * I - 1j * np.sin(theta/2) * X

def ry(theta):
    return np.cos(theta/2) * I - 1j * np.sin(theta/2) * Y

def rz(theta):
    return np.cos(theta/2) * I - 1j * np.sin(theta/2) * Z

CX = np.matrix([[1, 0, 0, 0],
                [0, 1, 0, 0],
                [0, 0, 0, 1],
                [0, 0, 1, 0]])

CZ = np.matrix([[1, 0, 0, 0],
                [0, 1, 0, 0],
                [0, 0, 1, 0],
                [0, 0, 0, -1]])

if __name__ == "__main__":
    print("=== Question 1: ===")

    in_state = 1/sqrt(2) * np.matrix([1,1,0,0]).T

    U = kron(rx(-PI/2), I) * CX * kron(I, rz(-PI/2)) * CX
    out_state = U * in_state

    print(in_state)
    print(U)
    print(out_state)

    print("=== Question 2: ===")
    in_state = 1/sqrt(2) * np.matrix([0,0,1,1]).T
    out_state = U * in_state

    print(in_state)
    print(U)
    print(out_state)

    print("=== Question 3: ===")
    in_state = 1/sqrt(2) * np.matrix([1,1,1,1]).T
    out_state = U * in_state

    print(in_state)
    print(U)
    print(out_state)

    print("=== Question 4: ===")
    # This is not working :(
    in_state = 1/sqrt(8) * np.matrix([1,1,1,1,1,1,1,1]).T

    U_12 = kron(I, U)
    U_23 = kron(U, I)

    out_state = U_23 * U_12 * in_state

    print(in_state)
    print(U_23 * U_12)
    print(out_state)
#
    #print(CX * kron(I, Z) * CX)
    #print(kron(Z, I) * kron(I, Z))
    #print(kron(Z, Z))
#
    #print(kron(Z, I))
    #print(kron(I, Z))
#
    #print(CX * np.matrix([1,1,0,0]).T)


'''
ANKIT KHANDELWAL
15863
Exercise 2
'''

from cmath import exp, pi

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

sunspots = pd.read_csv("sunspots.txt", sep='\t', header=None)
time = sunspots[0]
number = sunspots[1]
plt.plot(time, number)
plt.xlabel('Time')
plt.ylabel('Number of Sunspots')
plt.figure()

t1 = time[0:500]
n1 = number[0:500]
plt.plot(t1, n1)
plt.xlabel('Time')
plt.ylabel('Number of Sunspots')
plt.title('For approximating period.')
plt.figure()
# Period is around 100 months.

N = 3143
xv = np.arange(0, N)

def dft(y):
    c = np.zeros(N, complex)
    for k in range(N // 2 + 1):
        for n in range(N):
            c[k] = c[k] + y[n] * exp(-2j * pi * k * n / N)
    for i in range(1, N // 2 + 1):
        c[N - i] = c[i].conjugate()
    return c

dftnumber = dft(number)

cmod = []
for i in range(N):
    cmod.append(abs(dftnumber[i]) ** 2)

plt.plot(xv, cmod)
plt.title('Coefficient\'s amplitudes.')
plt.figure()

maxx = cmod[1:100]
xv1 = np.arange(1, 100)
plt.plot(xv1, maxx)
plt.title('Coefficient\'s amplitudes.')
plt.show()
# k = 24
# period of the sine wave = N/k ~ 131 months.

Ankit Khandelwal_HW4/Exercise 2/exercise 2.py


"""Workout of Statistical tests to estimate population means

These functions are created from using basic python libraries

The module contains useful functions for evaluating AB tests
1. one_mean_conf_interval
2. one_mean_hypothesis
3. two_means_diff_conf_interval
4. two_means_hypothesis

"""

import math
import numpy as np
import classical.workout.utils as utils

def one_mean_conf_interval(values: np.ndarray,
                           conf_level: float = 0.95) -> tuple:
    """calculates confidence interval for mean

    Args:
        values (np.array): list of sample values
        conf_level (float, optional): confidence level. Defaults to 0.95.

    Returns:
        tuple: lower and upper bounds of confidence interval
    """
    x_bar = np.mean(values)
    sd = np.std(values,  ddof=1)
    n = len(values)
    se = sd/math.sqrt(n)
    t_critical = utils.get_t_critical(conf_level, n-1)
    lower_ci = x_bar - t_critical * se
    upper_ci = x_bar + t_critical * se
    return (lower_ci, upper_ci)

def one_mean_hypothesis(values: np.ndarray,
                        null_val: float = 0,
                        alternative: str = "two-sided") -> tuple:
    x_bar = np.mean(values)
    sd = np.std(values, ddof=1)
    n = len(values)
    se = sd/math.sqrt(n)
    t_statistic = (x_bar-null_val)/se
    df = n - 1
    p_value = utils.get_t_pvalue(t_statistic, df, alternative)
    return (t_statistic, p_value)

def two_means_diff_conf_interval(values1: np.ndarray, values2: np.ndarray,
                                 conf_level: float,
                                 pooled: bool = False) -> tuple:
    """Calculates confidence interval for the difference of two means

    Args:
        values1 (np.array): sample 1 values
        values2 (np.array): sample 2 values
        conf_level (float): confidence level
        pooled (bool, optional): whether to calculate pooled std.
                                 Defaults to False.

    Returns:
        tuple: lower and upper values of confidence interval
    """
    x_bar1 = np.mean(values1)
    x_bar2 = np.mean(values2)
    x_diff = x_bar1 - x_bar2
    n1, n2 = len(values1), len(values2)
    se = __get_two_sample_standard_error(values1, values2, pooled)
    df = (n1 + n2 - 2) if pooled else min(n1 - 1, n2 - 1)

    t_critical = utils.get_t_critical(conf_level, df)
    lower_ci = x_diff - t_critical * se
    upper_ci = x_diff + t_critical * se
    return (lower_ci, upper_ci)

def two_means_hypothesis(values1: np.ndarray, values2: np.ndarray,
                         pooled: bool = False,
                         alternative: str = "two-sided") -> tuple:
    """Perform two sided t test to comparing two means

    Args:
        values1 (np.array): sample 1 values
        values2 (np.array): sample 2 values
        pooled (bool, optional): whether to calculate pooled std.
                                 Defaults to False.
        alternative (str, optional): two-sided/larger/smaller.
                                     Defaults to "two-sided".
    Returns:
        tuple: t_statistic and p_value of the test
    """
    x_bar1 = np.mean(values1)
    x_bar2 = np.mean(values2)
    x_diff = x_bar1 - x_bar2
    n1, n2 = len(values1), len(values2)

    se = __get_two_sample_standard_error(values1, values2, pooled)
    df = (n1 + n2 - 2) if pooled else min(n1 - 1, n2 - 1)

    t_statistic = x_diff/se

    p_value = utils.get_t_pvalue(t_statistic, df, alternative)

    return (t_statistic, p_value)

def multiple_mean_hypothesis(*args) -> tuple:
    """Computes Anova test to get whether the mean of at least one group is
    different
    Args:
        *args consecutive sample group values each group sample
              is represented by a list
    Returns:
        tuple: f statistic, p value
    """
    groups = [np.asarray(arg, dtype=float) for arg in args]
    all = np.concatenate(groups)
    n_g = len(groups)
    n_t = len(all)
    y_bar = np.mean(all)
    sst = np.sum((all-y_bar)**2)
    y_barg = list(map(np.mean, groups))
    n_per_g = list(map(len, groups))
    ssg = sum([n_per_g[i] * (y_g-y_bar)**2 for i, y_g in enumerate(y_barg)])

    sse = sst - ssg
    df_t = n_t - 1
    df_g = n_g - 1
    df_e = df_t - df_g
    mse = sse / df_e
    msg = ssg / df_g
    f_statistic = msg/mse
    p_value = utils.get_f_pvalue(f_statistic, df_g, df_e)
    return (f_statistic, p_value)

def __get_two_sample_standard_error(values1: np.ndarray, values2: np.ndarray,
                                    pooled: bool = False) -> float:
    """Calculates standard error for the mean of two samples

    Args:
        values1 (np.array): first sample values
        values2 (np.array): second sample values
        pooled (bool, optional): whether to calculate pooled estimate.
                                 Defaults to False.

    Returns:
        float: standard error
    """
    n1 = len(values1)
    n2 = len(values2)
    s1 = np.std(values1, ddof=1)
    s2 = np.std(values2, ddof=1)
    if pooled:
        s_pool = __get_pooled_standard_deviation(s1, s2, n1, n2)
        s1, s2 = s_pool, s_pool

    se = math.sqrt(s1**2 / n1 + s2**2 / n2)
    return se

def __get_pooled_standard_deviation(s1: float, s2: float,
                                    n1: int, n2: int) -> float:
    """Calcultes pooled standard deviation

    Args:
        s1 (float): standard deviation of sample 1
        s2 (float): standard deviation of sample 2
        n1 (int): no observations of sample 1
        n2 (int): no observations of sample 2

    Returns:
        float: pooled standard deviation
    """
    s_pool = math.sqrt((s1**2 * (n1 - 1) + s2**2 * (n2 - 1)) /
                       (n1 + n2 - 2))
    return s_pool


# a damped, driven pendulum, from Pang, Ch. 4

import math
import numpy
import pylab

class ddpend:

    def __init__(self, theta0, omega0, q, b, omega_d):
        self.theta0 = theta0  # initial angular displacement
        self.omega0 = omega0  # initial angular displacement

        self.q = q             # damping parameter
        self.b = b             # forcing amplitude
        self.omega_d = omega_d # driving frequency

        self.t = None
        self.theta = None
        self.omega = None

    def rhs(self, t, theta, omega):
        """ return the RHS (thetadot(t), omegadot(t)) """

        thetadot = omega
        omegadot = -self.q*omega - math.sin(theta) \
            + self.b*math.cos(self.omega_d*t)

        return thetadot, omegadot

    def intRK4(self, dt, tmax):
        """ integrate the system using 4th-order Runge-Kutta """

        # initial condition
        t = 0.0
        theta = self.theta0
        omega = self.omega0

        # store the solution
        tHist = [t]
        thetaHist = [theta]
        omegaHist = [omega]

        # integrate
        while (t < tmax):

            thetadot1, omegadot1 = self.rhs(t, theta, omega)

            thetadot2, omegadot2 = self.rhs(t+0.5*dt,
                                            theta+0.5*dt*thetadot1,
                                            omega+0.5*dt*omegadot1)

            thetadot3, omegadot3 = self.rhs(t+0.5*dt,
                                            theta+0.5*dt*thetadot2,
                                            omega+0.5*dt*omegadot2)

            thetadot4, omegadot4 = self.rhs(t+dt,
                                            theta+dt*thetadot3,
                                            omega+dt*omegadot3)

            theta += (dt/6.0)*(thetadot1 + 2.0*thetadot2 + 2.0*thetadot3 + thetadot4)
            omega += (dt/6.0)*(omegadot1 + 2.0*omegadot2 + 2.0*omegadot3 + omegadot4)

            t += dt

            tHist.append(t)
            thetaHist.append(theta)
            omegaHist.append(omega)

        self.t = numpy.array(tHist)
        self.theta = numpy.array(thetaHist)
        self.omega = numpy.array(omegaHist)

    def restrictTheta(self):
        """ convert theta in place to be restricted to lie between -pi
            and pi.  This is done in a periodic fashion, with theta' =
            theta +/- 2n pi """

        # shift everything by pi, then restrict to lie between [0,
        # 2pi], then shift back by pi

        self.theta += math.pi

        n = 0
        while (n < len(self.theta)):
            self.theta[n] += - 2.0*math.pi*math.floor(self.theta[n]/(2.0*math.pi))
            n += 1

        self.theta -= math.pi

    def powerSpectrum(self):
        """ return the power spectrum of theta.  For the frequency
            component, return it in terms of omega """

        # power spectrum
        N = len(self.t)

        F = (2.0/N)*numpy.fft.rfft(self.theta)

        k = numpy.fft.fftfreq(N)[range(0,N/2+1)]
        if N % 2 == 0:
            k[-1] *= -1

        kfreq = 2.0*math.pi*k*N/max(self.t)

        return kfreq, F

#-----------------------------------------------------------------------------
# normal (non-damped, non-driven) pendulum

# Note, without damping or driving, all the power should be at the
# natural oscillation period of the pendulum.  For a small amplitude,
# with L = g, then the period is T = 2 pi, and the frequency is nu_k =
# 1/(2 pi).  We plot things in terms of the angular frequency, omega_k
# = 2 pi nu_k, so all the power will be at omega_k = 1

# For a large amplitude perturbation, the period will be longer, so
# the power will be at an omega_k < 1

q = 0.0
b = 0.0
omega_d = 2./3.

T_d = 2.0*math.pi/omega_d
dt = T_d/200.0

# these conditons give a large amplitude perturbation
#theta0 = 0.0
#omega0 = 2.0

# these conditions give a small amplitude, so the power for the undamped,
# non-driven pendulum should be at omega_k = 1
theta0 = 0.1
omega0 = 0.0

p0 = ddpend(theta0, omega0, q, b, omega_d)
p0.intRK4(dt, 100.0*T_d)

pylab.subplot(211)

pylab.plot(p0.theta, p0.omega)

pylab.xlabel(r"$\theta$")
pylab.ylabel(r"$\omega$")

# power spectrum
omega_k, F = p0.powerSpectrum()

pylab.subplot(212)

pylab.plot(omega_k, numpy.abs(F)**2)

pylab.xlim(0.,2.)
#pylab.ylim(1.e-4,1.0)

ax = pylab.gca()
#ax.set_yscale('log')

pylab.xlabel(r"$\omega_k$")
pylab.ylabel(r"power spectrum")

pylab.tight_layout()

pylab.savefig("pend_nodamping.png")

#-----------------------------------------------------------------------------
# non-chaotic pendulum
q = 0.5
b = 0.9
omega_d = 2./3.

T_d = 2.0*math.pi/omega_d
dt = T_d/200.0

theta0 = 0.0
omega0 = 2.0

p1 = ddpend(theta0, omega0, q, b, omega_d)
p1.intRK4(dt, 100.0*T_d)

pylab.clf()

pylab.subplot(211)

pylab.plot(p1.theta, p1.omega)

pylab.xlabel(r"$\theta$")
pylab.ylabel(r"$\omega$")

# power spectrum
omega_k, F = p1.powerSpectrum()

pylab.subplot(212)

pylab.plot(omega_k, numpy.abs(F)**2)
pylab.plot([omega_d, omega_d], [1.e-10,2.0*max(numpy.abs(F)**2)], ls=":")

pylab.xlim(0.,1.)
pylab.ylim(1.e-4,1.0)

ax = pylab.gca()
ax.set_yscale('log')

pylab.xlabel(r"$\omega_k$")
pylab.ylabel(r"power spectrum")

pylab.tight_layout()

pylab.savefig("pend_q0.5_b0.9_om0.666.png")

#-----------------------------------------------------------------------------
# Chaotic pendulum
q = 0.5
bmin = 0.9
db = 0.05
N = 20

B = numpy.arange(N)*db + bmin

omega_d = 2./3.

T_d = 2.0*math.pi/omega_d
dt = T_d/200.0

theta0 = 0.0
omega0 = 2.0

for b in B:

    p2 = ddpend(theta0, omega0, q, b, omega_d)
    p2.intRK4(dt, 500.0*T_d)

    p2.restrictTheta()

    pylab.clf()

    pylab.subplot(211)

    pylab.plot(p2.theta, p2.omega)

    pylab.title(r"$q = %3.2f, \, \omega_d = %4.3f, \, b = %3.2f$" % (q, omega_d, b))

    pylab.xlabel(r"$\theta$")
    pylab.ylabel(r"$\omega$")

    # power spectrum
    omega_k, F = p2.powerSpectrum()

    pylab.subplot(212)

    pylab.plot(omega_k, numpy.abs(F)**2)
    pylab.plot([omega_d, omega_d], [1.e-10,2.0*max(numpy.abs(F)**2)], ls=":")

    pylab.xlim(0.,6.)
    pylab.ylim(1.e-4,1.0)

    ax = pylab.gca()
    ax.set_yscale('log')

    pylab.xlabel(r"$\omega_k$")
    pylab.ylabel(r"power spectrum")

    pylab.tight_layout()

    pylab.savefig("pend_q0.5_b%3.2f_om0.666.png" % (b))


'''
The Normal PDF
100xp

In this exercise, you will explore the Normal PDF and also learn a way to plot a PDF
of a known distribution using hacker statistics. Specifically, you will plot a Normal
PDF for various values of the variance.

Instructions
-Draw 100,000 samples from a Normal distribution that has a mean of 20 and a standard
deviation of 1. Do the same for Normal distributions with standard deviations of 3 and
10, each still with a mean of 20. Assign the results to samples_std1, samples_std3 and
samples_std10, respectively.
-Plot a histograms of each of the samples; for each, use 100 bins, also using the keyword
arguments normed=True and histtype='step'. The latter keyword argument makes the plot look
much like the smooth theoretical PDF. You will need to make 3 plt.hist() calls.
-Hit 'Submit Answer' to make a legend, showing which standard deviations you used, and show
your plot! There is no need to label the axes because we have not defined what is being
described by the Normal distribution; we are just looking at shapes of PDFs.
'''
import numpy as np
import matplotlib.pyplot as plt

# Seed random number generator
np.random.seed(42)

# Draw 100000 samples from Normal distribution with stds of interest: samples_std1, samples_std3,
#   samples_std10
samples_std1 = np.random.normal(20, 1, size=100000)
samples_std3 = np.random.normal(20, 3, size=100000)
samples_std10 = np.random.normal(20, 10, size=100000)

# Make histograms
_ = plt.hist(samples_std1, bins=100, normed=True, histtype='step')
_ = plt.hist(samples_std3, bins=100, normed=True, histtype='step')
_ = plt.hist(samples_std10, bins=100, normed=True, histtype='step')

# Make a legend, set limits and show plot
_ = plt.legend(('std = 1', 'std = 3', 'std = 10'))
plt.ylim(-0.01, 0.42)
plt.show()


import numpy as np

def skew_symmetric(v):
  """
  Returns the skew symmetric matrix [v] from vector `v`.\n
  [v] acts on vectors w such that [v].w = v x w

  Parameters
  ----------
  v : array_like
    The 3x1 vector from which to construct the skew-symmetric matrix.

  Returns
  -------
  [v] : ndarray
    The 3x3 skew-symmetric matrix associated to `v`.
  """

  return np.array([
    [  0  , -v[2],  v[1]],
    [ v[2],   0  , -v[0]],
    [-v[1],  v[0],   0  ]
  ])

def constrain(x, x_max, x_min=None):
  """
  Constrans a given number between a min and max value.

  Parameters
  ----------
  x : scalar
    The number to constrain.
  x_max : scalar
    The upper bound for the constrain.
  x_min : scalar, default=None
    The lower bound for the constrain. If None, defaults to -`x_max`.

  Returns
  -------
  scalar
    The constrained number.
  """

  if x_min is None:
    x_min = -x_max
  return min(max(x, x_min), x_max)