import numpy as np
from PIL import Image
from matplotlib import pyplot as plt

from numpy.fft import fft2, ifft2, fftshift, ifftshift

# %% read in the image and do transform
Q6_2 = np.array(Image.open("Q6_2.tif"))
row, col = Q6_2.shape
img_fourier = fftshift(fft2(Q6_2))
img_fourier_view = np.log(np.abs(img_fourier) + 1)
plt.imshow(img_fourier_view, cmap='gray')
plt.show()

# %% butterworth low pass filter
def butterworth(d: int = 40):
    n = 10

    def _func(mu, nu):
        return 1 / (1 + ((mu - row / 2) ** 2 + (nu - col / 2) ** 2) ** n /
                    d ** (2 * n))

    return np.fromfunction(_func, (row, col)).astype(float)

butter40 = butterworth(d=40)
butter70 = butterworth(d=70)
butter85 = butterworth(d=85)

plt.figure(figsize=(9.6, 4.8))
plt.subplot(131)
plt.imshow(butter40, cmap='gray')
plt.title('Butterworth low pass filter\n$d_0=40$')
plt.subplot(132)
plt.imshow(butter70, cmap='gray')
plt.title('Butterworth low pass filter\n$d_0=70$')
plt.subplot(133)
plt.imshow(butter85, cmap='gray')
plt.title('Butterworth low pass filter\n$d_0=85$')
plt.savefig("Q6_2_b.png")
plt.show()

# %% generate degradation function
k = 0.0025
func = np.fromfunction(lambda mu, nu:
                       np.exp(-k * ((mu - row / 2) ** 2 + (nu - col / 2) ** 2) ** (5 / 6)),
                       (row, col))

plt.imshow(func, cmap='gray')
plt.show()

# %% restore the image
# img_out_fourier = img_fourier / func
img_out_fourier = np.divide(img_fourier, func)
img_out_fourier_view = np.log(np.abs(img_out_fourier) + 1)
plt.imshow(img_out_fourier_view, cmap='gray')
plt.show()

def restore(butter, fourier=img_out_fourier):
    fourier *= butter
    # fourier = np.multiply(fourier, butter)
    img_out_view = np.log10(np.abs(fourier) + 1)
    img_out = np.abs(ifft2(ifftshift(img_out_fourier)))
    return fourier, img_out_view, img_out

_, img_out_view40, img_out40 = restore(butter40)
_, img_out_view70, img_out70 = restore(butter70)
_, img_out_view85, img_out85 = restore(butter85)

plt.figure(figsize=(9.6, 6.4))
plt.subplot(231)
plt.imshow(img_out_view40, cmap='gray')
plt.title(
    'Fourier transform of\n'
    'the restored image\n'
    '(log transformed, $d_0 = 40$)')
plt.subplot(234)
plt.imshow(img_out40, cmap='gray')
plt.title('Restored image')

plt.subplot(232)
plt.imshow(img_out_view70, cmap='gray')
plt.title(
    'Fourier transform of\n'
    'the restored image\n'
    '(log transformed, $d_0 = 70$)')
plt.subplot(235)
plt.imshow(img_out70, cmap='gray')
plt.title('Restored image')

plt.subplot(233)
plt.imshow(img_out_view85, cmap='gray')
plt.title(
    'Fourier transform of\n'
    'the restored image\n'
    '(log transformed, $d_0 = 85$)')
plt.subplot(236)
plt.imshow(img_out85, cmap='gray')
plt.title('Restored image')
plt.savefig('Q6_2_2.png')
plt.show()


from scipy import stats
import numpy as np
from matplotlib import pyplot as plt

x = np.array([112,345,196,325,372,550,302,420,578])
y = np.array([1120,2523,1502,2230,2615,3400,2010,2400,2500])

a, b, r_value, p_value, std_err = stats.linregress(x,y)

plt.plot(x,y, 'ro', color='blue')

plt.xlabel('Size of the house')
plt.ylabel('Price')

plt.axis([0,600,0,3500])
plt.plot(x,x*a+b,'y')
plt.plot()

#PREDICTION !!!
newX = 200
newY = newX*a+b
print(newY)

plt.show()

#PREDICTION !!!

#newX = 150
#newY = newX*a+b

#print(newY)


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

os.system("clear")

## Create a signal with multiple frequencies
dt =  1/ 200    # 2000 Hz Signal
total_t = 3
total_samples = int(total_t / dt)
t = np.linspace(0, total_t, total_samples )  # Timestamps

# Angular Frequencies in the signal
omega_1 = 50
omega_2 = 120

# generate a signal with these two frequencies
clean_signal = np.sin(2 * np.pi * omega_1 * t) + np.sin(2 * np.pi * omega_2 * t)

# Adding Gaussian noise to the signal with a variance
variance = 0.5
noisy_signal = np.random.normal(clean_signal, variance)

# Let's also visualise only the noise
noise = noisy_signal - clean_signal

# Let's Visualise these signals
#plt.plot(t, clean_signal, "r", label = "Clean Signal")
#plt.plot(t, noisy_signal, "b",  label = "Noisy Signal")
#plt.plot(t, noise, "c", label  = "Noise")
#plt.legend()
#plt.show()

## Now that we have Our Signals setup, we will try to filter out this noise
#noisy_signal = clean_signal
# Compute discrete fourier transform of the noisy signal
len_signal = len(noisy_signal)
signal_hat = np.fft.fft(noisy_signal, len_signal)

# Calculate Power Spectral Density
PSD = signal_hat * np.conj(signal_hat) / len_signal

# Create a frequency array for plotting
frequencies = (1 / dt * len_signal) * np.arange(len_signal)

# Let's plot everything now

fig, axs = plt.subplots(2, 1)
plt.sca(axs[0])
plt.plot(t, clean_signal, "r", LineWidth = 2,  label = "Clean Signal")
plt.plot(t, noisy_signal, "b",LineWidth = 1, label = "Noisy Signal")
plt.legend()

plt.sca(axs[1])
plt.plot(frequencies, PSD, "r", LineWidth = 2,  label = "PSD")
plt.legend()
plt.show()

## Now that we have the PSD, we can see some frequencies have the most power whilst the
## most of the other frequencies have very low power. So, based on this power we will
## filter out the other frequencies

# PSD threshold: below this power we will not pickup any signal

psd_threshold = 25  # based on current PSD plot

indices = PSD > psd_threshold

# Frequencies which have power above threshold will stay. Others will be zero
PSD_clean = PSD * indices
signal_hat = indices * signal_hat

# Taking inverse fourier transform now
signal_filtered = np.fft.ifft(signal_hat)

# Let's Visualise these signals
#plt.plot(t, clean_signal, "r", label = "Clean Signal")
plt.plot(t, noisy_signal, "b",  label = "Noisy Signal")
plt.plot(t, signal_filtered, "c", label  = "Filtered Signal")
plt.legend()
plt.show()


import numpy as np
import pycuda.autoinit
import pycuda.gpuarray as gpua

import skcuda.linalg as linalg
linalg.init()

# Matrix Inverse
def matrix_inverse(A, cuda = True):
    m, n = A.shape
    transpose = False
    pinv = None

#     A is m-by-n and the rank of A is equal to m (m ≤ n) then A has right inverse A_P = At * inv(A * At)
#     A is m-by-n and the rank of A is equal to n (n ≤ m) then A has left inverse A_P = A * inv(At * A)

    if m > n:
        A = np.ascontiguousarray(A.T)
        transpose = True
    # By default this calculates the right inverse
    At = np.ascontiguousarray(A.T)
    if cuda:
        A_gpu = gpua.to_gpu(A)
        At_gpu = gpua.to_gpu(At)

        inv = linalg.inv(linalg.dot(A_gpu, At_gpu))
        pinv = linalg.dot(At_gpu, inv).get()
    else:
        inv = np.linalg.inv(A.dot(At))
        pinv = At.dot(inv)

    if transpose:
        pinv = pinv.T

    return pinv


# -*- coding: utf-8 -*-
"""
Created on Fri May 27 21:14:27 2016

@author: Michael
"""

import numpy as np
from scipy.fftpack import fft, ifft, fftfreq, fftshift
from numpy import pi

import matplotlib.pyplot as pyplot

L = 0.01
N = 800 # number of points
T = 1.0 / 200.0  # point spacing
x = np.linspace(-N*T/2., (N-1)*T/2., N) # real space sampling points
y = np.exp(-np.abs(x/L))
print 'max frequency: %s' % (1./2/T)
print 'y sum = %s, y avg = %s' % (np.sum(y), np.sum(y)/N)

yf = fft(y)
xf = fftfreq(N, T) # sampling points in frequency domain. First entry corresponds to f=0, then come frequencies in increasing order until the middle of the array. From there on negative frequencies are arranged in decreasing order, i.e. the most negative frequency comes first.
xf = fftshift(xf) # rearrange array entries suitable for display

pyplot.subplot(5, 1, 1)
pyplot.plot(x, y)
pyplot.grid()

# for non-periodic function we have to scale with T because Dirac Comb and because FFT assumes periodicity!
pyplot.subplot(5, 1, 2)
exact = 2.*L / (1 + 4*pi*pi*xf*xf*L*L)
pyplot.plot(xf, T*fftshift(np.abs(yf)))
pyplot.plot(xf, exact, label = 'exact')
pyplot.legend()
pyplot.grid()

pyplot.subplot(5, 1, 3)
y2f = 2.*L/pi / (1 + np.square(fftfreq(N,T))*L*L)
y2  = 1./(T)*fftshift(ifft(y2f))
y2exact = 2.*np.exp(-2.*pi*np.abs(x/L))
pyplot.plot(x, y2)
pyplot.plot(x, y2exact, label = 'exact')
pyplot.legend()
pyplot.grid()

pyplot.subplot(5, 1, 4)
y3f = 2.*L / (1 + np.square(pi*2.*fftfreq(N,T))*L*L)
y3  = 1./(T)*fftshift(ifft(y3f))
y3exact = np.exp(-np.abs(x/L))
pyplot.plot(x, y3)
pyplot.plot(x, y3exact, label = 'exact')
pyplot.legend()

pyplot.subplot(5, 1, 5)
ysin = np.sin(2. * 2.0*pi*x) + 0.2*np.sin(90.5 * 2.0*pi*x) # there is a factor 1/2 in the result because the amplitude contribution is distributed between the positive and negative frequency component!
yfsin = fft(ysin)
pyplot.plot(xf, 1./N*fftshift(np.abs(yfsin)))
pyplot.show()


'''
How About Stock Returns?

In the last exercise, you showed that Amazon stock prices, contained in the DataFrame AMZN follow a random walk. In this exercise. you will do the same thing for Amazon returns (percent change in prices) and show that the returns do not follow a random walk.

INSTRUCTIONS
100XP
Import the adfuller module from statsmodels.
Create a new DataFrame of AMZN returns by taking the percent change of prices using the method .pct_change().
Eliminate the NaN in the first row of returns using the .dropna() method on the DataFrame.
Run the Augmented Dickey-Fuller test on the Adj Close column of the returns DataFrame, and print out the p-value in `results[1].
'''
# Import the adfuller module from statsmodels
from statsmodels.tsa.stattools import adfuller

# Create a DataFrame of AMZN returns
AMZN_ret = AMZN.pct_change()

# Eliminate the NaN in the first row of returns
AMZN_ret = AMZN_ret.dropna()

# Run the ADF test on the return series and print out the p-value
results = adfuller(AMZN_ret['Adj Close'])
print('The p-value of the test on returns is: ' + str(results[1]))


import numpy as np

def check(A):
    dia=[];off =[]
    A=np.array(A)
    n=len(A)
    for i in range(n):
        temp=0
        for j in range(n):
            if i==j:
                dia.append(abs(A[i][j]))
            else:
                temp+=abs(A[i,j])
        off.append(temp)
    dia,off=np.array(dia),np.array(off)
    if np.all(dia > off):
       return True
    else:
         return False

def seidal(a,b,tol):
    n=len(a)
    x=np.zeros(n)
    it=0
    while True:
        x_old = np.array(x)
        for j in range(0, n):
             d = b[j]
             for i in range(0, n):
                  if j != i:
                     d-=a[j][i] * x[i]
             if a[j][j] ==0 :
                 sys.exit("divide by zero detected")
             else:
              x[j] = d / a[j][j]
        dif = abs( x- x_old)
        e=max(dif)
        it += 1
        if abs(e) <= tol:
            break
    return x,it

a=[[-4,1,0],[1,-5,1], [0,1,-3]]
b=[1,-2,1]

#a = [[-3,0,4],[1,8,6],[ 4,2, 8]]  #not dominant
#b = [4,7,3]

j,i=np.shape(a);k=len(b)
'''
if j==k and j==i :
    s=check(a)
    if s==False:
        print("Coefficient Matrix not diagonally dominant.")
    else :
         mat,itr=seidal(a,b,1e-12)
         print("Number of iterations = ",itr)
         print("Solution matrix = ",mat)
         print("Results using numpy.linalg.solve = ",np.linalg.solve(a,b))
else:
   print("Number of equations should be equal to number of variables \nand number of rows in a must be equal to number of rows in b")
'''
if j==k and j==i :
         s=check(a)
         if s==False:
             print("Coefficient Matrix not diagonally dominant.")
         elif s==True:
             print("Coefficient Matrix diagonally dominant.")
         mat,itr=seidal(a,b,1e-5)
         mat,itr=seidal(a,b,1e-5)
         print("Number of iterations = ",itr)
         print("Solution matrix = ",mat)
         print("Results using numpy.linalg.solve = ",np.linalg.solve(a,b))
else:
   print("Number of equations should be equal to number of variables \nand number of rows in a must be equal to number of rows in b")


import numpy
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import StanfordStudySensitivity as sss
from scipy import stats

#set variables

SANTA_CLARA_POP = 1928000
SANTA_CLARA_DEATHS = 100
US_POPULATION = 330000000

N = 3330
positive_tests = 50

sensitivity = 0.65
specificity = 0.995

sens_num = 78
sens_den = 85

spec_num = 369
spec_den = 371

#Simulation Parameters
OUTER_LOOPS = 1000
INNER_LOOPS = 500

class StanfordStudyMC():

	def __init__(self):
		self.sss = sss.StanfordStudySensitivity()

	def draw_bin(self,N,p):
		return numpy.random.binomial(N,p)*1.0/N

	def draw_bin_perc(self,N,p):
		try:
			return numpy.random.binomial(N,p)*1.0
		except ValueError:
			print(p)

	def simulate_adjusted_cases(self):
		sampled_pos = []

		# Draw A Specificity
		spec = self.draw_bin(spec_den,spec_num*1.0/spec_den)

		# Draw A Sensitivity
		sens = self.draw_bin(sens_den,sens_num*1.0/sens_den)
		for i in range(INNER_LOOPS):
			sampled_pos.append(self.sss.determine_adjusted_cases(N,self.draw_bin_perc(N,positive_tests*1.0/N),sens,spec))
		return sampled_pos

	def draw_distribution_given_inputs(self,times=1000):
		sampled_pos = []
		for i in range(times):
			sampled_pos.extend(self.simulate_adjusted_cases())
		return sampled_pos

	def times10(self,a):
		return a*10

	def div10(self,a, b):
		return a*1.0/10

	def plot_hist(self):
		# Set up Figure and variables
		fig = plt.figure()
		ax = fig.add_subplot(1,1,1)

		#Plot histogram
		#Adjusted upwards to make density values readable
		data = map(self.sss.adjust_to_implied_prevalence,self.draw_distribution_given_inputs(OUTER_LOOPS))
		plt.hist(data, color='#0504aa',bins=numpy.arange(0,7,0.1),normed=True,stacked=True)

		lb = numpy.percentile(data,2.5)
		ub = numpy.percentile(data,97.5)
		mean = numpy.average(data)
		# X-Axis
		plt.xlabel('Prevalence Rate')
		xticks = mtick.FormatStrFormatter('%.1f%%')
		ax.xaxis.set_major_formatter(xticks)

		plt.ylabel("Probability Density")
		yticks = mtick.FuncFormatter(self.div10)
		ax.yaxis.set_major_formatter(yticks)

		plt.title("Bootstrapped Prevalance Rates")

		plt.text(1.5,0.8,"Mean: %.2f%%\n95%% Confidence Bound: [%.2f%%,%.2f%%] " % (mean,lb,ub))

		plt.show()

if __name__=="__main__":

	ssmc = StanfordStudyMC()
	ssmc.plot_hist()


"""
행렬의 내적(dot product)
A, B, ... : 2차원 이상의 ndarray
x, y, ... : 1차원 ndarray
"""

import numpy as np
x = np.array([1, 2])
W = np.array([[3, 4],
              [5, 6]])
print(x.dot(W))
print(W.dot(x))

A = np.arange(1, 7)
print(A)
A = np.arange(1, 7).reshape((2,3))
print(A)
B = np.arange(1, 7).reshape((3,2))
print(B)
print(A.dot(B))
print(B.dot(A))

# 행렬의 내적(dot product)은 교환 법칙(AB = BA)가 성립하지 않는다.

# ndarray.shape -> (x, ), (x, y), (x, y, z), ...
x = np.array([1, 2, 3])
print(x)
print(x.shape)  # (3, )

x = x.reshape(3, 1)
print(x)
print(x.shape)


"""
Chinese Restaurant Process
--------------------------
Generative story of CRP
"""
import numpy as np

N = 10  # num of customer
alpha = 1  # dirichlet prior

C = np.zeros(N)  # cust. table assignment
K = 0  # num of current table
tables = []  # cust. for tables

for n in range(N):
    # Join a table with prob propto # of people
    p_join = np.zeros(K)

    for k in range(K):
        p_join[k] = tables[k] / (n + alpha)

    # Open new table with prob propto alpha
    p_new = alpha / (n + alpha)

    # Draw table n-th cust will join
    p = np.append(p_join, p_new)
    t = np.random.multinomial(n=1, pvals=p).argmax()

    # Update table count
    if t >= K:
        K += 1
        tables.append(0)

    C[n] = t  # assign cust n to table t
    tables[t] += 1  # increment cust count for t-th table

print(C)


# Starting code for HW 2. Add to this!
import numpy as np
from matplotlib import pyplot as plt

method = 'Newton' # enter 'Newton' or 'secant' here.

# Function definitions:
def f(x):
    f = x-np.cos(x)
    return f

def fprime(x):
    return 1+np.sin(x)

# I just showed you two different ways to return function values...

tol = 1e-12 # tolerance
xk = 0 # Initial guess x_k
xkm1 = 0 # x_{k-1}

k = [0]
residuals = [np.abs(f(xk))]

itnum = 0 # iteration counter
success = True # Assume success unless we fail!

while np.abs(f(xk))>tol:

    if method == 'Newton':
        fp = fprime(xk)
        xk = xk-f(xk)/fp
    elif method == 'secant':
        old_xk = xk
        xk -= f(xk) * (xk - xkm1) / (f(xk) - f(xkm1))
        xkm1 = old_xk
    else:
        print('No such method implemented here!')
        success = False
        break

    itnum += 1 # Clean version of itnum = itnum + 1. Works with subtraction/multiplication too!
    k.append(itnum)
    residuals.append(np.abs(f(xk)))

    if itnum>10000:
        print('Something is wrong, too many iterations, let\'s break out of this loop...!')
        success = False
        break

if success:
    # Plotting using matplotlib, imported at the top of the code.
    plt.plot(k,residuals,'o')
    plt.xlabel('$k$')
    plt.ylabel('$r_k := |f(x_k)|$')
    plt.title('Root-finding comparison')
    plt.show()


from math import ceil, floor, sqrt
from pathlib import Path
from random import randint

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf

def version_check():
    print(f'Running TensorFlow version {tf.__version__}')

def load_data(dataset):
    (x_train, y_train), (x_test, y_test) = dataset.load_data()
    return x_train, y_train, x_test, y_test

def rescale_max_1(np_array):
    if np.issubdtype(np_array.dtype, np.number):
        return np_array / np.amax(np_array)
    else:
        raise ValueError("Function can only rescale numeric values")

def describe_categorical_dataset(x_train, y_train, y_test):
    n_training_points = y_train.shape[0]
    n_test_points = y_test.shape[0]
    input_shape = x_train.shape[1:3]
    n_categories = len(np.unique(y_train))

    print(f'We have {n_training_points} training points and {n_test_points} test points')
    print(f'Each training point is an image of dimensions {input_shape}')
    print(f'Within each image, the pixels run with values from {np.amin(x_train)} to {np.amax(x_train)}')
    print(f'We see {n_categories} distinct categorical labels in the training data')

    return n_training_points, n_test_points, input_shape, n_categories

def view_image(image, class_name: str, cmap='viridis'):
    plt.xticks([])
    plt.yticks([])
    plt.imshow(image, cmap=cmap)
    plt.grid(False)
    plt.xlabel(class_name)

def view_random_image(dataset_name: str, dataset, labels, class_names, dataset_size: int):
    Path(f'./mnist/{dataset_name}').mkdir(parents=True, exist_ok=True)
    random_image = randint(1, dataset_size)

    figure = plt.figure()
    view_image(dataset[random_image], class_names[labels[random_image]])
    plt.title(f'Random image {random_image} in dataset {dataset_name}')
    plt.colorbar()
    plt.grid(False)

    plt.show()
    figure.savefig(f'./{dataset_name}/image_{random_image}.png')

def view_n_images(n_images: int, dataset_name: str, dataset, labels, class_names: list):
    Path(f'./{dataset_name}').mkdir(parents=True, exist_ok=True)
    plt_width = floor(sqrt(n_images))
    plt_height = ceil(n_images / plt_width)
    figure = plt.figure(figsize=(2 * plt_width, 2 * plt_width))

    for i in range(n_images):
        plt.subplot(plt_height, plt_width, i + 1)
        view_image(dataset[i], class_name=class_names[labels[i]], cmap=plt.cm.binary)
    plt.show()
    figure.savefig(f'./{dataset_name}/first_{n_images}_images.png')

def initialise_data(dataset, dataset_name: str, class_names: list):
    x_train, y_train, x_test, y_test = load_data(dataset)
    n_training_points, n_test_points, input_shape, n_categories = describe_categorical_dataset(x_train, y_train, y_test)
    view_random_image(dataset_name, x_train, y_train, class_names, n_training_points)
    x_train, x_test = rescale_max_1(x_train), rescale_max_1(x_test)
    view_n_images(25, dataset_name, x_train, y_train, class_names)
    return x_train, y_train, x_test, y_test, n_training_points, n_test_points, input_shape, n_categories


import numpy as np
import pandas as pd
from copy import deepcopy
from scipy.spatial import distance

X= np.array([
    [0, -6],
    [4,4],
    [0,0],
    [-5,2]])

# Euclidean Distance Caculator
def dist(a, b, ax=1):
    return np.linalg.norm(a - b, axis=ax)

# Number of clusters
k = 2
C= np.array([[-5,2], [0,-6]])

distance.cdist(C, C_old, 'cityblock')
dist(C, C_old)

# To store the value of centroids when it updates
C_old = np.zeros(C.shape)
# Cluster Lables(0, 1, 2)
clusters = np.zeros(len(X))
# Error func. - Distance between new centroids and old centroids
error = dist(C, C_old, None)
# Loop will run till the error becomes zero
while error != 0:
    # Assigning each value to its closest cluster
    for i in range(len(X)):
        distances = dist(X[i], C)
        cluster = np.argmin(distances)
        clusters[i] = cluster
    # Storing the old centroid values
        C_old = deepcopy(C)
    # Finding the new centroids by taking the average value
    for i in range(k):
        points = [X[j] for j in range(len(X)) if clusters[j] == i]
        C[i] = np.mean(points)
    error = dist(C, C_old, None)

Machine-Learning-with-Python- From-LM-to-DL/Unit 4. Unsupervised Learning/kmeans_kmediods_2.py


#gauss suicidal

import numpy as np
from scipy.linalg import solve
import collections

def gauss(A, b, x):
    L = np.tril(A)
    U = A - L
    x = np.dot(np.linalg.inv(L), b - np.dot(U, x))
    print(x)
    return x

def gausssidel(A,b,tol,lim):
    cont = 0
    x = [1, 1, 1]
    while(True):
        old = x
        x = gauss(A,b,x)
        cont = cont + 1
        tols = []
        for val1,val2 in zip(x,old):
            if((abs(val1-val2))<tol):
                tols.append(True)
            else:
                tols.append(False)
        aux = np.all(tols)
        if np.allclose(x,old) or aux or cont == lim:
            return x

A = np.array([[1.0, 0.0, -1.0], [-0.5, 1.0, -0.25], [1.0, -0.5, 1.0]])
b = [0.2, -1.425, 2.0]

val = gausssidel(A,b,1e-2,300)
print(val)


# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

def gd(X, Y, alpha=0.01, epsilon=1e-6):
    m, n = np.shape(X)
    theta = np.ones(n)
    sse2, cnt = 0, 0
    Xt = np.transpose(X)
    while True:
        hypothesis = np.dot(X, theta)
        loss = hypothesis - Y
        # sse = sum(l ** 2.0 for l in loss) / (2 * m)
        sse = np.dot(loss.T, loss) / (2 * m)

        print("[ Epoch {0} ] theta = {1}, loss = {2}, error = {3})".format(cnt, theta, loss, sse))
        cnt += 1
        if abs(sse2 - sse) < epsilon:
            break
        else:
            sse2 = sse

        gradient = np.dot(Xt, loss) / m
        theta -= alpha * gradient
    return theta

X = [(1, 1.), (1, 2.), (1, 3.), (1, 4.), (1, 5.), (1, 6.), (1, 7.), (1, 8.), (1, 9.)]
Y = [0.199, 0.389, 0.580, 0.783, 0.980, 1.177, 1.380, 1.575, 1.771]

b, a = gd(X, Y, 0.05, 1e-6)

print('y = {0} * x + {1}'.format(a, b))

x = np.array(X)
plt.plot(x, Y, 'o', label='Original data', markersize=5)
plt.plot(x, a * x + b, 'r', label='Fitted line')
plt.show()


import numpy as np
import matplotlib.pyplot as plt
import integrators as intg

# Define diff eq xdot = f(t,x,u)
def f(t, x, u):
    A = np.array([[   0,    1],
                  [-k/m, -b/m]])
    B = np.array([0, 1/m])
    state = np.array([x[0],x[1]])
    return np.dot(A,state)+np.dot(B, u)

def underdamped_mass_spring_damper(t,x,m,b,k):
    # System Dependant Solution Parameters (0<zeta<1)
    wn = np.sqrt(k/m);
    zeta = b/(2*wn*m);
    if zeta > 1:
        raise Exception('Overdamped System')
    sigma = zeta*wn
    wd = wn*np.sqrt(1-zeta**2)
    # Parameters that depend on initial state
    alpha = x[0]/2;
    beta = -(x[1]+sigma*x[0])/(2*wd);

    return np.array([2*np.exp(-sigma*t)*(alpha*np.cos(wd*t)-beta*np.sin(wd*t)),
                     2*np.exp(-sigma*t)*((-sigma*alpha-beta*wd)*np.cos(wd*t)+(sigma*beta-alpha*wd)*np.sin(wd*t))])

# System Parameters
m = 1.0; #kg
b = 0.25; #kg/s
k = 1.0; #kg/s^2

#Simulation Parameters
t = 0; x = np.array([0.0,1.0]); u = 0
tf = 30; dt = 0.1; n = int(np.floor(tf/dt));

integrator_heun = intg.Heun(dt, f);
integrator_RK4 = intg.RungeKutta4(dt, f);

t_history = [0]
x_history_RK4 = [x]
x_history_heun = [x]
x_anal_hist = [x]
err_RK4_hist = [np.array([0.0,0.0])]
err_heun_hist = [np.array([0.0,0.0])]

# Init Arrays
x_RK4 = x
x_heun = x

#Loop to integrate xdot = f(t,x,u)
for i in range(n):
    # Integrated Solution
    x_RK4 = integrator_RK4.step(t, x_RK4, u)
    x_heun = integrator_heun.step(t, x_heun, u)
    # Analytic Solution
    x_anal = underdamped_mass_spring_damper(t,x,m,b,k);
    # Error in Integrated Solution
    err_RK4 = x_RK4-x_anal
    err_heun = x_heun-x_anal
    # Step time
    t = (i+1) * dt
    # Record Values
    t_history.append(t)
    x_history_RK4.append(x_RK4)
    x_history_heun.append(x_heun)
    x_anal_hist.append(x_anal)
    err_RK4_hist.append(err_RK4)
    err_heun_hist.append(err_heun)

intg.__doc__
sz = 5
plt.figure(figsize=(8, 8),dpi=800)
fig, axs = plt.subplots(2, 1, constrained_layout=True)
axs[0].plot(t_history, x_history_RK4, '-', t_history, x_anal_hist)
axs[0].set_title('Numerical vs. Analytical States')
axs[0].set_xlabel('Time(s)')
axs[0].set_ylabel('Amplitude')
axs[0].legend(['Numerical Position', 'Numerical Velocity','Analytical Position', 'Analytical Velocity'],loc='upper right', prop={'size': sz})
fig.suptitle('RK4, dt = '+str(dt)+'s', fontsize=16)

axs[1].plot(t_history, err_RK4_hist)
axs[1].set_xlabel('Time(s)')
axs[1].set_title('State Errors')
axs[1].set_ylabel('Amplitude')
axs[1].legend(['Position Error', 'Velocity Error'],loc='upper right', prop={'size': sz})
plt.show()


import numpy as np
import pandas as pd
from scipy.stats import binom_test

def simulation_binomial_test(observed_successes, n, p):
  #initialize null_outcomes
  null_outcomes = []

  #generate the simulated null distribution
  for i in range(observed_successes):
    simulated_monthly_visitors = np.random.choice(['y', 'n'], size=n, p=[p, 1-p])
    num_purchased = np.sum(simulated_monthly_visitors == 'y')
    null_outcomes.append(num_purchased)

  #calculate a 1-sided p-value
  null_outcomes = np.array(null_outcomes)
  p_value = np.sum(null_outcomes <= 41)/len(null_outcomes)

  #return the p-value
  return p_value

#Test your function below by uncommenting the code below. You should see that your simulation function gives you a very similar answer to the binom_test function from scipy:

p_value1 = simulation_binomial_test(45, 500, .1)
print("simulation p-value: ", p_value1)

p_value2 = binom_test(45, 500, .1, alternative = 'less')
print("binom_test p-value: ", p_value2)

Data Scientist Career Path/8. Hypothesis Testing/1. Testing a Sample Statistics/2. Binomial Test/10. write.py


import numpy as np

returns_disney = [0.22, 0.12, 0.01, 0.05, 0.04]
returns_cbs = [-0.13, -0.15, 0.31, -0.06, -0.29]

variance_disney = np.var(returns_disney)
variance_cbs = np.var(returns_cbs)

# Write code here
dataset = [10, 8, 9, 10, 12]

def calculate_variance(dataset):
  mean = sum(dataset) / len(dataset)
  numerator = 0
  for dat in dataset:
    numerator += (dat - mean) ** 2
  variance = numerator / len(dataset)
  return variance

variance_disney = calculate_variance(returns_disney)
variance_cbs = calculate_variance(returns_cbs)

print('The variance of Disney stock returns is', variance_disney)
print('The variance of CBS stock returns is', variance_cbs)

#EQUATION:
#σ^2= Σ(Xi − X)^2/n

    #σ^2: variance
    #Xi: the ith value in the dataset
    #X̄: the mean of the dataset
    #n: the number of values in the dataset


# Anil Osman TUR
# 12290551
#
# Kruskal algorithm for Minimum spanning tree
# step 1: sort the edges in ascending order
# step 2: if the edge won't create a cycle add edge to the spanning tree
# step 3: do the step 3 for all edges in the order

# to understand the cycle find set and make set functions will used
from graphClass import Graph

import numpy as np

def getKey(item):
    return item[2]

def mst_kruskal( graph ):
    A = [] # selected edges

    for v in graph.vertexes:
        graph.make_set(v)

    # sort edges in non-rising order
    sorted_edges = sorted(graph.edges, key=getKey)

    for edge in sorted_edges:
        if graph.find_set(edge[0]) != graph.find_set(edge[1]):
            A.append(edge)
            graph.union(edge[0], edge[1])
    return A

# test  #

#dgesW = [[0,1,3], [0,3,6], [0,4,9], [1,5,5], [2,5,4], [2,3,2] ,[3,5,3], [3,4,1], [4,5,7]]
#graph = Graph(edgesW)
#print "Graph :"
#print graph.getMat()
#print graph.edges
#tree = np.array(mst_kruskal(graph))
#print "tree :"
#print tree
#print graph.vertex_sets

#print "changes :"
#e_n = len(edgesW)
#t_n = len(tree)
#changes = []
#for i in range(e_n):
#    for j in range(t_n):
#        if np.array_equal(edgesW[i], tree[j]):
#           changes.append(i)
#print changes

#print "tree :"
#graphT = Graph(tree)
#print graphT.getMat()
#print graphT.edges


import numpy as np
import matplotlib.pyplot as plt

xi = np.array((-1, 0, 1, 2, 3, 4, 5, 6))
yi = np.array((10, 9, 7, 5, 4, 3, 0, -1))
n = len(xi)

xi2 = np.ones(n)
xy = np.ones(n)

for i in range(n):
    xi2[i] = xi[i]** 2
    xy[i] = xi[i] * yi[i]

def somatorio(x):
    soma = 0
    for i in range(len(x)):
        soma += x[i]
    return soma

#(somatorio(xi), somatorio(yi), somatorio(xi2), somatorio(xy))

s = np.ones(4)

s[0] = somatorio(xi)
s[1] = somatorio(yi)
s[2] = somatorio(xi2)
s[3] = somatorio(xy)

mat = np.ones((2, 2))
b = np.array((s[3], s[1]))

mat[0][0] = s[2]
mat[0][1] = s[0]

mat[1][0] = s[0]
mat[1][1] = n

x = np.linalg.solve(mat, b)
print(f'a = {x[0]}, b = {x[1]}')

########################### plotando os pontos
#### y = ax+b
plt.plot(xi, yi, 'ro')

d = np.linspace(-2, 7, 10)
dx = np.ones(10)

for i in range(len(d)):
    dx[i] = x[0]*d[i] + x[1]

plt.plot(d, dx)
plt.show()


import numpy as np
from scipy import constants
from scipy import special
import matplotlib.pyplot as plt

Q = 10**-13
l = 1

#defining simpsons rule
def simpsonsRule(f,a,b,N):
    h = (b-a)/N
    oddSum = 0
    for k in range(1, N, 2):
        oddSum += f(a+k*h)
    evenSum = 0
    for k in range(2, N, 2):
        evenSum += f(a+k*h)
    integral = (h/3)*(f(a)+f(b)+4*oddSum+2*evenSum)
    return integral

#defining constants for simpson's rule where N is the number of slices
#a is the lower bound and b is the upper bound
N = 60
a = -constants.pi/2
b = constants.pi/2

#defining eq 3
def V(z, r):
    #function generator for each z and r
    def f(u):
        return (Q*np.exp(-(np.tan(u))**2))/(4*np.pi*constants.epsilon_0*(np.cos(u)**2)*np.sqrt(((z-l*np.tan(u))**2)+r**2))
    #calculate the integral
    integral = simpsonsRule(f, a, b, N)
    return integral

#defining eq 4
def Vzero(r):
    return (Q/(4*np.pi*constants.epsilon_0*l))*np.exp(r**2/(2*l**2))*special.kn(0,r**2/(2*l**2))

#initialize lists to store respective results
VResults = []
VZeroResults = []
#creating a data set of radius from 0.25mm to 5.0mm with 238 entries
radiusRange = np.arange(0.25, 5.0, 0.02)
for r in radiusRange:
    #storing results to each list
    VResults.append(V(0, r))
    VZeroResults.append(Vzero(r))

#comparison of the results to ensure accuracy and check for fractional error
print('my method', np.sum(VResults))
print('V with z=0', np.sum(VZeroResults))

#plotting the 2 methods to check if it is accurate
fig1, overlay = plt.subplots(figsize=(8, 6))
overlay.plot(radiusRange, VZeroResults, label='eq(4) results')
overlay.plot(radiusRange, VResults, dashes=[6,2], label='eq(3) results')
overlay.set(xlabel='radius (mm)', ylabel='Voltage (V)',
       title='Overlay of V(r, z=0) and V(r,0)')
overlay.grid()
overlay.legend()
fig1.savefig("q4.png", dpi=150)
plt.show()

#part b
#creating a range of z from -5mm to 5mm with 200 entries
zRange = np.arange(-5, 5, 0.05)
#creating a 2D array that is currently filled with 0 with zRange rows and radiusRange columns
VzResults = [[0 for z in range(len(zRange))] for r in range(len(radiusRange))]

for r in range(len(radiusRange)):
    for z in range(len(zRange)):
        #update the 2D array respective values
        VzResults[r][z] = V(zRange[z], radiusRange[r])

#plot contour graph
X, Y = np.meshgrid(zRange, radiusRange)

fig2, contour = plt.subplots(figsize=(10, 8))
CS = contour.contour(X, Y, VzResults, extent=(-5, 5, -0, 5))
contour.set(xlabel='z range (mm)', ylabel='radius range (mm)',
       title='Contour graph of Voltage (V)')
CB = fig2.colorbar(CS, shrink=0.8, extend='both')
contour.clabel(CS, inline=1, fontsize=10)
contour.grid()
fig2.savefig("q4_2.png", dpi=150)
plt.show()


import numpy as np

def spectral_radius(A):
    assert A.ndim == 2
    assert A.shape[0] == A.shape[1]

    return np.max(np.abs(np.linalg.eigvals(A)))

def check_stability(A, eps=1e-6):
    assert A.ndim == 2
    assert A.shape[0] == A.shape[1]

    return spectral_radius(A) < 1 - eps

# P(empirical - E(unstable) >= eps) <= exp(-2 n eps**2) <= alpha
# n >= (1/(2eps**2)) * log(1/alpha) with alpha in (0,1), eps > 0
def one_sided_hoeffding_sample_bound(alpha=0.001, eps=0.005):
    return int(np.ceil(1./(2 * eps**2) * np.log(1/alpha)))

class LinearStabilityAnalysis:

    def __init__(self, uncertainStateSpaceModel, K, settings):
        self.K = K
        self.ussm = uncertainStateSpaceModel
        self.V = self.ussm.omega_var

        self.controllability_tol = settings.synthesis_settings['controllability_tol']

        self.confidence_interval = settings.synthesis_settings['confidence_interval']

        self.As = list()
        self.Bs = list()

    # Checks the probability of being stable w.r.t. the distribution of the state space model uncertainty
    # P(empirical - E(unstable) >= eps) <= exp(-2 n eps**2) <= alpha
    def p_stability(self, alpha=0.001, eps=0.01):

        sample_list = list()

        samples = one_sided_hoeffding_sample_bound(alpha=alpha, eps=eps)
        print('Check stability based on {} samples'.format(samples))

        if len(self.As) < samples:
            As, Bs = self.ussm.sample(n=samples,
                                      c=self.confidence_interval,
                                      controllability_tol=self.controllability_tol)
            self.As, self.Bs = As, Bs

        for A, B in zip(self.As, self.Bs):

            A_cl = A + B @ self.K
            stable = check_stability(A_cl)
            sample_list.append(stable)

        return np.mean(sample_list)


import os

""" First change the following directory link to where all input files do exist """
os.chdir("D:\\Book writing\\Codes\\Chapter 2")

import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
import seaborn as sns
#from sklearn.model_selection import train_test_split
#from sklearn.metrics import r2_score

wine_quality = pd.read_csv("winequality-red.csv",sep=';')
# Step for converting white space in columns to _ value for better handling
wine_quality.rename(columns=lambda x: x.replace(" ", "_"), inplace=True)

# Simple Linear Regression - chart
model = sm.OLS(wine_quality['quality'],sm.add_constant(wine_quality['alcohol'])).fit()

print (model.summary())

plt.scatter(wine_quality['alcohol'],wine_quality['quality'],label = 'Actual Data')
plt.plot(wine_quality['alcohol'],model.params[0]+model.params[1]*wine_quality['alcohol'],
         c ='r',label="Regression fit")
plt.title('Wine Quality regressed on Alchohol')
plt.xlabel('Alcohol')
plt.ylabel('Quality')
plt.show()

# Simple Linear Regression - Model fit
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score

wine_quality = pd.read_csv("winequality-red.csv",sep=';')
wine_quality.rename(columns=lambda x: x.replace(" ", "_"), inplace=True)

x_train,x_test,y_train,y_test = train_test_split(wine_quality['alcohol'],wine_quality["quality"],train_size = 0.7,random_state=42)

x_train = pd.DataFrame(x_train);x_test = pd.DataFrame(x_test)
y_train = pd.DataFrame(y_train);y_test = pd.DataFrame(y_test)

def mean(values):
    return round(sum(values)/float(len(values)),2)

alcohol_mean = mean(x_train['alcohol'])
quality_mean = mean(y_train['quality'])

alcohol_variance = round(sum((x_train['alcohol'] - alcohol_mean)**2),2)
quality_variance = round(sum((y_train['quality'] - quality_mean)**2),2)

covariance = round(sum((x_train['alcohol'] - alcohol_mean) * (y_train['quality'] - quality_mean )),2)
b1 = covariance/alcohol_variance
b0 = quality_mean - b1*alcohol_mean
print ("\n\nIntercept (B0):",round(b0,4),"Co-efficient (B1):",round(b1,4))
y_test["y_pred"] = pd.DataFrame(b0+b1*x_test['alcohol'])
R_sqrd = 1- ( sum((y_test['quality']-y_test['y_pred'])**2) / sum((y_test['quality'] - mean(y_test['quality']))**2 ))
print ("Test R-squared value:",round(R_sqrd,4))

# Plots - pair plots
eda_colnms = [ 'volatile_acidity',  'chlorides', 'sulphates', 'alcohol','quality']
sns.set(style='whitegrid',context = 'notebook')
sns.pairplot(wine_quality[eda_colnms],size = 2.5,x_vars= eda_colnms,y_vars=eda_colnms)
plt.show()

# Correlation coefficients
corr_mat = np.corrcoef(wine_quality[eda_colnms].values.T)
sns.set(font_scale=1)
full_mat = sns.heatmap(corr_mat, cbar=True, annot=True, square=True, fmt='.2f',
                       annot_kws={'size': 15}, yticklabels=eda_colnms, xticklabels=eda_colnms)

plt.show()

# Multi linear regression model
colnms = [ 'volatile_acidity',  'chlorides', 'free_sulfur_dioxide', 'total_sulfur_dioxide',
 'pH', 'sulphates', 'alcohol']

pdx = wine_quality[colnms]
pdy = wine_quality["quality"]

x_train,x_test,y_train,y_test = train_test_split(pdx,pdy,train_size = 0.7,random_state=42)
x_train_new = sm.add_constant(x_train)
x_test_new = sm.add_constant(x_test)

#random.seed(434)
full_mod = sm.OLS(y_train,x_train_new)
full_res = full_mod.fit()
print ("\n \n",full_res.summary())

print ("\nVariance Inflation Factor")
cnames = x_train.columns
for i in np.arange(0,len(cnames)):
    xvars = list(cnames)
    yvar = xvars.pop(i)
    mod = sm.OLS(x_train[yvar],sm.add_constant(x_train_new[xvars]))
    res = mod.fit()
    vif = 1/(1-res.rsquared)
    print (yvar,round(vif,3))

# Predition of data
y_pred = full_res.predict(x_test_new)
y_pred_df = pd.DataFrame(y_pred)
y_pred_df.columns = ['y_pred']
pred_data = pd.DataFrame(y_pred_df['y_pred'])
y_test_new = pd.DataFrame(y_test)
#y_test_new.reset_index(inplace=True)

pred_data['y_test'] = pd.DataFrame(y_test_new['quality'])

# R-square calculation
rsqd = r2_score(y_test_new['quality'].tolist(), y_pred_df['y_pred'].tolist())
print ("\nTest R-squared value:",round(rsqd,4))

# Ridge Regression
from sklearn.linear_model import Ridge

wine_quality = pd.read_csv("winequality-red.csv",sep=';')
wine_quality.rename(columns=lambda x: x.replace(" ", "_"), inplace=True)

all_colnms = ['fixed_acidity', 'volatile_acidity', 'citric_acid', 'residual_sugar',
 'chlorides', 'free_sulfur_dioxide', 'total_sulfur_dioxide', 'density',
 'pH', 'sulphates', 'alcohol']

pdx = wine_quality[all_colnms]
pdy = wine_quality["quality"]

x_train,x_test,y_train,y_test = train_test_split(pdx,pdy,train_size = 0.7,random_state=42)

alphas = [1e-4,1e-3,1e-2,0.1,0.5,1.0,5.0,10.0]

initrsq = 0

print ("\nRidge Regression: Best Parameters\n")
for alph in alphas:
    ridge_reg = Ridge(alpha=alph)
    ridge_reg.fit(x_train,y_train)
    tr_rsqrd = ridge_reg.score(x_train,y_train)
    ts_rsqrd = ridge_reg.score(x_test,y_test)

    if ts_rsqrd > initrsq:
        print ("Lambda: ",alph,"Train R-Squared value:",round(tr_rsqrd,5),"Test R-squared value:",round(ts_rsqrd,5))
        initrsq = ts_rsqrd

# Coeffients of Ridge regression of best alpha value
ridge_reg = Ridge(alpha=0.001)
ridge_reg.fit(x_train,y_train)

print ("\nRidge Regression coefficient values of Alpha = 0.001\n")
for i in range(11):
    print (all_colnms[i],": ",ridge_reg.coef_[i])

# Lasso Regression
from sklearn.linear_model import Lasso

alphas = [1e-4,1e-3,1e-2,0.1,0.5,1.0,5.0,10.0]
initrsq = 0
print ("\nLasso Regression: Best Parameters\n")

for alph in alphas:
    lasso_reg = Lasso(alpha=alph)
    lasso_reg.fit(x_train,y_train)
    tr_rsqrd = lasso_reg.score(x_train,y_train)
    ts_rsqrd = lasso_reg.score(x_test,y_test)

    if ts_rsqrd > initrsq:
        print ("Lambda: ",alph,"Train R-Squared value:",round(tr_rsqrd,5),"Test R-squared value:",round(ts_rsqrd,5))
        initrsq = ts_rsqrd

# Coeffients of Lasso regression of best alpha value
lasso_reg = Lasso(alpha=0.001)
lasso_reg.fit(x_train,y_train)

print ("\nLasso Regression coefficient values of Alpha = 0.001\n")
for i in range(11):
    print (all_colnms[i],": ",lasso_reg.coef_[i])

Module 1/Sample Code/Chapter02/Chapter 02_Parallelism of Statistics and Machine Learning.py


'''Write a function matrix_det(matrix_A) that calculates the determinant (an integer) of matrix A if it is a 1x1 or 2x2 matrix.
If the input matrix is not square, print this error message "Cannot calculate determinant of a non-square matrix."
If the input matrix is square but has a higher dimension, print the error message "Cannot calculate determinant of a n-by-n matrix", where you substitute n with the dimension of the input matrix.'''

import math
import numpy as np

def matrix_det(matrix_A):
    if matrix_A.shape[0] > 2  or matrix_A.shape[1] > 2:
        print( "Cannot calculate determinant of a {0}-by-{1} matrix".format(A.shape[0], A.shape[1]))
        return
    if matrix_A.shape[0] != matrix_A.shape[1]:
        print("Cannot calculate determinant of a non-square matrix.")
        return
    x = matrix_A.shape[0]
    y = matrix_A.shape[1]
    if x == 1: return matrix_A[0][0]
    return matrix_A.item(0, 0)*matrix_A.item(1, 1) - matrix_A.item(1, 0)*matrix_A.item(0, 1)

A = np.matrix([[1, 2],
               [3, 4]])
B= np.matrix([[1]])
print(matrix_det(A))
print(np.linalg.det(A))


import numpy as np
def rand_pd(dim):
    """
    随机生成一个正定矩阵，维度为dim
    Input:
       dim: 矩阵的维度
    Output:
       M: 正定矩阵
    """
    A = np.random.randn(dim)[:, np.newaxis] # shape=(dim, 1)
    M = A.dot(A.T)
    eig_vals, _ = np.linalg.eig(M)
    while not np.all(eig_vals > 0):
        M += np.diag(0.001*np.ones(dim))
        eig_vals, _ = np.linalg.eig(M)
    return M

#  测试代码
if __name__ == "__main__":
    test_M = rand_pd(4)
    eigs, _ = np.linalg.eig(test_M)
    print(np.all(eigs > 0))


import matplotlib.pylab as pl
import random
import math
import numpy as np

# NumRep Checkpoint1 class for muon decay simulations
# Simon McLaren

class muonPDF:

    def __init__(self, muonLifetime, mint, maxt): # Float, float, float
        self.tau  = float(muonLifetime)
        self.mint = float(mint)
        self.maxt = float(maxt)

    # Returns the value of the PDF at a particular time
    def evaluatePDF(self, time):
        return float((1 / self.tau) * math.exp(-(time / self.tau)))

    # Draws a random decay time from the PDF using the box method
    def drawRandomNumBoxMethod(self):
        fmax = self.evaluatePDF(0.)
        y2 = 10.
        y1 = 1.
        while y2 > y1:
            randomt = self.mint + (self.maxt - self.mint) * random.random()
            y1 = self.evaluatePDF(randomt)
            y2 = fmax * random.random()
        return randomt

    # Simulates N decays using the PDF, returning the list of decay times and the mean of the decay times
    def simulateNDecays(self, numOfMuonDecays): # Integer
        decayTimes = np.empty(numOfMuonDecays)
        for i in range(numOfMuonDecays):
            decayTimes[i] = self.drawRandomNumBoxMethod()
        return decayTimes, np.mean(decayTimes)

    # Writes an array of decay times to an output file
    def writeDecayTimesToFile(self, outputFileName, decayTimes): # String, integer
        muonDecayTimesOutputFile = open(outputFileName, "w")
        for decayTime in decayTimes:
            muonDecayTimesOutputFile.write("{0:f}\n".format(decayTime))
        muonDecayTimesOutputFile.close()

    # Produces and saves a histogram of given data
    def saveHistogram(self, data, numBins, outputFileName, xlabel, title): # Array/list, integer, string, string, string
        pl.hist(data[:], bins=numBins)
        pl.xlabel(xlabel)
        pl.title(title)
        pl.savefig(outputFileName)

    # Simulate N experiments with M decay times and return the N muon lifetimes, their mean and standard deviation
    def simulateNExperiments(self, numOfExperiments, numOfMuonDecays):
        muonLifetimes = np.empty(numOfExperiments)
        for i in range(numOfExperiments):
            currentDecayTimesList, muonLifetimes[i] = self.simulateNDecays(numOfMuonDecays)
        return muonLifetimes, np.mean(muonLifetimes), np.std(muonLifetimes)

# Testing
if __name__ == "__main__":
    myMuonDistribution = muonPDF(2.2, 0., 15.)
    # Simulate 500 experiments with 1000 muon decays each
    muonLifetimes, meanLifetime, stdLifetime = myMuonDistribution.simulateNExperiments(500, 1000)
    print meanLifetime, stdLifetime
    myMuonDistribution.saveHistogram(muonLifetimes, 100, "muonlifetimehistogram.png",
                                     "Estimated Muon Lifetime (microseconds)",
                                     "Hisogram of Muon Lifetimes")


# optimize convex objective function
from numpy import arange
from scipy.optimize import minimize_scalar
from matplotlib import pyplot

# objective function
def objective(x):
	return (5.0 + x)**2.0

# minimize the function
result = minimize_scalar(objective, method='brent')
# summarize the result
opt_x, opt_y = result['x'], result['fun']
print('Optimal Input x: %.6f' % opt_x)
print('Optimal Output f(x): %.6f' % opt_y)
print('Total Evaluations n: %d' % result['nfev'])
# define the range
r_min, r_max = -10.0, 10.0
# prepare inputs
inputs = arange(r_min, r_max, 0.1)
# compute targets
targets = [objective(x) for x in inputs]
# plot inputs vs target
pyplot.plot(inputs, targets, '--')
# plot the optima
pyplot.plot([opt_x], [opt_y], 's', color='r')
# show the plot
pyplot.show()


import numpy as np

def de_casteljau(t, control_net, return_diagonals=False):
    """
    Returns a point on the Bezier curve respect a given parameter.

    This function applies de Casteljau algorithm, using a
    constructive approach (ie, the geometric one).

    Given a control net, it produces a tuple (p, ud, ld) such that:
        - p is the point on the Bezier curve that interpolate the control net;
        - ud is an array containing points on the upper diagonal for curve splitting;
        - ld is an array containing points on the lower diagonal for curve splitting.
    Observe that to get the triple with diagonals, the argument `return_diagonals`
    should be set to `True`, otherwise only a point is returned.

    This function is persistent respect the given control net, ie it doesn't
    change the given net but, working on a copy of it (requires little extra time to
    make a copy of it, this is included in big-O complexity).

    The overall complexity is O(n^2), where n is the number of control points.
    """

    n, d = dimensions = np.shape(control_net)

    Q = np.copy(control_net)

    upper_diagonal = np.empty(dimensions)
    lower_diagonal = np.empty(dimensions)

    upper_diagonal[0,:] = Q[0,:]
    lower_diagonal[0,:] = Q[-1,:]

    for k in range(1,n):

        for i in range(n-k): Q[i,:] = (1-t)*Q[i,:] + t*Q[i+1,:]

        upper_diagonal[k,:] = Q[0,:]
        lower_diagonal[k,:] = Q[-(k+1),:]

    point = Q[0,:]

    return (point, upper_diagonal, lower_diagonal) if return_diagonals else point

def de_casteljau_surface(params, control_net):
    """
    Produces a point on the Bezier surface.

    Examples
    ========

    The following example works on a square control net:
    >>> b00 = np.array([0, 0, 0])
    >>> b01 = np.array([2, 0, 0])
    >>> b02 = np.array([4, 0, 0])
    >>> b10 = np.array([0, 2, 0])
    >>> b11 = np.array([2, 2, 0])
    >>> b12 = np.array([4, 2, 2])
    >>> b20 = np.array([0, 4, 0])
    >>> b21 = np.array([2, 4, 4])
    >>> b22 = np.array([4, 4, 4])
    >>> control_net = np.array([[b00,b01,b02],\
                                [b10,b11,b12],\
                                [b20,b21,b22]], dtype="float")
    >>> u,v = .5, .5
    >>> point = de_casteljau_surface((u,v), control_net)
    >>> point
    array([ 2.,  2.,  1.])
    """

    control_net = np.copy(control_net)

    u, v = params

    rows, cols, d = np.shape(control_net)

    square = min(rows, cols)

    def combine_col(r, c):
        return (1-v)*control_net[r, c, :] + v*control_net[r, c+1, :]

    def combine_row(r, c):
        return (1-u)*control_net[r, c, :] + u*control_net[r+1, c, :]

#   Combine the largest square in the control net from the top-left corner
    for k in range(square-1):
        for r in range(square-k):
            for c in range(square-k-1): control_net[r, c, :] = combine_col(r, c)

        # after the previous loops we've eliminated the rightmost column
        for c in range(square-k-1):
            for r in range(square-k-1): control_net[r, c, :] = combine_row(r, c)

    point = control_net[0, 0, :]

    if cols > square:
#       Combine remaining cols if any, using de Casteljau algorithm for curve case

        def de_casteljau_on_col(c): return de_casteljau(u,control_net[:, c, :])

        intermediate_row = np.array([de_casteljau_on_col(c)
                                        for c in range(square-1, cols)] )

        point = de_casteljau(v, np.vstack((point, intermediate_row)))

    elif rows > square:
#       Combine remaining rows if any, using de Casteljau algorithm for curve case

        def de_casteljau_on_row(r): return de_casteljau(v,control_net[r, :, :])

        intermediate_col = np.array([de_casteljau_on_row(r)
                                        for r in range(square-1, rows)] )

        point = de_casteljau(u, np.vstack((point, intermediate_col)))

    else: pass # square control net already handled

    return point

def naive_de_casteljau(control_net, tabs=None, squares_per_dim=20):
    """
    Naive implementation of de Casteljau algorithm for tensor product patches.
    """

    squares_per_dim *= 10

    if tabs is None:
        tabs = (np.linspace(0,1, squares_per_dim),
                np.linspace(0,1, squares_per_dim))

    X, Y = tabs

    X, Y = np.meshgrid(X, Y)

    surface = np.array([de_casteljau_surface((u,v), control_net)
                            for u,v in zip(np.ravel(X),np.ravel(Y))])

    return surface, X.shape

def vectorized_de_casteljau(control_net, tabs=None, squares_per_dim=20):
    """
    Vectorized implementation of de Casteljau algorithm for tensor product patches.
    """

    squares_per_dim *= 10

    if tabs is None:
        tabs = (np.linspace(0,1, squares_per_dim),
                np.linspace(0,1, squares_per_dim))

    u_tab, v_tab = tabs

#   Sestini's code calls `m` what we call `rows` and
#   calls `n` what we call `cols`.
    rows, cols, d = np.shape(control_net)

    k = min(rows, cols)
    mtab, ntab = len(u_tab), len(v_tab)
    u_tab, v_tab = np.meshgrid(u_tab, v_tab)
    shape = u_tab.shape
    u_tm, v_tm = 1-u_tab, 1-v_tab

    surface = np.zeros((mtab, ntab, d, rows, cols))

    def initialize(it, jt, i_d):
        surface[it, jt, i_d, :, :] = control_net[:, :, i_d]

    [initialize(it, jt, i_d)    for it in range(mtab)
                                for jt in range(ntab)
                                for i_d in range(d)]

    def update_square(i_d, i, j):
        uv_tm_tm = np.multiply(u_tm, v_tm)
        uv_tm_tab = np.multiply(u_tm, v_tab)
        uv_tab_tm = np.multiply(u_tab, v_tm)
        uv_tab_tab = np.multiply(u_tab, v_tab)
        surface[:, :, i_d, i, j] = (
                np.multiply(uv_tm_tm, surface[:, :, i_d, i, j])
                + np.multiply(uv_tm_tab, surface[:, :, i_d, i, j+1])
                + np.multiply(uv_tab_tm, surface[:, :, i_d, i+1, j])
                + np.multiply(uv_tab_tab, surface[:, :, i_d, i+1, j+1]))

#   Combine in square block as much as `k` allow
    for s in range(1, k):
        [update_square(i_d, i, j)   for i_d in range(d)
                                    for i in range(rows-s)
                                    for j in range(cols-s) ]

    def update_along_u(i_d, i):
        surface[:, :, i_d, i, 0] = (np.multiply(u_tm, surface[:, :, i_d, i, 0]) +
                np.multiply(u_tab, surface[:, :, i_d, i+1, 0]))

#   Complete combining along `u` direction if any
    for r in range(rows-k):
        [update_along_u(i_d, i) for i_d in range(d)
                                for i in range(rows-k-r)]

    def update_along_v(i_d, j):
        surface[:, :, i_d, 0, j] = (np.multiply(v_tm, surface[:, :, i_d, 0, j]) +
                np.multiply(v_tab, surface[:, :, i_d, 0, j+1]))

#   Complete combining along `v` direction if any
    for c in range(cols-k):
        [update_along_v(i_d, j) for i_d in range(d)
                                for j in range(cols-k-c)]

#   Clean parameterization values away from `surface` structure
    surface = np.array([surface[i,j,:, 0, 0]    for i in range(mtab)
                                                for j in range(ntab)])

    return surface, shape


"""
Author : Achintya Gupta
Date Created : 22-09-2020
"""

"""
Problem Statement
------------------------------------------------
Q) Consider all integer combinations of ab for 2 ≤ a ≤ 5 and 2 ≤ b ≤ 5:

            2^2=4, 2^3=8, 2^4=16, 2^5=32
            3^2=9, 3^3=27, 3^4=81, 3^5=243
            4^2=16, 4^3=64, 4^4=256, 4^5=1024
            5^2=25, 5^3=125, 5^4=625, 5^5=3125

    If they are then placed in numerical order, with any repeats removed, we get the following sequence of 15 distinct terms:
    4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125
    How many distinct terms are in the sequence generated by ab for 2 ≤ a ≤ 100 and 2 ≤ b ≤ 100?
"""
from utils import timing_decorator
import numpy as np

@timing_decorator
def count_distinct(a_min=2, a_max=100, b_min=2, b_max=100):
    nums = set()
    for b in range(b_min,b_max+1):
        for a in range(a_min,a_max+1):
            nums = nums.union([a**b])
    print(f'Number of disctinct numbers : ', len(nums))

count_distinct()


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

df = pd.read_csv("landslide_data3.csv")         #Reading the file

#Question 1

df = df.drop(columns=['dates', 'stationid'])

for key in df.keys():
    vals = []
    _, box = df.boxplot(column=[key], return_type='both')                       #Making boxplot to fetch outliers
    outliers = [flier.get_ydata() for flier in box["fliers"]]
    for i, record in df.iterrows():
        if record[key] in outliers[0]:
            vals.append(i)
    dfd = df.drop(vals)
    for val in vals:
        df.loc[val , key] = dfd[key].median()                                   #Replacing outliers with medians

plt.clf()

#Question 1a

min = df.min()
max = df.max()

print("Before Normalisation")
print('Dictionary of Minimum Values')
print(min)
print('Dictionary of Maximum Values')
print(max)

diff = max - min
df1a = (df - min)/diff * 6 + 3

min1a = df1a.min()
max1a = df1a.max()

print("After Normalisation")
print('Dictionary of Minimum Values')
print(min1a)
print('Dictionary of Maximum Values')
print(max1a)

#Question 1b

avg = df.mean()
sd = df.std()

print("Before Standardisation")
print('Mean')
print(avg)
print('Standard Deviation')
print(sd)

df1b = (df - avg)/sd

avg1b = df1b.mean()
sd1b = df1b.std()

print("After Standardisation")
print('Mean')
print(avg1b)
print('Standard Deviation')
print(sd1b)

#Question 2

covar = [[5, 10], [10, 13]]
D = np.random.multivariate_normal(mean = [0,0], cov = covar, size = 1000, check_valid = 'ignore')
D = pd.DataFrame(D, columns=['A', 'B'])
# Creating the 2-dimensional synthetic data with mean, μ = [0, 0]T and covariance matrix, Σ = [[5, 10], [10, 13]].

#Question 2a
plt.scatter(D['A'], D['B'])
plt.show()

#Question 2b
cov_matrix = np.dot(np.transpose(D), D)/1000
val, vec = np.linalg.eig(cov_matrix)            #This gives Eigenvectors and Eigenvalues from the Covariance Matrix
print('The eigenvalues are:')
print(val)
print('The eigenvectors are:')
print(vec)

plt.scatter(D['A'], D['B'])
plt.quiver(0, 0, vec[0][0], vec[1][0], scale=5, angles = 'xy')
plt.quiver(0, 0, vec[0][1], vec[1][1], scale=2, angles = 'xy')
plt.show()

#Question 2c

A = np.dot(D, vec)

for i in range(2):
    xx = []
    yy = []
    for d in A:
        xx.append(d[i]*vec[0][i])                       #x-coordinate of data projected along the Ith Eigenvector
        yy.append(d[i]*vec[1][i])                       #y-coordinate of data projected along the Ith Eigenvector
    plt.scatter(D['A'], D['B'])
    plt.scatter(xx, yy)
    plt.quiver(0, 0, vec[0][0], vec[1][0], scale=5, angles = 'xy')
    plt.quiver(0, 0, vec[0][1], vec[1][1], scale=2, angles = 'xy')
    plt.show()

#Question 2d

pca = decomposition.PCA(n_components = 2)
proj = pca.fit_transform(D)
#This fucntion helps us directly find the data as projected along the first n-most significant eigenvectors where
#n is already specified as a part of the previous statement as n_components.
recon = pca.inverse_transform(proj)
#This function reconstructs the data along original dimensions from the projected data using information about the
#eigenvectors and their directions as a function of the original components.
sum = ((D - recon)**2).sum()
rmse = (sum/(len(D)*2))**0.5
mse = rmse.sum()
print('MSE =', mse)

#Question 3

pca = decomposition.PCA(n_components = 2)

#Question 3a

df3a = pca.fit_transform(df1b)
df3a = pd.DataFrame(df3a, columns=['A', 'B'])           #Projected data along the first 2 most significant eigenvectors

cov_matrix = np.dot(np.transpose(df1b), df1b)/len(df1b)
val, vec = np.linalg.eig(cov_matrix)

print("Largest 2 eigenvalues are")
print(val[:2])                                          #2 most significant eigenvalues
print("Variance is")
print(df3a.var())                                       #Variance in Projected Data
plt.scatter(df3a['A'], df3a['B'])
plt.show()

#Question 3b

val = sorted(list(val), reverse = True)                 #Eigenvalues ranked in significance
x = [1, 2, 3, 4, 5, 6, 7, 8]
plt.bar(list(range(len(val))), val)
plt.title("Eigenvalues")
plt.show()

#Question 3c

errs = []
for i in range(1, 8):
    pca = decomposition.PCA(n_components = i)
    proj = pca.fit_transform(df1b)                      #Projected Data along first i eigenvectors
    recon = pca.inverse_transform(proj)                 #Reconstructed back to the original 7 dimensions
    sum = ((df1b - recon)**2).sum()
    rmse = (sum/(len(df1b)*7))**0.5
    rmse = rmse.sum()
    errs.append(rmse)

l = [1, 2, 3, 4, 5, 6, 7]
plt.plot(l, errs)
plt.xlabel('Values of l')
plt.ylabel('RMSE Errors')


import numpy as np
import matplotlib.pyplot as plt

class Leibniz_Series_Approximation():
    """
    This approximation creates a finite, alternating series to calculate pi.

    """

    def __init__(self, n=100):

        self.n = n

    def approximate_pi(self):
        """
        Function to approximate pi by a finite, alternating sum.

        """

        # approximate pi with a Leibniz series
        pi_app = 4*sum((-1)**i/(2*i + 1) for i in range(self.n))

        error = round(100*abs(pi_app - np.pi)/np.pi,6)

        return 'Approximation of pi: {}, error: {}%'.format(pi_app, error)

    def series_plot(self):
        """
        Function to plot the series by the number of iterations.

        """

        fig, ax = plt.subplots(1)

        # for loop to create bar plots
        for x in range(self.n+1):
            ax.bar(x-1, 4*sum((-1)**i/(2*i + 1) for i in range(x)),
                   width=0.5,
                   alpha=0.2,
                   align='edge',
                   edgecolor='b',
                   color='g')

        # create red line to indicate pi
        ax.axhline(y=np.pi, color='r').set_linewidth(0.5)

        plt.xlim(-0.25,self.n + 1)
        plt.ylim(-0.25,4.25)

        plt.grid(linestyle='--')

        plt.title('Leibniz Series converting to pi', fontsize=8)

        plt.show()


import numpy as np

def find_y_on_circle(x):
    """
    The circle equation
    """
    y = np.sqrt(1 - x**2) #circle equation
    return y

def est_pi(tot_num):
    """
    This function will estimate pi using the Monte Carlo method in a unit circle.
    """

    inside = 0
    res = 0 #counter for test points

    while res < tot_num:
        x = np.random.uniform(0,1)
        y = np.random.uniform(0,1)
        if find_y_on_circle(x) >= y: #inside the circle
            inside += 1
        res += 1

    return 4*inside/tot_num #prints pi estimate


# Given an ordered set of uniformly distributed nodes and the y-axis value
# relative to each node (e.g. the result of a periodic sampling) we want
# to estimate the derivative at each of the sampling points using the SDQ
# method.

import matplotlib.pyplot as plt
import numpy as np

N = 20
x = np.linspace(-np.pi, np.pi, N)
fx = np.sin(x)
dx = np.cos(x)
#fx = x**6 - 2*x**5 + x**3 - x**2 + 3*x + 1
#dx = 6*x**5 - 10*x**4 + 3*x**2 - 2*x + 3
h = x[1] - x[0]
print("h = ", h);

sdq = np.zeros(N)
sdq[0]   = (fx[1] - fx[0]) / h
sdq[N-1] = (fx[N-1] - fx[N-2]) / h
for i in range(1, N-1):
    sdq[i] = (fx[i+1] - fx[i-1]) / (2*h)

err = abs(dx - sdq)

print('| Dx           | SDQ          | Err')
for a,b,c in zip(dx, sdq, err):
    print('| {:.9f} | {:.9f} | {:.9f}'.format(a, b, c))

plt.text(2.2, 0.6, 'N = {}'.format(N))
plt.plot(x, dx)
plt.plot(x, sdq)
plt.legend(['dx','sdq'])
plt.show()


import load_MNIST
import numpy as np
import softmax
import gradient

##======================================================================
## STEP 0: Initialise constants and parameters
#
#  Here we define and initialise some constants which allow your code
#  to be used more generally on any arbitrary input.
#  We also initialise some parameters used for tuning the model.

# Size of input vector (MNIST images are 28x28)
input_size = 28 * 28
# Number of classes (MNIST images fall into 10 classes)
num_classes = 10
# Weight decay parameter
lambda_ = 1e-4
# Debug
debug = False

##======================================================================
## STEP 1: Load data
#
#  In this section, we load the input and output data.
#  For softmax regression on MNIST pixels,
#  the input data is the images, and
#  the output data is the labels.
#

# Change the filenames if you've saved the files under different names
# On some platforms, the files might be saved as
# train-images.idx3-ubyte / train-labels.idx1-ubyte

images = load_MNIST.load_MNIST_images('data/mnist/train-images-idx3-ubyte')
labels = load_MNIST.load_MNIST_labels('data/mnist/train-labels-idx1-ubyte')

if debug:
    input_size = 8 * 8
    input_data = np.random.randn(input_size, 100)
    labels = np.random.randint(num_classes, size=100)
else:
    input_size = 28 * 28
    input_data = images

# Randomly initialise theta
theta = 0.005 * np.random.randn(num_classes * input_size)

##======================================================================
## STEP 2: Implement softmaxCost
#
#  Implement softmaxCost in softmaxCost.m.

(cost, grad) = softmax.softmax_cost(theta, num_classes, input_size, lambda_, input_data, labels)

##======================================================================
## STEP 3: Gradient checking
#
#  As with any learning algorithm, you should always check that your
#  gradients are correct before learning the parameters.
#
if debug:
    J = lambda x: softmax.softmax_cost(x, num_classes, input_size, lambda_, input_data, labels)

    num_grad = gradient.compute_gradient(J, theta)

    # Use this to visually compare the gradients side by side
    print num_grad, grad

    # Compare numerically computed gradients with the ones obtained from backpropagation
    diff = np.linalg.norm(num_grad - grad) / np.linalg.norm(num_grad + grad)
    print diff
    print "Norm of the difference between numerical and analytical num_grad (should be < 1e-7)\n\n"

##======================================================================
## STEP 4: Learning parameters
#
#  Once you have verified that your gradients are correct,
#  you can start training your softmax regression code using softmaxTrain
#  (which uses minFunc).

options_ = {'maxiter': 100, 'disp': True}
opt_theta, input_size, num_classes = softmax.softmax_train(input_size, num_classes,
                                                           lambda_, input_data, labels, options_)

##======================================================================
## STEP 5: Testing
#
#  You should now test your model against the test images.
#  To do this, you will first need to write softmaxPredict
#  (in softmaxPredict.m), which should return predictions
#  given a softmax model and the input data.

test_images = load_MNIST.load_MNIST_images('data/mnist/t10k-images.idx3-ubyte')
test_labels = load_MNIST.load_MNIST_labels('data/mnist/t10k-labels.idx1-ubyte')
predictions = softmax.softmax_predict((opt_theta, input_size, num_classes), test_images)
print "Accuracy: {0:.2f}%".format(100 * np.sum(predictions == test_labels, dtype=np.float64) / test_labels.shape[0])


import numpy as np

def angle_binary_representation(angle: float) -> int:
    """Converts an angle in radians to a 16-bit representation.

    Parameters
    ----------
    angle : float
        The angle (in radians) to be converted.

    Returns
    -------
    int
        16-bit representation of angle.
    """
    return int(np.rint((angle % (2*np.pi)) / (2 * np.pi / 2**16)))


# Level 0
import numpy as np

A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
A1 = A + np.eye(3)
print('A1:')
print(A1)

v = np.array([[1], [2], [3]])
A1v = A1 @ v
print('A1v:')
print(A1v)

A1i = np.linalg.inv(A1)
print('A1i:')
print(A1i)
print('Double check if the inverse matrix is correctly calculated. A1 @ A1i:')
print(A1 @ A1i)

# Level 1
import numpy as np
import matplotlib.pyplot as plt

A = [
    [-100, -100, 1],
    [-100, 100, 1],
    [100, 100, 1],
    [0, 0, 1],
    [100, -100, 1],
    [-100, -100, 1]
]

def plot_object(arr: np.array, x_lim = [-200, 200], y_lim = [-200, 200]):
    x = arr[:, 0]
    y = arr[:, 1]
    plt.plot(x, y)
    plt.xlim(x_lim)
    plt.ylim(y_lim)
    plt.show()

A = np.array(A)
plot_object(A)

T_half_size = np.array([
    [0.5, 0, 0],
    [0, 0.5, 0],
    [0, 0, 1]])
A_half_size = A @ T_half_size
print('A_half_size:')
print(A_half_size)
plot_object(A_half_size)

angle_rad = np.deg2rad(130)
T_rotation = np.array([
    [np.cos(angle_rad), -np.sin(angle_rad), 0],
    [np.sin(angle_rad), np.cos(angle_rad), 0],
    [0, 0, 1]
])
A_rotated = A @ T_rotation
print('A_rotated:')
print(A_rotated)
plot_object(A_rotated)

T_Householder = np.array([
    [0, 1, 0],
    [1, 0, 0],
    [0, 0, 1]
])
A_reflected = A @ T_Householder
print('A_reflected:')
print(A_reflected)
plot_object(A_reflected)

x_shift = 200
y_shift = 300
T_shift = np.array([
    [x_shift, y_shift, 0],
    [x_shift, y_shift, 0],
    [x_shift, y_shift, 0],
    [x_shift, y_shift, 0],
    [x_shift, y_shift, 0],
    [x_shift, y_shift, 0]
])
T_scale = np.array([
    [0.5, 0, 0],
    [0, 1.2, 0],
    [0, 0, 1]
])
A_transformed = A @ T_scale + T_shift
print('A_transformed:')
print(A_transformed)
plot_object(A_transformed, [-200 + x_shift, 200 + x_shift], [-200 + y_shift, 200 + y_shift])


'''
FORMULA DE INTEGRACIÓN Y DERIVACIÓN DE TAYLOR

Ejemplo de ejecución:
def f3(x,y):
    return sp.exp(3*x)

succ_taylor(f3,0,1,1/10, 2) # devolverá el resultado de ejecutar el métood de Taylor
complete_taylor(f3,0,1,1,10)    # nodos y su valor en el los distintos nodos
'''

import numpy as np
import sympy as sp

t,z = sp.symbols('t,z')

def fact(x):
    ''' factorial
    '''
    r = 1
    for i in range(2,x):
        r = r*i
    return r

def _diff(F,orden=1):
    '''CALCULA DERIVADA
    F(x,y(x)) (en función de sympy)
    orden es el número de derivada
    '''
    def F_aux(x,y):
            return sp.diff(F(t,z),t).subs({t:x,z:y})  + sp.diff(F(t,z),z).subs({t:x,z:y}) * F(t,z).subs({t:x,z:y})

    if orden>1:
        F_aux= _diff(F_aux, orden-1)

    return F_aux

def serieTaylor(y0,F,h, orden = 1, ordenAcumulado=1, T = None,):
    '''Devuelve serie de teylor de centrada en y0
    y0: es el valor primero
    F(x,y) es el valor de la derivada

    Los parámetro ordenAcumulado y T NO SE TOCAN (son auxiliares a la función)
    '''

    if ordenAcumulado == 1:
        df = F
        def ret(x,y):
            return y0 + h*F(x,y)
    else:
        df = _diff(T)

        def ret(x,y):
            return F(x,y) + df(x,y)*h**ordenAcumulado/fact(ordenAcumulado)

    if orden == ordenAcumulado:
        return ret
    else:
        return serieTaylor(y0, ret, h, orden, (ordenAcumulado+1), df)

def succ_taylor(F,x,y,h, p = 1):
    '''Método de taylor, devuelve
    y_{n+1}
    calculado por el método de taylor
    y_{n+1} = y_n + \sum_{i = 1} ^p \frac{h^i}{i!} derivada_orden_i(y_n)
    '''
    taylorcillo = serieTaylor(y,F,h,p)
    return taylorcillo(x,y)

def complete_taylor(F, x0, y0, xfinal, N, p= 1):
    X = np.linspace(x0,xfinal,N+1)
    Y = [y0]
    h = (xfinal - x0)/N

    # Calculamos la aproximación
    taylorcillo = succ_taylor(F,t,z,h, p)

    for n in range(N):
        Y.append(taylorcillo.subs({t:X[n],z:Y[n]}) )
    return X,Y


import numpy

#%%
def makeH(dim: int) -> numpy.ndarray:
    """
    Make H matrix for estimating Fredholm equations as in (Twomey 1963).

    Parameters
    ----------
    dim : int
        The dimension of the H matrix.

    Returns
    -------
    Hmat : 2-D array
        The H matrix
    """
    # create (symmetric) diagonal vectors
    d2 = numpy.ones(dim - 2)
    d1 = numpy.concatenate(([-2], numpy.repeat(-4, dim - 3), [-2]))
    d0 = numpy.concatenate(([1, 5], numpy.repeat(6, dim - 4), [5, 1]))
    # make matrix with diagonals
    Hmat = numpy.diag(d1, 1) + numpy.diag(d2, 2)
    Hmat = Hmat + Hmat.T
    numpy.fill_diagonal(Hmat, d0)
    return Hmat

#%%
def simpson(dim: int) -> numpy.ndarray:
    """
    Make H matrix for estimating Fredholm equations as in (Twomey 1963).

    Parameters
    ----------
    dim : int
        The dimension of the H matrix.

    Returns
    -------
    weights : 1-D array
        The quadrature weights according to Simpson's rule.
    """
    if dim > 2 and (dim % 2) == 1:
        tiles = numpy.tile([4, 2], dim // 2)
        return numpy.concatenate(([1], tiles[0 : dim - 2], [1])) / 3
    else:
        raise ValueError("Simpson's rule requires an odd number of endpoints")

#%%
def smooth(v: numpy.ndarray) -> numpy.ndarray:
    """
    Smooth a vector that is oscillating.

    Parameters
    ----------
    v : 1-D array
        The oscillating vector you want to smooth.

    Returns
    -------
    sv : 1-D array
        The smoothed vector.
    """
    dim = len(v)
    smat = numpy.diag(
        numpy.concatenate(([1], numpy.repeat(0.5, dim - 1)))
    ) + numpy.diag(numpy.repeat(0.5, dim - 1), -1)
    return smat @ v


from scipy.special import gamma
import numpy as np
from numpy.polynomial import Polynomial as poly
fact = np.math.factorial

def nCr(n, r):
    return gamma(n+1)/(gamma(r+1)*gamma(n-r+1))

def upper_pochhammer(qty, n):
    result = 1
    for i in np.arange(n):
        result *= qty+i
    return result

def jacobi_recursive(n, a, b):
    """
    From 16.930 Project 1 handout

    2(n + 1)*(n + α + β + 1)*(2n + α + β)*P_{n+1}^{α, β}(x) = [(2n + α + β + 1)*(α^2 − β^2) + (2n + α + β)_3*x]*P{α, β}_n(x) - 2(n + α)*(n + β)*(2n + α + β + 2)*P_{n−1}^{α,β}(x)
    """

    # Base cases
    if n == 0:
        return poly([1])
    elif n == 1:
        return poly([(a-b)/2, (a+b+2)/2])

    n -= 1  # The formulas are for the n+1th polynomial, so here the nth polynomial really means the one with degree one less

    # Prepare coefficients
    c1 = 2*(n+1)*(n+a+b+1)*(2*n+a+b)
    c2 = (2*n + a + b + 1)*(a**2 - b**2)
    c3 = (2*n + a + b)*(2*n + a + b + 1)*(2*n + a + b + 2)
    c4 = 2*(n+a)*(n+b)*(2*n+a+b+2)

    tmp_poly = poly([c2, c3])
    p_n = jacobi_recursive(n, a, b)
    p_n_minus1 = jacobi_recursive(n-1, a, b)

    # Note: output is in the reverse order of the 16.930 matlab code
    return (tmp_poly*p_n - c4*p_n_minus1)/c1

def jacobi_wiki_realx(n, a, b):
    """
    From wikipedia (https://en.wikipedia.org/wiki/Jacobi_polynomials#Alternate_expression_for_real_argument): For real x, no restriction on n, a, or b

    """
    poly1 = poly([-1, 1])/2
    poly2 = poly([1, 1])/2

    result = poly([0])
    for s in np.arange(n+1):
        summand = nCr(n+a, n-s) * nCr(n+b, s)*poly1**s * poly2**(n-s)
        result += summand

    return result

def jacobi_wiki_nat_numbers(n, a, b):
    """
    From wikipedia (https://en.wikipedia.org/wiki/Jacobi_polynomials#Alternate_expression_for_real_argument): special case that n, a, and beta are nonnegative integers

    """
    coeff = fact(n+a)*fact(n+b)

    poly1 = poly([-1, 1])/2
    poly2 = poly([1, 1])/2

    result = poly([0])
    for s in np.arange(n+1):
        denom = fact(s)*fact(n+a-s)*fact(b+s)*fact(n-s)
        summand = (1/denom) * poly1**(n-s) * poly2**(s)
        result += summand

    return result*coeff

def jacobi(k, a, b):
    """
    From https://arxiv.org/pdf/2105.07547.pdf

    This is the one that I've selected to use going forward
    """
    poly1 = poly([-1, 1])/2

    result = poly([0])
    for j in np.arange(k+1):
        coeff = upper_pochhammer(a+j+1, k-j)*upper_pochhammer(k+a+b+1, j)/(fact(j)*fact(k-j))
        summand = coeff* poly1**j
        result += summand

    return result

if __name__ == '__main__':
    n = 3
    a = 0
    b = 0
    print(jacobi_recursive(n, a, b))
    print(jacobi_wiki_nat_numbers(n, a, b))
    print(jacobi_wiki_realx(n, a, b))
    print(jacobi(n, a, b))


import numpy as np
from matplotlib import pyplot as plt

# for apple
mean_01 = np.array([3.0,4.0])
cov_01 = np.array([[1.0,-0.5],[-0.5,1.0]])
#for leman(sweetness and color)
# Red is higher and yello is lower value
# sweetnes is higher and surness in lesser value

#  for Lemon
mean_02 = np.array([0.0,0.0])
cov_02 = np.array([[1.5,0.5],[0.5,0.6]])
#2x2 identity matrix
# Arrays of array

dist_01 = np.random.multivariate_normal(mean_01,cov_01,200)
dist_02 = np.random.multivariate_normal(mean_02,cov_02,200)

print dist_01.shape
print dist_02.shape
#print  dist_01

# Try to make scatter plot

plt.figure(0)

for x in range(dist_01.shape[0]):
    plt.scatter(dist_01[x,0],dist_01[x,1],color='red')
    plt.scatter(dist_02[x, 0], dist_02[x, 1], color='yellow')
#plt.show()

# Training data preperation of apples and lemons

# Using 400 Samples (200 for Apples and 200 for Lemons )

labels = np.zeros((400,1))
labels[200:] = 1.0

X_data = np.zeros((400,2))
X_data[:200, :] = dist_01
X_data[200:, :] = dist_02

print X_data
print labels

# KNN  Algorithm :)

#Dist of the query_point to all other points in the space ( O(N)) time for every point + sorting

#Euclidean Distance

def dist( x1 , x2):
    return np.sqrt(((x1-x2)**2).sum())

x1 = np.array([0.0,0.0])
x2 = np.array([1.0,1.0])

print dist(x1,x2)

def knn(X_train, query_point, y_train, k=5):
    vals = []

    for ix in range(X_train.shape[0]):
        v = [dist(query_point, X_train[ix, :]), y_train[ix]]
        vals.append(v)
    # vals is a list containing distances and their labels

    updated_vals = sorted(vals)

    # Lets us pick up top K values

    pred_arr = np.asarray(updated_vals[:k])
    pred_arr = np.unique(pred_arr[:, 1], return_counts=True)
    # Largest Occurence
    print pred_arr

# q = np.array([2.0,2.0])
# knn(X_data,q,labels)

    # Largest Occurence

    index = pred_arr[1].argmax()     # Index of largest freq
    return pred_arr[0][index]

q = np.array([0.0, 4.0])

predicted_label = knn(X_data, q, labels)

#if predicted label is 0.0 then apple else lemon

print predicted_label
#
# ## Run a Loop over a testing data(Split the original data into 2 sets - Training, Testing)
#
# # FInd predictions for Q Query points
#
# # If predicted outcome = actual outcome -> Sucess else Failure
#
# # Accuracy =  (Successes)/ (Total no of testing points) * 100


import numpy as np

def crossProd(v0,v1):
    """
        Cross product of 2 vectors

        :param numpy.array v0: vector of length 3
        :param numpy.array v1: vector of length 3
        :rtype: numpy.array
        :return: cross product of v0,v1
    """
    # ensure both n0, n1 are vectors of length 1
    assert len(v0) == 3, "Length of v0 should be 3"
    assert len(v1) == 3, "Length of v1 should be 3"

    v2 = np.zeros(3,dtype=float)

    v2[0] = v0[1]*v1[2] - v1[1]*v0[2]
    v2[1] = v1[0]*v0[2] - v0[0]*v1[2]
    v2[2] = v0[0]*v1[1] - v1[0]*v0[1]

    return v2

def rotationMatrixFromNormals(v0,v1,tol=1e-20):
    """
        Performs the minimum number of rotations to define a rotation from the direction indicated by the vector n0 to the direction indicated by n1.
        The axis of rotation is n0 x n1
        https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula

        :param numpy.array v0: vector of length 3
        :param numpy.array v1: vector of length 3
        :param tol = 1e-20: tolerance. If the norm of the cross product between the two vectors is below this, no rotation is performed
        :rtype: numpy.array, 3x3
        :return: rotation matrix which rotates the frame so that n0 is aligned with n1

    """

    # ensure both n0, n1 are vectors of length 1
    assert len(v0) == 3, "Length of n0 should be 3"
    assert len(v1) == 3, "Length of n1 should be 3"

    # ensure both are true normals
    n0 = v0*1./np.linalg.norm(v0)
    n1 = v1*1./np.linalg.norm(v1)

    n0dotn1 = n0.dot(n1)

    # define the rotation axis, which is the cross product of the two vectors
    rotAx = crossProd(n0,n1)

    if np.linalg.norm(rotAx) < tol:
        return np.eye(3,dtype=float)

    rotAx *= 1./np.linalg.norm(rotAx)

    cosT = n0dotn1/(np.linalg.norm(n0)*np.linalg.norm(n1))
    sinT = np.sqrt(1.-n0dotn1**2)

    ux = np.array([[0., -rotAx[2], rotAx[1]], [rotAx[2], 0., -rotAx[0]], [-rotAx[1], rotAx[0], 0.]],dtype=float)

    return np.eye(3,dtype=float) + sinT*ux + (1.-cosT)*(ux.dot(ux))

def rotatePointsFromNormals(XYZ,n0,n1,x0=np.r_[0.,0.,0.]):
    """
        rotates a grid so that the vector n0 is aligned with the vector n1

        :param numpy.array n0: vector of length 3, should have norm 1
        :param numpy.array n1: vector of length 3, should have norm 1
        :param numpy.array x0: vector of length 3, point about which we perform the rotation
        :rtype: numpy.array, 3x3
        :return: rotation matrix which rotates the frame so that n0 is aligned with n1
    """

    R = rotationMatrixFromNormals(n0, n1)

    assert XYZ.shape[1] == 3, "Grid XYZ should be 3 wide"
    assert len(x0) == 3, "x0 should have length 3"

    return (XYZ - x0).dot(R.T) + x0


# Numerical Analysis Course - Physics Department Auth
# Michael Chadolias  AEM: 14871
#
# Set 1st
# Exercise 1c

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

def f1(x):
    return 2*x+3*np.sin(4*x)-np.exp(x)

xpoints = np.linspace(-0.5,1,500)
fpoints = f1(xpoints)

plot1 = plt.plot(xpoints, fpoints)
plt.grid(True)
plt.show(plot1)

iteration = [0]
i=1
x=0.5
solution = [x]
print('%.d %.16f'% (iteration[0], solution[0]))
while True:
   x = x- f1(x)/(2+12*np.cos(4*x)-np.exp(x))
   iteration.append(i)
   solution.append(x)
   print('%.d %.16f'% (iteration[i], solution[i]))
   if solution[-1]==solution[-2]:
       break
   i=i+1

N = len(solution)
error = solution[N-1]-solution
fig, ax = plt.subplots()
ax.plot(iteration, abs(error))
ax.set_yscale('log')
ax.set(xlabel='iteration', ylabel='error')
ax.grid()
plt.ylim(bottom=abs(error[-2]))
plt.show()

#confirm the convergence of the error with the theoretical prediction
root = solution[N-1]
k = (48.0*np.sin(4.0*root)+np.exp(root))/(2.0*(12.0*np.cos(4.0*root)+2.0-np.exp(root)))

error_n = np.array([solution[N-1]-solution[1]])
error_np1 = np.array([solution[N-1]-solution[2]])
for i in range (2,N-1):
    error_n = np.append(error_n, [solution[N-1]-solution[i]])
    error_np1 = np.append(error_np1, [solution[N-1]-solution[i+1]])

error_np1_predict = k*error_n**2

NE = len(error_n)
fig, ax = plt.subplots()
ax.plot(abs(error_n), abs(error_np1_predict),label="Theoretical Prediction")
ax.plot(abs(error_n), abs(error_np1),label="Experimental Prediction")
ax.legend()
ax.set(xlabel='error_n', ylabel='error_n+1')
ax.set_xscale('log')
ax.set_yscale('log')

#plt.ylim(bottom=abs(error_np1[NE-1]))
#plt.xlim(left=abs(error_np1[NE-2]))

ax.grid()
plt.show()


#!/Users/robertpoenaru/.pyenv/shims/python
import numpy as np

# generate the matrices for the Ladder operators J_, J+, and also the set of commuting operators J^2, J_z

HBAR = 1

# generate the matrix element of $J^2$
def J2_MatEl(j, m1, m2):
    if(m1 != m2):
        return 0
    return np.power(HBAR, 2) * j * (j + 1)

# generate the matrix element of $J_z$
def Jz_MatEl(j, m1, m2):
    if(m1 != m2):
        return 0
    return HBAR * m1

# generate the matrix element of $J_+$
def JPlus_MatEl(j, m1, m2):
    if(m2 != m1 + 1):
        return 0
    c_plus = np.sqrt((j - m1) * (j + m1 + 1)) * HBAR
    return c_plus

# generate the matrix element of $J_-$
def JMinus_MatEl(j, m1, m2):
    if(m2 != m1 - 1):
        return 0
    c_minus = np.sqrt((j + m1) * (j - m1 + 1)) * HBAR
    return c_minus

def Jx_MatEl(j, m1, m2):
    Jx_matrix = 0.5 * (JPlus_MatEl(j, m1, m2) + JMinus_MatEl(j, m1, m2))
    return Jx_matrix

def Jy_MatEl(j, m1, m2):
    # c_plus = np.sqrt((j - m1) * (j + m1 + 1))
    # c_minus = np.sqrt((j + m1) * (j - m1 + 1))
    Jy_matrix = 0.5 * (JPlus_MatEl(j, m1, m2) - JMinus_MatEl(j, m1, m2))
    return Jy_matrix

# for a given angular momentum j, generate the matrix associated with the possible states that this |jm> representation can have
def JM_Matrix(j, angular_operator):
    matrix = []
    for m2 in reversed(np.arange(-j, j + 1, 1)):
        line = []
        for m1 in reversed(np.arange(-j, j + 1, 1)):
            # line.append(f'<{j},{m2}|{j},{m1}>')
            # line.append([m2, m1, angular_operator(j, m1, m2)])
            # only add the value of the operator's matrix element itself
            line.append(angular_operator(j, m1, m2))

        matrix.append(line)
    for line in matrix:
        print(line)

JM_Matrix(1, J2_MatEl)
JM_Matrix(1, Jz_MatEl)
JM_Matrix(1, JPlus_MatEl)
JM_Matrix(1, JMinus_MatEl)
JM_Matrix(1, Jx_MatEl)
JM_Matrix(1, Jy_MatEl)


import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import newton
from math import sqrt
import timeit

"""
Code for return and plot the minimum distance from a point P(a,b) to a curve f(x) = 620.7x^-0.71

Requisites
----------
numpy, matplotlib and scipy : python3 modules
	install by pip
python3-tk : python3 package
	install by apt
"""

def getDistance(P1, P2):
	"""Returns the distance between point P1 and P2 by Pythagoras.

	Parameters
	----------
	P1 : list
		coordinates (x,y) of point P1
	P2 : list
		coordinates (x,y) of point P2
	"""
	return sqrt((P1[0] - P2[0]) ** 2 + (P1[1] - P2[1]) ** 2)

def fplot():
	"""Plot the graph of f(x) and a circle of radius equal distance and center in point P.

	Attributes
	----------
	t : numpy.ndarray
		arrange of values for x from 0 to 100 by steps of 0.1
	"""
	t = np.arange(0.1, 800, 0.1)
	plt.plot(t, f(t))
	plt.plot(np.cos(t) * distance + P[0], np.sin(t) * distance + P[1])
	plt.plot(distance + P[0], distance + P[1],'-')
	plt.plot([P[0]],[P[1]],marker = 'o',markersize = 3, color = 'red')
	plt.plot([xmin],[f(xmin)],marker = 'o',markersize = 3, color = 'blue')
	plt.axis([0, 300, 0, 300])
	plt.grid(True)
	plt.show()

"""
Parameters
----------
a : float
	x coordinate of point P
b : float
	y coordinate of point P

Lambda Functions
----------------
f : function
	curve f(x)
f1 : function
	the derivative of curve f(x) in x
dist1 : function
	expression of derivative of distance

Newton
---------
	returns a zero using the Newton-Raphson method

	dist1 : function
		The function whose zero is wanted
	x0 : float
		An initial estimate of the zero
	tol : float, optional
		The allowable error of the zero value
	maxiter : int, optional
		Maximum number of iterations

	xmin: float
		returns estimated location where function is zero
"""

a = float(input("coord x: ")) #mm24h
b = float(input("coord y: ")) #mm1h

P = (a, b)

f = lambda x: 620.7*x**-0.71
f1 = lambda x: -0.71*620.7*x**-1.71
dist1 = lambda x: x - P[0] + f1(x) * (f(x) - P[1])

xmin = newton(dist1, x0 = a, tol=10 ** -10, maxiter=50)
distance = getDistance(P, (xmin, f(xmin)))

print("xmin,fmin: ",xmin,f(xmin))
print("distance: ",distance)

fplot()


#T# the following code shows how to do polynomial factoring

#T# to do polynomial factoring, the sympy package is used
import sympy

#T# create the variable of the polynomial
x = sympy.Symbol('x') # x

#T# create the polynomial to do polynomial factoring to it
P1 = 3*x**2 + 6*x  # 3*x**2 + 6*x

#T# the factor function of the sympy package expresses a polynomial as a product of its factors
P2 = sympy.factor(P1) # 3*x*(x + 2)


'''
    Problem 123 : Square remainders

    Problem Satement :
        Let pn be the nth prime: 2, 3, 5, 7, 11, ..., and
        let r be the remainder when (pn − 1)^n + (pn + 1)^n is divided by pn^2.

        For example, when n = 3, p3 = 5, and 4^3 + 6^3 = 280 ≡ 5 mod 25.

        The least value of n for which the remainder first exceeds 10^9 is 7037.

        Find the least value of n for which the remainder first exceeds 10^10.
'''
from time import time
import numpy as np

def get_primes(n):
    q, r = divmod(n, 2)
    r = q + r
    seive = np.ones(r, dtype=bool)
    seive[0] = 0

    lim = int(n**0.5 / 2) + 1

    for i in range(1, lim + 1):
        p = 2 * i + 1
        if seive[i]:
            sp = 2 * i * (i + 1)
            seive[sp:r:p] = False

    def_prime = np.asarray([2])
    seived_primes = np.asarray(np.nonzero(seive)).flatten() * 2 + 1
    primes = np.concatenate((def_prime, seived_primes))
    return primes

def get_rem(p, n):
    '''
        Find  [ (p-1)^n + (p+1)^n ] % p^2
    '''
    rem = 2 * p
    d = p * p
    if n % 2 == 1:
        rem = (2 * n * p) % d

    return rem

def p123(m=10**10):
    primes = get_primes(10**6)

    n = 0
    res = 0
    while (True):
        n += 1
        p = primes[n - 1]
        rem = get_rem(p, n)
        if rem > m:
            break

    return n

if __name__ == "__main__":
    m = 10**10
    start_time = time()
    print(p123(m))
    print("Time taken {:.1f} secs".format(time() - start_time))


import numpy.linalg as la
import numpy.polynomial.polynomial as poly
import matplotlib.pyplot as plt
import numpy as np

data = np.loadtxt('whData.dat', dtype=np.object, comments='#', delimiter=None)

# Removing rows with missing weights
data = data[data[:,0]!='-1',:]

#Reading weight and height data
hgt = data[:, 1].astype(np.float)
wgt = data[:, 0].astype(np.float)

xmin = hgt.min()-15
xmax = hgt.max()+15
ymin = wgt.min()-15
ymax = wgt.max()+15

def plot_data_and_fit(h, w, x, y, plt_name):
	plt.plot(h, w, 'ko', x, y, 'r-')
	plt.xlim(xmin,xmax)
	plt.ylim(ymin,ymax)
	plt.ylabel("Weight")
	plt.xlabel("Height")
	plt.savefig("{}.pdf".format(plt_name), facecolor='w', edgecolor='w',
                papertype=None, format='pdf', transparent=False,
                bbox_inches='tight', pad_inches=0.1)
	plt.show()

def trsf(x):
	return x / 100.

n = 10
x = np.linspace(xmin, xmax, 100)

# method 1:
# regression using ployfit
c = poly.polyfit(hgt, wgt, n)
y = poly.polyval(x, c)
plot_data_and_fit(hgt, wgt, x, y, "Method1-result")

# method 2:
# regression using the Vandermonde matrix and pinv
X = poly.polyvander(hgt, n)
c = np.dot(la.pinv(X), wgt)
y = np.dot(poly.polyvander(x,n), c)
plot_data_and_fit(hgt, wgt, x, y, "Method2-result")

# method 3:
# regression using the Vandermonde matrix and lstsq
X = poly.polyvander(hgt, n)
c = la.lstsq(X, wgt)[0]
y = np.dot(poly.polyvander(x,n), c)
plot_data_and_fit(hgt, wgt, x, y, "Method3-result")

# method 4:
# regression on transformed data using the Vandermonde
# matrix and either pinv or lstsq
X = poly.polyvander(trsf(hgt), n)
c = np.dot(la.pinv(X), wgt)
y = np.dot(poly.polyvander(trsf(x),n), c)
plot_data_and_fit(hgt, wgt, x, y, "Method4-result")


# Name          : dft.py
# Info          : Discrete Fourier Transform (DFT) Program
# Function file : dofft.py
# Written by    : Aulia Khalqillah, S.Si., M.Si.
# Written Date  : 10th March, 2020
#---------------------------------------------------------------------------
import math as m
import csv
import matplotlib.pyplot as plt
from numpy import arange,mean,argmax,allclose,abs
from random import random
from scipy.fftpack import fft
from dofft import dofft # call function file dofft.py
import numpy as np
import timeit

# SIGNAL
f1 = 20
time = 0.0
dt = 0.01
signal = [];
signal_rand = [];
t = [];
i = 0
n = 2000
while i < n:
    x = m.sin(2*m.pi*f1*time)
    xrd = x*random()
    signal.append(x)
    signal_rand.append(xrd)
    t.append(time)
    time = time + dt
    i = i + 1

print("Length of Data\t\t\t:", len(signal_rand))

with open("signal.csv","w") as f:
    fsignal = csv.writer(f, delimiter='\t')
    fsignal.writerows(zip(t,signal,signal_rand))

# DFT from function file
fs = 100
nfft = 1024
freq, spectrum = dofft(signal_rand,nfft,fs)
maxspec1 = max(abs(spectrum))
id_maxspec1 = argmax(abs(spectrum))
freq_spectrum = freq[id_maxspec1]

# FFT from Python Library
pyspectrum = fft(signal_rand,nfft)
freq2 = arange(0,len(pyspectrum))/(len(pyspectrum)/fs)
maxspec2 = max(abs(pyspectrum))
id_maxspec2 = argmax(abs(pyspectrum))
freq_pyspectrum = freq2[id_maxspec2]

# Check between dofft and fft
comparing = allclose(abs(spectrum),abs(pyspectrum))
print("Comparing Result\t\t:",comparing)
tot_time_pyspectrum = timeit.timeit("'scipy.fftpack.fft(signal_rand,nfft)'",number=1000000)
tot_time_dofft = timeit.timeit("'dofft(signal_rand,nfft,fs)'",number=1000000)
print("-----------------------------------------------------------------------")
print("FFT from Library [scipy.fftpack]")
print("-----------------------------------------------------------------------")
print("Time per loop (pyspectrum)\t:",tot_time_pyspectrum/1000000,"sec")
print("Length of FFT from python\t:",len(pyspectrum))
print("Frequency from FFT Library\t:", freq_pyspectrum)
print("-----------------------------------------------------------------------")
print("DFT from written function [dofft.py]")
print("-----------------------------------------------------------------------")
print("Time per loop (dofft)\t\t:",tot_time_dofft/1000000,"sec")
print("Length of DFT from function\t:",len(spectrum))
print("Frequency from DFT Function\t:", freq_spectrum)

topbound = 0.92
bottombound = 0.08
leftbound = 0.10
rightbound = 0.95
heighspace = 0.5
widthspace = 0.35

fig = plt.figure(1)
fig1 = fig.add_subplot(211)
plt.plot(t,signal,color='black', linewidth=0.5, label='Signal')
plt.title('Sinusoidal Signal and Random Signal')
plt.ylabel('Amplitude')
plt.legend(loc='upper left')
plt.grid()
plt.subplots_adjust(top=topbound, bottom=bottombound, left=leftbound, right=rightbound, hspace=heighspace,wspace=widthspace)

fig2 = fig.add_subplot(212)
plt2 = plt.plot(t,signal_rand, color='red', linewidth=0.5, label='Random Signal')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.legend(loc='upper left')
plt.grid()
plt.subplots_adjust(top=topbound, bottom=bottombound, left=leftbound, right=rightbound, hspace=heighspace,wspace=widthspace)

# Plot Spectrum Comparison
figspec = plt.figure(2)
fig3 = figspec.add_subplot(211)
plt.plot(freq,abs(spectrum),color='black', linewidth=0.5, label='Spectrum')
plt.title('DFT from written function')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Spectrum')
plt.legend(loc='upper left')
plt.grid()
plt.subplots_adjust(top=topbound, bottom=bottombound, left=leftbound, right=rightbound, hspace=heighspace,wspace=widthspace)

fig4 = figspec.add_subplot(212)
plt.plot(freq2, abs(pyspectrum),color='black', linewidth=0.5, label='Spectrum')
plt.title('FFT from Python Library')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Spectrum')
plt.legend(loc='upper left')
plt.grid()
plt.subplots_adjust(top=topbound, bottom=bottombound, left=leftbound, right=rightbound, hspace=heighspace,wspace=widthspace)

plt.show()


#
# Monte Carlo valuation of European call options with NumPy
# mcs_vector_numpy.py
# https://github.com/yhilpisch/py4fi

import numpy as np
from time import time

np.random.seed(1234)
t0 = time()

# Parameters
S0 = 100.
K = 105.
T = 1.0
r = 0.05
sigma = 0.2
M = 50
dt = T / M
n_paths = 250000 * 2

# Simulating n_paths paths with M time steps
S = np.zeros((M + 1, n_paths))
S[0] = S0
for t in range(1, M + 1):
    z = np.random.standard_normal(n_paths)  # pseudo-random numbers
    z -= z.mean()  # corrects 1st moment
    z /= z.std()  # corrects 2nd moment
    S[t] = S[t - 1] * np.exp((r - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * z)
    # vectorized operation per time step over all paths

# Calculating the Monte Carlo estimator
C0 = np.exp(-r * T) * np.sum(np.maximum(S[-1] - K, 0)) / n_paths

# Results output
tnp1 = time() - t0
print("European Option Value %7.3f" % C0)
print("Duration in Seconds   %7.3f" % tnp1)

# EXERCISE
# Implement a loop-free version taking the log on both sides and using a telescopic sum

03 Valuation of European call - vectorized.py


import numpy as np

class Neuron:
    """
    A neuron object holds all information needed to compute the ouput from a single neuron.

    Attributes:
        weights : numpy matrix to hold the weight values for the neuron with shape (n x 1).
        bias : the bias term used in output computation.

    Methods:
        forward : computes the neuron output for a given numpy matrix of inputs (with shape n x 1)
    """

    def __init__(self, num_inputs, b=1):
        """
        The initialization function for the neuron. Will generate a weight matrix using near 0 values.

        Paramters:
            num_inputs : the number of input values into the neuron.
            b : The given bias value to use for this neuron.
        """
        self.weights = np.random.rand(num_inputs, 1)
        self.bias = b

    def forward(self, inputs):
        """
        Computs the output from this neruon for the given inputs.

        Paramters:
            inputs : the numpy matrix of inputs with shape (n x 1)

        Return:
            A single value in a numpy array which is the output from the neuron object
        """

        # Verify that the inputs have the correct shape
        assert inputs.shape == self.weights.shape

        return np.reshape(np.dot(np.transpose(inputs), self.weights), 1) + self.bias

if __name__ == "__main__":
    """
    If this file is being run individually test the implementation of neuron classes.
    """

    test_inputs = np.array([[2], [1]])

    ## Test Linear Neuron Class Implementation ##
    print("Testing Single Linear Neuron")
    test_neuron = Neuron(2, 1)
    print(test_neuron.forward(test_inputs))


#! /usr/bin/python
# """ Methods to expand circular pupils in Zernike polynomial expansion """
# __author__ = [pacosalces, ]

import numpy as np
from math import factorial as fact

def zernike_pol(rho, theta, n, m):
    """Evaluate the normalized radial zernike polynomials in the unit
    circle using the radial and azimuthal index convention outlined in
    https://en.wikipedia.org/wiki/Zernike_polynomials.

    Arguments:
    rho -- radial mesh covering the unit range [0, 1]
    theta -- polar angle mesh covering the range [0, 2*pi]
    n, m -- integer radial Zernike polynomial indices
    """
    def R(r, i, j):
        radial = 0
        for s in range((i - np.abs(j))//2 + 1):
            num = (-1)**s * fact(i - s) * r**(i - 2*s)
            den = fact(s) * fact((i + np.abs(j) - 2*s)//2) * fact((i - np.abs(j) - 2*s)//2)
            radial += num / den
        return radial

    def Norm(i, j):
        if j == 0:
            return np.sqrt(2*(i + 1) / (1 + 1))
        else:
            return np.sqrt(2*(i + 1))

    amplitude = Norm(n, m) * R(rho, n, m)
    if m < 0:
        return -amplitude * np.sin(m*theta)
    else:
        return amplitude * np.cos(m*theta)

def zernike_expansion(rho, theta, coeffs):
    """Compute zernike expansion for a set of coefficients over the
    pupil coords. An example for the coeffs argument is:

        coeffs = {'Z00':0.1, 'Z20':0.012, 'Z1m1':-0.15}

    where the keys must be strings in the 'Znm' format denoting the
    (n, m)-th term, and the corresponding value. For negative m-indices
    use the 'Zxmx' format, with an 'm' between (n, m) for 'minus'.

    Arguments:
    rho -- radial mesh covering the unit range [0, 1]
    theta -- polar angle mesh covering the range [0, 2*pi]
    coeffs -- dictionary containing the Zernike coefficients
    """
    expansion = 0.
    for coeff_key, coeff_val in coeffs.items():
        n, m = int(coeff_key.strip('Z')[0]), int(coeff_key.strip('Z')[-1])
        if 'm' in coeff_key:
            m = -m
        expansion += coeff_val * zernike_pol(rho, theta, n, m)
    return expansion

if __name__ in '__main__':
    import matplotlib.pyplot as plt

    r, t = np.linspace(0, 1, 2**8), np.linspace(-np.pi, np.pi, 2**8)
    R, T = np.meshgrid(r, t)

    # Two lists of coefficients up to some order

    fourth_order_coeffs = {
                                                     'Z00':0.43,
                                                'Z1m1':-0.08, 'Z11':0.,
                                        'Z2m2':1.01, 'Z20':12.75, 'Z22':-9.89,
                                    'Z3m3':0.056, 'Z3m1':0.145, 'Z31':0., 'Z33':0.,
                             'Z4m4':-0.08, 'Z4m2':0.37, 'Z40':1.85, 'Z42':-0.06, 'Z44':-0.20,
#                         'Z5m5':0.0, 'Z5m3':0.0, 'Z5m1':0.0, 'Z51':0.0, 'Z53':0.0, 'Z55':0.0
    }

    eighth_order_coeffs = {
                                                     'Z00':1.0,
                                                'Z1m1':0.0, 'Z11':0.0,
                                        'Z2m2':3.0, 'Z20':1.0, 'Z22':-1.5,
                                    'Z3m3':0.1, 'Z3m1':1.0, 'Z31':0.5, 'Z33':0.3,
                             'Z4m4':1.5, 'Z4m2':3.0, 'Z40':2.00, 'Z42':1.0, 'Z44':0.2,
                        'Z5m5':0.0, 'Z5m3':0.0, 'Z5m1':0.0, 'Z51':0.0, 'Z53':0.0, 'Z55':0.0,
                 'Z6m6':-0.5, 'Z6m4':0.0, 'Z6m2':0.0, 'Z60':0.0, 'Z62':0.0, 'Z64':0.0, 'Z66':0.0,
            'Z7m7':0.0, 'Z7m5':0.0, 'Z7m3':2.0, 'Z7m1':0.0, 'Z71':0.0, 'Z73':0.0, 'Z75':0.0, 'Z77':0.0,
     'Z8m8':0.0, 'Z8m6':0.0, 'Z8m4':0.0, 'Z8m2':0.0, 'Z80':-1.0, 'Z82':0.0, 'Z84':0.0, 'Z86':0.0, 'Z88':0.0,
    }

    fourth_order = zernike_expansion(R, T, fourth_order_coeffs)
    eighth_order = zernike_expansion(R, T, eighth_order_coeffs)

    plt.figure()
    ax = plt.subplot(121, polar=True)
    ax.set_title('Fourth order expansion')
    pcolorbar = ax.pcolor(T, R, fourth_order, cmap='RdBu', shading='auto')
    ax.set_yticks([]), ax.set_xticks([])
    ax = plt.subplot(122, polar=True)
    ax.set_title('Eighth order expansion')
    ax.pcolor(T, R, eighth_order, cmap='RdBu', shading='auto')
    ax.set_yticks([]), ax.set_xticks([])
    plt.show()