#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))


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

from sklearn.datasets import load_digits
from sklearn.decomposition import PCA

# For reproducibility
np.random.seed(1000)

if __name__ == '__main__':
    # Load the dataset
    digits = load_digits()
    X = digits['data'] / np.max(digits['data'])

    # Compute the eigenvalues of C
    C = np.cov(X.T)
    l, v = np.linalg.eig(C)
    l = np.sort(l)[::-1]
    d = l[:l.shape[0] - 1] - l[1:]

    # Show the differences
    sns.set()

    fig, ax = plt.subplots(figsize=(22, 12))

    ax.bar(np.arange(2, len(d) + 2, 1), d)
    ax.set_xticks(np.arange(2, len(d) + 2, 1))
    ax.set_xlabel('Component', fontsize=16)
    ax.set_ylabel('Eigenvalue difference', fontsize=16)

    plt.show()

    # Perform the PCA
    pca = PCA(n_components=16, random_state=1000)
    digits_pca = pca.fit_transform(X)

    # Show some sample digits
    fig, ax = plt.subplots(2, 10, figsize=(22, 6))

    for i in range(10):
        ax[0, i].imshow(X[i].reshape((8, 8)), cmap='gray')
        ax[0, i].set_xticks([])
        ax[0, i].set_yticks([])

        ax[1, i].imshow(pca.inverse_transform(digits_pca[i]).reshape((8, 8)), cmap='gray')
        ax[1, i].set_xticks([])
        ax[1, i].set_yticks([])

    plt.show()

    # Total explained variance (as ratio)
    print(np.sum(pca.explained_variance_ratio_))

    # Show the explained variance ratio per component
    ev = pca.explained_variance_ratio_

    fig, ax = plt.subplots(figsize=(10, 6))

    ax.bar(np.arange(1, len(ev) + 1, 1), ev)
    ax.set_xticks(np.arange(1, len(ev) + 1, 1))
    ax.set_xlabel('Components')
    ax.set_ylabel('Explained variance ratio')

    plt.show()


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("运行完毕")


import numpy as np

def std_Normalize(x):
  z = np.max(x) - np.min(x)
  x_norm = (x - np.min(x)) / z
  return x_norm

def l2_Normalize(x):
  x = x - np.mean(x)
  z = np.sqrt(np.sum(np.multiply(x, x)))
  x_norm = x / z
  return x_norm


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


import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

def plot_bollinger_bands(df, sma, n_deviations):

    df["SMA"] = df["Close"].rolling(window=sma).mean()
    df["Upper Band"] = df["SMA"] + (df["Close"].rolling(window=sma).std()*n_deviations)
    df["Lower Band"] = df["SMA"] - (df["Close"].rolling(window=sma).std()*n_deviations)

    fig = go.Figure(data=go.Candlestick(x = df.index, open = df["Open"], high = df["High"], low = df["Low"], close = df["Close"], name="Candlestick"))
    fig.add_trace(go.Scatter(x = df.index, y = df["SMA"], line_color = "blue", name = "SMA"))
    fig.add_trace(go.Scatter(x = df.index, y = df["Upper Band"], line_color = "red", line = {"dash": "dash"}, name = "Upper Band", opacity = 0.5))
    fig.add_trace(go.Scatter(x = df.index, y = df["Lower Band"], line_color = "green", line = {"dash": "dash"}, name = "Lower Band", opacity = 0.5))
    fig.update_layout(xaxis_rangeslider_visible=False)
    return fig.show()

def boll_buy_lower_sell_upper(df, sma_number=50, n_deviations=2):

    trading_signals = np.array([])
    df["SMA"] = df["Close"].rolling(window=sma_number).mean()
    df["Upper Band"] = df["SMA"] + (df["Close"].rolling(window=sma_number).std()*n_deviations)
    df["Lower Band"] = df["SMA"] - (df["Close"].rolling(window=sma_number).std()*n_deviations)

    for i in range(0, len(df)):
        if df["Close"].iloc[i]<=df["Lower Band"].iloc[i]:
            trading_signals = np.append(trading_signals, "Buy")
        elif df["Close"].iloc[i]>=df["Upper Band"].iloc[i]:
            trading_signals = np.append(trading_signals, "Sell")
        else:
            trading_signals = np.append(trading_signals, None)

    return trading_signals

if __name__ == '__main__':

    from Strategy_Engine import strategy_engine

    #For VSCode
    #price_df = pd.read_csv(r"Trading_Strategies\Algotrading\AAPL_data.csv", index_col="Date")
    #For Jupyter Notebook
    price_df = pd.read_csv("AAPL_data.csv", index_col="Date")
    price_df.index.name = None

    #plot_bollinger_bands(price_df, 50, 2)

    strat = boll_buy_lower_sell_upper(price_df, 50, 2)
    history = strategy_engine(price_df, strat, 100000, 0.01, 0.1, close_positions=True)
    print(history)
    fig = px.line(np.cumsum(history["Profit/Loss"]))
    fig.show()


# 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)


"""
Purpose of this file is to give examples of masking

This script is partially dirived from the LinkedIn learning course
https://www.linkedin.com/learning/numpy-data-science-essential-training/create-arrays-from-python-structures

"""
import numpy as np

a1 = np.arange(70)
a2 = np.arange(3*4*5)

a1.shape = (2, 7, 5)
print(f"a1 is \n {a1}\n")
print(f"a2 is \n {a2}\n")

# shape attribute will return size of each dimension
# ndim attribute will return the number of dimension
# size attribute will return the number opf elements
# dtype is the type of of the elements in the array (which must all be same)
print(f'a1 length of each dimension is = {a1.shape}')
print(f'a1 has the number of dimensions = {a1.ndim}')
print(f'a1 the total number of elements is =  {a1.size}')
print(f'a1 elements is of type =  {a1.dtype} \n')

print(f'applying 5 * a1 - 2 is \n {5 * a1 - 2}')

# to do
left_mat = np.arange(6).reshape((2, 3))
right_mat = np.arange(15).reshape((3, 5))
print(f'left_mat is\n{left_mat}\n')
print(f'right_mat is\n{right_mat}\n')

# take the inner product
#  np.inner(left_mat, right_mat) will not work as there is a direction mismatch inner used for 1d array
# for 2d+ array use np.dot
print(f'the dot problem \n{np.dot(left_mat, right_mat)}\n')

# we sum the array
print(f'The sum of all the elements in a1 is {a1.sum()}')


import array

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import preprocessing

plt.rcParams['figure.figsize'] = (12.0, 9.0)
#plt.ticklabel_format(style='plain')

class LinearRegression:
    def __init__(self, filepath):
        self.data = pd.read_csv(filepath)

        self.x_name = self.data.columns[0]
        self.y_name = self.data.columns[1]

        self.x = self.data[self.x_name]
        self.y = self.data[self.y_name]

        self.b1 = 0
        self.b0 = 0

        self.iterations = []
        self.costs = []

    # Plots the data, including the linear regression line, if the model has been trained.
    def plot_model_data(self):
        plt.xlabel(self.x_name)
        plt.ylabel(self.y_name)
        plt.suptitle(self.y_name + ' against ' + self.x_name)
        plt.scatter(self.data[self.x_name], self.data[self.y_name], c="black")

        #If model has been trained, plot the line for the linear-regression aswell.
        if self.b1 != 0 and self.b0 != 0:
            pred_y = self.b1 * self.x + self.b0
            plt.plot([min(self.x), max(self.x)], [min(pred_y), max(pred_y)], color='red')  # regression line
        plt.show()

    def plot_loss(self):
        plt.xlabel('Iterations')
        plt.ylabel('Loss')
        plt.suptitle('Loss over iteration')
        plt.plot(self.iterations, self.costs, linewidth=1)
        plt.show()

    def train(self, learning_rate=0.0001, iterations=500):
        n = float(len(self.x))  # Number of samples

        self.b1 = 0  # Resets the values, if one wants to train the model again. The reason for wanting
        self.b0 = 0  # to train a model again can be to change learning rate, amount of iterations, etc.

        # Trains the model
        for i in range(iterations):
            predicted_y = self.b1 * self.x + self.b0

            der_b1 = (-2 / n) * sum(self.x * (self.y - predicted_y))    # Partial derivative of b1.
            der_b0 = (-2 / n) * sum(self.y - predicted_y)               # Partial derivative of b0.

            self.b1 = self.b1 - learning_rate * der_b1
            self.b0 = self.b0 - learning_rate * der_b0

            self.iterations.append(i)
            self.costs.append(self.calc_loss(predicted_y))

        print(self.b1, self.b0)

    def calc_loss(self, pred_y):
        n = len(self.x)
        return (sum((self.b0 + self.b1 * self.x)-pred_y)**2)/2*n

    def predict(self, x):
        if self.b1 != 0 and self.b0 != 0:
            predicted_y = self.b1 * x + self.b0
            print("The predicted value is: " + str(predicted_y))
        else:
            print("Please train the model before attempting to make any predictions!")


# -*- coding: utf-8 -*-
"""
Author: Paschalis Giakoumoglou
Date: Thu Jun 17 23:29:08 2021
"""

import matplotlib.pyplot as plt
import numpy as np
import math
import sympy as symb
from autograd import grad
import autograd

def print_derivatives(degree):
    print("Function and its derivatives:")
    x = symb.Symbol('x')
    y = x*symb.log(x)
    print(f"> Initial function = {y}")
    for i in range(1, degree+1):
        print(f"> Derivative {i} = {y.diff(x, i)}")
    return y

def f(x):
    return x**3

def find_max_grad_f(f, degree, a, b):
    ff =  f
    for _ in range(degree):
        ff = grad(ff)
    x = np.linspace(a,b,1000)
    ffx = [ff(float(i)) for i in x]
    return max(ffx)

def rect_left(f, a, b, N):
    print("Rectangle Left Method")
    h = (b-a)/N
    print(f"a = {a}, b = {b}, N = {N}")
    print(f"h = (b-a)/N = {h}")
    tot = 0
    for i in range(N):
        tot += f(a+i*h)
        print(f"f({a+i*h}) = {f(a+i*h)}")
    print(f"I = h*sum[f(x_i)] = {tot*h}")
    error = h/2*(b-a)*find_max_grad_f(f, 1, a, b)
    print(f"E = h/2*(b-a)*max(f'(x)) = {error}")
    print_derivatives(1+1)
    print()
    #return tot*h

def rect_right(f, a, b, N):
    print("Rectangle Right Method")
    h = (b-a)/N
    tot = 0
    for i in range(N):
        tot += f(a+i*h+h)
        print(f"f({a+i*h}) = {f(a+i*h)}")
    print(f"I = h*sum(f(a+i*h+h)) = {tot*h}")
    print()
    #return tot*h

def trapezoid(f, a, b, N):
    print("Trapezoidal Method")
    h = (b - a) / N
    print(f"a = {a}, b = {b}, N = {N}")
    print(f"h = (b-a)/N = {h}")
    tot = f(a)+f(b)
    print(f"f({a}) = {f(a)}")
    for i in range(1, N):
        tot += 2 * f(a + i * h)
        print(f"f({a+i*h}) = {f(a+i*h)}")
    print(f"f({b}) = {f(b)}")
    print(f"I = (h/2) * [f(x0) + 2f(x1) + 2f(x2) + ... + 2f(xN-1) + f(xN)] = {(h / 2) * tot}")
    error = (h**2)*(b-a)*find_max_grad_f(f,2,a,b)/12
    print(f"E = (h^2/12) * (b-a) * max(f''(x)) = {error}")
    print_derivatives(2+1)
    print()
    #return (h / 2) * tot

def simpson(f, a,b,N):
    print("Simpson's Method")
    print("N must be a multitude of 2")
    h = (b-a)/N
    print(f"a = {a}, b = {b}, 2N = {N}")
    print(f"h = (b-a)/N = {2*h}")
    tot = f(a) + f(b)
    print(f"f({a}) = {f(a)}")
    for i in range(1,N,1):
        tot += f(a+i*h)*(2*(i%2 == 0) + 4*(i%2 == 1))
        print(f"f({a+i*h}) = {f(a+i*h)}")
    print(f"f({b}) = {f(b)}")
    print(f"I = (h/6) * [f(x0) + 4f(x1) + 2f(x2) + 4f(x3) + 2f(x4) + ... + 2f(x2N-2) + 4f(x2N-1) + f(x2N)] = {(h / 3) * tot}")
    error = (h**2) * (b-a) * find_max_grad_f(f,4,a,b) / 180
    print(f"E = ((h/2)^4/180) * (b-a) * max(f''''(x)) = {error}")
    print_derivatives(3+1)
    print()
    #return tot*h/3

def simpson38(f, a,b,N):
    print("Simpson's Method")
    print("N must be a multitude of 3")
    h = (b-a)/N
    print(f"a = {a}, b = {b}, N = {N}")
    print(f"h = (b-a)/N = {h}")
    tot = f(a) + f(b)
    print(f"f({a}) = {f(a)}")
    for i in range(1,N,1):
        tot += f(a+i*h)*(2*(i%3 == 0) + 3*(i%3 != 0))
        print(f"f({a+i*h}) = {f(a+i*h)}")
    print(f"f({b}) = {f(b)}")
    print(f"I = (h/6) * [f(x0) + 3f(x1) + 3f(x2) + 2f(x3) + 3f(x4) + ... + 3f(xN-2) + 3f(xN-1) + f(xN)] = {(3*h / 8) * tot}")
    error = (h**4) * (b-a) * find_max_grad_f(f,4,a,b) / 80
    print(f"E = ((h/2)^4/80) * (b-a) * max(f''''(x)) = {error}")
    print_derivatives(3+1)
    print()
    #return tot*h/3

def midpoint(f, a, b, N):
    print("Midpoint Method")
    h = (b - a) / N
    print(f"a = {a}, b = {b}, N = {N}")
    print(f"h = (b-a)/N = {h}")
    tot = 0
    for i in range(0, N):
        tot += f(a+i*h + h/2)
        print(f"f({a+i*h + h/2}) = {f(a+i*h + h/2)}")
    print(f"I = h*sum[f(xi+h/2)] = {h*tot}")
    error = ((h**2)/24) * (b-a) * find_max_grad_f(f,2,a,b)
    print(f"E = (h^2/24) * (b-a) * max(f''(x)) = {error}")
    print_derivatives(2+1)
    print()
    #return tot*h

if __name__ == "__main__":

    # Examples for all methods
    rect_left(f, a=1, b=2, N=8)
    rect_right(f, a=1, b=2, N=8)
    trapezoid(f, a=1, b=2, N=8)
    simpson(f, a=1, b=2, N=8)
    simpson38(f, a=1, b=2, N=9)
    midpoint(f, a=1, b=2, N=8)

    #Example
    def f(x):
        return x*autograd.numpy.log(x)
    simpson(f, 1, 2, 4)


import numpy as np
from mpi4py import MPI

from sympde.calculus      import grad, dot
from sympde.topology      import ScalarFunctionSpace
from sympde.topology      import elements_of
from sympde.topology      import Square
from sympde.topology      import PolarMapping
from sympde.expr.expr     import LinearForm, BilinearForm
from sympde.expr.expr     import integral
from sympde.expr.expr     import Norm
from sympde.expr.equation import find, EssentialBC

from psydac.api.discretization import discretize

#==============================================================================
def run_poisson_2d(solution, f, domain, ncells, degree, comm=None):

    #+++++++++++++++++++++++++++++++
    # 1. Abstract model
    #+++++++++++++++++++++++++++++++

    V    = ScalarFunctionSpace('V', domain, kind=None)

    u, v = elements_of(V, names='u, v')

    bc   = EssentialBC(u, solution, domain.boundary)

    error  = u - solution

    a = BilinearForm((u,v),  integral(domain, dot(grad(u),grad(v))))
    l = LinearForm(v, integral(domain, f*v))

    equation = find(u, forall=v, lhs=a(u,v), rhs=l(v), bc=bc)

    l2norm = Norm(error, domain, kind='l2')
    h1norm = Norm(error, domain, kind='h1')

    #+++++++++++++++++++++++++++++++
    # 2. Discretization
    #+++++++++++++++++++++++++++++++

    domain_h = discretize(domain, ncells=ncells)
    Vh       = discretize(V, domain_h, degree=degree)

    equation_h = discretize(equation, domain_h, [Vh, Vh])

    l2norm_h = discretize(l2norm, domain_h, Vh)
    h1norm_h = discretize(h1norm, domain_h, Vh)

    uh = equation_h.solve()

    l2_error = l2norm_h.assemble(u=uh)
    h1_error = h1norm_h.assemble(u=uh)

    return l2_error, h1_error

#------------------------------------------------------------------------------
def test_poisson_2d_analytical_mapping_0():

    domain  = Square('A',bounds1=(0., 1.), bounds2=(0, np.pi))
    mapping = PolarMapping('M1',2, c1= 0., c2= 0., rmin = 0., rmax=1.)

    mapped_domain = mapping(domain)

    x,y = mapped_domain.coordinates
    solution = x**2 + y**2
    f        = -4

    l2_error, h1_error = run_poisson_2d(solution, f, mapped_domain, ncells=[2**2,2**2], degree=[2,2])

    expected_l2_error = 1.0930839536997034e-09
    expected_h1_error = 1.390398663745195e-08

    assert ( abs(l2_error - expected_l2_error) < 1e-7 )
    assert ( abs(h1_error - expected_h1_error) < 1e-7 )

#==============================================================================
# CLEAN UP SYMPY NAMESPACE
#==============================================================================
def teardown_module():
    from sympy.core import cache
    cache.clear_cache()

def teardown_function():
    from sympy.core import cache
    cache.clear_cache()


import numpy as np
import pandas as pd
def select_closest(neurons, origin):
    """Return the index of the closest candidate to a given point."""
    return euclidean_distance(neurons, origin).argmin()

def euclidean_distance(a, b):
    """Return the array of distances of two numpy arrays of points."""
    temp = a-b
    return np.linalg.norm(temp, axis=1)

def route_distance(cities):
    """Return the cost of traversing a route of cities in a certain order."""
    points = cities[['x', 'y']]
    distances = euclidean_distance(points, np.roll(points, 1, axis=0))
    return np.sum(distances)

def route_distance_p(path):
    """Return the cost of traversing a route of cities in a certain order."""
    cities = pd.read_csv(path)
    points = cities[['x', 'y']]
    distances = euclidean_distance(points, np.roll(points, 1, axis=0))
    return np.sum(distances)

def select_closest_gpid(neuron_chains, origin):
    ret_gid=0
    ret_pid=0
    min_value=100
    for gid,chain in enumerate(neuron_chains):
        dises = euclidean_distance(chain, origin)
        value = dises.min()
        idx = dises.argmin()
        if min_value>value:
            min_value = value
            ret_gid = gid
            ret_pid = idx
    #修正depot点

    return [ret_gid,ret_pid]

def routes_distances(cities_od):
    distances=[]
    for gid in range(int(cities_od['gid'].max())+1):
        df = cities_od.query('gid=='+str(gid))
        points = df[['x', 'y']]
        distance = euclidean_distance(points, np.roll(points, 1, axis=0)).sum()
        distances.append(distance)

    return distances


# Custom Functions
import numpy as np
import pandas as pd

def ATransformMatrix (theta): #A
    ATransform = np.array([[np.cos(theta), -np.sin(theta)],
                            [np.sin(theta), np.cos(theta)]])
    return ATransform

def ATransformMatrixTHETA (theta): #A_theta
    ATransformTHETA = np.array([[-np.sin(theta), -np.cos(theta)],
                                [np.cos(theta), -np.sin(theta)]])
    return ATransformTHETA

def prettyMatVect(matVect):
    prettyMatVect = pd.DataFrame(matVect, columns =
                                ['R1x', 'R1y', 'theta1',
                                'R2x','R2y','theta2',
                                'R3x','R3y','theta3',
                                'R4x','R4y','theta4'])
    return prettyMatVect

def calcGlobalCoor(qi, u_bar_iP, u_bar_jP, link_i, link_j):
    # To calculate Point of Interest positions in terms of global coordinates
    index_for_i = 3*(link_i-1)
    index_for_j = 3*(link_j-1)
    Ri = np.array([qi[index_for_i], qi[index_for_i+1]], dtype = float)
    Rj = np.array([qi[index_for_j], qi[index_for_j+1]], dtype = float)

    # Point P at link i
    riP = Ri + np.matmul(ATransformMatrix(float(qi[index_for_i+2])), u_bar_iP)
    # Point P at link j
    rjP = Rj + np.matmul(ATransformMatrix(float(qi[index_for_j+2])), u_bar_jP)

    return riP, rjP

def constraintEquation(constraintVector, qi, r1O2, r2O2, r2A, r3A,
                    r3B, r4B, r1O4, r4O4,
                    theta2Initial, omega2, timeNow):
    # Ground constraint
    for i in range(3):
        constraintVector[i] = 0 #qi[i] # just zero

    # Pin joint O2
    constraintPinO = r2O2# r1O -
    for i in range(np.size(constraintPinO)):
    # Equation 4-5
        constraintVector[i+3] = constraintPinO[i]

    # Pin joint A
    constraintPinA = r2A - r3A
    for i in range(np.size(constraintPinA)):
    # Equation 6-7
        constraintVector[i+5] = constraintPinA[i]

    # Pin joint B
    constraintPinB = r3B - r4B
    for i in range(np.size(constraintPinB)):
    # Equation 8-9
        constraintVector[i+7] = constraintPinB[i]

    # Pin joint O4
    constraintPinO4 = r1O4-r4O4
    for i in range(np.size(constraintPinO4)):
    # Equation 10-11
        constraintVector[i+9] = constraintPinB[i]

    # Equation 12 ===> Driving constraint
    constraintVector[11] = qi[5] - theta2Initial - omega2*timeNow

    return constraintVector

def jacobianMatrix(qi, u_bar_2O2, u_bar_2A, u_bar_3A, u_bar_3B,
                    u_bar_4B, u_bar_1O4, u_bar_4O4):
    n = np.size(qi)
    jacobianMatrixCq = np.zeros((n,n), dtype = float)
    identity3x3 = np.identity(3, dtype = float)
    identity2x2 = np.identity(2, dtype = float)

    # row 1-3 --> Ground constraint
    jacobianMatrixCq[0:3,0:3] = identity3x3

    # row 4-5 (r1O2 = r2O2)
    Cq45 = np.matmul(ATransformMatrixTHETA(float(qi[5])), u_bar_2O2)
    jacobianMatrixCq[3:5,3:5] = identity2x2
    jacobianMatrixCq[3:5,5:6] = Cq45

    # row 6-7 (r2A = r3A)
    Cq67_link2 = np.matmul(ATransformMatrixTHETA(float(qi[5])), u_bar_2A)
    Cq67_link3 = np.matmul(ATransformMatrixTHETA(float(qi[8])), u_bar_3A)
    jacobianMatrixCq[5:7,3:5] = identity2x2
    jacobianMatrixCq[5:7,5:6] = Cq67_link2
    jacobianMatrixCq[5:7,6:8] = -identity2x2
    jacobianMatrixCq[5:7,8:9] = -Cq67_link3

    # row 8-9 (r3B = r4B)
    Cq89_link3 = np.matmul(ATransformMatrixTHETA(float(qi[8])), u_bar_3B)
    Cq89_link4 = np.matmul(ATransformMatrixTHETA(float(qi[11])), u_bar_4B)
    jacobianMatrixCq[7:9,6:8] = identity2x2
    jacobianMatrixCq[7:9,8:9] = Cq89_link3
    jacobianMatrixCq[7:9,9:11] = -identity2x2
    jacobianMatrixCq[7:9,11:12] = -Cq89_link4

    # row 10-11 (r1O4 = r4O4)
    Cq1011_link1 = np.matmul(ATransformMatrixTHETA(float(qi[2])), u_bar_1O4)
    Cq1011_link4 = np.matmul(ATransformMatrixTHETA(float(qi[11])), u_bar_4O4)
    jacobianMatrixCq[9:11,0:2] = identity2x2
    jacobianMatrixCq[9:11,2:3] = Cq1011_link1
    jacobianMatrixCq[9:11,9:11] = -identity2x2
    jacobianMatrixCq[9:11,11:12] = -Cq1011_link4

    # row 12
    jacobianMatrixCq[11][5] = 1

    return jacobianMatrixCq

def constrEqDot(constraintVectorVel, omega):

    constraintVectorVel[11] = -omega

    return constraintVectorVel

def positionAnalysis(constraintVector, jacobianMatrix, qi):
    inverse_jacobian = np.linalg.inv(jacobianMatrix)
    delta_qi = - np.matmul(inverse_jacobian, constraintVector)
    delta_qi_norm = np.linalg.norm(delta_qi)
    qi = qi + delta_qi

    return qi, delta_qi_norm

def velocityAnalysis(constraintVectorVel, jacobianMatrix, qiDot):
    inverse_jacobian = np.linalg.inv(jacobianMatrix)
    qiDot= - np.matmul(inverse_jacobian, constraintVectorVel)

    return qiDot

def accelerationAnalysis(jacobianMatrix, qiDotDot, qiDot, qi,
                        u_bar_2O, u_bar_2A, u_bar_3A, u_bar_3B, u_bar_4B,
                        u_bar_1O4, u_bar_4O4):
    # Qd line 4-5
    Qd45 = np.square(float(qiDot[5]))*np.dot(ATransformMatrix(float(qi[5])), u_bar_2O)

    # Qd line 6-7
    Qd67a = np.square(float(qiDot[5]))*np.dot(ATransformMatrix(float(qi[5])), u_bar_2A)
    Qd67b = np.square(float(qiDot[8]))*np.dot(ATransformMatrix(float(qi[8])), u_bar_3A)
    Qd67 = Qd67a-Qd67b

    # Qd line 8-9
    Qd89a = np.square(float(qi[8]))*np.dot(ATransformMatrix(float(qi[8])), u_bar_3B)
    Qd89b = np.square(float(qi[11]))*np.dot(ATransformMatrix(float(qi[11])), u_bar_4B)
    Qd89 = Qd89a-Qd89b

    # Qd line 10-11
    Qd1011a = np.square(float(qi[2]))*np.dot(ATransformMatrix(float(qi[2])), u_bar_1O4)
    Qd1011b = np.square(float(qi[11]))*np.dot(ATransformMatrix(float(qi[11])), u_bar_4O4)
    Qd1011 = Qd1011a-Qd1011b

    Qd = np.array([[0],[0],[0], Qd45[0], Qd45[1],
                    Qd67[0], Qd67[1], Qd89[0], Qd89[1],
                    Qd1011[0], Qd1011[1], [0]])

    inverse_jacobian = np.linalg.inv(jacobianMatrix)
    qiDotDot= np.dot(inverse_jacobian, Qd)

    return qiDotDot

def eulerMethod(initialState, time, stepSize, systemFunction):
    # initialState = y1 and y2 (e.g. position and velocity)
    totalData = np.size(time)
    position = np.zeros(totalData, dtype = float)
    velocity = np.zeros(totalData, dtype = float)
    acceleration = np.zeros(totalData, dtype = float)

    state = initialState

    for i in range(totalData):
        eulerMeth = systemFunction(time[i], state)
        state = state + stepSize*np.array([state[1], [eulerMeth]], dtype = float)

        position[i] = (state[0])
        velocity[i] = (state[1])
        acceleration[i] = eulerMeth

    return position, velocity, acceleration

def rungeKutta4 (y, time, systemFunction, stepSize):
    # This function works with ANY number of DOF

    numberOfDOF = int(np.size(y)/2)
    totalData   = np.size(time)
    state       = np.zeros((totalData,numberOfDOF), dtype = float)
    stateDot    = np.zeros((totalData,numberOfDOF), dtype = float)
    stateDotDot = np.zeros((totalData,numberOfDOF), dtype = float)

    # RungeKutta4
    for currentTime in range(totalData):

        t1  = time[currentTime]
        f_1 = systemFunction(y, t1)
        k1  = np.zeros((np.size(y), 1), dtype = float)
        for x    in range(numberOfDOF):
            k1[x]   = y[x+numberOfDOF]
            k1[x+numberOfDOF] = f_1[x]

        t2  = time[currentTime]+0.5*stepSize
        y2  = y + 0.5*k1*stepSize
        f_2 = systemFunction(y2, t2)
        k2  = np.zeros((np.size(y), 1), dtype = float)
        for x    in range(numberOfDOF):
            k2[x]   = y2[x+numberOfDOF]
            k2[x+numberOfDOF] = f_2[x]

        t3  = time[currentTime]+0.5*stepSize
        y3  = y + 0.5*k2*stepSize
        f_3 = systemFunction(y3, t3)
        k3  = np.zeros((np.size(y), 1), dtype = float)
        for x    in range(numberOfDOF):
            k3[x]   = y3[x+numberOfDOF]
            k3[x+numberOfDOF] = f_3[x]

        t4  = time[currentTime]+stepSize
        y4  = y + k3*stepSize
        f_4 = systemFunction(y4, t4)
        k4  = np.zeros((np.size(y), 1), dtype = float)
        for x    in range(numberOfDOF):
            k4[x]   = y4[x+numberOfDOF]
            k4[x+numberOfDOF] = f_4[x]

        RKFunct = (k1 + 2*k2 + 2*k3 + k4)/6

        y = y + stepSize*RKFunct

        for dof in range(numberOfDOF):
            state       [currentTime][dof] = y[dof]
            stateDot    [currentTime][dof] = y[dof+numberOfDOF]
            stateDotDot [currentTime][dof] = RKFunct[dof+numberOfDOF]

    return state, stateDot, stateDotDot


import numpy as np

def gaussian_elimination(A, b):
    if len(A) != len(A[0]) or len(A[0]) != len(b):
        raise ValueError('gaussian elimination: invalid matrix or vector sizes')

    if not np.any(np.diag(A)):
        raise ValueError('gaussian elimination: no solution')

    A = np.array(A)
    b = np.array(b)
    n = len(A)

    for row in range(n - 1):
        for i in range(row + 1, n):
            factor = A[i, row] / A[row, row]
            for j in range(row, n):
                A[i, j] -= factor * A[row, j]
            b[i] -= factor * b[row]

    x = np.empty(n)
    x[n - 1] = b[n - 1] / A[n - 1, n - 1]
    for row in reversed(range(n - 2)):
        sums = b[row]
        for j in range(row + 1, n):
            sums -= A[row, j] * x[j]
        x[row] = sums / A[row, row]
    return x

def jacobi_method(A, b, n=10):
    if len(A) != len(A[0]) or len(A) != len(b):
        raise ValueError('jacobi method: invalid matrix and vector sizes')

    D = np.diagflat(np.diag(A))
    R = np.array(A) - D

    D_inv = np.linalg.inv(D)
    b = np.array(b)
    x = np.zeros(len(A))

    for _ in range(n):
        x = np.dot(D_inv, b - np.dot(R, x))

    return x

def gauss_seidel_method(A, b, n=10):
    if len(A) != len(A[0]) or len(A) != len(b):
        raise ValueError('gauss seidel method: invalid matrix and vector sizes')

    L = np.tril(A, k=0)
    U = np.triu(A, k=1)

    L_inv = np.linalg.inv(L)
    b = np.array(b)
    x = np.zeros(len(A))

    for _ in range(n):
        x = np.dot(L_inv, b - np.dot(U, x))

    return x

def successive_over_relaxation_method(A, b, w, n=10):
    if len(A) != len(A[0]) or len(A) != len(b):
        raise ValueError('successive over relaxation method: invalid matrix and vector sizes')

    D = np.diagflat(np.diag(A))
    L = np.tril(A, k=-1)
    U = np.triu(A, k=1)

    inv = np.linalg.inv(D + w * L)
    x = np.zeros(len(A))
    wb = w * np.array(b)
    M = w * U + (w + 1) * D

    for _ in range(n):
        x = np.dot(inv, wb - np.dot(M, x))

    return x


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

data=genfromtxt("multi_var.csv",delimiter=',')
x_data=data[:,0:2]
y_data=data[:,2]

#hypothesis function
def hypothesis(theta_0,theta_1,theta_2,x1,x2):
    return theta_0+theta_1*x1+theta_2*x2

#cost function
def square_error(theta_0,theta_1,theta_2,x_data,y_data):
    sqr_error=0
    for i in range(0,len(x_data)):
        sqr_error+=(hypothesis(theta_0,theta_1,theta_2,x_data[i,0],x_data[i,1])-y_data[i])**2
    return sqr_error/len(x_data)/2

#gradient descent
def gradient_descent(x_data,y_data,theta_0,theta_1,theta_2,learning_rate,iteration):
    N=len(x_data)
    cost_function=[]
    for i in range(iteration):
        theta_0_grad=0
        theta_1_grad=0
        theta_2_grad=0
        for j in range(0,N):
            theta_0_grad+=(1/N)*(hypothesis(theta_0,theta_1,theta_2,x_data[j,0],x_data[j,1])-y_data[j])
            theta_1_grad+=(1/N)*(hypothesis(theta_0,theta_1,theta_2,x_data[j,0],x_data[j,1])-y_data[j])*x_data[j,0]
            theta_2_grad+=(1/N)*(hypothesis(theta_0,theta_1,theta_2,x_data[j,0],x_data[j,1])-y_data[j])*x_data[j,1]
        theta_0=theta_0-(learning_rate*theta_0_grad)
        theta_1=theta_1-(learning_rate*theta_1_grad)
        theta_2=theta_2-(learning_rate*theta_2_grad)
        cost_function.append(square_error(theta_0,theta_1,theta_2,x_data,y_data))
        if i%200==0:
            #plot data
            ax=plt.figure().add_subplot(111,projection='3d')
            ax.scatter(x_data[:,0],x_data[:,1],y_data,c='r',marker='o',s=100)
            #plot the hypothesis
            x0=x_data[:,0]
            x1=x_data[:,1]
            x0,x1=np.meshgrid(x0,x1)
            z=theta_0+x0*theta_1+x1*theta_2
            ax.plot_surface(x0,x1,z)

            ax.set_title("the %d times of iteration" %(i))
            ax.set_xlabel("feature 1")
            ax.set_ylabel("feature 2")
            ax.set_zlabel("target")
            plt.show()
    return theta_0,theta_1,theta_2,cost_function

learning_rate=0.000001
theta_0=0
theta_1=0
theta_2=0
iteration=1000

print("Initial State:")
print("theta_0=%.3lf,   theta_1=%.3lf,  theta_2=%.3lf" %(theta_0,theta_1,theta_2))
print("Running for the method of gradient descent")
theta_0,theta_1,theta_2,cost_function=gradient_descent(x_data,y_data,theta_0,theta_1,theta_2,learning_rate,iteration)
print("Final state:")
print("theta_0=%.3lf,   theta_1=%.3lf,  theta_2=%.3lf" %(theta_0,theta_1,theta_2))

#plot the cost function versus iteration times
for i in range(0,len(cost_function)):
    plt.plot(i,cost_function[i],'b.')
plt.title("cost function versus iteration times")
plt.xlabel("iteration times")
plt.ylabel("cost function")
plt.show()


import numpy as np

from .base_test_function import BaseTestFunction

class HolderTable(BaseTestFunction):
    def __init__(self):
        self.search_domain = [-10, 10]

    def __call__(self, x):
        x, y = x

        y = -np.abs(np.sin(x)*np.cos(y)*np.exp(np.abs(1 - np.sqrt(x**2 + y**2)/np.pi)))

        return y


import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import inv

def get_points():
    x = list(map(float, input().split()))
    y = list(map(float, input().split()))

    return x, y

def lls(k, x, y):
    x = np.array(x)
    t = np.array([[i ** j for i in x] for j in reversed(range(k))])
    t_trans = np.transpose(t)
    g = t @ t_trans
    a = inv(g) @ t @ y

    return a

def calc_err(x, y, coeff):
    y_err = [np.polyval(coeff, i) for i in x]

    err = sum([(y_err[idx] - i) ** 2 for idx, i in enumerate(y)])

    return err

def main():
    x, y = get_points()

    coef_2d = lls(2, x, y)
    print(coef_2d)
    coef_3d = lls(3, x, y)
    print(coef_3d)
    x_vals = np.linspace(x[0], x[-1])
    y_2d = [np.polyval(coef_2d, i) for i in x_vals]
    y_3d = [np.polyval(coef_3d, i) for i in x_vals]

    plt.scatter(x, y, color='r')
    plt.plot(x_vals, y_2d, color='b')
    plt.plot(x_vals, y_3d, color='g')
    plt.show()
    print(f'error for ax + b = {calc_err(x, y, coef_2d)}')
    print(f'error for ax^2 + bx + c = {calc_err(x, y, coef_3d)}')

main()


import numpy as np

def gauss_jordan(matrix, sol_matrix):
    matrix = np.array(matrix, float)
    sol_matrix = np.array(sol_matrix, float)
    n = len(sol_matrix)

    for k in range(n):
        if np.fabs(matrix[k,k])< 1.0e-12:
            for i in range(k+1,n):
                if np.fabs(matrix[i,k]) > np.fabs(matrix[k,k]):
                    for j in range(k,n):
                        matrix[k,j], matrix[i,j] = matrix[i,j],matrix[k,j]
                    sol_matrix[k],sol_matrix[i] = sol_matrix[i],sol_matrix[k]
                    break
        pivot = matrix[k,k]
        for j in range(k,n):
            matrix[k,j] /= pivot
        sol_matrix[k] /= pivot

        for i in range(n):
            if i == k or matrix[i,k] == 0: continue
            factor = matrix[i,k]
            for j in range(k,n):
                matrix[i,j] -= factor * matrix[k,j]
            sol_matrix[i] -= factor*sol_matrix[k]

    return sol_matrix.tolist(), matrix.tolist()


import numpy as np
from sklearn import preprocessing

# Defining sample data

input_data = np.array([[2.1, -1.9, 5.5],
                      [-1.5, 2.4, 3.5],
                      [0.5, -7.9, 5.6],
                      [5.9, 2.3, -5.8]])

# Preprocessing data (Binarization)

data_binarized = preprocessing.Binarizer(threshold = 0.5).transform(input_data)
print("\nBinarized data:\n", data_binarized)

# Mean Removal - eliminating the mean from feature vector so every feature is centered on zero.

data_scaled = preprocessing.scale(input_data)
print("\nMean =", data_scaled.mean(axis=0))
print("Std deviation =", data_scaled.std(axis = 0))

# Scaling - the values of every feature can vary between many random values, it avoid any feature to be synthetically large or small

data_scaler_minmax = preprocessing.MinMaxScaler(feature_range=(0,1))
data_scaled_minmax = data_scaler_minmax.fit_transform(input_data)
print ("\nMin max scaled data:\n", data_scaled_minmax)

# Normalization - modify the feature vectors
# L1 - Least Absolute Deviations - This kind of normalization modifies the values so that the sum of the absolute values is always up to 1 in each row

data_normalized_l1 = preprocessing.normalize(input_data, norm = 'l1')
print("\nL1 normalized data:\n", data_normalized_l1)

# L2 - Least Squares - This kind of normalization modifies the values so that the sum of the squares is always up to 1 in each row.

data_normalized_l2 = preprocessing.normalize(input_data, norm = 'l2')
print("\nL2 normalized data:\n", data_normalized_l2)


import sys
import numpy as np
from sklearn.decomposition import PCA

path = sys.argv[1]

with open(path) as f:
    vals = f.readline().split()
    m = int(vals[0])
    n = int(vals[1])
    mat = list(map(float, f.readline().split()))

mat = np.asarray(mat)

mat = mat.reshape((m, n))

# print('M')
# print(mat)

mat_T = mat.T

# print('M Transpose')
# print(mat_T)

S = np.dot(mat_T, mat)

# print('S')
# print(S)

w, v = np.linalg.eig(S)

#print('Eigen Values')
#print(sorted(list(w),reverse=True))
l_w = sorted(list(w),reverse=True)
sum_ = np.sum(w)
# print(sum_)
k = 0
max_retention = 90.0
retention = 0
for i in range(len(l_w)):
    k += 1
    retention += l_w[i]
    if(100.0*retention/sum_ >= max_retention):
        break
# print(retention)
# print(k)
# print(np.sum(w))

# print('Eigen Vectors')
# print(v)

smat_inv = np.zeros((n, m), dtype=float)
smat_inv[:n, :n] = np.diag(1/np.sqrt(w))

smat = np.zeros((m, n), dtype=float)
smat[:n, :n] = np.diag(np.sqrt(w))

u_reg = np.dot(np.dot(mat,v),smat_inv)
# np.set_printoptions(threshold=sys.maxsize)

# print('U by mult')
# print(u_reg)
# print('M reg')
m_reg = np.dot(np.dot(u_reg,smat),v.T)
# print('Max error in regeneration = ',np.max(np.absolute(np.array(mat)-np.array(m_reg))))

u, s, vh = np.linalg.svd(mat)
# print('U')
# print(u)

# print('SIGMA')
# print(s)
# print('SIGMA INV')
# print(1/s)

print('VT')
print(vh)

pca = PCA(n_components=k)
y = pca.fit_transform(mat)
# print(y)


import numpy as np

from qr import QR

def Eigen(matrix):
    N = matrix.shape[0]
    np_dtype = np.float64
    values = np.zeros(N, dtype=np_dtype)
    vectors = np.eye(N, dtype=np_dtype)
    m = np.ascontiguousarray(matrix, dtype=np_dtype)
    for i in range(30):
        q, r = QR(m)
        np.matmul(vectors, q, out=vectors)
        np.matmul(r, q, out=m)
    for i in range(N):
        values[i] = m[i, i]
    return values, vectors

if __name__ == "__main__":
    A = np.array(
        [[1, 1, 1],
         [1, 2, 1],
         [1, 1, 2]])
    values, vectors = Eigen(A)

    values_np, vectors_np = np.linalg.eig(A)
    print('-----------test-result--------------')
    print('eigen value:\n', values)
    print('eigen vector:\n', vectors)
    print(np.matmul(A, vectors))
    print('----------------end-----------------')

    print('--------------numpy----------------')
    print('eigen value:\n', values_np)
    print('eigen vector:\n', vectors_np)
    print(np.matmul(A, vectors_np))
    print('----------------end-----------------')